[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.
This commit is contained in:
Jemma Issroff 2023-11-01 15:22:08 -03:00
parent 4a6bdbd6dc
commit f6ba87ca88
3 changed files with 75 additions and 26 deletions

View File

@ -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;
}

View File

@ -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: {

View File

@ -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
############################################################################