1{-# LANGUAGE GeneralizedNewtypeDeriving, ConstraintKinds, PatternGuards #-}
3module Idris.Parser(module Idris.Parser,
4 module Idris.ParseExpr,
5 module Idris.ParseData,
6 module Idris.ParseHelpers,
7 module Idris.ParseOps) where
9import Prelude hiding (pi)
11import Text.Trifecta.Delta
12import Text.Trifecta hiding (span, stringLiteral, charLiteral, natural, symbol, char, string, whiteSpace)
13import Text.Parser.LookAhead
14import Text.Parser.Expression
15import qualified Text.Parser.Token as Tok
16import qualified Text.Parser.Char as Chr
17import qualified Text.Parser.Token.Highlight as Hi
19import Text.PrettyPrint.ANSI.Leijen (Doc, plain)
20import qualified Text.PrettyPrint.ANSI.Leijen as ANSI
22import Idris.AbsSyntax hiding (namespace, params)
25import Idris.Delaborate
35import Idris.ParseHelpers
40import Idris.Docstrings
44import Util.DynamicLinker
45import qualified Util.Pretty as P
48import Idris.Core.Evaluate
50import Control.Applicative hiding (Const)
52import Control.Monad.Error (throwError, catchError)
53import Control.Monad.State.Strict
57import qualified Data.List.Split as Spl
62import qualified Data.Map as M
63import qualified Data.HashSet as HS
64import qualified Data.Text as T
65import qualified Data.ByteString.UTF8 as UTF8
66import qualified Data.Set as S
75 grammar shortcut notation:
76 ~CHARSEQ = complement of char sequence (i.e. any character except CHARSEQ)
77 RULE? = optional rule (i.e. RULE or nothing)
78 RULE* = repeated rule (i.e. RULE zero or more times)
79 RULE+ = repeated rule with at least one match (i.e. RULE one or more times)
80 RULE! = invalid rule (i.e. rule that is not valid in context, report meaningful error in case)
81 RULE{n} = rule repeated n times
87{- | Parses module definition
90 ModuleHeader ::= 'module' Identifier_t ';'?;
93moduleHeader :: IdrisParser [String]
94moduleHeader = try (do noDocCommentHere "Modules cannot have documentation comments"
97 option ';' (lchar ';')
98 return (moduleName i))
99 <|> try (do lchar '%'; reserved "unqualified"
101 <|> return (moduleName "Main")
102 where moduleName x = case span (/='.') x of
104 (x, '.':y) -> x : moduleName y
106{- | Parses an import statement
109 Import ::= 'import' Identifier_t ';'?;
112import_ :: IdrisParser (String, Maybe String, FC)
113import_ = do fc <- getFC
116 newName <- optional (reserved "as" *> identifier)
117 option ';' (lchar ';')
118 return (toPath id, toPath <$> newName, fc)
119 <?> "import statement"
120 where toPath = foldl1' (</>) . Spl.splitOn "."
122{- | Parses program source
128prog :: SyntaxInfo -> IdrisParser [PDecl]
129prog syn = do whiteSpace
130 decls <- many (decl syn)
131 let c = (concat decls)
133 Nothing -> do notOpenBraces; eof
137 put ist { idris_parsedSpan = Just (FC (fc_fname fc) (0,0) (fc_end fc)),
138 ibc_write = IBCParsedRegion fc : ibc_write ist }
141{-| Parses a top-level declaration
160decl :: SyntaxInfo -> IdrisParser [PDecl]
161decl syn = do fc <- getFC
162 -- if we're after maxline, stop here
163 let continue = case maxline syn of
165 Just l -> if fst (fc_end fc) > l
166 then mut_nesting syn /= 0
168 if continue then do notEndBlock
170 else fail "End of readable input"
171 where declBody :: IdrisParser [PDecl]
179 <|> do d <- dsl syn; return [d]
183 <|> do import_; fail "imports must be at top of file"
185 declBody' :: IdrisParser [PDecl]
186 declBody' = do d <- decl' syn
188 let d' = fmap (debindApp syn . (desugar syn i)) d
191{- | Parses a top-level declaration with possible syntax sugar
203decl' :: SyntaxInfo -> IdrisParser PDecl
211{- | Parses a syntax extension declaration (and adds the rule to parser state)
214 SyntaxDecl ::= SyntaxRule;
217syntaxDecl :: SyntaxInfo -> IdrisParser PDecl
218syntaxDecl syn = do s <- syntaxRule syn
220 let rs = syntax_rules i
221 let ns = syntax_keywords i
222 let ibc = ibc_write i
223 let ks = map show (names s)
224 put (i { syntax_rules = s : rs,
225 syntax_keywords = ks ++ ns,
226 ibc_write = IBCSyntax s : map IBCKeyword ks ++ ibc })
228 return (PSyntax fc s)
229 where names (Rule syms _ _) = mapMaybe ename syms
230 ename (Keyword n) = Just n
233{- | Parses a syntax extension declaration
236SyntaxRuleOpts ::= 'term' | 'pattern';
241 SyntaxRuleOpts? 'syntax' SyntaxSym+ '=' TypeExpr Terminator;
245SyntaxSym ::= '[' Name_t ']'
252syntaxRule :: SyntaxInfo -> IdrisParser Syntax
256 sty <- option AnySyntax (do reserved "term"; return TermSyntax
257 <|> do reserved "pattern"; return PatternSyntax)
260 syms <- some syntaxSym
261 when (all isExpr syms) $ unexpected "missing keywords in syntax rule"
262 let ns = mapMaybe getName syms
263 when (length ns /= length (nub ns))
264 $ unexpected "repeated variable in syntax rule"
266 tm <- typeExpr (allowImp syn)
268 return (Rule (mkSimple syms) tm sty)
270 isExpr (Expr _) = True
272 getName (Expr n) = Just n
274 -- Can't parse two full expressions (i.e. expressions with application) in a row
275 -- so change them both to a simple expression
276 mkSimple (Expr e : es) = SimpleExpr e : mkSimple' es
277 mkSimple xs = mkSimple' xs
279 mkSimple' (Expr e : Expr e1 : es) = SimpleExpr e : SimpleExpr e1 :
281 mkSimple' (e : es) = e : mkSimple' es
285{- | Parses a syntax symbol (either binding variable, keyword or expression)
288SyntaxSym ::= '[' Name_t ']'
295syntaxSym :: IdrisParser SSymbol
296syntaxSym = try (do lchar '['; n <- name; lchar ']'
298 <|> try (do lchar '{'; n <- name; lchar '}'
302 <|> do sym <- stringLiteral
306{- | Parses a function declaration with possible syntax sugar
309 FunDecl ::= FunDecl';
312fnDecl :: SyntaxInfo -> IdrisParser [PDecl]
313fnDecl syn = try (do notEndBlock
316 let d' = fmap (desugar syn i) d
317 return [d']) <?> "function declaration"
319{-| Parses a function declaration
323 DocComment_t? FnOpts* Accessibility? FnOpts* FnName TypeSig Terminator
330fnDecl' :: SyntaxInfo -> IdrisParser PDecl
331fnDecl' syn = checkFixity $
332 do (doc, fc, opts', n, acc) <- try (do
335 doc <- option noDocs docComment
337 let initOpts = if default_total ist
340 opts <- fnOpts initOpts
341 acc <- optional accessibility
344 let n = expandNS syn n_in
347 return (doc, fc, opts', n, acc))
348 ty <- typeExpr (allowImp syn)
351 return (PTy (fst doc) (snd doc) syn fc opts' n ty)
355 <?> "function declaration"
356 where checkFixity :: IdrisParser PDecl -> IdrisParser PDecl
357 checkFixity p = do decl <- p
359 Nothing -> return decl
360 Just n -> do fOk <- fixityOK n
362 "Missing fixity declaration for " ++ show n
364 getName (PTy _ _ _ _ _ n _) = Just n
366 fixityOK (NS n _) = fixityOK n
367 fixityOK (UN n) | all (flip elem opChars) (str n) =
368 do fixities <- fmap idris_infixes get
369 return . elem (str n) . map (\ (Fix _ op) -> op) $ fixities
370 | otherwise = return True
371 fixityOK _ = return True
373{-| Parses function options given initial options
381 | '%' 'error_handler'
383 | '%' 'specialise' '[' NameTimesList? ']'
388NameTimes ::= FnName Natural?;
394 | NameTimes ',' NameTimesList
398-- FIXME: Check compatability for function options (i.e. partal/total)
399fnOpts :: [FnOpt] -> IdrisParser [FnOpt]
401 = do reserved "total"; fnOpts (TotalFn : opts)
402 <|> do reserved "partial"; fnOpts (PartialFn : (opts \\ [TotalFn]))
403 <|> do reserved "covering"; fnOpts (CoveringFn : (opts \\ [TotalFn]))
404 <|> do try (lchar '%' *> reserved "export"); c <- stringLiteral;
405 fnOpts (CExport c : opts)
406 <|> do try (lchar '%' *> reserved "no_implicit");
407 fnOpts (NoImplicit : opts)
408 <|> do try (lchar '%' *> reserved "assert_total");
409 fnOpts (AssertTotal : opts)
410 <|> do try (lchar '%' *> reserved "error_handler");
411 fnOpts (ErrorHandler : opts)
412 <|> do try (lchar '%' *> reserved "error_reverse");
413 fnOpts (ErrorReverse : opts)
414 <|> do try (lchar '%' *> reserved "reflection");
415 fnOpts (Reflection : opts)
416 <|> do lchar '%'; reserved "specialise";
417 lchar '['; ns <- sepBy nameTimes (lchar ','); lchar ']'
418 fnOpts (Specialise ns : opts)
419 <|> do reserved "implicit"; fnOpts (Implicit : opts)
421 <?> "function modifier"
422 where nameTimes :: IdrisParser (Name, Maybe Int)
423 nameTimes = do n <- fnName
424 t <- option Nothing (do reds <- natural
425 return (Just (fromInteger reds)))
428{- | Parses a postulate
432 DocComment_t? 'postulate' FnOpts* Accesibility? FnOpts* FnName TypeSig Terminator
436postulate :: SyntaxInfo -> IdrisParser PDecl
437postulate syn = do doc <- try $ do doc <- option noDocs docComment
442 let initOpts = if default_total ist
445 opts <- fnOpts initOpts
446 acc <- optional accessibility
449 let n = expandNS syn n_in
451 ty <- typeExpr (allowImp syn)
455 return (PPostulate (fst doc) syn fc opts' n ty)
458{- | Parses a using declaration
462 'using' '(' UsingDeclList ')' OpenBlock Decl* CloseBlock
466using_ :: SyntaxInfo -> IdrisParser [PDecl]
468 do reserved "using"; lchar '('; ns <- usingDeclList syn; lchar ')'
470 let uvars = using syn
471 ds <- many (decl (syn { using = uvars ++ ns }))
474 <?> "using declaration"
476{- | Parses a parameters declaration
480 'parameters' '(' TypeDeclList ')' OpenBlock Decl* CloseBlock
484params :: SyntaxInfo -> IdrisParser [PDecl]
486 do reserved "parameters"; lchar '('; ns <- typeDeclList syn; lchar ')'
488 let pvars = syn_params syn
489 ds <- many (decl syn { syn_params = pvars ++ ns })
492 return [PParams fc ns (concat ds)]
493 <?> "parameters declaration"
495{- | Parses a mutual declaration (for mutually recursive functions)
499 'mutual' OpenBlock Decl* CloseBlock
503mutual :: SyntaxInfo -> IdrisParser [PDecl]
507 let pvars = syn_params syn
508 ds <- many (decl (syn { mut_nesting = mut_nesting syn + 1 } ))
511 return [PMutual fc (concat ds)]
514{-| Parses a namespace declaration
518 'namespace' identifier OpenBlock Decl+ CloseBlock
522namespace :: SyntaxInfo -> IdrisParser [PDecl]
524 do reserved "namespace"; n <- identifier;
526 ds <- some (decl syn { syn_namespace = n : syn_namespace syn })
528 return [PNamespace n (concat ds)]
529 <?> "namespace declaration"
531{- | Parses a methods block (for instances)
534 InstanceBlock ::= 'where' OpenBlock FnDecl* CloseBlock
537instanceBlock :: SyntaxInfo -> IdrisParser [PDecl]
538instanceBlock syn = do reserved "where"
540 ds <- many (fnDecl syn)
545{- | Parses a methods and instances block (for type classes)
556 'where' OpenBlock MethodOrInstance* CloseBlock
560classBlock :: SyntaxInfo -> IdrisParser [PDecl]
561classBlock syn = do reserved "where"
563 ds <- many ((notEndBlock >> instance_ syn) <|> fnDecl syn)
568{-| Parses a type class declaration
573 | '(' Name ':' Expr ')'
579 DocComment_t? Accessibility? 'class' ConstraintList? Name ClassArgument* ClassBlock?
583class_ :: SyntaxInfo -> IdrisParser [PDecl]
584class_ syn = do (doc, acc) <- try (do
585 doc <- option noDocs docComment
586 acc <- optional accessibility
588 reserved "class"; fc <- getFC; cons <- constraintList syn; n_in <- fnName
589 let n = expandNS syn n_in
591 ds <- option [] (classBlock syn)
592 accData acc n (concatMap declared ds)
593 return [PClass (fst doc) syn fc cons n cs (snd doc) ds]
594 <?> "type-class declaration"
596 carg :: IdrisParser (Name, PTerm)
597 carg = do lchar '('; i <- name; lchar ':'; ty <- expr syn; lchar ')'
602{- | Parses a type class instance declaration
606 'instance' InstanceName? ConstraintList? Name SimpleExpr* InstanceBlock?
611InstanceName ::= '[' Name ']';
614instance_ :: SyntaxInfo -> IdrisParser [PDecl]
615instance_ syn = do reserved "instance"; fc <- getFC
616 en <- optional instanceName
617 cs <- constraintList syn
619 args <- many (simpleExpr syn)
620 let sc = PApp fc (PRef fc cn) (map pexp args)
621 let t = bindList (PPi constraint) (map (\x -> (sMN 0 "constraint", x)) cs) sc
622 ds <- option [] (instanceBlock syn)
623 return [PInstance syn fc cs cn args t en ds]
624 <?> "instance declaration"
625 where instanceName :: IdrisParser Name
626 instanceName = do lchar '['; n_in <- fnName; lchar ']'
627 let n = expandNS syn n_in
632{- | Parses a using declaration list
644 | UsingDecl ',' UsingDeclList'
655usingDeclList :: SyntaxInfo -> IdrisParser [Using]
657 = try (sepBy1 (usingDecl syn) (lchar ','))
658 <|> do ns <- sepBy1 name (lchar ',')
660 t <- typeExpr (disallowImp syn)
661 return (map (\x -> UImplicit x t) ns)
662 <?> "using declaration list"
664{- |Parses a using declaration
673usingDecl :: SyntaxInfo -> IdrisParser Using
674usingDecl syn = try (do x <- fnName
676 t <- typeExpr (disallowImp syn)
677 return (UImplicit x t))
680 return (UConstraint c xs)
681 <?> "using declaration"
683{- | Parse a clause with patterns
689pattern :: SyntaxInfo -> IdrisParser PDecl
690pattern syn = do fc <- getFC
692 return (PClauses fc [] (sMN 2 "_") [clause]) -- collect together later
695{- | Parse a constant applicative form declaration
698CAF ::= 'let' FnName '=' Expr Terminator;
701caf :: SyntaxInfo -> IdrisParser PDecl
702caf syn = do reserved "let"
703 n_in <- fnName; let n = expandNS syn n_in
709 <?> "constant applicative form declaration"
711{- | Parse an argument expression
714ArgExpr ::= HSimpleExpr | {- In Pattern External (User-defined) Expression -};
717argExpr :: SyntaxInfo -> IdrisParser PTerm
718argExpr syn = let syn' = syn { inPattern = True } in
719 try (hsimpleExpr syn') <|> simpleExternalExpr syn'
720 <?> "argument expression"
722{- | Parse a right hand side of a function
732RHSName ::= '{' FnName '}';
735rhs :: SyntaxInfo -> Name -> IdrisParser PTerm
736rhs syn n = do lchar '='; expr syn
738 name <- option n' (do symbol "{"; n <- fnName; symbol "}";
741 return (addLet name r)
742 <|> do reserved "impossible"; return PImpossible
743 <?> "function right hand side"
744 where mkN :: Name -> Name
745 mkN (UN x) = if (tnull x || not (isAlpha (thead x)))
746 then sUN "infix_op_lemma_1"
747 else sUN (str x++"_lemma_1")
748 mkN (NS x n) = NS (mkN x) n
751 addLet :: Name -> PTerm -> PTerm
752 addLet nm (PLet n ty val r) = PLet n ty val (addLet nm r)
753 addLet nm (PCase fc t cs) = PCase fc t (map addLetC cs)
754 where addLetC (l, r) = (l, addLet nm r)
755 addLet nm r = (PLet (sUN "value") Placeholder r (PMetavar nm))
757{- |Parses a function clause
760RHSOrWithBlock ::= RHS WhereOrTerminator
761 | 'with' SimpleExpr OpenBlock FnDecl+ CloseBlock
766Clause ::= WExpr+ RHSOrWithBlock
767 | SimpleExpr '<==' FnName RHS WhereOrTerminator
768 | ArgExpr Operator ArgExpr WExpr* RHSOrWithBlock {- Except "=" and "?=" operators to avoid ambiguity -}
769 | FnName ConstraintArg* ImplicitOrArgExpr* WExpr* RHSOrWithBlock
774ImplicitOrArgExpr ::= ImplicitArg | ArgExpr;
778WhereOrTerminator ::= WhereBlock | Terminator;
781clause :: SyntaxInfo -> IdrisParser PClause
783 = do wargs <- try (do pushIndent; some (wExpr syn))
786 n <- case lastParse ist of
788 Nothing -> fail "Invalid clause"
790 let ctxt = tt_ctxt ist
791 let wsyn = syn { syn_namespace = [] }
792 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
797 return $ PClauseR fc wargs r wheres) <|> (do
800 wval <- simpleExpr syn
802 ds <- some $ fnDecl syn
803 let withs = concat ds
805 return $ PWithR fc wargs wval withs)
806 <|> do ty <- try (do pushIndent
811 n_in <- fnName; let n = expandNS syn n_in
814 let ctxt = tt_ctxt ist
815 let wsyn = syn { syn_namespace = [] }
816 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
821 let capp = PLet (sMN 0 "match")
824 (PRef fc (sMN 0 "match"))
826 put (ist { lastParse = Just n })
827 return $ PClause fc n capp [] r wheres
828 <|> do (l, op) <- try (do
832 when (op == "=" || op == "?=" ) $
833 fail "infix clause definition with \"=\" and \"?=\" not supported "
835 let n = expandNS syn (sUN op)
838 wargs <- many (wExpr syn)
840 let wsyn = syn { syn_namespace = [] }
841 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
847 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
848 put (ist { lastParse = Just n })
849 return $ PClause fc n capp wargs rs wheres) <|> (do
852 wval <- bracketed syn
854 ds <- some $ fnDecl syn
857 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
858 let withs = map (fillLHSD n capp wargs) $ concat ds
859 put (ist { lastParse = Just n })
860 return $ PWith fc n capp wargs wval withs)
862 n_in <- fnName; let n = expandNS syn n_in
863 cargs <- many (constraintArg syn)
865 args <- many (try (implicitArg (syn { inPattern = True } ))
866 <|> (fmap pexp (argExpr syn)))
867 wargs <- many (wExpr syn)
868 let capp = PApp fc (PRef fc n)
872 let ctxt = tt_ctxt ist
873 let wsyn = syn { syn_namespace = [] }
874 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
880 put (ist { lastParse = Just n })
881 return $ PClause fc n capp wargs r wheres) <|> (do
884 put (ist { lastParse = Just n })
885 wval <- bracketed syn
887 ds <- some $ fnDecl syn
888 let withs = map (fillLHSD n capp wargs) $ concat ds
891 return $ PWith fc n capp wargs wval withs)
892 <?> "function clause"
894 fillLHS :: Name -> PTerm -> [PTerm] -> PClause -> PClause
895 fillLHS n capp owargs (PClauseR fc wargs v ws)
896 = PClause fc n capp (owargs ++ wargs) v ws
897 fillLHS n capp owargs (PWithR fc wargs v ws)
898 = PWith fc n capp (owargs ++ wargs) v
899 (map (fillLHSD n capp (owargs ++ wargs)) ws)
902 fillLHSD :: Name -> PTerm -> [PTerm] -> PDecl -> PDecl
903 fillLHSD n c a (PClauses fc o fn cs) = PClauses fc o fn (map (fillLHS n c a) cs)
906{-| Parses with pattern
912wExpr :: SyntaxInfo -> IdrisParser PTerm
913wExpr syn = do lchar '|'
917{- | Parses a where block
920WhereBlock ::= 'where' OpenBlock Decl+ CloseBlock;
923whereBlock :: Name -> SyntaxInfo -> IdrisParser ([PDecl], [(Name, Name)])
925 = do reserved "where"
926 ds <- indentedBlock1 (decl syn)
927 let dns = concatMap (concatMap declared) ds
928 return (concat ds, map (\x -> (x, decoration syn x)) dns)
931{- |Parses a code generation target language name
943codegen_ :: IdrisParser Codegen
944codegen_ = do n <- identifier; return (Via (map toLower n))
945 <|> do reserved "Bytecode"; return Bytecode
946 <?> "code generation language"
948{- |Parses a compiler directive
952 | String ',' StringList
957Directive ::= '%' Directive';
961Directive' ::= 'lib' CodeGen String_t
962 | 'link' CodeGen String_t
963 | 'flag' CodeGen String_t
964 | 'include' CodeGen String_t
967 | 'access' Accessibility
970 | 'dynamic' StringList
971 | 'name' Name NameList
972 | 'error_handlers' Name NameList
973 | 'language' 'TypeProviders'
974 | 'language' 'ErrorReflection'
978directive :: SyntaxInfo -> IdrisParser [PDecl]
979directive syn = do try (lchar '%' *> reserved "lib"); cgn <- codegen_; lib <- stringLiteral;
980 return [PDirective (do addLib cgn lib
981 addIBC (IBCLib cgn lib))]
982 <|> do try (lchar '%' *> reserved "link"); cgn <- codegen_; obj <- stringLiteral;
983 return [PDirective (do dirs <- allImportDirs
984 o <- liftIO $ findInPath dirs obj
985 addIBC (IBCObj cgn obj) -- just name, search on loading ibc
986 addObjectFile cgn o)]
987 <|> do try (lchar '%' *> reserved "flag"); cgn <- codegen_;
988 flag <- stringLiteral
989 return [PDirective (do addIBC (IBCCGFlag cgn flag)
991 <|> do try (lchar '%' *> reserved "include"); cgn <- codegen_; hdr <- stringLiteral;
992 return [PDirective (do addHdr cgn hdr
993 addIBC (IBCHeader cgn hdr))]
994 <|> do try (lchar '%' *> reserved "hide"); n <- fnName
995 return [PDirective (do setAccessibility n Hidden
996 addIBC (IBCAccess n Hidden))]
997 <|> do try (lchar '%' *> reserved "freeze"); n <- iName []
998 return [PDirective (do setAccessibility n Frozen
999 addIBC (IBCAccess n Frozen))]
1000 <|> do try (lchar '%' *> reserved "access"); acc <- accessibility
1001 return [PDirective (do i <- get
1002 put(i { default_access = acc }))]
1003 <|> do try (lchar '%' *> reserved "default"); tot <- totality
1005 put (i { default_total = tot } )
1006 return [PDirective (do i <- get
1007 put(i { default_total = tot }))]
1008 <|> do try (lchar '%' *> reserved "logging"); i <- natural;
1009 return [PDirective (setLogLevel (fromInteger i))]
1010 <|> do try (lchar '%' *> reserved "dynamic"); libs <- sepBy1 stringLiteral (lchar ',');
1011 return [PDirective (do added <- addDyLib libs
1013 Left lib -> addIBC (IBCDyLib (lib_name lib))
1016 <|> do try (lchar '%' *> reserved "name")
1018 ns <- sepBy1 name (lchar ',')
1019 return [PDirective (do ty' <- disambiguate ty
1020 mapM_ (addNameHint ty') ns
1021 mapM_ (\n -> addIBC (IBCNameHint (ty', n))) ns)]
1022 <|> do try (lchar '%' *> reserved "error_handlers")
1025 ns <- sepBy1 name (lchar ',')
1026 return [PDirective (do fn' <- disambiguate fn
1027 ns' <- mapM disambiguate ns
1028 addFunctionErrorHandlers fn' arg ns'
1029 mapM_ (addIBC . IBCFunctionErrorHandler fn' arg) ns')]
1030 <|> do try (lchar '%' *> reserved "language"); ext <- pLangExt;
1031 return [PDirective (addLangExt ext)]
1033 where disambiguate :: Name -> Idris Name
1034 disambiguate n = do i <- getIState
1035 case lookupCtxtName n (idris_implicits i) of
1036 [(n', _)] -> return n'
1037 [] -> throwError (NoSuchVariable n)
1038 more -> throwError (CantResolveAlts (map fst more))
1040pLangExt :: IdrisParser LanguageExt
1041pLangExt = (reserved "TypeProviders" >> return TypeProviders)
1042 <|> (reserved "ErrorReflection" >> return ErrorReflection)
1044{- | Parses a totality
1047Totality ::= 'partial' | 'total'
1051totality :: IdrisParser Bool
1053 = do reserved "total"; return True
1054 <|> do reserved "partial"; return False
1056{- | Parses a type provider
1059Provider ::= '%' 'provide' Provider_What? '(' FnName TypeSig ')' 'with' Expr;
1060ProviderWhat ::= 'proof' | 'term' | 'type' | 'postulate'
1063provider :: SyntaxInfo -> IdrisParser [PDecl]
1064provider syn = do try (lchar '%' *> reserved "provide");
1065 provideTerm <|> providePostulate
1067 where provideTerm = do lchar '('; n <- fnName; lchar ':'; t <- typeExpr syn; lchar ')'
1070 e <- expr syn <?> "provider expression"
1071 return [PProvider syn fc (ProvTerm t e) n]
1072 providePostulate = do reserved "postulate"
1076 e <- expr syn <?> "provider expression"
1077 return [PProvider syn fc (ProvPostulate e) n]
1079{- | Parses a transform
1082Transform ::= '%' 'transform' Expr '==>' Expr
1085transform :: SyntaxInfo -> IdrisParser [PDecl]
1086transform syn = do try (lchar '%' *> reserved "transform")
1087 -- leave it unchecked, until we work out what this should
1089-- safety <- option True (do reserved "unsafe"
1095 return [PTransform fc False l r]
1099{- * Loading and parsing -}
1100{- | Parses an expression from input -}
1101parseExpr :: IState -> String -> Result PTerm
1102parseExpr st = runparser (fullExpr defaultSyntax) st "(input)"
1104{- | Parses a constant form input -}
1105parseConst :: IState -> String -> Result Const
1106parseConst st = runparser constant st "(input)"
1108{- | Parses a tactic from input -}
1109parseTactic :: IState -> String -> Result PTactic
1110parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
1112-- | Parse module header and imports
1113parseImports :: FilePath -> String -> Idris ([String], [(String, Maybe String, FC)], Maybe Delta)
1114parseImports fname input
1116 case parseString (runInnerParser (evalStateT imports i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
1117 Failure err -> fail (show err)
1118 Success (x, i) -> do putIState i
1120 where imports :: IdrisParser (([String], [(String, Maybe String, FC)], Maybe Delta), IState)
1121 imports = do whiteSpace
1122 mname <- moduleHeader
1125 isEof <- lookAheadMatches eof
1130 return ((mname, ps, mrk'), i)
1132-- | There should be a better way of doing this...
1133findFC :: Doc -> (FC, String)
1134findFC x = let s = show (plain x) in
1135 case span (/= ':') s of
1136 (failname, ':':rest) -> case span isDigit rest of
1137 (line, ':':rest') -> case span isDigit rest' of
1138 (col, ':':msg) -> let pos = (read line, read col) in
1139 (FC failname pos pos, msg)
1141-- | Check if the coloring matches the options and corrects if necessary
1142fixColour :: Bool -> ANSI.Doc -> ANSI.Doc
1143fixColour False doc = ANSI.plain doc
1144fixColour True doc = doc
1146-- | A program is a list of declarations, possibly with associated
1147-- documentation strings.
1148parseProg :: SyntaxInfo -> FilePath -> String -> Maybe Delta ->
1150parseProg syn fname input mrk
1152 case runparser mainProg i fname input of
1153 Failure doc -> do -- FIXME: Get error location from trifecta
1154 -- this can't be the solution!
1155 let (fc, msg) = findFC doc
1157 case idris_outputmode i of
1158 RawOutput h -> iputStrLn (show $ fixColour (idris_colourRepl i) doc)
1159 IdeSlave n h -> iWarn fc (P.text msg)
1160 putIState (i { errSpan = Just fc })
1162 Success (x, i) -> do putIState i
1163 reportParserWarnings
1165 where mainProg :: IdrisParser ([PDecl], IState)
1166 mainProg = case mrk of
1167 Nothing -> do i <- get; return ([], i)
1174{- | Load idris module and show error if something wrong happens -}
1175loadModule :: FilePath -> Idris String
1177 = idrisCatch (loadModule' f)
1178 (\e -> do setErrSpan (getErrSpan e)
1180 iWarn (getErrSpan e) $ pprintErr ist e
1183{- | Load idris module -}
1184loadModule' :: FilePath -> Idris String
1187 let file = takeWhile (/= ' ') f
1188 ibcsd <- valIBCSubDir i
1189 ids <- allImportDirs
1190 fp <- findImport ids ibcsd file
1191 if file `elem` imported i
1192 then iLOG $ "Already read " ++ file
1193 else do putIState (i { imported = file : imported i })
1195 IDR fn -> loadSource False fn Nothing
1196 LIDR fn -> loadSource True fn Nothing
1198 idrisCatch (loadIBC fn)
1199 (\c -> do iLOG $ fn ++ " failed " ++ pshow i c
1201 IDR sfn -> loadSource False sfn Nothing
1202 LIDR sfn -> loadSource True sfn Nothing)
1203 let (dir, fh) = splitFileName file
1204 return (dropExtension fh)
1207{- | Load idris code from file -}
1208loadFromIFile :: IFileType -> Maybe Int -> Idris ()
1209loadFromIFile i@(IBC fn src) maxline
1210 = do iLOG $ "Skipping " ++ getSrcFile i
1211 idrisCatch (loadIBC fn)
1212 (\err -> ierror $ LoadingFailed fn err)
1214 getSrcFile (IDR fn) = fn
1215 getSrcFile (LIDR fn) = fn
1216 getSrcFile (IBC f src) = getSrcFile src
1218loadFromIFile (IDR fn) maxline = loadSource' False fn maxline
1219loadFromIFile (LIDR fn) maxline = loadSource' True fn maxline
1221{-| Load idris source code and show error if something wrong happens -}
1222loadSource' :: Bool -> FilePath -> Maybe Int -> Idris ()
1223loadSource' lidr r maxline
1224 = idrisCatch (loadSource lidr r maxline)
1225 (\e -> do setErrSpan (getErrSpan e)
1228 At f e' -> iWarn f (pprintErr ist e')
1229 _ -> iWarn (getErrSpan e) (pprintErr ist e))
1231{- | Load Idris source code-}
1232loadSource :: Bool -> FilePath -> Maybe Int -> Idris ()
1233loadSource lidr f toline
1234 = do iLOG ("Reading " ++ f)
1236 let def_total = default_total i
1237 file_in <- runIO $ readFile f
1238 file <- if lidr then tclift $ unlit f file_in else return file_in
1239 (mname, imports_in, pos) <- parseImports f file
1240 ai <- getAutoImports
1241 let imports = map (\n -> (n, Just n, emptyFC)) ai ++ imports_in
1242 ids <- allImportDirs
1243 ibcsd <- valIBCSubDir i
1244 mapM_ (\f -> do fp <- findImport ids ibcsd f
1246 LIDR fn -> ifail $ "No ibc for " ++ f
1247 IDR fn -> ifail $ "No ibc for " ++ f
1248 IBC fn src -> loadIBC fn)
1249 [fn | (fn, _, _) <- imports]
1250 reportParserWarnings
1252 -- process and check module aliases
1253 let modAliases = M.fromList
1254 [(prep alias, prep realName) | (realName, Just alias, fc) <- imports]
1255 prep = map T.pack . reverse . Spl.splitOn "/"
1256 aliasNames = [(alias, fc) | (_, Just alias, fc) <- imports]
1257 histogram = groupBy ((==) `on` fst) . sortBy (comparing fst) $ aliasNames
1258 case map head . filter ((/= 1) . length) $ histogram of
1259 [] -> logLvl 3 $ "Module aliases: " ++ show (M.toList modAliases)
1260 (n,fc):_ -> throwError . At fc . Msg $ "import alias not unique: " ++ show n
1263 putIState (i { default_access = Hidden, module_aliases = modAliases })
1264 clearIBC -- start a new .ibc file
1265 -- record package info in .ibc
1266 imps <- allImportDirs
1267 mapM_ addIBC (map IBCImportDir imps)
1268 mapM_ (addIBC . IBCImport) [realName | (realName, alias, fc) <- imports]
1269 let syntax = defaultSyntax{ syn_namespace = reverse mname,
1271 ds' <- parseProg syntax f file pos
1273 -- Parsing done, now process declarations
1275 let ds = namespaces mname ds'
1276 logLvl 3 (show $ showDecls verbosePPOption ds)
1278 logLvl 10 (show (toAlist (idris_implicits i)))
1279 logLvl 3 (show (idris_infixes i))
1280 -- Now add all the declarations to the context
1282 when v $ iputStrLn $ "Type checking " ++ f
1283 -- we totality check after every Mutual block, so if
1284 -- anything is a single definition, wrap it in a
1285 -- mutual block on its own
1286 elabDecls toplevel (map toMutual ds)
1288 -- simplify every definition do give the totality checker
1290 mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
1291 updateContext (simplifyCasedef n $ getErasureInfo i))
1292 (map snd (idris_totcheck i))
1293 -- build size change graph from simplified definitions
1294 iLOG "Totality checking"
1296 mapM_ buildSCG (idris_totcheck i)
1297 mapM_ checkDeclTotality (idris_totcheck i)
1299 -- Redo totality check for deferred names
1300 let deftots = idris_defertotcheck i
1301 iLOG $ "Totality checking " ++ show deftots
1302 mapM_ (\x -> do tot <- getTotality x
1304 Total _ -> setTotality x Unchecked
1305 _ -> return ()) (map snd deftots)
1306 mapM_ buildSCG deftots
1307 mapM_ checkDeclTotality deftots
1309 iLOG ("Finished " ++ f)
1310 ibcsd <- valIBCSubDir i
1311 iLOG "Universe checking"
1313 let ibc = ibcPathNoFallback ibcsd f
1315 addHides (hide_list i)
1317 -- Finally, write an ibc if checking was successful
1320 idrisCatch (do writeIBC f ibc; clearIBC)
1321 (\c -> return ()) -- failure is harmless
1323 putIState (i { default_total = def_total,
1327 namespaces :: [String] -> [PDecl] -> [PDecl]
1328 namespaces [] ds = ds
1329 namespaces (x:xs) ds = [PNamespace x (namespaces xs ds)]
1331 toMutual :: PDecl -> PDecl
1332 toMutual m@(PMutual _ d) = m
1333 toMutual (PNamespace x ds) = PNamespace x (map toMutual ds)
1334 toMutual x = let r = PMutual (fileFC "single mutual") [x] in
1336 PClauses _ _ _ _ -> r
1337 PClass _ _ _ _ _ _ _ _ -> r
1338 PInstance _ _ _ _ _ _ _ _ -> r
1341{- | Adds names to hide list -}
1342addHides :: [(Name, Maybe Accessibility)] -> Idris ()
1343addHides xs = do i <- getIState
1344 let defh = default_access i
1345 let (hs, as) = partition isNothing xs
1348 (map (\ (n, _) -> (n, defh)) hs ++
1349 map (\ (n, Just a) -> (n, a)) as)
1350 where isNothing (_, Nothing) = True
1353 doHide (n, a) = do setAccessibility n a
1354 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