2Module : Idris.Parser.Data
3Description : Parse Data declarations.
6Maintainer : The Idris Community.
8{-# LANGUAGE ConstraintKinds, FlexibleContexts, GeneralizedNewtypeDeriving,
9 MultiParamTypeClasses, PatternGuards #-}
10module Idris.Parser.Data where
14import Idris.Docstrings
16import Idris.Parser.Expr
17import Idris.Parser.Helpers
18import Idris.Parser.Ops
20import Prelude hiding (pi)
22import Control.Applicative
23import Control.Monad.State.Strict
26import Text.Megaparsec ((<?>))
27import qualified Text.Megaparsec as P
29{- | Parses a record type declaration
31 DocComment Accessibility? 'record' FnName TypeSig 'where' OpenBlock Constructor KeepTerminator CloseBlock;
33record :: SyntaxInfo -> IdrisParser PDecl
34record syn = (appExtent $ do
35 (doc, paramDocs, acc, opts) <- P.try (do
36 (doc, paramDocs) <- P.option noDocs docComment
38 let doc' = annotCode (tryFullExpr syn ist) doc
39 paramDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
40 | (n, d) <- paramDocs ]
44 return (doc', paramDocs', acc, opts ++ co))
45 (tyn_in, nfc) <- withExtent fnName
46 let tyn = expandNS syn tyn_in
47 let rsyn = syn { syn_namespace = show (nsroot tyn) :
49 params <- P.manyTill (recordParameter rsyn) (keyword "where")
50 (fields, cname, cdoc) <- indentedBlockS $ recordBody rsyn tyn
51 let fnames = map (expandNS rsyn) (mapMaybe getName fields)
53 Just cn' -> accData acc tyn (fst cn' : fnames)
55 return $ \fc -> PRecord doc rsyn fc opts tyn nfc params paramDocs fields cname cdoc syn)
56 <?> "record type declaration"
58 getName (Just (n, _), _, _, _) = Just n
61 recordBody :: SyntaxInfo -> Name -> IdrisParser ([((Maybe (Name, FC)), Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))], Maybe (Name, FC), Docstring (Either Err PTerm))
62 recordBody syn tyn = do
65 (constructorName, constructorDoc) <- P.option (Nothing, emptyDocstring)
66 (do (doc, _) <- P.option noDocs docComment
67 n <- withExtent constructor
70 let constructorDoc' = annotate syn ist constructorDoc
72 fields <- many . indented $ fieldLine syn
74 return (concat fields, constructorName, constructorDoc')
76 fieldLine :: SyntaxInfo -> IdrisParser [(Maybe (Name, FC), Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))]
78 doc <- optional docComment
79 c <- optional $ lchar '{'
80 let oneName = (do (n, nfc) <- withExtent fnName
81 return $ Just (expandNS syn n, nfc))
82 <|> (symbol "_" >> return Nothing)
83 ns <- commaSeparated oneName
85 -- Implicits are scoped in fields (fields aren't top level)
86 t <- typeExpr (scopedImp syn)
89 let doc' = case doc of -- Temp: Throws away any possible arg docs
90 Just (d,_) -> Just $ annotate syn ist d
92 return $ map (\n -> (n, p, t, doc')) ns
94 constructor :: (Parsing m, MonadState IState m) => m Name
95 constructor = keyword "constructor" *> fnName
97 endPlicity :: Maybe Char -> IdrisParser Plicity
98 endPlicity (Just _) = do lchar '}'
100 endPlicity Nothing = return expl
102 annotate :: SyntaxInfo -> IState -> Docstring () -> Docstring (Either Err PTerm)
103 annotate syn ist = annotCode $ tryFullExpr syn ist
105recordParameter :: SyntaxInfo -> IdrisParser (Name, FC, Plicity, PTerm)
108 (n, nfc, pt) <- (namedTy syn <|> onlyName syn)
110 return (n, nfc, expl, pt))
112 (do (n, nfc, pt) <- onlyName syn
113 return (n, nfc, expl, pt))
115 namedTy :: SyntaxInfo -> IdrisParser (Name, FC, PTerm)
117 do (n, nfc) <- withExtent fnName
119 ty <- typeExpr (allowImp syn)
120 return (expandNS syn n, nfc, ty)
121 onlyName :: SyntaxInfo -> IdrisParser (Name, FC, PTerm)
123 do (n, nfc) <- withExtent fnName
124 return (expandNS syn n, nfc, PType nfc)
126{- | Parses data declaration type (normal or codata)
127DataI ::= 'data' | 'codata';
129dataI :: IdrisParser DataOpts
130dataI = do keyword "data"; return []
131 <|> do keyword "codata"; return [Codata]
133recordI :: IdrisParser DataOpts
134recordI = do keyword "record"; return []
135 <|> do keyword "corecord"; return [Codata]
137{- | Parses if a data should not have a default eliminator
138DefaultEliminator ::= 'noelim'?
140dataOpts :: DataOpts -> IdrisParser DataOpts
142 = do let kw = "%elim"
143 fc <- extent $ reserved kw
145 dataOpts (DefaultEliminator : DefaultCaseFun : opts)
146 <|> do let kw = "%case"
147 fc <- extent $ reserved kw
149 dataOpts (DefaultCaseFun : opts)
150 <|> do reserved "%error_reverse"; dataOpts (DataErrRev : opts)
153 where warnElim fc kw =
154 parserWarning fc (Just NoElimDeprecationWarnings)
155 (Msg ("The '" ++ kw ++ "' directive is deprecated."))
157{- | Parses a data type declaration
158Data ::= DocComment? Accessibility? DataI DefaultEliminator FnName TypeSig ExplicitTypeDataRest?
159 | DocComment? Accessibility? DataI DefaultEliminator FnName Name* DataRest?
161Constructor' ::= Constructor KeepTerminator;
162ExplicitTypeDataRest ::= 'where' OpenBlock Constructor'* CloseBlock;
164DataRest ::= '=' SimpleConstructorList Terminator
167SimpleConstructorList ::=
169 | SimpleConstructor '|' SimpleConstructorList
172data_ :: SyntaxInfo -> IdrisParser PDecl
173data_ syn = (checkDeclFixity $
174 do (doc, argDocs, acc, dataOpts) <- P.try (do
175 (doc, argDocs) <- P.option noDocs docComment
181 let dataOpts = combineDataOpts (elim ++ co)
182 doc' = annotCode (tryFullExpr syn ist) doc
183 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
184 | (n, d) <- argDocs ]
185 return (doc', argDocs', acc, dataOpts))
186 (tyn_in, nfc) <- withExtent fnName
187 (do P.try (lchar ':')
188 ty <- typeExpr (allowImp syn)
189 let tyn = expandNS syn tyn_in
190 d <- P.option (PData doc argDocs syn nfc dataOpts (PLaterdecl tyn nfc ty)) (do
192 cons <- indentedBlock (constructor syn)
193 accData acc tyn (map (\ (_, _, n, _, _, _, _) -> n) cons)
194 return $ PData doc argDocs syn nfc dataOpts (PDatadecl tyn nfc ty cons))
197 args <- many (do notEndApp
200 let ty = bindArgs (map (const (PType nfc)) args) (PType nfc)
201 let tyn = expandNS syn tyn_in
202 d <- P.option (PData doc argDocs syn nfc dataOpts (PLaterdecl tyn nfc ty)) (do
203 P.try (lchar '=') <|> do keyword "where"
204 let kw = (if DefaultEliminator `elem` dataOpts then "%elim" else "") ++ (if Codata `elem` dataOpts then "co" else "") ++ "data "
205 let n = show tyn_in ++ " "
207 let as = unwords (map show args) ++ " "
208 let ns = concat (intersperse " -> " $ map ((\x -> "(" ++ x ++ " : Type)") . show) args)
209 let ss = concat (intersperse " -> " $ map (const "Type") args)
210 let fix1 = s ++ as ++ " = ..."
211 let fix2 = s ++ ": " ++ ns ++ " -> Type where\n ..."
212 let fix3 = s ++ ": " ++ ss ++ " -> Type where\n ..."
213 fail $ fixErrorMsg "unexpected \"where\"" [fix1, fix2, fix3]
214 cons <- P.sepBy1 (simpleConstructor (syn { withAppAllowed = False })) (reservedOp "|")
215 let conty = mkPApp nfc (PRef nfc [] tyn) (map (PRef nfc []) args)
216 cons' <- mapM (\ (doc, argDocs, x, xfc, cargs, cfc, fs) ->
217 do let cty = bindArgs cargs conty
218 return (doc, argDocs, x, xfc, cty, cfc, fs)) cons
219 accData acc tyn (map (\ (_, _, n, _, _, _, _) -> n) cons')
220 return $ PData doc argDocs syn nfc dataOpts (PDatadecl tyn nfc ty cons'))
223 <?> "data type declaration"
225 mkPApp :: FC -> PTerm -> [PTerm] -> PTerm
227 mkPApp fc t xs = PApp fc t (map pexp xs)
228 bindArgs :: [PTerm] -> PTerm -> PTerm
229 bindArgs xs t = foldr (PPi expl (sMN 0 "_t") NoFC) t xs
230 combineDataOpts :: DataOpts -> DataOpts
231 combineDataOpts opts = if Codata `elem` opts
232 then delete DefaultEliminator opts
236{- | Parses a type constructor declaration
237 Constructor ::= DocComment? FnName TypeSig;
239constructor :: SyntaxInfo -> IdrisParser (Docstring (Either Err PTerm), [(Name, Docstring (Either Err PTerm))], Name, FC, PTerm, FC, [Name])
241 = do (doc, argDocs) <- P.option noDocs docComment
242 (cn_in, nfc) <- withExtent fnName
243 let cn = expandNS syn cn_in
245 fs <- P.option [] (do lchar '%'; reserved "erase"
246 P.sepBy1 name (lchar ','))
247 (ty, fc) <- withExtent $ typeExpr (allowImp syn)
249 let doc' = annotCode (tryFullExpr syn ist) doc
250 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
251 | (n, d) <- argDocs ]
253 return (doc', argDocs', cn, nfc, ty, fc, fs)
256{- | Parses a constructor for simple discriminated union data types
257 SimpleConstructor ::= FnName SimpleExpr* DocComment?
259simpleConstructor :: SyntaxInfo -> IdrisParser (Docstring (Either Err PTerm), [(Name, Docstring (Either Err PTerm))], Name, FC, [PTerm], FC, [Name])
262 (doc, _) <- P.option noDocs (P.try docComment)
264 let doc' = annotCode (tryFullExpr syn ist) doc
265 (cn_in, nfc) <- withExtent fnName
266 let cn = expandNS syn cn_in
267 args <- many (do notEndApp
270 return $ \fc -> (doc', [], cn, nfc, args, fc, []))
272{- | Parses a dsl block declaration
273DSL ::= 'dsl' FnName OpenBlock Overload'+ CloseBlock;
275dsl :: SyntaxInfo -> IdrisParser PDecl
276dsl syn = do keyword "dsl"
278 bs <- indentedBlock (overload syn)
279 let dsl = mkDSL bs (dsl_info syn)
282 put (i { idris_dsls = addDef n dsl (idris_dsls i) })
284 <?> "dsl block declaration"
285 where mkDSL :: [(String, PTerm)] -> DSL -> DSL
286 mkDSL bs dsl = let var = lookup "variable" bs
287 first = lookup "index_first" bs
288 next = lookup "index_next" bs
289 leto = lookup "let" bs
290 lambda = lookup "lambda" bs
291 pi = lookup "pi" bs in
292 initDSL { dsl_var = var,
299{- | Checks DSL for errors -}
300-- FIXME: currently does nothing, check if DSL is really sane
302-- Issue #1595 on the Issue Tracker
304-- https://github.com/idris-lang/Idris-dev/issues/1595
306checkDSL :: DSL -> IdrisParser ()
307checkDSL dsl = return ()
309{- | Parses a DSL overload declaration
310OverloadIdentifier ::= 'let' | Identifier;
311Overload ::= OverloadIdentifier '=' Expr;
313overload :: SyntaxInfo -> IdrisParser (String, PTerm)
314overload syn = do o <- highlight AnnKeyword $ identifier <|> "let" <$ reserved "let"
315 if o `notElem` overloadable
316 then fail $ show o ++ " is not an overloading"
321 <?> "dsl overload declaratioN"
322 where overloadable = ["let","lambda","pi","index_first","index_next","variable"]
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