Expression sequencing
This commit is contained in:
parent
b4cd87eea1
commit
c5260df41c
@ -290,12 +290,14 @@ struct Ast
|
|||||||
static Ast literal(Token);
|
static Ast literal(Token);
|
||||||
static Ast binary(Token, Ast lhs, Ast rhs);
|
static Ast binary(Token, Ast lhs, Ast rhs);
|
||||||
static Ast call(std::vector<Ast> call);
|
static Ast call(std::vector<Ast> call);
|
||||||
|
static Ast sequence(std::vector<Ast> call);
|
||||||
|
|
||||||
enum class Type
|
enum class Type
|
||||||
{
|
{
|
||||||
Literal, // Compile time known constant like `c` or `1`
|
Literal, // Compile time known constant like `c` or `1`
|
||||||
Binary, // Binary operator application like `1` + `2`
|
Binary, // Binary operator application like `1` + `2`
|
||||||
Call // Function call application like `print 42`
|
Call, // Function call application like `print 42`
|
||||||
|
Sequence, // Several expressions sequences like `42`, `42; 32`
|
||||||
};
|
};
|
||||||
|
|
||||||
Type type;
|
Type type;
|
||||||
@ -315,6 +317,7 @@ struct Parser
|
|||||||
// using Parser structure internally
|
// using Parser structure internally
|
||||||
static Result<Ast> parse(std::string_view source, std::string_view filename);
|
static Result<Ast> parse(std::string_view source, std::string_view filename);
|
||||||
|
|
||||||
|
Result<Ast> parse_sequence();
|
||||||
Result<Ast> parse_expression();
|
Result<Ast> parse_expression();
|
||||||
Result<Ast> parse_infix_expression();
|
Result<Ast> parse_infix_expression();
|
||||||
Result<Ast> parse_atomic_expression();
|
Result<Ast> parse_atomic_expression();
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#include <musique.hh>
|
#include <musique.hh>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
static Ast wrap_if_several(std::vector<Ast> &&ast, Ast(*wrapper)(std::vector<Ast>));
|
||||||
|
static Result<std::vector<Ast>> parse_one_or_more(Parser &p, Result<Ast> (Parser::*parser)(), std::optional<Token::Type> separator = std::nullopt);
|
||||||
|
|
||||||
Result<Ast> Parser::parse(std::string_view source, std::string_view filename)
|
Result<Ast> Parser::parse(std::string_view source, std::string_view filename)
|
||||||
{
|
{
|
||||||
Lexer lexer{source};
|
Lexer lexer{source};
|
||||||
@ -15,7 +18,7 @@ Result<Ast> Parser::parse(std::string_view source, std::string_view filename)
|
|||||||
return std::move(maybe_token).error();
|
return std::move(maybe_token).error();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const result = parser.parse_expression();
|
auto const result = parser.parse_sequence();
|
||||||
|
|
||||||
if (parser.token_id < parser.tokens.size()) {
|
if (parser.token_id < parser.tokens.size()) {
|
||||||
errors::all_tokens_were_not_parsed(std::span(parser.tokens).subspan(parser.token_id));
|
errors::all_tokens_were_not_parsed(std::span(parser.tokens).subspan(parser.token_id));
|
||||||
@ -24,6 +27,12 @@ Result<Ast> Parser::parse(std::string_view source, std::string_view filename)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<Ast> Parser::parse_sequence()
|
||||||
|
{
|
||||||
|
auto seq = Try(parse_one_or_more(*this, &Parser::parse_expression, Token::Type::Expression_Separator));
|
||||||
|
return wrap_if_several(std::move(seq), Ast::sequence);
|
||||||
|
}
|
||||||
|
|
||||||
Result<Ast> Parser::parse_expression()
|
Result<Ast> Parser::parse_expression()
|
||||||
{
|
{
|
||||||
return parse_infix_expression();
|
return parse_infix_expression();
|
||||||
@ -31,19 +40,8 @@ Result<Ast> Parser::parse_expression()
|
|||||||
|
|
||||||
Result<Ast> Parser::parse_infix_expression()
|
Result<Ast> Parser::parse_infix_expression()
|
||||||
{
|
{
|
||||||
std::vector<Ast> atomics;
|
auto atomics = Try(parse_one_or_more(*this, &Parser::parse_atomic_expression));
|
||||||
Result<Ast> expr;
|
auto lhs = wrap_if_several(std::move(atomics), Ast::call);
|
||||||
while ((expr = parse_atomic_expression()).has_value()) {
|
|
||||||
atomics.push_back(std::move(expr).value());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (atomics.empty()) {
|
|
||||||
return expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lhs = atomics.size() == 1
|
|
||||||
? std::move(atomics[0])
|
|
||||||
: Ast::call(std::move(atomics));
|
|
||||||
|
|
||||||
if (expect(Token::Type::Operator)) {
|
if (expect(Token::Type::Operator)) {
|
||||||
auto op = consume();
|
auto op = consume();
|
||||||
@ -77,6 +75,27 @@ Result<Ast> Parser::parse_atomic_expression()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<std::vector<Ast>> parse_one_or_more(Parser &p, Result<Ast> (Parser::*parser)(), std::optional<Token::Type> separator)
|
||||||
|
{
|
||||||
|
std::vector<Ast> trees;
|
||||||
|
Result<Ast> expr;
|
||||||
|
while ((expr = (p.*parser)()).has_value()) {
|
||||||
|
trees.push_back(std::move(expr).value());
|
||||||
|
if (separator) {
|
||||||
|
if (auto s = p.ensure(*separator); !s.has_value()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
do p.consume(); while (p.expect(*separator));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trees.empty()) {
|
||||||
|
return expr.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
return trees;
|
||||||
|
}
|
||||||
|
|
||||||
Result<Token> Parser::peek() const
|
Result<Token> Parser::peek() const
|
||||||
{
|
{
|
||||||
return token_id >= tokens.size()
|
return token_id >= tokens.size()
|
||||||
@ -134,6 +153,21 @@ Ast Ast::call(std::vector<Ast> call)
|
|||||||
return ast;
|
return ast;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ast Ast::sequence(std::vector<Ast> expressions)
|
||||||
|
{
|
||||||
|
Ast ast;
|
||||||
|
ast.type = Type::Sequence;
|
||||||
|
ast.arguments = std::move(expressions);
|
||||||
|
return ast;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ast wrap_if_several(std::vector<Ast> &&ast, Ast(*wrapper)(std::vector<Ast>))
|
||||||
|
{
|
||||||
|
if (ast.size() == 1)
|
||||||
|
return std::move(ast)[0];
|
||||||
|
return wrapper(std::move(ast));
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(Ast const& lhs, Ast const& rhs)
|
bool operator==(Ast const& lhs, Ast const& rhs)
|
||||||
{
|
{
|
||||||
if (lhs.type != rhs.type) {
|
if (lhs.type != rhs.type) {
|
||||||
@ -151,6 +185,7 @@ bool operator==(Ast const& lhs, Ast const& rhs)
|
|||||||
&& std::equal(lhs.arguments.begin(), lhs.arguments.end(), rhs.arguments.begin());
|
&& std::equal(lhs.arguments.begin(), lhs.arguments.end(), rhs.arguments.begin());
|
||||||
|
|
||||||
case Ast::Type::Call:
|
case Ast::Type::Call:
|
||||||
|
case Ast::Type::Sequence:
|
||||||
return lhs.arguments.size() == rhs.arguments.size()
|
return lhs.arguments.size() == rhs.arguments.size()
|
||||||
&& std::equal(lhs.arguments.begin(), lhs.arguments.end(), rhs.arguments.begin());
|
&& std::equal(lhs.arguments.begin(), lhs.arguments.end(), rhs.arguments.begin());
|
||||||
}
|
}
|
||||||
|
@ -109,4 +109,22 @@ suite parser_test = [] {
|
|||||||
)
|
)
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"Sequence"_test = [] {
|
||||||
|
expect_ast("42; 101", Ast::sequence({
|
||||||
|
Ast::literal({ Token::Type::Numeric, "42", {} }),
|
||||||
|
Ast::literal({ Token::Type::Numeric, "101", {} })
|
||||||
|
}));
|
||||||
|
|
||||||
|
expect_ast("say hello; say world", Ast::sequence({
|
||||||
|
Ast::call({
|
||||||
|
Ast::literal({ Token::Type::Symbol, "say", {} }),
|
||||||
|
Ast::literal({ Token::Type::Symbol, "hello", {} })
|
||||||
|
}),
|
||||||
|
Ast::call({
|
||||||
|
Ast::literal({ Token::Type::Symbol, "say", {} }),
|
||||||
|
Ast::literal({ Token::Type::Symbol, "world", {} })
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user