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.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
104makeDescriptor :: Content -> Descriptor
105makeDescriptor content =
106 Descriptor content noRank noMark Nothing
127newtype Mark = Mark Word32
141getVarNamesMark :: Mark
146{-# INLINE nextMark #-}
147nextMark :: Mark -> Mark
148nextMark (Mark mark) =
160(==>) :: Type -> Type -> Type
171int = AppN ModuleName.basics "Int" []
174{-# NOINLINE float #-}
176float = AppN ModuleName.basics "Float" []
181char = AppN ModuleName.char "Char" []
184{-# NOINLINE string #-}
186string = AppN ModuleName.string "String" []
191bool = AppN ModuleName.basics "Bool" []
200vec2 = AppN ModuleName.vector2 "Vec2" []
205vec3 = AppN ModuleName.vector3 "Vec3" []
210vec4 = AppN ModuleName.vector4 "Vec4" []
215mat4 = AppN ModuleName.matrix4 "Mat4" []
218{-# NOINLINE texture #-}
220texture = AppN ModuleName.webgl "Texture" []
224-- MAKE FLEX VARIABLES
227mkFlexVar :: IO Variable
229 UF.fresh flexVarDescriptor
232{-# NOINLINE flexVarDescriptor #-}
233flexVarDescriptor :: Descriptor
235 makeDescriptor unnamedFlexVar
238{-# NOINLINE unnamedFlexVar #-}
239unnamedFlexVar :: Content
248mkFlexNumber :: IO Variable
250 UF.fresh flexNumberDescriptor
253{-# NOINLINE flexNumberDescriptor #-}
254flexNumberDescriptor :: Descriptor
255flexNumberDescriptor =
256 makeDescriptor (unnamedFlexSuper Number)
259unnamedFlexSuper :: SuperType -> Content
260unnamedFlexSuper super =
261 FlexSuper super Nothing
265-- MAKE NAMED VARIABLES
268nameToFlex :: N.Name -> IO Variable
270 UF.fresh $ makeDescriptor $
271 maybe FlexVar FlexSuper (toSuper name) (Just name)
274nameToRigid :: N.Name -> IO Variable
276 UF.fresh $ makeDescriptor $
277 maybe RigidVar RigidSuper (toSuper name) name
280toSuper :: N.Name -> Maybe SuperType
282 if Text.isPrefixOf "number" name then
285 else if Text.isPrefixOf "comparable" name then
288 else if Text.isPrefixOf "appendable" name then
291 else if Text.isPrefixOf "compappend" name then
302-- TODO: Attach resulting type to the descriptor so that you
303-- never have to do extra work, particularly nice for aliased types
304toSrcType :: Variable -> IO Can.Type
306 do takenNames <- getVarNames variable Map.empty
307 State.evalStateT (variableToSrcType variable) (makeNameState takenNames)
310variableToSrcType :: Variable -> StateT NameState IO Can.Type
311variableToSrcType variable =
312 do descriptor <- liftIO $ UF.descriptor variable
313 let mark = _mark descriptor
314 if mark == occursMark
316 return (Can.TVar "∞")
319 do liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = occursMark })
320 srcType <- contentToSrcType variable (_content descriptor)
321 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = mark })
325contentToSrcType :: Variable -> Content -> StateT NameState IO Can.Type
326contentToSrcType variable content =
334 return (Can.TVar name)
337 do name <- getFreshVarName
338 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _content = FlexVar (Just name) })
339 return (Can.TVar name)
341 FlexSuper super maybeName ->
344 return (Can.TVar name)
347 do name <- getFreshSuperName super
348 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _content = FlexSuper super (Just name) })
349 return (Can.TVar name)
352 return (Can.TVar name)
355 return (Can.TVar name)
357 Alias home name args realVariable ->
358 do srcArgs <- traverse (traverse variableToSrcType) args
359 srcType <- variableToSrcType realVariable
360 return (Can.TAlias home name srcArgs (Can.Filled srcType))
363 return (Can.TVar name)
366termToSrcType :: FlatType -> StateT NameState IO Can.Type
369 App1 home name args ->
370 Can.TType home name <$> traverse variableToSrcType args
374 <$> variableToSrcType a
375 <*> variableToSrcType b
378 return $ Can.TRecord Map.empty Nothing
380 Record1 fields extension ->
381 do srcFields <- traverse variableToSrcType fields
382 srcExt <- Type.iteratedDealias <$> variableToSrcType extension
385 Can.TRecord subFields subExt ->
386 Can.TRecord (Map.union subFields srcFields) subExt
389 Can.TRecord srcFields (Just srcExt)
392 error "Used toSrcType on a type that is not well-formed"
399 <$> variableToSrcType a
400 <*> variableToSrcType b
401 <*> traverse variableToSrcType maybeC
405-- MANAGE FRESH VARIABLE NAMES
410 { _taken :: TakenNames
413 , _comparables :: Int
414 , _appendables :: Int
415 , _compAppends :: Int
419type TakenNames = Map.Map Text Variable
422makeNameState :: TakenNames -> NameState
424 NameState taken 0 0 0 0 0
427getFreshVarName :: (Monad m) => StateT NameState m Text
429 do index <- State.gets _normals
430 taken <- State.gets _taken
431 let (uniqueName, newIndex) = getFreshNormal index taken
432 State.modify (\state -> state { _normals = newIndex })
436getFreshSuperName :: (Monad m) => SuperType -> StateT NameState m Text
437getFreshSuperName super =
440 getFreshSuper "number" _numbers (\index state -> state { _numbers = index })
443 getFreshSuper "comparable" _comparables (\index state -> state { _comparables = index })
446 getFreshSuper "appendable" _appendables (\index state -> state { _appendables = index })
449 getFreshSuper "compappend" _compAppends (\index state -> state { _compAppends = index })
452getFreshNormal :: Int -> TakenNames -> (Text, Int)
453getFreshNormal index taken =
459 Char.chr (97 + letter)
462 Text.pack (if postfix <= 0 then [character] else character : show postfix)
464 if Map.member name taken then
465 getFreshNormal (index + 1) taken
474 -> (NameState -> Int)
475 -> (Int -> NameState -> NameState)
476 -> StateT NameState m Text
477getFreshSuper name getter setter =
478 do index <- State.gets getter
479 taken <- State.gets _taken
480 let (uniqueName, newIndex) = getFreshSuperHelp name index taken
481 State.modify (setter newIndex)
485getFreshSuperHelp :: Text -> Int -> TakenNames -> (Text, Int)
486getFreshSuperHelp name index taken =
489 if index <= 0 then name else name <> Text.pack (show index)
491 if Map.member newName taken then
492 getFreshSuperHelp name (index + 1) taken
499-- GET ALL VARIABLE NAMES
502getVarNames :: Variable -> TakenNames -> IO TakenNames
503getVarNames var takenNames =
504 do (Descriptor content rank mark copy) <- UF.descriptor var
505 if mark == getVarNamesMark
506 then return takenNames
508 do UF.setDescriptor var (Descriptor content rank getVarNamesMark copy)
519 addName 0 name var (FlexVar . Just) takenNames
521 FlexSuper super maybeName ->
527 addName 0 name var (FlexSuper super . Just) takenNames
530 addName 0 name var RigidVar takenNames
532 RigidSuper super name ->
533 addName 0 name var (RigidSuper super) takenNames
536 foldrM getVarNames takenNames (map snd args)
538 Structure flatType ->
541 foldrM getVarNames takenNames args
544 getVarNames arg =<< getVarNames body takenNames
549 Record1 fields extension ->
550 getVarNames extension =<<
551 foldrM getVarNames takenNames (Map.elems fields)
556 Tuple1 a b Nothing ->
557 getVarNames a =<< getVarNames b takenNames
559 Tuple1 a b (Just c) ->
560 getVarNames a =<< getVarNames b =<< getVarNames c takenNames
564-- REGISTER NAME / RENAME DUPLICATES
567addName :: Int -> N.Name -> Variable -> (N.Name -> Content) -> TakenNames -> IO TakenNames
568addName index givenName var makeContent takenNames =
573 else if Char.isDigit (Text.last givenName) then
574 givenName <> Text.pack ('_' : show index)
576 givenName <> Text.pack (show index)
578 case Map.lookup indexedName takenNames of
580 do if indexedName == givenName then return () else
581 UF.modifyDescriptor var $ \(Descriptor _ rank mark copy) ->
582 Descriptor (makeContent indexedName) rank mark copy
583 return $ Map.insert indexedName var takenNames
586 do same <- UF.equivalent var otherVar
588 then return takenNames
589 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