Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 2dde243

Browse files
committed
Block ampersand association
Fix parsing expressions like `foo.instance_exec(&T.must(block))`, where there are two `args_add_block` calls with a single `&`. Previously it was associating the `&` with the wrong block.
1 parent 9598362 commit 2dde243

File tree

3 files changed

+16
-10
lines changed

3 files changed

+16
-10
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
66

77
## [Unreleased]
88

9+
### Changed
10+
11+
- [#45](https://github.com/ruby-syntax-tree/syntax_tree/issues/45) - Fix parsing expressions like `foo.instance_exec(&T.must(block))`, where there are two `args_add_block` calls with a single `&`. Previously it was associating the `&` with the wrong block.
12+
913
## [2.1.0] - 2022-04-12
1014

1115
### Added

lib/syntax_tree/parser.rb

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -414,12 +414,19 @@ def on_args_add(arguments, argument)
414414
# (false | untyped) block
415415
# ) -> Args
416416
def on_args_add_block(arguments, block)
417+
# First, see if there is an & operator that could potentially be
418+
# associated with the block part of this args_add_block. If there is not,
419+
# then just return the arguments.
417420
operator = find_token(Op, "&", consume: false)
418-
419-
# If we can't find the & operator, then there's no block to add to the
420-
# list, so we're just going to return the arguments as-is.
421421
return arguments unless operator
422422

423+
# If there are any arguments and the operator we found from the list is
424+
# not after them, then we're going to return the arguments as-is because
425+
# we're looking at an & that occurs before the arguments are done.
426+
if arguments.parts.any? && operator.location.start_char < arguments.location.end_char
427+
return arguments
428+
end
429+
423430
# Now we know we have an & operator, so we're going to delete it from the
424431
# list of tokens to make sure it doesn't get confused with anything else.
425432
tokens.delete(operator)
@@ -428,13 +435,6 @@ def on_args_add_block(arguments, block)
428435
location = operator.location
429436
location = operator.location.to(block.location) if block
430437

431-
# If there are any arguments and the operator we found from the list is
432-
# not after them, then we're going to return the arguments as-is because
433-
# we're looking at an & that occurs before the arguments are done.
434-
if arguments.parts.any? && location.start_char < arguments.location.end_char
435-
return arguments
436-
end
437-
438438
# Otherwise, we're looking at an actual block argument (with or without a
439439
# block, which could be missing because it could be a bare & since 3.1.0).
440440
arg_block = ArgBlock.new(value: block, location: location)

test/fixtures/arg_block.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@
1818
def foo(&)
1919
bar(&)
2020
end
21+
% # https://github.com/ruby-syntax-tree/syntax_tree/issues/45
22+
foo.instance_exec(&T.must(block))

0 commit comments

Comments
 (0)