|
|
@ -9,9 +9,10 @@ const auto grammar_ = R"( |
|
|
|
|
|
|
|
|
|
|
|
PROGRAM <- _ STATEMENTS |
|
|
|
PROGRAM <- _ STATEMENTS |
|
|
|
STATEMENTS <- (STATEMENT (';' _)?)* |
|
|
|
STATEMENTS <- (STATEMENT (';' _)?)* |
|
|
|
STATEMENT <- DEBUGGER / EXPRESSION |
|
|
|
STATEMENT <- DEBUGGER / RETURN / EXPRESSION |
|
|
|
|
|
|
|
|
|
|
|
DEBUGGER <- 'debugger' _ |
|
|
|
DEBUGGER <- 'debugger' _ |
|
|
|
|
|
|
|
RETURN <- 'return' __ '\n' / 'return' _ EXPRESSION? |
|
|
|
|
|
|
|
|
|
|
|
EXPRESSION <- ASSIGNMENT / LOGICAL_OR |
|
|
|
EXPRESSION <- ASSIGNMENT / LOGICAL_OR |
|
|
|
|
|
|
|
|
|
|
@ -67,10 +68,11 @@ const auto grammar_ = R"( |
|
|
|
MUTABLE <- < 'mut'? > _ |
|
|
|
MUTABLE <- < 'mut'? > _ |
|
|
|
|
|
|
|
|
|
|
|
~_ <- (Space / EndOfLine / Comment)* |
|
|
|
~_ <- (Space / EndOfLine / Comment)* |
|
|
|
|
|
|
|
~__ <- (Space / Comment)* |
|
|
|
Space <- ' ' / '\t' |
|
|
|
Space <- ' ' / '\t' |
|
|
|
EndOfLine <- '\r\n' / '\n' / '\r' |
|
|
|
EndOfLine <- '\r\n' / '\n' / '\r' |
|
|
|
EndOfFile <- !. |
|
|
|
EndOfFile <- !. |
|
|
|
Comment <- '/*' (!'*/' .)* '*/' / ('#' / '//') (!(EndOfLine / EndOfFile) .)* (EndOfLine / EndOfFile)
|
|
|
|
Comment <- '/*' (!'*/' .)* '*/' / ('#' / '//') (!(EndOfLine / EndOfFile) .)* &(EndOfLine / EndOfFile)
|
|
|
|
|
|
|
|
|
|
|
|
)"; |
|
|
|
)"; |
|
|
|
|
|
|
|
|
|
|
@ -526,12 +528,21 @@ inline void setup_built_in_functions(Environment& env) { |
|
|
|
false); |
|
|
|
false); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct Eval |
|
|
|
struct Interpreter |
|
|
|
{ |
|
|
|
{ |
|
|
|
Eval(Debugger debugger = nullptr) |
|
|
|
Interpreter(Debugger debugger = nullptr) |
|
|
|
: debugger_(debugger) { |
|
|
|
: debugger_(debugger) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Value exec(const peglib::Ast& ast, std::shared_ptr<Environment> env) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
return eval(ast, env); |
|
|
|
|
|
|
|
} catch (const Value& val) { |
|
|
|
|
|
|
|
return val; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
Value eval(const peglib::Ast& ast, std::shared_ptr<Environment> env) { |
|
|
|
Value eval(const peglib::Ast& ast, std::shared_ptr<Environment> env) { |
|
|
|
using peglib::operator"" _; |
|
|
|
using peglib::operator"" _; |
|
|
|
|
|
|
|
|
|
|
@ -566,6 +577,7 @@ struct Eval |
|
|
|
case "NUMBER"_: return eval_number(ast, env); |
|
|
|
case "NUMBER"_: return eval_number(ast, env); |
|
|
|
case "INTERPOLATED_STRING"_: return eval_interpolated_string(ast, env); |
|
|
|
case "INTERPOLATED_STRING"_: return eval_interpolated_string(ast, env); |
|
|
|
case "DEBUGGER"_: return Value(); |
|
|
|
case "DEBUGGER"_: return Value(); |
|
|
|
|
|
|
|
case "RETURN"_: eval_return(ast, env); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (ast.is_token) { |
|
|
|
if (ast.is_token) { |
|
|
@ -576,7 +588,6 @@ struct Eval |
|
|
|
throw std::logic_error("invalid Ast type"); |
|
|
|
throw std::logic_error("invalid Ast type"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
Value eval_statements(const peglib::Ast& ast, std::shared_ptr<Environment> env) { |
|
|
|
Value eval_statements(const peglib::Ast& ast, std::shared_ptr<Environment> env) { |
|
|
|
if (ast.is_token) { |
|
|
|
if (ast.is_token) { |
|
|
|
return eval(ast, env); |
|
|
|
return eval(ast, env); |
|
|
@ -654,7 +665,11 @@ private: |
|
|
|
} |
|
|
|
} |
|
|
|
callEnv->initialize("__LINE__", Value((long)ast.line), false); |
|
|
|
callEnv->initialize("__LINE__", Value((long)ast.line), false); |
|
|
|
callEnv->initialize("__COLUMN__", Value((long)ast.column), false); |
|
|
|
callEnv->initialize("__COLUMN__", Value((long)ast.column), false); |
|
|
|
return f.eval(callEnv); |
|
|
|
try { |
|
|
|
|
|
|
|
return f.eval(callEnv); |
|
|
|
|
|
|
|
} catch (const Value& val) { |
|
|
|
|
|
|
|
return val; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::string msg = "arguments error..."; |
|
|
|
std::string msg = "arguments error..."; |
|
|
@ -901,6 +916,14 @@ private: |
|
|
|
return Value(std::move(s)); |
|
|
|
return Value(std::move(s)); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void eval_return(const peglib::Ast& ast, std::shared_ptr<Environment> env) { |
|
|
|
|
|
|
|
if (ast.nodes.empty()) { |
|
|
|
|
|
|
|
throw Value(); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
throw eval(*ast.nodes[0], env); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Debugger debugger_; |
|
|
|
Debugger debugger_; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
@ -924,8 +947,8 @@ inline bool run( |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
if (parser.parse_n(expr, len, ast, path.c_str())) { |
|
|
|
if (parser.parse_n(expr, len, ast, path.c_str())) { |
|
|
|
ast = peglib::AstOptimizer(true, { "PARAMETERS", "ARGUMENTS", "OBJECT", "ARRAY" }).optimize(ast); |
|
|
|
ast = peglib::AstOptimizer(true, { "PARAMETERS", "ARGUMENTS", "OBJECT", "ARRAY", "RETURN" }).optimize(ast); |
|
|
|
val = Eval(debugger).eval(*ast, env); |
|
|
|
val = Interpreter(debugger).exec(*ast, env); |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (std::runtime_error& e) { |
|
|
|
} catch (std::runtime_error& e) { |
|
|
|