    {-# LANGUAGE DeriveDataTypeable  #-}
    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Language.C.Analysis.Syntax
    -- Copyright   :  (c) 2008 Benedikt Huber
    -- License     :  BSD-style
    -- Maintainer  :  benedikt.huber@gmail.com
    -- Stability   :  alpha
    -- Portability :  ghc
    --
    -- This module contains definitions for representing C translation units.
    -- In contrast to 'Language.C.Syntax.AST', the representation tries to express the semantics of
    -- of a translation unit.
    ---------------------------------------------------------------------------------------------------
    module Language.C.Analysis.SemRep(
    -- * Sums of tags and identifiers
    TagDef(..),typeOfTagDef,
    Declaration(..),declIdent,declName,declType,declAttrs,
    IdentDecl(..),objKindDescr, splitIdentDecls,
    -- * Global definitions
    GlobalDecls(..),emptyGlobalDecls,filterGlobalDecls,mergeGlobalDecls,
    -- * Events for visitors
    DeclEvent(..),
    -- * Declarations and definitions
    Decl(..),
    ObjDef(..),isTentative,
    FunDef(..),
    ParamDecl(..),MemberDecl(..),
    TypeDef(..),identOfTypeDef,
    VarDecl(..),
    -- * Declaration attributes
    DeclAttrs(..),isExtDecl,
    Storage(..),declStorage,ThreadLocal,Register,
    Linkage(..),
    -- * Types
    Type(..),
    FunType(..),isFunctionType,
    derefTypeDef,referencedType,hasTypeOfExpr,
    ArraySize(..),
    TypeDefRef(..),
    TypeName(..),BuiltinType(..),
    IntType(..),FloatType(..),
    HasSUERef(..),HasCompTyKind(..),
    CompTypeRef(..),CompType(..),typeOfCompDef,CompTyKind(..),
    EnumTypeRef(..),EnumType(..),typeOfEnumDef,
    Enumerator(..),
    TypeQuals(..),noTypeQuals,mergeTypeQuals,
    -- * Variable names
    VarName(..),identOfVarName,AsmName,
    -- * Attributes (STUB, not yet analyzed)
    Attr(..),Attributes,
    -- * Statements and Expressions (STUB, aliases to Syntax)
    Stmt,Expr,Initializer,AsmBlock,
    )
    where
    import Language.C.Data
    import Language.C.Syntax
    import Language.C.Syntax.Constants

    import Data.Map (Map)
    import qualified Data.Map as Map
    import Data.Generics
    import Text.PrettyPrint.HughesPJ

    -- | accessor class : struct\/union\/enum names
    class HasSUERef a where
        sueRef  :: a -> SUERef

    -- | accessor class : composite type tags (struct or union)
    class HasCompTyKind a where
        compTag :: a -> CompTyKind

    -- | Composite type definitions (tags)
    data TagDef =  CompDef CompType	  --definition
         	       | EnumDef EnumType      -- enum definition
                   deriving (Typeable, Data {-! CNode !-})

    instance HasSUERef TagDef where
        sueRef (CompDef ct) = sueRef ct
        sueRef (EnumDef et) = sueRef et

    -- | return the type corresponding to a tag definition
    typeOfTagDef :: TagDef -> TypeName
    typeOfTagDef (CompDef comptype) =  typeOfCompDef comptype
    typeOfTagDef (EnumDef enumtype) =  typeOfEnumDef enumtype

    -- | All datatypes aggregating a declaration are instances of @Declaration@
    class Declaration n where
        -- | get the name, type and declaration attributes of a declaration or definition
        getVarDecl :: n -> VarDecl

    -- | get the declaration corresponding to a definition
    declOfDef :: (Declaration n, CNode n) => n -> Decl
    declOfDef def = let vd = getVarDecl def in Decl vd (nodeInfo def)

    -- | get the variable identifier of a declaration (only safe if the
    --    the declaration is known to have a name)
    declIdent :: (Declaration n) => n -> Ident
    declIdent = identOfVarName . declName
    -- | get the variable name of a @Declaration@
    declName ::  (Declaration n) => n -> VarName
    declName = (\(VarDecl n _ _) -> n) . getVarDecl
    -- | get the type of a @Declaration@
    declType ::  (Declaration n) => n -> Type
    declType = (\(VarDecl _ _ ty) -> ty) . getVarDecl
    -- | get the declaration attributes of a @Declaration@
    declAttrs :: (Declaration n) => n -> DeclAttrs
    declAttrs = (\(VarDecl _ specs _) -> specs) . getVarDecl

    instance (Declaration a, Declaration b) => Declaration (Either a b) where
        getVarDecl = either getVarDecl getVarDecl

    -- | identifiers, typedefs and enumeration constants (namespace sum)
    data IdentDecl = Declaration Decl           -- ^ object or function declaration
    	             | ObjectDef ObjDef           -- ^ object definition
    	             | FunctionDef FunDef         -- ^ function definition
    	             | EnumeratorDef Enumerator   -- ^ definition of an enumerator
                   deriving (Typeable, Data {-! CNode !-})

    instance Declaration IdentDecl where
      getVarDecl (Declaration decl) = getVarDecl decl
      getVarDecl (ObjectDef def) = getVarDecl def
      getVarDecl (FunctionDef def) = getVarDecl def
      getVarDecl (EnumeratorDef def) = getVarDecl def

    -- | textual description of the kind of an object
    objKindDescr :: IdentDecl -> String
    objKindDescr  (Declaration _ ) = "declaration"
    objKindDescr (ObjectDef _) = "object definition"
    objKindDescr (FunctionDef _) = "function definition"
    objKindDescr (EnumeratorDef _) = "enumerator definition"

    -- | @splitIdentDecls includeAllDecls@ splits a map of object, function and enumerator declarations and definitions into one map
    -- holding declarations, and three maps for object definitions, enumerator definitions and function definitions.
    -- If @includeAllDecls@ is @True@ all declarations are present in the first map, otherwise only those where no corresponding definition
    -- is available.
    splitIdentDecls :: Bool -> Map Ident IdentDecl -> (Map Ident Decl,
                                                    ( Map Ident Enumerator,
                                                      Map Ident ObjDef,
                                                      Map Ident FunDef ) )
    splitIdentDecls include_all = Map.foldWithKey (if include_all then deal else deal') (Map.empty,(Map.empty,Map.empty,Map.empty))
      where
      deal ident entry (decls,defs) = (Map.insert ident (declOfDef entry) decls, addDef ident entry defs)
      deal' ident (Declaration d) (decls,defs) = (Map.insert ident d decls,defs)
      deal' ident def (decls,defs) = (decls, addDef ident def defs)
      addDef ident entry (es,os,fs) =
        case entry of
            Declaration _   -> (es,os,fs)
            EnumeratorDef e -> (Map.insert ident e es,os,fs)
            ObjectDef o     -> (es,Map.insert ident o os,fs)
            FunctionDef f   -> (es, os,Map.insert ident f fs)

    -- | global declaration\/definition table returned by the analysis
    data GlobalDecls = GlobalDecls {
                         gObjs     :: Map Ident IdentDecl,
                         gTags     :: Map SUERef TagDef,
                         gTypeDefs :: Map Ident TypeDef
                       }

    -- | empty global declaration table
    emptyGlobalDecls :: GlobalDecls
    emptyGlobalDecls = GlobalDecls Map.empty Map.empty Map.empty

    -- | filter global declarations
    filterGlobalDecls :: (DeclEvent -> Bool) -> GlobalDecls -> GlobalDecls
    filterGlobalDecls decl_filter gmap = GlobalDecls
        {
            gObjs  = Map.filter (decl_filter . DeclEvent) (gObjs gmap),
            gTags  = Map.filter (decl_filter . TagEvent) (gTags gmap),
            gTypeDefs = Map.filter (decl_filter . TypeDefEvent) (gTypeDefs gmap)
        }
    -- | merge global declarations
    mergeGlobalDecls :: GlobalDecls -> GlobalDecls -> GlobalDecls
    mergeGlobalDecls gmap1 gmap2 = GlobalDecls
        {
            gObjs  = Map.union (gObjs gmap1) (gObjs gmap2),
            gTags  = Map.union  (gTags gmap1) (gTags gmap2),
            gTypeDefs = Map.union (gTypeDefs gmap1) (gTypeDefs gmap2)
        }

    -- * Events

    -- | Declaration events
    --
    -- Those events are reported to callbacks, which are executed during the traversal.
    data DeclEvent =
           TagEvent  TagDef
           -- ^ file-scope struct\/union\/enum event
         | DeclEvent IdentDecl
           -- ^ file-scope declaration or definition
         | TypeDefEvent TypeDef
           -- ^ a type definition
         | AsmEvent AsmBlock
           -- ^ assembler block
         deriving ({-! CNode !-})

    -- * Declarations and definitions

    -- | Declarations, which aren't definitions
    data Decl = Decl VarDecl NodeInfo
                deriving (Typeable, Data {-! CNode !-})

    instance Declaration Decl where
        getVarDecl   (Decl vd _) =  vd

    -- | Object Definitions
    --
    -- An object definition is a declaration together with an initializer.
    --
    -- If the initializer is missing, it is a tentative definition, i.e. a
    -- definition which might be overriden later on.
    data ObjDef = ObjDef VarDecl (Maybe Initializer) NodeInfo
                 deriving (Typeable, Data {-! CNode !-})
    instance Declaration ObjDef where
        getVarDecl  (ObjDef vd _ _) =  vd

    -- | Returns @True@ if the given object definition is tentative.
    isTentative :: ObjDef -> Bool
    isTentative (ObjDef decl init_opt _) | isExtDecl decl = maybe True (const False) init_opt
                                         | otherwise = False

    -- | Function definitions
    --
    -- A function definition is a declaration together with a statement (the function body).
    data FunDef = FunDef VarDecl Stmt NodeInfo
                 deriving (Typeable, Data {-! CNode !-})
    instance Declaration FunDef where
        getVarDecl (FunDef vd _ _) = vd

    -- | Parameter declaration
    data ParamDecl = ParamDecl VarDecl NodeInfo
                   | AbstractParamDecl VarDecl NodeInfo
        deriving (Typeable, Data {-! CNode !-} )

    instance Declaration ParamDecl where
      getVarDecl (ParamDecl vd _) = vd
      getVarDecl (AbstractParamDecl vd _) = vd

    -- | Struct\/Union member declaration
    data MemberDecl = MemberDecl VarDecl (Maybe Expr) NodeInfo
                      -- ^ @MemberDecl vardecl bitfieldsize node@
                    | AnonBitField Type Expr NodeInfo
                      -- ^ @AnonBitField typ size@
        deriving (Typeable, Data {-! CNode !-} )

    instance Declaration MemberDecl where
      getVarDecl (MemberDecl vd _ _) = vd
      getVarDecl (AnonBitField ty _ _) = VarDecl NoName (DeclAttrs False NoStorage []) ty

    -- | @typedef@ definitions.
    --
    -- The identifier is a new name for the given type.
    data TypeDef = TypeDef Ident Type Attributes NodeInfo
                   deriving (Typeable, Data {-! CNode !-} )

    -- | return the idenitifier of a @typedef@
    identOfTypeDef :: TypeDef -> Ident
    identOfTypeDef (TypeDef ide _ _ _) = ide

    -- | Generic variable declarations
    data VarDecl = VarDecl VarName DeclAttrs Type
                  deriving (Typeable, Data)

    instance Declaration VarDecl where
      getVarDecl = id

    -- @isExtDecl d@ returns true if the declaration has /linkage/
    isExtDecl :: (Declaration n) => n -> Bool
    isExtDecl = hasLinkage . declStorage

    -- | Declaration attributes of the form @DeclAttrs isInlineFunction storage linkage attrs@
    --
    -- They specify the storage and linkage of a declared object.
    data DeclAttrs = DeclAttrs Bool Storage Attributes
                     -- ^ @DeclAttrs inline storage attrs@
                   deriving (Typeable, Data)

    -- | get the 'Storage' of a declaration
    declStorage :: (Declaration d) => d -> Storage
    declStorage d = case declAttrs d of (DeclAttrs _ st _) -> st

    -- In C we have
    --  Identifiers can either have internal, external or no linkage
    --  (same object everywhere, same object within the translation unit, unique).
    --  * top-level identifiers
    --      static : internal linkage (objects and function defs)
    --      extern : linkage of prior declaration (if specified), external linkage otherwise
    --      no-spec: external linkage
    --  * storage duration
    --      * static storage duration: objects with external or internal linkage, or local ones with the static keyword
    --      * automatic storage duration: otherwise (register)
    -- See http://publications.gbdirect.co.uk/c_book/chapter8/declarations_and_definitions.html, Table 8.1, 8.2

    -- | Storage duration and linkage of a variable
    data Storage  =  NoStorage                  -- ^ no storage
                   | Auto Register              -- ^ automatic storage (optional: register)
                   | Static Linkage ThreadLocal -- ^ static storage, with linkage and thread local specifier (gnu c)
                   | FunLinkage Linkage         -- ^ function, either internal or external linkage
                   deriving (Typeable, Data, Show, Eq, Ord)

    type ThreadLocal = Bool
    type Register    = Bool

    -- | Linkage: Either internal to the translation unit or external
    data Linkage = InternalLinkage | ExternalLinkage
                   deriving (Typeable, Data, Show, Eq, Ord)

    -- | return @True@ if the object has linkage
    hasLinkage :: Storage -> Bool
    hasLinkage (Static _ _) = True
    hasLinkage _ = False

    -- * types

    -- | types of C objects
    data Type =
           DirectType TypeName TypeQuals
         -- ^ a non-derived type
         | PtrType Type TypeQuals Attributes
         -- ^ pointer type
         | ArrayType Type ArraySize TypeQuals Attributes
         -- ^ array type
         | FunctionType FunType
         -- ^ function type
         | TypeDefType TypeDefRef
         -- ^ a defined type
         | TypeOfExpr Expr
         -- ^ (GNU) typeof (/broken/ and should be removed, but we do not yet have expression type analysis)
         deriving (Typeable, Data)

    -- | Function types are of the form @FunType return-type params isVariadic attrs@.
    --
    -- If the parameter types aren't yet known, the function has type @FunTypeIncomplete type attrs@.
    data FunType = FunType Type [ParamDecl] Bool Attributes
                |  FunTypeIncomplete Type Attributes
                   deriving (Typeable, Data)

    -- | resolve typedefs, if possible
    derefTypeDef :: Type -> Type
    derefTypeDef (TypeDefType (TypeDefRef _ (Just actual_ty) _)) = derefTypeDef actual_ty
    derefTypeDef ty = ty

    -- may not be called on undefined typeDefs or typeof(expr)
    referencedType :: Type -> Maybe Type
    referencedType (PtrType ty _ _) = Just ty
    referencedType (FunctionType (FunType ty _ _ _)) = Just ty
    referencedType (ArrayType ty _ _ _) = Just ty
    referencedType (TypeDefType (TypeDefRef _ (Just actual_ty) _)) = Just actual_ty
    referencedType (DirectType _ _) = Nothing
    referencedType _ = error "referencedType: failed to resolve type"

    hasTypeOfExpr :: Type -> Bool
    hasTypeOfExpr (TypeOfExpr _) = True
    hasTypeOfExpr ty = maybe False hasTypeOfExpr (referencedType ty)

    -- | return @True@ if the given type is a function type
    --
    --   Result is undefined in the presence of TypeOfExpr or undefined typeDefs
    isFunctionType :: Type -> Bool
    isFunctionType ty =
        case ty of  TypeDefType (TypeDefRef _ (Just actual_ty) _) -> isFunctionType actual_ty
                    TypeDefType _ -> error "isFunctionType: unresolved typeDef"
                    TypeOfExpr _  -> error "isFunctionType: typeof(expr)"
                    FunctionType _ -> True
                    _ -> False

    -- | An array type may either have unknown size or a specified array size, the latter either variable or constant.
    -- Furthermore, when used as a function parameters, the size may be qualified as /static/.
    -- In a function prototype, the size may be `Unspecified variable size' (@[*]@).
    data ArraySize =  UnknownArraySize Bool
                    -- ^ @UnknownArraySize is-starred@
                    | ArraySize Bool Expr
                    -- ^ @FixedSizeArray is-static size-expr@
                   deriving (Typeable, Data)

    -- | normalized type representation
    data TypeName =
          TyVoid
        | TyIntegral IntType
        | TyFloating FloatType
        | TyComplex  FloatType
        | TyComp CompTypeRef
        | TyEnum EnumTypeRef
        | TyBuiltin BuiltinType
        deriving (Typeable, Data)

    -- | Builtin type (va_list)
    data BuiltinType = TyVaList
                       deriving (Typeable, Data)

    -- | typdef references
    -- If the actual type is known, it is attached for convenience
    data TypeDefRef = TypeDefRef Ident (Maybe Type) NodeInfo
                   deriving (Typeable, Data {-! CNode !-})

    -- | integral types (C99 6.7.2.2)
    data IntType =
          TyBool
        | TyChar
        | TySChar
        | TyUChar
        | TyShort
        | TyUShort
        | TyInt
        | TyUInt
        | TyLong
        | TyULong
        | TyLLong
        | TyULLong
        deriving (Typeable, Data, Eq, Ord)

    instance Show IntType where
        show TyBool = "_Bool"
        show TyChar = "char"
        show TySChar = "signed char"
        show TyUChar = "unsigned char"
        show TyShort = "short"
        show TyUShort = "unsigned short"
        show TyInt = "int"
        show TyUInt = "unsigned int"
        show TyLong = "long"
        show TyULong = "unsigned long"
        show TyLLong = "long long"
        show TyULLong = "unsigned long long"

    -- | floating point type (C99 6.7.2.2)
    data FloatType =
          TyFloat
        | TyDouble
        | TyLDouble
        deriving (Typeable, Data, Eq, Ord)

    instance Show FloatType where
        show TyFloat = "float"
        show TyDouble = "double"
        show TyLDouble = "long double"

    -- | composite type declarations
    data CompTypeRef = CompTypeRef SUERef CompTyKind NodeInfo
                        deriving (Typeable, Data {-! CNode !-})

    instance HasSUERef  CompTypeRef where sueRef  (CompTypeRef ref _ _) = ref
    instance HasCompTyKind CompTypeRef where compTag (CompTypeRef _ tag _)  = tag

    data EnumTypeRef = EnumTypeRef SUERef NodeInfo
        deriving (Typeable, Data {-! CNode !-})
    instance HasSUERef  EnumTypeRef where sueRef  (EnumTypeRef ref _) = ref

    -- | Composite type (struct or union).
    data CompType =  CompType SUERef CompTyKind [MemberDecl] Attributes NodeInfo
                     deriving (Typeable, Data {-! CNode !-} )
    instance HasSUERef  CompType where sueRef  (CompType ref _ _ _ _) = ref
    instance HasCompTyKind CompType where compTag (CompType _ tag _ _ _) = tag

    -- | return the type of a composite type definition
    typeOfCompDef :: CompType -> TypeName
    typeOfCompDef (CompType ref tag _ _ _) = TyComp (CompTypeRef ref tag internalNode)

    -- | a tag to determine wheter we refer to a @struct@ or @union@, see 'CompType'.
    data CompTyKind =  StructTag
                     | UnionTag
        deriving (Eq,Ord,Typeable,Data)

    instance Show CompTyKind where
        show StructTag = "struct"
        show UnionTag  = "union"

    -- | Representation of C enumeration types
    data EnumType = EnumType SUERef [Enumerator] Attributes NodeInfo
                     -- ^ @EnumType name enumeration-constants attrs node@
                     deriving (Typeable, Data {-! CNode !-} )

    instance HasSUERef EnumType where sueRef  (EnumType ref _ _ _) = ref

    -- | return the type of an enum definition
    typeOfEnumDef :: EnumType -> TypeName
    typeOfEnumDef (EnumType ref _ _ _) = TyEnum (EnumTypeRef ref internalNode)

    -- | An Enumerator consists of an identifier, a constant expressions and the link to its type
    data Enumerator = Enumerator Ident Expr EnumType NodeInfo
                      deriving (Typeable, Data {-! CNode !-})
    instance Declaration Enumerator where
      getVarDecl (Enumerator ide _ enumty _) =
        VarDecl
          (VarName ide Nothing)
          (DeclAttrs False NoStorage [])
          (DirectType (typeOfEnumDef enumty) noTypeQuals)

    -- | Type qualifiers: constant, volatile and restrict
    data TypeQuals = TypeQuals { constant :: Bool, volatile :: Bool, restrict :: Bool }
        deriving (Typeable, Data)

    -- | no type qualifiers
    noTypeQuals :: TypeQuals
    noTypeQuals = TypeQuals False False False

    -- | merge (/&&/) two type qualifier sets
    mergeTypeQuals :: TypeQuals -> TypeQuals -> TypeQuals
    mergeTypeQuals (TypeQuals c1 v1 r1) (TypeQuals c2 v2 r2) = TypeQuals (c1 && c2) (v1 && v2) (r1 && r2)

    -- * initializers

    -- | 'Initializer' is currently an alias for 'CInit'.
    --
    -- We're planning a normalized representation, but this depends on the implementation of
    -- constant expression evaluation
    type Initializer = CInit

    -- | Normalized C Initializers
    -- * If the expression has scalar type, the initializer is an expression
    -- * If the expression has struct type, the initializer is a map from designators to initializers
    -- * If the expression has array type, the initializer is a list of values
    -- Not implemented yet, as it depends on constant expression evaluation

    -- * names and attributes

    -- | @VarName name assembler-name@ is a name of an declared object
    data VarName =  VarName Ident (Maybe AsmName)
                  | NoName
                   deriving (Typeable, Data)
    identOfVarName :: VarName -> Ident
    identOfVarName NoName            = error "identOfVarName: NoName"
    identOfVarName (VarName ident _) = ident

    -- | Top level assembler block (alias for @CStrLit@)
    type AsmBlock = CStrLit

    -- | Assembler name (alias for @CStrLit@)
    type AsmName = CStrLit

    -- | @__attribute__@ annotations
    --
    -- Those are of the form @Attr attribute-name attribute-parameters@,
    -- and serve as generic properties of some syntax tree elements.
    --
    -- Some examples:
    --
    -- * labels can be attributed with /unused/ to indicate that their not used
    --
    -- * struct definitions can be attributed with /packed/ to tell the compiler to use the most compact representation
    --
    -- * declarations can be attributed with /deprecated/
    --
    -- * function declarations can be attributes with /noreturn/ to tell the compiler that the function will never return,
    --
    -- * or with /const/ to indicate that it is a pure function
    --
    -- /TODO/: ultimatively, we want to parse attributes and represent them in a typed way
    data Attr = Attr Ident [Expr] NodeInfo
                deriving (Typeable, Data {-! CNode !-})

    type Attributes = [Attr]

    -- * statements and expressions (Type aliases)

    -- | 'Stmt' is an alias for 'CStat' (Syntax)
    type Stmt = CStat
    -- | 'Expr' is currently an alias for 'CExpr' (Syntax)
    type Expr = CExpr

    --------------------------------------------------------
    -- DERIVES GENERATED CODE
    -- DO NOT MODIFY BELOW THIS LINE
    -- CHECKSUM: 1672142450

    instance CNode TagDef
        where nodeInfo (CompDef d) = nodeInfo d
              nodeInfo (EnumDef d) = nodeInfo d
    instance Pos TagDef
        where posOf x = posOfNode (nodeInfo x)

    instance CNode IdentDecl
        where nodeInfo (Declaration d) = nodeInfo d
              nodeInfo (ObjectDef d) = nodeInfo d
              nodeInfo (FunctionDef d) = nodeInfo d
              nodeInfo (EnumeratorDef d) = nodeInfo d
    instance Pos IdentDecl
        where posOf x = posOfNode (nodeInfo x)

    instance CNode DeclEvent
        where nodeInfo (TagEvent d) = nodeInfo d
              nodeInfo (DeclEvent d) = nodeInfo d
              nodeInfo (TypeDefEvent d) = nodeInfo d
              nodeInfo (AsmEvent d) = nodeInfo d
    instance Pos DeclEvent
        where posOf x = posOfNode (nodeInfo x)

    instance CNode Decl
        where nodeInfo (Decl _ nodeinfo) = nodeinfo
    instance Pos Decl
        where posOf x = posOfNode (nodeInfo x)

    instance CNode ObjDef
        where nodeInfo (ObjDef _ _ nodeinfo) = nodeinfo
    instance Pos ObjDef
        where posOf x = posOfNode (nodeInfo x)

    instance CNode FunDef
        where nodeInfo (FunDef _ _ nodeinfo) = nodeinfo
    instance Pos FunDef
        where posOf x = posOfNode (nodeInfo x)

    instance CNode ParamDecl
        where nodeInfo (ParamDecl _ nodeinfo) = nodeinfo
              nodeInfo (AbstractParamDecl _ nodeinfo) = nodeinfo
    instance Pos ParamDecl
        where posOf x = posOfNode (nodeInfo x)

    instance CNode MemberDecl
        where nodeInfo (MemberDecl _ _ nodeinfo) = nodeinfo
              nodeInfo (AnonBitField _ _ nodeinfo) = nodeinfo
    instance Pos MemberDecl
        where posOf x = posOfNode (nodeInfo x)

    instance CNode TypeDef
        where nodeInfo (TypeDef _ _ _ nodeinfo) = nodeinfo
    instance Pos TypeDef
        where posOf x = posOfNode (nodeInfo x)

    instance CNode TypeDefRef
        where nodeInfo (TypeDefRef _ _ nodeinfo) = nodeinfo
    instance Pos TypeDefRef
        where posOf x = posOfNode (nodeInfo x)

    instance CNode CompTypeRef
        where nodeInfo (CompTypeRef _ _ nodeinfo) = nodeinfo
    instance Pos CompTypeRef
        where posOf x = posOfNode (nodeInfo x)

    instance CNode EnumTypeRef
        where nodeInfo (EnumTypeRef _ nodeinfo) = nodeinfo
    instance Pos EnumTypeRef
        where posOf x = posOfNode (nodeInfo x)

    instance CNode CompType
        where nodeInfo (CompType _ _ _ _ nodeinfo) = nodeinfo
    instance Pos CompType
        where posOf x = posOfNode (nodeInfo x)

    instance CNode EnumType
        where nodeInfo (EnumType _ _ _ nodeinfo) = nodeinfo
    instance Pos EnumType
        where posOf x = posOfNode (nodeInfo x)

    instance CNode Enumerator
        where nodeInfo (Enumerator _ _ _ nodeinfo) = nodeinfo
    instance Pos Enumerator
        where posOf x = posOfNode (nodeInfo x)

    instance CNode Attr
        where nodeInfo (Attr _ _ nodeinfo) = nodeinfo
    instance Pos Attr
        where posOf x = posOfNode (nodeInfo x)