diff --git i/parse.y w/parse.y index f2a556a..a7a358a 100644 --- i/parse.y +++ w/parse.y @@ -356,6 +356,8 @@ static NODE *arg_append_gen(struct parser_params*,NODE*,NODE*); #define arg_append(h,t) arg_append_gen(parser,h,t) static NODE *arg_concat_gen(struct parser_params*,NODE*,NODE*); #define arg_concat(h,t) arg_concat_gen(parser,h,t) +static NODE *arg_prepend_gen(struct parser_params*,NODE*,NODE*); +#define arg_prepend(h,t) arg_prepend_gen(parser,h,t) static NODE *literal_concat_gen(struct parser_params*,NODE*,NODE*); #define literal_concat(h,t) literal_concat_gen(parser,h,t) static int literal_concat0(struct parser_params *, VALUE, VALUE); @@ -401,6 +403,9 @@ static NODE *match_op_gen(struct parser_params*,NODE*,NODE*); static ID *local_tbl_gen(struct parser_params*); #define local_tbl() local_tbl_gen(parser) +static NODE *symbol_lambda_gen(struct parser_params *, ID, NODE *); +#define symbol_lambda(mid, args) symbol_lambda_gen(parser, mid, args) + static void fixup_nodes(NODE **); extern int rb_dvar_defined(ID); @@ -676,7 +681,7 @@ static void token_info_pop(struct parser_params*, const char *token); keyword__FILE__ keyword__ENCODING__ -%token tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL +%token tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL tAREFBEG %token tINTEGER tFLOAT tSTRING_CONTENT tCHAR %token tNTH_REF tBACK_REF %token tREGEXP_END @@ -698,7 +703,7 @@ static void token_info_pop(struct parser_params*, const char *token); %type assoc_list assocs assoc undef_list backref string_dvar for_var %type block_param opt_block_param block_param_def f_opt %type bv_decls opt_bv_decl bvar -%type lambda f_larglist lambda_body +%type lambda f_larglist lambda_body sym_lambda %type brace_block cmd_brace_block do_block lhs none fitem %type mlhs mlhs_head mlhs_basic mlhs_item mlhs_node mlhs_post mlhs_inner %type fsym variable sym symbol operation operation2 operation3 @@ -1859,6 +1864,7 @@ op : '|' { ifndef_ripper($$ = '|'); } | tUMINUS { ifndef_ripper($$ = tUMINUS); } | tAREF { ifndef_ripper($$ = tAREF); } | tASET { ifndef_ripper($$ = tASET); } + | tAREFBEG { ifndef_ripper($$ = tAREFBEG); } | '`' { ifndef_ripper($$ = '`'); } ; @@ -2576,6 +2582,7 @@ mrhs : args ',' arg_value ; primary : literal + | sym_lambda | strings | xstring | regexp @@ -3528,6 +3535,39 @@ lambda_body : tLAMBEG compstmt '}' } ; +sym_lambda : literal paren_args + { + /*%%%*/ + if (nd_type($1) == NODE_LIT ? SYMBOL_P($1->nd_lit) : + nd_type($1) == NODE_DSYM) { + ID mid = id__send__; + if (nd_type($1) == NODE_LIT) { + mid = SYM2ID($1->nd_lit); + } + else { + $2 = arg_prepend(NEW_LIST($1), $2); + } + $$ = symbol_lambda(mid, $2); + fixpos($$, $1); + } + else { + compile_error(PARSER_ARG "non-symbol lambda"); + } + /*% + $$ = dispatch2(lambda, $1, $2); + %*/ + } + | /*:'['*/ tAREFBEG { $$ = ruby_sourceline; } aref_args ']' + { + /*%%%*/ + $$ = symbol_lambda(tAREF, $3); + nd_set_line($$, $2); + /*% + $$ = dispatch2(lambda, ripper_id2sym(tAREF), $3); + %*/ + } + ; + do_block : keyword_do_block { $1 = dyna_push(); @@ -7304,6 +7344,11 @@ parser_yylex(struct parser_params *parser) case '"': lex_strterm = NEW_STRTERM(str_dsym, c, 0); break; + case '[': + if (!peek(']')) { + lex_state = EXPR_BEG; + return tAREFBEG; + } default: pushback(c); break; @@ -8387,6 +8432,49 @@ arg_append_gen(struct parser_params *parser, NODE *node1, NODE *node2) } static NODE * +arg_prepend_gen(struct parser_params *parser, NODE *node1, NODE *node2) +{ + const char *ruby_node_name(int); + + if (!node1) return node2; + if (!node2) return node1; + switch (nd_type(node2)) { + case NODE_ARRAY: + return list_concat(node1, node2); + case NODE_BLOCK_PASS: + node2->nd_head = arg_prepend(node1, node2->nd_head); + return node2; + case NODE_SPLAT: + node2->nd_body = node2->nd_head; + node2->nd_head = node1; + nd_set_type(node2, NODE_ARGSCAT); + return node2; + case NODE_ARGSCAT: + node2->nd_head = arg_prepend(node1, node2->nd_head); + return node2; + case NODE_ARGSPUSH: + node2->nd_head = arg_prepend(node1, node2->nd_head); + return node2; + default: + compile_error(PARSER_ARG "unhandled node %s", ruby_node_name(nd_type(node2))); + return 0; + } +} + +static NODE * +symbol_lambda_gen(struct parser_params *parser, ID mid, NODE *args) +{ + const struct vtable *vars = dyna_push(); + ID tid = internal_id(); + NODE *lambda = NEW_LAMBDA(0); + arg_var(tid); + lambda->nd_body = NEW_SCOPE(new_args(NEW_ARGS_AUX(tid, 1), 0, 0, 0, 0), + NEW_CALL(NEW_DVAR(tid), mid, args)); + dyna_pop(vars); + return lambda; +} + +static NODE * splat_array(NODE* node) { if (nd_type(node) == NODE_SPLAT) node = node->nd_head; diff --git i/test/ruby/test_symbol.rb w/test/ruby/test_symbol.rb index 9061f19..35c628c 100644 --- i/test/ruby/test_symbol.rb +++ w/test/ruby/test_symbol.rb @@ -88,6 +88,9 @@ class TestSymbol < Test::Unit::TestCase ary_ids = ary.collect{|x| x.object_id } assert_equal ary_ids, ary.collect(&:object_id) end + + assert_equal [2, 4, 6], (1..3).map(&:*(2)) + assert_equal %w(b e h), %w[abc def ghi].map(&:[1]) end def test_call