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)
32import qualified AST.Type as T
33import qualified AST.Variable as Var
34import qualified Type.UnionFind as UF
46 = App1 Var.Canonical [Variable]
47 | Fun1 Variable Variable
49 | Record1 (Map.Map Text Variable) Variable
54 | AliasN Var.Canonical [(Text, Type)] Type
56 | AppN Var.Canonical [Type]
59 | RecordN (Map.Map Text Type) Type
71 , _copy :: Maybe Variable
77 | Var Flex (Maybe Super) (Maybe Text)
78 | Alias Var.Canonical [(Text,Variable)] Variable
82makeDescriptor :: Content -> Descriptor
83makeDescriptor content =
84 Descriptor content noRank noMark Nothing
121getVarNamesMark :: Int
134(==>) :: Type -> Type -> Type
139{-# NOINLINE float #-}
151{-# NOINLINE string #-}
164-- MAKE FLEX VARIABLES
167mkFlexVar :: IO Variable
169 UF.fresh flexVarDescriptor
172{-# NOINLINE flexVarDescriptor #-}
173flexVarDescriptor :: Descriptor
175 makeDescriptor unnamedFlexVar
179{-# NOINLINE unnamedFlexVar #-}
180unnamedFlexVar :: Content
182 Var Flex Nothing Nothing
189mkFlexNumber :: IO Variable
191 UF.fresh flexNumberDescriptor
194{-# NOINLINE flexNumberDescriptor #-}
195flexNumberDescriptor :: Descriptor
196flexNumberDescriptor =
197 makeDescriptor (unnamedFlexSuper Number)
200unnamedFlexSuper :: Super -> Content
201unnamedFlexSuper super =
202 Var Flex (Just super) Nothing
206-- MAKE NAMED FLEX VARIABLES
209mkNamedVar :: Flex -> Text -> IO Variable
210mkNamedVar flex name =
211 UF.fresh $ makeDescriptor $ Var flex (toSuper name) (Just name)
214toSuper :: Text -> Maybe Super
216 if Text.isPrefixOf "number" name then
219 else if Text.isPrefixOf "comparable" name then
222 else if Text.isPrefixOf "appendable" name then
225 else if Text.isPrefixOf "compappend" name then
233-- CONVERT TO SOURCE TYPES
236-- TODO: Attach resulting type to the descriptor so that you
237-- never have to do extra work, particularly nice for aliased types
238toSrcType :: Variable -> IO T.Canonical
240 do takenNames <- State.execStateT (getVarNames variable) Map.empty
241 State.evalStateT (variableToSrcType variable) (makeNameState takenNames)
244variableToSrcType :: Variable -> StateT NameState IO T.Canonical
245variableToSrcType variable =
246 do descriptor <- liftIO $ UF.descriptor variable
247 let mark = _mark descriptor
248 if mark == occursMark
253 do liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = occursMark })
254 srcType <- contentToSrcType variable (_content descriptor)
255 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = mark })
259contentToSrcType :: Variable -> Content -> StateT NameState IO T.Canonical
260contentToSrcType variable content =
265 Var _ _ (Just name) ->
268 Var flex maybeSuper Nothing ->
269 do freshName <- getFreshName maybeSuper
270 liftIO $ UF.modifyDescriptor variable $ \desc ->
271 desc { _content = Var flex maybeSuper (Just freshName) }
272 return (T.Var freshName)
274 Alias name args realVariable ->
275 do srcArgs <- traverse (traverse variableToSrcType) args
276 srcType <- variableToSrcType realVariable
277 return (T.Aliased name srcArgs (T.Filled srcType))
283termToSrcType :: FlatType -> StateT NameState IO T.Canonical
287 T.Type name <$> traverse variableToSrcType args
291 <$> variableToSrcType a
292 <*> variableToSrcType b
295 return $ T.Record [] Nothing
297 Record1 fields extension ->
298 do srcFields <- Map.toList <$> traverse variableToSrcType fields
299 srcExt <- T.iteratedDealias <$> variableToSrcType extension
302 T.Record subFields subExt ->
303 T.Record (subFields ++ srcFields) subExt
306 T.Record srcFields (Just srcExt)
309 error "Used toSrcType on a type that is not well-formed"
313-- MANAGE FRESH VARIABLE NAMES
318 { _taken :: TakenNames
321 , _comparables :: Int
322 , _appendables :: Int
323 , _compAppends :: Int
327type TakenNames = Map.Map Text Variable
330makeNameState :: TakenNames -> NameState
332 NameState taken 0 0 0 0 0
335getFreshName :: (Monad m) => Maybe Super -> StateT NameState m Text
336getFreshName maybeSuper =
339 do index <- State.gets _normals
340 taken <- State.gets _taken
341 let (uniqueName, newIndex) = getFreshNormal index taken
342 State.modify (\state -> state { _normals = newIndex })
346 getFreshSuper "number" _numbers (\index state -> state { _numbers = index })
349 getFreshSuper "comparable" _comparables (\index state -> state { _comparables = index })
352 getFreshSuper "appendable" _appendables (\index state -> state { _appendables = index })
355 getFreshSuper "compappend" _compAppends (\index state -> state { _compAppends = index })
358getFreshNormal :: Int -> TakenNames -> (Text, Int)
359getFreshNormal index taken =
365 Char.chr (97 + letter)
368 Text.pack (if postfix <= 0 then [character] else character : show postfix)
370 if Map.member name taken then
371 getFreshNormal (index + 1) taken
380 -> (NameState -> Int)
381 -> (Int -> NameState -> NameState)
382 -> StateT NameState m Text
383getFreshSuper name getter setter =
384 do index <- State.gets getter
385 taken <- State.gets _taken
386 let (uniqueName, newIndex) = getFreshSuperHelp name index taken
387 State.modify (setter newIndex)
391getFreshSuperHelp :: Text -> Int -> TakenNames -> (Text, Int)
392getFreshSuperHelp name index taken =
395 if index <= 0 then name else name <> Text.pack (show index)
397 if Map.member newName taken then
398 getFreshSuperHelp name (index + 1) taken
405-- GET ALL VARIABLE NAMES
408getVarNames :: Variable -> StateT TakenNames IO ()
410 do desc <- liftIO $ UF.descriptor var
411 case _mark desc == getVarNamesMark of
416 do liftIO $ UF.setDescriptor var (desc { _mark = getVarNamesMark })
417 case _content desc of
424 Var flex maybeSuper (Just name) ->
425 do oldTaken <- State.get
426 newTaken <- liftIO $ addVarName 0 name var flex maybeSuper oldTaken
429 Alias _ args realVar ->
430 do mapM_ (getVarNames . snd) args
433 Structure (App1 _ args) ->
434 mapM_ getVarNames args
436 Structure (Fun1 arg body) ->
440 Structure EmptyRecord1 ->
443 Structure (Record1 fields extension) ->
444 do mapM_ getVarNames fields
445 getVarNames extension
448addVarName :: Int -> Text -> Variable -> Flex -> Maybe Super -> TakenNames -> IO TakenNames
449addVarName index givenName var flex maybeSuper taken =
452 makeIndexedName givenName index
454 case Map.lookup name taken of
456 do when (name /= givenName) $ UF.modifyDescriptor var $ \desc ->
457 desc { _content = Var flex maybeSuper (Just name) }
458 return $ Map.insert name var taken
461 do same <- UF.equivalent var otherVar
464 else addVarName (index + 1) givenName var flex maybeSuper taken
467makeIndexedName :: Text -> Int -> Text
468makeIndexedName name index =
472 else if Char.isDigit (Text.last name) then
473 name <> Text.pack ('_' : show index)
476 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