mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-compier: keep stack reference to passed block after modifying &b
To mark `MRB_PROC_ORPHAN` we need to keep track of passed block, even after the assignment to the block argument. And `yield` should use the original block; #5786, #5791, #6369
This commit is contained in:
@@ -1376,7 +1376,7 @@ lambda_body(codegen_scope *s, node *tree, int blk)
|
||||
pa = node_len(tree->car->cdr->cdr->cdr->car);
|
||||
pargs = tree->car->cdr->cdr->cdr->car;
|
||||
/* keyword arguments */
|
||||
ka = tail? node_len(tail->cdr->car) : 0;
|
||||
ka = tail ? node_len(tail->cdr->car) : 0;
|
||||
/* keyword dictionary? */
|
||||
kd = tail && tail->cdr->cdr->car? 1 : 0;
|
||||
/* block argument? */
|
||||
@@ -1388,16 +1388,16 @@ lambda_body(codegen_scope *s, node *tree, int blk)
|
||||
/* (23bits = 5:5:1:5:5:1:1) */
|
||||
a = MRB_ARGS_REQ(ma)
|
||||
| MRB_ARGS_OPT(oa)
|
||||
| (ra? MRB_ARGS_REST() : 0)
|
||||
| (ra ? MRB_ARGS_REST() : 0)
|
||||
| MRB_ARGS_POST(pa)
|
||||
| MRB_ARGS_KEY(ka, kd)
|
||||
| (ba? MRB_ARGS_BLOCK() : 0);
|
||||
| (ba ? MRB_ARGS_BLOCK() : 0);
|
||||
genop_W(s, OP_ENTER, a);
|
||||
/* (12bits = 5:1:5:1) */
|
||||
s->ainfo = (((ma+oa) & 0x3f) << 7)
|
||||
| ((ra & 0x1) << 6)
|
||||
| ((pa & 0x1f) << 1)
|
||||
| ((ka | kd) ? 1 : 0);
|
||||
| (ka || kd);
|
||||
/* generate jump table for optional arguments initializer */
|
||||
pos = new_label(s);
|
||||
for (i=0; i<oa; i++) {
|
||||
@@ -1475,6 +1475,14 @@ lambda_body(codegen_scope *s, node *tree, int blk)
|
||||
if (tail->cdr->car && !kwrest) {
|
||||
genop_0(s, OP_KEYEND);
|
||||
}
|
||||
if (ba) {
|
||||
mrb_sym bparam = nsym(tail->cdr->cdr->cdr->car);
|
||||
pos = ma+oa+ra+pa+(ka||kd);
|
||||
if (bparam) {
|
||||
int idx = lv_idx(s, bparam);
|
||||
genop_2(s, OP_MOVE, idx, pos+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* argument destructuring */
|
||||
|
||||
@@ -334,12 +334,8 @@ local_add(parser_state *p, mrb_sym sym)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
local_add_blk(parser_state *p, mrb_sym blk)
|
||||
{
|
||||
/* allocate register for block */
|
||||
local_add_f(p, blk ? blk : 0);
|
||||
}
|
||||
/* allocate register for block */
|
||||
#define local_add_blk(p) local_add_f(p, 0)
|
||||
|
||||
static void
|
||||
local_add_kw(parser_state *p, mrb_sym kwd)
|
||||
@@ -865,7 +861,8 @@ new_args_tail(parser_state *p, node *kws, node *kwrest, mrb_sym blk)
|
||||
local_add_kw(p, (kwrest && kwrest->cdr)? sym(kwrest->cdr) : 0);
|
||||
}
|
||||
|
||||
local_add_blk(p, blk);
|
||||
local_add_blk(p);
|
||||
if (blk) local_add_f(p, blk);
|
||||
|
||||
/* allocate register for keywords arguments */
|
||||
/* order is for Proc#parameters */
|
||||
@@ -3096,7 +3093,7 @@ block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail
|
||||
|
||||
opt_block_param : none
|
||||
{
|
||||
local_add_blk(p, 0);
|
||||
local_add_blk(p);
|
||||
$$ = 0;
|
||||
}
|
||||
| block_param_def
|
||||
@@ -3106,13 +3103,13 @@ opt_block_param : none
|
||||
}
|
||||
;
|
||||
|
||||
block_param_def : '|' {local_add_blk(p, 0);} opt_bv_decl '|'
|
||||
block_param_def : '|' {local_add_blk(p);} opt_bv_decl '|'
|
||||
{
|
||||
$$ = 0;
|
||||
}
|
||||
| tOROP
|
||||
{
|
||||
local_add_blk(p, 0);
|
||||
local_add_blk(p);
|
||||
$$ = 0;
|
||||
}
|
||||
| '|' block_param opt_bv_decl '|'
|
||||
|
||||
@@ -152,6 +152,9 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
|
||||
mrb_ary_push(mrb, a, mrb_symbol_value(irep->lv[i]));
|
||||
}
|
||||
if (p->name == MRB_SYM(block)) {
|
||||
if (irep->lv[i+1]) {
|
||||
mrb_ary_push(mrb, a, mrb_symbol_value(irep->lv[i+1]));
|
||||
}
|
||||
block = a; continue;
|
||||
}
|
||||
if (p->name == MRB_SYM(keyrest)) {
|
||||
|
||||
@@ -33,11 +33,6 @@ assert('Proc#inspect') do
|
||||
assert_match "#<Proc:0x* #{file}:#{line}>", ins
|
||||
end
|
||||
|
||||
assert('Proc#parameters') do
|
||||
parameters = Proc.new{|x,y=42,*other|}.parameters
|
||||
assert_equal [[:opt, :x], [:opt, :y], [:rest, :other]], parameters
|
||||
end
|
||||
|
||||
assert('Proc#lambda?') do
|
||||
assert_true lambda{}.lambda?
|
||||
assert_true !Proc.new{}.lambda?
|
||||
@@ -80,6 +75,7 @@ assert('Proc#parameters') do
|
||||
assert_equal([[:req, :a]], ->(a){}.parameters)
|
||||
assert_equal([[:rest, :*]], lambda { |*| }.parameters)
|
||||
assert_equal([[:rest, :a]], Proc.new {|*a|}.parameters)
|
||||
assert_equal([[:opt, :x], [:opt, :y], [:rest, :other]], Proc.new{|x,y=42,*other|}.parameters)
|
||||
assert_equal([[:opt, :a], [:opt, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:opt, :f], [:opt, :g], [:block, :h]], Proc.new {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters)
|
||||
assert_equal([[:req, :a], [:req, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:req, :f], [:req, :g], [:block, :h]], lambda {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user