From 5dfba84cffd149c97e1cb7a1cb3e40869e127c5f Mon Sep 17 00:00:00 2001 From: Matt Valentine-House Date: Fri, 20 Oct 2023 10:59:02 +0100 Subject: [Prism] Compile ForNode Fixes ruby/prism#1648 --- compile.c | 8 ++++++- prism_compile.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/compile.c b/compile.c index 1c3bdde9a2..b7a9a1cccb 100644 --- a/compile.c +++ b/compile.c @@ -984,8 +984,14 @@ rb_iseq_compile_prism_node(rb_iseq_t * iseq, pm_scope_node_t *scope_node, pm_par constants[index] = rb_intern3((const char *) constant->start, constant->length, encoding); } - scope_node->constants = constants; + st_table *index_lookup_table = st_init_numtable(); + pm_constant_id_list_t *locals = &scope_node->locals; + for (size_t i = 0; i < locals->size; i++) { + st_insert(index_lookup_table, locals->ids[i], i); + } + scope_node->constants = (void *)constants; + scope_node->index_lookup_table = index_lookup_table; CHECK(rb_translate_prism(iseq, scope_node, ret)); free(constants); diff --git a/prism_compile.c b/prism_compile.c index 86c29ed5f0..9e65111c76 100644 --- a/prism_compile.c +++ b/prism_compile.c @@ -48,6 +48,8 @@ #define PM_SWAP_UNLESS_POPPED \ if (!popped) PM_SWAP; +#define TEMP_CONSTANT_IDENTIFIER ((pm_constant_id_t)(1 << 31)) + rb_iseq_t * pm_iseq_new_with_opt(pm_scope_node_t *scope_node, pm_parser_t *parser, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth, @@ -2006,6 +2008,48 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, } return; } + case PM_FOR_NODE: { + pm_for_node_t *for_node = (pm_for_node_t *)node; + + const rb_iseq_t *child_iseq; + const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block; + + LABEL *retry_label = NEW_LABEL(lineno); + LABEL *retry_end_l = NEW_LABEL(lineno); + + pm_scope_node_t next_scope_node; + pm_scope_node_init((pm_node_t *)for_node, &next_scope_node, scope_node, parser); + + pm_constant_id_list_t locals; + pm_constant_id_list_init(&locals); + pm_constant_id_list_append(&locals, TEMP_CONSTANT_IDENTIFIER); + next_scope_node.locals = locals; + + ADD_LABEL(ret, retry_label); + + PM_COMPILE(for_node->collection); + child_iseq = NEW_CHILD_ISEQ(next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno); + ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq; + ADD_SEND_WITH_BLOCK(ret, &dummy_line_node, idEach, INT2FIX(0), child_iseq); + + INSN *iobj; + LINK_ELEMENT *last_elem = LAST_ELEMENT(ret); + iobj = IS_INSN(last_elem) ? (INSN *)last_elem : (INSN *)get_prev_insn((INSN*)last_elem); + while (INSN_OF(iobj) != BIN(send) && + INSN_OF(iobj) != BIN(invokesuper)) { + iobj = (INSN *)get_prev_insn(iobj); + } + ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*)retry_end_l); + + if (popped) { + ADD_INSN(ret, &dummy_line_node, pop); + } + + ISEQ_COMPILE_DATA(iseq)->current_block = prevblock; + ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l); + + return; + } case PM_GLOBAL_VARIABLE_AND_WRITE_NODE: { pm_global_variable_and_write_node_t *global_variable_and_write_node = (pm_global_variable_and_write_node_t*) node; @@ -2494,6 +2538,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, pm_local_variable_target_node_t *local_write_node = (pm_local_variable_target_node_t *) node; pm_constant_id_t constant_id = local_write_node->name; + for (size_t index = 0; index < local_write_node->depth; index++) scope_node = scope_node->previous; int index = pm_lookup_local_index(iseq, scope_node, constant_id); ADD_SETLOCAL(ret, &dummy_line_node, (int)index, local_write_node->depth); @@ -2879,12 +2924,18 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, pm_constant_id_list_t locals = scope_node->locals; pm_parameters_node_t *parameters_node = (pm_parameters_node_t *)scope_node->parameters; - pm_node_list_t requireds_list = PM_EMPTY_NODE_LIST; pm_node_list_t optionals_list = PM_EMPTY_NODE_LIST; if (parameters_node) { - requireds_list = parameters_node->requireds; optionals_list = parameters_node->optionals; + ISEQ_BODY(iseq)->param.lead_num = (int) parameters_node->requireds.size; + ISEQ_BODY(iseq)->param.opt_num = (int) optionals_list.size; + } else if (PM_NODE_TYPE_P(scope_node->ast_node, PM_FOR_NODE)) { + ISEQ_BODY(iseq)->param.lead_num = 1; + ISEQ_BODY(iseq)->param.opt_num = 0; + } else { + ISEQ_BODY(iseq)->param.lead_num = 0; + ISEQ_BODY(iseq)->param.opt_num = 0; } size_t size = locals.size; @@ -2898,15 +2949,18 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, for (size_t i = 0; i < size; i++) { pm_constant_id_t constant_id = locals.ids[i]; - ID local = pm_constant_id_lookup(scope_node, constant_id); + ID local; + if (constant_id & TEMP_CONSTANT_IDENTIFIER) { + local = rb_make_temporary_id(i); + } else { + local = pm_constant_id_lookup(scope_node, constant_id); + } tbl->ids[i] = local; st_insert(index_lookup_table, constant_id, i); } scope_node->index_lookup_table = index_lookup_table; - ISEQ_BODY(iseq)->param.lead_num = (int)requireds_list.size; - ISEQ_BODY(iseq)->param.opt_num = (int)optionals_list.size; // TODO: Set all the other nums (good comment by lead_num illustrating what they are) ISEQ_BODY(iseq)->param.size = (unsigned int)size; @@ -2951,7 +3005,15 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, ADD_LABEL(ret, start); if (scope_node->body) { - PM_COMPILE((pm_node_t *)scope_node->body); + if (PM_NODE_TYPE_P(scope_node->ast_node, PM_FOR_NODE)) { + pm_for_node_t *for_node = (pm_for_node_t *)scope_node->ast_node; + + ADD_GETLOCAL(ret, &dummy_line_node, 1, 0); + pm_compile_node(iseq, for_node->index, ret, src, popped, scope_node); + ADD_INSN(ret, &dummy_line_node, nop); + } + + pm_compile_node(iseq, (pm_node_t *)(scope_node->body), ret, src, popped, scope_node); } else { PM_PUTNIL; -- cgit v1.2.3