{-# LANGUAGE DeriveDataTypeable, PatternGuards #-} ----------------------------------------------------------------------------- -- | -- Module : Language.C.Data.Position -- Copyright : (c) [1995..2000] Manuel M. T. Chakravarty -- License : BSD-style -- Maintainer : benedikt.huber@gmail.com -- Stability : experimental -- Portability : ghc -- -- Source code position ----------------------------------------------------------------------------- module Language.C.Data.Position ( -- -- source text positions -- Position(Position),initPos, posFile,posRow,posColumn,isSourcePos, nopos, isNoPos, builtinPos, isBuiltinPos, internalPos, isInternalPos, incPos, tabPos, retPos, adjustPos, Pos(..), ) where import Data.Generics -- | uniform representation of source file positions; the order of the arguments -- is important as it leads to the desired ordering of source positions data Position = Position String -- file name {-# UNPACK #-} !Int -- row {-# UNPACK #-} !Int -- column deriving (Eq, Ord, Typeable, Data) instance Show Position where show pos@(Position fname row col) | isNoPos pos = "" | isBuiltinPos pos = "" | isInternalPos pos = "" | otherwise = show (fname, row, col) instance Read Position where readsPrec p s = case s of '<' : _ -> readInternal s _ -> map (\((file,row,pos),r) -> (Position file row pos,r)) . readsPrec p $ s readInternal :: ReadS Position readInternal s | (Just rest) <- readString "" s = [(nopos,rest)] | (Just rest) <- readString "" s = [(builtinPos,rest)] | (Just rest) <- readString "" s = [(internalPos,rest)] | otherwise = [] where readString [] r = return r readString (c:cs) (c':cs') | c == c' = readString cs cs' | otherwise = Nothing readString (_:_) [] = Nothing -- | get the source file of the specified position. Fails unless @isSourcePos pos@. posFile :: Position -> String posFile (Position fname _ _) = fname -- | get the line number of the specified position. Fails unless @isSourcePos pos@ posRow :: Position -> Int posRow (Position _ row _) = row -- | get the column of the specified position. Fails unless @isSourcePos pos@ posColumn :: Position -> Int posColumn (Position _ _ col) = col -- | class of type which aggregate a source code location class Pos a where posOf :: a -> Position -- | initialize a Position to the start of the translation unit starting in the given file initPos :: FilePath -> Position initPos file = Position file 1 1 -- | returns @True@ if the given position refers to an actual source file isSourcePos :: Position -> Bool isSourcePos (Position _ row col) = row >= 0 && col >= 0 -- | no position (for unknown position information) nopos :: Position nopos = Position "" (-1) 0 isNoPos :: Position -> Bool isNoPos (Position _ (-1) 0) = True isNoPos _ = False -- | position attached to built-in objects -- builtinPos :: Position builtinPos = Position "" (-1) 1 -- | returns @True@ if the given position refers to a builtin definition isBuiltinPos :: Position -> Bool isBuiltinPos (Position _ (-1) 1) = True isBuiltinPos _ = False -- | position used for internal errors internalPos :: Position internalPos = Position "" (-1) 2 -- | returns @True@ if the given position is internal isInternalPos :: Position -> Bool isInternalPos (Position _ (-1) 2) = True isInternalPos _ = False {-# INLINE incPos #-} -- | advance column incPos :: Position -> Int -> Position incPos (Position fname row col) n = Position fname row (col + n) {-# DEPRECATED tabPos "Use 'incPos column-adjustment' instead" #-} -- | advance column to next tab positions (tabs are considered to be at every 8th column) tabPos :: Position -> Position tabPos (Position fname row col) = Position fname row (col + 8 - (col - 1) `mod` 8) {-# INLINE retPos #-} -- | advance to next line retPos :: Position -> Position retPos (Position fname row _col) = Position fname (row + 1) 1 {-# INLINE adjustPos #-} -- | adjust position: change file and line number, reseting column to 1. This is usually -- used for #LINE pragmas. adjustPos :: FilePath -> Int -> Position -> Position adjustPos fname row (Position _ _ _) = Position fname row 1