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)
378 do args' <- mapM (\(arg,tvar) -> (,) arg <$> variableToSrcType rootVariable tvar) args
379 return (T.Aliased name args' (T.Filled srcType))
381 backupSrcType :: Descriptor -> IO T.CanonicalType
384 Just v@(Var.Canonical _ x@(c:_))
393 [ "Problem converting the following type "
394 , "from a type-checker type to a source-syntax type:"
395 , P.render (pretty Never rootVariable)
399termToSrcType :: Variable -> Term1 Variable -> IO T.CanonicalType
400termToSrcType rootVariable term =
401 let go = variableToSrcType rootVariable in
408 return $ T.App f (args ++ [b'])
410 return $ T.App a' [b']
413 T.Lambda <$> go a <*> go b
419 return $ T.Record [] Nothing
421 Record1 tfields extension ->
422 do fields' <- Traverse.traverse (mapM go) tfields
423 let fields = concat [ map ((,) name) ts | (name,ts) <- Map.toList fields' ]
424 ext' <- dealias <$> go extension
427 T.Record fs ext -> T.Record (fs ++ fields) ext
428 T.Var _ -> T.Record fields (Just ext')
429 _ -> error "Used toSrcType on a type that is not well-formed"
431 dealias :: T.CanonicalType -> T.CanonicalType
434 T.Aliased _ args tipe' ->
442addNames :: Variable -> IO ()
444 do usedNames <- getVarNames variable
445 let freeNames = makeFreeNames usedNames
446 State.runStateT (varAddNames variable) (NameState freeNames 0 0 0)
450makeFreeNames :: Set.Set String -> [String]
451makeFreeNames usedNames =
452 let makeName suffix =
453 map (:suffix) ['a'..'z']
456 concatMap makeName ("" : "'" : "_" : map show [ (0 :: Int) .. ])
458 filter (\name -> Set.notMember name usedNames) allNames
461data NameState = NameState
462 { freeNames :: [String]
463 , numberPrimes :: Int
464 , comparablePrimes :: Int
465 , appendablePrimes :: Int
469varAddNames :: Variable -> StateT NameState IO ()
471 do desc <- liftIO (UF.descriptor var)
476 Just (_name, args) ->
477 mapM_ (\(v,t) -> (,) v <$> varAddNames t) args
479 case structure desc of
487 do name' <- createName desc
488 liftIO $ UF.modifyDescriptor var $ \desc ->
489 desc { name = Just (Var.local name') }
492termAddNames :: Term1 Variable -> StateT NameState IO ()
509 Record1 fields extension ->
510 do mapM_ varAddNames (concat (Map.elems fields))
511 varAddNames extension
514createName :: (Monad m) => Descriptor -> StateT NameState m String
518 do primes <- State.gets numberPrimes
519 State.modify (\state -> state { numberPrimes = primes + 1 })
520 return ("number" ++ replicate primes '\'')
523 do primes <- State.gets comparablePrimes
524 State.modify (\state -> state { comparablePrimes = primes + 1 })
525 return ("comparable" ++ replicate primes '\'')
528 do primes <- State.gets appendablePrimes
529 State.modify (\state -> state { appendablePrimes = primes + 1 })
530 return ("appendable" ++ replicate primes '\'')
533 do names <- State.gets freeNames
534 State.modify (\state -> state { freeNames = tail names })
538-- GET ALL VARIABLE NAMES
540getVarNames :: Variable -> IO (Set.Set String)
542 do desc <- UF.descriptor var
546 Just var -> Set.singleton (Var.toString var)
550 case structure desc of
551 Nothing -> return Set.empty
552 Just term -> getVarNamesTerm term
559 Just (_name, args) ->
560 do let set = Set.fromList (map fst args)
561 sets <- mapM (getVarNames . snd) args
562 return (Set.unions (set : sets))
564 return (Set.unions [ baseSet, structureSet, aliasSet ])
567getVarNamesTerm :: Term1 Variable -> IO (Set.Set String)
568getVarNamesTerm term =
569 let go = getVarNames in
572 Set.union <$> go a <*> go b
575 Set.union <$> go a <*> go b
583 Record1 fields extension ->
584 do fieldVars <- Set.unions <$> mapM go (concat (Map.elems fields))
585 Set.union fieldVars <$> go extension
588-- COLLECT APPLICATIONS
596collectApps :: Variable -> IO AppStructure
601 desc <- UF.descriptor var
602 case (structure desc, vars) of
605 Just n | Var.isList n -> return (List v)
610 Just n | Var.isTuple n -> return (Tuple vs)
615 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