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 qualified System.Directory as Dir (makeAbsolute)
13import Text.Trifecta.Delta
14import Text.Trifecta hiding (span, stringLiteral, charLiteral, natural, symbol, char, string, whiteSpace, Err)
15import Text.Parser.LookAhead
16import Text.Parser.Expression
17import qualified Text.Parser.Token as Tok
18import qualified Text.Parser.Char as Chr
19import qualified Text.Parser.Token.Highlight as Hi
21import Text.PrettyPrint.ANSI.Leijen (Doc, plain)
22import qualified Text.PrettyPrint.ANSI.Leijen as ANSI
24import Idris.AbsSyntax hiding (namespace, params)
27import Idris.Delaborate
29import Idris.Elab.Value
38import Idris.ParseHelpers
43import Idris.Docstrings hiding (Unchecked)
47import Util.DynamicLinker
48import Util.System (readSource, writeSource)
49import qualified Util.Pretty as P
52import Idris.Core.Evaluate
54import Control.Applicative hiding (Const)
56import Control.Monad.State.Strict
60import qualified Data.List.Split as Spl
65import Data.Generics.Uniplate.Data (descendM)
66import qualified Data.Map as M
67import qualified Data.HashSet as HS
68import qualified Data.Text as T
69import qualified Data.ByteString.UTF8 as UTF8
70import qualified Data.Set as S
79 grammar shortcut notation:
80 ~CHARSEQ = complement of char sequence (i.e. any character except CHARSEQ)
81 RULE? = optional rule (i.e. RULE or nothing)
82 RULE* = repeated rule (i.e. RULE zero or more times)
83 RULE+ = repeated rule with at least one match (i.e. RULE one or more times)
84 RULE! = invalid rule (i.e. rule that is not valid in context, report meaningful error in case)
85 RULE{n} = rule repeated n times
91{- | Parses module definition
94 ModuleHeader ::= DocComment_t? 'module' Identifier_t ';'?;
97moduleHeader :: IdrisParser (Maybe (Docstring ()), [String], [(FC, OutputAnnotation)])
98moduleHeader = try (do docs <- optional docComment
101 (i, ifc) <- identifier
102 option ';' (lchar ';')
103 let modName = moduleName i
104 return (fmap fst docs,
106 [(ifc, AnnNamespace (map T.pack modName) Nothing)]))
107 <|> try (do lchar '%'; reserved "unqualified"
108 return (Nothing, [], []))
109 <|> return (Nothing, moduleName "Main", [])
110 where moduleName x = case span (/='.') x of
112 (x, '.':y) -> x : moduleName y
113 noArgs (Just (_, args)) | not (null args) = fail "Modules do not take arguments"
116data ImportInfo = ImportInfo { import_reexport :: Bool
117 , import_path :: FilePath
118 , import_rename :: Maybe (String, FC)
119 , import_namespace :: [T.Text]
120 , import_location :: FC
121 , import_modname_location :: FC
124{- | Parses an import statement
127 Import ::= 'import' Identifier_t ';'?;
130import_ :: IdrisParser ImportInfo
131import_ = do fc <- getFC
133 reexport <- option False (do reserved "public"; return True)
134 (id, idfc) <- identifier
135 newName <- optional (reserved "as" *> identifier)
136 option ';' (lchar ';')
137 return $ ImportInfo reexport (toPath id)
138 (fmap (\(n, fc) -> (toPath n, fc)) newName)
139 (map T.pack $ ns id) fc idfc
140 <?> "import statement"
141 where ns = Spl.splitOn "."
142 toPath = foldl1' (</>) . ns
144{- | Parses program source
150prog :: SyntaxInfo -> IdrisParser [PDecl]
151prog syn = do whiteSpace
152 decls <- many (decl syn)
153 let c = (concat decls)
155 Nothing -> do notOpenBraces; eof
159 put ist { idris_parsedSpan = Just (FC (fc_fname fc) (0,0) (fc_end fc)),
160 ibc_write = IBCParsedRegion fc : ibc_write ist }
163{-| Parses a top-level declaration
182decl :: SyntaxInfo -> IdrisParser [PDecl]
183decl syn = do fc <- getFC
184 -- if we're after maxline, stop here
185 let continue = case maxline syn of
187 Just l -> if fst (fc_end fc) > l
188 then mut_nesting syn /= 0
190 if continue then do notEndBlock
192 else fail "End of readable input"
193 where declBody :: IdrisParser [PDecl]
201 <|> do d <- dsl syn; return [d]
205 <|> do import_; fail "imports must be at top of file"
207 declBody' :: IdrisParser [PDecl]
208 declBody' = do d <- decl' syn
210 let d' = fmap (debindApp syn . (desugar syn i)) d
213{- | Parses a top-level declaration with possible syntax sugar
225decl' :: SyntaxInfo -> IdrisParser PDecl
233{- | Parses a syntax extension declaration (and adds the rule to parser state)
236 SyntaxDecl ::= SyntaxRule;
239syntaxDecl :: SyntaxInfo -> IdrisParser PDecl
240syntaxDecl syn = do s <- syntaxRule syn
242 put (i `addSyntax` s)
244 return (PSyntax fc s)
246-- | Extend an 'IState' with a new syntax extension. See also 'addReplSyntax'.
247addSyntax :: IState -> Syntax -> IState
248addSyntax i s = i { syntax_rules = updateSyntaxRules [s] rs,
249 syntax_keywords = ks ++ ns,
250 ibc_write = IBCSyntax s : map IBCKeyword ks ++ ibc }
251 where rs = syntax_rules i
252 ns = syntax_keywords i
254 ks = map show (syntaxNames s)
256-- | Like 'addSyntax', but no effect on the IBC.
257addReplSyntax :: IState -> Syntax -> IState
258addReplSyntax i s = i { syntax_rules = updateSyntaxRules [s] rs,
259 syntax_keywords = ks ++ ns }
260 where rs = syntax_rules i
261 ns = syntax_keywords i
262 ks = map show (syntaxNames s)
264{- | Parses a syntax extension declaration
267SyntaxRuleOpts ::= 'term' | 'pattern';
272 SyntaxRuleOpts? 'syntax' SyntaxSym+ '=' TypeExpr Terminator;
276SyntaxSym ::= '[' Name_t ']'
283syntaxRule :: SyntaxInfo -> IdrisParser Syntax
287 sty <- option AnySyntax (do reserved "term"; return TermSyntax
288 <|> do reserved "pattern"; return PatternSyntax)
291 syms <- some syntaxSym
292 when (all isExpr syms) $ unexpected "missing keywords in syntax rule"
293 let ns = mapMaybe getName syms
294 when (length ns /= length (nub ns))
295 $ unexpected "repeated variable in syntax rule"
297 tm <- typeExpr (allowImp syn) >>= uniquifyBinders [n | Binding n <- syms]
299 return (Rule (mkSimple syms) tm sty)
301 isExpr (Expr _) = True
303 getName (Expr n) = Just n
305 -- Can't parse two full expressions (i.e. expressions with application) in a row
306 -- so change them both to a simple expression
307 mkSimple (Expr e : es) = SimpleExpr e : mkSimple' es
308 mkSimple xs = mkSimple' xs
310 mkSimple' (Expr e : Expr e1 : es) = SimpleExpr e : SimpleExpr e1 :
312 -- Can't parse a full expression followed by operator like characters due to ambiguity
313 mkSimple' (Expr e : Symbol s : es)
314 | takeWhile (`elem` opChars) ts /= "" && ts `notElem` invalidOperators = SimpleExpr e : Symbol s : mkSimple' es
315 where ts = dropWhile isSpace . dropWhileEnd isSpace $ s
316 mkSimple' (e : es) = e : mkSimple' es
319 -- Prevent syntax variable capture by making all binders under syntax unique
320 -- (the ol' Common Lisp GENSYM approach)
321 uniquifyBinders :: [Name] -> PTerm -> IdrisParser PTerm
322 uniquifyBinders userNames = fixBind []
324 fixBind :: [(Name, Name)] -> PTerm -> IdrisParser PTerm
325 fixBind rens (PRef fc n) | Just n' <- lookup n rens =
327 fixBind rens (PPatvar fc n) | Just n' <- lookup n rens =
328 return $ PPatvar fc n'
329 fixBind rens (PLam fc n nfc ty body)
330 | n `elem` userNames = liftM2 (PLam fc n nfc) (fixBind rens ty) (fixBind rens body)
332 do ty' <- fixBind rens ty
334 body' <- fixBind ((n,n'):rens) body
335 return $ PLam fc n' nfc ty' body'
336 fixBind rens (PPi plic n nfc argTy body)
337 | n `elem` userNames = liftM2 (PPi plic n nfc) (fixBind rens argTy) (fixBind rens body)
339 do ty' <- fixBind rens argTy
341 body' <- fixBind ((n,n'):rens) body
342 return $ (PPi plic n' nfc ty' body')
343 fixBind rens (PLet fc n nfc ty val body)
344 | n `elem` userNames = liftM3 (PLet fc n nfc)
349 do ty' <- fixBind rens ty
350 val' <- fixBind rens val
352 body' <- fixBind ((n,n'):rens) body
353 return $ PLet fc n' nfc ty' val' body'
354 fixBind rens (PMatchApp fc n) | Just n' <- lookup n rens =
355 return $ PMatchApp fc n'
356 fixBind rens x = descendM (fixBind rens) x
358 gensym :: Name -> IdrisParser Name
359 gensym n = do ist <- get
360 let idx = idris_name ist
361 put ist { idris_name = idx + 1 }
362 return $ sMN idx (show n)
364{- | Parses a syntax symbol (either binding variable, keyword or expression)
367SyntaxSym ::= '[' Name_t ']'
374syntaxSym :: IdrisParser SSymbol
375syntaxSym = try (do lchar '['; n <- fst <$> name; lchar ']'
377 <|> try (do lchar '{'; n <- fst <$> name; lchar '}'
379 <|> do n <- fst <$> iName []
381 <|> do sym <- fmap fst stringLiteral
385{- | Parses a function declaration with possible syntax sugar
388 FunDecl ::= FunDecl';
391fnDecl :: SyntaxInfo -> IdrisParser [PDecl]
392fnDecl syn = try (do notEndBlock
395 let d' = fmap (desugar syn i) d
396 return [d']) <?> "function declaration"
398{-| Parses a function declaration
402 DocComment_t? FnOpts* Accessibility? FnOpts* FnName TypeSig Terminator
409fnDecl' :: SyntaxInfo -> IdrisParser PDecl
410fnDecl' syn = checkFixity $
411 do (doc, argDocs, fc, opts', n, nfc, acc) <- try (do
413 (doc, argDocs) <- docstring syn
415 let initOpts = if default_total ist
418 opts <- fnOpts initOpts
419 acc <- optional accessibility
421 (n_in, nfc) <- fnName
422 let n = expandNS syn n_in
425 return (doc, argDocs, fc, opts', n, nfc, acc))
426 ty <- typeExpr (allowImp syn)
429 return (PTy doc argDocs syn fc opts' n nfc ty)
433 <?> "function declaration"
434 where checkFixity :: IdrisParser PDecl -> IdrisParser PDecl
435 checkFixity p = do decl <- p
437 Nothing -> return decl
438 Just n -> do fOk <- fixityOK n
440 "Missing fixity declaration for " ++ show n
442 getName (PTy _ _ _ _ _ n _ _) = Just n
444 fixityOK (NS n _) = fixityOK n
445 fixityOK (UN n) | all (flip elem opChars) (str n) =
446 do fixities <- fmap idris_infixes get
447 return . elem (str n) . map (\ (Fix _ op) -> op) $ fixities
448 | otherwise = return True
449 fixityOK _ = return True
451{-| Parses function options given initial options
460 | '%' 'error_handler'
462 | '%' 'specialise' '[' NameTimesList? ']'
467NameTimes ::= FnName Natural?;
473 | NameTimes ',' NameTimesList
477-- FIXME: Check compatability for function options (i.e. partal/total)
479-- Issue #1574 on the issue tracker.
480-- https://github.com/idris-lang/Idris-dev/issues/1574
481fnOpts :: [FnOpt] -> IdrisParser [FnOpt]
483 = do reserved "total"; fnOpts (TotalFn : opts)
484 <|> do reserved "partial"; fnOpts (PartialFn : (opts \\ [TotalFn]))
485 <|> do reserved "covering"; fnOpts (CoveringFn : (opts \\ [TotalFn]))
486 <|> do try (lchar '%' *> reserved "export"); c <- fmap fst stringLiteral;
487 fnOpts (CExport c : opts)
488 <|> do try (lchar '%' *> reserved "no_implicit");
489 fnOpts (NoImplicit : opts)
490 <|> do try (lchar '%' *> reserved "inline");
491 fnOpts (Inlinable : opts)
492 <|> do try (lchar '%' *> reserved "assert_total");
493 fnOpts (AssertTotal : opts)
494 <|> do try (lchar '%' *> reserved "error_handler");
495 fnOpts (ErrorHandler : opts)
496 <|> do try (lchar '%' *> reserved "error_reverse");
497 fnOpts (ErrorReverse : opts)
498 <|> do try (lchar '%' *> reserved "reflection");
499 fnOpts (Reflection : opts)
500 <|> do try (lchar '%' *> reserved "hint");
501 fnOpts (AutoHint : opts)
502 <|> do lchar '%'; reserved "specialise";
503 lchar '['; ns <- sepBy nameTimes (lchar ','); lchar ']'
504 fnOpts (Specialise ns : opts)
505 <|> do reserved "implicit"; fnOpts (Implicit : opts)
507 <?> "function modifier"
508 where nameTimes :: IdrisParser (Name, Maybe Int)
509 nameTimes = do n <- fst <$> fnName
510 t <- option Nothing (do reds <- fmap fst natural
511 return (Just (fromInteger reds)))
514{- | Parses a postulate
518 DocComment_t? 'postulate' FnOpts* Accesibility? FnOpts* FnName TypeSig Terminator
522postulate :: SyntaxInfo -> IdrisParser PDecl
523postulate syn = do (doc, ext)
524 <- try $ do (doc, _) <- docstring syn
529 let initOpts = if default_total ist
532 opts <- fnOpts initOpts
533 acc <- optional accessibility
535 n_in <- fst <$> fnName
536 let n = expandNS syn n_in
538 ty <- typeExpr (allowImp syn)
542 return (PPostulate ext doc syn fc opts' n ty)
544 where ppostDecl = do reserved "postulate"; return False
545 <|> do lchar '%'; reserved "extern"; return True
546{- | Parses a using declaration
550 'using' '(' UsingDeclList ')' OpenBlock Decl* CloseBlock
554using_ :: SyntaxInfo -> IdrisParser [PDecl]
556 do reserved "using"; lchar '('; ns <- usingDeclList syn; lchar ')'
558 let uvars = using syn
559 ds <- many (decl (syn { using = uvars ++ ns }))
562 <?> "using declaration"
564{- | Parses a parameters declaration
568 'parameters' '(' TypeDeclList ')' OpenBlock Decl* CloseBlock
572params :: SyntaxInfo -> IdrisParser [PDecl]
574 do reserved "parameters"; lchar '('; ns <- typeDeclList syn; lchar ')'
575 let ns' = [(n, ty) | (n, _, ty) <- ns]
577 let pvars = syn_params syn
578 ds <- many (decl syn { syn_params = pvars ++ ns' })
581 return [PParams fc ns' (concat ds)]
582 <?> "parameters declaration"
584{- | Parses a mutual declaration (for mutually recursive functions)
588 'mutual' OpenBlock Decl* CloseBlock
592mutual :: SyntaxInfo -> IdrisParser [PDecl]
596 let pvars = syn_params syn
597 ds <- many (decl (syn { mut_nesting = mut_nesting syn + 1 } ))
600 return [PMutual fc (concat ds)]
603{-| Parses a namespace declaration
607 'namespace' identifier OpenBlock Decl+ CloseBlock
611namespace :: SyntaxInfo -> IdrisParser [PDecl]
613 do reserved "namespace"
614 (n, nfc) <- identifier
616 ds <- some (decl syn { syn_namespace = n : syn_namespace syn })
618 return [PNamespace n nfc (concat ds)]
619 <?> "namespace declaration"
621{- | Parses a methods block (for instances)
624 InstanceBlock ::= 'where' OpenBlock FnDecl* CloseBlock
627instanceBlock :: SyntaxInfo -> IdrisParser [PDecl]
628instanceBlock syn = do reserved "where"
630 ds <- many (fnDecl syn)
635{- | Parses a methods and instances block (for type classes)
646 'where' OpenBlock Constructor? MethodOrInstance* CloseBlock
650classBlock :: SyntaxInfo -> IdrisParser (Maybe (Name, FC), Docstring (Either Err PTerm), [PDecl])
651classBlock syn = do reserved "where"
653 (cn, cd) <- option (Nothing, emptyDocstring) $
654 try (do (doc, _) <- option noDocs docComment
656 return (Just n, doc))
658 let cd' = annotate syn ist cd
660 ds <- many (notEndBlock >> instance_ syn <|> fnDecl syn)
662 return (cn, cd', concat ds)
666 constructor :: IdrisParser (Name, FC)
667 constructor = reserved "constructor" *> fnName
669 annotate :: SyntaxInfo -> IState -> Docstring () -> Docstring (Either Err PTerm)
670 annotate syn ist = annotCode $ tryFullExpr syn ist
672{-| Parses a type class declaration
677 | '(' Name ':' Expr ')'
683 DocComment_t? Accessibility? 'class' ConstraintList? Name ClassArgument* ClassBlock?
687class_ :: SyntaxInfo -> IdrisParser [PDecl]
688class_ syn = do (doc, argDocs, acc)
689 <- try (do (doc, argDocs) <- docstring syn
690 acc <- optional accessibility
692 return (doc, argDocs, acc))
694 cons <- constraintList syn
695 let cons' = [(c, ty) | (c, _, ty) <- cons]
696 (n_in, nfc) <- fnName
697 let n = expandNS syn n_in
699 fds <- option [(cn, NoFC) | (cn, _, _) <- cs] fundeps
700 (cn, cd, ds) <- option (Nothing, fst noDocs, []) (classBlock syn)
701 accData acc n (concatMap declared ds)
702 return [PClass doc syn fc cons' n nfc cs argDocs fds ds cn cd]
703 <?> "type-class declaration"
705 fundeps :: IdrisParser [(Name, FC)]
706 fundeps = do lchar '|'; sepBy name (lchar ',')
708 carg :: IdrisParser (Name, FC, PTerm)
709 carg = do lchar '('; (i, ifc) <- name; lchar ':'; ty <- expr syn; lchar ')'
711 <|> do (i, ifc) <- name
713 return (i, ifc, PType fc)
715{- | Parses a type class instance declaration
719 DocComment_t? 'instance' InstanceName? ConstraintList? Name SimpleExpr* InstanceBlock?
724InstanceName ::= '[' Name ']';
727instance_ :: SyntaxInfo -> IdrisParser [PDecl]
728instance_ syn = do (doc, argDocs)
729 <- try (docstring syn <* reserved "instance")
731 en <- optional instanceName
732 cs <- constraintList syn
733 let cs' = [(c, ty) | (c, _, ty) <- cs]
735 args <- many (simpleExpr syn)
736 let sc = PApp fc (PRef cnfc cn) (map pexp args)
737 let t = bindList (PPi constraint) cs sc
738 ds <- option [] (instanceBlock syn)
739 return [PInstance doc argDocs syn fc cs' cn cnfc args t en ds]
740 <?> "instance declaration"
741 where instanceName :: IdrisParser Name
742 instanceName = do lchar '['; n_in <- fst <$> fnName; lchar ']'
743 let n = expandNS syn n_in
748-- | Parse a docstring
749docstring :: SyntaxInfo
750 -> IdrisParser (Docstring (Either Err PTerm),
751 [(Name,Docstring (Either Err PTerm))])
752docstring syn = do (doc, argDocs) <- option noDocs docComment
754 let doc' = annotCode (tryFullExpr syn ist) doc
755 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
756 | (n, d) <- argDocs ]
757 return (doc', argDocs')
760{- | Parses a using declaration list
772 | UsingDecl ',' UsingDeclList'
783usingDeclList :: SyntaxInfo -> IdrisParser [Using]
785 = try (sepBy1 (usingDecl syn) (lchar ','))
786 <|> do ns <- sepBy1 (fst <$> name) (lchar ',')
788 t <- typeExpr (disallowImp syn)
789 return (map (\x -> UImplicit x t) ns)
790 <?> "using declaration list"
792{- |Parses a using declaration
801usingDecl :: SyntaxInfo -> IdrisParser Using
802usingDecl syn = try (do x <- fst <$> fnName
804 t <- typeExpr (disallowImp syn)
805 return (UImplicit x t))
806 <|> do c <- fst <$> fnName
807 xs <- some (fst <$> fnName)
808 return (UConstraint c xs)
809 <?> "using declaration"
811{- | Parse a clause with patterns
817pattern :: SyntaxInfo -> IdrisParser PDecl
818pattern syn = do fc <- getFC
820 return (PClauses fc [] (sMN 2 "_") [clause]) -- collect together later
823{- | Parse a constant applicative form declaration
826CAF ::= 'let' FnName '=' Expr Terminator;
829caf :: SyntaxInfo -> IdrisParser PDecl
830caf syn = do reserved "let"
831 n_in <- fst <$> fnName; let n = expandNS syn n_in
837 <?> "constant applicative form declaration"
839{- | Parse an argument expression
842ArgExpr ::= HSimpleExpr | {- In Pattern External (User-defined) Expression -};
845argExpr :: SyntaxInfo -> IdrisParser PTerm
846argExpr syn = let syn' = syn { inPattern = True } in
847 try (hsimpleExpr syn') <|> simpleExternalExpr syn'
848 <?> "argument expression"
850{- | Parse a right hand side of a function
860RHSName ::= '{' FnName '}';
863rhs :: SyntaxInfo -> Name -> IdrisParser PTerm
864rhs syn n = do lchar '='; expr syn
867 name <- option n' (do symbol "{"; n <- fst <$> fnName; symbol "}";
870 return (addLet fc name r)
872 <?> "function right hand side"
873 where mkN :: Name -> Name
874 mkN (UN x) = if (tnull x || not (isAlpha (thead x)))
875 then sUN "infix_op_lemma_1"
876 else sUN (str x++"_lemma_1")
877 mkN (NS x n) = NS (mkN x) n
880 addLet :: FC -> Name -> PTerm -> PTerm
881 addLet fc nm (PLet fc' n nfc ty val r) = PLet fc' n nfc ty val (addLet fc nm r)
882 addLet fc nm (PCase fc' t cs) = PCase fc' t (map addLetC cs)
883 where addLetC (l, r) = (l, addLet fc nm r)
884 addLet fc nm r = (PLet fc (sUN "value") NoFC Placeholder r (PMetavar NoFC nm))
886{- |Parses a function clause
889RHSOrWithBlock ::= RHS WhereOrTerminator
890 | 'with' SimpleExpr OpenBlock FnDecl+ CloseBlock
895Clause ::= WExpr+ RHSOrWithBlock
896 | SimpleExpr '<==' FnName RHS WhereOrTerminator
897 | ArgExpr Operator ArgExpr WExpr* RHSOrWithBlock {- Except "=" and "?=" operators to avoid ambiguity -}
898 | FnName ConstraintArg* ImplicitOrArgExpr* WExpr* RHSOrWithBlock
903ImplicitOrArgExpr ::= ImplicitArg | ArgExpr;
907WhereOrTerminator ::= WhereBlock | Terminator;
910clause :: SyntaxInfo -> IdrisParser PClause
912 = do wargs <- try (do pushIndent; some (wExpr syn))
915 n <- case lastParse ist of
917 Nothing -> fail "Invalid clause"
919 let ctxt = tt_ctxt ist
920 let wsyn = syn { syn_namespace = [] }
921 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
926 return $ PClauseR fc wargs r wheres) <|> (do
929 wval <- simpleExpr syn
932 ds <- some $ fnDecl syn
933 let withs = concat ds
935 return $ PWithR fc wargs wval pn withs)
936 <|> do ty <- try (do pushIndent
941 n_in <- fst <$> fnName; let n = expandNS syn n_in
944 let ctxt = tt_ctxt ist
945 let wsyn = syn { syn_namespace = [] }
946 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
951 let capp = PLet fc (sMN 0 "match") NoFC
954 (PRef fc (sMN 0 "match"))
956 put (ist { lastParse = Just n })
957 return $ PClause fc n capp [] r wheres
958 <|> do (l, op, nfc) <- try (do
961 (op, nfc) <- operatorFC
962 when (op == "=" || op == "?=" ) $
963 fail "infix clause definition with \"=\" and \"?=\" not supported "
965 let n = expandNS syn (sUN op)
968 wargs <- many (wExpr syn)
970 let wsyn = syn { syn_namespace = [] }
971 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
977 let capp = PApp fc (PRef nfc n) [pexp l, pexp r]
978 put (ist { lastParse = Just n })
979 return $ PClause fc n capp wargs rs wheres) <|> (do
982 wval <- bracketed syn
985 ds <- some $ fnDecl syn
988 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
989 let withs = map (fillLHSD n capp wargs) $ concat ds
990 put (ist { lastParse = Just n })
991 return $ PWith fc n capp wargs wval pn withs)
993 (n_in, nfc) <- fnName; let n = expandNS syn n_in
994 cargs <- many (constraintArg syn)
996 args <- many (try (implicitArg (syn { inPattern = True } ))
997 <|> (fmap pexp (argExpr syn)))
998 wargs <- many (wExpr syn)
999 let capp = PApp fc (PRef nfc n)
1003 let ctxt = tt_ctxt ist
1004 let wsyn = syn { syn_namespace = [] }
1005 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
1011 put (ist { lastParse = Just n })
1012 return $ PClause fc n capp wargs r wheres) <|> (do
1015 put (ist { lastParse = Just n })
1016 wval <- bracketed syn
1019 ds <- some $ fnDecl syn
1020 let withs = map (fillLHSD n capp wargs) $ concat ds
1023 return $ PWith fc n capp wargs wval pn withs)
1024 <?> "function clause"
1026 optProof = option Nothing (do reserved "proof"
1030 fillLHS :: Name -> PTerm -> [PTerm] -> PClause -> PClause
1031 fillLHS n capp owargs (PClauseR fc wargs v ws)
1032 = PClause fc n capp (owargs ++ wargs) v ws
1033 fillLHS n capp owargs (PWithR fc wargs v pn ws)
1034 = PWith fc n capp (owargs ++ wargs) v pn
1035 (map (fillLHSD n capp (owargs ++ wargs)) ws)
1038 fillLHSD :: Name -> PTerm -> [PTerm] -> PDecl -> PDecl
1039 fillLHSD n c a (PClauses fc o fn cs) = PClauses fc o fn (map (fillLHS n c a) cs)
1040 fillLHSD n c a x = x
1042{-| Parses with pattern
1048wExpr :: SyntaxInfo -> IdrisParser PTerm
1049wExpr syn = do lchar '|'
1050 expr' (syn { inPattern = True })
1053{- | Parses a where block
1056WhereBlock ::= 'where' OpenBlock Decl+ CloseBlock;
1059whereBlock :: Name -> SyntaxInfo -> IdrisParser ([PDecl], [(Name, Name)])
1061 = do reserved "where"
1062 ds <- indentedBlock1 (decl syn)
1063 let dns = concatMap (concatMap declared) ds
1064 return (concat ds, map (\x -> (x, decoration syn x)) dns)
1067{- |Parses a code generation target language name
1079codegen_ :: IdrisParser Codegen
1080codegen_ = do n <- fst <$> identifier
1081 return (Via (map toLower n))
1082 <|> do reserved "Bytecode"; return Bytecode
1083 <?> "code generation language"
1085{- |Parses a compiler directive
1089 | String ',' StringList
1094Directive ::= '%' Directive';
1098Directive' ::= 'lib' CodeGen String_t
1099 | 'link' CodeGen String_t
1100 | 'flag' CodeGen String_t
1101 | 'include' CodeGen String_t
1104 | 'access' Accessibility
1105 | 'default' Totality
1107 | 'dynamic' StringList
1108 | 'name' Name NameList
1109 | 'error_handlers' Name NameList
1110 | 'language' 'TypeProviders'
1111 | 'language' 'ErrorReflection'
1115directive :: SyntaxInfo -> IdrisParser [PDecl]
1116directive syn = do try (lchar '%' *> reserved "lib")
1118 lib <- fmap fst stringLiteral
1119 return [PDirective (DLib cgn lib)]
1120 <|> do try (lchar '%' *> reserved "link")
1121 cgn <- codegen_; obj <- fst <$> stringLiteral
1122 return [PDirective (DLink cgn obj)]
1123 <|> do try (lchar '%' *> reserved "flag")
1124 cgn <- codegen_; flag <- fst <$> stringLiteral
1125 return [PDirective (DFlag cgn flag)]
1126 <|> do try (lchar '%' *> reserved "include")
1128 hdr <- fst <$> stringLiteral
1129 return [PDirective (DInclude cgn hdr)]
1130 <|> do try (lchar '%' *> reserved "hide"); n <- fst <$> fnName
1131 return [PDirective (DHide n)]
1132 <|> do try (lchar '%' *> reserved "freeze"); n <- fst <$> iName []
1133 return [PDirective (DFreeze n)]
1134 <|> do try (lchar '%' *> reserved "access"); acc <- accessibility
1135 return [PDirective (DAccess acc)]
1136 <|> do try (lchar '%' *> reserved "default"); tot <- totality
1138 put (i { default_total = tot } )
1139 return [PDirective (DDefault tot)]
1140 <|> do try (lchar '%' *> reserved "logging")
1141 i <- fst <$> natural
1142 return [PDirective (DLogging i)]
1143 <|> do try (lchar '%' *> reserved "dynamic")
1144 libs <- sepBy1 (fmap fst stringLiteral) (lchar ',')
1145 return [PDirective (DDynamicLibs libs)]
1146 <|> do try (lchar '%' *> reserved "name")
1147 ty <- fst <$> fnName
1148 ns <- sepBy1 (fst <$> name) (lchar ',')
1149 return [PDirective (DNameHint ty ns)]
1150 <|> do try (lchar '%' *> reserved "error_handlers")
1151 fn <- fst <$> fnName
1152 arg <- fst <$> fnName
1153 ns <- sepBy1 (fst <$> name) (lchar ',')
1154 return [PDirective (DErrorHandlers fn arg ns) ]
1155 <|> do try (lchar '%' *> reserved "language"); ext <- pLangExt;
1156 return [PDirective (DLanguage ext)]
1158 try (lchar '%' *> reserved "used")
1159 fn <- fst <$> fnName
1160 arg <- fst <$> iName []
1161 return [PDirective (DUsed fc fn arg)]
1164pLangExt :: IdrisParser LanguageExt
1165pLangExt = (reserved "TypeProviders" >> return TypeProviders)
1166 <|> (reserved "ErrorReflection" >> return ErrorReflection)
1168{- | Parses a totality
1171Totality ::= 'partial' | 'total'
1175totality :: IdrisParser Bool
1177 = do reserved "total"; return True
1178 <|> do reserved "partial"; return False
1180{- | Parses a type provider
1183Provider ::= DocComment_t? '%' 'provide' Provider_What? '(' FnName TypeSig ')' 'with' Expr;
1184ProviderWhat ::= 'proof' | 'term' | 'type' | 'postulate'
1187provider :: SyntaxInfo -> IdrisParser [PDecl]
1188provider syn = do doc <- try (do (doc, _) <- docstring syn
1192 provideTerm doc <|> providePostulate doc
1194 where provideTerm doc =
1195 do lchar '('; n <- fst <$> fnName; lchar ':'; t <- typeExpr syn; lchar ')'
1198 e <- expr syn <?> "provider expression"
1199 return [PProvider doc syn fc (ProvTerm t e) n]
1200 providePostulate doc =
1201 do reserved "postulate"
1205 e <- expr syn <?> "provider expression"
1206 return [PProvider doc syn fc (ProvPostulate e) n]
1208{- | Parses a transform
1211Transform ::= '%' 'transform' Expr '==>' Expr
1214transform :: SyntaxInfo -> IdrisParser [PDecl]
1215transform syn = do try (lchar '%' *> reserved "transform")
1216 -- leave it unchecked, until we work out what this should
1218-- safety <- option True (do reserved "unsafe"
1224 return [PTransform fc False l r]
1228{- * Loading and parsing -}
1229{- | Parses an expression from input -}
1230parseExpr :: IState -> String -> Result PTerm
1231parseExpr st = runparser (fullExpr defaultSyntax) st "(input)"
1233{- | Parses a constant form input -}
1234parseConst :: IState -> String -> Result Const
1235parseConst st = runparser (fmap fst constant) st "(input)"
1237{- | Parses a tactic from input -}
1238parseTactic :: IState -> String -> Result PTactic
1239parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
1241-- | Parse module header and imports
1242parseImports :: FilePath -> String -> Idris (Maybe (Docstring ()), [String], [ImportInfo], Maybe Delta)
1243parseImports fname input
1245 case parseString (runInnerParser (evalStateT imports i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
1246 Failure err -> fail (show err)
1247 Success (x, annots, i) ->
1249 fname' <- runIO $ Dir.makeAbsolute fname
1250 sendHighlighting $ addPath annots fname'
1252 where imports :: IdrisParser ((Maybe (Docstring ()), [String],
1255 [(FC, OutputAnnotation)], IState)
1256 imports = do whiteSpace
1257 (mdoc, mname, annots) <- moduleHeader
1260 isEof <- lookAheadMatches eof
1265 return ((mdoc, mname, ps, mrk'), annots, i)
1266 addPath :: [(FC, OutputAnnotation)] -> FilePath -> [(FC, OutputAnnotation)]
1268 addPath ((fc, AnnNamespace ns Nothing) : annots) path =
1269 (fc, AnnNamespace ns (Just path)) : addPath annots path
1270 addPath (annot:annots) path = annot : addPath annots path
1272-- | There should be a better way of doing this...
1273findFC :: Doc -> (FC, String)
1274findFC x = let s = show (plain x) in
1275 case span (/= ':') s of
1276 (failname, ':':rest) -> case span isDigit rest of
1277 (line, ':':rest') -> case span isDigit rest' of
1278 (col, ':':msg) -> let pos = (read line, read col) in
1279 (FC failname pos pos, msg)
1281-- | Check if the coloring matches the options and corrects if necessary
1282fixColour :: Bool -> ANSI.Doc -> ANSI.Doc
1283fixColour False doc = ANSI.plain doc
1284fixColour True doc = doc
1286-- | A program is a list of declarations, possibly with associated
1287-- documentation strings.
1288parseProg :: SyntaxInfo -> FilePath -> String -> Maybe Delta ->
1290parseProg syn fname input mrk
1292 case runparser mainProg i fname input of
1293 Failure doc -> do -- FIXME: Get error location from trifecta
1294 -- this can't be the solution!
1295 -- Issue #1575 on the issue tracker.
1296 -- https://github.com/idris-lang/Idris-dev/issues/1575
1297 let (fc, msg) = findFC doc
1299 case idris_outputmode i of
1300 RawOutput h -> iputStrLn (show $ fixColour (idris_colourRepl i) doc)
1301 IdeMode n h -> iWarn fc (P.text msg)
1302 putIState (i { errSpan = Just fc })
1304 Success (x, i) -> do putIState i
1305 reportParserWarnings
1307 where mainProg :: IdrisParser ([PDecl], IState)
1308 mainProg = case mrk of
1309 Nothing -> do i <- get; return ([], i)
1316{- | Load idris module and show error if something wrong happens -}
1317loadModule :: FilePath -> Idris (Maybe String)
1319 = idrisCatch (loadModule' f)
1320 (\e -> do setErrSpan (getErrSpan e)
1322 iWarn (getErrSpan e) $ pprintErr ist e
1325{- | Load idris module -}
1326loadModule' :: FilePath -> Idris (Maybe String)
1329 let file = takeWhile (/= ' ') f
1330 ibcsd <- valIBCSubDir i
1331 ids <- allImportDirs
1332 fp <- findImport ids ibcsd file
1333 if file `elem` imported i
1334 then do iLOG $ "Already read " ++ file
1336 else do putIState (i { imported = file : imported i })
1338 IDR fn -> loadSource False fn Nothing
1339 LIDR fn -> loadSource True fn Nothing
1341 idrisCatch (loadIBC True fn)
1342 (\c -> do iLOG $ fn ++ " failed " ++ pshow i c
1344 IDR sfn -> loadSource False sfn Nothing
1345 LIDR sfn -> loadSource True sfn Nothing)
1348{- | Load idris code from file -}
1349loadFromIFile :: Bool -> IFileType -> Maybe Int -> Idris ()
1350loadFromIFile reexp i@(IBC fn src) maxline
1351 = do iLOG $ "Skipping " ++ getSrcFile i
1352 idrisCatch (loadIBC reexp fn)
1353 (\err -> ierror $ LoadingFailed fn err)
1355 getSrcFile (IDR fn) = fn
1356 getSrcFile (LIDR fn) = fn
1357 getSrcFile (IBC f src) = getSrcFile src
1359loadFromIFile _ (IDR fn) maxline = loadSource' False fn maxline
1360loadFromIFile _ (LIDR fn) maxline = loadSource' True fn maxline
1362{-| Load idris source code and show error if something wrong happens -}
1363loadSource' :: Bool -> FilePath -> Maybe Int -> Idris ()
1364loadSource' lidr r maxline
1365 = idrisCatch (loadSource lidr r maxline)
1366 (\e -> do setErrSpan (getErrSpan e)
1369 At f e' -> iWarn f (pprintErr ist e')
1370 _ -> iWarn (getErrSpan e) (pprintErr ist e))
1372{- | Load Idris source code-}
1373loadSource :: Bool -> FilePath -> Maybe Int -> Idris ()
1374loadSource lidr f toline
1375 = do iLOG ("Reading " ++ f)
1377 let def_total = default_total i
1378 file_in <- runIO $ readSource f
1379 file <- if lidr then tclift $ unlit f file_in else return file_in
1380 (mdocs, mname, imports_in, pos) <- parseImports f file
1381 ai <- getAutoImports
1382 let imports = map (\n -> ImportInfo True n Nothing [] NoFC NoFC) ai ++ imports_in
1383 ids <- allImportDirs
1384 ibcsd <- valIBCSubDir i
1385 mapM_ (\(re, f, ns, nfc) ->
1386 do fp <- findImport ids ibcsd f
1388 LIDR fn -> ifail $ "No ibc for " ++ f
1389 IDR fn -> ifail $ "No ibc for " ++ f
1392 let srcFn = case src of
1396 srcFnAbs <- case srcFn of
1397 Just fn -> fmap Just (runIO $ Dir.makeAbsolute fn)
1398 Nothing -> return Nothing
1399 sendHighlighting [(nfc, AnnNamespace ns srcFnAbs)])
1400 [(re, fn, ns, nfc) | ImportInfo re fn _ ns _ nfc <- imports]
1401 reportParserWarnings
1403 -- process and check module aliases
1404 let modAliases = M.fromList
1405 [ (prep alias, prep realName)
1406 | ImportInfo { import_reexport = reexport
1407 , import_path = realName
1408 , import_rename = Just (alias, _)
1409 , import_location = fc } <- imports
1411 prep = map T.pack . reverse . Spl.splitOn [pathSeparator]
1412 aliasNames = [ (alias, fc)
1413 | ImportInfo { import_rename = Just (alias, _)
1414 , import_location = fc } <- imports
1416 histogram = groupBy ((==) `on` fst) . sortBy (comparing fst) $ aliasNames
1417 case map head . filter ((/= 1) . length) $ histogram of
1418 [] -> logLvl 3 $ "Module aliases: " ++ show (M.toList modAliases)
1419 (n,fc):_ -> throwError . At fc . Msg $ "import alias not unique: " ++ show n
1422 putIState (i { default_access = Hidden, module_aliases = modAliases })
1423 clearIBC -- start a new .ibc file
1424 -- record package info in .ibc
1425 imps <- allImportDirs
1426 mapM_ addIBC (map IBCImportDir imps)
1427 mapM_ (addIBC . IBCImport)
1428 [ (reexport, realName)
1429 | ImportInfo { import_reexport = reexport
1430 , import_path = realName
1433 let syntax = defaultSyntax{ syn_namespace = reverse mname,
1436 -- Save the span from parsing the module header, because
1437 -- an empty program parse might obliterate it.
1438 let oldSpan = idris_parsedSpan ist
1439 ds' <- parseProg syntax f file pos
1441 case (ds', oldSpan) of
1443 -- If no program elements were parsed, we dind't
1444 -- get a loaded region in the IBC file. That
1445 -- means we need to add it back.
1447 putIState ist { idris_parsedSpan = oldSpan
1448 , ibc_write = IBCParsedRegion fc :
1453 -- Parsing done, now process declarations
1455 let ds = namespaces mname ds'
1456 logLvl 3 (show $ showDecls verbosePPOption ds)
1458 logLvl 10 (show (toAlist (idris_implicits i)))
1459 logLvl 3 (show (idris_infixes i))
1460 -- Now add all the declarations to the context
1462 when v $ iputStrLn $ "Type checking " ++ f
1463 -- we totality check after every Mutual block, so if
1464 -- anything is a single definition, wrap it in a
1465 -- mutual block on its own
1466 elabDecls toplevel (map toMutual ds)
1468 -- simplify every definition do give the totality checker
1470 mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
1471 updateContext (simplifyCasedef n $ getErasureInfo i))
1472 (map snd (idris_totcheck i))
1473 -- build size change graph from simplified definitions
1474 iLOG "Totality checking"
1476 mapM_ buildSCG (idris_totcheck i)
1477 mapM_ checkDeclTotality (idris_totcheck i)
1479 -- Redo totality check for deferred names
1480 let deftots = idris_defertotcheck i
1481 iLOG $ "Totality checking " ++ show deftots
1482 mapM_ (\x -> do tot <- getTotality x
1484 Total _ -> setTotality x Unchecked
1485 _ -> return ()) (map snd deftots)
1486 mapM_ buildSCG deftots
1487 mapM_ checkDeclTotality deftots
1489 iLOG ("Finished " ++ f)
1490 ibcsd <- valIBCSubDir i
1491 iLOG "Universe checking"
1493 let ibc = ibcPathNoFallback ibcsd f
1495 addHides (hide_list i)
1497 -- Save module documentation if applicable
1500 Nothing -> return ()
1501 Just docs -> addModDoc syntax mname docs
1504 -- Finally, write an ibc if checking was successful
1507 idrisCatch (do writeIBC f ibc; clearIBC)
1508 (\c -> return ()) -- failure is harmless
1510 putIState (i { default_total = def_total,
1514 namespaces :: [String] -> [PDecl] -> [PDecl]
1515 namespaces [] ds = ds
1516 namespaces (x:xs) ds = [PNamespace x NoFC (namespaces xs ds)]
1518 toMutual :: PDecl -> PDecl
1519 toMutual m@(PMutual _ d) = m
1520 toMutual (PNamespace x fc ds) = PNamespace x fc (map toMutual ds)
1521 toMutual x = let r = PMutual (fileFC "single mutual") [x] in
1529 addModDoc :: SyntaxInfo -> [String] -> Docstring () -> Idris ()
1530 addModDoc syn mname docs =
1532 docs' <- elabDocTerms recinfo (parsedDocs ist)
1533 let modDocs' = addDef docName docs' (idris_moduledocs ist)
1534 putIState ist { idris_moduledocs = modDocs' }
1535 addIBC (IBCModDocs docName)
1537 docName = NS modDocName (map T.pack (reverse mname))
1538 parsedDocs ist = annotCode (tryFullExpr syn ist) docs
1540{- | Adds names to hide list -}
1541addHides :: [(Name, Maybe Accessibility)] -> Idris ()
1542addHides xs = do i <- getIState
1543 let defh = default_access i
1544 let (hs, as) = partition isNothing xs
1547 (map (\ (n, _) -> (n, defh)) hs ++
1548 map (\ (n, Just a) -> (n, a)) as)
1549 where isNothing (_, Nothing) = True
1552 doHide (n, a) = do setAccessibility n a
1553 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