summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2019-09-02 15:21:30 (GMT)
committerGitHub <noreply@github.com>2019-09-02 15:21:30 (GMT)
commitf560609d66502101264706877577220e3ebf5a38 (patch)
treed30a77b807ed0d4eb5363270b7119f1f31165b54
parentbe86591458c5f29db0d97601f29e15e43d5fe23c (diff)
Merge pull request #2418 from jeremyevans/array-empty-kwsplat
Ignore empty keyword splats in arrays
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/2418 Merged-By: jeremyevans <code@jeremyevans.net>
-rw-r--r--compile.c18
-rw-r--r--insns.def20
-rw-r--r--test/ruby/test_syntax.rb27
3 files changed, 63 insertions, 2 deletions
diff --git a/compile.c b/compile.c
index 774aced..ad99982 100644
--- a/compile.c
+++ b/compile.c
@@ -4025,8 +4025,21 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node_ro
else {
if (!popped || kw) {
switch (type) {
- case COMPILE_ARRAY_TYPE_ARRAY:
- ADD_INSN1(anchor, line, newarray, INT2FIX(i));
+ case COMPILE_ARRAY_TYPE_ARRAY: {
+ const NODE *check_node = node_root;
+
+ /* Find last node in array, and if it is a keyword argument, then set
+ flag to check and remove empty keyword arguments hash from array */
+ while(check_node->nd_next) {
+ check_node = check_node->nd_next;
+ }
+ if (nd_type(check_node->nd_head) == NODE_HASH && check_node->nd_head->nd_brace == 0) {
+ ADD_INSN1(anchor, line, newarraykwsplat, INT2FIX(i));
+ }
+ else {
+ ADD_INSN1(anchor, line, newarray, INT2FIX(i));
+ }
+
if (first) {
first = 0;
@@ -4037,6 +4050,7 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node_ro
APPEND_LIST(ret, anchor);
break;
+ }
case COMPILE_ARRAY_TYPE_HASH:
if (i > 0) {
if (first) {
diff --git a/insns.def b/insns.def
index 35a6aa9..1399687 100644
--- a/insns.def
+++ b/insns.def
@@ -441,6 +441,26 @@ newarray
val = rb_ary_new4(num, STACK_ADDR_FROM_TOP(num));
}
+/* put new array initialized with num values on the stack. There
+ should be at least one element on the stack, and the top element
+ should be a hash. If the top element is empty, it is not
+ included in the array.
+ */
+DEFINE_INSN
+newarraykwsplat
+(rb_num_t num)
+(...)
+(VALUE val)
+// attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
+{
+ if (RHASH_EMPTY_P(*STACK_ADDR_FROM_TOP(1))) {
+ val = rb_ary_new4(num-1, STACK_ADDR_FROM_TOP(num));
+ }
+ else {
+ val = rb_ary_new4(num, STACK_ADDR_FROM_TOP(num));
+ }
+}
+
/* dup array */
DEFINE_INSN
duparray
diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb
index b98a233..56e2937 100644
--- a/test/ruby/test_syntax.rb
+++ b/test/ruby/test_syntax.rb
@@ -100,6 +100,33 @@ class TestSyntax < Test::Unit::TestCase
EOS
end
+ def test_array_kwsplat_hash
+ kw = {}
+ h = {a: 1}
+ assert_equal([], [**{}])
+ assert_equal([], [**kw])
+ assert_equal([h], [**h])
+ assert_equal([{}], [{}])
+ assert_equal([kw], [kw])
+ assert_equal([h], [h])
+
+ assert_equal([1], [1, **{}])
+ assert_equal([1], [1, **kw])
+ assert_equal([1, h], [1, **h])
+ assert_equal([1, {}], [1, {}])
+ assert_equal([1, kw], [1, kw])
+ assert_equal([1, h], [1, h])
+
+ assert_equal([], [**kw, **kw])
+ assert_equal([], [**kw, **{}, **kw])
+ assert_equal([1], [1, **kw, **{}, **kw])
+
+ assert_equal([{}], [{}, **kw, **kw])
+ assert_equal([kw], [kw, **kw, **kw])
+ assert_equal([h], [h, **kw, **kw])
+ assert_equal([h, h], [h, **kw, **kw, **h])
+ end
+
def test_normal_argument
assert_valid_syntax('def foo(x) end')
assert_syntax_error('def foo(X) end', /constant/)