1{-# LANGUAGE GeneralizedNewtypeDeriving, ConstraintKinds, PatternGuards #-}
2module Idris.Parser(module Idris.Parser,
3 module Idris.ParseExpr,
4 module Idris.ParseHelpers,
5 module Idris.ParseOps) where
7import Prelude hiding (pi)
9import Text.Trifecta.Delta
10import Text.Trifecta hiding (span, stringLiteral, charLiteral, natural, symbol, char, string, whiteSpace)
11import Text.Parser.LookAhead
12import Text.Parser.Expression
13import qualified Text.Parser.Token as Tok
14import qualified Text.Parser.Char as Chr
15import qualified Text.Parser.Token.Highlight as Hi
22import Idris.ElabTerm hiding (namespace, params)
28import Idris.ParseHelpers
34import Util.DynamicLinker
39import Control.Applicative
41import Control.Monad.State.Strict
44import qualified Data.List.Split as Spl
48import qualified Data.HashSet as HS
49import qualified Data.Text as T
50import qualified Data.ByteString.UTF8 as UTF8
56 grammar shortcut notation:
57 ~CHARSEQ = complement of char sequence (i.e. any character except CHARSEQ)
58 RULE? = optional rule (i.e. RULE or nothing)
59 RULE* = repeated rule (i.e. RULE zero or more times)
60 RULE+ = repeated rule with at least one match (i.e. RULE one or more times)
61 RULE! = invalid rule (i.e. rule that is not valid in context, report meaningful error in case)
62 RULE{n} = rule repeated n times
65-- | Adds accessibility option for function
66addAcc :: Name -> Maybe Accessibility -> IdrisParser ()
67addAcc n a = do i <- get
68 put (i { hide_list = (n, a) : hide_list i })
70{- | Add accessbility option for data declarations
71 (works for classes too - 'abstract' means the data/class is visible but members not) -}
72accData :: Maybe Accessibility -> Name -> [Name] -> IdrisParser ()
73accData (Just Frozen) n ns = do addAcc n (Just Frozen)
74 mapM_ (\n -> addAcc n (Just Hidden)) ns
75accData a n ns = do addAcc n a
79{- * Error reporting helpers -}
80{- | Error message with possible fixes list -}
81fixErrorMsg :: String -> [String] -> String
82fixErrorMsg msg fixes = msg ++ ", possible fixes:\n" ++ (concat $ intersperse "\n\nor\n\n" fixes)
86{- | Parses module definition
87 ModuleHeader ::= 'module' Identifier_t ';'?;
89moduleHeader :: IdrisParser [String]
90moduleHeader = try (do reserved "module"
92 option ';' (lchar ';')
93 return (moduleName i))
95 where moduleName x = case span (/='.') x of
97 (x, '.':y) -> x : moduleName y
99{- | Parses an import statement
100 Import ::= 'import' Identifier_t ';'?;
102import_ :: IdrisParser String
103import_ = do reserved "import"
105 option ';' (lchar ';')
107 <?> "import statement"
108 where toPath f = foldl1' (</>) (Spl.splitOn "." f)
110{- | Parses program source
113prog :: SyntaxInfo -> IdrisParser [PDecl]
114prog syn = do whiteSpace
115 decls <- many (decl syn)
118 let c = (concat decls)
121{- | Parses a top-level declaration
137decl :: SyntaxInfo -> IdrisParser [PDecl]
138decl syn = do notEndBlock
140 where declBody :: IdrisParser [PDecl]
148 <|> do d <- dsl syn; return [d]
152 <|> do import_; fail "imports must be at top of file"
154 declBody' :: IdrisParser [PDecl]
155 declBody' = do d <- decl' syn
157 let d' = fmap (desugar syn i) d
160{- | Parses a top-level declaration with possible syntax sugar
169decl' :: SyntaxInfo -> IdrisParser PDecl
177{- | Parses a syntax extension declaration (and adds the rule to parser state)
178 SyntaxDecl ::= SyntaxRule;
180syntaxDecl :: SyntaxInfo -> IdrisParser PDecl
181syntaxDecl syn = do s <- syntaxRule syn
183 let rs = syntax_rules i
184 let ns = syntax_keywords i
185 let ibc = ibc_write i
186 let ks = map show (names s)
187 put (i { syntax_rules = s : rs,
188 syntax_keywords = ks ++ ns,
189 ibc_write = IBCSyntax s : map IBCKeyword ks ++ ibc })
191 return (PSyntax fc s)
192 where names (Rule syms _ _) = mapMaybe ename syms
193 ename (Keyword n) = Just n
196{- | Parses a syntax extension declaration
197SyntaxRuleOpts ::= 'term' | 'pattern';
200 SyntaxRuleOpts? 'syntax' SyntaxSym+ '=' TypeExpr Terminator;
202SyntaxSym ::= '[' Name_t ']'
208syntaxRule :: SyntaxInfo -> IdrisParser Syntax
212 sty <- option AnySyntax (do reserved "term"; return TermSyntax
213 <|> do reserved "pattern"; return PatternSyntax)
216 syms <- some syntaxSym
217 when (all isExpr syms) $ unexpected "missing keywords in syntax rule"
218 let ns = mapMaybe getName syms
219 when (length ns /= length (nub ns))
220 $ unexpected "repeated variable in syntax rule"
222 tm <- typeExpr (allowImp syn)
224 return (Rule (mkSimple syms) tm sty)
226 isExpr (Expr _) = True
228 getName (Expr n) = Just n
230 -- Can't parse two full expressions (i.e. expressions with application) in a row
231 -- so change them both to a simple expression
232 mkSimple (Expr e : es) = SimpleExpr e : mkSimple' es
233 mkSimple xs = mkSimple' xs
235 mkSimple' (Expr e : Expr e1 : es) = SimpleExpr e : SimpleExpr e1 :
237 mkSimple' (e : es) = e : mkSimple' es
241{- | Parses a syntax symbol (either binding variable, keyword or expression)
242SyntaxSym ::= '[' Name_t ']'
248syntaxSym :: IdrisParser SSymbol
249syntaxSym = try (do lchar '['; n <- name; lchar ']'
251 <|> try (do lchar '{'; n <- name; lchar '}'
255 <|> do sym <- stringLiteral
259{- | Parses a function declaration with possible syntax sugar
260 FunDecl ::= FunDecl';
262fnDecl :: SyntaxInfo -> IdrisParser [PDecl]
264 = try (do notEndBlock
267 let d' = fmap (desugar syn i) d
269 <?> "function declaration"
271{- Parses a function declaration
273 DocComment_t? FnOpts* Accessibility? FnOpts* FnName TypeSig Terminator
279fnDecl' :: SyntaxInfo -> IdrisParser PDecl
280fnDecl' syn = do (doc, fc, opts', n, acc) <- try (do
281 doc <- option "" (docComment '|')
284 let initOpts = if default_total ist
287 opts <- fnOpts initOpts
288 acc <- optional accessibility
291 let n = expandNS syn n_in
294 return (doc, fc, opts', n, acc))
295 ty <- typeExpr (allowImp syn)
298 return (PTy doc syn fc opts' n ty)
302 <?> "function declaration"
305{- Parses function options given initial options
311 | '%' 'specialise' '[' NameTimesList? ']'
314NameTimes ::= FnName Natural?;
318 | NameTimes ',' NameTimesList
322-- FIXME: Check compatability for function options (i.e. partal/total)
323fnOpts :: [FnOpt] -> IdrisParser [FnOpt]
325 = do reserved "total"; fnOpts (TotalFn : opts)
326 <|> do reserved "partial"; fnOpts (PartialFn : (opts \\ [TotalFn]))
327 <|> do try (lchar '%' *> reserved "export"); c <- stringLiteral;
328 fnOpts (CExport c : opts)
329 <|> do try (lchar '%' *> reserved "assert_total");
330 fnOpts (AssertTotal : opts)
331 <|> do try (lchar '%' *> reserved "reflection");
332 fnOpts (Reflection : opts)
333 <|> do lchar '%'; reserved "specialise";
334 lchar '['; ns <- sepBy nameTimes (lchar ','); lchar ']'
335 fnOpts (Specialise ns : opts)
336 <|> do reserved "implicit"; fnOpts (Implicit : opts)
338 <?> "function modifier"
339 where nameTimes :: IdrisParser (Name, Maybe Int)
340 nameTimes = do n <- fnName
341 t <- option Nothing (do reds <- natural
342 return (Just (fromInteger reds)))
345{- | Parses an accessibilty modifier (e.g. public, private) -}
346accessibility :: IdrisParser Accessibility
347accessibility = do reserved "public"; return Public
348 <|> do reserved "abstract"; return Frozen
349 <|> do reserved "private"; return Hidden
350 <?> "accessibility modifier"
354{- | Parses a postulate
357 DocComment_t? 'postulate' FnOpts* Accesibility? FnOpts* FnName TypeSig Terminator
360postulate :: SyntaxInfo -> IdrisParser PDecl
361postulate syn = do doc <- try $ do doc <- option "" (docComment '|')
366 let initOpts = if default_total ist
369 opts <- fnOpts initOpts
370 acc <- optional accessibility
373 let n = expandNS syn n_in
375 ty <- typeExpr (allowImp syn)
379 return (PPostulate doc syn fc opts' n ty)
382{- | Parses a using declaration
385 'using' '(' UsingDeclList ')' OpenBlock Decl* CloseBlock
388using_ :: SyntaxInfo -> IdrisParser [PDecl]
390 do reserved "using"; lchar '('; ns <- usingDeclList syn; lchar ')'
392 let uvars = using syn
393 ds <- many (decl (syn { using = uvars ++ ns }))
396 <?> "using declaration"
398{- | Parses a parameters declaration
401 'parameters' '(' TypeDeclList ')' OpenBlock Decl* CloseBlock
404params :: SyntaxInfo -> IdrisParser [PDecl]
406 do reserved "parameters"; lchar '('; ns <- typeDeclList syn; lchar ')'
408 let pvars = syn_params syn
409 ds <- many (decl syn { syn_params = pvars ++ ns })
412 return [PParams fc ns (concat ds)]
413 <?> "parameters declaration"
415{- | Parses a mutual declaration (for mutually recursive functions)
418 'mutual' OpenBlock Decl* CloseBlock
421mutual :: SyntaxInfo -> IdrisParser [PDecl]
425 let pvars = syn_params syn
426 ds <- many (decl syn)
429 return [PMutual fc (concat ds)]
432{- | Parses a namespace declaration
435 'namespace' identifier OpenBlock Decl+ CloseBlock
438namespace :: SyntaxInfo -> IdrisParser [PDecl]
440 do reserved "namespace"; n <- identifier;
442 ds <- some (decl syn { syn_namespace = n : syn_namespace syn })
444 return [PNamespace n (concat ds)]
445 <?> "namespace declaration"
447{- | Parses a fixity declaration
450 FixityType Natural_t OperatorList Terminator
453fixity :: IdrisParser PDecl
454fixity = do pushIndent
455 f <- fixityType; i <- natural; ops <- sepBy1 operator (lchar ',')
457 let prec = fromInteger i
459 let infixes = idris_infixes istate
460 let fs = map (Fix (f prec)) ops
461 let redecls = map (alreadyDeclared infixes) fs
462 let ill = filter (not . checkValidity) redecls
464 then do put (istate { idris_infixes = nub $ sort (fs ++ infixes)
465 , ibc_write = map IBCFix fs ++ ibc_write istate
468 return (PFix fc (f prec) ops)
469 else fail $ concatMap (\(f, (x:xs)) -> "Illegal redeclaration of fixity:\n\t\""
470 ++ show f ++ "\" overrides \"" ++ show x ++ "\"") ill
471 <?> "fixity declaration"
472 where alreadyDeclared :: [FixDecl] -> FixDecl -> (FixDecl, [FixDecl])
473 alreadyDeclared fs f = (f, filter ((extractName f ==) . extractName) fs)
475 checkValidity :: (FixDecl, [FixDecl]) -> Bool
476 checkValidity (f, fs) = all (== f) fs
478 extractName :: FixDecl -> String
479 extractName (Fix _ n) = n
481{- | Parses a fixity declaration type (i.e. infix or prefix, associtavity)
489fixityType :: IdrisParser (Int -> Fixity)
490fixityType = do reserved "infixl"; return Infixl
491 <|> do reserved "infixr"; return Infixr
492 <|> do reserved "infix"; return InfixN
493 <|> do reserved "prefix"; return PrefixN
496{- |Parses a methods block (for type classes and instances)
497 MethodsBlock ::= 'where' OpenBlock FnDecl* CloseBlock
499methodsBlock :: SyntaxInfo -> IdrisParser [PDecl]
500methodsBlock syn = do reserved "where"
502 ds <- many (fnDecl syn)
507{- |Parses a type class declaration
511 | '(' Name ':' Expr ')'
515 DocComment_t? Accessibility? 'class' ConstraintList? Name ClassArgument* MethodsBlock?
518class_ :: SyntaxInfo -> IdrisParser [PDecl]
519class_ syn = do (doc, acc) <- try (do
520 doc <- option "" (docComment '|')
521 acc <- optional accessibility
523 reserved "class"; fc <- getFC; cons <- constraintList syn; n_in <- name
524 let n = expandNS syn n_in
526 ds <- option [] (methodsBlock syn)
527 accData acc n (concatMap declared ds)
528 return [PClass doc syn fc cons n cs ds]
529 <?> "type-class declaration"
531 carg :: IdrisParser (Name, PTerm)
532 carg = do lchar '('; i <- name; lchar ':'; ty <- expr syn; lchar ')'
537{- |Parses a type class instance declaration
540 'instance' InstanceName? ConstraintList? Name SimpleExpr* MethodsBlock?
543 InstanceName ::= '[' Name ']';
545instance_ :: SyntaxInfo -> IdrisParser [PDecl]
546instance_ syn = do reserved "instance"; fc <- getFC
547 en <- optional instanceName
548 cs <- constraintList syn
550 args <- many (simpleExpr syn)
551 let sc = PApp fc (PRef fc cn) (map pexp args)
552 let t = bindList (PPi constraint) (map (\x -> (MN 0 "c", x)) cs) sc
553 ds <- option [] (methodsBlock syn)
554 return [PInstance syn fc cs cn args t en ds]
555 <?> "instance declaratioN"
556 where instanceName :: IdrisParser Name
557 instanceName = do lchar '['; n_in <- fnName; lchar ']'
558 let n = expandNS syn n_in
563{- | Parses a using declaration list
571 | UsingDecl ',' UsingDeclList'
579usingDeclList :: SyntaxInfo -> IdrisParser [Using]
581 = try (sepBy1 (usingDecl syn) (lchar ','))
582 <|> do ns <- sepBy1 name (lchar ',')
584 t <- typeExpr (disallowImp syn)
585 return (map (\x -> UImplicit x t) ns)
586 <?> "using declaration list"
588{- |Parses a using declaration
594usingDecl :: SyntaxInfo -> IdrisParser Using
595usingDecl syn = try (do x <- fnName
597 t <- typeExpr (disallowImp syn)
598 return (UImplicit x t))
601 return (UConstraint c xs)
602 <?> "using declaration"
604{- |Parses a record type declaration
606 DocComment Accessibility? 'record' FnName TypeSig 'where' OpenBlock Constructor KeepTerminator CloseBlock;
608record :: SyntaxInfo -> IdrisParser PDecl
609record syn = do (doc, acc) <- try (do
610 doc <- option "" (docComment '|')
611 acc <- optional accessibility
617 ty <- typeExpr (allowImp syn)
618 let tyn = expandNS syn tyn_in
620 (cdoc, cn, cty, _) <- indentedBlockS (constructor syn)
622 let rsyn = syn { syn_namespace = show (nsroot tyn) :
624 let fns = getRecNames rsyn cty
625 mapM_ (\n -> addAcc n acc) fns
626 return $ PRecord doc rsyn fc tyn ty cdoc cn cty
627 <?> "record type declaration"
629 getRecNames :: SyntaxInfo -> PTerm -> [Name]
630 getRecNames syn (PPi _ n _ sc) = [expandNS syn n, expandNS syn (mkType n)]
631 ++ getRecNames syn sc
634 toFreeze :: Maybe Accessibility -> Maybe Accessibility
635 toFreeze (Just Frozen) = Just Hidden
638{- | Parses data declaration type (normal or codata)
639DataI ::= 'data' | 'codata';
641dataI :: IdrisParser Bool
642dataI = do reserved "data"; return False
643 <|> do reserved "codata"; return True
645{- | Parses a data type declaration
646Data ::= DocComment? Accessibility? DataI FnName TypeSig ExplicitTypeDataRest?
647 | DocComment? Accessibility? DataI FnName Name* DataRest?
649Constructor' ::= Constructor KeepTerminator;
650ExplicitTypeDataRest ::= 'where' OpenBlock Constructor'* CloseBlock;
652DataRest ::= '=' SimpleConstructorList Terminator
655SimpleConstructorList ::=
657 | SimpleConstructor '|' SimpleConstructorList
660data_ :: SyntaxInfo -> IdrisParser PDecl
661data_ syn = do (doc, acc, co) <- try (do
662 doc <- option "" (docComment '|')
664 acc <- optional accessibility
666 return (doc, acc, co))
671 ty <- typeExpr (allowImp syn)
672 let tyn = expandNS syn tyn_in
673 option (PData doc syn fc co (PLaterdecl tyn ty)) (do
675 cons <- indentedBlock (constructor syn)
676 accData acc tyn (map (\ (_, n, _, _) -> n) cons)
677 return $ PData doc syn fc co (PDatadecl tyn ty cons))) <|> (do
679 let ty = bindArgs (map (const PType) args) PType
680 let tyn = expandNS syn tyn_in
681 option (PData doc syn fc co (PLaterdecl tyn ty)) (do
682 try (lchar '=') <|> do reserved "where"
683 let kw = (if co then "co" else "") ++ "data "
684 let n = show tyn_in ++ " "
686 let as = concat (intersperse " " $ map show args) ++ " "
687 let ns = concat (intersperse " -> " $ map ((\x -> "(" ++ x ++ " : Type)") . show) args)
688 let ss = concat (intersperse " -> " $ map (const "Type") args)
689 let fix1 = s ++ as ++ " = ..."
690 let fix2 = s ++ ": " ++ ns ++ " -> Type where\n ..."
691 let fix3 = s ++ ": " ++ ss ++ " -> Type where\n ..."
692 fail $ fixErrorMsg "unexpected \"where\"" [fix1, fix2, fix3]
693 cons <- sepBy1 (simpleConstructor syn) (lchar '|')
695 let conty = mkPApp fc (PRef fc tyn) (map (PRef fc) args)
696 cons' <- mapM (\ (doc, x, cargs, cfc) ->
697 do let cty = bindArgs cargs conty
698 return (doc, x, cty, cfc)) cons
699 accData acc tyn (map (\ (_, n, _, _) -> n) cons')
700 return $ PData doc syn fc co (PDatadecl tyn ty cons')))
701 <?> "data type declaration"
703 mkPApp :: FC -> PTerm -> [PTerm] -> PTerm
705 mkPApp fc t xs = PApp fc t (map pexp xs)
706 bindArgs :: [PTerm] -> PTerm -> PTerm
707 bindArgs xs t = foldr (PPi expl (MN 0 "t")) t xs
710{- | Parses a type constructor declaration
711 Constructor ::= DocComment? FnName TypeSig;
713constructor :: SyntaxInfo -> IdrisParser (String, Name, PTerm, FC)
715 = do doc <- option "" (docComment '|')
716 cn_in <- fnName; fc <- getFC
717 let cn = expandNS syn cn_in
719 ty <- typeExpr (allowImp syn)
720 return (doc, cn, ty, fc)
723{- | Parses a constructor for simple discriminative union data types
724 SimpleConstructor ::= FnName SimpleExpr* DocComment?
726simpleConstructor :: SyntaxInfo -> IdrisParser (String, Name, [PTerm], FC)
729 let cn = expandNS syn cn_in
731 args <- many (do notEndApp
733 doc <- option "" (docComment '^')
734 return (doc, cn, args, fc)
737{- | Parses a dsl block declaration
738DSL ::= 'dsl' FnName OpenBlock Overload'+ CloseBlock;
740dsl :: SyntaxInfo -> IdrisParser PDecl
741dsl syn = do reserved "dsl"
743 bs <- indentedBlock (overload syn)
744 let dsl = mkDSL bs (dsl_info syn)
747 put (i { idris_dsls = addDef n dsl (idris_dsls i) })
749 <?> "dsl block declaration"
750 where mkDSL :: [(String, PTerm)] -> DSL -> DSL
751 mkDSL bs dsl = let var = lookup "variable" bs
752 first = lookup "index_first" bs
753 next = lookup "index_next" bs
754 leto = lookup "let" bs
755 lambda = lookup "lambda" bs in
756 initDSL { dsl_var = var,
762{- | Checks DSL for errors -}
763-- FIXME: currently does nothing, check if DSL is really sane
764checkDSL :: DSL -> IdrisParser ()
765checkDSL dsl = return ()
767{- | Parses a DSL overload declaration
768OverloadIdentifier ::= 'let' | Identifier;
769Overload ::= OverloadIdentifier '=' Expr;
771overload :: SyntaxInfo -> IdrisParser (String, PTerm)
772overload syn = do o <- identifier <|> do reserved "let"
774 if o `notElem` overloadable
775 then fail $ show o ++ " is not an overloading"
780 <?> "dsl overload declaratioN"
781 where overloadable = ["let","lambda","index_first","index_next","variable"]
783{- | Parse a clause with patterns
786pattern :: SyntaxInfo -> IdrisParser PDecl
787pattern syn = do fc <- getFC
789 return (PClauses fc [] (MN 2 "_") [clause]) -- collect together later
792{- | Parse a constant applicative form declaration
793 CAF ::= 'let' FnName '=' Expr Terminator;
795caf :: SyntaxInfo -> IdrisParser PDecl
796caf syn = do reserved "let"
797 n_in <- fnName; let n = expandNS syn n_in
803 <?> "constant applicative form declaration"
805{- | Parse an argument expression
806 ArgExpr ::= HSimpleExpr | {- In Pattern External (User-defined) Expression -};
808argExpr :: SyntaxInfo -> IdrisParser PTerm
809argExpr syn = let syn' = syn { inPattern = True } in
810 try (hsimpleExpr syn') <|> simpleExternalExpr syn'
811 <?> "argument expression"
813{- | Parse a right hand side of a function
819RHSName ::= '{' FnName '}';
821rhs :: SyntaxInfo -> Name -> IdrisParser PTerm
822rhs syn n = do lchar '='; expr syn
824 name <- option n' (do symbol "{"; n <- fnName; symbol "}";
827 return (addLet name r)
828 <|> do reserved "impossible"; return PImpossible
829 <?> "function right hand side"
830 where mkN :: Name -> Name
831 mkN (UN x) = UN (x++"_lemma_1")
832 mkN (NS x n) = NS (mkN x) n
835 addLet :: Name -> PTerm -> PTerm
836 addLet nm (PLet n ty val r) = PLet n ty val (addLet nm r)
837 addLet nm (PCase fc t cs) = PCase fc t (map addLetC cs)
838 where addLetC (l, r) = (l, addLet nm r)
839 addLet nm r = (PLet (UN "value") Placeholder r (PMetavar nm))
841{- |Parses a function clause
842RHSOrWithBlock ::= RHS WhereOrTerminator
843 | 'with' SimpleExpr OpenBlock FnDecl+ CloseBlock
845Clause ::= WExpr+ RHSOrWithBlock
846 | SimpleExpr '<==' FnName RHS WhereOrTerminator
847 | ArgExpr Operator ArgExpr WExpr* RHSOrWithBlock {- Except "=" and "?=" operators to avoid ambiguity -}
848 | FnName ConstraintArg* ImplicitOrArgExpr* WExpr* RHSOrWithBlock
850ImplicitOrArgExpr ::= ImplicitArg | ArgExpr;
851WhereOrTerminator ::= WhereBlock | Terminator;
853clause :: SyntaxInfo -> IdrisParser PClause
855 = do wargs <- try (do pushIndent; some (wExpr syn))
858 n <- case lastParse ist of
860 Nothing -> fail "Invalid clause"
862 let ctxt = tt_ctxt ist
863 let wsyn = syn { syn_namespace = [] }
864 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
869 return $ PClauseR fc wargs r wheres) <|> (do
872 wval <- simpleExpr syn
874 ds <- some $ fnDecl syn
875 let withs = concat ds
877 return $ PWithR fc wargs wval withs)
878 <|> do ty <- try (do pushIndent
883 n_in <- fnName; let n = expandNS syn n_in
886 let ctxt = tt_ctxt ist
887 let wsyn = syn { syn_namespace = [] }
888 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
893 let capp = PLet (MN 0 "match")
896 (PRef fc (MN 0 "match"))
898 put (ist { lastParse = Just n })
899 return $ PClause fc n capp [] r wheres
900 <|> do (l, op) <- try (do
904 when (op == "=" || op == "?=" ) (fail "infix clause definition with \"=\" and \"?=\" not supported ")
906 let n = expandNS syn (UN op)
909 wargs <- many (wExpr syn)
911 let wsyn = syn { syn_namespace = [] }
912 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
918 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
919 put (ist { lastParse = Just n })
920 return $ PClause fc n capp wargs rs wheres) <|> (do
923 lchar '(' <?> "parenthesized expression"
924 wval <- bracketed syn
926 ds <- some $ fnDecl syn
929 let capp = PApp fc (PRef fc n) [pexp l, pexp r]
930 let withs = map (fillLHSD n capp wargs) $ concat ds
931 put (ist { lastParse = Just n })
932 return $ PWith fc n capp wargs wval withs)
934 n_in <- fnName; let n = expandNS syn n_in
935 cargs <- many (constraintArg syn)
937 args <- many (try (implicitArg (syn { inPattern = True } ))
938 <|> (fmap pexp (argExpr syn)))
939 wargs <- many (wExpr syn)
940 let capp = PApp fc (PRef fc n)
944 let ctxt = tt_ctxt ist
945 let wsyn = syn { syn_namespace = [] }
946 (wheres, nmap) <- choice [do x <- whereBlock n wsyn
952 put (ist { lastParse = Just n })
953 return $ PClause fc n capp wargs r wheres) <|> (do
956 put (ist { lastParse = Just n })
957 lchar '(' <?> "parenthesized expression"
958 wval <- bracketed syn
960 ds <- some $ fnDecl syn
961 let withs = map (fillLHSD n capp wargs) $ concat ds
964 return $ PWith fc n capp wargs wval withs)
965 <?> "function clause"
967 fillLHS :: Name -> PTerm -> [PTerm] -> PClause -> PClause
968 fillLHS n capp owargs (PClauseR fc wargs v ws)
969 = PClause fc n capp (owargs ++ wargs) v ws
970 fillLHS n capp owargs (PWithR fc wargs v ws)
971 = PWith fc n capp (owargs ++ wargs) v
972 (map (fillLHSD n capp (owargs ++ wargs)) ws)
975 fillLHSD :: Name -> PTerm -> [PTerm] -> PDecl -> PDecl
976 fillLHSD n c a (PClauses fc o fn cs) = PClauses fc o fn (map (fillLHS n c a) cs)
979{- |Parses with pattern
982wExpr :: SyntaxInfo -> IdrisParser PTerm
983wExpr syn = do lchar '|'
987{- |Parses a where block
988WhereBlock ::= 'where' OpenBlock Decl+ CloseBlock;
990whereBlock :: Name -> SyntaxInfo -> IdrisParser ([PDecl], [(Name, Name)])
992 = do reserved "where"
993 ds <- indentedBlock1 (decl syn)
994 let dns = concatMap (concatMap declared) ds
995 return (concat ds, map (\x -> (x, decoration syn x)) dns)
998{- |Parses a code generation target language name
1007codegen_ :: IdrisParser Codegen
1008codegen_ = do reserved "C"; return ViaC
1009 <|> do reserved "Java"; return ViaJava
1010 <|> do reserved "JavaScript"; return ViaJavaScript
1011 <|> do reserved "Node"; return ViaNode
1012 <|> do reserved "LLVM"; return ViaLLVM
1013 <|> do reserved "Bytecode"; return Bytecode
1014 <?> "code generation language"
1016{- |Parses a compiler directive
1019 | String ',' StringList
1022Directive ::= '%' Directive';
1024Directive' ::= 'lib' CodeGen String_t
1025 | 'link' CodeGen String_t
1026 | 'flag' CodeGen String_t
1027 | 'include' CodeGen String_t
1030 | 'access' Accessibility
1031 | 'default' Totality
1033 | 'dynamic' StringList
1034 | 'language' 'TypeProviders'
1035 | 'language' 'ErrorReflection'
1038directive :: SyntaxInfo -> IdrisParser [PDecl]
1039directive syn = do try (lchar '%' *> reserved "lib"); cgn <- codegen_; lib <- stringLiteral;
1040 return [PDirective (do addLib cgn lib
1041 addIBC (IBCLib cgn lib))]
1042 <|> do try (lchar '%' *> reserved "link"); cgn <- codegen_; obj <- stringLiteral;
1043 return [PDirective (do dirs <- allImportDirs
1044 o <- liftIO $ findInPath dirs obj
1045 addIBC (IBCObj cgn obj) -- just name, search on loading ibc
1046 addObjectFile cgn o)]
1047 <|> do try (lchar '%' *> reserved "flag"); cgn <- codegen_;
1048 flag <- stringLiteral
1049 return [PDirective (do addIBC (IBCCGFlag cgn flag)
1051 <|> do try (lchar '%' *> reserved "include"); cgn <- codegen_; hdr <- stringLiteral;
1052 return [PDirective (do addHdr cgn hdr
1053 addIBC (IBCHeader cgn hdr))]
1054 <|> do try (lchar '%' *> reserved "hide"); n <- iName []
1055 return [PDirective (do setAccessibility n Hidden
1056 addIBC (IBCAccess n Hidden))]
1057 <|> do try (lchar '%' *> reserved "freeze"); n <- iName []
1058 return [PDirective (do setAccessibility n Frozen
1059 addIBC (IBCAccess n Frozen))]
1060 <|> do try (lchar '%' *> reserved "access"); acc <- accessibility
1061 return [PDirective (do i <- get
1062 put(i { default_access = acc }))]
1063 <|> do try (lchar '%' *> reserved "default"); tot <- totality
1065 put (i { default_total = tot } )
1066 return [PDirective (do i <- get
1067 put(i { default_total = tot }))]
1068 <|> do try (lchar '%' *> reserved "logging"); i <- natural;
1069 return [PDirective (setLogLevel (fromInteger i))]
1070 <|> do try (lchar '%' *> reserved "dynamic"); libs <- sepBy1 stringLiteral (lchar ',');
1071 return [PDirective (do added <- addDyLib libs
1073 Left lib -> addIBC (IBCDyLib (lib_name lib))
1076 <|> do try (lchar '%' *> reserved "language"); ext <- pLangExt;
1077 return [PDirective (addLangExt ext)]
1080pLangExt :: IdrisParser LanguageExt
1081pLangExt = (reserved "TypeProviders" >> return TypeProviders)
1082 <|> (reserved "ErrorReflection" >> return ErrorReflection)
1084{- | Parses a totality
1085Totality ::= 'partial' | 'total'
1087totality :: IdrisParser Bool
1089 = do reserved "total"; return True
1090 <|> do reserved "partial"; return False
1092{- | Parses a type provider
1093Provider ::= '%' 'provide' '(' FnName TypeSig ')' 'with' Expr;
1095provider :: SyntaxInfo -> IdrisParser [PDecl]
1096provider syn = do try (lchar '%' *> reserved "provide");
1097 lchar '('; n <- fnName; lchar ':'; t <- typeExpr syn; lchar ')'
1101 return [PProvider syn fc n t e]
1104{- | Parses a transform
1105Transform ::= '%' 'transform' Expr '==>' Expr
1107transform :: SyntaxInfo -> IdrisParser [PDecl]
1108transform syn = do try (lchar '%' *> reserved "transform")
1109 -- leave it unchecked, until we work out what this should
1111-- safety <- option True (do reserved "unsafe"
1117 return [PTransform fc False l r]
1121{- * Loading and parsing -}
1122{- | Parses an expression from input -}
1123parseExpr :: IState -> String -> Result PTerm
1124parseExpr st = parseString (runInnerParser (evalStateT (fullExpr defaultSyntax) st)) (Directed (UTF8.fromString "(input)") 0 0 0 0)
1126{- | Parses a tactic from input -}
1127parseTactic :: IState -> String -> Result PTactic
1128parseTactic st = parseString (runInnerParser (evalStateT (fullTactic defaultSyntax) st)) (Directed (UTF8.fromString "(input)") 0 0 0 0)
1130-- | Parse module header and imports
1131parseImports :: FilePath -> String -> Idris ([String], [String], Maybe Delta)
1132parseImports fname input
1134 case parseString (runInnerParser (evalStateT imports i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
1135 Failure err -> fail (show err)
1136 Success (x, i) -> do -- Discard state updates (there should be
1139 where imports :: IdrisParser (([String], [String], Maybe Delta), IState)
1140 imports = do whiteSpace
1141 mname <- moduleHeader
1144 isEof <- lookAheadMatches eof
1149 return ((mname, ps, mrk'), i)
1152-- | A program is a list of declarations, possibly with associated
1153-- documentation strings.
1154parseProg :: SyntaxInfo -> FilePath -> String -> Maybe Delta ->
1156parseProg syn fname input mrk
1158 case parseString (runInnerParser (evalStateT mainProg i)) (Directed (UTF8.fromString fname) 0 0 0 0) input of
1159 Failure doc -> do iputStrLn (show doc)
1160 -- FIXME: Get error location from trifecta
1161 --let errl = sourceLine (errorPos err)
1163 putIState (i { errLine = Just 0 }) -- Just errl })
1165 Success (x, i) -> do putIState i
1167 where mainProg :: IdrisParser ([PDecl], IState)
1168 mainProg = case mrk of
1169 Nothing -> do i <- get; return ([], i)
1176-- | Collect 'PClauses' with the same function name
1177collect :: [PDecl] -> [PDecl]
1178collect (c@(PClauses _ o _ _) : ds)
1179 = clauses (cname c) [] (c : ds)
1180 where clauses :: Maybe Name -> [PClause] -> [PDecl] -> [PDecl]
1181 clauses j@(Just n) acc (PClauses fc _ _ [PClause fc' n' l ws r w] : ds)
1182 | n == n' = clauses j (PClause fc' n' l ws r (collect w) : acc) ds
1183 clauses j@(Just n) acc (PClauses fc _ _ [PWith fc' n' l ws r w] : ds)
1184 | n == n' = clauses j (PWith fc' n' l ws r (collect w) : acc) ds
1185 clauses (Just n) acc xs = PClauses (fcOf c) o n (reverse acc) : collect xs
1186 clauses Nothing acc (x:xs) = collect xs
1187 clauses Nothing acc [] = []
1189 cname :: PDecl -> Maybe Name
1190 cname (PClauses fc _ _ [PClause _ n _ _ _ _]) = Just n
1191 cname (PClauses fc _ _ [PWith _ n _ _ _ _]) = Just n
1192 cname (PClauses fc _ _ [PClauseR _ _ _ _]) = Nothing
1193 cname (PClauses fc _ _ [PWithR _ _ _ _]) = Nothing
1195 fcOf (PClauses fc _ _ _) = fc
1196collect (PParams f ns ps : ds) = PParams f ns (collect ps) : collect ds
1197collect (PMutual f ms : ds) = PMutual f (collect ms) : collect ds
1198collect (PNamespace ns ps : ds) = PNamespace ns (collect ps) : collect ds
1199collect (PClass doc f s cs n ps ds : ds')
1200 = PClass doc f s cs n ps (collect ds) : collect ds'
1201collect (PInstance f s cs n ps t en ds : ds')
1202 = PInstance f s cs n ps t en (collect ds) : collect ds'
1203collect (d : ds) = d : collect ds
1206{- | Load idris module -}
1207loadModule :: FilePath -> Idris String
1209 = idrisCatch (do i <- getIState
1210 let file = takeWhile (/= ' ') f
1211 ibcsd <- valIBCSubDir i
1212 ids <- allImportDirs
1213 fp <- liftIO $ findImport ids ibcsd file
1214 if file `elem` imported i
1215 then iLOG $ "Already read " ++ file
1216 else do putIState (i { imported = file : imported i })
1218 IDR fn -> loadSource False fn
1219 LIDR fn -> loadSource True fn
1221 idrisCatch (loadIBC fn)
1222 (\c -> do iLOG $ fn ++ " failed " ++ show c
1224 IDR sfn -> loadSource False sfn
1225 LIDR sfn -> loadSource True sfn)
1226 let (dir, fh) = splitFileName file
1227 return (dropExtension fh))
1228 (\e -> do let msg = show e
1229 setErrLine (getErrLine msg)
1233{- | Load idris code from file -}
1234loadFromIFile :: IFileType -> Idris ()
1235loadFromIFile i@(IBC fn src)
1236 = do iLOG $ "Skipping " ++ getSrcFile i
1237 idrisCatch (loadIBC fn)
1238 (\c -> do fail $ fn ++ " failed " ++ show c)
1240 getSrcFile (IDR fn) = fn
1241 getSrcFile (LIDR fn) = fn
1242 getSrcFile (IBC f src) = getSrcFile src
1244loadFromIFile (IDR fn) = loadSource' False fn
1245loadFromIFile (LIDR fn) = loadSource' True fn
1247{-| Load idris source code and show error if something wrong happens -}
1248loadSource' :: Bool -> FilePath -> Idris ()
1250 = idrisCatch (loadSource lidr r)
1251 (\e -> do let msg = show e
1252 setErrLine (getErrLine msg)
1255{- | Load Idris source code-}
1256loadSource :: Bool -> FilePath -> Idris ()
1258 = do iLOG ("Reading " ++ f)
1260 let def_total = default_total i
1261 file_in <- liftIO $ readFile f
1262 file <- if lidr then tclift $ unlit f file_in else return file_in
1263 (mname, modules, pos) <- parseImports f file
1265 putIState (i { default_access = Hidden })
1266 clearIBC -- start a new .ibc file
1267 mapM_ (addIBC . IBCImport) modules
1268 ds' <- parseProg (defaultSyntax {syn_namespace = reverse mname })
1270 unless (null ds') $ do
1271 let ds = namespaces mname ds'
1272 logLvl 3 (dumpDecls ds)
1274 logLvl 10 (show (toAlist (idris_implicits i)))
1275 logLvl 3 (show (idris_infixes i))
1276 -- Now add all the declarations to the context
1278 when v $ iputStrLn $ "Type checking " ++ f
1279 -- we totality check after every Mutual block, so if
1280 -- anything is a single definition, wrap it in a
1281 -- mutual block on its own
1282 elabDecls toplevel (map toMutual ds)
1284 -- simplify every definition do give the totality checker
1286 mapM_ (\n -> do logLvl 5 $ "Simplifying " ++ show n
1287 updateContext (simplifyCasedef n))
1288 (map snd (idris_totcheck i))
1289 -- build size change graph from simplified definitions
1290 iLOG "Totality checking"
1292 mapM_ buildSCG (idris_totcheck i)
1293 mapM_ checkDeclTotality (idris_totcheck i)
1294 iLOG ("Finished " ++ f)
1295 ibcsd <- valIBCSubDir i
1296 iLOG "Universe checking"
1298 let ibc = ibcPathNoFallback ibcsd f
1300 addHides (hide_list i)
1303 idrisCatch (do writeIBC f ibc; clearIBC)
1304 (\c -> return ()) -- failure is harmless
1306 putIState (i { default_total = def_total,
1311 namespaces :: [String] -> [PDecl] -> [PDecl]
1312 namespaces [] ds = ds
1313 namespaces (x:xs) ds = [PNamespace x (namespaces xs ds)]
1315 toMutual :: PDecl -> PDecl
1316 toMutual m@(PMutual _ d) = m
1317 toMutual x = let r = PMutual (FC "single mutual" 0) [x] in
1319 PClauses _ _ _ _ -> r
1320 PClass _ _ _ _ _ _ _ -> r
1321 PInstance _ _ _ _ _ _ _ _ -> r
1324{- | Adds names to hide list -}
1325addHides :: [(Name, Maybe Accessibility)] -> Idris ()
1326addHides xs = do i <- getIState
1327 let defh = default_access i
1328 let (hs, as) = partition isNothing xs
1331 (map (\ (n, _) -> (n, defh)) hs ++
1332 map (\ (n, Just a) -> (n, a)) as)
1333 where isNothing (_, Nothing) = True
1336 doHide (n, a) = do setAccessibility n a
1337 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