#ifndef RUBY_PARSER_DRIVER_HH #define RUBY_PARSER_DRIVER_HH #include #include "diagnostic.hh" #include "lexer.hh" #include "node.hh" namespace ruby_parser { struct builder; using ForeignPtr = const void *; using SelfPtr = const void *; struct node_list { node_list() = default; node_list(ForeignPtr node) { nodes.emplace_back(node); } node_list &operator=(const ForeignPtr &other) = delete; node_list &operator=(ForeignPtr &&other) = delete; inline size_t size() const { return nodes.size(); } inline void emplace_back(const ForeignPtr &ptr) { nodes.emplace_back(ptr); } inline void push_front(const ForeignPtr &ptr) { nodes.insert(nodes.begin(), ptr); } inline ForeignPtr &at(size_t n) { return nodes.at(n); } inline void concat(node_list *other) { nodes.insert(nodes.end(), std::make_move_iterator(other->nodes.begin()), std::make_move_iterator(other->nodes.end())); } protected: std::vector nodes; }; struct delimited_node_list { delimited_node_list() = default; delimited_node_list(const token_t &begin, node_list *inner, const token_t &end) : begin(begin), inner(inner), end(end) {} token_t begin = nullptr; node_list *inner = nullptr; token_t end = nullptr; }; struct delimited_block { delimited_block() = default; delimited_block(const token_t &begin, ForeignPtr args, ForeignPtr body, const token_t &end) : begin(begin), args(args), body(body), end(end) {} token_t begin = nullptr; ForeignPtr args = nullptr; ForeignPtr body = nullptr; token_t end = nullptr; }; struct node_with_token { node_with_token() = default; node_with_token(const token_t &token_, ForeignPtr node_) : tok(token_), nod(node_) {} token_t tok = nullptr; ForeignPtr nod = nullptr; }; struct case_body { case_body() = default; case_body(node_with_token *else_) : els(else_) {} node_list whens; node_with_token *els = nullptr; }; class mempool { pool _node_list; pool _delimited_node_list; pool _delimited_block; pool _node_with_token; pool _case_body; pool _stacks; friend class base_driver; public: mempool() = default; template ruby_parser::node_list *node_list(Args &&... args) { return _node_list.alloc(std::forward(args)...); } template ruby_parser::delimited_node_list *delimited_node_list(Args &&... args) { return _delimited_node_list.alloc(std::forward(args)...); } template ruby_parser::delimited_block *delimited_block(Args &&... args) { return _delimited_block.alloc(std::forward(args)...); } template ruby_parser::node_with_token *node_with_token(Args &&... args) { return _node_with_token.alloc(std::forward(args)...); } template ruby_parser::case_body *case_body(Args &&... args) { return _case_body.alloc(std::forward(args)...); } }; class base_driver { public: diagnostics_t diagnostics; const builder &build; lexer lex; mempool alloc; bool pending_error; size_t def_level; ForeignPtr ast; token_t last_token; base_driver(ruby_version version, const std::string &source, const struct builder &builder); virtual ~base_driver() {} virtual ForeignPtr parse(SelfPtr self) = 0; bool valid_kwarg_name(const token *name) { char c = name->string().at(0); return !(c >= 'A' && c <= 'Z'); } ruby_parser::state_stack *copy_stack() { return alloc._stacks.alloc(lex.cmdarg); } void replace_stack(ruby_parser::state_stack *stack) { lex.cmdarg = *stack; } void external_diagnostic(dlevel lvl, dclass cls, size_t begin, size_t end, const std::string &msg) { diagnostics.emplace_back(lvl, cls, diagnostic::range(begin, end), msg); if (lvl == dlevel::ERROR) { pending_error = true; } } }; class typedruby25 : public base_driver { public: typedruby25(const std::string &source, const struct builder &builder); virtual ForeignPtr parse(SelfPtr self); ~typedruby25() {} }; } // namespace ruby_parser #endif