summaryrefslogtreecommitdiff
path: root/parse.y
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-10-22 06:30:12 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-10-22 06:30:12 +0000
commita356fe1c3550892902103f66928426ac8279e072 (patch)
treebee931e36267315487d45d5776ae8f4a568feddf /parse.y
parent5a599dde0c43b62ff32c8a0c36a05a758a309818 (diff)
Safe navigation operator
* compile.c (iseq_peephole_optimize): peephole optimization for branchnil jumps. * compile.c (iseq_compile_each): generate save navigation operator code. * insns.def (branchnil): new opcode to pop the tos and branch if it is nil. * parse.y (NEW_QCALL, call_op, parser_yylex): parse token '.?'. [Feature #11537] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52214 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'parse.y')
-rw-r--r--parse.y81
1 files changed, 47 insertions, 34 deletions
diff --git a/parse.y b/parse.y
index 21d6131bcf..243ec51a48 100644
--- a/parse.y
+++ b/parse.y
@@ -371,6 +371,9 @@ static int parser_yyerror(struct parser_params*, const char*);
#define ruby_coverage (parser->coverage)
#endif
+#define NODE_CALL_Q(q) (((q) == tDOTQ) ? NODE_QCALL : NODE_CALL)
+#define NEW_QCALL(q,r,m,a) NEW_NODE(NODE_CALL_Q(q),r,m,a)
+
static int yylex(YYSTYPE*, struct parser_params*);
#ifndef RIPPER
@@ -457,8 +460,8 @@ static NODE *node_assign_gen(struct parser_params*,NODE*,NODE*);
#define node_assign(node1, node2) node_assign_gen(parser, (node1), (node2))
static NODE *new_op_assign_gen(struct parser_params *parser, NODE *lhs, ID op, NODE *rhs);
-static NODE *new_attr_op_assign_gen(struct parser_params *parser, NODE *lhs, ID attr, ID op, NODE *rhs);
-#define new_attr_op_assign(lhs, type, attr, op, rhs) new_attr_op_assign_gen(parser, (lhs), (attr), (op), (rhs))
+static NODE *new_attr_op_assign_gen(struct parser_params *parser, NODE *lhs, ID atype, ID attr, ID op, NODE *rhs);
+#define new_attr_op_assign(lhs, type, attr, op, rhs) new_attr_op_assign_gen(parser, (lhs), (type), (attr), (op), (rhs))
static NODE *new_const_op_assign_gen(struct parser_params *parser, NODE *lhs, ID op, NODE *rhs);
#define new_const_op_assign(lhs, op, rhs) new_const_op_assign_gen(parser, (lhs), (op), (rhs))
@@ -844,7 +847,7 @@ static void token_info_pop(struct parser_params*, const char *token, size_t len)
%type <node> mlhs mlhs_head mlhs_basic mlhs_item mlhs_node mlhs_post mlhs_inner
%type <id> fsym keyword_variable user_variable sym symbol operation operation2 operation3
%type <id> cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_bad_arg
-%type <id> f_kwrest f_label f_arg_asgn
+%type <id> f_kwrest f_label f_arg_asgn call_op
/*%%%*/
/*%
%type <val> program reswords then do dot_or_colon
@@ -869,6 +872,7 @@ static void token_info_pop(struct parser_params*, const char *token, size_t len)
%token tASET RUBY_TOKEN(ASET) "[]="
%token tLSHFT RUBY_TOKEN(LSHFT) "<<"
%token tRSHFT RUBY_TOKEN(RSHFT) ">>"
+%token tDOTQ RUBY_TOKEN(DOTQ) ".?"
%token tCOLON2 "::"
%token tCOLON3 ":: at EXPR_BEG"
%token <id> tOP_ASGN /* +=, -= etc. */
@@ -1260,15 +1264,15 @@ stmt : keyword_alias fitem {lex_state = EXPR_FNAME;} fitem
$$ = dispatch3(opassign, $$, $5, $6);
%*/
}
- | primary_value '.' tIDENTIFIER tOP_ASGN command_call
+ | primary_value call_op tIDENTIFIER tOP_ASGN command_call
{
value_expr($5);
- $$ = new_attr_op_assign($1, '.', $3, $4, $5);
+ $$ = new_attr_op_assign($1, $2, $3, $4, $5);
}
- | primary_value '.' tCONSTANT tOP_ASGN command_call
+ | primary_value call_op tCONSTANT tOP_ASGN command_call
{
value_expr($5);
- $$ = new_attr_op_assign($1, '.', $3, $4, $5);
+ $$ = new_attr_op_assign($1, $2, $3, $4, $5);
}
| primary_value tCOLON2 tCONSTANT tOP_ASGN command_call
{
@@ -1456,24 +1460,24 @@ command : fcall command_args %prec tLOWEST
$$ = method_add_block($$, $3);
%*/
}
- | primary_value '.' operation2 command_args %prec tLOWEST
+ | primary_value call_op operation2 command_args %prec tLOWEST
{
/*%%%*/
- $$ = NEW_CALL($1, $3, $4);
+ $$ = NEW_QCALL($2, $1, $3, $4);
fixpos($$, $1);
/*%
- $$ = dispatch4(command_call, $1, ripper_id2sym('.'), $3, $4);
+ $$ = dispatch4(command_call, $1, ripper_id2sym($2), $3, $4);
%*/
}
- | primary_value '.' operation2 command_args cmd_brace_block
+ | primary_value call_op operation2 command_args cmd_brace_block
{
/*%%%*/
block_dup_check($4,$5);
- $5->nd_iter = NEW_CALL($1, $3, $4);
+ $5->nd_iter = NEW_QCALL($2, $1, $3, $4);
$$ = $5;
fixpos($$, $1);
/*%
- $$ = dispatch4(command_call, $1, ripper_id2sym('.'), $3, $4);
+ $$ = dispatch4(command_call, $1, ripper_id2sym($2), $3, $4);
$$ = method_add_block($$, $5);
%*/
}
@@ -1713,12 +1717,12 @@ mlhs_node : user_variable
$$ = dispatch2(aref_field, $1, escape_Qundef($3));
%*/
}
- | primary_value '.' tIDENTIFIER
+ | primary_value call_op tIDENTIFIER
{
/*%%%*/
$$ = attrset($1, $3);
/*%
- $$ = dispatch3(field, $1, ripper_id2sym('.'), $3);
+ $$ = dispatch3(field, $1, ripper_id2sym($2), $3);
%*/
}
| primary_value tCOLON2 tIDENTIFIER
@@ -1729,12 +1733,12 @@ mlhs_node : user_variable
$$ = dispatch2(const_path_field, $1, $3);
%*/
}
- | primary_value '.' tCONSTANT
+ | primary_value call_op tCONSTANT
{
/*%%%*/
$$ = attrset($1, $3);
/*%
- $$ = dispatch3(field, $1, ripper_id2sym('.'), $3);
+ $$ = dispatch3(field, $1, ripper_id2sym($2), $3);
%*/
}
| primary_value tCOLON2 tCONSTANT
@@ -1804,12 +1808,12 @@ lhs : user_variable
$$ = dispatch2(aref_field, $1, escape_Qundef($3));
%*/
}
- | primary_value '.' tIDENTIFIER
+ | primary_value call_op tIDENTIFIER
{
/*%%%*/
$$ = attrset($1, $3);
/*%
- $$ = dispatch3(field, $1, ripper_id2sym('.'), $3);
+ $$ = dispatch3(field, $1, ripper_id2sym($2), $3);
%*/
}
| primary_value tCOLON2 tIDENTIFIER
@@ -1820,12 +1824,12 @@ lhs : user_variable
$$ = dispatch3(field, $1, ID2SYM(idCOLON2), $3);
%*/
}
- | primary_value '.' tCONSTANT
+ | primary_value call_op tCONSTANT
{
/*%%%*/
$$ = attrset($1, $3);
/*%
- $$ = dispatch3(field, $1, ripper_id2sym('.'), $3);
+ $$ = dispatch3(field, $1, ripper_id2sym($2), $3);
%*/
}
| primary_value tCOLON2 tCONSTANT
@@ -2064,15 +2068,15 @@ arg : lhs '=' arg
$$ = dispatch3(opassign, $1, $5, $6);
%*/
}
- | primary_value '.' tIDENTIFIER tOP_ASGN arg
+ | primary_value call_op tIDENTIFIER tOP_ASGN arg
{
value_expr($5);
- $$ = new_attr_op_assign($1, '.', $3, $4, $5);
+ $$ = new_attr_op_assign($1, $2, $3, $4, $5);
}
- | primary_value '.' tCONSTANT tOP_ASGN arg
+ | primary_value call_op tCONSTANT tOP_ASGN arg
{
value_expr($5);
- $$ = new_attr_op_assign($1, '.', $3, $4, $5);
+ $$ = new_attr_op_assign($1, $2, $3, $4, $5);
}
| primary_value tCOLON2 tIDENTIFIER tOP_ASGN arg
{
@@ -3648,7 +3652,7 @@ method_call : fcall paren_args
$$ = method_arg(dispatch1(fcall, $1), $2);
%*/
}
- | primary_value '.' operation2
+ | primary_value call_op operation2
{
/*%%%*/
$<num>$ = ruby_sourceline;
@@ -3657,10 +3661,10 @@ method_call : fcall paren_args
opt_paren_args
{
/*%%%*/
- $$ = NEW_CALL($1, $3, $5);
+ $$ = NEW_QCALL($2, $1, $3, $5);
nd_set_line($$, $<num>4);
/*%
- $$ = dispatch3(call, $1, ripper_id2sym('.'), $3);
+ $$ = dispatch3(call, $1, ripper_id2sym($2), $3);
$$ = method_optarg($$, $5);
%*/
}
@@ -3688,7 +3692,7 @@ method_call : fcall paren_args
$$ = dispatch3(call, $1, ID2SYM(idCOLON2), $3);
%*/
}
- | primary_value '.'
+ | primary_value call_op
{
/*%%%*/
$<num>$ = ruby_sourceline;
@@ -3697,10 +3701,10 @@ method_call : fcall paren_args
paren_args
{
/*%%%*/
- $$ = NEW_CALL($1, idCall, $4);
+ $$ = NEW_QCALL($2, $1, idCall, $4);
nd_set_line($$, $<num>3);
/*%
- $$ = dispatch3(call, $1, ripper_id2sym('.'),
+ $$ = dispatch3(call, $1, ripper_id2sym($2),
ID2SYM(idCall));
$$ = method_optarg($$, $4);
%*/
@@ -5103,7 +5107,7 @@ operation3 : tIDENTIFIER
| op
;
-dot_or_colon : '.'
+dot_or_colon : call_op
/*%c%*/
/*%c
{ $$ = $<val>1; }
@@ -5115,6 +5119,10 @@ dot_or_colon : '.'
%*/
;
+call_op : '.' {$$ = '.';}
+ | tDOTQ {$$ = tDOTQ;}
+ ;
+
opt_terms : /* none */
| terms
;
@@ -8356,6 +8364,10 @@ parser_yylex(struct parser_params *parser)
pushback(c);
return tDOT2;
}
+ if (c == '?') {
+ lex_state = EXPR_DOT;
+ return tDOTQ;
+ }
pushback(c);
if (c != -1 && ISDIGIT(c)) {
yyerror("no .<digit> floating literal anymore; put 0 before dot");
@@ -10036,7 +10048,8 @@ new_op_assign_gen(struct parser_params *parser, NODE *lhs, ID op, NODE *rhs)
}
static NODE *
-new_attr_op_assign_gen(struct parser_params *parser, NODE *lhs, ID attr, ID op, NODE *rhs)
+new_attr_op_assign_gen(struct parser_params *parser, NODE *lhs,
+ ID atype, ID attr, ID op, NODE *rhs)
{
NODE *asgn;
@@ -10046,7 +10059,7 @@ new_attr_op_assign_gen(struct parser_params *parser, NODE *lhs, ID attr, ID op,
else if (op == tANDOP) {
op = 1;
}
- asgn = NEW_OP_ASGN2(lhs, attr, op, rhs);
+ asgn = NEW_OP_ASGN2(lhs, (atype == tDOTQ), attr, op, rhs);
fixpos(asgn, lhs);
return asgn;
}