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 try (lchar '%' *> reserved "hint");
483 fnOpts (AutoHint : opts)
484 <|> do lchar '%'; reserved "specialise";
485 lchar '['; ns <- sepBy nameTimes (lchar ','); lchar ']'
486 fnOpts (Specialise ns : opts)
487 <|> do reserved "implicit"; fnOpts (Implicit : opts)
489 <?> "function modifier"
490 where nameTimes :: IdrisParser (Name, Maybe Int)
491 nameTimes = do n <- fnName
492 t <- option Nothing (do reds <- natural
493 return (Just (fromInteger reds)))
496{- | Parses a postulate
500 DocComment_t? 'postulate' FnOpts* Accesibility? FnOpts* FnName TypeSig Terminator
504postulate :: SyntaxInfo -> IdrisParser PDecl
505postulate syn = do (doc, ext)
506 <- try $ do (doc, _) <- docstring syn
511 let initOpts = if default_total ist
514 opts <- fnOpts initOpts
515 acc <- optional accessibility
518 let n = expandNS syn n_in
520 ty <- typeExpr (allowImp syn)
524 return (PPostulate ext doc syn fc opts' n ty)
526 where ppostDecl = do reserved "postulate"; return False
527 <|> do lchar '%'; reserved "extern"; return True
528{- | Parses a using declaration
532 'using' '(' UsingDeclList ')' OpenBlock Decl* CloseBlock
536using_ :: SyntaxInfo -> IdrisParser [PDecl]
538 do reserved "using"; lchar '('; ns <- usingDeclList syn; lchar ')'
540 let uvars = using syn
541 ds <- many (decl (syn { using = uvars ++ ns }))
544 <?> "using declaration"
546{- | Parses a parameters declaration
550 'parameters' '(' TypeDeclList ')' OpenBlock Decl* CloseBlock
554params :: SyntaxInfo -> IdrisParser [PDecl]
556 do reserved "parameters"; lchar '('; ns <- typeDeclList syn; lchar ')'
558 let pvars = syn_params syn
559 ds <- many (decl syn { syn_params = pvars ++ ns })
562 return [PParams fc ns (concat ds)]
563 <?> "parameters declaration"
565{- | Parses a mutual declaration (for mutually recursive functions)
569 'mutual' OpenBlock Decl* CloseBlock
573mutual :: SyntaxInfo -> IdrisParser [PDecl]
577 let pvars = syn_params syn
578 ds <- many (decl (syn { mut_nesting = mut_nesting syn + 1 } ))
581 return [PMutual fc (concat ds)]
584{-| Parses a namespace declaration
588 'namespace' identifier OpenBlock Decl+ CloseBlock
592namespace :: SyntaxInfo -> IdrisParser [PDecl]
594 do reserved "namespace"; n <- identifier;
596 ds <- some (decl syn { syn_namespace = n : syn_namespace syn })
598 return [PNamespace n (concat ds)]
599 <?> "namespace declaration"
601{- | Parses a methods block (for instances)
604 InstanceBlock ::= 'where' OpenBlock FnDecl* CloseBlock
607instanceBlock :: SyntaxInfo -> IdrisParser [PDecl]
608instanceBlock syn = do reserved "where"
610 ds <- many (fnDecl syn)
615{- | Parses a methods and instances block (for type classes)
626 'where' OpenBlock MethodOrInstance* CloseBlock
630classBlock :: SyntaxInfo -> IdrisParser [PDecl]
631classBlock syn = do reserved "where"
633 ds <- many (notEndBlock >> instance_ syn <|> fnDecl syn)
638{-| Parses a type class declaration
643 | '(' Name ':' Expr ')'
649 DocComment_t? Accessibility? 'class' ConstraintList? Name ClassArgument* ClassBlock?
653class_ :: SyntaxInfo -> IdrisParser [PDecl]
654class_ syn = do (doc, argDocs, acc)
655 <- try (do (doc, argDocs) <- docstring syn
656 acc <- optional accessibility
658 return (doc, argDocs, acc))
660 cons <- constraintList syn
662 let n = expandNS syn n_in
664 fds <- option (map fst cs) fundeps
665 ds <- option [] (classBlock syn)
666 accData acc n (concatMap declared ds)
667 return [PClass doc syn fc cons n cs argDocs fds ds]
668 <?> "type-class declaration"
670 fundeps :: IdrisParser [Name]
671 fundeps = do lchar '|'; sepBy name (lchar ',')
673 carg :: IdrisParser (Name, PTerm)
674 carg = do lchar '('; i <- name; lchar ':'; ty <- expr syn; lchar ')'
679{- | Parses a type class instance declaration
683 DocComment_t? 'instance' InstanceName? ConstraintList? Name SimpleExpr* InstanceBlock?
688InstanceName ::= '[' Name ']';
691instance_ :: SyntaxInfo -> IdrisParser [PDecl]
692instance_ syn = do (doc, argDocs)
693 <- try (docstring syn <* reserved "instance")
695 en <- optional instanceName
696 cs <- constraintList syn
698 args <- many (simpleExpr syn)
699 let sc = PApp fc (PRef fc cn) (map pexp args)
700 let t = bindList (PPi constraint) cs sc
701 ds <- option [] (instanceBlock syn)
702 return [PInstance doc argDocs syn fc cs cn args t en ds]
703 <?> "instance declaration"
704 where instanceName :: IdrisParser Name
705 instanceName = do lchar '['; n_in <- fnName; lchar ']'
706 let n = expandNS syn n_in
711-- | Parse a docstring
712docstring :: SyntaxInfo
713 -> IdrisParser (Docstring (Either Err PTerm),
714 [(Name,Docstring (Either Err PTerm))])
715docstring syn = do (doc, argDocs) <- option noDocs docComment
717 let doc' = annotCode (tryFullExpr syn ist) doc
718 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
719 | (n, d) <- argDocs ]
720 return (doc', argDocs')
723{- | Parses a using declaration list
735 | UsingDecl ',' UsingDeclList'
746usingDeclList :: SyntaxInfo -> IdrisParser [Using]
748 = try (sepBy1 (usingDecl syn) (lchar ','))
749 <|> do ns <- sepBy1 name (lchar ',')
751 t <- typeExpr (disallowImp syn)
752 return (map (\x -> UImplicit x t) ns)
753 <?> "using declaration list"
755{- |Parses a using declaration
764usingDecl :: SyntaxInfo -> IdrisParser Using
765usingDecl syn = try (do x <- fnName
767 t <- typeExpr (disallowImp syn)
768 return (UImplicit x t))
771 return (UConstraint c xs)
772 <?> "using declaration"
774{- | Parse a clause with patterns
780pattern :: SyntaxInfo -> IdrisParser PDecl
781pattern syn = do fc <- getFC
783 return (PClauses fc [] (sMN 2 "_") [clause]) -- collect together later
786{- | Parse a constant applicative form declaration
789CAF ::= 'let' FnName '=' Expr Terminator;
792caf :: SyntaxInfo -> IdrisParser PDecl
793caf syn = do reserved "let"
794 n_in <- fnName; let n = expandNS syn n_in
800 <?> "constant applicative form declaration"
802{- | Parse an argument expression
805ArgExpr ::= HSimpleExpr | {- In Pattern External (User-defined) Expression -};
808argExpr :: SyntaxInfo -> IdrisParser PTerm
809argExpr syn = let syn' = syn { inPattern = True } in
810 try (hsimpleExpr syn') <|> simpleExternalExpr syn'
811 <?> "argument expression"
813{- | Parse a right hand side of a function
823RHSName ::= '{' FnName '}';
826rhs :: SyntaxInfo -> Name -> IdrisParser PTerm
827rhs syn n = do lchar '='; expr syn
830 name <- option n' (do symbol "{"; n <- fnName; symbol "}";
833 return (addLet fc name r)
835 <?> "function right hand side"
836 where mkN :: Name -> Name
837 mkN (UN x) = if (tnull x || not (isAlpha (thead x)))
838 then sUN "infix_op_lemma_1"
839 else sUN (str x++"_lemma_1")
840 mkN (NS x n) = NS (mkN x) n
843 addLet :: FC -> Name -> PTerm -> PTerm
844 addLet fc nm (PLet fc' n ty val r) = PLet fc' n ty val (addLet fc nm r)
845 addLet fc nm (PCase fc' t cs) = PCase fc' t (map addLetC cs)
846 where addLetC (l, r) = (l, addLet fc nm r)
847 addLet fc nm r = (PLet fc (sUN "value") Placeholder r (PMetavar nm))
849{- |Parses a function clause
852RHSOrWithBlock ::= RHS WhereOrTerminator
853 | 'with' SimpleExpr OpenBlock FnDecl+ CloseBlock
858Clause ::= WExpr+ RHSOrWithBlock
859 | SimpleExpr '<==' FnName RHS WhereOrTerminator
860 | ArgExpr Operator ArgExpr WExpr* RHSOrWithBlock {- Except "=" and "?=" operators to avoid ambiguity -}
861 | FnName ConstraintArg* ImplicitOrArgExpr* WExpr* RHSOrWithBlock
866ImplicitOrArgExpr ::= ImplicitArg | ArgExpr;
870WhereOrTerminator ::= WhereBlock | Terminator;
873clause :: SyntaxInfo -> IdrisParser PClause
875 = do wargs <- try (do pushIndent; some (wExpr syn))
878 n <- case lastParse ist of
880 Nothing -> fail "Invalid clause"
882 let ctxt = tt_ctxt ist
883 let wsyn = syn { syn_namespace = [] }
884 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
889 return $ PClauseR fc wargs r wheres) <|> (do
892 wval <- simpleExpr syn
895 ds <- some $ fnDecl syn
896 let withs = concat ds
898 return $ PWithR fc wargs wval pn withs)
899 <|> do ty <- try (do pushIndent
904 n_in <- fnName; let n = expandNS syn n_in
907 let ctxt = tt_ctxt ist
908 let wsyn = syn { syn_namespace = [] }
909 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
914 let capp = PLet fc (sMN 0 "match")
917 (PRef fc (sMN 0 "match"))
919 put (ist { lastParse = Just n })
920 return $ PClause fc n capp [] r wheres
921 <|> do (l, op) <- try (do
925 when (op == "=" || op == "?=" ) $
926 fail "infix clause definition with \"=\" and \"?=\" not supported "
928 let n = expandNS syn (sUN op)
931 wargs <- many (wExpr syn)
933 let wsyn = syn { syn_namespace = [] }
934 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
940 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
941 put (ist { lastParse = Just n })
942 return $ PClause fc n capp wargs rs wheres) <|> (do
945 wval <- bracketed syn
948 ds <- some $ fnDecl syn
951 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
952 let withs = map (fillLHSD n capp wargs) $ concat ds
953 put (ist { lastParse = Just n })
954 return $ PWith fc n capp wargs wval pn withs)
956 n_in <- fnName; let n = expandNS syn n_in
957 cargs <- many (constraintArg syn)
959 args <- many (try (implicitArg (syn { inPattern = True } ))
960 <|> (fmap pexp (argExpr syn)))
961 wargs <- many (wExpr syn)
962 let capp = PApp fc (PRef fc n)
966 let ctxt = tt_ctxt ist
967 let wsyn = syn { syn_namespace = [] }
968 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
974 put (ist { lastParse = Just n })
975 return $ PClause fc n capp wargs r wheres) <|> (do
978 put (ist { lastParse = Just n })
979 wval <- bracketed syn
982 ds <- some $ fnDecl syn
983 let withs = map (fillLHSD n capp wargs) $ concat ds
986 return $ PWith fc n capp wargs wval pn withs)
987 <?> "function clause"
989 optProof = option Nothing (do reserved "proof"
993 fillLHS :: Name -> PTerm -> [PTerm] -> PClause -> PClause
994 fillLHS n capp owargs (PClauseR fc wargs v ws)
995 = PClause fc n capp (owargs ++ wargs) v ws
996 fillLHS n capp owargs (PWithR fc wargs v pn ws)
997 = PWith fc n capp (owargs ++ wargs) v pn
998 (map (fillLHSD n capp (owargs ++ wargs)) ws)
1001 fillLHSD :: Name -> PTerm -> [PTerm] -> PDecl -> PDecl
1002 fillLHSD n c a (PClauses fc o fn cs) = PClauses fc o fn (map (fillLHS n c a) cs)
1003 fillLHSD n c a x = x
1005{-| Parses with pattern
1011wExpr :: SyntaxInfo -> IdrisParser PTerm
1012wExpr syn = do lchar '|'
1013 expr' (syn { inPattern = True })
1016{- | Parses a where block
1019WhereBlock ::= 'where' OpenBlock Decl+ CloseBlock;
1022whereBlock :: Name -> SyntaxInfo -> IdrisParser ([PDecl], [(Name, Name)])
1024 = do reserved "where"
1025 ds <- indentedBlock1 (decl syn)
1026 let dns = concatMap (concatMap declared) ds
1027 return (concat ds, map (\x -> (x, decoration syn x)) dns)
1030{- |Parses a code generation target language name
1042codegen_ :: IdrisParser Codegen
1043codegen_ = do n <- identifier; return (Via (map toLower n))
1044 <|> do reserved "Bytecode"; return Bytecode
1045 <?> "code generation language"
1047{- |Parses a compiler directive
1051 | String ',' StringList
1056Directive ::= '%' Directive';
1060Directive' ::= 'lib' CodeGen String_t
1061 | 'link' CodeGen String_t
1062 | 'flag' CodeGen String_t
1063 | 'include' CodeGen String_t
1066 | 'access' Accessibility
1067 | 'default' Totality
1069 | 'dynamic' StringList
1070 | 'name' Name NameList
1071 | 'error_handlers' Name NameList
1072 | 'language' 'TypeProviders'
1073 | 'language' 'ErrorReflection'
1077directive :: SyntaxInfo -> IdrisParser [PDecl]
1078directive syn = do try (lchar '%' *> reserved "lib"); cgn <- codegen_; lib <- stringLiteral;
1079 return [PDirective (do addLib cgn lib
1080 addIBC (IBCLib cgn lib))]
1081 <|> do try (lchar '%' *> reserved "link"); cgn <- codegen_; obj <- stringLiteral;
1082 return [PDirective (do dirs <- allImportDirs
1083 o <- liftIO $ findInPath dirs obj
1084 addIBC (IBCObj cgn obj) -- just name, search on loading ibc
1085 addObjectFile cgn o)]
1086 <|> do try (lchar '%' *> reserved "flag"); cgn <- codegen_;
1087 flag <- stringLiteral
1088 return [PDirective (do addIBC (IBCCGFlag cgn flag)
1090 <|> do try (lchar '%' *> reserved "include"); cgn <- codegen_; hdr <- stringLiteral;
1091 return [PDirective (do addHdr cgn hdr
1092 addIBC (IBCHeader cgn hdr))]
1093 <|> do try (lchar '%' *> reserved "hide"); n <- fnName
1094 return [PDirective (do setAccessibility n Hidden
1095 addIBC (IBCAccess n Hidden))]
1096 <|> do try (lchar '%' *> reserved "freeze"); n <- iName []
1097 return [PDirective (do setAccessibility n Frozen
1098 addIBC (IBCAccess n Frozen))]
1099 <|> do try (lchar '%' *> reserved "access"); acc <- accessibility
1100 return [PDirective (do i <- get
1101 put(i { default_access = acc }))]
1102 <|> do try (lchar '%' *> reserved "default"); tot <- totality
1104 put (i { default_total = tot } )
1105 return [PDirective (do i <- get
1106 put(i { default_total = tot }))]
1107 <|> do try (lchar '%' *> reserved "logging"); i <- natural;
1108 return [PDirective (setLogLevel (fromInteger i))]
1109 <|> do try (lchar '%' *> reserved "dynamic"); libs <- sepBy1 stringLiteral (lchar ',');
1110 return [PDirective (do added <- addDyLib libs
1112 Left lib -> addIBC (IBCDyLib (lib_name lib))
1115 <|> do try (lchar '%' *> reserved "name")
1117 ns <- sepBy1 name (lchar ',')
1118 return [PDirective (do ty' <- disambiguate ty
1119 mapM_ (addNameHint ty') ns
1120 mapM_ (\n -> addIBC (IBCNameHint (ty', n))) ns)]
1121 <|> do try (lchar '%' *> reserved "error_handlers")
1124 ns <- sepBy1 name (lchar ',')
1125 return [PDirective (do fn' <- disambiguate fn
1126 ns' <- mapM disambiguate ns
1127 addFunctionErrorHandlers fn' arg ns'
1128 mapM_ (addIBC . IBCFunctionErrorHandler fn' arg) ns')]
1129 <|> do try (lchar '%' *> reserved "language"); ext <- pLangExt;
1130 return [PDirective (addLangExt ext)]
1132 try (lchar '%' *> reserved "used")
1135 return [PDirective (addUsedName fc fn arg)]
1138 where disambiguate :: Name -> Idris Name
1139 disambiguate n = do i <- getIState
1140 case lookupCtxtName n (idris_implicits i) of
1141 [(n', _)] -> return n'
1142 [] -> throwError (NoSuchVariable n)
1143 more -> throwError (CantResolveAlts (map fst more))
1145pLangExt :: IdrisParser LanguageExt
1146pLangExt = (reserved "TypeProviders" >> return TypeProviders)
1147 <|> (reserved "ErrorReflection" >> return ErrorReflection)
1149{- | Parses a totality
1152Totality ::= 'partial' | 'total'
1156totality :: IdrisParser Bool
1158 = do reserved "total"; return True
1159 <|> do reserved "partial"; return False
1161{- | Parses a type provider
1164Provider ::= DocComment_t? '%' 'provide' Provider_What? '(' FnName TypeSig ')' 'with' Expr;
1165ProviderWhat ::= 'proof' | 'term' | 'type' | 'postulate'
1168provider :: SyntaxInfo -> IdrisParser [PDecl]
1169provider syn = do doc <- try (do (doc, _) <- docstring syn
1173 provideTerm doc <|> providePostulate doc
1175 where provideTerm doc =
1176 do lchar '('; n <- fnName; lchar ':'; t <- typeExpr syn; lchar ')'
1179 e <- expr syn <?> "provider expression"
1180 return [PProvider doc syn fc (ProvTerm t e) n]
1181 providePostulate doc =
1182 do reserved "postulate"
1186 e <- expr syn <?> "provider expression"
1187 return [PProvider doc syn fc (ProvPostulate e) n]
1189{- | Parses a transform
1192Transform ::= '%' 'transform' Expr '==>' Expr
1195transform :: SyntaxInfo -> IdrisParser [PDecl]
1196transform syn = do try (lchar '%' *> reserved "transform")
1197 -- leave it unchecked, until we work out what this should
1199-- safety <- option True (do reserved "unsafe"
1205 return [PTransform fc False l r]
1209{- * Loading and parsing -}
1210{- | Parses an expression from input -}
1211parseExpr :: IState -> String -> Result PTerm
1212parseExpr st = runparser (fullExpr defaultSyntax) st "(input)"
1214{- | Parses a constant form input -}
1215parseConst :: IState -> String -> Result Const
1216parseConst st = runparser constant st "(input)"
1218{- | Parses a tactic from input -}
1219parseTactic :: IState -> String -> Result PTactic
1220parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
1222-- | Parse module header and imports
1223parseImports :: FilePath -> String -> Idris (Maybe (Docstring ()), [String], [(Bool, String, Maybe String, FC)], Maybe Delta)
1224parseImports fname input
1226 case parseString (runInnerParser (evalStateT imports i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
1227 Failure err -> fail (show err)
1228 Success (x, i) -> do putIState i
1230 where imports :: IdrisParser ((Maybe (Docstring ()), [String], [(Bool, String, Maybe String, FC)], Maybe Delta), IState)
1231 imports = do whiteSpace
1232 (mdoc, mname) <- moduleHeader
1235 isEof <- lookAheadMatches eof
1240 return ((mdoc, mname, ps, mrk'), i)
1242-- | There should be a better way of doing this...
1243findFC :: Doc -> (FC, String)
1244findFC x = let s = show (plain x) in
1245 case span (/= ':') s of
1246 (failname, ':':rest) -> case span isDigit rest of
1247 (line, ':':rest') -> case span isDigit rest' of
1248 (col, ':':msg) -> let pos = (read line, read col) in
1249 (FC failname pos pos, msg)
1251-- | Check if the coloring matches the options and corrects if necessary
1252fixColour :: Bool -> ANSI.Doc -> ANSI.Doc
1253fixColour False doc = ANSI.plain doc
1254fixColour True doc = doc
1256-- | A program is a list of declarations, possibly with associated
1257-- documentation strings.
1258parseProg :: SyntaxInfo -> FilePath -> String -> Maybe Delta ->
1260parseProg syn fname input mrk
1262 case runparser mainProg i fname input of
1263 Failure doc -> do -- FIXME: Get error location from trifecta
1264 -- this can't be the solution!
1265 -- Issue #1575 on the issue tracker.
1266 -- https://github.com/idris-lang/Idris-dev/issues/1575
1267 let (fc, msg) = findFC doc
1269 case idris_outputmode i of
1270 RawOutput h -> iputStrLn (show $ fixColour (idris_colourRepl i) doc)
1271 IdeMode n h -> iWarn fc (P.text msg)
1272 putIState (i { errSpan = Just fc })
1274 Success (x, i) -> do putIState i
1275 reportParserWarnings
1277 where mainProg :: IdrisParser ([PDecl], IState)
1278 mainProg = case mrk of
1279 Nothing -> do i <- get; return ([], i)
1286{- | Load idris module and show error if something wrong happens -}
1287loadModule :: FilePath -> Idris (Maybe String)
1289 = idrisCatch (loadModule' f)
1290 (\e -> do setErrSpan (getErrSpan e)
1292 iWarn (getErrSpan e) $ pprintErr ist e
1295{- | Load idris module -}
1296loadModule' :: FilePath -> Idris (Maybe String)
1299 let file = takeWhile (/= ' ') f
1300 ibcsd <- valIBCSubDir i
1301 ids <- allImportDirs
1302 fp <- findImport ids ibcsd file
1303 if file `elem` imported i
1304 then do iLOG $ "Already read " ++ file
1306 else do putIState (i { imported = file : imported i })
1308 IDR fn -> loadSource False fn Nothing
1309 LIDR fn -> loadSource True fn Nothing
1311 idrisCatch (loadIBC True fn)
1312 (\c -> do iLOG $ fn ++ " failed " ++ pshow i c
1314 IDR sfn -> loadSource False sfn Nothing
1315 LIDR sfn -> loadSource True sfn Nothing)
1318{- | Load idris code from file -}
1319loadFromIFile :: Bool -> IFileType -> Maybe Int -> Idris ()
1320loadFromIFile reexp i@(IBC fn src) maxline
1321 = do iLOG $ "Skipping " ++ getSrcFile i
1322 idrisCatch (loadIBC reexp fn)
1323 (\err -> ierror $ LoadingFailed fn err)
1325 getSrcFile (IDR fn) = fn
1326 getSrcFile (LIDR fn) = fn
1327 getSrcFile (IBC f src) = getSrcFile src
1329loadFromIFile _ (IDR fn) maxline = loadSource' False fn maxline
1330loadFromIFile _ (LIDR fn) maxline = loadSource' True fn maxline
1332{-| Load idris source code and show error if something wrong happens -}
1333loadSource' :: Bool -> FilePath -> Maybe Int -> Idris ()
1334loadSource' lidr r maxline
1335 = idrisCatch (loadSource lidr r maxline)
1336 (\e -> do setErrSpan (getErrSpan e)
1339 At f e' -> iWarn f (pprintErr ist e')
1340 _ -> iWarn (getErrSpan e) (pprintErr ist e))
1342{- | Load Idris source code-}
1343loadSource :: Bool -> FilePath -> Maybe Int -> Idris ()
1344loadSource lidr f toline
1345 = do iLOG ("Reading " ++ f)
1347 let def_total = default_total i
1348 file_in <- runIO $ readFile f
1349 file <- if lidr then tclift $ unlit f file_in else return file_in
1350 (mdocs, mname, imports_in, pos) <- parseImports f file
1351 ai <- getAutoImports
1352 let imports = map (\n -> (True, n, Just n, emptyFC)) ai ++ imports_in
1353 ids <- allImportDirs
1354 ibcsd <- valIBCSubDir i
1356 do fp <- findImport ids ibcsd f
1358 LIDR fn -> ifail $ "No ibc for " ++ f
1359 IDR fn -> ifail $ "No ibc for " ++ f
1360 IBC fn src -> loadIBC True fn)
1361 [(re, fn) | (re, fn, _, _) <- imports]
1362 reportParserWarnings
1364 -- process and check module aliases
1365 let modAliases = M.fromList
1366 [(prep alias, prep realName) | (reexport, realName, Just alias, fc) <- imports]
1367 prep = map T.pack . reverse . Spl.splitOn "/"
1368 aliasNames = [(alias, fc) | (_, _, Just alias, fc) <- imports]
1369 histogram = groupBy ((==) `on` fst) . sortBy (comparing fst) $ aliasNames
1370 case map head . filter ((/= 1) . length) $ histogram of
1371 [] -> logLvl 3 $ "Module aliases: " ++ show (M.toList modAliases)
1372 (n,fc):_ -> throwError . At fc . Msg $ "import alias not unique: " ++ show n
1375 putIState (i { default_access = Hidden, module_aliases = modAliases })
1376 clearIBC -- start a new .ibc file
1377 -- record package info in .ibc
1378 imps <- allImportDirs
1379 mapM_ addIBC (map IBCImportDir imps)
1380 mapM_ (addIBC . IBCImport) [(reexport, realName) | (reexport, realName, alias, fc) <- imports]
1381 let syntax = defaultSyntax{ syn_namespace = reverse mname,
1384 -- Save the span from parsing the module header, because
1385 -- an empty program parse might obliterate it.
1386 let oldSpan = idris_parsedSpan ist
1387 ds' <- parseProg syntax f file pos
1389 case (ds', oldSpan) of
1391 -- If no program elements were parsed, we dind't
1392 -- get a loaded region in the IBC file. That
1393 -- means we need to add it back.
1395 putIState ist { idris_parsedSpan = oldSpan
1396 , ibc_write = IBCParsedRegion fc :
1401 -- Parsing done, now process declarations
1403 let ds = namespaces mname ds'
1404 logLvl 3 (show $ showDecls verbosePPOption ds)
1406 logLvl 10 (show (toAlist (idris_implicits i)))
1407 logLvl 3 (show (idris_infixes i))
1408 -- Now add all the declarations to the context
1410 when v $ iputStrLn $ "Type checking " ++ f
1411 -- we totality check after every Mutual block, so if
1412 -- anything is a single definition, wrap it in a
1413 -- mutual block on its own
1414 elabDecls toplevel (map toMutual ds)
1416 -- simplify every definition do give the totality checker
1418 mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
1419 updateContext (simplifyCasedef n $ getErasureInfo i))
1420 (map snd (idris_totcheck i))
1421 -- build size change graph from simplified definitions
1422 iLOG "Totality checking"
1424 mapM_ buildSCG (idris_totcheck i)
1425 mapM_ checkDeclTotality (idris_totcheck i)
1427 -- Redo totality check for deferred names
1428 let deftots = idris_defertotcheck i
1429 iLOG $ "Totality checking " ++ show deftots
1430 mapM_ (\x -> do tot <- getTotality x
1432 Total _ -> setTotality x Unchecked
1433 _ -> return ()) (map snd deftots)
1434 mapM_ buildSCG deftots
1435 mapM_ checkDeclTotality deftots
1437 iLOG ("Finished " ++ f)
1438 ibcsd <- valIBCSubDir i
1439 iLOG "Universe checking"
1441 let ibc = ibcPathNoFallback ibcsd f
1443 addHides (hide_list i)
1445 -- Save module documentation if applicable
1448 Nothing -> return ()
1449 Just docs -> addModDoc syntax mname docs
1452 -- Finally, write an ibc if checking was successful
1455 idrisCatch (do writeIBC f ibc; clearIBC)
1456 (\c -> return ()) -- failure is harmless
1458 putIState (i { default_total = def_total,
1462 namespaces :: [String] -> [PDecl] -> [PDecl]
1463 namespaces [] ds = ds
1464 namespaces (x:xs) ds = [PNamespace x (namespaces xs ds)]
1466 toMutual :: PDecl -> PDecl
1467 toMutual m@(PMutual _ d) = m
1468 toMutual (PNamespace x ds) = PNamespace x (map toMutual ds)
1469 toMutual x = let r = PMutual (fileFC "single mutual") [x] in
1476 addModDoc :: SyntaxInfo -> [String] -> Docstring () -> Idris ()
1477 addModDoc syn mname docs =
1479 docs' <- elabDocTerms recinfo (parsedDocs ist)
1480 let modDocs' = addDef docName docs' (idris_moduledocs ist)
1481 putIState ist { idris_moduledocs = modDocs' }
1482 addIBC (IBCModDocs docName)
1484 docName = NS modDocName (map T.pack (reverse mname))
1485 parsedDocs ist = annotCode (tryFullExpr syn ist) docs
1487{- | Adds names to hide list -}
1488addHides :: [(Name, Maybe Accessibility)] -> Idris ()
1489addHides xs = do i <- getIState
1490 let defh = default_access i
1491 let (hs, as) = partition isNothing xs
1494 (map (\ (n, _) -> (n, defh)) hs ++
1495 map (\ (n, Just a) -> (n, a)) as)
1496 where isNothing (_, Nothing) = True
1499 doHide (n, a) = do setAccessibility n a
1500 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