diff --git a/src/parser.cc b/src/parser.cc index 3952929..5212fc7 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -78,7 +78,7 @@ Result Parser::parse(std::string_view source, std::string_view filename) Result Parser::parse_sequence() { auto seq = Try(parse_many(*this, &Parser::parse_expression, Token::Type::Expression_Separator, At_Least::Zero)); - return wrap_if_several(std::move(seq), Ast::sequence); + return Ast::sequence(std::move(seq)); } Result Parser::parse_expression() @@ -283,14 +283,15 @@ Result Parser::parse_atomic_expression() } case Token::Type::Open_Paren: - consume(); - return parse_expression().and_then([&](Ast ast) -> Result { + { + consume(); + auto ast = Try(parse_sequence()); if (not expect(Token::Type::Close_Paren)) { unimplemented("Error handling of this code is not implemented yet"); } consume(); return ast; - }); + } default: return Error { diff --git a/src/tests/interpreter.cc b/src/tests/interpreter.cc index fdfb32a..1e2b21d 100644 --- a/src/tests/interpreter.cc +++ b/src/tests/interpreter.cc @@ -129,6 +129,12 @@ suite intepreter_test = [] { evaluates_to(Value::from(Number(42)), "var x = [i|i] 42; x"); }; + // Added to explicitly test against bug + // Previously this test would return 10 + should("respect parens in block") = [] { + evaluates_to(Value::from(Number(42)), "[(10;42)].0"); + }; + should("allow modifying declared variable") = [] { evaluates_to(Value::from(Number(43)), "var x = 42; x = 43; 10; x"); }; diff --git a/src/tests/parser.cc b/src/tests/parser.cc index 34550c8..c501a6c 100644 --- a/src/tests/parser.cc +++ b/src/tests/parser.cc @@ -10,7 +10,20 @@ void expect_ast( { auto result = Parser::parse(source, "test"); expect(result.has_value(), sl) << "code was expect to parse, but had not"; - expect(eq(*result, expected)) << "parser yielded unexpected tree"; + expect(eq(*result, expected), sl) << "parser yielded unexpected tree"; +} + +void expect_single_ast( + std::string_view source, + Ast const& expected, + reflection::source_location sl = reflection::source_location::current()) +{ + auto result = Parser::parse(source, "test"); + expect(result.has_value(), sl) << "code was expect to parse, but had not"; + + expect(eq(result->type, Ast::Type::Sequence), sl) << "parsed does not yielded sequence"; + expect(not result->arguments.empty(), sl) << "parsed yielded empty sequence"; + expect(eq(result->arguments[0], expected), sl) << "parser yielded unexpected tree"; } suite parser_test = [] { @@ -19,23 +32,23 @@ suite parser_test = [] { }; "Literal parsing"_test = [] { - expect_ast("1", Ast::literal(Token { Token::Type::Numeric, "1", {} })); + expect_single_ast("1", Ast::literal(Token { Token::Type::Numeric, "1", {} })); }; "Binary opreator parsing"_test = [] { - expect_ast("1 + 2", Ast::binary( + expect_single_ast("1 + 2", Ast::binary( Token { Token::Type::Operator, "+", {} }, Ast::literal({ Token::Type::Numeric, "1", {} }), Ast::literal({ Token::Type::Numeric, "2", {} }) )); - expect_ast("100 * 200", Ast::binary( + expect_single_ast("100 * 200", Ast::binary( Token { Token::Type::Operator, "*", {} }, Ast::literal({ Token::Type::Numeric, "100", {} }), Ast::literal({ Token::Type::Numeric, "200", {} }) )); - expect_ast("101 + 202 * 303", Ast::binary( + expect_single_ast("101 + 202 * 303", Ast::binary( Token { Token::Type::Operator, "+", {} }, Ast::literal({ Token::Type::Numeric, "101", {} }), Ast::binary( @@ -49,8 +62,8 @@ suite parser_test = [] { // This test shouldn't be skipped since language will support precedense. // It stays here as reminder that this feature should be implemented. - skip / "Binary operator precedense"_test = [] { - expect_ast("101 * 202 + 303", Ast::binary( + "Binary operator precedense"_test = [] { + expect_single_ast("101 * 202 + 303", Ast::binary( Token { Token::Type::Operator, "+", {} }, Ast::binary( Token { Token::Type::Operator, "*", {} }, @@ -62,56 +75,66 @@ suite parser_test = [] { }; "Grouping expressions in parentheses"_test = [] { - expect_ast("(101 + 202) * 303", Ast::binary( + expect_single_ast("(101 + 202) * 303", Ast::binary( Token { Token::Type::Operator, "*", {} }, - Ast::binary( + Ast::sequence({ Ast::binary( Token { Token::Type::Operator, "+", {} }, Ast::literal({ Token::Type::Numeric, "101", {} }), Ast::literal({ Token::Type::Numeric, "202", {} }) - ), + )}), Ast::literal({ Token::Type::Numeric, "303", {} }) )); - expect_ast("101 * (202 + 303)", Ast::binary( + expect_single_ast("101 * (202 + 303)", Ast::binary( Token { Token::Type::Operator, "*", {} }, Ast::literal({ Token::Type::Numeric, "101", {} }), - Ast::binary( - Token { Token::Type::Operator, "+", {} }, - Ast::literal({ Token::Type::Numeric, "202", {} }), - Ast::literal({ Token::Type::Numeric, "303", {} }) - ) + Ast::sequence({ + Ast::binary( + Token { Token::Type::Operator, "+", {} }, + Ast::literal({ Token::Type::Numeric, "202", {} }), + Ast::literal({ Token::Type::Numeric, "303", {} }) + ) + }) )); }; "Explicit function call"_test = [] { - expect_ast("foo 1 2", Ast::call({ + expect_single_ast("foo 1 2", Ast::call({ Ast::literal({ Token::Type::Symbol, "foo", {} }), Ast::literal({ Token::Type::Numeric, "1", {} }), Ast::literal({ Token::Type::Numeric, "2", {} }) })); - expect_ast("say (fib (n-1) + fib (n-2))", Ast::call({ - Ast::literal({ Token::Type::Symbol, "say", {} }), - Ast::binary( - { Token::Type::Operator, "+", {} }, - Ast::call({ - Ast::literal({ Token::Type::Symbol, "fib", {} }), + should("Support function call with complicated expression") = [] { + expect_single_ast("say (fib (n-1) + fib (n-2))", Ast::call({ + Ast::literal({ Token::Type::Symbol, "say", {} }), + Ast::sequence({ Ast::binary( - { Token::Type::Operator, "-", {} }, - Ast::literal({ Token::Type::Symbol, "n", {} }), - Ast::literal({ Token::Type::Numeric, "1", {} }) - ) - }), - Ast::call({ - Ast::literal({ Token::Type::Symbol, "fib", {} }), - Ast::binary( - { Token::Type::Operator, "-", {} }, - Ast::literal({ Token::Type::Symbol, "n", {} }), - Ast::literal({ Token::Type::Numeric, "2", {} }) + { Token::Type::Operator, "+", {} }, + Ast::call({ + Ast::literal({ Token::Type::Symbol, "fib", {} }), + Ast::sequence({ + Ast::binary( + { Token::Type::Operator, "-", {} }, + Ast::literal({ Token::Type::Symbol, "n", {} }), + Ast::literal({ Token::Type::Numeric, "1", {} }) + ) + }) + }), + Ast::call({ + Ast::literal({ Token::Type::Symbol, "fib", {} }), + Ast::sequence({ + Ast::binary( + { Token::Type::Operator, "-", {} }, + Ast::literal({ Token::Type::Symbol, "n", {} }), + Ast::literal({ Token::Type::Numeric, "2", {} }) + ) + }) + }) ) }) - ) - })); + })); + }; }; "Sequence"_test = [] { @@ -133,48 +156,52 @@ suite parser_test = [] { }; "Block"_test = [] { - expect_ast("[]", Ast::block(Location{})); + expect_single_ast("[]", Ast::block(Location{})); - expect_ast("[ i; j; k ]", Ast::block({}, Ast::sequence({ + expect_single_ast("[ i; j; k ]", Ast::block({}, Ast::sequence({ Ast::literal({ Token::Type::Symbol, "i", {} }), Ast::literal({ Token::Type::Symbol, "j", {} }), Ast::literal({ Token::Type::Symbol, "k", {} }) }))); - expect_ast("[ i j k | i + j + k ]", Ast::lambda({}, Ast::binary( - { Token::Type::Operator, "+", {} }, - Ast::literal({ Token::Type::Symbol, "i", {} }), + expect_single_ast("[ i j k | i + j + k ]", Ast::lambda({}, Ast::sequence({ Ast::binary( { Token::Type::Operator, "+", {} }, - Ast::literal({ Token::Type::Symbol, "j", {} }), - Ast::literal({ Token::Type::Symbol, "k", {} }) - ) - ), { + Ast::literal({ Token::Type::Symbol, "i", {} }), + Ast::binary( + { Token::Type::Operator, "+", {} }, + Ast::literal({ Token::Type::Symbol, "j", {} }), + Ast::literal({ Token::Type::Symbol, "k", {} }) + ) + ) + }) + , { Ast::literal({ Token::Type::Symbol, "i", {} }), Ast::literal({ Token::Type::Symbol, "j", {} }), Ast::literal({ Token::Type::Symbol, "k", {} }) })); - expect_ast("[ i; j; k | i + j + k ]", Ast::lambda({}, Ast::binary( - { Token::Type::Operator, "+", {} }, - Ast::literal({ Token::Type::Symbol, "i", {} }), + expect_single_ast("[ i; j; k | i + j + k ]", Ast::lambda({}, Ast::sequence({ Ast::binary( { Token::Type::Operator, "+", {} }, - Ast::literal({ Token::Type::Symbol, "j", {} }), - Ast::literal({ Token::Type::Symbol, "k", {} }) - ) - ), { + Ast::literal({ Token::Type::Symbol, "i", {} }), + Ast::binary( + { Token::Type::Operator, "+", {} }, + Ast::literal({ Token::Type::Symbol, "j", {} }), + Ast::literal({ Token::Type::Symbol, "k", {} }) + ) + )}), { Ast::literal({ Token::Type::Symbol, "i", {} }), Ast::literal({ Token::Type::Symbol, "j", {} }), Ast::literal({ Token::Type::Symbol, "k", {} }) })); - expect_ast("[|1]", Ast::lambda({}, Ast::literal({ Token::Type::Numeric, "1", {} }), {})); + expect_single_ast("[|1]", Ast::lambda({}, Ast::sequence({ Ast::literal({ Token::Type::Numeric, "1", {} })}), {})); }; "Variable declarations"_test = [] { should("Support variable declaration with assigment") = [] { - expect_ast("var x = 10", Ast::variable_declaration( + expect_single_ast("var x = 10", Ast::variable_declaration( {}, { Ast::literal({ Token::Type::Symbol, "x", {} }) }, Ast::literal({ Token::Type::Numeric, "10", {} })));