SHARE
TWEET

Untitled

a guest Apr 21st, 2017 47 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. modified   include/mruby.h
  2. @@ -109,6 +109,8 @@ typedef void* (*mrb_allocf) (struct mrb_state *mrb, void*, size_t, void *ud);
  3.  
  4.  typedef struct {
  5.    mrb_sym mid;
  6. +  mrb_bool use_kdict: 1;
  7. +  mrb_bool need_kdict_dup: 1;
  8.    struct RProc *proc;
  9.    mrb_value *stackent;
  10.    int nregs;
  11. @@ -120,6 +122,7 @@ typedef struct {
  12.    int argc;
  13.    int acc;
  14.    struct RClass *target_class;
  15. +  mrb_value *kwds;
  16.  } mrb_callinfo;
  17.  
  18.  enum mrb_fiber_state {
  19. modified   include/mruby/opcode.h
  20. @@ -96,8 +96,12 @@ enum {
  21.    OP_SUPER,/*     A C     R(A) := super(R(A+1),... ,R(A+C+1))             */
  22.    OP_ARGARY,/*    A Bx    R(A) := argument array (16=6:1:5:4)             */
  23.    OP_ENTER,/*     Ax      arg setup according to flags (23=5:5:1:5:5:1:1) */
  24. -  OP_KARG,/*      A B C   R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B))  */
  25. +  OP_KARG,/*      A B C   R(A) := kdict[Syms(B)]                          */
  26. +  /*                      R(A+1) := kdict.key?(Syms(B)) if C == 1         */
  27. +  /*                      raise ArgumentError if C == 2 && !kdict.key?(Syms(B)) */
  28. +  /*                      kdict.delete(Syms(B)) if C >= 1                 */
  29.    OP_KDICT,/*     A C     R(A) := kdict                                   */
  30. +  /*                      raise ArgumentError if C && !kdict.empty?       */
  31.  
  32.    OP_RETURN,/*    A B     return R(A) (B=normal,in-block return/break)    */
  33.    OP_TAILCALL,/*  A B C   return call(R(A),Syms(B),*R(C))                 */
  34. @@ -141,7 +145,11 @@ enum {
  35.    OP_STOP,/*              stop VM                                         */
  36.    OP_ERR,/*       Bx      raise RuntimeError with message Lit(Bx)         */
  37.  
  38. -  OP_RSVD1,/*             reserved instruction #1                         */
  39. +  OP_SENDK,/*     A B C   R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),    */
  40. +  /*                                   &R(A+C+1),                         */
  41. +  /*                                   R(A+C+2),R(A+C+2+1)...,            */
  42. +  /*                                   R(A+C+2+2K),R(A+C+2+2K+1),nil)     */
  43. +
  44.    OP_RSVD2,/*             reserved instruction #2                         */
  45.    OP_RSVD3,/*             reserved instruction #3                         */
  46.    OP_RSVD4,/*             reserved instruction #4                         */
  47. modified   mrbgems/mruby-compiler/core/codegen.c
  48. @@ -19,7 +19,7 @@
  49.  #include <mruby/re.h>
  50.  #include <mruby/throw.h>
  51.  
  52. -typedef mrb_ast_node node;
  53. +typedef mrb_ast_node const* node;
  54.  typedef struct mrb_parser_state parser_state;
  55.  
  56.  enum looptype {
  57. @@ -44,7 +44,7 @@ typedef struct scope {
  58.  
  59.    struct scope *prev;
  60.  
  61. -  node *lv;
  62. +  node lv;
  63.  
  64.    int sp;
  65.    int pc;
  66. @@ -75,16 +75,16 @@ typedef struct scope {
  67.    parser_state* parser;
  68.  } codegen_scope;
  69.  
  70. -static codegen_scope* scope_new(mrb_state *mrb, codegen_scope *prev, node *lv);
  71. +static codegen_scope* scope_new(mrb_state *mrb, codegen_scope *prev, node lv);
  72.  static void scope_finish(codegen_scope *s);
  73.  static struct loopinfo *loop_push(codegen_scope *s, enum looptype t);
  74. -static void loop_break(codegen_scope *s, node *tree);
  75. +static void loop_break(codegen_scope *s, node tree);
  76.  static void loop_pop(codegen_scope *s, int val);
  77.  
  78. -static void gen_assignment(codegen_scope *s, node *tree, int sp, int val);
  79. -static void gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val);
  80. +static void gen_assignment(codegen_scope *s, node tree, int sp, int val);
  81. +static void gen_vmassignment(codegen_scope *s, node tree, int rhs, int val);
  82.  
  83. -static void codegen(codegen_scope *s, node *tree, int val);
  84. +static void codegen(codegen_scope *s, node tree, int val);
  85.  static void raise_error(codegen_scope *s, const char *msg);
  86.  
  87.  static void
  88. @@ -556,7 +556,7 @@ new_sym(codegen_scope *s, mrb_sym sym)
  89.  }
  90.  
  91.  static int
  92. -node_len(node *tree)
  93. +node_len(node tree)
  94.  {
  95.    int n = 0;
  96.  
  97. @@ -572,7 +572,7 @@ node_len(node *tree)
  98.  static int
  99.  lv_idx(codegen_scope *s, mrb_sym id)
  100.  {
  101. -  node *lv = s->lv;
  102. +  node lv = s->lv;
  103.    int n = 1;
  104.  
  105.    while (lv) {
  106. @@ -584,12 +584,12 @@ lv_idx(codegen_scope *s, mrb_sym id)
  107.  }
  108.  
  109.  static void
  110. -for_body(codegen_scope *s, node *tree)
  111. +for_body(codegen_scope *s, node tree)
  112.  {
  113.    codegen_scope *prev = s;
  114.    int idx;
  115.    struct loopinfo *lp;
  116. -  node *n2;
  117. +  node n2;
  118.    mrb_code c;
  119.  
  120.    /* generate receiver */
  121. @@ -632,8 +632,22 @@ for_body(codegen_scope *s, node *tree)
  122.    genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, 0));
  123.  }
  124.  
  125. +/* count optional keywords */
  126.  static int
  127. -lambda_body(codegen_scope *s, node *tree, int blk)
  128. +kw_count_opt(node kws)
  129. +{
  130. +  int ret = 0;
  131. +
  132. +  while(kws) {
  133. +    if (kws->car->cdr->cdr->car) ++ret;
  134. +    kws = kws->cdr;
  135. +  }
  136. +
  137. +  return ret;
  138. +}
  139. +
  140. +static int
  141. +lambda_body(codegen_scope *s, node tree, int blk)
  142.  {
  143.    mrb_code c;
  144.    codegen_scope *parent = s;
  145. @@ -653,33 +667,46 @@ lambda_body(codegen_scope *s, node *tree, int blk)
  146.      mrb_aspec a;
  147.      int ma, oa, ra, pa, ka, kd, ba;
  148.      int pos, i;
  149. -    node *n, *opt;
  150. +    node n, opt;
  151. +    node tail;
  152.  
  153. +    // mandatory arguments
  154.      ma = node_len(tree->car->car);
  155.      n = tree->car->car;
  156.      while (n) {
  157.        n = n->cdr;
  158.      }
  159. +
  160. +    tail = tree->car->cdr->cdr->cdr->cdr;
  161. +
  162. +    // optional arguments
  163.      oa = node_len(tree->car->cdr->car);
  164. +    // rest arguments
  165.      ra = tree->car->cdr->cdr->car ? 1 : 0;
  166. +    // post required arguments
  167.      pa = node_len(tree->car->cdr->cdr->cdr->car);
  168. -    ka = kd = 0;
  169. -    ba = tree->car->cdr->cdr->cdr->cdr ? 1 : 0;
  170. +    // required keyword arguments
  171. +    ka = tail? node_len(tail->cdr->car) - kw_count_opt(tail->cdr->car) : 0;
  172. +    // keyword dictionary?
  173. +    kd = tail && (tail->cdr->car || tail->cdr->cdr->car)? 1 : 0;
  174. +    // block argument?
  175. +    ba = tail && tail->cdr->cdr->cdr->car ? 1 : 0;
  176.  
  177.      if (ma > 0x1f || oa > 0x1f || pa > 0x1f || ka > 0x1f) {
  178.        codegen_error(s, "too many formal arguments");
  179.      }
  180. -    a = ((mrb_aspec)(ma & 0x1f) << 18)
  181. -      | ((mrb_aspec)(oa & 0x1f) << 13)
  182. -      | ((ra & 1) << 12)
  183. -      | ((pa & 0x1f) << 7)
  184. -      | ((ka & 0x1f) << 2)
  185. -      | ((kd & 1)<< 1)
  186. -      | (ba & 1);
  187. +    a = MRB_ARGS_REQ(ma)
  188. +      | MRB_ARGS_OPT(oa)
  189. +      | (ra? MRB_ARGS_REST() : 0)
  190. +      | MRB_ARGS_POST(pa)
  191. +      | MRB_ARGS_KEY(ka, kd)
  192. +      | (ba? MRB_ARGS_BLOCK() : 0);
  193.      s->ainfo = (((ma+oa) & 0x3f) << 6) /* (12bits = 6:1:5) */
  194.        | ((ra & 1) << 5)
  195.        | (pa & 0x1f);
  196. +    // format arguments for this irep
  197.      genop(s, MKOP_Ax(OP_ENTER, a));
  198. +    // generate jump table for optional arguments initializer
  199.      pos = new_label(s);
  200.      for (i=0; i<oa; i++) {
  201.        new_label(s);
  202. @@ -704,6 +731,40 @@ lambda_body(codegen_scope *s, node *tree, int blk)
  203.      if (oa > 0) {
  204.        dispatch(s, pos+i);
  205.      }
  206. +
  207. +    if (tail) {
  208. +      int const kdict = 1 + ma + oa + ra + pa;
  209. +      node const kwds = tail->cdr->car;
  210. +      node const kwrest = tail->cdr->cdr->car;
  211. +      // mrb_sym blk = sym(tail->cdr->cdr->cdr->car);
  212. +      node k;
  213. +
  214. +      mrb_assert((intptr_t)tail->car == NODE_ARGS_TAIL);
  215. +      mrb_assert(node_len(tail) == 4);
  216. +
  217. +      for (k = kwds; k; k = k->cdr) {
  218. +        node kwd = k->car, def_arg = kwd->cdr->cdr->car;
  219. +        mrb_sym kwd_sym = sym(kwd->cdr->car);
  220. +
  221. +        mrb_assert((intptr_t)kwd->car == NODE_KW_ARG);
  222. +
  223. +        if (def_arg) {
  224. +          int jmpif_key_p;
  225. +          genop(s, MKOP_ABC(OP_KARG, cursp(), new_msym(s, kwd_sym), 1));
  226. +          jmpif_key_p = genop(s, MKOP_AsBx(OP_JMPIF, cursp() + 1, 0));
  227. +          codegen(s, def_arg, VAL);
  228. +          pop();
  229. +          dispatch(s, jmpif_key_p);
  230. +          genop(s, MKOP_AB(OP_MOVE, lv_idx(s, kwd_sym), cursp()));
  231. +        } else {
  232. +          genop(s, MKOP_ABC(OP_KARG, lv_idx(s, kwd_sym), new_msym(s, kwd_sym), 2));
  233. +        }
  234. +      }
  235. +
  236. +      if (kwrest || kwds) {
  237. +        genop(s, MKOP_ABC(OP_KDICT, kdict, 0, kwrest? 0 : 1));
  238. +      }
  239. +    }
  240.    }
  241.    codegen(s, tree->cdr->car, VAL);
  242.    pop();
  243. @@ -727,7 +788,7 @@ lambda_body(codegen_scope *s, node *tree, int blk)
  244.  }
  245.  
  246.  static int
  247. -scope_body(codegen_scope *s, node *tree, int val)
  248. +scope_body(codegen_scope *s, node tree, int val)
  249.  {
  250.    codegen_scope *scope = scope_new(s->mrb, s, tree->car);
  251.    if (scope == NULL) {
  252. @@ -759,7 +820,7 @@ scope_body(codegen_scope *s, node *tree, int val)
  253.  }
  254.  
  255.  static mrb_bool
  256. -nosplat(node *t)
  257. +nosplat(node t)
  258.  {
  259.    while (t) {
  260.      if ((intptr_t)t->car->car == NODE_SPLAT) return FALSE;
  261. @@ -791,13 +852,37 @@ attrsym(codegen_scope *s, mrb_sym a)
  262.  
  263.  #define CALL_MAXARGS 127
  264.  
  265. +// check NODE_KW_HASH with non-symbol key
  266. +static mrb_bool
  267. +check_symbol_only_kw_hash_p(node t)
  268. +{
  269. +  if ((intptr_t)t->car == NODE_KW_HASH) {
  270. +    node n;
  271. +    int non_sym = 0;
  272. +    for (n = t->cdr; n; n = n->cdr) {
  273. +      switch ((intptr_t)n->car->car->car) {
  274. +      case NODE_KW_REST_ARGS:
  275. +      case NODE_SYM:
  276. +        break;
  277. +      default:
  278. +        ++non_sym;
  279. +        break;
  280. +      }
  281. +    }
  282. +
  283. +    if (non_sym == 0) { return TRUE; }
  284. +  }
  285. +
  286. +  return FALSE;
  287. +}
  288. +
  289.  static int
  290. -gen_values(codegen_scope *s, node *t, int val, int extra)
  291. +gen_values(codegen_scope *s, node t, int val, int extra)
  292.  {
  293.    int n = 0;
  294.    int is_splat;
  295.  
  296. -  while (t) {
  297. +  for (; t; t = t->cdr) {
  298.      is_splat = (intptr_t)t->car->car == NODE_SPLAT; /* splat mode */
  299.      if (
  300.        n+extra >= CALL_MAXARGS - 1 /* need to subtract one because vm.c expects an array if n == CALL_MAXARGS */
  301. @@ -820,8 +905,9 @@ gen_values(codegen_scope *s, node *t, int val, int extra)
  302.              genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
  303.            }
  304.          }
  305. -        t = t->cdr;
  306. -        while (t) {
  307. +        for (t = t->cdr; t; t = t->cdr) {
  308. +          if (check_symbol_only_kw_hash_p(t->car)) { continue; }
  309. +
  310.            push();
  311.            codegen(s, t->car, VAL);
  312.            pop(); pop();
  313. @@ -831,31 +917,34 @@ gen_values(codegen_scope *s, node *t, int val, int extra)
  314.            else {
  315.              genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
  316.            }
  317. -          t = t->cdr;
  318.          }
  319.        }
  320.        else {
  321. -        while (t) {
  322. +        for (; t; t = t->cdr) {
  323. +          if (check_symbol_only_kw_hash_p(t->car)) { continue; }
  324. +
  325.            codegen(s, t->car, NOVAL);
  326. -          t = t->cdr;
  327.          }
  328.        }
  329.        return -1;
  330.      }
  331. +
  332. +    if (check_symbol_only_kw_hash_p(t->car)) { continue; }
  333. +
  334.      /* normal (no splat) mode */
  335.      codegen(s, t->car, val);
  336.      n++;
  337. -    t = t->cdr;
  338.    }
  339.    return n;
  340.  }
  341.  
  342.  static void
  343. -gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
  344. +gen_call(codegen_scope *s, node tree, mrb_sym name, int sp, int val, int safe)
  345.  {
  346.    mrb_sym sym = name ? name : sym(tree->cdr->car);
  347.    int idx, skip = 0;
  348.    int n = 0, noop = 0, sendv = 0, blk = 0;
  349. +  node kwargs = NULL;
  350.  
  351.    codegen(s, tree->car, VAL); /* receiver */
  352.    if (safe) {
  353. @@ -872,11 +961,58 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
  354.    idx = new_msym(s, sym);
  355.    tree = tree->cdr->cdr->car;
  356.    if (tree) {
  357. +    node kwrest = NULL, arg_n;
  358. +
  359. +    mrb_int symlen;
  360. +    const char *symname = mrb_sym2name_len(s->mrb, sym, &symlen);
  361. +
  362. +    mrb_bool skip_kwargs = FALSE;
  363. +
  364. +    switch (symlen) {
  365. +    case 1:
  366. +      if (symname[0] == '+' || symname[0] == '-' ||
  367. +          symname[0] == '*' || symname[0] == '/' ||
  368. +          symname[0] == '<' || symname[0] == '>')
  369. +      { skip_kwargs = TRUE; }
  370. +      break;
  371. +    case 2:
  372. +      if ((symname[0] == '=' && symname[1] == '=') ||
  373. +          (symname[0] == '>' && symname[1] == '=') ||
  374. +          (symname[0] == '<' && symname[1] == '='))
  375. +      { skip_kwargs = TRUE; }
  376. +      break;
  377. +    }
  378. +
  379. +    if (!skip_kwargs) {
  380. +      for (arg_n = tree->car; arg_n; arg_n = arg_n->cdr) {
  381. +        if ((intptr_t)arg_n->car->car == NODE_KW_HASH) {
  382. +          node n;
  383. +          mrb_assert(!arg_n->cdr);
  384. +          for (n = arg_n->car->cdr; n; n = n->cdr) {
  385. +            switch ((intptr_t)n->car->car->car) {
  386. +            case NODE_KW_REST_ARGS: kwrest = n->car; break;
  387. +            case NODE_SYM: kwargs = arg_n->car->cdr; break;
  388. +            }
  389. +          }
  390. +        }
  391. +      }
  392. +    }
  393. +
  394.      n = gen_values(s, tree->car, VAL, sp?1:0);
  395.      if (n < 0) {
  396.        n = noop = sendv = 1;
  397.        push();
  398.      }
  399. +
  400. +    if (kwrest) {
  401. +      mrb_assert((intptr_t)kwrest->car->car == NODE_KW_REST_ARGS);
  402. +      codegen(s, kwrest->cdr, VAL);
  403. +      if (sendv) {
  404. +        pop();
  405. +        genop(s, MKOP_AB(OP_ARYPUSH, cursp() - 1, cursp()));
  406. +      }
  407. +      else { ++n; }
  408. +    }
  409.    }
  410.    if (sp) {
  411.      if (sendv) {
  412. @@ -932,12 +1068,34 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
  413.        genop(s, MKOP_ABC(OP_EQ, cursp(), idx, n));
  414.      }
  415.      else {
  416. -      if (sendv) n = CALL_MAXARGS;
  417. -      if (blk > 0) {                   /* no block */
  418. -        genop(s, MKOP_ABC(OP_SEND, cursp(), idx, n));
  419. +      int const argc = sendv? CALL_MAXARGS : n;
  420. +
  421. +      if (kwargs) {
  422. +        int kwargs_count = 0;
  423. +
  424. +        push_n(sendv? 2 : n + 2);
  425. +        if (blk > 0) { genop(s, MKOP_A(OP_LOADNIL, cursp() - 1)); }
  426. +
  427. +        for (; kwargs; kwargs = kwargs->cdr) {
  428. +          if ((intptr_t)kwargs->car->car->car == NODE_SYM) {
  429. +            ++kwargs_count;
  430. +            codegen(s, kwargs->car->car, VAL);
  431. +            codegen(s, kwargs->car->cdr, VAL);
  432. +          }
  433. +        }
  434. +        // kwargs terminator
  435. +        genop(s, MKOP_A(OP_LOADNIL, cursp()));
  436. +
  437. +        pop_n(2 * kwargs_count);
  438. +        pop_n(sendv? 2 : n + 2);
  439. +
  440. +        genop(s, MKOP_ABC(OP_SENDK, cursp(), idx, argc));
  441. +      }
  442. +      else if (blk > 0) {                   /* no block */
  443. +        genop(s, MKOP_ABC(OP_SEND, cursp(), idx, argc));
  444.        }
  445.        else {
  446. -        genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, n));
  447. +        genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, argc));
  448.        }
  449.      }
  450.    }
  451. @@ -950,7 +1108,7 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
  452.  }
  453.  
  454.  static void
  455. -gen_assignment(codegen_scope *s, node *tree, int sp, int val)
  456. +gen_assignment(codegen_scope *s, node tree, int sp, int val)
  457.  {
  458.    int idx;
  459.    int type = (intptr_t)tree->car;
  460. @@ -1032,10 +1190,10 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val)
  461.  }
  462.  
  463.  static void
  464. -gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val)
  465. +gen_vmassignment(codegen_scope *s, node tree, int rhs, int val)
  466.  {
  467.    int n = 0, post = 0;
  468. -  node *t, *p;
  469. +  node t, p;
  470.  
  471.    if (tree->car) {              /* pre */
  472.      t = tree->car;
  473. @@ -1091,7 +1249,7 @@ gen_send_intern(codegen_scope *s)
  474.    push();
  475.  }
  476.  static void
  477. -gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val)
  478. +gen_literal_array(codegen_scope *s, node tree, mrb_bool sym, int val)
  479.  {
  480.    if (val) {
  481.      int i = 0, j = 0;
  482. @@ -1222,7 +1380,7 @@ readint_mrb_int(codegen_scope *s, const char *p, int base, mrb_bool neg, mrb_boo
  483.  }
  484.  
  485.  static void
  486. -gen_retval(codegen_scope *s, node *tree)
  487. +gen_retval(codegen_scope *s, node tree)
  488.  {
  489.    if ((intptr_t)tree->car == NODE_SPLAT) {
  490.      genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), 0));
  491. @@ -1238,7 +1396,7 @@ gen_retval(codegen_scope *s, node *tree)
  492.  }
  493.  
  494.  static void
  495. -codegen(codegen_scope *s, node *tree, int val)
  496. +codegen(codegen_scope *s, node tree, int val)
  497.  {
  498.    int nt;
  499.  
  500. @@ -1291,14 +1449,14 @@ codegen(codegen_scope *s, node *tree, int val)
  501.        exend = 0;
  502.        pos1 = 0;
  503.        if (tree->car) {
  504. -        node *n2 = tree->car;
  505. +        node n2 = tree->car;
  506.          int exc = cursp();
  507.  
  508.          genop(s, MKOP_ABC(OP_RESCUE, exc, 0, 0));
  509.          push();
  510.          while (n2) {
  511. -          node *n3 = n2->car;
  512. -          node *n4 = n3->car;
  513. +          node n3 = n2->car;
  514. +          node n4 = n3->car;
  515.  
  516.            if (pos1) dispatch(s, pos1);
  517.            pos2 = 0;
  518. @@ -1403,7 +1561,7 @@ codegen(codegen_scope *s, node *tree, int val)
  519.    case NODE_IF:
  520.      {
  521.        int pos1, pos2;
  522. -      node *e = tree->cdr->cdr->car;
  523. +      node e = tree->cdr->cdr->car;
  524.  
  525.        if (!tree->car) {
  526.          codegen(s, e, val);
  527. @@ -1513,7 +1671,7 @@ codegen(codegen_scope *s, node *tree, int val)
  528.      {
  529.        int head = 0;
  530.        int pos1, pos2, pos3, tmp;
  531. -      node *n;
  532. +      node n;
  533.  
  534.        pos3 = 0;
  535.        if (tree->car) {
  536. @@ -1647,11 +1805,35 @@ codegen(codegen_scope *s, node *tree, int val)
  537.      break;
  538.  
  539.    case NODE_HASH:
  540. +  case NODE_KW_HASH:
  541.      {
  542.        int len = 0;
  543.        mrb_bool update = FALSE;
  544.  
  545. +      if (nt == NODE_KW_HASH) {
  546. +        node n;
  547. +        int non_sym = 0;
  548. +        for (n = tree; n; n = n->cdr) {
  549. +          switch ((intptr_t)n->car->car->car) {
  550. +          case NODE_KW_REST_ARGS:
  551. +          case NODE_SYM:
  552. +            break;
  553. +          default:
  554. +            ++non_sym;
  555. +            break;
  556. +          }
  557. +        }
  558. +        mrb_assert(non_sym > 0);
  559. +      }
  560. +
  561.        while (tree) {
  562. +        if (nt == NODE_KW_HASH &&
  563. +            ((intptr_t)tree->car->car->car == NODE_SYM ||
  564. +             (intptr_t)tree->car->car->car == NODE_KW_REST_ARGS)) {
  565. +          tree = tree->cdr;
  566. +          continue;
  567. +        }
  568. +
  569.          codegen(s, tree->car->car, val);
  570.          codegen(s, tree->car->cdr, val);
  571.          len++;
  572. @@ -1693,7 +1875,7 @@ codegen(codegen_scope *s, node *tree, int val)
  573.    case NODE_MASGN:
  574.      {
  575.        int len = 0, n = 0, post = 0;
  576. -      node *t = tree->cdr, *p;
  577. +      node t = tree->cdr, p;
  578.        int rhs = cursp();
  579.  
  580.        if ((intptr_t)t->car == NODE_ARRAY && t->cdr && nosplat(t->cdr)) {
  581. @@ -1796,7 +1978,7 @@ codegen(codegen_scope *s, node *tree, int val)
  582.          loop_pop(s, NOVAL);
  583.        }
  584.        else if ((intptr_t)tree->car->car == NODE_CALL) {
  585. -        node *n = tree->car->cdr;
  586. +        node n = tree->car->cdr;
  587.  
  588.          if (val) {
  589.            vsp = cursp();
  590. @@ -1941,7 +2123,7 @@ codegen(codegen_scope *s, node *tree, int val)
  591.  
  592.        push();        /* room for receiver */
  593.        if (tree) {
  594. -        node *args = tree->car;
  595. +        node args = tree->car;
  596.          if (args) {
  597.            n = gen_values(s, args, VAL, 0);
  598.            if (n < 0) {
  599. @@ -2334,7 +2516,7 @@ codegen(codegen_scope *s, node *tree, int val)
  600.      /* fall through */
  601.    case NODE_DSTR:
  602.      if (val) {
  603. -      node *n = tree;
  604. +      node n = tree;
  605.  
  606.        if (!n) {
  607.          genop(s, MKOP_A(OP_LOADNIL, cursp()));
  608. @@ -2352,7 +2534,7 @@ codegen(codegen_scope *s, node *tree, int val)
  609.        }
  610.      }
  611.      else {
  612. -      node *n = tree;
  613. +      node n = tree;
  614.  
  615.        while (n) {
  616.          if ((intptr_t)n->car->car != NODE_STR) {
  617. @@ -2373,29 +2555,27 @@ codegen(codegen_scope *s, node *tree, int val)
  618.  
  619.    case NODE_DXSTR:
  620.      {
  621. -      node *n;
  622. +      node n;
  623.        int ai = mrb_gc_arena_save(s->mrb);
  624. -      int sym = new_sym(s, mrb_intern_lit(s->mrb, "Kernel"));
  625.  
  626.        genop(s, MKOP_A(OP_LOADSELF, cursp()));
  627.        push();
  628.        codegen(s, tree->car, VAL);
  629. -      n = tree->cdr;
  630. -      while (n) {
  631. +      for (n = tree->cdr; n; n = n->cdr) {
  632.          if ((intptr_t)n->car->car == NODE_XSTR) {
  633. -          n->car->car = (struct mrb_ast_node*)(intptr_t)NODE_STR;
  634. -          mrb_assert(!n->cdr); /* must be the end */
  635. +          int str_lit = new_lit(s, mrb_str_new(s->mrb, (char const*)n->car->cdr->car,
  636. +                                               (intptr_t)n->car->cdr->cdr));
  637. +          genop(s, MKOP_ABx(OP_STRING, cursp(), str_lit));
  638. +          push();
  639. +
  640. +          mrb_assert(!n->cdr); // NODE_XSTR is the terminator
  641.          }
  642. -        codegen(s, n->car, VAL);
  643. -        pop(); pop();
  644. -        genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
  645. -        push();
  646. -        n = n->cdr;
  647. +        else { codegen(s, n->car, VAL); }
  648. +        pop();
  649. +        genop_peep(s, MKOP_AB(OP_STRCAT, cursp() - 1, cursp()), VAL);
  650.        }
  651. -      push();                   /* for block */
  652. -      pop_n(3);
  653. -      sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
  654. -      genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
  655. +      pop_n(2);
  656. +      genop(s, MKOP_ABC(OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "`")), 1));
  657.        if (val) push();
  658.        mrb_gc_arena_restore(s->mrb, ai);
  659.      }
  660. @@ -2406,16 +2586,12 @@ codegen(codegen_scope *s, node *tree, int val)
  661.        char *p = (char*)tree->car;
  662.        size_t len = (intptr_t)tree->cdr;
  663.        int ai = mrb_gc_arena_save(s->mrb);
  664. -      int off = new_lit(s, mrb_str_new(s->mrb, p, len));
  665. -      int sym;
  666.  
  667.        genop(s, MKOP_A(OP_LOADSELF, cursp()));
  668.        push();
  669. -      genop(s, MKOP_ABx(OP_STRING, cursp(), off));
  670. -      push(); push();
  671. -      pop_n(3);
  672. -      sym = new_sym(s, mrb_intern_lit(s->mrb, "`"));
  673. -      genop(s, MKOP_ABC(OP_SEND, cursp(), sym, 1));
  674. +      genop(s, MKOP_ABx(OP_STRING, cursp(), new_lit(s, mrb_str_new(s->mrb, p, len))));
  675. +      pop();
  676. +      genop(s, MKOP_ABC(OP_SEND, cursp(), new_sym(s, mrb_intern_lit(s->mrb, "`")), 1));
  677.        if (val) push();
  678.        mrb_gc_arena_restore(s->mrb, ai);
  679.      }
  680. @@ -2464,7 +2640,7 @@ codegen(codegen_scope *s, node *tree, int val)
  681.  
  682.    case NODE_DREGX:
  683.      if (val) {
  684. -      node *n = tree->car;
  685. +      node n = tree->car;
  686.        int ai = mrb_gc_arena_save(s->mrb);
  687.        int sym = new_sym(s, mrb_intern_lit(s->mrb, REGEXP_CLASS));
  688.        int argc = 1;
  689. @@ -2515,7 +2691,7 @@ codegen(codegen_scope *s, node *tree, int val)
  690.        push();
  691.      }
  692.      else {
  693. -      node *n = tree->car;
  694. +      node n = tree->car;
  695.  
  696.        while (n) {
  697.          if ((intptr_t)n->car->car != NODE_STR) {
  698. @@ -2595,7 +2771,7 @@ codegen(codegen_scope *s, node *tree, int val)
  699.      {
  700.        int undef = new_msym(s, mrb_intern_lit(s->mrb, "undef_method"));
  701.        int num = 0;
  702. -      node *t = tree;
  703. +      node t = tree;
  704.  
  705.        genop(s, MKOP_A(OP_TCLASS, cursp()));
  706.        push();
  707. @@ -2636,11 +2812,11 @@ codegen(codegen_scope *s, node *tree, int val)
  708.      {
  709.        int idx;
  710.  
  711. -      if (tree->car->car == (node*)0) {
  712. +      if (tree->car->car == (node)0) {
  713.          genop(s, MKOP_A(OP_LOADNIL, cursp()));
  714.          push();
  715.        }
  716. -      else if (tree->car->car == (node*)1) {
  717. +      else if (tree->car->car == (node)1) {
  718.          genop(s, MKOP_A(OP_OCLASS, cursp()));
  719.          push();
  720.        }
  721. @@ -2669,11 +2845,11 @@ codegen(codegen_scope *s, node *tree, int val)
  722.      {
  723.        int idx;
  724.  
  725. -      if (tree->car->car == (node*)0) {
  726. +      if (tree->car->car == (node)0) {
  727.          genop(s, MKOP_A(OP_LOADNIL, cursp()));
  728.          push();
  729.        }
  730. -      else if (tree->car->car == (node*)1) {
  731. +      else if (tree->car->car == (node)1) {
  732.          genop(s, MKOP_A(OP_OCLASS, cursp()));
  733.          push();
  734.        }
  735. @@ -2726,7 +2902,7 @@ codegen(codegen_scope *s, node *tree, int val)
  736.  
  737.    case NODE_SDEF:
  738.      {
  739. -      node *recv = tree->car;
  740. +      node recv = tree->car;
  741.        int sym = new_msym(s, sym(tree->cdr->car));
  742.        int idx = lambda_body(s, tree->cdr->cdr, 0);
  743.  
  744. @@ -2769,7 +2945,7 @@ scope_add_irep(codegen_scope *s, mrb_irep *irep)
  745.  }
  746.  
  747.  static codegen_scope*
  748. -scope_new(mrb_state *mrb, codegen_scope *prev, node *lv)
  749. +scope_new(mrb_state *mrb, codegen_scope *prev, node lv)
  750.  {
  751.    static const codegen_scope codegen_scope_zero = { 0 };
  752.    mrb_pool *pool = mrb_pool_open(mrb);
  753. @@ -2806,7 +2982,7 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *lv)
  754.    p->sp += node_len(lv)+1;        /* add self */
  755.    p->nlocals = p->sp;
  756.    if (lv) {
  757. -    node *n = lv;
  758. +    node n = lv;
  759.      size_t i = 0;
  760.  
  761.      p->irep->lv = (struct mrb_locals*)mrb_malloc(mrb, sizeof(struct mrb_locals) * (p->nlocals - 1));
  762. @@ -2902,7 +3078,7 @@ loop_push(codegen_scope *s, enum looptype t)
  763.  }
  764.  
  765.  static void
  766. -loop_break(codegen_scope *s, node *tree)
  767. +loop_break(codegen_scope *s, node tree)
  768.  {
  769.    if (!s->loop) {
  770.      codegen(s, tree, NOVAL);
  771. modified   mrbgems/mruby-compiler/core/node.h
  772. @@ -46,6 +46,7 @@ enum node_type {
  773.    NODE_ARRAY,
  774.    NODE_ZARRAY,
  775.    NODE_HASH,
  776. +  NODE_KW_HASH,
  777.    NODE_RETURN,
  778.    NODE_YIELD,
  779.    NODE_LVAR,
  780. @@ -73,6 +74,9 @@ enum node_type {
  781.    NODE_DREGX_ONCE,
  782.    NODE_LIST,
  783.    NODE_ARG,
  784. +  NODE_ARGS_TAIL,
  785. +  NODE_KW_ARG,
  786. +  NODE_KW_REST_ARGS,
  787.    NODE_ARGSCAT,
  788.    NODE_ARGSPUSH,
  789.    NODE_SPLAT,
  790. modified   mrbgems/mruby-compiler/core/parse.y
  791. @@ -560,6 +560,13 @@ new_hash(parser_state *p, node *a)
  792.    return cons((node*)NODE_HASH, a);
  793.  }
  794.  
  795. +/* (:kw_hash (k . v) (k . v)...) */
  796. +static node*
  797. +new_kw_hash(parser_state *p, node *a)
  798. +{
  799. +  return cons((node*)NODE_KW_HASH, a);
  800. +}
  801. +
  802.  /* (:sym . a) */
  803.  static node*
  804.  new_sym(parser_state *p, mrb_sym sym)
  805. @@ -660,23 +667,54 @@ new_arg(parser_state *p, mrb_sym sym)
  806.    return cons((node*)NODE_ARG, nsym(sym));
  807.  }
  808.  
  809. -/* (m o r m2 b) */
  810. +/* (m o r m2 tail) */
  811.  /* m: (a b c) */
  812.  /* o: ((a . e1) (b . e2)) */
  813.  /* r: a */
  814.  /* m2: (a b c) */
  815.  /* b: a */
  816.  static node*
  817. -new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym blk)
  818. +new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, node *tail)
  819.  {
  820.    node *n;
  821.  
  822. -  n = cons(m2, nsym(blk));
  823. +  n = cons(m2, tail);
  824.    n = cons(nsym(rest), n);
  825.    n = cons(opt, n);
  826.    return cons(m, n);
  827.  }
  828.  
  829. +/* (:args_tail keywords rest_keywords_sym block_sym) */
  830. +static node*
  831. +new_args_tail(parser_state *p, node *kws, node *kwrest, mrb_sym blk)
  832. +{
  833. +  node *k = kws;
  834. +
  835. +  /* allocate register for keywords hash */
  836. +  if (kws || kwrest) {
  837. +    local_add_f(p, (kwrest && kwrest->cdr)? sym(kwrest->cdr) : mrb_intern_lit(p->mrb, "**"));
  838. +  }
  839. +
  840. +  /* allocate register for block */
  841. +  local_add_f(p, blk? blk : mrb_intern_lit(p->mrb, "&"));
  842. +
  843. +  /* allocate register for keywords arguments */
  844. +  while (k) {
  845. +    local_add_f(p, sym(k->car->cdr->car));
  846. +    k = k->cdr;
  847. +  }
  848. +
  849. +  return list4((node*)NODE_ARGS_TAIL, kws, kwrest, nsym(blk));
  850. +}
  851. +
  852. +/* (:kw_arg kw_sym def_arg) */
  853. +static node*
  854. +new_kw_arg(parser_state *p, mrb_sym kw, node *def_arg)
  855. +{
  856. +  mrb_assert(kw);
  857. +  return list3((node*)NODE_KW_ARG, nsym(kw), def_arg);
  858. +}
  859. +
  860.  /* (:block_arg . a) */
  861.  static node*
  862.  new_block_arg(parser_state *p, node *a)
  863. @@ -1117,6 +1155,10 @@ heredoc_end(parser_state *p)
  864.  %type <nd> heredoc words symbols
  865.  %type <num> call_op call_op2     /* 0:'&.', 1:'.', 2:'::' */
  866.  
  867. +%type <nd> args_tail opt_args_tail f_kwarg f_kw arg_value f_kwrest
  868. +%type <nd> f_block_kwarg f_block_kw block_args_tail opt_block_args_tail
  869. +%type <id> f_label
  870. +
  871.  %token tUPLUS             /* unary+ */
  872.  %token tUMINUS            /* unary- */
  873.  %token tPOW               /* ** */
  874. @@ -1142,6 +1184,7 @@ heredoc_end(parser_state *p)
  875.  %token tLBRACE            /* { */
  876.  %token tLBRACE_ARG        /* { */
  877.  %token tSTAR              /* * */
  878. +%token tDSTAR             /* ** */
  879.  %token tAMPER             /* & */
  880.  %token tLAMBDA            /* -> */
  881.  %token tANDDOT            /* &. */
  882. @@ -1716,6 +1759,7 @@ op              : '|'           { $$ = intern_c('|');   }
  883.                  | '/'           { $$ = intern_c('/');   }
  884.                  | '%'           { $$ = intern_c('%');   }
  885.                  | tPOW          { $$ = intern("**",2);  }
  886. +                | tDSTAR        { $$ = intern("**",2);  }
  887.                  | '!'           { $$ = intern_c('!');   }
  888.                  | '~'           { $$ = intern_c('~');   }
  889.                  | tUPLUS        { $$ = intern("+@",2);  }
  890. @@ -1920,11 +1964,11 @@ aref_args       : none
  891.                      }
  892.                  | args comma assocs trailer
  893.                      {
  894. -                      $$ = push($1, new_hash(p, $3));
  895. +                      $$ = push($1, new_kw_hash(p, $3));
  896.                      }
  897.                  | assocs trailer
  898.                      {
  899. -                      $$ = cons(new_hash(p, $1), 0);
  900. +                      $$ = cons(new_kw_hash(p, $1), 0);
  901.                        NODE_LINENO($$, $1);
  902.                      }
  903.                  ;
  904. @@ -1960,12 +2004,12 @@ opt_call_args   : none
  905.                      }
  906.                  | args comma assocs ','
  907.                      {
  908. -                      $$ = cons(push($1, new_hash(p, $3)), 0);
  909. +                      $$ = cons(push($1, new_kw_hash(p, $3)), 0);
  910.                        NODE_LINENO($$, $1);
  911.                      }
  912.                  | assocs ','
  913.                      {
  914. -                      $$ = cons(list1(new_hash(p, $1)), 0);
  915. +                      $$ = cons(list1(new_kw_hash(p, $1)), 0);
  916.                        NODE_LINENO($$, $1);
  917.                      }
  918.                  ;
  919. @@ -1982,12 +2026,12 @@ call_args       : command
  920.                      }
  921.                  | assocs opt_block_arg
  922.                      {
  923. -                      $$ = cons(list1(new_hash(p, $1)), $2);
  924. +                      $$ = cons(list1(new_kw_hash(p, $1)), $2);
  925.                        NODE_LINENO($$, $1);
  926.                      }
  927.                  | args comma assocs opt_block_arg
  928.                      {
  929. -                      $$ = cons(push($1, new_hash(p, $3)), $4);
  930. +                      $$ = cons(push($1, new_kw_hash(p, $3)), $4);
  931.                        NODE_LINENO($$, $1);
  932.                      }
  933.                  | block_arg
  934. @@ -2426,23 +2470,51 @@ f_margs         : f_marg_list
  935.                      }
  936.                  ;
  937.  
  938. -block_param     : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg
  939. +block_args_tail : f_block_kwarg ',' f_kwrest opt_f_block_arg
  940. +                    {
  941. +                      $$ = new_args_tail(p, $1, $3, $4);
  942. +                    }
  943. +                | f_block_kwarg opt_f_block_arg
  944. +                    {
  945. +                      $$ = new_args_tail(p, $1, 0, $2);
  946. +                    }
  947. +                | f_kwrest opt_f_block_arg
  948. +                    {
  949. +                      $$ = new_args_tail(p, 0, $1, $2);
  950. +                    }
  951. +                | f_block_arg
  952. +                    {
  953. +                      $$ = new_args_tail(p, 0, 0, $1);
  954. +                    }
  955. +                ;
  956. +
  957. +opt_block_args_tail : ',' block_args_tail
  958. +                    {
  959. +                      $$ = $2;
  960. +                    }
  961. +                | /* none */
  962. +                    {
  963. +                      $$ = new_args_tail(p, 0, 0, 0);
  964. +                    }
  965. +                ;
  966. +
  967. +block_param     : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail
  968.                      {
  969.                        $$ = new_args(p, $1, $3, $5, 0, $6);
  970.                      }
  971. -                | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
  972. +                | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail
  973.                      {
  974.                        $$ = new_args(p, $1, $3, $5, $7, $8);
  975.                      }
  976. -                | f_arg ',' f_block_optarg opt_f_block_arg
  977. +                | f_arg ',' f_block_optarg opt_block_args_tail
  978.                      {
  979.                        $$ = new_args(p, $1, $3, 0, 0, $4);
  980.                      }
  981. -                | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg
  982. +                | f_arg ',' f_block_optarg ',' f_arg opt_block_args_tail
  983.                      {
  984.                        $$ = new_args(p, $1, $3, 0, $5, $6);
  985.                      }
  986. -                | f_arg ',' f_rest_arg opt_f_block_arg
  987. +                | f_arg ',' f_rest_arg opt_block_args_tail
  988.                      {
  989.                        $$ = new_args(p, $1, 0, $3, 0, $4);
  990.                      }
  991. @@ -2450,39 +2522,39 @@ block_param     : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg
  992.                      {
  993.                        $$ = new_args(p, $1, 0, 0, 0, 0);
  994.                      }
  995. -                | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
  996. +                | f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail
  997.                      {
  998.                        $$ = new_args(p, $1, 0, $3, $5, $6);
  999.                      }
  1000. -                | f_arg opt_f_block_arg
  1001. +                | f_arg opt_block_args_tail
  1002.                      {
  1003.                        $$ = new_args(p, $1, 0, 0, 0, $2);
  1004.                      }
  1005. -                | f_block_optarg ',' f_rest_arg opt_f_block_arg
  1006. +                | f_block_optarg ',' f_rest_arg opt_block_args_tail
  1007.                      {
  1008.                        $$ = new_args(p, 0, $1, $3, 0, $4);
  1009.                      }
  1010. -                | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
  1011. +                | f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail
  1012.                      {
  1013.                        $$ = new_args(p, 0, $1, $3, $5, $6);
  1014.                      }
  1015. -                | f_block_optarg opt_f_block_arg
  1016. +                | f_block_optarg opt_block_args_tail
  1017.                      {
  1018.                        $$ = new_args(p, 0, $1, 0, 0, $2);
  1019.                      }
  1020. -                | f_block_optarg ',' f_arg opt_f_block_arg
  1021. +                | f_block_optarg ',' f_arg opt_block_args_tail
  1022.                      {
  1023.                        $$ = new_args(p, 0, $1, 0, $3, $4);
  1024.                      }
  1025. -                | f_rest_arg opt_f_block_arg
  1026. +                | f_rest_arg opt_block_args_tail
  1027.                      {
  1028.                        $$ = new_args(p, 0, 0, $1, 0, $2);
  1029.                      }
  1030. -                | f_rest_arg ',' f_arg opt_f_block_arg
  1031. +                | f_rest_arg ',' f_arg opt_block_args_tail
  1032.                      {
  1033.                        $$ = new_args(p, 0, 0, $1, $3, $4);
  1034.                      }
  1035. -                | f_block_arg
  1036. +                | block_args_tail
  1037.                      {
  1038.                        $$ = new_args(p, 0, 0, 0, 0, $1);
  1039.                      }
  1040. @@ -2987,65 +3059,153 @@ f_arglist       : '(' f_args rparen
  1041.                      }
  1042.                  ;
  1043.  
  1044. -f_args          : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg
  1045. +f_label         : tLABEL
  1046. +                ;
  1047. +
  1048. +arg_value       : arg
  1049. +                ;
  1050. +
  1051. +f_kw            : f_label arg_value
  1052. +                    {
  1053. +                      $$ = new_kw_arg(p, $1, $2);
  1054. +                    }
  1055. +                | f_label
  1056. +                    {
  1057. +                      $$ = new_kw_arg(p, $1, 0);
  1058. +                    }
  1059. +                ;
  1060. +
  1061. +f_block_kw      : f_label primary_value
  1062. +                    {
  1063. +                      $$ = new_kw_arg(p, $1, $2);
  1064. +                    }
  1065. +                | f_label
  1066. +                    {
  1067. +                      $$ = new_kw_arg(p, $1, 0);
  1068. +                    }
  1069. +                ;
  1070. +
  1071. +f_block_kwarg   : f_block_kw
  1072. +                    {
  1073. +                      $$ = list1($1);
  1074. +                    }
  1075. +                | f_block_kwarg ',' f_block_kw
  1076. +                    {
  1077. +                      $$ = push($1, $3);
  1078. +                    }
  1079. +                ;
  1080. +
  1081. +f_kwarg         : f_kw
  1082. +                    {
  1083. +                      $$ = list1($1);
  1084. +                    }
  1085. +                | f_kwarg ',' f_kw
  1086. +                    {
  1087. +                      $$ = push($1, $3);
  1088. +                    }
  1089. +                ;
  1090. +
  1091. +kwrest_mark     : tPOW
  1092. +                | tDSTAR
  1093. +                ;
  1094. +
  1095. +f_kwrest        : kwrest_mark tIDENTIFIER
  1096. +                    {
  1097. +                      $$ = cons((node*)NODE_KW_REST_ARGS, nsym($2));
  1098. +                    }
  1099. +                | kwrest_mark
  1100. +                    {
  1101. +                      $$ = cons((node*)NODE_KW_REST_ARGS, 0);
  1102. +                    }
  1103. +                ;
  1104. +
  1105. +args_tail       : f_kwarg ',' f_kwrest opt_f_block_arg
  1106. +                    {
  1107. +                      $$ = new_args_tail(p, $1, $3, $4);
  1108. +                    }
  1109. +                | f_kwarg opt_f_block_arg
  1110. +                    {
  1111. +                      $$ = new_args_tail(p, $1, 0, $2);
  1112. +                    }
  1113. +                | f_kwrest opt_f_block_arg
  1114. +                    {
  1115. +                      $$ = new_args_tail(p, 0, $1, $2);
  1116. +                    }
  1117. +                | f_block_arg
  1118. +                    {
  1119. +                      $$ = new_args_tail(p, 0, 0, $1);
  1120. +                    }
  1121. +                ;
  1122. +
  1123. +opt_args_tail   : ',' args_tail
  1124. +                    {
  1125. +                      $$ = $2;
  1126. +                    }
  1127. +                | /* none */
  1128. +                    {
  1129. +                      $$ = new_args_tail(p, 0, 0, 0);
  1130. +                    }
  1131. +                ;
  1132. +
  1133. +f_args          : f_arg ',' f_optarg ',' f_rest_arg opt_args_tail
  1134.                      {
  1135.                        $$ = new_args(p, $1, $3, $5, 0, $6);
  1136.                      }
  1137. -                | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
  1138. +                | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_args_tail
  1139.                      {
  1140.                        $$ = new_args(p, $1, $3, $5, $7, $8);
  1141.                      }
  1142. -                | f_arg ',' f_optarg opt_f_block_arg
  1143. +                | f_arg ',' f_optarg opt_args_tail
  1144.                      {
  1145.                        $$ = new_args(p, $1, $3, 0, 0, $4);
  1146.                      }
  1147. -                | f_arg ',' f_optarg ',' f_arg opt_f_block_arg
  1148. +                | f_arg ',' f_optarg ',' f_arg opt_args_tail
  1149.                      {
  1150.                        $$ = new_args(p, $1, $3, 0, $5, $6);
  1151.                      }
  1152. -                | f_arg ',' f_rest_arg opt_f_block_arg
  1153. +                | f_arg ',' f_rest_arg opt_args_tail
  1154.                      {
  1155.                        $$ = new_args(p, $1, 0, $3, 0, $4);
  1156.                      }
  1157. -                | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg
  1158. +                | f_arg ',' f_rest_arg ',' f_arg opt_args_tail
  1159.                      {
  1160.                        $$ = new_args(p, $1, 0, $3, $5, $6);
  1161.                      }
  1162. -                | f_arg opt_f_block_arg
  1163. +                | f_arg opt_args_tail
  1164.                      {
  1165.                        $$ = new_args(p, $1, 0, 0, 0, $2);
  1166.                      }
  1167. -                | f_optarg ',' f_rest_arg opt_f_block_arg
  1168. +                | f_optarg ',' f_rest_arg opt_args_tail
  1169.                      {
  1170.                        $$ = new_args(p, 0, $1, $3, 0, $4);
  1171.                      }
  1172. -                | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg
  1173. +                | f_optarg ',' f_rest_arg ',' f_arg opt_args_tail
  1174.                      {
  1175.                        $$ = new_args(p, 0, $1, $3, $5, $6);
  1176.                      }
  1177. -                | f_optarg opt_f_block_arg
  1178. +                | f_optarg opt_args_tail
  1179.                      {
  1180.                        $$ = new_args(p, 0, $1, 0, 0, $2);
  1181.                      }
  1182. -                | f_optarg ',' f_arg opt_f_block_arg
  1183. +                | f_optarg ',' f_arg opt_args_tail
  1184.                      {
  1185.                        $$ = new_args(p, 0, $1, 0, $3, $4);
  1186.                      }
  1187. -                | f_rest_arg opt_f_block_arg
  1188. +                | f_rest_arg opt_args_tail
  1189.                      {
  1190.                        $$ = new_args(p, 0, 0, $1, 0, $2);
  1191.                      }
  1192. -                | f_rest_arg ',' f_arg opt_f_block_arg
  1193. +                | f_rest_arg ',' f_arg opt_args_tail
  1194.                      {
  1195.                        $$ = new_args(p, 0, 0, $1, $3, $4);
  1196.                      }
  1197. -                | f_block_arg
  1198. +                | args_tail
  1199.                      {
  1200.                        $$ = new_args(p, 0, 0, 0, 0, $1);
  1201.                      }
  1202.                  | /* none */
  1203.                      {
  1204. -                      local_add_f(p, 0);
  1205. +                      local_add_f(p, mrb_intern_lit(p->mrb, "&"));
  1206.                        $$ = new_args(p, 0, 0, 0, 0, 0);
  1207.                      }
  1208.                  ;
  1209. @@ -3153,7 +3313,7 @@ f_rest_arg      : restarg_mark tIDENTIFIER
  1210.                      }
  1211.                  | restarg_mark
  1212.                      {
  1213. -                      local_add_f(p, 0);
  1214. +                      local_add_f(p, mrb_intern_lit(p->mrb, "*"));
  1215.                        $$ = -1;
  1216.                      }
  1217.                  ;
  1218. @@ -3164,7 +3324,6 @@ blkarg_mark     : '&'
  1219.  
  1220.  f_block_arg     : blkarg_mark tIDENTIFIER
  1221.                      {
  1222. -                      local_add_f(p, $2);
  1223.                        $$ = $2;
  1224.                      }
  1225.                  ;
  1226. @@ -3175,7 +3334,6 @@ opt_f_block_arg : ',' f_block_arg
  1227.                      }
  1228.                  | none
  1229.                      {
  1230. -                      local_add_f(p, 0);
  1231.                        $$ = 0;
  1232.                      }
  1233.                  ;
  1234. @@ -3228,15 +3386,16 @@ assocs          : assoc
  1235.                      }
  1236.                  ;
  1237.  
  1238. -assoc           : arg tASSOC arg
  1239. +assoc           : arg_value tASSOC arg_value
  1240.                      {
  1241. +                      /* if ((intptr_t)$1->car == NODE_STR) */
  1242.                        $$ = cons($1, $3);
  1243.                      }
  1244. -                | tLABEL arg
  1245. +                | tLABEL arg_value
  1246.                      {
  1247.                        $$ = cons(new_sym(p, $1), $2);
  1248.                      }
  1249. -                | tLABEL_END arg
  1250. +                | tLABEL_END arg_value
  1251.                      {
  1252.                        $$ = cons(new_sym(p, new_strsym(p, $1)), $2);
  1253.                      }
  1254. @@ -3248,6 +3407,10 @@ assoc           : arg tASSOC arg
  1255.                      {
  1256.                        $$ = cons(new_dsym(p, push($2, $3)), $4);
  1257.                      }
  1258. +                | tDSTAR arg_value
  1259. +                    {
  1260. +                      $$ = cons(cons((node*)NODE_KW_REST_ARGS, 0), $2);
  1261. +                    }
  1262.                  ;
  1263.  
  1264.  operation       : tIDENTIFIER
  1265. @@ -4325,7 +4488,16 @@ parser_yylex(parser_state *p)
  1266.          return tOP_ASGN;
  1267.        }
  1268.        pushback(p, c);
  1269. -      c = tPOW;
  1270. +      if (IS_SPCARG(c)) {
  1271. +        yywarning(p, "`**' interpreted as argument prefix");
  1272. +        c = tDSTAR;
  1273. +      }
  1274. +      else if (IS_BEG()) {
  1275. +        c = tDSTAR;
  1276. +      }
  1277. +      else {
  1278. +        c = tPOW; /* "**", "argument prefix" */
  1279. +      }
  1280.      }
  1281.      else {
  1282.        if (c == '=') {
  1283. @@ -5841,6 +6013,48 @@ dump_recur(mrb_state *mrb, node *tree, int offset)
  1284.    }
  1285.  }
  1286.  
  1287. +static void
  1288. +dump_args(mrb_state *mrb, node *n, int offset)
  1289. +{
  1290. +  if (n->car) {
  1291. +    dump_prefix(n, offset+1);
  1292. +    printf("mandatory args:\n");
  1293. +    dump_recur(mrb, n->car, offset+2);
  1294. +  }
  1295. +  n = n->cdr;
  1296. +  if (n->car) {
  1297. +    dump_prefix(n, offset+1);
  1298. +    printf("optional args:\n");
  1299. +    {
  1300. +      node *n2 = n->car;
  1301. +
  1302. +      while (n2) {
  1303. +        dump_prefix(n2, offset+2);
  1304. +        printf("%s=\n", mrb_sym2name(mrb, sym(n2->car->car)));
  1305. +        mrb_parser_dump(mrb, n2->car->cdr, offset+3);
  1306. +        n2 = n2->cdr;
  1307. +      }
  1308. +    }
  1309. +  }
  1310. +  n = n->cdr;
  1311. +  if (n->car) {
  1312. +    dump_prefix(n, offset+1);
  1313. +    printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
  1314. +  }
  1315. +  n = n->cdr;
  1316. +  if (n->car) {
  1317. +    dump_prefix(n, offset+1);
  1318. +    printf("post mandatory args:\n");
  1319. +    dump_recur(mrb, n->car, offset+2);
  1320. +  }
  1321. +
  1322. +  n = n->cdr;
  1323. +  if (n) {
  1324. +    mrb_assert((intptr_t)n->car == NODE_ARGS_TAIL);
  1325. +    mrb_parser_dump(mrb, n, offset);
  1326. +  }
  1327. +}
  1328. +
  1329.  #endif
  1330.  
  1331.  void
  1332. @@ -5912,7 +6126,8 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
  1333.      break;
  1334.  
  1335.    case NODE_LAMBDA:
  1336. -    printf("NODE_BLOCK:\n");
  1337. +    printf("NODE_LAMBDA:\n");
  1338. +    dump_prefix(tree, offset);
  1339.      goto block;
  1340.  
  1341.    case NODE_BLOCK:
  1342. @@ -5920,43 +6135,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
  1343.      printf("NODE_BLOCK:\n");
  1344.      tree = tree->cdr;
  1345.      if (tree->car) {
  1346. -      node *n = tree->car;
  1347. -
  1348. -      if (n->car) {
  1349. -        dump_prefix(n, offset+1);
  1350. -        printf("mandatory args:\n");
  1351. -        dump_recur(mrb, n->car, offset+2);
  1352. -      }
  1353. -      n = n->cdr;
  1354. -      if (n->car) {
  1355. -        dump_prefix(n, offset+1);
  1356. -        printf("optional args:\n");
  1357. -        {
  1358. -          node *n2 = n->car;
  1359. -
  1360. -          while (n2) {
  1361. -            dump_prefix(n2, offset+2);
  1362. -            printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
  1363. -            mrb_parser_dump(mrb, n2->car->cdr, 0);
  1364. -            n2 = n2->cdr;
  1365. -          }
  1366. -        }
  1367. -      }
  1368. -      n = n->cdr;
  1369. -      if (n->car) {
  1370. -        dump_prefix(n, offset+1);
  1371. -        printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
  1372. -      }
  1373. -      n = n->cdr;
  1374. -      if (n->car) {
  1375. -        dump_prefix(n, offset+1);
  1376. -        printf("post mandatory args:\n");
  1377. -        dump_recur(mrb, n->car, offset+2);
  1378. -      }
  1379. -      if (n->cdr) {
  1380. -        dump_prefix(n, offset+1);
  1381. -        printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr)));
  1382. -      }
  1383. +      dump_args(mrb, tree->car, offset+1);
  1384.      }
  1385.      dump_prefix(tree, offset+1);
  1386.      printf("body:\n");
  1387. @@ -6491,43 +6670,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
  1388.      }
  1389.      tree = tree->cdr;
  1390.      if (tree->car) {
  1391. -      node *n = tree->car;
  1392. -
  1393. -      if (n->car) {
  1394. -        dump_prefix(n, offset+1);
  1395. -        printf("mandatory args:\n");
  1396. -        dump_recur(mrb, n->car, offset+2);
  1397. -      }
  1398. -      n = n->cdr;
  1399. -      if (n->car) {
  1400. -        dump_prefix(n, offset+1);
  1401. -        printf("optional args:\n");
  1402. -        {
  1403. -          node *n2 = n->car;
  1404. -
  1405. -          while (n2) {
  1406. -            dump_prefix(n2, offset+2);
  1407. -            printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
  1408. -            mrb_parser_dump(mrb, n2->car->cdr, 0);
  1409. -            n2 = n2->cdr;
  1410. -          }
  1411. -        }
  1412. -      }
  1413. -      n = n->cdr;
  1414. -      if (n->car) {
  1415. -        dump_prefix(n, offset+1);
  1416. -        printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
  1417. -      }
  1418. -      n = n->cdr;
  1419. -      if (n->car) {
  1420. -        dump_prefix(n, offset+1);
  1421. -        printf("post mandatory args:\n");
  1422. -        dump_recur(mrb, n->car, offset+2);
  1423. -      }
  1424. -      if (n->cdr) {
  1425. -        dump_prefix(n, offset+1);
  1426. -        printf("blk=&%s\n", mrb_sym2name(mrb, sym(n->cdr)));
  1427. -      }
  1428. +      dump_args(mrb, tree->car, offset);
  1429.      }
  1430.      mrb_parser_dump(mrb, tree->cdr->car, offset+1);
  1431.      break;
  1432. @@ -6540,44 +6683,7 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
  1433.      printf(":%s\n", mrb_sym2name(mrb, sym(tree->car)));
  1434.      tree = tree->cdr->cdr;
  1435.      if (tree->car) {
  1436. -      node *n = tree->car;
  1437. -
  1438. -      if (n->car) {
  1439. -        dump_prefix(n, offset+1);
  1440. -        printf("mandatory args:\n");
  1441. -        dump_recur(mrb, n->car, offset+2);
  1442. -      }
  1443. -      n = n->cdr;
  1444. -      if (n->car) {
  1445. -        dump_prefix(n, offset+1);
  1446. -        printf("optional args:\n");
  1447. -        {
  1448. -          node *n2 = n->car;
  1449. -
  1450. -          while (n2) {
  1451. -            dump_prefix(n2, offset+2);
  1452. -            printf("%s=", mrb_sym2name(mrb, sym(n2->car->car)));
  1453. -            mrb_parser_dump(mrb, n2->car->cdr, 0);
  1454. -            n2 = n2->cdr;
  1455. -          }
  1456. -        }
  1457. -      }
  1458. -      n = n->cdr;
  1459. -      if (n->car) {
  1460. -        dump_prefix(n, offset+1);
  1461. -        printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car)));
  1462. -      }
  1463. -      n = n->cdr;
  1464. -      if (n->car) {
  1465. -        dump_prefix(n, offset+1);
  1466. -        printf("post mandatory args:\n");
  1467. -        dump_recur(mrb, n->car, offset+2);
  1468. -      }
  1469. -      n = n->cdr;
  1470. -      if (n) {
  1471. -        dump_prefix(n, offset+1);
  1472. -        printf("blk=&%s\n", mrb_sym2name(mrb, sym(n)));
  1473. -      }
  1474. +      dump_args(mrb, tree->car, offset+1);
  1475.      }
  1476.      tree = tree->cdr;
  1477.      mrb_parser_dump(mrb, tree->car, offset+1);
  1478. @@ -6593,6 +6699,37 @@ mrb_parser_dump(mrb_state *mrb, node *tree, int offset)
  1479.      dump_recur(mrb, ((parser_heredoc_info*)tree)->doc, offset+1);
  1480.      break;
  1481.  
  1482. +  case NODE_ARGS_TAIL:
  1483. +    printf("NODE_ARGS_TAIL:\n");
  1484. +    {
  1485. +      node *kws = tree->car;
  1486. +
  1487. +      while (kws) {
  1488. +        mrb_parser_dump(mrb, kws->car, offset+1);
  1489. +        kws = kws->cdr;
  1490. +      }
  1491. +    }
  1492. +    tree = tree->cdr;
  1493. +    if (tree->car) {
  1494. +      mrb_assert((intptr_t)tree->car->car == NODE_KW_REST_ARGS);
  1495. +      mrb_parser_dump(mrb, tree->car, offset+1);
  1496. +    }
  1497. +    tree = tree->cdr;
  1498. +    if (tree->car) {
  1499. +      dump_prefix(tree, offset+1);
  1500. +      printf("block='%s'\n", mrb_sym2name(mrb, sym(tree->car)));
  1501. +    }
  1502. +    break;
  1503. +
  1504. +  case NODE_KW_ARG:
  1505. +    printf("NODE_KW_ARG %s\n", mrb_sym2name(mrb, sym(tree->car)));
  1506. +    mrb_parser_dump(mrb, tree->cdr->car, offset + 1);
  1507. +    break;
  1508. +
  1509. +  case NODE_KW_REST_ARGS:
  1510. +    printf("NODE_KW_REST_ARGS %s\n", mrb_sym2name(mrb, sym(tree)));
  1511. +    break;
  1512. +
  1513.    default:
  1514.      printf("node type: %d (0x%x)\n", nodetype, (unsigned)nodetype);
  1515.      break;
  1516. modified   mrbgems/mruby-proc-ext/src/proc.c
  1517. @@ -104,7 +104,9 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
  1518.      {0, "opt"},
  1519.      {0, "rest"},
  1520.      {0, "req"},
  1521. +    {0, "kdict"},
  1522.      {0, "block"},
  1523. +    {0, "kwd"},
  1524.      {0, NULL}
  1525.    };
  1526.    const struct RProc *proc = mrb_proc_ptr(self);
  1527. @@ -137,7 +139,9 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
  1528.    parameters_list[1].size = MRB_ASPEC_OPT(aspec);
  1529.    parameters_list[2].size = MRB_ASPEC_REST(aspec);
  1530.    parameters_list[3].size = MRB_ASPEC_POST(aspec);
  1531. -  parameters_list[4].size = MRB_ASPEC_BLOCK(aspec);
  1532. +  parameters_list[4].size = MRB_ASPEC_KDICT(aspec);
  1533. +  parameters_list[5].size = MRB_ASPEC_BLOCK(aspec);
  1534. +  parameters_list[6].size = MRB_ASPEC_KEY(aspec);
  1535.  
  1536.    parameters = mrb_ary_new_capa(mrb, irep->nlocals-1);
  1537.  
  1538. @@ -145,9 +149,9 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
  1539.      if (p->size <= 0) continue;
  1540.      sname = mrb_symbol_value(mrb_intern_cstr(mrb, p->name));
  1541.      for (j = 0; j < p->size; i++, j++) {
  1542. -      mrb_value a = mrb_ary_new(mrb);
  1543. +      mrb_value a = mrb_ary_new_capa(mrb, 2);
  1544.        mrb_ary_push(mrb, a, sname);
  1545. -      if (irep->lv[i].name) {
  1546. +      if (irep->lv[i].name != mrb_intern_lit(mrb, "*")) {
  1547.          mrb_ary_push(mrb, a, mrb_symbol_value(irep->lv[i].name));
  1548.        }
  1549.        mrb_ary_push(mrb, parameters, a);
  1550. modified   mrbgems/mruby-struct/test/struct.rb
  1551. @@ -142,7 +142,7 @@ end
  1552.  
  1553.  assert('Struct#to_h') do
  1554.    s = Struct.new(:white, :red, :green).new('ruuko', 'yuzuki', 'hitoe')
  1555. -  assert_equal(:white => 'ruuko', :red => 'yuzuki', :green => 'hitoe') { s.to_h }
  1556. +  assert_equal({:white => 'ruuko', :red => 'yuzuki', :green => 'hitoe'}, s.to_h)
  1557.  end
  1558.  
  1559.  assert('Struct#values_at') do
  1560. modified   mrbgems/mruby-test/mrbgem.rake
  1561. @@ -41,7 +41,7 @@ MRuby::Gem::Specification.new('mruby-test') do |spec|
  1562.      dep_list = build.gems.tsort_dependencies(g.test_dependencies, gem_table).select(&:generate_functions)
  1563.  
  1564.      file test_rbobj => g.test_rbireps
  1565. -    file g.test_rbireps => [g.test_rbfiles].flatten do |t|
  1566. +    file g.test_rbireps => [g.test_rbfiles, build.mrbcfile].flatten do |t|
  1567.        FileUtils.mkdir_p File.dirname(t.name)
  1568.        open(t.name, 'w') do |f|
  1569.          g.print_gem_test_header(f)
  1570. modified   src/class.c
  1571. @@ -15,6 +15,8 @@
  1572.  #include <mruby/error.h>
  1573.  #include <mruby/data.h>
  1574.  #include <mruby/istruct.h>
  1575. +#include <mruby/opcode.h>
  1576. +#include <mruby/hash.h>
  1577.  
  1578.  KHASH_DEFINE(mt, mrb_sym, struct RProc*, TRUE, kh_int_hash_func, kh_int_hash_equal)
  1579.  
  1580. @@ -582,6 +584,25 @@ mrb_get_args(mrb_state *mrb, const char *format, ...)
  1581.    (array_argv ? mrb_ary_ptr(mrb->c->stack[1])->ptr : (mrb->c->stack + 1))
  1582.  
  1583.    while ((c = *format++)) {
  1584. +    if ((c == 'H' || c == 'o') &&
  1585. +        i == argc && mrb->c->ci->pc && GET_OPCODE(mrb->c->ci->pc[-1]) == OP_SENDK) {
  1586. +      mrb_value const *kw = mrb->c->stack + mrb->c->ci->argc + 2;
  1587. +      mrb_value hsh = mrb_hash_new(mrb);
  1588. +      mrb_value *p = va_arg(ap, mrb_value*);
  1589. +
  1590. +      for (; !mrb_nil_p(*kw); kw += 2) {
  1591. +        mrb_assert(mrb_symbol_p(kw[0]));
  1592. +        mrb_hash_set(mrb, hsh, kw[0], kw[1]);
  1593. +      }
  1594. +      mrb_assert(mrb_nil_p(*kw));
  1595. +
  1596. +      i++; argc++;
  1597. +
  1598. +      *p = hsh;
  1599. +
  1600. +      continue;
  1601. +    }
  1602. +
  1603.      switch (c) {
  1604.      case '|': case '*': case '&': case '?':
  1605.        break;
  1606. modified   src/codedump.c
  1607. @@ -64,6 +64,15 @@ codedump(mrb_state *mrb, mrb_irep *irep)
  1608.    printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d\n", (void*)irep,
  1609.           irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen);
  1610.  
  1611. +  if (irep->lv) {
  1612. +    printf("local variable names:\n");
  1613. +    printf("  R%d:%s\n", 0, "self");
  1614. +    for (i = 1; i < irep->nlocals; ++i) {
  1615. +      char const *n = mrb_sym2name(mrb, irep->lv[i - 1].name);
  1616. +      printf("  R%d:%s\n", irep->lv[i - 1].r, n? n : "");
  1617. +    }
  1618. +  }
  1619. +
  1620.    for (i = 0; i < (int)irep->ilen; i++) {
  1621.      ai = mrb_gc_arena_save(mrb);
  1622.  
  1623. @@ -198,14 +207,22 @@ codedump(mrb_state *mrb, mrb_irep *irep)
  1624.        printf("OP_JMPNOT\tR%d\t%03d\n", GETARG_A(c), i+GETARG_sBx(c));
  1625.        break;
  1626.      case OP_SEND:
  1627. -      printf("OP_SEND\tR%d\t:%s\t%d\n", GETARG_A(c),
  1628. +      printf("OP_SEND\tR%d\t:%s\t%d", GETARG_A(c),
  1629.               mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
  1630.               GETARG_C(c));
  1631. +      print_lv(mrb, irep, c, RA);
  1632.        break;
  1633.      case OP_SENDB:
  1634. -      printf("OP_SENDB\tR%d\t:%s\t%d\n", GETARG_A(c),
  1635. +      printf("OP_SENDB\tR%d\t:%s\t%d", GETARG_A(c),
  1636. +             mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
  1637. +             GETARG_C(c));
  1638. +      print_lv(mrb, irep, c, RA);
  1639. +      break;
  1640. +    case OP_SENDK:
  1641. +      printf("OP_SENDK\tR%d\t:%s\t%d", GETARG_A(c),
  1642.               mrb_sym2name(mrb, irep->syms[GETARG_B(c)]),
  1643.               GETARG_C(c));
  1644. +      print_lv(mrb, irep, c, RA);
  1645.        break;
  1646.      case OP_TAILCALL:
  1647.        printf("OP_TAILCALL\tR%d\t:%s\t%d\n", GETARG_A(c),
  1648. @@ -444,6 +461,16 @@ codedump(mrb_state *mrb, mrb_irep *irep)
  1649.        printf("OP_EPOP\t%d\n", GETARG_A(c));
  1650.        break;
  1651.  
  1652. +    case OP_KARG:
  1653. +      printf("OP_KARG\tR%d\t:%s\t%d", GETARG_A(c),
  1654. +             mrb_sym2name(mrb, irep->syms[GETARG_B(c)]), GETARG_C(c));
  1655. +      print_lv(mrb, irep, c, RAB);
  1656. +      break;
  1657. +    case OP_KDICT:
  1658. +      printf("OP_KDICT\tR%d\t%d", GETARG_A(c), GETARG_C(c));
  1659. +      print_lv(mrb, irep, c, RA);
  1660. +      break;
  1661. +
  1662.      default:
  1663.        printf("OP_unknown %d\t%d\t%d\t%d\n", GET_OPCODE(c),
  1664.               GETARG_A(c), GETARG_B(c), GETARG_C(c));
  1665. modified   src/kernel.c
  1666. @@ -1143,6 +1143,10 @@ mrb_local_variables(mrb_state *mrb, mrb_value self)
  1667.    mrb_value vars;
  1668.    struct mrb_irep *irep;
  1669.    size_t i;
  1670. +  mrb_sym const
  1671. +      blk = mrb_intern_lit(mrb, "&"),
  1672. +      rest = mrb_intern_lit(mrb, "*"),
  1673. +      kwrest = mrb_intern_lit(mrb, "**");
  1674.  
  1675.    proc = mrb->c->ci[-1].proc;
  1676.  
  1677. @@ -1156,8 +1160,9 @@ mrb_local_variables(mrb_state *mrb, mrb_value self)
  1678.    }
  1679.    vars = mrb_hash_new(mrb);
  1680.    for (i = 0; i + 1 < irep->nlocals; ++i) {
  1681. -    if (irep->lv[i].name) {
  1682. -      mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value());
  1683. +    mrb_sym const n = irep->lv[i].name;
  1684. +    if (n && n != blk && n != rest && n != kwrest) {
  1685. +      mrb_hash_set(mrb, vars, mrb_symbol_value(n), mrb_true_value());
  1686.      }
  1687.    }
  1688.    if (proc->env) {
  1689. @@ -1169,8 +1174,9 @@ mrb_local_variables(mrb_state *mrb, mrb_value self)
  1690.          irep = mrb->c->cibase[e->cioff].proc->body.irep;
  1691.          if (irep->lv) {
  1692.            for (i = 0; i + 1 < irep->nlocals; ++i) {
  1693. -            if (irep->lv[i].name) {
  1694. -              mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value());
  1695. +            mrb_sym const n = irep->lv[i].name;
  1696. +            if (n && n != blk && n != rest && n != kwrest) {
  1697. +              mrb_hash_set(mrb, vars, mrb_symbol_value(n), mrb_true_value());
  1698.              }
  1699.            }
  1700.          }
  1701. modified   src/vm.c
  1702. @@ -249,6 +249,9 @@ cipush(mrb_state *mrb)
  1703.    ci->err = 0;
  1704.    ci->proc = 0;
  1705.    ci->acc = 0;
  1706. +  ci->use_kdict = FALSE;
  1707. +  ci->need_kdict_dup = TRUE;
  1708. +  ci->kwds = NULL;
  1709.  
  1710.    return ci;
  1711.  }
  1712. @@ -890,6 +893,7 @@ mrb_vm_exec(mrb_state *mrb, struct RProc *proc, mrb_code *pc)
  1713.      &&L_OP_CLASS, &&L_OP_MODULE, &&L_OP_EXEC,
  1714.      &&L_OP_METHOD, &&L_OP_SCLASS, &&L_OP_TCLASS,
  1715.      &&L_OP_DEBUG, &&L_OP_STOP, &&L_OP_ERR,
  1716. +    &&L_OP_SENDK,
  1717.    };
  1718.  #endif
  1719.  
  1720. @@ -1210,6 +1214,14 @@ RETRY_TRY_BLOCK:
  1721.        NEXT;
  1722.      }
  1723.  
  1724. +    CASE(OP_SENDK) {
  1725. +      /* A B C   R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),    */
  1726. +      /*                      &R(A+C+1),                         */
  1727. +      /*                      R(A+C+2),R(A+C+2+1)...,            */
  1728. +      /*                      R(A+C+2+2K),R(A+C+2+2K+1),nil)     */
  1729. +      /* fall through */
  1730. +    };
  1731. +
  1732.      CASE(OP_SENDB) {
  1733.        /* A B C  R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),&R(A+C+1))*/
  1734.        /* fall through */
  1735. @@ -1234,10 +1246,7 @@ RETRY_TRY_BLOCK:
  1736.        else {
  1737.          bidx = a+n+1;
  1738.        }
  1739. -      if (GET_OPCODE(i) != OP_SENDB) {
  1740. -        SET_NIL_VALUE(regs[bidx]);
  1741. -      }
  1742. -      else {
  1743. +      if (GET_OPCODE(i) == OP_SENDB || GET_OPCODE(i) == OP_SENDK) {
  1744.          mrb_value blk = regs[bidx];
  1745.          if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) {
  1746.            if (bidx >= mrb->c->ci->nregs) {
  1747. @@ -1248,6 +1257,7 @@ RETRY_TRY_BLOCK:
  1748.            regs[bidx] = result;
  1749.          }
  1750.        }
  1751. +      else { SET_NIL_VALUE(regs[bidx]); }
  1752.        c = mrb_class(mrb, recv);
  1753.        m = mrb_method_search_vm(mrb, &c, mid);
  1754.        if (!m) {
  1755. @@ -1615,73 +1625,194 @@ RETRY_TRY_BLOCK:
  1756.        int o  = MRB_ASPEC_OPT(ax);
  1757.        int r  = MRB_ASPEC_REST(ax);
  1758.        int m2 = MRB_ASPEC_POST(ax);
  1759. +      int const kw = MRB_ASPEC_KEY(ax);
  1760. +      int const kd = (kw > 0 || MRB_ASPEC_KDICT(ax))? 1 : 0;
  1761.        /* unused
  1762. -      int k  = MRB_ASPEC_KEY(ax);
  1763. -      int kd = MRB_ASPEC_KDICT(ax);
  1764.        int b  = MRB_ASPEC_BLOCK(ax);
  1765.        */
  1766.        int argc = mrb->c->ci->argc;
  1767.        mrb_value *argv = regs+1;
  1768. -      mrb_value *argv0 = argv;
  1769. -      int len = m1 + o + r + m2;
  1770. +      mrb_value * const argv0 = argv;
  1771. +      mrb_bool const is_sendk = mrb->c->ci->pc && GET_OPCODE(mrb->c->ci->pc[-1]) == OP_SENDK;
  1772. +      int const len = m1 + o + r + m2;
  1773. +      int blk_pos = len + 1;
  1774.        mrb_value *blk = &argv[argc < 0 ? 1 : argc];
  1775. +      mrb_value kdict = mrb_undef_value();
  1776. +      mrb_bool separate_kdict_p = FALSE, dont_separate_kdict;
  1777.  
  1778. +      // arguments is passed with Array
  1779.        if (argc < 0) {
  1780.          struct RArray *ary = mrb_ary_ptr(regs[1]);
  1781.          argv = ary->ptr;
  1782.          argc = ary->len;
  1783.          mrb_gc_protect(mrb, regs[1]);
  1784.        }
  1785. +
  1786. +      // strict argument check
  1787.        if (mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc)) {
  1788. -        if (argc >= 0) {
  1789. -          if (argc < m1 + m2 || (r == 0 && argc > len)) {
  1790. -            argnum_error(mrb, m1+m2);
  1791. -            goto L_RAISE;
  1792. -          }
  1793. +        int const kd_append = (MRB_ASPEC_KDICT(ax) && kw == 0) || is_sendk? 0 : kd;
  1794. +        if (argc >= 0 &&
  1795. +            (argc < m1 + m2 + kd_append || (r == 0 && argc > len + kd_append))) {
  1796. +          argnum_error(mrb, m1+m2+kd_append);
  1797. +          goto L_RAISE;
  1798.          }
  1799.        }
  1800. +      // extract first argument array to arguments
  1801.        else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) {
  1802.          mrb_gc_protect(mrb, argv[0]);
  1803.          argc = mrb_ary_ptr(argv[0])->len;
  1804.          argv = mrb_ary_ptr(argv[0])->ptr;
  1805.        }
  1806. +
  1807. +      dont_separate_kdict = argc == 1 && (m1 + m2 == 1) && MRB_ASPEC_KDICT(ax);
  1808. +      mrb->c->ci->use_kdict = MRB_ASPEC_KDICT(ax)? TRUE : FALSE;
  1809. +      if (is_sendk) {
  1810. +        mrb_value *kw = regs + 2 + (mrb->c->ci->argc < 0? 1 : mrb->c->ci->argc);
  1811. +
  1812. +        if (kd && !dont_separate_kdict) {
  1813. +          mrb_value const *kw_beg = kw;
  1814. +          int kdict_size = 0;
  1815. +          for (; !mrb_nil_p(kw[0]); kw += 2, ++kdict_size) { mrb_assert(mrb_symbol_p(kw[0])); }
  1816. +          kdict = mrb_ary_new_from_values(mrb, 2 * kdict_size + 1, kw_beg);
  1817. +          mrb->c->ci->kwds = mrb_ary_ptr(kdict)->ptr;
  1818. +          mrb_assert(mrb_nil_p(RARRAY_PTR(kdict)[RARRAY_LEN(kdict) - 1]));
  1819. +        }
  1820. +        // store to last argument hash when proc doesn't use keyword arguments
  1821. +        else {
  1822. +          mrb_value last_hash = mrb_hash_p(argv[argc - 1])? argv[argc - 1] : mrb_hash_new(mrb);
  1823. +          kdict = !mrb_hash_p(argv[argc - 1])? last_hash : mrb_hash_new(mrb);
  1824. +
  1825. +          for (; !mrb_nil_p(kw[0]); kw += 2) {
  1826. +            mrb_assert(mrb_symbol_p(kw[0]));
  1827. +            mrb_hash_set(mrb, last_hash, kw[0], kw[1]);
  1828. +          }
  1829. +        }
  1830. +
  1831. +        mrb_assert(mrb_nil_p(*kw));
  1832. +      }
  1833. +      else if (kd) {
  1834. +        blk_pos += kd;
  1835. +
  1836. +        if (argc == 0 && kw > 0) {
  1837. +          mrb_value str = mrb_format(mrb, "excepcted `Hash` as last argument for keyword arguments");
  1838. +          mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str));
  1839. +          goto L_RAISE;
  1840. +        }
  1841. +
  1842. +        // check last arguments is hash if method takes keyword arguments
  1843. +        if (mrb_hash_p(argv[argc - 1])) { kdict = argv[argc - 1]; }
  1844. +        else if (mrb_respond_to(mrb, argv[argc - 1], mrb_intern_lit(mrb, "to_hash"))) {
  1845. +          kdict = argv[argc - 1] =
  1846. +                  mrb_convert_type(mrb, argv[argc - 1], MRB_TT_HASH, "Hash", "to_hash");
  1847. +        }
  1848. +        else {
  1849. +          // check optional keyword arguments
  1850. +          if (kw > 0) {
  1851. +            mrb_value str = mrb_format(mrb, "excepcted `Hash` as last argument for keyword arguments");
  1852. +            mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str));
  1853. +            goto L_RAISE;
  1854. +          }
  1855. +
  1856. +          kdict = mrb_hash_new(mrb);
  1857. +          separate_kdict_p = TRUE;
  1858. +        }
  1859. +
  1860. +        if (!separate_kdict_p && dont_separate_kdict) {
  1861. +          kdict = mrb_hash_new(mrb);
  1862. +          separate_kdict_p = TRUE;
  1863. +        }
  1864. +
  1865. +        if (!separate_kdict_p) {
  1866. +          khash_t(ht) *h = RHASH_TBL(kdict);
  1867. +          khiter_t k;
  1868. +          mrb_int non_sym_count = 0;
  1869. +
  1870. +          // count non symbol key
  1871. +          for (k = kh_begin(h); k != kh_end(h); ++k) {
  1872. +            if (kh_exist(h, k) && !mrb_symbol_p(kh_key(h, k))) { ++non_sym_count; }
  1873. +          }
  1874. +
  1875. +          // move keyword arguments to seperate hash
  1876. +          if (non_sym_count > 0) {
  1877. +            mrb_value const sep = mrb_hash_new_capa(mrb, kh_size(h) - non_sym_count);
  1878. +            mrb_value kv;
  1879. +
  1880. +            // duplicate hash
  1881. +            kdict = argv[argc - 1] = mrb_obj_dup(mrb, kdict);
  1882. +            mrb->c->ci->need_kdict_dup = FALSE;
  1883. +
  1884. +            for (k = kh_begin(h); k != kh_end(h); ++k) {
  1885. +              if (!kh_exist(h, k)) { continue; }
  1886. +
  1887. +              kv = kh_key(h, k);
  1888. +
  1889. +              if (mrb_symbol_p(kv)) {
  1890. +                mrb_hash_set(mrb, sep, kv, kh_value(h, k).v);
  1891. +                mrb_hash_delete_key(mrb, kdict, kv);
  1892. +              }
  1893. +            }
  1894. +
  1895. +            separate_kdict_p = TRUE;
  1896. +            kdict = sep;
  1897. +          }
  1898. +          // ignore passed hash as optional argument when hash splitting didn't occur
  1899. +          else if (o > 0) { --argc; }
  1900. +        }
  1901. +
  1902. +        // recheck arguments count when kdict is separate hash
  1903. +        if (separate_kdict_p && !dont_separate_kdict &&
  1904. +            mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc) &&
  1905. +            argc >= 0 && (argc < m1 + m2 || (r == 0 && argc > len))) {
  1906. +          argnum_error(mrb, m1+m2);
  1907. +          goto L_RAISE;
  1908. +        }
  1909. +
  1910. +        mrb_assert(mrb_hash_p(kdict));
  1911. +        mrb_assert(!mrb->c->ci->kwds);
  1912. +      }
  1913. +
  1914. +      // no rest arguments
  1915.        if (argc < len) {
  1916.          int mlen = m2;
  1917.          if (argc < m1+m2) {
  1918. -          if (m1 < argc)
  1919. -            mlen = argc - m1;
  1920. -          else
  1921. -            mlen = 0;
  1922. +          mlen = m1 < argc ? argc - m1 : 0;
  1923.          }
  1924. -        regs[len+1] = *blk; /* move block */
  1925. +        regs[blk_pos] = *blk; /* move block */
  1926. +        if (kd) { regs[len + 1] = kdict; }
  1927.          SET_NIL_VALUE(regs[argc+1]);
  1928. +        // copy mandatory and optional arguments
  1929.          if (argv0 != argv) {
  1930.            value_move(&regs[1], argv, argc-mlen); /* m1 + o */
  1931.          }
  1932.          if (argc < m1) {
  1933.            stack_clear(&regs[argc+1], m1-argc);
  1934.          }
  1935. +        // copy post mandatory arguments
  1936.          if (mlen) {
  1937.            value_move(&regs[len-m2+1], &argv[argc-mlen], mlen);
  1938.          }
  1939.          if (mlen < m2) {
  1940.            stack_clear(&regs[len-m2+mlen+1], m2-mlen);
  1941.          }
  1942. +        // initalize rest arguments with empty Array
  1943.          if (r) {
  1944.            regs[m1+o+1] = mrb_ary_new_capa(mrb, 0);
  1945.          }
  1946. +        // skip optional arguments
  1947.          if (o == 0 || argc < m1+m2) pc++;
  1948. +        // skip initailizer of passed arguments
  1949.          else
  1950.            pc += argc - m1 - m2 + 1;
  1951.        }
  1952.        else {
  1953.          int rnum = 0;
  1954.          if (argv0 != argv) {
  1955. -          regs[len+1] = *blk; /* move block */
  1956. +          regs[blk_pos] = *blk; /* move block */
  1957. +          if (kd) { regs[len + 1] = kdict; }
  1958.            value_move(&regs[1], argv, m1+o);
  1959.          }
  1960.          if (r) {
  1961. -          rnum = argc-m1-o-m2;
  1962. +          rnum = argc-m1-o-m2-(is_sendk || separate_kdict_p? 0 : kd);
  1963.            regs[m1+o+1] = mrb_ary_new_from_values(mrb, rnum, argv+m1+o);
  1964.          }
  1965.          if (m2) {
  1966. @@ -1690,11 +1821,12 @@ RETRY_TRY_BLOCK:
  1967.            }
  1968.          }
  1969.          if (argv0 == argv) {
  1970. -          regs[len+1] = *blk; /* move block */
  1971. +          regs[blk_pos] = *blk; /* move block */
  1972. +          if (kd) { regs[len + 1] = kdict; }
  1973.          }
  1974.          pc += o + 1;
  1975.        }
  1976. -      mrb->c->ci->argc = len;
  1977. +      mrb->c->ci->argc = len + kd;
  1978.        /* clear local (but non-argument) variables */
  1979.        if (irep->nlocals-len-2 > 0) {
  1980.          stack_clear(&regs[len+2], irep->nlocals-len-2);
  1981. @@ -1702,18 +1834,123 @@ RETRY_TRY_BLOCK:
  1982.        JUMP;
  1983.      }
  1984.  
  1985. +#define DUP_KDICT(kdict)                    \
  1986. +    do {                                    \
  1987. +      if (mrb->c->ci->need_kdict_dup) {     \
  1988. +        mrb->c->ci->need_kdict_dup = FALSE; \
  1989. +        *kdict = mrb_obj_dup(mrb, *kdict);  \
  1990. +      }                                     \
  1991. +    } while(FALSE)                          \
  1992. +
  1993.      CASE(OP_KARG) {
  1994. -      /* A B C          R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B)) */
  1995. -      /* if C == 2; raise unless kdict.empty? */
  1996. -      /* OP_JMP should follow to skip init code */
  1997. +      /* A B C   R(A) := kdict[Syms(B)]                          */
  1998. +      /*         R(A+1) := kdict.key?(Syms(B)) if C == 1         */
  1999. +      /*         raise ArgumentError if C == 2 && !kdict.key?(Syms(B)) */
  2000. +      /*         kdict.delete(Syms(B)) if C >= 1                 */
  2001. +      int a = GETARG_A(i), c = GETARG_C(i);
  2002. +      mrb_value k = mrb_symbol_value(syms[GETARG_B(i)]);
  2003. +      if (mrb->c->ci->kwds) {
  2004. +        mrb_value *kw;
  2005. +
  2006. +        mrb_assert(mrb_array_p(regs[mrb->c->ci->argc]));
  2007. +        mrb_assert(RARRAY_PTR(regs[mrb->c->ci->argc]) == mrb->c->ci->kwds);
  2008. +
  2009. +        regs[a] = mrb_undef_value();
  2010. +        for (kw = mrb->c->ci->kwds; !mrb_nil_p(*kw); kw += 2) {
  2011. +          mrb_assert(mrb_symbol_p(kw[0]));
  2012. +          if (mrb_symbol(kw[0]) == mrb_symbol(k)) {
  2013. +            regs[a] = kw[1];
  2014. +            if (c == 1) { regs[a + 1] = mrb_true_value(); }
  2015. +            if (c) { kw[0] = mrb_symbol_value(0); }
  2016. +            break;
  2017. +          }
  2018. +        }
  2019. +        if (!mrb_undef_p(regs[a])) { NEXT; }
  2020. +      }
  2021. +      else {
  2022. +        mrb_value *kdict = &regs[mrb->c->ci->argc];
  2023. +
  2024. +        mrb_assert(mrb_hash_p(*kdict));
  2025. +        regs[a] = mrb_hash_fetch(mrb, *kdict, k, mrb_undef_value());
  2026. +
  2027. +        if (!mrb_undef_p(regs[a])) {
  2028. +          if (c == 1) { regs[a + 1] = mrb_true_value(); }
  2029. +          if (c && mrb->c->ci->use_kdict) {
  2030. +            DUP_KDICT(kdict);
  2031. +            mrb_hash_delete_key(mrb, *kdict, k);
  2032. +          }
  2033. +          NEXT;
  2034. +        }
  2035. +      }
  2036. +
  2037. +      if (c == 2) {
  2038. +        mrb_value str = mrb_format(mrb, "keyword argument '%S' not passed", k);
  2039. +        mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str));
  2040. +        goto L_RAISE;
  2041. +      }
  2042. +      if (c == 1) { regs[a + 1] = mrb_false_value(); }
  2043. +      regs[a] = mrb_nil_value(); // clear undef value
  2044. +
  2045.        NEXT;
  2046.      }
  2047.  
  2048.      CASE(OP_KDICT) {
  2049.        /* A C            R(A) := kdict */
  2050. +      /*                raise ArgumentError if C && !kdict.empty? */
  2051. +      int a = GETARG_A(i), c = GETARG_C(i);
  2052. +      mrb_value *kdict = &regs[mrb->c->ci->argc], str;
  2053. +
  2054. +      if (mrb->c->ci->kwds) {
  2055. +        mrb_value *kw;
  2056. +
  2057. +        mrb_assert(mrb_array_p(*kdict));
  2058. +
  2059. +        if (c) {
  2060. +          mrb_int restkwd = 0;
  2061. +          for (kw = mrb->c->ci->kwds; !mrb_nil_p(*kw); kw += 2) {
  2062. +            if (mrb_symbol(kw[0]) != 0) { ++restkwd; }
  2063. +          }
  2064. +          if (restkwd > 0) { goto L_RAISE_KDICT_ERROR; }
  2065. +
  2066. +          if (kdict == (regs + a)) {
  2067. +            *kdict = mrb_nil_value();
  2068. +            NEXT;
  2069. +          }
  2070. +          else { regs[a] = mrb_hash_new(mrb); }
  2071. +        }
  2072. +        else {
  2073. +          mrb_value res = mrb_hash_new(mrb);
  2074. +          for (kw = mrb->c->ci->kwds; !mrb_nil_p(*kw); kw += 2) {
  2075. +            if (mrb_symbol(kw[0]) == 0) { continue; }
  2076. +            mrb_assert(mrb_symbol_p(kw[0]));
  2077. +            mrb_hash_set(mrb, res, kw[0], kw[1]);
  2078. +          }
  2079. +          mrb_assert(mrb_nil_p(*kw));
  2080. +          *kdict = regs[a] = res;
  2081. +        }
  2082. +
  2083. +        mrb->c->ci->kwds = NULL;
  2084. +      }
  2085. +      else {
  2086. +        if (c && kh_size(RHASH_TBL(*kdict)) > 0) { goto L_RAISE_KDICT_ERROR; }
  2087. +
  2088. +        DUP_KDICT(kdict);
  2089. +        regs[a] = *kdict;
  2090. +      }
  2091. +
  2092. +      mrb_assert(mrb_hash_p(*kdict));
  2093. +      mrb_assert(mrb_hash_p(regs[a]));
  2094. +
  2095.        NEXT;
  2096. +
  2097. +   L_RAISE_KDICT_ERROR:
  2098. +      str = mrb_format(mrb, "unhandled keyword arguments found: %S", *kdict);
  2099. +      mrb_exc_set(mrb, mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str));
  2100. +      goto L_RAISE;
  2101.      }
  2102.  
  2103. +#undef DUP_KDICT
  2104. +
  2105.      L_RETURN:
  2106.        i = MKOP_AB(OP_RETURN, GETARG_A(i), OP_R_NORMAL);
  2107.        /* fall through */
  2108. modified   test/t/syntax.rb
  2109. @@ -403,6 +403,9 @@ assert('External command execution.') do
  2110.      assert_equal 'test dynamic `', t
  2111.      assert_equal ['test', 'test dynamic `', 'test', 'test dynamic `'], results
  2112.  
  2113. +    results = []
  2114. +    assert_equal 'test sym test sym test', `test #{:sym} test #{:sym} test`
  2115. +
  2116.      alias_method sym, :old_cmd
  2117.    end
  2118.    true
  2119. @@ -466,3 +469,215 @@ this is a comment that has extra after =begin and =end with tabs after it
  2120.  =end   xxxxxxxxxxxxxxxxxxxxxxxxxx
  2121.    assert_equal(line + 4, __LINE__)
  2122.  end
  2123. +
  2124. +assert 'keyword arguments' do
  2125. +  def m(a:) a end
  2126. +  assert_equal 1, m(a: 1)
  2127. +  assert_raise(ArgumentError) { m }
  2128. +  assert_raise(ArgumentError) { m 'a'  => 1, a: 1 }
  2129. +  h = { a: 1 }
  2130. +  assert_equal 1, m(h)
  2131. +  assert_equal({ a: 1 }, h)
  2132. +
  2133. +  def m(a: 1) a end
  2134. +  assert_equal 1, m
  2135. +  assert_equal 2, m(a: 2)
  2136. +  assert_raise(ArgumentError) { m 1 }
  2137. +
  2138. +  def m(**) end
  2139. +  assert_nil m
  2140. +  assert_nil m a: 1, b: 2
  2141. +  assert_raise(ArgumentError) { m 2 }
  2142. +
  2143. +  def m(a, **) a end
  2144. +  assert_equal 1, m(1)
  2145. +  assert_equal 1, m(1, a: 2, b: 3)
  2146. +  assert_equal({ 'a' => 1, b: 2 }, m('a' => 1, b: 2))
  2147. +
  2148. +  def m(a, **k) [a, k] end
  2149. +  assert_equal [1, {}], m(1)
  2150. +  assert_equal [1, {a: 2, b: 3}], m(1, a: 2, b: 3)
  2151. +  assert_equal [{'a' => 1, b: 2}, {}], m('a' => 1, b: 2)
  2152. +
  2153. +  def m(a=1, **) a end
  2154. +  assert_equal 1, m
  2155. +  assert_equal 2, m(2, a: 1, b: 0)
  2156. +  assert_equal({'a' => 1}, m('a' => 1, a: 2))
  2157. +
  2158. +  def m(a=1, **k) [a, k] end
  2159. +  assert_equal [1, {}], m
  2160. +  assert_equal [2, {a: 1, b: 2}], m(2, a: 1, b: 2)
  2161. +
  2162. +  def m(*, a:) a end
  2163. +  assert_equal 1, m(a: 1)
  2164. +  assert_equal 3, m(1, 2, a: 3)
  2165. +  assert_equal 2, m('a' => 1, a: 2)
  2166. +
  2167. +  def m(*a, b:) [a, b] end
  2168. +  assert_equal [[], 1], m(b: 1)
  2169. +  assert_equal [[1, 2], 3], m(1, 2, b: 3)
  2170. +  assert_equal [[{'a' => 1}], 2], m('a' => 1, b: 2)
  2171. +
  2172. +  def m(*a, b: 1) [a, b] end
  2173. +  assert_equal [[], 1], m
  2174. +  assert_equal [[1, 2, 3], 4], m(1, 2, 3, b: 4)
  2175. +  assert_equal [[{'a' => 1}], 2], m('a' => 1, b: 2)
  2176. +  splat_val = Object.new
  2177. +  assert_false splat_val.respond_to? :to_ary
  2178. +  assert_equal [[splat_val], 1], m(*splat_val)
  2179. +
  2180. +  def m(*, **) end
  2181. +  assert_nil m()
  2182. +  assert_nil m(a: 1, b: 2)
  2183. +  assert_nil m(1, 2, 3, a: 4, b: 5)
  2184. +  h = Object.new
  2185. +  def h.to_hash; { a: 1 } end
  2186. +  assert_true h.respond_to? :to_hash
  2187. +  assert_nil m(h)
  2188. +  h = Object.new
  2189. +  def h.to_hash; raise end
  2190. +  assert_raise(RuntimeError) { m(h) }
  2191. +
  2192. +  def m(*a, **) a end
  2193. +  assert_equal [], m()
  2194. +  assert_equal [1, 2, 3], m(1, 2, 3, a: 4, b: 5)
  2195. +  assert_equal [{"a" => 1}], m("a" => 1, a: 1)
  2196. +  assert_equal [1], m(1, **{a: 2})
  2197. +  h = Object.new
  2198. +  def h.to_hash; nil end
  2199. +  assert_true h.respond_to?(:to_hash)
  2200. +  assert_raise(TypeError) { m(**h) }
  2201. +
  2202. +  def m(*, **k) k end
  2203. +  assert_equal({}, m())
  2204. +  assert_equal({a: 4, b: 5}, m(1, 2, 3, a: 4, b: 5))
  2205. +  assert_equal({a: 1}, m("a" => 1, a: 1))
  2206. +  h = Object.new
  2207. +  def h.to_hash; {a: 1} end
  2208. +  assert_true h.respond_to?(:to_hash)
  2209. +  assert_equal({a: 1}, m(h))
  2210. +
  2211. +  def m(a = nil, b = nil, **k) [a, k] end
  2212. +  assert_equal [nil, {}], m()
  2213. +  assert_equal [{"a" => 1}, {}], m("a" => 1)
  2214. +  assert_equal([nil, {a: 1}], m(a: 1))
  2215. +  assert_equal([{"a" => 1}, {a: 1}], m("a" => 1, a: 1))
  2216. +  assert_equal([{"a" => 1}, {a: 1}], m({ "a" => 1 }, a: 1))
  2217. +  assert_equal([{a: 1}, {}], m({a: 1}, {}))
  2218. +  h = {"a" => 1, b: 2}
  2219. +  assert_equal([{"a" => 1}, {b: 2}], m(h))
  2220. +  assert_equal({"a" => 1, b: 2}, h)
  2221. +  h = {"a" => 1}
  2222. +  assert_equal(h, m(h).first)
  2223. +  assert_equal([nil, {}], m({}))
  2224. +  hh = {}
  2225. +  h = Object.new
  2226. +  h.define_singleton_method(:to_hash) { hh }
  2227. +  assert_equal([nil, {}], m(h))
  2228. +  h = Object.new
  2229. +  def h.to_hash; {"a" => 1, a: 2} end
  2230. +  assert_equal([{"a" => 1}, {a: 2}], m(h))
  2231. +
  2232. +  def m(*a, **k) [a, k] end
  2233. +  assert_equal([[], {}], m())
  2234. +  assert_equal([[1], {}], m(1))
  2235. +  assert_equal([[], {a: 1, b: 2}], m(a: 1, b: 2))
  2236. +  assert_equal([[1, 2, 3], {a: 2}], m(1, 2, 3, a: 2))
  2237. +  assert_equal([[{"a" => 1}], {}], m("a" => 1))
  2238. +  assert_equal([[], {a: 1}], m(a: 1))
  2239. +  assert_equal([[{"a" => 1}], {a: 1}], m("a" => 1, a: 1))
  2240. +  assert_equal([[{"a" => 1}], {a: 1}], m({ "a" => 1 }, a: 1))
  2241. +  assert_equal([[{a: 1}], {}], m({a: 1}, {}))
  2242. +  assert_equal([[{a: 1}, {"a" => 1}], {}], m({a: 1}, {"a" => 1}))
  2243. +  bo = BasicObject.new
  2244. +  def bo.to_a; [1, 2, 3]; end
  2245. +  def bo.to_hash; {b: 2, c: 3}; end
  2246. +  assert_equal([[1, 2, 3], {:b => 2, :c => 3}], m(*bo, **bo))
  2247. +
  2248. +=begin
  2249. +  def m(*, &b) b end
  2250. +  m().should be_nil
  2251. +  m(1, 2, 3, 4).should be_nil
  2252. +  m(&(l = ->{})).should equal(l)
  2253. +
  2254. +  def m(*a, &b) [a, b] end
  2255. +  assert_equal([[], nil], m())
  2256. +  assert_equal([[1], nil], m(1))
  2257. +  assert_equal([[1, 2, 3], l], m(1, 2, 3, &(l = -> {})))
  2258. +=end
  2259. +
  2260. +  def m(a:, b:) [a, b] end
  2261. +  assert_equal([1, 2], m(a: 1, b: 2))
  2262. +  assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) }
  2263. +
  2264. +  def m(a:, b: 1) [a, b] end
  2265. +  assert_equal([1, 1], m(a: 1))
  2266. +  assert_equal([1, 2], m(a: 1, b: 2))
  2267. +  assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) }
  2268. +
  2269. +  def m(a:, **) a end
  2270. +  assert_equal(1, m(a: 1))
  2271. +  assert_equal(1, m(a: 1, b: 2))
  2272. +  assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) }
  2273. +
  2274. +  def m(a:, **k) [a, k] end
  2275. +  assert_equal([1, {}], m(a: 1))
  2276. +  assert_equal([1, {b: 2, c: 3}], m(a: 1, b: 2, c: 3))
  2277. +  assert_raise(ArgumentError) { m("a" => 1, a: 1, b: 2) }
  2278. +
  2279. +=begin
  2280. +  def m(a:, &b) [a, b] end
  2281. +  assert_equal([1, nil], m(a: 1))
  2282. +  assert_equal([1, l], m(a: 1, &(l = ->{})))
  2283. +=end
  2284. +
  2285. +  def m(a: 1, b:) [a, b] end
  2286. +  assert_equal([1, 0], m(b: 0))
  2287. +  assert_equal([3, 2], m(b: 2, a: 3))
  2288. +  assert_raise(ArgumentError) { m a: 1 }
  2289. +
  2290. +  def m(a: def m(a: 1) a end, b:)
  2291. +    [a, b]
  2292. +  end
  2293. +  assert_equal([2, 3], m(a: 2, b: 3))
  2294. +  assert_equal([:m, 1], m(b: 1))
  2295. +  # Note the default value of a: in the original method.
  2296. +  assert_equal(1, m())
  2297. +
  2298. +  def m(a: 1, b: 2) [a, b] end
  2299. +  assert_equal([1, 2], m())
  2300. +  assert_equal([4, 3], m(b: 3, a: 4))
  2301. +
  2302. +  def m(a: 1, **) a end
  2303. +  assert_equal(1, m())
  2304. +  assert_equal(2, m(a: 2, b: 1))
  2305. +
  2306. +  def m(a: 1, **k) [a, k] end
  2307. +  assert_equal([1, {b: 2, c: 3}], m(b: 2, c: 3))
  2308. +
  2309. +=begin
  2310. +  def m(a: 1, &b) [a, b] end
  2311. +  assert_equal([1, l], m(&(l = ->{})))
  2312. +  assert_equal([1, nil], m())
  2313. +
  2314. +  def m(**, &b) b end
  2315. +  assert_equal(l, m(a: 1, b: 2, &(l = ->{})))
  2316. +=end
  2317. +
  2318. +  def m(**k, &b) [k, b] end
  2319. +  assert_equal([{ a: 1, b: 2}, nil], m(a: 1, b: 2))
  2320. +
  2321. +=begin
  2322. +  def m(a, b=1, *c, (*d, (e)), f: 2, g:, h:, **k, &l)
  2323. +    [a, b, c, d, e, f, g, h, k, l]
  2324. +  end
  2325. +  result = m(9, 8, 7, 6, f: 5, g: 4, h: 3, &(l = ->{}))
  2326. +  assert_equal([9, 8, [7], [], 6, 5, 4, 3, {}, l], result)
  2327. +
  2328. +  def m a, b=1, *c, d, e:, f: 2, g:, **k, &l
  2329. +    [a, b, c, d, e, f, g, k, l]
  2330. +  end
  2331. +  result = m(1, 2, e: 3, g: 4, h: 5, i: 6, &(l = ->{}))
  2332. +  assert_equal([1, 1, [], 2, 3, 2, 4, { h: 5, i: 6 }, l], result)
  2333. +=end
  2334. +end
RAW Paste Data
Pastebin PRO Summer Special!
Get 40% OFF on Pastebin PRO accounts!
Top