@@ -13,14 +13,16 @@
1313-----------------------------------------------------------------------------
1414
1515module Language.PureScript.Sugar.Names (
16− rename
16+ desugarImports
1717) where
1818
1919import Data.Maybe (fromMaybe)
20−import Data.Generics (extM, mkM, everywhereM)
2120import Data.List (intersect)
21+import Data.Data
22+import Data.Generics (extM, mkM, everywhereM)
23+import Data.Generics.Extras (mkS, extS, everywhereWithContextM')
2224
23−import Control.Applicative ((<$>), (<*>))
25+import Control.Applicative (Applicative(..), (<$>), (<*>))
2426import Control.Monad (forM_, unless, foldM, liftM)
2527
2628import qualified Data.Map as M
@@ -38,15 +40,15 @@ data ExportEnvironment = ExportEnvironment
3840 -- |
3941 -- The types exported from each module
4042 --
41− { exportedTypes :: M.Map ModuleName (S.Set ProperName)
42− -- |
43− -- The data constructors exported from each module, grouped by type constructor
44− --
45− , exportedDataConstructors :: M.Map ModuleName (S.Set (ProperName, [ProperName]))
43+ { exportedTypes :: M.Map ModuleName (S.Set (ProperName, [ProperName]))
4644 -- |
4745 -- The classes exported from each module
4846 --
4947 , exportedTypeClasses :: M.Map ModuleName (S.Set ProperName)
48+ -- |
49+ -- The values exported from each module
50+ , exportedValues :: M.Map ModuleName (S.Set Ident)
51+ --
5052 } deriving (Show)
5153
5254-- |
@@ -65,31 +67,35 @@ data ImportEnvironment = ImportEnvironment
6567 -- Local names for classes within a module mapped to to their qualified names
6668 --
6769 , importedTypeClasses :: M.Map ProperName (Qualified ProperName)
70+ -- |
71+ -- Local names for values within a module mapped to to their qualified names
72+ --
73+ , importedValues :: M.Map Ident (Qualified Ident)
6874 } deriving (Show)
6975
7076-- |
7177-- Adds a type belonging to a module to the export environment.
7278--
73−addType :: ExportEnvironment -> ModuleName -> ProperName -> Either String ExportEnvironment
74−addType env mn name = do
75− types <- addExport (exportedTypes env) mn name
76− return $ env { exportedTypes = types }
79+addType :: ExportEnvironment -> ModuleName -> ProperName -> [ProperName] -> Either String ExportEnvironment
80+addType env mn name dctors = do
81+ types <- addExport (exportedTypes env) mn (name, dctors)
82+ return $ env { exportedTypes = types }
7783
7884-- |
79−-- Adds a group of data constructors with their associated type constructor the export environment.
85+-- Adds a class to the export environment.
8086--
81−addDataConstructors :: ExportEnvironment -> ModuleName -> ProperName -> [ProperName] -> Either String ExportEnvironment
82−addDataConstructors env mn tcon dcons = do
83− dataConstructors <- addExport (exportedDataConstructors env) mn (tcon, dcons)
84− return $ env { exportedDataConstructors = dataConstructors }
87+addTypeClass :: ExportEnvironment -> ModuleName -> ProperName -> Either String ExportEnvironment
88+addTypeClass env mn name = do
89+ classes <- addExport (exportedTypeClasses env) mn name
90+ return $ env { exportedTypeClasses = classes }
8591
8692-- |
8793-- Adds a class to the export environment.
8894--
89−addTypeclass :: ExportEnvironment -> ModuleName -> ProperName -> Either String ExportEnvironment
90−addTypeclass env mn name = do
91− classes <- addExport (exportedTypeClasses env) mn name
92− return $ env { exportedTypeClasses = classes }
95+addValue :: ExportEnvironment -> ModuleName -> Ident -> Either String ExportEnvironment
96+addValue env mn name = do
97+ values <- addExport (exportedValues env) mn name
98+ return $ env { exportedValues = values }
9399
94100-- |
95101-- 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
104110-- |
105111-- Replaces all local names with qualified names within a set of modules.
106112--
107−rename :: [Module] -> Either String [Module]
108−rename modules = do
113+desugarImports :: [Module] -> Either String [Module]
114+desugarImports modules = do
109115 exports <- findExports modules
110116 mapM (renameInModule' exports) modules
111117 where
@@ -120,20 +126,27 @@ renameInModule :: ImportEnvironment -> Module -> Either String Module
120126renameInModule imports (Module mn decls) =
121127 Module mn <$> mapM updateDecl decls >>= everywhereM (mkM updateType `extM` updateValue `extM` updateBinder)
122128 where
123− updateDecl (TypeInstanceDeclaration cs (Qualified Nothing cn) ts ds) = do
124− cn' <- updateClassName cn
125− cs' <- updateConstraints cs
126− return $ TypeInstanceDeclaration cs' cn' ts ds
129+ updateDecl (TypeInstanceDeclaration cs (Qualified Nothing cn) ts ds) =
130+ TypeInstanceDeclaration <$> updateConstraints cs <*> updateClassName cn <*> pure ts <*> pure ds
131+ updateDecl (ValueDeclaration name bs grd val) =
132+ ValueDeclaration name <$> updateVars bs <*> updateVars grd <*> updateVars val
133+ where
134+ updateVars :: (Data d) => d -> Either String d
135+ updateVars = everywhereWithContextM' [] (mkS bindFunctionArgs `extS` bindBinders)
136+ where
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))
127142 updateDecl d = return d
128143 updateValue (Constructor (Qualified Nothing nm)) = liftM Constructor $ updateDataConstructorName nm
129144 updateValue v = return v
130145 updateBinder (ConstructorBinder (Qualified Nothing nm) b) = liftM (`ConstructorBinder` b) $ updateDataConstructorName nm
131146 updateBinder v = return v
132147 updateType (TypeConstructor (Qualified Nothing nm)) = liftM TypeConstructor $ updateTypeName nm
133− updateType (SaturatedTypeSynonym (Qualified Nothing nm) tys) = do
134− nm' <- updateTypeName nm
135− tys' <- mapM updateType tys
136− return $ SaturatedTypeSynonym nm' tys'
148+ updateType (SaturatedTypeSynonym (Qualified Nothing nm) tys) =
149+ SaturatedTypeSynonym <$> updateTypeName nm <*> mapM updateType tys
137150 updateType (ConstrainedType cs t) = liftM (`ConstrainedType` t) $ updateConstraints cs
138151 updateType t = return t
139152 updateConstraints = mapM updateConstraint
@@ -142,7 +155,8 @@ renameInModule imports (Module mn decls) =
142155 return (nm', ts)
143156 updateConstraint other = return other
144157 updateTypeName = update "type" importedTypes
145− updateClassName = update "typeclass" importedTypeClasses
158+ updateClassName = update "type class" importedTypeClasses
159+ updateValueName = update "value" importedValues
146160 updateDataConstructorName = update "data constructor" importedDataConstructors
147161 update t get nm = maybe (Left $ "Unknown " ++ t ++ " '" ++ show nm ++ "' in module '" ++ show mn ++ "'") return $ M.lookup nm (get imports)
148162
@@ -153,12 +167,14 @@ findExports :: [Module] -> Either String ExportEnvironment
153167findExports = foldM addModule (ExportEnvironment M.empty M.empty M.empty)
154168 where
155169 addModule env (Module mn ds) = foldM (addDecl mn) env ds
156− addDecl mn env (TypeClassDeclaration tcn _ _) = addTypeclass env mn tcn
157− addDecl mn env (DataDeclaration tn _ dcs) = do
158− env' <- addDataConstructors env mn tn (map fst dcs)
159− addType env' mn tn
160− addDecl mn env (TypeSynonymDeclaration tn _ _) = addType env mn tn
161− addDecl mn env (ExternDataDeclaration tn _) = addType env mn tn
170+ addDecl mn env (TypeClassDeclaration tcn _ ds) = do
171+ env' <- addTypeClass env mn tcn
172+ foldM (\env'' (TypeDeclaration name _) -> addValue env'' mn name) env' ds
173+ addDecl mn env (DataDeclaration tn _ dcs) = addType env mn tn (map fst dcs)
174+ addDecl mn env (TypeSynonymDeclaration 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
162178 addDecl _ env _ = return env
163179
164180-- |
@@ -180,59 +196,53 @@ findImports = foldl findImports' M.empty
180196-- Constructs a local environment for a module.
181197--
182198resolveImports :: ExportEnvironment -> Module -> Either String ImportEnvironment
183−resolveImports env (Module currentModule decls) = ImportEnvironment
184− <$> resolve (exportedTypes env) (resolveDefs typeImports)
185− <*> resolve (exportedDataConstructors env) resolveDcons
186− <*> resolve (exportedTypeClasses env) (resolveDefs (const []))
199+resolveImports env (Module currentModule decls) =
200+ foldM resolveImport (ImportEnvironment M.empty M.empty M.empty M.empty) (M.toList scope)
187201 where
188202 -- A Map from module name to imports from that module, where Nothing indicates everything is to be imported
189203 scope :: M.Map ModuleName (Maybe ExplicitImports)
190204 scope = M.insert currentModule Nothing (findImports decls)
191205
192− -- Resolve all exported names in a set by applying a type-specific resolver function
193− resolve :: M.Map ModuleName (S.Set id) ->
194− (M.Map ProperName (Qualified ProperName) -> ModuleName -> S.Set id -> Maybe ExplicitImports -> Either String (M.Map ProperName (Qualified ProperName))) ->
195− Either String (M.Map ProperName (Qualified ProperName))
196− resolve m f = foldM (\m' (mn, maybeExpl) -> f m' mn (fromMaybe S.empty $ mn `M.lookup` m) maybeExpl) M.empty (M.toList scope)
197−
198− -- Resolve a single name by adding it to the Map with a specified ModuleName, checking first
199− -- that the name does not currently exist in scope.
200− resolveDef :: (Ord id, Show id) => ModuleName ->
201− M.Map id (Qualified id) ->
202− id ->
203− Either String (M.Map id (Qualified id))
204− resolveDef mn result name = case M.lookup name result of
205− Nothing -> return $ M.insert name (Qualified (Just mn) name) result
206− Just x@(Qualified (Just mn') _) -> Left $ "Module '" ++ show currentModule ++
207− if mn' == currentModule || mn == currentModule
208− 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) ++ "'"
210−
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) ->
216− ModuleName ->
217− S.Set 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
222− Just expl -> do
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'
228−
229− -- Resolve a set of data constructors keyed by their type constructor
230− resolveDcons :: M.Map ProperName (Qualified ProperName) ->
231− ModuleName ->
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 $
236− case maybeExpl of
237− Just expl -> filter ((`elem` typeImports expl) . fst) (S.toList tcons)
238− Nothing -> S.toList tcons
206+ -- Add data to the ImportEnvironment
207+ resolveImport :: ImportEnvironment -> (ModuleName, Maybe ExplicitImports) -> Either String ImportEnvironment
208+ resolveImport imp (mn, Nothing) = importAll imp mn env
209+ resolveImport imp (mn, Just expl) = foldM (importExplicit mn) imp expl
210+
211+ -- Import something explicitly
212+ importExplicit :: ModuleName -> ImportEnvironment -> ImportType -> Either String ImportEnvironment
213+ importExplicit mn imp (NameImport name) = do
214+ values' <- updateImports mn (importedValues imp) name
215+ return $ imp { importedValues = values' }
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' }
223+
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)
233+
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
239+
240+ -- Add something to the ImportEnvironment if it does not already exist there
241+ updateImports :: (Ord id, Show id) => ModuleName -> M.Map id (Qualified id) -> id -> Either String (M.Map id (Qualified id))
242+ updateImports mn m name = case M.lookup name m of
243+ Nothing -> return $ M.insert name (Qualified (Just mn) name) m
244+ Just x@(Qualified (Just mn') _) -> Left $ "Module '" ++ show currentModule ++
245+ if mn' == currentModule || mn == currentModule
246+ then "' defines '" ++ show name ++ "' which conflicts with imported definition '" ++ show (Qualified (Just mn) name) ++ "'"
247+ else "' has conflicting imports for '" ++ show name ++ "': '" ++ show x ++ "', '" ++ show (Qualified (Just mn) name) ++ "'"
248+