mirror of
https://github.com/yhirose/cpp-peglib.git
synced 2026-01-29 21:48:10 -05: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) {
|
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) {
|
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];
|
auto body = ast.nodes[1];
|
||||||
@ -95,19 +97,19 @@ private:
|
|||||||
const auto& var = ast.nodes[0]->token;
|
const auto& var = ast.nodes[0]->token;
|
||||||
const auto& args = ast.nodes[1]->nodes;
|
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();
|
const auto& fv = f.to_function();
|
||||||
|
|
||||||
if (fv.params.size() <= args.size()) {
|
if (fv.params.size() <= args.size()) {
|
||||||
auto callEnv = make_shared<Environment>();
|
auto callEnv = make_shared<Environment>();
|
||||||
|
|
||||||
callEnv->set("self", f);
|
callEnv->declare("self", f, false);
|
||||||
|
|
||||||
for (auto i = 0u; i < fv.params.size(); i++) {
|
for (auto i = 0u; i < fv.params.size(); i++) {
|
||||||
auto var = fv.params[i];
|
auto param = fv.params[i];
|
||||||
auto arg = args[i];
|
auto arg = args[i];
|
||||||
auto val = eval(*arg, env);
|
auto val = eval(*arg, env);
|
||||||
callEnv->set(var, val);
|
callEnv->declare(param.name, val, param.mut);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fv.eval(callEnv);
|
return fv.eval(callEnv);
|
||||||
@ -159,15 +161,20 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
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;
|
const auto& mut = ast.nodes[0]->token;
|
||||||
auto val = eval(*ast.nodes[1], env);
|
const auto& var = ast.nodes[1]->token;
|
||||||
env->set(var, val);
|
auto val = eval(*ast.nodes[2], env);
|
||||||
|
if (env->has(var)) {
|
||||||
|
env->assign(var, val);
|
||||||
|
} else {
|
||||||
|
env->declare(var, val, mut == "mut");
|
||||||
|
}
|
||||||
return 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;
|
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) {
|
static Value eval_number(const Ast& ast, shared_ptr<Environment> env) {
|
||||||
@ -186,14 +193,6 @@ private:
|
|||||||
}
|
}
|
||||||
return Value(std::move(s));
|
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)
|
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 {
|
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;
|
std::function<Value (std::shared_ptr<Environment> env)> eval;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -189,40 +193,58 @@ struct Environment
|
|||||||
|
|
||||||
Value get(const std::string& s) const {
|
Value get(const std::string& s) const {
|
||||||
if (dic_.find(s) != dic_.end()) {
|
if (dic_.find(s) != dic_.end()) {
|
||||||
return dic_.at(s);
|
return dic_.at(s).val;
|
||||||
}
|
}
|
||||||
if (outer_) {
|
if (outer_) {
|
||||||
return outer_->get(s);
|
return outer_->get(s);
|
||||||
}
|
}
|
||||||
// NOTREACHED
|
std::string msg = "undefined variable '" + s + "'...";
|
||||||
throw std::logic_error("invalid internal condition.");
|
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()) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (outer_ && outer_->has(s)) {
|
if (outer_ && outer_->has(s)) {
|
||||||
outer_->set(s, val);
|
outer_->assign(s, val);
|
||||||
return;
|
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() {
|
void setup_built_in_functions() {
|
||||||
set("pp", Value(Value::FunctionValue {
|
declare(
|
||||||
{ "arg" },
|
"pp",
|
||||||
[](std::shared_ptr<Environment> env) {
|
Value(Value::FunctionValue {
|
||||||
std::cout << env->get("arg").str() << std::endl;
|
{ {"arg", true} },
|
||||||
return Value();
|
[](std::shared_ptr<Environment> env) {
|
||||||
}
|
std::cout << env->get("arg").str() << std::endl;
|
||||||
}));
|
return Value();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct Symbol {
|
||||||
|
Value val;
|
||||||
|
bool mut;
|
||||||
|
};
|
||||||
|
|
||||||
std::shared_ptr<Environment> outer_;
|
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);
|
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*
|
STATEMENTS <- EXPRESSION*
|
||||||
|
|
||||||
EXPRESSION <- ASSIGNMENT / PRIMARY
|
EXPRESSION <- ASSIGNMENT / PRIMARY
|
||||||
ASSIGNMENT <- IDENTIFIER '=' _ EXPRESSION
|
ASSIGNMENT <- MUTABLE IDENTIFIER '=' _ EXPRESSION
|
||||||
WHILE <- 'while' _ EXPRESSION BLOCK
|
WHILE <- 'while' _ EXPRESSION BLOCK
|
||||||
IF <- 'if' _ EXPRESSION BLOCK ('else' _ 'if' _ EXPRESSION BLOCK)* ('else' _ BLOCK)?
|
IF <- 'if' _ EXPRESSION BLOCK ('else' _ 'if' _ EXPRESSION BLOCK)* ('else' _ BLOCK)?
|
||||||
FUNCTION <- 'fun' _ PARAMETERS BLOCK
|
FUNCTION <- 'fn' _ PARAMETERS BLOCK
|
||||||
PARAMETERS <- '(' _ (IDENTIFIER (',' _ IDENTIFIER)*)? ')' _
|
PARAMETERS <- '(' _ (PARAMETER (',' _ PARAMETER)*)? ')' _
|
||||||
|
PARAMETER <- MUTABLE IDENTIFIER
|
||||||
FUNCTION_CALL <- IDENTIFIER ARGUMENTS
|
FUNCTION_CALL <- IDENTIFIER ARGUMENTS
|
||||||
ARGUMENTS <- '(' _ (EXPRESSION (', ' _ EXPRESSION)*)? ')' _
|
ARGUMENTS <- '(' _ (EXPRESSION (', ' _ EXPRESSION)*)? ')' _
|
||||||
|
|
||||||
@ -36,6 +37,8 @@ static auto g_grammar = R"(
|
|||||||
INTERPOLATED_STRING <- '"' ('{' _ EXPRESSION '}' / INTERPOLATED_CONTENT)* '"' _
|
INTERPOLATED_STRING <- '"' ('{' _ EXPRESSION '}' / INTERPOLATED_CONTENT)* '"' _
|
||||||
INTERPOLATED_CONTENT <- (!["{] .) (!["{] .)*
|
INTERPOLATED_CONTENT <- (!["{] .) (!["{] .)*
|
||||||
|
|
||||||
|
MUTABLE <- < 'mut'? > _
|
||||||
|
|
||||||
~_ <- (Space / EndOfLine / Comment)*
|
~_ <- (Space / EndOfLine / Comment)*
|
||||||
Space <- ' ' / '\t'
|
Space <- ' ' / '\t'
|
||||||
EndOfLine <- '\r\n' / '\n' / '\r'
|
EndOfLine <- '\r\n' / '\n' / '\r'
|
||||||
@ -81,6 +84,7 @@ peg& get_parser()
|
|||||||
{ peg::AstNodeType::Token, "IDENTIFIER", Identifier },
|
{ peg::AstNodeType::Token, "IDENTIFIER", Identifier },
|
||||||
{ peg::AstNodeType::Regular, "INTERPOLATED_STRING", InterpolatedString },
|
{ peg::AstNodeType::Regular, "INTERPOLATED_STRING", InterpolatedString },
|
||||||
{ peg::AstNodeType::Token, "INTERPOLATED_CONTENT", Undefined },
|
{ peg::AstNodeType::Token, "INTERPOLATED_CONTENT", Undefined },
|
||||||
|
{ peg::AstNodeType::Token, "MUTABLE", Undefined },
|
||||||
},
|
},
|
||||||
Undefined);
|
Undefined);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user