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
35import Idris.ParseHelpers
40import Idris.Docstrings
44import Util.DynamicLinker
45import qualified Util.Pretty as P
48import Idris.Core.Evaluate
50import Control.Applicative hiding (Const)
52import Control.Monad.Error (throwError, catchError)
53import Control.Monad.State.Strict
57import qualified Data.List.Split as Spl
62import qualified Data.Map as M
63import qualified Data.HashSet as HS
64import qualified Data.Text as T
65import qualified Data.ByteString.UTF8 as UTF8
66import qualified Data.Set as S
75 grammar shortcut notation:
76 ~CHARSEQ = complement of char sequence (i.e. any character except CHARSEQ)
77 RULE? = optional rule (i.e. RULE or nothing)
78 RULE* = repeated rule (i.e. RULE zero or more times)
79 RULE+ = repeated rule with at least one match (i.e. RULE one or more times)
80 RULE! = invalid rule (i.e. rule that is not valid in context, report meaningful error in case)
81 RULE{n} = rule repeated n times
87{- | Parses module definition
90 ModuleHeader ::= 'module' Identifier_t ';'?;
93moduleHeader :: IdrisParser [String]
94moduleHeader = try (do noDocCommentHere "Modules cannot have documentation comments"
97 option ';' (lchar ';')
98 return (moduleName i))
99 <|> try (do lchar '%'; reserved "unqualified"
101 <|> return (moduleName "Main")
102 where moduleName x = case span (/='.') x of
104 (x, '.':y) -> x : moduleName y
106{- | Parses an import statement
109 Import ::= 'import' Identifier_t ';'?;
112import_ :: IdrisParser (String, Maybe String, FC)
113import_ = do fc <- getFC
116 newName <- optional (reserved "as" *> identifier)
117 option ';' (lchar ';')
118 return (toPath id, toPath <$> newName, fc)
119 <?> "import statement"
120 where toPath = foldl1' (</>) . Spl.splitOn "."
122{- | Parses program source
128prog :: SyntaxInfo -> IdrisParser [PDecl]
129prog syn = do whiteSpace
130 decls <- many (decl syn)
131 let c = (concat decls)
133 Nothing -> do notOpenBraces; eof
137 put ist { idris_parsedSpan = Just (FC (fc_fname fc) (0,0) (fc_end fc)),
138 ibc_write = IBCParsedRegion fc : ibc_write ist }
141{-| Parses a top-level declaration
160decl :: SyntaxInfo -> IdrisParser [PDecl]
161decl syn = do fc <- getFC
162 -- if we're after maxline, stop here
163 let continue = case maxline syn of
165 Just l -> if fst (fc_end fc) > l
166 then mut_nesting syn /= 0
168 if continue then do notEndBlock
170 else fail "End of readable input"
171 where declBody :: IdrisParser [PDecl]
179 <|> do d <- dsl syn; return [d]
183 <|> do import_; fail "imports must be at top of file"
185 declBody' :: IdrisParser [PDecl]
186 declBody' = do d <- decl' syn
188 let d' = fmap (debindApp syn . (desugar syn i)) d
191{- | Parses a top-level declaration with possible syntax sugar
203decl' :: SyntaxInfo -> IdrisParser PDecl
211{- | Parses a syntax extension declaration (and adds the rule to parser state)
214 SyntaxDecl ::= SyntaxRule;
217syntaxDecl :: SyntaxInfo -> IdrisParser PDecl
218syntaxDecl syn = do s <- syntaxRule syn
220 put (i `addSyntax` s)
222 return (PSyntax fc s)
224-- | Extend an 'IState' with a new syntax extension. See also 'addReplSyntax'.
225addSyntax :: IState -> Syntax -> IState
226addSyntax i s = i { syntax_rules = s : rs,
227 syntax_keywords = ks ++ ns,
228 ibc_write = IBCSyntax s : map IBCKeyword ks ++ ibc }
229 where rs = syntax_rules i
230 ns = syntax_keywords i
232 ks = map show (syntaxNames s)
234-- | Like 'addSyntax', but no effect on the IBC.
235addReplSyntax :: IState -> Syntax -> IState
236addReplSyntax i s = i { syntax_rules = s : rs,
237 syntax_keywords = ks ++ ns }
238 where rs = syntax_rules i
239 ns = syntax_keywords i
240 ks = map show (syntaxNames s)
242{- | Parses a syntax extension declaration
245SyntaxRuleOpts ::= 'term' | 'pattern';
250 SyntaxRuleOpts? 'syntax' SyntaxSym+ '=' TypeExpr Terminator;
254SyntaxSym ::= '[' Name_t ']'
261syntaxRule :: SyntaxInfo -> IdrisParser Syntax
265 sty <- option AnySyntax (do reserved "term"; return TermSyntax
266 <|> do reserved "pattern"; return PatternSyntax)
269 syms <- some syntaxSym
270 when (all isExpr syms) $ unexpected "missing keywords in syntax rule"
271 let ns = mapMaybe getName syms
272 when (length ns /= length (nub ns))
273 $ unexpected "repeated variable in syntax rule"
275 tm <- typeExpr (allowImp syn)
277 return (Rule (mkSimple syms) tm sty)
279 isExpr (Expr _) = True
281 getName (Expr n) = Just n
283 -- Can't parse two full expressions (i.e. expressions with application) in a row
284 -- so change them both to a simple expression
285 mkSimple (Expr e : es) = SimpleExpr e : mkSimple' es
286 mkSimple xs = mkSimple' xs
288 mkSimple' (Expr e : Expr e1 : es) = SimpleExpr e : SimpleExpr e1 :
290 mkSimple' (e : es) = e : mkSimple' es
294{- | Parses a syntax symbol (either binding variable, keyword or expression)
297SyntaxSym ::= '[' Name_t ']'
304syntaxSym :: IdrisParser SSymbol
305syntaxSym = try (do lchar '['; n <- name; lchar ']'
307 <|> try (do lchar '{'; n <- name; lchar '}'
311 <|> do sym <- stringLiteral
315{- | Parses a function declaration with possible syntax sugar
318 FunDecl ::= FunDecl';
321fnDecl :: SyntaxInfo -> IdrisParser [PDecl]
322fnDecl syn = try (do notEndBlock
325 let d' = fmap (desugar syn i) d
326 return [d']) <?> "function declaration"
328{-| Parses a function declaration
332 DocComment_t? FnOpts* Accessibility? FnOpts* FnName TypeSig Terminator
339fnDecl' :: SyntaxInfo -> IdrisParser PDecl
340fnDecl' syn = checkFixity $
341 do (doc, argDocs, fc, opts', n, acc) <- try (do
343 (doc, argDocs) <- option noDocs docComment
345 let doc' = annotCode (tryFullExpr syn ist) doc
346 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
347 | (n, d) <- argDocs ]
349 initOpts = if default_total ist
352 opts <- fnOpts initOpts
353 acc <- optional accessibility
356 let n = expandNS syn n_in
359 return (doc', argDocs', fc, opts', n, acc))
360 ty <- typeExpr (allowImp syn)
363 return (PTy doc argDocs syn fc opts' n ty)
367 <?> "function declaration"
368 where checkFixity :: IdrisParser PDecl -> IdrisParser PDecl
369 checkFixity p = do decl <- p
371 Nothing -> return decl
372 Just n -> do fOk <- fixityOK n
374 "Missing fixity declaration for " ++ show n
376 getName (PTy _ _ _ _ _ n _) = Just n
378 fixityOK (NS n _) = fixityOK n
379 fixityOK (UN n) | all (flip elem opChars) (str n) =
380 do fixities <- fmap idris_infixes get
381 return . elem (str n) . map (\ (Fix _ op) -> op) $ fixities
382 | otherwise = return True
383 fixityOK _ = return True
385{-| Parses function options given initial options
393 | '%' 'error_handler'
395 | '%' 'specialise' '[' NameTimesList? ']'
400NameTimes ::= FnName Natural?;
406 | NameTimes ',' NameTimesList
410-- FIXME: Check compatability for function options (i.e. partal/total)
412-- Issue #1574 on the issue tracker.
413-- https://github.com/idris-lang/Idris-dev/issues/1574
414fnOpts :: [FnOpt] -> IdrisParser [FnOpt]
416 = do reserved "total"; fnOpts (TotalFn : opts)
417 <|> do reserved "partial"; fnOpts (PartialFn : (opts \\ [TotalFn]))
418 <|> do reserved "covering"; fnOpts (CoveringFn : (opts \\ [TotalFn]))
419 <|> do try (lchar '%' *> reserved "export"); c <- stringLiteral;
420 fnOpts (CExport c : opts)
421 <|> do try (lchar '%' *> reserved "no_implicit");
422 fnOpts (NoImplicit : opts)
423 <|> do try (lchar '%' *> reserved "assert_total");
424 fnOpts (AssertTotal : opts)
425 <|> do try (lchar '%' *> reserved "error_handler");
426 fnOpts (ErrorHandler : opts)
427 <|> do try (lchar '%' *> reserved "error_reverse");
428 fnOpts (ErrorReverse : opts)
429 <|> do try (lchar '%' *> reserved "reflection");
430 fnOpts (Reflection : opts)
431 <|> do lchar '%'; reserved "specialise";
432 lchar '['; ns <- sepBy nameTimes (lchar ','); lchar ']'
433 fnOpts (Specialise ns : opts)
434 <|> do reserved "implicit"; fnOpts (Implicit : opts)
436 <?> "function modifier"
437 where nameTimes :: IdrisParser (Name, Maybe Int)
438 nameTimes = do n <- fnName
439 t <- option Nothing (do reds <- natural
440 return (Just (fromInteger reds)))
443{- | Parses a postulate
447 DocComment_t? 'postulate' FnOpts* Accesibility? FnOpts* FnName TypeSig Terminator
451postulate :: SyntaxInfo -> IdrisParser PDecl
452postulate syn = do doc <- try $ do (doc, _) <- option noDocs docComment
454 let doc' = annotCode (tryFullExpr syn ist) doc
459 let initOpts = if default_total ist
462 opts <- fnOpts initOpts
463 acc <- optional accessibility
466 let n = expandNS syn n_in
468 ty <- typeExpr (allowImp syn)
472 return (PPostulate doc syn fc opts' n ty)
475{- | Parses a using declaration
479 'using' '(' UsingDeclList ')' OpenBlock Decl* CloseBlock
483using_ :: SyntaxInfo -> IdrisParser [PDecl]
485 do reserved "using"; lchar '('; ns <- usingDeclList syn; lchar ')'
487 let uvars = using syn
488 ds <- many (decl (syn { using = uvars ++ ns }))
491 <?> "using declaration"
493{- | Parses a parameters declaration
497 'parameters' '(' TypeDeclList ')' OpenBlock Decl* CloseBlock
501params :: SyntaxInfo -> IdrisParser [PDecl]
503 do reserved "parameters"; lchar '('; ns <- typeDeclList syn; lchar ')'
505 let pvars = syn_params syn
506 ds <- many (decl syn { syn_params = pvars ++ ns })
509 return [PParams fc ns (concat ds)]
510 <?> "parameters declaration"
512{- | Parses a mutual declaration (for mutually recursive functions)
516 'mutual' OpenBlock Decl* CloseBlock
520mutual :: SyntaxInfo -> IdrisParser [PDecl]
524 let pvars = syn_params syn
525 ds <- many (decl (syn { mut_nesting = mut_nesting syn + 1 } ))
528 return [PMutual fc (concat ds)]
531{-| Parses a namespace declaration
535 'namespace' identifier OpenBlock Decl+ CloseBlock
539namespace :: SyntaxInfo -> IdrisParser [PDecl]
541 do reserved "namespace"; n <- identifier;
543 ds <- some (decl syn { syn_namespace = n : syn_namespace syn })
545 return [PNamespace n (concat ds)]
546 <?> "namespace declaration"
548{- | Parses a methods block (for instances)
551 InstanceBlock ::= 'where' OpenBlock FnDecl* CloseBlock
554instanceBlock :: SyntaxInfo -> IdrisParser [PDecl]
555instanceBlock syn = do reserved "where"
557 ds <- many (fnDecl syn)
562{- | Parses a methods and instances block (for type classes)
573 'where' OpenBlock MethodOrInstance* CloseBlock
577classBlock :: SyntaxInfo -> IdrisParser [PDecl]
578classBlock syn = do reserved "where"
580 ds <- many ((notEndBlock >> instance_ syn) <|> fnDecl syn)
585{-| Parses a type class declaration
590 | '(' Name ':' Expr ')'
596 DocComment_t? Accessibility? 'class' ConstraintList? Name ClassArgument* ClassBlock?
600class_ :: SyntaxInfo -> IdrisParser [PDecl]
601class_ syn = do (doc, argDocs, acc) <- try (do
602 (doc, argDocs) <- option noDocs docComment
604 let doc' = annotCode (tryFullExpr syn ist) doc
605 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
606 | (n, d) <- argDocs ]
607 acc <- optional accessibility
608 return (doc', argDocs', acc))
609 reserved "class"; fc <- getFC; cons <- constraintList syn; n_in <- fnName
610 let n = expandNS syn n_in
612 ds <- option [] (classBlock syn)
613 accData acc n (concatMap declared ds)
614 return [PClass doc syn fc cons n cs argDocs ds]
615 <?> "type-class declaration"
617 carg :: IdrisParser (Name, PTerm)
618 carg = do lchar '('; i <- name; lchar ':'; ty <- expr syn; lchar ')'
623{- | Parses a type class instance declaration
627 'instance' InstanceName? ConstraintList? Name SimpleExpr* InstanceBlock?
632InstanceName ::= '[' Name ']';
635instance_ :: SyntaxInfo -> IdrisParser [PDecl]
636instance_ syn = do reserved "instance"; fc <- getFC
637 en <- optional instanceName
638 cs <- constraintList syn
640 args <- many (simpleExpr syn)
641 let sc = PApp fc (PRef fc cn) (map pexp args)
642 let t = bindList (PPi constraint)
643 (map (\x -> (sMN 0 "constraint", x)) cs) sc
644 ds <- option [] (instanceBlock syn)
645 return [PInstance syn fc cs cn args t en ds]
646 <?> "instance declaration"
647 where instanceName :: IdrisParser Name
648 instanceName = do lchar '['; n_in <- fnName; lchar ']'
649 let n = expandNS syn n_in
654{- | Parses a using declaration list
666 | UsingDecl ',' UsingDeclList'
677usingDeclList :: SyntaxInfo -> IdrisParser [Using]
679 = try (sepBy1 (usingDecl syn) (lchar ','))
680 <|> do ns <- sepBy1 name (lchar ',')
682 t <- typeExpr (disallowImp syn)
683 return (map (\x -> UImplicit x t) ns)
684 <?> "using declaration list"
686{- |Parses a using declaration
695usingDecl :: SyntaxInfo -> IdrisParser Using
696usingDecl syn = try (do x <- fnName
698 t <- typeExpr (disallowImp syn)
699 return (UImplicit x t))
702 return (UConstraint c xs)
703 <?> "using declaration"
705{- | Parse a clause with patterns
711pattern :: SyntaxInfo -> IdrisParser PDecl
712pattern syn = do fc <- getFC
714 return (PClauses fc [] (sMN 2 "_") [clause]) -- collect together later
717{- | Parse a constant applicative form declaration
720CAF ::= 'let' FnName '=' Expr Terminator;
723caf :: SyntaxInfo -> IdrisParser PDecl
724caf syn = do reserved "let"
725 n_in <- fnName; let n = expandNS syn n_in
731 <?> "constant applicative form declaration"
733{- | Parse an argument expression
736ArgExpr ::= HSimpleExpr | {- In Pattern External (User-defined) Expression -};
739argExpr :: SyntaxInfo -> IdrisParser PTerm
740argExpr syn = let syn' = syn { inPattern = True } in
741 try (hsimpleExpr syn') <|> simpleExternalExpr syn'
742 <?> "argument expression"
744{- | Parse a right hand side of a function
754RHSName ::= '{' FnName '}';
757rhs :: SyntaxInfo -> Name -> IdrisParser PTerm
758rhs syn n = do lchar '='; expr syn
760 name <- option n' (do symbol "{"; n <- fnName; symbol "}";
763 return (addLet name r)
764 <|> do reserved "impossible"; return PImpossible
765 <?> "function right hand side"
766 where mkN :: Name -> Name
767 mkN (UN x) = if (tnull x || not (isAlpha (thead x)))
768 then sUN "infix_op_lemma_1"
769 else sUN (str x++"_lemma_1")
770 mkN (NS x n) = NS (mkN x) n
773 addLet :: Name -> PTerm -> PTerm
774 addLet nm (PLet n ty val r) = PLet n ty val (addLet nm r)
775 addLet nm (PCase fc t cs) = PCase fc t (map addLetC cs)
776 where addLetC (l, r) = (l, addLet nm r)
777 addLet nm r = (PLet (sUN "value") Placeholder r (PMetavar nm))
779{- |Parses a function clause
782RHSOrWithBlock ::= RHS WhereOrTerminator
783 | 'with' SimpleExpr OpenBlock FnDecl+ CloseBlock
788Clause ::= WExpr+ RHSOrWithBlock
789 | SimpleExpr '<==' FnName RHS WhereOrTerminator
790 | ArgExpr Operator ArgExpr WExpr* RHSOrWithBlock {- Except "=" and "?=" operators to avoid ambiguity -}
791 | FnName ConstraintArg* ImplicitOrArgExpr* WExpr* RHSOrWithBlock
796ImplicitOrArgExpr ::= ImplicitArg | ArgExpr;
800WhereOrTerminator ::= WhereBlock | Terminator;
803clause :: SyntaxInfo -> IdrisParser PClause
805 = do wargs <- try (do pushIndent; some (wExpr syn))
808 n <- case lastParse ist of
810 Nothing -> fail "Invalid clause"
812 let ctxt = tt_ctxt ist
813 let wsyn = syn { syn_namespace = [] }
814 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
819 return $ PClauseR fc wargs r wheres) <|> (do
822 wval <- simpleExpr syn
824 ds <- some $ fnDecl syn
825 let withs = concat ds
827 return $ PWithR fc wargs wval withs)
828 <|> do ty <- try (do pushIndent
833 n_in <- fnName; let n = expandNS syn n_in
836 let ctxt = tt_ctxt ist
837 let wsyn = syn { syn_namespace = [] }
838 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
843 let capp = PLet (sMN 0 "match")
846 (PRef fc (sMN 0 "match"))
848 put (ist { lastParse = Just n })
849 return $ PClause fc n capp [] r wheres
850 <|> do (l, op) <- try (do
854 when (op == "=" || op == "?=" ) $
855 fail "infix clause definition with \"=\" and \"?=\" not supported "
857 let n = expandNS syn (sUN op)
860 wargs <- many (wExpr syn)
862 let wsyn = syn { syn_namespace = [] }
863 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
869 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
870 put (ist { lastParse = Just n })
871 return $ PClause fc n capp wargs rs wheres) <|> (do
874 wval <- bracketed syn
876 ds <- some $ fnDecl syn
879 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
880 let withs = map (fillLHSD n capp wargs) $ concat ds
881 put (ist { lastParse = Just n })
882 return $ PWith fc n capp wargs wval withs)
884 n_in <- fnName; let n = expandNS syn n_in
885 cargs <- many (constraintArg syn)
887 args <- many (try (implicitArg (syn { inPattern = True } ))
888 <|> (fmap pexp (argExpr syn)))
889 wargs <- many (wExpr syn)
890 let capp = PApp fc (PRef fc n)
894 let ctxt = tt_ctxt ist
895 let wsyn = syn { syn_namespace = [] }
896 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
902 put (ist { lastParse = Just n })
903 return $ PClause fc n capp wargs r wheres) <|> (do
906 put (ist { lastParse = Just n })
907 wval <- bracketed syn
909 ds <- some $ fnDecl syn
910 let withs = map (fillLHSD n capp wargs) $ concat ds
913 return $ PWith fc n capp wargs wval withs)
914 <?> "function clause"
916 fillLHS :: Name -> PTerm -> [PTerm] -> PClause -> PClause
917 fillLHS n capp owargs (PClauseR fc wargs v ws)
918 = PClause fc n capp (owargs ++ wargs) v ws
919 fillLHS n capp owargs (PWithR fc wargs v ws)
920 = PWith fc n capp (owargs ++ wargs) v
921 (map (fillLHSD n capp (owargs ++ wargs)) ws)
924 fillLHSD :: Name -> PTerm -> [PTerm] -> PDecl -> PDecl
925 fillLHSD n c a (PClauses fc o fn cs) = PClauses fc o fn (map (fillLHS n c a) cs)
928{-| Parses with pattern
934wExpr :: SyntaxInfo -> IdrisParser PTerm
935wExpr syn = do lchar '|'
939{- | Parses a where block
942WhereBlock ::= 'where' OpenBlock Decl+ CloseBlock;
945whereBlock :: Name -> SyntaxInfo -> IdrisParser ([PDecl], [(Name, Name)])
947 = do reserved "where"
948 ds <- indentedBlock1 (decl syn)
949 let dns = concatMap (concatMap declared) ds
950 return (concat ds, map (\x -> (x, decoration syn x)) dns)
953{- |Parses a code generation target language name
965codegen_ :: IdrisParser Codegen
966codegen_ = do n <- identifier; return (Via (map toLower n))
967 <|> do reserved "Bytecode"; return Bytecode
968 <?> "code generation language"
970{- |Parses a compiler directive
974 | String ',' StringList
979Directive ::= '%' Directive';
983Directive' ::= 'lib' CodeGen String_t
984 | 'link' CodeGen String_t
985 | 'flag' CodeGen String_t
986 | 'include' CodeGen String_t
989 | 'access' Accessibility
992 | 'dynamic' StringList
993 | 'name' Name NameList
994 | 'error_handlers' Name NameList
995 | 'language' 'TypeProviders'
996 | 'language' 'ErrorReflection'
1000directive :: SyntaxInfo -> IdrisParser [PDecl]
1001directive syn = do try (lchar '%' *> reserved "lib"); cgn <- codegen_; lib <- stringLiteral;
1002 return [PDirective (do addLib cgn lib
1003 addIBC (IBCLib cgn lib))]
1004 <|> do try (lchar '%' *> reserved "link"); cgn <- codegen_; obj <- stringLiteral;
1005 return [PDirective (do dirs <- allImportDirs
1006 o <- liftIO $ findInPath dirs obj
1007 addIBC (IBCObj cgn obj) -- just name, search on loading ibc
1008 addObjectFile cgn o)]
1009 <|> do try (lchar '%' *> reserved "flag"); cgn <- codegen_;
1010 flag <- stringLiteral
1011 return [PDirective (do addIBC (IBCCGFlag cgn flag)
1013 <|> do try (lchar '%' *> reserved "include"); cgn <- codegen_; hdr <- stringLiteral;
1014 return [PDirective (do addHdr cgn hdr
1015 addIBC (IBCHeader cgn hdr))]
1016 <|> do try (lchar '%' *> reserved "hide"); n <- fnName
1017 return [PDirective (do setAccessibility n Hidden
1018 addIBC (IBCAccess n Hidden))]
1019 <|> do try (lchar '%' *> reserved "freeze"); n <- iName []
1020 return [PDirective (do setAccessibility n Frozen
1021 addIBC (IBCAccess n Frozen))]
1022 <|> do try (lchar '%' *> reserved "access"); acc <- accessibility
1023 return [PDirective (do i <- get
1024 put(i { default_access = acc }))]
1025 <|> do try (lchar '%' *> reserved "default"); tot <- totality
1027 put (i { default_total = tot } )
1028 return [PDirective (do i <- get
1029 put(i { default_total = tot }))]
1030 <|> do try (lchar '%' *> reserved "logging"); i <- natural;
1031 return [PDirective (setLogLevel (fromInteger i))]
1032 <|> do try (lchar '%' *> reserved "dynamic"); libs <- sepBy1 stringLiteral (lchar ',');
1033 return [PDirective (do added <- addDyLib libs
1035 Left lib -> addIBC (IBCDyLib (lib_name lib))
1038 <|> do try (lchar '%' *> reserved "name")
1040 ns <- sepBy1 name (lchar ',')
1041 return [PDirective (do ty' <- disambiguate ty
1042 mapM_ (addNameHint ty') ns
1043 mapM_ (\n -> addIBC (IBCNameHint (ty', n))) ns)]
1044 <|> do try (lchar '%' *> reserved "error_handlers")
1047 ns <- sepBy1 name (lchar ',')
1048 return [PDirective (do fn' <- disambiguate fn
1049 ns' <- mapM disambiguate ns
1050 addFunctionErrorHandlers fn' arg ns'
1051 mapM_ (addIBC . IBCFunctionErrorHandler fn' arg) ns')]
1052 <|> do try (lchar '%' *> reserved "language"); ext <- pLangExt;
1053 return [PDirective (addLangExt ext)]
1055 where disambiguate :: Name -> Idris Name
1056 disambiguate n = do i <- getIState
1057 case lookupCtxtName n (idris_implicits i) of
1058 [(n', _)] -> return n'
1059 [] -> throwError (NoSuchVariable n)
1060 more -> throwError (CantResolveAlts (map fst more))
1062pLangExt :: IdrisParser LanguageExt
1063pLangExt = (reserved "TypeProviders" >> return TypeProviders)
1064 <|> (reserved "ErrorReflection" >> return ErrorReflection)
1066{- | Parses a totality
1069Totality ::= 'partial' | 'total'
1073totality :: IdrisParser Bool
1075 = do reserved "total"; return True
1076 <|> do reserved "partial"; return False
1078{- | Parses a type provider
1081Provider ::= '%' 'provide' Provider_What? '(' FnName TypeSig ')' 'with' Expr;
1082ProviderWhat ::= 'proof' | 'term' | 'type' | 'postulate'
1085provider :: SyntaxInfo -> IdrisParser [PDecl]
1086provider syn = do try (lchar '%' *> reserved "provide");
1087 provideTerm <|> providePostulate
1089 where provideTerm = do lchar '('; n <- fnName; lchar ':'; t <- typeExpr syn; lchar ')'
1092 e <- expr syn <?> "provider expression"
1093 return [PProvider syn fc (ProvTerm t e) n]
1094 providePostulate = do reserved "postulate"
1098 e <- expr syn <?> "provider expression"
1099 return [PProvider syn fc (ProvPostulate e) n]
1101{- | Parses a transform
1104Transform ::= '%' 'transform' Expr '==>' Expr
1107transform :: SyntaxInfo -> IdrisParser [PDecl]
1108transform syn = do try (lchar '%' *> reserved "transform")
1109 -- leave it unchecked, until we work out what this should
1111-- safety <- option True (do reserved "unsafe"
1117 return [PTransform fc False l r]
1121{- * Loading and parsing -}
1122{- | Parses an expression from input -}
1123parseExpr :: IState -> String -> Result PTerm
1124parseExpr st = runparser (fullExpr defaultSyntax) st "(input)"
1126{- | Parses a constant form input -}
1127parseConst :: IState -> String -> Result Const
1128parseConst st = runparser constant st "(input)"
1130{- | Parses a tactic from input -}
1131parseTactic :: IState -> String -> Result PTactic
1132parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
1134-- | Parse module header and imports
1135parseImports :: FilePath -> String -> Idris ([String], [(String, Maybe String, FC)], Maybe Delta)
1136parseImports fname input
1138 case parseString (runInnerParser (evalStateT imports i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
1139 Failure err -> fail (show err)
1140 Success (x, i) -> do putIState i
1142 where imports :: IdrisParser (([String], [(String, Maybe String, FC)], Maybe Delta), IState)
1143 imports = do whiteSpace
1144 mname <- moduleHeader
1147 isEof <- lookAheadMatches eof
1152 return ((mname, ps, mrk'), i)
1154-- | There should be a better way of doing this...
1155findFC :: Doc -> (FC, String)
1156findFC x = let s = show (plain x) in
1157 case span (/= ':') s of
1158 (failname, ':':rest) -> case span isDigit rest of
1159 (line, ':':rest') -> case span isDigit rest' of
1160 (col, ':':msg) -> let pos = (read line, read col) in
1161 (FC failname pos pos, msg)
1163-- | Check if the coloring matches the options and corrects if necessary
1164fixColour :: Bool -> ANSI.Doc -> ANSI.Doc
1165fixColour False doc = ANSI.plain doc
1166fixColour True doc = doc
1168-- | A program is a list of declarations, possibly with associated
1169-- documentation strings.
1170parseProg :: SyntaxInfo -> FilePath -> String -> Maybe Delta ->
1172parseProg syn fname input mrk
1174 case runparser mainProg i fname input of
1175 Failure doc -> do -- FIXME: Get error location from trifecta
1176 -- this can't be the solution!
1177 -- Issue #1575 on the issue tracker.
1178 -- https://github.com/idris-lang/Idris-dev/issues/1575
1179 let (fc, msg) = findFC doc
1181 case idris_outputmode i of
1182 RawOutput h -> iputStrLn (show $ fixColour (idris_colourRepl i) doc)
1183 IdeSlave n h -> iWarn fc (P.text msg)
1184 putIState (i { errSpan = Just fc })
1186 Success (x, i) -> do putIState i
1187 reportParserWarnings
1189 where mainProg :: IdrisParser ([PDecl], IState)
1190 mainProg = case mrk of
1191 Nothing -> do i <- get; return ([], i)
1198{- | Load idris module and show error if something wrong happens -}
1199loadModule :: FilePath -> Idris String
1201 = idrisCatch (loadModule' f)
1202 (\e -> do setErrSpan (getErrSpan e)
1204 iWarn (getErrSpan e) $ pprintErr ist e
1207{- | Load idris module -}
1208loadModule' :: FilePath -> Idris String
1211 let file = takeWhile (/= ' ') f
1212 ibcsd <- valIBCSubDir i
1213 ids <- allImportDirs
1214 fp <- findImport ids ibcsd file
1215 if file `elem` imported i
1216 then iLOG $ "Already read " ++ file
1217 else do putIState (i { imported = file : imported i })
1219 IDR fn -> loadSource False fn Nothing
1220 LIDR fn -> loadSource True fn Nothing
1222 idrisCatch (loadIBC fn)
1223 (\c -> do iLOG $ fn ++ " failed " ++ pshow i c
1225 IDR sfn -> loadSource False sfn Nothing
1226 LIDR sfn -> loadSource True sfn Nothing)
1227 let (dir, fh) = splitFileName file
1228 return (dropExtension fh)
1231{- | Load idris code from file -}
1232loadFromIFile :: IFileType -> Maybe Int -> Idris ()
1233loadFromIFile i@(IBC fn src) maxline
1234 = do iLOG $ "Skipping " ++ getSrcFile i
1235 idrisCatch (loadIBC fn)
1236 (\err -> ierror $ LoadingFailed fn err)
1238 getSrcFile (IDR fn) = fn
1239 getSrcFile (LIDR fn) = fn
1240 getSrcFile (IBC f src) = getSrcFile src
1242loadFromIFile (IDR fn) maxline = loadSource' False fn maxline
1243loadFromIFile (LIDR fn) maxline = loadSource' True fn maxline
1245{-| Load idris source code and show error if something wrong happens -}
1246loadSource' :: Bool -> FilePath -> Maybe Int -> Idris ()
1247loadSource' lidr r maxline
1248 = idrisCatch (loadSource lidr r maxline)
1249 (\e -> do setErrSpan (getErrSpan e)
1252 At f e' -> iWarn f (pprintErr ist e')
1253 _ -> iWarn (getErrSpan e) (pprintErr ist e))
1255{- | Load Idris source code-}
1256loadSource :: Bool -> FilePath -> Maybe Int -> Idris ()
1257loadSource lidr f toline
1258 = do iLOG ("Reading " ++ f)
1260 let def_total = default_total i
1261 file_in <- runIO $ readFile f
1262 file <- if lidr then tclift $ unlit f file_in else return file_in
1263 (mname, imports_in, pos) <- parseImports f file
1264 ai <- getAutoImports
1265 let imports = map (\n -> (n, Just n, emptyFC)) ai ++ imports_in
1266 ids <- allImportDirs
1267 ibcsd <- valIBCSubDir i
1268 mapM_ (\f -> do fp <- findImport ids ibcsd f
1270 LIDR fn -> ifail $ "No ibc for " ++ f
1271 IDR fn -> ifail $ "No ibc for " ++ f
1272 IBC fn src -> loadIBC fn)
1273 [fn | (fn, _, _) <- imports]
1274 reportParserWarnings
1276 -- process and check module aliases
1277 let modAliases = M.fromList
1278 [(prep alias, prep realName) | (realName, Just alias, fc) <- imports]
1279 prep = map T.pack . reverse . Spl.splitOn "/"
1280 aliasNames = [(alias, fc) | (_, Just alias, fc) <- imports]
1281 histogram = groupBy ((==) `on` fst) . sortBy (comparing fst) $ aliasNames
1282 case map head . filter ((/= 1) . length) $ histogram of
1283 [] -> logLvl 3 $ "Module aliases: " ++ show (M.toList modAliases)
1284 (n,fc):_ -> throwError . At fc . Msg $ "import alias not unique: " ++ show n
1287 putIState (i { default_access = Hidden, module_aliases = modAliases })
1288 clearIBC -- start a new .ibc file
1289 -- record package info in .ibc
1290 imps <- allImportDirs
1291 mapM_ addIBC (map IBCImportDir imps)
1292 mapM_ (addIBC . IBCImport) [realName | (realName, alias, fc) <- imports]
1293 let syntax = defaultSyntax{ syn_namespace = reverse mname,
1295 ds' <- parseProg syntax f file pos
1297 -- Parsing done, now process declarations
1299 let ds = namespaces mname ds'
1300 logLvl 3 (show $ showDecls verbosePPOption ds)
1302 logLvl 10 (show (toAlist (idris_implicits i)))
1303 logLvl 3 (show (idris_infixes i))
1304 -- Now add all the declarations to the context
1306 when v $ iputStrLn $ "Type checking " ++ f
1307 -- we totality check after every Mutual block, so if
1308 -- anything is a single definition, wrap it in a
1309 -- mutual block on its own
1310 elabDecls toplevel (map toMutual ds)
1312 -- simplify every definition do give the totality checker
1314 mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
1315 updateContext (simplifyCasedef n $ getErasureInfo i))
1316 (map snd (idris_totcheck i))
1317 -- build size change graph from simplified definitions
1318 iLOG "Totality checking"
1320 mapM_ buildSCG (idris_totcheck i)
1321 mapM_ checkDeclTotality (idris_totcheck i)
1323 -- Redo totality check for deferred names
1324 let deftots = idris_defertotcheck i
1325 iLOG $ "Totality checking " ++ show deftots
1326 mapM_ (\x -> do tot <- getTotality x
1328 Total _ -> setTotality x Unchecked
1329 _ -> return ()) (map snd deftots)
1330 mapM_ buildSCG deftots
1331 mapM_ checkDeclTotality deftots
1333 iLOG ("Finished " ++ f)
1334 ibcsd <- valIBCSubDir i
1335 iLOG "Universe checking"
1337 let ibc = ibcPathNoFallback ibcsd f
1339 addHides (hide_list i)
1341 -- Finally, write an ibc if checking was successful
1344 idrisCatch (do writeIBC f ibc; clearIBC)
1345 (\c -> return ()) -- failure is harmless
1347 putIState (i { default_total = def_total,
1351 namespaces :: [String] -> [PDecl] -> [PDecl]
1352 namespaces [] ds = ds
1353 namespaces (x:xs) ds = [PNamespace x (namespaces xs ds)]
1355 toMutual :: PDecl -> PDecl
1356 toMutual m@(PMutual _ d) = m
1357 toMutual (PNamespace x ds) = PNamespace x (map toMutual ds)
1358 toMutual x = let r = PMutual (fileFC "single mutual") [x] in
1360 PClauses _ _ _ _ -> r
1361 PClass _ _ _ _ _ _ _ _ -> r
1362 PInstance _ _ _ _ _ _ _ _ -> r
1365{- | Adds names to hide list -}
1366addHides :: [(Name, Maybe Accessibility)] -> Idris ()
1367addHides xs = do i <- getIState
1368 let defh = default_access i
1369 let (hs, as) = partition isNothing xs
1372 (map (\ (n, _) -> (n, defh)) hs ++
1373 map (\ (n, Just a) -> (n, a)) as)
1374 where isNothing (_, Nothing) = True
1377 doHide (n, a) = do setAccessibility n a
1378 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