@@ -13,14 +13,16 @@
13-----------------------------------------------------------------------------
13-----------------------------------------------------------------------------
15module Language.PureScript.Sugar.Names (
15module Language.PureScript.Sugar.Names (
16− rename
16+ desugarImports
19import Data.Maybe (fromMaybe)
19import Data.Maybe (fromMaybe)
20−import Data.Generics (extM, mkM, everywhereM)
21import Data.List (intersect)
20import Data.List (intersect)
22+import Data.Generics (extM, mkM, everywhereM)
23+import Data.Generics.Extras (mkS, extS, everywhereWithContextM')
23−import Control.Applicative ((<$>), (<*>))
25+import Control.Applicative (Applicative(..), (<$>), (<*>))
24import Control.Monad (forM_, unless, foldM, liftM)
26import Control.Monad (forM_, unless, foldM, liftM)
26import qualified Data.Map as M
28import qualified Data.Map as M
@@ -38,15 +40,15 @@ data ExportEnvironment = ExportEnvironment
39 -- The types exported from each module
41 -- The types exported from each module
41− { exportedTypes :: M.Map ModuleName (S.Set ProperName)
43+ { exportedTypes :: M.Map ModuleName (S.Set (ProperName, [ProperName]))
43− -- The data constructors exported from each module, grouped by type constructor
45− , exportedDataConstructors :: M.Map ModuleName (S.Set (ProperName, [ProperName]))
47 -- The classes exported from each module
45 -- The classes exported from each module
49 , exportedTypeClasses :: M.Map ModuleName (S.Set ProperName)
47 , exportedTypeClasses :: M.Map ModuleName (S.Set ProperName)
49+ -- The values exported from each module
50+ , exportedValues :: M.Map ModuleName (S.Set Ident)
50 } deriving (Show)
52 } deriving (Show)
@@ -65,31 +67,35 @@ data ImportEnvironment = ImportEnvironment
65 -- Local names for classes within a module mapped to to their qualified names
67 -- Local names for classes within a module mapped to to their qualified names
67 , importedTypeClasses :: M.Map ProperName (Qualified ProperName)
69 , importedTypeClasses :: M.Map ProperName (Qualified ProperName)
71+ -- Local names for values within a module mapped to to their qualified names
73+ , importedValues :: M.Map Ident (Qualified Ident)
68 } deriving (Show)
74 } deriving (Show)
71-- Adds a type belonging to a module to the export environment.
77-- Adds a type belonging to a module to the export environment.
73−addType :: ExportEnvironment -> ModuleName -> ProperName -> Either String ExportEnvironment
79+addType :: ExportEnvironment -> ModuleName -> ProperName -> [ProperName] -> Either String ExportEnvironment
74−addType env mn name = do
80+addType env mn name dctors = do
75− types <- addExport (exportedTypes env) mn name
81+ types <- addExport (exportedTypes env) mn (name, dctors)
76− return $ env { exportedTypes = types }
82+ return $ env { exportedTypes = types }
79−-- Adds a group of data constructors with their associated type constructor the export environment.
85+-- Adds a class to the export environment.
81−addDataConstructors :: ExportEnvironment -> ModuleName -> ProperName -> [ProperName] -> Either String ExportEnvironment
87+addTypeClass :: ExportEnvironment -> ModuleName -> ProperName -> Either String ExportEnvironment
82−addDataConstructors env mn tcon dcons = do
88+addTypeClass env mn name = do
83− dataConstructors <- addExport (exportedDataConstructors env) mn (tcon, dcons)
89+ classes <- addExport (exportedTypeClasses env) mn name
84− return $ env { exportedDataConstructors = dataConstructors }
90+ return $ env { exportedTypeClasses = classes }
87-- Adds a class to the export environment.
93-- Adds a class to the export environment.
89−addTypeclass :: ExportEnvironment -> ModuleName -> ProperName -> Either String ExportEnvironment
95+addValue :: ExportEnvironment -> ModuleName -> Ident -> Either String ExportEnvironment
90−addTypeclass env mn name = do
96+addValue env mn name = do
91− classes <- addExport (exportedTypeClasses env) mn name
97+ values <- addExport (exportedValues env) mn name
92− return $ env { exportedTypeClasses = classes }
98+ return $ env { exportedValues = values }
95-- Adds an export to a map of exports of that type.
101-- Adds an export to a map of exports of that type.
@@ -104,8 +110,8 @@ addExport exports mn name = case M.lookup mn exports of
105-- Replaces all local names with qualified names within a set of modules.
111-- Replaces all local names with qualified names within a set of modules.
107−rename :: [Module] -> Either String [Module]
113+desugarImports :: [Module] -> Either String [Module]
108−rename modules = do
114+desugarImports modules = do
109 exports <- findExports modules
115 exports <- findExports modules
110 mapM (renameInModule' exports) modules
116 mapM (renameInModule' exports) modules
@@ -120,20 +126,27 @@ renameInModule :: ImportEnvironment -> Module -> Either String Module
120renameInModule imports (Module mn decls) =
126renameInModule imports (Module mn decls) =
121 Module mn <$> mapM updateDecl decls >>= everywhereM (mkM updateType `extM` updateValue `extM` updateBinder)
127 Module mn <$> mapM updateDecl decls >>= everywhereM (mkM updateType `extM` updateValue `extM` updateBinder)
123− updateDecl (TypeInstanceDeclaration cs (Qualified Nothing cn) ts ds) = do
129+ updateDecl (TypeInstanceDeclaration cs (Qualified Nothing cn) ts ds) =
124− cn' <- updateClassName cn
130+ TypeInstanceDeclaration <$> updateConstraints cs <*> updateClassName cn <*> pure ts <*> pure ds
125− cs' <- updateConstraints cs
131+ updateDecl (ValueDeclaration name bs grd val) =
126− return $ TypeInstanceDeclaration cs' cn' ts ds
132+ ValueDeclaration name <$> updateVars bs <*> updateVars grd <*> updateVars val
134+ updateVars :: (Data d) => d -> Either String d
135+ updateVars = everywhereWithContextM' [] (mkS bindFunctionArgs `extS` bindBinders)
137+ bindFunctionArgs bound (Abs (Left arg) val) = return (arg : bound, Abs (Left arg) val)
138+ bindFunctionArgs bound (Var (Qualified Nothing ident)) | ident `notElem` bound = (,) bound <$> (Var <$> updateValueName ident)
139+ bindFunctionArgs bound other = return (bound, other)
140+ bindBinders :: [Ident] -> ([Binder], Maybe Guard, Value) -> Either String ([Ident], ([Binder], Maybe Guard, Value))
141+ bindBinders bound (bs, grd, val) = return (binderNames bs ++ bound, (bs, grd, val))
127 updateDecl d = return d
142 updateDecl d = return d
128 updateValue (Constructor (Qualified Nothing nm)) = liftM Constructor $ updateDataConstructorName nm
143 updateValue (Constructor (Qualified Nothing nm)) = liftM Constructor $ updateDataConstructorName nm
129 updateValue v = return v
144 updateValue v = return v
130 updateBinder (ConstructorBinder (Qualified Nothing nm) b) = liftM (`ConstructorBinder` b) $ updateDataConstructorName nm
145 updateBinder (ConstructorBinder (Qualified Nothing nm) b) = liftM (`ConstructorBinder` b) $ updateDataConstructorName nm
131 updateBinder v = return v
146 updateBinder v = return v
132 updateType (TypeConstructor (Qualified Nothing nm)) = liftM TypeConstructor $ updateTypeName nm
147 updateType (TypeConstructor (Qualified Nothing nm)) = liftM TypeConstructor $ updateTypeName nm
133− updateType (SaturatedTypeSynonym (Qualified Nothing nm) tys) = do
148+ updateType (SaturatedTypeSynonym (Qualified Nothing nm) tys) =
134− nm' <- updateTypeName nm
135− tys' <- mapM updateType tys
149+ SaturatedTypeSynonym <$> updateTypeName nm <*> mapM updateType tys
136− return $ SaturatedTypeSynonym nm' tys'
137 updateType (ConstrainedType cs t) = liftM (`ConstrainedType` t) $ updateConstraints cs
150 updateType (ConstrainedType cs t) = liftM (`ConstrainedType` t) $ updateConstraints cs
138 updateType t = return t
151 updateType t = return t
139 updateConstraints = mapM updateConstraint
152 updateConstraints = mapM updateConstraint
@@ -142,7 +155,8 @@ renameInModule imports (Module mn decls) =
142 return (nm', ts)
155 return (nm', ts)
143 updateConstraint other = return other
156 updateConstraint other = return other
144 updateTypeName = update "type" importedTypes
157 updateTypeName = update "type" importedTypes
145− updateClassName = update "typeclass" importedTypeClasses
158+ updateClassName = update "type class" importedTypeClasses
159+ updateValueName = update "value" importedValues
146 updateDataConstructorName = update "data constructor" importedDataConstructors
160 updateDataConstructorName = update "data constructor" importedDataConstructors
147 update t get nm = maybe (Left $ "Unknown " ++ t ++ " '" ++ show nm ++ "' in module '" ++ show mn ++ "'") return $ M.lookup nm (get imports)
161 update t get nm = maybe (Left $ "Unknown " ++ t ++ " '" ++ show nm ++ "' in module '" ++ show mn ++ "'") return $ M.lookup nm (get imports)
@@ -153,12 +167,14 @@ findExports :: [Module] -> Either String ExportEnvironment
153findExports = foldM addModule (ExportEnvironment M.empty M.empty M.empty)
167findExports = foldM addModule (ExportEnvironment M.empty M.empty M.empty)
155 addModule env (Module mn ds) = foldM (addDecl mn) env ds
169 addModule env (Module mn ds) = foldM (addDecl mn) env ds
156− addDecl mn env (TypeClassDeclaration tcn _ _) = addTypeclass env mn tcn
170+ addDecl mn env (TypeClassDeclaration tcn _ ds) = do
157− addDecl mn env (DataDeclaration tn _ dcs) = do
171+ env' <- addTypeClass env mn tcn
158− env' <- addDataConstructors env mn tn (map fst dcs)
172+ foldM (\env'' (TypeDeclaration name _) -> addValue env'' mn name) env' ds
159− addType env' mn tn
173+ addDecl mn env (DataDeclaration tn _ dcs) = addType env mn tn (map fst dcs)
160− addDecl mn env (TypeSynonymDeclaration tn _ _) = addType env mn tn
174+ addDecl mn env (TypeSynonymDeclaration tn _ _) = addType env mn tn []
161− addDecl mn env (ExternDataDeclaration tn _) = addType env mn tn
175+ addDecl mn env (ExternDataDeclaration tn _) = addType env mn tn []
176+ addDecl mn env (ValueDeclaration name _ _ _) = addValue env mn name
177+ addDecl mn env (ExternDeclaration _ name _ _) = addValue env mn name
162 addDecl _ env _ = return env
178 addDecl _ env _ = return env
@@ -180,59 +196,53 @@ findImports = foldl findImports' M.empty
180-- Constructs a local environment for a module.
196-- Constructs a local environment for a module.
182resolveImports :: ExportEnvironment -> Module -> Either String ImportEnvironment
198resolveImports :: ExportEnvironment -> Module -> Either String ImportEnvironment
183−resolveImports env (Module currentModule decls) = ImportEnvironment
199+resolveImports env (Module currentModule decls) =
184− <$> resolve (exportedTypes env) (resolveDefs typeImports)
200+ foldM resolveImport (ImportEnvironment M.empty M.empty M.empty M.empty) (M.toList scope)
185− <*> resolve (exportedDataConstructors env) resolveDcons
186− <*> resolve (exportedTypeClasses env) (resolveDefs (const []))
188 -- A Map from module name to imports from that module, where Nothing indicates everything is to be imported
202 -- A Map from module name to imports from that module, where Nothing indicates everything is to be imported
189 scope :: M.Map ModuleName (Maybe ExplicitImports)
203 scope :: M.Map ModuleName (Maybe ExplicitImports)
190 scope = M.insert currentModule Nothing (findImports decls)
204 scope = M.insert currentModule Nothing (findImports decls)
192− -- Resolve all exported names in a set by applying a type-specific resolver function
206+ -- Add data to the ImportEnvironment
193− resolve :: M.Map ModuleName (S.Set id) ->
207+ resolveImport :: ImportEnvironment -> (ModuleName, Maybe ExplicitImports) -> Either String ImportEnvironment
194− (M.Map ProperName (Qualified ProperName) -> ModuleName -> S.Set id -> Maybe ExplicitImports -> Either String (M.Map ProperName (Qualified ProperName))) ->
208+ resolveImport imp (mn, Nothing) = importAll imp mn env
195− Either String (M.Map ProperName (Qualified ProperName))
209+ resolveImport imp (mn, Just expl) = foldM (importExplicit mn) imp expl
196− resolve m f = foldM (\m' (mn, maybeExpl) -> f m' mn (fromMaybe S.empty $ mn `M.lookup` m) maybeExpl) M.empty (M.toList scope)
210+
197−
211+ -- Import something explicitly
198− -- Resolve a single name by adding it to the Map with a specified ModuleName, checking first
212+ importExplicit :: ModuleName -> ImportEnvironment -> ImportType -> Either String ImportEnvironment
199− -- that the name does not currently exist in scope.
213+ importExplicit mn imp (NameImport name) = do
200− resolveDef :: (Ord id, Show id) => ModuleName ->
214+ values' <- updateImports mn (importedValues imp) name
201− M.Map id (Qualified id) ->
215+ return $ imp { importedValues = values' }
202− id ->
216+ importExplicit mn imp (TypeImport name dctors) = do
217+ types' <- updateImports mn (importedTypes imp) name
218+ dctors' <- foldM (updateImports mn) (importedDataConstructors imp) (fromMaybe (allExportedDataConstructors env mn name) dctors)
219+ return $ imp { importedTypes = types', importedDataConstructors = dctors' }
220+ importExplicit mn imp (TypeClassImport name) = do
221+ typeClasses' <- updateImports mn (importedTypeClasses imp) name
222+ return $ imp { importedTypeClasses = typeClasses' }
224+ -- Import everything from a module
225+ importAll :: ImportEnvironment -> ModuleName -> ExportEnvironment -> Either String ImportEnvironment
226+ importAll imp mn env = do
227+ imp' <- foldM (\m (name, dctors) -> importExplicit mn m (TypeImport name (Just dctors))) imp
228+ (S.toList . fromMaybe S.empty $ mn `M.lookup` exportedTypes env)
229+ imp'' <- foldM (\m name -> importExplicit mn m (NameImport name)) imp'
230+ (S.toList . fromMaybe S.empty $ mn `M.lookup` exportedValues env)
231+ foldM (\m name -> importExplicit mn m (TypeClassImport name)) imp''
232+ (S.toList . fromMaybe S.empty $ mn `M.lookup` exportedTypeClasses env)
234+ -- Find all exported data constructors for a given type
235+ allExportedDataConstructors :: ExportEnvironment -> ModuleName -> ProperName -> [ProperName]
236+ allExportedDataConstructors env mn name = fromMaybe (error $ "Unable to find exported data constructors for type " ++ show name ++ " in module " ++ show mn) $ do
237+ s <- mn `M.lookup` exportedTypes env
238+ name `lookup` S.toList s
240+ -- Add something to the ImportEnvironment if it does not already exist there
203− Either String (M.Map id (Qualified id))
241+ updateImports :: (Ord id, Show id) => ModuleName -> M.Map id (Qualified id) -> id -> Either String (M.Map id (Qualified id))
204− resolveDef mn result name = case M.lookup name result of
242+ updateImports mn m name = case M.lookup name m of
205− Nothing -> return $ M.insert name (Qualified (Just mn) name) result
243+ Nothing -> return $ M.insert name (Qualified (Just mn) name) m
206− Just x@(Qualified (Just mn') _) -> Left $ "Module '" ++ show currentModule ++
244+ Just x@(Qualified (Just mn') _) -> Left $ "Module '" ++ show currentModule ++
207− if mn' == currentModule || mn == currentModule
245+ if mn' == currentModule || mn == currentModule
208− then "' defines '" ++ show name ++ "' which conflicts with imported definition '" ++ show (Qualified (Just mn) name) ++ "'"
246+ then "' defines '" ++ show name ++ "' which conflicts with imported definition '" ++ show (Qualified (Just mn) name) ++ "'"
209− else "' has conflicting imports for '" ++ show name ++ "': '" ++ show x ++ "', '" ++ show (Qualified (Just mn) name) ++ "'"
247+ else "' has conflicting imports for '" ++ show name ++ "': '" ++ show x ++ "', '" ++ show (Qualified (Just mn) name) ++ "'"
211− -- Resolve a set of ProperName exports for a specific imported set of names
212− -- This function is used to resolve both types and type classes, hence the filter function as
213− -- its first argument
214− resolveDefs :: (ExplicitImports -> [ProperName]) ->
215− M.Map ProperName (Qualified ProperName) ->
218− Maybe ExplicitImports ->
219− Either String (M.Map ProperName (Qualified ProperName))
220− resolveDefs filt result mn names maybeExpl = do
221− names' <- case maybeExpl of
223− forM_ (filt expl) $ \name ->
224− unless (name `S.member` names) $ Left $ show name ++ " is explictly imported but is not defined in module " ++ show mn
225− return $ S.toList names `intersect` filt expl
226− Nothing -> return $ S.toList names
227− foldM (resolveDef mn) result names'
229− -- Resolve a set of data constructors keyed by their type constructor
230− resolveDcons :: M.Map ProperName (Qualified ProperName) ->
232− S.Set (ProperName, [ProperName]) ->
233− Maybe ExplicitImports ->
234− Either String (M.Map ProperName (Qualified ProperName))
235− resolveDcons result mn tcons maybeExpl = foldM (foldM $ resolveDef mn) result $ map snd $
237− Just expl -> filter ((`elem` typeImports expl) . fst) (S.toList tcons)
238− Nothing -> S.toList tcons