@@ -37,6 +37,9 @@ import qualified Data.ByteString.UTF8 as UTF8
38import Debug.Trace
38import Debug.Trace
40+type Docs = Docstring (Either Err PTerm)
41+type RecordConstructor = (Docs, [(Name, Docs)], Maybe Name, PTerm, [(Name, Plicity)])
40{- |Parses a record type declaration
43{- |Parses a record type declaration
42 DocComment Accessibility? 'record' FnName TypeSig 'where' OpenBlock Constructor KeepTerminator CloseBlock;
45 DocComment Accessibility? 'record' FnName TypeSig 'where' OpenBlock Constructor KeepTerminator CloseBlock;
@@ -50,23 +53,29 @@ record syn = do (doc, argDocs, acc, opts) <- try (do
50 | (n, d) <- argDocs ]
53 | (n, d) <- argDocs ]
51 acc <- optional accessibility
54 acc <- optional accessibility
52 opts <- dataOpts []
55 opts <- dataOpts []
53− reserved "record"
56+ co <- recordI
54− return (doc', argDocs', acc, opts))
57+ return (doc', argDocs', acc, opts ++ co))
55 fc <- getFC
58 fc <- getFC
56− tyn_in <- fnName
59+ tyn_in <- fnName
57− lchar ':'
60+ tys <- manyTill (recordTypeParameter syn) (reserved "where")
58− ty <- typeExpr (allowImp syn)
61+ let ty = recordTypeConstructor tys
62+ let ty' = withoutNames ty
59 let tyn = expandNS syn tyn_in
63 let tyn = expandNS syn tyn_in
61− (cdoc, cargDocs, cn, cty, _, _) <- indentedBlockS (constructor syn)
64+ (cdoc, cargDocs, cn, cty, args) <- indentedBlockS $ agdaStyleBody syn tyn ty
62− accData acc tyn [cn]
66+ Just cn' -> accData acc tyn [cn']
63 let rsyn = syn { syn_namespace = show (nsroot tyn) :
68 let rsyn = syn { syn_namespace = show (nsroot tyn) :
64 syn_namespace syn }
69 syn_namespace syn }
65 let fns = getRecNames rsyn cty
70 let fns = getRecNames rsyn cty
66 mapM_ (\n -> addAcc n acc) fns
71 mapM_ (\n -> addAcc n acc) fns
67− return $ PRecord doc rsyn fc tyn ty opts cdoc cn cty
72+ return $ PRecord doc rsyn fc tyn ty' opts cdoc cn args cty
68 <?> "record type declaration"
73 <?> "record type declaration"
75+ withoutNames :: PTerm -> PTerm
76+ withoutNames (PPi p _ t sc) = PPi p (sUN "__pi_arg") t (withoutNames sc)
70 getRecNames :: SyntaxInfo -> PTerm -> [Name]
79 getRecNames :: SyntaxInfo -> PTerm -> [Name]
71 getRecNames syn (PPi _ n _ sc) = [expandNS syn n, expandNS syn (mkType n)]
80 getRecNames syn (PPi _ n _ sc) = [expandNS syn n, expandNS syn (mkType n)]
72 ++ getRecNames syn sc
81 ++ getRecNames syn sc
@@ -76,6 +85,109 @@ record syn = do (doc, argDocs, acc, opts) <- try (do
76 toFreeze (Just Frozen) = Just Hidden
85 toFreeze (Just Frozen) = Just Hidden
77 toFreeze x = x
86 toFreeze x = x
88+ recordTypeConstructor :: [(Name, Plicity, PTerm)] -> PTerm
89+ recordTypeConstructor ((n, p, t) : rest) = PPi p n t (recordTypeConstructor rest)
90+ recordTypeConstructor [] = PType
92+ -- Greatly inspired by ziman (https://github.com/ziman)
93+ agdaStyleBody :: SyntaxInfo -> Name -> PTerm -> IdrisParser RecordConstructor
94+ agdaStyleBody syn tyn tyc = do
98+ fields <- many . indented $ field
100+ let constructorDoc = parseDocstring . T.pack $ "Constructor of " ++ show tyn
101+ (constructorName, args) <- do c <- optional constructor
102+ let (n, args) = maybePair c
103+ return (n, mList args)
105+ let constructorDoc' = annotate syn ist constructorDoc
106+ let fieldDocs = [(n, annotate syn ist doc) | (n, _, _, doc, _) <- fields]
107+ target = PApp fc (PRef fc tyn) (getParams fc tyc)
108+ constructorType = mkConstructorType [(n, t, p) | (n, t, p, _, _) <- fields] target
109+ constructorType' = replaceTarget constructorType (allImpl tyc)
111+ return (constructorDoc', fieldDocs, constructorName, constructorType', args)
113+ maybePair :: Maybe (a, b) -> (Maybe a, Maybe b)
114+ maybePair (Just(x, y)) = (Just x, Just y)
115+ maybePair Nothing = (Nothing, Nothing)
117+ mList :: Maybe [a] -> [a]
118+ mList (Just xs) = xs
121+ fieldsAndConstructor :: IdrisParser ([(Name, PTerm, Plicity, Docstring (), [(Name, Docstring ())])], (Maybe Name), [(Name, Plicity)])
122+ fieldsAndConstructor = do fields <- (indented field) `manyTill` (reserved "constructor")
123+ (cName, args) <- indented constructor
124+ return (fields, Just cName, args)
126+ allImpl :: PTerm -> PTerm
127+ allImpl (PPi _ n t t') = PPi impl n t (allImpl t')
130+ field :: IdrisParser (Name, PTerm, Plicity, Docstring (), [(Name, Docstring ())])
131+ field = do (doc, argDocs) <- option noDocs docComment
134+ t <- typeExpr (allowImp syn)
135+ return (n, t, expl, doc, argDocs)
137+ constructor :: IdrisParser (Name, [(Name, Plicity)])
138+ constructor = do n <- (reserved "constructor") *> fnName
139+ args <- option [] (do lchar '('
140+ args <- many (do p <- optional $ lchar '{'
142+ plicity <- endPlicity p
143+ return (argName, plicity))
148+ endPlicity :: Maybe Char -> IdrisParser Plicity
149+ endPlicity (Just _) = do lchar '}'
151+ endPlicity Nothing = return expl
153+ mkConstructorType :: [(Name, PTerm, Plicity)] -> PTerm -> PTerm
154+ mkConstructorType ((n, t, p) : rest) t' = PPi p (nsroot n) t (mkConstructorType rest t')
155+ mkConstructorType [] t = t
157+ getParams :: FC -> PTerm -> [PArg]
158+ getParams fc (PPi (Exp os _ _) n t ts) = (PExp 0 os n $ PRef fc n) : getParams fc ts
159+ getParams fc (PPi (Imp os _ _ _) n t ts) = (PImp 0 False os n $ PRef fc n) : getParams fc ts
162+ annotate :: SyntaxInfo -> IState -> Docstring () -> Docstring (Either Err PTerm)
163+ annotate syn ist = annotCode $ tryFullExpr syn ist
165+ replaceTarget :: PTerm -> PTerm -> PTerm
166+ replaceTarget trg (PPi p n t ts) = PPi p n t (replaceTarget trg ts)
167+ replaceTarget trg _ = trg
169+recordTypeParameter :: SyntaxInfo -> IdrisParser (Name, Plicity, PTerm)
170+recordTypeParameter syn =
172+ (n, pt) <- (namedTy syn <|> onlyName syn)
174+ return (n, expl, pt))
176+ (do (n, pt) <- onlyName syn
177+ return (n, expl, pt))
180+ namedTy :: SyntaxInfo -> IdrisParser (Name, PTerm)
184+ ty <- typeExpr (allowImp syn)
186+ onlyName :: SyntaxInfo -> IdrisParser (Name, PTerm)
79{- | Parses data declaration type (normal or codata)
191{- | Parses data declaration type (normal or codata)
80DataI ::= 'data' | 'codata';
192DataI ::= 'data' | 'codata';
@@ -83,6 +195,10 @@ dataI :: IdrisParser DataOpts
83dataI = do reserved "data"; return []
195dataI = do reserved "data"; return []
84 <|> do reserved "codata"; return [Codata]
196 <|> do reserved "codata"; return [Codata]
198+recordI :: IdrisParser DataOpts
199+recordI = do reserved "record"; return []
200+ <|> do reserved "corecord"; return [Codata]
86{- | Parses if a data should not have a default eliminator
202{- | Parses if a data should not have a default eliminator
87DefaultEliminator ::= 'noelim'?
203DefaultEliminator ::= 'noelim'?