@@ -1,3 +1,4 @@
1{-# LANGUAGE UndecidableInstances #-}
2{-# LANGUAGE UndecidableInstances #-}
2{-# LANGUAGE FunctionalDependencies #-}
3{-# LANGUAGE FunctionalDependencies #-}
@@ -23,6 +24,8 @@ import Text.XML.ParentAttributes
23import qualified Text.XML.Writer as XW
24import qualified Text.XML.Writer as XW
27+data GenType = Parser | Generator | Both
26data XmlFieldPlural
29data XmlFieldPlural
27 = XmlFieldPluralMandatory -- Occurs exactly 1 time (Identity)
30 = XmlFieldPluralMandatory -- Occurs exactly 1 time (Identity)
28 | XmlFieldPluralOptional -- Occurs 0 or 1 times (Maybe)
31 | XmlFieldPluralOptional -- Occurs 0 or 1 times (Maybe)
@@ -52,7 +55,7 @@ data IsoXmlDescRecordPart
52 | IsoXmlDescRecordAttribute IsoXmlDescAttribute
55 | IsoXmlDescRecordAttribute IsoXmlDescAttribute
53 | IsoXmlDescRecordContent IsoXmlDescContent
56 | IsoXmlDescRecordContent IsoXmlDescContent
55−newtype IsoXmlDescRecord = IsoXmlDescRecord [IsoXmlDescRecordPart]
58+data IsoXmlDescRecord = IsoXmlDescRecord GenType [IsoXmlDescRecordPart]
57makePrisms ''IsoXmlDescRecord
60makePrisms ''IsoXmlDescRecord
@@ -64,7 +67,7 @@ newtype IsoXmlDescEnumCon
64instance IsString IsoXmlDescEnumCon where
67instance IsString IsoXmlDescEnumCon where
65 fromString = IsoXmlDescEnumCon
68 fromString = IsoXmlDescEnumCon
67−data IsoXmlDescEnum = IsoXmlDescEnum [IsoXmlDescEnumCon]
70+data IsoXmlDescEnum = IsoXmlDescEnum GenType [IsoXmlDescEnumCon]
69makePrisms ''IsoXmlDescEnum
72makePrisms ''IsoXmlDescEnum
@@ -73,26 +76,26 @@ appendField
73 -> IsoXmlDescRecord
76 -> IsoXmlDescRecord
74 -> IsoXmlDescPreField
77 -> IsoXmlDescPreField
75 -> IsoXmlDescRecord
78 -> IsoXmlDescRecord
76−appendField plural xrec (IsoXmlDescPreField name ty) =
79+appendField plural (IsoXmlDescRecord genType fields) (IsoXmlDescPreField name ty) =
77 let xfield = IsoXmlDescRecordField $ IsoXmlDescField plural name ty
80 let xfield = IsoXmlDescRecordField $ IsoXmlDescField plural name ty
78− in over _IsoXmlDescRecord (xfield:) xrec
81+ in IsoXmlDescRecord genType (xfield:fields)
80appendAttribute
83appendAttribute
81 :: XmlAttributePlural
84 :: XmlAttributePlural
82 -> IsoXmlDescRecord
85 -> IsoXmlDescRecord
83 -> IsoXmlDescPreAttribute
86 -> IsoXmlDescPreAttribute
84 -> IsoXmlDescRecord
87 -> IsoXmlDescRecord
85−appendAttribute plural xrec (IsoXmlDescPreAttribute name ty) =
88+appendAttribute plural (IsoXmlDescRecord genType fields) (IsoXmlDescPreAttribute name ty) =
86 let xattribute = IsoXmlDescRecordAttribute $ IsoXmlDescAttribute plural name ty
89 let xattribute = IsoXmlDescRecordAttribute $ IsoXmlDescAttribute plural name ty
87− in over _IsoXmlDescRecord (xattribute:) xrec
90+ in IsoXmlDescRecord genType (xattribute:fields)
89appendContent
92appendContent
90 :: IsoXmlDescRecord
93 :: IsoXmlDescRecord
91 -> IsoXmlDescPreContent
94 -> IsoXmlDescPreContent
92 -> IsoXmlDescRecord
95 -> IsoXmlDescRecord
93−appendContent xrec (IsoXmlDescPreContent name ty) =
96+appendContent (IsoXmlDescRecord genType fields) (IsoXmlDescPreContent name ty) =
94 let xcontent = IsoXmlDescRecordContent $ IsoXmlDescContent name ty
97 let xcontent = IsoXmlDescRecordContent $ IsoXmlDescContent name ty
95− in over _IsoXmlDescRecord (xcontent:) xrec
98+ in IsoXmlDescRecord genType (xcontent:fields)
97(!), (?), (*), (+) :: IsoXmlDescRecord -> IsoXmlDescPreField -> IsoXmlDescRecord
100(!), (?), (*), (+) :: IsoXmlDescRecord -> IsoXmlDescPreField -> IsoXmlDescRecord
98(!) = appendField XmlFieldPluralMandatory
101(!) = appendField XmlFieldPluralMandatory
@@ -116,8 +119,8 @@ infixl 2 ?%
116infixl 2 ^
119infixl 2 ^
118appendEnumCon :: IsoXmlDescEnum -> IsoXmlDescEnumCon -> IsoXmlDescEnum
121appendEnumCon :: IsoXmlDescEnum -> IsoXmlDescEnumCon -> IsoXmlDescEnum
119−appendEnumCon xenum xenumcon =
122+appendEnumCon (IsoXmlDescEnum genType enumCons) xenumcon =
120− over _IsoXmlDescEnum (xenumcon:) xenum
123+ IsoXmlDescEnum genType (xenumcon:enumCons)
122(&) :: IsoXmlDescEnum -> IsoXmlDescEnumCon -> IsoXmlDescEnum
125(&) :: IsoXmlDescEnum -> IsoXmlDescEnumCon -> IsoXmlDescEnum
123(&) = appendEnumCon
126(&) = appendEnumCon
@@ -130,20 +133,18 @@ class Description name desc | desc -> name where
130infix 0 =:=
133infix 0 =:=
132instance Description PrefixName IsoXmlDescRecord where
135instance Description PrefixName IsoXmlDescRecord where
133− prefixName =:= descRecord =
136+ prefixName =:= (IsoXmlDescRecord genType descRecordParts) =
134− let descRecordParts = descRecord ^. _IsoXmlDescRecord
135− in isoXmlGenerateDatatype prefixName (reverse descRecordParts)
137+ isoXmlGenerateDatatype genType prefixName (reverse descRecordParts)
137−record :: IsoXmlDescRecord
139+record :: GenType -> IsoXmlDescRecord
138−record = IsoXmlDescRecord []
140+record gt = IsoXmlDescRecord gt []
140−enum :: IsoXmlDescEnum
142+enum :: GenType -> IsoXmlDescEnum
141−enum = IsoXmlDescEnum []
143+enum gt = IsoXmlDescEnum gt []
143instance Description ExhaustivenessName IsoXmlDescEnum where
145instance Description ExhaustivenessName IsoXmlDescEnum where
144− exhaustivenessName =:= descEnum =
146+ exhaustivenessName =:= (IsoXmlDescEnum genType descEnumCons) =
145− let descEnumCons = descEnum ^. _IsoXmlDescEnum
146− in isoXmlGenerateEnum exhaustivenessName (reverse descEnumCons)
147+ isoXmlGenerateEnum genType exhaustivenessName (reverse descEnumCons)
148instance IsString (TH.TypeQ -> IsoXmlDescPreField) where
149instance IsString (TH.TypeQ -> IsoXmlDescPreField) where
149 fromString = IsoXmlDescPreField
150 fromString = IsoXmlDescPreField
@@ -188,39 +189,57 @@ funSimple :: TH.Name -> TH.ExpQ -> TH.DecQ
188funSimple name body = TH.funD name [ TH.clause [] (TH.normalB body) [] ]
189funSimple name body = TH.funD name [ TH.clause [] (TH.normalB body) [] ]
190isoXmlGenerateEnum
191isoXmlGenerateEnum
191− :: ExhaustivenessName -> [IsoXmlDescEnumCon] -> TH.DecsQ
193+ -> ExhaustivenessName
194+ -> [IsoXmlDescEnumCon]
192−isoXmlGenerateEnum (ExhaustivenessName strName' exh) enumCons = do
196+isoXmlGenerateEnum genType (ExhaustivenessName strName' exh) enumCons = do
194 strName = "Xml" ++ strName'
198 strName = "Xml" ++ strName'
195 strVals = map unIsoXmlDescEnumCon enumCons
199 strVals = map unIsoXmlDescEnumCon enumCons
196 enumDesc = EnumDesc exh strName strVals
200 enumDesc = EnumDesc exh strName strVals
197 name = TH.mkName strName
201 name = TH.mkName strName
198 enumDecls <- enumGenerate enumDesc
202 enumDecls <- enumGenerate enumDesc
199− toXmlInst <- do
203+ let
200− TH.instanceD
205+ TH.instanceD
201− (return [])
206+ (return [])
202− [t|XW.ToXML $(TH.conT name)|]
207+ [t|XW.ToXML $(TH.conT name)|]
203− [funSimple 'XW.toXML [e|XW.toXML . T.pack . show|]]
208+ [funSimple 'XW.toXML [e|XW.toXML . T.pack . show|]]
204− toXmlAttributeInst <- do
209+ genToXmlAttributeInst = do
205− TH.instanceD
210+ TH.instanceD
206− (return [])
211+ (return [])
207− [t|ToXmlAttribute $(TH.conT name)|]
212+ [t|ToXmlAttribute $(TH.conT name)|]
208− [funSimple 'toXmlAttribute [e|T.pack . show|]]
213+ [funSimple 'toXmlAttribute [e|T.pack . show|]]
209− fromDomInst <- do
214+ genFromDomInst = do
210− TH.instanceD
215+ TH.instanceD
211− (return [])
216+ (return [])
212− [t|FromDom $(TH.conT name)|]
217+ [t|FromDom $(TH.conT name)|]
213− [funSimple 'fromDom [e|parseContent readContent|]]
218+ [funSimple 'fromDom [e|parseContent readContent|]]
214− fromAttributeInst <- do
219+ genFromAttributeInst = do
215− TH.instanceD
220+ TH.instanceD
216− (return [])
221+ (return [])
217− [t|FromAttribute $(TH.conT name)|]
222+ [t|FromAttribute $(TH.conT name)|]
218− [funSimple 'fromAttribute [e|readContent|]]
223+ [funSimple 'fromAttribute [e|readContent|]]
226+ toXmlInst <- genToXmlInst
227+ toXmlAttributeInst <- genToXmlAttributeInst
219− return $ enumDecls ++ [toXmlInst, toXmlAttributeInst,
228+ return $ enumDecls ++ [toXmlInst, toXmlAttributeInst]
230+ fromDomInst <- genFromDomInst
231+ fromAttributeInst <- genFromAttributeInst
232+ return $ enumDecls ++ [fromDomInst, fromAttributeInst]
234+ toXmlInst <- genToXmlInst
235+ toXmlAttributeInst <- genToXmlAttributeInst
236+ fromDomInst <- genFromDomInst
237+ fromAttributeInst <- genFromAttributeInst
238+ return $ enumDecls ++ [toXmlInst, toXmlAttributeInst,
220− fromDomInst, fromAttributeInst]
239+ fromDomInst, fromAttributeInst]
222−isoXmlGenerateDatatype :: PrefixName -> [IsoXmlDescRecordPart] -> TH.DecsQ
241+isoXmlGenerateDatatype :: GenType -> PrefixName -> [IsoXmlDescRecordPart] -> TH.DecsQ
223−isoXmlGenerateDatatype (PrefixName strName' strPrefix') descRecordParts = do
242+isoXmlGenerateDatatype genType (PrefixName strName' strPrefix') descRecordParts = do
225 isNewtype = length descRecordParts == 1
244 isNewtype = length descRecordParts == 1
226 strName = "Xml" ++ strName'
245 strName = "Xml" ++ strName'
@@ -274,103 +293,117 @@ isoXmlGenerateDatatype (PrefixName strName' strPrefix') descRecordParts = do
274 (return [])
293 (return [])
275 [t|NFData $(TH.conT name)|]
294 [t|NFData $(TH.conT name)|]
279− exprHeader = [e|pure $(TH.conE name)|]
280− exprRecordParts = do
281− descRecordPart <- descRecordParts
282− return $ case descRecordPart of
283− IsoXmlDescRecordField descField ->
285− IsoXmlDescField fieldPlural rawName _ = descField
286− fieldStrName = xmlLocalName rawName
287− exprFieldStrName = TH.litE (TH.stringL fieldStrName)
288− fieldParse = case fieldPlural of
289− XmlFieldPluralMandatory -> [e|inElem|]
290− _ -> [e|inElemTrav|]
292− [e|$fieldParse $exprFieldStrName fromDom|]
293− IsoXmlDescRecordAttribute descAttribute ->
295− IsoXmlDescAttribute attributePlural attributeStrName _ = descAttribute
296− exprAttributeStrName = TH.litE (TH.stringL attributeStrName)
297− attributeParse = case attributePlural of
298− XmlAttributePluralMandatory -> [e|parseAttribute|]
299− XmlAttributePluralOptional -> [e|parseAttributeMaybe|]
301− [e|$attributeParse $exprAttributeStrName fromAttribute|]
302− IsoXmlDescRecordContent _ -> [e|parseContent fromAttribute|]
303− fromDomExpr = foldl (\e fe -> [e| $e <*> $fe |]) exprHeader exprRecordParts
306− [t|FromDom $(TH.conT name)|]
307− [ funSimple 'fromDom fromDomExpr ]
310− objName <- TH.newName strPrefix
313− descRecordPart <- descRecordParts
314− case descRecordPart of
315− IsoXmlDescRecordField (IsoXmlDescField fieldPlural rawName _) -> do
317− fieldStrName = xmlLocalName rawName
318− fName = TH.mkName (fieldName fieldStrName)
319− exprFieldStrName = TH.litE (TH.stringL rawName)
320− exprForField = case fieldPlural of
321− XmlFieldPluralMandatory -> [e|id|]
323− exprFieldValue = [e|$(TH.varE fName) $(TH.varE objName)|]
326− XW.elementA $exprFieldStrName (toXmlParentAttributes a) a)|]
327− return [e|$exprForField $exprFieldRender $exprFieldValue|]
328− IsoXmlDescRecordContent (IsoXmlDescContent rawName _) -> do
330− fieldStrName = xmlLocalName rawName
331− fName = TH.mkName (fieldName fieldStrName)
332− exprFieldValue = [e|$(TH.varE fName) $(TH.varE objName)|]
333− return [e|XW.content . toXmlAttribute $ $exprFieldValue|]
336− = TH.lamE [if null exprFields then TH.wildP else TH.varP objName]
337− $ foldr (\fe e -> [e|$fe *> $e|]) [e|return ()|] exprFields
340− [t|XW.ToXML $(TH.conT name)|]
341− [funSimple 'XW.toXML toXmlExpr]
343− toXmlParentAttributesInst <- do
297+ let
300+ exprHeader = [e|pure $(TH.conE name)|]
301+ exprRecordParts = do
302+ descRecordPart <- descRecordParts
303+ return $ case descRecordPart of
304+ IsoXmlDescRecordField descField ->
306+ IsoXmlDescField fieldPlural rawName _ = descField
307+ fieldStrName = xmlLocalName rawName
308+ exprFieldStrName = TH.litE (TH.stringL fieldStrName)
309+ fieldParse = case fieldPlural of
310+ XmlFieldPluralMandatory -> [e|inElem|]
311+ _ -> [e|inElemTrav|]
313+ [e|$fieldParse $exprFieldStrName fromDom|]
314+ IsoXmlDescRecordAttribute descAttribute ->
316+ IsoXmlDescAttribute attributePlural attributeStrName _ = descAttribute
317+ exprAttributeStrName = TH.litE (TH.stringL attributeStrName)
318+ attributeParse = case attributePlural of
319+ XmlAttributePluralMandatory -> [e|parseAttribute|]
320+ XmlAttributePluralOptional -> [e|parseAttributeMaybe|]
322+ [e|$attributeParse $exprAttributeStrName fromAttribute|]
323+ IsoXmlDescRecordContent _ -> [e|parseContent fromAttribute|]
324+ fromDomExpr = foldl (\e fe -> [e| $e <*> $fe |]) exprHeader exprRecordParts
327+ [t|FromDom $(TH.conT name)|]
328+ [ funSimple 'fromDom fromDomExpr ]
344− objName <- TH.newName strPrefix
331+ objName <- TH.newName strPrefix
334+ descRecordPart <- descRecordParts
335+ case descRecordPart of
336+ IsoXmlDescRecordField (IsoXmlDescField fieldPlural rawName _) -> do
338+ fieldStrName = xmlLocalName rawName
339+ fName = TH.mkName (fieldName fieldStrName)
340+ exprFieldStrName = TH.litE (TH.stringL rawName)
341+ exprForField = case fieldPlural of
342+ XmlFieldPluralMandatory -> [e|id|]
344+ exprFieldValue = [e|$(TH.varE fName) $(TH.varE objName)|]
347+ XW.elementA $exprFieldStrName (toXmlParentAttributes a) a)|]
348+ return [e|$exprForField $exprFieldRender $exprFieldValue|]
349+ IsoXmlDescRecordContent (IsoXmlDescContent rawName _) -> do
351+ fieldStrName = xmlLocalName rawName
352+ fName = TH.mkName (fieldName fieldStrName)
353+ exprFieldValue = [e|$(TH.varE fName) $(TH.varE objName)|]
354+ return [e|XW.content . toXmlAttribute $ $exprFieldValue|]
357+ = TH.lamE [if null exprFields then TH.wildP else TH.varP objName]
358+ $ foldr (\fe e -> [e|$fe *> $e|]) [e|return ()|] exprFields
361+ [t|XW.ToXML $(TH.conT name)|]
362+ [funSimple 'XW.toXML toXmlExpr]
363+ genToXmlParentAttributeInst = do
364+ objName <- TH.newName strPrefix
346− exprAttributes = do
366+ exprAttributes = do
347− descRecordPart <- descRecordParts
367+ descRecordPart <- descRecordParts
348− IsoXmlDescAttribute attributePlural attributeStrName _ <-
368+ IsoXmlDescAttribute attributePlural attributeStrName _ <-
349− maybeToList $ case descRecordPart of
369+ maybeToList $ case descRecordPart of
350− IsoXmlDescRecordAttribute descAttribute -> Just descAttribute
370+ IsoXmlDescRecordAttribute descAttribute -> Just descAttribute
351− _ -> Nothing
371+ _ -> Nothing
353− fName = TH.mkName (fieldName attributeStrName)
373+ fName = TH.mkName (fieldName attributeStrName)
354− exprAttrStrName = TH.litE (TH.stringL attributeStrName)
374+ exprAttrStrName = TH.litE (TH.stringL attributeStrName)
355− exprAttrValue = [e|$(TH.varE fName) $(TH.varE objName)|]
375+ exprAttrValue = [e|$(TH.varE fName) $(TH.varE objName)|]
356− exprAttrWrap = case attributePlural of
376+ exprAttrWrap = case attributePlural of
357− XmlAttributePluralMandatory -> [e|Just . toXmlAttribute|]
377+ XmlAttributePluralMandatory -> [e|Just . toXmlAttribute|]
358− XmlAttributePluralOptional -> [e|fmap toXmlAttribute|]
378+ XmlAttributePluralOptional -> [e|fmap toXmlAttribute|]
359− return [e|($exprAttrStrName, $exprAttrWrap $exprAttrValue)|]
379+ return [e|($exprAttrStrName, $exprAttrWrap $exprAttrValue)|]
360− toXmlParentAttributesExpr
380+ toXmlParentAttributesExpr
361− = TH.lamE [if null exprAttributes then TH.wildP else TH.varP objName]
381+ = TH.lamE [if null exprAttributes then TH.wildP else TH.varP objName]
362− $ [e|mapMaybe distribPair $(TH.listE exprAttributes)|]
382+ $ [e|mapMaybe distribPair $(TH.listE exprAttributes)|]
363#if __GLASGOW_HASKELL__ < 800
383#if __GLASGOW_HASKELL__ < 800
364− TH.instanceD
384+ TH.instanceD
366− TH.instanceWithOverlapD (Just TH.Overlapping)
386+ TH.instanceWithOverlapD (Just TH.Overlapping)
368− (return [])
388+ (return [])
369− [t|ToXmlParentAttributes $(TH.conT name)|]
389+ [t|ToXmlParentAttributes $(TH.conT name)|]
370− [funSimple 'toXmlParentAttributes toXmlParentAttributesExpr]
390+ [funSimple 'toXmlParentAttributes toXmlParentAttributesExpr]
394+ toXmlInst <- genToXmlInst
395+ toXmlParentAttributesInst <- genToXmlParentAttributeInst
396+ return $ [termDecl] ++ lensDecls ++
397+ [toXmlInst, toXmlParentAttributesInst, nfDataInst]
399+ fromDomInst <- genFromDomInst
372− return $ [termDecl] ++ lensDecls ++
400+ return $ [termDecl] ++ lensDecls ++ [fromDomInst, nfDataInst]
402+ toXmlInst <- genToXmlInst
403+ toXmlParentAttributesInst <- genToXmlParentAttributeInst
404+ fromDomInst <- genFromDomInst
405+ return $ [termDecl] ++ lensDecls ++
373− [fromDomInst, toXmlInst, toXmlParentAttributesInst, nfDataInst]
406+ [fromDomInst, toXmlInst, toXmlParentAttributesInst, nfDataInst]
375distribPair :: Functor f => (a, f b) -> f (a, b)
408distribPair :: Functor f => (a, f b) -> f (a, b)
376distribPair (a, fb) = (a,) <$> fb
409distribPair (a, fb) = (a,) <$> fb