Project

General

Profile

Actions

Bug #19392

closed

Endless method and parsing priorities

Added by zverok (Victor Shepelev) almost 2 years ago. Updated 12 months ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:112119]

Description

Initial description

Discovered by Lucian Ghinda:

def test = puts("foo") and puts("bar")
# prints "bar" immediately
test
# prints "foo"

It seems that it is a parser error, right?..

RubyVM::AbstractSyntaxTree.parse('def test = puts("foo") and puts("bar")')
#  => 
# (SCOPE@1:0-1:38                                                         
#  tbl: []                                                                
#  args: nil                                                              
#  body:                                                                  
#    (AND@1:0-1:38                                                        
#       (DEFN@1:0-1:22                                                    
#        mid: :test                                                       
#        body:                                                            
#          (SCOPE@1:0-1:22                                                
#           tbl: []                                                       
#           args:                                                         
#             (ARGS@1:0-1:8 pre_num: 0 pre_init: nil opt: nil first_post: nil post_num: 0 post_init: nil rest: nil kw: nil kwrest: nil block: nil)
#           body: (FCALL@1:11-1:22 :puts (LIST@1:16-1:21 (STR@1:16-1:21 "foo") nil))))
#       (FCALL@1:27-1:38 :puts (LIST@1:32-1:37 (STR@1:32-1:37 "bar") nil)))) 

E.g. it is parsed as

(def test = puts("foo")) and (puts("bar"))

...which is hardly intentional or have any practical use. The rightly parsed code in this case can have practical use, like

def write(data) = File.write(@filename, data) == data.size or raise "Something went wrong"

Additional cases of what seems to be the same problem

def save = File.write(name, self.to_yaml) unless invalid?
# Parsed as:
(def save = File.write(name, self.to_yaml)) unless invalid?

...which makes it very hard for the users to diagnose the real reason, see #19731

def initialize(a, b) = @a, b = a, b
# syntax error, unexpected ',', expecting end-of-input (SyntaxError)                                                 
# def initialize(a, b) = @a, b = a, b                            
#                          ^         

# Again, parsed as
(def initialize(a, b) = @a), b = a, b

While this one is at least diagnosed early, in pathological cases, it might lead to very subtle bugs:

private def start = @operation, @conversion = :print, :to_s

This code doesn't throw a syntax error, but its effect is very far from expected. Again, it is parsed as

private( (def start = @operation), @conversion = :print, :to_s )

...and ends up in:

  • defining a private method start
  • making private methods :print and :to_s

Related issues 1 (0 open1 closed)

Related to Ruby master - Bug #19731: Can’t call an instance method inside an Endless method definitionClosedActions
Actions

Also available in: Atom PDF

Like1
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like1Like0Like0Like0