Carp/src/Env.hs

673 lines
24 KiB
Haskell
Raw Normal View History

Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
{-# LANGUAGE TupleSections #-}
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
module Env
( EnvironmentError,
Environment (..),
Mode (..),
-- utils
empty,
new,
parent,
setParent,
nested,
recursive,
binders,
------------------------
-- lookups
getType,
getTypeBinder,
findType,
findTypeBinder,
searchType,
searchTypeBinder,
getValue,
getValueBinder,
findValue,
findValueBinder,
searchValue,
searchValueBinder,
-------------------------
-- Environment getters
getInnerEnv,
contextEnv,
envIsExternal,
envPublicBindingNames,
-------------------------
-- mutation
insert,
insertX,
replace,
addBinding,
deleteBinding,
addListOfBindings,
addUsePath,
-------------------------
-- finds
findPoly,
findAllByMeta,
findChildren,
findImplementations,
findAllGlobalVariables,
findModules,
allImportedEnvs,
-------------------------
-- lookups
lookupContextually,
lookupMeta,
lookupChildren,
lookupInUsed,
lookupEverywhere,
lookupBinderEverywhere,
progenitor,
replaceInPlace,
)
where
import Data.Either (fromRight, rights)
import Data.List (foldl', unfoldr)
import Data.Maybe (fromMaybe)
import qualified Map
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
import qualified Meta
import Obj
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
import qualified Set
import Types
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
--------------------------------------------------------------------------------
-- Data
data EnvironmentError
= NoEnvInNonModule
| NoReplaceInNonModule
| BindingNotFound String Env
| NoMatchingBindingFound String
| NestedTypeError String
instance Show EnvironmentError where
show NoEnvInNonModule = "Can't get an environment from a non-module."
show NoReplaceInNonModule = "Can't replace an environment in a non-module."
show (BindingNotFound name e) = "Failed to find " ++ name ++ "in the given environment: " ++ show e
show (NoMatchingBindingFound predicate) = "Couldn't find any bindings with " ++ predicate ++ "in the given environment."
show (NestedTypeError name) =
"Couldn't insert the top-level type " ++ name
++ " in a module environment."
data Mode = Types | Values
--------------------------------------------------------------------------------
-- The Environment class and implementations
-- | Class for generically handling type and value environments.
class Environment e where
inj :: Env -> e
prj :: e -> Env
update :: e -> Binder -> Either EnvironmentError Binder
modality :: e -> Mode
-- | The value environment
instance Environment Env where
inj = id
prj = id
update e (Binder meta (XObj (Mod _ et) i t)) = Right (Binder meta (XObj (Mod e et) i t))
update _ _ = Left NoReplaceInNonModule
modality _ = Values
-- | The type environment
instance Environment TypeEnv where
inj = TypeEnv
prj = getTypeEnv
update e (Binder meta (XObj (Mod ev _) i t)) = Right (Binder meta (XObj (Mod ev e) i t))
update _ _ = Left NoReplaceInNonModule
modality _ = Types
--------------------------------------------------------------------------------
-- Misc. Environment utilities
-- | Returns an unnamed empty environment with no parent.
empty :: Environment e => e
empty = inj $ Env (Map.fromList []) Nothing Nothing Set.empty ExternalEnv 0
-- | Returns a new environment with a given parent and name.
new :: Environment e => Maybe e -> Maybe String -> e
new p name =
let e' = Env (Map.fromList []) (fmap prj p) name Set.empty ExternalEnv 0
in inj e'
-- | Returns a new environment with a designated nesting level.
nested :: Environment e => Maybe e -> Maybe String -> Int -> e
nested p name lvl = inj ((prj (new p name)) {envMode = InternalEnv, envFunctionNestingLevel = lvl})
-- | Returns a new recursive environment with a designated nesting level.
recursive :: Environment e => Maybe e -> Maybe String -> Int -> e
recursive p name lvl = inj ((prj (new p name)) {envMode = RecursionEnv, envFunctionNestingLevel = lvl})
-- | Returns the binders stored in an environment.
binders :: Environment e => e -> Map.Map String Binder
binders = envBindings . prj
-- | Get the parent of an environment.
parent :: Environment e => e -> Maybe e
parent = fmap inj . envParent . prj
-- | Set the parent of an environment.
setParent :: Environment e => e -> e -> e
setParent e p = inj ((prj e) {envParent = Just (prj p)})
-- | Get an environment stored in a module binder.
nextEnv :: Mode -> Binder -> Either EnvironmentError Env
nextEnv Types (Binder _ (XObj (Mod _ et) _ _)) = Right $ prj et
nextEnv Values (Binder _ (XObj (Mod ev _) _ _)) = Right $ prj ev
nextEnv _ _ = Left NoEnvInNonModule
-- | Replace an environment stored in a module binder.
updateEnv :: Mode -> Env -> Binder -> Either EnvironmentError Binder
updateEnv Values e (Binder meta (XObj (Mod _ et) i t)) = Right (Binder meta (XObj (Mod e et) i t))
updateEnv Types e (Binder meta (XObj (Mod ev _) i t)) = Right (Binder meta (XObj (Mod ev (TypeEnv e)) i t))
updateEnv _ _ _ = Left NoEnvInNonModule
--------------------------------------------------------------------------------
-- Environment traversal
--
-- Naming conventions:
--
-- get: Direct lookup. Try to get the designated binder directly from an
-- environment, without traversing into parents or children. If not found,
-- fail.
--
-- find: Preorder lookup. Try to get the designated binder by proceeding from
-- the root environment down to its children. If not found in a child, fail.
--
-- search: pre and post order lookup: Try to get the designated binder by
-- proceeding from the root to children. If not found, try to find the binder
-- by proceeding from the root's parent, if it exists, to its children. If
-- not found, fail.
-- | Walk down an environment chain.
walk' :: Mode -> Env -> SymPath -> Either EnvironmentError Env
walk' _ e (SymPath [] _) = pure e
walk' mode' e (SymPath (p : ps) name) =
do
(_, binder) <- get e p
go (SymPath ps name) binder
where
go :: SymPath -> Binder -> Either EnvironmentError Env
go (SymPath [] _) binder = nextEnv mode' binder
go path binder =
do
env <- nextEnv Values binder
walk' mode' env path
-- | Generic *unidirectional* retrieval of binders (does not check parents).
walkAndGet :: Environment e => e -> SymPath -> (Either EnvironmentError e, Either EnvironmentError Binder)
walkAndGet e path@(SymPath _ name) =
let target = walk' (modality e) (prj e) path
binder = target >>= \t -> get t name
in (fmap inj target, fmap snd binder)
-- | Direct lookup for a binder in environment `e`.
-- The environment returned in the output will be the same as that given as input.
--
-- Returns an error if not found.
get :: Environment e => e -> String -> Either EnvironmentError (e, Binder)
get e name =
case Map.lookup name (binders e) of
Nothing -> Left $ BindingNotFound name (prj e)
Just b -> Right (e, b)
-- | Same as `get` but only returns a binder.
getBinder :: Environment e => e -> String -> Either EnvironmentError Binder
getBinder e name = fmap snd (get e name)
-- | Generic unidirectional retrieval of binders.
-- Searches the children of `e` using a given path, stopping at the terminus.
--
-- Returns an error if not found.
find' :: Environment e => e -> SymPath -> Either EnvironmentError (e, Binder)
find' e path =
case walkAndGet e path of
(Right e', Right b) -> Right (e', b)
(Left err, _) -> Left err
(_, Left err) -> Left err
-- | Same as `find` but only returns a binder.
findBinder :: Environment e => e -> SymPath -> Either EnvironmentError Binder
findBinder e path = fmap snd (find' e path)
-- | Generic *multidirectional* retrieval of binders.
-- Searches the children and parents of `e` (or the parent of a sub-environment
-- found in `e` and given by `path`).
--
-- Returns an error if not found.
search :: Environment e => e -> SymPath -> Either EnvironmentError (e, Binder)
search e path =
case walkAndGet e path of
(Right e', Right b) -> Right (e', b)
(Right e', Left err) -> (checkParent e' err)
(Left err, Left _) -> (checkParent e err) <> Left err
-- impossible case. Included to keep `walk` honest.
(Left _, Right _) -> error "impossible"
where
checkParent env err = maybe (Left err) (`search` path) (parent env)
-- | Same as `search` but only returns a binder.
searchBinder :: Environment e => e -> SymPath -> Either EnvironmentError Binder
searchBinder e path = fmap snd (search e path)
--------------------------------------------------------------------------------
-- Specialized retrievals
--
-- These functions are all equivalent to the generic retrieval functions
-- defined above but they enforce further restrictions at type level. Thus,
-- they can be used to help enforce constraints at call sites.
--
-- For example, suppose we want to search for a binder that may name a type
-- * or* module, preferring types. One could cast to enforce a type search
-- starting from the global env:
--
-- search typeEnv path
-- <> search (TypeEnv global) path
-- <> search global path
--
-- But:
--
-- searchType typeEnv path
-- searchType global path
-- <> searchValue global path
--
-- Is arguably much clearer.
--------------------------------------------------------------------------------
-- Type retrievals
-- | Get a type from a type environment.
getType :: TypeEnv -> String -> Either EnvironmentError (TypeEnv, Binder)
getType = get
-- | Get a type binder from a type environment.
getTypeBinder :: TypeEnv -> String -> Either EnvironmentError Binder
getTypeBinder = getBinder
-- | Unidirectional binder retrieval specialized to types.
--
-- Restricts the final step of a search to binders in a module's *type* environment.
findType :: Environment e => e -> SymPath -> Either EnvironmentError (TypeEnv, Binder)
fix: fix nested polymorphic types (#1294) * refactor: refactor concretize module This commit primarily refactors the concretize module, breaking out the local definitions for visit functions into top level functions that are hopefully easier to change. I've also modified some monadic code in the interest of terseness. This commit adds some additional patterns for XObj forms as well. * refactor: Only export called functions in Concretize Adds an export list to Concretize so that the module encapsulates those functions that are only used internally within the module. * refactor: better names in concretize functions Clarify the names of variables in visitor type functions. * refactor: ensure findType returns a type Adds an additional check to findType that ensures the retrieved binder is in fact a type and not another object. This is necessary for certain contexts like type concretization since modules may also be designated by symbols that refer to types. * fix: ensure nested polymorphic types are emitted This commit fixes an issue whereby nested polymorphic types would not be emitted by the compiler, even though their member functions were emitted. In order to support this, we need to update a couple of functions to take the global environment (to find nested types, which live in modules) in addition to the top level type environment. Additionally, we had to update scoring to account for nested names. fixes #1293 * test: add tests for nested polymorphic types Adds regression tests to ensure nested polymorphic types are concretized and emitted correctly.
2021-08-10 09:41:20 +03:00
findType e path = go $ find' (inj (prj e)) path
where
-- Make sure the binder is actually a type.
go :: Either EnvironmentError (TypeEnv, Binder) -> Either EnvironmentError (TypeEnv, Binder)
go (Right (t, b)) =
if isType (binderXObj b)
then Right (t, b)
else Left (BindingNotFound (show path) (prj e))
go x = x
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
findTypeBinder :: Environment e => e -> SymPath -> Either EnvironmentError Binder
findTypeBinder e path = fmap snd (findType e path)
-- | Multidirectional binder retrieval specialized to types.
--
-- Restricts the final step of a search to binders in a module's *type* environment.
searchType :: Environment e => e -> SymPath -> Either EnvironmentError (TypeEnv, Binder)
searchType e path = search (inj (prj e)) path
searchTypeBinder :: Environment e => e -> SymPath -> Either EnvironmentError Binder
searchTypeBinder e path = fmap snd (searchType e path)
--------------------------------------------------------------------------------
-- Value retrievals
-- | Get a value from a value environment.
getValue :: Env -> String -> Either EnvironmentError (Env, Binder)
getValue = get
getValueBinder :: Env -> String -> Either EnvironmentError Binder
getValueBinder = getBinder
-- | Unidirectional binder retrieval specialized to values.
findValue :: Env -> SymPath -> Either EnvironmentError (Env, Binder)
findValue = find'
findValueBinder :: Env -> SymPath -> Either EnvironmentError Binder
findValueBinder = findBinder
-- | Multidirectional binder retrieval specialized to values.
searchValue :: Env -> SymPath -> Either EnvironmentError (Env, Binder)
searchValue = search
searchValueBinder :: Env -> SymPath -> Either EnvironmentError Binder
searchValueBinder = searchBinder
--------------------------------------------------------------------------------
-- Environment mutation
--------------------------------------------------------------------------------
-- Mutation primitives
-- N.B. The following functions returns an Either for compatibility with other
-- functions in this module. It is a constant function in the co-domain of
-- Either, as they always returns Right.
-- | Add a new binding to an environment.
addBinding :: Environment e => e -> String -> Binder -> Either EnvironmentError e
addBinding e name b = pure (inj ((prj e) {envBindings = Map.insert name b (binders e)}))
-- | Replace the value of a binding in an environment, but only if it already
-- exists.
replaceBinding :: Environment e => e -> String -> Binder -> Either EnvironmentError e
replaceBinding e name b =
pure (inj ((prj e) {envBindings = Map.adjust (const b) name (binders e)}))
-- | Delete a binding in an environment.
deleteBinding :: Environment e => e -> String -> Either EnvironmentError e
deleteBinding e name = pure (inj ((prj e) {envBindings = Map.delete name (binders e)}))
--------------------------------------------------------------------------------
-- Generic environment mutation
type EnvironmentProducer e = (e -> String -> Binder -> Either EnvironmentError e)
-- | Given an environment and a complete identifier path, traverse a chain of
-- environments until the path is exhausted, if requested, mutating the
-- environments along the way:
mutate :: Environment e => (EnvironmentProducer e) -> e -> SymPath -> Binder -> Either EnvironmentError e
mutate f e path binder = go path
where
go (SymPath [] name) = f e name binder
go (SymPath (p : []) name) =
2021-12-20 17:54:49 +03:00
do
mod' <- getBinder e p
env' <- nextEnv (modality e) mod'
res <- mutate f (inj env') (SymPath [] name) binder
new' <- updateEnv (modality e) (prj res) mod'
addBinding e p new'
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
go (SymPath (p : ps) name) =
2021-12-20 17:54:49 +03:00
do
mod' <- getBinder e p
old <- nextEnv Values mod'
result <- mutate f (inj old) (SymPath ps name) binder
new' <- updateEnv Values (prj result) mod'
addBinding e p new'
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
-- | Insert a binding into an environment at the given path.
insert :: Environment e => e -> SymPath -> Binder -> Either EnvironmentError e
insert = mutate addBinding
-- | Insert an XObj into an environment at the specified path.
-- This function does not perform insertions into parents.
insertX :: Environment e => e -> SymPath -> XObj -> Either EnvironmentError e
insertX e path x = insert e path (toBinder x)
-- | Replace a binding at the given path in an environment.
replace :: Environment e => e -> SymPath -> Binder -> Either EnvironmentError e
replace = mutate replaceBinding
-- | Replaces a binding "in-place" in an environment chain.
--
-- This function *only* considers members of an environment chain, that is,
-- it's limited to the given input environment and all of its ancestors (it's
-- parent and the parent of its parent all the way up).
--
-- It does not look in any "external" environments (used environments or
-- "children" (environments stored in module bindings)).
replaceInPlace :: Environment e => e -> String -> Binder -> Either EnvironmentError e
replaceInPlace e name b =
(get e name >>= \_ -> addBinding e name b)
<> case parent e of
Just p -> replaceInPlace p name b >>= \p' -> pure (inj ((prj e) {envParent = Just (prj p')}))
Nothing -> Left (BindingNotFound name (prj e))
-- | Add a list of bindings to an environment.
addListOfBindings :: Environment e => e -> [(String, Binder)] -> e
addListOfBindings e bindings =
foldl' (\e' (n, b) -> fromRight e (addBinding e' n b)) e bindings
-- | Add a module path to an environment's list of used modules.
addUsePath :: Environment e => e -> SymPath -> e
addUsePath e path = inj ((prj e) {envUseModules = Set.insert path (envUseModules (prj e))})
--------------------------------------------------------------------------------
-- Additional binding lookup functions
--
-- find* functions perform lookup in a single environment, without recursion.
-- lookup* functions perform lookups in an environment chain, with recursion.
-- | Get the metadata associated with the binder at the specified path in an environment.
lookupMeta :: Environment e => e -> SymPath -> Either EnvironmentError MetaData
lookupMeta e path = searchBinder e path >>= pure . Meta.fromBinder
-- | Find all binders in an environment that have a specified meta key.
findAllByMeta :: Environment e => e -> String -> Either EnvironmentError [Binder]
findAllByMeta e metaKey =
let candidates = Map.elems (Map.filter (Meta.binderMember metaKey) (binders e))
in case candidates of
[] -> Left (NoMatchingBindingFound ("metadata " ++ metaKey))
_ -> Right $ candidates
-- | Find all modules directly stored in environment `e`.
findModules :: Environment e => e -> [XObj]
findModules e =
map binderXObj (filter modsOnly (Map.elems (binders e)))
where
modsOnly :: Binder -> Bool
modsOnly binder =
case binderXObj binder of
XObj (Mod _ _) _ _ -> True
_ -> False
-- | It's more efficient to specialize this function as it can take advantage
-- of laziness; once we found the candidate function for a polymorphic
-- function, there's no need to consume the rest of the environment.
findPoly :: Environment e => e -> String -> Ty -> Either EnvironmentError (e, Binder)
findPoly env name ty =
case getBinder env name of
Right b ->
if unify b
then Right (env, b)
else (foldl' go (Left (BindingNotFound name (prj env))) (findChildren env))
Left _ -> foldl' go (Left (BindingNotFound name (prj env))) (findChildren env)
where
go x e = x <> (findPoly e name ty)
unify = areUnifiable ty . fromMaybe Universe . xobjTy . binderXObj
-- | Find all environments that are *direct* children of an environment (one
-- level down).
--
-- The modality of the children is determined by the modality of the root.
--
-- N.B. Don't use find here. We access binders directly, so there's no need to
-- perform additional O(n) lookup calls.
findChildren :: Environment e => e -> [e]
findChildren e =
foldl' getEnv [] (binders e)
where
getEnv acc binder =
case (nextEnv (modality e) binder) of
Left _ -> acc
Right e' -> ((inj e') : acc)
-- | Find all the environments contained in the modules initial environment,
-- plus any module environments contained in *those* modules.
lookupChildren :: Environment e => e -> [e]
lookupChildren e =
foldl' go [] (findChildren e)
where
go acc e' = case findChildren e' of
[] -> (e' : acc)
xs -> (foldl' go [] xs ++ acc)
-- | Find all the environments designated by the use paths in an environment.
findImportedEnvs :: Environment e => e -> [e]
findImportedEnvs e =
let eMode = modality e
usePaths = Set.toList (envUseModules (prj e))
getter path =
walk' eMode (prj e) path
>>= \e' ->
get e' (getName' path)
>>= nextEnv eMode . snd
>>= pure . inj
used = fmap getter usePaths
in (rights used)
where
getName' (SymPath _ name) = name
-- | Given an environment, get its topmost parent up the environment chain.
--
-- For nearly all environments, this should be the global environment.
progenitor :: Environment e => e -> e
progenitor e = fromMaybe e (parent e >>= \p -> pure (progenitor p))
-- | Find all possible environments imported at some point *upwards* from e in a chain of environments.
allImportedEnvs :: Environment e => e -> Env -> [e]
allImportedEnvs e global =
let env = prj e
paths = (Set.toList (foldl' og (envUseModules env) (unfoldr go env)))
in (rights (map get' paths))
where
go e' = parent e' >>= \p -> pure (p, p)
og acc e' = (envUseModules e') <> acc
get' path =
findBinder global path
>>= nextEnv (modality e)
>>= pure . inj
-- | Find all binders the implement a given interface, designated by its path.
findImplementations :: Environment e => e -> SymPath -> Either EnvironmentError [Binder]
findImplementations e interface =
( (findAllByMeta e "implements")
>>= \is -> (pure (filter (isImpl . Meta.fromBinder) is))
)
<> Left (NoMatchingBindingFound ("implementation meta for " ++ show interface))
where
isImpl :: MetaData -> Bool
isImpl meta =
case Meta.get "implements" meta of
Just (XObj (Lst interfaces) _ _) -> interface `elem` map getPath interfaces
_ -> False
-- | Searches for binders exhaustively in the given environment, a list of
-- child environments it contains derived using a function and its parent, if
-- it has one.
--
-- The parent environment, when it exists, is also searched exhaustively
-- (derived children of the parent are searched, as well as the parent of the
-- parent, should it exist).
lookupExhuastive :: Environment e => (e -> [e]) -> e -> String -> [(e, Binder)]
lookupExhuastive f e name =
let envs = [e] ++ (f e)
in (go (parent e) envs)
where
go _ [] = []
go Nothing xs = foldl' accum [] xs
go (Just p) xs = go (parent p) (xs ++ [p] ++ (f p))
accum acc e' = case getBinder e' name of
Right b -> ((e', b) : acc)
_ -> acc
lookupBinderExhuastive :: Environment e => (e -> [e]) -> e -> String -> [Binder]
lookupBinderExhuastive f e name = fmap snd (lookupExhuastive f e name)
lookupEverywhere :: Environment e => e -> String -> [(e, Binder)]
lookupEverywhere = lookupExhuastive lookupChildren
lookupInImports :: Environment e => e -> String -> [(e, Binder)]
lookupInImports = lookupExhuastive findImportedEnvs
lookupInUsed :: Environment e => e -> Env -> SymPath -> [(e, Binder)]
lookupInUsed e global spath =
foldl' go [] (allImportedEnvs e global)
where
go :: Environment e => [(e, Binder)] -> e -> [(e, Binder)]
go acc e' = case (search e' spath) of
Right (e'', b) -> ((e'', b) : acc)
_ -> acc
-- | Lookup a binder in *all* possible environments in the chain of an initial
-- environment (parents and children, including Use modules).
lookupBinderEverywhere :: Environment e => e -> String -> [Binder]
lookupBinderEverywhere = lookupBinderExhuastive lookupChildren
lookupContextually :: Environment e => e -> SymPath -> Either EnvironmentError [(e, Binder)]
lookupContextually e (SymPath [] name) =
case lookupInImports e name of
[] -> Left (BindingNotFound name (prj e))
xs -> Right xs
lookupContextually e path@(SymPath (p : ps) name) =
lookupDirectly <> lookupInUsedAndParent
where
lookupDirectly =
(getBinder e p)
>>= nextEnv (modality e)
>>= \e' ->
search (inj e') (SymPath ps name)
>>= pure . (: [])
lookupInUsedAndParent = case rights (fmap ((flip search) path) (findImportedEnvs e)) of
[] -> Left (BindingNotFound name (prj e))
xs ->
case parent e of
Nothing -> Right xs
Just e' -> (Env.search e' path >>= \found -> Right $ xs ++ [found]) <> Right xs
--------------------------------------------------------------------------------
-- Environment retrieval functions
-- | Get the environment at a given path that corresponds to the type of an
-- initial environment.
--
-- Returns the initial environment when given an empty path.
getInnerEnv :: Environment e => e -> [String] -> Either EnvironmentError e
getInnerEnv e [] = Right e
getInnerEnv e (p : ps) =
(getBinder e p)
>>= nextEnv (modality e)
>>= \moduleEnv -> getInnerEnv (inj moduleEnv) ps
-- | Get a context's internal environment if it exists, otherwise get the
-- innermost module's value environment based on the context path.
contextEnv :: Environment e => Context -> e
contextEnv Context {contextInternalEnv = Just e} = inj e
contextEnv Context {contextGlobalEnv = e, contextPath = p} = inj (fromRight e (getInnerEnv e p))
--------------------------------------------------------------------------------
-- Utility functions
-- | Checks if an environment is "external", meaning it's either the global
-- scope or a module scope.
envIsExternal :: Environment e => e -> Bool
envIsExternal e =
case envMode (prj e) of
ExternalEnv -> True
InternalEnv -> False
RecursionEnv -> True
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
--------------------------------------------------------------------------------
-- Binding Utilities
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
-- | Get a list of all the names of bindings in an environment that aren't
-- hidden or private.
envPublicBindingNames :: Environment e => e -> [String]
envPublicBindingNames e = concatMap select (Map.toList (binders e))
2021-02-01 21:20:44 +03:00
where
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
select :: (String, Binder) -> [String]
select (name, binder) =
case (nextEnv (modality e) binder) of
Left _ ->
if metaIsTrue (binderMeta binder) "private" || metaIsTrue (binderMeta binder) "hidden"
then []
else [name]
Right e' -> map (\n -> name ++ "." ++ n) (envPublicBindingNames e')
2021-02-01 21:20:44 +03:00
-- | Recursively look through all environments for (def ...) forms.
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
--
-- N.B. Don't use find here. We access binders directly, so there's no need to
-- perform additional O(n) lookup calls.
findAllGlobalVariables :: Env -> [Binder]
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
findAllGlobalVariables e =
foldl' finder [] (Map.elems (binders e))
where
Refactor: clean up Env module, store type environments in modules (#1207) * refactor: major environment mgmt refactor This big refactor primarily changes two things in terms of behavior: 1. Stores a SymPath on concretely named (non-generic) struct types; before we stored a string. 2. The SymPath mentioned in (1.) designates where the struct is stored in the current environment chain. Modules now carry a local type environment in addition to their local value environments. Any types defined in the module are added to this environment rather than the global type environment. To resolve a type such as `Foo.Bar` we now do the following: - Search the *global value environment* for the Foo module. - Get the type environment stored in the Foo module. - Search for Bar in the Foo module's type environment. Additionally, this commit eliminates the Lookup module entirely and refactors the Env module to handle all aspects of environment management in hopefully a more reusable fashion. I also took the opportunity to refactor primitiveDeftype in Primitives and qualifySym in Qualify, both of which were hefty functions that I found difficult to grok and needed refactoring anyway as a result of lookup changes (lookups now return an Either instead of a Maybe). Subsequent commits will clean up and clarify this work further. This does include one minor regression. Namely, an implementation of `hash` in core/Color that was maximally generic now needs type casting. * refactor: clean up recent Env changes This commit removes some redundant functions, unifies some logic, and renames some routines across the Env module in efforts to make it cleaner. Call sites have been updated accordingly. * chore: format code with ormolu * fix: update lookup tests Changes references to renamed functions in the Env module. * refactor: style + additional improvements from eriksvedang@ - Rename arrayTy -> arrayTyA in ArrayTemplates.hs to disambiguate. - Add maybeId util function. - Remove commented code. - Refactor a few functions for readability. * fix: fix type inference regression Recent commits introduced one minor regression whereby an instance of type inference in core/Color.carp no longer worked and required explicit type annotation. The problem ultimately had to do with qualification: - Prior to the recent changes, type inference worked because the call in question was qualified to Color.Id.get-tag, fixing the type. - Failing to copy over a local envs Use modules to function envs resulted in finding more than just Color.Id.get-tag for this instance. We now copy use modules over to function envs generated during qualification to ensure we resolve to Use'd definitions before more general cases. Similarly, I made a small change to primitiveUse to support contextual use calls (e.g. the `(use Id)` in Color.carp, which really means `(use Color.Id)`) * chore: Update some clarificatory comments * chore: fix inline comment
2021-05-19 20:20:48 +03:00
finder :: [Binder] -> Binder -> [Binder]
finder acc (Binder _ (XObj (Mod ev _) _ _)) = acc ++ (findAllGlobalVariables (inj ev))
finder acc def@(Binder _ (XObj (Lst (XObj Def _ _ : _)) _ _)) = (def : acc)
finder acc _ = acc