Skip to content

Commit f6ba87c

Browse files
committed
[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.
1 parent 4a6bdbd commit f6ba87c

File tree

3 files changed

+75
-26
lines changed

3 files changed

+75
-26
lines changed

compile.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5274,7 +5274,6 @@ compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs
52745274

52755275
int llen = 0;
52765276
int lpos = 0;
5277-
int expand = 1;
52785277

52795278
while (lhsn_count) {
52805279
llen++;
@@ -5312,17 +5311,14 @@ compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs
53125311
}
53135312
}
53145313

5315-
53165314
if (!state->nested) {
53175315
NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
53185316
}
53195317

53205318
if (!popped) {
53215319
ADD_INSN(rhs, node, dup);
53225320
}
5323-
if (expand) {
5324-
ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5325-
}
5321+
ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
53265322
return COMPILE_OK;
53275323
}
53285324

prism_compile.c

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2925,42 +2925,53 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
29252925
}
29262926
case PM_MULTI_TARGET_NODE: {
29272927
pm_multi_target_node_t *cast = (pm_multi_target_node_t *) node;
2928-
for (size_t index = 0; index < cast->lefts.size; index++) {
2929-
PM_COMPILE(cast->lefts.nodes[index]);
2928+
2929+
if (cast->lefts.size) {
2930+
int flag = (int) (bool) cast->rights.size;
2931+
ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(cast->lefts.size), INT2FIX(flag));
2932+
for (size_t index = 0; index < cast->lefts.size; index++) {
2933+
PM_COMPILE_NOT_POPPED(cast->lefts.nodes[index]);
2934+
}
2935+
}
2936+
2937+
if (cast->rights.size) {
2938+
ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(cast->rights.size), INT2FIX(2));
2939+
for (size_t index = 0; index < cast->rights.size; index++) {
2940+
PM_COMPILE_NOT_POPPED(cast->rights.nodes[index]);
2941+
}
29302942
}
29312943
return;
29322944
}
29332945
case PM_MULTI_WRITE_NODE: {
29342946
pm_multi_write_node_t *multi_write_node = (pm_multi_write_node_t *)node;
2935-
pm_node_list_t *node_list = &multi_write_node->lefts;
2947+
pm_node_list_t *lefts = &multi_write_node->lefts;
2948+
pm_node_list_t *rights = &multi_write_node->rights;
29362949

29372950
// pre-process the left hand side of multi-assignments.
29382951
uint8_t pushed = 0;
2939-
for (size_t index = 0; index < node_list->size; index++) {
2940-
pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, node_list->nodes[index], ret, scope_node, pushed, false);
2952+
for (size_t index = 0; index < lefts->size; index++) {
2953+
pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, lefts->nodes[index], ret, scope_node, pushed, false);
29412954
}
29422955

29432956
PM_COMPILE_NOT_POPPED(multi_write_node->value);
2944-
2945-
// TODO: int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
2946-
int flag = 0x00;
2947-
29482957
PM_DUP_UNLESS_POPPED;
2949-
ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(node_list->size), INT2FIX(flag));
29502958

2951-
for (size_t index = 0; index < node_list->size; index++) {
2952-
pm_node_t *considered_node = node_list->nodes[index];
2959+
if (lefts->size) {
2960+
ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(lefts->size), INT2FIX((int) (bool) rights->size));
2961+
for (size_t index = 0; index < lefts->size; index++) {
2962+
pm_node_t *considered_node = lefts->nodes[index];
29532963

2954-
if (PM_NODE_TYPE_P(considered_node, PM_CONSTANT_PATH_TARGET_NODE) && pushed > 0) {
2955-
pm_constant_path_target_node_t *cast = (pm_constant_path_target_node_t *) considered_node;
2956-
ID name = pm_constant_id_lookup(scope_node, ((pm_constant_read_node_t * ) cast->child)->name);
2964+
if (PM_NODE_TYPE_P(considered_node, PM_CONSTANT_PATH_TARGET_NODE) && pushed > 0) {
2965+
pm_constant_path_target_node_t *cast = (pm_constant_path_target_node_t *) considered_node;
2966+
ID name = pm_constant_id_lookup(scope_node, ((pm_constant_read_node_t * ) cast->child)->name);
29572967

2958-
pushed -= 2;
2968+
pushed -= 2;
29592969

2960-
ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(pushed));
2961-
ADD_INSN1(ret, &dummy_line_node, setconstant, ID2SYM(name));
2962-
} else {
2963-
PM_COMPILE(node_list->nodes[index]);
2970+
ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(pushed));
2971+
ADD_INSN1(ret, &dummy_line_node, setconstant, ID2SYM(name));
2972+
} else {
2973+
PM_COMPILE(lefts->nodes[index]);
2974+
}
29642975
}
29652976
}
29662977

@@ -2971,6 +2982,23 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
29712982
}
29722983
}
29732984

2985+
if (multi_write_node->rest) {
2986+
RUBY_ASSERT(PM_NODE_TYPE_P(multi_write_node->rest, PM_SPLAT_NODE));
2987+
2988+
pm_splat_node_t *rest_splat = ((pm_splat_node_t *)multi_write_node->rest);
2989+
if (rest_splat->expression) {
2990+
ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(0), INT2FIX(1));
2991+
PM_COMPILE(rest_splat->expression);
2992+
}
2993+
}
2994+
2995+
if (rights->size) {
2996+
ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(rights->size), INT2FIX(2));
2997+
for (size_t index = 0; index < rights->size; index++) {
2998+
PM_COMPILE(rights->nodes[index]);
2999+
}
3000+
}
3001+
29743002
return;
29753003
}
29763004
case PM_NEXT_NODE: {

test/ruby/test_compile_prism.rb

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,33 @@ def test_LocalVariableTargetNode
330330
assert_prism_eval("pit, pit1 = 1")
331331
end
332332

333+
def test_MultiTargetNode
334+
assert_prism_eval("a, (b, c) = [1, 2, 3]")
335+
assert_prism_eval("a, (b, c) = [1, 2, 3]; a")
336+
assert_prism_eval("a, (b, c) = [1, 2, 3]; b")
337+
assert_prism_eval("a, (b, c) = [1, 2, 3]; c")
338+
assert_prism_eval("a, (b, c) = [1, [2, 3]]; c")
339+
assert_prism_eval("(a, (b, c, d, e), f, g), h = [1, [2, 3]], 4, 5, [6, 7]; c")
340+
end
341+
333342
def test_MultiWriteNode
334-
assert_prism_eval("foo, bar = [1,2]")
343+
assert_prism_eval("foo, bar = [1, 2]")
344+
assert_prism_eval("foo, *, bar = [1, 2]")
345+
assert_prism_eval("foo, bar = 1, 2")
346+
assert_prism_eval("foo, *, bar = 1, 2")
347+
assert_prism_eval("foo, *, bar = 1, 2, 3, 4")
348+
assert_prism_eval("a, b, *, d = 1, 2, 3, 4")
349+
assert_prism_eval("a, b, *, d = 1, 2")
350+
assert_prism_eval("(a, b), *, c = [1, 3], 4, 5")
351+
assert_prism_eval("(a, b), *, c = [1, 3], 4, 5; a")
352+
assert_prism_eval("(a, b), *, c = [1, 3], 4, 5; b")
353+
assert_prism_eval("(a, b), *, c = [1, 3], 4, 5; c")
354+
assert_prism_eval("a, *, (c, d) = [1, 3], 4, 5; a")
355+
assert_prism_eval("a, *, (c, d) = [1, 3], 4, 5; c")
356+
assert_prism_eval("(a, b, c), *, (d, e) = [1, 3], 4, 5, [6, 7]")
357+
assert_prism_eval("(a, b, c), *, (d, e) = [1, 3], 4, 5, [6, 7]; b")
358+
assert_prism_eval("(a, b, c), *, (d, e) = [1, 3], 4, 5, [6, 7]; d")
359+
assert_prism_eval("((a, *, b), *, (c, *, (d, *, e, f, g))), *, ((h, i, *, j), *, (k, l, m, *, n, o, p), q, r) = 1; a")
335360
end
336361

337362
############################################################################

0 commit comments

Comments
 (0)