// Enumerated type class -*- c++ -*-

#ifndef ENUMTYPE_H_
# define ENUMTYPE_H_
# ifdef __GNUC__
#  pragma interface
# endif // __GNUC__

# include <map>
# include "Type.h"

/** @file EnumType.h
 * Enumerated data type
 */

/* Copyright © 1998-2001 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. */

/** Enumerated type */
class EnumType : public Type
{
public:
  /** Constructor */
  EnumType ();
  /** Copy constructor */
  EnumType (const class EnumType& old);
private:
  /** Assignment operator */
  class EnumType& operator= (const class EnumType& old);
public:
  /** Destructor */
  ~EnumType ();
  /** Copy the Type */
  class Type* copy () const { return new class EnumType (*this); }

  /** Add an enumeration symbol
   * @param name	name of the symbol
   * @param value	numeric value of the symbol
   */
  void addEnumeration (char* name, card_t value);
  /** Add an enumeration symbol
   * @param name	name of the symbol
   */
  void addEnumeration (char* name) { addEnumeration (name, myNextValue); }

  /** Get the value of an enumeration symbol
   * @param name	name of the symbol
   * @return		pointer to the value, or NULL if not found
   */
  const card_t* getValue (const char* name) const;

  /** Get the first enumeration value */
  card_t getFirstEnum () const;
  /** Get the last enumeration value */
  card_t getLastEnum () const;

  /** Determine whether the given value exists in the enumeration
   * @param value	the enumeration value
   * @return		true if the value exists in the enumeration
   */
  bool hasValue (card_t value) const;

  /** Get the name of an enumeration constant
   * @param value	numeric value of the constant
   * @return		the name, or NULL if not found
   */
  const char* getEnumName (card_t value) const;

  /** Determine the kind of the type */
  enum Kind getKind () const { return tEnum; }

  /** Get the first value of this type */
  class Value& getFirstValue () const;
  /** Get the last value of this type */
  class Value& getLastValue () const;

  /** See if the type is assignable to another type
   * @param type	the type this type should be assignable to
   * @return		true if this type is assignable to the type
   */
  bool isAssignable (const class Type& type) const { return &type == this; }

  /** Determine whether a value is compatible with the constraints of this type
   * @param value	value to check
   * @return		true if the value passes the constraint check
   */
  bool isConstrained (const class Value& value) const;

  /** Get the number of possible values for this type */
  card_t do_getNumValues () const;

  /** Convert a value of this type to a number
   * @param value	value to be converted
   * @return		number between 0 and getNumValues () - 1
   */
  card_t convert (const class Value& value) const;

  /** Convert a number to a value of this type
   * @param number	number between 0 and getNumValues () - 1
   * @return		the corresponding value
   */
  class Value* convert (card_t number) const;

# ifdef EXPR_COMPILE
  /** Generate a C type declaration
   * @param out		output stream for the declarations
   * @param indent	indentation level
   */
  void compileDefinition (class StringBuffer& out,
			  unsigned indent) const;

  /** Emit code for converting an unconstrained value to a number
   * @param out		output stream
   * @param indent	indentation level
   * @param value	value to be converted
   * @param number	number to be computed
   * @param add		flag: add to number instead of assigning
   */
  void do_compileConversion (class StringBuffer& out,
			     unsigned indent,
			     const char* value,
			     const char* number,
			     bool add) const;
# endif // EXPR_COMPILE

  /** Display the type definition
   * @param printer	the printer object
   */
  void display (const class Printer& printer) const;

private:
  /** Map of enumeration symbol names to enumeration symbol values */
  typedef std::map<char*,card_t,struct ltstr> EnumMap;
  /** Enumeration symbols */
  EnumMap myEnums;
  typedef std::map<card_t,const char*> ReverseMap;
  /** Reverse map from constants to symbols */
  ReverseMap myReverseMap;
  /** Default value for next enumeration symbol that is declared */
  card_t myNextValue;
};

#endif // ENUMTYPE_H_
