module Language.Grammars.SyntaxMacros.ScanUtils ( ScanOpts(..), defaultScanOpts , isNoPos, posIs1stColumn , InFilePos(..), infpStart, infpNone , infpAdvCol, infpAdvLine, infpAdv1Line, infpAdvStr , genTokVal, genTokTp, genTokMap , isLF, isStr, isStrQuote , isWhite, isBlack , isVarStart, isVarRest ) where import System.IO import Data.Char import Data.List import qualified Data.Set as Set -- import EH.Util.Pretty import UU.Parsing import UU.Scanner.Position( noPos, Pos(..), Position(..) ) import UU.Scanner.GenToken ------------------------------------------------------------------------- -- Utils for GenToken ------------------------------------------------------------------------- genTokVal :: GenToken v t v -> v genTokVal (ValToken _ v _) = v genTokVal (Reserved v _) = v genTokTp :: GenToken k t v -> Maybe t genTokTp (ValToken t _ _) = Just t genTokTp _ = Nothing genTokMap :: (a->b) -> GenToken a t a -> GenToken b t b genTokMap f (ValToken t v p) = ValToken t (f v) p genTokMap f (Reserved k p) = Reserved (f k) p ------------------------------------------------------------------------- -- Utils for Pos ------------------------------------------------------------------------- isNoPos :: Pos -> Bool isNoPos (Pos l c f) = l < 0 || c < 0 posIs1stColumn :: Pos -> Bool posIs1stColumn p = column p == 1 ------------------------------------------------------------------------- -- InFilePos: Simplified Pos for inside a file only ------------------------------------------------------------------------- data InFilePos = InFilePos { infpLine, infpColumn :: Int } deriving (Eq,Ord) instance Show InFilePos where show (InFilePos l c) = if l < 0 || c < 0 then "" else "(" ++ show l ++ ":" ++ show c ++ ")" infpStart :: InFilePos infpStart = InFilePos 1 1 infpNone :: InFilePos infpNone = InFilePos (-1) (-1) infpAdvCol :: Int -> InFilePos -> InFilePos infpAdvCol i p = p {infpColumn = i + infpColumn p} infpAdvStr :: String -> InFilePos -> InFilePos infpAdvStr s p = infpAdvCol (length s) p infpAdvLine :: Int -> InFilePos -> InFilePos infpAdvLine i p = p {infpLine = i + infpLine p, infpColumn = 1} infpAdv1Line :: InFilePos -> InFilePos infpAdv1Line = infpAdvLine 1 ------------------------------------------------------------------------- -- PP of parse errors ------------------------------------------------------------------------- instance Position p => Position (Maybe p) where line = maybe (line noPos) line column = maybe (column noPos) column file = maybe (file noPos) file instance Position (GenToken k t v) where line = line . position column = column . position file = file . position {------------------------------------------------------------------------ instance PP Pos where pp (Pos l c f) = ppParens $ (if null f then empty else pp f >|< ":" ) >|< l >|< "," >|< c ------------------------------------------------------------------------} ------------------------------------------------------------------------- -- ScanOpts ------------------------------------------------------------------------- {- ScanOpts encode all possible options we ever might want to pass to a scanner used inside the EHC project. Hence not all options are used by all scanners. -} data ScanOpts = ScanOpts { scoKeywordsTxt :: !(Set.Set String) -- identifiers which are keywords , scoCommandsTxt :: !(Set.Set String) -- identifiers which are commands , scoKeywordsOps :: !(Set.Set String) -- operators which are keywords , scoSpecChars :: !(Set.Set Char) -- 1 char keywords , scoOpChars :: !(Set.Set Char) -- chars used for operators , scoSpecPairs :: !(Set.Set String) -- pairs of chars which form keywords , scoDollarIdent :: !Bool -- allow $ encoded identifiers , scoOffsideTrigs :: ![String] -- offside triggers , scoOffsideModule :: !String -- offside start of module , scoOffsideOpen :: !String -- offside open symbol , scoOffsideClose :: !String -- offside close symbol , scoLitmode :: !Bool -- do literal scanning , scoVerbOpenClose :: ![(String,String)] -- open/close pairs used for verbatim text , scoAllowQualified :: !Bool -- allow qualified variations, i.e. prefixing with "XXX." } defaultScanOpts :: ScanOpts defaultScanOpts = ScanOpts { scoKeywordsTxt = Set.empty , scoCommandsTxt = Set.empty , scoKeywordsOps = Set.empty , scoSpecChars = Set.empty , scoOpChars = Set.empty , scoSpecPairs = Set.empty , scoDollarIdent = False , scoOffsideTrigs = [] , scoOffsideModule = "" , scoOffsideOpen = "" , scoOffsideClose = "" , scoLitmode = False , scoVerbOpenClose = [] , scoAllowQualified = True } ------------------------------------------------------------------------- -- Char predicates ------------------------------------------------------------------------- isLF :: Char -> Bool isLF = (`elem` "\n\r") isStrQuote :: Char -> Bool isStrQuote c = c == '"' isStr :: Char -> Bool isStr c = not (isStrQuote c || isLF c) isVarStart :: Char -> Bool isVarStart c = c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' isVarRest :: Char -> Bool isVarRest c = isVarStart c || isDigit c || c `elem` "'_" isWhite :: Char -> Bool isWhite = (`elem` " \t") {- isDig :: Char -> Bool isDig c = c >= '0' && c <= '9' -} isBlack :: Char -> Bool isBlack c = not (isWhite c || isLF c)