--  C->Haskell Compiler: traversals of C structure tree
--
--  Author : Manuel M. T. Chakravarty
--  Created: 16 October 99
--
--  Version $Revision: 1.1 $ from $Date: 2004/11/21 21:05:27 $
--
--  Copyright (c) [1999..2001] Manuel M. T. Chakravarty
--
--  This file 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 of the License, or
--  (at your option) any later version.
--
--  This file 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.
--
--- DESCRIPTION ---------------------------------------------------------------
--
--  This modules provides for traversals of C structure trees.  The C
--  traversal monad supports traversals that need convenient access to the
--  attributes of an attributed C structure tree.  The monads state can still
--  be extended.
--
--- DOCU ----------------------------------------------------------------------
--
--  language: Haskell 98
--
--  Handling of redefined tag values
--  --------------------------------
--
--  Structures allow both
--
--    struct s {...} ...;
--    struct s       ...;
--
--  and
--
--    struct s       ...;       /* this is called a forward reference */
--    struct s {...} ...;
--
--  In contrast enumerations only allow (in ANSI C)
--
--    enum e {...} ...;
--    enum e       ...;
--
--  The function `defTag' handles both types and establishes an object
--  association from the tag identifier in the empty declaration (ie, the one
--  without `{...}') to the actually definition of the structure of
--  enumeration.  This implies that when looking for the details of a
--  structure or enumeration, possibly a chain of references on tag
--  identifiers has to be chased.  Note that the object association attribute
--  is _not_defined_ when the `{...}'  part is present in a declaration.
--
--- TODO ----------------------------------------------------------------------
--
--  * `extractStruct' doesn't account for forward declarations that have no
--   full declaration yet; if `extractStruct' is called on such a declaration, 
--   we have a user error, but currently an internal error is raised
--

module CTrav (CT, readCT, transCT, getCHeaderCT, runCT, throwCTExc, ifCTExc,
              raiseErrorCTExc,
              enter, enterObjs, leave, leaveObjs, defObj, findObj,
              findObjShadow, defTag, findTag, findTagShadow,
              applyPrefixToNameSpaces, getDefOf, refersToDef, refersToNewDef,
              getDeclOf, findTypeObjMaybe, findTypeObj, findValueObj,
              findFunObj,
              --
              -- C structure tree query functions
              --
              isTypedef, simplifyDecl, declrFromDecl, declrNamed,
              declaredDeclr, declaredName, structMembers, expandDecl,
              structName, enumName, tagName, isArrDeclr, isPtrDeclr, dropPtrDeclr,
              isPtrDecl, isFunDeclr, structFromDecl, funResultAndArgs,
              chaseDecl, findAndChaseDecl, checkForAlias,
              checkForOneAliasName, lookupEnum, lookupStructUnion,
              lookupDeclOrTag)
where

import Data.List       (find)
import Data.Maybe         (fromMaybe)
import Control.Monad      (liftM)
import Control.Exception (assert)

import Position   (Position, Pos(..), nopos)
import Errors     (interr)
import Idents     (Ident, dumpIdent, identToLexeme)
import Attributes (Attr(..), newAttrsOnlyPos)

import C2HSState  (CST, nop, readCST, transCST, runCST, raiseError, catchExc,
                   throwExc, Traces(..), putTraceStr)
import CAST
import CAttrs     (AttrC, getCHeader, enterNewRangeC, enterNewObjRangeC,
                   leaveRangeC, leaveObjRangeC, addDefObjC, lookupDefObjC,
                   lookupDefObjCShadow, addDefTagC, lookupDefTagC,
                   lookupDefTagCShadow, applyPrefix, getDefOfIdentC,
                   setDefOfIdentC, updDefOfIdentC, CObj(..), CTag(..),
                   CDef(..)) 


-- the C traversal monad
-- ---------------------

-- C traversal monad (EXPORTED ABSTRACTLY)
--
type CState s    = (AttrC, s)
type CT     s a  = CST (CState s) a

-- read attributed struture tree
--
readAttrCCT        :: (AttrC -> a) -> CT s a
readAttrCCT :: forall a s. (AttrC -> a) -> CT s a
readAttrCCT AttrC -> a
reader  = forall s a e. (s -> a) -> PreCST e s a
readCST forall a b. (a -> b) -> a -> b
$ \(AttrC
ac, s
_) -> AttrC -> a
reader AttrC
ac

-- transform attributed structure tree
--
transAttrCCT       :: (AttrC -> (AttrC, a)) -> CT s a
transAttrCCT :: forall a s. (AttrC -> (AttrC, a)) -> CT s a
transAttrCCT AttrC -> (AttrC, a)
trans  = forall s a e. (s -> (s, a)) -> PreCST e s a
transCST forall a b. (a -> b) -> a -> b
$ \(AttrC
ac, s
s) -> let
                                               (AttrC
ac', a
r) = AttrC -> (AttrC, a)
trans AttrC
ac
                                             in
                                             ((AttrC
ac', s
s), a
r)

-- access to the user-defined state
--

-- read user-defined state (EXPORTED)
--
readCT        :: (s -> a) -> CT s a
readCT :: forall s a. (s -> a) -> CT s a
readCT s -> a
reader  = forall s a e. (s -> a) -> PreCST e s a
readCST forall a b. (a -> b) -> a -> b
$ \(AttrC
_, s
s) -> s -> a
reader s
s

-- transform user-defined state (EXPORTED)
--
transCT       :: (s -> (s, a)) -> CT s a
transCT :: forall s a. (s -> (s, a)) -> CT s a
transCT s -> (s, a)
trans  = forall s a e. (s -> (s, a)) -> PreCST e s a
transCST forall a b. (a -> b) -> a -> b
$ \(AttrC
ac, s
s) -> let
                                          (s
s', a
r) = s -> (s, a)
trans s
s
                                        in
                                        ((AttrC
ac, s
s'), a
r)

-- usage of a traversal monad
--

-- get the raw C header from the monad (EXPORTED)
--
getCHeaderCT :: CT s CHeader
getCHeaderCT :: forall s. CT s CHeader
getCHeaderCT  = forall a s. (AttrC -> a) -> CT s a
readAttrCCT AttrC -> CHeader
getCHeader

-- execute a traversal monad (EXPORTED)
--
--  * given a traversal monad, an attribute structure tree, and a user
--   state, the transformed structure tree and monads result are returned
--
runCT        :: CT s a -> AttrC -> s -> CST t (AttrC, a)
runCT :: forall s a t. CT s a -> AttrC -> s -> CST t (AttrC, a)
runCT CT s a
m AttrC
ac s
s  = forall e s a s'. PreCST e s a -> s -> PreCST e s' a
runCST PreCST SwitchBoard (CState s) (AttrC, a)
m' (AttrC
ac, s
s)
                where
                  m' :: PreCST SwitchBoard (CState s) (AttrC, a)
m' = do
                         a
r <- CT s a
m
                         (AttrC
ac, s
_) <- forall s a e. (s -> a) -> PreCST e s a
readCST forall a. a -> a
id
                         forall (m :: * -> *) a. Monad m => a -> m a
return (AttrC
ac, a
r)


-- exception handling
-- ------------------

-- exception identifier
--
ctExc :: String
ctExc :: String
ctExc  = String
"ctExc"

-- throw an exception  (EXPORTED)
--
throwCTExc :: CT s a
throwCTExc :: forall s a. CT s a
throwCTExc  = forall e s a. String -> String -> PreCST e s a
throwExc String
ctExc String
"Error during traversal of a C structure tree"

-- catch a `ctExc'  (EXPORTED)
--
ifCTExc           :: CT s a -> CT s a -> CT s a
ifCTExc :: forall s a. CT s a -> CT s a -> CT s a
ifCTExc CT s a
m CT s a
handler  = CT s a
m forall e s a.
PreCST e s a -> (String, String -> PreCST e s a) -> PreCST e s a
`catchExc` (String
ctExc, forall a b. a -> b -> a
const CT s a
handler)

-- raise an error followed by throwing a CT exception (EXPORTED)
--
raiseErrorCTExc          :: Position -> [String] -> CT s a
raiseErrorCTExc :: forall s a. Position -> [String] -> CT s a
raiseErrorCTExc Position
pos [String]
errs  = forall e s. Position -> [String] -> PreCST e s ()
raiseError Position
pos [String]
errs forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall s a. CT s a
throwCTExc


-- attribute manipulation
-- ----------------------

-- name spaces
--

-- enter a new local range (EXPORTED)
--
enter :: CT s ()
enter :: forall s. CT s ()
enter  = forall a s. (AttrC -> (AttrC, a)) -> CT s a
transAttrCCT forall a b. (a -> b) -> a -> b
$ \AttrC
ac -> (AttrC -> AttrC
enterNewRangeC AttrC
ac, ())

-- enter a new local range, only for objects (EXPORTED)
--
enterObjs :: CT s ()
enterObjs :: forall s. CT s ()
enterObjs  = forall a s. (AttrC -> (AttrC, a)) -> CT s a
transAttrCCT forall a b. (a -> b) -> a -> b
$ \AttrC
ac -> (AttrC -> AttrC
enterNewObjRangeC AttrC
ac, ())

-- leave the current local range (EXPORTED)
--
leave :: CT s ()
leave :: forall s. CT s ()
leave  = forall a s. (AttrC -> (AttrC, a)) -> CT s a
transAttrCCT forall a b. (a -> b) -> a -> b
$ \AttrC
ac -> (AttrC -> AttrC
leaveRangeC AttrC
ac, ())

-- leave the current local range, only for objects (EXPORTED)
--
leaveObjs :: CT s ()
leaveObjs :: forall s. CT s ()
leaveObjs  = forall a s. (AttrC -> (AttrC, a)) -> CT s a
transAttrCCT forall a b. (a -> b) -> a -> b
$ \AttrC
ac -> (AttrC -> AttrC
leaveObjRangeC AttrC
ac, ())

-- enter an object definition into the object name space (EXPORTED)
--
--  * if a definition of the same name was already present, it is returned 
--
defObj         :: Ident -> CObj -> CT s (Maybe CObj)
defObj :: forall s. Ident -> CObj -> CT s (Maybe CObj)
defObj Ident
ide CObj
obj  = forall a s. (AttrC -> (AttrC, a)) -> CT s a
transAttrCCT forall a b. (a -> b) -> a -> b
$ \AttrC
ac -> AttrC -> Ident -> CObj -> (AttrC, Maybe CObj)
addDefObjC AttrC
ac Ident
ide CObj
obj

-- find a definition in the object name space (EXPORTED)
--
findObj     :: Ident -> CT s (Maybe CObj)
findObj :: forall s. Ident -> CT s (Maybe CObj)
findObj Ident
ide  = forall a s. (AttrC -> a) -> CT s a
readAttrCCT forall a b. (a -> b) -> a -> b
$ \AttrC
ac -> AttrC -> Ident -> Maybe CObj
lookupDefObjC AttrC
ac Ident
ide

-- find a definition in the object name space; if nothing found, try 
-- whether there is a shadow identifier that matches (EXPORTED)
--
findObjShadow     :: Ident -> CT s (Maybe (CObj, Ident))
findObjShadow :: forall s. Ident -> CT s (Maybe (CObj, Ident))
findObjShadow Ident
ide  = forall a s. (AttrC -> a) -> CT s a
readAttrCCT forall a b. (a -> b) -> a -> b
$ \AttrC
ac -> AttrC -> Ident -> Maybe (CObj, Ident)
lookupDefObjCShadow AttrC
ac Ident
ide

-- enter a tag definition into the tag name space (EXPORTED)
--
--  * empty definitions of structures get overwritten with complete ones and a
--   forward reference is added to their tag identifier; furthermore, both
--   structures and enums may be referenced using an empty definition when
--   there was a full definition earlier and in this case there is also an
--   object association added; otherwise, if a definition of the same name was
--   already present, it is returned (see DOCU section)
--
--  * it is checked that the first occurence of an enumeration tag is
--   accompanied by a full definition of the enumeration
--
defTag         :: Ident -> CTag -> CT s (Maybe CTag)
defTag :: forall s. Ident -> CTag -> CT s (Maybe CTag)
defTag Ident
ide CTag
tag  = 
  do
    Maybe CTag
otag <- forall a s. (AttrC -> (AttrC, a)) -> CT s a
transAttrCCT forall a b. (a -> b) -> a -> b
$ \AttrC
ac -> AttrC -> Ident -> CTag -> (AttrC, Maybe CTag)
addDefTagC AttrC
ac Ident
ide CTag
tag
    case Maybe CTag
otag of
      Maybe CTag
Nothing      -> do
                        forall s. CTag -> CT s ()
assertIfEnumThenFull CTag
tag
                        forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing                  -- no collision
      Just CTag
prevTag -> case CTag -> CTag -> Maybe (CTag, Ident)
isRefinedOrUse CTag
prevTag CTag
tag of
                         Maybe (CTag, Ident)
Nothing                 -> forall (m :: * -> *) a. Monad m => a -> m a
return Maybe CTag
otag
                         Just (CTag
fullTag, Ident
foreIde) -> do
                           forall a s. (AttrC -> (AttrC, a)) -> CT s a
transAttrCCT forall a b. (a -> b) -> a -> b
$ \AttrC
ac -> AttrC -> Ident -> CTag -> (AttrC, Maybe CTag)
addDefTagC AttrC
ac Ident
ide CTag
fullTag
                           Ident
foreIde forall s. Ident -> CDef -> CT s ()
`refersToDef` CTag -> CDef
TagCD CTag
fullTag
                           forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing               -- transparent for env
  where
    -- compute whether we have the case of a non-conflicting redefined tag
    -- definition, and if so, return the full definition and the foreward 
    -- definition's tag identifier
    --
    --  * the first argument contains the _previous_ definition
    --
    --  * in the case of a structure, a foreward definition after a full
    --   definition is allowed, so we have to handle this case; enumerations
    --   don't allow foreward definitions
    --
    --  * there may also be multiple foreward definition; if we have two of
    --   them here, one is arbitrarily selected to take the role of the full
    --   definition 
    --
    isRefinedOrUse :: CTag -> CTag -> Maybe (CTag, Ident)
isRefinedOrUse     (StructUnionCT (CStruct CStructTag
_ (Just Ident
ide) [] Attrs
_))
                   tag :: CTag
tag@(StructUnionCT (CStruct CStructTag
_ (Just Ident
_  ) [CDecl]
_  Attrs
_)) = 
      forall a. a -> Maybe a
Just (CTag
tag, Ident
ide)
    isRefinedOrUse tag :: CTag
tag@(StructUnionCT (CStruct CStructTag
_ (Just Ident
_  ) [CDecl]
_  Attrs
_))
                       (StructUnionCT (CStruct CStructTag
_ (Just Ident
ide) [] Attrs
_)) = 
      forall a. a -> Maybe a
Just (CTag
tag, Ident
ide)
    isRefinedOrUse tag :: CTag
tag@(EnumCT        (CEnum (Just Ident
_  ) [(Ident, Maybe CExpr)]
_  Attrs
_))
                       (EnumCT        (CEnum (Just Ident
ide) [] Attrs
_))     = 
      forall a. a -> Maybe a
Just (CTag
tag, Ident
ide)
    isRefinedOrUse CTag
_ CTag
_                                             = forall a. Maybe a
Nothing

-- find an definition in the tag name space (EXPORTED)
--
findTag     :: Ident -> CT s (Maybe CTag)
findTag :: forall s. Ident -> CT s (Maybe CTag)
findTag Ident
ide  = forall a s. (AttrC -> a) -> CT s a
readAttrCCT forall a b. (a -> b) -> a -> b
$ \AttrC
ac -> AttrC -> Ident -> Maybe CTag
lookupDefTagC AttrC
ac Ident
ide

-- find an definition in the tag name space; if nothing found, try 
-- whether there is a shadow identifier that matches (EXPORTED)
--
findTagShadow     :: Ident -> CT s (Maybe (CTag, Ident))
findTagShadow :: forall s. Ident -> CT s (Maybe (CTag, Ident))
findTagShadow Ident
ide  = forall a s. (AttrC -> a) -> CT s a
readAttrCCT forall a b. (a -> b) -> a -> b
$ \AttrC
ac -> AttrC -> Ident -> Maybe (CTag, Ident)
lookupDefTagCShadow AttrC
ac Ident
ide

-- enrich the object and tag name space with identifiers obtained by dropping
-- the given prefix from the identifiers already in the name space (EXPORTED)
--
--  * if a new identifier would collides with an existing one, the new one is
--   discarded, ie, all associations that existed before the transformation
--   started are still in effect after the transformation
-- 
applyPrefixToNameSpaces        :: String -> CT s ()
applyPrefixToNameSpaces :: forall s. String -> CT s ()
applyPrefixToNameSpaces String
prefix  = 
  forall a s. (AttrC -> (AttrC, a)) -> CT s a
transAttrCCT forall a b. (a -> b) -> a -> b
$ \AttrC
ac -> (AttrC -> String -> AttrC
applyPrefix AttrC
ac String
prefix, ())

-- definition attribute
--

-- get the definition of an identifier (EXPORTED) 
--
--  * the attribute must be defined, ie, a definition must be associated with
--   the given identifier
--
getDefOf     :: Ident -> CT s CDef
getDefOf :: forall s. Ident -> CT s CDef
getDefOf Ident
ide  = do
                  CDef
def <- forall a s. (AttrC -> a) -> CT s a
readAttrCCT forall a b. (a -> b) -> a -> b
$ \AttrC
ac -> AttrC -> Ident -> CDef
getDefOfIdentC AttrC
ac Ident
ide
                  forall a. (?callStack::CallStack) => Bool -> a -> a
assert (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Attr a => a -> Bool
isUndef forall a b. (a -> b) -> a -> b
$ CDef
def) forall a b. (a -> b) -> a -> b
$
                    forall (m :: * -> *) a. Monad m => a -> m a
return CDef
def

-- set the definition of an identifier (EXPORTED) 
--
refersToDef         :: Ident -> CDef -> CT s ()
refersToDef :: forall s. Ident -> CDef -> CT s ()
refersToDef Ident
ide CDef
def  = forall a s. (AttrC -> (AttrC, a)) -> CT s a
transAttrCCT forall a b. (a -> b) -> a -> b
$ \AttrC
akl -> (AttrC -> Ident -> CDef -> AttrC
setDefOfIdentC AttrC
akl Ident
ide CDef
def, ())

-- update the definition of an identifier (EXPORTED) 
--
refersToNewDef         :: Ident -> CDef -> CT s ()
refersToNewDef :: forall s. Ident -> CDef -> CT s ()
refersToNewDef Ident
ide CDef
def  = 
  forall a s. (AttrC -> (AttrC, a)) -> CT s a
transAttrCCT forall a b. (a -> b) -> a -> b
$ \AttrC
akl -> (AttrC -> Ident -> CDef -> AttrC
updDefOfIdentC AttrC
akl Ident
ide CDef
def, ())

-- get the declarator of an identifier (EXPORTED)
--
getDeclOf     :: Ident -> CT s CDecl
getDeclOf :: forall s. Ident -> CT s CDecl
getDeclOf Ident
ide  = 
  do
    forall s. CT s ()
traceEnter
    CDef
def <- forall s. Ident -> CT s CDef
getDefOf Ident
ide
    case CDef
def of
      CDef
UndefCD    -> forall a. String -> a
interr String
"CTrav.getDeclOf: Undefined!"
      CDef
DontCareCD -> forall a. String -> a
interr String
"CTrav.getDeclOf: Don't care!"
      TagCD CTag
_    -> forall a. String -> a
interr String
"CTrav.getDeclOf: Illegal tag!"
      ObjCD CObj
obj  -> case CObj
obj of
                      TypeCO    CDecl
decl -> forall s. CT s ()
traceTypeCO forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
                                        forall (m :: * -> *) a. Monad m => a -> m a
return CDecl
decl
                      ObjCO     CDecl
decl -> forall s. CT s ()
traceObjCO forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
                                        forall (m :: * -> *) a. Monad m => a -> m a
return CDecl
decl
                      EnumCO    Ident
_ CEnum
_  -> forall {a}. a
illegalEnum
                      CObj
BuiltinCO      -> forall {a}. a
illegalBuiltin
  where
    illegalEnum :: a
illegalEnum    = forall a. String -> a
interr String
"CTrav.getDeclOf: Illegal enum!"
    illegalBuiltin :: a
illegalBuiltin = forall a. String -> a
interr String
"CTrav.getDeclOf: Attempted to get declarator of \
                            \builtin entity!"
                     -- if the latter ever becomes necessary, we have to
                     -- change the representation of builtins and give them
                     -- some dummy declarator
    traceEnter :: CT s ()
traceEnter  = forall s. String -> CT s ()
traceCTrav forall a b. (a -> b) -> a -> b
$ 
                    String
"Entering `getDeclOf' for `" forall a. [a] -> [a] -> [a]
++ Ident -> String
identToLexeme Ident
ide 
                    forall a. [a] -> [a] -> [a]
++ String
"'...\n"
    traceTypeCO :: CT s ()
traceTypeCO = forall s. String -> CT s ()
traceCTrav forall a b. (a -> b) -> a -> b
$ 
                    String
"...found a type object.\n"
    traceObjCO :: CT s ()
traceObjCO  = forall s. String -> CT s ()
traceCTrav forall a b. (a -> b) -> a -> b
$ 
                    String
"...found a vanilla object.\n"


-- convenience functions
--

-- find a type object in the object name space; returns `nothing' if the
-- identifier is not defined (EXPORTED)
--
--  * if the second argument is `True', use `findObjShadow'
--
findTypeObjMaybe                :: Ident -> Bool -> CT s (Maybe (CObj, Ident))
findTypeObjMaybe :: forall s. Ident -> Bool -> CT s (Maybe (CObj, Ident))
findTypeObjMaybe Ident
ide Bool
useShadows  = 
  do
    Maybe (CObj, Ident)
oobj <- if Bool
useShadows 
            then forall s. Ident -> CT s (Maybe (CObj, Ident))
findObjShadow Ident
ide 
            else forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\CObj
obj -> (CObj
obj, Ident
ide))) forall a b. (a -> b) -> a -> b
$ forall s. Ident -> CT s (Maybe CObj)
findObj Ident
ide
    case Maybe (CObj, Ident)
oobj of
      Just obj :: (CObj, Ident)
obj@(TypeCO CDecl
_ , Ident
_) -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a
Just (CObj, Ident)
obj
      Just obj :: (CObj, Ident)
obj@(CObj
BuiltinCO, Ident
_) -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a
Just (CObj, Ident)
obj
      Just (CObj, Ident)
_                  -> forall s a. Ident -> CT s a
typedefExpectedErr Ident
ide
      Maybe (CObj, Ident)
Nothing                 -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. Maybe a
Nothing

-- find a type object in the object name space; raises an error and exception
-- if the identifier is not defined (EXPORTED)
--
--  * if the second argument is `True', use `findObjShadow'
--
findTypeObj                :: Ident -> Bool -> CT s (CObj, Ident)
findTypeObj :: forall s. Ident -> Bool -> CT s (CObj, Ident)
findTypeObj Ident
ide Bool
useShadows  = do
  Maybe (CObj, Ident)
oobj <- forall s. Ident -> Bool -> CT s (Maybe (CObj, Ident))
findTypeObjMaybe Ident
ide Bool
useShadows
  case Maybe (CObj, Ident)
oobj of
    Maybe (CObj, Ident)
Nothing  -> forall s a. Ident -> CT s a
unknownObjErr Ident
ide
    Just (CObj, Ident)
obj -> forall (m :: * -> *) a. Monad m => a -> m a
return (CObj, Ident)
obj

-- find an object, function, or enumerator in the object name space; raises an
-- error and exception if the identifier is not defined (EXPORTED)
--
--  * if the second argument is `True', use `findObjShadow'
--
findValueObj                :: Ident -> Bool -> CT s (CObj, Ident)
findValueObj :: forall s. Ident -> Bool -> CT s (CObj, Ident)
findValueObj Ident
ide Bool
useShadows  = 
  do
    Maybe (CObj, Ident)
oobj <- if Bool
useShadows 
            then forall s. Ident -> CT s (Maybe (CObj, Ident))
findObjShadow Ident
ide 
            else forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\CObj
obj -> (CObj
obj, Ident
ide))) forall a b. (a -> b) -> a -> b
$ forall s. Ident -> CT s (Maybe CObj)
findObj Ident
ide
    case Maybe (CObj, Ident)
oobj of
      Just obj :: (CObj, Ident)
obj@(ObjCO  CDecl
_  , Ident
_) -> forall (m :: * -> *) a. Monad m => a -> m a
return (CObj, Ident)
obj
      Just obj :: (CObj, Ident)
obj@(EnumCO Ident
_ CEnum
_, Ident
_) -> forall (m :: * -> *) a. Monad m => a -> m a
return (CObj, Ident)
obj
      Just (CObj, Ident)
_                   -> forall s a. Position -> CT s a
unexpectedTypedefErr (forall a. Pos a => a -> Position
posOf Ident
ide)
      Maybe (CObj, Ident)
Nothing                  -> forall s a. Ident -> CT s a
unknownObjErr Ident
ide

-- find a function in the object name space; raises an error and exception if
-- the identifier is not defined (EXPORTED) 
--
--  * if the second argument is `True', use `findObjShadow'
--
findFunObj               :: Ident -> Bool -> CT s  (CObj, Ident)
findFunObj :: forall s. Ident -> Bool -> CT s (CObj, Ident)
findFunObj Ident
ide Bool
useShadows = 
  do
    (CObj
obj, Ident
ide') <- forall s. Ident -> Bool -> CT s (CObj, Ident)
findValueObj Ident
ide Bool
useShadows
    case CObj
obj of
      EnumCO Ident
_ CEnum
_  -> forall s a. Position -> CT s a
funExpectedErr (forall a. Pos a => a -> Position
posOf Ident
ide)
      ObjCO  CDecl
decl -> do
                       let declr :: CDeclr
declr = Ident
ide' Ident -> CDecl -> CDeclr
`declrFromDecl` CDecl
decl
                       forall s. Position -> CDeclr -> CT s ()
assertFunDeclr (forall a. Pos a => a -> Position
posOf Ident
ide) CDeclr
declr
                       forall (m :: * -> *) a. Monad m => a -> m a
return (CObj
obj, Ident
ide')


-- C structure tree query routines
-- -------------------------------

-- test if this is a type definition specification (EXPORTED)
--
isTypedef                   :: CDecl -> Bool
isTypedef :: CDecl -> Bool
isTypedef (CDecl [CDeclSpec]
specs [(Maybe CDeclr, Maybe CInit, Maybe CExpr)]
_ Attrs
_)  = 
  Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t a -> Bool
null forall a b. (a -> b) -> a -> b
$ [() | CStorageSpec (CTypedef Attrs
_) <- [CDeclSpec]
specs]

-- discard all declarators but the one declaring the given identifier
-- (EXPORTED) 
--
--  * the declaration must contain the identifier
--
simplifyDecl :: Ident -> CDecl -> CDecl
Ident
ide simplifyDecl :: Ident -> CDecl -> CDecl
`simplifyDecl` (CDecl [CDeclSpec]
specs [(Maybe CDeclr, Maybe CInit, Maybe CExpr)]
declrs Attrs
at) =
  case forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (forall {b} {c}. (Maybe CDeclr, b, c) -> Ident -> Bool
`declrPlusNamed` Ident
ide) [(Maybe CDeclr, Maybe CInit, Maybe CExpr)]
declrs of
    Maybe (Maybe CDeclr, Maybe CInit, Maybe CExpr)
Nothing    -> forall {a}. a
err
    Just (Maybe CDeclr, Maybe CInit, Maybe CExpr)
declr -> [CDeclSpec]
-> [(Maybe CDeclr, Maybe CInit, Maybe CExpr)] -> Attrs -> CDecl
CDecl [CDeclSpec]
specs [(Maybe CDeclr, Maybe CInit, Maybe CExpr)
declr] Attrs
at
  where
    (Just CDeclr
declr, b
_, c
_) declrPlusNamed :: (Maybe CDeclr, b, c) -> Ident -> Bool
`declrPlusNamed` Ident
ide = CDeclr
declr CDeclr -> Ident -> Bool
`declrNamed` Ident
ide
    (Maybe CDeclr, b, c)
_                  `declrPlusNamed` Ident
_   = Bool
False
    --
    err :: a
err = forall a. String -> a
interr forall a b. (a -> b) -> a -> b
$ String
"CTrav.simplifyDecl: Wrong C object!\n\
                   \  Looking for `" forall a. [a] -> [a] -> [a]
++ Ident -> String
identToLexeme Ident
ide forall a. [a] -> [a] -> [a]
++ String
"' in decl \
                   \at " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (forall a. Pos a => a -> Position
posOf Attrs
at)

-- extract the declarator that declares the given identifier (EXPORTED)
--
--  * the declaration must contain the identifier
--
declrFromDecl            :: Ident -> CDecl -> CDeclr
Ident
ide declrFromDecl :: Ident -> CDecl -> CDeclr
`declrFromDecl` CDecl
decl  = 
  let CDecl [CDeclSpec]
_ [(Just CDeclr
declr, Maybe CInit
_, Maybe CExpr
_)] Attrs
_ = Ident
ide Ident -> CDecl -> CDecl
`simplifyDecl` CDecl
decl
  in
  CDeclr
declr

-- tests whether the given declarator has the given name (EXPORTED)
--
declrNamed             :: CDeclr -> Ident -> Bool
CDeclr
declr declrNamed :: CDeclr -> Ident -> Bool
`declrNamed` Ident
ide  = CDeclr -> Maybe Ident
declrName CDeclr
declr forall a. Eq a => a -> a -> Bool
== forall a. a -> Maybe a
Just Ident
ide

-- get the declarator of a declaration that has at most one declarator
-- (EXPORTED) 
--
declaredDeclr                              :: CDecl -> Maybe CDeclr
declaredDeclr :: CDecl -> Maybe CDeclr
declaredDeclr (CDecl [CDeclSpec]
_ []               Attrs
_)  = forall a. Maybe a
Nothing
declaredDeclr (CDecl [CDeclSpec]
_ [(Maybe CDeclr
odeclr, Maybe CInit
_, Maybe CExpr
_)] Attrs
_)  = Maybe CDeclr
odeclr
declaredDeclr CDecl
decl                          = 
  forall a. String -> a
interr forall a b. (a -> b) -> a -> b
$ String
"CTrav.declaredDeclr: Too many declarators!\n\
           \  Declaration at " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (forall a. Pos a => a -> Position
posOf CDecl
decl)

-- get the name declared by a declaration that has exactly one declarator
-- (EXPORTED) 
--
declaredName      :: CDecl -> Maybe Ident
declaredName :: CDecl -> Maybe Ident
declaredName CDecl
decl  = CDecl -> Maybe CDeclr
declaredDeclr CDecl
decl forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= CDeclr -> Maybe Ident
declrName

-- obtains the member definitions and the tag of a struct (EXPORTED)
--
--  * member definitions are expanded
--
structMembers :: CStructUnion -> ([CDecl], CStructTag)
structMembers :: CStructUnion -> ([CDecl], CStructTag)
structMembers (CStruct CStructTag
tag Maybe Ident
_ [CDecl]
members Attrs
_) = (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map CDecl -> [CDecl]
expandDecl forall a b. (a -> b) -> a -> b
$ [CDecl]
members,
                                           CStructTag
tag)

-- expand declarators declaring more than one identifier into multiple
-- declarators, eg, `int x, y;' becomes `int x; int y;' (EXPORTED)
--
expandDecl                        :: CDecl -> [CDecl]
expandDecl :: CDecl -> [CDecl]
expandDecl (CDecl [CDeclSpec]
specs [(Maybe CDeclr, Maybe CInit, Maybe CExpr)]
decls Attrs
at)  = 
  forall a b. (a -> b) -> [a] -> [b]
map (\(Maybe CDeclr, Maybe CInit, Maybe CExpr)
decl -> [CDeclSpec]
-> [(Maybe CDeclr, Maybe CInit, Maybe CExpr)] -> Attrs -> CDecl
CDecl [CDeclSpec]
specs [(Maybe CDeclr, Maybe CInit, Maybe CExpr)
decl] Attrs
at) [(Maybe CDeclr, Maybe CInit, Maybe CExpr)]
decls

-- get a struct's name (EXPORTED)
--
structName                      :: CStructUnion -> Maybe Ident
structName :: CStructUnion -> Maybe Ident
structName (CStruct CStructTag
_ Maybe Ident
oide [CDecl]
_ Attrs
_)  = Maybe Ident
oide

-- get an enum's name (EXPORTED)
--
enumName                  :: CEnum -> Maybe Ident
enumName :: CEnum -> Maybe Ident
enumName (CEnum Maybe Ident
oide [(Ident, Maybe CExpr)]
_ Attrs
_)  = Maybe Ident
oide

-- get a tag's name (EXPORTED)
--
--  * fail if the tag is anonymous
--
tagName     :: CTag -> Ident
tagName :: CTag -> Ident
tagName CTag
tag  =
  case CTag
tag of
   StructUnionCT CStructUnion
struct -> forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall {a}. a
err forall a. a -> a
id forall a b. (a -> b) -> a -> b
$ CStructUnion -> Maybe Ident
structName CStructUnion
struct
   EnumCT        CEnum
enum   -> forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall {a}. a
err forall a. a -> a
id forall a b. (a -> b) -> a -> b
$ CEnum -> Maybe Ident
enumName   CEnum
enum
  where
    err :: a
err = forall a. String -> a
interr String
"CTrav.tagName: Anonymous tag definition"

-- checks whether the given declarator defines an object that is a pointer to
-- some other type (EXPORTED)
--
--  * as far as parameter passing is concerned, arrays are also pointer
--
isPtrDeclr                                 :: CDeclr -> Bool
isPtrDeclr :: CDeclr -> Bool
isPtrDeclr (CPtrDeclr [CTypeQual]
_ (CVarDeclr Maybe Ident
_ Attrs
_)   Attrs
_)  = Bool
True
isPtrDeclr (CPtrDeclr [CTypeQual]
_ CDeclr
declr             Attrs
_)  = CDeclr -> Bool
isPtrDeclr CDeclr
declr
isPtrDeclr (CArrDeclr (CVarDeclr Maybe Ident
_ Attrs
_) [CTypeQual]
_ Maybe CExpr
_ Attrs
_)  = Bool
True
isPtrDeclr (CArrDeclr CDeclr
declr [CTypeQual]
_ Maybe CExpr
_           Attrs
_)  = CDeclr -> Bool
isPtrDeclr CDeclr
declr
isPtrDeclr (CFunDeclr CDeclr
declr [CDecl]
_ Bool
_           Attrs
_)  = CDeclr -> Bool
isPtrDeclr CDeclr
declr
isPtrDeclr CDeclr
_                                  = Bool
False

-- checks whether the given declarator defines an object that is an array of
-- some other type (EXPORTED)
--
--  * difference between arrays and pure pointers is important for size
--   calculations
--
isArrDeclr                                 :: CDeclr -> Bool
isArrDeclr :: CDeclr -> Bool
isArrDeclr (CArrDeclr CDeclr
declr [CTypeQual]
_ Maybe CExpr
_         Attrs
_)  = Bool
True
isArrDeclr CDeclr
_                                = Bool
False

-- drops the first pointer level from the given declarator (EXPORTED)
--
--  * the declarator must declare a pointer object
--
-- FIXME: this implementation isn't nice, because we retain the `CVarDeclr'
--        unchanged; as the declarator is changed, we should maybe make this
--        into an anonymous declarator and also change its attributes
--
dropPtrDeclr                                          :: CDeclr -> CDeclr
dropPtrDeclr :: CDeclr -> CDeclr
dropPtrDeclr (CPtrDeclr [CTypeQual]
qs declr :: CDeclr
declr@(CVarDeclr Maybe Ident
_ Attrs
_) Attrs
ats)  = CDeclr
declr
dropPtrDeclr (CPtrDeclr [CTypeQual]
qs  CDeclr
declr                Attrs
ats)  = 
  let declr' :: CDeclr
declr' = CDeclr -> CDeclr
dropPtrDeclr CDeclr
declr
  in
  [CTypeQual] -> CDeclr -> Attrs -> CDeclr
CPtrDeclr [CTypeQual]
qs CDeclr
declr' Attrs
ats
dropPtrDeclr (CArrDeclr declr :: CDeclr
declr@(CVarDeclr Maybe Ident
_ Attrs
_) [CTypeQual]
_ Maybe CExpr
_ Attrs
_)   = CDeclr
declr
dropPtrDeclr (CArrDeclr CDeclr
declr                [CTypeQual]
tq Maybe CExpr
e Attrs
ats) =
  let declr' :: CDeclr
declr' = CDeclr -> CDeclr
dropPtrDeclr CDeclr
declr
  in
  CDeclr -> [CTypeQual] -> Maybe CExpr -> Attrs -> CDeclr
CArrDeclr CDeclr
declr' [CTypeQual]
tq Maybe CExpr
e Attrs
ats
dropPtrDeclr (CFunDeclr CDeclr
declr [CDecl]
args Bool
vari         Attrs
ats)   =
  let declr' :: CDeclr
declr' = CDeclr -> CDeclr
dropPtrDeclr CDeclr
declr
  in
  CDeclr -> [CDecl] -> Bool -> Attrs -> CDeclr
CFunDeclr CDeclr
declr' [CDecl]
args Bool
vari Attrs
ats
dropPtrDeclr CDeclr
_                                         =
  forall a. String -> a
interr String
"CTrav.dropPtrDeclr: No pointer!"

-- checks whether the given declaration defines a pointer object (EXPORTED)
--
--  * there may only be a single declarator in the declaration
--
isPtrDecl                                  :: CDecl -> Bool
isPtrDecl :: CDecl -> Bool
isPtrDecl (CDecl [CDeclSpec]
_ []                   Attrs
_)  = Bool
False
isPtrDecl (CDecl [CDeclSpec]
_ [(Just CDeclr
declr, Maybe CInit
_, Maybe CExpr
_)] Attrs
_)  = CDeclr -> Bool
isPtrDeclr CDeclr
declr
isPtrDecl CDecl
_                                 =
  forall a. String -> a
interr String
"CTrav.isPtrDecl: There was more than one declarator!"

-- checks whether the given declarator defines a function object (EXPORTED)
--
isFunDeclr                                   :: CDeclr -> Bool
isFunDeclr :: CDeclr -> Bool
isFunDeclr (CPtrDeclr [CTypeQual]
_ CDeclr
declr             Attrs
_)  = CDeclr -> Bool
isFunDeclr CDeclr
declr
isFunDeclr (CArrDeclr CDeclr
declr [CTypeQual]
_ Maybe CExpr
_           Attrs
_)  = CDeclr -> Bool
isFunDeclr CDeclr
declr
isFunDeclr (CFunDeclr (CVarDeclr Maybe Ident
_ Attrs
_) [CDecl]
_ Bool
_ Attrs
_)  = Bool
True
isFunDeclr (CFunDeclr CDeclr
declr [CDecl]
_ Bool
_           Attrs
_)  = CDeclr -> Bool
isFunDeclr CDeclr
declr
isFunDeclr CDeclr
_                                  = Bool
False

-- extract the structure from the type specifiers of a declaration (EXPORTED)
--
structFromDecl                       :: Position -> CDecl -> CT s CStructUnion
structFromDecl :: forall s. Position -> CDecl -> CT s CStructUnion
structFromDecl Position
pos (CDecl [CDeclSpec]
specs [(Maybe CDeclr, Maybe CInit, Maybe CExpr)]
_ Attrs
_)  =
  case forall a. [a] -> a
head [CTypeSpec
ts | CTypeSpec CTypeSpec
ts <- [CDeclSpec]
specs] of
    CSUType CStructUnion
su Attrs
_ -> forall s. Position -> CTag -> CT s CStructUnion
extractStruct Position
pos (CStructUnion -> CTag
StructUnionCT CStructUnion
su)
    CTypeSpec
_            -> forall s a. Position -> CT s a
structExpectedErr Position
pos

-- extracts the arguments from a function declaration (must be a unique
-- declarator) and constructs a declaration for the result of the function
-- (EXPORTED) 
--
--  * the boolean result indicates whether the function is variadic
--
funResultAndArgs :: CDecl -> ([CDecl], CDecl, Bool)
funResultAndArgs :: CDecl -> ([CDecl], CDecl, Bool)
funResultAndArgs (CDecl [CDeclSpec]
specs [(Just CDeclr
declr, Maybe CInit
_, Maybe CExpr
_)] Attrs
_) =
  let ([CDecl]
args, CDeclr
declr', Bool
variadic) = CDeclr -> ([CDecl], CDeclr, Bool)
funArgs CDeclr
declr
      result :: CDecl
result                   = [CDeclSpec]
-> [(Maybe CDeclr, Maybe CInit, Maybe CExpr)] -> Attrs -> CDecl
CDecl [CDeclSpec]
specs [(forall a. a -> Maybe a
Just CDeclr
declr', forall a. Maybe a
Nothing, forall a. Maybe a
Nothing)]
                                       (Position -> Attrs
newAttrsOnlyPos Position
nopos)
  in
  ([CDecl]
args, CDecl
result, Bool
variadic)
  where
    funArgs :: CDeclr -> ([CDecl], CDeclr, Bool)
funArgs (CFunDeclr var :: CDeclr
var@(CVarDeclr Maybe Ident
_ Attrs
_) [CDecl]
args Bool
variadic  Attrs
_) = 
      ([CDecl]
args, CDeclr
var, Bool
variadic)
    funArgs (CPtrDeclr [CTypeQual]
qs CDeclr
declr                          Attrs
at) = 
      let ([CDecl]
args, CDeclr
declr', Bool
variadic) = CDeclr -> ([CDecl], CDeclr, Bool)
funArgs CDeclr
declr
      in
      ([CDecl]
args, [CTypeQual] -> CDeclr -> Attrs -> CDeclr
CPtrDeclr [CTypeQual]
qs CDeclr
declr' Attrs
at, Bool
variadic)
    funArgs (CArrDeclr CDeclr
declr [CTypeQual]
tqs Maybe CExpr
oe                      Attrs
at) =
      let ([CDecl]
args, CDeclr
declr', Bool
variadic) = CDeclr -> ([CDecl], CDeclr, Bool)
funArgs CDeclr
declr
      in
      ([CDecl]
args, CDeclr -> [CTypeQual] -> Maybe CExpr -> Attrs -> CDeclr
CArrDeclr CDeclr
declr' [CTypeQual]
tqs Maybe CExpr
oe Attrs
at, Bool
variadic)
    funArgs (CFunDeclr CDeclr
declr [CDecl]
args Bool
var                    Attrs
at) =
      let ([CDecl]
args, CDeclr
declr', Bool
variadic) = CDeclr -> ([CDecl], CDeclr, Bool)
funArgs CDeclr
declr
      in
      ([CDecl]
args, CDeclr -> [CDecl] -> Bool -> Attrs -> CDeclr
CFunDeclr CDeclr
declr' [CDecl]
args Bool
var Attrs
at, Bool
variadic)
    funArgs CDeclr
_                                           =
      forall a. String -> a
interr String
"CTrav.funResultAndArgs: Illegal declarator!"

-- name chasing
--

-- find the declarator identified by the given identifier; if the declarator
-- is itself only a `typedef'ed name, the operation recursively searches for
-- the declarator associated with that name (this is called ``typedef
-- chasing'') (EXPORTED)
--
--  * if `ind = True', we have to hop over one indirection
--
--  * remove all declarators except the one we just looked up
--
chaseDecl         :: Ident -> Bool -> CT s CDecl
--
--  * cycles are no issue, as they cannot occur in a correct C header (we would 
--   have spotted the problem during name analysis)
--
chaseDecl :: forall s. Ident -> Bool -> CT s CDecl
chaseDecl Ident
ide Bool
ind  = 
  do
    forall s. CT s ()
traceEnter
    CDecl
cdecl     <- forall s. Ident -> CT s CDecl
getDeclOf Ident
ide
    let sdecl :: CDecl
sdecl  = Ident
ide Ident -> CDecl -> CDecl
`simplifyDecl` CDecl
cdecl
    case CDecl -> Bool -> Maybe (Ident, Bool)
extractAlias CDecl
sdecl Bool
ind of
      Just    (Ident
ide', Bool
ind') -> forall s. Ident -> Bool -> CT s CDecl
chaseDecl Ident
ide' Bool
ind'
      Maybe (Ident, Bool)
Nothing              -> forall (m :: * -> *) a. Monad m => a -> m a
return CDecl
sdecl
  where
    traceEnter :: CT s ()
traceEnter = forall s. String -> CT s ()
traceCTrav forall a b. (a -> b) -> a -> b
$ 
                   String
"Entering `chaseDecl' for `" forall a. [a] -> [a] -> [a]
++ Ident -> String
identToLexeme Ident
ide 
                   forall a. [a] -> [a] -> [a]
++ String
"' " forall a. [a] -> [a] -> [a]
++ (if Bool
ind then String
"" else String
"not ") 
                   forall a. [a] -> [a] -> [a]
++ String
"following indirections...\n"

-- find type object in object name space and then chase it (EXPORTED)
--
--  * see also `chaseDecl'
--
--  * also create an object association from the given identifier to the object
--   that it _directly_ represents
--
--  * if the third argument is `True', use `findObjShadow'
--
findAndChaseDecl                    :: Ident -> Bool -> Bool -> CT s CDecl
findAndChaseDecl :: forall s. Ident -> Bool -> Bool -> CT s CDecl
findAndChaseDecl Ident
ide Bool
ind Bool
useShadows  =
  do
    (CObj
obj, Ident
ide') <- forall s. Ident -> Bool -> CT s (CObj, Ident)
findTypeObj Ident
ide Bool
useShadows   -- is there an object def?
    Ident
ide  forall s. Ident -> CDef -> CT s ()
`refersToNewDef` CObj -> CDef
ObjCD CObj
obj
    Ident
ide' forall s. Ident -> CDef -> CT s ()
`refersToNewDef` CObj -> CDef
ObjCD CObj
obj             -- assoc needed for chasing
    forall s. Ident -> Bool -> CT s CDecl
chaseDecl Ident
ide' Bool
ind

-- given a declaration (which must have exactly one declarator), if the
-- declarator is an alias, chase it to the actual declaration (EXPORTED)
--
checkForAlias      :: CDecl -> CT s (Maybe CDecl)
checkForAlias :: forall s. CDecl -> CT s (Maybe CDecl)
checkForAlias CDecl
decl  =
  case CDecl -> Bool -> Maybe (Ident, Bool)
extractAlias CDecl
decl Bool
False of
    Maybe (Ident, Bool)
Nothing        -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
    Just (Ident
ide', Bool
_) -> forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall s. Ident -> Bool -> CT s CDecl
chaseDecl Ident
ide' Bool
False

-- given a declaration (which must have exactly one declarator), if the
-- declarator is an alias, yield the alias name; *no* chasing (EXPORTED)
--
checkForOneAliasName      :: CDecl -> Maybe Ident
checkForOneAliasName :: CDecl -> Maybe Ident
checkForOneAliasName CDecl
decl  = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> a
fst forall a b. (a -> b) -> a -> b
$ CDecl -> Bool -> Maybe (Ident, Bool)
extractAlias CDecl
decl Bool
False


-- smart lookup
--

-- for the given identifier, either find an enumeration in the tag name space
-- or a type definition referring to an enumeration in the object name space;
-- raises an error and exception if the identifier is not defined (EXPORTED)
--
--  * if the second argument is `True', use `findTagShadow'
--
lookupEnum               :: Ident -> Bool -> CT s CEnum
lookupEnum :: forall s. Ident -> Bool -> CT s CEnum
lookupEnum Ident
ide Bool
useShadows =
  do
    Maybe CTag
otag <- if Bool
useShadows 
            then forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> a
fst) forall a b. (a -> b) -> a -> b
$ forall s. Ident -> CT s (Maybe (CTag, Ident))
findTagShadow Ident
ide
            else forall s. Ident -> CT s (Maybe CTag)
findTag Ident
ide
    case Maybe CTag
otag of
      Just (StructUnionCT CStructUnion
_   ) -> forall s a. Ident -> CT s a
enumExpectedErr Ident
ide  -- wrong tag definition
      Just (EnumCT        CEnum
enum) -> forall (m :: * -> *) a. Monad m => a -> m a
return CEnum
enum          -- enum tag definition
      Maybe CTag
Nothing                   -> do                   -- no tag definition
        (CDecl [CDeclSpec]
specs [(Maybe CDeclr, Maybe CInit, Maybe CExpr)]
_ Attrs
_) <- forall s. Ident -> Bool -> Bool -> CT s CDecl
findAndChaseDecl Ident
ide Bool
False Bool
useShadows
        case forall a. [a] -> a
head [CTypeSpec
ts | CTypeSpec CTypeSpec
ts <- [CDeclSpec]
specs] of
          CEnumType CEnum
enum Attrs
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return CEnum
enum
          CTypeSpec
_                -> forall s a. Ident -> CT s a
enumExpectedErr Ident
ide

-- for the given identifier, either find a struct/union in the tag name space
-- or a type definition referring to a struct/union in the object name space;
-- raises an error and exception if the identifier is not defined (EXPORTED)
--
--  * if `ind = True', the identifier names a reference type to the searched
--   for struct/union
--
--  * typedef chasing is used only if there is no tag of the same name or an
--   indirection (ie, `ind = True') is explicitly required
--
--  * if the third argument is `True', use `findTagShadow'
--
--  * when finding a forward definition of a tag, follow it to the real
--   definition
--
lookupStructUnion :: Ident -> Bool -> Bool -> CT s CStructUnion
lookupStructUnion :: forall s. Ident -> Bool -> Bool -> CT s CStructUnion
lookupStructUnion Ident
ide Bool
ind Bool
useShadows
  | Bool
ind       = forall {s}. PreCST SwitchBoard (CState s) CStructUnion
chase
  | Bool
otherwise =
    do
      Maybe CTag
otag <- if Bool
useShadows 
              then forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> a
fst) forall a b. (a -> b) -> a -> b
$ forall s. Ident -> CT s (Maybe (CTag, Ident))
findTagShadow Ident
ide
              else forall s. Ident -> CT s (Maybe CTag)
findTag Ident
ide
      forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall {s}. PreCST SwitchBoard (CState s) CStructUnion
chase (forall s. Position -> CTag -> CT s CStructUnion
extractStruct (forall a. Pos a => a -> Position
posOf Ident
ide)) Maybe CTag
otag  -- `chase' if `Nothing'
  where
    chase :: PreCST SwitchBoard (CState s) CStructUnion
chase =
      do
        CDecl
decl <- forall s. Ident -> Bool -> Bool -> CT s CDecl
findAndChaseDecl Ident
ide Bool
ind Bool
useShadows
        forall s. Position -> CDecl -> CT s CStructUnion
structFromDecl (forall a. Pos a => a -> Position
posOf Ident
ide) CDecl
decl

-- for the given identifier, check for the existance of both a type definition
-- or a struct, union, or enum definition (EXPORTED)
--
--  * if a typedef and a tag exists, the typedef takes precedence
--
--  * typedefs are chased
--
--  * if the second argument is `True', look for shadows, too
--
lookupDeclOrTag                :: Ident -> Bool -> CT s (Either CDecl CTag)
lookupDeclOrTag :: forall s. Ident -> Bool -> CT s (Either CDecl CTag)
lookupDeclOrTag Ident
ide Bool
useShadows  = do
  Maybe (CObj, Ident)
oobj <- forall s. Ident -> Bool -> CT s (Maybe (CObj, Ident))
findTypeObjMaybe Ident
ide Bool
useShadows
  case Maybe (CObj, Ident)
oobj of
    Just (CObj
_, Ident
ide) -> forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ forall s. Ident -> Bool -> Bool -> CT s CDecl
findAndChaseDecl Ident
ide Bool
False Bool
False 
                                                   -- already did check shadows
    Maybe (CObj, Ident)
Nothing       -> do
                       Maybe CTag
otag <- if Bool
useShadows 
                               then forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> a
fst) forall a b. (a -> b) -> a -> b
$ forall s. Ident -> CT s (Maybe (CTag, Ident))
findTagShadow Ident
ide
                               else forall s. Ident -> CT s (Maybe CTag)
findTag Ident
ide
                       case Maybe CTag
otag of
                         Maybe CTag
Nothing  -> forall s a. Ident -> CT s a
unknownObjErr Ident
ide
                         Just CTag
tag -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right CTag
tag


-- auxiliary routines (internal)
--

-- if the given declaration (which may have at most one declarator) is a
-- `typedef' alias, yield the referenced name
--
--  * a `typedef' alias has one of the following forms
--
--     <specs> at  x, ...;
--     <specs> at *x, ...;
--
--   where `at' is the alias type, which has been defined by a `typedef', and
--   <specs> are arbitrary specifiers and qualifiers.  Note that `x' may be a
--   variable, a type name (if `typedef' is in <specs>), or be entirely
--   omitted.
--
--  * if `ind = True', the alias may be via an indirection
--
--  * if `ind = True' and the alias is _not_ over an indirection, yield `True'; 
--   otherwise `False' (ie, the ability to hop over an indirection is consumed)
--
--  * this may be an anonymous declaration, ie, the name in `CVarDeclr' may be
--   omitted or there may be no declarator at all
--
extractAlias :: CDecl -> Bool -> Maybe (Ident, Bool)
extractAlias :: CDecl -> Bool -> Maybe (Ident, Bool)
extractAlias decl :: CDecl
decl@(CDecl [CDeclSpec]
specs [(Maybe CDeclr, Maybe CInit, Maybe CExpr)]
_ Attrs
_) Bool
ind =
  case [CTypeSpec
ts | CTypeSpec CTypeSpec
ts <- [CDeclSpec]
specs] of
    [CTypeDef Ident
ide' Attrs
_] ->                        -- type spec is aliased ident
      case CDecl -> Maybe CDeclr
declaredDeclr CDecl
decl of
        Maybe CDeclr
Nothing                                -> forall a. a -> Maybe a
Just (Ident
ide', Bool
ind)
        Just (CVarDeclr Maybe Ident
_ Attrs
_                  ) -> forall a. a -> Maybe a
Just (Ident
ide', Bool
ind)
        Just (CPtrDeclr [CTypeQual
_] (CVarDeclr Maybe Ident
_ Attrs
_) Attrs
_)
          | Bool
ind                                -> forall a. a -> Maybe a
Just (Ident
ide', Bool
False)
          | Bool
otherwise                          -> forall a. Maybe a
Nothing
        Maybe CDeclr
_                                      -> forall a. Maybe a
Nothing
    [CTypeSpec]
_                 -> forall a. Maybe a
Nothing

-- if the given tag is a forward declaration of a structure, follow the
-- reference to the full declaration
--
--  * the recursive call is not dangerous as there can't be any cycles
--
extractStruct                        :: Position -> CTag -> CT s CStructUnion
extractStruct :: forall s. Position -> CTag -> CT s CStructUnion
extractStruct Position
pos (EnumCT        CEnum
_ )  = forall s a. Position -> CT s a
structExpectedErr Position
pos
extractStruct Position
pos (StructUnionCT CStructUnion
su)  =
  case CStructUnion
su of
    CStruct CStructTag
_ (Just Ident
ide') [] Attrs
_ -> do            -- found forward definition
                                    CDef
def <- forall s. Ident -> CT s CDef
getDefOf Ident
ide'
                                    case CDef
def of
                                      TagCD CTag
tag -> forall s. Position -> CTag -> CT s CStructUnion
extractStruct Position
pos CTag
tag
                                      CDef
_         -> forall {a}. a
err
    CStructUnion
_                          -> forall (m :: * -> *) a. Monad m => a -> m a
return CStructUnion
su
  where
    err :: a
err = forall a. String -> a
interr String
"CTrav.extractStruct: Illegal reference!"

-- yield the name declared by a declarator if any
--
declrName                          :: CDeclr -> Maybe Ident
declrName :: CDeclr -> Maybe Ident
declrName (CVarDeclr Maybe Ident
oide       Attrs
_)  = Maybe Ident
oide
declrName (CPtrDeclr [CTypeQual]
_ CDeclr
declr    Attrs
_)  = CDeclr -> Maybe Ident
declrName CDeclr
declr
declrName (CArrDeclr CDeclr
declr  [CTypeQual]
_ Maybe CExpr
_ Attrs
_)  = CDeclr -> Maybe Ident
declrName CDeclr
declr
declrName (CFunDeclr CDeclr
declr  [CDecl]
_ Bool
_ Attrs
_)  = CDeclr -> Maybe Ident
declrName CDeclr
declr

-- raise an error if the given declarator does not declare a C function or if
-- the function is supposed to return an array (the latter is illegal in C)
--
assertFunDeclr :: Position -> CDeclr -> CT s ()
assertFunDeclr :: forall s. Position -> CDeclr -> CT s ()
assertFunDeclr Position
pos (CArrDeclr (CFunDeclr (CVarDeclr Maybe Ident
_ Attrs
_) [CDecl]
_ Bool
_ Attrs
_) [CTypeQual]
_ Maybe CExpr
_ Attrs
_) =
  forall s a. Position -> CT s a
illegalFunResultErr Position
pos
assertFunDeclr Position
pos            (CFunDeclr (CVarDeclr Maybe Ident
_ Attrs
_) [CDecl]
_ Bool
_ Attrs
_)        =
  forall e s. PreCST e s ()
nop -- everything is ok
assertFunDeclr Position
pos            (CFunDeclr CDeclr
declr           [CDecl]
_ Bool
_ Attrs
_)        =
  forall s. Position -> CDeclr -> CT s ()
assertFunDeclr Position
pos CDeclr
declr
assertFunDeclr Position
pos            (CPtrDeclr [CTypeQual]
_ CDeclr
declr             Attrs
_)        =
  forall s. Position -> CDeclr -> CT s ()
assertFunDeclr Position
pos CDeclr
declr
assertFunDeclr Position
pos            (CArrDeclr CDeclr
declr           [CTypeQual]
_ Maybe CExpr
_ Attrs
_)        =
  forall s. Position -> CDeclr -> CT s ()
assertFunDeclr Position
pos CDeclr
declr
assertFunDeclr Position
pos CDeclr
_                                                 = 
  forall s a. Position -> CT s a
funExpectedErr Position
pos

-- raise an error if the given tag defines an enumeration, but does not fully
-- define it
--
assertIfEnumThenFull                          :: CTag -> CT s ()
assertIfEnumThenFull :: forall s. CTag -> CT s ()
assertIfEnumThenFull (EnumCT (CEnum Maybe Ident
_ [] Attrs
at))  = forall s a. Position -> CT s a
enumForwardErr (forall a. Pos a => a -> Position
posOf Attrs
at)
assertIfEnumThenFull CTag
_                         = forall e s. PreCST e s ()
nop

-- trace for this module
--
traceCTrav :: String -> CT s ()
traceCTrav :: forall s. String -> CT s ()
traceCTrav  = forall s. (Traces -> Bool) -> String -> CST s ()
putTraceStr Traces -> Bool
traceCTravSW


-- error messages
-- --------------

unknownObjErr     :: Ident -> CT s a
unknownObjErr :: forall s a. Ident -> CT s a
unknownObjErr Ident
ide  =
  forall s a. Position -> [String] -> CT s a
raiseErrorCTExc (forall a. Pos a => a -> Position
posOf Ident
ide) 
    [String
"Unknown identifier!",
     String
"Cannot find a definition for `" forall a. [a] -> [a] -> [a]
++ Ident -> String
identToLexeme Ident
ide forall a. [a] -> [a] -> [a]
++ String
"' in the \
     \header file."]

typedefExpectedErr      :: Ident -> CT s a
typedefExpectedErr :: forall s a. Ident -> CT s a
typedefExpectedErr Ident
ide  =   
  forall s a. Position -> [String] -> CT s a
raiseErrorCTExc (forall a. Pos a => a -> Position
posOf Ident
ide) 
    [String
"Expected type definition!",
     String
"The identifier `" forall a. [a] -> [a] -> [a]
++ Ident -> String
identToLexeme Ident
ide forall a. [a] -> [a] -> [a]
++ String
"' needs to be a C type name."]

unexpectedTypedefErr     :: Position -> CT s a
unexpectedTypedefErr :: forall s a. Position -> CT s a
unexpectedTypedefErr Position
pos  =   
  forall s a. Position -> [String] -> CT s a
raiseErrorCTExc Position
pos 
    [String
"Unexpected type name!",
     String
"An object, function, or enum constant is required here."]

illegalFunResultErr      :: Position -> CT s a
illegalFunResultErr :: forall s a. Position -> CT s a
illegalFunResultErr Position
pos  =
  forall s a. Position -> [String] -> CT s a
raiseErrorCTExc Position
pos [String
"Function cannot return an array!",
                       String
"ANSI C does not allow functions to return an array."]

funExpectedErr      :: Position -> CT s a
funExpectedErr :: forall s a. Position -> CT s a
funExpectedErr Position
pos  =
  forall s a. Position -> [String] -> CT s a
raiseErrorCTExc Position
pos 
    [String
"Function expected!",
     String
"A function is needed here, but this declarator does not declare",
     String
"a function."]

enumExpectedErr     :: Ident -> CT s a
enumExpectedErr :: forall s a. Ident -> CT s a
enumExpectedErr Ident
ide  =
  forall s a. Position -> [String] -> CT s a
raiseErrorCTExc (forall a. Pos a => a -> Position
posOf Ident
ide) 
    [String
"Expected enum!",
     String
"Expected `" forall a. [a] -> [a] -> [a]
++ Ident -> String
identToLexeme Ident
ide forall a. [a] -> [a] -> [a]
++ String
"' to denote an enum; instead found",
     String
"a struct, union, or object."]

structExpectedErr     :: Position -> CT s a
structExpectedErr :: forall s a. Position -> CT s a
structExpectedErr Position
pos  =
  forall s a. Position -> [String] -> CT s a
raiseErrorCTExc Position
pos
    [String
"Expected a struct!",
     String
"Expected a structure or union; instead found an enum or basic type."]

enumForwardErr     :: Position -> CT s a
enumForwardErr :: forall s a. Position -> CT s a
enumForwardErr Position
pos  =
  forall s a. Position -> [String] -> CT s a
raiseErrorCTExc Position
pos 
    [String
"Forward definition of enumeration!",
     String
"ANSI C does not permit foreward definitions of enumerations!"]