{-# LANGUAGE DeriveDataTypeable #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Language.C.Syntax.Attributes
-- Copyright   :  (c) [1995..1999] Manuel M. T. Chakravarty
--                (c) 2008 Benedikt Huber (stripped radically)
-- License     :  BSD-style
-- Maintainer  :  benedikt.huber@gmail.com
-- Stability   :  experimental
-- Portability :  ghc
--
-- source position and unqiue name
-----------------------------------------------------------------------------
module Language.C.Data.Node (
   NodeInfo(..), internalNode,mkNodeInfoOnlyPos,mkNodeInfo,
   CNode(nodeInfo), fileOfNode,
   posOfNode, nameOfNode,
   eqByName,
) where
import Language.C.Data.Position
import Language.C.Data.Name     (Name)
import Data.Generics

-- | Parsed entity attribute
data NodeInfo = OnlyPos   Position           -- only pos (for internal stuff only)
              | NodeInfo Position Name      -- pos and unique name
           deriving (Show,Read,Data,Typeable)

-- name equality of attributes, used to define (name) equality of objects
instance Eq NodeInfo where
  (NodeInfo   _ id1) == (NodeInfo   _ id2) = id1 == id2
  _               == _               =
    error "Attributes: Attempt to compare `OnlyPos' attributes!"

-- attribute ordering
instance Ord NodeInfo where
  (NodeInfo   _ id1) <= (NodeInfo   _ id2) = id1 <= id2
  _               <= _               =
    error "Attributes: Attempt to compare `OnlyPos' attributes!"

instance Pos NodeInfo where
  posOf (OnlyPos pos) = pos
  posOf (NodeInfo pos _) = pos

-- | a class for convenient access to the attributes of an attributed object
class CNode a where
  nodeInfo :: a -> NodeInfo
instance CNode NodeInfo where
  nodeInfo = id
instance (CNode a, CNode b) => CNode (Either a b) where
  nodeInfo = either nodeInfo nodeInfo

nameOfNode :: NodeInfo -> Maybe Name
nameOfNode (OnlyPos _) = Nothing
nameOfNode (NodeInfo _ name) = Just name
posOfNode :: NodeInfo -> Position
posOfNode ni = case ni of (OnlyPos pos  ) -> pos; (NodeInfo   pos _) -> pos
fileOfNode :: (CNode a) => a -> FilePath
fileOfNode = posFile . posOfNode . nodeInfo

-- | equality by name
eqByName           :: CNode a => a -> a -> Bool
eqByName obj1 obj2  = (nodeInfo obj1) == (nodeInfo obj2)


-- attribute identifier creation
-- -----------------------------

internalNode :: NodeInfo
internalNode = OnlyPos nopos

-- | Given only a source position, create a new attribute identifier
mkNodeInfoOnlyPos :: Position -> NodeInfo
mkNodeInfoOnlyPos pos  = OnlyPos pos

-- | Given a source position and a unique name, create a new attribute
-- identifier
mkNodeInfo :: Position -> Name -> NodeInfo
mkNodeInfo pos name  = NodeInfo pos name