Added 'mutable' support.

This commit is contained in:
yhirose 2015-06-03 18:39:10 -04:00
parent 8ce5650924
commit 471ed98277
3 changed files with 62 additions and 37 deletions

View File

@ -75,9 +75,11 @@ private:
}
static Value eval_function(const Ast& ast, shared_ptr<Environment> env) {
vector<string> params;
vector<Value::FunctionValue::Parameter> params;
for (auto node: ast.nodes[0]->nodes) {
params.push_back(node->token);
auto mut = node->nodes[0]->token == "mut";
const auto& name = node->nodes[1]->token;
params.push_back({ name, mut });
}
auto body = ast.nodes[1];
@ -95,19 +97,19 @@ private:
const auto& var = ast.nodes[0]->token;
const auto& args = ast.nodes[1]->nodes;
const auto& f = dereference_identirier(env, var);
const auto& f = env->get(var);
const auto& fv = f.to_function();
if (fv.params.size() <= args.size()) {
auto callEnv = make_shared<Environment>();
callEnv->set("self", f);
callEnv->declare("self", f, false);
for (auto i = 0u; i < fv.params.size(); i++) {
auto var = fv.params[i];
auto param = fv.params[i];
auto arg = args[i];
auto val = eval(*arg, env);
callEnv->set(var, val);
callEnv->declare(param.name, val, param.mut);
}
return fv.eval(callEnv);
@ -159,15 +161,20 @@ private:
}
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);
const auto& mut = ast.nodes[0]->token;
const auto& var = ast.nodes[1]->token;
auto val = eval(*ast.nodes[2], env);
if (env->has(var)) {
env->assign(var, val);
} else {
env->declare(var, val, mut == "mut");
}
return val;
};
static Value eval_identifier(const Ast& ast, shared_ptr<Environment> env) {
const auto& var = ast.token;
return dereference_identirier(env, var);
return env->get(var);
};
static Value eval_number(const Ast& ast, shared_ptr<Environment> env) {
@ -186,14 +193,6 @@ private:
}
return Value(std::move(s));
};
static Value dereference_identirier(shared_ptr<Environment> env, const string& var) {
if (!env->has(var)) {
string msg = "undefined variable '" + var + "'...";
throw runtime_error(msg);
}
return env->get(var);
};
};
bool run(const string& path, shared_ptr<Environment> env, const char* expr, size_t len, Value& val, std::string& msg, bool print_ast)

View File

@ -13,7 +13,11 @@ struct Value
};
struct FunctionValue {
std::vector<std::string> params;
struct Parameter {
std::string name;
bool mut;
};
std::vector<Parameter> params;
std::function<Value (std::shared_ptr<Environment> env)> eval;
};
@ -189,40 +193,58 @@ struct Environment
Value get(const std::string& s) const {
if (dic_.find(s) != dic_.end()) {
return dic_.at(s);
return dic_.at(s).val;
}
if (outer_) {
return outer_->get(s);
}
// NOTREACHED
throw std::logic_error("invalid internal condition.");
std::string msg = "undefined variable '" + s + "'...";
throw std::runtime_error(msg);
}
void set(const std::string& s, const Value& val) {
void assign(const std::string& s, const Value& val) {
assert(has(s));
if (dic_.find(s) != dic_.end()) {
dic_[s] = val;
auto& sym = dic_[s];
if (!sym.mut) {
std::string msg = "immutable variable '" + s + "'...";
throw std::runtime_error(msg);
}
sym.val = val;
return;
}
if (outer_ && outer_->has(s)) {
outer_->set(s, val);
outer_->assign(s, val);
return;
}
dic_[s] = val;
}
void declare(const std::string& s, const Value& val, bool mut) {
assert(!has(s));
dic_[s] = Symbol{val, mut};
}
void setup_built_in_functions() {
set("pp", Value(Value::FunctionValue {
{ "arg" },
[](std::shared_ptr<Environment> env) {
std::cout << env->get("arg").str() << std::endl;
return Value();
}
}));
declare(
"pp",
Value(Value::FunctionValue {
{ {"arg", true} },
[](std::shared_ptr<Environment> env) {
std::cout << env->get("arg").str() << std::endl;
return Value();
}
}),
false);
}
private:
struct Symbol {
Value val;
bool mut;
};
std::shared_ptr<Environment> outer_;
std::map<std::string, Value> dic_;
std::map<std::string, Symbol> 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);

View File

@ -9,11 +9,12 @@ static auto g_grammar = R"(
STATEMENTS <- EXPRESSION*
EXPRESSION <- ASSIGNMENT / PRIMARY
ASSIGNMENT <- IDENTIFIER '=' _ EXPRESSION
ASSIGNMENT <- MUTABLE IDENTIFIER '=' _ EXPRESSION
WHILE <- 'while' _ EXPRESSION BLOCK
IF <- 'if' _ EXPRESSION BLOCK ('else' _ 'if' _ EXPRESSION BLOCK)* ('else' _ BLOCK)?
FUNCTION <- 'fun' _ PARAMETERS BLOCK
PARAMETERS <- '(' _ (IDENTIFIER (',' _ IDENTIFIER)*)? ')' _
FUNCTION <- 'fn' _ PARAMETERS BLOCK
PARAMETERS <- '(' _ (PARAMETER (',' _ PARAMETER)*)? ')' _
PARAMETER <- MUTABLE IDENTIFIER
FUNCTION_CALL <- IDENTIFIER ARGUMENTS
ARGUMENTS <- '(' _ (EXPRESSION (', ' _ EXPRESSION)*)? ')' _
@ -36,6 +37,8 @@ static auto g_grammar = R"(
INTERPOLATED_STRING <- '"' ('{' _ EXPRESSION '}' / INTERPOLATED_CONTENT)* '"' _
INTERPOLATED_CONTENT <- (!["{] .) (!["{] .)*
MUTABLE <- < 'mut'? > _
~_ <- (Space / EndOfLine / Comment)*
Space <- ' ' / '\t'
EndOfLine <- '\r\n' / '\n' / '\r'
@ -81,6 +84,7 @@ peg& get_parser()
{ peg::AstNodeType::Token, "IDENTIFIER", Identifier },
{ peg::AstNodeType::Regular, "INTERPOLATED_STRING", InterpolatedString },
{ peg::AstNodeType::Token, "INTERPOLATED_CONTENT", Undefined },
{ peg::AstNodeType::Token, "MUTABLE", Undefined },
},
Undefined);
}