module Language.Scheme.Compiler.Libraries
(
importAll
)
where
import Language.Scheme.Compiler.Types
import qualified Language.Scheme.Core as LSC
(evalLisp, findFileOrLib, meval, nullEnvWithImport)
import Language.Scheme.Primitives
import Language.Scheme.Types
import Language.Scheme.Variables
import Control.Monad.Error
importAll
:: Env
-> Env
-> [LispVal]
-> CompLibOpts
-> CompOpts
-> IOThrowsError [HaskAST]
importAll env metaEnv [m] lopts
copts@(CompileOptions {}) = do
_importAll env metaEnv m lopts copts
importAll env metaEnv (m : ms) lopts
(CompileOptions thisFunc _ _ lastFunc) = do
Atom nextFunc <- _gensym "importAll"
c <- _importAll env metaEnv m lopts $
CompileOptions thisFunc False False (Just nextFunc)
rest <- importAll env metaEnv ms lopts $
CompileOptions nextFunc False False lastFunc
stub <- case rest of
[] -> return [createFunctionStub nextFunc lastFunc]
_ -> return []
return $ c ++ rest ++ stub
importAll _ _ [] _ _ = return []
_importAll :: Env
-> Env
-> LispVal
-> CompLibOpts
-> CompOpts
-> ErrorT LispError IO [HaskAST]
_importAll env metaEnv m lopts copts = do
resolved <- LSC.evalLisp metaEnv $
List [Atom "resolve-import", List [Atom "quote", m]]
case resolved of
List (moduleName : imports) -> do
importModule env metaEnv moduleName imports lopts copts
DottedList [List moduleName] imports@(Bool False) -> do
importModule env metaEnv (List moduleName) [imports] lopts copts
err -> throwError $ TypeMismatch "module/import" err
importModule :: Env
-> Env
-> LispVal
-> [LispVal]
-> CompLibOpts
-> CompOpts
-> ErrorT LispError IO [HaskAST]
importModule env metaEnv moduleName imports lopts
(CompileOptions thisFunc _ _ lastFunc) = do
Atom symImport <- _gensym "importFnc"
code <- loadModule metaEnv moduleName lopts $
CompileOptions thisFunc False False (Just symImport)
LispEnv modEnv <- LSC.evalLisp metaEnv $
List [Atom "module-env", List [Atom "find-module", List [Atom "quote", moduleName]]]
_ <- eval env $ List [Atom "%import",
LispEnv env,
LispEnv modEnv,
List [Atom "quote", List imports],
Bool False]
importFunc <- return $ [
codeToGetFromEnv moduleName code,
AstValue $ " _ <- evalLisp env $ List [Atom \"%import\", LispEnv env, value, List [Atom \"quote\", " ++
(ast2Str $ List imports) ++ "], Bool False]",
createAstCont (CompileOptions symImport False False lastFunc) "(value)" ""]
stub <- case code of
[] -> return [createFunctionStub thisFunc (Just symImport)]
_ -> return []
return $ [createAstFunc (CompileOptions symImport True False lastFunc)
importFunc] ++ code ++ stub
where
codeToGetFromEnv (List [Atom "scheme", Atom "r5rs"]) _ = do
AstValue $ " r5 <- liftIO $ r5rsEnv\n let value = LispEnv r5"
codeToGetFromEnv (List [Atom "scheme"]) _ = do
AstValue $ " r7 <- liftIO $ r7rsEnv\n let value = LispEnv r7"
codeToGetFromEnv (List [Atom "scheme", Atom "time", Atom "posix"]) _ = do
AstValue $ " e <- liftIO $ r7rsTimeEnv\n let value = LispEnv e"
codeToGetFromEnv name [] = do
AstValue $ " value <- evalLisp env $ List [Atom \"hash-table-ref\", Atom \"" ++
moduleRuntimeVar ++ "\", List [Atom \"quote\", " ++
(ast2Str name) ++ "]]"
codeToGetFromEnv _ _ = AstValue $ ""
loadModule
:: Env
-> LispVal
-> CompLibOpts
-> CompOpts
-> IOThrowsError [HaskAST]
loadModule metaEnv name lopts copts@(CompileOptions {}) = do
_mod' <- eval metaEnv $ List [Atom "find-module", List [Atom "quote", name]]
case _mod' of
Bool False -> return []
_ -> do
_mod <- recDerefPtrs _mod'
modEnv <- LSC.evalLisp metaEnv $ List [Atom "module-env", _mod]
case modEnv of
Bool False -> do
Atom symStartLoadNewEnv <- _gensym "startLoadingNewEnvFnc"
Atom symEndLoadNewEnv <- _gensym "doneLoadingNewEnvFnc"
newEnvFunc <- return $ [
AstValue $ " newEnv <- liftIO $ nullEnvWithImport",
AstValue $ " _ <- defineVar newEnv \"" ++ moduleRuntimeVar ++
"\" $ Pointer \"" ++ moduleRuntimeVar ++ "\" env",
AstValue $ " _ <- " ++ symStartLoadNewEnv ++
" newEnv (makeNullContinuation newEnv) (LispEnv env) (Just [])",
AstValue $ " _ <- evalLisp env $ List [Atom \"hash-table-set!\", Atom \"" ++
moduleRuntimeVar ++ "\", List [Atom \"quote\", " ++
(ast2Str name) ++ "], LispEnv newEnv]",
createAstCont copts "(LispEnv newEnv)" ""]
newEnv <- liftIO $ LSC.nullEnvWithImport
result <- compileModule newEnv metaEnv name _mod lopts $
CompileOptions symStartLoadNewEnv False False (Just symEndLoadNewEnv)
modWEnv <- eval metaEnv $ List (Atom "module-env-set!" : _mod' : [LispEnv newEnv])
_ <- eval metaEnv $ List [Atom "delete-module!", List [Atom "quote", name]]
_ <- eval metaEnv $ List [Atom "add-module!", List [Atom "quote", name], modWEnv]
return $
[createAstFunc copts newEnvFunc] ++
[createAstFunc (CompileOptions symEndLoadNewEnv False False Nothing)
[AstValue " return $ Nil \"\""]] ++
result
_ -> return [] --_mod
compileModule :: Env
-> Env
-> LispVal
-> LispVal
-> CompLibOpts
-> CompOpts
-> ErrorT LispError IO [HaskAST]
compileModule env metaEnv name _mod lopts
(CompileOptions thisFunc _ _ lastFunc) = do
Atom afterImportsFnc <- _gensym "modAfterImport"
metaData <- LSC.evalLisp metaEnv $
List [Atom "module-meta-data", List [Atom "quote", _mod]]
moduleImports <- cmpSubMod env metaEnv metaData lopts $
CompileOptions thisFunc False False (Just afterImportsFnc)
moduleDirectives <- cmpModExpr env metaEnv name metaData lopts $
moduleDirsCopts moduleImports afterImportsFnc
return $ moduleImports ++
moduleDirectives ++
(moduleStub moduleImports moduleDirectives afterImportsFnc)
where
moduleDirsCopts modImps afterImportsFnc = do
case modImps of
[] -> CompileOptions thisFunc False False (Just afterImportsFnc)
_ -> CompileOptions afterImportsFnc False False lastFunc
moduleStub modImps modDir afterImportsFnc = do
case (modImps, modDir) of
([], []) -> [createFunctionStub thisFunc lastFunc]
([], _) -> [createFunctionStub afterImportsFnc lastFunc]
(_, []) -> [createFunctionStub afterImportsFnc lastFunc]
_ -> []
createFunctionStub :: String -> Maybe String -> HaskAST
createFunctionStub thisFunc nextFunc = do
createAstFunc (CompileOptions thisFunc True False Nothing)
[createAstCont (CompileOptions "" True False nextFunc)
"value" ""]
cmpSubMod :: Env
-> Env
-> LispVal
-> CompLibOpts
-> CompOpts
-> ErrorT LispError IO [HaskAST]
cmpSubMod env metaEnv (List ((List (Atom "import-immutable" : modules)) : ls))
lopts copts = do
cmpSubMod env metaEnv
(List ((List (Atom "import" : modules)) : ls))
lopts copts
cmpSubMod env metaEnv (List ((List (Atom "import" : modules)) : ls)) lopts
(CompileOptions thisFunc _ _ lastFunc) = do
Atom nextFunc <- _gensym "cmpSubMod"
code <- importAll env metaEnv modules lopts $
CompileOptions thisFunc False False (Just nextFunc)
rest <- cmpSubMod env metaEnv (List ls) lopts $
CompileOptions nextFunc False False lastFunc
stub <- case rest of
[] -> return [createFunctionStub nextFunc lastFunc]
_ -> return []
return $ code ++ rest ++ stub
cmpSubMod env metaEnv (List (_ : ls)) lopts copts =
cmpSubMod env metaEnv (List ls) lopts copts
cmpSubMod _ _ _ _ (CompileOptions thisFunc _ _ lastFunc) =
return [createFunctionStub thisFunc lastFunc]
cmpModExpr :: Env
-> Env
-> LispVal
-> LispVal
-> CompLibOpts
-> CompOpts
-> ErrorT LispError IO [HaskAST]
cmpModExpr env metaEnv name (List ((List (Atom "include" : files)) : ls))
lopts@(CompileLibraryOptions _ compileLisp)
(CompileOptions thisFunc _ _ lastFunc) = do
dir <- LSC.evalLisp metaEnv $ List [Atom "module-name-prefix",
List [Atom "quote", name]]
Atom nextFunc <- _gensym "includeNext"
code <- includeAll env dir files compileInc lopts $
CompileOptions thisFunc False False (Just nextFunc)
rest <- cmpModExpr env metaEnv name (List ls) lopts $
CompileOptions nextFunc False False lastFunc
stub <- case rest of
[] -> return [createFunctionStub nextFunc lastFunc]
_ -> return []
return $ code ++ rest ++ stub
where
compileInc (String dir) (String filename) entry exit = do
let path = dir ++ filename
path' <- LSC.findFileOrLib path
compileLisp env path' entry exit
compileInc _ _ _ _ = throwError $ InternalError ""
cmpModExpr env metaEnv name (List ((List (Atom "include-ci" : code)) : ls)) lopts copts = do
cmpModExpr env metaEnv name
(List ((List (Atom "include" : code)) : ls)) lopts copts
cmpModExpr env metaEnv name (List ((List (Atom "body" : code)) : ls)) lopts copts = do
cmpModExpr env metaEnv name
(List ((List (Atom "begin" : code)) : ls)) lopts copts
cmpModExpr env metaEnv name
(List ((List (Atom "begin" : code')) : ls))
lopts@(CompileLibraryOptions compileBlock _)
(CompileOptions thisFunc _ _ lastFunc) = do
Atom nextFunc <- _gensym "cmpSubModNext"
code <- compileBlock thisFunc (Just nextFunc) env [] code'
rest <- cmpModExpr env metaEnv name (List ls) lopts $
CompileOptions nextFunc False False lastFunc
stub <- case rest of
[] -> return [createFunctionStub nextFunc lastFunc]
_ -> return []
return $ code ++ rest ++ stub
cmpModExpr env metaEnv name (List (_ : ls)) lopts copts =
cmpModExpr env metaEnv name (List ls) lopts copts
cmpModExpr _ _ _ _ _ (CompileOptions thisFunc _ _ lastFunc) =
return [createFunctionStub thisFunc lastFunc]
includeAll :: forall t t1 t2 t3.
t
-> t3
-> [t2]
-> (t3
-> t2 -> String -> Maybe String -> ErrorT LispError IO [HaskAST])
-> t1
-> CompOpts
-> ErrorT LispError IO [HaskAST]
includeAll _ dir [file] include _ --lopts
(CompileOptions thisFunc _ _ lastFunc) = do
include dir file thisFunc lastFunc
includeAll env dir (f : fs) include lopts
(CompileOptions thisFunc _ _ lastFunc) = do
Atom nextFunc <- _gensym "includeAll"
c <- include dir f thisFunc (Just nextFunc)
rest <- includeAll env dir fs include lopts $
CompileOptions nextFunc False False lastFunc
stub <- case rest of
[] -> return [createFunctionStub nextFunc lastFunc]
_ -> return []
return $ c ++ rest ++ stub
includeAll _ _ [] _ _ _ = return []
eval :: Env -> LispVal -> IOThrowsError LispVal
eval env lisp = do
LSC.meval env (makeNullContinuation env) lisp