mirror of
https://github.com/carp-lang/Carp.git
synced 2024-09-19 01:18:40 +03:00
444 lines
21 KiB
Haskell
444 lines
21 KiB
Haskell
{-# LANGUAGE TupleSections #-}
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
-- | Defines data, errors, and functions for qualifying symbols in a given
|
|
-- context.
|
|
module Qualify
|
|
( QualificationError,
|
|
QualifiedPath,
|
|
Qualified (..),
|
|
qualify,
|
|
qualifyPath,
|
|
unqualify,
|
|
markQualified,
|
|
qualifyNull,
|
|
getQualifiedPath,
|
|
)
|
|
where
|
|
|
|
import Control.Monad (foldM, liftM)
|
|
import Data.Bifunctor
|
|
import Data.Either (fromRight)
|
|
import qualified Env as E
|
|
import Info
|
|
import qualified Map
|
|
import Obj
|
|
import qualified Set
|
|
import SymPath
|
|
import Util
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Errors
|
|
|
|
-- | Error qualifying a symbol.
|
|
data QualificationError
|
|
= FailedToQualifyDeclarationName XObj
|
|
| FailedToQualifySymbols XObj
|
|
| FailedToQualifyPath SymPath
|
|
| NonVariableInMatch XObj
|
|
| NakedInitForUnnamedModule [String]
|
|
| QualifiedMulti SymPath
|
|
| LocalMulti SymPath [(Env, Binder)]
|
|
| FailedToFindSymbol XObj
|
|
|
|
instance Show QualificationError where
|
|
show (FailedToQualifyDeclarationName xobj) =
|
|
"Couldn't fully qualify the definition: " ++ pretty xobj
|
|
show (FailedToQualifySymbols xobj) =
|
|
"Couldn't fully qualify the symbols in the form: " ++ pretty xobj
|
|
show (FailedToQualifyPath spath) =
|
|
"Couldn't fully qualify the symbol: " ++ show spath
|
|
++ "in the given context."
|
|
show (NonVariableInMatch xobj) =
|
|
"Couldn't qualify the xobj: " ++ pretty xobj
|
|
++ "in a match expression."
|
|
show (NakedInitForUnnamedModule s) =
|
|
"Tried to emit a naked init for an unnamed module: " ++ (show s)
|
|
show (QualifiedMulti spath) =
|
|
"Tried to use a qualified symbol as a multi sym: " ++ (show spath)
|
|
show (LocalMulti spath binders) =
|
|
"Tried to use a symbol that has local bindings as a multi sym: " ++ show spath
|
|
++ show binders
|
|
show (FailedToFindSymbol xobj) =
|
|
"Couldn't find the xobj: " ++ pretty xobj
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Data
|
|
|
|
-- | Denotes an XObj containing only symbols that *have been fully qualified*.
|
|
--
|
|
-- A fully qualified xobj **must not** be qualified further (e.g. using context
|
|
-- paths).
|
|
newtype Qualified = Qualified {unQualified :: XObj} deriving (Show)
|
|
|
|
-- | Denotes a symbol that has been fully qualified.
|
|
newtype QualifiedPath = QualifiedPath SymPath
|
|
deriving (Ord, Eq)
|
|
|
|
instance Show QualifiedPath where
|
|
show (QualifiedPath spath) = show spath
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Path Qualification Functions
|
|
|
|
-- | Qualifies a symbol in a given Context.
|
|
qualifyPath :: Context -> SymPath -> QualifiedPath
|
|
qualifyPath ctx spath =
|
|
let qpath = consPath (contextPath ctx) spath
|
|
in (QualifiedPath qpath)
|
|
|
|
-- | Transforms a qualified path into an equivalent SymPath.
|
|
--
|
|
-- Used to cross the qualified/unqualified symbol boundary.
|
|
-- This is predominantly used for compatibility with other parts of the
|
|
-- codebase once qualification checks have been performed.
|
|
unqualify :: QualifiedPath -> SymPath
|
|
unqualify (QualifiedPath spath) = spath
|
|
|
|
-- | Marks a path as fully qualified without performing any transformations.
|
|
--
|
|
-- Used to indicate a "naked", unprocessed path should be treated qualified as
|
|
-- given. For example, `inc` in `(implements inc Module.inc)` should be
|
|
-- interpreted as fully qualified as typed and should not be qualified using
|
|
-- the overarching context.
|
|
markQualified :: SymPath -> QualifiedPath
|
|
markQualified = QualifiedPath
|
|
|
|
-- | Qualify a symbol contextually if it is not qualified, otherwise, mark it
|
|
-- qualified.
|
|
--
|
|
-- This should be used whenever a path entered with *any* initial
|
|
-- qualifications should be treated as an absolute reference while symbols
|
|
-- without qualifications should be treated as a relative reference.
|
|
--
|
|
-- For example, `Foo.inc` in `(implements inc Foo.inc)` will be treated as an
|
|
-- absolute reference to `Foo.inc`, even in the context of `Foo` and will not
|
|
-- be qualified further. Contrarily, the second `inc` in `(implements inc inc)`
|
|
-- in the context of `Foo` would be further qualified to `Foo.inc`.
|
|
qualifyNull :: Context -> SymPath -> QualifiedPath
|
|
qualifyNull ctx spath@(SymPath [] _) = qualifyPath ctx spath
|
|
qualifyNull _ spath = markQualified spath
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- XObj Qualification Functions
|
|
|
|
-- | Gets the qualified path of a fully qualified XObj.
|
|
getQualifiedPath :: Qualified -> QualifiedPath
|
|
getQualifiedPath = QualifiedPath . getPath . unQualified
|
|
|
|
-- | Qualifies all symbols in an XObj in the given context.
|
|
qualify :: Context -> XObj -> Either QualificationError Qualified
|
|
qualify ctx xobj@(XObj obj info ty) =
|
|
-- TODO: Merge this with setFullyQualifiedSymbols
|
|
case obj of
|
|
Lst [defn, (XObj (Sym (SymPath _ name) mode) symi symt), args, body] ->
|
|
inner >>= \i -> setFullyQualifiedSymbols t g i (XObj (Lst [defn, (XObj (Sym (SymPath pathStrings name) mode) symi symt), args, body]) info ty)
|
|
Lst [def, XObj (Sym (SymPath _ name) mode) symi symt, expr] ->
|
|
inner >>= \i -> setFullyQualifiedSymbols t g i (XObj (Lst [def, (XObj (Sym (SymPath pathStrings name) mode) symi symt), expr]) info ty)
|
|
_ -> inner >>= \i -> setFullyQualifiedSymbols t g i xobj
|
|
where
|
|
pathStrings :: [String]
|
|
pathStrings = contextPath ctx
|
|
t :: TypeEnv
|
|
t = contextTypeEnv ctx
|
|
g :: Env
|
|
g = contextGlobalEnv ctx
|
|
inner :: Either QualificationError Env
|
|
inner = replaceLeft (FailedToQualifySymbols xobj) (E.getInnerEnv g pathStrings)
|
|
|
|
-- | Changes all symbols EXCEPT bound vars (defn names, variable names, etc) to their fully qualified paths.
|
|
-- | This must run after the 'setFullyQualifiedDefn' function has fixed the paths of all bindings in the environment.
|
|
-- | This function does NOT go into function-body scope environments and the like.
|
|
setFullyQualifiedSymbols :: TypeEnv -> Env -> Env -> XObj -> Either QualificationError Qualified
|
|
setFullyQualifiedSymbols t g e xobj =
|
|
case qualified of
|
|
Right qualifiedXObj -> Right $ Qualified $ qualifiedXObj
|
|
err -> fmap Qualified err
|
|
where
|
|
qualified :: Either QualificationError XObj
|
|
qualified =
|
|
fmap unQualified $
|
|
case xobjObj xobj of
|
|
Lst ((XObj (Defn _) _ _) : _) ->
|
|
qualifyFunctionDefinition t g e xobj
|
|
Lst ((XObj (Fn _ _) _ _) : _) ->
|
|
qualifyLambda t g e xobj
|
|
Lst ((XObj The _ _) : _) ->
|
|
qualifyThe t g e xobj
|
|
Lst ((XObj Def _ _) : _) ->
|
|
qualifyDef t g e xobj
|
|
Lst ((XObj Let _ _) : _) ->
|
|
qualifyLet t g e xobj
|
|
Lst ((XObj (Match _) _ _) : _) ->
|
|
qualifyMatch t g e xobj
|
|
Lst ((XObj With _ _) : _) ->
|
|
qualifyWith t g e xobj
|
|
Lst _ ->
|
|
qualifyLst t g e xobj
|
|
Sym _ _ ->
|
|
qualifySym t g e xobj
|
|
Arr _ ->
|
|
qualifyArr t g e xobj
|
|
StaticArr _ ->
|
|
qualifyStaticArr t g e xobj
|
|
_ -> Right $ Qualified $ xobj
|
|
|
|
-- | The type of functions that qualify XObjs (forms/s-expressions).
|
|
type Qualifier = TypeEnv -> Env -> Env -> XObj -> Either QualificationError Qualified
|
|
|
|
-- Note to maintainers: liftM unQualified is used extensively throughout to
|
|
-- turn a Qualified XObj back into an XObj for further nesting. Recall that:
|
|
--
|
|
-- foo <- liftM unQualified x === foo <- pure . unQualified =<< x
|
|
|
|
-- | Qualify the symbols in a Defn form's body.
|
|
qualifyFunctionDefinition :: Qualifier
|
|
qualifyFunctionDefinition typeEnv globalEnv env x@(XObj (Lst [defn@(XObj (Defn _) _ _), sym@(XObj (Sym (SymPath _ functionName) _) _ _), args@(XObj (Arr argsArr) _ _), body]) i t) =
|
|
-- For self-recursion, there must be a binding to the function in the inner env.
|
|
-- It is marked as RecursionEnv basically is the same thing as external to not mess up lookup.
|
|
-- Inside the recursion env is the function env that contains bindings for the arguments of the function.
|
|
-- Note: These inner envs is ephemeral since they are not stored in a module or global scope.
|
|
do
|
|
recursionEnv <- fixLeft (pure (E.recursive (Just env) (Just (functionName ++ "-recurse-env")) 0))
|
|
envWithSelf <- fixLeft (E.insertX recursionEnv (SymPath [] functionName) sym)
|
|
-- Copy the use modules from the local env to ensure they are available from the function env.
|
|
functionEnv <- fixLeft (pure ((E.nested (Just envWithSelf) (Just (functionName ++ "-function-env")) 0) {envUseModules = (envUseModules env)}))
|
|
envWithArgs <- fixLeft (foldM (\e arg@(XObj (Sym path _) _ _) -> E.insertX e path arg) functionEnv argsArr)
|
|
qualifiedBody <- liftM unQualified (setFullyQualifiedSymbols typeEnv globalEnv envWithArgs body)
|
|
pure (Qualified (XObj (Lst [defn, sym, args, qualifiedBody]) i t))
|
|
where
|
|
fixLeft = replaceLeft (FailedToQualifyDeclarationName x)
|
|
qualifyFunctionDefinition _ _ _ xobj = Left $ FailedToQualifyDeclarationName xobj
|
|
|
|
-- | Qualify the symbols in a lambda body.
|
|
qualifyLambda :: Qualifier
|
|
qualifyLambda typeEnv globalEnv env x@(XObj (Lst [fn@(XObj (Fn _ _) _ _), args@(XObj (Arr argsArr) _ _), body]) i t) =
|
|
let lvl = envFunctionNestingLevel env
|
|
functionEnv = Env Map.empty (Just env) Nothing Set.empty InternalEnv (lvl + 1)
|
|
in (replaceLeft (FailedToQualifySymbols x) (foldM (\e arg@(XObj (Sym path _) _ _) -> E.insertX e path arg) functionEnv argsArr))
|
|
>>= \envWithArgs ->
|
|
liftM unQualified (setFullyQualifiedSymbols typeEnv globalEnv envWithArgs body)
|
|
>>= \qualifiedBody -> pure (Qualified (XObj (Lst [fn, args, qualifiedBody]) i t))
|
|
qualifyLambda _ _ _ xobj = Left $ FailedToQualifySymbols xobj
|
|
|
|
-- | Qualify the symbols in a The form's body.
|
|
qualifyThe :: Qualifier
|
|
qualifyThe typeEnv globalEnv env (XObj (Lst [the@(XObj The _ _), typeX, value]) i t) =
|
|
do
|
|
qualifiedValue <- liftM unQualified (setFullyQualifiedSymbols typeEnv globalEnv env value)
|
|
pure (Qualified (XObj (Lst [the, typeX, qualifiedValue]) i t))
|
|
qualifyThe _ _ _ xobj = Left $ FailedToQualifySymbols xobj
|
|
|
|
-- | Qualify the symbols in a Def form's body.
|
|
qualifyDef :: Qualifier
|
|
qualifyDef typeEnv globalEnv env (XObj (Lst [def@(XObj Def _ _), sym, expr]) i t) =
|
|
do
|
|
qualifiedExpr <- liftM unQualified (setFullyQualifiedSymbols typeEnv globalEnv env expr)
|
|
pure (Qualified (XObj (Lst [def, sym, qualifiedExpr]) i t))
|
|
qualifyDef _ _ _ xobj = Left $ FailedToQualifySymbols xobj
|
|
|
|
-- | Qualify the symbols in a Let form's bindings and body.
|
|
qualifyLet :: Qualifier
|
|
qualifyLet typeEnv globalEnv env x@(XObj (Lst [letExpr@(XObj Let _ _), bind@(XObj (Arr bindings) bindi bindt), body]) i t)
|
|
| odd (length bindings) = Right $ Qualified $ XObj (Lst [letExpr, bind, body]) i t -- Leave it untouched for the compiler to find the error.
|
|
| not (all isSym (evenIndices bindings)) = Right $ Qualified $ XObj (Lst [letExpr, bind, body]) i t -- Leave it untouched for the compiler to find the error.
|
|
| otherwise =
|
|
do
|
|
let Just ii = i
|
|
lvl = envFunctionNestingLevel env
|
|
innerEnv = Env Map.empty (Just env) (Just ("let-env-" ++ show (infoIdentifier ii))) Set.empty InternalEnv lvl
|
|
(innerEnv', qualifiedBindings) <- foldM qualifyBinding (innerEnv, []) (pairwise bindings)
|
|
qualifiedBody <- liftM unQualified (setFullyQualifiedSymbols typeEnv globalEnv innerEnv' body)
|
|
pure (Qualified (XObj (Lst [letExpr, XObj (Arr qualifiedBindings) bindi bindt, qualifiedBody]) i t))
|
|
where
|
|
qualifyBinding :: (Env, [XObj]) -> (XObj, XObj) -> Either QualificationError (Env, [XObj])
|
|
qualifyBinding (e, bs) (s@(XObj (Sym path _) _ _), o@(XObj (Lst [(XObj (Fn _ _) _ _), _, _]) _ _)) =
|
|
do
|
|
-- Let bindings to anonymous functions may recursively call themselves,
|
|
-- qualify the symbols appropriately by adding a recursion environment.
|
|
-- e.g. (let [f (fn [x] (if (= x 1) x (f (dec x))))])
|
|
-- Environment parenting is a bit nuanced here; the recursive reference
|
|
-- needs to be stored in a recursive env to mark the symbol correctly.
|
|
-- However, we also need to ensure captured variables are still marked
|
|
-- as such, which is based on env nesting level, and we need to ensure
|
|
-- the recursive reference isn't accidentally captured.
|
|
let Just origin = E.parent e
|
|
recursionEnv <- fixLeft (pure (E.recursive (Just e) (Just ("let-recurse-env")) 0))
|
|
envWithSelf <- fixLeft (E.insertX recursionEnv path s)
|
|
qualified <- liftM unQualified (setFullyQualifiedSymbols typeEnv globalEnv (E.setParent e (E.setParent origin envWithSelf)) o)
|
|
updated <- (replaceLeft (FailedToQualifySymbols x) (E.insertX e path s))
|
|
(pure (updated, bs ++ [s, qualified]))
|
|
where
|
|
fixLeft = replaceLeft (FailedToQualifyDeclarationName x)
|
|
qualifyBinding (e, bs) (s@(XObj (Sym path _) _ _), o) =
|
|
do
|
|
qualified <- liftM unQualified (setFullyQualifiedSymbols typeEnv globalEnv e o)
|
|
updated <- (replaceLeft (FailedToQualifySymbols x) (E.insertX e path s))
|
|
(pure (updated, bs ++ [s, qualified]))
|
|
qualifyBinding _ _ = error "bad let binding"
|
|
qualifyLet _ _ _ xobj = Left $ FailedToQualifySymbols xobj
|
|
|
|
-- | Qualify symbols in a Match form.
|
|
qualifyMatch :: Qualifier
|
|
qualifyMatch typeEnv globalEnv env (XObj (Lst (matchExpr@(XObj (Match _) _ _) : expr : casesXObjs)) i t)
|
|
-- Leave it untouched for the compiler to find the error.
|
|
| odd (length casesXObjs) = pure $ Qualified $ XObj (Lst (matchExpr : expr : casesXObjs)) i t
|
|
| otherwise =
|
|
do
|
|
qualifiedExpr <- pure . unQualified =<< setFullyQualifiedSymbols typeEnv globalEnv env expr
|
|
qualifiedCases <- pure . map (map unQualified) =<< mapM qualifyCases (pairwise casesXObjs)
|
|
pure (Qualified (XObj (Lst (matchExpr : qualifiedExpr : concat qualifiedCases)) i t))
|
|
where
|
|
Just ii = i
|
|
lvl = envFunctionNestingLevel env
|
|
-- Create an inner environment for each case.
|
|
innerEnv :: Env
|
|
innerEnv = E.nested (Just env) (Just ("case-env-" ++ show (infoIdentifier ii))) lvl
|
|
-- Qualify each case in the match form.
|
|
qualifyCases :: (XObj, XObj) -> Either QualificationError [Qualified]
|
|
qualifyCases (l@(XObj (Lst (_ : xs)) _ _), r) =
|
|
do
|
|
innerEnv' <- foldM foldVars innerEnv xs
|
|
qualifiedLHS <- setFullyQualifiedSymbols typeEnv globalEnv innerEnv' l
|
|
qualifiedRHS <- setFullyQualifiedSymbols typeEnv globalEnv innerEnv' r
|
|
Right [qualifiedLHS, qualifiedRHS]
|
|
qualifyCases (wild@(XObj (Sym (SymPath _ "_") _) _ _), r) =
|
|
do
|
|
qualifiedLHS <- foldVars env wild >>= \e -> setFullyQualifiedSymbols typeEnv globalEnv e wild
|
|
qualifiedRHS <- setFullyQualifiedSymbols typeEnv globalEnv env r
|
|
Right [qualifiedLHS, qualifiedRHS]
|
|
qualifyCases (l, r) =
|
|
do
|
|
qualifiedLHS <- setFullyQualifiedSymbols typeEnv globalEnv env l
|
|
qualifiedRHS <- setFullyQualifiedSymbols typeEnv globalEnv env r
|
|
Right [qualifiedLHS, qualifiedRHS]
|
|
-- Add variables in a case to its environment
|
|
foldVars :: Env -> XObj -> Either QualificationError Env
|
|
foldVars env' v@(XObj (Sym path _) _ _) = (replaceLeft (FailedToQualifySymbols v) (E.insertX env' path v))
|
|
-- Nested sumtypes; fold recursively -- is there a more efficient way?
|
|
foldVars _ (XObj (Lst (_ : ys)) _ _) = foldM foldVars innerEnv ys
|
|
foldVars _ v = Left $ NonVariableInMatch v
|
|
qualifyMatch _ _ _ xobj = Left $ FailedToQualifySymbols xobj
|
|
|
|
-- | Qualify symbols in a With form.
|
|
qualifyWith :: Qualifier
|
|
qualifyWith typeEnv globalEnv env (XObj (Lst [XObj With _ _, XObj (Sym path _) _ _, expression]) _ _) =
|
|
let useThese = envUseModules env
|
|
env' = env {envUseModules = Set.insert path useThese}
|
|
in setFullyQualifiedSymbols typeEnv globalEnv env' expression
|
|
qualifyWith _ _ _ xobj = Left $ FailedToQualifySymbols xobj
|
|
|
|
-- | Qualify symbols in a generic Lst form.
|
|
qualifyLst :: Qualifier
|
|
qualifyLst typeEnv globalEnv env (XObj (Lst xobjs) i t) =
|
|
-- TODO: Perhaps this general case can be sufficient? No need with all the cases above..?
|
|
do
|
|
qualifiedXObjs <- liftM (map unQualified) (mapM (setFullyQualifiedSymbols typeEnv globalEnv env) xobjs)
|
|
pure (Qualified (XObj (Lst qualifiedXObjs) i t))
|
|
qualifyLst _ _ _ xobj = Left $ FailedToQualifySymbols xobj
|
|
|
|
-- | Qualify a single symbol.
|
|
qualifySym :: Qualifier
|
|
-- Unqualified path.
|
|
qualifySym typeEnv globalEnv localEnv xobj@(XObj (Sym path@(SymPath _ name) _) i t) =
|
|
( ( ( replaceLeft
|
|
(FailedToFindSymbol xobj)
|
|
-- TODO: Why do we need getValue here? We should be able to restrict this
|
|
-- search only to direct children of the type environment, but this causes
|
|
-- errors.
|
|
( fmap (\(e, b) -> ((E.prj typeEnv), (E.prj e, b))) (E.searchType typeEnv path)
|
|
<> fmap (localEnv,) (E.searchValue localEnv path)
|
|
<> fmap (globalEnv,) (E.searchValue globalEnv path)
|
|
)
|
|
)
|
|
>>= \(origin, (e, binder)) ->
|
|
resolve (E.prj origin) (E.prj e) (binderXObj binder)
|
|
>>= pure . Qualified
|
|
)
|
|
<> ((resolveMulti path (E.lookupInUsed localEnv globalEnv path)) >>= pure . Qualified)
|
|
<> ((replaceLeft (FailedToFindSymbol xobj) (E.lookupContextually globalEnv path)) >>= (resolveMulti path) >>= pure . Qualified)
|
|
<> ((resolveMulti path (E.lookupEverywhere globalEnv name)) >>= pure . Qualified)
|
|
<> pure (Qualified xobj)
|
|
)
|
|
where
|
|
resolve :: Env -> Env -> XObj -> Either QualificationError XObj
|
|
resolve _ _ (XObj (Lst (XObj (Interface _ _) _ _ : _)) _ _) =
|
|
-- Before we return an interface, double check that it isn't shadowed by a local let-binding.
|
|
case (E.searchValue localEnv path) of
|
|
Right (e, Binder _ _) ->
|
|
case envMode e of
|
|
InternalEnv -> pure (XObj (Sym (getPath xobj) (LookupLocal (captureOrNot e localEnv))) i t)
|
|
_ -> pure (XObj (InterfaceSym name) i t)
|
|
_ -> pure (XObj (InterfaceSym name) i t)
|
|
resolve _ _ x@(XObj (Lst (XObj (External (Just overrideName)) _ _ : _)) _ _) =
|
|
pure (XObj (Sym (getPath x) (LookupGlobalOverride overrideName)) i t)
|
|
resolve _ _ (XObj (Mod modenv _) _ _) =
|
|
nakedInit modenv
|
|
resolve origin found xobj' =
|
|
if (isTypeDef xobj')
|
|
then
|
|
( (replaceLeft (FailedToFindSymbol xobj') (fmap (globalEnv,) (E.searchValue globalEnv path)))
|
|
>>= \(origin', (e', binder)) -> resolve (E.prj origin') (E.prj e') (binderXObj binder)
|
|
)
|
|
else case envMode (E.prj found) of
|
|
RecursionEnv -> pure (XObj (Sym (getPath xobj') LookupRecursive) i t)
|
|
InternalEnv -> pure (XObj (Sym (getPath xobj') (LookupLocal (captureOrNot found origin))) i t)
|
|
ExternalEnv -> pure (XObj (Sym (getPath xobj') (LookupGlobal (if isExternalFunction xobj' then ExternalCode else CarpLand) (definitionMode xobj'))) i t)
|
|
resolveMulti :: (Show e, E.Environment e) => SymPath -> [(e, Binder)] -> Either QualificationError XObj
|
|
resolveMulti _ [] =
|
|
Left (FailedToFindSymbol xobj)
|
|
resolveMulti _ [(e, b)] =
|
|
resolve (E.prj e) (E.prj e) (binderXObj b)
|
|
resolveMulti spath xs =
|
|
let localOnly = remove (E.envIsExternal . fst) xs
|
|
paths = map (getModuleSym . (second binderXObj)) xs
|
|
in case localOnly of
|
|
[] -> case spath of
|
|
(SymPath [] _) ->
|
|
Right $ XObj (MultiSym name paths) i t
|
|
_ -> Left (QualifiedMulti spath)
|
|
ys -> Left (LocalMulti spath (map (first E.prj) ys))
|
|
nakedInit :: Env -> Either QualificationError XObj
|
|
nakedInit e =
|
|
maybe
|
|
(Left (NakedInitForUnnamedModule (pathToEnv e)))
|
|
(Right . id)
|
|
( envModuleName e
|
|
>>= \name' ->
|
|
pure (XObj (Sym (SymPath ((init (pathToEnv e)) ++ [name']) "init") (LookupGlobal CarpLand AFunction)) i t)
|
|
)
|
|
getModuleSym (_, x) =
|
|
case x of
|
|
XObj (Mod ev _) _ _ ->
|
|
fromRight
|
|
(SymPath (init (pathToEnv ev)) name)
|
|
( (replaceLeft (FailedToFindSymbol x) (E.searchType globalEnv (SymPath (init (pathToEnv ev)) name)))
|
|
>> (fmap getPath (nakedInit ev))
|
|
)
|
|
_ -> (getPath x)
|
|
qualifySym _ _ _ xobj = Left $ FailedToQualifySymbols xobj
|
|
|
|
-- | Determine whether or not this symbol is captured in a local environment (closures).
|
|
captureOrNot :: Env -> Env -> CaptureMode
|
|
captureOrNot foundEnv localEnv =
|
|
if envFunctionNestingLevel foundEnv < envFunctionNestingLevel localEnv
|
|
then Capture (envFunctionNestingLevel localEnv - envFunctionNestingLevel foundEnv)
|
|
else NoCapture
|
|
|
|
-- | Qualify an Arr form.
|
|
qualifyArr :: Qualifier
|
|
qualifyArr typeEnv globalEnv env (XObj (Arr array) i t) =
|
|
do
|
|
qualifiedArr <- liftM (map unQualified) (mapM (setFullyQualifiedSymbols typeEnv globalEnv env) array)
|
|
pure (Qualified (XObj (Arr qualifiedArr) i t))
|
|
qualifyArr _ _ _ xobj = Left $ FailedToQualifySymbols xobj
|
|
|
|
-- | Qualify a StaticArr form.
|
|
qualifyStaticArr :: Qualifier
|
|
qualifyStaticArr typeEnv globalEnv env (XObj (StaticArr array) i t) =
|
|
do
|
|
qualifiedArr <- liftM (map unQualified) (mapM (setFullyQualifiedSymbols typeEnv globalEnv env) array)
|
|
pure (Qualified (XObj (StaticArr qualifiedArr) i t))
|
|
qualifyStaticArr _ _ _ xobj = Left $ FailedToQualifySymbols xobj
|