mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2024-12-22 20:05:31 +00:00
Added 'mutable' support.
This commit is contained in:
parent
8ce5650924
commit
471ed98277
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user