summaryrefslogtreecommitdiff
path: root/parse.y
diff options
context:
space:
mode:
authorS-H-GAMELINKS <gamelinks007@gmail.com>2025-07-08 23:14:37 +0900
committerNobuyoshi Nakada <nobu.nakada@gmail.com>2025-07-16 16:17:10 +0900
commitf0649ab46a5235904ea6f9b95aa07cb9375fd463 (patch)
treef58ccc2dcf3f9b1dd8678c9890f6fcc64dfd6593 /parse.y
parent54ec48249192325d108355bb8c7d735cd5081617 (diff)
Make `defined? (x;)` return `expression` when using parse.y parser
Follow up [Bug #21029]. Currently, `defined? (x;)` returns `expression` when using Prism parser. See: - https://github.com/ruby/ruby/pull/12949 - https://bugs.ruby-lang.org/issues/21029 However, `defined? (x;)` returns nil when using parse.y, as reported in bug ticket comment and test-all (when using parse.y parser) test result. This change adds a context flag to track trailing semicolons in defined? scope. When a trailing semicolon is detected within a defined? scope, the generated AST node is wrapped with NODE_BLOCK. This change ensures consistent behavior with `defined? (;x)` .
Diffstat (limited to 'parse.y')
-rw-r--r--parse.y21
1 files changed, 20 insertions, 1 deletions
diff --git a/parse.y b/parse.y
index 3138061b98..7b36caf78d 100644
--- a/parse.y
+++ b/parse.y
@@ -314,6 +314,7 @@ struct lex_context {
unsigned int in_argdef: 1;
unsigned int in_def: 1;
unsigned int in_class: 1;
+ unsigned int has_trailing_semicolon: 1;
BITFIELD(enum rb_parser_shareability, shareable_constant_value, 2);
BITFIELD(enum rescue_context, in_rescue, 2);
unsigned int cant_return: 1;
@@ -4041,6 +4042,7 @@ arg : asgn(arg_rhs)
{
p->ctxt.in_defined = $3.in_defined;
$$ = new_defined(p, $4, &@$);
+ p->ctxt.has_trailing_semicolon = $3.has_trailing_semicolon;
/*% ripper: defined!($:4) %*/
}
| def_endless_method(endless_arg)
@@ -4428,6 +4430,7 @@ primary : inline_primary
{
p->ctxt.in_defined = $4.in_defined;
$$ = new_defined(p, $5, &@$);
+ p->ctxt.has_trailing_semicolon = $4.has_trailing_semicolon;
/*% ripper: defined!($:5) %*/
}
| keyword_not '(' expr rparen
@@ -6706,7 +6709,14 @@ trailer : '\n'?
| ','
;
-term : ';' {yyerrok;token_flush(p);}
+term : ';'
+ {
+ yyerrok;
+ token_flush(p);
+ if (p->ctxt.in_defined) {
+ p->ctxt.has_trailing_semicolon = 1;
+ }
+ }
| '\n'
{
@$.end_pos = @$.beg_pos;
@@ -13013,6 +13023,9 @@ kwd_append(rb_node_kw_arg_t *kwlist, rb_node_kw_arg_t *kw)
static NODE *
new_defined(struct parser_params *p, NODE *expr, const YYLTYPE *loc)
{
+ int had_trailing_semicolon = p->ctxt.has_trailing_semicolon;
+ p->ctxt.has_trailing_semicolon = 0;
+
NODE *n = expr;
while (n) {
if (nd_type_p(n, NODE_BEGIN)) {
@@ -13025,6 +13038,12 @@ new_defined(struct parser_params *p, NODE *expr, const YYLTYPE *loc)
break;
}
}
+
+ if (had_trailing_semicolon && !nd_type_p(expr, NODE_BLOCK)) {
+ NODE *block = NEW_BLOCK(expr, loc);
+ return NEW_DEFINED(block, loc);
+ }
+
return NEW_DEFINED(n, loc);
}