Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jruby.parser.RubyParser.y Maven / Gradle / Ivy
%{
/***** BEGIN LICENSE BLOCK *****
* Version: EPL 2.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Eclipse Public
* License Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/epl-v20.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2008-2017 Thomas E Enebo
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the EPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the EPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/
package org.jruby.parser;
import java.io.IOException;
import org.jruby.RubySymbol;
import org.jruby.ast.ArgsNode;
import org.jruby.ast.ArgumentNode;
import org.jruby.ast.ArrayNode;
import org.jruby.ast.AssignableNode;
import org.jruby.ast.BackRefNode;
import org.jruby.ast.BeginNode;
import org.jruby.ast.BlockAcceptingNode;
import org.jruby.ast.BlockArgNode;
import org.jruby.ast.BlockNode;
import org.jruby.ast.BlockPassNode;
import org.jruby.ast.BreakNode;
import org.jruby.ast.ClassNode;
import org.jruby.ast.ClassVarNode;
import org.jruby.ast.ClassVarAsgnNode;
import org.jruby.ast.Colon3Node;
import org.jruby.ast.ConstNode;
import org.jruby.ast.ConstDeclNode;
import org.jruby.ast.DStrNode;
import org.jruby.ast.DSymbolNode;
import org.jruby.ast.DXStrNode;
import org.jruby.ast.DefnNode;
import org.jruby.ast.DefsNode;
import org.jruby.ast.DotNode;
import org.jruby.ast.EncodingNode;
import org.jruby.ast.EnsureNode;
import org.jruby.ast.EvStrNode;
import org.jruby.ast.FalseNode;
import org.jruby.ast.FileNode;
import org.jruby.ast.FCallNode;
import org.jruby.ast.FixnumNode;
import org.jruby.ast.FloatNode;
import org.jruby.ast.ForNode;
import org.jruby.ast.GlobalAsgnNode;
import org.jruby.ast.GlobalVarNode;
import org.jruby.ast.HashNode;
import org.jruby.ast.IfNode;
import org.jruby.ast.InstAsgnNode;
import org.jruby.ast.InstVarNode;
import org.jruby.ast.IterNode;
import org.jruby.ast.LambdaNode;
import org.jruby.ast.ListNode;
import org.jruby.ast.LiteralNode;
import org.jruby.ast.ModuleNode;
import org.jruby.ast.MultipleAsgnNode;
import org.jruby.ast.NextNode;
import org.jruby.ast.NilImplicitNode;
import org.jruby.ast.NilNode;
import org.jruby.ast.Node;
import org.jruby.ast.NonLocalControlFlowNode;
import org.jruby.ast.NumericNode;
import org.jruby.ast.OpAsgnAndNode;
import org.jruby.ast.OpAsgnOrNode;
import org.jruby.ast.OptArgNode;
import org.jruby.ast.PostExeNode;
import org.jruby.ast.PreExe19Node;
import org.jruby.ast.RationalNode;
import org.jruby.ast.RedoNode;
import org.jruby.ast.RegexpNode;
import org.jruby.ast.RequiredKeywordArgumentValueNode;
import org.jruby.ast.RescueBodyNode;
import org.jruby.ast.RescueNode;
import org.jruby.ast.RestArgNode;
import org.jruby.ast.RetryNode;
import org.jruby.ast.ReturnNode;
import org.jruby.ast.SClassNode;
import org.jruby.ast.SelfNode;
import org.jruby.ast.StarNode;
import org.jruby.ast.StrNode;
import org.jruby.ast.TrueNode;
import org.jruby.ast.UnnamedRestArgNode;
import org.jruby.ast.UntilNode;
import org.jruby.ast.VAliasNode;
import org.jruby.ast.WhileNode;
import org.jruby.ast.XStrNode;
import org.jruby.ast.YieldNode;
import org.jruby.ast.ZArrayNode;
import org.jruby.ast.ZSuperNode;
import org.jruby.ast.types.ILiteralNode;
import org.jruby.common.IRubyWarnings;
import org.jruby.common.IRubyWarnings.ID;
import org.jruby.lexer.yacc.ISourcePosition;
import org.jruby.lexer.yacc.ISourcePositionHolder;
import org.jruby.lexer.LexerSource;
import org.jruby.lexer.LexingCommon;
import org.jruby.lexer.yacc.RubyLexer;
import org.jruby.lexer.yacc.StrTerm;
import org.jruby.lexer.yacc.SyntaxException.PID;
import org.jruby.util.ByteList;
import org.jruby.util.KeyValuePair;
import org.jruby.util.StringSupport;
import static org.jruby.lexer.LexingCommon.EXPR_BEG;
import static org.jruby.lexer.LexingCommon.EXPR_FITEM;
import static org.jruby.lexer.LexingCommon.EXPR_FNAME;
import static org.jruby.lexer.LexingCommon.EXPR_ENDFN;
import static org.jruby.lexer.LexingCommon.EXPR_ENDARG;
import static org.jruby.lexer.LexingCommon.EXPR_END;
import static org.jruby.lexer.LexingCommon.EXPR_LABEL;
import static org.jruby.parser.ParserSupport.value_expr;
public class RubyParser {
protected ParserSupport support;
protected RubyLexer lexer;
public RubyParser(LexerSource source, IRubyWarnings warnings) {
this.support = new ParserSupport();
this.lexer = new RubyLexer(support, source, warnings);
support.setLexer(lexer);
support.setWarnings(warnings);
}
@Deprecated
public RubyParser(LexerSource source) {
this(new ParserSupport(), source);
}
@Deprecated
public RubyParser(ParserSupport support, LexerSource source) {
this.support = support;
lexer = new RubyLexer(support, source);
support.setLexer(lexer);
}
public void setWarnings(IRubyWarnings warnings) {
support.setWarnings(warnings);
lexer.setWarnings(warnings);
}
%}
%token keyword_class keyword_module keyword_def keyword_undef
keyword_begin keyword_rescue keyword_ensure keyword_end keyword_if
keyword_unless keyword_then keyword_elsif keyword_else keyword_case
keyword_when keyword_while keyword_until keyword_for keyword_break
keyword_next keyword_redo keyword_retry keyword_in keyword_do
keyword_do_cond keyword_do_block keyword_return keyword_yield keyword_super
keyword_self keyword_nil keyword_true keyword_false keyword_and keyword_or
keyword_not modifier_if modifier_unless modifier_while modifier_until
modifier_rescue keyword_alias keyword_defined keyword_BEGIN keyword_END
keyword__LINE__ keyword__FILE__ keyword__ENCODING__ keyword_do_lambda
%token tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
%token tCHAR
%type sym symbol operation operation2 operation3 op fname cname
%type f_norm_arg restarg_mark
%type dot_or_colon blkarg_mark
%token tUPLUS /* unary+ */
%token tUMINUS /* unary- */
%token tUMINUS_NUM /* unary- */
%token tPOW /* ** */
%token tCMP /* <=> */
%token tEQ /* == */
%token tEQQ /* === */
%token tNEQ /* != */
%token tGEQ /* >= */
%token tLEQ /* <= */
%token tANDOP tOROP /* && and || */
%token tMATCH tNMATCH /* =~ and !~ */
%token tDOT /* Is just '.' in ruby and not a token */
%token tDOT2 tDOT3 /* .. and ... */
%token tAREF tASET /* [] and []= */
%token tLSHFT tRSHFT /* << and >> */
%token tANDDOT /* &. */
%token tCOLON2 /* :: */
%token tCOLON3 /* :: at EXPR_BEG */
%token tOP_ASGN /* +=, -= etc. */
%token tASSOC /* => */
%token tLPAREN /* ( */
%token tLPAREN2 /* ( Is just '(' in ruby and not a token */
%token tRPAREN /* ) */
%token tLPAREN_ARG /* ( */
%token tLBRACK /* [ */
%token tRBRACK /* ] */
%token tLBRACE /* { */
%token tLBRACE_ARG /* { */
%token tSTAR /* * */
%token tSTAR2 /* * Is just '*' in ruby and not a token */
%token tAMPER /* & */
%token tAMPER2 /* & Is just '&' in ruby and not a token */
%token tTILDE /* ` is just '`' in ruby and not a token */
%token tPERCENT /* % is just '%' in ruby and not a token */
%token tDIVIDE /* / is just '/' in ruby and not a token */
%token tPLUS /* + is just '+' in ruby and not a token */
%token tMINUS /* - is just '-' in ruby and not a token */
%token tLT /* < is just '<' in ruby and not a token */
%token tGT /* > is just '>' in ruby and not a token */
%token tPIPE /* | is just '|' in ruby and not a token */
%token tBANG /* ! is just '!' in ruby and not a token */
%token tCARET /* ^ is just '^' in ruby and not a token */
%token tLCURLY /* { is just '{' in ruby and not a token */
%token tRCURLY /* } is just '}' in ruby and not a token */
%token tBACK_REF2 /* { is just '`' in ruby and not a token */
%token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tWORDS_BEG tQWORDS_BEG
%token tSTRING_DBEG tSTRING_DVAR tSTRING_END
%token tLAMBDA tLAMBEG
%token tNTH_REF tBACK_REF tSTRING_CONTENT tINTEGER tIMAGINARY
%token tFLOAT
%token tRATIONAL
%token tREGEXP_END
%type f_rest_arg
%type singleton strings string string1 xstring regexp
%type string_contents xstring_contents method_call
%type string_content
%type regexp_contents
%type words qwords word literal dsym cpath command_asgn command_call
%type numeric simple_numeric
%type mrhs_arg
%type compstmt bodystmt stmts stmt expr arg primary command
%type stmt_or_begin
%type expr_value primary_value opt_else cases if_tail exc_var rel_expr
%type call_args opt_ensure paren_args superclass
%type command_args var_ref opt_paren_args block_call block_command
%type command_rhs arg_rhs
%type f_opt
%type undef_list
%type string_dvar backref
%type f_args f_larglist block_param block_param_def opt_block_param
%type f_arglist
%type mrhs mlhs_item mlhs_node arg_value case_body exc_list aref_args
%type lhs none args
%type qword_list word_list
%type f_arg f_optarg
%type f_marg_list, symbol_list
%type qsym_list, symbols, qsymbols
// FIXME: These are node until a better understanding of underlying type
%type opt_args_tail, opt_block_args_tail, block_args_tail, args_tail
%type f_kw, f_block_kw
%type f_block_kwarg, f_kwarg
%type assoc_list
%type assocs
%type assoc
%type mlhs_head mlhs_post
%type f_block_optarg
%type opt_block_arg block_arg none_block_pass
%type opt_f_block_arg f_block_arg
%type brace_block do_block cmd_brace_block brace_body do_body
%type mlhs mlhs_basic
%type opt_rescue
%type var_lhs
%type fsym
%type fitem
%type f_arg_item
%type bv_decls
%type opt_bv_decl lambda_body
%type lambda
%type mlhs_inner f_block_opt for_var
%type opt_call_args f_marg f_margs
%type bvar
%type reswords f_bad_arg relop
%type rparen rbracket
%type top_compstmt top_stmts top_stmt
%token tSYMBOLS_BEG
%token tQSYMBOLS_BEG
%token tDSTAR
%token tSTRING_DEND
%type kwrest_mark f_kwrest f_label
%type call_op call_op2
%type f_arg_asgn
%type fcall
%token tLABEL_END, tSTRING_DEND
%type k_return k_class k_module
/*
* precedence table
*/
%nonassoc tLOWEST
%nonassoc tLBRACE_ARG
%nonassoc modifier_if modifier_unless modifier_while modifier_until
%left keyword_or keyword_and
%right keyword_not
%nonassoc keyword_defined
%right '=' tOP_ASGN
%left modifier_rescue
%right '?' ':'
%nonassoc tDOT2 tDOT3
%left tOROP
%left tANDOP
%nonassoc tCMP tEQ tEQQ tNEQ tMATCH tNMATCH
%left tGT tGEQ tLT tLEQ
%left tPIPE tCARET
%left tAMPER2
%left tLSHFT tRSHFT
%left tPLUS tMINUS
%left tSTAR2 tDIVIDE tPERCENT
%right tUMINUS_NUM tUMINUS
%right tPOW
%right tBANG tTILDE tUPLUS
//%token tLAST_TOKEN
%%
program : {
lexer.setState(EXPR_BEG);
support.initTopLocalVariables();
} top_compstmt {
// ENEBO: Removed !compile_for_eval which probably is to reduce warnings
if ($2 != null) {
/* last expression should not be void */
if ($2 instanceof BlockNode) {
support.checkUselessStatement($2.getLast());
} else {
support.checkUselessStatement($2);
}
}
support.getResult().setAST(support.addRootNode($2));
}
top_compstmt : top_stmts opt_terms {
if ($1 instanceof BlockNode) {
support.checkUselessStatements($1);
}
$$ = $1;
}
top_stmts : none
| top_stmt {
$$ = support.newline_node($1, support.getPosition($1));
}
| top_stmts terms top_stmt {
$$ = support.appendToBlock($1, support.newline_node($3, support.getPosition($3)));
}
| error top_stmt {
$$ = $2;
}
top_stmt : stmt
| keyword_BEGIN tLCURLY top_compstmt tRCURLY {
support.getResult().addBeginNode(new PreExe19Node($1, support.getCurrentScope(), $3));
$$ = null;
}
bodystmt : compstmt opt_rescue opt_else opt_ensure {
Node node = $1;
if ($2 != null) {
node = new RescueNode(support.getPosition($1), $1, $2, $3);
} else if ($3 != null) {
support.warn(ID.ELSE_WITHOUT_RESCUE, support.getPosition($1), "else without rescue is useless");
node = support.appendToBlock($1, $3);
}
if ($4 != null) {
if (node != null) {
node = new EnsureNode(support.getPosition($1), support.makeNullNil(node), $4);
} else {
node = support.appendToBlock($4, NilImplicitNode.NIL);
}
}
support.fixpos(node, $1);
$$ = node;
}
compstmt : stmts opt_terms {
if ($1 instanceof BlockNode) {
support.checkUselessStatements($1);
}
$$ = $1;
}
stmts : none
| stmt_or_begin {
$$ = support.newline_node($1, support.getPosition($1));
}
| stmts terms stmt_or_begin {
$$ = support.appendToBlock($1, support.newline_node($3, support.getPosition($3)));
}
| error stmt {
$$ = $2;
}
stmt_or_begin : stmt {
$$ = $1;
}
// FIXME: How can this new begin ever work? is yyerror conditional in MRI?
| keyword_begin {
support.yyerror("BEGIN is permitted only at toplevel");
} tLCURLY top_compstmt tRCURLY {
$$ = new BeginNode($1, support.makeNullNil($2));
}
stmt : keyword_alias fitem {
lexer.setState(EXPR_FNAME|EXPR_FITEM);
} fitem {
$$ = support.newAlias($1, $2, $4);
}
| keyword_alias tGVAR tGVAR {
$$ = new VAliasNode($1, support.symbolID($2), support.symbolID($3));
}
| keyword_alias tGVAR tBACK_REF {
$$ = new VAliasNode($1, support.symbolID($2), support.symbolID($3.getByteName()));
}
| keyword_alias tGVAR tNTH_REF {
support.yyerror("can't make alias for the number variables");
}
| keyword_undef undef_list {
$$ = $2;
}
| stmt modifier_if expr_value {
$$ = new IfNode(support.getPosition($1), support.getConditionNode($3), $1, null);
support.fixpos($$, $3);
}
| stmt modifier_unless expr_value {
$$ = new IfNode(support.getPosition($1), support.getConditionNode($3), null, $1);
support.fixpos($$, $3);
}
| stmt modifier_while expr_value {
if ($1 != null && $1 instanceof BeginNode) {
$$ = new WhileNode(support.getPosition($1), support.getConditionNode($3), $1.getBodyNode(), false);
} else {
$$ = new WhileNode(support.getPosition($1), support.getConditionNode($3), $1, true);
}
}
| stmt modifier_until expr_value {
if ($1 != null && $1 instanceof BeginNode) {
$$ = new UntilNode(support.getPosition($1), support.getConditionNode($3), $1.getBodyNode(), false);
} else {
$$ = new UntilNode(support.getPosition($1), support.getConditionNode($3), $1, true);
}
}
| stmt modifier_rescue stmt {
$$ = support.newRescueModNode($1, $3);
}
| keyword_END tLCURLY compstmt tRCURLY {
if (support.isInDef()) {
support.warn(ID.END_IN_METHOD, $1, "END in method; use at_exit");
}
$$ = new PostExeNode($1, $3);
}
| command_asgn
| mlhs '=' command_call {
value_expr(lexer, $3);
$1.setValueNode($3);
$$ = $1;
}
| lhs '=' mrhs {
value_expr(lexer, $3);
$$ = support.node_assign($1, $3);
}
| mlhs '=' mrhs_arg {
$1.setValueNode($3);
$$ = $1;
$1.setPosition(support.getPosition($1));
}
| expr
command_asgn : lhs '=' command_rhs {
value_expr(lexer, $3);
$$ = support.node_assign($1, $3);
}
| var_lhs tOP_ASGN command_rhs {
value_expr(lexer, $3);
ISourcePosition pos = $1.getPosition();
ByteList asgnOp = $2;
if (asgnOp == lexer.OR_OR) {
$1.setValueNode($3);
$$ = new OpAsgnOrNode(pos, support.gettable2($1), $1);
} else if (asgnOp == lexer.AMPERSAND_AMPERSAND) {
$1.setValueNode($3);
$$ = new OpAsgnAndNode(pos, support.gettable2($1), $1);
} else {
$1.setValueNode(support.getOperatorCallNode(support.gettable2($1), asgnOp, $3));
$1.setPosition(pos);
$$ = $1;
}
}
| primary_value '[' opt_call_args rbracket tOP_ASGN command_rhs {
// FIXME: arg_concat logic missing for opt_call_args
$$ = support.new_opElementAsgnNode($1, $5, $3, $6);
}
| primary_value call_op tIDENTIFIER tOP_ASGN command_rhs {
value_expr(lexer, $5);
$$ = support.newOpAsgn(support.getPosition($1), $1, $2, $5, $3, $4);
}
| primary_value call_op tCONSTANT tOP_ASGN command_rhs {
value_expr(lexer, $5);
$$ = support.newOpAsgn(support.getPosition($1), $1, $2, $5, $3, $4);
}
| primary_value tCOLON2 tCONSTANT tOP_ASGN command_rhs {
ISourcePosition pos = $1.getPosition();
$$ = support.newOpConstAsgn(pos, support.new_colon2(pos, $1, $2), $4, $5);
}
| primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_rhs {
value_expr(lexer, $5);
$$ = support.newOpAsgn(support.getPosition($1), $1, $2, $5, $3, $4);
}
| backref tOP_ASGN command_rhs {
support.backrefAssignError($1);
}
command_rhs : command_call %prec tOP_ASGN {
value_expr(lexer, $1);
$$ = $1;
}
| command_call modifier_rescue stmt {
value_expr(lexer, $1);
$$ = support.newRescueModNode($1, $3);
}
| command_asgn
// Node:expr *CURRENT* all but arg so far
expr : command_call
| expr keyword_and expr {
$$ = support.newAndNode(support.getPosition($1), $1, $3);
}
| expr keyword_or expr {
$$ = support.newOrNode(support.getPosition($1), $1, $3);
}
| keyword_not opt_nl expr {
$$ = support.getOperatorCallNode(support.getConditionNode($3), lexer.BANG);
}
| tBANG command_call {
$$ = support.getOperatorCallNode(support.getConditionNode($2), $1);
}
| arg
expr_value : expr {
value_expr(lexer, $1);
}
// Node:command - call with or with block on end [!null]
command_call : command
| block_command
// Node:block_command - A call with a block (foo.bar {...}, foo::bar {...}, bar {...}) [!null]
block_command : block_call
| block_call call_op2 operation2 command_args {
$$ = support.new_call($1, $2, $3, $4, null);
}
// :brace_block - [!null]
cmd_brace_block : tLBRACE_ARG brace_body tRCURLY {
$$ = $2;
}
fcall : operation {
$$ = support.new_fcall($1);
}
// Node:command - fcall/call/yield/super [!null]
command : fcall command_args %prec tLOWEST {
support.frobnicate_fcall_args($1, $2, null);
$$ = $1;
}
| fcall command_args cmd_brace_block {
support.frobnicate_fcall_args($1, $2, $3);
$$ = $1;
}
| primary_value call_op operation2 command_args %prec tLOWEST {
$$ = support.new_call($1, $2, $3, $4, null);
}
| primary_value call_op operation2 command_args cmd_brace_block {
$$ = support.new_call($1, $2, $3, $4, $5);
}
| primary_value tCOLON2 operation2 command_args %prec tLOWEST {
$$ = support.new_call($1, $3, $4, null);
}
| primary_value tCOLON2 operation2 command_args cmd_brace_block {
$$ = support.new_call($1, $3, $4, $5);
}
| keyword_super command_args {
$$ = support.new_super($1, $2);
}
| keyword_yield command_args {
$$ = support.new_yield($1, $2);
}
| k_return call_args {
$$ = new ReturnNode($1, support.ret_args($2, $1));
}
| keyword_break call_args {
$$ = new BreakNode($1, support.ret_args($2, $1));
}
| keyword_next call_args {
$$ = new NextNode($1, support.ret_args($2, $1));
}
// MultipleAssigNode:mlhs - [!null]
mlhs : mlhs_basic
| tLPAREN mlhs_inner rparen {
$$ = $2;
}
// MultipleAssignNode:mlhs_entry - mlhs w or w/o parens [!null]
mlhs_inner : mlhs_basic {
$$ = $1;
}
| tLPAREN mlhs_inner rparen {
$$ = new MultipleAsgnNode($1, support.newArrayNode($1, $2), null, null);
}
// MultipleAssignNode:mlhs_basic - multiple left hand side (basic because used in multiple context) [!null]
mlhs_basic : mlhs_head {
$$ = new MultipleAsgnNode($1.getPosition(), $1, null, null);
}
| mlhs_head mlhs_item {
$$ = new MultipleAsgnNode($1.getPosition(), $1.add($2), null, null);
}
| mlhs_head tSTAR mlhs_node {
$$ = new MultipleAsgnNode($1.getPosition(), $1, $3, (ListNode) null);
}
| mlhs_head tSTAR mlhs_node ',' mlhs_post {
$$ = new MultipleAsgnNode($1.getPosition(), $1, $3, $5);
}
| mlhs_head tSTAR {
$$ = new MultipleAsgnNode($1.getPosition(), $1, new StarNode(lexer.getPosition()), null);
}
| mlhs_head tSTAR ',' mlhs_post {
$$ = new MultipleAsgnNode($1.getPosition(), $1, new StarNode(lexer.getPosition()), $4);
}
| tSTAR mlhs_node {
$$ = new MultipleAsgnNode($2.getPosition(), null, $2, null);
}
| tSTAR mlhs_node ',' mlhs_post {
$$ = new MultipleAsgnNode($2.getPosition(), null, $2, $4);
}
| tSTAR {
$$ = new MultipleAsgnNode(lexer.getPosition(), null, new StarNode(lexer.getPosition()), null);
}
| tSTAR ',' mlhs_post {
$$ = new MultipleAsgnNode(lexer.getPosition(), null, new StarNode(lexer.getPosition()), $3);
}
mlhs_item : mlhs_node
| tLPAREN mlhs_inner rparen {
$$ = $2;
}
// Set of mlhs terms at front of mlhs (a, *b, d, e = arr # a is head)
mlhs_head : mlhs_item ',' {
$$ = support.newArrayNode($1.getPosition(), $1);
}
| mlhs_head mlhs_item ',' {
$$ = $1.add($2);
}
// Set of mlhs terms at end of mlhs (a, *b, d, e = arr # d,e is post)
mlhs_post : mlhs_item {
$$ = support.newArrayNode($1.getPosition(), $1);
}
| mlhs_post ',' mlhs_item {
$$ = $1.add($3);
}
mlhs_node : /*mri:user_variable*/ tIDENTIFIER {
$$ = support.assignableLabelOrIdentifier($1, null);
}
| tIVAR {
$$ = new InstAsgnNode(lexer.tokline, support.symbolID($1), NilImplicitNode.NIL);
}
| tGVAR {
$$ = new GlobalAsgnNode(lexer.tokline, support.symbolID($1), NilImplicitNode.NIL);
}
| tCONSTANT {
if (support.isInDef()) support.compile_error("dynamic constant assignment");
$$ = new ConstDeclNode(lexer.tokline, support.symbolID($1), null, NilImplicitNode.NIL);
}
| tCVAR {
$$ = new ClassVarAsgnNode(lexer.tokline, support.symbolID($1), NilImplicitNode.NIL);
} /*mri:user_variable*/
| /*mri:keyword_variable*/ keyword_nil {
support.compile_error("Can't assign to nil");
$$ = null;
}
| keyword_self {
support.compile_error("Can't change the value of self");
$$ = null;
}
| keyword_true {
support.compile_error("Can't assign to true");
$$ = null;
}
| keyword_false {
support.compile_error("Can't assign to false");
$$ = null;
}
| keyword__FILE__ {
support.compile_error("Can't assign to __FILE__");
$$ = null;
}
| keyword__LINE__ {
support.compile_error("Can't assign to __LINE__");
$$ = null;
}
| keyword__ENCODING__ {
support.compile_error("Can't assign to __ENCODING__");
$$ = null;
} /*mri:keyword_variable*/
| primary_value '[' opt_call_args rbracket {
$$ = support.aryset($1, $3);
}
| primary_value call_op tIDENTIFIER {
$$ = support.attrset($1, $2, $3);
}
| primary_value tCOLON2 tIDENTIFIER {
$$ = support.attrset($1, $3);
}
| primary_value call_op tCONSTANT {
$$ = support.attrset($1, $2, $3);
}
| primary_value tCOLON2 tCONSTANT {
if (support.isInDef()) support.yyerror("dynamic constant assignment");
ISourcePosition position = support.getPosition($1);
$$ = new ConstDeclNode(position, (RubySymbol) null, support.new_colon2(position, $1, $3), NilImplicitNode.NIL);
}
| tCOLON3 tCONSTANT {
if (support.isInDef()) {
support.yyerror("dynamic constant assignment");
}
ISourcePosition position = lexer.tokline;
$$ = new ConstDeclNode(position, (RubySymbol) null, support.new_colon3(position, $2), NilImplicitNode.NIL);
}
| backref {
support.backrefAssignError($1);
}
lhs : /*mri:user_variable*/ tIDENTIFIER {
$$ = support.assignableLabelOrIdentifier($1, null);
}
| tIVAR {
$$ = new InstAsgnNode(lexer.tokline, support.symbolID($1), NilImplicitNode.NIL);
}
| tGVAR {
$$ = new GlobalAsgnNode(lexer.tokline, support.symbolID($1), NilImplicitNode.NIL);
}
| tCONSTANT {
if (support.isInDef()) support.compile_error("dynamic constant assignment");
$$ = new ConstDeclNode(lexer.tokline, support.symbolID($1), null, NilImplicitNode.NIL);
}
| tCVAR {
$$ = new ClassVarAsgnNode(lexer.tokline, support.symbolID($1), NilImplicitNode.NIL);
} /*mri:user_variable*/
| /*mri:keyword_variable*/ keyword_nil {
support.compile_error("Can't assign to nil");
$$ = null;
}
| keyword_self {
support.compile_error("Can't change the value of self");
$$ = null;
}
| keyword_true {
support.compile_error("Can't assign to true");
$$ = null;
}
| keyword_false {
support.compile_error("Can't assign to false");
$$ = null;
}
| keyword__FILE__ {
support.compile_error("Can't assign to __FILE__");
$$ = null;
}
| keyword__LINE__ {
support.compile_error("Can't assign to __LINE__");
$$ = null;
}
| keyword__ENCODING__ {
support.compile_error("Can't assign to __ENCODING__");
$$ = null;
} /*mri:keyword_variable*/
| primary_value '[' opt_call_args rbracket {
$$ = support.aryset($1, $3);
}
| primary_value call_op tIDENTIFIER {
$$ = support.attrset($1, $2, $3);
}
| primary_value tCOLON2 tIDENTIFIER {
$$ = support.attrset($1, $3);
}
| primary_value call_op tCONSTANT {
$$ = support.attrset($1, $2, $3);
}
| primary_value tCOLON2 tCONSTANT {
if (support.isInDef()) {
support.yyerror("dynamic constant assignment");
}
ISourcePosition position = support.getPosition($1);
$$ = new ConstDeclNode(position, (RubySymbol) null, support.new_colon2(position, $1, $3), NilImplicitNode.NIL);
}
| tCOLON3 tCONSTANT {
if (support.isInDef()) {
support.yyerror("dynamic constant assignment");
}
ISourcePosition position = lexer.tokline;
$$ = new ConstDeclNode(position, (RubySymbol) null, support.new_colon3(position, $2), NilImplicitNode.NIL);
}
| backref {
support.backrefAssignError($1);
}
cname : tIDENTIFIER {
support.yyerror("class/module name must be CONSTANT");
}
| tCONSTANT {
$$ = $1;
}
cpath : tCOLON3 cname {
$$ = support.new_colon3(lexer.tokline, $2);
}
| cname {
$$ = support.new_colon2(lexer.tokline, null, $1);
}
| primary_value tCOLON2 cname {
$$ = support.new_colon2(support.getPosition($1), $1, $3);
}
// ByteList:fname - A function name [!null]
fname : tIDENTIFIER {
$$ = $1;
}
| tCONSTANT {
$$ = $1;
}
| tFID {
$$ = $1;
}
| op {
lexer.setState(EXPR_ENDFN);
$$ = $1;
}
| reswords {
lexer.setState(EXPR_ENDFN);
$$ = $1;
}
// LiteralNode:fsym
fsym : fname {
$$ = new LiteralNode(lexer.getPosition(), support.symbolID($1));
}
| symbol {
$$ = new LiteralNode(lexer.getPosition(), support.symbolID($1));
}
// Node:fitem
fitem : fsym { // LiteralNode
$$ = $1;
}
| dsym { // SymbolNode/DSymbolNode
$$ = $1;
}
undef_list : fitem {
$$ = support.newUndef($1.getPosition(), $1);
}
| undef_list ',' {
lexer.setState(EXPR_FNAME|EXPR_FITEM);
} fitem {
$$ = support.appendToBlock($1, support.newUndef($1.getPosition(), $4));
}
// ByteList:op
op : tPIPE {
$$ = $1;
}
| tCARET {
$$ = $1;
}
| tAMPER2 {
$$ = $1;
}
| tCMP {
$$ = $1;
}
| tEQ {
$$ = $1;
}
| tEQQ {
$$ = $1;
}
| tMATCH {
$$ = $1;
}
| tNMATCH {
$$ = $1;
}
| tGT {
$$ = $1;
}
| tGEQ {
$$ = $1;
}
| tLT {
$$ = $1;
}
| tLEQ {
$$ = $1;
}
| tNEQ {
$$ = $1;
}
| tLSHFT {
$$ = $1;
}
| tRSHFT{
$$ = $1;
}
| tDSTAR {
$$ = $1;
}
| tPLUS {
$$ = $1;
}
| tMINUS {
$$ = $1;
}
| tSTAR2 {
$$ = $1;
}
| tSTAR {
$$ = $1;
}
| tDIVIDE {
$$ = $1;
}
| tPERCENT {
$$ = $1;
}
| tPOW {
$$ = $1;
}
| tBANG {
$$ = $1;
}
| tTILDE {
$$ = $1;
}
| tUPLUS {
$$ = $1;
}
| tUMINUS {
$$ = $1;
}
| tAREF {
$$ = $1;
}
| tASET {
$$ = $1;
}
| tBACK_REF2 {
$$ = $1;
}
// String:op
reswords : keyword__LINE__ {
$$ = RubyLexer.Keyword.__LINE__.bytes;
}
| keyword__FILE__ {
$$ = RubyLexer.Keyword.__FILE__.bytes;
}
| keyword__ENCODING__ {
$$ = RubyLexer.Keyword.__ENCODING__.bytes;
}
| keyword_BEGIN {
$$ = RubyLexer.Keyword.LBEGIN.bytes;
}
| keyword_END {
$$ = RubyLexer.Keyword.LEND.bytes;
}
| keyword_alias {
$$ = RubyLexer.Keyword.ALIAS.bytes;
}
| keyword_and {
$$ = RubyLexer.Keyword.AND.bytes;
}
| keyword_begin {
$$ = RubyLexer.Keyword.BEGIN.bytes;
}
| keyword_break {
$$ = RubyLexer.Keyword.BREAK.bytes;
}
| keyword_case {
$$ = RubyLexer.Keyword.CASE.bytes;
}
| keyword_class {
$$ = RubyLexer.Keyword.CLASS.bytes;
}
| keyword_def {
$$ = RubyLexer.Keyword.DEF.bytes;
}
| keyword_defined {
$$ = RubyLexer.Keyword.DEFINED_P.bytes;
}
| keyword_do {
$$ = RubyLexer.Keyword.DO.bytes;
}
| keyword_else {
$$ = RubyLexer.Keyword.ELSE.bytes;
}
| keyword_elsif {
$$ = RubyLexer.Keyword.ELSIF.bytes;
}
| keyword_end {
$$ = RubyLexer.Keyword.END.bytes;
}
| keyword_ensure {
$$ = RubyLexer.Keyword.ENSURE.bytes;
}
| keyword_false {
$$ = RubyLexer.Keyword.FALSE.bytes;
}
| keyword_for {
$$ = RubyLexer.Keyword.FOR.bytes;
}
| keyword_in {
$$ = RubyLexer.Keyword.IN.bytes;
}
| keyword_module {
$$ = RubyLexer.Keyword.MODULE.bytes;
}
| keyword_next {
$$ = RubyLexer.Keyword.NEXT.bytes;
}
| keyword_nil {
$$ = RubyLexer.Keyword.NIL.bytes;
}
| keyword_not {
$$ = RubyLexer.Keyword.NOT.bytes;
}
| keyword_or {
$$ = RubyLexer.Keyword.OR.bytes;
}
| keyword_redo {
$$ = RubyLexer.Keyword.REDO.bytes;
}
| keyword_rescue {
$$ = RubyLexer.Keyword.RESCUE.bytes;
}
| keyword_retry {
$$ = RubyLexer.Keyword.RETRY.bytes;
}
| keyword_return {
$$ = RubyLexer.Keyword.RETURN.bytes;
}
| keyword_self {
$$ = RubyLexer.Keyword.SELF.bytes;
}
| keyword_super {
$$ = RubyLexer.Keyword.SUPER.bytes;
}
| keyword_then {
$$ = RubyLexer.Keyword.THEN.bytes;
}
| keyword_true {
$$ = RubyLexer.Keyword.TRUE.bytes;
}
| keyword_undef {
$$ = RubyLexer.Keyword.UNDEF.bytes;
}
| keyword_when {
$$ = RubyLexer.Keyword.WHEN.bytes;
}
| keyword_yield {
$$ = RubyLexer.Keyword.YIELD.bytes;
}
| keyword_if {
$$ = RubyLexer.Keyword.IF.bytes;
}
| keyword_unless {
$$ = RubyLexer.Keyword.UNLESS.bytes;
}
| keyword_while {
$$ = RubyLexer.Keyword.WHILE.bytes;
}
| keyword_until {
$$ = RubyLexer.Keyword.UNTIL.bytes;
}
| modifier_rescue {
$$ = RubyLexer.Keyword.RESCUE.bytes;
}
arg : lhs '=' arg_rhs {
$$ = support.node_assign($1, $3);
// FIXME: Consider fixing node_assign itself rather than single case
$$.setPosition(support.getPosition($1));
}
| var_lhs tOP_ASGN arg_rhs {
value_expr(lexer, $3);
ISourcePosition pos = $1.getPosition();
ByteList asgnOp = $2;
if (asgnOp == lexer.OR_OR) {
$1.setValueNode($3);
$$ = new OpAsgnOrNode(pos, support.gettable2($1), $1);
} else if (asgnOp == lexer.AMPERSAND_AMPERSAND) {
$1.setValueNode($3);
$$ = new OpAsgnAndNode(pos, support.gettable2($1), $1);
} else {
$1.setValueNode(support.getOperatorCallNode(support.gettable2($1), asgnOp, $3));
$1.setPosition(pos);
$$ = $1;
}
}
| primary_value '[' opt_call_args rbracket tOP_ASGN arg {
// FIXME: arg_concat missing for opt_call_args
$$ = support.new_opElementAsgnNode($1, $5, $3, $6);
}
| primary_value call_op tIDENTIFIER tOP_ASGN arg_rhs {
value_expr(lexer, $5);
$$ = support.newOpAsgn(support.getPosition($1), $1, $2, $5, $3, $4);
}
| primary_value call_op tCONSTANT tOP_ASGN arg_rhs {
value_expr(lexer, $5);
$$ = support.newOpAsgn(support.getPosition($1), $1, $2, $5, $3, $4);
}
| primary_value tCOLON2 tIDENTIFIER tOP_ASGN arg_rhs {
value_expr(lexer, $5);
$$ = support.newOpAsgn(support.getPosition($1), $1, $2, $5, $3, $4);
}
| primary_value tCOLON2 tCONSTANT tOP_ASGN arg_rhs {
ISourcePosition pos = support.getPosition($1);
$$ = support.newOpConstAsgn(pos, support.new_colon2(pos, $1, $3), $4, $5);
}
| tCOLON3 tCONSTANT tOP_ASGN arg_rhs {
ISourcePosition pos = lexer.getPosition();
$$ = support.newOpConstAsgn(pos, new Colon3Node(pos, support.symbolID($2)), $3, $4);
}
| backref tOP_ASGN arg_rhs {
support.backrefAssignError($1);
}
| arg tDOT2 arg {
value_expr(lexer, $1);
value_expr(lexer, $3);
boolean isLiteral = $1 instanceof FixnumNode && $3 instanceof FixnumNode;
$$ = new DotNode(support.getPosition($1), support.makeNullNil($1), support.makeNullNil($3), false, isLiteral);
}
| arg tDOT3 arg {
value_expr(lexer, $1);
value_expr(lexer, $3);
boolean isLiteral = $1 instanceof FixnumNode && $3 instanceof FixnumNode;
$$ = new DotNode(support.getPosition($1), support.makeNullNil($1), support.makeNullNil($3), true, isLiteral);
}
| arg tPLUS arg {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| arg tMINUS arg {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| arg tSTAR2 arg {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| arg tDIVIDE arg {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| arg tPERCENT arg {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| arg tPOW arg {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| tUMINUS_NUM simple_numeric tPOW arg {
$$ = support.getOperatorCallNode(support.getOperatorCallNode($2, $3, $4, lexer.getPosition()), $1);
}
| tUPLUS arg {
$$ = support.getOperatorCallNode($2, $1);
}
| tUMINUS arg {
$$ = support.getOperatorCallNode($2, $1);
}
| arg tPIPE arg {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| arg tCARET arg {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| arg tAMPER2 arg {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| arg tCMP arg {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| rel_expr %prec tCMP {
$$ = $1;
}
| arg tEQ arg {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| arg tEQQ arg {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| arg tNEQ arg {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| arg tMATCH arg {
$$ = support.getMatchNode($1, $3);
/* ENEBO
$$ = match_op($1, $3);
if (nd_type($1) == NODE_LIT && TYPE($1->nd_lit) == T_REGEXP) {
$$ = reg_named_capture_assign($1->nd_lit, $$);
}
*/
}
| arg tNMATCH arg {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| tBANG arg {
$$ = support.getOperatorCallNode(support.getConditionNode($2), $1);
}
| tTILDE arg {
$$ = support.getOperatorCallNode($2, $1);
}
| arg tLSHFT arg {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| arg tRSHFT arg {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| arg tANDOP arg {
$$ = support.newAndNode($1.getPosition(), $1, $3);
}
| arg tOROP arg {
$$ = support.newOrNode($1.getPosition(), $1, $3);
}
| keyword_defined opt_nl arg {
$$ = support.new_defined($1, $3);
}
| arg '?' arg opt_nl ':' arg {
value_expr(lexer, $1);
$$ = new IfNode(support.getPosition($1), support.getConditionNode($1), $3, $6);
}
| primary {
$$ = $1;
}
relop : tGT {
$$ = $1;
}
| tLT {
$$ = $1;
}
| tGEQ {
$$ = $1;
}
| tLEQ {
$$ = $1;
}
rel_expr : arg relop arg %prec tGT {
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
| rel_expr relop arg %prec tGT {
support.warning(ID.MISCELLANEOUS, lexer.getPosition(), "comparison '" + $2 + "' after comparison");
$$ = support.getOperatorCallNode($1, $2, $3, lexer.getPosition());
}
arg_value : arg {
value_expr(lexer, $1);
$$ = support.makeNullNil($1);
}
aref_args : none
| args trailer {
$$ = $1;
}
| args ',' assocs trailer {
$$ = support.arg_append($1, support.remove_duplicate_keys($3));
}
| assocs trailer {
$$ = support.newArrayNode($1.getPosition(), support.remove_duplicate_keys($1));
}
arg_rhs : arg %prec tOP_ASGN {
value_expr(lexer, $1);
$$ = $1;
}
| arg modifier_rescue arg {
value_expr(lexer, $1);
$$ = support.newRescueModNode($1, $3);
}
paren_args : tLPAREN2 opt_call_args rparen {
$$ = $2;
if ($$ != null) $$.setPosition($1);
}
opt_paren_args : none | paren_args
opt_call_args : none
| call_args
| args ',' {
$$ = $1;
}
| args ',' assocs ',' {
$$ = support.arg_append($1, support.remove_duplicate_keys($3));
}
| assocs ',' {
$$ = support.newArrayNode($1.getPosition(), support.remove_duplicate_keys($1));
}
// [!null] - ArgsCatNode, SplatNode, ArrayNode, HashNode, BlockPassNode
call_args : command {
value_expr(lexer, $1);
$$ = support.newArrayNode(support.getPosition($1), $1);
}
| args opt_block_arg {
$$ = support.arg_blk_pass($1, $2);
}
| assocs opt_block_arg {
$$ = support.newArrayNode($1.getPosition(), support.remove_duplicate_keys($1));
$$ = support.arg_blk_pass((Node)$$, $2);
}
| args ',' assocs opt_block_arg {
$$ = support.arg_append($1, support.remove_duplicate_keys($3));
$$ = support.arg_blk_pass((Node)$$, $4);
}
| block_arg {
}
// [!null] - ArgsCatNode, SplatNode, ArrayNode, HashNode, BlockPassNode
command_args : /* none */ {
$$ = Long.valueOf(lexer.getCmdArgumentState().getStack());
lexer.getCmdArgumentState().begin();
} call_args {
lexer.getCmdArgumentState().reset($1.longValue());
$$ = $2;
}
block_arg : tAMPER arg_value {
$$ = new BlockPassNode(support.getPosition($2), $2);
}
opt_block_arg : ',' block_arg {
$$ = $2;
}
| none_block_pass
// [!null]
args : arg_value { // ArrayNode
ISourcePosition pos = $1 == null ? lexer.getPosition() : $1.getPosition();
$$ = support.newArrayNode(pos, $1);
}
| tSTAR arg_value { // SplatNode
$$ = support.newSplatNode(support.getPosition($2), $2);
}
| args ',' arg_value { // ArgsCatNode, SplatNode, ArrayNode
Node node = support.splat_array($1);
if (node != null) {
$$ = support.list_append(node, $3);
} else {
$$ = support.arg_append($1, $3);
}
}
| args ',' tSTAR arg_value { // ArgsCatNode, SplatNode, ArrayNode
Node node = null;
// FIXME: lose syntactical elements here (and others like this)
if ($4 instanceof ArrayNode &&
(node = support.splat_array($1)) != null) {
$$ = support.list_concat(node, $4);
} else {
$$ = support.arg_concat(support.getPosition($1), $1, $4);
}
}
mrhs_arg : mrhs {
$$ = $1;
}
| arg_value {
$$ = $1;
}
mrhs : args ',' arg_value {
Node node = support.splat_array($1);
if (node != null) {
$$ = support.list_append(node, $3);
} else {
$$ = support.arg_append($1, $3);
}
}
| args ',' tSTAR arg_value {
Node node = null;
if ($4 instanceof ArrayNode &&
(node = support.splat_array($1)) != null) {
$$ = support.list_concat(node, $4);
} else {
$$ = support.arg_concat($1.getPosition(), $1, $4);
}
}
| tSTAR arg_value {
$$ = support.newSplatNode(support.getPosition($2), $2);
}
primary : literal
| strings
| xstring
| regexp
| words
| qwords
| symbols {
$$ = $1; // FIXME: Why complaining without $$ = $1;
}
| qsymbols {
$$ = $1; // FIXME: Why complaining without $$ = $1;
}
| var_ref
| backref
| tFID {
$$ = support.new_fcall($1);
}
| keyword_begin {
$$ = lexer.getCmdArgumentState().getStack();
lexer.getCmdArgumentState().reset();
} bodystmt keyword_end {
lexer.getCmdArgumentState().reset($2.longValue());
$$ = new BeginNode($1, support.makeNullNil($3));
}
| tLPAREN_ARG {
lexer.setState(EXPR_ENDARG);
} rparen {
$$ = null; //FIXME: Should be implicit nil?
}
| tLPAREN_ARG {
$$ = lexer.getCmdArgumentState().getStack();
lexer.getCmdArgumentState().reset();
} stmt {
lexer.setState(EXPR_ENDARG);
} rparen {
lexer.getCmdArgumentState().reset($2.longValue());
$$ = $3;
}
| tLPAREN compstmt tRPAREN {
if ($2 != null) {
// compstmt position includes both parens around it
((ISourcePositionHolder) $2).setPosition($1);
$$ = $2;
} else {
$$ = new NilNode($1);
}
}
| primary_value tCOLON2 tCONSTANT {
$$ = support.new_colon2(support.getPosition($1), $1, $3);
}
| tCOLON3 tCONSTANT {
$$ = support.new_colon3(lexer.tokline, $2);
}
| tLBRACK aref_args tRBRACK {
ISourcePosition position = support.getPosition($2);
if ($2 == null) {
$$ = new ZArrayNode(position); /* zero length array */
} else {
$$ = $2;
}
}
| tLBRACE assoc_list tRCURLY {
$$ = $2;
}
| k_return {
$$ = new ReturnNode($1, NilImplicitNode.NIL);
}
| keyword_yield tLPAREN2 call_args rparen {
$$ = support.new_yield($1, $3);
}
| keyword_yield tLPAREN2 rparen {
$$ = new YieldNode($1, null);
}
| keyword_yield {
$$ = new YieldNode($1, null);
}
| keyword_defined opt_nl tLPAREN2 expr rparen {
$$ = support.new_defined($1, $4);
}
| keyword_not tLPAREN2 expr rparen {
$$ = support.getOperatorCallNode(support.getConditionNode($3), lexer.BANG);
}
| keyword_not tLPAREN2 rparen {
$$ = support.getOperatorCallNode(NilImplicitNode.NIL, lexer.BANG);
}
| fcall brace_block {
support.frobnicate_fcall_args($1, null, $2);
$$ = $1;
}
| method_call
| method_call brace_block {
if ($1 != null &&
$1.getIterNode() instanceof BlockPassNode) {
lexer.compile_error(PID.BLOCK_ARG_AND_BLOCK_GIVEN, "Both block arg and actual block given.");
}
$$ = $1.setIterNode($2);
$$.setPosition($1.getPosition());
}
| tLAMBDA lambda {
$$ = $2;
}
| keyword_if expr_value then compstmt if_tail keyword_end {
$$ = new IfNode($1, support.getConditionNode($2), $4, $5);
}
| keyword_unless expr_value then compstmt opt_else keyword_end {
$$ = new IfNode($1, support.getConditionNode($2), $5, $4);
}
| keyword_while {
lexer.getConditionState().begin();
} expr_value do {
lexer.getConditionState().end();
} compstmt keyword_end {
Node body = support.makeNullNil($6);
$$ = new WhileNode($1, support.getConditionNode($3), body);
}
| keyword_until {
lexer.getConditionState().begin();
} expr_value do {
lexer.getConditionState().end();
} compstmt keyword_end {
Node body = support.makeNullNil($6);
$$ = new UntilNode($1, support.getConditionNode($3), body);
}
| keyword_case expr_value opt_terms case_body keyword_end {
$$ = support.newCaseNode($1, $2, $4);
}
| keyword_case opt_terms case_body keyword_end {
$$ = support.newCaseNode($1, null, $3);
}
| keyword_for for_var keyword_in {
lexer.getConditionState().begin();
} expr_value do {
lexer.getConditionState().end();
} compstmt keyword_end {
// ENEBO: Lots of optz in 1.9 parser here
$$ = new ForNode($1, $2, $8, $5, support.getCurrentScope());
}
| k_class cpath superclass {
if (support.isInDef()) {
support.yyerror("class definition in method body");
}
support.pushLocalScope();
$$ = support.isInClass(); // MRI reuses $1 but we use the value for position.
support.setIsInClass(true);
} bodystmt keyword_end {
Node body = support.makeNullNil($5);
$$ = new ClassNode($1, $2, support.getCurrentScope(), body, $3, lexer.getRubySourceline());
support.popCurrentScope();
support.setIsInClass($4.booleanValue());
}
| k_class tLSHFT expr {
$$ = new Integer((support.isInClass() ? 2 : 0) & (support.isInDef() ? 1 : 0));
support.setInDef(false);
support.setIsInClass(false);
support.pushLocalScope();
} term bodystmt keyword_end {
Node body = support.makeNullNil($6);
$$ = new SClassNode($1, $3, support.getCurrentScope(), body, lexer.getRubySourceline());
support.popCurrentScope();
support.setInDef((($4.intValue()) & 1) != 0);
support.setIsInClass((($4.intValue()) & 2) != 0);
}
| k_module cpath {
if (support.isInDef()) {
support.yyerror("module definition in method body");
}
$$ = support.isInClass();
support.setIsInClass(true);
support.pushLocalScope();
} bodystmt keyword_end {
Node body = support.makeNullNil($4);
$$ = new ModuleNode($1, $2, support.getCurrentScope(), body, lexer.getRubySourceline());
support.popCurrentScope();
support.setIsInClass($3.booleanValue());
}
| keyword_def fname {
support.pushLocalScope();
$$ = lexer.getCurrentArg();
lexer.setCurrentArg(null);
} {
$$ = support.isInDef();
support.setInDef(true);
} f_arglist bodystmt keyword_end {
Node body = support.makeNullNil($6);
$$ = new DefnNode($1, support.symbolID($2), (ArgsNode) $5, support.getCurrentScope(), body, $7.getLine());
support.popCurrentScope();
support.setInDef($4.booleanValue());
lexer.setCurrentArg($3);
}
| keyword_def singleton dot_or_colon {
lexer.setState(EXPR_FNAME);
$$ = support.isInDef();
support.setInDef(true);
} fname {
support.pushLocalScope();
lexer.setState(EXPR_ENDFN|EXPR_LABEL); /* force for args */
$$ = lexer.getCurrentArg();
lexer.setCurrentArg(null);
} f_arglist bodystmt keyword_end {
Node body = $8;
if (body == null) body = NilImplicitNode.NIL;
$$ = new DefsNode($1, $2, support.symbolID($5), (ArgsNode) $7, support.getCurrentScope(), body, $9.getLine());
support.popCurrentScope();
support.setInDef($4.booleanValue());
lexer.setCurrentArg($6);
}
| keyword_break {
$$ = new BreakNode($1, NilImplicitNode.NIL);
}
| keyword_next {
$$ = new NextNode($1, NilImplicitNode.NIL);
}
| keyword_redo {
$$ = new RedoNode($1);
}
| keyword_retry {
$$ = new RetryNode($1);
}
primary_value : primary {
value_expr(lexer, $1);
$$ = $1;
if ($$ == null) $$ = NilImplicitNode.NIL;
}
k_class : keyword_class {
$$ = $1;
}
k_module : keyword_module {
$$ = $1;
}
k_return : keyword_return {
if (support.isInClass() && !support.isInDef() && !support.getCurrentScope().isBlockScope()) {
lexer.compile_error(PID.TOP_LEVEL_RETURN, "Invalid return in class/module body");
}
$$ = $1;
}
then : term
| keyword_then
| term keyword_then
do : term
| keyword_do_cond
if_tail : opt_else
| keyword_elsif expr_value then compstmt if_tail {
$$ = new IfNode($1, support.getConditionNode($2), $4, $5);
}
opt_else : none
| keyword_else compstmt {
$$ = $2;
}
for_var : lhs
| mlhs {
}
f_marg : f_norm_arg {
$$ = support.assignableInCurr($1, NilImplicitNode.NIL);
}
| tLPAREN f_margs rparen {
$$ = $2;
}
// [!null]
f_marg_list : f_marg {
$$ = support.newArrayNode($1.getPosition(), $1);
}
| f_marg_list ',' f_marg {
$$ = $1.add($3);
}
f_margs : f_marg_list {
$$ = new MultipleAsgnNode($1.getPosition(), $1, null, null);
}
| f_marg_list ',' tSTAR f_norm_arg {
$$ = new MultipleAsgnNode($1.getPosition(), $1, support.assignableInCurr($4, null), null);
}
| f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list {
$$ = new MultipleAsgnNode($1.getPosition(), $1, support.assignableInCurr($4, null), $6);
}
| f_marg_list ',' tSTAR {
$$ = new MultipleAsgnNode($1.getPosition(), $1, new StarNode(lexer.getPosition()), null);
}
| f_marg_list ',' tSTAR ',' f_marg_list {
$$ = new MultipleAsgnNode($1.getPosition(), $1, new StarNode(lexer.getPosition()), $5);
}
| tSTAR f_norm_arg {
$$ = new MultipleAsgnNode(lexer.getPosition(), null, support.assignableInCurr($2, null), null);
}
| tSTAR f_norm_arg ',' f_marg_list {
$$ = new MultipleAsgnNode(lexer.getPosition(), null, support.assignableInCurr($2, null), $4);
}
| tSTAR {
$$ = new MultipleAsgnNode(lexer.getPosition(), null, new StarNode(lexer.getPosition()), null);
}
| tSTAR ',' f_marg_list {
$$ = new MultipleAsgnNode(support.getPosition($3), null, null, $3);
}
block_args_tail : f_block_kwarg ',' f_kwrest opt_f_block_arg {
$$ = support.new_args_tail($1.getPosition(), $1, $3, $4);
}
| f_block_kwarg opt_f_block_arg {
$$ = support.new_args_tail($1.getPosition(), $1, (ByteList) null, $2);
}
| f_kwrest opt_f_block_arg {
$$ = support.new_args_tail(lexer.getPosition(), null, $1, $2);
}
| f_block_arg {
$$ = support.new_args_tail($1.getPosition(), null, (ByteList) null, $1);
}
opt_block_args_tail : ',' block_args_tail {
$$ = $2;
}
| /* none */ {
$$ = support.new_args_tail(lexer.getPosition(), null, (ByteList) null, null);
}
// [!null]
block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail {
$$ = support.new_args($1.getPosition(), $1, $3, $5, null, $6);
}
| f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail {
$$ = support.new_args($1.getPosition(), $1, $3, $5, $7, $8);
}
| f_arg ',' f_block_optarg opt_block_args_tail {
$$ = support.new_args($1.getPosition(), $1, $3, null, null, $4);
}
| f_arg ',' f_block_optarg ',' f_arg opt_block_args_tail {
$$ = support.new_args($1.getPosition(), $1, $3, null, $5, $6);
}
| f_arg ',' f_rest_arg opt_block_args_tail {
$$ = support.new_args($1.getPosition(), $1, null, $3, null, $4);
}
| f_arg ',' {
RestArgNode rest = new UnnamedRestArgNode($1.getPosition(), null, support.getCurrentScope().addVariable("*"));
$$ = support.new_args($1.getPosition(), $1, null, rest, null, (ArgsTailHolder) null);
}
| f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail {
$$ = support.new_args($1.getPosition(), $1, null, $3, $5, $6);
}
| f_arg opt_block_args_tail {
$$ = support.new_args($1.getPosition(), $1, null, null, null, $2);
}
| f_block_optarg ',' f_rest_arg opt_block_args_tail {
$$ = support.new_args(support.getPosition($1), null, $1, $3, null, $4);
}
| f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail {
$$ = support.new_args(support.getPosition($1), null, $1, $3, $5, $6);
}
| f_block_optarg opt_block_args_tail {
$$ = support.new_args(support.getPosition($1), null, $1, null, null, $2);
}
| f_block_optarg ',' f_arg opt_block_args_tail {
$$ = support.new_args($1.getPosition(), null, $1, null, $3, $4);
}
| f_rest_arg opt_block_args_tail {
$$ = support.new_args($1.getPosition(), null, null, $1, null, $2);
}
| f_rest_arg ',' f_arg opt_block_args_tail {
$$ = support.new_args($1.getPosition(), null, null, $1, $3, $4);
}
| block_args_tail {
$$ = support.new_args($1.getPosition(), null, null, null, null, $1);
}
opt_block_param : none {
// was $$ = null;
$$ = support.new_args(lexer.getPosition(), null, null, null, null, (ArgsTailHolder) null);
}
| block_param_def {
lexer.commandStart = true;
$$ = $1;
}
block_param_def : tPIPE opt_bv_decl tPIPE {
lexer.setCurrentArg(null);
$$ = support.new_args(lexer.getPosition(), null, null, null, null, (ArgsTailHolder) null);
}
| tOROP {
$$ = support.new_args(lexer.getPosition(), null, null, null, null, (ArgsTailHolder) null);
}
| tPIPE block_param opt_bv_decl tPIPE {
lexer.setCurrentArg(null);
$$ = $2;
}
// shadowed block variables....
opt_bv_decl : opt_nl {
$$ = null;
}
| opt_nl ';' bv_decls opt_nl {
$$ = null;
}
// ENEBO: This is confusing...
bv_decls : bvar {
$$ = null;
}
| bv_decls ',' bvar {
$$ = null;
}
bvar : tIDENTIFIER {
support.new_bv($1);
}
| f_bad_arg {
$$ = null;
}
lambda : /* none */ {
support.pushBlockScope();
$$ = lexer.getLeftParenBegin();
lexer.setLeftParenBegin(lexer.incrementParenNest());
} f_larglist {
$$ = Long.valueOf(lexer.getCmdArgumentState().getStack());
lexer.getCmdArgumentState().reset();
} lambda_body {
lexer.getCmdArgumentState().reset($3.longValue());
lexer.getCmdArgumentState().restart();
$$ = new LambdaNode($2.getPosition(), $2, $4, support.getCurrentScope());
lexer.setLeftParenBegin($1);
support.popCurrentScope();
}
f_larglist : tLPAREN2 f_args opt_bv_decl tRPAREN {
$$ = $2;
}
| f_args {
$$ = $1;
}
lambda_body : tLAMBEG compstmt tRCURLY {
$$ = $2;
}
| keyword_do_lambda compstmt keyword_end {
$$ = $2;
}
do_block : keyword_do_block do_body keyword_end {
$$ = $2;
}
// JRUBY-2326 and GH #305 both end up hitting this production whereas in
// MRI these do not. I have never isolated the cause but I can work around
// the individual reported problems with a few extra conditionals in this
// first production
block_call : command do_block {
// Workaround for JRUBY-2326 (MRI does not enter this production for some reason)
if ($1 instanceof YieldNode) {
lexer.compile_error(PID.BLOCK_GIVEN_TO_YIELD, "block given to yield");
}
if ($1 instanceof BlockAcceptingNode && $1.getIterNode() instanceof BlockPassNode) {
lexer.compile_error(PID.BLOCK_ARG_AND_BLOCK_GIVEN, "Both block arg and actual block given.");
}
if ($1 instanceof NonLocalControlFlowNode) {
((BlockAcceptingNode) $1.getValueNode()).setIterNode($2);
} else {
$1.setIterNode($2);
}
$$ = $1;
$$.setPosition($1.getPosition());
}
| block_call call_op2 operation2 opt_paren_args {
$$ = support.new_call($1, $2, $3, $4, null);
}
| block_call call_op2 operation2 opt_paren_args brace_block {
$$ = support.new_call($1, $2, $3, $4, $5);
}
| block_call call_op2 operation2 command_args do_block {
$$ = support.new_call($1, $2, $3, $4, $5);
}
// [!null]
method_call : fcall paren_args {
support.frobnicate_fcall_args($1, $2, null);
$$ = $1;
}
| primary_value call_op operation2 opt_paren_args {
$$ = support.new_call($1, $2, $3, $4, null);
}
| primary_value tCOLON2 operation2 paren_args {
$$ = support.new_call($1, $3, $4, null);
}
| primary_value tCOLON2 operation3 {
$$ = support.new_call($1, $3, null, null);
}
| primary_value call_op paren_args {
$$ = support.new_call($1, $2, LexingCommon.CALL, $3, null);
}
| primary_value tCOLON2 paren_args {
$$ = support.new_call($1, LexingCommon.CALL, $3, null);
}
| keyword_super paren_args {
$$ = support.new_super($1, $2);
}
| keyword_super {
$$ = new ZSuperNode($1);
}
| primary_value '[' opt_call_args rbracket {
if ($1 instanceof SelfNode) {
$$ = support.new_fcall(LexingCommon.LBRACKET_RBRACKET);
support.frobnicate_fcall_args($$, $3, null);
} else {
$$ = support.new_call($1, lexer.LBRACKET_RBRACKET, $3, null);
}
}
brace_block : tLCURLY brace_body tRCURLY {
$$ = $2;
}
| keyword_do do_body keyword_end {
$$ = $2;
}
brace_body : {
$$ = lexer.getPosition();
} {
support.pushBlockScope();
$$ = Long.valueOf(lexer.getCmdArgumentState().getStack()) >> 1;
lexer.getCmdArgumentState().reset();
} opt_block_param compstmt {
$$ = new IterNode($1, $3, $4, support.getCurrentScope());
support.popCurrentScope();
lexer.getCmdArgumentState().reset($2.longValue());
}
do_body : {
$$ = lexer.getPosition();
} {
support.pushBlockScope();
$$ = Long.valueOf(lexer.getCmdArgumentState().getStack());
lexer.getCmdArgumentState().reset();
} opt_block_param bodystmt {
$$ = new IterNode($1, $3, $4, support.getCurrentScope());
support.popCurrentScope();
lexer.getCmdArgumentState().reset($2.longValue());
}
case_body : keyword_when args then compstmt cases {
$$ = support.newWhenNode($1, $2, $4, $5);
}
cases : opt_else | case_body
opt_rescue : keyword_rescue exc_list exc_var then compstmt opt_rescue {
Node node;
if ($3 != null) {
node = support.appendToBlock(support.node_assign($3, new GlobalVarNode($1, support.symbolID(lexer.DOLLAR_BANG))), $5);
if ($5 != null) {
node.setPosition($1);
}
} else {
node = $5;
}
Node body = support.makeNullNil(node);
$$ = new RescueBodyNode($1, $2, body, $6);
}
| {
$$ = null;
}
exc_list : arg_value {
$$ = support.newArrayNode($1.getPosition(), $1);
}
| mrhs {
$$ = support.splat_array($1);
if ($$ == null) $$ = $1; // ArgsCat or ArgsPush
}
| none
exc_var : tASSOC lhs {
$$ = $2;
}
| none
opt_ensure : keyword_ensure compstmt {
$$ = $2;
}
| none
literal : numeric {
$$ = $1;
}
| symbol {
$$ = support.asSymbol(lexer.getPosition(), $1);
}
| dsym
strings : string {
$$ = $1 instanceof EvStrNode ? new DStrNode($1.getPosition(), lexer.getEncoding()).add($1) : $1;
/*
NODE *node = $1;
if (!node) {
node = NEW_STR(STR_NEW0());
} else {
node = evstr2dstr(node);
}
$$ = node;
*/
}
// [!null]
string : tCHAR {
$$ = $1;
}
| string1 {
$$ = $1;
}
| string string1 {
$$ = support.literal_concat($1.getPosition(), $1, $2);
}
string1 : tSTRING_BEG string_contents tSTRING_END {
lexer.heredoc_dedent($2);
lexer.setHeredocIndent(0);
$$ = $2;
}
xstring : tXSTRING_BEG xstring_contents tSTRING_END {
ISourcePosition position = support.getPosition($2);
lexer.heredoc_dedent($2);
lexer.setHeredocIndent(0);
if ($2 == null) {
$$ = new XStrNode(position, null, StringSupport.CR_7BIT);
} else if ($2 instanceof StrNode) {
$$ = new XStrNode(position, (ByteList) $2.getValue().clone(), $2.getCodeRange());
} else if ($2 instanceof DStrNode) {
$$ = new DXStrNode(position, $2);
$$.setPosition(position);
} else {
$$ = new DXStrNode(position).add($2);
}
}
regexp : tREGEXP_BEG regexp_contents tREGEXP_END {
$$ = support.newRegexpNode(support.getPosition($2), $2, (RegexpNode) $3);
}
words : tWORDS_BEG ' ' word_list tSTRING_END {
$$ = $3;
}
word_list : /* none */ {
$$ = new ArrayNode(lexer.getPosition());
}
| word_list word ' ' {
$$ = $1.add($2 instanceof EvStrNode ? new DStrNode($1.getPosition(), lexer.getEncoding()).add($2) : $2);
}
word : string_content {
$$ = $1;
}
| word string_content {
$$ = support.literal_concat(support.getPosition($1), $1, $2);
}
symbols : tSYMBOLS_BEG ' ' symbol_list tSTRING_END {
$$ = $3;
}
symbol_list : /* none */ {
$$ = new ArrayNode(lexer.getPosition());
}
| symbol_list word ' ' {
$$ = $1.add($2 instanceof EvStrNode ? new DSymbolNode($1.getPosition()).add($2) : support.asSymbol($1.getPosition(), $2));
}
qwords : tQWORDS_BEG ' ' qword_list tSTRING_END {
$$ = $3;
}
qsymbols : tQSYMBOLS_BEG ' ' qsym_list tSTRING_END {
$$ = $3;
}
qword_list : /* none */ {
$$ = new ArrayNode(lexer.getPosition());
}
| qword_list tSTRING_CONTENT ' ' {
$$ = $1.add($2);
}
qsym_list : /* none */ {
$$ = new ArrayNode(lexer.getPosition());
}
| qsym_list tSTRING_CONTENT ' ' {
$$ = $1.add(support.asSymbol($1.getPosition(), $2));
}
string_contents : /* none */ {
ByteList aChar = ByteList.create("");
aChar.setEncoding(lexer.getEncoding());
$$ = lexer.createStr(aChar, 0);
}
| string_contents string_content {
$$ = support.literal_concat($1.getPosition(), $1, $2);
}
xstring_contents: /* none */ {
$$ = null;
}
| xstring_contents string_content {
$$ = support.literal_concat(support.getPosition($1), $1, $2);
}
regexp_contents: /* none */ {
$$ = null;
}
| regexp_contents string_content {
// FIXME: mri is different here.
$$ = support.literal_concat(support.getPosition($1), $1, $2);
}
string_content : tSTRING_CONTENT {
$$ = $1;
}
| tSTRING_DVAR {
$$ = lexer.getStrTerm();
lexer.setStrTerm(null);
lexer.setState(EXPR_BEG);
} string_dvar {
lexer.setStrTerm($2);
$$ = new EvStrNode(support.getPosition($3), $3);
}
| tSTRING_DBEG {
$$ = lexer.getStrTerm();
lexer.setStrTerm(null);
lexer.getConditionState().stop();
} {
$$ = lexer.getCmdArgumentState().getStack();
lexer.getCmdArgumentState().reset();
} {
$$ = lexer.getState();
lexer.setState(EXPR_BEG);
} {
$$ = lexer.getBraceNest();
lexer.setBraceNest(0);
} {
$$ = lexer.getHeredocIndent();
lexer.setHeredocIndent(0);
} compstmt tSTRING_DEND {
lexer.getConditionState().restart();
lexer.setStrTerm($2);
lexer.getCmdArgumentState().reset($3.longValue());
lexer.setState($4);
lexer.setBraceNest($5);
lexer.setHeredocIndent($6);
lexer.setHeredocLineIndent(-1);
$$ = support.newEvStrNode(support.getPosition($7), $7);
}
string_dvar : tGVAR {
$$ = new GlobalVarNode(lexer.getPosition(), support.symbolID($1));
}
| tIVAR {
$$ = new InstVarNode(lexer.getPosition(), support.symbolID($1));
}
| tCVAR {
$$ = new ClassVarNode(lexer.getPosition(), support.symbolID($1));
}
| backref
// ByteList:symbol
symbol : tSYMBEG sym {
lexer.setState(EXPR_END|EXPR_ENDARG);
$$ = $2;
}
// ByteList:symbol
sym : fname
| tIVAR {
$$ = $1;
}
| tGVAR {
$$ = $1;
}
| tCVAR {
$$ = $1;
}
dsym : tSYMBEG xstring_contents tSTRING_END {
lexer.setState(EXPR_END|EXPR_ENDARG);
// DStrNode: :"some text #{some expression}"
// StrNode: :"some text"
// EvStrNode :"#{some expression}"
// Ruby 1.9 allows empty strings as symbols
if ($2 == null) {
$$ = support.asSymbol(lexer.getPosition(), new ByteList(new byte[] {}));
} else if ($2 instanceof DStrNode) {
$$ = new DSymbolNode($2.getPosition(), $2);
} else if ($2 instanceof StrNode) {
$$ = support.asSymbol($2.getPosition(), $2);
} else {
$$ = new DSymbolNode($2.getPosition());
$$.add($2);
}
}
numeric : simple_numeric {
$$ = $1;
}
| tUMINUS_NUM simple_numeric %prec tLOWEST {
$$ = support.negateNumeric($2);
}
simple_numeric : tINTEGER {
$$ = $1;
}
| tFLOAT {
$$ = $1;
}
| tRATIONAL {
$$ = $1;
}
| tIMAGINARY {
$$ = $1;
}
// [!null]
var_ref : /*mri:user_variable*/ tIDENTIFIER {
$$ = support.declareIdentifier($1);
}
| tIVAR {
$$ = new InstVarNode(lexer.tokline, support.symbolID($1));
}
| tGVAR {
$$ = new GlobalVarNode(lexer.tokline, support.symbolID($1));
}
| tCONSTANT {
$$ = new ConstNode(lexer.tokline, support.symbolID($1));
}
| tCVAR {
$$ = new ClassVarNode(lexer.tokline, support.symbolID($1));
} /*mri:user_variable*/
| /*mri:keyword_variable*/ keyword_nil {
$$ = new NilNode(lexer.tokline);
}
| keyword_self {
$$ = new SelfNode(lexer.tokline);
}
| keyword_true {
$$ = new TrueNode(lexer.tokline);
}
| keyword_false {
$$ = new FalseNode(lexer.tokline);
}
| keyword__FILE__ {
$$ = new FileNode(lexer.tokline, new ByteList(lexer.getFile().getBytes(),
support.getConfiguration().getRuntime().getEncodingService().getLocaleEncoding()));
}
| keyword__LINE__ {
$$ = new FixnumNode(lexer.tokline, lexer.tokline.getLine()+1);
}
| keyword__ENCODING__ {
$$ = new EncodingNode(lexer.tokline, lexer.getEncoding());
} /*mri:keyword_variable*/
// [!null]
var_lhs : /*mri:user_variable*/ tIDENTIFIER {
$$ = support.assignableLabelOrIdentifier($1, null);
}
| tIVAR {
$$ = new InstAsgnNode(lexer.tokline, support.symbolID($1), NilImplicitNode.NIL);
}
| tGVAR {
$$ = new GlobalAsgnNode(lexer.tokline, support.symbolID($1), NilImplicitNode.NIL);
}
| tCONSTANT {
if (support.isInDef()) support.compile_error("dynamic constant assignment");
$$ = new ConstDeclNode(lexer.tokline, support.symbolID($1), null, NilImplicitNode.NIL);
}
| tCVAR {
$$ = new ClassVarAsgnNode(lexer.tokline, support.symbolID($1), NilImplicitNode.NIL);
} /*mri:user_variable*/
| /*mri:keyword_variable*/ keyword_nil {
support.compile_error("Can't assign to nil");
$$ = null;
}
| keyword_self {
support.compile_error("Can't change the value of self");
$$ = null;
}
| keyword_true {
support.compile_error("Can't assign to true");
$$ = null;
}
| keyword_false {
support.compile_error("Can't assign to false");
$$ = null;
}
| keyword__FILE__ {
support.compile_error("Can't assign to __FILE__");
$$ = null;
}
| keyword__LINE__ {
support.compile_error("Can't assign to __LINE__");
$$ = null;
}
| keyword__ENCODING__ {
support.compile_error("Can't assign to __ENCODING__");
$$ = null;
} /*mri:keyword_variable*/
// [!null]
backref : tNTH_REF {
$$ = $1;
}
| tBACK_REF {
$$ = $1;
}
superclass : tLT {
lexer.setState(EXPR_BEG);
lexer.commandStart = true;
} expr_value term {
$$ = $3;
}
| /* none */ {
$$ = null;
}
// [!null]
f_arglist : tLPAREN2 f_args rparen {
$$ = $2;
lexer.setState(EXPR_BEG);
lexer.commandStart = true;
}
| {
$$ = lexer.inKwarg;
lexer.inKwarg = true;
lexer.setState(lexer.getState() | EXPR_LABEL);
} f_args term {
lexer.inKwarg = $1;
$$ = $2;
lexer.setState(EXPR_BEG);
lexer.commandStart = true;
}
args_tail : f_kwarg ',' f_kwrest opt_f_block_arg {
$$ = support.new_args_tail($1.getPosition(), $1, $3, $4);
}
| f_kwarg opt_f_block_arg {
$$ = support.new_args_tail($1.getPosition(), $1, (ByteList) null, $2);
}
| f_kwrest opt_f_block_arg {
$$ = support.new_args_tail(lexer.getPosition(), null, $1, $2);
}
| f_block_arg {
$$ = support.new_args_tail($1.getPosition(), null, (ByteList) null, $1);
}
opt_args_tail : ',' args_tail {
$$ = $2;
}
| /* none */ {
$$ = support.new_args_tail(lexer.getPosition(), null, (ByteList) null, null);
}
// [!null]
f_args : f_arg ',' f_optarg ',' f_rest_arg opt_args_tail {
$$ = support.new_args($1.getPosition(), $1, $3, $5, null, $6);
}
| f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_args_tail {
$$ = support.new_args($1.getPosition(), $1, $3, $5, $7, $8);
}
| f_arg ',' f_optarg opt_args_tail {
$$ = support.new_args($1.getPosition(), $1, $3, null, null, $4);
}
| f_arg ',' f_optarg ',' f_arg opt_args_tail {
$$ = support.new_args($1.getPosition(), $1, $3, null, $5, $6);
}
| f_arg ',' f_rest_arg opt_args_tail {
$$ = support.new_args($1.getPosition(), $1, null, $3, null, $4);
}
| f_arg ',' f_rest_arg ',' f_arg opt_args_tail {
$$ = support.new_args($1.getPosition(), $1, null, $3, $5, $6);
}
| f_arg opt_args_tail {
$$ = support.new_args($1.getPosition(), $1, null, null, null, $2);
}
| f_optarg ',' f_rest_arg opt_args_tail {
$$ = support.new_args($1.getPosition(), null, $1, $3, null, $4);
}
| f_optarg ',' f_rest_arg ',' f_arg opt_args_tail {
$$ = support.new_args($1.getPosition(), null, $1, $3, $5, $6);
}
| f_optarg opt_args_tail {
$$ = support.new_args($1.getPosition(), null, $1, null, null, $2);
}
| f_optarg ',' f_arg opt_args_tail {
$$ = support.new_args($1.getPosition(), null, $1, null, $3, $4);
}
| f_rest_arg opt_args_tail {
$$ = support.new_args($1.getPosition(), null, null, $1, null, $2);
}
| f_rest_arg ',' f_arg opt_args_tail {
$$ = support.new_args($1.getPosition(), null, null, $1, $3, $4);
}
| args_tail {
$$ = support.new_args($1.getPosition(), null, null, null, null, $1);
}
| /* none */ {
$$ = support.new_args(lexer.getPosition(), null, null, null, null, (ArgsTailHolder) null);
}
f_bad_arg : tCONSTANT {
support.yyerror("formal argument cannot be a constant");
}
| tIVAR {
support.yyerror("formal argument cannot be an instance variable");
}
| tGVAR {
support.yyerror("formal argument cannot be a global variable");
}
| tCVAR {
support.yyerror("formal argument cannot be a class variable");
}
// ByteList:f_norm_arg [!null]
f_norm_arg : f_bad_arg {
$$ = $1; // Not really reached
}
| tIDENTIFIER {
$$ = support.formal_argument($1);
}
f_arg_asgn : f_norm_arg {
lexer.setCurrentArg($1);
$$ = support.arg_var($1);
}
f_arg_item : f_arg_asgn {
lexer.setCurrentArg(null);
$$ = $1;
}
| tLPAREN f_margs rparen {
$$ = $2;
/* {
ID tid = internal_id();
arg_var(tid);
if (dyna_in_block()) {
$2->nd_value = NEW_DVAR(tid);
}
else {
$2->nd_value = NEW_LVAR(tid);
}
$$ = NEW_ARGS_AUX(tid, 1);
$$->nd_next = $2;*/
}
// [!null]
f_arg : f_arg_item {
$$ = new ArrayNode(lexer.getPosition(), $1);
}
| f_arg ',' f_arg_item {
$1.add($3);
$$ = $1;
}
f_label : tLABEL {
support.arg_var(support.formal_argument($1));
lexer.setCurrentArg($1);
$$ = $1;
}
f_kw : f_label arg_value {
lexer.setCurrentArg(null);
$$ = support.keyword_arg($2.getPosition(), support.assignableKeyword($1, $2));
}
| f_label {
lexer.setCurrentArg(null);
$$ = support.keyword_arg(lexer.getPosition(), support.assignableKeyword($1, new RequiredKeywordArgumentValueNode()));
}
f_block_kw : f_label primary_value {
$$ = support.keyword_arg(support.getPosition($2), support.assignableKeyword($1, $2));
}
| f_label {
$$ = support.keyword_arg(lexer.getPosition(), support.assignableKeyword($1, new RequiredKeywordArgumentValueNode()));
}
f_block_kwarg : f_block_kw {
$$ = new ArrayNode($1.getPosition(), $1);
}
| f_block_kwarg ',' f_block_kw {
$$ = $1.add($3);
}
f_kwarg : f_kw {
$$ = new ArrayNode($1.getPosition(), $1);
}
| f_kwarg ',' f_kw {
$$ = $1.add($3);
}
kwrest_mark : tPOW {
$$ = $1;
}
| tDSTAR {
$$ = $1;
}
f_kwrest : kwrest_mark tIDENTIFIER {
support.shadowing_lvar($2);
$$ = $2;
}
| kwrest_mark {
$$ = support.INTERNAL_ID;
}
f_opt : f_arg_asgn '=' arg_value {
lexer.setCurrentArg(null);
$$ = new OptArgNode(support.getPosition($3), support.assignableLabelOrIdentifier($1.getName().getBytes(), $3));
}
f_block_opt : f_arg_asgn '=' primary_value {
lexer.setCurrentArg(null);
$$ = new OptArgNode(support.getPosition($3), support.assignableLabelOrIdentifier($1.getName().getBytes(), $3));
}
f_block_optarg : f_block_opt {
$$ = new BlockNode($1.getPosition()).add($1);
}
| f_block_optarg ',' f_block_opt {
$$ = support.appendToBlock($1, $3);
}
f_optarg : f_opt {
$$ = new BlockNode($1.getPosition()).add($1);
}
| f_optarg ',' f_opt {
$$ = support.appendToBlock($1, $3);
}
restarg_mark : tSTAR2 {
$$ = $1;
}
| tSTAR {
$$ = $1;
}
// [!null]
f_rest_arg : restarg_mark tIDENTIFIER {
if (!support.is_local_id($2)) {
support.yyerror("rest argument must be local variable");
}
$$ = new RestArgNode(support.arg_var(support.shadowing_lvar($2)));
}
| restarg_mark {
// FIXME: bytelist_love: somewhat silly to remake the empty bytelist over and over but this type should change (using null vs "" is a strange distinction).
$$ = new UnnamedRestArgNode(lexer.getPosition(), support.symbolID(new ByteList(new byte[] {})), support.getCurrentScope().addVariable("*"));
}
// [!null]
blkarg_mark : tAMPER2 {
$$ = $1;
}
| tAMPER {
$$ = $1;
}
// f_block_arg - Block argument def for function (foo(&block)) [!null]
f_block_arg : blkarg_mark tIDENTIFIER {
if (!support.is_local_id($2)) {
support.yyerror("block argument must be local variable");
}
$$ = new BlockArgNode(support.arg_var(support.shadowing_lvar($2)));
}
opt_f_block_arg : ',' f_block_arg {
$$ = $2;
}
| /* none */ {
$$ = null;
}
singleton : var_ref {
value_expr(lexer, $1);
$$ = $1;
}
| tLPAREN2 {
lexer.setState(EXPR_BEG);
} expr rparen {
if ($3 == null) {
support.yyerror("can't define single method for ().");
} else if ($3 instanceof ILiteralNode) {
support.yyerror("can't define single method for literals.");
}
value_expr(lexer, $3);
$$ = $3;
}
// HashNode: [!null]
assoc_list : none {
$$ = new HashNode(lexer.getPosition());
}
| assocs trailer {
$$ = support.remove_duplicate_keys($1);
}
// [!null]
assocs : assoc {
$$ = new HashNode(lexer.getPosition(), $1);
}
| assocs ',' assoc {
$$ = $1.add($3);
}
// Cons: [!null]
assoc : arg_value tASSOC arg_value {
$$ = support.createKeyValue($1, $3);
}
| tLABEL arg_value {
Node label = support.asSymbol(support.getPosition($2), $1);
$$ = support.createKeyValue(label, $2);
}
| tSTRING_BEG string_contents tLABEL_END arg_value {
if ($2 instanceof StrNode) {
DStrNode dnode = new DStrNode(support.getPosition($2), lexer.getEncoding());
dnode.add($2);
$$ = support.createKeyValue(new DSymbolNode(support.getPosition($2), dnode), $4);
} else if ($2 instanceof DStrNode) {
$$ = support.createKeyValue(new DSymbolNode(support.getPosition($2), $2), $4);
} else {
support.compile_error("Uknown type for assoc in strings: " + $2);
}
}
| tDSTAR arg_value {
$$ = support.createKeyValue(null, $2);
}
operation : tIDENTIFIER {
$$ = $1;
}
| tCONSTANT {
$$ = $1;
}
| tFID {
$$ = $1;
}
operation2 : tIDENTIFIER {
$$ = $1;
}
| tCONSTANT {
$$ = $1;
}
| tFID {
$$ = $1;
}
| op {
$$ = $1;
}
operation3 : tIDENTIFIER {
$$ = $1;
}
| tFID {
$$ = $1;
}
| op {
$$ = $1;
}
dot_or_colon : tDOT {
$$ = $1;
}
| tCOLON2 {
$$ = $1;
}
call_op : tDOT {
$$ = $1;
}
| tANDDOT {
$$ = $1;
}
call_op2 : call_op
| tCOLON2 {
$$ = $1;
}
opt_terms : /* none */ | terms
opt_nl : /* none */ | '\n'
rparen : opt_nl tRPAREN {
$$ = $2;
}
rbracket : opt_nl tRBRACK {
$$ = $2;
}
trailer : /* none */ | '\n' | ','
term : ';'
| '\n'
terms : term
| terms ';'
none : /* none */ {
$$ = null;
}
none_block_pass : /* none */ {
$$ = null;
}
%%
/** The parse method use an lexer stream and parse it to an AST node
* structure
*/
public RubyParserResult parse(ParserConfiguration configuration) throws IOException {
support.reset();
support.setConfiguration(configuration);
support.setResult(new RubyParserResult());
yyparse(lexer, configuration.isDebug() ? new YYDebug() : null);
return support.getResult();
}
}