From a7e2927efe8ff286089cb3fd42666f9c0423d0b5 Mon Sep 17 00:00:00 2001 From: yhirose Date: Mon, 1 Jun 2015 17:56:39 -0400 Subject: [PATCH] Added closure support. --- language/interpreter.cc | 44 +++++++++++++++++++++++----------------- language/interpreter.hpp | 35 ++++++++++++++++++++++---------- language/repl.cc | 2 +- language/repl.hpp | 2 +- 4 files changed, 51 insertions(+), 32 deletions(-) diff --git a/language/interpreter.cc b/language/interpreter.cc index 22de0cf..1d507e8 100755 --- a/language/interpreter.cc +++ b/language/interpreter.cc @@ -7,7 +7,7 @@ using namespace std; struct Eval { - static Value eval(const Ast& ast, shared_ptr& env) { + static Value eval(const Ast& ast, shared_ptr env) { switch (ast.type) { case Statements: return eval_statements(ast, env); case While: return eval_while(ast, env); @@ -32,7 +32,7 @@ struct Eval } private: - static Value eval_statements(const Ast& ast, shared_ptr& env) { + static Value eval_statements(const Ast& ast, shared_ptr env) { if (ast.is_token) { return eval(ast, env); } else if (ast.nodes.empty()) { @@ -46,7 +46,7 @@ private: return eval(**it, env); } - static Value eval_while(const Ast& ast, shared_ptr& env) { + static Value eval_while(const Ast& ast, shared_ptr env) { for (;;) { auto cond = eval(*ast.nodes[0], env); if (!cond.to_bool()) { @@ -57,7 +57,7 @@ private: return Value(); } - static Value eval_if(const Ast& ast, shared_ptr& env) { + static Value eval_if(const Ast& ast, shared_ptr env) { const auto& nodes = ast.nodes; for (auto i = 0u; i < nodes.size(); i += 2) { @@ -74,7 +74,7 @@ private: return Value(); } - static Value eval_function(const Ast& ast, shared_ptr& env) { + static Value eval_function(const Ast& ast, shared_ptr env) { vector params; for (auto node: ast.nodes[0]->nodes) { params.push_back(node->token); @@ -84,14 +84,16 @@ private: auto f = Value::FunctionValue { params, - [=](shared_ptr& callEnv) { - return eval(*body, callEnv); - } + [=](shared_ptr callEnv) { + callEnv->push_outer(env); + auto ret = eval(*body, callEnv); + return ret; + } }; return Value(f); }; - static Value eval_function_call(const Ast& ast, shared_ptr& env) { + static Value eval_function_call(const Ast& ast, shared_ptr env) { const auto& var = ast.nodes[0]->token; const auto& args = ast.nodes[1]->nodes; @@ -99,7 +101,8 @@ private: const auto& fv = f.to_function(); if (fv.params.size() <= args.size()) { - auto callEnv = make_shared(env); + auto callEnv = make_shared(); + callEnv->set("self", f); for (auto i = 0u; i < fv.params.size(); i++) { @@ -108,6 +111,9 @@ private: auto val = eval(*arg, env); callEnv->set(var, val); } + + callEnv->push_outer(env); + return fv.eval(callEnv); } @@ -115,7 +121,7 @@ private: throw runtime_error(msg); } - static Value eval_condition(const Ast& ast, shared_ptr& env) { + static Value eval_condition(const Ast& ast, shared_ptr env) { auto lhs = eval(*ast.nodes[0], env); if (ast.nodes.size() > 1) { auto ope = eval(*ast.nodes[1], env).to_string(); @@ -140,7 +146,7 @@ private: return lhs; // Any } - static Value eval_bin_expression(const Ast& ast, shared_ptr& env) { + static Value eval_bin_expression(const Ast& ast, shared_ptr env) { auto ret = eval(*ast.nodes[0], env).to_long(); for (auto i = 1u; i < ast.nodes.size(); i += 2) { auto val = eval(*ast.nodes[i + 1], env).to_long(); @@ -156,27 +162,27 @@ private: return Value(ret); } - static Value eval_assignment(const Ast& ast, shared_ptr& env) { + static Value eval_assignment(const Ast& ast, shared_ptr env) { const auto& var = ast.nodes[0]->token; auto val = eval(*ast.nodes[1], env); env->set(var, val); return val; }; - static Value eval_identifier(const Ast& ast, shared_ptr& env) { + static Value eval_identifier(const Ast& ast, shared_ptr env) { const auto& var = ast.token; return dereference_identirier(env, var); }; - static Value eval_number(const Ast& ast, shared_ptr& env) { + static Value eval_number(const Ast& ast, shared_ptr env) { return Value(stol(ast.token)); }; - static Value eval_bool(const Ast& ast, shared_ptr& env) { + static Value eval_bool(const Ast& ast, shared_ptr env) { return Value(ast.token == "true"); }; - static Value eval_interpolated_string(const Ast& ast, shared_ptr& env) { + static Value eval_interpolated_string(const Ast& ast, shared_ptr env) { string s; for (auto node: ast.nodes) { const auto& val = eval(*node, env); @@ -185,7 +191,7 @@ private: return Value(s); }; - static Value dereference_identirier(shared_ptr& env, const string& var) { + static Value dereference_identirier(shared_ptr env, const string& var) { if (!env->has(var)) { string msg = "undefined variable '" + var + "'..."; throw runtime_error(msg); @@ -199,7 +205,7 @@ std::ostream& operator<<(std::ostream& os, const Value& val) return val.out(os); } -bool run(const string& path, shared_ptr& env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast) +bool run(const string& path, shared_ptr env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast) { try { shared_ptr ast; diff --git a/language/interpreter.hpp b/language/interpreter.hpp index ddc670a..bc42574 100755 --- a/language/interpreter.hpp +++ b/language/interpreter.hpp @@ -13,8 +13,8 @@ struct Value }; struct FunctionValue { - std::vector params; - std::function& env)> eval; + std::vector params; + std::function env)> eval; }; explicit Value() : type(Undefined) {} @@ -166,14 +166,19 @@ std::ostream& operator<<(std::ostream& os, const Value& val); struct Environment { Environment() = default; - Environment(std::shared_ptr& outer) : outer_(outer) {} + + void push_outer(std::shared_ptr outer) { + outers_.push_back(outer); + } bool has(const std::string& s) const { if (dic_.find(s) != dic_.end()) { return true; } - if (outer_) { - return outer_->has(s); + for (auto& outer: outers_) { + if (outer->has(s)) { + return true; + } } return false; } @@ -183,15 +188,23 @@ struct Environment if (dic_.find(s) != dic_.end()) { return dic_.at(s); } - return outer_->get(s); + for (auto& outer: outers_) { + if (outer->has(s)) { + return outer->get(s); + } + } + // NOT REACHED } void set(const std::string& s, const Value& val) { if (dic_.find(s) != dic_.end()) { dic_[s] = val; } - if (outer_ && outer_->has(s)) { - return outer_->set(s, val); + for (auto& outer: outers_) { + if (outer->has(s)) { + outer->set(s, val); + return; + } } dic_[s] = val; } @@ -199,7 +212,7 @@ struct Environment void setup_built_in_functions() { auto func_pretty_print = Value::FunctionValue { { "arg" }, - [](std::shared_ptr& env) { + [](std::shared_ptr env) { std::cout << env->get("arg").str() << std::endl; return Value(); } @@ -208,8 +221,8 @@ struct Environment } private: - std::shared_ptr outer_; + std::vector> outers_; std::map dic_; }; -bool run(const std::string& path, std::shared_ptr& env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast); +bool run(const std::string& path, std::shared_ptr env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast); diff --git a/language/repl.cc b/language/repl.cc index 9baf442..29835ba 100755 --- a/language/repl.cc +++ b/language/repl.cc @@ -4,7 +4,7 @@ using namespace std; -int repl(shared_ptr& env, bool print_ast) +int repl(shared_ptr env, bool print_ast) { for (;;) { auto line = linenoise::Readline("cul> "); diff --git a/language/repl.hpp b/language/repl.hpp index 1ae8005..d1a5ad4 100755 --- a/language/repl.hpp +++ b/language/repl.hpp @@ -1,5 +1,5 @@ #include "interpreter.hpp" -int repl(std::shared_ptr& env, bool print_ast); +int repl(std::shared_ptr env, bool print_ast); // vim: et ts=4 sw=4 cin cino={1s ff=unix