|
|
|
@ -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); |
|
|
|
|
|
|
|
|
@ -111,6 +111,55 @@ ValuePtr Eval::evalQuote(const ValueVector& nodes)
|
|
|
|
|
return nodes.front(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// (try* x (catch* y z))
|
|
|
|
|
ValuePtr Eval::evalTry(const ValueVector& nodes, EnvironmentPtr env) |
|
|
|
|
{ |
|
|
|
|
CHECK_ARG_COUNT_AT_LEAST("try*", nodes.size(), 1); |
|
|
|
|
|
|
|
|
|
// Try 'x'
|
|
|
|
|
m_ast = nodes.front(); |
|
|
|
|
m_env = env; |
|
|
|
|
auto result = evalImpl(); |
|
|
|
|
|
|
|
|
|
if (!Error::the().hasAnyError()) { |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
if (nodes.size() == 1) { |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Catch
|
|
|
|
|
|
|
|
|
|
// Get the error message
|
|
|
|
|
auto error = (Error::the().hasOtherError()) |
|
|
|
|
? makePtr<String>(Error::the().otherError()) |
|
|
|
|
: Error::the().exception(); |
|
|
|
|
Error::the().clearErrors(); |
|
|
|
|
|
|
|
|
|
VALUE_CAST(catch_list, List, nodes.back()); |
|
|
|
|
const auto& catch_nodes = catch_list->nodes(); |
|
|
|
|
CHECK_ARG_COUNT_IS("catch*", catch_nodes.size() - 1, 2); |
|
|
|
|
|
|
|
|
|
VALUE_CAST(catch_symbol, Symbol, catch_nodes.front()); |
|
|
|
|
if (catch_symbol->symbol() != "catch*") { |
|
|
|
|
Error::the().add("catch block must begin with catch*"); |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
VALUE_CAST(catch_binding, Symbol, (*std::next(catch_nodes.begin()))); |
|
|
|
|
|
|
|
|
|
// Create new Environment that binds 'y' to the value of the exception
|
|
|
|
|
auto catch_env = Environment::create(env); |
|
|
|
|
catch_env->set(catch_binding->symbol(), error); |
|
|
|
|
|
|
|
|
|
// Evaluate 'z' using the new Environment
|
|
|
|
|
m_ast = catch_nodes.back(); |
|
|
|
|
m_env = catch_env; |
|
|
|
|
return evalImpl(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// -----------------------------------------
|
|
|
|
|
|
|
|
|
|
// (do 1 2 3)
|
|
|
|
|
void Eval::evalDo(const ValueVector& nodes, EnvironmentPtr env) |
|
|
|
|
{ |
|
|
|
@ -118,14 +167,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 +187,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 +222,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,53 +326,8 @@ void Eval::evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env)
|
|
|
|
|
|
|
|
|
|
auto result = evalQuasiQuoteImpl(nodes.front()); |
|
|
|
|
|
|
|
|
|
m_ast_stack.push(result); |
|
|
|
|
m_env_stack.push(env); |
|
|
|
|
return; // TCO
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// (try* x (catch* y z))
|
|
|
|
|
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); |
|
|
|
|
auto result = evalImpl(); |
|
|
|
|
|
|
|
|
|
// Catch
|
|
|
|
|
if (nodes.size() == 2 && (Error::the().hasOtherError() || Error::the().hasException())) { |
|
|
|
|
// Get the exception
|
|
|
|
|
auto error = (Error::the().hasOtherError()) |
|
|
|
|
? makePtr<String>(Error::the().otherError()) |
|
|
|
|
: Error::the().exception(); |
|
|
|
|
Error::the().clearErrors(); |
|
|
|
|
|
|
|
|
|
VALUE_CAST(catch_list, List, nodes.back(), void()); |
|
|
|
|
const auto& catch_nodes = catch_list->nodes(); |
|
|
|
|
CHECK_ARG_COUNT_IS("catch*", catch_nodes.size() - 1, 2, void()); |
|
|
|
|
|
|
|
|
|
VALUE_CAST(catch_symbol, Symbol, catch_nodes.front(), void()); |
|
|
|
|
if (catch_symbol->symbol() != "catch*") { |
|
|
|
|
Error::the().add("catch block must begin with catch*"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
VALUE_CAST(catch_binding, Symbol, (*std::next(catch_nodes.begin())), void()); |
|
|
|
|
|
|
|
|
|
// Create new Environment that binds 'y' to the value of the exception
|
|
|
|
|
auto catch_env = Environment::create(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); |
|
|
|
|
return; // TCO
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
m_ast_stack.push(result); |
|
|
|
|
m_env_stack.push(env); |
|
|
|
|
m_ast = result; |
|
|
|
|
m_env = env; |
|
|
|
|
return; // TCO
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|