diff --git a/src/language/ASTBuilder.cpp b/src/language/ASTBuilder.cpp index e8c81778fe53470bc1bf22185f1fde0f7a8a43d8..984ed5cba1f69098527296d196f966cf3d5918d5 100644 --- a/src/language/ASTBuilder.cpp +++ b/src/language/ASTBuilder.cpp @@ -201,60 +201,63 @@ struct ASTBuilder::simplify_stream_statement : parse_tree::apply<ASTBuilder::sim }; template <typename Rule> -using selector = - parse_tree::selector<Rule, - parse_tree::store_content::on<true_kw, - false_kw, - integer, - real, - literal, - name, - B_set, - N_set, - Z_set, - R_set, - string_type, - cout_kw, - cerr_kw, - clog_kw, - declaration, - if_statement, - do_while_statement, - while_statement, - for_statement, - break_kw, - continue_kw>, - ASTBuilder::rearrange::on<product, affectation, expression>, - ASTBuilder::simplify_unary::on<unary_minus, unary_plus, unary_not, unary_expression>, - parse_tree::remove_content::on<plus_op, - minus_op, - multiply_op, - divide_op, - lesser_op, - lesser_or_eq_op, - greater_op, - greater_or_eq_op, - eqeq_op, - not_eq_op, - and_op, - or_op, - xor_op, - eq_op, - multiplyeq_op, - divideeq_op, - pluseq_op, - minuseq_op, - unary_plusplus, - unary_minusminus, - post_minusminus, - post_plusplus>, - ASTBuilder::simplify_for_statement_block::on<for_statement_block>, - parse_tree::discard_empty::on<ignored, semicol, block>, - ASTBuilder::simplify_statement_block::on<statement_block>, - ASTBuilder::simplify_for_init::on<for_init>, - ASTBuilder::simplify_for_test::on<for_test>, - ASTBuilder::simplify_for_post::on<for_post>, - ASTBuilder::simplify_stream_statement::on<ostream_statement>>; +using selector = parse_tree::selector< + Rule, + parse_tree::store_content::on<true_kw, + false_kw, + integer, + real, + literal, + name, + B_set, + N_set, + Z_set, + R_set, + string_type, + cout_kw, + cerr_kw, + clog_kw, + declaration, + let_declaration, + function_domain_mapping, + function_definition, + if_statement, + do_while_statement, + while_statement, + for_statement, + break_kw, + continue_kw>, + ASTBuilder::rearrange::on<product, affectation, expression>, + ASTBuilder::simplify_unary::on<unary_minus, unary_plus, unary_not, function_evaluation, unary_expression>, + parse_tree::remove_content::on<plus_op, + minus_op, + multiply_op, + divide_op, + lesser_op, + lesser_or_eq_op, + greater_op, + greater_or_eq_op, + eqeq_op, + not_eq_op, + and_op, + or_op, + xor_op, + eq_op, + multiplyeq_op, + divideeq_op, + pluseq_op, + minuseq_op, + unary_plusplus, + unary_minusminus, + post_minusminus, + post_plusplus>, + ASTBuilder::simplify_for_statement_block::on<for_statement_block>, + parse_tree::discard_empty::on<ignored, semicol, block>, + ASTBuilder::simplify_statement_block::on<statement_block>, + ASTBuilder::simplify_for_init::on<for_init>, + ASTBuilder::simplify_for_test::on<for_test>, + ASTBuilder::simplify_for_post::on<for_post>, + ASTBuilder::simplify_stream_statement::on<ostream_statement>>; template <typename InputT> std::unique_ptr<ASTNode> diff --git a/src/language/ASTNodeDataType.cpp b/src/language/ASTNodeDataType.cpp index 855a3e04a0337f7bbc8cbe08ef17b1fd2aa2968a..1220df563cc9ec5685bc68dfaaa791062c086efb 100644 --- a/src/language/ASTNodeDataType.cpp +++ b/src/language/ASTNodeDataType.cpp @@ -26,6 +26,9 @@ dataTypeName(const ASTNodeDataType& data_type) case ASTNodeDataType::typename_t: name = "typename"; break; + case ASTNodeDataType::function_t: + name = "function"; + break; case ASTNodeDataType::void_t: name = "void"; break; diff --git a/src/language/ASTNodeDataType.hpp b/src/language/ASTNodeDataType.hpp index d6153c101347459c2958d9a816c4737969888d67..daabf0c0ec78ab9bf22c4f0dc52f1f20b78bcbf9 100644 --- a/src/language/ASTNodeDataType.hpp +++ b/src/language/ASTNodeDataType.hpp @@ -13,6 +13,7 @@ enum class ASTNodeDataType : int32_t double_t = 3, string_t = 5, typename_t = 10, + function_t = 11, void_t = std::numeric_limits<int32_t>::max() }; diff --git a/src/language/ASTNodeDataTypeBuilder.cpp b/src/language/ASTNodeDataTypeBuilder.cpp index 020e7baeddea0752916c9e24cf4fefb9385a8db4..cfdc0187c0564c9f73b022cac5bb84977d555ccc 100644 --- a/src/language/ASTNodeDataTypeBuilder.cpp +++ b/src/language/ASTNodeDataTypeBuilder.cpp @@ -51,6 +51,46 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) Assert(found); i_symbol->second.setDataType(data_type); n.m_data_type = data_type; + } else if (n.is<language::let_declaration>()) { + n.children[0]->m_data_type = ASTNodeDataType::function_t; + + n.children[1]->children[0]->m_data_type = ASTNodeDataType::typename_t; + n.children[1]->children[1]->m_data_type = ASTNodeDataType::typename_t; + + { // Function data type + const std::string& symbol = n.children[0]->string(); + + std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table; + + auto [i_symbol, found] = symbol_table->find(symbol, n.children[0]->begin()); + Assert(found); + i_symbol->second.setDataType(n.children[0]->m_data_type); + } + auto& type_node = *(n.children[1]->children[0]); + ASTNodeDataType data_type{ASTNodeDataType::undefined_t}; + if (type_node.is<language::B_set>()) { + data_type = ASTNodeDataType::bool_t; + } else if (type_node.is<language::Z_set>()) { + data_type = ASTNodeDataType::int_t; + } else if (type_node.is<language::N_set>()) { + data_type = ASTNodeDataType::unsigned_int_t; + } else if (type_node.is<language::R_set>()) { + data_type = ASTNodeDataType::double_t; + } else if (type_node.is<language::string_type>()) { + data_type = ASTNodeDataType::string_t; + } + + Assert(data_type != ASTNodeDataType::undefined_t); // LCOV_EXCL_LINE + + n.children[2]->children[0]->m_data_type = data_type; + const std::string& symbol = n.children[2]->children[0]->string(); + + std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table; + + auto [i_symbol, found] = symbol_table->find(symbol, n.children[2]->children[0]->begin()); + Assert(found); + i_symbol->second.setDataType(data_type); + n.m_data_type = ASTNodeDataType::void_t; } else if (n.is<language::name>()) { std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table; @@ -68,6 +108,8 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) } else if (n.is<language::eq_op>() or n.is<language::multiplyeq_op>() or n.is<language::divideeq_op>() or n.is<language::pluseq_op>() or n.is<language::minuseq_op>()) { n.m_data_type = n.children[0]->m_data_type; + } else if (n.is<language::function_domain_mapping>() or n.is<language::function_definition>()) { + n.m_data_type = ASTNodeDataType::void_t; } else if (n.is<language::for_post>() or n.is<language::for_init>() or n.is<language::for_statement_block>()) { n.m_data_type = ASTNodeDataType::void_t; } else if (n.is<language::for_test>()) { diff --git a/src/language/ASTNodeExpressionBuilder.cpp b/src/language/ASTNodeExpressionBuilder.cpp index e6dd686c6ee9db5104b343ecd2bdc5ebe8a3ef3d..f7157005e6d209fcc0ca23481285b3b83b5ac3aa 100644 --- a/src/language/ASTNodeExpressionBuilder.cpp +++ b/src/language/ASTNodeExpressionBuilder.cpp @@ -27,6 +27,11 @@ ASTNodeExpressionBuilder::_buildExpression(ASTNode& n) n.is<language::pluseq_op>() or n.is<language::minuseq_op>())) { ASTNodeAffectationExpressionBuilder{n}; + } else if (n.is<language::let_declaration>()) { + std::cerr << rang::fgB::red << "\"Let expression\" is not defined correctly" << rang::style::reset << '\n'; + n.m_node_processor = std::make_unique<FakeProcessor>(); + return; + } else if (n.is<language::real>()) { n.m_node_processor = std::make_unique<FakeProcessor>(); } else if (n.is<language::integer>()) { diff --git a/src/language/ASTSymbolInitializationChecker.cpp b/src/language/ASTSymbolInitializationChecker.cpp index 06b0e9975b53b48bb943f4de5d2cacb98ff493af..1c75f86a46a3dd868d582e2e421c4b2a6a5cc638 100644 --- a/src/language/ASTSymbolInitializationChecker.cpp +++ b/src/language/ASTSymbolInitializationChecker.cpp @@ -15,6 +15,20 @@ ASTSymbolInitializationChecker::_checkSymbolInitialization(ASTNode& node) this->_checkSymbolInitialization(*node.children[2]); i_symbol->second.setIsInitialized(); } + } else if (node.is<language::let_declaration>()) { + const std::string& symbol = node.children[0]->string(); + auto [i_symbol, found] = node.m_symbol_table->find(symbol, node.children[0]->begin()); + Assert(found, "unexpected error, should have been detected through declaration checking"); + if (node.children.size() == 3) { + this->_checkSymbolInitialization(*node.children[2]); + i_symbol->second.setIsInitialized(); + } + } else if (node.is<language::function_definition>()) { + const std::string& symbol = node.children[0]->string(); + auto [i_symbol, found] = node.m_symbol_table->find(symbol, node.children[0]->begin()); + Assert(found, "unexpected error, should have been detected through declaration checking"); + i_symbol->second.setIsInitialized(); + this->_checkSymbolInitialization(*node.children[1]); } else if (node.is<language::eq_op>()) { // first checks for right hand side this->_checkSymbolInitialization(*node.children[1]); diff --git a/src/language/ASTSymbolTableBuilder.cpp b/src/language/ASTSymbolTableBuilder.cpp index 5fadaf4e0cdd585a3a1e1a2adc9d0a077d24a34d..0d3c082326d037c801e7ea5391816087c11dd695 100644 --- a/src/language/ASTSymbolTableBuilder.cpp +++ b/src/language/ASTSymbolTableBuilder.cpp @@ -25,6 +25,22 @@ ASTSymbolTableBuilder::buildSymbolTable(ASTNode& n, std::shared_ptr<SymbolTable> error_message << "symbol '" << rang::fg::red << symbol << rang::fg::reset << '\'' << " was already defined!"; throw parse_error(error_message.str(), std::vector{n.begin()}); } + } else if (n.is<language::let_declaration>()) { + const std::string& symbol = n.children[0]->string(); + auto [i_symbol, success] = symbol_table->add(symbol, n.children[0]->begin()); + if (not success) { + std::ostringstream error_message; + error_message << "symbol '" << rang::fg::red << symbol << rang::fg::reset << '\'' << " was already defined!"; + throw parse_error(error_message.str(), std::vector{n.begin()}); + } + } else if (n.is<language::function_definition>()) { + const std::string& symbol = n.children[0]->string(); + auto [i_symbol, success] = symbol_table->add(symbol, n.children[0]->begin()); + if (not success) { + std::ostringstream error_message; + error_message << "symbol '" << rang::fg::red << symbol << rang::fg::reset << '\'' << " was already defined!"; + throw parse_error(error_message.str(), std::vector{n.begin()}); + } } else if (n.is<language::name>()) { auto [i_symbol, found] = symbol_table->find(n.string(), n.begin()); if (not found) { diff --git a/src/language/PEGGrammar.hpp b/src/language/PEGGrammar.hpp index 0c308405d92b25c785e59e93428fe51268a526bc..3a8eda150e722ef607106065adb580a162eab7ea 100644 --- a/src/language/PEGGrammar.hpp +++ b/src/language/PEGGrammar.hpp @@ -56,8 +56,6 @@ struct literal : if_must< one< '"' >, until< one< '"' >, character > > {}; struct LITERAL : seq< literal, ignored >{}; -struct semicol : one< ';' >{}; - struct REAL : seq< real, ignored >{}; struct B_set : one< 'B' >{}; @@ -82,6 +80,9 @@ struct false_kw : TAO_PEGTL_KEYWORD("false") {}; struct BOOL : seq< sor<true_kw, false_kw>, ignored > {}; +struct let_kw : TAO_PEGTL_KEYWORD("let") {}; +struct LET : seq < let_kw, ignored > {}; + struct do_kw : TAO_PEGTL_KEYWORD("do") {}; struct DO : seq < do_kw, ignored > {}; @@ -109,18 +110,30 @@ struct clog_kw : TAO_PEGTL_KEYWORD("clog") {}; struct keywork : sor < basic_type, true_kw, false_kw, do_kw, while_kw, for_kw, if_kw, else_kw, and_kw, or_kw, xor_kw, break_kw, continue_kw, cout_kw, cerr_kw, clog_kw > {}; -struct name : minus< identifier, keywork > {}; +struct name : minus< identifier, keywork > {}; struct NAME : seq < name, ignored > {}; +struct right_arrow_kw : seq< one< '-' >, one< '>' > > {}; +struct RIGHT_ARROW : seq< right_arrow_kw, ignored > {}; + +struct semicol : one< ';' > {}; struct SEMICOL : seq< semicol , ignored > {}; +struct column : one< ':' > {}; +struct COLUMN : seq< column , ignored > {}; + +struct comma : one< ',' > {}; +struct COMMA : seq< comma , ignored > {}; + struct open_parent : seq< one< '(' >, ignored > {}; struct close_parent : seq< one< ')' >, ignored > {}; struct expression; struct parented_expression : if_must< open_parent, expression, close_parent > {}; -struct primary_expression : sor< BOOL, REAL, INTEGER, LITERAL, NAME, parented_expression > {}; +struct function_evaluation : seq< NAME, parented_expression > {}; + +struct primary_expression : sor< BOOL, REAL, INTEGER, LITERAL, function_evaluation, NAME, parented_expression > {}; struct unary_plusplus : TAO_PEGTL_STRING("++") {}; struct unary_minusminus : TAO_PEGTL_STRING("--") {}; @@ -188,7 +201,12 @@ struct affect_op : sor< eq_op, multiplyeq_op, divideeq_op, pluseq_op, minuseq_op struct affectation : seq< NAME , if_must< affect_op, expression > >{}; -struct declaration : if_must<TYPESPECIFIER, NAME, opt<if_must<seq<one<'='>,ignored>, expression>> >{}; +struct declaration : if_must< TYPESPECIFIER, NAME, opt< if_must< seq< one< '=' >, ignored >, expression > > >{}; + +struct function_domain_mapping : seq< TYPESPECIFIER, RIGHT_ARROW, TYPESPECIFIER >{}; +struct function_definition : seq< NAME, RIGHT_ARROW, expression >{}; + +struct let_declaration : if_must< LET, NAME, COLUMN, function_domain_mapping, COMMA, function_definition >{}; struct open_brace : seq< one< '{' >, ignored >{}; struct close_brace : seq< one< '}' >, ignored >{}; @@ -198,7 +216,7 @@ struct instruction_list; struct braced_instruction_list : sor<try_catch< open_brace, instruction_list, close_brace >, // non matching braces management - if_must< at< one< '{' > >, raise<open_brace>, until<eof> > >{}; + if_must< at< one< '{' > >, raise< open_brace >, until< eof > > >{}; struct block : braced_instruction_list {}; @@ -222,7 +240,8 @@ struct ostream_object : seq< sor< cout_kw, cerr_kw, clog_kw >, ignored >{}; struct ostream_statement : seq< ostream_object, star< if_must< shift_left_op, expression, ignored > > >{}; struct instruction - : sor<if_must< declaration, semicol >, + : sor<if_must< let_declaration, semicol >, + if_must< declaration, semicol >, if_must< affectation, semicol >, if_statement, if_must<do_while_statement, semicol>, diff --git a/src/language/PugsParser.cpp b/src/language/PugsParser.cpp index 3c5b8ec4c86774f2071dfd9dde552d1d14ec5cc2..13c16e22362cd19bde2f883fe4738295d7363511 100644 --- a/src/language/PugsParser.cpp +++ b/src/language/PugsParser.cpp @@ -56,6 +56,7 @@ parser(const std::string& filename) ASTSymbolInitializationChecker{*root_node}; + ASTNodeDataTypeBuilder{*root_node}; { std::string dot_filename{"parse_tree.dot"}; std::ofstream fout(dot_filename); @@ -64,7 +65,6 @@ parser(const std::string& filename) std::cout << " AST dot file: " << dot_filename << '\n'; } - ASTNodeDataTypeBuilder{*root_node}; ASTNodeDataTypeChecker{*root_node}; ASTNodeValueBuilder{*root_node};