diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2018-11-25 09:01:14 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2018-11-25 09:07:49 +0900 |
| commit | 762f682b80460929d9c69b1957bcb2aad108ec93 (patch) | |
| tree | edc7d10dd061949ca605a3fac88148c6b0283256 | |
| parent | e6b72b2121b981c504f902723b3c1531be001c02 (diff) | |
| download | mruby-762f682b80460929d9c69b1957bcb2aad108ec93.tar.gz mruby-762f682b80460929d9c69b1957bcb2aad108ec93.zip | |
Allow destructuring in formal arguments.
e.g.
```
def m(a,(b,c),d); p [a,b,c,d]; end
m(1,[2,3],4) # => [1,2,3,4]
```
mruby limitation:
Destructured arguments (`b` and `c` in above example) cannot be accessed
from the default expression of optional arguments and keyword arguments,
since actual assignment is done after the evaluation of those default
expressions. Thus:
```
def f(a,(b,c),d=b)
p [a,b,c,d]
end
f(1,[2,3])
```
raises `NoMethodError` for `b` in mruby.
| -rw-r--r-- | mrbgems/mruby-compiler/core/codegen.c | 40 | ||||
| -rw-r--r-- | mrbgems/mruby-compiler/core/parse.y | 31 |
2 files changed, 63 insertions, 8 deletions
diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index ba7d8cf63..b3659863b 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -734,15 +734,13 @@ lambda_body(codegen_scope *s, node *tree, int blk) mrb_aspec a; int ma, oa, ra, pa, ka, kd, ba; int pos, i; - node *n, *opt; + node *opt; + node *margs, *pargs; node *tail; /* mandatory arguments */ ma = node_len(tree->car->car); - n = tree->car->car; - while (n) { - n = n->cdr; - } + margs = tree->car->car; tail = tree->car->cdr->cdr->cdr->cdr; /* optional arguments */ @@ -751,6 +749,7 @@ lambda_body(codegen_scope *s, node *tree, int blk) ra = tree->car->cdr->cdr->car ? 1 : 0; /* mandatory arugments after rest argument */ 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; /* keyword dictionary? */ @@ -798,6 +797,7 @@ lambda_body(codegen_scope *s, node *tree, int blk) dispatch(s, pos+i*3+1); } + /* keyword arguments */ if (tail) { node *kwds = tail->cdr->car; int kwrest = 0; @@ -836,7 +836,34 @@ lambda_body(codegen_scope *s, node *tree, int blk) genop_0(s, OP_KEYEND); } } + + /* argument destructuring */ + if (margs) { + node *n = margs; + + pos = 1; + while (n) { + if (nint(n->car->car) == NODE_MASGN) { + gen_vmassignment(s, n->car->cdr->car, pos, NOVAL); + } + pos++; + n = n->cdr; + } + } + if (pargs) { + node *n = margs; + + pos = ma+oa+ra+1; + while (n) { + if (nint(n->car->car) == NODE_MASGN) { + gen_vmassignment(s, n->car->cdr->car, pos, NOVAL); + } + pos++; + n = n->cdr; + } + } } + codegen(s, tree->cdr->car, VAL); pop(); if (s->pc > 0) { @@ -1066,6 +1093,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val) idx = new_sym(s, nsym(tree)); genop_2(s, OP_SETGV, sp, idx); break; + case NODE_ARG: case NODE_LVAR: idx = lv_idx(s, nsym(tree)); if (idx > 0) { @@ -1173,7 +1201,7 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val) pop_n(post+1); genop_3(s, OP_APOST, cursp(), n, post); n = 1; - if (t->car) { /* rest */ + if (t->car && t->car != (node*)-1) { /* rest */ gen_assignment(s, t->car, cursp(), NOVAL); } if (t->cdr && t->cdr->car) { diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index 1485fb086..d143344c3 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -682,6 +682,25 @@ new_arg(parser_state *p, mrb_sym sym) return cons((node*)NODE_ARG, nsym(sym)); } +static void +local_add_margs(parser_state *p, node *n) +{ + while (n) { + if (n->car->car == (node*)NODE_MASGN) { + node *t = n->car->cdr->cdr; + + n->car->cdr->cdr = NULL; + while (t) { + local_add_f(p, sym(t->car)); + t = t->cdr; + } + local_add_margs(p, n->car->cdr->car->car); + local_add_margs(p, n->car->cdr->car->cdr->cdr->car); + } + n = n->cdr; + } +} + /* (m o r m2 tail) */ /* m: (a b c) */ /* o: ((a . e1) (b . e2)) */ @@ -693,6 +712,8 @@ new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, node *tail { node *n; + local_add_margs(p, m); + local_add_margs(p, m2); n = cons(m2, tail); n = cons(nsym(rest), n); n = cons(opt, n); @@ -3275,9 +3296,15 @@ f_arg_item : f_norm_arg { $$ = new_arg(p, $1); } - | tLPAREN f_margs rparen + | tLPAREN + { + $<nd>$ = local_switch(p); + } + f_margs rparen { - $$ = new_masgn(p, $2, 0); + $$ = new_masgn(p, $3, p->locals->car); + local_resume(p, $<nd>2); + local_add_f(p, 0); } ; |
