|
|
|
@ -7,6 +7,7 @@
|
|
|
|
|
#include <iterator> // std::next, std::prev |
|
|
|
|
#include <list> |
|
|
|
|
#include <memory> |
|
|
|
|
#include <span> |
|
|
|
|
#include <string> |
|
|
|
|
|
|
|
|
|
#include "ast.h" |
|
|
|
@ -106,41 +107,56 @@ ValuePtr Eval::evalQuote(const ValueVector& nodes)
|
|
|
|
|
return nodes.front(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// (try* x (catch* y z))
|
|
|
|
|
// (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(); |
|
|
|
|
// Is last node a catch* block
|
|
|
|
|
bool is_last_node_catch = false; |
|
|
|
|
std::span<const ValuePtr> catch_nodes; |
|
|
|
|
if (nodes.size() >= 2 && is<List>(nodes.back().get())) { |
|
|
|
|
VALUE_CAST(list, List, nodes.back()); |
|
|
|
|
catch_nodes = list->nodesRead(); |
|
|
|
|
if (!list->empty() && is<Symbol>(catch_nodes.front().get())) { |
|
|
|
|
VALUE_CAST(catch_symbol, Symbol, catch_nodes.front()); |
|
|
|
|
if (catch_symbol->symbol() == "catch*") { |
|
|
|
|
CHECK_ARG_COUNT_IS("catch*", catch_nodes.size() - 1, 2); |
|
|
|
|
is_last_node_catch = true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Dont have to eval on malformed (catch*)
|
|
|
|
|
if (Error::the().hasAnyError()) { |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Try
|
|
|
|
|
|
|
|
|
|
ValuePtr result; |
|
|
|
|
auto end = (!is_last_node_catch) ? nodes.end() : std::prev(nodes.end(), 1); |
|
|
|
|
for (auto it = nodes.begin(); it != end; ++it) { |
|
|
|
|
m_ast = *it; |
|
|
|
|
m_env = env; |
|
|
|
|
result = evalImpl(); |
|
|
|
|
} |
|
|
|
|
if (!Error::the().hasAnyError()) { |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
if (nodes.size() == 1) { |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Catch
|
|
|
|
|
|
|
|
|
|
if (!is_last_node_catch) { |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 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->nodesRead(); |
|
|
|
|
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
|
|
|
|
@ -383,8 +399,6 @@ void Eval::evalWhile(const ValueVector& nodes, EnvironmentPtr env)
|
|
|
|
|
// Condition
|
|
|
|
|
ValuePtr predicate = *nodes.begin(); |
|
|
|
|
|
|
|
|
|
// Printer p;
|
|
|
|
|
|
|
|
|
|
m_ast = predicate; |
|
|
|
|
m_env = env; |
|
|
|
|
ValuePtr condition = evalImpl(); |
|
|
|
@ -399,8 +413,6 @@ void Eval::evalWhile(const ValueVector& nodes, EnvironmentPtr env)
|
|
|
|
|
m_ast = predicate; |
|
|
|
|
m_env = env; |
|
|
|
|
condition = evalImpl(); |
|
|
|
|
|
|
|
|
|
// print("{}\n", p.print(condition));
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
m_ast = makePtr<Constant>(); |
|
|
|
|