{- Lexical analysis of a file. -} module Parse.Lexical(lexical,lexicalCont,Lex ,LexState,PosToken,PosTokenPre,Pos) where import Util.Extra(Pos,toPos,strPos,insertPos) import Parse.Lex import Parse.LexPre import SysDeps(PackedString,packString,unpackPS) import TokenId type PosToken = (Pos,Lex, LexState, [PosTokenPre]) type LexState = [Int] -- stack of indentations of {} blocks -- 0 : no active indentation (explicit layout) lexical :: Bool -> [Char] -> [Char] -> [PosToken] -- with H'98 underscore -> filename -> file content -> tokens -- lexPre basically does the lexing, but afterwards iLex handles -- indentation for the layout rule lexical u file l = iLex [0] 0 (beginning (lexPre u file' l)) where file' = packString file -- handle pragmas and start and missing "module" header beginning :: [PosTokenPre] -> [PosTokenPre] beginning toks = case toks of lp@((f,r,c,L_module):_) -> lp lp@((f,r,c,L_AVARID t):_) | t==tinterface -> lp (lp@(f,r,c,L_LANNOT):rest) -> lp: discard_pragma rest lp -> ((file',toPos 1 0 0 0,0,L_module) :(file',toPos 1 0 0 0,0,L_ACONID tMain) :(file',toPos 1 0 0 0,0,L_where) :lp) discard_pragma (lp@(f,r,c,L_RANNOT):rest) = lp: beginning rest discard_pragma (lp@(f,r,c,_):rest) = lp: discard_pragma rest lexicalCont :: PosToken -> Either String [PosToken] lexicalCont (p,t,(i:s@(i':_)),r) = if i > 0 then -- Right ((p,t,s,r) : iLex s i' r) -- not correct? case r of ((f,_,_,_):_) -> Right (piLex f s i' p t r) else Left "Layout }" lexicalCont (p,t, [] ,r) = Left "Layout }" --- local iLex :: LexState -> Int -> [PosTokenPre] -> [PosToken] iLex s i [] = [] iLex s i ((f,p,c,t):pt) = seq p $ if c > i then piLex f s i p t pt else if c == i && i /= 0 && t /= L_in then seq p' $ (p',L_SEMI',s,pt) : piLex f s i p t pt else if c == 0 && i == 0 then piLex f s i p t pt else seq p' $ (p',L_RCURL',s,pt) : iLex s' i' ((f,p,c,t):pt) where (_:s'@(i':_)) = s p' = insertPos p piLex :: PackedString -> LexState -> Int -> Pos -> Lex -> [PosTokenPre] -> [PosToken] piLex file s i p tok tr@((f,p',c,t'):pt) | tok `elem` [L_let, L_where, L_of, L_do] = (p,tok,s,tr) : if t' == L_LCURL then seq p' $ (p',L_LCURL, s,pt) : iLex (0:s) 0 pt else let p'' = insertPos p' in seq p'' $ (p'', L_LCURL',s,tr) : if c > i then seq p' $ piLex f (c:s) c p' t' pt else (p, L_RCURL',s,tr) : iLex s i tr piLex file s i p L_LCURL pt = (p,L_LCURL,s,pt) : iLex (0:s) 0 pt piLex file s i p L_RCURL pt = if i == 0 then case s of (_:s'@(i':_)) -> (p,L_RCURL,s,pt) : iLex s' i' pt _ -> failPos file p "Unbalanced '}' (Stack empty)." else failPos file p "Unbalanced '}' (No explicit '{' in scope)" piLex file s i p t pt = (p,t,s,pt) : iLex s i pt failPos :: PackedString -> Pos -> [Char] -> a failPos file p msg = error ("Internal in " ++ unpackPS file ++ " at " ++ strPos p ++ ": " ++ msg ++ "\n")