Sha256: 60a7b8dbaa564a7bf42caf5f035509ea566de16ef9a6e27ae99710a365cbfdec

Contents?: true

Size: 1.66 KB

Versions: 1

Compression:

Stored size: 1.66 KB

Contents

require_relative './operation'
require 'bigdecimal'
require 'bigdecimal/util'

module Dentaku
  module AST
    class Arithmetic < Operation
      def initialize(*)
        super
        fail "#{ self.class } requires numeric operands" unless valid_node?(left) && valid_node?(right)
      end

      def type
        :numeric
      end

      def value(context={})
        l = cast(left.value(context))
        r = cast(right.value(context))
        l.public_send(operator, r)
      end

      private

      def cast(value, prefer_integer=true)
        v = BigDecimal.new(value, Float::DIG+1)
        v = v.to_i if prefer_integer && v.frac.zero?
        v
      end

      def valid_node?(node)
        node.is_a?(Identifier) || node.type == :numeric
      end
    end

    class Addition < Arithmetic
      def operator
        :+
      end

      def self.precedence
        10
      end
    end

    class Subtraction < Arithmetic
      def operator
        :-
      end

      def self.precedence
        10
      end
    end

    class Multiplication < Arithmetic
      def operator
        :*
      end

      def self.precedence
        20
      end
    end

    class Division < Arithmetic
      def value(context={})
        r = cast(right.value(context), false)
        raise ZeroDivisionError if r.zero?

        cast(cast(left.value(context)) / r)
      end

      def self.precedence
        20
      end
    end

    class Modulo < Arithmetic
      def operator
        :%
      end

      def self.precedence
        20
      end
    end

    class Exponentiation < Arithmetic
      def operator
        :**
      end

      def self.precedence
        30
      end
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
dentaku-2.0.4 lib/dentaku/ast/arithmetic.rb