grammar = - g:mklist ( d:definition { g[d.name] = d.expression; } ) + end-of-file { g; } definition = i:identifier ASSIGN e:expression SEMI? { Definition.new(name: i, expression: e); } expression = s1:sequence { s1 = Alternation.new().push(s1); } ( BAR s2:sequence { s1.push(s2); } ) * { s1; } sequence = p:prefix { p = Sequence.new().push(p); } ( q:prefix { p.push(q); } ) * { p; } prefix = AND a:action { ParseTimeAction.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:ruleCallIdent !ASSIGN { Assignment.new(name: i1, rule: i2); } | i:ruleCallIdent !ASSIGN { i; } | LPAREN e:expression RPAREN { e; } | l:literal { l; } | c:class { c; } | DOT { Dot.new(); } | a:action { a; } | BEGIN { Begin.new(); } | END { End.new(); } identifier = < [-a-zA-Z_][-a-zA-Z_0-9]* > - { intern(yytext); } ruleCallIdent = < [-a-zA-Z_][-a-zA-Z_0-9]* > - { RuleCall.new(name: intern(yytext)); } literal = ['] < ( !['] char )* > ['] - { StringLiteral.new(value: yytext); } | ["] < ( !["] char )* > ["] - { StringLiteral.new(value: 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:metaBlock - { Action.new(parseTree: 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 = !. metaStatement = b:metaBlock { b; } | e:metaExpression SEMI { e; } metaExpression = p:metaPrimary ( DOT i:metaId ASSIGN e:metaExpression # { $$ = newSetProp(p, i, e) } | LBRAK i:metaExpression RBRAK ASSIGN e:metaExpression { SetArray.new(object: p, index: i, value: e); } ) | i:metaId ASSIGN e:metaExpression { SetVar.new(name: i, value: e); } | pf:metaPostfix { pf; } metaPostfix = p:metaPrimary ( DOT i:metaId a:args !ASSIGN !LBRACE { p = Invoke.new(self: p, method: i, arguments: a); } | DOT i:metaId !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:metaId COLON e:metaExpression { a[k] = e; } | e:metaExpression { a.push(e); } ) ( COMMA ( k:metaId COLON e:metaExpression { a[k] = e; } | e:metaExpression { a.push(e); } ) ) * ) ? RPAREN { a; } mklist = { Object.new(); } metaPrimary = nil | metaVar | metaSubExpr metaSubExpr = LPAREN e:metaExpression RPAREN { e; } metaBlock = LBRACE b:mklist ( e:metaStatement { b.push(e); } ) * RBRACE { Block.new(body: b); } nil = NIL { nil; } metaVar = i:metaId { GetVar.new(name: i); } metaId = < LETTER ALNUM* > - { intern(yytext); } DIGIT = [0-9] LETTER = [A-Za-z_] ALNUM = LETTER | DIGIT BAR = '|' - NOT = '!' - QUERY = '?' - BEGIN = '<' - END = '>' - TILDE = '~' - RPERCENT = '%}' - NIL = "nil" !ALNUM - SEMI = ";" - ASSIGN = "=" ![=] - COMMA = "," - COLON = ":" - LPAREN = "(" - RPAREN = ")" - LBRAK = "[" - RBRAK = "]" - LBRACE = "{" - RBRACE = "}" - AND = "&" ![&=] - PLUS = "+" ![+=] - STAR = "*" ![=] - DOT = "." ![.] -