package skeb

import expression._
import scala.collection.mutable.{Map, HashMap}

/** A function that can reduce an expression to a constant value (that is,
  * evaluate it).
  * @param cell The cell in which the evaluation occurs. */
class Evaluator(val cell: Cell) extends Function1[Expression, Constant] {
  
  /** The type of a function that applies an operator to its parameters. */
  type Evaluator = List[Constant] => Constant
  
  /** A map that, for all known operator names, provides an evaluator. */
  val operations: Map[String, Evaluator] =
    new HashMap[String, Evaluator]()
  
  /** Reduces an expression to a constant. Operators will be looked-up in the
    * operations map. If the expression references foreign cells, their cell's
    * value will be used (as oposed to re-evaluating their expressions). */
  def apply (exp: Expression): Constant = exp match {
    case Reference(cell) => cell.value
    case const: Constant => const
    case Apply(operation, arguments) if operations.contains(operation) =>
      operations(operation)(arguments map this)
    case Apply(operation, _) =>
      Text("Operation '" + operation + "' is undefined.")
    case _ =>
      Text("I did not understand this expression")
  }
  
}
