%if false
  Copyright (c) 2009 ETH Zurich.
  All rights reserved.

  This file is distributed under the terms in the attached LICENSE file.
  If you do not find this file, copies can be found by writing to:
  ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
%endif

%include polycode.fmt

%if false

> module Constructs.Enumerations where

> import Data.Maybe 

> import Semantics
> import Constructs
> import PureExpressions
> import {-# SOURCE #-} Expressions

> import IL.FoF.FoF
> import IL.FoF.Compile

%endif

\section{Enumeration}

The |Enumeration| construct mirrors the @enum@ data-type of C. It
allows us to name a finite number of natural constants and manipulate
these names instead of numbers.

\subsection{Smart Constructors}

The |newEnum| combinator is used to create a member |value| belonging
to one of the |fields| of |nameEnum|.

> newEnum :: String ->
>            Enumeration ->
>            String ->
>            FoFCode PureExpr
> newEnum nameEnum fields value =
>     inject (NewEnum Nothing nameEnum fields value return)

Similarly, |newEnumN| creates a named member of an enumeration.

> newEnumN :: String ->
>            String ->
>            Enumeration ->
>            String ->
>            FoFCode PureExpr
> newEnumN name nameEnum fields value =
>     inject (NewEnum (Just name) name fields value return)

\subsection{Compile Instantiation}

A |NewEnum| is compiled as follow.

> compileEnumerations (NewEnum name enumName vals value r) binding = 
>     (FStatement (FNewEnum publicName enumName vals value) cont, 
>      binding3)
>         where (publicName, binding2) 
>                   = case name of
>                       Just x -> (Provided x, binding)
>                       Nothing -> (makeVarName Local loc,
>                                   binding1)
>                           where (loc, binding1) = getFreshVar binding 
>               ret = CLRef Global uint64T (Provided value) 
>               (cont, binding3) = r ret binding2

Note that |ret| is actually the name of the enumerated value: it is
treated as a constant and passed as such to the remaining code. A more
standard implementation would have been to create a variable
containing this constant value and pass the reference to the variable
to the subsequent code. However, when |switch|-ing over an enumerated
value, the case would match a variable instead of a constant, which is
refused by the C compiler.

Clearly, a clean solution to this implementation must be
found. However, the current solution, if not perfect, seems to be good
enough.

\subsection{Run Instantiation}

Running a |newEnum| simply consists in getting the associated value.

> runEnumerations (NewEnum _ _ enum name r) heap =
>     let ref = uint64 $ toInteger $ fromJust $ name `lookup` enum in
>     r ref heap 
