module Fbe::Award::PTerm

def abstract?

def abstract?
  false
end

def publish_to(bylaw)

def publish_to(bylaw)
  case @op
  when :award
    @operands.each do |o|
      o.publish_to(bylaw)
    rescue StandardError => e
      raise "Failure in #{o}: #{e.message}"
    end
  when :aka
    @operands[0..-2].each do |o|
      o.publish_to(bylaw)
    rescue StandardError => e
      raise "Failure in #{o}: #{e.message}"
    end
    bylaw.revert(@operands.size - 1)
    bylaw.line(to_p(@operands[@operands.size - 1]))
  when :explain
    bylaw.intro(to_p(@operands[0]))
  when :in
    bylaw.line("assume that #{to_p(@operands[0])} is #{to_p(@operands[1])}")
  when :let
    bylaw.line("let #{to_p(@operands[0])} be equal to #{to_p(@operands[1])}")
    bylaw.let(@operands[0], @operands[1])
  when :set
    bylaw.line("set #{to_p(@operands[0])} to #{to_p(@operands[1])}")
  when :give
    bylaw.line("award #{to_p(@operands[0])}")
  else
    raise "Unknown term '#{@op}'"
  end
end

def static?

def static?
  true
end

def to_p(any)

def to_p(any)
  case any
  when PTerm
    any.to_s
  when Symbol
    s = any.to_s
    subs = {
      0 => '₀',
      1 => '₁',
      2 => '₂',
      3 => '₃',
      4 => '₄',
      5 => '₅',
      6 => '₆',
      7 => '₇',
      8 => '₈',
      9 => '₉'
    }
    s.gsub!(/([a-z]+)([0-9])/) { |_| "#{Regexp.last_match[1]}#{subs[Regexp.last_match[2].to_i]}" }
    "_#{s.tr('_', '-')}_"
  when Integer, Float
    "**#{any}**"
  else
    any
  end
end

def to_s

def to_s
  case @op
  when :total
    'total'
  when :if
    "if #{to_p(@operands[0])} then #{to_p(@operands[1])} else #{to_p(@operands[2])}"
  when :and
    @operands.map(&:to_s).join(' and ')
  when :or
    @operands.map(&:to_s).join(' or ')
  when :not
    "not #{@operands[0]}"
  when :eq
    "#{to_p(@operands[0])} = #{to_p(@operands[1])}"
  when :lt
    "#{to_p(@operands[0])} < #{to_p(@operands[1])}"
  when :lte
    "#{to_p(@operands[0])}#{to_p(@operands[1])}"
  when :gt
    "#{to_p(@operands[0])} > #{to_p(@operands[1])}"
  when :gte
    "#{to_p(@operands[0])}#{to_p(@operands[1])}"
  when :div
    "#{to_p(@operands[0])} ÷ #{to_p(@operands[1])}"
  when :times
    "#{to_p(@operands[0])} × #{to_p(@operands[1])}"
  when :plus
    "#{to_p(@operands[0])} + #{to_p(@operands[1])}"
  when :minus
    "#{to_p(@operands[0])} - #{to_p(@operands[1])}"
  when :max
    "maximum of #{to_p(@operands[0])} and #{to_p(@operands[1])}"
  when :min
    "minimum of #{to_p(@operands[0])} and #{to_p(@operands[1])}"
  when :between
    "at least #{to_p(@operands[0])} and at most #{to_p(@operands[1])}"
  else
    raise "Unknown term '#{@op}'"
  end
end