prettier 1.6.0 → 2.0.0.pre.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +342 -288
  3. data/CONTRIBUTING.md +6 -9
  4. data/LICENSE +1 -1
  5. data/README.md +11 -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 +141 -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 +87 -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 +1195 -254
  54. data/dist/ruby/printer.js +129 -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 -17
  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 +2573 -2264
  76. data/node_modules/prettier/doc.js +4829 -0
  77. data/node_modules/prettier/index.js +5979 -6846
  78. data/node_modules/prettier/package.json +23 -0
  79. data/node_modules/prettier/parser-angular.js +13 -14
  80. data/node_modules/prettier/parser-babel.js +7 -7
  81. data/node_modules/prettier/parser-espree.js +7 -7
  82. data/node_modules/prettier/parser-flow.js +7 -7
  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 +17 -17
  86. data/node_modules/prettier/parser-markdown.js +9 -9
  87. data/node_modules/prettier/parser-meriyah.js +7 -7
  88. data/node_modules/prettier/parser-postcss.js +2 -2
  89. data/node_modules/prettier/parser-typescript.js +7 -7
  90. data/node_modules/prettier/parser-yaml.js +2 -2
  91. data/node_modules/prettier/third-party.js +794 -131
  92. data/package.json +26 -18
  93. metadata +76 -67
  94. data/src/haml/embed.js +0 -87
  95. data/src/haml/parser.js +0 -23
  96. data/src/haml/printer.js +0 -438
  97. data/src/parser/parseSync.js +0 -172
  98. data/src/parser/server.rb +0 -66
  99. data/src/plugin.js +0 -148
  100. data/src/prettier.js +0 -16
  101. data/src/rbs/parser.js +0 -37
  102. data/src/rbs/printer.js +0 -643
  103. data/src/ruby/embed.js +0 -142
  104. data/src/ruby/nodes/alias.js +0 -73
  105. data/src/ruby/nodes/args.js +0 -222
  106. data/src/ruby/nodes/arrays.js +0 -162
  107. data/src/ruby/nodes/assign.js +0 -47
  108. data/src/ruby/nodes/blocks.js +0 -90
  109. data/src/ruby/nodes/calls.js +0 -206
  110. data/src/ruby/nodes/case.js +0 -65
  111. data/src/ruby/nodes/class.js +0 -64
  112. data/src/ruby/nodes/commands.js +0 -131
  113. data/src/ruby/nodes/conditionals.js +0 -282
  114. data/src/ruby/nodes/constants.js +0 -43
  115. data/src/ruby/nodes/flow.js +0 -74
  116. data/src/ruby/nodes/hashes.js +0 -155
  117. data/src/ruby/nodes/heredocs.js +0 -36
  118. data/src/ruby/nodes/hooks.js +0 -34
  119. data/src/ruby/nodes/ints.js +0 -31
  120. data/src/ruby/nodes/lambdas.js +0 -76
  121. data/src/ruby/nodes/loops.js +0 -98
  122. data/src/ruby/nodes/massign.js +0 -98
  123. data/src/ruby/nodes/methods.js +0 -74
  124. data/src/ruby/nodes/operators.js +0 -83
  125. data/src/ruby/nodes/params.js +0 -106
  126. data/src/ruby/nodes/patterns.js +0 -157
  127. data/src/ruby/nodes/regexp.js +0 -56
  128. data/src/ruby/nodes/rescue.js +0 -101
  129. data/src/ruby/nodes/return.js +0 -94
  130. data/src/ruby/nodes/statements.js +0 -142
  131. data/src/ruby/nodes/strings.js +0 -270
  132. data/src/ruby/nodes/super.js +0 -35
  133. data/src/ruby/nodes/undef.js +0 -42
  134. data/src/ruby/nodes.js +0 -34
  135. data/src/ruby/parser.js +0 -37
  136. data/src/ruby/printer.js +0 -147
  137. data/src/ruby/toProc.js +0 -105
  138. data/src/utils/containsAssignment.js +0 -11
  139. data/src/utils/getTrailingComma.js +0 -5
  140. data/src/utils/hasAncestor.js +0 -17
  141. data/src/utils/isEmptyBodyStmt.js +0 -7
  142. data/src/utils/isEmptyStmts.js +0 -11
  143. data/src/utils/literal.js +0 -7
  144. data/src/utils/literallineWithoutBreakParent.js +0 -7
  145. data/src/utils/makeCall.js +0 -14
  146. data/src/utils/noIndent.js +0 -11
  147. data/src/utils/printEmptyCollection.js +0 -49
  148. data/src/utils/skipAssignIndent.js +0 -17
  149. 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.
@@ -16,6 +16,8 @@ end
16
16
  require 'json' unless defined?(JSON)
17
17
  require 'ripper'
18
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.
19
21
  module Prettier
20
22
  end
21
23
 
@@ -82,6 +84,18 @@ class Prettier::Parser < Ripper
82
84
  end
83
85
  end
84
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
+
85
99
  attr_reader :source, :lines, :scanner_events
86
100
 
87
101
  # This is an attr_accessor so Stmts objects can grab comments out of this
@@ -91,22 +105,58 @@ class Prettier::Parser < Ripper
91
105
  def initialize(source, *args)
92
106
  super(source, *args)
93
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.
94
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.
95
118
  @lines = source.split("\n")
96
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.
97
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.
98
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.
99
137
  @__end__ = nil
100
138
 
139
+ # Heredocs can actually be nested together if you're using interpolation, so
140
+ # this is a stack of heredoc nodes that are currently being created. When we
141
+ # get to the scanner event that finishes off a heredoc node, we pop the top
142
+ # one off. If there are others surrounding it, then the body events will now
143
+ # be added to the correct nodes.
101
144
  @heredocs = []
102
145
 
146
+ # This is a running list of scanner events that have fired. It's useful
147
+ # mostly for maintaining location information. For example, if you're inside
148
+ # the handle of a def event, then in order to determine where the AST node
149
+ # started, you need to look backward in the scanner events to find a def
150
+ # keyword. Most of the time, when a parser event consumes one of these
151
+ # events, it will be deleted from the list. So ideally, this list stays
152
+ # pretty short over the course of parsing a source string.
103
153
  @scanner_events = []
104
- @line_counts = []
105
154
 
106
155
  # Here we're going to build up a list of SingleByteString or MultiByteString
107
156
  # objects. They're each going to represent a string in the source. They are
108
157
  # used by the `char_pos` method to determine where we are in the source
109
158
  # string.
159
+ @line_counts = []
110
160
  last_index = 0
111
161
 
112
162
  @source.lines.each do |line|
@@ -157,114 +207,61 @@ class Prettier::Parser < Ripper
157
207
  (body == :any || (scanner_event[:body] == body))
158
208
  end
159
209
 
160
- consume ? scanner_events.delete_at(index) : (index && scanner_events[index])
161
- end
162
-
163
- # Scanner events occur when the lexer hits a new token, like a keyword or an
164
- # end. These nodes always contain just one argument which is a string
165
- # representing the content. For the most part these can just be printed
166
- # directly, which very few exceptions.
167
- defined = %i[
168
- comment
169
- embdoc
170
- embdoc_beg
171
- embdoc_end
172
- heredoc_beg
173
- heredoc_end
174
- ignored_nl
175
- ]
176
-
177
- (SCANNER_EVENTS - defined).each do |event|
178
- define_method(:"on_#{event}") do |value|
179
- ec = char_pos + value.size
180
- node = {
181
- type: :"@#{event}",
182
- body: value,
183
- sl: lineno,
184
- el: lineno,
185
- sc: char_pos,
186
- ec: ec
187
- }
210
+ if consume
211
+ # If we're expecting to be able to find a scanner event and consume it,
212
+ # but can't actually find it, then we need to raise an error. This is
213
+ # _usually_ caused by a syntax error in the source that we're printing. It
214
+ # could also be caused by accidentally attempting to consume a scanner
215
+ # event twice by two different parser event handlers.
216
+ unless index
217
+ message = "Cannot find expected #{body == :any ? type : body}"
218
+ raise ParserError.new(message, lineno, column)
219
+ end
188
220
 
189
- scanner_events << node
190
- node
221
+ scanner_events.delete_at(index)
222
+ elsif index
223
+ scanner_events[index]
191
224
  end
192
225
  end
193
226
 
194
- # We keep track of each comment as it comes in and then eventually add
195
- # them to the top of the generated AST so that prettier can start adding
196
- # them back into the final representation. Comments come in including
197
- # their starting pound sign and the newline at the end, so we also chop
198
- # those off.
199
- #
200
- # If there is an encoding magic comment at the top of the file, ripper
201
- # will actually change into that encoding for the storage of the string.
202
- # This will break everything, so we need to force the encoding back into
203
- # UTF-8 so that the JSON library won't break.
204
- def on_comment(value)
205
- @comments << {
206
- type: :@comment,
207
- value: value[1..-1].chomp.force_encoding('UTF-8'),
208
- inline: value.strip != lines[lineno - 1],
209
- sl: lineno,
210
- el: lineno,
211
- sc: char_pos,
212
- ec: char_pos + value.length - 1
213
- }
227
+ # A helper function to find a :: operator. We do special handling instead of
228
+ # using find_scanner_event here because we don't pop off all of the ::
229
+ # operators so you could end up getting the wrong information if you have for
230
+ # instance ::X::Y::Z.
231
+ def find_colon2_before(const)
232
+ index =
233
+ scanner_events.rindex do |event|
234
+ event[:type] == :@op && event[:body] == '::' && event[:sc] < const[:sc]
235
+ end
236
+
237
+ scanner_events[index]
214
238
  end
215
239
 
216
- # ignored_nl is a special kind of scanner event that passes nil as the value,
217
- # so we can't do our normal tracking of value.size. Instead of adding a
218
- # condition to the main SCANNER_EVENTS loop above, we'll just explicitly
219
- # define the method here. You can trigger the ignored_nl event with the
220
- # following snippet:
240
+ # Finds the next position in the source string that begins a statement. This
241
+ # is used to bind statements lists and make sure they don't include a
242
+ # preceding comment. For example, we want the following comment to be attached
243
+ # to the class node and not the statement node:
221
244
  #
222
- # foo.bar
223
- # .baz
245
+ # class Foo # :nodoc:
246
+ # ...
247
+ # end
224
248
  #
225
- def on_ignored_nl(value)
226
- {
227
- type: :ignored_nl,
228
- body: nil,
229
- sl: lineno,
230
- el: lineno,
231
- sc: char_pos,
232
- ec: char_pos
233
- }
234
- end
235
-
236
- prepend(
237
- Module.new do
238
- private
239
-
240
- # Handles __END__ syntax, which allows individual scripts to keep content
241
- # after the main ruby code that can be read through DATA. It looks like:
242
- #
243
- # foo.bar
244
- #
245
- # __END__
246
- # some other content that isn't normally read by ripper
247
- def on___end__(*)
248
- @__end__ = super(lines[lineno..-1].join("\n"))
249
- end
250
-
251
- # Like comments, we need to force the encoding here so JSON doesn't break.
252
- def on_ident(value)
253
- super(value.force_encoding('UTF-8'))
254
- end
249
+ # By finding the next non-space character, we can make sure that the bounds of
250
+ # the statement list are correct.
251
+ def find_next_statement_start(position)
252
+ remaining = source[position..-1]
255
253
 
256
- # Like comments, we need to force the encoding here so JSON doesn't break.
257
- def on_tstring_content(value)
258
- super(value.force_encoding('UTF-8'))
259
- end
254
+ if remaining.sub(/\A +/, '')[0] == '#'
255
+ return position + remaining.index("\n")
260
256
  end
261
- )
262
257
 
263
- # A BEGIN node is a parser event that represents the use of the BEGIN
264
- # keyword, which hooks into the lifecycle of the interpreter. It's a bit
265
- # of a legacy from the stream operating days, and gets its inspiration
266
- # from tools like awk. Whatever is inside the "block" will get executed
267
- # when the program starts. The syntax looks like the following:
258
+ position
259
+ end
260
+
261
+ # BEGIN is a parser event that represents the use of the BEGIN keyword, which
262
+ # hooks into the lifecycle of the interpreter. Whatever is inside the "block"
263
+ # will get executed when the program starts. The syntax looks like the
264
+ # following:
268
265
  #
269
266
  # BEGIN {
270
267
  # # execute stuff here
@@ -284,11 +281,35 @@ class Prettier::Parser < Ripper
284
281
  )
285
282
  end
286
283
 
287
- # A END node is a parser event that represents the use of the END keyword,
288
- # which hooks into the lifecycle of the interpreter. It's a bit of a
289
- # legacy from the stream operating days, and gets its inspiration from
290
- # tools like awk. Whatever is inside the "block" will get executed when
291
- # the program ends. The syntax looks like the following:
284
+ # CHAR is a parser event that represents a single codepoint in the script
285
+ # encoding. For example:
286
+ #
287
+ # ?a
288
+ #
289
+ # is a representation of the string literal "a". You can use control
290
+ # characters with this as well, as in ?\C-a.
291
+ #
292
+ def on_CHAR(value)
293
+ start_line = lineno
294
+ start_char = char_pos
295
+
296
+ node = {
297
+ type: :@CHAR,
298
+ body: value,
299
+ sl: start_line,
300
+ el: start_line,
301
+ sc: start_char,
302
+ ec: start_char + value.size
303
+ }
304
+
305
+ scanner_events << node
306
+ node
307
+ end
308
+
309
+ # END is a parser event that represents the use of the END keyword, which
310
+ # hooks into the lifecycle of the interpreter. Whatever is inside the "block"
311
+ # will get executed when the program ends. The syntax looks like the
312
+ # following:
292
313
  #
293
314
  # END {
294
315
  # # execute stuff here
@@ -308,11 +329,34 @@ class Prettier::Parser < Ripper
308
329
  )
309
330
  end
310
331
 
311
- # alias is a parser event that represents when you're using the alias
312
- # keyword with regular arguments. This can be either symbol literals or
313
- # bare words. You can optionally use parentheses with this keyword, so we
314
- # either track the location information based on those or the final
315
- # argument to the alias method.
332
+ # __END__ is a scanner event that represents __END__ syntax, which allows
333
+ # individual scripts to keep content after the main ruby code that can be read
334
+ # through the DATA constant. It looks like:
335
+ #
336
+ # puts DATA.read
337
+ #
338
+ # __END__
339
+ # some other content that isn't executed by the program
340
+ #
341
+ def on___end__(value)
342
+ start_line = lineno
343
+ start_char = char_pos
344
+
345
+ @__end__ = {
346
+ type: :@__end__,
347
+ body: lines[lineno..-1].join("\n"),
348
+ sl: start_line,
349
+ el: start_line,
350
+ sc: start_char,
351
+ ec: start_char + value.size
352
+ }
353
+ end
354
+
355
+ # alias is a parser event that represents the use of the alias keyword with
356
+ # regular arguments. This can be either symbol literals or bare words. You can
357
+ # optionally use parentheses with this keyword, so we either track the
358
+ # location information based on those or the final argument to the alias
359
+ # method.
316
360
  def on_alias(left, right)
317
361
  beging = find_scanner_event(:@kw, 'alias')
318
362
 
@@ -329,7 +373,7 @@ class Prettier::Parser < Ripper
329
373
  }
330
374
  end
331
375
 
332
- # aref nodes are when you're pulling a value out of a collection at a
376
+ # aref is a parser event when you're pulling a value out of a collection at a
333
377
  # specific index. Put another way, it's any time you're calling the method
334
378
  # #[]. As an example:
335
379
  #
@@ -373,26 +417,59 @@ class Prettier::Parser < Ripper
373
417
  }
374
418
  end
375
419
 
376
- # args_new is a parser event that represents the beginning of a list of
377
- # arguments to any method call or an array. It can be followed by any
378
- # number of args_add events, which we'll append onto an array body.
379
- def on_args_new
420
+ # arg_ambiguous is a parser event that represents when the parser sees an
421
+ # argument as ambiguous. For example, in the following snippet:
422
+ #
423
+ # foo //
424
+ #
425
+ # the question becomes if the forward slash is being used as a division
426
+ # operation or if it's the start of a regular expression. We don't need to
427
+ # track this event in the AST that we're generating, so we're not going to
428
+ # define an explicit handler for it.
429
+ #
430
+ # def on_arg_ambiguous(value)
431
+ # value
432
+ # end
433
+
434
+ # arg_paren is a parser event that represents wrapping arguments to a method
435
+ # inside a set of parentheses. For example, in the follow snippet:
436
+ #
437
+ # foo(bar)
438
+ #
439
+ # there would be an arg_paren node around the args_add_block node that
440
+ # represents the set of arguments being sent to the foo method. The args child
441
+ # node can be nil if no arguments were passed, as in:
442
+ #
443
+ # foo()
444
+ #
445
+ def on_arg_paren(args)
446
+ beging = find_scanner_event(:@lparen)
447
+ rparen = find_scanner_event(:@rparen)
448
+
449
+ # If the arguments exceed the ending of the parentheses, then we know we
450
+ # have a heredoc in the arguments, and we need to use the bounds of the
451
+ # arguments to determine how large the arg_paren is.
452
+ ending = (args && args[:el] > rparen[:el]) ? args : rparen
453
+
380
454
  {
381
- type: :args,
382
- body: [],
383
- sl: lineno,
384
- sc: char_pos,
385
- el: lineno,
386
- ec: char_pos
455
+ type: :arg_paren,
456
+ body: [args],
457
+ sl: beging[:sl],
458
+ sc: beging[:sc],
459
+ el: ending[:el],
460
+ ec: ending[:ec]
387
461
  }
388
462
  end
389
463
 
390
- # args_add is a parser event that represents a single argument inside a
391
- # list of arguments to any method call or an array. It accepts as
392
- # arguments the parent args node as well as an arg which can be anything
393
- # that could be passed as an argument.
464
+ # args_add is a parser event that represents a single argument inside a list
465
+ # of arguments to any method call or an array. It accepts as arguments the
466
+ # parent args node as well as an arg which can be anything that could be
467
+ # passed as an argument.
394
468
  def on_args_add(args, arg)
395
469
  if args[:body].empty?
470
+ # If this is the first argument being passed into the list of arguments,
471
+ # then we're going to use the bounds of the argument to override the
472
+ # parent node's location since this will be more accurate.
396
473
  arg.merge(type: :args, body: [arg])
397
474
  else
398
475
  args.merge!(body: args[:body] << arg, el: arg[:el], ec: arg[:ec])
@@ -401,7 +478,7 @@ class Prettier::Parser < Ripper
401
478
 
402
479
  # args_add_block is a parser event that represents a list of arguments and
403
480
  # potentially a block argument. If no block is passed, then the second
404
- # argument will be false.
481
+ # argument will be the literal false.
405
482
  def on_args_add_block(args, block)
406
483
  ending = block || args
407
484
 
@@ -436,24 +513,17 @@ class Prettier::Parser < Ripper
436
513
  find_scanner_event(:@op, '...').merge!(type: :args_forward)
437
514
  end
438
515
 
439
- # arg_paren is a parser event that represents wrapping arguments to a
440
- # method inside a set of parentheses.
441
- def on_arg_paren(args)
442
- beging = find_scanner_event(:@lparen)
443
- rparen = find_scanner_event(:@rparen)
444
-
445
- # If the arguments exceed the ending of the parentheses, then we know we
446
- # have a heredoc in the arguments, and we need to use the bounds of the
447
- # arguments to determine how large the arg_paren is.
448
- ending = (args && args[:el] > rparen[:el]) ? args : rparen
449
-
516
+ # args_new is a parser event that represents the beginning of a list of
517
+ # arguments to any method call or an array. It can be followed by any
518
+ # number of args_add events, which we'll append onto an array body.
519
+ def on_args_new
450
520
  {
451
- type: :arg_paren,
452
- body: [args],
453
- sl: beging[:sl],
454
- sc: beging[:sc],
455
- el: ending[:el],
456
- ec: ending[:ec]
521
+ type: :args,
522
+ body: [],
523
+ sl: lineno,
524
+ sc: char_pos,
525
+ el: lineno,
526
+ ec: char_pos
457
527
  }
458
528
  end
459
529
 
@@ -554,6 +624,45 @@ class Prettier::Parser < Ripper
554
624
  }
555
625
  end
556
626
 
627
+ # backref is a scanner event that represents a global variable referencing a
628
+ # matched value. It comes in the form of a $ followed by a positive integer.
629
+ def on_backref(value)
630
+ start_line = lineno
631
+ start_char = char_pos
632
+
633
+ node = {
634
+ type: :@backref,
635
+ body: value,
636
+ sl: start_line,
637
+ el: start_line,
638
+ sc: start_char,
639
+ ec: start_char + value.size
640
+ }
641
+
642
+ scanner_events << node
643
+ node
644
+ end
645
+
646
+ # backtick is a scanner event that represents the use of the ` operator. It's
647
+ # usually found being used for an xstring, but could also be found as the name
648
+ # of a method being defined.
649
+ def on_backtick(value)
650
+ start_line = lineno
651
+ start_char = char_pos
652
+
653
+ node = {
654
+ type: :@backtick,
655
+ body: value,
656
+ sl: start_line,
657
+ el: start_line,
658
+ sc: start_char,
659
+ ec: start_char + value.size
660
+ }
661
+
662
+ scanner_events << node
663
+ node
664
+ end
665
+
557
666
  # bare_assoc_hash is a parser event that represents a hash of contents
558
667
  # being passed as a method argument (and therefore has omitted braces). It
559
668
  # accepts as an argument an array of assoc events (either assoc_new or
@@ -684,11 +793,15 @@ class Prettier::Parser < Ripper
684
793
  beging = find_scanner_event(:@lbrace)
685
794
  ending = find_scanner_event(:@rbrace)
686
795
 
687
- stmts.bind((block_var || beging)[:ec], ending[:sc])
796
+ stmts.bind(
797
+ find_next_statement_start((block_var || beging)[:ec]),
798
+ ending[:sc]
799
+ )
688
800
 
689
801
  {
690
802
  type: :brace_block,
691
803
  body: [block_var, stmts],
804
+ beging: beging,
692
805
  sl: beging[:sl],
693
806
  sc: beging[:sc],
694
807
  el: [ending[:el], stmts[:el]].max,
@@ -768,27 +881,6 @@ class Prettier::Parser < Ripper
768
881
  )
769
882
  end
770
883
 
771
- # Finds the next position in the source string that begins a statement. This
772
- # is used to bind statements lists and make sure they don't include a
773
- # preceding comment. For example, we want the following comment to be attached
774
- # to the class node and not the statement node:
775
- #
776
- # class Foo # :nodoc:
777
- # ...
778
- # end
779
- #
780
- # By finding the next non-space character, we can make sure that the bounds of
781
- # the statement list are correct.
782
- def find_next_statement_start(position)
783
- remaining = source[position..-1]
784
-
785
- if remaining.sub(/\A +/, '')[0] == '#'
786
- return position + remaining.index("\n")
787
- end
788
-
789
- position
790
- end
791
-
792
884
  # class is a parser event that represents defining a class. It accepts as
793
885
  # arguments the name of the class, the optional name of the superclass,
794
886
  # and the bodystmt event that represents the statements evaluated within
@@ -812,6 +904,24 @@ class Prettier::Parser < Ripper
812
904
  }
813
905
  end
814
906
 
907
+ # comma is a scanner event that represents the use of the comma operator.
908
+ def on_comma(value)
909
+ start_line = lineno
910
+ start_char = char_pos
911
+
912
+ node = {
913
+ type: :@comma,
914
+ body: value,
915
+ sl: start_line,
916
+ el: start_line,
917
+ sc: start_char,
918
+ ec: start_char + value.size
919
+ }
920
+
921
+ scanner_events << node
922
+ node
923
+ end
924
+
815
925
  # command is a parser event representing a method call with arguments and
816
926
  # no parentheses. It accepts as arguments the name of the method and the
817
927
  # arguments being passed to the method.
@@ -843,6 +953,54 @@ class Prettier::Parser < Ripper
843
953
  }
844
954
  end
845
955
 
956
+ # We keep track of each comment as it comes in and then eventually add
957
+ # them to the top of the generated AST so that prettier can start adding
958
+ # them back into the final representation. Comments come in including
959
+ # their starting pound sign and the newline at the end, so we also chop
960
+ # those off.
961
+ def on_comment(value)
962
+ # If there is an encoding magic comment at the top of the file, ripper
963
+ # will actually change into that encoding for the storage of the string.
964
+ # This will break everything when we attempt to print as JSON, so we need to
965
+ # force the encoding back into UTF-8 so that it won't break.
966
+ body = value[1..-1].chomp.force_encoding('UTF-8')
967
+
968
+ start_line = lineno
969
+ start_char = char_pos
970
+
971
+ @comments << {
972
+ type: :@comment,
973
+ value: body,
974
+ inline: value.strip != lines[lineno - 1],
975
+ sl: start_line,
976
+ el: start_line,
977
+ sc: start_char,
978
+ ec: start_char + value.length - 1
979
+ }
980
+ end
981
+
982
+ # const is a scanner event that represents a literal value that _looks like_
983
+ # a constant. This could actually be a reference to a constant. It could also
984
+ # be something that looks like a constant in another context, as in a method
985
+ # call to a capitalized method, a symbol that starts with a capital letter,
986
+ # etc.
987
+ def on_const(value)
988
+ start_line = lineno
989
+ start_char = char_pos
990
+
991
+ node = {
992
+ type: :@const,
993
+ body: value,
994
+ sl: start_line,
995
+ el: start_line,
996
+ sc: start_char,
997
+ ec: start_char + value.size
998
+ }
999
+
1000
+ scanner_events << node
1001
+ node
1002
+ end
1003
+
846
1004
  # A const_path_field is a parser event that is always the child of some
847
1005
  # kind of assignment. It represents when you're assigning to a constant
848
1006
  # that is being referenced as a child of another variable. For example:
@@ -862,10 +1020,8 @@ class Prettier::Parser < Ripper
862
1020
 
863
1021
  # A const_path_ref is a parser event that is a very similar to
864
1022
  # const_path_field except that it is not involved in an assignment. It
865
- # looks like the following example:
866
- #
867
- # foo::X
868
- #
1023
+ # looks like the following example: foo::Bar, where left is foo and const is
1024
+ # Bar.
869
1025
  def on_const_path_ref(left, const)
870
1026
  {
871
1027
  type: :const_path_ref,
@@ -887,6 +1043,24 @@ class Prettier::Parser < Ripper
887
1043
  const.merge(type: :const_ref, body: [const])
888
1044
  end
889
1045
 
1046
+ # cvar is a scanner event that represents the use of a class variable.
1047
+ def on_cvar(value)
1048
+ start_line = lineno
1049
+ start_char = char_pos
1050
+
1051
+ node = {
1052
+ type: :@cvar,
1053
+ body: value,
1054
+ sl: start_line,
1055
+ el: start_line,
1056
+ sc: start_char,
1057
+ ec: start_char + value.size
1058
+ }
1059
+
1060
+ scanner_events << node
1061
+ node
1062
+ end
1063
+
890
1064
  # A def is a parser event that represents defining a regular method on the
891
1065
  # current self object. It accepts as arguments the ident (the name of the
892
1066
  # method being defined), the params (the parameter declaration for the
@@ -1016,11 +1190,15 @@ class Prettier::Parser < Ripper
1016
1190
  beging = find_scanner_event(:@kw, 'do')
1017
1191
  ending = find_scanner_event(:@kw, 'end')
1018
1192
 
1019
- bodystmt.bind((block_var || beging)[:ec], ending[:sc])
1193
+ bodystmt.bind(
1194
+ find_next_statement_start((block_var || beging)[:ec]),
1195
+ ending[:sc]
1196
+ )
1020
1197
 
1021
1198
  {
1022
1199
  type: :do_block,
1023
1200
  body: [block_var, bodystmt],
1201
+ beging: beging,
1024
1202
  sl: beging[:sl],
1025
1203
  sc: beging[:sc],
1026
1204
  el: ending[:el],
@@ -1113,25 +1291,22 @@ class Prettier::Parser < Ripper
1113
1291
  end
1114
1292
  end
1115
1293
 
1116
- # else can either end with an end keyword (in which case we'll want to
1117
- # consume that event) or it can end with an ensure keyword (in which case
1118
- # we'll leave that to the ensure to handle).
1119
- def find_else_ending
1294
+ # else is a parser event that represents the end of a if, unless, or begin
1295
+ # chain. It accepts as an argument the statements that are contained
1296
+ # within the else clause.
1297
+ def on_else(stmts)
1298
+ beging = find_scanner_event(:@kw, 'else')
1299
+
1300
+ # else can either end with an end keyword (in which case we'll want to
1301
+ # consume that event) or it can end with an ensure keyword (in which case
1302
+ # we'll leave that to the ensure to handle).
1120
1303
  index =
1121
1304
  scanner_events.rindex do |event|
1122
1305
  event[:type] == :@kw && %w[end ensure].include?(event[:body])
1123
1306
  end
1124
1307
 
1125
1308
  event = scanner_events[index]
1126
- event[:body] == 'end' ? scanner_events.delete_at(index) : event
1127
- end
1128
-
1129
- # else is a parser event that represents the end of a if, unless, or begin
1130
- # chain. It accepts as an argument the statements that are contained
1131
- # within the else clause.
1132
- def on_else(stmts)
1133
- beging = find_scanner_event(:@kw, 'else')
1134
- ending = find_else_ending
1309
+ ending = event[:body] == 'end' ? scanner_events.delete_at(index) : event
1135
1310
 
1136
1311
  stmts.bind(beging[:ec], ending[:sc])
1137
1312
 
@@ -1165,6 +1340,14 @@ class Prettier::Parser < Ripper
1165
1340
  }
1166
1341
  end
1167
1342
 
1343
+ # This is a scanner event that gets hit when we're inside an embdoc and
1344
+ # receive a new line of content. Here we are guaranteed to already have
1345
+ # initialized the @embdoc variable so we can just append the new line onto
1346
+ # the existing content.
1347
+ def on_embdoc(value)
1348
+ @embdoc[:value] << value
1349
+ end
1350
+
1168
1351
  # embdocs are long comments that are surrounded by =begin..=end. They
1169
1352
  # cannot be nested, so we don't need to worry about keeping a stack around
1170
1353
  # like we do with heredocs. Instead we can just track the current embdoc
@@ -1174,14 +1357,6 @@ class Prettier::Parser < Ripper
1174
1357
  @embdoc = { type: :@embdoc, value: value, sl: lineno, sc: char_pos }
1175
1358
  end
1176
1359
 
1177
- # This is a scanner event that gets hit when we're inside an embdoc and
1178
- # receive a new line of content. Here we are guaranteed to already have
1179
- # initialized the @embdoc variable so we can just append the new line onto
1180
- # the existing content.
1181
- def on_embdoc(value)
1182
- @embdoc[:value] << value
1183
- end
1184
-
1185
1360
  # This is the final scanner event for embdocs. It receives the =end. Here
1186
1361
  # we can finalize the embdoc with its location information and the final
1187
1362
  # piece of the string. We then add it to the list of comments so that
@@ -1197,6 +1372,72 @@ class Prettier::Parser < Ripper
1197
1372
  @embdoc = nil
1198
1373
  end
1199
1374
 
1375
+ # embexpr_beg is a scanner event that represents using interpolation inside of
1376
+ # a string, xstring, heredoc, or regexp. Its value is the string literal "#{".
1377
+ def on_embexpr_beg(value)
1378
+ start_line = lineno
1379
+ start_char = char_pos
1380
+
1381
+ node = {
1382
+ type: :@embexpr_beg,
1383
+ body: value,
1384
+ sl: start_line,
1385
+ el: start_line,
1386
+ sc: start_char,
1387
+ ec: start_char + value.size
1388
+ }
1389
+
1390
+ scanner_events << node
1391
+ node
1392
+ end
1393
+
1394
+ # embexpr_end is a scanner event that represents the end of an interpolated
1395
+ # expression in a string, xstring, heredoc, or regexp. Its value is the string
1396
+ # literal "}".
1397
+ def on_embexpr_end(value)
1398
+ start_line = lineno
1399
+ start_char = char_pos
1400
+
1401
+ node = {
1402
+ type: :@embexpr_end,
1403
+ body: value,
1404
+ sl: start_line,
1405
+ el: start_line,
1406
+ sc: start_char,
1407
+ ec: start_char + value.size
1408
+ }
1409
+
1410
+ scanner_events << node
1411
+ node
1412
+ end
1413
+
1414
+ # embvar is a scanner event that represents the use of shorthand interpolation
1415
+ # for an instance, class, or global variable into a string, xstring, heredoc,
1416
+ # or regexp. Its value is the string literal "#". For example, in the
1417
+ # following snippet:
1418
+ #
1419
+ # "#@foo"
1420
+ #
1421
+ # the embvar would be triggered by the "#", then an ivar event for the @foo
1422
+ # instance variable. That would all get bound up into a string_dvar node in
1423
+ # the final AST.
1424
+ def on_embvar(value)
1425
+ start_line = lineno
1426
+ start_char = char_pos
1427
+
1428
+ node = {
1429
+ type: :@embvar,
1430
+ body: value,
1431
+ sl: start_line,
1432
+ el: start_line,
1433
+ sc: start_char,
1434
+ ec: start_char + value.size
1435
+ }
1436
+
1437
+ scanner_events << node
1438
+ node
1439
+ end
1440
+
1200
1441
  # ensure is a parser event that represents the use of the ensure keyword
1201
1442
  # and its subsequent statements.
1202
1443
  def on_ensure(stmts)
@@ -1253,6 +1494,24 @@ class Prettier::Parser < Ripper
1253
1494
  }
1254
1495
  end
1255
1496
 
1497
+ # float is a scanner event that represents a floating point value literal.
1498
+ def on_float(value)
1499
+ start_line = lineno
1500
+ start_char = char_pos
1501
+
1502
+ node = {
1503
+ type: :@float,
1504
+ body: value,
1505
+ sl: start_line,
1506
+ el: start_line,
1507
+ sc: start_char,
1508
+ ec: start_char + value.size
1509
+ }
1510
+
1511
+ scanner_events << node
1512
+ node
1513
+ end
1514
+
1256
1515
  # fndptn is a parser event that represents matching against a pattern where
1257
1516
  # you find a pattern in an array using the Ruby 3.0+ pattern matching syntax.
1258
1517
  def on_fndptn(const, presplat, args, postsplat)
@@ -1273,15 +1532,22 @@ class Prettier::Parser < Ripper
1273
1532
  # loop. It accepts as arguments an ident which is the iterating variable,
1274
1533
  # an enumerable for that which is being enumerated, and a stmts event that
1275
1534
  # represents the statements inside the for loop.
1276
- def on_for(ident, enumerable, stmts)
1535
+ def on_for(ident, enum, stmts)
1277
1536
  beging = find_scanner_event(:@kw, 'for')
1278
1537
  ending = find_scanner_event(:@kw, 'end')
1279
1538
 
1280
- stmts.bind(enumerable[:ec], ending[:sc])
1539
+ # Consume the do keyword if it exists so that it doesn't get confused for
1540
+ # some other block
1541
+ do_event = find_scanner_event(:@kw, 'do', consume: false)
1542
+ if do_event && do_event[:sc] > enum[:ec] && do_event[:ec] < ending[:sc]
1543
+ scanner_events.delete(do_event)
1544
+ end
1545
+
1546
+ stmts.bind((do_event || enum)[:ec], ending[:sc])
1281
1547
 
1282
1548
  {
1283
1549
  type: :for,
1284
- body: [ident, enumerable, stmts],
1550
+ body: [ident, enum, stmts],
1285
1551
  sl: beging[:sl],
1286
1552
  sc: beging[:sc],
1287
1553
  el: ending[:el],
@@ -1289,6 +1555,24 @@ class Prettier::Parser < Ripper
1289
1555
  }
1290
1556
  end
1291
1557
 
1558
+ # gvar is a scanner event that represents a global variable literal.
1559
+ def on_gvar(value)
1560
+ start_line = lineno
1561
+ start_char = char_pos
1562
+
1563
+ node = {
1564
+ type: :@gvar,
1565
+ body: value,
1566
+ sl: start_line,
1567
+ el: start_line,
1568
+ sc: start_char,
1569
+ ec: start_char + value.size
1570
+ }
1571
+
1572
+ scanner_events << node
1573
+ node
1574
+ end
1575
+
1292
1576
  # hash is a parser event that represents a hash literal. It accepts as an
1293
1577
  # argument an optional assoclist_from_args event which contains the
1294
1578
  # contents of the hash.
@@ -1363,6 +1647,27 @@ class Prettier::Parser < Ripper
1363
1647
  }
1364
1648
  end
1365
1649
 
1650
+ # ident is a scanner event that represents an identifier anywhere in code. It
1651
+ # can actually represent a whole bunch of stuff, depending on where it is in
1652
+ # the AST. Like comments, we need to force the encoding here so JSON doesn't
1653
+ # break.
1654
+ def on_ident(value)
1655
+ start_line = lineno
1656
+ start_char = char_pos
1657
+
1658
+ node = {
1659
+ type: :@ident,
1660
+ body: value.force_encoding('UTF-8'),
1661
+ sl: start_line,
1662
+ el: start_line,
1663
+ sc: start_char,
1664
+ ec: start_char + value.size
1665
+ }
1666
+
1667
+ scanner_events << node
1668
+ node
1669
+ end
1670
+
1366
1671
  # if is a parser event that represents the first clause in an if chain.
1367
1672
  # It accepts as arguments the predicate of the if, the statements that are
1368
1673
  # contained within the if clause, and the optional consequent clause.
@@ -1410,6 +1715,56 @@ class Prettier::Parser < Ripper
1410
1715
  }
1411
1716
  end
1412
1717
 
1718
+ # ignored_nl is a special kind of scanner event that passes nil as the value.
1719
+ # You can trigger the ignored_nl event with the following snippet:
1720
+ #
1721
+ # foo.bar
1722
+ # .baz
1723
+ #
1724
+ # We don't need to track this event in the AST that we're generating, so we're
1725
+ # not going to define an explicit handler for it.
1726
+ #
1727
+ # def on_ignored_nl(value)
1728
+ # value
1729
+ # end
1730
+
1731
+ # ignored_sp is a scanner event that represents the space before the content
1732
+ # of each line of a squiggly heredoc that will be removed from the string
1733
+ # before it gets transformed into a string literal. For example, in the
1734
+ # following snippet:
1735
+ #
1736
+ # <<~HERE
1737
+ # foo
1738
+ # bar
1739
+ # HERE
1740
+ #
1741
+ # You would have two ignored_sp events, the first with two spaces and the
1742
+ # second with four. We don't need to track this event in the AST that we're
1743
+ # generating, so we're not going to define an explicit handler for it.
1744
+ #
1745
+ # def on_ignored_sp(value)
1746
+ # value
1747
+ # end
1748
+
1749
+ # imaginary is a scanner event that represents an imaginary number literal.
1750
+ # They become instances of the Complex class.
1751
+ def on_imaginary(value)
1752
+ start_line = lineno
1753
+ start_char = char_pos
1754
+
1755
+ node = {
1756
+ type: :@imaginary,
1757
+ body: value,
1758
+ sl: start_line,
1759
+ el: start_line,
1760
+ sc: start_char,
1761
+ ec: start_char + value.size
1762
+ }
1763
+
1764
+ scanner_events << node
1765
+ node
1766
+ end
1767
+
1413
1768
  # in is a parser event that represents using the in keyword within the
1414
1769
  # Ruby 2.7+ pattern matching syntax. Alternatively in Ruby 3+ it is also used
1415
1770
  # to handle rightward assignment for pattern matching.
@@ -1430,6 +1785,61 @@ class Prettier::Parser < Ripper
1430
1785
  )
1431
1786
  end
1432
1787
 
1788
+ # int is a scanner event the represents a number literal.
1789
+ def on_int(value)
1790
+ start_line = lineno
1791
+ start_char = char_pos
1792
+
1793
+ node = {
1794
+ type: :@int,
1795
+ body: value,
1796
+ sl: start_line,
1797
+ el: start_line,
1798
+ sc: start_char,
1799
+ ec: start_char + value.size
1800
+ }
1801
+
1802
+ scanner_events << node
1803
+ node
1804
+ end
1805
+
1806
+ # ivar is a scanner event the represents an instance variable literal.
1807
+ def on_ivar(value)
1808
+ start_line = lineno
1809
+ start_char = char_pos
1810
+
1811
+ node = {
1812
+ type: :@ivar,
1813
+ body: value,
1814
+ sl: start_line,
1815
+ el: start_line,
1816
+ sc: start_char,
1817
+ ec: start_char + value.size
1818
+ }
1819
+
1820
+ scanner_events << node
1821
+ node
1822
+ end
1823
+
1824
+ # kw is a scanner event the represents the use of a keyword. It can be
1825
+ # anywhere in the AST, so you end up seeing it quite a lot.
1826
+ def on_kw(value)
1827
+ start_line = lineno
1828
+ start_char = char_pos
1829
+
1830
+ node = {
1831
+ type: :@kw,
1832
+ body: value,
1833
+ sl: start_line,
1834
+ el: start_line,
1835
+ sc: start_char,
1836
+ ec: start_char + value.size
1837
+ }
1838
+
1839
+ scanner_events << node
1840
+ node
1841
+ end
1842
+
1433
1843
  # kwrest_param is a parser event that represents defining a parameter in a
1434
1844
  # method definition that accepts all remaining keyword parameters.
1435
1845
  def on_kwrest_param(ident)
@@ -1444,6 +1854,61 @@ class Prettier::Parser < Ripper
1444
1854
  )
1445
1855
  end
1446
1856
 
1857
+ # label is a scanner event that represents the use of an identifier to
1858
+ # associate with an object. You can find it in a hash key, as in:
1859
+ #
1860
+ # { foo: bar }
1861
+ #
1862
+ # in this case "foo:" would be the body of the label. You can also find it in
1863
+ # pattern matching, as in:
1864
+ #
1865
+ # case foo
1866
+ # in bar:
1867
+ # bar
1868
+ # end
1869
+ #
1870
+ # in this case "bar:" would be the body of the label.
1871
+ def on_label(value)
1872
+ start_line = lineno
1873
+ start_char = char_pos
1874
+
1875
+ node = {
1876
+ type: :@label,
1877
+ body: value,
1878
+ sl: start_line,
1879
+ el: start_line,
1880
+ sc: start_char,
1881
+ ec: start_char + value.size
1882
+ }
1883
+
1884
+ scanner_events << node
1885
+ node
1886
+ end
1887
+
1888
+ # label_end is a scanner event that represents the end of a dynamic symbol. If
1889
+ # for example you had the following hash:
1890
+ #
1891
+ # { "foo": bar }
1892
+ #
1893
+ # then the string "\":" would be the value of this label_end. It's useful for
1894
+ # determining the type of quote being used by the label.
1895
+ def on_label_end(value)
1896
+ start_line = lineno
1897
+ start_char = char_pos
1898
+
1899
+ node = {
1900
+ type: :@label_end,
1901
+ body: value,
1902
+ sl: start_line,
1903
+ el: start_line,
1904
+ sc: start_char,
1905
+ ec: start_char + value.size
1906
+ }
1907
+
1908
+ scanner_events << node
1909
+ node
1910
+ end
1911
+
1447
1912
  # lambda is a parser event that represents using a "stabby" lambda
1448
1913
  # literal. It accepts as arguments a params event that represents any
1449
1914
  # parameters to the lambda and a stmts event that represents the
@@ -1474,6 +1939,72 @@ class Prettier::Parser < Ripper
1474
1939
  }
1475
1940
  end
1476
1941
 
1942
+ # lbrace is a scanner event representing the use of a left brace, i.e., "{".
1943
+ def on_lbrace(value)
1944
+ start_line = lineno
1945
+ start_char = char_pos
1946
+
1947
+ node = {
1948
+ type: :@lbrace,
1949
+ body: value,
1950
+ sl: start_line,
1951
+ el: start_line,
1952
+ sc: start_char,
1953
+ ec: start_char + value.size
1954
+ }
1955
+
1956
+ scanner_events << node
1957
+ node
1958
+ end
1959
+
1960
+ # lbracket is a scanner event representing the use of a left bracket, i.e.,
1961
+ # "[".
1962
+ def on_lbracket(value)
1963
+ start_line = lineno
1964
+ start_char = char_pos
1965
+
1966
+ node = {
1967
+ type: :@lbracket,
1968
+ body: value,
1969
+ sl: start_line,
1970
+ el: start_line,
1971
+ sc: start_char,
1972
+ ec: start_char + value.size
1973
+ }
1974
+
1975
+ scanner_events << node
1976
+ node
1977
+ end
1978
+
1979
+ # lparen is a scanner event representing the use of a left parenthesis, i.e.,
1980
+ # "(".
1981
+ def on_lparen(value)
1982
+ start_line = lineno
1983
+ start_char = char_pos
1984
+
1985
+ node = {
1986
+ type: :@lparen,
1987
+ body: value,
1988
+ sl: start_line,
1989
+ el: start_line,
1990
+ sc: start_char,
1991
+ ec: start_char + value.size
1992
+ }
1993
+
1994
+ scanner_events << node
1995
+ node
1996
+ end
1997
+
1998
+ # magic_comment is a scanner event that represents the use of a pragma at the
1999
+ # beginning of the file. Usually it will inside something like
2000
+ # frozen_string_literal (the key) with a value of true (the value). Both
2001
+ # children come is a string literals. We're going to leave these alone as they
2002
+ # come in all kinds of shapes and sizes.
2003
+ #
2004
+ # def on_magic_comment(key, value)
2005
+ # @magic_comment = { value: " #{key}: #{value}" }
2006
+ # end
2007
+
1477
2008
  # massign is a parser event that is a parent node of any kind of multiple
1478
2009
  # assignment. This includes splitting out variables on the left like:
1479
2010
  #
@@ -1704,6 +2235,52 @@ class Prettier::Parser < Ripper
1704
2235
  )
1705
2236
  end
1706
2237
 
2238
+ # nl is a scanner event representing a newline in the source. As you can
2239
+ # imagine, it will typically get triggered quite a few times. We don't need to
2240
+ # track this event in the AST that we're generating, so we're not going to
2241
+ # define an explicit handler for it.
2242
+ #
2243
+ # def on_nl(value)
2244
+ # value
2245
+ # end
2246
+
2247
+ # nokw_param is a parser event that represents the use of the special 2.7+
2248
+ # syntax to indicate a method should take no additional keyword arguments. For
2249
+ # example in the following snippet:
2250
+ #
2251
+ # def foo(**nil) end
2252
+ #
2253
+ # this is saying that foo should not accept any keyword arguments. Its value
2254
+ # is always nil. We don't need to track this event in the AST that we're
2255
+ # generating, so we're not going to define an explicit handler for it.
2256
+ #
2257
+ # def on_nokw_param(value)
2258
+ # value
2259
+ # end
2260
+
2261
+ # op is a scanner event representing an operator literal in the source. For
2262
+ # example, in the following snippet:
2263
+ #
2264
+ # 1 + 2
2265
+ #
2266
+ # the + sign is an operator.
2267
+ def on_op(value)
2268
+ start_line = lineno
2269
+ start_char = char_pos
2270
+
2271
+ node = {
2272
+ type: :@op,
2273
+ body: value,
2274
+ sl: start_line,
2275
+ el: start_line,
2276
+ sc: start_char,
2277
+ ec: start_char + value.size
2278
+ }
2279
+
2280
+ scanner_events << node
2281
+ node
2282
+ end
2283
+
1707
2284
  # opassign is a parser event that represents assigning something to a
1708
2285
  # variable or constant using an operator like += or ||=. It accepts as
1709
2286
  # arguments the left side of the expression before the operator, the
@@ -1717,6 +2294,20 @@ class Prettier::Parser < Ripper
1717
2294
  )
1718
2295
  end
1719
2296
 
2297
+ # operator_ambiguous is a parser event that represents when the parsers sees
2298
+ # an operator as ambiguous. For example, in the following snippet:
2299
+ #
2300
+ # foo %[]
2301
+ #
2302
+ # the question becomes if the percent sign is being used as a method call or
2303
+ # if it's the start of a string literal. We don't need to track this event in
2304
+ # the AST that we're generating, so we're not going to define an explicit
2305
+ # handler for it.
2306
+ #
2307
+ # def on_operator_ambiguous(value)
2308
+ # value
2309
+ # end
2310
+
1720
2311
  # params is a parser event that represents defining parameters on a
1721
2312
  # method. They have a somewhat interesting structure in that they are an
1722
2313
  # array of arrays where the position in the top-level array indicates the
@@ -1743,31 +2334,25 @@ class Prettier::Parser < Ripper
1743
2334
  # anywhere in a Ruby program. It accepts as arguments the contents, which
1744
2335
  # can be either params or statements.
1745
2336
  def on_paren(contents)
1746
- beging = find_scanner_event(:@lparen)
1747
- ending = find_scanner_event(:@rparen)
2337
+ lparen = find_scanner_event(:@lparen)
2338
+ rparen = find_scanner_event(:@rparen)
1748
2339
 
1749
2340
  if contents && contents[:type] == :params
1750
- contents.merge!(sc: beging[:ec], ec: ending[:sc])
2341
+ contents.merge!(
2342
+ sc: find_next_statement_start(lparen[:ec]),
2343
+ ec: rparen[:sc]
2344
+ )
1751
2345
  end
1752
2346
 
1753
- beging.merge!(
2347
+ {
1754
2348
  type: :paren,
2349
+ lparen: lparen,
1755
2350
  body: [contents],
1756
- el: ending[:el],
1757
- ec: ending[:ec]
1758
- )
1759
- end
1760
-
1761
- # A special parser error so that we can get nice syntax displays on the error
1762
- # message when prettier prints out the results.
1763
- class ParserError < StandardError
1764
- attr_reader :lineno, :column
1765
-
1766
- def initialize(error, lineno, column)
1767
- super(error)
1768
- @lineno = lineno
1769
- @column = column
1770
- end
2351
+ sl: lparen[:sl],
2352
+ sc: lparen[:sc],
2353
+ el: rparen[:el],
2354
+ ec: rparen[:ec]
2355
+ }
1771
2356
  end
1772
2357
 
1773
2358
  # If we encounter a parse error, just immediately bail out so that our runner
@@ -1780,6 +2365,22 @@ class Prettier::Parser < Ripper
1780
2365
  alias on_class_name_error on_parse_error
1781
2366
  alias on_param_error on_parse_error
1782
2367
 
2368
+ # period is a scanner event that represents the use of the period operator. It
2369
+ # is usually found in method calls.
2370
+ def on_period(value)
2371
+ start_line = lineno
2372
+ start_char = char_pos
2373
+
2374
+ {
2375
+ type: :@period,
2376
+ body: value,
2377
+ sl: start_line,
2378
+ el: start_line,
2379
+ sc: start_char,
2380
+ ec: start_char + value.size
2381
+ }
2382
+ end
2383
+
1783
2384
  # The program node is the very top of the AST. Here we'll attach all of
1784
2385
  # the comments that we've gathered up over the course of parsing the
1785
2386
  # source string. We'll also attach on the __END__ content if there was
@@ -1793,6 +2394,29 @@ class Prettier::Parser < Ripper
1793
2394
  range.merge(type: :program, body: [stmts], comments: @comments)
1794
2395
  end
1795
2396
 
2397
+ # qsymbols_beg is a scanner event that represents the beginning of a symbol
2398
+ # literal array. For example in the following snippet:
2399
+ #
2400
+ # %i[foo bar baz]
2401
+ #
2402
+ # a qsymbols_beg would be triggered with the value of "%i[".
2403
+ def on_qsymbols_beg(value)
2404
+ start_line = lineno
2405
+ start_char = char_pos
2406
+
2407
+ node = {
2408
+ type: :@qsymbols_beg,
2409
+ body: value,
2410
+ sl: start_line,
2411
+ el: start_line,
2412
+ sc: start_char,
2413
+ ec: start_char + value.size
2414
+ }
2415
+
2416
+ scanner_events << node
2417
+ node
2418
+ end
2419
+
1796
2420
  # qsymbols_new is a parser event that represents the beginning of a symbol
1797
2421
  # literal array, like %i[one two three]. It can be followed by any number
1798
2422
  # of qsymbols_add events, which we'll append onto an array body.
@@ -1812,6 +2436,29 @@ class Prettier::Parser < Ripper
1812
2436
  )
1813
2437
  end
1814
2438
 
2439
+ # qwords_beg is a scanner event that represents the beginning of a word
2440
+ # literal array. For example in the following snippet:
2441
+ #
2442
+ # %w[foo bar baz]
2443
+ #
2444
+ # a qwords_beg would be triggered with the value of "%w[".
2445
+ def on_qwords_beg(value)
2446
+ start_line = lineno
2447
+ start_char = char_pos
2448
+
2449
+ node = {
2450
+ type: :@qwords_beg,
2451
+ body: value,
2452
+ sl: start_line,
2453
+ el: start_line,
2454
+ sc: start_char,
2455
+ ec: start_char + value.size
2456
+ }
2457
+
2458
+ scanner_events << node
2459
+ node
2460
+ end
2461
+
1815
2462
  # qwords_new is a parser event that represents the beginning of a string
1816
2463
  # literal array, like %w[one two three]. It can be followed by any number
1817
2464
  # of qwords_add events, which we'll append onto an array body.
@@ -1831,24 +2478,73 @@ class Prettier::Parser < Ripper
1831
2478
  )
1832
2479
  end
1833
2480
 
2481
+ # rational is a scanner event that represents a rational number literal.
2482
+ def on_rational(value)
2483
+ start_line = lineno
2484
+ start_char = char_pos
2485
+
2486
+ node = {
2487
+ type: :@rational,
2488
+ body: value,
2489
+ sl: start_line,
2490
+ el: start_line,
2491
+ sc: start_char,
2492
+ ec: start_char + value.size
2493
+ }
2494
+
2495
+ scanner_events << node
2496
+ node
2497
+ end
2498
+
2499
+ # rbrace is a scanner event that represents the use of a right brace, i.e.,
2500
+ # "}".
2501
+ def on_rbrace(value)
2502
+ start_line = lineno
2503
+ start_char = char_pos
2504
+
2505
+ node = {
2506
+ type: :@rbrace,
2507
+ body: value,
2508
+ sl: start_line,
2509
+ el: start_line,
2510
+ sc: start_char,
2511
+ ec: start_char + value.size
2512
+ }
2513
+
2514
+ scanner_events << node
2515
+ node
2516
+ end
2517
+
2518
+ # rbracket is a scanner event that represents the use of a right bracket,
2519
+ # i.e., "]".
2520
+ def on_rbracket(value)
2521
+ start_line = lineno
2522
+ start_char = char_pos
2523
+
2524
+ node = {
2525
+ type: :@rbracket,
2526
+ body: value,
2527
+ sl: start_line,
2528
+ el: start_line,
2529
+ sc: start_char,
2530
+ ec: start_char + value.size
2531
+ }
2532
+
2533
+ scanner_events << node
2534
+ node
2535
+ end
2536
+
1834
2537
  # redo is a parser event that represents the bare redo keyword. It has no
1835
2538
  # body as it accepts no arguments.
1836
2539
  def on_redo
1837
2540
  find_scanner_event(:@kw, 'redo').merge!(type: :redo)
1838
2541
  end
1839
2542
 
1840
- # regexp_new is a parser event that represents the beginning of a regular
1841
- # expression literal, like /foo/. It can be followed by any number of
1842
- # regexp_add events, which we'll append onto an array body.
1843
- def on_regexp_new
1844
- beging = find_scanner_event(:@regexp_beg)
1845
- beging.merge!(type: :regexp, body: [], beging: beging[:body])
1846
- end
1847
-
1848
- # regexp_add is a parser event that represents a piece of a regular
2543
+ # regexp_add is a parser event that represents a piece of a regular expression
1849
2544
  # body. It accepts as arguments the parent regexp node as well as a
1850
- # tstring_content scanner event representing string content or a
1851
- # string_embexpr parser event representing interpolated content.
2545
+ # tstring_content scanner event representing string content, a
2546
+ # string_embexpr parser event representing interpolated content, or a
2547
+ # string_dvar parser event representing an interpolated variable.
1852
2548
  def on_regexp_add(regexp, piece)
1853
2549
  regexp.merge!(
1854
2550
  body: regexp[:body] << piece,
@@ -1857,6 +2553,43 @@ class Prettier::Parser < Ripper
1857
2553
  )
1858
2554
  end
1859
2555
 
2556
+ # regexp_beg is a scanner event that represents the start of a regular
2557
+ # expression. It can take a couple of forms since regexp can either start with
2558
+ # a forward slash or a %r.
2559
+ def on_regexp_beg(value)
2560
+ start_line = lineno
2561
+ start_char = char_pos
2562
+
2563
+ node = {
2564
+ type: :@regexp_beg,
2565
+ body: value,
2566
+ sl: start_line,
2567
+ el: start_line,
2568
+ sc: start_char,
2569
+ ec: start_char + value.size
2570
+ }
2571
+
2572
+ scanner_events << node
2573
+ node
2574
+ end
2575
+
2576
+ # regexp_end is a scanner event that represents the end of a regular
2577
+ # expression. It will contain the closing brace or slash, as well as any flags
2578
+ # being passed to the regexp.
2579
+ def on_regexp_end(value)
2580
+ start_line = lineno
2581
+ start_char = char_pos
2582
+
2583
+ {
2584
+ type: :@regexp_end,
2585
+ body: value,
2586
+ sl: start_line,
2587
+ el: start_line,
2588
+ sc: start_char,
2589
+ ec: start_char + value.size
2590
+ }
2591
+ end
2592
+
1860
2593
  # regexp_literal is a parser event that represents a regular expression.
1861
2594
  # It accepts as arguments a regexp node which is a built-up array of
1862
2595
  # pieces that go into the regexp content, as well as the ending used to
@@ -1870,6 +2603,14 @@ class Prettier::Parser < Ripper
1870
2603
  )
1871
2604
  end
1872
2605
 
2606
+ # regexp_new is a parser event that represents the beginning of a regular
2607
+ # expression literal, like /foo/. It can be followed by any number of
2608
+ # regexp_add events, which we'll append onto an array body.
2609
+ def on_regexp_new
2610
+ beging = find_scanner_event(:@regexp_beg)
2611
+ beging.merge!(type: :regexp, body: [], beging: beging[:body])
2612
+ end
2613
+
1873
2614
  # rescue is a special kind of node where you have a rescue chain but it
1874
2615
  # doesn't really have all of the information that it needs in order to
1875
2616
  # determine its ending. Therefore it relies on its parent bodystmt node to
@@ -1983,6 +2724,25 @@ class Prettier::Parser < Ripper
1983
2724
  find_scanner_event(:@kw, 'return').merge!(type: :return0)
1984
2725
  end
1985
2726
 
2727
+ # rparen is a scanner event that represents the use of a right parenthesis,
2728
+ # i.e., ")".
2729
+ def on_rparen(value)
2730
+ start_line = lineno
2731
+ start_char = char_pos
2732
+
2733
+ node = {
2734
+ type: :@rparen,
2735
+ body: value,
2736
+ sl: start_line,
2737
+ el: start_line,
2738
+ sc: start_char,
2739
+ ec: start_char + value.size
2740
+ }
2741
+
2742
+ scanner_events << node
2743
+ node
2744
+ end
2745
+
1986
2746
  # sclass is a parser event that represents a block of statements that
1987
2747
  # should be evaluated within the context of the singleton class of an
1988
2748
  # object. It's frequently used to define singleton methods. It looks like
@@ -2009,6 +2769,31 @@ class Prettier::Parser < Ripper
2009
2769
  }
2010
2770
  end
2011
2771
 
2772
+ # semicolon is a scanner event that represents the use of a semicolon in the
2773
+ # source. We don't need to track this event in the AST that we're generating,
2774
+ # so we're not going to define an explicit handler for it.
2775
+ #
2776
+ # def on_semicolon(value)
2777
+ # value
2778
+ # end
2779
+
2780
+ # sp is a scanner event that represents the use of a space in the source. As
2781
+ # you can imagine, this event gets triggered quite often. We don't need to
2782
+ # track this event in the AST that we're generating, so we're not going to
2783
+ # define an explicit handler for it.
2784
+ #
2785
+ # def on_sp(value)
2786
+ # value
2787
+ # end
2788
+
2789
+ # stmts_add is a parser event that represents a single statement inside a
2790
+ # list of statements within any lexical block. It accepts as arguments the
2791
+ # parent stmts node as well as an stmt which can be any expression in
2792
+ # Ruby.
2793
+ def on_stmts_add(stmts, stmt)
2794
+ stmts << stmt
2795
+ end
2796
+
2012
2797
  # Everything that has a block of code inside of it has a list of statements.
2013
2798
  # Normally we would just track those as a node that has an array body, but we
2014
2799
  # have some special handling in order to handle empty statement lists. They
@@ -2074,12 +2859,12 @@ class Prettier::Parser < Ripper
2074
2859
  )
2075
2860
  end
2076
2861
 
2077
- # stmts_add is a parser event that represents a single statement inside a
2078
- # list of statements within any lexical block. It accepts as arguments the
2079
- # parent stmts node as well as an stmt which can be any expression in
2080
- # Ruby.
2081
- def on_stmts_add(stmts, stmt)
2082
- stmts << stmt
2862
+ # string_add is a parser event that represents a piece of a string. It
2863
+ # could be plain @tstring_content, string_embexpr, or string_dvar nodes.
2864
+ # It accepts as arguments the parent string node as well as the additional
2865
+ # piece of the string.
2866
+ def on_string_add(string, piece)
2867
+ string.merge!(body: string[:body] << piece, el: piece[:el], ec: piece[:ec])
2083
2868
  end
2084
2869
 
2085
2870
  # string_concat is a parser event that represents concatenating two
@@ -2115,14 +2900,6 @@ class Prettier::Parser < Ripper
2115
2900
  }
2116
2901
  end
2117
2902
 
2118
- # string_add is a parser event that represents a piece of a string. It
2119
- # could be plain @tstring_content, string_embexpr, or string_dvar nodes.
2120
- # It accepts as arguments the parent string node as well as the additional
2121
- # piece of the string.
2122
- def on_string_add(string, piece)
2123
- string.merge!(body: string[:body] << piece, el: piece[:el], ec: piece[:ec])
2124
- end
2125
-
2126
2903
  # string_dvar is a parser event that represents a very special kind of
2127
2904
  # interpolation into string. It allows you to take an instance variable,
2128
2905
  # class variable, or global variable and omit the braces when
@@ -2193,16 +2970,33 @@ class Prettier::Parser < Ripper
2193
2970
  )
2194
2971
  end
2195
2972
 
2973
+ # symbeg is a scanner event that represents the beginning of a symbol literal.
2974
+ # In most cases it will contain just ":" as in the value, but if its a dynamic
2975
+ # symbol being defined it will contain ":'" or ":\"".
2976
+ def on_symbeg(value)
2977
+ start_line = lineno
2978
+ start_char = char_pos
2979
+
2980
+ node = {
2981
+ type: :@symbeg,
2982
+ body: value,
2983
+ sl: start_line,
2984
+ el: start_line,
2985
+ sc: start_char,
2986
+ ec: start_char + value.size
2987
+ }
2988
+
2989
+ scanner_events << node
2990
+ node
2991
+ end
2992
+
2196
2993
  # A symbol is a parser event that immediately descends from a symbol
2197
2994
  # literal and contains an ident representing the contents of the symbol.
2198
2995
  def on_symbol(ident)
2199
- # What the heck is this here for you ask!? Turns out when Ripper is lexing
2200
- # source text, it turns symbols into keywords if their contents match, which
2201
- # will mess up the location information of all of our other nodes.
2202
- #
2203
- # So for example instead of { type: :@ident, body: "class" } you would
2204
- # instead get { type: :@kw, body: "class" } which is all kinds of
2205
- # problematic.
2996
+ # When ripper is lexing source text, it turns symbols into keywords if their
2997
+ # contents match, which will mess up the location information of all of our
2998
+ # other nodes. So for example instead of { type: :@ident, body: "class" }
2999
+ # you would instead get { type: :@kw, body: "class" }.
2206
3000
  #
2207
3001
  # In order to take care of this, we explicitly delete this scanner event
2208
3002
  # from the stack to make sure it doesn't screw things up.
@@ -2224,6 +3018,29 @@ class Prettier::Parser < Ripper
2224
3018
  end
2225
3019
  end
2226
3020
 
3021
+ # symbols_beg is a scanner event that represents the start of a symbol literal
3022
+ # array with interpolation. For example, in the following snippet:
3023
+ #
3024
+ # %I[foo bar baz]
3025
+ #
3026
+ # symbols_beg would be triggered with the value of "%I".
3027
+ def on_symbols_beg(value)
3028
+ start_line = lineno
3029
+ start_char = char_pos
3030
+
3031
+ node = {
3032
+ type: :@symbols_beg,
3033
+ body: value,
3034
+ sl: start_line,
3035
+ el: start_line,
3036
+ sc: start_char,
3037
+ ec: start_char + value.size
3038
+ }
3039
+
3040
+ scanner_events << node
3041
+ node
3042
+ end
3043
+
2227
3044
  # symbols_new is a parser event that represents the beginning of a symbol
2228
3045
  # literal array that accepts interpolation, like %I[one #{two} three]. It
2229
3046
  # can be followed by any number of symbols_add events, which we'll append
@@ -2244,17 +3061,42 @@ class Prettier::Parser < Ripper
2244
3061
  )
2245
3062
  end
2246
3063
 
2247
- # A helper function to find a :: operator for the next two nodes. We do
2248
- # special handling instead of using find_scanner_event here because we
2249
- # don't pop off all of the :: operators so you could end up getting the
2250
- # wrong information if you have for instance ::X::Y::Z.
2251
- def find_colon2_before(const)
2252
- index =
2253
- scanner_events.rindex do |event|
2254
- event[:type] == :@op && event[:body] == '::' && event[:sc] < const[:sc]
2255
- end
3064
+ # tlambda is a scanner event that represents the beginning of a lambda
3065
+ # literal. It always has the value of "->".
3066
+ def on_tlambda(value)
3067
+ start_line = lineno
3068
+ start_char = char_pos
2256
3069
 
2257
- scanner_events[index]
3070
+ node = {
3071
+ type: :@tlambda,
3072
+ body: value,
3073
+ sl: start_line,
3074
+ el: start_line,
3075
+ sc: start_char,
3076
+ ec: start_char + value.size
3077
+ }
3078
+
3079
+ scanner_events << node
3080
+ node
3081
+ end
3082
+
3083
+ # tlambeg is a scanner event that represents the beginning of the body of a
3084
+ # lambda literal. It always has the value of "{".
3085
+ def on_tlambeg(value)
3086
+ start_line = lineno
3087
+ start_char = char_pos
3088
+
3089
+ node = {
3090
+ type: :@tlambeg,
3091
+ body: value,
3092
+ sl: start_line,
3093
+ el: start_line,
3094
+ sc: start_char,
3095
+ ec: start_char + value.size
3096
+ }
3097
+
3098
+ scanner_events << node
3099
+ node
2258
3100
  end
2259
3101
 
2260
3102
  # A top_const_field is a parser event that is always the child of some
@@ -2289,6 +3131,63 @@ class Prettier::Parser < Ripper
2289
3131
  )
2290
3132
  end
2291
3133
 
3134
+ # tstring_beg is a scanner event that represents the beginning of a string
3135
+ # literal. It can represent either of the quotes for its value, or it can have
3136
+ # a %q/%Q with delimiter.
3137
+ def on_tstring_beg(value)
3138
+ start_line = lineno
3139
+ start_char = char_pos
3140
+
3141
+ node = {
3142
+ type: :@tstring_beg,
3143
+ body: value,
3144
+ sl: start_line,
3145
+ el: start_line,
3146
+ sc: start_char,
3147
+ ec: start_char + value.size
3148
+ }
3149
+
3150
+ scanner_events << node
3151
+ node
3152
+ end
3153
+
3154
+ # tstring_content is a scanner event that represents plain characters inside
3155
+ # of a string, heredoc, xstring, or regexp. Like comments, we need to force
3156
+ # the encoding here so JSON doesn't break.
3157
+ def on_tstring_content(value)
3158
+ start_line = lineno
3159
+ start_char = char_pos
3160
+
3161
+ {
3162
+ type: :@tstring_content,
3163
+ body: value.force_encoding('UTF-8'),
3164
+ sl: start_line,
3165
+ el: start_line,
3166
+ sc: start_char,
3167
+ ec: start_char + value.size
3168
+ }
3169
+ end
3170
+
3171
+ # tstring_end is a scanner event that represents the end of a string literal.
3172
+ # It can either contain quotes, or it can have the end delimiter of a %q/%Q
3173
+ # literal.
3174
+ def on_tstring_end(value)
3175
+ start_line = lineno
3176
+ start_char = char_pos
3177
+
3178
+ node = {
3179
+ type: :@tstring_end,
3180
+ body: value,
3181
+ sl: start_line,
3182
+ el: start_line,
3183
+ sc: start_char,
3184
+ ec: start_char + value.size
3185
+ }
3186
+
3187
+ scanner_events << node
3188
+ node
3189
+ end
3190
+
2292
3191
  # A unary node represents a unary method being called on an expression, as
2293
3192
  # in !, ~, or not. We have somewhat special handling of the not operator
2294
3193
  # since if it has parentheses they don't get reported as a paren node for
@@ -2586,6 +3485,48 @@ class Prettier::Parser < Ripper
2586
3485
  end
2587
3486
  end
2588
3487
 
3488
+ # words_beg is a scanner event that represents the start of a word literal
3489
+ # array with interpolation. For example, in the following snippet:
3490
+ #
3491
+ # %W[foo bar baz]
3492
+ #
3493
+ # words_beg would be triggered with the value of "%W".
3494
+ def on_words_beg(value)
3495
+ start_line = lineno
3496
+ start_char = char_pos
3497
+
3498
+ node = {
3499
+ type: :@words_beg,
3500
+ body: value,
3501
+ sl: start_line,
3502
+ el: start_line,
3503
+ sc: start_char,
3504
+ ec: start_char + value.size
3505
+ }
3506
+
3507
+ scanner_events << node
3508
+ node
3509
+ end
3510
+
3511
+ # words_sep is a scanner event that represents the separate between two words
3512
+ # inside of a word literal array. It contains any amount of whitespace
3513
+ # characters that are used to delimit the words. For example,
3514
+ #
3515
+ # %w[
3516
+ # foo
3517
+ # bar
3518
+ # baz
3519
+ # ]
3520
+ #
3521
+ # in the snippet above there would be two words_sep events triggered, one
3522
+ # between foo and bar and one between bar and baz. We don't need to track this
3523
+ # event in the AST that we're generating, so we're not going to define an
3524
+ # explicit handler for it.
3525
+ #
3526
+ # def on_words_sep(value)
3527
+ # value
3528
+ # end
3529
+
2589
3530
  # words_new is a parser event that represents the beginning of a string
2590
3531
  # literal array that accepts interpolation, like %W[one #{two} three]. It
2591
3532
  # can be followed by any number of words_add events, which we'll append