// Maria expression class -*- c++ -*-

#ifdef __GNUC__
# pragma implementation
#endif // __GNUC__
#include "Expression.h"
#include "allExpressions.h"
#include "Property.h"

#include <assert.h>
#include "ExpressionSet.h"

/** Cache for common subexpression elimination */
static class ExpressionSet exprs;

/** @file Expression.C
 * Abstract base class for expressions
 */

/* Copyright © 1998-2003 Marko Mäkelä (msmakela@tcs.hut.fi).

   This file is part of MARIA, a reachability analyzer and model checker
   for high-level Petri nets.

   MARIA is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   MARIA is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   The GNU General Public License is often shipped with GNU software, and
   is generally kept in a file called COPYING or LICENSE.  If you do not
   have a copy of the license, write to the Free Software Foundation,
   59 Temple Place, Suite 330, Boston, MA 02111 USA. */

Expression::Expression () :
  myReferences (1), myType (0),
  myIsAtomic (false)
{
}

Expression::~Expression ()
{
  assert (!myReferences);
}

class Expression*
Expression::cse ()
{
  return this ? exprs.insert (this) : 0;
}

void
Expression::setType (const class Type& type)
{
  assert (!myType || type.isAssignable (*myType));
  myType = &type;
}

bool
Expression::operator== (const class Expression& other) const
{
  if (this == &other)
    return true;
  if (getKind () != other.getKind () || getType () != other.getType ())
    return false;

  switch (getKind ()) {
  case eVariable:
    return
      static_cast<const class Variable&>(*this) ==
      static_cast<const class Variable&>(other);
  case eConstant:
    return
      static_cast<const class Constant&>(*this) ==
      static_cast<const class Constant&>(other);
  case eUndefined:
    return
      static_cast<const class Undefined&>(*this) ==
      static_cast<const class Undefined&>(other);
  case eStruct:
    return
      static_cast<const class StructExpression&>(*this) ==
      static_cast<const class StructExpression&>(other);
  case eStructComponent:
    return
      static_cast<const class StructComponent&>(*this) ==
      static_cast<const class StructComponent&>(other);
  case eStructAssign:
    return
      static_cast<const class StructAssign&>(*this) ==
      static_cast<const class StructAssign&>(other);
  case eUnion:
    return
      static_cast<const class UnionExpression&>(*this) ==
      static_cast<const class UnionExpression&>(other);
  case eUnionComponent:
    return
      static_cast<const class UnionComponent&>(*this) ==
      static_cast<const class UnionComponent&>(other);
  case eUnionType:
    return
      static_cast<const class UnionTypeExpression&>(*this) ==
      static_cast<const class UnionTypeExpression&>(other);
  case eVector:
    return
      static_cast<const class VectorExpression&>(*this) ==
      static_cast<const class VectorExpression&>(other);
  case eVectorIndex:
    return
      static_cast<const class VectorIndex&>(*this) ==
      static_cast<const class VectorIndex&>(other);
  case eVectorAssign:
    return
      static_cast<const class VectorAssign&>(*this) ==
      static_cast<const class VectorAssign&>(other);
  case eVectorShift:
    return
      static_cast<const class VectorShift&>(*this) ==
      static_cast<const class VectorShift&>(other);
  case eUnop:
    return
      static_cast<const class UnopExpression&>(*this) ==
      static_cast<const class UnopExpression&>(other);
  case eBinop:
    return
      static_cast<const class BinopExpression&>(*this) ==
      static_cast<const class BinopExpression&>(other);
  case eBooleanBinop:
    return
      static_cast<const class BooleanBinop&>(*this) ==
      static_cast<const class BooleanBinop&>(other);
  case eNot:
    return
      static_cast<const class NotExpression&>(*this) ==
      static_cast<const class NotExpression&>(other);
  case eRelop:
    return
      static_cast<const class RelopExpression&>(*this) ==
      static_cast<const class RelopExpression&>(other);
  case eBuffer:
    return
      static_cast<const class BufferExpression&>(*this) ==
      static_cast<const class BufferExpression&>(other);
  case eBufferUnop:
    return
      static_cast<const class BufferUnop&>(*this) ==
      static_cast<const class BufferUnop&>(other);
  case eBufferRemove:
    return
      static_cast<const class BufferRemove&>(*this) ==
      static_cast<const class BufferRemove&>(other);
  case eBufferWrite:
    return
      static_cast<const class BufferWrite&>(*this) ==
      static_cast<const class BufferWrite&>(other);
  case eBufferIndex:
    return
      static_cast<const class BufferIndex&>(*this) ==
      static_cast<const class BufferIndex&>(other);
  case eSet:
    return
      static_cast<const class SetExpression&>(*this) ==
      static_cast<const class SetExpression&>(other);
  case eIfThenElse:
    return
      static_cast<const class IfThenElse&>(*this) ==
      static_cast<const class IfThenElse&>(other);
  case eTemporalBinop:
    return
      static_cast<const class TemporalBinop&>(*this) ==
      static_cast<const class TemporalBinop&>(other);
  case eTemporalUnop:
    return
      static_cast<const class TemporalUnop&>(*this) ==
      static_cast<const class TemporalUnop&>(other);
  case eTypecast:
    return
      static_cast<const class Typecast&>(*this) ==
      static_cast<const class Typecast&>(other);
  case eCardinality:
    return
      static_cast<const class CardinalityExpression&>(*this) ==
      static_cast<const class CardinalityExpression&>(other);
  case eMarking:
    return
      static_cast<const class Marking&>(*this) ==
      static_cast<const class Marking&>(other);
  case eTransitionQualifier:
    return
      static_cast<const class TransitionQualifier&>(*this) ==
      static_cast<const class TransitionQualifier&>(other);
  case ePlaceContents:
    return
      static_cast<const class PlaceContents&>(*this) ==
      static_cast<const class PlaceContents&>(other);
  case eSubmarking:
    return
      static_cast<const class Submarking&>(*this) ==
      static_cast<const class Submarking&>(other);
  case eMapping:
    return
      static_cast<const class Mapping&>(*this) ==
      static_cast<const class Mapping&>(other);
  case eEmptySet:
    return
      static_cast<const class EmptySet&>(*this) ==
      static_cast<const class EmptySet&>(other);
  }

  assert (false);
  return false;
}

bool
Expression::operator< (const class Expression& other) const
{
  if (this == &other)
    return false;
  if (getKind () < other.getKind ())
    return true;
  if (getKind () > other.getKind ())
    return false;
  if (getType () < other.getType ())
    return true;
  if (getType () > other.getType ())
    return false;

  switch (getKind ()) {
  case eVariable:
    return
      static_cast<const class Variable&>(*this) <
      static_cast<const class Variable&>(other);
  case eConstant:
    return
      static_cast<const class Constant&>(*this) <
      static_cast<const class Constant&>(other);
  case eUndefined:
    return
      static_cast<const class Undefined&>(*this) <
      static_cast<const class Undefined&>(other);
  case eStruct:
    return
      static_cast<const class StructExpression&>(*this) <
      static_cast<const class StructExpression&>(other);
  case eStructComponent:
    return
      static_cast<const class StructComponent&>(*this) <
      static_cast<const class StructComponent&>(other);
  case eStructAssign:
    return
      static_cast<const class StructAssign&>(*this) <
      static_cast<const class StructAssign&>(other);
  case eUnion:
    return
      static_cast<const class UnionExpression&>(*this) <
      static_cast<const class UnionExpression&>(other);
  case eUnionComponent:
    return
      static_cast<const class UnionComponent&>(*this) <
      static_cast<const class UnionComponent&>(other);
  case eUnionType:
    return
      static_cast<const class UnionTypeExpression&>(*this) <
      static_cast<const class UnionTypeExpression&>(other);
  case eVector:
    return
      static_cast<const class VectorExpression&>(*this) <
      static_cast<const class VectorExpression&>(other);
  case eVectorIndex:
    return
      static_cast<const class VectorIndex&>(*this) <
      static_cast<const class VectorIndex&>(other);
  case eVectorAssign:
    return
      static_cast<const class VectorAssign&>(*this) <
      static_cast<const class VectorAssign&>(other);
  case eVectorShift:
    return
      static_cast<const class VectorShift&>(*this) <
      static_cast<const class VectorShift&>(other);
  case eUnop:
    return
      static_cast<const class UnopExpression&>(*this) <
      static_cast<const class UnopExpression&>(other);
  case eBinop:
    return
      static_cast<const class BinopExpression&>(*this) <
      static_cast<const class BinopExpression&>(other);
  case eBooleanBinop:
    return
      static_cast<const class BooleanBinop&>(*this) <
      static_cast<const class BooleanBinop&>(other);
  case eNot:
    return
      static_cast<const class NotExpression&>(*this) <
      static_cast<const class NotExpression&>(other);
  case eRelop:
    return
      static_cast<const class RelopExpression&>(*this) <
      static_cast<const class RelopExpression&>(other);
  case eBuffer:
    return
      static_cast<const class BufferExpression&>(*this) <
      static_cast<const class BufferExpression&>(other);
  case eBufferUnop:
    return
      static_cast<const class BufferUnop&>(*this) <
      static_cast<const class BufferUnop&>(other);
  case eBufferRemove:
    return
      static_cast<const class BufferRemove&>(*this) <
      static_cast<const class BufferRemove&>(other);
  case eBufferWrite:
    return
      static_cast<const class BufferWrite&>(*this) <
      static_cast<const class BufferWrite&>(other);
  case eBufferIndex:
    return
      static_cast<const class BufferIndex&>(*this) <
      static_cast<const class BufferIndex&>(other);
  case eSet:
    return
      static_cast<const class SetExpression&>(*this) <
      static_cast<const class SetExpression&>(other);
  case eIfThenElse:
    return
      static_cast<const class IfThenElse&>(*this) <
      static_cast<const class IfThenElse&>(other);
  case eTemporalBinop:
    return
      static_cast<const class TemporalBinop&>(*this) <
      static_cast<const class TemporalBinop&>(other);
  case eTemporalUnop:
    return
      static_cast<const class TemporalUnop&>(*this) <
      static_cast<const class TemporalUnop&>(other);
  case eTypecast:
    return
      static_cast<const class Typecast&>(*this) <
      static_cast<const class Typecast&>(other);
  case eCardinality:
    return
      static_cast<const class CardinalityExpression&>(*this) <
      static_cast<const class CardinalityExpression&>(other);
  case eMarking:
    return
      static_cast<const class Marking&>(*this) <
      static_cast<const class Marking&>(other);
  case eTransitionQualifier:
    return
      static_cast<const class TransitionQualifier&>(*this) <
      static_cast<const class TransitionQualifier&>(other);
  case ePlaceContents:
    return
      static_cast<const class PlaceContents&>(*this) <
      static_cast<const class PlaceContents&>(other);
  case eSubmarking:
    return
      static_cast<const class Submarking&>(*this) <
      static_cast<const class Submarking&>(other);
  case eMapping:
    return
      static_cast<const class Mapping&>(*this) <
      static_cast<const class Mapping&>(other);
  case eEmptySet:
    return
      static_cast<const class EmptySet&>(*this) <
      static_cast<const class EmptySet&>(other);
  }

  assert (false);
  return false;
}

class Value*
Expression::do_eval (const class Valuation&) const
{
  assert (false);
  return 0;
}

class Expression*
Expression::ground (const class Valuation& valuation)
{
  assert (valuation.isOK ());

  if (!isBasic () || getKind () == eConstant);
  else if (class Value* v = eval (valuation)) {
    destroy ();
    return (new class Constant (*v))->cse ();
  }
  else if (!valuation.isOKorVar ()) {
    destroy ();
    return 0;
  }
  valuation.clearErrors ();
  return cse ();
}

class PlaceMarking*
Expression::meval (const class Valuation&) const
{
  assert (false);
  return 0;
}

bool
Expression::isTypeCompatible (const class Value& value) const
{
  return isAssignable (value.getType ());
}

bool
Expression::isCompatible (const class Value& value,
			  const class Valuation& valuation) const
{
  assert (isTypeCompatible (value));

  if (class Value* v = eval (valuation)) {
    bool compatible = value == *v;
    delete v;
    return compatible;
  }
  assert (!valuation.isOK ());
  if (valuation.getError () != errVar)
    return false;
  valuation.clearErrors ();
  return true;
}

void
Expression::getLvalues (const class Value&,
			class Valuation&,
			const class VariableSet&) const
{
}

void
Expression::getLvalues (const class VariableSet&,
			class VariableSet*&) const
{
}

class Ltl*
Expression::toFormula (class Property& property)
{
  assert (getType () && getType ()->getKind () == Type::tBool);
  return property.addExpression (*this);
}

class Expression*
Expression::disqualify (const class Transition&)
{
  return copy ();
}

#ifdef EXPR_COMPILE
# include "CExpression.h"

void
Expression::compileLvalue (class CExpression&,
			   unsigned,
			   const class VariableSet&,
			   const char*) const
{
}

void
Expression::compileCompatible (class CExpression& cexpr,
			       unsigned indent,
			       const class VariableSet& vars,
			       const char* value) const
{
  if (myType->getNumValues () == 1 || depends (vars, true))
    return;
  bool* checkpoint = 0;
  unsigned checkpointSize = cexpr.getCheckpoint (checkpoint);
  class StringBuffer& out = cexpr.getOut ();
  out.indent (indent);
  out.append ("do {\n");
  char* result;
  if (cexpr.getVariable (*this, result))
    compile (cexpr, indent + 2, result, &vars);
  out.indent (indent + 2);
  out.append ("if (");
  if (!myType->compileEqual (out, indent + 6, result, value,
			     false, true, true, false))
    out.append ("1");
  out.append (")\n");
  cexpr.compileError (indent + 4, errComp);
  out.indent (indent);
  out.append ("} while (0);\n");
  cexpr.setCheckpoint (indent, checkpoint, checkpointSize);
  delete[] checkpoint;
  delete[] result;
}

void
Expression::compileScalarMset (class CExpression& cexpr,
			       unsigned indent,
			       const char* result,
			       const class VariableSet* vars,
			       bool check) const
{
  class StringBuffer& out = cexpr.getOut ();
  char* tmp;
  if (cexpr.getVariable (*this, tmp))
    compileMset (cexpr, indent, 0, tmp, vars);
  if (check) {
    out.indent (indent);
    out.append ("if (");
    out.append (result);
    out.append (" && singleton (");
    out.append (tmp);
    out.append ("))\n");
    cexpr.compileError (indent + 2, errConst);
  }
  out.indent (indent);
  out.append (result);
  out.append (" = singleton (");
  out.append (tmp);
  out.append (");\n");
  delete[] tmp;
}

void
Expression::compileMset (class CExpression&,
			 unsigned,
			 const char*,
			 const char*,
			 const class VariableSet*) const
{
  assert (getKind () == eEmptySet);
}

#endif // EXPR_COMPILE
