Eval: Change stack-based TCO to loop-based TCO
This commit is contained in:
+26
-26
@@ -30,8 +30,8 @@ ValuePtr Eval::evalDef(const ValueVector& nodes, EnvironmentPtr env)
|
||||
VALUE_CAST(symbol, Symbol, nodes.front());
|
||||
|
||||
// Eval second argument
|
||||
m_ast_stack.push(*std::next(nodes.begin()));
|
||||
m_env_stack.push(env);
|
||||
m_ast = *std::next(nodes.begin());
|
||||
m_env = env;
|
||||
ValuePtr value = evalImpl();
|
||||
|
||||
// Dont overwrite symbols after an error
|
||||
@@ -52,8 +52,8 @@ ValuePtr Eval::evalDefMacro(const ValueVector& nodes, EnvironmentPtr env)
|
||||
VALUE_CAST(symbol, Symbol, nodes.front());
|
||||
|
||||
// Eval second argument
|
||||
m_ast_stack.push(*std::next(nodes.begin()));
|
||||
m_env_stack.push(env);
|
||||
m_ast = *std::next(nodes.begin());
|
||||
m_env = env;
|
||||
ValuePtr value = evalImpl();
|
||||
VALUE_CAST(lambda, Lambda, value);
|
||||
|
||||
@@ -118,14 +118,14 @@ void Eval::evalDo(const ValueVector& nodes, EnvironmentPtr env)
|
||||
|
||||
// Evaluate all nodes except the last
|
||||
for (auto it = nodes.begin(); it != std::prev(nodes.end(), 1); ++it) {
|
||||
m_ast_stack.push(*it);
|
||||
m_env_stack.push(env);
|
||||
m_ast = *it;
|
||||
m_env = env;
|
||||
evalImpl();
|
||||
}
|
||||
|
||||
// Eval last node
|
||||
m_ast_stack.push(nodes.back());
|
||||
m_env_stack.push(env);
|
||||
m_ast = nodes.back();
|
||||
m_env = env;
|
||||
return; // TCO
|
||||
}
|
||||
|
||||
@@ -138,18 +138,18 @@ void Eval::evalIf(const ValueVector& nodes, EnvironmentPtr env)
|
||||
auto second_argument = *std::next(nodes.begin());
|
||||
auto third_argument = (nodes.size() == 3) ? *std::next(std::next(nodes.begin())) : makePtr<Constant>(Constant::Nil);
|
||||
|
||||
m_ast_stack.push(first_argument);
|
||||
m_env_stack.push(env);
|
||||
m_ast = first_argument;
|
||||
m_env = env;
|
||||
auto first_evaluated = evalImpl();
|
||||
if (!is<Constant>(first_evaluated.get())
|
||||
|| std::static_pointer_cast<Constant>(first_evaluated)->state() == Constant::True) {
|
||||
m_ast_stack.push(second_argument);
|
||||
m_env_stack.push(env);
|
||||
m_ast = second_argument;
|
||||
m_env = env;
|
||||
return; // TCO
|
||||
}
|
||||
|
||||
m_ast_stack.push(third_argument);
|
||||
m_env_stack.push(env);
|
||||
m_ast = third_argument;
|
||||
m_env = env;
|
||||
return; // TCO
|
||||
}
|
||||
|
||||
@@ -173,16 +173,16 @@ void Eval::evalLet(const ValueVector& nodes, EnvironmentPtr env)
|
||||
VALUE_CAST(elt, Symbol, (*it), void());
|
||||
|
||||
std::string key = elt->symbol();
|
||||
m_ast_stack.push(*std::next(it));
|
||||
m_env_stack.push(let_env);
|
||||
m_ast = *std::next(it);
|
||||
m_env = let_env;
|
||||
ValuePtr value = evalImpl();
|
||||
let_env->set(key, value);
|
||||
}
|
||||
|
||||
// TODO: Remove limitation of 3 arguments
|
||||
// Eval all arguments in this new env, return last sexp of the result
|
||||
m_ast_stack.push(*std::next(nodes.begin()));
|
||||
m_env_stack.push(let_env);
|
||||
m_ast = *std::next(nodes.begin());
|
||||
m_env = let_env;
|
||||
return; // TCO
|
||||
}
|
||||
|
||||
@@ -277,8 +277,8 @@ void Eval::evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env)
|
||||
|
||||
auto result = evalQuasiQuoteImpl(nodes.front());
|
||||
|
||||
m_ast_stack.push(result);
|
||||
m_env_stack.push(env);
|
||||
m_ast = result;
|
||||
m_env = env;
|
||||
return; // TCO
|
||||
}
|
||||
|
||||
@@ -288,8 +288,8 @@ void Eval::evalTry(const ValueVector& nodes, EnvironmentPtr env)
|
||||
CHECK_ARG_COUNT_AT_LEAST("try*", nodes.size(), 1, void());
|
||||
|
||||
// Try 'x'
|
||||
m_ast_stack.push(nodes.front());
|
||||
m_env_stack.push(env);
|
||||
m_ast = nodes.front();
|
||||
m_env = env;
|
||||
auto result = evalImpl();
|
||||
|
||||
// Catch
|
||||
@@ -317,13 +317,13 @@ void Eval::evalTry(const ValueVector& nodes, EnvironmentPtr env)
|
||||
catch_env->set(catch_binding->symbol(), error);
|
||||
|
||||
// Evaluate 'z' using the new Environment
|
||||
m_ast_stack.push(catch_nodes.back());
|
||||
m_env_stack.push(catch_env);
|
||||
m_ast = catch_nodes.back();
|
||||
m_env = catch_env;
|
||||
return; // TCO
|
||||
}
|
||||
|
||||
m_ast_stack.push(result);
|
||||
m_env_stack.push(env);
|
||||
m_ast = result;
|
||||
m_env = env;
|
||||
return; // TCO
|
||||
}
|
||||
|
||||
|
||||
+15
-25
@@ -23,6 +23,7 @@ namespace blaze {
|
||||
Eval::Eval(ValuePtr ast, EnvironmentPtr env)
|
||||
: m_ast(ast)
|
||||
, m_env(env)
|
||||
, m_outer_env(env)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -30,11 +31,6 @@ Eval::Eval(ValuePtr ast, EnvironmentPtr env)
|
||||
|
||||
void Eval::eval()
|
||||
{
|
||||
m_ast_stack = std::stack<ValuePtr>();
|
||||
m_env_stack = std::stack<EnvironmentPtr>();
|
||||
m_ast_stack.push(m_ast);
|
||||
m_env_stack.push(m_env);
|
||||
|
||||
m_ast = evalImpl();
|
||||
}
|
||||
|
||||
@@ -48,20 +44,13 @@ ValuePtr Eval::evalImpl()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (m_ast_stack.size() == 0) {
|
||||
return nullptr;
|
||||
ast = m_ast;
|
||||
env = m_env;
|
||||
|
||||
if (env == nullptr) {
|
||||
env = m_outer_env;
|
||||
}
|
||||
|
||||
if (m_env_stack.size() == 0) {
|
||||
m_env_stack.push(m_env);
|
||||
}
|
||||
|
||||
ast = m_ast_stack.top();
|
||||
env = m_env_stack.top();
|
||||
|
||||
m_ast_stack.pop();
|
||||
m_env_stack.pop();
|
||||
|
||||
if (!is<List>(ast.get())) {
|
||||
return evalAst(ast, env);
|
||||
}
|
||||
@@ -133,8 +122,8 @@ ValuePtr Eval::evalImpl()
|
||||
if (is<Lambda>(evaluated_list->front().get())) {
|
||||
auto lambda = std::static_pointer_cast<Lambda>(evaluated_list->front());
|
||||
|
||||
m_ast_stack.push(lambda->body());
|
||||
m_env_stack.push(Environment::create(lambda, evaluated_list->rest()));
|
||||
m_ast = lambda->body();
|
||||
m_env = Environment::create(lambda, evaluated_list->rest());
|
||||
continue; // TCO
|
||||
}
|
||||
|
||||
@@ -165,8 +154,8 @@ ValuePtr Eval::evalAst(ValuePtr ast, EnvironmentPtr env)
|
||||
auto evaluated_nodes = ValueVector(count);
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
m_ast_stack.push(nodes[i]);
|
||||
m_env_stack.push(env);
|
||||
m_ast = nodes[i];
|
||||
m_env = env;
|
||||
ValuePtr eval_node = evalImpl();
|
||||
if (eval_node == nullptr) {
|
||||
return nullptr;
|
||||
@@ -184,8 +173,8 @@ ValuePtr Eval::evalAst(ValuePtr ast, EnvironmentPtr env)
|
||||
const auto& elements = std::static_pointer_cast<HashMap>(ast)->elements();
|
||||
Elements evaluated_elements;
|
||||
for (const auto& element : elements) {
|
||||
m_ast_stack.push(element.second);
|
||||
m_env_stack.push(env);
|
||||
m_ast = element.second;
|
||||
m_env = env;
|
||||
ValuePtr element_node = evalImpl();
|
||||
if (element_node == nullptr) {
|
||||
return nullptr;
|
||||
@@ -231,11 +220,12 @@ ValuePtr Eval::macroExpand(ValuePtr ast, EnvironmentPtr env)
|
||||
{
|
||||
while (isMacroCall(ast, env)) {
|
||||
auto list = std::static_pointer_cast<List>(ast);
|
||||
|
||||
auto value = env->get(std::static_pointer_cast<Symbol>(list->front())->symbol());
|
||||
auto lambda = std::static_pointer_cast<Lambda>(value);
|
||||
|
||||
m_ast_stack.push(lambda->body());
|
||||
m_env_stack.push(Environment::create(lambda, list->rest()));
|
||||
m_ast = lambda->body();
|
||||
m_env = Environment::create(lambda, list->rest());
|
||||
ast = evalImpl();
|
||||
}
|
||||
|
||||
|
||||
+1
-3
@@ -48,9 +48,7 @@ private:
|
||||
|
||||
ValuePtr m_ast;
|
||||
EnvironmentPtr m_env;
|
||||
|
||||
std::stack<ValuePtr> m_ast_stack;
|
||||
std::stack<EnvironmentPtr> m_env_stack;
|
||||
EnvironmentPtr m_outer_env;
|
||||
};
|
||||
|
||||
} // namespace blaze
|
||||
|
||||
+3
-3
@@ -518,7 +518,7 @@ ADD_FUNCTION(
|
||||
return makePtr<List>(collection->rest());
|
||||
});
|
||||
|
||||
// (apply + 1 2 (list 3 4)) -> (+ 1 2 3 4)
|
||||
// (apply + 1 2 (list 3 4)) -> (+ 1 2 3 4) -> 10
|
||||
ADD_FUNCTION(
|
||||
"apply",
|
||||
{
|
||||
@@ -984,8 +984,8 @@ ADD_FUNCTION(
|
||||
|
||||
void installFunctions(EnvironmentPtr env)
|
||||
{
|
||||
for (const auto& [name, lambda] : s_functions) {
|
||||
env->set(name, makePtr<Function>(name, lambda));
|
||||
for (const auto& [name, function] : s_functions) {
|
||||
env->set(name, makePtr<Function>(name, function));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user