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
16import Idris.Parser.Expr
17import Idris.Parser.Helpers
18import Idris.Parser.Ops
20import Prelude hiding (pi)
22import Control.Applicative
24import Control.Monad.State.Strict
25import qualified Data.ByteString.UTF8 as UTF8
27import qualified Data.HashSet as HS
29import qualified Data.List.Split as Spl
32import qualified Data.Text as T
34import qualified Text.Parser.Char as Chr
35import Text.Parser.Expression
36import Text.Parser.LookAhead
37import qualified Text.Parser.Token as Tok
38import qualified Text.Parser.Token.Highlight as Hi
39import Text.Trifecta hiding (Err, char, charLiteral, natural, span, string,
40 stringLiteral, symbol, whiteSpace)
41import Text.Trifecta.Delta
43{- | Parses a record type declaration
45 DocComment Accessibility? 'record' FnName TypeSig 'where' OpenBlock Constructor KeepTerminator CloseBlock;
47record :: SyntaxInfo -> IdrisParser PDecl
48record syn = do (doc, paramDocs, acc, opts) <- try (do
49 (doc, paramDocs) <- option noDocs docComment
51 let doc' = annotCode (tryFullExpr syn ist) doc
52 paramDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
53 | (n, d) <- paramDocs ]
57 return (doc', paramDocs', acc, opts ++ co))
59 (tyn_in, nfc) <- fnName
60 let tyn = expandNS syn tyn_in
61 let rsyn = syn { syn_namespace = show (nsroot tyn) :
63 params <- manyTill (recordParameter rsyn) (reservedHL "where")
64 (fields, cname, cdoc) <- indentedBlockS $ recordBody rsyn tyn
65 let fnames = map (expandNS rsyn) (mapMaybe getName fields)
67 Just cn' -> accData acc tyn (fst cn' : fnames)
69 return $ PRecord doc rsyn fc opts tyn nfc params paramDocs fields cname cdoc syn
70 <?> "record type declaration"
72 getRecNames :: SyntaxInfo -> PTerm -> [Name]
73 getRecNames syn (PPi _ n _ _ sc) = [expandNS syn n, expandNS syn (mkType n)]
77 getName (Just (n, _), _, _, _) = Just n
80 toFreeze :: Maybe Accessibility -> Maybe Accessibility
81 toFreeze (Just Frozen) = Just Private
84 recordBody :: SyntaxInfo -> Name -> IdrisParser ([((Maybe (Name, FC)), Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))], Maybe (Name, FC), Docstring (Either Err PTerm))
85 recordBody syn tyn = do
89 (constructorName, constructorDoc) <- option (Nothing, emptyDocstring)
90 (do (doc, _) <- option noDocs docComment
94 let constructorDoc' = annotate syn ist constructorDoc
96 fields <- many . indented $ fieldLine syn
98 return (concat fields, constructorName, constructorDoc')
100 fieldLine :: SyntaxInfo -> IdrisParser [(Maybe (Name, FC), Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))]
102 doc <- optional docComment
103 c <- optional $ lchar '{'
104 let oneName = (do (n, nfc) <- fnName
105 return $ Just (expandNS syn n, nfc))
106 <|> (symbol "_" >> return Nothing)
107 ns <- commaSeparated oneName
109 -- Implicits are scoped in fields (fields aren't top level)
110 t <- typeExpr (scopedImp syn)
113 let doc' = case doc of -- Temp: Throws away any possible arg docs
114 Just (d,_) -> Just $ annotate syn ist d
116 return $ map (\n -> (n, p, t, doc')) ns
118 constructor :: IdrisParser (Name, FC)
119 constructor = (reservedHL "constructor") *> fnName
122 endPlicity :: Maybe Char -> IdrisParser Plicity
123 endPlicity (Just _) = do lchar '}'
125 endPlicity Nothing = return expl
127 annotate :: SyntaxInfo -> IState -> Docstring () -> Docstring (Either Err PTerm)
128 annotate syn ist = annotCode $ tryFullExpr syn ist
130recordParameter :: SyntaxInfo -> IdrisParser (Name, FC, Plicity, PTerm)
133 (n, nfc, pt) <- (namedTy syn <|> onlyName syn)
135 return (n, nfc, expl, pt))
137 (do (n, nfc, pt) <- onlyName syn
138 return (n, nfc, expl, pt))
140 namedTy :: SyntaxInfo -> IdrisParser (Name, FC, PTerm)
142 do (n, nfc) <- fnName
144 ty <- typeExpr (allowImp syn)
145 return (expandNS syn n, nfc, ty)
146 onlyName :: SyntaxInfo -> IdrisParser (Name, FC, PTerm)
148 do (n, nfc) <- fnName
150 return (expandNS syn n, nfc, PType fc)
152{- | Parses data declaration type (normal or codata)
153DataI ::= 'data' | 'codata';
155dataI :: IdrisParser DataOpts
156dataI = do reservedHL "data"; return []
157 <|> do reservedHL "codata"; return [Codata]
159recordI :: IdrisParser DataOpts
160recordI = do reservedHL "record"; return []
161 <|> do reservedHL "corecord"; return [Codata]
163{- | Parses if a data should not have a default eliminator
164DefaultEliminator ::= 'noelim'?
166dataOpts :: DataOpts -> IdrisParser DataOpts
168 = do fc <- reservedFC "%elim"
170 dataOpts (DefaultEliminator : DefaultCaseFun : opts)
171 <|> do fc <- reservedFC "%case"
173 dataOpts (DefaultCaseFun : opts)
174 <|> do reserved "%error_reverse"; dataOpts (DataErrRev : opts)
178 parserWarning fc (Just NoElimDeprecationWarnings) (Msg "The 'class' keyword is deprecated. Use 'interface' instead.")
180{- | Parses a data type declaration
181Data ::= DocComment? Accessibility? DataI DefaultEliminator FnName TypeSig ExplicitTypeDataRest?
182 | DocComment? Accessibility? DataI DefaultEliminator FnName Name* DataRest?
184Constructor' ::= Constructor KeepTerminator;
185ExplicitTypeDataRest ::= 'where' OpenBlock Constructor'* CloseBlock;
187DataRest ::= '=' SimpleConstructorList Terminator
190SimpleConstructorList ::=
192 | SimpleConstructor '|' SimpleConstructorList
195data_ :: SyntaxInfo -> IdrisParser PDecl
196data_ syn = checkDeclFixity $
197 do (doc, argDocs, acc, dataOpts) <- try (do
198 (doc, argDocs) <- option noDocs docComment
204 let dataOpts = combineDataOpts (elim ++ co)
205 doc' = annotCode (tryFullExpr syn ist) doc
206 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
207 | (n, d) <- argDocs ]
208 return (doc', argDocs', acc, dataOpts))
210 (tyn_in, nfc) <- fnName
212 ty <- typeExpr (allowImp syn)
213 let tyn = expandNS syn tyn_in
214 d <- option (PData doc argDocs syn fc dataOpts (PLaterdecl tyn nfc ty)) (do
216 cons <- indentedBlock (constructor syn)
217 accData acc tyn (map (\ (_, _, n, _, _, _, _) -> n) cons)
218 return $ PData doc argDocs syn fc dataOpts (PDatadecl tyn nfc ty cons))
221 args <- many (do notEndApp
224 let ty = bindArgs (map (const (PType fc)) args) (PType fc)
225 let tyn = expandNS syn tyn_in
226 d <- option (PData doc argDocs syn fc dataOpts (PLaterdecl tyn nfc ty)) (do
227 try (lchar '=') <|> do reservedHL "where"
228 let kw = (if DefaultEliminator `elem` dataOpts then "%elim" else "") ++ (if Codata `elem` dataOpts then "co" else "") ++ "data "
229 let n = show tyn_in ++ " "
231 let as = unwords (map show args) ++ " "
232 let ns = concat (intersperse " -> " $ map ((\x -> "(" ++ x ++ " : Type)") . show) args)
233 let ss = concat (intersperse " -> " $ map (const "Type") args)
234 let fix1 = s ++ as ++ " = ..."
235 let fix2 = s ++ ": " ++ ns ++ " -> Type where\n ..."
236 let fix3 = s ++ ": " ++ ss ++ " -> Type where\n ..."
237 fail $ fixErrorMsg "unexpected \"where\"" [fix1, fix2, fix3]
238 cons <- sepBy1 (simpleConstructor (syn { withAppAllowed = False })) (reservedOp "|")
239 let conty = mkPApp fc (PRef fc [] tyn) (map (PRef fc []) args)
240 cons' <- mapM (\ (doc, argDocs, x, xfc, cargs, cfc, fs) ->
241 do let cty = bindArgs cargs conty
242 return (doc, argDocs, x, xfc, cty, cfc, fs)) cons
243 accData acc tyn (map (\ (_, _, n, _, _, _, _) -> n) cons')
244 return $ PData doc argDocs syn fc dataOpts (PDatadecl tyn nfc ty cons'))
247 <?> "data type declaration"
249 mkPApp :: FC -> PTerm -> [PTerm] -> PTerm
251 mkPApp fc t xs = PApp fc t (map pexp xs)
252 bindArgs :: [PTerm] -> PTerm -> PTerm
253 bindArgs xs t = foldr (PPi expl (sMN 0 "_t") NoFC) t xs
254 combineDataOpts :: DataOpts -> DataOpts
255 combineDataOpts opts = if Codata `elem` opts
256 then delete DefaultEliminator opts
260{- | Parses a type constructor declaration
261 Constructor ::= DocComment? FnName TypeSig;
263constructor :: SyntaxInfo -> IdrisParser (Docstring (Either Err PTerm), [(Name, Docstring (Either Err PTerm))], Name, FC, PTerm, FC, [Name])
265 = do (doc, argDocs) <- option noDocs docComment
266 (cn_in, nfc) <- fnName; fc <- getFC
267 let cn = expandNS syn cn_in
269 fs <- option [] (do lchar '%'; reserved "erase"
270 sepBy1 (fst <$> name) (lchar ','))
271 ty <- typeExpr (allowImp syn)
273 let doc' = annotCode (tryFullExpr syn ist) doc
274 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
275 | (n, d) <- argDocs ]
277 return (doc', argDocs', cn, nfc, ty, fc, fs)
280{- | Parses a constructor for simple discriminated union data types
281 SimpleConstructor ::= FnName SimpleExpr* DocComment?
283simpleConstructor :: SyntaxInfo -> IdrisParser (Docstring (Either Err PTerm), [(Name, Docstring (Either Err PTerm))], Name, FC, [PTerm], FC, [Name])
285 = do (doc, _) <- option noDocs (try docComment)
287 let doc' = annotCode (tryFullExpr syn ist) doc
288 (cn_in, nfc) <- fnName
289 let cn = expandNS syn cn_in
291 args <- many (do notEndApp
294 return (doc', [], cn, nfc, args, fc, [])
297{- | Parses a dsl block declaration
298DSL ::= 'dsl' FnName OpenBlock Overload'+ CloseBlock;
300dsl :: SyntaxInfo -> IdrisParser PDecl
301dsl syn = do reservedHL "dsl"
303 bs <- indentedBlock (overload syn)
304 let dsl = mkDSL bs (dsl_info syn)
307 put (i { idris_dsls = addDef n dsl (idris_dsls i) })
309 <?> "dsl block declaration"
310 where mkDSL :: [(String, PTerm)] -> DSL -> DSL
311 mkDSL bs dsl = let var = lookup "variable" bs
312 first = lookup "index_first" bs
313 next = lookup "index_next" bs
314 leto = lookup "let" bs
315 lambda = lookup "lambda" bs
316 pi = lookup "pi" bs in
317 initDSL { dsl_var = var,
324{- | Checks DSL for errors -}
325-- FIXME: currently does nothing, check if DSL is really sane
327-- Issue #1595 on the Issue Tracker
329-- https://github.com/idris-lang/Idris-dev/issues/1595
331checkDSL :: DSL -> IdrisParser ()
332checkDSL dsl = return ()
334{- | Parses a DSL overload declaration
335OverloadIdentifier ::= 'let' | Identifier;
336Overload ::= OverloadIdentifier '=' Expr;
338overload :: SyntaxInfo -> IdrisParser (String, PTerm)
339overload syn = do (o, fc) <- identifier <|> do fc <- reservedFC "let"
341 if o `notElem` overloadable
342 then fail $ show o ++ " is not an overloading"
344 highlightP fc AnnKeyword
348 <?> "dsl overload declaratioN"
349 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