Bug #19877
closedNon intuitive behavior of syntax only applied to literal value
Description
Non intuitive behavior of syntax only applied to literal value
Some ruby syntax is only applied to literal value.
def 1.foo; end # receiver is a literal, it is Syntax Error
/(?<a>)/ =~ s # receiver is regexp literal, it will assign to local variable
if cond1..cond2; end # range-like syntax appears in condition, it is flipflop
If it is wrapped with parenthesis, the behavior seems not intuitive for me, and YARP parses it differently.
def (1).foo; end # Syntax Error
def ((1;1)).foo; end # Syntax Error
def ((;1)).foo; end # Syntax OK
def ((1+1;1)).foo; end # Syntax OK
def ((%s();1)).foo; end # Syntax Error
def ((%w();1)).foo; end # Syntax OK
def ("#{42}").foo; end # Syntax Error
def (:"#{42}").foo; end # Syntax OK
(/(?<a>)/) =~ s # assigns to a
(;/(?<a>)/) =~ s # does not assigns
(%s();/(?<a>)/) =~ s # assigns to a
(%w();/(?<a>)/) =~ s # does not assigns
(1; (2; 3; (4; /(?<a>)/))) =~ s # assigns to a
(1+1; /(?<a>)/) =~ s # does not assign
if ((cond1..cond2)); end # flipflop
if (; cond1..cond2); end # range
if (1; cond1..cond2); end # flipflop
if (%s(); cond1..cond2); end # flipflop
if (%w(); cond1..cond2); end # range
if (1; (2; (3; 4; cond1..cond2))); end # flipflop
if (1+1; cond1..cond2); end # range
I expect YARP and parse.y parses same.
I expect all parenthesis-wrapped result same.
I think it is simple and intuitive if parenthesis-wrapped code always behaves different from non-wrapped code because there are more complex variation like this
def (class A; 1; end).foo; end
(break; /?<a>/) =~ s
class A; /?<a>/; end =~ s
Updated by nobu (Nobuyoshi Nakada) about 1 year ago
- Status changed from Open to Closed
Applied in changeset git|e8896a31d48e5797df3878696dcb50aed85b87c2.
[Bug #19877] Literals cannot have singleton methods even in blocks
Updated by kddnewton (Kevin Newton) 11 months ago
We need an answer on this in order to properly understand what we need to support. In particular,
(1; /(?<foo>)/) =~ s
assigning to the local seems incorrect. It would mean the only way for a parser (prism or any other) to be correct would be to mirror CRuby dropping literal nodes from the tree. In the meantime I know @yui-knk (Kaneko Yuichiro) has been working on adding those nodes back in for the universal parser.
So either way, we need to know what is "correct" in this case.
Updated by nobu (Nobuyoshi Nakada) 11 months ago
Updated by kddnewton (Kevin Newton) 11 months ago
Thank you @nobu (Nobuyoshi Nakada) that fixes the regex, but we still need it for flip-flops:
https://github.com/ruby/prism/issues/1923
RubyVM::AbstractSyntaxTree.parse 'if (1; a..b); end'
# =>
(SCOPE@1:0-1:17
tbl: []
args: nil
body: (IF@1:0-1:17 (FLIP2@1:7-1:11 (VCALL@1:7-1:8 :a) (VCALL@1:10-1:11 :b)) (BEGIN@1:13-1:13 nil) nil))
Updated by tompng (tomoya ishida) 11 months ago
I found a similar behavior for MATCH node (Prism::MatchLastLineNode)
RubyVM::AbstractSyntaxTree.parse 'if (1; //); end'
(none):1: warning: regex literal in condition
=>
(SCOPE@1:0-1:15
tbl: []
args: nil
body:
(IF@1:0-1:15
(BEGIN@1:3-1:10
(BLOCK@1:4-1:9 (LIT@1:4-1:5 1) (MATCH@1:7-1:9 //)))
(BEGIN@1:11-1:11 nil) nil))
Updated by mame (Yusuke Endoh) 11 months ago
In today's dev meeting, @matz (Yukihiro Matsumoto) said:
expr if (cond1..cond2) # This should be a flip-flop
expr if (((cond1..cond2))) # This should be a flip-flop
expr if begin cond1..cond2; end # This should be a flip-flop
expr if (;;; cond1..cond2) # Don't care. Either is ok
expr if (1; cond1..cond2) # This should NOT be a flip-flop
expr if (method; cond1..cond2) # This should NOT be a flip-flop
(111; /(?<a>)/) =~ s; # a should NOT be defined
(foo; /(?<a>)/) =~ s; # a should NOT be defined
(/(?<a>)/) =~ s # a should NOT be defined