1{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, DeriveFunctor,
2 TypeSynonymInstances #-}
4module Idris.AbsSyntax where
10import Control.Monad.State
15import qualified Epic.Epic as E
17data IOption = IOption { opt_logLevel :: Int,
22defaultOpts = IOption 0 False
24-- TODO: Add 'module data' to IState, which can be saved out and reloaded quickly (i.e
25-- without typechecking).
26-- This will include all the functions and data declarations, plus fixity declarations
29data IState = IState { tt_ctxt :: Context,
30 idris_infixes :: [FixDecl],
31 idris_implicits :: Ctxt [PArg],
32 idris_statics :: Ctxt [Bool],
34 idris_options :: IOption,
36 idris_metavars :: [Name],
37 syntax_rules :: [Syntax],
38 syntax_keywords :: [String],
39 imported :: [FilePath],
40 idris_prims :: [(Name, ([E.Name], E.Term))]
43idrisInit = IState emptyContext [] emptyContext emptyContext
44 "" defaultOpts 6 [] [] [] [] []
46-- The monad for the main REPL - reading and processing files and updating
47-- global state (hence the IO inner monad).
48type Idris a = StateT IState IO a
51getContext :: Idris Context
52getContext = do i <- get; return (tt_ctxt i)
54getIState :: Idris IState
57putIState :: IState -> Idris ()
62 let idx = idris_name i;
63 put (i { idris_name = idx + 1 })
66checkUndefined :: FC -> Name -> Idris ()
69 case lookupCtxt n i of
70 Just _ -> fail $ show fc ++ ":" ++
71 show n ++ " already defined"
74setContext :: Context -> Idris ()
75setContext ctxt = do i <- get; put (i { tt_ctxt = ctxt } )
77updateContext :: (Context -> Context) -> Idris ()
78updateContext f = do i <- get; put (i { tt_ctxt = f (tt_ctxt i) } )
80addDeferred :: [(Name, Type)] -> Idris ()
81addDeferred ns = do mapM_ (\(n, t) -> updateContext (addTyDecl n t)) ns
83 put (i { idris_metavars = map fst ns ++ idris_metavars i })
85solveDeferred :: Name -> Idris ()
86solveDeferred n = do i <- get
87 put (i { idris_metavars = idris_metavars i \\ [n] })
89iputStrLn :: String -> Idris ()
90iputStrLn = lift.putStrLn
92setLogLevel :: Int -> Idris ()
93setLogLevel l = do i <- get
94 let opts = idris_options i
95 let opt' = opts { opt_logLevel = l }
96 put (i { idris_options = opt' } )
100 return (opt_logLevel (idris_options i))
102logLvl :: Int -> String -> Idris ()
103logLvl l str = do i <- get
104 let lvl = opt_logLevel (idris_options i)
106 $ do lift (putStrLn str)
107 put (i { idris_log = idris_log i ++ str ++ "\n" } )
109iLOG :: String -> Idris ()
112setTypeCase :: Bool -> Idris ()
113setTypeCase t = do i <- get
114 let opts = idris_options i
115 let opt' = opts { opt_typecase = t }
116 put (i { idris_options = opt' })
118-- Commands in the REPL
120data Command = Quit | Help | Eval PTerm
122 | Metavars | Prove Name
124 | LogLvl Int | Spec PTerm | HNF PTerm
127-- Parsed declarations
129data Fixity = Infixl { prec :: Int }
130 | Infixr { prec :: Int }
131 | InfixN { prec :: Int }
132 | PrefixN { prec :: Int }
135instance Show Fixity where
136 show (Infixl i) = "infixl " ++ show i
137 show (Infixr i) = "infixr " ++ show i
138 show (InfixN i) = "infix " ++ show i
139 show (PrefixN i) = "prefix " ++ show i
141data FixDecl = Fix Fixity String
144instance Ord FixDecl where
145 compare (Fix x _) (Fix y _) = compare (prec x) (prec y)
148data Static = Static | Dynamic
151-- Mark bindings with their explicitness, and laziness
152data Plicity = Imp { plazy :: Bool,
154 | Exp { plazy :: Bool,
158impl = Imp False Dynamic
159expl = Exp False Dynamic
161data PDecl' t = PFix FC Fixity [String] -- fixity declaration
162 | PTy FC Name t -- type declaration
163 | PClauses FC Name [PClause' t] -- pattern clause
164 | PData FC (PData' t) -- data declaration
165 | PParams FC [(Name, PTerm)] [PDecl' t] -- params block
169data PClause' t = PClause Name t [t] t [PDecl]
170 | PWith Name t [t] t [PDecl]
173data PData' t = PDatadecl { d_name :: Name,
175 d_cons :: [(Name, t, FC)] }
178-- Handy to get a free function for applying PTerm -> PTerm functions
179-- across a program, by deriving Functor
181type PDecl = PDecl' PTerm
182type PData = PData' PTerm
183type PClause = PClause' PTerm
185-- get all the names declared in a decl
187declared :: PDecl -> [Name]
188declared (PFix _ _ _) = []
189declared (PTy _ n t) = [n]
190declared (PClauses _ n _) = [] -- not a declaration
191declared (PData _ (PDatadecl n _ ts)) = n : map fstt ts
192 where fstt (a, _, _) = a
193declared (PParams _ _ ds) = concatMap declared ds
194-- declared (PImport _) = []
196-- High level language terms
198data PTerm = PQuote Raw
200 | PLam Name PTerm PTerm
201 | PPi Plicity Name PTerm PTerm
202 | PLet Name PTerm PTerm PTerm
203 | PApp FC PTerm [PArg]
208 | PPair FC PTerm PTerm
209 | PDPair FC PTerm PTerm
210 | PHidden PTerm -- irrelevant or hidden pattern
218 | PElabError String -- error to report on elaboration
221data PTactic = Intro [Name]
226 | ProofState | ProofTerm
230data PDo = DoExp FC PTerm
231 | DoBind FC Name PTerm
232 | DoLet FC Name PTerm
235data PArg' t = PImp { lazyarg :: Bool, pname :: Name, getTm :: t }
236 | PExp { lazyarg :: Bool, getTm :: t }
237 deriving (Show, Eq, Functor)
242type PArg = PArg' PTerm
244-- Syntactic sugar info (TODO: namespaces, modules)
246data DSL = DSL { dsl_bind :: Name,
250data Syntax = Rule [SSymbol] PTerm
253data SSymbol = Keyword Name
258initDSL = DSL (UN ["io_bind"]) (UN ["io_return"])
260data SyntaxInfo = Syn { using :: [(Name, PTerm)],
261 syn_params :: [(Name, PTerm)],
266defaultSyntax = Syn [] [] [] initDSL
268--- Pretty printing declarations and terms
270instance Show PTerm where
271 show tm = showImp False tm
273instance Show PDecl where
274 show (PFix _ f ops) = show f ++ " " ++ showSep ", " ops
275 show (PTy _ n ty) = show n ++ " : " ++ show ty
276 show (PClauses _ n c) = showSep "\n" (map show c)
277 show (PData _ d) = show d
279instance Show PClause where
280 show c = showCImp True c
282instance Show PData where
283 show d = showDImp False d
285showCImp :: Bool -> PClause -> String
286showCImp impl (PClause n l ws r w)
287 = showImp impl l ++ showWs ws ++ " = " ++ showImp impl r
288 ++ " where " ++ show w
291 showWs (x : xs) = " | " ++ showImp impl x ++ showWs xs
292showCImp impl (PWith n l ws r w)
293 = showImp impl l ++ showWs ws ++ " with " ++ showImp impl r
294 ++ " { " ++ show w ++ " } "
297 showWs (x : xs) = " | " ++ showImp impl x ++ showWs xs
300showDImp :: Bool -> PData -> String
301showDImp impl (PDatadecl n ty cons)
302 = "data " ++ show n ++ " : " ++ showImp impl ty ++ " where\n\t"
304 (map (\ (n, t, _) -> show n ++ " : " ++ showImp impl t) cons)
306getImps :: [PArg] -> [(Name, PTerm)]
308getImps (PImp _ n tm : xs) = (n, tm) : getImps xs
309getImps (_ : xs) = getImps xs
311getExps :: [PArg] -> [PTerm]
313getExps (PExp _ tm : xs) = tm : getExps xs
314getExps (_ : xs) = getExps xs
316getAll :: [PArg] -> [PTerm]
319showImp :: Bool -> PTerm -> String
320showImp impl tm = se 10 tm where
321 se p (PQuote r) = "![" ++ show r ++ "]"
322 se p (PRef _ n) = show n
323 se p (PLam n ty sc) = bracket p 2 $ "\\ " ++ show n ++ " => " ++ show sc
324 se p (PLet n ty v sc) = bracket p 2 $ "let " ++ show n ++ " = " ++ se 10 v ++
326 se p (PPi (Exp l s) n ty sc)
327 | n `elem` allNamesIn sc = bracket p 2 $
328 if l then "|(" else "(" ++
329 show n ++ " : " ++ se 10 ty ++
332 | otherwise = bracket p 2 $ se 0 ty ++ " " ++ st ++ "-> " ++ se 10 sc
334 Static -> "[static] "
336 se p (PPi (Imp l s) n ty sc)
337 | impl = bracket p 2 $ if l then "|{" else "{" ++
338 show n ++ " : " ++ se 10 ty ++
339 "} " ++ st ++ "-> " ++ se 10 sc
340 | otherwise = se 10 sc
342 Static -> "[static] "
344 se p (PApp _ (PRef _ f) [])
346 se p (PApp _ (PRef _ op@(UN [f:_])) args)
347 | length (getExps args) == 2 && not impl && not (isAlpha f)
348 = let [l, r] = getExps args in
349 bracket p 1 $ se 1 l ++ " " ++ show op ++ " " ++ se 0 r
351 = let (imps, args) = (getImps as, getExps as) in
352 bracket p 1 $ se 1 f ++ (if impl then concatMap siArg imps else "")
353 ++ concatMap seArg args
354 se p (PHidden tm) = "." ++ se 0 tm
355 se p (PRefl _) = "refl"
356 se p (PTrue _) = "()"
357 se p (PFalse _) = "_|_"
358 se p (PEq _ l r) = bracket p 2 $ se 10 l ++ " = " ++ se 10 r
359 se p (PPair _ l r) = "(" ++ se 10 l ++ ", " ++ se 10 r ++ ")"
360 se p (PDPair _ l r) = "(" ++ se 10 l ++ " ** " ++ se 10 r ++ ")"
362 se p (PConstant c) = show c
363 se p (PProof ts) = "proof { " ++ show ts ++ "}"
364 se p (PMetavar n) = "?" ++ show n
365 se p Placeholder = "_"
367 seArg arg = " " ++ se 0 arg
368 siArg (n, val) = " {" ++ show n ++ " = " ++ se 10 val ++ "}"
370 bracket outer inner str | inner > outer = "(" ++ str ++ ")"
373allNamesIn :: PTerm -> [Name]
374allNamesIn tm = nub $ ni [] tm
377 | not (n `elem` env) = [n]
378 ni env (PApp _ f as) = ni env f ++ concatMap (ni env) (map getTm as)
379 ni env (PLam n ty sc) = ni env ty ++ ni (n:env) sc
380 ni env (PPi _ n ty sc) = ni env ty ++ ni (n:env) sc
381 ni env (PHidden tm) = ni env tm
382 ni env (PEq _ l r) = ni env l ++ ni env r
383 ni env (PPair _ l r) = ni env l ++ ni env r
384 ni env (PDPair _ l r) = ni env l ++ ni env r
387namesIn :: IState -> PTerm -> [Name]
388namesIn ist tm = nub $ ni [] tm
392 = case lookupCtxt n (idris_implicits ist) of
395 ni env (PApp _ f as) = ni env f ++ concatMap (ni env) (map getTm as)
396 ni env (PLam n ty sc) = ni env ty ++ ni (n:env) sc
397 ni env (PPi _ n ty sc) = ni env ty ++ ni (n:env) sc
398 ni env (PEq _ l r) = ni env l ++ ni env r
399 ni env (PPair _ l r) = ni env l ++ ni env r
400 ni env (PDPair _ l r) = ni env l ++ ni env r
401 ni env (PHidden tm) = ni env tm
404-- For inferring types of things
408inferTy = MN 0 "__Infer"
409inferCon = MN 0 "__infer"
410inferDecl = PDatadecl inferTy
412 [(inferCon, PPi impl (MN 0 "A") PSet (
413 PPi expl (MN 0 "a") (PRef bi (MN 0 "A"))
414 (PRef bi inferTy)), bi)]
416infTerm t = PApp bi (PRef bi inferCon) [pimp (MN 0 "A") Placeholder, pexp t]
417infP = P (TCon 6 0) inferTy (Set 0)
419getInferTerm, getInferType :: Term -> Term
420getInferTerm (Bind n b sc) = Bind n b $ getInferTerm sc
421getInferTerm (App (App _ _) tm) = tm
422getInferTerm tm = error ("getInferTerm " ++ show tm)
424getInferType (Bind n b sc) = Bind n b $ getInferType sc
425getInferType (App (App _ ty) _) = ty
427-- Handy primitives: Unit, False, Pair, MkPair, =, mkForeign
429unitTy = MN 0 "__Unit"
431unitDecl = PDatadecl unitTy PSet
432 [(unitCon, PRef bi unitTy, bi)]
434falseTy = MN 0 "__False"
435falseDecl = PDatadecl falseTy PSet []
437pairTy = MN 0 "__Pair"
438pairCon = MN 0 "__MkPair"
439pairDecl = PDatadecl pairTy (piBind [(n "A", PSet), (n "B", PSet)] PSet)
440 [(pairCon, PPi impl (n "A") PSet (
441 PPi impl (n "B") PSet (
442 PPi expl (n "a") (PRef bi (n "A")) (
443 PPi expl (n "b") (PRef bi (n "B"))
444 (PApp bi (PRef bi pairTy) [pexp (PRef bi (n "A")),
445 pexp (PRef bi (n "B"))])))), bi)]
450eqDecl = PDatadecl eqTy (piBind [(n "a", PSet), (n "b", PSet),
451 (n "x", PRef bi (n "a")), (n "y", PRef bi (n "b"))]
453 [(eqCon, PPi impl (n "a") PSet (
454 PPi impl (n "x") (PRef bi (n "a"))
455 (PApp bi (PRef bi eqTy) [pimp (n "a") Placeholder,
456 pimp (n "b") Placeholder,
457 pexp (PRef bi (n "x")),
458 pexp (PRef bi (n "x"))])), bi)]
461-- Defined in builtins.idr
462sigmaTy = UN ["Sigma"]
463existsCon = UN ["Exists"]
465piBind :: [(Name, PTerm)] -> PTerm -> PTerm
467piBind ((n, ty):ns) t = PPi expl n ty (piBind ns t)
469-- Dealing with implicit arguments
471-- Add implicit Pi bindings for any names in the term which appear in an
474-- This has become a right mess already. Better redo it some time...
476implicitise :: SyntaxInfo -> IState -> PTerm -> (PTerm, [PArg])
477implicitise syn ist tm
478 = let uvars = using syn
479 pvars = syn_params syn
480 (declimps, ns') = execState (imps True [] tm) ([], [])
481 ns = ns' \\ (map fst pvars ++ no_imp syn) in
483 then (tm, reverse declimps)
484 else implicitise syn ist (pibind uvars ns tm)
486 dropAll (x:xs) ys | x `elem` ys = dropAll xs ys
487 | otherwise = x : dropAll xs ys
490 imps top env (PApp _ f as)
491 = do (decls, ns) <- get
492 let isn = concatMap (namesIn ist) (map getTm as)
493 put (decls, nub (ns ++ (isn `dropAll` (env ++ map fst (getImps decls)))))
494 imps top env (PPi (Imp l _) n ty sc)
495 = do let isn = nub (namesIn ist ty) `dropAll` [n]
497 put (PImp l n ty : decls,
498 nub (ns ++ (isn `dropAll` (env ++ map fst (getImps decls)))))
500 imps top env (PPi (Exp l _) n ty sc)
501 = do let isn = nub (namesIn ist ty ++ case sc of
502 (PRef _ x) -> namesIn ist sc `dropAll` [n]
504 (decls, ns) <- get -- ignore decls in HO types
505 put (PExp l ty : decls,
506 nub (ns ++ (isn `dropAll` (env ++ map fst (getImps decls)))))
508 imps top env (PEq _ l r)
509 = do (decls, ns) <- get
510 let isn = namesIn ist l ++ namesIn ist r
511 put (decls, nub (ns ++ (isn `dropAll` (env ++ map fst (getImps decls)))))
512 imps top env (PPair _ l r)
513 = do (decls, ns) <- get
514 let isn = namesIn ist l ++ namesIn ist r
515 put (decls, nub (ns ++ (isn `dropAll` (env ++ map fst (getImps decls)))))
516 imps top env (PDPair _ (PRef _ n) r)
517 = do (decls, ns) <- get
518 let isn = nub (namesIn ist r) \\ [n]
519 put (decls, nub (ns ++ (isn \\ (env ++ map fst (getImps decls)))))
520 imps top env (PDPair _ l r)
521 = do (decls, ns) <- get
522 let isn = namesIn ist l ++ namesIn ist r
523 put (decls, nub (ns ++ (isn \\ (env ++ map fst (getImps decls)))))
524 imps top env (PLam n ty sc)
525 = do imps False env ty
526 imps False (n:env) sc
527 imps top env (PHidden tm) = imps False env tm
528 imps top env _ = return ()
530 pibind using [] sc = sc
531 pibind using (n:ns) sc
532 = case lookup n using of
533 Just ty -> PPi (Imp False Dynamic) n ty (pibind using ns sc)
534 Nothing -> PPi (Imp False Dynamic) n Placeholder (pibind using ns sc)
536-- Add implicit arguments in function calls
538addImpl :: IState -> PTerm -> PTerm
539addImpl ist ptm = ai [] ptm
541 ai env (PRef fc f) = aiFn fc env (PRef fc f) []
542 ai env (PEq fc l r) = let l' = ai env l
545 ai env (PPair fc l r) = let l' = ai env l
548 ai env (PDPair fc l r) = let l' = ai env l
551 ai env (PApp fc (PRef _ f) as)
552 = let as' = map (fmap (ai env)) as in
553 aiFn fc env (PRef fc f) as'
554 ai env (PApp fc f as) = let f' = ai env f
555 as' = map (fmap (ai env)) as in
557 ai env (PLam n ty sc) = let ty' = ai env ty
558 sc' = ai (n:env) sc in
560 ai env (PLet n ty val sc)
561 = let ty' = ai env ty
563 sc' = ai (n:env) sc in
565 ai env (PPi p n ty sc) = let ty' = ai env ty
566 sc' = ai (n:env) sc in
568 ai env (PHidden tm) = PHidden (ai env tm)
571 aiFn _ env (PRef fc f) as | not (f `elem` env)
572 = case lookupCtxt f (idris_implicits ist) of
573 Just ns -> pApp fc (length ns) (PRef fc f) (insertImpl ns as)
574 Nothing -> pApp fc 1 (PRef fc f) as
575 aiFn fc env f as = pApp fc 1 f as
578 pApp fc a f as = let rest = drop a as in
579 appRest fc (PApp fc f (take a as)) rest
582 appRest fc f (a : as) = appRest fc (PApp fc f [a]) as
584 insertImpl :: [PArg] -> [PArg] -> [PArg]
585 insertImpl (PExp l ty : ps) (PExp _ tm : given) =
586 PExp l tm : insertImpl ps given
587 insertImpl (PImp l n ty : ps) given =
588 case find n given [] of
589 Just (tm, given') -> PImp l n tm : insertImpl ps given'
590 Nothing -> PImp l n Placeholder : insertImpl ps given
591 insertImpl expected [] = []
592 insertImpl [] given = given
594 find n [] acc = Nothing
595 find n (PImp _ n' t : gs) acc
596 | n == n' = Just (t, reverse acc ++ gs)
597 find n (g : gs) acc = find n gs (g : acc)
599-- Find 'static' argument positions
600-- (the declared ones, plus any names in argument position in the declared
602-- FIXME: It's possible that this really has to happen after elaboration
604findStatics :: IState -> PTerm -> (PTerm, [Bool])
605findStatics ist tm = let (ns, ss) = fs tm in
606 runState (pos ns ss tm) []
607 where fs (PPi p n t sc)
608 | Static <- pstatic p
609 = let (ns, ss) = fs sc in
610 (namesIn ist t : ns, namesIn ist t ++ n : ss)
611 | otherwise = let (ns, ss) = fs sc in
612 (namesIn ist t : ns, ss)
615 inOne n ns = length (filter id (map (elem n) ns)) == 1
617 pos ns ss (PPi p n t sc)
618 | n `inOne` ns && elem n ss
619 = do sc' <- pos ns ss sc
622 return (PPi (p { pstatic = Static }) n t sc')
623 | otherwise = do sc' <- pos ns ss sc
626 return (PPi p n t sc')
627 pos ns ss t = return t
629-- Debugging/logging stuff
631dumpDecls :: [PDecl] -> String
633dumpDecls (d:ds) = dumpDecl d ++ "\n" ++ dumpDecls ds
635dumpDecl (PFix _ f ops) = show f ++ " " ++ showSep ", " ops
636dumpDecl (PTy _ n t) = "tydecl " ++ show n ++ " : " ++ showImp True t
637dumpDecl (PClauses _ n cs) = "pat\t" ++ showSep "\n\t" (map (showCImp True) cs)
638dumpDecl (PData _ d) = showDImp True d
639dumpDecl (PParams _ ns ps) = "params {" ++ show ns ++ "\n" ++ dumpDecls ps ++ "}\n"
640dumpDecl (PSyntax _ syn) = "syntax " ++ show syn
641-- dumpDecl (PImport i) = "import " ++ i
643-- syntactic match of a against b, returning pair of variables in a
644-- and what they match. Returns 'Nothing' if not a match.
646matchClause :: PTerm -> PTerm -> Maybe [(Name, PTerm)]
647matchClause x y = match x y where
648 matchArg x y = match (getTm x) (getTm y)
650 match (PApp _ f args) (PApp _ f' args')
651 | length args == length args'
652 = do mf <- match f f'
653 ms <- zipWithM matchArg args args'
654 return (mf ++ concat ms)
655 match (PRef _ n) (PRef _ n') | n == n' = return []
656 | otherwise = Nothing
657 match (PRef _ n) tm = return [(n, tm)]
658 match (PEq _ l r) (PEq _ l' r') = do ml <- match l l'
661 match (PPair _ l r) (PPair _ l' r') = do ml <- match l l'
664 match (PDPair _ l r) (PDPair _ l' r') = do ml <- match l l'
667 match (PRefl _) (PRefl _) = return []
668 match (PTrue _) (PTrue _) = return []
669 match (PFalse _) (PFalse _) = return []
670 match (PReturn _) (PReturn _) = return []
671 match (PPi _ _ t s) (PPi _ _ t' s') = do mt <- match t t'
674 match (PLam _ t s) (PLam _ t' s') = do mt <- match t t'
677 match (PHidden x) (PHidden y) = match x y
678 match a b | a == b = return []
679 | otherwise = Nothing
681substMatches :: [(Name, PTerm)] -> PTerm -> PTerm
683substMatches ((n,tm):ns) t = substMatch n tm (substMatches ns t)
685substMatch :: Name -> PTerm -> PTerm -> PTerm
686substMatch n tm t = sm t where
687 sm (PRef _ n') | n == n' = tm
688 sm (PLam x t sc) = PLam x (sm t) (sm sc)
689 sm (PPi p x t sc) = PPi p x (sm t) (sm sc)
690 sm (PApp f x as) = PApp f (sm x) (map (fmap sm) as)
691 sm (PEq f x y) = PEq f (sm x) (sm y)
692 sm (PPair f x y) = PPair f (sm x) (sm y)
693 sm (PDPair f x y) = PDPair f (sm x) (sm y)
694 sm (PHidden x) = PHidden (sm x)
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