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
380 | '%' 'error_handler'
382 | '%' 'specialise' '[' NameTimesList? ']'
387NameTimes ::= FnName Natural?;
393 | NameTimes ',' NameTimesList
397-- FIXME: Check compatability for function options (i.e. partal/total)
398fnOpts :: [FnOpt] -> IdrisParser [FnOpt]
400 = do reserved "total"; fnOpts (TotalFn : opts)
401 <|> do reserved "partial"; fnOpts (PartialFn : (opts \\ [TotalFn]))
402 <|> do reserved "covering"; fnOpts (CoveringFn : (opts \\ [TotalFn]))
403 <|> do try (lchar '%' *> reserved "export"); c <- stringLiteral;
404 fnOpts (CExport c : opts)
405 <|> do try (lchar '%' *> reserved "assert_total");
406 fnOpts (AssertTotal : opts)
407 <|> do try (lchar '%' *> reserved "error_handler");
408 fnOpts (ErrorHandler : opts)
409 <|> do try (lchar '%' *> reserved "error_reverse");
410 fnOpts (ErrorReverse : opts)
411 <|> do try (lchar '%' *> reserved "reflection");
412 fnOpts (Reflection : opts)
413 <|> do lchar '%'; reserved "specialise";
414 lchar '['; ns <- sepBy nameTimes (lchar ','); lchar ']'
415 fnOpts (Specialise ns : opts)
416 <|> do reserved "implicit"; fnOpts (Implicit : opts)
418 <?> "function modifier"
419 where nameTimes :: IdrisParser (Name, Maybe Int)
420 nameTimes = do n <- fnName
421 t <- option Nothing (do reds <- natural
422 return (Just (fromInteger reds)))
425{- | Parses a postulate
429 DocComment_t? 'postulate' FnOpts* Accesibility? FnOpts* FnName TypeSig Terminator
433postulate :: SyntaxInfo -> IdrisParser PDecl
434postulate syn = do doc <- try $ do doc <- option noDocs docComment
439 let initOpts = if default_total ist
442 opts <- fnOpts initOpts
443 acc <- optional accessibility
446 let n = expandNS syn n_in
448 ty <- typeExpr (allowImp syn)
452 return (PPostulate (fst doc) syn fc opts' n ty)
455{- | Parses a using declaration
459 'using' '(' UsingDeclList ')' OpenBlock Decl* CloseBlock
463using_ :: SyntaxInfo -> IdrisParser [PDecl]
465 do reserved "using"; lchar '('; ns <- usingDeclList syn; lchar ')'
467 let uvars = using syn
468 ds <- many (decl (syn { using = uvars ++ ns }))
471 <?> "using declaration"
473{- | Parses a parameters declaration
477 'parameters' '(' TypeDeclList ')' OpenBlock Decl* CloseBlock
481params :: SyntaxInfo -> IdrisParser [PDecl]
483 do reserved "parameters"; lchar '('; ns <- typeDeclList syn; lchar ')'
485 let pvars = syn_params syn
486 ds <- many (decl syn { syn_params = pvars ++ ns })
489 return [PParams fc ns (concat ds)]
490 <?> "parameters declaration"
492{- | Parses a mutual declaration (for mutually recursive functions)
496 'mutual' OpenBlock Decl* CloseBlock
500mutual :: SyntaxInfo -> IdrisParser [PDecl]
504 let pvars = syn_params syn
505 ds <- many (decl (syn { mut_nesting = mut_nesting syn + 1 } ))
508 return [PMutual fc (concat ds)]
511{-| Parses a namespace declaration
515 'namespace' identifier OpenBlock Decl+ CloseBlock
519namespace :: SyntaxInfo -> IdrisParser [PDecl]
521 do reserved "namespace"; n <- identifier;
523 ds <- some (decl syn { syn_namespace = n : syn_namespace syn })
525 return [PNamespace n (concat ds)]
526 <?> "namespace declaration"
528{- | Parses a methods block (for instances)
531 InstanceBlock ::= 'where' OpenBlock FnDecl* CloseBlock
534instanceBlock :: SyntaxInfo -> IdrisParser [PDecl]
535instanceBlock syn = do reserved "where"
537 ds <- many (fnDecl syn)
542{- | Parses a methods and instances block (for type classes)
553 'where' OpenBlock MethodOrInstance* CloseBlock
557classBlock :: SyntaxInfo -> IdrisParser [PDecl]
558classBlock syn = do reserved "where"
560 ds <- many ((notEndBlock >> instance_ syn) <|> fnDecl syn)
565{-| Parses a type class declaration
570 | '(' Name ':' Expr ')'
576 DocComment_t? Accessibility? 'class' ConstraintList? Name ClassArgument* ClassBlock?
580class_ :: SyntaxInfo -> IdrisParser [PDecl]
581class_ syn = do (doc, acc) <- try (do
582 doc <- option noDocs docComment
583 acc <- optional accessibility
585 reserved "class"; fc <- getFC; cons <- constraintList syn; n_in <- fnName
586 let n = expandNS syn n_in
588 ds <- option [] (classBlock syn)
589 accData acc n (concatMap declared ds)
590 return [PClass (fst doc) syn fc cons n cs (snd doc) ds]
591 <?> "type-class declaration"
593 carg :: IdrisParser (Name, PTerm)
594 carg = do lchar '('; i <- name; lchar ':'; ty <- expr syn; lchar ')'
599{- | Parses a type class instance declaration
603 'instance' InstanceName? ConstraintList? Name SimpleExpr* InstanceBlock?
608InstanceName ::= '[' Name ']';
611instance_ :: SyntaxInfo -> IdrisParser [PDecl]
612instance_ syn = do reserved "instance"; fc <- getFC
613 en <- optional instanceName
614 cs <- constraintList syn
616 args <- many (simpleExpr syn)
617 let sc = PApp fc (PRef fc cn) (map pexp args)
618 let t = bindList (PPi constraint) (map (\x -> (sMN 0 "constraint", x)) cs) sc
619 ds <- option [] (instanceBlock syn)
620 return [PInstance syn fc cs cn args t en ds]
621 <?> "instance declaration"
622 where instanceName :: IdrisParser Name
623 instanceName = do lchar '['; n_in <- fnName; lchar ']'
624 let n = expandNS syn n_in
629{- | Parses a using declaration list
641 | UsingDecl ',' UsingDeclList'
652usingDeclList :: SyntaxInfo -> IdrisParser [Using]
654 = try (sepBy1 (usingDecl syn) (lchar ','))
655 <|> do ns <- sepBy1 name (lchar ',')
657 t <- typeExpr (disallowImp syn)
658 return (map (\x -> UImplicit x t) ns)
659 <?> "using declaration list"
661{- |Parses a using declaration
670usingDecl :: SyntaxInfo -> IdrisParser Using
671usingDecl syn = try (do x <- fnName
673 t <- typeExpr (disallowImp syn)
674 return (UImplicit x t))
677 return (UConstraint c xs)
678 <?> "using declaration"
680{- | Parse a clause with patterns
686pattern :: SyntaxInfo -> IdrisParser PDecl
687pattern syn = do fc <- getFC
689 return (PClauses fc [] (sMN 2 "_") [clause]) -- collect together later
692{- | Parse a constant applicative form declaration
695CAF ::= 'let' FnName '=' Expr Terminator;
698caf :: SyntaxInfo -> IdrisParser PDecl
699caf syn = do reserved "let"
700 n_in <- fnName; let n = expandNS syn n_in
706 <?> "constant applicative form declaration"
708{- | Parse an argument expression
711ArgExpr ::= HSimpleExpr | {- In Pattern External (User-defined) Expression -};
714argExpr :: SyntaxInfo -> IdrisParser PTerm
715argExpr syn = let syn' = syn { inPattern = True } in
716 try (hsimpleExpr syn') <|> simpleExternalExpr syn'
717 <?> "argument expression"
719{- | Parse a right hand side of a function
729RHSName ::= '{' FnName '}';
732rhs :: SyntaxInfo -> Name -> IdrisParser PTerm
733rhs syn n = do lchar '='; expr syn
735 name <- option n' (do symbol "{"; n <- fnName; symbol "}";
738 return (addLet name r)
739 <|> do reserved "impossible"; return PImpossible
740 <?> "function right hand side"
741 where mkN :: Name -> Name
742 mkN (UN x) = if (tnull x || not (isAlpha (thead x)))
743 then sUN "infix_op_lemma_1"
744 else sUN (str x++"_lemma_1")
745 mkN (NS x n) = NS (mkN x) n
748 addLet :: Name -> PTerm -> PTerm
749 addLet nm (PLet n ty val r) = PLet n ty val (addLet nm r)
750 addLet nm (PCase fc t cs) = PCase fc t (map addLetC cs)
751 where addLetC (l, r) = (l, addLet nm r)
752 addLet nm r = (PLet (sUN "value") Placeholder r (PMetavar nm))
754{- |Parses a function clause
757RHSOrWithBlock ::= RHS WhereOrTerminator
758 | 'with' SimpleExpr OpenBlock FnDecl+ CloseBlock
763Clause ::= WExpr+ RHSOrWithBlock
764 | SimpleExpr '<==' FnName RHS WhereOrTerminator
765 | ArgExpr Operator ArgExpr WExpr* RHSOrWithBlock {- Except "=" and "?=" operators to avoid ambiguity -}
766 | FnName ConstraintArg* ImplicitOrArgExpr* WExpr* RHSOrWithBlock
771ImplicitOrArgExpr ::= ImplicitArg | ArgExpr;
775WhereOrTerminator ::= WhereBlock | Terminator;
778clause :: SyntaxInfo -> IdrisParser PClause
780 = do wargs <- try (do pushIndent; some (wExpr syn))
783 n <- case lastParse ist of
785 Nothing -> fail "Invalid clause"
787 let ctxt = tt_ctxt ist
788 let wsyn = syn { syn_namespace = [] }
789 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
794 return $ PClauseR fc wargs r wheres) <|> (do
797 wval <- simpleExpr syn
799 ds <- some $ fnDecl syn
800 let withs = concat ds
802 return $ PWithR fc wargs wval withs)
803 <|> do ty <- try (do pushIndent
808 n_in <- fnName; let n = expandNS syn n_in
811 let ctxt = tt_ctxt ist
812 let wsyn = syn { syn_namespace = [] }
813 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
818 let capp = PLet (sMN 0 "match")
821 (PRef fc (sMN 0 "match"))
823 put (ist { lastParse = Just n })
824 return $ PClause fc n capp [] r wheres
825 <|> do (l, op) <- try (do
829 when (op == "=" || op == "?=" ) $
830 fail "infix clause definition with \"=\" and \"?=\" not supported "
832 let n = expandNS syn (sUN op)
835 wargs <- many (wExpr syn)
837 let wsyn = syn { syn_namespace = [] }
838 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
844 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
845 put (ist { lastParse = Just n })
846 return $ PClause fc n capp wargs rs wheres) <|> (do
849 wval <- bracketed syn
851 ds <- some $ fnDecl syn
854 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
855 let withs = map (fillLHSD n capp wargs) $ concat ds
856 put (ist { lastParse = Just n })
857 return $ PWith fc n capp wargs wval withs)
859 n_in <- fnName; let n = expandNS syn n_in
860 cargs <- many (constraintArg syn)
862 args <- many (try (implicitArg (syn { inPattern = True } ))
863 <|> (fmap pexp (argExpr syn)))
864 wargs <- many (wExpr syn)
865 let capp = PApp fc (PRef fc n)
869 let ctxt = tt_ctxt ist
870 let wsyn = syn { syn_namespace = [] }
871 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
877 put (ist { lastParse = Just n })
878 return $ PClause fc n capp wargs r wheres) <|> (do
881 put (ist { lastParse = Just n })
882 wval <- bracketed syn
884 ds <- some $ fnDecl syn
885 let withs = map (fillLHSD n capp wargs) $ concat ds
888 return $ PWith fc n capp wargs wval withs)
889 <?> "function clause"
891 fillLHS :: Name -> PTerm -> [PTerm] -> PClause -> PClause
892 fillLHS n capp owargs (PClauseR fc wargs v ws)
893 = PClause fc n capp (owargs ++ wargs) v ws
894 fillLHS n capp owargs (PWithR fc wargs v ws)
895 = PWith fc n capp (owargs ++ wargs) v
896 (map (fillLHSD n capp (owargs ++ wargs)) ws)
899 fillLHSD :: Name -> PTerm -> [PTerm] -> PDecl -> PDecl
900 fillLHSD n c a (PClauses fc o fn cs) = PClauses fc o fn (map (fillLHS n c a) cs)
903{-| Parses with pattern
909wExpr :: SyntaxInfo -> IdrisParser PTerm
910wExpr syn = do lchar '|'
914{- | Parses a where block
917WhereBlock ::= 'where' OpenBlock Decl+ CloseBlock;
920whereBlock :: Name -> SyntaxInfo -> IdrisParser ([PDecl], [(Name, Name)])
922 = do reserved "where"
923 ds <- indentedBlock1 (decl syn)
924 let dns = concatMap (concatMap declared) ds
925 return (concat ds, map (\x -> (x, decoration syn x)) dns)
928{- |Parses a code generation target language name
940codegen_ :: IdrisParser Codegen
941codegen_ = do reserved "C"; return ViaC
942 <|> do reserved "Java"; return ViaJava
943 <|> do reserved "JavaScript"; return ViaJavaScript
944 <|> do reserved "Node"; return ViaNode
945 <|> do reserved "LLVM"; return ViaLLVM
946 <|> do reserved "Bytecode"; return Bytecode
947 <?> "code generation language"
949{- |Parses a compiler directive
953 | String ',' StringList
958Directive ::= '%' Directive';
962Directive' ::= 'lib' CodeGen String_t
963 | 'link' CodeGen String_t
964 | 'flag' CodeGen String_t
965 | 'include' CodeGen String_t
968 | 'access' Accessibility
971 | 'dynamic' StringList
972 | 'name' Name NameList
973 | 'error_handlers' Name NameList
974 | 'language' 'TypeProviders'
975 | 'language' 'ErrorReflection'
979directive :: SyntaxInfo -> IdrisParser [PDecl]
980directive syn = do try (lchar '%' *> reserved "lib"); cgn <- codegen_; lib <- stringLiteral;
981 return [PDirective (do addLib cgn lib
982 addIBC (IBCLib cgn lib))]
983 <|> do try (lchar '%' *> reserved "link"); cgn <- codegen_; obj <- stringLiteral;
984 return [PDirective (do dirs <- allImportDirs
985 o <- liftIO $ findInPath dirs obj
986 addIBC (IBCObj cgn obj) -- just name, search on loading ibc
987 addObjectFile cgn o)]
988 <|> do try (lchar '%' *> reserved "flag"); cgn <- codegen_;
989 flag <- stringLiteral
990 return [PDirective (do addIBC (IBCCGFlag cgn flag)
992 <|> do try (lchar '%' *> reserved "include"); cgn <- codegen_; hdr <- stringLiteral;
993 return [PDirective (do addHdr cgn hdr
994 addIBC (IBCHeader cgn hdr))]
995 <|> do try (lchar '%' *> reserved "hide"); n <- fnName
996 return [PDirective (do setAccessibility n Hidden
997 addIBC (IBCAccess n Hidden))]
998 <|> do try (lchar '%' *> reserved "freeze"); n <- iName []
999 return [PDirective (do setAccessibility n Frozen
1000 addIBC (IBCAccess n Frozen))]
1001 <|> do try (lchar '%' *> reserved "access"); acc <- accessibility
1002 return [PDirective (do i <- get
1003 put(i { default_access = acc }))]
1004 <|> do try (lchar '%' *> reserved "default"); tot <- totality
1006 put (i { default_total = tot } )
1007 return [PDirective (do i <- get
1008 put(i { default_total = tot }))]
1009 <|> do try (lchar '%' *> reserved "logging"); i <- natural;
1010 return [PDirective (setLogLevel (fromInteger i))]
1011 <|> do try (lchar '%' *> reserved "dynamic"); libs <- sepBy1 stringLiteral (lchar ',');
1012 return [PDirective (do added <- addDyLib libs
1014 Left lib -> addIBC (IBCDyLib (lib_name lib))
1017 <|> do try (lchar '%' *> reserved "name")
1019 ns <- sepBy1 name (lchar ',')
1020 return [PDirective (do ty' <- disambiguate ty
1021 mapM_ (addNameHint ty') ns
1022 mapM_ (\n -> addIBC (IBCNameHint (ty', n))) ns)]
1023 <|> do try (lchar '%' *> reserved "error_handlers")
1026 ns <- sepBy1 name (lchar ',')
1027 return [PDirective (do fn' <- disambiguate fn
1028 ns' <- mapM disambiguate ns
1029 addFunctionErrorHandlers fn' arg ns'
1030 mapM_ (addIBC . IBCFunctionErrorHandler fn' arg) ns')]
1031 <|> do try (lchar '%' *> reserved "language"); ext <- pLangExt;
1032 return [PDirective (addLangExt ext)]
1034 where disambiguate :: Name -> Idris Name
1035 disambiguate n = do i <- getIState
1036 case lookupCtxtName n (idris_implicits i) of
1037 [(n', _)] -> return n'
1038 [] -> throwError (NoSuchVariable n)
1039 more -> throwError (CantResolveAlts (map fst more))
1041pLangExt :: IdrisParser LanguageExt
1042pLangExt = (reserved "TypeProviders" >> return TypeProviders)
1043 <|> (reserved "ErrorReflection" >> return ErrorReflection)
1045{- | Parses a totality
1048Totality ::= 'partial' | 'total'
1052totality :: IdrisParser Bool
1054 = do reserved "total"; return True
1055 <|> do reserved "partial"; return False
1057{- | Parses a type provider
1060Provider ::= '%' 'provide' Provider_What? '(' FnName TypeSig ')' 'with' Expr;
1061ProviderWhat ::= 'proof' | 'term' | 'type' | 'postulate'
1064provider :: SyntaxInfo -> IdrisParser [PDecl]
1065provider syn = do try (lchar '%' *> reserved "provide");
1066 provideTerm <|> providePostulate
1068 where provideTerm = do lchar '('; n <- fnName; lchar ':'; t <- typeExpr syn; lchar ')'
1071 e <- expr syn <?> "provider expression"
1072 return [PProvider syn fc (ProvTerm t e) n]
1073 providePostulate = do reserved "postulate"
1077 e <- expr syn <?> "provider expression"
1078 return [PProvider syn fc (ProvPostulate e) n]
1080{- | Parses a transform
1083Transform ::= '%' 'transform' Expr '==>' Expr
1086transform :: SyntaxInfo -> IdrisParser [PDecl]
1087transform syn = do try (lchar '%' *> reserved "transform")
1088 -- leave it unchecked, until we work out what this should
1090-- safety <- option True (do reserved "unsafe"
1096 return [PTransform fc False l r]
1100{- * Loading and parsing -}
1101{- | Parses an expression from input -}
1102parseExpr :: IState -> String -> Result PTerm
1103parseExpr st = runparser (fullExpr defaultSyntax) st "(input)"
1105{- | Parses a constant form input -}
1106parseConst :: IState -> String -> Result Const
1107parseConst st = runparser constant st "(input)"
1109{- | Parses a tactic from input -}
1110parseTactic :: IState -> String -> Result PTactic
1111parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
1113-- | Parse module header and imports
1114parseImports :: FilePath -> String -> Idris ([String], [(String, Maybe String, FC)], Maybe Delta)
1115parseImports fname input
1117 case parseString (runInnerParser (evalStateT imports i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
1118 Failure err -> fail (show err)
1119 Success (x, i) -> do putIState i
1121 where imports :: IdrisParser (([String], [(String, Maybe String, FC)], Maybe Delta), IState)
1122 imports = do whiteSpace
1123 mname <- moduleHeader
1126 isEof <- lookAheadMatches eof
1131 return ((mname, ps, mrk'), i)
1133-- | There should be a better way of doing this...
1134findFC :: Doc -> (FC, String)
1135findFC x = let s = show (plain x) in
1136 case span (/= ':') s of
1137 (failname, ':':rest) -> case span isDigit rest of
1138 (line, ':':rest') -> case span isDigit rest' of
1139 (col, ':':msg) -> let pos = (read line, read col) in
1140 (FC failname pos pos, msg)
1142-- | Check if the coloring matches the options and corrects if necessary
1143fixColour :: Bool -> ANSI.Doc -> ANSI.Doc
1144fixColour False doc = ANSI.plain doc
1145fixColour True doc = doc
1147-- | A program is a list of declarations, possibly with associated
1148-- documentation strings.
1149parseProg :: SyntaxInfo -> FilePath -> String -> Maybe Delta ->
1151parseProg syn fname input mrk
1153 case runparser mainProg i fname input of
1154 Failure doc -> do -- FIXME: Get error location from trifecta
1155 -- this can't be the solution!
1156 let (fc, msg) = findFC doc
1158 case idris_outputmode i of
1159 RawOutput -> ihputStrLn (idris_outh i) (show $ fixColour (idris_colourRepl i) doc)
1160 IdeSlave n -> ihWarn (idris_outh i) fc (P.text msg)
1161 putIState (i { errSpan = Just fc })
1163 Success (x, i) -> do putIState i
1164 reportParserWarnings
1166 where mainProg :: IdrisParser ([PDecl], IState)
1167 mainProg = case mrk of
1168 Nothing -> do i <- get; return ([], i)
1175{- | Load idris module and show error if something wrong happens -}
1176loadModule :: Handle -> FilePath -> Idris String
1178 = idrisCatch (loadModule' outh f)
1179 (\e -> do setErrSpan (getErrSpan e)
1181 ihWarn outh (getErrSpan e) $ pprintErr ist e
1184{- | Load idris module -}
1185loadModule' :: Handle -> FilePath -> Idris String
1188 let file = takeWhile (/= ' ') f
1189 ibcsd <- valIBCSubDir i
1190 ids <- allImportDirs
1191 fp <- findImport ids ibcsd file
1192 if file `elem` imported i
1193 then iLOG $ "Already read " ++ file
1194 else do putIState (i { imported = file : imported i })
1196 IDR fn -> loadSource outh False fn Nothing
1197 LIDR fn -> loadSource outh True fn Nothing
1199 idrisCatch (loadIBC fn)
1200 (\c -> do iLOG $ fn ++ " failed " ++ pshow i c
1202 IDR sfn -> loadSource outh False sfn Nothing
1203 LIDR sfn -> loadSource outh True sfn Nothing)
1204 let (dir, fh) = splitFileName file
1205 return (dropExtension fh)
1208{- | Load idris code from file -}
1209loadFromIFile :: Handle -> IFileType -> Maybe Int -> Idris ()
1210loadFromIFile h i@(IBC fn src) maxline
1211 = do iLOG $ "Skipping " ++ getSrcFile i
1212 idrisCatch (loadIBC fn)
1213 (\err -> ierror $ LoadingFailed fn err)
1215 getSrcFile (IDR fn) = fn
1216 getSrcFile (LIDR fn) = fn
1217 getSrcFile (IBC f src) = getSrcFile src
1219loadFromIFile h (IDR fn) maxline = loadSource' h False fn maxline
1220loadFromIFile h (LIDR fn) maxline = loadSource' h True fn maxline
1222{-| Load idris source code and show error if something wrong happens -}
1223loadSource' :: Handle -> Bool -> FilePath -> Maybe Int -> Idris ()
1224loadSource' h lidr r maxline
1225 = idrisCatch (loadSource h lidr r maxline)
1226 (\e -> do setErrSpan (getErrSpan e)
1229 At f e' -> ihWarn h f (pprintErr ist e')
1230 _ -> ihWarn h (getErrSpan e) (pprintErr ist e))
1232{- | Load Idris source code-}
1233loadSource :: Handle -> Bool -> FilePath -> Maybe Int -> Idris ()
1234loadSource h lidr f toline
1235 = do iLOG ("Reading " ++ f)
1237 let def_total = default_total i
1238 file_in <- runIO $ readFile f
1239 file <- if lidr then tclift $ unlit f file_in else return file_in
1240 (mname, imports, pos) <- parseImports f file
1241 ids <- allImportDirs
1242 ibcsd <- valIBCSubDir i
1243 mapM_ (\f -> do fp <- findImport ids ibcsd f
1245 LIDR fn -> ifail $ "No ibc for " ++ f
1246 IDR fn -> ifail $ "No ibc for " ++ f
1247 IBC fn src -> loadIBC fn)
1248 [fn | (fn, _, _) <- imports]
1249 reportParserWarnings
1251 -- process and check module aliases
1252 let modAliases = M.fromList
1253 [(prep alias, prep realName) | (realName, Just alias, fc) <- imports]
1254 prep = map T.pack . reverse . Spl.splitOn "/"
1255 aliasNames = [(alias, fc) | (_, Just alias, fc) <- imports]
1256 histogram = groupBy ((==) `on` fst) . sortBy (comparing fst) $ aliasNames
1257 case map head . filter ((/= 1) . length) $ histogram of
1258 [] -> logLvl 3 $ "Module aliases: " ++ show (M.toList modAliases)
1259 (n,fc):_ -> throwError . At fc . Msg $ "import alias not unique: " ++ show n
1262 putIState (i { default_access = Hidden, module_aliases = modAliases })
1263 clearIBC -- start a new .ibc file
1264 mapM_ (addIBC . IBCImport) [realName | (realName, alias, fc) <- imports]
1265 let syntax = defaultSyntax{ syn_namespace = reverse mname,
1267 ds' <- parseProg syntax f file pos
1269 -- Parsing done, now process declarations
1271 let ds = namespaces mname ds'
1272 logLvl 3 (show $ showDecls verbosePPOption ds)
1274 logLvl 10 (show (toAlist (idris_implicits i)))
1275 logLvl 3 (show (idris_infixes i))
1276 -- Now add all the declarations to the context
1278 when v $ ihputStrLn h $ "Type checking " ++ f
1279 -- we totality check after every Mutual block, so if
1280 -- anything is a single definition, wrap it in a
1281 -- mutual block on its own
1282 elabDecls toplevel (map toMutual ds)
1284 -- simplify every definition do give the totality checker
1286 mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
1287 updateContext (simplifyCasedef n $ getErasureInfo i))
1288 (map snd (idris_totcheck i))
1289 -- build size change graph from simplified definitions
1290 iLOG "Totality checking"
1292 mapM_ buildSCG (idris_totcheck i)
1293 mapM_ checkDeclTotality (idris_totcheck i)
1295 -- Redo totality check for deferred names
1296 let deftots = idris_defertotcheck i
1297 iLOG $ "Totality checking " ++ show deftots
1298 mapM_ (\x -> do tot <- getTotality x
1300 Total _ -> setTotality x Unchecked
1301 _ -> return ()) (map snd deftots)
1302 mapM_ buildSCG deftots
1303 mapM_ checkDeclTotality deftots
1305 iLOG ("Finished " ++ f)
1306 ibcsd <- valIBCSubDir i
1307 iLOG "Universe checking"
1309 let ibc = ibcPathNoFallback ibcsd f
1311 addHides (hide_list i)
1313 -- Finally, write an ibc if checking was successful
1316 idrisCatch (do writeIBC f ibc; clearIBC)
1317 (\c -> return ()) -- failure is harmless
1319 putIState (i { default_total = def_total,
1323 namespaces :: [String] -> [PDecl] -> [PDecl]
1324 namespaces [] ds = ds
1325 namespaces (x:xs) ds = [PNamespace x (namespaces xs ds)]
1327 toMutual :: PDecl -> PDecl
1328 toMutual m@(PMutual _ d) = m
1329 toMutual (PNamespace x ds) = PNamespace x (map toMutual ds)
1330 toMutual x = let r = PMutual (fileFC "single mutual") [x] in
1332 PClauses _ _ _ _ -> r
1333 PClass _ _ _ _ _ _ _ _ -> r
1334 PInstance _ _ _ _ _ _ _ _ -> r
1337{- | Adds names to hide list -}
1338addHides :: [(Name, Maybe Accessibility)] -> Idris ()
1339addHides xs = do i <- getIState
1340 let defh = default_access i
1341 let (hs, as) = partition isNothing xs
1344 (map (\ (n, _) -> (n, defh)) hs ++
1345 map (\ (n, Just a) -> (n, a)) as)
1346 where isNothing (_, Nothing) = True
1349 doHide (n, a) = do setAccessibility n a
1350 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