From 918f1c8d7868ddb7e0fbd73fe934b92fa307fb22 Mon Sep 17 00:00:00 2001 From: CFU9 Date: Thu, 26 Nov 2020 14:21:24 +0100 Subject: [PATCH 01/17] added Ast classes for treesitter --- include/MiniLua/tree_sitter_ast.hpp | 198 ++++++++++++++++++++++++++++ src/core/tree_sitter_ast.cpp | 5 + tests/tree_sitter_ast_tests.cpp | 3 + 3 files changed, 206 insertions(+) create mode 100644 include/MiniLua/tree_sitter_ast.hpp create mode 100644 src/core/tree_sitter_ast.cpp create mode 100644 tests/tree_sitter_ast_tests.cpp diff --git a/include/MiniLua/tree_sitter_ast.hpp b/include/MiniLua/tree_sitter_ast.hpp new file mode 100644 index 00000000..1a46e6d1 --- /dev/null +++ b/include/MiniLua/tree_sitter_ast.hpp @@ -0,0 +1,198 @@ + +#ifndef MINILUA_TREE_SITTER_AST_HPP +#define MINILUA_TREE_SITTER_AST_HPP +#include +namespace lua { +namespace rt { +enum class BinOpEnum { ADD, SUB, MUL, DIV, MOD, POW, LT, GT, LEQ, GEQ, EQ, NEQ, CONCAT, AND, OR, BSL, BSR, BWNOT, BWOR, BWAND, INTDIV}; +class Expression {}; +class BinaryOperation { + ts::Node left_node; + ts::Node right_node; + ts::Node op_node; + +public: + BinaryOperation(ts::Node node); + auto left() -> ts::Node; + auto right() -> ts::Node; + auto op() -> BinOpEnum; +}; +enum class UnOpEnum { NOT, NEG }; +class UnaryOperation { + ts::Node operand_node; + ts::Node operator_node; + +public: + UnaryOperation(ts::Node node); + auto op() -> UnOpEnum; + auto exp() -> ts::Node; +}; +class ForStatement { + ts::Node loop_expression; + std::vector loop_body; + // TODO loopexpression into forstatement +public: + ForStatement(ts::Node node); + auto loop_exp() -> ts::Node; + auto body() -> std::vector; +}; +class LoopExpression { + ts::Node loop_var; + ts::Node start_val; + std::optional step_val; + ts::Node end_val; +public: + LoopExpression(ts::Node); + auto variable() -> ts::Node; + auto start() -> ts::Node; + auto step() -> std::optional; + auto end() -> ts::Node; +}; +class ForInStatement { + std::vector loop_exp_namelist; + std::vector loop_exp_explist; + std::vector loop_body; +public: + ForInStatement(ts::Node); + auto body() -> ts::Node; + auto loop_vars() -> std::vector; + auto loop_exps() -> std::vector; +}; +class WhileStatement { + ts::Node exit_condition; + std::vector loop_body; + +public: + WhileStatement(ts::Node node); + auto exit_cond() -> ts::Node; + auto body() -> std::vector; +}; +class RepeatStatement { + ts::Node until_condition; + std::vector loop_body; + +public: + RepeatStatement(ts::Node node); + auto until_cond() -> ts::Node; + auto body() -> std::vector; +}; +class IfStatement { + ts::Node condition; + std::vector if_body; + std::vector elseif_statements; + std::optional else_node; + +public: + IfStatement(ts::Node node); + auto body() -> std::vector; + auto elseifs() -> std::vector; + auto cond() -> ts::Node; + auto else_() -> std::optional; +}; + +class ElseIf{ + ts::Node condition; + std::vector else_if_body; +public: + auto body() -> std::vector; + auto cond() -> ts::Node; +}; +class Else{ + std::vector else_body; +public: + Else(ts::Node); + auto body() -> std::vector; +}; + +class Return{ + std::vector expression_list; +public: + Return(ts::Node node); + auto explist() -> std::vector; +}; +class VariableDeclaration{ + std::vector variable_declarators; + std::vector variable_declarations; +public: + VariableDeclaration(ts::Node node); + auto declarators() -> std::vector; + auto declarations() -> std::vector; +}; +class VariableDeclarator{ + ts::Node variable; +public: + VariableDeclarator(ts::Node node); + auto var() -> ts::Node; +}; +class LocalVariableDeclaration{ + ts::Node variable_declarator; + std::vector variable_declarations; +public: + LocalVariableDeclaration(ts::Node node); + auto declarations() -> std::vector; +}; +class LocalVariableDeclarator{ + std::vector variables; +public: + LocalVariableDeclarator(ts::Node node); + auto vars() -> std::vector; +}; +class FieldExpression{ + ts::Node table_identifier; + ts::Node property_identifier; +public: + FieldExpression(ts::Node); + auto table_id() -> ts::Node; + auto property_id() -> ts::Node; +}; +class DoStatement{ + std::vector do_body; +public: + DoStatement(ts::Node); + auto body() -> std::vector; +}; +class GoTo{ + ts::Node identifier; +public: + GoTo(ts::Node node); + auto id() -> ts::Node; +}; +class Label{ + ts::Node identifier; +public: + Label(ts::Node node); + auto id() -> ts::Node; +}; +class Function { + ts::Node function_name; + std::vector parameters; + std::vector function_body; +}; +class FunctionName{ + std::vector table_references; + ts::Node name; + bool method; +}; +class LocalFunction { + ts::Node local_function_name; + std::vector parameters; + std::vector function_body; +}; +class FunctionCall{ + std::optional table_reference; + ts::Node function_name; + bool method; + std::vector arguments; + +}; +enum GV {_G,_VERSION}; +class GlobalVariable{ + GV type; +}; +class Table{ + std::vector fields; +}; +} // namespace rt +} // namespace lua + +#endif // MINILUA_TREE_SITTER_AST_HPP diff --git a/src/core/tree_sitter_ast.cpp b/src/core/tree_sitter_ast.cpp new file mode 100644 index 00000000..c3d19f51 --- /dev/null +++ b/src/core/tree_sitter_ast.cpp @@ -0,0 +1,5 @@ +// +// Created by clemens on 16.09.20. +// + +#include "tree_sitter_ast.hpp" diff --git a/tests/tree_sitter_ast_tests.cpp b/tests/tree_sitter_ast_tests.cpp new file mode 100644 index 00000000..2092d130 --- /dev/null +++ b/tests/tree_sitter_ast_tests.cpp @@ -0,0 +1,3 @@ +// +// Created by clemens on 16.09.20. +// From 6751bb55085576ec27b81de8f51641dcc69e0836 Mon Sep 17 00:00:00 2001 From: CFU9 Date: Thu, 17 Dec 2020 16:10:03 +0100 Subject: [PATCH 02/17] Updated ast_classes --- include/MiniLua/tree_sitter_ast.hpp | 287 ++++++++++------ include/tree_sitter/tree_sitter.hpp | 22 +- src/core/tree_sitter_ast.cpp | 512 +++++++++++++++++++++++++++- tests/CMakeLists.txt | 2 +- 4 files changed, 709 insertions(+), 114 deletions(-) diff --git a/include/MiniLua/tree_sitter_ast.hpp b/include/MiniLua/tree_sitter_ast.hpp index 1a46e6d1..74f6cbd4 100644 --- a/include/MiniLua/tree_sitter_ast.hpp +++ b/include/MiniLua/tree_sitter_ast.hpp @@ -2,197 +2,286 @@ #ifndef MINILUA_TREE_SITTER_AST_HPP #define MINILUA_TREE_SITTER_AST_HPP #include -namespace lua { -namespace rt { -enum class BinOpEnum { ADD, SUB, MUL, DIV, MOD, POW, LT, GT, LEQ, GEQ, EQ, NEQ, CONCAT, AND, OR, BSL, BSR, BWNOT, BWOR, BWAND, INTDIV}; -class Expression {}; +#include +namespace minilua{ +namespace details { +class Expression; +class Statement; +class Prefix; +class Return; +class Body{ + std::vector nodes; +public: + Body(std::vector); + auto statements() -> std::vector; + auto ret() -> std::optional; +}; +class Identifier { + ts::Node node; +public: + Identifier(ts::Node); +}; +enum class BinOpEnum { + ADD, + SUB, + MUL, + DIV, + MOD, + POW, + LT, + GT, + LEQ, + GEQ, + EQ, + NEQ, + CONCAT, + AND, + OR, + BSL, + BSR, + BWNOT, + BWOR, + BWAND, + INTDIV +}; + class BinaryOperation { - ts::Node left_node; - ts::Node right_node; - ts::Node op_node; + ts::Node bin_op; public: BinaryOperation(ts::Node node); - auto left() -> ts::Node; - auto right() -> ts::Node; + auto left() -> Expression; + auto right() -> Expression; auto op() -> BinOpEnum; }; -enum class UnOpEnum { NOT, NEG }; +enum class UnOpEnum { NOT, NEG, LEN, BWNOT }; class UnaryOperation { - ts::Node operand_node; - ts::Node operator_node; + ts::Node un_op; public: UnaryOperation(ts::Node node); auto op() -> UnOpEnum; - auto exp() -> ts::Node; + auto exp() -> Expression; }; class ForStatement { - ts::Node loop_expression; - std::vector loop_body; - // TODO loopexpression into forstatement + ts::Node for_statement; + public: ForStatement(ts::Node node); auto loop_exp() -> ts::Node; - auto body() -> std::vector; + auto body() -> Body; }; class LoopExpression { - ts::Node loop_var; - ts::Node start_val; - std::optional step_val; - ts::Node end_val; + ts::Node loop_exp; + public: LoopExpression(ts::Node); - auto variable() -> ts::Node; - auto start() -> ts::Node; - auto step() -> std::optional; - auto end() -> ts::Node; + auto variable() -> Identifier; + auto start() -> Expression; + auto step() -> std::optional; + auto end() -> Expression; +}; +class InLoopExpression{ + ts::Node loop_exp; +public: + InLoopExpression(ts::Node); + auto loop_vars() -> std::vector; + auto loop_exps() -> std::vector; }; class ForInStatement { - std::vector loop_exp_namelist; - std::vector loop_exp_explist; - std::vector loop_body; + ts::Node for_in; public: ForInStatement(ts::Node); - auto body() -> ts::Node; - auto loop_vars() -> std::vector; - auto loop_exps() -> std::vector; + auto body() -> std::vector; + auto loop_exp() -> InLoopExpression; + auto ret() -> std::optional; }; class WhileStatement { + ts::Node while_statement; ts::Node exit_condition; std::vector loop_body; public: WhileStatement(ts::Node node); - auto exit_cond() -> ts::Node; - auto body() -> std::vector; + auto exit_cond() -> Expression; + auto body() -> Body; }; class RepeatStatement { + ts::Node repeat_statement; ts::Node until_condition; std::vector loop_body; public: RepeatStatement(ts::Node node); - auto until_cond() -> ts::Node; - auto body() -> std::vector; + auto until_cond() -> Expression; + auto body() -> Body; }; -class IfStatement { - ts::Node condition; - std::vector if_body; - std::vector elseif_statements; - std::optional else_node; +class ElseIf { + ts::Node else_if; public: - IfStatement(ts::Node node); - auto body() -> std::vector; - auto elseifs() -> std::vector; - auto cond() -> ts::Node; - auto else_() -> std::optional; + ElseIf(ts::Node); + auto body() -> Body; + auto cond() -> Expression; }; - -class ElseIf{ - ts::Node condition; - std::vector else_if_body; +class Else { + ts::Node else_statement; public: - auto body() -> std::vector; - auto cond() -> ts::Node; + Else(ts::Node); + auto body() -> Body; }; -class Else{ - std::vector else_body; +class IfStatement { + ts::Node if_statement; + public: - Else(ts::Node); - auto body() -> std::vector; + IfStatement(ts::Node node); + auto body() -> Body; + auto elseifs() -> std::vector; + auto cond() -> Expression; + auto else_() -> std::optional; }; +//Return +class Return { + ts::Node expressions; -class Return{ - std::vector expression_list; public: Return(ts::Node node); - auto explist() -> std::vector; + auto explist() -> std::vector; }; -class VariableDeclaration{ - std::vector variable_declarators; - std::vector variable_declarations; -public: - VariableDeclaration(ts::Node node); - auto declarators() -> std::vector; - auto declarations() -> std::vector; +//TableIndex +class TableIndex{ + }; -class VariableDeclarator{ - ts::Node variable; +class VariableDeclarator { + ts::Node dec; public: VariableDeclarator(ts::Node node); - auto var() -> ts::Node; + auto var() -> std::variant; }; -class LocalVariableDeclaration{ - ts::Node variable_declarator; - std::vector variable_declarations; +class VariableDeclaration { + ts::Node var_dec; public: - LocalVariableDeclaration(ts::Node node); - auto declarations() -> std::vector; + VariableDeclaration(ts::Node node); + auto declarators() -> std::vector; + auto declarations() -> std::vector; }; -class LocalVariableDeclarator{ - std::vector variables; +class LocalVariableDeclarator { + ts::Node var_dec; public: LocalVariableDeclarator(ts::Node node); - auto vars() -> std::vector; + auto vars() -> std::vector; +}; + +class LocalVariableDeclaration { + ts::Node local_var_dec; + +public: + LocalVariableDeclaration(ts::Node node); + auto declarator() -> LocalVariableDeclarator; + auto declarations() -> std::vector; }; -class FieldExpression{ + +class FieldExpression { ts::Node table_identifier; ts::Node property_identifier; + public: FieldExpression(ts::Node); - auto table_id() -> ts::Node; - auto property_id() -> ts::Node; + auto table_id() -> Prefix; + auto property_id() -> Identifier; }; -class DoStatement{ - std::vector do_body; +class DoStatement { + std::vector do_statement; public: DoStatement(ts::Node); - auto body() -> std::vector; + auto body() -> Body; }; -class GoTo{ - ts::Node identifier; +class GoTo { + ts::Node go_to; + public: GoTo(ts::Node node); - auto id() -> ts::Node; + auto label() -> Identifier; }; -class Label{ - ts::Node identifier; +class Label { + ts::Node label; + public: Label(ts::Node node); - auto id() -> ts::Node; + auto identifier() -> Identifier; }; -class Function { +class FunctionDefinition { + +}; + +class FunctionStatement { ts::Node function_name; std::vector parameters; std::vector function_body; }; -class FunctionName{ +class FunctionName { std::vector table_references; ts::Node name; bool method; }; -class LocalFunction { +class LocalFunctionStatement { ts::Node local_function_name; std::vector parameters; std::vector function_body; }; -class FunctionCall{ +class FunctionCall { std::optional table_reference; ts::Node function_name; bool method; std::vector arguments; - }; -enum GV {_G,_VERSION}; -class GlobalVariable{ +enum GV { _G, _VERSION }; +class GlobalVariable { GV type; }; -class Table{ - std::vector fields; +class Table { + ts::Node table; +public: + Table(ts::Node); + auto +}; +class Spread {}; +class Self {}; +class Next {}; +class String {}; +class Number {}; +class Nil {}; +class True {}; +class False {}; + +class Prefix { + ts::Node prefix; +public: + Prefix(ts::Node); + auto options() + -> std::variant; +}; +class Expression { + ts::Node exp; +public: + Expression(ts::Node); + auto options() -> std::variant< + Spread, Prefix, Next, Function, Table, BinaryOperation, UnaryOperation, String, Number, Nil, + True, False, Identifier>; +}; +class Break {}; +class Empty {}; +class Statement { + ts::Node statement; + +public: + Statement(ts::Node); + auto options() -> std::variant< + VariableDeclaration, LocalVariableDeclaration, DoStatement, IfStatement, WhileStatement, + RepeatStatement, ForStatement, ForInStatement, GoTo, Break, Label, Empty, Function, + LocalFunction, FunctionCall, Expression>; }; -} // namespace rt -} // namespace lua +} +} #endif // MINILUA_TREE_SITTER_AST_HPP diff --git a/include/tree_sitter/tree_sitter.hpp b/include/tree_sitter/tree_sitter.hpp index e52b1b3d..18fd0a61 100644 --- a/include/tree_sitter/tree_sitter.hpp +++ b/include/tree_sitter/tree_sitter.hpp @@ -306,17 +306,17 @@ const TypeId NODE_LOCAL_VARIABLE_DECLARATION = const TypeId NODE_FIELD_EXPRESSION = LUA_LANGUAGE.node_type_id("field_expression", true); const TypeId NODE_VARIABLE_DECLARATOR = LUA_LANGUAGE.node_type_id("variable_declarator", true); const TypeId NODE_DO_STATEMENT = LUA_LANGUAGE.node_type_id("do_statement", true); -const TypeId NODE_IF_STATEMENT = LUA_LANGUAGE.node_type_id("if_statement", true); -const TypeId NODE_ELSEIF = LUA_LANGUAGE.node_type_id("elseif", true); -const TypeId NODE_ELSE = LUA_LANGUAGE.node_type_id("else", true); -const TypeId NODE_WHILE_STATEMENT = LUA_LANGUAGE.node_type_id("while_statement", true); -const TypeId NODE_REPEAT_STATEMENT = LUA_LANGUAGE.node_type_id("repeat_statement", true); -const TypeId NODE_FOR_STATEMENT = LUA_LANGUAGE.node_type_id("for_statement", true); +const TypeId NODE_IF_STATEMENT = LUA_LANGUAGE.node_type_id("if_statement", true);// +const TypeId NODE_ELSEIF = LUA_LANGUAGE.node_type_id("elseif", true);// +const TypeId NODE_ELSE = LUA_LANGUAGE.node_type_id("else", true);// +const TypeId NODE_WHILE_STATEMENT = LUA_LANGUAGE.node_type_id("while_statement", true);// +const TypeId NODE_REPEAT_STATEMENT = LUA_LANGUAGE.node_type_id("repeat_statement", true);// +const TypeId NODE_FOR_STATEMENT = LUA_LANGUAGE.node_type_id("for_statement", true);// const TypeId NODE_FOR_IN_STATEMENT = LUA_LANGUAGE.node_type_id("for_in_statement", true); -const TypeId NODE_LOOP_EXPRESSION = LUA_LANGUAGE.node_type_id("loop_expression", true); +const TypeId NODE_LOOP_EXPRESSION = LUA_LANGUAGE.node_type_id("loop_expression", true);// const TypeId NODE_GOTO_STATEMENT = LUA_LANGUAGE.node_type_id("goto_statement", true); const TypeId NODE_LABEL_STATEMENT = LUA_LANGUAGE.node_type_id("label_statement", true); -const TypeId NODE_FUNCTION = LUA_LANGUAGE.node_type_id("function", true); +const TypeId NODE_FUNCTION = LUA_LANGUAGE.node_type_id("function", true);// const TypeId NODE_LOCAL_FUNCTION = LUA_LANGUAGE.node_type_id("local_function", true); const TypeId NODE_FUNCTION_CALL = LUA_LANGUAGE.node_type_id("function_call", true); const TypeId NODE_ARGUMENTS = LUA_LANGUAGE.node_type_id("ARGUMENTS", true); @@ -327,8 +327,8 @@ const TypeId NODE_GLOBAL_VARIABLE = LUA_LANGUAGE.node_type_id("global_variable", const TypeId NODE_FUNCTION_DEFINITION = LUA_LANGUAGE.node_type_id("function_definition", true); const TypeId NODE_TABLE = LUA_LANGUAGE.node_type_id("table", true); const TypeId NODE_FIELD = LUA_LANGUAGE.node_type_id("field", true); -const TypeId NODE_BINARY_OPERATION = LUA_LANGUAGE.node_type_id("binary_operation", true); -const TypeId NODE_UNARY_OPERATION = LUA_LANGUAGE.node_type_id("unary_operation", true); +const TypeId NODE_BINARY_OPERATION = LUA_LANGUAGE.node_type_id("binary_operation", true);// +const TypeId NODE_UNARY_OPERATION = LUA_LANGUAGE.node_type_id("unary_operation", true);// const TypeId NODE_CONDITION_EXPRESSION = LUA_LANGUAGE.node_type_id("condition_expression", true); const TypeId NODE_EXPRESSION = LUA_LANGUAGE.node_type_id("expression", true); const TypeId NODE_METHOD = LUA_LANGUAGE.node_type_id("method", true); @@ -380,7 +380,9 @@ class Node { struct unsafe_t {}; // used as a token for the unsafe constructor constexpr static unsafe_t unsafe{}; + Node(){ + } /** * Creates a new node from the given tree-sitter node and the tree. * diff --git a/src/core/tree_sitter_ast.cpp b/src/core/tree_sitter_ast.cpp index c3d19f51..b73203c1 100644 --- a/src/core/tree_sitter_ast.cpp +++ b/src/core/tree_sitter_ast.cpp @@ -1,5 +1,509 @@ -// -// Created by clemens on 16.09.20. -// +#include "MiniLua/tree_sitter_ast.hpp" +#include +#include +#include +using namespace std::string_literals; +namespace minilua { +namespace details { +//Body +Body::Body(std::vector node_vec) : nodes(node_vec) { -#include "tree_sitter_ast.hpp" +} +auto Body::ret() -> std::optional { + if(nodes[nodes.size()-1].type_id()==ts::NODE_RETURN_STATEMENT){ + return Return(nodes[nodes.size()-1]); + }else{ + return {}; + } +} +auto Body::statements() -> std::vector { + std::vector::iterator end; + std::vector res; + if((nodes.end()-1) -> type_id() == ts::NODE_RETURN_STATEMENT){ + res.reserve(nodes.size()-1); + end = nodes.end()-1; + }else{ + res.reserve(nodes.size()); + end = nodes.end(); + } + std::transform(nodes.begin(),end,std::back_inserter(res),[](ts::Node node){return Statement(node);}); + return res; +} +// BinOpEnum +std::ostream& operator<<(std::ostream& os, BinOpEnum& binOpEnum) { + switch (binOpEnum) { + case BinOpEnum::ADD: + return os << '+'; + case BinOpEnum::SUB: + return os << '-'; + case BinOpEnum::MUL: + return os << '*'; + case BinOpEnum::DIV: + return os << '/'; + case BinOpEnum::POW: + return os << '^'; + case BinOpEnum::MOD: + return os << '%'; + case BinOpEnum::LEQ: + return os << "<="; + case BinOpEnum::GEQ: + return os << ">="; + case BinOpEnum::EQ: + return os << "=="; + case BinOpEnum::LT: + return os << '<'; + case BinOpEnum::GT: + return os << '>'; + case BinOpEnum::NEQ: + return os << "~="; + case BinOpEnum::AND: + return os << "and"; + case BinOpEnum::OR: + return os << "or"; + case BinOpEnum::CONCAT: + return os << ".."; + } +}; +// BinaryOperation +BinaryOperation::BinaryOperation(ts::Node node) : bin_op(node) { + if (node.type_id() != ts::NODE_BINARY_OPERATION || node.child_count() != 3) { + throw std::runtime_error("not a binary_operation node"); + } +} +// TODO +auto BinaryOperation::left() -> Expression { return Expression(bin_op.child(0).value()); } +auto BinaryOperation::right() -> Expression { return Expression(bin_op.child(2).value()); } +auto BinaryOperation::op() -> BinOpEnum { + std::string op_str = bin_op.child(1)->text(); + if (op_str == "+"s) { + return BinOpEnum::ADD; + } else if (op_str == "-"s) { + return BinOpEnum::SUB; + } else if (op_str == "/"s) { + return BinOpEnum::DIV; + } else if (op_str == "*"s) { + return BinOpEnum::MUL; + } else if (op_str == "%"s) { + return BinOpEnum::MOD; + } else if (op_str == "^"s) { + return BinOpEnum::POW; + } else if (op_str == "<"s) { + return BinOpEnum::LT; + } else if (op_str == ">"s) { + return BinOpEnum::GT; + } else if (op_str == "<="s) { + return BinOpEnum::LEQ; + } else if (op_str == ">="s) { + return BinOpEnum::GEQ; + } else if (op_str == "==") { + return BinOpEnum::EQ; + } else if (op_str == "~="s) { + return BinOpEnum::NEQ; + } else if (op_str == ".."s) { + return BinOpEnum::CONCAT; + } else if (op_str == "and"s) { + return BinOpEnum::AND; + } else if (op_str == "or"s) { + return BinOpEnum::OR; + } else if (op_str == "<<"s) { + return BinOpEnum::BSL; + } else if (op_str == ">>"s) { + return BinOpEnum::BSR; + } else if (op_str == "//"s) { + return BinOpEnum::INTDIV; + } else if (op_str == "|"s) { + return BinOpEnum::BWOR; + } else if (op_str == "&"s) { + return BinOpEnum::BWAND; + } else if (op_str == "~"s) { + return BinOpEnum::BWNOT; + } else { + throw std::runtime_error("Unknown Binary Operator: " + op_str); + } +} +/*std::ostream& operator<<(std::ostream& os, BinaryOperation& binaryOperation){ + return os << binaryOperation.left().type() << (int)binaryOperation.op() << +binaryOperation.right().type(); +}*/ +// UnaryOperation +UnaryOperation::UnaryOperation(ts::Node node) : un_op(node) { + if (node.type_id() != ts::NODE_UNARY_OPERATION || node.child_count() != 2) { + throw std::runtime_error("not an unary_operation node"); + } +} + +auto UnaryOperation::op() -> UnOpEnum { + if (this->un_op.child(0)->text() == "not"s) { + return UnOpEnum::NOT; + } else if (this->un_op.child(0)->text() == "-"s) { + return UnOpEnum::NEG; + } else if (this->un_op.child(0)->text() == "~"s) { + return UnOpEnum::BWNOT; + } else if (this->un_op.child(0)->text() == "#"s) { + return UnOpEnum::LEN; + } else { + throw std::runtime_error("unknown Unary Operator: " + this->un_op.child(0)->text()); + } +} + +auto UnaryOperation::exp() -> Expression { return Expression(un_op.child(0).value()); } + +/*std::ostream& operator<<(std::ostream& os, UnaryOperation& unaryOperation){ + return os << (int)unaryOperation.op() << unaryOperation.exp().type(); +}*/ + +// ForStatement +ForStatement::ForStatement(ts::Node node) : for_statement(node) { + if (node.type_id() != ts::NODE_FOR_STATEMENT || !node.named_child(0).has_value() || node.named_child(0).value().type_id() != ts::NODE_LOOP_EXPRESSION) { + throw std::runtime_error("not a for_statement node"); + } +} +auto ForStatement::body() -> Body { + std::vector body = for_statement.named_children(); + body.erase(body.begin()); + return Body(body); +} + +auto ForStatement::loop_exp() -> ts::Node { return for_statement.named_child(0).value(); } + +LoopExpression::LoopExpression(ts::Node node) : loop_exp(node) { + if (node.type_id() != ts::NODE_LOOP_EXPRESSION || node.child_count()<3) { + throw std::runtime_error("not a loop_expression node"); + } +} +auto LoopExpression::variable() -> Identifier {return Identifier(loop_exp.named_child(0).value());} +auto LoopExpression::end() -> Expression { + if(loop_exp.child_count()==4){ + return Expression(loop_exp.named_child(3).value()); + }else{ + return Expression(loop_exp.named_child(2).value()); + } +} +auto LoopExpression::start() -> Expression { return Expression(loop_exp.named_child(0).value()); } +auto LoopExpression::step() -> std::optional { + if(loop_exp.child_count()==4){ + return Expression(loop_exp.named_child(2).value()); + }else{ + return {}; + } +} +//TODO find way to split childern +InLoopExpression::InLoopExpression(ts::Node node) : loop_exp(node){ + if(node.type_id()!=ts::NODE_LOOP_EXPRESSION){ + throw std::runtime_error("not a loop_expression node"); + } + +} +auto InLoopExpression::loop_exps() -> std::vector { + std::vector body = loop_exp.named_children(); + for(int i=0;i res; + std::transform(body.begin()+i,body.end(),std::back_inserter(res),[](ts::Node node){return Expression(node);}); + return res; + } + } +} +auto InLoopExpression::loop_vars() -> std::vector { + std::vector body = loop_exp.named_children(); + for(int i=0;i res; + std::transform(body.begin(),body.begin()+i,std::back_inserter(res),[](ts::Node node){return Identifier(node);}); + return res; + } + } +} +WhileStatement::WhileStatement(ts::Node node) : while_statement(node){ + if (node.type_id() != ts::NODE_WHILE_STATEMENT || !node.named_child(0).has_value() ||node.named_child(0).value().type_id()!=ts::NODE_CONDITION_EXPRESSION) { + throw std::runtime_error("not a while_statement node"); + } +} + +auto WhileStatement::body() -> Body { + std::vector body = while_statement.named_children(); + body.erase(body.begin()); + return Body(body); +} +auto WhileStatement::exit_cond() -> Expression { + return Expression(while_statement.named_child(0).value()); +} +RepeatStatement::RepeatStatement(ts::Node node) : repeat_statement(node){ + if (node.type_id() != ts::NODE_REPEAT_STATEMENT || (node.named_children().end()-1)->type_id()!=ts::NODE_CONDITION_EXPRESSION) { + throw std::runtime_error("not a repeat_statement node"); + } +} +auto RepeatStatement::body() -> Body { + std::vector body = repeat_statement.named_children(); + body.pop_back(); + return Body(body); +} +auto RepeatStatement::until_cond() -> Expression { + return Expression(repeat_statement.named_child(repeat_statement.named_child_count()-1).value()); +} +//If +IfStatement::IfStatement(ts::Node node) : if_statement(node){ + if (node.type_id() != ts::NODE_IF_STATEMENT || !node.named_child(0).has_value() || node.named_child(0).value().type_id()!=ts::NODE_CONDITION_EXPRESSION) { + throw std::runtime_error("not an if_statement node"); + } +} +auto IfStatement::cond() -> Expression { + return Expression(if_statement.named_child(0).value()); +} +auto IfStatement::else_() -> std::optional { + if(if_statement.named_child(if_statement.named_child_count()-1).has_value() && if_statement.named_child(if_statement.named_child_count()-1)->type_id()==ts::NODE_ELSE){ + return Else(if_statement.named_child(if_statement.named_child_count()-1).value()); + }else{ + return {}; + } +} +auto IfStatement::elseifs() -> std::vector { + std::vector if_children = if_statement.named_children(); + std::vector::iterator end; + std::vector res; + if((if_children.end()-1)->type_id()==ts::NODE_ELSE){ + end = if_children.end()-1; + }else{ + end = if_children.end(); + } + std::vector::iterator begin = end; + if(begin->type_id()!=ts::NODE_ELSEIF){ + return res; + } + while((begin--)->type_id()==ts::NODE_ELSEIF){ + begin--; + } + std::transform(begin,end,std::back_inserter(res),[](ts::Node node){return ElseIf(node);}); +} +auto IfStatement::body() -> Body { + std::vector if_children = if_statement.named_children(); + std::vector::iterator end; + if((if_children.end()-1)->type_id()==ts::NODE_ELSE){ + end = if_children.end()-1; + }else{ + end = if_children.end(); + } + if(end->type_id()!=ts::NODE_ELSEIF){ + return Body(std::vector(if_children.begin()+1,end)); + } + while((end--)->type_id()==ts::NODE_ELSEIF){ + end--; + } + return Body(std::vector(if_children.begin()+1,end)); +} +//Else +Else::Else(ts::Node node) : else_statement(node){ + if(node.type_id()!=ts::NODE_ELSE){ + throw std::runtime_error("Not an else_statement node"); + } +} +auto Else::body() -> Body { + return Body(else_statement.named_children()); +} +//ElseIf +ElseIf::ElseIf(ts::Node node) : else_if(node) { + if (node.type_id() != ts::NODE_ELSEIF || !node.named_child(0).has_value() ||node.named_child(0).value().type_id()!=ts::NODE_CONDITION_EXPRESSION) { + throw std::runtime_error("not a else_if node"); + } +} +auto ElseIf::body() -> Body { + std::vector body = else_if.named_children(); + body.erase(body.begin()); + return Body(body); +} +auto ElseIf::cond() -> Expression { + return Expression(else_if.named_child(0).value()); +} +//Return +Return::Return(ts::Node node) : expressions(node){ + +} +auto Return::explist() -> std::vector { + std::vector exps = expressions.named_children(); + std::vector::iterator end; + std::vector res; + if(exps.size()>1 && exps[exps.size()-1].text()==";"s){ + end = exps.end()-1; + res.reserve(exps.size()-1); + }else{ + end = exps.end(); + res.reserve(exps.size()); + } + std::transform(exps.begin(),end,std::back_inserter(res),[](ts::Node node){return Expression(node);}); + return res; +} +//VariableDeclaration +VariableDeclaration::VariableDeclaration(ts::Node node) : var_dec(node){ + if(node.type_id()!=ts::NODE_VARIABLE_DECLARATION || node.named_child_count()<2 || node.named_child(0).value().type_id() != ts::NODE_VARIABLE_DECLARATOR){ + throw std::runtime_error("not a variable declaration node"); + } +} +auto VariableDeclaration::declarations() -> std::vector { + std::vector nodes = var_dec.named_children(); + std::vector res; + std::vector::iterator it = nodes.begin(); + while(it->type_id() == ts::NODE_VARIABLE_DECLARATOR){ + it++; + } + res.reserve(nodes.size()-(it-nodes.begin())); + std::transform(it,nodes.end(),std::back_inserter(res),[](ts::Node node){return Expression(node);}); + return res; +} +auto VariableDeclaration::declarators() -> std::vector { + std::vector nodes = var_dec.named_children(); + std::vector res; + std::vector::iterator it = nodes.begin(); + while(it->type_id() == ts::NODE_VARIABLE_DECLARATOR){ + it++; + } + res.reserve(it-nodes.begin()); + std::transform(nodes.begin(),it,std::back_inserter(res),[](ts::Node node){return VariableDeclarator(node);}); + return res; +} +//VariableDeclarator +VariableDeclarator::VariableDeclarator(ts::Node node) : dec(node){ + if(node.type_id() != ts::NODE_VARIABLE_DECLARATOR){ + throw std::runtime_error("not a variable declarator"); + } +} +auto VariableDeclarator::var() -> std::variant { + if(dec.named_child_count()==1){ + if(dec.named_child(0) -> type_id() == ts::NODE_IDENTIFIER){ + return Identifier(dec.named_child(0).value()); + }else if(dec.named_child(0) -> type_id() == ts::NODE_FIELD_EXPRESSION){ + return FieldExpression(dec.named_child(0).value()); + } + }else{ + return TableIndex();//TODO find good constructor for tableindex + } +} +//LocalVariableDeclaration +LocalVariableDeclaration::LocalVariableDeclaration(ts::Node node) : local_var_dec(node){ + if(node.type_id() != ts::NODE_LOCAL_VARIABLE_DECLARATION || !node.named_child(0).has_value() || node.named_child(0) -> type_id() != ts::NODE_VARIABLE_DECLARATOR){ + throw std::runtime_error("not a local_variable_declaration node"); + } +} +auto LocalVariableDeclaration::declarator() -> LocalVariableDeclarator { + return LocalVariableDeclarator(local_var_dec.named_child(0).value()); +} +auto LocalVariableDeclaration::declarations() -> std::vector { + std::vector nodes = local_var_dec.named_children(); + std::vector res; + res.reserve(nodes.size()-1); + std::transform(nodes.begin()+1,nodes.end(),std::back_inserter(res),[](ts::Node node){return Expression(node);}); + return res; +} +//LocalVariableDeclarator +LocalVariableDeclarator::LocalVariableDeclarator(ts::Node node) : var_dec(node){ + if(node.type_id() != ts::NODE_VARIABLE_DECLARATOR){ + throw std::runtime_error("not a local_variable_declarator node"); + } +} +auto LocalVariableDeclarator::vars() -> std::vector { + std::vector nodes = var_dec.named_children(); + std::vector res; + res.reserve(nodes.size()); + std::transform(nodes.begin(),nodes.end(),std::back_inserter(res),[](ts::Node node){return Identifier(node);}); + return res; +} + +// Prefix +Prefix::Prefix(ts::Node node) : prefix(node) { + if (!(node.type_id() == ts::NODE_SELF || node.type_id() == ts::NODE_GLOBAL_VARIABLE || + node.type_id() == ts::NODE_FUNCTION_CALL || node.child(0)->text() == "(")) { + throw std::runtime_error("Not a prefix-node"); + } +} +auto Prefix::options() -> std::variant { if(prefix.type_id() == ts::NODE_SELF){ return Self(); }else if(prefix.type_id() == +ts::NODE_GLOBAL_VARIABLE){ return GlobalVariable(prefix); }else if(prefix.type_id() == +ts::NODE_FUNCTION_CALL){ return FunctionCall(prefix); }else if(prefix.child(0)->text() == "("){ + return Expression(prefix.child(1).value()); + }else{ + throw std::runtime_error("Not a prefix-node"); + } +} +//Expression +Expression::Expression(ts::Node node) : exp(node){ + if(!(node.type_id() == ts::NODE_SPREAD || node.type_id() == ts::NODE_NEXT || node.type_id() == +ts::NODE_FUNCTION_DEFINITION || node.type_id() == ts::NODE_TABLE || node.type_id() == +ts::NODE_BINARY_OPERATION || node.type_id() == ts::NODE_UNARY_OPERATION || node.type_id() == +ts::NODE_STRING || node.type_id() == ts::NODE_NUMBER || node.type_id() == ts::NODE_NIL || +node.type_id() == ts::NODE_FALSE || node.type_id() == ts::NODE_TRUE || node.type_id() == +ts::NODE_IDENTIFIER || (node.type_id() == ts::NODE_SELF || node.type_id() == +ts::NODE_GLOBAL_VARIABLE || node.type_id() == ts::NODE_FUNCTION_CALL || node.child(0)->text() == +"("))){ throw std::runtime_error("Not an expression-node"); + } +} +auto Expression::options() -> std::variant { if(exp.type_id() == +ts::NODE_SPREAD){ return Spread(); }else if(exp.type_id() == ts::NODE_NEXT){ return Next(); }else +if(exp.type_id() == ts::NODE_FUNCTION_DEFINITION){ return Function(exp); }else if(exp.type_id() == +ts::NODE_TABLE){ return Table(exp); }else if(exp.type_id() == ts::NODE_BINARY_OPERATION){ return +BinaryOperation(exp); }else if(exp.type_id() == ts::NODE_UNARY_OPERATION){ return +UnaryOperation(exp); }else if(exp.type_id() == ts::NODE_STRING){ return String(exp); }else +if(exp.type_id() == ts::NODE_NUMBER){ return Number(exp); }else if(exp.type_id() == ts::NODE_NIL){ + return Nil(); + }else if(exp.type_id() == ts::NODE_TRUE){ + return True(); + }else if(exp.type_id() == ts::NODE_FALSE){ + return False(); + }else if(exp.type_id() == ts::NODE_IDENTIFIER){ + return Identifier(exp); + }else if(exp.type_id() == ts::NODE_SELF || exp.type_id() == ts::NODE_FUNCTION_CALL || +exp.type_id() == ts::NODE_GLOBAL_VARIABLE || (exp.child(0).has_value() && exp.child(0) -> text() == +"(")){ return Prefix(exp); }else{ throw std::runtime_error("Not an expression-node"); + } +} +//Statement +Statement::Statement(ts::Node node) : statement(node){ + if(!(node.type_id() == ts::NODE_EXPRESSION || node.type_id() == ts::NODE_VARIABLE_DECLARATION || +node.type_id() == ts::NODE_LOCAL_VARIABLE_DECLARATION || node.type_id() == ts::NODE_DO_STATEMENT || +node.type_id() == ts::NODE_IF_STATEMENT || node.type_id() == ts::NODE_WHILE_STATEMENT || +node.type_id() == ts::NODE_REPEAT_STATEMENT || node.type_id() == ts::NODE_FOR_STATEMENT || +node.type_id() == ts::NODE_FOR_IN_STATEMENT || node.type_id() == ts::NODE_GOTO_STATEMENT || +node.type_id() == ts::NODE_BREAK_STATEMENT || node.type_id() == ts::NODE_LABEL_STATEMENT || +node.type_id() == ts::NODE_FUNCTION || node.type_id() == ts::NODE_LOCAL_FUNCTION || node.type_id() +== ts::NODE_FUNCTION_CALL || (node.child(0).has_value() && node.child(0) -> text() == ";"))){ throw +std::runtime_error("Not a statement-node"); + } +} +auto Statement::options() -> std::variant { if(statement.type_id() == +ts::NODE_EXPRESSION){ return Expression(statement.named_child(0).value()); }else +if(statement.type_id() == ts::NODE_VARIABLE_DECLARATION){ return VariableDeclaration(statement); + }else if(statement.type_id() == ts::NODE_LOCAL_VARIABLE_DECLARATION){ + return LocalVariableDeclaration(statement); + }else if(statement.type_id() == ts::NODE_DO_STATEMENT){ + return DoStatement(statement); + }else if(statement.type_id() == ts::NODE_IF_STATEMENT){ + return IfStatement(statement); + }else if(statement.type_id() == ts::NODE_WHILE_STATEMENT){ + return WhileStatement(statement); + }else if(statement.type_id() == ts::NODE_REPEAT_STATEMENT){ + return RepeatStatement(statement); + }else if(statement.type_id() == ts::NODE_FOR_STATEMENT){ + return ForStatement(statement); + }else if(statement.type_id() == ts::NODE_FOR_IN_STATEMENT){ + return ForInStatement(statement); + }else if(statement.type_id() == ts::NODE_GOTO_STATEMENT){ + return GoTo(statement); + }else if(statement.type_id() == ts::NODE_BREAK_STATEMENT){ + return Break(); + }else if(statement.type_id() == ts::NODE_LABEL_STATEMENT){ + return Label(statement); + }else if(statement.type_id() == ts::NODE_FUNCTION){ + return Function(statement); + }else if(statement.type_id() == ts::NODE_LOCAL_FUNCTION){ + return LocalFunction(statement); + }else if(statement.type_id() == ts::NODE_FUNCTION_CALL){ + return FunctionCall(statement); + }else if((statement.child(0).has_value() && statement.child(0) -> text() == ";")){ + return Empty(); + }else{ + throw std::runtime_error("Not a statement-node"); + } +} +} +} \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8f8e5c3e..2a612d2c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,7 +10,7 @@ add_executable(MiniLua-tests main.cpp unit_tests.cpp integration_tests.cpp - tree_sitter.cpp) + tree_sitter.cpp tree_sitter_ast_tests.cpp) target_include_directories(MiniLua-tests PRIVATE ${tree-sitter_SOURCE_DIR}/lib/include) target_link_libraries(MiniLua-tests PRIVATE Catch2::Catch2 MiniLua From 4f97d2e46558a9d03c45c441a5cb344b873ddff1 Mon Sep 17 00:00:00 2001 From: CFU9 Date: Thu, 17 Dec 2020 16:18:19 +0100 Subject: [PATCH 03/17] minor change --- include/tree_sitter/tree_sitter.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/tree_sitter/tree_sitter.hpp b/include/tree_sitter/tree_sitter.hpp index 18fd0a61..88c86079 100644 --- a/include/tree_sitter/tree_sitter.hpp +++ b/include/tree_sitter/tree_sitter.hpp @@ -306,17 +306,17 @@ const TypeId NODE_LOCAL_VARIABLE_DECLARATION = const TypeId NODE_FIELD_EXPRESSION = LUA_LANGUAGE.node_type_id("field_expression", true); const TypeId NODE_VARIABLE_DECLARATOR = LUA_LANGUAGE.node_type_id("variable_declarator", true); const TypeId NODE_DO_STATEMENT = LUA_LANGUAGE.node_type_id("do_statement", true); -const TypeId NODE_IF_STATEMENT = LUA_LANGUAGE.node_type_id("if_statement", true);// -const TypeId NODE_ELSEIF = LUA_LANGUAGE.node_type_id("elseif", true);// -const TypeId NODE_ELSE = LUA_LANGUAGE.node_type_id("else", true);// -const TypeId NODE_WHILE_STATEMENT = LUA_LANGUAGE.node_type_id("while_statement", true);// -const TypeId NODE_REPEAT_STATEMENT = LUA_LANGUAGE.node_type_id("repeat_statement", true);// -const TypeId NODE_FOR_STATEMENT = LUA_LANGUAGE.node_type_id("for_statement", true);// +const TypeId NODE_IF_STATEMENT = LUA_LANGUAGE.node_type_id("if_statement", true); +const TypeId NODE_ELSEIF = LUA_LANGUAGE.node_type_id("elseif", true); +const TypeId NODE_ELSE = LUA_LANGUAGE.node_type_id("else", true); +const TypeId NODE_WHILE_STATEMENT = LUA_LANGUAGE.node_type_id("while_statement", true); +const TypeId NODE_REPEAT_STATEMENT = LUA_LANGUAGE.node_type_id("repeat_statement", true); +const TypeId NODE_FOR_STATEMENT = LUA_LANGUAGE.node_type_id("for_statement", true); const TypeId NODE_FOR_IN_STATEMENT = LUA_LANGUAGE.node_type_id("for_in_statement", true); -const TypeId NODE_LOOP_EXPRESSION = LUA_LANGUAGE.node_type_id("loop_expression", true);// +const TypeId NODE_LOOP_EXPRESSION = LUA_LANGUAGE.node_type_id("loop_expression", true); const TypeId NODE_GOTO_STATEMENT = LUA_LANGUAGE.node_type_id("goto_statement", true); const TypeId NODE_LABEL_STATEMENT = LUA_LANGUAGE.node_type_id("label_statement", true); -const TypeId NODE_FUNCTION = LUA_LANGUAGE.node_type_id("function", true);// +const TypeId NODE_FUNCTION = LUA_LANGUAGE.node_type_id("function", true); const TypeId NODE_LOCAL_FUNCTION = LUA_LANGUAGE.node_type_id("local_function", true); const TypeId NODE_FUNCTION_CALL = LUA_LANGUAGE.node_type_id("function_call", true); const TypeId NODE_ARGUMENTS = LUA_LANGUAGE.node_type_id("ARGUMENTS", true); @@ -327,8 +327,8 @@ const TypeId NODE_GLOBAL_VARIABLE = LUA_LANGUAGE.node_type_id("global_variable", const TypeId NODE_FUNCTION_DEFINITION = LUA_LANGUAGE.node_type_id("function_definition", true); const TypeId NODE_TABLE = LUA_LANGUAGE.node_type_id("table", true); const TypeId NODE_FIELD = LUA_LANGUAGE.node_type_id("field", true); -const TypeId NODE_BINARY_OPERATION = LUA_LANGUAGE.node_type_id("binary_operation", true);// -const TypeId NODE_UNARY_OPERATION = LUA_LANGUAGE.node_type_id("unary_operation", true);// +const TypeId NODE_BINARY_OPERATION = LUA_LANGUAGE.node_type_id("binary_operation", true); +const TypeId NODE_UNARY_OPERATION = LUA_LANGUAGE.node_type_id("unary_operation", true); const TypeId NODE_CONDITION_EXPRESSION = LUA_LANGUAGE.node_type_id("condition_expression", true); const TypeId NODE_EXPRESSION = LUA_LANGUAGE.node_type_id("expression", true); const TypeId NODE_METHOD = LUA_LANGUAGE.node_type_id("method", true); From 950f2b4cd151063d73f820aea981dc1f46343751 Mon Sep 17 00:00:00 2001 From: CFU9 Date: Thu, 17 Dec 2020 16:20:16 +0100 Subject: [PATCH 04/17] minor change --- tests/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2a612d2c..bedfb28e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,7 +10,8 @@ add_executable(MiniLua-tests main.cpp unit_tests.cpp integration_tests.cpp - tree_sitter.cpp tree_sitter_ast_tests.cpp) + tree_sitter.cpp + tree_sitter_ast_tests.cpp) target_include_directories(MiniLua-tests PRIVATE ${tree-sitter_SOURCE_DIR}/lib/include) target_link_libraries(MiniLua-tests PRIVATE Catch2::Catch2 MiniLua From 0e329690984bec5102e0b74159b2e8e77984467c Mon Sep 17 00:00:00 2001 From: CFU9 Date: Sun, 20 Dec 2020 14:24:01 +0100 Subject: [PATCH 05/17] minor change --- include/MiniLua/tree_sitter_ast.hpp | 11 ++---- src/core/tree_sitter_ast.cpp | 56 ++++++++++++++++++----------- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/include/MiniLua/tree_sitter_ast.hpp b/include/MiniLua/tree_sitter_ast.hpp index 38ceb5d3..3d5d277e 100644 --- a/include/MiniLua/tree_sitter_ast.hpp +++ b/include/MiniLua/tree_sitter_ast.hpp @@ -1,8 +1,9 @@ #ifndef MINILUA_TREE_SITTER_AST_HPP #define MINILUA_TREE_SITTER_AST_HPP +#include "values.hpp" #include -#include +#include namespace minilua{ namespace details { class Expression; @@ -257,11 +258,6 @@ class Table { class Spread {}; class Self {}; class Next {}; -class String {}; -class Number {}; -class Nil {}; -class True {}; -class False {}; class Prefix { ts::Node prefix; @@ -275,8 +271,7 @@ class Expression { public: Expression(ts::Node); auto options() -> std::variant< - Spread, Prefix, Next, FunctionDefinition, Table, BinaryOperation, UnaryOperation, String, Number, Nil, - True, False, Identifier>; + Spread, Prefix, Next, FunctionDefinition, Table, BinaryOperation, UnaryOperation, minilua::Value, Identifier>; }; class Break {}; class Empty {}; diff --git a/src/core/tree_sitter_ast.cpp b/src/core/tree_sitter_ast.cpp index b73203c1..b40d2c1f 100644 --- a/src/core/tree_sitter_ast.cpp +++ b/src/core/tree_sitter_ast.cpp @@ -435,24 +435,40 @@ ts::NODE_GLOBAL_VARIABLE || node.type_id() == ts::NODE_FUNCTION_CALL || node.chi "("))){ throw std::runtime_error("Not an expression-node"); } } -auto Expression::options() -> std::variant { if(exp.type_id() == -ts::NODE_SPREAD){ return Spread(); }else if(exp.type_id() == ts::NODE_NEXT){ return Next(); }else -if(exp.type_id() == ts::NODE_FUNCTION_DEFINITION){ return Function(exp); }else if(exp.type_id() == -ts::NODE_TABLE){ return Table(exp); }else if(exp.type_id() == ts::NODE_BINARY_OPERATION){ return -BinaryOperation(exp); }else if(exp.type_id() == ts::NODE_UNARY_OPERATION){ return -UnaryOperation(exp); }else if(exp.type_id() == ts::NODE_STRING){ return String(exp); }else -if(exp.type_id() == ts::NODE_NUMBER){ return Number(exp); }else if(exp.type_id() == ts::NODE_NIL){ - return Nil(); - }else if(exp.type_id() == ts::NODE_TRUE){ - return True(); - }else if(exp.type_id() == ts::NODE_FALSE){ - return False(); - }else if(exp.type_id() == ts::NODE_IDENTIFIER){ +auto Expression::options() -> std::variant< + Spread, Prefix, Next, FunctionDefinition, Table, BinaryOperation, UnaryOperation, + minilua::Value, Identifier> { + if (exp.type_id() == ts::NODE_SPREAD) { + return Spread(); + } else if (exp.type_id() == ts::NODE_NEXT) { + return Next(); + } else if (exp.type_id() == ts::NODE_FUNCTION_DEFINITION) { + return FunctionDefinition(exp); + } else if (exp.type_id() == ts::NODE_TABLE) { + return Table(exp); + } else if (exp.type_id() == ts::NODE_BINARY_OPERATION) { + return BinaryOperation(exp); + } else if (exp.type_id() == ts::NODE_UNARY_OPERATION) { + return UnaryOperation(exp); + } else if (exp.type_id() == ts::NODE_STRING) { + return minilua::Value(exp.text()); + } else if (exp.type_id() == ts::NODE_NUMBER) { + return minilua::Value();//TODO parse number and put into value + } else if (exp.type_id() == ts::NODE_NIL) { + return minilua::Value(Nil()); + } else if (exp.type_id() == ts::NODE_TRUE) { + return minilua::Value(true); + } else if (exp.type_id() == ts::NODE_FALSE) { + return minilua::Value(false); + } else if (exp.type_id() == ts::NODE_IDENTIFIER) { return Identifier(exp); - }else if(exp.type_id() == ts::NODE_SELF || exp.type_id() == ts::NODE_FUNCTION_CALL || -exp.type_id() == ts::NODE_GLOBAL_VARIABLE || (exp.child(0).has_value() && exp.child(0) -> text() == -"(")){ return Prefix(exp); }else{ throw std::runtime_error("Not an expression-node"); + } else if ( + exp.type_id() == ts::NODE_SELF || exp.type_id() == ts::NODE_FUNCTION_CALL || + exp.type_id() == ts::NODE_GLOBAL_VARIABLE || + (exp.child(0).has_value() && exp.child(0)->text() == "(")) { + return Prefix(exp); + } else { + throw std::runtime_error("Not an expression-node"); } } //Statement @@ -470,7 +486,7 @@ std::runtime_error("Not a statement-node"); } auto Statement::options() -> std::variant { if(statement.type_id() == +Break, Label, Empty, FunctionStatement, LocalFunctionStatement, FunctionCall, Expression> { if(statement.type_id() == ts::NODE_EXPRESSION){ return Expression(statement.named_child(0).value()); }else if(statement.type_id() == ts::NODE_VARIABLE_DECLARATION){ return VariableDeclaration(statement); }else if(statement.type_id() == ts::NODE_LOCAL_VARIABLE_DECLARATION){ @@ -494,9 +510,9 @@ if(statement.type_id() == ts::NODE_VARIABLE_DECLARATION){ return VariableDeclara }else if(statement.type_id() == ts::NODE_LABEL_STATEMENT){ return Label(statement); }else if(statement.type_id() == ts::NODE_FUNCTION){ - return Function(statement); + return FunctionStatement(statement); }else if(statement.type_id() == ts::NODE_LOCAL_FUNCTION){ - return LocalFunction(statement); + return LocalFunctionStatement(statement); }else if(statement.type_id() == ts::NODE_FUNCTION_CALL){ return FunctionCall(statement); }else if((statement.child(0).has_value() && statement.child(0) -> text() == ";")){ From a43e4253f50fc2334d55992901874943048ad6cb Mon Sep 17 00:00:00 2001 From: CFU9 Date: Sun, 17 Jan 2021 20:38:43 +0100 Subject: [PATCH 06/17] first complete version of the ast classes --- include/MiniLua/tree_sitter_ast.hpp | 583 +++++++++++++++++--- src/core/tree_sitter_ast.cpp | 724 +++++++++++++++++------- tests/CMakeLists.txt | 30 +- tests/tree_sitter_ast_tests.cpp | 817 ++++++++++++++++++++++++---- 4 files changed, 1764 insertions(+), 390 deletions(-) diff --git a/include/MiniLua/tree_sitter_ast.hpp b/include/MiniLua/tree_sitter_ast.hpp index 3d5d277e..0b9be71e 100644 --- a/include/MiniLua/tree_sitter_ast.hpp +++ b/include/MiniLua/tree_sitter_ast.hpp @@ -1,173 +1,396 @@ #ifndef MINILUA_TREE_SITTER_AST_HPP #define MINILUA_TREE_SITTER_AST_HPP + #include "values.hpp" #include #include -namespace minilua{ -namespace details { +namespace minilua::details { +#define INDEX_FIELD std::pair +#define ID_FIELD std::pair +// Some forward declarations class Expression; class Statement; class Prefix; class Return; -class Body{ +class FieldExpression; +/** + * The Body class groups a variable amount of statements together + * the last statement of a Body might be a return_statement + */ +class Body { std::vector nodes; + public: Body(std::vector); + /** + * This method maps the statement Nodes to Statement classes + * @return the statements in this body excluding a potential return_statement + */ auto statements() -> std::vector; + /** + * This checks for a return node + * the return_statement is always the last statement of the body + * @return a Return class if the body has a return statement + * else an empty optional + */ auto ret() -> std::optional; }; +/** + * class for program nodes. It only holds a body + */ +class Program { + ts::Node program; + +public: + Program(ts::Node); + /** + * the children nodes of the Program get put into a Body class by this method + * @return a Body containing the full program + */ + auto body() -> Body; +}; +/** + * class for identifier_nodes + */ class Identifier { - ts::Node node; + ts::Node id; + public: Identifier(ts::Node); -}; + /** + * get the identifier name as a string + * @return the identifer as a string + */ + auto str() -> std::string; +}; +/** + * this enum holds all possible BinaryOperators in lua + */ enum class BinOpEnum { - ADD, - SUB, - MUL, - DIV, - MOD, - POW, - LT, - GT, - LEQ, - GEQ, - EQ, - NEQ, - CONCAT, - AND, - OR, - BSL, - BSR, - BWNOT, - BWOR, - BWAND, - INTDIV -}; - + ADD, // + + SUB, // - + MUL, // * + DIV, // / + MOD, // % + POW, // ^ + LT, // < + GT, // > + LEQ, // <= + GEQ, // >= + EQ, // == + NEQ, // ~= + CONCAT, // .. + AND, // and + OR, // or + BSL, // << + BSR, // >> + BWNOT, // ~ + BWOR, // | + BWAND, // & + INTDIV // // +}; +/** + * class for binary_operation nodes + */ class BinaryOperation { ts::Node bin_op; public: BinaryOperation(ts::Node node); + /** + * + * @return The left operand + */ auto left() -> Expression; + /** + * + * @return The right operand + */ auto right() -> Expression; + /** + * + * @return the operator of the operation + */ auto op() -> BinOpEnum; }; -enum class UnOpEnum { NOT, NEG, LEN, BWNOT }; +/** + * This enum holds all unary Operators of lua + */ +enum class UnOpEnum { + NOT, // not + NEG, // - + LEN, // # + BWNOT // ~ +}; +/** + * class for unary_operation nodes + */ class UnaryOperation { ts::Node un_op; public: UnaryOperation(ts::Node node); + /** + * + * @return the operator of the operation + */ auto op() -> UnOpEnum; + /** + * + * @return the operand of + */ auto exp() -> Expression; }; -class ForStatement { - ts::Node for_statement; - -public: - ForStatement(ts::Node node); - auto loop_exp() -> ts::Node; - auto body() -> Body; -}; +/** + * class for loop_expression nodes + */ class LoopExpression { ts::Node loop_exp; public: LoopExpression(ts::Node); + /** + * + * @return The identifier of the loop variable + */ auto variable() -> Identifier; + /** + * + * @return The start value of the loop variable + */ auto start() -> Expression; + /** + * + * @return the step size of the loop variable if specified + * otherwise an empty optional (then the step size is 1 by default) + */ auto step() -> std::optional; + /** + * + * @return the end value of the loop variable + */ auto end() -> Expression; }; -class InLoopExpression{ +/** + * class for for_statement nodes + */ +class ForStatement { + ts::Node for_statement; + +public: + ForStatement(ts::Node node); + /** + * + * @return returns the loop expression of the loop + */ + auto loop_exp() -> LoopExpression; + /** + * + * @return a Body containing all statements inside the loop + */ + auto body() -> Body; +}; +/** + * class for in_loop_expression nodes + */ +class InLoopExpression { ts::Node loop_exp; + public: InLoopExpression(ts::Node); + /** + * + * @return all identifiers that are specified as loop variables by the loop + */ auto loop_vars() -> std::vector; + /** + * the loop expressions usually should eveluate to a functioncall + * @return the loop expressions + */ auto loop_exps() -> std::vector; }; +/** + * class for for_in_statement nodes + */ class ForInStatement { ts::Node for_in; + public: ForInStatement(ts::Node); - auto body() -> std::vector; + /** + * + * @return a Body containing all statements inside the loop + */ + auto body() -> Body; + /** + * + * @return the corresponding loop expression + */ auto loop_exp() -> InLoopExpression; - auto ret() -> std::optional; }; +/** + * class for while_statement nodes + */ class WhileStatement { ts::Node while_statement; - ts::Node exit_condition; - std::vector loop_body; public: WhileStatement(ts::Node node); + /** + * This method gets the contitional expression of the loop. In while loops this is always + * checked before executing the body statements + * @return an expression containing the conditional expression of the loop + */ auto exit_cond() -> Expression; + /** + * + * @return a body with all statements inside the loop + */ auto body() -> Body; }; +/** + * class for repeat_statement nodes + */ class RepeatStatement { ts::Node repeat_statement; - ts::Node until_condition; - std::vector loop_body; public: RepeatStatement(ts::Node node); + /** + * This method gets the conditional expression of the loop. In repeat loops this is always + * checked after executing the statements of the body + * @return an expression containing the conditional expression of the loop + */ auto until_cond() -> Expression; + /** + * + * @return a body with all statements inside the loop + */ auto body() -> Body; }; +/** + * class for else_if nodes + */ class ElseIf { ts::Node else_if; public: ElseIf(ts::Node); + /** + * + * @return a body with all statements inside the else if statement + */ auto body() -> Body; + /** + * + * @return an expression that holds the conditional expression of the else_if_statement + */ auto cond() -> Expression; }; +/** + * class for else nodes + */ class Else { ts::Node else_statement; + public: Else(ts::Node); + /** + * + * @return a body containing the statements in the else block + */ auto body() -> Body; }; +/** + * class for if_statement nodes + */ class IfStatement { ts::Node if_statement; public: IfStatement(ts::Node node); + /** + * + * @return a ody conatining the statements of the if block excluding else_if and else statements + */ auto body() -> Body; + /** + * + * @return all else_if statements that are inside this if_statement + */ auto elseifs() -> std::vector; + /** + * + * @return an expression that holds the conditional expression of the if_statement + */ auto cond() -> Expression; + /** + * + * @return an Else class if there is one + * otherwise an empty optional + */ auto else_() -> std::optional; }; -//Return +/** + * a class for return_statement nodes + */ class Return { ts::Node expressions; public: Return(ts::Node node); + /** + * + * @return a vector holding all expressions that will be returned by this statement + * the vector can be empty + */ auto explist() -> std::vector; }; -//TableIndex -class TableIndex{ - +// TableIndex +class TableIndex { + // TODO }; +/** + * class for variable_declarators + */ class VariableDeclarator { ts::Node dec; + public: VariableDeclarator(ts::Node node); + /** + * + * @return a variant containing the class this variable declarator gets resolved to + */ auto var() -> std::variant; }; +/** + * class for variable_declaration nodes + */ class VariableDeclaration { ts::Node var_dec; + public: VariableDeclaration(ts::Node node); + /** + * + * @return a vector containing all variables declared by the varaible declaration + */ auto declarators() -> std::vector; + /** + * + * @return a vector with the expressions that get assigned to to the declared variables + * there should always be at least one element in it + */ auto declarations() -> std::vector; }; +/** + * class for local_variable_declarator nodes + */ class LocalVariableDeclarator { ts::Node var_dec; + public: LocalVariableDeclarator(ts::Node node); auto vars() -> std::vector; @@ -178,114 +401,308 @@ class LocalVariableDeclaration { public: LocalVariableDeclaration(ts::Node node); - auto declarator() -> LocalVariableDeclarator; + /** + * this method gets all Identifiers of variables declared in this statement + * @return a vector with all Identifiers + */ + auto declarators() -> std::vector; + /** + * + * @return a vector with the expressions that get assigned to to the declaraed variables + */ auto declarations() -> std::vector; }; - +/** + * class for field_expression nodes + */ class FieldExpression { - ts::Node table_identifier; - ts::Node property_identifier; + ts::Node exp; public: FieldExpression(ts::Node); + /** + * + * @return a Prefix containing the Identifier for the table + */ auto table_id() -> Prefix; + /** + * + * @return an Identifier for a property of the Table + */ auto property_id() -> Identifier; }; +/** + * class for do_statement nodes + */ class DoStatement { - std::vector do_statement; + ts::Node do_statement; + public: DoStatement(ts::Node); + /** + * + * @return a body containing all statements of the do block + */ auto body() -> Body; }; +/** + * class for go_to_statements + */ class GoTo { ts::Node go_to; public: GoTo(ts::Node node); + /** + * + * @return the Identifier of the Label that is specified + */ auto label() -> Identifier; }; +/** + * class for label_statements + */ class Label { ts::Node label; public: Label(ts::Node node); - auto identifier() -> Identifier; -}; -class FunctionDefinition { + /** + * + * @return the identifier of this label + */ + auto id() -> Identifier; +}; +/** + * class for function_name nodes + */ +class FunctionName { + ts::Node func_name; -}; +public: + FunctionName(ts::Node); + /** + * This method looks through the function name and returns Identifiers in order they reference + * on tables e.g. the vector [id_1,id_2] refers to a function name "id_1.id_2" in lua syntax + * @return a vector containing all identifiers used for the function name + * + */ + auto identifier() -> std::vector; + /** + * The identifier returned here is the last one if it is present + * e.g. identifiers() returns [id_1,id_2] and method returns id_5 then the full functionname is: + * "id_1.id_2:id_5" in lua syntax + * @return + * an empty optional if the function is not a method + * the function-/method- name if the function is a method + */ + auto method() -> std::optional; +}; +/** + * an enum defining the different positions a Spread can occur in the parameters of a method + */ +enum SpreadPos { BEGIN, END, NO_SPREAD }; +/** + * a class for parameter nodes + */ +class Parameters { + ts::Node parameters; +public: + Parameters(ts::Node); + /** + * self can only be the first parameter this method looks if the self keyword is present in this + * parameter list + * @return true if the first parameter is "self" + * false otherwise + */ + auto leading_self() -> bool; + /** + * + * @return a vector containing all parameters excluding a potential spread at the beginning or + * and or a potential self at the beginning + */ + auto params() -> std::vector; + /** + * specifies the position of a potential spread contained within the parameters + * SpreadPos::BEGIN and a leading self is not possible + * @return SpreadPos::BEGIN if there is a spread as the first parameter + * SpreadPos::END if there is a spread as the last parameter + * SpreadPos::NO_SPREAD if there is no spread amongst the parameters + */ + auto spread() -> SpreadPos; +}; +/** + * class for function_definition nodes + */ +class FunctionDefinition { + ts::Node func_def; + +public: + FunctionDefinition(ts::Node); + /** + * + * @return a body containing all statements of this function + */ + auto body() -> Body; + /** + * + * @return the parameters of this function + */ + auto parameters() -> Parameters; +}; +/** + * class for function_statements + */ class FunctionStatement { - ts::Node function_name; - std::vector parameters; - std::vector function_body; -}; -class FunctionName { - std::vector table_references; - ts::Node name; - bool method; -}; + ts::Node func_stat; + +public: + FunctionStatement(ts::Node); + /** + * + * @return a FunctionName class that can be resolved to the function name + */ + auto name() -> FunctionName; + /** + * + * @return a body containing all statements of this function + */ + auto body() -> Body; + /** + * + * @return a Parameter class containing all information about the Parameters of this function + */ + auto parameters() -> Parameters; +}; +/** + * class for local_function_statements + */ class LocalFunctionStatement { - ts::Node local_function_name; - std::vector parameters; - std::vector function_body; + ts::Node func_stat; + +public: + LocalFunctionStatement(ts::Node); + auto name() -> Identifier; + auto body() -> Body; + auto parameters() -> Parameters; }; class FunctionCall { - std::optional table_reference; - ts::Node function_name; - bool method; - std::vector arguments; + ts::Node func_call; + +public: + FunctionCall(ts::Node); + /** + * + * @return + * If the call is a method call id() the Prefix should refer to to a table + * else the Prefix states the functionname + */ + auto id() -> Prefix; + /** + * + * @return + * an empty optional if it is not a method call + * the functionname if it is a method call + */ + auto method() -> std::optional; + auto args() -> std::vector; }; enum GV { _G, _VERSION }; class GlobalVariable { ts::Node g_var; + public: GlobalVariable(ts::Node); + /** + * + * @return the Type of this Global Variable + */ auto type() -> GV; }; -class Field{ +/** + * class for field_nodes + */ +class Field { ts::Node field; + public: Field(ts::Node); - -}; + /** + * this method splits a field into the identifier of the field and the content of the field + * or just returns the expression + * an INDEX_FIELD looks like this in lua: "[INDEX_FIELD.first()] = INDEX_FIELD.second()" + * an ID_FIELD looks like this in lua: "ID_FIELD.first() = ID_FIELD.second" + * the Expression is + * @return a variant containing the right format for the field + */ + auto content() -> std::variant; +}; +/** + * class for table nodes + */ class Table { ts::Node table; + public: Table(ts::Node); + /** + * + * @return a vector containing all fields of the table + */ auto fields() -> std::vector; }; +// a few empty classes that are just used as additional return types class Spread {}; class Self {}; class Next {}; - +class Break {}; +/** + * class for prefix nodes + */ class Prefix { ts::Node prefix; + public: Prefix(ts::Node); + /** + * + * @return a variant containing the class this Prefix gets resolved to + */ auto options() -> std::variant; }; +/** + * class for expression nodes + */ class Expression { ts::Node exp; + public: Expression(ts::Node); + /** + * + * @return a variant containing the class this expression gets resolved to + */ auto options() -> std::variant< - Spread, Prefix, Next, FunctionDefinition, Table, BinaryOperation, UnaryOperation, minilua::Value, Identifier>; + Spread, Prefix, Next, FunctionDefinition, Table, BinaryOperation, UnaryOperation, + minilua::Value, Identifier>; }; -class Break {}; -class Empty {}; + class Statement { ts::Node statement; public: Statement(ts::Node); + /** + * + * @return a variant containing the class this statement gets resolved to + */ auto options() -> std::variant< VariableDeclaration, LocalVariableDeclaration, DoStatement, IfStatement, WhileStatement, - RepeatStatement, ForStatement, ForInStatement, GoTo, Break, Label, Empty, FunctionStatement, + RepeatStatement, ForStatement, ForInStatement, GoTo, Break, Label, FunctionStatement, LocalFunctionStatement, FunctionCall, Expression>; }; -} -} +} // namespace minilua::details #endif // MINILUA_TREE_SITTER_AST_HPP diff --git a/src/core/tree_sitter_ast.cpp b/src/core/tree_sitter_ast.cpp index b40d2c1f..66c5baa6 100644 --- a/src/core/tree_sitter_ast.cpp +++ b/src/core/tree_sitter_ast.cpp @@ -1,36 +1,54 @@ #include "MiniLua/tree_sitter_ast.hpp" -#include #include #include +#include using namespace std::string_literals; -namespace minilua { -namespace details { -//Body -Body::Body(std::vector node_vec) : nodes(node_vec) { - -} +namespace minilua::details { +// Body +Body::Body(std::vector node_vec) : nodes(std::move(node_vec)) {} auto Body::ret() -> std::optional { - if(nodes[nodes.size()-1].type_id()==ts::NODE_RETURN_STATEMENT){ - return Return(nodes[nodes.size()-1]); - }else{ + if (nodes.empty() || nodes[nodes.size() - 1].type_id() != ts::NODE_RETURN_STATEMENT) { return {}; + } else { + return Return(nodes[nodes.size() - 1]); } } auto Body::statements() -> std::vector { + std::vector::iterator end; std::vector res; - if((nodes.end()-1) -> type_id() == ts::NODE_RETURN_STATEMENT){ - res.reserve(nodes.size()-1); - end = nodes.end()-1; - }else{ + if (nodes.empty()) { + return res; + } + if ((nodes.end() - 1)->type_id() == ts::NODE_RETURN_STATEMENT) { + res.reserve(nodes.size() - 1); + end = nodes.end() - 1; + } else { res.reserve(nodes.size()); end = nodes.end(); } - std::transform(nodes.begin(),end,std::back_inserter(res),[](ts::Node node){return Statement(node);}); + std::transform( + nodes.begin(), end, std::back_inserter(res), [](ts::Node node) { return Statement(node); }); return res; } +// Identifier +Identifier::Identifier(ts::Node node) : id(node) { + if (node.type_id() != ts::NODE_IDENTIFIER && node.type_id() != ts::NODE_METHOD && + node.type_id() != ts::NODE_PROPERTY_IDENTIFIER && + node.type_id() != ts::NODE_FUNCTION_NAME_FIELD) { + throw std::runtime_error("not an identifier node" + to_string(node.type_id())); + } +} +auto Identifier::str() -> std::string { return id.text(); } +// Program +Program::Program(ts::Node node) : program(node) { + if (node.type_id() != ts::NODE_PROGRAM) { + throw std::runtime_error("not a program node"); + } +} +auto Program::body() -> Body { return Body(program.named_children()); } // BinOpEnum -std::ostream& operator<<(std::ostream& os, BinOpEnum& binOpEnum) { +/*static std::ostream& operator<<(std::ostream& os, BinOpEnum& binOpEnum) { switch (binOpEnum) { case BinOpEnum::ADD: return os << '+'; @@ -62,15 +80,27 @@ std::ostream& operator<<(std::ostream& os, BinOpEnum& binOpEnum) { return os << "or"; case BinOpEnum::CONCAT: return os << ".."; - } -}; + case BinOpEnum::BSL: + return os << "<<"; + case BinOpEnum::BSR: + return os << ">>"; + case BinOpEnum::BWNOT: + return os << "~"; + case BinOpEnum::BWAND: + return os << "&"; + case BinOpEnum::BWOR: + return os << "|"; + case BinOpEnum::INTDIV: + return os << "//"; + } + throw std::runtime_error("invalid binary operator"); +};*/ // BinaryOperation BinaryOperation::BinaryOperation(ts::Node node) : bin_op(node) { if (node.type_id() != ts::NODE_BINARY_OPERATION || node.child_count() != 3) { throw std::runtime_error("not a binary_operation node"); } } -// TODO auto BinaryOperation::left() -> Expression { return Expression(bin_op.child(0).value()); } auto BinaryOperation::right() -> Expression { return Expression(bin_op.child(2).value()); } auto BinaryOperation::op() -> BinOpEnum { @@ -121,10 +151,6 @@ auto BinaryOperation::op() -> BinOpEnum { throw std::runtime_error("Unknown Binary Operator: " + op_str); } } -/*std::ostream& operator<<(std::ostream& os, BinaryOperation& binaryOperation){ - return os << binaryOperation.left().type() << (int)binaryOperation.op() << -binaryOperation.right().type(); -}*/ // UnaryOperation UnaryOperation::UnaryOperation(ts::Node node) : un_op(node) { if (node.type_id() != ts::NODE_UNARY_OPERATION || node.child_count() != 2) { @@ -154,7 +180,8 @@ auto UnaryOperation::exp() -> Expression { return Expression(un_op.child(0).valu // ForStatement ForStatement::ForStatement(ts::Node node) : for_statement(node) { - if (node.type_id() != ts::NODE_FOR_STATEMENT || !node.named_child(0).has_value() || node.named_child(0).value().type_id() != ts::NODE_LOOP_EXPRESSION) { + if (node.type_id() != ts::NODE_FOR_STATEMENT || !node.named_child(0).has_value() || + node.named_child(0).value().type_id() != ts::NODE_LOOP_EXPRESSION) { throw std::runtime_error("not a for_statement node"); } } @@ -164,58 +191,91 @@ auto ForStatement::body() -> Body { return Body(body); } -auto ForStatement::loop_exp() -> ts::Node { return for_statement.named_child(0).value(); } +auto ForStatement::loop_exp() -> LoopExpression { + return LoopExpression(for_statement.named_child(0).value()); +} LoopExpression::LoopExpression(ts::Node node) : loop_exp(node) { - if (node.type_id() != ts::NODE_LOOP_EXPRESSION || node.child_count()<3) { + if (node.type_id() != ts::NODE_LOOP_EXPRESSION || node.child_count() < 3) { throw std::runtime_error("not a loop_expression node"); } } -auto LoopExpression::variable() -> Identifier {return Identifier(loop_exp.named_child(0).value());} +auto LoopExpression::variable() -> Identifier { + return Identifier(loop_exp.named_child(0).value()); +} auto LoopExpression::end() -> Expression { - if(loop_exp.child_count()==4){ + if (loop_exp.named_child_count() == 4) { return Expression(loop_exp.named_child(3).value()); - }else{ + } else { return Expression(loop_exp.named_child(2).value()); } } -auto LoopExpression::start() -> Expression { return Expression(loop_exp.named_child(0).value()); } +auto LoopExpression::start() -> Expression { return Expression(loop_exp.named_child(1).value()); } auto LoopExpression::step() -> std::optional { - if(loop_exp.child_count()==4){ + if (loop_exp.named_child_count() == 4) { return Expression(loop_exp.named_child(2).value()); - }else{ + } else { return {}; } } -//TODO find way to split childern -InLoopExpression::InLoopExpression(ts::Node node) : loop_exp(node){ - if(node.type_id()!=ts::NODE_LOOP_EXPRESSION){ +InLoopExpression::InLoopExpression(ts::Node node) : loop_exp(node) { + if (node.type_id() != ts::NODE_LOOP_EXPRESSION) { throw std::runtime_error("not a loop_expression node"); } - } auto InLoopExpression::loop_exps() -> std::vector { - std::vector body = loop_exp.named_children(); - for(int i=0;i temp_body = loop_exp.children(); + std::vector body; + std::copy_if(temp_body.begin(), temp_body.end(), std::back_inserter(body), [](ts::Node node) { + return node.text() != ","; + }); + for (long unsigned int i = 0; i < body.size(); i++) { + if (body[i].type_id() != ts::NODE_IDENTIFIER) { std::vector res; - std::transform(body.begin()+i,body.end(),std::back_inserter(res),[](ts::Node node){return Expression(node);}); + std::transform( + body.begin() + i + 1, body.end(), std::back_inserter(res), + [](ts::Node node) { return Expression(node); }); return res; } } + throw std::runtime_error("invalid in_loop_expression"); } auto InLoopExpression::loop_vars() -> std::vector { - std::vector body = loop_exp.named_children(); - for(int i=0;i temp_body = loop_exp.children(); + std::vector body; + std::copy_if(temp_body.begin(), temp_body.end(), std::back_inserter(body), [](ts::Node node) { + return node.text() != ","; + }); + for (long unsigned int i = 0; i < body.size(); i++) { + if (body[i].type_id() != ts::NODE_IDENTIFIER) { std::vector res; - std::transform(body.begin(),body.begin()+i,std::back_inserter(res),[](ts::Node node){return Identifier(node);}); + std::transform( + body.begin(), body.begin() + i, std::back_inserter(res), + [](ts::Node node) { return Identifier(node); }); return res; } } + throw std::runtime_error("invalid in_loop_expression"); +} +// ForInStatement +ForInStatement::ForInStatement(ts::Node node) : for_in(node) { + if (node.type_id() != ts::NODE_FOR_IN_STATEMENT || !node.named_child(0).has_value() || + node.named_child(0)->type_id() != ts::NODE_LOOP_EXPRESSION) { + throw std::runtime_error("not a for_in_statement node"); + } +} +auto ForInStatement::loop_exp() -> InLoopExpression { + return InLoopExpression(for_in.named_child(0).value()); +} +auto ForInStatement::body() -> Body { + std::vector children = for_in.named_children(); + children.erase(children.begin()); + return Body(children); } -WhileStatement::WhileStatement(ts::Node node) : while_statement(node){ - if (node.type_id() != ts::NODE_WHILE_STATEMENT || !node.named_child(0).has_value() ||node.named_child(0).value().type_id()!=ts::NODE_CONDITION_EXPRESSION) { +// WhileStatement +WhileStatement::WhileStatement(ts::Node node) : while_statement(node) { + if (node.type_id() != ts::NODE_WHILE_STATEMENT || !node.named_child(0).has_value() || + node.named_child(0).value().type_id() != ts::NODE_CONDITION_EXPRESSION) { throw std::runtime_error("not a while_statement node"); } } @@ -226,10 +286,11 @@ auto WhileStatement::body() -> Body { return Body(body); } auto WhileStatement::exit_cond() -> Expression { - return Expression(while_statement.named_child(0).value()); + return Expression(while_statement.named_child(0).value().named_child(0).value()); } -RepeatStatement::RepeatStatement(ts::Node node) : repeat_statement(node){ - if (node.type_id() != ts::NODE_REPEAT_STATEMENT || (node.named_children().end()-1)->type_id()!=ts::NODE_CONDITION_EXPRESSION) { +RepeatStatement::RepeatStatement(ts::Node node) : repeat_statement(node) { + if (node.type_id() != ts::NODE_REPEAT_STATEMENT || + (node.named_children().end() - 1)->type_id() != ts::NODE_CONDITION_EXPRESSION) { throw std::runtime_error("not a repeat_statement node"); } } @@ -239,70 +300,82 @@ auto RepeatStatement::body() -> Body { return Body(body); } auto RepeatStatement::until_cond() -> Expression { - return Expression(repeat_statement.named_child(repeat_statement.named_child_count()-1).value()); -} -//If -IfStatement::IfStatement(ts::Node node) : if_statement(node){ - if (node.type_id() != ts::NODE_IF_STATEMENT || !node.named_child(0).has_value() || node.named_child(0).value().type_id()!=ts::NODE_CONDITION_EXPRESSION) { + return Expression(repeat_statement.named_child(repeat_statement.named_child_count() - 1) + .value() + .named_child(0) + .value()); +} +// If +IfStatement::IfStatement(ts::Node node) : if_statement(node) { + if (node.type_id() != ts::NODE_IF_STATEMENT || !node.named_child(0).has_value() || + node.named_child(0).value().type_id() != ts::NODE_CONDITION_EXPRESSION) { throw std::runtime_error("not an if_statement node"); } } auto IfStatement::cond() -> Expression { - return Expression(if_statement.named_child(0).value()); + return Expression(if_statement.named_child(0).value().named_child(0).value()); } auto IfStatement::else_() -> std::optional { - if(if_statement.named_child(if_statement.named_child_count()-1).has_value() && if_statement.named_child(if_statement.named_child_count()-1)->type_id()==ts::NODE_ELSE){ - return Else(if_statement.named_child(if_statement.named_child_count()-1).value()); - }else{ + if (if_statement.named_child(if_statement.named_child_count() - 1).has_value() && + if_statement.named_child(if_statement.named_child_count() - 1)->type_id() == + ts::NODE_ELSE) { + return Else(if_statement.named_child(if_statement.named_child_count() - 1).value()); + } else { return {}; } } auto IfStatement::elseifs() -> std::vector { + if (if_statement.named_child_count() == 1) { + return std::vector(); + } std::vector if_children = if_statement.named_children(); std::vector::iterator end; std::vector res; - if((if_children.end()-1)->type_id()==ts::NODE_ELSE){ - end = if_children.end()-1; - }else{ + if ((if_children.end() - 1)->type_id() == ts::NODE_ELSE) { + end = if_children.end() - 1; + } else { end = if_children.end(); } - std::vector::iterator begin = end; - if(begin->type_id()!=ts::NODE_ELSEIF){ - return res; - } - while((begin--)->type_id()==ts::NODE_ELSEIF){ + auto begin = end; + while ((begin - 1)->type_id() == ts::NODE_ELSEIF && begin - 1 != if_children.begin()) { begin--; } - std::transform(begin,end,std::back_inserter(res),[](ts::Node node){return ElseIf(node);}); + if (begin == end) { + return std::vector(); + } + std::transform(begin, end, std::back_inserter(res), [](ts::Node node) { return ElseIf(node); }); + return res; } auto IfStatement::body() -> Body { + if (if_statement.named_child_count() == 1 || + (if_statement.named_child(1).has_value() && + if_statement.named_child(1)->type_id() == ts::NODE_ELSEIF)) { + return Body(std::vector()); + } std::vector if_children = if_statement.named_children(); std::vector::iterator end; - if((if_children.end()-1)->type_id()==ts::NODE_ELSE){ - end = if_children.end()-1; - }else{ + + if ((if_children.end() - 1)->type_id() == ts::NODE_ELSE) { + end = if_children.end() - 1; + } else { end = if_children.end(); } - if(end->type_id()!=ts::NODE_ELSEIF){ - return Body(std::vector(if_children.begin()+1,end)); - } - while((end--)->type_id()==ts::NODE_ELSEIF){ + while ((end - 1)->type_id() == ts::NODE_ELSEIF) { end--; } - return Body(std::vector(if_children.begin()+1,end)); + return Body(std::vector(if_children.begin() + 1, end)); } -//Else -Else::Else(ts::Node node) : else_statement(node){ - if(node.type_id()!=ts::NODE_ELSE){ +// Else +Else::Else(ts::Node node) : else_statement(node) { + if (node.type_id() != ts::NODE_ELSE) { throw std::runtime_error("Not an else_statement node"); } } -auto Else::body() -> Body { - return Body(else_statement.named_children()); -} -//ElseIf +auto Else::body() -> Body { return Body(else_statement.named_children()); } +// ElseIf ElseIf::ElseIf(ts::Node node) : else_if(node) { - if (node.type_id() != ts::NODE_ELSEIF || !node.named_child(0).has_value() ||node.named_child(0).value().type_id()!=ts::NODE_CONDITION_EXPRESSION) { + if (node.type_id() != ts::NODE_ELSEIF || !node.named_child(0).has_value() || + node.named_child(0).value().type_id() != ts::NODE_CONDITION_EXPRESSION) { throw std::runtime_error("not a else_if node"); } } @@ -312,90 +385,105 @@ auto ElseIf::body() -> Body { return Body(body); } auto ElseIf::cond() -> Expression { - return Expression(else_if.named_child(0).value()); -} -//Return -Return::Return(ts::Node node) : expressions(node){ - + return Expression(else_if.named_child(0).value().named_child(0).value()); } +// Return +Return::Return(ts::Node node) : expressions(node) {} auto Return::explist() -> std::vector { std::vector exps = expressions.named_children(); std::vector::iterator end; std::vector res; - if(exps.size()>1 && exps[exps.size()-1].text()==";"s){ - end = exps.end()-1; - res.reserve(exps.size()-1); - }else{ + if (exps.size() > 1 && exps[exps.size() - 1].text() == ";"s) { + end = exps.end() - 1; + res.reserve(exps.size() - 1); + } else { end = exps.end(); res.reserve(exps.size()); } - std::transform(exps.begin(),end,std::back_inserter(res),[](ts::Node node){return Expression(node);}); + std::transform( + exps.begin(), end, std::back_inserter(res), [](ts::Node node) { return Expression(node); }); return res; } -//VariableDeclaration -VariableDeclaration::VariableDeclaration(ts::Node node) : var_dec(node){ - if(node.type_id()!=ts::NODE_VARIABLE_DECLARATION || node.named_child_count()<2 || node.named_child(0).value().type_id() != ts::NODE_VARIABLE_DECLARATOR){ - throw std::runtime_error("not a variable declaration node"); +// VariableDeclaration +VariableDeclaration::VariableDeclaration(ts::Node node) : var_dec(node) { + if (node.type_id() != ts::NODE_VARIABLE_DECLARATION || node.named_child_count() < 2 || + node.named_child(0).value().type_id() != 113) { + throw std::runtime_error(std::to_string(node.named_child(0)->type_id())); } } auto VariableDeclaration::declarations() -> std::vector { std::vector nodes = var_dec.named_children(); std::vector res; - std::vector::iterator it = nodes.begin(); - while(it->type_id() == ts::NODE_VARIABLE_DECLARATOR){ + auto it = nodes.begin(); + while (it->type_id() == 113) { it++; } - res.reserve(nodes.size()-(it-nodes.begin())); - std::transform(it,nodes.end(),std::back_inserter(res),[](ts::Node node){return Expression(node);}); + res.reserve(nodes.size() - (it - nodes.begin())); + std::transform( + it, nodes.end(), std::back_inserter(res), [](ts::Node node) { return Expression(node); }); return res; } auto VariableDeclaration::declarators() -> std::vector { std::vector nodes = var_dec.named_children(); std::vector res; - std::vector::iterator it = nodes.begin(); - while(it->type_id() == ts::NODE_VARIABLE_DECLARATOR){ + auto it = nodes.begin(); + while (it->type_id() == 113) { it++; } - res.reserve(it-nodes.begin()); - std::transform(nodes.begin(),it,std::back_inserter(res),[](ts::Node node){return VariableDeclarator(node);}); + res.reserve(it - nodes.begin()); + std::transform(nodes.begin(), it, std::back_inserter(res), [](ts::Node node) { + return VariableDeclarator(node); + }); return res; } -//VariableDeclarator -VariableDeclarator::VariableDeclarator(ts::Node node) : dec(node){ - if(node.type_id() != ts::NODE_VARIABLE_DECLARATOR){ +// VariableDeclarator +VariableDeclarator::VariableDeclarator(ts::Node node) : dec(node) { + if (node.type_id() != ts::NODE_VARIABLE_DECLARATOR && node.type_id() != ts::NODE_IDENTIFIER && + node.type_id() != ts::NODE_FIELD_EXPRESSION && + node.type_id() != 113) { // TODO add tableindex throw std::runtime_error("not a variable declarator"); } } -auto VariableDeclarator::var() -> std::variant { - if(dec.named_child_count()==1){ - if(dec.named_child(0) -> type_id() == ts::NODE_IDENTIFIER){ +auto VariableDeclarator::var() -> std::variant { + if (dec.type_id() == ts::NODE_IDENTIFIER) { + return Identifier(dec); + } else if (dec.type_id() == ts::NODE_FIELD_EXPRESSION) { + return FieldExpression(dec); + } // TODO add tableindex + if (dec.named_child_count() == 1) { + if (dec.named_child(0)->type_id() == ts::NODE_IDENTIFIER) { return Identifier(dec.named_child(0).value()); - }else if(dec.named_child(0) -> type_id() == ts::NODE_FIELD_EXPRESSION){ + } else if (dec.named_child(0)->type_id() == ts::NODE_FIELD_EXPRESSION) { return FieldExpression(dec.named_child(0).value()); + } else { + throw std::runtime_error("invalid variable declarator"); } - }else{ - return TableIndex();//TODO find good constructor for tableindex + } else { + return TableIndex(); // TODO find good constructor for tableindex } } -//LocalVariableDeclaration -LocalVariableDeclaration::LocalVariableDeclaration(ts::Node node) : local_var_dec(node){ - if(node.type_id() != ts::NODE_LOCAL_VARIABLE_DECLARATION || !node.named_child(0).has_value() || node.named_child(0) -> type_id() != ts::NODE_VARIABLE_DECLARATOR){ +// LocalVariableDeclaration +LocalVariableDeclaration::LocalVariableDeclaration(ts::Node node) : local_var_dec(node) { + if (node.type_id() != ts::NODE_LOCAL_VARIABLE_DECLARATION || !node.named_child(0).has_value() || + node.named_child(0)->type_id() != ts::NODE_VARIABLE_DECLARATOR) { throw std::runtime_error("not a local_variable_declaration node"); } } -auto LocalVariableDeclaration::declarator() -> LocalVariableDeclarator { - return LocalVariableDeclarator(local_var_dec.named_child(0).value()); +auto LocalVariableDeclaration::declarators() -> std::vector { + return LocalVariableDeclarator(local_var_dec.named_child(0).value()).vars(); } auto LocalVariableDeclaration::declarations() -> std::vector { std::vector nodes = local_var_dec.named_children(); std::vector res; - res.reserve(nodes.size()-1); - std::transform(nodes.begin()+1,nodes.end(),std::back_inserter(res),[](ts::Node node){return Expression(node);}); + res.reserve(nodes.size() - 1); + std::transform(nodes.begin() + 1, nodes.end(), std::back_inserter(res), [](ts::Node node) { + return Expression(node); + }); return res; } -//LocalVariableDeclarator -LocalVariableDeclarator::LocalVariableDeclarator(ts::Node node) : var_dec(node){ - if(node.type_id() != ts::NODE_VARIABLE_DECLARATOR){ +// LocalVariableDeclarator +LocalVariableDeclarator::LocalVariableDeclarator(ts::Node node) : var_dec(node) { + if (node.type_id() != ts::NODE_VARIABLE_DECLARATOR) { throw std::runtime_error("not a local_variable_declarator node"); } } @@ -403,36 +491,302 @@ auto LocalVariableDeclarator::vars() -> std::vector { std::vector nodes = var_dec.named_children(); std::vector res; res.reserve(nodes.size()); - std::transform(nodes.begin(),nodes.end(),std::back_inserter(res),[](ts::Node node){return Identifier(node);}); + std::transform(nodes.begin(), nodes.end(), std::back_inserter(res), [](ts::Node node) { + return Identifier(node); + }); return res; } - +// DoStatement +DoStatement::DoStatement(ts::Node node) : do_statement(node) { + if (node.type_id() != ts::NODE_DO_STATEMENT) { + throw std::runtime_error("not a do_statement node"); + } +} +auto DoStatement::body() -> Body { return Body(do_statement.named_children()); } +// FieldExpression +FieldExpression::FieldExpression(ts::Node node) : exp(node) { + if (node.type_id() != ts::NODE_FIELD_EXPRESSION || node.named_child_count() != 2) { + throw std::runtime_error("not a field_expression node"); + } +} +auto FieldExpression::table_id() -> Prefix { return Prefix(exp.named_child(0).value()); } +auto FieldExpression::property_id() -> Identifier { return Identifier(exp.named_child(1).value()); } +// Label +Label::Label(ts::Node node) : label(node) { + if (node.type_id() != ts::NODE_LABEL_STATEMENT || node.named_child_count() < 1) { + throw std::runtime_error("not a label node"); + } +} +auto Label::id() -> Identifier { return Identifier(label.named_child(0).value()); } +// GoTo +GoTo::GoTo(ts::Node node) : go_to(node) { + if (node.type_id() != ts::NODE_GOTO_STATEMENT || node.named_child_count() < 1) { + throw std::runtime_error("not a go_to node"); + } +} +auto GoTo::label() -> Identifier { return Identifier(go_to.named_child(0).value()); } +// Parameters +Parameters::Parameters(ts::Node node) : parameters(node) { + if (node.type_id() != ts::NODE_PARAMETERS) { + throw std::runtime_error("not a parameters node"); + } +} +auto Parameters::leading_self() -> bool { + if (parameters.named_child_count() < 1) { + return false; + } else { + return parameters.named_child(0)->type_id() == ts::NODE_SELF; + } +} +auto Parameters::spread() -> SpreadPos { + if (parameters.named_child_count() < 1) { + return SpreadPos::NO_SPREAD; + } else if (parameters.named_child(0)->type_id() == ts::NODE_SPREAD) { + return SpreadPos::BEGIN; + } else if ( + parameters.named_child(parameters.named_child_count() - 1)->type_id() == ts::NODE_SPREAD) { + return SpreadPos::END; + } else { + return SpreadPos::NO_SPREAD; + } +} +auto Parameters::params() -> std::vector { + SpreadPos sp = spread(); + std::vector res; + std::vector children = parameters.named_children(); + if (leading_self()) { + if (sp == NO_SPREAD) { + if (parameters.named_child_count() < 1) { + return res; + } + res.reserve(parameters.named_child_count() - 1); + std::transform( + children.begin() + 1, children.end(), std::back_inserter(res), + [](ts::Node node) { return Identifier(node); }); + } else { + if (parameters.named_child_count() < 2) { + return res; + } + res.reserve(parameters.named_child_count() - 2); + std::transform( + children.begin() + 1, children.end() - 1, std::back_inserter(res), + [](ts::Node node) { return Identifier(node); }); + } + } else { + switch (sp) { + case NO_SPREAD: + res.reserve(parameters.named_child_count()); + std::transform( + children.begin(), children.end(), std::back_inserter(res), + [](ts::Node node) { return Identifier(node); }); + break; + case BEGIN: + if (parameters.named_child_count() < 1) { + return res; + } + res.reserve(parameters.named_child_count() - 1); + std::transform( + children.begin() + 1, children.end(), std::back_inserter(res), + [](ts::Node node) { return Identifier(node); }); + break; + case END: + if (parameters.named_child_count() < 1) { + return res; + } + res.reserve(parameters.named_child_count() - 1); + std::transform( + children.begin(), children.end() - 1, std::back_inserter(res), + [](ts::Node node) { return Identifier(node); }); + break; + } + } + return res; +} +// FunctionName +FunctionName::FunctionName(ts::Node node) : func_name(node) { + if (node.type_id() != ts::NODE_FUNCTION_NAME) { + throw std::runtime_error("Not a function_name node"); + } +} +auto FunctionName::method() -> std::optional { + if (func_name.named_child(func_name.named_child_count() - 1)->type_id() == ts::NODE_METHOD) { + return Identifier(func_name.named_child(func_name.named_child_count() - 1).value()); + } else { + return {}; + } +} +auto FunctionName::identifier() -> std::vector { + if (func_name.named_child(0)->type_id() == ts::NODE_IDENTIFIER) { + return std::vector{Identifier(func_name.named_child(0).value())}; + } else { + std::vector res; + std::vector children = func_name.named_child(0).value().named_children(); + res.reserve(children.size()); + std::transform( + children.begin(), children.end(), std::back_inserter(res), + [](ts::Node node) { return Identifier(node); }); + return res; + } +} +// FunctionDefinition +FunctionDefinition::FunctionDefinition(ts::Node node) : func_def(node) { + if (node.type_id() != ts::NODE_FUNCTION_DEFINITION) { + throw std::runtime_error("not a function_definition node"); + } +} +auto FunctionDefinition::parameters() -> Parameters { + return Parameters(func_def.named_child(0).value()); +} +auto FunctionDefinition::body() -> Body { + std::vector children = func_def.named_children(); + return Body(std::vector(children.begin() + 1, children.end())); +} +// FunctionStatement +FunctionStatement::FunctionStatement(ts::Node node) : func_stat(node) { + if (node.type_id() != ts::NODE_FUNCTION) { + throw std::runtime_error("not a function(_statement) node"); + } +} +auto FunctionStatement::body() -> Body { + std::vector children = func_stat.named_children(); + return Body(std::vector(children.begin() + 2, children.end())); +} +auto FunctionStatement::name() -> FunctionName { + return FunctionName(func_stat.named_child(0).value()); +} +auto FunctionStatement::parameters() -> Parameters { + return Parameters(func_stat.named_child(1).value()); +} +// LocalFunctionStatement +LocalFunctionStatement::LocalFunctionStatement(ts::Node node) : func_stat(node) { + if (node.type_id() != ts::NODE_LOCAL_FUNCTION) { + throw std::runtime_error("not a function(_statement) node"); + } +} +auto LocalFunctionStatement::parameters() -> Parameters { + return Parameters(func_stat.named_child(1).value()); +} +auto LocalFunctionStatement::name() -> Identifier { + return Identifier(func_stat.named_child(0).value()); +} +auto LocalFunctionStatement::body() -> Body { + std::vector children = func_stat.named_children(); + return Body(std::vector(children.begin() + 2, children.end())); +} +// FunctionCall +FunctionCall::FunctionCall(ts::Node node) : func_call(node) { + if (node.type_id() != ts::NODE_FUNCTION_CALL || node.named_child_count() < 2 || + node.named_child_count() > 3) { + throw runtime_error("not a function_call node"); + } +} +auto FunctionCall::method() -> std::optional { + if (func_call.named_child_count() == 3) { + return Identifier(func_call.named_child(1).value()); + } else { + return {}; + } +} +auto FunctionCall::id() -> Prefix { return Prefix(func_call.named_child(0).value()); } +auto FunctionCall::args() -> std::vector { + std::vector arg_nodes = + func_call.named_child(func_call.named_child_count() - 1).value().named_children(); + std::vector args; + args.reserve(arg_nodes.size()); + std::transform(arg_nodes.begin(), arg_nodes.end(), std::back_inserter(args), [](ts::Node node) { + return Expression(node); + }); + return args; +} +// GlobalVariable +GlobalVariable::GlobalVariable(ts::Node node) : g_var(node) { + if (node.type_id() != ts::NODE_GLOBAL_VARIABLE || + !(node.text() == "_G" || node.text() == "_VERSION")) { + throw runtime_error("not a global variable node"); + } +} +auto GlobalVariable::type() -> GV { + if (g_var.text() == "_G") { + return GV::_G; + } else { + return GV::_VERSION; + } +} +// Table +Table::Table(ts::Node node) : table(node) { + if (node.type_id() != ts::NODE_TABLE) { + throw runtime_error("not a table node"); + } +} +auto Table::fields() -> std::vector { + if (table.named_child_count() < 1) { + return std::vector(); + } + std::vector fields; + fields.reserve(table.named_child_count()); + std::vector nodes = table.named_children(); + std::transform(nodes.begin(), nodes.end(), std::back_inserter(fields), [](ts::Node node) { + return Field(node); + }); + return fields; +} +// Field +Field::Field(ts::Node node) : field(node) { + if (node.type_id() != ts::NODE_FIELD || node.named_child_count() > 2 || + node.named_child_count() < 1) { + throw runtime_error("not a field node"); + } +} +auto Field::content() -> std::variant< + std::pair, std::pair, Expression> { + if (field.named_child_count() < 2) { + return Expression(field.named_child(0).value()); + } else if (field.child(0)->text() == "[") { + return std::pair( + Expression(field.named_child(0).value()), Expression(field.named_child(1).value())); + } else { + return std::pair( + Identifier(field.named_child(0).value()), Expression(field.named_child(1).value())); + } +} // Prefix Prefix::Prefix(ts::Node node) : prefix(node) { if (!(node.type_id() == ts::NODE_SELF || node.type_id() == ts::NODE_GLOBAL_VARIABLE || - node.type_id() == ts::NODE_FUNCTION_CALL || node.child(0)->text() == "(")) { + node.type_id() == ts::NODE_FUNCTION_CALL || node.type_id() == ts::NODE_IDENTIFIER || + node.type_id() == ts::NODE_FIELD_EXPRESSION)) { // TODO add tableindex throw std::runtime_error("Not a prefix-node"); } } -auto Prefix::options() -> std::variant { if(prefix.type_id() == ts::NODE_SELF){ return Self(); }else if(prefix.type_id() == -ts::NODE_GLOBAL_VARIABLE){ return GlobalVariable(prefix); }else if(prefix.type_id() == -ts::NODE_FUNCTION_CALL){ return FunctionCall(prefix); }else if(prefix.child(0)->text() == "("){ +auto Prefix::options() + -> std::variant { + if (prefix.type_id() == ts::NODE_SELF) { + return Self(); + } else if (prefix.type_id() == ts::NODE_GLOBAL_VARIABLE) { + return GlobalVariable(prefix); + } else if (prefix.type_id() == ts::NODE_FUNCTION_CALL) { + return FunctionCall(prefix); + } else if (prefix.child_count() > 0 && prefix.child(0)->text() == "(") { return Expression(prefix.child(1).value()); - }else{ + } else if ( + prefix.type_id() == ts::NODE_IDENTIFIER || + prefix.type_id() == ts::NODE_FIELD_EXPRESSION) { // TODO add table index + return VariableDeclarator(prefix); + } else { throw std::runtime_error("Not a prefix-node"); } } -//Expression -Expression::Expression(ts::Node node) : exp(node){ - if(!(node.type_id() == ts::NODE_SPREAD || node.type_id() == ts::NODE_NEXT || node.type_id() == -ts::NODE_FUNCTION_DEFINITION || node.type_id() == ts::NODE_TABLE || node.type_id() == -ts::NODE_BINARY_OPERATION || node.type_id() == ts::NODE_UNARY_OPERATION || node.type_id() == -ts::NODE_STRING || node.type_id() == ts::NODE_NUMBER || node.type_id() == ts::NODE_NIL || -node.type_id() == ts::NODE_FALSE || node.type_id() == ts::NODE_TRUE || node.type_id() == -ts::NODE_IDENTIFIER || (node.type_id() == ts::NODE_SELF || node.type_id() == -ts::NODE_GLOBAL_VARIABLE || node.type_id() == ts::NODE_FUNCTION_CALL || node.child(0)->text() == -"("))){ throw std::runtime_error("Not an expression-node"); +// Expression +Expression::Expression(ts::Node node) : exp(node) { + if (!(node.type_id() == ts::NODE_SPREAD || node.type_id() == ts::NODE_NEXT || + node.type_id() == ts::NODE_FUNCTION_DEFINITION || node.type_id() == ts::NODE_TABLE || + node.type_id() == ts::NODE_BINARY_OPERATION || + node.type_id() == ts::NODE_UNARY_OPERATION || node.type_id() == ts::NODE_STRING || + node.type_id() == ts::NODE_NUMBER || node.type_id() == ts::NODE_NIL || + node.type_id() == ts::NODE_FALSE || node.type_id() == ts::NODE_TRUE || + node.type_id() == ts::NODE_IDENTIFIER || + (node.type_id() == ts::NODE_SELF || node.type_id() == ts::NODE_GLOBAL_VARIABLE || + node.type_id() == ts::NODE_FUNCTION_CALL || node.child(0)->text() == "("))) { + throw std::runtime_error("Not an expression-node"); } } auto Expression::options() -> std::variant< @@ -451,11 +805,12 @@ auto Expression::options() -> std::variant< } else if (exp.type_id() == ts::NODE_UNARY_OPERATION) { return UnaryOperation(exp); } else if (exp.type_id() == ts::NODE_STRING) { - return minilua::Value(exp.text()); + std::string str = exp.text(); + return minilua::Value(String(std::string(str.begin() + 1, str.end() - 1))); } else if (exp.type_id() == ts::NODE_NUMBER) { - return minilua::Value();//TODO parse number and put into value + return minilua::Value(Number(stoi(exp.text()))); // TODO parse number and put into value } else if (exp.type_id() == ts::NODE_NIL) { - return minilua::Value(Nil()); + return minilua::Value(Value::Type(Nil())); } else if (exp.type_id() == ts::NODE_TRUE) { return minilua::Value(true); } else if (exp.type_id() == ts::NODE_FALSE) { @@ -464,62 +819,65 @@ auto Expression::options() -> std::variant< return Identifier(exp); } else if ( exp.type_id() == ts::NODE_SELF || exp.type_id() == ts::NODE_FUNCTION_CALL || - exp.type_id() == ts::NODE_GLOBAL_VARIABLE || - (exp.child(0).has_value() && exp.child(0)->text() == "(")) { + exp.type_id() == ts::NODE_GLOBAL_VARIABLE || exp.type_id() == ts::NODE_FIELD_EXPRESSION || + (exp.child(0).has_value() && exp.child(0)->text() == "(")) { // TODO add TableIndex to if return Prefix(exp); } else { throw std::runtime_error("Not an expression-node"); } } -//Statement -Statement::Statement(ts::Node node) : statement(node){ - if(!(node.type_id() == ts::NODE_EXPRESSION || node.type_id() == ts::NODE_VARIABLE_DECLARATION || -node.type_id() == ts::NODE_LOCAL_VARIABLE_DECLARATION || node.type_id() == ts::NODE_DO_STATEMENT || -node.type_id() == ts::NODE_IF_STATEMENT || node.type_id() == ts::NODE_WHILE_STATEMENT || -node.type_id() == ts::NODE_REPEAT_STATEMENT || node.type_id() == ts::NODE_FOR_STATEMENT || -node.type_id() == ts::NODE_FOR_IN_STATEMENT || node.type_id() == ts::NODE_GOTO_STATEMENT || -node.type_id() == ts::NODE_BREAK_STATEMENT || node.type_id() == ts::NODE_LABEL_STATEMENT || -node.type_id() == ts::NODE_FUNCTION || node.type_id() == ts::NODE_LOCAL_FUNCTION || node.type_id() -== ts::NODE_FUNCTION_CALL || (node.child(0).has_value() && node.child(0) -> text() == ";"))){ throw -std::runtime_error("Not a statement-node"); - } -} -auto Statement::options() -> std::variant { if(statement.type_id() == -ts::NODE_EXPRESSION){ return Expression(statement.named_child(0).value()); }else -if(statement.type_id() == ts::NODE_VARIABLE_DECLARATION){ return VariableDeclaration(statement); - }else if(statement.type_id() == ts::NODE_LOCAL_VARIABLE_DECLARATION){ +// Statement +Statement::Statement(ts::Node node) : statement(node) { + if (!(node.type_id() == ts::NODE_EXPRESSION || + node.type_id() == ts::NODE_VARIABLE_DECLARATION || + node.type_id() == ts::NODE_LOCAL_VARIABLE_DECLARATION || + node.type_id() == ts::NODE_DO_STATEMENT || node.type_id() == ts::NODE_IF_STATEMENT || + node.type_id() == ts::NODE_WHILE_STATEMENT || + node.type_id() == ts::NODE_REPEAT_STATEMENT || node.type_id() == ts::NODE_FOR_STATEMENT || + node.type_id() == ts::NODE_FOR_IN_STATEMENT || + node.type_id() == ts::NODE_GOTO_STATEMENT || node.type_id() == ts::NODE_BREAK_STATEMENT || + node.type_id() == ts::NODE_LABEL_STATEMENT || node.type_id() == ts::NODE_FUNCTION || + node.type_id() == ts::NODE_LOCAL_FUNCTION || node.type_id() == ts::NODE_FUNCTION_CALL || + (node.child(0).has_value() && node.child(0)->text() == ";"))) { + throw std::runtime_error("Not a statement-node" + to_string(node.type_id())); + } +} +auto Statement::options() -> std::variant< + VariableDeclaration, LocalVariableDeclaration, DoStatement, IfStatement, WhileStatement, + RepeatStatement, ForStatement, ForInStatement, GoTo, Break, Label, FunctionStatement, + LocalFunctionStatement, FunctionCall, Expression> { + if (statement.type_id() == ts::NODE_EXPRESSION) { + return Expression(statement.named_child(0).value()); + } else if (statement.type_id() == ts::NODE_VARIABLE_DECLARATION) { + return VariableDeclaration(statement); + } else if (statement.type_id() == ts::NODE_LOCAL_VARIABLE_DECLARATION) { return LocalVariableDeclaration(statement); - }else if(statement.type_id() == ts::NODE_DO_STATEMENT){ + } else if (statement.type_id() == ts::NODE_DO_STATEMENT) { return DoStatement(statement); - }else if(statement.type_id() == ts::NODE_IF_STATEMENT){ + } else if (statement.type_id() == ts::NODE_IF_STATEMENT) { return IfStatement(statement); - }else if(statement.type_id() == ts::NODE_WHILE_STATEMENT){ + } else if (statement.type_id() == ts::NODE_WHILE_STATEMENT) { return WhileStatement(statement); - }else if(statement.type_id() == ts::NODE_REPEAT_STATEMENT){ + } else if (statement.type_id() == ts::NODE_REPEAT_STATEMENT) { return RepeatStatement(statement); - }else if(statement.type_id() == ts::NODE_FOR_STATEMENT){ + } else if (statement.type_id() == ts::NODE_FOR_STATEMENT) { return ForStatement(statement); - }else if(statement.type_id() == ts::NODE_FOR_IN_STATEMENT){ + } else if (statement.type_id() == ts::NODE_FOR_IN_STATEMENT) { return ForInStatement(statement); - }else if(statement.type_id() == ts::NODE_GOTO_STATEMENT){ + } else if (statement.type_id() == ts::NODE_GOTO_STATEMENT) { return GoTo(statement); - }else if(statement.type_id() == ts::NODE_BREAK_STATEMENT){ + } else if (statement.type_id() == ts::NODE_BREAK_STATEMENT) { return Break(); - }else if(statement.type_id() == ts::NODE_LABEL_STATEMENT){ + } else if (statement.type_id() == ts::NODE_LABEL_STATEMENT) { return Label(statement); - }else if(statement.type_id() == ts::NODE_FUNCTION){ + } else if (statement.type_id() == ts::NODE_FUNCTION) { return FunctionStatement(statement); - }else if(statement.type_id() == ts::NODE_LOCAL_FUNCTION){ + } else if (statement.type_id() == ts::NODE_LOCAL_FUNCTION) { return LocalFunctionStatement(statement); - }else if(statement.type_id() == ts::NODE_FUNCTION_CALL){ + } else if (statement.type_id() == ts::NODE_FUNCTION_CALL) { return FunctionCall(statement); - }else if((statement.child(0).has_value() && statement.child(0) -> text() == ";")){ - return Empty(); - }else{ + } else { throw std::runtime_error("Not a statement-node"); } } -} -} \ No newline at end of file +} // namespace minilua::details \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d63a5ccd..97c03faf 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,22 +1,14 @@ -# DEPENDENCIES -FetchContent_Declare( - Catch2 - GIT_REPOSITORY https://github.com/catchorg/Catch2.git - GIT_TAG v2.13.0) -FetchContent_MakeAvailable(Catch2) -FetchContent_MakeAvailable(tree-sitter) - add_executable(MiniLua-tests - main.cpp - unit_tests.cpp - integration_tests.cpp - public_api/integration_tests.cpp - public_api/owning_ptr.cpp - public_api/values.cpp - public_api/origin.cpp - public_api/environment.cpp - tree_sitter.cpp - tree_sitter_ast_tests.cpp) + main.cpp + unit_tests.cpp + integration_tests.cpp + public_api/integration_tests.cpp + public_api/owning_ptr.cpp + public_api/values.cpp + public_api/origin.cpp + public_api/environment.cpp + tree_sitter.cpp + tree_sitter_ast_tests.cpp) target_include_directories(MiniLua-tests PRIVATE ${tree-sitter_SOURCE_DIR}/lib/include) target_link_libraries(MiniLua-tests PRIVATE MiniLua @@ -25,4 +17,4 @@ target_link_libraries(MiniLua-tests if(COVERAGE) setup_target_for_coverage(MiniLua-tests-coverage MiniLua-tests coverage) -endif() +endif() \ No newline at end of file diff --git a/tests/tree_sitter_ast_tests.cpp b/tests/tree_sitter_ast_tests.cpp index d013f10f..2bc6a33d 100644 --- a/tests/tree_sitter_ast_tests.cpp +++ b/tests/tree_sitter_ast_tests.cpp @@ -1,154 +1,761 @@ +#include "MiniLua/tree_sitter_ast.hpp" +#include "tree_sitter/tree_sitter.hpp" #include -#include #include #include -#include "tree_sitter/tree_sitter.hpp" -#include "MiniLua/tree_sitter_ast.hpp" -using namespace std::string_literals; - -std::basic_string all_children(ts::Node node){ - std::vector children = node.children(); - std::basic_string res; - std::vector::iterator it; - for(it = children.begin();it!=children.end();it++){ - res += it->as_s_expr(); - res += "\n\n"; +namespace minilua::details { +TEST_CASE("statements", "[tree-sitter][!hide]") { + ts::Parser parser; + std::string source = "i,t,l = 5\n" + "local z = 42\n" + "do\n" + "z = i+k\n" + "end\n" + "if z>k then\n" + "else\n" + "end\n" + "while z>k do\n" + "z = z-1\n" + "end\n" + "repeat\n" + "z = z*k\n" + "until z> k^10\n" + "for l = 1,9 do\n" + "z = z-l\n" + "end\n" + "for k, v in next, t, nil do\n" + " print(k, v)\n" + "end\n" + "goto alpha\n" + "break\n" + "::alpha::\n" + "function foo (f,o,o)\n" + "return f,o*o\n" + "end\n" + "local function foo (f,o,oo)\n" + "return f,o*oo\n" + "end\n" + "foo(i,k,z)\n" + "function (a,b)\n" + "print(a .. b)\n" + "end\n"; + ts::Tree tree = parser.parse_string(source); + ts::Node root = tree.root_node(); + auto prog = Program(root); + Body body = prog.body(); + assert(!body.ret().has_value()); + vector statement = body.statements(); + assert(statement.size() == 15); + long unsigned int statement_count = statement.size(); + // this loop tests if each statement got parsed to the right Class + for (long unsigned int i = 0; i < statement_count; i++) { + assert(statement.at(i).options().index() == i); } - return res; } +TEST_CASE("expressions", "[tree-sitter][!hide]") { + uint exp_count = 29; + ts::Parser parser; + std::string source = "...\n" + "next\n" + "function (a,b)\n" + " foo()\n" + "end\n" + "{1,2,3,4,5}\n" + "1+1\n" + "1-1\n" + "1*1\n" + "1/1\n" + "1%1\n" + "1^1\n" + "1<1\n" + "1>1\n" + "1<=1\n" + "1>=1\n" + "1==1\n" + "1~=1\n" + "1 .. a\n" + "true and true\n" + "true or true\n" + "1<<1\n" + "1>>1\n" + "1~1\n" + "1|1\n" + "1&1\n" + "1//1\n" + "nil\n" + "true\n" + "false\n" + "id\n" + "d = not true\n" + "c = -1\n" + "a = #table\n" + "b = ~a\n"; + ts::Tree tree = parser.parse_string(source); + ts::Node root = tree.root_node(); + auto prog = Program(root); + Body body = prog.body(); + assert(!body.ret().has_value()); + vector statement = body.statements(); + vector exps; + exps.reserve(exp_count); + std::transform( + statement.begin(), statement.begin() + exp_count, std::back_inserter(exps), + [](Statement statement) { + auto opt = statement.options(); + return *std::get_if(&opt); + }); + auto spread = exps[0].options(); + assert(spread.index() == 0); + auto next = exps[1].options(); + assert(next.index() == 2); + auto func_def = exps[2].options(); + assert(func_def.index() == 3); + auto table = exps[3].options(); + assert(table.index() == 4); + vector bin_ops; + bin_ops.reserve(25); + std::transform( + exps.begin() + 4, exps.begin() + 25, std::back_inserter(bin_ops), [](Expression exp) { + auto opt = exp.options(); + return *get_if(&opt); + }); + for (uint i = 0; i < bin_ops.size(); i++) { + assert( + bin_ops[i].op() == + (BinOpEnum)i); // Bin Operations are in the same sequence as in the BinOpEnum + } -std::basic_string all_named_children(ts::Node node){ - std::vector children = node.named_children(); - std::basic_string res; - std::vector::iterator it; - for(it = children.begin();it!=children.end();it++){ - res += it->as_s_expr(); - res += "\n\n"; + auto nil = exps[25].options(); + assert(holds_alternative(nil)); + auto* temp = get_if(&nil); + assert(temp->is_nil()); + auto _true = exps[26].options(); + assert(holds_alternative(_true)); + temp = get_if(&_true); + assert(temp->is_bool() && temp == Value(true)); + auto* b = get_if(&(temp->raw())); + assert(b->operator bool()); + auto _false = exps[27].options(); + assert(holds_alternative(_false)); + temp = get_if(&_false); + assert(temp->is_bool()); + b = get_if(&(temp->raw())); + assert(!(b->operator bool())); + auto id = exps[28].options(); + assert(holds_alternative(id)); + Identifier temp2 = *get_if(&id); + assert(temp2.str() == "id"s); + vector un_op; + un_op.reserve(4); + std::transform( + statement.begin() + exp_count, statement.end(), std::back_inserter(un_op), + [](Statement stat) { + auto opt = stat.options(); + auto* vd = std::get_if(&opt); + auto exps = vd->declarations(); + auto exp = exps[0].options(); + assert(holds_alternative(exp)); + return *get_if(&exp); + }); + for (uint j = 0; j < un_op.size(); j++) { + assert(un_op[j].op() == (UnOpEnum)j); } - return res; } -/*TEST_CASE("Print3", "[tree-sitter][!hide]") { +TEST_CASE("do_statements", "[tree-sitter][!hide]") { ts::Parser parser; - - std::string source = "local teams = {\n" - " [\"teamA\"] = 12,\n" - " [\"teamB\"] = 15\n" - "}\n" - "\n" - "print(teams[\"teamA\"]) -- 12\n" - "\n" - "for key,value in pairs(teams) do\n" - " print(key .. \":\" .. value)\n" + std::string source = "do\n" + "end\n" + "do\n" + "1+1\n" + "end\n" + "do\n" + "1+1\n" + "2+2\n" + "end\n" + "do\n" + "return 2\n" + "end\n" + "do\n" + "1+1\n" + "return 1+1\n" "end"; ts::Tree tree = parser.parse_string(source); ts::Node root = tree.root_node(); - - INFO(all_named_children(root)); - FAIL(); + auto prog = Program(root); + Body body = prog.body(); + auto stats = body.statements(); + assert(stats.size() == 5); + assert(!body.ret().has_value()); + std::vector dos; + std::transform(stats.begin(), stats.end(), std::back_inserter(dos), [](Statement stat) { + auto opt = stat.options(); + assert(std::holds_alternative(opt)); + return *std::get_if(&opt); + }); + assert(dos.size() == 5); + assert(dos[0].body().statements().empty()); + assert(!dos[0].body().ret().has_value()); + assert(dos[1].body().statements().size() == 1); + assert(!dos[1].body().ret().has_value()); + assert(dos[2].body().statements().size() == 2); + assert(!dos[2].body().ret().has_value()); + assert(dos[3].body().statements().empty()); + assert(dos[3].body().ret().has_value()); + assert(dos[4].body().statements().size() == 1); + assert(dos[4].body().ret().has_value()); } - -TEST_CASE("iftest", "[tree-sitter][!hide]") { +TEST_CASE("if_statements", "[tree-sitter][!hide]") { ts::Parser parser; - - std::string source = "if 1<4 then\n1+1\n2+2\n3+3\nelseif false then\n2+2\nelseif true then\n1+1\nelse 3+3\nend"; + std::string source = "if c ifs; + std::transform(stats.begin(), stats.end(), std::back_inserter(ifs), [](Statement stat) { + auto opt = stat.options(); + assert(std::holds_alternative(opt)); + return *std::get_if(&opt); + }); + assert(ifs.size() == 6); + assert(holds_alternative(ifs[0].cond().options())); + assert(ifs[0].body().statements().empty()); + assert(!ifs[0].body().ret().has_value()); + assert(ifs[0].elseifs().size() == 2); + assert(holds_alternative(ifs[0].elseifs()[0].cond().options())); + assert(ifs[0].elseifs()[0].body().statements().size() == 1); + assert(!ifs[0].elseifs()[0].body().ret().has_value()); + assert(holds_alternative(ifs[0].elseifs()[1].cond().options())); + assert(ifs[0].elseifs()[1].body().statements().size() == 2); + assert(!ifs[0].elseifs()[1].body().ret().has_value()); + assert(ifs[0].else_().has_value()); + assert(ifs[0].else_().value().body().statements().empty()); + assert(ifs[0].else_().value().body().ret().has_value()); + assert(std::holds_alternative( + ifs[0].else_().value().body().ret().value().explist()[0].options())); + assert(ifs[1].body().statements().empty()); + assert(ifs[1].body().ret().has_value()); + assert(ifs[1].elseifs().empty()); + assert(!ifs[1].else_().has_value()); + assert(holds_alternative(ifs[1].cond().options())); + assert(holds_alternative(ifs[2].cond().options())); + assert(ifs[2].body().statements().size() == 1); + assert(!ifs[2].body().ret().has_value()); + assert(ifs[2].elseifs().empty()); + assert(ifs[2].else_().has_value()); + assert(ifs[2].else_().value().body().statements().size() == 1); + assert(!ifs[2].else_().value().body().ret().has_value()); + assert(holds_alternative(ifs[3].cond().options())); + assert(ifs[3].body().statements().empty()); + assert(!ifs[3].body().ret().has_value()); + assert(ifs[3].elseifs().empty()); + assert(ifs[3].else_().has_value()); + assert(ifs[3].else_().value().body().statements().size() == 1); + assert(!ifs[3].else_().value().body().ret().has_value()); + assert(holds_alternative(ifs[4].cond().options())); + assert(ifs[4].body().statements().size() == 1); + assert(!ifs[4].body().ret().has_value()); + assert(ifs[4].elseifs().size() == 2); + assert(!ifs[4].else_().has_value()); + assert(ifs[4].elseifs()[0].body().statements().size() == 1); + assert(!ifs[4].elseifs()[0].body().ret().has_value()); + assert(ifs[4].elseifs()[1].body().statements().size() == 2); + assert(!ifs[4].elseifs()[1].body().ret().has_value()); + assert(ifs[5].body().statements().empty()); + assert(!ifs[5].body().ret().has_value()); + assert(ifs[5].elseifs().empty()); + assert(!ifs[5].else_().has_value()); } -TEST_CASE("functiontest", "[tree-sitter][!hide]") { +TEST_CASE("for_statements", "[tree-sitter][!hide]") { ts::Parser parser; - std::string source = "function tester(a,b,c)\nreturn a+b+c\nend\nlocal function t(a,b,c)\nreturn a,b,c\nend"; + std::string source = "for i = 1,2 do\n" + " foo(12)\n" + "end\n" + + "for i = 1,2 do\n" + "end\n" + + "for c = a,b,42 do\n" + " foo()\n" + " s = a+c+s\n" + " f = 36+6\n" + "end"; ts::Tree tree = parser.parse_string(source); ts::Node root = tree.root_node(); + auto prog = Program(root); + Body body = prog.body(); + auto stats = body.statements(); + assert(stats.size() == 3); + assert(!body.ret().has_value()); + std::vector fors; + std::transform(stats.begin(), stats.end(), std::back_inserter(fors), [](Statement stat) { + auto opt = stat.options(); + assert(std::holds_alternative(opt)); + return *std::get_if(&opt); + }); + assert(fors.size() == 3); + // 1st loop + assert(fors[0].body().statements().size() == 1); + assert(!fors[0].body().ret().has_value()); + assert(fors[0].loop_exp().variable().str() == "i"s); + auto start1_opt = fors[0].loop_exp().start().options(); + assert(holds_alternative(start1_opt)); + auto* start1 = get_if(&start1_opt); + assert(start1->is_number()); + assert(holds_alternative(start1->raw())); + if (auto* num1 = get_if(&start1->raw())) { + assert(num1->value == 1); + } + auto end1_opt = fors[0].loop_exp().end().options(); + assert(holds_alternative(end1_opt)); + auto* end1 = get_if(&end1_opt); + assert(end1->is_number()); + assert(holds_alternative(end1->raw())); + if (auto* num2 = get_if(&end1->raw())) { + assert(num2->value == 2); + } + assert(!fors[0].loop_exp().step().has_value()); + // 2nd loop just to check if the empty body works fine here + assert(fors[1].body().statements().empty()); + // 3rd loop + assert(fors[2].body().statements().size() == 3); + assert(!fors[2].body().ret().has_value()); + // checking the loopexpression + assert(fors[2].loop_exp().variable().str() == "c"s); + auto start3_opt = fors[2].loop_exp().start().options(); + assert(holds_alternative(start3_opt)); + auto start3 = get_if(&start3_opt); + assert(start3->str() == "a"s); + assert(fors[2].loop_exp().step().has_value()); + auto step3_opt = fors[2].loop_exp().step()->options(); + assert(holds_alternative(step3_opt)); + auto step3 = get_if(&step3_opt); + assert(step3->str() == "b"s); + auto end3_opt = fors[2].loop_exp().end().options(); + assert(holds_alternative(end3_opt)); + auto end3 = get_if(&end3_opt); + assert(end3->is_number()); + auto end3_num = get_if(&end3->raw()); + assert(end3_num->value == 42); +} +TEST_CASE("for_in_statements", "[tree-sitter][!hide]") { + ts::Parser parser; + std::string source = "for k, v in next, t, nil do\n" + " print(k, v)\n" + "end\n" + "for a,b,c,d,e in foo(var) do\n" + " return 1\n" + "end"; - INFO(all_named_children(root)); - FAIL(); + ts::Tree tree = parser.parse_string(source); + ts::Node root = tree.root_node(); + auto prog = Program(root); + Body body = prog.body(); + auto stats = body.statements(); + assert(stats.size() == 2); + assert(!body.ret().has_value()); + std::vector fors; + std::transform(stats.begin(), stats.end(), std::back_inserter(fors), [](Statement stat) { + auto opt = stat.options(); + assert(std::holds_alternative(opt)); + return *std::get_if(&opt); + }); + assert(fors.size() == 2); + assert(fors[0].loop_exp().loop_vars().size() == 2); + assert(fors[0].loop_exp().loop_exps().size() == 3); + assert(fors[1].loop_exp().loop_vars().size() == 5); + assert(fors[1].loop_exp().loop_exps().size() == 1); } -TEST_CASE("variabledectest", "[tree-sitter][!hide]") { +TEST_CASE("function_statements", "[tree-sitter][!hide]") { ts::Parser parser; - std::string source = "i\nlocal b = 5\n i = b"; + std::string source = "function foo (a,b,c)\n" + " 1+1\n" + " return 3+3\n" + "end\n" + "function table.prop1.prop2.prop3:method (a,b,c)\n" + " return true\n" + "end\n" + "function foo(self,...)\n" + "end\n" + "function foo(...)\n" + "end\n" + "function foo(self)\n" + "end\n" + "function foo (self,a,b,c)\n" + "end\n" + "function foo (a,b,c,...)\n" + "end\n" + "function foo (...,a,b,c)\n" + "end\n" + "function foo(self,a,b,c,...)\n" + "end\n" + "function foo()\n" + "end"; ts::Tree tree = parser.parse_string(source); ts::Node root = tree.root_node(); - - INFO(root); - FAIL(); + auto prog = Program(root); + Body body = prog.body(); + auto stats = body.statements(); + assert(stats.size() == 10); + assert(!body.ret().has_value()); + std::vector func; + std::transform(stats.begin(), stats.end(), std::back_inserter(func), [](Statement stat) { + auto opt = stat.options(); + assert(std::holds_alternative(opt)); + return *std::get_if(&opt); + }); + assert(func.size() == 10); + assert(func[1].name().method().has_value()); + assert(func[1].name().identifier().size() == 4); + assert(func[0].name().identifier().size() == 1); + std::vector vec{"a", "b", "c"}; + std::vector params; + vector identifiers; + for (uint i = 0; i < 9; i++) { + if (i < 2 || i > 4) { + assert(func[i].parameters().params().size() == 3); + params.clear(); + identifiers = func[i].parameters().params(); + std::transform( + identifiers.begin(), identifiers.end(), std::back_inserter(params), + [](Identifier id) { return id.str(); }); + assert(params == vec); + } else { + assert(func[i].parameters().params().empty()); + } + switch (i) { + case 0: + case 1: + assert(!func[i].parameters().leading_self()); + assert(func[i].parameters().spread() == NO_SPREAD); + break; + case 2: + assert(func[i].parameters().leading_self()); + assert(func[i].parameters().spread() == END); + break; + case 3: + assert(!func[i].parameters().leading_self()); + assert(func[i].parameters().spread() == BEGIN); + break; + case 4: + case 5: + assert(func[i].parameters().leading_self()); + assert(func[i].parameters().spread() == NO_SPREAD); + break; + case 6: + assert(!func[i].parameters().leading_self()); + assert(func[i].parameters().spread() == END); + break; + case 7: + assert(!func[i].parameters().leading_self()); + assert(func[i].parameters().spread() == BEGIN); + break; + case 8: + assert(func[i].parameters().leading_self()); + assert(func[i].parameters().spread() == END); + break; + } + } + assert(!func[9].parameters().leading_self()); + assert(func[9].parameters().spread() == NO_SPREAD); + assert(func[9].parameters().params().empty()); } - -TEST_CASE("tablesandstuff", "[tree-sitter][!hide]") { +TEST_CASE("while_and_repeat_statements", "[tree-sitter][!hide]") { ts::Parser parser; - std::string source = "local pet = {\n" - "age = 0,\n" - "hungry = function (self) print(self.type .. \" is hungry!\") end\n" - "}\n" - "pet.type = \"\"\n" - "\n" - "\n" - "local dog = pet\n" - "dog.type = 3\n" - "\n" - "print(dog.type)\n" - "dog:hungry()"; + std::string source = "while i<#table do\n" + " i=i+1\n" + "end\n" + "while i<#table do\n" + "end\n" + "" + "repeat\n" + "until i>42\n" + "repeat\n" + " i=i*9;" + " return 1,2,3\n" + "until b\n"; ts::Tree tree = parser.parse_string(source); ts::Node root = tree.root_node(); - - INFO(all_children(root)); - FAIL(); + auto prog = Program(root); + Body body = prog.body(); + auto stats = body.statements(); + assert(stats.size() == 4); + auto opt1 = stats[0].options(); + assert(std::holds_alternative(opt1)); + auto while_stat = std::get_if(&opt1); + assert(holds_alternative(while_stat->exit_cond().options())); + assert(while_stat->body().statements().size() == 1); + assert(!while_stat->body().ret().has_value()); + auto opt2 = stats[1].options(); + assert(std::holds_alternative(opt2)); + while_stat = std::get_if(&opt2); + assert(holds_alternative(while_stat->exit_cond().options())); + assert(while_stat->body().statements().empty()); + assert(!while_stat->body().ret().has_value()); + auto opt3 = stats[2].options(); + assert(std::holds_alternative(opt3)); + auto repeat_stat = std::get_if(&opt3); + assert(holds_alternative(repeat_stat->until_cond().options())); + assert(repeat_stat->body().statements().empty()); + assert(!repeat_stat->body().ret().has_value()); + auto opt4 = stats[3].options(); + assert(std::holds_alternative(opt4)); + repeat_stat = std::get_if(&opt4); + assert(holds_alternative(repeat_stat->until_cond().options())); + assert(repeat_stat->body().statements().size() == 1); + assert(repeat_stat->body().ret().has_value()); } -TEST_CASE("function", "[tree-sitter][!hide]") { +TEST_CASE("return_statements", "[tree-sitter][!hide]") { ts::Parser parser; - std::string source = "function n()\n" - " print(2)\n" + std::string source = "do\n" + "return a,b,c,d;\n" + "end\n" + "do\n" + "return\n" "end\n" + "do\n" + "return a\n" + "end"; + ts::Tree tree = parser.parse_string(source); + ts::Node root = tree.root_node(); + auto prog = Program(root); + Body body = prog.body(); + auto stats = body.statements(); + assert(stats.size() == 3); + std::vector returns; + std::transform(stats.begin(), stats.end(), std::back_inserter(returns), [](Statement stat) { + auto opt = stat.options(); + assert(std::holds_alternative(opt)); + auto do_stat = *std::get_if(&opt); + assert(do_stat.body().ret().has_value()); + return do_stat.body().ret().value(); + }); + assert(returns[0].explist().size() == 4); + for (uint i = 0; i < 4; i++) { + assert(std::holds_alternative(returns[0].explist()[i].options())); + } + assert(returns[1].explist().empty()); + assert(returns[2].explist().size() == 1); + assert(std::holds_alternative(returns[2].explist()[0].options())); +} +TEST_CASE("var_dec_statements", "[tree-sitter][!hide]") { + ts::Parser parser; + std::string source = "a = 1\n" + "a,b,c,d = 1+2,5+7,a\n" + "local e\n" + "local f,g,h\n" + "local i,j = 42,96\n" "\n" - "n()"; + "table1.table2.field1 = function() print(2) end\n" + ""; ts::Tree tree = parser.parse_string(source); ts::Node root = tree.root_node(); - - INFO(all_children(root)); - FAIL(); + auto prog = Program(root); + Body body = prog.body(); + auto stats = body.statements(); + assert(stats.size() == 6); + // 1st statement + auto opt1 = stats[0].options(); + assert(std::holds_alternative(opt1)); + auto var_dec1 = std::get_if(&opt1); + assert(var_dec1->declarations().size() == 1); + assert(var_dec1->declarators().size() == 1); + assert(std::holds_alternative(var_dec1->declarators()[0].var())); + assert(std::holds_alternative(var_dec1->declarations()[0].options())); + // 2nd statement + auto opt2 = stats[1].options(); + assert(std::holds_alternative(opt2)); + auto var_dec2 = std::get_if(&opt2); + assert(var_dec2->declarations().size() == 3); + assert(var_dec2->declarators().size() == 4); + for (uint i = 0; i < 4; i++) { + assert(std::holds_alternative(var_dec2->declarators()[i].var())); + } + assert(std::holds_alternative(var_dec2->declarations()[0].options())); + assert(std::holds_alternative(var_dec2->declarations()[1].options())); + assert(std::holds_alternative(var_dec2->declarations()[2].options())); + // 3rd statement + auto opt3 = stats[2].options(); + assert(std::holds_alternative(opt3)); + auto var_dec3 = std::get_if(&opt3); + assert(var_dec3->declarations().empty()); + assert(var_dec3->declarators().size() == 1); + assert(var_dec3->declarators()[0].str() == "e"s); + // 4th statement + auto opt4 = stats[3].options(); + assert(std::holds_alternative(opt4)); + auto var_dec4 = std::get_if(&opt4); + assert(var_dec4->declarations().empty()); + assert(var_dec4->declarators().size() == 3); + assert(var_dec4->declarators()[0].str() == "f"s); + assert(var_dec4->declarators()[1].str() == "g"s); + assert(var_dec4->declarators()[2].str() == "h"s); + // 5th statement + auto opt5 = stats[4].options(); + assert(std::holds_alternative(opt5)); + auto var_dec5 = std::get_if(&opt5); + assert(var_dec5->declarations().size() == 2); + assert(var_dec5->declarators().size() == 2); + assert(std::holds_alternative(var_dec5->declarations()[0].options())); + assert(std::holds_alternative(var_dec5->declarations()[1].options())); + assert(var_dec5->declarators()[0].str() == "i"s); + assert(var_dec5->declarators()[1].str() == "j"s); + // 6th statement + auto opt6 = stats[5].options(); + assert(std::holds_alternative(opt6)); + auto var_dec6 = std::get_if(&opt6); + assert(var_dec6->declarators().size() == 1); + auto declarator = var_dec6->declarators()[0]; + auto dec_opt1 = declarator.var(); + assert(std::holds_alternative(dec_opt1)); + auto fe1 = std::get_if(&dec_opt1); + assert(fe1->property_id().str() == "field1"); + auto prefix1 = fe1->table_id().options(); + assert(std::holds_alternative(prefix1)); + auto dec2 = get_if(&prefix1); + auto dec_opt2 = dec2->var(); + assert(holds_alternative(dec_opt2)); + auto fe2 = std::get_if(&dec_opt2); + assert(fe2->property_id().str() == "table2"); + auto prefix2 = fe2->table_id().options(); + assert(std::holds_alternative(prefix2)); + auto dec3 = std::get_if(&prefix2); + auto dec_opt3 = dec3->var(); + assert(holds_alternative(dec_opt3)); + auto table_id = std::get_if(&dec_opt3); + assert(table_id->str() == "table1"s); } -TEST_CASE("Print2", "[tree-sitter][!hide]") { - - - +TEST_CASE("table_statements", "[tree-sitter][!hide]") { ts::Parser parser; - - std::string source = "if 2<6 then\ni=1+2\n1+2\n1+2\n1+2\nelseif false then\n1+2\nelse\n\"w\" .. 2\nend"; + std::string source = "{\n" + "field1 = \"name\";\n" + "[2+2] = {1,2,3};\n" + "function()\n" + " return field1\n" + "end" + "}\n"; ts::Tree tree = parser.parse_string(source); ts::Node root = tree.root_node(); - - INFO(all_named_children(root.child(0).value())); - FAIL(); + auto prog = Program(root); + Body body = prog.body(); + auto stats = body.statements(); + assert(stats.size() == 1); + auto opt1 = stats[0].options(); + assert(std::holds_alternative(opt1)); + auto* exp1 = std::get_if(&opt1); + auto exp_opt1 = exp1->options(); + assert(std::holds_alternative(exp_opt1)); + auto table1 = std::get_if
(&exp_opt1); + auto fields = table1->fields(); + assert(fields.size() == 3); + auto field1_opt = fields[0].content(); + assert(std::holds_alternative(field1_opt)); + auto field1 = std::get_if(&field1_opt); + assert(field1->first.str() == "field1"s); + assert(std::holds_alternative(field1->second.options())); + auto content1_opt = field1->second.options(); + auto content1 = std::get_if(&content1_opt); + assert(content1->is_string()); + auto raw = content1->raw(); + auto content1_str = get_if(&raw); + assert(content1_str->value == "name"s); + auto field2_opt = fields[1].content(); + assert(std::holds_alternative(field2_opt)); + auto field2 = std::get_if(&field2_opt); + assert(std::holds_alternative(field2->first.options())); + assert(std::holds_alternative
(field2->second.options())); + auto field3_opt = fields[2].content(); + assert(std::holds_alternative(field3_opt)); + auto field3 = std::get_if(&field3_opt); + auto content3_opt = field3->options(); + assert(std::holds_alternative(content3_opt)); } - -TEST_CASE("variables", "[tree-sitter][!hide]") { +TEST_CASE("function_calls", "[tree-sitter][!hide]") { ts::Parser parser; - std::string source = "a = {t1 = 2;\n" - " t2 = 4}\n" - "a.t2 = 5+3\n" - "c = a [\"t2\"]\n" - "function (a)\n" - "2+2\nend\ndoa \"a\""; + std::string source = "foo(a,b)\n" + "table.foo()\n" + "table:foo()\n" + "foo \"abc\"\n" + "table:foo {1,2,3,4}"; ts::Tree tree = parser.parse_string(source); ts::Node root = tree.root_node(); + auto prog = Program(root); + Body body = prog.body(); + auto stats = body.statements(); + assert(stats.size() == 5); + std::vector func_calls; + std::transform(stats.begin(), stats.end(), std::back_inserter(func_calls), [](Statement stat) { + auto opt = stat.options(); + assert(std::holds_alternative(opt)); + return *std::get_if(&opt); + }); + assert(!func_calls[0].method().has_value()); + assert(std::holds_alternative(func_calls[0].id().options())); + auto opt1 = func_calls[0].id().options(); + auto name1 = std::get_if(&opt1); + assert(holds_alternative(name1->var())); + assert(func_calls[0].args().size() == 2); - INFO(all_children(root)); - FAIL(); -} + assert(!func_calls[1].method().has_value()); + assert(std::holds_alternative(func_calls[1].id().options())); + auto opt2 = func_calls[1].id().options(); + auto name2 = std::get_if(&opt2); + assert(holds_alternative(name2->var())); + assert(func_calls[1].args().empty()); -*/ -TEST_CASE("Print42", "[tree-sitter][!hide]") { - ts::Parser parser; + assert(func_calls[2].method().has_value()); + assert(std::holds_alternative(func_calls[2].id().options())); + auto opt3 = func_calls[2].id().options(); + auto name3 = std::get_if(&opt3); + assert(holds_alternative(name3->var())); + assert(func_calls[2].args().empty()); - std::string source = "for i=1,5 do\n" - "print(i)\n" - "end"; - ts::Tree tree = parser.parse_string(source); - ts::Node root = tree.root_node().child(0).value(); + assert(func_calls[3].args().size() == 1); + assert(std::holds_alternative(func_calls[3].args()[0].options())); + auto opt4 = func_calls[3].args()[0].options(); + auto str = std::get_if(&opt4); + assert(str->is_string()); - INFO(root.child_count()); - FAIL(); + assert(func_calls[4].args().size() == 1); + assert(std::holds_alternative
(func_calls[4].args()[0].options())); + auto opt5 = func_calls[4].args()[0].options(); + auto table = std::get_if
(&opt5); + assert(table->fields().size() == 4); + for (uint i = 0; i < 4; i++) { + assert(std::holds_alternative(table->fields()[i].content())); + } } +} // namespace minilua::details \ No newline at end of file From e9146833f35efd4e974d5ce74a54168b0e0ac460 Mon Sep 17 00:00:00 2001 From: CFU9 Date: Mon, 18 Jan 2021 00:44:10 +0100 Subject: [PATCH 07/17] minor change --- tests/tree_sitter_ast_tests.cpp | 495 ++++++++++++++++---------------- 1 file changed, 248 insertions(+), 247 deletions(-) diff --git a/tests/tree_sitter_ast_tests.cpp b/tests/tree_sitter_ast_tests.cpp index 2bc6a33d..22990f3d 100644 --- a/tests/tree_sitter_ast_tests.cpp +++ b/tests/tree_sitter_ast_tests.cpp @@ -43,13 +43,13 @@ TEST_CASE("statements", "[tree-sitter][!hide]") { ts::Node root = tree.root_node(); auto prog = Program(root); Body body = prog.body(); - assert(!body.ret().has_value()); + CHECK(!body.ret().has_value()); vector statement = body.statements(); - assert(statement.size() == 15); + CHECK(statement.size() == 15); long unsigned int statement_count = statement.size(); // this loop tests if each statement got parsed to the right Class for (long unsigned int i = 0; i < statement_count; i++) { - assert(statement.at(i).options().index() == i); + CHECK(statement.at(i).options().index() == i); } } TEST_CASE("expressions", "[tree-sitter][!hide]") { @@ -94,7 +94,7 @@ TEST_CASE("expressions", "[tree-sitter][!hide]") { ts::Node root = tree.root_node(); auto prog = Program(root); Body body = prog.body(); - assert(!body.ret().has_value()); + CHECK(!body.ret().has_value()); vector statement = body.statements(); vector exps; exps.reserve(exp_count); @@ -105,13 +105,13 @@ TEST_CASE("expressions", "[tree-sitter][!hide]") { return *std::get_if(&opt); }); auto spread = exps[0].options(); - assert(spread.index() == 0); + CHECK(spread.index() == 0); auto next = exps[1].options(); - assert(next.index() == 2); + CHECK(next.index() == 2); auto func_def = exps[2].options(); - assert(func_def.index() == 3); + CHECK(func_def.index() == 3); auto table = exps[3].options(); - assert(table.index() == 4); + CHECK(table.index() == 4); vector bin_ops; bin_ops.reserve(25); std::transform( @@ -120,31 +120,32 @@ TEST_CASE("expressions", "[tree-sitter][!hide]") { return *get_if(&opt); }); for (uint i = 0; i < bin_ops.size(); i++) { - assert( + CHECK( bin_ops[i].op() == (BinOpEnum)i); // Bin Operations are in the same sequence as in the BinOpEnum } auto nil = exps[25].options(); - assert(holds_alternative(nil)); + CHECK(holds_alternative(nil)); auto* temp = get_if(&nil); - assert(temp->is_nil()); + CHECK(temp->is_nil()); auto _true = exps[26].options(); - assert(holds_alternative(_true)); + CHECK(holds_alternative(_true)); temp = get_if(&_true); - assert(temp->is_bool() && temp == Value(true)); + CHECK(temp->is_bool()); + CHECK(temp == Value(true)); auto* b = get_if(&(temp->raw())); - assert(b->operator bool()); + CHECK(b->operator bool()); auto _false = exps[27].options(); - assert(holds_alternative(_false)); + CHECK(holds_alternative(_false)); temp = get_if(&_false); - assert(temp->is_bool()); + CHECK(temp->is_bool()); b = get_if(&(temp->raw())); - assert(!(b->operator bool())); + CHECK(!(b->operator bool())); auto id = exps[28].options(); - assert(holds_alternative(id)); + CHECK(holds_alternative(id)); Identifier temp2 = *get_if(&id); - assert(temp2.str() == "id"s); + CHECK(temp2.str() == "id"s); vector un_op; un_op.reserve(4); std::transform( @@ -154,11 +155,11 @@ TEST_CASE("expressions", "[tree-sitter][!hide]") { auto* vd = std::get_if(&opt); auto exps = vd->declarations(); auto exp = exps[0].options(); - assert(holds_alternative(exp)); + CHECK(holds_alternative(exp)); return *get_if(&exp); }); for (uint j = 0; j < un_op.size(); j++) { - assert(un_op[j].op() == (UnOpEnum)j); + CHECK(un_op[j].op() == (UnOpEnum)j); } } @@ -185,25 +186,25 @@ TEST_CASE("do_statements", "[tree-sitter][!hide]") { auto prog = Program(root); Body body = prog.body(); auto stats = body.statements(); - assert(stats.size() == 5); - assert(!body.ret().has_value()); + CHECK(stats.size() == 5); + CHECK(!body.ret().has_value()); std::vector dos; std::transform(stats.begin(), stats.end(), std::back_inserter(dos), [](Statement stat) { auto opt = stat.options(); - assert(std::holds_alternative(opt)); + CHECK(std::holds_alternative(opt)); return *std::get_if(&opt); }); - assert(dos.size() == 5); - assert(dos[0].body().statements().empty()); - assert(!dos[0].body().ret().has_value()); - assert(dos[1].body().statements().size() == 1); - assert(!dos[1].body().ret().has_value()); - assert(dos[2].body().statements().size() == 2); - assert(!dos[2].body().ret().has_value()); - assert(dos[3].body().statements().empty()); - assert(dos[3].body().ret().has_value()); - assert(dos[4].body().statements().size() == 1); - assert(dos[4].body().ret().has_value()); + CHECK(dos.size() == 5); + CHECK(dos[0].body().statements().empty()); + CHECK(!dos[0].body().ret().has_value()); + CHECK(dos[1].body().statements().size() == 1); + CHECK(!dos[1].body().ret().has_value()); + CHECK(dos[2].body().statements().size() == 2); + CHECK(!dos[2].body().ret().has_value()); + CHECK(dos[3].body().statements().empty()); + CHECK(dos[3].body().ret().has_value()); + CHECK(dos[4].body().statements().size() == 1); + CHECK(dos[4].body().ret().has_value()); } TEST_CASE("if_statements", "[tree-sitter][!hide]") { ts::Parser parser; @@ -243,61 +244,61 @@ TEST_CASE("if_statements", "[tree-sitter][!hide]") { auto prog = Program(root); Body body = prog.body(); auto stats = body.statements(); - assert(stats.size() == 6); + CHECK(stats.size() == 6); std::vector ifs; std::transform(stats.begin(), stats.end(), std::back_inserter(ifs), [](Statement stat) { auto opt = stat.options(); - assert(std::holds_alternative(opt)); + CHECK(std::holds_alternative(opt)); return *std::get_if(&opt); }); - assert(ifs.size() == 6); - assert(holds_alternative(ifs[0].cond().options())); - assert(ifs[0].body().statements().empty()); - assert(!ifs[0].body().ret().has_value()); - assert(ifs[0].elseifs().size() == 2); - assert(holds_alternative(ifs[0].elseifs()[0].cond().options())); - assert(ifs[0].elseifs()[0].body().statements().size() == 1); - assert(!ifs[0].elseifs()[0].body().ret().has_value()); - assert(holds_alternative(ifs[0].elseifs()[1].cond().options())); - assert(ifs[0].elseifs()[1].body().statements().size() == 2); - assert(!ifs[0].elseifs()[1].body().ret().has_value()); - assert(ifs[0].else_().has_value()); - assert(ifs[0].else_().value().body().statements().empty()); - assert(ifs[0].else_().value().body().ret().has_value()); - assert(std::holds_alternative( + CHECK(ifs.size() == 6); + CHECK(holds_alternative(ifs[0].cond().options())); + CHECK(ifs[0].body().statements().empty()); + CHECK(!ifs[0].body().ret().has_value()); + CHECK(ifs[0].elseifs().size() == 2); + CHECK(holds_alternative(ifs[0].elseifs()[0].cond().options())); + CHECK(ifs[0].elseifs()[0].body().statements().size() == 1); + CHECK(!ifs[0].elseifs()[0].body().ret().has_value()); + CHECK(holds_alternative(ifs[0].elseifs()[1].cond().options())); + CHECK(ifs[0].elseifs()[1].body().statements().size() == 2); + CHECK(!ifs[0].elseifs()[1].body().ret().has_value()); + CHECK(ifs[0].else_().has_value()); + CHECK(ifs[0].else_().value().body().statements().empty()); + CHECK(ifs[0].else_().value().body().ret().has_value()); + CHECK(std::holds_alternative( ifs[0].else_().value().body().ret().value().explist()[0].options())); - assert(ifs[1].body().statements().empty()); - assert(ifs[1].body().ret().has_value()); - assert(ifs[1].elseifs().empty()); - assert(!ifs[1].else_().has_value()); - assert(holds_alternative(ifs[1].cond().options())); - assert(holds_alternative(ifs[2].cond().options())); - assert(ifs[2].body().statements().size() == 1); - assert(!ifs[2].body().ret().has_value()); - assert(ifs[2].elseifs().empty()); - assert(ifs[2].else_().has_value()); - assert(ifs[2].else_().value().body().statements().size() == 1); - assert(!ifs[2].else_().value().body().ret().has_value()); - assert(holds_alternative(ifs[3].cond().options())); - assert(ifs[3].body().statements().empty()); - assert(!ifs[3].body().ret().has_value()); - assert(ifs[3].elseifs().empty()); - assert(ifs[3].else_().has_value()); - assert(ifs[3].else_().value().body().statements().size() == 1); - assert(!ifs[3].else_().value().body().ret().has_value()); - assert(holds_alternative(ifs[4].cond().options())); - assert(ifs[4].body().statements().size() == 1); - assert(!ifs[4].body().ret().has_value()); - assert(ifs[4].elseifs().size() == 2); - assert(!ifs[4].else_().has_value()); - assert(ifs[4].elseifs()[0].body().statements().size() == 1); - assert(!ifs[4].elseifs()[0].body().ret().has_value()); - assert(ifs[4].elseifs()[1].body().statements().size() == 2); - assert(!ifs[4].elseifs()[1].body().ret().has_value()); - assert(ifs[5].body().statements().empty()); - assert(!ifs[5].body().ret().has_value()); - assert(ifs[5].elseifs().empty()); - assert(!ifs[5].else_().has_value()); + CHECK(ifs[1].body().statements().empty()); + CHECK(ifs[1].body().ret().has_value()); + CHECK(ifs[1].elseifs().empty()); + CHECK(!ifs[1].else_().has_value()); + CHECK(holds_alternative(ifs[1].cond().options())); + CHECK(holds_alternative(ifs[2].cond().options())); + CHECK(ifs[2].body().statements().size() == 1); + CHECK(!ifs[2].body().ret().has_value()); + CHECK(ifs[2].elseifs().empty()); + CHECK(ifs[2].else_().has_value()); + CHECK(ifs[2].else_().value().body().statements().size() == 1); + CHECK(!ifs[2].else_().value().body().ret().has_value()); + CHECK(holds_alternative(ifs[3].cond().options())); + CHECK(ifs[3].body().statements().empty()); + CHECK(!ifs[3].body().ret().has_value()); + CHECK(ifs[3].elseifs().empty()); + CHECK(ifs[3].else_().has_value()); + CHECK(ifs[3].else_().value().body().statements().size() == 1); + CHECK(!ifs[3].else_().value().body().ret().has_value()); + CHECK(holds_alternative(ifs[4].cond().options())); + CHECK(ifs[4].body().statements().size() == 1); + CHECK(!ifs[4].body().ret().has_value()); + CHECK(ifs[4].elseifs().size() == 2); + CHECK(!ifs[4].else_().has_value()); + CHECK(ifs[4].elseifs()[0].body().statements().size() == 1); + CHECK(!ifs[4].elseifs()[0].body().ret().has_value()); + CHECK(ifs[4].elseifs()[1].body().statements().size() == 2); + CHECK(!ifs[4].elseifs()[1].body().ret().has_value()); + CHECK(ifs[5].body().statements().empty()); + CHECK(!ifs[5].body().ret().has_value()); + CHECK(ifs[5].elseifs().empty()); + CHECK(!ifs[5].else_().has_value()); } TEST_CASE("for_statements", "[tree-sitter][!hide]") { ts::Parser parser; @@ -318,58 +319,58 @@ TEST_CASE("for_statements", "[tree-sitter][!hide]") { auto prog = Program(root); Body body = prog.body(); auto stats = body.statements(); - assert(stats.size() == 3); - assert(!body.ret().has_value()); + CHECK(stats.size() == 3); + CHECK(!body.ret().has_value()); std::vector fors; std::transform(stats.begin(), stats.end(), std::back_inserter(fors), [](Statement stat) { auto opt = stat.options(); - assert(std::holds_alternative(opt)); + CHECK(std::holds_alternative(opt)); return *std::get_if(&opt); }); - assert(fors.size() == 3); + CHECK(fors.size() == 3); // 1st loop - assert(fors[0].body().statements().size() == 1); - assert(!fors[0].body().ret().has_value()); - assert(fors[0].loop_exp().variable().str() == "i"s); + CHECK(fors[0].body().statements().size() == 1); + CHECK(!fors[0].body().ret().has_value()); + CHECK(fors[0].loop_exp().variable().str() == "i"s); auto start1_opt = fors[0].loop_exp().start().options(); - assert(holds_alternative(start1_opt)); + CHECK(holds_alternative(start1_opt)); auto* start1 = get_if(&start1_opt); - assert(start1->is_number()); - assert(holds_alternative(start1->raw())); + CHECK(start1->is_number()); + CHECK(holds_alternative(start1->raw())); if (auto* num1 = get_if(&start1->raw())) { - assert(num1->value == 1); + CHECK(num1->value == 1); } auto end1_opt = fors[0].loop_exp().end().options(); - assert(holds_alternative(end1_opt)); + CHECK(holds_alternative(end1_opt)); auto* end1 = get_if(&end1_opt); - assert(end1->is_number()); - assert(holds_alternative(end1->raw())); + CHECK(end1->is_number()); + CHECK(holds_alternative(end1->raw())); if (auto* num2 = get_if(&end1->raw())) { - assert(num2->value == 2); + CHECK(num2->value == 2); } - assert(!fors[0].loop_exp().step().has_value()); + CHECK(!fors[0].loop_exp().step().has_value()); // 2nd loop just to check if the empty body works fine here - assert(fors[1].body().statements().empty()); + CHECK(fors[1].body().statements().empty()); // 3rd loop - assert(fors[2].body().statements().size() == 3); - assert(!fors[2].body().ret().has_value()); + CHECK(fors[2].body().statements().size() == 3); + CHECK(!fors[2].body().ret().has_value()); // checking the loopexpression - assert(fors[2].loop_exp().variable().str() == "c"s); + CHECK(fors[2].loop_exp().variable().str() == "c"s); auto start3_opt = fors[2].loop_exp().start().options(); - assert(holds_alternative(start3_opt)); + CHECK(holds_alternative(start3_opt)); auto start3 = get_if(&start3_opt); - assert(start3->str() == "a"s); - assert(fors[2].loop_exp().step().has_value()); + CHECK(start3->str() == "a"s); + CHECK(fors[2].loop_exp().step().has_value()); auto step3_opt = fors[2].loop_exp().step()->options(); - assert(holds_alternative(step3_opt)); + CHECK(holds_alternative(step3_opt)); auto step3 = get_if(&step3_opt); - assert(step3->str() == "b"s); + CHECK(step3->str() == "b"s); auto end3_opt = fors[2].loop_exp().end().options(); - assert(holds_alternative(end3_opt)); + CHECK(holds_alternative(end3_opt)); auto end3 = get_if(&end3_opt); - assert(end3->is_number()); + CHECK(end3->is_number()); auto end3_num = get_if(&end3->raw()); - assert(end3_num->value == 42); + CHECK(end3_num->value == 42); } TEST_CASE("for_in_statements", "[tree-sitter][!hide]") { ts::Parser parser; @@ -385,19 +386,19 @@ TEST_CASE("for_in_statements", "[tree-sitter][!hide]") { auto prog = Program(root); Body body = prog.body(); auto stats = body.statements(); - assert(stats.size() == 2); - assert(!body.ret().has_value()); + CHECK(stats.size() == 2); + CHECK(!body.ret().has_value()); std::vector fors; std::transform(stats.begin(), stats.end(), std::back_inserter(fors), [](Statement stat) { auto opt = stat.options(); - assert(std::holds_alternative(opt)); + CHECK(std::holds_alternative(opt)); return *std::get_if(&opt); }); - assert(fors.size() == 2); - assert(fors[0].loop_exp().loop_vars().size() == 2); - assert(fors[0].loop_exp().loop_exps().size() == 3); - assert(fors[1].loop_exp().loop_vars().size() == 5); - assert(fors[1].loop_exp().loop_exps().size() == 1); + CHECK(fors.size() == 2); + CHECK(fors[0].loop_exp().loop_vars().size() == 2); + CHECK(fors[0].loop_exp().loop_exps().size() == 3); + CHECK(fors[1].loop_exp().loop_vars().size() == 5); + CHECK(fors[1].loop_exp().loop_exps().size() == 1); } TEST_CASE("function_statements", "[tree-sitter][!hide]") { ts::Parser parser; @@ -429,69 +430,69 @@ TEST_CASE("function_statements", "[tree-sitter][!hide]") { auto prog = Program(root); Body body = prog.body(); auto stats = body.statements(); - assert(stats.size() == 10); - assert(!body.ret().has_value()); + CHECK(stats.size() == 10); + CHECK(!body.ret().has_value()); std::vector func; std::transform(stats.begin(), stats.end(), std::back_inserter(func), [](Statement stat) { auto opt = stat.options(); - assert(std::holds_alternative(opt)); + CHECK(std::holds_alternative(opt)); return *std::get_if(&opt); }); - assert(func.size() == 10); - assert(func[1].name().method().has_value()); - assert(func[1].name().identifier().size() == 4); - assert(func[0].name().identifier().size() == 1); + CHECK(func.size() == 10); + CHECK(func[1].name().method().has_value()); + CHECK(func[1].name().identifier().size() == 4); + CHECK(func[0].name().identifier().size() == 1); std::vector vec{"a", "b", "c"}; std::vector params; vector identifiers; for (uint i = 0; i < 9; i++) { if (i < 2 || i > 4) { - assert(func[i].parameters().params().size() == 3); + CHECK(func[i].parameters().params().size() == 3); params.clear(); identifiers = func[i].parameters().params(); std::transform( identifiers.begin(), identifiers.end(), std::back_inserter(params), [](Identifier id) { return id.str(); }); - assert(params == vec); + CHECK(params == vec); } else { - assert(func[i].parameters().params().empty()); + CHECK(func[i].parameters().params().empty()); } switch (i) { case 0: case 1: - assert(!func[i].parameters().leading_self()); - assert(func[i].parameters().spread() == NO_SPREAD); + CHECK(!func[i].parameters().leading_self()); + CHECK(func[i].parameters().spread() == NO_SPREAD); break; case 2: - assert(func[i].parameters().leading_self()); - assert(func[i].parameters().spread() == END); + CHECK(func[i].parameters().leading_self()); + CHECK(func[i].parameters().spread() == END); break; case 3: - assert(!func[i].parameters().leading_self()); - assert(func[i].parameters().spread() == BEGIN); + CHECK(!func[i].parameters().leading_self()); + CHECK(func[i].parameters().spread() == BEGIN); break; case 4: case 5: - assert(func[i].parameters().leading_self()); - assert(func[i].parameters().spread() == NO_SPREAD); + CHECK(func[i].parameters().leading_self()); + CHECK(func[i].parameters().spread() == NO_SPREAD); break; case 6: - assert(!func[i].parameters().leading_self()); - assert(func[i].parameters().spread() == END); + CHECK(!func[i].parameters().leading_self()); + CHECK(func[i].parameters().spread() == END); break; case 7: - assert(!func[i].parameters().leading_self()); - assert(func[i].parameters().spread() == BEGIN); + CHECK(!func[i].parameters().leading_self()); + CHECK(func[i].parameters().spread() == BEGIN); break; case 8: - assert(func[i].parameters().leading_self()); - assert(func[i].parameters().spread() == END); + CHECK(func[i].parameters().leading_self()); + CHECK(func[i].parameters().spread() == END); break; } } - assert(!func[9].parameters().leading_self()); - assert(func[9].parameters().spread() == NO_SPREAD); - assert(func[9].parameters().params().empty()); + CHECK(!func[9].parameters().leading_self()); + CHECK(func[9].parameters().spread() == NO_SPREAD); + CHECK(func[9].parameters().params().empty()); } TEST_CASE("while_and_repeat_statements", "[tree-sitter][!hide]") { ts::Parser parser; @@ -512,31 +513,31 @@ TEST_CASE("while_and_repeat_statements", "[tree-sitter][!hide]") { auto prog = Program(root); Body body = prog.body(); auto stats = body.statements(); - assert(stats.size() == 4); + CHECK(stats.size() == 4); auto opt1 = stats[0].options(); - assert(std::holds_alternative(opt1)); + CHECK(std::holds_alternative(opt1)); auto while_stat = std::get_if(&opt1); - assert(holds_alternative(while_stat->exit_cond().options())); - assert(while_stat->body().statements().size() == 1); - assert(!while_stat->body().ret().has_value()); + CHECK(holds_alternative(while_stat->exit_cond().options())); + CHECK(while_stat->body().statements().size() == 1); + CHECK(!while_stat->body().ret().has_value()); auto opt2 = stats[1].options(); - assert(std::holds_alternative(opt2)); + CHECK(std::holds_alternative(opt2)); while_stat = std::get_if(&opt2); - assert(holds_alternative(while_stat->exit_cond().options())); - assert(while_stat->body().statements().empty()); - assert(!while_stat->body().ret().has_value()); + CHECK(holds_alternative(while_stat->exit_cond().options())); + CHECK(while_stat->body().statements().empty()); + CHECK(!while_stat->body().ret().has_value()); auto opt3 = stats[2].options(); - assert(std::holds_alternative(opt3)); + CHECK(std::holds_alternative(opt3)); auto repeat_stat = std::get_if(&opt3); - assert(holds_alternative(repeat_stat->until_cond().options())); - assert(repeat_stat->body().statements().empty()); - assert(!repeat_stat->body().ret().has_value()); + CHECK(holds_alternative(repeat_stat->until_cond().options())); + CHECK(repeat_stat->body().statements().empty()); + CHECK(!repeat_stat->body().ret().has_value()); auto opt4 = stats[3].options(); - assert(std::holds_alternative(opt4)); + CHECK(std::holds_alternative(opt4)); repeat_stat = std::get_if(&opt4); - assert(holds_alternative(repeat_stat->until_cond().options())); - assert(repeat_stat->body().statements().size() == 1); - assert(repeat_stat->body().ret().has_value()); + CHECK(holds_alternative(repeat_stat->until_cond().options())); + CHECK(repeat_stat->body().statements().size() == 1); + CHECK(repeat_stat->body().ret().has_value()); } TEST_CASE("return_statements", "[tree-sitter][!hide]") { ts::Parser parser; @@ -554,22 +555,22 @@ TEST_CASE("return_statements", "[tree-sitter][!hide]") { auto prog = Program(root); Body body = prog.body(); auto stats = body.statements(); - assert(stats.size() == 3); + CHECK(stats.size() == 3); std::vector returns; std::transform(stats.begin(), stats.end(), std::back_inserter(returns), [](Statement stat) { auto opt = stat.options(); - assert(std::holds_alternative(opt)); + CHECK(std::holds_alternative(opt)); auto do_stat = *std::get_if(&opt); - assert(do_stat.body().ret().has_value()); + CHECK(do_stat.body().ret().has_value()); return do_stat.body().ret().value(); }); - assert(returns[0].explist().size() == 4); + CHECK(returns[0].explist().size() == 4); for (uint i = 0; i < 4; i++) { - assert(std::holds_alternative(returns[0].explist()[i].options())); + CHECK(std::holds_alternative(returns[0].explist()[i].options())); } - assert(returns[1].explist().empty()); - assert(returns[2].explist().size() == 1); - assert(std::holds_alternative(returns[2].explist()[0].options())); + CHECK(returns[1].explist().empty()); + CHECK(returns[2].explist().size() == 1); + CHECK(std::holds_alternative(returns[2].explist()[0].options())); } TEST_CASE("var_dec_statements", "[tree-sitter][!hide]") { ts::Parser parser; @@ -586,77 +587,77 @@ TEST_CASE("var_dec_statements", "[tree-sitter][!hide]") { auto prog = Program(root); Body body = prog.body(); auto stats = body.statements(); - assert(stats.size() == 6); + CHECK(stats.size() == 6); // 1st statement auto opt1 = stats[0].options(); - assert(std::holds_alternative(opt1)); + CHECK(std::holds_alternative(opt1)); auto var_dec1 = std::get_if(&opt1); - assert(var_dec1->declarations().size() == 1); - assert(var_dec1->declarators().size() == 1); - assert(std::holds_alternative(var_dec1->declarators()[0].var())); - assert(std::holds_alternative(var_dec1->declarations()[0].options())); + CHECK(var_dec1->declarations().size() == 1); + CHECK(var_dec1->declarators().size() == 1); + CHECK(std::holds_alternative(var_dec1->declarators()[0].var())); + CHECK(std::holds_alternative(var_dec1->declarations()[0].options())); // 2nd statement auto opt2 = stats[1].options(); - assert(std::holds_alternative(opt2)); + CHECK(std::holds_alternative(opt2)); auto var_dec2 = std::get_if(&opt2); - assert(var_dec2->declarations().size() == 3); - assert(var_dec2->declarators().size() == 4); + CHECK(var_dec2->declarations().size() == 3); + CHECK(var_dec2->declarators().size() == 4); for (uint i = 0; i < 4; i++) { - assert(std::holds_alternative(var_dec2->declarators()[i].var())); + CHECK(std::holds_alternative(var_dec2->declarators()[i].var())); } - assert(std::holds_alternative(var_dec2->declarations()[0].options())); - assert(std::holds_alternative(var_dec2->declarations()[1].options())); - assert(std::holds_alternative(var_dec2->declarations()[2].options())); + CHECK(std::holds_alternative(var_dec2->declarations()[0].options())); + CHECK(std::holds_alternative(var_dec2->declarations()[1].options())); + CHECK(std::holds_alternative(var_dec2->declarations()[2].options())); // 3rd statement auto opt3 = stats[2].options(); - assert(std::holds_alternative(opt3)); + CHECK(std::holds_alternative(opt3)); auto var_dec3 = std::get_if(&opt3); - assert(var_dec3->declarations().empty()); - assert(var_dec3->declarators().size() == 1); - assert(var_dec3->declarators()[0].str() == "e"s); + CHECK(var_dec3->declarations().empty()); + CHECK(var_dec3->declarators().size() == 1); + CHECK(var_dec3->declarators()[0].str() == "e"s); // 4th statement auto opt4 = stats[3].options(); - assert(std::holds_alternative(opt4)); + CHECK(std::holds_alternative(opt4)); auto var_dec4 = std::get_if(&opt4); - assert(var_dec4->declarations().empty()); - assert(var_dec4->declarators().size() == 3); - assert(var_dec4->declarators()[0].str() == "f"s); - assert(var_dec4->declarators()[1].str() == "g"s); - assert(var_dec4->declarators()[2].str() == "h"s); + CHECK(var_dec4->declarations().empty()); + CHECK(var_dec4->declarators().size() == 3); + CHECK(var_dec4->declarators()[0].str() == "f"s); + CHECK(var_dec4->declarators()[1].str() == "g"s); + CHECK(var_dec4->declarators()[2].str() == "h"s); // 5th statement auto opt5 = stats[4].options(); - assert(std::holds_alternative(opt5)); + CHECK(std::holds_alternative(opt5)); auto var_dec5 = std::get_if(&opt5); - assert(var_dec5->declarations().size() == 2); - assert(var_dec5->declarators().size() == 2); - assert(std::holds_alternative(var_dec5->declarations()[0].options())); - assert(std::holds_alternative(var_dec5->declarations()[1].options())); - assert(var_dec5->declarators()[0].str() == "i"s); - assert(var_dec5->declarators()[1].str() == "j"s); + CHECK(var_dec5->declarations().size() == 2); + CHECK(var_dec5->declarators().size() == 2); + CHECK(std::holds_alternative(var_dec5->declarations()[0].options())); + CHECK(std::holds_alternative(var_dec5->declarations()[1].options())); + CHECK(var_dec5->declarators()[0].str() == "i"s); + CHECK(var_dec5->declarators()[1].str() == "j"s); // 6th statement auto opt6 = stats[5].options(); - assert(std::holds_alternative(opt6)); + CHECK(std::holds_alternative(opt6)); auto var_dec6 = std::get_if(&opt6); - assert(var_dec6->declarators().size() == 1); + CHECK(var_dec6->declarators().size() == 1); auto declarator = var_dec6->declarators()[0]; auto dec_opt1 = declarator.var(); - assert(std::holds_alternative(dec_opt1)); + CHECK(std::holds_alternative(dec_opt1)); auto fe1 = std::get_if(&dec_opt1); - assert(fe1->property_id().str() == "field1"); + CHECK(fe1->property_id().str() == "field1"); auto prefix1 = fe1->table_id().options(); - assert(std::holds_alternative(prefix1)); + CHECK(std::holds_alternative(prefix1)); auto dec2 = get_if(&prefix1); auto dec_opt2 = dec2->var(); - assert(holds_alternative(dec_opt2)); + CHECK(holds_alternative(dec_opt2)); auto fe2 = std::get_if(&dec_opt2); - assert(fe2->property_id().str() == "table2"); + CHECK(fe2->property_id().str() == "table2"); auto prefix2 = fe2->table_id().options(); - assert(std::holds_alternative(prefix2)); + CHECK(std::holds_alternative(prefix2)); auto dec3 = std::get_if(&prefix2); auto dec_opt3 = dec3->var(); - assert(holds_alternative(dec_opt3)); + CHECK(holds_alternative(dec_opt3)); auto table_id = std::get_if(&dec_opt3); - assert(table_id->str() == "table1"s); + CHECK(table_id->str() == "table1"s); } TEST_CASE("table_statements", "[tree-sitter][!hide]") { ts::Parser parser; @@ -672,36 +673,36 @@ TEST_CASE("table_statements", "[tree-sitter][!hide]") { auto prog = Program(root); Body body = prog.body(); auto stats = body.statements(); - assert(stats.size() == 1); + CHECK(stats.size() == 1); auto opt1 = stats[0].options(); - assert(std::holds_alternative(opt1)); + CHECK(std::holds_alternative(opt1)); auto* exp1 = std::get_if(&opt1); auto exp_opt1 = exp1->options(); - assert(std::holds_alternative
(exp_opt1)); + CHECK(std::holds_alternative
(exp_opt1)); auto table1 = std::get_if
(&exp_opt1); auto fields = table1->fields(); - assert(fields.size() == 3); + CHECK(fields.size() == 3); auto field1_opt = fields[0].content(); - assert(std::holds_alternative(field1_opt)); + CHECK(std::holds_alternative(field1_opt)); auto field1 = std::get_if(&field1_opt); - assert(field1->first.str() == "field1"s); - assert(std::holds_alternative(field1->second.options())); + CHECK(field1->first.str() == "field1"s); + CHECK(std::holds_alternative(field1->second.options())); auto content1_opt = field1->second.options(); auto content1 = std::get_if(&content1_opt); - assert(content1->is_string()); + CHECK(content1->is_string()); auto raw = content1->raw(); auto content1_str = get_if(&raw); - assert(content1_str->value == "name"s); + CHECK(content1_str->value == "name"s); auto field2_opt = fields[1].content(); - assert(std::holds_alternative(field2_opt)); + CHECK(std::holds_alternative(field2_opt)); auto field2 = std::get_if(&field2_opt); - assert(std::holds_alternative(field2->first.options())); - assert(std::holds_alternative
(field2->second.options())); + CHECK(std::holds_alternative(field2->first.options())); + CHECK(std::holds_alternative
(field2->second.options())); auto field3_opt = fields[2].content(); - assert(std::holds_alternative(field3_opt)); + CHECK(std::holds_alternative(field3_opt)); auto field3 = std::get_if(&field3_opt); auto content3_opt = field3->options(); - assert(std::holds_alternative(content3_opt)); + CHECK(std::holds_alternative(content3_opt)); } TEST_CASE("function_calls", "[tree-sitter][!hide]") { ts::Parser parser; @@ -715,47 +716,47 @@ TEST_CASE("function_calls", "[tree-sitter][!hide]") { auto prog = Program(root); Body body = prog.body(); auto stats = body.statements(); - assert(stats.size() == 5); + CHECK(stats.size() == 5); std::vector func_calls; std::transform(stats.begin(), stats.end(), std::back_inserter(func_calls), [](Statement stat) { auto opt = stat.options(); - assert(std::holds_alternative(opt)); + CHECK(std::holds_alternative(opt)); return *std::get_if(&opt); }); - assert(!func_calls[0].method().has_value()); - assert(std::holds_alternative(func_calls[0].id().options())); + CHECK(!func_calls[0].method().has_value()); + CHECK(std::holds_alternative(func_calls[0].id().options())); auto opt1 = func_calls[0].id().options(); auto name1 = std::get_if(&opt1); - assert(holds_alternative(name1->var())); - assert(func_calls[0].args().size() == 2); + CHECK(holds_alternative(name1->var())); + CHECK(func_calls[0].args().size() == 2); - assert(!func_calls[1].method().has_value()); - assert(std::holds_alternative(func_calls[1].id().options())); + CHECK(!func_calls[1].method().has_value()); + CHECK(std::holds_alternative(func_calls[1].id().options())); auto opt2 = func_calls[1].id().options(); auto name2 = std::get_if(&opt2); - assert(holds_alternative(name2->var())); - assert(func_calls[1].args().empty()); + CHECK(holds_alternative(name2->var())); + CHECK(func_calls[1].args().empty()); - assert(func_calls[2].method().has_value()); - assert(std::holds_alternative(func_calls[2].id().options())); + CHECK(func_calls[2].method().has_value()); + CHECK(std::holds_alternative(func_calls[2].id().options())); auto opt3 = func_calls[2].id().options(); auto name3 = std::get_if(&opt3); - assert(holds_alternative(name3->var())); - assert(func_calls[2].args().empty()); + CHECK(holds_alternative(name3->var())); + CHECK(func_calls[2].args().empty()); - assert(func_calls[3].args().size() == 1); - assert(std::holds_alternative(func_calls[3].args()[0].options())); + CHECK(func_calls[3].args().size() == 1); + CHECK(std::holds_alternative(func_calls[3].args()[0].options())); auto opt4 = func_calls[3].args()[0].options(); auto str = std::get_if(&opt4); - assert(str->is_string()); + CHECK(str->is_string()); - assert(func_calls[4].args().size() == 1); - assert(std::holds_alternative
(func_calls[4].args()[0].options())); + CHECK(func_calls[4].args().size() == 1); + CHECK(std::holds_alternative
(func_calls[4].args()[0].options())); auto opt5 = func_calls[4].args()[0].options(); auto table = std::get_if
(&opt5); - assert(table->fields().size() == 4); + CHECK(table->fields().size() == 4); for (uint i = 0; i < 4; i++) { - assert(std::holds_alternative(table->fields()[i].content())); + CHECK(std::holds_alternative(table->fields()[i].content())); } } } // namespace minilua::details \ No newline at end of file From 3c8eb8c27e253011a4cb72c6831ab28b31820167 Mon Sep 17 00:00:00 2001 From: CFU9 Date: Wed, 20 Jan 2021 13:28:16 +0100 Subject: [PATCH 08/17] updated submodule tree-sitter-lua to the modified version and adjusted all necessary classes to support the new grammar --- .gitmodules | 2 +- include/MiniLua/tree_sitter_ast.hpp | 20 ++++++- include/tree_sitter/tree_sitter.hpp | 2 + src/core/tree_sitter_ast.cpp | 91 ++++++++++++++--------------- tests/tree_sitter_ast_tests.cpp | 58 +++++++++++++----- 5 files changed, 107 insertions(+), 66 deletions(-) diff --git a/.gitmodules b/.gitmodules index 4d082dc4..c3c84b01 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,7 @@ url = ../../tree-sitter/tree-sitter.git [submodule "extern/tree-sitter-lua"] path = extern/tree-sitter-lua - url = ../../Azganoth/tree-sitter-lua.git + url = ../../CFU9/tree-sitter-lua.git [submodule "extern/catch2"] path = extern/catch2 url = ../../catchorg/Catch2.git diff --git a/include/MiniLua/tree_sitter_ast.hpp b/include/MiniLua/tree_sitter_ast.hpp index 0b9be71e..cff43807 100644 --- a/include/MiniLua/tree_sitter_ast.hpp +++ b/include/MiniLua/tree_sitter_ast.hpp @@ -347,12 +347,26 @@ class Return { */ auto explist() -> std::vector; }; -// TableIndex +/** + * class for table_index nodes + */ class TableIndex { - // TODO + ts::Node table_index; +public: + TableIndex(ts::Node); + /** + * + * @return a prefix that eveluates to the table of this table index + */ + auto table() -> Prefix; + /** + * + * @return an expression that eveluates to the index + */ + auto index() -> Expression; }; /** - * class for variable_declarators + * class for variable_declarator nodes */ class VariableDeclarator { ts::Node dec; diff --git a/include/tree_sitter/tree_sitter.hpp b/include/tree_sitter/tree_sitter.hpp index 2726c644..9c142a5f 100644 --- a/include/tree_sitter/tree_sitter.hpp +++ b/include/tree_sitter/tree_sitter.hpp @@ -306,7 +306,9 @@ const TypeId NODE_VARIABLE_DECLARATION = LUA_LANGUAGE.node_type_id("variable_dec const TypeId NODE_LOCAL_VARIABLE_DECLARATION = LUA_LANGUAGE.node_type_id("local_variable_declaration", true); const TypeId NODE_FIELD_EXPRESSION = LUA_LANGUAGE.node_type_id("field_expression", true); +const TypeId NODE_TABLE_INDEX = LUA_LANGUAGE.node_type_id("table_index", true); const TypeId NODE_VARIABLE_DECLARATOR = LUA_LANGUAGE.node_type_id("variable_declarator", true); +const TypeId NODE_LOCAL_VARIABLE_DECLARATOR = LUA_LANGUAGE.node_type_id("local_variable_declarator", true); const TypeId NODE_DO_STATEMENT = LUA_LANGUAGE.node_type_id("do_statement", true); const TypeId NODE_IF_STATEMENT = LUA_LANGUAGE.node_type_id("if_statement", true); const TypeId NODE_ELSEIF = LUA_LANGUAGE.node_type_id("elseif", true); diff --git a/src/core/tree_sitter_ast.cpp b/src/core/tree_sitter_ast.cpp index 66c5baa6..40b3a45e 100644 --- a/src/core/tree_sitter_ast.cpp +++ b/src/core/tree_sitter_ast.cpp @@ -219,43 +219,24 @@ auto LoopExpression::step() -> std::optional { } } InLoopExpression::InLoopExpression(ts::Node node) : loop_exp(node) { - if (node.type_id() != ts::NODE_LOOP_EXPRESSION) { - throw std::runtime_error("not a loop_expression node"); + if (node.type_id() != ts::NODE_LOOP_EXPRESSION || node.named_child_count()!=2) { + throw std::runtime_error("not a in_loop_expression node"); } } auto InLoopExpression::loop_exps() -> std::vector { - std::vector temp_body = loop_exp.children(); - std::vector body; - std::copy_if(temp_body.begin(), temp_body.end(), std::back_inserter(body), [](ts::Node node) { - return node.text() != ","; - }); - for (long unsigned int i = 0; i < body.size(); i++) { - if (body[i].type_id() != ts::NODE_IDENTIFIER) { - std::vector res; - std::transform( - body.begin() + i + 1, body.end(), std::back_inserter(res), - [](ts::Node node) { return Expression(node); }); - return res; - } - } - throw std::runtime_error("invalid in_loop_expression"); + std::vector children = loop_exp.named_child(1).value().named_children(); + std::vector exps; + exps.reserve(children.size()); + std::transform(children.begin(), children.end(),std::back_inserter(exps),[](ts::Node node){return Expression(node);}); + return exps; } auto InLoopExpression::loop_vars() -> std::vector { - std::vector temp_body = loop_exp.children(); - std::vector body; - std::copy_if(temp_body.begin(), temp_body.end(), std::back_inserter(body), [](ts::Node node) { - return node.text() != ","; - }); - for (long unsigned int i = 0; i < body.size(); i++) { - if (body[i].type_id() != ts::NODE_IDENTIFIER) { - std::vector res; - std::transform( - body.begin(), body.begin() + i, std::back_inserter(res), - [](ts::Node node) { return Identifier(node); }); - return res; - } - } - throw std::runtime_error("invalid in_loop_expression"); + std::vector children = loop_exp.named_child(0).value().named_children(); + std::vector loop_vars; + loop_vars.reserve(children.size()); + std::transform( + children.begin(), children.end(),std::back_inserter(loop_vars),[](ts::Node node){return Identifier(node);}); + return loop_vars; } // ForInStatement ForInStatement::ForInStatement(ts::Node node) : for_in(node) { @@ -407,15 +388,15 @@ auto Return::explist() -> std::vector { // VariableDeclaration VariableDeclaration::VariableDeclaration(ts::Node node) : var_dec(node) { if (node.type_id() != ts::NODE_VARIABLE_DECLARATION || node.named_child_count() < 2 || - node.named_child(0).value().type_id() != 113) { - throw std::runtime_error(std::to_string(node.named_child(0)->type_id())); + node.named_child(0).value().type_id() != ts::NODE_VARIABLE_DECLARATOR) { + throw std::runtime_error("not a variable_declaration node"); } } auto VariableDeclaration::declarations() -> std::vector { std::vector nodes = var_dec.named_children(); std::vector res; auto it = nodes.begin(); - while (it->type_id() == 113) { + while (it->type_id() == ts::NODE_VARIABLE_DECLARATOR) { it++; } res.reserve(nodes.size() - (it - nodes.begin())); @@ -427,7 +408,7 @@ auto VariableDeclaration::declarators() -> std::vector { std::vector nodes = var_dec.named_children(); std::vector res; auto it = nodes.begin(); - while (it->type_id() == 113) { + while (it->type_id() == ts::NODE_VARIABLE_DECLARATOR) { it++; } res.reserve(it - nodes.begin()); @@ -440,7 +421,7 @@ auto VariableDeclaration::declarators() -> std::vector { VariableDeclarator::VariableDeclarator(ts::Node node) : dec(node) { if (node.type_id() != ts::NODE_VARIABLE_DECLARATOR && node.type_id() != ts::NODE_IDENTIFIER && node.type_id() != ts::NODE_FIELD_EXPRESSION && - node.type_id() != 113) { // TODO add tableindex + node.type_id() != ts::NODE_TABLE_INDEX) { throw std::runtime_error("not a variable declarator"); } } @@ -449,23 +430,26 @@ auto VariableDeclarator::var() -> std::varianttype_id() == ts::NODE_IDENTIFIER) { return Identifier(dec.named_child(0).value()); } else if (dec.named_child(0)->type_id() == ts::NODE_FIELD_EXPRESSION) { return FieldExpression(dec.named_child(0).value()); + } else if (dec.named_child(0)->type_id() == ts::NODE_TABLE_INDEX) { + return TableIndex(dec.named_child(0).value()); } else { throw std::runtime_error("invalid variable declarator"); } - } else { - return TableIndex(); // TODO find good constructor for tableindex + }else{ + throw std::runtime_error("invalid variable declarator"); } } // LocalVariableDeclaration LocalVariableDeclaration::LocalVariableDeclaration(ts::Node node) : local_var_dec(node) { - if (node.type_id() != ts::NODE_LOCAL_VARIABLE_DECLARATION || !node.named_child(0).has_value() || - node.named_child(0)->type_id() != ts::NODE_VARIABLE_DECLARATOR) { + if (node.type_id() != ts::NODE_LOCAL_VARIABLE_DECLARATION) { throw std::runtime_error("not a local_variable_declaration node"); } } @@ -483,7 +467,7 @@ auto LocalVariableDeclaration::declarations() -> std::vector { } // LocalVariableDeclarator LocalVariableDeclarator::LocalVariableDeclarator(ts::Node node) : var_dec(node) { - if (node.type_id() != ts::NODE_VARIABLE_DECLARATOR) { + if (node.type_id() != ts::NODE_LOCAL_VARIABLE_DECLARATOR) { throw std::runtime_error("not a local_variable_declarator node"); } } @@ -496,6 +480,18 @@ auto LocalVariableDeclarator::vars() -> std::vector { }); return res; } +//TableIndex +TableIndex::TableIndex(ts::Node node) : table_index(node) { + if (node.type_id() != ts::NODE_TABLE_INDEX || node.named_child_count() != 2) { + throw std::runtime_error("not a table_index node"); + } +} +auto TableIndex::table() -> Prefix { + return Prefix(table_index.named_child(0).value()); +} +auto TableIndex::index() -> Expression { + return Expression(table_index.named_child(1).value()); +} // DoStatement DoStatement::DoStatement(ts::Node node) : do_statement(node) { if (node.type_id() != ts::NODE_DO_STATEMENT) { @@ -753,7 +749,7 @@ auto Field::content() -> std::variant< Prefix::Prefix(ts::Node node) : prefix(node) { if (!(node.type_id() == ts::NODE_SELF || node.type_id() == ts::NODE_GLOBAL_VARIABLE || node.type_id() == ts::NODE_FUNCTION_CALL || node.type_id() == ts::NODE_IDENTIFIER || - node.type_id() == ts::NODE_FIELD_EXPRESSION)) { // TODO add tableindex + node.type_id() == ts::NODE_FIELD_EXPRESSION || node.type_id() == ts::NODE_TABLE_INDEX)) { throw std::runtime_error("Not a prefix-node"); } } @@ -769,7 +765,7 @@ auto Prefix::options() return Expression(prefix.child(1).value()); } else if ( prefix.type_id() == ts::NODE_IDENTIFIER || - prefix.type_id() == ts::NODE_FIELD_EXPRESSION) { // TODO add table index + prefix.type_id() == ts::NODE_FIELD_EXPRESSION || prefix.type_id() == ts::NODE_TABLE_INDEX) { return VariableDeclarator(prefix); } else { throw std::runtime_error("Not a prefix-node"); @@ -820,7 +816,8 @@ auto Expression::options() -> std::variant< } else if ( exp.type_id() == ts::NODE_SELF || exp.type_id() == ts::NODE_FUNCTION_CALL || exp.type_id() == ts::NODE_GLOBAL_VARIABLE || exp.type_id() == ts::NODE_FIELD_EXPRESSION || - (exp.child(0).has_value() && exp.child(0)->text() == "(")) { // TODO add TableIndex to if + exp.type_id() == ts::NODE_TABLE_INDEX || + (exp.child(0).has_value() && exp.child(0)->text() == "(")) { return Prefix(exp); } else { throw std::runtime_error("Not an expression-node"); diff --git a/tests/tree_sitter_ast_tests.cpp b/tests/tree_sitter_ast_tests.cpp index 22990f3d..e1186d09 100644 --- a/tests/tree_sitter_ast_tests.cpp +++ b/tests/tree_sitter_ast_tests.cpp @@ -4,7 +4,7 @@ #include #include namespace minilua::details { -TEST_CASE("statements", "[tree-sitter][!hide]") { +TEST_CASE("statements", "[tree-sitter]") { ts::Parser parser; std::string source = "i,t,l = 5\n" "local z = 42\n" @@ -52,7 +52,7 @@ TEST_CASE("statements", "[tree-sitter][!hide]") { CHECK(statement.at(i).options().index() == i); } } -TEST_CASE("expressions", "[tree-sitter][!hide]") { +TEST_CASE("expressions", "[tree-sitter]") { uint exp_count = 29; ts::Parser parser; std::string source = "...\n" @@ -163,7 +163,7 @@ TEST_CASE("expressions", "[tree-sitter][!hide]") { } } -TEST_CASE("do_statements", "[tree-sitter][!hide]") { +TEST_CASE("do_statements", "[tree-sitter]") { ts::Parser parser; std::string source = "do\n" "end\n" @@ -206,7 +206,7 @@ TEST_CASE("do_statements", "[tree-sitter][!hide]") { CHECK(dos[4].body().statements().size() == 1); CHECK(dos[4].body().ret().has_value()); } -TEST_CASE("if_statements", "[tree-sitter][!hide]") { +TEST_CASE("if_statements", "[tree-sitter]") { ts::Parser parser; std::string source = "if c(&end3->raw()); CHECK(end3_num->value == 42); } -TEST_CASE("for_in_statements", "[tree-sitter][!hide]") { +TEST_CASE("for_in_statements", "[tree-sitter]") { ts::Parser parser; std::string source = "for k, v in next, t, nil do\n" " print(k, v)\n" @@ -400,7 +400,7 @@ TEST_CASE("for_in_statements", "[tree-sitter][!hide]") { CHECK(fors[1].loop_exp().loop_vars().size() == 5); CHECK(fors[1].loop_exp().loop_exps().size() == 1); } -TEST_CASE("function_statements", "[tree-sitter][!hide]") { +TEST_CASE("function_statements", "[tree-sitter]") { ts::Parser parser; std::string source = "function foo (a,b,c)\n" " 1+1\n" @@ -494,7 +494,7 @@ TEST_CASE("function_statements", "[tree-sitter][!hide]") { CHECK(func[9].parameters().spread() == NO_SPREAD); CHECK(func[9].parameters().params().empty()); } -TEST_CASE("while_and_repeat_statements", "[tree-sitter][!hide]") { +TEST_CASE("while_and_repeat_statements", "[tree-sitter]") { ts::Parser parser; std::string source = "while i<#table do\n" " i=i+1\n" @@ -539,7 +539,7 @@ TEST_CASE("while_and_repeat_statements", "[tree-sitter][!hide]") { CHECK(repeat_stat->body().statements().size() == 1); CHECK(repeat_stat->body().ret().has_value()); } -TEST_CASE("return_statements", "[tree-sitter][!hide]") { +TEST_CASE("return_statements", "[tree-sitter]") { ts::Parser parser; std::string source = "do\n" "return a,b,c,d;\n" @@ -572,7 +572,7 @@ TEST_CASE("return_statements", "[tree-sitter][!hide]") { CHECK(returns[2].explist().size() == 1); CHECK(std::holds_alternative(returns[2].explist()[0].options())); } -TEST_CASE("var_dec_statements", "[tree-sitter][!hide]") { +TEST_CASE("var_dec_statements", "[tree-sitter]") { ts::Parser parser; std::string source = "a = 1\n" "a,b,c,d = 1+2,5+7,a\n" @@ -581,13 +581,13 @@ TEST_CASE("var_dec_statements", "[tree-sitter][!hide]") { "local i,j = 42,96\n" "\n" "table1.table2.field1 = function() print(2) end\n" - ""; + "table1[table2] = 2\n"; ts::Tree tree = parser.parse_string(source); ts::Node root = tree.root_node(); auto prog = Program(root); Body body = prog.body(); auto stats = body.statements(); - CHECK(stats.size() == 6); + CHECK(stats.size() == 7); // 1st statement auto opt1 = stats[0].options(); CHECK(std::holds_alternative(opt1)); @@ -658,8 +658,28 @@ TEST_CASE("var_dec_statements", "[tree-sitter][!hide]") { CHECK(holds_alternative(dec_opt3)); auto table_id = std::get_if(&dec_opt3); CHECK(table_id->str() == "table1"s); + //7th statement + auto opt7 = stats[6].options(); + CHECK(std::holds_alternative(opt7)); + auto var_dec7 = std::get_if(&opt7); + CHECK(var_dec7->declarations().size()==1); + CHECK(var_dec7->declarators().size()==1); + auto ti_opt1 = var_dec7->declarators()[0].var(); + CHECK(std::holds_alternative(ti_opt1)); + auto ti1 = std::get_if(&ti_opt1); + auto pref1 = ti1->table().options(); + CHECK(std::holds_alternative(pref1)); + auto pref_dec1 = std::get_if(&pref1); + auto pref_opt1 = pref_dec1->var(); + CHECK(std::holds_alternative(pref_opt1)); + auto id1 = std::get_if(&pref_opt1); + CHECK(id1->str()=="table1"); + auto index1_opt = ti1->index().options(); + CHECK(std::holds_alternative(index1_opt)); + auto index1 = std::get_if(&index1_opt); + CHECK(index1->str()=="table2"); } -TEST_CASE("table_statements", "[tree-sitter][!hide]") { +TEST_CASE("table_statements", "[tree-sitter]") { ts::Parser parser; std::string source = "{\n" "field1 = \"name\";\n" @@ -704,7 +724,7 @@ TEST_CASE("table_statements", "[tree-sitter][!hide]") { auto content3_opt = field3->options(); CHECK(std::holds_alternative(content3_opt)); } -TEST_CASE("function_calls", "[tree-sitter][!hide]") { +TEST_CASE("function_calls", "[tree-sitter]") { ts::Parser parser; std::string source = "foo(a,b)\n" "table.foo()\n" @@ -759,4 +779,12 @@ TEST_CASE("function_calls", "[tree-sitter][!hide]") { CHECK(std::holds_alternative(table->fields()[i].content())); } } -} // namespace minilua::details \ No newline at end of file +} // namespace minilua::details + +TEST_CASE("new_nodes", "[tree-sitter]") { + ts::Parser parser; + std::string source = "a[\"b\"] = 4+4\n" + "local d"; + ts::Tree tree = parser.parse_string(source); + ts::Node root = tree.root_node(); +} \ No newline at end of file From b0f92f2964f54f18da825dfcf11a6aaeb7b251df Mon Sep 17 00:00:00 2001 From: CFU9 Date: Wed, 20 Jan 2021 13:48:09 +0100 Subject: [PATCH 09/17] updated submodule tree-sitter-lua to the modified version --- .gitmodules | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitmodules b/.gitmodules index c3c84b01..655657ed 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,6 +4,7 @@ [submodule "extern/tree-sitter-lua"] path = extern/tree-sitter-lua url = ../../CFU9/tree-sitter-lua.git + update = rebase [submodule "extern/catch2"] path = extern/catch2 url = ../../catchorg/Catch2.git From 905324212b77e1748226a42933317f50ef5904b1 Mon Sep 17 00:00:00 2001 From: CFU9 Date: Wed, 20 Jan 2021 13:52:13 +0100 Subject: [PATCH 10/17] updated submodule tree-sitter-lua to the modified version --- .gitmodules | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitmodules b/.gitmodules index 655657ed..70fdd710 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,6 +5,7 @@ path = extern/tree-sitter-lua url = ../../CFU9/tree-sitter-lua.git update = rebase + branch = master [submodule "extern/catch2"] path = extern/catch2 url = ../../catchorg/Catch2.git From e75a1dc1276ee6a0b4736669e0431a9a2685ef52 Mon Sep 17 00:00:00 2001 From: CFU9 Date: Wed, 20 Jan 2021 14:00:25 +0100 Subject: [PATCH 11/17] updated submodule tree-sitter-lua to the modified version --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 70fdd710..d7eb753b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,7 +5,7 @@ path = extern/tree-sitter-lua url = ../../CFU9/tree-sitter-lua.git update = rebase - branch = master + branch = adjustments [submodule "extern/catch2"] path = extern/catch2 url = ../../catchorg/Catch2.git From 7f32c51f7685034bc51544c377474d09a363ab6c Mon Sep 17 00:00:00 2001 From: CFU9 Date: Wed, 20 Jan 2021 14:19:26 +0100 Subject: [PATCH 12/17] updated submodule tree-sitter-lua to the modified version --- extern/tree-sitter-lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/tree-sitter-lua b/extern/tree-sitter-lua index d835774e..d1da08cf 160000 --- a/extern/tree-sitter-lua +++ b/extern/tree-sitter-lua @@ -1 +1 @@ -Subproject commit d835774e14fd7073567358cdb8900c6012ea5eef +Subproject commit d1da08cf00ecfa157fce5d020509d790abe067a9 From 0fa8a9f939a53e57bfd9e3519e569dd06096c019 Mon Sep 17 00:00:00 2001 From: CFU9 Date: Wed, 20 Jan 2021 15:04:55 +0100 Subject: [PATCH 13/17] updated submodule tree-sitter --- extern/tree-sitter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/tree-sitter b/extern/tree-sitter index 12341dbb..1dc127e5 160000 --- a/extern/tree-sitter +++ b/extern/tree-sitter @@ -1 +1 @@ -Subproject commit 12341dbbc03075e0b3bdcbf05191efbac78731fe +Subproject commit 1dc127e5dae7550a58a09886a19fdea19196bcf1 From 10764225cd4e5299af8017fa9e62e6ff82f94113 Mon Sep 17 00:00:00 2001 From: CFU9 Date: Fri, 22 Jan 2021 12:42:58 +0100 Subject: [PATCH 14/17] moved and renamed the files for the ast classes --- include/tree_sitter/tree_sitter.hpp | 3 --- src/{core/tree_sitter_ast.cpp => details/ast.cpp} | 2 +- .../MiniLua/tree_sitter_ast.hpp => src/details/ast.hpp | 8 ++++---- tests/tree_sitter_ast_tests.cpp | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) rename src/{core/tree_sitter_ast.cpp => details/ast.cpp} (99%) rename include/MiniLua/tree_sitter_ast.hpp => src/details/ast.hpp (99%) diff --git a/include/tree_sitter/tree_sitter.hpp b/include/tree_sitter/tree_sitter.hpp index 9c142a5f..b64d3a28 100644 --- a/include/tree_sitter/tree_sitter.hpp +++ b/include/tree_sitter/tree_sitter.hpp @@ -384,9 +384,6 @@ class Node { struct unsafe_t {}; // used as a token for the unsafe constructor constexpr static unsafe_t unsafe{}; - Node(){ - - } /** * Creates a new node from the given tree-sitter node and the tree. * diff --git a/src/core/tree_sitter_ast.cpp b/src/details/ast.cpp similarity index 99% rename from src/core/tree_sitter_ast.cpp rename to src/details/ast.cpp index 40b3a45e..b4408013 100644 --- a/src/core/tree_sitter_ast.cpp +++ b/src/details/ast.cpp @@ -1,4 +1,4 @@ -#include "MiniLua/tree_sitter_ast.hpp" +#include "ast.hpp" #include #include #include diff --git a/include/MiniLua/tree_sitter_ast.hpp b/src/details/ast.hpp similarity index 99% rename from include/MiniLua/tree_sitter_ast.hpp rename to src/details/ast.hpp index cff43807..4eacccd7 100644 --- a/include/MiniLua/tree_sitter_ast.hpp +++ b/src/details/ast.hpp @@ -1,8 +1,8 @@ -#ifndef MINILUA_TREE_SITTER_AST_HPP -#define MINILUA_TREE_SITTER_AST_HPP +#ifndef MINILUA_AST_HPP +#define MINILUA_AST_HPP -#include "values.hpp" +#include "MiniLua/values.hpp" #include #include namespace minilua::details { @@ -719,4 +719,4 @@ class Statement { }; } // namespace minilua::details -#endif // MINILUA_TREE_SITTER_AST_HPP +#endif // MINILUA_AST_HPP diff --git a/tests/tree_sitter_ast_tests.cpp b/tests/tree_sitter_ast_tests.cpp index e1186d09..744d3b95 100644 --- a/tests/tree_sitter_ast_tests.cpp +++ b/tests/tree_sitter_ast_tests.cpp @@ -1,4 +1,4 @@ -#include "MiniLua/tree_sitter_ast.hpp" +#include "details/ast.hpp" #include "tree_sitter/tree_sitter.hpp" #include #include From 64f408446c65f6aeaf815f58bfdb2f8b11f46785 Mon Sep 17 00:00:00 2001 From: CFU9 Date: Fri, 22 Jan 2021 13:37:46 +0100 Subject: [PATCH 15/17] merged variable_declaration and local_variable_declaration and moved some conditions that should be ensured by the tree sitter grammar into asserts --- src/details/ast.cpp | 170 ++++++++++++++++---------------- src/details/ast.hpp | 38 ++----- tests/tree_sitter_ast_tests.cpp | 62 +++++++----- 3 files changed, 133 insertions(+), 137 deletions(-) diff --git a/src/details/ast.cpp b/src/details/ast.cpp index b4408013..2d15af36 100644 --- a/src/details/ast.cpp +++ b/src/details/ast.cpp @@ -1,4 +1,5 @@ #include "ast.hpp" +#include #include #include #include @@ -97,7 +98,8 @@ auto Program::body() -> Body { return Body(program.named_children()); } };*/ // BinaryOperation BinaryOperation::BinaryOperation(ts::Node node) : bin_op(node) { - if (node.type_id() != ts::NODE_BINARY_OPERATION || node.child_count() != 3) { + assert(node.child_count() == 3); + if (node.type_id() != ts::NODE_BINARY_OPERATION) { throw std::runtime_error("not a binary_operation node"); } } @@ -153,7 +155,8 @@ auto BinaryOperation::op() -> BinOpEnum { } // UnaryOperation UnaryOperation::UnaryOperation(ts::Node node) : un_op(node) { - if (node.type_id() != ts::NODE_UNARY_OPERATION || node.child_count() != 2) { + assert(node.child_count() == 2); + if (node.type_id() != ts::NODE_UNARY_OPERATION) { throw std::runtime_error("not an unary_operation node"); } } @@ -180,8 +183,9 @@ auto UnaryOperation::exp() -> Expression { return Expression(un_op.child(0).valu // ForStatement ForStatement::ForStatement(ts::Node node) : for_statement(node) { - if (node.type_id() != ts::NODE_FOR_STATEMENT || !node.named_child(0).has_value() || - node.named_child(0).value().type_id() != ts::NODE_LOOP_EXPRESSION) { + assert(node.named_child(0).has_value() && + node.named_child(0).value().type_id() == ts::NODE_LOOP_EXPRESSION); + if (node.type_id() != ts::NODE_FOR_STATEMENT) { throw std::runtime_error("not a for_statement node"); } } @@ -196,7 +200,8 @@ auto ForStatement::loop_exp() -> LoopExpression { } LoopExpression::LoopExpression(ts::Node node) : loop_exp(node) { - if (node.type_id() != ts::NODE_LOOP_EXPRESSION || node.child_count() < 3) { + assert(node.named_child_count() == 3 || node.named_child_count() == 4); + if (node.type_id() != ts::NODE_LOOP_EXPRESSION) { throw std::runtime_error("not a loop_expression node"); } } @@ -219,7 +224,8 @@ auto LoopExpression::step() -> std::optional { } } InLoopExpression::InLoopExpression(ts::Node node) : loop_exp(node) { - if (node.type_id() != ts::NODE_LOOP_EXPRESSION || node.named_child_count()!=2) { + assert(node.named_child_count()==2); + if (node.type_id() != ts::NODE_LOOP_EXPRESSION) { throw std::runtime_error("not a in_loop_expression node"); } } @@ -240,8 +246,9 @@ auto InLoopExpression::loop_vars() -> std::vector { } // ForInStatement ForInStatement::ForInStatement(ts::Node node) : for_in(node) { - if (node.type_id() != ts::NODE_FOR_IN_STATEMENT || !node.named_child(0).has_value() || - node.named_child(0)->type_id() != ts::NODE_LOOP_EXPRESSION) { + assert(node.named_child(0).has_value() && + node.named_child(0)->type_id() == ts::NODE_LOOP_EXPRESSION); + if (node.type_id() != ts::NODE_FOR_IN_STATEMENT) { throw std::runtime_error("not a for_in_statement node"); } } @@ -255,8 +262,9 @@ auto ForInStatement::body() -> Body { } // WhileStatement WhileStatement::WhileStatement(ts::Node node) : while_statement(node) { - if (node.type_id() != ts::NODE_WHILE_STATEMENT || !node.named_child(0).has_value() || - node.named_child(0).value().type_id() != ts::NODE_CONDITION_EXPRESSION) { + assert(node.named_child(0).has_value() && + node.named_child(0).value().type_id() == ts::NODE_CONDITION_EXPRESSION); + if (node.type_id() != ts::NODE_WHILE_STATEMENT) { throw std::runtime_error("not a while_statement node"); } } @@ -270,8 +278,9 @@ auto WhileStatement::exit_cond() -> Expression { return Expression(while_statement.named_child(0).value().named_child(0).value()); } RepeatStatement::RepeatStatement(ts::Node node) : repeat_statement(node) { - if (node.type_id() != ts::NODE_REPEAT_STATEMENT || - (node.named_children().end() - 1)->type_id() != ts::NODE_CONDITION_EXPRESSION) { + assert(node.named_child_count()>=1 && (node.named_children().end() - 1)->type_id() == ts::NODE_CONDITION_EXPRESSION); + if (node.type_id() != ts::NODE_REPEAT_STATEMENT) + { throw std::runtime_error("not a repeat_statement node"); } } @@ -288,8 +297,9 @@ auto RepeatStatement::until_cond() -> Expression { } // If IfStatement::IfStatement(ts::Node node) : if_statement(node) { - if (node.type_id() != ts::NODE_IF_STATEMENT || !node.named_child(0).has_value() || - node.named_child(0).value().type_id() != ts::NODE_CONDITION_EXPRESSION) { + assert(node.named_child(0).has_value() && + node.named_child(0).value().type_id() == ts::NODE_CONDITION_EXPRESSION); + if (node.type_id() != ts::NODE_IF_STATEMENT) { throw std::runtime_error("not an if_statement node"); } } @@ -355,8 +365,9 @@ Else::Else(ts::Node node) : else_statement(node) { auto Else::body() -> Body { return Body(else_statement.named_children()); } // ElseIf ElseIf::ElseIf(ts::Node node) : else_if(node) { - if (node.type_id() != ts::NODE_ELSEIF || !node.named_child(0).has_value() || - node.named_child(0).value().type_id() != ts::NODE_CONDITION_EXPRESSION) { + assert(node.named_child(0).has_value() && + node.named_child(0).value().type_id() == ts::NODE_CONDITION_EXPRESSION); + if (node.type_id() != ts::NODE_ELSEIF) { throw std::runtime_error("not a else_if node"); } } @@ -387,35 +398,59 @@ auto Return::explist() -> std::vector { } // VariableDeclaration VariableDeclaration::VariableDeclaration(ts::Node node) : var_dec(node) { - if (node.type_id() != ts::NODE_VARIABLE_DECLARATION || node.named_child_count() < 2 || - node.named_child(0).value().type_id() != ts::NODE_VARIABLE_DECLARATOR) { + if (node.type_id() != ts::NODE_VARIABLE_DECLARATION && node.type_id() != ts::NODE_LOCAL_VARIABLE_DECLARATION) { throw std::runtime_error("not a variable_declaration node"); + }else{ + _local = node.type_id() == ts::NODE_LOCAL_VARIABLE_DECLARATION; } } auto VariableDeclaration::declarations() -> std::vector { - std::vector nodes = var_dec.named_children(); std::vector res; - auto it = nodes.begin(); - while (it->type_id() == ts::NODE_VARIABLE_DECLARATOR) { - it++; + if(_local){ + std::vector nodes = var_dec.named_children(); + res.reserve(nodes.size() - 1); + std::transform(nodes.begin() + 1, nodes.end(), std::back_inserter(res), [](ts::Node node) { + return Expression(node); + }); + return res; + }else { + std::vector nodes = var_dec.named_children(); + auto it = nodes.begin(); + while (it->type_id() == ts::NODE_VARIABLE_DECLARATOR) { + it++; + } + res.reserve(nodes.size() - (it - nodes.begin())); + std::transform(it, nodes.end(), std::back_inserter(res), [](ts::Node node) { + return Expression(node); + }); + return res; } - res.reserve(nodes.size() - (it - nodes.begin())); - std::transform( - it, nodes.end(), std::back_inserter(res), [](ts::Node node) { return Expression(node); }); - return res; } auto VariableDeclaration::declarators() -> std::vector { - std::vector nodes = var_dec.named_children(); - std::vector res; - auto it = nodes.begin(); - while (it->type_id() == ts::NODE_VARIABLE_DECLARATOR) { - it++; - } - res.reserve(it - nodes.begin()); - std::transform(nodes.begin(), it, std::back_inserter(res), [](ts::Node node) { - return VariableDeclarator(node); - }); - return res; + if(_local){ + std::vector nodes = var_dec.named_child(0).value().named_children(); + std::vector res; + res.reserve(nodes.size()); + std::transform(nodes.begin(), nodes.end(), std::back_inserter(res), [](ts::Node node) { + return VariableDeclarator(node); + }); + return res; + }else { + std::vector nodes = var_dec.named_children(); + std::vector res; + auto it = nodes.begin(); + while (it->type_id() == ts::NODE_VARIABLE_DECLARATOR) { + it++; + } + res.reserve(it - nodes.begin()); + std::transform(nodes.begin(), it, std::back_inserter(res), [](ts::Node node) { + return VariableDeclarator(node); + }); + return res; + } +} +auto VariableDeclaration::local() -> bool { + return _local; } // VariableDeclarator VariableDeclarator::VariableDeclarator(ts::Node node) : dec(node) { @@ -447,42 +482,10 @@ auto VariableDeclarator::var() -> std::variant std::vector { - return LocalVariableDeclarator(local_var_dec.named_child(0).value()).vars(); -} -auto LocalVariableDeclaration::declarations() -> std::vector { - std::vector nodes = local_var_dec.named_children(); - std::vector res; - res.reserve(nodes.size() - 1); - std::transform(nodes.begin() + 1, nodes.end(), std::back_inserter(res), [](ts::Node node) { - return Expression(node); - }); - return res; -} -// LocalVariableDeclarator -LocalVariableDeclarator::LocalVariableDeclarator(ts::Node node) : var_dec(node) { - if (node.type_id() != ts::NODE_LOCAL_VARIABLE_DECLARATOR) { - throw std::runtime_error("not a local_variable_declarator node"); - } -} -auto LocalVariableDeclarator::vars() -> std::vector { - std::vector nodes = var_dec.named_children(); - std::vector res; - res.reserve(nodes.size()); - std::transform(nodes.begin(), nodes.end(), std::back_inserter(res), [](ts::Node node) { - return Identifier(node); - }); - return res; -} //TableIndex TableIndex::TableIndex(ts::Node node) : table_index(node) { - if (node.type_id() != ts::NODE_TABLE_INDEX || node.named_child_count() != 2) { + assert(node.named_child_count()==2); + if (node.type_id() != ts::NODE_TABLE_INDEX) { throw std::runtime_error("not a table_index node"); } } @@ -501,7 +504,8 @@ DoStatement::DoStatement(ts::Node node) : do_statement(node) { auto DoStatement::body() -> Body { return Body(do_statement.named_children()); } // FieldExpression FieldExpression::FieldExpression(ts::Node node) : exp(node) { - if (node.type_id() != ts::NODE_FIELD_EXPRESSION || node.named_child_count() != 2) { + assert(node.named_child_count() == 2); + if (node.type_id() != ts::NODE_FIELD_EXPRESSION) { throw std::runtime_error("not a field_expression node"); } } @@ -509,14 +513,16 @@ auto FieldExpression::table_id() -> Prefix { return Prefix(exp.named_child(0).va auto FieldExpression::property_id() -> Identifier { return Identifier(exp.named_child(1).value()); } // Label Label::Label(ts::Node node) : label(node) { - if (node.type_id() != ts::NODE_LABEL_STATEMENT || node.named_child_count() < 1) { + assert(node.named_child_count()==1); + if (node.type_id() != ts::NODE_LABEL_STATEMENT) { throw std::runtime_error("not a label node"); } } auto Label::id() -> Identifier { return Identifier(label.named_child(0).value()); } // GoTo GoTo::GoTo(ts::Node node) : go_to(node) { - if (node.type_id() != ts::NODE_GOTO_STATEMENT || node.named_child_count() < 1) { + assert(node.named_child_count()==1); + if (node.type_id() != ts::NODE_GOTO_STATEMENT) { throw std::runtime_error("not a go_to node"); } } @@ -671,8 +677,8 @@ auto LocalFunctionStatement::body() -> Body { } // FunctionCall FunctionCall::FunctionCall(ts::Node node) : func_call(node) { - if (node.type_id() != ts::NODE_FUNCTION_CALL || node.named_child_count() < 2 || - node.named_child_count() > 3) { + assert(node.named_child_count()==2 || node.named_child_count()==3); + if (node.type_id() != ts::NODE_FUNCTION_CALL) { throw runtime_error("not a function_call node"); } } @@ -728,8 +734,8 @@ auto Table::fields() -> std::vector { } // Field Field::Field(ts::Node node) : field(node) { - if (node.type_id() != ts::NODE_FIELD || node.named_child_count() > 2 || - node.named_child_count() < 1) { + assert(node.named_child_count()==1 || node.named_child_count()==2); + if (node.type_id() != ts::NODE_FIELD) { throw runtime_error("not a field node"); } } @@ -804,7 +810,7 @@ auto Expression::options() -> std::variant< std::string str = exp.text(); return minilua::Value(String(std::string(str.begin() + 1, str.end() - 1))); } else if (exp.type_id() == ts::NODE_NUMBER) { - return minilua::Value(Number(stoi(exp.text()))); // TODO parse number and put into value + return parse_number_literal(exp.text()); } else if (exp.type_id() == ts::NODE_NIL) { return minilua::Value(Value::Type(Nil())); } else if (exp.type_id() == ts::NODE_TRUE) { @@ -840,15 +846,13 @@ Statement::Statement(ts::Node node) : statement(node) { } } auto Statement::options() -> std::variant< - VariableDeclaration, LocalVariableDeclaration, DoStatement, IfStatement, WhileStatement, + VariableDeclaration, DoStatement, IfStatement, WhileStatement, RepeatStatement, ForStatement, ForInStatement, GoTo, Break, Label, FunctionStatement, LocalFunctionStatement, FunctionCall, Expression> { if (statement.type_id() == ts::NODE_EXPRESSION) { return Expression(statement.named_child(0).value()); - } else if (statement.type_id() == ts::NODE_VARIABLE_DECLARATION) { + } else if (statement.type_id() == ts::NODE_VARIABLE_DECLARATION || statement.type_id() == ts::NODE_LOCAL_VARIABLE_DECLARATION) { return VariableDeclaration(statement); - } else if (statement.type_id() == ts::NODE_LOCAL_VARIABLE_DECLARATION) { - return LocalVariableDeclaration(statement); } else if (statement.type_id() == ts::NODE_DO_STATEMENT) { return DoStatement(statement); } else if (statement.type_id() == ts::NODE_IF_STATEMENT) { diff --git a/src/details/ast.hpp b/src/details/ast.hpp index 4eacccd7..c524542c 100644 --- a/src/details/ast.hpp +++ b/src/details/ast.hpp @@ -380,13 +380,18 @@ class VariableDeclarator { auto var() -> std::variant; }; /** - * class for variable_declaration nodes + * class for variable_declaration and local_variable_declaration nodes */ class VariableDeclaration { ts::Node var_dec; - + bool _local; public: VariableDeclaration(ts::Node node); + /** + * + * @return true if the declaration is local + */ + auto local() -> bool; /** * * @return a vector containing all variables declared by the varaible declaration @@ -399,33 +404,6 @@ class VariableDeclaration { */ auto declarations() -> std::vector; }; -/** - * class for local_variable_declarator nodes - */ -class LocalVariableDeclarator { - ts::Node var_dec; - -public: - LocalVariableDeclarator(ts::Node node); - auto vars() -> std::vector; -}; - -class LocalVariableDeclaration { - ts::Node local_var_dec; - -public: - LocalVariableDeclaration(ts::Node node); - /** - * this method gets all Identifiers of variables declared in this statement - * @return a vector with all Identifiers - */ - auto declarators() -> std::vector; - /** - * - * @return a vector with the expressions that get assigned to to the declaraed variables - */ - auto declarations() -> std::vector; -}; /** * class for field_expression nodes */ @@ -713,7 +691,7 @@ class Statement { * @return a variant containing the class this statement gets resolved to */ auto options() -> std::variant< - VariableDeclaration, LocalVariableDeclaration, DoStatement, IfStatement, WhileStatement, + VariableDeclaration, DoStatement, IfStatement, WhileStatement, RepeatStatement, ForStatement, ForInStatement, GoTo, Break, Label, FunctionStatement, LocalFunctionStatement, FunctionCall, Expression>; }; diff --git a/tests/tree_sitter_ast_tests.cpp b/tests/tree_sitter_ast_tests.cpp index 744d3b95..63752813 100644 --- a/tests/tree_sitter_ast_tests.cpp +++ b/tests/tree_sitter_ast_tests.cpp @@ -7,7 +7,6 @@ namespace minilua::details { TEST_CASE("statements", "[tree-sitter]") { ts::Parser parser; std::string source = "i,t,l = 5\n" - "local z = 42\n" "do\n" "z = i+k\n" "end\n" @@ -45,7 +44,7 @@ TEST_CASE("statements", "[tree-sitter]") { Body body = prog.body(); CHECK(!body.ret().has_value()); vector statement = body.statements(); - CHECK(statement.size() == 15); + CHECK(statement.size() == 14); long unsigned int statement_count = statement.size(); // this loop tests if each statement got parsed to the right Class for (long unsigned int i = 0; i < statement_count; i++) { @@ -592,6 +591,7 @@ TEST_CASE("var_dec_statements", "[tree-sitter]") { auto opt1 = stats[0].options(); CHECK(std::holds_alternative(opt1)); auto var_dec1 = std::get_if(&opt1); + CHECK(!var_dec1 -> local()); CHECK(var_dec1->declarations().size() == 1); CHECK(var_dec1->declarators().size() == 1); CHECK(std::holds_alternative(var_dec1->declarators()[0].var())); @@ -600,6 +600,7 @@ TEST_CASE("var_dec_statements", "[tree-sitter]") { auto opt2 = stats[1].options(); CHECK(std::holds_alternative(opt2)); auto var_dec2 = std::get_if(&opt2); + CHECK(!var_dec2 -> local()); CHECK(var_dec2->declarations().size() == 3); CHECK(var_dec2->declarators().size() == 4); for (uint i = 0; i < 4; i++) { @@ -610,30 +611,51 @@ TEST_CASE("var_dec_statements", "[tree-sitter]") { CHECK(std::holds_alternative(var_dec2->declarations()[2].options())); // 3rd statement auto opt3 = stats[2].options(); - CHECK(std::holds_alternative(opt3)); - auto var_dec3 = std::get_if(&opt3); + CHECK(std::holds_alternative(opt3)); + auto var_dec3 = std::get_if(&opt3); + CHECK(var_dec3->local()); CHECK(var_dec3->declarations().empty()); CHECK(var_dec3->declarators().size() == 1); - CHECK(var_dec3->declarators()[0].str() == "e"s); + CHECK(std::holds_alternative(var_dec3->declarators()[0].var())); + auto id1_opt = var_dec3->declarators()[0].var(); + auto id1 = std::get_if(&id1_opt); + CHECK(id1 -> str() == "e"s); // 4th statement auto opt4 = stats[3].options(); - CHECK(std::holds_alternative(opt4)); - auto var_dec4 = std::get_if(&opt4); + CHECK(std::holds_alternative(opt4)); + auto var_dec4 = std::get_if(&opt4); + CHECK(var_dec4->local()); CHECK(var_dec4->declarations().empty()); CHECK(var_dec4->declarators().size() == 3); - CHECK(var_dec4->declarators()[0].str() == "f"s); - CHECK(var_dec4->declarators()[1].str() == "g"s); - CHECK(var_dec4->declarators()[2].str() == "h"s); + CHECK(std::holds_alternative(var_dec4->declarators()[0].var())); + auto id2_opt = var_dec4->declarators()[0].var(); + auto id2 = std::get_if(&id2_opt); + CHECK(id2 -> str() == "f"s); + CHECK(std::holds_alternative(var_dec4->declarators()[1].var())); + auto id3_opt = var_dec4->declarators()[1].var(); + auto id3 = std::get_if(&id3_opt); + CHECK(id3 -> str() == "g"s); + CHECK(std::holds_alternative(var_dec4->declarators()[2].var())); + auto id4_opt = var_dec4->declarators()[2].var(); + auto id4 = std::get_if(&id4_opt); + CHECK(id4 -> str() == "h"s); // 5th statement auto opt5 = stats[4].options(); - CHECK(std::holds_alternative(opt5)); - auto var_dec5 = std::get_if(&opt5); + CHECK(std::holds_alternative(opt5)); + auto var_dec5 = std::get_if(&opt5); + CHECK(var_dec5->local()); CHECK(var_dec5->declarations().size() == 2); CHECK(var_dec5->declarators().size() == 2); CHECK(std::holds_alternative(var_dec5->declarations()[0].options())); CHECK(std::holds_alternative(var_dec5->declarations()[1].options())); - CHECK(var_dec5->declarators()[0].str() == "i"s); - CHECK(var_dec5->declarators()[1].str() == "j"s); + CHECK(std::holds_alternative(var_dec5->declarators()[0].var())); + auto id5_opt = var_dec5->declarators()[0].var(); + auto id5 = std::get_if(&id5_opt); + CHECK(id5 -> str() == "i"s); + CHECK(std::holds_alternative(var_dec5->declarators()[1].var())); + auto id6_opt = var_dec5->declarators()[1].var(); + auto id6 = std::get_if(&id6_opt); + CHECK(id6 -> str() == "j"s); // 6th statement auto opt6 = stats[5].options(); CHECK(std::holds_alternative(opt6)); @@ -672,8 +694,8 @@ TEST_CASE("var_dec_statements", "[tree-sitter]") { auto pref_dec1 = std::get_if(&pref1); auto pref_opt1 = pref_dec1->var(); CHECK(std::holds_alternative(pref_opt1)); - auto id1 = std::get_if(&pref_opt1); - CHECK(id1->str()=="table1"); + auto id7 = std::get_if(&pref_opt1); + CHECK(id7->str()=="table1"); auto index1_opt = ti1->index().options(); CHECK(std::holds_alternative(index1_opt)); auto index1 = std::get_if(&index1_opt); @@ -780,11 +802,3 @@ TEST_CASE("function_calls", "[tree-sitter]") { } } } // namespace minilua::details - -TEST_CASE("new_nodes", "[tree-sitter]") { - ts::Parser parser; - std::string source = "a[\"b\"] = 4+4\n" - "local d"; - ts::Tree tree = parser.parse_string(source); - ts::Node root = tree.root_node(); -} \ No newline at end of file From d5ab672da3c522cc5c970b054e67f917b398d12d Mon Sep 17 00:00:00 2001 From: CFU9 Date: Fri, 22 Jan 2021 13:44:18 +0100 Subject: [PATCH 16/17] minor change --- src/details/ast.cpp | 8 ++++---- src/details/ast.hpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/details/ast.cpp b/src/details/ast.cpp index 2d15af36..acc5f9f9 100644 --- a/src/details/ast.cpp +++ b/src/details/ast.cpp @@ -401,12 +401,12 @@ VariableDeclaration::VariableDeclaration(ts::Node node) : var_dec(node) { if (node.type_id() != ts::NODE_VARIABLE_DECLARATION && node.type_id() != ts::NODE_LOCAL_VARIABLE_DECLARATION) { throw std::runtime_error("not a variable_declaration node"); }else{ - _local = node.type_id() == ts::NODE_LOCAL_VARIABLE_DECLARATION; + local_dec = node.type_id() == ts::NODE_LOCAL_VARIABLE_DECLARATION; } } auto VariableDeclaration::declarations() -> std::vector { std::vector res; - if(_local){ + if(local_dec){ std::vector nodes = var_dec.named_children(); res.reserve(nodes.size() - 1); std::transform(nodes.begin() + 1, nodes.end(), std::back_inserter(res), [](ts::Node node) { @@ -427,7 +427,7 @@ auto VariableDeclaration::declarations() -> std::vector { } } auto VariableDeclaration::declarators() -> std::vector { - if(_local){ + if(local_dec){ std::vector nodes = var_dec.named_child(0).value().named_children(); std::vector res; res.reserve(nodes.size()); @@ -450,7 +450,7 @@ auto VariableDeclaration::declarators() -> std::vector { } } auto VariableDeclaration::local() -> bool { - return _local; + return local_dec; } // VariableDeclarator VariableDeclarator::VariableDeclarator(ts::Node node) : dec(node) { diff --git a/src/details/ast.hpp b/src/details/ast.hpp index c524542c..c213f754 100644 --- a/src/details/ast.hpp +++ b/src/details/ast.hpp @@ -384,7 +384,7 @@ class VariableDeclarator { */ class VariableDeclaration { ts::Node var_dec; - bool _local; + bool local_dec; public: VariableDeclaration(ts::Node node); /** From 982a3c2f2cfdd44c31d11e5b5e0991bea6171bea Mon Sep 17 00:00:00 2001 From: CFU9 Date: Fri, 22 Jan 2021 14:29:00 +0100 Subject: [PATCH 17/17] moved asserts to better positions --- src/details/ast.cpp | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/details/ast.cpp b/src/details/ast.cpp index acc5f9f9..79b6cd81 100644 --- a/src/details/ast.cpp +++ b/src/details/ast.cpp @@ -98,10 +98,10 @@ auto Program::body() -> Body { return Body(program.named_children()); } };*/ // BinaryOperation BinaryOperation::BinaryOperation(ts::Node node) : bin_op(node) { - assert(node.child_count() == 3); if (node.type_id() != ts::NODE_BINARY_OPERATION) { throw std::runtime_error("not a binary_operation node"); } + assert(node.child_count() == 3); } auto BinaryOperation::left() -> Expression { return Expression(bin_op.child(0).value()); } auto BinaryOperation::right() -> Expression { return Expression(bin_op.child(2).value()); } @@ -155,10 +155,10 @@ auto BinaryOperation::op() -> BinOpEnum { } // UnaryOperation UnaryOperation::UnaryOperation(ts::Node node) : un_op(node) { - assert(node.child_count() == 2); if (node.type_id() != ts::NODE_UNARY_OPERATION) { throw std::runtime_error("not an unary_operation node"); } + assert(node.child_count() == 2); } auto UnaryOperation::op() -> UnOpEnum { @@ -183,11 +183,11 @@ auto UnaryOperation::exp() -> Expression { return Expression(un_op.child(0).valu // ForStatement ForStatement::ForStatement(ts::Node node) : for_statement(node) { - assert(node.named_child(0).has_value() && - node.named_child(0).value().type_id() == ts::NODE_LOOP_EXPRESSION); if (node.type_id() != ts::NODE_FOR_STATEMENT) { throw std::runtime_error("not a for_statement node"); } + assert(node.named_child(0).has_value() && + node.named_child(0).value().type_id() == ts::NODE_LOOP_EXPRESSION); } auto ForStatement::body() -> Body { std::vector body = for_statement.named_children(); @@ -200,10 +200,10 @@ auto ForStatement::loop_exp() -> LoopExpression { } LoopExpression::LoopExpression(ts::Node node) : loop_exp(node) { - assert(node.named_child_count() == 3 || node.named_child_count() == 4); if (node.type_id() != ts::NODE_LOOP_EXPRESSION) { throw std::runtime_error("not a loop_expression node"); } + assert(node.named_child_count() == 3 || node.named_child_count() == 4); } auto LoopExpression::variable() -> Identifier { return Identifier(loop_exp.named_child(0).value()); @@ -224,10 +224,10 @@ auto LoopExpression::step() -> std::optional { } } InLoopExpression::InLoopExpression(ts::Node node) : loop_exp(node) { - assert(node.named_child_count()==2); if (node.type_id() != ts::NODE_LOOP_EXPRESSION) { throw std::runtime_error("not a in_loop_expression node"); } + assert(node.named_child_count()==2); } auto InLoopExpression::loop_exps() -> std::vector { std::vector children = loop_exp.named_child(1).value().named_children(); @@ -246,11 +246,11 @@ auto InLoopExpression::loop_vars() -> std::vector { } // ForInStatement ForInStatement::ForInStatement(ts::Node node) : for_in(node) { - assert(node.named_child(0).has_value() && - node.named_child(0)->type_id() == ts::NODE_LOOP_EXPRESSION); if (node.type_id() != ts::NODE_FOR_IN_STATEMENT) { throw std::runtime_error("not a for_in_statement node"); } + assert(node.named_child(0).has_value() && + node.named_child(0)->type_id() == ts::NODE_LOOP_EXPRESSION); } auto ForInStatement::loop_exp() -> InLoopExpression { return InLoopExpression(for_in.named_child(0).value()); @@ -262,11 +262,11 @@ auto ForInStatement::body() -> Body { } // WhileStatement WhileStatement::WhileStatement(ts::Node node) : while_statement(node) { - assert(node.named_child(0).has_value() && - node.named_child(0).value().type_id() == ts::NODE_CONDITION_EXPRESSION); if (node.type_id() != ts::NODE_WHILE_STATEMENT) { throw std::runtime_error("not a while_statement node"); } + assert(node.named_child(0).has_value() && + node.named_child(0).value().type_id() == ts::NODE_CONDITION_EXPRESSION); } auto WhileStatement::body() -> Body { @@ -278,11 +278,11 @@ auto WhileStatement::exit_cond() -> Expression { return Expression(while_statement.named_child(0).value().named_child(0).value()); } RepeatStatement::RepeatStatement(ts::Node node) : repeat_statement(node) { - assert(node.named_child_count()>=1 && (node.named_children().end() - 1)->type_id() == ts::NODE_CONDITION_EXPRESSION); if (node.type_id() != ts::NODE_REPEAT_STATEMENT) { throw std::runtime_error("not a repeat_statement node"); } + assert(node.named_child_count()>=1 && (node.named_children().end() - 1)->type_id() == ts::NODE_CONDITION_EXPRESSION); } auto RepeatStatement::body() -> Body { std::vector body = repeat_statement.named_children(); @@ -297,11 +297,11 @@ auto RepeatStatement::until_cond() -> Expression { } // If IfStatement::IfStatement(ts::Node node) : if_statement(node) { - assert(node.named_child(0).has_value() && - node.named_child(0).value().type_id() == ts::NODE_CONDITION_EXPRESSION); if (node.type_id() != ts::NODE_IF_STATEMENT) { throw std::runtime_error("not an if_statement node"); } + assert(node.named_child(0).has_value() && + node.named_child(0).value().type_id() == ts::NODE_CONDITION_EXPRESSION); } auto IfStatement::cond() -> Expression { return Expression(if_statement.named_child(0).value().named_child(0).value()); @@ -365,11 +365,11 @@ Else::Else(ts::Node node) : else_statement(node) { auto Else::body() -> Body { return Body(else_statement.named_children()); } // ElseIf ElseIf::ElseIf(ts::Node node) : else_if(node) { - assert(node.named_child(0).has_value() && - node.named_child(0).value().type_id() == ts::NODE_CONDITION_EXPRESSION); if (node.type_id() != ts::NODE_ELSEIF) { throw std::runtime_error("not a else_if node"); } + assert(node.named_child(0).has_value() && + node.named_child(0).value().type_id() == ts::NODE_CONDITION_EXPRESSION); } auto ElseIf::body() -> Body { std::vector body = else_if.named_children(); @@ -484,10 +484,10 @@ auto VariableDeclarator::var() -> std::variant Prefix { return Prefix(table_index.named_child(0).value()); @@ -504,27 +504,27 @@ DoStatement::DoStatement(ts::Node node) : do_statement(node) { auto DoStatement::body() -> Body { return Body(do_statement.named_children()); } // FieldExpression FieldExpression::FieldExpression(ts::Node node) : exp(node) { - assert(node.named_child_count() == 2); if (node.type_id() != ts::NODE_FIELD_EXPRESSION) { throw std::runtime_error("not a field_expression node"); } + assert(node.named_child_count() == 2); } auto FieldExpression::table_id() -> Prefix { return Prefix(exp.named_child(0).value()); } auto FieldExpression::property_id() -> Identifier { return Identifier(exp.named_child(1).value()); } // Label Label::Label(ts::Node node) : label(node) { - assert(node.named_child_count()==1); if (node.type_id() != ts::NODE_LABEL_STATEMENT) { throw std::runtime_error("not a label node"); } + assert(node.named_child_count()==1); } auto Label::id() -> Identifier { return Identifier(label.named_child(0).value()); } // GoTo GoTo::GoTo(ts::Node node) : go_to(node) { - assert(node.named_child_count()==1); if (node.type_id() != ts::NODE_GOTO_STATEMENT) { throw std::runtime_error("not a go_to node"); } + assert(node.named_child_count()==1); } auto GoTo::label() -> Identifier { return Identifier(go_to.named_child(0).value()); } // Parameters @@ -677,10 +677,10 @@ auto LocalFunctionStatement::body() -> Body { } // FunctionCall FunctionCall::FunctionCall(ts::Node node) : func_call(node) { - assert(node.named_child_count()==2 || node.named_child_count()==3); if (node.type_id() != ts::NODE_FUNCTION_CALL) { throw runtime_error("not a function_call node"); } + assert(node.named_child_count()==2 || node.named_child_count()==3); } auto FunctionCall::method() -> std::optional { if (func_call.named_child_count() == 3) { @@ -734,10 +734,10 @@ auto Table::fields() -> std::vector { } // Field Field::Field(ts::Node node) : field(node) { - assert(node.named_child_count()==1 || node.named_child_count()==2); if (node.type_id() != ts::NODE_FIELD) { throw runtime_error("not a field node"); } + assert(node.named_child_count()==1 || node.named_child_count()==2); } auto Field::content() -> std::variant< std::pair, std::pair, Expression> {