1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
7 , Descriptor(Descriptor)
14 , (==>), float, char, string, bool
25import Control.Monad.State.Strict (StateT, liftIO)
26import qualified Control.Monad.State.Strict as State
27import qualified Data.Char as Char
28import qualified Data.Map.Strict as Map
29import Data.Monoid ((<>))
30import qualified Data.Text as Text
31import Data.Text (Text)
32import Data.Word (Word32)
34import qualified AST.Type as T
35import qualified AST.Variable as Var
36import qualified Type.UnionFind as UF
48 = App1 Var.Canonical [Variable]
49 | Fun1 Variable Variable
51 | Record1 (Map.Map Text Variable) Variable
56 | AliasN Var.Canonical [(Text, Type)] Type
58 | AppN Var.Canonical [Type]
61 | RecordN (Map.Map Text Type) Type
73 , _copy :: Maybe Variable
78 = FlexVar (Maybe Text)
79 | FlexSuper T.Super (Maybe Text)
81 | RigidSuper T.Super Text
83 | Alias Var.Canonical [(Text,Variable)] Variable
87makeDescriptor :: Content -> Descriptor
88makeDescriptor content =
89 Descriptor content noRank noMark Nothing
110newtype Mark = Mark Word32
124getVarNamesMark :: Mark
129{-# INLINE nextMark #-}
130nextMark :: Mark -> Mark
131nextMark (Mark mark) =
143(==>) :: Type -> Type -> Type
148{-# NOINLINE float #-}
160{-# NOINLINE string #-}
173-- MAKE FLEX VARIABLES
176mkFlexVar :: IO Variable
178 UF.fresh flexVarDescriptor
181{-# NOINLINE flexVarDescriptor #-}
182flexVarDescriptor :: Descriptor
184 makeDescriptor unnamedFlexVar
187{-# NOINLINE unnamedFlexVar #-}
188unnamedFlexVar :: Content
197mkFlexNumber :: IO Variable
199 UF.fresh flexNumberDescriptor
202{-# NOINLINE flexNumberDescriptor #-}
203flexNumberDescriptor :: Descriptor
204flexNumberDescriptor =
205 makeDescriptor (unnamedFlexSuper T.Number)
208unnamedFlexSuper :: T.Super -> Content
209unnamedFlexSuper super =
210 FlexSuper super Nothing
214-- MAKE NAMED VARIABLES
217nameToFlex :: Text -> IO Variable
219 UF.fresh $ makeDescriptor $
220 maybe FlexVar FlexSuper (toSuper name) (Just name)
223nameToRigid :: Text -> IO Variable
225 UF.fresh $ makeDescriptor $
226 maybe RigidVar RigidSuper (toSuper name) name
229toSuper :: Text -> Maybe T.Super
231 if Text.isPrefixOf "number" name then
234 else if Text.isPrefixOf "comparable" name then
237 else if Text.isPrefixOf "appendable" name then
240 else if Text.isPrefixOf "compappend" name then
248-- CONVERT TO SOURCE TYPES
251-- TODO: Attach resulting type to the descriptor so that you
252-- never have to do extra work, particularly nice for aliased types
253toSrcType :: Variable -> IO T.Canonical
255 do takenNames <- State.execStateT (getVarNames variable) Map.empty
256 State.evalStateT (variableToSrcType variable) (makeNameState takenNames)
259variableToSrcType :: Variable -> StateT NameState IO T.Canonical
260variableToSrcType variable =
261 do descriptor <- liftIO $ UF.descriptor variable
262 let mark = _mark descriptor
263 if mark == occursMark
268 do liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = occursMark })
269 srcType <- contentToSrcType variable (_content descriptor)
270 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = mark })
274contentToSrcType :: Variable -> Content -> StateT NameState IO T.Canonical
275contentToSrcType variable content =
286 do name <- getFreshVarName
287 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _content = FlexVar (Just name) })
290 FlexSuper super maybeName ->
296 do name <- getFreshSuperName super
297 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _content = FlexSuper super (Just name) })
306 Alias name args realVariable ->
307 do srcArgs <- traverse (traverse variableToSrcType) args
308 srcType <- variableToSrcType realVariable
309 return (T.Aliased name srcArgs (T.Filled srcType))
315termToSrcType :: FlatType -> StateT NameState IO T.Canonical
319 T.Type name <$> traverse variableToSrcType args
323 <$> variableToSrcType a
324 <*> variableToSrcType b
327 return $ T.Record [] Nothing
329 Record1 fields extension ->
330 do srcFields <- Map.toList <$> traverse variableToSrcType fields
331 srcExt <- T.iteratedDealias <$> variableToSrcType extension
334 T.Record subFields subExt ->
335 T.Record (subFields ++ srcFields) subExt
338 T.Record srcFields (Just srcExt)
341 error "Used toSrcType on a type that is not well-formed"
345-- MANAGE FRESH VARIABLE NAMES
350 { _taken :: TakenNames
353 , _comparables :: Int
354 , _appendables :: Int
355 , _compAppends :: Int
359type TakenNames = Map.Map Text Variable
362makeNameState :: TakenNames -> NameState
364 NameState taken 0 0 0 0 0
367getFreshVarName :: (Monad m) => StateT NameState m Text
369 do index <- State.gets _normals
370 taken <- State.gets _taken
371 let (uniqueName, newIndex) = getFreshNormal index taken
372 State.modify (\state -> state { _normals = newIndex })
376getFreshSuperName :: (Monad m) => T.Super -> StateT NameState m Text
377getFreshSuperName super =
380 getFreshSuper "number" _numbers (\index state -> state { _numbers = index })
383 getFreshSuper "comparable" _comparables (\index state -> state { _comparables = index })
386 getFreshSuper "appendable" _appendables (\index state -> state { _appendables = index })
389 getFreshSuper "compappend" _compAppends (\index state -> state { _compAppends = index })
392getFreshNormal :: Int -> TakenNames -> (Text, Int)
393getFreshNormal index taken =
399 Char.chr (97 + letter)
402 Text.pack (if postfix <= 0 then [character] else character : show postfix)
404 if Map.member name taken then
405 getFreshNormal (index + 1) taken
414 -> (NameState -> Int)
415 -> (Int -> NameState -> NameState)
416 -> StateT NameState m Text
417getFreshSuper name getter setter =
418 do index <- State.gets getter
419 taken <- State.gets _taken
420 let (uniqueName, newIndex) = getFreshSuperHelp name index taken
421 State.modify (setter newIndex)
425getFreshSuperHelp :: Text -> Int -> TakenNames -> (Text, Int)
426getFreshSuperHelp name index taken =
429 if index <= 0 then name else name <> Text.pack (show index)
431 if Map.member newName taken then
432 getFreshSuperHelp name (index + 1) taken
439-- GET ALL VARIABLE NAMES
442getVarNames :: Variable -> StateT TakenNames IO ()
444 do (Descriptor content rank mark copy) <- liftIO $ UF.descriptor var
445 if mark == getVarNamesMark then return () else
446 do liftIO $ UF.setDescriptor var (Descriptor content rank getVarNamesMark copy)
457 registerName name var (FlexVar . Just)
459 FlexSuper super maybeName ->
465 registerName name var (FlexSuper super . Just)
468 registerName name var RigidVar
470 RigidSuper super name ->
471 registerName name var (RigidSuper super)
473 Alias _ args realVar ->
474 do mapM_ (getVarNames . snd) args
477 Structure (App1 _ args) ->
478 mapM_ getVarNames args
480 Structure (Fun1 arg body) ->
484 Structure EmptyRecord1 ->
487 Structure (Record1 fields extension) ->
488 do mapM_ getVarNames fields
489 getVarNames extension
493-- REGISTER NAME / RENAME DUPLICATES
496registerName :: Text -> Variable -> (Text -> Content) -> StateT TakenNames IO ()
497registerName givenName var makeContent =
498 if Text.null givenName then
501 do takenNames <- State.get
502 State.put =<< liftIO (checkName 0 givenName var makeContent takenNames)
505checkName :: Int -> Text -> Variable -> (Text -> Content) -> TakenNames -> IO TakenNames
506checkName index givenName var makeContent takenNames =
511 else if Char.isDigit (Text.last givenName) then
512 givenName <> Text.pack ('_' : show index)
514 givenName <> Text.pack (show index)
516 case Map.lookup indexedName takenNames of
518 do if indexedName == givenName then return () else
519 UF.modifyDescriptor var $ \(Descriptor _ rank mark copy) ->
520 Descriptor (makeContent indexedName) rank mark copy
521 return $ Map.insert indexedName var takenNames
524 do same <- UF.equivalent var otherVar
526 then return takenNames
527 else checkName (index + 1) givenName var makeContent takenNames
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