Sha256: abcb218acf544ba801ed407660548a5e5dce5d92e6a5a7a56b8d546786ba239e

Contents?: true

Size: 1.57 KB

Versions: 2

Compression:

Stored size: 1.57 KB

Contents

require "metamorpher/visitable/visitor"
require "metamorpher/matcher/match"
require "metamorpher/matcher/no_match"

module Metamorpher
  module Matcher
    module Matching
      def match(other)
        if other.nil?
          Matcher::NoMatch.new
        else
          accept MatchingVisitor.new(other)
        end
      end
    end

    class MatchingVisitor < Visitable::Visitor
      attr_accessor :other

      def initialize(other)
        @other = other
      end

      def visit_variable(variable)
        captured = variable.greedy? ? other.with_younger_siblings : other
        if variable.condition.call(captured)
          Matcher::Match.new(root: captured, substitution: { variable.name => captured })
        else
          Matcher::NoMatch.new
        end
      end

      def visit_literal(literal)
        if other.name == literal.name && expected_number_of_children?(literal)
          literal.children
            .zip(other.children)
            .map { |child, other_child| child.match(other_child) }
            .reduce(Matcher::Match.new(root: other), :combine)
        else
          Matcher::NoMatch.new
        end
      end

      def visit_derived(_derived)
        fail MatchingError, "Cannot match against a derived variable."
      end

      private

      def expected_number_of_children?(literal)
        other.children.size == literal.children.size || greedy_child?(literal)
      end

      def greedy_child?(literal)
        literal.children.any? { |c| c.is_a?(Terms::Variable) && c.greedy? }
      end
    end

    class MatchingError < ArgumentError; end
  end
end

Version data entries

2 entries across 2 versions & 1 rubygems

Version Path
metamorpher-0.2.0 lib/metamorpher/matcher/matching.rb
metamorpher-0.1.1 lib/metamorpher/matcher/matching.rb