1{-# OPTIONS_GHC -Wall #-}
2module Transform.Canonicalize.Setup
5 , typeAliasErrorExplanation
8import Control.Arrow (first)
9import Control.Monad (foldM)
10import Control.Monad.Error (throwError)
11import qualified Data.Graph as Graph
12import qualified Data.List as List
13import qualified Data.Map as Map
15import qualified AST.Expression.Valid as Valid
17import AST.Module (Interface(iAdts, iTypes, iAliases))
18import qualified AST.Module as Module
19import qualified AST.Type as Type
20import qualified AST.Variable as Var
21import qualified AST.Declaration as D
22import AST.PrettyPrint (pretty, eightyCharLines)
23import qualified AST.Pattern as P
24import Text.PrettyPrint as P
26import Transform.Canonicalize.Environment as Env
27import qualified Transform.Canonicalize.Type as Canonicalize
28import qualified Transform.Interface as Interface
31environment :: Module.Interfaces -> Module.ValidModule -> Canonicalizer [Doc] Environment
32environment interfaces modul@(Module.Module _ _ _ imports decls) =
33 do () <- allImportsAvailable
34 let moduleName = Module.names modul
35 nonLocalEnv <- foldM (addImports moduleName interfaces) (builtIns moduleName) imports
36 let (aliases, env) = List.foldl' (addDecl moduleName) ([], nonLocalEnv) decls
37 addTypeAliases moduleName aliases env
39 allImportsAvailable :: Canonicalizer [Doc] ()
41 case filter (not . found) modules of
43 missings -> throwError [ P.text (missingModuleError missings) ]
45 modules = map fst imports
47 found m = Map.member m interfaces || Module.nameIsNative m
49 missingModuleError missings =
50 concat [ "The following imports were not found:\n "
51 , List.intercalate ", " (map Module.nameToString missings)
55addImports :: Module.Name -> Module.Interfaces -> Environment -> (Module.Name, Module.ImportMethod)
56 -> Canonicalizer [Doc] Environment
57addImports moduleName interfaces environ (name, method)
58 | Module.nameIsNative name = return environ
62 return (updateEnviron (name' ++ "."))
64 Module.Open (Var.Listing vs open)
65 | open -> return (updateEnviron "")
66 | otherwise -> foldM (addValue name interface) environ vs
68 interface = Interface.filterExports ((Map.!) interfaces name)
70 updateEnviron prefix =
71 let dict' = dict . map (first (prefix++)) in
73 Env { _home = moduleName
74 , _values = dict' $ map pair (Map.keys (iTypes interface)) ++ ctors
75 , _adts = dict' $ map pair (Map.keys (iAdts interface))
76 , _aliases = dict' $ map alias (Map.toList (iAliases interface))
77 , _patterns = dict' $ ctors
80 canonical :: String -> Var.Canonical
81 canonical = Var.Canonical (Var.Module name)
83 pair :: String -> (String, Var.Canonical)
84 pair key = (key, canonical key)
86 alias (x,(tvars,tipe)) = (x, (canonical x, tvars, tipe))
88 ctors = concatMap (map (pair . fst) . snd . snd) (Map.toList (iAdts interface))
90addValue :: Module.Name -> Module.Interface -> Environment -> Var.Value
91 -> Canonicalizer [Doc] Environment
92addValue moduleName interface env value =
93 let name = Module.nameToString moduleName
94 insert' x = insert x (Var.Canonical (Var.Module moduleName) x)
95 msg x = "Import Error: Could not import value '" ++ name ++ "." ++ x ++
96 "'.\n It is not exported by module " ++ name ++ "."
97 notFound x = throwError [ P.text (msg x) ]
101 | Map.notMember x (iTypes interface) -> notFound x
103 return $ env { _values = insert' x (_values env) }
106 case Map.lookup x (iAliases interface) of
109 { _aliases = insert x v (_aliases env)
110 , _values = updatedValues
113 v = (Var.Canonical (Var.Module moduleName) x, tvars, t)
115 if Map.member x (iTypes interface)
116 then insert' x (_values env)
120 case Map.lookup x (iAdts interface) of
121 Nothing -> notFound x
123 return $ env { _adts = insert' x (_adts env) }
125 Var.Union x (Var.Listing xs open) ->
126 case Map.lookup x (iAdts interface) of
127 Nothing -> notFound x
128 Just (_tvars, ctors) ->
129 do ctors' <- filterNames (map fst ctors)
130 return $ env { _adts = insert' x (_adts env)
131 , _values = foldr insert' (_values env) ctors'
132 , _patterns = foldr insert' (_patterns env) ctors'
136 | open = return names
138 case filter (`notElem` names) xs of
142type Node = ((String, [String], Type.RawType), String, [String])
144node :: String -> [String] -> Type.RawType -> Node
145node name tvars alias = ((name, tvars, alias), name, edges alias)
149 Type.Lambda t1 t2 -> edges t1 ++ edges t2
151 Type.Type (Var.Raw x) -> [x]
152 Type.App t ts -> edges t ++ concatMap edges ts
153 Type.Record fs ext -> maybe [] edges ext ++ concatMap (edges . snd) fs
154 Type.Aliased _ t -> edges t
161 -> Canonicalizer [Doc] Environment
162addTypeAliases moduleName nodes environ =
163 foldM (addTypeAlias moduleName) environ (Graph.stronglyConnComp nodes)
169 -> Graph.SCC (String, [String], Type.RawType)
170 -> Canonicalizer [Doc] Environment
171addTypeAlias moduleName env scc =
172 case Graph.flattenSCC scc of
173 [(name, tvars, alias)] ->
174 do alias' <- Env.onError throw (Canonicalize.tipe env alias)
175 let value = (Var.Canonical (Var.Module moduleName) name, tvars, alias')
176 return $ env { _aliases = insert name value (_aliases env) }
179 let msg = "Problem with type alias '" ++ name ++ "':"
180 in P.vcat [ P.text msg, P.text err ]
185 [ P.text (eightyCharLines 0 mutuallyRecursiveMessage)
186 , indented (map typeAlias aliases)
187 , P.text (eightyCharLines 0 typeAliasErrorSegue)
188 , indented (map datatype aliases)
189 , P.text (eightyCharLines 0 typeAliasErrorExplanation)
195 :: (String, [String], Type.Type var)
196 -> D.Declaration' port def var
202 :: (String, [String], Type.Type var)
203 -> D.Declaration' port def var
205 D.Datatype n ts [(n,[t])]
208indented :: [D.ValidDecl] -> Doc
209indented decls = P.vcat (map prty decls) <> P.text "\n"
211 prty decl = P.text "\n " <> pretty decl
214mutuallyRecursiveMessage :: String
215mutuallyRecursiveMessage =
216 "The following type aliases are mutually recursive, forming an \
217 \infinite type. When you expand them, they just keep getting bigger:"
220typeAliasErrorSegue :: String
225typeAliasErrorExplanation :: String
226typeAliasErrorExplanation =
227 "It looks very similar, but the 'type' keyword creates a brand new type, \
228 \not just an alias for an existing one. This lets us avoid infinitely \
229 \expanding it during type inference."
232-- When canonicalizing, all _values should be Local, but all _adts and _patterns
233-- should be fully namespaced. With _adts, they may appear in types that can
235addDecl :: Module.Name -> ([Node], Environment) -> D.ValidDecl -> ([Node], Environment)
236addDecl moduleName info@(nodes,env) decl =
237 let namespacedVar = Var.Canonical (Var.Module moduleName)
238 addLocal x e = insert x (Var.local x) e
239 addNamespaced x e = insert x (namespacedVar x) e
242 D.Definition (Valid.Definition pattern _ _) ->
244 { _values = foldr addLocal (_values env) (P.boundVarList pattern) }
246 D.Datatype name _ ctors ->
248 { _values = addCtors addLocal (_values env)
249 , _adts = addNamespaced name (_adts env)
250 , _patterns = addCtors addNamespaced (_patterns env)
253 addCtors how e = foldr how e (map fst ctors)
255 D.TypeAlias name tvars alias ->
256 (,) (node name tvars alias : nodes) $ env
257 { _values = case alias of
258 Type.Record _ _ -> addLocal name (_values env)
263 let portName = case port of
264 D.Out name _ _ -> name
267 (,) nodes $ env { _values = addLocal portName (_values env) }
269 D.Fixity _ _ _ -> info
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