Added closure support.

This commit is contained in:
yhirose 2015-06-01 17:56:39 -04:00
parent a4c9cec900
commit a7e2927efe
4 changed files with 51 additions and 32 deletions

View File

@ -7,7 +7,7 @@ using namespace std;
struct Eval
{
static Value eval(const Ast& ast, shared_ptr<Environment>& env) {
static Value eval(const Ast& ast, shared_ptr<Environment> 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<Environment>& env) {
static Value eval_statements(const Ast& ast, shared_ptr<Environment> 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<Environment>& env) {
static Value eval_while(const Ast& ast, shared_ptr<Environment> 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<Environment>& env) {
static Value eval_if(const Ast& ast, shared_ptr<Environment> 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<Environment>& env) {
static Value eval_function(const Ast& ast, shared_ptr<Environment> env) {
vector<string> 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<Environment>& callEnv) {
return eval(*body, callEnv);
}
[=](shared_ptr<Environment> 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<Environment>& env) {
static Value eval_function_call(const Ast& ast, shared_ptr<Environment> 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<Environment>(env);
auto callEnv = make_shared<Environment>();
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<Environment>& env) {
static Value eval_condition(const Ast& ast, shared_ptr<Environment> 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<Environment>& env) {
static Value eval_bin_expression(const Ast& ast, shared_ptr<Environment> 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<Environment>& env) {
static Value eval_assignment(const Ast& ast, shared_ptr<Environment> 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<Environment>& env) {
static Value eval_identifier(const Ast& ast, shared_ptr<Environment> env) {
const auto& var = ast.token;
return dereference_identirier(env, var);
};
static Value eval_number(const Ast& ast, shared_ptr<Environment>& env) {
static Value eval_number(const Ast& ast, shared_ptr<Environment> env) {
return Value(stol(ast.token));
};
static Value eval_bool(const Ast& ast, shared_ptr<Environment>& env) {
static Value eval_bool(const Ast& ast, shared_ptr<Environment> env) {
return Value(ast.token == "true");
};
static Value eval_interpolated_string(const Ast& ast, shared_ptr<Environment>& env) {
static Value eval_interpolated_string(const Ast& ast, shared_ptr<Environment> 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<Environment>& env, const string& var) {
static Value dereference_identirier(shared_ptr<Environment> 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<Environment>& env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast)
bool run(const string& path, shared_ptr<Environment> env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast)
{
try {
shared_ptr<Ast> ast;

View File

@ -13,8 +13,8 @@ struct Value
};
struct FunctionValue {
std::vector<std::string> params;
std::function<Value (std::shared_ptr<Environment>& env)> eval;
std::vector<std::string> params;
std::function<Value (std::shared_ptr<Environment> 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<Environment>& outer) : outer_(outer) {}
void push_outer(std::shared_ptr<Environment> 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<Environment>& env) {
[](std::shared_ptr<Environment> env) {
std::cout << env->get("arg").str() << std::endl;
return Value();
}
@ -208,8 +221,8 @@ struct Environment
}
private:
std::shared_ptr<Environment> outer_;
std::vector<std::shared_ptr<Environment>> outers_;
std::map<std::string, Value> dic_;
};
bool run(const std::string& path, std::shared_ptr<Environment>& env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast);
bool run(const std::string& path, std::shared_ptr<Environment> env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast);

View File

@ -4,7 +4,7 @@
using namespace std;
int repl(shared_ptr<Environment>& env, bool print_ast)
int repl(shared_ptr<Environment> env, bool print_ast)
{
for (;;) {
auto line = linenoise::Readline("cul> ");

View File

@ -1,5 +1,5 @@
#include "interpreter.hpp"
int repl(std::shared_ptr<Environment>& env, bool print_ast);
int repl(std::shared_ptr<Environment> env, bool print_ast);
// vim: et ts=4 sw=4 cin cino={1s ff=unix