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 reserved "C"; return ViaC
945 <|> do reserved "Java"; return ViaJava
946 <|> do reserved "JavaScript"; return ViaJavaScript
947 <|> do reserved "Node"; return ViaNode
948 <|> do reserved "LLVM"; return ViaLLVM
949 <|> do reserved "Bytecode"; return Bytecode
950 <?> "code generation language"
952{- |Parses a compiler directive
956 | String ',' StringList
961Directive ::= '%' Directive';
965Directive' ::= 'lib' CodeGen String_t
966 | 'link' CodeGen String_t
967 | 'flag' CodeGen String_t
968 | 'include' CodeGen String_t
971 | 'access' Accessibility
974 | 'dynamic' StringList
975 | 'name' Name NameList
976 | 'error_handlers' Name NameList
977 | 'language' 'TypeProviders'
978 | 'language' 'ErrorReflection'
982directive :: SyntaxInfo -> IdrisParser [PDecl]
983directive syn = do try (lchar '%' *> reserved "lib"); cgn <- codegen_; lib <- stringLiteral;
984 return [PDirective (do addLib cgn lib
985 addIBC (IBCLib cgn lib))]
986 <|> do try (lchar '%' *> reserved "link"); cgn <- codegen_; obj <- stringLiteral;
987 return [PDirective (do dirs <- allImportDirs
988 o <- liftIO $ findInPath dirs obj
989 addIBC (IBCObj cgn obj) -- just name, search on loading ibc
990 addObjectFile cgn o)]
991 <|> do try (lchar '%' *> reserved "flag"); cgn <- codegen_;
992 flag <- stringLiteral
993 return [PDirective (do addIBC (IBCCGFlag cgn flag)
995 <|> do try (lchar '%' *> reserved "include"); cgn <- codegen_; hdr <- stringLiteral;
996 return [PDirective (do addHdr cgn hdr
997 addIBC (IBCHeader cgn hdr))]
998 <|> do try (lchar '%' *> reserved "hide"); n <- fnName
999 return [PDirective (do setAccessibility n Hidden
1000 addIBC (IBCAccess n Hidden))]
1001 <|> do try (lchar '%' *> reserved "freeze"); n <- iName []
1002 return [PDirective (do setAccessibility n Frozen
1003 addIBC (IBCAccess n Frozen))]
1004 <|> do try (lchar '%' *> reserved "access"); acc <- accessibility
1005 return [PDirective (do i <- get
1006 put(i { default_access = acc }))]
1007 <|> do try (lchar '%' *> reserved "default"); tot <- totality
1009 put (i { default_total = tot } )
1010 return [PDirective (do i <- get
1011 put(i { default_total = tot }))]
1012 <|> do try (lchar '%' *> reserved "logging"); i <- natural;
1013 return [PDirective (setLogLevel (fromInteger i))]
1014 <|> do try (lchar '%' *> reserved "dynamic"); libs <- sepBy1 stringLiteral (lchar ',');
1015 return [PDirective (do added <- addDyLib libs
1017 Left lib -> addIBC (IBCDyLib (lib_name lib))
1020 <|> do try (lchar '%' *> reserved "name")
1022 ns <- sepBy1 name (lchar ',')
1023 return [PDirective (do ty' <- disambiguate ty
1024 mapM_ (addNameHint ty') ns
1025 mapM_ (\n -> addIBC (IBCNameHint (ty', n))) ns)]
1026 <|> do try (lchar '%' *> reserved "error_handlers")
1029 ns <- sepBy1 name (lchar ',')
1030 return [PDirective (do fn' <- disambiguate fn
1031 ns' <- mapM disambiguate ns
1032 addFunctionErrorHandlers fn' arg ns'
1033 mapM_ (addIBC . IBCFunctionErrorHandler fn' arg) ns')]
1034 <|> do try (lchar '%' *> reserved "language"); ext <- pLangExt;
1035 return [PDirective (addLangExt ext)]
1037 where disambiguate :: Name -> Idris Name
1038 disambiguate n = do i <- getIState
1039 case lookupCtxtName n (idris_implicits i) of
1040 [(n', _)] -> return n'
1041 [] -> throwError (NoSuchVariable n)
1042 more -> throwError (CantResolveAlts (map fst more))
1044pLangExt :: IdrisParser LanguageExt
1045pLangExt = (reserved "TypeProviders" >> return TypeProviders)
1046 <|> (reserved "ErrorReflection" >> return ErrorReflection)
1048{- | Parses a totality
1051Totality ::= 'partial' | 'total'
1055totality :: IdrisParser Bool
1057 = do reserved "total"; return True
1058 <|> do reserved "partial"; return False
1060{- | Parses a type provider
1063Provider ::= '%' 'provide' Provider_What? '(' FnName TypeSig ')' 'with' Expr;
1064ProviderWhat ::= 'proof' | 'term' | 'type' | 'postulate'
1067provider :: SyntaxInfo -> IdrisParser [PDecl]
1068provider syn = do try (lchar '%' *> reserved "provide");
1069 provideTerm <|> providePostulate
1071 where provideTerm = do lchar '('; n <- fnName; lchar ':'; t <- typeExpr syn; lchar ')'
1074 e <- expr syn <?> "provider expression"
1075 return [PProvider syn fc (ProvTerm t e) n]
1076 providePostulate = do reserved "postulate"
1080 e <- expr syn <?> "provider expression"
1081 return [PProvider syn fc (ProvPostulate e) n]
1083{- | Parses a transform
1086Transform ::= '%' 'transform' Expr '==>' Expr
1089transform :: SyntaxInfo -> IdrisParser [PDecl]
1090transform syn = do try (lchar '%' *> reserved "transform")
1091 -- leave it unchecked, until we work out what this should
1093-- safety <- option True (do reserved "unsafe"
1099 return [PTransform fc False l r]
1103{- * Loading and parsing -}
1104{- | Parses an expression from input -}
1105parseExpr :: IState -> String -> Result PTerm
1106parseExpr st = runparser (fullExpr defaultSyntax) st "(input)"
1108{- | Parses a constant form input -}
1109parseConst :: IState -> String -> Result Const
1110parseConst st = runparser constant st "(input)"
1112{- | Parses a tactic from input -}
1113parseTactic :: IState -> String -> Result PTactic
1114parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
1116-- | Parse module header and imports
1117parseImports :: FilePath -> String -> Idris ([String], [(String, Maybe String, FC)], Maybe Delta)
1118parseImports fname input
1120 case parseString (runInnerParser (evalStateT imports i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
1121 Failure err -> fail (show err)
1122 Success (x, i) -> do putIState i
1124 where imports :: IdrisParser (([String], [(String, Maybe String, FC)], Maybe Delta), IState)
1125 imports = do whiteSpace
1126 mname <- moduleHeader
1129 isEof <- lookAheadMatches eof
1134 return ((mname, ps, mrk'), i)
1136-- | There should be a better way of doing this...
1137findFC :: Doc -> (FC, String)
1138findFC x = let s = show (plain x) in
1139 case span (/= ':') s of
1140 (failname, ':':rest) -> case span isDigit rest of
1141 (line, ':':rest') -> case span isDigit rest' of
1142 (col, ':':msg) -> let pos = (read line, read col) in
1143 (FC failname pos pos, msg)
1145-- | Check if the coloring matches the options and corrects if necessary
1146fixColour :: Bool -> ANSI.Doc -> ANSI.Doc
1147fixColour False doc = ANSI.plain doc
1148fixColour True doc = doc
1150-- | A program is a list of declarations, possibly with associated
1151-- documentation strings.
1152parseProg :: SyntaxInfo -> FilePath -> String -> Maybe Delta ->
1154parseProg syn fname input mrk
1156 case runparser mainProg i fname input of
1157 Failure doc -> do -- FIXME: Get error location from trifecta
1158 -- this can't be the solution!
1159 let (fc, msg) = findFC doc
1161 case idris_outputmode i of
1162 RawOutput h -> iputStrLn (show $ fixColour (idris_colourRepl i) doc)
1163 IdeSlave n h -> iWarn fc (P.text msg)
1164 putIState (i { errSpan = Just fc })
1166 Success (x, i) -> do putIState i
1167 reportParserWarnings
1169 where mainProg :: IdrisParser ([PDecl], IState)
1170 mainProg = case mrk of
1171 Nothing -> do i <- get; return ([], i)
1178{- | Load idris module and show error if something wrong happens -}
1179loadModule :: FilePath -> Idris String
1181 = idrisCatch (loadModule' f)
1182 (\e -> do setErrSpan (getErrSpan e)
1184 iWarn (getErrSpan e) $ pprintErr ist e
1187{- | Load idris module -}
1188loadModule' :: FilePath -> Idris String
1191 let file = takeWhile (/= ' ') f
1192 ibcsd <- valIBCSubDir i
1193 ids <- allImportDirs
1194 fp <- findImport ids ibcsd file
1195 if file `elem` imported i
1196 then iLOG $ "Already read " ++ file
1197 else do putIState (i { imported = file : imported i })
1199 IDR fn -> loadSource False fn Nothing
1200 LIDR fn -> loadSource True fn Nothing
1202 idrisCatch (loadIBC fn)
1203 (\c -> do iLOG $ fn ++ " failed " ++ pshow i c
1205 IDR sfn -> loadSource False sfn Nothing
1206 LIDR sfn -> loadSource True sfn Nothing)
1207 let (dir, fh) = splitFileName file
1208 return (dropExtension fh)
1211{- | Load idris code from file -}
1212loadFromIFile :: IFileType -> Maybe Int -> Idris ()
1213loadFromIFile i@(IBC fn src) maxline
1214 = do iLOG $ "Skipping " ++ getSrcFile i
1215 idrisCatch (loadIBC fn)
1216 (\err -> ierror $ LoadingFailed fn err)
1218 getSrcFile (IDR fn) = fn
1219 getSrcFile (LIDR fn) = fn
1220 getSrcFile (IBC f src) = getSrcFile src
1222loadFromIFile (IDR fn) maxline = loadSource' False fn maxline
1223loadFromIFile (LIDR fn) maxline = loadSource' True fn maxline
1225{-| Load idris source code and show error if something wrong happens -}
1226loadSource' :: Bool -> FilePath -> Maybe Int -> Idris ()
1227loadSource' lidr r maxline
1228 = idrisCatch (loadSource lidr r maxline)
1229 (\e -> do setErrSpan (getErrSpan e)
1232 At f e' -> iWarn f (pprintErr ist e')
1233 _ -> iWarn (getErrSpan e) (pprintErr ist e))
1235{- | Load Idris source code-}
1236loadSource :: Bool -> FilePath -> Maybe Int -> Idris ()
1237loadSource lidr f toline
1238 = do iLOG ("Reading " ++ f)
1240 let def_total = default_total i
1241 file_in <- runIO $ readFile f
1242 file <- if lidr then tclift $ unlit f file_in else return file_in
1243 (mname, imports, pos) <- parseImports f file
1244 ids <- allImportDirs
1245 ibcsd <- valIBCSubDir i
1246 mapM_ (\f -> do fp <- findImport ids ibcsd f
1248 LIDR fn -> ifail $ "No ibc for " ++ f
1249 IDR fn -> ifail $ "No ibc for " ++ f
1250 IBC fn src -> loadIBC fn)
1251 [fn | (fn, _, _) <- imports]
1252 reportParserWarnings
1254 -- process and check module aliases
1255 let modAliases = M.fromList
1256 [(prep alias, prep realName) | (realName, Just alias, fc) <- imports]
1257 prep = map T.pack . reverse . Spl.splitOn "/"
1258 aliasNames = [(alias, fc) | (_, Just alias, fc) <- imports]
1259 histogram = groupBy ((==) `on` fst) . sortBy (comparing fst) $ aliasNames
1260 case map head . filter ((/= 1) . length) $ histogram of
1261 [] -> logLvl 3 $ "Module aliases: " ++ show (M.toList modAliases)
1262 (n,fc):_ -> throwError . At fc . Msg $ "import alias not unique: " ++ show n
1265 putIState (i { default_access = Hidden, module_aliases = modAliases })
1266 clearIBC -- start a new .ibc file
1267 mapM_ (addIBC . IBCImport) [realName | (realName, alias, fc) <- imports]
1268 let syntax = defaultSyntax{ syn_namespace = reverse mname,
1270 ds' <- parseProg syntax f file pos
1272 -- Parsing done, now process declarations
1274 let ds = namespaces mname ds'
1275 logLvl 3 (show $ showDecls verbosePPOption ds)
1277 logLvl 10 (show (toAlist (idris_implicits i)))
1278 logLvl 3 (show (idris_infixes i))
1279 -- Now add all the declarations to the context
1281 when v $ iputStrLn $ "Type checking " ++ f
1282 -- we totality check after every Mutual block, so if
1283 -- anything is a single definition, wrap it in a
1284 -- mutual block on its own
1285 elabDecls toplevel (map toMutual ds)
1287 -- simplify every definition do give the totality checker
1289 mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
1290 updateContext (simplifyCasedef n $ getErasureInfo i))
1291 (map snd (idris_totcheck i))
1292 -- build size change graph from simplified definitions
1293 iLOG "Totality checking"
1295 mapM_ buildSCG (idris_totcheck i)
1296 mapM_ checkDeclTotality (idris_totcheck i)
1298 -- Redo totality check for deferred names
1299 let deftots = idris_defertotcheck i
1300 iLOG $ "Totality checking " ++ show deftots
1301 mapM_ (\x -> do tot <- getTotality x
1303 Total _ -> setTotality x Unchecked
1304 _ -> return ()) (map snd deftots)
1305 mapM_ buildSCG deftots
1306 mapM_ checkDeclTotality deftots
1308 iLOG ("Finished " ++ f)
1309 ibcsd <- valIBCSubDir i
1310 iLOG "Universe checking"
1312 let ibc = ibcPathNoFallback ibcsd f
1314 addHides (hide_list i)
1316 -- Finally, write an ibc if checking was successful
1319 idrisCatch (do writeIBC f ibc; clearIBC)
1320 (\c -> return ()) -- failure is harmless
1322 putIState (i { default_total = def_total,
1326 namespaces :: [String] -> [PDecl] -> [PDecl]
1327 namespaces [] ds = ds
1328 namespaces (x:xs) ds = [PNamespace x (namespaces xs ds)]
1330 toMutual :: PDecl -> PDecl
1331 toMutual m@(PMutual _ d) = m
1332 toMutual (PNamespace x ds) = PNamespace x (map toMutual ds)
1333 toMutual x = let r = PMutual (fileFC "single mutual") [x] in
1335 PClauses _ _ _ _ -> r
1336 PClass _ _ _ _ _ _ _ _ -> r
1337 PInstance _ _ _ _ _ _ _ _ -> r
1340{- | Adds names to hide list -}
1341addHides :: [(Name, Maybe Accessibility)] -> Idris ()
1342addHides xs = do i <- getIState
1343 let defh = default_access i
1344 let (hs, as) = partition isNothing xs
1347 (map (\ (n, _) -> (n, defh)) hs ++
1348 map (\ (n, Just a) -> (n, a)) as)
1349 where isNothing (_, Nothing) = True
1352 doHide (n, a) = do setAccessibility n a
1353 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