Skip to content

Commit 4e33f53

Browse files
authored
Merge pull request ruby#3517 from ruby/defined-newline
Accept a newline after the defined? keyword
2 parents 3c7a2d7 + 22be955 commit 4e33f53

File tree

6 files changed

+114
-25
lines changed

6 files changed

+114
-25
lines changed

lib/prism/translation/parser/compiler.rb

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -696,13 +696,37 @@ def visit_def_node(node)
696696
# defined?(a)
697697
# ^^^^^^^^^^^
698698
def visit_defined_node(node)
699-
builder.keyword_cmd(
700-
:defined?,
701-
token(node.keyword_loc),
702-
token(node.lparen_loc),
703-
[visit(node.value)],
704-
token(node.rparen_loc)
705-
)
699+
# Very weird circumstances here where something like:
700+
#
701+
# defined?
702+
# (1)
703+
#
704+
# gets parsed in Ruby as having only the `1` expression but in parser
705+
# it gets parsed as having a begin. In this case we need to synthesize
706+
# that begin to match parser's behavior.
707+
if node.lparen_loc && node.keyword_loc.join(node.lparen_loc).slice.include?("\n")
708+
builder.keyword_cmd(
709+
:defined?,
710+
token(node.keyword_loc),
711+
nil,
712+
[
713+
builder.begin(
714+
token(node.lparen_loc),
715+
visit(node.value),
716+
token(node.rparen_loc)
717+
)
718+
],
719+
nil
720+
)
721+
else
722+
builder.keyword_cmd(
723+
:defined?,
724+
token(node.keyword_loc),
725+
token(node.lparen_loc),
726+
[visit(node.value)],
727+
token(node.rparen_loc)
728+
)
729+
end
706730
end
707731

708732
# if foo then bar else baz end

lib/prism/translation/ripper.rb

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1615,8 +1615,23 @@ def visit_def_node(node)
16151615
# defined?(a)
16161616
# ^^^^^^^^^^^
16171617
def visit_defined_node(node)
1618+
expression = visit(node.value)
1619+
1620+
# Very weird circumstances here where something like:
1621+
#
1622+
# defined?
1623+
# (1)
1624+
#
1625+
# gets parsed in Ruby as having only the `1` expression but in Ripper it
1626+
# gets parsed as having a parentheses node. In this case we need to
1627+
# synthesize that node to match Ripper's behavior.
1628+
if node.lparen_loc && node.keyword_loc.join(node.lparen_loc).slice.include?("\n")
1629+
bounds(node.lparen_loc.join(node.rparen_loc))
1630+
expression = on_paren(on_stmts_add(on_stmts_new, expression))
1631+
end
1632+
16181633
bounds(node.location)
1619-
on_defined(visit(node.value))
1634+
on_defined(expression)
16201635
end
16211636

16221637
# if foo then bar else baz end

src/prism.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19607,18 +19607,27 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1960719607
pm_token_t lparen;
1960819608
pm_token_t rparen;
1960919609
pm_node_t *expression;
19610+
1961019611
context_push(parser, PM_CONTEXT_DEFINED);
19612+
bool newline = accept1(parser, PM_TOKEN_NEWLINE);
1961119613

1961219614
if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
1961319615
lparen = parser->previous;
19614-
expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
1961519616

19616-
if (parser->recovering) {
19617+
if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19618+
expression = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0);
19619+
lparen = not_provided(parser);
1961719620
rparen = not_provided(parser);
1961819621
} else {
19619-
accept1(parser, PM_TOKEN_NEWLINE);
19620-
expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19621-
rparen = parser->previous;
19622+
expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19623+
19624+
if (parser->recovering) {
19625+
rparen = not_provided(parser);
19626+
} else {
19627+
accept1(parser, PM_TOKEN_NEWLINE);
19628+
expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19629+
rparen = parser->previous;
19630+
}
1962219631
}
1962319632
} else {
1962419633
lparen = not_provided(parser);

test/prism/errors/defined_empty.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
defined?()
2+
^ expected an expression after `defined?`
3+

test/prism/fixtures/defined.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,12 @@ defined? 1
88

99
defined?("foo"
1010
)
11+
12+
defined?
13+
1
14+
15+
defined?
16+
(1)
17+
18+
defined?
19+
()

test/prism/snapshots/defined.txt

Lines changed: 41 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)