Advertisement
Guest User

Untitled

a guest
Apr 21st, 2017
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 72.95 KB | None | 0 0
  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
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement