Class: Keisan::AST::Operator

Inherits:
Parent show all
Defined in:
lib/keisan/ast/operator.rb

Constant Summary collapse

ARITY_PRIORITY_ASSOCIATIVITY =

NOTE: operators with same priority must have same associativity

{
  "u!": [1, 100, :right],  # Logical not
  "u~": [1, 100, :right],  # Bitwise not
  "u+": [1, 100, :right],  # Unary plus
  "**": [2,  95, :right],  # Exponent
  "u-": [1,  90, :right],  # Unary minus
  "*":  [2,  85, :left],   # Times
  # "/":  [2,  85, :left], # Divide
  "%":  [2,  85, :left],   # Modulo
  "+":  [2,  80, :left],   # Plus
  # "-":  [2,  80, :left], # Minus
  "<<": [2,  75, :left],   # Bitwise left shift
  ">>": [2,  75, :left],   # Bitwise right shift
  "&":  [2,  70, :left],   # Bitwise and
  "^":  [2,  65, :left],   # Bitwise xor
  "|":  [2,  65, :left],   # Bitwise or
  ">":  [2,  60, :left],   # Greater than
  ">=": [2,  60, :left],   # Greater than or equal to
  "<":  [2,  60, :left],   # Less than
  "<=": [2,  60, :left],   # Less than or equal to
  "==": [2,  55, :none],   # Equal
  "!=": [2,  55, :none],   # Not equal
  "&&": [2,  50, :left],   # Logical and
  "||": [2,  45, :left],   # Logical or
  "=":  [2,  40, :right] # TODO: handle and test
}.freeze
ARITIES =
Hash[ARITY_PRIORITY_ASSOCIATIVITY.map {|sym, ary| [sym, ary[0]]}].freeze
PRIORITIES =
Hash[ARITY_PRIORITY_ASSOCIATIVITY.map {|sym, ary| [sym, ary[1]]}].freeze
ASSOCIATIVITIES =
Hash[ARITY_PRIORITY_ASSOCIATIVITY.map {|sym, ary| [sym, ary[2]]}].freeze
ASSOCIATIVITY_OF_PRIORITY =
ARITY_PRIORITY_ASSOCIATIVITY.inject({}) do |h, (symbol,arity_priority_associativity)|
  h[arity_priority_associativity[1]] = arity_priority_associativity[2]
  h
end.freeze

Instance Attribute Summary

Attributes inherited from Parent

#children

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Parent

#==, #deep_dup, #evaluate, #freeze, #replace, #simplify, #traverse, #unbound_functions, #unbound_variables

Methods inherited from Node

#!, #%, #&, #*, #**, #+, #+@, #-, #-@, #/, #<, #<<, #<=, #>, #>=, #>>, #^, #and, #coerce, #contains_a?, #deep_dup, #differentiate, #differentiated, #equal, #evaluate, #evaluated, #false?, #not_equal, #or, #replace, #replaced, #simplified, #simplify, #to_cell, #to_node, #traverse, #true?, #unbound_functions, #unbound_variables, #well_defined?, #|, #~

Constructor Details

#initialize(children = [], parsing_operators = []) ⇒ Operator

Returns a new instance of Operator.



41
42
43
44
45
46
47
48
49
50
# File 'lib/keisan/ast/operator.rb', line 41

def initialize(children = [], parsing_operators = [])
  unless parsing_operators.empty? || children.count == parsing_operators.count + 1
    raise Exceptions::ASTError.new("Mismatch of children and operators")
  end

  children = Array(children)
  super(children)

  @parsing_operators = parsing_operators
end

Class Method Details

.arityObject



68
69
70
# File 'lib/keisan/ast/operator.rb', line 68

def self.arity
  ARITIES[symbol]
end

.associativityObject



84
85
86
# File 'lib/keisan/ast/operator.rb', line 84

def self.associativity
  ASSOCIATIVITIES[symbol]
end

.associativity_of_priority(priority) ⇒ Object



60
61
62
# File 'lib/keisan/ast/operator.rb', line 60

def self.associativity_of_priority(priority)
  ASSOCIATIVITY_OF_PRIORITY[priority]
end

.priorityObject



76
77
78
# File 'lib/keisan/ast/operator.rb', line 76

def self.priority
  PRIORITIES[symbol]
end

.symbolObject



92
93
94
# File 'lib/keisan/ast/operator.rb', line 92

def self.symbol
  raise Exceptions::NotImplementedError.new
end

Instance Method Details

#arityObject



64
65
66
# File 'lib/keisan/ast/operator.rb', line 64

def arity
  self.class.arity
end

#associativityObject



80
81
82
# File 'lib/keisan/ast/operator.rb', line 80

def associativity
  self.class.associativity
end

#blank_valueObject



96
97
98
# File 'lib/keisan/ast/operator.rb', line 96

def blank_value
  raise Exceptions::NotImplementedError.new
end

#evaluate_assignments(context = nil) ⇒ Object



52
53
54
55
56
57
58
# File 'lib/keisan/ast/operator.rb', line 52

def evaluate_assignments(context = nil)
  context ||= Context.new
  @children = children.map do |child|
    child.evaluate_assignments(context)
  end
  self
end

#priorityObject



72
73
74
# File 'lib/keisan/ast/operator.rb', line 72

def priority
  self.class.priority
end

#symbolObject



88
89
90
# File 'lib/keisan/ast/operator.rb', line 88

def symbol
  self.class.symbol
end

#to_sObject



113
114
115
116
117
118
119
120
121
122
# File 'lib/keisan/ast/operator.rb', line 113

def to_s
  children.map do |child|
    case child
    when Operator
      "(#{child.to_s})"
    else
      "#{child.to_s}"
    end
  end.join(symbol.to_s)
end

#value(context = nil) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/keisan/ast/operator.rb', line 100

def value(context = nil)
  args = children
  args = args.reverse if associativity == :right

  args.inject(blank_value) do |result, child|
    if associativity == :left
      result.send(symbol, child.value(context))
    else
      child.value(context).send(symbol, result)
    end
  end
end