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 = "~" -
|