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.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 (Maybe (Docstring ()), [String])
94moduleHeader = try (do docs <- optional docComment
98 option ';' (lchar ';')
99 return (fmap fst docs, moduleName i))
100 <|> try (do lchar '%'; reserved "unqualified"
101 return (Nothing, []))
102 <|> return (Nothing, moduleName "Main")
103 where moduleName x = case span (/='.') x of
105 (x, '.':y) -> x : moduleName y
106 noArgs (Just (_, args)) | not (null args) = fail "Modules do not take arguments"
109{- | Parses an import statement
112 Import ::= 'import' Identifier_t ';'?;
115import_ :: IdrisParser (Bool, String, Maybe String, FC)
116import_ = do fc <- getFC
118 reexport <- option False (do reserved "public"; return True)
120 newName <- optional (reserved "as" *> identifier)
121 option ';' (lchar ';')
122 return (reexport, toPath id, toPath <$> newName, fc)
123 <?> "import statement"
124 where toPath = foldl1' (</>) . Spl.splitOn "."
126{- | Parses program source
132prog :: SyntaxInfo -> IdrisParser [PDecl]
133prog syn = do whiteSpace
134 decls <- many (decl syn)
135 let c = (concat decls)
137 Nothing -> do notOpenBraces; eof
141 put ist { idris_parsedSpan = Just (FC (fc_fname fc) (0,0) (fc_end fc)),
142 ibc_write = IBCParsedRegion fc : ibc_write ist }
145{-| Parses a top-level declaration
164decl :: SyntaxInfo -> IdrisParser [PDecl]
165decl syn = do fc <- getFC
166 -- if we're after maxline, stop here
167 let continue = case maxline syn of
169 Just l -> if fst (fc_end fc) > l
170 then mut_nesting syn /= 0
172 if continue then do notEndBlock
174 else fail "End of readable input"
175 where declBody :: IdrisParser [PDecl]
183 <|> do d <- dsl syn; return [d]
187 <|> do import_; fail "imports must be at top of file"
189 declBody' :: IdrisParser [PDecl]
190 declBody' = do d <- decl' syn
192 let d' = fmap (debindApp syn . (desugar syn i)) d
195{- | Parses a top-level declaration with possible syntax sugar
207decl' :: SyntaxInfo -> IdrisParser PDecl
215{- | Parses a syntax extension declaration (and adds the rule to parser state)
218 SyntaxDecl ::= SyntaxRule;
221syntaxDecl :: SyntaxInfo -> IdrisParser PDecl
222syntaxDecl syn = do s <- syntaxRule syn
224 put (i `addSyntax` s)
226 return (PSyntax fc s)
228-- | Extend an 'IState' with a new syntax extension. See also 'addReplSyntax'.
229addSyntax :: IState -> Syntax -> IState
230addSyntax i s = i { syntax_rules = updateSyntaxRules [s] rs,
231 syntax_keywords = ks ++ ns,
232 ibc_write = IBCSyntax s : map IBCKeyword ks ++ ibc }
233 where rs = syntax_rules i
234 ns = syntax_keywords i
236 ks = map show (syntaxNames s)
238-- | Like 'addSyntax', but no effect on the IBC.
239addReplSyntax :: IState -> Syntax -> IState
240addReplSyntax i s = i { syntax_rules = updateSyntaxRules [s] rs,
241 syntax_keywords = ks ++ ns }
242 where rs = syntax_rules i
243 ns = syntax_keywords i
244 ks = map show (syntaxNames s)
246{- | Parses a syntax extension declaration
249SyntaxRuleOpts ::= 'term' | 'pattern';
254 SyntaxRuleOpts? 'syntax' SyntaxSym+ '=' TypeExpr Terminator;
258SyntaxSym ::= '[' Name_t ']'
265syntaxRule :: SyntaxInfo -> IdrisParser Syntax
269 sty <- option AnySyntax (do reserved "term"; return TermSyntax
270 <|> do reserved "pattern"; return PatternSyntax)
273 syms <- some syntaxSym
274 when (all isExpr syms) $ unexpected "missing keywords in syntax rule"
275 let ns = mapMaybe getName syms
276 when (length ns /= length (nub ns))
277 $ unexpected "repeated variable in syntax rule"
279 tm <- typeExpr (allowImp syn)
281 return (Rule (mkSimple syms) tm sty)
283 isExpr (Expr _) = True
285 getName (Expr n) = Just n
287 -- Can't parse two full expressions (i.e. expressions with application) in a row
288 -- so change them both to a simple expression
289 mkSimple (Expr e : es) = SimpleExpr e : mkSimple' es
290 mkSimple xs = mkSimple' xs
292 mkSimple' (Expr e : Expr e1 : es) = SimpleExpr e : SimpleExpr e1 :
294 -- Can't parse a full expression followed by operator like characters due to ambiguity
295 mkSimple' (Expr e : Symbol s : es)
296 | takeWhile (`elem` opChars) ts /= "" && ts `notElem` invalidOperators = SimpleExpr e : Symbol s : mkSimple' es
297 where ts = dropWhile isSpace . dropWhileEnd isSpace $ s
298 mkSimple' (e : es) = e : mkSimple' es
302{- | Parses a syntax symbol (either binding variable, keyword or expression)
305SyntaxSym ::= '[' Name_t ']'
312syntaxSym :: IdrisParser SSymbol
313syntaxSym = try (do lchar '['; n <- name; lchar ']'
315 <|> try (do lchar '{'; n <- name; lchar '}'
319 <|> do sym <- stringLiteral
323{- | Parses a function declaration with possible syntax sugar
326 FunDecl ::= FunDecl';
329fnDecl :: SyntaxInfo -> IdrisParser [PDecl]
330fnDecl syn = try (do notEndBlock
333 let d' = fmap (desugar syn i) d
334 return [d']) <?> "function declaration"
336{-| Parses a function declaration
340 DocComment_t? FnOpts* Accessibility? FnOpts* FnName TypeSig Terminator
347fnDecl' :: SyntaxInfo -> IdrisParser PDecl
348fnDecl' syn = checkFixity $
349 do (doc, argDocs, fc, opts', n, acc) <- try (do
351 (doc, argDocs) <- option noDocs docComment
353 let doc' = annotCode (tryFullExpr syn ist) doc
354 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
355 | (n, d) <- argDocs ]
357 initOpts = if default_total ist
360 opts <- fnOpts initOpts
361 acc <- optional accessibility
364 let n = expandNS syn n_in
367 return (doc', argDocs', fc, opts', n, acc))
368 ty <- typeExpr (allowImp syn)
371 return (PTy doc argDocs syn fc opts' n ty)
375 <?> "function declaration"
376 where checkFixity :: IdrisParser PDecl -> IdrisParser PDecl
377 checkFixity p = do decl <- p
379 Nothing -> return decl
380 Just n -> do fOk <- fixityOK n
382 "Missing fixity declaration for " ++ show n
384 getName (PTy _ _ _ _ _ n _) = Just n
386 fixityOK (NS n _) = fixityOK n
387 fixityOK (UN n) | all (flip elem opChars) (str n) =
388 do fixities <- fmap idris_infixes get
389 return . elem (str n) . map (\ (Fix _ op) -> op) $ fixities
390 | otherwise = return True
391 fixityOK _ = return True
393{-| Parses function options given initial options
401 | '%' 'error_handler'
403 | '%' 'specialise' '[' NameTimesList? ']'
408NameTimes ::= FnName Natural?;
414 | NameTimes ',' NameTimesList
418-- FIXME: Check compatability for function options (i.e. partal/total)
420-- Issue #1574 on the issue tracker.
421-- https://github.com/idris-lang/Idris-dev/issues/1574
422fnOpts :: [FnOpt] -> IdrisParser [FnOpt]
424 = do reserved "total"; fnOpts (TotalFn : opts)
425 <|> do reserved "partial"; fnOpts (PartialFn : (opts \\ [TotalFn]))
426 <|> do reserved "covering"; fnOpts (CoveringFn : (opts \\ [TotalFn]))
427 <|> do try (lchar '%' *> reserved "export"); c <- stringLiteral;
428 fnOpts (CExport c : opts)
429 <|> do try (lchar '%' *> reserved "no_implicit");
430 fnOpts (NoImplicit : opts)
431 <|> do try (lchar '%' *> reserved "inline");
432 fnOpts (Inlinable : opts)
433 <|> do try (lchar '%' *> reserved "assert_total");
434 fnOpts (AssertTotal : opts)
435 <|> do try (lchar '%' *> reserved "error_handler");
436 fnOpts (ErrorHandler : opts)
437 <|> do try (lchar '%' *> reserved "error_reverse");
438 fnOpts (ErrorReverse : opts)
439 <|> do try (lchar '%' *> reserved "reflection");
440 fnOpts (Reflection : opts)
441 <|> do lchar '%'; reserved "specialise";
442 lchar '['; ns <- sepBy nameTimes (lchar ','); lchar ']'
443 fnOpts (Specialise ns : opts)
444 <|> do reserved "implicit"; fnOpts (Implicit : opts)
446 <?> "function modifier"
447 where nameTimes :: IdrisParser (Name, Maybe Int)
448 nameTimes = do n <- fnName
449 t <- option Nothing (do reds <- natural
450 return (Just (fromInteger reds)))
453{- | Parses a postulate
457 DocComment_t? 'postulate' FnOpts* Accesibility? FnOpts* FnName TypeSig Terminator
461postulate :: SyntaxInfo -> IdrisParser PDecl
462postulate syn = do doc <- try $ do (doc, _) <- option noDocs docComment
464 let doc' = annotCode (tryFullExpr syn ist) doc
469 let initOpts = if default_total ist
472 opts <- fnOpts initOpts
473 acc <- optional accessibility
476 let n = expandNS syn n_in
478 ty <- typeExpr (allowImp syn)
482 return (PPostulate doc syn fc opts' n ty)
485{- | Parses a using declaration
489 'using' '(' UsingDeclList ')' OpenBlock Decl* CloseBlock
493using_ :: SyntaxInfo -> IdrisParser [PDecl]
495 do reserved "using"; lchar '('; ns <- usingDeclList syn; lchar ')'
497 let uvars = using syn
498 ds <- many (decl (syn { using = uvars ++ ns }))
501 <?> "using declaration"
503{- | Parses a parameters declaration
507 'parameters' '(' TypeDeclList ')' OpenBlock Decl* CloseBlock
511params :: SyntaxInfo -> IdrisParser [PDecl]
513 do reserved "parameters"; lchar '('; ns <- typeDeclList syn; lchar ')'
515 let pvars = syn_params syn
516 ds <- many (decl syn { syn_params = pvars ++ ns })
519 return [PParams fc ns (concat ds)]
520 <?> "parameters declaration"
522{- | Parses a mutual declaration (for mutually recursive functions)
526 'mutual' OpenBlock Decl* CloseBlock
530mutual :: SyntaxInfo -> IdrisParser [PDecl]
534 let pvars = syn_params syn
535 ds <- many (decl (syn { mut_nesting = mut_nesting syn + 1 } ))
538 return [PMutual fc (concat ds)]
541{-| Parses a namespace declaration
545 'namespace' identifier OpenBlock Decl+ CloseBlock
549namespace :: SyntaxInfo -> IdrisParser [PDecl]
551 do reserved "namespace"; n <- identifier;
553 ds <- some (decl syn { syn_namespace = n : syn_namespace syn })
555 return [PNamespace n (concat ds)]
556 <?> "namespace declaration"
558{- | Parses a methods block (for instances)
561 InstanceBlock ::= 'where' OpenBlock FnDecl* CloseBlock
564instanceBlock :: SyntaxInfo -> IdrisParser [PDecl]
565instanceBlock syn = do reserved "where"
567 ds <- many (fnDecl syn)
572{- | Parses a methods and instances block (for type classes)
583 'where' OpenBlock MethodOrInstance* CloseBlock
587classBlock :: SyntaxInfo -> IdrisParser [PDecl]
588classBlock syn = do reserved "where"
590 ds <- many ((notEndBlock >> instance_ syn) <|> fnDecl syn)
595{-| Parses a type class declaration
600 | '(' Name ':' Expr ')'
606 DocComment_t? Accessibility? 'class' ConstraintList? Name ClassArgument* ClassBlock?
610class_ :: SyntaxInfo -> IdrisParser [PDecl]
611class_ syn = do (doc, argDocs, acc) <- try (do
612 (doc, argDocs) <- option noDocs docComment
614 let doc' = annotCode (tryFullExpr syn ist) doc
615 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
616 | (n, d) <- argDocs ]
617 acc <- optional accessibility
618 return (doc', argDocs', acc))
619 reserved "class"; fc <- getFC; cons <- constraintList syn; n_in <- fnName
620 let n = expandNS syn n_in
622 ds <- option [] (classBlock syn)
623 accData acc n (concatMap declared ds)
624 return [PClass doc syn fc cons n cs argDocs ds]
625 <?> "type-class declaration"
627 carg :: IdrisParser (Name, PTerm)
628 carg = do lchar '('; i <- name; lchar ':'; ty <- expr syn; lchar ')'
633{- | Parses a type class instance declaration
637 'instance' InstanceName? ConstraintList? Name SimpleExpr* InstanceBlock?
642InstanceName ::= '[' Name ']';
645instance_ :: SyntaxInfo -> IdrisParser [PDecl]
646instance_ syn = do reserved "instance"; fc <- getFC
647 en <- optional instanceName
648 cs <- constraintList syn
650 args <- many (simpleExpr syn)
651 let sc = PApp fc (PRef fc cn) (map pexp args)
652 let t = bindList (PPi constraint) cs sc
653 ds <- option [] (instanceBlock syn)
654 return [PInstance syn fc cs cn args t en ds]
655 <?> "instance declaration"
656 where instanceName :: IdrisParser Name
657 instanceName = do lchar '['; n_in <- fnName; lchar ']'
658 let n = expandNS syn n_in
663{- | Parses a using declaration list
675 | UsingDecl ',' UsingDeclList'
686usingDeclList :: SyntaxInfo -> IdrisParser [Using]
688 = try (sepBy1 (usingDecl syn) (lchar ','))
689 <|> do ns <- sepBy1 name (lchar ',')
691 t <- typeExpr (disallowImp syn)
692 return (map (\x -> UImplicit x t) ns)
693 <?> "using declaration list"
695{- |Parses a using declaration
704usingDecl :: SyntaxInfo -> IdrisParser Using
705usingDecl syn = try (do x <- fnName
707 t <- typeExpr (disallowImp syn)
708 return (UImplicit x t))
711 return (UConstraint c xs)
712 <?> "using declaration"
714{- | Parse a clause with patterns
720pattern :: SyntaxInfo -> IdrisParser PDecl
721pattern syn = do fc <- getFC
723 return (PClauses fc [] (sMN 2 "_") [clause]) -- collect together later
726{- | Parse a constant applicative form declaration
729CAF ::= 'let' FnName '=' Expr Terminator;
732caf :: SyntaxInfo -> IdrisParser PDecl
733caf syn = do reserved "let"
734 n_in <- fnName; let n = expandNS syn n_in
740 <?> "constant applicative form declaration"
742{- | Parse an argument expression
745ArgExpr ::= HSimpleExpr | {- In Pattern External (User-defined) Expression -};
748argExpr :: SyntaxInfo -> IdrisParser PTerm
749argExpr syn = let syn' = syn { inPattern = True } in
750 try (hsimpleExpr syn') <|> simpleExternalExpr syn'
751 <?> "argument expression"
753{- | Parse a right hand side of a function
763RHSName ::= '{' FnName '}';
766rhs :: SyntaxInfo -> Name -> IdrisParser PTerm
767rhs syn n = do lchar '='; expr syn
770 name <- option n' (do symbol "{"; n <- fnName; symbol "}";
773 return (addLet fc name r)
774 <|> do reserved "impossible"; return PImpossible
775 <?> "function right hand side"
776 where mkN :: Name -> Name
777 mkN (UN x) = if (tnull x || not (isAlpha (thead x)))
778 then sUN "infix_op_lemma_1"
779 else sUN (str x++"_lemma_1")
780 mkN (NS x n) = NS (mkN x) n
783 addLet :: FC -> Name -> PTerm -> PTerm
784 addLet fc nm (PLet fc' n ty val r) = PLet fc' n ty val (addLet fc nm r)
785 addLet fc nm (PCase fc' t cs) = PCase fc' t (map addLetC cs)
786 where addLetC (l, r) = (l, addLet fc nm r)
787 addLet fc nm r = (PLet fc (sUN "value") Placeholder r (PMetavar nm))
789{- |Parses a function clause
792RHSOrWithBlock ::= RHS WhereOrTerminator
793 | 'with' SimpleExpr OpenBlock FnDecl+ CloseBlock
798Clause ::= WExpr+ RHSOrWithBlock
799 | SimpleExpr '<==' FnName RHS WhereOrTerminator
800 | ArgExpr Operator ArgExpr WExpr* RHSOrWithBlock {- Except "=" and "?=" operators to avoid ambiguity -}
801 | FnName ConstraintArg* ImplicitOrArgExpr* WExpr* RHSOrWithBlock
806ImplicitOrArgExpr ::= ImplicitArg | ArgExpr;
810WhereOrTerminator ::= WhereBlock | Terminator;
813clause :: SyntaxInfo -> IdrisParser PClause
815 = do wargs <- try (do pushIndent; some (wExpr syn))
818 n <- case lastParse ist of
820 Nothing -> fail "Invalid clause"
822 let ctxt = tt_ctxt ist
823 let wsyn = syn { syn_namespace = [] }
824 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
829 return $ PClauseR fc wargs r wheres) <|> (do
832 wval <- simpleExpr syn
835 ds <- some $ fnDecl syn
836 let withs = concat ds
838 return $ PWithR fc wargs wval pn withs)
839 <|> do ty <- try (do pushIndent
844 n_in <- fnName; let n = expandNS syn n_in
847 let ctxt = tt_ctxt ist
848 let wsyn = syn { syn_namespace = [] }
849 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
854 let capp = PLet fc (sMN 0 "match")
857 (PRef fc (sMN 0 "match"))
859 put (ist { lastParse = Just n })
860 return $ PClause fc n capp [] r wheres
861 <|> do (l, op) <- try (do
865 when (op == "=" || op == "?=" ) $
866 fail "infix clause definition with \"=\" and \"?=\" not supported "
868 let n = expandNS syn (sUN op)
871 wargs <- many (wExpr syn)
873 let wsyn = syn { syn_namespace = [] }
874 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
880 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
881 put (ist { lastParse = Just n })
882 return $ PClause fc n capp wargs rs wheres) <|> (do
885 wval <- bracketed syn
888 ds <- some $ fnDecl syn
891 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
892 let withs = map (fillLHSD n capp wargs) $ concat ds
893 put (ist { lastParse = Just n })
894 return $ PWith fc n capp wargs wval pn withs)
896 n_in <- fnName; let n = expandNS syn n_in
897 cargs <- many (constraintArg syn)
899 args <- many (try (implicitArg (syn { inPattern = True } ))
900 <|> (fmap pexp (argExpr syn)))
901 wargs <- many (wExpr syn)
902 let capp = PApp fc (PRef fc n)
906 let ctxt = tt_ctxt ist
907 let wsyn = syn { syn_namespace = [] }
908 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
914 put (ist { lastParse = Just n })
915 return $ PClause fc n capp wargs r wheres) <|> (do
918 put (ist { lastParse = Just n })
919 wval <- bracketed syn
922 ds <- some $ fnDecl syn
923 let withs = map (fillLHSD n capp wargs) $ concat ds
926 return $ PWith fc n capp wargs wval pn withs)
927 <?> "function clause"
929 optProof = option Nothing (do reserved "proof"
933 fillLHS :: Name -> PTerm -> [PTerm] -> PClause -> PClause
934 fillLHS n capp owargs (PClauseR fc wargs v ws)
935 = PClause fc n capp (owargs ++ wargs) v ws
936 fillLHS n capp owargs (PWithR fc wargs v pn ws)
937 = PWith fc n capp (owargs ++ wargs) v pn
938 (map (fillLHSD n capp (owargs ++ wargs)) ws)
941 fillLHSD :: Name -> PTerm -> [PTerm] -> PDecl -> PDecl
942 fillLHSD n c a (PClauses fc o fn cs) = PClauses fc o fn (map (fillLHS n c a) cs)
945{-| Parses with pattern
951wExpr :: SyntaxInfo -> IdrisParser PTerm
952wExpr syn = do lchar '|'
953 expr' (syn { inPattern = True })
956{- | Parses a where block
959WhereBlock ::= 'where' OpenBlock Decl+ CloseBlock;
962whereBlock :: Name -> SyntaxInfo -> IdrisParser ([PDecl], [(Name, Name)])
964 = do reserved "where"
965 ds <- indentedBlock1 (decl syn)
966 let dns = concatMap (concatMap declared) ds
967 return (concat ds, map (\x -> (x, decoration syn x)) dns)
970{- |Parses a code generation target language name
982codegen_ :: IdrisParser Codegen
983codegen_ = do n <- identifier; return (Via (map toLower n))
984 <|> do reserved "Bytecode"; return Bytecode
985 <?> "code generation language"
987{- |Parses a compiler directive
991 | String ',' StringList
996Directive ::= '%' Directive';
1000Directive' ::= 'lib' CodeGen String_t
1001 | 'link' CodeGen String_t
1002 | 'flag' CodeGen String_t
1003 | 'include' CodeGen String_t
1006 | 'access' Accessibility
1007 | 'default' Totality
1009 | 'dynamic' StringList
1010 | 'name' Name NameList
1011 | 'error_handlers' Name NameList
1012 | 'language' 'TypeProviders'
1013 | 'language' 'ErrorReflection'
1017directive :: SyntaxInfo -> IdrisParser [PDecl]
1018directive syn = do try (lchar '%' *> reserved "lib"); cgn <- codegen_; lib <- stringLiteral;
1019 return [PDirective (do addLib cgn lib
1020 addIBC (IBCLib cgn lib))]
1021 <|> do try (lchar '%' *> reserved "link"); cgn <- codegen_; obj <- stringLiteral;
1022 return [PDirective (do dirs <- allImportDirs
1023 o <- liftIO $ findInPath dirs obj
1024 addIBC (IBCObj cgn obj) -- just name, search on loading ibc
1025 addObjectFile cgn o)]
1026 <|> do try (lchar '%' *> reserved "flag"); cgn <- codegen_;
1027 flag <- stringLiteral
1028 return [PDirective (do addIBC (IBCCGFlag cgn flag)
1030 <|> do try (lchar '%' *> reserved "include"); cgn <- codegen_; hdr <- stringLiteral;
1031 return [PDirective (do addHdr cgn hdr
1032 addIBC (IBCHeader cgn hdr))]
1033 <|> do try (lchar '%' *> reserved "hide"); n <- fnName
1034 return [PDirective (do setAccessibility n Hidden
1035 addIBC (IBCAccess n Hidden))]
1036 <|> do try (lchar '%' *> reserved "freeze"); n <- iName []
1037 return [PDirective (do setAccessibility n Frozen
1038 addIBC (IBCAccess n Frozen))]
1039 <|> do try (lchar '%' *> reserved "access"); acc <- accessibility
1040 return [PDirective (do i <- get
1041 put(i { default_access = acc }))]
1042 <|> do try (lchar '%' *> reserved "default"); tot <- totality
1044 put (i { default_total = tot } )
1045 return [PDirective (do i <- get
1046 put(i { default_total = tot }))]
1047 <|> do try (lchar '%' *> reserved "logging"); i <- natural;
1048 return [PDirective (setLogLevel (fromInteger i))]
1049 <|> do try (lchar '%' *> reserved "dynamic"); libs <- sepBy1 stringLiteral (lchar ',');
1050 return [PDirective (do added <- addDyLib libs
1052 Left lib -> addIBC (IBCDyLib (lib_name lib))
1055 <|> do try (lchar '%' *> reserved "name")
1057 ns <- sepBy1 name (lchar ',')
1058 return [PDirective (do ty' <- disambiguate ty
1059 mapM_ (addNameHint ty') ns
1060 mapM_ (\n -> addIBC (IBCNameHint (ty', n))) ns)]
1061 <|> do try (lchar '%' *> reserved "error_handlers")
1064 ns <- sepBy1 name (lchar ',')
1065 return [PDirective (do fn' <- disambiguate fn
1066 ns' <- mapM disambiguate ns
1067 addFunctionErrorHandlers fn' arg ns'
1068 mapM_ (addIBC . IBCFunctionErrorHandler fn' arg) ns')]
1069 <|> do try (lchar '%' *> reserved "language"); ext <- pLangExt;
1070 return [PDirective (addLangExt ext)]
1072 try (lchar '%' *> reserved "used")
1075 return [PDirective (addUsedName fc fn arg)]
1078 where disambiguate :: Name -> Idris Name
1079 disambiguate n = do i <- getIState
1080 case lookupCtxtName n (idris_implicits i) of
1081 [(n', _)] -> return n'
1082 [] -> throwError (NoSuchVariable n)
1083 more -> throwError (CantResolveAlts (map fst more))
1085pLangExt :: IdrisParser LanguageExt
1086pLangExt = (reserved "TypeProviders" >> return TypeProviders)
1087 <|> (reserved "ErrorReflection" >> return ErrorReflection)
1089{- | Parses a totality
1092Totality ::= 'partial' | 'total'
1096totality :: IdrisParser Bool
1098 = do reserved "total"; return True
1099 <|> do reserved "partial"; return False
1101{- | Parses a type provider
1104Provider ::= '%' 'provide' Provider_What? '(' FnName TypeSig ')' 'with' Expr;
1105ProviderWhat ::= 'proof' | 'term' | 'type' | 'postulate'
1108provider :: SyntaxInfo -> IdrisParser [PDecl]
1109provider syn = do try (lchar '%' *> reserved "provide");
1110 provideTerm <|> providePostulate
1112 where provideTerm = do lchar '('; n <- fnName; lchar ':'; t <- typeExpr syn; lchar ')'
1115 e <- expr syn <?> "provider expression"
1116 return [PProvider syn fc (ProvTerm t e) n]
1117 providePostulate = do reserved "postulate"
1121 e <- expr syn <?> "provider expression"
1122 return [PProvider syn fc (ProvPostulate e) n]
1124{- | Parses a transform
1127Transform ::= '%' 'transform' Expr '==>' Expr
1130transform :: SyntaxInfo -> IdrisParser [PDecl]
1131transform syn = do try (lchar '%' *> reserved "transform")
1132 -- leave it unchecked, until we work out what this should
1134-- safety <- option True (do reserved "unsafe"
1140 return [PTransform fc False l r]
1144{- * Loading and parsing -}
1145{- | Parses an expression from input -}
1146parseExpr :: IState -> String -> Result PTerm
1147parseExpr st = runparser (fullExpr defaultSyntax) st "(input)"
1149{- | Parses a constant form input -}
1150parseConst :: IState -> String -> Result Const
1151parseConst st = runparser constant st "(input)"
1153{- | Parses a tactic from input -}
1154parseTactic :: IState -> String -> Result PTactic
1155parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
1157-- | Parse module header and imports
1158parseImports :: FilePath -> String -> Idris (Maybe (Docstring ()), [String], [(Bool, String, Maybe String, FC)], Maybe Delta)
1159parseImports fname input
1161 case parseString (runInnerParser (evalStateT imports i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
1162 Failure err -> fail (show err)
1163 Success (x, i) -> do putIState i
1165 where imports :: IdrisParser ((Maybe (Docstring ()), [String], [(Bool, String, Maybe String, FC)], Maybe Delta), IState)
1166 imports = do whiteSpace
1167 (mdoc, mname) <- moduleHeader
1170 isEof <- lookAheadMatches eof
1175 return ((mdoc, mname, ps, mrk'), i)
1177-- | There should be a better way of doing this...
1178findFC :: Doc -> (FC, String)
1179findFC x = let s = show (plain x) in
1180 case span (/= ':') s of
1181 (failname, ':':rest) -> case span isDigit rest of
1182 (line, ':':rest') -> case span isDigit rest' of
1183 (col, ':':msg) -> let pos = (read line, read col) in
1184 (FC failname pos pos, msg)
1186-- | Check if the coloring matches the options and corrects if necessary
1187fixColour :: Bool -> ANSI.Doc -> ANSI.Doc
1188fixColour False doc = ANSI.plain doc
1189fixColour True doc = doc
1191-- | A program is a list of declarations, possibly with associated
1192-- documentation strings.
1193parseProg :: SyntaxInfo -> FilePath -> String -> Maybe Delta ->
1195parseProg syn fname input mrk
1197 case runparser mainProg i fname input of
1198 Failure doc -> do -- FIXME: Get error location from trifecta
1199 -- this can't be the solution!
1200 -- Issue #1575 on the issue tracker.
1201 -- https://github.com/idris-lang/Idris-dev/issues/1575
1202 let (fc, msg) = findFC doc
1204 case idris_outputmode i of
1205 RawOutput h -> iputStrLn (show $ fixColour (idris_colourRepl i) doc)
1206 IdeMode n h -> iWarn fc (P.text msg)
1207 putIState (i { errSpan = Just fc })
1209 Success (x, i) -> do putIState i
1210 reportParserWarnings
1212 where mainProg :: IdrisParser ([PDecl], IState)
1213 mainProg = case mrk of
1214 Nothing -> do i <- get; return ([], i)
1221{- | Load idris module and show error if something wrong happens -}
1222loadModule :: FilePath -> Idris (Maybe String)
1224 = idrisCatch (loadModule' f)
1225 (\e -> do setErrSpan (getErrSpan e)
1227 iWarn (getErrSpan e) $ pprintErr ist e
1230{- | Load idris module -}
1231loadModule' :: FilePath -> Idris (Maybe String)
1234 let file = takeWhile (/= ' ') f
1235 ibcsd <- valIBCSubDir i
1236 ids <- allImportDirs
1237 fp <- findImport ids ibcsd file
1238 if file `elem` imported i
1239 then do iLOG $ "Already read " ++ file
1241 else do putIState (i { imported = file : imported i })
1243 IDR fn -> loadSource False fn Nothing
1244 LIDR fn -> loadSource True fn Nothing
1246 idrisCatch (loadIBC True fn)
1247 (\c -> do iLOG $ fn ++ " failed " ++ pshow i c
1249 IDR sfn -> loadSource False sfn Nothing
1250 LIDR sfn -> loadSource True sfn Nothing)
1253{- | Load idris code from file -}
1254loadFromIFile :: Bool -> IFileType -> Maybe Int -> Idris ()
1255loadFromIFile reexp i@(IBC fn src) maxline
1256 = do iLOG $ "Skipping " ++ getSrcFile i
1257 idrisCatch (loadIBC reexp fn)
1258 (\err -> ierror $ LoadingFailed fn err)
1260 getSrcFile (IDR fn) = fn
1261 getSrcFile (LIDR fn) = fn
1262 getSrcFile (IBC f src) = getSrcFile src
1264loadFromIFile _ (IDR fn) maxline = loadSource' False fn maxline
1265loadFromIFile _ (LIDR fn) maxline = loadSource' True fn maxline
1267{-| Load idris source code and show error if something wrong happens -}
1268loadSource' :: Bool -> FilePath -> Maybe Int -> Idris ()
1269loadSource' lidr r maxline
1270 = idrisCatch (loadSource lidr r maxline)
1271 (\e -> do setErrSpan (getErrSpan e)
1274 At f e' -> iWarn f (pprintErr ist e')
1275 _ -> iWarn (getErrSpan e) (pprintErr ist e))
1277{- | Load Idris source code-}
1278loadSource :: Bool -> FilePath -> Maybe Int -> Idris ()
1279loadSource lidr f toline
1280 = do iLOG ("Reading " ++ f)
1282 let def_total = default_total i
1283 file_in <- runIO $ readFile f
1284 file <- if lidr then tclift $ unlit f file_in else return file_in
1285 (mdocs, mname, imports_in, pos) <- parseImports f file
1286 ai <- getAutoImports
1287 let imports = map (\n -> (True, n, Just n, emptyFC)) ai ++ imports_in
1288 ids <- allImportDirs
1289 ibcsd <- valIBCSubDir i
1291 do fp <- findImport ids ibcsd f
1293 LIDR fn -> ifail $ "No ibc for " ++ f
1294 IDR fn -> ifail $ "No ibc for " ++ f
1295 IBC fn src -> loadIBC True fn)
1296 [(re, fn) | (re, fn, _, _) <- imports]
1297 reportParserWarnings
1299 -- process and check module aliases
1300 let modAliases = M.fromList
1301 [(prep alias, prep realName) | (reexport, realName, Just alias, fc) <- imports]
1302 prep = map T.pack . reverse . Spl.splitOn "/"
1303 aliasNames = [(alias, fc) | (_, _, Just alias, fc) <- imports]
1304 histogram = groupBy ((==) `on` fst) . sortBy (comparing fst) $ aliasNames
1305 case map head . filter ((/= 1) . length) $ histogram of
1306 [] -> logLvl 3 $ "Module aliases: " ++ show (M.toList modAliases)
1307 (n,fc):_ -> throwError . At fc . Msg $ "import alias not unique: " ++ show n
1310 putIState (i { default_access = Hidden, module_aliases = modAliases })
1311 clearIBC -- start a new .ibc file
1312 -- record package info in .ibc
1313 imps <- allImportDirs
1314 mapM_ addIBC (map IBCImportDir imps)
1315 mapM_ (addIBC . IBCImport) [(reexport, realName) | (reexport, realName, alias, fc) <- imports]
1316 let syntax = defaultSyntax{ syn_namespace = reverse mname,
1319 -- Save the span from parsing the module header, because
1320 -- an empty program parse might obliterate it.
1321 let oldSpan = idris_parsedSpan ist
1322 ds' <- parseProg syntax f file pos
1324 case (ds', oldSpan) of
1326 -- If no program elements were parsed, we dind't
1327 -- get a loaded region in the IBC file. That
1328 -- means we need to add it back.
1330 putIState ist { idris_parsedSpan = oldSpan
1331 , ibc_write = IBCParsedRegion fc :
1336 -- Parsing done, now process declarations
1338 let ds = namespaces mname ds'
1339 logLvl 3 (show $ showDecls verbosePPOption ds)
1341 logLvl 10 (show (toAlist (idris_implicits i)))
1342 logLvl 3 (show (idris_infixes i))
1343 -- Now add all the declarations to the context
1345 when v $ iputStrLn $ "Type checking " ++ f
1346 -- we totality check after every Mutual block, so if
1347 -- anything is a single definition, wrap it in a
1348 -- mutual block on its own
1349 elabDecls toplevel (map toMutual ds)
1351 -- simplify every definition do give the totality checker
1353 mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
1354 updateContext (simplifyCasedef n $ getErasureInfo i))
1355 (map snd (idris_totcheck i))
1356 -- build size change graph from simplified definitions
1357 iLOG "Totality checking"
1359 mapM_ buildSCG (idris_totcheck i)
1360 mapM_ checkDeclTotality (idris_totcheck i)
1362 -- Redo totality check for deferred names
1363 let deftots = idris_defertotcheck i
1364 iLOG $ "Totality checking " ++ show deftots
1365 mapM_ (\x -> do tot <- getTotality x
1367 Total _ -> setTotality x Unchecked
1368 _ -> return ()) (map snd deftots)
1369 mapM_ buildSCG deftots
1370 mapM_ checkDeclTotality deftots
1372 iLOG ("Finished " ++ f)
1373 ibcsd <- valIBCSubDir i
1374 iLOG "Universe checking"
1376 let ibc = ibcPathNoFallback ibcsd f
1378 addHides (hide_list i)
1380 -- Save module documentation if applicable
1383 Nothing -> return ()
1384 Just docs -> addModDoc syntax mname docs
1387 -- Finally, write an ibc if checking was successful
1390 idrisCatch (do writeIBC f ibc; clearIBC)
1391 (\c -> return ()) -- failure is harmless
1393 putIState (i { default_total = def_total,
1397 namespaces :: [String] -> [PDecl] -> [PDecl]
1398 namespaces [] ds = ds
1399 namespaces (x:xs) ds = [PNamespace x (namespaces xs ds)]
1401 toMutual :: PDecl -> PDecl
1402 toMutual m@(PMutual _ d) = m
1403 toMutual (PNamespace x ds) = PNamespace x (map toMutual ds)
1404 toMutual x = let r = PMutual (fileFC "single mutual") [x] in
1406 PClauses _ _ _ _ -> r
1407 PClass _ _ _ _ _ _ _ _ -> r
1408 PInstance _ _ _ _ _ _ _ _ -> r
1411 addModDoc :: SyntaxInfo -> [String] -> Docstring () -> Idris ()
1412 addModDoc syn mname docs =
1414 docs' <- elabDocTerms recinfo (parsedDocs ist)
1415 let modDocs' = addDef docName docs' (idris_moduledocs ist)
1416 putIState ist { idris_moduledocs = modDocs' }
1417 addIBC (IBCModDocs docName)
1419 docName = NS modDocName (map T.pack (reverse mname))
1420 parsedDocs ist = annotCode (tryFullExpr syn ist) docs
1422{- | Adds names to hide list -}
1423addHides :: [(Name, Maybe Accessibility)] -> Idris ()
1424addHides xs = do i <- getIState
1425 let defh = default_access i
1426 let (hs, as) = partition isNothing xs
1429 (map (\ (n, _) -> (n, defh)) hs ++
1430 map (\ (n, Just a) -> (n, a)) as)
1431 where isNothing (_, Nothing) = True
1434 doHide (n, a) = do setAccessibility n a
1435 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