1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
7 , Descriptor(Descriptor)
16 , int, float, char, string, bool, never
17 , vec2, vec3, vec4, mat4, texture
30import Control.Monad.State.Strict (StateT, liftIO)
31import qualified Control.Monad.State.Strict as State
32import qualified Data.Char as Char
33import Data.Foldable (foldrM)
34import qualified Data.Map.Strict as Map
35import Data.Monoid ((<>))
36import qualified Data.Text as Text
37import Data.Text (Text)
38import Data.Word (Word32)
40import qualified AST.Canonical as Can
41import qualified AST.Module.Name as ModuleName
42import qualified AST.Utils.Type as Type
43import qualified Elm.Name as N
44import qualified Type.UnionFind as UF
56 = App1 ModuleName.Canonical N.Name [Variable]
57 | Fun1 Variable Variable
59 | Record1 (Map.Map N.Name Variable) Variable
61 | Tuple1 Variable Variable (Maybe Variable)
66 | AliasN ModuleName.Canonical N.Name [(N.Name, Type)] Type
68 | AppN ModuleName.Canonical N.Name [Type]
71 | RecordN (Map.Map N.Name Type) Type
73 | TupleN Type Type (Maybe Type)
85 , _copy :: Maybe Variable
90 = FlexVar (Maybe N.Name)
91 | FlexSuper SuperType (Maybe N.Name)
93 | RigidSuper SuperType N.Name
95 | Alias ModuleName.Canonical N.Name [(N.Name,Variable)] Variable
107makeDescriptor :: Content -> Descriptor
108makeDescriptor content =
109 Descriptor content noRank noMark Nothing
130newtype Mark = Mark Word32
144getVarNamesMark :: Mark
149{-# INLINE nextMark #-}
150nextMark :: Mark -> Mark
151nextMark (Mark mark) =
163(==>) :: Type -> Type -> Type
174int = AppN ModuleName.basics "Int" []
177{-# NOINLINE float #-}
179float = AppN ModuleName.basics "Float" []
184char = AppN ModuleName.char "Char" []
187{-# NOINLINE string #-}
189string = AppN ModuleName.string "String" []
194bool = AppN ModuleName.basics "Bool" []
197{-# NOINLINE never #-}
199never = AppN ModuleName.basics "Never" []
208vec2 = AppN ModuleName.vector2 "Vec2" []
213vec3 = AppN ModuleName.vector3 "Vec3" []
218vec4 = AppN ModuleName.vector4 "Vec4" []
223mat4 = AppN ModuleName.matrix4 "Mat4" []
226{-# NOINLINE texture #-}
228texture = AppN ModuleName.webgl "Texture" []
232-- MAKE FLEX VARIABLES
235mkFlexVar :: IO Variable
237 UF.fresh flexVarDescriptor
240{-# NOINLINE flexVarDescriptor #-}
241flexVarDescriptor :: Descriptor
243 makeDescriptor unnamedFlexVar
246{-# NOINLINE unnamedFlexVar #-}
247unnamedFlexVar :: Content
256mkFlexNumber :: IO Variable
258 UF.fresh flexNumberDescriptor
261{-# NOINLINE flexNumberDescriptor #-}
262flexNumberDescriptor :: Descriptor
263flexNumberDescriptor =
264 makeDescriptor (unnamedFlexSuper Number)
267unnamedFlexSuper :: SuperType -> Content
268unnamedFlexSuper super =
269 FlexSuper super Nothing
273-- MAKE NAMED VARIABLES
276nameToFlex :: N.Name -> IO Variable
278 UF.fresh $ makeDescriptor $
279 maybe FlexVar FlexSuper (toSuper name) (Just name)
282nameToRigid :: N.Name -> IO Variable
284 UF.fresh $ makeDescriptor $
285 maybe RigidVar RigidSuper (toSuper name) name
288toSuper :: N.Name -> Maybe SuperType
290 if Text.isPrefixOf "number" name then
293 else if Text.isPrefixOf "comparable" name then
296 else if Text.isPrefixOf "appendable" name then
299 else if Text.isPrefixOf "compappend" name then
310-- TODO: Attach resulting type to the descriptor so that you
311-- never have to do extra work, particularly nice for aliased types
312toAnnotation :: Variable -> IO Can.Annotation
313toAnnotation variable =
314 do userNames <- getVarNames variable Map.empty
315 (tipe, NameState allNames _ _ _ _ _) <-
316 State.runStateT (variableToSrcType variable) (makeNameState userNames)
317 return $ Can.Forall (Map.map (\_ -> ()) allNames) tipe
320toSrcType :: Variable -> IO Can.Type
322 do userNames <- getVarNames variable Map.empty
323 State.evalStateT (variableToSrcType variable) (makeNameState userNames)
326variableToSrcType :: Variable -> StateT NameState IO Can.Type
327variableToSrcType variable =
328 do descriptor <- liftIO $ UF.get variable
329 let mark = _mark descriptor
330 if mark == occursMark
332 return (Can.TVar "∞")
335 do liftIO $ UF.modify variable (\desc -> desc { _mark = occursMark })
336 srcType <- contentToSrcType variable (_content descriptor)
337 liftIO $ UF.modify variable (\desc -> desc { _mark = mark })
341contentToSrcType :: Variable -> Content -> StateT NameState IO Can.Type
342contentToSrcType variable content =
350 return (Can.TVar name)
353 do name <- getFreshVarName
354 liftIO $ UF.modify variable (\desc -> desc { _content = FlexVar (Just name) })
355 return (Can.TVar name)
357 FlexSuper super maybeName ->
360 return (Can.TVar name)
363 do name <- getFreshSuperName super
364 liftIO $ UF.modify variable (\desc -> desc { _content = FlexSuper super (Just name) })
365 return (Can.TVar name)
368 return (Can.TVar name)
371 return (Can.TVar name)
373 Alias home name args realVariable ->
374 do srcArgs <- traverse (traverse variableToSrcType) args
375 srcType <- variableToSrcType realVariable
376 return (Can.TAlias home name srcArgs (Can.Filled srcType))
379 return (Can.TVar name)
382termToSrcType :: FlatType -> StateT NameState IO Can.Type
385 App1 home name args ->
386 Can.TType home name <$> traverse variableToSrcType args
390 <$> variableToSrcType a
391 <*> variableToSrcType b
394 return $ Can.TRecord Map.empty Nothing
396 Record1 fields extension ->
397 do srcFields <- traverse variableToSrcType fields
398 srcExt <- Type.iteratedDealias <$> variableToSrcType extension
401 Can.TRecord subFields subExt ->
402 Can.TRecord (Map.union subFields srcFields) subExt
405 Can.TRecord srcFields (Just srcExt)
408 error "Used toSrcType on a type that is not well-formed"
415 <$> variableToSrcType a
416 <*> variableToSrcType b
417 <*> traverse variableToSrcType maybeC
421-- MANAGE FRESH VARIABLE NAMES
426 { _taken :: TakenNames
429 , _comparables :: Int
430 , _appendables :: Int
431 , _compAppends :: Int
435type TakenNames = Map.Map N.Name Variable
438makeNameState :: TakenNames -> NameState
440 NameState taken 0 0 0 0 0
443getFreshVarName :: (Monad m) => StateT NameState m N.Name
445 do index <- State.gets _normals
446 taken <- State.gets _taken
447 let (uniqueName, newIndex) = getFreshNormal index taken
448 State.modify (\state -> state { _normals = newIndex })
452getFreshSuperName :: (Monad m) => SuperType -> StateT NameState m N.Name
453getFreshSuperName super =
456 getFreshSuper "number" _numbers (\index state -> state { _numbers = index })
459 getFreshSuper "comparable" _comparables (\index state -> state { _comparables = index })
462 getFreshSuper "appendable" _appendables (\index state -> state { _appendables = index })
465 getFreshSuper "compappend" _compAppends (\index state -> state { _compAppends = index })
468getFreshNormal :: Int -> TakenNames -> (N.Name, Int)
469getFreshNormal index taken =
475 Char.chr (97 + letter)
478 Text.pack (if postfix <= 0 then [character] else character : show postfix)
480 if Map.member name taken then
481 getFreshNormal (index + 1) taken
490 -> (NameState -> Int)
491 -> (Int -> NameState -> NameState)
492 -> StateT NameState m N.Name
493getFreshSuper name getter setter =
494 do index <- State.gets getter
495 taken <- State.gets _taken
496 let (uniqueName, newIndex) = getFreshSuperHelp name index taken
497 State.modify (setter newIndex)
501getFreshSuperHelp :: N.Name -> Int -> TakenNames -> (N.Name, Int)
502getFreshSuperHelp name index taken =
505 if index <= 0 then name else name <> Text.pack (show index)
507 if Map.member newName taken then
508 getFreshSuperHelp name (index + 1) taken
515-- GET ALL VARIABLE NAMES
518getVarNames :: Variable -> TakenNames -> IO TakenNames
519getVarNames var takenNames =
520 do (Descriptor content rank mark copy) <- UF.get var
521 if mark == getVarNamesMark
522 then return takenNames
524 do UF.set var (Descriptor content rank getVarNamesMark copy)
535 addName 0 name var (FlexVar . Just) takenNames
537 FlexSuper super maybeName ->
543 addName 0 name var (FlexSuper super . Just) takenNames
546 addName 0 name var RigidVar takenNames
548 RigidSuper super name ->
549 addName 0 name var (RigidSuper super) takenNames
552 foldrM getVarNames takenNames (map snd args)
554 Structure flatType ->
557 foldrM getVarNames takenNames args
560 getVarNames arg =<< getVarNames body takenNames
565 Record1 fields extension ->
566 getVarNames extension =<<
567 foldrM getVarNames takenNames (Map.elems fields)
572 Tuple1 a b Nothing ->
573 getVarNames a =<< getVarNames b takenNames
575 Tuple1 a b (Just c) ->
576 getVarNames a =<< getVarNames b =<< getVarNames c takenNames
580-- REGISTER NAME / RENAME DUPLICATES
583addName :: Int -> N.Name -> Variable -> (N.Name -> Content) -> TakenNames -> IO TakenNames
584addName index givenName var makeContent takenNames =
589 else if Char.isDigit (Text.last givenName) then
590 givenName <> Text.pack ('_' : show index)
592 givenName <> Text.pack (show index)
594 case Map.lookup indexedName takenNames of
596 do if indexedName == givenName then return () else
597 UF.modify var $ \(Descriptor _ rank mark copy) ->
598 Descriptor (makeContent indexedName) rank mark copy
599 return $ Map.insert indexedName var takenNames
602 do same <- UF.equivalent var otherVar
604 then return takenNames
605 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