prettier 2.0.0.pre.rc4 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +58 -10
  3. data/README.md +16 -16
  4. data/exe/rbprettier +2 -2
  5. data/lib/prettier/rake/task.rb +5 -5
  6. data/lib/prettier.rb +12 -11
  7. data/node_modules/prettier/bin-prettier.js +48 -18924
  8. data/node_modules/prettier/cli.js +12335 -0
  9. data/node_modules/prettier/doc.js +1306 -4755
  10. data/node_modules/prettier/index.js +37468 -57614
  11. data/node_modules/prettier/package.json +3 -2
  12. data/node_modules/prettier/parser-angular.js +2 -66
  13. data/node_modules/prettier/parser-babel.js +27 -22
  14. data/node_modules/prettier/parser-espree.js +26 -22
  15. data/node_modules/prettier/parser-flow.js +26 -22
  16. data/node_modules/prettier/parser-glimmer.js +27 -1
  17. data/node_modules/prettier/parser-graphql.js +15 -1
  18. data/node_modules/prettier/parser-html.js +21 -117
  19. data/node_modules/prettier/parser-markdown.js +61 -19
  20. data/node_modules/prettier/parser-meriyah.js +19 -22
  21. data/node_modules/prettier/parser-postcss.js +76 -22
  22. data/node_modules/prettier/parser-typescript.js +280 -22
  23. data/node_modules/prettier/parser-yaml.js +150 -15
  24. data/node_modules/prettier/third-party.js +8660 -11030
  25. data/package.json +10 -24
  26. data/rubocop.yml +14 -8
  27. data/src/getInfo.js +23 -0
  28. data/{dist/parser → src}/netcat.js +0 -1
  29. data/src/parseSync.js +212 -0
  30. data/src/plugin.js +161 -0
  31. data/{dist/parser → src}/server.rb +45 -27
  32. metadata +97 -77
  33. data/bin/console +0 -7
  34. data/dist/haml/embed.js +0 -53
  35. data/dist/haml/parser.js +0 -31
  36. data/dist/haml/parser.rb +0 -143
  37. data/dist/haml/printer.js +0 -336
  38. data/dist/parser/getInfo.js +0 -17
  39. data/dist/parser/parseSync.js +0 -179
  40. data/dist/plugin.js +0 -143
  41. data/dist/prettier.js +0 -15
  42. data/dist/rbs/parser.js +0 -34
  43. data/dist/rbs/parser.rb +0 -98
  44. data/dist/rbs/printer.js +0 -517
  45. data/dist/ruby/embed.js +0 -110
  46. data/dist/ruby/nodes/alias.js +0 -59
  47. data/dist/ruby/nodes/aref.js +0 -53
  48. data/dist/ruby/nodes/args.js +0 -165
  49. data/dist/ruby/nodes/arrays.js +0 -126
  50. data/dist/ruby/nodes/assign.js +0 -41
  51. data/dist/ruby/nodes/blocks.js +0 -87
  52. data/dist/ruby/nodes/calls.js +0 -260
  53. data/dist/ruby/nodes/case.js +0 -50
  54. data/dist/ruby/nodes/class.js +0 -54
  55. data/dist/ruby/nodes/commands.js +0 -124
  56. data/dist/ruby/nodes/conditionals.js +0 -242
  57. data/dist/ruby/nodes/constants.js +0 -38
  58. data/dist/ruby/nodes/flow.js +0 -66
  59. data/dist/ruby/nodes/hashes.js +0 -130
  60. data/dist/ruby/nodes/heredocs.js +0 -30
  61. data/dist/ruby/nodes/hooks.js +0 -35
  62. data/dist/ruby/nodes/ints.js +0 -27
  63. data/dist/ruby/nodes/lambdas.js +0 -69
  64. data/dist/ruby/nodes/loops.js +0 -73
  65. data/dist/ruby/nodes/massign.js +0 -73
  66. data/dist/ruby/nodes/methods.js +0 -70
  67. data/dist/ruby/nodes/operators.js +0 -70
  68. data/dist/ruby/nodes/params.js +0 -89
  69. data/dist/ruby/nodes/patterns.js +0 -109
  70. data/dist/ruby/nodes/regexp.js +0 -45
  71. data/dist/ruby/nodes/rescue.js +0 -85
  72. data/dist/ruby/nodes/return.js +0 -75
  73. data/dist/ruby/nodes/statements.js +0 -111
  74. data/dist/ruby/nodes/strings.js +0 -218
  75. data/dist/ruby/nodes/super.js +0 -30
  76. data/dist/ruby/nodes/undef.js +0 -26
  77. data/dist/ruby/nodes.js +0 -151
  78. data/dist/ruby/parser.js +0 -34
  79. data/dist/ruby/parser.rb +0 -3636
  80. data/dist/ruby/printer.js +0 -129
  81. data/dist/ruby/toProc.js +0 -93
  82. data/dist/types/haml.js +0 -4
  83. data/dist/types/plugin.js +0 -3
  84. data/dist/types/rbs.js +0 -4
  85. data/dist/types/ruby.js +0 -4
  86. data/dist/types/utils.js +0 -2
  87. data/dist/types.js +0 -30
  88. data/dist/utils/containsAssignment.js +0 -15
  89. data/dist/utils/getTrailingComma.js +0 -6
  90. data/dist/utils/hasAncestor.js +0 -15
  91. data/dist/utils/inlineEnsureParens.js +0 -49
  92. data/dist/utils/isEmptyBodyStmt.js +0 -10
  93. data/dist/utils/isEmptyStmts.js +0 -10
  94. data/dist/utils/literal.js +0 -8
  95. data/dist/utils/literallineWithoutBreakParent.js +0 -8
  96. data/dist/utils/makeCall.js +0 -13
  97. data/dist/utils/noIndent.js +0 -11
  98. data/dist/utils/printEmptyCollection.js +0 -44
  99. data/dist/utils/skipAssignIndent.js +0 -15
  100. data/dist/utils.js +0 -30
data/dist/ruby/parser.rb DELETED
@@ -1,3636 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # We implement our own version checking here instead of using Gem::Version so
4
- # that we can use the --disable-gems flag.
5
- RUBY_MAJOR, RUBY_MINOR, RUBY_PATCH, * = RUBY_VERSION.split('.').map(&:to_i)
6
-
7
- if (RUBY_MAJOR < 2) || ((RUBY_MAJOR == 2) && (RUBY_MINOR < 5))
8
- warn(
9
- "Ruby version #{RUBY_VERSION} not supported. " \
10
- 'Please upgrade to 2.5.0 or above.'
11
- )
12
-
13
- exit 1
14
- end
15
-
16
- require 'json' unless defined?(JSON)
17
- require 'ripper'
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.
21
- module Prettier
22
- end
23
-
24
- class Prettier::Parser < Ripper
25
- # Represents a line in the source. If this class is being used, it means that
26
- # every character in the string is 1 byte in length, so we can just return the
27
- # start of the line + the index.
28
- class SingleByteString
29
- def initialize(start)
30
- @start = start
31
- end
32
-
33
- def [](byteindex)
34
- @start + byteindex
35
- end
36
- end
37
-
38
- # Represents a line in the source. If this class is being used, it means that
39
- # there are characters in the string that are multi-byte, so we will build up
40
- # an array of indices, such that array[byteindex] will be equal to the index
41
- # of the character within the string.
42
- class MultiByteString
43
- def initialize(start, line)
44
- @indices = []
45
-
46
- line
47
- .each_char
48
- .with_index(start) do |char, index|
49
- char.bytesize.times { @indices << index }
50
- end
51
- end
52
-
53
- def [](byteindex)
54
- @indices[byteindex]
55
- end
56
- end
57
-
58
- # This is a small wrapper around the value of a node for those specific events
59
- # that need extra handling. (For example: statement, body statement, and
60
- # rescue nodes which all need extra information to determine their character
61
- # boundaries.)
62
- class Node
63
- attr_reader :parser, :value
64
-
65
- def initialize(parser, value)
66
- @parser = parser
67
- @value = value
68
- end
69
-
70
- def [](key)
71
- value[key]
72
- end
73
-
74
- def dig(*keys)
75
- value.dig(*keys)
76
- end
77
-
78
- def to_json(*opts)
79
- value.to_json(*opts)
80
- end
81
-
82
- def pretty_print(q)
83
- q.pp_hash(self)
84
- end
85
- end
86
-
87
- # A special parser error so that we can get nice syntax displays on the error
88
- # message when prettier prints out the results.
89
- class ParserError < StandardError
90
- attr_reader :lineno, :column
91
-
92
- def initialize(error, lineno, column)
93
- super(error)
94
- @lineno = lineno
95
- @column = column
96
- end
97
- end
98
-
99
- attr_reader :source, :lines, :scanner_events
100
-
101
- # This is an attr_accessor so Stmts objects can grab comments out of this
102
- # array and attach them to themselves.
103
- attr_accessor :comments
104
-
105
- def initialize(source, *args)
106
- super(source, *args)
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.
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.
118
- @lines = source.split("\n")
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.
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.
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.
137
- @__end__ = nil
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.
144
- @heredocs = []
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.
153
- @scanner_events = []
154
-
155
- # Here we're going to build up a list of SingleByteString or MultiByteString
156
- # objects. They're each going to represent a string in the source. They are
157
- # used by the `char_pos` method to determine where we are in the source
158
- # string.
159
- @line_counts = []
160
- last_index = 0
161
-
162
- @source.lines.each do |line|
163
- if line.size == line.bytesize
164
- @line_counts << SingleByteString.new(last_index)
165
- else
166
- @line_counts << MultiByteString.new(last_index, line)
167
- end
168
-
169
- last_index += line.size
170
- end
171
- end
172
-
173
- def self.parse(source)
174
- builder = new(source)
175
-
176
- response = builder.parse
177
- response unless builder.error?
178
- end
179
-
180
- private
181
-
182
- # This represents the current place in the source string that we've gotten to
183
- # so far. We have a memoized line_counts object that we can use to get the
184
- # number of characters that we've had to go through to get to the beginning of
185
- # this line, then we add the number of columns into this line that we've gone
186
- # through.
187
- def char_pos
188
- @line_counts[lineno - 1][column]
189
- end
190
-
191
- # As we build up a list of scanner events, we'll periodically need to go
192
- # backwards and find the ones that we've already hit in order to determine the
193
- # location information for nodes that use them. For example, if you have a
194
- # module node then you'll look backward for a @module scanner event to
195
- # determine your start location.
196
- #
197
- # This works with nesting since we're deleting scanner events from the list
198
- # once they've been used up. For example if you had nested module declarations
199
- # then the innermost declaration would grab the last @module event (which
200
- # would happen to be the innermost keyword). Then the outer one would only be
201
- # able to grab the first one. In this way all of the scanner events act as
202
- # their own stack.
203
- def find_scanner_event(type, body = :any, consume: true)
204
- index =
205
- scanner_events.rindex do |scanner_event|
206
- scanner_event[:type] == type &&
207
- (body == :any || (scanner_event[:body] == body))
208
- end
209
-
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
220
-
221
- scanner_events.delete_at(index)
222
- elsif index
223
- scanner_events[index]
224
- end
225
- end
226
-
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]
238
- end
239
-
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:
244
- #
245
- # class Foo # :nodoc:
246
- # ...
247
- # end
248
- #
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]
253
-
254
- if remaining.sub(/\A +/, '')[0] == '#'
255
- return position + remaining.index("\n")
256
- end
257
-
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:
265
- #
266
- # BEGIN {
267
- # # execute stuff here
268
- # }
269
- #
270
- def on_BEGIN(stmts)
271
- beging = find_scanner_event(:@lbrace)
272
- ending = find_scanner_event(:@rbrace)
273
-
274
- stmts.bind(find_next_statement_start(beging[:ec]), ending[:sc])
275
-
276
- find_scanner_event(:@kw, 'BEGIN').merge!(
277
- type: :BEGIN,
278
- body: [beging, stmts],
279
- el: ending[:el],
280
- ec: ending[:ec]
281
- )
282
- end
283
-
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:
313
- #
314
- # END {
315
- # # execute stuff here
316
- # }
317
- #
318
- def on_END(stmts)
319
- beging = find_scanner_event(:@lbrace)
320
- ending = find_scanner_event(:@rbrace)
321
-
322
- stmts.bind(find_next_statement_start(beging[:ec]), ending[:sc])
323
-
324
- find_scanner_event(:@kw, 'END').merge!(
325
- type: :END,
326
- body: [beging, stmts],
327
- el: ending[:el],
328
- ec: ending[:ec]
329
- )
330
- end
331
-
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.
360
- def on_alias(left, right)
361
- beging = find_scanner_event(:@kw, 'alias')
362
-
363
- paren = source[beging[:ec]...left[:sc]].include?('(')
364
- ending = paren ? find_scanner_event(:@rparen) : right
365
-
366
- {
367
- type: :alias,
368
- body: [left, right],
369
- sl: beging[:sl],
370
- sc: beging[:sc],
371
- el: ending[:el],
372
- ec: ending[:ec]
373
- }
374
- end
375
-
376
- # aref is a parser event when you're pulling a value out of a collection at a
377
- # specific index. Put another way, it's any time you're calling the method
378
- # #[]. As an example:
379
- #
380
- # foo[index]
381
- #
382
- # The nodes usually contains two children, the collection and the index.
383
- # In some cases, you don't necessarily have the second child node, because
384
- # you can call procs with a pretty esoteric syntax. In the following
385
- # example, you wouldn't have a second child, and "foo" would be the first
386
- # child:
387
- #
388
- # foo[]
389
- #
390
- def on_aref(collection, index)
391
- find_scanner_event(:@lbracket)
392
- ending = find_scanner_event(:@rbracket)
393
-
394
- {
395
- type: :aref,
396
- body: [collection, index],
397
- sl: collection[:sl],
398
- sc: collection[:sc],
399
- el: ending[:el],
400
- ec: ending[:ec]
401
- }
402
- end
403
-
404
- # aref_field is a parser event that is very similar to aref except that it
405
- # is being used inside of an assignment.
406
- def on_aref_field(collection, index)
407
- find_scanner_event(:@lbracket)
408
- ending = find_scanner_event(:@rbracket)
409
-
410
- {
411
- type: :aref_field,
412
- body: [collection, index],
413
- sl: collection[:sl],
414
- sc: collection[:sc],
415
- el: ending[:el],
416
- ec: ending[:ec]
417
- }
418
- end
419
-
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
-
454
- {
455
- type: :arg_paren,
456
- body: [args],
457
- sl: beging[:sl],
458
- sc: beging[:sc],
459
- el: ending[:el],
460
- ec: ending[:ec]
461
- }
462
- end
463
-
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.
468
- def on_args_add(args, arg)
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.
473
- arg.merge(type: :args, body: [arg])
474
- else
475
- args.merge!(body: args[:body] << arg, el: arg[:el], ec: arg[:ec])
476
- end
477
- end
478
-
479
- # args_add_block is a parser event that represents a list of arguments and
480
- # potentially a block argument. If no block is passed, then the second
481
- # argument will be the literal false.
482
- def on_args_add_block(args, block)
483
- ending = block || args
484
-
485
- args.merge(
486
- type: :args_add_block,
487
- body: [args, block],
488
- el: ending[:el],
489
- ec: ending[:ec]
490
- )
491
- end
492
-
493
- # args_add_star is a parser event that represents adding a splat of values
494
- # to a list of arguments. If accepts as arguments the parent args node as
495
- # well as the part that is being splatted.
496
- def on_args_add_star(args, part)
497
- beging = find_scanner_event(:@op, '*')
498
- ending = part || beging
499
-
500
- {
501
- type: :args_add_star,
502
- body: [args, part],
503
- sl: beging[:sl],
504
- sc: beging[:sc],
505
- el: ending[:el],
506
- ec: ending[:ec]
507
- }
508
- end
509
-
510
- # args_forward is a parser event that represents forwarding all kinds of
511
- # arguments onto another method call.
512
- def on_args_forward
513
- find_scanner_event(:@op, '...').merge!(type: :args_forward)
514
- end
515
-
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
520
- {
521
- type: :args,
522
- body: [],
523
- sl: lineno,
524
- sc: char_pos,
525
- el: lineno,
526
- ec: char_pos
527
- }
528
- end
529
-
530
- # Array nodes can contain a myriad of subnodes because of the special
531
- # array literal syntax like %w and %i. As a result, we may be looking for
532
- # an left bracket, or we may be just looking at the children to get the
533
- # bounds.
534
- def on_array(contents)
535
- if !contents || %i[args args_add_star].include?(contents[:type])
536
- beging = find_scanner_event(:@lbracket)
537
- ending = find_scanner_event(:@rbracket)
538
-
539
- {
540
- type: :array,
541
- body: [contents],
542
- sl: beging[:sl],
543
- sc: beging[:sc],
544
- el: ending[:el],
545
- ec: ending[:ec]
546
- }
547
- else
548
- ending = find_scanner_event(:@tstring_end)
549
- contents[:ec] = ending[:ec]
550
-
551
- ending.merge!(
552
- type: :array,
553
- body: [contents],
554
- sl: contents[:sl],
555
- sc: contents[:sc]
556
- )
557
- end
558
- end
559
-
560
- # aryptn is a parser event that represents matching against an array pattern
561
- # using the Ruby 2.7+ pattern matching syntax.
562
- def on_aryptn(const, preargs, splatarg, postargs)
563
- pieces = [const, *preargs, splatarg, *postargs].compact
564
-
565
- {
566
- type: :aryptn,
567
- body: [const, preargs, splatarg, postargs],
568
- sl: pieces[0][:sl],
569
- sc: pieces[0][:sc],
570
- el: pieces[-1][:el],
571
- ec: pieces[-1][:ec]
572
- }
573
- end
574
-
575
- # assign is a parser event that represents assigning something to a
576
- # variable or constant. It accepts as arguments the left side of the
577
- # expression before the equals sign and the right side of the expression.
578
- def on_assign(left, right)
579
- left.merge(
580
- type: :assign,
581
- body: [left, right],
582
- el: right[:el],
583
- ec: right[:ec]
584
- )
585
- end
586
-
587
- # assoc_new is a parser event that contains a key-value pair within a
588
- # hash. It is a child event of either an assoclist_from_args or a
589
- # bare_assoc_hash.
590
- def on_assoc_new(key, value)
591
- {
592
- type: :assoc_new,
593
- body: [key, value],
594
- sl: key[:sl],
595
- sc: key[:sc],
596
- el: value[:el],
597
- ec: value[:ec]
598
- }
599
- end
600
-
601
- # assoc_splat is a parser event that represents splatting a value into a
602
- # hash (either a hash literal or a bare hash in a method call).
603
- def on_assoc_splat(contents)
604
- find_scanner_event(:@op, '**').merge!(
605
- type: :assoc_splat,
606
- body: [contents],
607
- el: contents[:el],
608
- ec: contents[:ec]
609
- )
610
- end
611
-
612
- # assoclist_from_args is a parser event that contains a list of all of the
613
- # associations inside of a hash literal. Its parent node is always a hash.
614
- # It accepts as an argument an array of assoc events (either assoc_new or
615
- # assoc_splat).
616
- def on_assoclist_from_args(assocs)
617
- {
618
- type: :assoclist_from_args,
619
- body: assocs,
620
- sl: assocs[0][:sl],
621
- sc: assocs[0][:sc],
622
- el: assocs[-1][:el],
623
- ec: assocs[-1][:ec]
624
- }
625
- end
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
-
666
- # bare_assoc_hash is a parser event that represents a hash of contents
667
- # being passed as a method argument (and therefore has omitted braces). It
668
- # accepts as an argument an array of assoc events (either assoc_new or
669
- # assoc_splat).
670
- def on_bare_assoc_hash(assoc_news)
671
- {
672
- type: :bare_assoc_hash,
673
- body: assoc_news,
674
- sl: assoc_news[0][:sl],
675
- sc: assoc_news[0][:sc],
676
- el: assoc_news[-1][:el],
677
- ec: assoc_news[-1][:ec]
678
- }
679
- end
680
-
681
- # begin is a parser event that represents the beginning of a begin..end chain.
682
- # It includes a bodystmt event that has all of the consequent clauses.
683
- def on_begin(bodystmt)
684
- beging = find_scanner_event(:@kw, 'begin')
685
- ec =
686
- if bodystmt[:body][1..-1].any?
687
- bodystmt[:ec]
688
- else
689
- find_scanner_event(:@kw, 'end')[:ec]
690
- end
691
-
692
- bodystmt.bind(beging[:ec], ec)
693
-
694
- beging.merge!(
695
- type: :begin,
696
- body: [bodystmt],
697
- el: bodystmt[:el],
698
- ec: bodystmt[:ec]
699
- )
700
- end
701
-
702
- # binary is a parser event that represents a binary operation between two
703
- # values.
704
- def on_binary(left, oper, right)
705
- # On most Ruby implementations, oper is a Symbol that represents that
706
- # operation being performed. For instance in the example `1 < 2`, the `oper`
707
- # object would be `:<`. However, on JRuby, it's an `@op` node, so here we're
708
- # going to explicitly convert it into the same normalized form.
709
- oper = scanner_events.delete(oper)[:body] unless oper.is_a?(Symbol)
710
-
711
- {
712
- type: :binary,
713
- body: [left, oper, right],
714
- sl: left[:sl],
715
- sc: left[:sc],
716
- el: right[:el],
717
- ec: right[:ec]
718
- }
719
- end
720
-
721
- # block_var is a parser event that represents the parameters being passed to
722
- # block. Effectively they're everything contained within the pipes.
723
- def on_block_var(params, locals)
724
- index =
725
- scanner_events.rindex do |event|
726
- event[:type] == :@op && %w[| ||].include?(event[:body]) &&
727
- event[:sc] < params[:sc]
728
- end
729
-
730
- beging = scanner_events[index]
731
- ending = scanner_events[-1]
732
-
733
- {
734
- type: :block_var,
735
- body: [params, locals],
736
- sl: beging[:sl],
737
- sc: beging[:sc],
738
- el: ending[:el],
739
- ec: ending[:ec]
740
- }
741
- end
742
-
743
- # blockarg is a parser event that represents defining a block variable on
744
- # a method definition.
745
- def on_blockarg(ident)
746
- find_scanner_event(:@op, '&').merge!(
747
- type: :blockarg,
748
- body: [ident],
749
- el: ident[:el],
750
- ec: ident[:ec]
751
- )
752
- end
753
-
754
- # bodystmt can't actually determine its bounds appropriately because it
755
- # doesn't necessarily know where it started. So the parent node needs to
756
- # report back down into this one where it goes.
757
- class BodyStmt < Node
758
- def bind(sc, ec)
759
- value.merge!(sc: sc, ec: ec)
760
- parts = value[:body]
761
-
762
- # Here we're going to determine the bounds for the stmts
763
- consequent = parts[1..-1].compact.first
764
- value[:body][0].bind(sc, consequent ? consequent[:sc] : ec)
765
-
766
- # Next we're going to determine the rescue clause if there is one
767
- if parts[1]
768
- consequent = parts[2..-1].compact.first
769
- value[:body][1].bind_end(consequent ? consequent[:sc] : ec)
770
- end
771
- end
772
- end
773
-
774
- # bodystmt is a parser event that represents all of the possible combinations
775
- # of clauses within the body of a method or block.
776
- def on_bodystmt(stmts, rescued, ensured, elsed)
777
- BodyStmt.new(
778
- self,
779
- type: :bodystmt,
780
- body: [stmts, rescued, ensured, elsed],
781
- sl: lineno,
782
- sc: char_pos,
783
- el: lineno,
784
- ec: char_pos
785
- )
786
- end
787
-
788
- # brace_block is a parser event that represents passing a block to a
789
- # method call using the {..} operators. It accepts as arguments an
790
- # optional block_var event that represents any parameters to the block as
791
- # well as a stmts event that represents the statements inside the block.
792
- def on_brace_block(block_var, stmts)
793
- beging = find_scanner_event(:@lbrace)
794
- ending = find_scanner_event(:@rbrace)
795
-
796
- stmts.bind(
797
- find_next_statement_start((block_var || beging)[:ec]),
798
- ending[:sc]
799
- )
800
-
801
- {
802
- type: :brace_block,
803
- body: [block_var, stmts],
804
- beging: beging,
805
- sl: beging[:sl],
806
- sc: beging[:sc],
807
- el: [ending[:el], stmts[:el]].max,
808
- ec: ending[:ec]
809
- }
810
- end
811
-
812
- # break is a parser event that represents using the break keyword. It
813
- # accepts as an argument an args or args_add_block event that contains all
814
- # of the arguments being passed to the break.
815
- def on_break(args_add_block)
816
- beging = find_scanner_event(:@kw, 'break')
817
-
818
- # You can hit this if you are passing no arguments to break but it has a
819
- # comment right after it. In that case we can just use the location
820
- # information straight from the keyword.
821
- if args_add_block[:type] == :args
822
- return beging.merge!(type: :break, body: [args_add_block])
823
- end
824
-
825
- beging.merge!(
826
- type: :break,
827
- body: [args_add_block],
828
- el: args_add_block[:el],
829
- ec: args_add_block[:ec]
830
- )
831
- end
832
-
833
- # call is a parser event representing a method call with no arguments. It
834
- # accepts as arguments the receiver of the method, the operator being used
835
- # to send the method (., ::, or &.), and the value that is being sent to
836
- # the receiver (which can be another nested call as well).
837
- #
838
- # There is one esoteric syntax that comes into play here as well. If the
839
- # sending argument to this method is the symbol :call, then it represents
840
- # calling a lambda in a very odd looking way, as in:
841
- #
842
- # foo.(1, 2, 3)
843
- #
844
- def on_call(receiver, oper, sending)
845
- ending = sending
846
-
847
- if sending == :call
848
- ending = oper
849
-
850
- # Special handling here for Ruby <= 2.5 because the oper argument to this
851
- # method wasn't a parser event here it was just a plain symbol.
852
- ending = receiver if RUBY_MAJOR <= 2 && RUBY_MINOR <= 5
853
- end
854
-
855
- {
856
- type: :call,
857
- body: [receiver, oper, sending],
858
- sl: receiver[:sl],
859
- sc: receiver[:sc],
860
- el: [ending[:el], receiver[:el]].max,
861
- ec: ending[:ec]
862
- }
863
- end
864
-
865
- # case is a parser event that represents the beginning of a case chain.
866
- # It accepts as arguments the switch of the case and the consequent
867
- # clause.
868
- def on_case(switch, consequent)
869
- beging =
870
- if event = find_scanner_event(:@kw, 'case', consume: false)
871
- scanner_events.delete(event).merge!(type: :case)
872
- else
873
- keyword = find_scanner_event(:@kw, 'in', consume: false)
874
- switch.merge(type: :rassign, keyword: keyword)
875
- end
876
-
877
- beging.merge!(
878
- body: [switch, consequent],
879
- el: consequent[:el],
880
- ec: consequent[:ec]
881
- )
882
- end
883
-
884
- # class is a parser event that represents defining a class. It accepts as
885
- # arguments the name of the class, the optional name of the superclass,
886
- # and the bodystmt event that represents the statements evaluated within
887
- # the context of the class.
888
- def on_class(const, superclass, bodystmt)
889
- beging = find_scanner_event(:@kw, 'class')
890
- ending = find_scanner_event(:@kw, 'end')
891
-
892
- bodystmt.bind(
893
- find_next_statement_start((superclass || const)[:ec]),
894
- ending[:sc]
895
- )
896
-
897
- {
898
- type: :class,
899
- body: [const, superclass, bodystmt],
900
- sl: beging[:sl],
901
- sc: beging[:sc],
902
- el: ending[:el],
903
- ec: ending[:ec]
904
- }
905
- end
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
-
925
- # command is a parser event representing a method call with arguments and
926
- # no parentheses. It accepts as arguments the name of the method and the
927
- # arguments being passed to the method.
928
- def on_command(ident, args)
929
- {
930
- type: :command,
931
- body: [ident, args],
932
- sl: ident[:sl],
933
- sc: ident[:sc],
934
- el: args[:el],
935
- ec: args[:ec]
936
- }
937
- end
938
-
939
- # command_call is a parser event representing a method call on an object
940
- # with arguments and no parentheses. It accepts as arguments the receiver
941
- # of the method, the operator being used to send the method, the name of
942
- # the method, and the arguments being passed to the method.
943
- def on_command_call(receiver, oper, ident, args)
944
- ending = args || ident
945
-
946
- {
947
- type: :command_call,
948
- body: [receiver, oper, ident, args],
949
- sl: receiver[:sl],
950
- sc: receiver[:sc],
951
- el: ending[:el],
952
- ec: ending[:ec]
953
- }
954
- end
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
-
1004
- # A const_path_field is a parser event that is always the child of some
1005
- # kind of assignment. It represents when you're assigning to a constant
1006
- # that is being referenced as a child of another variable. For example:
1007
- #
1008
- # foo::X = 1
1009
- #
1010
- def on_const_path_field(left, const)
1011
- {
1012
- type: :const_path_field,
1013
- body: [left, const],
1014
- sl: left[:sl],
1015
- sc: left[:sc],
1016
- el: const[:el],
1017
- ec: const[:ec]
1018
- }
1019
- end
1020
-
1021
- # A const_path_ref is a parser event that is a very similar to
1022
- # const_path_field except that it is not involved in an assignment. It
1023
- # looks like the following example: foo::Bar, where left is foo and const is
1024
- # Bar.
1025
- def on_const_path_ref(left, const)
1026
- {
1027
- type: :const_path_ref,
1028
- body: [left, const],
1029
- sl: left[:sl],
1030
- sc: left[:sc],
1031
- el: const[:el],
1032
- ec: const[:ec]
1033
- }
1034
- end
1035
-
1036
- # A const_ref is a parser event that represents the name of the constant
1037
- # being used in a class or module declaration. In the following example it
1038
- # is the @const scanner event that has the contents of Foo.
1039
- #
1040
- # class Foo; end
1041
- #
1042
- def on_const_ref(const)
1043
- const.merge(type: :const_ref, body: [const])
1044
- end
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
-
1064
- # A def is a parser event that represents defining a regular method on the
1065
- # current self object. It accepts as arguments the ident (the name of the
1066
- # method being defined), the params (the parameter declaration for the
1067
- # method), and a bodystmt node which represents the statements inside the
1068
- # method. As an example, here are the parts that go into this:
1069
- #
1070
- # def foo(bar) do baz end
1071
- # │ │ │
1072
- # │ │ └> bodystmt
1073
- # │ └> params
1074
- # └> ident
1075
- #
1076
- # You can also have single-line methods since Ruby 3.0+, which have slightly
1077
- # different syntax but still flow through this method. Those look like:
1078
- #
1079
- # def foo = bar
1080
- # | |
1081
- # | └> stmt
1082
- # └> ident
1083
- #
1084
- def on_def(ident, params, bodystmt)
1085
- # Make sure to delete this scanner event in case you're defining something
1086
- # like def class which would lead to this being a kw and causing all kinds
1087
- # of trouble
1088
- scanner_events.delete(ident)
1089
-
1090
- # Find the beginning of the method definition, which works for single-line
1091
- # and normal method definitions.
1092
- beging = find_scanner_event(:@kw, 'def')
1093
-
1094
- # If we don't have a bodystmt node, then we have a single-line method
1095
- if bodystmt[:type] != :bodystmt
1096
- return(
1097
- {
1098
- type: :defsl,
1099
- body: [ident, params, bodystmt],
1100
- sl: beging[:sl],
1101
- sc: beging[:sc],
1102
- el: bodystmt[:el],
1103
- ec: bodystmt[:ec]
1104
- }
1105
- )
1106
- end
1107
-
1108
- if params[:type] == :params && !params[:body].any?
1109
- location = ident[:ec]
1110
- params.merge!(sc: location, ec: location)
1111
- end
1112
-
1113
- ending = find_scanner_event(:@kw, 'end')
1114
-
1115
- bodystmt.bind(find_next_statement_start(params[:ec]), ending[:sc])
1116
-
1117
- {
1118
- type: :def,
1119
- body: [ident, params, bodystmt],
1120
- sl: beging[:sl],
1121
- sc: beging[:sc],
1122
- el: ending[:el],
1123
- ec: ending[:ec]
1124
- }
1125
- end
1126
-
1127
- # A defs is a parser event that represents defining a singleton method on
1128
- # an object. It accepts the same arguments as the def event, as well as
1129
- # the target and operator that on which this method is being defined. As
1130
- # an example, here are the parts that go into this:
1131
- #
1132
- # def foo.bar(baz) do baz end
1133
- # │ │ │ │ │
1134
- # │ │ │ │ │
1135
- # │ │ │ │ └> bodystmt
1136
- # │ │ │ └> params
1137
- # │ │ └> ident
1138
- # │ └> oper
1139
- # └> target
1140
- #
1141
- def on_defs(target, oper, ident, params, bodystmt)
1142
- # Make sure to delete this scanner event in case you're defining something
1143
- # like def class which would lead to this being a kw and causing all kinds
1144
- # of trouble
1145
- scanner_events.delete(ident)
1146
-
1147
- if params[:type] == :params && !params[:body].any?
1148
- location = ident[:ec]
1149
- params.merge!(sc: location, ec: location)
1150
- end
1151
-
1152
- beging = find_scanner_event(:@kw, 'def')
1153
- ending = find_scanner_event(:@kw, 'end')
1154
-
1155
- bodystmt.bind(find_next_statement_start(params[:ec]), ending[:sc])
1156
-
1157
- {
1158
- type: :defs,
1159
- body: [target, oper, ident, params, bodystmt],
1160
- sl: beging[:sl],
1161
- sc: beging[:sc],
1162
- el: ending[:el],
1163
- ec: ending[:ec]
1164
- }
1165
- end
1166
-
1167
- # A defined node represents the rather unique defined? operator. It can be
1168
- # used with and without parentheses. If they're present, we use them to
1169
- # determine our bounds, otherwise we use the value that's being passed to
1170
- # the operator.
1171
- def on_defined(value)
1172
- beging = find_scanner_event(:@kw, 'defined?')
1173
-
1174
- paren = source[beging[:ec]...value[:sc]].include?('(')
1175
- ending = paren ? find_scanner_event(:@rparen) : value
1176
-
1177
- beging.merge!(
1178
- type: :defined,
1179
- body: [value],
1180
- el: ending[:el],
1181
- ec: ending[:ec]
1182
- )
1183
- end
1184
-
1185
- # do_block is a parser event that represents passing a block to a method
1186
- # call using the do..end keywords. It accepts as arguments an optional
1187
- # block_var event that represents any parameters to the block as well as
1188
- # a bodystmt event that represents the statements inside the block.
1189
- def on_do_block(block_var, bodystmt)
1190
- beging = find_scanner_event(:@kw, 'do')
1191
- ending = find_scanner_event(:@kw, 'end')
1192
-
1193
- bodystmt.bind(
1194
- find_next_statement_start((block_var || beging)[:ec]),
1195
- ending[:sc]
1196
- )
1197
-
1198
- {
1199
- type: :do_block,
1200
- body: [block_var, bodystmt],
1201
- beging: beging,
1202
- sl: beging[:sl],
1203
- sc: beging[:sc],
1204
- el: ending[:el],
1205
- ec: ending[:ec]
1206
- }
1207
- end
1208
-
1209
- # dot2 is a parser event that represents using the .. operator between two
1210
- # expressions. Usually this is to create a range object but sometimes it's to
1211
- # use the flip-flop operator.
1212
- def on_dot2(left, right)
1213
- operator = find_scanner_event(:@op, '..')
1214
-
1215
- beging = left || operator
1216
- ending = right || operator
1217
-
1218
- {
1219
- type: :dot2,
1220
- body: [left, right],
1221
- sl: beging[:sl],
1222
- sc: beging[:sc],
1223
- el: ending[:el],
1224
- ec: ending[:ec]
1225
- }
1226
- end
1227
-
1228
- # dot3 is a parser event that represents using the ... operator between two
1229
- # expressions. Usually this is to create a range object but sometimes it's to
1230
- # use the flip-flop operator.
1231
- def on_dot3(left, right)
1232
- operator = find_scanner_event(:@op, '...')
1233
-
1234
- beging = left || operator
1235
- ending = right || operator
1236
-
1237
- {
1238
- type: :dot3,
1239
- body: [left, right],
1240
- sl: beging[:sl],
1241
- sc: beging[:sc],
1242
- el: ending[:el],
1243
- ec: ending[:ec]
1244
- }
1245
- end
1246
-
1247
- # A dyna_symbol is a parser event that represents a symbol literal that
1248
- # uses quotes to interpolate its value. For example, if you had a variable
1249
- # foo and you wanted a symbol that contained its value, you would write:
1250
- #
1251
- # :"#{foo}"
1252
- #
1253
- # As such, they accept as one argument a string node, which is the same
1254
- # node that gets accepted into a string_literal (since we're basically
1255
- # talking about a string literal with a : character at the beginning).
1256
- #
1257
- # They can also come in another flavor which is a dynamic symbol as a hash
1258
- # key. This is kind of an interesting syntax which results in us having to
1259
- # look for a @label_end scanner event instead to get our bearings. That
1260
- # kind of code would look like:
1261
- #
1262
- # { "#{foo}": bar }
1263
- #
1264
- # which would be the same symbol as above.
1265
- def on_dyna_symbol(string)
1266
- if find_scanner_event(:@symbeg, consume: false)
1267
- # A normal dynamic symbol
1268
- beging = find_scanner_event(:@symbeg)
1269
- ending = find_scanner_event(:@tstring_end)
1270
-
1271
- beging.merge(
1272
- type: :dyna_symbol,
1273
- quote: beging[:body],
1274
- body: string[:body],
1275
- el: ending[:el],
1276
- ec: ending[:ec]
1277
- )
1278
- else
1279
- # A dynamic symbol as a hash key
1280
- beging = find_scanner_event(:@tstring_beg)
1281
- ending = find_scanner_event(:@label_end)
1282
-
1283
- string.merge!(
1284
- type: :dyna_symbol,
1285
- quote: ending[:body][0],
1286
- sl: beging[:sl],
1287
- sc: beging[:sc],
1288
- el: ending[:el],
1289
- ec: ending[:ec]
1290
- )
1291
- end
1292
- end
1293
-
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).
1303
- index =
1304
- scanner_events.rindex do |event|
1305
- event[:type] == :@kw && %w[end ensure].include?(event[:body])
1306
- end
1307
-
1308
- event = scanner_events[index]
1309
- ending = event[:body] == 'end' ? scanner_events.delete_at(index) : event
1310
-
1311
- stmts.bind(beging[:ec], ending[:sc])
1312
-
1313
- {
1314
- type: :else,
1315
- body: [stmts],
1316
- sl: beging[:sl],
1317
- sc: beging[:sc],
1318
- el: ending[:el],
1319
- ec: ending[:ec]
1320
- }
1321
- end
1322
-
1323
- # elsif is a parser event that represents another clause in an if chain.
1324
- # It accepts as arguments the predicate of the else if, the statements
1325
- # that are contained within the else if clause, and the optional
1326
- # consequent clause.
1327
- def on_elsif(predicate, stmts, consequent)
1328
- beging = find_scanner_event(:@kw, 'elsif')
1329
- ending = consequent || find_scanner_event(:@kw, 'end')
1330
-
1331
- stmts.bind(predicate[:ec], ending[:sc])
1332
-
1333
- {
1334
- type: :elsif,
1335
- body: [predicate, stmts, consequent],
1336
- sl: beging[:sl],
1337
- sc: beging[:sc],
1338
- el: ending[:el],
1339
- ec: ending[:ec]
1340
- }
1341
- end
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
-
1351
- # embdocs are long comments that are surrounded by =begin..=end. They
1352
- # cannot be nested, so we don't need to worry about keeping a stack around
1353
- # like we do with heredocs. Instead we can just track the current embdoc
1354
- # and add to it as we get content. It always starts with this scanner
1355
- # event, so here we'll initialize the current embdoc.
1356
- def on_embdoc_beg(value)
1357
- @embdoc = { type: :@embdoc, value: value, sl: lineno, sc: char_pos }
1358
- end
1359
-
1360
- # This is the final scanner event for embdocs. It receives the =end. Here
1361
- # we can finalize the embdoc with its location information and the final
1362
- # piece of the string. We then add it to the list of comments so that
1363
- # prettier can place it into the final source string.
1364
- def on_embdoc_end(value)
1365
- @comments <<
1366
- @embdoc.merge!(
1367
- value: @embdoc[:value] << value.chomp,
1368
- el: lineno,
1369
- ec: char_pos + value.length - 1
1370
- )
1371
-
1372
- @embdoc = nil
1373
- end
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
-
1441
- # ensure is a parser event that represents the use of the ensure keyword
1442
- # and its subsequent statements.
1443
- def on_ensure(stmts)
1444
- beging = find_scanner_event(:@kw, 'ensure')
1445
-
1446
- # Specifically not using find_scanner_event here because we don't want to
1447
- # consume the :@end event, because that would break def..ensure..end chains.
1448
- index =
1449
- scanner_events.rindex do |scanner_event|
1450
- scanner_event[:type] == :@kw && scanner_event[:body] == 'end'
1451
- end
1452
-
1453
- ending = scanner_events[index]
1454
- stmts.bind(find_next_statement_start(beging[:ec]), ending[:sc])
1455
-
1456
- {
1457
- type: :ensure,
1458
- body: [beging, stmts],
1459
- sl: beging[:sl],
1460
- sc: beging[:sc],
1461
- el: ending[:el],
1462
- ec: ending[:ec]
1463
- }
1464
- end
1465
-
1466
- # An excessed_comma is a special kind of parser event that represents a comma
1467
- # at the end of a list of parameters. It's a very strange node. It accepts a
1468
- # different number of arguments depending on Ruby version, which is why we
1469
- # have the anonymous splat there.
1470
- def on_excessed_comma(*)
1471
- find_scanner_event(:@comma).merge!(type: :excessed_comma)
1472
- end
1473
-
1474
- # An fcall is a parser event that represents the piece of a method call
1475
- # that comes before any arguments (i.e., just the name of the method).
1476
- def on_fcall(ident)
1477
- ident.merge(type: :fcall, body: [ident])
1478
- end
1479
-
1480
- # A field is a parser event that is always the child of an assignment. It
1481
- # accepts as arguments the left side of operation, the operator (. or ::),
1482
- # and the right side of the operation. For example:
1483
- #
1484
- # foo.x = 1
1485
- #
1486
- def on_field(left, oper, right)
1487
- {
1488
- type: :field,
1489
- body: [left, oper, right],
1490
- sl: left[:sl],
1491
- sc: left[:sc],
1492
- el: right[:el],
1493
- ec: right[:ec]
1494
- }
1495
- end
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
-
1515
- # fndptn is a parser event that represents matching against a pattern where
1516
- # you find a pattern in an array using the Ruby 3.0+ pattern matching syntax.
1517
- def on_fndptn(const, presplat, args, postsplat)
1518
- beging = const || find_scanner_event(:@lbracket)
1519
- ending = find_scanner_event(:@rbracket)
1520
-
1521
- {
1522
- type: :fndptn,
1523
- body: [const, presplat, args, postsplat],
1524
- sl: beging[:sl],
1525
- sc: beging[:sc],
1526
- el: ending[:el],
1527
- ec: ending[:ec]
1528
- }
1529
- end
1530
-
1531
- # for is a parser event that represents using the somewhat esoteric for
1532
- # loop. It accepts as arguments an ident which is the iterating variable,
1533
- # an enumerable for that which is being enumerated, and a stmts event that
1534
- # represents the statements inside the for loop.
1535
- def on_for(ident, enum, stmts)
1536
- beging = find_scanner_event(:@kw, 'for')
1537
- ending = find_scanner_event(:@kw, 'end')
1538
-
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])
1547
-
1548
- {
1549
- type: :for,
1550
- body: [ident, enum, stmts],
1551
- sl: beging[:sl],
1552
- sc: beging[:sc],
1553
- el: ending[:el],
1554
- ec: ending[:ec]
1555
- }
1556
- end
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
-
1576
- # hash is a parser event that represents a hash literal. It accepts as an
1577
- # argument an optional assoclist_from_args event which contains the
1578
- # contents of the hash.
1579
- def on_hash(assoclist_from_args)
1580
- beging = find_scanner_event(:@lbrace)
1581
- ending = find_scanner_event(:@rbrace)
1582
-
1583
- if assoclist_from_args
1584
- # Here we're going to expand out the location information for the assocs
1585
- # node so that it can grab up any remaining comments inside the hash.
1586
- assoclist_from_args.merge!(sc: beging[:ec], ec: ending[:sc])
1587
- end
1588
-
1589
- {
1590
- type: :hash,
1591
- body: [assoclist_from_args],
1592
- sl: beging[:sl],
1593
- sc: beging[:sc],
1594
- el: ending[:el],
1595
- ec: ending[:ec]
1596
- }
1597
- end
1598
-
1599
- # This is a scanner event that represents the beginning of the heredoc. It
1600
- # includes the declaration (which we call beging here, which is just short
1601
- # for beginning). The declaration looks something like <<-HERE or <<~HERE.
1602
- # If the downcased version of the declaration actually matches an existing
1603
- # prettier parser, we'll later attempt to print it using that parser and
1604
- # printer through our embed function.
1605
- def on_heredoc_beg(beging)
1606
- location = {
1607
- sl: lineno,
1608
- el: lineno,
1609
- sc: char_pos,
1610
- ec: char_pos + beging.length + 1
1611
- }
1612
-
1613
- # Here we're going to artificially create an extra node type so that if
1614
- # there are comments after the declaration of a heredoc, they get printed.
1615
- location
1616
- .merge(
1617
- type: :heredoc,
1618
- beging: location.merge(type: :@heredoc_beg, body: beging)
1619
- )
1620
- .tap { |node| @heredocs << node }
1621
- end
1622
-
1623
- # This is a parser event that occurs when you're using a heredoc with a
1624
- # tilde. These are considered `heredoc_dedent` nodes, whereas the hyphen
1625
- # heredocs show up as string literals.
1626
- def on_heredoc_dedent(string, _width)
1627
- @heredocs[-1].merge!(body: string[:body])
1628
- end
1629
-
1630
- # This is a scanner event that represents the end of the heredoc.
1631
- def on_heredoc_end(ending)
1632
- @heredocs[-1].merge!(ending: ending.chomp, el: lineno, ec: char_pos)
1633
- end
1634
-
1635
- # hshptn is a parser event that represents matching against a hash pattern
1636
- # using the Ruby 2.7+ pattern matching syntax.
1637
- def on_hshptn(const, kw, kwrest)
1638
- pieces = [const, kw, kwrest].flatten(2).compact
1639
-
1640
- {
1641
- type: :hshptn,
1642
- body: [const, kw, kwrest],
1643
- sl: pieces[0][:sl],
1644
- sc: pieces[0][:sc],
1645
- el: pieces[-1][:el],
1646
- ec: pieces[-1][:ec]
1647
- }
1648
- end
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
-
1671
- # if is a parser event that represents the first clause in an if chain.
1672
- # It accepts as arguments the predicate of the if, the statements that are
1673
- # contained within the if clause, and the optional consequent clause.
1674
- def on_if(predicate, stmts, consequent)
1675
- beging = find_scanner_event(:@kw, 'if')
1676
- ending = consequent || find_scanner_event(:@kw, 'end')
1677
-
1678
- stmts.bind(predicate[:ec], ending[:sc])
1679
-
1680
- {
1681
- type: :if,
1682
- body: [predicate, stmts, consequent],
1683
- sl: beging[:sl],
1684
- sc: beging[:sc],
1685
- el: ending[:el],
1686
- ec: ending[:ec]
1687
- }
1688
- end
1689
-
1690
- # ifop is a parser event that represents a ternary operator. It accepts as
1691
- # arguments the predicate to the ternary, the truthy clause, and the falsy
1692
- # clause.
1693
- def on_ifop(predicate, truthy, falsy)
1694
- predicate.merge(
1695
- type: :ifop,
1696
- body: [predicate, truthy, falsy],
1697
- el: falsy[:el],
1698
- ec: falsy[:ec]
1699
- )
1700
- end
1701
-
1702
- # if_mod is a parser event that represents the modifier form of an if
1703
- # statement. It accepts as arguments the predicate of the if and the
1704
- # statement that are contained within the if clause.
1705
- def on_if_mod(predicate, statement)
1706
- find_scanner_event(:@kw, 'if')
1707
-
1708
- {
1709
- type: :if_mod,
1710
- body: [predicate, statement],
1711
- sl: statement[:sl],
1712
- sc: statement[:sc],
1713
- el: predicate[:el],
1714
- ec: predicate[:ec]
1715
- }
1716
- end
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
-
1768
- # in is a parser event that represents using the in keyword within the
1769
- # Ruby 2.7+ pattern matching syntax. Alternatively in Ruby 3+ it is also used
1770
- # to handle rightward assignment for pattern matching.
1771
- def on_in(pattern, stmts, consequent)
1772
- # Here we have a rightward assignment
1773
- return pattern unless stmts
1774
-
1775
- beging = find_scanner_event(:@kw, 'in')
1776
- ending = consequent || find_scanner_event(:@kw, 'end')
1777
-
1778
- stmts.bind(beging[:ec], ending[:sc])
1779
-
1780
- beging.merge!(
1781
- type: :in,
1782
- body: [pattern, stmts, consequent],
1783
- el: ending[:el],
1784
- ec: ending[:ec]
1785
- )
1786
- end
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
-
1843
- # kwrest_param is a parser event that represents defining a parameter in a
1844
- # method definition that accepts all remaining keyword parameters.
1845
- def on_kwrest_param(ident)
1846
- oper = find_scanner_event(:@op, '**')
1847
- return oper.merge!(type: :kwrest_param, body: [nil]) unless ident
1848
-
1849
- oper.merge!(
1850
- type: :kwrest_param,
1851
- body: [ident],
1852
- el: ident[:el],
1853
- ec: ident[:ec]
1854
- )
1855
- end
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
-
1912
- # lambda is a parser event that represents using a "stabby" lambda
1913
- # literal. It accepts as arguments a params event that represents any
1914
- # parameters to the lambda and a stmts event that represents the
1915
- # statements inside the lambda.
1916
- #
1917
- # It can be wrapped in either {..} or do..end so we look for either of
1918
- # those combinations to get our bounds.
1919
- def on_lambda(params, stmts)
1920
- beging = find_scanner_event(:@tlambda)
1921
-
1922
- if event = find_scanner_event(:@tlambeg, consume: false)
1923
- opening = scanner_events.delete(event)
1924
- closing = find_scanner_event(:@rbrace)
1925
- else
1926
- opening = find_scanner_event(:@kw, 'do')
1927
- closing = find_scanner_event(:@kw, 'end')
1928
- end
1929
-
1930
- stmts.bind(opening[:ec], closing[:sc])
1931
-
1932
- {
1933
- type: :lambda,
1934
- body: [params, stmts],
1935
- sl: beging[:sl],
1936
- sc: beging[:sc],
1937
- el: closing[:el],
1938
- ec: closing[:ec]
1939
- }
1940
- end
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
-
2008
- # massign is a parser event that is a parent node of any kind of multiple
2009
- # assignment. This includes splitting out variables on the left like:
2010
- #
2011
- # a, b, c = foo
2012
- #
2013
- # as well as splitting out variables on the right, as in:
2014
- #
2015
- # foo = a, b, c
2016
- #
2017
- # Both sides support splats, as well as variables following them. There's
2018
- # also slightly odd behavior that you can achieve with the following:
2019
- #
2020
- # a, = foo
2021
- #
2022
- # In this case a would receive only the first value of the foo enumerable,
2023
- # in which case we need to explicitly track the comma and add it onto the
2024
- # child node.
2025
- def on_massign(left, right)
2026
- left[:comma] = true if source[left[:ec]...right[:sc]].strip.start_with?(',')
2027
-
2028
- {
2029
- type: :massign,
2030
- body: [left, right],
2031
- sl: left[:sl],
2032
- sc: left[:sc],
2033
- el: right[:el],
2034
- ec: right[:ec]
2035
- }
2036
- end
2037
-
2038
- # method_add_arg is a parser event that represents a method call with
2039
- # arguments and parentheses. It accepts as arguments the method being called
2040
- # and the arg_paren event that contains the arguments to the method.
2041
- def on_method_add_arg(fcall, arg_paren)
2042
- # You can hit this if you are passing no arguments to a method that ends in
2043
- # a question mark. Because it knows it has to be a method and not a local
2044
- # variable. In that case we can just use the location information straight
2045
- # from the fcall.
2046
- if arg_paren[:type] == :args
2047
- return fcall.merge(type: :method_add_arg, body: [fcall, arg_paren])
2048
- end
2049
-
2050
- {
2051
- type: :method_add_arg,
2052
- body: [fcall, arg_paren],
2053
- sl: fcall[:sl],
2054
- sc: fcall[:sc],
2055
- el: arg_paren[:el],
2056
- ec: arg_paren[:ec]
2057
- }
2058
- end
2059
-
2060
- # method_add_block is a parser event that represents a method call with a
2061
- # block argument. It accepts as arguments the method being called and the
2062
- # block event.
2063
- def on_method_add_block(method_add_arg, block)
2064
- {
2065
- type: :method_add_block,
2066
- body: [method_add_arg, block],
2067
- sl: method_add_arg[:sl],
2068
- sc: method_add_arg[:sc],
2069
- el: block[:el],
2070
- ec: block[:ec]
2071
- }
2072
- end
2073
-
2074
- # An mlhs_new is a parser event that represents the beginning of the left
2075
- # side of a multiple assignment. It is followed by any number of mlhs_add
2076
- # nodes that each represent another variable being assigned.
2077
- def on_mlhs_new
2078
- {
2079
- type: :mlhs,
2080
- body: [],
2081
- sl: lineno,
2082
- sc: char_pos,
2083
- el: lineno,
2084
- ec: char_pos
2085
- }
2086
- end
2087
-
2088
- # An mlhs_add is a parser event that represents adding another variable
2089
- # onto a list of assignments. It accepts as arguments the parent mlhs node
2090
- # as well as the part that is being added to the list.
2091
- def on_mlhs_add(mlhs, part)
2092
- if mlhs[:body].empty?
2093
- part.merge(type: :mlhs, body: [part])
2094
- else
2095
- mlhs.merge!(body: mlhs[:body] << part, el: part[:el], ec: part[:ec])
2096
- end
2097
- end
2098
-
2099
- # An mlhs_add_post is a parser event that represents adding another set of
2100
- # variables onto a list of assignments after a splat variable. It accepts
2101
- # as arguments the previous mlhs_add_star node that represented the splat
2102
- # as well another mlhs node that represents all of the variables after the
2103
- # splat.
2104
- def on_mlhs_add_post(mlhs_add_star, mlhs)
2105
- mlhs_add_star.merge(
2106
- type: :mlhs_add_post,
2107
- body: [mlhs_add_star, mlhs],
2108
- el: mlhs[:el],
2109
- ec: mlhs[:ec]
2110
- )
2111
- end
2112
-
2113
- # An mlhs_add_star is a parser event that represents a splatted variable
2114
- # inside of a multiple assignment on the left hand side. It accepts as
2115
- # arguments the parent mlhs node as well as the part that represents the
2116
- # splatted variable.
2117
- def on_mlhs_add_star(mlhs, part)
2118
- beging = find_scanner_event(:@op, '*')
2119
- ending = part || beging
2120
-
2121
- {
2122
- type: :mlhs_add_star,
2123
- body: [mlhs, part],
2124
- sl: beging[:sl],
2125
- sc: beging[:sc],
2126
- el: ending[:el],
2127
- ec: ending[:ec]
2128
- }
2129
- end
2130
-
2131
- # An mlhs_paren is a parser event that represents parentheses being used
2132
- # to deconstruct values in a multiple assignment on the left hand side. It
2133
- # accepts as arguments the contents of the inside of the parentheses,
2134
- # which is another mlhs node.
2135
- def on_mlhs_paren(contents)
2136
- beging = find_scanner_event(:@lparen)
2137
- ending = find_scanner_event(:@rparen)
2138
-
2139
- if source[beging[:ec]...ending[:sc]].strip.end_with?(',')
2140
- contents[:comma] = true
2141
- end
2142
-
2143
- {
2144
- type: :mlhs_paren,
2145
- body: [contents],
2146
- sl: beging[:sl],
2147
- sc: beging[:sc],
2148
- el: ending[:el],
2149
- ec: ending[:ec]
2150
- }
2151
- end
2152
-
2153
- # module is a parser event that represents defining a module. It accepts
2154
- # as arguments the name of the module and the bodystmt event that
2155
- # represents the statements evaluated within the context of the module.
2156
- def on_module(const, bodystmt)
2157
- beging = find_scanner_event(:@kw, 'module')
2158
- ending = find_scanner_event(:@kw, 'end')
2159
-
2160
- bodystmt.bind(find_next_statement_start(const[:ec]), ending[:sc])
2161
-
2162
- {
2163
- type: :module,
2164
- body: [const, bodystmt],
2165
- sl: beging[:sl],
2166
- sc: beging[:sc],
2167
- el: ending[:el],
2168
- ec: ending[:ec]
2169
- }
2170
- end
2171
-
2172
- # An mrhs_new is a parser event that represents the beginning of a list of
2173
- # values that are being assigned within a multiple assignment node. It can
2174
- # be followed by any number of mrhs_add nodes that we'll build up into an
2175
- # array body.
2176
- def on_mrhs_new
2177
- {
2178
- type: :mrhs,
2179
- body: [],
2180
- sl: lineno,
2181
- sc: char_pos,
2182
- el: lineno,
2183
- ec: char_pos
2184
- }
2185
- end
2186
-
2187
- # An mrhs_add is a parser event that represents adding another value onto
2188
- # a list on the right hand side of a multiple assignment.
2189
- def on_mrhs_add(mrhs, part)
2190
- if mrhs[:body].empty?
2191
- part.merge(type: :mrhs, body: [part])
2192
- else
2193
- mrhs.merge!(body: mrhs[:body] << part, el: part[:el], ec: part[:ec])
2194
- end
2195
- end
2196
-
2197
- # An mrhs_add_star is a parser event that represents using the splat
2198
- # operator to expand out a value on the right hand side of a multiple
2199
- # assignment.
2200
- def on_mrhs_add_star(mrhs, part)
2201
- beging = find_scanner_event(:@op, '*')
2202
- ending = part || beging
2203
-
2204
- {
2205
- type: :mrhs_add_star,
2206
- body: [mrhs, part],
2207
- sl: beging[:sl],
2208
- sc: beging[:sc],
2209
- el: ending[:el],
2210
- ec: ending[:ec]
2211
- }
2212
- end
2213
-
2214
- # An mrhs_new_from_args is a parser event that represents the shorthand
2215
- # of a multiple assignment that allows you to assign values using just
2216
- # commas as opposed to assigning from an array. For example, in the
2217
- # following segment the right hand side of the assignment would trigger
2218
- # this event:
2219
- #
2220
- # foo = 1, 2, 3
2221
- #
2222
- def on_mrhs_new_from_args(args)
2223
- args.merge(type: :mrhs_new_from_args, body: [args])
2224
- end
2225
-
2226
- # next is a parser event that represents using the next keyword. It
2227
- # accepts as an argument an args or args_add_block event that contains all
2228
- # of the arguments being passed to the next.
2229
- def on_next(args_add_block)
2230
- find_scanner_event(:@kw, 'next').merge!(
2231
- type: :next,
2232
- body: [args_add_block],
2233
- el: args_add_block[:el],
2234
- ec: args_add_block[:ec]
2235
- )
2236
- end
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
-
2284
- # opassign is a parser event that represents assigning something to a
2285
- # variable or constant using an operator like += or ||=. It accepts as
2286
- # arguments the left side of the expression before the operator, the
2287
- # operator itself, and the right side of the expression.
2288
- def on_opassign(left, oper, right)
2289
- left.merge(
2290
- type: :opassign,
2291
- body: [left, oper, right],
2292
- el: right[:el],
2293
- ec: right[:ec]
2294
- )
2295
- end
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
-
2311
- # params is a parser event that represents defining parameters on a
2312
- # method. They have a somewhat interesting structure in that they are an
2313
- # array of arrays where the position in the top-level array indicates the
2314
- # type of param and the subarray is the list of parameters of that type.
2315
- # We therefore have to flatten them down to get to the location.
2316
- def on_params(*types)
2317
- flattened = types.flatten(2).select { |type| type.is_a?(Hash) }
2318
- location =
2319
- if flattened.any?
2320
- {
2321
- sl: flattened[0][:sl],
2322
- sc: flattened[0][:sc],
2323
- el: flattened[-1][:el],
2324
- ec: flattened[-1][:ec]
2325
- }
2326
- else
2327
- { sl: lineno, sc: char_pos, el: lineno, ec: char_pos }
2328
- end
2329
-
2330
- location.merge!(type: :params, body: types)
2331
- end
2332
-
2333
- # A paren is a parser event that represents using parentheses pretty much
2334
- # anywhere in a Ruby program. It accepts as arguments the contents, which
2335
- # can be either params or statements.
2336
- def on_paren(contents)
2337
- lparen = find_scanner_event(:@lparen)
2338
- rparen = find_scanner_event(:@rparen)
2339
-
2340
- if contents && contents[:type] == :params
2341
- contents.merge!(
2342
- sc: find_next_statement_start(lparen[:ec]),
2343
- ec: rparen[:sc]
2344
- )
2345
- end
2346
-
2347
- {
2348
- type: :paren,
2349
- lparen: lparen,
2350
- body: [contents],
2351
- sl: lparen[:sl],
2352
- sc: lparen[:sc],
2353
- el: rparen[:el],
2354
- ec: rparen[:ec]
2355
- }
2356
- end
2357
-
2358
- # If we encounter a parse error, just immediately bail out so that our runner
2359
- # can catch it.
2360
- def on_parse_error(error, *)
2361
- raise ParserError.new(error, lineno, column)
2362
- end
2363
- alias on_alias_error on_parse_error
2364
- alias on_assign_error on_parse_error
2365
- alias on_class_name_error on_parse_error
2366
- alias on_param_error on_parse_error
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
-
2384
- # The program node is the very top of the AST. Here we'll attach all of
2385
- # the comments that we've gathered up over the course of parsing the
2386
- # source string. We'll also attach on the __END__ content if there was
2387
- # some found at the end of the source string.
2388
- def on_program(stmts)
2389
- range = { sl: 1, el: lines.length, sc: 0, ec: source.length }
2390
-
2391
- stmts[:body] << @__end__ if @__end__
2392
- stmts.bind(0, source.length)
2393
-
2394
- range.merge(type: :program, body: [stmts], comments: @comments)
2395
- end
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
-
2420
- # qsymbols_new is a parser event that represents the beginning of a symbol
2421
- # literal array, like %i[one two three]. It can be followed by any number
2422
- # of qsymbols_add events, which we'll append onto an array body.
2423
- def on_qsymbols_new
2424
- find_scanner_event(:@qsymbols_beg).merge!(type: :qsymbols, body: [])
2425
- end
2426
-
2427
- # qsymbols_add is a parser event that represents an element inside of a
2428
- # symbol literal array like %i[one two three]. It accepts as arguments the
2429
- # parent qsymbols node as well as a tstring_content scanner event
2430
- # representing the bare words.
2431
- def on_qsymbols_add(qsymbols, tstring_content)
2432
- qsymbols.merge!(
2433
- body: qsymbols[:body] << tstring_content,
2434
- el: tstring_content[:el],
2435
- ec: tstring_content[:ec]
2436
- )
2437
- end
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
-
2462
- # qwords_new is a parser event that represents the beginning of a string
2463
- # literal array, like %w[one two three]. It can be followed by any number
2464
- # of qwords_add events, which we'll append onto an array body.
2465
- def on_qwords_new
2466
- find_scanner_event(:@qwords_beg).merge!(type: :qwords, body: [])
2467
- end
2468
-
2469
- # qsymbols_add is a parser event that represents an element inside of a
2470
- # symbol literal array like %i[one two three]. It accepts as arguments the
2471
- # parent qsymbols node as well as a tstring_content scanner event
2472
- # representing the bare words.
2473
- def on_qwords_add(qwords, tstring_content)
2474
- qwords.merge!(
2475
- body: qwords[:body] << tstring_content,
2476
- el: tstring_content[:el],
2477
- ec: tstring_content[:ec]
2478
- )
2479
- end
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
-
2537
- # redo is a parser event that represents the bare redo keyword. It has no
2538
- # body as it accepts no arguments.
2539
- def on_redo
2540
- find_scanner_event(:@kw, 'redo').merge!(type: :redo)
2541
- end
2542
-
2543
- # regexp_add is a parser event that represents a piece of a regular expression
2544
- # body. It accepts as arguments the parent regexp node as well as a
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.
2548
- def on_regexp_add(regexp, piece)
2549
- regexp.merge!(
2550
- body: regexp[:body] << piece,
2551
- el: regexp[:el],
2552
- ec: regexp[:ec]
2553
- )
2554
- end
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
-
2593
- # regexp_literal is a parser event that represents a regular expression.
2594
- # It accepts as arguments a regexp node which is a built-up array of
2595
- # pieces that go into the regexp content, as well as the ending used to
2596
- # close out the regexp which includes any modifiers.
2597
- def on_regexp_literal(regexp, ending)
2598
- regexp.merge!(
2599
- type: :regexp_literal,
2600
- ending: ending[:body],
2601
- el: ending[:el],
2602
- ec: ending[:ec]
2603
- )
2604
- end
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
-
2614
- # rescue is a special kind of node where you have a rescue chain but it
2615
- # doesn't really have all of the information that it needs in order to
2616
- # determine its ending. Therefore it relies on its parent bodystmt node to
2617
- # report its ending to it.
2618
- class Rescue < Node
2619
- def bind_end(ec)
2620
- value.merge!(ec: ec)
2621
-
2622
- stmts = value[:body][1]
2623
- consequent = value[:body][2]
2624
-
2625
- if consequent
2626
- consequent.bind_end(ec)
2627
- stmts.bind_end(consequent[:sc])
2628
- else
2629
- stmts.bind_end(ec)
2630
- end
2631
- end
2632
- end
2633
-
2634
- # rescue is a parser event that represents the use of the rescue keyword
2635
- # inside of a bodystmt.
2636
- def on_rescue(exceptions, variable, stmts, consequent)
2637
- beging = find_scanner_event(:@kw, 'rescue')
2638
- exceptions = exceptions[0] if exceptions.is_a?(Array)
2639
-
2640
- last_node = variable || exceptions || beging
2641
- stmts.bind(find_next_statement_start(last_node[:ec]), char_pos)
2642
-
2643
- # We add an additional inner node here that ripper doesn't provide so that
2644
- # we have a nice place to attach inline comment. But we only need it if we
2645
- # have an exception or a variable that we're rescuing.
2646
- rescue_ex =
2647
- if exceptions || variable
2648
- {
2649
- type: :rescue_ex,
2650
- body: [exceptions, variable],
2651
- sl: beging[:sl],
2652
- sc: beging[:ec] + 1,
2653
- el: last_node[:el],
2654
- ec: last_node[:ec]
2655
- }
2656
- end
2657
-
2658
- Rescue.new(
2659
- self,
2660
- beging.merge!(
2661
- type: :rescue,
2662
- body: [rescue_ex, stmts, consequent],
2663
- el: lineno,
2664
- ec: char_pos
2665
- )
2666
- )
2667
- end
2668
-
2669
- # rescue_mod represents the modifier form of a rescue clause. It accepts as
2670
- # arguments the statement that may raise an error and the value that should
2671
- # be used if it does.
2672
- def on_rescue_mod(statement, rescued)
2673
- find_scanner_event(:@kw, 'rescue')
2674
-
2675
- {
2676
- type: :rescue_mod,
2677
- body: [statement, rescued],
2678
- sl: statement[:sl],
2679
- sc: statement[:sc],
2680
- el: rescued[:el],
2681
- ec: rescued[:ec]
2682
- }
2683
- end
2684
-
2685
- # rest_param is a parser event that represents defining a parameter in a
2686
- # method definition that accepts all remaining positional parameters. It
2687
- # accepts as an argument an optional identifier for the parameter. If it
2688
- # is omitted, then we're just using the plain operator.
2689
- def on_rest_param(ident)
2690
- oper = find_scanner_event(:@op, '*')
2691
- return oper.merge!(type: :rest_param, body: [nil]) unless ident
2692
-
2693
- oper.merge!(
2694
- type: :rest_param,
2695
- body: [ident],
2696
- el: ident[:el],
2697
- ec: ident[:ec]
2698
- )
2699
- end
2700
-
2701
- # retry is a parser event that represents the bare retry keyword. It has
2702
- # no body as it accepts no arguments.
2703
- def on_retry
2704
- find_scanner_event(:@kw, 'retry').merge!(type: :retry)
2705
- end
2706
-
2707
- # return is a parser event that represents using the return keyword with
2708
- # arguments. It accepts as an argument an args_add_block event that
2709
- # contains all of the arguments being passed.
2710
- def on_return(args_add_block)
2711
- find_scanner_event(:@kw, 'return').merge!(
2712
- type: :return,
2713
- body: [args_add_block],
2714
- el: args_add_block[:el],
2715
- ec: args_add_block[:ec]
2716
- )
2717
- end
2718
-
2719
- # return0 is a parser event that represents the bare return keyword. It
2720
- # has no body as it accepts no arguments. This is as opposed to the return
2721
- # parser event, which is the version where you're returning one or more
2722
- # values.
2723
- def on_return0
2724
- find_scanner_event(:@kw, 'return').merge!(type: :return0)
2725
- end
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
-
2746
- # sclass is a parser event that represents a block of statements that
2747
- # should be evaluated within the context of the singleton class of an
2748
- # object. It's frequently used to define singleton methods. It looks like
2749
- # the following example:
2750
- #
2751
- # class << self do foo end
2752
- # │ │
2753
- # │ └> bodystmt
2754
- # └> target
2755
- #
2756
- def on_sclass(target, bodystmt)
2757
- beging = find_scanner_event(:@kw, 'class')
2758
- ending = find_scanner_event(:@kw, 'end')
2759
-
2760
- bodystmt.bind(find_next_statement_start(target[:ec]), ending[:sc])
2761
-
2762
- {
2763
- type: :sclass,
2764
- body: [target, bodystmt],
2765
- sl: beging[:sl],
2766
- sc: beging[:sc],
2767
- el: ending[:el],
2768
- ec: ending[:ec]
2769
- }
2770
- end
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
-
2797
- # Everything that has a block of code inside of it has a list of statements.
2798
- # Normally we would just track those as a node that has an array body, but we
2799
- # have some special handling in order to handle empty statement lists. They
2800
- # need to have the right location information, so all of the parent node of
2801
- # stmts nodes will report back down the location information. We then
2802
- # propagate that onto void_stmt nodes inside the stmts in order to make sure
2803
- # all comments get printed appropriately.
2804
- class Stmts < Node
2805
- def bind(sc, ec)
2806
- value.merge!(sc: sc, ec: ec)
2807
-
2808
- if value[:body][0][:type] == :void_stmt
2809
- value[:body][0].merge!(sc: sc, ec: sc)
2810
- end
2811
-
2812
- attach_comments(sc, ec)
2813
- end
2814
-
2815
- def bind_end(ec)
2816
- value.merge!(ec: ec)
2817
- end
2818
-
2819
- def <<(statement)
2820
- if value[:body].any?
2821
- value.merge!(statement.slice(:el, :ec))
2822
- else
2823
- value.merge!(statement.slice(:sl, :el, :sc, :ec))
2824
- end
2825
-
2826
- value[:body] << statement
2827
- self
2828
- end
2829
-
2830
- private
2831
-
2832
- def attach_comments(sc, ec)
2833
- attachable =
2834
- parser.comments.select do |comment|
2835
- comment[:type] == :@comment && !comment[:inline] &&
2836
- sc <= comment[:sc] && ec >= comment[:ec] &&
2837
- !comment[:value].include?('prettier-ignore')
2838
- end
2839
-
2840
- return if attachable.empty?
2841
-
2842
- parser.comments -= attachable
2843
- value[:body] = (value[:body] + attachable).sort_by! { |node| node[:sc] }
2844
- end
2845
- end
2846
-
2847
- # stmts_new is a parser event that represents the beginning of a list of
2848
- # statements within any lexical block. It can be followed by any number of
2849
- # stmts_add events, which we'll append onto an array body.
2850
- def on_stmts_new
2851
- Stmts.new(
2852
- self,
2853
- type: :stmts,
2854
- body: [],
2855
- sl: lineno,
2856
- el: lineno,
2857
- sc: char_pos,
2858
- ec: char_pos
2859
- )
2860
- end
2861
-
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])
2868
- end
2869
-
2870
- # string_concat is a parser event that represents concatenating two
2871
- # strings together using a backward slash, as in the following example:
2872
- #
2873
- # 'foo' \
2874
- # 'bar'
2875
- #
2876
- def on_string_concat(left, right)
2877
- {
2878
- type: :string_concat,
2879
- body: [left, right],
2880
- sl: left[:sl],
2881
- sc: left[:sc],
2882
- el: right[:el],
2883
- ec: right[:ec]
2884
- }
2885
- end
2886
-
2887
- # string_content is a parser event that represents the beginning of the
2888
- # contents of a string, which will either be embedded inside of a
2889
- # string_literal or a dyna_symbol node. It will have an array body so that
2890
- # we can build up a list of @tstring_content, string_embexpr, and
2891
- # string_dvar nodes.
2892
- def on_string_content
2893
- {
2894
- type: :string,
2895
- body: [],
2896
- sl: lineno,
2897
- el: lineno,
2898
- sc: char_pos,
2899
- ec: char_pos
2900
- }
2901
- end
2902
-
2903
- # string_dvar is a parser event that represents a very special kind of
2904
- # interpolation into string. It allows you to take an instance variable,
2905
- # class variable, or global variable and omit the braces when
2906
- # interpolating. For example, if you wanted to interpolate the instance
2907
- # variable @foo into a string, you could do "#@foo".
2908
- def on_string_dvar(var_ref)
2909
- find_scanner_event(:@embvar).merge!(
2910
- type: :string_dvar,
2911
- body: [var_ref],
2912
- el: var_ref[:el],
2913
- ec: var_ref[:ec]
2914
- )
2915
- end
2916
-
2917
- # string_embexpr is a parser event that represents interpolated content.
2918
- # It can go a bunch of different parent nodes, including regexp, strings,
2919
- # xstrings, heredocs, dyna_symbols, etc. Basically it's anywhere you see
2920
- # the #{} construct.
2921
- def on_string_embexpr(stmts)
2922
- beging = find_scanner_event(:@embexpr_beg)
2923
- ending = find_scanner_event(:@embexpr_end)
2924
-
2925
- stmts.bind(beging[:ec], ending[:sc])
2926
-
2927
- {
2928
- type: :string_embexpr,
2929
- body: [stmts],
2930
- sl: beging[:sl],
2931
- sc: beging[:sc],
2932
- el: ending[:el],
2933
- ec: ending[:ec]
2934
- }
2935
- end
2936
-
2937
- # String literals are either going to be a normal string or they're going
2938
- # to be a heredoc if we've just closed a heredoc.
2939
- def on_string_literal(string)
2940
- heredoc = @heredocs[-1]
2941
-
2942
- if heredoc && heredoc[:ending]
2943
- @heredocs.pop.merge!(body: string[:body])
2944
- else
2945
- beging = find_scanner_event(:@tstring_beg)
2946
- ending = find_scanner_event(:@tstring_end)
2947
-
2948
- {
2949
- type: :string_literal,
2950
- body: string[:body],
2951
- quote: beging[:body],
2952
- sl: beging[:sl],
2953
- sc: beging[:sc],
2954
- el: ending[:el],
2955
- ec: ending[:ec]
2956
- }
2957
- end
2958
- end
2959
-
2960
- # A super is a parser event that represents using the super keyword with
2961
- # any number of arguments. It can optionally use parentheses (represented
2962
- # by an arg_paren node) or just skip straight to the arguments (with an
2963
- # args_add_block node).
2964
- def on_super(contents)
2965
- find_scanner_event(:@kw, 'super').merge!(
2966
- type: :super,
2967
- body: [contents],
2968
- el: contents[:el],
2969
- ec: contents[:ec]
2970
- )
2971
- end
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
-
2993
- # A symbol is a parser event that immediately descends from a symbol
2994
- # literal and contains an ident representing the contents of the symbol.
2995
- def on_symbol(ident)
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" }.
3000
- #
3001
- # In order to take care of this, we explicitly delete this scanner event
3002
- # from the stack to make sure it doesn't screw things up.
3003
- scanner_events.pop
3004
-
3005
- ident.merge(type: :symbol, body: [ident])
3006
- end
3007
-
3008
- # A symbol_literal represents a symbol in the system with no interpolation
3009
- # (as opposed to a dyna_symbol). As its only argument it accepts either a
3010
- # symbol node (for most cases) or an ident node (in the case that we're
3011
- # using bare words, as in an alias node like alias foo bar).
3012
- def on_symbol_literal(contents)
3013
- if scanner_events[-1] == contents
3014
- contents.merge(type: :symbol_literal, body: [contents])
3015
- else
3016
- beging = find_scanner_event(:@symbeg)
3017
- contents.merge!(type: :symbol_literal, sc: beging[:sc])
3018
- end
3019
- end
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
-
3044
- # symbols_new is a parser event that represents the beginning of a symbol
3045
- # literal array that accepts interpolation, like %I[one #{two} three]. It
3046
- # can be followed by any number of symbols_add events, which we'll append
3047
- # onto an array body.
3048
- def on_symbols_new
3049
- find_scanner_event(:@symbols_beg).merge!(type: :symbols, body: [])
3050
- end
3051
-
3052
- # symbols_add is a parser event that represents an element inside of a
3053
- # symbol literal array that accepts interpolation, like
3054
- # %I[one #{two} three]. It accepts as arguments the parent symbols node as
3055
- # well as a word_add parser event.
3056
- def on_symbols_add(symbols, word_add)
3057
- symbols.merge!(
3058
- body: symbols[:body] << word_add,
3059
- el: word_add[:el],
3060
- ec: word_add[:ec]
3061
- )
3062
- end
3063
-
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
3069
-
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
3100
- end
3101
-
3102
- # A top_const_field is a parser event that is always the child of some
3103
- # kind of assignment. It represents when you're assigning to a constant
3104
- # that is being referenced at the top level. For example:
3105
- #
3106
- # ::X = 1
3107
- #
3108
- def on_top_const_field(const)
3109
- beging = find_colon2_before(const)
3110
- const.merge(
3111
- type: :top_const_field,
3112
- body: [const],
3113
- sl: beging[:sl],
3114
- sc: beging[:sc]
3115
- )
3116
- end
3117
-
3118
- # A top_const_ref is a parser event that is a very similar to
3119
- # top_const_field except that it is not involved in an assignment. It
3120
- # looks like the following example:
3121
- #
3122
- # ::X
3123
- #
3124
- def on_top_const_ref(const)
3125
- beging = find_colon2_before(const)
3126
- const.merge(
3127
- type: :top_const_ref,
3128
- body: [const],
3129
- sl: beging[:sl],
3130
- sc: beging[:sc]
3131
- )
3132
- end
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
-
3191
- # A unary node represents a unary method being called on an expression, as
3192
- # in !, ~, or not. We have somewhat special handling of the not operator
3193
- # since if it has parentheses they don't get reported as a paren node for
3194
- # some reason.
3195
- def on_unary(oper, value)
3196
- if oper == :not
3197
- node = find_scanner_event(:@kw, 'not')
3198
-
3199
- paren = source[node[:ec]...value[:sc]].include?('(')
3200
- ending = paren ? find_scanner_event(:@rparen) : value
3201
-
3202
- node.merge!(
3203
- type: :unary,
3204
- oper: oper,
3205
- body: [value],
3206
- el: ending[:el],
3207
- ec: ending[:ec],
3208
- paren: paren
3209
- )
3210
- else
3211
- # Special case instead of using find_scanner_event here. It turns out that
3212
- # if you have a range that goes from a negative number to a negative
3213
- # number then you can end up with a .. or a ... that's higher in the
3214
- # stack. So we need to explicitly disallow those operators.
3215
- index =
3216
- scanner_events.rindex do |scanner_event|
3217
- scanner_event[:type] == :@op && scanner_event[:sc] < value[:sc] &&
3218
- !%w[.. ...].include?(scanner_event[:body])
3219
- end
3220
-
3221
- beging = scanner_events.delete_at(index)
3222
- beging.merge!(
3223
- type: :unary,
3224
- oper: oper[0],
3225
- body: [value],
3226
- el: value[:el],
3227
- ec: value[:ec]
3228
- )
3229
- end
3230
- end
3231
-
3232
- # undef nodes represent using the keyword undef. It accepts as an argument
3233
- # an array of symbol_literal nodes that represent each message that the
3234
- # user is attempting to undefine. We use the keyword to get the beginning
3235
- # location and the last symbol to get the ending.
3236
- def on_undef(symbol_literals)
3237
- last = symbol_literals.last
3238
-
3239
- find_scanner_event(:@kw, 'undef').merge!(
3240
- type: :undef,
3241
- body: symbol_literals,
3242
- el: last[:el],
3243
- ec: last[:ec]
3244
- )
3245
- end
3246
-
3247
- # unless is a parser event that represents the first clause in an unless
3248
- # chain. It accepts as arguments the predicate of the unless, the
3249
- # statements that are contained within the unless clause, and the optional
3250
- # consequent clause.
3251
- def on_unless(predicate, stmts, consequent)
3252
- beging = find_scanner_event(:@kw, 'unless')
3253
- ending = consequent || find_scanner_event(:@kw, 'end')
3254
-
3255
- stmts.bind(predicate[:ec], ending[:sc])
3256
-
3257
- {
3258
- type: :unless,
3259
- body: [predicate, stmts, consequent],
3260
- sl: beging[:sl],
3261
- sc: beging[:sc],
3262
- el: ending[:el],
3263
- ec: ending[:ec]
3264
- }
3265
- end
3266
-
3267
- # unless_mod is a parser event that represents the modifier form of an
3268
- # unless statement. It accepts as arguments the predicate of the unless
3269
- # and the statement that are contained within the unless clause.
3270
- def on_unless_mod(predicate, statement)
3271
- find_scanner_event(:@kw, 'unless')
3272
-
3273
- {
3274
- type: :unless_mod,
3275
- body: [predicate, statement],
3276
- sl: statement[:sl],
3277
- sc: statement[:sc],
3278
- el: predicate[:el],
3279
- ec: predicate[:ec]
3280
- }
3281
- end
3282
-
3283
- # until is a parser event that represents an until loop. It accepts as
3284
- # arguments the predicate to the until and the statements that are
3285
- # contained within the until clause.
3286
- def on_until(predicate, stmts)
3287
- beging = find_scanner_event(:@kw, 'until')
3288
- ending = find_scanner_event(:@kw, 'end')
3289
-
3290
- # Consume the do keyword if it exists so that it doesn't get confused for
3291
- # some other block
3292
- do_event = find_scanner_event(:@kw, 'do', consume: false)
3293
- if do_event && do_event[:sc] > predicate[:ec] && do_event[:ec] < ending[:sc]
3294
- scanner_events.delete(do_event)
3295
- end
3296
-
3297
- stmts.bind(predicate[:ec], ending[:sc])
3298
-
3299
- {
3300
- type: :until,
3301
- body: [predicate, stmts],
3302
- sl: beging[:sl],
3303
- sc: beging[:sc],
3304
- el: ending[:el],
3305
- ec: ending[:ec]
3306
- }
3307
- end
3308
-
3309
- # until_mod is a parser event that represents the modifier form of an
3310
- # until loop. It accepts as arguments the predicate to the until and the
3311
- # statement that is contained within the until loop.
3312
- def on_until_mod(predicate, statement)
3313
- find_scanner_event(:@kw, 'until')
3314
-
3315
- {
3316
- type: :until_mod,
3317
- body: [predicate, statement],
3318
- sl: statement[:sl],
3319
- sc: statement[:sc],
3320
- el: predicate[:el],
3321
- ec: predicate[:ec]
3322
- }
3323
- end
3324
-
3325
- # var_alias is a parser event that represents when you're using the alias
3326
- # keyword with global variable arguments. You can optionally use
3327
- # parentheses with this keyword, so we either track the location
3328
- # information based on those or the final argument to the alias method.
3329
- def on_var_alias(left, right)
3330
- beging = find_scanner_event(:@kw, 'alias')
3331
-
3332
- paren = source[beging[:ec]...left[:sc]].include?('(')
3333
- ending = paren ? find_scanner_event(:@rparen) : right
3334
-
3335
- {
3336
- type: :var_alias,
3337
- body: [left, right],
3338
- sl: beging[:sl],
3339
- sc: beging[:sc],
3340
- el: ending[:el],
3341
- ec: ending[:ec]
3342
- }
3343
- end
3344
-
3345
- # var_ref is a parser event that represents using either a local variable,
3346
- # a nil literal, a true or false literal, or a numbered block variable.
3347
- def on_var_ref(contents)
3348
- contents.merge(type: :var_ref, body: [contents])
3349
- end
3350
-
3351
- # var_field is a parser event that represents a variable that is being
3352
- # assigned a value. As such, it is always a child of an assignment type
3353
- # node. For example, in the following example foo is a var_field:
3354
- #
3355
- # foo = 1
3356
- #
3357
- def on_var_field(ident)
3358
- if ident
3359
- ident.merge(type: :var_field, body: [ident])
3360
- else
3361
- # You can hit this pattern if you're assigning to a splat using pattern
3362
- # matching syntax in Ruby 2.7+
3363
- { type: :var_field, body: nil }
3364
- end
3365
- end
3366
-
3367
- # vcall nodes are any plain named thing with Ruby that could be either a
3368
- # local variable or a method call. They accept as an argument the ident
3369
- # scanner event that contains their content.
3370
- #
3371
- # Access controls like private, protected, and public are reported as
3372
- # vcall nodes since they're technically method calls. We want to be able
3373
- # add new lines around them as necessary, so here we're going to
3374
- # explicitly track those as a different node type.
3375
- def on_vcall(ident)
3376
- @controls ||= %w[private protected public].freeze
3377
-
3378
- body = ident[:body]
3379
- type =
3380
- if @controls.include?(body) && body == lines[lineno - 1].strip
3381
- :access_ctrl
3382
- else
3383
- :vcall
3384
- end
3385
-
3386
- ident.merge(type: type, body: [ident])
3387
- end
3388
-
3389
- # void_stmt is a special kind of parser event that represents an empty lexical
3390
- # block of code. It often will have comments attached to it, so it requires
3391
- # some special handling.
3392
- def on_void_stmt
3393
- { type: :void_stmt, sl: lineno, el: lineno, sc: char_pos, ec: char_pos }
3394
- end
3395
-
3396
- # when is a parser event that represents another clause in a case chain.
3397
- # It accepts as arguments the predicate of the when, the statements that
3398
- # are contained within the else if clause, and the optional consequent
3399
- # clause.
3400
- def on_when(predicate, stmts, consequent)
3401
- beging = find_scanner_event(:@kw, 'when')
3402
- ending = consequent || find_scanner_event(:@kw, 'end')
3403
-
3404
- stmts.bind(predicate[:ec], ending[:sc])
3405
-
3406
- {
3407
- type: :when,
3408
- body: [predicate, stmts, consequent],
3409
- sl: beging[:sl],
3410
- sc: beging[:sc],
3411
- el: ending[:el],
3412
- ec: ending[:ec]
3413
- }
3414
- end
3415
-
3416
- # while is a parser event that represents a while loop. It accepts as
3417
- # arguments the predicate to the while and the statements that are
3418
- # contained within the while clause.
3419
- def on_while(predicate, stmts)
3420
- beging = find_scanner_event(:@kw, 'while')
3421
- ending = find_scanner_event(:@kw, 'end')
3422
-
3423
- # Consume the do keyword if it exists so that it doesn't get confused for
3424
- # some other block
3425
- do_event = find_scanner_event(:@kw, 'do', consume: false)
3426
- if do_event && do_event[:sc] > predicate[:ec] && do_event[:ec] < ending[:sc]
3427
- scanner_events.delete(do_event)
3428
- end
3429
-
3430
- stmts.bind(predicate[:ec], ending[:sc])
3431
-
3432
- {
3433
- type: :while,
3434
- body: [predicate, stmts],
3435
- sl: beging[:sl],
3436
- sc: beging[:sc],
3437
- el: ending[:el],
3438
- ec: ending[:ec]
3439
- }
3440
- end
3441
-
3442
- # while_mod is a parser event that represents the modifier form of an
3443
- # while loop. It accepts as arguments the predicate to the while and the
3444
- # statement that is contained within the while loop.
3445
- def on_while_mod(predicate, statement)
3446
- find_scanner_event(:@kw, 'while')
3447
-
3448
- {
3449
- type: :while_mod,
3450
- body: [predicate, statement],
3451
- sl: statement[:sl],
3452
- sc: statement[:sc],
3453
- el: predicate[:el],
3454
- ec: predicate[:ec]
3455
- }
3456
- end
3457
-
3458
- # word_new is a parser event that represents the beginning of a word
3459
- # within a special array literal (either strings or symbols) that accepts
3460
- # interpolation. For example, in the following array, there are three
3461
- # word nodes:
3462
- #
3463
- # %W[one a#{two}a three]
3464
- #
3465
- # Each word inside that array is represented as its own node, which is in
3466
- # terms of the parser a tree of word_new and word_add nodes. For our
3467
- # purposes, we're going to report this as a word node and build up an
3468
- # array body of our parts.
3469
- def on_word_new
3470
- { type: :word, body: [] }
3471
- end
3472
-
3473
- # word_add is a parser event that represents a piece of a word within a
3474
- # special array literal that accepts interpolation. It accepts as
3475
- # arguments the parent word node as well as the additional piece of the
3476
- # word, which can be either a @tstring_content node for a plain string
3477
- # piece or a string_embexpr for an interpolated piece.
3478
- def on_word_add(word, piece)
3479
- if word[:body].empty?
3480
- # Here we're making sure we get the correct bounds by using the
3481
- # location information from the first piece.
3482
- piece.merge(type: :word, body: [piece])
3483
- else
3484
- word.merge!(body: word[:body] << piece, el: piece[:el], ec: piece[:ec])
3485
- end
3486
- end
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
-
3530
- # words_new is a parser event that represents the beginning of a string
3531
- # literal array that accepts interpolation, like %W[one #{two} three]. It
3532
- # can be followed by any number of words_add events, which we'll append
3533
- # onto an array body.
3534
- def on_words_new
3535
- find_scanner_event(:@words_beg).merge!(type: :words, body: [])
3536
- end
3537
-
3538
- # words_add is a parser event that represents an element inside of a
3539
- # string literal array that accepts interpolation, like
3540
- # %W[one #{two} three]. It accepts as arguments the parent words node as
3541
- # well as a word_add parser event.
3542
- def on_words_add(words, word_add)
3543
- words.merge!(
3544
- body: words[:body] << word_add,
3545
- el: word_add[:el],
3546
- ec: word_add[:ec]
3547
- )
3548
- end
3549
-
3550
- # xstring_new is a parser event that represents the beginning of a string
3551
- # of commands that gets sent out to the terminal, like `ls`. It can
3552
- # optionally include interpolation much like a regular string, so we're
3553
- # going to build up an array body.
3554
- #
3555
- # If the xstring actually starts with a heredoc declaration, then we're
3556
- # going to let heredocs continue to do their thing and instead just use
3557
- # its location information.
3558
- def on_xstring_new
3559
- heredoc = @heredocs[-1]
3560
-
3561
- if heredoc && heredoc[:beging][3] = '`'
3562
- heredoc.merge(type: :xstring, body: [])
3563
- elsif RUBY_MAJOR <= 2 && RUBY_MINOR <= 5 && RUBY_PATCH < 7
3564
- { type: :xstring, body: [] }
3565
- else
3566
- find_scanner_event(:@backtick).merge!(type: :xstring, body: [])
3567
- end
3568
- end
3569
-
3570
- # xstring_add is a parser event that represents a piece of a string of
3571
- # commands that gets sent out to the terminal, like `ls`. It accepts two
3572
- # arguments, the parent xstring node as well as the piece that is being
3573
- # added to the string. Because it supports interpolation this is either a
3574
- # tstring_content scanner event representing bare string content or a
3575
- # string_embexpr representing interpolated content.
3576
- def on_xstring_add(xstring, piece)
3577
- xstring.merge!(
3578
- body: xstring[:body] << piece,
3579
- el: piece[:el],
3580
- ec: piece[:ec]
3581
- )
3582
- end
3583
-
3584
- # xstring_literal is a parser event that represents a string of commands
3585
- # that gets sent to the terminal, like `ls`. It accepts as its only
3586
- # argument an xstring node that is a built up array representation of all
3587
- # of the parts of the string (including the plain string content and the
3588
- # interpolated content).
3589
- #
3590
- # They can also use heredocs to present themselves, as in the example:
3591
- #
3592
- # <<-`SHELL`
3593
- # ls
3594
- # SHELL
3595
- #
3596
- # In this case we need to change the node type to be a heredoc instead of
3597
- # an xstring_literal in order to get the right formatting.
3598
- def on_xstring_literal(xstring)
3599
- heredoc = @heredocs[-1]
3600
-
3601
- if heredoc && heredoc[:beging][3] = '`'
3602
- heredoc.merge!(body: xstring[:body])
3603
- else
3604
- ending = find_scanner_event(:@tstring_end)
3605
- xstring.merge!(type: :xstring_literal, el: ending[:el], ec: ending[:ec])
3606
- end
3607
- end
3608
-
3609
- # yield is a parser event that represents using the yield keyword with
3610
- # arguments. It accepts as an argument an args_add_block event that
3611
- # contains all of the arguments being passed.
3612
- def on_yield(args_add_block)
3613
- find_scanner_event(:@kw, 'yield').merge!(
3614
- type: :yield,
3615
- body: [args_add_block],
3616
- el: args_add_block[:el],
3617
- ec: args_add_block[:ec]
3618
- )
3619
- end
3620
-
3621
- # yield0 is a parser event that represents the bare yield keyword. It has
3622
- # no body as it accepts no arguments. This is as opposed to the yield
3623
- # parser event, which is the version where you're yielding one or more
3624
- # values.
3625
- def on_yield0
3626
- find_scanner_event(:@kw, 'yield').merge!(type: :yield0)
3627
- end
3628
-
3629
- # zsuper is a parser event that represents the bare super keyword. It has
3630
- # no body as it accepts no arguments. This is as opposed to the super
3631
- # parser event, which is the version where you're calling super with one
3632
- # or more values.
3633
- def on_zsuper
3634
- find_scanner_event(:@kw, 'super').merge!(type: :zsuper)
3635
- end
3636
- end