Preserving sequences
This commit is contained in:
parent
ea1dddaf26
commit
d60e2dfb38
@ -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 {
|
||||||
|
@ -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");
|
||||||
};
|
};
|
||||||
|
@ -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", {} })));
|
||||||
|
Loading…
Reference in New Issue
Block a user