Eval: Fix bug with try* catch*, was set as TCO in main loop
This commit is contained in:
+49
-45
@@ -111,6 +111,55 @@ ValuePtr Eval::evalQuote(const ValueVector& nodes)
|
|||||||
return nodes.front();
|
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)
|
// (do 1 2 3)
|
||||||
void Eval::evalDo(const ValueVector& nodes, EnvironmentPtr env)
|
void Eval::evalDo(const ValueVector& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
@@ -282,51 +331,6 @@ void Eval::evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env)
|
|||||||
return; // TCO
|
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 = nodes.front();
|
|
||||||
m_env = 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 = catch_nodes.back();
|
|
||||||
m_env = catch_env;
|
|
||||||
return; // TCO
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ast = result;
|
|
||||||
m_env = env;
|
|
||||||
return; // TCO
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
} // namespace blaze
|
} // namespace blaze
|
||||||
|
|||||||
+3
-4
@@ -89,6 +89,9 @@ ValuePtr Eval::evalImpl()
|
|||||||
if (symbol == "quote") {
|
if (symbol == "quote") {
|
||||||
return evalQuote(nodes);
|
return evalQuote(nodes);
|
||||||
}
|
}
|
||||||
|
if (symbol == "try*") {
|
||||||
|
return evalTry(nodes, env);
|
||||||
|
}
|
||||||
// Tail call optimized functions
|
// Tail call optimized functions
|
||||||
if (symbol == "do") {
|
if (symbol == "do") {
|
||||||
evalDo(nodes, env);
|
evalDo(nodes, env);
|
||||||
@@ -106,10 +109,6 @@ ValuePtr Eval::evalImpl()
|
|||||||
evalQuasiQuote(nodes, env);
|
evalQuasiQuote(nodes, env);
|
||||||
continue; // TCO
|
continue; // TCO
|
||||||
}
|
}
|
||||||
if (symbol == "try*") {
|
|
||||||
evalTry(nodes, env);
|
|
||||||
continue; // TCO
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto evaluated_list = std::static_pointer_cast<List>(evalAst(ast, env));
|
auto evaluated_list = std::static_pointer_cast<List>(evalAst(ast, env));
|
||||||
|
|||||||
+2
-1
@@ -38,11 +38,12 @@ private:
|
|||||||
ValuePtr evalMacroExpand(const ValueVector& nodes, EnvironmentPtr env);
|
ValuePtr evalMacroExpand(const ValueVector& nodes, EnvironmentPtr env);
|
||||||
ValuePtr evalQuasiQuoteExpand(const ValueVector& nodes);
|
ValuePtr evalQuasiQuoteExpand(const ValueVector& nodes);
|
||||||
ValuePtr evalQuote(const ValueVector& nodes);
|
ValuePtr evalQuote(const ValueVector& nodes);
|
||||||
|
ValuePtr evalTry(const ValueVector& nodes, EnvironmentPtr env);
|
||||||
|
|
||||||
void evalDo(const ValueVector& nodes, EnvironmentPtr env);
|
void evalDo(const ValueVector& nodes, EnvironmentPtr env);
|
||||||
void evalIf(const ValueVector& nodes, EnvironmentPtr env);
|
void evalIf(const ValueVector& nodes, EnvironmentPtr env);
|
||||||
void evalLet(const ValueVector& nodes, EnvironmentPtr env);
|
void evalLet(const ValueVector& nodes, EnvironmentPtr env);
|
||||||
void evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env);
|
void evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env);
|
||||||
void evalTry(const ValueVector& nodes, EnvironmentPtr env);
|
|
||||||
|
|
||||||
ValuePtr apply(std::shared_ptr<List> evaluated_list);
|
ValuePtr apply(std::shared_ptr<List> evaluated_list);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user