<commit_before>require "metamorpher/rewriting/term"
require "metamorpher/matching/match"
require "metamorpher/matching/no_match"

module Metamorpher
  module Rewriting
    class Literal < Term
      attributes children: []

      def initialize(attributes = {})
        initialize_attributes(attributes)
        children.each { |child| child.parent = self }
      end

      def inspect
        if children.empty?
          "#{name}"
        else
          "#{name}(#{children.map(&:inspect).join(', ')})"
        end
      end

      def children_younger_than_or_equal_to(child)
        children[(index(child))..-1]
      end

      def match(other)
        if name == other.name
          children_match(other)
        else
          Matching::NoMatch.new
        end
      end

      def substitute(substitution)
        Literal.new(
          name: name,
          children: children.map { |child| child.substitute(substitution) }
        )
      end

      def replace(child, replacement)
        Literal.new(
          name: name,
          children: children.map { |original| original == child ? replacement : original }
        )
      end

      private

      def index(child)
        children.index(child) ||
        fail(ArgumentError, "#{child.inspect} is not a child of #{inspect}")
      end

      def children_match(other)
        children
          .zip(other.children)
          .map { |child, other_child| child.match(other_child) }
          .reduce(Matching::Match.new(root: other), :combine)
      end
    end
  end
end
<commit_msg>Matching against nil should result in a NoMatch.<commit_after>require "metamorpher/rewriting/term"
require "metamorpher/matching/match"
require "metamorpher/matching/no_match"

module Metamorpher
  module Rewriting
    class Literal < Term
      attributes children: []

      def initialize(attributes = {})
        initialize_attributes(attributes)
        children.each { |child| child.parent = self }
      end

      def inspect
        if children.empty?
          "#{name}"
        else
          "#{name}(#{children.map(&:inspect).join(', ')})"
        end
      end

      def children_younger_than_or_equal_to(child)
        children[(index(child))..-1]
      end

      def match(other)
        if other && other.name == name
          children_match(other)
        else
          Matching::NoMatch.new
        end
      end

      def substitute(substitution)
        Literal.new(
          name: name,
          children: children.map { |child| child.substitute(substitution) }
        )
      end

      def replace(child, replacement)
        Literal.new(
          name: name,
          children: children.map { |original| original == child ? replacement : original }
        )
      end

      private

      def index(child)
        children.index(child) ||
        fail(ArgumentError, "#{child.inspect} is not a child of #{inspect}")
      end

      def children_match(other)
        children
          .zip(other.children)
          .map { |child, other_child| child.match(other_child) }
          .reduce(Matching::Match.new(root: other), :combine)
      end
    end
  end
end

{'fraction_non_alphanumeric': 0.10304375396322131, 'fraction_numerical': 0.0006341154090044388, 'mean_word_length': 2.024928092042186, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '349214', 'n_tokens_mistral': 926, 'n_tokens_neox': 897, 'n_words': 204}