syntax_tree 5.3.0 → 6.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -1
  3. data/CHANGELOG.md +78 -1
  4. data/Gemfile.lock +7 -7
  5. data/README.md +33 -9
  6. data/Rakefile +12 -8
  7. data/bin/console +1 -0
  8. data/bin/whitequark +79 -0
  9. data/doc/changing_structure.md +16 -0
  10. data/lib/syntax_tree/basic_visitor.rb +44 -5
  11. data/lib/syntax_tree/cli.rb +2 -2
  12. data/lib/syntax_tree/dsl.rb +23 -11
  13. data/lib/syntax_tree/{visitor/field_visitor.rb → field_visitor.rb} +54 -55
  14. data/lib/syntax_tree/formatter.rb +1 -1
  15. data/lib/syntax_tree/index.rb +158 -59
  16. data/lib/syntax_tree/json_visitor.rb +55 -0
  17. data/lib/syntax_tree/language_server.rb +157 -2
  18. data/lib/syntax_tree/match_visitor.rb +120 -0
  19. data/lib/syntax_tree/mermaid.rb +177 -0
  20. data/lib/syntax_tree/mermaid_visitor.rb +69 -0
  21. data/lib/syntax_tree/{visitor/mutation_visitor.rb → mutation_visitor.rb} +27 -27
  22. data/lib/syntax_tree/node.rb +245 -123
  23. data/lib/syntax_tree/parser.rb +332 -119
  24. data/lib/syntax_tree/pretty_print_visitor.rb +83 -0
  25. data/lib/syntax_tree/reflection.rb +241 -0
  26. data/lib/syntax_tree/translation/parser.rb +3107 -0
  27. data/lib/syntax_tree/translation/rubocop_ast.rb +21 -0
  28. data/lib/syntax_tree/translation.rb +28 -0
  29. data/lib/syntax_tree/version.rb +1 -1
  30. data/lib/syntax_tree/with_scope.rb +244 -0
  31. data/lib/syntax_tree/yarv/basic_block.rb +53 -0
  32. data/lib/syntax_tree/yarv/calldata.rb +91 -0
  33. data/lib/syntax_tree/yarv/compiler.rb +110 -100
  34. data/lib/syntax_tree/yarv/control_flow_graph.rb +257 -0
  35. data/lib/syntax_tree/yarv/data_flow_graph.rb +338 -0
  36. data/lib/syntax_tree/yarv/decompiler.rb +1 -1
  37. data/lib/syntax_tree/yarv/disassembler.rb +104 -80
  38. data/lib/syntax_tree/yarv/instruction_sequence.rb +43 -18
  39. data/lib/syntax_tree/yarv/instructions.rb +203 -649
  40. data/lib/syntax_tree/yarv/legacy.rb +12 -24
  41. data/lib/syntax_tree/yarv/sea_of_nodes.rb +534 -0
  42. data/lib/syntax_tree/yarv.rb +18 -0
  43. data/lib/syntax_tree.rb +88 -56
  44. data/tasks/sorbet.rake +277 -0
  45. data/tasks/whitequark.rake +87 -0
  46. metadata +23 -11
  47. data/.gitmodules +0 -9
  48. data/lib/syntax_tree/language_server/inlay_hints.rb +0 -159
  49. data/lib/syntax_tree/visitor/environment.rb +0 -84
  50. data/lib/syntax_tree/visitor/json_visitor.rb +0 -55
  51. data/lib/syntax_tree/visitor/match_visitor.rb +0 -122
  52. data/lib/syntax_tree/visitor/pretty_print_visitor.rb +0 -85
  53. data/lib/syntax_tree/visitor/with_environment.rb +0 -140
@@ -126,18 +126,28 @@ module SyntaxTree
126
126
  raise NotImplementedError
127
127
  end
128
128
 
129
+ def start_char
130
+ location.start_char
131
+ end
132
+
133
+ def end_char
134
+ location.end_char
135
+ end
136
+
129
137
  def pretty_print(q)
130
- visitor = Visitor::PrettyPrintVisitor.new(q)
131
- visitor.visit(self)
138
+ accept(PrettyPrintVisitor.new(q))
132
139
  end
133
140
 
134
141
  def to_json(*opts)
135
- visitor = Visitor::JSONVisitor.new
136
- visitor.visit(self).to_json(*opts)
142
+ accept(JSONVisitor.new).to_json(*opts)
143
+ end
144
+
145
+ def to_mermaid
146
+ accept(MermaidVisitor.new)
137
147
  end
138
148
 
139
149
  def construct_keys
140
- PrettierPrint.format(+"") { |q| Visitor::MatchVisitor.new(q).visit(self) }
150
+ PrettierPrint.format(+"") { |q| accept(MatchVisitor.new(q)) }
141
151
  end
142
152
  end
143
153
 
@@ -555,7 +565,7 @@ module SyntaxTree
555
565
  # collection[]
556
566
  #
557
567
  class ARef < Node
558
- # [untyped] the value being indexed
568
+ # [Node] the value being indexed
559
569
  attr_reader :collection
560
570
 
561
571
  # [nil | Args] the value being passed within the brackets
@@ -633,7 +643,7 @@ module SyntaxTree
633
643
  # collection[index] = value
634
644
  #
635
645
  class ARefField < Node
636
- # [untyped] the value being indexed
646
+ # [Node] the value being indexed
637
647
  attr_reader :collection
638
648
 
639
649
  # [nil | Args] the value being passed within the brackets
@@ -808,7 +818,7 @@ module SyntaxTree
808
818
  # method(first, second, third)
809
819
  #
810
820
  class Args < Node
811
- # [Array[ untyped ]] the arguments that this node wraps
821
+ # [Array[ Node ]] the arguments that this node wraps
812
822
  attr_reader :parts
813
823
 
814
824
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -874,7 +884,7 @@ module SyntaxTree
874
884
  # method(&expression)
875
885
  #
876
886
  class ArgBlock < Node
877
- # [nil | untyped] the expression being turned into a block
887
+ # [nil | Node] the expression being turned into a block
878
888
  attr_reader :value
879
889
 
880
890
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -926,7 +936,7 @@ module SyntaxTree
926
936
  # method(*arguments)
927
937
  #
928
938
  class ArgStar < Node
929
- # [nil | untyped] the expression being splatted
939
+ # [nil | Node] the expression being splatted
930
940
  attr_reader :value
931
941
 
932
942
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -1129,7 +1139,8 @@ module SyntaxTree
1129
1139
  end
1130
1140
  end
1131
1141
 
1132
- # [LBracket] the bracket that opens this array
1142
+ # [nil | LBracket | QSymbolsBeg | QWordsBeg | SymbolsBeg | WordsBeg] the
1143
+ # bracket that opens this array
1133
1144
  attr_reader :lbracket
1134
1145
 
1135
1146
  # [nil | Args] the contents of the array
@@ -1287,7 +1298,7 @@ module SyntaxTree
1287
1298
  # [nil | VarRef] the optional constant wrapper
1288
1299
  attr_reader :constant
1289
1300
 
1290
- # [Array[ untyped ]] the regular positional arguments that this array
1301
+ # [Array[ Node ]] the regular positional arguments that this array
1291
1302
  # pattern is matching against
1292
1303
  attr_reader :requireds
1293
1304
 
@@ -1295,7 +1306,7 @@ module SyntaxTree
1295
1306
  # positional arguments
1296
1307
  attr_reader :rest
1297
1308
 
1298
- # [Array[ untyped ]] the list of positional arguments occurring after the
1309
+ # [Array[ Node ]] the list of positional arguments occurring after the
1299
1310
  # optional star if there is one
1300
1311
  attr_reader :posts
1301
1312
 
@@ -1405,7 +1416,7 @@ module SyntaxTree
1405
1416
  # to assign the result of the expression to
1406
1417
  attr_reader :target
1407
1418
 
1408
- # [untyped] the expression to be assigned
1419
+ # [Node] the expression to be assigned
1409
1420
  attr_reader :value
1410
1421
 
1411
1422
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -1480,10 +1491,10 @@ module SyntaxTree
1480
1491
  #
1481
1492
  # In the above example, the would be two Assoc nodes.
1482
1493
  class Assoc < Node
1483
- # [untyped] the key of this pair
1494
+ # [Node] the key of this pair
1484
1495
  attr_reader :key
1485
1496
 
1486
- # [untyped] the value of this pair
1497
+ # [nil | Node] the value of this pair
1487
1498
  attr_reader :value
1488
1499
 
1489
1500
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -1537,7 +1548,7 @@ module SyntaxTree
1537
1548
  private
1538
1549
 
1539
1550
  def format_contents(q)
1540
- q.parent.format_key(q, key)
1551
+ (q.parent || HashKeyFormatter::Identity.new).format_key(q, key)
1541
1552
  return unless value
1542
1553
 
1543
1554
  if key.comments.empty? && AssignFormatting.skip_indent?(value)
@@ -1558,7 +1569,7 @@ module SyntaxTree
1558
1569
  # { **pairs }
1559
1570
  #
1560
1571
  class AssocSplat < Node
1561
- # [nil | untyped] the expression that is being splatted
1572
+ # [nil | Node] the expression that is being splatted
1562
1573
  attr_reader :value
1563
1574
 
1564
1575
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -1754,14 +1765,40 @@ module SyntaxTree
1754
1765
  end
1755
1766
  end
1756
1767
 
1757
- def self.for(container)
1758
- labels =
1759
- container.assocs.all? do |assoc|
1760
- next true if assoc.is_a?(AssocSplat)
1768
+ # When formatting a single assoc node without the context of the parent
1769
+ # hash, this formatter is used. It uses whatever is present in the node,
1770
+ # because there is nothing to be consistent with.
1771
+ class Identity
1772
+ def format_key(q, key)
1773
+ if key.is_a?(Label)
1774
+ q.format(key)
1775
+ else
1776
+ q.format(key)
1777
+ q.text(" =>")
1778
+ end
1779
+ end
1780
+ end
1761
1781
 
1782
+ def self.for(container)
1783
+ container.assocs.each do |assoc|
1784
+ if assoc.is_a?(AssocSplat)
1785
+ # Splat nodes do not impact the formatting choice.
1786
+ elsif assoc.value.nil?
1787
+ # If the value is nil, then it has been omitted. In this case we have
1788
+ # to match the existing formatting because standardizing would
1789
+ # potentially break the code. For example:
1790
+ #
1791
+ # { first:, "second" => "value" }
1792
+ #
1793
+ return Identity.new
1794
+ else
1795
+ # Otherwise, we need to check the type of the key. If it's a label or
1796
+ # dynamic symbol, we can use labels. If it's a symbol literal then it
1797
+ # needs to match a certain pattern to be used as a label. If it's
1798
+ # anything else, then we need to use hash rockets.
1762
1799
  case assoc.key
1763
- when Label
1764
- true
1800
+ when Label, DynaSymbol
1801
+ # Here labels can be used.
1765
1802
  when SymbolLiteral
1766
1803
  # When attempting to convert a hash rocket into a hash label,
1767
1804
  # you need to take care because only certain patterns are
@@ -1769,15 +1806,18 @@ module SyntaxTree
1769
1806
  # arguments to methods, but don't specify what that is. After
1770
1807
  # some experimentation, it looks like it's:
1771
1808
  value = assoc.key.value.value
1772
- value.match?(/^[_A-Za-z]/) && !value.end_with?("=")
1773
- when DynaSymbol
1774
- true
1809
+
1810
+ if !value.match?(/^[_A-Za-z]/) || value.end_with?("=")
1811
+ return Rockets.new
1812
+ end
1775
1813
  else
1776
- false
1814
+ # If the value is anything else, we have to use hash rockets.
1815
+ return Rockets.new
1777
1816
  end
1778
1817
  end
1818
+ end
1779
1819
 
1780
- (labels ? Labels : Rockets).new
1820
+ Labels.new
1781
1821
  end
1782
1822
  end
1783
1823
 
@@ -1834,7 +1874,15 @@ module SyntaxTree
1834
1874
  end
1835
1875
 
1836
1876
  def format_key(q, key)
1837
- (@key_formatter ||= HashKeyFormatter.for(self)).format_key(q, key)
1877
+ @key_formatter ||=
1878
+ case q.parents.take(3).last
1879
+ when Break, Next, ReturnNode
1880
+ HashKeyFormatter::Identity.new
1881
+ else
1882
+ HashKeyFormatter.for(self)
1883
+ end
1884
+
1885
+ @key_formatter.format_key(q, key)
1838
1886
  end
1839
1887
  end
1840
1888
 
@@ -1908,7 +1956,7 @@ module SyntaxTree
1908
1956
  # end
1909
1957
  #
1910
1958
  class PinnedBegin < Node
1911
- # [untyped] the expression being pinned
1959
+ # [Node] the expression being pinned
1912
1960
  attr_reader :statement
1913
1961
 
1914
1962
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -1989,13 +2037,13 @@ module SyntaxTree
1989
2037
  }
1990
2038
  end
1991
2039
 
1992
- # [untyped] the left-hand side of the expression
2040
+ # [Node] the left-hand side of the expression
1993
2041
  attr_reader :left
1994
2042
 
1995
2043
  # [Symbol] the operator used between the two expressions
1996
2044
  attr_reader :operator
1997
2045
 
1998
- # [untyped] the right-hand side of the expression
2046
+ # [Node] the right-hand side of the expression
1999
2047
  attr_reader :right
2000
2048
 
2001
2049
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -2049,10 +2097,15 @@ module SyntaxTree
2049
2097
  q.group { q.format(left) }
2050
2098
  q.text(" ") unless power
2051
2099
 
2052
- if operator == :<<
2053
- q.text("<< ")
2054
- q.format(right)
2055
- else
2100
+ if operator != :<<
2101
+ q.group do
2102
+ q.text(operator.name)
2103
+ q.indent do
2104
+ power ? q.breakable_empty : q.breakable_space
2105
+ q.format(right)
2106
+ end
2107
+ end
2108
+ elsif left.is_a?(Binary) && left.operator == :<<
2056
2109
  q.group do
2057
2110
  q.text(operator.name)
2058
2111
  q.indent do
@@ -2060,6 +2113,9 @@ module SyntaxTree
2060
2113
  q.format(right)
2061
2114
  end
2062
2115
  end
2116
+ else
2117
+ q.text("<< ")
2118
+ q.format(right)
2063
2119
  end
2064
2120
  end
2065
2121
  end
@@ -2149,6 +2205,14 @@ module SyntaxTree
2149
2205
  other.is_a?(BlockVar) && params === other.params &&
2150
2206
  ArrayMatch.call(locals, other.locals)
2151
2207
  end
2208
+
2209
+ # When a single required parameter is declared for a block, it gets
2210
+ # automatically expanded if the values being yielded into it are an array.
2211
+ def arg0?
2212
+ params.requireds.length == 1 && params.optionals.empty? &&
2213
+ params.rest.nil? && params.posts.empty? && params.keywords.empty? &&
2214
+ params.keyword_rest.nil? && params.block.nil?
2215
+ end
2152
2216
  end
2153
2217
 
2154
2218
  # BlockArg represents declaring a block parameter on a method definition.
@@ -2242,7 +2306,7 @@ module SyntaxTree
2242
2306
  @comments = []
2243
2307
  end
2244
2308
 
2245
- def bind(start_char, start_column, end_char, end_column)
2309
+ def bind(parser, start_char, start_column, end_char, end_column)
2246
2310
  @location =
2247
2311
  Location.new(
2248
2312
  start_line: location.start_line,
@@ -2256,6 +2320,7 @@ module SyntaxTree
2256
2320
  # Here we're going to determine the bounds for the statements
2257
2321
  consequent = rescue_clause || else_clause || ensure_clause
2258
2322
  statements.bind(
2323
+ parser,
2259
2324
  start_char,
2260
2325
  start_column,
2261
2326
  consequent ? consequent.location.start_char : end_char,
@@ -2646,7 +2711,7 @@ module SyntaxTree
2646
2711
  # Of course there are a lot of caveats to that, including trailing operators
2647
2712
  # when necessary, where comments are places, how blocks are aligned, etc.
2648
2713
  class CallChainFormatter
2649
- # [Call | MethodAddBlock] the top of the call chain
2714
+ # [CallNode | MethodAddBlock] the top of the call chain
2650
2715
  attr_reader :node
2651
2716
 
2652
2717
  def initialize(node)
@@ -2867,7 +2932,7 @@ module SyntaxTree
2867
2932
  # receiver.message
2868
2933
  #
2869
2934
  class CallNode < Node
2870
- # [nil | untyped] the receiver of the method call
2935
+ # [nil | Node] the receiver of the method call
2871
2936
  attr_reader :receiver
2872
2937
 
2873
2938
  # [nil | :"::" | Op | Period] the operator being used to send the message
@@ -3043,7 +3108,7 @@ module SyntaxTree
3043
3108
  # [Kw] the keyword that opens this expression
3044
3109
  attr_reader :keyword
3045
3110
 
3046
- # [nil | untyped] optional value being switched on
3111
+ # [nil | Node] optional value being switched on
3047
3112
  attr_reader :value
3048
3113
 
3049
3114
  # [In | When] the next clause in the chain
@@ -3122,14 +3187,14 @@ module SyntaxTree
3122
3187
  # value => pattern
3123
3188
  #
3124
3189
  class RAssign < Node
3125
- # [untyped] the left-hand expression
3190
+ # [Node] the left-hand expression
3126
3191
  attr_reader :value
3127
3192
 
3128
3193
  # [Kw | Op] the operator being used to match against the pattern, which is
3129
3194
  # either => or in
3130
3195
  attr_reader :operator
3131
3196
 
3132
- # [untyped] the pattern on the right-hand side of the expression
3197
+ # [Node] the pattern on the right-hand side of the expression
3133
3198
  attr_reader :pattern
3134
3199
 
3135
3200
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -3240,7 +3305,7 @@ module SyntaxTree
3240
3305
  # defined
3241
3306
  attr_reader :constant
3242
3307
 
3243
- # [nil | untyped] the optional superclass declaration
3308
+ # [nil | Node] the optional superclass declaration
3244
3309
  attr_reader :superclass
3245
3310
 
3246
3311
  # [BodyStmt] the expressions to execute within the context of the class
@@ -3378,7 +3443,7 @@ module SyntaxTree
3378
3443
  # [Args] the arguments being sent with the message
3379
3444
  attr_reader :arguments
3380
3445
 
3381
- # [nil | Block] the optional block being passed to the method
3446
+ # [nil | BlockNode] the optional block being passed to the method
3382
3447
  attr_reader :block
3383
3448
 
3384
3449
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -3484,19 +3549,19 @@ module SyntaxTree
3484
3549
  # object.method argument
3485
3550
  #
3486
3551
  class CommandCall < Node
3487
- # [untyped] the receiver of the message
3552
+ # [nil | Node] the receiver of the message
3488
3553
  attr_reader :receiver
3489
3554
 
3490
- # [:"::" | Op | Period] the operator used to send the message
3555
+ # [nil | :"::" | Op | Period] the operator used to send the message
3491
3556
  attr_reader :operator
3492
3557
 
3493
- # [Const | Ident | Op] the message being send
3558
+ # [:call | Const | Ident | Op] the message being send
3494
3559
  attr_reader :message
3495
3560
 
3496
- # [nil | Args] the arguments going along with the message
3561
+ # [nil | Args | ArgParen] the arguments going along with the message
3497
3562
  attr_reader :arguments
3498
3563
 
3499
- # [nil | Block] the block associated with this method call
3564
+ # [nil | BlockNode] the block associated with this method call
3500
3565
  attr_reader :block
3501
3566
 
3502
3567
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -3782,7 +3847,7 @@ module SyntaxTree
3782
3847
  # object::Const = value
3783
3848
  #
3784
3849
  class ConstPathField < Node
3785
- # [untyped] the source of the constant
3850
+ # [Node] the source of the constant
3786
3851
  attr_reader :parent
3787
3852
 
3788
3853
  # [Const] the constant itself
@@ -3846,7 +3911,7 @@ module SyntaxTree
3846
3911
  # object::Const
3847
3912
  #
3848
3913
  class ConstPathRef < Node
3849
- # [untyped] the source of the constant
3914
+ # [Node] the source of the constant
3850
3915
  attr_reader :parent
3851
3916
 
3852
3917
  # [Const] the constant itself
@@ -4015,7 +4080,7 @@ module SyntaxTree
4015
4080
  # def object.method(param) result end
4016
4081
  #
4017
4082
  class DefNode < Node
4018
- # [nil | untyped] the target where the method is being defined
4083
+ # [nil | Node] the target where the method is being defined
4019
4084
  attr_reader :target
4020
4085
 
4021
4086
  # [nil | Op | Period] the operator being used to declare the method
@@ -4027,7 +4092,7 @@ module SyntaxTree
4027
4092
  # [nil | Params | Paren] the parameter declaration for the method
4028
4093
  attr_reader :params
4029
4094
 
4030
- # [BodyStmt | untyped] the expressions to be executed by the method
4095
+ # [BodyStmt | Node] the expressions to be executed by the method
4031
4096
  attr_reader :bodystmt
4032
4097
 
4033
4098
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -4090,7 +4155,8 @@ module SyntaxTree
4090
4155
  def format(q)
4091
4156
  q.group do
4092
4157
  q.group do
4093
- q.text("def ")
4158
+ q.text("def")
4159
+ q.text(" ") if target || name.comments.empty?
4094
4160
 
4095
4161
  if target
4096
4162
  q.format(target)
@@ -4160,7 +4226,7 @@ module SyntaxTree
4160
4226
  # defined?(variable)
4161
4227
  #
4162
4228
  class Defined < Node
4163
- # [untyped] the value being sent to the keyword
4229
+ # [Node] the value being sent to the keyword
4164
4230
  attr_reader :value
4165
4231
 
4166
4232
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -4317,7 +4383,7 @@ module SyntaxTree
4317
4383
  # are no parentheses around the arguments to that command, so we need to
4318
4384
  # break the block.
4319
4385
  case q.parent
4320
- when Command, CommandCall
4386
+ when nil, Command, CommandCall
4321
4387
  q.break_parent
4322
4388
  format_break(q, break_opening, break_closing)
4323
4389
  return
@@ -4371,7 +4437,7 @@ module SyntaxTree
4371
4437
  # If we're a sibling of a control-flow keyword, then we're going to have to
4372
4438
  # use the do..end bounds.
4373
4439
  def forced_do_end_bounds?(q)
4374
- case q.parent.call
4440
+ case q.parent&.call
4375
4441
  when Break, Next, ReturnNode, Super
4376
4442
  true
4377
4443
  else
@@ -4451,13 +4517,13 @@ module SyntaxTree
4451
4517
  #
4452
4518
  # One of the sides of the expression may be nil, but not both.
4453
4519
  class RangeNode < Node
4454
- # [nil | untyped] the left side of the expression
4520
+ # [nil | Node] the left side of the expression
4455
4521
  attr_reader :left
4456
4522
 
4457
4523
  # [Op] the operator used for this range
4458
4524
  attr_reader :operator
4459
4525
 
4460
- # [nil | untyped] the right side of the expression
4526
+ # [nil | Node] the right side of the expression
4461
4527
  attr_reader :right
4462
4528
 
4463
4529
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -4578,7 +4644,7 @@ module SyntaxTree
4578
4644
  # dynamic symbol
4579
4645
  attr_reader :parts
4580
4646
 
4581
- # [String] the quote used to delimit the dynamic symbol
4647
+ # [nil | String] the quote used to delimit the dynamic symbol
4582
4648
  attr_reader :quote
4583
4649
 
4584
4650
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -4776,7 +4842,7 @@ module SyntaxTree
4776
4842
  # end
4777
4843
  #
4778
4844
  class Elsif < Node
4779
- # [untyped] the expression to be checked
4845
+ # [Node] the expression to be checked
4780
4846
  attr_reader :predicate
4781
4847
 
4782
4848
  # [Statements] the expressions to be executed
@@ -4872,6 +4938,25 @@ module SyntaxTree
4872
4938
  def initialize(value:, location:)
4873
4939
  @value = value
4874
4940
  @location = location
4941
+
4942
+ @leading = false
4943
+ @trailing = false
4944
+ end
4945
+
4946
+ def leading!
4947
+ @leading = true
4948
+ end
4949
+
4950
+ def leading?
4951
+ @leading
4952
+ end
4953
+
4954
+ def trailing!
4955
+ @trailing = true
4956
+ end
4957
+
4958
+ def trailing?
4959
+ @trailing
4875
4960
  end
4876
4961
 
4877
4962
  def inline?
@@ -4908,7 +4993,13 @@ module SyntaxTree
4908
4993
  end
4909
4994
 
4910
4995
  def format(q)
4911
- q.trim
4996
+ if (q.parent.is_a?(DefNode) && q.parent.endless?) ||
4997
+ q.parent.is_a?(Statements)
4998
+ q.trim
4999
+ else
5000
+ q.breakable_return
5001
+ end
5002
+
4912
5003
  q.text(value)
4913
5004
  end
4914
5005
 
@@ -5177,7 +5268,7 @@ module SyntaxTree
5177
5268
  # object.variable = value
5178
5269
  #
5179
5270
  class Field < Node
5180
- # [untyped] the parent object that owns the field being assigned
5271
+ # [Node] the parent object that owns the field being assigned
5181
5272
  attr_reader :parent
5182
5273
 
5183
5274
  # [:"::" | Op | Period] the operator being used for the assignment
@@ -5303,13 +5394,13 @@ module SyntaxTree
5303
5394
  # end
5304
5395
  #
5305
5396
  class FndPtn < Node
5306
- # [nil | untyped] the optional constant wrapper
5397
+ # [nil | Node] the optional constant wrapper
5307
5398
  attr_reader :constant
5308
5399
 
5309
5400
  # [VarField] the splat on the left-hand side
5310
5401
  attr_reader :left
5311
5402
 
5312
- # [Array[ untyped ]] the list of positional expressions in the pattern that
5403
+ # [Array[ Node ]] the list of positional expressions in the pattern that
5313
5404
  # are being matched
5314
5405
  attr_reader :values
5315
5406
 
@@ -5405,7 +5496,7 @@ module SyntaxTree
5405
5496
  # pull values out of the object being enumerated
5406
5497
  attr_reader :index
5407
5498
 
5408
- # [untyped] the object being enumerated in the loop
5499
+ # [Node] the object being enumerated in the loop
5409
5500
  attr_reader :collection
5410
5501
 
5411
5502
  # [Statements] the statements to be executed
@@ -5884,7 +5975,7 @@ module SyntaxTree
5884
5975
  # [Label] the keyword being used
5885
5976
  attr_reader :key
5886
5977
 
5887
- # [untyped] the optional value for the keyword
5978
+ # [Node] the optional value for the keyword
5888
5979
  attr_reader :value
5889
5980
 
5890
5981
  def initialize(key, value)
@@ -5897,7 +5988,7 @@ module SyntaxTree
5897
5988
  end
5898
5989
 
5899
5990
  def format(q)
5900
- q.format(key)
5991
+ HashKeyFormatter::Labels.new.format_key(q, key)
5901
5992
 
5902
5993
  if value
5903
5994
  q.text(" ")
@@ -5925,11 +6016,11 @@ module SyntaxTree
5925
6016
  end
5926
6017
  end
5927
6018
 
5928
- # [nil | untyped] the optional constant wrapper
6019
+ # [nil | Node] the optional constant wrapper
5929
6020
  attr_reader :constant
5930
6021
 
5931
- # [Array[ [Label, untyped] ]] the set of tuples representing the keywords
5932
- # that should be matched against in the pattern
6022
+ # [Array[ [DynaSymbol | Label, nil | Node] ]] the set of tuples
6023
+ # representing the keywords that should be matched against in the pattern
5933
6024
  attr_reader :keywords
5934
6025
 
5935
6026
  # [nil | VarField] an optional parameter to gather up all remaining keywords
@@ -6354,7 +6445,7 @@ module SyntaxTree
6354
6445
  # end
6355
6446
  #
6356
6447
  class IfNode < Node
6357
- # [untyped] the expression to be checked
6448
+ # [Node] the expression to be checked
6358
6449
  attr_reader :predicate
6359
6450
 
6360
6451
  # [Statements] the expressions to be executed
@@ -6427,13 +6518,13 @@ module SyntaxTree
6427
6518
  # predicate ? truthy : falsy
6428
6519
  #
6429
6520
  class IfOp < Node
6430
- # [untyped] the expression to be checked
6521
+ # [Node] the expression to be checked
6431
6522
  attr_reader :predicate
6432
6523
 
6433
- # [untyped] the expression to be executed if the predicate is truthy
6524
+ # [Node] the expression to be executed if the predicate is truthy
6434
6525
  attr_reader :truthy
6435
6526
 
6436
- # [untyped] the expression to be executed if the predicate is falsy
6527
+ # [Node] the expression to be executed if the predicate is falsy
6437
6528
  attr_reader :falsy
6438
6529
 
6439
6530
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -6617,7 +6708,7 @@ module SyntaxTree
6617
6708
  # end
6618
6709
  #
6619
6710
  class In < Node
6620
- # [untyped] the pattern to check against
6711
+ # [Node] the pattern to check against
6621
6712
  attr_reader :pattern
6622
6713
 
6623
6714
  # [Statements] the expressions to execute if the pattern matched
@@ -7400,7 +7491,7 @@ module SyntaxTree
7400
7491
  # [MLHS | MLHSParen] the target of the multiple assignment
7401
7492
  attr_reader :target
7402
7493
 
7403
- # [untyped] the value being assigned
7494
+ # [Node] the value being assigned
7404
7495
  attr_reader :value
7405
7496
 
7406
7497
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -7460,10 +7551,10 @@ module SyntaxTree
7460
7551
  # method {}
7461
7552
  #
7462
7553
  class MethodAddBlock < Node
7463
- # [Call | Command | CommandCall] the method call
7554
+ # [ARef | CallNode | Command | CommandCall | Super | ZSuper] the method call
7464
7555
  attr_reader :call
7465
7556
 
7466
- # [Block] the block being sent with the method call
7557
+ # [BlockNode] the block being sent with the method call
7467
7558
  attr_reader :block
7468
7559
 
7469
7560
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -7535,8 +7626,12 @@ module SyntaxTree
7535
7626
  # first, second, third = value
7536
7627
  #
7537
7628
  class MLHS < Node
7538
- # Array[ARefField | ArgStar | Field | Ident | MLHSParen | VarField] the
7539
- # parts of the left-hand side of a multiple assignment
7629
+ # [
7630
+ # Array[
7631
+ # ARefField | ArgStar | ConstPathField | Field | Ident | MLHSParen |
7632
+ # TopConstField | VarField
7633
+ # ]
7634
+ # ] the parts of the left-hand side of a multiple assignment
7540
7635
  attr_reader :parts
7541
7636
 
7542
7637
  # [boolean] whether or not there is a trailing comma at the end of this
@@ -7762,7 +7857,7 @@ module SyntaxTree
7762
7857
  # values = first, second, third
7763
7858
  #
7764
7859
  class MRHS < Node
7765
- # Array[untyped] the parts that are being assigned
7860
+ # [Array[Node]] the parts that are being assigned
7766
7861
  attr_reader :parts
7767
7862
 
7768
7863
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -7938,7 +8033,7 @@ module SyntaxTree
7938
8033
  # [Op] the operator being used for the assignment
7939
8034
  attr_reader :operator
7940
8035
 
7941
- # [untyped] the expression to be assigned
8036
+ # [Node] the expression to be assigned
7942
8037
  attr_reader :value
7943
8038
 
7944
8039
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -8095,7 +8190,7 @@ module SyntaxTree
8095
8190
  # [Ident] the name of the parameter
8096
8191
  attr_reader :name
8097
8192
 
8098
- # [untyped] the value of the parameter
8193
+ # [Node] the value of the parameter
8099
8194
  attr_reader :value
8100
8195
 
8101
8196
  def initialize(name, value)
@@ -8120,7 +8215,7 @@ module SyntaxTree
8120
8215
  # [Ident] the name of the parameter
8121
8216
  attr_reader :name
8122
8217
 
8123
- # [nil | untyped] the value of the parameter
8218
+ # [nil | Node] the value of the parameter
8124
8219
  attr_reader :value
8125
8220
 
8126
8221
  def initialize(name, value)
@@ -8161,10 +8256,10 @@ module SyntaxTree
8161
8256
  end
8162
8257
  end
8163
8258
 
8164
- # [Array[ Ident ]] any required parameters
8259
+ # [Array[ Ident | MLHSParen ]] any required parameters
8165
8260
  attr_reader :requireds
8166
8261
 
8167
- # [Array[ [ Ident, untyped ] ]] any optional parameters and their default
8262
+ # [Array[ [ Ident, Node ] ]] any optional parameters and their default
8168
8263
  # values
8169
8264
  attr_reader :optionals
8170
8265
 
@@ -8176,11 +8271,12 @@ module SyntaxTree
8176
8271
  # parameter
8177
8272
  attr_reader :posts
8178
8273
 
8179
- # [Array[ [ Ident, nil | untyped ] ]] any keyword parameters and their
8274
+ # [Array[ [ Label, nil | Node ] ]] any keyword parameters and their
8180
8275
  # optional default values
8181
8276
  attr_reader :keywords
8182
8277
 
8183
- # [nil | :nil | KwRestParam] the optional keyword rest parameter
8278
+ # [nil | :nil | ArgsForward | KwRestParam] the optional keyword rest
8279
+ # parameter
8184
8280
  attr_reader :keyword_rest
8185
8281
 
8186
8282
  # [nil | BlockArg] the optional block parameter
@@ -8369,7 +8465,7 @@ module SyntaxTree
8369
8465
  # [LParen] the left parenthesis that opened this statement
8370
8466
  attr_reader :lparen
8371
8467
 
8372
- # [nil | untyped] the expression inside the parentheses
8468
+ # [nil | Node] the expression inside the parentheses
8373
8469
  attr_reader :contents
8374
8470
 
8375
8471
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -9218,7 +9314,7 @@ module SyntaxTree
9218
9314
  # end
9219
9315
  #
9220
9316
  class RescueEx < Node
9221
- # [untyped] the list of exceptions being rescued
9317
+ # [nil | Node] the list of exceptions being rescued
9222
9318
  attr_reader :exceptions
9223
9319
 
9224
9320
  # [nil | Field | VarField] the expression being used to capture the raised
@@ -9296,7 +9392,7 @@ module SyntaxTree
9296
9392
  # [Kw] the rescue keyword
9297
9393
  attr_reader :keyword
9298
9394
 
9299
- # [RescueEx] the exceptions being rescued
9395
+ # [nil | RescueEx] the exceptions being rescued
9300
9396
  attr_reader :exception
9301
9397
 
9302
9398
  # [Statements] the expressions to evaluate when an error is rescued
@@ -9416,10 +9512,10 @@ module SyntaxTree
9416
9512
  # expression rescue value
9417
9513
  #
9418
9514
  class RescueMod < Node
9419
- # [untyped] the expression to execute
9515
+ # [Node] the expression to execute
9420
9516
  attr_reader :statement
9421
9517
 
9422
- # [untyped] the value to use if the executed expression raises an error
9518
+ # [Node] the value to use if the executed expression raises an error
9423
9519
  attr_reader :value
9424
9520
 
9425
9521
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -9678,7 +9774,7 @@ module SyntaxTree
9678
9774
  # end
9679
9775
  #
9680
9776
  class SClass < Node
9681
- # [untyped] the target of the singleton class to enter
9777
+ # [Node] the target of the singleton class to enter
9682
9778
  attr_reader :target
9683
9779
 
9684
9780
  # [BodyStmt] the expressions to be executed
@@ -9752,23 +9848,19 @@ module SyntaxTree
9752
9848
  # propagate that onto void_stmt nodes inside the stmts in order to make sure
9753
9849
  # all comments get printed appropriately.
9754
9850
  class Statements < Node
9755
- # [SyntaxTree] the parser that is generating this node
9756
- attr_reader :parser
9757
-
9758
- # [Array[ untyped ]] the list of expressions contained within this node
9851
+ # [Array[ Node ]] the list of expressions contained within this node
9759
9852
  attr_reader :body
9760
9853
 
9761
9854
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
9762
9855
  attr_reader :comments
9763
9856
 
9764
- def initialize(parser, body:, location:)
9765
- @parser = parser
9857
+ def initialize(body:, location:)
9766
9858
  @body = body
9767
9859
  @location = location
9768
9860
  @comments = []
9769
9861
  end
9770
9862
 
9771
- def bind(start_char, start_column, end_char, end_column)
9863
+ def bind(parser, start_char, start_column, end_char, end_column)
9772
9864
  @location =
9773
9865
  Location.new(
9774
9866
  start_line: location.start_line,
@@ -9794,7 +9886,7 @@ module SyntaxTree
9794
9886
  body[0] = VoidStmt.new(location: location)
9795
9887
  end
9796
9888
 
9797
- attach_comments(start_char, end_char)
9889
+ attach_comments(parser, start_char, end_char)
9798
9890
  end
9799
9891
 
9800
9892
  def bind_end(end_char, end_column)
@@ -9826,7 +9918,6 @@ module SyntaxTree
9826
9918
  def copy(body: nil, location: nil)
9827
9919
  node =
9828
9920
  Statements.new(
9829
- parser,
9830
9921
  body: body || self.body,
9831
9922
  location: location || self.location
9832
9923
  )
@@ -9838,7 +9929,7 @@ module SyntaxTree
9838
9929
  alias deconstruct child_nodes
9839
9930
 
9840
9931
  def deconstruct_keys(_keys)
9841
- { parser: parser, body: body, location: location, comments: comments }
9932
+ { body: body, location: location, comments: comments }
9842
9933
  end
9843
9934
 
9844
9935
  def format(q)
@@ -9898,7 +9989,7 @@ module SyntaxTree
9898
9989
  # As efficiently as possible, gather up all of the comments that have been
9899
9990
  # found while this statements list was being parsed and add them into the
9900
9991
  # body.
9901
- def attach_comments(start_char, end_char)
9992
+ def attach_comments(parser, start_char, end_char)
9902
9993
  parser_comments = parser.comments
9903
9994
 
9904
9995
  comment_index = 0
@@ -9945,9 +10036,13 @@ module SyntaxTree
9945
10036
  # string
9946
10037
  attr_reader :parts
9947
10038
 
10039
+ # [Array[ Comment | EmbDoc ]] the comments attached to this node
10040
+ attr_reader :comments
10041
+
9948
10042
  def initialize(parts:, location:)
9949
10043
  @parts = parts
9950
10044
  @location = location
10045
+ @comments = []
9951
10046
  end
9952
10047
 
9953
10048
  def accept(visitor)
@@ -9974,6 +10069,33 @@ module SyntaxTree
9974
10069
  def ===(other)
9975
10070
  other.is_a?(StringContent) && ArrayMatch.call(parts, other.parts)
9976
10071
  end
10072
+
10073
+ def format(q)
10074
+ q.text(q.quote)
10075
+ q.group do
10076
+ parts.each do |part|
10077
+ if part.is_a?(TStringContent)
10078
+ value = Quotes.normalize(part.value, q.quote)
10079
+ first = true
10080
+
10081
+ value.each_line(chomp: true) do |line|
10082
+ if first
10083
+ first = false
10084
+ else
10085
+ q.breakable_return
10086
+ end
10087
+
10088
+ q.text(line)
10089
+ end
10090
+
10091
+ q.breakable_return if value.end_with?("\n")
10092
+ else
10093
+ q.format(part)
10094
+ end
10095
+ end
10096
+ end
10097
+ q.text(q.quote)
10098
+ end
9977
10099
  end
9978
10100
 
9979
10101
  # StringConcat represents concatenating two strings together using a backward
@@ -9983,7 +10105,8 @@ module SyntaxTree
9983
10105
  # "second"
9984
10106
  #
9985
10107
  class StringConcat < Node
9986
- # [StringConcat | StringLiteral] the left side of the concatenation
10108
+ # [Heredoc | StringConcat | StringLiteral] the left side of the
10109
+ # concatenation
9987
10110
  attr_reader :left
9988
10111
 
9989
10112
  # [StringLiteral] the right side of the concatenation
@@ -10180,7 +10303,7 @@ module SyntaxTree
10180
10303
  # string literal
10181
10304
  attr_reader :parts
10182
10305
 
10183
- # [String] which quote was used by the string literal
10306
+ # [nil | String] which quote was used by the string literal
10184
10307
  attr_reader :quote
10185
10308
 
10186
10309
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -10425,8 +10548,8 @@ module SyntaxTree
10425
10548
  # :symbol
10426
10549
  #
10427
10550
  class SymbolLiteral < Node
10428
- # [Backtick | Const | CVar | GVar | Ident | IVar | Kw | Op] the value of the
10429
- # symbol
10551
+ # [Backtick | Const | CVar | GVar | Ident | IVar | Kw | Op | TStringContent]
10552
+ # the value of the symbol
10430
10553
  attr_reader :value
10431
10554
 
10432
10555
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -10465,6 +10588,7 @@ module SyntaxTree
10465
10588
 
10466
10589
  def format(q)
10467
10590
  q.text(":")
10591
+ q.text("\\") if value.comments.any?
10468
10592
  q.format(value)
10469
10593
  end
10470
10594
 
@@ -10934,7 +11058,7 @@ module SyntaxTree
10934
11058
  # not value
10935
11059
  #
10936
11060
  class Not < Node
10937
- # [nil | untyped] the statement on which to operate
11061
+ # [nil | Node] the statement on which to operate
10938
11062
  attr_reader :statement
10939
11063
 
10940
11064
  # [boolean] whether or not parentheses were used
@@ -11021,7 +11145,7 @@ module SyntaxTree
11021
11145
  # [String] the operator being used
11022
11146
  attr_reader :operator
11023
11147
 
11024
- # [untyped] the statement on which to operate
11148
+ # [Node] the statement on which to operate
11025
11149
  attr_reader :statement
11026
11150
 
11027
11151
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -11165,7 +11289,7 @@ module SyntaxTree
11165
11289
  # end
11166
11290
  #
11167
11291
  class UnlessNode < Node
11168
- # [untyped] the expression to be checked
11292
+ # [Node] the expression to be checked
11169
11293
  attr_reader :predicate
11170
11294
 
11171
11295
  # [Statements] the expressions to be executed
@@ -11311,7 +11435,7 @@ module SyntaxTree
11311
11435
  # end
11312
11436
  #
11313
11437
  class UntilNode < Node
11314
- # [untyped] the expression to be checked
11438
+ # [Node] the expression to be checked
11315
11439
  attr_reader :predicate
11316
11440
 
11317
11441
  # [Statements] the expressions to be executed
@@ -11379,7 +11503,7 @@ module SyntaxTree
11379
11503
  #
11380
11504
  # In the example above, the VarField node represents the +variable+ token.
11381
11505
  class VarField < Node
11382
- # [nil | Const | CVar | GVar | Ident | IVar] the target of this node
11506
+ # [nil | :nil | Const | CVar | GVar | Ident | IVar] the target of this node
11383
11507
  attr_reader :value
11384
11508
 
11385
11509
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -11490,8 +11614,9 @@ module SyntaxTree
11490
11614
  #
11491
11615
  # To be clear, this method should just not exist. It's not good. It's a
11492
11616
  # place of shame. But it's necessary for now, so I'm keeping it.
11493
- def pin(parent)
11494
- replace = PinnedVarRef.new(value: value, location: location)
11617
+ def pin(parent, pin)
11618
+ replace =
11619
+ PinnedVarRef.new(value: value, location: pin.location.to(location))
11495
11620
 
11496
11621
  parent
11497
11622
  .deconstruct_keys([])
@@ -11517,7 +11642,7 @@ module SyntaxTree
11517
11642
  # This can be a plain local variable like the example above. It can also be a
11518
11643
  # a class variable, a global variable, or an instance variable.
11519
11644
  class PinnedVarRef < Node
11520
- # [VarRef] the value of this node
11645
+ # [Const | CVar | GVar | Ident | IVar] the value of this node
11521
11646
  attr_reader :value
11522
11647
 
11523
11648
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
@@ -11631,9 +11756,6 @@ module SyntaxTree
11631
11756
  # ;;
11632
11757
  #
11633
11758
  class VoidStmt < Node
11634
- # [Location] the location of this node
11635
- attr_reader :location
11636
-
11637
11759
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
11638
11760
  attr_reader :comments
11639
11761
 
@@ -11794,7 +11916,7 @@ module SyntaxTree
11794
11916
  # end
11795
11917
  #
11796
11918
  class WhileNode < Node
11797
- # [untyped] the expression to be checked
11919
+ # [Node] the expression to be checked
11798
11920
  attr_reader :predicate
11799
11921
 
11800
11922
  # [Statements] the expressions to be executed