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 Data.Foldable (foldrM)
29import qualified Data.Map.Strict as Map
30import Data.Monoid ((<>))
31import qualified Data.Text as Text
32import Data.Text (Text)
33import Data.Word (Word32)
35import qualified AST.Module.Name as ModuleName
36import qualified AST.Type as T
37import qualified Elm.Name as N
38import qualified Type.UnionFind as UF
50 = App1 ModuleName.Canonical N.Name [Variable]
51 | Fun1 Variable Variable
53 | Record1 (Map.Map N.Name Variable) Variable
55 | Tuple1 Variable Variable (Maybe Variable)
60 | AliasN ModuleName.Canonical N.Name [(N.Name, Type)] Type
62 | AppN ModuleName.Canonical N.Name [Type]
65 | RecordN (Map.Map N.Name Type) Type
67 | TupleN Type Type (Maybe Type)
79 , _copy :: Maybe Variable
84 = FlexVar (Maybe N.Name)
85 | FlexSuper T.Super (Maybe N.Name)
87 | RigidSuper T.Super N.Name
89 | Alias ModuleName.Canonical N.Name [(N.Name,Variable)] Variable
93makeDescriptor :: Content -> Descriptor
94makeDescriptor content =
95 Descriptor content noRank noMark Nothing
116newtype Mark = Mark Word32
130getVarNamesMark :: Mark
135{-# INLINE nextMark #-}
136nextMark :: Mark -> Mark
137nextMark (Mark mark) =
149(==>) :: Type -> Type -> Type
154{-# NOINLINE float #-}
157 AppN ModuleName.basics "Float" []
163 AppN ModuleName.basics "Char" []
166{-# NOINLINE string #-}
169 AppN ModuleName.basics "String" []
175 AppN ModuleName.basics "Bool" []
179-- MAKE FLEX VARIABLES
182mkFlexVar :: IO Variable
184 UF.fresh flexVarDescriptor
187{-# NOINLINE flexVarDescriptor #-}
188flexVarDescriptor :: Descriptor
190 makeDescriptor unnamedFlexVar
193{-# NOINLINE unnamedFlexVar #-}
194unnamedFlexVar :: Content
203mkFlexNumber :: IO Variable
205 UF.fresh flexNumberDescriptor
208{-# NOINLINE flexNumberDescriptor #-}
209flexNumberDescriptor :: Descriptor
210flexNumberDescriptor =
211 makeDescriptor (unnamedFlexSuper T.Number)
214unnamedFlexSuper :: T.Super -> Content
215unnamedFlexSuper super =
216 FlexSuper super Nothing
220-- MAKE NAMED VARIABLES
223nameToFlex :: N.Name -> IO Variable
225 UF.fresh $ makeDescriptor $
226 maybe FlexVar FlexSuper (toSuper name) (Just name)
229nameToRigid :: N.Name -> IO Variable
231 UF.fresh $ makeDescriptor $
232 maybe RigidVar RigidSuper (toSuper name) name
235toSuper :: N.Name -> Maybe T.Super
237 if Text.isPrefixOf "number" name then
240 else if Text.isPrefixOf "comparable" name then
243 else if Text.isPrefixOf "appendable" name then
246 else if Text.isPrefixOf "compappend" name then
257-- TODO: Attach resulting type to the descriptor so that you
258-- never have to do extra work, particularly nice for aliased types
259toSrcType :: Variable -> IO T.Canonical
261 do takenNames <- getVarNames variable Map.empty
262 State.evalStateT (variableToSrcType variable) (makeNameState takenNames)
265variableToSrcType :: Variable -> StateT NameState IO T.Canonical
266variableToSrcType variable =
267 do descriptor <- liftIO $ UF.descriptor variable
268 let mark = _mark descriptor
269 if mark == occursMark
274 do liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = occursMark })
275 srcType <- contentToSrcType variable (_content descriptor)
276 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = mark })
280contentToSrcType :: Variable -> Content -> StateT NameState IO T.Canonical
281contentToSrcType variable content =
292 do name <- getFreshVarName
293 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _content = FlexVar (Just name) })
296 FlexSuper super maybeName ->
302 do name <- getFreshSuperName super
303 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _content = FlexSuper super (Just name) })
312 Alias home name args realVariable ->
313 do srcArgs <- traverse (traverse variableToSrcType) args
314 srcType <- variableToSrcType realVariable
315 return (T.Aliased home name srcArgs (T.Filled srcType))
321termToSrcType :: FlatType -> StateT NameState IO T.Canonical
324 App1 home name args ->
325 T.Type home name <$> traverse variableToSrcType args
329 <$> variableToSrcType a
330 <*> variableToSrcType b
333 return $ T.Record Map.empty Nothing
335 Record1 fields extension ->
336 do srcFields <- traverse variableToSrcType fields
337 srcExt <- T.iteratedDealias <$> variableToSrcType extension
340 T.Record subFields subExt ->
341 T.Record (Map.union subFields srcFields) subExt
344 T.Record srcFields (Just srcExt)
347 error "Used toSrcType on a type that is not well-formed"
354 <$> variableToSrcType a
355 <*> variableToSrcType b
356 <*> traverse variableToSrcType maybeC
360-- MANAGE FRESH VARIABLE NAMES
365 { _taken :: TakenNames
368 , _comparables :: Int
369 , _appendables :: Int
370 , _compAppends :: Int
374type TakenNames = Map.Map Text Variable
377makeNameState :: TakenNames -> NameState
379 NameState taken 0 0 0 0 0
382getFreshVarName :: (Monad m) => StateT NameState m Text
384 do index <- State.gets _normals
385 taken <- State.gets _taken
386 let (uniqueName, newIndex) = getFreshNormal index taken
387 State.modify (\state -> state { _normals = newIndex })
391getFreshSuperName :: (Monad m) => T.Super -> StateT NameState m Text
392getFreshSuperName super =
395 getFreshSuper "number" _numbers (\index state -> state { _numbers = index })
398 getFreshSuper "comparable" _comparables (\index state -> state { _comparables = index })
401 getFreshSuper "appendable" _appendables (\index state -> state { _appendables = index })
404 getFreshSuper "compappend" _compAppends (\index state -> state { _compAppends = index })
407getFreshNormal :: Int -> TakenNames -> (Text, Int)
408getFreshNormal index taken =
414 Char.chr (97 + letter)
417 Text.pack (if postfix <= 0 then [character] else character : show postfix)
419 if Map.member name taken then
420 getFreshNormal (index + 1) taken
429 -> (NameState -> Int)
430 -> (Int -> NameState -> NameState)
431 -> StateT NameState m Text
432getFreshSuper name getter setter =
433 do index <- State.gets getter
434 taken <- State.gets _taken
435 let (uniqueName, newIndex) = getFreshSuperHelp name index taken
436 State.modify (setter newIndex)
440getFreshSuperHelp :: Text -> Int -> TakenNames -> (Text, Int)
441getFreshSuperHelp name index taken =
444 if index <= 0 then name else name <> Text.pack (show index)
446 if Map.member newName taken then
447 getFreshSuperHelp name (index + 1) taken
454-- GET ALL VARIABLE NAMES
457getVarNames :: Variable -> TakenNames -> IO TakenNames
458getVarNames var takenNames =
459 do (Descriptor content rank mark copy) <- UF.descriptor var
460 if mark == getVarNamesMark
461 then return takenNames
463 do UF.setDescriptor var (Descriptor content rank getVarNamesMark copy)
474 addName 0 name var (FlexVar . Just) takenNames
476 FlexSuper super maybeName ->
482 addName 0 name var (FlexSuper super . Just) takenNames
485 addName 0 name var RigidVar takenNames
487 RigidSuper super name ->
488 addName 0 name var (RigidSuper super) takenNames
491 foldrM getVarNames takenNames (map snd args)
493 Structure flatType ->
496 foldrM getVarNames takenNames args
499 getVarNames arg =<< getVarNames body takenNames
504 Record1 fields extension ->
505 getVarNames extension =<<
506 foldrM getVarNames takenNames (Map.elems fields)
511 Tuple1 a b Nothing ->
512 getVarNames a =<< getVarNames b takenNames
514 Tuple1 a b (Just c) ->
515 getVarNames a =<< getVarNames b =<< getVarNames c takenNames
519-- REGISTER NAME / RENAME DUPLICATES
522addName :: Int -> N.Name -> Variable -> (N.Name -> Content) -> TakenNames -> IO TakenNames
523addName index givenName var makeContent takenNames =
528 else if Char.isDigit (Text.last givenName) then
529 givenName <> Text.pack ('_' : show index)
531 givenName <> Text.pack (show index)
533 case Map.lookup indexedName takenNames of
535 do if indexedName == givenName then return () else
536 UF.modifyDescriptor var $ \(Descriptor _ rank mark copy) ->
537 Descriptor (makeContent indexedName) rank mark copy
538 return $ Map.insert indexedName var takenNames
541 do same <- UF.equivalent var otherVar
543 then return takenNames
544 else addName (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