1{-# LANGUAGE GeneralizedNewtypeDeriving, ConstraintKinds, PatternGuards #-}
3module Idris.Parser(module Idris.Parser,
4 module Idris.ParseExpr,
5 module Idris.ParseData,
6 module Idris.ParseHelpers,
7 module Idris.ParseOps) where
9import Prelude hiding (pi)
11import qualified System.Directory as Dir (makeAbsolute)
13import Text.Trifecta.Delta
14import Text.Trifecta hiding (span, stringLiteral, charLiteral, natural, symbol, char, string, whiteSpace, Err)
15import Text.Parser.LookAhead
16import Text.Parser.Expression
17import qualified Text.Parser.Token as Tok
18import qualified Text.Parser.Char as Chr
19import qualified Text.Parser.Token.Highlight as Hi
21import Text.PrettyPrint.ANSI.Leijen (Doc, plain)
22import qualified Text.PrettyPrint.ANSI.Leijen as ANSI
24import Idris.AbsSyntax hiding (namespace, params)
27import Idris.Delaborate
29import Idris.Elab.Value
38import Idris.ParseHelpers
43import Idris.Docstrings hiding (Unchecked)
47import Util.DynamicLinker
48import Util.System (readSource, writeSource)
49import qualified Util.Pretty as P
52import Idris.Core.Evaluate
54import Control.Applicative hiding (Const)
56import Control.Monad.State.Strict
60import qualified Data.List.Split as Spl
65import Data.Foldable (asum)
66import Data.Generics.Uniplate.Data (descendM)
67import qualified Data.Map as M
68import qualified Data.HashSet as HS
69import qualified Data.Text as T
70import qualified Data.ByteString.UTF8 as UTF8
71import qualified Data.Set as S
80 grammar shortcut notation:
81 ~CHARSEQ = complement of char sequence (i.e. any character except CHARSEQ)
82 RULE? = optional rule (i.e. RULE or nothing)
83 RULE* = repeated rule (i.e. RULE zero or more times)
84 RULE+ = repeated rule with at least one match (i.e. RULE one or more times)
85 RULE! = invalid rule (i.e. rule that is not valid in context, report meaningful error in case)
86 RULE{n} = rule repeated n times
92{- | Parses module definition
95 ModuleHeader ::= DocComment_t? 'module' Identifier_t ';'?;
98moduleHeader :: IdrisParser (Maybe (Docstring ()), [String], [(FC, OutputAnnotation)])
99moduleHeader = try (do docs <- optional docComment
102 (i, ifc) <- identifier
103 option ';' (lchar ';')
104 let modName = moduleName i
105 return (fmap fst docs,
107 [(ifc, AnnNamespace (map T.pack modName) Nothing)]))
108 <|> try (do lchar '%'; reserved "unqualified"
109 return (Nothing, [], []))
110 <|> return (Nothing, moduleName "Main", [])
111 where moduleName x = case span (/='.') x of
113 (x, '.':y) -> x : moduleName y
114 noArgs (Just (_, args)) | not (null args) = fail "Modules do not take arguments"
117data ImportInfo = ImportInfo { import_reexport :: Bool
118 , import_path :: FilePath
119 , import_rename :: Maybe (String, FC)
120 , import_namespace :: [T.Text]
121 , import_location :: FC
122 , import_modname_location :: FC
125{- | Parses an import statement
128 Import ::= 'import' Identifier_t ';'?;
131import_ :: IdrisParser ImportInfo
132import_ = do fc <- getFC
134 reexport <- option False (do reservedHL "public"
136 (id, idfc) <- identifier
137 newName <- optional (do reservedHL "as"
139 option ';' (lchar ';')
140 return $ ImportInfo reexport (toPath id)
141 (fmap (\(n, fc) -> (toPath n, fc)) newName)
142 (map T.pack $ ns id) fc idfc
143 <?> "import statement"
144 where ns = Spl.splitOn "."
145 toPath = foldl1' (</>) . ns
147{- | Parses program source
153prog :: SyntaxInfo -> IdrisParser [PDecl]
154prog syn = do whiteSpace
155 decls <- many (decl syn)
156 let c = (concat decls)
158 Nothing -> do notOpenBraces; eof
162 put ist { idris_parsedSpan = Just (FC (fc_fname fc) (0,0) (fc_end fc)),
163 ibc_write = IBCParsedRegion fc : ibc_write ist }
166{-| Parses a top-level declaration
185decl :: SyntaxInfo -> IdrisParser [PDecl]
186decl syn = do fc <- getFC
187 -- if we're after maxline, stop here
188 let continue = case maxline syn of
190 Just l -> if fst (fc_end fc) > l
191 then mut_nesting syn /= 0
193 if continue then do notEndBlock
195 else fail "End of readable input"
196 where declBody :: IdrisParser [PDecl]
204 <|> do d <- dsl syn; return [d]
208 <|> do import_; fail "imports must be at top of file"
210 declBody' :: IdrisParser [PDecl]
211 declBody' = do d <- decl' syn
213 let d' = fmap (debindApp syn . (desugar syn i)) d
216{- | Parses a top-level declaration with possible syntax sugar
228decl' :: SyntaxInfo -> IdrisParser PDecl
236{- | Parses a syntax extension declaration (and adds the rule to parser state)
239 SyntaxDecl ::= SyntaxRule;
242syntaxDecl :: SyntaxInfo -> IdrisParser PDecl
243syntaxDecl syn = do s <- syntaxRule syn
245 put (i `addSyntax` s)
247 return (PSyntax fc s)
249-- | Extend an 'IState' with a new syntax extension. See also 'addReplSyntax'.
250addSyntax :: IState -> Syntax -> IState
251addSyntax i s = i { syntax_rules = updateSyntaxRules [s] rs,
252 syntax_keywords = ks ++ ns,
253 ibc_write = IBCSyntax s : map IBCKeyword ks ++ ibc }
254 where rs = syntax_rules i
255 ns = syntax_keywords i
257 ks = map show (syntaxNames s)
259-- | Like 'addSyntax', but no effect on the IBC.
260addReplSyntax :: IState -> Syntax -> IState
261addReplSyntax i s = i { syntax_rules = updateSyntaxRules [s] rs,
262 syntax_keywords = ks ++ ns }
263 where rs = syntax_rules i
264 ns = syntax_keywords i
265 ks = map show (syntaxNames s)
267{- | Parses a syntax extension declaration
270SyntaxRuleOpts ::= 'term' | 'pattern';
275 SyntaxRuleOpts? 'syntax' SyntaxSym+ '=' TypeExpr Terminator;
279SyntaxSym ::= '[' Name_t ']'
286syntaxRule :: SyntaxInfo -> IdrisParser Syntax
290 sty <- option AnySyntax
291 (do reservedHL "term"; return TermSyntax
292 <|> do reservedHL "pattern"; return PatternSyntax)
295 syms <- some syntaxSym
296 when (all isExpr syms) $ unexpected "missing keywords in syntax rule"
297 let ns = mapMaybe getName syms
298 when (length ns /= length (nub ns))
299 $ unexpected "repeated variable in syntax rule"
301 tm <- typeExpr (allowImp syn) >>= uniquifyBinders [n | Binding n <- syms]
303 return (Rule (mkSimple syms) tm sty)
305 isExpr (Expr _) = True
307 getName (Expr n) = Just n
309 -- Can't parse two full expressions (i.e. expressions with application) in a row
310 -- so change them both to a simple expression
311 mkSimple (Expr e : es) = SimpleExpr e : mkSimple' es
312 mkSimple xs = mkSimple' xs
314 mkSimple' (Expr e : Expr e1 : es) = SimpleExpr e : SimpleExpr e1 :
316 -- Can't parse a full expression followed by operator like characters due to ambiguity
317 mkSimple' (Expr e : Symbol s : es)
318 | takeWhile (`elem` opChars) ts /= "" && ts `notElem` invalidOperators = SimpleExpr e : Symbol s : mkSimple' es
319 where ts = dropWhile isSpace . dropWhileEnd isSpace $ s
320 mkSimple' (e : es) = e : mkSimple' es
323 -- Prevent syntax variable capture by making all binders under syntax unique
324 -- (the ol' Common Lisp GENSYM approach)
325 uniquifyBinders :: [Name] -> PTerm -> IdrisParser PTerm
326 uniquifyBinders userNames = fixBind []
328 fixBind :: [(Name, Name)] -> PTerm -> IdrisParser PTerm
329 fixBind rens (PRef fc hls n) | Just n' <- lookup n rens =
330 return $ PRef fc hls n'
331 fixBind rens (PPatvar fc n) | Just n' <- lookup n rens =
332 return $ PPatvar fc n'
333 fixBind rens (PLam fc n nfc ty body)
334 | n `elem` userNames = liftM2 (PLam fc n nfc) (fixBind rens ty) (fixBind rens body)
336 do ty' <- fixBind rens ty
338 body' <- fixBind ((n,n'):rens) body
339 return $ PLam fc n' nfc ty' body'
340 fixBind rens (PPi plic n nfc argTy body)
341 | n `elem` userNames = liftM2 (PPi plic n nfc) (fixBind rens argTy) (fixBind rens body)
343 do ty' <- fixBind rens argTy
345 body' <- fixBind ((n,n'):rens) body
346 return $ (PPi plic n' nfc ty' body')
347 fixBind rens (PLet fc n nfc ty val body)
348 | n `elem` userNames = liftM3 (PLet fc n nfc)
353 do ty' <- fixBind rens ty
354 val' <- fixBind rens val
356 body' <- fixBind ((n,n'):rens) body
357 return $ PLet fc n' nfc ty' val' body'
358 fixBind rens (PMatchApp fc n) | Just n' <- lookup n rens =
359 return $ PMatchApp fc n'
360 fixBind rens x = descendM (fixBind rens) x
362 gensym :: Name -> IdrisParser Name
363 gensym n = do ist <- get
364 let idx = idris_name ist
365 put ist { idris_name = idx + 1 }
366 return $ sMN idx (show n)
368{- | Parses a syntax symbol (either binding variable, keyword or expression)
371SyntaxSym ::= '[' Name_t ']'
378syntaxSym :: IdrisParser SSymbol
379syntaxSym = try (do lchar '['; n <- fst <$> name; lchar ']'
381 <|> try (do lchar '{'; n <- fst <$> name; lchar '}'
383 <|> do n <- fst <$> iName []
385 <|> do sym <- fmap fst stringLiteral
389{- | Parses a function declaration with possible syntax sugar
392 FunDecl ::= FunDecl';
395fnDecl :: SyntaxInfo -> IdrisParser [PDecl]
396fnDecl syn = try (do notEndBlock
399 let d' = fmap (desugar syn i) d
400 return [d']) <?> "function declaration"
402{-| Parses a function declaration
406 DocComment_t? FnOpts* Accessibility? FnOpts* FnName TypeSig Terminator
413fnDecl' :: SyntaxInfo -> IdrisParser PDecl
414fnDecl' syn = checkFixity $
415 do (doc, argDocs, fc, opts', n, nfc, acc) <- try (do
417 (doc, argDocs) <- docstring syn
419 let initOpts = if default_total ist
422 opts <- fnOpts initOpts
423 acc <- optional accessibility
425 (n_in, nfc) <- fnName
426 let n = expandNS syn n_in
429 return (doc, argDocs, fc, opts', n, nfc, acc))
430 ty <- typeExpr (allowImp syn)
433 return (PTy doc argDocs syn fc opts' n nfc ty)
437 <?> "function declaration"
438 where checkFixity :: IdrisParser PDecl -> IdrisParser PDecl
439 checkFixity p = do decl <- p
441 Nothing -> return decl
442 Just n -> do fOk <- fixityOK n
444 "Missing fixity declaration for " ++ show n
446 getName (PTy _ _ _ _ _ n _ _) = Just n
448 fixityOK (NS n _) = fixityOK n
449 fixityOK (UN n) | all (flip elem opChars) (str n) =
450 do fixities <- fmap idris_infixes get
451 return . elem (str n) . map (\ (Fix _ op) -> op) $ fixities
452 | otherwise = return True
453 fixityOK _ = return True
455{-| Parses function options given initial options
464 | '%' 'error_handler'
466 | '%' 'specialise' '[' NameTimesList? ']'
471NameTimes ::= FnName Natural?;
477 | NameTimes ',' NameTimesList
481-- FIXME: Check compatability for function options (i.e. partal/total)
483-- Issue #1574 on the issue tracker.
484-- https://github.com/idris-lang/Idris-dev/issues/1574
485fnOpts :: [FnOpt] -> IdrisParser [FnOpt]
487 = do reservedHL "total"; fnOpts (TotalFn : opts)
488 <|> do reservedHL "partial"; fnOpts (PartialFn : (opts \\ [TotalFn]))
489 <|> do reservedHL "covering"; fnOpts (CoveringFn : (opts \\ [TotalFn]))
490 <|> do try (lchar '%' *> reserved "export"); c <- fmap fst stringLiteral;
491 fnOpts (CExport c : opts)
492 <|> do try (lchar '%' *> reserved "no_implicit");
493 fnOpts (NoImplicit : opts)
494 <|> do try (lchar '%' *> reserved "inline");
495 fnOpts (Inlinable : opts)
496 <|> do try (lchar '%' *> reserved "assert_total");
497 fnOpts (AssertTotal : opts)
498 <|> do try (lchar '%' *> reserved "error_handler");
499 fnOpts (ErrorHandler : opts)
500 <|> do try (lchar '%' *> reserved "error_reverse");
501 fnOpts (ErrorReverse : opts)
502 <|> do try (lchar '%' *> reserved "reflection");
503 fnOpts (Reflection : opts)
504 <|> do try (lchar '%' *> reserved "hint");
505 fnOpts (AutoHint : opts)
506 <|> do lchar '%'; reserved "specialise";
507 lchar '['; ns <- sepBy nameTimes (lchar ','); lchar ']'
508 fnOpts (Specialise ns : opts)
509 <|> do reservedHL "implicit"; fnOpts (Implicit : opts)
511 <?> "function modifier"
512 where nameTimes :: IdrisParser (Name, Maybe Int)
513 nameTimes = do n <- fst <$> fnName
514 t <- option Nothing (do reds <- fmap fst natural
515 return (Just (fromInteger reds)))
518{- | Parses a postulate
522 DocComment_t? 'postulate' FnOpts* Accesibility? FnOpts* FnName TypeSig Terminator
526postulate :: SyntaxInfo -> IdrisParser PDecl
527postulate syn = do (doc, ext)
528 <- try $ do (doc, _) <- docstring syn
533 let initOpts = if default_total ist
536 opts <- fnOpts initOpts
537 acc <- optional accessibility
539 (n_in, nfc) <- fnName
540 let n = expandNS syn n_in
542 ty <- typeExpr (allowImp syn)
546 return (PPostulate ext doc syn fc nfc opts' n ty)
548 where ppostDecl = do fc <- reservedHL "postulate"; return False
549 <|> do lchar '%'; reserved "extern"; return True
550{- | Parses a using declaration
554 'using' '(' UsingDeclList ')' OpenBlock Decl* CloseBlock
558using_ :: SyntaxInfo -> IdrisParser [PDecl]
560 do reservedHL "using"
561 lchar '('; ns <- usingDeclList syn; lchar ')'
563 let uvars = using syn
564 ds <- many (decl (syn { using = uvars ++ ns }))
567 <?> "using declaration"
569{- | Parses a parameters declaration
573 'parameters' '(' TypeDeclList ')' OpenBlock Decl* CloseBlock
577params :: SyntaxInfo -> IdrisParser [PDecl]
579 do reservedHL "parameters"; lchar '('; ns <- typeDeclList syn; lchar ')'
580 let ns' = [(n, ty) | (n, _, ty) <- ns]
582 let pvars = syn_params syn
583 ds <- many (decl syn { syn_params = pvars ++ ns' })
586 return [PParams fc ns' (concat ds)]
587 <?> "parameters declaration"
589{- | Parses a mutual declaration (for mutually recursive functions)
593 'mutual' OpenBlock Decl* CloseBlock
597mutual :: SyntaxInfo -> IdrisParser [PDecl]
599 do reservedHL "mutual"
601 let pvars = syn_params syn
602 ds <- many (decl (syn { mut_nesting = mut_nesting syn + 1 } ))
605 return [PMutual fc (concat ds)]
608{-| Parses a namespace declaration
612 'namespace' identifier OpenBlock Decl+ CloseBlock
616namespace :: SyntaxInfo -> IdrisParser [PDecl]
618 do reservedHL "namespace"
619 (n, nfc) <- identifier
621 ds <- some (decl syn { syn_namespace = n : syn_namespace syn })
623 return [PNamespace n nfc (concat ds)]
624 <?> "namespace declaration"
626{- | Parses a methods block (for instances)
629 InstanceBlock ::= 'where' OpenBlock FnDecl* CloseBlock
632instanceBlock :: SyntaxInfo -> IdrisParser [PDecl]
633instanceBlock syn = do reservedHL "where"
635 ds <- many (fnDecl syn)
640{- | Parses a methods and instances block (for type classes)
651 'where' OpenBlock Constructor? MethodOrInstance* CloseBlock
655classBlock :: SyntaxInfo -> IdrisParser (Maybe (Name, FC), Docstring (Either Err PTerm), [PDecl])
656classBlock syn = do reservedHL "where"
658 (cn, cd) <- option (Nothing, emptyDocstring) $
659 try (do (doc, _) <- option noDocs docComment
661 return (Just n, doc))
663 let cd' = annotate syn ist cd
665 ds <- many (notEndBlock >> instance_ syn <|> fnDecl syn)
667 return (cn, cd', concat ds)
671 constructor :: IdrisParser (Name, FC)
672 constructor = reservedHL "constructor" *> fnName
674 annotate :: SyntaxInfo -> IState -> Docstring () -> Docstring (Either Err PTerm)
675 annotate syn ist = annotCode $ tryFullExpr syn ist
677{-| Parses a type class declaration
682 | '(' Name ':' Expr ')'
688 DocComment_t? Accessibility? 'class' ConstraintList? Name ClassArgument* ClassBlock?
692class_ :: SyntaxInfo -> IdrisParser [PDecl]
693class_ syn = do (doc, argDocs, acc)
694 <- try (do (doc, argDocs) <- docstring syn
695 acc <- optional accessibility
697 return (doc, argDocs, acc))
699 cons <- constraintList syn
700 let cons' = [(c, ty) | (c, _, ty) <- cons]
701 (n_in, nfc) <- fnName
702 let n = expandNS syn n_in
704 fds <- option [(cn, NoFC) | (cn, _, _) <- cs] fundeps
705 (cn, cd, ds) <- option (Nothing, fst noDocs, []) (classBlock syn)
706 accData acc n (concatMap declared ds)
707 return [PClass doc syn fc cons' n nfc cs argDocs fds ds cn cd]
708 <?> "type-class declaration"
710 fundeps :: IdrisParser [(Name, FC)]
711 fundeps = do lchar '|'; sepBy name (lchar ',')
713 carg :: IdrisParser (Name, FC, PTerm)
714 carg = do lchar '('; (i, ifc) <- name; lchar ':'; ty <- expr syn; lchar ')'
716 <|> do (i, ifc) <- name
718 return (i, ifc, PType fc)
720{- | Parses a type class instance declaration
724 DocComment_t? 'instance' InstanceName? ConstraintList? Name SimpleExpr* InstanceBlock?
729InstanceName ::= '[' Name ']';
732instance_ :: SyntaxInfo -> IdrisParser [PDecl]
733instance_ syn = do (doc, argDocs)
734 <- try (docstring syn <* reservedHL "instance")
736 en <- optional instanceName
737 cs <- constraintList syn
738 let cs' = [(c, ty) | (c, _, ty) <- cs]
740 args <- many (simpleExpr syn)
741 let sc = PApp fc (PRef cnfc [cnfc] cn) (map pexp args)
742 let t = bindList (PPi constraint) cs sc
743 ds <- option [] (instanceBlock syn)
744 return [PInstance doc argDocs syn fc cs' cn cnfc args t en ds]
745 <?> "instance declaration"
746 where instanceName :: IdrisParser Name
747 instanceName = do lchar '['; n_in <- fst <$> fnName; lchar ']'
748 let n = expandNS syn n_in
753-- | Parse a docstring
754docstring :: SyntaxInfo
755 -> IdrisParser (Docstring (Either Err PTerm),
756 [(Name,Docstring (Either Err PTerm))])
757docstring syn = do (doc, argDocs) <- option noDocs docComment
759 let doc' = annotCode (tryFullExpr syn ist) doc
760 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
761 | (n, d) <- argDocs ]
762 return (doc', argDocs')
765{- | Parses a using declaration list
777 | UsingDecl ',' UsingDeclList'
788usingDeclList :: SyntaxInfo -> IdrisParser [Using]
790 = try (sepBy1 (usingDecl syn) (lchar ','))
791 <|> do ns <- sepBy1 (fst <$> name) (lchar ',')
793 t <- typeExpr (disallowImp syn)
794 return (map (\x -> UImplicit x t) ns)
795 <?> "using declaration list"
797{- |Parses a using declaration
806usingDecl :: SyntaxInfo -> IdrisParser Using
807usingDecl syn = try (do x <- fst <$> fnName
809 t <- typeExpr (disallowImp syn)
810 return (UImplicit x t))
811 <|> do c <- fst <$> fnName
812 xs <- some (fst <$> fnName)
813 return (UConstraint c xs)
814 <?> "using declaration"
816{- | Parse a clause with patterns
822pattern :: SyntaxInfo -> IdrisParser PDecl
823pattern syn = do fc <- getFC
825 return (PClauses fc [] (sMN 2 "_") [clause]) -- collect together later
828{- | Parse a constant applicative form declaration
831CAF ::= 'let' FnName '=' Expr Terminator;
834caf :: SyntaxInfo -> IdrisParser PDecl
835caf syn = do reservedHL "let"
836 n_in <- fst <$> fnName; let n = expandNS syn n_in
839 t <- indented $ expr syn
843 <?> "constant applicative form declaration"
845{- | Parse an argument expression
848ArgExpr ::= HSimpleExpr | {- In Pattern External (User-defined) Expression -};
851argExpr :: SyntaxInfo -> IdrisParser PTerm
852argExpr syn = let syn' = syn { inPattern = True } in
853 try (hsimpleExpr syn') <|> simpleExternalExpr syn'
854 <?> "argument expression"
856{- | Parse a right hand side of a function
866RHSName ::= '{' FnName '}';
869rhs :: SyntaxInfo -> Name -> IdrisParser PTerm
870rhs syn n = do lchar '='; expr syn
873 name <- option n' (do symbol "{"; n <- fst <$> fnName; symbol "}";
876 return (addLet fc name r)
878 <?> "function right hand side"
879 where mkN :: Name -> Name
880 mkN (UN x) = if (tnull x || not (isAlpha (thead x)))
881 then sUN "infix_op_lemma_1"
882 else sUN (str x++"_lemma_1")
883 mkN (NS x n) = NS (mkN x) n
886 addLet :: FC -> Name -> PTerm -> PTerm
887 addLet fc nm (PLet fc' n nfc ty val r) = PLet fc' n nfc ty val (addLet fc nm r)
888 addLet fc nm (PCase fc' t cs) = PCase fc' t (map addLetC cs)
889 where addLetC (l, r) = (l, addLet fc nm r)
890 addLet fc nm r = (PLet fc (sUN "value") NoFC Placeholder r (PMetavar NoFC nm))
892{- |Parses a function clause
895RHSOrWithBlock ::= RHS WhereOrTerminator
896 | 'with' SimpleExpr OpenBlock FnDecl+ CloseBlock
901Clause ::= WExpr+ RHSOrWithBlock
902 | SimpleExpr '<==' FnName RHS WhereOrTerminator
903 | ArgExpr Operator ArgExpr WExpr* RHSOrWithBlock {- Except "=" and "?=" operators to avoid ambiguity -}
904 | FnName ConstraintArg* ImplicitOrArgExpr* WExpr* RHSOrWithBlock
909ImplicitOrArgExpr ::= ImplicitArg | ArgExpr;
913WhereOrTerminator ::= WhereBlock | Terminator;
916clause :: SyntaxInfo -> IdrisParser PClause
918 = do wargs <- try (do pushIndent; some (wExpr syn))
921 n <- case lastParse ist of
923 Nothing -> fail "Invalid clause"
925 let ctxt = tt_ctxt ist
926 let wsyn = syn { syn_namespace = [] }
927 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
932 return $ PClauseR fc wargs r wheres) <|> (do
935 wval <- simpleExpr syn
938 ds <- some $ fnDecl syn
939 let withs = concat ds
941 return $ PWithR fc wargs wval pn withs)
942 <|> do ty <- try (do pushIndent
947 n_in <- fst <$> fnName; let n = expandNS syn n_in
950 let ctxt = tt_ctxt ist
951 let wsyn = syn { syn_namespace = [] }
952 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
957 let capp = PLet fc (sMN 0 "match") NoFC
960 (PRef fc [] (sMN 0 "match"))
962 put (ist { lastParse = Just n })
963 return $ PClause fc n capp [] r wheres
964 <|> do (l, op, nfc) <- try (do
967 (op, nfc) <- operatorFC
968 when (op == "=" || op == "?=" ) $
969 fail "infix clause definition with \"=\" and \"?=\" not supported "
971 let n = expandNS syn (sUN op)
974 wargs <- many (wExpr syn)
976 let wsyn = syn { syn_namespace = [] }
977 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
983 let capp = PApp fc (PRef nfc [nfc] n) [pexp l, pexp r]
984 put (ist { lastParse = Just n })
985 return $ PClause fc n capp wargs rs wheres) <|> (do
988 wval <- bracketed syn
991 ds <- some $ fnDecl syn
994 let capp = PApp fc (PRef fc [] n) [pexp l, pexp r]
995 let withs = map (fillLHSD n capp wargs) $ concat ds
996 put (ist { lastParse = Just n })
997 return $ PWith fc n capp wargs wval pn withs)
999 (n_in, nfc) <- fnName; let n = expandNS syn n_in
1000 cargs <- many (constraintArg syn)
1002 args <- many (try (implicitArg (syn { inPattern = True } ))
1003 <|> (fmap pexp (argExpr syn)))
1004 wargs <- many (wExpr syn)
1005 let capp = PApp fc (PRef nfc [nfc] n)
1009 let ctxt = tt_ctxt ist
1010 let wsyn = syn { syn_namespace = [] }
1011 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
1017 put (ist { lastParse = Just n })
1018 return $ PClause fc n capp wargs r wheres) <|> (do
1021 put (ist { lastParse = Just n })
1022 wval <- bracketed syn
1025 ds <- some $ fnDecl syn
1026 let withs = map (fillLHSD n capp wargs) $ concat ds
1029 return $ PWith fc n capp wargs wval pn withs)
1030 <?> "function clause"
1032 optProof = option Nothing (do reservedHL "proof"
1036 fillLHS :: Name -> PTerm -> [PTerm] -> PClause -> PClause
1037 fillLHS n capp owargs (PClauseR fc wargs v ws)
1038 = PClause fc n capp (owargs ++ wargs) v ws
1039 fillLHS n capp owargs (PWithR fc wargs v pn ws)
1040 = PWith fc n capp (owargs ++ wargs) v pn
1041 (map (fillLHSD n capp (owargs ++ wargs)) ws)
1044 fillLHSD :: Name -> PTerm -> [PTerm] -> PDecl -> PDecl
1045 fillLHSD n c a (PClauses fc o fn cs) = PClauses fc o fn (map (fillLHS n c a) cs)
1046 fillLHSD n c a x = x
1048{-| Parses with pattern
1054wExpr :: SyntaxInfo -> IdrisParser PTerm
1055wExpr syn = do lchar '|'
1056 expr' (syn { inPattern = True })
1059{- | Parses a where block
1062WhereBlock ::= 'where' OpenBlock Decl+ CloseBlock;
1065whereBlock :: Name -> SyntaxInfo -> IdrisParser ([PDecl], [(Name, Name)])
1067 = do reservedHL "where"
1068 ds <- indentedBlock1 (decl syn)
1069 let dns = concatMap (concatMap declared) ds
1070 return (concat ds, map (\x -> (x, decoration syn x)) dns)
1073{- |Parses a code generation target language name
1085codegen_ :: IdrisParser Codegen
1086codegen_ = do n <- fst <$> identifier
1087 return (Via (map toLower n))
1088 <|> do reserved "Bytecode"; return Bytecode
1089 <?> "code generation language"
1091{- |Parses a compiler directive
1095 | String ',' StringList
1100Directive ::= '%' Directive';
1104Directive' ::= 'lib' CodeGen String_t
1105 | 'link' CodeGen String_t
1106 | 'flag' CodeGen String_t
1107 | 'include' CodeGen String_t
1110 | 'access' Accessibility
1111 | 'default' Totality
1113 | 'dynamic' StringList
1114 | 'name' Name NameList
1115 | 'error_handlers' Name NameList
1116 | 'language' 'TypeProviders'
1117 | 'language' 'ErrorReflection'
1121directive :: SyntaxInfo -> IdrisParser [PDecl]
1122directive syn = do try (lchar '%' *> reserved "lib")
1124 lib <- fmap fst stringLiteral
1125 return [PDirective (DLib cgn lib)]
1126 <|> do try (lchar '%' *> reserved "link")
1127 cgn <- codegen_; obj <- fst <$> stringLiteral
1128 return [PDirective (DLink cgn obj)]
1129 <|> do try (lchar '%' *> reserved "flag")
1130 cgn <- codegen_; flag <- fst <$> stringLiteral
1131 return [PDirective (DFlag cgn flag)]
1132 <|> do try (lchar '%' *> reserved "include")
1134 hdr <- fst <$> stringLiteral
1135 return [PDirective (DInclude cgn hdr)]
1136 <|> do try (lchar '%' *> reserved "hide"); n <- fst <$> fnName
1137 return [PDirective (DHide n)]
1138 <|> do try (lchar '%' *> reserved "freeze"); n <- fst <$> iName []
1139 return [PDirective (DFreeze n)]
1140 <|> do try (lchar '%' *> reserved "access"); acc <- accessibility
1141 return [PDirective (DAccess acc)]
1142 <|> do try (lchar '%' *> reserved "default"); tot <- totality
1144 put (i { default_total = tot } )
1145 return [PDirective (DDefault tot)]
1146 <|> do try (lchar '%' *> reserved "logging")
1147 i <- fst <$> natural
1148 return [PDirective (DLogging i)]
1149 <|> do try (lchar '%' *> reserved "dynamic")
1150 libs <- sepBy1 (fmap fst stringLiteral) (lchar ',')
1151 return [PDirective (DDynamicLibs libs)]
1152 <|> do try (lchar '%' *> reserved "name")
1153 (ty, tyFC) <- fnName
1154 ns <- sepBy1 name (lchar ',')
1155 return [PDirective (DNameHint ty tyFC ns)]
1156 <|> do try (lchar '%' *> reserved "error_handlers")
1158 (arg, afc) <- fnName
1159 ns <- sepBy1 name (lchar ',')
1160 return [PDirective (DErrorHandlers fn nfc arg afc ns) ]
1161 <|> do try (lchar '%' *> reserved "language"); ext <- pLangExt;
1162 return [PDirective (DLanguage ext)]
1164 try (lchar '%' *> reserved "used")
1165 fn <- fst <$> fnName
1166 arg <- fst <$> iName []
1167 return [PDirective (DUsed fc fn arg)]
1170pLangExt :: IdrisParser LanguageExt
1171pLangExt = (reserved "TypeProviders" >> return TypeProviders)
1172 <|> (reserved "ErrorReflection" >> return ErrorReflection)
1174{- | Parses a totality
1177Totality ::= 'partial' | 'total'
1181totality :: IdrisParser Bool
1183 = do reservedHL "total"; return True
1184 <|> do reservedHL "partial"; return False
1186{- | Parses a type provider
1189Provider ::= DocComment_t? '%' 'provide' Provider_What? '(' FnName TypeSig ')' 'with' Expr;
1190ProviderWhat ::= 'proof' | 'term' | 'type' | 'postulate'
1193provider :: SyntaxInfo -> IdrisParser [PDecl]
1194provider syn = do doc <- try (do (doc, _) <- docstring syn
1197 fc2 <- reservedFC "provide"
1198 highlightP (spanFC fc1 fc2) AnnKeyword
1200 provideTerm doc <|> providePostulate doc
1202 where provideTerm doc =
1203 do lchar '('; (n, nfc) <- fnName; lchar ':'; t <- typeExpr syn; lchar ')'
1206 e <- expr syn <?> "provider expression"
1207 return [PProvider doc syn fc nfc (ProvTerm t e) n]
1208 providePostulate doc =
1209 do reservedHL "postulate"
1213 e <- expr syn <?> "provider expression"
1214 return [PProvider doc syn fc nfc (ProvPostulate e) n]
1216{- | Parses a transform
1219Transform ::= '%' 'transform' Expr '==>' Expr
1222transform :: SyntaxInfo -> IdrisParser [PDecl]
1223transform syn = do try (lchar '%' *> reserved "transform")
1224 -- leave it unchecked, until we work out what this should
1226-- safety <- option True (do reserved "unsafe"
1232 return [PTransform fc False l r]
1236{- * Loading and parsing -}
1237{- | Parses an expression from input -}
1238parseExpr :: IState -> String -> Result PTerm
1239parseExpr st = runparser (fullExpr defaultSyntax) st "(input)"
1241{- | Parses a constant form input -}
1242parseConst :: IState -> String -> Result Const
1243parseConst st = runparser (fmap fst constant) st "(input)"
1245{- | Parses a tactic from input -}
1246parseTactic :: IState -> String -> Result PTactic
1247parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
1249{- | Parses a do-step from input (used in the elab shell) -}
1250parseElabShellStep :: IState -> String -> Result (Either ElabShellCmd PDo)
1251parseElabShellStep ist = runparser (fmap Right (do_ defaultSyntax) <|> fmap Left elabShellCmd) ist "(input)"
1252 where elabShellCmd = char ':' >>
1253 (reserved "qed" >> pure EQED ) <|>
1254 (reserved "abandon" >> pure EAbandon ) <|>
1255 (reserved "undo" >> pure EUndo ) <|>
1256 (reserved "state" >> pure EProofState) <|>
1257 (reserved "term" >> pure EProofTerm ) <|>
1258 (expressionTactic ["e", "eval"] EEval ) <|>
1259 (expressionTactic ["t", "type"] ECheck) <|>
1260 (expressionTactic ["search"] ESearch ) <|>
1262 doc <- (Right . fst <$> constant) <|> (Left . fst <$> fnName)
1264 return (EDocStr doc))
1266 expressionTactic cmds tactic =
1267 do asum (map reserved cmds)
1268 t <- spaced (expr defaultSyntax)
1270 return $ tactic (desugar defaultSyntax i t)
1271 spaced parser = indentPropHolds gtProp *> parser
1273-- | Parse module header and imports
1274parseImports :: FilePath -> String -> Idris (Maybe (Docstring ()), [String], [ImportInfo], Maybe Delta)
1275parseImports fname input
1277 case parseString (runInnerParser (evalStateT imports i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
1278 Failure err -> fail (show err)
1279 Success (x, annots, i) ->
1281 fname' <- runIO $ Dir.makeAbsolute fname
1282 sendHighlighting $ addPath annots fname'
1284 where imports :: IdrisParser ((Maybe (Docstring ()), [String],
1287 [(FC, OutputAnnotation)], IState)
1288 imports = do whiteSpace
1289 (mdoc, mname, annots) <- moduleHeader
1292 isEof <- lookAheadMatches eof
1297 return ((mdoc, mname, ps, mrk'), annots, i)
1298 addPath :: [(FC, OutputAnnotation)] -> FilePath -> [(FC, OutputAnnotation)]
1300 addPath ((fc, AnnNamespace ns Nothing) : annots) path =
1301 (fc, AnnNamespace ns (Just path)) : addPath annots path
1302 addPath (annot:annots) path = annot : addPath annots path
1304-- | There should be a better way of doing this...
1305findFC :: Doc -> (FC, String)
1306findFC x = let s = show (plain x) in findFC' s
1307 where findFC' s = case span (/= ':') s of
1308 -- Horrid kludge to prevent crashes on Windows
1309 (prefix, ':':'\\':rest) ->
1310 case findFC' rest of
1311 (NoFC, msg) -> (NoFC, msg)
1312 (FileFC f, msg) -> (FileFC (prefix ++ ":\\" ++ f), msg)
1313 (FC f start end, msg) -> (FC (prefix ++ ":\\" ++ f) start end, msg)
1314 (failname, ':':rest) -> case span isDigit rest of
1315 (line, ':':rest') -> case span isDigit rest' of
1316 (col, ':':msg) -> let pos = (read line, read col) in
1317 (FC failname pos pos, msg)
1319-- | Check if the coloring matches the options and corrects if necessary
1320fixColour :: Bool -> ANSI.Doc -> ANSI.Doc
1321fixColour False doc = ANSI.plain doc
1322fixColour True doc = doc
1324-- | A program is a list of declarations, possibly with associated
1325-- documentation strings.
1326parseProg :: SyntaxInfo -> FilePath -> String -> Maybe Delta ->
1328parseProg syn fname input mrk
1330 case runparser mainProg i fname input of
1331 Failure doc -> do -- FIXME: Get error location from trifecta
1332 -- this can't be the solution!
1333 -- Issue #1575 on the issue tracker.
1334 -- https://github.com/idris-lang/Idris-dev/issues/1575
1335 let (fc, msg) = findFC doc
1337 case idris_outputmode i of
1338 RawOutput h -> iputStrLn (show $ fixColour (idris_colourRepl i) doc)
1339 IdeMode n h -> iWarn fc (P.text msg)
1340 putIState (i { errSpan = Just fc })
1342 Success (x, i) -> do putIState i
1343 reportParserWarnings
1345 where mainProg :: IdrisParser ([PDecl], IState)
1346 mainProg = case mrk of
1347 Nothing -> do i <- get; return ([], i)
1354{- | Load idris module and show error if something wrong happens -}
1355loadModule :: FilePath -> Idris (Maybe String)
1357 = idrisCatch (loadModule' f)
1358 (\e -> do setErrSpan (getErrSpan e)
1360 iWarn (getErrSpan e) $ pprintErr ist e
1363{- | Load idris module -}
1364loadModule' :: FilePath -> Idris (Maybe String)
1367 let file = takeWhile (/= ' ') f
1368 ibcsd <- valIBCSubDir i
1369 ids <- allImportDirs
1370 fp <- findImport ids ibcsd file
1371 if file `elem` imported i
1372 then do logLvl 1 $ "Already read " ++ file
1374 else do putIState (i { imported = file : imported i })
1376 IDR fn -> loadSource False fn Nothing
1377 LIDR fn -> loadSource True fn Nothing
1379 idrisCatch (loadIBC True fn)
1380 (\c -> do logLvl 1 $ fn ++ " failed " ++ pshow i c
1382 IDR sfn -> loadSource False sfn Nothing
1383 LIDR sfn -> loadSource True sfn Nothing)
1386{- | Load idris code from file -}
1387loadFromIFile :: Bool -> IFileType -> Maybe Int -> Idris ()
1388loadFromIFile reexp i@(IBC fn src) maxline
1389 = do logLvl 1 $ "Skipping " ++ getSrcFile i
1390 idrisCatch (loadIBC reexp fn)
1391 (\err -> ierror $ LoadingFailed fn err)
1393 getSrcFile (IDR fn) = fn
1394 getSrcFile (LIDR fn) = fn
1395 getSrcFile (IBC f src) = getSrcFile src
1397loadFromIFile _ (IDR fn) maxline = loadSource' False fn maxline
1398loadFromIFile _ (LIDR fn) maxline = loadSource' True fn maxline
1400{-| Load idris source code and show error if something wrong happens -}
1401loadSource' :: Bool -> FilePath -> Maybe Int -> Idris ()
1402loadSource' lidr r maxline
1403 = idrisCatch (loadSource lidr r maxline)
1404 (\e -> do setErrSpan (getErrSpan e)
1407 At f e' -> iWarn f (pprintErr ist e')
1408 _ -> iWarn (getErrSpan e) (pprintErr ist e))
1410{- | Load Idris source code-}
1411loadSource :: Bool -> FilePath -> Maybe Int -> Idris ()
1412loadSource lidr f toline
1413 = do logLvl 1 ("Reading " ++ f)
1415 let def_total = default_total i
1416 file_in <- runIO $ readSource f
1417 file <- if lidr then tclift $ unlit f file_in else return file_in
1418 (mdocs, mname, imports_in, pos) <- parseImports f file
1419 ai <- getAutoImports
1420 let imports = map (\n -> ImportInfo True n Nothing [] NoFC NoFC) ai ++ imports_in
1421 ids <- allImportDirs
1422 ibcsd <- valIBCSubDir i
1423 mapM_ (\(re, f, ns, nfc) ->
1424 do fp <- findImport ids ibcsd f
1426 LIDR fn -> ifail $ "No ibc for " ++ f
1427 IDR fn -> ifail $ "No ibc for " ++ f
1430 let srcFn = case src of
1434 srcFnAbs <- case srcFn of
1435 Just fn -> fmap Just (runIO $ Dir.makeAbsolute fn)
1436 Nothing -> return Nothing
1437 sendHighlighting [(nfc, AnnNamespace ns srcFnAbs)])
1438 [(re, fn, ns, nfc) | ImportInfo re fn _ ns _ nfc <- imports]
1439 reportParserWarnings
1440 sendParserHighlighting
1442 -- process and check module aliases
1443 let modAliases = M.fromList
1444 [ (prep alias, prep realName)
1445 | ImportInfo { import_reexport = reexport
1446 , import_path = realName
1447 , import_rename = Just (alias, _)
1448 , import_location = fc } <- imports
1450 prep = map T.pack . reverse . Spl.splitOn [pathSeparator]
1451 aliasNames = [ (alias, fc)
1452 | ImportInfo { import_rename = Just (alias, _)
1453 , import_location = fc } <- imports
1455 histogram = groupBy ((==) `on` fst) . sortBy (comparing fst) $ aliasNames
1456 case map head . filter ((/= 1) . length) $ histogram of
1457 [] -> logLvl 3 $ "Module aliases: " ++ show (M.toList modAliases)
1458 (n,fc):_ -> throwError . At fc . Msg $ "import alias not unique: " ++ show n
1461 putIState (i { default_access = Hidden, module_aliases = modAliases })
1462 clearIBC -- start a new .ibc file
1463 -- record package info in .ibc
1464 imps <- allImportDirs
1465 mapM_ addIBC (map IBCImportDir imps)
1466 mapM_ (addIBC . IBCImport)
1467 [ (reexport, realName)
1468 | ImportInfo { import_reexport = reexport
1469 , import_path = realName
1472 let syntax = defaultSyntax{ syn_namespace = reverse mname,
1475 -- Save the span from parsing the module header, because
1476 -- an empty program parse might obliterate it.
1477 let oldSpan = idris_parsedSpan ist
1478 ds' <- parseProg syntax f file pos
1480 case (ds', oldSpan) of
1482 -- If no program elements were parsed, we dind't
1483 -- get a loaded region in the IBC file. That
1484 -- means we need to add it back.
1486 putIState ist { idris_parsedSpan = oldSpan
1487 , ibc_write = IBCParsedRegion fc :
1491 sendParserHighlighting
1493 -- Parsing done, now process declarations
1495 let ds = namespaces mname ds'
1496 logLvl 3 (show $ showDecls verbosePPOption ds)
1498 logLvl 10 (show (toAlist (idris_implicits i)))
1499 logLvl 3 (show (idris_infixes i))
1500 -- Now add all the declarations to the context
1502 when v $ iputStrLn $ "Type checking " ++ f
1503 -- we totality check after every Mutual block, so if
1504 -- anything is a single definition, wrap it in a
1505 -- mutual block on its own
1506 elabDecls toplevel (map toMutual ds)
1508 -- simplify every definition do give the totality checker
1510 mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
1512 do ctxt <- getContext
1513 tclift $ simplifyCasedef n (getErasureInfo i) ctxt
1515 (map snd (idris_totcheck i))
1516 -- build size change graph from simplified definitions
1517 logLvl 1 "Totality checking"
1519 mapM_ buildSCG (idris_totcheck i)
1520 mapM_ checkDeclTotality (idris_totcheck i)
1522 -- Redo totality check for deferred names
1523 let deftots = idris_defertotcheck i
1524 logLvl 1 $ "Totality checking " ++ show deftots
1525 mapM_ (\x -> do tot <- getTotality x
1527 Total _ -> setTotality x Unchecked
1528 _ -> return ()) (map snd deftots)
1529 mapM_ buildSCG deftots
1530 mapM_ checkDeclTotality deftots
1532 logLvl 1 ("Finished " ++ f)
1533 ibcsd <- valIBCSubDir i
1534 logLvl 1 "Universe checking"
1536 let ibc = ibcPathNoFallback ibcsd f
1538 addHides (hide_list i)
1540 -- Save module documentation if applicable
1543 Nothing -> return ()
1544 Just docs -> addModDoc syntax mname docs
1547 -- Finally, write an ibc and highlights if checking was successful
1550 do idrisCatch (do writeIBC f ibc; clearIBC)
1551 (\c -> return ()) -- failure is harmless
1552 hl <- getDumpHighlighting
1554 idrisCatch (writeHighlights f)
1555 (const $ return ()) -- failure is harmless
1558 putIState (i { default_total = def_total,
1562 namespaces :: [String] -> [PDecl] -> [PDecl]
1563 namespaces [] ds = ds
1564 namespaces (x:xs) ds = [PNamespace x NoFC (namespaces xs ds)]
1566 toMutual :: PDecl -> PDecl
1567 toMutual m@(PMutual _ d) = m
1568 toMutual (PNamespace x fc ds) = PNamespace x fc (map toMutual ds)
1569 toMutual x = let r = PMutual (fileFC "single mutual") [x] in
1577 addModDoc :: SyntaxInfo -> [String] -> Docstring () -> Idris ()
1578 addModDoc syn mname docs =
1580 docs' <- elabDocTerms recinfo (parsedDocs ist)
1581 let modDocs' = addDef docName docs' (idris_moduledocs ist)
1582 putIState ist { idris_moduledocs = modDocs' }
1583 addIBC (IBCModDocs docName)
1585 docName = NS modDocName (map T.pack (reverse mname))
1586 parsedDocs ist = annotCode (tryFullExpr syn ist) docs
1588{- | Adds names to hide list -}
1589addHides :: [(Name, Maybe Accessibility)] -> Idris ()
1590addHides xs = do i <- getIState
1591 let defh = default_access i
1592 let (hs, as) = partition isNothing xs
1595 (map (\ (n, _) -> (n, defh)) hs ++
1596 map (\ (n, Just a) -> (n, a)) as)
1597 where isNothing (_, Nothing) = True
1600 doHide (n, a) = do setAccessibility n a
1601 addIBC (IBCAccess n 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