From 517a103970165471aa5e2fe5fd2bff52e92c21af Mon Sep 17 00:00:00 2001 From: Slavasil Date: Tue, 10 Mar 2026 14:37:53 +0300 Subject: [PATCH] add expression classes and implement to_s for them --- lib/ruby_algebra.rb | 1 + lib/ruby_algebra/expression.rb | 223 +++++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 lib/ruby_algebra/expression.rb diff --git a/lib/ruby_algebra.rb b/lib/ruby_algebra.rb index 32b91b2..cd719d2 100644 --- a/lib/ruby_algebra.rb +++ b/lib/ruby_algebra.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require_relative "ruby_algebra/version" +require_relative "ruby_algebra/expression" module RubyAlgebra end diff --git a/lib/ruby_algebra/expression.rb b/lib/ruby_algebra/expression.rb new file mode 100644 index 0000000..bca8232 --- /dev/null +++ b/lib/ruby_algebra/expression.rb @@ -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