[ruby-core:114722] [Ruby master Bug#19877] Non intuitive behavior of syntax only applied to literal value

Issue #19877 has been reported by tompng (tomoya ishida). ---------------------------------------- Bug #19877: Non intuitive behavior of syntax only applied to literal value https://bugs.ruby-lang.org/issues/19877 * Author: tompng (tomoya ishida) * Status: Open * Priority: Normal * ruby -v: ruby 3.3.0dev (2023-09-08T23:08:32Z master b635a66e95) [x86_64-linux] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- Non intuitive behavior of syntax only applied to literal value Some ruby syntax is only applied to literal value. ~~~ruby 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. ~~~ruby 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 ~~~ruby def (class A; 1; end).foo; end (break; /?<a>/) =~ s class A; /?<a>/; end =~ s ~~~ -- https://bugs.ruby-lang.org/

Issue #19877 has been updated by kddnewton (Kevin Newton). We need an answer on this in order to properly understand what we need to support. In particular, ``` ruby (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 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. ---------------------------------------- Bug #19877: Non intuitive behavior of syntax only applied to literal value https://bugs.ruby-lang.org/issues/19877#change-105420 * Author: tompng (tomoya ishida) * Status: Closed * Priority: Normal * ruby -v: ruby 3.3.0dev (2023-09-08T23:08:32Z master b635a66e95) [x86_64-linux] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- Non intuitive behavior of syntax only applied to literal value Some ruby syntax is only applied to literal value. ~~~ruby 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. ~~~ruby 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 ~~~ruby def (class A; 1; end).foo; end (break; /?<a>/) =~ s class A; /?<a>/; end =~ s ~~~ -- https://bugs.ruby-lang.org/

Issue #19877 has been updated by nobu (Nobuyoshi Nakada). https://github.com/ruby/ruby/pull/9077 ? ---------------------------------------- Bug #19877: Non intuitive behavior of syntax only applied to literal value https://bugs.ruby-lang.org/issues/19877#change-105480 * Author: tompng (tomoya ishida) * Status: Closed * Priority: Normal * ruby -v: ruby 3.3.0dev (2023-09-08T23:08:32Z master b635a66e95) [x86_64-linux] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- Non intuitive behavior of syntax only applied to literal value Some ruby syntax is only applied to literal value. ~~~ruby 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. ~~~ruby 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 ~~~ruby def (class A; 1; end).foo; end (break; /?<a>/) =~ s class A; /?<a>/; end =~ s ~~~ -- https://bugs.ruby-lang.org/

Issue #19877 has been updated by kddnewton (Kevin Newton). Thank you @nobu that fixes the regex, but we still need it for flip-flops: https://github.com/ruby/prism/issues/1923 ``` ruby 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)) ``` ---------------------------------------- Bug #19877: Non intuitive behavior of syntax only applied to literal value https://bugs.ruby-lang.org/issues/19877#change-105499 * Author: tompng (tomoya ishida) * Status: Closed * Priority: Normal * ruby -v: ruby 3.3.0dev (2023-09-08T23:08:32Z master b635a66e95) [x86_64-linux] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- Non intuitive behavior of syntax only applied to literal value Some ruby syntax is only applied to literal value. ~~~ruby 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. ~~~ruby 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 ~~~ruby def (class A; 1; end).foo; end (break; /?<a>/) =~ s class A; /?<a>/; end =~ s ~~~ -- https://bugs.ruby-lang.org/

Issue #19877 has been updated by tompng (tomoya ishida). I found a similar behavior for MATCH node (Prism::MatchLastLineNode) ~~~ruby 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)) ~~~ ---------------------------------------- Bug #19877: Non intuitive behavior of syntax only applied to literal value https://bugs.ruby-lang.org/issues/19877#change-105509 * Author: tompng (tomoya ishida) * Status: Closed * Priority: Normal * ruby -v: ruby 3.3.0dev (2023-09-08T23:08:32Z master b635a66e95) [x86_64-linux] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- Non intuitive behavior of syntax only applied to literal value Some ruby syntax is only applied to literal value. ~~~ruby 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. ~~~ruby 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 ~~~ruby def (class A; 1; end).foo; end (break; /?<a>/) =~ s class A; /?<a>/; end =~ s ~~~ -- https://bugs.ruby-lang.org/

Issue #19877 has been updated by mame (Yusuke Endoh). In today's dev meeting, @matz 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 ``` ---------------------------------------- Bug #19877: Non intuitive behavior of syntax only applied to literal value https://bugs.ruby-lang.org/issues/19877#change-105574 * Author: tompng (tomoya ishida) * Status: Closed * Priority: Normal * ruby -v: ruby 3.3.0dev (2023-09-08T23:08:32Z master b635a66e95) [x86_64-linux] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- Non intuitive behavior of syntax only applied to literal value Some ruby syntax is only applied to literal value. ~~~ruby 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. ~~~ruby 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 ~~~ruby def (class A; 1; end).foo; end (break; /?<a>/) =~ s class A; /?<a>/; end =~ s ~~~ -- https://bugs.ruby-lang.org/
participants (4)
-
kddnewton (Kevin Newton)
-
mame (Yusuke Endoh)
-
nobu (Nobuyoshi Nakada)
-
tompng (tomoya ishida)