Preserving sequences

This commit is contained in:
Robert Bendun 2022-06-20 06:20:24 +02:00
parent ea1dddaf26
commit d60e2dfb38
3 changed files with 92 additions and 58 deletions

View File

@ -78,7 +78,7 @@ Result<Ast> Parser::parse(std::string_view source, std::string_view filename)
Result<Ast> Parser::parse_sequence() Result<Ast> Parser::parse_sequence()
{ {
auto seq = Try(parse_many(*this, &Parser::parse_expression, Token::Type::Expression_Separator, At_Least::Zero)); 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<Ast> Parser::parse_expression() Result<Ast> Parser::parse_expression()
@ -283,14 +283,15 @@ Result<Ast> Parser::parse_atomic_expression()
} }
case Token::Type::Open_Paren: case Token::Type::Open_Paren:
{
consume(); consume();
return parse_expression().and_then([&](Ast ast) -> Result<Ast> { auto ast = Try(parse_sequence());
if (not expect(Token::Type::Close_Paren)) { if (not expect(Token::Type::Close_Paren)) {
unimplemented("Error handling of this code is not implemented yet"); unimplemented("Error handling of this code is not implemented yet");
} }
consume(); consume();
return ast; return ast;
}); }
default: default:
return Error { return Error {

View File

@ -129,6 +129,12 @@ suite intepreter_test = [] {
evaluates_to(Value::from(Number(42)), "var x = [i|i] 42; x"); 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") = [] { should("allow modifying declared variable") = [] {
evaluates_to(Value::from(Number(43)), "var x = 42; x = 43; 10; x"); evaluates_to(Value::from(Number(43)), "var x = 42; x = 43; 10; x");
}; };

View File

@ -10,7 +10,20 @@ void expect_ast(
{ {
auto result = Parser::parse(source, "test"); auto result = Parser::parse(source, "test");
expect(result.has_value(), sl) << "code was expect to parse, but had not"; 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 = [] { suite parser_test = [] {
@ -19,23 +32,23 @@ suite parser_test = [] {
}; };
"Literal parsing"_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 = [] { "Binary opreator parsing"_test = [] {
expect_ast("1 + 2", Ast::binary( expect_single_ast("1 + 2", Ast::binary(
Token { Token::Type::Operator, "+", {} }, Token { Token::Type::Operator, "+", {} },
Ast::literal({ Token::Type::Numeric, "1", {} }), Ast::literal({ Token::Type::Numeric, "1", {} }),
Ast::literal({ Token::Type::Numeric, "2", {} }) Ast::literal({ Token::Type::Numeric, "2", {} })
)); ));
expect_ast("100 * 200", Ast::binary( expect_single_ast("100 * 200", Ast::binary(
Token { Token::Type::Operator, "*", {} }, Token { Token::Type::Operator, "*", {} },
Ast::literal({ Token::Type::Numeric, "100", {} }), Ast::literal({ Token::Type::Numeric, "100", {} }),
Ast::literal({ Token::Type::Numeric, "200", {} }) 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, "+", {} }, Token { Token::Type::Operator, "+", {} },
Ast::literal({ Token::Type::Numeric, "101", {} }), Ast::literal({ Token::Type::Numeric, "101", {} }),
Ast::binary( Ast::binary(
@ -49,8 +62,8 @@ suite parser_test = [] {
// This test shouldn't be skipped since language will support precedense. // This test shouldn't be skipped since language will support precedense.
// It stays here as reminder that this feature should be implemented. // It stays here as reminder that this feature should be implemented.
skip / "Binary operator precedense"_test = [] { "Binary operator precedense"_test = [] {
expect_ast("101 * 202 + 303", Ast::binary( expect_single_ast("101 * 202 + 303", Ast::binary(
Token { Token::Type::Operator, "+", {} }, Token { Token::Type::Operator, "+", {} },
Ast::binary( Ast::binary(
Token { Token::Type::Operator, "*", {} }, Token { Token::Type::Operator, "*", {} },
@ -62,57 +75,67 @@ suite parser_test = [] {
}; };
"Grouping expressions in parentheses"_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, "*", {} }, Token { Token::Type::Operator, "*", {} },
Ast::binary( Ast::sequence({ Ast::binary(
Token { Token::Type::Operator, "+", {} }, Token { Token::Type::Operator, "+", {} },
Ast::literal({ Token::Type::Numeric, "101", {} }), Ast::literal({ Token::Type::Numeric, "101", {} }),
Ast::literal({ Token::Type::Numeric, "202", {} }) Ast::literal({ Token::Type::Numeric, "202", {} })
), )}),
Ast::literal({ Token::Type::Numeric, "303", {} }) 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, "*", {} }, Token { Token::Type::Operator, "*", {} },
Ast::literal({ Token::Type::Numeric, "101", {} }), Ast::literal({ Token::Type::Numeric, "101", {} }),
Ast::sequence({
Ast::binary( Ast::binary(
Token { Token::Type::Operator, "+", {} }, Token { Token::Type::Operator, "+", {} },
Ast::literal({ Token::Type::Numeric, "202", {} }), Ast::literal({ Token::Type::Numeric, "202", {} }),
Ast::literal({ Token::Type::Numeric, "303", {} }) Ast::literal({ Token::Type::Numeric, "303", {} })
) )
})
)); ));
}; };
"Explicit function call"_test = [] { "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::Symbol, "foo", {} }),
Ast::literal({ Token::Type::Numeric, "1", {} }), Ast::literal({ Token::Type::Numeric, "1", {} }),
Ast::literal({ Token::Type::Numeric, "2", {} }) Ast::literal({ Token::Type::Numeric, "2", {} })
})); }));
expect_ast("say (fib (n-1) + fib (n-2))", Ast::call({ 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::literal({ Token::Type::Symbol, "say", {} }),
Ast::sequence({
Ast::binary( Ast::binary(
{ Token::Type::Operator, "+", {} }, { Token::Type::Operator, "+", {} },
Ast::call({ Ast::call({
Ast::literal({ Token::Type::Symbol, "fib", {} }), Ast::literal({ Token::Type::Symbol, "fib", {} }),
Ast::sequence({
Ast::binary( Ast::binary(
{ Token::Type::Operator, "-", {} }, { Token::Type::Operator, "-", {} },
Ast::literal({ Token::Type::Symbol, "n", {} }), Ast::literal({ Token::Type::Symbol, "n", {} }),
Ast::literal({ Token::Type::Numeric, "1", {} }) Ast::literal({ Token::Type::Numeric, "1", {} })
) )
})
}), }),
Ast::call({ Ast::call({
Ast::literal({ Token::Type::Symbol, "fib", {} }), Ast::literal({ Token::Type::Symbol, "fib", {} }),
Ast::sequence({
Ast::binary( Ast::binary(
{ Token::Type::Operator, "-", {} }, { Token::Type::Operator, "-", {} },
Ast::literal({ Token::Type::Symbol, "n", {} }), Ast::literal({ Token::Type::Symbol, "n", {} }),
Ast::literal({ Token::Type::Numeric, "2", {} }) Ast::literal({ Token::Type::Numeric, "2", {} })
) )
}) })
})
) )
})
})); }));
}; };
};
"Sequence"_test = [] { "Sequence"_test = [] {
expect_ast("42; 101", Ast::sequence({ expect_ast("42; 101", Ast::sequence({
@ -133,15 +156,16 @@ suite parser_test = [] {
}; };
"Block"_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, "i", {} }),
Ast::literal({ Token::Type::Symbol, "j", {} }), Ast::literal({ Token::Type::Symbol, "j", {} }),
Ast::literal({ Token::Type::Symbol, "k", {} }) Ast::literal({ Token::Type::Symbol, "k", {} })
}))); })));
expect_ast("[ i j k | i + j + k ]", Ast::lambda({}, Ast::binary( expect_single_ast("[ i j k | i + j + k ]", Ast::lambda({}, Ast::sequence({
Ast::binary(
{ Token::Type::Operator, "+", {} }, { Token::Type::Operator, "+", {} },
Ast::literal({ Token::Type::Symbol, "i", {} }), Ast::literal({ Token::Type::Symbol, "i", {} }),
Ast::binary( Ast::binary(
@ -149,13 +173,16 @@ suite parser_test = [] {
Ast::literal({ Token::Type::Symbol, "j", {} }), Ast::literal({ Token::Type::Symbol, "j", {} }),
Ast::literal({ Token::Type::Symbol, "k", {} }) Ast::literal({ Token::Type::Symbol, "k", {} })
) )
), { )
})
, {
Ast::literal({ Token::Type::Symbol, "i", {} }), Ast::literal({ Token::Type::Symbol, "i", {} }),
Ast::literal({ Token::Type::Symbol, "j", {} }), Ast::literal({ Token::Type::Symbol, "j", {} }),
Ast::literal({ Token::Type::Symbol, "k", {} }) Ast::literal({ Token::Type::Symbol, "k", {} })
})); }));
expect_ast("[ i; j; k | i + j + k ]", Ast::lambda({}, Ast::binary( expect_single_ast("[ i; j; k | i + j + k ]", Ast::lambda({}, Ast::sequence({
Ast::binary(
{ Token::Type::Operator, "+", {} }, { Token::Type::Operator, "+", {} },
Ast::literal({ Token::Type::Symbol, "i", {} }), Ast::literal({ Token::Type::Symbol, "i", {} }),
Ast::binary( Ast::binary(
@ -163,18 +190,18 @@ suite parser_test = [] {
Ast::literal({ Token::Type::Symbol, "j", {} }), Ast::literal({ Token::Type::Symbol, "j", {} }),
Ast::literal({ Token::Type::Symbol, "k", {} }) Ast::literal({ Token::Type::Symbol, "k", {} })
) )
), { )}), {
Ast::literal({ Token::Type::Symbol, "i", {} }), Ast::literal({ Token::Type::Symbol, "i", {} }),
Ast::literal({ Token::Type::Symbol, "j", {} }), Ast::literal({ Token::Type::Symbol, "j", {} }),
Ast::literal({ Token::Type::Symbol, "k", {} }) 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 = [] { "Variable declarations"_test = [] {
should("Support variable declaration with assigment") = [] { 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::Symbol, "x", {} }) },
Ast::literal({ Token::Type::Numeric, "10", {} }))); Ast::literal({ Token::Type::Numeric, "10", {} })));