1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
7 , Descriptor(Descriptor)
16 , int, float, char, string, bool, never
17 , vec2, vec3, vec4, mat4, texture
29import Control.Monad.State.Strict (StateT, liftIO)
30import qualified Control.Monad.State.Strict as State
31import qualified Data.Char as Char
32import Data.Foldable (foldrM)
33import qualified Data.Map.Strict as Map
34import Data.Monoid ((<>))
35import qualified Data.Text as Text
36import Data.Text (Text)
37import Data.Word (Word32)
39import qualified AST.Canonical as Can
40import qualified AST.Module.Name as ModuleName
41import qualified AST.Utils.Type as Type
42import qualified Elm.Name as N
43import qualified Type.UnionFind as UF
55 = App1 ModuleName.Canonical N.Name [Variable]
56 | Fun1 Variable Variable
58 | Record1 (Map.Map N.Name Variable) Variable
60 | Tuple1 Variable Variable (Maybe Variable)
65 | AliasN ModuleName.Canonical N.Name [(N.Name, Type)] Type
67 | AppN ModuleName.Canonical N.Name [Type]
70 | RecordN (Map.Map N.Name Type) Type
72 | TupleN Type Type (Maybe Type)
84 , _copy :: Maybe Variable
89 = FlexVar (Maybe N.Name)
90 | FlexSuper SuperType (Maybe N.Name)
92 | RigidSuper SuperType N.Name
94 | Alias ModuleName.Canonical N.Name [(N.Name,Variable)] Variable
106makeDescriptor :: Content -> Descriptor
107makeDescriptor content =
108 Descriptor content noRank noMark Nothing
129newtype Mark = Mark Word32
143getVarNamesMark :: Mark
148{-# INLINE nextMark #-}
149nextMark :: Mark -> Mark
150nextMark (Mark mark) =
162(==>) :: Type -> Type -> Type
173int = AppN ModuleName.basics "Int" []
176{-# NOINLINE float #-}
178float = AppN ModuleName.basics "Float" []
183char = AppN ModuleName.char "Char" []
186{-# NOINLINE string #-}
188string = AppN ModuleName.string "String" []
193bool = AppN ModuleName.basics "Bool" []
196{-# NOINLINE never #-}
198never = AppN ModuleName.basics "Never" []
207vec2 = AppN ModuleName.vector2 "Vec2" []
212vec3 = AppN ModuleName.vector3 "Vec3" []
217vec4 = AppN ModuleName.vector4 "Vec4" []
222mat4 = AppN ModuleName.matrix4 "Mat4" []
225{-# NOINLINE texture #-}
227texture = AppN ModuleName.webgl "Texture" []
231-- MAKE FLEX VARIABLES
234mkFlexVar :: IO Variable
236 UF.fresh flexVarDescriptor
239{-# NOINLINE flexVarDescriptor #-}
240flexVarDescriptor :: Descriptor
242 makeDescriptor unnamedFlexVar
245{-# NOINLINE unnamedFlexVar #-}
246unnamedFlexVar :: Content
255mkFlexNumber :: IO Variable
257 UF.fresh flexNumberDescriptor
260{-# NOINLINE flexNumberDescriptor #-}
261flexNumberDescriptor :: Descriptor
262flexNumberDescriptor =
263 makeDescriptor (unnamedFlexSuper Number)
266unnamedFlexSuper :: SuperType -> Content
267unnamedFlexSuper super =
268 FlexSuper super Nothing
272-- MAKE NAMED VARIABLES
275nameToFlex :: N.Name -> IO Variable
277 UF.fresh $ makeDescriptor $
278 maybe FlexVar FlexSuper (toSuper name) (Just name)
281nameToRigid :: N.Name -> IO Variable
283 UF.fresh $ makeDescriptor $
284 maybe RigidVar RigidSuper (toSuper name) name
287toSuper :: N.Name -> Maybe SuperType
289 if Text.isPrefixOf "number" name then
292 else if Text.isPrefixOf "comparable" name then
295 else if Text.isPrefixOf "appendable" name then
298 else if Text.isPrefixOf "compappend" name then
309-- TODO: Attach resulting type to the descriptor so that you
310-- never have to do extra work, particularly nice for aliased types
311toSrcType :: Variable -> IO Can.Type
313 do takenNames <- getVarNames variable Map.empty
314 State.evalStateT (variableToSrcType variable) (makeNameState takenNames)
317variableToSrcType :: Variable -> StateT NameState IO Can.Type
318variableToSrcType variable =
319 do descriptor <- liftIO $ UF.get variable
320 let mark = _mark descriptor
321 if mark == occursMark
323 return (Can.TVar "∞")
326 do liftIO $ UF.modify variable (\desc -> desc { _mark = occursMark })
327 srcType <- contentToSrcType variable (_content descriptor)
328 liftIO $ UF.modify variable (\desc -> desc { _mark = mark })
332contentToSrcType :: Variable -> Content -> StateT NameState IO Can.Type
333contentToSrcType variable content =
341 return (Can.TVar name)
344 do name <- getFreshVarName
345 liftIO $ UF.modify variable (\desc -> desc { _content = FlexVar (Just name) })
346 return (Can.TVar name)
348 FlexSuper super maybeName ->
351 return (Can.TVar name)
354 do name <- getFreshSuperName super
355 liftIO $ UF.modify variable (\desc -> desc { _content = FlexSuper super (Just name) })
356 return (Can.TVar name)
359 return (Can.TVar name)
362 return (Can.TVar name)
364 Alias home name args realVariable ->
365 do srcArgs <- traverse (traverse variableToSrcType) args
366 srcType <- variableToSrcType realVariable
367 return (Can.TAlias home name srcArgs (Can.Filled srcType))
370 return (Can.TVar name)
373termToSrcType :: FlatType -> StateT NameState IO Can.Type
376 App1 home name args ->
377 Can.TType home name <$> traverse variableToSrcType args
381 <$> variableToSrcType a
382 <*> variableToSrcType b
385 return $ Can.TRecord Map.empty Nothing
387 Record1 fields extension ->
388 do srcFields <- traverse variableToSrcType fields
389 srcExt <- Type.iteratedDealias <$> variableToSrcType extension
392 Can.TRecord subFields subExt ->
393 Can.TRecord (Map.union subFields srcFields) subExt
396 Can.TRecord srcFields (Just srcExt)
399 error "Used toSrcType on a type that is not well-formed"
406 <$> variableToSrcType a
407 <*> variableToSrcType b
408 <*> traverse variableToSrcType maybeC
412-- MANAGE FRESH VARIABLE NAMES
417 { _taken :: TakenNames
420 , _comparables :: Int
421 , _appendables :: Int
422 , _compAppends :: Int
426type TakenNames = Map.Map Text Variable
429makeNameState :: TakenNames -> NameState
431 NameState taken 0 0 0 0 0
434getFreshVarName :: (Monad m) => StateT NameState m Text
436 do index <- State.gets _normals
437 taken <- State.gets _taken
438 let (uniqueName, newIndex) = getFreshNormal index taken
439 State.modify (\state -> state { _normals = newIndex })
443getFreshSuperName :: (Monad m) => SuperType -> StateT NameState m Text
444getFreshSuperName super =
447 getFreshSuper "number" _numbers (\index state -> state { _numbers = index })
450 getFreshSuper "comparable" _comparables (\index state -> state { _comparables = index })
453 getFreshSuper "appendable" _appendables (\index state -> state { _appendables = index })
456 getFreshSuper "compappend" _compAppends (\index state -> state { _compAppends = index })
459getFreshNormal :: Int -> TakenNames -> (Text, Int)
460getFreshNormal index taken =
466 Char.chr (97 + letter)
469 Text.pack (if postfix <= 0 then [character] else character : show postfix)
471 if Map.member name taken then
472 getFreshNormal (index + 1) taken
481 -> (NameState -> Int)
482 -> (Int -> NameState -> NameState)
483 -> StateT NameState m Text
484getFreshSuper name getter setter =
485 do index <- State.gets getter
486 taken <- State.gets _taken
487 let (uniqueName, newIndex) = getFreshSuperHelp name index taken
488 State.modify (setter newIndex)
492getFreshSuperHelp :: Text -> Int -> TakenNames -> (Text, Int)
493getFreshSuperHelp name index taken =
496 if index <= 0 then name else name <> Text.pack (show index)
498 if Map.member newName taken then
499 getFreshSuperHelp name (index + 1) taken
506-- GET ALL VARIABLE NAMES
509getVarNames :: Variable -> TakenNames -> IO TakenNames
510getVarNames var takenNames =
511 do (Descriptor content rank mark copy) <- UF.get var
512 if mark == getVarNamesMark
513 then return takenNames
515 do UF.set var (Descriptor content rank getVarNamesMark copy)
526 addName 0 name var (FlexVar . Just) takenNames
528 FlexSuper super maybeName ->
534 addName 0 name var (FlexSuper super . Just) takenNames
537 addName 0 name var RigidVar takenNames
539 RigidSuper super name ->
540 addName 0 name var (RigidSuper super) takenNames
543 foldrM getVarNames takenNames (map snd args)
545 Structure flatType ->
548 foldrM getVarNames takenNames args
551 getVarNames arg =<< getVarNames body takenNames
556 Record1 fields extension ->
557 getVarNames extension =<<
558 foldrM getVarNames takenNames (Map.elems fields)
563 Tuple1 a b Nothing ->
564 getVarNames a =<< getVarNames b takenNames
566 Tuple1 a b (Just c) ->
567 getVarNames a =<< getVarNames b =<< getVarNames c takenNames
571-- REGISTER NAME / RENAME DUPLICATES
574addName :: Int -> N.Name -> Variable -> (N.Name -> Content) -> TakenNames -> IO TakenNames
575addName index givenName var makeContent takenNames =
580 else if Char.isDigit (Text.last givenName) then
581 givenName <> Text.pack ('_' : show index)
583 givenName <> Text.pack (show 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