@@ -10,10 +10,12 @@ import qualified Data.Map as Map
1010import qualified Data.Set as Set
1111
1212import qualified AST.Expression.Canonical as Can
13+import qualified AST.Expression.Source as Src
1314import qualified AST.Expression.Valid as Valid
1415import qualified AST.Module.Name as ModuleName
1516import qualified AST.Type as Type
1617import qualified Canonicalize.Environment as Env
18+import qualified Canonicalize.Environment.Dups as Dups
1719import qualified Canonicalize.Expression as Expr
1820import qualified Canonicalize.Pattern as Pattern
1921import qualified Canonicalize.Type as Type
@@ -47,15 +49,34 @@ canonicalize
4749 -> Result Can.Module
4850canonicalize pkg importDict interfaces module_ =
4951 do env <- Env.create pkg importDict interfaces module_
50− let (Valid.Module name _ _ _ _ decls unions aliases binops _) = module_
51− Can.Module (ModuleName.Canonical pkg name)
52− <$> error "TODO docs"
53− <*> error "TODO imports"
54− <*> canonicalizeDecls env decls
55− <*> (Map.fromList <$> traverse (canonicalizeUnion env) unions)
56− <*> (Map.fromList <$> traverse (canonicalizeAlias env) aliases)
57− <*> return (Map.fromList (map canonicalizeBinop binops))
58− <*> error "TODO effects"
52+ let (Valid.Module name _ _ exports _ decls unions aliases binops effects) = module_
53+ (cdecls, cunions, caliases) <-
54+ (,,)
55+ <$> canonicalizeDecls env decls
56+ <*> (Map.fromList <$> traverse (canonicalizeUnion env) unions)
57+ <*> (Map.fromList <$> traverse (canonicalizeAlias env) aliases)
58+
59+ let cbinops = Map.fromList (map canonicalizeBinop binops)
60+ ceffects <- canonicalizeEffects env cunions effects
61+ cexports <- canonicalizeExports decls cunions caliases cbinops ceffects exports
62+
63+ let home = ModuleName.Canonical pkg name
64+ let docs = toDocs module_
65+ return $ Can.Module home docs cexports cdecls cunions caliases cbinops ceffects
66+
67+
68+
69+-- DOCUMENTATION
70+
71+
72+toDocs :: Valid.Module -> A.Located (Maybe Can.Docs)
73+toDocs (Valid.Module _ (A.A region maybeOverview) comments _ _ _ _ _ _ _) =
74+ case maybeOverview of
75+ Nothing ->
76+ A.A region Nothing
77+
78+ Just overview ->
79+ A.A region (Just (Can.Docs overview comments))
5980
6081
6182
@@ -65,7 +86,17 @@ canonicalize pkg importDict interfaces module_ =
6586canonicalizeAlias :: Env.Env -> Valid.Alias -> Result ( N.Name, Can.Alias )
6687canonicalizeAlias env (Valid.Alias (A.A _ name) args tipe) =
6788 do ctipe <- Type.canonicalize env tipe
68− return (name, Can.Alias (map A.drop args) ctipe)
89+ return (name, Can.Alias (map A.drop args) ctipe (toRecordCtorInfo tipe))
90+
91+
92+toRecordCtorInfo :: Type.Raw -> Maybe [N.Name]
93+toRecordCtorInfo (A.A _ tipe) =
94+ case tipe of
95+ Type.RRecord fields Nothing ->
96+ Just (map (A.drop . fst) fields)
97+
98+ _ ->
99+ Nothing
69100
70101
71102
@@ -178,3 +209,138 @@ detectBadCyclesHelp decl =
178209
179210 Function _ _ _ _ ->
180211 Nothing
212+
213+
214+
215+-- CANONICALIZE EFFECTS
216+
217+
218+canonicalizeEffects :: Env.Env -> Map.Map N.Name a -> Valid.Effects -> Result Can.Effects
219+canonicalizeEffects env unions effects =
220+ case effects of
221+ Valid.NoEffects ->
222+ Result.ok Can.NoEffects
223+
224+ Valid.Ports ports ->
225+ do pairs <- traverse (canonicalizePort env) ports
226+ return $ Can.Ports (Map.fromList pairs)
227+
228+ Valid.Cmd cmdType ->
229+ Can.Cmd <$> verifyEffectType cmdType unions
230+
231+ Valid.Sub subType ->
232+ Can.Sub <$> verifyEffectType subType unions
233+
234+ Valid.Fx cmdType subType ->
235+ Can.Fx
236+ <$> verifyEffectType cmdType unions
237+ <*> verifyEffectType subType unions
238+
239+
240+canonicalizePort :: Env.Env -> Valid.Port -> Result (N.Name, Type.Canonical)
241+canonicalizePort env (Valid.Port (A.A _ name) tipe) =
242+ (,) name <$> Type.canonicalize env tipe
243+
244+
245+verifyEffectType :: A.Located N.Name -> Map.Map N.Name a -> Result N.Name
246+verifyEffectType (A.A region name) unions =
247+ if Map.member name unions then
248+ Result.ok name
249+ else
250+ Result.throw region (Error.EffectNotFound name)
251+
252+
253+
254+-- CANONICALIZE EXPORTS
255+
256+
257+canonicalizeExports
258+ :: [A.Located Valid.Decl]
259+ -> Map.Map N.Name union
260+ -> Map.Map N.Name alias
261+ -> Map.Map N.Name binop
262+ -> Can.Effects
263+ -> Src.Exposing
264+ -> Result Can.Exports
265+canonicalizeExports decls unions aliases binops effects exposing =
266+ case exposing of
267+ Src.Open ->
268+ Result.ok Can.ExportEverything
269+
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
275+
276+
277+declToName :: A.Located Valid.Decl -> (N.Name, Can.Export)
278+declToName (A.A _ (Valid.Decl (A.A _ name) _ _ _)) =
279+ (name, Can.ExportValue)
280+
281+
282+checkExposed
283+ :: Map.Map N.Name decl
284+ -> Map.Map N.Name union
285+ -> Map.Map N.Name alias
286+ -> Map.Map N.Name binop
287+ -> Can.Effects
288+ -> A.Located Src.Exposed
289+ -> Result (N.Name, [Dups.Info () Can.Export])
290+checkExposed decls unions aliases binops effects (A.A region exposed) =
291+ case exposed of
292+ Src.Lower name ->
293+ if Map.member name decls then
294+ Result.ok (Dups.info name region () Can.ExportValue)
295+ else
296+ case checkPorts effects name of
297+ Nothing ->
298+ Result.ok (Dups.info name region () Can.ExportPort)
299+
300+ Just ports ->
301+ Result.throw region $ Error.ExportNotFound Error.BadVar name $
302+ ports ++ Map.keys decls
303+
304+ Src.Operator name ->
305+ if Map.member name binops then
306+ Result.ok (Dups.info name region () Can.ExportBinop)
307+ else
308+ Result.throw region $ Error.ExportNotFound Error.BadOp name $
309+ Map.keys binops
310+
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
316+ else
317+ Result.throw region $ Error.ExportNotFound Error.BadType name $
318+ Map.keys unions ++ Map.keys aliases
319+
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)
325+ else
326+ Result.throw region $ Error.ExportNotFound Error.BadType name $
327+ Map.keys unions ++ Map.keys aliases
328+
329+
330+checkPorts :: Can.Effects -> N.Name -> Maybe [N.Name]
331+checkPorts effects name =
332+ case effects of
333+ Can.NoEffects ->
334+ Just []
335+
336+ Can.Ports ports ->
337+ if Map.member name ports then Nothing else Just (Map.keys ports)
338+
339+ Can.Cmd _ ->
340+ Just []
341+
342+ Can.Sub _ ->
343+ Just []
344+
345+ Can.Fx _ _ ->
346+ Just []