class Fast::Matcher
Joins the AST and the search expression to create a complete matcher that recusively check if the node pattern expression matches with the given AST.
Using captures
One of the most important features of the matcher is find captures and also bind them on demand in case the expression is using previous captures.
@example simple match
ast = Fast.ast("a = 1") expression = Fast.expression("(lvasgn _ (int _))") Matcher.new(expression, ast).match? # true
@example simple capture
ast = Fast.ast("a = 1") expression = Fast.expression("(lvasgn _ (int $_))") Matcher.new(expression, ast).match? # => [1]
Public Class Methods
# File lib/fast.rb, line 692 def initialize(pattern, ast, *args) @ast = ast @expression = if pattern.is_a?(String) Fast.expression(pattern) else [*pattern].map(&Find.method(:new)) end @captures = [] prepare_arguments(@expression, args) if args.any? end
Public Instance Methods
Look recursively into @param expression to check if the expression is have captures. @return [true] if any sub expression have captures.
# File lib/fast.rb, line 724 def captures?(expression = @expression) case expression when Capture then true when Array then expression.any?(&method(:captures?)) when Find then captures?(expression.token) end end
Find
search captures recursively.
@return [Array<Object>] of captures from the expression @return [true] in case of no captures in the expression @see Fast::Capture
@see Fast::FindFromArgument
# File lib/fast.rb, line 738 def find_captures(expression = @expression) return true if expression == @expression && !captures?(expression) case expression when Capture then expression.captures when Array then expression.flat_map(&method(:find_captures)).compact when Find then find_captures(expression.token) end end
@return [true] if the @param ast recursively matches with expression. @return find_captures
case matches
# File lib/fast.rb, line 705 def match?(expression = @expression, ast = @ast) head, *tail_expression = expression return false unless head.match?(ast) return find_captures if tail_expression.empty? match_tail?(tail_expression, ast.children) end
@return [true] if all children matches with tail
# File lib/fast.rb, line 714 def match_tail?(tail, child) tail.each_with_index.all? do |token, i| prepare_token(token) token.is_a?(Array) ? match?(token, child[i]) : token.match?(child[i]) end && find_captures end
Private Instance Methods
Prepare arguments case the expression needs to bind extra arguments. @return [void]
# File lib/fast.rb, line 752 def prepare_arguments(expression, arguments) case expression when Array expression.each do |item| prepare_arguments(item, arguments) end when Fast::FindFromArgument expression.arguments = arguments when Fast::Find prepare_arguments expression.token, arguments end end
Prepare token with previous captures @param [FindWithCapture] token set the current captures @return [void] @see [FindWithCapture#previous_captures]
# File lib/fast.rb, line 769 def prepare_token(token) case token when Fast::FindWithCapture token.previous_captures = find_captures end end