@@ -5,7 +5,7 @@
55module Data.THGen.XML.Internal where
66
77import Control.DeepSeq
8−import Control.Lens hiding (repeated, enum, (&), Strict)
8+import Control.Lens hiding (repeated, enum, (&))
99import Control.Lens.Internal.FieldTH (makeFieldOpticsForDec)
1010import qualified Data.Char as C
1111import Data.List.NonEmpty (NonEmpty)
@@ -15,7 +15,7 @@ import Data.THGen.Compat as THC
1515import Data.THGen.Enum
1616import qualified Data.Text as T
1717import GHC.Generics (Generic)
18−import Language.Haskell.TH as TH hiding (Strict)
18+import Language.Haskell.TH as TH
1919import Prelude hiding ((+), (*), (^))
2020import qualified Text.XML as X
2121import Text.XML.DOM.Parser hiding (parseContent)
@@ -23,22 +23,26 @@ import Text.XML.DOM.Parser.Internal.Content
2323import Text.XML.ParentAttributes
2424import qualified Text.XML.Writer as XW
2525
26−data ParserMode
27− = Strict
28− | Lenient
2926
30−data GenType
31− = Parser
32− | Generator
33− | ParserAndGenerator
34− | LenientParser
35− | LenientParserAndGenerator
27+-- | Marks the type of code generation:
28+-- Parser - generate only instances for xml parsing (@FromDom@)
29+-- Generator - generate only @ToXML@ instances
30+-- Both - generate @FromDom@ and @ToXML@ instances
31+data GenType = Parser | Generator | Both
3632
37−isLenientType :: GenType -> Bool
38−isLenientType = \case
39− LenientParser -> True
40− LenientParserAndGenerator -> True
41− _ -> False
33+{- | Marks the style of code generation regarding records fields
34+@LensRenaming@ - fields get renamed by prefixing the field name with
35+'_' and lowercased capital letter used in the type name.
36+e.g. for
37+
38+> "MyNewDataType" =:= record genType LensRenaming
39+> * "field1"
40+
41+field will be renamed to `_mndtField1` and lens `mndtField1` will be created.
42+
43+@NoLens@ - no field renaming and no lens generation.
44+-}
45+data GenerateLens = LensRenaming | NoLens
4246
4347data XmlFieldPlural
4448 = XmlFieldPluralMandatory -- Occurs exactly 1 time (Identity)
@@ -69,7 +73,7 @@ data IsoXmlDescRecordPart
6973 | IsoXmlDescRecordAttribute IsoXmlDescAttribute
7074 | IsoXmlDescRecordContent IsoXmlDescContent
7175
72−data IsoXmlDescRecord = IsoXmlDescRecord GenType [IsoXmlDescRecordPart]
76+data IsoXmlDescRecord = IsoXmlDescRecord GenType GenerateLens [IsoXmlDescRecordPart]
7377
7478makePrisms ''IsoXmlDescRecord
7579
@@ -90,26 +94,34 @@ appendField
9094 -> IsoXmlDescRecord
9195 -> IsoXmlDescPreField
9296 -> IsoXmlDescRecord
93−appendField plural (IsoXmlDescRecord genType fields) (IsoXmlDescPreField name ty) =
94− let xfield = IsoXmlDescRecordField $ IsoXmlDescField plural name ty
95− in IsoXmlDescRecord genType (xfield:fields)
97+appendField
98+ plural
99+ (IsoXmlDescRecord genType generateLens fields)
100+ (IsoXmlDescPreField name ty) =
101+ let xfield = IsoXmlDescRecordField $ IsoXmlDescField plural name ty
102+ in IsoXmlDescRecord genType generateLens (xfield:fields)
96103
97104appendAttribute
98105 :: XmlAttributePlural
99106 -> IsoXmlDescRecord
100107 -> IsoXmlDescPreAttribute
101108 -> IsoXmlDescRecord
102−appendAttribute plural (IsoXmlDescRecord genType fields) (IsoXmlDescPreAttribute name ty) =
103− let xattribute = IsoXmlDescRecordAttribute $ IsoXmlDescAttribute plural name ty
104− in IsoXmlDescRecord genType (xattribute:fields)
109+appendAttribute
110+ plural
111+ (IsoXmlDescRecord genType generateLens fields)
112+ (IsoXmlDescPreAttribute name ty) =
113+ let xattribute = IsoXmlDescRecordAttribute $ IsoXmlDescAttribute plural name ty
114+ in IsoXmlDescRecord genType generateLens (xattribute:fields)
105115
106116appendContent
107117 :: IsoXmlDescRecord
108118 -> IsoXmlDescPreContent
109119 -> IsoXmlDescRecord
110−appendContent (IsoXmlDescRecord genType fields) (IsoXmlDescPreContent name ty) =
111− let xcontent = IsoXmlDescRecordContent $ IsoXmlDescContent name ty
112− in IsoXmlDescRecord genType (xcontent:fields)
120+appendContent
121+ (IsoXmlDescRecord genType generateLens fields)
122+ (IsoXmlDescPreContent name ty) =
123+ let xcontent = IsoXmlDescRecordContent $ IsoXmlDescContent name ty
124+ in IsoXmlDescRecord genType generateLens (xcontent:fields)
113125
114126(!), (?), (*), (+) :: IsoXmlDescRecord -> IsoXmlDescPreField -> IsoXmlDescRecord
115127(!) = appendField XmlFieldPluralMandatory
@@ -147,11 +159,11 @@ class Description name desc | desc -> name where
147159infix 0 =:=
148160
149161instance Description PrefixName IsoXmlDescRecord where
150− prefixName =:= (IsoXmlDescRecord genType descRecordParts) =
151− isoXmlGenerateDatatype genType prefixName (reverse descRecordParts)
162+ prefixName =:= (IsoXmlDescRecord genType generateLens descRecordParts) =
163+ isoXmlGenerateDatatype genType generateLens prefixName (reverse descRecordParts)
152164
153−record :: GenType -> IsoXmlDescRecord
154−record gt = IsoXmlDescRecord gt []
165+record :: GenType -> GenerateLens -> IsoXmlDescRecord
166+record gt gl = IsoXmlDescRecord gt gl []
155167
156168enum :: GenType -> IsoXmlDescEnum
157169enum gt = IsoXmlDescEnum gt []
@@ -160,7 +172,7 @@ instance Description ExhaustivenessName IsoXmlDescEnum where
160172 exhaustivenessName =:= (IsoXmlDescEnum genType descEnumCons) =
161173 isoXmlGenerateEnum genType exhaustivenessName (reverse descEnumCons)
162174
163−instance (m ~ Q) => IsString (m TH.Type -> IsoXmlDescPreField) where
175+instance IsString (TH.TypeQ -> IsoXmlDescPreField) where
164176 fromString = IsoXmlDescPreField
165177
166178instance IsString IsoXmlDescPreField where
@@ -168,10 +180,10 @@ instance IsString IsoXmlDescPreField where
168180 where
169181 ty = (TH.conT . TH.mkName) ("Xml" ++ over _head C.toUpper (xmlLocalName name))
170182
171−instance (m ~ Q) => IsString (m TH.Type -> IsoXmlDescPreAttribute) where
183+instance IsString (TH.TypeQ -> IsoXmlDescPreAttribute) where
172184 fromString = IsoXmlDescPreAttribute
173185
174−instance (m ~ Q) => IsString (m Type -> IsoXmlDescPreContent) where
186+instance IsString (TH.TypeQ -> IsoXmlDescPreContent) where
175187 fromString = IsoXmlDescPreContent
176188
177189instance IsString IsoXmlDescPreAttribute where
@@ -197,7 +209,7 @@ instance IsString ExhaustivenessName where
197209 fromString strName = ExhaustivenessName strName NonExhaustive
198210
199211makeNamePrefix :: String -> String
200−makeNamePrefix = map C.toLower . filter (\c -> C.isUpper c || C.isDigit c)
212+makeNamePrefix = map C.toLower . filter C.isUpper
201213
202214funSimple :: TH.Name -> TH.ExpQ -> TH.DecQ
203215funSimple name body = TH.funD name [ TH.clause [] (TH.normalB body) [] ]
@@ -225,14 +237,11 @@ isoXmlGenerateEnum genType (ExhaustivenessName strName' exh) enumCons = do
225237 (return [])
226238 [t|ToXmlAttribute $(TH.conT name)|]
227239 [funSimple 'toXmlAttribute [e|T.pack . show|]]
228− genFromDomInst mode = do
240+ genFromDomInst = do
229241 TH.instanceD
230242 (return [])
231243 [t|FromDom $(TH.conT name)|]
232− [case mode of
233− Strict -> funSimple 'fromDom [e|parseContent readContent|]
234− Lenient -> funSimple 'fromDom [e|ignoreBlank $ parseContent readContent|]
235− ]
244+ [funSimple 'fromDom [e|parseContent readContent|]]
236245 genFromAttributeInst = do
237246 TH.instanceD
238247 (return [])
@@ -244,36 +253,36 @@ isoXmlGenerateEnum genType (ExhaustivenessName strName' exh) enumCons = do
244253 toXmlAttributeInst <- genToXmlAttributeInst
245254 return $ enumDecls ++ [toXmlInst, toXmlAttributeInst]
246255 Parser -> do
247− fromDomInst <- genFromDomInst Strict
256+ fromDomInst <- genFromDomInst
248257 fromAttributeInst <- genFromAttributeInst
249258 return $ enumDecls ++ [fromDomInst, fromAttributeInst]
250− LenientParser -> do
251− fromDomInst <- genFromDomInst Lenient
252− fromAttributeInst <- genFromAttributeInst
253− return $ enumDecls ++ [fromDomInst, fromAttributeInst]
254− ParserAndGenerator -> do
259+ Both -> do
255260 toXmlInst <- genToXmlInst
256261 toXmlAttributeInst <- genToXmlAttributeInst
257− fromDomInst <- genFromDomInst Strict
258− fromAttributeInst <- genFromAttributeInst
259− return $ enumDecls ++ [toXmlInst, toXmlAttributeInst,
260− fromDomInst, fromAttributeInst]
261− LenientParserAndGenerator -> do
262− toXmlInst <- genToXmlInst
263− toXmlAttributeInst <- genToXmlAttributeInst
264− fromDomInst <- genFromDomInst Lenient
262+ fromDomInst <- genFromDomInst
265263 fromAttributeInst <- genFromAttributeInst
266264 return $ enumDecls ++ [toXmlInst, toXmlAttributeInst,
267265 fromDomInst, fromAttributeInst]
268266
269−isoXmlGenerateDatatype :: GenType -> PrefixName -> [IsoXmlDescRecordPart] -> TH.DecsQ
270−isoXmlGenerateDatatype genType (PrefixName strName' strPrefix') descRecordParts = do
267+isoXmlGenerateDatatype
268+ :: GenType
269+ -> GenerateLens
270+ -> PrefixName
271+ -> [IsoXmlDescRecordPart]
272+ -> TH.DecsQ
273+isoXmlGenerateDatatype
274+ genType
275+ generateLens
276+ (PrefixName strName' strPrefix')
277+ descRecordParts = do
271278 let
272279 isNewtype = length descRecordParts == 1
273280 strName = "Xml" ++ strName'
274281 strPrefix = "x" ++ strPrefix'
275282 name = TH.mkName strName
276− fieldName str = "_" ++ strPrefix ++ over _head C.toUpper str
283+ fieldName str = case generateLens of
284+ LensRenaming -> "_" ++ strPrefix ++ over _head C.toUpper str
285+ NoLens -> str
277286 termDecl <- do
278287 let
279288 fields = do
@@ -284,14 +293,11 @@ isoXmlGenerateDatatype genType (PrefixName strName' strPrefix') descRecordParts
284293 IsoXmlDescField fieldPlural rawName fieldType = descField
285294 fieldStrName = xmlLocalName rawName
286295 fName = TH.mkName (fieldName fieldStrName)
287− fType' = case fieldPlural of
296+ fType = case fieldPlural of
288297 XmlFieldPluralMandatory -> fieldType
289298 XmlFieldPluralOptional -> [t| Maybe $fieldType |]
290299 XmlFieldPluralRepeated -> [t| [$fieldType] |]
291300 XmlFieldPluralMultiplied -> [t| NonEmpty $fieldType |]
292− fType = if isLenientType genType
293− then [t| Maybe $fType' |]
294− else fType'
295301 in if isNewtype
296302 then THC.varStrictType fName (THC.nonStrictType fType)
297303 else THC.varStrictType fName (THC.strictType fType)
@@ -326,7 +332,7 @@ isoXmlGenerateDatatype genType (PrefixName strName' strPrefix') descRecordParts
326332 [ ]
327333
328334 let
329− genFromDomInst mode = do
335+ genFromDomInst = do
330336 let
331337 exprHeader = [e|pure $(TH.conE name)|]
332338 exprRecordParts = do
@@ -340,9 +346,8 @@ isoXmlGenerateDatatype genType (PrefixName strName' strPrefix') descRecordParts
340346 fieldParse = case fieldPlural of
341347 XmlFieldPluralMandatory -> [e|inElem|]
342348 _ -> [e|inElemTrav|]
343− in case mode of
344− Strict -> [e|$fieldParse $exprFieldStrName fromDom|]
345− Lenient -> [e|$fieldParse $exprFieldStrName (ignoreBlank fromDom)|]
349+ in
350+ [e|$fieldParse $exprFieldStrName fromDom|]
346351 IsoXmlDescRecordAttribute descAttribute ->
347352 let
348353 IsoXmlDescAttribute attributePlural attributeStrName _ = descAttribute
@@ -428,21 +433,12 @@ isoXmlGenerateDatatype genType (PrefixName strName' strPrefix') descRecordParts
428433 return $ [termDecl] ++ lensDecls ++
429434 [toXmlInst, toXmlParentAttributesInst, nfDataInst]
430435 Parser -> do
431− fromDomInst <- genFromDomInst Strict
436+ fromDomInst <- genFromDomInst
432437 return $ [termDecl] ++ lensDecls ++ [fromDomInst, nfDataInst]
433− LenientParser -> do
434− fromDomInst <- genFromDomInst Lenient
435− return $ [termDecl] ++ lensDecls ++ [fromDomInst, nfDataInst]
436− ParserAndGenerator -> do
437− toXmlInst <- genToXmlInst
438− toXmlParentAttributesInst <- genToXmlParentAttributeInst
439− fromDomInst <- genFromDomInst Strict
440− return $ [termDecl] ++ lensDecls ++
441− [fromDomInst, toXmlInst, toXmlParentAttributesInst, nfDataInst]
442− LenientParserAndGenerator -> do
438+ Both -> do
443439 toXmlInst <- genToXmlInst
444440 toXmlParentAttributesInst <- genToXmlParentAttributeInst
445− fromDomInst <- genFromDomInst Lenient
441+ fromDomInst <- genFromDomInst
446442 return $ [termDecl] ++ lensDecls ++
447443 [fromDomInst, toXmlInst, toXmlParentAttributesInst, nfDataInst]
448444