1{-# OPTIONS_GHC -Wall #-}
4import Control.Monad (when)
5import Control.Monad.State (StateT, liftIO)
6import qualified Control.Monad.State as State
7import qualified Data.Char as Char
8import qualified Data.List as List
9import qualified Data.Map as Map
10import qualified Data.UnionFind.IO as UF
12import qualified AST.Type as T
13import qualified AST.Variable as Var
14import qualified Reporting.Annotation as A
15import qualified Reporting.Error.Type as Error
16import qualified Reporting.Region as R
32 Constraint Type Variable
47 | Record1 (Map.Map String a) a
52 | AliasN Var.Canonical [(String, TermN a)] (TermN a)
54 | TermN (Term1 (TermN a))
57record :: Map.Map String (TermN a) -> TermN a -> TermN a
59 TermN (Record1 fs rec)
66data Descriptor = Descriptor
70 , _copy :: Maybe Variable
75 = Structure (Term1 Variable)
77 | Var Flex (Maybe Super) (Maybe String)
78 | Alias Var.Canonical [(String,Variable)] Variable
116getVarNamesMark :: Int
128 | CEqual Error.Hint R.Region a a
129 | CAnd [Constraint a b]
130 | CLet [Scheme a b] (Constraint a b)
131 | CInstance R.Region SchemeName a
134type SchemeName = String
137data Scheme a b = Scheme
138 { _rigidQuantifiers :: [b]
139 , _flexibleQuantifiers :: [b]
140 , _constraint :: Constraint a b
141 , _header :: Map.Map String (A.Located a)
152(==>) :: Type -> Type -> Type
157(<|) :: TermN a -> TermN a -> TermN a
166mkDescriptor :: Content -> Descriptor
167mkDescriptor content =
176mkAtom :: Var.Canonical -> IO Variable
178 UF.fresh $ mkDescriptor (Atom name)
181mkVar :: Maybe Super -> IO Variable
183 UF.fresh $ mkDescriptor (Var Flex maybeSuper Nothing)
186mkNamedVar :: Flex -> String -> IO Variable
187mkNamedVar flex name =
188 UF.fresh $ mkDescriptor $ Var flex (toSuper name) (Just name)
191toSuper :: String -> Maybe Super
193 if List.isPrefixOf "number" name then
196 else if List.isPrefixOf "comparable" name then
199 else if List.isPrefixOf "appendable" name then
210monoscheme :: Map.Map String (A.Located a) -> Scheme a b
212 Scheme [] [] CTrue headers
217(/\) :: Constraint a b -> Constraint a b -> Constraint a b
225-- ex qs constraint == exists qs. constraint
226ex :: [Variable] -> TypeConstraint -> TypeConstraint
228 CLet [Scheme [] fqs constraint Map.empty] CTrue
231forall :: [Variable] -> TypeConstraint -> TypeConstraint
232forall rqs constraint =
233 CLet [Scheme rqs [] constraint Map.empty] CTrue
236exists :: (Type -> IO TypeConstraint) -> IO TypeConstraint
238 do v <- mkVar Nothing
239 ex [v] <$> f (VarN v)
242existsNumber :: (Type -> IO TypeConstraint) -> IO TypeConstraint
244 do v <- mkVar (Just Number)
245 ex [v] <$> f (VarN v)
249-- CONVERT TO SOURCE TYPES
252-- TODO: Attach resulting type to the descriptor so that you
253-- never have to do extra work, particularly nice for aliased types
254toSrcType :: Variable -> IO T.Canonical
256 do takenNames <- State.execStateT (getVarNames variable) Map.empty
257 State.evalStateT (variableToSrcType variable) (makeNameState takenNames)
260variableToSrcType :: Variable -> StateT NameState IO T.Canonical
261variableToSrcType variable =
262 do descriptor <- liftIO $ UF.descriptor variable
263 let mark = _mark descriptor
264 if mark == occursMark
269 do liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = occursMark })
270 srcType <- contentToSrcType variable (_content descriptor)
271 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = mark })
275contentToSrcType :: Variable -> Content -> StateT NameState IO T.Canonical
276contentToSrcType variable content =
284 Var _ _ (Just name) ->
287 Var flex maybeSuper Nothing ->
288 do freshName <- getFreshName maybeSuper
289 liftIO $ UF.modifyDescriptor variable $ \desc ->
290 desc { _content = Var flex maybeSuper (Just freshName) }
291 return (T.Var freshName)
293 Alias name args realVariable ->
294 do srcArgs <- traverse (traverse variableToSrcType) args
295 srcType <- variableToSrcType realVariable
296 return (T.Aliased name srcArgs (T.Filled srcType))
302termToSrcType :: Term1 Variable -> StateT NameState IO T.Canonical
306 do srcFunc <- variableToSrcType func
307 srcArg <- variableToSrcType arg
310 return (T.App f (args ++ [srcArg]))
313 return (T.App srcFunc [srcArg])
317 <$> variableToSrcType a
318 <*> variableToSrcType b
321 return $ T.Record [] Nothing
323 Record1 fields extension ->
324 do srcFields <- Map.toList <$> traverse variableToSrcType fields
325 srcExt <- T.iteratedDealias <$> variableToSrcType extension
328 T.Record subFields subExt ->
329 T.Record (subFields ++ srcFields) subExt
332 T.Record srcFields (Just srcExt)
335 error "Used toSrcType on a type that is not well-formed"
339-- MANAGE FRESH VARIABLE NAMES
342data NameState = NameState
343 { _taken :: TakenNames
346 , _comparables :: Int
347 , _appendables :: Int
348 , _compAppends :: Int
352type TakenNames = Map.Map String Variable
355makeNameState :: TakenNames -> NameState
357 NameState taken 0 0 0 0 0
360getFreshName :: (Monad m) => Maybe Super -> StateT NameState m String
361getFreshName maybeSuper =
364 do index <- State.gets _normals
365 taken <- State.gets _taken
366 let (uniqueName, newIndex) = getFreshNormal index taken
367 State.modify (\state -> state { _normals = newIndex })
371 getFreshSuper "number" _numbers (\index state -> state { _numbers = index })
374 getFreshSuper "comparable" _comparables (\index state -> state { _comparables = index })
377 getFreshSuper "appendable" _appendables (\index state -> state { _appendables = index })
380 getFreshSuper "compappend" _compAppends (\index state -> state { _compAppends = index })
383getFreshNormal :: Int -> TakenNames -> (String, Int)
384getFreshNormal index taken =
390 Char.chr (97 + letter) : if postfix <= 0 then "" else show postfix
392 if Map.member name taken then
393 getFreshNormal (index + 1) taken
402 -> (NameState -> Int)
403 -> (Int -> NameState -> NameState)
404 -> StateT NameState m String
405getFreshSuper name getter setter =
406 do index <- State.gets getter
407 taken <- State.gets _taken
408 let (uniqueName, newIndex) = getFreshSuperHelp name index taken
409 State.modify (setter newIndex)
413getFreshSuperHelp :: String -> Int -> TakenNames -> (String, Int)
414getFreshSuperHelp name index taken =
417 if index <= 0 then name else name ++ show index
419 if Map.member newName taken then
420 getFreshSuperHelp name (index + 1) taken
427-- GET ALL VARIABLE NAMES
430getVarNames :: Variable -> StateT TakenNames IO ()
432 do desc <- liftIO $ UF.descriptor var
433 case _mark desc == getVarNamesMark of
438 do liftIO $ UF.setDescriptor var (desc { _mark = getVarNamesMark })
439 case _content desc of
449 Var flex maybeSuper (Just name) ->
450 do oldTaken <- State.get
451 newTaken <- liftIO $ addVarName 0 name var flex maybeSuper oldTaken
454 Alias _ args realVar ->
455 do mapM_ (getVarNames . snd) args
458 Structure (App1 func arg) ->
462 Structure (Fun1 arg body) ->
466 Structure EmptyRecord1 ->
469 Structure (Record1 fields extension) ->
470 do mapM_ getVarNames fields
471 getVarNames extension
474addVarName :: Int -> String -> Variable -> Flex -> Maybe Super -> TakenNames -> IO TakenNames
475addVarName index givenName var flex maybeSuper taken =
478 makeIndexedName givenName index
480 case Map.lookup name taken of
482 do when (name /= givenName) $ UF.modifyDescriptor var $ \desc ->
483 desc { _content = Var flex maybeSuper (Just name) }
484 return $ Map.insert name var taken
487 do same <- UF.equivalent var otherVar
490 else addVarName (index + 1) givenName var flex maybeSuper taken
493makeIndexedName :: String -> Int -> String
494makeIndexedName name index =
498 else if Char.isDigit (last name) then
499 name ++ '_' : show index
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