module Fay.Compiler.InitialPass where
import Fay.Compiler.Misc
import Fay.Types
import Fay.Compiler.Config
import Fay.Compiler.Decl (compileNewtypeDecl)
import Control.Applicative
import Control.Monad.Error
import Control.Monad.RWS
import Language.Haskell.Exts.Syntax
import Language.Haskell.Exts.Parser
initialPass :: Module -> Compile ()
initialPass (Module _ _ _ Nothing _ imports decls) = do
forM_ imports $ \imp ->
case imp of
ImportDecl _ _ _ _ Just{} _ _ -> return ()
ImportDecl _ name False _ Nothing Nothing _ ->
void $ unlessImported name $ \filepath contents -> do
result <- compileWith filepath initialPass contents
case result of
Right ((),st,_) ->
modify $ \s -> s { stateRecords = stateRecords st
, stateRecordTypes = stateRecordTypes st
, stateImported = stateImported st
, stateNewtypes = stateNewtypes st
}
Left err -> throwError err
i -> throwError $ UnsupportedImport i
forM_ decls scanRecordDecls
forM_ decls scanNewtypeDecls
initialPass m = throwError (UnsupportedModuleSyntax m)
compileWith :: (Show from,Parseable from)
=> FilePath
-> (from -> Compile ())
-> String
-> Compile (Either CompileError ((),CompileState,CompileWriter))
compileWith filepath with from = do
compileReader <- ask
compileState <- get
liftIO $ runCompile compileReader
compileState
(parseResult (throwError . uncurry ParseError)
with
(parseFay filepath from))
unlessImported :: ModuleName
-> (FilePath -> String -> Compile ())
-> Compile ()
unlessImported name importIt = do
imported <- gets stateImported
case lookup name imported of
Just _ -> return ()
Nothing -> do
dirs <- configDirectoryIncludePaths <$> config id
(filepath,contents) <- findImport dirs name
modify $ \s -> s { stateImported = (name,filepath) : imported }
importIt filepath contents
scanNewtypeDecls :: Decl -> Compile ()
scanNewtypeDecls (DataDecl _ NewType _ _ _ constructors _) =
void $ compileNewtypeDecl constructors
scanNewtypeDecls _ = return ()
scanRecordDecls :: Decl -> Compile ()
scanRecordDecls decl = do
case decl of
DataDecl _loc DataType _ctx name _tyvarb qualcondecls _deriv -> do
let ns = flip map qualcondecls (\(QualConDecl _loc' _tyvarbinds _ctx' condecl) -> conDeclName condecl)
addRecordTypeState name ns
_ -> return ()
case decl of
DataDecl _ DataType _ _ _ constructors _ -> dataDecl constructors
GDataDecl _ DataType _l _i _v _n decls _ -> dataDecl (map convertGADT decls)
_ -> return ()
where
addRecordTypeState name cons = modify $ \s -> s
{ stateRecordTypes = (UnQual name, map UnQual cons) : stateRecordTypes s }
conDeclName (ConDecl n _) = n
conDeclName (InfixConDecl _ n _) = n
conDeclName (RecDecl n _) = n
dataDecl :: [QualConDecl] -> Compile ()
dataDecl constructors = do
forM_ constructors $ \(QualConDecl _ _ _ condecl) ->
case condecl of
ConDecl name types -> do
let fields = map (Ident . ("slot"++) . show . fst) . zip [1 :: Integer ..] $ types
addRecordState name fields
InfixConDecl _t1 name _t2 ->
addRecordState name ["slot1", "slot2"]
RecDecl name fields' -> do
let fields = concatMap fst fields'
addRecordState name fields
where
addRecordState :: Name -> [Name] -> Compile ()
addRecordState name fields = modify $ \s -> s
{ stateRecords = (UnQual name,map UnQual fields) : stateRecords s }