%require "~> 0.1" %generator "ruby" %define api.push-pull pull %define panic-mode true %define ruby.error-class {SyntaxError} %terminal REGEX %terminal DIRECTIVE %terminal IDENTIFIER %terminal KEYWORD %terminal NUMBER %terminal SSTRING %terminal ACTION %terminal BINOP %terminal PREUNOP %terminal UNOP %terminal HEREDOC %terminal HEREDOC_REF %terminal IHEREDOC %terminal IHEREDOC_REF %terminal IHEREDOC_BEGIN %terminal ISTRING %terminal ISTRING_BEGIN %terminal CLASS "class" %terminal MODULE "module" %terminal IF "if" %terminal UNLESS "unless" %terminal ELSIF "elsif" %terminal ELSE "else" %terminal FOR "for" %terminal WHILE "while" %terminal TRY "try" %terminal CATCH "catch" %terminal FINALLY "finally" %terminal RETURN "return" %terminal IN "in" %terminal ARROW "->" %terminal EQUAL "=" %terminal LBRACE "{" %terminal LPAREN "(" %terminal LBRACK "[" %terminal RBRACE "}" %terminal RPAREN ")" %terminal RBRACK "]" %terminal COLON ":" %terminal RANGE ".." %terminal ERANGE "..." %terminal PROP "." %terminal COMMA "," %terminal MINUS "-" %terminal PLUS "+" %terminal NEWLINE "\n" %nonassoc FIX %nonassoc LBRACK LPAREN %right UNOP PROP %left RANGE ERANGE %left BINOP PLUS MINUS %right EQUAL %null.data left LPAREN LBRACK BINOP MINUS PLUS %null.data right EQUAL PROP RANGE ERANGE UNOP %% main: expressions.maybe expressions.maybe: expressions | %empty { nil } expressions: expressions expression { |a, b| a << b } | expression { |a| [a] } block: LBRACE expressions.maybe RBRACE { |_, a, _| [:block, a] } block_or_vexpression: block | vexpression expression: conditional | class | module | loop | action | exception | directive | vexpression | NEWLINE { nil } | vvexpression EQUAL vexpression { |a, _, b| [:set, a, b] } vexpression: NUMBER | ISTRING | SSTRING | KEYWORD | REGEX | interpolation | PLUS vexpression { |_, a| [:pos, a] } | MINUS vexpression { |_, a| [:neg, a] } | object | array | function | PREUNOP vexpression { |a, b| [:unop, a, b] } | UNOP vexpression { |a, b| [:unop, a, b] } | HEREDOC_REF | IHEREDOC_REF | LPAREN vexpression RPAREN { |_, a, _| a } | heredoc | vexpression LPAREN vexpression.parameters.maybe RPAREN { |a, _, b, _| [:call, a, b] } | vexpression RANGE vexpression { |a, _, b| [:range, a, b] } | vexpression ERANGE vexpression { |a, _, b| [:erange, a, b] } | vexpression BINOP vexpression { |a, b, c| [:binop, a, b, c] } | vexpression MINUS vexpression { |a, b, c| [:binop, a, b, c] } | vexpression PLUS vexpression { |a, b, c| [:plus, a, b, c] } | vexpression UNOP { |a, b| [:unop, a, b] } | vvexpression vvexpression: vexpression PROP IDENTIFIER { |a, _, b| [:prop, a, b] } | vexpression LBRACK vexpression RBRACK { |a, _, b| [:access, a, b] } | IDENTIFIER vexpression.parameters.maybe: vexpression.parameters | %empty vexpression.parameters: vexpression.parameters COMMA vexpression { |a, _, b| a << b } | vexpression { |*a| a } object: LBRACE RBRACE { [:object] } array: LBRACK RBRACK { [:array] } function: ARROW function.arguments.maybe block { |_, a, b| [:func, a, b] } heredoc: HEREDOC | IHEREDOC function.arguments.maybe: LPAREN function.arguments.body.maybe RPAREN { |_, a, _| a } | %empty { nil } function.arguments.body.maybe: function.arguments.body | %empty { nil } function.arguments.body: function.arguments.body COMMA IDENTIFIER { |a, _, b| a << b } | IDENTIFIER { |a| [a] } interpolation: interpolation.string | interpolation.heredoc interpolation.heredoc: IHEREDOC_BEGIN vexpression interpolation.heredoc.finish interpolation.heredoc.finish: interpolation.heredoc | IHEREDOC interpolation.string: ISTRING_BEGIN vexpression interpolation.string.finish interpolation.string.finish: interpolation.string | ISTRING conditional: IF LPAREN vexpression RPAREN block conditional.continue.maybe { |_, _, a, _, b, c| [:if, a, b, c] } | UNLESS LPAREN vexpression RPAREN block { |_, _, a, _, b| [:unless, a, b] } conditional.continue.maybe: conditional.continue | %empty { nil } conditional.continue: ELSIF LPAREN vexpression RPAREN block conditional.continue.maybe { |_, _, a, _, b, c| [:elsif, a, b, c] } | ELSE block { |_, a| [:else, a] } class: CLASS IDENTIFIER LBRACE class.definition.parts.maybe RBRACE { |_, a, _, b, _| [:class, a, b] } module: MODULE IDENTIFIER LBRACE module.definition.parts.maybe RBRACE { |_, a, _, b, _| [:module, a, b] } class.definition.parts.maybe: class.definition.parts | %empty { nil } class.definition.parts: class.definition.parts class.definition.part { |a, b| a << b } | class.definition.part { |a| [a] } class.definition.part: IDENTIFIER COLON vexpression { |a, _, b| [:inst, a, b] } | IDENTIFIER PROP IDENTIFIER COLON vexpression { |a, _, b, _, c| [:class, a, b, c] } | module | class module.definition.parts.maybe: module.definition.parts | %empty { nil } module.definition.parts: module.definition.parts module.definition.part { |a, b| a << b } | module.definition.part { |a| [a] } module.definition.part: IDENTIFIER COLON vexpression { |a, _, b| [:inst, a, b] } loop: WHILE LPAREN vexpression RPAREN block { |_, _, a, _, b| [:while, a, b] } | FOR LPAREN IDENTIFIER IN vexpression RPAREN block { |_, _, a, _, b, _, c| [:forin, a, b, c] } | FOR LPAREN vexpression RPAREN block { |_, _, a, _, b| [:for, a, b] } action: RETURN vexpression { |_, a| [:return, a] } | ACTION exception: TRY LBRACE expressions.maybe RBRACE exception.catch.maybe exception.finally.maybe { |_, _, a, _, b, c| [:try, a, b, c] } exception.catch.maybe: exception.catch | %empty { nil } exception.finally.maybe: exception.finally | %empty { nil } exception.catch: CATCH exception.catch.possible block { |_, a, b| [:catch, a, b] } exception.catch.possible: LPAREN IDENTIFIER RPAREN { |_, a, _| a } | LPAREN RPAREN { nil } | %empty { nil } exception.finally: FINALLY block { |_, a| [:finally, a ] } directive: COLON LBRACK expressions RBRACK { |_, _, a, _| [:directive, a] } %%