git.iko.soy/typeable/xml-isogen
on master help sign in
Merge pull request #17 from typeable/export-internal
4c69be0Denis Redozubov
src/Data/THGen/XML.hs+7−382
@@ -1,5 +1,4 @@
1−{-# LANGUAGE UndecidableInstances #-}
1+{-# LANGUAGE NoImplicitPrelude #-}
2−{-# LANGUAGE FunctionalDependencies #-}
3
2
4{- |
3{- |
5
4
@@ -117,386 +116,12 @@ module Data.THGen.XML
117 , (^)
116 , (^)
118 , (=:=)
117 , (=:=)
119 -- Re-exports
118 -- Re-exports
120− , T.Text
119+ , Text
121− , Int
120+ , P.Int
122− , Integer
121+ , P.Integer
123 ) where
122 ) where
124
123
125−import Control.DeepSeq
126−import Control.Lens hiding (repeated, enum, (&))
127−import Control.Lens.Internal.FieldTH (makeFieldOpticsForDec)
128−import qualified Data.Char as C
129−import Data.List.NonEmpty (NonEmpty)
130−import Data.Maybe (maybeToList, mapMaybe)
131−import Data.String
132−import Data.THGen.Compat
133import Data.THGen.Enum
124import Data.THGen.Enum
134−import qualified Data.Text as T
125+import Data.THGen.XML.Internal
135−import GHC.Generics (Generic)
126+import Data.Text
136−import qualified Language.Haskell.TH as TH
127+import qualified Prelude as P
137−import Prelude hiding ((+), (*), (^))
138−import qualified Text.XML as X
139−import Text.XML.DOM.Parser hiding (parseContent)
140−import Text.XML.ParentAttributes
141−import qualified Text.XML.Writer as XW
142−import Text.XML.DOM.Parser.Internal.Content
143−
144−
145−data XmlFieldPlural
146− = XmlFieldPluralMandatory -- Occurs exactly 1 time (Identity)
147− | XmlFieldPluralOptional -- Occurs 0 or 1 times (Maybe)
148− | XmlFieldPluralRepeated -- Occurs 0 or more times (List)
149− | XmlFieldPluralMultiplied -- Occurs 1 or more times (NonEmpty)
150−
151−data XmlAttributePlural
152− = XmlAttributePluralMandatory -- Occurs exactly 1 time (Identity)
153− | XmlAttributePluralOptional -- Occurs 0 or 1 times (Maybe)
154−
155−data PrefixName = PrefixName String String
156−
157−data IsoXmlDescPreField = IsoXmlDescPreField String TH.TypeQ
158−
159−data IsoXmlDescPreAttribute = IsoXmlDescPreAttribute String TH.TypeQ
160−
161−data IsoXmlDescPreContent = IsoXmlDescPreContent String TH.TypeQ
162−
163−data IsoXmlDescField = IsoXmlDescField XmlFieldPlural String TH.TypeQ
164−
165−data IsoXmlDescAttribute = IsoXmlDescAttribute XmlAttributePlural String TH.TypeQ
166−
167−data IsoXmlDescContent = IsoXmlDescContent String TH.TypeQ
168−
169−data IsoXmlDescRecordPart
170− = IsoXmlDescRecordField IsoXmlDescField
171− | IsoXmlDescRecordAttribute IsoXmlDescAttribute
172− | IsoXmlDescRecordContent IsoXmlDescContent
173−
174−newtype IsoXmlDescRecord = IsoXmlDescRecord [IsoXmlDescRecordPart]
175−
176−makePrisms ''IsoXmlDescRecord
177−
178−data ExhaustivenessName = ExhaustivenessName String Exhaustiveness
179−
180−newtype IsoXmlDescEnumCon
181− = IsoXmlDescEnumCon { unIsoXmlDescEnumCon :: String }
182−
183−instance IsString IsoXmlDescEnumCon where
184− fromString = IsoXmlDescEnumCon
185−
186−data IsoXmlDescEnum = IsoXmlDescEnum [IsoXmlDescEnumCon]
187−
188−makePrisms ''IsoXmlDescEnum
189−
190−appendField
191− :: XmlFieldPlural
192− -> IsoXmlDescRecord
193− -> IsoXmlDescPreField
194− -> IsoXmlDescRecord
195−appendField plural xrec (IsoXmlDescPreField name ty) =
196− let xfield = IsoXmlDescRecordField $ IsoXmlDescField plural name ty
197− in over _IsoXmlDescRecord (xfield:) xrec
198−
199−appendAttribute
200− :: XmlAttributePlural
201− -> IsoXmlDescRecord
202− -> IsoXmlDescPreAttribute
203− -> IsoXmlDescRecord
204−appendAttribute plural xrec (IsoXmlDescPreAttribute name ty) =
205− let xattribute = IsoXmlDescRecordAttribute $ IsoXmlDescAttribute plural name ty
206− in over _IsoXmlDescRecord (xattribute:) xrec
207−
208−appendContent
209− :: IsoXmlDescRecord
210− -> IsoXmlDescPreContent
211− -> IsoXmlDescRecord
212−appendContent xrec (IsoXmlDescPreContent name ty) =
213− let xcontent = IsoXmlDescRecordContent $ IsoXmlDescContent name ty
214− in over _IsoXmlDescRecord (xcontent:) xrec
215−
216−(!), (?), (*), (+) :: IsoXmlDescRecord -> IsoXmlDescPreField -> IsoXmlDescRecord
217−(!) = appendField XmlFieldPluralMandatory
218−(?) = appendField XmlFieldPluralOptional
219−(*) = appendField XmlFieldPluralRepeated
220−(+) = appendField XmlFieldPluralMultiplied
221−
222−(!%), (?%) :: IsoXmlDescRecord -> IsoXmlDescPreAttribute -> IsoXmlDescRecord
223−(!%) = appendAttribute XmlAttributePluralMandatory
224−(?%) = appendAttribute XmlAttributePluralOptional
225−
226−(^) :: IsoXmlDescRecord -> IsoXmlDescPreContent -> IsoXmlDescRecord
227−(^) = appendContent
228−
229−infixl 2 !
230−infixl 2 ?
231−infixl 2 *
232−infixl 2 +
233−infixl 2 !%
234−infixl 2 ?%
235−infixl 2 ^
236−
237−appendEnumCon :: IsoXmlDescEnum -> IsoXmlDescEnumCon -> IsoXmlDescEnum
238−appendEnumCon xenum xenumcon =
239− over _IsoXmlDescEnum (xenumcon:) xenum
240−
241−(&) :: IsoXmlDescEnum -> IsoXmlDescEnumCon -> IsoXmlDescEnum
242−(&) = appendEnumCon
243−
244−infixl 2 &
245−
246−class Description name desc | desc -> name where
247− (=:=) :: name -> desc -> TH.DecsQ
248−
249−infix 0 =:=
250−
251−instance Description PrefixName IsoXmlDescRecord where
252− prefixName =:= descRecord =
253− let descRecordParts = descRecord ^. _IsoXmlDescRecord
254− in isoXmlGenerateDatatype prefixName (reverse descRecordParts)
255−
256−record :: IsoXmlDescRecord
257−record = IsoXmlDescRecord []
258−
259−enum :: IsoXmlDescEnum
260−enum = IsoXmlDescEnum []
261−
262−instance Description ExhaustivenessName IsoXmlDescEnum where
263− exhaustivenessName =:= descEnum =
264− let descEnumCons = descEnum ^. _IsoXmlDescEnum
265− in isoXmlGenerateEnum exhaustivenessName (reverse descEnumCons)
266−
267−instance IsString (TH.TypeQ -> IsoXmlDescPreField) where
268− fromString = IsoXmlDescPreField
269−
270−instance IsString IsoXmlDescPreField where
271− fromString name = IsoXmlDescPreField name ty
272− where
273− ty = (TH.conT . TH.mkName) ("Xml" ++ over _head C.toUpper (xmlLocalName name))
274−
275−instance IsString (TH.TypeQ -> IsoXmlDescPreAttribute) where
276− fromString = IsoXmlDescPreAttribute
277−
278−instance IsString (TH.TypeQ -> IsoXmlDescPreContent) where
279− fromString = IsoXmlDescPreContent
280−
281−instance IsString IsoXmlDescPreAttribute where
282− fromString name = IsoXmlDescPreAttribute name ty
283− where
284− ty = (TH.conT . TH.mkName) ("Xml" ++ over _head C.toUpper name)
285−
286−instance IsString IsoXmlDescPreContent where
287− fromString name = IsoXmlDescPreContent name ty
288− where
289− ty = (TH.conT . TH.mkName) ("Xml" ++ over _head C.toUpper name)
290−
291−instance s ~ String => IsString (s -> PrefixName) where
292− fromString = PrefixName
293−
294−instance IsString PrefixName where
295− fromString strName = PrefixName strName (makeNamePrefix strName)
296−
297−instance e ~ Exhaustiveness => IsString (e -> ExhaustivenessName) where
298− fromString = ExhaustivenessName
299−
300−instance IsString ExhaustivenessName where
301− fromString strName = ExhaustivenessName strName NonExhaustive
302−
303−makeNamePrefix :: String -> String
304−makeNamePrefix = map C.toLower . filter C.isUpper
305−
306−funSimple :: TH.Name -> TH.ExpQ -> TH.DecQ
307−funSimple name body = TH.funD name [ TH.clause [] (TH.normalB body) [] ]
308−
309−isoXmlGenerateEnum
310− :: ExhaustivenessName -> [IsoXmlDescEnumCon] -> TH.DecsQ
311−isoXmlGenerateEnum (ExhaustivenessName strName' exh) enumCons = do
312− let
313− strName = "Xml" ++ strName'
314− strVals = map unIsoXmlDescEnumCon enumCons
315− enumDesc = EnumDesc exh strName strVals
316− name = TH.mkName strName
317− enumDecls <- enumGenerate enumDesc
318− toXmlInst <- do
319− TH.instanceD
320− (return [])
321− [t|XW.ToXML $(TH.conT name)|]
322− [funSimple 'XW.toXML [e|XW.toXML . T.pack . show|]]
323− toXmlAttributeInst <- do
324− TH.instanceD
325− (return [])
326− [t|ToXmlAttribute $(TH.conT name)|]
327− [funSimple 'toXmlAttribute [e|T.pack . show|]]
328− fromDomInst <- do
329− TH.instanceD
330− (return [])
331− [t|FromDom $(TH.conT name)|]
332− [funSimple 'fromDom [e|parseContent readContent|]]
333− fromAttributeInst <- do
334− TH.instanceD
335− (return [])
336− [t|FromAttribute $(TH.conT name)|]
337− [funSimple 'fromAttribute [e|readContent|]]
338− return $ enumDecls ++ [toXmlInst, toXmlAttributeInst,
339− fromDomInst, fromAttributeInst]
340−
341−isoXmlGenerateDatatype :: PrefixName -> [IsoXmlDescRecordPart] -> TH.DecsQ
342−isoXmlGenerateDatatype (PrefixName strName' strPrefix') descRecordParts = do
343− let
344− isNewtype = length descRecordParts == 1
345− strName = "Xml" ++ strName'
346− strPrefix = "x" ++ strPrefix'
347− name = TH.mkName strName
348− fieldName str = "_" ++ strPrefix ++ over _head C.toUpper str
349− termDecl <- do
350− let
351− fields = do
352− descRecordPart <- descRecordParts
353− return $ case descRecordPart of
354− IsoXmlDescRecordField descField ->
355− let
356− IsoXmlDescField fieldPlural rawName fieldType = descField
357− fieldStrName = xmlLocalName rawName
358− fName = TH.mkName (fieldName fieldStrName)
359− fType = case fieldPlural of
360− XmlFieldPluralMandatory -> fieldType
361− XmlFieldPluralOptional -> [t| Maybe $fieldType |]
362− XmlFieldPluralRepeated -> [t| [$fieldType] |]
363− XmlFieldPluralMultiplied -> [t| NonEmpty $fieldType |]
364− in if isNewtype
365− then varStrictType fName (nonStrictType fType)
366− else varStrictType fName (strictType fType)
367− IsoXmlDescRecordAttribute descAttribute ->
368− let
369− IsoXmlDescAttribute
370− attributePlural attributeStrName attributeType = descAttribute
371− fName = TH.mkName (fieldName attributeStrName)
372− fType = case attributePlural of
373− XmlAttributePluralMandatory -> attributeType
374− XmlAttributePluralOptional -> [t| Maybe $attributeType |]
375− in if isNewtype
376− then varStrictType fName (nonStrictType fType)
377− else varStrictType fName (strictType fType)
378− IsoXmlDescRecordContent descContent ->
379− let
380− IsoXmlDescContent contentStrName contentType = descContent
381− fName = TH.mkName (fieldName contentStrName)
382− fType = contentType
383− in if isNewtype
384− then varStrictType fName (nonStrictType fType)
385− else varStrictType fName (strictType fType)
386− if isNewtype
387− -- generate a newtype instead to do less allocations later
388− then newtypeD name (TH.recC name fields) [''Eq, ''Show, ''Generic]
389− else dataD name [TH.recC name fields] [''Eq, ''Show, ''Generic]
390− lensDecls <- makeFieldOpticsForDec lensRules termDecl
391− nfDataInst <- do
392− TH.instanceD
393− (return [])
394− [t|NFData $(TH.conT name)|]
395− [ ]
396− fromDomInst <- do
397− let
398− exprHeader = [e|pure $(TH.conE name)|]
399− exprRecordParts = do
400− descRecordPart <- descRecordParts
401− return $ case descRecordPart of
402− IsoXmlDescRecordField descField ->
403− let
404− IsoXmlDescField fieldPlural rawName _ = descField
405− fieldStrName = xmlLocalName rawName
406− exprFieldStrName = TH.litE (TH.stringL fieldStrName)
407− fieldParse = case fieldPlural of
408− XmlFieldPluralMandatory -> [e|inElem|]
409− _ -> [e|inElemTrav|]
410− in
411− [e|$fieldParse $exprFieldStrName fromDom|]
412− IsoXmlDescRecordAttribute descAttribute ->
413− let
414− IsoXmlDescAttribute attributePlural attributeStrName _ = descAttribute
415− exprAttributeStrName = TH.litE (TH.stringL attributeStrName)
416− attributeParse = case attributePlural of
417− XmlAttributePluralMandatory -> [e|parseAttribute|]
418− XmlAttributePluralOptional -> [e|parseAttributeMaybe|]
419− in
420− [e|$attributeParse $exprAttributeStrName fromAttribute|]
421− IsoXmlDescRecordContent _ -> [e|parseContent fromAttribute|]
422− fromDomExpr = foldl (\e fe -> [e| $e <*> $fe |]) exprHeader exprRecordParts
423− TH.instanceD
424− (return [])
425− [t|FromDom $(TH.conT name)|]
426− [ funSimple 'fromDom fromDomExpr ]
427−
428− toXmlInst <- do
429− objName <- TH.newName strPrefix
430− let
431− exprFields = do
432− descRecordPart <- descRecordParts
433− case descRecordPart of
434− IsoXmlDescRecordField (IsoXmlDescField fieldPlural rawName _) -> do
435− let
436− fieldStrName = xmlLocalName rawName
437− fName = TH.mkName (fieldName fieldStrName)
438− exprFieldStrName = TH.litE (TH.stringL rawName)
439− exprForField = case fieldPlural of
440− XmlFieldPluralMandatory -> [e|id|]
441− _ -> [e|traverse|]
442− exprFieldValue = [e|$(TH.varE fName) $(TH.varE objName)|]
443− exprFieldRender =
444− [e|(\a ->
445− XW.elementA $exprFieldStrName (toXmlParentAttributes a) a)|]
446− return [e|$exprForField $exprFieldRender $exprFieldValue|]
447− IsoXmlDescRecordContent (IsoXmlDescContent rawName _) -> do
448− let
449− fieldStrName = xmlLocalName rawName
450− fName = TH.mkName (fieldName fieldStrName)
451− exprFieldValue = [e|$(TH.varE fName) $(TH.varE objName)|]
452− return [e|XW.content . toXmlAttribute $ $exprFieldValue|]
453− _ -> []
454− toXmlExpr
455− = TH.lamE [if null exprFields then TH.wildP else TH.varP objName]
456− $ foldr (\fe e -> [e|$fe *> $e|]) [e|return ()|] exprFields
457− TH.instanceD
458− (return [])
459− [t|XW.ToXML $(TH.conT name)|]
460− [funSimple 'XW.toXML toXmlExpr]
461−
462− toXmlParentAttributesInst <- do
463− objName <- TH.newName strPrefix
464− let
465− exprAttributes = do
466− descRecordPart <- descRecordParts
467− IsoXmlDescAttribute attributePlural attributeStrName _ <-
468− maybeToList $ case descRecordPart of
469− IsoXmlDescRecordAttribute descAttribute -> Just descAttribute
470− _ -> Nothing
471− let
472− fName = TH.mkName (fieldName attributeStrName)
473− exprAttrStrName = TH.litE (TH.stringL attributeStrName)
474− exprAttrValue = [e|$(TH.varE fName) $(TH.varE objName)|]
475− exprAttrWrap = case attributePlural of
476− XmlAttributePluralMandatory -> [e|Just . toXmlAttribute|]
477− XmlAttributePluralOptional -> [e|fmap toXmlAttribute|]
478− return [e|($exprAttrStrName, $exprAttrWrap $exprAttrValue)|]
479− toXmlParentAttributesExpr
480− = TH.lamE [if null exprAttributes then TH.wildP else TH.varP objName]
481− $ [e|mapMaybe distribPair $(TH.listE exprAttributes)|]
482−#if __GLASGOW_HASKELL__ < 800
483− TH.instanceD
484−#else
485− TH.instanceWithOverlapD (Just TH.Overlapping)
486−#endif
487− (return [])
488− [t|ToXmlParentAttributes $(TH.conT name)|]
489− [funSimple 'toXmlParentAttributes toXmlParentAttributesExpr]
490−
491− return $ [termDecl] ++ lensDecls ++
492− [fromDomInst, toXmlInst, toXmlParentAttributesInst, nfDataInst]
493−
494−distribPair :: Functor f => (a, f b) -> f (a, b)
495−distribPair (a, fb) = (a,) <$> fb
496−
497−-- | Get a local part of (possibly) fully qualified 'X.Name':
498−--
499−-- >>> xmlLocalName "{http://example.com/ns/my-namespace}my-name"
500−-- "my-name"
501−xmlLocalName :: String -> String
502−xmlLocalName = T.unpack . X.nameLocalName . fromString
src/Data/THGen/XML/Internal.hsnew file+383
@@ -0,0 +1,383 @@
1+{-# LANGUAGE UndecidableInstances #-}
2+{-# LANGUAGE FunctionalDependencies #-}
3+
4+module Data.THGen.XML.Internal where
5+
6+import Control.DeepSeq
7+import Control.Lens hiding (repeated, enum, (&))
8+import Control.Lens.Internal.FieldTH (makeFieldOpticsForDec)
9+import qualified Data.Char as C
10+import Data.List.NonEmpty (NonEmpty)
11+import Data.Maybe (maybeToList, mapMaybe)
12+import Data.String
13+import Data.THGen.Compat as THC
14+import Data.THGen.Enum
15+import qualified Data.Text as T
16+import GHC.Generics (Generic)
17+import Language.Haskell.TH as TH
18+import Prelude hiding ((+), (*), (^))
19+import qualified Text.XML as X
20+import Text.XML.DOM.Parser hiding (parseContent)
21+import Text.XML.DOM.Parser.Internal.Content
22+import Text.XML.ParentAttributes
23+import qualified Text.XML.Writer as XW
24+
25+
26+data XmlFieldPlural
27+ = XmlFieldPluralMandatory -- Occurs exactly 1 time (Identity)
28+ | XmlFieldPluralOptional -- Occurs 0 or 1 times (Maybe)
29+ | XmlFieldPluralRepeated -- Occurs 0 or more times (List)
30+ | XmlFieldPluralMultiplied -- Occurs 1 or more times (NonEmpty)
31+
32+data XmlAttributePlural
33+ = XmlAttributePluralMandatory -- Occurs exactly 1 time (Identity)
34+ | XmlAttributePluralOptional -- Occurs 0 or 1 times (Maybe)
35+
36+data PrefixName = PrefixName String String
37+
38+data IsoXmlDescPreField = IsoXmlDescPreField String TH.TypeQ
39+
40+data IsoXmlDescPreAttribute = IsoXmlDescPreAttribute String TH.TypeQ
41+
42+data IsoXmlDescPreContent = IsoXmlDescPreContent String TH.TypeQ
43+
44+data IsoXmlDescField = IsoXmlDescField XmlFieldPlural String TH.TypeQ
45+
46+data IsoXmlDescAttribute = IsoXmlDescAttribute XmlAttributePlural String TH.TypeQ
47+
48+data IsoXmlDescContent = IsoXmlDescContent String TH.TypeQ
49+
50+data IsoXmlDescRecordPart
51+ = IsoXmlDescRecordField IsoXmlDescField
52+ | IsoXmlDescRecordAttribute IsoXmlDescAttribute
53+ | IsoXmlDescRecordContent IsoXmlDescContent
54+
55+newtype IsoXmlDescRecord = IsoXmlDescRecord [IsoXmlDescRecordPart]
56+
57+makePrisms ''IsoXmlDescRecord
58+
59+data ExhaustivenessName = ExhaustivenessName String Exhaustiveness
60+
61+newtype IsoXmlDescEnumCon
62+ = IsoXmlDescEnumCon { unIsoXmlDescEnumCon :: String }
63+
64+instance IsString IsoXmlDescEnumCon where
65+ fromString = IsoXmlDescEnumCon
66+
67+data IsoXmlDescEnum = IsoXmlDescEnum [IsoXmlDescEnumCon]
68+
69+makePrisms ''IsoXmlDescEnum
70+
71+appendField
72+ :: XmlFieldPlural
73+ -> IsoXmlDescRecord
74+ -> IsoXmlDescPreField
75+ -> IsoXmlDescRecord
76+appendField plural xrec (IsoXmlDescPreField name ty) =
77+ let xfield = IsoXmlDescRecordField $ IsoXmlDescField plural name ty
78+ in over _IsoXmlDescRecord (xfield:) xrec
79+
80+appendAttribute
81+ :: XmlAttributePlural
82+ -> IsoXmlDescRecord
83+ -> IsoXmlDescPreAttribute
84+ -> IsoXmlDescRecord
85+appendAttribute plural xrec (IsoXmlDescPreAttribute name ty) =
86+ let xattribute = IsoXmlDescRecordAttribute $ IsoXmlDescAttribute plural name ty
87+ in over _IsoXmlDescRecord (xattribute:) xrec
88+
89+appendContent
90+ :: IsoXmlDescRecord
91+ -> IsoXmlDescPreContent
92+ -> IsoXmlDescRecord
93+appendContent xrec (IsoXmlDescPreContent name ty) =
94+ let xcontent = IsoXmlDescRecordContent $ IsoXmlDescContent name ty
95+ in over _IsoXmlDescRecord (xcontent:) xrec
96+
97+(!), (?), (*), (+) :: IsoXmlDescRecord -> IsoXmlDescPreField -> IsoXmlDescRecord
98+(!) = appendField XmlFieldPluralMandatory
99+(?) = appendField XmlFieldPluralOptional
100+(*) = appendField XmlFieldPluralRepeated
101+(+) = appendField XmlFieldPluralMultiplied
102+
103+(!%), (?%) :: IsoXmlDescRecord -> IsoXmlDescPreAttribute -> IsoXmlDescRecord
104+(!%) = appendAttribute XmlAttributePluralMandatory
105+(?%) = appendAttribute XmlAttributePluralOptional
106+
107+(^) :: IsoXmlDescRecord -> IsoXmlDescPreContent -> IsoXmlDescRecord
108+(^) = appendContent
109+
110+infixl 2 !
111+infixl 2 ?
112+infixl 2 *
113+infixl 2 +
114+infixl 2 !%
115+infixl 2 ?%
116+infixl 2 ^
117+
118+appendEnumCon :: IsoXmlDescEnum -> IsoXmlDescEnumCon -> IsoXmlDescEnum
119+appendEnumCon xenum xenumcon =
120+ over _IsoXmlDescEnum (xenumcon:) xenum
121+
122+(&) :: IsoXmlDescEnum -> IsoXmlDescEnumCon -> IsoXmlDescEnum
123+(&) = appendEnumCon
124+
125+infixl 2 &
126+
127+class Description name desc | desc -> name where
128+ (=:=) :: name -> desc -> TH.DecsQ
129+
130+infix 0 =:=
131+
132+instance Description PrefixName IsoXmlDescRecord where
133+ prefixName =:= descRecord =
134+ let descRecordParts = descRecord ^. _IsoXmlDescRecord
135+ in isoXmlGenerateDatatype prefixName (reverse descRecordParts)
136+
137+record :: IsoXmlDescRecord
138+record = IsoXmlDescRecord []
139+
140+enum :: IsoXmlDescEnum
141+enum = IsoXmlDescEnum []
142+
143+instance Description ExhaustivenessName IsoXmlDescEnum where
144+ exhaustivenessName =:= descEnum =
145+ let descEnumCons = descEnum ^. _IsoXmlDescEnum
146+ in isoXmlGenerateEnum exhaustivenessName (reverse descEnumCons)
147+
148+instance IsString (TH.TypeQ -> IsoXmlDescPreField) where
149+ fromString = IsoXmlDescPreField
150+
151+instance IsString IsoXmlDescPreField where
152+ fromString name = IsoXmlDescPreField name ty
153+ where
154+ ty = (TH.conT . TH.mkName) ("Xml" ++ over _head C.toUpper (xmlLocalName name))
155+
156+instance IsString (TH.TypeQ -> IsoXmlDescPreAttribute) where
157+ fromString = IsoXmlDescPreAttribute
158+
159+instance IsString (TH.TypeQ -> IsoXmlDescPreContent) where
160+ fromString = IsoXmlDescPreContent
161+
162+instance IsString IsoXmlDescPreAttribute where
163+ fromString name = IsoXmlDescPreAttribute name ty
164+ where
165+ ty = (TH.conT . TH.mkName) ("Xml" ++ over _head C.toUpper name)
166+
167+instance IsString IsoXmlDescPreContent where
168+ fromString name = IsoXmlDescPreContent name ty
169+ where
170+ ty = (TH.conT . TH.mkName) ("Xml" ++ over _head C.toUpper name)
171+
172+instance s ~ String => IsString (s -> PrefixName) where
173+ fromString = PrefixName
174+
175+instance IsString PrefixName where
176+ fromString strName = PrefixName strName (makeNamePrefix strName)
177+
178+instance e ~ Exhaustiveness => IsString (e -> ExhaustivenessName) where
179+ fromString = ExhaustivenessName
180+
181+instance IsString ExhaustivenessName where
182+ fromString strName = ExhaustivenessName strName NonExhaustive
183+
184+makeNamePrefix :: String -> String
185+makeNamePrefix = map C.toLower . filter C.isUpper
186+
187+funSimple :: TH.Name -> TH.ExpQ -> TH.DecQ
188+funSimple name body = TH.funD name [ TH.clause [] (TH.normalB body) [] ]
189+
190+isoXmlGenerateEnum
191+ :: ExhaustivenessName -> [IsoXmlDescEnumCon] -> TH.DecsQ
192+isoXmlGenerateEnum (ExhaustivenessName strName' exh) enumCons = do
193+ let
194+ strName = "Xml" ++ strName'
195+ strVals = map unIsoXmlDescEnumCon enumCons
196+ enumDesc = EnumDesc exh strName strVals
197+ name = TH.mkName strName
198+ enumDecls <- enumGenerate enumDesc
199+ toXmlInst <- do
200+ TH.instanceD
201+ (return [])
202+ [t|XW.ToXML $(TH.conT name)|]
203+ [funSimple 'XW.toXML [e|XW.toXML . T.pack . show|]]
204+ toXmlAttributeInst <- do
205+ TH.instanceD
206+ (return [])
207+ [t|ToXmlAttribute $(TH.conT name)|]
208+ [funSimple 'toXmlAttribute [e|T.pack . show|]]
209+ fromDomInst <- do
210+ TH.instanceD
211+ (return [])
212+ [t|FromDom $(TH.conT name)|]
213+ [funSimple 'fromDom [e|parseContent readContent|]]
214+ fromAttributeInst <- do
215+ TH.instanceD
216+ (return [])
217+ [t|FromAttribute $(TH.conT name)|]
218+ [funSimple 'fromAttribute [e|readContent|]]
219+ return $ enumDecls ++ [toXmlInst, toXmlAttributeInst,
220+ fromDomInst, fromAttributeInst]
221+
222+isoXmlGenerateDatatype :: PrefixName -> [IsoXmlDescRecordPart] -> TH.DecsQ
223+isoXmlGenerateDatatype (PrefixName strName' strPrefix') descRecordParts = do
224+ let
225+ isNewtype = length descRecordParts == 1
226+ strName = "Xml" ++ strName'
227+ strPrefix = "x" ++ strPrefix'
228+ name = TH.mkName strName
229+ fieldName str = "_" ++ strPrefix ++ over _head C.toUpper str
230+ termDecl <- do
231+ let
232+ fields = do
233+ descRecordPart <- descRecordParts
234+ return $ case descRecordPart of
235+ IsoXmlDescRecordField descField ->
236+ let
237+ IsoXmlDescField fieldPlural rawName fieldType = descField
238+ fieldStrName = xmlLocalName rawName
239+ fName = TH.mkName (fieldName fieldStrName)
240+ fType = case fieldPlural of
241+ XmlFieldPluralMandatory -> fieldType
242+ XmlFieldPluralOptional -> [t| Maybe $fieldType |]
243+ XmlFieldPluralRepeated -> [t| [$fieldType] |]
244+ XmlFieldPluralMultiplied -> [t| NonEmpty $fieldType |]
245+ in if isNewtype
246+ then THC.varStrictType fName (THC.nonStrictType fType)
247+ else THC.varStrictType fName (THC.strictType fType)
248+ IsoXmlDescRecordAttribute descAttribute ->
249+ let
250+ IsoXmlDescAttribute
251+ attributePlural attributeStrName attributeType = descAttribute
252+ fName = TH.mkName (fieldName attributeStrName)
253+ fType = case attributePlural of
254+ XmlAttributePluralMandatory -> attributeType
255+ XmlAttributePluralOptional -> [t| Maybe $attributeType |]
256+ in if isNewtype
257+ then THC.varStrictType fName (THC.nonStrictType fType)
258+ else THC.varStrictType fName (THC.strictType fType)
259+ IsoXmlDescRecordContent descContent ->
260+ let
261+ IsoXmlDescContent contentStrName contentType = descContent
262+ fName = TH.mkName (fieldName contentStrName)
263+ fType = contentType
264+ in if isNewtype
265+ then THC.varStrictType fName (THC.nonStrictType fType)
266+ else THC.varStrictType fName (THC.strictType fType)
267+ if isNewtype
268+ -- generate a newtype instead to do less allocations later
269+ then THC.newtypeD name (TH.recC name fields) [''Eq, ''Show, ''Generic]
270+ else THC.dataD name [TH.recC name fields] [''Eq, ''Show, ''Generic]
271+ lensDecls <- makeFieldOpticsForDec lensRules termDecl
272+ nfDataInst <- do
273+ TH.instanceD
274+ (return [])
275+ [t|NFData $(TH.conT name)|]
276+ [ ]
277+ fromDomInst <- do
278+ let
279+ exprHeader = [e|pure $(TH.conE name)|]
280+ exprRecordParts = do
281+ descRecordPart <- descRecordParts
282+ return $ case descRecordPart of
283+ IsoXmlDescRecordField descField ->
284+ let
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|]
291+ in
292+ [e|$fieldParse $exprFieldStrName fromDom|]
293+ IsoXmlDescRecordAttribute descAttribute ->
294+ let
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|]
300+ in
301+ [e|$attributeParse $exprAttributeStrName fromAttribute|]
302+ IsoXmlDescRecordContent _ -> [e|parseContent fromAttribute|]
303+ fromDomExpr = foldl (\e fe -> [e| $e <*> $fe |]) exprHeader exprRecordParts
304+ TH.instanceD
305+ (return [])
306+ [t|FromDom $(TH.conT name)|]
307+ [ funSimple 'fromDom fromDomExpr ]
308+
309+ toXmlInst <- do
310+ objName <- TH.newName strPrefix
311+ let
312+ exprFields = do
313+ descRecordPart <- descRecordParts
314+ case descRecordPart of
315+ IsoXmlDescRecordField (IsoXmlDescField fieldPlural rawName _) -> do
316+ let
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|]
322+ _ -> [e|traverse|]
323+ exprFieldValue = [e|$(TH.varE fName) $(TH.varE objName)|]
324+ exprFieldRender =
325+ [e|(\a ->
326+ XW.elementA $exprFieldStrName (toXmlParentAttributes a) a)|]
327+ return [e|$exprForField $exprFieldRender $exprFieldValue|]
328+ IsoXmlDescRecordContent (IsoXmlDescContent rawName _) -> do
329+ let
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|]
334+ _ -> []
335+ toXmlExpr
336+ = TH.lamE [if null exprFields then TH.wildP else TH.varP objName]
337+ $ foldr (\fe e -> [e|$fe *> $e|]) [e|return ()|] exprFields
338+ TH.instanceD
339+ (return [])
340+ [t|XW.ToXML $(TH.conT name)|]
341+ [funSimple 'XW.toXML toXmlExpr]
342+
343+ toXmlParentAttributesInst <- do
344+ objName <- TH.newName strPrefix
345+ let
346+ exprAttributes = do
347+ descRecordPart <- descRecordParts
348+ IsoXmlDescAttribute attributePlural attributeStrName _ <-
349+ maybeToList $ case descRecordPart of
350+ IsoXmlDescRecordAttribute descAttribute -> Just descAttribute
351+ _ -> Nothing
352+ let
353+ fName = TH.mkName (fieldName attributeStrName)
354+ exprAttrStrName = TH.litE (TH.stringL attributeStrName)
355+ exprAttrValue = [e|$(TH.varE fName) $(TH.varE objName)|]
356+ exprAttrWrap = case attributePlural of
357+ XmlAttributePluralMandatory -> [e|Just . toXmlAttribute|]
358+ XmlAttributePluralOptional -> [e|fmap toXmlAttribute|]
359+ return [e|($exprAttrStrName, $exprAttrWrap $exprAttrValue)|]
360+ toXmlParentAttributesExpr
361+ = TH.lamE [if null exprAttributes then TH.wildP else TH.varP objName]
362+ $ [e|mapMaybe distribPair $(TH.listE exprAttributes)|]
363+#if __GLASGOW_HASKELL__ < 800
364+ TH.instanceD
365+#else
366+ TH.instanceWithOverlapD (Just TH.Overlapping)
367+#endif
368+ (return [])
369+ [t|ToXmlParentAttributes $(TH.conT name)|]
370+ [funSimple 'toXmlParentAttributes toXmlParentAttributesExpr]
371+
372+ return $ [termDecl] ++ lensDecls ++
373+ [fromDomInst, toXmlInst, toXmlParentAttributesInst, nfDataInst]
374+
375+distribPair :: Functor f => (a, f b) -> f (a, b)
376+distribPair (a, fb) = (a,) <$> fb
377+
378+-- | Get a local part of (possibly) fully qualified 'X.Name':
379+--
380+-- >>> xmlLocalName "{http://example.com/ns/my-namespace}my-name"
381+-- "my-name"
382+xmlLocalName :: String -> String
383+xmlLocalName = T.unpack . X.nameLocalName . fromString
xml-isogen.cabal+1
@@ -30,6 +30,7 @@ source-repository head
30library
30library
31 exposed-modules: Data.THGen.Enum
31 exposed-modules: Data.THGen.Enum
32 , Data.THGen.XML
32 , Data.THGen.XML
33+ , Data.THGen.XML.Internal
33 , Text.XML.ParentAttributes
34 , Text.XML.ParentAttributes
34 other-modules: Data.THGen.Compat
35 other-modules: Data.THGen.Compat
35 , Text.XML.DOM.Parser.Internal.Content
36 , Text.XML.DOM.Parser.Internal.Content