summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorHiroshi Mimaki <[email protected]>2018-11-27 09:09:20 +0900
committerHiroshi Mimaki <[email protected]>2018-11-27 09:09:20 +0900
commite3ae0e4f2962418106875217adcd4f5971ce4689 (patch)
tree3000278ca91d089918c3b6103aedcff71baed99d
parent0711c861ca939c73bed9d91601f6cc38bdf474ba (diff)
parent26475d0a7897c25f8632b776014a19c3a6f6ecc2 (diff)
downloadmruby-e3ae0e4f2962418106875217adcd4f5971ce4689.tar.gz
mruby-e3ae0e4f2962418106875217adcd4f5971ce4689.zip
Merge branch 'master' into stable
-rw-r--r--doc/limitations.md22
-rw-r--r--include/mruby/irep.h5
-rw-r--r--include/mruby/throw.h8
-rw-r--r--mrbgems/mruby-array-ext/mrblib/array.rb2
-rw-r--r--mrbgems/mruby-bin-mirb/tools/mirb/mirb.c12
-rw-r--r--mrbgems/mruby-compiler/core/codegen.c40
-rw-r--r--mrbgems/mruby-compiler/core/parse.y67
7 files changed, 112 insertions, 44 deletions
diff --git a/doc/limitations.md b/doc/limitations.md
index 92858cb1f..825435f01 100644
--- a/doc/limitations.md
+++ b/doc/limitations.md
@@ -219,7 +219,7 @@ $ ruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)'
[[{"a"=>1}], {:b=>2}]
```
-#### mruby []
+#### mruby [mruby 2.0.0]
```
$ ./bin/mruby -e 'def m(*r,**k) p [r,k] end; m("a"=>1,:b=>2)'
@@ -227,3 +227,23 @@ trace (most recent call last):
[0] -e:1
-e:1: keyword argument hash with non symbol keys (ArgumentError)
```
+
+## Argument Destructuring
+
+```ruby
+def m(a,(b,c),d); p [a,b,c,d]; end
+m(1,[2,3],4) # => [1,2,3,4]
+```
+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:
+
+```ruby
+def f(a,(b,c),d=b)
+ p [a,b,c,d]
+end
+f(1,[2,3])
+```
+
+CRuby gives `[1,2,3,nil]`. mruby raises `NoMethodError` for `b`.
diff --git a/include/mruby/irep.h b/include/mruby/irep.h
index 78cbc2b74..027a294d5 100644
--- a/include/mruby/irep.h
+++ b/include/mruby/irep.h
@@ -48,8 +48,13 @@ typedef struct mrb_irep {
#define MRB_ISEQ_NO_FREE 1
MRB_API mrb_irep *mrb_add_irep(mrb_state *mrb);
+
+/* @param [const uint8_t*] irep code, expected as a literal */
MRB_API mrb_value mrb_load_irep(mrb_state*, const uint8_t*);
+
+/* @param [const uint8_t*] irep code, expected as a literal */
MRB_API mrb_value mrb_load_irep_cxt(mrb_state*, const uint8_t*, mrbc_context*);
+
void mrb_irep_free(mrb_state*, struct mrb_irep*);
void mrb_irep_incref(mrb_state*, struct mrb_irep*);
void mrb_irep_decref(mrb_state*, struct mrb_irep*);
diff --git a/include/mruby/throw.h b/include/mruby/throw.h
index 5d3d214e7..4a1fd8d60 100644
--- a/include/mruby/throw.h
+++ b/include/mruby/throw.h
@@ -15,9 +15,9 @@
#if defined(MRB_ENABLE_CXX_EXCEPTION) && defined(__cplusplus)
-#define MRB_TRY(buf) do { try {
+#define MRB_TRY(buf) try {
#define MRB_CATCH(buf) } catch(mrb_jmpbuf_impl e) { if (e != (buf)->impl) { throw e; }
-#define MRB_END_EXC(buf) } } while(0)
+#define MRB_END_EXC(buf) }
#define MRB_THROW(buf) throw((buf)->impl)
typedef mrb_int mrb_jmpbuf_impl;
@@ -34,9 +34,9 @@ typedef mrb_int mrb_jmpbuf_impl;
#define MRB_LONGJMP longjmp
#endif
-#define MRB_TRY(buf) do { if (MRB_SETJMP((buf)->impl) == 0) {
+#define MRB_TRY(buf) if (MRB_SETJMP((buf)->impl) == 0) {
#define MRB_CATCH(buf) } else {
-#define MRB_END_EXC(buf) } } while(0)
+#define MRB_END_EXC(buf) }
#define MRB_THROW(buf) MRB_LONGJMP((buf)->impl, 1);
#define mrb_jmpbuf_impl jmp_buf
diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb
index bb95d70c5..6096696cb 100644
--- a/mrbgems/mruby-array-ext/mrblib/array.rb
+++ b/mrbgems/mruby-array-ext/mrblib/array.rb
@@ -291,7 +291,7 @@ class Array
# #=> "100 is out of bounds"
#
- def fetch(n=nil, ifnone=NONE, &block)
+ def fetch(n, ifnone=NONE, &block)
warn "block supersedes default value argument" if !n.nil? && ifnone != NONE && block
idx = n
diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
index 19f533acd..8d7c719d8 100644
--- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
+++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
@@ -56,6 +56,7 @@
#include <mruby/dump.h>
#include <mruby/string.h>
#include <mruby/variable.h>
+#include <mruby/throw.h>
#ifdef ENABLE_READLINE
@@ -491,7 +492,10 @@ main(int argc, char **argv)
while (TRUE) {
char *utf8;
+ struct mrb_jmpbuf c_jmp;
+ MRB_TRY(&c_jmp);
+ mrb->jmp = &c_jmp;
if (args.rfp) {
if (fgets(last_code_line, sizeof(last_code_line)-1, args.rfp) != NULL)
goto done;
@@ -555,8 +559,7 @@ main(int argc, char **argv)
MIRB_LINE_FREE(line);
#endif
-done:
-
+ done:
if (code_block_open) {
if (strlen(ruby_code)+strlen(last_code_line) > sizeof(ruby_code)-1) {
fputs("concatenated input string too long\n", stderr);
@@ -648,6 +651,11 @@ done:
}
mrb_parser_free(parser);
cxt->lineno++;
+ MRB_CATCH(&c_jmp) {
+ p(mrb, mrb_obj_value(mrb->exc), 0);
+ mrb->exc = 0;
+ }
+ MRB_END_EXC(&c_jmp);
}
#ifdef ENABLE_READLINE
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 70b9d0fc4..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);
@@ -1171,7 +1192,7 @@ heredoc_end(parser_state *p)
%type <nd> command_args aref_args opt_block_arg block_arg var_ref var_lhs
%type <nd> command_asgn command_rhs mrhs superclass block_call block_command
%type <nd> f_block_optarg f_block_opt
-%type <nd> f_arglist f_args f_arg f_arg_item f_optarg f_marg f_marg_list f_margs
+%type <nd> f_arglist f_args f_arg f_arg_item f_optarg f_margs
%type <nd> assoc_list assocs assoc undef_list backref for_var
%type <nd> block_param opt_block_param block_param_def f_opt
%type <nd> bv_decls opt_bv_decl bvar f_larglist lambda_body
@@ -2447,44 +2468,24 @@ for_var : lhs
| mlhs
;
-f_marg : f_norm_arg
- {
- $$ = new_arg(p, $1);
- }
- | tLPAREN f_margs rparen
- {
- $$ = new_masgn(p, $2, 0);
- }
- ;
-
-f_marg_list : f_marg
- {
- $$ = list1($1);
- }
- | f_marg_list ',' f_marg
- {
- $$ = push($1, $3);
- }
- ;
-
-f_margs : f_marg_list
+f_margs : f_arg
{
$$ = list3($1,0,0);
}
- | f_marg_list ',' tSTAR f_norm_arg
+ | f_arg ',' tSTAR f_norm_arg
{
$$ = list3($1, new_arg(p, $4), 0);
}
- | f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list
+ | f_arg ',' tSTAR f_norm_arg ',' f_arg
{
$$ = list3($1, new_arg(p, $4), $6);
}
- | f_marg_list ',' tSTAR
+ | f_arg ',' tSTAR
{
local_add_f(p, 0);
$$ = list3($1, (node*)-1, 0);
}
- | f_marg_list ',' tSTAR ',' f_marg_list
+ | f_arg ',' tSTAR ',' f_arg
{
$$ = list3($1, (node*)-1, $5);
}
@@ -2492,7 +2493,7 @@ f_margs : f_marg_list
{
$$ = list3(0, new_arg(p, $2), 0);
}
- | tSTAR f_norm_arg ',' f_marg_list
+ | tSTAR f_norm_arg ',' f_arg
{
$$ = list3(0, new_arg(p, $2), $4);
}
@@ -2505,7 +2506,7 @@ f_margs : f_marg_list
{
local_add_f(p, 0);
}
- f_marg_list
+ f_arg
{
$$ = list3(0, (node*)-1, $4);
}
@@ -3295,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);
}
;