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.



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

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.



706
707
708
709
710
711
712
# File 'lib/fast.rb', line 706

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:



720
721
722
723
724
725
726
727
728
# File 'lib/fast.rb', line 720

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



689
690
691
692
693
694
695
696
697
698
699
700
701
# File 'lib/fast.rb', line 689

def match?(ast = @ast, fast = @fast)
  head, *tail = fast
  return false unless head.match?(ast)
  if tail.empty?
    return ast == @ast ? find_captures : true # root node
  end

  child = ast.children
  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