Eval: Allow multiple s-expr in try*
This commit is contained in:
+35
-23
@@ -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());
|
||||||
if (!Error::the().hasAnyError()) {
|
catch_nodes = list->nodesRead();
|
||||||
return result;
|
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;
|
||||||
}
|
}
|
||||||
if (nodes.size() == 1) {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dont have to eval on malformed (catch*)
|
||||||
|
if (Error::the().hasAnyError()) {
|
||||||
return nullptr;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
// 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>();
|
||||||
|
|||||||
Reference in New Issue
Block a user