class Keisan::AST::Plus

Public Class Methods

new(children = [], parsing_operators = []) click to toggle source
Calls superclass method
# File lib/keisan/ast/plus.rb, line 4
def initialize(children = [], parsing_operators = [])
  super
  convert_minus_to_plus!(parsing_operators)
end
symbol() click to toggle source
# File lib/keisan/ast/plus.rb, line 9
def self.symbol
  :+
end

Public Instance Methods

blank_value() click to toggle source
# File lib/keisan/ast/plus.rb, line 13
def blank_value
  0
end
differentiate(variable, context = nil) click to toggle source
# File lib/keisan/ast/plus.rb, line 78
def differentiate(variable, context = nil)
  Plus.new(children.map {|child| child.differentiate(variable, context)}).simplify(context)
end
evaluate(context = nil) click to toggle source
# File lib/keisan/ast/plus.rb, line 34
def evaluate(context = nil)
  children[1..-1].inject(children.first.evaluate(context)) {|total, child| total + child.evaluate(context)}
end
simplify(context = nil) click to toggle source
Calls superclass method
# File lib/keisan/ast/plus.rb, line 38
def simplify(context = nil)
  context ||= Context.new

  super(context)

  # Commutative, so pull in operands of any `Plus` operators
  @children = children.inject([]) do |new_children, cur_child|
    case cur_child
    when Plus
      new_children + cur_child.children
    else
      new_children << cur_child
    end
  end

  if children.all? {|child| child.is_a?(String)}
    return String.new(children.inject("") do |result, child|
      result + child.value
    end)
  elsif children.all? {|child| child.is_a?(List)}
    return List.new(children.inject([]) do |result, child|
      result + child.value
    end)
  end

  constants, non_constants = *children.partition {|child| child.is_a?(Number)}
  constant = constants.inject(Number.new(0), &:+).simplify(context)

  if non_constants.empty?
    constant
  else
    @children = constant.value(context) == 0 ? [] : [constant]
    @children += non_constants

    return @children.first.simplify(context) if @children.size == 1

    self
  end
end
value(context = nil) click to toggle source
# File lib/keisan/ast/plus.rb, line 17
def value(context = nil)
  children_values = children.map {|child| child.value(context)}
  # Special case of string concatenation
  if children_values.all? {|child| child.is_a?(::String)}
    children_values.join
  # Special case of array concatenation
  elsif children_values.all? {|child| child.is_a?(::Array)}
    children_values.inject([], &:+)
  elsif children_values.one? {|child| child.is_a?(::Date)}
    date_time_plus(children_values, ::Date)
  elsif children_values.one? {|child| child.is_a?(::Time)}
    date_time_plus(children_values, ::Time)
  else
    children_values.inject(0, &:+)
  end.to_node.value(context)
end

Private Instance Methods

convert_minus_to_plus!(parsing_operators) click to toggle source
# File lib/keisan/ast/plus.rb, line 90
def convert_minus_to_plus!(parsing_operators)
  parsing_operators.each.with_index do |parsing_operator, index|
    if parsing_operator.is_a?(Parsing::Minus)
      @children[index+1] = UnaryMinus.new(@children[index+1])
    end
  end
end
date_time_plus(elements, klass) click to toggle source
# File lib/keisan/ast/plus.rb, line 84
def date_time_plus(elements, klass)
  date_time = elements.select {|child| child.is_a?(klass)}.first
  others = elements.select {|child| !child.is_a?(klass)}
  date_time + others.inject(0, &:+)
end