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, Err)
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 Data.Generics.Uniplate.Data (descendM)
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 ::= DocComment_t? '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) >>= uniquifyBinders [n | Binding n <- syms]
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 -- Can't parse a full expression followed by operator like characters due to ambiguity
296 mkSimple' (Expr e : Symbol s : es)
297 | takeWhile (`elem` opChars) ts /= "" && ts `notElem` invalidOperators = SimpleExpr e : Symbol s : mkSimple' es
298 where ts = dropWhile isSpace . dropWhileEnd isSpace $ s
299 mkSimple' (e : es) = e : mkSimple' es
302 -- Prevent syntax variable capture by making all binders under syntax unique
303 -- (the ol' Common Lisp GENSYM approach)
304 uniquifyBinders :: [Name] -> PTerm -> IdrisParser PTerm
305 uniquifyBinders userNames = fixBind []
307 fixBind :: [(Name, Name)] -> PTerm -> IdrisParser PTerm
308 fixBind rens (PRef fc n) | Just n' <- lookup n rens =
310 fixBind rens (PPatvar fc n) | Just n' <- lookup n rens =
311 return $ PPatvar fc n'
312 fixBind rens (PLam fc n ty body)
313 | n `elem` userNames = liftM2 (PLam fc n) (fixBind rens ty) (fixBind rens body)
315 do ty' <- fixBind rens ty
317 body' <- fixBind ((n,n'):rens) body
318 return $ PLam fc n' ty' body'
319 fixBind rens (PPi plic n argTy body)
320 | n `elem` userNames = liftM2 (PPi plic n) (fixBind rens argTy) (fixBind rens body)
322 do ty' <- fixBind rens argTy
324 body' <- fixBind ((n,n'):rens) body
325 return $ (PPi plic n' ty' body')
326 fixBind rens (PLet fc n ty val body)
327 | n `elem` userNames = liftM3 (PLet fc n)
332 do ty' <- fixBind rens ty
333 val' <- fixBind rens val
335 body' <- fixBind ((n,n'):rens) body
336 return $ (PLet fc n' ty' val' body')
337 fixBind rens (PMatchApp fc n) | Just n' <- lookup n rens =
338 return $ PMatchApp fc n'
339 fixBind rens x = descendM (fixBind rens) x
341 gensym :: Name -> IdrisParser Name
342 gensym n = do ist <- get
343 let idx = idris_name ist
344 put ist { idris_name = idx + 1 }
345 return $ sMN idx (show n)
347{- | Parses a syntax symbol (either binding variable, keyword or expression)
350SyntaxSym ::= '[' Name_t ']'
357syntaxSym :: IdrisParser SSymbol
358syntaxSym = try (do lchar '['; n <- name; lchar ']'
360 <|> try (do lchar '{'; n <- name; lchar '}'
364 <|> do sym <- stringLiteral
368{- | Parses a function declaration with possible syntax sugar
371 FunDecl ::= FunDecl';
374fnDecl :: SyntaxInfo -> IdrisParser [PDecl]
375fnDecl syn = try (do notEndBlock
378 let d' = fmap (desugar syn i) d
379 return [d']) <?> "function declaration"
381{-| Parses a function declaration
385 DocComment_t? FnOpts* Accessibility? FnOpts* FnName TypeSig Terminator
392fnDecl' :: SyntaxInfo -> IdrisParser PDecl
393fnDecl' syn = checkFixity $
394 do (doc, argDocs, fc, opts', n, acc) <- try (do
396 (doc, argDocs) <- docstring syn
398 let initOpts = if default_total ist
401 opts <- fnOpts initOpts
402 acc <- optional accessibility
405 let n = expandNS syn n_in
408 return (doc, argDocs, fc, opts', n, acc))
409 ty <- typeExpr (allowImp syn)
412 return (PTy doc argDocs syn fc opts' n ty)
416 <?> "function declaration"
417 where checkFixity :: IdrisParser PDecl -> IdrisParser PDecl
418 checkFixity p = do decl <- p
420 Nothing -> return decl
421 Just n -> do fOk <- fixityOK n
423 "Missing fixity declaration for " ++ show n
425 getName (PTy _ _ _ _ _ n _) = Just n
427 fixityOK (NS n _) = fixityOK n
428 fixityOK (UN n) | all (flip elem opChars) (str n) =
429 do fixities <- fmap idris_infixes get
430 return . elem (str n) . map (\ (Fix _ op) -> op) $ fixities
431 | otherwise = return True
432 fixityOK _ = return True
434{-| Parses function options given initial options
442 | '%' 'error_handler'
444 | '%' 'specialise' '[' NameTimesList? ']'
449NameTimes ::= FnName Natural?;
455 | NameTimes ',' NameTimesList
459-- FIXME: Check compatability for function options (i.e. partal/total)
461-- Issue #1574 on the issue tracker.
462-- https://github.com/idris-lang/Idris-dev/issues/1574
463fnOpts :: [FnOpt] -> IdrisParser [FnOpt]
465 = do reserved "total"; fnOpts (TotalFn : opts)
466 <|> do reserved "partial"; fnOpts (PartialFn : (opts \\ [TotalFn]))
467 <|> do reserved "covering"; fnOpts (CoveringFn : (opts \\ [TotalFn]))
468 <|> do try (lchar '%' *> reserved "export"); c <- stringLiteral;
469 fnOpts (CExport c : opts)
470 <|> do try (lchar '%' *> reserved "no_implicit");
471 fnOpts (NoImplicit : opts)
472 <|> do try (lchar '%' *> reserved "inline");
473 fnOpts (Inlinable : opts)
474 <|> do try (lchar '%' *> reserved "assert_total");
475 fnOpts (AssertTotal : opts)
476 <|> do try (lchar '%' *> reserved "error_handler");
477 fnOpts (ErrorHandler : opts)
478 <|> do try (lchar '%' *> reserved "error_reverse");
479 fnOpts (ErrorReverse : opts)
480 <|> do try (lchar '%' *> reserved "reflection");
481 fnOpts (Reflection : opts)
482 <|> do lchar '%'; reserved "specialise";
483 lchar '['; ns <- sepBy nameTimes (lchar ','); lchar ']'
484 fnOpts (Specialise ns : opts)
485 <|> do reserved "implicit"; fnOpts (Implicit : opts)
487 <?> "function modifier"
488 where nameTimes :: IdrisParser (Name, Maybe Int)
489 nameTimes = do n <- fnName
490 t <- option Nothing (do reds <- natural
491 return (Just (fromInteger reds)))
494{- | Parses a postulate
498 DocComment_t? 'postulate' FnOpts* Accesibility? FnOpts* FnName TypeSig Terminator
502postulate :: SyntaxInfo -> IdrisParser PDecl
503postulate syn = do doc <- try $ do (doc, _) <- docstring syn
508 let initOpts = if default_total ist
511 opts <- fnOpts initOpts
512 acc <- optional accessibility
515 let n = expandNS syn n_in
517 ty <- typeExpr (allowImp syn)
521 return (PPostulate doc syn fc opts' n ty)
524{- | Parses a using declaration
528 'using' '(' UsingDeclList ')' OpenBlock Decl* CloseBlock
532using_ :: SyntaxInfo -> IdrisParser [PDecl]
534 do reserved "using"; lchar '('; ns <- usingDeclList syn; lchar ')'
536 let uvars = using syn
537 ds <- many (decl (syn { using = uvars ++ ns }))
540 <?> "using declaration"
542{- | Parses a parameters declaration
546 'parameters' '(' TypeDeclList ')' OpenBlock Decl* CloseBlock
550params :: SyntaxInfo -> IdrisParser [PDecl]
552 do reserved "parameters"; lchar '('; ns <- typeDeclList syn; lchar ')'
554 let pvars = syn_params syn
555 ds <- many (decl syn { syn_params = pvars ++ ns })
558 return [PParams fc ns (concat ds)]
559 <?> "parameters declaration"
561{- | Parses a mutual declaration (for mutually recursive functions)
565 'mutual' OpenBlock Decl* CloseBlock
569mutual :: SyntaxInfo -> IdrisParser [PDecl]
573 let pvars = syn_params syn
574 ds <- many (decl (syn { mut_nesting = mut_nesting syn + 1 } ))
577 return [PMutual fc (concat ds)]
580{-| Parses a namespace declaration
584 'namespace' identifier OpenBlock Decl+ CloseBlock
588namespace :: SyntaxInfo -> IdrisParser [PDecl]
590 do reserved "namespace"; n <- identifier;
592 ds <- some (decl syn { syn_namespace = n : syn_namespace syn })
594 return [PNamespace n (concat ds)]
595 <?> "namespace declaration"
597{- | Parses a methods block (for instances)
600 InstanceBlock ::= 'where' OpenBlock FnDecl* CloseBlock
603instanceBlock :: SyntaxInfo -> IdrisParser [PDecl]
604instanceBlock syn = do reserved "where"
606 ds <- many (fnDecl syn)
611{- | Parses a methods and instances block (for type classes)
622 'where' OpenBlock MethodOrInstance* CloseBlock
626classBlock :: SyntaxInfo -> IdrisParser [PDecl]
627classBlock syn = do reserved "where"
629 ds <- many (notEndBlock >> instance_ syn <|> fnDecl syn)
634{-| Parses a type class declaration
639 | '(' Name ':' Expr ')'
645 DocComment_t? Accessibility? 'class' ConstraintList? Name ClassArgument* ClassBlock?
649class_ :: SyntaxInfo -> IdrisParser [PDecl]
650class_ syn = do (doc, argDocs, acc)
651 <- try (do (doc, argDocs) <- docstring syn
652 acc <- optional accessibility
654 return (doc, argDocs, acc))
656 cons <- constraintList syn
658 let n = expandNS syn n_in
660 fds <- option (map fst cs) fundeps
661 ds <- option [] (classBlock syn)
662 accData acc n (concatMap declared ds)
663 return [PClass doc syn fc cons n cs argDocs fds ds]
664 <?> "type-class declaration"
666 fundeps :: IdrisParser [Name]
667 fundeps = do lchar '|'; sepBy name (lchar ',')
669 carg :: IdrisParser (Name, PTerm)
670 carg = do lchar '('; i <- name; lchar ':'; ty <- expr syn; lchar ')'
675{- | Parses a type class instance declaration
679 DocComment_t? 'instance' InstanceName? ConstraintList? Name SimpleExpr* InstanceBlock?
684InstanceName ::= '[' Name ']';
687instance_ :: SyntaxInfo -> IdrisParser [PDecl]
688instance_ syn = do (doc, argDocs)
689 <- try (docstring syn <* reserved "instance")
691 en <- optional instanceName
692 cs <- constraintList syn
694 args <- many (simpleExpr syn)
695 let sc = PApp fc (PRef fc cn) (map pexp args)
696 let t = bindList (PPi constraint) cs sc
697 ds <- option [] (instanceBlock syn)
698 return [PInstance doc argDocs syn fc cs cn args t en ds]
699 <?> "instance declaration"
700 where instanceName :: IdrisParser Name
701 instanceName = do lchar '['; n_in <- fnName; lchar ']'
702 let n = expandNS syn n_in
707-- | Parse a docstring
708docstring :: SyntaxInfo
709 -> IdrisParser (Docstring (Either Err PTerm),
710 [(Name,Docstring (Either Err PTerm))])
711docstring syn = do (doc, argDocs) <- option noDocs docComment
713 let doc' = annotCode (tryFullExpr syn ist) doc
714 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
715 | (n, d) <- argDocs ]
716 return (doc', argDocs')
719{- | Parses a using declaration list
731 | UsingDecl ',' UsingDeclList'
742usingDeclList :: SyntaxInfo -> IdrisParser [Using]
744 = try (sepBy1 (usingDecl syn) (lchar ','))
745 <|> do ns <- sepBy1 name (lchar ',')
747 t <- typeExpr (disallowImp syn)
748 return (map (\x -> UImplicit x t) ns)
749 <?> "using declaration list"
751{- |Parses a using declaration
760usingDecl :: SyntaxInfo -> IdrisParser Using
761usingDecl syn = try (do x <- fnName
763 t <- typeExpr (disallowImp syn)
764 return (UImplicit x t))
767 return (UConstraint c xs)
768 <?> "using declaration"
770{- | Parse a clause with patterns
776pattern :: SyntaxInfo -> IdrisParser PDecl
777pattern syn = do fc <- getFC
779 return (PClauses fc [] (sMN 2 "_") [clause]) -- collect together later
782{- | Parse a constant applicative form declaration
785CAF ::= 'let' FnName '=' Expr Terminator;
788caf :: SyntaxInfo -> IdrisParser PDecl
789caf syn = do reserved "let"
790 n_in <- fnName; let n = expandNS syn n_in
796 <?> "constant applicative form declaration"
798{- | Parse an argument expression
801ArgExpr ::= HSimpleExpr | {- In Pattern External (User-defined) Expression -};
804argExpr :: SyntaxInfo -> IdrisParser PTerm
805argExpr syn = let syn' = syn { inPattern = True } in
806 try (hsimpleExpr syn') <|> simpleExternalExpr syn'
807 <?> "argument expression"
809{- | Parse a right hand side of a function
819RHSName ::= '{' FnName '}';
822rhs :: SyntaxInfo -> Name -> IdrisParser PTerm
823rhs syn n = do lchar '='; expr syn
826 name <- option n' (do symbol "{"; n <- fnName; symbol "}";
829 return (addLet fc name r)
830 <|> do reserved "impossible"; return PImpossible
831 <?> "function right hand side"
832 where mkN :: Name -> Name
833 mkN (UN x) = if (tnull x || not (isAlpha (thead x)))
834 then sUN "infix_op_lemma_1"
835 else sUN (str x++"_lemma_1")
836 mkN (NS x n) = NS (mkN x) n
839 addLet :: FC -> Name -> PTerm -> PTerm
840 addLet fc nm (PLet fc' n ty val r) = PLet fc' n ty val (addLet fc nm r)
841 addLet fc nm (PCase fc' t cs) = PCase fc' t (map addLetC cs)
842 where addLetC (l, r) = (l, addLet fc nm r)
843 addLet fc nm r = (PLet fc (sUN "value") Placeholder r (PMetavar nm))
845{- |Parses a function clause
848RHSOrWithBlock ::= RHS WhereOrTerminator
849 | 'with' SimpleExpr OpenBlock FnDecl+ CloseBlock
854Clause ::= WExpr+ RHSOrWithBlock
855 | SimpleExpr '<==' FnName RHS WhereOrTerminator
856 | ArgExpr Operator ArgExpr WExpr* RHSOrWithBlock {- Except "=" and "?=" operators to avoid ambiguity -}
857 | FnName ConstraintArg* ImplicitOrArgExpr* WExpr* RHSOrWithBlock
862ImplicitOrArgExpr ::= ImplicitArg | ArgExpr;
866WhereOrTerminator ::= WhereBlock | Terminator;
869clause :: SyntaxInfo -> IdrisParser PClause
871 = do wargs <- try (do pushIndent; some (wExpr syn))
874 n <- case lastParse ist of
876 Nothing -> fail "Invalid clause"
878 let ctxt = tt_ctxt ist
879 let wsyn = syn { syn_namespace = [] }
880 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
885 return $ PClauseR fc wargs r wheres) <|> (do
888 wval <- simpleExpr syn
891 ds <- some $ fnDecl syn
892 let withs = concat ds
894 return $ PWithR fc wargs wval pn withs)
895 <|> do ty <- try (do pushIndent
900 n_in <- fnName; let n = expandNS syn n_in
903 let ctxt = tt_ctxt ist
904 let wsyn = syn { syn_namespace = [] }
905 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
910 let capp = PLet fc (sMN 0 "match")
913 (PRef fc (sMN 0 "match"))
915 put (ist { lastParse = Just n })
916 return $ PClause fc n capp [] r wheres
917 <|> do (l, op) <- try (do
921 when (op == "=" || op == "?=" ) $
922 fail "infix clause definition with \"=\" and \"?=\" not supported "
924 let n = expandNS syn (sUN op)
927 wargs <- many (wExpr syn)
929 let wsyn = syn { syn_namespace = [] }
930 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
936 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
937 put (ist { lastParse = Just n })
938 return $ PClause fc n capp wargs rs wheres) <|> (do
941 wval <- bracketed syn
944 ds <- some $ fnDecl syn
947 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
948 let withs = map (fillLHSD n capp wargs) $ concat ds
949 put (ist { lastParse = Just n })
950 return $ PWith fc n capp wargs wval pn withs)
952 n_in <- fnName; let n = expandNS syn n_in
953 cargs <- many (constraintArg syn)
955 args <- many (try (implicitArg (syn { inPattern = True } ))
956 <|> (fmap pexp (argExpr syn)))
957 wargs <- many (wExpr syn)
958 let capp = PApp fc (PRef fc n)
962 let ctxt = tt_ctxt ist
963 let wsyn = syn { syn_namespace = [] }
964 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
970 put (ist { lastParse = Just n })
971 return $ PClause fc n capp wargs r wheres) <|> (do
974 put (ist { lastParse = Just n })
975 wval <- bracketed syn
978 ds <- some $ fnDecl syn
979 let withs = map (fillLHSD n capp wargs) $ concat ds
982 return $ PWith fc n capp wargs wval pn withs)
983 <?> "function clause"
985 optProof = option Nothing (do reserved "proof"
989 fillLHS :: Name -> PTerm -> [PTerm] -> PClause -> PClause
990 fillLHS n capp owargs (PClauseR fc wargs v ws)
991 = PClause fc n capp (owargs ++ wargs) v ws
992 fillLHS n capp owargs (PWithR fc wargs v pn ws)
993 = PWith fc n capp (owargs ++ wargs) v pn
994 (map (fillLHSD n capp (owargs ++ wargs)) ws)
997 fillLHSD :: Name -> PTerm -> [PTerm] -> PDecl -> PDecl
998 fillLHSD n c a (PClauses fc o fn cs) = PClauses fc o fn (map (fillLHS n c a) cs)
1001{-| Parses with pattern
1007wExpr :: SyntaxInfo -> IdrisParser PTerm
1008wExpr syn = do lchar '|'
1009 expr' (syn { inPattern = True })
1012{- | Parses a where block
1015WhereBlock ::= 'where' OpenBlock Decl+ CloseBlock;
1018whereBlock :: Name -> SyntaxInfo -> IdrisParser ([PDecl], [(Name, Name)])
1020 = do reserved "where"
1021 ds <- indentedBlock1 (decl syn)
1022 let dns = concatMap (concatMap declared) ds
1023 return (concat ds, map (\x -> (x, decoration syn x)) dns)
1026{- |Parses a code generation target language name
1038codegen_ :: IdrisParser Codegen
1039codegen_ = do n <- identifier; return (Via (map toLower n))
1040 <|> do reserved "Bytecode"; return Bytecode
1041 <?> "code generation language"
1043{- |Parses a compiler directive
1047 | String ',' StringList
1052Directive ::= '%' Directive';
1056Directive' ::= 'lib' CodeGen String_t
1057 | 'link' CodeGen String_t
1058 | 'flag' CodeGen String_t
1059 | 'include' CodeGen String_t
1062 | 'access' Accessibility
1063 | 'default' Totality
1065 | 'dynamic' StringList
1066 | 'name' Name NameList
1067 | 'error_handlers' Name NameList
1068 | 'language' 'TypeProviders'
1069 | 'language' 'ErrorReflection'
1073directive :: SyntaxInfo -> IdrisParser [PDecl]
1074directive syn = do try (lchar '%' *> reserved "lib"); cgn <- codegen_; lib <- stringLiteral;
1075 return [PDirective (do addLib cgn lib
1076 addIBC (IBCLib cgn lib))]
1077 <|> do try (lchar '%' *> reserved "link"); cgn <- codegen_; obj <- stringLiteral;
1078 return [PDirective (do dirs <- allImportDirs
1079 o <- liftIO $ findInPath dirs obj
1080 addIBC (IBCObj cgn obj) -- just name, search on loading ibc
1081 addObjectFile cgn o)]
1082 <|> do try (lchar '%' *> reserved "flag"); cgn <- codegen_;
1083 flag <- stringLiteral
1084 return [PDirective (do addIBC (IBCCGFlag cgn flag)
1086 <|> do try (lchar '%' *> reserved "include"); cgn <- codegen_; hdr <- stringLiteral;
1087 return [PDirective (do addHdr cgn hdr
1088 addIBC (IBCHeader cgn hdr))]
1089 <|> do try (lchar '%' *> reserved "hide"); n <- fnName
1090 return [PDirective (do setAccessibility n Hidden
1091 addIBC (IBCAccess n Hidden))]
1092 <|> do try (lchar '%' *> reserved "freeze"); n <- iName []
1093 return [PDirective (do setAccessibility n Frozen
1094 addIBC (IBCAccess n Frozen))]
1095 <|> do try (lchar '%' *> reserved "access"); acc <- accessibility
1096 return [PDirective (do i <- get
1097 put(i { default_access = acc }))]
1098 <|> do try (lchar '%' *> reserved "default"); tot <- totality
1100 put (i { default_total = tot } )
1101 return [PDirective (do i <- get
1102 put(i { default_total = tot }))]
1103 <|> do try (lchar '%' *> reserved "logging"); i <- natural;
1104 return [PDirective (setLogLevel (fromInteger i))]
1105 <|> do try (lchar '%' *> reserved "dynamic"); libs <- sepBy1 stringLiteral (lchar ',');
1106 return [PDirective (do added <- addDyLib libs
1108 Left lib -> addIBC (IBCDyLib (lib_name lib))
1111 <|> do try (lchar '%' *> reserved "name")
1113 ns <- sepBy1 name (lchar ',')
1114 return [PDirective (do ty' <- disambiguate ty
1115 mapM_ (addNameHint ty') ns
1116 mapM_ (\n -> addIBC (IBCNameHint (ty', n))) ns)]
1117 <|> do try (lchar '%' *> reserved "error_handlers")
1120 ns <- sepBy1 name (lchar ',')
1121 return [PDirective (do fn' <- disambiguate fn
1122 ns' <- mapM disambiguate ns
1123 addFunctionErrorHandlers fn' arg ns'
1124 mapM_ (addIBC . IBCFunctionErrorHandler fn' arg) ns')]
1125 <|> do try (lchar '%' *> reserved "language"); ext <- pLangExt;
1126 return [PDirective (addLangExt ext)]
1128 try (lchar '%' *> reserved "used")
1131 return [PDirective (addUsedName fc fn arg)]
1134 where disambiguate :: Name -> Idris Name
1135 disambiguate n = do i <- getIState
1136 case lookupCtxtName n (idris_implicits i) of
1137 [(n', _)] -> return n'
1138 [] -> throwError (NoSuchVariable n)
1139 more -> throwError (CantResolveAlts (map fst more))
1141pLangExt :: IdrisParser LanguageExt
1142pLangExt = (reserved "TypeProviders" >> return TypeProviders)
1143 <|> (reserved "ErrorReflection" >> return ErrorReflection)
1145{- | Parses a totality
1148Totality ::= 'partial' | 'total'
1152totality :: IdrisParser Bool
1154 = do reserved "total"; return True
1155 <|> do reserved "partial"; return False
1157{- | Parses a type provider
1160Provider ::= DocComment_t? '%' 'provide' Provider_What? '(' FnName TypeSig ')' 'with' Expr;
1161ProviderWhat ::= 'proof' | 'term' | 'type' | 'postulate'
1164provider :: SyntaxInfo -> IdrisParser [PDecl]
1165provider syn = do doc <- try (do (doc, _) <- docstring syn
1169 provideTerm doc <|> providePostulate doc
1171 where provideTerm doc =
1172 do lchar '('; n <- fnName; lchar ':'; t <- typeExpr syn; lchar ')'
1175 e <- expr syn <?> "provider expression"
1176 return [PProvider doc syn fc (ProvTerm t e) n]
1177 providePostulate doc =
1178 do reserved "postulate"
1182 e <- expr syn <?> "provider expression"
1183 return [PProvider doc syn fc (ProvPostulate e) n]
1185{- | Parses a transform
1188Transform ::= '%' 'transform' Expr '==>' Expr
1191transform :: SyntaxInfo -> IdrisParser [PDecl]
1192transform syn = do try (lchar '%' *> reserved "transform")
1193 -- leave it unchecked, until we work out what this should
1195-- safety <- option True (do reserved "unsafe"
1201 return [PTransform fc False l r]
1205{- * Loading and parsing -}
1206{- | Parses an expression from input -}
1207parseExpr :: IState -> String -> Result PTerm
1208parseExpr st = runparser (fullExpr defaultSyntax) st "(input)"
1210{- | Parses a constant form input -}
1211parseConst :: IState -> String -> Result Const
1212parseConst st = runparser constant st "(input)"
1214{- | Parses a tactic from input -}
1215parseTactic :: IState -> String -> Result PTactic
1216parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
1218-- | Parse module header and imports
1219parseImports :: FilePath -> String -> Idris (Maybe (Docstring ()), [String], [(Bool, String, Maybe String, FC)], Maybe Delta)
1220parseImports fname input
1222 case parseString (runInnerParser (evalStateT imports i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
1223 Failure err -> fail (show err)
1224 Success (x, i) -> do putIState i
1226 where imports :: IdrisParser ((Maybe (Docstring ()), [String], [(Bool, String, Maybe String, FC)], Maybe Delta), IState)
1227 imports = do whiteSpace
1228 (mdoc, mname) <- moduleHeader
1231 isEof <- lookAheadMatches eof
1236 return ((mdoc, mname, ps, mrk'), i)
1238-- | There should be a better way of doing this...
1239findFC :: Doc -> (FC, String)
1240findFC x = let s = show (plain x) in
1241 case span (/= ':') s of
1242 (failname, ':':rest) -> case span isDigit rest of
1243 (line, ':':rest') -> case span isDigit rest' of
1244 (col, ':':msg) -> let pos = (read line, read col) in
1245 (FC failname pos pos, msg)
1247-- | Check if the coloring matches the options and corrects if necessary
1248fixColour :: Bool -> ANSI.Doc -> ANSI.Doc
1249fixColour False doc = ANSI.plain doc
1250fixColour True doc = doc
1252-- | A program is a list of declarations, possibly with associated
1253-- documentation strings.
1254parseProg :: SyntaxInfo -> FilePath -> String -> Maybe Delta ->
1256parseProg syn fname input mrk
1258 case runparser mainProg i fname input of
1259 Failure doc -> do -- FIXME: Get error location from trifecta
1260 -- this can't be the solution!
1261 -- Issue #1575 on the issue tracker.
1262 -- https://github.com/idris-lang/Idris-dev/issues/1575
1263 let (fc, msg) = findFC doc
1265 case idris_outputmode i of
1266 RawOutput h -> iputStrLn (show $ fixColour (idris_colourRepl i) doc)
1267 IdeMode n h -> iWarn fc (P.text msg)
1268 putIState (i { errSpan = Just fc })
1270 Success (x, i) -> do putIState i
1271 reportParserWarnings
1273 where mainProg :: IdrisParser ([PDecl], IState)
1274 mainProg = case mrk of
1275 Nothing -> do i <- get; return ([], i)
1282{- | Load idris module and show error if something wrong happens -}
1283loadModule :: FilePath -> Idris (Maybe String)
1285 = idrisCatch (loadModule' f)
1286 (\e -> do setErrSpan (getErrSpan e)
1288 iWarn (getErrSpan e) $ pprintErr ist e
1291{- | Load idris module -}
1292loadModule' :: FilePath -> Idris (Maybe String)
1295 let file = takeWhile (/= ' ') f
1296 ibcsd <- valIBCSubDir i
1297 ids <- allImportDirs
1298 fp <- findImport ids ibcsd file
1299 if file `elem` imported i
1300 then do iLOG $ "Already read " ++ file
1302 else do putIState (i { imported = file : imported i })
1304 IDR fn -> loadSource False fn Nothing
1305 LIDR fn -> loadSource True fn Nothing
1307 idrisCatch (loadIBC True fn)
1308 (\c -> do iLOG $ fn ++ " failed " ++ pshow i c
1310 IDR sfn -> loadSource False sfn Nothing
1311 LIDR sfn -> loadSource True sfn Nothing)
1314{- | Load idris code from file -}
1315loadFromIFile :: Bool -> IFileType -> Maybe Int -> Idris ()
1316loadFromIFile reexp i@(IBC fn src) maxline
1317 = do iLOG $ "Skipping " ++ getSrcFile i
1318 idrisCatch (loadIBC reexp fn)
1319 (\err -> ierror $ LoadingFailed fn err)
1321 getSrcFile (IDR fn) = fn
1322 getSrcFile (LIDR fn) = fn
1323 getSrcFile (IBC f src) = getSrcFile src
1325loadFromIFile _ (IDR fn) maxline = loadSource' False fn maxline
1326loadFromIFile _ (LIDR fn) maxline = loadSource' True fn maxline
1328{-| Load idris source code and show error if something wrong happens -}
1329loadSource' :: Bool -> FilePath -> Maybe Int -> Idris ()
1330loadSource' lidr r maxline
1331 = idrisCatch (loadSource lidr r maxline)
1332 (\e -> do setErrSpan (getErrSpan e)
1335 At f e' -> iWarn f (pprintErr ist e')
1336 _ -> iWarn (getErrSpan e) (pprintErr ist e))
1338{- | Load Idris source code-}
1339loadSource :: Bool -> FilePath -> Maybe Int -> Idris ()
1340loadSource lidr f toline
1341 = do iLOG ("Reading " ++ f)
1343 let def_total = default_total i
1344 file_in <- runIO $ readFile f
1345 file <- if lidr then tclift $ unlit f file_in else return file_in
1346 (mdocs, mname, imports_in, pos) <- parseImports f file
1347 ai <- getAutoImports
1348 let imports = map (\n -> (True, n, Just n, emptyFC)) ai ++ imports_in
1349 ids <- allImportDirs
1350 ibcsd <- valIBCSubDir i
1352 do fp <- findImport ids ibcsd f
1354 LIDR fn -> ifail $ "No ibc for " ++ f
1355 IDR fn -> ifail $ "No ibc for " ++ f
1356 IBC fn src -> loadIBC True fn)
1357 [(re, fn) | (re, fn, _, _) <- imports]
1358 reportParserWarnings
1360 -- process and check module aliases
1361 let modAliases = M.fromList
1362 [(prep alias, prep realName) | (reexport, realName, Just alias, fc) <- imports]
1363 prep = map T.pack . reverse . Spl.splitOn "/"
1364 aliasNames = [(alias, fc) | (_, _, Just alias, fc) <- imports]
1365 histogram = groupBy ((==) `on` fst) . sortBy (comparing fst) $ aliasNames
1366 case map head . filter ((/= 1) . length) $ histogram of
1367 [] -> logLvl 3 $ "Module aliases: " ++ show (M.toList modAliases)
1368 (n,fc):_ -> throwError . At fc . Msg $ "import alias not unique: " ++ show n
1371 putIState (i { default_access = Hidden, module_aliases = modAliases })
1372 clearIBC -- start a new .ibc file
1373 -- record package info in .ibc
1374 imps <- allImportDirs
1375 mapM_ addIBC (map IBCImportDir imps)
1376 mapM_ (addIBC . IBCImport) [(reexport, realName) | (reexport, realName, alias, fc) <- imports]
1377 let syntax = defaultSyntax{ syn_namespace = reverse mname,
1380 -- Save the span from parsing the module header, because
1381 -- an empty program parse might obliterate it.
1382 let oldSpan = idris_parsedSpan ist
1383 ds' <- parseProg syntax f file pos
1385 case (ds', oldSpan) of
1387 -- If no program elements were parsed, we dind't
1388 -- get a loaded region in the IBC file. That
1389 -- means we need to add it back.
1391 putIState ist { idris_parsedSpan = oldSpan
1392 , ibc_write = IBCParsedRegion fc :
1397 -- Parsing done, now process declarations
1399 let ds = namespaces mname ds'
1400 logLvl 3 (show $ showDecls verbosePPOption ds)
1402 logLvl 10 (show (toAlist (idris_implicits i)))
1403 logLvl 3 (show (idris_infixes i))
1404 -- Now add all the declarations to the context
1406 when v $ iputStrLn $ "Type checking " ++ f
1407 -- we totality check after every Mutual block, so if
1408 -- anything is a single definition, wrap it in a
1409 -- mutual block on its own
1410 elabDecls toplevel (map toMutual ds)
1412 -- simplify every definition do give the totality checker
1414 mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
1415 updateContext (simplifyCasedef n $ getErasureInfo i))
1416 (map snd (idris_totcheck i))
1417 -- build size change graph from simplified definitions
1418 iLOG "Totality checking"
1420 mapM_ buildSCG (idris_totcheck i)
1421 mapM_ checkDeclTotality (idris_totcheck i)
1423 -- Redo totality check for deferred names
1424 let deftots = idris_defertotcheck i
1425 iLOG $ "Totality checking " ++ show deftots
1426 mapM_ (\x -> do tot <- getTotality x
1428 Total _ -> setTotality x Unchecked
1429 _ -> return ()) (map snd deftots)
1430 mapM_ buildSCG deftots
1431 mapM_ checkDeclTotality deftots
1433 iLOG ("Finished " ++ f)
1434 ibcsd <- valIBCSubDir i
1435 iLOG "Universe checking"
1437 let ibc = ibcPathNoFallback ibcsd f
1439 addHides (hide_list i)
1441 -- Save module documentation if applicable
1444 Nothing -> return ()
1445 Just docs -> addModDoc syntax mname docs
1448 -- Finally, write an ibc if checking was successful
1451 idrisCatch (do writeIBC f ibc; clearIBC)
1452 (\c -> return ()) -- failure is harmless
1454 putIState (i { default_total = def_total,
1458 namespaces :: [String] -> [PDecl] -> [PDecl]
1459 namespaces [] ds = ds
1460 namespaces (x:xs) ds = [PNamespace x (namespaces xs ds)]
1462 toMutual :: PDecl -> PDecl
1463 toMutual m@(PMutual _ d) = m
1464 toMutual (PNamespace x ds) = PNamespace x (map toMutual ds)
1465 toMutual x = let r = PMutual (fileFC "single mutual") [x] in
1472 addModDoc :: SyntaxInfo -> [String] -> Docstring () -> Idris ()
1473 addModDoc syn mname docs =
1475 docs' <- elabDocTerms recinfo (parsedDocs ist)
1476 let modDocs' = addDef docName docs' (idris_moduledocs ist)
1477 putIState ist { idris_moduledocs = modDocs' }
1478 addIBC (IBCModDocs docName)
1480 docName = NS modDocName (map T.pack (reverse mname))
1481 parsedDocs ist = annotCode (tryFullExpr syn ist) docs
1483{- | Adds names to hide list -}
1484addHides :: [(Name, Maybe Accessibility)] -> Idris ()
1485addHides xs = do i <- getIState
1486 let defh = default_access i
1487 let (hs, as) = partition isNothing xs
1490 (map (\ (n, _) -> (n, defh)) hs ++
1491 map (\ (n, Just a) -> (n, a)) as)
1492 where isNothing (_, Nothing) = True
1495 doHide (n, a) = do setAccessibility n a
1496 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