From 178267d30031a8632fe6ff761a197166dd7ed1c4 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Sun, 30 Oct 2022 22:27:20 -0400 Subject: [PATCH 01/35] Fix up linguist percentages --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..b24bb2da --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +bin/* linguist-language=Ruby From d15c56f3a1134dac554a1493a18057441e5255c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Nov 2022 17:39:03 +0000 Subject: [PATCH 02/35] Bump rubocop from 1.37.1 to 1.38.0 Bumps [rubocop](https://github.com/rubocop/rubocop) from 1.37.1 to 1.38.0. - [Release notes](https://github.com/rubocop/rubocop/releases) - [Changelog](https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md) - [Commits](https://github.com/rubocop/rubocop/compare/v1.37.1...v1.38.0) --- updated-dependencies: - dependency-name: rubocop dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 25f461c6..1c1a127c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -19,7 +19,7 @@ GEM rake (13.0.6) regexp_parser (2.6.0) rexml (3.2.5) - rubocop (1.37.1) + rubocop (1.38.0) json (~> 2.3) parallel (~> 1.10) parser (>= 3.1.2.1) From 5afee6ba9266742c2c90153ffd98bdf7642dd894 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 10:36:10 -0400 Subject: [PATCH 03/35] Remove comments from initializers --- lib/syntax_tree/node.rb | 522 +++++++++++++++++++------------------- lib/syntax_tree/parser.rb | 28 +- 2 files changed, 276 insertions(+), 274 deletions(-) diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index aa133b7f..a1e5c0ae 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -146,11 +146,11 @@ class BEGINBlock < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(lbrace:, statements:, location:, comments: []) + def initialize(lbrace:, statements:, location:) @lbrace = lbrace @statements = statements @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -199,10 +199,10 @@ class CHAR < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -249,11 +249,11 @@ class ENDBlock < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(lbrace:, statements:, location:, comments: []) + def initialize(lbrace:, statements:, location:) @lbrace = lbrace @statements = statements @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -305,10 +305,10 @@ class EndContent < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -392,11 +392,11 @@ def format(q) # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(left:, right:, location:, comments: []) + def initialize(left:, right:, location:) @left = left @right = right @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -453,11 +453,11 @@ class ARef < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(collection:, index:, location:, comments: []) + def initialize(collection:, index:, location:) @collection = collection @index = index @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -514,11 +514,11 @@ class ARefField < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(collection:, index:, location:, comments: []) + def initialize(collection:, index:, location:) @collection = collection @index = index @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -577,10 +577,10 @@ class ArgParen < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(arguments:, location:, comments: []) + def initialize(arguments:, location:) @arguments = arguments @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -650,10 +650,10 @@ class Args < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(parts:, location:, comments: []) + def initialize(parts:, location:) @parts = parts @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -686,10 +686,10 @@ class ArgBlock < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -723,10 +723,10 @@ class ArgStar < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -773,10 +773,10 @@ class ArgsForward < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -955,11 +955,11 @@ def format(q) # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(lbracket:, contents:, location:, comments: []) + def initialize(lbracket:, contents:, location:) @lbracket = lbracket @contents = contents @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -1132,7 +1132,7 @@ def initialize( @rest = rest @posts = posts @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -1209,11 +1209,11 @@ class Assign < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(target:, value:, location:, comments: []) + def initialize(target:, value:, location:) @target = target @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -1271,11 +1271,11 @@ class Assoc < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(key:, value:, location:, comments: []) + def initialize(key:, value:, location:) @key = key @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -1330,10 +1330,10 @@ class AssocSplat < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -1368,10 +1368,10 @@ class Backref < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -1403,10 +1403,10 @@ class Backtick < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -1515,10 +1515,10 @@ class BareAssocHash < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(assocs:, location:, comments: []) + def initialize(assocs:, location:) @assocs = assocs @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -1557,10 +1557,10 @@ class Begin < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(bodystmt:, location:, comments: []) + def initialize(bodystmt:, location:) @bodystmt = bodystmt @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -1605,10 +1605,10 @@ class PinnedBegin < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(statement:, location:, comments: []) + def initialize(statement:, location:) @statement = statement @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -1677,12 +1677,12 @@ def name # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(left:, operator:, right:, location:, comments: []) + def initialize(left:, operator:, right:, location:) @left = left @operator = operator @right = right @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -1745,11 +1745,11 @@ class BlockVar < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(params:, locals:, location:, comments: []) + def initialize(params:, locals:, location:) @params = params @locals = locals @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -1803,10 +1803,10 @@ class BlockArg < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(name:, location:, comments: []) + def initialize(name:, location:) @name = name @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -1866,7 +1866,7 @@ def initialize( @else_clause = else_clause @ensure_clause = ensure_clause @location = location - @comments = comments + @comments = [] end def bind(start_char, start_column, end_char, end_column) @@ -2141,12 +2141,12 @@ class BraceBlock < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(lbrace:, block_var:, statements:, location:, comments: []) + def initialize(lbrace:, block_var:, statements:, location:) @lbrace = lbrace @block_var = block_var @statements = statements @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -2371,10 +2371,10 @@ class Break < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(arguments:, location:, comments: []) + def initialize(arguments:, location:) @arguments = arguments @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -2672,7 +2672,7 @@ def initialize( @message = message @arguments = arguments @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -2782,12 +2782,12 @@ class Case < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(keyword:, value:, consequent:, location:, comments: []) + def initialize(keyword:, value:, consequent:, location:) @keyword = keyword @value = value @consequent = consequent @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -2847,12 +2847,12 @@ class RAssign < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, operator:, pattern:, location:, comments: []) + def initialize(value:, operator:, pattern:, location:) @value = value @operator = operator @pattern = pattern @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -2943,12 +2943,12 @@ class ClassDeclaration < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(constant:, superclass:, bodystmt:, location:, comments: []) + def initialize(constant:, superclass:, bodystmt:, location:) @constant = constant @superclass = superclass @bodystmt = bodystmt @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -3049,11 +3049,11 @@ class Command < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(message:, arguments:, location:, comments: []) + def initialize(message:, arguments:, location:) @message = message @arguments = arguments @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -3151,7 +3151,7 @@ def initialize( @message = message @arguments = arguments @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -3323,10 +3323,10 @@ class Const < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -3364,11 +3364,11 @@ class ConstPathField < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(parent:, constant:, location:, comments: []) + def initialize(parent:, constant:, location:) @parent = parent @constant = constant @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -3411,11 +3411,11 @@ class ConstPathRef < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(parent:, constant:, location:, comments: []) + def initialize(parent:, constant:, location:) @parent = parent @constant = constant @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -3457,10 +3457,10 @@ class ConstRef < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(constant:, location:, comments: []) + def initialize(constant:, location:) @constant = constant @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -3493,10 +3493,10 @@ class CVar < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -3535,12 +3535,12 @@ class Def < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(name:, params:, bodystmt:, location:, comments: []) + def initialize(name:, params:, bodystmt:, location:) @name = name @params = params @bodystmt = bodystmt @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -3625,7 +3625,7 @@ def initialize( @paren = paren @statement = statement @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -3690,10 +3690,10 @@ class Defined < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -3761,7 +3761,7 @@ def initialize( @params = params @bodystmt = bodystmt @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -3831,12 +3831,12 @@ class DoBlock < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(keyword:, block_var:, bodystmt:, location:, comments: []) + def initialize(keyword:, block_var:, bodystmt:, location:) @keyword = keyword @block_var = block_var @bodystmt = bodystmt @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -3915,11 +3915,11 @@ class Dot2 < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(left:, right:, location:, comments: []) + def initialize(left:, right:, location:) @left = left @right = right @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -3963,11 +3963,11 @@ class Dot3 < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(left:, right:, location:, comments: []) + def initialize(left:, right:, location:) @left = left @right = right @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -4050,11 +4050,11 @@ class DynaSymbol < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(parts:, quote:, location:, comments: []) + def initialize(parts:, quote:, location:) @parts = parts @quote = quote @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -4161,11 +4161,11 @@ class Else < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(keyword:, statements:, location:, comments: []) + def initialize(keyword:, statements:, location:) @keyword = keyword @statements = statements @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -4231,7 +4231,7 @@ def initialize( @statements = statements @consequent = consequent @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -4435,11 +4435,11 @@ class Ensure < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(keyword:, statements:, location:, comments: []) + def initialize(keyword:, statements:, location:) @keyword = keyword @statements = statements @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -4490,10 +4490,10 @@ class ExcessedComma < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -4532,11 +4532,11 @@ class FCall < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, arguments:, location:, comments: []) + def initialize(value:, arguments:, location:) @value = value @arguments = arguments @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -4591,12 +4591,12 @@ class Field < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(parent:, operator:, name:, location:, comments: []) + def initialize(parent:, operator:, name:, location:) @parent = parent @operator = operator @name = name @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -4639,10 +4639,10 @@ class FloatLiteral < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -4688,13 +4688,13 @@ class FndPtn < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(constant:, left:, values:, right:, location:, comments: []) + def initialize(constant:, left:, values:, right:, location:) @constant = constant @left = left @values = values @right = right @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -4763,12 +4763,12 @@ class For < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(index:, collection:, statements:, location:, comments: []) + def initialize(index:, collection:, statements:, location:) @index = index @collection = collection @statements = statements @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -4822,10 +4822,10 @@ class GVar < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -4887,11 +4887,11 @@ def format(q) # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(lbrace:, assocs:, location:, comments: []) + def initialize(lbrace:, assocs:, location:) @lbrace = lbrace @assocs = assocs @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -4987,7 +4987,7 @@ def initialize( @dedent = dedent @parts = parts @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -5064,10 +5064,10 @@ class HeredocBeg < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -5103,10 +5103,10 @@ class HeredocEnd < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -5195,12 +5195,12 @@ def format(q) # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(constant:, keywords:, keyword_rest:, location:, comments: []) + def initialize(constant:, keywords:, keyword_rest:, location:) @constant = constant @keywords = keywords @keyword_rest = keyword_rest @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -5305,10 +5305,10 @@ class Ident < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -5574,7 +5574,7 @@ def initialize( @statements = statements @consequent = consequent @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -5619,12 +5619,12 @@ class IfOp < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(predicate:, truthy:, falsy:, location:, comments: []) + def initialize(predicate:, truthy:, falsy:, location:) @predicate = predicate @truthy = truthy @falsy = falsy @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -5761,11 +5761,11 @@ class IfMod < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(statement:, predicate:, location:, comments: []) + def initialize(statement:, predicate:, location:) @statement = statement @predicate = predicate @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -5803,10 +5803,10 @@ class Imaginary < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -5848,12 +5848,12 @@ class In < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(pattern:, statements:, consequent:, location:, comments: []) + def initialize(pattern:, statements:, consequent:, location:) @pattern = pattern @statements = statements @consequent = consequent @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -5909,10 +5909,10 @@ class Int < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -5953,10 +5953,10 @@ class IVar < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6001,11 +6001,11 @@ class Kw < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @name = value.to_sym @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6039,10 +6039,10 @@ class KwRestParam < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(name:, location:, comments: []) + def initialize(name:, location:) @name = name @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6085,10 +6085,10 @@ class Label < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6155,11 +6155,11 @@ class Lambda < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(params:, statements:, location:, comments: []) + def initialize(params:, statements:, location:) @params = params @statements = statements @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6263,11 +6263,11 @@ class LambdaVar < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(params:, locals:, location:, comments: []) + def initialize(params:, locals:, location:) @params = params @locals = locals @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6306,10 +6306,10 @@ class LBrace < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6339,10 +6339,10 @@ class LBracket < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6372,10 +6372,10 @@ class LParen < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6421,11 +6421,11 @@ class MAssign < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(target:, value:, location:, comments: []) + def initialize(target:, value:, location:) @target = target @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6468,11 +6468,11 @@ class MethodAddBlock < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(call:, block:, location:, comments: []) + def initialize(call:, block:, location:) @call = call @block = block @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6529,11 +6529,11 @@ class MLHS < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(parts:, comma: false, location:, comments: []) + def initialize(parts:, comma: false, location:) @parts = parts @comma = comma @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6573,11 +6573,11 @@ class MLHSParen < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(contents:, comma: false, location:, comments: []) + def initialize(contents:, comma: false, location:) @contents = contents @comma = comma @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6631,11 +6631,11 @@ class ModuleDeclaration < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(constant:, bodystmt:, location:, comments: []) + def initialize(constant:, bodystmt:, location:) @constant = constant @bodystmt = bodystmt @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6701,10 +6701,10 @@ class MRHS < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(parts:, location:, comments: []) + def initialize(parts:, location:) @parts = parts @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6750,10 +6750,10 @@ class Next < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(arguments:, location:, comments: []) + def initialize(arguments:, location:) @arguments = arguments @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6790,11 +6790,11 @@ class Op < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @name = value.to_sym @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -6835,12 +6835,12 @@ class OpAssign < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(target:, operator:, value:, location:, comments: []) + def initialize(target:, operator:, value:, location:) @target = target @operator = operator @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -7081,7 +7081,7 @@ def initialize( @keyword_rest = keyword_rest @block = block @location = location - @comments = comments + @comments = [] end # Params nodes are the most complicated in the tree. Occasionally you want @@ -7187,11 +7187,11 @@ class Paren < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(lparen:, contents:, location:, comments: []) + def initialize(lparen:, contents:, location:) @lparen = lparen @contents = contents @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -7239,10 +7239,10 @@ class Period < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -7272,10 +7272,10 @@ class Program < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(statements:, location:, comments: []) + def initialize(statements:, location:) @statements = statements @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -7316,11 +7316,11 @@ class QSymbols < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(beginning:, elements:, location:, comments: []) + def initialize(beginning:, elements:, location:) @beginning = beginning @elements = elements @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -7410,11 +7410,11 @@ class QWords < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(beginning:, elements:, location:, comments: []) + def initialize(beginning:, elements:, location:) @beginning = beginning @elements = elements @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -7501,10 +7501,10 @@ class RationalLiteral < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -7587,10 +7587,10 @@ class Redo < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -7732,12 +7732,12 @@ class RegexpLiteral < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(beginning:, ending:, parts:, location:, comments: []) + def initialize(beginning:, ending:, parts:, location:) @beginning = beginning @ending = ending @parts = parts @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -7843,11 +7843,11 @@ class RescueEx < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(exceptions:, variable:, location:, comments: []) + def initialize(exceptions:, variable:, location:) @exceptions = exceptions @variable = variable @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -7919,7 +7919,7 @@ def initialize( @statements = statements @consequent = consequent @location = location - @comments = comments + @comments = [] end def bind_end(end_char, end_column) @@ -8004,11 +8004,11 @@ class RescueMod < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(statement:, value:, location:, comments: []) + def initialize(statement:, value:, location:) @statement = statement @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -8061,10 +8061,10 @@ class RestParam < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(name:, location:, comments: []) + def initialize(name:, location:) @name = name @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -8098,10 +8098,10 @@ class Retry < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -8134,10 +8134,10 @@ class Return < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(arguments:, location:, comments: []) + def initialize(arguments:, location:) @arguments = arguments @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -8170,10 +8170,10 @@ class Return0 < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -8237,11 +8237,11 @@ class SClass < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(target:, bodystmt:, location:, comments: []) + def initialize(target:, bodystmt:, location:) @target = target @bodystmt = bodystmt @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -8294,11 +8294,11 @@ class Statements < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(parser, body:, location:, comments: []) + def initialize(parser, body:, location:) @parser = parser @body = body @location = location - @comments = comments + @comments = [] end def bind(start_char, start_column, end_char, end_column) @@ -8498,11 +8498,11 @@ class StringConcat < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(left:, right:, location:, comments: []) + def initialize(left:, right:, location:) @left = left @right = right @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -8544,10 +8544,10 @@ class StringDVar < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(variable:, location:, comments: []) + def initialize(variable:, location:) @variable = variable @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -8584,10 +8584,10 @@ class StringEmbExpr < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(statements:, location:, comments: []) + def initialize(statements:, location:) @statements = statements @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -8646,11 +8646,11 @@ class StringLiteral < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(parts:, quote:, location:, comments: []) + def initialize(parts:, quote:, location:) @parts = parts @quote = quote @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -8721,10 +8721,10 @@ class Super < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(arguments:, location:, comments: []) + def initialize(arguments:, location:) @arguments = arguments @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -8838,10 +8838,10 @@ class SymbolLiteral < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -8878,11 +8878,11 @@ class Symbols < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(beginning:, elements:, location:, comments: []) + def initialize(beginning:, elements:, location:) @beginning = beginning @elements = elements @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -9031,10 +9031,10 @@ class TopConstField < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(constant:, location:, comments: []) + def initialize(constant:, location:) @constant = constant @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -9069,10 +9069,10 @@ class TopConstRef < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(constant:, location:, comments: []) + def initialize(constant:, location:) @constant = constant @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -9144,10 +9144,10 @@ class TStringContent < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def match?(pattern) @@ -9222,11 +9222,11 @@ class Not < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(statement:, parentheses:, location:, comments: []) + def initialize(statement:, parentheses:, location:) @statement = statement @parentheses = parentheses @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -9288,11 +9288,11 @@ class Unary < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(operator:, statement:, location:, comments: []) + def initialize(operator:, statement:, location:) @operator = operator @statement = statement @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -9355,10 +9355,10 @@ def format(q) # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(symbols:, location:, comments: []) + def initialize(symbols:, location:) @symbols = symbols @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -9417,7 +9417,7 @@ def initialize( @statements = statements @consequent = consequent @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -9459,11 +9459,11 @@ class UnlessMod < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(statement:, predicate:, location:, comments: []) + def initialize(statement:, predicate:, location:) @statement = statement @predicate = predicate @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -9556,11 +9556,11 @@ class Until < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(predicate:, statements:, location:, comments: []) + def initialize(predicate:, statements:, location:) @predicate = predicate @statements = statements @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -9612,11 +9612,11 @@ class UntilMod < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(statement:, predicate:, location:, comments: []) + def initialize(statement:, predicate:, location:) @statement = statement @predicate = predicate @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -9678,11 +9678,11 @@ class VarAlias < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(left:, right:, location:, comments: []) + def initialize(left:, right:, location:) @left = left @right = right @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -9722,10 +9722,10 @@ class VarField < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -9766,10 +9766,10 @@ class VarRef < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -9830,10 +9830,10 @@ class PinnedVarRef < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -9870,10 +9870,10 @@ class VCall < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -9910,9 +9910,9 @@ class VoidStmt < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(location:, comments: []) + def initialize(location:) @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -9963,7 +9963,7 @@ def initialize( @statements = statements @consequent = consequent @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -10055,11 +10055,11 @@ class While < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(predicate:, statements:, location:, comments: []) + def initialize(predicate:, statements:, location:) @predicate = predicate @statements = statements @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -10111,11 +10111,11 @@ class WhileMod < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(statement:, predicate:, location:, comments: []) + def initialize(statement:, predicate:, location:) @statement = statement @predicate = predicate @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -10177,10 +10177,10 @@ class Word < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(parts:, location:, comments: []) + def initialize(parts:, location:) @parts = parts @location = location - @comments = comments + @comments = [] end def match?(pattern) @@ -10220,11 +10220,11 @@ class Words < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(beginning:, elements:, location:, comments: []) + def initialize(beginning:, elements:, location:) @beginning = beginning @elements = elements @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -10342,10 +10342,10 @@ class XStringLiteral < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(parts:, location:, comments: []) + def initialize(parts:, location:) @parts = parts @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -10380,10 +10380,10 @@ class Yield < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(arguments:, location:, comments: []) + def initialize(arguments:, location:) @arguments = arguments @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -10430,10 +10430,10 @@ class Yield0 < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) @@ -10466,10 +10466,10 @@ class ZSuper < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:, comments: []) + def initialize(value:, location:) @value = value @location = location - @comments = comments + @comments = [] end def accept(visitor) diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index 61a7ca57..abd9bd60 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -2104,17 +2104,20 @@ def on_lambda(params, statements) location = params.contents.location location = location.to(locals.last.location) if locals.any? - Paren.new( - lparen: params.lparen, - contents: - LambdaVar.new( - params: params.contents, - locals: locals, - location: location - ), - location: params.location, - comments: params.comments - ) + node = + Paren.new( + lparen: params.lparen, + contents: + LambdaVar.new( + params: params.contents, + locals: locals, + location: location + ), + location: params.location + ) + + node.comments.concat(params.comments) + node when Params # In this case we've gotten to the <3.2 plain set of parameters. In # this case there cannot be lambda locals, so we will wrap the @@ -2199,8 +2202,7 @@ def lambda_locals(source) on_comma: :item, on_rparen: :final }, - final: { - } + final: {} } tokens[(index + 1)..].each_with_object([]) do |token, locals| From 38a1b036593e1a220a6666817d3c655b432f4656 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 10:46:48 -0400 Subject: [PATCH 04/35] Fold IfMod into If and UnlessMod into Unless --- CHANGELOG.md | 5 + lib/syntax_tree/node.rb | 232 ++++++----------------- lib/syntax_tree/parser.rb | 14 +- lib/syntax_tree/visitor.rb | 6 - lib/syntax_tree/visitor/field_visitor.rb | 16 -- test/node_test.rb | 6 +- 6 files changed, 77 insertions(+), 202 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45a06c13..5d944f7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ## [Unreleased] +### Changed + +- Nodes no longer have a `comments:` keyword on their initializers. By default, they initialize to an empty array. If you were previously passing comments into the initializer, you should now create the node first, then call `node.comments.concat` to add your comments. +- `IfMod` and `UnlessMod` are no longer nodes. Instead, they have been folded into `If` and `Unless`, respectively. The `If` and `Unless` nodes now have a `modifier?` method to tell you if they were original found in the modifier form. + ## [4.3.0] - 2022-10-28 ### Added diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index a1e5c0ae..2f23e9a1 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -2071,8 +2071,7 @@ def forced_brace_bounds?(q) when Paren, Statements # If we hit certain breakpoints then we know we're safe. return false - when If, IfMod, IfOp, Unless, UnlessMod, While, WhileMod, Until, - UntilMod + when If, IfOp, Unless, While, WhileMod, Until, UntilMod return true if parent.predicate == previous end @@ -3884,7 +3883,7 @@ def format(q) q.format(left) if left case q.parent - when If, IfMod, Unless, UnlessMod + when If, Unless q.text(" #{operator} ") else q.text(operator) @@ -5398,10 +5397,10 @@ def call(q, node) # and default instead to breaking them into multiple lines. def ternaryable?(statement) case statement - when Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfMod, - IfOp, Lambda, MAssign, Next, OpAssign, RescueMod, Return, Return0, - Super, Undef, Unless, UnlessMod, Until, UntilMod, VarAlias, - VoidStmt, While, WhileMod, Yield, Yield0, ZSuper + when Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfOp, + Lambda, MAssign, Next, OpAssign, RescueMod, Return, Return0, Super, + Undef, Unless, Until, UntilMod, VarAlias, VoidStmt, While, + WhileMod, Yield, Yield0, ZSuper # This is a list of nodes that should not be allowed to be a part of a # ternary clause. false @@ -5432,41 +5431,60 @@ def initialize(keyword, node) end def format(q) - # If we can transform this node into a ternary, then we're going to print - # a special version that uses the ternary operator if it fits on one line. - if Ternaryable.call(q, node) - format_ternary(q) - return - end + if node.modifier? + statement = node.statements.body[0] - # If the predicate of the conditional contains an assignment (in which - # case we can't know for certain that that assignment doesn't impact the - # statements inside the conditional) then we can't use the modifier form - # and we must use the block form. - if ContainsAssignment.call(node.predicate) - format_break(q, force: true) - return - end - - if node.consequent || node.statements.empty? || contains_conditional? - q.group { format_break(q, force: true) } + if ContainsAssignment.call(statement) || q.parent.is_a?(In) + q.group { format_flat(q) } + else + q.group { q.if_break { format_break(q, force: false) }.if_flat { format_flat(q) } } + end else - q.group do - q - .if_break { format_break(q, force: false) } - .if_flat do - Parentheses.flat(q) do - q.format(node.statements) - q.text(" #{keyword} ") - q.format(node.predicate) + # If we can transform this node into a ternary, then we're going to + # print a special version that uses the ternary operator if it fits on + # one line. + if Ternaryable.call(q, node) + format_ternary(q) + return + end + + # If the predicate of the conditional contains an assignment (in which + # case we can't know for certain that that assignment doesn't impact the + # statements inside the conditional) then we can't use the modifier form + # and we must use the block form. + if ContainsAssignment.call(node.predicate) + format_break(q, force: true) + return + end + + if node.consequent || node.statements.empty? || contains_conditional? + q.group { format_break(q, force: true) } + else + q.group do + q + .if_break { format_break(q, force: false) } + .if_flat do + Parentheses.flat(q) do + q.format(node.statements) + q.text(" #{keyword} ") + q.format(node.predicate) + end end - end + end end end end private + def format_flat(q) + Parentheses.flat(q) do + q.format(node.statements.body[0]) + q.text(" #{keyword} ") + q.format(node.predicate) + end + end + def format_break(q, force:) q.text("#{keyword} ") q.nest(keyword.length + 1) { q.format(node.predicate) } @@ -5537,7 +5555,7 @@ def contains_conditional? return false if statements.length != 1 case statements.first - when If, IfMod, IfOp, Unless, UnlessMod + when If, IfOp, Unless true else false @@ -5600,6 +5618,11 @@ def deconstruct_keys(_keys) def format(q) ConditionalFormatter.new("if", self).format(q) end + + # Checks if the node was originally found in the modifier form. + def modifier? + predicate.location.start_char > statements.location.start_char + end end # IfOp represents a ternary clause. @@ -5649,10 +5672,9 @@ def deconstruct_keys(_keys) def format(q) force_flat = [ - Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfMod, IfOp, - Lambda, MAssign, Next, OpAssign, RescueMod, Return, Return0, Super, - Undef, Unless, UnlessMod, UntilMod, VarAlias, VoidStmt, WhileMod, Yield, - Yield0, ZSuper + Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfOp, Lambda, + MAssign, Next, OpAssign, RescueMod, Return, Return0, Super, Undef, + Unless, UntilMod, VarAlias, VoidStmt, WhileMod, Yield, Yield0, ZSuper ] if q.parent.is_a?(Paren) || force_flat.include?(truthy.class) || @@ -5704,94 +5726,6 @@ def format_flat(q) end end - # Formats an IfMod or UnlessMod node. - class ConditionalModFormatter - # [String] the keyword associated with this conditional - attr_reader :keyword - - # [IfMod | UnlessMod] the node that is being formatted - attr_reader :node - - def initialize(keyword, node) - @keyword = keyword - @node = node - end - - def format(q) - if ContainsAssignment.call(node.statement) || q.parent.is_a?(In) - q.group { format_flat(q) } - else - q.group { q.if_break { format_break(q) }.if_flat { format_flat(q) } } - end - end - - private - - def format_break(q) - q.text("#{keyword} ") - q.nest(keyword.length + 1) { q.format(node.predicate) } - q.indent do - q.breakable_space - q.format(node.statement) - end - q.breakable_space - q.text("end") - end - - def format_flat(q) - Parentheses.flat(q) do - q.format(node.statement) - q.text(" #{keyword} ") - q.format(node.predicate) - end - end - end - - # IfMod represents the modifier form of an +if+ statement. - # - # expression if predicate - # - class IfMod < Node - # [untyped] the expression to be executed - attr_reader :statement - - # [untyped] the expression to be checked - attr_reader :predicate - - # [Array[ Comment | EmbDoc ]] the comments attached to this node - attr_reader :comments - - def initialize(statement:, predicate:, location:) - @statement = statement - @predicate = predicate - @location = location - @comments = [] - end - - def accept(visitor) - visitor.visit_if_mod(self) - end - - def child_nodes - [statement, predicate] - end - - alias deconstruct child_nodes - - def deconstruct_keys(_keys) - { - statement: statement, - predicate: predicate, - location: location, - comments: comments - } - end - - def format(q) - ConditionalModFormatter.new("if", self).format(q) - end - end - # Imaginary represents an imaginary number literal. # # 1i @@ -9443,50 +9377,10 @@ def deconstruct_keys(_keys) def format(q) ConditionalFormatter.new("unless", self).format(q) end - end - - # UnlessMod represents the modifier form of an +unless+ statement. - # - # expression unless predicate - # - class UnlessMod < Node - # [untyped] the expression to be executed - attr_reader :statement - - # [untyped] the expression to be checked - attr_reader :predicate - - # [Array[ Comment | EmbDoc ]] the comments attached to this node - attr_reader :comments - - def initialize(statement:, predicate:, location:) - @statement = statement - @predicate = predicate - @location = location - @comments = [] - end - - def accept(visitor) - visitor.visit_unless_mod(self) - end - - def child_nodes - [statement, predicate] - end - - alias deconstruct child_nodes - - def deconstruct_keys(_keys) - { - statement: statement, - predicate: predicate, - location: location, - comments: comments - } - end - def format(q) - ConditionalModFormatter.new("unless", self).format(q) + # Checks if the node was originally found in the modifier form. + def modifier? + predicate.location.start_char > statements.location.start_char end end diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index abd9bd60..c4d6f8e9 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -1911,13 +1911,14 @@ def on_ifop(predicate, truthy, falsy) end # :call-seq: - # on_if_mod: (untyped predicate, untyped statement) -> IfMod + # on_if_mod: (untyped predicate, untyped statement) -> If def on_if_mod(predicate, statement) consume_keyword(:if) - IfMod.new( - statement: statement, + If.new( predicate: predicate, + statements: Statements.new(self, body: [statement], location: statement.location), + consequent: nil, location: statement.location.to(predicate.location) ) end @@ -3586,13 +3587,14 @@ def on_unless(predicate, statements, consequent) end # :call-seq: - # on_unless_mod: (untyped predicate, untyped statement) -> UnlessMod + # on_unless_mod: (untyped predicate, untyped statement) -> Unless def on_unless_mod(predicate, statement) consume_keyword(:unless) - UnlessMod.new( - statement: statement, + Unless.new( predicate: predicate, + statements: Statements.new(self, body: [statement], location: statement.location), + consequent: nil, location: statement.location.to(predicate.location) ) end diff --git a/lib/syntax_tree/visitor.rb b/lib/syntax_tree/visitor.rb index e3b52077..0ea83e7b 100644 --- a/lib/syntax_tree/visitor.rb +++ b/lib/syntax_tree/visitor.rb @@ -206,9 +206,6 @@ class Visitor < BasicVisitor # Visit an If node. alias visit_if visit_child_nodes - # Visit an IfMod node. - alias visit_if_mod visit_child_nodes - # Visit an IfOp node. alias visit_if_op visit_child_nodes @@ -431,9 +428,6 @@ class Visitor < BasicVisitor # Visit an Unless node. alias visit_unless visit_child_nodes - # Visit an UnlessMod node. - alias visit_unless_mod visit_child_nodes - # Visit an Until node. alias visit_until visit_child_nodes diff --git a/lib/syntax_tree/visitor/field_visitor.rb b/lib/syntax_tree/visitor/field_visitor.rb index 6c5c6139..aa1b80ab 100644 --- a/lib/syntax_tree/visitor/field_visitor.rb +++ b/lib/syntax_tree/visitor/field_visitor.rb @@ -523,14 +523,6 @@ def visit_if(node) end end - def visit_if_mod(node) - node(node, "if_mod") do - field("statement", node.statement) - field("predicate", node.predicate) - comments(node) - end - end - def visit_if_op(node) node(node, "if_op") do field("predicate", node.predicate) @@ -982,14 +974,6 @@ def visit_unless(node) end end - def visit_unless_mod(node) - node(node, "unless_mod") do - field("statement", node.statement) - field("predicate", node.predicate) - comments(node) - end - end - def visit_until(node) node(node, "until") do field("predicate", node.predicate) diff --git a/test/node_test.rb b/test/node_test.rb index ce26f9ea..8400fa7c 100644 --- a/test/node_test.rb +++ b/test/node_test.rb @@ -583,7 +583,7 @@ def test_if_op end def test_if_mod - assert_node(IfMod, "expression if predicate") + assert_node(If, "expression if predicate") end def test_imaginary @@ -926,10 +926,6 @@ def test_unless assert_node(Unless, "unless value then else end") end - def test_unless_mod - assert_node(UnlessMod, "expression unless predicate") - end - def test_until assert_node(Until, "until value do end") end From b97b9cb03f65a6156657b19b656124a79b276863 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 11:02:50 -0400 Subject: [PATCH 05/35] Fold UntilMod and WhileMod --- CHANGELOG.md | 1 + lib/syntax_tree/node.rb | 226 +++++------------------ lib/syntax_tree/parser.rb | 12 +- lib/syntax_tree/visitor.rb | 6 - lib/syntax_tree/visitor/field_visitor.rb | 16 -- test/node_test.rb | 4 +- 6 files changed, 60 insertions(+), 205 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d944f7a..faed7811 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - Nodes no longer have a `comments:` keyword on their initializers. By default, they initialize to an empty array. If you were previously passing comments into the initializer, you should now create the node first, then call `node.comments.concat` to add your comments. - `IfMod` and `UnlessMod` are no longer nodes. Instead, they have been folded into `If` and `Unless`, respectively. The `If` and `Unless` nodes now have a `modifier?` method to tell you if they were original found in the modifier form. +- `WhileMod` and `UntilMod` are no longer nodes. Instead, they have been folded into `While` and `Until`, respectively. The `While` and `Until` nodes now have a `modifier?` method to tell you if they were originally found in the modifier form. ## [4.3.0] - 2022-10-28 diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index 2f23e9a1..71d5e0d8 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -2071,7 +2071,7 @@ def forced_brace_bounds?(q) when Paren, Statements # If we hit certain breakpoints then we know we're safe. return false - when If, IfOp, Unless, While, WhileMod, Until, UntilMod + when If, IfOp, Unless, While, Until return true if parent.predicate == previous end @@ -5399,8 +5399,8 @@ def ternaryable?(statement) case statement when Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfOp, Lambda, MAssign, Next, OpAssign, RescueMod, Return, Return0, Super, - Undef, Unless, Until, UntilMod, VarAlias, VoidStmt, While, - WhileMod, Yield, Yield0, ZSuper + Undef, Unless, Until, VarAlias, VoidStmt, While, Yield, Yield0, + ZSuper # This is a list of nodes that should not be allowed to be a part of a # ternary clause. false @@ -5674,7 +5674,7 @@ def format(q) force_flat = [ Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfOp, Lambda, MAssign, Next, OpAssign, RescueMod, Return, Return0, Super, Undef, - Unless, UntilMod, VarAlias, VoidStmt, WhileMod, Yield, Yield0, ZSuper + Unless, VarAlias, VoidStmt, Yield, Yield0, ZSuper ] if q.parent.is_a?(Paren) || force_flat.include?(truthy.class) || @@ -9384,40 +9384,60 @@ def modifier? end end - # Formats an Until, UntilMod, While, or WhileMod node. + # Formats an Until or While node. class LoopFormatter # [String] the name of the keyword used for this loop attr_reader :keyword - # [Until | UntilMod | While | WhileMod] the node that is being formatted + # [Until | While] the node that is being formatted attr_reader :node - # [untyped] the statements associated with the node - attr_reader :statements - - def initialize(keyword, node, statements) + def initialize(keyword, node) @keyword = keyword @node = node - @statements = statements end def format(q) - if ContainsAssignment.call(node.predicate) + # If we're in the modifier form and we're modifying a `begin`, then this + # is a special case where we need to explicitly use the modifier form + # because otherwise the semantic meaning changes. This looks like: + # + # begin + # foo + # end while bar + # + # Also, if the statement of the modifier includes an assignment, then we + # can't know for certain that it won't impact the predicate, so we need to + # force it to stay as it is. This looks like: + # + # foo = bar while foo + # + if node.modifier? && (statement = node.statements.body.first) && (statement.is_a?(Begin) || ContainsAssignment.call(statement)) + q.format(statement) + q.text(" #{keyword} ") + q.format(node.predicate) + elsif node.statements.empty? + q.group do + q.text("#{keyword} ") + q.nest(keyword.length + 1) { q.format(node.predicate) } + q.breakable_force + q.text("end") + end + elsif ContainsAssignment.call(node.predicate) format_break(q) q.break_parent - return - end - - q.group do - q - .if_break { format_break(q) } - .if_flat do - Parentheses.flat(q) do - q.format(statements) - q.text(" #{keyword} ") - q.format(node.predicate) + else + q.group do + q + .if_break { format_break(q) } + .if_flat do + Parentheses.flat(q) do + q.format(node.statements) + q.text(" #{keyword} ") + q.format(node.predicate) + end end - end + end end end @@ -9428,7 +9448,7 @@ def format_break(q) q.nest(keyword.length + 1) { q.format(node.predicate) } q.indent do q.breakable_empty - q.format(statements) + q.format(node.statements) end q.breakable_empty q.text("end") @@ -9477,83 +9497,11 @@ def deconstruct_keys(_keys) end def format(q) - if statements.empty? - keyword = "until " - - q.group do - q.text(keyword) - q.nest(keyword.length) { q.format(predicate) } - q.breakable_force - q.text("end") - end - else - LoopFormatter.new("until", self, statements).format(q) - end + LoopFormatter.new("until", self).format(q) end - end - # UntilMod represents the modifier form of a +until+ loop. - # - # expression until predicate - # - class UntilMod < Node - # [untyped] the expression to be executed - attr_reader :statement - - # [untyped] the expression to be checked - attr_reader :predicate - - # [Array[ Comment | EmbDoc ]] the comments attached to this node - attr_reader :comments - - def initialize(statement:, predicate:, location:) - @statement = statement - @predicate = predicate - @location = location - @comments = [] - end - - def accept(visitor) - visitor.visit_until_mod(self) - end - - def child_nodes - [statement, predicate] - end - - alias deconstruct child_nodes - - def deconstruct_keys(_keys) - { - statement: statement, - predicate: predicate, - location: location, - comments: comments - } - end - - def format(q) - # If we're in the modifier form and we're modifying a `begin`, then this - # is a special case where we need to explicitly use the modifier form - # because otherwise the semantic meaning changes. This looks like: - # - # begin - # foo - # end until bar - # - # Also, if the statement of the modifier includes an assignment, then we - # can't know for certain that it won't impact the predicate, so we need to - # force it to stay as it is. This looks like: - # - # foo = bar until foo - # - if statement.is_a?(Begin) || ContainsAssignment.call(statement) - q.format(statement) - q.text(" until ") - q.format(predicate) - else - LoopFormatter.new("until", self, statement).format(q) - end + def modifier? + predicate.location.start_char > statements.location.start_char end end @@ -9976,83 +9924,11 @@ def deconstruct_keys(_keys) end def format(q) - if statements.empty? - keyword = "while " - - q.group do - q.text(keyword) - q.nest(keyword.length) { q.format(predicate) } - q.breakable_force - q.text("end") - end - else - LoopFormatter.new("while", self, statements).format(q) - end - end - end - - # WhileMod represents the modifier form of a +while+ loop. - # - # expression while predicate - # - class WhileMod < Node - # [untyped] the expression to be executed - attr_reader :statement - - # [untyped] the expression to be checked - attr_reader :predicate - - # [Array[ Comment | EmbDoc ]] the comments attached to this node - attr_reader :comments - - def initialize(statement:, predicate:, location:) - @statement = statement - @predicate = predicate - @location = location - @comments = [] - end - - def accept(visitor) - visitor.visit_while_mod(self) - end - - def child_nodes - [statement, predicate] - end - - alias deconstruct child_nodes - - def deconstruct_keys(_keys) - { - statement: statement, - predicate: predicate, - location: location, - comments: comments - } + LoopFormatter.new("while", self).format(q) end - def format(q) - # If we're in the modifier form and we're modifying a `begin`, then this - # is a special case where we need to explicitly use the modifier form - # because otherwise the semantic meaning changes. This looks like: - # - # begin - # foo - # end while bar - # - # Also, if the statement of the modifier includes an assignment, then we - # can't know for certain that it won't impact the predicate, so we need to - # force it to stay as it is. This looks like: - # - # foo = bar while foo - # - if statement.is_a?(Begin) || ContainsAssignment.call(statement) - q.format(statement) - q.text(" while ") - q.format(predicate) - else - LoopFormatter.new("while", self, statement).format(q) - end + def modifier? + predicate.location.start_char > statements.location.start_char end end diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index c4d6f8e9..2b5231d2 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -3630,13 +3630,13 @@ def on_until(predicate, statements) end # :call-seq: - # on_until_mod: (untyped predicate, untyped statement) -> UntilMod + # on_until_mod: (untyped predicate, untyped statement) -> Until def on_until_mod(predicate, statement) consume_keyword(:until) - UntilMod.new( - statement: statement, + Until.new( predicate: predicate, + statements: Statements.new(self, body: [statement], location: statement.location), location: statement.location.to(predicate.location) ) end @@ -3756,13 +3756,13 @@ def on_while(predicate, statements) end # :call-seq: - # on_while_mod: (untyped predicate, untyped statement) -> WhileMod + # on_while_mod: (untyped predicate, untyped statement) -> While def on_while_mod(predicate, statement) consume_keyword(:while) - WhileMod.new( - statement: statement, + While.new( predicate: predicate, + statements: Statements.new(self, body: [statement], location: statement.location), location: statement.location.to(predicate.location) ) end diff --git a/lib/syntax_tree/visitor.rb b/lib/syntax_tree/visitor.rb index 0ea83e7b..efbd47c0 100644 --- a/lib/syntax_tree/visitor.rb +++ b/lib/syntax_tree/visitor.rb @@ -431,9 +431,6 @@ class Visitor < BasicVisitor # Visit an Until node. alias visit_until visit_child_nodes - # Visit an UntilMod node. - alias visit_until_mod visit_child_nodes - # Visit a VarAlias node. alias visit_var_alias visit_child_nodes @@ -455,9 +452,6 @@ class Visitor < BasicVisitor # Visit a While node. alias visit_while visit_child_nodes - # Visit a WhileMod node. - alias visit_while_mod visit_child_nodes - # Visit a Word node. alias visit_word visit_child_nodes diff --git a/lib/syntax_tree/visitor/field_visitor.rb b/lib/syntax_tree/visitor/field_visitor.rb index aa1b80ab..853fe4c7 100644 --- a/lib/syntax_tree/visitor/field_visitor.rb +++ b/lib/syntax_tree/visitor/field_visitor.rb @@ -982,14 +982,6 @@ def visit_until(node) end end - def visit_until_mod(node) - node(node, "until_mod") do - field("statement", node.statement) - field("predicate", node.predicate) - comments(node) - end - end - def visit_var_alias(node) node(node, "var_alias") do field("left", node.left) @@ -1040,14 +1032,6 @@ def visit_while(node) end end - def visit_while_mod(node) - node(node, "while_mod") do - field("statement", node.statement) - field("predicate", node.predicate) - comments(node) - end - end - def visit_word(node) node(node, "word") do list("parts", node.parts) diff --git a/test/node_test.rb b/test/node_test.rb index 8400fa7c..1419e151 100644 --- a/test/node_test.rb +++ b/test/node_test.rb @@ -931,7 +931,7 @@ def test_until end def test_until_mod - assert_node(UntilMod, "expression until predicate") + assert_node(Until, "expression until predicate") end def test_var_alias @@ -981,7 +981,7 @@ def test_while end def test_while_mod - assert_node(WhileMod, "expression while predicate") + assert_node(While, "expression while predicate") end def test_word From 672abb2d6c86f1a0ac2a8b04743dfdda0bd3b7ad Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 11:06:58 -0400 Subject: [PATCH 06/35] Fold VarAlias into Alias --- CHANGELOG.md | 1 + lib/syntax_tree/node.rb | 61 ++++-------------------- lib/syntax_tree/parser.rb | 4 +- lib/syntax_tree/visitor.rb | 3 -- lib/syntax_tree/visitor/field_visitor.rb | 8 ---- test/node_test.rb | 2 +- 6 files changed, 13 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index faed7811..e04aaa18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - Nodes no longer have a `comments:` keyword on their initializers. By default, they initialize to an empty array. If you were previously passing comments into the initializer, you should now create the node first, then call `node.comments.concat` to add your comments. - `IfMod` and `UnlessMod` are no longer nodes. Instead, they have been folded into `If` and `Unless`, respectively. The `If` and `Unless` nodes now have a `modifier?` method to tell you if they were original found in the modifier form. - `WhileMod` and `UntilMod` are no longer nodes. Instead, they have been folded into `While` and `Until`, respectively. The `While` and `Until` nodes now have a `modifier?` method to tell you if they were originally found in the modifier form. +- `VarAlias` is no longer a node. Instead it has been folded into the `Alias` node. The `Alias` node now has a `var_alias?` method to tell you if it is aliasing a global variable. ## [4.3.0] - 2022-10-28 diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index 71d5e0d8..1c69026b 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -359,7 +359,7 @@ class Alias < Node # Formats an argument to the alias keyword. For symbol literals it uses the # value of the symbol directly to look like bare words. class AliasArgumentFormatter - # [DynaSymbol | SymbolLiteral] the argument being passed to alias + # [Backref | DynaSymbol | GVar | SymbolLiteral] the argument being passed to alias attr_reader :argument def initialize(argument) @@ -383,10 +383,10 @@ def format(q) end end - # [DynaSymbol | SymbolLiteral] the new name of the method + # [DynaSymbol | GVar | SymbolLiteral] the new name of the method attr_reader :left - # [DynaSymbol | SymbolLiteral] the old name of the method + # [Backref | DynaSymbol | GVar | SymbolLiteral] the old name of the method attr_reader :right # [Array[ Comment | EmbDoc ]] the comments attached to this node @@ -428,6 +428,10 @@ def format(q) end end end + + def var_alias? + left.is_a?(GVar) + end end # ARef represents when you're pulling a value out of a collection at a @@ -5399,8 +5403,7 @@ def ternaryable?(statement) case statement when Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfOp, Lambda, MAssign, Next, OpAssign, RescueMod, Return, Return0, Super, - Undef, Unless, Until, VarAlias, VoidStmt, While, Yield, Yield0, - ZSuper + Undef, Unless, Until, VoidStmt, While, Yield, Yield0, ZSuper # This is a list of nodes that should not be allowed to be a part of a # ternary clause. false @@ -5674,7 +5677,7 @@ def format(q) force_flat = [ Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfOp, Lambda, MAssign, Next, OpAssign, RescueMod, Return, Return0, Super, Undef, - Unless, VarAlias, VoidStmt, Yield, Yield0, ZSuper + Unless, VoidStmt, Yield, Yield0, ZSuper ] if q.parent.is_a?(Paren) || force_flat.include?(truthy.class) || @@ -9505,52 +9508,6 @@ def modifier? end end - # VarAlias represents when you're using the +alias+ keyword with global - # variable arguments. - # - # alias $new $old - # - class VarAlias < Node - # [GVar] the new alias of the variable - attr_reader :left - - # [Backref | GVar] the current name of the variable to be aliased - attr_reader :right - - # [Array[ Comment | EmbDoc ]] the comments attached to this node - attr_reader :comments - - def initialize(left:, right:, location:) - @left = left - @right = right - @location = location - @comments = [] - end - - def accept(visitor) - visitor.visit_var_alias(self) - end - - def child_nodes - [left, right] - end - - alias deconstruct child_nodes - - def deconstruct_keys(_keys) - { left: left, right: right, location: location, comments: comments } - end - - def format(q) - keyword = "alias " - - q.text(keyword) - q.format(left) - q.text(" ") - q.format(right) - end - end - # VarField represents a variable that is being assigned a value. As such, it # is always a child of an assignment type node. # diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index 2b5231d2..a28bb296 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -3642,11 +3642,11 @@ def on_until_mod(predicate, statement) end # :call-seq: - # on_var_alias: (GVar left, (Backref | GVar) right) -> VarAlias + # on_var_alias: (GVar left, (Backref | GVar) right) -> Alias def on_var_alias(left, right) keyword = consume_keyword(:alias) - VarAlias.new( + Alias.new( left: left, right: right, location: keyword.location.to(right.location) diff --git a/lib/syntax_tree/visitor.rb b/lib/syntax_tree/visitor.rb index efbd47c0..06fa7e17 100644 --- a/lib/syntax_tree/visitor.rb +++ b/lib/syntax_tree/visitor.rb @@ -431,9 +431,6 @@ class Visitor < BasicVisitor # Visit an Until node. alias visit_until visit_child_nodes - # Visit a VarAlias node. - alias visit_var_alias visit_child_nodes - # Visit a VarField node. alias visit_var_field visit_child_nodes diff --git a/lib/syntax_tree/visitor/field_visitor.rb b/lib/syntax_tree/visitor/field_visitor.rb index 853fe4c7..c5b00c50 100644 --- a/lib/syntax_tree/visitor/field_visitor.rb +++ b/lib/syntax_tree/visitor/field_visitor.rb @@ -982,14 +982,6 @@ def visit_until(node) end end - def visit_var_alias(node) - node(node, "var_alias") do - field("left", node.left) - field("right", node.right) - comments(node) - end - end - def visit_var_field(node) node(node, "var_field") do field("value", node.value) diff --git a/test/node_test.rb b/test/node_test.rb index 1419e151..05ae2254 100644 --- a/test/node_test.rb +++ b/test/node_test.rb @@ -935,7 +935,7 @@ def test_until_mod end def test_var_alias - assert_node(VarAlias, "alias $new $old") + assert_node(Alias, "alias $new $old") end def test_var_field From 7f04f53fd2c0a7f24c404dc10b9b0302adf01f18 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 11:10:01 -0400 Subject: [PATCH 07/35] Fold Yield0 into Yield --- CHANGELOG.md | 1 + lib/syntax_tree/node.rb | 47 ++++-------------------- lib/syntax_tree/parser.rb | 4 +- lib/syntax_tree/visitor.rb | 3 -- lib/syntax_tree/visitor/field_visitor.rb | 4 -- test/node_test.rb | 2 +- 6 files changed, 12 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e04aaa18..148da6f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - `IfMod` and `UnlessMod` are no longer nodes. Instead, they have been folded into `If` and `Unless`, respectively. The `If` and `Unless` nodes now have a `modifier?` method to tell you if they were original found in the modifier form. - `WhileMod` and `UntilMod` are no longer nodes. Instead, they have been folded into `While` and `Until`, respectively. The `While` and `Until` nodes now have a `modifier?` method to tell you if they were originally found in the modifier form. - `VarAlias` is no longer a node. Instead it has been folded into the `Alias` node. The `Alias` node now has a `var_alias?` method to tell you if it is aliasing a global variable. +- `Yield0` is no longer a node. Instead if has been folded into the `Yield` node. The `Yield` node can now have its `arguments` field be `nil`. ## [4.3.0] - 2022-10-28 diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index 1c69026b..7d4cb414 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -5403,7 +5403,7 @@ def ternaryable?(statement) case statement when Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfOp, Lambda, MAssign, Next, OpAssign, RescueMod, Return, Return0, Super, - Undef, Unless, Until, VoidStmt, While, Yield, Yield0, ZSuper + Undef, Unless, Until, VoidStmt, While, Yield, ZSuper # This is a list of nodes that should not be allowed to be a part of a # ternary clause. false @@ -5677,7 +5677,7 @@ def format(q) force_flat = [ Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfOp, Lambda, MAssign, Next, OpAssign, RescueMod, Return, Return0, Super, Undef, - Unless, VoidStmt, Yield, Yield0, ZSuper + Unless, VoidStmt, Yield, ZSuper ] if q.parent.is_a?(Paren) || force_flat.include?(truthy.class) || @@ -10101,7 +10101,7 @@ def format(q) # yield value # class Yield < Node - # [Args | Paren] the arguments passed to the yield + # [nil | Args | Paren] the arguments passed to the yield attr_reader :arguments # [Array[ Comment | EmbDoc ]] the comments attached to this node @@ -10128,6 +10128,11 @@ def deconstruct_keys(_keys) end def format(q) + if arguments.nil? + q.text("yield") + return + end + q.group do q.text("yield") @@ -10146,42 +10151,6 @@ def format(q) end end - # Yield0 represents the bare +yield+ keyword with no arguments. - # - # yield - # - class Yield0 < Node - # [String] the value of the keyword - attr_reader :value - - # [Array[ Comment | EmbDoc ]] the comments attached to this node - attr_reader :comments - - def initialize(value:, location:) - @value = value - @location = location - @comments = [] - end - - def accept(visitor) - visitor.visit_yield0(self) - end - - def child_nodes - [] - end - - alias deconstruct child_nodes - - def deconstruct_keys(_keys) - { value: value, location: location, comments: comments } - end - - def format(q) - q.text(value) - end - end - # ZSuper represents the bare +super+ keyword with no arguments. # # super diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index a28bb296..56cba022 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -3896,11 +3896,11 @@ def on_yield(arguments) end # :call-seq: - # on_yield0: () -> Yield0 + # on_yield0: () -> Yield def on_yield0 keyword = consume_keyword(:yield) - Yield0.new(value: keyword.value, location: keyword.location) + Yield.new(arguments: nil, location: keyword.location) end # :call-seq: diff --git a/lib/syntax_tree/visitor.rb b/lib/syntax_tree/visitor.rb index 06fa7e17..a41a3ed7 100644 --- a/lib/syntax_tree/visitor.rb +++ b/lib/syntax_tree/visitor.rb @@ -467,9 +467,6 @@ class Visitor < BasicVisitor # Visit a Yield node. alias visit_yield visit_child_nodes - # Visit a Yield0 node. - alias visit_yield0 visit_child_nodes - # Visit a ZSuper node. alias visit_zsuper visit_child_nodes diff --git a/lib/syntax_tree/visitor/field_visitor.rb b/lib/syntax_tree/visitor/field_visitor.rb index c5b00c50..52dca6f9 100644 --- a/lib/syntax_tree/visitor/field_visitor.rb +++ b/lib/syntax_tree/visitor/field_visitor.rb @@ -1060,10 +1060,6 @@ def visit_yield(node) end end - def visit_yield0(node) - visit_token(node, "yield0") - end - def visit_zsuper(node) visit_token(node, "zsuper") end diff --git a/test/node_test.rb b/test/node_test.rb index 05ae2254..608c7fbe 100644 --- a/test/node_test.rb +++ b/test/node_test.rb @@ -1013,7 +1013,7 @@ def test_yield end def test_yield0 - assert_node(Yield0, "yield") + assert_node(Yield, "yield") end def test_zsuper From 5f64ba7c0b38bfe7e01df913a011c56ec95d0c4a Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 11:19:51 -0400 Subject: [PATCH 08/35] Fold FCall into Call --- CHANGELOG.md | 1 + lib/syntax_tree/node.rb | 101 ++++++++++--------------------------- lib/syntax_tree/parser.rb | 28 +++++----- lib/syntax_tree/visitor.rb | 3 -- test/node_test.rb | 2 +- 5 files changed, 41 insertions(+), 94 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 148da6f8..fbae9d38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - `WhileMod` and `UntilMod` are no longer nodes. Instead, they have been folded into `While` and `Until`, respectively. The `While` and `Until` nodes now have a `modifier?` method to tell you if they were originally found in the modifier form. - `VarAlias` is no longer a node. Instead it has been folded into the `Alias` node. The `Alias` node now has a `var_alias?` method to tell you if it is aliasing a global variable. - `Yield0` is no longer a node. Instead if has been folded into the `Yield` node. The `Yield` node can now have its `arguments` field be `nil`. +- `FCall` is no longer a node. Instead it has been folded into the `Call` node. The `Call` node can now have its `receiver` and `operator` fields be `nil`. ## [4.3.0] - 2022-10-28 diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index 7d4cb414..0277d8b1 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -2484,8 +2484,7 @@ def format(q) # nodes. parent = parents[3] if parent.is_a?(DoBlock) - if parent.is_a?(MethodAddBlock) && parent.call.is_a?(FCall) && - parent.call.value.value == "sig" + if parent.is_a?(MethodAddBlock) && parent.call.is_a?(Call) && parent.call.message.value == "sig" threshold = 2 end end @@ -2647,10 +2646,10 @@ def format_child( # receiver.message # class Call < Node - # [untyped] the receiver of the method call + # [nil | untyped] the receiver of the method call attr_reader :receiver - # [:"::" | Op | Period] the operator being used to send the message + # [nil | :"::" | Op | Period] the operator being used to send the message attr_reader :operator # [:call | Backtick | Const | Ident | Op] the message being sent @@ -2705,23 +2704,35 @@ def deconstruct_keys(_keys) end def format(q) - # If we're at the top of a call chain, then we're going to do some - # specialized printing in case we can print it nicely. We _only_ do this - # at the top of the chain to avoid weird recursion issues. - if CallChainFormatter.chained?(receiver) && - !CallChainFormatter.chained?(q.parent) - q.group do - q - .if_break { CallChainFormatter.new(self).format(q) } - .if_flat { format_contents(q) } + if receiver + # If we're at the top of a call chain, then we're going to do some + # specialized printing in case we can print it nicely. We _only_ do this + # at the top of the chain to avoid weird recursion issues. + if CallChainFormatter.chained?(receiver) && !CallChainFormatter.chained?(q.parent) + q.group do + q + .if_break { CallChainFormatter.new(self).format(q) } + .if_flat { format_contents(q) } + end + else + format_contents(q) end else - format_contents(q) + q.format(message) + + if arguments.is_a?(ArgParen) && arguments.arguments.nil? && !message.is_a?(Const) + # If you're using an explicit set of parentheses on something that looks + # like a constant, then we need to match that in order to maintain valid + # Ruby. For example, you could do something like Foo(), on which we + # would need to keep the parentheses to make it look like a method call. + else + q.format(arguments) + end end end # Print out the arguments to this call. If there are no arguments, then do - #nothing. + # nothing. def format_arguments(q) case arguments when ArgParen @@ -4518,64 +4529,6 @@ def format(q) end end - # FCall represents the piece of a method call that comes before any arguments - # (i.e., just the name of the method). It is used in places where the parser - # is sure that it is a method call and not potentially a local variable. - # - # method(argument) - # - # In the above example, it's referring to the +method+ segment. - class FCall < Node - # [Const | Ident] the name of the method - attr_reader :value - - # [nil | ArgParen | Args] the arguments to the method call - attr_reader :arguments - - # [Array[ Comment | EmbDoc ]] the comments attached to this node - attr_reader :comments - - def initialize(value:, arguments:, location:) - @value = value - @arguments = arguments - @location = location - @comments = [] - end - - def accept(visitor) - visitor.visit_fcall(self) - end - - def child_nodes - [value, arguments] - end - - alias deconstruct child_nodes - - def deconstruct_keys(_keys) - { - value: value, - arguments: arguments, - location: location, - comments: comments - } - end - - def format(q) - q.format(value) - - if arguments.is_a?(ArgParen) && arguments.arguments.nil? && - !value.is_a?(Const) - # If you're using an explicit set of parentheses on something that looks - # like a constant, then we need to match that in order to maintain valid - # Ruby. For example, you could do something like Foo(), on which we - # would need to keep the parentheses to make it look like a method call. - else - q.format(arguments) - end - end - end - # Field is always the child of an assignment. It represents assigning to a # “field” on an object. # @@ -6396,7 +6349,7 @@ def format(q) # method {} # class MethodAddBlock < Node - # [Call | Command | CommandCall | FCall] the method call + # [Call | Command | CommandCall] the method call attr_reader :call # [BraceBlock | DoBlock] the block being sent with the method call diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index 56cba022..7fa02c67 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -1608,9 +1608,9 @@ def on_excessed_comma(*) end # :call-seq: - # on_fcall: ((Const | Ident) value) -> FCall + # on_fcall: ((Const | Ident) value) -> Call def on_fcall(value) - FCall.new(value: value, arguments: nil, location: value.location) + Call.new(receiver: nil, operator: nil, message: value, arguments: nil, location: value.location) end # :call-seq: @@ -2305,29 +2305,25 @@ def on_massign(target, value) # :call-seq: # on_method_add_arg: ( - # (Call | FCall) call, + # Call call, # (ArgParen | Args) arguments - # ) -> Call | FCall + # ) -> Call def on_method_add_arg(call, arguments) location = call.location location = location.to(arguments.location) if arguments.is_a?(ArgParen) - if call.is_a?(FCall) - FCall.new(value: call.value, arguments: arguments, location: location) - else - Call.new( - receiver: call.receiver, - operator: call.operator, - message: call.message, - arguments: arguments, - location: location - ) - end + Call.new( + receiver: call.receiver, + operator: call.operator, + message: call.message, + arguments: arguments, + location: location + ) end # :call-seq: # on_method_add_block: ( - # (Call | Command | CommandCall | FCall) call, + # (Call | Command | CommandCall) call, # (BraceBlock | DoBlock) block # ) -> MethodAddBlock def on_method_add_block(call, block) diff --git a/lib/syntax_tree/visitor.rb b/lib/syntax_tree/visitor.rb index a41a3ed7..3b652f89 100644 --- a/lib/syntax_tree/visitor.rb +++ b/lib/syntax_tree/visitor.rb @@ -167,9 +167,6 @@ class Visitor < BasicVisitor # Visit an ExcessedComma node. alias visit_excessed_comma visit_child_nodes - # Visit a FCall node. - alias visit_fcall visit_child_nodes - # Visit a Field node. alias visit_field visit_child_nodes diff --git a/test/node_test.rb b/test/node_test.rb index 608c7fbe..69c147c3 100644 --- a/test/node_test.rb +++ b/test/node_test.rb @@ -487,7 +487,7 @@ def test_excessed_comma end def test_fcall - assert_node(FCall, "method(argument)") + assert_node(Call, "method(argument)") end def test_field From 087350aa095d04b9595b761a7eaaa2d7349300e3 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 11:32:38 -0400 Subject: [PATCH 09/35] Fold Dot2 and Dot3 into RangeLiteral --- CHANGELOG.md | 11 +-- lib/syntax_tree/node.rb | 103 +++++------------------ lib/syntax_tree/parser.rb | 10 ++- lib/syntax_tree/visitor.rb | 9 +- lib/syntax_tree/visitor/field_visitor.rb | 25 ++---- test/node_test.rb | 4 +- 6 files changed, 45 insertions(+), 117 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbae9d38..25bb7891 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,11 +9,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ### Changed - Nodes no longer have a `comments:` keyword on their initializers. By default, they initialize to an empty array. If you were previously passing comments into the initializer, you should now create the node first, then call `node.comments.concat` to add your comments. -- `IfMod` and `UnlessMod` are no longer nodes. Instead, they have been folded into `If` and `Unless`, respectively. The `If` and `Unless` nodes now have a `modifier?` method to tell you if they were original found in the modifier form. -- `WhileMod` and `UntilMod` are no longer nodes. Instead, they have been folded into `While` and `Until`, respectively. The `While` and `Until` nodes now have a `modifier?` method to tell you if they were originally found in the modifier form. -- `VarAlias` is no longer a node. Instead it has been folded into the `Alias` node. The `Alias` node now has a `var_alias?` method to tell you if it is aliasing a global variable. -- `Yield0` is no longer a node. Instead if has been folded into the `Yield` node. The `Yield` node can now have its `arguments` field be `nil`. -- `FCall` is no longer a node. Instead it has been folded into the `Call` node. The `Call` node can now have its `receiver` and `operator` fields be `nil`. +- A lot of nodes have been folded into other nodes to make it easier to interact with the AST. This means that a lot of visit methods have been removed from the visitor and a lot of class definitions are no longer present. This also means that the nodes that received more function now have additional methods or fields to be able to differentiate them. Note that none of these changes have resulted in different formatting. The changes are listed below: + - `IfMod`, `UnlessMod`, `WhileMod`, `UntilMod` have been folded into `If`, `Unless`, `While`, and `Until`. Each of the nodes now have a `modifier?` method to tell if it was originally in the modifier form. Consequently, the `visit_if_mod`, `visit_unless_mod`, `visit_while_mod`, and `visit_until_mod` methods have been removed from the visitor. + - `VarAlias` is no longer a node. Instead it has been folded into the `Alias` node. The `Alias` node now has a `var_alias?` method to tell you if it is aliasing a global variable. Consequently, the `visit_var_alias` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_alias` instead. + - `Yield0` is no longer a node. Instead if has been folded into the `Yield` node. The `Yield` node can now have its `arguments` field be `nil`. Consequently, the `visit_yield0` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_yield` instead. + - `FCall` is no longer a node. Instead it has been folded into the `Call` node. The `Call` node can now have its `receiver` and `operator` fields be `nil`. Consequently, the `visit_fcall` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_call` instead. + - `Dot2` and `Dot3` are no longer nodes. Instead they have become a single new `RangeLiteral` node. This node looks the same as `Dot2` and `Dot3`, except that it additionally has an `operator` field that contains the operator that created the node. Consequently, the `visit_dot2` and `visit_dot3` methods have been removed from the visitor interface. If you were previously using these methods, you should now use `visit_range_literal` instead. ## [4.3.0] - 2022-10-28 diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index 0277d8b1..8f3892e1 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -3878,38 +3878,8 @@ def format(q) end end - # Responsible for formatting Dot2 and Dot3 nodes. - class DotFormatter - # [String] the operator to display - attr_reader :operator - - # [Dot2 | Dot3] the node that is being formatter - attr_reader :node - - def initialize(operator, node) - @operator = operator - @node = node - end - - def format(q) - left = node.left - right = node.right - - q.format(left) if left - - case q.parent - when If, Unless - q.text(" #{operator} ") - else - q.text(operator) - end - - q.format(right) if right - end - end - - # Dot2 represents using the .. operator between two expressions. Usually this - # is to create a range object. + # RangeLiteral represents using the .. or the ... operator between two + # expressions. Usually this is to create a range object. # # 1..2 # @@ -3919,25 +3889,29 @@ def format(q) # end # # One of the sides of the expression may be nil, but not both. - class Dot2 < Node + class RangeLiteral < Node # [nil | untyped] the left side of the expression attr_reader :left + # [Op] the operator used for this range + attr_reader :operator + # [nil | untyped] the right side of the expression attr_reader :right # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(left:, right:, location:) + def initialize(left:, operator:, right:, location:) @left = left + @operator = operator @right = right @location = location @comments = [] end def accept(visitor) - visitor.visit_dot2(self) + visitor.visit_range_literal(self) end def child_nodes @@ -3947,59 +3921,20 @@ def child_nodes alias deconstruct child_nodes def deconstruct_keys(_keys) - { left: left, right: right, location: location, comments: comments } + { left: left, operator: operator, right: right, location: location, comments: comments } end def format(q) - DotFormatter.new("..", self).format(q) - end - end - - # Dot3 represents using the ... operator between two expressions. Usually this - # is to create a range object. It's effectively the same event as the Dot2 - # node but with this operator you're asking Ruby to omit the final value. - # - # 1...2 - # - # Like Dot2 it can also be used to create a flip-flop. - # - # if value == 5 ... value == 10 - # end - # - # One of the sides of the expression may be nil, but not both. - class Dot3 < Node - # [nil | untyped] the left side of the expression - attr_reader :left - - # [nil | untyped] the right side of the expression - attr_reader :right - - # [Array[ Comment | EmbDoc ]] the comments attached to this node - attr_reader :comments - - def initialize(left:, right:, location:) - @left = left - @right = right - @location = location - @comments = [] - end - - def accept(visitor) - visitor.visit_dot3(self) - end - - def child_nodes - [left, right] - end - - alias deconstruct child_nodes + q.format(left) if left - def deconstruct_keys(_keys) - { left: left, right: right, location: location, comments: comments } - end + case q.parent + when If, Unless + q.text(" #{operator.value} ") + else + q.text(operator.value) + end - def format(q) - DotFormatter.new("...", self).format(q) + q.format(right) if right end end @@ -9771,7 +9706,7 @@ def format(q) # last argument to the predicate is and endless range, then you are # forced to use the "then" keyword to make it parse properly. last = arguments.parts.last - if (last.is_a?(Dot2) || last.is_a?(Dot3)) && !last.right + if last.is_a?(RangeLiteral) && !last.right q.text(" then") end end diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index 7fa02c67..4bc0bb6f 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -1357,30 +1357,32 @@ def on_do_block(block_var, bodystmt) end # :call-seq: - # on_dot2: ((nil | untyped) left, (nil | untyped) right) -> Dot2 + # on_dot2: ((nil | untyped) left, (nil | untyped) right) -> RangeLiteral def on_dot2(left, right) operator = consume_operator(:"..") beginning = left || operator ending = right || operator - Dot2.new( + RangeLiteral.new( left: left, + operator: operator, right: right, location: beginning.location.to(ending.location) ) end # :call-seq: - # on_dot3: ((nil | untyped) left, (nil | untyped) right) -> Dot3 + # on_dot3: ((nil | untyped) left, (nil | untyped) right) -> RangeLiteral def on_dot3(left, right) operator = consume_operator(:"...") beginning = left || operator ending = right || operator - Dot3.new( + RangeLiteral.new( left: left, + operator: operator, right: right, location: beginning.location.to(ending.location) ) diff --git a/lib/syntax_tree/visitor.rb b/lib/syntax_tree/visitor.rb index 3b652f89..ad4757d7 100644 --- a/lib/syntax_tree/visitor.rb +++ b/lib/syntax_tree/visitor.rb @@ -131,12 +131,6 @@ class Visitor < BasicVisitor # Visit a DoBlock node. alias visit_do_block visit_child_nodes - # Visit a Dot2 node. - alias visit_dot2 visit_child_nodes - - # Visit a Dot3 node. - alias visit_dot3 visit_child_nodes - # Visit a DynaSymbol node. alias visit_dyna_symbol visit_child_nodes @@ -305,6 +299,9 @@ class Visitor < BasicVisitor # Visit a QWordsBeg node. alias visit_qwords_beg visit_child_nodes + # Visit a RangeLiteral node + alias visit_range_literal visit_child_nodes + # Visit a RAssign node. alias visit_rassign visit_child_nodes diff --git a/lib/syntax_tree/visitor/field_visitor.rb b/lib/syntax_tree/visitor/field_visitor.rb index 52dca6f9..ac7b3603 100644 --- a/lib/syntax_tree/visitor/field_visitor.rb +++ b/lib/syntax_tree/visitor/field_visitor.rb @@ -362,22 +362,6 @@ def visit_do_block(node) end end - def visit_dot2(node) - node(node, "dot2") do - field("left", node.left) if node.left - field("right", node.right) if node.right - comments(node) - end - end - - def visit_dot3(node) - node(node, "dot3") do - field("left", node.left) if node.left - field("right", node.right) if node.right - comments(node) - end - end - def visit_dyna_symbol(node) node(node, "dyna_symbol") do list("parts", node.parts) @@ -739,6 +723,15 @@ def visit_qwords_beg(node) node(node, "qwords_beg") { field("value", node.value) } end + def visit_range_literal(node) + node(node, "range_literal") do + field("left", node.left) if node.left + field("operator", node.operator) + field("right", node.right) if node.right + comments(node) + end + end + def visit_rassign(node) node(node, "rassign") do field("value", node.value) diff --git a/test/node_test.rb b/test/node_test.rb index 69c147c3..d27c0d5f 100644 --- a/test/node_test.rb +++ b/test/node_test.rb @@ -414,11 +414,11 @@ def test_do_block end def test_dot2 - assert_node(Dot2, "1..3") + assert_node(RangeLiteral, "1..3") end def test_dot3 - assert_node(Dot3, "1...3") + assert_node(RangeLiteral, "1...3") end def test_dyna_symbol From a99d08124ade363c0b9371897918e0ded74f42c3 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 12:02:42 -0400 Subject: [PATCH 10/35] Fold DefEndless into Def and Defs nodes --- CHANGELOG.md | 1 + lib/syntax_tree/node.rb | 171 +++++++------------- lib/syntax_tree/parser.rb | 16 +- lib/syntax_tree/visitor.rb | 3 - lib/syntax_tree/visitor/field_visitor.rb | 14 -- lib/syntax_tree/visitor/with_environment.rb | 4 - test/fixtures/def_endless.rb | 4 - test/node_test.rb | 4 +- 8 files changed, 70 insertions(+), 147 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25bb7891..67b4e150 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - `Yield0` is no longer a node. Instead if has been folded into the `Yield` node. The `Yield` node can now have its `arguments` field be `nil`. Consequently, the `visit_yield0` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_yield` instead. - `FCall` is no longer a node. Instead it has been folded into the `Call` node. The `Call` node can now have its `receiver` and `operator` fields be `nil`. Consequently, the `visit_fcall` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_call` instead. - `Dot2` and `Dot3` are no longer nodes. Instead they have become a single new `RangeLiteral` node. This node looks the same as `Dot2` and `Dot3`, except that it additionally has an `operator` field that contains the operator that created the node. Consequently, the `visit_dot2` and `visit_dot3` methods have been removed from the visitor interface. If you were previously using these methods, you should now use `visit_range_literal` instead. + - `DefEndless` has been folded into the `Def` and `Defs` nodes. ## [4.3.0] - 2022-10-28 diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index 8f3892e1..ebfcc336 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -3108,7 +3108,7 @@ def align(q, node, &block) part = parts.first case part - when Def, Defs, DefEndless + when Def, Defs q.text(" ") yield when IfOp @@ -3540,10 +3540,10 @@ class Def < Node # [Backtick | Const | Ident | Kw | Op] the name of the method attr_reader :name - # [Params | Paren] the parameter declaration for the method + # [nil | Params | Paren] the parameter declaration for the method attr_reader :params - # [BodyStmt] the expressions to be executed by the method + # [BodyStmt | untyped] the expressions to be executed by the method attr_reader :bodystmt # [Array[ Comment | EmbDoc ]] the comments attached to this node @@ -3583,112 +3583,41 @@ def format(q) q.text("def ") q.format(name) - if !params.is_a?(Params) || !params.empty? || params.comments.any? + case params + when Paren q.format(params) + when Params + q.format(params) if !params.empty? || params.comments.any? end end - unless bodystmt.empty? - q.indent do - q.breakable_force - q.format(bodystmt) + if endless? + q.text(" =") + q.group do + q.indent do + q.breakable_space + q.format(bodystmt) + end + end + else + unless bodystmt.empty? + q.indent do + q.breakable_force + q.format(bodystmt) + end end - end - q.breakable_force - q.text("end") + q.breakable_force + q.text("end") + end end end - end - - # DefEndless represents defining a single-line method since Ruby 3.0+. - # - # def method = result - # - class DefEndless < Node - # [untyped] the target where the method is being defined - attr_reader :target - - # [Op | Period] the operator being used to declare the method - attr_reader :operator - - # [Backtick | Const | Ident | Kw | Op] the name of the method - attr_reader :name - - # [nil | Params | Paren] the parameter declaration for the method - attr_reader :paren - - # [untyped] the expression to be executed by the method - attr_reader :statement - - # [Array[ Comment | EmbDoc ]] the comments attached to this node - attr_reader :comments - - def initialize( - target:, - operator:, - name:, - paren:, - statement:, - location:, - comments: [] - ) - @target = target - @operator = operator - @name = name - @paren = paren - @statement = statement - @location = location - @comments = [] - end - - def accept(visitor) - visitor.visit_def_endless(self) - end - def child_nodes - [target, operator, name, paren, statement] - end - - alias deconstruct child_nodes - - def deconstruct_keys(_keys) - { - target: target, - operator: operator, - name: name, - paren: paren, - statement: statement, - location: location, - comments: comments - } - end - - def format(q) - q.group do - q.text("def ") - - if target - q.format(target) - q.format(CallOperatorFormatter.new(operator), stackable: false) - end - - q.format(name) - - if paren - params = paren - params = params.contents if params.is_a?(Paren) - q.format(paren) unless params.empty? - end - - q.text(" =") - q.group do - q.indent do - q.breakable_space - q.format(statement) - end - end - end + # Returns true if the method was found in the source in the "endless" form, + # i.e. where the method body is defined using the `=` operator after the + # method name and parameters. + def endless? + !bodystmt.is_a?(BodyStmt) end end @@ -3751,10 +3680,10 @@ class Defs < Node # [Backtick | Const | Ident | Kw | Op] the name of the method attr_reader :name - # [Params | Paren] the parameter declaration for the method + # [nil | Params | Paren] the parameter declaration for the method attr_reader :params - # [BodyStmt] the expressions to be executed by the method + # [BodyStmt | untyped] the expressions to be executed by the method attr_reader :bodystmt # [Array[ Comment | EmbDoc ]] the comments attached to this node @@ -3808,22 +3737,42 @@ def format(q) q.format(CallOperatorFormatter.new(operator), stackable: false) q.format(name) - if !params.is_a?(Params) || !params.empty? || params.comments.any? + case params + when Paren q.format(params) + when Params + q.format(params) if !params.empty? || params.comments.any? end end - unless bodystmt.empty? - q.indent do - q.breakable_force - q.format(bodystmt) + if endless? + q.text(" =") + q.group do + q.indent do + q.breakable_space + q.format(bodystmt) + end + end + else + unless bodystmt.empty? + q.indent do + q.breakable_force + q.format(bodystmt) + end end - end - q.breakable_force - q.text("end") + q.breakable_force + q.text("end") + end end end + + # Returns true if the method was found in the source in the "endless" form, + # i.e. where the method body is defined using the `=` operator after the + # method name and parameters. + def endless? + !bodystmt.is_a?(BodyStmt) + end end # DoBlock represents passing a block to a method call using the +do+ and +end+ @@ -6971,7 +6920,7 @@ def format(q) end case q.parent - when Def, Defs, DefEndless + when Def, Defs q.nest(0) do q.text("(") q.group do diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index 4bc0bb6f..508348d8 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -1181,7 +1181,7 @@ def on_cvar(value) # (Backtick | Const | Ident | Kw | Op) name, # (nil | Params | Paren) params, # untyped bodystmt - # ) -> Def | DefEndless + # ) -> Def def on_def(name, params, bodystmt) # Make sure to delete this token in case you're defining something like # def class which would lead to this being a kw and causing all kinds of @@ -1234,12 +1234,10 @@ def on_def(name, params, bodystmt) # the statements list. Before, it was just the individual statement. statement = bodystmt.is_a?(BodyStmt) ? bodystmt.statements : bodystmt - DefEndless.new( - target: nil, - operator: nil, + Def.new( name: name, - paren: params, - statement: statement, + params: params, + bodystmt: statement, location: beginning.location.to(bodystmt.location) ) end @@ -1322,12 +1320,12 @@ def on_defs(target, operator, name, params, bodystmt) # the statements list. Before, it was just the individual statement. statement = bodystmt.is_a?(BodyStmt) ? bodystmt.statements : bodystmt - DefEndless.new( + Defs.new( target: target, operator: operator, name: name, - paren: params, - statement: statement, + params: params, + bodystmt: statement, location: beginning.location.to(bodystmt.location) ) end diff --git a/lib/syntax_tree/visitor.rb b/lib/syntax_tree/visitor.rb index ad4757d7..3bf3c72d 100644 --- a/lib/syntax_tree/visitor.rb +++ b/lib/syntax_tree/visitor.rb @@ -119,9 +119,6 @@ class Visitor < BasicVisitor # Visit a Def node. alias visit_def visit_child_nodes - # Visit a DefEndless node. - alias visit_def_endless visit_child_nodes - # Visit a Defined node. alias visit_defined visit_child_nodes diff --git a/lib/syntax_tree/visitor/field_visitor.rb b/lib/syntax_tree/visitor/field_visitor.rb index ac7b3603..14ecd2fc 100644 --- a/lib/syntax_tree/visitor/field_visitor.rb +++ b/lib/syntax_tree/visitor/field_visitor.rb @@ -322,20 +322,6 @@ def visit_def(node) end end - def visit_def_endless(node) - node(node, "def_endless") do - if node.target - field("target", node.target) - field("operator", node.operator) - end - - field("name", node.name) - field("paren", node.paren) if node.paren - field("statement", node.statement) - comments(node) - end - end - def visit_defined(node) node(node, "defined") do field("value", node.value) diff --git a/lib/syntax_tree/visitor/with_environment.rb b/lib/syntax_tree/visitor/with_environment.rb index 043cbd4c..006f7b09 100644 --- a/lib/syntax_tree/visitor/with_environment.rb +++ b/lib/syntax_tree/visitor/with_environment.rb @@ -60,10 +60,6 @@ def visit_defs(node) with_new_environment { super } end - def visit_def_endless(node) - with_new_environment { super } - end - # Visit for keeping track of local arguments, such as method and block # arguments def visit_params(node) diff --git a/test/fixtures/def_endless.rb b/test/fixtures/def_endless.rb index 15ea518b..4595fba9 100644 --- a/test/fixtures/def_endless.rb +++ b/test/fixtures/def_endless.rb @@ -4,8 +4,6 @@ def foo = bar def foo(bar) = baz % def foo() = bar -- -def foo = bar % # >= 3.1.0 def foo = bar baz % # >= 3.1.0 @@ -14,8 +12,6 @@ def self.foo = bar def self.foo(bar) = baz % # >= 3.1.0 def self.foo() = bar -- -def self.foo = bar % # >= 3.1.0 def self.foo = bar baz % diff --git a/test/node_test.rb b/test/node_test.rb index d27c0d5f..49f6f921 100644 --- a/test/node_test.rb +++ b/test/node_test.rb @@ -379,13 +379,13 @@ def method guard_version("3.0.0") do def test_def_endless - assert_node(DefEndless, "def method = result") + assert_node(Def, "def method = result") end end guard_version("3.1.0") do def test_def_endless_command - assert_node(DefEndless, "def method = result argument") + assert_node(Def, "def method = result argument") end end From 4a9a7c6a8b55764676f47b2ddcd10e614b4aff8c Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 12:07:46 -0400 Subject: [PATCH 11/35] Fold Def and DefEndless --- CHANGELOG.md | 2 +- lib/syntax_tree/node.rb | 135 +++----------------- lib/syntax_tree/parser.rb | 10 +- lib/syntax_tree/visitor.rb | 3 - lib/syntax_tree/visitor/field_visitor.rb | 13 +- lib/syntax_tree/visitor/with_environment.rb | 4 - test/node_test.rb | 4 +- 7 files changed, 33 insertions(+), 138 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67b4e150..10c33420 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - `Yield0` is no longer a node. Instead if has been folded into the `Yield` node. The `Yield` node can now have its `arguments` field be `nil`. Consequently, the `visit_yield0` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_yield` instead. - `FCall` is no longer a node. Instead it has been folded into the `Call` node. The `Call` node can now have its `receiver` and `operator` fields be `nil`. Consequently, the `visit_fcall` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_call` instead. - `Dot2` and `Dot3` are no longer nodes. Instead they have become a single new `RangeLiteral` node. This node looks the same as `Dot2` and `Dot3`, except that it additionally has an `operator` field that contains the operator that created the node. Consequently, the `visit_dot2` and `visit_dot3` methods have been removed from the visitor interface. If you were previously using these methods, you should now use `visit_range_literal` instead. - - `DefEndless` has been folded into the `Def` and `Defs` nodes. + - `DefEndless` and `Defs` have both been folded into the `Def` node. The `Def` node now has the `target` and `operator` fields which originally came from `Defs` which can both be `nil`. It also now has an `endless?` method on it to tell if the original node was found in the endless form. Finally the `bodystmt` field can now either be a `BodyStmt` as it was or any other kind of node since that was the body of the `DefEndless` node. The `visit_defs` and `visit_def_endless` methods on the visitor have therefore been removed. ## [4.3.0] - 2022-10-28 diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index ebfcc336..b1080f1f 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -3108,7 +3108,7 @@ def align(q, node, &block) part = parts.first case part - when Def, Defs + when Def q.text(" ") yield when IfOp @@ -3535,8 +3535,15 @@ def format(q) # Def represents defining a regular method on the current self object. # # def method(param) result end + # def object.method(param) result end # class Def < Node + # [nil | untyped] the target where the method is being defined + attr_reader :target + + # [nil | Op | Period] the operator being used to declare the method + attr_reader :operator + # [Backtick | Const | Ident | Kw | Op] the name of the method attr_reader :name @@ -3549,7 +3556,9 @@ class Def < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(name:, params:, bodystmt:, location:) + def initialize(target:, operator:, name:, params:, bodystmt:, location:) + @target = target + @operator = operator @name = name @params = params @bodystmt = bodystmt @@ -3562,13 +3571,15 @@ def accept(visitor) end def child_nodes - [name, params, bodystmt] + [target, operator, name, params, bodystmt] end alias deconstruct child_nodes def deconstruct_keys(_keys) { + target: target, + operator: operator, name: name, params: params, bodystmt: bodystmt, @@ -3581,6 +3592,12 @@ def format(q) q.group do q.group do q.text("def ") + + if target + q.format(target) + q.format(CallOperatorFormatter.new(operator), stackable: false) + end + q.format(name) case params @@ -3666,115 +3683,6 @@ def format(q) end end - # Defs represents defining a singleton method on an object. - # - # def object.method(param) result end - # - class Defs < Node - # [untyped] the target where the method is being defined - attr_reader :target - - # [Op | Period] the operator being used to declare the method - attr_reader :operator - - # [Backtick | Const | Ident | Kw | Op] the name of the method - attr_reader :name - - # [nil | Params | Paren] the parameter declaration for the method - attr_reader :params - - # [BodyStmt | untyped] the expressions to be executed by the method - attr_reader :bodystmt - - # [Array[ Comment | EmbDoc ]] the comments attached to this node - attr_reader :comments - - def initialize( - target:, - operator:, - name:, - params:, - bodystmt:, - location:, - comments: [] - ) - @target = target - @operator = operator - @name = name - @params = params - @bodystmt = bodystmt - @location = location - @comments = [] - end - - def accept(visitor) - visitor.visit_defs(self) - end - - def child_nodes - [target, operator, name, params, bodystmt] - end - - alias deconstruct child_nodes - - def deconstruct_keys(_keys) - { - target: target, - operator: operator, - name: name, - params: params, - bodystmt: bodystmt, - location: location, - comments: comments - } - end - - def format(q) - q.group do - q.group do - q.text("def ") - q.format(target) - q.format(CallOperatorFormatter.new(operator), stackable: false) - q.format(name) - - case params - when Paren - q.format(params) - when Params - q.format(params) if !params.empty? || params.comments.any? - end - end - - if endless? - q.text(" =") - q.group do - q.indent do - q.breakable_space - q.format(bodystmt) - end - end - else - unless bodystmt.empty? - q.indent do - q.breakable_force - q.format(bodystmt) - end - end - - q.breakable_force - q.text("end") - end - end - end - - # Returns true if the method was found in the source in the "endless" form, - # i.e. where the method body is defined using the `=` operator after the - # method name and parameters. - def endless? - !bodystmt.is_a?(BodyStmt) - end - end - # DoBlock represents passing a block to a method call using the +do+ and +end+ # keywords. # @@ -6919,8 +6827,7 @@ def format(q) return end - case q.parent - when Def, Defs + if q.parent.is_a?(Def) q.nest(0) do q.text("(") q.group do diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index 508348d8..797f69d2 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -1224,6 +1224,8 @@ def on_def(name, params, bodystmt) ) Def.new( + target: nil, + operator: nil, name: name, params: params, bodystmt: bodystmt, @@ -1235,6 +1237,8 @@ def on_def(name, params, bodystmt) statement = bodystmt.is_a?(BodyStmt) ? bodystmt.statements : bodystmt Def.new( + target: nil, + operator: nil, name: name, params: params, bodystmt: statement, @@ -1268,7 +1272,7 @@ def on_defined(value) # (Backtick | Const | Ident | Kw | Op) name, # (Params | Paren) params, # BodyStmt bodystmt - # ) -> Defs + # ) -> Def def on_defs(target, operator, name, params, bodystmt) # Make sure to delete this token in case you're defining something # like def class which would lead to this being a kw and causing all kinds @@ -1307,7 +1311,7 @@ def on_defs(target, operator, name, params, bodystmt) ending.location.start_column ) - Defs.new( + Def.new( target: target, operator: operator, name: name, @@ -1320,7 +1324,7 @@ def on_defs(target, operator, name, params, bodystmt) # the statements list. Before, it was just the individual statement. statement = bodystmt.is_a?(BodyStmt) ? bodystmt.statements : bodystmt - Defs.new( + Def.new( target: target, operator: operator, name: name, diff --git a/lib/syntax_tree/visitor.rb b/lib/syntax_tree/visitor.rb index 3bf3c72d..9748d0e1 100644 --- a/lib/syntax_tree/visitor.rb +++ b/lib/syntax_tree/visitor.rb @@ -122,9 +122,6 @@ class Visitor < BasicVisitor # Visit a Defined node. alias visit_defined visit_child_nodes - # Visit a Defs node. - alias visit_defs visit_child_nodes - # Visit a DoBlock node. alias visit_do_block visit_child_nodes diff --git a/lib/syntax_tree/visitor/field_visitor.rb b/lib/syntax_tree/visitor/field_visitor.rb index 14ecd2fc..0fc8c908 100644 --- a/lib/syntax_tree/visitor/field_visitor.rb +++ b/lib/syntax_tree/visitor/field_visitor.rb @@ -315,6 +315,8 @@ def visit_cvar(node) def visit_def(node) node(node, "def") do + field("target", node.target) + field("operator", node.operator) field("name", node.name) field("params", node.params) field("bodystmt", node.bodystmt) @@ -329,17 +331,6 @@ def visit_defined(node) end end - def visit_defs(node) - node(node, "defs") do - field("target", node.target) - field("operator", node.operator) - field("name", node.name) - field("params", node.params) - field("bodystmt", node.bodystmt) - comments(node) - end - end - def visit_do_block(node) node(node, "do_block") do field("block_var", node.block_var) if node.block_var diff --git a/lib/syntax_tree/visitor/with_environment.rb b/lib/syntax_tree/visitor/with_environment.rb index 006f7b09..59033d50 100644 --- a/lib/syntax_tree/visitor/with_environment.rb +++ b/lib/syntax_tree/visitor/with_environment.rb @@ -56,10 +56,6 @@ def visit_def(node) with_new_environment { super } end - def visit_defs(node) - with_new_environment { super } - end - # Visit for keeping track of local arguments, such as method and block # arguments def visit_params(node) diff --git a/test/node_test.rb b/test/node_test.rb index 49f6f921..8bb28131 100644 --- a/test/node_test.rb +++ b/test/node_test.rb @@ -394,7 +394,7 @@ def test_defined end def test_defs - assert_node(Defs, "def object.method(param) result end") + assert_node(Def, "def object.method(param) result end") end def test_defs_paramless @@ -403,7 +403,7 @@ def object.method end SOURCE - assert_node(Defs, source) + assert_node(Def, source) end def test_do_block From 3445e6435639914c73309d412ad639c11a165763 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 12:24:42 -0400 Subject: [PATCH 12/35] Fold DoBlock and BraceBlock into Block --- CHANGELOG.md | 1 + lib/syntax_tree/node.rb | 396 ++++++++++------------- lib/syntax_tree/parser.rb | 16 +- lib/syntax_tree/visitor.rb | 9 +- lib/syntax_tree/visitor/field_visitor.rb | 24 +- test/node_test.rb | 6 +- 6 files changed, 186 insertions(+), 266 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10c33420..92f03f01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - `FCall` is no longer a node. Instead it has been folded into the `Call` node. The `Call` node can now have its `receiver` and `operator` fields be `nil`. Consequently, the `visit_fcall` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_call` instead. - `Dot2` and `Dot3` are no longer nodes. Instead they have become a single new `RangeLiteral` node. This node looks the same as `Dot2` and `Dot3`, except that it additionally has an `operator` field that contains the operator that created the node. Consequently, the `visit_dot2` and `visit_dot3` methods have been removed from the visitor interface. If you were previously using these methods, you should now use `visit_range_literal` instead. - `DefEndless` and `Defs` have both been folded into the `Def` node. The `Def` node now has the `target` and `operator` fields which originally came from `Defs` which can both be `nil`. It also now has an `endless?` method on it to tell if the original node was found in the endless form. Finally the `bodystmt` field can now either be a `BodyStmt` as it was or any other kind of node since that was the body of the `DefEndless` node. The `visit_defs` and `visit_def_endless` methods on the visitor have therefore been removed. + - `DoBlock` and `BraceBlock` have now been folded into a `Block` node. The `Block` node now has a `keywords?` method on it that returns true if the block was constructed with the `do`..`end` keywords. The `visit_do_block` and `visit_brace_block` methods on the visitor have therefore been removed and replaced with the `visit_block` method. ## [4.3.0] - 2022-10-28 diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index b1080f1f..0ab33b83 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -1961,222 +1961,6 @@ def format(q) end end - # Responsible for formatting either a BraceBlock or a DoBlock. - class BlockFormatter - # Formats the opening brace or keyword of a block. - class BlockOpenFormatter - # [String] the actual output that should be printed - attr_reader :text - - # [LBrace | Keyword] the node that is being represented - attr_reader :node - - def initialize(text, node) - @text = text - @node = node - end - - def comments - node.comments - end - - def format(q) - q.text(text) - end - end - - # [BraceBlock | DoBlock] the block node to be formatted - attr_reader :node - - # [LBrace | Keyword] the node that opens the block - attr_reader :block_open - - # [String] the string that closes the block - attr_reader :block_close - - # [BodyStmt | Statements] the statements inside the block - attr_reader :statements - - def initialize(node, block_open, block_close, statements) - @node = node - @block_open = block_open - @block_close = block_close - @statements = statements - end - - def format(q) - # If this is nested anywhere inside of a Command or CommandCall node, then - # we can't change which operators we're using for the bounds of the block. - break_opening, break_closing, flat_opening, flat_closing = - if unchangeable_bounds?(q) - [block_open.value, block_close, block_open.value, block_close] - elsif forced_do_end_bounds?(q) - %w[do end do end] - elsif forced_brace_bounds?(q) - %w[{ } { }] - else - %w[do end { }] - end - - # If the receiver of this block a Command or CommandCall node, then there - # are no parentheses around the arguments to that command, so we need to - # break the block. - case q.parent.call - when Command, CommandCall - q.break_parent - format_break(q, break_opening, break_closing) - return - end - - q.group do - q - .if_break { format_break(q, break_opening, break_closing) } - .if_flat { format_flat(q, flat_opening, flat_closing) } - end - end - - private - - # If this is nested anywhere inside certain nodes, then we can't change - # which operators/keywords we're using for the bounds of the block. - def unchangeable_bounds?(q) - q.parents.any? do |parent| - # If we hit a statements, then we're safe to use whatever since we - # know for certain we're going to get split over multiple lines - # anyway. - case parent - when Statements, ArgParen - break false - when Command, CommandCall - true - else - false - end - end - end - - # If we're a sibling of a control-flow keyword, then we're going to have to - # use the do..end bounds. - def forced_do_end_bounds?(q) - case q.parent.call - when Break, Next, Return, Super - true - else - false - end - end - - # If we're the predicate of a loop or conditional, then we're going to have - # to go with the {..} bounds. - def forced_brace_bounds?(q) - previous = nil - q.parents.any? do |parent| - case parent - when Paren, Statements - # If we hit certain breakpoints then we know we're safe. - return false - when If, IfOp, Unless, While, Until - return true if parent.predicate == previous - end - - previous = parent - false - end - end - - def format_break(q, opening, closing) - q.text(" ") - q.format(BlockOpenFormatter.new(opening, block_open), stackable: false) - - if node.block_var - q.text(" ") - q.format(node.block_var) - end - - unless statements.empty? - q.indent do - q.breakable_space - q.format(statements) - end - end - - q.breakable_space - q.text(closing) - end - - def format_flat(q, opening, closing) - q.text(" ") - q.format(BlockOpenFormatter.new(opening, block_open), stackable: false) - - if node.block_var - q.breakable_space - q.format(node.block_var) - q.breakable_space - end - - if statements.empty? - q.text(" ") if opening == "do" - else - q.breakable_space unless node.block_var - q.format(statements) - q.breakable_space - end - - q.text(closing) - end - end - - # BraceBlock represents passing a block to a method call using the { } - # operators. - # - # method { |variable| variable + 1 } - # - class BraceBlock < Node - # [LBrace] the left brace that opens this block - attr_reader :lbrace - - # [nil | BlockVar] the optional set of parameters to the block - attr_reader :block_var - - # [Statements] the list of expressions to evaluate within the block - attr_reader :statements - - # [Array[ Comment | EmbDoc ]] the comments attached to this node - attr_reader :comments - - def initialize(lbrace:, block_var:, statements:, location:) - @lbrace = lbrace - @block_var = block_var - @statements = statements - @location = location - @comments = [] - end - - def accept(visitor) - visitor.visit_brace_block(self) - end - - def child_nodes - [lbrace, block_var, statements] - end - - alias deconstruct child_nodes - - def deconstruct_keys(_keys) - { - lbrace: lbrace, - block_var: block_var, - statements: statements, - location: location, - comments: comments - } - end - - def format(q) - BlockFormatter.new(self, lbrace, "}", statements).format(q) - end - end - # Formats either a Break, Next, or Return node. class FlowControlFormatter # [String] the keyword to print @@ -2479,10 +2263,10 @@ def format(q) # https://github.com/prettier/plugin-ruby/issues/863. parents = q.parents.take(4) if (parent = parents[2]) - # If we're at a do_block, then we want to go one more level up. This is - # because do blocks have BodyStmt nodes instead of just Statements - # nodes. - parent = parents[3] if parent.is_a?(DoBlock) + # If we're at a block with the `do` keywords, then we want to go one + # more level up. This is because do blocks have BodyStmt nodes instead + # of just Statements nodes. + parent = parents[3] if parent.is_a?(Block) && parent.keywords? if parent.is_a?(MethodAddBlock) && parent.call.is_a?(Call) && parent.call.message.value == "sig" threshold = 2 @@ -3683,27 +3467,51 @@ def format(q) end end - # DoBlock represents passing a block to a method call using the +do+ and +end+ - # keywords. + # Block represents passing a block to a method call using the +do+ and +end+ + # keywords or the +{+ and +}+ operators. # # method do |value| # end # - class DoBlock < Node - # [Kw] the do keyword that opens this block - attr_reader :keyword + # method { |value| } + # + class Block < Node + # Formats the opening brace or keyword of a block. + class BlockOpenFormatter + # [String] the actual output that should be printed + attr_reader :text + + # [LBrace | Keyword] the node that is being represented + attr_reader :node + + def initialize(text, node) + @text = text + @node = node + end + + def comments + node.comments + end + + def format(q) + q.text(text) + end + end + + # [LBrace | Kw] the left brace or the do keyword that opens this block + attr_reader :opening # [nil | BlockVar] the optional variable declaration within this block attr_reader :block_var - # [BodyStmt] the expressions to be executed within this block + # [BodyStmt | Statements] the expressions to be executed within this block attr_reader :bodystmt # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(keyword:, block_var:, bodystmt:, location:) - @keyword = keyword + def initialize(opening:, block_var:, bodystmt:, location:) + @opening = opening @block_var = block_var @bodystmt = bodystmt @location = location @@ -3711,18 +3519,18 @@ def initialize(keyword:, block_var:, bodystmt:, location:) end def accept(visitor) - visitor.visit_do_block(self) + visitor.visit_block(self) end def child_nodes - [keyword, block_var, bodystmt] + [opening, block_var, bodystmt] end alias deconstruct child_nodes def deconstruct_keys(_keys) { - keyword: keyword, + opening: opening, block_var: block_var, bodystmt: bodystmt, location: location, @@ -3731,7 +3539,129 @@ def deconstruct_keys(_keys) end def format(q) - BlockFormatter.new(self, keyword, "end", bodystmt).format(q) + # If this is nested anywhere inside of a Command or CommandCall node, then + # we can't change which operators we're using for the bounds of the block. + break_opening, break_closing, flat_opening, flat_closing = + if unchangeable_bounds?(q) + block_close = keywords? ? "end" : "}" + [opening.value, block_close, opening.value, block_close] + elsif forced_do_end_bounds?(q) + %w[do end do end] + elsif forced_brace_bounds?(q) + %w[{ } { }] + else + %w[do end { }] + end + + # If the receiver of this block a Command or CommandCall node, then there + # are no parentheses around the arguments to that command, so we need to + # break the block. + case q.parent.call + when Command, CommandCall + q.break_parent + format_break(q, break_opening, break_closing) + return + end + + q.group do + q + .if_break { format_break(q, break_opening, break_closing) } + .if_flat { format_flat(q, flat_opening, flat_closing) } + end + end + + def keywords? + opening.is_a?(Kw) + end + + private + + # If this is nested anywhere inside certain nodes, then we can't change + # which operators/keywords we're using for the bounds of the block. + def unchangeable_bounds?(q) + q.parents.any? do |parent| + # If we hit a statements, then we're safe to use whatever since we + # know for certain we're going to get split over multiple lines + # anyway. + case parent + when Statements, ArgParen + break false + when Command, CommandCall + true + else + false + end + end + end + + # If we're a sibling of a control-flow keyword, then we're going to have to + # use the do..end bounds. + def forced_do_end_bounds?(q) + case q.parent.call + when Break, Next, Return, Super + true + else + false + end + end + + # If we're the predicate of a loop or conditional, then we're going to have + # to go with the {..} bounds. + def forced_brace_bounds?(q) + previous = nil + q.parents.any? do |parent| + case parent + when Paren, Statements + # If we hit certain breakpoints then we know we're safe. + return false + when If, IfOp, Unless, While, Until + return true if parent.predicate == previous + end + + previous = parent + false + end + end + + def format_break(q, break_opening, break_closing) + q.text(" ") + q.format(BlockOpenFormatter.new(break_opening, opening), stackable: false) + + if block_var + q.text(" ") + q.format(block_var) + end + + unless bodystmt.empty? + q.indent do + q.breakable_space + q.format(bodystmt) + end + end + + q.breakable_space + q.text(break_closing) + end + + def format_flat(q, flat_opening, flat_closing) + q.text(" ") + q.format(BlockOpenFormatter.new(flat_opening, opening), stackable: false) + + if block_var + q.breakable_space + q.format(block_var) + q.breakable_space + end + + if bodystmt.empty? + q.text(" ") if flat_opening == "do" + else + q.breakable_space unless block_var + q.format(bodystmt) + q.breakable_space + end + + q.text(flat_closing) end end @@ -6144,7 +6074,7 @@ class MethodAddBlock < Node # [Call | Command | CommandCall] the method call attr_reader :call - # [BraceBlock | DoBlock] the block being sent with the method call + # [Block] the block being sent with the method call attr_reader :block # [Array[ Comment | EmbDoc ]] the comments attached to this node diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index 797f69d2..c7ac5e74 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -920,7 +920,7 @@ def on_bodystmt(statements, rescue_clause, else_clause, ensure_clause) # on_brace_block: ( # (nil | BlockVar) block_var, # Statements statements - # ) -> BraceBlock + # ) -> Block def on_brace_block(block_var, statements) lbrace = consume_token(LBrace) rbrace = consume_token(RBrace) @@ -947,10 +947,10 @@ def on_brace_block(block_var, statements) end_column: rbrace.location.end_column ) - BraceBlock.new( - lbrace: lbrace, + Block.new( + opening: lbrace, block_var: block_var, - statements: statements, + bodystmt: statements, location: location ) end @@ -1336,7 +1336,7 @@ def on_defs(target, operator, name, params, bodystmt) end # :call-seq: - # on_do_block: (BlockVar block_var, BodyStmt bodystmt) -> DoBlock + # on_do_block: (BlockVar block_var, BodyStmt bodystmt) -> Block def on_do_block(block_var, bodystmt) beginning = consume_keyword(:do) ending = consume_keyword(:end) @@ -1350,8 +1350,8 @@ def on_do_block(block_var, bodystmt) ending.location.start_column ) - DoBlock.new( - keyword: beginning, + Block.new( + opening: beginning, block_var: block_var, bodystmt: bodystmt, location: beginning.location.to(ending.location) @@ -2328,7 +2328,7 @@ def on_method_add_arg(call, arguments) # :call-seq: # on_method_add_block: ( # (Call | Command | CommandCall) call, - # (BraceBlock | DoBlock) block + # Block block # ) -> MethodAddBlock def on_method_add_block(call, block) MethodAddBlock.new( diff --git a/lib/syntax_tree/visitor.rb b/lib/syntax_tree/visitor.rb index 9748d0e1..2ee0fc15 100644 --- a/lib/syntax_tree/visitor.rb +++ b/lib/syntax_tree/visitor.rb @@ -62,6 +62,9 @@ class Visitor < BasicVisitor # Visit a Binary node. alias visit_binary visit_child_nodes + # Visit a Block node. + alias visit_block visit_child_nodes + # Visit a BlockArg node. alias visit_blockarg visit_child_nodes @@ -71,9 +74,6 @@ class Visitor < BasicVisitor # Visit a BodyStmt node. alias visit_bodystmt visit_child_nodes - # Visit a BraceBlock node. - alias visit_brace_block visit_child_nodes - # Visit a Break node. alias visit_break visit_child_nodes @@ -122,9 +122,6 @@ class Visitor < BasicVisitor # Visit a Defined node. alias visit_defined visit_child_nodes - # Visit a DoBlock node. - alias visit_do_block visit_child_nodes - # Visit a DynaSymbol node. alias visit_dyna_symbol visit_child_nodes diff --git a/lib/syntax_tree/visitor/field_visitor.rb b/lib/syntax_tree/visitor/field_visitor.rb index 0fc8c908..e1e75474 100644 --- a/lib/syntax_tree/visitor/field_visitor.rb +++ b/lib/syntax_tree/visitor/field_visitor.rb @@ -184,6 +184,14 @@ def visit_binary(node) end end + def visit_block(node) + node(node, "block") do + field("block_var", node.block_var) if node.block_var + field("bodystmt", node.bodystmt) + comments(node) + end + end + def visit_blockarg(node) node(node, "blockarg") do field("name", node.name) if node.name @@ -209,14 +217,6 @@ def visit_bodystmt(node) end end - def visit_brace_block(node) - node(node, "brace_block") do - field("block_var", node.block_var) if node.block_var - field("statements", node.statements) - comments(node) - end - end - def visit_break(node) node(node, "break") do field("arguments", node.arguments) @@ -331,14 +331,6 @@ def visit_defined(node) end end - def visit_do_block(node) - node(node, "do_block") do - field("block_var", node.block_var) if node.block_var - field("bodystmt", node.bodystmt) - comments(node) - end - end - def visit_dyna_symbol(node) node(node, "dyna_symbol") do list("parts", node.parts) diff --git a/test/node_test.rb b/test/node_test.rb index 8bb28131..05618552 100644 --- a/test/node_test.rb +++ b/test/node_test.rb @@ -276,7 +276,7 @@ def test_brace_block source = "method { |variable| variable + 1 }" at = location(chars: 7..34) - assert_node(BraceBlock, source, at: at, &:block) + assert_node(Block, source, at: at, &:block) end def test_break @@ -410,7 +410,7 @@ def test_do_block source = "method do |variable| variable + 1 end" at = location(chars: 7..37) - assert_node(DoBlock, source, at: at, &:block) + assert_node(Block, source, at: at, &:block) end def test_dot2 @@ -647,7 +647,7 @@ def test_lbrace source = "method {}" at = location(chars: 7..8) - assert_node(LBrace, source, at: at) { |node| node.block.lbrace } + assert_node(LBrace, source, at: at) { |node| node.block.opening } end def test_lparen From 0059a828241892c84c83196c758da92a4e6bfdbf Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 18:16:15 -0400 Subject: [PATCH 13/35] Remove the "value" field from ZSuper --- CHANGELOG.md | 1 + lib/syntax_tree/node.rb | 10 +++------- lib/syntax_tree/parser.rb | 2 +- lib/syntax_tree/visitor/field_visitor.rb | 4 +++- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92f03f01..989c0657 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - `Dot2` and `Dot3` are no longer nodes. Instead they have become a single new `RangeLiteral` node. This node looks the same as `Dot2` and `Dot3`, except that it additionally has an `operator` field that contains the operator that created the node. Consequently, the `visit_dot2` and `visit_dot3` methods have been removed from the visitor interface. If you were previously using these methods, you should now use `visit_range_literal` instead. - `DefEndless` and `Defs` have both been folded into the `Def` node. The `Def` node now has the `target` and `operator` fields which originally came from `Defs` which can both be `nil`. It also now has an `endless?` method on it to tell if the original node was found in the endless form. Finally the `bodystmt` field can now either be a `BodyStmt` as it was or any other kind of node since that was the body of the `DefEndless` node. The `visit_defs` and `visit_def_endless` methods on the visitor have therefore been removed. - `DoBlock` and `BraceBlock` have now been folded into a `Block` node. The `Block` node now has a `keywords?` method on it that returns true if the block was constructed with the `do`..`end` keywords. The `visit_do_block` and `visit_brace_block` methods on the visitor have therefore been removed and replaced with the `visit_block` method. +- The `ZSuper` node no longer has a `value` field associated with it (which was always a "super" string literal). ## [4.3.0] - 2022-10-28 diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index 0ab33b83..f6baef2f 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -9830,14 +9830,10 @@ def format(q) # super # class ZSuper < Node - # [String] the value of the keyword - attr_reader :value - # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:) - @value = value + def initialize(location:) @location = location @comments = [] end @@ -9853,11 +9849,11 @@ def child_nodes alias deconstruct child_nodes def deconstruct_keys(_keys) - { value: value, location: location, comments: comments } + { location: location, comments: comments } end def format(q) - q.text(value) + q.text("super") end end end diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index c7ac5e74..32b4562a 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -3908,7 +3908,7 @@ def on_yield0 def on_zsuper keyword = consume_keyword(:super) - ZSuper.new(value: keyword.value, location: keyword.location) + ZSuper.new(location: keyword.location) end end end diff --git a/lib/syntax_tree/visitor/field_visitor.rb b/lib/syntax_tree/visitor/field_visitor.rb index e1e75474..4fab1b6c 100644 --- a/lib/syntax_tree/visitor/field_visitor.rb +++ b/lib/syntax_tree/visitor/field_visitor.rb @@ -1023,7 +1023,9 @@ def visit_yield(node) end def visit_zsuper(node) - visit_token(node, "zsuper") + node(node, "zsuper") do + comments(node) + end end def visit___end__(node) From 0bdddcccd08827032434fd699391416d547fc944 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 18:21:25 -0400 Subject: [PATCH 14/35] Fold Return0 into Return --- CHANGELOG.md | 1 + lib/syntax_tree/node.rb | 53 ++++++------------------ lib/syntax_tree/parser.rb | 4 +- lib/syntax_tree/visitor.rb | 3 -- lib/syntax_tree/visitor/field_visitor.rb | 4 -- test/node_test.rb | 2 +- 6 files changed, 16 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 989c0657..2d1fb994 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - `Dot2` and `Dot3` are no longer nodes. Instead they have become a single new `RangeLiteral` node. This node looks the same as `Dot2` and `Dot3`, except that it additionally has an `operator` field that contains the operator that created the node. Consequently, the `visit_dot2` and `visit_dot3` methods have been removed from the visitor interface. If you were previously using these methods, you should now use `visit_range_literal` instead. - `DefEndless` and `Defs` have both been folded into the `Def` node. The `Def` node now has the `target` and `operator` fields which originally came from `Defs` which can both be `nil`. It also now has an `endless?` method on it to tell if the original node was found in the endless form. Finally the `bodystmt` field can now either be a `BodyStmt` as it was or any other kind of node since that was the body of the `DefEndless` node. The `visit_defs` and `visit_def_endless` methods on the visitor have therefore been removed. - `DoBlock` and `BraceBlock` have now been folded into a `Block` node. The `Block` node now has a `keywords?` method on it that returns true if the block was constructed with the `do`..`end` keywords. The `visit_do_block` and `visit_brace_block` methods on the visitor have therefore been removed and replaced with the `visit_block` method. + - `Return0` is no longer a node. Instead if has been folded into the `Return` node. The `Return` node can now have its `arguments` field be `nil`. Consequently, the `visit_return0` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_return` instead. - The `ZSuper` node no longer has a `value` field associated with it (which was always a "super" string literal). ## [4.3.0] - 2022-10-28 diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index f6baef2f..31e27da1 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -1975,6 +1975,13 @@ def initialize(keyword, node) end def format(q) + # If there are no arguments associated with this flow control, then we can + # safely just print the keyword and return. + if node.arguments.nil? + q.text(keyword) + return + end + q.group do q.text(keyword) @@ -5077,8 +5084,8 @@ def call(q, node) def ternaryable?(statement) case statement when Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfOp, - Lambda, MAssign, Next, OpAssign, RescueMod, Return, Return0, Super, - Undef, Unless, Until, VoidStmt, While, Yield, ZSuper + Lambda, MAssign, Next, OpAssign, RescueMod, Return, Super, Undef, + Unless, Until, VoidStmt, While, Yield, ZSuper # This is a list of nodes that should not be allowed to be a part of a # ternary clause. false @@ -5351,8 +5358,8 @@ def deconstruct_keys(_keys) def format(q) force_flat = [ Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfOp, Lambda, - MAssign, Next, OpAssign, RescueMod, Return, Return0, Super, Undef, - Unless, VoidStmt, Yield, ZSuper + MAssign, Next, OpAssign, RescueMod, Return, Super, Undef, Unless, + VoidStmt, Yield, ZSuper ] if q.parent.is_a?(Paren) || force_flat.include?(truthy.class) || @@ -7739,7 +7746,7 @@ def format(q) # return value # class Return < Node - # [Args] the arguments being passed to the keyword + # [nil | Args] the arguments being passed to the keyword attr_reader :arguments # [Array[ Comment | EmbDoc ]] the comments attached to this node @@ -7770,42 +7777,6 @@ def format(q) end end - # Return0 represents the bare +return+ keyword with no arguments. - # - # return - # - class Return0 < Node - # [String] the value of the keyword - attr_reader :value - - # [Array[ Comment | EmbDoc ]] the comments attached to this node - attr_reader :comments - - def initialize(value:, location:) - @value = value - @location = location - @comments = [] - end - - def accept(visitor) - visitor.visit_return0(self) - end - - def child_nodes - [] - end - - alias deconstruct child_nodes - - def deconstruct_keys(_keys) - { value: value, location: location, comments: comments } - end - - def format(q) - q.text(value) - end - end - # RParen represents the use of a right parenthesis, i.e., +)+. class RParen < Node # [String] the parenthesis diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index 32b4562a..9fe750d7 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -3084,11 +3084,11 @@ def on_return(arguments) end # :call-seq: - # on_return0: () -> Return0 + # on_return0: () -> Return def on_return0 keyword = consume_keyword(:return) - Return0.new(value: keyword.value, location: keyword.location) + Return.new(arguments: nil, location: keyword.location) end # :call-seq: diff --git a/lib/syntax_tree/visitor.rb b/lib/syntax_tree/visitor.rb index 2ee0fc15..57aca619 100644 --- a/lib/syntax_tree/visitor.rb +++ b/lib/syntax_tree/visitor.rb @@ -338,9 +338,6 @@ class Visitor < BasicVisitor # Visit a Return node. alias visit_return visit_child_nodes - # Visit a Return0 node. - alias visit_return0 visit_child_nodes - # Visit a RParen node. alias visit_rparen visit_child_nodes diff --git a/lib/syntax_tree/visitor/field_visitor.rb b/lib/syntax_tree/visitor/field_visitor.rb index 4fab1b6c..150a4e97 100644 --- a/lib/syntax_tree/visitor/field_visitor.rb +++ b/lib/syntax_tree/visitor/field_visitor.rb @@ -789,10 +789,6 @@ def visit_return(node) end end - def visit_return0(node) - visit_token(node, "return0") - end - def visit_rparen(node) node(node, "rparen") { field("value", node.value) } end diff --git a/test/node_test.rb b/test/node_test.rb index 05618552..cbfc6173 100644 --- a/test/node_test.rb +++ b/test/node_test.rb @@ -841,7 +841,7 @@ def test_return end def test_return0 - assert_node(Return0, "return") + assert_node(Return, "return") end def test_sclass From 1a006d47262494ed7f4b7a29ab7667d63b9e3fa2 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 18:24:12 -0400 Subject: [PATCH 15/35] Drop the value attribute from Redo and Retry --- CHANGELOG.md | 2 +- lib/syntax_tree/node.rb | 20 ++++++-------------- lib/syntax_tree/parser.rb | 4 ++-- lib/syntax_tree/visitor/field_visitor.rb | 6 ++++-- 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d1fb994..d3c3e915 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - `DefEndless` and `Defs` have both been folded into the `Def` node. The `Def` node now has the `target` and `operator` fields which originally came from `Defs` which can both be `nil`. It also now has an `endless?` method on it to tell if the original node was found in the endless form. Finally the `bodystmt` field can now either be a `BodyStmt` as it was or any other kind of node since that was the body of the `DefEndless` node. The `visit_defs` and `visit_def_endless` methods on the visitor have therefore been removed. - `DoBlock` and `BraceBlock` have now been folded into a `Block` node. The `Block` node now has a `keywords?` method on it that returns true if the block was constructed with the `do`..`end` keywords. The `visit_do_block` and `visit_brace_block` methods on the visitor have therefore been removed and replaced with the `visit_block` method. - `Return0` is no longer a node. Instead if has been folded into the `Return` node. The `Return` node can now have its `arguments` field be `nil`. Consequently, the `visit_return0` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_return` instead. -- The `ZSuper` node no longer has a `value` field associated with it (which was always a "super" string literal). +- The `Redo`, `Retry`, and `ZSuper` nodes no longer have `value` fields associated with them (which were always string literals corresponding to the keyword being used). ## [4.3.0] - 2022-10-28 diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index 31e27da1..f93f4935 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -7199,14 +7199,10 @@ def deconstruct_keys(_keys) # redo # class Redo < Node - # [String] the value of the keyword - attr_reader :value - # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:) - @value = value + def initialize(location:) @location = location @comments = [] end @@ -7222,11 +7218,11 @@ def child_nodes alias deconstruct child_nodes def deconstruct_keys(_keys) - { value: value, location: location, comments: comments } + { location: location, comments: comments } end def format(q) - q.text(value) + q.text("redo") end end @@ -7710,14 +7706,10 @@ def format(q) # retry # class Retry < Node - # [String] the value of the keyword - attr_reader :value - # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:) - @value = value + def initialize(location:) @location = location @comments = [] end @@ -7733,11 +7725,11 @@ def child_nodes alias deconstruct child_nodes def deconstruct_keys(_keys) - { value: value, location: location, comments: comments } + { location: location, comments: comments } end def format(q) - q.text(value) + q.text("retry") end end diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index 9fe750d7..ef0b77a0 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -2903,7 +2903,7 @@ def on_rbracket(value) def on_redo keyword = consume_keyword(:redo) - Redo.new(value: keyword.value, location: keyword.location) + Redo.new(location: keyword.location) end # :call-seq: @@ -3069,7 +3069,7 @@ def on_rest_param(name) def on_retry keyword = consume_keyword(:retry) - Retry.new(value: keyword.value, location: keyword.location) + Retry.new(location: keyword.location) end # :call-seq: diff --git a/lib/syntax_tree/visitor/field_visitor.rb b/lib/syntax_tree/visitor/field_visitor.rb index 150a4e97..d32dc877 100644 --- a/lib/syntax_tree/visitor/field_visitor.rb +++ b/lib/syntax_tree/visitor/field_visitor.rb @@ -723,7 +723,7 @@ def visit_rbracket(node) end def visit_redo(node) - visit_token(node, "redo") + node(node, "redo") { comments(node) } end def visit_regexp_beg(node) @@ -779,7 +779,9 @@ def visit_rest_param(node) end def visit_retry(node) - visit_token(node, "retry") + node(node, "retry") do + comments(node) + end end def visit_return(node) From 73e59c7760809af285eb231772a94be32e6768f7 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 18:25:55 -0400 Subject: [PATCH 16/35] Remove ArgsForward value --- CHANGELOG.md | 2 +- lib/syntax_tree/node.rb | 10 +++------- lib/syntax_tree/parser.rb | 2 +- lib/syntax_tree/visitor/field_visitor.rb | 2 +- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3c3e915..a2fae5b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - `DefEndless` and `Defs` have both been folded into the `Def` node. The `Def` node now has the `target` and `operator` fields which originally came from `Defs` which can both be `nil`. It also now has an `endless?` method on it to tell if the original node was found in the endless form. Finally the `bodystmt` field can now either be a `BodyStmt` as it was or any other kind of node since that was the body of the `DefEndless` node. The `visit_defs` and `visit_def_endless` methods on the visitor have therefore been removed. - `DoBlock` and `BraceBlock` have now been folded into a `Block` node. The `Block` node now has a `keywords?` method on it that returns true if the block was constructed with the `do`..`end` keywords. The `visit_do_block` and `visit_brace_block` methods on the visitor have therefore been removed and replaced with the `visit_block` method. - `Return0` is no longer a node. Instead if has been folded into the `Return` node. The `Return` node can now have its `arguments` field be `nil`. Consequently, the `visit_return0` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_return` instead. -- The `Redo`, `Retry`, and `ZSuper` nodes no longer have `value` fields associated with them (which were always string literals corresponding to the keyword being used). +- The `ArgsForward`, `Redo`, `Retry`, and `ZSuper` nodes no longer have `value` fields associated with them (which were always string literals corresponding to the keyword being used). ## [4.3.0] - 2022-10-28 diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index f93f4935..b1ddcc43 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -771,14 +771,10 @@ def format(q) # The ArgsForward node appears in both the caller (the request method calls) # and the callee (the get and post definitions). class ArgsForward < Node - # [String] the value of the operator - attr_reader :value - # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(value:, location:) - @value = value + def initialize(location:) @location = location @comments = [] end @@ -794,11 +790,11 @@ def child_nodes alias deconstruct child_nodes def deconstruct_keys(_keys) - { value: value, location: location, comments: comments } + { location: location, comments: comments } end def format(q) - q.text(value) + q.text("...") end end diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index ef0b77a0..324dfb47 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -575,7 +575,7 @@ def on_args_add_star(arguments, argument) def on_args_forward op = consume_operator(:"...") - ArgsForward.new(value: op.value, location: op.location) + ArgsForward.new(location: op.location) end # :call-seq: diff --git a/lib/syntax_tree/visitor/field_visitor.rb b/lib/syntax_tree/visitor/field_visitor.rb index d32dc877..c8014106 100644 --- a/lib/syntax_tree/visitor/field_visitor.rb +++ b/lib/syntax_tree/visitor/field_visitor.rb @@ -103,7 +103,7 @@ def visit_args(node) end def visit_args_forward(node) - visit_token(node, "args_forward") + node(node, "args_forward") { comments(node) } end def visit_array(node) From 321c5b9ba56f021abfe098ab126fc925c1b769e4 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 18:30:51 -0400 Subject: [PATCH 17/35] Move block down to CommandCall --- CHANGELOG.md | 1 + lib/syntax_tree/node.rb | 12 ++++++++++-- lib/syntax_tree/parser.rb | 27 ++++++++++++++++++++++----- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2fae5b7..435c4f54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - `DoBlock` and `BraceBlock` have now been folded into a `Block` node. The `Block` node now has a `keywords?` method on it that returns true if the block was constructed with the `do`..`end` keywords. The `visit_do_block` and `visit_brace_block` methods on the visitor have therefore been removed and replaced with the `visit_block` method. - `Return0` is no longer a node. Instead if has been folded into the `Return` node. The `Return` node can now have its `arguments` field be `nil`. Consequently, the `visit_return0` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_return` instead. - The `ArgsForward`, `Redo`, `Retry`, and `ZSuper` nodes no longer have `value` fields associated with them (which were always string literals corresponding to the keyword being used). +- `CommandCall` now has a `block` attribute on it. This attribute is used in the place where you would previously have a `MethodAddBlock` structure. Where before the `MethodAddBlock` would have the `CommandCall` and `Block` as its two children, you now just have one `CommandCall` node with the `block` attribute set to the `Block` node. ## [4.3.0] - 2022-10-28 diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index b1ddcc43..9cd2dba6 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -2936,6 +2936,9 @@ class CommandCall < Node # [nil | Args] the arguments going along with the message attr_reader :arguments + # [nil | Block] the block associated with this method call + attr_reader :block + # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments @@ -2944,6 +2947,7 @@ def initialize( operator:, message:, arguments:, + block:, location:, comments: [] ) @@ -2951,6 +2955,7 @@ def initialize( @operator = operator @message = message @arguments = arguments + @block = block @location = location @comments = [] end @@ -2971,6 +2976,7 @@ def deconstruct_keys(_keys) operator: operator, message: message, arguments: arguments, + block: block, location: location, comments: comments } @@ -3011,6 +3017,8 @@ def format(q) end end end + + q.format(block) if block end private @@ -3559,8 +3567,8 @@ def format(q) # If the receiver of this block a Command or CommandCall node, then there # are no parentheses around the arguments to that command, so we need to # break the block. - case q.parent.call - when Command, CommandCall + parent = q.parent + if (parent.is_a?(MethodAddBlock) && parent.call.is_a?(Command)) || parent.is_a?(CommandCall) q.break_parent format_break(q, break_opening, break_closing) return diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index 324dfb47..257a25c2 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -1095,6 +1095,7 @@ def on_command_call(receiver, operator, message, arguments) operator: operator, message: message, arguments: arguments, + block: nil, location: receiver.location.to(ending.location) ) end @@ -2331,11 +2332,27 @@ def on_method_add_arg(call, arguments) # Block block # ) -> MethodAddBlock def on_method_add_block(call, block) - MethodAddBlock.new( - call: call, - block: block, - location: call.location.to(block.location) - ) + case call + when CommandCall + node = + CommandCall.new( + receiver: call.receiver, + operator: call.operator, + message: call.message, + arguments: call.arguments, + block: block, + location: call.location.to(block.location) + ) + + node.comments.concat(call.comments) + node + else + MethodAddBlock.new( + call: call, + block: block, + location: call.location.to(block.location) + ) + end end # :call-seq: From e0ce4ffbcdad0c8dddb8bcf25a807ebc08c64f3d Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 18:34:39 -0400 Subject: [PATCH 18/35] Move block down to the command node --- CHANGELOG.md | 2 +- lib/syntax_tree/node.rb | 17 ++++++++++++----- lib/syntax_tree/parser.rb | 12 ++++++++++++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 435c4f54..642e7866 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - `DoBlock` and `BraceBlock` have now been folded into a `Block` node. The `Block` node now has a `keywords?` method on it that returns true if the block was constructed with the `do`..`end` keywords. The `visit_do_block` and `visit_brace_block` methods on the visitor have therefore been removed and replaced with the `visit_block` method. - `Return0` is no longer a node. Instead if has been folded into the `Return` node. The `Return` node can now have its `arguments` field be `nil`. Consequently, the `visit_return0` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_return` instead. - The `ArgsForward`, `Redo`, `Retry`, and `ZSuper` nodes no longer have `value` fields associated with them (which were always string literals corresponding to the keyword being used). -- `CommandCall` now has a `block` attribute on it. This attribute is used in the place where you would previously have a `MethodAddBlock` structure. Where before the `MethodAddBlock` would have the `CommandCall` and `Block` as its two children, you now just have one `CommandCall` node with the `block` attribute set to the `Block` node. +- The `Command` and `CommandCall` nodes now has `block` attributes on them. These attributes are used in the place where you would previously have had a `MethodAddBlock` structure. Where before the `MethodAddBlock` would have the command and block as its two children, you now just have one command node with the `block` attribute set to the `Block` node. ## [4.3.0] - 2022-10-28 diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index 9cd2dba6..e966e32f 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -2847,12 +2847,16 @@ class Command < Node # [Args] the arguments being sent with the message attr_reader :arguments + # [nil | Block] the optional block being passed to the method + attr_reader :block + # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize(message:, arguments:, location:) + def initialize(message:, arguments:, block:, location:) @message = message @arguments = arguments + @block = block @location = location @comments = [] end @@ -2862,7 +2866,7 @@ def accept(visitor) end def child_nodes - [message, arguments] + [message, arguments, block] end alias deconstruct child_nodes @@ -2871,6 +2875,7 @@ def deconstruct_keys(_keys) { message: message, arguments: arguments, + block: block, location: location, comments: comments } @@ -2881,6 +2886,8 @@ def format(q) q.format(message) align(q, self) { q.format(arguments) } end + + q.format(block) if block end private @@ -2965,7 +2972,7 @@ def accept(visitor) end def child_nodes - [receiver, message, arguments] + [receiver, message, arguments, block] end alias deconstruct child_nodes @@ -3567,8 +3574,8 @@ def format(q) # If the receiver of this block a Command or CommandCall node, then there # are no parentheses around the arguments to that command, so we need to # break the block. - parent = q.parent - if (parent.is_a?(MethodAddBlock) && parent.call.is_a?(Command)) || parent.is_a?(CommandCall) + case q.parent + when Command, CommandCall q.break_parent format_break(q, break_opening, break_closing) return diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index 257a25c2..9344653b 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -1076,6 +1076,7 @@ def on_command(message, arguments) Command.new( message: message, arguments: arguments, + block: nil, location: message.location.to(arguments.location) ) end @@ -2333,6 +2334,17 @@ def on_method_add_arg(call, arguments) # ) -> MethodAddBlock def on_method_add_block(call, block) case call + when Command + node = + Command.new( + message: call.message, + arguments: call.arguments, + block: block, + location: call.location.to(block.location) + ) + + node.comments.concat(call.comments) + node when CommandCall node = CommandCall.new( From 9bbf6cf5e65718fbe777bb3bde0f3929bfefa04f Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Tue, 8 Nov 2022 11:55:30 +0100 Subject: [PATCH 19/35] Unskip test_multiple_inline_scripts on TruffleRuby * StringIO is thread-safe now so this test should pass reliably. --- test/cli_test.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/test/cli_test.rb b/test/cli_test.rb index c00fb338..b4ef0afc 100644 --- a/test/cli_test.rb +++ b/test/cli_test.rb @@ -148,7 +148,6 @@ def test_inline_script end def test_multiple_inline_scripts - skip if RUBY_ENGINE == "truffleruby" # Relies on a thread-safe StringIO stdio, = capture_io { SyntaxTree::CLI.run(%w[format -e 1+1 -e 2+2]) } assert_equal(["1 + 1", "2 + 2"], stdio.split("\n").sort) end From b8bebe0aee7335e06e6f6271dd07408abb0b269b Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 2 Nov 2022 18:40:40 -0400 Subject: [PATCH 20/35] Fix up call chaining with new folded nodes --- lib/syntax_tree/node.rb | 71 ++++++++++++++++-------- lib/syntax_tree/parser.rb | 23 ++++++-- lib/syntax_tree/visitor/field_visitor.rb | 8 +-- 3 files changed, 68 insertions(+), 34 deletions(-) diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index e966e32f..97bec379 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -359,7 +359,8 @@ class Alias < Node # Formats an argument to the alias keyword. For symbol literals it uses the # value of the symbol directly to look like bare words. class AliasArgumentFormatter - # [Backref | DynaSymbol | GVar | SymbolLiteral] the argument being passed to alias + # [Backref | DynaSymbol | GVar | SymbolLiteral] the argument being passed + # to alias attr_reader :argument def initialize(argument) @@ -2245,14 +2246,26 @@ def format(q) when Call case (receiver = child.receiver) when Call - children << receiver + if receiver.receiver.nil? + break + else + children << receiver + end when MethodAddBlock - receiver.call.is_a?(Call) ? children << receiver : break + if receiver.call.is_a?(Call) && !receiver.call.receiver.nil? + children << receiver + else + break + end else break end when MethodAddBlock - child.call.is_a?(Call) ? children << child.call : break + if child.call.is_a?(Call) && !child.call.receiver.nil? + children << child.call + else + break + end else break end @@ -2271,7 +2284,8 @@ def format(q) # of just Statements nodes. parent = parents[3] if parent.is_a?(Block) && parent.keywords? - if parent.is_a?(MethodAddBlock) && parent.call.is_a?(Call) && parent.call.message.value == "sig" + if parent.is_a?(MethodAddBlock) && parent.call.is_a?(Call) && + parent.call.message.value == "sig" threshold = 2 end end @@ -2300,7 +2314,7 @@ def format_chain(q, children) # formatter so it's as if we had descending normally into them. This is # necessary so they can check their parents as normal. q.stack.concat(children) - q.format(children.last.receiver) + q.format(children.last.receiver) if children.last.receiver q.group do if attach_directly?(children.last) @@ -2343,7 +2357,8 @@ def format_chain(q, children) # If the parent call node has a comment on the message then we need # to print the operator trailing in order to keep it working. last_child = children.last - if last_child.is_a?(Call) && last_child.message.comments.any? + if last_child.is_a?(Call) && last_child.message.comments.any? && + last_child.operator q.format(CallOperatorFormatter.new(last_child.operator)) skip_operator = true else @@ -2372,9 +2387,9 @@ def self.chained?(node) case node when Call - true + !node.receiver.nil? when MethodAddBlock - node.call.is_a?(Call) + node.call.is_a?(Call) && !node.call.receiver.nil? else false end @@ -2405,7 +2420,7 @@ def format_child( case child when Call q.group do - unless skip_operator + if !skip_operator && child.operator q.format(CallOperatorFormatter.new(child.operator)) end q.format(child.message) if child.message != :call @@ -2495,7 +2510,8 @@ def format(q) # If we're at the top of a call chain, then we're going to do some # specialized printing in case we can print it nicely. We _only_ do this # at the top of the chain to avoid weird recursion issues. - if CallChainFormatter.chained?(receiver) && !CallChainFormatter.chained?(q.parent) + if CallChainFormatter.chained?(receiver) && + !CallChainFormatter.chained?(q.parent) q.group do q .if_break { CallChainFormatter.new(self).format(q) } @@ -2507,11 +2523,13 @@ def format(q) else q.format(message) - if arguments.is_a?(ArgParen) && arguments.arguments.nil? && !message.is_a?(Const) - # If you're using an explicit set of parentheses on something that looks - # like a constant, then we need to match that in order to maintain valid - # Ruby. For example, you could do something like Foo(), on which we - # would need to keep the parentheses to make it look like a method call. + if arguments.is_a?(ArgParen) && arguments.arguments.nil? && + !message.is_a?(Const) + # If you're using an explicit set of parentheses on something that + # looks like a constant, then we need to match that in order to + # maintain valid Ruby. For example, you could do something like Foo(), + # on which we would need to keep the parentheses to make it look like + # a method call. else q.format(arguments) end @@ -3726,7 +3744,13 @@ def child_nodes alias deconstruct child_nodes def deconstruct_keys(_keys) - { left: left, operator: operator, right: right, location: location, comments: comments } + { + left: left, + operator: operator, + right: right, + location: location, + comments: comments + } end def format(q) @@ -5133,7 +5157,11 @@ def format(q) if ContainsAssignment.call(statement) || q.parent.is_a?(In) q.group { format_flat(q) } else - q.group { q.if_break { format_break(q, force: false) }.if_flat { format_flat(q) } } + q.group do + q + .if_break { format_break(q, force: false) } + .if_flat { format_flat(q) } + end end else # If we can transform this node into a ternary, then we're going to @@ -9063,7 +9091,8 @@ def format(q) # # foo = bar while foo # - if node.modifier? && (statement = node.statements.body.first) && (statement.is_a?(Begin) || ContainsAssignment.call(statement)) + if node.modifier? && (statement = node.statements.body.first) && + (statement.is_a?(Begin) || ContainsAssignment.call(statement)) q.format(statement) q.text(" #{keyword} ") q.format(node.predicate) @@ -9466,9 +9495,7 @@ def format(q) # last argument to the predicate is and endless range, then you are # forced to use the "then" keyword to make it parse properly. last = arguments.parts.last - if last.is_a?(RangeLiteral) && !last.right - q.text(" then") - end + q.text(" then") if last.is_a?(RangeLiteral) && !last.right end end diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index 9344653b..cd14672e 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -1616,7 +1616,13 @@ def on_excessed_comma(*) # :call-seq: # on_fcall: ((Const | Ident) value) -> Call def on_fcall(value) - Call.new(receiver: nil, operator: nil, message: value, arguments: nil, location: value.location) + Call.new( + receiver: nil, + operator: nil, + message: value, + arguments: nil, + location: value.location + ) end # :call-seq: @@ -1923,7 +1929,8 @@ def on_if_mod(predicate, statement) If.new( predicate: predicate, - statements: Statements.new(self, body: [statement], location: statement.location), + statements: + Statements.new(self, body: [statement], location: statement.location), consequent: nil, location: statement.location.to(predicate.location) ) @@ -2209,7 +2216,8 @@ def lambda_locals(source) on_comma: :item, on_rparen: :final }, - final: {} + final: { + } } tokens[(index + 1)..].each_with_object([]) do |token, locals| @@ -3622,7 +3630,8 @@ def on_unless_mod(predicate, statement) Unless.new( predicate: predicate, - statements: Statements.new(self, body: [statement], location: statement.location), + statements: + Statements.new(self, body: [statement], location: statement.location), consequent: nil, location: statement.location.to(predicate.location) ) @@ -3665,7 +3674,8 @@ def on_until_mod(predicate, statement) Until.new( predicate: predicate, - statements: Statements.new(self, body: [statement], location: statement.location), + statements: + Statements.new(self, body: [statement], location: statement.location), location: statement.location.to(predicate.location) ) end @@ -3791,7 +3801,8 @@ def on_while_mod(predicate, statement) While.new( predicate: predicate, - statements: Statements.new(self, body: [statement], location: statement.location), + statements: + Statements.new(self, body: [statement], location: statement.location), location: statement.location.to(predicate.location) ) end diff --git a/lib/syntax_tree/visitor/field_visitor.rb b/lib/syntax_tree/visitor/field_visitor.rb index c8014106..01c7de4e 100644 --- a/lib/syntax_tree/visitor/field_visitor.rb +++ b/lib/syntax_tree/visitor/field_visitor.rb @@ -779,9 +779,7 @@ def visit_rest_param(node) end def visit_retry(node) - node(node, "retry") do - comments(node) - end + node(node, "retry") { comments(node) } end def visit_return(node) @@ -1021,9 +1019,7 @@ def visit_yield(node) end def visit_zsuper(node) - node(node, "zsuper") do - comments(node) - end + node(node, "zsuper") { comments(node) } end def visit___end__(node) From 686f938b66a6033349d5bd88b94366335be66691 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Tue, 8 Nov 2022 10:45:34 -0500 Subject: [PATCH 21/35] Create #copy API for mutating nodes --- lib/syntax_tree/node.rb | 1437 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 1437 insertions(+) diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index 97bec379..2882687c 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -161,6 +161,15 @@ def child_nodes [lbrace, statements] end + def copy(lbrace: nil, statements: nil, location: nil, comments: nil) + BEGINBlock.new( + lbrace: lbrace || self.lbrace, + statements: statements || self.statements, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -213,6 +222,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + CHAR.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -264,6 +281,15 @@ def child_nodes [lbrace, statements] end + def copy(lbrace: nil, statements: nil, location: nil, comments: nil) + ENDBlock.new( + lbrace: lbrace || self.lbrace, + statements: statements || self.statements, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -319,6 +345,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + EndContent.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -408,6 +442,15 @@ def child_nodes [left, right] end + def copy(left: nil, right: nil, location: nil, comments: nil) + Alias.new( + left: left || self.left, + right: right || self.right, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -473,6 +516,15 @@ def child_nodes [collection, index] end + def copy(collection: nil, index: nil, location: nil, comments: nil) + ARef.new( + collection: collection || self.collection, + index: index || self.index, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -534,6 +586,15 @@ def child_nodes [collection, index] end + def copy(collection: nil, index: nil, location: nil, comments: nil) + ARefField.new( + collection: collection || self.collection, + index: index || self.index, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -596,6 +657,14 @@ def child_nodes [arguments] end + def copy(arguments: nil, location: nil, comments: nil) + ArgParen.new( + arguments: arguments || self.arguments, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -669,6 +738,14 @@ def child_nodes parts end + def copy(parts: nil, location: nil, comments: nil) + Args.new( + parts: parts || self.parts, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -705,6 +782,14 @@ def child_nodes [value] end + def copy(value: nil, location: nil, comments: nil) + ArgBlock.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -742,6 +827,14 @@ def child_nodes [value] end + def copy(value: nil, location: nil, comments: nil) + ArgStar.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -788,6 +881,13 @@ def child_nodes [] end + def copy(location: nil, comments: nil) + ArgsForward.new( + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -971,6 +1071,15 @@ def child_nodes [lbracket, contents] end + def copy(lbracket: nil, contents: nil, location: nil, comments: nil) + ArrayLiteral.new( + lbracket: lbracket || self.lbracket, + contents: contents || self.contents, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -1144,6 +1253,24 @@ def child_nodes [constant, *requireds, rest, *posts] end + def copy( + constant: nil, + requireds: nil, + rest: nil, + posts: nil, + location: nil, + comments: nil + ) + AryPtn.new( + constant: constant || self.constant, + requireds: requireds || self.requireds, + rest: rest || self.rest, + posts: posts || self.posts, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -1225,6 +1352,15 @@ def child_nodes [target, value] end + def copy(target: nil, value: nil, location: nil, comments: nil) + Assign.new( + target: target || self.target, + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -1287,6 +1423,15 @@ def child_nodes [key, value] end + def copy(key: nil, value: nil, location: nil, comments: nil) + Assoc.new( + key: key || self.key, + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -1345,6 +1490,14 @@ def child_nodes [value] end + def copy(value: nil, location: nil, comments: nil) + AssocSplat.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -1383,6 +1536,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + Backref.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -1418,6 +1579,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + Backtick.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -1530,6 +1699,14 @@ def child_nodes assocs end + def copy(assocs: nil, location: nil, comments: nil) + BareAssocHash.new( + assocs: assocs || self.assocs, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -1572,6 +1749,14 @@ def child_nodes [bodystmt] end + def copy(bodystmt: nil, location: nil, comments: nil) + Begin.new( + bodystmt: bodystmt || self.bodystmt, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -1620,6 +1805,14 @@ def child_nodes [statement] end + def copy(statement: nil, location: nil, comments: nil) + PinnedBegin.new( + statement: statement || self.statement, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -1694,6 +1887,16 @@ def child_nodes [left, right] end + def copy(left: nil, operator: nil, right: nil, location: nil, comments: nil) + Binary.new( + left: left || self.left, + operator: operator || self.operator, + right: right || self.right, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -1761,6 +1964,15 @@ def child_nodes [params, *locals] end + def copy(params: nil, locals: nil, location: nil, comments: nil) + BlockVar.new( + params: params || self.params, + locals: locals || self.locals, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -1818,6 +2030,14 @@ def child_nodes [name] end + def copy(name: nil, location: nil, comments: nil) + BlockArg.new( + name: name || self.name, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -1912,6 +2132,24 @@ def child_nodes [statements, rescue_clause, else_keyword, else_clause, ensure_clause] end + def copy( + statements: nil, + rescue_clause: nil, + else_clause: nil, + ensure_clause: nil, + location: nil, + comments: nil + ) + BodyStmt.new( + statements: statements || self.statements, + rescue_clause: rescue_clause || self.rescue_clause, + else_clause: else_clause || self.else_clause, + ensure_clause: ensure_clause || self.ensure_clause, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -2176,6 +2414,14 @@ def child_nodes [arguments] end + def copy(arguments: nil, location: nil, comments: nil) + Break.new( + arguments: arguments || self.arguments, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -2492,6 +2738,24 @@ def child_nodes ] end + def copy( + receiver: nil, + operator: nil, + message: nil, + arguments: nil, + location: nil, + comments: nil + ) + Call.new( + receiver: receiver || self.receiver, + operator: operator || self.operator, + message: message || self.message, + arguments: arguments || self.arguments, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -2617,6 +2881,22 @@ def child_nodes [keyword, value, consequent] end + def copy( + keyword: nil, + value: nil, + consequent: nil, + location: nil, + comments: nil + ) + Case.new( + keyword: keyword || self.keyword, + value: value || self.value, + consequent: consequent || self.consequent, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -2682,6 +2962,22 @@ def child_nodes [value, operator, pattern] end + def copy( + value: nil, + operator: nil, + pattern: nil, + location: nil, + comments: nil + ) + RAssign.new( + value: value || self.value, + operator: operator || self.operator, + pattern: pattern || self.pattern, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -2778,6 +3074,22 @@ def child_nodes [constant, superclass, bodystmt] end + def copy( + constant: nil, + superclass: nil, + bodystmt: nil, + location: nil, + comments: nil + ) + ClassDeclaration.new( + constant: constant || self.constant, + superclass: superclass || self.superclass, + bodystmt: bodystmt || self.bodystmt, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -2845,6 +3157,10 @@ def child_nodes [] end + def copy(value: nil, location: nil) + Comma.new(value: value || self.value, location: location || self.location) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -2887,6 +3203,22 @@ def child_nodes [message, arguments, block] end + def copy( + message: nil, + arguments: nil, + block: nil, + location: nil, + comments: nil + ) + Command.new( + message: message || self.message, + arguments: arguments || self.arguments, + block: block || self.block, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -2993,6 +3325,26 @@ def child_nodes [receiver, message, arguments, block] end + def copy( + receiver: nil, + operator: nil, + message: nil, + arguments: nil, + block: nil, + location: nil, + comments: nil + ) + CommandCall.new( + receiver: receiver || self.receiver, + operator: operator || self.operator, + message: message || self.message, + arguments: arguments || self.arguments, + block: block || self.block, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -3125,6 +3477,14 @@ def child_nodes [] end + def copy(value: nil, inline: nil, location: nil) + Comment.new( + value: value || self.value, + inline: inline || self.inline, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -3171,6 +3531,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + Const.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -3213,6 +3581,15 @@ def child_nodes [parent, constant] end + def copy(parent: nil, constant: nil, location: nil, comments: nil) + ConstPathField.new( + parent: parent || self.parent, + constant: constant || self.constant, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -3260,6 +3637,15 @@ def child_nodes [parent, constant] end + def copy(parent: nil, constant: nil, location: nil, comments: nil) + ConstPathRef.new( + parent: parent || self.parent, + constant: constant || self.constant, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -3305,6 +3691,14 @@ def child_nodes [constant] end + def copy(constant: nil, location: nil, comments: nil) + ConstRef.new( + constant: constant || self.constant, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -3341,6 +3735,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + CVar.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -3394,6 +3796,26 @@ def child_nodes [target, operator, name, params, bodystmt] end + def copy( + target: nil, + operator: nil, + name: nil, + params: nil, + bodystmt: nil, + location: nil, + comments: nil + ) + Def.new( + target: target || self.target, + operator: operator || self.operator, + name: name || self.name, + params: params || self.params, + bodystmt: bodystmt || self.bodystmt, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -3484,6 +3906,14 @@ def child_nodes [value] end + def copy(value: nil, location: nil, comments: nil) + Defined.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -3562,6 +3992,22 @@ def child_nodes [opening, block_var, bodystmt] end + def copy( + opening: nil, + block_var: nil, + bodystmt: nil, + location: nil, + comments: nil + ) + Block.new( + opening: opening || self.opening, + block_var: block_var || self.block_var, + bodystmt: bodystmt || self.bodystmt, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -3741,6 +4187,16 @@ def child_nodes [left, right] end + def copy(left: nil, operator: nil, right: nil, location: nil, comments: nil) + RangeLiteral.new( + left: left || self.left, + operator: operator || self.operator, + right: right || self.right, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -3843,6 +4299,15 @@ def child_nodes parts end + def copy(parts: nil, quote: nil, location: nil, comments: nil) + DynaSymbol.new( + parts: parts || self.parts, + quote: quote || self.quote, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -3954,6 +4419,15 @@ def child_nodes [keyword, statements] end + def copy(keyword: nil, statements: nil, location: nil, comments: nil) + Else.new( + keyword: keyword || self.keyword, + statements: statements || self.statements, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4020,6 +4494,22 @@ def child_nodes [predicate, statements, consequent] end + def copy( + predicate: nil, + statements: nil, + consequent: nil, + location: nil, + comments: nil + ) + Elsif.new( + predicate: predicate || self.predicate, + statements: statements || self.statements, + consequent: consequent || self.consequent, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4092,6 +4582,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + EmbDoc.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4127,6 +4624,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + EmbExprBeg.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4157,6 +4661,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + EmbExprEnd.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4189,6 +4700,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + EmbVar.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4228,6 +4746,15 @@ def child_nodes [keyword, statements] end + def copy(keyword: nil, statements: nil, location: nil, comments: nil) + Ensure.new( + keyword: keyword || self.keyword, + statements: statements || self.statements, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4282,6 +4809,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + ExcessedComma.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4327,6 +4862,22 @@ def child_nodes [parent, (operator if operator != :"::"), name] end + def copy( + parent: nil, + operator: nil, + name: nil, + location: nil, + comments: nil + ) + Field.new( + parent: parent || self.parent, + operator: operator || self.operator, + name: name || self.name, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4373,6 +4924,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + FloatLiteral.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4425,6 +4984,24 @@ def child_nodes [constant, left, *values, right] end + def copy( + constant: nil, + left: nil, + values: nil, + right: nil, + location: nil, + comments: nil + ) + FndPtn.new( + constant: constant || self.constant, + left: left || self.left, + values: values || self.values, + right: right || self.right, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4499,6 +5076,22 @@ def child_nodes [index, collection, statements] end + def copy( + index: nil, + collection: nil, + statements: nil, + location: nil, + comments: nil + ) + For.new( + index: index || self.index, + collection: collection || self.collection, + statements: statements || self.statements, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4556,6 +5149,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + GVar.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4622,6 +5223,15 @@ def child_nodes [lbrace] + assocs end + def copy(lbrace: nil, assocs: nil, location: nil, comments: nil) + HashLiteral.new( + lbrace: lbrace || self.lbrace, + assocs: assocs || self.assocs, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4718,6 +5328,22 @@ def child_nodes [beginning, *parts, ending] end + def copy( + beginning: nil, + location: nil, + ending: nil, + parts: nil, + comments: nil + ) + Heredoc.new( + beginning: beginning || self.beginning, + location: location || self.location, + ending: ending || self.ending, + parts: parts || self.parts, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4798,6 +5424,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + HeredocBeg.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4837,6 +5471,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + HeredocEnd.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -4931,6 +5573,22 @@ def child_nodes [constant, *keywords.flatten(1), keyword_rest] end + def copy( + constant: nil, + keywords: nil, + keyword_rest: nil, + location: nil, + comments: nil + ) + HshPtn.new( + constant: constant || self.constant, + keywords: keywords || self.keywords, + keyword_rest: keyword_rest || self.keyword_rest, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -5039,6 +5697,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + Ident.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -5327,6 +5993,22 @@ def child_nodes [predicate, statements, consequent] end + def copy( + predicate: nil, + statements: nil, + consequent: nil, + location: nil, + comments: nil + ) + If.new( + predicate: predicate || self.predicate, + statements: statements || self.statements, + consequent: consequent || self.consequent, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -5382,6 +6064,22 @@ def child_nodes [predicate, truthy, falsy] end + def copy( + predicate: nil, + truthy: nil, + falsy: nil, + location: nil, + comments: nil + ) + IfOp.new( + predicate: predicate || self.predicate, + truthy: truthy || self.truthy, + falsy: falsy || self.falsy, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -5475,6 +6173,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + Imaginary.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -5522,6 +6228,22 @@ def child_nodes [pattern, statements, consequent] end + def copy( + pattern: nil, + statements: nil, + consequent: nil, + location: nil, + comments: nil + ) + In.new( + pattern: pattern || self.pattern, + statements: statements || self.statements, + consequent: consequent || self.consequent, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -5581,6 +6303,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + Int.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -5625,6 +6355,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + IVar.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -5674,6 +6412,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + Kw.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -5711,6 +6457,14 @@ def child_nodes [name] end + def copy(name: nil, location: nil, comments: nil) + KwRestParam.new( + name: name || self.name, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -5757,6 +6511,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + Label.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -5792,6 +6554,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + LabelEnd.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -5828,6 +6597,15 @@ def child_nodes [params, statements] end + def copy(params: nil, statements: nil, location: nil, comments: nil) + Lambda.new( + params: params || self.params, + statements: statements || self.statements, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -5936,6 +6714,15 @@ def child_nodes [params, *locals] end + def copy(params: nil, locals: nil, location: nil, comments: nil) + LambdaVar.new( + params: params || self.params, + locals: locals || self.locals, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -5978,6 +6765,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + LBrace.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -6011,6 +6806,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + LBracket.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -6044,6 +6847,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + LParen.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -6094,6 +6905,15 @@ def child_nodes [target, value] end + def copy(target: nil, value: nil, location: nil, comments: nil) + MAssign.new( + target: target || self.target, + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -6141,6 +6961,15 @@ def child_nodes [call, block] end + def copy(call: nil, block: nil, location: nil, comments: nil) + MethodAddBlock.new( + call: call || self.call, + block: block || self.block, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -6202,6 +7031,15 @@ def child_nodes parts end + def copy(parts: nil, location: nil, comma: nil, comments: nil) + MLHS.new( + parts: parts || self.parts, + location: location || self.location, + comma: comma || self.comma, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -6246,6 +7084,14 @@ def child_nodes [contents] end + def copy(contents: nil, location: nil, comments: nil) + MLHSParen.new( + contents: contents || self.contents, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -6304,6 +7150,15 @@ def child_nodes [constant, bodystmt] end + def copy(constant: nil, bodystmt: nil, location: nil, comments: nil) + ModuleDeclaration.new( + constant: constant || self.constant, + bodystmt: bodystmt || self.bodystmt, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -6373,6 +7228,14 @@ def child_nodes parts end + def copy(parts: nil, location: nil, comments: nil) + MRHS.new( + parts: parts || self.parts, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -6422,6 +7285,14 @@ def child_nodes [arguments] end + def copy(arguments: nil, location: nil, comments: nil) + Next.new( + arguments: arguments || self.arguments, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -6463,6 +7334,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + Op.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -6509,6 +7388,22 @@ def child_nodes [target, operator, value] end + def copy( + target: nil, + operator: nil, + value: nil, + location: nil, + comments: nil + ) + OpAssign.new( + target: target || self.target, + operator: operator || self.operator, + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -6767,6 +7662,30 @@ def child_nodes ] end + def copy( + location: nil, + requireds: nil, + optionals: nil, + rest: nil, + posts: nil, + keywords: nil, + keyword_rest: nil, + block: nil, + comments: nil + ) + Params.new( + location: location || self.location, + requireds: requireds || self.requireds, + optionals: optionals || self.optionals, + rest: rest || self.rest, + posts: posts || self.posts, + keywords: keywords || self.keywords, + keyword_rest: keyword_rest || self.keyword_rest, + block: block || self.block, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -6859,6 +7778,15 @@ def child_nodes [lparen, contents] end + def copy(lparen: nil, contents: nil, location: nil, comments: nil) + Paren.new( + lparen: lparen || self.lparen, + contents: contents || self.contents, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -6910,6 +7838,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + Period.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -6943,6 +7879,14 @@ def child_nodes [statements] end + def copy(statements: nil, location: nil, comments: nil) + Program.new( + statements: statements || self.statements, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -6988,6 +7932,15 @@ def child_nodes [] end + def copy(beginning: nil, elements: nil, location: nil, comments: nil) + QSymbols.new( + beginning: beginning || self.beginning, + elements: elements || self.elements, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7046,6 +7999,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + QSymbolsBeg.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7082,6 +8042,15 @@ def child_nodes [] end + def copy(beginning: nil, elements: nil, location: nil, comments: nil) + QWords.new( + beginning: beginning || self.beginning, + elements: elements || self.elements, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7140,6 +8109,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + QWordsBeg.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7172,6 +8148,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + RationalLiteral.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7201,6 +8185,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + RBrace.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7226,6 +8217,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + RBracket.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7254,6 +8252,13 @@ def child_nodes [] end + def copy(location: nil, comments: nil) + Redo.new( + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7293,6 +8298,14 @@ def child_nodes parts end + def copy(beginning: nil, parts: nil, location: nil) + RegexpContent.new( + beginning: beginning || self.beginning, + parts: parts || self.parts, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7326,6 +8339,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + RegexpBeg.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7360,6 +8380,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + RegexpEnd.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7401,6 +8428,24 @@ def child_nodes parts end + def copy( + beginning: nil, + ending: nil, + options: nil, + parts: nil, + location: nil, + comments: nil + ) + RegexpLiteral.new( + beginning: beginning || self.beginning, + ending: ending || self.ending, + options: options || self.options, + parts: parts || self.parts, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7511,6 +8556,15 @@ def child_nodes [*exceptions, variable] end + def copy(exceptions: nil, variable: nil, location: nil, comments: nil) + RescueEx.new( + exceptions: exceptions || self.exceptions, + variable: variable || self.variable, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7605,6 +8659,24 @@ def child_nodes [keyword, exception, statements, consequent] end + def copy( + keyword: nil, + exception: nil, + statements: nil, + consequent: nil, + location: nil, + comments: nil + ) + Rescue.new( + keyword: keyword || self.keyword, + exception: exception || self.exception, + statements: statements || self.statements, + consequent: consequent || self.consequent, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7672,6 +8744,15 @@ def child_nodes [statement, value] end + def copy(statement: nil, value: nil, location: nil, comments: nil) + RescueMod.new( + statement: statement || self.statement, + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7728,6 +8809,14 @@ def child_nodes [name] end + def copy(name: nil, location: nil, comments: nil) + RestParam.new( + name: name || self.name, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7761,6 +8850,13 @@ def child_nodes [] end + def copy(location: nil, comments: nil) + Retry.new( + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7797,6 +8893,14 @@ def child_nodes [arguments] end + def copy(arguments: nil, location: nil, comments: nil) + Return.new( + arguments: arguments || self.arguments, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7826,6 +8930,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + RParen.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7865,6 +8976,15 @@ def child_nodes [target, bodystmt] end + def copy(target: nil, bodystmt: nil, location: nil, comments: nil) + SClass.new( + target: target || self.target, + bodystmt: bodystmt || self.bodystmt, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -7969,6 +9089,15 @@ def child_nodes body end + def copy(parser: nil, body: nil, location: nil, comments: nil) + Statements.new( + parser: parser || self.parser, + body: body || self.body, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8088,6 +9217,13 @@ def child_nodes parts end + def copy(parts: nil, location: nil) + StringContent.new( + parts: parts || self.parts, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8126,6 +9262,15 @@ def child_nodes [left, right] end + def copy(left: nil, right: nil, location: nil, comments: nil) + StringConcat.new( + left: left || self.left, + right: right || self.right, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8171,6 +9316,14 @@ def child_nodes [variable] end + def copy(variable: nil, location: nil, comments: nil) + StringDVar.new( + variable: variable || self.variable, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8211,6 +9364,14 @@ def child_nodes [statements] end + def copy(statements: nil, location: nil, comments: nil) + StringEmbExpr.new( + statements: statements || self.statements, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8274,6 +9435,15 @@ def child_nodes parts end + def copy(parts: nil, quote: nil, location: nil, comments: nil) + StringLiteral.new( + parts: parts || self.parts, + quote: quote || self.quote, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8348,6 +9518,14 @@ def child_nodes [arguments] end + def copy(arguments: nil, location: nil, comments: nil) + Super.new( + arguments: arguments || self.arguments, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8401,6 +9579,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + SymBeg.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8431,6 +9616,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + SymbolContent.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8465,6 +9657,14 @@ def child_nodes [value] end + def copy(value: nil, location: nil, comments: nil) + SymbolLiteral.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8506,6 +9706,15 @@ def child_nodes [] end + def copy(beginning: nil, elements: nil, location: nil, comments: nil) + Symbols.new( + beginning: beginning || self.beginning, + elements: elements || self.elements, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8565,6 +9774,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + SymbolsBeg.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8594,6 +9810,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + TLambda.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8624,6 +9847,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + TLamBeg.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8658,6 +9888,14 @@ def child_nodes [constant] end + def copy(constant: nil, location: nil, comments: nil) + TopConstField.new( + constant: constant || self.constant, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8696,6 +9934,14 @@ def child_nodes [constant] end + def copy(constant: nil, location: nil, comments: nil) + TopConstRef.new( + constant: constant || self.constant, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8735,6 +9981,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + TStringBeg.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8775,6 +10028,14 @@ def child_nodes [] end + def copy(value: nil, location: nil, comments: nil) + TStringContent.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8813,6 +10074,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + TStringEnd.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8850,6 +10118,15 @@ def child_nodes [statement] end + def copy(statement: nil, parentheses: nil, location: nil, comments: nil) + Not.new( + statement: statement || self.statement, + parentheses: parentheses || self.parentheses, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8916,6 +10193,15 @@ def child_nodes [statement] end + def copy(operator: nil, statement: nil, location: nil, comments: nil) + Unary.new( + operator: operator || self.operator, + statement: statement || self.statement, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -8982,6 +10268,14 @@ def child_nodes symbols end + def copy(symbols: nil, location: nil, comments: nil) + Undef.new( + symbols: symbols || self.symbols, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -9041,6 +10335,22 @@ def child_nodes [predicate, statements, consequent] end + def copy( + predicate: nil, + statements: nil, + consequent: nil, + location: nil, + comments: nil + ) + Unless.new( + predicate: predicate || self.predicate, + statements: statements || self.statements, + consequent: consequent || self.consequent, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -9165,6 +10475,15 @@ def child_nodes [predicate, statements] end + def copy(predicate: nil, statements: nil, location: nil, comments: nil) + Until.new( + predicate: predicate || self.predicate, + statements: statements || self.statements, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -9212,6 +10531,14 @@ def child_nodes [value] end + def copy(value: nil, location: nil, comments: nil) + VarField.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -9256,6 +10583,14 @@ def child_nodes [value] end + def copy(value: nil, location: nil, comments: nil) + VarRef.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -9320,6 +10655,14 @@ def child_nodes [value] end + def copy(value: nil, location: nil, comments: nil) + PinnedVarRef.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -9360,6 +10703,14 @@ def child_nodes [value] end + def copy(value: nil, location: nil, comments: nil) + VCall.new( + value: value || self.value, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -9399,6 +10750,13 @@ def child_nodes [] end + def copy(location: nil, comments: nil) + VoidStmt.new( + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -9450,6 +10808,22 @@ def child_nodes [arguments, statements, consequent] end + def copy( + arguments: nil, + statements: nil, + consequent: nil, + location: nil, + comments: nil + ) + When.new( + arguments: arguments || self.arguments, + statements: statements || self.statements, + consequent: consequent || self.consequent, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -9544,6 +10918,15 @@ def child_nodes [predicate, statements] end + def copy(predicate: nil, statements: nil, location: nil, comments: nil) + While.new( + predicate: predicate || self.predicate, + statements: statements || self.statements, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -9597,6 +10980,14 @@ def child_nodes parts end + def copy(parts: nil, location: nil, comments: nil) + Word.new( + parts: parts || self.parts, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -9637,6 +11028,15 @@ def child_nodes [] end + def copy(beginning: nil, elements: nil, location: nil, comments: nil) + Words.new( + beginning: beginning || self.beginning, + elements: elements || self.elements, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -9696,6 +11096,13 @@ def child_nodes [] end + def copy(value: nil, location: nil) + WordsBeg.new( + value: value || self.value, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -9725,6 +11132,13 @@ def child_nodes parts end + def copy(parts: nil, location: nil) + XString.new( + parts: parts || self.parts, + location: location || self.location + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -9758,6 +11172,14 @@ def child_nodes parts end + def copy(parts: nil, location: nil, comments: nil) + XStringLiteral.new( + parts: parts || self.parts, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -9796,6 +11218,14 @@ def child_nodes [arguments] end + def copy(arguments: nil, location: nil, comments: nil) + Yield.new( + arguments: arguments || self.arguments, + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) @@ -9847,6 +11277,13 @@ def child_nodes [] end + def copy(location: nil, comments: nil) + ZSuper.new( + location: location || self.location, + comments: comments || self.comments + ) + end + alias deconstruct child_nodes def deconstruct_keys(_keys) From 1ee58b2fe410fe9ebce7bb6ada60a818796bd2f7 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Tue, 8 Nov 2022 11:37:44 -0500 Subject: [PATCH 22/35] Create mutation visitor --- lib/syntax_tree.rb | 1 + lib/syntax_tree/node.rb | 811 ++++++------------ lib/syntax_tree/visitor/mutation_visitor.rb | 887 ++++++++++++++++++++ test/test_helper.rb | 3 + 4 files changed, 1149 insertions(+), 553 deletions(-) create mode 100644 lib/syntax_tree/visitor/mutation_visitor.rb diff --git a/lib/syntax_tree.rb b/lib/syntax_tree.rb index df2f43a9..5808cd15 100644 --- a/lib/syntax_tree.rb +++ b/lib/syntax_tree.rb @@ -16,6 +16,7 @@ require_relative "syntax_tree/visitor/field_visitor" require_relative "syntax_tree/visitor/json_visitor" require_relative "syntax_tree/visitor/match_visitor" +require_relative "syntax_tree/visitor/mutation_visitor" require_relative "syntax_tree/visitor/pretty_print_visitor" require_relative "syntax_tree/visitor/environment" require_relative "syntax_tree/visitor/with_environment" diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index 2882687c..fb4bab21 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -161,12 +161,11 @@ def child_nodes [lbrace, statements] end - def copy(lbrace: nil, statements: nil, location: nil, comments: nil) + def copy(lbrace: nil, statements: nil, location: nil) BEGINBlock.new( lbrace: lbrace || self.lbrace, statements: statements || self.statements, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -222,12 +221,8 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) - CHAR.new( - value: value || self.value, - location: location || self.location, - comments: comments || self.comments - ) + def copy(value: nil, location: nil) + CHAR.new(value: value || self.value, location: location || self.location) end alias deconstruct child_nodes @@ -281,12 +276,11 @@ def child_nodes [lbrace, statements] end - def copy(lbrace: nil, statements: nil, location: nil, comments: nil) + def copy(lbrace: nil, statements: nil, location: nil) ENDBlock.new( lbrace: lbrace || self.lbrace, statements: statements || self.statements, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -345,11 +339,10 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) EndContent.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -442,12 +435,11 @@ def child_nodes [left, right] end - def copy(left: nil, right: nil, location: nil, comments: nil) + def copy(left: nil, right: nil, location: nil) Alias.new( left: left || self.left, right: right || self.right, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -516,12 +508,11 @@ def child_nodes [collection, index] end - def copy(collection: nil, index: nil, location: nil, comments: nil) + def copy(collection: nil, index: nil, location: nil) ARef.new( collection: collection || self.collection, index: index || self.index, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -586,12 +577,11 @@ def child_nodes [collection, index] end - def copy(collection: nil, index: nil, location: nil, comments: nil) + def copy(collection: nil, index: nil, location: nil) ARefField.new( collection: collection || self.collection, index: index || self.index, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -657,11 +647,10 @@ def child_nodes [arguments] end - def copy(arguments: nil, location: nil, comments: nil) + def copy(arguments: nil, location: nil) ArgParen.new( arguments: arguments || self.arguments, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -738,12 +727,8 @@ def child_nodes parts end - def copy(parts: nil, location: nil, comments: nil) - Args.new( - parts: parts || self.parts, - location: location || self.location, - comments: comments || self.comments - ) + def copy(parts: nil, location: nil) + Args.new(parts: parts || self.parts, location: location || self.location) end alias deconstruct child_nodes @@ -782,11 +767,10 @@ def child_nodes [value] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) ArgBlock.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -827,11 +811,10 @@ def child_nodes [value] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) ArgStar.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -881,11 +864,8 @@ def child_nodes [] end - def copy(location: nil, comments: nil) - ArgsForward.new( - location: location || self.location, - comments: comments || self.comments - ) + def copy(location: nil) + ArgsForward.new(location: location || self.location) end alias deconstruct child_nodes @@ -1071,12 +1051,11 @@ def child_nodes [lbracket, contents] end - def copy(lbracket: nil, contents: nil, location: nil, comments: nil) + def copy(lbracket: nil, contents: nil, location: nil) ArrayLiteral.new( lbracket: lbracket || self.lbracket, contents: contents || self.contents, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -1258,16 +1237,14 @@ def copy( requireds: nil, rest: nil, posts: nil, - location: nil, - comments: nil + location: nil ) AryPtn.new( constant: constant || self.constant, requireds: requireds || self.requireds, rest: rest || self.rest, posts: posts || self.posts, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -1352,12 +1329,11 @@ def child_nodes [target, value] end - def copy(target: nil, value: nil, location: nil, comments: nil) + def copy(target: nil, value: nil, location: nil) Assign.new( target: target || self.target, value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -1397,7 +1373,7 @@ def skip_indent? # # { key1: value1, key2: value2 } # - # In the above example, the would be two AssocNew nodes. + # In the above example, the would be two Assoc nodes. class Assoc < Node # [untyped] the key of this pair attr_reader :key @@ -1423,12 +1399,11 @@ def child_nodes [key, value] end - def copy(key: nil, value: nil, location: nil, comments: nil) + def copy(key: nil, value: nil, location: nil) Assoc.new( key: key || self.key, value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -1490,11 +1465,10 @@ def child_nodes [value] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) AssocSplat.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -1536,11 +1510,10 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) Backref.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -1579,11 +1552,10 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) Backtick.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -1699,11 +1671,10 @@ def child_nodes assocs end - def copy(assocs: nil, location: nil, comments: nil) + def copy(assocs: nil, location: nil) BareAssocHash.new( assocs: assocs || self.assocs, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -1749,11 +1720,10 @@ def child_nodes [bodystmt] end - def copy(bodystmt: nil, location: nil, comments: nil) + def copy(bodystmt: nil, location: nil) Begin.new( bodystmt: bodystmt || self.bodystmt, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -1805,11 +1775,10 @@ def child_nodes [statement] end - def copy(statement: nil, location: nil, comments: nil) + def copy(statement: nil, location: nil) PinnedBegin.new( statement: statement || self.statement, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -1887,13 +1856,12 @@ def child_nodes [left, right] end - def copy(left: nil, operator: nil, right: nil, location: nil, comments: nil) + def copy(left: nil, operator: nil, right: nil, location: nil) Binary.new( left: left || self.left, operator: operator || self.operator, right: right || self.right, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -1964,12 +1932,11 @@ def child_nodes [params, *locals] end - def copy(params: nil, locals: nil, location: nil, comments: nil) + def copy(params: nil, locals: nil, location: nil) BlockVar.new( params: params || self.params, locals: locals || self.locals, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -2030,12 +1997,8 @@ def child_nodes [name] end - def copy(name: nil, location: nil, comments: nil) - BlockArg.new( - name: name || self.name, - location: location || self.location, - comments: comments || self.comments - ) + def copy(name: nil, location: nil) + BlockArg.new(name: name || self.name, location: location || self.location) end alias deconstruct child_nodes @@ -2135,18 +2098,18 @@ def child_nodes def copy( statements: nil, rescue_clause: nil, + else_keyword: nil, else_clause: nil, ensure_clause: nil, - location: nil, - comments: nil + location: nil ) BodyStmt.new( statements: statements || self.statements, rescue_clause: rescue_clause || self.rescue_clause, + else_keyword: else_keyword || self.else_keyword, else_clause: else_clause || self.else_clause, ensure_clause: ensure_clause || self.ensure_clause, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -2156,6 +2119,7 @@ def deconstruct_keys(_keys) { statements: statements, rescue_clause: rescue_clause, + else_keyword: else_keyword, else_clause: else_clause, ensure_clause: ensure_clause, location: location, @@ -2414,11 +2378,10 @@ def child_nodes [arguments] end - def copy(arguments: nil, location: nil, comments: nil) + def copy(arguments: nil, location: nil) Break.new( arguments: arguments || self.arguments, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -2743,16 +2706,14 @@ def copy( operator: nil, message: nil, arguments: nil, - location: nil, - comments: nil + location: nil ) Call.new( receiver: receiver || self.receiver, operator: operator || self.operator, message: message || self.message, arguments: arguments || self.arguments, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -2881,19 +2842,12 @@ def child_nodes [keyword, value, consequent] end - def copy( - keyword: nil, - value: nil, - consequent: nil, - location: nil, - comments: nil - ) + def copy(keyword: nil, value: nil, consequent: nil, location: nil) Case.new( keyword: keyword || self.keyword, value: value || self.value, consequent: consequent || self.consequent, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -2962,19 +2916,12 @@ def child_nodes [value, operator, pattern] end - def copy( - value: nil, - operator: nil, - pattern: nil, - location: nil, - comments: nil - ) + def copy(value: nil, operator: nil, pattern: nil, location: nil) RAssign.new( value: value || self.value, operator: operator || self.operator, pattern: pattern || self.pattern, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -3074,19 +3021,12 @@ def child_nodes [constant, superclass, bodystmt] end - def copy( - constant: nil, - superclass: nil, - bodystmt: nil, - location: nil, - comments: nil - ) + def copy(constant: nil, superclass: nil, bodystmt: nil, location: nil) ClassDeclaration.new( constant: constant || self.constant, superclass: superclass || self.superclass, bodystmt: bodystmt || self.bodystmt, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -3203,19 +3143,12 @@ def child_nodes [message, arguments, block] end - def copy( - message: nil, - arguments: nil, - block: nil, - location: nil, - comments: nil - ) + def copy(message: nil, arguments: nil, block: nil, location: nil) Command.new( message: message || self.message, arguments: arguments || self.arguments, block: block || self.block, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -3331,8 +3264,7 @@ def copy( message: nil, arguments: nil, block: nil, - location: nil, - comments: nil + location: nil ) CommandCall.new( receiver: receiver || self.receiver, @@ -3340,8 +3272,7 @@ def copy( message: message || self.message, arguments: arguments || self.arguments, block: block || self.block, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -3531,12 +3462,8 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) - Const.new( - value: value || self.value, - location: location || self.location, - comments: comments || self.comments - ) + def copy(value: nil, location: nil) + Const.new(value: value || self.value, location: location || self.location) end alias deconstruct child_nodes @@ -3581,12 +3508,11 @@ def child_nodes [parent, constant] end - def copy(parent: nil, constant: nil, location: nil, comments: nil) + def copy(parent: nil, constant: nil, location: nil) ConstPathField.new( parent: parent || self.parent, constant: constant || self.constant, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -3637,12 +3563,11 @@ def child_nodes [parent, constant] end - def copy(parent: nil, constant: nil, location: nil, comments: nil) + def copy(parent: nil, constant: nil, location: nil) ConstPathRef.new( parent: parent || self.parent, constant: constant || self.constant, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -3691,11 +3616,10 @@ def child_nodes [constant] end - def copy(constant: nil, location: nil, comments: nil) + def copy(constant: nil, location: nil) ConstRef.new( constant: constant || self.constant, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -3735,12 +3659,8 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) - CVar.new( - value: value || self.value, - location: location || self.location, - comments: comments || self.comments - ) + def copy(value: nil, location: nil) + CVar.new(value: value || self.value, location: location || self.location) end alias deconstruct child_nodes @@ -3802,8 +3722,7 @@ def copy( name: nil, params: nil, bodystmt: nil, - location: nil, - comments: nil + location: nil ) Def.new( target: target || self.target, @@ -3811,8 +3730,7 @@ def copy( name: name || self.name, params: params || self.params, bodystmt: bodystmt || self.bodystmt, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -3906,11 +3824,10 @@ def child_nodes [value] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) Defined.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -3992,19 +3909,12 @@ def child_nodes [opening, block_var, bodystmt] end - def copy( - opening: nil, - block_var: nil, - bodystmt: nil, - location: nil, - comments: nil - ) + def copy(opening: nil, block_var: nil, bodystmt: nil, location: nil) Block.new( opening: opening || self.opening, block_var: block_var || self.block_var, bodystmt: bodystmt || self.bodystmt, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -4187,13 +4097,12 @@ def child_nodes [left, right] end - def copy(left: nil, operator: nil, right: nil, location: nil, comments: nil) + def copy(left: nil, operator: nil, right: nil, location: nil) RangeLiteral.new( left: left || self.left, operator: operator || self.operator, right: right || self.right, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -4299,12 +4208,11 @@ def child_nodes parts end - def copy(parts: nil, quote: nil, location: nil, comments: nil) + def copy(parts: nil, quote: nil, location: nil) DynaSymbol.new( parts: parts || self.parts, quote: quote || self.quote, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -4419,12 +4327,11 @@ def child_nodes [keyword, statements] end - def copy(keyword: nil, statements: nil, location: nil, comments: nil) + def copy(keyword: nil, statements: nil, location: nil) Else.new( keyword: keyword || self.keyword, statements: statements || self.statements, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -4494,19 +4401,12 @@ def child_nodes [predicate, statements, consequent] end - def copy( - predicate: nil, - statements: nil, - consequent: nil, - location: nil, - comments: nil - ) + def copy(predicate: nil, statements: nil, consequent: nil, location: nil) Elsif.new( predicate: predicate || self.predicate, statements: statements || self.statements, consequent: consequent || self.consequent, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -4746,12 +4646,11 @@ def child_nodes [keyword, statements] end - def copy(keyword: nil, statements: nil, location: nil, comments: nil) + def copy(keyword: nil, statements: nil, location: nil) Ensure.new( keyword: keyword || self.keyword, statements: statements || self.statements, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -4809,11 +4708,10 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) ExcessedComma.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -4862,19 +4760,12 @@ def child_nodes [parent, (operator if operator != :"::"), name] end - def copy( - parent: nil, - operator: nil, - name: nil, - location: nil, - comments: nil - ) + def copy(parent: nil, operator: nil, name: nil, location: nil) Field.new( parent: parent || self.parent, operator: operator || self.operator, name: name || self.name, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -4924,11 +4815,10 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) FloatLiteral.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -4984,21 +4874,13 @@ def child_nodes [constant, left, *values, right] end - def copy( - constant: nil, - left: nil, - values: nil, - right: nil, - location: nil, - comments: nil - ) + def copy(constant: nil, left: nil, values: nil, right: nil, location: nil) FndPtn.new( constant: constant || self.constant, left: left || self.left, values: values || self.values, right: right || self.right, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -5076,19 +4958,12 @@ def child_nodes [index, collection, statements] end - def copy( - index: nil, - collection: nil, - statements: nil, - location: nil, - comments: nil - ) + def copy(index: nil, collection: nil, statements: nil, location: nil) For.new( index: index || self.index, collection: collection || self.collection, statements: statements || self.statements, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -5149,12 +5024,8 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) - GVar.new( - value: value || self.value, - location: location || self.location, - comments: comments || self.comments - ) + def copy(value: nil, location: nil) + GVar.new(value: value || self.value, location: location || self.location) end alias deconstruct child_nodes @@ -5202,7 +5073,7 @@ def format(q) # [LBrace] the left brace that opens this hash attr_reader :lbrace - # [Array[ AssocNew | AssocSplat ]] the optional contents of the hash + # [Array[ Assoc | AssocSplat ]] the optional contents of the hash attr_reader :assocs # [Array[ Comment | EmbDoc ]] the comments attached to this node @@ -5223,12 +5094,11 @@ def child_nodes [lbrace] + assocs end - def copy(lbrace: nil, assocs: nil, location: nil, comments: nil) + def copy(lbrace: nil, assocs: nil, location: nil) HashLiteral.new( lbrace: lbrace || self.lbrace, assocs: assocs || self.assocs, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -5328,19 +5198,12 @@ def child_nodes [beginning, *parts, ending] end - def copy( - beginning: nil, - location: nil, - ending: nil, - parts: nil, - comments: nil - ) + def copy(beginning: nil, location: nil, ending: nil, parts: nil) Heredoc.new( beginning: beginning || self.beginning, location: location || self.location, ending: ending || self.ending, - parts: parts || self.parts, - comments: comments || self.comments + parts: parts || self.parts ) end @@ -5424,11 +5287,10 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) HeredocBeg.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -5471,11 +5333,10 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) HeredocEnd.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -5573,19 +5434,12 @@ def child_nodes [constant, *keywords.flatten(1), keyword_rest] end - def copy( - constant: nil, - keywords: nil, - keyword_rest: nil, - location: nil, - comments: nil - ) + def copy(constant: nil, keywords: nil, keyword_rest: nil, location: nil) HshPtn.new( constant: constant || self.constant, keywords: keywords || self.keywords, keyword_rest: keyword_rest || self.keyword_rest, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -5697,12 +5551,8 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) - Ident.new( - value: value || self.value, - location: location || self.location, - comments: comments || self.comments - ) + def copy(value: nil, location: nil) + Ident.new(value: value || self.value, location: location || self.location) end alias deconstruct child_nodes @@ -5965,7 +5815,7 @@ class If < Node # [Statements] the expressions to be executed attr_reader :statements - # [nil, Elsif, Else] the next clause in the chain + # [nil | Elsif | Else] the next clause in the chain attr_reader :consequent # [Array[ Comment | EmbDoc ]] the comments attached to this node @@ -5993,19 +5843,12 @@ def child_nodes [predicate, statements, consequent] end - def copy( - predicate: nil, - statements: nil, - consequent: nil, - location: nil, - comments: nil - ) + def copy(predicate: nil, statements: nil, consequent: nil, location: nil) If.new( predicate: predicate || self.predicate, statements: statements || self.statements, consequent: consequent || self.consequent, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -6064,19 +5907,12 @@ def child_nodes [predicate, truthy, falsy] end - def copy( - predicate: nil, - truthy: nil, - falsy: nil, - location: nil, - comments: nil - ) + def copy(predicate: nil, truthy: nil, falsy: nil, location: nil) IfOp.new( predicate: predicate || self.predicate, truthy: truthy || self.truthy, falsy: falsy || self.falsy, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -6173,11 +6009,10 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) Imaginary.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -6228,19 +6063,12 @@ def child_nodes [pattern, statements, consequent] end - def copy( - pattern: nil, - statements: nil, - consequent: nil, - location: nil, - comments: nil - ) + def copy(pattern: nil, statements: nil, consequent: nil, location: nil) In.new( pattern: pattern || self.pattern, statements: statements || self.statements, consequent: consequent || self.consequent, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -6303,12 +6131,8 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) - Int.new( - value: value || self.value, - location: location || self.location, - comments: comments || self.comments - ) + def copy(value: nil, location: nil) + Int.new(value: value || self.value, location: location || self.location) end alias deconstruct child_nodes @@ -6355,12 +6179,8 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) - IVar.new( - value: value || self.value, - location: location || self.location, - comments: comments || self.comments - ) + def copy(value: nil, location: nil) + IVar.new(value: value || self.value, location: location || self.location) end alias deconstruct child_nodes @@ -6412,12 +6232,8 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) - Kw.new( - value: value || self.value, - location: location || self.location, - comments: comments || self.comments - ) + def copy(value: nil, location: nil) + Kw.new(value: value || self.value, location: location || self.location) end alias deconstruct child_nodes @@ -6457,11 +6273,10 @@ def child_nodes [name] end - def copy(name: nil, location: nil, comments: nil) + def copy(name: nil, location: nil) KwRestParam.new( name: name || self.name, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -6511,12 +6326,8 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) - Label.new( - value: value || self.value, - location: location || self.location, - comments: comments || self.comments - ) + def copy(value: nil, location: nil) + Label.new(value: value || self.value, location: location || self.location) end alias deconstruct child_nodes @@ -6597,12 +6408,11 @@ def child_nodes [params, statements] end - def copy(params: nil, statements: nil, location: nil, comments: nil) + def copy(params: nil, statements: nil, location: nil) Lambda.new( params: params || self.params, statements: statements || self.statements, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -6714,12 +6524,11 @@ def child_nodes [params, *locals] end - def copy(params: nil, locals: nil, location: nil, comments: nil) + def copy(params: nil, locals: nil, location: nil) LambdaVar.new( params: params || self.params, locals: locals || self.locals, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -6765,11 +6574,10 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) LBrace.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -6806,11 +6614,10 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) LBracket.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -6847,11 +6654,10 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) LParen.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -6905,12 +6711,11 @@ def child_nodes [target, value] end - def copy(target: nil, value: nil, location: nil, comments: nil) + def copy(target: nil, value: nil, location: nil) MAssign.new( target: target || self.target, value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -6961,12 +6766,11 @@ def child_nodes [call, block] end - def copy(call: nil, block: nil, location: nil, comments: nil) + def copy(call: nil, block: nil, location: nil) MethodAddBlock.new( call: call || self.call, block: block || self.block, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -7031,12 +6835,11 @@ def child_nodes parts end - def copy(parts: nil, location: nil, comma: nil, comments: nil) + def copy(parts: nil, location: nil, comma: nil) MLHS.new( parts: parts || self.parts, location: location || self.location, - comma: comma || self.comma, - comments: comments || self.comments + comma: comma || self.comma ) end @@ -7084,11 +6887,10 @@ def child_nodes [contents] end - def copy(contents: nil, location: nil, comments: nil) + def copy(contents: nil, location: nil) MLHSParen.new( contents: contents || self.contents, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -7150,12 +6952,11 @@ def child_nodes [constant, bodystmt] end - def copy(constant: nil, bodystmt: nil, location: nil, comments: nil) + def copy(constant: nil, bodystmt: nil, location: nil) ModuleDeclaration.new( constant: constant || self.constant, bodystmt: bodystmt || self.bodystmt, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -7228,12 +7029,8 @@ def child_nodes parts end - def copy(parts: nil, location: nil, comments: nil) - MRHS.new( - parts: parts || self.parts, - location: location || self.location, - comments: comments || self.comments - ) + def copy(parts: nil, location: nil) + MRHS.new(parts: parts || self.parts, location: location || self.location) end alias deconstruct child_nodes @@ -7285,11 +7082,10 @@ def child_nodes [arguments] end - def copy(arguments: nil, location: nil, comments: nil) + def copy(arguments: nil, location: nil) Next.new( arguments: arguments || self.arguments, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -7334,12 +7130,8 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) - Op.new( - value: value || self.value, - location: location || self.location, - comments: comments || self.comments - ) + def copy(value: nil, location: nil) + Op.new(value: value || self.value, location: location || self.location) end alias deconstruct child_nodes @@ -7388,19 +7180,12 @@ def child_nodes [target, operator, value] end - def copy( - target: nil, - operator: nil, - value: nil, - location: nil, - comments: nil - ) + def copy(target: nil, operator: nil, value: nil, location: nil) OpAssign.new( target: target || self.target, operator: operator || self.operator, value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -7670,8 +7455,7 @@ def copy( posts: nil, keywords: nil, keyword_rest: nil, - block: nil, - comments: nil + block: nil ) Params.new( location: location || self.location, @@ -7681,8 +7465,7 @@ def copy( posts: posts || self.posts, keywords: keywords || self.keywords, keyword_rest: keyword_rest || self.keyword_rest, - block: block || self.block, - comments: comments || self.comments + block: block || self.block ) end @@ -7778,12 +7561,11 @@ def child_nodes [lparen, contents] end - def copy(lparen: nil, contents: nil, location: nil, comments: nil) + def copy(lparen: nil, contents: nil, location: nil) Paren.new( lparen: lparen || self.lparen, contents: contents || self.contents, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -7838,11 +7620,10 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) Period.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -7879,11 +7660,10 @@ def child_nodes [statements] end - def copy(statements: nil, location: nil, comments: nil) + def copy(statements: nil, location: nil) Program.new( statements: statements || self.statements, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -7932,12 +7712,11 @@ def child_nodes [] end - def copy(beginning: nil, elements: nil, location: nil, comments: nil) + def copy(beginning: nil, elements: nil, location: nil) QSymbols.new( beginning: beginning || self.beginning, elements: elements || self.elements, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -8042,12 +7821,11 @@ def child_nodes [] end - def copy(beginning: nil, elements: nil, location: nil, comments: nil) + def copy(beginning: nil, elements: nil, location: nil) QWords.new( beginning: beginning || self.beginning, elements: elements || self.elements, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -8148,11 +7926,10 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) RationalLiteral.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -8252,11 +8029,8 @@ def child_nodes [] end - def copy(location: nil, comments: nil) - Redo.new( - location: location || self.location, - comments: comments || self.comments - ) + def copy(location: nil) + Redo.new(location: location || self.location) end alias deconstruct child_nodes @@ -8428,21 +8202,12 @@ def child_nodes parts end - def copy( - beginning: nil, - ending: nil, - options: nil, - parts: nil, - location: nil, - comments: nil - ) + def copy(beginning: nil, ending: nil, parts: nil, location: nil) RegexpLiteral.new( beginning: beginning || self.beginning, ending: ending || self.ending, - options: options || self.options, parts: parts || self.parts, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -8556,12 +8321,11 @@ def child_nodes [*exceptions, variable] end - def copy(exceptions: nil, variable: nil, location: nil, comments: nil) + def copy(exceptions: nil, variable: nil, location: nil) RescueEx.new( exceptions: exceptions || self.exceptions, variable: variable || self.variable, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -8664,16 +8428,14 @@ def copy( exception: nil, statements: nil, consequent: nil, - location: nil, - comments: nil + location: nil ) Rescue.new( keyword: keyword || self.keyword, exception: exception || self.exception, statements: statements || self.statements, consequent: consequent || self.consequent, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -8744,12 +8506,11 @@ def child_nodes [statement, value] end - def copy(statement: nil, value: nil, location: nil, comments: nil) + def copy(statement: nil, value: nil, location: nil) RescueMod.new( statement: statement || self.statement, value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -8809,11 +8570,10 @@ def child_nodes [name] end - def copy(name: nil, location: nil, comments: nil) + def copy(name: nil, location: nil) RestParam.new( name: name || self.name, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -8850,11 +8610,8 @@ def child_nodes [] end - def copy(location: nil, comments: nil) - Retry.new( - location: location || self.location, - comments: comments || self.comments - ) + def copy(location: nil) + Retry.new(location: location || self.location) end alias deconstruct child_nodes @@ -8893,11 +8650,10 @@ def child_nodes [arguments] end - def copy(arguments: nil, location: nil, comments: nil) + def copy(arguments: nil, location: nil) Return.new( arguments: arguments || self.arguments, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -8976,12 +8732,11 @@ def child_nodes [target, bodystmt] end - def copy(target: nil, bodystmt: nil, location: nil, comments: nil) + def copy(target: nil, bodystmt: nil, location: nil) SClass.new( target: target || self.target, bodystmt: bodystmt || self.bodystmt, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -9089,12 +8844,11 @@ def child_nodes body end - def copy(parser: nil, body: nil, location: nil, comments: nil) + def copy(body: nil, location: nil) Statements.new( - parser: parser || self.parser, + parser, body: body || self.body, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -9262,12 +9016,11 @@ def child_nodes [left, right] end - def copy(left: nil, right: nil, location: nil, comments: nil) + def copy(left: nil, right: nil, location: nil) StringConcat.new( left: left || self.left, right: right || self.right, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -9316,11 +9069,10 @@ def child_nodes [variable] end - def copy(variable: nil, location: nil, comments: nil) + def copy(variable: nil, location: nil) StringDVar.new( variable: variable || self.variable, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -9364,11 +9116,10 @@ def child_nodes [statements] end - def copy(statements: nil, location: nil, comments: nil) + def copy(statements: nil, location: nil) StringEmbExpr.new( statements: statements || self.statements, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -9435,12 +9186,11 @@ def child_nodes parts end - def copy(parts: nil, quote: nil, location: nil, comments: nil) + def copy(parts: nil, quote: nil, location: nil) StringLiteral.new( parts: parts || self.parts, quote: quote || self.quote, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -9518,11 +9268,10 @@ def child_nodes [arguments] end - def copy(arguments: nil, location: nil, comments: nil) + def copy(arguments: nil, location: nil) Super.new( arguments: arguments || self.arguments, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -9657,11 +9406,10 @@ def child_nodes [value] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) SymbolLiteral.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -9706,12 +9454,11 @@ def child_nodes [] end - def copy(beginning: nil, elements: nil, location: nil, comments: nil) + def copy(beginning: nil, elements: nil, location: nil) Symbols.new( beginning: beginning || self.beginning, elements: elements || self.elements, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -9888,11 +9635,10 @@ def child_nodes [constant] end - def copy(constant: nil, location: nil, comments: nil) + def copy(constant: nil, location: nil) TopConstField.new( constant: constant || self.constant, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -9934,11 +9680,10 @@ def child_nodes [constant] end - def copy(constant: nil, location: nil, comments: nil) + def copy(constant: nil, location: nil) TopConstRef.new( constant: constant || self.constant, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -10028,11 +9773,10 @@ def child_nodes [] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) TStringContent.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -10118,12 +9862,11 @@ def child_nodes [statement] end - def copy(statement: nil, parentheses: nil, location: nil, comments: nil) + def copy(statement: nil, parentheses: nil, location: nil) Not.new( statement: statement || self.statement, parentheses: parentheses || self.parentheses, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -10193,12 +9936,11 @@ def child_nodes [statement] end - def copy(operator: nil, statement: nil, location: nil, comments: nil) + def copy(operator: nil, statement: nil, location: nil) Unary.new( operator: operator || self.operator, statement: statement || self.statement, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -10268,11 +10010,10 @@ def child_nodes symbols end - def copy(symbols: nil, location: nil, comments: nil) + def copy(symbols: nil, location: nil) Undef.new( symbols: symbols || self.symbols, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -10307,7 +10048,7 @@ class Unless < Node # [Statements] the expressions to be executed attr_reader :statements - # [nil, Elsif, Else] the next clause in the chain + # [nil | Elsif | Else] the next clause in the chain attr_reader :consequent # [Array[ Comment | EmbDoc ]] the comments attached to this node @@ -10335,19 +10076,12 @@ def child_nodes [predicate, statements, consequent] end - def copy( - predicate: nil, - statements: nil, - consequent: nil, - location: nil, - comments: nil - ) + def copy(predicate: nil, statements: nil, consequent: nil, location: nil) Unless.new( predicate: predicate || self.predicate, statements: statements || self.statements, consequent: consequent || self.consequent, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -10475,12 +10209,11 @@ def child_nodes [predicate, statements] end - def copy(predicate: nil, statements: nil, location: nil, comments: nil) + def copy(predicate: nil, statements: nil, location: nil) Until.new( predicate: predicate || self.predicate, statements: statements || self.statements, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -10531,11 +10264,10 @@ def child_nodes [value] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) VarField.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -10583,11 +10315,10 @@ def child_nodes [value] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) VarRef.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -10655,11 +10386,10 @@ def child_nodes [value] end - def copy(value: nil, location: nil, comments: nil) + def copy(value: nil, location: nil) PinnedVarRef.new( value: value || self.value, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -10703,12 +10433,8 @@ def child_nodes [value] end - def copy(value: nil, location: nil, comments: nil) - VCall.new( - value: value || self.value, - location: location || self.location, - comments: comments || self.comments - ) + def copy(value: nil, location: nil) + VCall.new(value: value || self.value, location: location || self.location) end alias deconstruct child_nodes @@ -10750,11 +10476,8 @@ def child_nodes [] end - def copy(location: nil, comments: nil) - VoidStmt.new( - location: location || self.location, - comments: comments || self.comments - ) + def copy(location: nil) + VoidStmt.new(location: location || self.location) end alias deconstruct child_nodes @@ -10808,19 +10531,12 @@ def child_nodes [arguments, statements, consequent] end - def copy( - arguments: nil, - statements: nil, - consequent: nil, - location: nil, - comments: nil - ) + def copy(arguments: nil, statements: nil, consequent: nil, location: nil) When.new( arguments: arguments || self.arguments, statements: statements || self.statements, consequent: consequent || self.consequent, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -10918,12 +10634,11 @@ def child_nodes [predicate, statements] end - def copy(predicate: nil, statements: nil, location: nil, comments: nil) + def copy(predicate: nil, statements: nil, location: nil) While.new( predicate: predicate || self.predicate, statements: statements || self.statements, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -10980,12 +10695,8 @@ def child_nodes parts end - def copy(parts: nil, location: nil, comments: nil) - Word.new( - parts: parts || self.parts, - location: location || self.location, - comments: comments || self.comments - ) + def copy(parts: nil, location: nil) + Word.new(parts: parts || self.parts, location: location || self.location) end alias deconstruct child_nodes @@ -11028,12 +10739,11 @@ def child_nodes [] end - def copy(beginning: nil, elements: nil, location: nil, comments: nil) + def copy(beginning: nil, elements: nil, location: nil) Words.new( beginning: beginning || self.beginning, elements: elements || self.elements, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -11172,11 +10882,10 @@ def child_nodes parts end - def copy(parts: nil, location: nil, comments: nil) + def copy(parts: nil, location: nil) XStringLiteral.new( parts: parts || self.parts, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -11218,11 +10927,10 @@ def child_nodes [arguments] end - def copy(arguments: nil, location: nil, comments: nil) + def copy(arguments: nil, location: nil) Yield.new( arguments: arguments || self.arguments, - location: location || self.location, - comments: comments || self.comments + location: location || self.location ) end @@ -11277,11 +10985,8 @@ def child_nodes [] end - def copy(location: nil, comments: nil) - ZSuper.new( - location: location || self.location, - comments: comments || self.comments - ) + def copy(location: nil) + ZSuper.new(location: location || self.location) end alias deconstruct child_nodes diff --git a/lib/syntax_tree/visitor/mutation_visitor.rb b/lib/syntax_tree/visitor/mutation_visitor.rb new file mode 100644 index 00000000..c2bdc7fc --- /dev/null +++ b/lib/syntax_tree/visitor/mutation_visitor.rb @@ -0,0 +1,887 @@ +# frozen_string_literal: true + +module SyntaxTree + class Visitor + # This visitor walks through the tree and copies each node as it is being + # visited. This is useful for mutating the tree before it is formatted. + class MutationVisitor < Visitor + # Visit a BEGINBlock node. + def visit_BEGIN(node) + node.copy( + lbrace: visit(node.lbrace), + statements: visit(node.statements) + ) + end + + # Visit a CHAR node. + def visit_CHAR(node) + node.copy + end + + # Visit a ENDBlock node. + def visit_END(node) + node.copy( + lbrace: visit(node.lbrace), + statements: visit(node.statements) + ) + end + + # Visit a EndContent node. + def visit___end__(node) + node.copy + end + + # Visit a Alias node. + def visit_alias(node) + node.copy(left: visit(node.left), right: visit(node.right)) + end + + # Visit a ARef node. + def visit_aref(node) + node.copy(index: visit(node.index)) + end + + # Visit a ARefField node. + def visit_aref_field(node) + node.copy(index: visit(node.index)) + end + + # Visit a ArgParen node. + def visit_arg_paren(node) + node.copy(arguments: visit(node.arguments)) + end + + # Visit a Args node. + def visit_args(node) + node.copy(parts: visit_all(node.parts)) + end + + # Visit a ArgBlock node. + def visit_arg_block(node) + node.copy(value: visit(node.value)) + end + + # Visit a ArgStar node. + def visit_arg_star(node) + node.copy(value: visit(node.value)) + end + + # Visit a ArgsForward node. + def visit_args_forward(node) + node.copy + end + + # Visit a ArrayLiteral node. + def visit_array(node) + node.copy( + lbracket: visit(node.lbracket), + contents: visit(node.contents) + ) + end + + # Visit a AryPtn node. + def visit_aryptn(node) + node.copy( + constant: visit(node.constant), + requireds: visit_all(node.requireds), + rest: visit(node.rest), + posts: visit_all(node.posts) + ) + end + + # Visit a Assign node. + def visit_assign(node) + node.copy(target: visit(node.target)) + end + + # Visit a Assoc node. + def visit_assoc(node) + node.copy + end + + # Visit a AssocSplat node. + def visit_assoc_splat(node) + node.copy + end + + # Visit a Backref node. + def visit_backref(node) + node.copy + end + + # Visit a Backtick node. + def visit_backtick(node) + node.copy + end + + # Visit a BareAssocHash node. + def visit_bare_assoc_hash(node) + node.copy(assocs: visit_all(node.assocs)) + end + + # Visit a Begin node. + def visit_begin(node) + node.copy(bodystmt: visit(node.bodystmt)) + end + + # Visit a PinnedBegin node. + def visit_pinned_begin(node) + node.copy + end + + # Visit a Binary node. + def visit_binary(node) + node.copy + end + + # Visit a BlockVar node. + def visit_block_var(node) + node.copy(params: visit(node.params), locals: visit_all(node.locals)) + end + + # Visit a BlockArg node. + def visit_blockarg(node) + node.copy(name: visit(node.name)) + end + + # Visit a BodyStmt node. + def visit_bodystmt(node) + node.copy( + statements: visit(node.statements), + rescue_clause: visit(node.rescue_clause), + else_clause: visit(node.else_clause), + ensure_clause: visit(node.ensure_clause) + ) + end + + # Visit a Break node. + def visit_break(node) + node.copy(arguments: visit(node.arguments)) + end + + # Visit a Call node. + def visit_call(node) + node.copy( + receiver: visit(node.receiver), + operator: node.operator == :"::" ? :"::" : visit(node.operator), + message: node.message == :call ? :call : visit(node.message), + arguments: visit(node.arguments) + ) + end + + # Visit a Case node. + def visit_case(node) + node.copy( + keyword: visit(node.keyword), + value: visit(node.value), + consequent: visit(node.consequent) + ) + end + + # Visit a RAssign node. + def visit_rassign(node) + node.copy(operator: visit(node.operator)) + end + + # Visit a ClassDeclaration node. + def visit_class(node) + node.copy( + constant: visit(node.constant), + superclass: visit(node.superclass), + bodystmt: visit(node.bodystmt) + ) + end + + # Visit a Comma node. + def visit_comma(node) + node.copy + end + + # Visit a Command node. + def visit_command(node) + node.copy( + message: visit(node.message), + arguments: visit(node.arguments), + block: visit(node.block) + ) + end + + # Visit a CommandCall node. + def visit_command_call(node) + node.copy( + operator: node.operator == :"::" ? :"::" : visit(node.operator), + message: visit(node.message), + arguments: visit(node.arguments), + block: visit(node.block) + ) + end + + # Visit a Comment node. + def visit_comment(node) + node.copy + end + + # Visit a Const node. + def visit_const(node) + node.copy + end + + # Visit a ConstPathField node. + def visit_const_path_field(node) + node.copy(constant: visit(node.constant)) + end + + # Visit a ConstPathRef node. + def visit_const_path_ref(node) + node.copy(constant: visit(node.constant)) + end + + # Visit a ConstRef node. + def visit_const_ref(node) + node.copy(constant: visit(node.constant)) + end + + # Visit a CVar node. + def visit_cvar(node) + node.copy + end + + # Visit a Def node. + def visit_def(node) + node.copy( + target: visit(node.target), + operator: visit(node.operator), + name: visit(node.name), + params: visit(node.params), + bodystmt: visit(node.bodystmt) + ) + end + + # Visit a Defined node. + def visit_defined(node) + node.copy + end + + # Visit a Block node. + def visit_block(node) + node.copy( + opening: visit(node.opening), + block_var: visit(node.block_var), + bodystmt: visit(node.bodystmt) + ) + end + + # Visit a RangeLiteral node. + def visit_range_literal(node) + node.copy( + left: visit(node.left), + operator: visit(node.operator), + right: visit(node.right) + ) + end + + # Visit a DynaSymbol node. + def visit_dyna_symbol(node) + node.copy(parts: visit_all(node.parts)) + end + + # Visit a Else node. + def visit_else(node) + node.copy( + keyword: visit(node.keyword), + statements: visit(node.statements) + ) + end + + # Visit a Elsif node. + def visit_elsif(node) + node.copy( + statements: visit(node.statements), + consequent: visit(node.consequent) + ) + end + + # Visit a EmbDoc node. + def visit_embdoc(node) + node.copy + end + + # Visit a EmbExprBeg node. + def visit_embexpr_beg(node) + node.copy + end + + # Visit a EmbExprEnd node. + def visit_embexpr_end(node) + node.copy + end + + # Visit a EmbVar node. + def visit_embvar(node) + node.copy + end + + # Visit a Ensure node. + def visit_ensure(node) + node.copy( + keyword: visit(node.keyword), + statements: visit(node.statements) + ) + end + + # Visit a ExcessedComma node. + def visit_excessed_comma(node) + node.copy + end + + # Visit a Field node. + def visit_field(node) + node.copy( + operator: node.operator == :"::" ? :"::" : visit(node.operator), + name: visit(node.name) + ) + end + + # Visit a FloatLiteral node. + def visit_float(node) + node.copy + end + + # Visit a FndPtn node. + def visit_fndptn(node) + node.copy( + constant: visit(node.constant), + left: visit(node.left), + values: visit_all(node.values), + right: visit(node.right) + ) + end + + # Visit a For node. + def visit_for(node) + node.copy(index: visit(node.index), statements: visit(node.statements)) + end + + # Visit a GVar node. + def visit_gvar(node) + node.copy + end + + # Visit a HashLiteral node. + def visit_hash(node) + node.copy(lbrace: visit(node.lbrace), assocs: visit_all(node.assocs)) + end + + # Visit a Heredoc node. + def visit_heredoc(node) + node.copy( + beginning: visit(node.beginning), + ending: visit(node.ending), + parts: visit_all(node.parts) + ) + end + + # Visit a HeredocBeg node. + def visit_heredoc_beg(node) + node.copy + end + + # Visit a HeredocEnd node. + def visit_heredoc_end(node) + node.copy + end + + # Visit a HshPtn node. + def visit_hshptn(node) + node.copy( + constant: visit(node.constant), + keywords: + node.keywords.map { |label, value| [visit(label), visit(value)] }, + keyword_rest: visit(node.keyword_rest) + ) + end + + # Visit a Ident node. + def visit_ident(node) + node.copy + end + + # Visit a If node. + def visit_if(node) + node.copy( + statements: visit(node.statements), + consequent: visit(node.consequent) + ) + end + + # Visit a IfOp node. + def visit_if_op(node) + node.copy + end + + # Visit a Imaginary node. + def visit_imaginary(node) + node.copy + end + + # Visit a In node. + def visit_in(node) + node.copy( + statements: visit(node.statements), + consequent: visit(node.consequent) + ) + end + + # Visit a Int node. + def visit_int(node) + node.copy + end + + # Visit a IVar node. + def visit_ivar(node) + node.copy + end + + # Visit a Kw node. + def visit_kw(node) + node.copy + end + + # Visit a KwRestParam node. + def visit_kwrest_param(node) + node.copy(name: visit(node.name)) + end + + # Visit a Label node. + def visit_label(node) + node.copy + end + + # Visit a LabelEnd node. + def visit_label_end(node) + node.copy + end + + # Visit a Lambda node. + def visit_lambda(node) + node.copy( + params: visit(node.params), + statements: visit(node.statements) + ) + end + + # Visit a LambdaVar node. + def visit_lambda_var(node) + node.copy(params: visit(node.params), locals: visit_all(node.locals)) + end + + # Visit a LBrace node. + def visit_lbrace(node) + node.copy + end + + # Visit a LBracket node. + def visit_lbracket(node) + node.copy + end + + # Visit a LParen node. + def visit_lparen(node) + node.copy + end + + # Visit a MAssign node. + def visit_massign(node) + node.copy(target: visit(node.target)) + end + + # Visit a MethodAddBlock node. + def visit_method_add_block(node) + node.copy(call: visit(node.call), block: visit(node.block)) + end + + # Visit a MLHS node. + def visit_mlhs(node) + node.copy(parts: visit_all(node.parts)) + end + + # Visit a MLHSParen node. + def visit_mlhs_paren(node) + node.copy(contents: visit(node.contents)) + end + + # Visit a ModuleDeclaration node. + def visit_module(node) + node.copy( + constant: visit(node.constant), + bodystmt: visit(node.bodystmt) + ) + end + + # Visit a MRHS node. + def visit_mrhs(node) + node.copy(parts: visit_all(node.parts)) + end + + # Visit a Next node. + def visit_next(node) + node.copy(arguments: visit(node.arguments)) + end + + # Visit a Op node. + def visit_op(node) + node.copy + end + + # Visit a OpAssign node. + def visit_opassign(node) + node.copy(target: visit(node.target), operator: visit(node.operator)) + end + + # Visit a Params node. + def visit_params(node) + node.copy( + requireds: visit_all(node.requireds), + optionals: + node.optionals.map { |ident, value| [visit(ident), visit(value)] }, + rest: visit(node.rest), + posts: visit_all(node.posts), + keywords: + node.keywords.map { |ident, value| [visit(ident), visit(value)] }, + keyword_rest: + node.keyword_rest == :nil ? :nil : visit(node.keyword_rest), + block: visit(node.block) + ) + end + + # Visit a Paren node. + def visit_paren(node) + node.copy(lparen: visit(node.lparen), contents: visit(node.contents)) + end + + # Visit a Period node. + def visit_period(node) + node.copy + end + + # Visit a Program node. + def visit_program(node) + node.copy(statements: visit(node.statements)) + end + + # Visit a QSymbols node. + def visit_qsymbols(node) + node.copy( + beginning: visit(node.beginning), + elements: visit_all(node.elements) + ) + end + + # Visit a QSymbolsBeg node. + def visit_qsymbols_beg(node) + node.copy + end + + # Visit a QWords node. + def visit_qwords(node) + node.copy( + beginning: visit(node.beginning), + elements: visit_all(node.elements) + ) + end + + # Visit a QWordsBeg node. + def visit_qwords_beg(node) + node.copy + end + + # Visit a RationalLiteral node. + def visit_rational(node) + node.copy + end + + # Visit a RBrace node. + def visit_rbrace(node) + node.copy + end + + # Visit a RBracket node. + def visit_rbracket(node) + node.copy + end + + # Visit a Redo node. + def visit_redo(node) + node.copy + end + + # Visit a RegexpContent node. + def visit_regexp_content(node) + node.copy(parts: visit_all(node.parts)) + end + + # Visit a RegexpBeg node. + def visit_regexp_beg(node) + node.copy + end + + # Visit a RegexpEnd node. + def visit_regexp_end(node) + node.copy + end + + # Visit a RegexpLiteral node. + def visit_regexp_literal(node) + node.copy(parts: visit_all(node.parts)) + end + + # Visit a RescueEx node. + def visit_rescue_ex(node) + node.copy(variable: visit(node.variable)) + end + + # Visit a Rescue node. + def visit_rescue(node) + node.copy( + keyword: visit(node.keyword), + exception: visit(node.exception), + statements: visit(node.statements), + consequent: visit(node.consequent) + ) + end + + # Visit a RescueMod node. + def visit_rescue_mod(node) + node.copy + end + + # Visit a RestParam node. + def visit_rest_param(node) + node.copy(name: visit(node.name)) + end + + # Visit a Retry node. + def visit_retry(node) + node.copy + end + + # Visit a Return node. + def visit_return(node) + node.copy(arguments: visit(node.arguments)) + end + + # Visit a RParen node. + def visit_rparen(node) + node.copy + end + + # Visit a SClass node. + def visit_sclass(node) + node.copy(bodystmt: visit(node.bodystmt)) + end + + # Visit a Statements node. + def visit_statements(node) + node.copy(body: visit_all(node.body)) + end + + # Visit a StringContent node. + def visit_string_content(node) + node.copy(parts: visit_all(node.parts)) + end + + # Visit a StringConcat node. + def visit_string_concat(node) + node.copy(left: visit(node.left), right: visit(node.right)) + end + + # Visit a StringDVar node. + def visit_string_dvar(node) + node.copy(variable: visit(node.variable)) + end + + # Visit a StringEmbExpr node. + def visit_string_embexpr(node) + node.copy(statements: visit(node.statements)) + end + + # Visit a StringLiteral node. + def visit_string_literal(node) + node.copy(parts: visit_all(node.parts)) + end + + # Visit a Super node. + def visit_super(node) + node.copy(arguments: visit(node.arguments)) + end + + # Visit a SymBeg node. + def visit_symbeg(node) + node.copy + end + + # Visit a SymbolContent node. + def visit_symbol_content(node) + node.copy(value: visit(node.value)) + end + + # Visit a SymbolLiteral node. + def visit_symbol_literal(node) + node.copy(value: visit(node.value)) + end + + # Visit a Symbols node. + def visit_symbols(node) + node.copy( + beginning: visit(node.beginning), + elements: visit_all(node.elements) + ) + end + + # Visit a SymbolsBeg node. + def visit_symbols_beg(node) + node.copy + end + + # Visit a TLambda node. + def visit_tlambda(node) + node.copy + end + + # Visit a TLamBeg node. + def visit_tlambeg(node) + node.copy + end + + # Visit a TopConstField node. + def visit_top_const_field(node) + node.copy(constant: visit(node.constant)) + end + + # Visit a TopConstRef node. + def visit_top_const_ref(node) + node.copy(constant: visit(node.constant)) + end + + # Visit a TStringBeg node. + def visit_tstring_beg(node) + node.copy + end + + # Visit a TStringContent node. + def visit_tstring_content(node) + node.copy + end + + # Visit a TStringEnd node. + def visit_tstring_end(node) + node.copy + end + + # Visit a Not node. + def visit_not(node) + node.copy(statement: visit(node.statement)) + end + + # Visit a Unary node. + def visit_unary(node) + node.copy + end + + # Visit a Undef node. + def visit_undef(node) + node.copy(symbols: visit_all(node.symbols)) + end + + # Visit a Unless node. + def visit_unless(node) + node.copy( + statements: visit(node.statements), + consequent: visit(node.consequent) + ) + end + + # Visit a Until node. + def visit_until(node) + node.copy(statements: visit(node.statements)) + end + + # Visit a VarField node. + def visit_var_field(node) + node.copy(value: visit(node.value)) + end + + # Visit a VarRef node. + def visit_var_ref(node) + node.copy(value: visit(node.value)) + end + + # Visit a PinnedVarRef node. + def visit_pinned_var_ref(node) + node.copy(value: visit(node.value)) + end + + # Visit a VCall node. + def visit_vcall(node) + node.copy(value: visit(node.value)) + end + + # Visit a VoidStmt node. + def visit_void_stmt(node) + node.copy + end + + # Visit a When node. + def visit_when(node) + node.copy( + arguments: visit(node.arguments), + statements: visit(node.statements), + consequent: visit(node.consequent) + ) + end + + # Visit a While node. + def visit_while(node) + node.copy(statements: visit(node.statements)) + end + + # Visit a Word node. + def visit_word(node) + node.copy(parts: visit_all(node.parts)) + end + + # Visit a Words node. + def visit_words(node) + node.copy( + beginning: visit(node.beginning), + elements: visit_all(node.elements) + ) + end + + # Visit a WordsBeg node. + def visit_words_beg(node) + node.copy + end + + # Visit a XString node. + def visit_xstring(node) + node.copy(parts: visit_all(node.parts)) + end + + # Visit a XStringLiteral node. + def visit_xstring_literal(node) + node.copy(parts: visit_all(node.parts)) + end + + # Visit a Yield node. + def visit_yield(node) + node.copy(arguments: visit(node.arguments)) + end + + # Visit a ZSuper node. + def visit_zsuper(node) + node.copy + end + end + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index c46022ae..21bb75e3 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -61,6 +61,9 @@ def assert_syntax_tree(node) refute_includes(pretty, "#<") assert_includes(pretty, type) + # Assert that we can get back a new tree by using the mutation visitor. + node.accept(Visitor::MutationVisitor.new) + # Serialize the node to JSON, parse it back out, and assert that we have # found the expected type. json = node.to_json From bab6417a328b93112ae8edbbda7d255a1ac6d959 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Tue, 8 Nov 2022 12:25:04 -0500 Subject: [PATCH 23/35] Add the === operator to check for matching --- lib/syntax_tree/node.rb | 693 ++++++++++++++++++++++++++++++++++++++++ test/test_helper.rb | 2 +- 2 files changed, 694 insertions(+), 1 deletion(-) diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index fb4bab21..c9789e1e 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -127,6 +127,18 @@ def construct_keys end end + # When we're implementing the === operator for a node, we oftentimes need to + # compare two arrays. We want to skip over the === definition of array and use + # our own here, so we do that using this module. + module ArrayMatch + def self.call(left, right) + left.length === right.length && + left + .zip(right) + .all? { |left_value, right_value| left_value === right_value } + end + end + # BEGINBlock represents the use of the +BEGIN+ keyword, which hooks into the # lifecycle of the interpreter. Whatever is inside the block will get executed # when the program starts. @@ -192,6 +204,11 @@ def format(q) q.text("}") end end + + def ===(other) + other.is_a?(BEGINBlock) && lbrace === other.lbrace && + statements === other.statements + end end # CHAR irepresents a single codepoint in the script encoding. @@ -240,6 +257,10 @@ def format(q) q.text(q.quote) end end + + def ===(other) + other.is_a?(CHAR) && value === other.value + end end # ENDBlock represents the use of the +END+ keyword, which hooks into the @@ -307,6 +328,11 @@ def format(q) q.text("}") end end + + def ===(other) + other.is_a?(ENDBlock) && lbrace === other.lbrace && + statements === other.statements + end end # EndContent represents the use of __END__ syntax, which allows individual @@ -369,6 +395,10 @@ def format(q) q.breakable_return if value.end_with?("\n") end + + def ===(other) + other.is_a?(EndContent) && value === other.value + end end # Alias represents the use of the +alias+ keyword with regular arguments (not @@ -465,6 +495,10 @@ def format(q) end end + def ===(other) + other.is_a?(Alias) && left === other.left && right === other.right + end + def var_alias? left.is_a?(GVar) end @@ -543,6 +577,11 @@ def format(q) q.text("]") end end + + def ===(other) + other.is_a?(ARef) && collection === other.collection && + index === other.index + end end # ARefField represents assigning values into collections at specific indices. @@ -612,6 +651,11 @@ def format(q) q.text("]") end end + + def ===(other) + other.is_a?(ARefField) && collection === other.collection && + index === other.index + end end # ArgParen represents wrapping arguments to a method inside a set of @@ -678,6 +722,10 @@ def format(q) q.text(")") end + def ===(other) + other.is_a?(ArgParen) && arguments === other.arguments + end + private def trailing_comma? @@ -740,6 +788,10 @@ def deconstruct_keys(_keys) def format(q) q.seplist(parts) { |part| q.format(part) } end + + def ===(other) + other.is_a?(Args) && ArrayMatch.call(parts, other.parts) + end end # ArgBlock represents using a block operator on an expression. @@ -784,6 +836,10 @@ def format(q) q.text("&") q.format(value) if value end + + def ===(other) + other.is_a?(ArgBlock) && value === other.value + end end # Star represents using a splat operator on an expression. @@ -828,6 +884,10 @@ def format(q) q.text("*") q.format(value) if value end + + def ===(other) + other.is_a?(ArgStar) && value === other.value + end end # ArgsForward represents forwarding all kinds of arguments onto another method @@ -877,6 +937,10 @@ def deconstruct_keys(_keys) def format(q) q.text("...") end + + def ===(other) + other.is_a?(ArgsForward) + end end # ArrayLiteral represents an array literal, which can optionally contain @@ -1107,6 +1171,11 @@ def format(q) end end + def ===(other) + other.is_a?(ArrayLiteral) && lbracket === other.lbracket && + contents === other.contents + end + private def qwords? @@ -1278,6 +1347,12 @@ def format(q) q.text("]") end end + + def ===(other) + other.is_a?(AryPtn) && constant === other.constant && + ArrayMatch.call(requireds, other.requireds) && rest === other.rest && + ArrayMatch.call(posts, other.posts) + end end # Determins if the following value should be indented or not. @@ -1360,6 +1435,10 @@ def format(q) end end + def ===(other) + other.is_a?(Assign) && target === other.target && value === other.value + end + private def skip_indent? @@ -1421,6 +1500,10 @@ def format(q) end end + def ===(other) + other.is_a?(Assoc) && key === other.key && value === other.value + end + private def format_contents(q) @@ -1482,6 +1565,10 @@ def format(q) q.text("**") q.format(value) end + + def ===(other) + other.is_a?(AssocSplat) && value === other.value + end end # Backref represents a global variable referencing a matched value. It comes @@ -1526,6 +1613,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(Backref) && value === other.value + end end # Backtick represents the use of the ` operator. It's usually found being used @@ -1568,6 +1659,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(Backtick) && value === other.value + end end # This module is responsible for formatting the assocs contained within a @@ -1688,6 +1783,10 @@ def format(q) q.seplist(assocs) { |assoc| q.format(assoc) } end + def ===(other) + other.is_a?(BareAssocHash) && ArrayMatch.call(assocs, other.assocs) + end + def format_key(q, key) (@key_formatter ||= HashKeyFormatter.for(self)).format_key(q, key) end @@ -1746,6 +1845,10 @@ def format(q) q.breakable_force q.text("end") end + + def ===(other) + other.is_a?(Begin) && bodystmt === other.bodystmt + end end # PinnedBegin represents a pinning a nested statement within pattern matching. @@ -1801,6 +1904,10 @@ def format(q) end end end + + def ===(other) + other.is_a?(PinnedBegin) && statement === other.statement + end end # Binary represents any expression that involves two sub-expressions with an @@ -1898,6 +2005,11 @@ def format(q) end end end + + def ===(other) + other.is_a?(Binary) && left === other.left && + operator === other.operator && right === other.right + end end # BlockVar represents the parameters being declared for a block. Effectively @@ -1970,6 +2082,11 @@ def format(q) end q.text("|") end + + def ===(other) + other.is_a?(BlockVar) && params === other.params && + ArrayMatch.call(locals, other.locals) + end end # BlockArg represents declaring a block parameter on a method definition. @@ -2011,6 +2128,10 @@ def format(q) q.text("&") q.format(name) if name end + + def ===(other) + other.is_a?(BlockArg) && name === other.name + end end # bodystmt can't actually determine its bounds appropriately because it @@ -2158,6 +2279,14 @@ def format(q) end end end + + def ===(other) + other.is_a?(BodyStmt) && statements === other.statements && + rescue_clause === other.rescue_clause && + else_keyword === other.else_keyword && + else_clause === other.else_clause && + ensure_clause === other.ensure_clause + end end # Formats either a Break, Next, or Return node. @@ -2394,6 +2523,10 @@ def deconstruct_keys(_keys) def format(q) FlowControlFormatter.new("break", self).format(q) end + + def ===(other) + other.is_a?(Break) && arguments === other.arguments + end end # Wraps a call operator (which can be a string literal :: or an Op node or a @@ -2761,6 +2894,12 @@ def format(q) end end + def ===(other) + other.is_a?(Call) && receiver === other.receiver && + operator === other.operator && message === other.message && + arguments === other.arguments + end + # Print out the arguments to this call. If there are no arguments, then do # nothing. def format_arguments(q) @@ -2879,6 +3018,11 @@ def format(q) q.text("end") end end + + def ===(other) + other.is_a?(Case) && keyword === other.keyword && value === other.value && + consequent === other.consequent + end end # RAssign represents a single-line pattern match. @@ -2957,6 +3101,11 @@ def format(q) end end end + + def ===(other) + other.is_a?(RAssign) && value === other.value && + operator === other.operator && pattern === other.pattern + end end # Class represents defining a class using the +class+ keyword. @@ -3064,6 +3213,11 @@ def format(q) end end + def ===(other) + other.is_a?(ClassDeclaration) && constant === other.constant && + superclass === other.superclass && bodystmt === other.bodystmt + end + private def format_declaration(q) @@ -3106,6 +3260,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(Comma) && value === other.value + end end # Command represents a method call with arguments and no parentheses. Note @@ -3173,6 +3331,11 @@ def format(q) q.format(block) if block end + def ===(other) + other.is_a?(Command) && message === other.message && + arguments === other.arguments && block === other.block + end + private def align(q, node, &block) @@ -3329,6 +3492,12 @@ def format(q) q.format(block) if block end + def ===(other) + other.is_a?(CommandCall) && receiver === other.receiver && + operator === other.operator && message === other.message && + arguments === other.arguments && block === other.block + end + private def argument_alignment(q, doc) @@ -3425,6 +3594,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(Comment) && value === other.value && inline === other.inline + end end # Const represents a literal value that _looks_ like a constant. This could @@ -3475,6 +3648,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(Const) && value === other.value + end end # ConstPathField represents the child node of some kind of assignment. It @@ -3532,6 +3709,11 @@ def format(q) q.text("::") q.format(constant) end + + def ===(other) + other.is_a?(ConstPathField) && parent === other.parent && + constant === other.constant + end end # ConstPathRef represents referencing a constant by a path. @@ -3587,6 +3769,11 @@ def format(q) q.text("::") q.format(constant) end + + def ===(other) + other.is_a?(ConstPathRef) && parent === other.parent && + constant === other.constant + end end # ConstRef represents the name of the constant being used in a class or module @@ -3632,6 +3819,10 @@ def deconstruct_keys(_keys) def format(q) q.format(constant) end + + def ===(other) + other.is_a?(ConstRef) && constant === other.constant + end end # CVar represents the use of a class variable. @@ -3672,6 +3863,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(CVar) && value === other.value + end end # Def represents defining a regular method on the current self object. @@ -3790,6 +3985,12 @@ def format(q) end end + def ===(other) + other.is_a?(Def) && target === other.target && + operator === other.operator && name === other.name && + params === other.params && bodystmt === other.bodystmt + end + # Returns true if the method was found in the source in the "endless" form, # i.e. where the method body is defined using the `=` operator after the # method name and parameters. @@ -3848,6 +4049,10 @@ def format(q) end q.text(")") end + + def ===(other) + other.is_a?(Defined) && value === other.value + end end # Block represents passing a block to a method call using the +do+ and +end+ @@ -3962,6 +4167,11 @@ def format(q) end end + def ===(other) + other.is_a?(Block) && opening === other.opening && + block_var === other.block_var && bodystmt === other.bodystmt + end + def keywords? opening.is_a?(Kw) end @@ -4130,6 +4340,11 @@ def format(q) q.format(right) if right end + + def ===(other) + other.is_a?(RangeLiteral) && left === other.left && + operator === other.operator && right === other.right + end end # Responsible for providing information about quotes to be used for strings @@ -4251,6 +4466,11 @@ def format(q) q.text(closing_quote) end + def ===(other) + other.is_a?(DynaSymbol) && ArrayMatch.call(parts, other.parts) && + quote === other.quote + end + private # Here we determine the quotes to use for a dynamic symbol. It's bound by a @@ -4358,6 +4578,11 @@ def format(q) end end end + + def ===(other) + other.is_a?(Else) && keyword === other.keyword && + statements === other.statements + end end # Elsif represents another clause in an +if+ or +unless+ chain. @@ -4444,6 +4669,11 @@ def format(q) end end end + + def ===(other) + other.is_a?(Elsif) && predicate === other.predicate && + statements === other.statements && consequent === other.consequent + end end # EmbDoc represents a multi-line comment. @@ -4499,6 +4729,10 @@ def format(q) q.trim q.text(value) end + + def ===(other) + other.is_a?(EmbDoc) && value === other.value + end end # EmbExprBeg represents the beginning token for using interpolation inside of @@ -4536,6 +4770,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(EmbExprBeg) && value === other.value + end end # EmbExprEnd represents the ending token for using interpolation inside of a @@ -4573,6 +4811,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(EmbExprEnd) && value === other.value + end end # EmbVar represents the use of shorthand interpolation for an instance, class, @@ -4612,6 +4854,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(EmbVar) && value === other.value + end end # Ensure represents the use of the +ensure+ keyword and its subsequent @@ -4675,6 +4921,11 @@ def format(q) end end end + + def ===(other) + other.is_a?(Ensure) && keyword === other.keyword && + statements === other.statements + end end # ExcessedComma represents a trailing comma in a list of block parameters. It @@ -4724,6 +4975,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(ExcessedComma) && value === other.value + end end # Field is always the child of an assignment. It represents assigning to a @@ -4788,6 +5043,11 @@ def format(q) q.format(name) end end + + def ===(other) + other.is_a?(Field) && parent === other.parent && + operator === other.operator && name === other.name + end end # FloatLiteral represents a floating point number literal. @@ -4831,6 +5091,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(FloatLiteral) && value === other.value + end end # FndPtn represents matching against a pattern where you find a pattern in an @@ -4921,6 +5185,12 @@ def format(q) q.text("]") end end + + def ===(other) + other.is_a?(FndPtn) && constant === other.constant && + left === other.left && ArrayMatch.call(values, other.values) && + right === other.right + end end # For represents using a +for+ loop. @@ -4997,6 +5267,11 @@ def format(q) q.text("end") end end + + def ===(other) + other.is_a?(For) && index === other.index && + collection === other.collection && statements === other.statements + end end # GVar represents a global variable literal. @@ -5037,6 +5312,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(GVar) && value === other.value + end end # HashLiteral represents a hash literal. @@ -5116,6 +5395,11 @@ def format(q) end end + def ===(other) + other.is_a?(HashLiteral) && lbrace === other.lbrace && + ArrayMatch.call(assocs, other.assocs) + end + def format_key(q, key) (@key_formatter ||= HashKeyFormatter.for(self)).format_key(q, key) end @@ -5257,6 +5541,11 @@ def format(q) end end end + + def ===(other) + other.is_a?(Heredoc) && beginning === other.beginning && + ending === other.ending && ArrayMatch.call(parts, other.parts) + end end # HeredocBeg represents the beginning declaration of a heredoc. @@ -5303,6 +5592,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(HeredocBeg) && value === other.value + end end # HeredocEnd represents the closing declaration of a heredoc. @@ -5349,6 +5642,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(HeredocEnd) && value === other.value + end end # HshPtn represents matching against a hash pattern using the Ruby 2.7+ @@ -5507,6 +5804,15 @@ def format(q) end end + def ===(other) + other.is_a?(HshPtn) && constant === other.constant && + keywords.length == other.keywords.length && + keywords + .zip(other.keywords) + .all? { |left, right| ArrayMatch.call(left, right) } && + keyword_rest === other.keyword_rest + end + private def format_contents(q, parts, nested) @@ -5564,6 +5870,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(Ident) && value === other.value + end end # If the predicate of a conditional or loop contains an assignment (in which @@ -5868,6 +6178,11 @@ def format(q) ConditionalFormatter.new("if", self).format(q) end + def ===(other) + other.is_a?(If) && predicate === other.predicate && + statements === other.statements && consequent === other.consequent + end + # Checks if the node was originally found in the modifier form. def modifier? predicate.location.start_char > statements.location.start_char @@ -5944,6 +6259,11 @@ def format(q) q.group { q.if_break { format_break(q) }.if_flat { format_flat(q) } } end + def ===(other) + other.is_a?(IfOp) && predicate === other.predicate && + truthy === other.truthy && falsy === other.falsy + end + private def format_break(q) @@ -6025,6 +6345,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(Imaginary) && value === other.value + end end # In represents using the +in+ keyword within the Ruby 2.7+ pattern matching @@ -6104,6 +6428,11 @@ def format(q) end end end + + def ===(other) + other.is_a?(In) && pattern === other.pattern && + statements === other.statements && consequent === other.consequent + end end # Int represents an integer number literal. @@ -6152,6 +6481,10 @@ def format(q) q.text(value) end end + + def ===(other) + other.is_a?(Int) && value === other.value + end end # IVar represents an instance variable literal. @@ -6192,6 +6525,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(IVar) && value === other.value + end end # Kw represents the use of a keyword. It can be almost anywhere in the syntax @@ -6245,6 +6582,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(Kw) && value === other.value + end end # KwRestParam represents defining a parameter in a method definition that @@ -6290,6 +6631,10 @@ def format(q) q.text("**") q.format(name) if name end + + def ===(other) + other.is_a?(KwRestParam) && name === other.name + end end # Label represents the use of an identifier to associate with an object. You @@ -6339,6 +6684,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(Label) && value === other.value + end end # LabelEnd represents the end of a dynamic symbol. @@ -6377,6 +6726,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(LabelEnd) && value === other.value + end end # Lambda represents using a lambda literal (not the lambda method call). @@ -6489,6 +6842,11 @@ def format(q) end end end + + def ===(other) + other.is_a?(Lambda) && params === other.params && + statements === other.statements + end end # LambdaVar represents the parameters being declared for a lambda. Effectively @@ -6550,6 +6908,11 @@ def format(q) q.seplist(locals, BlockVar::SEPARATOR) { |local| q.format(local) } end end + + def ===(other) + other.is_a?(LambdaVar) && params === other.params && + ArrayMatch.call(locals, other.locals) + end end # LBrace represents the use of a left brace, i.e., {. @@ -6590,6 +6953,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(LBrace) && value === other.value + end end # LBracket represents the use of a left bracket, i.e., [. @@ -6630,6 +6997,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(LBracket) && value === other.value + end end # LParen represents the use of a left parenthesis, i.e., (. @@ -6670,6 +7041,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(LParen) && value === other.value + end end # MAssign is a parent node of any kind of multiple assignment. This includes @@ -6735,6 +7110,10 @@ def format(q) end end end + + def ===(other) + other.is_a?(MAssign) && target === other.target && value === other.value + end end # MethodAddBlock represents a method call with a block argument. @@ -6796,6 +7175,11 @@ def format(q) end end + def ===(other) + other.is_a?(MethodAddBlock) && call === other.call && + block === other.block + end + def format_contents(q) q.format(call) q.format(block) @@ -6853,6 +7237,11 @@ def format(q) q.seplist(parts) { |part| q.format(part) } q.text(",") if comma end + + def ===(other) + other.is_a?(MLHS) && ArrayMatch.call(parts, other.parts) && + comma === other.comma + end end # MLHSParen represents parentheses being used to destruct values in a multiple @@ -6920,6 +7309,10 @@ def format(q) q.text(")") end end + + def ===(other) + other.is_a?(MLHSParen) && contents === other.contents + end end # ModuleDeclaration represents defining a module using the +module+ keyword. @@ -6993,6 +7386,11 @@ def format(q) end end + def ===(other) + other.is_a?(ModuleDeclaration) && constant === other.constant && + bodystmt === other.bodystmt + end + private def format_declaration(q) @@ -7042,6 +7440,10 @@ def deconstruct_keys(_keys) def format(q) q.seplist(parts) { |part| q.format(part) } end + + def ===(other) + other.is_a?(MRHS) && ArrayMatch.call(parts, other.parts) + end end # Next represents using the +next+ keyword. @@ -7098,6 +7500,10 @@ def deconstruct_keys(_keys) def format(q) FlowControlFormatter.new("next", self).format(q) end + + def ===(other) + other.is_a?(Next) && arguments === other.arguments + end end # Op represents an operator literal in the source. @@ -7143,6 +7549,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(Op) && value === other.value + end end # OpAssign represents assigning a value to a variable or constant using an @@ -7219,6 +7629,11 @@ def format(q) end end + def ===(other) + other.is_a?(OpAssign) && target === other.target && + operator === other.operator && value === other.value + end + private def skip_indent? @@ -7522,6 +7937,20 @@ def format(q) end end + def ===(other) + other.is_a?(Params) && ArrayMatch.call(requireds, other.requireds) && + optionals.length == other.optionals.length && + optionals + .zip(other.optionals) + .all? { |left, right| ArrayMatch.call(left, right) } && + rest === other.rest && ArrayMatch.call(posts, other.posts) && + keywords.length == other.keywords.length && + keywords + .zip(other.keywords) + .all? { |left, right| ArrayMatch.call(left, right) } && + keyword_rest === other.keyword_rest && block === other.block + end + private def format_contents(q, parts) @@ -7595,6 +8024,11 @@ def format(q) q.text(")") end end + + def ===(other) + other.is_a?(Paren) && lparen === other.lparen && + contents === other.contents + end end # Period represents the use of the +.+ operator. It is usually found in method @@ -7636,6 +8070,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(Period) && value === other.value + end end # Program represents the overall syntax tree. @@ -7681,6 +8119,10 @@ def format(q) # replicate the text exactly so we will just let it be. q.breakable_force unless statements.body.last.is_a?(EndContent) end + + def ===(other) + other.is_a?(Program) && statements === other.statements + end end # QSymbols represents a symbol literal array without interpolation. @@ -7752,6 +8194,11 @@ def format(q) end q.text(closing) end + + def ===(other) + other.is_a?(QSymbols) && beginning === other.beginning && + ArrayMatch.call(elements, other.elements) + end end # QSymbolsBeg represents the beginning of a symbol literal array. @@ -7790,6 +8237,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(QSymbolsBeg) && value === other.value + end end # QWords represents a string literal array without interpolation. @@ -7861,6 +8312,11 @@ def format(q) end q.text(closing) end + + def ===(other) + other.is_a?(QWords) && beginning === other.beginning && + ArrayMatch.call(elements, other.elements) + end end # QWordsBeg represents the beginning of a string literal array. @@ -7899,6 +8355,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(QWordsBeg) && value === other.value + end end # RationalLiteral represents the use of a rational number literal. @@ -7942,6 +8402,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(RationalLiteral) && value === other.value + end end # RBrace represents the use of a right brace, i.e., +++. @@ -7974,6 +8438,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(RBrace) && value === other.value + end end # RBracket represents the use of a right bracket, i.e., +]+. @@ -8006,6 +8474,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(RBracket) && value === other.value + end end # Redo represents the use of the +redo+ keyword. @@ -8042,6 +8514,10 @@ def deconstruct_keys(_keys) def format(q) q.text("redo") end + + def ===(other) + other.is_a?(Redo) + end end # RegexpContent represents the body of a regular expression. @@ -8085,6 +8561,11 @@ def copy(beginning: nil, parts: nil, location: nil) def deconstruct_keys(_keys) { beginning: beginning, parts: parts, location: location } end + + def ===(other) + other.is_a?(RegexpContent) && beginning === other.beginning && + parts === other.parts + end end # RegexpBeg represents the start of a regular expression literal. @@ -8125,6 +8606,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(RegexpBeg) && value === other.value + end end # RegexpEnd represents the end of a regular expression literal. @@ -8166,6 +8651,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(RegexpEnd) && value === other.value + end end # RegexpLiteral represents a regular expression literal. @@ -8264,6 +8753,12 @@ def format(q) end end + def ===(other) + other.is_a?(RegexpLiteral) && beginning === other.beginning && + ending === other.ending && options === other.options && + ArrayMatch.call(parts, other.parts) + end + def options ending[1..] end @@ -8353,6 +8848,11 @@ def format(q) end end end + + def ===(other) + other.is_a?(RescueEx) && exceptions === other.exceptions && + variable === other.variable + end end # Rescue represents the use of the rescue keyword inside of a BodyStmt node. @@ -8475,6 +8975,12 @@ def format(q) end end end + + def ===(other) + other.is_a?(Rescue) && keyword === other.keyword && + exception === other.exception && statements === other.statements && + consequent === other.consequent + end end # RescueMod represents the use of the modifier form of a +rescue+ clause. @@ -8542,6 +9048,11 @@ def format(q) end q.text("end") end + + def ===(other) + other.is_a?(RescueMod) && statement === other.statement && + value === other.value + end end # RestParam represents defining a parameter in a method definition that @@ -8587,6 +9098,10 @@ def format(q) q.text("*") q.format(name) if name end + + def ===(other) + other.is_a?(RestParam) && name === other.name + end end # Retry represents the use of the +retry+ keyword. @@ -8623,6 +9138,10 @@ def deconstruct_keys(_keys) def format(q) q.text("retry") end + + def ===(other) + other.is_a?(Retry) + end end # Return represents using the +return+ keyword with arguments. @@ -8666,6 +9185,10 @@ def deconstruct_keys(_keys) def format(q) FlowControlFormatter.new("return", self).format(q) end + + def ===(other) + other.is_a?(Return) && arguments === other.arguments + end end # RParen represents the use of a right parenthesis, i.e., +)+. @@ -8698,6 +9221,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(RParen) && value === other.value + end end # SClass represents a block of statements that should be evaluated within the @@ -8763,6 +9290,11 @@ def format(q) end q.text("end") end + + def ===(other) + other.is_a?(SClass) && target === other.target && + bodystmt === other.bodystmt + end end # Everything that has a block of code inside of it has a list of statements. @@ -8906,6 +9438,10 @@ def format(q) end end + def ===(other) + other.is_a?(Statements) && ArrayMatch.call(body, other.body) + end + private # As efficiently as possible, gather up all of the comments that have been @@ -8983,6 +9519,10 @@ def copy(parts: nil, location: nil) def deconstruct_keys(_keys) { parts: parts, location: location } end + + def ===(other) + other.is_a?(StringContent) && ArrayMatch.call(parts, other.parts) + end end # StringConcat represents concatenating two strings together using a backward @@ -9040,6 +9580,10 @@ def format(q) end end end + + def ===(other) + other.is_a?(StringConcat) && left === other.left && right === other.right + end end # StringDVar represents shorthand interpolation of a variable into a string. @@ -9087,6 +9631,10 @@ def format(q) q.format(variable) q.text("}") end + + def ===(other) + other.is_a?(StringDVar) && variable === other.variable + end end # StringEmbExpr represents interpolated content. It can be contained within a @@ -9154,6 +9702,10 @@ def format(q) end end end + + def ===(other) + other.is_a?(StringEmbExpr) && statements === other.statements + end end # StringLiteral represents a string literal. @@ -9240,6 +9792,11 @@ def format(q) end q.text(closing_quote) end + + def ===(other) + other.is_a?(StringLiteral) && ArrayMatch.call(parts, other.parts) && + quote === other.quote + end end # Super represents using the +super+ keyword with arguments. It can optionally @@ -9293,6 +9850,10 @@ def format(q) end end end + + def ===(other) + other.is_a?(Super) && arguments === other.arguments + end end # SymBeg represents the beginning of a symbol literal. @@ -9340,6 +9901,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(SymBeg) && value === other.value + end end # SymbolContent represents symbol contents and is always the child of a @@ -9377,6 +9942,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(SymbolContent) && value === other.value + end end # SymbolLiteral represents a symbol in the system with no interpolation @@ -9423,6 +9992,10 @@ def format(q) q.text(":") q.format(value) end + + def ===(other) + other.is_a?(SymbolLiteral) && value === other.value + end end # Symbols represents a symbol array literal with interpolation. @@ -9494,6 +10067,11 @@ def format(q) end q.text(closing) end + + def ===(other) + other.is_a?(Symbols) && beginning === other.beginning && + ArrayMatch.call(elements, other.elements) + end end # SymbolsBeg represents the start of a symbol array literal with @@ -9533,6 +10111,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(SymbolsBeg) && value === other.value + end end # TLambda represents the beginning of a lambda literal. @@ -9569,6 +10151,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(TLambda) && value === other.value + end end # TLamBeg represents the beginning of the body of a lambda literal using @@ -9606,6 +10192,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(TLamBeg) && value === other.value + end end # TopConstField is always the child node of some kind of assignment. It @@ -9652,6 +10242,10 @@ def format(q) q.text("::") q.format(constant) end + + def ===(other) + other.is_a?(TopConstField) && constant === other.constant + end end # TopConstRef is very similar to TopConstField except that it is not involved @@ -9697,6 +10291,10 @@ def format(q) q.text("::") q.format(constant) end + + def ===(other) + other.is_a?(TopConstRef) && constant === other.constant + end end # TStringBeg represents the beginning of a string literal. @@ -9738,6 +10336,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(TStringBeg) && value === other.value + end end # TStringContent represents plain characters inside of an entity that accepts @@ -9789,6 +10391,10 @@ def deconstruct_keys(_keys) def format(q) q.text(value) end + + def ===(other) + other.is_a?(TStringContent) && value === other.value + end end # TStringEnd represents the end of a string literal. @@ -9830,6 +10436,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(TStringEnd) && value === other.value + end end # Not represents the unary +not+ method being called on an expression. @@ -9904,6 +10514,11 @@ def format(q) end end end + + def ===(other) + other.is_a?(Not) && statement === other.statement && + parentheses === other.parentheses + end end # Unary represents a unary method being called on an expression, as in +!+ or @@ -9959,6 +10574,11 @@ def format(q) q.text(operator) q.format(statement) end + + def ===(other) + other.is_a?(Unary) && operator === other.operator && + statement === other.statement + end end # Undef represents the use of the +undef+ keyword. @@ -10034,6 +10654,10 @@ def format(q) end end end + + def ===(other) + other.is_a?(Undef) && ArrayMatch.call(symbols, other.symbols) + end end # Unless represents the first clause in an +unless+ chain. @@ -10101,6 +10725,11 @@ def format(q) ConditionalFormatter.new("unless", self).format(q) end + def ===(other) + other.is_a?(Unless) && predicate === other.predicate && + statements === other.statements && consequent === other.consequent + end + # Checks if the node was originally found in the modifier form. def modifier? predicate.location.start_char > statements.location.start_char @@ -10232,6 +10861,11 @@ def format(q) LoopFormatter.new("until", self).format(q) end + def ===(other) + other.is_a?(Until) && predicate === other.predicate && + statements === other.statements + end + def modifier? predicate.location.start_char > statements.location.start_char end @@ -10284,6 +10918,10 @@ def format(q) q.format(value) end end + + def ===(other) + other.is_a?(VarField) && value === other.value + end end # VarRef represents a variable reference. @@ -10332,6 +10970,10 @@ def format(q) q.format(value) end + def ===(other) + other.is_a?(VarRef) && value === other.value + end + # Oh man I hate this so much. Basically, ripper doesn't provide enough # functionality to actually know where pins are within an expression. So we # have to walk the tree ourselves and insert more information. In doing so, @@ -10405,6 +11047,10 @@ def format(q) q.format(value) end end + + def ===(other) + other.is_a?(PinnedVarRef) && value === other.value + end end # VCall represent any plain named object with Ruby that could be either a @@ -10447,6 +11093,10 @@ def format(q) q.format(value) end + def ===(other) + other.is_a?(VCall) && value === other.value + end + def access_control? @access_control ||= %w[private protected public].include?(value.value) end @@ -10488,6 +11138,10 @@ def deconstruct_keys(_keys) def format(q) end + + def ===(other) + other.is_a?(VoidStmt) + end end # When represents a +when+ clause in a +case+ chain. @@ -10602,6 +11256,11 @@ def format(q) end end end + + def ===(other) + other.is_a?(When) && arguments === other.arguments && + statements === other.statements && consequent === other.consequent + end end # While represents a +while+ loop. @@ -10657,6 +11316,11 @@ def format(q) LoopFormatter.new("while", self).format(q) end + def ===(other) + other.is_a?(While) && predicate === other.predicate && + statements === other.statements + end + def modifier? predicate.location.start_char > statements.location.start_char end @@ -10708,6 +11372,10 @@ def deconstruct_keys(_keys) def format(q) q.format_each(parts) end + + def ===(other) + other.is_a?(Word) && ArrayMatch.call(parts, other.parts) + end end # Words represents a string literal array with interpolation. @@ -10779,6 +11447,11 @@ def format(q) end q.text(closing) end + + def ===(other) + other.is_a?(Words) && beginning === other.beginning && + ArrayMatch.call(elements, other.elements) + end end # WordsBeg represents the beginning of a string literal array with @@ -10818,6 +11491,10 @@ def copy(value: nil, location: nil) def deconstruct_keys(_keys) { value: value, location: location } end + + def ===(other) + other.is_a?(WordsBeg) && value === other.value + end end # XString represents the contents of an XStringLiteral. @@ -10854,6 +11531,10 @@ def copy(parts: nil, location: nil) def deconstruct_keys(_keys) { parts: parts, location: location } end + + def ===(other) + other.is_a?(XString) && ArrayMatch.call(parts, other.parts) + end end # XStringLiteral represents a string that gets executed. @@ -10900,6 +11581,10 @@ def format(q) q.format_each(parts) q.text("`") end + + def ===(other) + other.is_a?(XStringLiteral) && ArrayMatch.call(parts, other.parts) + end end # Yield represents using the +yield+ keyword with arguments. @@ -10962,6 +11647,10 @@ def format(q) end end end + + def ===(other) + other.is_a?(Yield) && arguments === other.arguments + end end # ZSuper represents the bare +super+ keyword with no arguments. @@ -10998,5 +11687,9 @@ def deconstruct_keys(_keys) def format(q) q.text("super") end + + def ===(other) + other.is_a?(ZSuper) + end end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 21bb75e3..1683e7cf 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -62,7 +62,7 @@ def assert_syntax_tree(node) assert_includes(pretty, type) # Assert that we can get back a new tree by using the mutation visitor. - node.accept(Visitor::MutationVisitor.new) + assert_operator node, :===, node.accept(Visitor::MutationVisitor.new) # Serialize the node to JSON, parse it back out, and assert that we have # found the expected type. From 6c41e756ede60302fd83c119df2ed0d3a2b62da5 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Tue, 8 Nov 2022 12:35:30 -0500 Subject: [PATCH 24/35] Track parent context in the mutation visitor --- lib/syntax_tree/visitor/mutation_visitor.rb | 28 ++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/syntax_tree/visitor/mutation_visitor.rb b/lib/syntax_tree/visitor/mutation_visitor.rb index c2bdc7fc..8b7f187b 100644 --- a/lib/syntax_tree/visitor/mutation_visitor.rb +++ b/lib/syntax_tree/visitor/mutation_visitor.rb @@ -4,7 +4,33 @@ module SyntaxTree class Visitor # This visitor walks through the tree and copies each node as it is being # visited. This is useful for mutating the tree before it is formatted. - class MutationVisitor < Visitor + class MutationVisitor < BasicVisitor + # Here we maintain a stack of parent nodes so that it's easy to reflect on + # the context of a given node while mutating it. + attr_reader :stack + + def initialize + @stack = [] + end + + # This is the main entrypoint that's going to be called when we're + # recursing down through the tree. + def visit(node) + return unless node + + stack << node + result = node.accept(self) + + stack.pop + result + end + + # This is a small helper to visit an array of nodes and return the result + # of visiting them all. + def visit_all(nodes) + nodes.map { |node| visit(node) } + end + # Visit a BEGINBlock node. def visit_BEGIN(node) node.copy( From 3086f41642a3f66aa7bed39a2b8471113e387cec Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Tue, 8 Nov 2022 13:01:42 -0500 Subject: [PATCH 25/35] Ensure comments are copied over correctly for copy method --- lib/syntax_tree/node.rb | 1665 ++++++++++++------- lib/syntax_tree/visitor/mutation_visitor.rb | 2 +- 2 files changed, 1071 insertions(+), 596 deletions(-) diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index c9789e1e..219c0de1 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -83,6 +83,17 @@ def self.fixed(line:, char:, column:) end_column: column ) end + + def self.default + new( + start_line: 1, + start_char: 0, + start_column: 0, + end_line: 1, + end_char: 0, + end_column: 0 + ) + end end # This is the parent node of all of the syntax tree nodes. It's pretty much @@ -174,11 +185,15 @@ def child_nodes end def copy(lbrace: nil, statements: nil, location: nil) - BEGINBlock.new( - lbrace: lbrace || self.lbrace, - statements: statements || self.statements, - location: location || self.location - ) + node = + BEGINBlock.new( + lbrace: lbrace || self.lbrace, + statements: statements || self.statements, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -239,7 +254,14 @@ def child_nodes end def copy(value: nil, location: nil) - CHAR.new(value: value || self.value, location: location || self.location) + node = + CHAR.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -298,11 +320,15 @@ def child_nodes end def copy(lbrace: nil, statements: nil, location: nil) - ENDBlock.new( - lbrace: lbrace || self.lbrace, - statements: statements || self.statements, - location: location || self.location - ) + node = + ENDBlock.new( + lbrace: lbrace || self.lbrace, + statements: statements || self.statements, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -366,10 +392,14 @@ def child_nodes end def copy(value: nil, location: nil) - EndContent.new( - value: value || self.value, - location: location || self.location - ) + node = + EndContent.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -466,11 +496,15 @@ def child_nodes end def copy(left: nil, right: nil, location: nil) - Alias.new( - left: left || self.left, - right: right || self.right, - location: location || self.location - ) + node = + Alias.new( + left: left || self.left, + right: right || self.right, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -543,11 +577,15 @@ def child_nodes end def copy(collection: nil, index: nil, location: nil) - ARef.new( - collection: collection || self.collection, - index: index || self.index, - location: location || self.location - ) + node = + ARef.new( + collection: collection || self.collection, + index: index || self.index, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -617,11 +655,15 @@ def child_nodes end def copy(collection: nil, index: nil, location: nil) - ARefField.new( - collection: collection || self.collection, - index: index || self.index, - location: location || self.location - ) + node = + ARefField.new( + collection: collection || self.collection, + index: index || self.index, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -692,10 +734,14 @@ def child_nodes end def copy(arguments: nil, location: nil) - ArgParen.new( - arguments: arguments || self.arguments, - location: location || self.location - ) + node = + ArgParen.new( + arguments: arguments || self.arguments, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -776,7 +822,14 @@ def child_nodes end def copy(parts: nil, location: nil) - Args.new(parts: parts || self.parts, location: location || self.location) + node = + Args.new( + parts: parts || self.parts, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -820,10 +873,14 @@ def child_nodes end def copy(value: nil, location: nil) - ArgBlock.new( - value: value || self.value, - location: location || self.location - ) + node = + ArgBlock.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -868,10 +925,14 @@ def child_nodes end def copy(value: nil, location: nil) - ArgStar.new( - value: value || self.value, - location: location || self.location - ) + node = + ArgStar.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -925,7 +986,10 @@ def child_nodes end def copy(location: nil) - ArgsForward.new(location: location || self.location) + node = ArgsForward.new(location: location || self.location) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -1116,11 +1180,15 @@ def child_nodes end def copy(lbracket: nil, contents: nil, location: nil) - ArrayLiteral.new( - lbracket: lbracket || self.lbracket, - contents: contents || self.contents, - location: location || self.location - ) + node = + ArrayLiteral.new( + lbracket: lbracket || self.lbracket, + contents: contents || self.contents, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -1277,14 +1345,7 @@ def format(q) # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize( - constant:, - requireds:, - rest:, - posts:, - location:, - comments: [] - ) + def initialize(constant:, requireds:, rest:, posts:, location:) @constant = constant @requireds = requireds @rest = rest @@ -1308,13 +1369,17 @@ def copy( posts: nil, location: nil ) - AryPtn.new( - constant: constant || self.constant, - requireds: requireds || self.requireds, - rest: rest || self.rest, - posts: posts || self.posts, - location: location || self.location - ) + node = + AryPtn.new( + constant: constant || self.constant, + requireds: requireds || self.requireds, + rest: rest || self.rest, + posts: posts || self.posts, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -1405,11 +1470,15 @@ def child_nodes end def copy(target: nil, value: nil, location: nil) - Assign.new( - target: target || self.target, - value: value || self.value, - location: location || self.location - ) + node = + Assign.new( + target: target || self.target, + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -1479,11 +1548,15 @@ def child_nodes end def copy(key: nil, value: nil, location: nil) - Assoc.new( - key: key || self.key, - value: value || self.value, - location: location || self.location - ) + node = + Assoc.new( + key: key || self.key, + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -1549,10 +1622,14 @@ def child_nodes end def copy(value: nil, location: nil) - AssocSplat.new( - value: value || self.value, - location: location || self.location - ) + node = + AssocSplat.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -1598,10 +1675,14 @@ def child_nodes end def copy(value: nil, location: nil) - Backref.new( - value: value || self.value, - location: location || self.location - ) + node = + Backref.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -1644,10 +1725,14 @@ def child_nodes end def copy(value: nil, location: nil) - Backtick.new( - value: value || self.value, - location: location || self.location - ) + node = + Backtick.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -1767,10 +1852,14 @@ def child_nodes end def copy(assocs: nil, location: nil) - BareAssocHash.new( - assocs: assocs || self.assocs, - location: location || self.location - ) + node = + BareAssocHash.new( + assocs: assocs || self.assocs, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -1820,10 +1909,14 @@ def child_nodes end def copy(bodystmt: nil, location: nil) - Begin.new( - bodystmt: bodystmt || self.bodystmt, - location: location || self.location - ) + node = + Begin.new( + bodystmt: bodystmt || self.bodystmt, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -1879,10 +1972,14 @@ def child_nodes end def copy(statement: nil, location: nil) - PinnedBegin.new( - statement: statement || self.statement, - location: location || self.location - ) + node = + PinnedBegin.new( + statement: statement || self.statement, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -1964,12 +2061,16 @@ def child_nodes end def copy(left: nil, operator: nil, right: nil, location: nil) - Binary.new( - left: left || self.left, - operator: operator || self.operator, - right: right || self.right, - location: location || self.location - ) + node = + Binary.new( + left: left || self.left, + operator: operator || self.operator, + right: right || self.right, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -2045,11 +2146,15 @@ def child_nodes end def copy(params: nil, locals: nil, location: nil) - BlockVar.new( - params: params || self.params, - locals: locals || self.locals, - location: location || self.location - ) + node = + BlockVar.new( + params: params || self.params, + locals: locals || self.locals, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -2115,7 +2220,14 @@ def child_nodes end def copy(name: nil, location: nil) - BlockArg.new(name: name || self.name, location: location || self.location) + node = + BlockArg.new( + name: name || self.name, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -2162,8 +2274,7 @@ def initialize( else_keyword:, else_clause:, ensure_clause:, - location:, - comments: [] + location: ) @statements = statements @rescue_clause = rescue_clause @@ -2224,14 +2335,18 @@ def copy( ensure_clause: nil, location: nil ) - BodyStmt.new( - statements: statements || self.statements, - rescue_clause: rescue_clause || self.rescue_clause, - else_keyword: else_keyword || self.else_keyword, - else_clause: else_clause || self.else_clause, - ensure_clause: ensure_clause || self.ensure_clause, - location: location || self.location - ) + node = + BodyStmt.new( + statements: statements || self.statements, + rescue_clause: rescue_clause || self.rescue_clause, + else_keyword: else_keyword || self.else_keyword, + else_clause: else_clause || self.else_clause, + ensure_clause: ensure_clause || self.ensure_clause, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -2508,10 +2623,14 @@ def child_nodes end def copy(arguments: nil, location: nil) - Break.new( - arguments: arguments || self.arguments, - location: location || self.location - ) + node = + Break.new( + arguments: arguments || self.arguments, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -2805,14 +2924,7 @@ class Call < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize( - receiver:, - operator:, - message:, - arguments:, - location:, - comments: [] - ) + def initialize(receiver:, operator:, message:, arguments:, location:) @receiver = receiver @operator = operator @message = message @@ -2841,13 +2953,17 @@ def copy( arguments: nil, location: nil ) - Call.new( - receiver: receiver || self.receiver, - operator: operator || self.operator, - message: message || self.message, - arguments: arguments || self.arguments, - location: location || self.location - ) + node = + Call.new( + receiver: receiver || self.receiver, + operator: operator || self.operator, + message: message || self.message, + arguments: arguments || self.arguments, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -2982,12 +3098,16 @@ def child_nodes end def copy(keyword: nil, value: nil, consequent: nil, location: nil) - Case.new( - keyword: keyword || self.keyword, - value: value || self.value, - consequent: consequent || self.consequent, - location: location || self.location - ) + node = + Case.new( + keyword: keyword || self.keyword, + value: value || self.value, + consequent: consequent || self.consequent, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -3061,12 +3181,16 @@ def child_nodes end def copy(value: nil, operator: nil, pattern: nil, location: nil) - RAssign.new( - value: value || self.value, - operator: operator || self.operator, - pattern: pattern || self.pattern, - location: location || self.location - ) + node = + RAssign.new( + value: value || self.value, + operator: operator || self.operator, + pattern: pattern || self.pattern, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -3171,12 +3295,16 @@ def child_nodes end def copy(constant: nil, superclass: nil, bodystmt: nil, location: nil) - ClassDeclaration.new( - constant: constant || self.constant, - superclass: superclass || self.superclass, - bodystmt: bodystmt || self.bodystmt, - location: location || self.location - ) + node = + ClassDeclaration.new( + constant: constant || self.constant, + superclass: superclass || self.superclass, + bodystmt: bodystmt || self.bodystmt, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -3302,12 +3430,16 @@ def child_nodes end def copy(message: nil, arguments: nil, block: nil, location: nil) - Command.new( - message: message || self.message, - arguments: arguments || self.arguments, - block: block || self.block, - location: location || self.location - ) + node = + Command.new( + message: message || self.message, + arguments: arguments || self.arguments, + block: block || self.block, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -3401,8 +3533,7 @@ def initialize( message:, arguments:, block:, - location:, - comments: [] + location: ) @receiver = receiver @operator = operator @@ -3429,14 +3560,18 @@ def copy( block: nil, location: nil ) - CommandCall.new( - receiver: receiver || self.receiver, - operator: operator || self.operator, - message: message || self.message, - arguments: arguments || self.arguments, - block: block || self.block, - location: location || self.location - ) + node = + CommandCall.new( + receiver: receiver || self.receiver, + operator: operator || self.operator, + message: message || self.message, + arguments: arguments || self.arguments, + block: block || self.block, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -3636,7 +3771,14 @@ def child_nodes end def copy(value: nil, location: nil) - Const.new(value: value || self.value, location: location || self.location) + node = + Const.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -3686,11 +3828,15 @@ def child_nodes end def copy(parent: nil, constant: nil, location: nil) - ConstPathField.new( - parent: parent || self.parent, - constant: constant || self.constant, - location: location || self.location - ) + node = + ConstPathField.new( + parent: parent || self.parent, + constant: constant || self.constant, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -3746,11 +3892,15 @@ def child_nodes end def copy(parent: nil, constant: nil, location: nil) - ConstPathRef.new( - parent: parent || self.parent, - constant: constant || self.constant, - location: location || self.location - ) + node = + ConstPathRef.new( + parent: parent || self.parent, + constant: constant || self.constant, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -3804,10 +3954,14 @@ def child_nodes end def copy(constant: nil, location: nil) - ConstRef.new( - constant: constant || self.constant, - location: location || self.location - ) + node = + ConstRef.new( + constant: constant || self.constant, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -3851,7 +4005,14 @@ def child_nodes end def copy(value: nil, location: nil) - CVar.new(value: value || self.value, location: location || self.location) + node = + CVar.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -3919,14 +4080,18 @@ def copy( bodystmt: nil, location: nil ) - Def.new( - target: target || self.target, - operator: operator || self.operator, - name: name || self.name, - params: params || self.params, - bodystmt: bodystmt || self.bodystmt, - location: location || self.location - ) + node = + Def.new( + target: target || self.target, + operator: operator || self.operator, + name: name || self.name, + params: params || self.params, + bodystmt: bodystmt || self.bodystmt, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -4026,10 +4191,14 @@ def child_nodes end def copy(value: nil, location: nil) - Defined.new( - value: value || self.value, - location: location || self.location - ) + node = + Defined.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -4115,12 +4284,16 @@ def child_nodes end def copy(opening: nil, block_var: nil, bodystmt: nil, location: nil) - Block.new( - opening: opening || self.opening, - block_var: block_var || self.block_var, - bodystmt: bodystmt || self.bodystmt, - location: location || self.location - ) + node = + Block.new( + opening: opening || self.opening, + block_var: block_var || self.block_var, + bodystmt: bodystmt || self.bodystmt, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -4308,12 +4481,16 @@ def child_nodes end def copy(left: nil, operator: nil, right: nil, location: nil) - RangeLiteral.new( - left: left || self.left, - operator: operator || self.operator, - right: right || self.right, - location: location || self.location - ) + node = + RangeLiteral.new( + left: left || self.left, + operator: operator || self.operator, + right: right || self.right, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -4424,11 +4601,15 @@ def child_nodes end def copy(parts: nil, quote: nil, location: nil) - DynaSymbol.new( - parts: parts || self.parts, - quote: quote || self.quote, - location: location || self.location - ) + node = + DynaSymbol.new( + parts: parts || self.parts, + quote: quote || self.quote, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -4548,11 +4729,15 @@ def child_nodes end def copy(keyword: nil, statements: nil, location: nil) - Else.new( - keyword: keyword || self.keyword, - statements: statements || self.statements, - location: location || self.location - ) + node = + Else.new( + keyword: keyword || self.keyword, + statements: statements || self.statements, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -4604,13 +4789,7 @@ class Elsif < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize( - predicate:, - statements:, - consequent:, - location:, - comments: [] - ) + def initialize(predicate:, statements:, consequent:, location:) @predicate = predicate @statements = statements @consequent = consequent @@ -4627,12 +4806,16 @@ def child_nodes end def copy(predicate: nil, statements: nil, consequent: nil, location: nil) - Elsif.new( - predicate: predicate || self.predicate, - statements: statements || self.statements, - consequent: consequent || self.consequent, - location: location || self.location - ) + node = + Elsif.new( + predicate: predicate || self.predicate, + statements: statements || self.statements, + consequent: consequent || self.consequent, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -4893,11 +5076,15 @@ def child_nodes end def copy(keyword: nil, statements: nil, location: nil) - Ensure.new( - keyword: keyword || self.keyword, - statements: statements || self.statements, - location: location || self.location - ) + node = + Ensure.new( + keyword: keyword || self.keyword, + statements: statements || self.statements, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -4960,10 +5147,14 @@ def child_nodes end def copy(value: nil, location: nil) - ExcessedComma.new( - value: value || self.value, - location: location || self.location - ) + node = + ExcessedComma.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -5016,12 +5207,16 @@ def child_nodes end def copy(parent: nil, operator: nil, name: nil, location: nil) - Field.new( - parent: parent || self.parent, - operator: operator || self.operator, - name: name || self.name, - location: location || self.location - ) + node = + Field.new( + parent: parent || self.parent, + operator: operator || self.operator, + name: name || self.name, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -5076,10 +5271,14 @@ def child_nodes end def copy(value: nil, location: nil) - FloatLiteral.new( - value: value || self.value, - location: location || self.location - ) + node = + FloatLiteral.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -5139,13 +5338,17 @@ def child_nodes end def copy(constant: nil, left: nil, values: nil, right: nil, location: nil) - FndPtn.new( - constant: constant || self.constant, - left: left || self.left, - values: values || self.values, - right: right || self.right, - location: location || self.location - ) + node = + FndPtn.new( + constant: constant || self.constant, + left: left || self.left, + values: values || self.values, + right: right || self.right, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -5229,12 +5432,16 @@ def child_nodes end def copy(index: nil, collection: nil, statements: nil, location: nil) - For.new( - index: index || self.index, - collection: collection || self.collection, - statements: statements || self.statements, - location: location || self.location - ) + node = + For.new( + index: index || self.index, + collection: collection || self.collection, + statements: statements || self.statements, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -5300,7 +5507,14 @@ def child_nodes end def copy(value: nil, location: nil) - GVar.new(value: value || self.value, location: location || self.location) + node = + GVar.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -5374,11 +5588,15 @@ def child_nodes end def copy(lbrace: nil, assocs: nil, location: nil) - HashLiteral.new( - lbrace: lbrace || self.lbrace, - assocs: assocs || self.assocs, - location: location || self.location - ) + node = + HashLiteral.new( + lbrace: lbrace || self.lbrace, + assocs: assocs || self.assocs, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -5458,14 +5676,7 @@ class Heredoc < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize( - beginning:, - ending: nil, - dedent: 0, - parts: [], - location:, - comments: [] - ) + def initialize(beginning:, ending: nil, dedent: 0, parts: [], location:) @beginning = beginning @ending = ending @dedent = dedent @@ -5483,12 +5694,16 @@ def child_nodes end def copy(beginning: nil, location: nil, ending: nil, parts: nil) - Heredoc.new( - beginning: beginning || self.beginning, - location: location || self.location, - ending: ending || self.ending, - parts: parts || self.parts - ) + node = + Heredoc.new( + beginning: beginning || self.beginning, + location: location || self.location, + ending: ending || self.ending, + parts: parts || self.parts + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -5577,10 +5792,14 @@ def child_nodes end def copy(value: nil, location: nil) - HeredocBeg.new( - value: value || self.value, - location: location || self.location - ) + node = + HeredocBeg.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -5627,10 +5846,14 @@ def child_nodes end def copy(value: nil, location: nil) - HeredocEnd.new( - value: value || self.value, - location: location || self.location - ) + node = + HeredocEnd.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -5732,12 +5955,16 @@ def child_nodes end def copy(constant: nil, keywords: nil, keyword_rest: nil, location: nil) - HshPtn.new( - constant: constant || self.constant, - keywords: keywords || self.keywords, - keyword_rest: keyword_rest || self.keyword_rest, - location: location || self.location - ) + node = + HshPtn.new( + constant: constant || self.constant, + keywords: keywords || self.keywords, + keyword_rest: keyword_rest || self.keyword_rest, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -5858,7 +6085,14 @@ def child_nodes end def copy(value: nil, location: nil) - Ident.new(value: value || self.value, location: location || self.location) + node = + Ident.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -6131,13 +6365,7 @@ class If < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize( - predicate:, - statements:, - consequent:, - location:, - comments: [] - ) + def initialize(predicate:, statements:, consequent:, location:) @predicate = predicate @statements = statements @consequent = consequent @@ -6154,12 +6382,16 @@ def child_nodes end def copy(predicate: nil, statements: nil, consequent: nil, location: nil) - If.new( - predicate: predicate || self.predicate, - statements: statements || self.statements, - consequent: consequent || self.consequent, - location: location || self.location - ) + node = + If.new( + predicate: predicate || self.predicate, + statements: statements || self.statements, + consequent: consequent || self.consequent, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -6223,12 +6455,16 @@ def child_nodes end def copy(predicate: nil, truthy: nil, falsy: nil, location: nil) - IfOp.new( - predicate: predicate || self.predicate, - truthy: truthy || self.truthy, - falsy: falsy || self.falsy, - location: location || self.location - ) + node = + IfOp.new( + predicate: predicate || self.predicate, + truthy: truthy || self.truthy, + falsy: falsy || self.falsy, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -6330,10 +6566,14 @@ def child_nodes end def copy(value: nil, location: nil) - Imaginary.new( - value: value || self.value, - location: location || self.location - ) + node = + Imaginary.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -6388,12 +6628,16 @@ def child_nodes end def copy(pattern: nil, statements: nil, consequent: nil, location: nil) - In.new( - pattern: pattern || self.pattern, - statements: statements || self.statements, - consequent: consequent || self.consequent, - location: location || self.location - ) + node = + In.new( + pattern: pattern || self.pattern, + statements: statements || self.statements, + consequent: consequent || self.consequent, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -6461,7 +6705,11 @@ def child_nodes end def copy(value: nil, location: nil) - Int.new(value: value || self.value, location: location || self.location) + node = + Int.new(value: value || self.value, location: location || self.location) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -6513,7 +6761,14 @@ def child_nodes end def copy(value: nil, location: nil) - IVar.new(value: value || self.value, location: location || self.location) + node = + IVar.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -6570,7 +6825,11 @@ def child_nodes end def copy(value: nil, location: nil) - Kw.new(value: value || self.value, location: location || self.location) + node = + Kw.new(value: value || self.value, location: location || self.location) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -6615,10 +6874,14 @@ def child_nodes end def copy(name: nil, location: nil) - KwRestParam.new( - name: name || self.name, - location: location || self.location - ) + node = + KwRestParam.new( + name: name || self.name, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -6672,7 +6935,14 @@ def child_nodes end def copy(value: nil, location: nil) - Label.new(value: value || self.value, location: location || self.location) + node = + Label.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -6762,11 +7032,15 @@ def child_nodes end def copy(params: nil, statements: nil, location: nil) - Lambda.new( - params: params || self.params, - statements: statements || self.statements, - location: location || self.location - ) + node = + Lambda.new( + params: params || self.params, + statements: statements || self.statements, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -6883,11 +7157,15 @@ def child_nodes end def copy(params: nil, locals: nil, location: nil) - LambdaVar.new( - params: params || self.params, - locals: locals || self.locals, - location: location || self.location - ) + node = + LambdaVar.new( + params: params || self.params, + locals: locals || self.locals, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -6938,10 +7216,14 @@ def child_nodes end def copy(value: nil, location: nil) - LBrace.new( - value: value || self.value, - location: location || self.location - ) + node = + LBrace.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -6982,10 +7264,14 @@ def child_nodes end def copy(value: nil, location: nil) - LBracket.new( - value: value || self.value, - location: location || self.location - ) + node = + LBracket.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -7026,10 +7312,14 @@ def child_nodes end def copy(value: nil, location: nil) - LParen.new( - value: value || self.value, - location: location || self.location - ) + node = + LParen.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -7087,11 +7377,15 @@ def child_nodes end def copy(target: nil, value: nil, location: nil) - MAssign.new( - target: target || self.target, - value: value || self.value, - location: location || self.location - ) + node = + MAssign.new( + target: target || self.target, + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -7146,11 +7440,15 @@ def child_nodes end def copy(call: nil, block: nil, location: nil) - MethodAddBlock.new( - call: call || self.call, - block: block || self.block, - location: location || self.location - ) + node = + MethodAddBlock.new( + call: call || self.call, + block: block || self.block, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -7220,11 +7518,15 @@ def child_nodes end def copy(parts: nil, location: nil, comma: nil) - MLHS.new( - parts: parts || self.parts, - location: location || self.location, - comma: comma || self.comma - ) + node = + MLHS.new( + parts: parts || self.parts, + location: location || self.location, + comma: comma || self.comma + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -7277,10 +7579,14 @@ def child_nodes end def copy(contents: nil, location: nil) - MLHSParen.new( - contents: contents || self.contents, - location: location || self.location - ) + node = + MLHSParen.new( + contents: contents || self.contents, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -7346,11 +7652,15 @@ def child_nodes end def copy(constant: nil, bodystmt: nil, location: nil) - ModuleDeclaration.new( - constant: constant || self.constant, - bodystmt: bodystmt || self.bodystmt, - location: location || self.location - ) + node = + ModuleDeclaration.new( + constant: constant || self.constant, + bodystmt: bodystmt || self.bodystmt, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -7428,7 +7738,14 @@ def child_nodes end def copy(parts: nil, location: nil) - MRHS.new(parts: parts || self.parts, location: location || self.location) + node = + MRHS.new( + parts: parts || self.parts, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -7485,10 +7802,14 @@ def child_nodes end def copy(arguments: nil, location: nil) - Next.new( - arguments: arguments || self.arguments, - location: location || self.location - ) + node = + Next.new( + arguments: arguments || self.arguments, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -7537,7 +7858,11 @@ def child_nodes end def copy(value: nil, location: nil) - Op.new(value: value || self.value, location: location || self.location) + node = + Op.new(value: value || self.value, location: location || self.location) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -7591,12 +7916,16 @@ def child_nodes end def copy(target: nil, operator: nil, value: nil, location: nil) - OpAssign.new( - target: target || self.target, - operator: operator || self.operator, - value: value || self.value, - location: location || self.location - ) + node = + OpAssign.new( + target: target || self.target, + operator: operator || self.operator, + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -7823,8 +8152,7 @@ def initialize( keywords: [], keyword_rest: nil, block: nil, - location:, - comments: [] + location: ) @requireds = requireds @optionals = optionals @@ -7872,16 +8200,20 @@ def copy( keyword_rest: nil, block: nil ) - Params.new( - location: location || self.location, - requireds: requireds || self.requireds, - optionals: optionals || self.optionals, - rest: rest || self.rest, - posts: posts || self.posts, - keywords: keywords || self.keywords, - keyword_rest: keyword_rest || self.keyword_rest, - block: block || self.block - ) + node = + Params.new( + location: location || self.location, + requireds: requireds || self.requireds, + optionals: optionals || self.optionals, + rest: rest || self.rest, + posts: posts || self.posts, + keywords: keywords || self.keywords, + keyword_rest: keyword_rest || self.keyword_rest, + block: block || self.block + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -7991,11 +8323,15 @@ def child_nodes end def copy(lparen: nil, contents: nil, location: nil) - Paren.new( - lparen: lparen || self.lparen, - contents: contents || self.contents, - location: location || self.location - ) + node = + Paren.new( + lparen: lparen || self.lparen, + contents: contents || self.contents, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -8055,10 +8391,14 @@ def child_nodes end def copy(value: nil, location: nil) - Period.new( - value: value || self.value, - location: location || self.location - ) + node = + Period.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -8099,10 +8439,14 @@ def child_nodes end def copy(statements: nil, location: nil) - Program.new( - statements: statements || self.statements, - location: location || self.location - ) + node = + Program.new( + statements: statements || self.statements, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -8155,11 +8499,15 @@ def child_nodes end def copy(beginning: nil, elements: nil, location: nil) - QSymbols.new( - beginning: beginning || self.beginning, - elements: elements || self.elements, - location: location || self.location - ) + node = + QSymbols.new( + beginning: beginning || self.beginning, + elements: elements || self.elements, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -8387,10 +8735,14 @@ def child_nodes end def copy(value: nil, location: nil) - RationalLiteral.new( - value: value || self.value, - location: location || self.location - ) + node = + RationalLiteral.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -8502,7 +8854,10 @@ def child_nodes end def copy(location: nil) - Redo.new(location: location || self.location) + node = Redo.new(location: location || self.location) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -8692,12 +9047,16 @@ def child_nodes end def copy(beginning: nil, ending: nil, parts: nil, location: nil) - RegexpLiteral.new( - beginning: beginning || self.beginning, - ending: ending || self.ending, - parts: parts || self.parts, - location: location || self.location - ) + node = + RegexpLiteral.new( + beginning: beginning || self.beginning, + ending: ending || self.ending, + parts: parts || self.parts, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -8817,11 +9176,15 @@ def child_nodes end def copy(exceptions: nil, variable: nil, location: nil) - RescueEx.new( - exceptions: exceptions || self.exceptions, - variable: variable || self.variable, - location: location || self.location - ) + node = + RescueEx.new( + exceptions: exceptions || self.exceptions, + variable: variable || self.variable, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -8877,14 +9240,7 @@ class Rescue < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize( - keyword:, - exception:, - statements:, - consequent:, - location:, - comments: [] - ) + def initialize(keyword:, exception:, statements:, consequent:, location:) @keyword = keyword @exception = exception @statements = statements @@ -8930,13 +9286,17 @@ def copy( consequent: nil, location: nil ) - Rescue.new( - keyword: keyword || self.keyword, - exception: exception || self.exception, - statements: statements || self.statements, - consequent: consequent || self.consequent, - location: location || self.location - ) + node = + Rescue.new( + keyword: keyword || self.keyword, + exception: exception || self.exception, + statements: statements || self.statements, + consequent: consequent || self.consequent, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -9013,11 +9373,15 @@ def child_nodes end def copy(statement: nil, value: nil, location: nil) - RescueMod.new( - statement: statement || self.statement, - value: value || self.value, - location: location || self.location - ) + node = + RescueMod.new( + statement: statement || self.statement, + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -9082,10 +9446,14 @@ def child_nodes end def copy(name: nil, location: nil) - RestParam.new( - name: name || self.name, - location: location || self.location - ) + node = + RestParam.new( + name: name || self.name, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -9126,7 +9494,10 @@ def child_nodes end def copy(location: nil) - Retry.new(location: location || self.location) + node = Retry.new(location: location || self.location) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -9170,10 +9541,14 @@ def child_nodes end def copy(arguments: nil, location: nil) - Return.new( - arguments: arguments || self.arguments, - location: location || self.location - ) + node = + Return.new( + arguments: arguments || self.arguments, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -9260,11 +9635,15 @@ def child_nodes end def copy(target: nil, bodystmt: nil, location: nil) - SClass.new( - target: target || self.target, - bodystmt: bodystmt || self.bodystmt, - location: location || self.location - ) + node = + SClass.new( + target: target || self.target, + bodystmt: bodystmt || self.bodystmt, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -9377,11 +9756,15 @@ def child_nodes end def copy(body: nil, location: nil) - Statements.new( - parser, - body: body || self.body, - location: location || self.location - ) + node = + Statements.new( + parser, + body: body || self.body, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -9557,11 +9940,15 @@ def child_nodes end def copy(left: nil, right: nil, location: nil) - StringConcat.new( - left: left || self.left, - right: right || self.right, - location: location || self.location - ) + node = + StringConcat.new( + left: left || self.left, + right: right || self.right, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -9614,10 +10001,14 @@ def child_nodes end def copy(variable: nil, location: nil) - StringDVar.new( - variable: variable || self.variable, - location: location || self.location - ) + node = + StringDVar.new( + variable: variable || self.variable, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -9665,10 +10056,14 @@ def child_nodes end def copy(statements: nil, location: nil) - StringEmbExpr.new( - statements: statements || self.statements, - location: location || self.location - ) + node = + StringEmbExpr.new( + statements: statements || self.statements, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -9739,11 +10134,15 @@ def child_nodes end def copy(parts: nil, quote: nil, location: nil) - StringLiteral.new( - parts: parts || self.parts, - quote: quote || self.quote, - location: location || self.location - ) + node = + StringLiteral.new( + parts: parts || self.parts, + quote: quote || self.quote, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -9826,10 +10225,14 @@ def child_nodes end def copy(arguments: nil, location: nil) - Super.new( - arguments: arguments || self.arguments, - location: location || self.location - ) + node = + Super.new( + arguments: arguments || self.arguments, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -9976,10 +10379,14 @@ def child_nodes end def copy(value: nil, location: nil) - SymbolLiteral.new( - value: value || self.value, - location: location || self.location - ) + node = + SymbolLiteral.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -10226,10 +10633,14 @@ def child_nodes end def copy(constant: nil, location: nil) - TopConstField.new( - constant: constant || self.constant, - location: location || self.location - ) + node = + TopConstField.new( + constant: constant || self.constant, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -10275,10 +10686,14 @@ def child_nodes end def copy(constant: nil, location: nil) - TopConstRef.new( - constant: constant || self.constant, - location: location || self.location - ) + node = + TopConstRef.new( + constant: constant || self.constant, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -10376,10 +10791,14 @@ def child_nodes end def copy(value: nil, location: nil) - TStringContent.new( - value: value || self.value, - location: location || self.location - ) + node = + TStringContent.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -10473,11 +10892,15 @@ def child_nodes end def copy(statement: nil, parentheses: nil, location: nil) - Not.new( - statement: statement || self.statement, - parentheses: parentheses || self.parentheses, - location: location || self.location - ) + node = + Not.new( + statement: statement || self.statement, + parentheses: parentheses || self.parentheses, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -10552,11 +10975,15 @@ def child_nodes end def copy(operator: nil, statement: nil, location: nil) - Unary.new( - operator: operator || self.operator, - statement: statement || self.statement, - location: location || self.location - ) + node = + Unary.new( + operator: operator || self.operator, + statement: statement || self.statement, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -10631,10 +11058,14 @@ def child_nodes end def copy(symbols: nil, location: nil) - Undef.new( - symbols: symbols || self.symbols, - location: location || self.location - ) + node = + Undef.new( + symbols: symbols || self.symbols, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -10678,13 +11109,7 @@ class Unless < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize( - predicate:, - statements:, - consequent:, - location:, - comments: [] - ) + def initialize(predicate:, statements:, consequent:, location:) @predicate = predicate @statements = statements @consequent = consequent @@ -10701,12 +11126,16 @@ def child_nodes end def copy(predicate: nil, statements: nil, consequent: nil, location: nil) - Unless.new( - predicate: predicate || self.predicate, - statements: statements || self.statements, - consequent: consequent || self.consequent, - location: location || self.location - ) + node = + Unless.new( + predicate: predicate || self.predicate, + statements: statements || self.statements, + consequent: consequent || self.consequent, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -10839,11 +11268,15 @@ def child_nodes end def copy(predicate: nil, statements: nil, location: nil) - Until.new( - predicate: predicate || self.predicate, - statements: statements || self.statements, - location: location || self.location - ) + node = + Until.new( + predicate: predicate || self.predicate, + statements: statements || self.statements, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -10899,10 +11332,14 @@ def child_nodes end def copy(value: nil, location: nil) - VarField.new( - value: value || self.value, - location: location || self.location - ) + node = + VarField.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -10954,10 +11391,14 @@ def child_nodes end def copy(value: nil, location: nil) - VarRef.new( - value: value || self.value, - location: location || self.location - ) + node = + VarRef.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -11029,10 +11470,14 @@ def child_nodes end def copy(value: nil, location: nil) - PinnedVarRef.new( - value: value || self.value, - location: location || self.location - ) + node = + PinnedVarRef.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -11080,7 +11525,14 @@ def child_nodes end def copy(value: nil, location: nil) - VCall.new(value: value || self.value, location: location || self.location) + node = + VCall.new( + value: value || self.value, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -11127,7 +11579,10 @@ def child_nodes end def copy(location: nil) - VoidStmt.new(location: location || self.location) + node = VoidStmt.new(location: location || self.location) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -11163,13 +11618,7 @@ class When < Node # [Array[ Comment | EmbDoc ]] the comments attached to this node attr_reader :comments - def initialize( - arguments:, - statements:, - consequent:, - location:, - comments: [] - ) + def initialize(arguments:, statements:, consequent:, location:) @arguments = arguments @statements = statements @consequent = consequent @@ -11186,12 +11635,16 @@ def child_nodes end def copy(arguments: nil, statements: nil, consequent: nil, location: nil) - When.new( - arguments: arguments || self.arguments, - statements: statements || self.statements, - consequent: consequent || self.consequent, - location: location || self.location - ) + node = + When.new( + arguments: arguments || self.arguments, + statements: statements || self.statements, + consequent: consequent || self.consequent, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -11294,11 +11747,15 @@ def child_nodes end def copy(predicate: nil, statements: nil, location: nil) - While.new( - predicate: predicate || self.predicate, - statements: statements || self.statements, - location: location || self.location - ) + node = + While.new( + predicate: predicate || self.predicate, + statements: statements || self.statements, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -11360,7 +11817,14 @@ def child_nodes end def copy(parts: nil, location: nil) - Word.new(parts: parts || self.parts, location: location || self.location) + node = + Word.new( + parts: parts || self.parts, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -11564,10 +12028,14 @@ def child_nodes end def copy(parts: nil, location: nil) - XStringLiteral.new( - parts: parts || self.parts, - location: location || self.location - ) + node = + XStringLiteral.new( + parts: parts || self.parts, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -11613,10 +12081,14 @@ def child_nodes end def copy(arguments: nil, location: nil) - Yield.new( - arguments: arguments || self.arguments, - location: location || self.location - ) + node = + Yield.new( + arguments: arguments || self.arguments, + location: location || self.location + ) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes @@ -11675,7 +12147,10 @@ def child_nodes end def copy(location: nil) - ZSuper.new(location: location || self.location) + node = ZSuper.new(location: location || self.location) + + node.comments.concat(comments.map(&:copy)) + node end alias deconstruct child_nodes diff --git a/lib/syntax_tree/visitor/mutation_visitor.rb b/lib/syntax_tree/visitor/mutation_visitor.rb index 8b7f187b..6ad7feef 100644 --- a/lib/syntax_tree/visitor/mutation_visitor.rb +++ b/lib/syntax_tree/visitor/mutation_visitor.rb @@ -24,7 +24,7 @@ def visit(node) stack.pop result end - + # This is a small helper to visit an array of nodes and return the result # of visiting them all. def visit_all(nodes) From 648145396c968f300d75eb51b6ae4168220df7f5 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Tue, 8 Nov 2022 15:03:16 -0500 Subject: [PATCH 26/35] Final tests, documentation, changelog for mutations --- CHANGELOG.md | 6 ++ README.md | 70 +++++++++++++++++++++ lib/syntax_tree.rb | 7 +++ lib/syntax_tree/node.rb | 30 +++++++++ lib/syntax_tree/visitor/mutation_visitor.rb | 45 ++++++++----- test/mutation_test.rb | 47 ++++++++++++++ 6 files changed, 188 insertions(+), 17 deletions(-) create mode 100644 test/mutation_test.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 642e7866..d8a848f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ## [Unreleased] +### Added + +- Every node now implements the `#copy(**)` method, which provides a copy of the node with the given attributes replaced. +- Every node now implements the `#===(other)` method, which checks if the given node matches the current node for all attributes except for comments and location. +- There is a new `SyntaxTree::Visitor::MutationVisitor` and its convenience method `SyntaxTree.mutation` which can be used to mutate a syntax tree. For details on how to use this visitor, check the README. + ### Changed - Nodes no longer have a `comments:` keyword on their initializers. By default, they initialize to an empty array. If you were previously passing comments into the initializer, you should now create the node first, then call `node.comments.concat` to add your comments. diff --git a/README.md b/README.md index 368c9361..2bd333ae 100644 --- a/README.md +++ b/README.md @@ -27,17 +27,21 @@ It is built with only standard library dependencies. It additionally ships with - [SyntaxTree.read(filepath)](#syntaxtreereadfilepath) - [SyntaxTree.parse(source)](#syntaxtreeparsesource) - [SyntaxTree.format(source)](#syntaxtreeformatsource) + - [SyntaxTree.mutation(&block)](#syntaxtreemutationblock) - [SyntaxTree.search(source, query, &block)](#syntaxtreesearchsource-query-block) - [Nodes](#nodes) - [child_nodes](#child_nodes) + - [copy(**)](#copy) - [Pattern matching](#pattern-matching) - [pretty_print(q)](#pretty_printq) - [to_json(*opts)](#to_jsonopts) - [format(q)](#formatq) + - [===(other)](#other) - [construct_keys](#construct_keys) - [Visitor](#visitor) - [visit_method](#visit_method) - [BasicVisitor](#basicvisitor) + - [MutationVisitor](#mutationvisitor) - [Language server](#language-server) - [textDocument/formatting](#textdocumentformatting) - [textDocument/inlayHint](#textdocumentinlayhint) @@ -332,6 +336,10 @@ This function takes an input string containing Ruby code and returns the syntax This function takes an input string containing Ruby code, parses it into its underlying syntax tree, and formats it back out to a string. You can optionally pass a second argument to this method as well that is the maximum width to print. It defaults to `80`. +### SyntaxTree.mutation(&block) + +This function yields a new mutation visitor to the block, and then returns the initialized visitor. It's effectively a shortcut for creating a `SyntaxTree::Visitor::MutationVisitor` without having to remember the class name. For more information on that visitor, see the definition below. + ### SyntaxTree.search(source, query, &block) This function takes an input string containing Ruby code, an input string containing a valid Ruby `in` clause expression that can be used to match against nodes in the tree (can be generated using `stree expr`, `stree match`, or `Node#construct_keys`), and a block. Each node that matches the given query will be yielded to the block. The block will receive the node as its only argument. @@ -350,6 +358,20 @@ program.child_nodes.first.child_nodes.first # => (binary (int "1") :+ (int "1")) ``` +### copy + +This method returns a copy of the node, with the given attributes replaced. + +```ruby +program = SyntaxTree.parse("1 + 1") + +binary = program.statements.body.first +# => (binary (int "1") + (int "1")) + +binary.copy(operator: :-) +# => (binary (int "1") - (int "1")) +``` + ### Pattern matching Pattern matching is another way to descend the tree which is more specific than using `child_nodes`. Using Ruby's built-in pattern matching, you can extract the same information but be as specific about your constraints as you like. For example, with minimal constraints: @@ -407,6 +429,18 @@ formatter.output.join # => "1 + 1" ``` +### ===(other) + +Every node responds to `===`, which is used to check if the given other node matches all of the attributes of the current node except for location and comments. For example: + +```ruby +program1 = SyntaxTree.parse("1 + 1") +program2 = SyntaxTree.parse("1 + 1") + +program1 === program2 +# => true +``` + ### construct_keys Every node responds to `construct_keys`, which will return a string that contains a Ruby pattern-matching expression that could be used to match against the current node. It's meant to be used in tooling and through the CLI mostly. @@ -495,6 +529,42 @@ end The visitor defined above will error out unless it's only visiting a `SyntaxTree::Int` node. This is useful in a couple of ways, e.g., if you're trying to define a visitor to handle the whole tree but it's currently a work-in-progress. +### MutationVisitor + +The `MutationVisitor` is a visitor that can be used to mutate the tree. It works by defining a default `visit_*` method that returns a copy of the given node with all of its attributes visited. This new node will replace the old node in the tree. Typically, you use the `#mutate` method on it to define mutations using patterns. For example: + +```ruby +# Create a new visitor +visitor = SyntaxTree::Visitor::MutationVisitor.new + +# Specify that it should mutate If nodes with assignments in their predicates +visitor.mutate("If[predicate: Assign | OpAssign]") do |node| + # Get the existing If's predicate node + predicate = node.predicate + + # Create a new predicate node that wraps the existing predicate node + # in parentheses + predicate = + SyntaxTree::Paren.new( + lparen: SyntaxTree::LParen.default, + contents: predicate, + location: predicate.location + ) + + # Return a copy of this node with the new predicate + node.copy(predicate: predicate) +end + +source = "if a = 1; end" +program = SyntaxTree.parse(source) + +SyntaxTree::Formatter.format(source, program) +# => "if a = 1\nend\n" + +SyntaxTree::Formatter.format(source, program.accept(visitor)) +# => "if (a = 1)\nend\n" +``` + ### WithEnvironment The `WithEnvironment` module can be included in visitors to automatically keep track of local variables and arguments diff --git a/lib/syntax_tree.rb b/lib/syntax_tree.rb index 5808cd15..aff4404c 100644 --- a/lib/syntax_tree.rb +++ b/lib/syntax_tree.rb @@ -62,6 +62,13 @@ def self.format(source, maxwidth = DEFAULT_PRINT_WIDTH) formatter.output.join end + # A convenience method for creating a new mutation visitor. + def self.mutation + visitor = Visitor::MutationVisitor.new + yield visitor + visitor + end + # Returns the source from the given filepath taking into account any potential # magic encoding comments. def self.read(filepath) diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index 219c0de1..639eb7be 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -84,6 +84,9 @@ def self.fixed(line:, char:, column:) ) end + # A convenience method that is typically used when you don't care about the + # location of a node, but need to create a Location instance to pass to a + # constructor. def self.default new( start_line: 1, @@ -7239,6 +7242,15 @@ def format(q) def ===(other) other.is_a?(LBrace) && value === other.value end + + # Because some nodes keep around a { token so that comments can be attached + # to it if they occur in the source, oftentimes an LBrace is a child of + # another node. This means it's required at initialization time. To make it + # easier to create LBrace nodes without any specific value, this method + # provides a default node. + def self.default + new(value: "{", location: Location.default) + end end # LBracket represents the use of a left bracket, i.e., [. @@ -7287,6 +7299,15 @@ def format(q) def ===(other) other.is_a?(LBracket) && value === other.value end + + # Because some nodes keep around a [ token so that comments can be attached + # to it if they occur in the source, oftentimes an LBracket is a child of + # another node. This means it's required at initialization time. To make it + # easier to create LBracket nodes without any specific value, this method + # provides a default node. + def self.default + new(value: "[", location: Location.default) + end end # LParen represents the use of a left parenthesis, i.e., (. @@ -7335,6 +7356,15 @@ def format(q) def ===(other) other.is_a?(LParen) && value === other.value end + + # Because some nodes keep around a ( token so that comments can be attached + # to it if they occur in the source, oftentimes an LParen is a child of + # another node. This means it's required at initialization time. To make it + # easier to create LParen nodes without any specific value, this method + # provides a default node. + def self.default + new(value: "(", location: Location.default) + end end # MAssign is a parent node of any kind of multiple assignment. This includes diff --git a/lib/syntax_tree/visitor/mutation_visitor.rb b/lib/syntax_tree/visitor/mutation_visitor.rb index 6ad7feef..6e7d4ff2 100644 --- a/lib/syntax_tree/visitor/mutation_visitor.rb +++ b/lib/syntax_tree/visitor/mutation_visitor.rb @@ -5,30 +5,33 @@ class Visitor # This visitor walks through the tree and copies each node as it is being # visited. This is useful for mutating the tree before it is formatted. class MutationVisitor < BasicVisitor - # Here we maintain a stack of parent nodes so that it's easy to reflect on - # the context of a given node while mutating it. - attr_reader :stack + attr_reader :mutations def initialize - @stack = [] + @mutations = [] end - # This is the main entrypoint that's going to be called when we're - # recursing down through the tree. + # Create a new mutation based on the given query that will mutate the node + # using the given block. The block should return a new node that will take + # the place of the given node in the tree. These blocks frequently make + # use of the `copy` method on nodes to create a new node with the same + # properties as the original node. + def mutate(query, &block) + mutations << [Pattern.new(query).compile, block] + end + + # This is the base visit method for each node in the tree. It first + # creates a copy of the node using the visit_* methods defined below. Then + # it checks each mutation in sequence and calls it if it finds a match. def visit(node) return unless node - - stack << node result = node.accept(self) - stack.pop - result - end + mutations.each do |(pattern, mutation)| + result = mutation.call(result) if pattern.call(result) + end - # This is a small helper to visit an array of nodes and return the result - # of visiting them all. - def visit_all(nodes) - nodes.map { |node| visit(node) } + result end # Visit a BEGINBlock node. @@ -435,6 +438,7 @@ def visit_ident(node) # Visit a If node. def visit_if(node) node.copy( + predicate: visit(node.predicate), statements: visit(node.statements), consequent: visit(node.consequent) ) @@ -822,6 +826,7 @@ def visit_undef(node) # Visit a Unless node. def visit_unless(node) node.copy( + predicate: visit(node.predicate), statements: visit(node.statements), consequent: visit(node.consequent) ) @@ -829,7 +834,10 @@ def visit_unless(node) # Visit a Until node. def visit_until(node) - node.copy(statements: visit(node.statements)) + node.copy( + predicate: visit(node.predicate), + statements: visit(node.statements) + ) end # Visit a VarField node. @@ -868,7 +876,10 @@ def visit_when(node) # Visit a While node. def visit_while(node) - node.copy(statements: visit(node.statements)) + node.copy( + predicate: visit(node.predicate), + statements: visit(node.statements) + ) end # Visit a Word node. diff --git a/test/mutation_test.rb b/test/mutation_test.rb new file mode 100644 index 00000000..ab607beb --- /dev/null +++ b/test/mutation_test.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require_relative "test_helper" + +module SyntaxTree + class MutationTest < Minitest::Test + def test_mutates_based_on_patterns + source = <<~RUBY + if a = b + c + end + RUBY + + expected = <<~RUBY + if (a = b) + c + end + RUBY + + program = SyntaxTree.parse(source).accept(build_mutation) + assert_equal(expected, SyntaxTree::Formatter.format(source, program)) + end + + private + + def build_mutation + SyntaxTree.mutation do |mutation| + mutation.mutate("If[predicate: Assign | OpAssign]") do |node| + # Get the existing If's predicate node + predicate = node.predicate + + # Create a new predicate node that wraps the existing predicate node + # in parentheses + predicate = + SyntaxTree::Paren.new( + lparen: SyntaxTree::LParen.default, + contents: predicate, + location: predicate.location + ) + + # Return a copy of this node with the new predicate + node.copy(predicate: predicate) + end + end + end + end +end From 416e48147b4eb52fefb5a42103287f33bdee87b5 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Tue, 8 Nov 2022 15:10:03 -0500 Subject: [PATCH 27/35] Cleaner README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2bd333ae..e87ec765 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ It is built with only standard library dependencies. It additionally ships with - [SyntaxTree.search(source, query, &block)](#syntaxtreesearchsource-query-block) - [Nodes](#nodes) - [child_nodes](#child_nodes) - - [copy(**)](#copy) + - [copy(**attrs)](#copyattrs) - [Pattern matching](#pattern-matching) - [pretty_print(q)](#pretty_printq) - [to_json(*opts)](#to_jsonopts) @@ -358,7 +358,7 @@ program.child_nodes.first.child_nodes.first # => (binary (int "1") :+ (int "1")) ``` -### copy +### copy(**attrs) This method returns a copy of the node, with the given attributes replaced. From 52bed533a0b1377565c9a5b10fbe3ce87aff16ce Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Tue, 8 Nov 2022 16:41:43 -0500 Subject: [PATCH 28/35] Increase test coverage --- lib/syntax_tree/cli.rb | 12 ++-- lib/syntax_tree/pattern.rb | 6 +- lib/syntax_tree/visitor/environment.rb | 11 ++-- lib/syntax_tree/visitor/field_visitor.rb | 8 --- test/cli_test.rb | 66 +++++++++++++++++++- test/language_server_test.rb | 18 ++++++ test/rake_test.rb | 20 +++++- test/search_test.rb | 79 +++++++++++++++++++++--- test/test_helper.rb | 7 +-- test/visitor_with_environment_test.rb | 40 ++++++++++++ 10 files changed, 233 insertions(+), 34 deletions(-) diff --git a/lib/syntax_tree/cli.rb b/lib/syntax_tree/cli.rb index 62e8ab68..11c93537 100644 --- a/lib/syntax_tree/cli.rb +++ b/lib/syntax_tree/cli.rb @@ -497,10 +497,14 @@ def run(argv) Dir .glob(pattern) .each do |filepath| - if File.readable?(filepath) && - options.ignore_files.none? { File.fnmatch?(_1, filepath) } - queue << FileItem.new(filepath) - end + # Skip past invalid filepaths by default. + next unless File.readable?(filepath) + + # Skip past any ignored filepaths. + next if options.ignore_files.any? { File.fnmatch(_1, filepath) } + + # Otherwise, a new file item for the given filepath to the list. + queue << FileItem.new(filepath) end end diff --git a/lib/syntax_tree/pattern.rb b/lib/syntax_tree/pattern.rb index 439d573f..ca49c6bf 100644 --- a/lib/syntax_tree/pattern.rb +++ b/lib/syntax_tree/pattern.rb @@ -142,11 +142,11 @@ def compile_binary(node) def compile_const(node) value = node.value - if SyntaxTree.const_defined?(value) + if SyntaxTree.const_defined?(value, false) clazz = SyntaxTree.const_get(value) ->(other) { clazz === other } - elsif Object.const_defined?(value) + elsif Object.const_defined?(value, false) clazz = Object.const_get(value) ->(other) { clazz === other } @@ -179,7 +179,7 @@ def compile_dyna_symbol(node) ->(other) { symbol === other } else - compile_error(root) + compile_error(node) end end diff --git a/lib/syntax_tree/visitor/environment.rb b/lib/syntax_tree/visitor/environment.rb index dfcf0a80..b07a5203 100644 --- a/lib/syntax_tree/visitor/environment.rb +++ b/lib/syntax_tree/visitor/environment.rb @@ -4,10 +4,6 @@ module SyntaxTree # The environment class is used to keep track of local variables and arguments # inside a particular scope class Environment - # [Array[Local]] The local variables and arguments defined in this - # environment - attr_reader :locals - # This class tracks the occurrences of a local variable or argument class Local # [Symbol] The type of the local (e.g. :argument, :variable) @@ -38,6 +34,13 @@ def add_usage(location) end end + # [Array[Local]] The local variables and arguments defined in this + # environment + attr_reader :locals + + # [Environment | nil] The parent environment + attr_reader :parent + # initialize: (Environment | nil parent) -> void def initialize(parent = nil) @locals = {} diff --git a/lib/syntax_tree/visitor/field_visitor.rb b/lib/syntax_tree/visitor/field_visitor.rb index 01c7de4e..b56d771c 100644 --- a/lib/syntax_tree/visitor/field_visitor.rb +++ b/lib/syntax_tree/visitor/field_visitor.rb @@ -388,14 +388,6 @@ def visit_excessed_comma(node) visit_token(node, "excessed_comma") end - def visit_fcall(node) - node(node, "fcall") do - field("value", node.value) - field("arguments", node.arguments) if node.arguments - comments(node) - end - end - def visit_field(node) node(node, "field") do field("parent", node.parent) diff --git a/test/cli_test.rb b/test/cli_test.rb index b4ef0afc..9740806d 100644 --- a/test/cli_test.rb +++ b/test/cli_test.rb @@ -41,6 +41,7 @@ def test_ast_ignore def test_ast_syntax_error result = run_cli("ast", contents: "foo\n<>\nbar\n") assert_includes(result.stderr, "syntax error") + refute_equal(0, result.status) end def test_check @@ -51,6 +52,7 @@ def test_check def test_check_unformatted result = run_cli("check", contents: "foo") assert_includes(result.stderr, "expected") + refute_equal(0, result.status) end def test_check_print_width @@ -59,6 +61,17 @@ def test_check_print_width assert_includes(result.stdio, "match") end + def test_check_target_ruby_version + previous = Formatter::OPTIONS[:target_ruby_version] + + begin + result = run_cli("check", "--target-ruby-version=2.6.0") + assert_includes(result.stdio, "match") + ensure + Formatter::OPTIONS[:target_ruby_version] = previous + end + end + def test_debug result = run_cli("debug") assert_includes(result.stdio, "idempotently") @@ -71,6 +84,7 @@ def test_debug_non_idempotent_format SyntaxTree.stub(:format, formatting) do result = run_cli("debug") assert_includes(result.stderr, "idempotently") + refute_equal(0, result.status) end end @@ -84,6 +98,12 @@ def test_expr assert_includes(result.stdio, "SyntaxTree::Ident") end + def test_expr_more_than_one + result = run_cli("expr", contents: "1; 2") + assert_includes(result.stderr, "single expression") + refute_equal(0, result.status) + end + def test_format result = run_cli("format") assert_equal("test\n", result.stdio) @@ -104,6 +124,17 @@ def test_search assert_equal(2, result.stdio.lines.length) end + def test_search_multi_line + result = run_cli("search", "Binary", contents: "1 +\n2") + assert_equal(1, result.stdio.lines.length) + end + + def test_search_invalid + result = run_cli("search", "FooBar") + assert_includes(result.stderr, "unable") + refute_equal(0, result.status) + end + def test_version result = run_cli("version") assert_includes(result.stdio, SyntaxTree::VERSION.to_s) @@ -120,6 +151,29 @@ def test_write def test_write_syntax_tree result = run_cli("write", contents: "<>") assert_includes(result.stderr, "syntax error") + refute_equal(0, result.status) + end + + def test_write_script + args = ["write", "-e", "1 + 2"] + stdout, stderr = capture_io { SyntaxTree::CLI.run(args) } + + assert_includes stdout, "script" + assert_empty stderr + end + + def test_write_stdin + previous = $stdin + $stdin = StringIO.new("1 + 2") + + begin + stdout, stderr = capture_io { SyntaxTree::CLI.run(["write"]) } + + assert_includes stdout, "stdin" + assert_empty stderr + ensure + $stdin = previous + end end def test_help @@ -128,8 +182,10 @@ def test_help end def test_help_default - *, stderr = capture_io { SyntaxTree::CLI.run(["foobar"]) } + status = 0 + *, stderr = capture_io { status = SyntaxTree::CLI.run(["foobar"]) } assert_includes(stderr, "stree help") + refute_equal(0, status) end def test_no_arguments @@ -215,6 +271,7 @@ def test_print_width_args_with_config_file_override result = run_cli("check", "--print-width=82", contents: contents) assert_includes(result.stderr, "expected") + refute_equal(0, result.status) end end @@ -251,7 +308,12 @@ def run_cli(command, *args, contents: :default) status = nil stdio, stderr = capture_io do - status = SyntaxTree::CLI.run([command, *args, tempfile.path]) + status = + begin + SyntaxTree::CLI.run([command, *args, tempfile.path]) + rescue SystemExit => error + error.status + end end Result.new(status: status, stdio: stdio, stderr: stderr) diff --git a/test/language_server_test.rb b/test/language_server_test.rb index 8e1ed9a7..2fe4e60a 100644 --- a/test/language_server_test.rb +++ b/test/language_server_test.rb @@ -159,6 +159,24 @@ def test_inlay_hint assert_equal(3, responses.dig(1, :result).size) end + def test_inlay_hint_invalid + responses = run_server([ + Initialize.new(1), + TextDocumentDidOpen.new("file:///path/to/file.rb", "<>"), + TextDocumentInlayHint.new(2, "file:///path/to/file.rb"), + Shutdown.new(3) + ]) + + shape = LanguageServer::Request[[ + { id: 1, result: { capabilities: Hash } }, + { id: 2, result: :any }, + { id: 3, result: {} } + ]] + + assert_operator(shape, :===, responses) + assert_equal(0, responses.dig(1, :result).size) + end + def test_visualizing responses = run_server([ Initialize.new(1), diff --git a/test/rake_test.rb b/test/rake_test.rb index bd315cc6..d07fc49c 100644 --- a/test/rake_test.rb +++ b/test/rake_test.rb @@ -8,12 +8,28 @@ module Rake class CheckTaskTest < Minitest::Test Invocation = Struct.new(:args) + def test_task_command + assert_raises(NotImplementedError) { Task.new.command } + end + def test_check_task source_files = "{app,config,lib}/**/*.rb" - CheckTask.new { |t| t.source_files = source_files } + + CheckTask.new do |t| + t.source_files = source_files + t.print_width = 100 + t.target_ruby_version = Gem::Version.new("2.6.0") + end + + expected = [ + "check", + "--print-width=100", + "--target-ruby-version=2.6.0", + source_files + ] invocation = invoke("stree:check") - assert_equal(["check", source_files], invocation.args) + assert_equal(expected, invocation.args) end def test_write_task diff --git a/test/search_test.rb b/test/search_test.rb index 314142e3..9f7d89b8 100644 --- a/test/search_test.rb +++ b/test/search_test.rb @@ -4,6 +4,50 @@ module SyntaxTree class SearchTest < Minitest::Test + def test_search_invalid_syntax + assert_raises(Pattern::CompilationError) { search("", "<>") } + end + + def test_search_invalid_constant + assert_raises(Pattern::CompilationError) { search("", "Foo") } + end + + def test_search_invalid_nested_constant + assert_raises(Pattern::CompilationError) { search("", "Foo::Bar") } + end + + def test_search_regexp_with_interpolation + assert_raises(Pattern::CompilationError) { search("", "/\#{foo}/") } + end + + def test_search_string_with_interpolation + assert_raises(Pattern::CompilationError) { search("", '"#{foo}"') } + end + + def test_search_symbol_with_interpolation + assert_raises(Pattern::CompilationError) { search("", ":\"\#{foo}\"") } + end + + def test_search_invalid_node + assert_raises(Pattern::CompilationError) { search("", "Int[^foo]") } + end + + def test_search_self + assert_raises(Pattern::CompilationError) { search("", "self") } + end + + def test_search_array_pattern_no_constant + results = search("1 + 2", "[Int, Int]") + + assert_equal 1, results.length + end + + def test_search_array_pattern + results = search("1 + 2", "Binary[Int, Int]") + + assert_equal 1, results.length + end + def test_search_binary_or results = search("Foo + Bar + 1", "VarRef | Int") @@ -18,12 +62,24 @@ def test_search_const assert_equal %w[Bar Baz Foo], results.map { |node| node.value.value }.sort end + def test_search_object_const + results = search("1 + 2 + 3", "Int[value: String]") + + assert_equal 3, results.length + end + def test_search_syntax_tree_const results = search("Foo + Bar + Baz", "SyntaxTree::VarRef") assert_equal 3, results.length end + def test_search_hash_pattern_no_constant + results = search("Foo + Bar + Baz", "{ value: Const }") + + assert_equal 3, results.length + end + def test_search_hash_pattern_string results = search("Foo + Bar + Baz", "VarRef[value: Const[value: 'Foo']]") @@ -39,13 +95,25 @@ def test_search_hash_pattern_regexp end def test_search_string_empty - results = search("''", "StringLiteral[parts: []]") + results = search("", "''") - assert_equal 1, results.length + assert_empty results end def test_search_symbol_empty - results = search(":''", "DynaSymbol[parts: []]") + results = search("", ":''") + + assert_empty results + end + + def test_search_symbol_plain + results = search("1 + 2", "Binary[operator: :'+']") + + assert_equal 1, results.length + end + + def test_search_symbol + results = search("1 + 2", "Binary[operator: :+]") assert_equal 1, results.length end @@ -53,10 +121,7 @@ def test_search_symbol_empty private def search(source, query) - pattern = Pattern.new(query).compile - program = SyntaxTree.parse(source) - - Search.new(pattern).scan(program).to_a + SyntaxTree.search(source, query).to_a end end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 1683e7cf..b2cd6787 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -2,10 +2,9 @@ require "simplecov" SimpleCov.start do - unless ENV["CI"] - add_filter("accept_methods_test.rb") - add_filter("idempotency_test.rb") - end + add_filter("idempotency_test.rb") unless ENV["CI"] + add_group("lib", "lib") + add_group("test", "test") end $LOAD_PATH.unshift(File.expand_path("../lib", __dir__)) diff --git a/test/visitor_with_environment_test.rb b/test/visitor_with_environment_test.rb index b37bad16..cc4007fe 100644 --- a/test/visitor_with_environment_test.rb +++ b/test/visitor_with_environment_test.rb @@ -615,5 +615,45 @@ def test_double_nested_arguments assert_equal(1, argument.definitions[0].start_line) assert_equal(5, argument.usages[0].start_line) end + + class Resolver < Visitor + include WithEnvironment + + attr_reader :locals + + def initialize + @locals = [] + end + + def visit_assign(node) + level = 0 + environment = current_environment + level += 1 until (environment = environment.parent).nil? + + locals << [node.target.value.value, level] + super + end + end + + def test_class + source = <<~RUBY + module Level0 + level0 = 0 + + module Level1 + level1 = 1 + + class Level2 + level2 = 2 + end + end + end + RUBY + + visitor = Resolver.new + SyntaxTree.parse(source).accept(visitor) + + assert_equal [["level0", 0], ["level1", 1], ["level2", 2]], visitor.locals + end end end From a3c65df07baa42c348ac9a8c17463807b05d7f4e Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 9 Nov 2022 09:46:33 -0500 Subject: [PATCH 29/35] Support formatting from a non-main ractor --- CHANGELOG.md | 1 + Gemfile.lock | 4 +- lib/syntax_tree.rb | 8 ++- lib/syntax_tree/cli.rb | 70 +++++++++++++++------- lib/syntax_tree/formatter.rb | 76 +++++++++++++++++------- lib/syntax_tree/node.rb | 13 ++-- lib/syntax_tree/plugin/single_quotes.rb | 6 +- lib/syntax_tree/plugin/trailing_comma.rb | 6 +- syntax_tree.gemspec | 2 +- test/cli_test.rb | 10 +--- test/plugin/single_quotes_test.rb | 5 +- test/plugin/trailing_comma_test.rb | 5 +- test/ractor_test.rb | 37 ++++++++++++ test/test_helper.rb | 25 +------- 14 files changed, 177 insertions(+), 91 deletions(-) create mode 100644 test/ractor_test.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index d8a848f5..dc5637ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - `Return0` is no longer a node. Instead if has been folded into the `Return` node. The `Return` node can now have its `arguments` field be `nil`. Consequently, the `visit_return0` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_return` instead. - The `ArgsForward`, `Redo`, `Retry`, and `ZSuper` nodes no longer have `value` fields associated with them (which were always string literals corresponding to the keyword being used). - The `Command` and `CommandCall` nodes now has `block` attributes on them. These attributes are used in the place where you would previously have had a `MethodAddBlock` structure. Where before the `MethodAddBlock` would have the command and block as its two children, you now just have one command node with the `block` attribute set to the `Block` node. +- Previously the formatting options were defined on an unfrozen hash called `SyntaxTree::Formatter::OPTIONS`. It was globally mutable, which made it impossible to reference from within a Ractor. As such, it has now been replaced with `SyntaxTree::Formatter::Options.new` which creates a new options object instance that can be modified without impacting global state. As a part of this change, formatting can now be performed from within a non-main Ractor. In order to check if the `plugin/single_quotes` plugin has been loaded, check if `SyntaxTree::Formatter::SINGLE_QUOTES` is defined. In order to check if the `plugin/trailing_comma` plugin has been loaded, check if `SyntaxTree::Formatter::TRAILING_COMMA` is defined. ## [4.3.0] - 2022-10-28 diff --git a/Gemfile.lock b/Gemfile.lock index 1c1a127c..351c842a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,7 +2,7 @@ PATH remote: . specs: syntax_tree (4.3.0) - prettier_print (>= 1.0.2) + prettier_print (>= 1.1.0) GEM remote: https://rubygems.org/ @@ -14,7 +14,7 @@ GEM parallel (1.22.1) parser (3.1.2.1) ast (~> 2.4.1) - prettier_print (1.0.2) + prettier_print (1.1.0) rainbow (3.1.1) rake (13.0.6) regexp_parser (2.6.0) diff --git a/lib/syntax_tree.rb b/lib/syntax_tree.rb index aff4404c..c2cb3484 100644 --- a/lib/syntax_tree.rb +++ b/lib/syntax_tree.rb @@ -54,8 +54,12 @@ def self.parse(source) end # Parses the given source and returns the formatted source. - def self.format(source, maxwidth = DEFAULT_PRINT_WIDTH) - formatter = Formatter.new(source, [], maxwidth) + def self.format( + source, + maxwidth = DEFAULT_PRINT_WIDTH, + options: Formatter::Options.new + ) + formatter = Formatter.new(source, [], maxwidth, options: options) parse(source).format(formatter) formatter.flush diff --git a/lib/syntax_tree/cli.rb b/lib/syntax_tree/cli.rb index 11c93537..3975df18 100644 --- a/lib/syntax_tree/cli.rb +++ b/lib/syntax_tree/cli.rb @@ -131,9 +131,14 @@ class UnformattedError < StandardError def run(item) source = item.source - if source != item.handler.format(source, options.print_width) - raise UnformattedError - end + formatted = + item.handler.format( + source, + options.print_width, + options: options.formatter_options + ) + + raise UnformattedError if source != formatted rescue StandardError warn("[#{Color.yellow("warn")}] #{item.filepath}") raise @@ -156,13 +161,23 @@ class NonIdempotentFormatError < StandardError def run(item) handler = item.handler - warning = "[#{Color.yellow("warn")}] #{item.filepath}" - formatted = handler.format(item.source, options.print_width) - if formatted != handler.format(formatted, options.print_width) - raise NonIdempotentFormatError - end + formatted = + handler.format( + item.source, + options.print_width, + options: options.formatter_options + ) + + double_formatted = + handler.format( + formatted, + options.print_width, + options: options.formatter_options + ) + + raise NonIdempotentFormatError if formatted != double_formatted rescue StandardError warn(warning) raise @@ -182,7 +197,9 @@ class Doc < Action def run(item) source = item.source - formatter = Formatter.new(source, []) + formatter_options = options.formatter_options + formatter = Formatter.new(source, [], options: formatter_options) + item.handler.parse(source).format(formatter) pp formatter.groups.first end @@ -206,7 +223,14 @@ def run(item) # An action of the CLI that formats the input source and prints it out. class Format < Action def run(item) - puts item.handler.format(item.source, options.print_width) + formatted = + item.handler.format( + item.source, + options.print_width, + options: options.formatter_options + ) + + puts formatted end end @@ -273,7 +297,13 @@ def run(item) start = Time.now source = item.source - formatted = item.handler.format(source, options.print_width) + formatted = + item.handler.format( + source, + options.print_width, + options: options.formatter_options + ) + File.write(filepath, formatted) if item.writable? color = source == formatted ? Color.gray(filepath) : filepath @@ -347,20 +377,16 @@ class Options :plugins, :print_width, :scripts, - :target_ruby_version + :formatter_options - def initialize(print_width: DEFAULT_PRINT_WIDTH) + def initialize @ignore_files = [] @plugins = [] - @print_width = print_width + @print_width = DEFAULT_PRINT_WIDTH @scripts = [] - @target_ruby_version = nil + @formatter_options = Formatter::Options.new end - # TODO: This function causes a couple of side-effects that I really don't - # like to have here. It mutates the global state by requiring the plugins, - # and mutates the global options hash by adding the target ruby version. - # That should be done on a config-by-config basis, not here. def parse(arguments) parser.parse!(arguments) end @@ -404,8 +430,10 @@ def parser # If there is a target ruby version specified on the command line, # parse that out and use it when formatting. opts.on("--target-ruby-version=VERSION") do |version| - @target_ruby_version = Gem::Version.new(version) - Formatter::OPTIONS[:target_ruby_version] = @target_ruby_version + @formatter_options = + Formatter::Options.new( + target_ruby_version: Formatter::SemanticVersion.new(version) + ) end end end diff --git a/lib/syntax_tree/formatter.rb b/lib/syntax_tree/formatter.rb index f878490c..d5d251c6 100644 --- a/lib/syntax_tree/formatter.rb +++ b/lib/syntax_tree/formatter.rb @@ -4,21 +4,63 @@ module SyntaxTree # A slightly enhanced PP that knows how to format recursively including # comments. class Formatter < PrettierPrint + # Unfortunately, Gem::Version.new is not ractor-safe because it performs + # global caching using a class variable. This works around that by just + # setting the instance variables directly. + class SemanticVersion < ::Gem::Version + def initialize(version) + @version = version + @segments = nil + end + end + # We want to minimize as much as possible the number of options that are # available in syntax tree. For the most part, if users want non-default # formatting, they should override the format methods on the specific nodes # themselves. However, because of some history with prettier and the fact # that folks have become entrenched in their ways, we decided to provide a # small amount of configurability. - # - # Note that we're keeping this in a global-ish hash instead of just - # overriding methods on classes so that other plugins can reference this if - # necessary. For example, the RBS plugin references the quote style. - OPTIONS = { - quote: "\"", - trailing_comma: false, - target_ruby_version: Gem::Version.new(RUBY_VERSION) - } + class Options + attr_reader :quote, :trailing_comma, :target_ruby_version + + def initialize( + quote: :default, + trailing_comma: :default, + target_ruby_version: :default + ) + @quote = + if quote == :default + # We ship with a single quotes plugin that will define this + # constant. That constant is responsible for determining the default + # quote style. If it's defined, we default to single quotes, + # otherwise we default to double quotes. + defined?(SINGLE_QUOTES) ? "'" : "\"" + else + quote + end + + @trailing_comma = + if trailing_comma == :default + # We ship with a trailing comma plugin that will define this + # constant. That constant is responsible for determining the default + # trailing comma value. If it's defined, then we default to true. + # Otherwise we default to false. + defined?(TRAILING_COMMA) + else + trailing_comma + end + + @target_ruby_version = + if target_ruby_version == :default + # The default target Ruby version is the current version of Ruby. + # This is really only used for very niche cases, and it shouldn't be + # used by most users. + SemanticVersion.new(RUBY_VERSION) + else + target_ruby_version + end + end + end COMMENT_PRIORITY = 1 HEREDOC_PRIORITY = 2 @@ -30,22 +72,16 @@ class Formatter < PrettierPrint attr_reader :quote, :trailing_comma, :target_ruby_version alias trailing_comma? trailing_comma - def initialize( - source, - *args, - quote: OPTIONS[:quote], - trailing_comma: OPTIONS[:trailing_comma], - target_ruby_version: OPTIONS[:target_ruby_version] - ) + def initialize(source, *args, options: Options.new) super(*args) @source = source @stack = [] - # Memoizing these values per formatter to make access faster. - @quote = quote - @trailing_comma = trailing_comma - @target_ruby_version = target_ruby_version + # Memoizing these values to make access faster. + @quote = options.quote + @trailing_comma = options.trailing_comma + @target_ruby_version = options.target_ruby_version end def self.format(source, node) diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index 639eb7be..1ed74e12 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -1026,7 +1026,7 @@ def call(q) end end - BREAKABLE_SPACE_SEPARATOR = BreakableSpaceSeparator.new + BREAKABLE_SPACE_SEPARATOR = BreakableSpaceSeparator.new.freeze # Formats an array of multiple simple string literals into the %w syntax. class QWordsFormatter @@ -1759,7 +1759,7 @@ def ===(other) module HashKeyFormatter # Formats the keys of a hash literal using labels. class Labels - LABEL = /\A[A-Za-z_](\w*[\w!?])?\z/ + LABEL = /\A[A-Za-z_](\w*[\w!?])?\z/.freeze def format_key(q, key) case key @@ -2176,7 +2176,7 @@ def call(q) # We'll keep a single instance of this separator around for all block vars # to cut down on allocations. - SEPARATOR = Separator.new + SEPARATOR = Separator.new.freeze def format(q) q.text("|") @@ -5723,7 +5723,8 @@ def deconstruct_keys(_keys) # This is a very specific behavior where you want to force a newline, but # don't want to force the break parent. - SEPARATOR = PrettierPrint::Breakable.new(" ", 1, indent: false, force: true) + SEPARATOR = + PrettierPrint::Breakable.new(" ", 1, indent: false, force: true).freeze def format(q) q.group do @@ -6025,7 +6026,7 @@ def format(q) format_contents(q, parts, nested) end - if q.target_ruby_version < Gem::Version.new("2.7.3") + if q.target_ruby_version < Formatter::SemanticVersion.new("2.7.3") q.text(" }") else q.breakable_space @@ -11703,7 +11704,7 @@ def call(q) # We're going to keep a single instance of this separator around so we don't # have to allocate a new one every time we format a when clause. - SEPARATOR = Separator.new + SEPARATOR = Separator.new.freeze def format(q) keyword = "when " diff --git a/lib/syntax_tree/plugin/single_quotes.rb b/lib/syntax_tree/plugin/single_quotes.rb index c6e829e0..c7405e2c 100644 --- a/lib/syntax_tree/plugin/single_quotes.rb +++ b/lib/syntax_tree/plugin/single_quotes.rb @@ -1,3 +1,7 @@ # frozen_string_literal: true -SyntaxTree::Formatter::OPTIONS[:quote] = "'" +module SyntaxTree + class Formatter + SINGLE_QUOTES = true + end +end diff --git a/lib/syntax_tree/plugin/trailing_comma.rb b/lib/syntax_tree/plugin/trailing_comma.rb index 878703c3..1ae2b96d 100644 --- a/lib/syntax_tree/plugin/trailing_comma.rb +++ b/lib/syntax_tree/plugin/trailing_comma.rb @@ -1,3 +1,7 @@ # frozen_string_literal: true -SyntaxTree::Formatter::OPTIONS[:trailing_comma] = true +module SyntaxTree + class Formatter + TRAILING_COMMA = true + end +end diff --git a/syntax_tree.gemspec b/syntax_tree.gemspec index c82a8e98..19f4ee97 100644 --- a/syntax_tree.gemspec +++ b/syntax_tree.gemspec @@ -25,7 +25,7 @@ Gem::Specification.new do |spec| spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = %w[lib] - spec.add_dependency "prettier_print", ">= 1.0.2" + spec.add_dependency "prettier_print", ">= 1.1.0" spec.add_development_dependency "bundler" spec.add_development_dependency "minitest" diff --git a/test/cli_test.rb b/test/cli_test.rb index 9740806d..7c9e2652 100644 --- a/test/cli_test.rb +++ b/test/cli_test.rb @@ -62,14 +62,8 @@ def test_check_print_width end def test_check_target_ruby_version - previous = Formatter::OPTIONS[:target_ruby_version] - - begin - result = run_cli("check", "--target-ruby-version=2.6.0") - assert_includes(result.stdio, "match") - ensure - Formatter::OPTIONS[:target_ruby_version] = previous - end + result = run_cli("check", "--target-ruby-version=2.6.0") + assert_includes(result.stdio, "match") end def test_debug diff --git a/test/plugin/single_quotes_test.rb b/test/plugin/single_quotes_test.rb index 719f33c1..6ce10448 100644 --- a/test/plugin/single_quotes_test.rb +++ b/test/plugin/single_quotes_test.rb @@ -4,8 +4,6 @@ module SyntaxTree class SingleQuotesTest < Minitest::Test - OPTIONS = Plugin.options("syntax_tree/plugin/single_quotes") - def test_empty_string_literal assert_format("''\n", "\"\"") end @@ -36,7 +34,8 @@ def test_label private def assert_format(expected, source = expected) - formatter = Formatter.new(source, [], **OPTIONS) + options = Formatter::Options.new(quote: "'") + formatter = Formatter.new(source, [], options: options) SyntaxTree.parse(source).format(formatter) formatter.flush diff --git a/test/plugin/trailing_comma_test.rb b/test/plugin/trailing_comma_test.rb index ba9ad846..7f6e49a8 100644 --- a/test/plugin/trailing_comma_test.rb +++ b/test/plugin/trailing_comma_test.rb @@ -4,8 +4,6 @@ module SyntaxTree class TrailingCommaTest < Minitest::Test - OPTIONS = Plugin.options("syntax_tree/plugin/trailing_comma") - def test_arg_paren_flat assert_format("foo(a)\n") end @@ -82,7 +80,8 @@ def test_hash_literal_break private def assert_format(expected, source = expected) - formatter = Formatter.new(source, [], **OPTIONS) + options = Formatter::Options.new(trailing_comma: true) + formatter = Formatter.new(source, [], options: options) SyntaxTree.parse(source).format(formatter) formatter.flush diff --git a/test/ractor_test.rb b/test/ractor_test.rb new file mode 100644 index 00000000..e697b48e --- /dev/null +++ b/test/ractor_test.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +# Don't run this test if we're in a version of Ruby that doesn't have Ractors. +return unless defined?(Ractor) + +# Don't run this version on Ruby 3.0.0. For some reason it just hangs within the +# main Ractor waiting for this children. Not going to investigate it since it's +# already been fixed in 3.1.0. +return if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.1.0") + +require_relative "test_helper" + +module SyntaxTree + class RactorTest < Minitest::Test + def test_formatting + ractors = + filepaths.map do |filepath| + # At the moment we have to parse in the main Ractor because Ripper is + # not marked as a Ractor-safe extension. + source = SyntaxTree.read(filepath) + program = SyntaxTree.parse(source) + + Ractor.new(source, program, name: filepath) do |source, program| + SyntaxTree::Formatter.format(source, program) + end + end + + ractors.each(&:take) + end + + private + + def filepaths + Dir.glob(File.expand_path("../lib/syntax_tree/{node,parser}.rb", __dir__)) + end + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index b2cd6787..77627e26 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -86,26 +86,6 @@ def assert_syntax_tree(node) end end -module SyntaxTree - module Plugin - # A couple of plugins modify the options hash on the formatter. They're - # modeled as files that should be required so that it's simple for the CLI - # and the library to use the same code path. In this case we're going to - # require the file for the plugin but ensure it doesn't make any lasting - # changes. - def self.options(path) - previous_options = SyntaxTree::Formatter::OPTIONS.dup - - begin - require path - SyntaxTree::Formatter::OPTIONS.dup - ensure - SyntaxTree::Formatter::OPTIONS.merge!(previous_options) - end - end - end -end - # There are a bunch of fixtures defined in test/fixtures. They exercise every # possible combination of syntax that leads to variations in the types of nodes. # They are used for testing various parts of Syntax Tree, including formatting, @@ -153,9 +133,8 @@ def self.each_fixture # If there's a comment starting with >= that starts after the % that # delineates the test, then we're going to check if the version # satisfies that constraint. - if comment&.start_with?(">=") && - (ruby_version < Gem::Version.new(comment.split[1])) - next + if comment&.start_with?(">=") + next if ruby_version < Gem::Version.new(comment.split[1]) end name = :"#{fixture}_#{index}" From 8e31ca9e323a05048f4c577335dfdd860c43c576 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 9 Nov 2022 11:22:31 -0500 Subject: [PATCH 30/35] More naming changes --- .rubocop.yml | 2 +- CHANGELOG.md | 16 +-- README.md | 2 +- lib/syntax_tree/node.rb | 136 ++++++++++---------- lib/syntax_tree/parser.rb | 124 ++++++++---------- lib/syntax_tree/visitor.rb | 16 +-- lib/syntax_tree/visitor/field_visitor.rb | 4 +- lib/syntax_tree/visitor/mutation_visitor.rb | 16 +-- test/mutation_test.rb | 2 +- test/node_test.rb | 54 ++++---- 10 files changed, 180 insertions(+), 192 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 27efc39a..6c9be677 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -7,7 +7,7 @@ AllCops: SuggestExtensions: false TargetRubyVersion: 2.7 Exclude: - - '{bin,coverage,pkg,test/fixtures,vendor,tmp}/**/*' + - '{.git,.github,bin,coverage,pkg,test/fixtures,vendor,tmp}/**/*' - test.rb Layout/LineLength: diff --git a/CHANGELOG.md b/CHANGELOG.md index dc5637ce..2e4783e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,14 +16,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - Nodes no longer have a `comments:` keyword on their initializers. By default, they initialize to an empty array. If you were previously passing comments into the initializer, you should now create the node first, then call `node.comments.concat` to add your comments. - A lot of nodes have been folded into other nodes to make it easier to interact with the AST. This means that a lot of visit methods have been removed from the visitor and a lot of class definitions are no longer present. This also means that the nodes that received more function now have additional methods or fields to be able to differentiate them. Note that none of these changes have resulted in different formatting. The changes are listed below: - - `IfMod`, `UnlessMod`, `WhileMod`, `UntilMod` have been folded into `If`, `Unless`, `While`, and `Until`. Each of the nodes now have a `modifier?` method to tell if it was originally in the modifier form. Consequently, the `visit_if_mod`, `visit_unless_mod`, `visit_while_mod`, and `visit_until_mod` methods have been removed from the visitor. - - `VarAlias` is no longer a node. Instead it has been folded into the `Alias` node. The `Alias` node now has a `var_alias?` method to tell you if it is aliasing a global variable. Consequently, the `visit_var_alias` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_alias` instead. - - `Yield0` is no longer a node. Instead if has been folded into the `Yield` node. The `Yield` node can now have its `arguments` field be `nil`. Consequently, the `visit_yield0` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_yield` instead. - - `FCall` is no longer a node. Instead it has been folded into the `Call` node. The `Call` node can now have its `receiver` and `operator` fields be `nil`. Consequently, the `visit_fcall` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_call` instead. - - `Dot2` and `Dot3` are no longer nodes. Instead they have become a single new `RangeLiteral` node. This node looks the same as `Dot2` and `Dot3`, except that it additionally has an `operator` field that contains the operator that created the node. Consequently, the `visit_dot2` and `visit_dot3` methods have been removed from the visitor interface. If you were previously using these methods, you should now use `visit_range_literal` instead. - - `DefEndless` and `Defs` have both been folded into the `Def` node. The `Def` node now has the `target` and `operator` fields which originally came from `Defs` which can both be `nil`. It also now has an `endless?` method on it to tell if the original node was found in the endless form. Finally the `bodystmt` field can now either be a `BodyStmt` as it was or any other kind of node since that was the body of the `DefEndless` node. The `visit_defs` and `visit_def_endless` methods on the visitor have therefore been removed. - - `DoBlock` and `BraceBlock` have now been folded into a `Block` node. The `Block` node now has a `keywords?` method on it that returns true if the block was constructed with the `do`..`end` keywords. The `visit_do_block` and `visit_brace_block` methods on the visitor have therefore been removed and replaced with the `visit_block` method. - - `Return0` is no longer a node. Instead if has been folded into the `Return` node. The `Return` node can now have its `arguments` field be `nil`. Consequently, the `visit_return0` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_return` instead. + - `IfMod`, `UnlessMod`, `WhileMod`, `UntilMod` have been folded into `IfNode`, `UnlessNode`, `WhileNode`, and `UntilNode`. Each of the nodes now have a `modifier?` method to tell if it was originally in the modifier form. Consequently, the `visit_if_mod`, `visit_unless_mod`, `visit_while_mod`, and `visit_until_mod` methods have been removed from the visitor. + - `VarAlias` is no longer a node, and the `Alias` node has been renamed. They have been folded into the `AliasNode` node. The `AliasNode` node now has a `var_alias?` method to tell you if it is aliasing a global variable. Consequently, the `visit_var_alias` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_alias` instead. + - `Yield0` is no longer a node, and the `Yield` node has been renamed. They has been folded into the `YieldNode` node. The `YieldNode` node can now have its `arguments` field be `nil`. Consequently, the `visit_yield0` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_yield` instead. + - `FCall` is no longer a node, and the `Call` node has been renamed. They have been folded into the `CallNode` node. The `CallNode` node can now have its `receiver` and `operator` fields be `nil`. Consequently, the `visit_fcall` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_call` instead. + - `Dot2` and `Dot3` are no longer nodes. Instead they have become a single new `RangeNode` node. This node looks the same as `Dot2` and `Dot3`, except that it additionally has an `operator` field that contains the operator that created the node. Consequently, the `visit_dot2` and `visit_dot3` methods have been removed from the visitor interface. If you were previously using these methods, you should now use `visit_range` instead. + - `Def`, `DefEndless`, and `Defs` have been folded into the `DefNode` node. The `DefNode` node now has the `target` and `operator` fields which originally came from `Defs` which can both be `nil`. It also now has an `endless?` method on it to tell if the original node was found in the endless form. Finally the `bodystmt` field can now either be a `BodyStmt` as it was or any other kind of node since that was the body of the `DefEndless` node. The `visit_defs` and `visit_def_endless` methods on the visitor have therefore been removed. + - `DoBlock` and `BraceBlock` have now been folded into a `BlockNode` node. The `BlockNode` node now has a `keywords?` method on it that returns true if the block was constructed with the `do`..`end` keywords. The `visit_do_block` and `visit_brace_block` methods on the visitor have therefore been removed and replaced with the `visit_block` method. + - `Return0` is no longer a node, and the `Return` node has been renamed. They have been folded into the `ReturnNode` node. The `ReturnNode` node can now have its `arguments` field be `nil`. Consequently, the `visit_return0` method has been removed from the visitor interface. If you were previously using this method, you should now use `visit_return` instead. - The `ArgsForward`, `Redo`, `Retry`, and `ZSuper` nodes no longer have `value` fields associated with them (which were always string literals corresponding to the keyword being used). - The `Command` and `CommandCall` nodes now has `block` attributes on them. These attributes are used in the place where you would previously have had a `MethodAddBlock` structure. Where before the `MethodAddBlock` would have the command and block as its two children, you now just have one command node with the `block` attribute set to the `Block` node. - Previously the formatting options were defined on an unfrozen hash called `SyntaxTree::Formatter::OPTIONS`. It was globally mutable, which made it impossible to reference from within a Ractor. As such, it has now been replaced with `SyntaxTree::Formatter::Options.new` which creates a new options object instance that can be modified without impacting global state. As a part of this change, formatting can now be performed from within a non-main Ractor. In order to check if the `plugin/single_quotes` plugin has been loaded, check if `SyntaxTree::Formatter::SINGLE_QUOTES` is defined. In order to check if the `plugin/trailing_comma` plugin has been loaded, check if `SyntaxTree::Formatter::TRAILING_COMMA` is defined. diff --git a/README.md b/README.md index e87ec765..050877ee 100644 --- a/README.md +++ b/README.md @@ -538,7 +538,7 @@ The `MutationVisitor` is a visitor that can be used to mutate the tree. It works visitor = SyntaxTree::Visitor::MutationVisitor.new # Specify that it should mutate If nodes with assignments in their predicates -visitor.mutate("If[predicate: Assign | OpAssign]") do |node| +visitor.mutate("IfNode[predicate: Assign | OpAssign]") do |node| # Get the existing If's predicate node predicate = node.predicate diff --git a/lib/syntax_tree/node.rb b/lib/syntax_tree/node.rb index 1ed74e12..f32789a3 100644 --- a/lib/syntax_tree/node.rb +++ b/lib/syntax_tree/node.rb @@ -445,7 +445,7 @@ def ===(other) # can either provide bare words (like the example above) or you can provide # symbols (note that this includes dynamic symbols like # :"left-#{middle}-right"). - class Alias < Node + class AliasNode < Node # Formats an argument to the alias keyword. For symbol literals it uses the # value of the symbol directly to look like bare words. class AliasArgumentFormatter @@ -500,7 +500,7 @@ def child_nodes def copy(left: nil, right: nil, location: nil) node = - Alias.new( + AliasNode.new( left: left || self.left, right: right || self.right, location: location || self.location @@ -533,7 +533,7 @@ def format(q) end def ===(other) - other.is_a?(Alias) && left === other.left && right === other.right + other.is_a?(AliasNode) && left === other.left && right === other.right end def var_alias? @@ -1430,7 +1430,7 @@ def self.skip_indent?(value) when ArrayLiteral, HashLiteral, Heredoc, Lambda, QSymbols, QWords, Symbols, Words true - when Call + when CallNode skip_indent?(value.receiver) when DynaSymbol value.quote.start_with?("%s") @@ -2707,16 +2707,16 @@ def format(q) # longer at a chainable node. loop do case (child = children.last) - when Call + when CallNode case (receiver = child.receiver) - when Call + when CallNode if receiver.receiver.nil? break else children << receiver end when MethodAddBlock - if receiver.call.is_a?(Call) && !receiver.call.receiver.nil? + if receiver.call.is_a?(CallNode) && !receiver.call.receiver.nil? children << receiver else break @@ -2725,7 +2725,7 @@ def format(q) break end when MethodAddBlock - if child.call.is_a?(Call) && !child.call.receiver.nil? + if child.call.is_a?(CallNode) && !child.call.receiver.nil? children << child.call else break @@ -2746,9 +2746,9 @@ def format(q) # If we're at a block with the `do` keywords, then we want to go one # more level up. This is because do blocks have BodyStmt nodes instead # of just Statements nodes. - parent = parents[3] if parent.is_a?(Block) && parent.keywords? + parent = parents[3] if parent.is_a?(BlockNode) && parent.keywords? - if parent.is_a?(MethodAddBlock) && parent.call.is_a?(Call) && + if parent.is_a?(MethodAddBlock) && parent.call.is_a?(CallNode) && parent.call.message.value == "sig" threshold = 2 end @@ -2772,7 +2772,7 @@ def format_chain(q, children) empty_except_last = children .drop(1) - .all? { |child| child.is_a?(Call) && child.arguments.nil? } + .all? { |child| child.is_a?(CallNode) && child.arguments.nil? } # Here, we're going to add all of the children onto the stack of the # formatter so it's as if we had descending normally into them. This is @@ -2793,8 +2793,8 @@ def format_chain(q, children) skip_operator = false while (child = children.pop) - if child.is_a?(Call) - if child.receiver.is_a?(Call) && + if child.is_a?(CallNode) + if child.receiver.is_a?(CallNode) && (child.receiver.message != :call) && (child.receiver.message.value == "where") && (child.message.value == "not") @@ -2821,7 +2821,7 @@ def format_chain(q, children) # If the parent call node has a comment on the message then we need # to print the operator trailing in order to keep it working. last_child = children.last - if last_child.is_a?(Call) && last_child.message.comments.any? && + if last_child.is_a?(CallNode) && last_child.message.comments.any? && last_child.operator q.format(CallOperatorFormatter.new(last_child.operator)) skip_operator = true @@ -2838,7 +2838,7 @@ def format_chain(q, children) if empty_except_last case node - when Call + when CallNode node.format_arguments(q) when MethodAddBlock q.format(node.block) @@ -2850,10 +2850,10 @@ def self.chained?(node) return false if ENV["STREE_FAST_FORMAT"] case node - when Call + when CallNode !node.receiver.nil? when MethodAddBlock - node.call.is_a?(Call) && !node.call.receiver.nil? + node.call.is_a?(CallNode) && !node.call.receiver.nil? else false end @@ -2866,7 +2866,8 @@ def self.chained?(node) # format it separately here. def attach_directly?(node) case node.receiver - when ArrayLiteral, HashLiteral, Heredoc, If, Unless, XStringLiteral + when ArrayLiteral, HashLiteral, Heredoc, IfNode, UnlessNode, + XStringLiteral true else false @@ -2882,7 +2883,7 @@ def format_child( ) # First, format the actual contents of the child. case child - when Call + when CallNode q.group do if !skip_operator && child.operator q.format(CallOperatorFormatter.new(child.operator)) @@ -2907,11 +2908,11 @@ def format_child( end end - # Call represents a method call. + # CallNode represents a method call. # # receiver.message # - class Call < Node + class CallNode < Node # [nil | untyped] the receiver of the method call attr_reader :receiver @@ -2957,7 +2958,7 @@ def copy( location: nil ) node = - Call.new( + CallNode.new( receiver: receiver || self.receiver, operator: operator || self.operator, message: message || self.message, @@ -3014,7 +3015,7 @@ def format(q) end def ===(other) - other.is_a?(Call) && receiver === other.receiver && + other.is_a?(CallNode) && receiver === other.receiver && operator === other.operator && message === other.message && arguments === other.arguments end @@ -3483,7 +3484,7 @@ def align(q, node, &block) part = parts.first case part - when Def + when DefNode q.text(" ") yield when IfOp @@ -4038,7 +4039,7 @@ def ===(other) # def method(param) result end # def object.method(param) result end # - class Def < Node + class DefNode < Node # [nil | untyped] the target where the method is being defined attr_reader :target @@ -4084,7 +4085,7 @@ def copy( location: nil ) node = - Def.new( + DefNode.new( target: target || self.target, operator: operator || self.operator, name: name || self.name, @@ -4154,7 +4155,7 @@ def format(q) end def ===(other) - other.is_a?(Def) && target === other.target && + other.is_a?(DefNode) && target === other.target && operator === other.operator && name === other.name && params === other.params && bodystmt === other.bodystmt end @@ -4235,7 +4236,7 @@ def ===(other) # # method { |value| } # - class Block < Node + class BlockNode < Node # Formats the opening brace or keyword of a block. class BlockOpenFormatter # [String] the actual output that should be printed @@ -4288,7 +4289,7 @@ def child_nodes def copy(opening: nil, block_var: nil, bodystmt: nil, location: nil) node = - Block.new( + BlockNode.new( opening: opening || self.opening, block_var: block_var || self.block_var, bodystmt: bodystmt || self.bodystmt, @@ -4344,7 +4345,7 @@ def format(q) end def ===(other) - other.is_a?(Block) && opening === other.opening && + other.is_a?(BlockNode) && opening === other.opening && block_var === other.block_var && bodystmt === other.bodystmt end @@ -4376,7 +4377,7 @@ def unchangeable_bounds?(q) # use the do..end bounds. def forced_do_end_bounds?(q) case q.parent.call - when Break, Next, Return, Super + when Break, Next, ReturnNode, Super true else false @@ -4392,7 +4393,7 @@ def forced_brace_bounds?(q) when Paren, Statements # If we hit certain breakpoints then we know we're safe. return false - when If, IfOp, Unless, While, Until + when IfNode, IfOp, UnlessNode, WhileNode, UntilNode return true if parent.predicate == previous end @@ -4443,7 +4444,7 @@ def format_flat(q, flat_opening, flat_closing) end end - # RangeLiteral represents using the .. or the ... operator between two + # RangeNode represents using the .. or the ... operator between two # expressions. Usually this is to create a range object. # # 1..2 @@ -4454,7 +4455,7 @@ def format_flat(q, flat_opening, flat_closing) # end # # One of the sides of the expression may be nil, but not both. - class RangeLiteral < Node + class RangeNode < Node # [nil | untyped] the left side of the expression attr_reader :left @@ -4476,7 +4477,7 @@ def initialize(left:, operator:, right:, location:) end def accept(visitor) - visitor.visit_range_literal(self) + visitor.visit_range(self) end def child_nodes @@ -4485,7 +4486,7 @@ def child_nodes def copy(left: nil, operator: nil, right: nil, location: nil) node = - RangeLiteral.new( + RangeNode.new( left: left || self.left, operator: operator || self.operator, right: right || self.right, @@ -4512,7 +4513,7 @@ def format(q) q.format(left) if left case q.parent - when If, Unless + when IfNode, UnlessNode q.text(" #{operator.value} ") else q.text(operator.value) @@ -4522,7 +4523,7 @@ def format(q) end def ===(other) - other.is_a?(RangeLiteral) && left === other.left && + other.is_a?(RangeNode) && left === other.left && operator === other.operator && right === other.right end end @@ -6182,9 +6183,10 @@ def call(q, node) # and default instead to breaking them into multiple lines. def ternaryable?(statement) case statement - when Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfOp, - Lambda, MAssign, Next, OpAssign, RescueMod, Return, Super, Undef, - Unless, Until, VoidStmt, While, Yield, ZSuper + when AliasNode, Assign, Break, Command, CommandCall, Heredoc, IfNode, + IfOp, Lambda, MAssign, Next, OpAssign, RescueMod, ReturnNode, + Super, Undef, UnlessNode, UntilNode, VoidStmt, WhileNode, + YieldNode, ZSuper # This is a list of nodes that should not be allowed to be a part of a # ternary clause. false @@ -6343,7 +6345,7 @@ def contains_conditional? return false if statements.length != 1 case statements.first - when If, IfOp, Unless + when IfNode, IfOp, UnlessNode true else false @@ -6356,7 +6358,7 @@ def contains_conditional? # if predicate # end # - class If < Node + class IfNode < Node # [untyped] the expression to be checked attr_reader :predicate @@ -6387,7 +6389,7 @@ def child_nodes def copy(predicate: nil, statements: nil, consequent: nil, location: nil) node = - If.new( + IfNode.new( predicate: predicate || self.predicate, statements: statements || self.statements, consequent: consequent || self.consequent, @@ -6415,7 +6417,7 @@ def format(q) end def ===(other) - other.is_a?(If) && predicate === other.predicate && + other.is_a?(IfNode) && predicate === other.predicate && statements === other.statements && consequent === other.consequent end @@ -6485,9 +6487,9 @@ def deconstruct_keys(_keys) def format(q) force_flat = [ - Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfOp, Lambda, - MAssign, Next, OpAssign, RescueMod, Return, Super, Undef, Unless, - VoidStmt, Yield, ZSuper + AliasNode, Assign, Break, Command, CommandCall, Heredoc, IfNode, IfOp, + Lambda, MAssign, Next, OpAssign, RescueMod, ReturnNode, Super, Undef, + UnlessNode, VoidStmt, YieldNode, ZSuper ] if q.parent.is_a?(Paren) || force_flat.include?(truthy.class) || @@ -8039,7 +8041,7 @@ module Parentheses Assign, Assoc, Binary, - Call, + CallNode, Defined, MAssign, OpAssign @@ -8283,7 +8285,7 @@ def format(q) return end - if q.parent.is_a?(Def) + if q.parent.is_a?(DefNode) q.nest(0) do q.text("(") q.group do @@ -9550,7 +9552,7 @@ def ===(other) # # return value # - class Return < Node + class ReturnNode < Node # [nil | Args] the arguments being passed to the keyword attr_reader :arguments @@ -9573,7 +9575,7 @@ def child_nodes def copy(arguments: nil, location: nil) node = - Return.new( + ReturnNode.new( arguments: arguments || self.arguments, location: location || self.location ) @@ -9593,7 +9595,7 @@ def format(q) end def ===(other) - other.is_a?(Return) && arguments === other.arguments + other.is_a?(ReturnNode) && arguments === other.arguments end end @@ -10955,7 +10957,7 @@ def format(q) else grandparent = q.grandparent ternary = - (grandparent.is_a?(If) || grandparent.is_a?(Unless)) && + (grandparent.is_a?(IfNode) || grandparent.is_a?(UnlessNode)) && Ternaryable.call(q, grandparent) if ternary @@ -11127,7 +11129,7 @@ def ===(other) # unless predicate # end # - class Unless < Node + class UnlessNode < Node # [untyped] the expression to be checked attr_reader :predicate @@ -11158,7 +11160,7 @@ def child_nodes def copy(predicate: nil, statements: nil, consequent: nil, location: nil) node = - Unless.new( + UnlessNode.new( predicate: predicate || self.predicate, statements: statements || self.statements, consequent: consequent || self.consequent, @@ -11186,7 +11188,7 @@ def format(q) end def ===(other) - other.is_a?(Unless) && predicate === other.predicate && + other.is_a?(UnlessNode) && predicate === other.predicate && statements === other.statements && consequent === other.consequent end @@ -11273,7 +11275,7 @@ def format_break(q) # until predicate # end # - class Until < Node + class UntilNode < Node # [untyped] the expression to be checked attr_reader :predicate @@ -11300,7 +11302,7 @@ def child_nodes def copy(predicate: nil, statements: nil, location: nil) node = - Until.new( + UntilNode.new( predicate: predicate || self.predicate, statements: statements || self.statements, location: location || self.location @@ -11326,7 +11328,7 @@ def format(q) end def ===(other) - other.is_a?(Until) && predicate === other.predicate && + other.is_a?(UntilNode) && predicate === other.predicate && statements === other.statements end @@ -11723,7 +11725,7 @@ def format(q) # last argument to the predicate is and endless range, then you are # forced to use the "then" keyword to make it parse properly. last = arguments.parts.last - q.text(" then") if last.is_a?(RangeLiteral) && !last.right + q.text(" then") if last.is_a?(RangeNode) && !last.right end end @@ -11752,7 +11754,7 @@ def ===(other) # while predicate # end # - class While < Node + class WhileNode < Node # [untyped] the expression to be checked attr_reader :predicate @@ -11779,7 +11781,7 @@ def child_nodes def copy(predicate: nil, statements: nil, location: nil) node = - While.new( + WhileNode.new( predicate: predicate || self.predicate, statements: statements || self.statements, location: location || self.location @@ -11805,7 +11807,7 @@ def format(q) end def ===(other) - other.is_a?(While) && predicate === other.predicate && + other.is_a?(WhileNode) && predicate === other.predicate && statements === other.statements end @@ -12090,7 +12092,7 @@ def ===(other) # # yield value # - class Yield < Node + class YieldNode < Node # [nil | Args | Paren] the arguments passed to the yield attr_reader :arguments @@ -12113,7 +12115,7 @@ def child_nodes def copy(arguments: nil, location: nil) node = - Yield.new( + YieldNode.new( arguments: arguments || self.arguments, location: location || self.location ) @@ -12152,7 +12154,7 @@ def format(q) end def ===(other) - other.is_a?(Yield) && arguments === other.arguments + other.is_a?(YieldNode) && arguments === other.arguments end end diff --git a/lib/syntax_tree/parser.rb b/lib/syntax_tree/parser.rb index cd14672e..23a3196c 100644 --- a/lib/syntax_tree/parser.rb +++ b/lib/syntax_tree/parser.rb @@ -421,11 +421,11 @@ def on___end__(value) # on_alias: ( # (DynaSymbol | SymbolLiteral) left, # (DynaSymbol | SymbolLiteral) right - # ) -> Alias + # ) -> AliasNode def on_alias(left, right) keyword = consume_keyword(:alias) - Alias.new( + AliasNode.new( left: left, right: right, location: keyword.location.to(right.location) @@ -920,7 +920,7 @@ def on_bodystmt(statements, rescue_clause, else_clause, ensure_clause) # on_brace_block: ( # (nil | BlockVar) block_var, # Statements statements - # ) -> Block + # ) -> BlockNode def on_brace_block(block_var, statements) lbrace = consume_token(LBrace) rbrace = consume_token(RBrace) @@ -947,7 +947,7 @@ def on_brace_block(block_var, statements) end_column: rbrace.location.end_column ) - Block.new( + BlockNode.new( opening: lbrace, block_var: block_var, bodystmt: statements, @@ -971,7 +971,7 @@ def on_break(arguments) # untyped receiver, # (:"::" | Op | Period) operator, # (:call | Backtick | Const | Ident | Op) message - # ) -> Call + # ) -> CallNode def on_call(receiver, operator, message) ending = if message != :call @@ -982,7 +982,7 @@ def on_call(receiver, operator, message) receiver end - Call.new( + CallNode.new( receiver: receiver, operator: operator, message: message, @@ -1183,7 +1183,7 @@ def on_cvar(value) # (Backtick | Const | Ident | Kw | Op) name, # (nil | Params | Paren) params, # untyped bodystmt - # ) -> Def + # ) -> DefNode def on_def(name, params, bodystmt) # Make sure to delete this token in case you're defining something like # def class which would lead to this being a kw and causing all kinds of @@ -1225,7 +1225,7 @@ def on_def(name, params, bodystmt) ending.location.start_column ) - Def.new( + DefNode.new( target: nil, operator: nil, name: name, @@ -1238,7 +1238,7 @@ def on_def(name, params, bodystmt) # the statements list. Before, it was just the individual statement. statement = bodystmt.is_a?(BodyStmt) ? bodystmt.statements : bodystmt - Def.new( + DefNode.new( target: nil, operator: nil, name: name, @@ -1274,7 +1274,7 @@ def on_defined(value) # (Backtick | Const | Ident | Kw | Op) name, # (Params | Paren) params, # BodyStmt bodystmt - # ) -> Def + # ) -> DefNode def on_defs(target, operator, name, params, bodystmt) # Make sure to delete this token in case you're defining something # like def class which would lead to this being a kw and causing all kinds @@ -1313,7 +1313,7 @@ def on_defs(target, operator, name, params, bodystmt) ending.location.start_column ) - Def.new( + DefNode.new( target: target, operator: operator, name: name, @@ -1326,7 +1326,7 @@ def on_defs(target, operator, name, params, bodystmt) # the statements list. Before, it was just the individual statement. statement = bodystmt.is_a?(BodyStmt) ? bodystmt.statements : bodystmt - Def.new( + DefNode.new( target: target, operator: operator, name: name, @@ -1338,7 +1338,7 @@ def on_defs(target, operator, name, params, bodystmt) end # :call-seq: - # on_do_block: (BlockVar block_var, BodyStmt bodystmt) -> Block + # on_do_block: (BlockVar block_var, BodyStmt bodystmt) -> BlockNode def on_do_block(block_var, bodystmt) beginning = consume_keyword(:do) ending = consume_keyword(:end) @@ -1352,7 +1352,7 @@ def on_do_block(block_var, bodystmt) ending.location.start_column ) - Block.new( + BlockNode.new( opening: beginning, block_var: block_var, bodystmt: bodystmt, @@ -1361,14 +1361,14 @@ def on_do_block(block_var, bodystmt) end # :call-seq: - # on_dot2: ((nil | untyped) left, (nil | untyped) right) -> RangeLiteral + # on_dot2: ((nil | untyped) left, (nil | untyped) right) -> RangeNode def on_dot2(left, right) operator = consume_operator(:"..") beginning = left || operator ending = right || operator - RangeLiteral.new( + RangeNode.new( left: left, operator: operator, right: right, @@ -1377,14 +1377,14 @@ def on_dot2(left, right) end # :call-seq: - # on_dot3: ((nil | untyped) left, (nil | untyped) right) -> RangeLiteral + # on_dot3: ((nil | untyped) left, (nil | untyped) right) -> RangeNode def on_dot3(left, right) operator = consume_operator(:"...") beginning = left || operator ending = right || operator - RangeLiteral.new( + RangeNode.new( left: left, operator: operator, right: right, @@ -1614,9 +1614,9 @@ def on_excessed_comma(*) end # :call-seq: - # on_fcall: ((Const | Ident) value) -> Call + # on_fcall: ((Const | Ident) value) -> CallNode def on_fcall(value) - Call.new( + CallNode.new( receiver: nil, operator: nil, message: value, @@ -1890,7 +1890,7 @@ def on_ident(value) # untyped predicate, # Statements statements, # (nil | Elsif | Else) consequent - # ) -> If + # ) -> IfNode def on_if(predicate, statements, consequent) beginning = consume_keyword(:if) ending = consequent || consume_keyword(:end) @@ -1903,7 +1903,7 @@ def on_if(predicate, statements, consequent) ending.location.start_column ) - If.new( + IfNode.new( predicate: predicate, statements: statements, consequent: consequent, @@ -1923,11 +1923,11 @@ def on_ifop(predicate, truthy, falsy) end # :call-seq: - # on_if_mod: (untyped predicate, untyped statement) -> If + # on_if_mod: (untyped predicate, untyped statement) -> IfNode def on_if_mod(predicate, statement) consume_keyword(:if) - If.new( + IfNode.new( predicate: predicate, statements: Statements.new(self, body: [statement], location: statement.location), @@ -2319,14 +2319,14 @@ def on_massign(target, value) # :call-seq: # on_method_add_arg: ( - # Call call, + # CallNode call, # (ArgParen | Args) arguments - # ) -> Call + # ) -> CallNode def on_method_add_arg(call, arguments) location = call.location location = location.to(arguments.location) if arguments.is_a?(ArgParen) - Call.new( + CallNode.new( receiver: call.receiver, operator: call.operator, message: call.message, @@ -2341,29 +2341,11 @@ def on_method_add_arg(call, arguments) # Block block # ) -> MethodAddBlock def on_method_add_block(call, block) - case call - when Command - node = - Command.new( - message: call.message, - arguments: call.arguments, - block: block, - location: call.location.to(block.location) - ) - - node.comments.concat(call.comments) - node - when CommandCall - node = - CommandCall.new( - receiver: call.receiver, - operator: call.operator, - message: call.message, - arguments: call.arguments, - block: block, - location: call.location.to(block.location) - ) + location = call.location.to(block.location) + case call + when Command, CommandCall + node = call.copy(block: block, location: location) node.comments.concat(call.comments) node else @@ -3110,22 +3092,22 @@ def on_retry end # :call-seq: - # on_return: (Args arguments) -> Return + # on_return: (Args arguments) -> ReturnNode def on_return(arguments) keyword = consume_keyword(:return) - Return.new( + ReturnNode.new( arguments: arguments, location: keyword.location.to(arguments.location) ) end # :call-seq: - # on_return0: () -> Return + # on_return0: () -> ReturnNode def on_return0 keyword = consume_keyword(:return) - Return.new(arguments: nil, location: keyword.location) + ReturnNode.new(arguments: nil, location: keyword.location) end # :call-seq: @@ -3602,7 +3584,7 @@ def on_undef(symbols) # untyped predicate, # Statements statements, # ((nil | Elsif | Else) consequent) - # ) -> Unless + # ) -> UnlessNode def on_unless(predicate, statements, consequent) beginning = consume_keyword(:unless) ending = consequent || consume_keyword(:end) @@ -3615,7 +3597,7 @@ def on_unless(predicate, statements, consequent) ending.location.start_column ) - Unless.new( + UnlessNode.new( predicate: predicate, statements: statements, consequent: consequent, @@ -3624,11 +3606,11 @@ def on_unless(predicate, statements, consequent) end # :call-seq: - # on_unless_mod: (untyped predicate, untyped statement) -> Unless + # on_unless_mod: (untyped predicate, untyped statement) -> UnlessNode def on_unless_mod(predicate, statement) consume_keyword(:unless) - Unless.new( + UnlessNode.new( predicate: predicate, statements: Statements.new(self, body: [statement], location: statement.location), @@ -3638,7 +3620,7 @@ def on_unless_mod(predicate, statement) end # :call-seq: - # on_until: (untyped predicate, Statements statements) -> Until + # on_until: (untyped predicate, Statements statements) -> UntilNode def on_until(predicate, statements) beginning = consume_keyword(:until) ending = consume_keyword(:end) @@ -3660,7 +3642,7 @@ def on_until(predicate, statements) ending.location.start_column ) - Until.new( + UntilNode.new( predicate: predicate, statements: statements, location: beginning.location.to(ending.location) @@ -3668,11 +3650,11 @@ def on_until(predicate, statements) end # :call-seq: - # on_until_mod: (untyped predicate, untyped statement) -> Until + # on_until_mod: (untyped predicate, untyped statement) -> UntilNode def on_until_mod(predicate, statement) consume_keyword(:until) - Until.new( + UntilNode.new( predicate: predicate, statements: Statements.new(self, body: [statement], location: statement.location), @@ -3681,11 +3663,11 @@ def on_until_mod(predicate, statement) end # :call-seq: - # on_var_alias: (GVar left, (Backref | GVar) right) -> Alias + # on_var_alias: (GVar left, (Backref | GVar) right) -> AliasNode def on_var_alias(left, right) keyword = consume_keyword(:alias) - Alias.new( + AliasNode.new( left: left, right: right, location: keyword.location.to(right.location) @@ -3765,7 +3747,7 @@ def on_when(arguments, statements, consequent) end # :call-seq: - # on_while: (untyped predicate, Statements statements) -> While + # on_while: (untyped predicate, Statements statements) -> WhileNode def on_while(predicate, statements) beginning = consume_keyword(:while) ending = consume_keyword(:end) @@ -3787,7 +3769,7 @@ def on_while(predicate, statements) ending.location.start_column ) - While.new( + WhileNode.new( predicate: predicate, statements: statements, location: beginning.location.to(ending.location) @@ -3795,11 +3777,11 @@ def on_while(predicate, statements) end # :call-seq: - # on_while_mod: (untyped predicate, untyped statement) -> While + # on_while_mod: (untyped predicate, untyped statement) -> WhileNode def on_while_mod(predicate, statement) consume_keyword(:while) - While.new( + WhileNode.new( predicate: predicate, statements: Statements.new(self, body: [statement], location: statement.location), @@ -3925,22 +3907,22 @@ def on_xstring_literal(xstring) end # :call-seq: - # on_yield: ((Args | Paren) arguments) -> Yield + # on_yield: ((Args | Paren) arguments) -> YieldNode def on_yield(arguments) keyword = consume_keyword(:yield) - Yield.new( + YieldNode.new( arguments: arguments, location: keyword.location.to(arguments.location) ) end # :call-seq: - # on_yield0: () -> Yield + # on_yield0: () -> YieldNode def on_yield0 keyword = consume_keyword(:yield) - Yield.new(arguments: nil, location: keyword.location) + YieldNode.new(arguments: nil, location: keyword.location) end # :call-seq: diff --git a/lib/syntax_tree/visitor.rb b/lib/syntax_tree/visitor.rb index 57aca619..eb57acd2 100644 --- a/lib/syntax_tree/visitor.rb +++ b/lib/syntax_tree/visitor.rb @@ -11,7 +11,7 @@ class Visitor < BasicVisitor # Visit an ARefField node. alias visit_aref_field visit_child_nodes - # Visit an Alias node. + # Visit an AliasNode node. alias visit_alias visit_child_nodes # Visit an ArgBlock node. @@ -185,7 +185,7 @@ class Visitor < BasicVisitor # Visit an Ident node. alias visit_ident visit_child_nodes - # Visit an If node. + # Visit an IfNode node. alias visit_if visit_child_nodes # Visit an IfOp node. @@ -290,8 +290,8 @@ class Visitor < BasicVisitor # Visit a QWordsBeg node. alias visit_qwords_beg visit_child_nodes - # Visit a RangeLiteral node - alias visit_range_literal visit_child_nodes + # Visit a RangeNode node + alias visit_range visit_child_nodes # Visit a RAssign node. alias visit_rassign visit_child_nodes @@ -407,10 +407,10 @@ class Visitor < BasicVisitor # Visit an Undef node. alias visit_undef visit_child_nodes - # Visit an Unless node. + # Visit an UnlessNode node. alias visit_unless visit_child_nodes - # Visit an Until node. + # Visit an UntilNode node. alias visit_until visit_child_nodes # Visit a VarField node. @@ -428,7 +428,7 @@ class Visitor < BasicVisitor # Visit a When node. alias visit_when visit_child_nodes - # Visit a While node. + # Visit a WhileNode node. alias visit_while visit_child_nodes # Visit a Word node. @@ -446,7 +446,7 @@ class Visitor < BasicVisitor # Visit a XStringLiteral node. alias visit_xstring_literal visit_child_nodes - # Visit a Yield node. + # Visit a YieldNode node. alias visit_yield visit_child_nodes # Visit a ZSuper node. diff --git a/lib/syntax_tree/visitor/field_visitor.rb b/lib/syntax_tree/visitor/field_visitor.rb index b56d771c..6e643e09 100644 --- a/lib/syntax_tree/visitor/field_visitor.rb +++ b/lib/syntax_tree/visitor/field_visitor.rb @@ -684,8 +684,8 @@ def visit_qwords_beg(node) node(node, "qwords_beg") { field("value", node.value) } end - def visit_range_literal(node) - node(node, "range_literal") do + def visit_range(node) + node(node, "range") do field("left", node.left) if node.left field("operator", node.operator) field("right", node.right) if node.right diff --git a/lib/syntax_tree/visitor/mutation_visitor.rb b/lib/syntax_tree/visitor/mutation_visitor.rb index 6e7d4ff2..65f8c5ba 100644 --- a/lib/syntax_tree/visitor/mutation_visitor.rb +++ b/lib/syntax_tree/visitor/mutation_visitor.rb @@ -60,7 +60,7 @@ def visit___end__(node) node.copy end - # Visit a Alias node. + # Visit a AliasNode node. def visit_alias(node) node.copy(left: visit(node.left), right: visit(node.right)) end @@ -300,8 +300,8 @@ def visit_block(node) ) end - # Visit a RangeLiteral node. - def visit_range_literal(node) + # Visit a RangeNode node. + def visit_range(node) node.copy( left: visit(node.left), operator: visit(node.operator), @@ -435,7 +435,7 @@ def visit_ident(node) node.copy end - # Visit a If node. + # Visit a IfNode node. def visit_if(node) node.copy( predicate: visit(node.predicate), @@ -823,7 +823,7 @@ def visit_undef(node) node.copy(symbols: visit_all(node.symbols)) end - # Visit a Unless node. + # Visit a UnlessNode node. def visit_unless(node) node.copy( predicate: visit(node.predicate), @@ -832,7 +832,7 @@ def visit_unless(node) ) end - # Visit a Until node. + # Visit a UntilNode node. def visit_until(node) node.copy( predicate: visit(node.predicate), @@ -874,7 +874,7 @@ def visit_when(node) ) end - # Visit a While node. + # Visit a WhileNode node. def visit_while(node) node.copy( predicate: visit(node.predicate), @@ -910,7 +910,7 @@ def visit_xstring_literal(node) node.copy(parts: visit_all(node.parts)) end - # Visit a Yield node. + # Visit a YieldNode node. def visit_yield(node) node.copy(arguments: visit(node.arguments)) end diff --git a/test/mutation_test.rb b/test/mutation_test.rb index ab607beb..ab9dd019 100644 --- a/test/mutation_test.rb +++ b/test/mutation_test.rb @@ -25,7 +25,7 @@ def test_mutates_based_on_patterns def build_mutation SyntaxTree.mutation do |mutation| - mutation.mutate("If[predicate: Assign | OpAssign]") do |node| + mutation.mutate("IfNode[predicate: Assign | OpAssign]") do |node| # Get the existing If's predicate node predicate = node.predicate diff --git a/test/node_test.rb b/test/node_test.rb index cbfc6173..15826be0 100644 --- a/test/node_test.rb +++ b/test/node_test.rb @@ -32,7 +32,7 @@ def test___end__ end def test_alias - assert_node(Alias, "alias left right") + assert_node(AliasNode, "alias left right") end def test_aref @@ -276,7 +276,7 @@ def test_brace_block source = "method { |variable| variable + 1 }" at = location(chars: 7..34) - assert_node(Block, source, at: at, &:block) + assert_node(BlockNode, source, at: at, &:block) end def test_break @@ -284,7 +284,7 @@ def test_break end def test_call - assert_node(Call, "receiver.message") + assert_node(CallNode, "receiver.message") end def test_case @@ -365,7 +365,7 @@ def test_cvar end def test_def - assert_node(Def, "def method(param) result end") + assert_node(DefNode, "def method(param) result end") end def test_def_paramless @@ -374,18 +374,18 @@ def method end SOURCE - assert_node(Def, source) + assert_node(DefNode, source) end guard_version("3.0.0") do def test_def_endless - assert_node(Def, "def method = result") + assert_node(DefNode, "def method = result") end end guard_version("3.1.0") do def test_def_endless_command - assert_node(Def, "def method = result argument") + assert_node(DefNode, "def method = result argument") end end @@ -394,7 +394,7 @@ def test_defined end def test_defs - assert_node(Def, "def object.method(param) result end") + assert_node(DefNode, "def object.method(param) result end") end def test_defs_paramless @@ -403,22 +403,22 @@ def object.method end SOURCE - assert_node(Def, source) + assert_node(DefNode, source) end def test_do_block source = "method do |variable| variable + 1 end" at = location(chars: 7..37) - assert_node(Block, source, at: at, &:block) + assert_node(BlockNode, source, at: at, &:block) end def test_dot2 - assert_node(RangeLiteral, "1..3") + assert_node(RangeNode, "1..3") end def test_dot3 - assert_node(RangeLiteral, "1...3") + assert_node(RangeNode, "1...3") end def test_dyna_symbol @@ -487,7 +487,7 @@ def test_excessed_comma end def test_fcall - assert_node(Call, "method(argument)") + assert_node(CallNode, "method(argument)") end def test_field @@ -575,7 +575,7 @@ def test_ident end def test_if - assert_node(If, "if value then else end") + assert_node(IfNode, "if value then else end") end def test_if_op @@ -583,7 +583,7 @@ def test_if_op end def test_if_mod - assert_node(If, "expression if predicate") + assert_node(IfNode, "expression if predicate") end def test_imaginary @@ -837,11 +837,11 @@ def test_retry end def test_return - assert_node(Return, "return value") + assert_node(ReturnNode, "return value") end def test_return0 - assert_node(Return, "return") + assert_node(ReturnNode, "return") end def test_sclass @@ -923,19 +923,23 @@ def test_undef end def test_unless - assert_node(Unless, "unless value then else end") + assert_node(UnlessNode, "unless value then else end") + end + + def test_unless_mod + assert_node(UnlessNode, "expression unless predicate") end def test_until - assert_node(Until, "until value do end") + assert_node(UntilNode, "until value do end") end def test_until_mod - assert_node(Until, "expression until predicate") + assert_node(UntilNode, "expression until predicate") end def test_var_alias - assert_node(Alias, "alias $new $old") + assert_node(AliasNode, "alias $new $old") end def test_var_field @@ -977,11 +981,11 @@ def test_when end def test_while - assert_node(While, "while value do end") + assert_node(WhileNode, "while value do end") end def test_while_mod - assert_node(While, "expression while predicate") + assert_node(WhileNode, "expression while predicate") end def test_word @@ -1009,11 +1013,11 @@ def test_xstring_heredoc end def test_yield - assert_node(Yield, "yield value") + assert_node(YieldNode, "yield value") end def test_yield0 - assert_node(Yield, "yield") + assert_node(YieldNode, "yield") end def test_zsuper From 8faf11edfd407237c1eb07420bef0bb9a395c121 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 9 Nov 2022 11:58:05 -0500 Subject: [PATCH 31/35] Make the test suite silent --- test/ractor_test.rb | 21 ++++++++++++++++++--- test/rake_test.rb | 7 +++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/test/ractor_test.rb b/test/ractor_test.rb index e697b48e..bcdb2a51 100644 --- a/test/ractor_test.rb +++ b/test/ractor_test.rb @@ -20,12 +20,14 @@ def test_formatting source = SyntaxTree.read(filepath) program = SyntaxTree.parse(source) - Ractor.new(source, program, name: filepath) do |source, program| - SyntaxTree::Formatter.format(source, program) + with_silenced_warnings do + Ractor.new(source, program, name: filepath) do |source, program| + SyntaxTree::Formatter.format(source, program) + end end end - ractors.each(&:take) + ractors.each { |ractor| assert_kind_of String, ractor.take } end private @@ -33,5 +35,18 @@ def test_formatting def filepaths Dir.glob(File.expand_path("../lib/syntax_tree/{node,parser}.rb", __dir__)) end + + # Ractors still warn about usage, so I'm disabling that warning here just to + # have clean test output. + def with_silenced_warnings + previous = $VERBOSE + + begin + $VERBOSE = nil + yield + ensure + $VERBOSE = previous + end + end end end diff --git a/test/rake_test.rb b/test/rake_test.rb index d07fc49c..90662519 100644 --- a/test/rake_test.rb +++ b/test/rake_test.rb @@ -46,12 +46,11 @@ def invoke(task_name) invocation = nil stub = ->(args) { invocation = Invocation.new(args) } - begin + assert_raises SystemExit do SyntaxTree::CLI.stub(:run, stub) { ::Rake::Task[task_name].invoke } - flunk - rescue SystemExit - invocation end + + invocation end end end From a1981d70011efa9e7c8a5b97f121635df5cbbeee Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 9 Nov 2022 12:07:43 -0500 Subject: [PATCH 32/35] Document ignoring code --- README.md | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 050877ee..a6b01362 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,8 @@ It is built with only standard library dependencies. It additionally ships with - [textDocument/formatting](#textdocumentformatting) - [textDocument/inlayHint](#textdocumentinlayhint) - [syntaxTree/visualizing](#syntaxtreevisualizing) -- [Plugins](#plugins) - - [Customization](#customization) +- [Customization](#customization) + - [Plugins](#plugins) - [Languages](#languages) - [Integration](#integration) - [Rake](#rake) @@ -320,6 +320,10 @@ Baked into this syntax is the ability to provide exceptions to file name pattern stree write "**/{[!schema]*,*}.rb" ``` +## Formatting + + + ## Library Syntax Tree can be used as a library to access the syntax tree underlying Ruby source code. @@ -619,18 +623,45 @@ Implicity, the `2 * 3` is going to be executed first because the `*` operator ha The language server additionally includes this custom request to return a textual representation of the syntax tree underlying the source code of a file. Language server clients can use this to (for example) open an additional tab with this information displayed. -## Plugins +## Customization + +There are multiple ways to customize Syntax Tree's behavior when parsing and formatting code. You can ignore certain sections of the source code, you can register plugins to provide custom formatting behavior, and you can register additional languages to be parsed and formatted. + +### Ignoring code + +To ignore a section of source code, you can a special `# stree-ignore` comment. This comment should be placed immediately above the code that you want to ignore. For example: + +```ruby +numbers = [ + 10000, + 20000, + 30000 +] +``` + +Normally the snippet above would be formatted as `numbers = [10_000, 20_000, 30_000]`. However, sometimes you want to keep the original formatting to improve readability or maintainability. In that case, you can put the ignore comment before it, as in: + +```ruby +# stree-ignore +numbers = [ + 10000, + 20000, + 30000 +] +``` + +Now when Syntax Tree goes to format that code, it will copy the source code exactly as it is, including the newlines and indentation. -You can register additional customization and additional languages that can flow through the same CLI with Syntax Tree's plugin system. When invoking the CLI, you pass through the list of plugins with the `--plugins` options to the commands that accept them. They should be a comma-delimited list. When the CLI first starts, it will require the files corresponding to those names. +### Plugins -### Customization +You can register additional customization that can flow through the same CLI with Syntax Tree's plugin system. When invoking the CLI, you pass through the list of plugins with the `--plugins` options to the commands that accept them. They should be a comma-delimited list. When the CLI first starts, it will require the files corresponding to those names. -To register additional customization, define a file somewhere in your load path named `syntax_tree/my_plugin`. Then when invoking the CLI, you will pass `--plugins=my_plugin`. To require multiple, separate them by a comma. In this way, you can modify Syntax Tree however you would like. Some plugins ship with Syntax Tree itself. They are: +To register plugins, define a file somewhere in your load path named `syntax_tree/my_plugin`. Then when invoking the CLI, you will pass `--plugins=my_plugin`. To require multiple, separate them by a comma. In this way, you can modify Syntax Tree however you would like. Some plugins ship with Syntax Tree itself. They are: * `plugin/single_quotes` - This will change all of your string literals to use single quotes instead of the default double quotes. * `plugin/trailing_comma` - This will put trailing commas into multiline array literals, hash literals, and method calls that can support trailing commas. -If you're using Syntax Tree as a library, you should require those files directly. +If you're using Syntax Tree as a library, you can require those files directly or manually pass those options to the formatter initializer through the `SyntaxTree::Formatter::Options` class. ### Languages From cdede9bed6fd0951d92c4587a2fe691c79e87b4c Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 9 Nov 2022 12:13:43 -0500 Subject: [PATCH 33/35] Update documentation in the README --- README.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index a6b01362..db047bb1 100644 --- a/README.md +++ b/README.md @@ -42,11 +42,13 @@ It is built with only standard library dependencies. It additionally ships with - [visit_method](#visit_method) - [BasicVisitor](#basicvisitor) - [MutationVisitor](#mutationvisitor) + - [WithEnvironment](#withenvironment) - [Language server](#language-server) - [textDocument/formatting](#textdocumentformatting) - [textDocument/inlayHint](#textdocumentinlayhint) - [syntaxTree/visualizing](#syntaxtreevisualizing) - [Customization](#customization) + - [Ignoring code](#ignoring-code) - [Plugins](#plugins) - [Languages](#languages) - [Integration](#integration) @@ -320,10 +322,6 @@ Baked into this syntax is the ability to provide exceptions to file name pattern stree write "**/{[!schema]*,*}.rb" ``` -## Formatting - - - ## Library Syntax Tree can be used as a library to access the syntax tree underlying Ruby source code. @@ -580,13 +578,13 @@ class MyVisitor < Visitor include WithEnvironment def visit_ident(node) - # find_local will return a Local for any local variables or arguments present in the current environment or nil if - # the identifier is not a local + # find_local will return a Local for any local variables or arguments + # present in the current environment or nil if the identifier is not a local local = current_environment.find_local(node) - puts local.type # print the type of the local (:variable or :argument) - puts local.definitions # print the array of locations where this local is defined - puts local.usages # print the array of locations where this local occurs + puts local.type # the type of the local (:variable or :argument) + puts local.definitions # the array of locations where this local is defined + puts local.usages # the array of locations where this local occurs end end ``` From a651a4e8acbf4b338e97c950ec26034f917a19c9 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 9 Nov 2022 12:14:57 -0500 Subject: [PATCH 34/35] Fix typos in READMe --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index db047bb1..0f1b626a 100644 --- a/README.md +++ b/README.md @@ -627,7 +627,7 @@ There are multiple ways to customize Syntax Tree's behavior when parsing and for ### Ignoring code -To ignore a section of source code, you can a special `# stree-ignore` comment. This comment should be placed immediately above the code that you want to ignore. For example: +To ignore a section of source code, you can use a special `# stree-ignore` comment. This comment should be placed immediately above the code that you want to ignore. For example: ```ruby numbers = [ From 64f045bafcb66f6c7459b1c1e8069ad1f1787347 Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 9 Nov 2022 12:18:59 -0500 Subject: [PATCH 35/35] Bump to v5.0.0 --- CHANGELOG.md | 5 ++++- Gemfile.lock | 2 +- lib/syntax_tree/version.rb | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e4783e4..034fe2b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ## [Unreleased] +## [5.0.0] - 2022-11-09 + ### Added - Every node now implements the `#copy(**)` method, which provides a copy of the node with the given attributes replaced. @@ -448,7 +450,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a - 🎉 Initial release! 🎉 -[unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v4.3.0...HEAD +[unreleased]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v5.0.0...HEAD +[5.0.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v4.3.0...v5.0.0 [4.3.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v4.2.0...v4.3.0 [4.2.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v4.1.0...v4.2.0 [4.1.0]: https://github.com/ruby-syntax-tree/syntax_tree/compare/v4.0.2...v4.1.0 diff --git a/Gemfile.lock b/Gemfile.lock index 351c842a..d9067ba9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - syntax_tree (4.3.0) + syntax_tree (5.0.0) prettier_print (>= 1.1.0) GEM diff --git a/lib/syntax_tree/version.rb b/lib/syntax_tree/version.rb index a12c472d..29a413d9 100644 --- a/lib/syntax_tree/version.rb +++ b/lib/syntax_tree/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module SyntaxTree - VERSION = "4.3.0" + VERSION = "5.0.0" end