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 Data.Foldable (foldrM)
33import qualified Data.Map.Strict as Map
34import Data.Word (Word32)
36import qualified AST.Canonical as Can
37import qualified AST.Module.Name as ModuleName
38import qualified AST.Utils.Type as Type
39import qualified Elm.Name as N
40import qualified Type.UnionFind as UF
52 = App1 ModuleName.Canonical N.Name [Variable]
53 | Fun1 Variable Variable
55 | Record1 (Map.Map N.Name Variable) Variable
57 | Tuple1 Variable Variable (Maybe Variable)
62 | AliasN ModuleName.Canonical N.Name [(N.Name, Type)] Type
64 | AppN ModuleName.Canonical N.Name [Type]
67 | RecordN (Map.Map N.Name Type) Type
69 | TupleN Type Type (Maybe Type)
81 , _copy :: Maybe Variable
86 = FlexVar (Maybe N.Name)
87 | FlexSuper SuperType (Maybe N.Name)
89 | RigidSuper SuperType N.Name
91 | Alias ModuleName.Canonical N.Name [(N.Name,Variable)] Variable
103makeDescriptor :: Content -> Descriptor
104makeDescriptor content =
105 Descriptor content noRank noMark Nothing
126newtype Mark = Mark Word32
140getVarNamesMark :: Mark
145{-# INLINE nextMark #-}
146nextMark :: Mark -> Mark
147nextMark (Mark mark) =
159(==>) :: Type -> Type -> Type
170int = AppN ModuleName.basics "Int" []
173{-# NOINLINE float #-}
175float = AppN ModuleName.basics "Float" []
180char = AppN ModuleName.char "Char" []
183{-# NOINLINE string #-}
185string = AppN ModuleName.string "String" []
190bool = AppN ModuleName.basics "Bool" []
193{-# NOINLINE never #-}
195never = AppN ModuleName.basics "Never" []
204vec2 = AppN ModuleName.vector2 "Vec2" []
209vec3 = AppN ModuleName.vector3 "Vec3" []
214vec4 = AppN ModuleName.vector4 "Vec4" []
219mat4 = AppN ModuleName.matrix4 "Mat4" []
222{-# NOINLINE texture #-}
224texture = AppN ModuleName.webgl "Texture" []
228-- MAKE FLEX VARIABLES
231mkFlexVar :: IO Variable
233 UF.fresh flexVarDescriptor
236{-# NOINLINE flexVarDescriptor #-}
237flexVarDescriptor :: Descriptor
239 makeDescriptor unnamedFlexVar
242{-# NOINLINE unnamedFlexVar #-}
243unnamedFlexVar :: Content
252mkFlexNumber :: IO Variable
254 UF.fresh flexNumberDescriptor
257{-# NOINLINE flexNumberDescriptor #-}
258flexNumberDescriptor :: Descriptor
259flexNumberDescriptor =
260 makeDescriptor (unnamedFlexSuper Number)
263unnamedFlexSuper :: SuperType -> Content
264unnamedFlexSuper super =
265 FlexSuper super Nothing
269-- MAKE NAMED VARIABLES
272nameToFlex :: N.Name -> IO Variable
274 UF.fresh $ makeDescriptor $
275 maybe FlexVar FlexSuper (toSuper name) (Just name)
278nameToRigid :: N.Name -> IO Variable
280 UF.fresh $ makeDescriptor $
281 maybe RigidVar RigidSuper (toSuper name) name
284toSuper :: N.Name -> Maybe SuperType
286 if N.startsWith "number" name then
289 else if N.startsWith "comparable" name then
292 else if N.startsWith "appendable" name then
295 else if N.startsWith "compappend" name then
306-- TODO: Attach resulting type to the descriptor so that you
307-- never have to do extra work, particularly nice for aliased types
308toAnnotation :: Variable -> IO Can.Annotation
309toAnnotation variable =
310 do userNames <- getVarNames variable Map.empty
311 (tipe, NameState allNames _ _ _ _ _) <-
312 State.runStateT (variableToSrcType variable) (makeNameState userNames)
313 return $ Can.Forall (Map.map (\_ -> ()) allNames) tipe
316toSrcType :: Variable -> IO Can.Type
318 do userNames <- getVarNames variable Map.empty
319 State.evalStateT (variableToSrcType variable) (makeNameState userNames)
322variableToSrcType :: Variable -> StateT NameState IO Can.Type
323variableToSrcType variable =
324 do descriptor <- liftIO $ UF.get variable
325 let mark = _mark descriptor
326 if mark == occursMark
328 return (Can.TVar "∞")
331 do liftIO $ UF.modify variable (\desc -> desc { _mark = occursMark })
332 srcType <- contentToSrcType variable (_content descriptor)
333 liftIO $ UF.modify variable (\desc -> desc { _mark = mark })
337contentToSrcType :: Variable -> Content -> StateT NameState IO Can.Type
338contentToSrcType variable content =
346 return (Can.TVar name)
349 do name <- getFreshVarName
350 liftIO $ UF.modify variable (\desc -> desc { _content = FlexVar (Just name) })
351 return (Can.TVar name)
353 FlexSuper super maybeName ->
356 return (Can.TVar name)
359 do name <- getFreshSuperName super
360 liftIO $ UF.modify variable (\desc -> desc { _content = FlexSuper super (Just name) })
361 return (Can.TVar name)
364 return (Can.TVar name)
367 return (Can.TVar name)
369 Alias home name args realVariable ->
370 do srcArgs <- traverse (traverse variableToSrcType) args
371 srcType <- variableToSrcType realVariable
372 return (Can.TAlias home name srcArgs (Can.Filled srcType))
375 return (Can.TVar name)
378termToSrcType :: FlatType -> StateT NameState IO Can.Type
381 App1 home name args ->
382 Can.TType home name <$> traverse variableToSrcType args
386 <$> variableToSrcType a
387 <*> variableToSrcType b
390 return $ Can.TRecord Map.empty Nothing
392 Record1 fields extension ->
393 do srcFields <- traverse variableToSrcType fields
394 srcExt <- Type.iteratedDealias <$> variableToSrcType extension
397 Can.TRecord subFields subExt ->
398 Can.TRecord (Map.union subFields srcFields) subExt
401 Can.TRecord srcFields (Just srcExt)
404 error "Used toSrcType on a type that is not well-formed"
411 <$> variableToSrcType a
412 <*> variableToSrcType b
413 <*> traverse variableToSrcType maybeC
417-- MANAGE FRESH VARIABLE NAMES
422 { _taken :: TakenNames
425 , _comparables :: Int
426 , _appendables :: Int
427 , _compAppends :: Int
431type TakenNames = Map.Map N.Name Variable
434makeNameState :: TakenNames -> NameState
436 NameState taken 0 0 0 0 0
439getFreshVarName :: (Monad m) => StateT NameState m N.Name
441 do index <- State.gets _normals
442 taken <- State.gets _taken
443 let (uniqueName, newIndex) = getFreshNormal index taken
444 State.modify (\state -> state { _normals = newIndex })
448getFreshSuperName :: (Monad m) => SuperType -> StateT NameState m N.Name
449getFreshSuperName super =
452 getFreshSuper "number" _numbers (\index state -> state { _numbers = index })
455 getFreshSuper "comparable" _comparables (\index state -> state { _comparables = index })
458 getFreshSuper "appendable" _appendables (\index state -> state { _appendables = index })
461 getFreshSuper "compappend" _compAppends (\index state -> state { _compAppends = index })
464getFreshNormal :: Int -> TakenNames -> (N.Name, Int)
465getFreshNormal index taken =
470 chr = N.fromLetter letter
471 name = if postfix <= 0 then chr else N.addIndex chr postfix
473 if Map.member name taken then
474 getFreshNormal (index + 1) taken
483 -> (NameState -> Int)
484 -> (Int -> NameState -> NameState)
485 -> StateT NameState m N.Name
486getFreshSuper name getter setter =
487 do index <- State.gets getter
488 taken <- State.gets _taken
489 let (uniqueName, newIndex) = getFreshSuperHelp name index taken
490 State.modify (setter newIndex)
494getFreshSuperHelp :: N.Name -> Int -> TakenNames -> (N.Name, Int)
495getFreshSuperHelp name index taken =
498 if index <= 0 then name else N.addIndex name index
500 if Map.member newName taken then
501 getFreshSuperHelp name (index + 1) taken
508-- GET ALL VARIABLE NAMES
511getVarNames :: Variable -> TakenNames -> IO TakenNames
512getVarNames var takenNames =
513 do (Descriptor content rank mark copy) <- UF.get var
514 if mark == getVarNamesMark
515 then return takenNames
517 do UF.set var (Descriptor content rank getVarNamesMark copy)
528 addName 0 name var (FlexVar . Just) takenNames
530 FlexSuper super maybeName ->
536 addName 0 name var (FlexSuper super . Just) takenNames
539 addName 0 name var RigidVar takenNames
541 RigidSuper super name ->
542 addName 0 name var (RigidSuper super) takenNames
545 foldrM getVarNames takenNames (map snd args)
547 Structure flatType ->
550 foldrM getVarNames takenNames args
553 getVarNames arg =<< getVarNames body takenNames
558 Record1 fields extension ->
559 getVarNames extension =<<
560 foldrM getVarNames takenNames (Map.elems fields)
565 Tuple1 a b Nothing ->
566 getVarNames a =<< getVarNames b takenNames
568 Tuple1 a b (Just c) ->
569 getVarNames a =<< getVarNames b =<< getVarNames c takenNames
573-- REGISTER NAME / RENAME DUPLICATES
576addName :: Int -> N.Name -> Variable -> (N.Name -> Content) -> TakenNames -> IO TakenNames
577addName index givenName var makeContent takenNames =
583 N.addSafeIndex givenName index
585 case Map.lookup indexedName takenNames of
587 do if indexedName == givenName then return () else
588 UF.modify var $ \(Descriptor _ rank mark copy) ->
589 Descriptor (makeContent indexedName) rank mark copy
590 return $ Map.insert indexedName var takenNames
593 do same <- UF.equivalent var otherVar
595 then return takenNames
596 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