[PRISM] Better handle interpolated* nodes with inner frozen parts

This commit is contained in:
Kevin Newton 2024-03-26 09:58:24 -04:00
parent 8ec7c3ce30
commit 4300c42a7e

View File

@ -129,7 +129,8 @@ parse_integer(const pm_integer_node_t *node)
if (integer->values == NULL) { if (integer->values == NULL) {
result = UINT2NUM(integer->value); result = UINT2NUM(integer->value);
} else { }
else {
VALUE string = rb_str_new(NULL, integer->length * 8); VALUE string = rb_str_new(NULL, integer->length * 8);
unsigned char *bytes = (unsigned char *) RSTRING_PTR(string); unsigned char *bytes = (unsigned char *) RSTRING_PTR(string);
@ -251,9 +252,11 @@ parse_string_encoded(const pm_scope_node_t *scope_node, const pm_node_t *node, c
if (node->flags & PM_ENCODING_FLAGS_FORCED_BINARY_ENCODING) { if (node->flags & PM_ENCODING_FLAGS_FORCED_BINARY_ENCODING) {
encoding = rb_ascii8bit_encoding(); encoding = rb_ascii8bit_encoding();
} else if (node->flags & PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING) { }
else if (node->flags & PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING) {
encoding = rb_utf8_encoding(); encoding = rb_utf8_encoding();
} else { }
else {
encoding = scope_node->encoding; encoding = scope_node->encoding;
} }
@ -335,21 +338,21 @@ pm_reg_flags(const pm_node_t *node) {
} }
static rb_encoding * static rb_encoding *
pm_reg_enc(const pm_scope_node_t *scope_node, const pm_regular_expression_node_t *node) pm_reg_enc(const pm_scope_node_t *scope_node, const pm_node_t *node)
{ {
if (node->base.flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) { if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) {
return rb_ascii8bit_encoding(); return rb_ascii8bit_encoding();
} }
if (node->base.flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) { if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EUC_JP)) {
return rb_enc_get_from_index(ENCINDEX_EUC_JP); return rb_enc_get_from_index(ENCINDEX_EUC_JP);
} }
if (node->base.flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) { if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J)) {
return rb_enc_get_from_index(ENCINDEX_Windows_31J); return rb_enc_get_from_index(ENCINDEX_Windows_31J);
} }
if (node->base.flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) { if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_UTF_8)) {
return rb_utf8_encoding(); return rb_utf8_encoding();
} }
@ -368,12 +371,12 @@ pm_static_literal_p(const pm_node_t *node)
} }
static VALUE static VALUE
pm_new_regex(const pm_scope_node_t *scope_node, const pm_regular_expression_node_t *node) pm_new_regex(const pm_scope_node_t *scope_node, const pm_node_t *node, const pm_string_t *unescaped)
{ {
VALUE regex_str = parse_string(scope_node, &node->unescaped); VALUE regex_str = parse_string(scope_node, unescaped);
rb_encoding *enc = pm_reg_enc(scope_node, node); rb_encoding *enc = pm_reg_enc(scope_node, node);
VALUE regex = rb_enc_reg_new(RSTRING_PTR(regex_str), RSTRING_LEN(regex_str), enc, pm_reg_flags((const pm_node_t *) node)); VALUE regex = rb_enc_reg_new(RSTRING_PTR(regex_str), RSTRING_LEN(regex_str), enc, pm_reg_flags(node));
RB_GC_GUARD(regex_str); RB_GC_GUARD(regex_str);
rb_obj_freeze(regex); rb_obj_freeze(regex);
@ -381,12 +384,44 @@ pm_new_regex(const pm_scope_node_t *scope_node, const pm_regular_expression_node
return regex; return regex;
} }
static VALUE
pm_static_literal_concat(const pm_node_list_t *nodes, const pm_scope_node_t *scope_node, bool top)
{
VALUE current = Qnil;
for (size_t index = 0; index < nodes->size; index++) {
const pm_node_t *part = nodes->nodes[index];
VALUE string;
switch (PM_NODE_TYPE(part)) {
case PM_STRING_NODE:
string = parse_string_encoded(scope_node, part, &((const pm_string_node_t *) part)->unescaped);
break;
case PM_INTERPOLATED_STRING_NODE:
string = pm_static_literal_concat(&((const pm_interpolated_string_node_t *) part)->parts, scope_node, false);
break;
default:
RUBY_ASSERT(false && "unexpected node type in pm_static_literal_concat");
return Qnil;
}
if (current != Qnil) {
current = rb_str_concat(current, string);
}
else {
current = string;
}
}
return top ? rb_fstring(current) : current;
}
/** /**
* Certain nodes can be compiled literally. This function returns the literal * Certain nodes can be compiled literally. This function returns the literal
* value described by the given node. For example, an array node with all static * value described by the given node. For example, an array node with all static
* literal values can be compiled into a literal array. * literal values can be compiled into a literal array.
*/ */
static inline VALUE static VALUE
pm_static_literal_value(const pm_node_t *node, const pm_scope_node_t *scope_node) pm_static_literal_value(const pm_node_t *node, const pm_scope_node_t *scope_node)
{ {
// Every node that comes into this function should already be marked as // Every node that comes into this function should already be marked as
@ -433,12 +468,40 @@ pm_static_literal_value(const pm_node_t *node, const pm_scope_node_t *scope_node
return parse_imaginary((pm_imaginary_node_t *) node); return parse_imaginary((pm_imaginary_node_t *) node);
case PM_INTEGER_NODE: case PM_INTEGER_NODE:
return parse_integer((const pm_integer_node_t *) node); return parse_integer((const pm_integer_node_t *) node);
case PM_INTERPOLATED_MATCH_LAST_LINE_NODE: {
const pm_interpolated_match_last_line_node_t *cast = (const pm_interpolated_match_last_line_node_t *) node;
VALUE string = pm_static_literal_concat(&cast->parts, scope_node, true);
rb_encoding *encoding = pm_reg_enc(scope_node, (const pm_node_t *) cast);
return rb_obj_freeze(rb_enc_reg_new(RSTRING_PTR(string), RSTRING_LEN(string), encoding, pm_reg_flags((const pm_node_t *) cast)));
}
case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: {
const pm_interpolated_regular_expression_node_t *cast = (const pm_interpolated_regular_expression_node_t *) node;
VALUE string = pm_static_literal_concat(&cast->parts, scope_node, true);
rb_encoding *encoding = pm_reg_enc(scope_node, (const pm_node_t *) cast);
return rb_obj_freeze(rb_enc_reg_new(RSTRING_PTR(string), RSTRING_LEN(string), encoding, pm_reg_flags((const pm_node_t *) cast)));
}
case PM_INTERPOLATED_STRING_NODE:
return pm_static_literal_concat(&((const pm_interpolated_string_node_t *) node)->parts, scope_node, true);
case PM_INTERPOLATED_SYMBOL_NODE: {
const pm_interpolated_symbol_node_t *cast = (const pm_interpolated_symbol_node_t *) node;
VALUE string = pm_static_literal_concat(&cast->parts, scope_node, true);
return ID2SYM(rb_intern_str(string));
}
case PM_MATCH_LAST_LINE_NODE: {
const pm_match_last_line_node_t *cast = (const pm_match_last_line_node_t *) node;
return pm_new_regex(scope_node, (const pm_node_t *) cast, &cast->unescaped);
}
case PM_NIL_NODE: case PM_NIL_NODE:
return Qnil; return Qnil;
case PM_RATIONAL_NODE: case PM_RATIONAL_NODE:
return parse_rational((const pm_rational_node_t *) node); return parse_rational((const pm_rational_node_t *) node);
case PM_REGULAR_EXPRESSION_NODE: case PM_REGULAR_EXPRESSION_NODE: {
return pm_new_regex(scope_node, (const pm_regular_expression_node_t *) node); const pm_regular_expression_node_t *cast = (const pm_regular_expression_node_t *) node;
return pm_new_regex(scope_node, (const pm_node_t *) cast, &cast->unescaped);
}
case PM_SOURCE_ENCODING_NODE: case PM_SOURCE_ENCODING_NODE:
return rb_enc_from_encoding(scope_node->encoding); return rb_enc_from_encoding(scope_node->encoding);
case PM_SOURCE_FILE_NODE: { case PM_SOURCE_FILE_NODE: {
@ -757,7 +820,8 @@ pm_compile_loop(rb_iseq_t *iseq, const pm_line_column_t *line_column, pm_node_fl
PUSH_LABEL(ret, next_label); PUSH_LABEL(ret, next_label);
if (type == PM_WHILE_NODE) { if (type == PM_WHILE_NODE) {
pm_compile_branch_condition(iseq, ret, predicate, redo_label, end_label, popped, scope_node); pm_compile_branch_condition(iseq, ret, predicate, redo_label, end_label, popped, scope_node);
} else if (type == PM_UNTIL_NODE) { }
else if (type == PM_UNTIL_NODE) {
pm_compile_branch_condition(iseq, ret, predicate, end_label, redo_label, popped, scope_node); pm_compile_branch_condition(iseq, ret, predicate, end_label, redo_label, popped, scope_node);
} }
@ -779,7 +843,7 @@ pm_compile_loop(rb_iseq_t *iseq, const pm_line_column_t *line_column, pm_node_fl
} }
static int static int
pm_interpolated_node_compile(pm_node_list_t *parts, rb_iseq_t *iseq, NODE dummy_line_node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node) pm_interpolated_node_compile(const pm_node_list_t *parts, rb_iseq_t *iseq, NODE dummy_line_node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
{ {
int number_of_items_pushed = 0; int number_of_items_pushed = 0;
size_t parts_size = parts->size; size_t parts_size = parts->size;
@ -787,44 +851,6 @@ pm_interpolated_node_compile(pm_node_list_t *parts, rb_iseq_t *iseq, NODE dummy_
if (parts_size > 0) { if (parts_size > 0) {
VALUE current_string = Qnil; VALUE current_string = Qnil;
bool literal = true;
for (size_t index = 0; index < parts_size; index++) {
const pm_node_t *part = parts->nodes[index];
if (!PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
literal = false;
break;
}
}
if (literal) {
for (size_t index = 0; index < parts_size; index++) {
const pm_node_t *part = parts->nodes[index];
const pm_string_node_t *string_node = (const pm_string_node_t *)part;
VALUE string_value = parse_string_encoded(scope_node, (pm_node_t *)string_node, &string_node->unescaped);
if (RTEST(current_string)) {
current_string = rb_str_concat(current_string, string_value);
}
else {
current_string = string_value;
}
}
const pm_node_t *part = parts->nodes[0];
current_string = rb_fstring(current_string);
if (PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
ADD_INSN1(ret, &dummy_line_node, putobject, current_string);
}
else if (PM_NODE_FLAG_P(part, PM_STRING_FLAGS_MUTABLE)) {
ADD_INSN1(ret, &dummy_line_node, putstring, current_string);
}
else {
ADD_INSN1(ret, &dummy_line_node, putchilledstring, current_string);
}
return 1;
}
for (size_t index = 0; index < parts_size; index++) { for (size_t index = 0; index < parts_size; index++) {
const pm_node_t *part = parts->nodes[index]; const pm_node_t *part = parts->nodes[index];
@ -882,6 +908,7 @@ pm_interpolated_node_compile(pm_node_list_t *parts, rb_iseq_t *iseq, NODE dummy_
else { else {
PM_PUTNIL; PM_PUTNIL;
} }
return number_of_items_pushed; return number_of_items_pushed;
} }
@ -904,7 +931,8 @@ pm_lookup_local_index(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, pm_con
if (scope_node->previous) { if (scope_node->previous) {
scope_node = scope_node->previous; scope_node = scope_node->previous;
} else { }
else {
// We have recursed up all scope nodes // We have recursed up all scope nodes
// and have not found the local yet // and have not found the local yet
rb_bug("Local with constant_id %u does not exist", (unsigned int) constant_id); rb_bug("Local with constant_id %u does not exist", (unsigned int) constant_id);
@ -1213,7 +1241,8 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
} }
RUBY_ASSERT(keyword_index == size); RUBY_ASSERT(keyword_index == size);
} else { }
else {
// If they aren't all symbol keys then we need to // If they aren't all symbol keys then we need to
// construct a new hash and pass that as an argument. // construct a new hash and pass that as an argument.
orig_argc++; orig_argc++;
@ -1819,7 +1848,8 @@ pm_compile_pattern_deconstruct(rb_iseq_t *iseq, pm_scope_node_t *scope_node, con
ADD_INSN(ret, &line.node, pop); ADD_INSN(ret, &line.node, pop);
ADD_INSN1(ret, &line.node, topn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE - 1)); ADD_INSN1(ret, &line.node, topn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE - 1));
ADD_INSNL(ret, &line.node, jump, deconstructed_label); ADD_INSNL(ret, &line.node, jump, deconstructed_label);
} else { }
else {
ADD_INSNL(ret, &line.node, jump, deconstruct_label); ADD_INSNL(ret, &line.node, jump, deconstruct_label);
} }
@ -2006,7 +2036,8 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
ADD_INSN1(ret, &line.node, setn, INT2FIX(4)); ADD_INSN1(ret, &line.node, setn, INT2FIX(4));
ADD_SEND(ret, &line.node, idAREF, INT2FIX(2)); ADD_SEND(ret, &line.node, idAREF, INT2FIX(2));
CHECK(pm_compile_pattern_match(iseq, scope_node, ((const pm_splat_node_t *) cast->rest)->expression, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1)); CHECK(pm_compile_pattern_match(iseq, scope_node, ((const pm_splat_node_t *) cast->rest)->expression, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
} else if (posts_size > 0) { }
else if (posts_size > 0) {
ADD_INSN(ret, &line.node, dup); ADD_INSN(ret, &line.node, dup);
ADD_SEND(ret, &line.node, idLength, INT2FIX(0)); ADD_SEND(ret, &line.node, idLength, INT2FIX(0));
ADD_INSN1(ret, &line.node, putobject, INT2FIX(minimum_size)); ADD_INSN1(ret, &line.node, putobject, INT2FIX(minimum_size));
@ -2237,7 +2268,8 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
if (NIL_P(keys)) { if (NIL_P(keys)) {
ADD_INSN(ret, &line.node, putnil); ADD_INSN(ret, &line.node, putnil);
} else { }
else {
ADD_INSN1(ret, &line.node, duparray, keys); ADD_INSN1(ret, &line.node, duparray, keys);
RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys)); RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
} }
@ -2301,7 +2333,8 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
} }
ADD_SEQ(ret, match_values); ADD_SEQ(ret, match_values);
} else { }
else {
ADD_INSN(ret, &line.node, dup); ADD_INSN(ret, &line.node, dup);
ADD_SEND(ret, &line.node, idEmptyP, INT2FIX(0)); ADD_SEND(ret, &line.node, idEmptyP, INT2FIX(0));
if (in_single_pattern) { if (in_single_pattern) {
@ -2516,7 +2549,8 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
RUBY_ASSERT(cast->statements != NULL && cast->statements->body.size == 1); RUBY_ASSERT(cast->statements != NULL && cast->statements->body.size == 1);
statement = cast->statements->body.nodes[0]; statement = cast->statements->body.nodes[0];
} else { }
else {
const pm_unless_node_t *cast = (const pm_unless_node_t *) node; const pm_unless_node_t *cast = (const pm_unless_node_t *) node;
predicate = cast->predicate; predicate = cast->predicate;
@ -2533,7 +2567,8 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
ADD_INSN(ret, &line.node, dup); ADD_INSN(ret, &line.node, dup);
if (PM_NODE_TYPE_P(node, PM_IF_NODE)) { if (PM_NODE_TYPE_P(node, PM_IF_NODE)) {
ADD_INSNL(ret, &line.node, branchif, match_succeeded_label); ADD_INSNL(ret, &line.node, branchif, match_succeeded_label);
} else { }
else {
ADD_INSNL(ret, &line.node, branchunless, match_succeeded_label); ADD_INSNL(ret, &line.node, branchunless, match_succeeded_label);
} }
@ -2550,7 +2585,8 @@ pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t
if (PM_NODE_TYPE_P(node, PM_IF_NODE)) { if (PM_NODE_TYPE_P(node, PM_IF_NODE)) {
ADD_INSNL(ret, &line.node, branchunless, unmatched_label); ADD_INSNL(ret, &line.node, branchunless, unmatched_label);
} else { }
else {
ADD_INSNL(ret, &line.node, branchif, unmatched_label); ADD_INSNL(ret, &line.node, branchif, unmatched_label);
} }
@ -3254,7 +3290,8 @@ pm_compile_destructured_param_locals(const pm_multi_target_node_t *node, st_tabl
pm_insert_local_index(((const pm_required_parameter_node_t *) left)->name, local_index, index_lookup_table, local_table_for_iseq, scope_node); pm_insert_local_index(((const pm_required_parameter_node_t *) left)->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
local_index++; local_index++;
} }
} else { }
else {
RUBY_ASSERT(PM_NODE_TYPE_P(left, PM_MULTI_TARGET_NODE)); RUBY_ASSERT(PM_NODE_TYPE_P(left, PM_MULTI_TARGET_NODE));
local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) left, index_lookup_table, local_table_for_iseq, scope_node, local_index); local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) left, index_lookup_table, local_table_for_iseq, scope_node, local_index);
} }
@ -3276,7 +3313,8 @@ pm_compile_destructured_param_locals(const pm_multi_target_node_t *node, st_tabl
if (PM_NODE_TYPE_P(right, PM_REQUIRED_PARAMETER_NODE)) { if (PM_NODE_TYPE_P(right, PM_REQUIRED_PARAMETER_NODE)) {
pm_insert_local_index(((const pm_required_parameter_node_t *) right)->name, local_index, index_lookup_table, local_table_for_iseq, scope_node); pm_insert_local_index(((const pm_required_parameter_node_t *) right)->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
local_index++; local_index++;
} else { }
else {
RUBY_ASSERT(PM_NODE_TYPE_P(right, PM_MULTI_TARGET_NODE)); RUBY_ASSERT(PM_NODE_TYPE_P(right, PM_MULTI_TARGET_NODE));
local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) right, index_lookup_table, local_table_for_iseq, scope_node, local_index); local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) right, index_lookup_table, local_table_for_iseq, scope_node, local_index);
} }
@ -3324,7 +3362,8 @@ pm_compile_destructured_param_writes(rb_iseq_t *iseq, const pm_multi_target_node
if (PM_NODE_TYPE_P(left, PM_REQUIRED_PARAMETER_NODE)) { if (PM_NODE_TYPE_P(left, PM_REQUIRED_PARAMETER_NODE)) {
pm_compile_destructured_param_write(iseq, (const pm_required_parameter_node_t *) left, ret, scope_node); pm_compile_destructured_param_write(iseq, (const pm_required_parameter_node_t *) left, ret, scope_node);
} else { }
else {
RUBY_ASSERT(PM_NODE_TYPE_P(left, PM_MULTI_TARGET_NODE)); RUBY_ASSERT(PM_NODE_TYPE_P(left, PM_MULTI_TARGET_NODE));
pm_compile_destructured_param_writes(iseq, (const pm_multi_target_node_t *) left, ret, scope_node); pm_compile_destructured_param_writes(iseq, (const pm_multi_target_node_t *) left, ret, scope_node);
} }
@ -3351,7 +3390,8 @@ pm_compile_destructured_param_writes(rb_iseq_t *iseq, const pm_multi_target_node
if (PM_NODE_TYPE_P(right, PM_REQUIRED_PARAMETER_NODE)) { if (PM_NODE_TYPE_P(right, PM_REQUIRED_PARAMETER_NODE)) {
pm_compile_destructured_param_write(iseq, (const pm_required_parameter_node_t *) right, ret, scope_node); pm_compile_destructured_param_write(iseq, (const pm_required_parameter_node_t *) right, ret, scope_node);
} else { }
else {
RUBY_ASSERT(PM_NODE_TYPE_P(right, PM_MULTI_TARGET_NODE)); RUBY_ASSERT(PM_NODE_TYPE_P(right, PM_MULTI_TARGET_NODE));
pm_compile_destructured_param_writes(iseq, (const pm_multi_target_node_t *) right, ret, scope_node); pm_compile_destructured_param_writes(iseq, (const pm_multi_target_node_t *) right, ret, scope_node);
} }
@ -3420,7 +3460,8 @@ pm_multi_target_state_push(pm_multi_target_state_t *state, INSN *topn, size_t st
if (state->head == NULL) { if (state->head == NULL) {
state->head = node; state->head = node;
state->tail = node; state->tail = node;
} else { }
else {
state->tail->next = node; state->tail->next = node;
state->tail = node; state->tail = node;
} }
@ -3585,13 +3626,15 @@ pm_compile_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *cons
if (cast->parent != NULL) { if (cast->parent != NULL) {
pm_compile_node(iseq, cast->parent, parents, false, scope_node); pm_compile_node(iseq, cast->parent, parents, false, scope_node);
} else { }
else {
ADD_INSN1(parents, &dummy_line_node, putobject, rb_cObject); ADD_INSN1(parents, &dummy_line_node, putobject, rb_cObject);
} }
if (state == NULL) { if (state == NULL) {
ADD_INSN(writes, &dummy_line_node, swap); ADD_INSN(writes, &dummy_line_node, swap);
} else { }
else {
ADD_INSN1(writes, &dummy_line_node, topn, INT2FIX(1)); ADD_INSN1(writes, &dummy_line_node, topn, INT2FIX(1));
pm_multi_target_state_push(state, (INSN *) LAST_ELEMENT(writes), 1); pm_multi_target_state_push(state, (INSN *) LAST_ELEMENT(writes), 1);
} }
@ -3660,7 +3703,8 @@ pm_compile_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *cons
if (argc == 0) { if (argc == 0) {
ADD_INSN(writes, &dummy_line_node, swap); ADD_INSN(writes, &dummy_line_node, swap);
} else { }
else {
for (int index = 0; index < argc; index++) { for (int index = 0; index < argc; index++) {
ADD_INSN1(writes, &dummy_line_node, topn, INT2FIX(argc + 1)); ADD_INSN1(writes, &dummy_line_node, topn, INT2FIX(argc + 1));
} }
@ -4529,7 +4573,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
ADD_ADJUST_RESTORE(ret, splabel); ADD_ADJUST_RESTORE(ret, splabel);
PM_PUTNIL_UNLESS_POPPED; PM_PUTNIL_UNLESS_POPPED;
} else { }
else {
const rb_iseq_t *ip = iseq; const rb_iseq_t *ip = iseq;
while (ip) { while (ip) {
@ -4985,7 +5030,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
branch_id++; branch_id++;
if (in_node->statements != NULL) { if (in_node->statements != NULL) {
PM_COMPILE_INTO_ANCHOR(body_seq, (const pm_node_t *) in_node->statements); PM_COMPILE_INTO_ANCHOR(body_seq, (const pm_node_t *) in_node->statements);
} else if (!popped) { }
else if (!popped) {
ADD_INSN(body_seq, &in_line.node, putnil); ADD_INSN(body_seq, &in_line.node, putnil);
} }
@ -5013,7 +5059,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
if (else_node->statements != NULL) { if (else_node->statements != NULL) {
PM_COMPILE_INTO_ANCHOR(cond_seq, (const pm_node_t *) else_node->statements); PM_COMPILE_INTO_ANCHOR(cond_seq, (const pm_node_t *) else_node->statements);
} else if (!popped) { }
else if (!popped) {
ADD_INSN(cond_seq, &dummy_line_node, putnil); ADD_INSN(cond_seq, &dummy_line_node, putnil);
} }
@ -5022,7 +5069,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
if (popped) { if (popped) {
ADD_INSN(cond_seq, &dummy_line_node, putnil); ADD_INSN(cond_seq, &dummy_line_node, putnil);
} }
} else { }
else {
// Otherwise, if we do not have an `else` clause, we will compile in // Otherwise, if we do not have an `else` clause, we will compile in
// the code to handle raising an appropriate error. // the code to handle raising an appropriate error.
ADD_LABEL(cond_seq, else_label); ADD_LABEL(cond_seq, else_label);
@ -5032,7 +5080,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
if (in_single_pattern) { if (in_single_pattern) {
pm_compile_pattern_error_handler(iseq, scope_node, node, cond_seq, end_label, popped); pm_compile_pattern_error_handler(iseq, scope_node, node, cond_seq, end_label, popped);
} else { }
else {
ADD_INSN1(cond_seq, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); ADD_INSN1(cond_seq, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
ADD_INSN1(cond_seq, &dummy_line_node, putobject, rb_eNoMatchingPatternError); ADD_INSN1(cond_seq, &dummy_line_node, putobject, rb_eNoMatchingPatternError);
ADD_INSN1(cond_seq, &dummy_line_node, topn, INT2FIX(2)); ADD_INSN1(cond_seq, &dummy_line_node, topn, INT2FIX(2));
@ -5846,7 +5895,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
ADD_INSN1(ret, &dummy_line_node, duphash, value); ADD_INSN1(ret, &dummy_line_node, duphash, value);
RB_OBJ_WRITTEN(iseq, Qundef, value); RB_OBJ_WRITTEN(iseq, Qundef, value);
} }
} else { }
else {
// Here since we know there are possible side-effects inside the // Here since we know there are possible side-effects inside the
// hash contents, we're going to build it entirely at runtime. We'll // hash contents, we're going to build it entirely at runtime. We'll
// do this by pushing all of the key-value pairs onto the stack and // do this by pushing all of the key-value pairs onto the stack and
@ -6018,71 +6068,114 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
return; return;
} }
case PM_INTERPOLATED_MATCH_LAST_LINE_NODE: { case PM_INTERPOLATED_MATCH_LAST_LINE_NODE: {
pm_interpolated_match_last_line_node_t *cast = (pm_interpolated_match_last_line_node_t *) node; // if /foo #{bar}/ then end
// ^^^^^^^^^^^^
if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
if (!popped) {
VALUE regexp = pm_static_literal_value(node, scope_node);
PUSH_INSN1(ret, location, putobject, regexp);
}
}
else {
const pm_interpolated_match_last_line_node_t *cast = (const pm_interpolated_match_last_line_node_t *) node;
int length = pm_interpolated_node_compile(&cast->parts, iseq, dummy_line_node, ret, popped, scope_node);
PUSH_INSN2(ret, location, toregexp, INT2FIX(pm_reg_flags((const pm_node_t *) cast)), INT2FIX(length));
}
int parts_size = (int)cast->parts.size; PUSH_INSN1(ret, location, getglobal, rb_id2sym(idLASTLINE));
PUSH_SEND(ret, location, idEqTilde, INT2NUM(1));
pm_interpolated_node_compile(&cast->parts, iseq, dummy_line_node, ret, popped, scope_node); if (popped) PUSH_INSN(ret, location, pop);
ADD_INSN2(ret, &dummy_line_node, toregexp, INT2FIX(pm_reg_flags(node)), INT2FIX(parts_size));
ADD_INSN1(ret, &dummy_line_node, getglobal, rb_id2sym(idLASTLINE));
ADD_SEND(ret, &dummy_line_node, idEqTilde, INT2NUM(1));
PM_POP_IF_POPPED;
return; return;
} }
case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: { case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: {
if (node->flags & PM_REGULAR_EXPRESSION_FLAGS_ONCE) { // /foo #{bar}/
// ^^^^^^^^^^^^
if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_ONCE)) {
const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block; const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
const rb_iseq_t *block_iseq = NULL; const rb_iseq_t *block_iseq = NULL;
int ic_index = ISEQ_BODY(iseq)->ise_size++; int ise_index = ISEQ_BODY(iseq)->ise_size++;
pm_scope_node_t next_scope_node; pm_scope_node_t next_scope_node;
pm_scope_node_init((pm_node_t*)node, &next_scope_node, scope_node); pm_scope_node_init(node, &next_scope_node, scope_node);
block_iseq = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
block_iseq = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, location.line);
pm_scope_node_destroy(&next_scope_node); pm_scope_node_destroy(&next_scope_node);
ISEQ_COMPILE_DATA(iseq)->current_block = block_iseq; ISEQ_COMPILE_DATA(iseq)->current_block = block_iseq;
PUSH_INSN2(ret, location, once, block_iseq, INT2FIX(ise_index));
ADD_INSN2(ret, &dummy_line_node, once, block_iseq, INT2FIX(ic_index));
ISEQ_COMPILE_DATA(iseq)->current_block = prevblock; ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
return; return;
} }
pm_interpolated_regular_expression_node_t *cast = (pm_interpolated_regular_expression_node_t *) node; if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
if (!popped) {
VALUE regexp = pm_static_literal_value(node, scope_node);
PUSH_INSN1(ret, location, putobject, regexp);
}
}
else {
const pm_interpolated_regular_expression_node_t *cast = (const pm_interpolated_regular_expression_node_t *) node;
int length = pm_interpolated_node_compile(&cast->parts, iseq, dummy_line_node, ret, popped, scope_node);
int parts_size = pm_interpolated_node_compile(&cast->parts, iseq, dummy_line_node, ret, popped, scope_node); PUSH_INSN2(ret, location, toregexp, INT2FIX(pm_reg_flags((const pm_node_t *) cast)), INT2FIX(length));
if (popped) PUSH_INSN(ret, location, pop);
}
ADD_INSN2(ret, &dummy_line_node, toregexp, INT2FIX(pm_reg_flags(node)), INT2FIX(parts_size));
PM_POP_IF_POPPED;
return; return;
} }
case PM_INTERPOLATED_STRING_NODE: { case PM_INTERPOLATED_STRING_NODE: {
pm_interpolated_string_node_t *interp_string_node = (pm_interpolated_string_node_t *) node; // "foo #{bar}"
int number_of_items_pushed = pm_interpolated_node_compile(&interp_string_node->parts, iseq, dummy_line_node, ret, popped, scope_node); // ^^^^^^^^^^^^
if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
if (!popped) {
VALUE string = pm_static_literal_value(node, scope_node);
if (number_of_items_pushed > 1) { if (PM_NODE_FLAG_P(node, PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN)) {
ADD_INSN1(ret, &dummy_line_node, concatstrings, INT2FIX(number_of_items_pushed)); PUSH_INSN1(ret, location, putobject, string);
}
else if (PM_NODE_FLAG_P(node, PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE)) {
PUSH_INSN1(ret, location, putstring, string);
}
else {
PUSH_INSN1(ret, location, putchilledstring, string);
}
}
}
else {
const pm_interpolated_string_node_t *cast = (const pm_interpolated_string_node_t *) node;
int length = pm_interpolated_node_compile(&cast->parts, iseq, dummy_line_node, ret, popped, scope_node);
if (length > 1) PUSH_INSN1(ret, location, concatstrings, INT2FIX(length));
if (popped) PUSH_INSN(ret, location, pop);
} }
PM_POP_IF_POPPED;
return; return;
} }
case PM_INTERPOLATED_SYMBOL_NODE: { case PM_INTERPOLATED_SYMBOL_NODE: {
pm_interpolated_symbol_node_t *interp_symbol_node = (pm_interpolated_symbol_node_t *) node; // :"foo #{bar}"
int number_of_items_pushed = pm_interpolated_node_compile(&interp_symbol_node->parts, iseq, dummy_line_node, ret, popped, scope_node); // ^^^^^^^^^^^^^
const pm_interpolated_symbol_node_t *cast = (const pm_interpolated_symbol_node_t *) node;
int length;
if (number_of_items_pushed > 1) { if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
ADD_INSN1(ret, &dummy_line_node, concatstrings, INT2FIX(number_of_items_pushed)); if (!popped) {
} VALUE symbol = pm_static_literal_value(node, scope_node);
PUSH_INSN1(ret, location, putobject, symbol);
if (!popped) { }
ADD_INSN(ret, &dummy_line_node, intern);
} }
else { else {
PM_POP; if ((length = pm_interpolated_node_compile(&cast->parts, iseq, dummy_line_node, ret, popped, scope_node)) > 1) {
PUSH_INSN1(ret, location, concatstrings, INT2FIX(length));
}
if (!popped) {
PUSH_INSN(ret, location, intern);
}
else {
PUSH_INSN(ret, location, pop);
}
} }
return; return;
@ -6228,17 +6321,14 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
return; return;
} }
case PM_MATCH_LAST_LINE_NODE: { case PM_MATCH_LAST_LINE_NODE: {
if (!popped) { // if /foo/ then end
pm_match_last_line_node_t *cast = (pm_match_last_line_node_t *) node; // ^^^^^
VALUE regexp = pm_static_literal_value(node, scope_node);
VALUE regex_str = parse_string(scope_node, &cast->unescaped); PUSH_INSN1(ret, location, putobject, regexp);
VALUE regex = rb_reg_new(RSTRING_PTR(regex_str), RSTRING_LEN(regex_str), pm_reg_flags(node)); PUSH_INSN2(ret, location, getspecial, INT2FIX(0), INT2FIX(0));
RB_GC_GUARD(regex_str); PUSH_SEND(ret, location, idEqTilde, INT2NUM(1));
if (popped) PUSH_INSN(ret, location, pop);
ADD_INSN1(ret, &dummy_line_node, putobject, regex);
ADD_INSN2(ret, &dummy_line_node, getspecial, INT2FIX(0), INT2FIX(0));
ADD_SEND(ret, &dummy_line_node, idEqTilde, INT2NUM(1));
}
return; return;
} }
@ -6634,7 +6724,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
if (cast->body != NULL) { if (cast->body != NULL) {
PM_COMPILE(cast->body); PM_COMPILE(cast->body);
} else if (!popped) { }
else if (!popped) {
PUSH_INSN(ret, location, putnil); PUSH_INSN(ret, location, putnil);
} }
@ -6714,13 +6805,15 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
else { else {
if (cast->left == NULL) { if (cast->left == NULL) {
PUSH_INSN(ret, location, putnil); PUSH_INSN(ret, location, putnil);
} else { }
else {
PM_COMPILE(cast->left); PM_COMPILE(cast->left);
} }
if (cast->right == NULL) { if (cast->right == NULL) {
PUSH_INSN(ret, location, putnil); PUSH_INSN(ret, location, putnil);
} else { }
else {
PM_COMPILE(cast->right); PM_COMPILE(cast->right);
} }
@ -6837,7 +6930,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN1(ret, location, checkmatch, INT2FIX(checkmatch_flags)); PUSH_INSN1(ret, location, checkmatch, INT2FIX(checkmatch_flags));
PUSH_INSNL(ret, location, branchif, exception_match_label); PUSH_INSNL(ret, location, branchif, exception_match_label);
} }
} else { }
else {
ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0); ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
PUSH_INSN1(ret, location, putobject, rb_eStandardError); PUSH_INSN1(ret, location, putobject, rb_eStandardError);
PUSH_INSN1(ret, location, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE)); PUSH_INSN1(ret, location, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
@ -6885,7 +6979,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
// Now restore the end_label // Now restore the end_label
ISEQ_COMPILE_DATA(iseq)->end_label = prev_end; ISEQ_COMPILE_DATA(iseq)->end_label = prev_end;
} else { }
else {
PUSH_INSN(ret, location, putnil); PUSH_INSN(ret, location, putnil);
} }
@ -6898,7 +6993,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_LABEL(ret, rescue_end_label); PUSH_LABEL(ret, rescue_end_label);
if (cast->consequent) { if (cast->consequent) {
PM_COMPILE((pm_node_t *) cast->consequent); PM_COMPILE((pm_node_t *) cast->consequent);
} else { }
else {
ADD_GETLOCAL(ret, &dummy_line_node, 1, 0); ADD_GETLOCAL(ret, &dummy_line_node, 1, 0);
} }
@ -7005,7 +7101,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
PUSH_INSN(ret, location, putnil); PUSH_INSN(ret, location, putnil);
PUSH_INSN1(ret, location, throw, INT2FIX(TAG_RETRY)); PUSH_INSN1(ret, location, throw, INT2FIX(TAG_RETRY));
if (popped) PUSH_INSN(ret, location, pop); if (popped) PUSH_INSN(ret, location, pop);
} else { }
else {
COMPILE_ERROR(ERROR_ARGS "Invalid retry"); COMPILE_ERROR(ERROR_ARGS "Invalid retry");
return; return;
} }
@ -7595,7 +7692,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
if (PM_NODE_TYPE_P(scope_node->ast_node, PM_FOR_NODE)) { if (PM_NODE_TYPE_P(scope_node->ast_node, PM_FOR_NODE)) {
if (PM_NODE_TYPE_P(((const pm_for_node_t *) scope_node->ast_node)->index, PM_LOCAL_VARIABLE_TARGET_NODE)) { if (PM_NODE_TYPE_P(((const pm_for_node_t *) scope_node->ast_node)->index, PM_LOCAL_VARIABLE_TARGET_NODE)) {
body->param.lead_num++; body->param.lead_num++;
} else { }
else {
body->param.rest_start = local_index; body->param.rest_start = local_index;
body->param.flags.has_rest = true; body->param.flags.has_rest = true;
} }
@ -7823,7 +7921,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
pm_compile_node(iseq, scope_node->body, ret, popped, scope_node); pm_compile_node(iseq, scope_node->body, ret, popped, scope_node);
break; break;
} }
} else { }
else {
PM_PUTNIL; PM_PUTNIL;
} }
@ -7851,7 +7950,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
ADD_TRACE(ret, RUBY_EVENT_CALL); ADD_TRACE(ret, RUBY_EVENT_CALL);
if (scope_node->body) { if (scope_node->body) {
PM_COMPILE((pm_node_t *)scope_node->body); PM_COMPILE((pm_node_t *)scope_node->body);
} else { }
else {
PM_PUTNIL; PM_PUTNIL;
} }
@ -7886,7 +7986,8 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
default: default:
if (scope_node->body) { if (scope_node->body) {
PM_COMPILE((pm_node_t *)scope_node->body); PM_COMPILE((pm_node_t *)scope_node->body);
} else { }
else {
PM_PUTNIL; PM_PUTNIL;
} }
break; break;