@ -0,0 +1,316 @@ | |||||
# minproto.leg -- minimal prototype langauge for semantic experiments | |||||
# | |||||
# last edited: 2024-07-04 10:07:00 by piumarta on zora | |||||
start = - ( s:stmt { global yysval = s } | |||||
| !. { global yysval = 0 } | |||||
| < (!EOL .)* > { syntaxError(yytext) } | |||||
) | |||||
stmt = WHILE LPAREN c:expr RPAREN s:stmt { $$ = newWhile(c, s) } | |||||
| IF LPAREN c:expr RPAREN s:stmt | |||||
( ELSE t:stmt { $$ = newIf(c, s, t ) } | |||||
| { $$ = newIf(c, s, nil) } | |||||
) | |||||
| CONT EOS { $$ = newContinue() } | |||||
| BREAK e:expr EOS { $$ = newBreak(e) } | |||||
| BREAK EOS { $$ = newBreak(nil) } | |||||
| RETURN e:expr EOS { $$ = newReturn(e) } | |||||
| RETURN EOS { $$ = newReturn(nil) } | |||||
| FOR LPAREN i:id IN e:expr RPAREN | |||||
s:stmt { $$ = newForIn(i, e, s) } | |||||
| FOR LPAREN i:id FROM a:expr | |||||
TO b:expr RPAREN s:stmt { $$ = newForFromTo(i, a, b, s) } | |||||
| FOR LPAREN i:expr SEMI c:expr SEMI | |||||
u:expr RPAREN s:stmt { $$ = newFor(i, c, u, s) } | |||||
| TRY t:stmt | |||||
( CATCH LPAREN i:id RPAREN c:stmt { $$ = newTryCatch(t, i, c) } | |||||
| ENSURE e:stmt { $$ = newTryEnsure(t, e) } | |||||
) | |||||
| RAISE e:expr EOS { $$ = newRaise(e) } | |||||
| LOCAL i:id p:params b:block { $$ = newSetLocal (i, newLambda(p, b, nil, i)) } | |||||
| GLOBAL i:id p:params b:block { $$ = newSetGlobal(i, newLambda(p, b, nil, i)) } | |||||
| i:id p:params b:block { $$ = newSetVar (i, newLambda(p, b, nil, i)) } | |||||
| v:proto DOT i:id p:params b:block { $$ = newSetProp(v, i, newLambda(p, b, v, i)) } | |||||
| b:block { $$ = newBlock(b) } | |||||
| e:expr EOS { $$ = e } | |||||
proto = v:var ( DOT j:id !LPAREN { v = newGetProp(v, j) } | |||||
)* { $$ = v } | |||||
EOS = SEMI+ | &RBRACE | &ELSE | &CATCH | |||||
expr = LOCAL i:id ASSIGN e:expr { $$ = newSetLocal (i, e) } | |||||
| GLOBAL i:id ASSIGN e:expr { $$ = newSetGlobal(i, e) } | |||||
| i:id ASSIGN e:expr { $$ = newSetVar (i, e) } | |||||
| l:logor ( ASSIGN r:expr { l = assign(l, r) } | |||||
| PLUSEQ r:expr { l = newBinop(opPreAdd, lvalue(l), r) } | |||||
| MINUSEQ r:expr { l = newBinop(opPreSub, lvalue(l), r) } | |||||
| STAREQ r:expr { l = newBinop(opPreMul, lvalue(l), r) } | |||||
| SLASHEQ r:expr { l = newBinop(opPreDiv, lvalue(l), r) } | |||||
| PCENTEQ r:expr { l = newBinop(opPreMod, lvalue(l), r) } | |||||
| SHLEQ r:expr { l = newBinop(opPreShl, lvalue(l), r) } | |||||
| SHREQ r:expr { l = newBinop(opPreShr, lvalue(l), r) } | |||||
| ANDEQ r:expr { l = newBinop(opPreAnd, lvalue(l), r) } | |||||
| XOREQ r:expr { l = newBinop(opPreXor, lvalue(l), r) } | |||||
| OREQ r:expr { l = newBinop(opPreOr, lvalue(l), r) } | |||||
)? { $$ = l } | |||||
logor = l:logand ( BARBAR r:logand { l = newBinop(opLogOr, l, r) } | |||||
)* { $$ = l } | |||||
logand = l:bitor ( ANDAND r:bitor { l = newBinop(opLogAnd, l, r) } | |||||
)* { $$ = l } | |||||
bitor = l:bitxor ( OR r:bitxor { l = newBinop(opBitOr, l, r) } | |||||
)* { $$ = l } | |||||
bitxor = l:bitand ( XOR r:bitand { l = newBinop(opBitXor, l, r) } | |||||
)* { $$ = l } | |||||
bitand = l:eq ( AND r:eq { l = newBinop(opBitAnd, l, r) } | |||||
)* { $$ = l } | |||||
eq = l:ineq ( EQ r:ineq { l = newBinop(opEq, l, r) } | |||||
| NOTEQ r:ineq { l = newBinop(opNotEq, l, r) } | |||||
)* { $$ = l } | |||||
ineq = l:shift ( LESS r:shift { l = newBinop(opLess, l, r) } | |||||
| LESSEQ r:shift { l = newBinop(opLessEq, l, r) } | |||||
| GRTREQ r:shift { l = newBinop(opGrtrEq, l, r) } | |||||
| GRTR r:shift { l = newBinop(opGrtr, l, r) } | |||||
)* { $$ = l } | |||||
shift = l:sum ( SHL r:sum { l = newBinop(opShl, l, r) } | |||||
| SHR r:sum { l = newBinop(opShr, l, r) } | |||||
)* { $$ = l } | |||||
sum = l:prod ( PLUS r:prod { l = newBinop(opAdd, l, r) } | |||||
| MINUS r:prod { l = newBinop(opSub, l, r) } | |||||
)* { $$ = l } | |||||
prod = l:prefix ( STAR r:prefix { l = newBinop(opMul, l, r) } | |||||
| SLASH r:prefix { l = newBinop(opDiv, l, r) } | |||||
| PCENT r:prefix { l = newBinop(opMod, l, r) } | |||||
) * { $$ = l } | |||||
prefix = PPLUS p:prefix { $$ = newBinop(opPreAdd, lvalue(p), newInteger(1)) } | |||||
| MMINUS p:prefix { $$ = newBinop(opPreSub, lvalue(p), newInteger(1)) } | |||||
| PLING p:prefix { $$ = newUnyop(opNot, p) } | |||||
| MINUS p:prefix { $$ = newUnyop(opNeg, p) } | |||||
| TILDE p:prefix { $$ = newUnyop(opCom, p) } | |||||
| BQUOTE s:stmt { $$ = newUnyop(opQuasiquote, s) } | |||||
| COMMAT e:expr { $$ = newUnyop(opUnquote, e) } | |||||
| postfix | |||||
postfix = SUPER DOT i:id a:args { $$ = newSuper(i, a) } | |||||
| p:primary | |||||
( LBRAK | |||||
( COLON ( RBRAK { p = newGetSlice(p, nil, nil) } | |||||
| e:xexpr RBRAK { p = newGetSlice(p, nil, e) } | |||||
) | |||||
| s:xexpr ( COLON ( RBRAK { p = newGetSlice(p, s, nil) } | |||||
| e:xexpr RBRAK { p = newGetSlice(p, s, e) } | |||||
) | |||||
| RBRAK { p = newGetArray(p, s) } | |||||
) | |||||
) | |||||
| DOT i:id ( a:args !LBRACE { p = newInvoke(p, i, a) } | |||||
| { p = newGetProp(p, i) } | |||||
) | |||||
| a:args !LBRACE { p = newApply(p, a) } | |||||
)* | |||||
( PPLUS { p = newBinop(opPostAdd, lvalue(p), newInteger( 1)) } | |||||
| MMINUS { p = newBinop(opPostAdd, lvalue(p), newInteger(-1)) } | |||||
)? { $$ = p } | |||||
args = LPAREN a:mkobj | |||||
( RPAREN | |||||
| ( k:id COLON e:xexpr { Object_put(a, k, e) } | |||||
| e:xexpr { Object_push(a, e) } | |||||
) | |||||
( COMMA ( k:id COLON e:xexpr { Object_put(a, k, e) } | |||||
| e:xexpr { Object_push(a, e) } | |||||
) )* RPAREN ) { $$ = a } | |||||
params = LPAREN p:mkobj | |||||
( RPAREN | |||||
| i:id ( COLON e:expr { Object_put(p, i, e) } | |||||
| { Object_push(p, i) } | |||||
) | |||||
( COMMA i:id ( COLON e:expr { Object_put(p, i, e) } | |||||
| { Object_push(p, i) } | |||||
) | |||||
)* RPAREN ) { $$ = p } | |||||
mkobj = { $$ = (global new)(pObject) } | |||||
primary = nil | number | string | symbol | var | lambda | subexpr | literal # | regex | |||||
lambda = p:params b:block { $$ = newLambda(p, b, nil, nil) } | |||||
subexpr = LPAREN e:expr RPAREN { $$ = e } | |||||
| b:block { $$ = newBlock(b) } | |||||
literal = LBRAK o:mkobj | |||||
( RBRAK | |||||
| ( ( i:id COLON e:expr { Object_put(o, i, e) } | |||||
| e:expr { Object_push(o, e) } | |||||
) ( COMMA ( i:id COLON e:expr { Object_put(o, i, e) } | |||||
| e:expr { Object_push(o, e) } | |||||
) )* )? RBRAK ) { $$ = newLiteral(o) } | |||||
block = LBRACE b:mkobj | |||||
( e:stmt { Object_push(b, e) } | |||||
)* ( RBRACE { $$ = b } | |||||
| error @{ expected("statement or \x7D", yytext) } | |||||
) | |||||
nil = NIL { $$ = nil } | |||||
number = "-" n:unsign { $$ = neg(n) } | |||||
| "+" n:number { $$ = n } | |||||
| n:unsign { $$ = n } | |||||
unsign = < DIGIT* '.' DIGIT+ EXP? > - { $$ = newFloat(strtod(yytext, 0)) } | |||||
| "0" [bB] < BIGIT+ > - { $$ = newInteger(strtol(yytext, 0, 2)) } | |||||
| "0" [xX] < HIGIT+ > - { $$ = newInteger(strtol(yytext, 0, 16)) } | |||||
| "0" < OIGIT* > - { $$ = newInteger(strtol(yytext, 0, 8)) } | |||||
| < DIGIT+ > - { $$ = newInteger(strtol(yytext, 0, 10)) } | |||||
| "'" < char > "'" - { $$ = newInteger(_get(newStringUnescaped(yytext), String,value)[0]) } | |||||
string = '"' < ( !'"' char )* > '"' - { $$ = newStringUnescaped(yytext) } | |||||
char = '\\' [abefnrtv'"\[\]\\] | |||||
| '\\' [0-3][0-7][0-7] | |||||
| '\\' [xX] HIGIT* | |||||
| '\\' [0-7][0-7]? | |||||
| !'\\' . | |||||
# char = "\\" ( ["'\\abfnrtv] | |||||
# | [xX] HIGIT* | |||||
# | [0-7][0-7]?[0-7]? | |||||
# ) | |||||
# | . | |||||
symbol = HASH i:id { $$ = i } | |||||
var = LOCAL i:id { $$ = newGetLocal (i) } | |||||
| GLOBAL i:id { $$ = newGetGlobal(i) } | |||||
| i:id { $$ = newGetVar (i) } | |||||
id = < LETTER ALNUM* > - { $$ = intern(yytext) } | |||||
# regex = SLASH a:alts SLASH { $$ = a } | |||||
# alts = s:seq ( OR t:seq { s = Alt_append(t) } | |||||
# )* { $$ = s } | |||||
# seq = p:pre ( q:pre { s = Seq_append(t) } | |||||
# )* { $$ = s } | |||||
# elt = action | pre | |||||
# action = b:block { $$ = newAction(b) } | |||||
# pre = PLING p:pre { $$ = newNot(p) } | |||||
# | AND p:pre { $$ = newAnd(p) } | |||||
# | post | |||||
# post = a:atom ( STAR { a = newMany(a) } | |||||
# | PLUS { a = newMore(a) } | |||||
# | QUERY { a = newMore(a) } | |||||
# )? { $$ = a } | |||||
# atom = DOT { $$ = newDot() } | |||||
# | "[" ( !"]" "\\"? . )* "]" - { $$ = newClass(yytext) } | |||||
# | '"' xxxxxx | |||||
# class = LBRAK | |||||
BIGIT = [0-1] | |||||
OIGIT = [0-7] | |||||
DIGIT = [0-9] | |||||
HIGIT = [0-9A-Fa-f] | |||||
LETTER = [A-Za-z_$?] | |||||
ALNUM = LETTER | DIGIT | |||||
SIGN = [-+] | |||||
EXP = [eE] SIGN DIGIT+ | |||||
- = SPACE* | |||||
SPACE = [ \t] | EOL | SLC | MLC | |||||
EOL = [\n\r] { ++lineno } | |||||
SLC = "//" (!EOL .)* | |||||
MLC = "/*" ( MLC | !"*/" (EOL | .))* "*/" - | |||||
NIL = "nil" !ALNUM - | |||||
WHILE = "while" !ALNUM - | |||||
IF = "if" !ALNUM - | |||||
ELSE = "else" !ALNUM - | |||||
FOR = "for" !ALNUM - | |||||
IN = "in" !ALNUM - | |||||
FROM = "from" !ALNUM - | |||||
TO = "to" !ALNUM - | |||||
CONT = "continue" !ALNUM - | |||||
BREAK = "break" !ALNUM - | |||||
RETURN = "return" !ALNUM - | |||||
TRY = "try" !ALNUM - | |||||
CATCH = "catch" !ALNUM - | |||||
ENSURE = "ensure" !ALNUM - | |||||
RAISE = "raise" !ALNUM - | |||||
GLOBAL = "global" !ALNUM - | |||||
LOCAL = "local" !ALNUM - | |||||
SUPER = "super" !ALNUM - | |||||
BQUOTE = "`" - | |||||
COMMAT = "@" - | |||||
HASH = "#" - | |||||
SEMI = ";" - | |||||
ASSIGN = "=" ![=] - | |||||
COMMA = "," - | |||||
COLON = ":" ![:] - | |||||
LPAREN = "(" - | |||||
RPAREN = ")" - | |||||
LBRAK = "[" - | |||||
RBRAK = "]" - | |||||
LBRACE = "{" - | |||||
RBRACE = "}" - | |||||
BARBAR = "||" ![=] - | |||||
ANDAND = "&&" ![=] - | |||||
OR = "|" ![|=] - | |||||
OREQ = "|=" - | |||||
XOR = "^" ![=] - | |||||
XOREQ = "^=" - | |||||
AND = "&" ![&=] - | |||||
ANDEQ = "&=" - | |||||
EQ = "==" - | |||||
NOTEQ = "!=" - | |||||
LESS = "<" ![<=] - | |||||
LESSEQ = "<=" - | |||||
GRTREQ = ">=" - | |||||
GRTR = ">" ![=] - | |||||
SHL = "<<" ![=] - | |||||
SHLEQ = "<<=" - | |||||
SHR = ">>" ![=] - | |||||
SHREQ = ">>=" - | |||||
PLUS = "+" ![+=] - | |||||
PLUSEQ = "+=" - | |||||
PPLUS = "++" - | |||||
MINUS = "-" ![-=] - | |||||
MINUSEQ = "-=" - | |||||
MMINUS = "--" - | |||||
STAR = "*" ![=] - | |||||
STAREQ = "*=" - | |||||
SLASH = "/" ![/=] - | |||||
SLASHEQ = "/=" - | |||||
PCENT = "%" ![=] - | |||||
PCENTEQ = "%=" - | |||||
DOT = "." ![.] - | |||||
PLING = "!" ![=] - | |||||
TILDE = "~" - | |||||
error = - < (!EOL .)* > | |||||
xexpr = expr | error @{ expected("expression", yytext) } | |||||
@ -0,0 +1,73 @@ | |||||
statement = b:block { b; } | |||||
| e:expression SEMI { e; } | |||||
expression = p:primary | |||||
( DOT i:id ASSIGN e:expression # { $$ = newSetProp(p, i, e) } | |||||
| LBRAK i:expression RBRAK ASSIGN e:expression { SetArray.new(object: p, index: i, value: e); } | |||||
) | |||||
| i:id ASSIGN e:expression { SetVar.new(name: i, value: e); } | |||||
| pf:postfix { pf; } | |||||
postfix = p:primary | |||||
( DOT i:id a:args !ASSIGN !LBRACE { p = Invoke.new(self: p, method: i, arguments: a); } | |||||
| DOT i:id !ASSIGN { p = GetProp.new(object: p, key: i); } | |||||
| a:args !ASSIGN !LBRACE { p = Call.new(function: p, arguments: a); } | |||||
) * { p; } | |||||
args = LPAREN a:mklist | |||||
( | |||||
( k:id COLON e:expression { a[k] = e; } | |||||
| e:expression { a.push(e); } | |||||
) | |||||
( COMMA | |||||
( k:id COLON e:expression { a[k] = e; } | |||||
| e:expression { a.push(e); } | |||||
) | |||||
) * | |||||
) ? RPAREN { a; } | |||||
mklist = { Object.new(); } | |||||
primary = nil | number | var | subExpr | |||||
subExpr = LPAREN e:expression RPAREN { e; } | |||||
block = LBRACE b:mklist | |||||
( e:statement { b.push(e); } | |||||
) * RBRACE { Block.new(body: b); } | |||||
nil = NIL { nil; } | |||||
number = "-" n:unsign { Unyop.new(operation: __opNeg).push(n) } | |||||
| "+" n:number { n } | |||||
| n:unsign { n } | |||||
unsign = < DIGIT+ > - { yytext.asInteger(10); } | |||||
var = i:id { GetVar.new(name: i); } | |||||
id = < LETTER ALNUM* > - { intern(yytext); } | |||||
DIGIT = [0-9] | |||||
LETTER = [A-Za-z_] | |||||
ALNUM = LETTER | DIGIT | |||||
NIL = "nil" !ALNUM - | |||||
SEMI = ";" - | |||||
COMMA = "," - | |||||
LPAREN = "(" - | |||||
RPAREN = ")" - | |||||
LBRAK = "[" - | |||||
RBRAK = "]" - | |||||
LBRACE = "{" - | |||||
RBRACE = "}" - | |||||
COLON = ":" ![:] - | |||||
ASSIGN = "=" ![=] - | |||||
DOT = "." ![.] - | |||||
- = ( space | comment )* | |||||
space = ' ' | '\t' | end-of-line | |||||
comment = '//' ( !end-of-line . )* end-of-line | |||||
end-of-line = '\r\n' | '\n' | '\r' | |||||
end-of-file = !. |
@ -0,0 +1,79 @@ | |||||
grammar = - ( d:definition { d; } | |||||
| end-of-file { nil; } | |||||
) | |||||
definition = i:identifier ASSIGN e:expression SEMI? { Definition.new(name: i, expression: e); } | |||||
expression = s:sequence !BAR { s; } | |||||
| s1:sequence { s1 = Alternation.new().push(s1); } | |||||
( BAR s2:sequence { s1.push(s2); } | |||||
) * { s1; } | |||||
sequence = p:prefix ( q:prefix { p = Sequence.new().push(p).push(q); } | |||||
( q:prefix { p.push(q); } | |||||
) * ) ? { p; } | |||||
prefix = AND a:action { ParseTimeAction.new(action: a); } | |||||
| AT a:action { ExecuteAction.new(action: a); } | |||||
| | |||||
( AND s:suffix { And.new(expression: s); } | |||||
| NOT s:suffix { Not.new(expression: s); } | |||||
| s:suffix { s; } | |||||
) | |||||
suffix = p:primary | |||||
( QUERY { p = Optional.new(expression: p); } | |||||
| STAR { p = Star.new(expression: p); } | |||||
| PLUS { p = Plus.new(expression: p); } | |||||
) ? { p; } | |||||
primary = i1:identifier COLON i2:ruleCall !ASSIGN { Assignment.new(name: i1, rule: i2); } | |||||
| i:ruleCall !ASSIGN { i; } | |||||
| LPAREN e:expression RPAREN { e; } | |||||
| l:literal { l; } | |||||
| c:class { c; } | |||||
| DOT { Dot.new(); } | |||||
| a:action { a; } | |||||
| BEGIN e:expression END { Capture.new(expression: e); } | |||||
identifier = < [-a-zA-Z_][-a-zA-Z_0-9]* > - { intern(yytext); } | |||||
ruleCall = n:identifier CCOLON r:identifier { NamespacedRuleCall.new(namespace: n, name: r); } | |||||
| i:identifier { RuleCall.new(name: i); } | |||||
literal = ['] < ( !['] char )* > ['] - { StringLiteral.new(string: yytext); } | |||||
| ["] < ( !["] char )* > ["] - { StringLiteral.new(string: yytext); } | |||||
class = '[' < ( !']' range )* > ']' - { CharacterClass.new(value: yytext); } | |||||
range = char '-' char | char | |||||
char = '\\' [abefnrtv'"\[\]\\] | |||||
| '\\' [0-3][0-7][0-7] | |||||
| '\\' [0-7][0-7]? | |||||
| !'\\' . | |||||
action = m:metaLanguage::block - { Action.new(parseTree: Block.new(body: m)); } | |||||
- = ( space | comment )* | |||||
space = ' ' | '\t' | end-of-line | |||||
comment = '#' ( !end-of-line . )* end-of-line | |||||
end-of-line = '\r\n' | '\n' | '\r' | |||||
end-of-file = !. | |||||
BAR = '|' - | |||||
NOT = '!' - | |||||
QUERY = '?' - | |||||
BEGIN = '<' - | |||||
END = '>' - | |||||
SEMI = ";" - | |||||
CCOLON = "::" - | |||||
LPAREN = "(" - | |||||
RPAREN = ")" - | |||||
ASSIGN = "=" ![=] - | |||||
AND = "&" ![&=] - | |||||
PLUS = "+" ![+=] - | |||||
STAR = "*" ![=] - | |||||
DOT = "." ![.] - | |||||
COLON = ":" ![:] - | |||||
AT = "@" - |
@ -0,0 +1,275 @@ | |||||
start = - ( s:stmt { s; } | |||||
| !. # { yysval = 0 } | |||||
| < (!EOL .)* > # { fatal("syntax error near: %s", yytext) } | |||||
) | |||||
stmt = WHILE LPAREN c:expr RPAREN s:stmt { While.new(condition: c, body: s) } | |||||
| IF LPAREN c:expr RPAREN s:stmt | |||||
( ELSE t:stmt { If.new(condition: c, consequent: s, alternate: t ) } | |||||
| { If.new(condition: c, consequent: s, alternate: nil) } | |||||
) | |||||
| CONT EOS { Continue.new() } | |||||
| BREAK e:expr EOS { Break.new(value: e) } | |||||
| BREAK EOS { Break.new(value: nil) } | |||||
| RETURN e:expr EOS { Return.new(value: e) } | |||||
| RETURN EOS { Return.new(value: nil) } | |||||
| FOR LPAREN i:id IN e:expr RPAREN | |||||
s:stmt { ForIn.new(identifier: i, expression: e, body: s) } | |||||
| FOR LPAREN i:id FROM a:expr | |||||
TO b:expr RPAREN s:stmt { ForFromTo.new(identifier: i, first: a, last: b, body: s) } | |||||
| FOR LPAREN i:expr SEMI c:expr SEMI | |||||
u:expr RPAREN s:stmt { For.new(initialise: i, condition: c, update: u, body: s) } | |||||
| TRY t:stmt | |||||
( CATCH LPAREN i:id RPAREN c:stmt { TryCatch.new(statement: t, identifier: i, handler: c) } | |||||
| ENSURE e:stmt { TryEnsure.new(statement: t, handler: e) } | |||||
) | |||||
| RAISE e:expr EOS { Raise.new(value: e) } | |||||
| LOCAL i:id p:params b:block { SetLocal.new(name: i, value: Lambda.new(parameters: p, body: b)) } | |||||
| GLOBAL i:id p:params b:block { SetGlobal.new(name: i, value: Lambda.new(parameters: p, body: b)) } | |||||
| i:id p:params b:block { SetVar.new(name: i, value: Lambda.new(parameters: p, body: b)) } | |||||
| v:proto DOT i:id p:params b:block { SetProp.new(object: v, key: i, value: Lambda.new(parameters: p, body: b)) } | |||||
| b:block { Block.new(body: b) } | |||||
| e:expr EOS { e } | |||||
proto = v:var ( DOT j:id !LPAREN { v = GetProp.new(object: v, key: j) } | |||||
)* { v } | |||||
EOS = SEMI+ | &RBRACE | &ELSE | &CATCH | |||||
expr = LOCAL i:id ASSIGN e:expr { SetLocal.new(name: i, value: e) } | |||||
| GLOBAL i:id ASSIGN e:expr { SetGlobal.new(name: i, value: e) } | |||||
| i:id ASSIGN e:expr { SetVar.new(name: i, value: e) } | |||||
| l:logor ( ASSIGN r:expr { l = assign(l, r) } | |||||
| PLUSEQ r:expr { l = newBinop(__opPreAdd, lvalue(l), r) } | |||||
| MINUSEQ r:expr { l = newBinop(__opPreSub, lvalue(l), r) } | |||||
| STAREQ r:expr { l = newBinop(__opPreMul, lvalue(l), r) } | |||||
| SLASHEQ r:expr { l = newBinop(__opPreDiv, lvalue(l), r) } | |||||
| PCENTEQ r:expr { l = newBinop(__opPreMod, lvalue(l), r) } | |||||
| SHLEQ r:expr { l = newBinop(__opPreShl, lvalue(l), r) } | |||||
| SHREQ r:expr { l = newBinop(__opPreShr, lvalue(l), r) } | |||||
| ANDEQ r:expr { l = newBinop(__opPreAnd, lvalue(l), r) } | |||||
| XOREQ r:expr { l = newBinop(__opPreXor, lvalue(l), r) } | |||||
| OREQ r:expr { l = newBinop(__opPreOr, lvalue(l), r) } | |||||
)? { l } | |||||
logor = l:logand ( BARBAR r:logand { l = newBinop(__opLogOr, l, r) } | |||||
)* { l } | |||||
logand = l:bitor ( ANDAND r:bitor { l = newBinop(__opLogAnd, l, r) } | |||||
)* { l } | |||||
bitor = l:bitxor ( OR r:bitxor { l = newBinop(__opBitOr, l, r) } | |||||
)* { l } | |||||
bitxor = l:bitand ( XOR r:bitand { l = newBinop(__opBitXor, l, r) } | |||||
)* { l } | |||||
bitand = l:eq ( AND r:eq { l = newBinop(__opBitAnd, l, r) } | |||||
)* { l } | |||||
eq = l:ineq ( EQ r:ineq { l = newBinop(__opEq, l, r) } | |||||
| NOTEQ r:ineq { l = newBinop(__opNotEq, l, r) } | |||||
)* { l } | |||||
ineq = l:shift ( LESS r:shift { l = newBinop(__opLess, l, r) } | |||||
| LESSEQ r:shift { l = newBinop(__opLessEq, l, r) } | |||||
| GRTREQ r:shift { l = newBinop(__opGrtrEq, l, r) } | |||||
| GRTR r:shift { l = newBinop(__opGrtr, l, r) } | |||||
)* { l } | |||||
shift = l:sum ( SHL r:sum { l = newBinop(__opShl, l, r) } | |||||
| SHR r:sum { l = newBinop(__opShr, l, r) } | |||||
)* { l } | |||||
sum = l:prod ( PLUS r:prod { l = newBinop(__opAdd, l, r) } | |||||
| MINUS r:prod { l = newBinop(__opSub, l, r) } | |||||
)* { l } | |||||
prod = l:range ( STAR r:range { l = newBinop(__opMul, l, r) } | |||||
| SLASH r:range { l = newBinop(__opDiv, l, r) } | |||||
| PCENT r:range { l = newBinop(__opMod, l, r) } | |||||
) * { l } | |||||
range = i1:prefix ( DOTDOT i2:prefix { i1 = Range.new(start: i1, end: i2) } | |||||
) ? { i1 } | |||||
prefix = PPLUS p:prefix { newBinop(__opPreAdd, lvalue(p), 1) } | |||||
| MMINUS p:prefix { newBinop(__opPreSub, lvalue(p), 1) } | |||||
| PLING p:prefix { Unyop.new(operation: __opNot).push(p) } | |||||
| MINUS p:prefix { Unyop.new(operation: __opNeg).push(p) } | |||||
| TILDE p:prefix { Unyop.new(operation: __opCom).push(p) } | |||||
| BQUOTE s:stmt { Unyop.new(operation: __opQuasiquote).push(s) } | |||||
| COMMAT e:expr { Unyop.new(operation: __opUnquote).push(e) } | |||||
| postfix | |||||
postfix = SUPER DOT i:id a:args { Super.new(method: i, arguments: a) } | |||||
| p:primary | |||||
( LBRAK e:expr RBRAK { p = GetArray.new(object: p, index: e) } | |||||
| DOT i:id ( a:args !LBRACE { p = Invoke.new(self: p, method: i, arguments: a) } | |||||
| { p = GetProp.new(object: p, key: i) } | |||||
) | |||||
| a:args !LBRACE { p = newApply(p, a) } | |||||
)* | |||||
( PPLUS { p = newBinop(__opPostAdd, lvalue(p), 1) } | |||||
| MMINUS { p = newBinop(__opPostAdd, lvalue(p), -1) } | |||||
)? { p } | |||||
args = LPAREN a:mkobj | |||||
( RPAREN | |||||
| ( k:id COLON e:expr { a[k] = e } | |||||
| e:expr { a.push(e) } | |||||
) | |||||
( COMMA ( k:id COLON e:expr { a[k] = e } | |||||
| e:expr { a.push(e) } | |||||
) )* RPAREN ) { a } | |||||
params = LPAREN p:mkobj | |||||
( RPAREN | |||||
| i:id ( COLON e:expr { p[i] = e } | |||||
| { p.push(i) } | |||||
) | |||||
( COMMA i:id ( COLON e:expr { p[i] = e } | |||||
| { p.push(i) } | |||||
) | |||||
)* RPAREN ) { p } | |||||
mkobj = { Object.new() } | |||||
primary = nil | number | string | symbol | var | lambda | subexpr | literal | |||||
lambda = p:params b:block { Lambda.new(parameters: p, body: b) } | |||||
subexpr = LPAREN e:expr RPAREN { e } | |||||
| b:block { Block.new(body: b) } | |||||
literal = LBRAK o:mkobj | |||||
( RBRAK | |||||
| ( ( i:id COLON e:expr { o[i] = e } | |||||
| e:expr { o.push(e) } | |||||
) ( COMMA ( i:id COLON e:expr { o[i] = e } | |||||
| e:expr { o.push(e) } | |||||
) )* )? RBRAK ) { Literal.new(object: o) } | |||||
block = LBRACE b:mkobj | |||||
( e:stmt { b.push(e) } | |||||
)* RBRACE { b } | |||||
nil = NIL { nil } | |||||
number = "-" n:unsign { Unyop.new(operation: __opNeg).push(n) } | |||||
| "+" n:number { n } | |||||
| n:unsign { n } | |||||
unsign = < DIGIT* '.' DIGIT+ EXP? > - { yytext.asFloat() } | |||||
| "0" [bB] < BIGIT+ > - { yytext.asInteger(2) } | |||||
| "0" [xX] < HIGIT+ > - { yytext.asInteger(16) } | |||||
| "0" < OIGIT* > - { yytext.asInteger(8) } | |||||
| < DIGIT+ > - { yytext.asInteger() } | |||||
| "'" < char > "'" - { ord(yytext.unescaped()) } | |||||
string = '"' < ( !'"' char )* > '"' - { yytext } | |||||
# Version originale, qui ne parse pas deux antislash pour une raison obscure | |||||
# char = "\\" ( ["'\\abfnrtv] | |||||
# | [xX] HIGIT* | |||||
# | [0-7][0-7]?[0-7]? | |||||
# ) | |||||
# | . | |||||
# Version de rawgrammar.leg, qui fonctionne sans problème | |||||
char = '\\' [abefnrtv'"\[\]\\] | |||||
| '\\' [0-3][0-7][0-7] | |||||
| '\\' [0-7][0-7]? | |||||
| '\\' [xX] HIGIT+ | |||||
| !'\\' . | |||||
symbol = HASH i:id { i } | |||||
var = LOCAL i:id { GetLocal.new(name: i) } | |||||
| GLOBAL i:id { GetGlobal.new(name: i) } | |||||
| i:id { GetVar.new(name: i) } | |||||
id = < LETTER ALNUM* > - { intern(yytext) } | |||||
BIGIT = [0-1] | |||||
OIGIT = [0-7] | |||||
DIGIT = [0-9] | |||||
HIGIT = [0-9A-Fa-f] | |||||
LETTER = [A-Za-z_$?] | |||||
ALNUM = LETTER | DIGIT | |||||
SIGN = [-+] | |||||
EXP = [eE] SIGN DIGIT+ | |||||
- = SPACE* | |||||
SPACE = [ \t] | EOL | SLC | MLC | |||||
EOL = [\n\r] # { ++lineno } | |||||
SLC = "//" (!EOL .)* | |||||
MLC = "/*" ( MLC | !"*/" (EOL | .))* "*/" - | |||||
NIL = "nil" !ALNUM - | |||||
WHILE = "while" !ALNUM - | |||||
IF = "if" !ALNUM - | |||||
ELSE = "else" !ALNUM - | |||||
FOR = "for" !ALNUM - | |||||
IN = "in" !ALNUM - | |||||
FROM = "from" !ALNUM - | |||||
TO = "to" !ALNUM - | |||||
CONT = "continue" !ALNUM - | |||||
BREAK = "break" !ALNUM - | |||||
RETURN = "return" !ALNUM - | |||||
TRY = "try" !ALNUM - | |||||
CATCH = "catch" !ALNUM - | |||||
ENSURE = "ensure" !ALNUM - | |||||
RAISE = "raise" !ALNUM - | |||||
GLOBAL = "global" !ALNUM - | |||||
LOCAL = "local" !ALNUM - | |||||
SUPER = "super" !ALNUM - | |||||
BQUOTE = "`" - | |||||
COMMAT = "@" - | |||||
HASH = "#" - | |||||
SEMI = ";" - | |||||
ASSIGN = "=" ![=] - | |||||
COMMA = "," - | |||||
COLON = ":" ![:] - | |||||
LPAREN = "(" - | |||||
RPAREN = ")" - | |||||
LBRAK = "[" - | |||||
RBRAK = "]" - | |||||
LBRACE = "{" - | |||||
RBRACE = "}" - | |||||
BARBAR = "||" ![=] - | |||||
ANDAND = "&&" ![=] - | |||||
OR = "|" ![|=] - | |||||
OREQ = "|=" - | |||||
XOR = "^" ![=] - | |||||
XOREQ = "^=" - | |||||
AND = "&" ![&=] - | |||||
ANDEQ = "&=" - | |||||
EQ = "==" - | |||||
NOTEQ = "!=" - | |||||
LESS = "<" ![<=] - | |||||
LESSEQ = "<=" - | |||||
GRTREQ = ">=" - | |||||
GRTR = ">" ![=] - | |||||
SHL = "<<" ![=] - | |||||
SHLEQ = "<<=" - | |||||
SHR = ">>" ![=] - | |||||
SHREQ = ">>=" - | |||||
PLUS = "+" ![+=] - | |||||
PLUSEQ = "+=" - | |||||
PPLUS = "++" - | |||||
MINUS = "-" ![-=] - | |||||
MINUSEQ = "-=" - | |||||
MMINUS = "--" - | |||||
STAR = "*" ![=] - | |||||
STAREQ = "*=" - | |||||
SLASH = "/" ![/=] - | |||||
SLASHEQ = "/=" - | |||||
PCENT = "%" ![=] - | |||||
PCENTEQ = "%=" - | |||||
DOT = "." ![.] - | |||||
DOTDOT = ".." - | |||||
PLING = "!" ![=] - | |||||
TILDE = "~" - |