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)
24import Idris.Delaborate
27import Idris.ElabTerm hiding (namespace, params)
33import Idris.ParseHelpers
40import Util.DynamicLinker
41import qualified Util.Pretty as P
44import Idris.Core.Evaluate
46import Control.Applicative
48import Control.Monad.Error (throwError, catchError)
49import Control.Monad.State.Strict
53import qualified Data.List.Split as Spl
58import qualified Data.Map as M
59import qualified Data.HashSet as HS
60import qualified Data.Text as T
61import qualified Data.ByteString.UTF8 as UTF8
62import qualified Data.Set as S
71 grammar shortcut notation:
72 ~CHARSEQ = complement of char sequence (i.e. any character except CHARSEQ)
73 RULE? = optional rule (i.e. RULE or nothing)
74 RULE* = repeated rule (i.e. RULE zero or more times)
75 RULE+ = repeated rule with at least one match (i.e. RULE one or more times)
76 RULE! = invalid rule (i.e. rule that is not valid in context, report meaningful error in case)
77 RULE{n} = rule repeated n times
83{- | Parses module definition
86 ModuleHeader ::= 'module' Identifier_t ';'?;
89moduleHeader :: IdrisParser [String]
90moduleHeader = try (do reserved "module"
92 option ';' (lchar ';')
93 return (moduleName i))
94 <|> try (do lchar '%'; reserved "unqualified"
96 <|> return (moduleName "Main")
97 where moduleName x = case span (/='.') x of
99 (x, '.':y) -> x : moduleName y
101{- | Parses an import statement
104 Import ::= 'import' Identifier_t ';'?;
107import_ :: IdrisParser (String, Maybe String, FC)
108import_ = do fc <- getFC
111 newName <- optional (reserved "as" *> identifier)
112 option ';' (lchar ';')
113 return (toPath id, toPath <$> newName, fc)
114 <?> "import statement"
115 where toPath = foldl1' (</>) . Spl.splitOn "."
117{- | Parses program source
123prog :: SyntaxInfo -> IdrisParser [PDecl]
124prog syn = do whiteSpace
125 decls <- many (decl syn)
128 let c = (concat decls)
131{-| Parses a top-level declaration
150decl :: SyntaxInfo -> IdrisParser [PDecl]
151decl syn = do notEndBlock
153 where declBody :: IdrisParser [PDecl]
161 <|> do d <- dsl syn; return [d]
165 <|> do import_; fail "imports must be at top of file"
167 declBody' :: IdrisParser [PDecl]
168 declBody' = do d <- decl' syn
170 let d' = fmap (debindApp syn . (desugar syn i)) d
173{- | Parses a top-level declaration with possible syntax sugar
185decl' :: SyntaxInfo -> IdrisParser PDecl
193{- | Parses a syntax extension declaration (and adds the rule to parser state)
196 SyntaxDecl ::= SyntaxRule;
199syntaxDecl :: SyntaxInfo -> IdrisParser PDecl
200syntaxDecl syn = do s <- syntaxRule syn
202 let rs = syntax_rules i
203 let ns = syntax_keywords i
204 let ibc = ibc_write i
205 let ks = map show (names s)
206 put (i { syntax_rules = s : rs,
207 syntax_keywords = ks ++ ns,
208 ibc_write = IBCSyntax s : map IBCKeyword ks ++ ibc })
210 return (PSyntax fc s)
211 where names (Rule syms _ _) = mapMaybe ename syms
212 ename (Keyword n) = Just n
215{- | Parses a syntax extension declaration
218SyntaxRuleOpts ::= 'term' | 'pattern';
223 SyntaxRuleOpts? 'syntax' SyntaxSym+ '=' TypeExpr Terminator;
227SyntaxSym ::= '[' Name_t ']'
234syntaxRule :: SyntaxInfo -> IdrisParser Syntax
238 sty <- option AnySyntax (do reserved "term"; return TermSyntax
239 <|> do reserved "pattern"; return PatternSyntax)
242 syms <- some syntaxSym
243 when (all isExpr syms) $ unexpected "missing keywords in syntax rule"
244 let ns = mapMaybe getName syms
245 when (length ns /= length (nub ns))
246 $ unexpected "repeated variable in syntax rule"
248 tm <- typeExpr (allowImp syn)
250 return (Rule (mkSimple syms) tm sty)
252 isExpr (Expr _) = True
254 getName (Expr n) = Just n
256 -- Can't parse two full expressions (i.e. expressions with application) in a row
257 -- so change them both to a simple expression
258 mkSimple (Expr e : es) = SimpleExpr e : mkSimple' es
259 mkSimple xs = mkSimple' xs
261 mkSimple' (Expr e : Expr e1 : es) = SimpleExpr e : SimpleExpr e1 :
263 mkSimple' (e : es) = e : mkSimple' es
267{- | Parses a syntax symbol (either binding variable, keyword or expression)
270SyntaxSym ::= '[' Name_t ']'
277syntaxSym :: IdrisParser SSymbol
278syntaxSym = try (do lchar '['; n <- name; lchar ']'
280 <|> try (do lchar '{'; n <- name; lchar '}'
284 <|> do sym <- stringLiteral
288{- | Parses a function declaration with possible syntax sugar
291 FunDecl ::= FunDecl';
294fnDecl :: SyntaxInfo -> IdrisParser [PDecl]
295fnDecl syn = try (do notEndBlock
298 let d' = fmap (desugar syn i) d
299 return [d']) <?> "function declaration"
301{-| Parses a function declaration
305 DocComment_t? FnOpts* Accessibility? FnOpts* FnName TypeSig Terminator
312fnDecl' :: SyntaxInfo -> IdrisParser PDecl
313fnDecl' syn = checkFixity $
314 do (doc, fc, opts', n, acc) <- try (do
315 doc <- option "" (docComment '|')
318 let initOpts = if default_total ist
321 opts <- fnOpts initOpts
322 acc <- optional accessibility
325 let n = expandNS syn n_in
328 return (doc, fc, opts', n, acc))
329 ty <- typeExpr (allowImp syn)
332 return (PTy doc syn fc opts' n ty)
336 <?> "function declaration"
337 where checkFixity :: IdrisParser PDecl -> IdrisParser PDecl
338 checkFixity p = do decl <- p
340 Nothing -> return decl
341 Just n -> do fOk <- fixityOK n
343 "Missing fixity declaration for " ++ show n
345 getName (PTy _ _ _ _ n _) = Just n
347 fixityOK (NS n _) = fixityOK n
348 fixityOK (UN n) | all (flip elem opChars) (str n) =
349 do fixities <- fmap idris_infixes get
350 return . elem (str n) . map (\ (Fix _ op) -> op) $ fixities
351 | otherwise = return True
352 fixityOK _ = return True
354{-| Parses function options given initial options
361 | '%' 'error_handler'
363 | '%' 'specialise' '[' NameTimesList? ']'
368NameTimes ::= FnName Natural?;
374 | NameTimes ',' NameTimesList
378-- FIXME: Check compatability for function options (i.e. partal/total)
379fnOpts :: [FnOpt] -> IdrisParser [FnOpt]
381 = do reserved "total"; fnOpts (TotalFn : opts)
382 <|> do reserved "partial"; fnOpts (PartialFn : (opts \\ [TotalFn]))
383 <|> do try (lchar '%' *> reserved "export"); c <- stringLiteral;
384 fnOpts (CExport c : opts)
385 <|> do try (lchar '%' *> reserved "assert_total");
386 fnOpts (AssertTotal : opts)
387 <|> do try (lchar '%' *> reserved "error_handler");
388 fnOpts (ErrorHandler : opts)
389 <|> do try (lchar '%' *> reserved "error_reverse");
390 fnOpts (ErrorReverse : opts)
391 <|> do try (lchar '%' *> reserved "reflection");
392 fnOpts (Reflection : opts)
393 <|> do lchar '%'; reserved "specialise";
394 lchar '['; ns <- sepBy nameTimes (lchar ','); lchar ']'
395 fnOpts (Specialise ns : opts)
396 <|> do reserved "implicit"; fnOpts (Implicit : opts)
398 <?> "function modifier"
399 where nameTimes :: IdrisParser (Name, Maybe Int)
400 nameTimes = do n <- fnName
401 t <- option Nothing (do reds <- natural
402 return (Just (fromInteger reds)))
405{- | Parses a postulate
409 DocComment_t? 'postulate' FnOpts* Accesibility? FnOpts* FnName TypeSig Terminator
413postulate :: SyntaxInfo -> IdrisParser PDecl
414postulate syn = do doc <- try $ do doc <- option "" (docComment '|')
419 let initOpts = if default_total ist
422 opts <- fnOpts initOpts
423 acc <- optional accessibility
426 let n = expandNS syn n_in
428 ty <- typeExpr (allowImp syn)
432 return (PPostulate doc syn fc opts' n ty)
435{- | Parses a using declaration
439 'using' '(' UsingDeclList ')' OpenBlock Decl* CloseBlock
443using_ :: SyntaxInfo -> IdrisParser [PDecl]
445 do reserved "using"; lchar '('; ns <- usingDeclList syn; lchar ')'
447 let uvars = using syn
448 ds <- many (decl (syn { using = uvars ++ ns }))
451 <?> "using declaration"
453{- | Parses a parameters declaration
457 'parameters' '(' TypeDeclList ')' OpenBlock Decl* CloseBlock
461params :: SyntaxInfo -> IdrisParser [PDecl]
463 do reserved "parameters"; lchar '('; ns <- typeDeclList syn; lchar ')'
465 let pvars = syn_params syn
466 ds <- many (decl syn { syn_params = pvars ++ ns })
469 return [PParams fc ns (concat ds)]
470 <?> "parameters declaration"
472{- | Parses a mutual declaration (for mutually recursive functions)
476 'mutual' OpenBlock Decl* CloseBlock
480mutual :: SyntaxInfo -> IdrisParser [PDecl]
484 let pvars = syn_params syn
485 ds <- many (decl syn)
488 return [PMutual fc (concat ds)]
491{-| Parses a namespace declaration
495 'namespace' identifier OpenBlock Decl+ CloseBlock
499namespace :: SyntaxInfo -> IdrisParser [PDecl]
501 do reserved "namespace"; n <- identifier;
503 ds <- some (decl syn { syn_namespace = n : syn_namespace syn })
505 return [PNamespace n (concat ds)]
506 <?> "namespace declaration"
508{- | Parses a methods block (for instances)
511 InstanceBlock ::= 'where' OpenBlock FnDecl* CloseBlock
514instanceBlock :: SyntaxInfo -> IdrisParser [PDecl]
515instanceBlock syn = do reserved "where"
517 ds <- many (fnDecl syn)
522{- | Parses a methods and instances block (for type classes)
533 'where' OpenBlock MethodOrInstance* CloseBlock
537classBlock :: SyntaxInfo -> IdrisParser [PDecl]
538classBlock syn = do reserved "where"
540 ds <- many ((notEndBlock >> instance_ syn) <|> fnDecl syn)
545{-| Parses a type class declaration
550 | '(' Name ':' Expr ')'
556 DocComment_t? Accessibility? 'class' ConstraintList? Name ClassArgument* ClassBlock?
560class_ :: SyntaxInfo -> IdrisParser [PDecl]
561class_ syn = do (doc, acc) <- try (do
562 doc <- option "" (docComment '|')
563 acc <- optional accessibility
565 reserved "class"; fc <- getFC; cons <- constraintList syn; n_in <- fnName
566 let n = expandNS syn n_in
568 ds <- option [] (classBlock syn)
569 accData acc n (concatMap declared ds)
570 return [PClass doc syn fc cons n cs ds]
571 <?> "type-class declaration"
573 carg :: IdrisParser (Name, PTerm)
574 carg = do lchar '('; i <- name; lchar ':'; ty <- expr syn; lchar ')'
579{- | Parses a type class instance declaration
583 'instance' InstanceName? ConstraintList? Name SimpleExpr* InstanceBlock?
588InstanceName ::= '[' Name ']';
591instance_ :: SyntaxInfo -> IdrisParser [PDecl]
592instance_ syn = do reserved "instance"; fc <- getFC
593 en <- optional instanceName
594 cs <- constraintList syn
596 args <- many (simpleExpr syn)
597 let sc = PApp fc (PRef fc cn) (map pexp args)
598 let t = bindList (PPi constraint) (map (\x -> (sMN 0 "constraint", x)) cs) sc
599 ds <- option [] (instanceBlock syn)
600 return [PInstance syn fc cs cn args t en ds]
601 <?> "instance declaration"
602 where instanceName :: IdrisParser Name
603 instanceName = do lchar '['; n_in <- fnName; lchar ']'
604 let n = expandNS syn n_in
609{- | Parses a using declaration list
621 | UsingDecl ',' UsingDeclList'
632usingDeclList :: SyntaxInfo -> IdrisParser [Using]
634 = try (sepBy1 (usingDecl syn) (lchar ','))
635 <|> do ns <- sepBy1 name (lchar ',')
637 t <- typeExpr (disallowImp syn)
638 return (map (\x -> UImplicit x t) ns)
639 <?> "using declaration list"
641{- |Parses a using declaration
650usingDecl :: SyntaxInfo -> IdrisParser Using
651usingDecl syn = try (do x <- fnName
653 t <- typeExpr (disallowImp syn)
654 return (UImplicit x t))
657 return (UConstraint c xs)
658 <?> "using declaration"
660{- | Parse a clause with patterns
666pattern :: SyntaxInfo -> IdrisParser PDecl
667pattern syn = do fc <- getFC
669 return (PClauses fc [] (sMN 2 "_") [clause]) -- collect together later
672{- | Parse a constant applicative form declaration
675CAF ::= 'let' FnName '=' Expr Terminator;
678caf :: SyntaxInfo -> IdrisParser PDecl
679caf syn = do reserved "let"
680 n_in <- fnName; let n = expandNS syn n_in
686 <?> "constant applicative form declaration"
688{- | Parse an argument expression
691ArgExpr ::= HSimpleExpr | {- In Pattern External (User-defined) Expression -};
694argExpr :: SyntaxInfo -> IdrisParser PTerm
695argExpr syn = let syn' = syn { inPattern = True } in
696 try (hsimpleExpr syn') <|> simpleExternalExpr syn'
697 <?> "argument expression"
699{- | Parse a right hand side of a function
709RHSName ::= '{' FnName '}';
712rhs :: SyntaxInfo -> Name -> IdrisParser PTerm
713rhs syn n = do lchar '='; expr syn
715 name <- option n' (do symbol "{"; n <- fnName; symbol "}";
718 return (addLet name r)
719 <|> do reserved "impossible"; return PImpossible
720 <?> "function right hand side"
721 where mkN :: Name -> Name
722 mkN (UN x) = sUN (str x++"_lemma_1")
723 mkN (NS x n) = NS (mkN x) n
726 addLet :: Name -> PTerm -> PTerm
727 addLet nm (PLet n ty val r) = PLet n ty val (addLet nm r)
728 addLet nm (PCase fc t cs) = PCase fc t (map addLetC cs)
729 where addLetC (l, r) = (l, addLet nm r)
730 addLet nm r = (PLet (sUN "value") Placeholder r (PMetavar nm))
732{- |Parses a function clause
735RHSOrWithBlock ::= RHS WhereOrTerminator
736 | 'with' SimpleExpr OpenBlock FnDecl+ CloseBlock
741Clause ::= WExpr+ RHSOrWithBlock
742 | SimpleExpr '<==' FnName RHS WhereOrTerminator
743 | ArgExpr Operator ArgExpr WExpr* RHSOrWithBlock {- Except "=" and "?=" operators to avoid ambiguity -}
744 | FnName ConstraintArg* ImplicitOrArgExpr* WExpr* RHSOrWithBlock
749ImplicitOrArgExpr ::= ImplicitArg | ArgExpr;
753WhereOrTerminator ::= WhereBlock | Terminator;
756clause :: SyntaxInfo -> IdrisParser PClause
758 = do wargs <- try (do pushIndent; some (wExpr syn))
761 n <- case lastParse ist of
763 Nothing -> fail "Invalid clause"
765 let ctxt = tt_ctxt ist
766 let wsyn = syn { syn_namespace = [] }
767 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
772 return $ PClauseR fc wargs r wheres) <|> (do
775 wval <- simpleExpr syn
777 ds <- some $ fnDecl syn
778 let withs = concat ds
780 return $ PWithR fc wargs wval withs)
781 <|> do ty <- try (do pushIndent
786 n_in <- fnName; let n = expandNS syn n_in
789 let ctxt = tt_ctxt ist
790 let wsyn = syn { syn_namespace = [] }
791 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
796 let capp = PLet (sMN 0 "match")
799 (PRef fc (sMN 0 "match"))
801 put (ist { lastParse = Just n })
802 return $ PClause fc n capp [] r wheres
803 <|> do (l, op) <- try (do
807 when (op == "=" || op == "?=" ) $
808 fail "infix clause definition with \"=\" and \"?=\" not supported "
810 let n = expandNS syn (sUN op)
813 wargs <- many (wExpr syn)
815 let wsyn = syn { syn_namespace = [] }
816 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
822 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
823 put (ist { lastParse = Just n })
824 return $ PClause fc n capp wargs rs wheres) <|> (do
827 lchar '(' <?> "parenthesized expression"
828 wval <- bracketed syn
830 ds <- some $ fnDecl syn
833 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
834 let withs = map (fillLHSD n capp wargs) $ concat ds
835 put (ist { lastParse = Just n })
836 return $ PWith fc n capp wargs wval withs)
838 n_in <- fnName; let n = expandNS syn n_in
839 cargs <- many (constraintArg syn)
841 args <- many (try (implicitArg (syn { inPattern = True } ))
842 <|> (fmap pexp (argExpr syn)))
843 wargs <- many (wExpr syn)
844 let capp = PApp fc (PRef fc n)
848 let ctxt = tt_ctxt ist
849 let wsyn = syn { syn_namespace = [] }
850 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
856 put (ist { lastParse = Just n })
857 return $ PClause fc n capp wargs r wheres) <|> (do
860 put (ist { lastParse = Just n })
861 lchar '(' <?> "parenthesized expression"
862 wval <- bracketed syn
864 ds <- some $ fnDecl syn
865 let withs = map (fillLHSD n capp wargs) $ concat ds
868 return $ PWith fc n capp wargs wval withs)
869 <?> "function clause"
871 fillLHS :: Name -> PTerm -> [PTerm] -> PClause -> PClause
872 fillLHS n capp owargs (PClauseR fc wargs v ws)
873 = PClause fc n capp (owargs ++ wargs) v ws
874 fillLHS n capp owargs (PWithR fc wargs v ws)
875 = PWith fc n capp (owargs ++ wargs) v
876 (map (fillLHSD n capp (owargs ++ wargs)) ws)
879 fillLHSD :: Name -> PTerm -> [PTerm] -> PDecl -> PDecl
880 fillLHSD n c a (PClauses fc o fn cs) = PClauses fc o fn (map (fillLHS n c a) cs)
883{-| Parses with pattern
889wExpr :: SyntaxInfo -> IdrisParser PTerm
890wExpr syn = do lchar '|'
894{- | Parses a where block
897WhereBlock ::= 'where' OpenBlock Decl+ CloseBlock;
900whereBlock :: Name -> SyntaxInfo -> IdrisParser ([PDecl], [(Name, Name)])
902 = do reserved "where"
903 ds <- indentedBlock1 (decl syn)
904 let dns = concatMap (concatMap declared) ds
905 return (concat ds, map (\x -> (x, decoration syn x)) dns)
908{- |Parses a code generation target language name
920codegen_ :: IdrisParser Codegen
921codegen_ = do reserved "C"; return ViaC
922 <|> do reserved "Java"; return ViaJava
923 <|> do reserved "JavaScript"; return ViaJavaScript
924 <|> do reserved "Node"; return ViaNode
925 <|> do reserved "LLVM"; return ViaLLVM
926 <|> do reserved "Bytecode"; return Bytecode
927 <?> "code generation language"
929{- |Parses a compiler directive
933 | String ',' StringList
938Directive ::= '%' Directive';
942Directive' ::= 'lib' CodeGen String_t
943 | 'link' CodeGen String_t
944 | 'flag' CodeGen String_t
945 | 'include' CodeGen String_t
948 | 'access' Accessibility
951 | 'dynamic' StringList
952 | 'name' Name NameList
953 | 'error_handlers' Name NameList
954 | 'language' 'TypeProviders'
955 | 'language' 'ErrorReflection'
959directive :: SyntaxInfo -> IdrisParser [PDecl]
960directive syn = do try (lchar '%' *> reserved "lib"); cgn <- codegen_; lib <- stringLiteral;
961 return [PDirective (do addLib cgn lib
962 addIBC (IBCLib cgn lib))]
963 <|> do try (lchar '%' *> reserved "link"); cgn <- codegen_; obj <- stringLiteral;
964 return [PDirective (do dirs <- allImportDirs
965 o <- liftIO $ findInPath dirs obj
966 addIBC (IBCObj cgn obj) -- just name, search on loading ibc
967 addObjectFile cgn o)]
968 <|> do try (lchar '%' *> reserved "flag"); cgn <- codegen_;
969 flag <- stringLiteral
970 return [PDirective (do addIBC (IBCCGFlag cgn flag)
972 <|> do try (lchar '%' *> reserved "include"); cgn <- codegen_; hdr <- stringLiteral;
973 return [PDirective (do addHdr cgn hdr
974 addIBC (IBCHeader cgn hdr))]
975 <|> do try (lchar '%' *> reserved "hide"); n <- fnName
976 return [PDirective (do setAccessibility n Hidden
977 addIBC (IBCAccess n Hidden))]
978 <|> do try (lchar '%' *> reserved "freeze"); n <- iName []
979 return [PDirective (do setAccessibility n Frozen
980 addIBC (IBCAccess n Frozen))]
981 <|> do try (lchar '%' *> reserved "access"); acc <- accessibility
982 return [PDirective (do i <- get
983 put(i { default_access = acc }))]
984 <|> do try (lchar '%' *> reserved "default"); tot <- totality
986 put (i { default_total = tot } )
987 return [PDirective (do i <- get
988 put(i { default_total = tot }))]
989 <|> do try (lchar '%' *> reserved "logging"); i <- natural;
990 return [PDirective (setLogLevel (fromInteger i))]
991 <|> do try (lchar '%' *> reserved "dynamic"); libs <- sepBy1 stringLiteral (lchar ',');
992 return [PDirective (do added <- addDyLib libs
994 Left lib -> addIBC (IBCDyLib (lib_name lib))
997 <|> do try (lchar '%' *> reserved "name")
999 ns <- sepBy1 name (lchar ',')
1000 return [PDirective (do ty' <- disambiguate ty
1001 mapM_ (addNameHint ty') ns
1002 mapM_ (\n -> addIBC (IBCNameHint (ty', n))) ns)]
1003 <|> do try (lchar '%' *> reserved "error_handlers")
1006 ns <- sepBy1 name (lchar ',')
1007 return [PDirective (do fn' <- disambiguate fn
1008 ns' <- mapM disambiguate ns
1009 addFunctionErrorHandlers fn' arg ns'
1010 mapM_ (addIBC . IBCFunctionErrorHandler fn' arg) ns')]
1011 <|> do try (lchar '%' *> reserved "language"); ext <- pLangExt;
1012 return [PDirective (addLangExt ext)]
1014 where disambiguate :: Name -> Idris Name
1015 disambiguate n = do i <- getIState
1016 case lookupCtxtName n (idris_implicits i) of
1017 [(n', _)] -> return n'
1018 [] -> throwError (NoSuchVariable n)
1019 more -> throwError (CantResolveAlts (map (show . fst) more))
1021pLangExt :: IdrisParser LanguageExt
1022pLangExt = (reserved "TypeProviders" >> return TypeProviders)
1023 <|> (reserved "ErrorReflection" >> return ErrorReflection)
1025{- | Parses a totality
1028Totality ::= 'partial' | 'total'
1032totality :: IdrisParser Bool
1034 = do reserved "total"; return True
1035 <|> do reserved "partial"; return False
1037{- | Parses a type provider
1040Provider ::= '%' 'provide' '(' FnName TypeSig ')' 'with' Expr;
1043provider :: SyntaxInfo -> IdrisParser [PDecl]
1044provider syn = do try (lchar '%' *> reserved "provide");
1045 lchar '('; n <- fnName; lchar ':'; t <- typeExpr syn; lchar ')'
1049 return [PProvider syn fc n t e]
1052{- | Parses a transform
1055Transform ::= '%' 'transform' Expr '==>' Expr
1058transform :: SyntaxInfo -> IdrisParser [PDecl]
1059transform syn = do try (lchar '%' *> reserved "transform")
1060 -- leave it unchecked, until we work out what this should
1062-- safety <- option True (do reserved "unsafe"
1068 return [PTransform fc False l r]
1072{- * Loading and parsing -}
1073{- | Parses an expression from input -}
1074parseExpr :: IState -> String -> Result PTerm
1075parseExpr st = runparser (fullExpr defaultSyntax) st "(input)"
1077{- | Parses a tactic from input -}
1078parseTactic :: IState -> String -> Result PTactic
1079parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
1081-- | Parse module header and imports
1082parseImports :: FilePath -> String -> Idris ([String], [(String, Maybe String, FC)], Maybe Delta)
1083parseImports fname input
1085 case parseString (runInnerParser (evalStateT imports i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
1086 Failure err -> fail (show err)
1087 Success (x, i) -> do -- Discard state updates (there should be
1090 where imports :: IdrisParser (([String], [(String, Maybe String, FC)], Maybe Delta), IState)
1091 imports = do whiteSpace
1092 mname <- moduleHeader
1095 isEof <- lookAheadMatches eof
1100 return ((mname, ps, mrk'), i)
1102-- | There should be a better way of doing this...
1103findFC :: Doc -> (FC, String)
1104findFC x = let s = show (plain x) in
1105 case span (/= ':') s of
1106 (failname, ':':rest) -> case span isDigit rest of
1107 (line, ':':rest') -> case span isDigit rest' of
1108 (col, ':':msg) -> (FC failname (read line) (read col), msg)
1110-- | A program is a list of declarations, possibly with associated
1111-- documentation strings.
1112parseProg :: SyntaxInfo -> FilePath -> String -> Maybe Delta ->
1114parseProg syn fname input mrk
1116 case runparser mainProg i fname input of
1117 Failure doc -> do -- FIXME: Get error location from trifecta
1118 -- this can't be the solution!
1119 let (fc, msg) = findFC doc
1121 case idris_outputmode i of
1122 RawOutput -> ihputStrLn (idris_outh i) (show doc)
1123 IdeSlave n -> ihWarn (idris_outh i) fc (P.text msg)
1124 putIState (i { errLine = Just (fc_line fc) }) -- Just errl })
1126 Success (x, i) -> do putIState i
1128 where mainProg :: IdrisParser ([PDecl], IState)
1129 mainProg = case mrk of
1130 Nothing -> do i <- get; return ([], i)
1137{- | Load idris module and show error if something wrong happens -}
1138loadModule :: Handle -> FilePath -> Idris String
1140 = idrisCatch (loadModule' outh f)
1141 (\e -> do setErrLine (getErrLine e)
1147{- | Load idris module -}
1148loadModule' :: Handle -> FilePath -> Idris String
1151 let file = takeWhile (/= ' ') f
1152 ibcsd <- valIBCSubDir i
1153 ids <- allImportDirs
1154 fp <- liftIO $ findImport ids ibcsd file
1155 if file `elem` imported i
1156 then iLOG $ "Already read " ++ file
1157 else do putIState (i { imported = file : imported i })
1159 IDR fn -> loadSource outh False fn
1160 LIDR fn -> loadSource outh True fn
1162 idrisCatch (loadIBC fn)
1163 (\c -> do iLOG $ fn ++ " failed " ++ pshow i c
1165 IDR sfn -> loadSource outh False sfn
1166 LIDR sfn -> loadSource outh True sfn)
1167 let (dir, fh) = splitFileName file
1168 return (dropExtension fh)
1171{- | Load idris code from file -}
1172loadFromIFile :: Handle -> IFileType -> Idris ()
1173loadFromIFile h i@(IBC fn src)
1174 = do iLOG $ "Skipping " ++ getSrcFile i
1175 idrisCatch (loadIBC fn)
1176 (\err -> ierror $ LoadingFailed fn err)
1178 getSrcFile (IDR fn) = fn
1179 getSrcFile (LIDR fn) = fn
1180 getSrcFile (IBC f src) = getSrcFile src
1182loadFromIFile h (IDR fn) = loadSource' h False fn
1183loadFromIFile h (LIDR fn) = loadSource' h True fn
1185{-| Load idris source code and show error if something wrong happens -}
1186loadSource' :: Handle -> Bool -> FilePath -> Idris ()
1188 = idrisCatch (loadSource h lidr r)
1189 (\e -> do setErrLine (getErrLine e)
1191 ihRenderError h (pprintErr ist e))
1193{- | Load Idris source code-}
1194loadSource :: Handle -> Bool -> FilePath -> Idris ()
1196 = do iLOG ("Reading " ++ f)
1198 let def_total = default_total i
1199 file_in <- runIO $ readFile f
1200 file <- if lidr then tclift $ unlit f file_in else return file_in
1201 (mname, imports, pos) <- parseImports f file
1203 -- process and check module aliases
1204 let modAliases = M.fromList
1205 [(prep alias, prep realName) | (realName, Just alias, fc) <- imports]
1206 prep = map T.pack . reverse . Spl.splitOn "/"
1207 aliasNames = [(alias, fc) | (_, Just alias, fc) <- imports]
1208 histogram = groupBy ((==) `on` fst) . sortBy (comparing fst) $ aliasNames
1209 case map head . filter ((/= 1) . length) $ histogram of
1210 [] -> logLvl 3 $ "Module aliases: " ++ show (M.toList modAliases)
1211 (n,fc):_ -> throwError . At fc . Msg $ "import alias not unique: " ++ show n
1214 putIState (i { default_access = Hidden, module_aliases = modAliases })
1215 clearIBC -- start a new .ibc file
1216 mapM_ (addIBC . IBCImport) [realName | (realName, alias, fc) <- imports]
1217 let syntax = defaultSyntax{ syn_namespace = reverse mname }
1218 ds' <- parseProg syntax f file pos
1219 unless (null ds') $ do
1220 let ds = namespaces mname ds'
1221 logLvl 3 (show $ showDecls True ds)
1223 logLvl 10 (show (toAlist (idris_implicits i)))
1224 logLvl 3 (show (idris_infixes i))
1225 -- Now add all the declarations to the context
1227 when v $ ihputStrLn h $ "Type checking " ++ f
1228 -- we totality check after every Mutual block, so if
1229 -- anything is a single definition, wrap it in a
1230 -- mutual block on its own
1231 elabDecls toplevel (map toMutual ds)
1233 -- simplify every definition do give the totality checker
1235 mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
1236 updateContext (simplifyCasedef n))
1237 (map snd (idris_totcheck i))
1238 -- build size change graph from simplified definitions
1239 iLOG "Totality checking"
1241 mapM_ buildSCG (idris_totcheck i)
1242 mapM_ checkDeclTotality (idris_totcheck i)
1244 -- Redo totality check for deferred names
1245 let deftots = idris_defertotcheck i
1246 iLOG $ "Totality checking " ++ show deftots
1247 mapM_ (\x -> do tot <- getTotality x
1249 Total _ -> setTotality x Unchecked
1250 _ -> return ()) (map snd deftots)
1251 mapM_ buildSCG deftots
1252 mapM_ checkDeclTotality deftots
1254 iLOG ("Finished " ++ f)
1255 ibcsd <- valIBCSubDir i
1256 iLOG "Universe checking"
1258 let ibc = ibcPathNoFallback ibcsd f
1260 addHides (hide_list i)
1263 idrisCatch (do writeIBC f ibc; clearIBC)
1264 (\c -> return ()) -- failure is harmless
1266 putIState (i { default_total = def_total,
1271 namespaces :: [String] -> [PDecl] -> [PDecl]
1272 namespaces [] ds = ds
1273 namespaces (x:xs) ds = [PNamespace x (namespaces xs ds)]
1275 toMutual :: PDecl -> PDecl
1276 toMutual m@(PMutual _ d) = m
1277 toMutual (PNamespace x ds) = PNamespace x (map toMutual ds)
1278 toMutual x = let r = PMutual (fileFC "single mutual") [x] in
1280 PClauses _ _ _ _ -> r
1281 PClass _ _ _ _ _ _ _ -> r
1282 PInstance _ _ _ _ _ _ _ _ -> r
1285{- | Adds names to hide list -}
1286addHides :: [(Name, Maybe Accessibility)] -> Idris ()
1287addHides xs = do i <- getIState
1288 let defh = default_access i
1289 let (hs, as) = partition isNothing xs
1292 (map (\ (n, _) -> (n, defh)) hs ++
1293 map (\ (n, Just a) -> (n, a)) as)
1294 where isNothing (_, Nothing) = True
1297 doHide (n, a) = do setAccessibility n a
1298 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