diff --git a/furc/include/furc/ast/expression.hpp b/furc/include/furc/ast/expression.hpp index 8b73b3a..6cb9349 100644 --- a/furc/include/furc/ast/expression.hpp +++ b/furc/include/furc/ast/expression.hpp @@ -11,6 +11,7 @@ enum class expression_node_t { Literal, Unaryop, Binop, + Paren, }; class expression_node : public statement_node { @@ -50,6 +51,8 @@ public: expression_node_t expression_type() const override { return expression_node_t::Unaryop; } std::ostream& print(std::ostream& os) const override; +protected: + bool equal(const node& rhs) const override; private: unaryop_expression_node_t m_type; expression_node_h m_node; @@ -91,6 +94,26 @@ private: using binop_expression_node_h = node_handle; +class paren_expression_node : public expression_node { +public: + paren_expression_node(expression_node_h&& node) + : m_node(std::move(node)) {} + + const expression_node_h& get_node() const { return m_node; } + expression_node_h& get_node() { return m_node; } + expression_node_h&& move_node() { return std::move(m_node); } +public: + expression_node_t expression_type() const override { return expression_node_t::Paren; } + + std::ostream& print(std::ostream& os) const override; +protected: + bool equal(const node& rhs) const override; +private: + expression_node_h m_node; +}; + +using paren_expression_node_h = node_handle; + } // namespace ast } // namespace furc diff --git a/furc/include/furc/front/parser.hpp b/furc/include/furc/front/parser.hpp index f7f59c6..83987a9 100644 --- a/furc/include/furc/front/parser.hpp +++ b/furc/include/furc/front/parser.hpp @@ -29,7 +29,7 @@ public: private: ast::declaration_node_h parse_declaration(); ast::statement_node_h parse_statement(); - ast::expression_node_h parse_expression(); + ast::expression_node_h parse_expression(std::uint32_t precedence = 16); ast::literal_node_h parse_literal(); ast::expression_node_h parse_expression_primary(); diff --git a/furc/src/ast.cpp b/furc/src/ast.cpp index 14d7b8d..cf948f5 100644 --- a/furc/src/ast.cpp +++ b/furc/src/ast.cpp @@ -58,6 +58,11 @@ std::ostream& unaryop_expression_node::print(std::ostream& os) const { return os; } +bool unaryop_expression_node::equal(const node& rhsNode) const { + const auto& rhs = reinterpret_cast(rhsNode); + return expression_node::equal(rhsNode) && m_type == rhs.m_type && m_node == rhs.m_node; +} + std::ostream& operator<<(std::ostream& os, binop_expression_node_t type) { switch (type) { case binop_expression_node_t::Add: return os << '+'; @@ -77,6 +82,15 @@ bool binop_expression_node::equal(const node& rhsNode) const { return expression_node::equal(rhsNode) && m_type == rhs.m_type && m_lhs == rhs.m_lhs && m_rhs == rhs.m_rhs; } +std::ostream& paren_expression_node::print(std::ostream& os) const { + return os << *m_node; +} + +bool paren_expression_node::equal(const node& rhsNode) const { + const auto& rhs = reinterpret_cast(rhsNode); + return expression_node::equal(rhsNode) && m_node == rhs.m_node; +} + bool declaration_node::equal(const node& rhs) const { return declaration_type() == reinterpret_cast(rhs).declaration_type(); } diff --git a/furc/src/front/parser.cpp b/furc/src/front/parser.cpp index a2141f0..92f5f8a 100644 --- a/furc/src/front/parser.cpp +++ b/furc/src/front/parser.cpp @@ -118,8 +118,8 @@ ast::statement_node_h parser::parse_statement() { return { token.location(), "unexpected token "s + token->type + ", expected statement, declaration or expression" }; } -ast::expression_node_h parser::parse_expression() { - return parse_expression_rhs(parse_expression_unary(16), 16); +ast::expression_node_h parser::parse_expression(std::uint32_t precedence) { + return parse_expression_rhs(parse_expression_unary(precedence), precedence); } ast::literal_node_h parser::parse_literal() { @@ -145,10 +145,20 @@ ast::literal_node_h parser::parse_literal() { ast::expression_node_h parser::parse_expression_primary() { const auto& tok = peek_token(); - - auto literal = parse_literal(); - if (literal.present()) return std::move(literal); - return { tok.location(), "unexpected token"s + tok->type + ", expected expression or literal" }; + switch (tok->type) { + case token_t::Lparen: { + auto tok = next_token(); + auto node = parse_expression(); + auto err = eat_token(token_t::Rparen); + if (err.has_error()) return err; + return ast::paren_expression_node_h{ tok.location(), m_arena, std::move(node) }; + } + default: { + auto literal = parse_literal(); + if (literal.present()) return std::move(literal); + return { tok.location(), "unexpected token"s + tok->type + ", expected expression or literal" }; + } + } } struct unaryop_info { diff --git a/furc/src/main.cpp b/furc/src/main.cpp index f89b5ed..9fa2732 100644 --- a/furc/src/main.cpp +++ b/furc/src/main.cpp @@ -5,7 +5,7 @@ #include int main(void) { - furc::front::parser parser("", "func main() {\n return 6 - -7 * 9++;\n}"); + furc::front::parser parser("", "func main() {\n return (6 - -7) * 9++;\n}"); std::cout << parser.parse() << '\n'; return 0; diff --git a/furc/test/parser.cpp b/furc/test/parser.cpp index ec098f9..2f72008 100644 --- a/furc/test/parser.cpp +++ b/furc/test/parser.cpp @@ -180,4 +180,33 @@ TEST(Parser, UnaryOperator_PrePost) { EXPECT_INTLIT(dec->get_node(), 5); } +TEST(Parser, Paren) { + parser parser("", "func main() { return --(5++); }"); + auto program = parser.parse(); + EXPECT_TRUE(program.present()); + EXPECT_EQ(program->declarations().size(), 1); + auto func = program->declarations()[0]; + EXPECT_TRUE(func.present()); + EXPECT_EQ(func->declaration_type(), declaration_node_t::FunctionDefinition); + function_definition_node_h funcDef = func; + EXPECT_EQ(funcDef->name()->string, "main"); + EXPECT_EQ(funcDef->body()->statements.size(), 1); + return_statement_node_h ret = funcDef->body()->statements[0]; + + auto retVal = ret->value(); + EXPECT_TRUE(retVal.present()); + + EXPECT_EQ(retVal->expression_type(), expression_node_t::Unaryop); + unaryop_expression_node_h dec = retVal; + EXPECT_EQ(dec->type(), unaryop_expression_node_t::PrefixDecrement); + + EXPECT_EQ(dec->get_node()->expression_type(), expression_node_t::Paren); + paren_expression_node_h paren = dec->get_node(); + + EXPECT_EQ(paren->get_node()->expression_type(), expression_node_t::Unaryop); + unaryop_expression_node_h inc = paren->get_node(); + EXPECT_EQ(inc->type(), unaryop_expression_node_t::PostfixIncrement); + EXPECT_INTLIT(inc->get_node(), 5); +} + } // namespace \ No newline at end of file