Everywhere: Implement step9 try/catch
This commit is contained in:
+1
-1
@@ -29,7 +29,7 @@ EnvironmentPtr Environment::create(EnvironmentPtr outer)
|
|||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
EnvironmentPtr Environment::create(const ValuePtr lambda, std::list<ValuePtr> arguments)
|
EnvironmentPtr Environment::create(const ValuePtr lambda, const std::list<ValuePtr>& arguments)
|
||||||
{
|
{
|
||||||
auto lambda_casted = std::static_pointer_cast<Lambda>(lambda);
|
auto lambda_casted = std::static_pointer_cast<Lambda>(lambda);
|
||||||
auto env = create(lambda_casted->env());
|
auto env = create(lambda_casted->env());
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ public:
|
|||||||
// Factory functions instead of constructors because it can fail in the bindings/arguments case
|
// Factory functions instead of constructors because it can fail in the bindings/arguments case
|
||||||
static EnvironmentPtr create();
|
static EnvironmentPtr create();
|
||||||
static EnvironmentPtr create(EnvironmentPtr outer);
|
static EnvironmentPtr create(EnvironmentPtr outer);
|
||||||
static EnvironmentPtr create(const ValuePtr lambda, std::list<ValuePtr> arguments);
|
static EnvironmentPtr create(const ValuePtr lambda, const std::list<ValuePtr>& arguments);
|
||||||
|
|
||||||
bool exists(const std::string& symbol);
|
bool exists(const std::string& symbol);
|
||||||
ValuePtr set(const std::string& symbol, ValuePtr value);
|
ValuePtr set(const std::string& symbol, ValuePtr value);
|
||||||
|
|||||||
+7
-1
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "ruc/singleton.h"
|
#include "ruc/singleton.h"
|
||||||
|
|
||||||
|
#include "forward.h"
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
|
|
||||||
namespace blaze {
|
namespace blaze {
|
||||||
@@ -23,23 +24,28 @@ public:
|
|||||||
{
|
{
|
||||||
m_token_errors.clear();
|
m_token_errors.clear();
|
||||||
m_other_errors.clear();
|
m_other_errors.clear();
|
||||||
|
m_exceptions.clear();
|
||||||
}
|
}
|
||||||
void add(Token error) { m_token_errors.push_back(error); }
|
void add(Token error) { m_token_errors.push_back(error); }
|
||||||
void add(const std::string& error) { m_other_errors.push_back(error); }
|
void add(const std::string& error) { m_other_errors.push_back(error); }
|
||||||
|
void add(ValuePtr error) { m_exceptions.push_back(error); }
|
||||||
|
|
||||||
bool hasTokenError() { return m_token_errors.size() > 0; }
|
bool hasTokenError() { return m_token_errors.size() > 0; }
|
||||||
bool hasOtherError() { return m_other_errors.size() > 0; }
|
bool hasOtherError() { return m_other_errors.size() > 0; }
|
||||||
bool hasAnyError() { return hasTokenError() || hasOtherError(); }
|
bool hasException() { return m_exceptions.size() > 0; }
|
||||||
|
bool hasAnyError() { return hasTokenError() || hasOtherError() || hasException(); }
|
||||||
|
|
||||||
void setInput(std::string_view input) { m_input = input; }
|
void setInput(std::string_view input) { m_input = input; }
|
||||||
|
|
||||||
Token tokenError() const { return m_token_errors[0]; }
|
Token tokenError() const { return m_token_errors[0]; }
|
||||||
const std::string& otherError() const { return m_other_errors[0]; }
|
const std::string& otherError() const { return m_other_errors[0]; }
|
||||||
|
ValuePtr exception() const { return m_exceptions[0]; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string_view m_input;
|
std::string_view m_input;
|
||||||
std::vector<Token> m_token_errors;
|
std::vector<Token> m_token_errors;
|
||||||
std::vector<std::string> m_other_errors;
|
std::vector<std::string> m_other_errors;
|
||||||
|
std::vector<ValuePtr> m_exceptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blaze
|
} // namespace blaze
|
||||||
|
|||||||
@@ -4,10 +4,13 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <iterator> // std::next, std::prev
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
|
#include "environment.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "eval.h"
|
#include "eval.h"
|
||||||
#include "forward.h"
|
#include "forward.h"
|
||||||
@@ -277,6 +280,51 @@ void Eval::evalQuasiQuote(const std::list<ValuePtr>& nodes, EnvironmentPtr env)
|
|||||||
return; // TCO
|
return; // TCO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// (try* x (catch* y z))
|
||||||
|
void Eval::evalTry(const std::list<ValuePtr>& nodes, EnvironmentPtr env)
|
||||||
|
{
|
||||||
|
CHECK_ARG_COUNT_AT_LEAST("try*", nodes.size(), 1, void());
|
||||||
|
|
||||||
|
// Try 'x'
|
||||||
|
m_ast_stack.push(nodes.front());
|
||||||
|
m_env_stack.push(env);
|
||||||
|
auto result = evalImpl();
|
||||||
|
|
||||||
|
// Catch
|
||||||
|
if (nodes.size() == 2 && (Error::the().hasOtherError() || Error::the().hasException())) {
|
||||||
|
// Get the exception
|
||||||
|
auto error = (Error::the().hasOtherError())
|
||||||
|
? makePtr<String>(Error::the().otherError())
|
||||||
|
: Error::the().exception();
|
||||||
|
Error::the().clearErrors();
|
||||||
|
|
||||||
|
VALUE_CAST(catch_list, List, nodes.back(), void());
|
||||||
|
auto catch_nodes = catch_list->nodes();
|
||||||
|
CHECK_ARG_COUNT_IS("catch*", catch_nodes.size() - 1, 2, void());
|
||||||
|
|
||||||
|
VALUE_CAST(catch_symbol, Symbol, catch_nodes.front(), void());
|
||||||
|
if (catch_symbol->symbol() != "catch*") {
|
||||||
|
Error::the().add("catch block must begin with catch*");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE_CAST(catch_binding, Symbol, (*std::next(catch_nodes.begin())), void());
|
||||||
|
|
||||||
|
// Create new Environment that binds 'y' to the value of the exception
|
||||||
|
auto catch_env = Environment::create(env);
|
||||||
|
catch_env->set(catch_binding->symbol(), error);
|
||||||
|
|
||||||
|
// Evaluate 'z' using the new Environment
|
||||||
|
m_ast_stack.push(catch_nodes.back());
|
||||||
|
m_env_stack.push(catch_env);
|
||||||
|
return; // TCO
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ast_stack.push(result);
|
||||||
|
m_env_stack.push(env);
|
||||||
|
return; // TCO
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
} // namespace blaze
|
} // namespace blaze
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ ValuePtr Eval::evalImpl()
|
|||||||
EnvironmentPtr env = nullptr;
|
EnvironmentPtr env = nullptr;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
if (Error::the().hasAnyError()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_ast_stack.size() == 0) {
|
if (m_ast_stack.size() == 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -114,6 +118,10 @@ ValuePtr Eval::evalImpl()
|
|||||||
evalQuasiQuote(nodes, env);
|
evalQuasiQuote(nodes, env);
|
||||||
continue; // TCO
|
continue; // TCO
|
||||||
}
|
}
|
||||||
|
if (symbol == "try*") {
|
||||||
|
evalTry(nodes, env);
|
||||||
|
continue; // TCO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto evaluated_list = std::static_pointer_cast<List>(evalAst(ast, env));
|
auto evaluated_list = std::static_pointer_cast<List>(evalAst(ast, env));
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ private:
|
|||||||
void evalIf(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
void evalIf(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
||||||
void evalLet(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
void evalLet(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
||||||
void evalQuasiQuote(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
void evalQuasiQuote(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
||||||
|
void evalTry(const std::list<ValuePtr>& nodes, EnvironmentPtr env);
|
||||||
|
|
||||||
ValuePtr apply(std::shared_ptr<List> evaluated_list);
|
ValuePtr apply(std::shared_ptr<List> evaluated_list);
|
||||||
|
|
||||||
|
|||||||
@@ -570,6 +570,17 @@ ADD_FUNCTION(
|
|||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// (throw x)
|
||||||
|
ADD_FUNCTION(
|
||||||
|
"throw",
|
||||||
|
{
|
||||||
|
CHECK_ARG_COUNT_IS("throw", nodes.size(), 1);
|
||||||
|
|
||||||
|
Error::the().add(nodes.front());
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
})
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
#define IS_CONSTANT(name, constant) \
|
#define IS_CONSTANT(name, constant) \
|
||||||
|
|||||||
@@ -161,6 +161,10 @@ void Printer::printError()
|
|||||||
std::string error = Error::the().otherError();
|
std::string error = Error::the().otherError();
|
||||||
m_print += format("{}", error);
|
m_print += format("{}", error);
|
||||||
}
|
}
|
||||||
|
else if (Error::the().hasException()) {
|
||||||
|
ValuePtr error = Error::the().exception();
|
||||||
|
m_print += format("{}", error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace blaze
|
} // namespace blaze
|
||||||
|
|||||||
Reference in New Issue
Block a user