diff --git a/.clang-tidy b/.clang-tidy index 3cda293..deaf726 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1 +1 @@ -Checks: '*,clang-analyzer-*,-llvmlibc-*,-fuchsia-*,-altera-*,-abseil-*,-android-*,-modernize-use-trailing-return-type,-readability-identifier-length,-*-readability-todo,-*-magic-numbers,-readability-function-cognitive-complexity,-*-easily-swappable-parameters' \ No newline at end of file +Checks: '*,clang-analyzer-*,-llvmlibc-*,-fuchsia-*,-altera-*,-abseil-*,-android-*,-modernize-use-trailing-return-type,-readability-identifier-length,-*-readability-todo,-*-magic-numbers,-readability-function-cognitive-complexity,-*-easily-swappable-parameters,-*-non-private-member-variables-in-classes,-*-no-recursion' \ No newline at end of file diff --git a/src/main.cc b/src/main.cc index e5d6d16..3f8d840 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,3 +1,18 @@ +#include "parser.h" +#include #include +#include -int main() { std::cout << "Hello, World!\n"; } \ No newline at end of file +int main() { + std::ifstream file("zlib.shrap"); + if (!file) { + std::cerr << "Error opening file\n"; + return 1; + } + + std::stringstream buffer; + buffer << file.rdbuf(); + + Expr pkg = Expr::parse(buffer.str()); + std::cout << pkg.get("name").value << std::endl; +} \ No newline at end of file diff --git a/src/parser.h b/src/parser.h new file mode 100644 index 0000000..320638b --- /dev/null +++ b/src/parser.h @@ -0,0 +1,141 @@ +#pragma once + +#include +#include +#include + +struct Expr { +public: + enum class Type { Atom, String, List }; + + Type type = Type::Atom; + std::string value; + std::vector children; + + [[nodiscard]] Expr get(const std::string &key) const { + if (type != Type::List) { + throw std::runtime_error("get() called on non-list"); + } + for (const auto &child : children) { + if (child.type == Type::List && child.children.size() >= 2 && + child.children[0].type == Type::Atom && + child.children[0].value == key) { + return child.children[1]; + } + } + throw std::runtime_error("key not found: " + key); + } + + static Expr parse(const std::string &input) { + std::istringstream in(input); + return parse_expr(in); + } + +private: + static std::string read_atom(std::istringstream &in) { + std::string atom; + while (true) { + int next = in.peek(); + if (next == -1 || is_space(static_cast(next)) || next == '(' || + next == ')') { + break; + } + atom += static_cast(in.get()); + } + if (atom.empty()) { + throw std::runtime_error("empty atom"); + } + return atom; + } + + static Expr parse_list(std::istringstream &in) { + Expr result = {.type = Expr::Type::List}; + + in.get(); // consume bracket + + while (true) { + while (is_space(static_cast(in.peek()))) { + in.get(); + } + if (!in) { + throw std::runtime_error("unexpected EOF"); + } + + if (in.peek() == ')') { + in.get(); + break; + } + + result.children.push_back(parse_expr(in)); + } + + return result; + } + + static std::string read_string(std::istringstream &in) { + std::string result; + + in.get(); // consume the quote + + while (true) { + if (!in) { + throw std::runtime_error("unexpected EOF in string"); + } + + auto c = static_cast(in.get()); + if (c == '"') { + break; + } + result += c; + } + return result; + } + + static Expr parse_expr(std::istringstream &in) { + while (is_space(static_cast(in.peek()))) { + in.get(); + } + if (!in) { + throw std::runtime_error("unexpected EOF"); + } + + if (in.peek() == '(') { + return parse_list(in); + } + if (in.peek() == ')') { + throw std::runtime_error("unexpected ')'"); + } + + if (in.peek() == '"') { + return {.type = Type::String, .value = read_string(in)}; + } + + return {.type = Type::Atom, .value = read_atom(in)}; + } + + static bool is_space(char c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\r'; + } +}; + +inline std::ostream &operator<<(std::ostream &out, const Expr &e) { + switch (e.type) { + case Expr::Type::Atom: + out << e.value; + break; + case Expr::Type::String: + out << '"' << e.value << '"'; + break; + case Expr::Type::List: + out << '('; + for (size_t i = 0; i < e.children.size(); ++i) { + if (i > 0) { + out << ' '; + } + out << e.children[i]; + } + out << ')'; + break; + } + return out; +} \ No newline at end of file diff --git a/zlib.shrap b/zlib.shrap new file mode 100644 index 0000000..d30ac5c --- /dev/null +++ b/zlib.shrap @@ -0,0 +1,7 @@ +(package + (name "zlib") + (version "1.3.1") + (homepage "https://zlib.net/") + (src (tar "https://zlib.net/zlib-1.3.1.tar.gz" "207c3b0862cb4e3686f8405f76a98c38dbad9c94bcf4be4b9efca0716aba51ec")) + (build + (configure_make))) \ No newline at end of file