1{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, DeriveFunctor,
2 TypeSynonymInstances #-}
4module Idris.AbsSyntax where
9import Control.Monad.State
14import qualified Epic.Epic as E
16data IOption = IOption { opt_logLevel :: Int }
19defaultOpts = IOption 0
21-- TODO: Add 'module data' to IState, which can be saved out and reloaded quickly (i.e
22-- without typechecking).
23-- This will include all the functions and data declarations, plus fixity declarations
26data IState = IState { tt_ctxt :: Context,
27 idris_infixes :: [FixDecl],
28 idris_implicits :: Ctxt [PArg],
30 idris_options :: IOption,
32 idris_metavars :: [Name],
33 syntax_rules :: [Syntax],
34 imported :: [FilePath],
35 idris_prims :: [(Name, ([E.Name], E.Term))]
38idrisInit = IState emptyContext [] emptyContext "" defaultOpts 0 [] [] [] []
40-- The monad for the main REPL - reading and processing files and updating
41-- global state (hence the IO inner monad).
42type Idris a = StateT IState IO a
44getContext :: Idris Context
45getContext = do i <- get; return (tt_ctxt i)
47getIState :: Idris IState
50putIState :: IState -> Idris ()
55 let idx = idris_name i;
56 put (i { idris_name = idx + 1 })
59checkUndefined :: FC -> Name -> Idris ()
62 case lookupCtxt n i of
63 Just _ -> fail $ show fc ++ ":" ++
64 show n ++ " already defined"
67setContext :: Context -> Idris ()
68setContext ctxt = do i <- get; put (i { tt_ctxt = ctxt } )
70updateContext :: (Context -> Context) -> Idris ()
71updateContext f = do i <- get; put (i { tt_ctxt = f (tt_ctxt i) } )
73addDeferred :: [(Name, Type)] -> Idris ()
74addDeferred ns = do mapM_ (\(n, t) -> updateContext (addTyDecl n t)) ns
76 put (i { idris_metavars = map fst ns ++ idris_metavars i })
78solveDeferred :: Name -> Idris ()
79solveDeferred n = do i <- get
80 put (i { idris_metavars = idris_metavars i \\ [n] })
82iputStrLn :: String -> Idris ()
83iputStrLn = lift.putStrLn
85setLogLevel :: Int -> Idris ()
86setLogLevel l = do i <- get
87 let opts = idris_options i
88 let opt' = opts { opt_logLevel = l }
89 put (i { idris_options = opt' } )
93 return (opt_logLevel (idris_options i))
95logLvl :: Int -> String -> Idris ()
96logLvl l str = do i <- get
97 let lvl = opt_logLevel (idris_options i)
99 $ do lift (putStrLn str)
100 put (i { idris_log = idris_log i ++ str ++ "\n" } )
102iLOG :: String -> Idris ()
105-- Commands in the REPL
107data Command = Quit | Help | Eval PTerm
113-- Parsed declarations
115data Fixity = Infixl { prec :: Int }
116 | Infixr { prec :: Int }
117 | InfixN { prec :: Int }
118 | PrefixN { prec :: Int }
121instance Show Fixity where
122 show (Infixl i) = "infixl " ++ show i
123 show (Infixr i) = "infixr " ++ show i
124 show (InfixN i) = "infix " ++ show i
125 show (PrefixN i) = "prefix " ++ show i
127data FixDecl = Fix Fixity String
130instance Ord FixDecl where
131 compare (Fix x _) (Fix y _) = compare (prec x) (prec y)
133data Plicity = Imp | Exp deriving Show
135data PDecl' t = PFix FC Fixity [String] -- fixity declaration
136 | PTy FC Name t -- type declaration
137 | PClauses FC Name [PClause' t] -- pattern clause
138 | PData FC (PData' t) -- data declaration
139 | PParams FC [(Name, PTerm)] [PDecl' t] -- params block
143data PClause' t = PClause Name t [t] t [PDecl]
144 | PWith Name t [t] t [PDecl]
147data PData' t = PDatadecl { d_name :: Name,
149 d_cons :: [(Name, t, FC)] }
152-- Handy to get a free function for applying PTerm -> PTerm functions
153-- across a program, by deriving Functor
155type PDecl = PDecl' PTerm
156type PData = PData' PTerm
157type PClause = PClause' PTerm
159-- get all the names declared in a decl
161declared :: PDecl -> [Name]
162declared (PFix _ _ _) = []
163declared (PTy _ n t) = [n]
164declared (PClauses _ n _) = [] -- not a declaration
165declared (PData _ (PDatadecl n _ ts)) = n : map fstt ts
166 where fstt (a, _, _) = a
167declared (PParams _ _ ds) = concatMap declared ds
168-- declared (PImport _) = []
170-- High level language terms
172data PTerm = PQuote Raw
174 | PLam Name PTerm PTerm
175 | PPi Plicity Name PTerm PTerm
176 | PLet Name PTerm PTerm PTerm -- not implemented yet
177 | PApp FC PTerm [PArg]
180 | PPair FC PTerm PTerm
181 | PHidden PTerm -- irrelevant or hidden pattern
188 | PElabError String -- error to report on elaboration
190data PDo = DoExp FC PTerm
191 | DoBind FC Name PTerm
192 | DoLet FC Name PTerm
194data PArg' t = PImp { pname :: Name, getTm :: t }
195 | PExp { getTm :: t }
196 deriving (Show, Functor)
198type PArg = PArg' PTerm
200-- Syntactic sugar info (TODO: namespaces, modules)
202data DSL = DSL { dsl_bind :: Name,
206data Syntax = Rule [SSymbol] PTerm
209data SSymbol = Keyword Name
214initDSL = DSL (UN ["io_bind"]) (UN ["io_return"])
216data SyntaxInfo = Syn { using :: [(Name, PTerm)],
217 syn_params :: [(Name, PTerm)],
221defaultSyntax = Syn [] [] initDSL
223--- Pretty printing declarations and terms
225instance Show PTerm where
226 show tm = showImp False tm
228instance Show PDecl where
229 show (PFix _ f ops) = show f ++ " " ++ showSep ", " ops
230 show (PTy _ n ty) = show n ++ " : " ++ show ty
231 show (PClauses _ n c) = showSep "\n" (map show c)
232 show (PData _ d) = show d
234instance Show PClause where
235 show c = showCImp True c
237instance Show PData where
238 show d = showDImp False d
240showCImp :: Bool -> PClause -> String
241showCImp impl (PClause n l ws r w)
242 = showImp impl l ++ showWs ws ++ " = " ++ showImp impl r
243 ++ " where " ++ show w
246 showWs (x : xs) = " | " ++ showImp impl x ++ showWs xs
247showCImp impl (PWith n l ws r w)
248 = showImp impl l ++ showWs ws ++ " with " ++ showImp impl r
249 ++ " { " ++ show w ++ " } "
252 showWs (x : xs) = " | " ++ showImp impl x ++ showWs xs
255showDImp :: Bool -> PData -> String
256showDImp impl (PDatadecl n ty cons)
257 = "data " ++ show n ++ " : " ++ showImp impl ty ++ " where\n\t"
259 (map (\ (n, t, _) -> show n ++ " : " ++ showImp impl t) cons)
261getImps :: [PArg] -> [(Name, PTerm)]
263getImps (PImp n tm : xs) = (n, tm) : getImps xs
264getImps (_ : xs) = getImps xs
266getExps :: [PArg] -> [PTerm]
268getExps (PExp tm : xs) = tm : getExps xs
269getExps (_ : xs) = getExps xs
271getAll :: [PArg] -> [PTerm]
274showImp :: Bool -> PTerm -> String
275showImp impl tm = se 10 tm where
276 se p (PQuote r) = "![" ++ show r ++ "]"
277 se p (PRef _ n) = show n
278 se p (PLam n ty sc) = bracket p 2 $ "\\ " ++ show n ++ " => " ++ show sc
279 se p (PLet n ty v sc) = bracket p 2 $ "let " ++ show n ++ " = " ++ se 10 v ++
281 se p (PPi Exp n ty sc)
282 | n `elem` allNamesIn sc = bracket p 2 $
283 "(" ++ show n ++ " : " ++ se 10 ty ++
285 | otherwise = bracket p 2 $ se 0 ty ++ " -> " ++ se 10 sc
286 se p (PPi Imp n ty sc)
287 | impl = bracket p 2 $ "{" ++ show n ++ " : " ++ se 10 ty ++
289 | otherwise = se 10 sc
290 se p (PApp _ (PRef _ f) [])
292 se p (PApp _ (PRef _ op@(UN [f:_])) args)
293 | length (getExps args) == 2 && not impl && not (isAlpha f)
294 = let [l, r] = getExps args in
295 bracket p 1 $ se 1 l ++ " " ++ show op ++ " " ++ se 0 r
297 = let (imps, args) = (getImps as, getExps as) in
298 bracket p 1 $ se 1 f ++ (if impl then concatMap siArg imps else "")
299 ++ concatMap seArg args
300 se p (PHidden tm) = "." ++ se 0 tm
301 se p (PTrue _) = "()"
302 se p (PFalse _) = "_|_"
303 se p (PPair _ l r) = "(" ++ se 10 l ++ ", " ++ se 10 r ++ ")"
305 se p (PConstant c) = show c
306 se p (PMetavar n) = "?" ++ show n
307 se p Placeholder = "_"
309 seArg arg = " " ++ se 0 arg
310 siArg (n, val) = " {" ++ show n ++ " = " ++ se 10 val ++ "}"
312 bracket outer inner str | inner > outer = "(" ++ str ++ ")"
315allNamesIn :: PTerm -> [Name]
316allNamesIn tm = nub $ ni [] tm
319 | not (n `elem` env) = [n]
320 ni env (PApp _ f as) = ni env f ++ concatMap (ni env) (map getTm as)
321 ni env (PLam n ty sc) = ni env ty ++ ni (n:env) sc
322 ni env (PPi _ n ty sc) = ni env ty ++ ni (n:env) sc
323 ni env (PHidden tm) = ni env tm
324 ni env (PPair _ l r) = ni env l ++ ni env r
327namesIn :: IState -> PTerm -> [Name]
328namesIn ist tm = nub $ ni [] tm
332 = case lookupCtxt n (idris_implicits ist) of
335 ni env (PApp _ f as) = ni env f ++ concatMap (ni env) (map getTm as)
336 ni env (PLam n ty sc) = ni env ty ++ ni (n:env) sc
337 ni env (PPi _ n ty sc) = ni env ty ++ ni (n:env) sc
338 ni env (PPair _ l r) = ni env l ++ ni env r
339 ni env (PHidden tm) = ni env tm
342-- For inferring types of things
346inferTy = MN 0 "__Infer"
347inferCon = MN 0 "__infer"
348inferDecl = PDatadecl inferTy
350 [(inferCon, PPi Imp (MN 0 "A") PSet (
351 PPi Exp (MN 0 "a") (PRef bi (MN 0 "A"))
352 (PRef bi inferTy)), bi)]
354infTerm t = PApp bi (PRef bi inferCon) [PImp (MN 0 "A") Placeholder, PExp t]
355infP = P (TCon 0) inferTy (Set 0)
357getInferTerm, getInferType :: Term -> Term
358getInferTerm (Bind n b sc) = Bind n b $ getInferTerm sc
359getInferTerm (App (App _ _) tm) = tm
360getInferTerm tm = error ("getInferTerm " ++ show tm)
362getInferType (Bind n b sc) = Bind n b $ getInferType sc
363getInferType (App (App _ ty) _) = ty
365-- Handy primitives: Unit, False, Pair, MkPair, mkForeign
368unitTy = MN 0 "__Unit"
370unitDecl = PDatadecl unitTy PSet
371 [(unitCon, PRef bi unitTy, bi)]
373falseTy = MN 0 "__False"
374falseDecl = PDatadecl falseTy PSet []
376pairTy = UN ["Pair"] -- MN 0 "__Pair"
377pairCon = UN ["MkPair"] -- MN 0 "__MkPair"
378pairDecl = PDatadecl pairTy (piBind [(n "A", PSet), (n "B", PSet)] PSet)
379 [(pairCon, PPi Imp (n "A") PSet (
380 PPi Imp (n "B") PSet (
381 PPi Exp (n "a") (PRef bi (n "A")) (
382 PPi Exp (n "b") (PRef bi (n "B"))
383 (PApp bi (PRef bi pairTy) [PExp (PRef bi (n "A")),
384 PExp (PRef bi (n "B"))])))), bi)]
387piBind :: [(Name, PTerm)] -> PTerm -> PTerm
389piBind ((n, ty):ns) t = PPi Exp n ty (piBind ns t)
391-- Dealing with implicit arguments
393-- Add implicit Pi bindings for any names in the term which appear in an
396implicitise :: SyntaxInfo -> IState -> PTerm -> (PTerm, [PArg])
397implicitise syn ist tm
398 = let uvars = using syn
399 pvars = syn_params syn
400 (declimps, ns') = execState (imps True [] tm) ([], [])
401 ns = ns' \\ map fst pvars in
403 then (tm, reverse declimps)
404 else implicitise syn ist (pibind uvars ns tm)
406 imps top env (PApp _ f as)
407 = do (decls, ns) <- get
408 let isn = concatMap (namesIn ist) (map getTm as)
409 put (decls, nub (ns ++ (isn \\ (env ++ map fst (getImps decls)))))
410 imps top env (PPi Imp n ty sc)
411 = do let isn = namesIn ist ty \\ [n]
413 put (PImp n ty : decls, nub (ns ++ (isn \\ (env ++ map fst (getImps decls)))))
415 imps top env (PPi Exp n ty sc)
416 = do let isn = (namesIn ist ty ++ case sc of
417 (PRef _ x) -> namesIn ist sc
419 (decls, ns) <- get -- ignore decls in HO types
420 put (PExp ty : decls, nub (ns ++ (isn \\ (env ++ map fst (getImps decls)))))
422 imps top env (PPair _ l r)
423 = do (decls, ns) <- get
424 put (decls, nub (ns ++ namesIn ist l ++ namesIn ist r))
425 imps top env (PLam n ty sc)
426 = do imps False env ty
427 imps False (n:env) sc
428 imps top env (PHidden tm) = imps False env tm
429 imps top env _ = return ()
431 pibind using [] sc = sc
432 pibind using (n:ns) sc = case lookup n using of
433 Just ty -> PPi Imp n ty (pibind using ns sc)
434 Nothing -> PPi Imp n Placeholder (pibind using ns sc)
436-- Add implicit arguments in function calls
438addImpl :: IState -> PTerm -> PTerm
439addImpl ist ptm = ai [] ptm
441 ai env (PRef fc f) = aiFn fc env (PRef fc f) []
442 ai env (PPair fc l r) = let l' = ai env l
445 ai env (PApp fc (PRef _ f) as)
446 = let as' = map (fmap (ai env)) as in
447 aiFn fc env (PRef fc f) as'
448 ai env (PApp fc f as) = let f' = ai env f
449 as' = map (fmap (ai env)) as in
451 ai env (PLam n ty sc) = let ty' = ai env ty
452 sc' = ai (n:env) sc in
454 ai env (PLet n ty val sc)
455 = let ty' = ai env ty
457 sc' = ai (n:env) sc in
459 ai env (PPi p n ty sc) = let ty' = ai env ty
460 sc' = ai (n:env) sc in
462 ai env (PHidden tm) = PHidden (ai env tm)
465 aiFn _ env (PRef fc f) as | not (f `elem` env)
466 = case lookupCtxt f (idris_implicits ist) of
467 Just ns -> pApp fc (length ns) (PRef fc f) (insertImpl ns as)
468 Nothing -> pApp fc 1 (PRef fc f) as
469 aiFn fc env f as = pApp fc 1 f as
472 pApp fc a f as = let rest = drop a as in
473 appRest fc (PApp fc f (take a as)) rest
476 appRest fc f (a : as) = appRest fc (PApp fc f [a]) as
478 insertImpl :: [PArg] -> [PArg] -> [PArg]
479 insertImpl (PExp ty : ps) (PExp tm : given) =
480 PExp tm : insertImpl ps given
481 insertImpl (PImp n ty : ps) given =
482 case find n given [] of
483 Just (tm, given') -> PImp n tm : insertImpl ps given'
484 Nothing -> PImp n Placeholder : insertImpl ps given
485 insertImpl expected [] = []
486 insertImpl [] given = given
488 find n [] acc = Nothing
489 find n (PImp n' t : gs) acc
490 | n == n' = Just (t, reverse acc ++ gs)
491 find n (g : gs) acc = find n gs (g : acc)
493-- Debugging/logging stuff
495dumpDecls :: [PDecl] -> String
497dumpDecls (d:ds) = dumpDecl d ++ "\n" ++ dumpDecls ds
499dumpDecl (PFix _ f ops) = show f ++ " " ++ showSep ", " ops
500dumpDecl (PTy _ n t) = "tydecl " ++ show n ++ " : " ++ showImp True t
501dumpDecl (PClauses _ n cs) = "pat\t" ++ showSep "\n\t" (map (showCImp True) cs)
502dumpDecl (PData _ d) = showDImp True d
503dumpDecl (PParams _ ns ps) = "params {" ++ show ns ++ "\n" ++ dumpDecls ps ++ "}\n"
504dumpDecl (PSyntax _ syn) = "syntax " ++ show syn
505-- dumpDecl (PImport i) = "import " ++ i
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