1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
7 , Descriptor(Descriptor)
16 , int, float, char, string, bool
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" []
202vec2 = AppN ModuleName.vector2 "Vec2" []
207vec3 = AppN ModuleName.vector3 "Vec3" []
212vec4 = AppN ModuleName.vector4 "Vec4" []
217mat4 = AppN ModuleName.matrix4 "Mat4" []
220{-# NOINLINE texture #-}
222texture = AppN ModuleName.webgl "Texture" []
226-- MAKE FLEX VARIABLES
229mkFlexVar :: IO Variable
231 UF.fresh flexVarDescriptor
234{-# NOINLINE flexVarDescriptor #-}
235flexVarDescriptor :: Descriptor
237 makeDescriptor unnamedFlexVar
240{-# NOINLINE unnamedFlexVar #-}
241unnamedFlexVar :: Content
250mkFlexNumber :: IO Variable
252 UF.fresh flexNumberDescriptor
255{-# NOINLINE flexNumberDescriptor #-}
256flexNumberDescriptor :: Descriptor
257flexNumberDescriptor =
258 makeDescriptor (unnamedFlexSuper Number)
261unnamedFlexSuper :: SuperType -> Content
262unnamedFlexSuper super =
263 FlexSuper super Nothing
267-- MAKE NAMED VARIABLES
270nameToFlex :: N.Name -> IO Variable
272 UF.fresh $ makeDescriptor $
273 maybe FlexVar FlexSuper (toSuper name) (Just name)
276nameToRigid :: N.Name -> IO Variable
278 UF.fresh $ makeDescriptor $
279 maybe RigidVar RigidSuper (toSuper name) name
282toSuper :: N.Name -> Maybe SuperType
284 if Text.isPrefixOf "number" name then
287 else if Text.isPrefixOf "comparable" name then
290 else if Text.isPrefixOf "appendable" name then
293 else if Text.isPrefixOf "compappend" name then
304-- TODO: Attach resulting type to the descriptor so that you
305-- never have to do extra work, particularly nice for aliased types
306toSrcType :: Variable -> IO Can.Type
308 do takenNames <- getVarNames variable Map.empty
309 State.evalStateT (variableToSrcType variable) (makeNameState takenNames)
312variableToSrcType :: Variable -> StateT NameState IO Can.Type
313variableToSrcType variable =
314 do descriptor <- liftIO $ UF.get variable
315 let mark = _mark descriptor
316 if mark == occursMark
318 return (Can.TVar "∞")
321 do liftIO $ UF.modify variable (\desc -> desc { _mark = occursMark })
322 srcType <- contentToSrcType variable (_content descriptor)
323 liftIO $ UF.modify variable (\desc -> desc { _mark = mark })
327contentToSrcType :: Variable -> Content -> StateT NameState IO Can.Type
328contentToSrcType variable content =
336 return (Can.TVar name)
339 do name <- getFreshVarName
340 liftIO $ UF.modify variable (\desc -> desc { _content = FlexVar (Just name) })
341 return (Can.TVar name)
343 FlexSuper super maybeName ->
346 return (Can.TVar name)
349 do name <- getFreshSuperName super
350 liftIO $ UF.modify variable (\desc -> desc { _content = FlexSuper super (Just name) })
351 return (Can.TVar name)
354 return (Can.TVar name)
357 return (Can.TVar name)
359 Alias home name args realVariable ->
360 do srcArgs <- traverse (traverse variableToSrcType) args
361 srcType <- variableToSrcType realVariable
362 return (Can.TAlias home name srcArgs (Can.Filled srcType))
365 return (Can.TVar name)
368termToSrcType :: FlatType -> StateT NameState IO Can.Type
371 App1 home name args ->
372 Can.TType home name <$> traverse variableToSrcType args
376 <$> variableToSrcType a
377 <*> variableToSrcType b
380 return $ Can.TRecord Map.empty Nothing
382 Record1 fields extension ->
383 do srcFields <- traverse variableToSrcType fields
384 srcExt <- Type.iteratedDealias <$> variableToSrcType extension
387 Can.TRecord subFields subExt ->
388 Can.TRecord (Map.union subFields srcFields) subExt
391 Can.TRecord srcFields (Just srcExt)
394 error "Used toSrcType on a type that is not well-formed"
401 <$> variableToSrcType a
402 <*> variableToSrcType b
403 <*> traverse variableToSrcType maybeC
407-- MANAGE FRESH VARIABLE NAMES
412 { _taken :: TakenNames
415 , _comparables :: Int
416 , _appendables :: Int
417 , _compAppends :: Int
421type TakenNames = Map.Map Text Variable
424makeNameState :: TakenNames -> NameState
426 NameState taken 0 0 0 0 0
429getFreshVarName :: (Monad m) => StateT NameState m Text
431 do index <- State.gets _normals
432 taken <- State.gets _taken
433 let (uniqueName, newIndex) = getFreshNormal index taken
434 State.modify (\state -> state { _normals = newIndex })
438getFreshSuperName :: (Monad m) => SuperType -> StateT NameState m Text
439getFreshSuperName super =
442 getFreshSuper "number" _numbers (\index state -> state { _numbers = index })
445 getFreshSuper "comparable" _comparables (\index state -> state { _comparables = index })
448 getFreshSuper "appendable" _appendables (\index state -> state { _appendables = index })
451 getFreshSuper "compappend" _compAppends (\index state -> state { _compAppends = index })
454getFreshNormal :: Int -> TakenNames -> (Text, Int)
455getFreshNormal index taken =
461 Char.chr (97 + letter)
464 Text.pack (if postfix <= 0 then [character] else character : show postfix)
466 if Map.member name taken then
467 getFreshNormal (index + 1) taken
476 -> (NameState -> Int)
477 -> (Int -> NameState -> NameState)
478 -> StateT NameState m Text
479getFreshSuper name getter setter =
480 do index <- State.gets getter
481 taken <- State.gets _taken
482 let (uniqueName, newIndex) = getFreshSuperHelp name index taken
483 State.modify (setter newIndex)
487getFreshSuperHelp :: Text -> Int -> TakenNames -> (Text, Int)
488getFreshSuperHelp name index taken =
491 if index <= 0 then name else name <> Text.pack (show index)
493 if Map.member newName taken then
494 getFreshSuperHelp name (index + 1) taken
501-- GET ALL VARIABLE NAMES
504getVarNames :: Variable -> TakenNames -> IO TakenNames
505getVarNames var takenNames =
506 do (Descriptor content rank mark copy) <- UF.get var
507 if mark == getVarNamesMark
508 then return takenNames
510 do UF.set var (Descriptor content rank getVarNamesMark copy)
521 addName 0 name var (FlexVar . Just) takenNames
523 FlexSuper super maybeName ->
529 addName 0 name var (FlexSuper super . Just) takenNames
532 addName 0 name var RigidVar takenNames
534 RigidSuper super name ->
535 addName 0 name var (RigidSuper super) takenNames
538 foldrM getVarNames takenNames (map snd args)
540 Structure flatType ->
543 foldrM getVarNames takenNames args
546 getVarNames arg =<< getVarNames body takenNames
551 Record1 fields extension ->
552 getVarNames extension =<<
553 foldrM getVarNames takenNames (Map.elems fields)
558 Tuple1 a b Nothing ->
559 getVarNames a =<< getVarNames b takenNames
561 Tuple1 a b (Just c) ->
562 getVarNames a =<< getVarNames b =<< getVarNames c takenNames
566-- REGISTER NAME / RENAME DUPLICATES
569addName :: Int -> N.Name -> Variable -> (N.Name -> Content) -> TakenNames -> IO TakenNames
570addName index givenName var makeContent takenNames =
575 else if Char.isDigit (Text.last givenName) then
576 givenName <> Text.pack ('_' : show index)
578 givenName <> Text.pack (show index)
580 case Map.lookup indexedName takenNames of
582 do if indexedName == givenName then return () else
583 UF.modify var $ \(Descriptor _ rank mark copy) ->
584 Descriptor (makeContent indexedName) rank mark copy
585 return $ Map.insert indexedName var takenNames
588 do same <- UF.equivalent var otherVar
590 then return takenNames
591 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