1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
7 , Descriptor(Descriptor)
22import Control.Monad (when)
23import Control.Monad.State.Strict (StateT, liftIO)
24import qualified Control.Monad.State.Strict as State
25import qualified Data.Char as Char
26import qualified Data.Map as Map
27import Data.Monoid ((<>))
28import qualified Data.Text as Text
29import Data.Text (Text)
31import qualified AST.Type as T
32import qualified AST.Variable as Var
33import qualified Type.UnionFind as UF
45 = App1 Var.Canonical [Variable]
46 | Fun1 Variable Variable
48 | Record1 (Map.Map Text Variable) Variable
53 | AliasN Var.Canonical [(Text, Type)] Type
55 | AppN Var.Canonical [Type]
58 | RecordN (Map.Map Text Type) Type
70 , _copy :: Maybe Variable
76 | Var Flex (Maybe Super) (Maybe Text)
77 | Alias Var.Canonical [(Text,Variable)] Variable
115getVarNamesMark :: Int
128(==>) :: Type -> Type -> Type
137mkDescriptor :: Content -> Descriptor
138mkDescriptor content =
147mkVar :: Maybe Super -> IO Variable
149 UF.fresh $ mkDescriptor (Var Flex maybeSuper Nothing)
152mkNamedVar :: Flex -> Text -> IO Variable
153mkNamedVar flex name =
154 UF.fresh $ mkDescriptor $ Var flex (toSuper name) (Just name)
157toSuper :: Text -> Maybe Super
159 if Text.isPrefixOf "number" name then
162 else if Text.isPrefixOf "comparable" name then
165 else if Text.isPrefixOf "appendable" name then
173-- CONVERT TO SOURCE TYPES
176-- TODO: Attach resulting type to the descriptor so that you
177-- never have to do extra work, particularly nice for aliased types
178toSrcType :: Variable -> IO T.Canonical
180 do takenNames <- State.execStateT (getVarNames variable) Map.empty
181 State.evalStateT (variableToSrcType variable) (makeNameState takenNames)
184variableToSrcType :: Variable -> StateT NameState IO T.Canonical
185variableToSrcType variable =
186 do descriptor <- liftIO $ UF.descriptor variable
187 let mark = _mark descriptor
188 if mark == occursMark
193 do liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = occursMark })
194 srcType <- contentToSrcType variable (_content descriptor)
195 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = mark })
199contentToSrcType :: Variable -> Content -> StateT NameState IO T.Canonical
200contentToSrcType variable content =
205 Var _ _ (Just name) ->
208 Var flex maybeSuper Nothing ->
209 do freshName <- getFreshName maybeSuper
210 liftIO $ UF.modifyDescriptor variable $ \desc ->
211 desc { _content = Var flex maybeSuper (Just freshName) }
212 return (T.Var freshName)
214 Alias name args realVariable ->
215 do srcArgs <- traverse (traverse variableToSrcType) args
216 srcType <- variableToSrcType realVariable
217 return (T.Aliased name srcArgs (T.Filled srcType))
223termToSrcType :: FlatType -> StateT NameState IO T.Canonical
227 T.Type name <$> traverse variableToSrcType args
231 <$> variableToSrcType a
232 <*> variableToSrcType b
235 return $ T.Record [] Nothing
237 Record1 fields extension ->
238 do srcFields <- Map.toList <$> traverse variableToSrcType fields
239 srcExt <- T.iteratedDealias <$> variableToSrcType extension
242 T.Record subFields subExt ->
243 T.Record (subFields ++ srcFields) subExt
246 T.Record srcFields (Just srcExt)
249 error "Used toSrcType on a type that is not well-formed"
253-- MANAGE FRESH VARIABLE NAMES
258 { _taken :: TakenNames
261 , _comparables :: Int
262 , _appendables :: Int
263 , _compAppends :: Int
267type TakenNames = Map.Map Text Variable
270makeNameState :: TakenNames -> NameState
272 NameState taken 0 0 0 0 0
275getFreshName :: (Monad m) => Maybe Super -> StateT NameState m Text
276getFreshName maybeSuper =
279 do index <- State.gets _normals
280 taken <- State.gets _taken
281 let (uniqueName, newIndex) = getFreshNormal index taken
282 State.modify (\state -> state { _normals = newIndex })
286 getFreshSuper "number" _numbers (\index state -> state { _numbers = index })
289 getFreshSuper "comparable" _comparables (\index state -> state { _comparables = index })
292 getFreshSuper "appendable" _appendables (\index state -> state { _appendables = index })
295 getFreshSuper "compappend" _compAppends (\index state -> state { _compAppends = index })
298getFreshNormal :: Int -> TakenNames -> (Text, Int)
299getFreshNormal index taken =
305 Char.chr (97 + letter)
308 Text.pack (if postfix <= 0 then [char] else char : show postfix)
310 if Map.member name taken then
311 getFreshNormal (index + 1) taken
320 -> (NameState -> Int)
321 -> (Int -> NameState -> NameState)
322 -> StateT NameState m Text
323getFreshSuper name getter setter =
324 do index <- State.gets getter
325 taken <- State.gets _taken
326 let (uniqueName, newIndex) = getFreshSuperHelp name index taken
327 State.modify (setter newIndex)
331getFreshSuperHelp :: Text -> Int -> TakenNames -> (Text, Int)
332getFreshSuperHelp name index taken =
335 if index <= 0 then name else name <> Text.pack (show index)
337 if Map.member newName taken then
338 getFreshSuperHelp name (index + 1) taken
345-- GET ALL VARIABLE NAMES
348getVarNames :: Variable -> StateT TakenNames IO ()
350 do desc <- liftIO $ UF.descriptor var
351 case _mark desc == getVarNamesMark of
356 do liftIO $ UF.setDescriptor var (desc { _mark = getVarNamesMark })
357 case _content desc of
364 Var flex maybeSuper (Just name) ->
365 do oldTaken <- State.get
366 newTaken <- liftIO $ addVarName 0 name var flex maybeSuper oldTaken
369 Alias _ args realVar ->
370 do mapM_ (getVarNames . snd) args
373 Structure (App1 _ args) ->
374 mapM_ getVarNames args
376 Structure (Fun1 arg body) ->
380 Structure EmptyRecord1 ->
383 Structure (Record1 fields extension) ->
384 do mapM_ getVarNames fields
385 getVarNames extension
388addVarName :: Int -> Text -> Variable -> Flex -> Maybe Super -> TakenNames -> IO TakenNames
389addVarName index givenName var flex maybeSuper taken =
392 makeIndexedName givenName index
394 case Map.lookup name taken of
396 do when (name /= givenName) $ UF.modifyDescriptor var $ \desc ->
397 desc { _content = Var flex maybeSuper (Just name) }
398 return $ Map.insert name var taken
401 do same <- UF.equivalent var otherVar
404 else addVarName (index + 1) givenName var flex maybeSuper taken
407makeIndexedName :: Text -> Int -> Text
408makeIndexedName name index =
412 else if Char.isDigit (Text.last name) then
413 name <> Text.pack ('_' : show index)
416 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