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 t <- typeExpr (allowImp syn)
112 let doc' = case doc of -- Temp: Throws away any possible arg docs
113 Just (d,_) -> Just $ annotate syn ist d
115 return $ map (\n -> (n, p, t, doc')) ns
117 constructor :: IdrisParser (Name, FC)
118 constructor = (reservedHL "constructor") *> fnName
121 endPlicity :: Maybe Char -> IdrisParser Plicity
122 endPlicity (Just _) = do lchar '}'
124 endPlicity Nothing = return expl
126 annotate :: SyntaxInfo -> IState -> Docstring () -> Docstring (Either Err PTerm)
127 annotate syn ist = annotCode $ tryFullExpr syn ist
129recordParameter :: SyntaxInfo -> IdrisParser (Name, FC, Plicity, PTerm)
132 (n, nfc, pt) <- (namedTy syn <|> onlyName syn)
134 return (n, nfc, expl, pt))
136 (do (n, nfc, pt) <- onlyName syn
137 return (n, nfc, expl, pt))
139 namedTy :: SyntaxInfo -> IdrisParser (Name, FC, PTerm)
141 do (n, nfc) <- fnName
143 ty <- typeExpr (allowImp syn)
144 return (expandNS syn n, nfc, ty)
145 onlyName :: SyntaxInfo -> IdrisParser (Name, FC, PTerm)
147 do (n, nfc) <- fnName
149 return (expandNS syn n, nfc, PType fc)
151{- | Parses data declaration type (normal or codata)
152DataI ::= 'data' | 'codata';
154dataI :: IdrisParser DataOpts
155dataI = do reservedHL "data"; return []
156 <|> do reservedHL "codata"; return [Codata]
158recordI :: IdrisParser DataOpts
159recordI = do reservedHL "record"; return []
160 <|> do reservedHL "corecord"; return [Codata]
162{- | Parses if a data should not have a default eliminator
163DefaultEliminator ::= 'noelim'?
165dataOpts :: DataOpts -> IdrisParser DataOpts
167 = do fc <- reservedFC "%elim"
169 dataOpts (DefaultEliminator : DefaultCaseFun : opts)
170 <|> do fc <- reservedFC "%case"
172 dataOpts (DefaultCaseFun : opts)
173 <|> do reserved "%error_reverse"; dataOpts (DataErrRev : opts)
177 parserWarning fc (Just NoElimDeprecationWarnings) (Msg "The 'class' keyword is deprecated. Use 'interface' instead.")
179{- | Parses a data type declaration
180Data ::= DocComment? Accessibility? DataI DefaultEliminator FnName TypeSig ExplicitTypeDataRest?
181 | DocComment? Accessibility? DataI DefaultEliminator FnName Name* DataRest?
183Constructor' ::= Constructor KeepTerminator;
184ExplicitTypeDataRest ::= 'where' OpenBlock Constructor'* CloseBlock;
186DataRest ::= '=' SimpleConstructorList Terminator
189SimpleConstructorList ::=
191 | SimpleConstructor '|' SimpleConstructorList
194data_ :: SyntaxInfo -> IdrisParser PDecl
195data_ syn = checkDeclFixity $
196 do (doc, argDocs, acc, dataOpts) <- try (do
197 (doc, argDocs) <- option noDocs docComment
203 let dataOpts = combineDataOpts (elim ++ co)
204 doc' = annotCode (tryFullExpr syn ist) doc
205 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
206 | (n, d) <- argDocs ]
207 return (doc', argDocs', acc, dataOpts))
209 (tyn_in, nfc) <- fnName
211 ty <- typeExpr (allowImp syn)
212 let tyn = expandNS syn tyn_in
213 d <- option (PData doc argDocs syn fc dataOpts (PLaterdecl tyn nfc ty)) (do
215 cons <- indentedBlock (constructor syn)
216 accData acc tyn (map (\ (_, _, n, _, _, _, _) -> n) cons)
217 return $ PData doc argDocs syn fc dataOpts (PDatadecl tyn nfc ty cons))
220 args <- many (do notEndApp
223 let ty = bindArgs (map (const (PType fc)) args) (PType fc)
224 let tyn = expandNS syn tyn_in
225 d <- option (PData doc argDocs syn fc dataOpts (PLaterdecl tyn nfc ty)) (do
226 try (lchar '=') <|> do reservedHL "where"
227 let kw = (if DefaultEliminator `elem` dataOpts then "%elim" else "") ++ (if Codata `elem` dataOpts then "co" else "") ++ "data "
228 let n = show tyn_in ++ " "
230 let as = unwords (map show args) ++ " "
231 let ns = concat (intersperse " -> " $ map ((\x -> "(" ++ x ++ " : Type)") . show) args)
232 let ss = concat (intersperse " -> " $ map (const "Type") args)
233 let fix1 = s ++ as ++ " = ..."
234 let fix2 = s ++ ": " ++ ns ++ " -> Type where\n ..."
235 let fix3 = s ++ ": " ++ ss ++ " -> Type where\n ..."
236 fail $ fixErrorMsg "unexpected \"where\"" [fix1, fix2, fix3]
237 cons <- sepBy1 (simpleConstructor (syn { withAppAllowed = False })) (reservedOp "|")
238 let conty = mkPApp fc (PRef fc [] tyn) (map (PRef fc []) args)
239 cons' <- mapM (\ (doc, argDocs, x, xfc, cargs, cfc, fs) ->
240 do let cty = bindArgs cargs conty
241 return (doc, argDocs, x, xfc, cty, cfc, fs)) cons
242 accData acc tyn (map (\ (_, _, n, _, _, _, _) -> n) cons')
243 return $ PData doc argDocs syn fc dataOpts (PDatadecl tyn nfc ty cons'))
246 <?> "data type declaration"
248 mkPApp :: FC -> PTerm -> [PTerm] -> PTerm
250 mkPApp fc t xs = PApp fc t (map pexp xs)
251 bindArgs :: [PTerm] -> PTerm -> PTerm
252 bindArgs xs t = foldr (PPi expl (sMN 0 "_t") NoFC) t xs
253 combineDataOpts :: DataOpts -> DataOpts
254 combineDataOpts opts = if Codata `elem` opts
255 then delete DefaultEliminator opts
259{- | Parses a type constructor declaration
260 Constructor ::= DocComment? FnName TypeSig;
262constructor :: SyntaxInfo -> IdrisParser (Docstring (Either Err PTerm), [(Name, Docstring (Either Err PTerm))], Name, FC, PTerm, FC, [Name])
264 = do (doc, argDocs) <- option noDocs docComment
265 (cn_in, nfc) <- fnName; fc <- getFC
266 let cn = expandNS syn cn_in
268 fs <- option [] (do lchar '%'; reserved "erase"
269 sepBy1 (fst <$> name) (lchar ','))
270 ty <- typeExpr (allowImp syn)
272 let doc' = annotCode (tryFullExpr syn ist) doc
273 argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
274 | (n, d) <- argDocs ]
276 return (doc', argDocs', cn, nfc, ty, fc, fs)
279{- | Parses a constructor for simple discriminated union data types
280 SimpleConstructor ::= FnName SimpleExpr* DocComment?
282simpleConstructor :: SyntaxInfo -> IdrisParser (Docstring (Either Err PTerm), [(Name, Docstring (Either Err PTerm))], Name, FC, [PTerm], FC, [Name])
284 = do (doc, _) <- option noDocs (try docComment)
286 let doc' = annotCode (tryFullExpr syn ist) doc
287 (cn_in, nfc) <- fnName
288 let cn = expandNS syn cn_in
290 args <- many (do notEndApp
293 return (doc', [], cn, nfc, args, fc, [])
296{- | Parses a dsl block declaration
297DSL ::= 'dsl' FnName OpenBlock Overload'+ CloseBlock;
299dsl :: SyntaxInfo -> IdrisParser PDecl
300dsl syn = do reservedHL "dsl"
302 bs <- indentedBlock (overload syn)
303 let dsl = mkDSL bs (dsl_info syn)
306 put (i { idris_dsls = addDef n dsl (idris_dsls i) })
308 <?> "dsl block declaration"
309 where mkDSL :: [(String, PTerm)] -> DSL -> DSL
310 mkDSL bs dsl = let var = lookup "variable" bs
311 first = lookup "index_first" bs
312 next = lookup "index_next" bs
313 leto = lookup "let" bs
314 lambda = lookup "lambda" bs
315 pi = lookup "pi" bs in
316 initDSL { dsl_var = var,
323{- | Checks DSL for errors -}
324-- FIXME: currently does nothing, check if DSL is really sane
326-- Issue #1595 on the Issue Tracker
328-- https://github.com/idris-lang/Idris-dev/issues/1595
330checkDSL :: DSL -> IdrisParser ()
331checkDSL dsl = return ()
333{- | Parses a DSL overload declaration
334OverloadIdentifier ::= 'let' | Identifier;
335Overload ::= OverloadIdentifier '=' Expr;
337overload :: SyntaxInfo -> IdrisParser (String, PTerm)
338overload syn = do (o, fc) <- identifier <|> do fc <- reservedFC "let"
340 if o `notElem` overloadable
341 then fail $ show o ++ " is not an overloading"
343 highlightP fc AnnKeyword
347 <?> "dsl overload declaratioN"
348 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