Separated blocks from lambdas

This commit is contained in:
Robert Bendun 2022-05-17 14:09:40 +02:00
parent 52ef323284
commit 8025e9bd0f
3 changed files with 47 additions and 10 deletions

View File

@ -321,8 +321,9 @@ struct Ast
{ {
// Named constructors of AST structure // Named constructors of AST structure
static Ast binary(Token, Ast lhs, Ast rhs); static Ast binary(Token, Ast lhs, Ast rhs);
static Ast block(Location location, Ast seq = sequence({}), std::vector<Ast> parameters = {}); static Ast block(Location location, Ast seq = sequence({}));
static Ast call(std::vector<Ast> call); static Ast call(std::vector<Ast> call);
static Ast lambda(Location location, Ast seq = sequence({}), std::vector<Ast> parameters = {});
static Ast literal(Token); static Ast literal(Token);
static Ast sequence(std::vector<Ast> call); static Ast sequence(std::vector<Ast> call);
static Ast variable_declaration(Location loc, std::vector<Ast> lvalues, std::optional<Ast> rvalue); static Ast variable_declaration(Location loc, std::vector<Ast> lvalues, std::optional<Ast> rvalue);
@ -331,6 +332,7 @@ struct Ast
{ {
Binary, // Binary operator application like `1` + `2` Binary, // Binary operator application like `1` + `2`
Block, // Block expressions like `[42; hello]` Block, // Block expressions like `[42; hello]`
Lambda, // Block expression beeing functions like `[i|i+1]`
Call, // Function call application like `print 42` Call, // Function call application like `print 42`
Literal, // Compile time known constant like `c` or `1` Literal, // Compile time known constant like `c` or `1`
Sequence, // Several expressions sequences like `42`, `42; 32` Sequence, // Several expressions sequences like `42`, `42; 32`
@ -418,9 +420,19 @@ struct Number
std::ostream& operator<<(std::ostream& os, Number const& num); std::ostream& operator<<(std::ostream& os, Number const& num);
struct Value; struct Value;
struct Interpreter;
using Function = std::function<Result<Value>(std::vector<Value>)>; using Function = std::function<Result<Value>(std::vector<Value>)>;
struct Lambda
{
Location location;
std::vector<std::string> parameters;
Ast body;
Result<Value> operator()(Interpreter &i, std::vector<Value> params);
};
template<typename T, typename ...XS> template<typename T, typename ...XS>
constexpr auto is_one_of = (std::is_same_v<T, XS> || ...); constexpr auto is_one_of = (std::is_same_v<T, XS> || ...);

View File

@ -102,18 +102,30 @@ Result<Ast> Parser::parse_atomic_expression()
auto start = token_id; auto start = token_id;
std::vector<Ast> parameters; std::vector<Ast> parameters;
bool is_lambda = false;
if (auto p = parse_many(*this, &Parser::parse_identifier_with_trailing_separators, std::nullopt, At_Least::One); p && expect(Token::Type::Parameter_Separator)) { if (expect(Token::Type::Parameter_Separator)) {
consume(); consume();
parameters = std::move(p).value(); is_lambda = true;
} else { } else {
token_id = start; auto p = parse_many(*this, &Parser::parse_identifier_with_trailing_separators, std::nullopt, At_Least::One);
if (p && expect(Token::Type::Parameter_Separator)) {
consume();
parameters = std::move(p).value();
is_lambda = true;
} else {
token_id = start;
}
} }
return parse_sequence().and_then([&](Ast &&ast) -> Result<Ast> { return parse_sequence().and_then([&](Ast &&ast) -> Result<Ast> {
Try(ensure(Token::Type::Close_Block)); Try(ensure(Token::Type::Close_Block));
consume(); consume();
return Ast::block(opening.location, std::move(ast), std::move(parameters)); if (is_lambda) {
return Ast::lambda(opening.location, std::move(ast), std::move(parameters));
} else {
return Ast::block(opening.location, std::move(ast));
}
}); });
} }
@ -253,16 +265,25 @@ Ast Ast::sequence(std::vector<Ast> expressions)
return ast; return ast;
} }
Ast Ast::block(Location location, Ast seq, std::vector<Ast> parameters) Ast Ast::block(Location location, Ast seq)
{ {
Ast ast; Ast ast;
ast.type = Type::Block; ast.type = Type::Block;
ast.location = location; ast.location = location;
ast.arguments = std::move(parameters);
ast.arguments.push_back(std::move(seq)); ast.arguments.push_back(std::move(seq));
return ast; return ast;
} }
Ast Ast::lambda(Location location, Ast body, std::vector<Ast> parameters)
{
Ast ast;
ast.type = Type::Lambda;
ast.location = location;
ast.arguments = std::move(parameters);
ast.arguments.push_back(std::move(body));
return ast;
}
Ast Ast::variable_declaration(Location loc, std::vector<Ast> lvalues, std::optional<Ast> rvalue) Ast Ast::variable_declaration(Location loc, std::vector<Ast> lvalues, std::optional<Ast> rvalue)
{ {
Ast ast; Ast ast;
@ -300,6 +321,7 @@ bool operator==(Ast const& lhs, Ast const& rhs)
case Ast::Type::Block: case Ast::Type::Block:
case Ast::Type::Call: case Ast::Type::Call:
case Ast::Type::Lambda:
case Ast::Type::Sequence: case Ast::Type::Sequence:
case Ast::Type::Variable_Declaration: case Ast::Type::Variable_Declaration:
return lhs.arguments.size() == rhs.arguments.size() return lhs.arguments.size() == rhs.arguments.size()
@ -315,6 +337,7 @@ std::ostream& operator<<(std::ostream& os, Ast::Type type)
case Ast::Type::Binary: return os << "BINARY"; case Ast::Type::Binary: return os << "BINARY";
case Ast::Type::Block: return os << "BLOCK"; case Ast::Type::Block: return os << "BLOCK";
case Ast::Type::Call: return os << "CALL"; case Ast::Type::Call: return os << "CALL";
case Ast::Type::Lambda: return os << "LAMBDA";
case Ast::Type::Literal: return os << "LITERAL"; case Ast::Type::Literal: return os << "LITERAL";
case Ast::Type::Sequence: return os << "SEQUENCE"; case Ast::Type::Sequence: return os << "SEQUENCE";
case Ast::Type::Variable_Declaration: return os << "VAR"; case Ast::Type::Variable_Declaration: return os << "VAR";

View File

@ -139,9 +139,9 @@ suite parser_test = [] {
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::block({}, Ast::binary( expect_ast("[ i j k | i + j + k ]", Ast::lambda({}, Ast::binary(
{ Token::Type::Operator, "+", {} }, { Token::Type::Operator, "+", {} },
Ast::literal({ Token::Type::Symbol, "i", {} }), Ast::literal({ Token::Type::Symbol, "i", {} }),
Ast::binary( Ast::binary(
@ -155,7 +155,7 @@ suite parser_test = [] {
Ast::literal({ Token::Type::Symbol, "k", {} }) Ast::literal({ Token::Type::Symbol, "k", {} })
})); }));
expect_ast("[ i; j; k | i + j + k ]", Ast::block({}, Ast::binary( expect_ast("[ i; j; k | i + j + k ]", Ast::lambda({}, Ast::binary(
{ Token::Type::Operator, "+", {} }, { Token::Type::Operator, "+", {} },
Ast::literal({ Token::Type::Symbol, "i", {} }), Ast::literal({ Token::Type::Symbol, "i", {} }),
Ast::binary( Ast::binary(
@ -168,6 +168,8 @@ 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", {} })
})); }));
expect_ast("[|1]", Ast::lambda({}, Ast::literal({ Token::Type::Numeric, "1", {} }), {}));
}; };
"Variable declarations"_test = [] { "Variable declarations"_test = [] {