From 5b6a4d8c1253fd1ab77c0539d33276fe1856cf24 Mon Sep 17 00:00:00 2001 From: Matt Valentine-House Date: Wed, 13 Dec 2023 21:09:39 +0000 Subject: [PATCH] [PRISM] Compile IndexTargetNode --- prism_compile.c | 61 ++++++++++++++++++++++++++++----- test/ruby/test_compile_prism.rb | 5 +++ 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/prism_compile.c b/prism_compile.c index e99218ed60..a7c50f389b 100644 --- a/prism_compile.c +++ b/prism_compile.c @@ -1210,13 +1210,26 @@ pm_compile_index_and_or_write_node(bool and_node, pm_node_t *receiver, pm_node_t * path). */ static uint8_t -pm_compile_multi_write_lhs(rb_iseq_t *iseq, NODE dummy_line_node, const pm_node_t *node, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node, uint8_t pushed, bool nested) +pm_compile_multi_write_lhs(rb_iseq_t *iseq, NODE dummy_line_node, const uint8_t *src, bool popped, const pm_node_t *node, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node, uint8_t pushed, bool nested) { switch (PM_NODE_TYPE(node)) { + case PM_INDEX_TARGET_NODE: { + pm_index_target_node_t *cast = (pm_index_target_node_t *)node; + PM_COMPILE_NOT_POPPED((pm_node_t *)cast->receiver); + pushed++; + + if (cast->arguments) { + for (size_t i = 0; i < cast->arguments->arguments.size; i++) { + PM_COMPILE_NOT_POPPED((pm_node_t *)cast->arguments->arguments.nodes[i]); + } + pushed += cast->arguments->arguments.size; + } + break; + } 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++) { - pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, cast->lefts.nodes[index], ret, scope_node, pushed, false); + pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, src, popped, cast->lefts.nodes[index], ret, scope_node, pushed, false); } break; } @@ -1224,7 +1237,7 @@ pm_compile_multi_write_lhs(rb_iseq_t *iseq, NODE dummy_line_node, const pm_node_ pm_constant_path_target_node_t *cast = (pm_constant_path_target_node_t *)node; if (cast->parent) { PM_PUTNIL; - pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, cast->parent, ret, scope_node, pushed, false); + pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, src, popped, cast->parent, ret, scope_node, pushed, false); } else { ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject); } @@ -1233,12 +1246,12 @@ pm_compile_multi_write_lhs(rb_iseq_t *iseq, NODE dummy_line_node, const pm_node_ case PM_CONSTANT_PATH_NODE: { pm_constant_path_node_t *cast = (pm_constant_path_node_t *) node; if (cast->parent) { - pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, cast->parent, ret, scope_node, pushed, false); + pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, src, popped, cast->parent, ret, scope_node, pushed, false); } else { PM_POP; ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject); } - pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, cast->child, ret, scope_node, pushed, cast->parent); + pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, src, popped, cast->child, ret, scope_node, pushed, cast->parent); break; } case PM_CONSTANT_READ_NODE: { @@ -4927,11 +4940,12 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, pm_multi_write_node_t *multi_write_node = (pm_multi_write_node_t *)node; pm_node_list_t *lefts = &multi_write_node->lefts; pm_node_list_t *rights = &multi_write_node->rights; + size_t argc = 0; // pre-process the left hand side of multi-assignments. uint8_t pushed = 0; 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); + pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, src, popped, lefts->nodes[index], ret, scope_node, pushed, false); } PM_COMPILE_NOT_POPPED(multi_write_node->value); @@ -4943,6 +4957,9 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, rest_expression = rest_splat->expression; } + size_t remainder = pushed; + if (popped) remainder--; + if (lefts->size) { ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(lefts->size), INT2FIX((int) (bool) (rights->size || rest_expression))); for (size_t index = 0; index < lefts->size; index++) { @@ -4956,15 +4973,41 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(pushed)); ADD_INSN1(ret, &dummy_line_node, setconstant, ID2SYM(name)); + } else if (PM_NODE_TYPE_P(considered_node, PM_INDEX_TARGET_NODE)) { + pm_index_target_node_t *cast = (pm_index_target_node_t *)considered_node; + + if (cast->arguments) { + pm_arguments_node_t *args = (pm_arguments_node_t *)cast->arguments; + argc = args->arguments.size + 1; + } + + if (argc == 1) { + ADD_INSN(ret, &dummy_line_node, swap); + } + else { + VALUE vals = INT2FIX(remainder + (lefts->size - index)); + ADD_INSN1(ret, &dummy_line_node, topn, vals); + for (size_t i = 1; i < argc; i++) { + ADD_INSN1(ret, &dummy_line_node, topn, vals); + } + ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(argc)); + } + + ADD_SEND(ret, &dummy_line_node, idASET, INT2FIX(argc)); + PM_POP; + PM_POP; + remainder -= argc; } else { PM_COMPILE(lefts->nodes[index]); } } } - if (pushed) { - ADD_INSN1(ret, &dummy_line_node, setn, INT2FIX(pushed)); - for (uint8_t index = 0; index < pushed; index++) { + if ((pushed)) { + if (!popped) { + ADD_INSN1(ret, &dummy_line_node, setn, INT2FIX(pushed)); + } + for (uint8_t index = 0; index < (pushed); index++) { PM_POP; } } diff --git a/test/ruby/test_compile_prism.rb b/test/ruby/test_compile_prism.rb index fc563951f6..28adbe0916 100644 --- a/test/ruby/test_compile_prism.rb +++ b/test/ruby/test_compile_prism.rb @@ -529,6 +529,11 @@ module Prism 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") + assert_prism_eval("_, {}[:foo] = 1") + assert_prism_eval("_, {}[:foo], _ = 1") + assert_prism_eval("_, {}[:foo], _ = 1") + assert_prism_eval("_,{}[:foo], _, {}[:bar] = 1") + end ############################################################################