From c6c6d69e734bd38a88f92b444575c3ecfae901b2 Mon Sep 17 00:00:00 2001 From: Riyyi Date: Fri, 27 Oct 2023 23:50:35 +0200 Subject: [PATCH] Eval: Allow multiple s-expr in try* --- src/eval-special-form.cpp | 56 ++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/src/eval-special-form.cpp b/src/eval-special-form.cpp index 804b435..2213252 100644 --- a/src/eval-special-form.cpp +++ b/src/eval-special-form.cpp @@ -7,6 +7,7 @@ #include // std::next, std::prev #include #include +#include #include #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 catch_nodes; + if (nodes.size() >= 2 && is(nodes.back().get())) { + VALUE_CAST(list, List, nodes.back()); + catch_nodes = list->nodesRead(); + if (!list->empty() && is(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(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();