add expression classes and implement to_s for them

This commit is contained in:
2026-03-10 14:37:53 +03:00
parent e121decd12
commit 517a103970
2 changed files with 224 additions and 0 deletions

View 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