1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
7 , Descriptor(Descriptor)
15 , int, float, char, string, bool
16 , vec2, vec3, vec4, mat4, texture
28import Control.Monad.State.Strict (StateT, liftIO)
29import qualified Control.Monad.State.Strict as State
30import qualified Data.Char as Char
31import Data.Foldable (foldrM)
32import qualified Data.Map.Strict as Map
33import Data.Monoid ((<>))
34import qualified Data.Text as Text
35import Data.Text (Text)
36import Data.Word (Word32)
38import qualified AST.Module.Name as ModuleName
39import qualified AST.Type as T
40import qualified Elm.Name as N
41import qualified Type.UnionFind as UF
53 = App1 ModuleName.Canonical N.Name [Variable]
54 | Fun1 Variable Variable
56 | Record1 (Map.Map N.Name Variable) Variable
58 | Tuple1 Variable Variable (Maybe Variable)
63 | AliasN ModuleName.Canonical N.Name [(N.Name, Type)] Type
65 | AppN ModuleName.Canonical N.Name [Type]
68 | RecordN (Map.Map N.Name Type) Type
70 | TupleN Type Type (Maybe Type)
82 , _copy :: Maybe Variable
87 = FlexVar (Maybe N.Name)
88 | FlexSuper T.Super (Maybe N.Name)
90 | RigidSuper T.Super N.Name
92 | Alias ModuleName.Canonical N.Name [(N.Name,Variable)] Variable
96makeDescriptor :: Content -> Descriptor
97makeDescriptor content =
98 Descriptor content noRank noMark Nothing
119newtype Mark = Mark Word32
133getVarNamesMark :: Mark
138{-# INLINE nextMark #-}
139nextMark :: Mark -> Mark
140nextMark (Mark mark) =
152(==>) :: Type -> Type -> Type
163int = AppN ModuleName.basics "Int" []
166{-# NOINLINE float #-}
168float = AppN ModuleName.basics "Float" []
173char = AppN ModuleName.char "Char" []
176{-# NOINLINE string #-}
178string = AppN ModuleName.string "String" []
183bool = AppN ModuleName.basics "Bool" []
192vec2 = AppN ModuleName.vector2 "Vec2" []
197vec3 = AppN ModuleName.vector3 "Vec3" []
202vec4 = AppN ModuleName.vector4 "Vec4" []
207mat4 = AppN ModuleName.matrix4 "Mat4" []
210{-# NOINLINE texture #-}
212texture = AppN ModuleName.webgl "Texture" []
216-- MAKE FLEX VARIABLES
219mkFlexVar :: IO Variable
221 UF.fresh flexVarDescriptor
224{-# NOINLINE flexVarDescriptor #-}
225flexVarDescriptor :: Descriptor
227 makeDescriptor unnamedFlexVar
230{-# NOINLINE unnamedFlexVar #-}
231unnamedFlexVar :: Content
240mkFlexNumber :: IO Variable
242 UF.fresh flexNumberDescriptor
245{-# NOINLINE flexNumberDescriptor #-}
246flexNumberDescriptor :: Descriptor
247flexNumberDescriptor =
248 makeDescriptor (unnamedFlexSuper T.Number)
251unnamedFlexSuper :: T.Super -> Content
252unnamedFlexSuper super =
253 FlexSuper super Nothing
257-- MAKE NAMED VARIABLES
260nameToFlex :: N.Name -> IO Variable
262 UF.fresh $ makeDescriptor $
263 maybe FlexVar FlexSuper (toSuper name) (Just name)
266nameToRigid :: N.Name -> IO Variable
268 UF.fresh $ makeDescriptor $
269 maybe RigidVar RigidSuper (toSuper name) name
272toSuper :: N.Name -> Maybe T.Super
274 if Text.isPrefixOf "number" name then
277 else if Text.isPrefixOf "comparable" name then
280 else if Text.isPrefixOf "appendable" name then
283 else if Text.isPrefixOf "compappend" name then
294-- TODO: Attach resulting type to the descriptor so that you
295-- never have to do extra work, particularly nice for aliased types
296toSrcType :: Variable -> IO T.Canonical
298 do takenNames <- getVarNames variable Map.empty
299 State.evalStateT (variableToSrcType variable) (makeNameState takenNames)
302variableToSrcType :: Variable -> StateT NameState IO T.Canonical
303variableToSrcType variable =
304 do descriptor <- liftIO $ UF.descriptor variable
305 let mark = _mark descriptor
306 if mark == occursMark
311 do liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = occursMark })
312 srcType <- contentToSrcType variable (_content descriptor)
313 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = mark })
317contentToSrcType :: Variable -> Content -> StateT NameState IO T.Canonical
318contentToSrcType variable content =
329 do name <- getFreshVarName
330 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _content = FlexVar (Just name) })
333 FlexSuper super maybeName ->
339 do name <- getFreshSuperName super
340 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _content = FlexSuper super (Just name) })
349 Alias home name args realVariable ->
350 do srcArgs <- traverse (traverse variableToSrcType) args
351 srcType <- variableToSrcType realVariable
352 return (T.Aliased home name srcArgs (T.Filled srcType))
358termToSrcType :: FlatType -> StateT NameState IO T.Canonical
361 App1 home name args ->
362 T.Type home name <$> traverse variableToSrcType args
366 <$> variableToSrcType a
367 <*> variableToSrcType b
370 return $ T.Record Map.empty Nothing
372 Record1 fields extension ->
373 do srcFields <- traverse variableToSrcType fields
374 srcExt <- T.iteratedDealias <$> variableToSrcType extension
377 T.Record subFields subExt ->
378 T.Record (Map.union subFields srcFields) subExt
381 T.Record srcFields (Just srcExt)
384 error "Used toSrcType on a type that is not well-formed"
391 <$> variableToSrcType a
392 <*> variableToSrcType b
393 <*> traverse variableToSrcType maybeC
397-- MANAGE FRESH VARIABLE NAMES
402 { _taken :: TakenNames
405 , _comparables :: Int
406 , _appendables :: Int
407 , _compAppends :: Int
411type TakenNames = Map.Map Text Variable
414makeNameState :: TakenNames -> NameState
416 NameState taken 0 0 0 0 0
419getFreshVarName :: (Monad m) => StateT NameState m Text
421 do index <- State.gets _normals
422 taken <- State.gets _taken
423 let (uniqueName, newIndex) = getFreshNormal index taken
424 State.modify (\state -> state { _normals = newIndex })
428getFreshSuperName :: (Monad m) => T.Super -> StateT NameState m Text
429getFreshSuperName super =
432 getFreshSuper "number" _numbers (\index state -> state { _numbers = index })
435 getFreshSuper "comparable" _comparables (\index state -> state { _comparables = index })
438 getFreshSuper "appendable" _appendables (\index state -> state { _appendables = index })
441 getFreshSuper "compappend" _compAppends (\index state -> state { _compAppends = index })
444getFreshNormal :: Int -> TakenNames -> (Text, Int)
445getFreshNormal index taken =
451 Char.chr (97 + letter)
454 Text.pack (if postfix <= 0 then [character] else character : show postfix)
456 if Map.member name taken then
457 getFreshNormal (index + 1) taken
466 -> (NameState -> Int)
467 -> (Int -> NameState -> NameState)
468 -> StateT NameState m Text
469getFreshSuper name getter setter =
470 do index <- State.gets getter
471 taken <- State.gets _taken
472 let (uniqueName, newIndex) = getFreshSuperHelp name index taken
473 State.modify (setter newIndex)
477getFreshSuperHelp :: Text -> Int -> TakenNames -> (Text, Int)
478getFreshSuperHelp name index taken =
481 if index <= 0 then name else name <> Text.pack (show index)
483 if Map.member newName taken then
484 getFreshSuperHelp name (index + 1) taken
491-- GET ALL VARIABLE NAMES
494getVarNames :: Variable -> TakenNames -> IO TakenNames
495getVarNames var takenNames =
496 do (Descriptor content rank mark copy) <- UF.descriptor var
497 if mark == getVarNamesMark
498 then return takenNames
500 do UF.setDescriptor var (Descriptor content rank getVarNamesMark copy)
511 addName 0 name var (FlexVar . Just) takenNames
513 FlexSuper super maybeName ->
519 addName 0 name var (FlexSuper super . Just) takenNames
522 addName 0 name var RigidVar takenNames
524 RigidSuper super name ->
525 addName 0 name var (RigidSuper super) takenNames
528 foldrM getVarNames takenNames (map snd args)
530 Structure flatType ->
533 foldrM getVarNames takenNames args
536 getVarNames arg =<< getVarNames body takenNames
541 Record1 fields extension ->
542 getVarNames extension =<<
543 foldrM getVarNames takenNames (Map.elems fields)
548 Tuple1 a b Nothing ->
549 getVarNames a =<< getVarNames b takenNames
551 Tuple1 a b (Just c) ->
552 getVarNames a =<< getVarNames b =<< getVarNames c takenNames
556-- REGISTER NAME / RENAME DUPLICATES
559addName :: Int -> N.Name -> Variable -> (N.Name -> Content) -> TakenNames -> IO TakenNames
560addName index givenName var makeContent takenNames =
565 else if Char.isDigit (Text.last givenName) then
566 givenName <> Text.pack ('_' : show index)
568 givenName <> Text.pack (show index)
570 case Map.lookup indexedName takenNames of
572 do if indexedName == givenName then return () else
573 UF.modifyDescriptor var $ \(Descriptor _ rank mark copy) ->
574 Descriptor (makeContent indexedName) rank mark copy
575 return $ Map.insert indexedName var takenNames
578 do same <- UF.equivalent var otherVar
580 then return takenNames
581 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