diff --git a/include/compiler/treeifier/ast.hh b/include/compiler/treeifier/ast.hh index ba6eb11..f779f38 100644 --- a/include/compiler/treeifier/ast.hh +++ b/include/compiler/treeifier/ast.hh @@ -1,43 +1,84 @@ #pragma once #include -#include +#include #include #include #include "compiler/treeifier/tokenizer.hh" #include "utils/data.hh" -#include "utils/slice.hh" #include "lang/common.hh" using namespace std::string_literals; using namespace ppc; +using namespace ppc::messages; namespace ppc::comp::tree::ast { - class constr_parser_t { - private: - std::string name; - public: - const std::string &name() { return name; } - virtual bool parse(messages::msg_stack_t &messages, vec_slice_t &tokens, data::map_t &out) = 0; - }; + class parser_t; + class group_parser_t; - class group_parser_t : constr_parser_t { + struct ast_ctx_t { private: - struct named_parser { - constr_parser_t *parser; - std::string name; + using named_parser_t = std::pair; + + struct parser_proxy_t { + private: + ast_ctx_t &parent; + public: + parser_t &operator[](const std::string &name) const; + parser_proxy_t(ast_ctx_t &parent): parent(parent) { } }; - std::list parsers; - std::unordered_map insertion_points; + + struct group_proxy_t { + private: + ast_ctx_t &parent; + public: + group_parser_t &operator[](const std::string &name) const; + group_proxy_t(ast_ctx_t &parent): parent(parent) { } + }; + + std::unordered_map parsers; + std::set groups; + public: - void add_insertion_point(constr_parser_t &parser, const std::string &name); - void add(constr_parser_t &parser); - void add(const std::string &ins_point, constr_parser_t &parser); + msg_stack_t &messages; + std::vector &tokens; - bool parse(messages::msg_stack_t &messages, data::map_t &out); + void add_parser(std::string name, parser_t &parser); + void add_parser(std::string name, group_parser_t &parser); - group_parser_t(); + const parser_proxy_t parser; + const group_proxy_t group; + + ast_ctx_t(msg_stack_t &messages, std::vector tokens): + messages(messages), + tokens(tokens), + parser(*this), + group(*this) { } }; - extern const constr_parser_t &glob_parser; + class parser_t { + private: + std::string _name; + public: + const std::string &name() { return _name; } + virtual bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) const = 0; + bool operator()(ast_ctx_t &ctx, size_t &i, data::map_t &out) const { + return parse(ctx, i, out); + } + }; + + class group_parser_t : public parser_t { + private: + std::vector> named_parsers; + std::vector parsers; + public: + group_parser_t &add(parser_t &parser); + group_parser_t &add(parser_t &parser, const lang::namespace_name_t &name); + + bool parse(ast_ctx_t &ctx, size_t &i, data::map_t &out) const; + }; + + extern const parser_t &glob_parser; + + const group_parser_t &get_group(std::string name); } \ No newline at end of file diff --git a/include/compiler/treeifier/ast/helper.hh b/include/compiler/treeifier/ast/helper.hh new file mode 100644 index 0000000..9d64d7e --- /dev/null +++ b/include/compiler/treeifier/ast/helper.hh @@ -0,0 +1,75 @@ +#include "compiler/treeifier/ast.hh" + +namespace ppc::comp::tree::ast { + struct tree_helper_t { + private: + ast_ctx_t &ctx; + size_t &res_i; + size_t i; + public: + void submit() { + res_i = i; + } + + bool ended() { + return i == ctx.tokens.size(); + } + + tok::token_t &curr() { return ctx.tokens[i]; } + + location_t next_loc(size_t n = 1) { + location_t res = loc(); + res.start += res.length; + res.code_start += res.length; + res.length = n; + return res; + } + location_t loc() { + if (ended()) { + if (i == 0) return location_t::NONE; + + location_t loc = ctx.tokens[i - 1].location; + + loc.start += loc.length; + loc.code_start += loc.length; + loc.length = 1; + + return loc; + } + else return curr().location; + } + + bool try_parse(const parser_t &parser, data::map_t &out, messages::msg_stack_t &messages) { + try { + return parser(ctx, i, out); + } + catch (messages::message_t msg) { + messages.push(msg); + return false; + } + } + bool try_parse(const parser_t &parser, data::map_t &out) { + try { + return parser(ctx, i, out); + } + catch (messages::message_t msg) { + return false; + } + } + + bool try_advance() { + if (ended()) return false; + i++; + return !ended(); + } + bool advance() { + if (ended()) throw messages::message_t(message_t::ERROR, "Unexpected end.", loc()); + i++; + if (ended()) throw messages::message_t(message_t::ERROR, "Unexpected end.", loc()); + } + + tree_helper_t(ast_ctx_t &ctx, size_t &i): ctx(ctx), res_i(i) { + this->i = i; + } + }; +} \ No newline at end of file diff --git a/include/lang/common.hh b/include/lang/common.hh index 5e2fba2..75d7801 100644 --- a/include/lang/common.hh +++ b/include/lang/common.hh @@ -4,11 +4,31 @@ #include "utils/location.hh" namespace ppc::lang { + template + struct located_t : T { + location_t location; + + template + located_t(location_t loc, Args ...args): T(args...), location(loc) { } + template + located_t(Args ...args): T(args...), location(location_t::NONE) { } + }; + struct namespace_name_t { std::vector segments; - ppc::location_t location; - bool operator ==(const namespace_name_t &other); + bool is_empty() const { return segments.empty(); } + + auto begin() { return segments.begin(); } + auto end() { return segments.end(); } + + bool operator ==(const namespace_name_t &other) const; + const std::string &operator[](size_t i) const { return segments[i]; } + + std::string to_string() const; + + namespace_name_t() { } + namespace_name_t(std::initializer_list segments): segments(segments.begin(), segments.end()) { } }; bool is_identifier_valid(messages::msg_stack_t &msg_stack, ppc::location_t location, const std::string &name); diff --git a/include/utils/message.hh b/include/utils/message.hh index 60f7657..4223d3a 100644 --- a/include/utils/message.hh +++ b/include/utils/message.hh @@ -14,8 +14,8 @@ namespace ppc::messages { WARNING, ERROR, } level; - location_t location; std::string content; + location_t location; message_t(level_t level, std::string content, location_t loc = location_t::NONE) : level(level), diff --git a/include/utils/slice.hh b/include/utils/slice.hh deleted file mode 100644 index 7a9fa33..0000000 --- a/include/utils/slice.hh +++ /dev/null @@ -1,54 +0,0 @@ -#include - -namespace ppc { - template - class slice_t { - private: - T *iterable; - std::size_t start; - std::size_t n; - public: - auto begin() const { return iterable->begin() + start; } - auto end() const { return iterable->end() + start + n; } - - auto size() const { return n; } - auto &operator[](std::size_t i) const { return (iterable*)[start + i]; } - - slice_t(T &iterable, std::size_t start, std::size_t n) { - this->iterable = &iterable; - this->start = start; - this->n = n; - if (n == -1u) this->n = iterable.size() - start; - } - }; - - template - using vec_slice_t = slice_t>; - - - template - inline slice_t slice(slice_t &sl) { - return slice_t(sl.iterable, sl.start, sl.n); - } - template - inline slice_t slice(slice_t &sl, std::size_t start) { - return slice_t(sl.iterable, sl.start + start, sl.n); - } - template - inline slice_t slice(slice_t &sl, std::size_t start, std::size_t n) { - return slice_t(sl.iterable, sl.start + start, n); - } - - template - inline slice_t slice(T &vec) { - return slice_t(vec, 0, vec.size()); - } - template - inline slice_t slice(T &vec, std::size_t start) { - return slice_t(vec, start, vec.size()); - } - template - inline slice_t slice(T &vec, std::size_t start, std::size_t n) { - return slice_t(vec, start, n); - } -} \ No newline at end of file diff --git a/src/compiler/treeifier/ast.cc b/src/compiler/treeifier/ast.cc index 04e224d..1805400 100644 --- a/src/compiler/treeifier/ast.cc +++ b/src/compiler/treeifier/ast.cc @@ -1 +1,27 @@ #include "compiler/treeifier/ast.hh" + +namespace ppc::comp::tree::ast { + std::unordered_map parsers; + + parser_t &ast_ctx_t::parser_proxy_t::operator[](const std::string &name) const { + auto it = parent.parsers.find(name); + if (it == parent.parsers.end()) throw "The parser '" + name + "' doesn't exist."; + return *it->second; + } + group_parser_t &ast_ctx_t::group_proxy_t::operator[](const std::string &name) const { + parser_t *p = &parent.parser[name]; + if (parent.groups.find(p) == parent.groups.end()) throw "A parser '" + name + "' exists, but isn't a group."; + return *(group_parser_t*)p; + } + + void ast_ctx_t::add_parser(std::string name, parser_t &parser) { + if (parsers.find(name) != parsers.end()) throw "The parser '" + name + "' already exists."; + parsers[name] = &parser; + } + void ast_ctx_t::add_parser(std::string name, group_parser_t &parser) { + if (parsers.find(name) != parsers.end()) throw "The parser '" + name + "' already exists."; + parsers[name] = &parser; + groups.emplace(&parser); + } +} + diff --git a/src/compiler/treeifier/parsers/glob.cc b/src/compiler/treeifier/parsers/glob.cc index bd30023..a4627b8 100644 --- a/src/compiler/treeifier/parsers/glob.cc +++ b/src/compiler/treeifier/parsers/glob.cc @@ -1,11 +1,11 @@ #include "compiler/treeifier/ast.hh" namespace ppc::comp::tree::ast { - class glob_parser_t : public constr_parser_t { - bool parse(messages::msg_stack_t &messages, vec_slice_t &tokens, data::map_t &out) { - + class glob_parser_t : public parser_t { + bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) const { + return false; } }; - const constr_parser_t &glob_parser = glob_parser_t(); + const parser_t &glob_parser = glob_parser_t(); } diff --git a/src/compiler/treeifier/parsers/group.cc b/src/compiler/treeifier/parsers/group.cc new file mode 100644 index 0000000..3471c78 --- /dev/null +++ b/src/compiler/treeifier/parsers/group.cc @@ -0,0 +1,20 @@ +#include "compiler/treeifier/ast.hh" +#include + +using namespace ppc::comp::tree::ast; +using namespace std::string_literals; + +group_parser_t &group_parser_t::add(parser_t &parser) { + parsers.push_back(&parser); + return *this; +} +group_parser_t &group_parser_t::add(parser_t &parser, const lang::namespace_name_t &name) { + if (name.is_empty()) throw "Name can't be empty."s; + if (std::find(parsers.begin(), parsers.end(), &parser) != parsers.end()) { + throw "Parser '" + name.to_string() + "' already in group."; + } + + named_parsers.push_back({ name, &parser }); + + return *this; +} diff --git a/src/lang/common.cc b/src/lang/common.cc new file mode 100644 index 0000000..7b6c9f5 --- /dev/null +++ b/src/lang/common.cc @@ -0,0 +1,27 @@ + +#include +#include "lang/common.hh" + +namespace ppc::lang { + std::string namespace_name_t::to_string() const { + std::stringstream res; + + for (size_t i = 0; i < segments.size(); i++) { + if (i != 0) res << "::"; + res << segments[i]; + } + + return res.str(); + } + + bool namespace_name_t::operator==(const namespace_name_t &other) const { + if (other.segments.size() != segments.size()) return false; + + for (size_t i = 0; i < segments.size(); i++) { + if (other[i] != segments[i]) return false; + } + + return true; + } +} +