@@ -5,7 +5,7 @@
55module Data.THGen.XML.Internal where
66
77import Control.DeepSeq
8−import Control.Lens hiding (repeated, enum, (&))
8+import Control.Lens hiding (repeated, enum, (&), Strict)
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
18+import Language.Haskell.TH as TH hiding (Strict)
1919import Prelude hiding ((+), (*), (^))
2020import qualified Text.XML as X
2121import Text.XML.DOM.Parser hiding (parseContent)
@@ -23,10 +23,22 @@ 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
2629
27−data GenType = Parser | Generator | Both
30+data GenType
31+ = Parser
32+ | Generator
33+ | ParserAndGenerator
34+ | LenientParser
35+ | LenientParserAndGenerator
2836
29−data GenerateLens = Lens | NoLens
37+isLenientType :: GenType -> Bool
38+isLenientType = \case
39+ LenientParser -> True
40+ LenientParserAndGenerator -> True
41+ _ -> False
3042
3143data XmlFieldPlural
3244 = XmlFieldPluralMandatory -- Occurs exactly 1 time (Identity)
@@ -57,7 +69,7 @@ data IsoXmlDescRecordPart
5769 | IsoXmlDescRecordAttribute IsoXmlDescAttribute
5870 | IsoXmlDescRecordContent IsoXmlDescContent
5971
60−data IsoXmlDescRecord = IsoXmlDescRecord GenType GenerateLens [IsoXmlDescRecordPart]
72+data IsoXmlDescRecord = IsoXmlDescRecord GenType [IsoXmlDescRecordPart]
6173
6274makePrisms ''IsoXmlDescRecord
6375
@@ -78,34 +90,26 @@ appendField
7890 -> IsoXmlDescRecord
7991 -> IsoXmlDescPreField
8092 -> IsoXmlDescRecord
81−appendField
82− plural
83− (IsoXmlDescRecord genType generateLens fields)
84− (IsoXmlDescPreField name ty) =
85− let xfield = IsoXmlDescRecordField $ IsoXmlDescField plural name ty
86− in IsoXmlDescRecord genType generateLens (xfield:fields)
93+appendField plural (IsoXmlDescRecord genType fields) (IsoXmlDescPreField name ty) =
94+ let xfield = IsoXmlDescRecordField $ IsoXmlDescField plural name ty
95+ in IsoXmlDescRecord genType (xfield:fields)
8796
8897appendAttribute
8998 :: XmlAttributePlural
9099 -> IsoXmlDescRecord
91100 -> IsoXmlDescPreAttribute
92101 -> IsoXmlDescRecord
93−appendAttribute
94− plural
95− (IsoXmlDescRecord genType generateLens fields)
96− (IsoXmlDescPreAttribute name ty) =
97− let xattribute = IsoXmlDescRecordAttribute $ IsoXmlDescAttribute plural name ty
98− in IsoXmlDescRecord genType generateLens (xattribute:fields)
102+appendAttribute plural (IsoXmlDescRecord genType fields) (IsoXmlDescPreAttribute name ty) =
103+ let xattribute = IsoXmlDescRecordAttribute $ IsoXmlDescAttribute plural name ty
104+ in IsoXmlDescRecord genType (xattribute:fields)
99105
100106appendContent
101107 :: IsoXmlDescRecord
102108 -> IsoXmlDescPreContent
103109 -> IsoXmlDescRecord
104−appendContent
105− (IsoXmlDescRecord genType generateLens fields)
106− (IsoXmlDescPreContent name ty) =
107− let xcontent = IsoXmlDescRecordContent $ IsoXmlDescContent name ty
108− in IsoXmlDescRecord genType generateLens (xcontent:fields)
110+appendContent (IsoXmlDescRecord genType fields) (IsoXmlDescPreContent name ty) =
111+ let xcontent = IsoXmlDescRecordContent $ IsoXmlDescContent name ty
112+ in IsoXmlDescRecord genType (xcontent:fields)
109113
110114(!), (?), (*), (+) :: IsoXmlDescRecord -> IsoXmlDescPreField -> IsoXmlDescRecord
111115(!) = appendField XmlFieldPluralMandatory
@@ -143,11 +147,11 @@ class Description name desc | desc -> name where
143147infix 0 =:=
144148
145149instance Description PrefixName IsoXmlDescRecord where
146− prefixName =:= (IsoXmlDescRecord genType generateLens descRecordParts) =
147− isoXmlGenerateDatatype genType generateLens prefixName (reverse descRecordParts)
150+ prefixName =:= (IsoXmlDescRecord genType descRecordParts) =
151+ isoXmlGenerateDatatype genType prefixName (reverse descRecordParts)
148152
149−record :: GenType -> GenerateLens -> IsoXmlDescRecord
150−record gt gl = IsoXmlDescRecord gt gl []
153+record :: GenType -> IsoXmlDescRecord
154+record gt = IsoXmlDescRecord gt []
151155
152156enum :: GenType -> IsoXmlDescEnum
153157enum gt = IsoXmlDescEnum gt []
@@ -156,7 +160,7 @@ instance Description ExhaustivenessName IsoXmlDescEnum where
156160 exhaustivenessName =:= (IsoXmlDescEnum genType descEnumCons) =
157161 isoXmlGenerateEnum genType exhaustivenessName (reverse descEnumCons)
158162
159−instance IsString (TH.TypeQ -> IsoXmlDescPreField) where
163+instance (m ~ Q) => IsString (m TH.Type -> IsoXmlDescPreField) where
160164 fromString = IsoXmlDescPreField
161165
162166instance IsString IsoXmlDescPreField where
@@ -164,10 +168,10 @@ instance IsString IsoXmlDescPreField where
164168 where
165169 ty = (TH.conT . TH.mkName) ("Xml" ++ over _head C.toUpper (xmlLocalName name))
166170
167−instance IsString (TH.TypeQ -> IsoXmlDescPreAttribute) where
171+instance (m ~ Q) => IsString (m TH.Type -> IsoXmlDescPreAttribute) where
168172 fromString = IsoXmlDescPreAttribute
169173
170−instance IsString (TH.TypeQ -> IsoXmlDescPreContent) where
174+instance (m ~ Q) => IsString (m Type -> IsoXmlDescPreContent) where
171175 fromString = IsoXmlDescPreContent
172176
173177instance IsString IsoXmlDescPreAttribute where
@@ -193,7 +197,7 @@ instance IsString ExhaustivenessName where
193197 fromString strName = ExhaustivenessName strName NonExhaustive
194198
195199makeNamePrefix :: String -> String
196−makeNamePrefix = map C.toLower . filter C.isUpper
200+makeNamePrefix = map C.toLower . filter (\c -> C.isUpper c || C.isDigit c)
197201
198202funSimple :: TH.Name -> TH.ExpQ -> TH.DecQ
199203funSimple name body = TH.funD name [ TH.clause [] (TH.normalB body) [] ]
@@ -221,11 +225,14 @@ isoXmlGenerateEnum genType (ExhaustivenessName strName' exh) enumCons = do
221225 (return [])
222226 [t|ToXmlAttribute $(TH.conT name)|]
223227 [funSimple 'toXmlAttribute [e|T.pack . show|]]
224− genFromDomInst = do
228+ genFromDomInst mode = do
225229 TH.instanceD
226230 (return [])
227231 [t|FromDom $(TH.conT name)|]
228− [funSimple 'fromDom [e|parseContent readContent|]]
232+ [case mode of
233+ Strict -> funSimple 'fromDom [e|parseContent readContent|]
234+ Lenient -> funSimple 'fromDom [e|ignoreBlank $ parseContent readContent|]
235+ ]
229236 genFromAttributeInst = do
230237 TH.instanceD
231238 (return [])
@@ -237,28 +244,30 @@ isoXmlGenerateEnum genType (ExhaustivenessName strName' exh) enumCons = do
237244 toXmlAttributeInst <- genToXmlAttributeInst
238245 return $ enumDecls ++ [toXmlInst, toXmlAttributeInst]
239246 Parser -> do
240− fromDomInst <- genFromDomInst
247+ fromDomInst <- genFromDomInst Strict
248+ fromAttributeInst <- genFromAttributeInst
249+ return $ enumDecls ++ [fromDomInst, fromAttributeInst]
250+ LenientParser -> do
251+ fromDomInst <- genFromDomInst Lenient
241252 fromAttributeInst <- genFromAttributeInst
242253 return $ enumDecls ++ [fromDomInst, fromAttributeInst]
243− Both -> do
254+ ParserAndGenerator -> do
255+ toXmlInst <- genToXmlInst
256+ toXmlAttributeInst <- genToXmlAttributeInst
257+ fromDomInst <- genFromDomInst Strict
258+ fromAttributeInst <- genFromAttributeInst
259+ return $ enumDecls ++ [toXmlInst, toXmlAttributeInst,
260+ fromDomInst, fromAttributeInst]
261+ LenientParserAndGenerator -> do
244262 toXmlInst <- genToXmlInst
245263 toXmlAttributeInst <- genToXmlAttributeInst
246− fromDomInst <- genFromDomInst
264+ fromDomInst <- genFromDomInst Lenient
247265 fromAttributeInst <- genFromAttributeInst
248266 return $ enumDecls ++ [toXmlInst, toXmlAttributeInst,
249267 fromDomInst, fromAttributeInst]
250268
251−isoXmlGenerateDatatype
252− :: GenType
253− -> GenerateLens
254− -> PrefixName
255− -> [IsoXmlDescRecordPart]
256− -> TH.DecsQ
257−isoXmlGenerateDatatype
258− genType
259− generateLens
260− (PrefixName strName' strPrefix')
261− descRecordParts = do
269+isoXmlGenerateDatatype :: GenType -> PrefixName -> [IsoXmlDescRecordPart] -> TH.DecsQ
270+isoXmlGenerateDatatype genType (PrefixName strName' strPrefix') descRecordParts = do
262271 let
263272 isNewtype = length descRecordParts == 1
264273 strName = "Xml" ++ strName'
@@ -275,11 +284,14 @@ isoXmlGenerateDatatype
275284 IsoXmlDescField fieldPlural rawName fieldType = descField
276285 fieldStrName = xmlLocalName rawName
277286 fName = TH.mkName (fieldName fieldStrName)
278− fType = case fieldPlural of
287+ fType' = case fieldPlural of
279288 XmlFieldPluralMandatory -> fieldType
280289 XmlFieldPluralOptional -> [t| Maybe $fieldType |]
281290 XmlFieldPluralRepeated -> [t| [$fieldType] |]
282291 XmlFieldPluralMultiplied -> [t| NonEmpty $fieldType |]
292+ fType = if isLenientType genType
293+ then [t| Maybe $fType' |]
294+ else fType'
283295 in if isNewtype
284296 then THC.varStrictType fName (THC.nonStrictType fType)
285297 else THC.varStrictType fName (THC.strictType fType)
@@ -314,7 +326,7 @@ isoXmlGenerateDatatype
314326 [ ]
315327
316328 let
317− genFromDomInst = do
329+ genFromDomInst mode = do
318330 let
319331 exprHeader = [e|pure $(TH.conE name)|]
320332 exprRecordParts = do
@@ -328,8 +340,9 @@ isoXmlGenerateDatatype
328340 fieldParse = case fieldPlural of
329341 XmlFieldPluralMandatory -> [e|inElem|]
330342 _ -> [e|inElemTrav|]
331− in
332− [e|$fieldParse $exprFieldStrName fromDom|]
343+ in case mode of
344+ Strict -> [e|$fieldParse $exprFieldStrName fromDom|]
345+ Lenient -> [e|$fieldParse $exprFieldStrName (ignoreBlank fromDom)|]
333346 IsoXmlDescRecordAttribute descAttribute ->
334347 let
335348 IsoXmlDescAttribute attributePlural attributeStrName _ = descAttribute
@@ -415,12 +428,21 @@ isoXmlGenerateDatatype
415428 return $ [termDecl] ++ lensDecls ++
416429 [toXmlInst, toXmlParentAttributesInst, nfDataInst]
417430 Parser -> do
418− fromDomInst <- genFromDomInst
431+ fromDomInst <- genFromDomInst Strict
432+ return $ [termDecl] ++ lensDecls ++ [fromDomInst, nfDataInst]
433+ LenientParser -> do
434+ fromDomInst <- genFromDomInst Lenient
419435 return $ [termDecl] ++ lensDecls ++ [fromDomInst, nfDataInst]
420− Both -> do
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
421443 toXmlInst <- genToXmlInst
422444 toXmlParentAttributesInst <- genToXmlParentAttributeInst
423− fromDomInst <- genFromDomInst
445+ fromDomInst <- genFromDomInst Lenient
424446 return $ [termDecl] ++ lensDecls ++
425447 [fromDomInst, toXmlInst, toXmlParentAttributesInst, nfDataInst]
426448