|
|
@ -7,82 +7,90 @@ namespace culebra { |
|
|
|
|
|
|
|
|
|
|
|
const auto grammar_ = R"( |
|
|
|
const auto grammar_ = R"( |
|
|
|
|
|
|
|
|
|
|
|
PROGRAM <- _ STATEMENTS |
|
|
|
PROGRAM <- _ STATEMENTS _ |
|
|
|
STATEMENTS <- (STATEMENT (';' _)?)* |
|
|
|
STATEMENTS <- (STATEMENT (_sp_ (';' / _nl_) (_ STATEMENT)?)*)? |
|
|
|
STATEMENT <- DEBUGGER / RETURN / EXPRESSION |
|
|
|
STATEMENT <- DEBUGGER / RETURN / EXPRESSION |
|
|
|
|
|
|
|
|
|
|
|
DEBUGGER <- debugger |
|
|
|
DEBUGGER <- debugger |
|
|
|
RETURN <- return End _ / return EXPRESSION |
|
|
|
RETURN <- return (_sp_ !_nl_ EXPRESSION)? |
|
|
|
|
|
|
|
|
|
|
|
EXPRESSION <- ASSIGNMENT / LOGICAL_OR |
|
|
|
EXPRESSION <- ASSIGNMENT / LOGICAL_OR |
|
|
|
|
|
|
|
|
|
|
|
ASSIGNMENT <- MUTABLE PRIMARY (ARGUMENTS / INDEX / DOT)* '=' _ EXPRESSION |
|
|
|
ASSIGNMENT <- MUTABLE _ PRIMARY (_ (ARGUMENTS / INDEX / DOT))* _ '=' _ EXPRESSION |
|
|
|
|
|
|
|
|
|
|
|
LOGICAL_OR <- LOGICAL_AND ('||' _ LOGICAL_AND)* |
|
|
|
LOGICAL_OR <- LOGICAL_AND (_ '||' _ LOGICAL_AND)* |
|
|
|
LOGICAL_AND <- CONDITION ('&&' _ CONDITION)* |
|
|
|
LOGICAL_AND <- CONDITION (_ '&&' _ CONDITION)* |
|
|
|
CONDITION <- ADDITIVE (CONDITION_OPERATOR ADDITIVE)* |
|
|
|
CONDITION <- ADDITIVE (_ CONDITION_OPERATOR _ ADDITIVE)* |
|
|
|
ADDITIVE <- UNARY_PLUS (ADDITIVE_OPERATOR UNARY_PLUS)* |
|
|
|
ADDITIVE <- UNARY_PLUS (_ ADDITIVE_OPERATOR _ UNARY_PLUS)* |
|
|
|
UNARY_PLUS <- UNARY_PLUS_OPERATOR? UNARY_MINUS |
|
|
|
UNARY_PLUS <- UNARY_PLUS_OPERATOR? UNARY_MINUS |
|
|
|
UNARY_MINUS <- UNARY_MINUS_OPERATOR? UNARY_NOT |
|
|
|
UNARY_MINUS <- UNARY_MINUS_OPERATOR? UNARY_NOT |
|
|
|
UNARY_NOT <- UNARY_NOT_OPERATOR? MULTIPLICATIVE |
|
|
|
UNARY_NOT <- UNARY_NOT_OPERATOR? MULTIPLICATIVE |
|
|
|
MULTIPLICATIVE <- CALL (MULTIPLICATIVE_OPERATOR CALL)* |
|
|
|
MULTIPLICATIVE <- CALL (_ MULTIPLICATIVE_OPERATOR _ CALL)* |
|
|
|
|
|
|
|
|
|
|
|
CALL <- PRIMARY (ARGUMENTS / INDEX / DOT)* |
|
|
|
CALL <- PRIMARY (_ (ARGUMENTS / INDEX / DOT))* |
|
|
|
ARGUMENTS <- '(' _ (EXPRESSION (',' _ EXPRESSION)*)? ')' _ |
|
|
|
ARGUMENTS <- '(' _ (EXPRESSION (_ ',' _ EXPRESSION)*)? _ ')' |
|
|
|
INDEX <- '[' _ EXPRESSION ']' _ |
|
|
|
INDEX <- '[' _ EXPRESSION _ ']' |
|
|
|
DOT <- '.' _ IDENTIFIER |
|
|
|
DOT <- '.' _ IDENTIFIER |
|
|
|
|
|
|
|
|
|
|
|
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)? |
|
|
|
|
|
|
|
|
|
|
|
PRIMARY <- WHILE / IF / FUNCTION / OBJECT / ARRAY / UNDEFINED / BOOLEAN / NUMBER / IDENTIFIER / STRING / INTERPOLATED_STRING / '(' _ EXPRESSION ')' _ |
|
|
|
PRIMARY <- WHILE / IF / FUNCTION / OBJECT / ARRAY / UNDEFINED / BOOLEAN / NUMBER / IDENTIFIER / STRING / INTERPOLATED_STRING / '(' _ EXPRESSION _ ')' |
|
|
|
|
|
|
|
|
|
|
|
FUNCTION <- fn PARAMETERS BLOCK |
|
|
|
FUNCTION <- fn _ PARAMETERS _ BLOCK |
|
|
|
PARAMETERS <- '(' _ (PARAMETER (',' _ PARAMETER)*)? ')' _ |
|
|
|
PARAMETERS <- '(' _ (PARAMETER (_ ',' _ PARAMETER)*)? _ ')' |
|
|
|
PARAMETER <- MUTABLE IDENTIFIER |
|
|
|
PARAMETER <- MUTABLE _ IDENTIFIER |
|
|
|
|
|
|
|
|
|
|
|
BLOCK <- '{' _ STATEMENTS '}' _ |
|
|
|
BLOCK <- '{' _ STATEMENTS _ '}' |
|
|
|
|
|
|
|
|
|
|
|
CONDITION_OPERATOR <- < ('==' / '!=' / '<=' / '<' / '>=' / '>') > _ |
|
|
|
CONDITION_OPERATOR <- '==' / '!=' / '<=' / '<' / '>=' / '>' |
|
|
|
ADDITIVE_OPERATOR <- < [-+] > _ |
|
|
|
ADDITIVE_OPERATOR <- [-+] |
|
|
|
UNARY_PLUS_OPERATOR <- < '+' > _ |
|
|
|
UNARY_PLUS_OPERATOR <- '+' |
|
|
|
UNARY_MINUS_OPERATOR <- < '-' > _ |
|
|
|
UNARY_MINUS_OPERATOR <- '-' |
|
|
|
UNARY_NOT_OPERATOR <- < '!' > _ |
|
|
|
UNARY_NOT_OPERATOR <- '!' |
|
|
|
MULTIPLICATIVE_OPERATOR <- < [*/%] > _ |
|
|
|
MULTIPLICATIVE_OPERATOR <- [*/%] |
|
|
|
|
|
|
|
|
|
|
|
IDENTIFIER <- < IdentInitChar IdentChar* > _ |
|
|
|
MUTABLE <- < ('mut' _wd_)? > |
|
|
|
|
|
|
|
|
|
|
|
OBJECT <- '{' _ (OBJECT_PROPERTY (',' _ OBJECT_PROPERTY)*)? '}' _ |
|
|
|
IDENTIFIER <- < IdentInitChar IdentChar* > |
|
|
|
OBJECT_PROPERTY <- MUTABLE IDENTIFIER ':' _ EXPRESSION |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ARRAY <- '[' _ (EXPRESSION (',' _ EXPRESSION)*)? ']' _ |
|
|
|
OBJECT <- '{' _ (OBJECT_PROPERTY (_ ',' _ OBJECT_PROPERTY)*)? _ '}' |
|
|
|
|
|
|
|
OBJECT_PROPERTY <- MUTABLE _ IDENTIFIER _ ':' _ EXPRESSION |
|
|
|
|
|
|
|
|
|
|
|
UNDEFINED <- < 'undefined' > __ |
|
|
|
ARRAY <- '[' _ (EXPRESSION (',' _ EXPRESSION)*)? ']' |
|
|
|
BOOLEAN <- < ('true' / 'false') > __ |
|
|
|
|
|
|
|
MUTABLE <- (< 'mut' > __)? |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
~debugger <- 'debugger' __ |
|
|
|
UNDEFINED <- < 'undefined' _wd_ > |
|
|
|
~return <- 'return' !IdentInitChar Space* |
|
|
|
BOOLEAN <- < ('true' / 'false') _wd_ > |
|
|
|
~while <- 'while' __ |
|
|
|
|
|
|
|
~if <- 'if' __ |
|
|
|
|
|
|
|
~else <- 'else' __ |
|
|
|
|
|
|
|
~fn <- 'fn' __ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NUMBER <- < [0-9]+ > _ |
|
|
|
NUMBER <- < [0-9]+ > |
|
|
|
STRING <- ['] < (!['] .)* > ['] _ |
|
|
|
STRING <- ['] < (!['] .)* > ['] |
|
|
|
|
|
|
|
|
|
|
|
INTERPOLATED_STRING <- '"' ('{' _ EXPRESSION '}' / INTERPOLATED_CONTENT)* '"' _ |
|
|
|
INTERPOLATED_STRING <- '"' ('{' _ EXPRESSION _ '}' / INTERPOLATED_CONTENT)* '"' |
|
|
|
INTERPOLATED_CONTENT <- (!["{] .) (!["{] .)* |
|
|
|
INTERPOLATED_CONTENT <- (!["{] .) (!["{] .)* |
|
|
|
|
|
|
|
|
|
|
|
~_ <- (Space / End)* |
|
|
|
~debugger <- 'debugger' _wd_ |
|
|
|
__ <- !IdentInitChar (Space / End)* |
|
|
|
~while <- 'while' _wd_ |
|
|
|
~Space <- ' ' / '\t' / Comment |
|
|
|
~if <- 'if' _wd_ |
|
|
|
~End <- EndOfLine / EndOfFile |
|
|
|
~else <- 'else' _wd_ |
|
|
|
Comment <- '/*' (!'*/' .)* '*/' / ('#' / '//') (!End .)* &End
|
|
|
|
~fn <- 'fn' _wd_ |
|
|
|
|
|
|
|
~return <- 'return' _wd_ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
~_ <- (WhiteSpace / End)* |
|
|
|
|
|
|
|
~_sp_ <- SpaceChar* |
|
|
|
|
|
|
|
~_nl_ <- LineComment? End |
|
|
|
|
|
|
|
~_wd_ <- !IdentInitChar |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WhiteSpace <- SpaceChar / Comment |
|
|
|
|
|
|
|
End <- EndOfLine / EndOfFile |
|
|
|
|
|
|
|
Comment <- BlockComment / LineComment |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SpaceChar <- ' ' / '\t' |
|
|
|
EndOfLine <- '\r\n' / '\n' / '\r' |
|
|
|
EndOfLine <- '\r\n' / '\n' / '\r' |
|
|
|
EndOfFile <- !. |
|
|
|
EndOfFile <- !. |
|
|
|
IdentInitChar <- [a-zA-Z_] |
|
|
|
IdentInitChar <- [a-zA-Z_] |
|
|
|
IdentChar <- [a-zA-Z0-9_] |
|
|
|
IdentChar <- [a-zA-Z0-9_] |
|
|
|
|
|
|
|
BlockComment <- '/*' (!'*/' .)* '*/' |
|
|
|
|
|
|
|
LineComment <- ('#' / '//') (!End .)* &End
|
|
|
|
|
|
|
|
|
|
|
|
)"; |
|
|
|
)"; |
|
|
|
|
|
|
|
|
|
|
@ -208,6 +216,7 @@ struct Value |
|
|
|
const ObjectValue& to_object() const { |
|
|
|
const ObjectValue& to_object() const { |
|
|
|
switch (type) { |
|
|
|
switch (type) { |
|
|
|
case Object: return v.get<ObjectValue>(); |
|
|
|
case Object: return v.get<ObjectValue>(); |
|
|
|
|
|
|
|
case Array: return v.get<ArrayValue>(); |
|
|
|
default: throw std::runtime_error("type error."); |
|
|
|
default: throw std::runtime_error("type error."); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -533,15 +542,6 @@ struct Interpreter |
|
|
|
: debugger_(debugger) { |
|
|
|
: debugger_(debugger) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Value exec(const peg::Ast& ast, std::shared_ptr<Environment> env) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
return eval(ast, env); |
|
|
|
|
|
|
|
} catch (...) { |
|
|
|
|
|
|
|
return Value(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
Value eval(const peg::Ast& ast, std::shared_ptr<Environment> env) { |
|
|
|
Value eval(const peg::Ast& ast, std::shared_ptr<Environment> env) { |
|
|
|
using peg::operator"" _; |
|
|
|
using peg::operator"" _; |
|
|
|
|
|
|
|
|
|
|
@ -587,6 +587,7 @@ private: |
|
|
|
throw std::logic_error("invalid Ast type"); |
|
|
|
throw std::logic_error("invalid Ast type"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
Value eval_statements(const peg::Ast& ast, std::shared_ptr<Environment> env) { |
|
|
|
Value eval_statements(const peg::Ast& ast, std::shared_ptr<Environment> env) { |
|
|
|
if (ast.is_token) { |
|
|
|
if (ast.is_token) { |
|
|
|
return eval(ast, env); |
|
|
|
return eval(ast, env); |
|
|
@ -666,8 +667,8 @@ private: |
|
|
|
callEnv->initialize("__COLUMN__", Value((long)ast.column), false); |
|
|
|
callEnv->initialize("__COLUMN__", Value((long)ast.column), false); |
|
|
|
try { |
|
|
|
try { |
|
|
|
return f.eval(callEnv); |
|
|
|
return f.eval(callEnv); |
|
|
|
} catch (...) { |
|
|
|
} catch (const Value& val) { |
|
|
|
return Value(); |
|
|
|
return val; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -935,7 +936,7 @@ inline bool run( |
|
|
|
size_t len, |
|
|
|
size_t len, |
|
|
|
Value& val, |
|
|
|
Value& val, |
|
|
|
std::vector<std::string>& msgs, |
|
|
|
std::vector<std::string>& msgs, |
|
|
|
std::shared_ptr<peg::Ast>& ast, |
|
|
|
std::shared_ptr<peg::Ast>& ast, |
|
|
|
Debugger debugger = nullptr) |
|
|
|
Debugger debugger = nullptr) |
|
|
|
{ |
|
|
|
{ |
|
|
|
try { |
|
|
|
try { |
|
|
@ -949,7 +950,7 @@ inline bool run( |
|
|
|
|
|
|
|
|
|
|
|
if (parser.parse_n(expr, len, ast, path.c_str())) { |
|
|
|
if (parser.parse_n(expr, len, ast, path.c_str())) { |
|
|
|
ast = peg::AstOptimizer(true, { "PARAMETERS", "ARGUMENTS", "OBJECT", "ARRAY", "RETURN" }).optimize(ast); |
|
|
|
ast = peg::AstOptimizer(true, { "PARAMETERS", "ARGUMENTS", "OBJECT", "ARRAY", "RETURN" }).optimize(ast); |
|
|
|
val = Interpreter(debugger).exec(*ast, env); |
|
|
|
val = Interpreter(debugger).eval(*ast, env); |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (std::runtime_error& e) { |
|
|
|
} catch (std::runtime_error& e) { |
|
|
|