daily pastebin goal
67%
SHARE
TWEET

Untitled

a guest Apr 21st, 2017 51 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
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top