Skip to content

Commit 72d57ad

Browse files
hoshiumiaratamatz
authored andcommitted
Implement numbered parameters
1 parent 8267993 commit 72d57ad

File tree

5 files changed

+143
-4
lines changed

5 files changed

+143
-4
lines changed

include/mruby/compile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ struct mrb_parser_state {
161161
uint16_t current_filename_index;
162162

163163
struct mrb_jmpbuf* jmp;
164+
mrb_ast_node *nvars;
164165
};
165166

166167
MRB_API struct mrb_parser_state* mrb_parser_new(mrb_state*);

mrbgems/mruby-compiler/core/codegen.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,10 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val)
11221122
}
11231123
}
11241124
break;
1125+
case NODE_NVAR:
1126+
idx = nint(tree);
1127+
codegen_error(s, "Can't assign to numbered parameter");
1128+
break;
11251129
case NODE_IVAR:
11261130
idx = new_sym(s, nsym(tree));
11271131
genop_2(s, OP_SETIV, sp, idx);
@@ -2340,6 +2344,17 @@ codegen(codegen_scope *s, node *tree, int val)
23402344
}
23412345
break;
23422346

2347+
case NODE_NVAR:
2348+
if (val) {
2349+
int idx = nint(tree);
2350+
2351+
gen_move(s, cursp(), idx, val);
2352+
if (val && on_eval(s)) genop_0(s, OP_NOP);
2353+
2354+
push();
2355+
}
2356+
break;
2357+
23432358
case NODE_GVAR:
23442359
{
23452360
int sym = new_sym(s, nsym(tree));

mrbgems/mruby-compiler/core/node.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ enum node_type {
5151
NODE_IVAR,
5252
NODE_CONST,
5353
NODE_CVAR,
54+
NODE_NVAR,
5455
NODE_NTH_REF,
5556
NODE_BACK_REF,
5657
NODE_MATCH,

mrbgems/mruby-compiler/core/parse.y

Lines changed: 117 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ typedef unsigned int stack_type;
7474
#define NUM_SUFFIX_R (1<<0)
7575
#define NUM_SUFFIX_I (1<<1)
7676

77+
#define NUMPARAM_MAX 31
78+
7779
static inline mrb_sym
7880
intern_cstr_gen(parser_state *p, const char *s)
7981
{
@@ -315,6 +317,24 @@ locals_node(parser_state *p)
315317
return p->locals ? p->locals->car : NULL;
316318
}
317319

320+
static void
321+
nvars_nest(parser_state *p)
322+
{
323+
p->nvars = cons(p->nvars, nint(0));
324+
}
325+
326+
static void
327+
nvars_block(parser_state *p)
328+
{
329+
p->nvars = cons(p->nvars, nint(-1));
330+
}
331+
332+
static void
333+
nvars_unnest(parser_state *p)
334+
{
335+
p->nvars = p->nvars->car;
336+
}
337+
318338
/* (:scope (vars..) (prog...)) */
319339
static node*
320340
new_scope(parser_state *p, node *body)
@@ -649,6 +669,19 @@ new_cvar(parser_state *p, mrb_sym sym)
649669
return cons((node*)NODE_CVAR, nsym(sym));
650670
}
651671

672+
/* (:nvar . a) */
673+
static node*
674+
new_nvar(parser_state *p, int num)
675+
{
676+
if (!p->nvars || intn(p->nvars->cdr) < 0) {
677+
yyerror(p, "numbered parameter outside block");
678+
} else {
679+
int nvars = intn(p->nvars->cdr);
680+
p->nvars->cdr = nint(nvars > num ? nvars : num);
681+
}
682+
return cons((node*)NODE_NVAR, nint(num));
683+
}
684+
652685
/* (:const . a) */
653686
static node*
654687
new_const(parser_state *p, mrb_sym sym)
@@ -806,17 +839,44 @@ new_block_arg(parser_state *p, node *a)
806839
return cons((node*)NODE_BLOCK_ARG, a);
807840
}
808841

842+
static node*
843+
setup_args(parser_state *p, node *a)
844+
{
845+
int nvars = intn(p->nvars->cdr);
846+
if (nvars > 0) {
847+
int i;
848+
char buf[5];
849+
mrb_sym sym;
850+
// m || opt || rest || tail
851+
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))) {
852+
yyerror(p, "ordinary parameter is defined");
853+
} else {
854+
node* args = 0;
855+
for (i = nvars; i > 0; i--) {
856+
sprintf(buf, "@%d", i);
857+
sym = intern_cstr(buf);
858+
args = cons(new_arg(p, sym), args);
859+
p->locals->car = cons(nsym(sym), p->locals->car);
860+
}
861+
a = new_args(p, args, 0, 0, 0, 0);
862+
}
863+
}
864+
return a;
865+
}
866+
809867
/* (:block arg body) */
810868
static node*
811869
new_block(parser_state *p, node *a, node *b)
812870
{
871+
a = setup_args(p, a);
813872
return list4((node*)NODE_BLOCK, locals_node(p), a, b);
814873
}
815874

816875
/* (:lambda arg body) */
817876
static node*
818877
new_lambda(parser_state *p, node *a, node *b)
819878
{
879+
a = setup_args(p, a);
820880
return list4((node*)NODE_LAMBDA, locals_node(p), a, b);
821881
}
822882

@@ -1334,6 +1394,7 @@ heredoc_end(parser_state *p)
13341394
%token <nd> tSTRING tSTRING_PART tSTRING_MID
13351395
%token <nd> tNTH_REF tBACK_REF
13361396
%token <num> tREGEXP_END
1397+
%token <num> tNUMPARAM
13371398

13381399
%type <nd> singleton string string_fragment string_rep string_interp xstring regexp
13391400
%type <nd> literal numeric cpath symbol
@@ -1466,11 +1527,13 @@ top_stmt : stmt
14661527
| keyword_BEGIN
14671528
{
14681529
$<nd>$ = local_switch(p);
1530+
nvars_block(p);
14691531
}
14701532
'{' top_compstmt '}'
14711533
{
14721534
yyerror(p, "BEGIN not supported");
14731535
local_resume(p, $<nd>2);
1536+
nvars_unnest(p);
14741537
$$ = 0;
14751538
}
14761539
;
@@ -1668,13 +1731,15 @@ block_command : block_call
16681731
cmd_brace_block : tLBRACE_ARG
16691732
{
16701733
local_nest(p);
1734+
nvars_nest(p);
16711735
}
16721736
opt_block_param
16731737
compstmt
16741738
'}'
16751739
{
16761740
$$ = new_block(p, $3, $4);
16771741
local_unnest(p);
1742+
nvars_unnest(p);
16781743
}
16791744
;
16801745

@@ -2410,6 +2475,7 @@ primary : literal
24102475
| tLAMBDA
24112476
{
24122477
local_nest(p);
2478+
nvars_nest(p);
24132479
$<num>$ = p->lpar_beg;
24142480
p->lpar_beg = ++p->paren_nest;
24152481
}
@@ -2423,6 +2489,7 @@ primary : literal
24232489
p->lpar_beg = $<num>2;
24242490
$$ = new_lambda(p, $3, $5);
24252491
local_unnest(p);
2492+
nvars_unnest(p);
24262493
p->cmdarg_stack = $<stack>4;
24272494
CMDARG_LEXPOP();
24282495
}
@@ -2482,13 +2549,15 @@ primary : literal
24822549
if (p->in_def || p->in_single)
24832550
yyerror(p, "class definition in method body");
24842551
$<nd>$ = local_switch(p);
2552+
nvars_block(p);
24852553
}
24862554
bodystmt
24872555
keyword_end
24882556
{
24892557
$$ = new_class(p, $2, $3, $5);
24902558
SET_LINENO($$, $1);
24912559
local_resume(p, $<nd>4);
2560+
nvars_unnest(p);
24922561
}
24932562
| keyword_class
24942563
tLSHFT expr
@@ -2499,6 +2568,7 @@ primary : literal
24992568
term
25002569
{
25012570
$<nd>$ = cons(local_switch(p), nint(p->in_single));
2571+
nvars_block(p);
25022572
p->in_single = 0;
25032573
}
25042574
bodystmt
@@ -2507,6 +2577,7 @@ primary : literal
25072577
$$ = new_sclass(p, $3, $7);
25082578
SET_LINENO($$, $1);
25092579
local_resume(p, $<nd>6->car);
2580+
nvars_unnest(p);
25102581
p->in_def = $<num>4;
25112582
p->in_single = intn($<nd>6->cdr);
25122583
}
@@ -2516,13 +2587,15 @@ primary : literal
25162587
if (p->in_def || p->in_single)
25172588
yyerror(p, "module definition in method body");
25182589
$<nd>$ = local_switch(p);
2590+
nvars_block(p);
25192591
}
25202592
bodystmt
25212593
keyword_end
25222594
{
25232595
$$ = new_module(p, $2, $4);
25242596
SET_LINENO($$, $1);
25252597
local_resume(p, $<nd>3);
2598+
nvars_unnest(p);
25262599
}
25272600
| keyword_def fname
25282601
{
@@ -2532,6 +2605,7 @@ primary : literal
25322605
{
25332606
p->in_def++;
25342607
$<nd>$ = local_switch(p);
2608+
nvars_block(p);
25352609
}
25362610
f_arglist
25372611
bodystmt
@@ -2540,6 +2614,7 @@ primary : literal
25402614
$$ = new_def(p, $2, $5, $6);
25412615
SET_LINENO($$, $1);
25422616
local_resume(p, $<nd>4);
2617+
nvars_unnest(p);
25432618
p->in_def--;
25442619
p->cmdarg_stack = $<stack>3;
25452620
}
@@ -2554,6 +2629,7 @@ primary : literal
25542629
p->in_single++;
25552630
p->lstate = EXPR_ENDFN; /* force for args */
25562631
$<nd>$ = local_switch(p);
2632+
nvars_block(p);
25572633
}
25582634
f_arglist
25592635
bodystmt
@@ -2562,6 +2638,7 @@ primary : literal
25622638
$$ = new_sdef(p, $2, $5, $7, $8);
25632639
SET_LINENO($$, $1);
25642640
local_resume(p, $<nd>6);
2641+
nvars_unnest(p);
25652642
p->in_single--;
25662643
p->cmdarg_stack = $<stack>4;
25672644
}
@@ -2829,13 +2906,15 @@ lambda_body : tLAMBEG compstmt '}'
28292906
do_block : keyword_do_block
28302907
{
28312908
local_nest(p);
2909+
nvars_nest(p);
28322910
}
28332911
opt_block_param
28342912
bodystmt
28352913
keyword_end
28362914
{
28372915
$$ = new_block(p,$3,$4);
28382916
local_unnest(p);
2917+
nvars_unnest(p);
28392918
}
28402919
;
28412920

@@ -2906,6 +2985,7 @@ method_call : operation paren_args
29062985
brace_block : '{'
29072986
{
29082987
local_nest(p);
2988+
nvars_nest(p);
29092989
$<num>$ = p->lineno;
29102990
}
29112991
opt_block_param
@@ -2914,10 +2994,12 @@ brace_block : '{'
29142994
$$ = new_block(p,$3,$4);
29152995
SET_LINENO($$, $<num>2);
29162996
local_unnest(p);
2997+
nvars_unnest(p);
29172998
}
29182999
| keyword_do
29193000
{
29203001
local_nest(p);
3002+
nvars_nest(p);
29213003
$<num>$ = p->lineno;
29223004
}
29233005
opt_block_param
@@ -2926,6 +3008,7 @@ brace_block : '{'
29263008
$$ = new_block(p,$3,$4);
29273009
SET_LINENO($$, $<num>2);
29283010
local_unnest(p);
3011+
nvars_unnest(p);
29293012
}
29303013
;
29313014

@@ -3182,6 +3265,10 @@ variable : tIDENTIFIER
31823265
{
31833266
$$ = new_cvar(p, $1);
31843267
}
3268+
| tNUMPARAM
3269+
{
3270+
$$ = new_nvar(p, $1);
3271+
}
31853272
| tCONSTANT
31863273
{
31873274
$$ = new_const(p, $1);
@@ -5788,14 +5875,36 @@ parser_yylex(parser_state *p)
57885875
}
57895876
else if (ISDIGIT(c)) {
57905877
if (p->tidx == 1) {
5791-
yyerror_c(p, "wrong instance variable name: @", c);
5878+
if (last_state == EXPR_FNAME) {
5879+
yyerror_c(p, "wrong instance variable name: @", c);
5880+
return 0;
5881+
}
5882+
if (c == '0') {
5883+
yyerror(p, "leading zero is not allowed as a numbered parameter");
5884+
return 0;
5885+
}
5886+
do {
5887+
tokadd(p, c);
5888+
c = nextc(p);
5889+
} while (c >= 0 && ISDIGIT(c));
5890+
pushback(p, c);
5891+
tokfix(p);
5892+
{
5893+
unsigned long n = strtoul(tok(p) + 1, NULL, 10);
5894+
if (n > NUMPARAM_MAX || n < 0) {
5895+
yyerror(p, "too large numbered parameter");
5896+
return 0;
5897+
}
5898+
pylval.num = n;
5899+
}
5900+
p->lstate = EXPR_END;
5901+
return tNUMPARAM;
57925902
}
57935903
else {
57945904
yyerror_c(p, "wrong class variable name: @@", c);
5905+
return 0;
57955906
}
5796-
return 0;
5797-
}
5798-
if (!identchar(c)) {
5907+
} else if (!identchar(c)) {
57995908
pushback(p, c);
58005909
return '@';
58015910
}
@@ -6843,6 +6952,10 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
68436952
printf("NODE_CVAR %s\n", mrb_sym_name(mrb, sym(tree)));
68446953
break;
68456954

6955+
case NODE_NVAR:
6956+
printf("NODE_NVAR %d\n", intn(tree));
6957+
break;
6958+
68466959
case NODE_CONST:
68476960
printf("NODE_CONST %s\n", mrb_sym_name(mrb, sym(tree)));
68486961
break;

test/t/syntax.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,3 +671,12 @@ def m(a: b = 1, c:) [a, b, c] end
671671
assert_equal([1, 1, :c], m(c: :c))
672672
assert_equal([:a, nil, :c], m(a: :a, c: :c))
673673
end
674+
675+
676+
assert('numbered parameters') do
677+
assert_equal(15, [1,2,3,4,5].reduce {@1+@2})
678+
assert_equal(3, ->{@1+@2}.call(1,2))
679+
assert_equal(4, ->(a=->{@1}){a}.call.call(4))
680+
assert_equal(5, -> a: ->{@1} {a}.call.call(5))
681+
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]))
682+
end

0 commit comments

Comments
 (0)