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 doxygen
cd doc; $(MAKE) html cd doc; $(MAKE) html
.PHONY: doc-open
doc-open: doc
xdg-open ./doc/build/html/index.html
bin/unit-tests: src/tests/*.cc $(Obj) bin/unit-tests: src/tests/*.cc $(Obj)
g++ $(CXXFLAGS) $(CPPFLAGS) -o $@ $^ 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)); 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 errors::unexpected_token(Token::Type expected, Token const& unexpected)
{ {
Error err; Error err;

View File

@ -289,11 +289,13 @@ struct Ast
// Named constructors of AST structure // Named constructors of AST structure
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);
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`
}; };
Type type; Type type;
@ -314,9 +316,10 @@ struct Parser
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_expression(); Result<Ast> parse_expression();
Result<Ast> parse_binary_operator(); Result<Ast> parse_infix_expression();
Result<Ast> parse_literal(); Result<Ast> parse_atomic_expression();
Result<Token> peek() const;
Result<Token::Type> peek_type() const; Result<Token::Type> peek_type() const;
Token consume(); Token consume();
@ -334,6 +337,7 @@ namespace errors
Error unrecognized_character(u32 invalid_character, Location location); Error unrecognized_character(u32 invalid_character, Location location);
Error unexpected_token(Token::Type expected, Token const& unexpected); Error unexpected_token(Token::Type expected, Token const& unexpected);
Error unexpected_token(Token const& unexpected);
Error unexpected_end_of_source(Location location); Error unexpected_end_of_source(Location location);
[[noreturn]] [[noreturn]]

View File

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