1{-# OPTIONS_GHC -Wall #-}
2module Canonicalize.Module
8import qualified Data.Graph as Graph
9import qualified Data.Map as Map
10import qualified Data.Set as Set
12import qualified AST.Expression.Canonical as Can
13import qualified AST.Expression.Source as Src
14import qualified AST.Expression.Valid as Valid
15import qualified AST.Module.Name as ModuleName
16import qualified AST.Type as Type
17import qualified Canonicalize.Environment as Env
18import qualified Canonicalize.Environment.Dups as Dups
19import qualified Canonicalize.Expression as Expr
20import qualified Canonicalize.Pattern as Pattern
21import qualified Canonicalize.Type as Type
22import qualified Elm.Interface as I
23import qualified Elm.Name as N
24import qualified Elm.Package as Pkg
25import qualified Reporting.Annotation as A
26import qualified Reporting.Error.Canonicalize as Error
27import qualified Reporting.Region as R
28import qualified Reporting.Result as Result
29import qualified Reporting.Warning as Warning
37 Result.Result () Warning.Warning Error.Error a
46 -> Map.Map ModuleName.Raw ModuleName.Canonical
50canonicalize pkg importDict interfaces module_ =
51 do env <- Env.create pkg importDict interfaces module_
52 let (Valid.Module name _ _ exports _ decls unions aliases binops effects) = module_
53 (cdecls, cunions, caliases) <-
55 <$> canonicalizeDecls env decls
56 <*> (Map.fromList <$> traverse (canonicalizeUnion env) unions)
57 <*> (Map.fromList <$> traverse (canonicalizeAlias env) aliases)
59 let cbinops = Map.fromList (map canonicalizeBinop binops)
60 ceffects <- canonicalizeEffects env cunions effects
61 cexports <- canonicalizeExports decls cunions caliases cbinops ceffects exports
63 let home = ModuleName.Canonical pkg name
64 let docs = toDocs module_
65 return $ Can.Module home docs cexports cdecls cunions caliases cbinops ceffects
72toDocs :: Valid.Module -> A.Located (Maybe Can.Docs)
73toDocs (Valid.Module _ (A.A region maybeOverview) comments _ _ _ _ _ _ _) =
79 A.A region (Just (Can.Docs overview comments))
86canonicalizeAlias :: Env.Env -> Valid.Alias -> Result ( N.Name, Can.Alias )
87canonicalizeAlias env (Valid.Alias (A.A _ name) args tipe) =
88 do ctipe <- Type.canonicalize env tipe
89 return (name, Can.Alias (map A.drop args) ctipe (toRecordCtorInfo tipe))
92toRecordCtorInfo :: Type.Raw -> Maybe [N.Name]
93toRecordCtorInfo (A.A _ tipe) =
95 Type.RRecord fields Nothing ->
96 Just (map (A.drop . fst) fields)
106canonicalizeUnion :: Env.Env -> Valid.Union -> Result ( N.Name, Can.Union )
107canonicalizeUnion env (Valid.Union (A.A _ name) args ctors) =
109 canonicalizeCtor (A.A _ ctor, tipes) =
110 do ctipes <- traverse (Type.canonicalize env) tipes
111 return (ctor, ctipes)
113 do cctors <- traverse canonicalizeCtor ctors
114 return ( name, Can.Union (map A.drop args) cctors )
121canonicalizeBinop :: Valid.Binop -> ( N.Name, Can.Binop )
122canonicalizeBinop (Valid.Binop (A.A _ op) associativity precedence func) =
123 ( op, Can.Binop_ associativity precedence func )
127-- CANONICALIZE DECLARATIONS
130canonicalizeDecls :: Env.Env -> [A.Located Valid.Decl] -> Result Can.Decls
131canonicalizeDecls env decls =
132 do nodes <- traverse (toNode env) decls
133 detectCycles (Graph.stronglyConnComp nodes)
136detectCycles :: [Graph.SCC Decl] -> Result Can.Decls
140 Result.ok Can.SaveTheEnvironment
144 Graph.AcyclicSCC decl ->
145 Can.Declare (toCanDecl decl)
146 <$> detectCycles otherSccs
148 Graph.CyclicSCC [] ->
149 detectCycles otherSccs
151 Graph.CyclicSCC (decl:decls) ->
152 do detectBadCycles decl decls
153 Can.DeclareRec (toCanDecl decl) (map toCanDecl decls)
154 <$> detectCycles otherSccs
157toNode :: Env.Env -> A.Located Valid.Decl -> Result (Decl, N.Name, [N.Name])
158toNode env (A.A region (Valid.Decl name@(A.A _ key) args body tipe)) =
161 do ctipe <- traverse (Type.canonicalize env) tipe
162 (cbody, freeLocals) <- Expr.removeLocals Map.empty $ Expr.canonicalize env body
163 return (Value region name cbody ctipe, key, Set.toList freeLocals)
166 do ctipe <- traverse (Type.canonicalize env) tipe
167 cargs@(Can.Args _ destructors) <- Pattern.canonicalizeArgs env args
168 newEnv <- Env.addLocals destructors env
169 (cbody, freeLocals) <- Expr.removeLocals destructors $ Expr.canonicalize newEnv body
170 return (Function key cargs cbody ctipe, key, Set.toList freeLocals)
174 = Value R.Region (A.Located N.Name) Can.Expr (Maybe Type.Canonical)
175 | Function N.Name Can.Args Can.Expr (Maybe Type.Canonical)
178toCanDecl :: Decl -> Can.Decl
181 Value _ (A.A _ name) body tipe ->
182 Can.Value name body tipe
184 Function name args body tipe ->
185 Can.Function name args body tipe
188detectBadCycles :: Decl -> [Decl] -> Result ()
189detectBadCycles decl decls =
190 case traverse detectBadCyclesHelp (decl:decls) of
199 (declRegion, A.A region name) : otherInfo ->
200 let otherNames = map (A.drop . snd) otherInfo in
201 Result.throw declRegion (Error.RecursiveDecl region name otherNames)
204detectBadCyclesHelp :: Decl -> Maybe (R.Region, A.Located N.Name)
205detectBadCyclesHelp decl =
207 Value region name _ _ ->
215-- CANONICALIZE EFFECTS
218canonicalizeEffects :: Env.Env -> Map.Map N.Name a -> Valid.Effects -> Result Can.Effects
219canonicalizeEffects env unions effects =
222 Result.ok Can.NoEffects
225 do pairs <- traverse (canonicalizePort env) ports
226 return $ Can.Ports (Map.fromList pairs)
229 Can.Cmd <$> verifyEffectType cmdType unions
232 Can.Sub <$> verifyEffectType subType unions
234 Valid.Fx cmdType subType ->
236 <$> verifyEffectType cmdType unions
237 <*> verifyEffectType subType unions
240canonicalizePort :: Env.Env -> Valid.Port -> Result (N.Name, Type.Canonical)
241canonicalizePort env (Valid.Port (A.A _ name) tipe) =
242 (,) name <$> Type.canonicalize env tipe
245verifyEffectType :: A.Located N.Name -> Map.Map N.Name a -> Result N.Name
246verifyEffectType (A.A region name) unions =
247 if Map.member name unions then
250 Result.throw region (Error.EffectNotFound name)
254-- CANONICALIZE EXPORTS
258 :: [A.Located Valid.Decl]
259 -> Map.Map N.Name union
260 -> Map.Map N.Name alias
261 -> Map.Map N.Name binop
264 -> Result Can.Exports
265canonicalizeExports decls unions aliases binops effects exposing =
268 Result.ok Can.ExportEverything
270 Src.Explicit exposeds ->
271 do let names = Map.fromList (map declToName decls)
272 infos <- traverse (checkExposed names unions aliases binops effects) exposeds
273 let toError name () () = Error.ExportDuplicate name
274 Can.Export <$> Dups.detect toError infos
277declToName :: A.Located Valid.Decl -> (N.Name, Can.Export)
278declToName (A.A _ (Valid.Decl (A.A _ name) _ _ _)) =
279 (name, Can.ExportValue)
283 :: Map.Map N.Name decl
284 -> Map.Map N.Name union
285 -> Map.Map N.Name alias
286 -> Map.Map N.Name binop
288 -> A.Located Src.Exposed
289 -> Result (N.Name, [Dups.Info () Can.Export])
290checkExposed decls unions aliases binops effects (A.A region exposed) =
293 if Map.member name decls then
294 Result.ok (Dups.info name region () Can.ExportValue)
296 case checkPorts effects name of
298 Result.ok (Dups.info name region () Can.ExportPort)
301 Result.throw region $ Error.ExportNotFound Error.BadVar name $
302 ports ++ Map.keys decls
305 if Map.member name binops then
306 Result.ok (Dups.info name region () Can.ExportBinop)
308 Result.throw region $ Error.ExportNotFound Error.BadOp name $
311 Src.Upper name Src.Public ->
312 if Map.member name unions then
313 Result.ok (Dups.info name region () Can.ExportUnionOpen)
314 else if Map.member name aliases then
315 Result.throw region $ Error.ExportOpenAlias name
317 Result.throw region $ Error.ExportNotFound Error.BadType name $
318 Map.keys unions ++ Map.keys aliases
320 Src.Upper name Src.Private ->
321 if Map.member name unions then
322 Result.ok (Dups.info name region () Can.ExportUnionClosed)
323 else if Map.member name aliases then
324 Result.ok (Dups.info name region () Can.ExportAlias)
326 Result.throw region $ Error.ExportNotFound Error.BadType name $
327 Map.keys unions ++ Map.keys aliases
330checkPorts :: Can.Effects -> N.Name -> Maybe [N.Name]
331checkPorts effects name =
337 if Map.member name ports then Nothing else Just (Map.keys ports)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list