diff options
author | Jemma Issroff <[email protected]> | 2023-11-01 15:22:08 -0300 |
---|---|---|
committer | Jemma Issroff <[email protected]> | 2023-11-06 10:39:07 -0300 |
commit | f6ba87ca8899cd753306ffbca475b16c367995a3 (patch) | |
tree | b68e10e175ea4d9203dfca4577d4db7ee636e8fb | |
parent | 4a6bdbd6dc160c4614105f0478d398b2222429e0 (diff) |
[PRISM] Implement compilation for MultiWriteNodes, fix MultiTargetNodes
Compilation now works for MultiWriteNodes and MultiTargetNodes, with
nesting on MultiWrites. See the tests added in this commit for example
behavior.
-rw-r--r-- | compile.c | 6 | ||||
-rw-r--r-- | prism_compile.c | 68 | ||||
-rw-r--r-- | test/ruby/test_compile_prism.rb | 27 |
3 files changed, 75 insertions, 26 deletions
@@ -5274,7 +5274,6 @@ compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs int llen = 0; int lpos = 0; - int expand = 1; while (lhsn_count) { llen++; @@ -5312,7 +5311,6 @@ compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs } } - if (!state->nested) { NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn)); } @@ -5320,9 +5318,7 @@ compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs if (!popped) { ADD_INSN(rhs, node, dup); } - if (expand) { - ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat)); - } + ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat)); return COMPILE_OK; } diff --git a/prism_compile.c b/prism_compile.c index 4350a346e3..ba59e6f04d 100644 --- a/prism_compile.c +++ b/prism_compile.c @@ -2925,42 +2925,53 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, } case PM_MULTI_TARGET_NODE: { pm_multi_target_node_t *cast = (pm_multi_target_node_t *) node; - for (size_t index = 0; index < cast->lefts.size; index++) { - PM_COMPILE(cast->lefts.nodes[index]); + + if (cast->lefts.size) { + int flag = (int) (bool) cast->rights.size; + ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(cast->lefts.size), INT2FIX(flag)); + for (size_t index = 0; index < cast->lefts.size; index++) { + PM_COMPILE_NOT_POPPED(cast->lefts.nodes[index]); + } + } + + if (cast->rights.size) { + ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(cast->rights.size), INT2FIX(2)); + for (size_t index = 0; index < cast->rights.size; index++) { + PM_COMPILE_NOT_POPPED(cast->rights.nodes[index]); + } } return; } case PM_MULTI_WRITE_NODE: { pm_multi_write_node_t *multi_write_node = (pm_multi_write_node_t *)node; - pm_node_list_t *node_list = &multi_write_node->lefts; + pm_node_list_t *lefts = &multi_write_node->lefts; + pm_node_list_t *rights = &multi_write_node->rights; // pre-process the left hand side of multi-assignments. uint8_t pushed = 0; - for (size_t index = 0; index < node_list->size; index++) { - pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, node_list->nodes[index], ret, scope_node, pushed, false); + for (size_t index = 0; index < lefts->size; index++) { + pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, lefts->nodes[index], ret, scope_node, pushed, false); } PM_COMPILE_NOT_POPPED(multi_write_node->value); - - // TODO: int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00); - int flag = 0x00; - PM_DUP_UNLESS_POPPED; - ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(node_list->size), INT2FIX(flag)); - for (size_t index = 0; index < node_list->size; index++) { - pm_node_t *considered_node = node_list->nodes[index]; + if (lefts->size) { + ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(lefts->size), INT2FIX((int) (bool) rights->size)); + for (size_t index = 0; index < lefts->size; index++) { + pm_node_t *considered_node = lefts->nodes[index]; - if (PM_NODE_TYPE_P(considered_node, PM_CONSTANT_PATH_TARGET_NODE) && pushed > 0) { - pm_constant_path_target_node_t *cast = (pm_constant_path_target_node_t *) considered_node; - ID name = pm_constant_id_lookup(scope_node, ((pm_constant_read_node_t * ) cast->child)->name); + if (PM_NODE_TYPE_P(considered_node, PM_CONSTANT_PATH_TARGET_NODE) && pushed > 0) { + pm_constant_path_target_node_t *cast = (pm_constant_path_target_node_t *) considered_node; + ID name = pm_constant_id_lookup(scope_node, ((pm_constant_read_node_t * ) cast->child)->name); - pushed -= 2; + pushed -= 2; - ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(pushed)); - ADD_INSN1(ret, &dummy_line_node, setconstant, ID2SYM(name)); - } else { - PM_COMPILE(node_list->nodes[index]); + ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(pushed)); + ADD_INSN1(ret, &dummy_line_node, setconstant, ID2SYM(name)); + } else { + PM_COMPILE(lefts->nodes[index]); + } } } @@ -2971,6 +2982,23 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, } } + if (multi_write_node->rest) { + RUBY_ASSERT(PM_NODE_TYPE_P(multi_write_node->rest, PM_SPLAT_NODE)); + + pm_splat_node_t *rest_splat = ((pm_splat_node_t *)multi_write_node->rest); + if (rest_splat->expression) { + ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(0), INT2FIX(1)); + PM_COMPILE(rest_splat->expression); + } + } + + if (rights->size) { + ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(rights->size), INT2FIX(2)); + for (size_t index = 0; index < rights->size; index++) { + PM_COMPILE(rights->nodes[index]); + } + } + return; } case PM_NEXT_NODE: { diff --git a/test/ruby/test_compile_prism.rb b/test/ruby/test_compile_prism.rb index 900c868f4c..911b126e73 100644 --- a/test/ruby/test_compile_prism.rb +++ b/test/ruby/test_compile_prism.rb @@ -330,8 +330,33 @@ module Prism assert_prism_eval("pit, pit1 = 1") end + def test_MultiTargetNode + assert_prism_eval("a, (b, c) = [1, 2, 3]") + assert_prism_eval("a, (b, c) = [1, 2, 3]; a") + assert_prism_eval("a, (b, c) = [1, 2, 3]; b") + assert_prism_eval("a, (b, c) = [1, 2, 3]; c") + assert_prism_eval("a, (b, c) = [1, [2, 3]]; c") + assert_prism_eval("(a, (b, c, d, e), f, g), h = [1, [2, 3]], 4, 5, [6, 7]; c") + end + def test_MultiWriteNode - assert_prism_eval("foo, bar = [1,2]") + assert_prism_eval("foo, bar = [1, 2]") + assert_prism_eval("foo, *, bar = [1, 2]") + assert_prism_eval("foo, bar = 1, 2") + assert_prism_eval("foo, *, bar = 1, 2") + assert_prism_eval("foo, *, bar = 1, 2, 3, 4") + assert_prism_eval("a, b, *, d = 1, 2, 3, 4") + assert_prism_eval("a, b, *, d = 1, 2") + assert_prism_eval("(a, b), *, c = [1, 3], 4, 5") + assert_prism_eval("(a, b), *, c = [1, 3], 4, 5; a") + assert_prism_eval("(a, b), *, c = [1, 3], 4, 5; b") + assert_prism_eval("(a, b), *, c = [1, 3], 4, 5; c") + assert_prism_eval("a, *, (c, d) = [1, 3], 4, 5; a") + assert_prism_eval("a, *, (c, d) = [1, 3], 4, 5; c") + assert_prism_eval("(a, b, c), *, (d, e) = [1, 3], 4, 5, [6, 7]") + assert_prism_eval("(a, b, c), *, (d, e) = [1, 3], 4, 5, [6, 7]; b") + assert_prism_eval("(a, b, c), *, (d, e) = [1, 3], 4, 5, [6, 7]; d") + assert_prism_eval("((a, *, b), *, (c, *, (d, *, e, f, g))), *, ((h, i, *, j), *, (k, l, m, *, n, o, p), q, r) = 1; a") end ############################################################################ |