ffast 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|