summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2018-08-25 09:10:37 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2018-08-25 09:41:21 +0900
commit49d1b168221221b7e810f001d88e16ebc94378fd (patch)
tree10ff0f8b4e9b8bb7e8dea4003f2126e9e2c3bf5b
parent306732e02da5f0d47f44033ec1a3af1a77c5f418 (diff)
downloadmruby-49d1b168221221b7e810f001d88e16ebc94378fd.tar.gz
mruby-49d1b168221221b7e810f001d88e16ebc94378fd.zip
Hash splat `**` should not be ignored.
Implemented by adding `OP_HASHCAT` that merges hashes.
-rw-r--r--include/mruby/ops.h1
-rw-r--r--mrbgems/mruby-compiler/core/codegen.c37
-rw-r--r--src/codedump.c6
-rw-r--r--src/vm.c5
4 files changed, 39 insertions, 10 deletions
diff --git a/include/mruby/ops.h b/include/mruby/ops.h
index b8fc89d43..f23bb1b0b 100644
--- a/include/mruby/ops.h
+++ b/include/mruby/ops.h
@@ -94,6 +94,7 @@ OPCODE(STRING, BB) /* R(a) = str_dup(Lit(b)) */
OPCODE(STRCAT, B) /* str_cat(R(a),R(a+1)) */
OPCODE(HASH, BB) /* R(a) = hash_new(R(a),R(a+1)..R(a+b)) */
OPCODE(HASHADD, BB) /* R(a) = hash_push(R(a),R(a+1)..R(a+b)) */
+OPCODE(HASHCAT, B) /* R(a) = hash_cat(R(a),R(a+1)) */
OPCODE(LAMBDA, BB) /* R(a) = lambda(SEQ[b],L_LAMBDA) */
OPCODE(BLOCK, BB) /* R(a) = lambda(SEQ[b],L_BLOCK) */
OPCODE(METHOD, BB) /* R(a) = lambda(SEQ[b],L_METHOD) */
diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c
index 8e72abda2..bf5cc14b0 100644
--- a/mrbgems/mruby-compiler/core/codegen.c
+++ b/mrbgems/mruby-compiler/core/codegen.c
@@ -1874,15 +1874,32 @@ codegen(codegen_scope *s, node *tree, int val)
mrb_bool update = FALSE;
while (tree) {
- if (nt == NODE_KW_HASH &&
- nint(tree->car->car->car) == NODE_KW_REST_ARGS) {
- tree = tree->cdr;
- continue;
+ if (nint(tree->car->car->car) == NODE_KW_REST_ARGS) {
+ if (len > 0) {
+ pop_n(len*2);
+ if (!update) {
+ genop_2(s, OP_HASH, cursp(), len);
+ }
+ else {
+ pop();
+ genop_2(s, OP_HASHADD, cursp(), len);
+ }
+ push();
+ }
+ codegen(s, tree->car->cdr, VAL);
+ if (len > 0) {
+ pop(); pop();
+ genop_1(s, OP_HASHCAT, cursp());
+ push();
+ }
+ update = TRUE;
+ len = 0;
+ }
+ else {
+ codegen(s, tree->car->car, VAL);
+ codegen(s, tree->car->cdr, VAL);
+ len++;
}
-
- codegen(s, tree->car->car, val);
- codegen(s, tree->car->cdr, val);
- len++;
tree = tree->cdr;
if (val && len == 255) {
pop_n(len*2);
@@ -1905,7 +1922,9 @@ codegen(codegen_scope *s, node *tree, int val)
}
else {
pop();
- genop_2(s, OP_HASHADD, cursp(), len);
+ if (len > 0) {
+ genop_2(s, OP_HASHADD, cursp(), len);
+ }
}
push();
}
diff --git a/src/codedump.c b/src/codedump.c
index 842d40bdf..9174ebe3d 100644
--- a/src/codedump.c
+++ b/src/codedump.c
@@ -416,7 +416,11 @@ codedump(mrb_state *mrb, mrb_irep *irep)
print_lv_a(mrb, irep, a);
break;
CASE(OP_HASHADD, BB):
- printf("OP_HASHADD\tR%d\t%d", a, b);
+ printf("OP_HASHADD\tR%d\t%d\t", a, b);
+ print_lv_a(mrb, irep, a);
+ break;
+ CASE(OP_HASHCAT, B):
+ printf("OP_HASHCAT\tR%d\t", a);
print_lv_a(mrb, irep, a);
break;
diff --git a/src/vm.c b/src/vm.c
index 8332158f7..b47469ebf 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -2710,6 +2710,11 @@ RETRY_TRY_BLOCK:
mrb_gc_arena_restore(mrb, ai);
NEXT;
}
+ CASE(OP_HASHCAT, B) {
+ mrb_hash_merge(mrb, regs[a], regs[a+1]);
+ mrb_gc_arena_restore(mrb, ai);
+ NEXT;
+ }
CASE(OP_LAMBDA, BB)
c = OP_L_LAMBDA;