Class: Fast::Matcher

Inherits:
Object
  • Object
show all
Defined in:
lib/fast.rb

Overview

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.

Examples:

simple match

ast = Fast.ast("a = 1")
expression = Fast.expression("(lvasgn _ (int _))")
Matcher.new(expression, ast).match? # true

simple capture

ast = Fast.ast("a = 1")
expression = Fast.expression("(lvasgn _ (int $_))")
Matcher.new(expression, ast).match? # => [1]

Instance Method Summary collapse

Constructor Details

#initialize(pattern, ast, *args) ⇒ Matcher



624
625
626
627
628
629
630
631
632
633
# File 'lib/fast.rb', line 624

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

Instance Method Details

#captures?(expression = @expression) ⇒ true

Look recursively into @param expression to check if the expression is have captures.



656
657
658
659
660
661
662
# File 'lib/fast.rb', line 656

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_captures(expression = @expression) ⇒ Array<Object>, true

Find search captures recursively.



670
671
672
673
674
675
676
677
678
# File 'lib/fast.rb', line 670

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

#match?(expression = @expression, ast = @ast) ⇒ true



637
638
639
640
641
642
643
# File 'lib/fast.rb', line 637

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

#match_tail?(tail, child) ⇒ true



646
647
648
649
650
651
# File 'lib/fast.rb', line 646

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