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) = sUN (str x++"_lemma_1")
743 mkN (NS x n) = NS (mkN x) n
746 addLet :: Name -> PTerm -> PTerm
747 addLet nm (PLet n ty val r) = PLet n ty val (addLet nm r)
748 addLet nm (PCase fc t cs) = PCase fc t (map addLetC cs)
749 where addLetC (l, r) = (l, addLet nm r)
750 addLet nm r = (PLet (sUN "value") Placeholder r (PMetavar nm))
752{- |Parses a function clause
755RHSOrWithBlock ::= RHS WhereOrTerminator
756 | 'with' SimpleExpr OpenBlock FnDecl+ CloseBlock
761Clause ::= WExpr+ RHSOrWithBlock
762 | SimpleExpr '<==' FnName RHS WhereOrTerminator
763 | ArgExpr Operator ArgExpr WExpr* RHSOrWithBlock {- Except "=" and "?=" operators to avoid ambiguity -}
764 | FnName ConstraintArg* ImplicitOrArgExpr* WExpr* RHSOrWithBlock
769ImplicitOrArgExpr ::= ImplicitArg | ArgExpr;
773WhereOrTerminator ::= WhereBlock | Terminator;
776clause :: SyntaxInfo -> IdrisParser PClause
778 = do wargs <- try (do pushIndent; some (wExpr syn))
781 n <- case lastParse ist of
783 Nothing -> fail "Invalid clause"
785 let ctxt = tt_ctxt ist
786 let wsyn = syn { syn_namespace = [] }
787 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
792 return $ PClauseR fc wargs r wheres) <|> (do
795 wval <- simpleExpr syn
797 ds <- some $ fnDecl syn
798 let withs = concat ds
800 return $ PWithR fc wargs wval withs)
801 <|> do ty <- try (do pushIndent
806 n_in <- fnName; let n = expandNS syn n_in
809 let ctxt = tt_ctxt ist
810 let wsyn = syn { syn_namespace = [] }
811 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
816 let capp = PLet (sMN 0 "match")
819 (PRef fc (sMN 0 "match"))
821 put (ist { lastParse = Just n })
822 return $ PClause fc n capp [] r wheres
823 <|> do (l, op) <- try (do
827 when (op == "=" || op == "?=" ) $
828 fail "infix clause definition with \"=\" and \"?=\" not supported "
830 let n = expandNS syn (sUN op)
833 wargs <- many (wExpr syn)
835 let wsyn = syn { syn_namespace = [] }
836 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
842 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
843 put (ist { lastParse = Just n })
844 return $ PClause fc n capp wargs rs wheres) <|> (do
847 wval <- bracketed syn
849 ds <- some $ fnDecl syn
852 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
853 let withs = map (fillLHSD n capp wargs) $ concat ds
854 put (ist { lastParse = Just n })
855 return $ PWith fc n capp wargs wval withs)
857 n_in <- fnName; let n = expandNS syn n_in
858 cargs <- many (constraintArg syn)
860 args <- many (try (implicitArg (syn { inPattern = True } ))
861 <|> (fmap pexp (argExpr syn)))
862 wargs <- many (wExpr syn)
863 let capp = PApp fc (PRef fc n)
867 let ctxt = tt_ctxt ist
868 let wsyn = syn { syn_namespace = [] }
869 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
875 put (ist { lastParse = Just n })
876 return $ PClause fc n capp wargs r wheres) <|> (do
879 put (ist { lastParse = Just n })
880 wval <- bracketed syn
882 ds <- some $ fnDecl syn
883 let withs = map (fillLHSD n capp wargs) $ concat ds
886 return $ PWith fc n capp wargs wval withs)
887 <?> "function clause"
889 fillLHS :: Name -> PTerm -> [PTerm] -> PClause -> PClause
890 fillLHS n capp owargs (PClauseR fc wargs v ws)
891 = PClause fc n capp (owargs ++ wargs) v ws
892 fillLHS n capp owargs (PWithR fc wargs v ws)
893 = PWith fc n capp (owargs ++ wargs) v
894 (map (fillLHSD n capp (owargs ++ wargs)) ws)
897 fillLHSD :: Name -> PTerm -> [PTerm] -> PDecl -> PDecl
898 fillLHSD n c a (PClauses fc o fn cs) = PClauses fc o fn (map (fillLHS n c a) cs)
901{-| Parses with pattern
907wExpr :: SyntaxInfo -> IdrisParser PTerm
908wExpr syn = do lchar '|'
912{- | Parses a where block
915WhereBlock ::= 'where' OpenBlock Decl+ CloseBlock;
918whereBlock :: Name -> SyntaxInfo -> IdrisParser ([PDecl], [(Name, Name)])
920 = do reserved "where"
921 ds <- indentedBlock1 (decl syn)
922 let dns = concatMap (concatMap declared) ds
923 return (concat ds, map (\x -> (x, decoration syn x)) dns)
926{- |Parses a code generation target language name
938codegen_ :: IdrisParser Codegen
939codegen_ = do reserved "C"; return ViaC
940 <|> do reserved "Java"; return ViaJava
941 <|> do reserved "JavaScript"; return ViaJavaScript
942 <|> do reserved "Node"; return ViaNode
943 <|> do reserved "LLVM"; return ViaLLVM
944 <|> do reserved "Bytecode"; return Bytecode
945 <?> "code generation language"
947{- |Parses a compiler directive
951 | String ',' StringList
956Directive ::= '%' Directive';
960Directive' ::= 'lib' CodeGen String_t
961 | 'link' CodeGen String_t
962 | 'flag' CodeGen String_t
963 | 'include' CodeGen String_t
966 | 'access' Accessibility
969 | 'dynamic' StringList
970 | 'name' Name NameList
971 | 'error_handlers' Name NameList
972 | 'language' 'TypeProviders'
973 | 'language' 'ErrorReflection'
977directive :: SyntaxInfo -> IdrisParser [PDecl]
978directive syn = do try (lchar '%' *> reserved "lib"); cgn <- codegen_; lib <- stringLiteral;
979 return [PDirective (do addLib cgn lib
980 addIBC (IBCLib cgn lib))]
981 <|> do try (lchar '%' *> reserved "link"); cgn <- codegen_; obj <- stringLiteral;
982 return [PDirective (do dirs <- allImportDirs
983 o <- liftIO $ findInPath dirs obj
984 addIBC (IBCObj cgn obj) -- just name, search on loading ibc
985 addObjectFile cgn o)]
986 <|> do try (lchar '%' *> reserved "flag"); cgn <- codegen_;
987 flag <- stringLiteral
988 return [PDirective (do addIBC (IBCCGFlag cgn flag)
990 <|> do try (lchar '%' *> reserved "include"); cgn <- codegen_; hdr <- stringLiteral;
991 return [PDirective (do addHdr cgn hdr
992 addIBC (IBCHeader cgn hdr))]
993 <|> do try (lchar '%' *> reserved "hide"); n <- fnName
994 return [PDirective (do setAccessibility n Hidden
995 addIBC (IBCAccess n Hidden))]
996 <|> do try (lchar '%' *> reserved "freeze"); n <- iName []
997 return [PDirective (do setAccessibility n Frozen
998 addIBC (IBCAccess n Frozen))]
999 <|> do try (lchar '%' *> reserved "access"); acc <- accessibility
1000 return [PDirective (do i <- get
1001 put(i { default_access = acc }))]
1002 <|> do try (lchar '%' *> reserved "default"); tot <- totality
1004 put (i { default_total = tot } )
1005 return [PDirective (do i <- get
1006 put(i { default_total = tot }))]
1007 <|> do try (lchar '%' *> reserved "logging"); i <- natural;
1008 return [PDirective (setLogLevel (fromInteger i))]
1009 <|> do try (lchar '%' *> reserved "dynamic"); libs <- sepBy1 stringLiteral (lchar ',');
1010 return [PDirective (do added <- addDyLib libs
1012 Left lib -> addIBC (IBCDyLib (lib_name lib))
1015 <|> do try (lchar '%' *> reserved "name")
1017 ns <- sepBy1 name (lchar ',')
1018 return [PDirective (do ty' <- disambiguate ty
1019 mapM_ (addNameHint ty') ns
1020 mapM_ (\n -> addIBC (IBCNameHint (ty', n))) ns)]
1021 <|> do try (lchar '%' *> reserved "error_handlers")
1024 ns <- sepBy1 name (lchar ',')
1025 return [PDirective (do fn' <- disambiguate fn
1026 ns' <- mapM disambiguate ns
1027 addFunctionErrorHandlers fn' arg ns'
1028 mapM_ (addIBC . IBCFunctionErrorHandler fn' arg) ns')]
1029 <|> do try (lchar '%' *> reserved "language"); ext <- pLangExt;
1030 return [PDirective (addLangExt ext)]
1032 where disambiguate :: Name -> Idris Name
1033 disambiguate n = do i <- getIState
1034 case lookupCtxtName n (idris_implicits i) of
1035 [(n', _)] -> return n'
1036 [] -> throwError (NoSuchVariable n)
1037 more -> throwError (CantResolveAlts (map fst more))
1039pLangExt :: IdrisParser LanguageExt
1040pLangExt = (reserved "TypeProviders" >> return TypeProviders)
1041 <|> (reserved "ErrorReflection" >> return ErrorReflection)
1043{- | Parses a totality
1046Totality ::= 'partial' | 'total'
1050totality :: IdrisParser Bool
1052 = do reserved "total"; return True
1053 <|> do reserved "partial"; return False
1055{- | Parses a type provider
1058Provider ::= '%' 'provide' Provider_What? '(' FnName TypeSig ')' 'with' Expr;
1059ProviderWhat ::= 'proof' | 'term' | 'type' | 'postulate'
1062provider :: SyntaxInfo -> IdrisParser [PDecl]
1063provider syn = do try (lchar '%' *> reserved "provide");
1064 provideTerm <|> providePostulate
1066 where provideTerm = do lchar '('; n <- fnName; lchar ':'; t <- typeExpr syn; lchar ')'
1069 e <- expr syn <?> "provider expression"
1070 return [PProvider syn fc (ProvTerm t e) n]
1071 providePostulate = do reserved "postulate"
1075 e <- expr syn <?> "provider expression"
1076 return [PProvider syn fc (ProvPostulate e) n]
1078{- | Parses a transform
1081Transform ::= '%' 'transform' Expr '==>' Expr
1084transform :: SyntaxInfo -> IdrisParser [PDecl]
1085transform syn = do try (lchar '%' *> reserved "transform")
1086 -- leave it unchecked, until we work out what this should
1088-- safety <- option True (do reserved "unsafe"
1094 return [PTransform fc False l r]
1098{- * Loading and parsing -}
1099{- | Parses an expression from input -}
1100parseExpr :: IState -> String -> Result PTerm
1101parseExpr st = runparser (fullExpr defaultSyntax) st "(input)"
1103{- | Parses a constant form input -}
1104parseConst :: IState -> String -> Result Const
1105parseConst st = runparser constant st "(input)"
1107{- | Parses a tactic from input -}
1108parseTactic :: IState -> String -> Result PTactic
1109parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
1111-- | Parse module header and imports
1112parseImports :: FilePath -> String -> Idris ([String], [(String, Maybe String, FC)], Maybe Delta)
1113parseImports fname input
1115 case parseString (runInnerParser (evalStateT imports i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
1116 Failure err -> fail (show err)
1117 Success (x, i) -> do putIState i
1119 where imports :: IdrisParser (([String], [(String, Maybe String, FC)], Maybe Delta), IState)
1120 imports = do whiteSpace
1121 mname <- moduleHeader
1124 isEof <- lookAheadMatches eof
1129 return ((mname, ps, mrk'), i)
1131-- | There should be a better way of doing this...
1132findFC :: Doc -> (FC, String)
1133findFC x = let s = show (plain x) in
1134 case span (/= ':') s of
1135 (failname, ':':rest) -> case span isDigit rest of
1136 (line, ':':rest') -> case span isDigit rest' of
1137 (col, ':':msg) -> let pos = (read line, read col) in
1138 (FC failname pos pos, msg)
1140-- | Check if the coloring matches the options and corrects if necessary
1141fixColour :: Bool -> ANSI.Doc -> ANSI.Doc
1142fixColour False doc = ANSI.plain doc
1143fixColour True doc = doc
1145-- | A program is a list of declarations, possibly with associated
1146-- documentation strings.
1147parseProg :: SyntaxInfo -> FilePath -> String -> Maybe Delta ->
1149parseProg syn fname input mrk
1151 case runparser mainProg i fname input of
1152 Failure doc -> do -- FIXME: Get error location from trifecta
1153 -- this can't be the solution!
1154 let (fc, msg) = findFC doc
1156 case idris_outputmode i of
1157 RawOutput -> ihputStrLn (idris_outh i) (show $ fixColour (idris_colourRepl i) doc)
1158 IdeSlave n -> ihWarn (idris_outh i) fc (P.text msg)
1159 putIState (i { errSpan = Just fc })
1161 Success (x, i) -> do putIState i
1162 reportParserWarnings
1164 where mainProg :: IdrisParser ([PDecl], IState)
1165 mainProg = case mrk of
1166 Nothing -> do i <- get; return ([], i)
1173{- | Load idris module and show error if something wrong happens -}
1174loadModule :: Handle -> FilePath -> Idris String
1176 = idrisCatch (loadModule' outh f)
1177 (\e -> do setErrSpan (getErrSpan e)
1179 ihWarn outh (getErrSpan e) $ pprintErr ist e
1182{- | Load idris module -}
1183loadModule' :: Handle -> FilePath -> Idris String
1186 let file = takeWhile (/= ' ') f
1187 ibcsd <- valIBCSubDir i
1188 ids <- allImportDirs
1189 fp <- findImport ids ibcsd file
1190 if file `elem` imported i
1191 then iLOG $ "Already read " ++ file
1192 else do putIState (i { imported = file : imported i })
1194 IDR fn -> loadSource outh False fn Nothing
1195 LIDR fn -> loadSource outh True fn Nothing
1197 idrisCatch (loadIBC fn)
1198 (\c -> do iLOG $ fn ++ " failed " ++ pshow i c
1200 IDR sfn -> loadSource outh False sfn Nothing
1201 LIDR sfn -> loadSource outh True sfn Nothing)
1202 let (dir, fh) = splitFileName file
1203 return (dropExtension fh)
1206{- | Load idris code from file -}
1207loadFromIFile :: Handle -> IFileType -> Maybe Int -> Idris ()
1208loadFromIFile h i@(IBC fn src) maxline
1209 = do iLOG $ "Skipping " ++ getSrcFile i
1210 idrisCatch (loadIBC fn)
1211 (\err -> ierror $ LoadingFailed fn err)
1213 getSrcFile (IDR fn) = fn
1214 getSrcFile (LIDR fn) = fn
1215 getSrcFile (IBC f src) = getSrcFile src
1217loadFromIFile h (IDR fn) maxline = loadSource' h False fn maxline
1218loadFromIFile h (LIDR fn) maxline = loadSource' h True fn maxline
1220{-| Load idris source code and show error if something wrong happens -}
1221loadSource' :: Handle -> Bool -> FilePath -> Maybe Int -> Idris ()
1222loadSource' h lidr r maxline
1223 = idrisCatch (loadSource h lidr r maxline)
1224 (\e -> do setErrSpan (getErrSpan e)
1227 At f e' -> ihWarn h f (pprintErr ist e')
1228 _ -> ihWarn h (getErrSpan e) (pprintErr ist e))
1230{- | Load Idris source code-}
1231loadSource :: Handle -> Bool -> FilePath -> Maybe Int -> Idris ()
1232loadSource h lidr f toline
1233 = do iLOG ("Reading " ++ f)
1235 let def_total = default_total i
1236 file_in <- runIO $ readFile f
1237 file <- if lidr then tclift $ unlit f file_in else return file_in
1238 (mname, imports, pos) <- parseImports f file
1239 ids <- allImportDirs
1240 ibcsd <- valIBCSubDir i
1241 mapM_ (\f -> do fp <- findImport ids ibcsd f
1243 LIDR fn -> ifail $ "No ibc for " ++ f
1244 IDR fn -> ifail $ "No ibc for " ++ f
1245 IBC fn src -> loadIBC fn)
1246 [fn | (fn, _, _) <- imports]
1247 reportParserWarnings
1249 -- process and check module aliases
1250 let modAliases = M.fromList
1251 [(prep alias, prep realName) | (realName, Just alias, fc) <- imports]
1252 prep = map T.pack . reverse . Spl.splitOn "/"
1253 aliasNames = [(alias, fc) | (_, Just alias, fc) <- imports]
1254 histogram = groupBy ((==) `on` fst) . sortBy (comparing fst) $ aliasNames
1255 case map head . filter ((/= 1) . length) $ histogram of
1256 [] -> logLvl 3 $ "Module aliases: " ++ show (M.toList modAliases)
1257 (n,fc):_ -> throwError . At fc . Msg $ "import alias not unique: " ++ show n
1260 putIState (i { default_access = Hidden, module_aliases = modAliases })
1261 clearIBC -- start a new .ibc file
1262 mapM_ (addIBC . IBCImport) [realName | (realName, alias, fc) <- imports]
1263 let syntax = defaultSyntax{ syn_namespace = reverse mname,
1265 ds' <- parseProg syntax f file pos
1267 -- Parsing done, now process declarations
1269 let ds = namespaces mname ds'
1270 logLvl 3 (show $ showDecls verbosePPOption ds)
1272 logLvl 10 (show (toAlist (idris_implicits i)))
1273 logLvl 3 (show (idris_infixes i))
1274 -- Now add all the declarations to the context
1276 when v $ ihputStrLn h $ "Type checking " ++ f
1277 -- we totality check after every Mutual block, so if
1278 -- anything is a single definition, wrap it in a
1279 -- mutual block on its own
1280 elabDecls toplevel (map toMutual ds)
1282 -- simplify every definition do give the totality checker
1284 mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
1285 updateContext (simplifyCasedef n))
1286 (map snd (idris_totcheck i))
1287 -- build size change graph from simplified definitions
1288 iLOG "Totality checking"
1290 mapM_ buildSCG (idris_totcheck i)
1291 mapM_ checkDeclTotality (idris_totcheck i)
1293 -- Redo totality check for deferred names
1294 let deftots = idris_defertotcheck i
1295 iLOG $ "Totality checking " ++ show deftots
1296 mapM_ (\x -> do tot <- getTotality x
1298 Total _ -> setTotality x Unchecked
1299 _ -> return ()) (map snd deftots)
1300 mapM_ buildSCG deftots
1301 mapM_ checkDeclTotality deftots
1303 iLOG ("Finished " ++ f)
1304 ibcsd <- valIBCSubDir i
1305 iLOG "Universe checking"
1307 let ibc = ibcPathNoFallback ibcsd f
1309 addHides (hide_list i)
1311 -- Finally, write an ibc if checking was successful
1314 idrisCatch (do writeIBC f ibc; clearIBC)
1315 (\c -> return ()) -- failure is harmless
1317 putIState (i { default_total = def_total,
1321 namespaces :: [String] -> [PDecl] -> [PDecl]
1322 namespaces [] ds = ds
1323 namespaces (x:xs) ds = [PNamespace x (namespaces xs ds)]
1325 toMutual :: PDecl -> PDecl
1326 toMutual m@(PMutual _ d) = m
1327 toMutual (PNamespace x ds) = PNamespace x (map toMutual ds)
1328 toMutual x = let r = PMutual (fileFC "single mutual") [x] in
1330 PClauses _ _ _ _ -> r
1331 PClass _ _ _ _ _ _ _ _ -> r
1332 PInstance _ _ _ _ _ _ _ _ -> r
1335{- | Adds names to hide list -}
1336addHides :: [(Name, Maybe Accessibility)] -> Idris ()
1337addHides xs = do i <- getIState
1338 let defh = default_access i
1339 let (hs, as) = partition isNothing xs
1342 (map (\ (n, _) -> (n, defh)) hs ++
1343 map (\ (n, Just a) -> (n, a)) as)
1344 where isNothing (_, Nothing) = True
1347 doHide (n, a) = do setAccessibility n a
1348 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