3import Control.Applicative ((<$>),(<*>))
4import Control.Monad.State (StateT)
5import qualified Control.Monad.State as State
6import Control.Monad.Error (ErrorT, Error, liftIO)
7import qualified Data.Char as Char
8import qualified Data.Map as Map
9import qualified Data.Set as Set
10import qualified Data.Traversable as Traverse (traverse)
11import qualified Data.UnionFind.IO as UF
12import Text.PrettyPrint as P
13import System.IO.Unsafe
16import qualified AST.PrettyPrint as PP
17import qualified AST.Type as T
18import qualified AST.Variable as Var
19import Type.PrettyPrint
24type Type = TermN Variable
26type Variable = UF.Point Descriptor
28type TypeConstraint = Constraint Type Variable
30type TypeScheme = Scheme Type Variable
32type Alias a = Maybe (Var.Canonical, [(String,a)])
42 | Record1 (Map.Map String [a]) a
47 | VarN (Alias (TermN a)) a
48 | TermN (Alias (TermN a)) (Term1 (TermN a))
56termN :: (Term1 (TermN a)) -> TermN a
61record :: Map.Map String [TermN a] -> TermN a -> TermN a
63 termN (Record1 fs rec)
68data Descriptor = Descriptor
69 { structure :: Maybe (Term1 Variable)
72 , name :: Maybe TypeName
73 , copy :: Maybe Variable
75 , alias :: Alias Variable
107 Located (BasicConstraint a b)
109data BasicConstraint a b
113 | CAnd [Constraint a b]
114 | CLet [Scheme a b] (Constraint a b)
115 | CInstance SchemeName a
117type SchemeName = String
119type TypeName = Var.Canonical
121data Scheme a b = Scheme
122 { rigidQuantifiers :: [b]
123 , flexibleQuantifiers :: [b]
124 , constraint :: Constraint a b
125 , header :: Map.Map String a
133(==>) :: Type -> Type -> Type
138(<|) :: TermN a -> TermN a -> TermN a
145namedVar :: Flex -> Var.Canonical -> IO Variable
146namedVar flex name = UF.fresh $ Descriptor
147 { structure = Nothing
157variable :: Flex -> IO Variable
158variable flex = UF.fresh $ Descriptor
159 { structure = Nothing
171monoscheme :: Map.Map String a -> Scheme a b
173 Scheme [] [] (noneNoDocs CTrue) headers
178(/\) :: Constraint a b -> Constraint a b -> Constraint a b
179(/\) a@(A _ c1) b@(A _ c2) =
183 _ -> mergeOldDocs a b (CAnd [a,b])
186-- ex qs constraint == exists qs. constraint
187ex :: [Variable] -> TypeConstraint -> TypeConstraint
188ex fqs constraint@(A ann _) =
189 A ann $ CLet [Scheme [] fqs constraint Map.empty] (A ann CTrue)
192-- fl qs constraint == forall qs. constraint
193fl :: [Variable] -> TypeConstraint -> TypeConstraint
194fl rqs constraint@(A ann _) =
195 A ann $ CLet [Scheme rqs [] constraint Map.empty] (A ann CTrue)
198exists :: Error e => (Type -> ErrorT e IO TypeConstraint) -> ErrorT e IO TypeConstraint
200 do v <- liftIO $ variable Flexible
201 ex [v] <$> f (varN v)
204existsNumber :: Error e => (Type -> ErrorT e IO TypeConstraint) -> ErrorT e IO TypeConstraint
206 do v <- liftIO $ variable (Is Number)
207 ex [v] <$> f (varN v)
210-- TYPES TO PRETTY STRINGS
212instance PrettyType a => PrettyType (UF.Point a) where
214 unsafePerformIO $ fmap (pretty when) (UF.descriptor point)
217instance PrettyType t => PrettyType (Annotated a t) where
218 pretty when (A _ e) =
222instance PrettyType a => PrettyType (Term1 a) where
224 let prty = pretty Never in
227 parensIf needed (px <+> pretty App x)
236 parensIf needed (pretty Fn arg <+> P.text "->" <+> prty body)
249 Record1 fields ext ->
250 P.braces (extend <+> commaSep prettyFields)
255 | P.render prettyExt == "{}" =
258 prettyExt <+> P.text "|"
261 P.text f <+> P.text ":" <+> prty t
264 concatMap (\(f,ts) -> map (mkPretty f) ts) (Map.toList fields)
267instance PrettyType a => PrettyType (TermN a) where
271 error "problem prettifying type, probably indicates a bigger problem"
274 either alias (pretty when x)
277 either alias (pretty when t1)
279 either maybeAlias doc =
283 P.hang (PP.pretty name) 2 (P.sep (map (pretty App . snd) args))
286instance PrettyType Descriptor where
288 case (alias desc, structure desc, name desc) of
289 (Just (name, args), _, _) ->
290 P.hang (PP.pretty name) 4 (P.sep (map (pretty App . snd) args))
296 | Var.isTuple name ->
297 P.parens . P.text $ replicate (read (drop 6 (Var.toString name)) - 1) ','
299 P.text (Var.toString name)
304instance (PrettyType a, PrettyType b) => PrettyType (BasicConstraint a b) where
305 pretty _ constraint =
306 let prty = pretty Never in
308 CTrue -> P.text "True"
309 CSaveEnv -> P.text "SaveTheEnvironment!!!"
310 CEqual a b -> prty a <+> P.text "=" <+> prty b
311 CAnd [] -> P.text "True"
314 P.parens . P.sep $ P.punctuate (P.text " and") (map (pretty Never) cs)
316 CLet [Scheme [] fqs constraint header] (A _ CTrue) | Map.null header ->
317 P.sep [ binder, pretty Never c ]
319 mergeExists vs (A _ c) =
321 CLet [Scheme [] fqs' c' _] (A _ CTrue) -> mergeExists (vs ++ fqs') c'
324 (fqs', c) = mergeExists fqs constraint
326 binder = if null fqs' then P.empty else
327 P.text "\x2203" <+> P.hsep (map (pretty Never) fqs') <> P.text "."
329 CLet schemes constraint ->
330 P.fsep [ P.hang (P.text "let") 4 (P.brackets . commaSep $ map (pretty Never) schemes)
331 , P.text "in", pretty Never constraint ]
333 CInstance name tipe ->
334 P.text name <+> P.text "<" <+> prty tipe
337instance (PrettyType a, PrettyType b) => PrettyType (Scheme a b) where
338 pretty _ (Scheme rqs fqs (A _ constraint) headers) =
339 P.sep [ forall, cs, headers' ]
343 forall = if null rqs && null fqs then P.empty else
344 P.text "\x2200" <+> frees <+> rigids
346 frees = P.hsep $ map prty fqs
347 rigids = if null rqs then P.empty else P.braces . P.hsep $ map prty rqs
349 cs = case constraint of
352 _ -> P.brackets (pretty Never constraint)
354 headers' = if Map.size headers > 0 then dict else P.empty
355 dict = P.parens . commaSep . map prettyPair $ Map.toList headers
356 prettyPair (n,t) = P.text n <+> P.text ":" <+> pretty Never t
359-- CONVERT TO SOURCE TYPES
361-- TODO: Attach resulting type to the descriptor so that you
362-- never have to do extra work, particularly nice for aliased types
363toSrcType :: Variable -> IO T.CanonicalType
366 variableToSrcType variable variable
369variableToSrcType :: Variable -> Variable -> IO T.CanonicalType
370variableToSrcType rootVariable variable =
371 do desc <- UF.descriptor variable
372 srcType <- maybe (backupSrcType desc) (termToSrcType rootVariable) (structure desc)
379 T.Type (Var.Canonical Var.BuiltIn _) ->
383 do args' <- mapM (\(arg,tvar) -> (,) arg <$> variableToSrcType rootVariable tvar) args
384 return (T.Aliased name args' (T.Filled srcType))
386 backupSrcType :: Descriptor -> IO T.CanonicalType
389 Just v@(Var.Canonical _ x@(c:_))
398 [ "Problem converting the following type "
399 , "from a type-checker type to a source-syntax type:"
400 , P.render (pretty Never rootVariable)
404termToSrcType :: Variable -> Term1 Variable -> IO T.CanonicalType
405termToSrcType rootVariable term =
406 let go = variableToSrcType rootVariable in
413 return $ T.App f (args ++ [b'])
415 return $ T.App a' [b']
418 T.Lambda <$> go a <*> go b
424 return $ T.Record [] Nothing
426 Record1 tfields extension ->
427 do fields' <- Traverse.traverse (mapM go) tfields
428 let fields = concat [ map ((,) name) ts | (name,ts) <- Map.toList fields' ]
429 ext' <- dealias <$> go extension
432 T.Record fs ext -> T.Record (fs ++ fields) ext
433 T.Var _ -> T.Record fields (Just ext')
434 _ -> error "Used toSrcType on a type that is not well-formed"
436 dealias :: T.CanonicalType -> T.CanonicalType
439 T.Aliased _ args tipe' ->
447addNames :: Variable -> IO ()
449 do usedNames <- getVarNames variable
450 let freeNames = makeFreeNames usedNames
451 State.runStateT (varAddNames variable) (NameState freeNames 0 0 0)
455makeFreeNames :: Set.Set String -> [String]
456makeFreeNames usedNames =
457 let makeName suffix =
458 map (:suffix) ['a'..'z']
461 concatMap makeName ("" : "'" : "_" : map show [ (0 :: Int) .. ])
463 filter (\name -> Set.notMember name usedNames) allNames
466data NameState = NameState
467 { freeNames :: [String]
468 , numberPrimes :: Int
469 , comparablePrimes :: Int
470 , appendablePrimes :: Int
474varAddNames :: Variable -> StateT NameState IO ()
476 do desc <- liftIO (UF.descriptor var)
481 Just (_name, args) ->
482 mapM_ (\(v,t) -> (,) v <$> varAddNames t) args
484 case structure desc of
492 do name' <- createName desc
493 liftIO $ UF.modifyDescriptor var $ \desc ->
494 desc { name = Just (Var.local name') }
497termAddNames :: Term1 Variable -> StateT NameState IO ()
514 Record1 fields extension ->
515 do mapM_ varAddNames (concat (Map.elems fields))
516 varAddNames extension
519createName :: (Monad m) => Descriptor -> StateT NameState m String
523 do primes <- State.gets numberPrimes
524 State.modify (\state -> state { numberPrimes = primes + 1 })
525 return ("number" ++ replicate primes '\'')
528 do primes <- State.gets comparablePrimes
529 State.modify (\state -> state { comparablePrimes = primes + 1 })
530 return ("comparable" ++ replicate primes '\'')
533 do primes <- State.gets appendablePrimes
534 State.modify (\state -> state { appendablePrimes = primes + 1 })
535 return ("appendable" ++ replicate primes '\'')
538 do names <- State.gets freeNames
539 State.modify (\state -> state { freeNames = tail names })
543-- GET ALL VARIABLE NAMES
545getVarNames :: Variable -> IO (Set.Set String)
547 do desc <- UF.descriptor var
551 Just var -> Set.singleton (Var.toString var)
555 case structure desc of
556 Nothing -> return Set.empty
557 Just term -> getVarNamesTerm term
564 Just (_name, args) ->
565 do let set = Set.fromList (map fst args)
566 sets <- mapM (getVarNames . snd) args
567 return (Set.unions (set : sets))
569 return (Set.unions [ baseSet, structureSet, aliasSet ])
572getVarNamesTerm :: Term1 Variable -> IO (Set.Set String)
573getVarNamesTerm term =
574 let go = getVarNames in
577 Set.union <$> go a <*> go b
580 Set.union <$> go a <*> go b
588 Record1 fields extension ->
589 do fieldVars <- Set.unions <$> mapM go (concat (Map.elems fields))
590 Set.union fieldVars <$> go extension
593-- COLLECT APPLICATIONS
601collectApps :: Variable -> IO AppStructure
606 desc <- UF.descriptor var
607 case (structure desc, vars) of
610 Just n | Var.isList n -> return (List v)
615 Just n | Var.isTuple n -> return (Tuple vs)
620 App1 a b -> go (vars ++ [b]) a
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