2Module : Idris.Parser.Data
3Description : Parse Data declarations.
6Maintainer : The Idris Community.
8{-# LANGUAGE ConstraintKinds, GeneralizedNewtypeDeriving, PatternGuards #-}
9module Idris.Parser.Data where
12import Idris.Core.Evaluate
14import Idris.Docstrings
17import Idris.Parser.Expr
18import Idris.Parser.Helpers
19import Idris.Parser.Ops
21import Prelude hiding (pi)
23import Control.Applicative
25import Control.Monad.State.Strict
26import qualified Data.ByteString.UTF8 as UTF8
28import qualified Data.HashSet as HS
30import qualified Data.List.Split as Spl
33import qualified Data.Text as T
35import qualified Text.Parser.Char as Chr
36import Text.Parser.Expression
37import Text.Parser.LookAhead
38import qualified Text.Parser.Token as Tok
39import qualified Text.Parser.Token.Highlight as Hi
40import Text.Trifecta hiding (Err, char, charLiteral, natural, span, string,
41 stringLiteral, symbol, whiteSpace)
42import Text.Trifecta.Delta
44{- | Parses a record type declaration
46 DocComment Accessibility? 'record' FnName TypeSig 'where' OpenBlock Constructor KeepTerminator CloseBlock;
48record :: SyntaxInfo -> IdrisParser PDecl
49record syn = do (doc, paramDocs, acc, opts) <- try (do
50 (doc, paramDocs) <- option noDocs docComment
52 let doc' = annotCode (tryFullExpr syn ist) doc
53 paramDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
54 | (n, d) <- paramDocs ]
58 return (doc', paramDocs', acc, opts ++ co))
60 (tyn_in, nfc) <- fnName
61 let tyn = expandNS syn tyn_in
62 let rsyn = syn { syn_namespace = show (nsroot tyn) :
64 params <- manyTill (recordParameter rsyn) (reservedHL "where")
65 (fields, cname, cdoc) <- indentedBlockS $ recordBody rsyn tyn
66 let fnames = map (expandNS rsyn) (mapMaybe getName fields)
68 Just cn' -> accData acc tyn (fst cn' : fnames)
70 return $ PRecord doc rsyn fc opts tyn nfc params paramDocs fields cname cdoc syn
71 <?> "record type declaration"
73 getRecNames :: SyntaxInfo -> PTerm -> [Name]
74 getRecNames syn (PPi _ n _ _ sc) = [expandNS syn n, expandNS syn (mkType n)]
78 getName (Just (n, _), _, _, _) = Just n
81 toFreeze :: Maybe Accessibility -> Maybe Accessibility
82 toFreeze (Just Frozen) = Just Private
85 recordBody :: SyntaxInfo -> Name -> IdrisParser ([((Maybe (Name, FC)), Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))], Maybe (Name, FC), Docstring (Either Err PTerm))
86 recordBody syn tyn = do
90 (constructorName, constructorDoc) <- option (Nothing, emptyDocstring)
91 (do (doc, _) <- option noDocs docComment
95 let constructorDoc' = annotate syn ist constructorDoc
97 fields <- many . indented $ fieldLine syn
99 return (concat fields, constructorName, constructorDoc')
101 fieldLine :: SyntaxInfo -> IdrisParser [(Maybe (Name, FC), Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))]
103 doc <- optional docComment
104 c <- optional $ lchar '{'
105 let oneName = (do (n, nfc) <- fnName
106 return $ Just (expandNS syn n, nfc))
107 <|> (symbol "_" >> return Nothing)
108 ns <- commaSeparated oneName
110 -- Implicits are scoped in fields (fields aren't top level)
111 t <- typeExpr (scopedImp syn)
114 let doc' = case doc of -- Temp: Throws away any possible arg docs
115 Just (d,_) -> Just $ annotate syn ist d
117 return $ map (\n -> (n, p, t, doc')) ns
119 constructor :: IdrisParser (Name, FC)
120 constructor = (reservedHL "constructor") *> fnName
123 endPlicity :: Maybe Char -> IdrisParser Plicity
124 endPlicity (Just _) = do lchar '}'
126 endPlicity Nothing = return expl
128 annotate :: SyntaxInfo -> IState -> Docstring () -> Docstring (Either Err PTerm)
129 annotate syn ist = annotCode $ tryFullExpr syn ist
131recordParameter :: SyntaxInfo -> IdrisParser (Name, FC, Plicity, PTerm)
134 (n, nfc, pt) <- (namedTy syn <|> onlyName syn)
136 return (n, nfc, expl, pt))
138 (do (n, nfc, pt) <- onlyName syn
139 return (n, nfc, expl, pt))
141 namedTy :: SyntaxInfo -> IdrisParser (Name, FC, PTerm)
143 do (n, nfc) <- fnName
145 ty <- typeExpr (allowImp syn)
146 return (expandNS syn n, nfc, ty)
147 onlyName :: SyntaxInfo -> IdrisParser (Name, FC, PTerm)
149 do (n, nfc) <- fnName
151 return (expandNS syn n, nfc, PType fc)
153{- | Parses data declaration type (normal or codata)
154DataI ::= 'data' | 'codata';
156dataI :: IdrisParser DataOpts
157dataI = do reservedHL "data"; return []
158 <|> do reservedHL "codata"; return [Codata]
160recordI :: IdrisParser DataOpts
161recordI = do reservedHL "record"; return []
162 <|> do reservedHL "corecord"; return [Codata]
164{- | Parses if a data should not have a default eliminator
165DefaultEliminator ::= 'noelim'?
167dataOpts :: DataOpts -> IdrisParser DataOpts
169 = do fc <- reservedFC "%elim"
171 dataOpts (DefaultEliminator : DefaultCaseFun : opts)
172 <|> do fc <- reservedFC "%case"
174 dataOpts (DefaultCaseFun : opts)
175 <|> do reserved "%error_reverse"; dataOpts (DataErrRev : opts)
179 parserWarning fc (Just NoElimDeprecationWarnings) (Msg "The 'class' keyword is deprecated. Use 'interface' instead.")
181{- | Parses a data type declaration
182Data ::= DocComment? Accessibility? DataI DefaultEliminator FnName TypeSig ExplicitTypeDataRest?
183 | DocComment? Accessibility? DataI DefaultEliminator FnName Name* DataRest?
185Constructor' ::= Constructor KeepTerminator;
186ExplicitTypeDataRest ::= 'where' OpenBlock Constructor'* CloseBlock;
188DataRest ::= '=' SimpleConstructorList Terminator
191SimpleConstructorList ::=
193 | SimpleConstructor '|' SimpleConstructorList
196data_ :: SyntaxInfo -> IdrisParser PDecl
197data_ syn = checkDeclFixity $
198 do (doc, argDocs, acc, dataOpts) <- try (do
199 (doc, argDocs) <- option noDocs docComment
205 let dataOpts = combineDataOpts (elim ++ co)
206 doc' = annotCode (tryFullExpr syn ist) doc
207 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
208 | (n, d) <- argDocs ]
209 return (doc', argDocs', acc, dataOpts))
211 (tyn_in, nfc) <- fnName
213 ty <- typeExpr (allowImp syn)
214 let tyn = expandNS syn tyn_in
215 d <- option (PData doc argDocs syn fc dataOpts (PLaterdecl tyn nfc ty)) (do
217 cons <- indentedBlock (constructor syn)
218 accData acc tyn (map (\ (_, _, n, _, _, _, _) -> n) cons)
219 return $ PData doc argDocs syn fc dataOpts (PDatadecl tyn nfc ty cons))
222 args <- many (do notEndApp
225 let ty = bindArgs (map (const (PType fc)) args) (PType fc)
226 let tyn = expandNS syn tyn_in
227 d <- option (PData doc argDocs syn fc dataOpts (PLaterdecl tyn nfc ty)) (do
228 try (lchar '=') <|> do reservedHL "where"
229 let kw = (if DefaultEliminator `elem` dataOpts then "%elim" else "") ++ (if Codata `elem` dataOpts then "co" else "") ++ "data "
230 let n = show tyn_in ++ " "
232 let as = unwords (map show args) ++ " "
233 let ns = concat (intersperse " -> " $ map ((\x -> "(" ++ x ++ " : Type)") . show) args)
234 let ss = concat (intersperse " -> " $ map (const "Type") args)
235 let fix1 = s ++ as ++ " = ..."
236 let fix2 = s ++ ": " ++ ns ++ " -> Type where\n ..."
237 let fix3 = s ++ ": " ++ ss ++ " -> Type where\n ..."
238 fail $ fixErrorMsg "unexpected \"where\"" [fix1, fix2, fix3]
239 cons <- sepBy1 (simpleConstructor (syn { withAppAllowed = False })) (reservedOp "|")
240 let conty = mkPApp fc (PRef fc [] tyn) (map (PRef fc []) args)
241 cons' <- mapM (\ (doc, argDocs, x, xfc, cargs, cfc, fs) ->
242 do let cty = bindArgs cargs conty
243 return (doc, argDocs, x, xfc, cty, cfc, fs)) cons
244 accData acc tyn (map (\ (_, _, n, _, _, _, _) -> n) cons')
245 return $ PData doc argDocs syn fc dataOpts (PDatadecl tyn nfc ty cons'))
248 <?> "data type declaration"
250 mkPApp :: FC -> PTerm -> [PTerm] -> PTerm
252 mkPApp fc t xs = PApp fc t (map pexp xs)
253 bindArgs :: [PTerm] -> PTerm -> PTerm
254 bindArgs xs t = foldr (PPi expl (sMN 0 "_t") NoFC) t xs
255 combineDataOpts :: DataOpts -> DataOpts
256 combineDataOpts opts = if Codata `elem` opts
257 then delete DefaultEliminator opts
261{- | Parses a type constructor declaration
262 Constructor ::= DocComment? FnName TypeSig;
264constructor :: SyntaxInfo -> IdrisParser (Docstring (Either Err PTerm), [(Name, Docstring (Either Err PTerm))], Name, FC, PTerm, FC, [Name])
266 = do (doc, argDocs) <- option noDocs docComment
267 (cn_in, nfc) <- fnName; fc <- getFC
268 let cn = expandNS syn cn_in
270 fs <- option [] (do lchar '%'; reserved "erase"
271 sepBy1 (fst <$> name) (lchar ','))
272 ty <- typeExpr (allowImp syn)
274 let doc' = annotCode (tryFullExpr syn ist) doc
275 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
276 | (n, d) <- argDocs ]
278 return (doc', argDocs', cn, nfc, ty, fc, fs)
281{- | Parses a constructor for simple discriminated union data types
282 SimpleConstructor ::= FnName SimpleExpr* DocComment?
284simpleConstructor :: SyntaxInfo -> IdrisParser (Docstring (Either Err PTerm), [(Name, Docstring (Either Err PTerm))], Name, FC, [PTerm], FC, [Name])
286 = do (doc, _) <- option noDocs (try docComment)
288 let doc' = annotCode (tryFullExpr syn ist) doc
289 (cn_in, nfc) <- fnName
290 let cn = expandNS syn cn_in
292 args <- many (do notEndApp
295 return (doc', [], cn, nfc, args, fc, [])
298{- | Parses a dsl block declaration
299DSL ::= 'dsl' FnName OpenBlock Overload'+ CloseBlock;
301dsl :: SyntaxInfo -> IdrisParser PDecl
302dsl syn = do reservedHL "dsl"
304 bs <- indentedBlock (overload syn)
305 let dsl = mkDSL bs (dsl_info syn)
308 put (i { idris_dsls = addDef n dsl (idris_dsls i) })
310 <?> "dsl block declaration"
311 where mkDSL :: [(String, PTerm)] -> DSL -> DSL
312 mkDSL bs dsl = let var = lookup "variable" bs
313 first = lookup "index_first" bs
314 next = lookup "index_next" bs
315 leto = lookup "let" bs
316 lambda = lookup "lambda" bs
317 pi = lookup "pi" bs in
318 initDSL { dsl_var = var,
325{- | Checks DSL for errors -}
326-- FIXME: currently does nothing, check if DSL is really sane
328-- Issue #1595 on the Issue Tracker
330-- https://github.com/idris-lang/Idris-dev/issues/1595
332checkDSL :: DSL -> IdrisParser ()
333checkDSL dsl = return ()
335{- | Parses a DSL overload declaration
336OverloadIdentifier ::= 'let' | Identifier;
337Overload ::= OverloadIdentifier '=' Expr;
339overload :: SyntaxInfo -> IdrisParser (String, PTerm)
340overload syn = do (o, fc) <- identifier <|> do fc <- reservedFC "let"
342 if o `notElem` overloadable
343 then fail $ show o ++ " is not an overloading"
345 highlightP fc AnnKeyword
349 <?> "dsl overload declaratioN"
350 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