add expression classes and implement to_s for them
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require_relative "ruby_algebra/version"
|
require_relative "ruby_algebra/version"
|
||||||
|
require_relative "ruby_algebra/expression"
|
||||||
|
|
||||||
module RubyAlgebra
|
module RubyAlgebra
|
||||||
end
|
end
|
||||||
|
|||||||
223
lib/ruby_algebra/expression.rb
Normal file
223
lib/ruby_algebra/expression.rb
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module RubyAlgebra
|
||||||
|
class Expression
|
||||||
|
def to_s
|
||||||
|
raise NotImplementedError
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
raise NotImplementedError
|
||||||
|
end
|
||||||
|
|
||||||
|
def op_priority
|
||||||
|
raise NotImplementedError
|
||||||
|
end
|
||||||
|
|
||||||
|
def op_assoc_type
|
||||||
|
raise NotImplementedError
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Addition < Expression
|
||||||
|
attr_reader :lhs, :rhs
|
||||||
|
|
||||||
|
def initialize(lhs, rhs)
|
||||||
|
raise ArgumentError unless lhs.is_a?(Expression) && rhs.is_a?(Expression)
|
||||||
|
@lhs = lhs
|
||||||
|
@rhs = rhs
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
need_parentheses_left = lhs.op_priority < op_priority || (lhs.op_priority == op_priority && op_assoc_type == :right)
|
||||||
|
need_parentheses_right = rhs.op_priority < op_priority || (rhs.op_priority == op_priority && op_assoc_type == :left)
|
||||||
|
|
||||||
|
result = need_parentheses_left ? "(#{lhs}) + " : "#{lhs} + "
|
||||||
|
result + (need_parentheses_right ? "(#{rhs})" : rhs.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
:add
|
||||||
|
end
|
||||||
|
|
||||||
|
def op_priority
|
||||||
|
10
|
||||||
|
end
|
||||||
|
|
||||||
|
def op_assoc_type
|
||||||
|
:left
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Subtraction < Addition
|
||||||
|
attr_reader :lhs, :rhs
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
need_parentheses_left = lhs.op_priority < op_priority || (lhs.op_priority == op_priority && op_assoc_type == :right)
|
||||||
|
need_parentheses_right = rhs.op_priority < op_priority || (rhs.op_priority == op_priority && op_assoc_type == :left)
|
||||||
|
|
||||||
|
result = need_parentheses_left ? "(#{lhs}) - " : "#{lhs} - "
|
||||||
|
result + (need_parentheses_right ? "(#{rhs})" : rhs.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
:sub
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Multiplication < Expression
|
||||||
|
attr_reader :lhs, :rhs
|
||||||
|
|
||||||
|
def initialize(lhs, rhs)
|
||||||
|
raise ArgumentError unless lhs.is_a?(Expression) && rhs.is_a?(Expression)
|
||||||
|
@lhs = lhs
|
||||||
|
@rhs = rhs
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
need_parentheses_left = lhs.op_priority < op_priority || (lhs.op_priority == op_priority && op_assoc_type == :right)
|
||||||
|
need_parentheses_right = rhs.op_priority < op_priority || (rhs.op_priority == op_priority && op_assoc_type == :left)
|
||||||
|
|
||||||
|
if lhs.type == :constant && lhs.value == 1
|
||||||
|
need_parentheses_right ? "(#{rhs})" : rhs.to_s
|
||||||
|
elsif lhs.type == :constant && lhs.value == -1
|
||||||
|
need_parentheses_right ? "-(#{rhs})" : "-#{rhs.to_s}"
|
||||||
|
elsif (need_parentheses_right || rhs.type == :variable) && (need_parentheses_left || lhs.type == :mult || lhs.type == :constant)
|
||||||
|
result = need_parentheses_left ? "(#{lhs})" : lhs.to_s
|
||||||
|
if lhs.type == :variable && rhs.type == :variable && lhs.single_letter? && rhs.single_letter?
|
||||||
|
result += " "
|
||||||
|
end
|
||||||
|
result + (need_parentheses_right ? "(#{rhs})" : rhs.to_s)
|
||||||
|
else
|
||||||
|
result = need_parentheses_left ? "(#{lhs}) * " : "#{lhs} * "
|
||||||
|
result + (need_parentheses_right ? "(#{rhs})" : rhs.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
:mult
|
||||||
|
end
|
||||||
|
|
||||||
|
def op_priority
|
||||||
|
20
|
||||||
|
end
|
||||||
|
|
||||||
|
def op_assoc_type
|
||||||
|
:left
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Division < Multiplication
|
||||||
|
def to_s
|
||||||
|
need_parentheses_left = lhs.op_priority < op_priority || (lhs.op_priority == op_priority && op_assoc_type == :right)
|
||||||
|
need_parentheses_right = rhs.op_priority < op_priority || (rhs.op_priority == op_priority && op_assoc_type == :left)
|
||||||
|
|
||||||
|
result = need_parentheses_left ? "(#{lhs}) / " : "#{lhs} / "
|
||||||
|
result + (need_parentheses_right ? "(#{rhs})" : rhs.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
:div
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Power < Expression
|
||||||
|
attr_reader :base, :exponent
|
||||||
|
|
||||||
|
def initialize(base, exponent)
|
||||||
|
raise ArgumentError unless base.is_a?(Expression) && exponent.is_a?(Expression)
|
||||||
|
@base = base
|
||||||
|
@exponent = exponent
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
need_parentheses_left = base.op_priority < op_priority || (base.op_priority == op_priority && op_assoc_type == :right)
|
||||||
|
need_parentheses_right = exponent.op_priority < op_priority || (exponent.op_priority == op_priority && op_assoc_type == :left)
|
||||||
|
|
||||||
|
result = need_parentheses_left ? "(#{base}) ^ " : "#{base} ^ "
|
||||||
|
result + (need_parentheses_right ? "(#{exponent})" : exponent.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
:pow
|
||||||
|
end
|
||||||
|
|
||||||
|
def op_priority
|
||||||
|
30
|
||||||
|
end
|
||||||
|
|
||||||
|
def op_assoc_type
|
||||||
|
:right
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Subtraction < Addition
|
||||||
|
attr_reader :lhs, :rhs
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
need_parentheses_left = lhs.op_priority < op_priority || (lhs.op_priority == op_priority && op_assoc_type == :right)
|
||||||
|
need_parentheses_right = rhs.op_priority < op_priority || (rhs.op_priority == op_priority && op_assoc_type == :left)
|
||||||
|
|
||||||
|
result = need_parentheses_left ? "(#{lhs}) - " : "#{lhs} - "
|
||||||
|
result + (need_parentheses_right ? "(#{rhs})" : rhs.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
:sub
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
class Constant < Expression
|
||||||
|
attr_reader :value
|
||||||
|
|
||||||
|
def initialize(value)
|
||||||
|
@value = value
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
@value.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
:constant
|
||||||
|
end
|
||||||
|
|
||||||
|
def op_priority
|
||||||
|
1000
|
||||||
|
end
|
||||||
|
|
||||||
|
def op_assoc_type
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Variable < Expression
|
||||||
|
attr_reader :symbol
|
||||||
|
|
||||||
|
def initialize(symbol)
|
||||||
|
@symbol = symbol
|
||||||
|
@is_single_letter = symbol.length == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
@symbol
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
:variable
|
||||||
|
end
|
||||||
|
|
||||||
|
def op_priority
|
||||||
|
1000
|
||||||
|
end
|
||||||
|
|
||||||
|
def op_assoc_type
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def single_letter?
|
||||||
|
@is_single_letter
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user