Browse Source

Eval: Allow multiple s-expr in try*

master
Riyyi 1 year ago
parent
commit
c6c6d69e73
  1. 56
      src/eval-special-form.cpp

56
src/eval-special-form.cpp

@ -7,6 +7,7 @@
#include <iterator> // std::next, std::prev #include <iterator> // std::next, std::prev
#include <list> #include <list>
#include <memory> #include <memory>
#include <span>
#include <string> #include <string>
#include "ast.h" #include "ast.h"
@ -106,41 +107,56 @@ ValuePtr Eval::evalQuote(const ValueVector& nodes)
return nodes.front(); return nodes.front();
} }
// (try* x (catch* y z)) // (try* x ... (catch* y z))
ValuePtr Eval::evalTry(const ValueVector& nodes, EnvironmentPtr env) ValuePtr Eval::evalTry(const ValueVector& nodes, EnvironmentPtr env)
{ {
CHECK_ARG_COUNT_AT_LEAST("try*", nodes.size(), 1); CHECK_ARG_COUNT_AT_LEAST("try*", nodes.size(), 1);
// Try 'x' // Is last node a catch* block
m_ast = nodes.front(); bool is_last_node_catch = false;
m_env = env; std::span<const ValuePtr> catch_nodes;
auto result = evalImpl(); 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()) { if (!Error::the().hasAnyError()) {
return result; return result;
} }
if (nodes.size() == 1) {
return nullptr;
}
// Catch // Catch
if (!is_last_node_catch) {
return nullptr;
}
// Get the error message // Get the error message
auto error = (Error::the().hasOtherError()) auto error = (Error::the().hasOtherError())
? makePtr<String>(Error::the().otherError()) ? makePtr<String>(Error::the().otherError())
: Error::the().exception(); : Error::the().exception();
Error::the().clearErrors(); 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()))); VALUE_CAST(catch_binding, Symbol, (*std::next(catch_nodes.begin())));
// Create new Environment that binds 'y' to the value of the exception // 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 // Condition
ValuePtr predicate = *nodes.begin(); ValuePtr predicate = *nodes.begin();
// Printer p;
m_ast = predicate; m_ast = predicate;
m_env = env; m_env = env;
ValuePtr condition = evalImpl(); ValuePtr condition = evalImpl();
@ -399,8 +413,6 @@ void Eval::evalWhile(const ValueVector& nodes, EnvironmentPtr env)
m_ast = predicate; m_ast = predicate;
m_env = env; m_env = env;
condition = evalImpl(); condition = evalImpl();
// print("{}\n", p.print(condition));
} }
m_ast = makePtr<Constant>(); m_ast = makePtr<Constant>();

Loading…
Cancel
Save