зеркало из https://github.com/github/ruby.git
Handle hash and splat nodes in defined?
This supports the nodes in both in the parse.y and prism compilers. Fixes [Bug #20043] Co-authored-by: Kevin Newton <kddnewton@gmail.com>
This commit is contained in:
Родитель
e428ee7bbe
Коммит
ae0c7faa79
30
compile.c
30
compile.c
|
@ -5859,17 +5859,22 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
|
|||
expr_type = DEFINED_FALSE;
|
||||
break;
|
||||
|
||||
case NODE_HASH:
|
||||
case NODE_LIST:{
|
||||
const NODE *vals = node;
|
||||
const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
|
||||
|
||||
do {
|
||||
defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
|
||||
if (vals) {
|
||||
do {
|
||||
if (RNODE_LIST(vals)->nd_head) {
|
||||
defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
|
||||
|
||||
if (!lfinish[1]) {
|
||||
lfinish[1] = NEW_LABEL(line);
|
||||
}
|
||||
ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
|
||||
} while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
|
||||
if (!lfinish[1]) {
|
||||
lfinish[1] = NEW_LABEL(line);
|
||||
}
|
||||
ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
|
||||
}
|
||||
} while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
|
||||
}
|
||||
}
|
||||
/* fall through */
|
||||
case NODE_STR:
|
||||
|
@ -5889,6 +5894,15 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
|
|||
expr_type = DEFINED_EXPR;
|
||||
break;
|
||||
|
||||
case NODE_SPLAT:
|
||||
defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
|
||||
if (!lfinish[1]) {
|
||||
lfinish[1] = NEW_LABEL(line);
|
||||
}
|
||||
ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
|
||||
expr_type = DEFINED_EXPR;
|
||||
break;
|
||||
|
||||
/* variables */
|
||||
case NODE_LVAR:
|
||||
case NODE_DVAR:
|
||||
|
|
|
@ -3443,19 +3443,83 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_line_c
|
|||
dtype = DEFINED_FALSE;
|
||||
break;
|
||||
case PM_ARRAY_NODE: {
|
||||
const pm_array_node_t *cast = (const pm_array_node_t *) node;
|
||||
const pm_array_node_t *cast = (const pm_array_node_t *) node;
|
||||
|
||||
if (!PM_NODE_FLAG_P(cast, PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT)) {
|
||||
for (size_t index = 0; index < cast->elements.size; index++) {
|
||||
pm_compile_defined_expr0(iseq, cast->elements.nodes[index], node_location, ret, popped, scope_node, true, lfinish, false);
|
||||
if (cast->elements.size > 0 && !lfinish[1]) {
|
||||
lfinish[1] = NEW_LABEL(location.line);
|
||||
}
|
||||
|
||||
if (!lfinish[1]) {
|
||||
lfinish[1] = NEW_LABEL(location.line);
|
||||
}
|
||||
for (size_t index = 0; index < cast->elements.size; index++) {
|
||||
pm_compile_defined_expr0(iseq, cast->elements.nodes[index], node_location, ret, popped, scope_node, true, lfinish, false);
|
||||
PUSH_INSNL(ret, location, branchunless, lfinish[1]);
|
||||
}
|
||||
|
||||
PUSH_INSNL(ret, location, branchunless, lfinish[1]);
|
||||
dtype = DEFINED_EXPR;
|
||||
break;
|
||||
}
|
||||
case PM_HASH_NODE:
|
||||
case PM_KEYWORD_HASH_NODE: {
|
||||
const pm_node_list_t *elements;
|
||||
|
||||
if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
|
||||
elements = &((const pm_hash_node_t *) node)->elements;
|
||||
}
|
||||
else {
|
||||
elements = &((const pm_keyword_hash_node_t *) node)->elements;
|
||||
}
|
||||
|
||||
if (elements->size > 0 && !lfinish[1]) {
|
||||
lfinish[1] = NEW_LABEL(location.line);
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < elements->size; index++) {
|
||||
const pm_node_t *element = elements->nodes[index];
|
||||
|
||||
switch (PM_NODE_TYPE(element)) {
|
||||
case PM_ASSOC_NODE: {
|
||||
const pm_assoc_node_t *assoc = (const pm_assoc_node_t *) element;
|
||||
|
||||
pm_compile_defined_expr0(iseq, assoc->key, node_location, ret, popped, scope_node, true, lfinish, false);
|
||||
PUSH_INSNL(ret, location, branchunless, lfinish[1]);
|
||||
|
||||
pm_compile_defined_expr0(iseq, assoc->value, node_location, ret, popped, scope_node, true, lfinish, false);
|
||||
PUSH_INSNL(ret, location, branchunless, lfinish[1]);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
case PM_ASSOC_SPLAT_NODE: {
|
||||
const pm_assoc_splat_node_t *assoc_splat = (const pm_assoc_splat_node_t *) element;
|
||||
|
||||
pm_compile_defined_expr0(iseq, assoc_splat->value, node_location, ret, popped, scope_node, true, lfinish, false);
|
||||
PUSH_INSNL(ret, location, branchunless, lfinish[1]);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rb_bug("unexpected node type in hash node: %s", pm_node_type_to_str(PM_NODE_TYPE(element)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dtype = DEFINED_EXPR;
|
||||
break;
|
||||
}
|
||||
case PM_SPLAT_NODE: {
|
||||
const pm_splat_node_t *cast = (const pm_splat_node_t *) node;
|
||||
pm_compile_defined_expr0(iseq, cast->expression, node_location, ret, popped, scope_node, in_condition, lfinish, false);
|
||||
|
||||
if (!lfinish[1]) {
|
||||
lfinish[1] = NEW_LABEL(location.line);
|
||||
}
|
||||
|
||||
PUSH_INSNL(ret, location, branchunless, lfinish[1]);
|
||||
dtype = DEFINED_EXPR;
|
||||
break;
|
||||
}
|
||||
case PM_IMPLICIT_NODE: {
|
||||
const pm_implicit_node_t *cast = (const pm_implicit_node_t *) node;
|
||||
pm_compile_defined_expr0(iseq, cast->value, node_location, ret, popped, scope_node, in_condition, lfinish, explicit_receiver);
|
||||
return;
|
||||
}
|
||||
case PM_AND_NODE:
|
||||
case PM_BEGIN_NODE:
|
||||
|
@ -3467,7 +3531,6 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_line_c
|
|||
case PM_DEFINED_NODE:
|
||||
case PM_FLOAT_NODE:
|
||||
case PM_FOR_NODE:
|
||||
case PM_HASH_NODE:
|
||||
case PM_IF_NODE:
|
||||
case PM_IMAGINARY_NODE:
|
||||
case PM_INTEGER_NODE:
|
||||
|
@ -3475,7 +3538,6 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_line_c
|
|||
case PM_INTERPOLATED_STRING_NODE:
|
||||
case PM_INTERPOLATED_SYMBOL_NODE:
|
||||
case PM_INTERPOLATED_X_STRING_NODE:
|
||||
case PM_KEYWORD_HASH_NODE:
|
||||
case PM_LAMBDA_NODE:
|
||||
case PM_MATCH_PREDICATE_NODE:
|
||||
case PM_MATCH_REQUIRED_NODE:
|
||||
|
|
|
@ -139,6 +139,41 @@ class TestDefined < Test::Unit::TestCase
|
|||
assert_equal("assignment", eval('defined?(A::B &&= 1)'))
|
||||
end
|
||||
|
||||
def test_defined_splat
|
||||
assert_nil(defined?([*a]))
|
||||
assert_nil(defined?(itself(*a)))
|
||||
assert_equal("expression", defined?([*itself]))
|
||||
assert_equal("method", defined?(itself(*itself)))
|
||||
end
|
||||
|
||||
def test_defined_hash
|
||||
assert_nil(defined?({a: a}))
|
||||
assert_nil(defined?({a => 1}))
|
||||
assert_nil(defined?({a => a}))
|
||||
assert_nil(defined?({**a}))
|
||||
assert_nil(defined?(itself(a: a)))
|
||||
assert_nil(defined?(itself(a => 1)))
|
||||
assert_nil(defined?(itself(a => a)))
|
||||
assert_nil(defined?(itself(**a)))
|
||||
assert_nil(defined?(itself({a: a})))
|
||||
assert_nil(defined?(itself({a => 1})))
|
||||
assert_nil(defined?(itself({a => a})))
|
||||
assert_nil(defined?(itself({**a})))
|
||||
|
||||
assert_equal("expression", defined?({a: itself}))
|
||||
assert_equal("expression", defined?({itself => 1}))
|
||||
assert_equal("expression", defined?({itself => itself}))
|
||||
assert_equal("expression", defined?({**itself}))
|
||||
assert_equal("method", defined?(itself(a: itself)))
|
||||
assert_equal("method", defined?(itself(itself => 1)))
|
||||
assert_equal("method", defined?(itself(itself => itself)))
|
||||
assert_equal("method", defined?(itself(**itself)))
|
||||
assert_equal("method", defined?(itself({a: itself})))
|
||||
assert_equal("method", defined?(itself({itself => 1})))
|
||||
assert_equal("method", defined?(itself({itself => itself})))
|
||||
assert_equal("method", defined?(itself({**itself})))
|
||||
end
|
||||
|
||||
def test_defined_literal
|
||||
assert_equal("nil", defined?(nil))
|
||||
assert_equal("true", defined?(true))
|
||||
|
|
Загрузка…
Ссылка в новой задаче