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(ast,expression).match? # true

simple capture

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

Instance Method Summary collapse

Constructor Details

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

Returns a new instance of Matcher.



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

def initialize(ast, fast, *args)
  @ast = ast
  @fast = if fast.is_a?(String)
            Fast.expression(fast)
          else
            [*fast].map(&Find.method(:new))
          end
  @captures = []
  prepare_arguments(@fast, args) if args.any?
end

Instance Method Details

#captures?(fast = @fast) ⇒ true

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

Returns:

  • (true)

    if any sub expression have captures.



686
687
688
689
690
691
692
# File 'lib/fast.rb', line 686

def captures?(fast = @fast)
  case fast
  when Capture then true
  when Array then fast.any?(&method(:captures?))
  when Find then captures?(fast.token)
  end
end

#find_captures(fast = @fast) ⇒ Array<Object>, true

Find search captures recursively.

Returns:

  • (Array<Object>)

    of captures from the expression

  • (true)

    in case of no captures in the expression

See Also:



700
701
702
703
704
705
706
707
708
# File 'lib/fast.rb', line 700

def find_captures(fast = @fast)
  return true if fast == @fast && !captures?(fast)

  case fast
  when Capture then fast.captures
  when Array then fast.flat_map(&method(:find_captures)).compact
  when Find then find_captures(fast.token)
  end
end

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

Returns:

  • (true)

    if the @param ast recursively matches with expression.

  • #find_captures case matches



667
668
669
670
671
672
673
# File 'lib/fast.rb', line 667

def match?(ast = @ast, fast = @fast)
  head, *tail = fast
  return false unless head.match?(ast)
  return find_captures if tail.empty?

  match_tail?(ast.children, tail)
end

#match_tail?(child, tail) ⇒ true

Returns if all children matches with tail.

Returns:

  • (true)

    if all children matches with tail



676
677
678
679
680
681
# File 'lib/fast.rb', line 676

def match_tail?(child, tail)
  tail.each_with_index.all? do |token, i|
    prepare_token(token)
    token.is_a?(Array) ? match?(child[i], token) : token.match?(child[i])
  end && find_captures
end