ffast 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +191 -263
- data/docs/index.md +2 -4
- data/lib/fast.rb +239 -53
- data/lib/fast/experiment.rb +164 -28
- data/lib/fast/version.rb +1 -1
- metadata +2 -2
data/docs/index.md
CHANGED
@@ -284,15 +284,13 @@ Fast.capture(code('a = 1'), '(int $_)') # => 1
|
|
284
284
|
And if I want to refactor a code and use `delegate <attribute>, to: <object>`, try with replace:
|
285
285
|
|
286
286
|
```ruby
|
287
|
-
Fast.replace ast,
|
288
|
-
'(def $_ ... (send (send nil $_) \1))',
|
289
|
-
-> (node, captures) {
|
287
|
+
Fast.replace ast, '(def $_ ... (send (send nil $_) \1))' do |node, captures|
|
290
288
|
attribute, object = captures
|
291
289
|
replace(
|
292
290
|
node.location.expression,
|
293
291
|
"delegate :#{attribute}, to: :#{object}"
|
294
292
|
)
|
295
|
-
|
293
|
+
end
|
296
294
|
```
|
297
295
|
|
298
296
|
## Fast.replace_file
|
data/lib/fast.rb
CHANGED
@@ -22,12 +22,14 @@ end
|
|
22
22
|
|
23
23
|
# Fast is a tool to help you search in the code through the Abstract Syntax Tree
|
24
24
|
module Fast
|
25
|
+
# Literals are shortcuts allowed inside {ExpressionParser}
|
25
26
|
LITERAL = {
|
26
27
|
'...' => ->(node) { node&.children&.any? },
|
27
28
|
'_' => ->(node) { !node.nil? },
|
28
29
|
'nil' => nil
|
29
30
|
}.freeze
|
30
31
|
|
32
|
+
# Allowed tokens in the node pattern domain
|
31
33
|
TOKENIZER = %r/
|
32
34
|
[\+\-\/\*\\!] # operators or negation
|
33
35
|
|
|
@@ -65,38 +67,82 @@ module Fast
|
|
65
67
|
/x.freeze
|
66
68
|
|
67
69
|
class << self
|
68
|
-
|
69
|
-
|
70
|
+
# @return [Astrolabe::Node] from the parsed content
|
71
|
+
# @example
|
72
|
+
# Fast.ast("1") # => s(:int, 1)
|
73
|
+
# Fast.ast("a.b") # => s(:send, s(:send, nil, :a), :b)
|
74
|
+
def ast(content, buffer_name: '(string)')
|
75
|
+
buffer = Parser::Source::Buffer.new(buffer_name)
|
76
|
+
buffer.source = content
|
77
|
+
Parser::CurrentRuby.new(Astrolabe::Builder.new).parse(buffer)
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return [Astrolabe::Node] parsed from file content
|
81
|
+
# caches the content based on the filename.
|
82
|
+
# @example
|
83
|
+
# Fast.ast_from_file("example.rb") # => s(...)
|
84
|
+
def ast_from_file(file)
|
85
|
+
@cache ||= {}
|
86
|
+
@cache[file] ||= ast(IO.read(file), buffer_name: file)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Verify if a given AST matches with a specific pattern
|
90
|
+
# @return [Boolean] case matches ast with the current expression
|
91
|
+
# @example
|
92
|
+
# Fast.match?(Fast.ast("1"),"int") # => true
|
93
|
+
def match?(ast, pattern, *args)
|
94
|
+
Matcher.new(ast, pattern, *args).match?
|
70
95
|
end
|
71
96
|
|
72
|
-
|
97
|
+
# Replaces content based on a pattern.
|
98
|
+
# @param &replacement gives the [Rewriter] context in the block.
|
99
|
+
# @example
|
100
|
+
# Fast.replace?(Fast.ast("a = 1"),"lvasgn") do |node|
|
101
|
+
# replace(node.location.name, 'variable_renamed')
|
102
|
+
# end # => variable_renamed = 1
|
103
|
+
# @return [String] with the new source code after apply the replacement
|
104
|
+
# @see Fast::Rewriter
|
105
|
+
def replace(ast, pattern, &replacement)
|
73
106
|
buffer = Parser::Source::Buffer.new('replacement')
|
74
107
|
buffer.source = ast.loc.expression.source
|
75
|
-
to_replace = search(ast,
|
108
|
+
to_replace = search(ast, pattern)
|
76
109
|
types = to_replace.grep(Parser::AST::Node).map(&:type).uniq
|
77
110
|
rewriter = Rewriter.new
|
78
111
|
rewriter.buffer = buffer
|
79
|
-
rewriter.search =
|
112
|
+
rewriter.search = pattern
|
80
113
|
rewriter.replacement = replacement
|
81
114
|
rewriter.affect_types(*types)
|
82
115
|
rewriter.rewrite(buffer, ast)
|
83
116
|
end
|
84
117
|
|
85
|
-
|
118
|
+
# Replaces the source of an {#ast_from_file} with
|
119
|
+
# based on a search.
|
120
|
+
# @return [String] with the content of the new file
|
121
|
+
# and the same source if the pattern does not match.
|
122
|
+
def replace_file(file, pattern, &replacement)
|
86
123
|
ast = ast_from_file(file)
|
87
|
-
replace(ast,
|
124
|
+
replace(ast, pattern, &replacement)
|
88
125
|
end
|
89
126
|
|
127
|
+
# Search with pattern directly on file
|
128
|
+
# @return Array<Astrolabe::Node> that matches the pattern
|
90
129
|
def search_file(pattern, file)
|
91
130
|
node = ast_from_file(file)
|
92
131
|
search node, pattern
|
93
132
|
end
|
94
133
|
|
134
|
+
# Capture elements from searches in files. Keep in mind you need to use `$`
|
135
|
+
# in the pattern to make it work.
|
136
|
+
# @return Array<Object> captured from the pattern matched in the file
|
95
137
|
def capture_file(pattern, file)
|
96
138
|
node = ast_from_file(file)
|
97
139
|
capture node, pattern
|
98
140
|
end
|
99
141
|
|
142
|
+
# Search recursively into a node and its children.
|
143
|
+
# If the node matches with the pattern it returns the node,
|
144
|
+
# otherwise it recursively collect possible children nodes
|
145
|
+
# @yield node and capture if block given
|
100
146
|
def search(node, pattern)
|
101
147
|
if (match = Fast.match?(node, pattern))
|
102
148
|
yield node, match if block_given?
|
@@ -108,6 +154,9 @@ module Fast
|
|
108
154
|
end
|
109
155
|
end
|
110
156
|
|
157
|
+
# Return only captures from a search
|
158
|
+
# @return Array<Object> with all captured elements.
|
159
|
+
# If the result is only a single capture, it will return the single element.
|
111
160
|
def capture(node, pattern)
|
112
161
|
res =
|
113
162
|
if (match = Fast.match?(node, pattern))
|
@@ -120,17 +169,8 @@ module Fast
|
|
120
169
|
res&.size == 1 ? res[0] : res
|
121
170
|
end
|
122
171
|
|
123
|
-
|
124
|
-
|
125
|
-
buffer.source = content
|
126
|
-
Parser::CurrentRuby.new(Astrolabe::Builder.new).parse(buffer)
|
127
|
-
end
|
128
|
-
|
129
|
-
def ast_from_file(file)
|
130
|
-
@cache ||= {}
|
131
|
-
@cache[file] ||= ast(IO.read(file), buffer_name: file)
|
132
|
-
end
|
133
|
-
|
172
|
+
# Highligh some source code based on the node.
|
173
|
+
# Useful for printing code with syntax highlight.
|
134
174
|
def highlight(node, show_sexp: false)
|
135
175
|
output =
|
136
176
|
if node.respond_to?(:loc) && !show_sexp
|
@@ -141,6 +181,13 @@ module Fast
|
|
141
181
|
CodeRay.scan(output, :ruby).term
|
142
182
|
end
|
143
183
|
|
184
|
+
# Combines {.highlight} with files printing file name in the head with the
|
185
|
+
# source line.
|
186
|
+
# @param result [Astrolabe::Node]
|
187
|
+
# @param show_sexp [Boolean] Show string expression instead of source
|
188
|
+
# @param file [String] Show the file name and result line before content
|
189
|
+
# @example
|
190
|
+
# Fast.highlight(Fast.search(...))
|
144
191
|
def report(result, show_sexp: nil, file: nil)
|
145
192
|
if file
|
146
193
|
line = result.loc.expression.line if result.is_a?(Parser::AST::Node)
|
@@ -152,8 +199,19 @@ module Fast
|
|
152
199
|
def expression(string)
|
153
200
|
ExpressionParser.new(string).parse
|
154
201
|
end
|
202
|
+
|
155
203
|
attr_accessor :debugging
|
156
204
|
|
205
|
+
# Utility function to inspect search details using debug block.
|
206
|
+
#
|
207
|
+
# It prints output of all matching cases.
|
208
|
+
#
|
209
|
+
# @example
|
210
|
+
# Fast.debug do
|
211
|
+
# Fast.match?(s(:int, 1), [:int, 1])
|
212
|
+
# end
|
213
|
+
# int == (int 1) # => true
|
214
|
+
# 1 == 1 # => true
|
157
215
|
def debug
|
158
216
|
return yield if debugging
|
159
217
|
|
@@ -169,6 +227,9 @@ module Fast
|
|
169
227
|
result
|
170
228
|
end
|
171
229
|
|
230
|
+
# @return Array<String> with all ruby files from arguments.
|
231
|
+
# @param *files can be files or directories.
|
232
|
+
# When the argument is a folder, it recursively fetches all `.rb` files from it.
|
172
233
|
def ruby_files_from(*files)
|
173
234
|
directories = files.select(&File.method(:directory?))
|
174
235
|
|
@@ -180,6 +241,15 @@ module Fast
|
|
180
241
|
files
|
181
242
|
end
|
182
243
|
|
244
|
+
# Extracts a node pattern expression from a given node supressing identifiers and primitive types.
|
245
|
+
# Useful to index abstract patterns or similar code structure.
|
246
|
+
# @see https://jonatas.github.io/fast/similarity_tutorial/
|
247
|
+
# @return [String] with an pattern to search from it.
|
248
|
+
# @param node [Astrolabe::Node]
|
249
|
+
# @example
|
250
|
+
# Fast.expression_from(Fast.ast('1')) # => '(int _)'
|
251
|
+
# Fast.expression_from(Fast.ast('a = 1')) # => '(lvasgn _ (int _))'
|
252
|
+
# Fast.expression_from(Fast.ast('def name; person.name end')) # => '(def _ (args) (send (send nil _) _))'
|
183
253
|
def expression_from(node)
|
184
254
|
case node
|
185
255
|
when Parser::AST::Node
|
@@ -195,9 +265,22 @@ module Fast
|
|
195
265
|
end
|
196
266
|
end
|
197
267
|
|
198
|
-
# Rewriter encapsulates
|
199
|
-
#
|
268
|
+
# Rewriter encapsulates {Rewriter#match_index} to allow
|
269
|
+
# {ExperimentFile.partial_replace} in a {Fast::ExperimentFile}.
|
270
|
+
# @see https://www.rubydoc.info/github/whitequark/parser/Parser/TreeRewriter
|
271
|
+
# @note the standalone class needs to combines {Rewriter#affect_types} to properly generate the `on_<node-type>` methods depending on the expression being used.
|
272
|
+
# @example Simple Rewriter
|
273
|
+
# ast = Fast.ast("a = 1")
|
274
|
+
# buffer = Parser::Source::Buffer.new('replacement')
|
275
|
+
# buffer.source = ast.loc.expression.source
|
276
|
+
# rewriter = Rewriter.new
|
277
|
+
# rewriter.buffer = buffer
|
278
|
+
# rewriter.search ='(lvasgn _ ...)'
|
279
|
+
# rewriter.replacement = -> (node) { replace(node.location.name, 'variable_renamed') }
|
280
|
+
# rewriter.affect_types(:lvasgn)
|
281
|
+
# rewriter.rewrite(buffer, ast) # => "variable_renamed = 1"
|
200
282
|
class Rewriter < Parser::TreeRewriter
|
283
|
+
# @return [Integer] with occurrence index
|
201
284
|
attr_reader :match_index
|
202
285
|
attr_accessor :buffer, :search, :replacement
|
203
286
|
def initialize(*args)
|
@@ -209,6 +292,8 @@ module Fast
|
|
209
292
|
Fast.match?(node, search)
|
210
293
|
end
|
211
294
|
|
295
|
+
# Generate methods for all affected types.
|
296
|
+
# @see Fast.replace
|
212
297
|
def affect_types(*types) # rubocop:disable Metrics/MethodLength
|
213
298
|
types.map do |type|
|
214
299
|
self.class.send :define_method, "on_#{type}" do |node|
|
@@ -227,21 +312,47 @@ module Fast
|
|
227
312
|
end
|
228
313
|
|
229
314
|
# ExpressionParser empowers the AST search in Ruby.
|
230
|
-
#
|
231
|
-
#
|
315
|
+
# All classes inheriting Fast::Find have a grammar shortcut that is processed here.
|
316
|
+
#
|
232
317
|
# Exclamation Mark to negate: `!(int _)` is equivalent to a `not integer` node.
|
233
318
|
# Curly Braces allows [Any]: `({int float} _)` or `{(int _) (float _)}`.
|
234
319
|
# Square Braquets allows [All]: [(int _) !(int 0)] # all integer less zero.
|
235
320
|
# Dollar sign can be used to capture values: `(${int float} _)` will capture the node type.
|
321
|
+
#
|
322
|
+
# @example find a simple int node
|
323
|
+
# Fast.expression("int")
|
324
|
+
# # => #<Fast::Find:0x00007ffae39274e0 @token="int">
|
325
|
+
# @example parens make the expression an array of Fast::Find and children classes
|
326
|
+
# Fast.expression("(int _)")
|
327
|
+
# # => [#<Fast::Find:0x00007ffae3a860e8 @token="int">, #<Fast::Find:0x00007ffae3a86098 @token="_">]
|
328
|
+
# @example not int token
|
329
|
+
# Fast.expression("!int")
|
330
|
+
# # => #<Fast::Not:0x00007ffae43f35b8 @token=#<Fast::Find:0x00007ffae43f35e0 @token="int">>
|
331
|
+
# @example int or float token
|
332
|
+
# Fast.expression("{int float}")
|
333
|
+
# # => #<Fast::Any:0x00007ffae43bbf00 @token=[
|
334
|
+
# # #<Fast::Find:0x00007ffae43bbfa0 @token="int">,
|
335
|
+
# # #<Fast::Find:0x00007ffae43bbf50 @token="float">
|
336
|
+
# # #]>
|
337
|
+
# @example capture something not nil
|
338
|
+
# Fast.expression("$_")
|
339
|
+
# # => #<Fast::Capture:0x00007ffae433a860 @captures=[], @token=#<Fast::Find:0x00007ffae433a888 @token="_">>
|
340
|
+
# @example capture a hash with keys that all are not string and not symbols
|
341
|
+
# Fast.expression("(hash (pair ([!sym !str] _))")
|
342
|
+
# # => [#<Fast::Find:0x00007ffae3b45010 @token="hash">,
|
343
|
+
# # [#<Fast::Find:0x00007ffae3b44f70 @token="pair">,
|
344
|
+
# # [#<Fast::All:0x00007ffae3b44cf0 @token=[
|
345
|
+
# # #<Fast::Not:0x00007ffae3b44e30 @token=#<Fast::Find:0x00007ffae3b44e80 @token="sym">>,
|
346
|
+
# # #<Fast::Not:0x00007ffae3b44d40 @token=#<Fast::Find:0x00007ffae3b44d68 @token="str">>]>,
|
347
|
+
# # #<Fast::Find:0x00007ffae3b44ca0 @token="_">]]]")")
|
348
|
+
# @example of match using string expression
|
349
|
+
# Fast.match?(Fast.ast("{1 => 1}"),"(hash (pair ([!sym !str] _))") => true")")
|
236
350
|
class ExpressionParser
|
351
|
+
# @param expression [String]
|
237
352
|
def initialize(expression)
|
238
353
|
@tokens = expression.scan TOKENIZER
|
239
354
|
end
|
240
355
|
|
241
|
-
def next_token
|
242
|
-
@tokens.shift
|
243
|
-
end
|
244
|
-
|
245
356
|
# rubocop:disable Metrics/CyclomaticComplexity
|
246
357
|
# rubocop:disable Metrics/AbcSize
|
247
358
|
# rubocop:disable Metrics/MethodLength
|
@@ -262,10 +373,17 @@ module Fast
|
|
262
373
|
else Find.new(token)
|
263
374
|
end
|
264
375
|
end
|
376
|
+
|
265
377
|
# rubocop:enable Metrics/CyclomaticComplexity
|
266
378
|
# rubocop:enable Metrics/AbcSize
|
267
379
|
# rubocop:enable Metrics/MethodLength
|
268
380
|
|
381
|
+
private
|
382
|
+
|
383
|
+
def next_token
|
384
|
+
@tokens.shift
|
385
|
+
end
|
386
|
+
|
269
387
|
def parse_until_peek(token)
|
270
388
|
list = []
|
271
389
|
list << parse until @tokens.empty? || @tokens.first == token
|
@@ -387,6 +505,11 @@ module Fast
|
|
387
505
|
|
388
506
|
# Allow use previous captures while searching in the AST.
|
389
507
|
# Use `\\1` to point the match to the first captured element
|
508
|
+
# or sequential numbers considering the order of the captures.
|
509
|
+
#
|
510
|
+
# @example check comparision of integers that will always return true
|
511
|
+
# ast = Fast.ast("1 == 1") => s(:send, s(:int, 1), :==, s(:int, 1))
|
512
|
+
# Fast.match?(ast, "(send $(int _) == \1)") # => [s(:int, 1)]
|
390
513
|
class FindWithCapture < Find
|
391
514
|
attr_writer :previous_captures
|
392
515
|
|
@@ -406,8 +529,14 @@ module Fast
|
|
406
529
|
end
|
407
530
|
end
|
408
531
|
|
532
|
+
# Allow the user to interpolate expressions from external stuff.
|
409
533
|
# Use `%1` in the expression and the Matcher#prepare_arguments will
|
410
534
|
# interpolate the argument in the expression.
|
535
|
+
# @example interpolate the node value 1
|
536
|
+
# Fast.match?(Fast.ast("1"), "(int %1)", 1) # => true
|
537
|
+
# Fast.match?(Fast.ast("1"), "(int %1)", 2) # => false
|
538
|
+
# @example interpolate multiple arguments
|
539
|
+
# Fast.match?(Fast.ast("1"), "(%1 %2)", :int, 1) # => true
|
411
540
|
class FindFromArgument < Find
|
412
541
|
attr_writer :arguments
|
413
542
|
|
@@ -430,19 +559,41 @@ module Fast
|
|
430
559
|
end
|
431
560
|
end
|
432
561
|
|
433
|
-
# Capture some expression while searching for it
|
434
|
-
#
|
435
|
-
#
|
436
|
-
#
|
437
|
-
#
|
438
|
-
#
|
562
|
+
# Capture some expression while searching for it.
|
563
|
+
#
|
564
|
+
# The captures behaves exactly like Fast::Find and the only difference is that
|
565
|
+
# when it {#match?} stores #captures for future usage.
|
566
|
+
#
|
567
|
+
# @example capture int node
|
568
|
+
# capture = Fast::Capture.new("int") => #<Fast::Capture:0x00...e0 @captures=[], @token="int">
|
569
|
+
# capture.match?(Fast.ast("1")) # => [s(:int, 1)]
|
570
|
+
#
|
571
|
+
# @example binding directly in the Fast.expression
|
572
|
+
# Fast.match?(Fast.ast("1"), "(int $_)") # => [1]
|
573
|
+
#
|
574
|
+
# @example capture the value of a local variable assignment
|
575
|
+
# (${int float} _)
|
576
|
+
# @example expression to capture only the node type
|
577
|
+
# (${int float} _)
|
578
|
+
# @example expression to capture entire node
|
579
|
+
# $({int float} _)
|
580
|
+
# @example expression to capture only the node value of int or float nodes
|
581
|
+
# ({int float} $_)
|
582
|
+
# @example expression to capture both node type and value
|
583
|
+
# ($_ $_)
|
584
|
+
#
|
585
|
+
# You can capture stuff in multiple levels and
|
586
|
+
# build expressions that reference captures with Fast::FindWithCapture.
|
439
587
|
class Capture < Find
|
588
|
+
# Stores nodes that matches with the current expression.
|
440
589
|
attr_reader :captures
|
590
|
+
|
441
591
|
def initialize(token)
|
442
592
|
super
|
443
593
|
@captures = []
|
444
594
|
end
|
445
595
|
|
596
|
+
# Append the matching node to {#captures} if it matches
|
446
597
|
def match?(node)
|
447
598
|
@captures << node if super
|
448
599
|
end
|
@@ -507,7 +658,24 @@ module Fast
|
|
507
658
|
end
|
508
659
|
end
|
509
660
|
|
510
|
-
# Joins the AST and the search expression to create a complete
|
661
|
+
# Joins the AST and the search expression to create a complete matcher that
|
662
|
+
# recusively check if the node pattern expression matches with the given AST.
|
663
|
+
#
|
664
|
+
### Using captures
|
665
|
+
#
|
666
|
+
# One of the most important features of the matcher is find captures and also
|
667
|
+
# bind them on demand in case the expression is using previous captures.
|
668
|
+
#
|
669
|
+
# @example simple match
|
670
|
+
# ast = Fast.ast("a = 1")
|
671
|
+
# expression = Fast.expression("(lvasgn _ (int _))")
|
672
|
+
# Matcher.new(ast,expression).match? # true
|
673
|
+
#
|
674
|
+
# @example simple capture
|
675
|
+
# ast = Fast.ast("a = 1")
|
676
|
+
# expression = Fast.expression("(lvasgn _ (int $_))")
|
677
|
+
# Matcher.new(ast,expression).match? # => [1]
|
678
|
+
#
|
511
679
|
class Matcher
|
512
680
|
def initialize(ast, fast, *args)
|
513
681
|
@ast = ast
|
@@ -520,19 +688,8 @@ module Fast
|
|
520
688
|
prepare_arguments(@fast, args) if args.any?
|
521
689
|
end
|
522
690
|
|
523
|
-
|
524
|
-
|
525
|
-
when Array
|
526
|
-
expression.each do |item|
|
527
|
-
prepare_arguments(item, arguments)
|
528
|
-
end
|
529
|
-
when Fast::FindFromArgument
|
530
|
-
expression.arguments = arguments
|
531
|
-
when Fast::Find
|
532
|
-
prepare_arguments expression.token, arguments
|
533
|
-
end
|
534
|
-
end
|
535
|
-
|
691
|
+
# @return [true] if the @param ast recursively matches with expression.
|
692
|
+
# @return #find_captures case matches
|
536
693
|
def match?(ast = @ast, fast = @fast)
|
537
694
|
head, *tail = fast
|
538
695
|
return false unless head.match?(ast)
|
@@ -547,13 +704,9 @@ module Fast
|
|
547
704
|
end && find_captures
|
548
705
|
end
|
549
706
|
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
token.previous_captures = find_captures
|
554
|
-
end
|
555
|
-
end
|
556
|
-
|
707
|
+
# Look recursively into @param fast to check if the expression is have
|
708
|
+
# captures.
|
709
|
+
# @return [true] if any sub expression have captures.
|
557
710
|
def captures?(fast = @fast)
|
558
711
|
case fast
|
559
712
|
when Capture then true
|
@@ -562,6 +715,12 @@ module Fast
|
|
562
715
|
end
|
563
716
|
end
|
564
717
|
|
718
|
+
# Find search captures recursively.
|
719
|
+
#
|
720
|
+
# @return Array<Object> of captures from the expression
|
721
|
+
# @return true in case of no captures in the expression
|
722
|
+
# @see Fast::Capture
|
723
|
+
# @see Fast::FindFromArgument
|
565
724
|
def find_captures(fast = @fast)
|
566
725
|
return true if fast == @fast && !captures?(fast)
|
567
726
|
|
@@ -571,5 +730,32 @@ module Fast
|
|
571
730
|
when Find then find_captures(fast.token)
|
572
731
|
end
|
573
732
|
end
|
733
|
+
|
734
|
+
private
|
735
|
+
|
736
|
+
# Prepare arguments case the expression needs to bind extra arguments.
|
737
|
+
# @return [void]
|
738
|
+
def prepare_arguments(expression, arguments)
|
739
|
+
case expression
|
740
|
+
when Array
|
741
|
+
expression.each do |item|
|
742
|
+
prepare_arguments(item, arguments)
|
743
|
+
end
|
744
|
+
when Fast::FindFromArgument
|
745
|
+
expression.arguments = arguments
|
746
|
+
when Fast::Find
|
747
|
+
prepare_arguments expression.token, arguments
|
748
|
+
end
|
749
|
+
end
|
750
|
+
|
751
|
+
# @param [FindWithCapture] set the current captures
|
752
|
+
# as previous captures to the current node.
|
753
|
+
# @return [void] and only set [FindWithCapture#previous_captures]
|
754
|
+
def prepare_token(token)
|
755
|
+
case token
|
756
|
+
when Fast::FindWithCapture
|
757
|
+
token.previous_captures = find_captures
|
758
|
+
end
|
759
|
+
end
|
574
760
|
end
|
575
761
|
end
|