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 Text.Trifecta.Delta
12import Text.Trifecta hiding (span, stringLiteral, charLiteral, natural, symbol, char, string, whiteSpace)
13import Text.Parser.LookAhead
14import Text.Parser.Expression
15import qualified Text.Parser.Token as Tok
16import qualified Text.Parser.Char as Chr
17import qualified Text.Parser.Token.Highlight as Hi
19import Text.PrettyPrint.ANSI.Leijen (Doc, plain)
20import qualified Text.PrettyPrint.ANSI.Leijen as ANSI
22import Idris.AbsSyntax hiding (namespace, params)
25import Idris.Delaborate
27import Idris.Elab.Value
36import Idris.ParseHelpers
41import Idris.Docstrings hiding (Unchecked)
45import Util.DynamicLinker
46import qualified Util.Pretty as P
49import Idris.Core.Evaluate
51import Control.Applicative hiding (Const)
53import Control.Monad.Except (throwError, catchError)
54import Control.Monad.State.Strict
58import qualified Data.List.Split as Spl
63import qualified Data.Map as M
64import qualified Data.HashSet as HS
65import qualified Data.Text as T
66import qualified Data.ByteString.UTF8 as UTF8
67import qualified Data.Set as S
76 grammar shortcut notation:
77 ~CHARSEQ = complement of char sequence (i.e. any character except CHARSEQ)
78 RULE? = optional rule (i.e. RULE or nothing)
79 RULE* = repeated rule (i.e. RULE zero or more times)
80 RULE+ = repeated rule with at least one match (i.e. RULE one or more times)
81 RULE! = invalid rule (i.e. rule that is not valid in context, report meaningful error in case)
82 RULE{n} = rule repeated n times
88{- | Parses module definition
91 ModuleHeader ::= 'module' Identifier_t ';'?;
94moduleHeader :: IdrisParser (Maybe (Docstring ()), [String])
95moduleHeader = try (do docs <- optional docComment
99 option ';' (lchar ';')
100 return (fmap fst docs, moduleName i))
101 <|> try (do lchar '%'; reserved "unqualified"
102 return (Nothing, []))
103 <|> return (Nothing, moduleName "Main")
104 where moduleName x = case span (/='.') x of
106 (x, '.':y) -> x : moduleName y
107 noArgs (Just (_, args)) | not (null args) = fail "Modules do not take arguments"
110{- | Parses an import statement
113 Import ::= 'import' Identifier_t ';'?;
116import_ :: IdrisParser (Bool, String, Maybe String, FC)
117import_ = do fc <- getFC
119 reexport <- option False (do reserved "public"; return True)
121 newName <- optional (reserved "as" *> identifier)
122 option ';' (lchar ';')
123 return (reexport, toPath id, toPath <$> newName, fc)
124 <?> "import statement"
125 where toPath = foldl1' (</>) . Spl.splitOn "."
127{- | Parses program source
133prog :: SyntaxInfo -> IdrisParser [PDecl]
134prog syn = do whiteSpace
135 decls <- many (decl syn)
136 let c = (concat decls)
138 Nothing -> do notOpenBraces; eof
142 put ist { idris_parsedSpan = Just (FC (fc_fname fc) (0,0) (fc_end fc)),
143 ibc_write = IBCParsedRegion fc : ibc_write ist }
146{-| Parses a top-level declaration
165decl :: SyntaxInfo -> IdrisParser [PDecl]
166decl syn = do fc <- getFC
167 -- if we're after maxline, stop here
168 let continue = case maxline syn of
170 Just l -> if fst (fc_end fc) > l
171 then mut_nesting syn /= 0
173 if continue then do notEndBlock
175 else fail "End of readable input"
176 where declBody :: IdrisParser [PDecl]
184 <|> do d <- dsl syn; return [d]
188 <|> do import_; fail "imports must be at top of file"
190 declBody' :: IdrisParser [PDecl]
191 declBody' = do d <- decl' syn
193 let d' = fmap (debindApp syn . (desugar syn i)) d
196{- | Parses a top-level declaration with possible syntax sugar
208decl' :: SyntaxInfo -> IdrisParser PDecl
216{- | Parses a syntax extension declaration (and adds the rule to parser state)
219 SyntaxDecl ::= SyntaxRule;
222syntaxDecl :: SyntaxInfo -> IdrisParser PDecl
223syntaxDecl syn = do s <- syntaxRule syn
225 put (i `addSyntax` s)
227 return (PSyntax fc s)
229-- | Extend an 'IState' with a new syntax extension. See also 'addReplSyntax'.
230addSyntax :: IState -> Syntax -> IState
231addSyntax i s = i { syntax_rules = updateSyntaxRules [s] rs,
232 syntax_keywords = ks ++ ns,
233 ibc_write = IBCSyntax s : map IBCKeyword ks ++ ibc }
234 where rs = syntax_rules i
235 ns = syntax_keywords i
237 ks = map show (syntaxNames s)
239-- | Like 'addSyntax', but no effect on the IBC.
240addReplSyntax :: IState -> Syntax -> IState
241addReplSyntax i s = i { syntax_rules = updateSyntaxRules [s] rs,
242 syntax_keywords = ks ++ ns }
243 where rs = syntax_rules i
244 ns = syntax_keywords i
245 ks = map show (syntaxNames s)
247{- | Parses a syntax extension declaration
250SyntaxRuleOpts ::= 'term' | 'pattern';
255 SyntaxRuleOpts? 'syntax' SyntaxSym+ '=' TypeExpr Terminator;
259SyntaxSym ::= '[' Name_t ']'
266syntaxRule :: SyntaxInfo -> IdrisParser Syntax
270 sty <- option AnySyntax (do reserved "term"; return TermSyntax
271 <|> do reserved "pattern"; return PatternSyntax)
274 syms <- some syntaxSym
275 when (all isExpr syms) $ unexpected "missing keywords in syntax rule"
276 let ns = mapMaybe getName syms
277 when (length ns /= length (nub ns))
278 $ unexpected "repeated variable in syntax rule"
280 tm <- typeExpr (allowImp syn)
282 return (Rule (mkSimple syms) tm sty)
284 isExpr (Expr _) = True
286 getName (Expr n) = Just n
288 -- Can't parse two full expressions (i.e. expressions with application) in a row
289 -- so change them both to a simple expression
290 mkSimple (Expr e : es) = SimpleExpr e : mkSimple' es
291 mkSimple xs = mkSimple' xs
293 mkSimple' (Expr e : Expr e1 : es) = SimpleExpr e : SimpleExpr e1 :
295 mkSimple' (e : es) = e : mkSimple' es
299{- | Parses a syntax symbol (either binding variable, keyword or expression)
302SyntaxSym ::= '[' Name_t ']'
309syntaxSym :: IdrisParser SSymbol
310syntaxSym = try (do lchar '['; n <- name; lchar ']'
312 <|> try (do lchar '{'; n <- name; lchar '}'
316 <|> do sym <- stringLiteral
320{- | Parses a function declaration with possible syntax sugar
323 FunDecl ::= FunDecl';
326fnDecl :: SyntaxInfo -> IdrisParser [PDecl]
327fnDecl syn = try (do notEndBlock
330 let d' = fmap (desugar syn i) d
331 return [d']) <?> "function declaration"
333{-| Parses a function declaration
337 DocComment_t? FnOpts* Accessibility? FnOpts* FnName TypeSig Terminator
344fnDecl' :: SyntaxInfo -> IdrisParser PDecl
345fnDecl' syn = checkFixity $
346 do (doc, argDocs, fc, opts', n, acc) <- try (do
348 (doc, argDocs) <- option noDocs docComment
350 let doc' = annotCode (tryFullExpr syn ist) doc
351 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
352 | (n, d) <- argDocs ]
354 initOpts = if default_total ist
357 opts <- fnOpts initOpts
358 acc <- optional accessibility
361 let n = expandNS syn n_in
364 return (doc', argDocs', fc, opts', n, acc))
365 ty <- typeExpr (allowImp syn)
368 return (PTy doc argDocs syn fc opts' n ty)
372 <?> "function declaration"
373 where checkFixity :: IdrisParser PDecl -> IdrisParser PDecl
374 checkFixity p = do decl <- p
376 Nothing -> return decl
377 Just n -> do fOk <- fixityOK n
379 "Missing fixity declaration for " ++ show n
381 getName (PTy _ _ _ _ _ n _) = Just n
383 fixityOK (NS n _) = fixityOK n
384 fixityOK (UN n) | all (flip elem opChars) (str n) =
385 do fixities <- fmap idris_infixes get
386 return . elem (str n) . map (\ (Fix _ op) -> op) $ fixities
387 | otherwise = return True
388 fixityOK _ = return True
390{-| Parses function options given initial options
398 | '%' 'error_handler'
400 | '%' 'specialise' '[' NameTimesList? ']'
405NameTimes ::= FnName Natural?;
411 | NameTimes ',' NameTimesList
415-- FIXME: Check compatability for function options (i.e. partal/total)
417-- Issue #1574 on the issue tracker.
418-- https://github.com/idris-lang/Idris-dev/issues/1574
419fnOpts :: [FnOpt] -> IdrisParser [FnOpt]
421 = do reserved "total"; fnOpts (TotalFn : opts)
422 <|> do reserved "partial"; fnOpts (PartialFn : (opts \\ [TotalFn]))
423 <|> do reserved "covering"; fnOpts (CoveringFn : (opts \\ [TotalFn]))
424 <|> do try (lchar '%' *> reserved "export"); c <- stringLiteral;
425 fnOpts (CExport c : opts)
426 <|> do try (lchar '%' *> reserved "no_implicit");
427 fnOpts (NoImplicit : opts)
428 <|> do try (lchar '%' *> reserved "assert_total");
429 fnOpts (AssertTotal : opts)
430 <|> do try (lchar '%' *> reserved "error_handler");
431 fnOpts (ErrorHandler : opts)
432 <|> do try (lchar '%' *> reserved "error_reverse");
433 fnOpts (ErrorReverse : opts)
434 <|> do try (lchar '%' *> reserved "reflection");
435 fnOpts (Reflection : opts)
436 <|> do lchar '%'; reserved "specialise";
437 lchar '['; ns <- sepBy nameTimes (lchar ','); lchar ']'
438 fnOpts (Specialise ns : opts)
439 <|> do reserved "implicit"; fnOpts (Implicit : opts)
441 <?> "function modifier"
442 where nameTimes :: IdrisParser (Name, Maybe Int)
443 nameTimes = do n <- fnName
444 t <- option Nothing (do reds <- natural
445 return (Just (fromInteger reds)))
448{- | Parses a postulate
452 DocComment_t? 'postulate' FnOpts* Accesibility? FnOpts* FnName TypeSig Terminator
456postulate :: SyntaxInfo -> IdrisParser PDecl
457postulate syn = do doc <- try $ do (doc, _) <- option noDocs docComment
459 let doc' = annotCode (tryFullExpr syn ist) doc
464 let initOpts = if default_total ist
467 opts <- fnOpts initOpts
468 acc <- optional accessibility
471 let n = expandNS syn n_in
473 ty <- typeExpr (allowImp syn)
477 return (PPostulate doc syn fc opts' n ty)
480{- | Parses a using declaration
484 'using' '(' UsingDeclList ')' OpenBlock Decl* CloseBlock
488using_ :: SyntaxInfo -> IdrisParser [PDecl]
490 do reserved "using"; lchar '('; ns <- usingDeclList syn; lchar ')'
492 let uvars = using syn
493 ds <- many (decl (syn { using = uvars ++ ns }))
496 <?> "using declaration"
498{- | Parses a parameters declaration
502 'parameters' '(' TypeDeclList ')' OpenBlock Decl* CloseBlock
506params :: SyntaxInfo -> IdrisParser [PDecl]
508 do reserved "parameters"; lchar '('; ns <- typeDeclList syn; lchar ')'
510 let pvars = syn_params syn
511 ds <- many (decl syn { syn_params = pvars ++ ns })
514 return [PParams fc ns (concat ds)]
515 <?> "parameters declaration"
517{- | Parses a mutual declaration (for mutually recursive functions)
521 'mutual' OpenBlock Decl* CloseBlock
525mutual :: SyntaxInfo -> IdrisParser [PDecl]
529 let pvars = syn_params syn
530 ds <- many (decl (syn { mut_nesting = mut_nesting syn + 1 } ))
533 return [PMutual fc (concat ds)]
536{-| Parses a namespace declaration
540 'namespace' identifier OpenBlock Decl+ CloseBlock
544namespace :: SyntaxInfo -> IdrisParser [PDecl]
546 do reserved "namespace"; n <- identifier;
548 ds <- some (decl syn { syn_namespace = n : syn_namespace syn })
550 return [PNamespace n (concat ds)]
551 <?> "namespace declaration"
553{- | Parses a methods block (for instances)
556 InstanceBlock ::= 'where' OpenBlock FnDecl* CloseBlock
559instanceBlock :: SyntaxInfo -> IdrisParser [PDecl]
560instanceBlock syn = do reserved "where"
562 ds <- many (fnDecl syn)
567{- | Parses a methods and instances block (for type classes)
578 'where' OpenBlock MethodOrInstance* CloseBlock
582classBlock :: SyntaxInfo -> IdrisParser [PDecl]
583classBlock syn = do reserved "where"
585 ds <- many ((notEndBlock >> instance_ syn) <|> fnDecl syn)
590{-| Parses a type class declaration
595 | '(' Name ':' Expr ')'
601 DocComment_t? Accessibility? 'class' ConstraintList? Name ClassArgument* ClassBlock?
605class_ :: SyntaxInfo -> IdrisParser [PDecl]
606class_ syn = do (doc, argDocs, acc) <- try (do
607 (doc, argDocs) <- option noDocs docComment
609 let doc' = annotCode (tryFullExpr syn ist) doc
610 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
611 | (n, d) <- argDocs ]
612 acc <- optional accessibility
613 return (doc', argDocs', acc))
614 reserved "class"; fc <- getFC; cons <- constraintList syn; n_in <- fnName
615 let n = expandNS syn n_in
617 ds <- option [] (classBlock syn)
618 accData acc n (concatMap declared ds)
619 return [PClass doc syn fc cons n cs argDocs ds]
620 <?> "type-class declaration"
622 carg :: IdrisParser (Name, PTerm)
623 carg = do lchar '('; i <- name; lchar ':'; ty <- expr syn; lchar ')'
628{- | Parses a type class instance declaration
632 'instance' InstanceName? ConstraintList? Name SimpleExpr* InstanceBlock?
637InstanceName ::= '[' Name ']';
640instance_ :: SyntaxInfo -> IdrisParser [PDecl]
641instance_ syn = do reserved "instance"; fc <- getFC
642 en <- optional instanceName
643 cs <- constraintList syn
645 args <- many (simpleExpr syn)
646 let sc = PApp fc (PRef fc cn) (map pexp args)
647 let t = bindList (PPi constraint) cs sc
648 ds <- option [] (instanceBlock syn)
649 return [PInstance syn fc cs cn args t en ds]
650 <?> "instance declaration"
651 where instanceName :: IdrisParser Name
652 instanceName = do lchar '['; n_in <- fnName; lchar ']'
653 let n = expandNS syn n_in
658{- | Parses a using declaration list
670 | UsingDecl ',' UsingDeclList'
681usingDeclList :: SyntaxInfo -> IdrisParser [Using]
683 = try (sepBy1 (usingDecl syn) (lchar ','))
684 <|> do ns <- sepBy1 name (lchar ',')
686 t <- typeExpr (disallowImp syn)
687 return (map (\x -> UImplicit x t) ns)
688 <?> "using declaration list"
690{- |Parses a using declaration
699usingDecl :: SyntaxInfo -> IdrisParser Using
700usingDecl syn = try (do x <- fnName
702 t <- typeExpr (disallowImp syn)
703 return (UImplicit x t))
706 return (UConstraint c xs)
707 <?> "using declaration"
709{- | Parse a clause with patterns
715pattern :: SyntaxInfo -> IdrisParser PDecl
716pattern syn = do fc <- getFC
718 return (PClauses fc [] (sMN 2 "_") [clause]) -- collect together later
721{- | Parse a constant applicative form declaration
724CAF ::= 'let' FnName '=' Expr Terminator;
727caf :: SyntaxInfo -> IdrisParser PDecl
728caf syn = do reserved "let"
729 n_in <- fnName; let n = expandNS syn n_in
735 <?> "constant applicative form declaration"
737{- | Parse an argument expression
740ArgExpr ::= HSimpleExpr | {- In Pattern External (User-defined) Expression -};
743argExpr :: SyntaxInfo -> IdrisParser PTerm
744argExpr syn = let syn' = syn { inPattern = True } in
745 try (hsimpleExpr syn') <|> simpleExternalExpr syn'
746 <?> "argument expression"
748{- | Parse a right hand side of a function
758RHSName ::= '{' FnName '}';
761rhs :: SyntaxInfo -> Name -> IdrisParser PTerm
762rhs syn n = do lchar '='; expr syn
765 name <- option n' (do symbol "{"; n <- fnName; symbol "}";
768 return (addLet fc name r)
769 <|> do reserved "impossible"; return PImpossible
770 <?> "function right hand side"
771 where mkN :: Name -> Name
772 mkN (UN x) = if (tnull x || not (isAlpha (thead x)))
773 then sUN "infix_op_lemma_1"
774 else sUN (str x++"_lemma_1")
775 mkN (NS x n) = NS (mkN x) n
778 addLet :: FC -> Name -> PTerm -> PTerm
779 addLet fc nm (PLet fc' n ty val r) = PLet fc' n ty val (addLet fc nm r)
780 addLet fc nm (PCase fc' t cs) = PCase fc' t (map addLetC cs)
781 where addLetC (l, r) = (l, addLet fc nm r)
782 addLet fc nm r = (PLet fc (sUN "value") Placeholder r (PMetavar nm))
784{- |Parses a function clause
787RHSOrWithBlock ::= RHS WhereOrTerminator
788 | 'with' SimpleExpr OpenBlock FnDecl+ CloseBlock
793Clause ::= WExpr+ RHSOrWithBlock
794 | SimpleExpr '<==' FnName RHS WhereOrTerminator
795 | ArgExpr Operator ArgExpr WExpr* RHSOrWithBlock {- Except "=" and "?=" operators to avoid ambiguity -}
796 | FnName ConstraintArg* ImplicitOrArgExpr* WExpr* RHSOrWithBlock
801ImplicitOrArgExpr ::= ImplicitArg | ArgExpr;
805WhereOrTerminator ::= WhereBlock | Terminator;
808clause :: SyntaxInfo -> IdrisParser PClause
810 = do wargs <- try (do pushIndent; some (wExpr syn))
813 n <- case lastParse ist of
815 Nothing -> fail "Invalid clause"
817 let ctxt = tt_ctxt ist
818 let wsyn = syn { syn_namespace = [] }
819 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
824 return $ PClauseR fc wargs r wheres) <|> (do
827 wval <- simpleExpr syn
829 ds <- some $ fnDecl syn
830 let withs = concat ds
832 return $ PWithR fc wargs wval withs)
833 <|> do ty <- try (do pushIndent
838 n_in <- fnName; let n = expandNS syn n_in
841 let ctxt = tt_ctxt ist
842 let wsyn = syn { syn_namespace = [] }
843 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
848 let capp = PLet fc (sMN 0 "match")
851 (PRef fc (sMN 0 "match"))
853 put (ist { lastParse = Just n })
854 return $ PClause fc n capp [] r wheres
855 <|> do (l, op) <- try (do
859 when (op == "=" || op == "?=" ) $
860 fail "infix clause definition with \"=\" and \"?=\" not supported "
862 let n = expandNS syn (sUN op)
865 wargs <- many (wExpr syn)
867 let wsyn = syn { syn_namespace = [] }
868 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
874 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
875 put (ist { lastParse = Just n })
876 return $ PClause fc n capp wargs rs wheres) <|> (do
879 wval <- bracketed syn
881 ds <- some $ fnDecl syn
884 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
885 let withs = map (fillLHSD n capp wargs) $ concat ds
886 put (ist { lastParse = Just n })
887 return $ PWith fc n capp wargs wval withs)
889 n_in <- fnName; let n = expandNS syn n_in
890 cargs <- many (constraintArg syn)
892 args <- many (try (implicitArg (syn { inPattern = True } ))
893 <|> (fmap pexp (argExpr syn)))
894 wargs <- many (wExpr syn)
895 let capp = PApp fc (PRef fc n)
899 let ctxt = tt_ctxt ist
900 let wsyn = syn { syn_namespace = [] }
901 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
907 put (ist { lastParse = Just n })
908 return $ PClause fc n capp wargs r wheres) <|> (do
911 put (ist { lastParse = Just n })
912 wval <- bracketed syn
914 ds <- some $ fnDecl syn
915 let withs = map (fillLHSD n capp wargs) $ concat ds
918 return $ PWith fc n capp wargs wval withs)
919 <?> "function clause"
921 fillLHS :: Name -> PTerm -> [PTerm] -> PClause -> PClause
922 fillLHS n capp owargs (PClauseR fc wargs v ws)
923 = PClause fc n capp (owargs ++ wargs) v ws
924 fillLHS n capp owargs (PWithR fc wargs v ws)
925 = PWith fc n capp (owargs ++ wargs) v
926 (map (fillLHSD n capp (owargs ++ wargs)) ws)
929 fillLHSD :: Name -> PTerm -> [PTerm] -> PDecl -> PDecl
930 fillLHSD n c a (PClauses fc o fn cs) = PClauses fc o fn (map (fillLHS n c a) cs)
933{-| Parses with pattern
939wExpr :: SyntaxInfo -> IdrisParser PTerm
940wExpr syn = do lchar '|'
941 expr' (syn { inPattern = True })
944{- | Parses a where block
947WhereBlock ::= 'where' OpenBlock Decl+ CloseBlock;
950whereBlock :: Name -> SyntaxInfo -> IdrisParser ([PDecl], [(Name, Name)])
952 = do reserved "where"
953 ds <- indentedBlock1 (decl syn)
954 let dns = concatMap (concatMap declared) ds
955 return (concat ds, map (\x -> (x, decoration syn x)) dns)
958{- |Parses a code generation target language name
970codegen_ :: IdrisParser Codegen
971codegen_ = do n <- identifier; return (Via (map toLower n))
972 <|> do reserved "Bytecode"; return Bytecode
973 <?> "code generation language"
975{- |Parses a compiler directive
979 | String ',' StringList
984Directive ::= '%' Directive';
988Directive' ::= 'lib' CodeGen String_t
989 | 'link' CodeGen String_t
990 | 'flag' CodeGen String_t
991 | 'include' CodeGen String_t
994 | 'access' Accessibility
997 | 'dynamic' StringList
998 | 'name' Name NameList
999 | 'error_handlers' Name NameList
1000 | 'language' 'TypeProviders'
1001 | 'language' 'ErrorReflection'
1005directive :: SyntaxInfo -> IdrisParser [PDecl]
1006directive syn = do try (lchar '%' *> reserved "lib"); cgn <- codegen_; lib <- stringLiteral;
1007 return [PDirective (do addLib cgn lib
1008 addIBC (IBCLib cgn lib))]
1009 <|> do try (lchar '%' *> reserved "link"); cgn <- codegen_; obj <- stringLiteral;
1010 return [PDirective (do dirs <- allImportDirs
1011 o <- liftIO $ findInPath dirs obj
1012 addIBC (IBCObj cgn obj) -- just name, search on loading ibc
1013 addObjectFile cgn o)]
1014 <|> do try (lchar '%' *> reserved "flag"); cgn <- codegen_;
1015 flag <- stringLiteral
1016 return [PDirective (do addIBC (IBCCGFlag cgn flag)
1018 <|> do try (lchar '%' *> reserved "include"); cgn <- codegen_; hdr <- stringLiteral;
1019 return [PDirective (do addHdr cgn hdr
1020 addIBC (IBCHeader cgn hdr))]
1021 <|> do try (lchar '%' *> reserved "hide"); n <- fnName
1022 return [PDirective (do setAccessibility n Hidden
1023 addIBC (IBCAccess n Hidden))]
1024 <|> do try (lchar '%' *> reserved "freeze"); n <- iName []
1025 return [PDirective (do setAccessibility n Frozen
1026 addIBC (IBCAccess n Frozen))]
1027 <|> do try (lchar '%' *> reserved "access"); acc <- accessibility
1028 return [PDirective (do i <- get
1029 put(i { default_access = acc }))]
1030 <|> do try (lchar '%' *> reserved "default"); tot <- totality
1032 put (i { default_total = tot } )
1033 return [PDirective (do i <- get
1034 put(i { default_total = tot }))]
1035 <|> do try (lchar '%' *> reserved "logging"); i <- natural;
1036 return [PDirective (setLogLevel (fromInteger i))]
1037 <|> do try (lchar '%' *> reserved "dynamic"); libs <- sepBy1 stringLiteral (lchar ',');
1038 return [PDirective (do added <- addDyLib libs
1040 Left lib -> addIBC (IBCDyLib (lib_name lib))
1043 <|> do try (lchar '%' *> reserved "name")
1045 ns <- sepBy1 name (lchar ',')
1046 return [PDirective (do ty' <- disambiguate ty
1047 mapM_ (addNameHint ty') ns
1048 mapM_ (\n -> addIBC (IBCNameHint (ty', n))) ns)]
1049 <|> do try (lchar '%' *> reserved "error_handlers")
1052 ns <- sepBy1 name (lchar ',')
1053 return [PDirective (do fn' <- disambiguate fn
1054 ns' <- mapM disambiguate ns
1055 addFunctionErrorHandlers fn' arg ns'
1056 mapM_ (addIBC . IBCFunctionErrorHandler fn' arg) ns')]
1057 <|> do try (lchar '%' *> reserved "language"); ext <- pLangExt;
1058 return [PDirective (addLangExt ext)]
1060 where disambiguate :: Name -> Idris Name
1061 disambiguate n = do i <- getIState
1062 case lookupCtxtName n (idris_implicits i) of
1063 [(n', _)] -> return n'
1064 [] -> throwError (NoSuchVariable n)
1065 more -> throwError (CantResolveAlts (map fst more))
1067pLangExt :: IdrisParser LanguageExt
1068pLangExt = (reserved "TypeProviders" >> return TypeProviders)
1069 <|> (reserved "ErrorReflection" >> return ErrorReflection)
1071{- | Parses a totality
1074Totality ::= 'partial' | 'total'
1078totality :: IdrisParser Bool
1080 = do reserved "total"; return True
1081 <|> do reserved "partial"; return False
1083{- | Parses a type provider
1086Provider ::= '%' 'provide' Provider_What? '(' FnName TypeSig ')' 'with' Expr;
1087ProviderWhat ::= 'proof' | 'term' | 'type' | 'postulate'
1090provider :: SyntaxInfo -> IdrisParser [PDecl]
1091provider syn = do try (lchar '%' *> reserved "provide");
1092 provideTerm <|> providePostulate
1094 where provideTerm = do lchar '('; n <- fnName; lchar ':'; t <- typeExpr syn; lchar ')'
1097 e <- expr syn <?> "provider expression"
1098 return [PProvider syn fc (ProvTerm t e) n]
1099 providePostulate = do reserved "postulate"
1103 e <- expr syn <?> "provider expression"
1104 return [PProvider syn fc (ProvPostulate e) n]
1106{- | Parses a transform
1109Transform ::= '%' 'transform' Expr '==>' Expr
1112transform :: SyntaxInfo -> IdrisParser [PDecl]
1113transform syn = do try (lchar '%' *> reserved "transform")
1114 -- leave it unchecked, until we work out what this should
1116-- safety <- option True (do reserved "unsafe"
1122 return [PTransform fc False l r]
1126{- * Loading and parsing -}
1127{- | Parses an expression from input -}
1128parseExpr :: IState -> String -> Result PTerm
1129parseExpr st = runparser (fullExpr defaultSyntax) st "(input)"
1131{- | Parses a constant form input -}
1132parseConst :: IState -> String -> Result Const
1133parseConst st = runparser constant st "(input)"
1135{- | Parses a tactic from input -}
1136parseTactic :: IState -> String -> Result PTactic
1137parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
1139-- | Parse module header and imports
1140parseImports :: FilePath -> String -> Idris (Maybe (Docstring ()), [String], [(Bool, String, Maybe String, FC)], Maybe Delta)
1141parseImports fname input
1143 case parseString (runInnerParser (evalStateT imports i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
1144 Failure err -> fail (show err)
1145 Success (x, i) -> do putIState i
1147 where imports :: IdrisParser ((Maybe (Docstring ()), [String], [(Bool, String, Maybe String, FC)], Maybe Delta), IState)
1148 imports = do whiteSpace
1149 (mdoc, mname) <- moduleHeader
1152 isEof <- lookAheadMatches eof
1157 return ((mdoc, mname, ps, mrk'), i)
1159-- | There should be a better way of doing this...
1160findFC :: Doc -> (FC, String)
1161findFC x = let s = show (plain x) in
1162 case span (/= ':') s of
1163 (failname, ':':rest) -> case span isDigit rest of
1164 (line, ':':rest') -> case span isDigit rest' of
1165 (col, ':':msg) -> let pos = (read line, read col) in
1166 (FC failname pos pos, msg)
1168-- | Check if the coloring matches the options and corrects if necessary
1169fixColour :: Bool -> ANSI.Doc -> ANSI.Doc
1170fixColour False doc = ANSI.plain doc
1171fixColour True doc = doc
1173-- | A program is a list of declarations, possibly with associated
1174-- documentation strings.
1175parseProg :: SyntaxInfo -> FilePath -> String -> Maybe Delta ->
1177parseProg syn fname input mrk
1179 case runparser mainProg i fname input of
1180 Failure doc -> do -- FIXME: Get error location from trifecta
1181 -- this can't be the solution!
1182 -- Issue #1575 on the issue tracker.
1183 -- https://github.com/idris-lang/Idris-dev/issues/1575
1184 let (fc, msg) = findFC doc
1186 case idris_outputmode i of
1187 RawOutput h -> iputStrLn (show $ fixColour (idris_colourRepl i) doc)
1188 IdeSlave n h -> iWarn fc (P.text msg)
1189 putIState (i { errSpan = Just fc })
1191 Success (x, i) -> do putIState i
1192 reportParserWarnings
1194 where mainProg :: IdrisParser ([PDecl], IState)
1195 mainProg = case mrk of
1196 Nothing -> do i <- get; return ([], i)
1203{- | Load idris module and show error if something wrong happens -}
1204loadModule :: FilePath -> Idris (Maybe String)
1206 = idrisCatch (fmap Just (loadModule' f))
1207 (\e -> do setErrSpan (getErrSpan e)
1209 iWarn (getErrSpan e) $ pprintErr ist e
1212{- | Load idris module -}
1213loadModule' :: FilePath -> Idris String
1216 let file = takeWhile (/= ' ') f
1217 ibcsd <- valIBCSubDir i
1218 ids <- allImportDirs
1219 fp <- findImport ids ibcsd file
1220 if file `elem` imported i
1221 then iLOG $ "Already read " ++ file
1222 else do putIState (i { imported = file : imported i })
1224 IDR fn -> loadSource False fn Nothing
1225 LIDR fn -> loadSource True fn Nothing
1227 idrisCatch (loadIBC True fn)
1228 (\c -> do iLOG $ fn ++ " failed " ++ pshow i c
1230 IDR sfn -> loadSource False sfn Nothing
1231 LIDR sfn -> loadSource True sfn Nothing)
1232 let (dir, fh) = splitFileName file
1233 return (dropExtension fh)
1236{- | Load idris code from file -}
1237loadFromIFile :: Bool -> IFileType -> Maybe Int -> Idris ()
1238loadFromIFile reexp i@(IBC fn src) maxline
1239 = do iLOG $ "Skipping " ++ getSrcFile i
1240 idrisCatch (loadIBC reexp fn)
1241 (\err -> ierror $ LoadingFailed fn err)
1243 getSrcFile (IDR fn) = fn
1244 getSrcFile (LIDR fn) = fn
1245 getSrcFile (IBC f src) = getSrcFile src
1247loadFromIFile _ (IDR fn) maxline = loadSource' False fn maxline
1248loadFromIFile _ (LIDR fn) maxline = loadSource' True fn maxline
1250{-| Load idris source code and show error if something wrong happens -}
1251loadSource' :: Bool -> FilePath -> Maybe Int -> Idris ()
1252loadSource' lidr r maxline
1253 = idrisCatch (loadSource lidr r maxline)
1254 (\e -> do setErrSpan (getErrSpan e)
1257 At f e' -> iWarn f (pprintErr ist e')
1258 _ -> iWarn (getErrSpan e) (pprintErr ist e))
1260{- | Load Idris source code-}
1261loadSource :: Bool -> FilePath -> Maybe Int -> Idris ()
1262loadSource lidr f toline
1263 = do iLOG ("Reading " ++ f)
1265 let def_total = default_total i
1266 file_in <- runIO $ readFile f
1267 file <- if lidr then tclift $ unlit f file_in else return file_in
1268 (mdocs, mname, imports_in, pos) <- parseImports f file
1269 ai <- getAutoImports
1270 let imports = map (\n -> (True, n, Just n, emptyFC)) ai ++ imports_in
1271 ids <- allImportDirs
1272 ibcsd <- valIBCSubDir i
1274 do fp <- findImport ids ibcsd f
1276 LIDR fn -> ifail $ "No ibc for " ++ f
1277 IDR fn -> ifail $ "No ibc for " ++ f
1278 IBC fn src -> loadIBC True fn)
1279 [(re, fn) | (re, fn, _, _) <- imports]
1280 reportParserWarnings
1282 -- process and check module aliases
1283 let modAliases = M.fromList
1284 [(prep alias, prep realName) | (reexport, realName, Just alias, fc) <- imports]
1285 prep = map T.pack . reverse . Spl.splitOn "/"
1286 aliasNames = [(alias, fc) | (_, _, Just alias, fc) <- imports]
1287 histogram = groupBy ((==) `on` fst) . sortBy (comparing fst) $ aliasNames
1288 case map head . filter ((/= 1) . length) $ histogram of
1289 [] -> logLvl 3 $ "Module aliases: " ++ show (M.toList modAliases)
1290 (n,fc):_ -> throwError . At fc . Msg $ "import alias not unique: " ++ show n
1293 putIState (i { default_access = Hidden, module_aliases = modAliases })
1294 clearIBC -- start a new .ibc file
1295 -- record package info in .ibc
1296 imps <- allImportDirs
1297 mapM_ addIBC (map IBCImportDir imps)
1298 mapM_ (addIBC . IBCImport) [(reexport, realName) | (reexport, realName, alias, fc) <- imports]
1299 let syntax = defaultSyntax{ syn_namespace = reverse mname,
1301 ds' <- parseProg syntax f file pos
1303 -- Parsing done, now process declarations
1305 let ds = namespaces mname ds'
1306 logLvl 3 (show $ showDecls verbosePPOption ds)
1308 logLvl 10 (show (toAlist (idris_implicits i)))
1309 logLvl 3 (show (idris_infixes i))
1310 -- Now add all the declarations to the context
1312 when v $ iputStrLn $ "Type checking " ++ f
1313 -- we totality check after every Mutual block, so if
1314 -- anything is a single definition, wrap it in a
1315 -- mutual block on its own
1316 elabDecls toplevel (map toMutual ds)
1318 -- simplify every definition do give the totality checker
1320 mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
1321 updateContext (simplifyCasedef n $ getErasureInfo i))
1322 (map snd (idris_totcheck i))
1323 -- build size change graph from simplified definitions
1324 iLOG "Totality checking"
1326 mapM_ buildSCG (idris_totcheck i)
1327 mapM_ checkDeclTotality (idris_totcheck i)
1329 -- Redo totality check for deferred names
1330 let deftots = idris_defertotcheck i
1331 iLOG $ "Totality checking " ++ show deftots
1332 mapM_ (\x -> do tot <- getTotality x
1334 Total _ -> setTotality x Unchecked
1335 _ -> return ()) (map snd deftots)
1336 mapM_ buildSCG deftots
1337 mapM_ checkDeclTotality deftots
1339 iLOG ("Finished " ++ f)
1340 ibcsd <- valIBCSubDir i
1341 iLOG "Universe checking"
1343 let ibc = ibcPathNoFallback ibcsd f
1345 addHides (hide_list i)
1347 -- Save module documentation if applicable
1350 Nothing -> return ()
1351 Just docs -> addModDoc syntax mname docs
1354 -- Finally, write an ibc if checking was successful
1357 idrisCatch (do writeIBC f ibc; clearIBC)
1358 (\c -> return ()) -- failure is harmless
1360 putIState (i { default_total = def_total,
1364 namespaces :: [String] -> [PDecl] -> [PDecl]
1365 namespaces [] ds = ds
1366 namespaces (x:xs) ds = [PNamespace x (namespaces xs ds)]
1368 toMutual :: PDecl -> PDecl
1369 toMutual m@(PMutual _ d) = m
1370 toMutual (PNamespace x ds) = PNamespace x (map toMutual ds)
1371 toMutual x = let r = PMutual (fileFC "single mutual") [x] in
1373 PClauses _ _ _ _ -> r
1374 PClass _ _ _ _ _ _ _ _ -> r
1375 PInstance _ _ _ _ _ _ _ _ -> r
1378 addModDoc :: SyntaxInfo -> [String] -> Docstring () -> Idris ()
1379 addModDoc syn mname docs =
1381 docs' <- elabDocTerms recinfo (parsedDocs ist)
1382 let modDocs' = addDef docName docs' (idris_moduledocs ist)
1383 putIState ist { idris_moduledocs = modDocs' }
1384 addIBC (IBCModDocs docName)
1386 docName = NS modDocName (map T.pack (reverse mname))
1387 parsedDocs ist = annotCode (tryFullExpr syn ist) docs
1389{- | Adds names to hide list -}
1390addHides :: [(Name, Maybe Accessibility)] -> Idris ()
1391addHides xs = do i <- getIState
1392 let defh = default_access i
1393 let (hs, as) = partition isNothing xs
1396 (map (\ (n, _) -> (n, defh)) hs ++
1397 map (\ (n, Just a) -> (n, a)) as)
1398 where isNothing (_, Nothing) = True
1401 doHide (n, a) = do setAccessibility n a
1402 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