prettier 1.6.1 → 2.0.0.pre.rc1

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 +316 -293
  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 +128 -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 +220 -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 +1215 -252
  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 -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 +313 -190
  76. data/node_modules/prettier/doc.js +191 -323
  77. data/node_modules/prettier/index.js +2753 -3677
  78. data/node_modules/prettier/package.json +1 -1
  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 +143 -78
  92. data/package.json +26 -18
  93. metadata +74 -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 -246
  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 -272
  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 -10
  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,64 @@ 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
+ # 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.
101
150
  @heredocs = []
102
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.
103
159
  @scanner_events = []
104
- @line_counts = []
105
160
 
106
161
  # Here we're going to build up a list of SingleByteString or MultiByteString
107
162
  # objects. They're each going to represent a string in the source. They are
108
163
  # used by the `char_pos` method to determine where we are in the source
109
164
  # string.
165
+ @line_counts = []
110
166
  last_index = 0
111
167
 
112
168
  @source.lines.each do |line|
@@ -157,114 +213,61 @@ class Prettier::Parser < Ripper
157
213
  (body == :any || (scanner_event[:body] == body))
158
214
  end
159
215
 
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
- }
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
188
226
 
189
- scanner_events << node
190
- node
227
+ scanner_events.delete_at(index)
228
+ elsif index
229
+ scanner_events[index]
191
230
  end
192
231
  end
193
232
 
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
- }
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]
214
244
  end
215
245
 
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:
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:
221
250
  #
222
- # foo.bar
223
- # .baz
251
+ # class Foo # :nodoc:
252
+ # ...
253
+ # end
224
254
  #
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
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]
255
259
 
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
260
+ if remaining.sub(/\A +/, '')[0] == '#'
261
+ return position + remaining.index("\n")
260
262
  end
261
- )
262
263
 
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:
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:
268
271
  #
269
272
  # BEGIN {
270
273
  # # execute stuff here
@@ -284,11 +287,35 @@ class Prettier::Parser < Ripper
284
287
  )
285
288
  end
286
289
 
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:
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:
292
319
  #
293
320
  # END {
294
321
  # # execute stuff here
@@ -308,11 +335,34 @@ class Prettier::Parser < Ripper
308
335
  )
309
336
  end
310
337
 
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.
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.
316
366
  def on_alias(left, right)
317
367
  beging = find_scanner_event(:@kw, 'alias')
318
368
 
@@ -329,7 +379,7 @@ class Prettier::Parser < Ripper
329
379
  }
330
380
  end
331
381
 
332
- # 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
333
383
  # specific index. Put another way, it's any time you're calling the method
334
384
  # #[]. As an example:
335
385
  #
@@ -373,26 +423,59 @@ class Prettier::Parser < Ripper
373
423
  }
374
424
  end
375
425
 
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
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
+
380
460
  {
381
- type: :args,
382
- body: [],
383
- sl: lineno,
384
- sc: char_pos,
385
- el: lineno,
386
- 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]
387
467
  }
388
468
  end
389
469
 
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.
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.
394
474
  def on_args_add(args, arg)
395
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.
396
479
  arg.merge(type: :args, body: [arg])
397
480
  else
398
481
  args.merge!(body: args[:body] << arg, el: arg[:el], ec: arg[:ec])
@@ -401,7 +484,7 @@ class Prettier::Parser < Ripper
401
484
 
402
485
  # args_add_block is a parser event that represents a list of arguments and
403
486
  # potentially a block argument. If no block is passed, then the second
404
- # argument will be false.
487
+ # argument will be the literal false.
405
488
  def on_args_add_block(args, block)
406
489
  ending = block || args
407
490
 
@@ -436,24 +519,17 @@ class Prettier::Parser < Ripper
436
519
  find_scanner_event(:@op, '...').merge!(type: :args_forward)
437
520
  end
438
521
 
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
-
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
450
526
  {
451
- type: :arg_paren,
452
- body: [args],
453
- sl: beging[:sl],
454
- sc: beging[:sc],
455
- el: ending[:el],
456
- ec: ending[:ec]
527
+ type: :args,
528
+ body: [],
529
+ sl: lineno,
530
+ sc: char_pos,
531
+ el: lineno,
532
+ ec: char_pos
457
533
  }
458
534
  end
459
535
 
@@ -554,6 +630,45 @@ class Prettier::Parser < Ripper
554
630
  }
555
631
  end
556
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
+
557
672
  # bare_assoc_hash is a parser event that represents a hash of contents
558
673
  # being passed as a method argument (and therefore has omitted braces). It
559
674
  # accepts as an argument an array of assoc events (either assoc_new or
@@ -768,27 +883,6 @@ class Prettier::Parser < Ripper
768
883
  )
769
884
  end
770
885
 
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
886
  # class is a parser event that represents defining a class. It accepts as
793
887
  # arguments the name of the class, the optional name of the superclass,
794
888
  # and the bodystmt event that represents the statements evaluated within
@@ -812,6 +906,24 @@ class Prettier::Parser < Ripper
812
906
  }
813
907
  end
814
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
+
815
927
  # command is a parser event representing a method call with arguments and
816
928
  # no parentheses. It accepts as arguments the name of the method and the
817
929
  # arguments being passed to the method.
@@ -843,6 +955,70 @@ class Prettier::Parser < Ripper
843
955
  }
844
956
  end
845
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
+
846
1022
  # A const_path_field is a parser event that is always the child of some
847
1023
  # kind of assignment. It represents when you're assigning to a constant
848
1024
  # that is being referenced as a child of another variable. For example:
@@ -862,10 +1038,8 @@ class Prettier::Parser < Ripper
862
1038
 
863
1039
  # A const_path_ref is a parser event that is a very similar to
864
1040
  # const_path_field except that it is not involved in an assignment. It
865
- # looks like the following example:
866
- #
867
- # foo::X
868
- #
1041
+ # looks like the following example: foo::Bar, where left is foo and const is
1042
+ # Bar.
869
1043
  def on_const_path_ref(left, const)
870
1044
  {
871
1045
  type: :const_path_ref,
@@ -887,6 +1061,24 @@ class Prettier::Parser < Ripper
887
1061
  const.merge(type: :const_ref, body: [const])
888
1062
  end
889
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
+
890
1082
  # A def is a parser event that represents defining a regular method on the
891
1083
  # current self object. It accepts as arguments the ident (the name of the
892
1084
  # method being defined), the params (the parameter declaration for the
@@ -1113,25 +1305,22 @@ class Prettier::Parser < Ripper
1113
1305
  end
1114
1306
  end
1115
1307
 
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
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).
1120
1317
  index =
1121
1318
  scanner_events.rindex do |event|
1122
1319
  event[:type] == :@kw && %w[end ensure].include?(event[:body])
1123
1320
  end
1124
1321
 
1125
1322
  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
1323
+ ending = event[:body] == 'end' ? scanner_events.delete_at(index) : event
1135
1324
 
1136
1325
  stmts.bind(beging[:ec], ending[:sc])
1137
1326
 
@@ -1165,6 +1354,14 @@ class Prettier::Parser < Ripper
1165
1354
  }
1166
1355
  end
1167
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
+
1168
1365
  # embdocs are long comments that are surrounded by =begin..=end. They
1169
1366
  # cannot be nested, so we don't need to worry about keeping a stack around
1170
1367
  # like we do with heredocs. Instead we can just track the current embdoc
@@ -1174,14 +1371,6 @@ class Prettier::Parser < Ripper
1174
1371
  @embdoc = { type: :@embdoc, value: value, sl: lineno, sc: char_pos }
1175
1372
  end
1176
1373
 
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
1374
  # This is the final scanner event for embdocs. It receives the =end. Here
1186
1375
  # we can finalize the embdoc with its location information and the final
1187
1376
  # piece of the string. We then add it to the list of comments so that
@@ -1197,6 +1386,72 @@ class Prettier::Parser < Ripper
1197
1386
  @embdoc = nil
1198
1387
  end
1199
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
+
1200
1455
  # ensure is a parser event that represents the use of the ensure keyword
1201
1456
  # and its subsequent statements.
1202
1457
  def on_ensure(stmts)
@@ -1253,6 +1508,24 @@ class Prettier::Parser < Ripper
1253
1508
  }
1254
1509
  end
1255
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
+
1256
1529
  # fndptn is a parser event that represents matching against a pattern where
1257
1530
  # you find a pattern in an array using the Ruby 3.0+ pattern matching syntax.
1258
1531
  def on_fndptn(const, presplat, args, postsplat)
@@ -1273,15 +1546,22 @@ class Prettier::Parser < Ripper
1273
1546
  # loop. It accepts as arguments an ident which is the iterating variable,
1274
1547
  # an enumerable for that which is being enumerated, and a stmts event that
1275
1548
  # represents the statements inside the for loop.
1276
- def on_for(ident, enumerable, stmts)
1549
+ def on_for(ident, enum, stmts)
1277
1550
  beging = find_scanner_event(:@kw, 'for')
1278
1551
  ending = find_scanner_event(:@kw, 'end')
1279
1552
 
1280
- 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])
1281
1561
 
1282
1562
  {
1283
1563
  type: :for,
1284
- body: [ident, enumerable, stmts],
1564
+ body: [ident, enum, stmts],
1285
1565
  sl: beging[:sl],
1286
1566
  sc: beging[:sc],
1287
1567
  el: ending[:el],
@@ -1289,6 +1569,24 @@ class Prettier::Parser < Ripper
1289
1569
  }
1290
1570
  end
1291
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
+
1292
1590
  # hash is a parser event that represents a hash literal. It accepts as an
1293
1591
  # argument an optional assoclist_from_args event which contains the
1294
1592
  # contents of the hash.
@@ -1363,6 +1661,27 @@ class Prettier::Parser < Ripper
1363
1661
  }
1364
1662
  end
1365
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
+
1366
1685
  # if is a parser event that represents the first clause in an if chain.
1367
1686
  # It accepts as arguments the predicate of the if, the statements that are
1368
1687
  # contained within the if clause, and the optional consequent clause.
@@ -1410,6 +1729,56 @@ class Prettier::Parser < Ripper
1410
1729
  }
1411
1730
  end
1412
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
1776
+ }
1777
+
1778
+ scanner_events << node
1779
+ node
1780
+ end
1781
+
1413
1782
  # in is a parser event that represents using the in keyword within the
1414
1783
  # Ruby 2.7+ pattern matching syntax. Alternatively in Ruby 3+ it is also used
1415
1784
  # to handle rightward assignment for pattern matching.
@@ -1430,6 +1799,61 @@ class Prettier::Parser < Ripper
1430
1799
  )
1431
1800
  end
1432
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
+
1433
1857
  # kwrest_param is a parser event that represents defining a parameter in a
1434
1858
  # method definition that accepts all remaining keyword parameters.
1435
1859
  def on_kwrest_param(ident)
@@ -1444,6 +1868,61 @@ class Prettier::Parser < Ripper
1444
1868
  )
1445
1869
  end
1446
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
+
1447
1926
  # lambda is a parser event that represents using a "stabby" lambda
1448
1927
  # literal. It accepts as arguments a params event that represents any
1449
1928
  # parameters to the lambda and a stmts event that represents the
@@ -1474,6 +1953,80 @@ class Prettier::Parser < Ripper
1474
1953
  }
1475
1954
  end
1476
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
+
1477
2030
  # massign is a parser event that is a parent node of any kind of multiple
1478
2031
  # assignment. This includes splitting out variables on the left like:
1479
2032
  #
@@ -1704,6 +2257,52 @@ class Prettier::Parser < Ripper
1704
2257
  )
1705
2258
  end
1706
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
+
1707
2306
  # opassign is a parser event that represents assigning something to a
1708
2307
  # variable or constant using an operator like += or ||=. It accepts as
1709
2308
  # arguments the left side of the expression before the operator, the
@@ -1717,6 +2316,20 @@ class Prettier::Parser < Ripper
1717
2316
  )
1718
2317
  end
1719
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
+
1720
2333
  # params is a parser event that represents defining parameters on a
1721
2334
  # method. They have a somewhat interesting structure in that they are an
1722
2335
  # array of arrays where the position in the top-level array indicates the
@@ -1743,31 +2356,25 @@ class Prettier::Parser < Ripper
1743
2356
  # anywhere in a Ruby program. It accepts as arguments the contents, which
1744
2357
  # can be either params or statements.
1745
2358
  def on_paren(contents)
1746
- beging = find_scanner_event(:@lparen)
1747
- ending = find_scanner_event(:@rparen)
2359
+ lparen = find_scanner_event(:@lparen)
2360
+ rparen = find_scanner_event(:@rparen)
1748
2361
 
1749
2362
  if contents && contents[:type] == :params
1750
- contents.merge!(sc: beging[:ec], ec: ending[:sc])
2363
+ contents.merge!(
2364
+ sc: find_next_statement_start(lparen[:ec]),
2365
+ ec: rparen[:sc]
2366
+ )
1751
2367
  end
1752
2368
 
1753
- beging.merge!(
2369
+ {
1754
2370
  type: :paren,
2371
+ lparen: lparen,
1755
2372
  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
2373
+ sl: lparen[:sl],
2374
+ sc: lparen[:sc],
2375
+ el: rparen[:el],
2376
+ ec: rparen[:ec]
2377
+ }
1771
2378
  end
1772
2379
 
1773
2380
  # If we encounter a parse error, just immediately bail out so that our runner
@@ -1780,6 +2387,22 @@ class Prettier::Parser < Ripper
1780
2387
  alias on_class_name_error on_parse_error
1781
2388
  alias on_param_error on_parse_error
1782
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
+
1783
2406
  # The program node is the very top of the AST. Here we'll attach all of
1784
2407
  # the comments that we've gathered up over the course of parsing the
1785
2408
  # source string. We'll also attach on the __END__ content if there was
@@ -1793,6 +2416,29 @@ class Prettier::Parser < Ripper
1793
2416
  range.merge(type: :program, body: [stmts], comments: @comments)
1794
2417
  end
1795
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
+
1796
2442
  # qsymbols_new is a parser event that represents the beginning of a symbol
1797
2443
  # literal array, like %i[one two three]. It can be followed by any number
1798
2444
  # of qsymbols_add events, which we'll append onto an array body.
@@ -1812,6 +2458,29 @@ class Prettier::Parser < Ripper
1812
2458
  )
1813
2459
  end
1814
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
+
1815
2484
  # qwords_new is a parser event that represents the beginning of a string
1816
2485
  # literal array, like %w[one two three]. It can be followed by any number
1817
2486
  # of qwords_add events, which we'll append onto an array body.
@@ -1831,24 +2500,73 @@ class Prettier::Parser < Ripper
1831
2500
  )
1832
2501
  end
1833
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
+
1834
2559
  # redo is a parser event that represents the bare redo keyword. It has no
1835
2560
  # body as it accepts no arguments.
1836
2561
  def on_redo
1837
2562
  find_scanner_event(:@kw, 'redo').merge!(type: :redo)
1838
2563
  end
1839
2564
 
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
2565
+ # regexp_add is a parser event that represents a piece of a regular expression
1849
2566
  # 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.
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.
1852
2570
  def on_regexp_add(regexp, piece)
1853
2571
  regexp.merge!(
1854
2572
  body: regexp[:body] << piece,
@@ -1857,6 +2575,43 @@ class Prettier::Parser < Ripper
1857
2575
  )
1858
2576
  end
1859
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
+
1860
2615
  # regexp_literal is a parser event that represents a regular expression.
1861
2616
  # It accepts as arguments a regexp node which is a built-up array of
1862
2617
  # pieces that go into the regexp content, as well as the ending used to
@@ -1870,6 +2625,14 @@ class Prettier::Parser < Ripper
1870
2625
  )
1871
2626
  end
1872
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
+
1873
2636
  # rescue is a special kind of node where you have a rescue chain but it
1874
2637
  # doesn't really have all of the information that it needs in order to
1875
2638
  # determine its ending. Therefore it relies on its parent bodystmt node to
@@ -1983,6 +2746,25 @@ class Prettier::Parser < Ripper
1983
2746
  find_scanner_event(:@kw, 'return').merge!(type: :return0)
1984
2747
  end
1985
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
+
1986
2768
  # sclass is a parser event that represents a block of statements that
1987
2769
  # should be evaluated within the context of the singleton class of an
1988
2770
  # object. It's frequently used to define singleton methods. It looks like
@@ -2009,6 +2791,31 @@ class Prettier::Parser < Ripper
2009
2791
  }
2010
2792
  end
2011
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
+
2012
2819
  # Everything that has a block of code inside of it has a list of statements.
2013
2820
  # Normally we would just track those as a node that has an array body, but we
2014
2821
  # have some special handling in order to handle empty statement lists. They
@@ -2074,12 +2881,12 @@ class Prettier::Parser < Ripper
2074
2881
  )
2075
2882
  end
2076
2883
 
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
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])
2083
2890
  end
2084
2891
 
2085
2892
  # string_concat is a parser event that represents concatenating two
@@ -2115,14 +2922,6 @@ class Prettier::Parser < Ripper
2115
2922
  }
2116
2923
  end
2117
2924
 
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
2925
  # string_dvar is a parser event that represents a very special kind of
2127
2926
  # interpolation into string. It allows you to take an instance variable,
2128
2927
  # class variable, or global variable and omit the braces when
@@ -2193,16 +2992,33 @@ class Prettier::Parser < Ripper
2193
2992
  )
2194
2993
  end
2195
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
+
2196
3015
  # A symbol is a parser event that immediately descends from a symbol
2197
3016
  # literal and contains an ident representing the contents of the symbol.
2198
3017
  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.
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" }.
2206
3022
  #
2207
3023
  # In order to take care of this, we explicitly delete this scanner event
2208
3024
  # from the stack to make sure it doesn't screw things up.
@@ -2224,6 +3040,29 @@ class Prettier::Parser < Ripper
2224
3040
  end
2225
3041
  end
2226
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
+
2227
3066
  # symbols_new is a parser event that represents the beginning of a symbol
2228
3067
  # literal array that accepts interpolation, like %I[one #{two} three]. It
2229
3068
  # can be followed by any number of symbols_add events, which we'll append
@@ -2244,17 +3083,42 @@ class Prettier::Parser < Ripper
2244
3083
  )
2245
3084
  end
2246
3085
 
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
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
2256
3091
 
2257
- 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
2258
3122
  end
2259
3123
 
2260
3124
  # A top_const_field is a parser event that is always the child of some
@@ -2289,6 +3153,63 @@ class Prettier::Parser < Ripper
2289
3153
  )
2290
3154
  end
2291
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
+
2292
3213
  # A unary node represents a unary method being called on an expression, as
2293
3214
  # in !, ~, or not. We have somewhat special handling of the not operator
2294
3215
  # since if it has parentheses they don't get reported as a paren node for
@@ -2586,6 +3507,48 @@ class Prettier::Parser < Ripper
2586
3507
  end
2587
3508
  end
2588
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
+
2589
3552
  # words_new is a parser event that represents the beginning of a string
2590
3553
  # literal array that accepts interpolation, like %W[one #{two} three]. It
2591
3554
  # can be followed by any number of words_add events, which we'll append