<commit_before>module Calvin
  class Evaluator < Parslet::Transform
    attr_accessor :env

    def initialize
      super
      @env = {}

      rule monad: subtree(:monad) do
        symbol = monad[:symbol].to_sym
        expression = monad[:expression]

        case symbol
        when :+
          # Just return expression, for now.
          expression
        when :-
          Evaluator::Helpers.apply lambda { |x| -x }, expression
        when :*
          Evaluator::Helpers.apply lambda { |x| x <=> 0 },expression
        when :/
          Evaluator::Helpers.apply lambda { |x| 1 / x },expression
        when :^
          Evaluator::Helpers.apply lambda { |x| Math::E ** x },expression
        when :%
          Evaluator::Helpers.apply lambda { |x| x.abs },expression
        end
      end

      rule dyad: subtree(:dyad) do
        left = dyad[:left]
        right = dyad[:right]
        symbol = dyad[:symbol].to_sym

        case symbol
        when :+
          Evaluator::Helpers.apply_dyad lambda { |left, right| left + right }, left, right
        when :-
          Evaluator::Helpers.apply_dyad lambda { |left, right| left - right }, left, right
        when :*
          Evaluator::Helpers.apply_dyad lambda { |left, right| left * right }, left, right
        when :/
          Evaluator::Helpers.apply_dyad lambda { |left, right| left / right }, left, right
        when :^
          Evaluator::Helpers.apply_dyad lambda { |left, right| left ** right }, left, right
        when :%
          Evaluator::Helpers.apply_dyad lambda { |left, right| left % right }, left, right
        end
      end
    end

    # helpers
    module Helpers
      extend self

      def apply(fn, object)
        if object.is_a?(Array)
          object.map { |el| apply(fn, el) }
        else
          fn.call object
        end
      end

      def apply_dyad(fn, left, right)
        if left.is_a?(Numeric)
          Evaluator::Helpers.apply lambda { |x| fn.call(left,  x) }, right
        elsif right.is_a?(Numeric)
          Evaluator::Helpers.apply lambda { |x| fn.call(x, right) }, left
        else
          Evaluator::Helpers.apply_each fn, left, right
        end
      end

      def apply_each(fn, left, right)
        if left.is_a?(Array) && right.is_a?(Array)
          if left.size == right.size
            left.zip(right).map do |l, r|
              apply_each(fn, l, r)
            end
          else
            # Raise error: Size doesn't match
            raise ArgumentError.new "Array size doesn't match. `left` had size #{left.size}, while `right` had size #{right.size}."
          end<commit_msg>More refactor.<commit_after>module Calvin
  class Evaluator < Parslet::Transform
    attr_accessor :env

    def initialize
      super
      @env = {}

      rule monad: subtree(:monad) do
        symbol = monad[:symbol].to_sym
        expression = monad[:expression]

        case symbol
        when :+
          # Just return expression, for now.
          expression
        when :-
          Evaluator::Helpers.apply lambda { |x| -x }, expression
        when :*
          Evaluator::Helpers.apply lambda { |x| x <=> 0 },expression
        when :/
          Evaluator::Helpers.apply lambda { |x| 1 / x },expression
        when :^
          Evaluator::Helpers.apply lambda { |x| Math::E ** x },expression
        when :%
          Evaluator::Helpers.apply lambda { |x| x.abs },expression
        end
      end

      rule dyad: subtree(:dyad) do
        left = dyad[:left]
        right = dyad[:right]
        symbol = dyad[:symbol].to_sym

        case symbol
        when :+, :-, :*, :/, :%
          Evaluator::Helpers.apply_dyad symbol, left, right
        when :^
          Evaluator::Helpers.apply_dyad :**, left, right
        end
      end
    end

    # helpers
    module Helpers
      extend self

      def apply(fn, object)
        if object.is_a?(Array)
          object.map { |el| apply(fn, el) }
        else
          fn.call object
        end
      end

      def apply_dyad(fn, left, right)
        if fn.is_a?(Symbol)
          sym = fn
          fn = lambda { |left, right| left.send(sym, right) }
        end

        if left.is_a?(Numeric)
          Evaluator::Helpers.apply lambda { |x| fn.call(left,  x) }, right
        elsif right.is_a?(Numeric)
          Evaluator::Helpers.apply lambda { |x| fn.call(x, right) }, left
        else
          Evaluator::Helpers.apply_each fn, left, right
        end
      end

      def apply_each(fn, left, right)
        if left.is_a?(Array) && right.is_a?(Array)
          if left.size == right.size
            left.zip(right).map do |l, r|
              apply_each(fn, l, r)
            end
          else
            # Raise error: Size doesn't match
            raise ArgumentError.new "Array size doesn't match. `left` had size #{left.size}, while `right` had size #{right.size}."
          end
{'fraction_non_alphanumeric': 0.11313048805391056, 'fraction_numerical': 0.0008168266285480906, 'mean_word_length': 1.7656691134952005, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, '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': '776734', 'n_tokens_mistral': 1482, 'n_tokens_neox': 1483, 'n_words': 402}