diff --git a/src/eval-special-form.cpp b/src/eval-special-form.cpp index 2213252..60ee18e 100644 --- a/src/eval-special-form.cpp +++ b/src/eval-special-form.cpp @@ -171,6 +171,30 @@ ValuePtr Eval::evalTry(const ValueVector& nodes, EnvironmentPtr env) // ----------------------------------------- +// (and 1 2 3) +void Eval::evalAnd(const ValueVector& nodes, EnvironmentPtr env) +{ + ValuePtr result; + for (auto node : nodes) { + m_ast = node; + m_env = env; + result = evalImpl(); + + if (is(result.get())) { + VALUE_CAST(constant, Constant, result, void()); + if (constant->state() == Constant::Nil || constant->state() == Constant::False) { + m_ast = makePtr(Constant::Nil); + m_env = env; + return; // TCO + } + } + } + + m_ast = result; + m_env = env; + return; // TCO +} + // (do 1 2 3) void Eval::evalDo(const ValueVector& nodes, EnvironmentPtr env) { @@ -295,6 +319,36 @@ void Eval::evalMacroExpand1(const ValueVector& nodes, EnvironmentPtr env) // ----------------------------------------- +// (or 1 2 3) +void Eval::evalOr(const ValueVector& nodes, EnvironmentPtr env) +{ + ValuePtr result; + for (auto node : nodes) { + m_ast = node; + m_env = env; + result = evalImpl(); + + if (!is(result.get())) { + m_ast = result; + m_env = env; + return; // TCO + } + + VALUE_CAST(constant, Constant, result, void()); + if (constant->state() == Constant::True) { + m_ast = result; + m_env = env; + return; // TCO + } + } + + m_ast = makePtr(Constant::Nil); + m_env = env; + return; // TCO +} + +// ----------------------------------------- + static bool isSymbol(ValuePtr value, const std::string& symbol) { if (!is(value.get())) { diff --git a/src/eval.cpp b/src/eval.cpp index ec632af..de014a0 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -93,6 +93,10 @@ ValuePtr Eval::evalImpl() return evalTry(nodes, env); } // Tail call optimized functions + if (symbol == "and") { + evalAnd(nodes, env); + continue; // TCO + } if (symbol == "do") { evalDo(nodes, env); continue; // TCO @@ -109,6 +113,10 @@ ValuePtr Eval::evalImpl() evalMacroExpand1(nodes, env); continue; // TCO } + if (symbol == "or") { + evalOr(nodes, env); + continue; // TCO + } if (symbol == "quasiquote") { evalQuasiQuote(nodes, env); continue; // TCO diff --git a/src/eval.h b/src/eval.h index c1da50c..7e3c9d9 100644 --- a/src/eval.h +++ b/src/eval.h @@ -38,10 +38,12 @@ private: ValuePtr evalQuote(const ValueVector& nodes); ValuePtr evalTry(const ValueVector& nodes, EnvironmentPtr env); + void evalAnd(const ValueVector& nodes, EnvironmentPtr env); void evalDo(const ValueVector& nodes, EnvironmentPtr env); void evalIf(const ValueVector& nodes, EnvironmentPtr env); void evalLet(const ValueVector& nodes, EnvironmentPtr env); void evalMacroExpand1(const ValueVector& nodes, EnvironmentPtr env); + void evalOr(const ValueVector& nodes, EnvironmentPtr env); void evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env); void evalWhile(const ValueVector& nodes, EnvironmentPtr env);