{-# LANGUAGE RecordWildCards #-}
module HSE.All(
module X,
ParseFlags(..), defaultParseFlags, parseFlagsAddFixities, parseFlagsSetExtensions,
parseModuleEx, ParseError(..)
) where
import HSE.Util as X
import HSE.Evaluate as X
import HSE.Type as X
import HSE.Bracket as X
import HSE.Match as X
import HSE.Scope as X
import HSE.FreeVars as X
import Util
import CmdLine
import Control.Exception
import Data.Char
import Data.List
import Data.Maybe
import Language.Preprocessor.Cpphs
import qualified Data.Map as Map
data ParseFlags = ParseFlags
{encoding :: Encoding
,cppFlags :: CppFlags
,hseFlags :: ParseMode
}
defaultParseFlags :: ParseFlags
defaultParseFlags = ParseFlags defaultEncoding NoCpp defaultParseMode{fixities=Just baseFixities, ignoreLinePragmas=False, extensions=defaultExtensions}
parseFlagsNoLocations :: ParseFlags -> ParseFlags
parseFlagsNoLocations x = x{cppFlags = case cppFlags x of Cpphs y -> Cpphs $ f y; y -> y}
where f x = x{boolopts = (boolopts x){locations=False}}
parseFlagsAddFixities :: [Fixity] -> ParseFlags -> ParseFlags
parseFlagsAddFixities fx x = x{hseFlags=hse{fixities = Just $ fx ++ fromMaybe [] (fixities hse)}}
where hse = hseFlags x
parseFlagsSetExtensions :: [Extension] -> ParseFlags -> ParseFlags
parseFlagsSetExtensions es x = x{hseFlags=(hseFlags x){extensions = es}}
runCpp :: CppFlags -> FilePath -> String -> IO String
runCpp NoCpp _ x = return x
runCpp CppSimple _ x = return $ unlines [if "#" `isPrefixOf` ltrim x then "" else x | x <- lines x]
runCpp (Cpphs o) file x = runCpphs o file x
data ParseError = ParseError
{parseErrorLocation :: SrcLoc
,parseErrorMessage :: String
,parseErrorContents :: String
}
parseModuleEx :: ParseFlags -> FilePath -> Maybe String -> IO (Either ParseError (Module SrcSpanInfo, [Comment]))
parseModuleEx flags file str = do
str <- maybe (readFileEncoding (encoding flags) file) return str
ppstr <- runCpp (cppFlags flags) file str
case parseFileContentsWithComments (mode flags) ppstr of
ParseOk (x, cs) -> return $ Right (applyFixity fixity x, cs)
ParseFailed sl msg -> do
flags <- return $ parseFlagsNoLocations flags
ppstr2 <- runCpp (cppFlags flags) file str
pe <- return $ case parseFileContentsWithMode (mode flags) ppstr2 of
ParseFailed sl2 _ -> context (srcLine sl2) ppstr2
_ -> context (srcLine sl) ppstr
Control.Exception.evaluate $ length pe
return $ Left $ ParseError sl msg pe
where
fixity = fromMaybe [] $ fixities $ hseFlags flags
mode flags = (hseFlags flags)
{parseFilename = file
,fixities = Nothing
}
context :: Int -> String -> String
context lineNo src =
unlines $ trimBy (all isSpace) $
zipWith (++) ticks $ take 5 $ drop (lineNo - 3) $ lines src ++ ["","","","",""]
where ticks = [" "," ","> "," "," "]
applyFixity :: [Fixity] -> Module_ -> Module_
applyFixity base modu = descendBi f modu
where
f x = fromMaybe (cheapFixities fixs x) $ applyFixities fixs x :: Decl_
fixs = concatMap getFixity (moduleDecls modu) ++ base
cheapFixities :: [Fixity] -> Decl_ -> Decl_
cheapFixities fixs = descendBi (transform f)
where
ask = askFixity fixs
f o@(InfixApp s1 (InfixApp s2 x op1 y) op2 z)
| p1 == p2 && (a1 /= a2 || a1 == AssocNone) = o
| p1 > p2 || p1 == p2 && (a1 == AssocLeft || a2 == AssocNone) = o
| otherwise = InfixApp s1 x op1 (f $ InfixApp s1 y op2 z)
where
(a1,p1) = ask op1
(a2,p2) = ask op2
f x = x
askFixity :: [Fixity] -> QOp S -> (Assoc, Int)
askFixity xs = \k -> Map.findWithDefault (AssocLeft, 9) (fromNamed k) mp
where
mp = Map.fromList [(s,(a,p)) | Fixity a p x <- xs, let s = fromNamed x, s /= ""]