@@ -124,7 +124,7 @@ import Data.Aeson.Key (Key)
124
124
import qualified Data.Aeson.Key as Key
125
125
import qualified Data.Aeson.KeyMap as KM
126
126
import Data.Foldable (foldr' )
127
- import Data.List (genericLength , intercalate , partition , union )
127
+ import Data.List (genericLength , intercalate , union )
128
128
import Data.List.NonEmpty ((<|) , NonEmpty ((:|) ))
129
129
import Data.Map (Map )
130
130
import qualified Data.Monoid as Monoid
@@ -321,10 +321,11 @@ consToValue _ _ _ _ [] =
321
321
322
322
consToValue target jc opts instTys cons = autoletE liftSBS $ \ letInsert -> do
323
323
value <- newName " value"
324
+ os <- newNameList " _o" $ arityInt jc
324
325
tjs <- newNameList " _tj" $ arityInt jc
325
326
tjls <- newNameList " _tjl" $ arityInt jc
326
- let zippedTJs = zip tjs tjls
327
- interleavedTJs = interleave tjs tjls
327
+ let zippedTJs = zip3 os tjs tjls
328
+ interleavedTJs = flatten3 zippedTJs
328
329
lastTyVars = map varTToName $ drop (length instTys - arityInt jc) instTys
329
330
tvMap = M. fromList $ zip lastTyVars zippedTJs
330
331
lamE (map varP $ interleavedTJs ++ [value]) $
@@ -461,8 +462,10 @@ argsToValue letInsert target jc tvMap opts multiCons
461
462
toPair (arg, argTy, fld) =
462
463
let fieldName = fieldLabel opts fld
463
464
toValue = dispatchToJSON target jc conName tvMap argTy
465
+
466
+ omitFn :: Q Exp
464
467
omitFn
465
- | omitNothingFields opts = [ | omitField | ]
468
+ | omitNothingFields opts = dispatchOmitField jc conName tvMap argTy
466
469
| otherwise = [| const False | ]
467
470
in
468
471
[| \ f x arg' -> bool x mempty (f arg') | ]
@@ -653,10 +656,11 @@ consFromJSON _ _ _ _ [] =
653
656
654
657
consFromJSON jc tName opts instTys cons = do
655
658
value <- newName " value"
659
+ os <- newNameList " _o" $ arityInt jc
656
660
pjs <- newNameList " _pj" $ arityInt jc
657
661
pjls <- newNameList " _pjl" $ arityInt jc
658
- let zippedPJs = zip pjs pjls
659
- interleavedPJs = interleave pjs pjls
662
+ let zippedPJs = zip3 os pjs pjls
663
+ interleavedPJs = flatten3 zippedPJs
660
664
lastTyVars = map varTToName $ drop (length instTys - arityInt jc) instTys
661
665
tvMap = M. fromList $ zip lastTyVars zippedPJs
662
666
lamE (map varP $ interleavedPJs ++ [value]) $ lamExpr value tvMap
@@ -921,9 +925,11 @@ parseRecord jc tvMap argTys opts tName conName fields obj inTaggedObject =
921
925
(infixApp (conE conName) [| (<$>) | ] x)
922
926
xs
923
927
where
924
- defVal = case jc of
925
- JSONClass From Arity0 -> [| omittedField| ]
926
- _ -> [| Nothing | ]
928
+ lookupField :: Type -> Q Exp
929
+ lookupField argTy
930
+ | omitNothingFields opts = [| lookupFieldOmit | ] `appE` dispatchOmittedField jc conName tvMap argTy
931
+ | otherwise = [| lookupFieldNoOmit | ]
932
+
927
933
tagFieldNameAppender =
928
934
if inTaggedObject then (tagFieldName (sumEncoding opts) : ) else id
929
935
knownFields = appE [| KM. fromList| ] $ listE $
@@ -940,8 +946,7 @@ parseRecord jc tvMap argTys opts tName conName fields obj inTaggedObject =
940
946
(appE [| show | ] (varE unknownFields)))
941
947
[]
942
948
]
943
- x: xs = [ [| lookupField| ]
944
- `appE` defVal
949
+ x: xs = [ lookupField argTy
945
950
`appE` dispatchParseJSON jc conName tvMap argTy
946
951
`appE` litE (stringL $ show tName)
947
952
`appE` litE (stringL $ constructorTagModifier opts $ nameBase conName)
@@ -1109,16 +1114,21 @@ parseTypeMismatch tName conName expected actual =
1109
1114
, actual
1110
1115
]
1111
1116
1112
- lookupField :: Maybe a -> (Value -> Parser a ) -> String -> String
1113
- -> Object -> Key -> Parser a
1114
- lookupField maybeDefault pj tName rec obj key =
1117
+ lookupFieldOmit :: Maybe a -> (Value -> Parser a ) -> String -> String -> Object -> Key -> Parser a
1118
+ lookupFieldOmit maybeDefault pj tName rec obj key =
1115
1119
case KM. lookup key obj of
1116
1120
Nothing ->
1117
1121
case maybeDefault of
1118
1122
Nothing -> unknownFieldFail tName rec (Key. toString key)
1119
1123
Just x -> pure x
1120
1124
Just v -> pj v <?> Key key
1121
1125
1126
+ lookupFieldNoOmit :: (Value -> Parser a ) -> String -> String -> Object -> Key -> Parser a
1127
+ lookupFieldNoOmit pj tName rec obj key =
1128
+ case KM. lookup key obj of
1129
+ Nothing -> unknownFieldFail tName rec (Key. toString key)
1130
+ Just v -> pj v <?> Key key
1131
+
1122
1132
unknownFieldFail :: String -> String -> String -> Parser fail
1123
1133
unknownFieldFail tName rec key =
1124
1134
fail $ printf " When parsing the record %s of type %s the key %s was not present."
@@ -1245,20 +1255,26 @@ mkFunCommon consFun jc opts name = do
1245
1255
! _ <- buildTypeInstance parentName jc ctxt instTys variant
1246
1256
consFun jc parentName opts instTys cons
1247
1257
1258
+ data FunArg = Omit | Single | Plural
1259
+
1248
1260
dispatchFunByType :: JSONClass
1249
1261
-> JSONFun
1250
1262
-> Name
1251
1263
-> TyVarMap
1252
- -> Bool -- True if we are using the function argument that works
1253
- -- on lists (e.g., [a] -> Value). False is we are using
1254
- -- the function argument that works on single values
1255
- -- (e.g., a -> Value).
1264
+ -> FunArg -- Plural if we are using the function argument that works
1265
+ -- on lists (e.g., [a] -> Value). Single is we are using
1266
+ -- the function argument that works on single values
1267
+ -- (e.g., a -> Value). Omit if we use it to check omission
1268
+ -- (e.g. a -> Bool)
1256
1269
-> Type
1257
1270
-> Q Exp
1258
1271
dispatchFunByType _ jf _ tvMap list (VarT tyName) =
1259
1272
varE $ case M. lookup tyName tvMap of
1260
- Just (tfjExp, tfjlExp) -> if list then tfjlExp else tfjExp
1261
- Nothing -> jsonFunValOrListName list jf Arity0
1273
+ Just (tfjoExp, tfjExp, tfjlExp) -> case list of
1274
+ Omit -> tfjoExp
1275
+ Single -> tfjExp
1276
+ Plural -> tfjlExp
1277
+ Nothing -> jsonFunValOrListName list jf Arity0
1262
1278
dispatchFunByType jc jf conName tvMap list (SigT ty _) =
1263
1279
dispatchFunByType jc jf conName tvMap list ty
1264
1280
dispatchFunByType jc jf conName tvMap list (ForallT _ _ ty) =
@@ -1283,18 +1299,21 @@ dispatchFunByType jc jf conName tvMap list ty = do
1283
1299
else if any (`mentionsName` tyVarNames) rhsArgs
1284
1300
then appsE $ varE (jsonFunValOrListName list jf $ toEnum numLastArgs)
1285
1301
: zipWith (dispatchFunByType jc jf conName tvMap)
1286
- (cycle [False , True ])
1287
- (interleave rhsArgs rhsArgs)
1302
+ (cycle [Omit , Single , Plural ])
1303
+ (triple rhsArgs)
1288
1304
else varE $ jsonFunValOrListName list jf Arity0
1289
1305
1290
- dispatchToJSON
1291
- :: ToJSONFun -> JSONClass -> Name -> TyVarMap -> Type -> Q Exp
1292
- dispatchToJSON target jc n tvMap =
1293
- dispatchFunByType jc (targetToJSONFun target) n tvMap False
1306
+ dispatchToJSON :: ToJSONFun -> JSONClass -> Name -> TyVarMap -> Type -> Q Exp
1307
+ dispatchToJSON target jc n tvMap = dispatchFunByType jc (targetToJSONFun target) n tvMap Single
1308
+
1309
+ dispatchOmitField :: JSONClass -> Name -> TyVarMap -> Type -> Q Exp
1310
+ dispatchOmitField jc n tvMap = dispatchFunByType jc ToJSON n tvMap Omit
1311
+
1312
+ dispatchParseJSON :: JSONClass -> Name -> TyVarMap -> Type -> Q Exp
1313
+ dispatchParseJSON jc n tvMap = dispatchFunByType jc ParseJSON n tvMap Single
1294
1314
1295
- dispatchParseJSON
1296
- :: JSONClass -> Name -> TyVarMap -> Type -> Q Exp
1297
- dispatchParseJSON jc n tvMap = dispatchFunByType jc ParseJSON n tvMap False
1315
+ dispatchOmittedField :: JSONClass -> Name -> TyVarMap -> Type -> Q Exp
1316
+ dispatchOmittedField jc n tvMap = dispatchFunByType jc ParseJSON n tvMap Omit
1298
1317
1299
1318
--------------------------------------------------------------------------------
1300
1319
-- Utility functions
@@ -1565,13 +1584,14 @@ Both.
1565
1584
-- A mapping of type variable Names to their encoding/decoding function Names.
1566
1585
-- For example, in a ToJSON2 declaration, a TyVarMap might look like
1567
1586
--
1568
- -- { a ~> (tj1, tjl1)
1569
- -- , b ~> (tj2, tjl2) }
1587
+ -- { a ~> (o1, tj1, tjl1)
1588
+ -- , b ~> (o2, tj2, tjl2) }
1570
1589
--
1571
- -- where a and b are the last two type variables of the datatype, tj1 and tjl1 are
1572
- -- the function arguments of types (a -> Value) and ([a] -> Value), and tj2 and tjl2
1573
- -- are the function arguments of types (b -> Value) and ([b] -> Value).
1574
- type TyVarMap = Map Name (Name , Name )
1590
+ -- where a and b are the last two type variables of the datatype,
1591
+ -- o1 and o2 are function argument of types (a -> Bool),
1592
+ -- tj1 and tjl1 are the function arguments of types (a -> Value)
1593
+ -- and ([a] -> Value), and tj2 and tjl2 are the function arguments of types (b -> Value) and ([b] -> Value).
1594
+ type TyVarMap = Map Name (Name , Name , Name )
1575
1595
1576
1596
-- | Returns True if a Type has kind *.
1577
1597
hasKindStar :: Type -> Bool
@@ -1616,9 +1636,11 @@ varTToNameMaybe _ = Nothing
1616
1636
varTToName :: Type -> Name
1617
1637
varTToName = fromMaybe (error " Not a type variable!" ) . varTToNameMaybe
1618
1638
1619
- interleave :: [a ] -> [a ] -> [a ]
1620
- interleave (a1: a1s) (a2: a2s) = a1: a2: interleave a1s a2s
1621
- interleave _ _ = []
1639
+ flatten3 :: [(a ,a ,a )] -> [a ]
1640
+ flatten3 = foldr (\ (a,b,c) xs -> a: b: c: xs) []
1641
+
1642
+ triple :: [a ] -> [a ]
1643
+ triple = foldr (\ x xs -> x: x: x: xs) []
1622
1644
1623
1645
-- | Fully applies a type constructor to its type variables.
1624
1646
applyTyCon :: Name -> [Type ] -> Type
@@ -1909,6 +1931,17 @@ jsonClassName (JSONClass From Arity0) = ''FromJSON
1909
1931
jsonClassName (JSONClass From Arity1 ) = ''FromJSON1
1910
1932
jsonClassName (JSONClass From Arity2 ) = ''FromJSON2
1911
1933
1934
+ jsonFunOmitName :: JSONFun -> Arity -> Name
1935
+ jsonFunOmitName ToJSON Arity0 = 'omitField
1936
+ jsonFunOmitName ToJSON Arity1 = 'liftOmitField
1937
+ jsonFunOmitName ToJSON Arity2 = 'liftOmitField2
1938
+ jsonFunOmitName ToEncoding Arity0 = 'omitField
1939
+ jsonFunOmitName ToEncoding Arity1 = 'liftOmitField
1940
+ jsonFunOmitName ToEncoding Arity2 = 'liftOmitField2
1941
+ jsonFunOmitName ParseJSON Arity0 = 'omittedField
1942
+ jsonFunOmitName ParseJSON Arity1 = 'liftOmittedField
1943
+ jsonFunOmitName ParseJSON Arity2 = 'liftOmittedField2
1944
+
1912
1945
jsonFunValName :: JSONFun -> Arity -> Name
1913
1946
jsonFunValName ToJSON Arity0 = 'toJSON
1914
1947
jsonFunValName ToJSON Arity1 = 'liftToJSON
@@ -1931,10 +1964,11 @@ jsonFunListName ParseJSON Arity0 = 'parseJSONList
1931
1964
jsonFunListName ParseJSON Arity1 = 'liftParseJSONList
1932
1965
jsonFunListName ParseJSON Arity2 = 'liftParseJSONList2
1933
1966
1934
- jsonFunValOrListName :: Bool -- e.g., toJSONList if True, toJSON if False
1967
+ jsonFunValOrListName :: FunArg -- e.g., toJSONList if True, toJSON if False
1935
1968
-> JSONFun -> Arity -> Name
1936
- jsonFunValOrListName False = jsonFunValName
1937
- jsonFunValOrListName True = jsonFunListName
1969
+ jsonFunValOrListName Omit = jsonFunOmitName
1970
+ jsonFunValOrListName Single = jsonFunValName
1971
+ jsonFunValOrListName Plural = jsonFunListName
1938
1972
1939
1973
arityInt :: JSONClass -> Int
1940
1974
arityInt = fromEnum . arity
0 commit comments