3Description : Idris' parser.
6Maintainer : The Idris Community.
9{-# LANGUAGE ConstraintKinds, FlexibleContexts, GeneralizedNewtypeDeriving,
11{-# OPTIONS_GHC -O0 #-}
12-- FIXME: {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
13{-# OPTIONS_GHC -fwarn-unused-imports #-}
15module Idris.Parser(IdrisParser(..), ImportInfo(..), addReplSyntax, clearParserWarnings,
16 decl, fixColour, loadFromIFile, loadModule, name, opChars, parseElabShellStep, parseConst, parseExpr, parseImports, parseTactic,
17 runparser, ParseError, parseErrorDoc) where
19import Idris.AbsSyntax hiding (namespace, params)
20import Idris.Core.Evaluate
22import Idris.Delaborate
23import Idris.Docstrings hiding (Unchecked)
25import Idris.Elab.Value
32import Idris.Parser.Data
33import Idris.Parser.Expr
34import Idris.Parser.Helpers
35import Idris.Parser.Ops
36import Idris.Termination
39import qualified Util.Pretty
40import Util.System (readSource)
42import Prelude hiding (pi)
44import Control.Applicative hiding (Const)
46import Control.Monad.State.Strict
48import Data.Foldable (asum)
50import Data.Generics.Uniplate.Data (descendM)
52import qualified Data.List.NonEmpty as NonEmpty
53import qualified Data.List.Split as Spl
54import qualified Data.Map as M
57import qualified Data.Text as T
58import qualified System.Directory as Dir (makeAbsolute)
60import Text.Megaparsec ((<?>))
61import qualified Text.Megaparsec as P
62import qualified Text.Megaparsec.Char as P
63import qualified Text.PrettyPrint.ANSI.Leijen as PP
67 grammar shortcut notation:
68 ~CHARSEQ = complement of char sequence (i.e. any character except CHARSEQ)
69 RULE? = optional rule (i.e. RULE or nothing)
70 RULE* = repeated rule (i.e. RULE zero or more times)
71 RULE+ = repeated rule with at least one match (i.e. RULE one or more times)
72 RULE! = invalid rule (i.e. rule that is not valid in context, report meaningful error in case)
73 RULE{n} = rule repeated n times
79{-| Parses module definition
82 ModuleHeader ::= DocComment_t? 'module' Identifier_t ';'?;
85moduleHeader :: IdrisParser (Maybe (Docstring ()), [String], [(FC, OutputAnnotation)])
86moduleHeader = P.try (do docs <- optional docComment
89 (i, ifc) <- withExtent identifier
90 P.option ';' (lchar ';')
91 let modName = moduleName i
92 return (fmap fst docs,
94 [(ifc, AnnNamespace (map T.pack modName) Nothing)]))
95 <|> P.try (do lchar '%'; reserved "unqualified"
96 return (Nothing, [], []))
97 <|> return (Nothing, moduleName "Main", [])
98 where moduleName x = case span (/='.') x of
100 (x, '.':y) -> x : moduleName y
101 noArgs (Just (_, args)) | not (null args) = fail "Modules do not take arguments"
104data ImportInfo = ImportInfo { import_reexport :: Bool
105 , import_path :: FilePath
106 , import_rename :: Maybe (String, FC)
107 , import_namespace :: [T.Text]
108 , import_location :: FC
109 , import_modname_location :: FC
112{-| Parses an import statement
115 Import ::= 'import' Identifier_t ';'?;
118import_ :: IdrisParser ImportInfo
119import_ = do fc <- extent $ keyword "import"
120 reexport <- P.option False (True <$ keyword "public")
121 (id, idfc) <- withExtent identifier
122 newName <- optional (do keyword "as"
123 withExtent identifier)
124 P.option ';' (lchar ';')
125 return $ ImportInfo reexport (toPath id)
126 (fmap (\(n, fc) -> (toPath n, fc)) newName)
127 (map T.pack $ ns id) fc idfc
128 <?> "import statement"
129 where ns = Spl.splitOn "."
130 toPath = foldl1' (</>) . ns
132{-| Parses program source
138prog :: SyntaxInfo -> IdrisParser [PDecl]
139prog syn = do (decls, fc) <- withExtent $ do
141 decls <- concat <$> many (decl syn)
143 Nothing -> do notOpenBraces; P.eof
147 put ist { idris_parsedSpan = Just (FC (fc_fname fc) (0,0) (fc_end fc)),
148 ibc_write = IBCParsedRegion fc : ibc_write ist }
151{-| Parses a top-level declaration
171decl :: SyntaxInfo -> IdrisParser [PDecl]
172decl syn = P.try (externalDecl syn)
176internalDecl :: SyntaxInfo -> IdrisParser [PDecl]
179 -- if we're after maxline, stop at the next type declaration
180 -- (so we get all cases of a definition to preserve totality
181 -- results, in particular).
182 let continue = case maxline syn of
184 Just l -> if fst (fc_end fc) > l
185 then mut_nesting syn /= 0
187 -- What I'd really like to do here is explicitly save the
188 -- current state, then if reading ahead finds we've passed
189 -- the end of the definition, reset the state. But I've lost
190 -- patience with trying to find out how to do that from the
191 -- trifecta docs, so this does the job instead.
195 else P.try (do notEndBlock
197 <|> fail "End of readable input"
198 where declBody :: Bool -> IdrisParser [PDecl]
200 P.try (implementation syn)
201 <|> P.try (openInterface syn)
208 <|> do d <- dsl syn; return [d]
212 <|> do import_; fail "imports must be at top of file"
214 declBody' :: Bool -> IdrisParser [PDecl]
215 declBody' cont = do d <- decl' syn
217 let d' = fmap (debindApp syn . (desugar syn i)) d
220 else fail "End of readable input"
222 -- Keep going while we're still parsing clauses
223 continue False (PClauses _ _ _ _) = True
226{-| Parses a top-level declaration with possible syntax sugar
238decl' :: SyntaxInfo -> IdrisParser PDecl
247externalDecl :: SyntaxInfo -> IdrisParser [PDecl]
248externalDecl syn = do i <- get
250 (decls, fc@(FC fn _ _)) <- withExtent $ declExtensions syn (syntaxRulesList $ syntax_rules i)
251 return $ map (mapPDeclFC (fixFC fc) (fixFCH fn fc)) decls
253 -- | Fix non-highlighting FCs to prevent spurious error location reports
254 fixFC :: FC -> FC -> FC
255 fixFC outer inner | inner `fcIn` outer = inner
257 -- | Fix highlighting FCs by obliterating them, to avoid spurious highlights
258 fixFCH fn outer inner | inner `fcIn` outer = inner
259 | otherwise = FileFC fn
261declExtensions :: SyntaxInfo -> [Syntax] -> IdrisParser [PDecl]
262declExtensions syn rules = declExtension syn [] (filter isDeclRule rules)
263 <?> "user-defined declaration"
265 isDeclRule (DeclRule _ _) = True
268declExtension :: SyntaxInfo -> [Maybe (Name, SynMatch)] -> [Syntax]
269 -> IdrisParser [PDecl]
270declExtension syn ns rules =
271 P.choice $ flip map (groupBy (ruleGroup `on` syntaxSymbols) rules) $ \rs ->
272 case head rs of -- can never be []
273 DeclRule (symb:_) _ -> P.try $ do
275 declExtension syn (n : ns) [DeclRule ss t | (DeclRule (_:ss) t) <- rs]
276 -- If we have more than one Rule in this bucket, our grammar is
278 DeclRule [] dec -> let r = map (update (mapMaybe id ns)) dec in
282 update :: [(Name, SynMatch)] -> PDecl -> PDecl
283 update ns = updateNs ns . fmap (updateRefs ns) . fmap (updateSynMatch ns)
285 updateRefs ns = mapPT newref
287 newref (PRef fc fcs n) = PRef fc fcs (updateB ns n)
290 -- Below is a lot of tedious boilerplate which updates any top level
291 -- names in the declaration. It will only change names which are bound in
292 -- the declaration (including method names in interfaces and field names in
293 -- record declarations, not including pattern variables)
294 updateB :: [(Name, SynMatch)] -> Name -> Name
295 updateB ns (NS n mods) = NS (updateB ns n) mods
296 updateB ns n = case lookup n ns of
297 Just (SynBind tfc t) -> t
300 updateNs :: [(Name, SynMatch)] -> PDecl -> PDecl
301 updateNs ns (PTy doc argdoc s fc o n fc' t)
302 = PTy doc argdoc s fc o (updateB ns n) fc' t
303 updateNs ns (PClauses fc o n cs)
304 = PClauses fc o (updateB ns n) (map (updateClause ns) cs)
305 updateNs ns (PCAF fc n t) = PCAF fc (updateB ns n) t
306 updateNs ns (PData ds cds s fc o dat)
307 = PData ds cds s fc o (updateData ns dat)
308 updateNs ns (PParams fc ps ds) = PParams fc ps (map (updateNs ns) ds)
309 updateNs ns (PNamespace s fc ds) = PNamespace s fc (map (updateNs ns) ds)
310 updateNs ns (PRecord doc syn fc o n fc' ps pdocs fields cname cdoc s)
311 = PRecord doc syn fc o (updateB ns n) fc' ps pdocs
312 (map (updateField ns) fields)
313 (updateRecCon ns cname)
316 updateNs ns (PInterface docs s fc cs cn fc' ps pdocs pdets ds cname cdocs)
317 = PInterface docs s fc cs (updateB ns cn) fc' ps pdocs pdets
318 (map (updateNs ns) ds)
319 (updateRecCon ns cname)
321 updateNs ns (PImplementation docs pdocs s fc cs pnames acc opts cn fc' ps pextra ity ni ds)
322 = PImplementation docs pdocs s fc cs pnames acc opts (updateB ns cn) fc'
323 ps pextra ity (fmap (updateB ns) ni)
324 (map (updateNs ns) ds)
325 updateNs ns (PMutual fc ds) = PMutual fc (map (updateNs ns) ds)
326 updateNs ns (PProvider docs s fc fc' pw n)
327 = PProvider docs s fc fc' pw (updateB ns n)
330 updateRecCon ns Nothing = Nothing
331 updateRecCon ns (Just (n, fc)) = Just (updateB ns n, fc)
333 updateField ns (m, p, t, doc) = (updateRecCon ns m, p, t, doc)
335 updateClause ns (PClause fc n t ts t' ds)
336 = PClause fc (updateB ns n) t ts t' (map (update ns) ds)
337 updateClause ns (PWith fc n t ts t' m ds)
338 = PWith fc (updateB ns n) t ts t' m (map (update ns) ds)
339 updateClause ns (PClauseR fc ts t ds)
340 = PClauseR fc ts t (map (update ns) ds)
341 updateClause ns (PWithR fc ts t m ds)
342 = PWithR fc ts t m (map (update ns) ds)
344 updateData ns (PDatadecl n fc t cs)
345 = PDatadecl (updateB ns n) fc t (map (updateCon ns) cs)
346 updateData ns (PLaterdecl n fc t)
347 = PLaterdecl (updateB ns n) fc t
349 updateCon ns (cd, ads, cn, fc, ty, fc', fns)
350 = (cd, ads, updateB ns cn, fc, ty, fc', fns)
352 ruleGroup [] [] = True
353 ruleGroup (s1:_) (s2:_) = s1 == s2
354 ruleGroup _ _ = False
356 extSymbol :: SSymbol -> IdrisParser (Maybe (Name, SynMatch))
357 extSymbol (Keyword n) = Nothing <$ keyword (show n)
358 extSymbol (Expr n) = do tm <- expr syn
359 return $ Just (n, SynTm tm)
360 extSymbol (SimpleExpr n) = do tm <- simpleExpr syn
361 return $ Just (n, SynTm tm)
362 extSymbol (Binding n) = do (b, fc) <- withExtent name
363 return $ Just (n, SynBind fc b)
364 extSymbol (Symbol s) = Nothing <$ highlight AnnKeyword (symbol s)
366{-| Parses a syntax extension declaration (and adds the rule to parser state)
369 SyntaxDecl ::= SyntaxRule;
372syntaxDecl :: SyntaxInfo -> IdrisParser PDecl
373syntaxDecl syn = do (s, fc) <- withExtent $ syntaxRule syn
374 modify $ \i -> i `addSyntax` s
375 return (PSyntax fc s)
377-- | Extend an 'IState' with a new syntax extension. See also 'addReplSyntax'.
378addSyntax :: IState -> Syntax -> IState
379addSyntax i s = i { syntax_rules = updateSyntaxRules [s] rs,
380 syntax_keywords = ks ++ ns,
381 ibc_write = IBCSyntax s : map IBCKeyword ks ++ ibc }
382 where rs = syntax_rules i
383 ns = syntax_keywords i
385 ks = map show (syntaxNames s)
387-- | Like 'addSyntax', but no effect on the IBC.
388addReplSyntax :: IState -> Syntax -> IState
389addReplSyntax i s = i { syntax_rules = updateSyntaxRules [s] rs,
390 syntax_keywords = ks ++ ns }
391 where rs = syntax_rules i
392 ns = syntax_keywords i
393 ks = map show (syntaxNames s)
395{-| Parses a syntax extension declaration
398SyntaxRuleOpts ::= 'term' | 'pattern';
403 SyntaxRuleOpts? 'syntax' SyntaxSym+ '=' TypeExpr Terminator;
407SyntaxSym ::= '[' Name_t ']'
414syntaxRule :: SyntaxInfo -> IdrisParser Syntax
416 = do sty <- P.try (do
418 sty <- P.option AnySyntax
419 (TermSyntax <$ keyword "term"
420 <|> PatternSyntax <$ keyword "pattern")
423 syms <- some syntaxSym
424 when (all isExpr syms) $ P.unexpected . P.Label . NonEmpty.fromList $ "missing keywords in syntax rule"
425 let ns = mapMaybe getName syms
426 when (length ns /= length (nub ns))
427 $ P.unexpected . P.Label . NonEmpty.fromList $ "repeated variable in syntax rule"
429 tm <- typeExpr (allowImp syn) >>= uniquifyBinders [n | Binding n <- syms]
431 return (Rule (mkSimple syms) tm sty)
432 <|> do keyword "decl"; keyword "syntax"
433 syms <- some syntaxSym
434 when (all isExpr syms) $ P.unexpected . P.Label . NonEmpty.fromList $ "missing keywords in syntax rule"
435 let ns = mapMaybe getName syms
436 when (length ns /= length (nub ns))
437 $ P.unexpected . P.Label . NonEmpty.fromList $ "repeated variable in syntax rule"
440 dec <- some (decl syn)
442 return (DeclRule (mkSimple syms) (concat dec))
444 isExpr (Expr _) = True
446 getName (Expr n) = Just n
448 -- Can't parse two full expressions (i.e. expressions with application) in a row
449 -- so change them both to a simple expression
450 mkSimple (Expr e : es) = SimpleExpr e : mkSimple' es
451 mkSimple xs = mkSimple' xs
453 mkSimple' (Expr e : Expr e1 : es) = SimpleExpr e : SimpleExpr e1 :
455 -- Can't parse a full expression followed by operator like characters due to ambiguity
456 mkSimple' (Expr e : Symbol s : es)
457 | takeWhile (`elem` opChars) ts /= "" = SimpleExpr e : Symbol s : mkSimple' es
458 where ts = dropWhile isSpace . dropWhileEnd isSpace $ s
459 mkSimple' (e : es) = e : mkSimple' es
462 -- Prevent syntax variable capture by making all binders under syntax unique
463 -- (the ol' Common Lisp GENSYM approach)
464 uniquifyBinders :: [Name] -> PTerm -> IdrisParser PTerm
465 uniquifyBinders userNames = fixBind 0 []
467 fixBind :: Int -> [(Name, Name)] -> PTerm -> IdrisParser PTerm
468 fixBind 0 rens (PRef fc hls n) | Just n' <- lookup n rens =
469 return $ PRef fc hls n'
470 fixBind 0 rens (PPatvar fc n) | Just n' <- lookup n rens =
471 return $ PPatvar fc n'
472 fixBind 0 rens (PLam fc n nfc ty body)
473 | n `elem` userNames = liftM2 (PLam fc n nfc)
475 (fixBind 0 rens body)
477 do ty' <- fixBind 0 rens ty
479 body' <- fixBind 0 ((n,n'):rens) body
480 return $ PLam fc n' nfc ty' body'
481 fixBind 0 rens (PPi plic n nfc argTy body)
482 | n `elem` userNames = liftM2 (PPi plic n nfc)
483 (fixBind 0 rens argTy)
484 (fixBind 0 rens body)
486 do ty' <- fixBind 0 rens argTy
488 body' <- fixBind 0 ((n,n'):rens) body
489 return $ (PPi plic n' nfc ty' body')
490 fixBind 0 rens (PLet fc rig n nfc ty val body)
491 | n `elem` userNames = liftM3 (PLet fc rig n nfc)
494 (fixBind 0 rens body)
496 do ty' <- fixBind 0 rens ty
497 val' <- fixBind 0 rens val
499 body' <- fixBind 0 ((n,n'):rens) body
500 return $ PLet fc rig n' nfc ty' val' body'
501 fixBind 0 rens (PMatchApp fc n) | Just n' <- lookup n rens =
502 return $ PMatchApp fc n'
503 -- Also rename resolved quotations, to allow syntax rules to
504 -- have quoted references to their own bindings.
505 fixBind 0 rens (PQuoteName n True fc) | Just n' <- lookup n rens =
506 return $ PQuoteName n' True fc
508 -- Don't mess with quoted terms
509 fixBind q rens (PQuasiquote tm goal) =
510 flip PQuasiquote goal <$> fixBind (q + 1) rens tm
511 fixBind q rens (PUnquote tm) =
512 PUnquote <$> fixBind (q - 1) rens tm
514 fixBind q rens x = descendM (fixBind q rens) x
516 gensym :: Name -> IdrisParser Name
517 gensym n = do ist <- get
518 let idx = idris_name ist
519 put ist { idris_name = idx + 1 }
520 return $ sMN idx (show n)
522{-| Parses a syntax symbol (either binding variable, keyword or expression)
525SyntaxSym ::= '[' Name_t ']'
532syntaxSym :: IdrisParser SSymbol
533syntaxSym = P.try (do lchar '['; n <- name; lchar ']'
535 <|> P.try (do lchar '{'; n <- name; lchar '}'
539 <|> do sym <- stringLiteral
543{-| Parses a function declaration with possible syntax sugar
546 FunDecl ::= FunDecl';
549fnDecl :: SyntaxInfo -> IdrisParser [PDecl]
550fnDecl syn = P.try (do notEndBlock
553 let d' = fmap (desugar syn i) d
554 return [d']) <?> "function declaration"
556{-| Parses a function declaration
560 DocComment_t? FnOpts* Accessibility? FnOpts* FnName TypeSig Terminator
567fnDecl' :: SyntaxInfo -> IdrisParser PDecl
568fnDecl' syn = (checkDeclFixity $
569 do (doc, argDocs, fc, opts', n, nfc, acc) <- P.try (do
571 (doc, argDocs) <- docstring syn
572 (opts, acc) <- fnOpts
573 (n_in, nfc) <- withExtent fnName
574 let n = expandNS syn n_in
575 fc <- extent $ lchar ':'
576 return (doc, argDocs, fc, opts, n, nfc, acc))
577 ty <- typeExpr (allowImp syn)
579 -- If it's a top level function, note the accessibility
581 when (syn_toplevel syn) $ addAcc n acc
582 return (PTy doc argDocs syn fc opts' n nfc ty)
586 <?> "function declaration"
588{-| Parses a series of function and accessbility options
591FnOpts ::= FnOpt* Accessibility FnOpt*
594fnOpts :: IdrisParser ([FnOpt], Accessibility)
599 let allOpts = opts ++ opts'
600 let existingTotality = allOpts `intersect` [TotalFn, CoveringFn, PartialFn]
601 opts'' <- addDefaultTotality (nub existingTotality) allOpts
603 where prettyTot TotalFn = "total"
604 prettyTot PartialFn = "partial"
605 prettyTot CoveringFn = "covering"
606 addDefaultTotality [] opts = do
608 case default_total ist of
609 DefaultCheckingTotal -> return (TotalFn:opts)
610 DefaultCheckingCovering -> return (CoveringFn:opts)
611 DefaultCheckingPartial -> return opts -- Don't add partial so that --warn-partial still reports warnings if necessary
612 addDefaultTotality [tot] opts = return opts
613 -- Should really be a semantics error instead of a parser error
614 addDefaultTotality (tot1:tot2:tots) opts =
615 fail ("Conflicting totality modifiers specified " ++ prettyTot tot1 ++ " and " ++ prettyTot tot2)
618{-| Parses a function option
627 | '%' 'error_handler'
629 | '%' 'specialise' '[' NameTimesList? ']'
634NameTimes ::= FnName Natural?;
640 | NameTimes ',' NameTimesList
644fnOpt :: IdrisParser FnOpt
645fnOpt = do keyword "total"; return TotalFn
646 <|> PartialFn <$ keyword "partial"
647 <|> CoveringFn <$ keyword "covering"
648 <|> do P.try (lchar '%' *> reserved "export"); c <- stringLiteral;
650 <|> NoImplicit <$ P.try (lchar '%' *> reserved "no_implicit")
651 <|> Inlinable <$ P.try (lchar '%' *> reserved "inline")
652 <|> StaticFn <$ P.try (lchar '%' *> reserved "static")
653 <|> do fc <- P.try $ extent $ lchar '%' *> reserved "assert_total"
654 parserWarning fc Nothing (Msg "%assert_total is deprecated. Use the 'assert_total' function instead.")
656 <|> ErrorHandler <$ P.try (lchar '%' *> reserved "error_handler")
657 <|> ErrorReverse <$ P.try (lchar '%' *> reserved "error_reverse")
658 <|> ErrorReduce <$ P.try (lchar '%' *> reserved "error_reduce")
659 <|> Reflection <$ P.try (lchar '%' *> reserved "reflection")
660 <|> AutoHint <$ P.try (lchar '%' *> reserved "hint")
661 <|> OverlappingDictionary <$ P.try (lchar '%' *> reserved "overlapping")
662 <|> do lchar '%'; reserved "specialise";
663 lchar '['; ns <- P.sepBy nameTimes (lchar ','); lchar ']';
664 return $ Specialise ns
665 <|> Implicit <$ keyword "implicit"
666 <?> "function modifier"
667 where nameTimes :: IdrisParser (Name, Maybe Int)
668 nameTimes = do n <- fnName
669 t <- P.option Nothing (do reds <- natural
670 return (Just (fromInteger reds)))
673{-| Parses a postulate
677 DocComment_t? 'postulate' FnOpts* Accesibility? FnOpts* FnName TypeSig Terminator
681postulate :: SyntaxInfo -> IdrisParser PDecl
682postulate syn = do (doc, ext)
683 <- P.try $ do (doc, _) <- docstring syn
688 (opts, acc) <- fnOpts
689 (n_in, nfc) <- withExtent fnName
690 let n = expandNS syn n_in
692 ty <- typeExpr (allowImp syn)
693 fc <- extent $ terminator
695 return (PPostulate ext doc syn fc nfc opts n ty)
697 where ppostDecl = do fc <- keyword "postulate"; return False
698 <|> do lchar '%'; reserved "extern"; return True
700{-| Parses a using declaration
704 'using' '(' UsingDeclList ')' OpenBlock Decl* CloseBlock
708using_ :: SyntaxInfo -> IdrisParser [PDecl]
711 lchar '('; ns <- usingDeclList syn; lchar ')'
713 let uvars = using syn
714 ds <- many (decl (syn { using = uvars ++ ns }))
717 <?> "using declaration"
719{-| Parses a parameters declaration
723 'parameters' '(' TypeDeclList ')' OpenBlock Decl* CloseBlock
727params :: SyntaxInfo -> IdrisParser [PDecl]
729 do (ns, fc) <- withExtent $ do
731 lchar '(' *> typeDeclList syn <* lchar ')'
732 let ns' = [(n, ty) | (_, n, _, ty) <- ns]
734 let pvars = syn_params syn
735 ds <- many (decl syn { syn_params = pvars ++ ns' })
737 return [PParams fc ns' (concat ds)]
738 <?> "parameters declaration"
740-- | Parses an open block
741openInterface :: SyntaxInfo -> IdrisParser [PDecl]
743 do (ns, fc) <- withExtent $ do
745 keyword "implementation"
746 P.sepBy1 (withExtent fnName) (lchar ',')
749 ds <- many (decl syn)
751 return [POpenInterfaces fc (map fst ns) (concat ds)]
752 <?> "open interface declaration"
758{-| Parses a mutual declaration (for mutually recursive functions)
762 'mutual' OpenBlock Decl* CloseBlock
766mutual :: SyntaxInfo -> IdrisParser [PDecl]
768 do fc <- extent $ keyword "mutual"
770 ds <- many (decl (syn { mut_nesting = mut_nesting syn + 1 } ))
772 return [PMutual fc (concat ds)]
775{-| Parses a namespace declaration
779 'namespace' identifier OpenBlock Decl+ CloseBlock
783namespace :: SyntaxInfo -> IdrisParser [PDecl]
785 do keyword "namespace"
786 (n, nfc) <- withExtent identifier
788 ds <- some (decl syn { syn_namespace = n : syn_namespace syn })
790 return [PNamespace n nfc (concat ds)]
791 <?> "namespace declaration"
793{-| Parses a methods block (for implementations)
796 ImplementationBlock ::= 'where' OpenBlock FnDecl* CloseBlock
799implementationBlock :: SyntaxInfo -> IdrisParser [PDecl]
800implementationBlock syn = do keyword "where"
802 ds <- many (fnDecl syn)
805 <?> "implementation block"
807{-| Parses a methods and implementations block (for interfaces)
810MethodOrImplementation ::=
818 'where' OpenBlock Constructor? MethodOrImplementation* CloseBlock
822interfaceBlock :: SyntaxInfo -> IdrisParser (Maybe (Name, FC), Docstring (Either Err PTerm), [PDecl])
823interfaceBlock syn = do keyword "where"
825 (cn, cd) <- P.option (Nothing, emptyDocstring) $
826 P.try (do (doc, _) <- P.option noDocs docComment
828 return (Just n, doc))
830 let cd' = annotate syn ist cd
832 ds <- many (notEndBlock >> P.try (implementation syn)
833 <|> do x <- data_ syn
837 return (cn, cd', concat ds)
838 <?> "interface block"
840 constructor :: IdrisParser (Name, FC)
841 constructor = keyword "constructor" *> withExtent fnName
843 annotate :: SyntaxInfo -> IState -> Docstring () -> Docstring (Either Err PTerm)
844 annotate syn ist = annotCode $ tryFullExpr syn ist
846{-| Parses an interface declaration
851 | '(' Name ':' Expr ')'
857 DocComment_t? Accessibility? 'interface' ConstraintList? Name InterfaceArgument* InterfaceBlock?
861interface_ :: SyntaxInfo -> IdrisParser [PDecl]
862interface_ syn = do (doc, argDocs, acc)
863 <- P.try (do (doc, argDocs) <- docstring syn
866 return (doc, argDocs, acc))
867 ((cons', n, nfc, cs, fds), fc) <- withExtent $ do
868 cons <- constraintList syn
869 let cons' = [(c, ty) | (_, c, _, ty) <- cons]
870 (n_in, nfc) <- withExtent fnName
871 let n = expandNS syn n_in
873 fds <- P.option [(cn, NoFC) | (cn, _, _) <- cs] fundeps
874 return (cons', n, nfc, cs, fds)
876 (cn, cd, ds) <- P.option (Nothing, fst noDocs, []) (interfaceBlock syn)
877 accData acc n (concatMap declared ds)
878 return [PInterface doc syn fc cons' n nfc cs argDocs fds ds cn cd]
879 <?> "interface declaration"
881 fundeps :: IdrisParser [(Name, FC)]
882 fundeps = do lchar '|'; P.sepBy (withExtent name) (lchar ',')
884 interfaceKeyword :: IdrisParser ()
885 interfaceKeyword = keyword "interface"
886 <|> do fc <- extent $ keyword "class"
887 parserWarning fc Nothing (Msg "The 'class' keyword is deprecated. Use 'interface' instead.")
889 carg :: IdrisParser (Name, FC, PTerm)
890 carg = do lchar '('; (i, ifc) <- withExtent name; lchar ':'; ty <- expr syn; lchar ')'
892 <|> do (i, ifc) <- withExtent name
893 return (i, ifc, PType ifc)
895{-| Parses an interface implementation declaration
899 DocComment_t? 'implementation' ImplementationName? ConstraintList? Name SimpleExpr* ImplementationBlock?
904ImplementationName ::= '[' Name ']';
907implementation :: SyntaxInfo -> IdrisParser [PDecl]
908implementation syn = do (doc, argDocs) <- docstring syn
909 (opts, acc) <- fnOpts
910 optional implementationKeyword
912 ((en, cs, cs', cn, cnfc, args, pnames), fc) <- withExtent $ do
913 en <- optional implementationName
914 cs <- constraintList syn
915 let cs' = [(c, ty) | (_, c, _, ty) <- cs]
916 (cn, cnfc) <- withExtent fnName
917 args <- many (simpleExpr syn)
918 pnames <- implementationUsing
919 return (en, cs, cs', cn, cnfc, args, pnames)
921 let sc = PApp fc (PRef cnfc [cnfc] cn) (map pexp args)
922 let t = bindList (\r -> PPi constraint { pcount = r }) cs sc
924 ds <- implementationBlock syn
925 return [PImplementation doc argDocs syn fc cs' pnames acc opts cn cnfc args [] t en ds]
926 <?> "implementation declaration"
927 where implementationName :: IdrisParser Name
928 implementationName = do lchar '['; n_in <- fnName; lchar ']'
929 let n = expandNS syn n_in
931 <?> "implementation name"
932 implementationKeyword :: IdrisParser ()
933 implementationKeyword = keyword "implementation"
934 <|> do fc <- extent $ keyword "instance"
935 parserWarning fc Nothing (Msg "The 'instance' keyword is deprecated. Use 'implementation' (or omit it) instead.")
937 implementationUsing :: IdrisParser [Name]
938 implementationUsing = do keyword "using"
939 ns <- P.sepBy1 (withExtent fnName) (lchar ',')
943-- | Parse a docstring
944docstring :: SyntaxInfo
945 -> IdrisParser (Docstring (Either Err PTerm),
946 [(Name,Docstring (Either Err PTerm))])
947docstring syn = do (doc, argDocs) <- P.option noDocs docComment
949 let doc' = annotCode (tryFullExpr syn ist) doc
950 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
951 | (n, d) <- argDocs ]
952 return (doc', argDocs')
955{-| Parses a using declaration list
967 | UsingDecl ',' UsingDeclList'
978usingDeclList :: SyntaxInfo -> IdrisParser [Using]
980 = P.try (P.sepBy1 (usingDecl syn) (lchar ','))
981 <|> do ns <- P.sepBy1 name (lchar ',')
983 t <- typeExpr (disallowImp syn)
984 return (map (\x -> UImplicit x t) ns)
985 <?> "using declaration list"
987{-| Parses a using declaration
996usingDecl :: SyntaxInfo -> IdrisParser Using
997usingDecl syn = P.try (do x <- fnName
999 t <- typeExpr (disallowImp syn)
1000 return (UImplicit x t))
1003 return (UConstraint c xs)
1004 <?> "using declaration"
1006{-| Parse a clause with patterns
1012pattern :: SyntaxInfo -> IdrisParser PDecl
1013pattern syn = do (clause, fc) <- withExtent (clause syn)
1014 return (PClauses fc [] (sMN 2 "_") [clause]) -- collect together later
1017{-| Parse a constant applicative form declaration
1020CAF ::= 'let' FnName '=' Expr Terminator;
1023caf :: SyntaxInfo -> IdrisParser PDecl
1024caf syn = do keyword "let"
1025 (n, fc) <- withExtent (expandNS syn <$> fnName)
1028 t <- indented $ expr syn
1030 return (PCAF fc n t)
1031 <?> "constant applicative form declaration"
1033{-| Parse an argument expression
1036ArgExpr ::= HSimpleExpr | {- In Pattern External (User-defined) Expression -};
1039argExpr :: SyntaxInfo -> IdrisParser PTerm
1040argExpr syn = let syn' = syn { inPattern = True } in
1041 P.try (hsimpleExpr syn') <|> simpleExternalExpr syn'
1042 <?> "argument expression"
1044{-| Parse a right hand side of a function
1048 | '?=' RHSName? Expr
1054RHSName ::= '{' FnName '}';
1057rhs :: SyntaxInfo -> Name -> IdrisParser PTerm
1058rhs syn n = do lchar '='
1062 (name, fc) <- withExtent $ P.option n' (symbol "{" *> fnName <* symbol "}")
1064 return (addLet fc name r)
1066 <?> "function right hand side"
1067 where mkN :: Name -> Name
1068 mkN (UN x) = if (tnull x || not (isAlpha (thead x)))
1069 then sUN "infix_op_lemma_1"
1070 else sUN (str x++"_lemma_1")
1071 mkN (NS x n) = NS (mkN x) n
1074 addLet :: FC -> Name -> PTerm -> PTerm
1075 addLet fc nm (PLet fc' rig n nfc ty val r) = PLet fc' rig n nfc ty val (addLet fc nm r)
1076 addLet fc nm (PCase fc' t cs) = PCase fc' t (map addLetC cs)
1077 where addLetC (l, r) = (l, addLet fc nm r)
1078 addLet fc nm r = (PLet fc RigW (sUN "value") NoFC Placeholder r (PMetavar NoFC nm))
1080{-|Parses a function clause
1083RHSOrWithBlock ::= RHS WhereOrTerminator
1084 | 'with' SimpleExpr OpenBlock FnDecl+ CloseBlock
1089Clause ::= WExpr+ RHSOrWithBlock
1090 | SimpleExpr '<==' FnName RHS WhereOrTerminator
1091 | ArgExpr Operator ArgExpr WExpr* RHSOrWithBlock {- Except "=" and "?=" operators to avoid ambiguity -}
1092 | FnName ConstraintArg* ImplicitOrArgExpr* WExpr* RHSOrWithBlock
1097ImplicitOrArgExpr ::= ImplicitArg | ArgExpr;
1101WhereOrTerminator ::= WhereBlock | Terminator;
1104clause :: SyntaxInfo -> IdrisParser PClause
1106 -- unnamed with or function clause (inside a with)
1108 wargs <- P.try (do pushIndent; some (wExpr syn))
1110 n <- case lastParse ist of
1112 Nothing -> fail "Invalid clause"
1114 let wsyn = syn { syn_namespace = [], syn_toplevel = False }
1115 (wheres, nmap) <- whereBlock n wsyn <* popIndent
1116 <|> ([], []) <$ terminator
1117 return $ \fc -> PClauseR fc wargs r wheres) <|> (do
1120 wval <- simpleExpr syn
1123 ds <- some $ fnDecl syn
1124 let withs = concat ds
1126 return $ \fc -> PWithR fc wargs wval pn withs))
1128 <|> do ty <- P.try (do pushIndent
1129 ty <- simpleExpr syn
1132 (n, fc) <- withExtent (expandNS syn <$> fnName)
1134 let wsyn = syn { syn_namespace = [] }
1135 (wheres, nmap) <- whereBlock n wsyn <* popIndent
1136 <|> ([], []) <$ terminator
1137 let capp = PLet fc RigW (sMN 0 "match") NoFC
1140 (PRef fc [] (sMN 0 "match"))
1142 put (ist { lastParse = Just n })
1143 return $ PClause fc n capp [] r wheres
1144 -- lhs application "with" clause or function clause
1146 (n, nfc, capp, wargs) <- lhs
1147 modify $ \ist -> ist { lastParse = Just n }
1148 (do (rs, fc) <- withExtent (rhs syn n)
1149 let wsyn = syn { syn_namespace = [] }
1150 (wheres, nmap) <- whereBlock n wsyn <* popIndent
1151 <|> ([], []) <$ terminator
1152 return $ PClause fc n capp wargs rs wheres) <|> (do
1154 ((wval, pn), fc) <- withExtent $ do
1156 wval <- bracketed syn
1160 ds <- some $ fnDecl syn
1162 let withs = map (fillLHSD n capp wargs) $ concat ds
1163 return $ PWith fc n capp wargs wval pn withs)
1164 <?> "function clause"
1166 lhsInfixApp :: IdrisParser (Name, FC, [PArg], [PTerm])
1167 lhsInfixApp = do l <- argExpr syn
1168 (op, nfc) <- withExtent symbolicOperator
1169 when (op == "=" || op == "?=" ) $
1170 fail "infix clause definition with \"=\" and \"?=\" not supported "
1171 let n = expandNS syn (sUN op)
1173 wargs <- many (wExpr syn)
1174 return (n, nfc, [pexp l, pexp r], wargs)
1176 lhsPrefixApp :: IdrisParser (Name, FC, [PArg], [PTerm])
1177 lhsPrefixApp = do (n, nfc) <- withExtent (expandNS syn <$> fnName)
1178 args <- many (P.try (implicitArg (syn { inPattern = True } ))
1179 <|> P.try (constraintArg (syn { inPattern = True }))
1180 <|> (fmap pexp (argExpr syn)))
1181 wargs <- many (wExpr syn)
1182 return (n, nfc, args, wargs)
1184 lhs :: IdrisParser (Name, FC, PTerm, [PTerm])
1185 lhs = do ((n, nfc, args, wargs), lhs_fc) <- withExtent (P.try lhsInfixApp <|> lhsPrefixApp)
1186 let capp = PApp lhs_fc (PRef nfc [nfc] n) args
1187 return (n, nfc, capp, wargs)
1189 optProof = P.option Nothing (do keyword "proof"
1190 n <- withExtent fnName
1193 fillLHS :: Name -> PTerm -> [PTerm] -> PClause -> PClause
1194 fillLHS n capp owargs (PClauseR fc wargs v ws)
1195 = PClause fc n capp (owargs ++ wargs) v ws
1196 fillLHS n capp owargs (PWithR fc wargs v pn ws)
1197 = PWith fc n capp (owargs ++ wargs) v pn
1198 (map (fillLHSD n capp (owargs ++ wargs)) ws)
1201 fillLHSD :: Name -> PTerm -> [PTerm] -> PDecl -> PDecl
1202 fillLHSD n c a (PClauses fc o fn cs) = PClauses fc o fn (map (fillLHS n c a) cs)
1203 fillLHSD n c a x = x
1205{-| Parses with pattern
1211wExpr :: SyntaxInfo -> IdrisParser PTerm
1212wExpr syn = do lchar '|'
1213 expr' (syn { inPattern = True })
1216{-| Parses a where block
1219WhereBlock ::= 'where' OpenBlock Decl+ CloseBlock;
1222whereBlock :: Name -> SyntaxInfo -> IdrisParser ([PDecl], [(Name, Name)])
1224 = do keyword "where"
1225 ds <- indentedBlock1 (decl syn)
1226 let dns = concatMap (concatMap declared) ds
1227 return (concat ds, map (\x -> (x, decoration syn x)) dns)
1230{-|Parses a code generation target language name
1242codegen_ :: IdrisParser Codegen
1243codegen_ = do n <- identifier
1244 return (Via IBCFormat (map toLower n))
1245 <|> do reserved "Bytecode"; return Bytecode
1246 <?> "code generation language"
1248{-|Parses a compiler directive
1252 | String ',' StringList
1257Directive ::= '%' Directive';
1261Directive' ::= 'lib' CodeGen String_t
1262 | 'link' CodeGen String_t
1263 | 'flag' CodeGen String_t
1264 | 'include' CodeGen String_t
1268 | 'access' Accessibility
1269 | 'default' Totality
1271 | 'dynamic' StringList
1272 | 'name' Name NameList
1273 | 'error_handlers' Name NameList
1274 | 'language' 'TypeProviders'
1275 | 'language' 'ErrorReflection'
1276 | 'deprecated' Name String
1277 | 'fragile' Name Reason
1281directive :: SyntaxInfo -> IdrisParser [PDecl]
1282directive syn = do P.try (lchar '%' *> reserved "lib")
1284 lib <- stringLiteral
1285 return [PDirective (DLib cgn lib)]
1286 <|> do P.try (lchar '%' *> reserved "link")
1287 cgn <- codegen_; obj <- stringLiteral
1288 return [PDirective (DLink cgn obj)]
1289 <|> do P.try (lchar '%' *> reserved "flag")
1290 cgn <- codegen_; flag <- stringLiteral
1291 return [PDirective (DFlag cgn flag)]
1292 <|> do P.try (lchar '%' *> reserved "include")
1294 hdr <- stringLiteral
1295 return [PDirective (DInclude cgn hdr)]
1296 <|> do P.try (lchar '%' *> reserved "hide"); n <- fnName
1297 return [PDirective (DHide n)]
1298 <|> do P.try (lchar '%' *> reserved "freeze"); n <- iName []
1299 return [PDirective (DFreeze n)]
1300 <|> do P.try (lchar '%' *> reserved "thaw"); n <- iName []
1301 return [PDirective (DThaw n)]
1302 -- injectivity assertins are intended for debugging purposes
1303 -- only, and won't be documented/could be removed at any point
1304 <|> do P.try (lchar '%' *> reserved "assert_injective"); n <- fnName
1305 return [PDirective (DInjective n)]
1306 -- Assert totality of something after definition. This is
1307 -- here as a debugging aid, so commented out...
1308-- <|> do P.try (lchar '%' *> reserved "assert_set_total"); n <- fst <$> fnName
1309-- return [PDirective (DSetTotal n)]
1310 <|> do P.try (lchar '%' *> reserved "access")
1311 acc <- accessibility
1313 put ist { default_access = acc }
1314 return [PDirective (DAccess acc)]
1315 <|> do P.try (lchar '%' *> reserved "default"); tot <- totality
1317 put (i { default_total = tot } )
1318 return [PDirective (DDefault tot)]
1319 <|> do P.try (lchar '%' *> reserved "logging")
1321 return [PDirective (DLogging i)]
1322 <|> do P.try (lchar '%' *> reserved "dynamic")
1323 libs <- P.sepBy1 stringLiteral (lchar ',')
1324 return [PDirective (DDynamicLibs libs)]
1325 <|> do P.try (lchar '%' *> reserved "name")
1326 (ty, tyFC) <- withExtent fnName
1327 ns <- P.sepBy1 (withExtent name) (lchar ',')
1328 return [PDirective (DNameHint ty tyFC ns)]
1329 <|> do P.try (lchar '%' *> reserved "error_handlers")
1330 (fn, nfc) <- withExtent fnName
1331 (arg, afc) <- withExtent fnName
1332 ns <- P.sepBy1 (withExtent name) (lchar ',')
1333 return [PDirective (DErrorHandlers fn nfc arg afc ns) ]
1334 <|> do P.try (lchar '%' *> reserved "language"); ext <- pLangExt;
1335 return [PDirective (DLanguage ext)]
1336 <|> do P.try (lchar '%' *> reserved "deprecate")
1338 alt <- P.option "" stringLiteral
1339 return [PDirective (DDeprecate n alt)]
1340 <|> do P.try (lchar '%' *> reserved "fragile")
1342 alt <- P.option "" stringLiteral
1343 return [PDirective (DFragile n alt)]
1344 <|> do fc <- extent $ P.try (lchar '%' *> reserved "used")
1347 return [PDirective (DUsed fc fn arg)]
1348 <|> do P.try (lchar '%' *> reserved "auto_implicits")
1350 return [PDirective (DAutoImplicits b)]
1352 where on_off = do reserved "on"; return True
1353 <|> do reserved "off"; return False
1355pLangExt :: IdrisParser LanguageExt
1356pLangExt = (reserved "TypeProviders" >> return TypeProviders)
1357 <|> (reserved "ErrorReflection" >> return ErrorReflection)
1358 <|> (reserved "UniquenessTypes" >> return UniquenessTypes)
1359 <|> (reserved "LinearTypes" >> return LinearTypes)
1360 <|> (reserved "DSLNotation" >> return DSLNotation)
1361 <|> (reserved "ElabReflection" >> return ElabReflection)
1362 <|> (reserved "FirstClassReflection" >> return FCReflection)
1364{-| Parses a totality
1367Totality ::= 'partial' | 'total' | 'covering'
1371totality :: IdrisParser DefaultTotality
1373 = do keyword "total"; return DefaultCheckingTotal
1374 <|> do keyword "partial"; return DefaultCheckingPartial
1375 <|> do keyword "covering"; return DefaultCheckingCovering
1377{-| Parses a type provider
1380Provider ::= DocComment_t? '%' 'provide' Provider_What? '(' FnName TypeSig ')' 'with' Expr;
1381ProviderWhat ::= 'proof' | 'term' | 'type' | 'postulate'
1384provider :: SyntaxInfo -> IdrisParser [PDecl]
1385provider syn = do doc <- P.try (do (doc, _) <- docstring syn
1386 highlight AnnKeyword $ lchar '%' *> reserved "provide"
1388 provideTerm doc <|> providePostulate doc
1390 where provideTerm doc =
1391 do lchar '('; (n, nfc) <- withExtent fnName; lchar ':'; t <- typeExpr syn; lchar ')'
1393 (e, fc) <- withExtent (expr syn) <?> "provider expression"
1394 return [PProvider doc syn fc nfc (ProvTerm t e) n]
1395 providePostulate doc =
1396 do keyword "postulate"
1397 (n, nfc) <- withExtent fnName
1399 (e, fc) <- withExtent (expr syn) <?> "provider expression"
1400 return [PProvider doc syn fc nfc (ProvPostulate e) n]
1402{-| Parses a transform
1405Transform ::= '%' 'transform' Expr '==>' Expr
1408transform :: SyntaxInfo -> IdrisParser [PDecl]
1409transform syn = do P.try (lchar '%' *> reserved "transform")
1410 -- leave it unchecked, until we work out what this should
1412-- safety <- option True (do reserved "unsafe"
1415 fc <- extent $ symbol "==>"
1417 return [PTransform fc False l r]
1420{-| Parses a top-level reflected elaborator script
1423RunElabDecl ::= '%' 'runElab' Expr
1426runElabDecl :: SyntaxInfo -> IdrisParser PDecl
1428 do kwFC <- P.try (highlight AnnKeyword (extent $ lchar '%' *> reserved "runElab"))
1429 script <- expr syn <?> "elaborator script"
1430 return $ PRunElabDecl kwFC script (syn_namespace syn)
1431 <?> "top-level elaborator script"
1433{- * Loading and parsing -}
1434{-| Parses an expression from input -}
1435parseExpr :: IState -> String -> Either ParseError PTerm
1436parseExpr st = runparser (fullExpr defaultSyntax) st "(input)"
1438{-| Parses a constant form input -}
1439parseConst :: IState -> String -> Either ParseError Const
1440parseConst st = runparser constant st "(input)"
1442{-| Parses a tactic from input -}
1443parseTactic :: IState -> String -> Either ParseError PTactic
1444parseTactic st = runparser (fullTactic defaultSyntax) st "(input)"
1446{-| Parses a do-step from input (used in the elab shell) -}
1447parseElabShellStep :: IState -> String -> Either ParseError (Either ElabShellCmd PDo)
1448parseElabShellStep ist = runparser (Right <$> do_ defaultSyntax <|> Left <$> elabShellCmd) ist "(input)"
1449 where elabShellCmd = char ':' >>
1450 (reserved "qed" >> pure EQED ) <|>
1451 (reserved "abandon" >> pure EAbandon ) <|>
1452 (reserved "undo" >> pure EUndo ) <|>
1453 (reserved "state" >> pure EProofState) <|>
1454 (reserved "term" >> pure EProofTerm ) <|>
1455 (expressionTactic ["e", "eval"] EEval ) <|>
1456 (expressionTactic ["t", "type"] ECheck) <|>
1457 (expressionTactic ["search"] ESearch ) <|>
1459 doc <- (Right <$> constant) <|> (Left <$> fnName)
1461 return (EDocStr doc))
1463 expressionTactic cmds tactic =
1464 do asum (map reserved cmds)
1465 t <- spaced (expr defaultSyntax)
1467 return $ tactic (desugar defaultSyntax i t)
1468 spaced parser = indentGt *> parser
1470-- | Parse module header and imports
1471parseImports :: FilePath -> String -> Idris (Maybe (Docstring ()), [String], [ImportInfo], Maybe Mark)
1472parseImports fname input
1474 case runparser imports i fname input of
1475 Left err -> ifail . show . parseErrorDoc $ err
1476 Right (x, annots, i) ->
1478 fname' <- runIO $ Dir.makeAbsolute fname
1479 sendHighlighting $ addPath annots fname'
1481 where imports :: IdrisParser ((Maybe (Docstring ()), [String],
1484 [(FC, OutputAnnotation)], IState)
1485 imports = do optional shebang
1487 (mdoc, mname, annots) <- moduleHeader
1488 ps_exp <- many import_
1490 isEof <- lookAheadMatches P.eof
1495 -- add Builtins and Prelude, unless options say
1497 let ps = ps_exp -- imp "Builtins" : imp "Prelude" : ps_exp
1498 return ((mdoc, mname, ps, mrk'), annots, i)
1500 addPath :: [(FC, OutputAnnotation)] -> FilePath -> [(FC, OutputAnnotation)]
1502 addPath ((fc, AnnNamespace ns Nothing) : annots) path =
1503 (fc, AnnNamespace ns (Just path)) : addPath annots path
1504 addPath (annot:annots) path = annot : addPath annots path
1506 shebang :: IdrisParser ()
1507 shebang = string "#!" *> many (P.satisfy $ not . isEol) *> eol *> pure ()
1509-- | Check if the coloring matches the options and corrects if necessary
1510fixColour :: Bool -> PP.Doc -> PP.Doc
1511fixColour False doc = PP.plain doc
1512fixColour True doc = doc
1514-- | A program is a list of declarations, possibly with associated
1515-- documentation strings.
1516parseProg :: SyntaxInfo -> FilePath -> String -> Maybe Mark -> Idris [PDecl]
1517parseProg syn fname input mrk
1519 case runparser mainProg i fname input of
1520 Left err -> do let fc = errorExtent err
1522 case idris_outputmode i of
1523 RawOutput h -> iputStrLn (show . fixColour (idris_colourRepl i) . parseErrorDoc $ err)
1524 IdeMode n h -> iWarn fc (Util.Pretty.text $ errorMessage err)
1525 putIState (i { errSpan = Just fc })
1527 Right (x, i) -> do putIState i
1528 reportParserWarnings
1530 where mainProg :: IdrisParser ([PDecl], IState)
1531 mainProg = case mrk of
1532 Nothing -> do i <- get; return ([], i)
1539-- | Collect 'PClauses' with the same function name
1540collect :: [PDecl] -> [PDecl]
1541collect (c@(PClauses _ o _ _) : ds)
1542 = clauses (cname c) [] (c : ds)
1543 where clauses :: Maybe Name -> [PClause] -> [PDecl] -> [PDecl]
1544 clauses j@(Just n) acc (PClauses fc _ _ [PClause fc' n' l ws r w] : ds)
1545 | n == n' = clauses j (PClause fc' n' l ws r (collect w) : acc) ds
1546 clauses j@(Just n) acc (PClauses fc _ _ [PWith fc' n' l ws r pn w] : ds)
1547 | n == n' = clauses j (PWith fc' n' l ws r pn (collect w) : acc) ds
1548 clauses (Just n) acc xs = PClauses (fcOf c) o n (reverse acc) : collect xs
1549 clauses Nothing acc (x:xs) = collect xs
1550 clauses Nothing acc [] = []
1552 cname :: PDecl -> Maybe Name
1553 cname (PClauses fc _ _ [PClause _ n _ _ _ _]) = Just n
1554 cname (PClauses fc _ _ [PWith _ n _ _ _ _ _]) = Just n
1555 cname (PClauses fc _ _ [PClauseR _ _ _ _]) = Nothing
1556 cname (PClauses fc _ _ [PWithR _ _ _ _ _]) = Nothing
1558 fcOf (PClauses fc _ _ _) = fc
1559collect (PParams f ns ps : ds) = PParams f ns (collect ps) : collect ds
1560collect (POpenInterfaces f ns ps : ds) = POpenInterfaces f ns (collect ps) : collect ds
1561collect (PMutual f ms : ds) = PMutual f (collect ms) : collect ds
1562collect (PNamespace ns fc ps : ds) = PNamespace ns fc (collect ps) : collect ds
1563collect (PInterface doc f s cs n nfc ps pdocs fds ds cn cd : ds')
1564 = PInterface doc f s cs n nfc ps pdocs fds (collect ds) cn cd : collect ds'
1565collect (PImplementation doc argDocs f s cs pnames acc opts n nfc ps pextra t en ds : ds')
1566 = PImplementation doc argDocs f s cs pnames acc opts n nfc ps pextra t en (collect ds) : collect ds'
1567collect (d : ds) = d : collect ds
1570{-| Load idris module and show error if something wrong happens -}
1571loadModule :: FilePath -> IBCPhase -> Idris (Maybe String)
1573 = idrisCatch (loadModule' f phase)
1574 (\e -> do setErrSpan (getErrSpan e)
1576 iWarn (getErrSpan e) $ pprintErr ist e
1579{-| Load idris module -}
1580loadModule' :: FilePath -> IBCPhase -> Idris (Maybe String)
1583 let file = takeWhile (/= ' ') f
1584 ibcsd <- valIBCSubDir i
1585 ids <- rankedImportDirs file
1586 fp <- findImport ids ibcsd file
1587 if file `elem` imported i
1588 then do logParser 1 $ "Already read " ++ file
1590 else do putIState (i { imported = file : imported i })
1592 IDR fn -> loadSource False fn Nothing
1593 LIDR fn -> loadSource True fn Nothing
1595 idrisCatch (loadIBC True phase fn)
1596 (\c -> do logParser 1 $ fn ++ " failed " ++ pshow i c
1598 IDR sfn -> loadSource False sfn Nothing
1599 LIDR sfn -> loadSource True sfn Nothing)
1602{-| Load idris code from file -}
1603loadFromIFile :: Bool -> IBCPhase -> IFileType -> Maybe Int -> Idris ()
1604loadFromIFile reexp phase i@(IBC fn src) maxline
1605 = do logParser 1 $ "Skipping " ++ getSrcFile i
1606 logParser 3 $ "loadFromIFile i" ++ show i
1607 idrisCatch (loadIBC reexp phase fn)
1608 (\err -> ierror $ LoadingFailed fn err)
1610 getSrcFile (IDR fn) = fn
1611 getSrcFile (LIDR fn) = fn
1612 getSrcFile (IBC f src) = getSrcFile src
1614loadFromIFile _ _ (IDR fn) maxline = loadSource' False fn maxline
1615loadFromIFile _ _ (LIDR fn) maxline = loadSource' True fn maxline
1617{-| Load idris source code and show error if something wrong happens -}
1618loadSource' :: Bool -> FilePath -> Maybe Int -> Idris ()
1619loadSource' lidr r maxline
1620 = idrisCatch (loadSource lidr r maxline)
1621 (\e -> do setErrSpan (getErrSpan e)
1624 At f e' -> iWarn f (pprintErr ist e')
1625 _ -> iWarn (getErrSpan e) (pprintErr ist e))
1627{-| Load Idris source code-}
1628loadSource :: Bool -> FilePath -> Maybe Int -> Idris ()
1629loadSource lidr f toline
1630 = do logParser 1 ("Reading " ++ f)
1631 iReport 2 ("Reading " ++ f)
1633 let def_total = default_total i
1634 file_in <- runIO $ readSource f
1635 file <- if lidr then tclift $ unlit f file_in else return file_in
1636 (mdocs, mname, imports_in, pos) <- parseImports f file
1637 ai <- getAutoImports
1638 let imports = map (\n -> ImportInfo True n Nothing [] NoFC NoFC) ai ++ imports_in
1639 ids <- rankedImportDirs f
1640 ibcsd <- valIBCSubDir i
1641 mapM_ (\(re, f, ns, nfc) ->
1642 do fp <- findImport ids ibcsd f
1644 LIDR fn -> ifail $ "No ibc for " ++ f
1645 IDR fn -> ifail $ "No ibc for " ++ f
1647 do loadIBC True IBC_Building fn
1648 let srcFn = case src of
1652 srcFnAbs <- case srcFn of
1653 Just fn -> fmap Just (runIO $ Dir.makeAbsolute fn)
1654 Nothing -> return Nothing
1655 sendHighlighting [(nfc, AnnNamespace ns srcFnAbs)])
1656 [(re, fn, ns, nfc) | ImportInfo re fn _ ns _ nfc <- imports]
1657 reportParserWarnings
1658 sendParserHighlighting
1660 -- process and check module aliases
1661 let modAliases = M.fromList
1662 [ (prep alias, prep realName)
1663 | ImportInfo { import_reexport = reexport
1664 , import_path = realName
1665 , import_rename = Just (alias, _)
1666 , import_location = fc } <- imports
1668 prep = map T.pack . reverse . Spl.splitOn [pathSeparator]
1669 aliasNames = [ (alias, fc)
1670 | ImportInfo { import_rename = Just (alias, fc)
1673 histogram = groupBy ((==) `on` fst) . sortBy (comparing fst) $ aliasNames
1674 case map head . filter ((/= 1) . length) $ histogram of
1675 [] -> logParser 3 $ "Module aliases: " ++ show (M.toList modAliases)
1676 (n,fc):_ -> throwError . At fc . Msg $ "import alias not unique: " ++ show n
1679 putIState (i { default_access = Private, module_aliases = modAliases })
1680 clearIBC -- start a new .ibc file
1681 -- record package info in .ibc
1682 imps <- allImportDirs
1683 mapM_ addIBC (map IBCImportDir imps)
1684 mapM_ (addIBC . IBCImport)
1685 [ (reexport, realName)
1686 | ImportInfo { import_reexport = reexport
1687 , import_path = realName
1690 let syntax = defaultSyntax{ syn_namespace = reverse mname,
1693 -- Save the span from parsing the module header, because
1694 -- an empty program parse might obliterate it.
1695 let oldSpan = idris_parsedSpan ist
1696 ds' <- parseProg syntax f file pos
1698 case (ds', oldSpan) of
1700 -- If no program elements were parsed, we dind't
1701 -- get a loaded region in the IBC file. That
1702 -- means we need to add it back.
1704 putIState ist { idris_parsedSpan = oldSpan
1705 , ibc_write = IBCParsedRegion fc :
1709 sendParserHighlighting
1711 -- Parsing done, now process declarations
1713 let ds = namespaces mname ds'
1714 logParser 3 (show $ showDecls verbosePPOption ds)
1716 logLvl 10 (show (toAlist (idris_implicits i)))
1717 logLvl 3 (show (idris_infixes i))
1718 -- Now add all the declarations to the context
1719 iReport 1 $ "Type checking " ++ f
1720 -- we totality check after every Mutual block, so if
1721 -- anything is a single definition, wrap it in a
1722 -- mutual block on its own
1723 elabDecls (toplevelWith f) (map toMutual ds)
1725 -- simplify every definition do give the totality checker
1727 mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
1729 do ctxt <- getContext
1730 tclift $ simplifyCasedef n [] [] (getErasureInfo i) ctxt
1732 (map snd (idris_totcheck i))
1733 -- build size change graph from simplified definitions
1734 iReport 3 $ "Totality checking " ++ f
1735 logLvl 1 $ "Totality checking " ++ f
1737 mapM_ buildSCG (idris_totcheck i)
1738 mapM_ checkDeclTotality (idris_totcheck i)
1739 mapM_ verifyTotality (idris_totcheck i)
1741 -- Redo totality check for deferred names
1742 let deftots = idris_defertotcheck i
1743 logLvl 2 $ "Totality checking " ++ show deftots
1744 mapM_ (\x -> do tot <- getTotality x
1747 do let opts = case lookupCtxtExact x (idris_flags i) of
1750 when (AssertTotal `notElem` opts) $
1751 setTotality x Unchecked
1752 _ -> return ()) (map snd deftots)
1753 mapM_ buildSCG deftots
1754 mapM_ checkDeclTotality deftots
1756 logLvl 1 ("Finished " ++ f)
1757 ibcsd <- valIBCSubDir i
1758 logLvl 1 $ "Universe checking " ++ f
1759 iReport 3 $ "Universe checking " ++ f
1761 let ibc = ibcPathNoFallback ibcsd f
1763 addHides (hide_list i)
1765 -- Save module documentation if applicable
1768 Nothing -> return ()
1769 Just docs -> addModDoc syntax mname docs
1772 -- Finally, write an ibc and highlights if checking was successful
1775 do idrisCatch (do writeIBC f ibc; clearIBC)
1776 (\c -> return ()) -- failure is harmless
1777 hl <- getDumpHighlighting
1779 idrisCatch (writeHighlights f)
1780 (const $ return ()) -- failure is harmless
1783 putIState (i { default_total = def_total,
1784 hide_list = emptyContext })
1787 namespaces :: [String] -> [PDecl] -> [PDecl]
1788 namespaces [] ds = ds
1789 namespaces (x:xs) ds = [PNamespace x NoFC (namespaces xs ds)]
1791 toMutual :: PDecl -> PDecl
1792 toMutual m@(PMutual _ d) = m
1793 toMutual (PNamespace x fc ds) = PNamespace x fc (map toMutual ds)
1794 toMutual x = let r = PMutual (fileFC "single mutual") [x] in
1799 PImplementation{} -> r
1802 addModDoc :: SyntaxInfo -> [String] -> Docstring () -> Idris ()
1803 addModDoc syn mname docs =
1805 docs' <- elabDocTerms (toplevelWith f) (parsedDocs ist)
1806 let modDocs' = addDef docName docs' (idris_moduledocs ist)
1807 putIState ist { idris_moduledocs = modDocs' }
1808 addIBC (IBCModDocs docName)
1810 docName = NS modDocName (map T.pack (reverse mname))
1811 parsedDocs ist = annotCode (tryFullExpr syn ist) docs
1813{-| Adds names to hide list -}
1814addHides :: Ctxt Accessibility -> Idris ()
1815addHides xs = mapM_ doHide (toAlist xs)
1816 where doHide (n, a) = do setAccessibility n a
1817 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