Commit 72d57ad0 authored by Ukrainskiy Sergey's avatar Ukrainskiy Sergey Committed by Yukihiro "Matz" Matsumoto

Implement numbered parameters

parent 82679939
...@@ -161,6 +161,7 @@ struct mrb_parser_state { ...@@ -161,6 +161,7 @@ struct mrb_parser_state {
uint16_t current_filename_index; uint16_t current_filename_index;
struct mrb_jmpbuf* jmp; struct mrb_jmpbuf* jmp;
mrb_ast_node *nvars;
}; };
MRB_API struct mrb_parser_state* mrb_parser_new(mrb_state*); MRB_API struct mrb_parser_state* mrb_parser_new(mrb_state*);
......
...@@ -1122,6 +1122,10 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) ...@@ -1122,6 +1122,10 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val)
} }
} }
break; break;
case NODE_NVAR:
idx = nint(tree);
codegen_error(s, "Can't assign to numbered parameter");
break;
case NODE_IVAR: case NODE_IVAR:
idx = new_sym(s, nsym(tree)); idx = new_sym(s, nsym(tree));
genop_2(s, OP_SETIV, sp, idx); genop_2(s, OP_SETIV, sp, idx);
...@@ -2340,6 +2344,17 @@ codegen(codegen_scope *s, node *tree, int val) ...@@ -2340,6 +2344,17 @@ codegen(codegen_scope *s, node *tree, int val)
} }
break; break;
case NODE_NVAR:
if (val) {
int idx = nint(tree);
gen_move(s, cursp(), idx, val);
if (val && on_eval(s)) genop_0(s, OP_NOP);
push();
}
break;
case NODE_GVAR: case NODE_GVAR:
{ {
int sym = new_sym(s, nsym(tree)); int sym = new_sym(s, nsym(tree));
......
...@@ -51,6 +51,7 @@ enum node_type { ...@@ -51,6 +51,7 @@ enum node_type {
NODE_IVAR, NODE_IVAR,
NODE_CONST, NODE_CONST,
NODE_CVAR, NODE_CVAR,
NODE_NVAR,
NODE_NTH_REF, NODE_NTH_REF,
NODE_BACK_REF, NODE_BACK_REF,
NODE_MATCH, NODE_MATCH,
......
...@@ -74,6 +74,8 @@ typedef unsigned int stack_type; ...@@ -74,6 +74,8 @@ typedef unsigned int stack_type;
#define NUM_SUFFIX_R (1<<0) #define NUM_SUFFIX_R (1<<0)
#define NUM_SUFFIX_I (1<<1) #define NUM_SUFFIX_I (1<<1)
#define NUMPARAM_MAX 31
static inline mrb_sym static inline mrb_sym
intern_cstr_gen(parser_state *p, const char *s) intern_cstr_gen(parser_state *p, const char *s)
{ {
...@@ -315,6 +317,24 @@ locals_node(parser_state *p) ...@@ -315,6 +317,24 @@ locals_node(parser_state *p)
return p->locals ? p->locals->car : NULL; return p->locals ? p->locals->car : NULL;
} }
static void
nvars_nest(parser_state *p)
{
p->nvars = cons(p->nvars, nint(0));
}
static void
nvars_block(parser_state *p)
{
p->nvars = cons(p->nvars, nint(-1));
}
static void
nvars_unnest(parser_state *p)
{
p->nvars = p->nvars->car;
}
/* (:scope (vars..) (prog...)) */ /* (:scope (vars..) (prog...)) */
static node* static node*
new_scope(parser_state *p, node *body) new_scope(parser_state *p, node *body)
...@@ -649,6 +669,19 @@ new_cvar(parser_state *p, mrb_sym sym) ...@@ -649,6 +669,19 @@ new_cvar(parser_state *p, mrb_sym sym)
return cons((node*)NODE_CVAR, nsym(sym)); return cons((node*)NODE_CVAR, nsym(sym));
} }
/* (:nvar . a) */
static node*
new_nvar(parser_state *p, int num)
{
if (!p->nvars || intn(p->nvars->cdr) < 0) {
yyerror(p, "numbered parameter outside block");
} else {
int nvars = intn(p->nvars->cdr);
p->nvars->cdr = nint(nvars > num ? nvars : num);
}
return cons((node*)NODE_NVAR, nint(num));
}
/* (:const . a) */ /* (:const . a) */
static node* static node*
new_const(parser_state *p, mrb_sym sym) new_const(parser_state *p, mrb_sym sym)
...@@ -806,10 +839,36 @@ new_block_arg(parser_state *p, node *a) ...@@ -806,10 +839,36 @@ new_block_arg(parser_state *p, node *a)
return cons((node*)NODE_BLOCK_ARG, a); return cons((node*)NODE_BLOCK_ARG, a);
} }
static node*
setup_args(parser_state *p, node *a)
{
int nvars = intn(p->nvars->cdr);
if (nvars > 0) {
int i;
char buf[5];
mrb_sym sym;
// m || opt || rest || tail
if (a && (a->car || (a->cdr && a->cdr->car) || (a->cdr->cdr && a->cdr->cdr->car) || (a->cdr->cdr->cdr->cdr && a->cdr->cdr->cdr->cdr->car))) {
yyerror(p, "ordinary parameter is defined");
} else {
node* args = 0;
for (i = nvars; i > 0; i--) {
sprintf(buf, "@%d", i);
sym = intern_cstr(buf);
args = cons(new_arg(p, sym), args);
p->locals->car = cons(nsym(sym), p->locals->car);
}
a = new_args(p, args, 0, 0, 0, 0);
}
}
return a;
}
/* (:block arg body) */ /* (:block arg body) */
static node* static node*
new_block(parser_state *p, node *a, node *b) new_block(parser_state *p, node *a, node *b)
{ {
a = setup_args(p, a);
return list4((node*)NODE_BLOCK, locals_node(p), a, b); return list4((node*)NODE_BLOCK, locals_node(p), a, b);
} }
...@@ -817,6 +876,7 @@ new_block(parser_state *p, node *a, node *b) ...@@ -817,6 +876,7 @@ new_block(parser_state *p, node *a, node *b)
static node* static node*
new_lambda(parser_state *p, node *a, node *b) new_lambda(parser_state *p, node *a, node *b)
{ {
a = setup_args(p, a);
return list4((node*)NODE_LAMBDA, locals_node(p), a, b); return list4((node*)NODE_LAMBDA, locals_node(p), a, b);
} }
...@@ -1334,6 +1394,7 @@ heredoc_end(parser_state *p) ...@@ -1334,6 +1394,7 @@ heredoc_end(parser_state *p)
%token <nd> tSTRING tSTRING_PART tSTRING_MID %token <nd> tSTRING tSTRING_PART tSTRING_MID
%token <nd> tNTH_REF tBACK_REF %token <nd> tNTH_REF tBACK_REF
%token <num> tREGEXP_END %token <num> tREGEXP_END
%token <num> tNUMPARAM
%type <nd> singleton string string_fragment string_rep string_interp xstring regexp %type <nd> singleton string string_fragment string_rep string_interp xstring regexp
%type <nd> literal numeric cpath symbol %type <nd> literal numeric cpath symbol
...@@ -1466,11 +1527,13 @@ top_stmt : stmt ...@@ -1466,11 +1527,13 @@ top_stmt : stmt
| keyword_BEGIN | keyword_BEGIN
{ {
$<nd>$ = local_switch(p); $<nd>$ = local_switch(p);
nvars_block(p);
} }
'{' top_compstmt '}' '{' top_compstmt '}'
{ {
yyerror(p, "BEGIN not supported"); yyerror(p, "BEGIN not supported");
local_resume(p, $<nd>2); local_resume(p, $<nd>2);
nvars_unnest(p);
$$ = 0; $$ = 0;
} }
; ;
...@@ -1668,6 +1731,7 @@ block_command : block_call ...@@ -1668,6 +1731,7 @@ block_command : block_call
cmd_brace_block : tLBRACE_ARG cmd_brace_block : tLBRACE_ARG
{ {
local_nest(p); local_nest(p);
nvars_nest(p);
} }
opt_block_param opt_block_param
compstmt compstmt
...@@ -1675,6 +1739,7 @@ cmd_brace_block : tLBRACE_ARG ...@@ -1675,6 +1739,7 @@ cmd_brace_block : tLBRACE_ARG
{ {
$$ = new_block(p, $3, $4); $$ = new_block(p, $3, $4);
local_unnest(p); local_unnest(p);
nvars_unnest(p);
} }
; ;
...@@ -2410,6 +2475,7 @@ primary : literal ...@@ -2410,6 +2475,7 @@ primary : literal
| tLAMBDA | tLAMBDA
{ {
local_nest(p); local_nest(p);
nvars_nest(p);
$<num>$ = p->lpar_beg; $<num>$ = p->lpar_beg;
p->lpar_beg = ++p->paren_nest; p->lpar_beg = ++p->paren_nest;
} }
...@@ -2423,6 +2489,7 @@ primary : literal ...@@ -2423,6 +2489,7 @@ primary : literal
p->lpar_beg = $<num>2; p->lpar_beg = $<num>2;
$$ = new_lambda(p, $3, $5); $$ = new_lambda(p, $3, $5);
local_unnest(p); local_unnest(p);
nvars_unnest(p);
p->cmdarg_stack = $<stack>4; p->cmdarg_stack = $<stack>4;
CMDARG_LEXPOP(); CMDARG_LEXPOP();
} }
...@@ -2482,6 +2549,7 @@ primary : literal ...@@ -2482,6 +2549,7 @@ primary : literal
if (p->in_def || p->in_single) if (p->in_def || p->in_single)
yyerror(p, "class definition in method body"); yyerror(p, "class definition in method body");
$<nd>$ = local_switch(p); $<nd>$ = local_switch(p);
nvars_block(p);
} }
bodystmt bodystmt
keyword_end keyword_end
...@@ -2489,6 +2557,7 @@ primary : literal ...@@ -2489,6 +2557,7 @@ primary : literal
$$ = new_class(p, $2, $3, $5); $$ = new_class(p, $2, $3, $5);
SET_LINENO($$, $1); SET_LINENO($$, $1);
local_resume(p, $<nd>4); local_resume(p, $<nd>4);
nvars_unnest(p);
} }
| keyword_class | keyword_class
tLSHFT expr tLSHFT expr
...@@ -2499,6 +2568,7 @@ primary : literal ...@@ -2499,6 +2568,7 @@ primary : literal
term term
{ {
$<nd>$ = cons(local_switch(p), nint(p->in_single)); $<nd>$ = cons(local_switch(p), nint(p->in_single));
nvars_block(p);
p->in_single = 0; p->in_single = 0;
} }
bodystmt bodystmt
...@@ -2507,6 +2577,7 @@ primary : literal ...@@ -2507,6 +2577,7 @@ primary : literal
$$ = new_sclass(p, $3, $7); $$ = new_sclass(p, $3, $7);
SET_LINENO($$, $1); SET_LINENO($$, $1);
local_resume(p, $<nd>6->car); local_resume(p, $<nd>6->car);
nvars_unnest(p);
p->in_def = $<num>4; p->in_def = $<num>4;
p->in_single = intn($<nd>6->cdr); p->in_single = intn($<nd>6->cdr);
} }
...@@ -2516,6 +2587,7 @@ primary : literal ...@@ -2516,6 +2587,7 @@ primary : literal
if (p->in_def || p->in_single) if (p->in_def || p->in_single)
yyerror(p, "module definition in method body"); yyerror(p, "module definition in method body");
$<nd>$ = local_switch(p); $<nd>$ = local_switch(p);
nvars_block(p);
} }
bodystmt bodystmt
keyword_end keyword_end
...@@ -2523,6 +2595,7 @@ primary : literal ...@@ -2523,6 +2595,7 @@ primary : literal
$$ = new_module(p, $2, $4); $$ = new_module(p, $2, $4);
SET_LINENO($$, $1); SET_LINENO($$, $1);
local_resume(p, $<nd>3); local_resume(p, $<nd>3);
nvars_unnest(p);
} }
| keyword_def fname | keyword_def fname
{ {
...@@ -2532,6 +2605,7 @@ primary : literal ...@@ -2532,6 +2605,7 @@ primary : literal
{ {
p->in_def++; p->in_def++;
$<nd>$ = local_switch(p); $<nd>$ = local_switch(p);
nvars_block(p);
} }
f_arglist f_arglist
bodystmt bodystmt
...@@ -2540,6 +2614,7 @@ primary : literal ...@@ -2540,6 +2614,7 @@ primary : literal
$$ = new_def(p, $2, $5, $6); $$ = new_def(p, $2, $5, $6);
SET_LINENO($$, $1); SET_LINENO($$, $1);
local_resume(p, $<nd>4); local_resume(p, $<nd>4);
nvars_unnest(p);
p->in_def--; p->in_def--;
p->cmdarg_stack = $<stack>3; p->cmdarg_stack = $<stack>3;
} }
...@@ -2554,6 +2629,7 @@ primary : literal ...@@ -2554,6 +2629,7 @@ primary : literal
p->in_single++; p->in_single++;
p->lstate = EXPR_ENDFN; /* force for args */ p->lstate = EXPR_ENDFN; /* force for args */
$<nd>$ = local_switch(p); $<nd>$ = local_switch(p);
nvars_block(p);
} }
f_arglist f_arglist
bodystmt bodystmt
...@@ -2562,6 +2638,7 @@ primary : literal ...@@ -2562,6 +2638,7 @@ primary : literal
$$ = new_sdef(p, $2, $5, $7, $8); $$ = new_sdef(p, $2, $5, $7, $8);
SET_LINENO($$, $1); SET_LINENO($$, $1);
local_resume(p, $<nd>6); local_resume(p, $<nd>6);
nvars_unnest(p);
p->in_single--; p->in_single--;
p->cmdarg_stack = $<stack>4; p->cmdarg_stack = $<stack>4;
} }
...@@ -2829,6 +2906,7 @@ lambda_body : tLAMBEG compstmt '}' ...@@ -2829,6 +2906,7 @@ lambda_body : tLAMBEG compstmt '}'
do_block : keyword_do_block do_block : keyword_do_block
{ {
local_nest(p); local_nest(p);
nvars_nest(p);
} }
opt_block_param opt_block_param
bodystmt bodystmt
...@@ -2836,6 +2914,7 @@ do_block : keyword_do_block ...@@ -2836,6 +2914,7 @@ do_block : keyword_do_block
{ {
$$ = new_block(p,$3,$4); $$ = new_block(p,$3,$4);
local_unnest(p); local_unnest(p);
nvars_unnest(p);
} }
; ;
...@@ -2906,6 +2985,7 @@ method_call : operation paren_args ...@@ -2906,6 +2985,7 @@ method_call : operation paren_args
brace_block : '{' brace_block : '{'
{ {
local_nest(p); local_nest(p);
nvars_nest(p);
$<num>$ = p->lineno; $<num>$ = p->lineno;
} }
opt_block_param opt_block_param
...@@ -2914,10 +2994,12 @@ brace_block : '{' ...@@ -2914,10 +2994,12 @@ brace_block : '{'
$$ = new_block(p,$3,$4); $$ = new_block(p,$3,$4);
SET_LINENO($$, $<num>2); SET_LINENO($$, $<num>2);
local_unnest(p); local_unnest(p);
nvars_unnest(p);
} }
| keyword_do | keyword_do
{ {
local_nest(p); local_nest(p);
nvars_nest(p);
$<num>$ = p->lineno; $<num>$ = p->lineno;
} }
opt_block_param opt_block_param
...@@ -2926,6 +3008,7 @@ brace_block : '{' ...@@ -2926,6 +3008,7 @@ brace_block : '{'
$$ = new_block(p,$3,$4); $$ = new_block(p,$3,$4);
SET_LINENO($$, $<num>2); SET_LINENO($$, $<num>2);
local_unnest(p); local_unnest(p);
nvars_unnest(p);
} }
; ;
...@@ -3182,6 +3265,10 @@ variable : tIDENTIFIER ...@@ -3182,6 +3265,10 @@ variable : tIDENTIFIER
{ {
$$ = new_cvar(p, $1); $$ = new_cvar(p, $1);
} }
| tNUMPARAM
{
$$ = new_nvar(p, $1);
}
| tCONSTANT | tCONSTANT
{ {
$$ = new_const(p, $1); $$ = new_const(p, $1);
...@@ -5788,14 +5875,36 @@ parser_yylex(parser_state *p) ...@@ -5788,14 +5875,36 @@ parser_yylex(parser_state *p)
} }
else if (ISDIGIT(c)) { else if (ISDIGIT(c)) {
if (p->tidx == 1) { if (p->tidx == 1) {
if (last_state == EXPR_FNAME) {
yyerror_c(p, "wrong instance variable name: @", c); yyerror_c(p, "wrong instance variable name: @", c);
return 0;
}
if (c == '0') {
yyerror(p, "leading zero is not allowed as a numbered parameter");
return 0;
}
do {
tokadd(p, c);
c = nextc(p);
} while (c >= 0 && ISDIGIT(c));
pushback(p, c);
tokfix(p);
{
unsigned long n = strtoul(tok(p) + 1, NULL, 10);
if (n > NUMPARAM_MAX || n < 0) {
yyerror(p, "too large numbered parameter");
return 0;
}
pylval.num = n;
}
p->lstate = EXPR_END;
return tNUMPARAM;
} }
else { else {
yyerror_c(p, "wrong class variable name: @@", c); yyerror_c(p, "wrong class variable name: @@", c);
}
return 0; return 0;
} }
if (!identchar(c)) { } else if (!identchar(c)) {
pushback(p, c); pushback(p, c);
return '@'; return '@';
} }
...@@ -6843,6 +6952,10 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset) ...@@ -6843,6 +6952,10 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
printf("NODE_CVAR %s\n", mrb_sym_name(mrb, sym(tree))); printf("NODE_CVAR %s\n", mrb_sym_name(mrb, sym(tree)));
break; break;
case NODE_NVAR:
printf("NODE_NVAR %d\n", intn(tree));
break;
case NODE_CONST: case NODE_CONST:
printf("NODE_CONST %s\n", mrb_sym_name(mrb, sym(tree))); printf("NODE_CONST %s\n", mrb_sym_name(mrb, sym(tree)));
break; break;
......
...@@ -671,3 +671,12 @@ assert 'keyword arguments' do ...@@ -671,3 +671,12 @@ assert 'keyword arguments' do
assert_equal([1, 1, :c], m(c: :c)) assert_equal([1, 1, :c], m(c: :c))
assert_equal([:a, nil, :c], m(a: :a, c: :c)) assert_equal([:a, nil, :c], m(a: :a, c: :c))
end end
assert('numbered parameters') do
assert_equal(15, [1,2,3,4,5].reduce {@1+@2})
assert_equal(3, ->{@1+@2}.call(1,2))
assert_equal(4, ->(a=->{@1}){a}.call.call(4))
assert_equal(5, -> a: ->{@1} {a}.call.call(5))
assert_equal(55, Proc.new do @1 + @2 + @3 + @4 + @5 + @6 + @7 + @8 + @9 + @10 end.call(*[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment