Browse Source

Eval: Improve correctness and error handling

master
Riyyi 2 years ago
parent
commit
f132397e15
  1. 80
      src/eval.cpp
  2. 6
      src/functions.cpp

80
src/eval.cpp

@ -7,6 +7,7 @@
#include <memory> // std::static_pointer_cast #include <memory> // std::static_pointer_cast
#include <span> // std::span #include <span> // std::span
#include <string> #include <string>
#include <vector>
#include "ast.h" #include "ast.h"
#include "environment.h" #include "environment.h"
@ -30,6 +31,10 @@ void Eval::eval()
ASTNodePtr Eval::evalImpl(ASTNodePtr ast, EnvironmentPtr env) ASTNodePtr Eval::evalImpl(ASTNodePtr ast, EnvironmentPtr env)
{ {
if (ast == nullptr || env == nullptr) {
return nullptr;
}
if (!is<List>(ast.get())) { if (!is<List>(ast.get())) {
return evalAst(ast, env); return evalAst(ast, env);
} }
@ -52,16 +57,22 @@ ASTNodePtr Eval::evalImpl(ASTNodePtr ast, EnvironmentPtr env)
} }
} }
// Function call
return apply(std::static_pointer_cast<List>(evalAst(ast, env))); return apply(std::static_pointer_cast<List>(evalAst(ast, env)));
} }
ASTNodePtr Eval::evalAst(ASTNodePtr ast, EnvironmentPtr env) ASTNodePtr Eval::evalAst(ASTNodePtr ast, EnvironmentPtr env)
{ {
if (ast == nullptr || env == nullptr) {
return nullptr;
}
ASTNode* ast_raw_ptr = ast.get(); ASTNode* ast_raw_ptr = ast.get();
if (is<Symbol>(ast_raw_ptr)) { if (is<Symbol>(ast_raw_ptr)) {
auto result = env->get(std::static_pointer_cast<Symbol>(ast)->symbol()); auto result = env->get(std::static_pointer_cast<Symbol>(ast)->symbol());
if (!result) { if (!result) {
Error::the().addError(format("'{}' not found", ast)); Error::the().addError(format("'{}' not found", ast));
return nullptr;
} }
return result; return result;
} }
@ -69,7 +80,11 @@ ASTNodePtr Eval::evalAst(ASTNodePtr ast, EnvironmentPtr env)
auto result = makePtr<List>(); auto result = makePtr<List>();
auto nodes = std::static_pointer_cast<List>(ast)->nodes(); auto nodes = std::static_pointer_cast<List>(ast)->nodes();
for (auto node : nodes) { for (auto node : nodes) {
result->addNode(evalImpl(node, env)); ASTNodePtr eval_node = evalImpl(node, env);
if (eval_node == nullptr) {
return nullptr;
}
result->addNode(eval_node);
} }
return result; return result;
} }
@ -77,7 +92,11 @@ ASTNodePtr Eval::evalAst(ASTNodePtr ast, EnvironmentPtr env)
auto result = makePtr<Vector>(); auto result = makePtr<Vector>();
auto nodes = std::static_pointer_cast<Vector>(ast)->nodes(); auto nodes = std::static_pointer_cast<Vector>(ast)->nodes();
for (auto node : nodes) { for (auto node : nodes) {
result->addNode(evalImpl(node, env)); ASTNodePtr eval_node = evalImpl(node, env);
if (eval_node == nullptr) {
return nullptr;
}
result->addNode(eval_node);
} }
return result; return result;
} }
@ -85,7 +104,11 @@ ASTNodePtr Eval::evalAst(ASTNodePtr ast, EnvironmentPtr env)
auto result = makePtr<HashMap>(); auto result = makePtr<HashMap>();
auto elements = std::static_pointer_cast<HashMap>(ast)->elements(); auto elements = std::static_pointer_cast<HashMap>(ast)->elements();
for (auto& element : elements) { for (auto& element : elements) {
result->addElement(element.first, evalImpl(element.second, env)); ASTNodePtr element_node = evalImpl(element.second, env);
if (element_node == nullptr) {
return nullptr;
}
result->addElement(element.first, element_node);
} }
return result; return result;
} }
@ -107,9 +130,15 @@ ASTNodePtr Eval::evalDef(const std::vector<ASTNodePtr>& nodes, EnvironmentPtr en
} }
std::string symbol = std::static_pointer_cast<Symbol>(nodes[1])->symbol(); std::string symbol = std::static_pointer_cast<Symbol>(nodes[1])->symbol();
ASTNodePtr value = evalImpl(nodes[2], env);
// Dont overwrite symbols after an error
if (Error::the().hasAnyError()) {
return nullptr;
}
// Modify existing environment // Modify existing environment
return env->set(symbol, evalImpl(nodes[2], env)); return env->set(symbol, value);
} }
ASTNodePtr Eval::evalLet(const std::vector<ASTNodePtr>& nodes, EnvironmentPtr env) ASTNodePtr Eval::evalLet(const std::vector<ASTNodePtr>& nodes, EnvironmentPtr env)
@ -119,33 +148,42 @@ ASTNodePtr Eval::evalLet(const std::vector<ASTNodePtr>& nodes, EnvironmentPtr en
return nullptr; return nullptr;
} }
// Create new environment // First argument needs to be a List or Vector
auto let_env = makePtr<Environment>(env); if (!is<List>(nodes[1].get()) && !is<Vector>(nodes[1].get())) {
Error::the().addError(format("wrong argument type: list, '{}'", nodes[1]));
// First argument needs to be a List
if (!is<List>(nodes[1].get())) {
Error::the().addError(format("wrong type argument: list, {}", nodes[1]));
return nullptr; return nullptr;
} }
// List needs to have an even number of elements // Get the nodes out of the List or Vector
auto bindings = std::static_pointer_cast<List>(nodes[1]); std::vector<ASTNodePtr> binding_nodes;
auto binding_nodes = bindings->nodes(); if (is<List>(nodes[1].get())) {
if (bindings->nodes().size() % 2 != 0) { auto bindings = std::static_pointer_cast<List>(nodes[1]);
// FIXME: Print correct value binding_nodes = bindings->nodes();
Error::the().addError("FIXME"); }
// Error::the().addError(format("wrong number of arguments: {}, {}", bindings, bindings->nodes().size())); else {
auto bindings = std::static_pointer_cast<Vector>(nodes[1]);
binding_nodes = bindings->nodes();
} }
// List or Vector needs to have an even number of elements
size_t count = binding_nodes.size(); size_t count = binding_nodes.size();
if (count % 2 != 0) {
Error::the().addError(format("wrong number of arguments: {}, {}", "let* bindings", count));
return nullptr;
}
// Create new environment
auto let_env = makePtr<Environment>(env);
for (size_t i = 0; i < count; i += 2) { for (size_t i = 0; i < count; i += 2) {
// First element needs to be a Symbol // First element needs to be a Symbol
if (!is<Symbol>(binding_nodes[i].get())) { if (!is<Symbol>(binding_nodes[i].get())) {
Error::the().addError(format("wrong type argument: symbol, {}", binding_nodes[i])); Error::the().addError(format("wrong argument type: symbol, '{}'", binding_nodes[i]));
return nullptr;
} }
std::string key = std::static_pointer_cast<Symbol>(binding_nodes[i])->symbol(); std::string key = std::static_pointer_cast<Symbol>(binding_nodes[i])->symbol();
ASTNodePtr value = evalAst(binding_nodes[i + 1], let_env); ASTNodePtr value = evalImpl(binding_nodes[i + 1], let_env);
let_env->set(key, value); let_env->set(key, value);
} }
@ -156,6 +194,10 @@ ASTNodePtr Eval::evalLet(const std::vector<ASTNodePtr>& nodes, EnvironmentPtr en
ASTNodePtr Eval::apply(std::shared_ptr<List> evaluated_list) ASTNodePtr Eval::apply(std::shared_ptr<List> evaluated_list)
{ {
if (evaluated_list == nullptr) {
return nullptr;
}
auto nodes = evaluated_list->nodes(); auto nodes = evaluated_list->nodes();
if (!is<Function>(nodes[0].get())) { if (!is<Function>(nodes[0].get())) {

6
src/functions.cpp

@ -22,7 +22,7 @@ void GlobalEnvironment::add()
for (auto node : nodes) { for (auto node : nodes) {
if (!is<Number>(node.get())) { if (!is<Number>(node.get())) {
Error::the().addError(format("wrong type argument: number-or-marker-p, '{}'", node)); Error::the().addError(format("wrong argument type: number, '{}'", node));
return nullptr; return nullptr;
} }
@ -46,7 +46,7 @@ void GlobalEnvironment::sub()
for (auto node : nodes) { for (auto node : nodes) {
if (!is<Number>(node.get())) { if (!is<Number>(node.get())) {
Error::the().addError(format("wrong type argument: number-or-marker-p, '{}'", node)); Error::the().addError(format("wrong argument type: number, '{}'", node));
return nullptr; return nullptr;
} }
} }
@ -72,7 +72,7 @@ void GlobalEnvironment::mul()
for (auto node : nodes) { for (auto node : nodes) {
if (!is<Number>(node.get())) { if (!is<Number>(node.get())) {
Error::the().addError(format("wrong type argument: number-or-marker-p, '{}'", node)); Error::the().addError(format("wrong argument type: number, '{}'", node));
return nullptr; return nullptr;
} }

Loading…
Cancel
Save