[email protected]$G$9!#e(B
http://www.rubyist.net/~matz/20070806.html#p01
?.e$B$O$$$m$$$m$H$+$V$k$N$G!"e(B.?e$B$He(B.&e$B$K$7$F$_$^$7$?!#e(B
e$B$G$be(Bsafe navigatione$B$C$FMQ8l$,$$$^$$$A$o$+$j$K$/$$$+$b!#e(B
Index: compile.c
— compile.c (revision 13073)
+++ compile.c (working copy)
@@ -3496,4 +3496,5 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_
break;
}
-
case NODE_SAFENAV: case NODE_CALL: case NODE_FCALL:
@@ -3509,4 +3510,5 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_
VALUE argc;
unsigned long flag = 0;
- LABEL *end_label = 0;
VALUE parent_block = iseq->compile_data->current_block;
iseq->compile_data->current_block = Qfalse;
@@ -3566,5 +3568,5 @@ iseq_compile_each(rb_iseq_t iseq, LINK_
#endif
/ reciever */
- if (type == NODE_CALL) {
-
if (type == NODE_CALL || type == NODE_SAFENAV) {
COMPILE(recv, “recv”, node->nd_recv);
}
@@ -3582,4 +3584,9 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ADD_SEQ(ret, recv);
-
if (type == NODE_SAFENAV) {
-
end_label = NEW_LABEL(nd_line(node));
-
ADD_INSN(ret, nd_line(node), dup);
-
ADD_INSNL(ret, nd_line(node), branchunless, end_label);
-
}
ADD_SEQ(ret, args);
@@ -3598,4 +3605,15 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_
argc, parent_block, LONG2FIX(flag));
- if (end_label) {
-
ADD_LABEL(ret, end_label);
- }
- if (poped) {
-
ADD_INSN(ret, nd_line(node), pop);
- }
- break;
-
}
-
case NODE_METHOBJ:{
- COMPILE(ret, “recv”, node->nd_recv);
- ADD_INSN1(ret, nd_line(node), methobj, ID2SYM(node->nd_mid));
if (poped) {
ADD_INSN(ret, nd_line(node), pop);
Index: insns.def
===================================================================
— insns.def (revision 13073)
+++ insns.def (working copy)
@@ -1199,4 +1199,18 @@ finish
}
+/**
- @c method/iterator
- @e return Method object
- @j Method e$B%*%V%8%’%/%H$r:n$ke(B
- */
+DEFINE_INSN
+methobj
+(VALUE mid)
+(VALUE recv)
+(VALUE val)
+{ - val = rb_obj_method(recv, mid);
+}
/*********************************************************/
/ deal with control flow 3: exception */
Index: parse.y
— parse.y (revision 13073)
+++ parse.y (working copy)
@@ -373,4 +373,6 @@ static NODE new_yield_gen(struct parser
static NODE new_not_gen(struct parser_params,NODE);
#define new_not(node) new_not_gen(parser, node)
+static NODE new_safenav_gen(struct parser_params,NODE*,ID,NODE*);
+#define new_safenav(r, m, a) new_safenav_gen(parser, r, m, a)
static NODE gettable_gen(struct parser_params,ID);
@@ -682,4 +684,6 @@ static void ripper_compile_error(struct
%token tAMPER /* & /
%token tLAMBDA / -> /
+%token tSAFENAV / .? /
+%token tMETHOBJ / .& /
%token tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tWORDS_BEG
tQWORDS_BEG
%token tSTRING_DBEG tSTRING_DVAR tSTRING_END tLAMBEG
@@ -702,4 +706,5 @@ static void ripper_compile_error(struct
%left tOROP
%left tANDOP
+%left tSAFENAV
%nonassoc tCMP tEQ tEQQ tNEQ tMATCH tNMATCH
%left ‘>’ tGEQ ‘<’ tLEQ
@@ -708,5 +713,5 @@ static void ripper_compile_error(struct
%left tLSHFT tRSHFT
%left ‘+’ ‘-’
-%left '’ ‘/’ ‘%’
+%left '’ ‘/’ ‘%’ tMETHOBJ
%right tUMINUS_NUM tUMINUS
%right tPOW
@@ -1305,4 +1310,24 @@ command : operation command_args
%/
}
- | primary_value tSAFENAV operation2 command_args %prec tLOWEST
-
{
-
/*%%%*/
-
$$ = new_safenav($1, $3, $4);
-
fixpos($$, $1);
-
/*%
-
$$ = dispatch4(command_call, $1, ripper_intern("::"), $3, $4);
-
%*/
-
}
- | primary_value tSAFENAV operation2 command_args cmd_brace_block
-
{
-
/*%%%*/
-
$$ = new_safenav($1, $3, $4);
-
block_dup_check($4, $5);
-
fixpos($$, $1);
-
/*%
-
$$ = dispatch4(command_call, $1, ripper_intern("::"), $3, $4);
-
$$ = dispatch2(iter_block, $$, $5);
-
%*/
-
| keyword_super command_args}
{
@@ -1996,4 +2021,12 @@ arg : lhs ‘=’ arg
%*/
} - | arg tMETHOBJ operation2
-
{
-
/*%%%*/
-
$$ = NEW_METHOBJ($1, $3);
-
/*%
-
$$ = dispatch3(binary, $1, ID2SYM('%'), $3);
-
%*/
-
| tUMINUS_NUM tINTEGER tPOW arg}
{
@@ -3403,4 +3436,14 @@ method_call : operation paren_args
%*/
} - | primary_value tSAFENAV operation2 opt_paren_args
-
{
-
/*%%%*/
-
$$ = new_safenav($1, $3, $4);
-
fixpos($$, $1);
-
/*%
-
$$ = dispatch3(call, $1, ripper_id2sym('.'), $3);
-
$$ = method_optarg($$, $4);
-
%*/
-
| keyword_super paren_args}
{
@@ -3431,4 +3474,16 @@ method_call : operation paren_args
%*/
} - | primary_value tSAFENAV ‘[’ aref_args ‘]’
-
{
-
/*%%%*/
-
if ($1 && nd_type($1) == NODE_SELF)
-
$$ = logop(NODE_AND, $1, NEW_FCALL(tAREF, $4));
-
else
-
$$ = NEW_SAFENAV($1, tAREF, $4);
-
fixpos($$, $1);
-
/*%
-
$$ = dispatch2(aref, $1, escape_Qundef($4));
-
%*/
-
;}
@@ -6115,5 +6170,6 @@ parser_yylex(struct parser_params *parse
case ‘.’:
lex_state = EXPR_BEG;
- if ((c = nextc()) == ‘.’) {
- switch (c = nextc()) {
- case ‘.’:
if ((c = nextc()) == ‘.’) {
return tDOT3;
@@ -6121,4 +6177,11 @@ parser_yylex(struct parser_params *parse
pushback©;
return tDOT2; - case ‘&’:
-
if (peek('(')) break;
-
lex_state = EXPR_DOT;
-
return tMETHOBJ;
- case ‘?’:
-
lex_state = EXPR_DOT;
-
}return tSAFENAV;
pushback©;
@@ -7963,4 +8026,14 @@ new_args_gen(struct parser_params *parse
}
+static NODE*
+new_safenav_gen(struct parser_params *parser, NODE *r, ID m, NODE *a)
+{
- if (a && nd_type(a) == NODE_BLOCK_PASS) {
- a->nd_iter = NEW_SAFENAV(r,m,a->nd_head);
- return a;
- }
- return NEW_SAFENAV(r,m,a);
+}
static void
local_push_gen(struct parser_params *parser, int inherit_dvars)
Index: include/ruby/node.h
— include/ruby/node.h (revision 13073)
+++ include/ruby/node.h (working copy)
@@ -240,4 +240,8 @@ enum node_type {
NODE_OPTBLOCK,
#define NODE_OPTBLOCK NODE_OPTBLOCK
- NODE_SAFENAV,
+#define NODE_SAFENAV NODE_SAFENAV - NODE_METHOBJ,
+#define NODE_METHOBJ NODE_METHOBJ
NODE_LAST
#define NODE_LAST NODE_LAST
@@ -436,4 +440,5 @@ enum ruby_node_flags {
#define NEW_FCALL(m,a) NEW_NODE(NODE_FCALL,0,m,a)
#define NEW_VCALL(m) NEW_NODE(NODE_VCALL,0,m,0)
+#define NEW_SAFENAV(r,m,a) NEW_NODE(NODE_SAFENAV,r,m,a)
#define NEW_SUPER(a) NEW_NODE(NODE_SUPER,0,0,a)
#define NEW_ZSUPER() NEW_NODE(NODE_ZSUPER,0,0,0)
@@ -471,4 +476,5 @@ enum ruby_node_flags {
#define NEW_PRELUDE(p,b) NEW_NODE(NODE_PRELUDE,p,b,0)
#define NEW_OPTBLOCK(a) NEW_NODE(NODE_OPTBLOCK,a,0,0)
+#define NEW_METHOBJ(r,m) NEW_NODE(NODE_METHOBJ,r,m,0)
#define NOEX_PUBLIC 0x00