Block expressions
This commit is contained in:
parent
c5260df41c
commit
5bfec0e77a
@ -29,8 +29,9 @@ void usage()
|
|||||||
|
|
||||||
static Result<void> run(std::string_view source, std::string_view filename)
|
static Result<void> run(std::string_view source, std::string_view filename)
|
||||||
{
|
{
|
||||||
Try(Parser::parse(source, filename));
|
auto ast = Try(Parser::parse(source, filename));
|
||||||
std::cout << "successfully parsed: " << source << " \n";
|
std::cout << "successfully parsed: " << source << " \n";
|
||||||
|
dump(ast);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,6 +291,7 @@ struct Ast
|
|||||||
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);
|
static Ast sequence(std::vector<Ast> call);
|
||||||
|
static Ast block(Ast seq, std::vector<Ast> parameters = {});
|
||||||
|
|
||||||
enum class Type
|
enum class Type
|
||||||
{
|
{
|
||||||
@ -298,15 +299,19 @@ struct Ast
|
|||||||
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`
|
Sequence, // Several expressions sequences like `42`, `42; 32`
|
||||||
|
Block, // Block expressions like `[42; hello]`
|
||||||
};
|
};
|
||||||
|
|
||||||
Type type;
|
Type type;
|
||||||
Token token;
|
Token token;
|
||||||
std::vector<Ast> arguments;
|
std::vector<Ast> arguments{};
|
||||||
|
std::vector<Ast> parameters{};
|
||||||
};
|
};
|
||||||
|
|
||||||
bool operator==(Ast const& lhs, Ast const& rhs);
|
bool operator==(Ast const& lhs, Ast const& rhs);
|
||||||
|
std::ostream& operator<<(std::ostream& os, Ast::Type type);
|
||||||
std::ostream& operator<<(std::ostream& os, Ast const& tree);
|
std::ostream& operator<<(std::ostream& os, Ast const& tree);
|
||||||
|
void dump(Ast const& ast, unsigned indent = 0);
|
||||||
|
|
||||||
struct Parser
|
struct Parser
|
||||||
{
|
{
|
||||||
@ -321,6 +326,7 @@ struct Parser
|
|||||||
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();
|
||||||
|
Result<Ast> parse_identifier();
|
||||||
|
|
||||||
Result<Token> peek() const;
|
Result<Token> peek() const;
|
||||||
Result<Token::Type> peek_type() const;
|
Result<Token::Type> peek_type() const;
|
||||||
|
@ -60,6 +60,26 @@ Result<Ast> Parser::parse_atomic_expression()
|
|||||||
case Token::Type::Numeric:
|
case Token::Type::Numeric:
|
||||||
return Ast::literal(consume());
|
return Ast::literal(consume());
|
||||||
|
|
||||||
|
case Token::Type::Open_Block:
|
||||||
|
{
|
||||||
|
consume();
|
||||||
|
auto start = token_id;
|
||||||
|
std::vector<Ast> parameters;
|
||||||
|
|
||||||
|
if (auto p = parse_one_or_more(*this, &Parser::parse_identifier); p && expect(Token::Type::Variable_Separator)) {
|
||||||
|
consume();
|
||||||
|
parameters = std::move(p).value();
|
||||||
|
} else {
|
||||||
|
token_id = start;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse_sequence().and_then([&](Ast ast) -> tl::expected<Ast, Error> {
|
||||||
|
Try(ensure(Token::Type::Close_Block));
|
||||||
|
consume();
|
||||||
|
return Ast::block(ast, std::move(parameters));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
case Token::Type::Open_Paren:
|
case Token::Type::Open_Paren:
|
||||||
consume();
|
consume();
|
||||||
return parse_expression().and_then([&](Ast ast) -> tl::expected<Ast, Error> {
|
return parse_expression().and_then([&](Ast ast) -> tl::expected<Ast, Error> {
|
||||||
@ -75,6 +95,12 @@ Result<Ast> Parser::parse_atomic_expression()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<Ast> Parser::parse_identifier()
|
||||||
|
{
|
||||||
|
Try(ensure(Token::Type::Symbol));
|
||||||
|
return Ast::literal(consume());
|
||||||
|
}
|
||||||
|
|
||||||
Result<std::vector<Ast>> parse_one_or_more(Parser &p, Result<Ast> (Parser::*parser)(), std::optional<Token::Type> separator)
|
Result<std::vector<Ast>> parse_one_or_more(Parser &p, Result<Ast> (Parser::*parser)(), std::optional<Token::Type> separator)
|
||||||
{
|
{
|
||||||
std::vector<Ast> trees;
|
std::vector<Ast> trees;
|
||||||
@ -161,6 +187,18 @@ Ast Ast::sequence(std::vector<Ast> expressions)
|
|||||||
return ast;
|
return ast;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ast Ast::block(Ast seq, std::vector<Ast> parameters)
|
||||||
|
{
|
||||||
|
Ast ast;
|
||||||
|
ast.type = Type::Block;
|
||||||
|
ast.parameters = std::move(parameters);
|
||||||
|
if (seq.type == Type::Sequence)
|
||||||
|
ast.arguments = std::move(seq).arguments;
|
||||||
|
else
|
||||||
|
ast.arguments.push_back(std::move(seq));
|
||||||
|
return ast;
|
||||||
|
}
|
||||||
|
|
||||||
Ast wrap_if_several(std::vector<Ast> &&ast, Ast(*wrapper)(std::vector<Ast>))
|
Ast wrap_if_several(std::vector<Ast> &&ast, Ast(*wrapper)(std::vector<Ast>))
|
||||||
{
|
{
|
||||||
if (ast.size() == 1)
|
if (ast.size() == 1)
|
||||||
@ -184,6 +222,7 @@ bool operator==(Ast const& lhs, Ast const& rhs)
|
|||||||
&& 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::Block:
|
||||||
case Ast::Type::Call:
|
case Ast::Type::Call:
|
||||||
case Ast::Type::Sequence:
|
case Ast::Type::Sequence:
|
||||||
return lhs.arguments.size() == rhs.arguments.size()
|
return lhs.arguments.size() == rhs.arguments.size()
|
||||||
@ -193,9 +232,21 @@ bool operator==(Ast const& lhs, Ast const& rhs)
|
|||||||
unreachable();
|
unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, Ast::Type type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case Ast::Type::Binary: return os << "BINARY";
|
||||||
|
case Ast::Type::Block: return os << "BLOCK";
|
||||||
|
case Ast::Type::Call: return os << "CALL";
|
||||||
|
case Ast::Type::Literal: return os << "LITERAL";
|
||||||
|
case Ast::Type::Sequence: return os << "SEQUENCE";
|
||||||
|
}
|
||||||
|
unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, Ast const& tree)
|
std::ostream& operator<<(std::ostream& os, Ast const& tree)
|
||||||
{
|
{
|
||||||
os << "Ast(" << tree.token.source << ")";
|
os << "Ast::" << tree.type << "(" << tree.token.source << ")";
|
||||||
if (!tree.arguments.empty()) {
|
if (!tree.arguments.empty()) {
|
||||||
os << " { ";
|
os << " { ";
|
||||||
for (auto const& arg : tree.arguments) {
|
for (auto const& arg : tree.arguments) {
|
||||||
@ -203,5 +254,50 @@ std::ostream& operator<<(std::ostream& os, Ast const& tree)
|
|||||||
}
|
}
|
||||||
os << '}';
|
os << '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!tree.parameters.empty()) {
|
||||||
|
os << " with parameters { ";
|
||||||
|
for (auto const& arg : tree.parameters) {
|
||||||
|
os << arg << ' ';
|
||||||
|
}
|
||||||
|
os << '}';
|
||||||
|
}
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Indent
|
||||||
|
{
|
||||||
|
unsigned count;
|
||||||
|
Indent operator+() { return { count + 2 }; }
|
||||||
|
operator unsigned() { return count; }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, Indent n)
|
||||||
|
{
|
||||||
|
while (n.count-- > 0)
|
||||||
|
os.put(' ');
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump(Ast const& tree, unsigned indent)
|
||||||
|
{
|
||||||
|
Indent i{indent};
|
||||||
|
std::cout << i << "Ast::" << tree.type << "(" << tree.token.source << ")";
|
||||||
|
if (!tree.arguments.empty()) {
|
||||||
|
std::cout << " {\n";
|
||||||
|
for (auto const& arg : tree.arguments) {
|
||||||
|
dump(arg, +i);
|
||||||
|
}
|
||||||
|
std::cout << i << '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tree.parameters.empty()) {
|
||||||
|
std::cout << " with parameters {\n";
|
||||||
|
for (auto const& arg : tree.parameters) {
|
||||||
|
dump(arg, +i);
|
||||||
|
}
|
||||||
|
std::cout << i << '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << '\n';
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user