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 qualified Data.Text as Text
36import Data.Word (Word32)
38import qualified AST.Canonical as Can
39import qualified AST.Module.Name as ModuleName
40import qualified AST.Utils.Type as Type
41import qualified Elm.Name as N
42import qualified Type.UnionFind as UF
54 = App1 ModuleName.Canonical N.Name [Variable]
55 | Fun1 Variable Variable
57 | Record1 (Map.Map N.Name Variable) Variable
59 | Tuple1 Variable Variable (Maybe Variable)
64 | AliasN ModuleName.Canonical N.Name [(N.Name, Type)] Type
66 | AppN ModuleName.Canonical N.Name [Type]
69 | RecordN (Map.Map N.Name Type) Type
71 | TupleN Type Type (Maybe Type)
83 , _copy :: Maybe Variable
88 = FlexVar (Maybe N.Name)
89 | FlexSuper SuperType (Maybe N.Name)
91 | RigidSuper SuperType N.Name
93 | Alias ModuleName.Canonical N.Name [(N.Name,Variable)] Variable
105makeDescriptor :: Content -> Descriptor
106makeDescriptor content =
107 Descriptor content noRank noMark Nothing
128newtype Mark = Mark Word32
142getVarNamesMark :: Mark
147{-# INLINE nextMark #-}
148nextMark :: Mark -> Mark
149nextMark (Mark mark) =
161(==>) :: Type -> Type -> Type
172int = AppN ModuleName.basics "Int" []
175{-# NOINLINE float #-}
177float = AppN ModuleName.basics "Float" []
182char = AppN ModuleName.char "Char" []
185{-# NOINLINE string #-}
187string = AppN ModuleName.string "String" []
192bool = AppN ModuleName.basics "Bool" []
195{-# NOINLINE never #-}
197never = AppN ModuleName.basics "Never" []
206vec2 = AppN ModuleName.vector2 "Vec2" []
211vec3 = AppN ModuleName.vector3 "Vec3" []
216vec4 = AppN ModuleName.vector4 "Vec4" []
221mat4 = AppN ModuleName.matrix4 "Mat4" []
224{-# NOINLINE texture #-}
226texture = AppN ModuleName.webgl "Texture" []
230-- MAKE FLEX VARIABLES
233mkFlexVar :: IO Variable
235 UF.fresh flexVarDescriptor
238{-# NOINLINE flexVarDescriptor #-}
239flexVarDescriptor :: Descriptor
241 makeDescriptor unnamedFlexVar
244{-# NOINLINE unnamedFlexVar #-}
245unnamedFlexVar :: Content
254mkFlexNumber :: IO Variable
256 UF.fresh flexNumberDescriptor
259{-# NOINLINE flexNumberDescriptor #-}
260flexNumberDescriptor :: Descriptor
261flexNumberDescriptor =
262 makeDescriptor (unnamedFlexSuper Number)
265unnamedFlexSuper :: SuperType -> Content
266unnamedFlexSuper super =
267 FlexSuper super Nothing
271-- MAKE NAMED VARIABLES
274nameToFlex :: N.Name -> IO Variable
276 UF.fresh $ makeDescriptor $
277 maybe FlexVar FlexSuper (toSuper name) (Just name)
280nameToRigid :: N.Name -> IO Variable
282 UF.fresh $ makeDescriptor $
283 maybe RigidVar RigidSuper (toSuper name) name
286toSuper :: N.Name -> Maybe SuperType
288 if N.startsWith "number" name then
291 else if N.startsWith "comparable" name then
294 else if N.startsWith "appendable" name then
297 else if N.startsWith "compappend" name then
308-- TODO: Attach resulting type to the descriptor so that you
309-- never have to do extra work, particularly nice for aliased types
310toAnnotation :: Variable -> IO Can.Annotation
311toAnnotation variable =
312 do userNames <- getVarNames variable Map.empty
313 (tipe, NameState allNames _ _ _ _ _) <-
314 State.runStateT (variableToSrcType variable) (makeNameState userNames)
315 return $ Can.Forall (Map.map (\_ -> ()) allNames) tipe
318toSrcType :: Variable -> IO Can.Type
320 do userNames <- getVarNames variable Map.empty
321 State.evalStateT (variableToSrcType variable) (makeNameState userNames)
324variableToSrcType :: Variable -> StateT NameState IO Can.Type
325variableToSrcType variable =
326 do descriptor <- liftIO $ UF.get variable
327 let mark = _mark descriptor
328 if mark == occursMark
330 return (Can.TVar "∞")
333 do liftIO $ UF.modify variable (\desc -> desc { _mark = occursMark })
334 srcType <- contentToSrcType variable (_content descriptor)
335 liftIO $ UF.modify variable (\desc -> desc { _mark = mark })
339contentToSrcType :: Variable -> Content -> StateT NameState IO Can.Type
340contentToSrcType variable content =
348 return (Can.TVar name)
351 do name <- getFreshVarName
352 liftIO $ UF.modify variable (\desc -> desc { _content = FlexVar (Just name) })
353 return (Can.TVar name)
355 FlexSuper super maybeName ->
358 return (Can.TVar name)
361 do name <- getFreshSuperName super
362 liftIO $ UF.modify variable (\desc -> desc { _content = FlexSuper super (Just name) })
363 return (Can.TVar name)
366 return (Can.TVar name)
369 return (Can.TVar name)
371 Alias home name args realVariable ->
372 do srcArgs <- traverse (traverse variableToSrcType) args
373 srcType <- variableToSrcType realVariable
374 return (Can.TAlias home name srcArgs (Can.Filled srcType))
377 return (Can.TVar name)
380termToSrcType :: FlatType -> StateT NameState IO Can.Type
383 App1 home name args ->
384 Can.TType home name <$> traverse variableToSrcType args
388 <$> variableToSrcType a
389 <*> variableToSrcType b
392 return $ Can.TRecord Map.empty Nothing
394 Record1 fields extension ->
395 do srcFields <- traverse variableToSrcType fields
396 srcExt <- Type.iteratedDealias <$> variableToSrcType extension
399 Can.TRecord subFields subExt ->
400 Can.TRecord (Map.union subFields srcFields) subExt
403 Can.TRecord srcFields (Just srcExt)
406 error "Used toSrcType on a type that is not well-formed"
413 <$> variableToSrcType a
414 <*> variableToSrcType b
415 <*> traverse variableToSrcType maybeC
419-- MANAGE FRESH VARIABLE NAMES
424 { _taken :: TakenNames
427 , _comparables :: Int
428 , _appendables :: Int
429 , _compAppends :: Int
433type TakenNames = Map.Map N.Name Variable
436makeNameState :: TakenNames -> NameState
438 NameState taken 0 0 0 0 0
441getFreshVarName :: (Monad m) => StateT NameState m N.Name
443 do index <- State.gets _normals
444 taken <- State.gets _taken
445 let (uniqueName, newIndex) = getFreshNormal index taken
446 State.modify (\state -> state { _normals = newIndex })
450getFreshSuperName :: (Monad m) => SuperType -> StateT NameState m N.Name
451getFreshSuperName super =
454 getFreshSuper "number" _numbers (\index state -> state { _numbers = index })
457 getFreshSuper "comparable" _comparables (\index state -> state { _comparables = index })
460 getFreshSuper "appendable" _appendables (\index state -> state { _appendables = index })
463 getFreshSuper "compappend" _compAppends (\index state -> state { _compAppends = index })
466getFreshNormal :: Int -> TakenNames -> (N.Name, Int)
467getFreshNormal index taken =
473 Char.chr (97 + letter)
476 Text.pack (if postfix <= 0 then [character] else character : show postfix)
478 if Map.member name taken then
479 getFreshNormal (index + 1) taken
488 -> (NameState -> Int)
489 -> (Int -> NameState -> NameState)
490 -> StateT NameState m N.Name
491getFreshSuper name getter setter =
492 do index <- State.gets getter
493 taken <- State.gets _taken
494 let (uniqueName, newIndex) = getFreshSuperHelp name index taken
495 State.modify (setter newIndex)
499getFreshSuperHelp :: N.Name -> Int -> TakenNames -> (N.Name, Int)
500getFreshSuperHelp name index taken =
503 if index <= 0 then name else N.addIndex name index
505 if Map.member newName taken then
506 getFreshSuperHelp name (index + 1) taken
513-- GET ALL VARIABLE NAMES
516getVarNames :: Variable -> TakenNames -> IO TakenNames
517getVarNames var takenNames =
518 do (Descriptor content rank mark copy) <- UF.get var
519 if mark == getVarNamesMark
520 then return takenNames
522 do UF.set var (Descriptor content rank getVarNamesMark copy)
533 addName 0 name var (FlexVar . Just) takenNames
535 FlexSuper super maybeName ->
541 addName 0 name var (FlexSuper super . Just) takenNames
544 addName 0 name var RigidVar takenNames
546 RigidSuper super name ->
547 addName 0 name var (RigidSuper super) takenNames
550 foldrM getVarNames takenNames (map snd args)
552 Structure flatType ->
555 foldrM getVarNames takenNames args
558 getVarNames arg =<< getVarNames body takenNames
563 Record1 fields extension ->
564 getVarNames extension =<<
565 foldrM getVarNames takenNames (Map.elems fields)
570 Tuple1 a b Nothing ->
571 getVarNames a =<< getVarNames b takenNames
573 Tuple1 a b (Just c) ->
574 getVarNames a =<< getVarNames b =<< getVarNames c takenNames
578-- REGISTER NAME / RENAME DUPLICATES
581addName :: Int -> N.Name -> Variable -> (N.Name -> Content) -> TakenNames -> IO TakenNames
582addName index givenName var makeContent takenNames =
588 N.addSafeIndex givenName index
590 case Map.lookup indexedName takenNames of
592 do if indexedName == givenName then return () else
593 UF.modify var $ \(Descriptor _ rank mark copy) ->
594 Descriptor (makeContent indexedName) rank mark copy
595 return $ Map.insert indexedName var takenNames
598 do same <- UF.equivalent var otherVar
600 then return takenNames
601 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