1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
7 , Descriptor(Descriptor)
15 , (==>), float, char, string, bool
23import Control.Monad (when)
24import Control.Monad.State.Strict (StateT, liftIO)
25import qualified Control.Monad.State.Strict as State
26import qualified Data.Char as Char
27import qualified Data.Map as Map
28import Data.Monoid ((<>))
29import qualified Data.Text as Text
30import Data.Text (Text)
31import Data.Word (Word32)
33import qualified AST.Type as T
34import qualified AST.Variable as Var
35import qualified Type.UnionFind as UF
47 = App1 Var.Canonical [Variable]
48 | Fun1 Variable Variable
50 | Record1 (Map.Map Text Variable) Variable
55 | AliasN Var.Canonical [(Text, Type)] Type
57 | AppN Var.Canonical [Type]
60 | RecordN (Map.Map Text Type) Type
72 , _copy :: Maybe Variable
78 | Var Flex (Maybe T.Super) (Maybe Text)
79 | Alias Var.Canonical [(Text,Variable)] Variable
83makeDescriptor :: Content -> Descriptor
84makeDescriptor content =
85 Descriptor content noRank noMark Nothing
109newtype Mark = Mark Word32
123getVarNamesMark :: Mark
128{-# INLINE nextMark #-}
129nextMark :: Mark -> Mark
130nextMark (Mark mark) =
142(==>) :: Type -> Type -> Type
147{-# NOINLINE float #-}
159{-# NOINLINE string #-}
172-- MAKE FLEX VARIABLES
175mkFlexVar :: IO Variable
177 UF.fresh flexVarDescriptor
180{-# NOINLINE flexVarDescriptor #-}
181flexVarDescriptor :: Descriptor
183 makeDescriptor unnamedFlexVar
187{-# NOINLINE unnamedFlexVar #-}
188unnamedFlexVar :: Content
190 Var Flex Nothing Nothing
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 Var Flex (Just super) Nothing
214-- MAKE NAMED FLEX VARIABLES
217mkNamedVar :: Flex -> Text -> IO Variable
218mkNamedVar flex name =
219 UF.fresh $ makeDescriptor $ Var flex (toSuper name) (Just name)
222toSuper :: Text -> Maybe T.Super
224 if Text.isPrefixOf "number" name then
227 else if Text.isPrefixOf "comparable" name then
230 else if Text.isPrefixOf "appendable" name then
233 else if Text.isPrefixOf "compappend" name then
241-- CONVERT TO SOURCE TYPES
244-- TODO: Attach resulting type to the descriptor so that you
245-- never have to do extra work, particularly nice for aliased types
246toSrcType :: Variable -> IO T.Canonical
248 do takenNames <- State.execStateT (getVarNames variable) Map.empty
249 State.evalStateT (variableToSrcType variable) (makeNameState takenNames)
252variableToSrcType :: Variable -> StateT NameState IO T.Canonical
253variableToSrcType variable =
254 do descriptor <- liftIO $ UF.descriptor variable
255 let mark = _mark descriptor
256 if mark == occursMark
261 do liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = occursMark })
262 srcType <- contentToSrcType variable (_content descriptor)
263 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = mark })
267contentToSrcType :: Variable -> Content -> StateT NameState IO T.Canonical
268contentToSrcType variable content =
273 Var _ _ (Just name) ->
276 Var flex maybeSuper Nothing ->
277 do freshName <- getFreshName maybeSuper
278 liftIO $ UF.modifyDescriptor variable $ \desc ->
279 desc { _content = Var flex maybeSuper (Just freshName) }
280 return (T.Var freshName)
282 Alias name args realVariable ->
283 do srcArgs <- traverse (traverse variableToSrcType) args
284 srcType <- variableToSrcType realVariable
285 return (T.Aliased name srcArgs (T.Filled srcType))
291termToSrcType :: FlatType -> StateT NameState IO T.Canonical
295 T.Type name <$> traverse variableToSrcType args
299 <$> variableToSrcType a
300 <*> variableToSrcType b
303 return $ T.Record [] Nothing
305 Record1 fields extension ->
306 do srcFields <- Map.toList <$> traverse variableToSrcType fields
307 srcExt <- T.iteratedDealias <$> variableToSrcType extension
310 T.Record subFields subExt ->
311 T.Record (subFields ++ srcFields) subExt
314 T.Record srcFields (Just srcExt)
317 error "Used toSrcType on a type that is not well-formed"
321-- MANAGE FRESH VARIABLE NAMES
326 { _taken :: TakenNames
329 , _comparables :: Int
330 , _appendables :: Int
331 , _compAppends :: Int
335type TakenNames = Map.Map Text Variable
338makeNameState :: TakenNames -> NameState
340 NameState taken 0 0 0 0 0
343getFreshName :: (Monad m) => Maybe T.Super -> StateT NameState m Text
344getFreshName maybeSuper =
347 do index <- State.gets _normals
348 taken <- State.gets _taken
349 let (uniqueName, newIndex) = getFreshNormal index taken
350 State.modify (\state -> state { _normals = newIndex })
354 getFreshSuper "number" _numbers (\index state -> state { _numbers = index })
357 getFreshSuper "comparable" _comparables (\index state -> state { _comparables = index })
360 getFreshSuper "appendable" _appendables (\index state -> state { _appendables = index })
363 getFreshSuper "compappend" _compAppends (\index state -> state { _compAppends = index })
366getFreshNormal :: Int -> TakenNames -> (Text, Int)
367getFreshNormal index taken =
373 Char.chr (97 + letter)
376 Text.pack (if postfix <= 0 then [character] else character : show postfix)
378 if Map.member name taken then
379 getFreshNormal (index + 1) taken
388 -> (NameState -> Int)
389 -> (Int -> NameState -> NameState)
390 -> StateT NameState m Text
391getFreshSuper name getter setter =
392 do index <- State.gets getter
393 taken <- State.gets _taken
394 let (uniqueName, newIndex) = getFreshSuperHelp name index taken
395 State.modify (setter newIndex)
399getFreshSuperHelp :: Text -> Int -> TakenNames -> (Text, Int)
400getFreshSuperHelp name index taken =
403 if index <= 0 then name else name <> Text.pack (show index)
405 if Map.member newName taken then
406 getFreshSuperHelp name (index + 1) taken
413-- GET ALL VARIABLE NAMES
416getVarNames :: Variable -> StateT TakenNames IO ()
418 do desc <- liftIO $ UF.descriptor var
419 case _mark desc == getVarNamesMark of
424 do liftIO $ UF.setDescriptor var (desc { _mark = getVarNamesMark })
425 case _content desc of
432 Var flex maybeSuper (Just name) ->
433 do oldTaken <- State.get
434 newTaken <- liftIO $ addVarName 0 name var flex maybeSuper oldTaken
437 Alias _ args realVar ->
438 do mapM_ (getVarNames . snd) args
441 Structure (App1 _ args) ->
442 mapM_ getVarNames args
444 Structure (Fun1 arg body) ->
448 Structure EmptyRecord1 ->
451 Structure (Record1 fields extension) ->
452 do mapM_ getVarNames fields
453 getVarNames extension
456addVarName :: Int -> Text -> Variable -> Flex -> Maybe T.Super -> TakenNames -> IO TakenNames
457addVarName index givenName var flex maybeSuper taken =
460 makeIndexedName givenName index
462 case Map.lookup name taken of
464 do when (name /= givenName) $ UF.modifyDescriptor var $ \desc ->
465 desc { _content = Var flex maybeSuper (Just name) }
466 return $ Map.insert name var taken
469 do same <- UF.equivalent var otherVar
472 else addVarName (index + 1) givenName var flex maybeSuper taken
475makeIndexedName :: Text -> Int -> Text
476makeIndexedName name index =
480 else if Char.isDigit (Text.last name) then
481 name <> Text.pack ('_' : show index)
484 name <> Text.pack (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