module Kakezan def flatten2 r = MultiNode.new() each do |child| case child when MultiNode r.append child when MulNode r.append child.flatten2 when ContainerNode r.append child.flatten2 else r.append child end end r end def name n = nil for c in @children next if NumberNode === c na = c.name if n.nil? n = na else raise "multiple names found" if na != n end end n = "1" if n.nil? n end def factor f = 1 for c in @children f *= c.factor end f end end class MulNode < ContainerNode include BinaryNode include Kakezan def initialize(lhs, rhs) @lhs, @rhs = lhs, rhs end def to_s lhs = @lhs.to_s rhs = @rhs.to_s if (/\d$/ =~ lhs && /^\w/ =~ rhs) then "#{lhs} #{rhs}" else "#{lhs}.#{rhs}" end end end class MultiNode < ContainerNode include Kakezan def initialize(*children) @children = children for c in @children raise "# MultiNode.new(#{children.inspect})" unless Node === c end end def to_s s = @children.join(';') s.gsub(/\d;\w/) { |dsw| dsw.sub(/;/, ' ') }.gsub(/;/, '.') end def each @children.each {|child| yield child } end attr_reader :children def append(other) case other when MultiNode @children += other.children else @children.push other end end def sort table = {} for child in self name = child.name if (table.include?(name)) then table[name] = table[name].mul_eval(child) else table[name] = child end end list = [] for name in table.keys.sort candi = table[name] if PowNode === candi and NumberNode === candi.lhs then v = candi.value list.push NumberNode.new(v) unless v == 1 next end next if candi.power.value == 0 list.push candi end if list.length > 1 list.delete(NumberNode::UNITY) end self.class.new(*list) end def collect_hash(stopper, op) list = [] for child in self list.push(child.send(op, stopper)) end self.class.new(*list).flatten2 end def expand(stopper) collect_hash(stopper, :expand) end def unalias(stopper) collect_hash(stopper, :unalias) end def foldnumber(stopper) collect_hash(stopper, :foldnumber) end def value raise "this is dimensional units" if (@children.size > 1) @children.first ? @children.first.value : NumberNode::UNITY.value end end