2Module : Idris.Parser.Data
3Description : Parse Data declarations.
6Maintainer : The Idris Community.
8{-# LANGUAGE GeneralizedNewtypeDeriving, ConstraintKinds, PatternGuards #-}
9module Idris.Parser.Data where
11import Prelude hiding (pi)
13import Text.Trifecta.Delta
14import Text.Trifecta hiding ( span, stringLiteral, charLiteral, natural
15 , symbol, char, string, whiteSpace, Err)
17import Text.Parser.LookAhead
18import Text.Parser.Expression
19import qualified Text.Parser.Token as Tok
20import qualified Text.Parser.Char as Chr
21import qualified Text.Parser.Token.Highlight as Hi
24import Idris.Parser.Helpers
25import Idris.Parser.Ops
26import Idris.Parser.Expr
30import Idris.Core.Evaluate
32import Idris.Docstrings
34import Control.Applicative
36import Control.Monad.State.Strict
39import qualified Data.List.Split as Spl
43import qualified Data.HashSet as HS
44import qualified Data.Text as T
45import qualified Data.ByteString.UTF8 as UTF8
49{- | Parses a record type declaration
51 DocComment Accessibility? 'record' FnName TypeSig 'where' OpenBlock Constructor KeepTerminator CloseBlock;
53record :: SyntaxInfo -> IdrisParser PDecl
54record syn = do (doc, paramDocs, acc, opts) <- try (do
55 (doc, paramDocs) <- option noDocs docComment
57 let doc' = annotCode (tryFullExpr syn ist) doc
58 paramDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
59 | (n, d) <- paramDocs ]
63 return (doc', paramDocs', acc, opts ++ co))
65 (tyn_in, nfc) <- fnName
66 let tyn = expandNS syn tyn_in
67 let rsyn = syn { syn_namespace = show (nsroot tyn) :
69 params <- manyTill (recordParameter rsyn) (reservedHL "where")
70 (fields, cname, cdoc) <- indentedBlockS $ recordBody rsyn tyn
71 let fnames = map (expandNS rsyn) (mapMaybe getName fields)
73 Just cn' -> accData acc tyn (fst cn' : fnames)
75 return $ PRecord doc rsyn fc opts tyn nfc params paramDocs fields cname cdoc syn
76 <?> "record type declaration"
78 getRecNames :: SyntaxInfo -> PTerm -> [Name]
79 getRecNames syn (PPi _ n _ _ sc) = [expandNS syn n, expandNS syn (mkType n)]
83 getName (Just (n, _), _, _, _) = Just n
86 toFreeze :: Maybe Accessibility -> Maybe Accessibility
87 toFreeze (Just Frozen) = Just Private
90 recordBody :: SyntaxInfo -> Name -> IdrisParser ([((Maybe (Name, FC)), Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))], Maybe (Name, FC), Docstring (Either Err PTerm))
91 recordBody syn tyn = do
95 (constructorName, constructorDoc) <- option (Nothing, emptyDocstring)
96 (do (doc, _) <- option noDocs docComment
100 let constructorDoc' = annotate syn ist constructorDoc
102 fields <- many . indented $ fieldLine syn
104 return (concat fields, constructorName, constructorDoc')
106 fieldLine :: SyntaxInfo -> IdrisParser [(Maybe (Name, FC), Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))]
108 doc <- optional docComment
109 c <- optional $ lchar '{'
110 let oneName = (do (n, nfc) <- fnName
111 return $ Just (expandNS syn n, nfc))
112 <|> (symbol "_" >> return Nothing)
113 ns <- commaSeparated oneName
115 t <- typeExpr (allowImp syn)
118 let doc' = case doc of -- Temp: Throws away any possible arg docs
119 Just (d,_) -> Just $ annotate syn ist d
121 return $ map (\n -> (n, p, t, doc')) ns
123 constructor :: IdrisParser (Name, FC)
124 constructor = (reservedHL "constructor") *> fnName
127 endPlicity :: Maybe Char -> IdrisParser Plicity
128 endPlicity (Just _) = do lchar '}'
130 endPlicity Nothing = return expl
132 annotate :: SyntaxInfo -> IState -> Docstring () -> Docstring (Either Err PTerm)
133 annotate syn ist = annotCode $ tryFullExpr syn ist
135recordParameter :: SyntaxInfo -> IdrisParser (Name, FC, Plicity, PTerm)
138 (n, nfc, pt) <- (namedTy syn <|> onlyName syn)
140 return (n, nfc, expl, pt))
142 (do (n, nfc, pt) <- onlyName syn
143 return (n, nfc, expl, pt))
145 namedTy :: SyntaxInfo -> IdrisParser (Name, FC, PTerm)
147 do (n, nfc) <- fnName
149 ty <- typeExpr (allowImp syn)
150 return (expandNS syn n, nfc, ty)
151 onlyName :: SyntaxInfo -> IdrisParser (Name, FC, PTerm)
153 do (n, nfc) <- fnName
155 return (expandNS syn n, nfc, PType fc)
157{- | Parses data declaration type (normal or codata)
158DataI ::= 'data' | 'codata';
160dataI :: IdrisParser DataOpts
161dataI = do reservedHL "data"; return []
162 <|> do reservedHL "codata"; return [Codata]
164recordI :: IdrisParser DataOpts
165recordI = do reservedHL "record"; return []
166 <|> do reservedHL "corecord"; return [Codata]
168{- | Parses if a data should not have a default eliminator
169DefaultEliminator ::= 'noelim'?
171dataOpts :: DataOpts -> IdrisParser DataOpts
173 = do fc <- reservedFC "%elim"
175 dataOpts (DefaultEliminator : DefaultCaseFun : opts)
176 <|> do fc <- reservedFC "%case"
178 dataOpts (DefaultCaseFun : opts)
179 <|> do reserved "%error_reverse"; dataOpts (DataErrRev : opts)
183 parserWarning fc (Just NoElimDeprecationWarnings) (Msg "The 'class' keyword is deprecated. Use 'interface' instead.")
185{- | Parses a data type declaration
186Data ::= DocComment? Accessibility? DataI DefaultEliminator FnName TypeSig ExplicitTypeDataRest?
187 | DocComment? Accessibility? DataI DefaultEliminator FnName Name* DataRest?
189Constructor' ::= Constructor KeepTerminator;
190ExplicitTypeDataRest ::= 'where' OpenBlock Constructor'* CloseBlock;
192DataRest ::= '=' SimpleConstructorList Terminator
195SimpleConstructorList ::=
197 | SimpleConstructor '|' SimpleConstructorList
200data_ :: SyntaxInfo -> IdrisParser PDecl
201data_ syn = do (doc, argDocs, acc, dataOpts) <- try (do
202 (doc, argDocs) <- option noDocs docComment
208 let dataOpts = combineDataOpts (elim ++ co)
209 doc' = annotCode (tryFullExpr syn ist) doc
210 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
211 | (n, d) <- argDocs ]
212 return (doc', argDocs', acc, dataOpts))
214 (tyn_in, nfc) <- fnName
216 ty <- typeExpr (allowImp syn)
217 let tyn = expandNS syn tyn_in
218 d <- option (PData doc argDocs syn fc dataOpts (PLaterdecl tyn nfc ty)) (do
220 cons <- indentedBlock (constructor syn)
221 accData acc tyn (map (\ (_, _, n, _, _, _, _) -> n) cons)
222 return $ PData doc argDocs syn fc dataOpts (PDatadecl tyn nfc ty cons))
225 args <- many (do notEndApp
228 let ty = bindArgs (map (const (PType fc)) args) (PType fc)
229 let tyn = expandNS syn tyn_in
230 d <- option (PData doc argDocs syn fc dataOpts (PLaterdecl tyn nfc ty)) (do
231 try (lchar '=') <|> do reservedHL "where"
232 let kw = (if DefaultEliminator `elem` dataOpts then "%elim" else "") ++ (if Codata `elem` dataOpts then "co" else "") ++ "data "
233 let n = show tyn_in ++ " "
235 let as = unwords (map show args) ++ " "
236 let ns = concat (intersperse " -> " $ map ((\x -> "(" ++ x ++ " : Type)") . show) args)
237 let ss = concat (intersperse " -> " $ map (const "Type") args)
238 let fix1 = s ++ as ++ " = ..."
239 let fix2 = s ++ ": " ++ ns ++ " -> Type where\n ..."
240 let fix3 = s ++ ": " ++ ss ++ " -> Type where\n ..."
241 fail $ fixErrorMsg "unexpected \"where\"" [fix1, fix2, fix3]
242 cons <- sepBy1 (simpleConstructor (syn { withAppAllowed = False })) (reservedOp "|")
243 let conty = mkPApp fc (PRef fc [] tyn) (map (PRef fc []) args)
244 cons' <- mapM (\ (doc, argDocs, x, xfc, cargs, cfc, fs) ->
245 do let cty = bindArgs cargs conty
246 return (doc, argDocs, x, xfc, cty, cfc, fs)) cons
247 accData acc tyn (map (\ (_, _, n, _, _, _, _) -> n) cons')
248 return $ PData doc argDocs syn fc dataOpts (PDatadecl tyn nfc ty cons'))
251 <?> "data type declaration"
253 mkPApp :: FC -> PTerm -> [PTerm] -> PTerm
255 mkPApp fc t xs = PApp fc t (map pexp xs)
256 bindArgs :: [PTerm] -> PTerm -> PTerm
257 bindArgs xs t = foldr (PPi expl (sMN 0 "_t") NoFC) t xs
258 combineDataOpts :: DataOpts -> DataOpts
259 combineDataOpts opts = if Codata `elem` opts
260 then delete DefaultEliminator opts
264{- | Parses a type constructor declaration
265 Constructor ::= DocComment? FnName TypeSig;
267constructor :: SyntaxInfo -> IdrisParser (Docstring (Either Err PTerm), [(Name, Docstring (Either Err PTerm))], Name, FC, PTerm, FC, [Name])
269 = do (doc, argDocs) <- option noDocs docComment
270 (cn_in, nfc) <- fnName; fc <- getFC
271 let cn = expandNS syn cn_in
273 fs <- option [] (do lchar '%'; reserved "erase"
274 sepBy1 (fst <$> name) (lchar ','))
275 ty <- typeExpr (allowImp syn)
277 let doc' = annotCode (tryFullExpr syn ist) doc
278 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
279 | (n, d) <- argDocs ]
280 return (doc', argDocs', cn, nfc, ty, fc, fs)
283{- | Parses a constructor for simple discriminated union data types
284 SimpleConstructor ::= FnName SimpleExpr* DocComment?
286simpleConstructor :: SyntaxInfo -> IdrisParser (Docstring (Either Err PTerm), [(Name, Docstring (Either Err PTerm))], Name, FC, [PTerm], FC, [Name])
288 = do (doc, _) <- option noDocs (try docComment)
290 let doc' = annotCode (tryFullExpr syn ist) doc
291 (cn_in, nfc) <- fnName
292 let cn = expandNS syn cn_in
294 args <- many (do notEndApp
296 return (doc', [], cn, nfc, args, fc, [])
299{- | Parses a dsl block declaration
300DSL ::= 'dsl' FnName OpenBlock Overload'+ CloseBlock;
302dsl :: SyntaxInfo -> IdrisParser PDecl
303dsl syn = do reservedHL "dsl"
305 bs <- indentedBlock (overload syn)
306 let dsl = mkDSL bs (dsl_info syn)
309 put (i { idris_dsls = addDef n dsl (idris_dsls i) })
311 <?> "dsl block declaration"
312 where mkDSL :: [(String, PTerm)] -> DSL -> DSL
313 mkDSL bs dsl = let var = lookup "variable" bs
314 first = lookup "index_first" bs
315 next = lookup "index_next" bs
316 leto = lookup "let" bs
317 lambda = lookup "lambda" bs
318 pi = lookup "pi" bs in
319 initDSL { dsl_var = var,
326{- | Checks DSL for errors -}
327-- FIXME: currently does nothing, check if DSL is really sane
329-- Issue #1595 on the Issue Tracker
331-- https://github.com/idris-lang/Idris-dev/issues/1595
333checkDSL :: DSL -> IdrisParser ()
334checkDSL dsl = return ()
336{- | Parses a DSL overload declaration
337OverloadIdentifier ::= 'let' | Identifier;
338Overload ::= OverloadIdentifier '=' Expr;
340overload :: SyntaxInfo -> IdrisParser (String, PTerm)
341overload syn = do (o, fc) <- identifier <|> do fc <- reservedFC "let"
343 if o `notElem` overloadable
344 then fail $ show o ++ " is not an overloading"
346 highlightP fc AnnKeyword
350 <?> "dsl overload declaratioN"
351 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