Function calls

This commit is contained in:
Robert Bendun 2022-05-10 15:25:17 +02:00
parent a25719c987
commit 555a35ecc0
5 changed files with 102 additions and 21 deletions

View File

@ -38,6 +38,10 @@ doc: Doxyfile src/*.cc src/*.hh
doxygen
cd doc; $(MAKE) html
.PHONY: doc-open
doc-open: doc
xdg-open ./doc/build/html/index.html
bin/unit-tests: src/tests/*.cc $(Obj)
g++ $(CXXFLAGS) $(CPPFLAGS) -o $@ $^

View File

@ -103,6 +103,15 @@ Error errors::unrecognized_character(u32 invalid_character, Location location)
return unrecognized_character(invalid_character).with(std::move(location));
}
Error errors::unexpected_token(Token const& unexpected)
{
Error err;
err.type = errors::Unexpected_Token_Type;
err.location = unexpected.location;
err.message = format("unexpected ", unexpected.type);
return err;
}
Error errors::unexpected_token(Token::Type expected, Token const& unexpected)
{
Error err;

View File

@ -289,11 +289,13 @@ struct Ast
// Named constructors of AST structure
static Ast literal(Token);
static Ast binary(Token, Ast lhs, Ast rhs);
static Ast call(std::vector<Ast> call);
enum class Type
{
Literal, // Compile time known constant like c or 1
Binary // Binary operator application like 1 + 2
Literal, // Compile time known constant like `c` or `1`
Binary, // Binary operator application like `1` + `2`
Call // Function call application like `print 42`
};
Type type;
@ -314,9 +316,10 @@ struct Parser
static Result<Ast> parse(std::string_view source, std::string_view filename);
Result<Ast> parse_expression();
Result<Ast> parse_binary_operator();
Result<Ast> parse_literal();
Result<Ast> parse_infix_expression();
Result<Ast> parse_atomic_expression();
Result<Token> peek() const;
Result<Token::Type> peek_type() const;
Token consume();
@ -334,6 +337,7 @@ namespace errors
Error unrecognized_character(u32 invalid_character, Location location);
Error unexpected_token(Token::Type expected, Token const& unexpected);
Error unexpected_token(Token const& unexpected);
Error unexpected_end_of_source(Location location);
[[noreturn]]

View File

@ -1,4 +1,5 @@
#include <musique.hh>
#include <iostream>
Result<Ast> Parser::parse(std::string_view source, std::string_view filename)
{
@ -25,26 +26,39 @@ Result<Ast> Parser::parse(std::string_view source, std::string_view filename)
Result<Ast> Parser::parse_expression()
{
return parse_binary_operator();
return parse_infix_expression();
}
Result<Ast> Parser::parse_binary_operator()
Result<Ast> Parser::parse_infix_expression()
{
return parse_literal().and_then([&](Ast lhs) -> tl::expected<Ast, Error> {
std::vector<Ast> atomics;
Result<Ast> expr;
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)) {
auto op = consume();
return parse_expression().map([&](Ast rhs) {
return Ast::binary(std::move(op), std::move(lhs), std::move(rhs));
});
} else {
return lhs;
}
});
return lhs;
}
Result<Ast> Parser::parse_literal()
Result<Ast> Parser::parse_atomic_expression()
{
switch (Try(peek_type())) {
case Token::Type::Symbol:
case Token::Type::Numeric:
return Ast::literal(consume());
@ -57,15 +71,22 @@ Result<Ast> Parser::parse_literal()
});
default:
unimplemented();
return peek().and_then([](auto const& token) -> tl::expected<Ast, Error> {
return tl::unexpected(errors::unexpected_token(token));
});
}
}
Result<Token> Parser::peek() const
{
return token_id >= tokens.size()
? errors::unexpected_end_of_source(tokens.back().location)
: Result<Token>(tokens[token_id]);
}
Result<Token::Type> Parser::peek_type() const
{
return token_id >= tokens.size()
? errors::unexpected_end_of_source(tokens.back().location)
: Result<Token::Type>(tokens[token_id].type);
return peek().map([](Token const& token) { return token.type; });
}
Token Parser::consume()
@ -105,6 +126,14 @@ Ast Ast::binary(Token token, Ast lhs, Ast rhs)
return ast;
}
Ast Ast::call(std::vector<Ast> call)
{
Ast ast;
ast.type = Type::Call;
ast.arguments = std::move(call);
return ast;
}
bool operator==(Ast const& lhs, Ast const& rhs)
{
if (lhs.type != rhs.type) {
@ -120,6 +149,10 @@ bool operator==(Ast const& lhs, Ast const& rhs)
&& lhs.token.source == rhs.token.source
&& lhs.arguments.size() == rhs.arguments.size()
&& std::equal(lhs.arguments.begin(), lhs.arguments.end(), rhs.arguments.begin());
case Ast::Type::Call:
return lhs.arguments.size() == rhs.arguments.size()
&& std::equal(lhs.arguments.begin(), lhs.arguments.end(), rhs.arguments.begin());
}
unreachable();

View File

@ -78,4 +78,35 @@ suite parser_test = [] {
)
));
};
"Explicit function call"_test = [] {
expect_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", {} }),
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", {} })
)
})
)
}));
};
};