prettier 1.5.5 → 2.0.0.pre.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +344 -282
  3. data/CONTRIBUTING.md +8 -11
  4. data/LICENSE +1 -1
  5. data/README.md +30 -12
  6. data/dist/haml/embed.js +53 -0
  7. data/dist/haml/parser.js +31 -0
  8. data/{src → dist}/haml/parser.rb +0 -0
  9. data/dist/haml/printer.js +336 -0
  10. data/dist/parser/getInfo.js +17 -0
  11. data/{src → dist}/parser/netcat.js +1 -0
  12. data/dist/parser/parseSync.js +142 -0
  13. data/dist/parser/server.rb +140 -0
  14. data/dist/plugin.js +143 -0
  15. data/dist/prettier.js +15 -0
  16. data/dist/rbs/parser.js +34 -0
  17. data/{src → dist}/rbs/parser.rb +0 -0
  18. data/dist/rbs/printer.js +517 -0
  19. data/dist/ruby/embed.js +110 -0
  20. data/dist/ruby/nodes/alias.js +59 -0
  21. data/{src → dist}/ruby/nodes/aref.js +26 -35
  22. data/dist/ruby/nodes/args.js +165 -0
  23. data/dist/ruby/nodes/arrays.js +126 -0
  24. data/dist/ruby/nodes/assign.js +41 -0
  25. data/dist/ruby/nodes/blocks.js +68 -0
  26. data/dist/ruby/nodes/calls.js +260 -0
  27. data/dist/ruby/nodes/case.js +50 -0
  28. data/dist/ruby/nodes/class.js +54 -0
  29. data/dist/ruby/nodes/commands.js +124 -0
  30. data/dist/ruby/nodes/conditionals.js +242 -0
  31. data/dist/ruby/nodes/constants.js +38 -0
  32. data/dist/ruby/nodes/flow.js +66 -0
  33. data/dist/ruby/nodes/hashes.js +130 -0
  34. data/dist/ruby/nodes/heredocs.js +30 -0
  35. data/dist/ruby/nodes/hooks.js +35 -0
  36. data/dist/ruby/nodes/ints.js +27 -0
  37. data/dist/ruby/nodes/lambdas.js +69 -0
  38. data/dist/ruby/nodes/loops.js +73 -0
  39. data/dist/ruby/nodes/massign.js +73 -0
  40. data/dist/ruby/nodes/methods.js +70 -0
  41. data/dist/ruby/nodes/operators.js +70 -0
  42. data/dist/ruby/nodes/params.js +89 -0
  43. data/dist/ruby/nodes/patterns.js +109 -0
  44. data/dist/ruby/nodes/regexp.js +45 -0
  45. data/dist/ruby/nodes/rescue.js +82 -0
  46. data/dist/ruby/nodes/return.js +75 -0
  47. data/dist/ruby/nodes/statements.js +111 -0
  48. data/dist/ruby/nodes/strings.js +218 -0
  49. data/dist/ruby/nodes/super.js +30 -0
  50. data/dist/ruby/nodes/undef.js +26 -0
  51. data/dist/ruby/nodes.js +151 -0
  52. data/dist/ruby/parser.js +34 -0
  53. data/{src → dist}/ruby/parser.rb +1274 -288
  54. data/dist/ruby/printer.js +125 -0
  55. data/dist/ruby/toProc.js +93 -0
  56. data/dist/types/haml.js +4 -0
  57. data/dist/types/plugin.js +3 -0
  58. data/dist/types/rbs.js +4 -0
  59. data/dist/types/ruby.js +4 -0
  60. data/dist/types/utils.js +2 -0
  61. data/dist/types.js +30 -0
  62. data/dist/utils/containsAssignment.js +15 -0
  63. data/dist/utils/getTrailingComma.js +6 -0
  64. data/dist/utils/hasAncestor.js +15 -0
  65. data/{src → dist}/utils/inlineEnsureParens.js +16 -16
  66. data/dist/utils/isEmptyBodyStmt.js +10 -0
  67. data/dist/utils/isEmptyStmts.js +10 -0
  68. data/dist/utils/literal.js +8 -0
  69. data/dist/utils/literallineWithoutBreakParent.js +8 -0
  70. data/dist/utils/makeCall.js +13 -0
  71. data/dist/utils/noIndent.js +11 -0
  72. data/dist/utils/printEmptyCollection.js +44 -0
  73. data/dist/utils/skipAssignIndent.js +15 -0
  74. data/dist/utils.js +30 -0
  75. data/node_modules/prettier/bin-prettier.js +13343 -10961
  76. data/node_modules/prettier/doc.js +4829 -0
  77. data/node_modules/prettier/index.js +23988 -22229
  78. data/node_modules/prettier/package.json +23 -0
  79. data/node_modules/prettier/parser-angular.js +60 -40
  80. data/node_modules/prettier/parser-babel.js +22 -1
  81. data/node_modules/prettier/parser-espree.js +22 -1
  82. data/node_modules/prettier/parser-flow.js +22 -1
  83. data/node_modules/prettier/parser-glimmer.js +1 -1
  84. data/node_modules/prettier/parser-graphql.js +1 -1
  85. data/node_modules/prettier/parser-html.js +82 -63
  86. data/node_modules/prettier/parser-markdown.js +24 -9
  87. data/node_modules/prettier/parser-meriyah.js +22 -1
  88. data/node_modules/prettier/parser-postcss.js +22 -1
  89. data/node_modules/prettier/parser-typescript.js +22 -1
  90. data/node_modules/prettier/parser-yaml.js +2 -2
  91. data/node_modules/prettier/third-party.js +1734 -862
  92. data/package.json +27 -19
  93. data/rubocop.yml +9 -0
  94. metadata +77 -77
  95. data/src/haml/embed.js +0 -87
  96. data/src/haml/nodes/comment.js +0 -27
  97. data/src/haml/nodes/doctype.js +0 -34
  98. data/src/haml/nodes/filter.js +0 -16
  99. data/src/haml/nodes/hamlComment.js +0 -21
  100. data/src/haml/nodes/plain.js +0 -6
  101. data/src/haml/nodes/root.js +0 -8
  102. data/src/haml/nodes/script.js +0 -33
  103. data/src/haml/nodes/silentScript.js +0 -59
  104. data/src/haml/nodes/tag.js +0 -232
  105. data/src/haml/parser.js +0 -22
  106. data/src/haml/printer.js +0 -28
  107. data/src/parser/parseSync.js +0 -170
  108. data/src/parser/server.rb +0 -66
  109. data/src/plugin.js +0 -148
  110. data/src/prettier.js +0 -16
  111. data/src/rbs/parser.js +0 -39
  112. data/src/rbs/printer.js +0 -615
  113. data/src/ruby/embed.js +0 -142
  114. data/src/ruby/nodes/alias.js +0 -73
  115. data/src/ruby/nodes/args.js +0 -178
  116. data/src/ruby/nodes/arrays.js +0 -162
  117. data/src/ruby/nodes/assign.js +0 -47
  118. data/src/ruby/nodes/blocks.js +0 -90
  119. data/src/ruby/nodes/calls.js +0 -199
  120. data/src/ruby/nodes/case.js +0 -65
  121. data/src/ruby/nodes/class.js +0 -64
  122. data/src/ruby/nodes/commands.js +0 -131
  123. data/src/ruby/nodes/conditionals.js +0 -280
  124. data/src/ruby/nodes/constants.js +0 -43
  125. data/src/ruby/nodes/flow.js +0 -74
  126. data/src/ruby/nodes/hashes.js +0 -164
  127. data/src/ruby/nodes/heredocs.js +0 -36
  128. data/src/ruby/nodes/hooks.js +0 -34
  129. data/src/ruby/nodes/ints.js +0 -31
  130. data/src/ruby/nodes/lambdas.js +0 -76
  131. data/src/ruby/nodes/loops.js +0 -98
  132. data/src/ruby/nodes/massign.js +0 -98
  133. data/src/ruby/nodes/methods.js +0 -74
  134. data/src/ruby/nodes/operators.js +0 -83
  135. data/src/ruby/nodes/params.js +0 -113
  136. data/src/ruby/nodes/patterns.js +0 -157
  137. data/src/ruby/nodes/regexp.js +0 -56
  138. data/src/ruby/nodes/rescue.js +0 -101
  139. data/src/ruby/nodes/return.js +0 -94
  140. data/src/ruby/nodes/statements.js +0 -142
  141. data/src/ruby/nodes/strings.js +0 -177
  142. data/src/ruby/nodes/super.js +0 -35
  143. data/src/ruby/nodes/undef.js +0 -42
  144. data/src/ruby/nodes.js +0 -34
  145. data/src/ruby/parser.js +0 -39
  146. data/src/ruby/printer.js +0 -138
  147. data/src/ruby/toProc.js +0 -105
  148. data/src/utils/containsAssignment.js +0 -11
  149. data/src/utils/getTrailingComma.js +0 -5
  150. data/src/utils/hasAncestor.js +0 -17
  151. data/src/utils/isEmptyBodyStmt.js +0 -7
  152. data/src/utils/isEmptyStmts.js +0 -11
  153. data/src/utils/literal.js +0 -7
  154. data/src/utils/literallineWithoutBreakParent.js +0 -7
  155. data/src/utils/makeCall.js +0 -14
  156. data/src/utils/noIndent.js +0 -11
  157. data/src/utils/printEmptyCollection.js +0 -49
  158. data/src/utils/skipAssignIndent.js +0 -10
  159. data/src/utils.js +0 -13
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ # frozen_string_literal: true
2
2
 
3
3
  # We implement our own version checking here instead of using Gem::Version so
4
4
  # that we can use the --disable-gems flag.
@@ -13,10 +13,11 @@ if (RUBY_MAJOR < 2) || ((RUBY_MAJOR == 2) && (RUBY_MINOR < 5))
13
13
  exit 1
14
14
  end
15
15
 
16
- require 'delegate'
17
- require 'json'
16
+ require 'json' unless defined?(JSON)
18
17
  require 'ripper'
19
18
 
19
+ # Ensure the module is already defined. This is mostly so that we don't have to
20
+ # indent the Parser definition one more time.
20
21
  module Prettier
21
22
  end
22
23
 
@@ -54,6 +55,47 @@ class Prettier::Parser < Ripper
54
55
  end
55
56
  end
56
57
 
58
+ # This is a small wrapper around the value of a node for those specific events
59
+ # that need extra handling. (For example: statement, body statement, and
60
+ # rescue nodes which all need extra information to determine their character
61
+ # boundaries.)
62
+ class Node
63
+ attr_reader :parser, :value
64
+
65
+ def initialize(parser, value)
66
+ @parser = parser
67
+ @value = value
68
+ end
69
+
70
+ def [](key)
71
+ value[key]
72
+ end
73
+
74
+ def dig(*keys)
75
+ value.dig(*keys)
76
+ end
77
+
78
+ def to_json(*opts)
79
+ value.to_json(*opts)
80
+ end
81
+
82
+ def pretty_print(q)
83
+ q.pp_hash(self)
84
+ end
85
+ end
86
+
87
+ # A special parser error so that we can get nice syntax displays on the error
88
+ # message when prettier prints out the results.
89
+ class ParserError < StandardError
90
+ attr_reader :lineno, :column
91
+
92
+ def initialize(error, lineno, column)
93
+ super(error)
94
+ @lineno = lineno
95
+ @column = column
96
+ end
97
+ end
98
+
57
99
  attr_reader :source, :lines, :scanner_events
58
100
 
59
101
  # This is an attr_accessor so Stmts objects can grab comments out of this
@@ -63,22 +105,64 @@ class Prettier::Parser < Ripper
63
105
  def initialize(source, *args)
64
106
  super(source, *args)
65
107
 
108
+ # We keep the source around so that we can refer back to it when we're
109
+ # generating the AST. Sometimes it's easier to just reference the source
110
+ # string when you want to check if it contains a certain character, for
111
+ # example.
66
112
  @source = source
113
+
114
+ # Similarly, we keep the lines of the source string around to be able to
115
+ # check if certain lines contain certain characters. For example, we'll use
116
+ # this to generate the content that goes after the __END__ keyword. Or we'll
117
+ # use this to check if a comment has other content on its line.
67
118
  @lines = source.split("\n")
68
119
 
120
+ # This is the full set of comments that have been found by the parser. It's
121
+ # a running list. At the end of every block of statements, they will go in
122
+ # and attempt to grab any comments that are on their own line and turn them
123
+ # into regular statements. So at the end of parsing the only comments left
124
+ # in here will be comments on lines that also contain code.
69
125
  @comments = []
126
+
127
+ # This is the current embdoc (comments that start with =begin and end with
128
+ # =end). Since they can't be nested, there's no need for a stack here, as
129
+ # there can only be one active. These end up getting dumped into the
130
+ # comments list before getting picked up by the statements that surround
131
+ # them.
70
132
  @embdoc = nil
133
+
134
+ # This is an optional node that can be present if the __END__ keyword is
135
+ # used in the file. In that case, this will represent the content after that
136
+ # keyword.
71
137
  @__end__ = nil
72
138
 
139
+ # Magic comments are a certain kind of comment that can impact the way the
140
+ # file is parsed (encoding/string frozen default/etc.). These scanner events
141
+ # are immediately followed by a comment scanner event, so we only need the
142
+ # one variable to set/unset it immediately.
143
+ @magic_comment = nil
144
+
145
+ # Heredocs can actually be nested together if you're using interpolation, so
146
+ # this is a stack of heredoc nodes that are currently being created. When we
147
+ # get to the scanner event that finishes off a heredoc node, we pop the top
148
+ # one off. If there are others surrounding it, then the body events will now
149
+ # be added to the correct nodes.
73
150
  @heredocs = []
74
151
 
152
+ # This is a running list of scanner events that have fired. It's useful
153
+ # mostly for maintaining location information. For example, if you're inside
154
+ # the handle of a def event, then in order to determine where the AST node
155
+ # started, you need to look backward in the scanner events to find a def
156
+ # keyword. Most of the time, when a parser event consumes one of these
157
+ # events, it will be deleted from the list. So ideally, this list stays
158
+ # pretty short over the course of parsing a source string.
75
159
  @scanner_events = []
76
- @line_counts = []
77
160
 
78
161
  # Here we're going to build up a list of SingleByteString or MultiByteString
79
162
  # objects. They're each going to represent a string in the source. They are
80
163
  # used by the `char_pos` method to determine where we are in the source
81
164
  # string.
165
+ @line_counts = []
82
166
  last_index = 0
83
167
 
84
168
  @source.lines.each do |line|
@@ -129,114 +213,61 @@ class Prettier::Parser < Ripper
129
213
  (body == :any || (scanner_event[:body] == body))
130
214
  end
131
215
 
132
- consume ? scanner_events.delete_at(index) : (index && scanner_events[index])
133
- end
134
-
135
- # Scanner events occur when the lexer hits a new token, like a keyword or an
136
- # end. These nodes always contain just one argument which is a string
137
- # representing the content. For the most part these can just be printed
138
- # directly, which very few exceptions.
139
- defined = %i[
140
- comment
141
- embdoc
142
- embdoc_beg
143
- embdoc_end
144
- heredoc_beg
145
- heredoc_end
146
- ignored_nl
147
- ]
148
-
149
- (SCANNER_EVENTS - defined).each do |event|
150
- define_method(:"on_#{event}") do |value|
151
- ec = char_pos + value.size
152
- node = {
153
- type: :"@#{event}",
154
- body: value,
155
- sl: lineno,
156
- el: lineno,
157
- sc: char_pos,
158
- ec: ec
159
- }
216
+ if consume
217
+ # If we're expecting to be able to find a scanner event and consume it,
218
+ # but can't actually find it, then we need to raise an error. This is
219
+ # _usually_ caused by a syntax error in the source that we're printing. It
220
+ # could also be caused by accidentally attempting to consume a scanner
221
+ # event twice by two different parser event handlers.
222
+ unless index
223
+ message = "Cannot find expected #{body == :any ? type : body}"
224
+ raise ParserError.new(message, lineno, column)
225
+ end
160
226
 
161
- scanner_events << node
162
- node
227
+ scanner_events.delete_at(index)
228
+ elsif index
229
+ scanner_events[index]
163
230
  end
164
231
  end
165
232
 
166
- # We keep track of each comment as it comes in and then eventually add
167
- # them to the top of the generated AST so that prettier can start adding
168
- # them back into the final representation. Comments come in including
169
- # their starting pound sign and the newline at the end, so we also chop
170
- # those off.
171
- #
172
- # If there is an encoding magic comment at the top of the file, ripper
173
- # will actually change into that encoding for the storage of the string.
174
- # This will break everything, so we need to force the encoding back into
175
- # UTF-8 so that the JSON library won't break.
176
- def on_comment(value)
177
- @comments << {
178
- type: :@comment,
179
- value: value[1..-1].chomp.force_encoding('UTF-8'),
180
- inline: value.strip != lines[lineno - 1],
181
- sl: lineno,
182
- el: lineno,
183
- sc: char_pos,
184
- ec: char_pos + value.length - 1
185
- }
233
+ # A helper function to find a :: operator. We do special handling instead of
234
+ # using find_scanner_event here because we don't pop off all of the ::
235
+ # operators so you could end up getting the wrong information if you have for
236
+ # instance ::X::Y::Z.
237
+ def find_colon2_before(const)
238
+ index =
239
+ scanner_events.rindex do |event|
240
+ event[:type] == :@op && event[:body] == '::' && event[:sc] < const[:sc]
241
+ end
242
+
243
+ scanner_events[index]
186
244
  end
187
245
 
188
- # ignored_nl is a special kind of scanner event that passes nil as the value,
189
- # so we can't do our normal tracking of value.size. Instead of adding a
190
- # condition to the main SCANNER_EVENTS loop above, we'll just explicitly
191
- # define the method here. You can trigger the ignored_nl event with the
192
- # following snippet:
246
+ # Finds the next position in the source string that begins a statement. This
247
+ # is used to bind statements lists and make sure they don't include a
248
+ # preceding comment. For example, we want the following comment to be attached
249
+ # to the class node and not the statement node:
193
250
  #
194
- # foo.bar
195
- # .baz
251
+ # class Foo # :nodoc:
252
+ # ...
253
+ # end
196
254
  #
197
- def on_ignored_nl(value)
198
- {
199
- type: :ignored_nl,
200
- body: nil,
201
- sl: lineno,
202
- el: lineno,
203
- sc: char_pos,
204
- ec: char_pos
205
- }
206
- end
207
-
208
- prepend(
209
- Module.new do
210
- private
211
-
212
- # Handles __END__ syntax, which allows individual scripts to keep content
213
- # after the main ruby code that can be read through DATA. It looks like:
214
- #
215
- # foo.bar
216
- #
217
- # __END__
218
- # some other content that isn't normally read by ripper
219
- def on___end__(*)
220
- @__end__ = super(lines[lineno..-1].join("\n"))
221
- end
222
-
223
- # Like comments, we need to force the encoding here so JSON doesn't break.
224
- def on_ident(value)
225
- super(value.force_encoding('UTF-8'))
226
- end
255
+ # By finding the next non-space character, we can make sure that the bounds of
256
+ # the statement list are correct.
257
+ def find_next_statement_start(position)
258
+ remaining = source[position..-1]
227
259
 
228
- # Like comments, we need to force the encoding here so JSON doesn't break.
229
- def on_tstring_content(value)
230
- super(value.force_encoding('UTF-8'))
231
- end
260
+ if remaining.sub(/\A +/, '')[0] == '#'
261
+ return position + remaining.index("\n")
232
262
  end
233
- )
234
263
 
235
- # A BEGIN node is a parser event that represents the use of the BEGIN
236
- # keyword, which hooks into the lifecycle of the interpreter. It's a bit
237
- # of a legacy from the stream operating days, and gets its inspiration
238
- # from tools like awk. Whatever is inside the "block" will get executed
239
- # when the program starts. The syntax looks like the following:
264
+ position
265
+ end
266
+
267
+ # BEGIN is a parser event that represents the use of the BEGIN keyword, which
268
+ # hooks into the lifecycle of the interpreter. Whatever is inside the "block"
269
+ # will get executed when the program starts. The syntax looks like the
270
+ # following:
240
271
  #
241
272
  # BEGIN {
242
273
  # # execute stuff here
@@ -256,11 +287,35 @@ class Prettier::Parser < Ripper
256
287
  )
257
288
  end
258
289
 
259
- # A END node is a parser event that represents the use of the END keyword,
260
- # which hooks into the lifecycle of the interpreter. It's a bit of a
261
- # legacy from the stream operating days, and gets its inspiration from
262
- # tools like awk. Whatever is inside the "block" will get executed when
263
- # the program ends. The syntax looks like the following:
290
+ # CHAR is a parser event that represents a single codepoint in the script
291
+ # encoding. For example:
292
+ #
293
+ # ?a
294
+ #
295
+ # is a representation of the string literal "a". You can use control
296
+ # characters with this as well, as in ?\C-a.
297
+ #
298
+ def on_CHAR(value)
299
+ start_line = lineno
300
+ start_char = char_pos
301
+
302
+ node = {
303
+ type: :@CHAR,
304
+ body: value,
305
+ sl: start_line,
306
+ el: start_line,
307
+ sc: start_char,
308
+ ec: start_char + value.size
309
+ }
310
+
311
+ scanner_events << node
312
+ node
313
+ end
314
+
315
+ # END is a parser event that represents the use of the END keyword, which
316
+ # hooks into the lifecycle of the interpreter. Whatever is inside the "block"
317
+ # will get executed when the program ends. The syntax looks like the
318
+ # following:
264
319
  #
265
320
  # END {
266
321
  # # execute stuff here
@@ -280,11 +335,34 @@ class Prettier::Parser < Ripper
280
335
  )
281
336
  end
282
337
 
283
- # alias is a parser event that represents when you're using the alias
284
- # keyword with regular arguments. This can be either symbol literals or
285
- # bare words. You can optionally use parentheses with this keyword, so we
286
- # either track the location information based on those or the final
287
- # argument to the alias method.
338
+ # __END__ is a scanner event that represents __END__ syntax, which allows
339
+ # individual scripts to keep content after the main ruby code that can be read
340
+ # through the DATA constant. It looks like:
341
+ #
342
+ # puts DATA.read
343
+ #
344
+ # __END__
345
+ # some other content that isn't executed by the program
346
+ #
347
+ def on___end__(value)
348
+ start_line = lineno
349
+ start_char = char_pos
350
+
351
+ @__end__ = {
352
+ type: :@__end__,
353
+ body: lines[lineno..-1].join("\n"),
354
+ sl: start_line,
355
+ el: start_line,
356
+ sc: start_char,
357
+ ec: start_char + value.size
358
+ }
359
+ end
360
+
361
+ # alias is a parser event that represents the use of the alias keyword with
362
+ # regular arguments. This can be either symbol literals or bare words. You can
363
+ # optionally use parentheses with this keyword, so we either track the
364
+ # location information based on those or the final argument to the alias
365
+ # method.
288
366
  def on_alias(left, right)
289
367
  beging = find_scanner_event(:@kw, 'alias')
290
368
 
@@ -301,7 +379,7 @@ class Prettier::Parser < Ripper
301
379
  }
302
380
  end
303
381
 
304
- # aref nodes are when you're pulling a value out of a collection at a
382
+ # aref is a parser event when you're pulling a value out of a collection at a
305
383
  # specific index. Put another way, it's any time you're calling the method
306
384
  # #[]. As an example:
307
385
  #
@@ -345,26 +423,59 @@ class Prettier::Parser < Ripper
345
423
  }
346
424
  end
347
425
 
348
- # args_new is a parser event that represents the beginning of a list of
349
- # arguments to any method call or an array. It can be followed by any
350
- # number of args_add events, which we'll append onto an array body.
351
- def on_args_new
426
+ # arg_ambiguous is a parser event that represents when the parser sees an
427
+ # argument as ambiguous. For example, in the following snippet:
428
+ #
429
+ # foo //
430
+ #
431
+ # the question becomes if the forward slash is being used as a division
432
+ # operation or if it's the start of a regular expression. We don't need to
433
+ # track this event in the AST that we're generating, so we're not going to
434
+ # define an explicit handler for it.
435
+ #
436
+ # def on_arg_ambiguous(value)
437
+ # value
438
+ # end
439
+
440
+ # arg_paren is a parser event that represents wrapping arguments to a method
441
+ # inside a set of parentheses. For example, in the follow snippet:
442
+ #
443
+ # foo(bar)
444
+ #
445
+ # there would be an arg_paren node around the args_add_block node that
446
+ # represents the set of arguments being sent to the foo method. The args child
447
+ # node can be nil if no arguments were passed, as in:
448
+ #
449
+ # foo()
450
+ #
451
+ def on_arg_paren(args)
452
+ beging = find_scanner_event(:@lparen)
453
+ rparen = find_scanner_event(:@rparen)
454
+
455
+ # If the arguments exceed the ending of the parentheses, then we know we
456
+ # have a heredoc in the arguments, and we need to use the bounds of the
457
+ # arguments to determine how large the arg_paren is.
458
+ ending = (args && args[:el] > rparen[:el]) ? args : rparen
459
+
352
460
  {
353
- type: :args,
354
- body: [],
355
- sl: lineno,
356
- sc: char_pos,
357
- el: lineno,
358
- ec: char_pos
461
+ type: :arg_paren,
462
+ body: [args],
463
+ sl: beging[:sl],
464
+ sc: beging[:sc],
465
+ el: ending[:el],
466
+ ec: ending[:ec]
359
467
  }
360
468
  end
361
469
 
362
- # args_add is a parser event that represents a single argument inside a
363
- # list of arguments to any method call or an array. It accepts as
364
- # arguments the parent args node as well as an arg which can be anything
365
- # that could be passed as an argument.
470
+ # args_add is a parser event that represents a single argument inside a list
471
+ # of arguments to any method call or an array. It accepts as arguments the
472
+ # parent args node as well as an arg which can be anything that could be
473
+ # passed as an argument.
366
474
  def on_args_add(args, arg)
367
475
  if args[:body].empty?
476
+ # If this is the first argument being passed into the list of arguments,
477
+ # then we're going to use the bounds of the argument to override the
478
+ # parent node's location since this will be more accurate.
368
479
  arg.merge(type: :args, body: [arg])
369
480
  else
370
481
  args.merge!(body: args[:body] << arg, el: arg[:el], ec: arg[:ec])
@@ -373,7 +484,7 @@ class Prettier::Parser < Ripper
373
484
 
374
485
  # args_add_block is a parser event that represents a list of arguments and
375
486
  # potentially a block argument. If no block is passed, then the second
376
- # argument will be false.
487
+ # argument will be the literal false.
377
488
  def on_args_add_block(args, block)
378
489
  ending = block || args
379
490
 
@@ -408,24 +519,17 @@ class Prettier::Parser < Ripper
408
519
  find_scanner_event(:@op, '...').merge!(type: :args_forward)
409
520
  end
410
521
 
411
- # arg_paren is a parser event that represents wrapping arguments to a
412
- # method inside a set of parentheses.
413
- def on_arg_paren(args)
414
- beging = find_scanner_event(:@lparen)
415
- rparen = find_scanner_event(:@rparen)
416
-
417
- # If the arguments exceed the ending of the parentheses, then we know we
418
- # have a heredoc in the arguments, and we need to use the bounds of the
419
- # arguments to determine how large the arg_paren is.
420
- ending = (args && args[:el] > rparen[:el]) ? args : rparen
421
-
522
+ # args_new is a parser event that represents the beginning of a list of
523
+ # arguments to any method call or an array. It can be followed by any
524
+ # number of args_add events, which we'll append onto an array body.
525
+ def on_args_new
422
526
  {
423
- type: :arg_paren,
424
- body: [args],
425
- sl: beging[:sl],
426
- sc: beging[:sc],
427
- el: ending[:el],
428
- ec: ending[:ec]
527
+ type: :args,
528
+ body: [],
529
+ sl: lineno,
530
+ sc: char_pos,
531
+ el: lineno,
532
+ ec: char_pos
429
533
  }
430
534
  end
431
535
 
@@ -526,6 +630,45 @@ class Prettier::Parser < Ripper
526
630
  }
527
631
  end
528
632
 
633
+ # backref is a scanner event that represents a global variable referencing a
634
+ # matched value. It comes in the form of a $ followed by a positive integer.
635
+ def on_backref(value)
636
+ start_line = lineno
637
+ start_char = char_pos
638
+
639
+ node = {
640
+ type: :@backref,
641
+ body: value,
642
+ sl: start_line,
643
+ el: start_line,
644
+ sc: start_char,
645
+ ec: start_char + value.size
646
+ }
647
+
648
+ scanner_events << node
649
+ node
650
+ end
651
+
652
+ # backtick is a scanner event that represents the use of the ` operator. It's
653
+ # usually found being used for an xstring, but could also be found as the name
654
+ # of a method being defined.
655
+ def on_backtick(value)
656
+ start_line = lineno
657
+ start_char = char_pos
658
+
659
+ node = {
660
+ type: :@backtick,
661
+ body: value,
662
+ sl: start_line,
663
+ el: start_line,
664
+ sc: start_char,
665
+ ec: start_char + value.size
666
+ }
667
+
668
+ scanner_events << node
669
+ node
670
+ end
671
+
529
672
  # bare_assoc_hash is a parser event that represents a hash of contents
530
673
  # being passed as a method argument (and therefore has omitted braces). It
531
674
  # accepts as an argument an array of assoc events (either assoc_new or
@@ -617,19 +760,19 @@ class Prettier::Parser < Ripper
617
760
  # bodystmt can't actually determine its bounds appropriately because it
618
761
  # doesn't necessarily know where it started. So the parent node needs to
619
762
  # report back down into this one where it goes.
620
- class BodyStmt < SimpleDelegator
763
+ class BodyStmt < Node
621
764
  def bind(sc, ec)
622
- merge!(sc: sc, ec: ec)
623
- parts = self[:body]
765
+ value.merge!(sc: sc, ec: ec)
766
+ parts = value[:body]
624
767
 
625
768
  # Here we're going to determine the bounds for the stmts
626
769
  consequent = parts[1..-1].compact.first
627
- self[:body][0].bind(sc, consequent ? consequent[:sc] : ec)
770
+ value[:body][0].bind(sc, consequent ? consequent[:sc] : ec)
628
771
 
629
772
  # Next we're going to determine the rescue clause if there is one
630
773
  if parts[1]
631
774
  consequent = parts[2..-1].compact.first
632
- self[:body][1].bind_end(consequent ? consequent[:sc] : ec)
775
+ value[:body][1].bind_end(consequent ? consequent[:sc] : ec)
633
776
  end
634
777
  end
635
778
  end
@@ -638,6 +781,7 @@ class Prettier::Parser < Ripper
638
781
  # of clauses within the body of a method or block.
639
782
  def on_bodystmt(stmts, rescued, ensured, elsed)
640
783
  BodyStmt.new(
784
+ self,
641
785
  type: :bodystmt,
642
786
  body: [stmts, rescued, ensured, elsed],
643
787
  sl: lineno,
@@ -739,27 +883,6 @@ class Prettier::Parser < Ripper
739
883
  )
740
884
  end
741
885
 
742
- # Finds the next position in the source string that begins a statement. This
743
- # is used to bind statements lists and make sure they don't include a
744
- # preceding comment. For example, we want the following comment to be attached
745
- # to the class node and not the statement node:
746
- #
747
- # class Foo # :nodoc:
748
- # ...
749
- # end
750
- #
751
- # By finding the next non-space character, we can make sure that the bounds of
752
- # the statement list are correct.
753
- def find_next_statement_start(position)
754
- remaining = source[position..-1]
755
-
756
- if remaining.sub(/\A +/, '')[0] == '#'
757
- return position + remaining.index("\n")
758
- end
759
-
760
- position
761
- end
762
-
763
886
  # class is a parser event that represents defining a class. It accepts as
764
887
  # arguments the name of the class, the optional name of the superclass,
765
888
  # and the bodystmt event that represents the statements evaluated within
@@ -783,6 +906,24 @@ class Prettier::Parser < Ripper
783
906
  }
784
907
  end
785
908
 
909
+ # comma is a scanner event that represents the use of the comma operator.
910
+ def on_comma(value)
911
+ start_line = lineno
912
+ start_char = char_pos
913
+
914
+ node = {
915
+ type: :@comma,
916
+ body: value,
917
+ sl: start_line,
918
+ el: start_line,
919
+ sc: start_char,
920
+ ec: start_char + value.size
921
+ }
922
+
923
+ scanner_events << node
924
+ node
925
+ end
926
+
786
927
  # command is a parser event representing a method call with arguments and
787
928
  # no parentheses. It accepts as arguments the name of the method and the
788
929
  # arguments being passed to the method.
@@ -814,6 +955,70 @@ class Prettier::Parser < Ripper
814
955
  }
815
956
  end
816
957
 
958
+ # We keep track of each comment as it comes in and then eventually add
959
+ # them to the top of the generated AST so that prettier can start adding
960
+ # them back into the final representation. Comments come in including
961
+ # their starting pound sign and the newline at the end, so we also chop
962
+ # those off.
963
+ def on_comment(value)
964
+ # If there is an encoding magic comment at the top of the file, ripper
965
+ # will actually change into that encoding for the storage of the string.
966
+ # This will break everything when we attempt to print as JSON, so we need to
967
+ # force the encoding back into UTF-8 so that it won't break.
968
+ body = value[1..-1].chomp.force_encoding('UTF-8')
969
+
970
+ start_line = lineno
971
+ start_char = char_pos
972
+
973
+ # If we already had special handling of a magic comment, then we can just
974
+ # skip and return the value of that node.
975
+ if @magic_comment
976
+ comment = @magic_comment
977
+ @magic_comment = nil
978
+
979
+ # At the moment, merging in the value of the string being passed into
980
+ # here. In the next major version I'd like to remove this and just use the
981
+ # value of the magic comment. At the moment though that would change
982
+ # comments like -*- encoding: UTF-8 -*- into encoding: UTF-8 so need to
983
+
984
+ # wait for a major version to do that.
985
+ @comments << comment.merge(value: body, ec: start_char + value.length - 1)
986
+ return comment
987
+ end
988
+
989
+ @comments << {
990
+ type: :@comment,
991
+ value: body,
992
+ inline: value.strip != lines[lineno - 1],
993
+ sl: start_line,
994
+ el: start_line,
995
+ sc: start_char,
996
+ ec: start_char + value.length - 1
997
+ }
998
+ end
999
+
1000
+ # const is a scanner event that represents a literal value that _looks like_
1001
+ # a constant. This could actually be a reference to a constant. It could also
1002
+ # be something that looks like a constant in another context, as in a method
1003
+ # call to a capitalized method, a symbol that starts with a capital letter,
1004
+ # etc.
1005
+ def on_const(value)
1006
+ start_line = lineno
1007
+ start_char = char_pos
1008
+
1009
+ node = {
1010
+ type: :@const,
1011
+ body: value,
1012
+ sl: start_line,
1013
+ el: start_line,
1014
+ sc: start_char,
1015
+ ec: start_char + value.size
1016
+ }
1017
+
1018
+ scanner_events << node
1019
+ node
1020
+ end
1021
+
817
1022
  # A const_path_field is a parser event that is always the child of some
818
1023
  # kind of assignment. It represents when you're assigning to a constant
819
1024
  # that is being referenced as a child of another variable. For example:
@@ -833,10 +1038,8 @@ class Prettier::Parser < Ripper
833
1038
 
834
1039
  # A const_path_ref is a parser event that is a very similar to
835
1040
  # const_path_field except that it is not involved in an assignment. It
836
- # looks like the following example:
837
- #
838
- # foo::X
839
- #
1041
+ # looks like the following example: foo::Bar, where left is foo and const is
1042
+ # Bar.
840
1043
  def on_const_path_ref(left, const)
841
1044
  {
842
1045
  type: :const_path_ref,
@@ -858,6 +1061,24 @@ class Prettier::Parser < Ripper
858
1061
  const.merge(type: :const_ref, body: [const])
859
1062
  end
860
1063
 
1064
+ # cvar is a scanner event that represents the use of a class variable.
1065
+ def on_cvar(value)
1066
+ start_line = lineno
1067
+ start_char = char_pos
1068
+
1069
+ node = {
1070
+ type: :@cvar,
1071
+ body: value,
1072
+ sl: start_line,
1073
+ el: start_line,
1074
+ sc: start_char,
1075
+ ec: start_char + value.size
1076
+ }
1077
+
1078
+ scanner_events << node
1079
+ node
1080
+ end
1081
+
861
1082
  # A def is a parser event that represents defining a regular method on the
862
1083
  # current self object. It accepts as arguments the ident (the name of the
863
1084
  # method being defined), the params (the parameter declaration for the
@@ -1063,7 +1284,7 @@ class Prettier::Parser < Ripper
1063
1284
 
1064
1285
  beging.merge(
1065
1286
  type: :dyna_symbol,
1066
- quote: beging[:body][1],
1287
+ quote: beging[:body],
1067
1288
  body: string[:body],
1068
1289
  el: ending[:el],
1069
1290
  ec: ending[:ec]
@@ -1084,25 +1305,22 @@ class Prettier::Parser < Ripper
1084
1305
  end
1085
1306
  end
1086
1307
 
1087
- # else can either end with an end keyword (in which case we'll want to
1088
- # consume that event) or it can end with an ensure keyword (in which case
1089
- # we'll leave that to the ensure to handle).
1090
- def find_else_ending
1308
+ # else is a parser event that represents the end of a if, unless, or begin
1309
+ # chain. It accepts as an argument the statements that are contained
1310
+ # within the else clause.
1311
+ def on_else(stmts)
1312
+ beging = find_scanner_event(:@kw, 'else')
1313
+
1314
+ # else can either end with an end keyword (in which case we'll want to
1315
+ # consume that event) or it can end with an ensure keyword (in which case
1316
+ # we'll leave that to the ensure to handle).
1091
1317
  index =
1092
1318
  scanner_events.rindex do |event|
1093
1319
  event[:type] == :@kw && %w[end ensure].include?(event[:body])
1094
1320
  end
1095
1321
 
1096
1322
  event = scanner_events[index]
1097
- event[:body] == 'end' ? scanner_events.delete_at(index) : event
1098
- end
1099
-
1100
- # else is a parser event that represents the end of a if, unless, or begin
1101
- # chain. It accepts as an argument the statements that are contained
1102
- # within the else clause.
1103
- def on_else(stmts)
1104
- beging = find_scanner_event(:@kw, 'else')
1105
- ending = find_else_ending
1323
+ ending = event[:body] == 'end' ? scanner_events.delete_at(index) : event
1106
1324
 
1107
1325
  stmts.bind(beging[:ec], ending[:sc])
1108
1326
 
@@ -1136,6 +1354,14 @@ class Prettier::Parser < Ripper
1136
1354
  }
1137
1355
  end
1138
1356
 
1357
+ # This is a scanner event that gets hit when we're inside an embdoc and
1358
+ # receive a new line of content. Here we are guaranteed to already have
1359
+ # initialized the @embdoc variable so we can just append the new line onto
1360
+ # the existing content.
1361
+ def on_embdoc(value)
1362
+ @embdoc[:value] << value
1363
+ end
1364
+
1139
1365
  # embdocs are long comments that are surrounded by =begin..=end. They
1140
1366
  # cannot be nested, so we don't need to worry about keeping a stack around
1141
1367
  # like we do with heredocs. Instead we can just track the current embdoc
@@ -1145,14 +1371,6 @@ class Prettier::Parser < Ripper
1145
1371
  @embdoc = { type: :@embdoc, value: value, sl: lineno, sc: char_pos }
1146
1372
  end
1147
1373
 
1148
- # This is a scanner event that gets hit when we're inside an embdoc and
1149
- # receive a new line of content. Here we are guaranteed to already have
1150
- # initialized the @embdoc variable so we can just append the new line onto
1151
- # the existing content.
1152
- def on_embdoc(value)
1153
- @embdoc[:value] << value
1154
- end
1155
-
1156
1374
  # This is the final scanner event for embdocs. It receives the =end. Here
1157
1375
  # we can finalize the embdoc with its location information and the final
1158
1376
  # piece of the string. We then add it to the list of comments so that
@@ -1168,6 +1386,72 @@ class Prettier::Parser < Ripper
1168
1386
  @embdoc = nil
1169
1387
  end
1170
1388
 
1389
+ # embexpr_beg is a scanner event that represents using interpolation inside of
1390
+ # a string, xstring, heredoc, or regexp. Its value is the string literal "#{".
1391
+ def on_embexpr_beg(value)
1392
+ start_line = lineno
1393
+ start_char = char_pos
1394
+
1395
+ node = {
1396
+ type: :@embexpr_beg,
1397
+ body: value,
1398
+ sl: start_line,
1399
+ el: start_line,
1400
+ sc: start_char,
1401
+ ec: start_char + value.size
1402
+ }
1403
+
1404
+ scanner_events << node
1405
+ node
1406
+ end
1407
+
1408
+ # embexpr_end is a scanner event that represents the end of an interpolated
1409
+ # expression in a string, xstring, heredoc, or regexp. Its value is the string
1410
+ # literal "}".
1411
+ def on_embexpr_end(value)
1412
+ start_line = lineno
1413
+ start_char = char_pos
1414
+
1415
+ node = {
1416
+ type: :@embexpr_end,
1417
+ body: value,
1418
+ sl: start_line,
1419
+ el: start_line,
1420
+ sc: start_char,
1421
+ ec: start_char + value.size
1422
+ }
1423
+
1424
+ scanner_events << node
1425
+ node
1426
+ end
1427
+
1428
+ # embvar is a scanner event that represents the use of shorthand interpolation
1429
+ # for an instance, class, or global variable into a string, xstring, heredoc,
1430
+ # or regexp. Its value is the string literal "#". For example, in the
1431
+ # following snippet:
1432
+ #
1433
+ # "#@foo"
1434
+ #
1435
+ # the embvar would be triggered by the "#", then an ivar event for the @foo
1436
+ # instance variable. That would all get bound up into a string_dvar node in
1437
+ # the final AST.
1438
+ def on_embvar(value)
1439
+ start_line = lineno
1440
+ start_char = char_pos
1441
+
1442
+ node = {
1443
+ type: :@embvar,
1444
+ body: value,
1445
+ sl: start_line,
1446
+ el: start_line,
1447
+ sc: start_char,
1448
+ ec: start_char + value.size
1449
+ }
1450
+
1451
+ scanner_events << node
1452
+ node
1453
+ end
1454
+
1171
1455
  # ensure is a parser event that represents the use of the ensure keyword
1172
1456
  # and its subsequent statements.
1173
1457
  def on_ensure(stmts)
@@ -1224,6 +1508,24 @@ class Prettier::Parser < Ripper
1224
1508
  }
1225
1509
  end
1226
1510
 
1511
+ # float is a scanner event that represents a floating point value literal.
1512
+ def on_float(value)
1513
+ start_line = lineno
1514
+ start_char = char_pos
1515
+
1516
+ node = {
1517
+ type: :@float,
1518
+ body: value,
1519
+ sl: start_line,
1520
+ el: start_line,
1521
+ sc: start_char,
1522
+ ec: start_char + value.size
1523
+ }
1524
+
1525
+ scanner_events << node
1526
+ node
1527
+ end
1528
+
1227
1529
  # fndptn is a parser event that represents matching against a pattern where
1228
1530
  # you find a pattern in an array using the Ruby 3.0+ pattern matching syntax.
1229
1531
  def on_fndptn(const, presplat, args, postsplat)
@@ -1244,15 +1546,22 @@ class Prettier::Parser < Ripper
1244
1546
  # loop. It accepts as arguments an ident which is the iterating variable,
1245
1547
  # an enumerable for that which is being enumerated, and a stmts event that
1246
1548
  # represents the statements inside the for loop.
1247
- def on_for(ident, enumerable, stmts)
1549
+ def on_for(ident, enum, stmts)
1248
1550
  beging = find_scanner_event(:@kw, 'for')
1249
1551
  ending = find_scanner_event(:@kw, 'end')
1250
1552
 
1251
- stmts.bind(enumerable[:ec], ending[:sc])
1553
+ # Consume the do keyword if it exists so that it doesn't get confused for
1554
+ # some other block
1555
+ do_event = find_scanner_event(:@kw, 'do', consume: false)
1556
+ if do_event && do_event[:sc] > enum[:ec] && do_event[:ec] < ending[:sc]
1557
+ scanner_events.delete(do_event)
1558
+ end
1559
+
1560
+ stmts.bind((do_event || enum)[:ec], ending[:sc])
1252
1561
 
1253
1562
  {
1254
1563
  type: :for,
1255
- body: [ident, enumerable, stmts],
1564
+ body: [ident, enum, stmts],
1256
1565
  sl: beging[:sl],
1257
1566
  sc: beging[:sc],
1258
1567
  el: ending[:el],
@@ -1260,6 +1569,24 @@ class Prettier::Parser < Ripper
1260
1569
  }
1261
1570
  end
1262
1571
 
1572
+ # gvar is a scanner event that represents a global variable literal.
1573
+ def on_gvar(value)
1574
+ start_line = lineno
1575
+ start_char = char_pos
1576
+
1577
+ node = {
1578
+ type: :@gvar,
1579
+ body: value,
1580
+ sl: start_line,
1581
+ el: start_line,
1582
+ sc: start_char,
1583
+ ec: start_char + value.size
1584
+ }
1585
+
1586
+ scanner_events << node
1587
+ node
1588
+ end
1589
+
1263
1590
  # hash is a parser event that represents a hash literal. It accepts as an
1264
1591
  # argument an optional assoclist_from_args event which contains the
1265
1592
  # contents of the hash.
@@ -1334,6 +1661,27 @@ class Prettier::Parser < Ripper
1334
1661
  }
1335
1662
  end
1336
1663
 
1664
+ # ident is a scanner event that represents an identifier anywhere in code. It
1665
+ # can actually represent a whole bunch of stuff, depending on where it is in
1666
+ # the AST. Like comments, we need to force the encoding here so JSON doesn't
1667
+ # break.
1668
+ def on_ident(value)
1669
+ start_line = lineno
1670
+ start_char = char_pos
1671
+
1672
+ node = {
1673
+ type: :@ident,
1674
+ body: value.force_encoding('UTF-8'),
1675
+ sl: start_line,
1676
+ el: start_line,
1677
+ sc: start_char,
1678
+ ec: start_char + value.size
1679
+ }
1680
+
1681
+ scanner_events << node
1682
+ node
1683
+ end
1684
+
1337
1685
  # if is a parser event that represents the first clause in an if chain.
1338
1686
  # It accepts as arguments the predicate of the if, the statements that are
1339
1687
  # contained within the if clause, and the optional consequent clause.
@@ -1371,14 +1719,64 @@ class Prettier::Parser < Ripper
1371
1719
  def on_if_mod(predicate, statement)
1372
1720
  find_scanner_event(:@kw, 'if')
1373
1721
 
1374
- {
1375
- type: :if_mod,
1376
- body: [predicate, statement],
1377
- sl: statement[:sl],
1378
- sc: statement[:sc],
1379
- el: predicate[:el],
1380
- ec: predicate[:ec]
1722
+ {
1723
+ type: :if_mod,
1724
+ body: [predicate, statement],
1725
+ sl: statement[:sl],
1726
+ sc: statement[:sc],
1727
+ el: predicate[:el],
1728
+ ec: predicate[:ec]
1729
+ }
1730
+ end
1731
+
1732
+ # ignored_nl is a special kind of scanner event that passes nil as the value.
1733
+ # You can trigger the ignored_nl event with the following snippet:
1734
+ #
1735
+ # foo.bar
1736
+ # .baz
1737
+ #
1738
+ # We don't need to track this event in the AST that we're generating, so we're
1739
+ # not going to define an explicit handler for it.
1740
+ #
1741
+ # def on_ignored_nl(value)
1742
+ # value
1743
+ # end
1744
+
1745
+ # ignored_sp is a scanner event that represents the space before the content
1746
+ # of each line of a squiggly heredoc that will be removed from the string
1747
+ # before it gets transformed into a string literal. For example, in the
1748
+ # following snippet:
1749
+ #
1750
+ # <<~HERE
1751
+ # foo
1752
+ # bar
1753
+ # HERE
1754
+ #
1755
+ # You would have two ignored_sp events, the first with two spaces and the
1756
+ # second with four. We don't need to track this event in the AST that we're
1757
+ # generating, so we're not going to define an explicit handler for it.
1758
+ #
1759
+ # def on_ignored_sp(value)
1760
+ # value
1761
+ # end
1762
+
1763
+ # imaginary is a scanner event that represents an imaginary number literal.
1764
+ # They become instances of the Complex class.
1765
+ def on_imaginary(value)
1766
+ start_line = lineno
1767
+ start_char = char_pos
1768
+
1769
+ node = {
1770
+ type: :@imaginary,
1771
+ body: value,
1772
+ sl: start_line,
1773
+ el: start_line,
1774
+ sc: start_char,
1775
+ ec: start_char + value.size
1381
1776
  }
1777
+
1778
+ scanner_events << node
1779
+ node
1382
1780
  end
1383
1781
 
1384
1782
  # in is a parser event that represents using the in keyword within the
@@ -1401,6 +1799,61 @@ class Prettier::Parser < Ripper
1401
1799
  )
1402
1800
  end
1403
1801
 
1802
+ # int is a scanner event the represents a number literal.
1803
+ def on_int(value)
1804
+ start_line = lineno
1805
+ start_char = char_pos
1806
+
1807
+ node = {
1808
+ type: :@int,
1809
+ body: value,
1810
+ sl: start_line,
1811
+ el: start_line,
1812
+ sc: start_char,
1813
+ ec: start_char + value.size
1814
+ }
1815
+
1816
+ scanner_events << node
1817
+ node
1818
+ end
1819
+
1820
+ # ivar is a scanner event the represents an instance variable literal.
1821
+ def on_ivar(value)
1822
+ start_line = lineno
1823
+ start_char = char_pos
1824
+
1825
+ node = {
1826
+ type: :@ivar,
1827
+ body: value,
1828
+ sl: start_line,
1829
+ el: start_line,
1830
+ sc: start_char,
1831
+ ec: start_char + value.size
1832
+ }
1833
+
1834
+ scanner_events << node
1835
+ node
1836
+ end
1837
+
1838
+ # kw is a scanner event the represents the use of a keyword. It can be
1839
+ # anywhere in the AST, so you end up seeing it quite a lot.
1840
+ def on_kw(value)
1841
+ start_line = lineno
1842
+ start_char = char_pos
1843
+
1844
+ node = {
1845
+ type: :@kw,
1846
+ body: value,
1847
+ sl: start_line,
1848
+ el: start_line,
1849
+ sc: start_char,
1850
+ ec: start_char + value.size
1851
+ }
1852
+
1853
+ scanner_events << node
1854
+ node
1855
+ end
1856
+
1404
1857
  # kwrest_param is a parser event that represents defining a parameter in a
1405
1858
  # method definition that accepts all remaining keyword parameters.
1406
1859
  def on_kwrest_param(ident)
@@ -1415,6 +1868,61 @@ class Prettier::Parser < Ripper
1415
1868
  )
1416
1869
  end
1417
1870
 
1871
+ # label is a scanner event that represents the use of an identifier to
1872
+ # associate with an object. You can find it in a hash key, as in:
1873
+ #
1874
+ # { foo: bar }
1875
+ #
1876
+ # in this case "foo:" would be the body of the label. You can also find it in
1877
+ # pattern matching, as in:
1878
+ #
1879
+ # case foo
1880
+ # in bar:
1881
+ # bar
1882
+ # end
1883
+ #
1884
+ # in this case "bar:" would be the body of the label.
1885
+ def on_label(value)
1886
+ start_line = lineno
1887
+ start_char = char_pos
1888
+
1889
+ node = {
1890
+ type: :@label,
1891
+ body: value,
1892
+ sl: start_line,
1893
+ el: start_line,
1894
+ sc: start_char,
1895
+ ec: start_char + value.size
1896
+ }
1897
+
1898
+ scanner_events << node
1899
+ node
1900
+ end
1901
+
1902
+ # label_end is a scanner event that represents the end of a dynamic symbol. If
1903
+ # for example you had the following hash:
1904
+ #
1905
+ # { "foo": bar }
1906
+ #
1907
+ # then the string "\":" would be the value of this label_end. It's useful for
1908
+ # determining the type of quote being used by the label.
1909
+ def on_label_end(value)
1910
+ start_line = lineno
1911
+ start_char = char_pos
1912
+
1913
+ node = {
1914
+ type: :@label_end,
1915
+ body: value,
1916
+ sl: start_line,
1917
+ el: start_line,
1918
+ sc: start_char,
1919
+ ec: start_char + value.size
1920
+ }
1921
+
1922
+ scanner_events << node
1923
+ node
1924
+ end
1925
+
1418
1926
  # lambda is a parser event that represents using a "stabby" lambda
1419
1927
  # literal. It accepts as arguments a params event that represents any
1420
1928
  # parameters to the lambda and a stmts event that represents the
@@ -1445,6 +1953,80 @@ class Prettier::Parser < Ripper
1445
1953
  }
1446
1954
  end
1447
1955
 
1956
+ # lbrace is a scanner event representing the use of a left brace, i.e., "{".
1957
+ def on_lbrace(value)
1958
+ start_line = lineno
1959
+ start_char = char_pos
1960
+
1961
+ node = {
1962
+ type: :@lbrace,
1963
+ body: value,
1964
+ sl: start_line,
1965
+ el: start_line,
1966
+ sc: start_char,
1967
+ ec: start_char + value.size
1968
+ }
1969
+
1970
+ scanner_events << node
1971
+ node
1972
+ end
1973
+
1974
+ # lbracket is a scanner event representing the use of a left bracket, i.e.,
1975
+ # "[".
1976
+ def on_lbracket(value)
1977
+ start_line = lineno
1978
+ start_char = char_pos
1979
+
1980
+ node = {
1981
+ type: :@lbracket,
1982
+ body: value,
1983
+ sl: start_line,
1984
+ el: start_line,
1985
+ sc: start_char,
1986
+ ec: start_char + value.size
1987
+ }
1988
+
1989
+ scanner_events << node
1990
+ node
1991
+ end
1992
+
1993
+ # lparen is a scanner event representing the use of a left parenthesis, i.e.,
1994
+ # "(".
1995
+ def on_lparen(value)
1996
+ start_line = lineno
1997
+ start_char = char_pos
1998
+
1999
+ node = {
2000
+ type: :@lparen,
2001
+ body: value,
2002
+ sl: start_line,
2003
+ el: start_line,
2004
+ sc: start_char,
2005
+ ec: start_char + value.size
2006
+ }
2007
+
2008
+ scanner_events << node
2009
+ node
2010
+ end
2011
+
2012
+ # magic_comment is a scanner event that represents the use of a pragma at the
2013
+ # beginning of the file. Usually it will inside something like
2014
+ # frozen_string_literal (the key) with a value of true (the value). Both
2015
+ # children come is a string literals.
2016
+ def on_magic_comment(key, value)
2017
+ start_line = lineno
2018
+ start_char = char_pos
2019
+
2020
+ @magic_comment = {
2021
+ type: :@comment,
2022
+ value: " #{key}: #{value}",
2023
+ sl: start_line,
2024
+ el: start_line,
2025
+ sc: start_char,
2026
+ ec: start_char + @line_counts[start_line][-1]
2027
+ }
2028
+ end
2029
+
1448
2030
  # massign is a parser event that is a parent node of any kind of multiple
1449
2031
  # assignment. This includes splitting out variables on the left like:
1450
2032
  #
@@ -1675,6 +2257,52 @@ class Prettier::Parser < Ripper
1675
2257
  )
1676
2258
  end
1677
2259
 
2260
+ # nl is a scanner event representing a newline in the source. As you can
2261
+ # imagine, it will typically get triggered quite a few times. We don't need to
2262
+ # track this event in the AST that we're generating, so we're not going to
2263
+ # define an explicit handler for it.
2264
+ #
2265
+ # def on_nl(value)
2266
+ # value
2267
+ # end
2268
+
2269
+ # nokw_param is a parser event that represents the use of the special 2.7+
2270
+ # syntax to indicate a method should take no additional keyword arguments. For
2271
+ # example in the following snippet:
2272
+ #
2273
+ # def foo(**nil) end
2274
+ #
2275
+ # this is saying that foo should not accept any keyword arguments. Its value
2276
+ # is always nil. We don't need to track this event in the AST that we're
2277
+ # generating, so we're not going to define an explicit handler for it.
2278
+ #
2279
+ # def on_nokw_param(value)
2280
+ # value
2281
+ # end
2282
+
2283
+ # op is a scanner event representing an operator literal in the source. For
2284
+ # example, in the following snippet:
2285
+ #
2286
+ # 1 + 2
2287
+ #
2288
+ # the + sign is an operator.
2289
+ def on_op(value)
2290
+ start_line = lineno
2291
+ start_char = char_pos
2292
+
2293
+ node = {
2294
+ type: :@op,
2295
+ body: value,
2296
+ sl: start_line,
2297
+ el: start_line,
2298
+ sc: start_char,
2299
+ ec: start_char + value.size
2300
+ }
2301
+
2302
+ scanner_events << node
2303
+ node
2304
+ end
2305
+
1678
2306
  # opassign is a parser event that represents assigning something to a
1679
2307
  # variable or constant using an operator like += or ||=. It accepts as
1680
2308
  # arguments the left side of the expression before the operator, the
@@ -1688,6 +2316,20 @@ class Prettier::Parser < Ripper
1688
2316
  )
1689
2317
  end
1690
2318
 
2319
+ # operator_ambiguous is a parser event that represents when the parsers sees
2320
+ # an operator as ambiguous. For example, in the following snippet:
2321
+ #
2322
+ # foo %[]
2323
+ #
2324
+ # the question becomes if the percent sign is being used as a method call or
2325
+ # if it's the start of a string literal. We don't need to track this event in
2326
+ # the AST that we're generating, so we're not going to define an explicit
2327
+ # handler for it.
2328
+ #
2329
+ # def on_operator_ambiguous(value)
2330
+ # value
2331
+ # end
2332
+
1691
2333
  # params is a parser event that represents defining parameters on a
1692
2334
  # method. They have a somewhat interesting structure in that they are an
1693
2335
  # array of arrays where the position in the top-level array indicates the
@@ -1714,31 +2356,25 @@ class Prettier::Parser < Ripper
1714
2356
  # anywhere in a Ruby program. It accepts as arguments the contents, which
1715
2357
  # can be either params or statements.
1716
2358
  def on_paren(contents)
1717
- beging = find_scanner_event(:@lparen)
1718
- ending = find_scanner_event(:@rparen)
2359
+ lparen = find_scanner_event(:@lparen)
2360
+ rparen = find_scanner_event(:@rparen)
1719
2361
 
1720
2362
  if contents && contents[:type] == :params
1721
- contents.merge!(sc: beging[:ec], ec: ending[:sc])
2363
+ contents.merge!(
2364
+ sc: find_next_statement_start(lparen[:ec]),
2365
+ ec: rparen[:sc]
2366
+ )
1722
2367
  end
1723
2368
 
1724
- beging.merge!(
2369
+ {
1725
2370
  type: :paren,
2371
+ lparen: lparen,
1726
2372
  body: [contents],
1727
- el: ending[:el],
1728
- ec: ending[:ec]
1729
- )
1730
- end
1731
-
1732
- # A special parser error so that we can get nice syntax displays on the error
1733
- # message when prettier prints out the results.
1734
- class ParserError < StandardError
1735
- attr_reader :lineno, :column
1736
-
1737
- def initialize(error, lineno, column)
1738
- super(error)
1739
- @lineno = lineno
1740
- @column = column
1741
- end
2373
+ sl: lparen[:sl],
2374
+ sc: lparen[:sc],
2375
+ el: rparen[:el],
2376
+ ec: rparen[:ec]
2377
+ }
1742
2378
  end
1743
2379
 
1744
2380
  # If we encounter a parse error, just immediately bail out so that our runner
@@ -1751,6 +2387,22 @@ class Prettier::Parser < Ripper
1751
2387
  alias on_class_name_error on_parse_error
1752
2388
  alias on_param_error on_parse_error
1753
2389
 
2390
+ # period is a scanner event that represents the use of the period operator. It
2391
+ # is usually found in method calls.
2392
+ def on_period(value)
2393
+ start_line = lineno
2394
+ start_char = char_pos
2395
+
2396
+ {
2397
+ type: :@period,
2398
+ body: value,
2399
+ sl: start_line,
2400
+ el: start_line,
2401
+ sc: start_char,
2402
+ ec: start_char + value.size
2403
+ }
2404
+ end
2405
+
1754
2406
  # The program node is the very top of the AST. Here we'll attach all of
1755
2407
  # the comments that we've gathered up over the course of parsing the
1756
2408
  # source string. We'll also attach on the __END__ content if there was
@@ -1764,6 +2416,29 @@ class Prettier::Parser < Ripper
1764
2416
  range.merge(type: :program, body: [stmts], comments: @comments)
1765
2417
  end
1766
2418
 
2419
+ # qsymbols_beg is a scanner event that represents the beginning of a symbol
2420
+ # literal array. For example in the following snippet:
2421
+ #
2422
+ # %i[foo bar baz]
2423
+ #
2424
+ # a qsymbols_beg would be triggered with the value of "%i[".
2425
+ def on_qsymbols_beg(value)
2426
+ start_line = lineno
2427
+ start_char = char_pos
2428
+
2429
+ node = {
2430
+ type: :@qsymbols_beg,
2431
+ body: value,
2432
+ sl: start_line,
2433
+ el: start_line,
2434
+ sc: start_char,
2435
+ ec: start_char + value.size
2436
+ }
2437
+
2438
+ scanner_events << node
2439
+ node
2440
+ end
2441
+
1767
2442
  # qsymbols_new is a parser event that represents the beginning of a symbol
1768
2443
  # literal array, like %i[one two three]. It can be followed by any number
1769
2444
  # of qsymbols_add events, which we'll append onto an array body.
@@ -1783,6 +2458,29 @@ class Prettier::Parser < Ripper
1783
2458
  )
1784
2459
  end
1785
2460
 
2461
+ # qwords_beg is a scanner event that represents the beginning of a word
2462
+ # literal array. For example in the following snippet:
2463
+ #
2464
+ # %w[foo bar baz]
2465
+ #
2466
+ # a qwords_beg would be triggered with the value of "%w[".
2467
+ def on_qwords_beg(value)
2468
+ start_line = lineno
2469
+ start_char = char_pos
2470
+
2471
+ node = {
2472
+ type: :@qwords_beg,
2473
+ body: value,
2474
+ sl: start_line,
2475
+ el: start_line,
2476
+ sc: start_char,
2477
+ ec: start_char + value.size
2478
+ }
2479
+
2480
+ scanner_events << node
2481
+ node
2482
+ end
2483
+
1786
2484
  # qwords_new is a parser event that represents the beginning of a string
1787
2485
  # literal array, like %w[one two three]. It can be followed by any number
1788
2486
  # of qwords_add events, which we'll append onto an array body.
@@ -1802,24 +2500,73 @@ class Prettier::Parser < Ripper
1802
2500
  )
1803
2501
  end
1804
2502
 
2503
+ # rational is a scanner event that represents a rational number literal.
2504
+ def on_rational(value)
2505
+ start_line = lineno
2506
+ start_char = char_pos
2507
+
2508
+ node = {
2509
+ type: :@rational,
2510
+ body: value,
2511
+ sl: start_line,
2512
+ el: start_line,
2513
+ sc: start_char,
2514
+ ec: start_char + value.size
2515
+ }
2516
+
2517
+ scanner_events << node
2518
+ node
2519
+ end
2520
+
2521
+ # rbrace is a scanner event that represents the use of a right brace, i.e.,
2522
+ # "}".
2523
+ def on_rbrace(value)
2524
+ start_line = lineno
2525
+ start_char = char_pos
2526
+
2527
+ node = {
2528
+ type: :@rbrace,
2529
+ body: value,
2530
+ sl: start_line,
2531
+ el: start_line,
2532
+ sc: start_char,
2533
+ ec: start_char + value.size
2534
+ }
2535
+
2536
+ scanner_events << node
2537
+ node
2538
+ end
2539
+
2540
+ # rbracket is a scanner event that represents the use of a right bracket,
2541
+ # i.e., "]".
2542
+ def on_rbracket(value)
2543
+ start_line = lineno
2544
+ start_char = char_pos
2545
+
2546
+ node = {
2547
+ type: :@rbracket,
2548
+ body: value,
2549
+ sl: start_line,
2550
+ el: start_line,
2551
+ sc: start_char,
2552
+ ec: start_char + value.size
2553
+ }
2554
+
2555
+ scanner_events << node
2556
+ node
2557
+ end
2558
+
1805
2559
  # redo is a parser event that represents the bare redo keyword. It has no
1806
2560
  # body as it accepts no arguments.
1807
2561
  def on_redo
1808
2562
  find_scanner_event(:@kw, 'redo').merge!(type: :redo)
1809
2563
  end
1810
2564
 
1811
- # regexp_new is a parser event that represents the beginning of a regular
1812
- # expression literal, like /foo/. It can be followed by any number of
1813
- # regexp_add events, which we'll append onto an array body.
1814
- def on_regexp_new
1815
- beging = find_scanner_event(:@regexp_beg)
1816
- beging.merge!(type: :regexp, body: [], beging: beging[:body])
1817
- end
1818
-
1819
- # regexp_add is a parser event that represents a piece of a regular
2565
+ # regexp_add is a parser event that represents a piece of a regular expression
1820
2566
  # body. It accepts as arguments the parent regexp node as well as a
1821
- # tstring_content scanner event representing string content or a
1822
- # string_embexpr parser event representing interpolated content.
2567
+ # tstring_content scanner event representing string content, a
2568
+ # string_embexpr parser event representing interpolated content, or a
2569
+ # string_dvar parser event representing an interpolated variable.
1823
2570
  def on_regexp_add(regexp, piece)
1824
2571
  regexp.merge!(
1825
2572
  body: regexp[:body] << piece,
@@ -1828,6 +2575,43 @@ class Prettier::Parser < Ripper
1828
2575
  )
1829
2576
  end
1830
2577
 
2578
+ # regexp_beg is a scanner event that represents the start of a regular
2579
+ # expression. It can take a couple of forms since regexp can either start with
2580
+ # a forward slash or a %r.
2581
+ def on_regexp_beg(value)
2582
+ start_line = lineno
2583
+ start_char = char_pos
2584
+
2585
+ node = {
2586
+ type: :@regexp_beg,
2587
+ body: value,
2588
+ sl: start_line,
2589
+ el: start_line,
2590
+ sc: start_char,
2591
+ ec: start_char + value.size
2592
+ }
2593
+
2594
+ scanner_events << node
2595
+ node
2596
+ end
2597
+
2598
+ # regexp_end is a scanner event that represents the end of a regular
2599
+ # expression. It will contain the closing brace or slash, as well as any flags
2600
+ # being passed to the regexp.
2601
+ def on_regexp_end(value)
2602
+ start_line = lineno
2603
+ start_char = char_pos
2604
+
2605
+ {
2606
+ type: :@regexp_end,
2607
+ body: value,
2608
+ sl: start_line,
2609
+ el: start_line,
2610
+ sc: start_char,
2611
+ ec: start_char + value.size
2612
+ }
2613
+ end
2614
+
1831
2615
  # regexp_literal is a parser event that represents a regular expression.
1832
2616
  # It accepts as arguments a regexp node which is a built-up array of
1833
2617
  # pieces that go into the regexp content, as well as the ending used to
@@ -1841,16 +2625,24 @@ class Prettier::Parser < Ripper
1841
2625
  )
1842
2626
  end
1843
2627
 
2628
+ # regexp_new is a parser event that represents the beginning of a regular
2629
+ # expression literal, like /foo/. It can be followed by any number of
2630
+ # regexp_add events, which we'll append onto an array body.
2631
+ def on_regexp_new
2632
+ beging = find_scanner_event(:@regexp_beg)
2633
+ beging.merge!(type: :regexp, body: [], beging: beging[:body])
2634
+ end
2635
+
1844
2636
  # rescue is a special kind of node where you have a rescue chain but it
1845
2637
  # doesn't really have all of the information that it needs in order to
1846
2638
  # determine its ending. Therefore it relies on its parent bodystmt node to
1847
2639
  # report its ending to it.
1848
- class Rescue < SimpleDelegator
2640
+ class Rescue < Node
1849
2641
  def bind_end(ec)
1850
- merge!(ec: ec)
2642
+ value.merge!(ec: ec)
1851
2643
 
1852
- stmts = self[:body][1]
1853
- consequent = self[:body][2]
2644
+ stmts = value[:body][1]
2645
+ consequent = value[:body][2]
1854
2646
 
1855
2647
  if consequent
1856
2648
  consequent.bind_end(ec)
@@ -1886,6 +2678,7 @@ class Prettier::Parser < Ripper
1886
2678
  end
1887
2679
 
1888
2680
  Rescue.new(
2681
+ self,
1889
2682
  beging.merge!(
1890
2683
  type: :rescue,
1891
2684
  body: [rescue_ex, stmts, consequent],
@@ -1953,6 +2746,25 @@ class Prettier::Parser < Ripper
1953
2746
  find_scanner_event(:@kw, 'return').merge!(type: :return0)
1954
2747
  end
1955
2748
 
2749
+ # rparen is a scanner event that represents the use of a right parenthesis,
2750
+ # i.e., ")".
2751
+ def on_rparen(value)
2752
+ start_line = lineno
2753
+ start_char = char_pos
2754
+
2755
+ node = {
2756
+ type: :@rparen,
2757
+ body: value,
2758
+ sl: start_line,
2759
+ el: start_line,
2760
+ sc: start_char,
2761
+ ec: start_char + value.size
2762
+ }
2763
+
2764
+ scanner_events << node
2765
+ node
2766
+ end
2767
+
1956
2768
  # sclass is a parser event that represents a block of statements that
1957
2769
  # should be evaluated within the context of the singleton class of an
1958
2770
  # object. It's frequently used to define singleton methods. It looks like
@@ -1979,6 +2791,31 @@ class Prettier::Parser < Ripper
1979
2791
  }
1980
2792
  end
1981
2793
 
2794
+ # semicolon is a scanner event that represents the use of a semicolon in the
2795
+ # source. We don't need to track this event in the AST that we're generating,
2796
+ # so we're not going to define an explicit handler for it.
2797
+ #
2798
+ # def on_semicolon(value)
2799
+ # value
2800
+ # end
2801
+
2802
+ # sp is a scanner event that represents the use of a space in the source. As
2803
+ # you can imagine, this event gets triggered quite often. We don't need to
2804
+ # track this event in the AST that we're generating, so we're not going to
2805
+ # define an explicit handler for it.
2806
+ #
2807
+ # def on_sp(value)
2808
+ # value
2809
+ # end
2810
+
2811
+ # stmts_add is a parser event that represents a single statement inside a
2812
+ # list of statements within any lexical block. It accepts as arguments the
2813
+ # parent stmts node as well as an stmt which can be any expression in
2814
+ # Ruby.
2815
+ def on_stmts_add(stmts, stmt)
2816
+ stmts << stmt
2817
+ end
2818
+
1982
2819
  # Everything that has a block of code inside of it has a list of statements.
1983
2820
  # Normally we would just track those as a node that has an array body, but we
1984
2821
  # have some special handling in order to handle empty statement lists. They
@@ -1986,36 +2823,29 @@ class Prettier::Parser < Ripper
1986
2823
  # stmts nodes will report back down the location information. We then
1987
2824
  # propagate that onto void_stmt nodes inside the stmts in order to make sure
1988
2825
  # all comments get printed appropriately.
1989
- class Stmts < SimpleDelegator
1990
- attr_reader :parser
1991
-
1992
- def initialize(parser, values)
1993
- @parser = parser
1994
- __setobj__(values)
1995
- end
1996
-
2826
+ class Stmts < Node
1997
2827
  def bind(sc, ec)
1998
- merge!(sc: sc, ec: ec)
2828
+ value.merge!(sc: sc, ec: ec)
1999
2829
 
2000
- if self[:body][0][:type] == :void_stmt
2001
- self[:body][0].merge!(sc: sc, ec: sc)
2830
+ if value[:body][0][:type] == :void_stmt
2831
+ value[:body][0].merge!(sc: sc, ec: sc)
2002
2832
  end
2003
2833
 
2004
2834
  attach_comments(sc, ec)
2005
2835
  end
2006
2836
 
2007
2837
  def bind_end(ec)
2008
- merge!(ec: ec)
2838
+ value.merge!(ec: ec)
2009
2839
  end
2010
2840
 
2011
2841
  def <<(statement)
2012
- if self[:body].any?
2013
- merge!(statement.slice(:el, :ec))
2842
+ if value[:body].any?
2843
+ value.merge!(statement.slice(:el, :ec))
2014
2844
  else
2015
- merge!(statement.slice(:sl, :el, :sc, :ec))
2845
+ value.merge!(statement.slice(:sl, :el, :sc, :ec))
2016
2846
  end
2017
2847
 
2018
- self[:body] << statement
2848
+ value[:body] << statement
2019
2849
  self
2020
2850
  end
2021
2851
 
@@ -2032,7 +2862,7 @@ class Prettier::Parser < Ripper
2032
2862
  return if attachable.empty?
2033
2863
 
2034
2864
  parser.comments -= attachable
2035
- self[:body] = (self[:body] + attachable).sort_by! { |node| node[:sc] }
2865
+ value[:body] = (value[:body] + attachable).sort_by! { |node| node[:sc] }
2036
2866
  end
2037
2867
  end
2038
2868
 
@@ -2051,12 +2881,12 @@ class Prettier::Parser < Ripper
2051
2881
  )
2052
2882
  end
2053
2883
 
2054
- # stmts_add is a parser event that represents a single statement inside a
2055
- # list of statements within any lexical block. It accepts as arguments the
2056
- # parent stmts node as well as an stmt which can be any expression in
2057
- # Ruby.
2058
- def on_stmts_add(stmts, stmt)
2059
- stmts << stmt
2884
+ # string_add is a parser event that represents a piece of a string. It
2885
+ # could be plain @tstring_content, string_embexpr, or string_dvar nodes.
2886
+ # It accepts as arguments the parent string node as well as the additional
2887
+ # piece of the string.
2888
+ def on_string_add(string, piece)
2889
+ string.merge!(body: string[:body] << piece, el: piece[:el], ec: piece[:ec])
2060
2890
  end
2061
2891
 
2062
2892
  # string_concat is a parser event that represents concatenating two
@@ -2092,14 +2922,6 @@ class Prettier::Parser < Ripper
2092
2922
  }
2093
2923
  end
2094
2924
 
2095
- # string_add is a parser event that represents a piece of a string. It
2096
- # could be plain @tstring_content, string_embexpr, or string_dvar nodes.
2097
- # It accepts as arguments the parent string node as well as the additional
2098
- # piece of the string.
2099
- def on_string_add(string, piece)
2100
- string.merge!(body: string[:body] << piece, el: piece[:el], ec: piece[:ec])
2101
- end
2102
-
2103
2925
  # string_dvar is a parser event that represents a very special kind of
2104
2926
  # interpolation into string. It allows you to take an instance variable,
2105
2927
  # class variable, or global variable and omit the braces when
@@ -2170,16 +2992,33 @@ class Prettier::Parser < Ripper
2170
2992
  )
2171
2993
  end
2172
2994
 
2995
+ # symbeg is a scanner event that represents the beginning of a symbol literal.
2996
+ # In most cases it will contain just ":" as in the value, but if its a dynamic
2997
+ # symbol being defined it will contain ":'" or ":\"".
2998
+ def on_symbeg(value)
2999
+ start_line = lineno
3000
+ start_char = char_pos
3001
+
3002
+ node = {
3003
+ type: :@symbeg,
3004
+ body: value,
3005
+ sl: start_line,
3006
+ el: start_line,
3007
+ sc: start_char,
3008
+ ec: start_char + value.size
3009
+ }
3010
+
3011
+ scanner_events << node
3012
+ node
3013
+ end
3014
+
2173
3015
  # A symbol is a parser event that immediately descends from a symbol
2174
3016
  # literal and contains an ident representing the contents of the symbol.
2175
3017
  def on_symbol(ident)
2176
- # What the heck is this here for you ask!? Turns out when Ripper is lexing
2177
- # source text, it turns symbols into keywords if their contents match, which
2178
- # will mess up the location information of all of our other nodes.
2179
- #
2180
- # So for example instead of { type: :@ident, body: "class" } you would
2181
- # instead get { type: :@kw, body: "class" } which is all kinds of
2182
- # problematic.
3018
+ # When ripper is lexing source text, it turns symbols into keywords if their
3019
+ # contents match, which will mess up the location information of all of our
3020
+ # other nodes. So for example instead of { type: :@ident, body: "class" }
3021
+ # you would instead get { type: :@kw, body: "class" }.
2183
3022
  #
2184
3023
  # In order to take care of this, we explicitly delete this scanner event
2185
3024
  # from the stack to make sure it doesn't screw things up.
@@ -2201,6 +3040,29 @@ class Prettier::Parser < Ripper
2201
3040
  end
2202
3041
  end
2203
3042
 
3043
+ # symbols_beg is a scanner event that represents the start of a symbol literal
3044
+ # array with interpolation. For example, in the following snippet:
3045
+ #
3046
+ # %I[foo bar baz]
3047
+ #
3048
+ # symbols_beg would be triggered with the value of "%I".
3049
+ def on_symbols_beg(value)
3050
+ start_line = lineno
3051
+ start_char = char_pos
3052
+
3053
+ node = {
3054
+ type: :@symbols_beg,
3055
+ body: value,
3056
+ sl: start_line,
3057
+ el: start_line,
3058
+ sc: start_char,
3059
+ ec: start_char + value.size
3060
+ }
3061
+
3062
+ scanner_events << node
3063
+ node
3064
+ end
3065
+
2204
3066
  # symbols_new is a parser event that represents the beginning of a symbol
2205
3067
  # literal array that accepts interpolation, like %I[one #{two} three]. It
2206
3068
  # can be followed by any number of symbols_add events, which we'll append
@@ -2221,17 +3083,42 @@ class Prettier::Parser < Ripper
2221
3083
  )
2222
3084
  end
2223
3085
 
2224
- # A helper function to find a :: operator for the next two nodes. We do
2225
- # special handling instead of using find_scanner_event here because we
2226
- # don't pop off all of the :: operators so you could end up getting the
2227
- # wrong information if you have for instance ::X::Y::Z.
2228
- def find_colon2_before(const)
2229
- index =
2230
- scanner_events.rindex do |event|
2231
- event[:type] == :@op && event[:body] == '::' && event[:sc] < const[:sc]
2232
- end
3086
+ # tlambda is a scanner event that represents the beginning of a lambda
3087
+ # literal. It always has the value of "->".
3088
+ def on_tlambda(value)
3089
+ start_line = lineno
3090
+ start_char = char_pos
2233
3091
 
2234
- scanner_events[index]
3092
+ node = {
3093
+ type: :@tlambda,
3094
+ body: value,
3095
+ sl: start_line,
3096
+ el: start_line,
3097
+ sc: start_char,
3098
+ ec: start_char + value.size
3099
+ }
3100
+
3101
+ scanner_events << node
3102
+ node
3103
+ end
3104
+
3105
+ # tlambeg is a scanner event that represents the beginning of the body of a
3106
+ # lambda literal. It always has the value of "{".
3107
+ def on_tlambeg(value)
3108
+ start_line = lineno
3109
+ start_char = char_pos
3110
+
3111
+ node = {
3112
+ type: :@tlambeg,
3113
+ body: value,
3114
+ sl: start_line,
3115
+ el: start_line,
3116
+ sc: start_char,
3117
+ ec: start_char + value.size
3118
+ }
3119
+
3120
+ scanner_events << node
3121
+ node
2235
3122
  end
2236
3123
 
2237
3124
  # A top_const_field is a parser event that is always the child of some
@@ -2266,6 +3153,63 @@ class Prettier::Parser < Ripper
2266
3153
  )
2267
3154
  end
2268
3155
 
3156
+ # tstring_beg is a scanner event that represents the beginning of a string
3157
+ # literal. It can represent either of the quotes for its value, or it can have
3158
+ # a %q/%Q with delimiter.
3159
+ def on_tstring_beg(value)
3160
+ start_line = lineno
3161
+ start_char = char_pos
3162
+
3163
+ node = {
3164
+ type: :@tstring_beg,
3165
+ body: value,
3166
+ sl: start_line,
3167
+ el: start_line,
3168
+ sc: start_char,
3169
+ ec: start_char + value.size
3170
+ }
3171
+
3172
+ scanner_events << node
3173
+ node
3174
+ end
3175
+
3176
+ # tstring_content is a scanner event that represents plain characters inside
3177
+ # of a string, heredoc, xstring, or regexp. Like comments, we need to force
3178
+ # the encoding here so JSON doesn't break.
3179
+ def on_tstring_content(value)
3180
+ start_line = lineno
3181
+ start_char = char_pos
3182
+
3183
+ {
3184
+ type: :@tstring_content,
3185
+ body: value.force_encoding('UTF-8'),
3186
+ sl: start_line,
3187
+ el: start_line,
3188
+ sc: start_char,
3189
+ ec: start_char + value.size
3190
+ }
3191
+ end
3192
+
3193
+ # tstring_end is a scanner event that represents the end of a string literal.
3194
+ # It can either contain quotes, or it can have the end delimiter of a %q/%Q
3195
+ # literal.
3196
+ def on_tstring_end(value)
3197
+ start_line = lineno
3198
+ start_char = char_pos
3199
+
3200
+ node = {
3201
+ type: :@tstring_end,
3202
+ body: value,
3203
+ sl: start_line,
3204
+ el: start_line,
3205
+ sc: start_char,
3206
+ ec: start_char + value.size
3207
+ }
3208
+
3209
+ scanner_events << node
3210
+ node
3211
+ end
3212
+
2269
3213
  # A unary node represents a unary method being called on an expression, as
2270
3214
  # in !, ~, or not. We have somewhat special handling of the not operator
2271
3215
  # since if it has parentheses they don't get reported as a paren node for
@@ -2563,6 +3507,48 @@ class Prettier::Parser < Ripper
2563
3507
  end
2564
3508
  end
2565
3509
 
3510
+ # words_beg is a scanner event that represents the start of a word literal
3511
+ # array with interpolation. For example, in the following snippet:
3512
+ #
3513
+ # %W[foo bar baz]
3514
+ #
3515
+ # words_beg would be triggered with the value of "%W".
3516
+ def on_words_beg(value)
3517
+ start_line = lineno
3518
+ start_char = char_pos
3519
+
3520
+ node = {
3521
+ type: :@words_beg,
3522
+ body: value,
3523
+ sl: start_line,
3524
+ el: start_line,
3525
+ sc: start_char,
3526
+ ec: start_char + value.size
3527
+ }
3528
+
3529
+ scanner_events << node
3530
+ node
3531
+ end
3532
+
3533
+ # words_sep is a scanner event that represents the separate between two words
3534
+ # inside of a word literal array. It contains any amount of whitespace
3535
+ # characters that are used to delimit the words. For example,
3536
+ #
3537
+ # %w[
3538
+ # foo
3539
+ # bar
3540
+ # baz
3541
+ # ]
3542
+ #
3543
+ # in the snippet above there would be two words_sep events triggered, one
3544
+ # between foo and bar and one between bar and baz. We don't need to track this
3545
+ # event in the AST that we're generating, so we're not going to define an
3546
+ # explicit handler for it.
3547
+ #
3548
+ # def on_words_sep(value)
3549
+ # value
3550
+ # end
3551
+
2566
3552
  # words_new is a parser event that represents the beginning of a string
2567
3553
  # literal array that accepts interpolation, like %W[one #{two} three]. It
2568
3554
  # can be followed by any number of words_add events, which we'll append