srctree

Robin Linden parent a275b3c1 3f1922c0
js: Add support for returning values out of function calls

inlinesplit
js/ast.h added: 69, removed: 4, total 65
@@ -5,6 +5,7 @@
#ifndef JS_AST_H_
#define JS_AST_H_
 
#include <exception>
#include <map>
#include <memory>
#include <optional>
@@ -19,6 +20,7 @@ namespace ast {
struct Function;
struct BinaryExpression;
struct BlockStatement;
struct ReturnStatement;
struct CallExpression;
struct ExpressionStatement;
struct FunctionDeclaration;
@@ -32,7 +34,7 @@ struct VariableDeclarator;
using Declaration = std::variant<FunctionDeclaration, VariableDeclaration>;
using Literal = std::variant<NumericLiteral, StringLiteral>;
using Pattern = std::variant<Identifier>;
using Statement = std::variant<Declaration, ExpressionStatement, BlockStatement>;
using Statement = std::variant<Declaration, ExpressionStatement, BlockStatement, ReturnStatement>;
using Expression = std::variant<Identifier, Literal, CallExpression, BinaryExpression>;
using Node = std::variant<Expression, Statement, Pattern, Program, Function, VariableDeclarator>;
 
@@ -101,7 +103,9 @@ struct BlockStatement {
std::vector<std::shared_ptr<Statement>> body;
};
 
using FunctionBody = BlockStatement;
struct FunctionBody {
std::vector<Statement> body;
};
 
struct Function {
std::vector<Pattern> params;
@@ -131,6 +135,10 @@ struct VariableDeclaration {
Kind kind{Kind::Var};
};
 
struct ReturnStatement {
std::optional<Expression> argument;
};
 
class AstExecutor {
public:
Value execute(auto const &ast) { return (*this)(ast); }
@@ -141,6 +149,11 @@ public:
Value operator()(Expression const &v) { return std::visit(*this, v); }
Value operator()(Identifier const &v) { return Value{v.name}; }
Value operator()(Pattern const &v) { return std::visit(*this, v); }
Value operator()(Declaration const &v) { return std::visit(*this, v); }
Value operator()(Statement const &v) { return std::visit(*this, v); }
 
// TODO(robinlinden): Implement.
Value operator()(ExpressionStatement const &) { std::terminate(); }
 
Value operator()(BinaryExpression const &v) {
auto lhs = execute(*v.lhs);
@@ -202,7 +215,24 @@ public:
return Value{};
}
 
Value operator()(FunctionBody const &v) {
for (auto const &statement : v.body) {
execute(statement);
if (returning) {
return *std::exchange(returning, std::nullopt);
}
}
 
return Value{};
}
 
Value operator()(ReturnStatement const &v) {
returning = v.argument ? execute(*v.argument) : Value{};
return Value{};
}
 
std::map<std::string, Value, std::less<>> variables;
std::optional<Value> returning;
};
 
} // namespace ast
 
js/ast_test.cpp added: 69, removed: 4, total 65
@@ -90,5 +90,40 @@ int main() {
expect_eq(e.variables.at("two"), Value{"beep beep boop"});
});
 
etest::test("return, values are returned", [] {
auto declaration = FunctionDeclaration{
.id = Identifier{"func"},
.function = std::make_shared<Function>(Function{
.params{},
.body{{ReturnStatement{NumericLiteral{42.}}}},
}),
};
 
auto call = CallExpression{.callee = std::make_shared<Expression>(Identifier{"func"})};
 
AstExecutor e;
expect_eq(e.execute(declaration), Value{});
expect_eq(e.execute(call), Value{42.});
});
 
etest::test("return, function execution is ended", [] {
auto declaration = FunctionDeclaration{
.id = Identifier{"func"},
.function = std::make_shared<Function>(Function{
.params{},
.body{{
ReturnStatement{},
ReturnStatement{NumericLiteral{42.}},
}},
}),
};
 
auto call = CallExpression{.callee = std::make_shared<Expression>(Identifier{"func"})};
 
AstExecutor e;
expect_eq(e.execute(declaration), Value{});
expect_eq(e.execute(call), Value{});
});
 
return etest::run_all_tests();
}