on master help sign in
1054 files changed+73254−3895
since splitsnapshots
unifiedsplit
.gitattributes+1 .gitignore+11 .hlint.yaml+11 .travis.yml+43−16 CONTRIBUTING.md+98 Data/Aeson.hs+87−14 Data/Aeson/Encode.hs+5−2 Data/Aeson/Encoding.hs+12−1 Data/Aeson/Encoding/Builder.hs+23−20 Data/Aeson/Encoding/Internal.hs+110−83 Data/Aeson/Internal.hs+2 Data/Aeson/Internal/Functions.hs+5−1 Data/Aeson/Internal/Time.hs+1−38 Data/Aeson/Parser.hs+14−5 Data/Aeson/Parser/Internal.hs+325−198 Data/Aeson/Parser/Time.hs+21−104 Data/Aeson/Parser/Unescape.hs+11 Data/Aeson/QQ/Simple.hs+25 Data/Aeson/TH.hs+522−962 Data/Aeson/Text.hs+12−7 Data/Aeson/Types.hs+55−7 Data/Aeson/Types/Class.hs+30−9 Data/Aeson/Types/FromJSON.hs+1346−555 Data/Aeson/Types/Generic.hs+35−22 Data/Aeson/Types/Internal.hs+195−32 Data/Aeson/Types/ToJSON.hs+1184−790 Makefile+2 README.markdown+3−4 aeson.cabal+136−61 attoparsec-iso8601/Data/Attoparsec/Time.hs+148 attoparsec-iso8601/Data/Attoparsec/Time/Internal.hs+64 attoparsec-iso8601/LICENSE+30 attoparsec-iso8601/README.md+19 attoparsec-iso8601/attoparsec-iso8601.cabal+55 attoparsec-iso8601/changelog.md+5 benchmarks/AesonCompareAutoInstances.hs−231 benchmarks/AesonEncode.hs+12−6 benchmarks/AesonFoldable.hs+86 benchmarks/AesonMap.hs+28−17 benchmarks/AesonParse.hs+9−4 benchmarks/AesonTuples.hs+5−3 benchmarks/Auto/G/BigProduct.hs+33 benchmarks/Auto/G/BigRecord.hs+33 benchmarks/Auto/G/BigSum.hs+28 benchmarks/Auto/G/D.hs+44 benchmarks/Auto/T/BigProduct.hs+27 benchmarks/Auto/T/BigRecord.hs+27 benchmarks/Auto/T/BigSum.hs+22 benchmarks/Auto/T/D.hs+38 benchmarks/AutoCompare.hs+73 benchmarks/Compare.hs+12−3 benchmarks/Compare/BufferBuilder.hs+9−4 benchmarks/Compare/JsonBench.hs+21−7 benchmarks/Compare/JsonBuilder.hs+6−2 benchmarks/CompareWithJSON.hs+38−21 benchmarks/Dates.hs+14−9 benchmarks/Escape.hs+32 benchmarks/Issue673.hs+165 benchmarks/JsonParse.hs+10−3 benchmarks/Micro.hs+10−6 benchmarks/Options.hs+1−1 benchmarks/ReadFile.hs+8−2 benchmarks/Typed.hs+7 benchmarks/Typed/Common.hs+9−3 benchmarks/Typed/Generic.hs+23−8 benchmarks/Typed/Manual.hs+22−7 benchmarks/Typed/TH.hs+22−7 benchmarks/aeson-benchmarks.cabal+226−60 cabal.project+5 cbits/unescape_string.c+149 changelog.md+312−19 examples/Generic.hs+7−5 examples/Simplest.hs+8−2 examples/TemplateHaskell.hs+6−3 examples/Twitter.hs+12−6 examples/Twitter/Generic.hs+27−9 examples/Twitter/Manual.hs+11−6 examples/Twitter/Options.hs+10 examples/Twitter/TH.hs+10−5 examples/aeson-examples.cabal+3 ffi/Data/Aeson/Parser/UnescapeFFI.hs+52 include/incoherent-compat.h+7 include/overlapping-compat.h−7 pure/Data/Aeson/Parser/UnescapePure.hs+254 run-hlint.sh+7 stack-bench.yaml+12 stack-ffi-unescape.yaml+9 stack-lts12.yaml+15 stack-nightly.yaml+11 stack.yaml−7 tests/DataFamilies/Encoders.hs+5−2 tests/DataFamilies/Instances.hs+6−3 tests/DataFamilies/Properties.hs+7−4 tests/DataFamilies/Types.hs+8−3 tests/Encoders.hs+232−7 tests/ErrorMessages.hs+224 tests/Functions.hs+9−1 tests/Instances.hs+38−53 tests/JSONTestSuite/LICENSE+21 tests/JSONTestSuite/README.md+50 tests/JSONTestSuite/parsers/test-AppleJSONSerialization/bin/test-AppleJSONSerialization tests/JSONTestSuite/parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/project.pbxproj+260 tests/JSONTestSuite/parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test-AppleJSONSerialization.xcscheme+91 tests/JSONTestSuite/parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test-AppleJSONSerialization/test-AppleJSONSerialization/main.swift+34 tests/JSONTestSuite/parsers/test_Bash_JSON/JSON.sh+208 tests/JSONTestSuite/parsers/test_Freddy_20160830/bin/test_Freddy tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy.xcodeproj/project.pbxproj+300 tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy.xcodeproj/project.xcworkspace/xcshareddata/test_Freddy.xcscmblueprint+30 tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_Freddy.xcscheme+91 tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSON.swift+95 tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSONDecodable.swift+177 tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSONEncodable.swift+83 tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSONEncodingDetector.swift+110 tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSONLiteralConvertible.swift+130 tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSONParser.swift+907 tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSONParsing.swift+126 tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSONSerializing.swift+43 tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSONSubscripting.swift+705 tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/main.swift+37 tests/JSONTestSuite/parsers/test_Freddy_20161018/bin/test_Freddy tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy.xcodeproj/project.pbxproj+300 tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy.xcodeproj/project.xcworkspace/xcshareddata/test_Freddy.xcscmblueprint+30 tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_Freddy.xcscheme+91 tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSON.swift+98 tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONDecodable.swift+186 tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONEncodable.swift+83 tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONEncodingDetector.swift+110 tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONLiteralConvertible.swift+134 tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONParser.swift+918 tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONParsing.swift+126 tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONSerializing.swift+54 tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONSubscripting.swift+613 tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/main.swift+40 tests/JSONTestSuite/parsers/test_Freddy_2_1_0/bin/test_Freddy_2_1_0 tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/project.pbxproj+300 tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/project.xcworkspace/xcshareddata/test_Freddy.xcscmblueprint+30 tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_Freddy.xcscheme+91 tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSON.swift+95 tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSONDecodable.swift+151 tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSONEncodable.swift+83 tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSONEncodingDetector.swift+110 tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSONLiteralConvertible.swift+130 tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSONParser.swift+903 tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSONParsing.swift+126 tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSONSerializing.swift+43 tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSONSubscripting.swift+643 tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/main.swift+37 tests/JSONTestSuite/parsers/test_JSONKit/JSONKit.h+251 tests/JSONTestSuite/parsers/test_JSONKit/JSONKit.m+3065 tests/JSONTestSuite/parsers/test_JSONKit/bin/test-JSONKit tests/JSONTestSuite/parsers/test_JSONKit/test-JSONKit.xcodeproj/project.pbxproj+252 tests/JSONTestSuite/parsers/test_JSONKit/test-JSONKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_JSONKit/test-JSONKit.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_JSONKit/test-JSONKit.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test-JSONKit.xcscheme+91 tests/JSONTestSuite/parsers/test_JSONKit/test-JSONKit.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test_JSONKit/test-JSONKit/main.m+73 tests/JSONTestSuite/parsers/test_Json.NET/Program.cs+46 tests/JSONTestSuite/parsers/test_Json.NET/bin/Release/netcoreapp1.0/publish/Newtonsoft.Json.dll tests/JSONTestSuite/parsers/test_Json.NET/bin/Release/netcoreapp1.0/publish/System.Runtime.Serialization.Primitives.dll tests/JSONTestSuite/parsers/test_Json.NET/bin/Release/netcoreapp1.0/publish/test_Json.NET.deps.json+49 tests/JSONTestSuite/parsers/test_Json.NET/bin/Release/netcoreapp1.0/publish/test_Json.NET.dll tests/JSONTestSuite/parsers/test_Json.NET/bin/Release/netcoreapp1.0/publish/test_Json.NET.pdb tests/JSONTestSuite/parsers/test_Json.NET/bin/Release/netcoreapp1.0/publish/test_Json.NET.runtimeconfig.json+8 tests/JSONTestSuite/parsers/test_Json.NET/project.json+21 tests/JSONTestSuite/parsers/test_Json.NET/project.lock.json+6741 tests/JSONTestSuite/parsers/test_Lua_JSON/JSON.lua+1451 tests/JSONTestSuite/parsers/test_Lua_JSON/test_JSON.lua+22 tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/bin/test_ObjCNSJSONSerializer tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/project.pbxproj+246 tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_ObjCNSJSONSerializer.xcscheme+97 tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/a.out tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/a.out.dSYM/Contents/Info.plist+20 tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/a.out.dSYM/Contents/Resources/DWARF/a.out tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/findings_dir/plot_data+1 tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/main.m+32 tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/Accessors.swift+255 tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/DecimalNumber.swift+236 tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/Decoder.swift+294 tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/Encoder.swift+167 tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/JSON.swift+170 tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/JSONError.swift+1619 tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/JSONObject.swift+215 tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/ObjectiveC.swift+233 tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/Parser.swift+674 tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/bin/test_PMJSON tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/test_PMJSON.xcodeproj/project.pbxproj+296 tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/test_PMJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/test_PMJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/test_PMJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_PMJSON.xcscheme+97 tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/test_PMJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/test_PMJSON/main.swift+46 tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/Accessors.swift+255 tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/DecimalNumber.swift+236 tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/Decoder.swift+502 tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/Encoder.swift+215 tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/JSON.swift+170 tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/JSONError.swift+1619 tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/JSONObject.swift+215 tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/ObjectiveC.swift+331 tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/Parser.swift+745 tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/bin/test_PMJSON tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/test_PMJSON.xcodeproj/project.pbxproj+296 tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/test_PMJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/test_PMJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/test_PMJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_PMJSON.xcscheme+97 tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/test_PMJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/test_PMJSON/main.swift+46 tests/JSONTestSuite/parsers/test_SBJSON/SBJson4.h+35 tests/JSONTestSuite/parsers/test_SBJSON/SBJson4Parser.h+248 tests/JSONTestSuite/parsers/test_SBJSON/SBJson4Parser.m+287 tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamParser.h+131 tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamParser.m+317 tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamParserState.h+82 tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamParserState.m+355 tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamTokeniser.h+40 tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamTokeniser.m+395 tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamWriter.h+210 tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamWriter.m+358 tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamWriterState.h+69 tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamWriterState.m+147 tests/JSONTestSuite/parsers/test_SBJSON/SBJson4Writer.h+103 tests/JSONTestSuite/parsers/test_SBJSON/SBJson4Writer.m+102 tests/JSONTestSuite/parsers/test_SBJSON/bin/test_SBJSON tests/JSONTestSuite/parsers/test_SBJSON/test_SBJSON.xcodeproj/project.pbxproj+290 tests/JSONTestSuite/parsers/test_SBJSON/test_SBJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_SBJSON/test_SBJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_SBJSON/test_SBJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist+5 tests/JSONTestSuite/parsers/test_SBJSON/test_SBJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_SBJSON.xcscheme+91 tests/JSONTestSuite/parsers/test_SBJSON/test_SBJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test_SBJSON/test_SBJSON/main.m+38 tests/JSONTestSuite/parsers/test_STJSON/STJSON.xcodeproj/project.pbxproj+361 tests/JSONTestSuite/parsers/test_STJSON/STJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_STJSON/STJSON.xcodeproj/project.xcworkspace/xcshareddata/STJSON.xcscmblueprint+30 tests/JSONTestSuite/parsers/test_STJSON/STJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_STJSON/STJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/STJSON.xcscheme+91 tests/JSONTestSuite/parsers/test_STJSON/STJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/STJSONTests.xcscheme+56 tests/JSONTestSuite/parsers/test_STJSON/STJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+32 tests/JSONTestSuite/parsers/test_STJSON/STJSON/STJSONParser.swift+663 tests/JSONTestSuite/parsers/test_STJSON/STJSON/main.swift+47 tests/JSONTestSuite/parsers/test_STJSON/STJSONTests/Info.plist+22 tests/JSONTestSuite/parsers/test_STJSON/STJSONTests/STJSONTests.swift+92 tests/JSONTestSuite/parsers/test_STJSON/bin/STJSON tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Info.plist+563 tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/MacOS/Squeak tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/English.lproj/Localizable.strings+9 tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/English.lproj/MainMenu.nib tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/Squeak.icns tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/SqueakChanges.icns tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/SqueakGeneric.icns tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/SqueakImage.icns tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/SqueakPlugin.icns tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/SqueakProject.icns tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/SqueakScript.icns tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/SqueakSources.icns tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak5.1-16549-32bit.image tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/test_JSON.st+9 tests/JSONTestSuite/parsers/test_TouchJSON/bin/test_TouchJSON tests/JSONTestSuite/parsers/test_TouchJSON/test_TouchJSON.xcodeproj/project.pbxproj+262 tests/JSONTestSuite/parsers/test_TouchJSON/test_TouchJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_TouchJSON/test_TouchJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_TouchJSON/test_TouchJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_TouchJSON.xcscheme+97 tests/JSONTestSuite/parsers/test_TouchJSON/test_TouchJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test_TouchJSON/test_TouchJSON/CJSONDeserializer.h+96 tests/JSONTestSuite/parsers/test_TouchJSON/test_TouchJSON/CJSONDeserializer.m+1240 tests/JSONTestSuite/parsers/test_TouchJSON/test_TouchJSON/main.m+25 tests/JSONTestSuite/parsers/test_cJSON/bin/test-cJSON tests/JSONTestSuite/parsers/test_cJSON/cJSON.c+754 tests/JSONTestSuite/parsers/test_cJSON/cJSON.h+153 tests/JSONTestSuite/parsers/test_cJSON/test-cJSON.xcodeproj/project.pbxproj+257 tests/JSONTestSuite/parsers/test_cJSON/test-cJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_cJSON/test-cJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_cJSON/test-cJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist+5 tests/JSONTestSuite/parsers/test_cJSON/test-cJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test-cJSON.xcscheme+91 tests/JSONTestSuite/parsers/test_cJSON/test-cJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test_cJSON/test-cJSON/main.c+69 tests/JSONTestSuite/parsers/test_ccan_json/bin/test_ccan tests/JSONTestSuite/parsers/test_ccan_json/json/_test/common.h+18 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_10.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_101.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_11.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_12.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_125.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_127.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_13.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_136.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_137.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_139.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_14.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_140.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_145.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_147.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_149.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_15.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_150.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_151.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_153.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_154.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_155.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_156.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_157.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_158.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_159.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_16.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_160.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_161.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_162.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_163.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_164.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_165.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_169.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_17.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_171.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_172.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_173.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_175.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_176.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_177.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_178.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_179.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_18.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_180.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_181.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_183.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_184.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_185.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_186.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_187.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_188.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_189.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_19.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_190.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_191.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_192.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_193.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_194.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_195.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_197.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_198.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_199.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_2.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_20.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_200.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_201.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_202.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_203.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_204.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_205.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_206.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_207.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_208.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_209.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_21.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_210.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_211.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_212.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_213.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_214.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_216.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_217.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_218.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_219.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_22.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_220.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_221.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_222.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_223.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_23.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_24.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_25.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_26.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_27.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_28.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_29.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_3.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_30.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_31.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_32.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_33.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_34.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_35.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_36.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_37.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_4.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_40.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_44.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_46.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_5.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_54.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_55.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_59.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_6.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_63.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_64.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_66.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_69.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_7.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_77.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_78.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_79.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_8.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_80.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_81.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_82.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_83.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_85.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_86.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_87.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_9.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_91.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_100.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_102.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_103.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_104.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_105.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_106.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_107.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_108.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_109.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_110.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_111.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_112.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_113.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_114.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_115.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_116.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_117.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_118.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_119.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_120.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_121.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_122.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_123.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_124.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_126.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_128.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_129.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_130.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_131.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_132.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_133.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_134.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_135.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_138.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_141.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_142.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_143.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_144.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_146.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_148.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_152.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_166.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_167.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_168.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_170.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_174.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_182.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_196.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_215.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_38.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_39.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_41.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_42.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_43.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_45.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_47.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_48.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_49.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_50.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_51.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_52.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_53.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_56.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_57.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_58.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_60.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_61.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_62.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_65.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_67.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_68.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_70.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_71.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_72.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_73.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_74.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_75.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_76.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_84.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_88.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_89.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_90.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_92.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_93.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_94.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_95.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_96.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_97.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_98.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_99.json+1 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/run-construction.c+191 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/run-decode-encode.c+77 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/run-stringify.c+108 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/run-validate.c+49 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/test-strings+224 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/test-strings-reencoded+90 tests/JSONTestSuite/parsers/test_ccan_json/json/_test/x.py+21 tests/JSONTestSuite/parsers/test_ccan_json/json/json.c+1381 tests/JSONTestSuite/parsers/test_ccan_json/json/json.h+117 tests/JSONTestSuite/parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/project.pbxproj+262 tests/JSONTestSuite/parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_ccan.xcscheme+91 tests/JSONTestSuite/parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test_ccan_json/test_ccan/test_ccan/main.c+44 tests/JSONTestSuite/parsers/test_dkjson.lua+25 tests/JSONTestSuite/parsers/test_go/test_json tests/JSONTestSuite/parsers/test_go/test_json.go+30 tests/JSONTestSuite/parsers/test_haskell-aeson/.gitignore+1 tests/JSONTestSuite/parsers/test_haskell-aeson/package.yaml+12 tests/JSONTestSuite/parsers/test_haskell-aeson/src/Main.hs+29 tests/JSONTestSuite/parsers/test_haskell-aeson/stack.yaml+1 tests/JSONTestSuite/parsers/test_haskell-aeson/testaeson+8 tests/JSONTestSuite/parsers/test_haskell-aeson/testaeson.cabal+21 tests/JSONTestSuite/parsers/test_jansson/bin/test_jansson tests/JSONTestSuite/parsers/test_jansson/dump.c+467 tests/JSONTestSuite/parsers/test_jansson/error.c+63 tests/JSONTestSuite/parsers/test_jansson/hashtable.c+356 tests/JSONTestSuite/parsers/test_jansson/hashtable.h+184 tests/JSONTestSuite/parsers/test_jansson/hashtable_seed.c+277 tests/JSONTestSuite/parsers/test_jansson/jansson.h+298 tests/JSONTestSuite/parsers/test_jansson/jansson_config.h+43 tests/JSONTestSuite/parsers/test_jansson/jansson_private.h+109 tests/JSONTestSuite/parsers/test_jansson/load.c+1110 tests/JSONTestSuite/parsers/test_jansson/lookup3.h+381 tests/JSONTestSuite/parsers/test_jansson/memory.c+69 tests/JSONTestSuite/parsers/test_jansson/pack_unpack.c+871 tests/JSONTestSuite/parsers/test_jansson/strbuffer.c+111 tests/JSONTestSuite/parsers/test_jansson/strbuffer.h+34 tests/JSONTestSuite/parsers/test_jansson/strconv.c+145 tests/JSONTestSuite/parsers/test_jansson/test_jansson.xcodeproj/project.pbxproj+309 tests/JSONTestSuite/parsers/test_jansson/test_jansson.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_jansson/test_jansson.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_jansson/test_jansson.xcodeproj/xcuserdata/nst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist+5 tests/JSONTestSuite/parsers/test_jansson/test_jansson.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_jansson.xcscheme+91 tests/JSONTestSuite/parsers/test_jansson/test_jansson.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test_jansson/test_jansson/main.c+208 tests/JSONTestSuite/parsers/test_jansson/utf.c+187 tests/JSONTestSuite/parsers/test_jansson/utf.h+27 tests/JSONTestSuite/parsers/test_jansson/value.c+1048 tests/JSONTestSuite/parsers/test_java_com_leastfixedpoint_json_1_0/META-INF/MANIFEST.MF+3 tests/JSONTestSuite/parsers/test_java_com_leastfixedpoint_json_1_0/README.txt+5 tests/JSONTestSuite/parsers/test_java_com_leastfixedpoint_json_1_0/TestJSONParsing.class tests/JSONTestSuite/parsers/test_java_com_leastfixedpoint_json_1_0/TestJSONParsing.jar tests/JSONTestSuite/parsers/test_java_com_leastfixedpoint_json_1_0/TestJSONParsing.java+40 tests/JSONTestSuite/parsers/test_java_com_leastfixedpoint_json_1_0/com.leastfixedpoint.json-1.0.jar tests/JSONTestSuite/parsers/test_java_gson_2_7/META-INF/MANIFEST.MF+3 tests/JSONTestSuite/parsers/test_java_gson_2_7/README.txt+5 tests/JSONTestSuite/parsers/test_java_gson_2_7/TestJSONParsing.class tests/JSONTestSuite/parsers/test_java_gson_2_7/TestJSONParsing.jar tests/JSONTestSuite/parsers/test_java_gson_2_7/TestJSONParsing.java+51 tests/JSONTestSuite/parsers/test_java_gson_2_7/gson-2.7.jar tests/JSONTestSuite/parsers/test_java_jackson_2_8_4/META-INF/MANIFEST.MF+3 tests/JSONTestSuite/parsers/test_java_jackson_2_8_4/README.txt+5 tests/JSONTestSuite/parsers/test_java_jackson_2_8_4/TestJSONParsing.class tests/JSONTestSuite/parsers/test_java_jackson_2_8_4/TestJSONParsing.jar tests/JSONTestSuite/parsers/test_java_jackson_2_8_4/TestJSONParsing.java+48 tests/JSONTestSuite/parsers/test_java_jackson_2_8_4/jackson-annotations-2.2.3.jar tests/JSONTestSuite/parsers/test_java_jackson_2_8_4/jackson-core-2.8.4.jar tests/JSONTestSuite/parsers/test_java_jackson_2_8_4/jackson-databind-2.3.1.jar tests/JSONTestSuite/parsers/test_java_nanojson_1_0/META-INF/MANIFEST.MF+3 tests/JSONTestSuite/parsers/test_java_nanojson_1_0/README.txt+5 tests/JSONTestSuite/parsers/test_java_nanojson_1_0/TestJSONParsing.class tests/JSONTestSuite/parsers/test_java_nanojson_1_0/TestJSONParsing.jar tests/JSONTestSuite/parsers/test_java_nanojson_1_0/TestJSONParsing.java+45 tests/JSONTestSuite/parsers/test_java_nanojson_1_0/nanojson-1.0.jar tests/JSONTestSuite/parsers/test_java_simple_json_1_1_1/META-INF/MANIFEST.MF+3 tests/JSONTestSuite/parsers/test_java_simple_json_1_1_1/README.txt+3 tests/JSONTestSuite/parsers/test_java_simple_json_1_1_1/TestJSONParsing.class tests/JSONTestSuite/parsers/test_java_simple_json_1_1_1/TestJSONParsing.jar tests/JSONTestSuite/parsers/test_java_simple_json_1_1_1/TestJSONParsing.java+43 tests/JSONTestSuite/parsers/test_java_simple_json_1_1_1/json-simple-1.1.1.jar tests/JSONTestSuite/parsers/test_jsmn/bin/test_jsmn tests/JSONTestSuite/parsers/test_jsmn/jsmn.c+311 tests/JSONTestSuite/parsers/test_jsmn/jsmn.h+76 tests/JSONTestSuite/parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/project.pbxproj+253 tests/JSONTestSuite/parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/xcuserdata/nst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist+23 tests/JSONTestSuite/parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_jsmn.xcscheme+101 tests/JSONTestSuite/parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test_jsmn/test_jsmn/test_jsmn/main.c+50 tests/JSONTestSuite/parsers/test_json-jq.py+34 tests/JSONTestSuite/parsers/test_json-parser/bin/test_json-parser tests/JSONTestSuite/parsers/test_json-parser/test_json-parser.xcodeproj/project.pbxproj+258 tests/JSONTestSuite/parsers/test_json-parser/test_json-parser.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_json-parser/test_json-parser.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_json-parser/test_json-parser.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_json-parser.xcscheme+91 tests/JSONTestSuite/parsers/test_json-parser/test_json-parser.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test_json-parser/test_json-parser/json.c+1011 tests/JSONTestSuite/parsers/test_json-parser/test_json-parser/json.h+283 tests/JSONTestSuite/parsers/test_json-parser/test_json-parser/main.c+66 tests/JSONTestSuite/parsers/test_json-rust-serde_json/rj/.gitignore+2 tests/JSONTestSuite/parsers/test_json-rust-serde_json/rj/Cargo.toml+7 tests/JSONTestSuite/parsers/test_json-rust-serde_json/rj/README+2 tests/JSONTestSuite/parsers/test_json-rust-serde_json/rj/src/main.rs+30 tests/JSONTestSuite/parsers/test_json-rust/Cargo.lock+14 tests/JSONTestSuite/parsers/test_json-rust/Cargo.toml+7 tests/JSONTestSuite/parsers/test_json-rust/README+2 tests/JSONTestSuite/parsers/test_json-rust/src/main.rs+42 tests/JSONTestSuite/parsers/test_json-rust/target/debug/.cargo-lock tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/json-74a82b4ec4439e90/dep-lib-json tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/json-74a82b4ec4439e90/lib-json+1 tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/json-74a82b4ec4439e90/lib-json.json+1 tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-b5d63a9d8da2968e/bin-tj+1 tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-b5d63a9d8da2968e/bin-tj.json+1 tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-b5d63a9d8da2968e/dep-bin-tj tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-bb890ae6f101bb25/bin-tj+1 tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-bb890ae6f101bb25/bin-tj.json+1 tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-bb890ae6f101bb25/dep-bin-tj tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-bf24d0bdc8d0f4d6/bin-tj+1 tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-bf24d0bdc8d0f4d6/bin-tj.json+1 tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-bf24d0bdc8d0f4d6/dep-bin-tj tests/JSONTestSuite/parsers/test_json-rust/target/debug/deps/libjson-6bbf4c11dd6d7c25.rlib tests/JSONTestSuite/parsers/test_json-rust/target/debug/tj tests/JSONTestSuite/parsers/test_json-rust/target/debug/tj.dSYM/Contents/Info.plist+20 tests/JSONTestSuite/parsers/test_json-rust/target/debug/tj.dSYM/Contents/Resources/DWARF/tj tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/Cargo.lock+14 tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/Cargo.toml+7 tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/README+2 tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/src/main.rs+32 tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.cargo-lock tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-8f8b750d20f3bf10/bin-rj+1 tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-8f8b750d20f3bf10/bin-rj.json+1 tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-8f8b750d20f3bf10/dep-bin-rj tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-da0f8f63b87cf531/bin-rj+1 tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-da0f8f63b87cf531/bin-rj.json+1 tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-da0f8f63b87cf531/dep-bin-rj tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rustc-serialize-80c565222c5ccdbb/dep-lib-rustc-serialize tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rustc-serialize-80c565222c5ccdbb/lib-rustc-serialize+1 tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rustc-serialize-80c565222c5ccdbb/lib-rustc-serialize.json+1 tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/deps/librustc_serialize-3561541d79c18212.rlib tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/rj tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/rj.dSYM/Contents/Info.plist+20 tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/rj.dSYM/Contents/Resources/DWARF/rj tests/JSONTestSuite/parsers/test_json.cr+19 tests/JSONTestSuite/parsers/test_json.js+13 tests/JSONTestSuite/parsers/test_json.php+21 tests/JSONTestSuite/parsers/test_json.pl+32 tests/JSONTestSuite/parsers/test_json.py+39 tests/JSONTestSuite/parsers/test_json.rb+23 tests/JSONTestSuite/parsers/test_jsonChecker/bin/jsonChecker tests/JSONTestSuite/parsers/test_jsonChecker/jsonChecker/JSON_checker.c+400 tests/JSONTestSuite/parsers/test_jsonChecker/jsonChecker/JSON_checker.h+13 tests/JSONTestSuite/parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/project.pbxproj+253 tests/JSONTestSuite/parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/jsonChecker.xcscheme+91 tests/JSONTestSuite/parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test_jsonChecker/jsonChecker/jsonChecker/main.c+53 tests/JSONTestSuite/parsers/test_jsonChecker2/FSM.rtf+103 tests/JSONTestSuite/parsers/test_jsonChecker2/bin/jsonChecker2 tests/JSONTestSuite/parsers/test_jsonChecker2/jsonChecker2/JSON_checker.c+402 tests/JSONTestSuite/parsers/test_jsonChecker2/jsonChecker2/JSON_checker.h+13 tests/JSONTestSuite/parsers/test_jsonChecker2/jsonChecker2/jsonChecker/main.c+53 tests/JSONTestSuite/parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/project.pbxproj+253 tests/JSONTestSuite/parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 tests/JSONTestSuite/parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate tests/JSONTestSuite/parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/jsonChecker.xcscheme+97 tests/JSONTestSuite/parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 tests/JSONTestSuite/parsers/test_json_re.rb+33 tests/JSONTestSuite/parsers/test_json_xs.pl+28 tests/JSONTestSuite/parsers/test_jsonlite.r+7 tests/JSONTestSuite/parsers/test_oj_compat.rb+25 tests/JSONTestSuite/parsers/test_oj_strict.rb+25 tests/JSONTestSuite/parsers/test_qt/build.sh+4 tests/JSONTestSuite/parsers/test_qt/main.cpp+25 tests/JSONTestSuite/parsers/test_qt/test_qt.pro+12 tests/JSONTestSuite/parsers/test_rjson.r+7 tests/JSONTestSuite/parsers/test_yajl.rb+24 tests/JSONTestSuite/results/logs.txt+2048 tests/JSONTestSuite/results/parsing.html+2816 tests/JSONTestSuite/results/parsing_pruned.html+2661 tests/JSONTestSuite/results/pruned_results.png tests/JSONTestSuite/results/style.css+89 tests/JSONTestSuite/results/transform.html+1492 tests/JSONTestSuite/run_tests.py+673 tests/JSONTestSuite/test_parsing/i_object_key_lone_2nd_surrogate.json+1 tests/JSONTestSuite/test_parsing/i_string_1st_surrogate_but_2nd_missing.json+1 tests/JSONTestSuite/test_parsing/i_string_1st_valid_surrogate_2nd_invalid.json+1 tests/JSONTestSuite/test_parsing/i_string_UTF-16LE_with_BOM.json tests/JSONTestSuite/test_parsing/i_string_UTF-8_invalid_sequence.json+1 tests/JSONTestSuite/test_parsing/i_string_incomplete_surrogate_and_escape_valid.json+1 tests/JSONTestSuite/test_parsing/i_string_incomplete_surrogate_pair.json+1 tests/JSONTestSuite/test_parsing/i_string_incomplete_surrogates_escape_valid.json+1 tests/JSONTestSuite/test_parsing/i_string_invalid_lonely_surrogate.json+1 tests/JSONTestSuite/test_parsing/i_string_invalid_surrogate.json+1 tests/JSONTestSuite/test_parsing/i_string_inverted_surrogates_U+1D11E.json+1 tests/JSONTestSuite/test_parsing/i_string_lone_second_surrogate.json+1 tests/JSONTestSuite/test_parsing/i_string_not_in_unicode_range.json+1 tests/JSONTestSuite/test_parsing/i_string_truncated-utf-8.json+1 tests/JSONTestSuite/test_parsing/i_string_unicode_U+10FFFE_nonchar.json+1 tests/JSONTestSuite/test_parsing/i_string_unicode_U+1FFFE_nonchar.json+1 tests/JSONTestSuite/test_parsing/i_string_unicode_U+FDD0_nonchar.json+1 tests/JSONTestSuite/test_parsing/i_string_unicode_U+FFFE_nonchar.json+1 tests/JSONTestSuite/test_parsing/i_structure_500_nested_arrays.json+1 tests/JSONTestSuite/test_parsing/i_structure_UTF-8_BOM_empty_object.json+1 tests/JSONTestSuite/test_parsing/n_array_1_true_without_comma.json+1 tests/JSONTestSuite/test_parsing/n_array_a_invalid_utf8.json+1 tests/JSONTestSuite/test_parsing/n_array_colon_instead_of_comma.json+1 tests/JSONTestSuite/test_parsing/n_array_comma_after_close.json+1 tests/JSONTestSuite/test_parsing/n_array_comma_and_number.json+1 tests/JSONTestSuite/test_parsing/n_array_double_comma.json+1 tests/JSONTestSuite/test_parsing/n_array_double_extra_comma.json+1 tests/JSONTestSuite/test_parsing/n_array_extra_close.json+1 tests/JSONTestSuite/test_parsing/n_array_extra_comma.json+1 tests/JSONTestSuite/test_parsing/n_array_incomplete.json+1 tests/JSONTestSuite/test_parsing/n_array_incomplete_invalid_value.json+1 tests/JSONTestSuite/test_parsing/n_array_inner_array_no_comma.json+1 tests/JSONTestSuite/test_parsing/n_array_invalid_utf8.json+1 tests/JSONTestSuite/test_parsing/n_array_items_separated_by_semicolon.json+1 tests/JSONTestSuite/test_parsing/n_array_just_comma.json+1 tests/JSONTestSuite/test_parsing/n_array_just_minus.json+1 tests/JSONTestSuite/test_parsing/n_array_missing_value.json+1 tests/JSONTestSuite/test_parsing/n_array_newlines_unclosed.json+3 tests/JSONTestSuite/test_parsing/n_array_number_and_comma.json+1 tests/JSONTestSuite/test_parsing/n_array_number_and_several_commas.json+1 tests/JSONTestSuite/test_parsing/n_array_spaces_vertical_tab_formfeed.json+1 tests/JSONTestSuite/test_parsing/n_array_star_inside.json+1 tests/JSONTestSuite/test_parsing/n_array_unclosed.json+1 tests/JSONTestSuite/test_parsing/n_array_unclosed_trailing_comma.json+1 tests/JSONTestSuite/test_parsing/n_array_unclosed_with_new_lines.json+3 tests/JSONTestSuite/test_parsing/n_array_unclosed_with_object_inside.json+1 tests/JSONTestSuite/test_parsing/n_incomplete_false.json+1 tests/JSONTestSuite/test_parsing/n_incomplete_null.json+1 tests/JSONTestSuite/test_parsing/n_incomplete_true.json+1 tests/JSONTestSuite/test_parsing/n_number_++.json+1 tests/JSONTestSuite/test_parsing/n_number_+1.json+1 tests/JSONTestSuite/test_parsing/n_number_+Inf.json+1 tests/JSONTestSuite/test_parsing/n_number_-01.json+1 tests/JSONTestSuite/test_parsing/n_number_-1.0..json+1 tests/JSONTestSuite/test_parsing/n_number_-2..json+1 tests/JSONTestSuite/test_parsing/n_number_-NaN.json+1 tests/JSONTestSuite/test_parsing/n_number_.-1.json+1 tests/JSONTestSuite/test_parsing/n_number_.2e-3.json+1 tests/JSONTestSuite/test_parsing/n_number_0.1.2.json+1 tests/JSONTestSuite/test_parsing/n_number_0.3e+.json+1 tests/JSONTestSuite/test_parsing/n_number_0.3e.json+1 tests/JSONTestSuite/test_parsing/n_number_0.e1.json+1 tests/JSONTestSuite/test_parsing/n_number_0_capital_E+.json+1 tests/JSONTestSuite/test_parsing/n_number_0_capital_E.json+1 tests/JSONTestSuite/test_parsing/n_number_0e+.json+1 tests/JSONTestSuite/test_parsing/n_number_0e.json+1 tests/JSONTestSuite/test_parsing/n_number_1.0e+.json+1 tests/JSONTestSuite/test_parsing/n_number_1.0e-.json+1 tests/JSONTestSuite/test_parsing/n_number_1.0e.json+1 tests/JSONTestSuite/test_parsing/n_number_1_000.json+1 tests/JSONTestSuite/test_parsing/n_number_1eE2.json+1 tests/JSONTestSuite/test_parsing/n_number_2.e+3.json+1 tests/JSONTestSuite/test_parsing/n_number_2.e-3.json+1 tests/JSONTestSuite/test_parsing/n_number_2.e3.json+1 tests/JSONTestSuite/test_parsing/n_number_9.e+.json+1 tests/JSONTestSuite/test_parsing/n_number_Inf.json+1 tests/JSONTestSuite/test_parsing/n_number_NaN.json+1 tests/JSONTestSuite/test_parsing/n_number_U+FF11_fullwidth_digit_one.json+1 tests/JSONTestSuite/test_parsing/n_number_expression.json+1 tests/JSONTestSuite/test_parsing/n_number_hex_1_digit.json+1 tests/JSONTestSuite/test_parsing/n_number_hex_2_digits.json+1 tests/JSONTestSuite/test_parsing/n_number_infinity.json+1 tests/JSONTestSuite/test_parsing/n_number_invalid+-.json+1 tests/JSONTestSuite/test_parsing/n_number_invalid-negative-real.json+1 tests/JSONTestSuite/test_parsing/n_number_invalid-utf-8-in-bigger-int.json+1 tests/JSONTestSuite/test_parsing/n_number_invalid-utf-8-in-exponent.json+1 tests/JSONTestSuite/test_parsing/n_number_invalid-utf-8-in-int.json+1 tests/JSONTestSuite/test_parsing/n_number_minus_infinity.json+1 tests/JSONTestSuite/test_parsing/n_number_minus_sign_with_trailing_garbage.json+1 tests/JSONTestSuite/test_parsing/n_number_minus_space_1.json+1 tests/JSONTestSuite/test_parsing/n_number_neg_int_starting_with_zero.json+1 tests/JSONTestSuite/test_parsing/n_number_neg_real_without_int_part.json+1 tests/JSONTestSuite/test_parsing/n_number_neg_with_garbage_at_end.json+1 tests/JSONTestSuite/test_parsing/n_number_real_garbage_after_e.json+1 tests/JSONTestSuite/test_parsing/n_number_real_with_invalid_utf8_after_e.json+1 tests/JSONTestSuite/test_parsing/n_number_real_without_fractional_part.json+1 tests/JSONTestSuite/test_parsing/n_number_starting_with_dot.json+1 tests/JSONTestSuite/test_parsing/n_number_then_00.json tests/JSONTestSuite/test_parsing/n_number_with_alpha.json+1 tests/JSONTestSuite/test_parsing/n_number_with_alpha_char.json+1 tests/JSONTestSuite/test_parsing/n_number_with_leading_zero.json+1 tests/JSONTestSuite/test_parsing/n_object_bad_value.json+1 tests/JSONTestSuite/test_parsing/n_object_bracket_key.json+1 tests/JSONTestSuite/test_parsing/n_object_comma_instead_of_colon.json+1 tests/JSONTestSuite/test_parsing/n_object_double_colon.json+1 tests/JSONTestSuite/test_parsing/n_object_emoji.json+1 tests/JSONTestSuite/test_parsing/n_object_garbage_at_end.json+1 tests/JSONTestSuite/test_parsing/n_object_key_with_single_quotes.json+1 tests/JSONTestSuite/test_parsing/n_object_missing_colon.json+1 tests/JSONTestSuite/test_parsing/n_object_missing_key.json+1 tests/JSONTestSuite/test_parsing/n_object_missing_semicolon.json+1 tests/JSONTestSuite/test_parsing/n_object_missing_value.json+1 tests/JSONTestSuite/test_parsing/n_object_no-colon.json+1 tests/JSONTestSuite/test_parsing/n_object_non_string_key.json+1 tests/JSONTestSuite/test_parsing/n_object_non_string_key_but_huge_number_instead.json+1 tests/JSONTestSuite/test_parsing/n_object_pi_in_key_and_trailing_comma.json+1 tests/JSONTestSuite/test_parsing/n_object_repeated_null_null.json+1 tests/JSONTestSuite/test_parsing/n_object_several_trailing_commas.json+1 tests/JSONTestSuite/test_parsing/n_object_single_quote.json+1 tests/JSONTestSuite/test_parsing/n_object_trailing_comma.json+1 tests/JSONTestSuite/test_parsing/n_object_trailing_comment.json+1 tests/JSONTestSuite/test_parsing/n_object_trailing_comment_open.json+1 tests/JSONTestSuite/test_parsing/n_object_trailing_comment_slash_open.json+1 tests/JSONTestSuite/test_parsing/n_object_trailing_comment_slash_open_incomplete.json+1 tests/JSONTestSuite/test_parsing/n_object_two_commas_in_a_row.json+1 tests/JSONTestSuite/test_parsing/n_object_unquoted_key.json+1 tests/JSONTestSuite/test_parsing/n_object_unterminated-value.json+1 tests/JSONTestSuite/test_parsing/n_object_with_single_string.json+1 tests/JSONTestSuite/test_parsing/n_object_with_trailing_garbage.json+1 tests/JSONTestSuite/test_parsing/n_single_space.json+1 tests/JSONTestSuite/test_parsing/n_string_1_surrogate_then_escape u.json+1 tests/JSONTestSuite/test_parsing/n_string_1_surrogate_then_escape u1.json+1 tests/JSONTestSuite/test_parsing/n_string_1_surrogate_then_escape u1x.json+1 tests/JSONTestSuite/test_parsing/n_string_1_surrogate_then_escape.json+1 tests/JSONTestSuite/test_parsing/n_string_UTF8_surrogate_U+D800.json+1 tests/JSONTestSuite/test_parsing/n_string_accentuated_char_no_quotes.json+1 tests/JSONTestSuite/test_parsing/n_string_backslash_00.json tests/JSONTestSuite/test_parsing/n_string_escape_x.json+1 tests/JSONTestSuite/test_parsing/n_string_escaped_backslash_bad.json+1 tests/JSONTestSuite/test_parsing/n_string_escaped_ctrl_char_tab.json+1 tests/JSONTestSuite/test_parsing/n_string_escaped_emoji.json+1 tests/JSONTestSuite/test_parsing/n_string_incomplete_escape.json+1 tests/JSONTestSuite/test_parsing/n_string_incomplete_escaped_character.json+1 tests/JSONTestSuite/test_parsing/n_string_incomplete_surrogate.json+1 tests/JSONTestSuite/test_parsing/n_string_incomplete_surrogate_escape_invalid.json+1 tests/JSONTestSuite/test_parsing/n_string_invalid-utf-8-in-escape.json+1 tests/JSONTestSuite/test_parsing/n_string_invalid_backslash_esc.json+1 tests/JSONTestSuite/test_parsing/n_string_invalid_unicode_escape.json+1 tests/JSONTestSuite/test_parsing/n_string_invalid_utf-8.json+1 tests/JSONTestSuite/test_parsing/n_string_invalid_utf8_after_escape.json+1 tests/JSONTestSuite/test_parsing/n_string_iso_latin_1.json+1 tests/JSONTestSuite/test_parsing/n_string_leading_uescaped_thinspace.json+1 tests/JSONTestSuite/test_parsing/n_string_lone_utf8_continuation_byte.json+1 tests/JSONTestSuite/test_parsing/n_string_no_quotes_with_bad_escape.json+1 tests/JSONTestSuite/test_parsing/n_string_overlong_sequence_2_bytes.json+1 tests/JSONTestSuite/test_parsing/n_string_overlong_sequence_6_bytes.json+1 tests/JSONTestSuite/test_parsing/n_string_overlong_sequence_6_bytes_null.json+1 tests/JSONTestSuite/test_parsing/n_string_single_doublequote.json+1 tests/JSONTestSuite/test_parsing/n_string_single_quote.json+1 tests/JSONTestSuite/test_parsing/n_string_single_string_no_double_quotes.json+1 tests/JSONTestSuite/test_parsing/n_string_start_escape_unclosed.json+1 tests/JSONTestSuite/test_parsing/n_string_unescaped_crtl_char.json tests/JSONTestSuite/test_parsing/n_string_unescaped_newline.json+2 tests/JSONTestSuite/test_parsing/n_string_unescaped_tab.json+1 tests/JSONTestSuite/test_parsing/n_string_unicode_CapitalU.json+1 tests/JSONTestSuite/test_parsing/n_string_with_trailing_garbage.json+1 tests/JSONTestSuite/test_parsing/n_structure_..json+1 tests/JSONTestSuite/test_parsing/n_structure_100000_opening_arrays.json+1 tests/JSONTestSuite/test_parsing/n_structure_U+2060_word_joined.json+1 tests/JSONTestSuite/test_parsing/n_structure_UTF8_BOM_no_data.json+1 tests/JSONTestSuite/test_parsing/n_structure_array_trailing_garbage.json+1 tests/JSONTestSuite/test_parsing/n_structure_array_with_extra_array_close.json+1 tests/JSONTestSuite/test_parsing/n_structure_array_with_unclosed_string.json+1 tests/JSONTestSuite/test_parsing/n_structure_ascii-unicode-identifier.json+1 tests/JSONTestSuite/test_parsing/n_structure_capitalized_True.json+1 tests/JSONTestSuite/test_parsing/n_structure_close_unopened_array.json+1 tests/JSONTestSuite/test_parsing/n_structure_comma_instead_of_closing_brace.json+1 tests/JSONTestSuite/test_parsing/n_structure_double_array.json+1 tests/JSONTestSuite/test_parsing/n_structure_end_array.json+1 tests/JSONTestSuite/test_parsing/n_structure_incomplete_UTF8_BOM.json+1 tests/JSONTestSuite/test_parsing/n_structure_lone-invalid-utf-8.json+1 tests/JSONTestSuite/test_parsing/n_structure_lone-open-bracket.json+1 tests/JSONTestSuite/test_parsing/n_structure_no_data.json tests/JSONTestSuite/test_parsing/n_structure_null-byte-outside-string.json tests/JSONTestSuite/test_parsing/n_structure_null.json+1 tests/JSONTestSuite/test_parsing/n_structure_number_with_trailing_garbage.json+1 tests/JSONTestSuite/test_parsing/n_structure_object_followed_by_closing_object.json+1 tests/JSONTestSuite/test_parsing/n_structure_object_unclosed_no_value.json+1 tests/JSONTestSuite/test_parsing/n_structure_object_with_comment.json+1 tests/JSONTestSuite/test_parsing/n_structure_object_with_trailing_garbage.json+1 tests/JSONTestSuite/test_parsing/n_structure_open_array_apostrophe.json+1 tests/JSONTestSuite/test_parsing/n_structure_open_array_comma.json+1 tests/JSONTestSuite/test_parsing/n_structure_open_array_object.json+1 tests/JSONTestSuite/test_parsing/n_structure_open_array_open_object.json+1 tests/JSONTestSuite/test_parsing/n_structure_open_array_open_string.json+1 tests/JSONTestSuite/test_parsing/n_structure_open_array_string.json+1 tests/JSONTestSuite/test_parsing/n_structure_open_object.json+1 tests/JSONTestSuite/test_parsing/n_structure_open_object_close_array.json+1 tests/JSONTestSuite/test_parsing/n_structure_open_object_comma.json+1 tests/JSONTestSuite/test_parsing/n_structure_open_object_open_array.json+1 tests/JSONTestSuite/test_parsing/n_structure_open_object_open_string.json+1 tests/JSONTestSuite/test_parsing/n_structure_open_object_string_with_apostrophes.json+1 tests/JSONTestSuite/test_parsing/n_structure_open_open.json+1 tests/JSONTestSuite/test_parsing/n_structure_single_point.json+1 tests/JSONTestSuite/test_parsing/n_structure_single_star.json+1 tests/JSONTestSuite/test_parsing/n_structure_trailing_#.json+1 tests/JSONTestSuite/test_parsing/n_structure_uescaped_LF_before_string.json+1 tests/JSONTestSuite/test_parsing/n_structure_unclosed_array.json+1 tests/JSONTestSuite/test_parsing/n_structure_unclosed_array_partial_null.json+1 tests/JSONTestSuite/test_parsing/n_structure_unclosed_array_unfinished_false.json+1 tests/JSONTestSuite/test_parsing/n_structure_unclosed_array_unfinished_true.json+1 tests/JSONTestSuite/test_parsing/n_structure_unclosed_object.json+1 tests/JSONTestSuite/test_parsing/n_structure_unicode-identifier.json+1 tests/JSONTestSuite/test_parsing/n_structure_whitespace_U+2060_word_joiner.json+1 tests/JSONTestSuite/test_parsing/n_structure_whitespace_formfeed.json+1 tests/JSONTestSuite/test_parsing/y_array_arraysWithSpaces.json+1 tests/JSONTestSuite/test_parsing/y_array_empty-string.json+1 tests/JSONTestSuite/test_parsing/y_array_empty.json+1 tests/JSONTestSuite/test_parsing/y_array_ending_with_newline.json+1 tests/JSONTestSuite/test_parsing/y_array_false.json+1 tests/JSONTestSuite/test_parsing/y_array_heterogeneous.json+1 tests/JSONTestSuite/test_parsing/y_array_null.json+1 tests/JSONTestSuite/test_parsing/y_array_with_1_and_newline.json+2 tests/JSONTestSuite/test_parsing/y_array_with_leading_space.json+1 tests/JSONTestSuite/test_parsing/y_array_with_several_null.json+1 tests/JSONTestSuite/test_parsing/y_array_with_trailing_space.json+1 tests/JSONTestSuite/test_parsing/y_number.json+1 tests/JSONTestSuite/test_parsing/y_number_0e+1.json+1 tests/JSONTestSuite/test_parsing/y_number_0e1.json+1 tests/JSONTestSuite/test_parsing/y_number_after_space.json+1 tests/JSONTestSuite/test_parsing/y_number_double_close_to_zero.json+1 tests/JSONTestSuite/test_parsing/y_number_double_huge_neg_exp.json+1 tests/JSONTestSuite/test_parsing/y_number_huge_exp.json+1 tests/JSONTestSuite/test_parsing/y_number_int_with_exp.json+1 tests/JSONTestSuite/test_parsing/y_number_minus_zero.json+1 tests/JSONTestSuite/test_parsing/y_number_neg_int_huge_exp.json+1 tests/JSONTestSuite/test_parsing/y_number_negative_int.json+1 tests/JSONTestSuite/test_parsing/y_number_negative_one.json+1 tests/JSONTestSuite/test_parsing/y_number_negative_zero.json+1 tests/JSONTestSuite/test_parsing/y_number_pos_double_huge_exp.json+1 tests/JSONTestSuite/test_parsing/y_number_real_capital_e.json+1 tests/JSONTestSuite/test_parsing/y_number_real_capital_e_neg_exp.json+1 tests/JSONTestSuite/test_parsing/y_number_real_capital_e_pos_exp.json+1 tests/JSONTestSuite/test_parsing/y_number_real_exponent.json+1 tests/JSONTestSuite/test_parsing/y_number_real_fraction_exponent.json+1 tests/JSONTestSuite/test_parsing/y_number_real_neg_exp.json+1 tests/JSONTestSuite/test_parsing/y_number_real_neg_overflow.json+1 tests/JSONTestSuite/test_parsing/y_number_real_pos_exponent.json+1 tests/JSONTestSuite/test_parsing/y_number_real_pos_overflow.json+1 tests/JSONTestSuite/test_parsing/y_number_real_underflow.json+1 tests/JSONTestSuite/test_parsing/y_number_simple_int.json+1 tests/JSONTestSuite/test_parsing/y_number_simple_real.json+1 tests/JSONTestSuite/test_parsing/y_number_too_big_neg_int.json+1 tests/JSONTestSuite/test_parsing/y_number_too_big_pos_int.json+1 tests/JSONTestSuite/test_parsing/y_number_very_big_negative_int.json+1 tests/JSONTestSuite/test_parsing/y_object.json+1 tests/JSONTestSuite/test_parsing/y_object_basic.json+1 tests/JSONTestSuite/test_parsing/y_object_duplicated_key.json+1 tests/JSONTestSuite/test_parsing/y_object_duplicated_key_and_value.json+1 tests/JSONTestSuite/test_parsing/y_object_empty.json+1 tests/JSONTestSuite/test_parsing/y_object_empty_key.json+1 tests/JSONTestSuite/test_parsing/y_object_escaped_null_in_key.json+1 tests/JSONTestSuite/test_parsing/y_object_extreme_numbers.json+1 tests/JSONTestSuite/test_parsing/y_object_long_strings.json+1 tests/JSONTestSuite/test_parsing/y_object_simple.json+1 tests/JSONTestSuite/test_parsing/y_object_string_unicode.json+1 tests/JSONTestSuite/test_parsing/y_object_with_newlines.json+3 tests/JSONTestSuite/test_parsing/y_string_1_2_3_bytes_UTF-8_sequences.json+1 tests/JSONTestSuite/test_parsing/y_string_accepted_surrogate_pair.json+1 tests/JSONTestSuite/test_parsing/y_string_accepted_surrogate_pairs.json+1 tests/JSONTestSuite/test_parsing/y_string_allowed_escapes.json+1 tests/JSONTestSuite/test_parsing/y_string_backslash_and_u_escaped_zero.json+1 tests/JSONTestSuite/test_parsing/y_string_backslash_doublequotes.json+1 tests/JSONTestSuite/test_parsing/y_string_comments.json+1 tests/JSONTestSuite/test_parsing/y_string_double_escape_a.json+1 tests/JSONTestSuite/test_parsing/y_string_double_escape_n.json+1 tests/JSONTestSuite/test_parsing/y_string_escaped_control_character.json+1 tests/JSONTestSuite/test_parsing/y_string_escaped_noncharacter.json+1 tests/JSONTestSuite/test_parsing/y_string_in_array.json+1 tests/JSONTestSuite/test_parsing/y_string_in_array_with_leading_space.json+1 tests/JSONTestSuite/test_parsing/y_string_last_surrogates_1_and_2.json+1 tests/JSONTestSuite/test_parsing/y_string_newline_uescaped.json+1 tests/JSONTestSuite/test_parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json+1 tests/JSONTestSuite/test_parsing/y_string_nonCharacterInUTF-8_U+1FFFF.json+1 tests/JSONTestSuite/test_parsing/y_string_nonCharacterInUTF-8_U+FFFF.json+1 tests/JSONTestSuite/test_parsing/y_string_null_escape.json+1 tests/JSONTestSuite/test_parsing/y_string_one-byte-utf-8.json+1 tests/JSONTestSuite/test_parsing/y_string_pi.json+1 tests/JSONTestSuite/test_parsing/y_string_simple_ascii.json+1 tests/JSONTestSuite/test_parsing/y_string_space.json+1 tests/JSONTestSuite/test_parsing/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json+1 tests/JSONTestSuite/test_parsing/y_string_three-byte-utf-8.json+1 tests/JSONTestSuite/test_parsing/y_string_two-byte-utf-8.json+1 tests/JSONTestSuite/test_parsing/y_string_u+2028_line_sep.json+1 tests/JSONTestSuite/test_parsing/y_string_u+2029_par_sep.json+1 tests/JSONTestSuite/test_parsing/y_string_uEscape.json+1 tests/JSONTestSuite/test_parsing/y_string_unescaped_char_delete.json+1 tests/JSONTestSuite/test_parsing/y_string_unicode.json+1 tests/JSONTestSuite/test_parsing/y_string_unicodeEscapedBackslash.json+1 tests/JSONTestSuite/test_parsing/y_string_unicode_2.json+1 tests/JSONTestSuite/test_parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json+1 tests/JSONTestSuite/test_parsing/y_string_unicode_U+2064_invisible_plus.json+1 tests/JSONTestSuite/test_parsing/y_string_unicode_escaped_double_quote.json+1 tests/JSONTestSuite/test_parsing/y_string_utf16BE_no_BOM.json tests/JSONTestSuite/test_parsing/y_string_utf16LE_no_BOM.json tests/JSONTestSuite/test_parsing/y_string_utf8.json+1 tests/JSONTestSuite/test_parsing/y_string_with_del_character.json+1 tests/JSONTestSuite/test_parsing/y_structure_lonely_false.json+1 tests/JSONTestSuite/test_parsing/y_structure_lonely_int.json+1 tests/JSONTestSuite/test_parsing/y_structure_lonely_negative_real.json+1 tests/JSONTestSuite/test_parsing/y_structure_lonely_null.json+1 tests/JSONTestSuite/test_parsing/y_structure_lonely_string.json+1 tests/JSONTestSuite/test_parsing/y_structure_lonely_true.json+1 tests/JSONTestSuite/test_parsing/y_structure_string_empty.json+1 tests/JSONTestSuite/test_parsing/y_structure_trailing_newline.json+1 tests/JSONTestSuite/test_parsing/y_structure_true_in_array.json+1 tests/JSONTestSuite/test_parsing/y_structure_whitespace_array.json+1 tests/JSONTestSuite/test_transform/number_1.0.json+1 tests/JSONTestSuite/test_transform/number_1.000000000000000005.json+1 tests/JSONTestSuite/test_transform/number_1000000000000000.json+1 tests/JSONTestSuite/test_transform/number_10000000000000000999.json+1 tests/JSONTestSuite/test_transform/number_1e-999.json+1 tests/JSONTestSuite/test_transform/number_1e6.json+1 tests/JSONTestSuite/test_transform/object_key_nfc_nfd.json+1 tests/JSONTestSuite/test_transform/object_key_nfd_nfc.json+1 tests/JSONTestSuite/test_transform/object_same_key_different_values.json+1 tests/JSONTestSuite/test_transform/object_same_key_same_value.json+1 tests/JSONTestSuite/test_transform/object_same_key_unclear_values.json+1 tests/JSONTestSuite/test_transform/string_1_escaped_invalid_codepoint.json+1 tests/JSONTestSuite/test_transform/string_1_invalid_codepoint.json+1 tests/JSONTestSuite/test_transform/string_2_escaped_invalid_codepoints.json+1 tests/JSONTestSuite/test_transform/string_2_invalid_codepoints.json+1 tests/JSONTestSuite/test_transform/string_3_escaped_invalid_codepoints.json+1 tests/JSONTestSuite/test_transform/string_3_invalid_codepoints.json+1 tests/JSONTestSuite/test_transform/string_with_escaped_NULL.json+1 tests/Options.hs+33−1 tests/PropUtils.hs+208 tests/Properties.hs+17−297 tests/PropertyGeneric.hs+116 tests/PropertyKeys.hs+40 tests/PropertyRTFunctors.hs+51 tests/PropertyRoundTrip.hs+74 tests/PropertyTH.hs+130 tests/SerializationFormatSpec.hs+294 tests/Tests.hs+7−2 tests/Types.hs+93−4 tests/UnitTests.hs+459−110 tests/UnitTests/NullaryConstructors.hs+14−3 tests/golden/generic.expected+48 tests/golden/simple.expected+22 travis/cabal_macros.h+448 travis/install.sh+11 travis/script.sh+8−1
.gitattributesnew file+1
@@ -0,0 +1 @@
1+tests/JSONTestSuite/* linguist-vendored
.gitignore+11
@@ -1,10 +1,21 @@
11dist
2+dist-newstyle
3+.ghc.environment.*
24.cabal-sandbox/
35cabal.sandbox.config
6+.stack-work/
7+.stack-work-bench/
8+*.yaml.lock
49
510*.o
611*.hi
712*.nix
13+*.swp
14+.\#*
15+\#*
16+
17+# Emacs backup files
18+*~
819
920benchmarks/AesonEncode
1021
.hlint.yamlnew file+11
@@ -0,0 +1,11 @@
1+# Ignore some builtin hints
2+- ignore:
3+ name: "Reduce duplication"
4+ within:
5+ - Data.Aeson.Types.ToJSON
6+- ignore:
7+ name: "Eta reduce"
8+- ignore:
9+ name: "Use newtype instead of data"
10+ within:
11+ - Data.Aeson.Types.Internal
.travis.yml+43−16
@@ -12,31 +12,58 @@ cache:
1212 - $HOME/.stack
1313 - $HOME/.cabsnap
1414 - $HOME/.cabal/packages
15+ - $HOME/.cabal/store
1516
1617before_cache:
1718 - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
18− - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar
19+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*
20+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json
21+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache
22+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar
23+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx
1924
2025matrix:
2126 include:
22− - env: BUILD=cabal CABALVER=1.16 GHCVER=7.4.2
23− compiler: ": #GHC 7.4.2"
24− addons: {apt: {packages: [cabal-install-1.16,ghc-7.4.2], sources: [hvr-ghc]}}
25− - env: BUILD=cabal CABALVER=1.16 GHCVER=7.6.3
26− compiler: ": #GHC 7.6.3"
27− addons: {apt: {packages: [cabal-install-1.16,ghc-7.6.3], sources: [hvr-ghc]}}
27+
28+ - env: BUILD=hlint CABALVER=2.2 GHCVER=8.4.4
29+ compiler: ": #GHC 8.4.4"
30+ addons: {apt: {packages: [cabal-install-2.2,ghc-8.4.4], sources: [hvr-ghc]}}
31+
32+ - env: BUILD=stack CABALVER=2.4 GHCVER=8.6.5 STACK_YAML=stack-bench.yaml
33+ compiler: ": #GHC 8.6.5"
34+ addons: {apt: {packages: [cabal-install-2.4,ghc-8.6.5], sources: [hvr-ghc]}}
35+
36+ - env: BUILD=stack CABALVER=2.2 GHCVER=8.6.5 STACK_YAML=stack-ffi-unescape.yaml
37+ compiler: ": #GHC 8.6.5"
38+ addons: {apt: {packages: [cabal-install-2.2,ghc-8.6.5], sources: [hvr-ghc]}}
39+
40+ - env: BUILD=cabal2 CABALVER=3.0 GHCVER=8.8.1
41+ compiler: ": #GHC 8.8.1"
42+ addons: {apt: {packages: [cabal-install-3.0,ghc-8.8.1], sources: [hvr-ghc]}}
43+
44+ - env: BUILD=cabal CABALVER=2.4 GHCVER=8.6.5
45+ compiler: ": #GHC 8.6.5"
46+ addons: {apt: {packages: [cabal-install-2.4,ghc-8.6.5], sources: [hvr-ghc]}}
47+
48+ - env: BUILD=cabal CABALVER=2.2 GHCVER=8.4.4
49+ compiler: ": #GHC 8.4.4"
50+ addons: {apt: {packages: [cabal-install-2.2,ghc-8.4.4], sources: [hvr-ghc]}}
51+
52+ - env: BUILD=cabal CABALVER=2.0 GHCVER=8.2.2
53+ compiler: ": #GHC 8.2.2"
54+ addons: {apt: {packages: [cabal-install-2.0,ghc-8.2.2], sources: [hvr-ghc]}}
55+
56+ - env: BUILD=cabal CABALVER=2.0 GHCVER=8.0.2
57+ compiler: ": #GHC 8.0.2"
58+ addons: {apt: {packages: [cabal-install-2.0,ghc-8.0.2], sources: [hvr-ghc]}}
59+
60+ - env: BUILD=cabal CABALVER=1.22 GHCVER=7.10.3
61+ compiler: ": #GHC 7.10.3"
62+ addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3], sources: [hvr-ghc]}}
63+
2864 - env: BUILD=cabal CABALVER=1.18 GHCVER=7.8.4
2965 compiler: ": #GHC 7.8.4"
3066 addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4], sources: [hvr-ghc]}}
31− - env: BUILD=cabal CABALVER=1.22 GHCVER=7.10.2
32− compiler: ": #GHC 7.10.2"
33− addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.2], sources: [hvr-ghc]}}
34− - env: BUILD=cabal CABALVER=1.24 GHCVER=8.0.1
35− compiler: ": #GHC 8.0.1"
36− addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.1], sources: [hvr-ghc]}}
37− - env: BUILD=stack CABALVER=1.22 GHCVER=7.10.3
38− compiler: ": #GHC 7.10.3"
39− addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3], sources: [hvr-ghc]}}
4067
4168before_install:
4269 - unset CC
CONTRIBUTING.mdnew file+98
@@ -0,0 +1,98 @@
1+# Documenting changes
2+
3+Changes that affect users of aeson should be mentioned in `changelog.md`. It should contain
4+* A description
5+* The level of change, see [PVP](https://wiki.haskell.org/Package_versioning_policy)
6+* Where applicable
7+ * How to migrate existing code
8+ * When it should be used
9+ * What it supersedes
10+
11+Add this entry under an `## Upcoming` header above existing releases.
12+
13+The exact format of entries is not important as we'll go through everything before a release is made.
14+
15+# Style guide
16+
17+* 4 space indentation
18+
19+## Pragmas
20+
21+* One pragma on each line
22+* No alignment
23+* Sort lexicographically
24+
25+```haskell
26+{-# LANGUAGE BangPatterns #-}
27+{-# LANGUAGE CPP #-}
28+{-# LANGUAGE DataKinds #-}
29+```
30+
31+## Module declaration and exports
32+
33+* Opening paren on its own line
34+* Prefix with commas
35+* End with `) where`
36+
37+```haskell
38+module Data.Aeson.Types.ToJSON
39+ (
40+ -- * Core JSON classes
41+ ToJSON(..)
42+ -- * Liftings to unary and binary type constructors
43+ , ToJSON1(..)
44+ , toJSON1
45+ ) where
46+```
47+
48+## Imports
49+
50+* No alignment of import lists or qualifications
51+* Sort lexicographically (qualified imports will be last)
52+* No space between types and constructor lists
53+* Sort identifiers in import lists lexicographically
54+
55+```haskell
56+import BarBar as B ((<>), foo)
57+import Foo as F
58+import Qux (Q(..), q)
59+import qualified A
60+```
61+
62+## Development Workflow (If you plan on using Stack)
63+
64+Here we outline a general workflow new contributors could adopt for a nice incremental development experience.
65+
66+The root folder consists of two stack-*.yaml config files.
67+
68+1. stack-nightly.yaml - Config file defines all the settings to build and test any changes.
69+2. stack-bench.yaml - Used to run benchmark tests.
70+3. stack-ffi-unescape.yaml - This is for replacing certain parts with a C-implementation.
71+
72+Therefore, a ghci development experience would be:
73+
74+1. `stack ghci --stack-yaml stack-nightly.yaml --test`
75+2. :r to recompile
76+3. `main` to run all tests, or `:main --pattern Foo` to run specific tests matched by pattern.
77+
78+Some discussion on this topic can also be found here [here](https://github.com/bos/aeson/issues/733)
79+
80+Of course before submitting a PR, the following steps are recommended:
81+
82+1. 'stack test --stack-yaml stack-nightly.yaml` - Run the entire suite of tests
83+2. `make hlint` - Run hlint on the source folders.
84+3. 'stack test --stack-yaml stack-bench.yaml` - Run the benchmark tests if you believe your changes could affect the benchmarks.
85+
86+## Development Workflow (If you plan on using Cabal)
87+
88+A ghci development experience would be:
89+
90+1. `cabal new-repl test:tests`
91+2. `:r` to recompile
92+3. `Main.main` to run all tests, or `:m Main; :main --pattern Foo` to run specific tests matched by pattern.
93+
94+Of course before submitting a PR, the following steps are recommended:
95+
96+1. `cabal new-test` - Run the entire suite of tests
97+2. `make hlint` - Run hlint on the source folders.
98+3. Uncomment the `benchmarks` line in `cabal.project` - Run the benchmark tests if you believe your changes could affect the benchmarks.
Data/Aeson.hs+87−14
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12-- |
23-- Module: Data.Aeson
34-- Copyright: (c) 2011-2016 Bryan O'Sullivan
@@ -38,11 +39,16 @@ module Data.Aeson
3839 , eitherDecode
3940 , eitherDecode'
4041 , encode
42+ , encodeFile
4143 -- ** Variants for strict bytestrings
4244 , decodeStrict
45+ , decodeFileStrict
4346 , decodeStrict'
47+ , decodeFileStrict'
4448 , eitherDecodeStrict
49+ , eitherDecodeFileStrict
4550 , eitherDecodeStrict'
51+ , eitherDecodeFileStrict'
4652 -- * Core JSON types
4753 , Value(..)
4854 , Encoding
@@ -57,11 +63,18 @@ module Data.Aeson
5763 , fromJSON
5864 , ToJSON(..)
5965 , KeyValue(..)
66+ , (<?>)
67+ , JSONPath
6068 -- ** Keys for maps
6169 , ToJSONKey(..)
6270 , ToJSONKeyFunction(..)
6371 , FromJSONKey(..)
6472 , FromJSONKeyFunction(..)
73+ -- *** Generic keys
74+ , GToJSONKey()
75+ , genericToJSONKey
76+ , GFromJSONKey()
77+ , genericFromJSONKey
6578 -- ** Liftings to unary and binary type constructors
6679 , FromJSON1(..)
6780 , parseJSON1
@@ -75,8 +88,10 @@ module Data.Aeson
7588 , toEncoding2
7689 -- ** Generic JSON classes and options
7790 , GFromJSON(..)
78− , GToJSON(..)
79− , GToEncoding(..)
91+ , FromArgs(..)
92+ , GToJSON
93+ , GToEncoding
94+ , ToArgs(..)
8095 , Zero
8196 , One
8297 , genericToJSON
@@ -85,15 +100,34 @@ module Data.Aeson
85100 , genericLiftToEncoding
86101 , genericParseJSON
87102 , genericLiftParseJSON
103+ -- ** Generic and TH encoding configuration
104+ , Options
88105 , defaultOptions
106+ -- *** Options fields
107+ -- $optionsFields
108+ , fieldLabelModifier
109+ , constructorTagModifier
110+ , allNullaryToStringTag
111+ , omitNothingFields
112+ , sumEncoding
113+ , unwrapUnaryRecords
114+ , tagSingleConstructors
115+ -- *** Options utilities
116+ , SumEncoding(..)
117+ , camelTo2
118+ , defaultTaggedObject
119+ -- ** Options for object keys
120+ , JSONKeyOptions
121+ , keyModifier
122+ , defaultJSONKeyOptions
89123
90124 -- * Inspecting @'Value's@
91125 , withObject
92126 , withText
93127 , withArray
94− , withNumber
95128 , withScientific
96129 , withBool
130+ , withEmbeddedJSON
97131 -- * Constructors and accessors
98132 , Series
99133 , pairs
@@ -106,15 +140,16 @@ module Data.Aeson
106140 -- * Parsing
107141 , json
108142 , json'
143+ , parseIndexedJSON
109144 ) where
110145
111−import Data.Aeson.Types.FromJSON (ifromJSON)
146+import Prelude.Compat
147+
148+import Data.Aeson.Types.FromJSON (ifromJSON, parseIndexedJSON)
112149import Data.Aeson.Encoding (encodingToLazyByteString)
113−import Data.Aeson.Parser.Internal (decodeWith, decodeStrictWith,
114− eitherDecodeWith, eitherDecodeStrictWith,
115− jsonEOF, json, jsonEOF', json')
150+import Data.Aeson.Parser.Internal (decodeWith, decodeStrictWith, eitherDecodeWith, eitherDecodeStrictWith, jsonEOF, json, jsonEOF', json')
116151import Data.Aeson.Types
117−import Data.Aeson.Types.Internal (JSONPath, formatError)
152+import Data.Aeson.Types.Internal (JSONPath, formatError, (<?>))
118153import qualified Data.ByteString as B
119154import qualified Data.ByteString.Lazy as L
120155
@@ -124,6 +159,10 @@ import qualified Data.ByteString.Lazy as L
124159encode :: (ToJSON a) => a -> L.ByteString
125160encode = encodingToLazyByteString . toEncoding
126161
162+-- | Efficiently serialize a JSON value as a lazy 'L.ByteString' and write it to a file.
163+encodeFile :: (ToJSON a) => FilePath -> a -> IO ()
164+encodeFile fp = L.writeFile fp . encode
165+
127166-- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.
128167-- If this fails due to incomplete or invalid input, 'Nothing' is
129168-- returned.
@@ -150,6 +189,18 @@ decodeStrict :: (FromJSON a) => B.ByteString -> Maybe a
150189decodeStrict = decodeStrictWith jsonEOF fromJSON
151190{-# INLINE decodeStrict #-}
152191
192+-- | Efficiently deserialize a JSON value from a file.
193+-- If this fails due to incomplete or invalid input, 'Nothing' is
194+-- returned.
195+--
196+-- The input file's content must consist solely of a JSON document,
197+-- with no trailing data except for whitespace.
198+--
199+-- This function parses immediately, but defers conversion. See
200+-- 'json' for details.
201+decodeFileStrict :: (FromJSON a) => FilePath -> IO (Maybe a)
202+decodeFileStrict = fmap decodeStrict . B.readFile
203+
153204-- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.
154205-- If this fails due to incomplete or invalid input, 'Nothing' is
155206-- returned.
@@ -176,6 +227,18 @@ decodeStrict' :: (FromJSON a) => B.ByteString -> Maybe a
176227decodeStrict' = decodeStrictWith jsonEOF' fromJSON
177228{-# INLINE decodeStrict' #-}
178229
230+-- | Efficiently deserialize a JSON value from a file.
231+-- If this fails due to incomplete or invalid input, 'Nothing' is
232+-- returned.
233+--
234+-- The input file's content must consist solely of a JSON document,
235+-- with no trailing data except for whitespace.
236+--
237+-- This function parses and performs conversion immediately. See
238+-- 'json'' for details.
239+decodeFileStrict' :: (FromJSON a) => FilePath -> IO (Maybe a)
240+decodeFileStrict' = fmap decodeStrict' . B.readFile
241+
179242eitherFormatError :: Either (JSONPath, String) a -> Either String a
180243eitherFormatError = either (Left . uncurry formatError) Right
181244{-# INLINE eitherFormatError #-}
@@ -191,6 +254,12 @@ eitherDecodeStrict =
191254 eitherFormatError . eitherDecodeStrictWith jsonEOF ifromJSON
192255{-# INLINE eitherDecodeStrict #-}
193256
257+-- | Like 'decodeFileStrict' but returns an error message when decoding fails.
258+eitherDecodeFileStrict :: (FromJSON a) => FilePath -> IO (Either String a)
259+eitherDecodeFileStrict =
260+ fmap (eitherFormatError . eitherDecodeStrictWith jsonEOF ifromJSON) . B.readFile
261+{-# INLINE eitherDecodeFileStrict #-}
262+
194263-- | Like 'decode'' but returns an error message when decoding fails.
195264eitherDecode' :: (FromJSON a) => L.ByteString -> Either String a
196265eitherDecode' = eitherFormatError . eitherDecodeWith jsonEOF' ifromJSON
@@ -202,6 +271,12 @@ eitherDecodeStrict' =
202271 eitherFormatError . eitherDecodeStrictWith jsonEOF' ifromJSON
203272{-# INLINE eitherDecodeStrict' #-}
204273
274+-- | Like 'decodeFileStrict'' but returns an error message when decoding fails.
275+eitherDecodeFileStrict' :: (FromJSON a) => FilePath -> IO (Either String a)
276+eitherDecodeFileStrict' =
277+ fmap (eitherFormatError . eitherDecodeStrictWith jsonEOF' ifromJSON) . B.readFile
278+{-# INLINE eitherDecodeFileStrict' #-}
279+
205280-- $use
206281--
207282-- This section contains basic information on the different ways to
@@ -271,11 +346,9 @@ eitherDecodeStrict' =
271346-- > {-# LANGUAGE OverloadedStrings #-}
272347-- >
273348-- > instance FromJSON Person where
274−-- > parseJSON (Object v) = Person <$>
275−-- > v .: "name" <*>
276−-- > v .: "age"
277−-- > -- A non-Object value is of the wrong type, so fail.
278−-- > parseJSON _ = empty
349+-- > parseJSON = withObject "Person" $ \v -> Person
350+-- > <$> v .: "name"
351+-- > <*> v .: "age"
279352--
280353-- We can now parse the JSON data like so:
281354--
@@ -365,7 +438,7 @@ eitherDecodeStrict' =
365438-- The 'Object' type contains JSON objects:
366439--
367440-- > λ> decode "{\"name\":\"Dave\",\"age\":2}" :: Maybe Object
368−-- > Just (fromList) [("name",String "Dave"),("age",Number 2)]
441+-- > Just (fromList [("name",String "Dave"),("age",Number 2)])
369442--
370443-- You can extract values from it with a parser using 'parse',
371444-- 'parseEither' or, in this example, 'parseMaybe':
Data/Aeson/Encode.hs+5−2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12-- |
23-- Module: Data.Aeson.Encode
34-- Copyright: (c) 2012-2016 Bryan O'Sullivan
@@ -8,14 +9,16 @@
89-- Portability: portable
910--
1011-- This module is left to supply limited backwards-compatibility.
12+
1113module Data.Aeson.Encode {-# DEPRECATED "Use Data.Aeson or Data.Aeson.Text instead" #-}
12− ( encode
14+ (
15+ encode
1316 , encodeToTextBuilder
1417 ) where
1518
19+
1620import Data.ByteString.Lazy (ByteString)
1721import Data.Text.Lazy.Builder (Builder)
18−
1922import qualified Data.Aeson as A
2023import qualified Data.Aeson.Text as A
2124
Data/Aeson/Encoding.hs+12−1
@@ -1,13 +1,23 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+-- |
3+--
4+-- Functions in this module return well-formed 'Encoding''.
5+-- Polymorphic variants, which return @'Encoding' a@, return a textual JSON
6+-- value, so it can be used as both @'Encoding'' 'Text'@ and @'Encoding' = 'Encoding'' 'Value'@.
7+
18module Data.Aeson.Encoding
29 (
310 -- * Encoding
411 Encoding
5− , encodingToLazyByteString
12+ , Encoding'
13+ , encodingToLazyByteString
614 , fromEncoding
715 , unsafeToEncoding
816 , Series
917 , pairs
1018 , pair
19+ , pairStr
20+ , pair'
1121 -- * Predicates
1222 , nullEncoding
1323 -- * Encoding constructors
@@ -41,4 +51,5 @@ module Data.Aeson.Encoding
4151 , value
4252 ) where
4353
54+
4455import Data.Aeson.Encoding.Internal
Data/Aeson/Encoding/Builder.hs+23−20
@@ -1,5 +1,6 @@
1−{-# LANGUAGE BangPatterns, OverloadedStrings #-}
2−
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE TupleSections #-}
34-- |
45-- Module: Data.Aeson.Encoding.Builder
56-- Copyright: (c) 2011 MailRank, Inc.
@@ -35,21 +36,23 @@ module Data.Aeson.Encoding.Builder
3536 , ascii5
3637 ) where
3738
39+import Prelude.Compat
40+
3841import Data.Aeson.Internal.Time
3942import Data.Aeson.Types.Internal (Value (..))
4043import Data.ByteString.Builder as B
4144import Data.ByteString.Builder.Prim as BP
4245import Data.ByteString.Builder.Scientific (scientificBuilder)
4346import Data.Char (chr, ord)
44−import Data.Monoid ((<>))
47+import Data.Semigroup ((<>))
4548import Data.Scientific (Scientific, base10Exponent, coefficient)
49+import Data.Text.Encoding (encodeUtf8BuilderEscaped)
4650import Data.Time (UTCTime(..))
4751import Data.Time.Calendar (Day(..), toGregorian)
4852import Data.Time.LocalTime
4953import Data.Word (Word8)
5054import qualified Data.HashMap.Strict as HMS
5155import qualified Data.Text as T
52−import qualified Data.Text.Encoding as TE
5356import qualified Data.Vector as V
5457
5558-- | Encode a JSON value to a "Data.ByteString" 'B.Builder'.
@@ -98,7 +101,7 @@ text t = B.char8 '"' <> unquoted t <> B.char8 '"'
98101
99102-- | Encode a JSON string, without enclosing quotes.
100103unquoted :: T.Text -> Builder
101−unquoted = TE.encodeUtf8BuilderEscaped escapeAscii
104+unquoted = encodeUtf8BuilderEscaped escapeAscii
102105
103106-- | Add quotes surrounding a builder
104107quote :: Builder -> Builder
@@ -117,7 +120,7 @@ escapeAscii =
117120 BP.condB (== c2w '\n' ) (ascii2 ('\\','n' )) $
118121 BP.condB (== c2w '\r' ) (ascii2 ('\\','r' )) $
119122 BP.condB (== c2w '\t' ) (ascii2 ('\\','t' )) $
120− (BP.liftFixedToBounded hexEscape) -- fallback for chars < 0x20
123+ BP.liftFixedToBounded hexEscape -- fallback for chars < 0x20
121124 where
122125 hexEscape :: BP.FixedPrim Word8
123126 hexEscape = (\c -> ('\\', ('u', fromIntegral c))) BP.>$<
@@ -130,7 +133,7 @@ c2w c = fromIntegral (ord c)
130133-- | Encode a JSON number.
131134scientific :: Scientific -> Builder
132135scientific s
133− | e < 0 = scientificBuilder s
136+ | e < 0 || e > 1024 = scientificBuilder s
134137 | otherwise = B.integerDec (coefficient s * 10 ^ e)
135138 where
136139 e = base10Exponent s
@@ -142,27 +145,27 @@ emptyObject_ :: Builder
142145emptyObject_ = BP.primBounded (ascii2 ('{','}')) ()
143146
144147ascii2 :: (Char, Char) -> BP.BoundedPrim a
145−ascii2 cs = BP.liftFixedToBounded $ (const cs) BP.>$< BP.char7 >*< BP.char7
148+ascii2 cs = BP.liftFixedToBounded $ const cs BP.>$< BP.char7 >*< BP.char7
146149{-# INLINE ascii2 #-}
147150
148151ascii4 :: (Char, (Char, (Char, Char))) -> BP.BoundedPrim a
149−ascii4 cs = BP.liftFixedToBounded $ (const cs) >$<
152+ascii4 cs = BP.liftFixedToBounded $ const cs >$<
150153 BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7
151154{-# INLINE ascii4 #-}
152155
153156ascii5 :: (Char, (Char, (Char, (Char, Char)))) -> BP.BoundedPrim a
154−ascii5 cs = BP.liftFixedToBounded $ (const cs) >$<
157+ascii5 cs = BP.liftFixedToBounded $ const cs >$<
155158 BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7
156159{-# INLINE ascii5 #-}
157160
158161ascii6 :: (Char, (Char, (Char, (Char, (Char, Char))))) -> BP.BoundedPrim a
159−ascii6 cs = BP.liftFixedToBounded $ (const cs) >$<
162+ascii6 cs = BP.liftFixedToBounded $ const cs >$<
160163 BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7
161164{-# INLINE ascii6 #-}
162165
163166ascii8 :: (Char, (Char, (Char, (Char, (Char, (Char, (Char, Char)))))))
164167 -> BP.BoundedPrim a
165−ascii8 cs = BP.liftFixedToBounded $ (const cs) >$<
168+ascii8 cs = BP.liftFixedToBounded $ const cs >$<
166169 BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7 >*<
167170 BP.char7 >*< BP.char7 >*< BP.char7 >*< BP.char7
168171{-# INLINE ascii8 #-}
@@ -175,12 +178,13 @@ day dd = encodeYear yr <>
175178 !(T dh dl) = twoDigits d
176179 encodeYear y
177180 | y >= 1000 = B.integerDec y
178− | y > 0 =
179− let (ab,c) = fromIntegral y `quotRem` 10
180− (a,b) = ab `quotRem` 10
181− in BP.primBounded (ascii4 ('0',(digit a,(digit b,digit c)))) ()
182− | otherwise =
183− error "Data.Aeson.Encode.Builder.day: years BCE not supported"
181+ | y >= 0 = BP.primBounded (ascii4 (padYear y)) ()
182+ | y >= -999 = BP.primBounded (ascii5 ('-',padYear (- y))) ()
183+ | otherwise = B.integerDec y
184+ padYear y =
185+ let (ab,c) = fromIntegral y `quotRem` 10
186+ (a,b) = ab `quotRem` 10
187+ in ('0',(digit a,(digit b,digit c)))
184188{-# INLINE day #-}
185189
186190timeOfDay :: TimeOfDay -> Builder
@@ -197,7 +201,7 @@ timeOfDay64 (TOD h m s)
197201 !(T mh ml) = twoDigits m
198202 !(T sh sl) = twoDigits (fromIntegral real)
199203 (real,frac) = s `quotRem` pico
200− showFrac = (\x -> ('.', x)) >$< (BP.liftFixedToBounded BP.char7 >*< trunc12)
204+ showFrac = ('.',) >$< (BP.liftFixedToBounded BP.char7 >*< trunc12)
201205 trunc12 = (`quotRem` micro) >$<
202206 BP.condB (\(_,y) -> y == 0) (fst >$< trunc6) (digits6 >*< trunc6)
203207 digits6 = ((`quotRem` milli) . fromIntegral) >$< (digits3 >*< digits3)
@@ -215,7 +219,6 @@ timeOfDay64 (TOD h m s)
215219 pico = 1000000000000 -- number of picoseconds in 1 second
216220 micro = 1000000 -- number of microseconds in 1 second
217221 milli = 1000 -- number of milliseconds in 1 second
218−{-# INLINE timeOfDay64 #-}
219222
220223timeZone :: TimeZone -> Builder
221224timeZone (TimeZone off _ _)
Data/Aeson/Encoding/Internal.hs+110−83
@@ -1,23 +1,29 @@
1−{-# LANGUAGE DeriveDataTypeable #-}
2−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3−{-# LANGUAGE OverloadedStrings #-}
4−{-# LANGUAGE RankNTypes #-}
1+{-# LANGUAGE DeriveDataTypeable #-}
2+{-# LANGUAGE EmptyDataDecls #-}
3+{-# LANGUAGE NoImplicitPrelude #-}
4+{-# LANGUAGE OverloadedStrings #-}
5+{-# LANGUAGE RankNTypes #-}
6+
57module Data.Aeson.Encoding.Internal
68 (
79 -- * Encoding
8− Encoding (..) -- TODO: export fromEncoding for now
9− , encodingToLazyByteString
10+ Encoding' (..)
11+ , Encoding
12+ , encodingToLazyByteString
1013 , unsafeToEncoding
11− , Series (..) -- TODO: don't export constructor
14+ , retagEncoding
15+ , Series (..)
1216 , pairs
1317 , pair
18+ , pairStr
19+ , pair'
1420 -- * Predicates
1521 , nullEncoding
1622 -- * Encoding constructors
1723 , emptyArray_
1824 , emptyObject_
19− , wrapArray
2025 , wrapObject
26+ , wrapArray
2127 , null_
2228 , bool
2329 , text
@@ -27,6 +33,10 @@ module Data.Aeson.Encoding.Internal
2733 , dict
2834 , tuple
2935 , (>*<)
36+ , InArray
37+ , empty
38+ , (><)
39+ , econcat
3040 -- ** Decimal numbers
3141 , int8, int16, int32, int64, int
3242 , word8, word16, word32, word64, word
@@ -47,55 +57,59 @@ module Data.Aeson.Encoding.Internal
4757 , comma, colon, openBracket, closeBracket, openCurly, closeCurly
4858 ) where
4959
50−import Prelude ()
5160import Prelude.Compat
5261
53−import Data.ByteString.Builder (Builder, char7, toLazyByteString)
54−import Data.ByteString.Builder.Prim (primBounded)
62+import Data.Aeson.Types.Internal (Value)
63+import Data.ByteString.Builder (Builder, char7, toLazyByteString)
5564import Data.Int
56−import Data.Scientific (Scientific)
57−import Data.Semigroup (Semigroup ((<>)))
58−import Data.Text (Text)
59−import Data.Time (Day, LocalTime, TimeOfDay, UTCTime,
60− ZonedTime)
61−import Data.Typeable (Typeable)
65+import Data.Scientific (Scientific)
66+import Data.Semigroup (Semigroup ((<>)))
67+import Data.Text (Text)
68+import Data.Time (Day, LocalTime, TimeOfDay, UTCTime, ZonedTime)
69+import Data.Typeable (Typeable)
6270import Data.Word
63−
64−import Data.Aeson.Types.Internal (Value)
65−
6671import qualified Data.Aeson.Encoding.Builder as EB
67−import qualified Data.ByteString.Builder as B
68−import qualified Data.ByteString.Lazy as BSL
69−import qualified Data.Text.Lazy as LT
72+import qualified Data.ByteString.Builder as B
73+import qualified Data.ByteString.Lazy as BSL
74+import qualified Data.Text.Lazy as LT
7075
7176-- | An encoding of a JSON value.
72−newtype Encoding = Encoding {
77+--
78+-- @tag@ represents which kind of JSON the Encoding is encoding to,
79+-- we reuse 'Text' and 'Value' as tags here.
80+newtype Encoding' tag = Encoding {
7381 fromEncoding :: Builder
7482 -- ^ Acquire the underlying bytestring builder.
75− } deriving (Semigroup,Monoid,Typeable)
83+ } deriving (Typeable)
84+
85+-- | Often used synonym for 'Encoding''.
86+type Encoding = Encoding' Value
7687
7788-- | Make Encoding from Builder.
7889--
7990-- Use with care! You have to make sure that the passed Builder
8091-- is a valid JSON Encoding!
81−unsafeToEncoding :: Builder -> Encoding
92+unsafeToEncoding :: Builder -> Encoding' a
8293unsafeToEncoding = Encoding
8394
84−encodingToLazyByteString :: Encoding -> BSL.ByteString
95+encodingToLazyByteString :: Encoding' a -> BSL.ByteString
8596encodingToLazyByteString = toLazyByteString . fromEncoding
8697{-# INLINE encodingToLazyByteString #-}
8798
99+retagEncoding :: Encoding' a -> Encoding' b
100+retagEncoding = Encoding . fromEncoding
101+
88102-------------------------------------------------------------------------------
89103-- Encoding instances
90104-------------------------------------------------------------------------------
91105
92−instance Show Encoding where
106+instance Show (Encoding' a) where
93107 show (Encoding e) = show (toLazyByteString e)
94108
95−instance Eq Encoding where
109+instance Eq (Encoding' a) where
96110 Encoding a == Encoding b = toLazyByteString a == toLazyByteString b
97111
98−instance Ord Encoding where
112+instance Ord (Encoding' a) where
99113 compare (Encoding a) (Encoding b) =
100114 compare (toLazyByteString a) (toLazyByteString b)
101115
@@ -107,25 +121,30 @@ instance Ord Encoding where
107121--
108122-- > toEncoding (Person name age) = pairs ("name" .= name <> "age" .= age)
109123data Series = Empty
110− | Value Encoding
124+ | Value (Encoding' Series)
111125 deriving (Typeable)
112126
113127pair :: Text -> Encoding -> Series
114−pair name val = Value $ text name <> colon <> val
128+pair name val = pair' (text name) val
129+{-# INLINE pair #-}
130+
131+pairStr :: String -> Encoding -> Series
132+pairStr name val = pair' (string name) val
133+{-# INLINE pairStr #-}
134+
135+pair' :: Encoding' Text -> Encoding -> Series
136+pair' name val = Value $ retagEncoding $ retagEncoding name >< colon >< val
115137
116138instance Semigroup Series where
117− Empty <> a = a
118− Value a <> b =
119− Value $
120− a <> case b of
121− Empty -> mempty
122− Value c -> Encoding (char7 ',') <> c
139+ Empty <> a = a
140+ a <> Empty = a
141+ Value a <> Value b = Value (a >< comma >< b)
123142
124143instance Monoid Series where
125144 mempty = Empty
126145 mappend = (<>)
127146
128−nullEncoding :: Encoding -> Bool
147+nullEncoding :: Encoding' a -> Bool
129148nullEncoding = BSL.null . toLazyByteString . fromEncoding
130149
131150emptyArray_ :: Encoding
@@ -134,11 +153,11 @@ emptyArray_ = Encoding EB.emptyArray_
134153emptyObject_ :: Encoding
135154emptyObject_ = Encoding EB.emptyObject_
136155
137−wrapArray :: Encoding -> Encoding
138−wrapArray e = openBracket <> e <> closeBracket
156+wrapArray :: Encoding' a -> Encoding
157+wrapArray e = retagEncoding $ openBracket >< e >< closeBracket
139158
140−wrapObject :: Encoding -> Encoding
141−wrapObject e = openCurly <> e <> closeCurly
159+wrapObject :: Encoding' a -> Encoding
160+wrapObject e = retagEncoding $ openCurly >< e >< closeCurly
142161
143162null_ :: Encoding
144163null_ = Encoding EB.null_
@@ -149,41 +168,50 @@ bool False = Encoding "false"
149168
150169-- | Encode a series of key/value pairs, separated by commas.
151170pairs :: Series -> Encoding
152−pairs = brackets '{' '}'
171+pairs (Value v) = openCurly >< retagEncoding v >< closeCurly
172+pairs Empty = emptyObject_
153173{-# INLINE pairs #-}
154174
155−brackets :: Char -> Char -> Series -> Encoding
156−brackets begin end (Value v) = Encoding $
157− char7 begin <> fromEncoding v <> char7 end
158−brackets begin end Empty = Encoding (primBounded (EB.ascii2 (begin,end)) ())
159−
160175list :: (a -> Encoding) -> [a] -> Encoding
161176list _ [] = emptyArray_
162−list to' (x:xs) = Encoding $
163− char7 '[' <> fromEncoding (to' x) <> commas xs <> char7 ']'
177+list to' (x:xs) = openBracket >< to' x >< commas xs >< closeBracket
164178 where
165− commas = foldr (\v vs -> char7 ',' <> fromEncoding (to' v) <> vs) mempty
179+ commas = foldr (\v vs -> comma >< to' v >< vs) empty
166180{-# INLINE list #-}
167181
168182-- | Encode as JSON object
169183dict
170− :: (k -> Encoding) -- ^ key encoding
184+ :: (k -> Encoding' Text) -- ^ key encoding
171185 -> (v -> Encoding) -- ^ value encoding
172186 -> (forall a. (k -> v -> a -> a) -> a -> m -> a) -- ^ @foldrWithKey@ - indexed fold
173187 -> m -- ^ container
174188 -> Encoding
175−dict encodeKey encodeVal foldrWithKey = brackets '{' '}' . foldrWithKey go mempty
189+dict encodeKey encodeVal foldrWithKey = pairs . foldrWithKey go mempty
176190 where
177191 go k v c = Value (encodeKV k v) <> c
178− encodeKV k v = encodeKey k <> Encoding (char7 ':') <> encodeVal v
192+ encodeKV k v = retagEncoding (encodeKey k) >< colon >< retagEncoding (encodeVal v)
179193{-# INLINE dict #-}
180194
195+-- | Type tag for tuples contents, see 'tuple'.
196+data InArray
197+
181198infixr 6 >*<
182199-- | See 'tuple'.
183−(>*<) :: Encoding -> Encoding -> Encoding
184−Encoding a >*< Encoding b = Encoding $ a <> char7 ',' <> b
200+(>*<) :: Encoding' a -> Encoding' b -> Encoding' InArray
201+a >*< b = retagEncoding a >< comma >< retagEncoding b
185202{-# INLINE (>*<) #-}
186203
204+empty :: Encoding' a
205+empty = Encoding mempty
206+
207+econcat :: [Encoding' a] -> Encoding' a
208+econcat = foldr (><) empty
209+
210+infixr 6 ><
211+(><) :: Encoding' a -> Encoding' a -> Encoding' a
212+Encoding a >< Encoding b = Encoding (a <> b)
213+{-# INLINE (><) #-}
214+
187215-- | Encode as a tuple.
188216--
189217-- @
@@ -191,26 +219,26 @@ Encoding a >*< Encoding b = Encoding $ a <> char7 ',' <> b
191219-- toEncoding a >*<
192220-- toEncoding b >*<
193221-- toEncoding c
194−tuple :: Encoding -> Encoding
195−tuple b = Encoding (char7 '[' <> fromEncoding b <> char7 ']')
222+tuple :: Encoding' InArray -> Encoding
223+tuple b = retagEncoding $ openBracket >< b >< closeBracket
196224{-# INLINE tuple #-}
197225
198−text :: Text -> Encoding
226+text :: Text -> Encoding' a
199227text = Encoding . EB.text
200228
201−lazyText :: LT.Text -> Encoding
229+lazyText :: LT.Text -> Encoding' a
202230lazyText t = Encoding $
203231 B.char7 '"' <>
204232 LT.foldrChunks (\x xs -> EB.unquoted x <> xs) (B.char7 '"') t
205233
206−string :: String -> Encoding
234+string :: String -> Encoding' a
207235string = Encoding . EB.string
208236
209237-------------------------------------------------------------------------------
210238-- chars
211239-------------------------------------------------------------------------------
212240
213−comma, colon, openBracket, closeBracket, openCurly, closeCurly :: Encoding
241+comma, colon, openBracket, closeBracket, openCurly, closeCurly :: Encoding' a
214242comma = Encoding $ char7 ','
215243colon = Encoding $ char7 ':'
216244openBracket = Encoding $ char7 '['
@@ -274,66 +302,65 @@ realFloatToEncoding e d
274302-- Decimal numbers as Text
275303-------------------------------------------------------------------------------
276304
277−int8Text :: Int8 -> Encoding
305+int8Text :: Int8 -> Encoding' a
278306int8Text = Encoding . EB.quote . B.int8Dec
279307
280−int16Text :: Int16 -> Encoding
308+int16Text :: Int16 -> Encoding' a
281309int16Text = Encoding . EB.quote . B.int16Dec
282310
283−int32Text :: Int32 -> Encoding
311+int32Text :: Int32 -> Encoding' a
284312int32Text = Encoding . EB.quote . B.int32Dec
285313
286−int64Text :: Int64 -> Encoding
314+int64Text :: Int64 -> Encoding' a
287315int64Text = Encoding . EB.quote . B.int64Dec
288316
289−intText :: Int -> Encoding
317+intText :: Int -> Encoding' a
290318intText = Encoding . EB.quote . B.intDec
291319
292−word8Text :: Word8 -> Encoding
320+word8Text :: Word8 -> Encoding' a
293321word8Text = Encoding . EB.quote . B.word8Dec
294322
295−word16Text :: Word16 -> Encoding
323+word16Text :: Word16 -> Encoding' a
296324word16Text = Encoding . EB.quote . B.word16Dec
297325
298−word32Text :: Word32 -> Encoding
326+word32Text :: Word32 -> Encoding' a
299327word32Text = Encoding . EB.quote . B.word32Dec
300328
301−word64Text :: Word64 -> Encoding
329+word64Text :: Word64 -> Encoding' a
302330word64Text = Encoding . EB.quote . B.word64Dec
303331
304−wordText :: Word -> Encoding
332+wordText :: Word -> Encoding' a
305333wordText = Encoding . EB.quote . B.wordDec
306334
307−integerText :: Integer -> Encoding
335+integerText :: Integer -> Encoding' a
308336integerText = Encoding . EB.quote . B.integerDec
309337
310−-- | TODO: check infinite and nan?
311−floatText :: Float -> Encoding
338+floatText :: Float -> Encoding' a
312339floatText = Encoding . EB.quote . B.floatDec
313340
314−doubleText :: Double -> Encoding
341+doubleText :: Double -> Encoding' a
315342doubleText = Encoding . EB.quote . B.doubleDec
316343
317−scientificText :: Scientific -> Encoding
344+scientificText :: Scientific -> Encoding' a
318345scientificText = Encoding . EB.quote . EB.scientific
319346
320347-------------------------------------------------------------------------------
321348-- time
322349-------------------------------------------------------------------------------
323350
324−day :: Day -> Encoding
351+day :: Day -> Encoding' a
325352day = Encoding . EB.quote . EB.day
326353
327−localTime :: LocalTime -> Encoding
354+localTime :: LocalTime -> Encoding' a
328355localTime = Encoding . EB.quote . EB.localTime
329356
330−utcTime :: UTCTime -> Encoding
357+utcTime :: UTCTime -> Encoding' a
331358utcTime = Encoding . EB.quote . EB.utcTime
332359
333−timeOfDay :: TimeOfDay -> Encoding
360+timeOfDay :: TimeOfDay -> Encoding' a
334361timeOfDay = Encoding . EB.quote . EB.timeOfDay
335362
336−zonedTime :: ZonedTime -> Encoding
363+zonedTime :: ZonedTime -> Encoding' a
337364zonedTime = Encoding . EB.quote . EB.zonedTime
338365
339366-------------------------------------------------------------------------------
Data/Aeson/Internal.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12-- |
23-- Module: Data.Aeson.Internal
34-- Copyright: (c) 2015-2016 Bryan O'Sullivan
@@ -22,5 +23,6 @@ module Data.Aeson.Internal
2223 , iparse
2324 ) where
2425
26+
2527import Data.Aeson.Types.Internal
2628import Data.Aeson.Types.FromJSON (ifromJSON)
Data/Aeson/Internal/Functions.hs+5−1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12-- |
23-- Module: Data.Aeson.Functions
34-- Copyright: (c) 2011-2016 Bryan O'Sullivan
@@ -8,11 +9,14 @@
89-- Portability: portable
910
1011module Data.Aeson.Internal.Functions
11− ( mapHashKeyVal
12+ (
13+ mapHashKeyVal
1214 , mapKeyVal
1315 , mapKey
1416 ) where
1517
18+import Prelude.Compat
19+
1620import Data.Hashable (Hashable)
1721import qualified Data.HashMap.Strict as H
1822import qualified Data.Map as M
Data/Aeson/Internal/Time.hs+1−38
@@ -17,41 +17,4 @@ module Data.Aeson.Internal.Time
1717 , toTimeOfDay64
1818 ) where
1919
20−import Data.Fixed (Pico)
21−import Data.Int (Int64)
22−import Data.Time
23−import Unsafe.Coerce (unsafeCoerce)
24−
25−#if MIN_VERSION_base(4,7,0)
26−
27−import Data.Fixed (Fixed(MkFixed))
28−
29−toPico :: Integer -> Pico
30−toPico = MkFixed
31−
32−fromPico :: Pico -> Integer
33−fromPico (MkFixed i) = i
34−
35−#else
36−
37−toPico :: Integer -> Pico
38−toPico = unsafeCoerce
39−
40−fromPico :: Pico -> Integer
41−fromPico = unsafeCoerce
42−
43−#endif
44−
45−-- | Like TimeOfDay, but using a fixed-width integer for seconds.
46−data TimeOfDay64 = TOD {-# UNPACK #-} !Int
47− {-# UNPACK #-} !Int
48− {-# UNPACK #-} !Int64
49−
50−diffTimeOfDay64 :: DiffTime -> TimeOfDay64
51−diffTimeOfDay64 t = TOD (fromIntegral h) (fromIntegral m) s
52− where (h,mp) = fromIntegral pico `quotRem` 3600000000000000
53− (m,s) = mp `quotRem` 60000000000000
54− pico = unsafeCoerce t :: Integer
55−
56−toTimeOfDay64 :: TimeOfDay -> TimeOfDay64
57−toTimeOfDay64 (TimeOfDay h m s) = TOD h m (fromIntegral (fromPico s))
20+import Data.Attoparsec.Time.Internal
Data/Aeson/Parser.hs+14−5
@@ -1,5 +1,4 @@
1−{-# LANGUAGE BangPatterns, OverloadedStrings #-}
2−
1+{-# LANGUAGE NoImplicitPrelude #-}
32-- |
43-- Module: Data.Aeson.Parser
54-- Copyright: (c) 2012-2016 Bryan O'Sullivan
@@ -35,10 +34,21 @@ module Data.Aeson.Parser
3534 json
3635 , value
3736 , jstring
37+ , scientific
38+ -- ** Handling objects with duplicate keys
39+ , jsonWith
40+ , jsonLast
41+ , jsonAccum
42+ , jsonNoDup
3843 -- * Strict parsers
3944 -- $strict
4045 , json'
4146 , value'
47+ -- ** Handling objects with duplicate keys
48+ , jsonWith'
49+ , jsonLast'
50+ , jsonAccum'
51+ , jsonNoDup'
4252 -- * Decoding without FromJSON instances
4353 , decodeWith
4454 , decodeStrictWith
@@ -46,9 +56,8 @@ module Data.Aeson.Parser
4656 , eitherDecodeStrictWith
4757 ) where
4858
49−import Data.Aeson.Parser.Internal (decodeStrictWith, decodeWith,
50− eitherDecodeStrictWith, eitherDecodeWith,
51− json, json', jstring, value, value')
59+
60+import Data.Aeson.Parser.Internal
5261
5362-- $lazy
5463--
Data/Aeson/Parser/Internal.hs+325−198
@@ -1,8 +1,14 @@
1−{-# LANGUAGE BangPatterns, CPP, OverloadedStrings #-}
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE CPP #-}
3+{-# LANGUAGE NoImplicitPrelude #-}
4+{-# LANGUAGE OverloadedStrings #-}
25#if MIN_VERSION_ghc_prim(0,3,1)
36{-# LANGUAGE MagicHash #-}
47#endif
5−
8+#if __GLASGOW_HASKELL__ <= 710 && __GLASGOW_HASKELL__ >= 706
9+-- Work around a compiler bug
10+{-# OPTIONS_GHC -fsimpl-tick-factor=200 #-}
11+#endif
612-- |
713-- Module: Data.Aeson.Parser.Internal
814-- Copyright: (c) 2011-2016 Bryan O'Sullivan
@@ -19,52 +25,56 @@ module Data.Aeson.Parser.Internal
1925 (
2026 -- * Lazy parsers
2127 json, jsonEOF
28+ , jsonWith
29+ , jsonLast
30+ , jsonAccum
31+ , jsonNoDup
2232 , value
2333 , jstring
34+ , jstring_
35+ , scientific
2436 -- * Strict parsers
2537 , json', jsonEOF'
38+ , jsonWith'
39+ , jsonLast'
40+ , jsonAccum'
41+ , jsonNoDup'
2642 , value'
2743 -- * Helpers
2844 , decodeWith
2945 , decodeStrictWith
3046 , eitherDecodeWith
3147 , eitherDecodeStrictWith
48+ -- ** Handling objects with duplicate keys
49+ , fromListAccum
50+ , parseListNoDup
3251 ) where
3352
34−import Control.Monad.IO.Class (liftIO)
35−import Data.Aeson.Types.Internal (IResult(..), JSONPath, Result(..), Value(..))
36−import Data.Attoparsec.ByteString.Char8 (Parser, char, endOfInput, scientific,
37− skipSpace, string)
38−import Data.Bits ((.|.), shiftL)
39−import Data.ByteString.Internal (ByteString(..))
40−import Data.Char (chr)
53+import Prelude.Compat
54+
55+import Control.Applicative ((<|>))
56+import Control.Monad (void, when)
57+import Data.Aeson.Types.Internal (IResult(..), JSONPath, Object, Result(..), Value(..))
58+import Data.Attoparsec.ByteString.Char8 (Parser, char, decimal, endOfInput, isDigit_w8, signed, string)
59+import Data.Function (fix)
60+import Data.Functor.Compat (($>))
61+import Data.Scientific (Scientific)
4162import Data.Text (Text)
42−import Data.Text.Encoding (decodeUtf8')
43−import Data.Text.Internal.Encoding.Utf8 (ord2, ord3, ord4)
44−import Data.Text.Internal.Unsafe.Char (ord)
45−import Data.Vector as Vector (Vector, empty, fromList, reverse)
46−import Data.Word (Word8)
47−import Foreign.ForeignPtr (withForeignPtr)
48−import Foreign.Ptr (Ptr, plusPtr)
49−import Foreign.Ptr (minusPtr)
50−import Foreign.Storable (poke)
51−import System.IO.Unsafe (unsafePerformIO)
63+import Data.Vector (Vector)
64+import qualified Data.Vector as Vector (empty, fromList, fromListN, reverse)
5265import qualified Data.Attoparsec.ByteString as A
5366import qualified Data.Attoparsec.Lazy as L
54−import qualified Data.Attoparsec.Zepto as Z
5567import qualified Data.ByteString as B
56−import qualified Data.ByteString.Internal as B
57−import qualified Data.ByteString.Lazy as L
5868import qualified Data.ByteString.Unsafe as B
69+import qualified Data.ByteString.Lazy as L
5970import qualified Data.HashMap.Strict as H
60−
61−#if !MIN_VERSION_base(4,8,0)
62−import Control.Applicative ((*>), (<$>), (<*), pure)
63−#endif
71+import qualified Data.Scientific as Sci
72+import Data.Aeson.Parser.Unescape (unescapeText)
6473
6574#if MIN_VERSION_ghc_prim(0,3,1)
66−import GHC.Base (Int#, (==#), isTrue#, orI#, word2Int#)
75+import GHC.Base (Int#, (==#), isTrue#, word2Int#, orI#, andI#)
6776import GHC.Word (Word8(W8#))
77+import qualified Data.Text.Encoding as TE
6878#endif
6979
7080#define BACKSLASH 92
@@ -83,7 +93,7 @@ import GHC.Word (Word8(W8#))
8393#define C_n 110
8494#define C_t 116
8595
86−-- | Parse a top-level JSON value.
96+-- | Parse any JSON value.
8797--
8898-- The conversion of a parsed value to a Haskell value is deferred
8999-- until the Haskell value is needed. This may improve performance if
@@ -93,10 +103,15 @@ import GHC.Word (Word8(W8#))
93103-- This function is an alias for 'value'. In aeson 0.8 and earlier, it
94104-- parsed only object or array types, in conformance with the
95105-- now-obsolete RFC 4627.
106+--
107+-- ==== Warning
108+--
109+-- If an object contains duplicate keys, only the first one will be kept.
110+-- For a more flexible alternative, see 'jsonWith'.
96111json :: Parser Value
97112json = value
98113
99−-- | Parse a top-level JSON value.
114+-- | Parse any JSON value.
100115--
101116-- This is a strict version of 'json' which avoids building up thunks
102117-- during parsing; it performs all conversions immediately. Prefer
@@ -105,46 +120,64 @@ json = value
105120-- This function is an alias for 'value''. In aeson 0.8 and earlier, it
106121-- parsed only object or array types, in conformance with the
107122-- now-obsolete RFC 4627.
123+--
124+-- ==== Warning
125+--
126+-- If an object contains duplicate keys, only the first one will be kept.
127+-- For a more flexible alternative, see 'jsonWith''.
108128json' :: Parser Value
109129json' = value'
110130
111−object_ :: Parser Value
112−object_ = {-# SCC "object_" #-} Object <$> objectValues jstring value
131+-- Open recursion: object_, object_', array_, array_' are parameterized by the
132+-- toplevel Value parser to be called recursively, to keep the parameter
133+-- mkObject outside of the recursive loop for proper inlining.
134+
135+object_ :: ([(Text, Value)] -> Either String Object) -> Parser Value -> Parser Value
136+object_ mkObject val = {-# SCC "object_" #-} Object <$> objectValues mkObject jstring val
137+{-# INLINE object_ #-}
113138
114−object_' :: Parser Value
115−object_' = {-# SCC "object_'" #-} do
116− !vals <- objectValues jstring' value'
139+object_' :: ([(Text, Value)] -> Either String Object) -> Parser Value -> Parser Value
140+object_' mkObject val' = {-# SCC "object_'" #-} do
141+ !vals <- objectValues mkObject jstring' val'
117142 return (Object vals)
118143 where
119144 jstring' = do
120145 !s <- jstring
121146 return s
147+{-# INLINE object_' #-}
122148
123−objectValues :: Parser Text -> Parser Value -> Parser (H.HashMap Text Value)
124−objectValues str val = do
149+objectValues :: ([(Text, Value)] -> Either String Object)
150+ -> Parser Text -> Parser Value -> Parser (H.HashMap Text Value)
151+objectValues mkObject str val = do
125152 skipSpace
126153 w <- A.peekWord8'
127154 if w == CLOSE_CURLY
128155 then A.anyWord8 >> return H.empty
129− else loop H.empty
156+ else loop []
130157 where
131− loop m0 = do
132− k <- str <* skipSpace <* char ':'
133− v <- val <* skipSpace
134− let !m = H.insert k v m0
135− ch <- A.satisfy $ \w -> w == COMMA || w == CLOSE_CURLY
158+ -- Why use acc pattern here, you may ask? because 'H.fromList' use 'unsafeInsert'
159+ -- and it's much faster because it's doing in place update to the 'HashMap'!
160+ loop acc = do
161+ k <- (str A.<?> "object key") <* skipSpace <* (char ':' A.<?> "':'")
162+ v <- (val A.<?> "object value") <* skipSpace
163+ ch <- A.satisfy (\w -> w == COMMA || w == CLOSE_CURLY) A.<?> "',' or '}'"
164+ let acc' = (k, v) : acc
136165 if ch == COMMA
137− then skipSpace >> loop m
138− else return m
166+ then skipSpace >> loop acc'
167+ else case mkObject acc' of
168+ Left err -> fail err
169+ Right obj -> pure obj
139170{-# INLINE objectValues #-}
140171
141−array_ :: Parser Value
142−array_ = {-# SCC "array_" #-} Array <$> arrayValues value
172+array_ :: Parser Value -> Parser Value
173+array_ val = {-# SCC "array_" #-} Array <$> arrayValues val
174+{-# INLINE array_ #-}
143175
144−array_' :: Parser Value
145−array_' = {-# SCC "array_'" #-} do
146− !vals <- arrayValues value'
176+array_' :: Parser Value -> Parser Value
177+array_' val = {-# SCC "array_'" #-} do
178+ !vals <- arrayValues val
147179 return (Array vals)
180+{-# INLINE array_' #-}
148181
149182arrayValues :: Parser Value -> Parser (Vector Value)
150183arrayValues val = do
@@ -152,60 +185,136 @@ arrayValues val = do
152185 w <- A.peekWord8'
153186 if w == CLOSE_SQUARE
154187 then A.anyWord8 >> return Vector.empty
155− else loop []
188+ else loop [] 1
156189 where
157− loop acc = do
158− v <- val <* skipSpace
159− ch <- A.satisfy $ \w -> w == COMMA || w == CLOSE_SQUARE
190+ loop acc !len = do
191+ v <- (val A.<?> "json list value") <* skipSpace
192+ ch <- A.satisfy (\w -> w == COMMA || w == CLOSE_SQUARE) A.<?> "',' or ']'"
160193 if ch == COMMA
161− then skipSpace >> loop (v:acc)
162− else return (Vector.reverse (Vector.fromList (v:acc)))
194+ then skipSpace >> loop (v:acc) (len+1)
195+ else return (Vector.reverse (Vector.fromListN len (v:acc)))
163196{-# INLINE arrayValues #-}
164197
165−-- | Parse any JSON value. You should usually 'json' in preference to
166−-- this function, as this function relaxes the object-or-array
167−-- requirement of RFC 4627.
168−--
169−-- In particular, be careful in using this function if you think your
170−-- code might interoperate with Javascript. A na&#xef;ve Javascript
171−-- library that parses JSON data using @eval@ is vulnerable to attack
172−-- unless the encoded data represents an object or an array. JSON
173−-- implementations in other languages conform to that same restriction
174−-- to preserve interoperability and security.
198+-- | Parse any JSON value. Synonym of 'json'.
175199value :: Parser Value
176−value = do
200+value = jsonWith (pure . H.fromList)
201+
202+-- | Parse any JSON value.
203+--
204+-- This parser is parameterized by a function to construct an 'Object'
205+-- from a raw list of key-value pairs, where duplicates are preserved.
206+-- The pairs appear in __reverse order__ from the source.
207+--
208+-- ==== __Examples__
209+--
210+-- 'json' keeps only the first occurence of each key, using 'HashMap.Lazy.fromList'.
211+--
212+-- @
213+-- 'json' = 'jsonWith' ('Right' '.' 'H.fromList')
214+-- @
215+--
216+-- 'jsonLast' keeps the last occurence of each key, using
217+-- @'HashMap.Lazy.fromListWith' ('const' 'id')@.
218+--
219+-- @
220+-- 'jsonLast' = 'jsonWith' ('Right' '.' 'HashMap.Lazy.fromListWith' ('const' 'id'))
221+-- @
222+--
223+-- 'jsonAccum' keeps wraps all values in arrays to keep duplicates, using
224+-- 'fromListAccum'.
225+--
226+-- @
227+-- 'jsonAccum' = 'jsonWith' ('Right' . 'fromListAccum')
228+-- @
229+--
230+-- 'jsonNoDup' fails if any object contains duplicate keys, using 'parseListNoDup'.
231+--
232+-- @
233+-- 'jsonNoDup' = 'jsonWith' 'parseListNoDup'
234+-- @
235+jsonWith :: ([(Text, Value)] -> Either String Object) -> Parser Value
236+jsonWith mkObject = fix $ \value_ -> do
177237 skipSpace
178238 w <- A.peekWord8'
179239 case w of
180240 DOUBLE_QUOTE -> A.anyWord8 *> (String <$> jstring_)
181− OPEN_CURLY -> A.anyWord8 *> object_
182− OPEN_SQUARE -> A.anyWord8 *> array_
183− C_f -> string "false" *> pure (Bool False)
184− C_t -> string "true" *> pure (Bool True)
185− C_n -> string "null" *> pure Null
241+ OPEN_CURLY -> A.anyWord8 *> object_ mkObject value_
242+ OPEN_SQUARE -> A.anyWord8 *> array_ value_
243+ C_f -> string "false" $> Bool False
244+ C_t -> string "true" $> Bool True
245+ C_n -> string "null" $> Null
186246 _ | w >= 48 && w <= 57 || w == 45
187247 -> Number <$> scientific
188248 | otherwise -> fail "not a valid json value"
249+{-# INLINE jsonWith #-}
250+
251+-- | Variant of 'json' which keeps only the last occurence of every key.
252+jsonLast :: Parser Value
253+jsonLast = jsonWith (Right . H.fromListWith (const id))
254+
255+-- | Variant of 'json' wrapping all object mappings in 'Array' to preserve
256+-- key-value pairs with the same keys.
257+jsonAccum :: Parser Value
258+jsonAccum = jsonWith (Right . fromListAccum)
259+
260+-- | Variant of 'json' which fails if any object contains duplicate keys.
261+jsonNoDup :: Parser Value
262+jsonNoDup = jsonWith parseListNoDup
263+
264+-- | @'fromListAccum' kvs@ is an object mapping keys to arrays containing all
265+-- associated values from the original list @kvs@.
266+--
267+-- >>> fromListAccum [("apple", Bool True), ("apple", Bool False), ("orange", Bool False)]
268+-- fromList [("apple", [Bool False, Bool True]), ("orange", [Bool False])]
269+fromListAccum :: [(Text, Value)] -> Object
270+fromListAccum =
271+ fmap (Array . Vector.fromList . ($ [])) . H.fromListWith (.) . (fmap . fmap) (:)
272+
273+-- | @'fromListNoDup' kvs@ fails if @kvs@ contains duplicate keys.
274+parseListNoDup :: [(Text, Value)] -> Either String Object
275+parseListNoDup =
276+ H.traverseWithKey unwrap . H.fromListWith (\_ _ -> Nothing) . (fmap . fmap) Just
277+ where
278+ unwrap k Nothing = Left $ "found duplicate key: " ++ show k
279+ unwrap _ (Just v) = Right v
189280
190−-- | Strict version of 'value'. See also 'json''.
281+-- | Strict version of 'value'. Synonym of 'json''.
191282value' :: Parser Value
192−value' = do
283+value' = jsonWith' (pure . H.fromList)
284+
285+-- | Strict version of 'jsonWith'.
286+jsonWith' :: ([(Text, Value)] -> Either String Object) -> Parser Value
287+jsonWith' mkObject = fix $ \value_ -> do
193288 skipSpace
194289 w <- A.peekWord8'
195290 case w of
196291 DOUBLE_QUOTE -> do
197292 !s <- A.anyWord8 *> jstring_
198293 return (String s)
199− OPEN_CURLY -> A.anyWord8 *> object_'
200− OPEN_SQUARE -> A.anyWord8 *> array_'
201− C_f -> string "false" *> pure (Bool False)
202− C_t -> string "true" *> pure (Bool True)
203− C_n -> string "null" *> pure Null
294+ OPEN_CURLY -> A.anyWord8 *> object_' mkObject value_
295+ OPEN_SQUARE -> A.anyWord8 *> array_' value_
296+ C_f -> string "false" $> Bool False
297+ C_t -> string "true" $> Bool True
298+ C_n -> string "null" $> Null
204299 _ | w >= 48 && w <= 57 || w == 45
205300 -> do
206301 !n <- scientific
207302 return (Number n)
208303 | otherwise -> fail "not a valid json value"
304+{-# INLINE jsonWith' #-}
305+
306+-- | Variant of 'json'' which keeps only the last occurence of every key.
307+jsonLast' :: Parser Value
308+jsonLast' = jsonWith' (pure . H.fromListWith (const id))
309+
310+-- | Variant of 'json'' wrapping all object mappings in 'Array' to preserve
311+-- key-value pairs with the same keys.
312+jsonAccum' :: Parser Value
313+jsonAccum' = jsonWith' (pure . fromListAccum)
314+
315+-- | Variant of 'json'' which fails if any object contains duplicate keys.
316+jsonNoDup' :: Parser Value
317+jsonNoDup' = jsonWith' parseListNoDup
209318
210319-- | Parse a quoted JSON string.
211320jstring :: Parser Text
@@ -215,101 +324,48 @@ jstring = A.word8 DOUBLE_QUOTE *> jstring_
215324jstring_ :: Parser Text
216325{-# INLINE jstring_ #-}
217326jstring_ = {-# SCC "jstring_" #-} do
218− (s, fin) <- A.runScanner startState go
219− _ <- A.anyWord8
220− s1 <- if isEscaped fin
221− then case unescape s of
222− Right r -> return r
223− Left err -> fail err
224− else return s
225− case decodeUtf8' s1 of
226− Right r -> return r
227− Left err -> fail $ show err
228− where
229327#if MIN_VERSION_ghc_prim(0,3,1)
230− isEscaped (S _ escaped) = isTrue# escaped
328+ (s, S _ escaped) <- A.runScanner startState go <* A.anyWord8
329+ -- We escape only if there are
330+ -- non-ascii (over 7bit) characters or backslash present.
331+ --
332+ -- Note: if/when text will have fast ascii -> text conversion
333+ -- (e.g. uses utf8 encoding) we can have further speedup.
334+ if isTrue# escaped
335+ then case unescapeText s of
336+ Right r -> return r
337+ Left err -> fail $ show err
338+ else return (TE.decodeUtf8 s)
339+ where
231340 startState = S 0# 0#
232− go (S a b) (W8# c)
233− | isTrue# a = Just (S 0# b)
234− | isTrue# (word2Int# c ==# 34#) = Nothing -- double quote
235− | otherwise = let a' = word2Int# c ==# 92# -- backslash
236− in Just (S a' (orI# a' b))
341+ go (S skip escaped) (W8# c)
342+ | isTrue# skip = Just (S 0# escaped')
343+ | isTrue# (w ==# 34#) = Nothing -- double quote
344+ | otherwise = Just (S skip' escaped')
345+ where
346+ w = word2Int# c
347+ skip' = w ==# 92# -- backslash
348+ escaped' = escaped
349+ `orI#` (w `andI#` 0x80# ==# 0x80#) -- c >= 0x80
350+ `orI#` skip'
351+ `orI#` (w `andI#` 0x1f# ==# w) -- c < 0x20
237352
238353data S = S Int# Int#
239354#else
240− isEscaped (S _ escaped) = escaped
241− startState = S False False
242− go (S a b) c
243− | a = Just (S False b)
355+ s <- A.scan startState go <* A.anyWord8
356+ case unescapeText s of
357+ Right r -> return r
358+ Left err -> fail $ show err
359+ where
360+ startState = False
361+ go a c
362+ | a = Just False
244363 | c == DOUBLE_QUOTE = Nothing
245364 | otherwise = let a' = c == backslash
246− in Just (S a' (a' || b))
365+ in Just a'
247366 where backslash = BACKSLASH
248−
249−data S = S !Bool !Bool
250367#endif
251368
252−unescape :: ByteString -> Either String ByteString
253−unescape s = unsafePerformIO $ do
254− let len = B.length s
255− fp <- B.mallocByteString len
256− -- We perform no bounds checking when writing to the destination
257− -- string, as unescaping always makes it shorter than the source.
258− withForeignPtr fp $ \ptr -> do
259− ret <- Z.parseT (go ptr) s
260− case ret of
261− Left err -> return (Left err)
262− Right p -> do
263− let newlen = p `minusPtr` ptr
264− slop = len - newlen
265− Right <$> if slop >= 128 && slop >= len `quot` 4
266− then B.create newlen $ \np -> B.memcpy np ptr newlen
267− else return (PS fp 0 newlen)
268− where
269− go ptr = do
270− h <- Z.takeWhile (/=BACKSLASH)
271− let rest = do
272− start <- Z.take 2
273− let !slash = B.unsafeHead start
274− !t = B.unsafeIndex start 1
275− escape = case B.elemIndex t "\"\\/ntbrfu" of
276− Just i -> i
277− _ -> 255
278− if slash /= BACKSLASH || escape == 255
279− then fail "invalid JSON escape sequence"
280− else
281− if t /= 117 -- 'u'
282− then copy h ptr >>= word8 (B.unsafeIndex mapping escape) >>= go
283− else do
284− a <- hexQuad
285− if a < 0xd800 || a > 0xdfff
286− then copy h ptr >>= charUtf8 (chr a) >>= go
287− else do
288− b <- Z.string "\\u" *> hexQuad
289− if a <= 0xdbff && b >= 0xdc00 && b <= 0xdfff
290− then let !c = ((a - 0xd800) `shiftL` 10) +
291− (b - 0xdc00) + 0x10000
292− in copy h ptr >>= charUtf8 (chr c) >>= go
293− else fail "invalid UTF-16 surrogates"
294− done <- Z.atEnd
295− if done
296− then copy h ptr
297− else rest
298− mapping = "\"\\/\n\t\b\r\f"
299−
300−hexQuad :: Z.ZeptoT IO Int
301−hexQuad = do
302− s <- Z.take 4
303− let hex n | w >= C_0 && w <= C_9 = w - C_0
304− | w >= C_a && w <= C_f = w - 87
305− | w >= C_A && w <= C_F = w - 55
306− | otherwise = 255
307− where w = fromIntegral $ B.unsafeIndex s n
308− a = hex 0; b = hex 1; c = hex 2; d = hex 3
309− if (a .|. b .|. c .|. d) /= 255
310− then return $! d .|. (c `shiftL` 4) .|. (b `shiftL` 8) .|. (a `shiftL` 12)
311− else fail "invalid hex escape"
312−
313369decodeWith :: Parser Value -> (Value -> Result a) -> L.ByteString -> Maybe a
314370decodeWith p to s =
315371 case L.parse p s of
@@ -334,7 +390,12 @@ eitherDecodeWith p to s =
334390 L.Done _ v -> case to v of
335391 ISuccess a -> Right a
336392 IError path msg -> Left (path, msg)
337− L.Fail _ _ msg -> Left ([], msg)
393+ L.Fail _ ctx msg -> Left ([], buildMsg ctx msg)
394+ where
395+ buildMsg :: [String] -> String -> String
396+ buildMsg [] msg = msg
397+ buildMsg (expectation:_) msg =
398+ msg ++ ". Expecting " ++ expectation
338399{-# INLINE eitherDecodeWith #-}
339400
340401eitherDecodeStrictWith :: Parser Value -> (Value -> IResult a) -> B.ByteString
@@ -374,37 +435,103 @@ jsonEOF = json <* skipSpace <* endOfInput
374435jsonEOF' :: Parser Value
375436jsonEOF' = json' <* skipSpace <* endOfInput
376437
377−word8 :: Word8 -> Ptr Word8 -> Z.ZeptoT IO (Ptr Word8)
378−word8 w ptr = do
379− liftIO $ poke ptr w
380− return $! ptr `plusPtr` 1
381−
382−copy :: ByteString -> Ptr Word8 -> Z.ZeptoT IO (Ptr Word8)
383−copy (PS fp off len) ptr =
384− liftIO . withForeignPtr fp $ \src -> do
385− B.memcpy ptr (src `plusPtr` off) len
386− return $! ptr `plusPtr` len
387−
388−charUtf8 :: Char -> Ptr Word8 -> Z.ZeptoT IO (Ptr Word8)
389−charUtf8 ch ptr
390− | ch < '\x80' = liftIO $ do
391− poke ptr (fromIntegral (ord ch))
392− return $! ptr `plusPtr` 1
393− | ch < '\x800' = liftIO $ do
394− let (a,b) = ord2 ch
395− poke ptr a
396− poke (ptr `plusPtr` 1) b
397− return $! ptr `plusPtr` 2
398− | ch < '\xffff' = liftIO $ do
399− let (a,b,c) = ord3 ch
400− poke ptr a
401− poke (ptr `plusPtr` 1) b
402− poke (ptr `plusPtr` 2) c
403− return $! ptr `plusPtr` 3
404− | otherwise = liftIO $ do
405− let (a,b,c,d) = ord4 ch
406− poke ptr a
407− poke (ptr `plusPtr` 1) b
408− poke (ptr `plusPtr` 2) c
409− poke (ptr `plusPtr` 3) d
410− return $! ptr `plusPtr` 4
438+-- | The only valid whitespace in a JSON document is space, newline,
439+-- carriage return, and tab.
440+skipSpace :: Parser ()
441+skipSpace = A.skipWhile $ \w -> w == 0x20 || w == 0x0a || w == 0x0d || w == 0x09
442+{-# INLINE skipSpace #-}
443+
444+------------------ Copy-pasted and adapted from attoparsec ------------------
445+
446+-- A strict pair
447+data SP = SP !Integer {-# UNPACK #-}!Int
448+
449+decimal0 :: Parser Integer
450+decimal0 = do
451+ let zero = 48
452+ digits <- A.takeWhile1 isDigit_w8
453+ if B.length digits > 1 && B.unsafeHead digits == zero
454+ then fail "leading zero"
455+ else return (bsToInteger digits)
456+
457+-- | Parse a JSON number.
458+scientific :: Parser Scientific
459+scientific = do
460+ let minus = 45
461+ plus = 43
462+ sign <- A.peekWord8'
463+ let !positive = sign == plus || sign /= minus
464+ when (sign == plus || sign == minus) $
465+ void A.anyWord8
466+
467+ n <- decimal0
468+
469+ let f fracDigits = SP (B.foldl' step n fracDigits)
470+ (negate $ B.length fracDigits)
471+ step a w = a * 10 + fromIntegral (w - 48)
472+
473+ dotty <- A.peekWord8
474+ -- '.' -> ascii 46
475+ SP c e <- case dotty of
476+ Just 46 -> A.anyWord8 *> (f <$> A.takeWhile1 isDigit_w8)
477+ _ -> pure (SP n 0)
478+
479+ let !signedCoeff | positive = c
480+ | otherwise = -c
481+
482+ let littleE = 101
483+ bigE = 69
484+ (A.satisfy (\ex -> ex == littleE || ex == bigE) *>
485+ fmap (Sci.scientific signedCoeff . (e +)) (signed decimal)) <|>
486+ return (Sci.scientific signedCoeff e)
487+{-# INLINE scientific #-}
488+
489+------------------ Copy-pasted and adapted from base ------------------------
490+
491+bsToInteger :: B.ByteString -> Integer
492+bsToInteger bs
493+ | l > 40 = valInteger 10 l [ fromIntegral (w - 48) | w <- B.unpack bs ]
494+ | otherwise = bsToIntegerSimple bs
495+ where
496+ l = B.length bs
497+
498+bsToIntegerSimple :: B.ByteString -> Integer
499+bsToIntegerSimple = B.foldl' step 0 where
500+ step a b = a * 10 + fromIntegral (b - 48) -- 48 = '0'
501+
502+-- A sub-quadratic algorithm for Integer. Pairs of adjacent radix b
503+-- digits are combined into a single radix b^2 digit. This process is
504+-- repeated until we are left with a single digit. This algorithm
505+-- performs well only on large inputs, so we use the simple algorithm
506+-- for smaller inputs.
507+valInteger :: Integer -> Int -> [Integer] -> Integer
508+valInteger = go
509+ where
510+ go :: Integer -> Int -> [Integer] -> Integer
511+ go _ _ [] = 0
512+ go _ _ [d] = d
513+ go b l ds
514+ | l > 40 = b' `seq` go b' l' (combine b ds')
515+ | otherwise = valSimple b ds
516+ where
517+ -- ensure that we have an even number of digits
518+ -- before we call combine:
519+ ds' = if even l then ds else 0 : ds
520+ b' = b * b
521+ l' = (l + 1) `quot` 2
522+
523+ combine b (d1 : d2 : ds) = d `seq` (d : combine b ds)
524+ where
525+ d = d1 * b + d2
526+ combine _ [] = []
527+ combine _ [_] = errorWithoutStackTrace "this should not happen"
528+
529+-- The following algorithm is only linear for types whose Num operations
530+-- are in constant time.
531+valSimple :: Integer -> [Integer] -> Integer
532+valSimple base = go 0
533+ where
534+ go r [] = r
535+ go r (d : ds) = r' `seq` go r' ds
536+ where
537+ r' = r * base + fromIntegral d
Data/Aeson/Parser/Time.hs+21−104
@@ -1,14 +1,4 @@
1−{-# LANGUAGE BangPatterns, CPP, ScopedTypeVariables #-}
2−
3−-- |
4−-- Module: Data.Aeson.Parser.Time
5−-- Copyright: (c) 2015-2016 Bryan O'Sullivan
6−-- License: BSD3
7−-- Maintainer: Bryan O'Sullivan <bos@serpentine.com>
8−-- Stability: experimental
9−-- Portability: portable
10−--
11−-- Parsers for parsing dates and times.
1+{-# LANGUAGE NoImplicitPrelude #-}
122
133module Data.Aeson.Parser.Time
144 (
@@ -21,122 +11,51 @@ module Data.Aeson.Parser.Time
2111 , zonedTime
2212 ) where
2313
24−import Control.Monad (when, void)
25−import Data.Aeson.Internal.Time (toPico)
26−import Data.Attoparsec.Text as A
27−import Data.Bits ((.&.))
28−import Data.Char (isDigit, ord)
29−import Data.Fixed (Pico)
30−import Data.Int (Int64)
31−import Data.Maybe (fromMaybe)
14+import Prelude.Compat
15+
16+import Data.Attoparsec.Text (Parser)
3217import Data.Text (Text)
33−import Data.Time.Calendar (Day, fromGregorianValid)
18+import Data.Time.Calendar (Day)
3419import Data.Time.Clock (UTCTime(..))
3520import qualified Data.Aeson.Types.Internal as Aeson
36−import qualified Data.Text as T
21+import qualified Data.Attoparsec.Text as A
22+import qualified Data.Attoparsec.Time as T
3723import qualified Data.Time.LocalTime as Local
3824
39−#if !MIN_VERSION_base(4,8,0)
40−import Control.Applicative ((<$>), (<*>), (<*), (*>))
41−#endif
42−
4325-- | Run an attoparsec parser as an aeson parser.
4426run :: Parser a -> Text -> Aeson.Parser a
45−run p t = case A.parseOnly (p <* endOfInput) t of
27+run p t = case A.parseOnly (p <* A.endOfInput) t of
4628 Left err -> fail $ "could not parse date: " ++ err
4729 Right r -> return r
4830
49−-- | Parse a date of the form @YYYY-MM-DD@.
31+-- | Parse a date of the form @[+,-]YYYY-MM-DD@.
5032day :: Parser Day
51−day = do
52− y <- decimal <* char '-'
53− m <- twoDigits <* char '-'
54− d <- twoDigits
55− maybe (fail "invalid date") return (fromGregorianValid y m d)
56−
57−-- | Parse a two-digit integer (e.g. day of month, hour).
58−twoDigits :: Parser Int
59−twoDigits = do
60− a <- digit
61− b <- digit
62− let c2d c = ord c .&. 15
63− return $! c2d a * 10 + c2d b
33+day = T.day
34+{-# INLINE day #-}
6435
6536-- | Parse a time of the form @HH:MM[:SS[.SSS]]@.
6637timeOfDay :: Parser Local.TimeOfDay
67−timeOfDay = do
68− h <- twoDigits
69− m <- char ':' *> twoDigits
70− s <- option 0 (char ':' *> seconds)
71− if h < 24 && m < 60 && s < 61
72− then return (Local.TimeOfDay h m s)
73− else fail "invalid time"
74−
75−data T = T {-# UNPACK #-} !Int {-# UNPACK #-} !Int64
76−
77−-- | Parse a count of seconds, with the integer part being two digits
78−-- long.
79−seconds :: Parser Pico
80−seconds = do
81− real <- twoDigits
82− mc <- peekChar
83− case mc of
84− Just '.' -> do
85− t <- anyChar *> takeWhile1 isDigit
86− return $! parsePicos real t
87− _ -> return $! fromIntegral real
88− where
89− parsePicos a0 t = toPico (fromIntegral (t' * 10^n))
90− where T n t' = T.foldl' step (T 12 (fromIntegral a0)) t
91− step ma@(T m a) c
92− | m <= 0 = ma
93− | otherwise = T (m-1) (10 * a + fromIntegral (ord c) .&. 15)
38+timeOfDay = T.timeOfDay
39+{-# INLINE timeOfDay #-}
9440
9541-- | Parse a time zone, and return 'Nothing' if the offset from UTC is
9642-- zero. (This makes some speedups possible.)
9743timeZone :: Parser (Maybe Local.TimeZone)
98−timeZone = do
99− let maybeSkip c = do ch <- peekChar'; when (ch == c) (void anyChar)
100− maybeSkip ' '
101− ch <- satisfy $ \c -> c == 'Z' || c == '+' || c == '-'
102− if ch == 'Z'
103− then return Nothing
104− else do
105− h <- twoDigits
106− mm <- peekChar
107− m <- case mm of
108− Just ':' -> anyChar *> twoDigits
109− Just d | isDigit d -> twoDigits
110− _ -> return 0
111− let off | ch == '-' = negate off0
112− | otherwise = off0
113− off0 = h * 60 + m
114− case undefined of
115− _ | off == 0 ->
116− return Nothing
117− | off < -720 || off > 840 || m > 59 ->
118− fail "invalid time zone offset"
119− | otherwise ->
120− let !tz = Local.minutesToTimeZone off
121− in return (Just tz)
44+timeZone = T.timeZone
45+{-# INLINE timeZone #-}
12246
12347-- | Parse a date and time, of the form @YYYY-MM-DD HH:MM[:SS[.SSS]]@.
12448-- The space may be replaced with a @T@. The number of seconds is optional
12549-- and may be followed by a fractional component.
12650localTime :: Parser Local.LocalTime
127−localTime = Local.LocalTime <$> day <* daySep <*> timeOfDay
128− where daySep = satisfy (\c -> c == 'T' || c == ' ')
51+localTime = T.localTime
52+{-# INLINE localTime #-}
12953
13054-- | Behaves as 'zonedTime', but converts any time zone offset into a
13155-- UTC time.
13256utcTime :: Parser UTCTime
133−utcTime = do
134− lt@(Local.LocalTime d t) <- localTime
135− mtz <- timeZone
136− case mtz of
137− Nothing -> let !tt = Local.timeOfDayToTime t
138− in return (UTCTime d tt)
139− Just tz -> return $! Local.localTimeToUTC tz lt
57+utcTime = T.utcTime
58+{-# INLINE utcTime #-}
14059
14160-- | Parse a date with time zone info. Acceptable formats:
14261--
@@ -150,7 +69,5 @@ utcTime = do
15069-- two digits are hours, the @:@ is optional and the second two digits
15170-- (also optional) are minutes.
15271zonedTime :: Parser Local.ZonedTime
153−zonedTime = Local.ZonedTime <$> localTime <*> (fromMaybe utc <$> timeZone)
154−
155−utc :: Local.TimeZone
156−utc = Local.TimeZone 0 False ""
72+zonedTime = T.zonedTime
73+{-# INLINE zonedTime #-}
Data/Aeson/Parser/Unescape.hsnew file+11
@@ -0,0 +1,11 @@
1+{-# LANGUAGE CPP #-}
2+module Data.Aeson.Parser.Unescape
3+ (
4+ unescapeText
5+ ) where
6+
7+#ifdef CFFI
8+import Data.Aeson.Parser.UnescapeFFI (unescapeText)
9+#else
10+import Data.Aeson.Parser.UnescapePure (unescapeText)
11+#endif
Data/Aeson/QQ/Simple.hsnew file+25
@@ -0,0 +1,25 @@
1+-- | Like "Data.Aeson.QQ" but without interpolation.
2+module Data.Aeson.QQ.Simple (aesonQQ) where
3+
4+import Data.Aeson
5+import qualified Data.Text as T
6+import qualified Data.Text.Encoding as TE
7+import Language.Haskell.TH
8+import Language.Haskell.TH.Quote
9+import Language.Haskell.TH.Syntax (Lift (..))
10+import Prelude ()
11+import Prelude.Compat
12+
13+aesonQQ :: QuasiQuoter
14+aesonQQ = QuasiQuoter
15+ { quoteExp = aesonExp
16+ , quotePat = const $ error "No quotePat defined for jsonQQ"
17+ , quoteType = const $ error "No quoteType defined for jsonQQ"
18+ , quoteDec = const $ error "No quoteDec defined for jsonQQ"
19+ }
20+
21+aesonExp :: String -> ExpQ
22+aesonExp txt =
23+ case eitherDecodeStrict $ TE.encodeUtf8 $ T.pack txt of
24+ Left err -> error $ "Error in aesonExp: " ++ show err
25+ Right val -> lift (val :: Value)
Data/Aeson/TH.hs+522−962
@@ -13,6 +13,7 @@
1313{-# LANGUAGE TemplateHaskell #-}
1414#endif
1515
16+#include "incoherent-compat.h"
1617#include "overlapping-compat.h"
1718
1819{-|
@@ -84,10 +85,13 @@ $('deriveJSON' 'defaultOptions' ''(,,,))
8485@
8586
8687-}
87−
8888module Data.Aeson.TH
89− ( -- * Encoding configuration
90− Options(..), SumEncoding(..), defaultOptions, defaultTaggedObject
89+ (
90+ -- * Encoding configuration
91+ Options(..)
92+ , SumEncoding(..)
93+ , defaultOptions
94+ , defaultTaggedObject
9195
9296 -- * FromJSON and ToJSON derivation
9397 , deriveJSON
@@ -112,73 +116,41 @@ module Data.Aeson.TH
112116 , mkLiftParseJSON2
113117 ) where
114118
115−import Control.Applicative ( pure, (<$>), (<*>) )
116−import Data.Aeson ( Object, (.=), (.:)
117− , ToJSON(..), FromJSON(..)
118− , ToJSON1(..), FromJSON1(..)
119− , ToJSON2(..), FromJSON2(..)
120− )
121−import Data.Aeson.Types ( Value(..), Parser
122− , Options(..)
123− , SumEncoding(..)
124− , defaultOptions
125− , defaultTaggedObject
126− )
127−import Data.Aeson.Types.Internal (Pair, (<?>), JSONPathElement(Key))
119+import Prelude.Compat
120+
121+import Control.Applicative ((<|>))
122+import Data.Aeson (Object, (.:), FromJSON(..), FromJSON1(..), FromJSON2(..), ToJSON(..), ToJSON1(..), ToJSON2(..))
123+import Data.Aeson.Types (Options(..), Parser, SumEncoding(..), Value(..), defaultOptions, defaultTaggedObject)
124+import Data.Aeson.Types.Internal ((<?>), JSONPathElement(Key))
128125import Data.Aeson.Types.FromJSON (parseOptionalFieldWith)
129−import Control.Monad ( fail, liftM2, mapM, return, unless, when )
130−import Data.Bool ( Bool(False, True), otherwise, (&&), not )
131−import Data.Either ( Either(Left, Right) )
132−import Data.Eq ( (==) )
133−import Data.Foldable ( concatMap, foldr' )
134−import Data.Function ( ($), (.), flip )
135−import Data.Functor ( fmap )
136−import Data.Int ( Int )
137−import Data.List ( (++), all, any, find, foldl, foldl'
138− , genericLength , intercalate , intersperse, length, map
139− , partition, union, zip, zip3
140− )
141−import Data.List.NonEmpty ( NonEmpty((:|)), (<|) )
142−import Data.Map ( Map )
143−import Data.Maybe ( Maybe(Nothing, Just), catMaybes, fromMaybe, mapMaybe )
144−import Data.Monoid ( (<>), mconcat )
145−import Data.Set ( Set )
146−import Language.Haskell.TH
147−#if MIN_VERSION_template_haskell(2,8,0)
148− hiding ( Arity )
149−#endif
150−import Language.Haskell.TH.Syntax ( VarStrictType )
151−import Prelude ( Enum(..), Eq(..), Integer, Ord(..), String
152− , concat, cycle, drop, elem, error, foldr1, fromIntegral
153− , showChar, showParen, shows, showString, snd, splitAt
154− , take, unzip, zipWith, (-), (||)
155− )
156−#if MIN_VERSION_template_haskell(2,7,0) && !(MIN_VERSION_template_haskell(2,8,0))
157−import Language.Haskell.TH.Lib ( starK )
126+import Data.Aeson.Types.ToJSON (fromPairs, pair)
127+import Control.Monad (liftM2, unless, when)
128+import Data.Foldable (foldr')
129+#if MIN_VERSION_template_haskell(2,8,0) && !MIN_VERSION_template_haskell(2,10,0)
130+import Data.List (nub)
158131#endif
132+import Data.List (foldl', genericLength, intercalate, partition, union)
133+import Data.List.NonEmpty ((<|), NonEmpty((:|)))
134+import Data.Map (Map)
135+import Data.Maybe (catMaybes, fromMaybe, mapMaybe)
136+import qualified Data.Monoid as Monoid
137+import Data.Set (Set)
138+import Language.Haskell.TH hiding (Arity)
139+import Language.Haskell.TH.Datatype
159140#if MIN_VERSION_template_haskell(2,8,0) && !(MIN_VERSION_template_haskell(2,10,0))
160−import Data.List ( nub )
161−import Language.Haskell.TH.Syntax ( mkNameG_tc )
162−import Prelude ( uncurry )
141+import Language.Haskell.TH.Syntax (mkNameG_tc)
163142#endif
164−#if MIN_VERSION_template_haskell(2,11,0)
165−import Prelude ( head )
166−#endif
167−import Text.Printf ( printf )
168−import Text.Show ( show )
169−import qualified Data.Aeson as A
143+import Text.Printf (printf)
170144import qualified Data.Aeson.Encoding.Internal as E
171−import qualified Data.Foldable as F ( all )
172−import qualified Data.HashMap.Strict as H ( lookup, toList )
173−import qualified Data.List.NonEmpty as NE ( drop, length, reverse, splitAt )
174−import qualified Data.Map as M ( fromList, findWithDefault, keys, lookup
175− , singleton, size
176− )
177−import qualified Data.Set as Set ( empty, insert, member )
178−import qualified Data.Text as T ( Text, pack, unpack )
179−import qualified Data.Vector as V ( unsafeIndex, null, length, create, fromList )
180−import qualified Data.Vector.Mutable as VM ( unsafeNew, unsafeWrite )
181−
145+import qualified Data.Foldable as F (all)
146+import qualified Data.HashMap.Strict as H (difference, fromList, keys, lookup, toList)
147+import qualified Data.List.NonEmpty as NE (length, reverse)
148+import qualified Data.Map as M (fromList, keys, lookup , singleton, size)
149+import qualified Data.Semigroup as Semigroup (Option(..))
150+import qualified Data.Set as Set (empty, insert, member)
151+import qualified Data.Text as T (Text, pack, unpack)
152+import qualified Data.Vector as V (unsafeIndex, null, length, create, empty)
153+import qualified Data.Vector.Mutable as VM (unsafeNew, unsafeWrite)
182154
183155--------------------------------------------------------------------------------
184156-- Convenience
@@ -273,8 +245,8 @@ deriveToJSONCommon :: JSONClass
273245 -> Name
274246 -- ^ Name of the type for which to generate an instance.
275247 -> Q [Dec]
276−deriveToJSONCommon = deriveJSONClass [ (ToJSON, \jc _ -> consToValue jc)
277− , (ToEncoding, \jc _ -> consToEncoding jc)
248+deriveToJSONCommon = deriveJSONClass [ (ToJSON, \jc _ -> consToValue Value jc)
249+ , (ToEncoding, \jc _ -> consToValue Encoding jc)
278250 ]
279251
280252-- | Generates a lambda expression which encodes the given data type or
@@ -304,7 +276,7 @@ mkToJSONCommon :: JSONClass -- ^ Which class's method is being derived.
304276 -> Options -- ^ Encoding options.
305277 -> Name -- ^ Name of the encoded type.
306278 -> Q Exp
307−mkToJSONCommon = mkFunCommon (\jc _ -> consToValue jc)
279+mkToJSONCommon = mkFunCommon (\jc _ -> consToValue Value jc)
308280
309281-- | Generates a lambda expression which encodes the given data type or
310282-- data family instance constructor as a JSON string.
@@ -333,409 +305,272 @@ mkToEncodingCommon :: JSONClass -- ^ Which class's method is being derived.
333305 -> Options -- ^ Encoding options.
334306 -> Name -- ^ Name of the encoded type.
335307 -> Q Exp
336−mkToEncodingCommon = mkFunCommon (\jc _ -> consToEncoding jc)
308+mkToEncodingCommon = mkFunCommon (\jc _ -> consToValue Encoding jc)
337309
338310-- | Helper function used by both 'deriveToJSON' and 'mkToJSON'. Generates
339−-- code to generate a 'Value' of a number of constructors. All constructors
340−-- must be from the same type.
341−consToValue :: JSONClass
311+-- code to generate a 'Value' or 'Encoding' of a number of constructors. All
312+-- constructors must be from the same type.
313+consToValue :: ToJSONFun
314+ -- ^ The method ('toJSON' or 'toEncoding') being derived.
315+ -> JSONClass
342316 -- ^ The ToJSON variant being derived.
343317 -> Options
344318 -- ^ Encoding options.
345− -> [Con]
319+ -> [Type]
320+ -- ^ The types from the data type/data family instance declaration
321+ -> [ConstructorInfo]
346322 -- ^ Constructors for which to generate JSON generating code.
347323 -> Q Exp
348324
349−consToValue _ _ [] = error $ "Data.Aeson.TH.consToValue: "
350− ++ "Not a single constructor given!"
325+consToValue _ _ _ _ [] = error $ "Data.Aeson.TH.consToValue: "
326+ ++ "Not a single constructor given!"
351327
352−consToValue jc opts cons = do
328+consToValue target jc opts instTys cons = do
353329 value <- newName "value"
354330 tjs <- newNameList "_tj" $ arityInt jc
355331 tjls <- newNameList "_tjl" $ arityInt jc
356332 let zippedTJs = zip tjs tjls
357333 interleavedTJs = interleave tjs tjls
334+ lastTyVars = map varTToName $ drop (length instTys - arityInt jc) instTys
335+ tvMap = M.fromList $ zip lastTyVars zippedTJs
358336 lamE (map varP $ interleavedTJs ++ [value]) $
359− caseE (varE value) (matches zippedTJs)
337+ caseE (varE value) (matches tvMap)
360338 where
361− matches tjs = case cons of
339+ matches tvMap = case cons of
362340 -- A single constructor is directly encoded. The constructor itself may be
363341 -- forgotten.
364− [con] -> [argsToValue jc tjs opts False con]
342+ [con] | not (tagSingleConstructors opts) -> [argsToValue target jc tvMap opts False con]
365343 _ | allNullaryToStringTag opts && all isNullary cons ->
366− [ match (conP conName []) (normalB $ conStr opts conName) []
344+ [ match (conP conName []) (normalB $ conStr target opts conName) []
367345 | con <- cons
368− , let conName = getConName con
346+ , let conName = constructorName con
369347 ]
370− | otherwise -> [argsToValue jc tjs opts True con | con <- cons]
348+ | otherwise -> [argsToValue target jc tvMap opts True con | con <- cons]
371349
372−conStr :: Options -> Name -> Q Exp
373−conStr opts = appE [|String|] . conTxt opts
350+-- | Name of the constructor as a quoted 'Value' or 'Encoding'.
351+conStr :: ToJSONFun -> Options -> Name -> Q Exp
352+conStr Value opts = appE [|String|] . conTxt opts
353+conStr Encoding opts = appE [|E.text|] . conTxt opts
374354
355+-- | Name of the constructor as a quoted 'Text'.
375356conTxt :: Options -> Name -> Q Exp
376−conTxt opts = appE [|T.pack|] . conStringE opts
377−
378−conStringE :: Options -> Name -> Q Exp
379−conStringE opts = stringE . constructorTagModifier opts . nameBase
380−
381−-- | Helper function used by both 'deriveToJSON' and 'mkToEncoding'. Generates
382−-- code to write out a value for a number of constructors. All constructors
383−-- must be from the same type.
384−consToEncoding :: JSONClass
385− -- ^ The ToJSON variant being derived.
386− -> Options
387− -- ^ Encoding options.
388− -> [Con]
389− -- ^ Constructors for which to generate JSON generating code.
390− -> Q Exp
391−
392−consToEncoding _ _ [] = error $ "Data.Aeson.TH.consToEncoding: "
393− ++ "Not a single constructor given!"
394−
395−consToEncoding jc opts cons = do
396− value <- newName "value"
397− tes <- newNameList "_te" $ arityInt jc
398− tels <- newNameList "_tel" $ arityInt jc
399− let zippedTEs = zip tes tels
400− interleavedTEs = interleave tes tels
401− lamE (map varP $ interleavedTEs ++ [value]) $
402− caseE (varE value) (matches zippedTEs)
403− where
404− matches tes = case cons of
405− -- A single constructor is directly encoded. The constructor itself may be
406− -- forgotten.
407− [con] -> [argsToEncoding jc tes opts False con]
408− -- Encode just the name of the constructor of a sum type iff all the
409− -- constructors are nullary.
410− _ | allNullaryToStringTag opts && all isNullary cons ->
411− [ match (conP conName [])
412− (normalB $ encStr opts conName) []
413− | con <- cons
414− , let conName = getConName con
415− ]
416− | otherwise -> [argsToEncoding jc tes opts True con | con <- cons]
357+conTxt opts = appE [|T.pack|] . stringE . conString opts
417358
418−encStr :: Options -> Name -> Q Exp
419−encStr opts = appE [|E.text|] . conTxt opts
359+-- | Name of the constructor.
360+conString :: Options -> Name -> String
361+conString opts = constructorTagModifier opts . nameBase
420362
421363-- | If constructor is nullary.
422−isNullary :: Con -> Bool
423−isNullary (NormalC _ []) = True
364+isNullary :: ConstructorInfo -> Bool
365+isNullary ConstructorInfo { constructorVariant = NormalConstructor
366+ , constructorFields = tys } = null tys
424367isNullary _ = False
425368
426−sumToValue :: Options -> Bool -> Name -> Q Exp -> Q Exp
427−sumToValue opts multiCons conName exp
369+-- | Wrap fields of a non-record constructor. See 'sumToValue'.
370+opaqueSumToValue :: ToJSONFun -> Options -> Bool -> Bool -> Name -> ExpQ -> ExpQ
371+opaqueSumToValue target opts multiCons nullary conName value =
372+ sumToValue target opts multiCons nullary conName
373+ value
374+ pairs
375+ where
376+ pairs contentsFieldName = pairE contentsFieldName value
377+
378+-- | Wrap fields of a record constructor. See 'sumToValue'.
379+recordSumToValue :: ToJSONFun -> Options -> Bool -> Bool -> Name -> ExpQ -> ExpQ
380+recordSumToValue target opts multiCons nullary conName pairs =
381+ sumToValue target opts multiCons nullary conName
382+ (fromPairsE pairs)
383+ (const pairs)
384+
385+-- | Wrap fields of a constructor.
386+sumToValue
387+ :: ToJSONFun
388+ -- ^ The method being derived.
389+ -> Options
390+ -- ^ Deriving options.
391+ -> Bool
392+ -- ^ Does this type have multiple constructors.
393+ -> Bool
394+ -- ^ Is this constructor nullary.
395+ -> Name
396+ -- ^ Constructor name.
397+ -> ExpQ
398+ -- ^ Fields of the constructor as a 'Value' or 'Encoding'.
399+ -> (String -> ExpQ)
400+ -- ^ Representation of an 'Object' fragment used for the 'TaggedObject'
401+ -- variant; of type @[(Text,Value)]@ or @[Encoding]@, depending on the method
402+ -- being derived.
403+ --
404+ -- - For non-records, produces a pair @"contentsFieldName":value@,
405+ -- given a @contentsFieldName@ as an argument. See 'opaqueSumToValue'.
406+ -- - For records, produces the list of pairs corresponding to fields of the
407+ -- encoded value (ignores the argument). See 'recordSumToValue'.
408+ -> ExpQ
409+sumToValue target opts multiCons nullary conName value pairs
428410 | multiCons =
429411 case sumEncoding opts of
430412 TwoElemArray ->
431− [|Array|] `appE` ([|V.fromList|] `appE` listE [conStr opts conName, exp])
413+ array target [conStr target opts conName, value]
432414 TaggedObject{tagFieldName, contentsFieldName} ->
433− [|A.object|] `appE` listE
434− [ infixApp [|T.pack tagFieldName|] [|(.=)|] (conStr opts conName)
435− , infixApp [|T.pack contentsFieldName|] [|(.=)|] exp
436− ]
415+ -- TODO: Maybe throw an error in case
416+ -- tagFieldName overwrites a field in pairs.
417+ let tag = pairE tagFieldName (conStr target opts conName)
418+ content = pairs contentsFieldName
419+ in fromPairsE $
420+ if nullary then tag else infixApp tag [|(Monoid.<>)|] content
437421 ObjectWithSingleField ->
438− [|A.object|] `appE` listE
439− [ infixApp (conTxt opts conName) [|(.=)|] exp
440− ]
441−
442− | otherwise = exp
443−
444−nullarySumToValue :: Options -> Bool -> Name -> Q Exp
445−nullarySumToValue opts multiCons conName =
446− case sumEncoding opts of
447− TaggedObject{tagFieldName} ->
448− [|A.object|] `appE` listE
449− [ infixApp [|T.pack tagFieldName|] [|(.=)|] (conStr opts conName)
450− ]
451− _ -> sumToValue opts multiCons conName [e|toJSON ([] :: [()])|]
422+ objectE [(conString opts conName, value)]
423+ UntaggedValue | nullary -> conStr target opts conName
424+ UntaggedValue -> value
425+ | otherwise = value
452426
453427-- | Generates code to generate the JSON encoding of a single constructor.
454−argsToValue :: JSONClass -> [(Name, Name)] -> Options -> Bool -> Con -> Q Match
455−-- Nullary constructors. Generates code that explicitly matches against the
456−-- constructor even though it doesn't contain data. This is useful to prevent
457−-- type errors.
458−argsToValue jc tjs opts multiCons (NormalC conName []) = do
459− ([], _) <- reifyConTys jc tjs conName
460− match (conP conName [])
461− (normalB (nullarySumToValue opts multiCons conName))
462− []
428+argsToValue :: ToJSONFun -> JSONClass -> TyVarMap -> Options -> Bool -> ConstructorInfo -> Q Match
463429
464430-- Polyadic constructors with special case for unary constructors.
465−argsToValue jc tjs opts multiCons (NormalC conName ts) = do
466− (argTys, tvMap) <- reifyConTys jc tjs conName
467− let len = length ts
431+argsToValue target jc tvMap opts multiCons
432+ ConstructorInfo { constructorName = conName
433+ , constructorVariant = NormalConstructor
434+ , constructorFields = argTys } = do
435+ argTys' <- mapM resolveTypeSynonyms argTys
436+ let len = length argTys'
468437 args <- newNameList "arg" len
469− js <- case [ dispatchToJSON jc conName tvMap argTy
470− `appE` varE arg
471− | (arg, argTy) <- zip args argTys
472− ] of
473− -- Single argument is directly converted.
474− [e] -> return e
475− -- Multiple arguments are converted to a JSON array.
476− es -> do
477− mv <- newName "mv"
478− let newMV = bindS (varP mv)
479− ([|VM.unsafeNew|] `appE`
480− litE (integerL $ fromIntegral len))
481− stmts = [ noBindS $
482− [|VM.unsafeWrite|] `appE`
483− (varE mv) `appE`
484− litE (integerL ix) `appE`
485− e
486− | (ix, e) <- zip [(0::Integer)..] es
487− ]
488− ret = noBindS $ [|return|] `appE` varE mv
489− return $ [|Array|] `appE`
490− (varE 'V.create `appE`
491− doE (newMV:stmts++[ret]))
438+ let js = case [ dispatchToJSON target jc conName tvMap argTy
439+ `appE` varE arg
440+ | (arg, argTy) <- zip args argTys'
441+ ] of
442+ -- Single argument is directly converted.
443+ [e] -> e
444+ -- Zero and multiple arguments are converted to a JSON array.
445+ es -> array target es
446+
492447 match (conP conName $ map varP args)
493− (normalB $ sumToValue opts multiCons conName js)
448+ (normalB $ opaqueSumToValue target opts multiCons (null argTys') conName js)
494449 []
495450
496451-- Records.
497−argsToValue jc tjs opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts, not multiCons, ts) of
498− (True,True,[(_,st,ty)]) -> argsToValue jc tjs opts multiCons (NormalC conName [(st,ty)])
499− _ -> do
500− (argTys, tvMap) <- reifyConTys jc tjs conName
501− args <- newNameList "arg" $ length ts
502− let exp = [|A.object|] `appE` pairs
503−
504− pairs | omitNothingFields opts = infixApp maybeFields
505− [|(++)|]
506− restFields
507− | otherwise = listE $ map toPair argCons
508−
509− argCons = zip3 args argTys ts
510−
511− maybeFields = [|catMaybes|] `appE` listE (map maybeToPair maybes)
512−
513− restFields = listE $ map toPair rest
514−
515− (maybes, rest) = partition isMaybe argCons
516−
517− maybeToPair (arg, argTy, (field, _, _)) =
518− infixApp ([|keyValuePairWith|]
519− `appE` dispatchToJSON jc conName tvMap argTy
520− `appE` toFieldName field)
521− [|(<$>)|]
522− (varE arg)
523−
524− toPair (arg, argTy, (field, _, _)) =
525− [|keyValuePairWith|]
526− `appE` dispatchToJSON jc conName tvMap argTy
527− `appE` toFieldName field
528− `appE` varE arg
529−
530− toFieldName field = [|T.pack|] `appE` fieldLabelExp opts field
531−
532− match (conP conName $ map varP args)
533− ( normalB
534− $ if multiCons
535− then case sumEncoding opts of
536− TwoElemArray -> [|toJSON|] `appE` tupE [conStr opts conName, exp]
537− TaggedObject{tagFieldName} ->
538− [|A.object|] `appE`
539− -- TODO: Maybe throw an error in case
540− -- tagFieldName overwrites a field in pairs.
541− infixApp (infixApp [|T.pack tagFieldName|]
542− [|(.=)|]
543− (conStr opts conName))
544− [|(:)|]
545− pairs
546− ObjectWithSingleField ->
547− [|A.object|] `appE` listE
548− [ infixApp (conTxt opts conName) [|(.=)|] exp ]
549− else exp
550− ) []
452+argsToValue target jc tvMap opts multiCons
453+ info@ConstructorInfo { constructorName = conName
454+ , constructorVariant = RecordConstructor fields
455+ , constructorFields = argTys } =
456+ case (unwrapUnaryRecords opts, not multiCons, argTys) of
457+ (True,True,[_]) -> argsToValue target jc tvMap opts multiCons
458+ (info{constructorVariant = NormalConstructor})
459+ _ -> do
460+ argTys' <- mapM resolveTypeSynonyms argTys
461+ args <- newNameList "arg" $ length argTys'
462+ let pairs | omitNothingFields opts = infixApp maybeFields
463+ [|(Monoid.<>)|]
464+ restFields
465+ | otherwise = mconcatE (map pureToPair argCons)
466+
467+ argCons = zip3 (map varE args) argTys' fields
468+
469+ maybeFields = mconcatE (map maybeToPair maybes)
470+
471+ restFields = mconcatE (map pureToPair rest)
472+
473+ (maybes0, rest0) = partition isMaybe argCons
474+ (options, rest) = partition isOption rest0
475+ maybes = maybes0 ++ map optionToMaybe options
476+
477+ maybeToPair = toPairLifted True
478+ pureToPair = toPairLifted False
479+
480+ toPairLifted lifted (arg, argTy, field) =
481+ let toValue = dispatchToJSON target jc conName tvMap argTy
482+ fieldName = fieldLabel opts field
483+ e arg' = pairE fieldName (toValue `appE` arg')
484+ in if lifted
485+ then do
486+ x <- newName "x"
487+ [|maybe mempty|] `appE` lam1E (varP x) (e (varE x)) `appE` arg
488+ else e arg
489+
490+ match (conP conName $ map varP args)
491+ (normalB $ recordSumToValue target opts multiCons (null argTys) conName pairs)
492+ []
551493
552494-- Infix constructors.
553−argsToValue jc tjs opts multiCons (InfixC _ conName _) = do
554− ([alTy, arTy], tvMap) <- reifyConTys jc tjs conName
495+argsToValue target jc tvMap opts multiCons
496+ ConstructorInfo { constructorName = conName
497+ , constructorVariant = InfixConstructor
498+ , constructorFields = argTys } = do
499+ [alTy, arTy] <- mapM resolveTypeSynonyms argTys
555500 al <- newName "argL"
556501 ar <- newName "argR"
557502 match (infixP (varP al) conName (varP ar))
558503 ( normalB
559− $ sumToValue opts multiCons conName
560− $ [|toJSON|] `appE` listE [ dispatchToJSON jc conName tvMap aTy
561− `appE` varE a
562− | (a, aTy) <- [(al,alTy), (ar,arTy)]
563− ]
504+ $ opaqueSumToValue target opts multiCons False conName
505+ $ array target
506+ [ dispatchToJSON target jc conName tvMap aTy
507+ `appE` varE a
508+ | (a, aTy) <- [(al,alTy), (ar,arTy)]
509+ ]
564510 )
565511 []
566−-- Existentially quantified constructors.
567−argsToValue jc tjs opts multiCons (ForallC _ _ con) =
568− argsToValue jc tjs opts multiCons con
569512
570−#if MIN_VERSION_template_haskell(2,11,0)
571−-- GADTs.
572−argsToValue jc tjs opts multiCons (GadtC conNames ts _) =
573− argsToValue jc tjs opts multiCons $ NormalC (head conNames) ts
513+isMaybe :: (a, Type, b) -> Bool
514+isMaybe (_, AppT (ConT t) _, _) = t == ''Maybe
515+isMaybe _ = False
574516
575−argsToValue jc tjs opts multiCons (RecGadtC conNames ts _) =
576− argsToValue jc tjs opts multiCons $ RecC (head conNames) ts
577−#endif
517+isOption :: (a, Type, b) -> Bool
518+isOption (_, AppT (ConT t) _, _) = t == ''Semigroup.Option
519+isOption _ = False
578520
579−isMaybe :: (a, b, (c, d, Type)) -> Bool
580−isMaybe (_, _, (_, _, AppT (ConT t) _)) = t == ''Maybe
581−isMaybe _ = False
521+optionToMaybe :: (ExpQ, b, c) -> (ExpQ, b, c)
522+optionToMaybe (a, b, c) = ([|Semigroup.getOption|] `appE` a, b, c)
582523
583524(<^>) :: ExpQ -> ExpQ -> ExpQ
584−(<^>) a b = infixApp a [|(<>)|] b
525+(<^>) a b = infixApp a [|(E.><)|] b
585526infixr 6 <^>
586527
587−(<:>) :: ExpQ -> ExpQ -> ExpQ
588−(<:>) a b = a <^> [|E.colon|] <^> b
589−infixr 5 <:>
590−
591528(<%>) :: ExpQ -> ExpQ -> ExpQ
592529(<%>) a b = a <^> [|E.comma|] <^> b
593530infixr 4 <%>
594531
595−array :: ExpQ -> ExpQ
596−array exp = [|E.wrapArray|] `appE` exp
597−
598−object :: ExpQ -> ExpQ
599−object exp = [|E.wrapObject|] `appE` exp
600−
601−sumToEncoding :: Options -> Bool -> Name -> Q Exp -> Q Exp
602−sumToEncoding opts multiCons conName exp
603− | multiCons =
604− let fexp = exp in
605− case sumEncoding opts of
606− TwoElemArray ->
607− array (encStr opts conName <%> fexp)
608− TaggedObject{tagFieldName, contentsFieldName} ->
609− object $
610− ([|E.text (T.pack tagFieldName)|] <:> encStr opts conName) <%>
611− ([|E.text (T.pack contentsFieldName)|] <:> fexp)
612− ObjectWithSingleField ->
613− object (encStr opts conName <:> fexp)
614−
615− | otherwise = exp
616−
617−nullarySumToEncoding :: Options -> Bool -> Name -> Q Exp
618−nullarySumToEncoding opts multiCons conName =
619− case sumEncoding opts of
620− TaggedObject{tagFieldName} ->
621− object $
622− ([|E.text (T.pack tagFieldName)|] <:> encStr opts conName)
623− _ -> sumToEncoding opts multiCons conName [e|toEncoding ([] :: [()])|]
624−
625−-- | Generates code to generate the JSON encoding of a single constructor.
626−argsToEncoding :: JSONClass -> [(Name, Name)] -> Options -> Bool -> Con -> Q Match
627−-- Nullary constructors. Generates code that explicitly matches against the
628−-- constructor even though it doesn't contain data. This is useful to prevent
629−-- type errors.
630−argsToEncoding jc tes opts multiCons (NormalC conName []) = do
631− ([], _) <- reifyConTys jc tes conName
632− match (conP conName [])
633− (normalB (nullarySumToEncoding opts multiCons conName))
634− []
635−
636−-- Polyadic constructors with special case for unary constructors.
637−argsToEncoding jc tes opts multiCons (NormalC conName ts) = do
638− (argTys, tvMap) <- reifyConTys jc tes conName
639− let len = length ts
640− args <- newNameList "arg" len
641− js <- case zip args argTys of
642− -- Single argument is directly converted.
643− [(e,eTy)] -> return (dispatchToEncoding jc conName tvMap eTy
644− `appE` varE e)
645− -- Multiple arguments are converted to a JSON array.
646− es ->
647− return (array (foldr1 (<%>) [ dispatchToEncoding jc conName tvMap xTy
648− `appE` varE x
649− | (x,xTy) <- es
650− ]))
651− match (conP conName $ map varP args)
652− (normalB $ sumToEncoding opts multiCons conName js)
653− []
654−
655−-- Records.
656−argsToEncoding jc tes opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts, not multiCons, ts) of
657− (True,True,[(_,st,ty)]) -> argsToEncoding jc tes opts multiCons (NormalC conName [(st,ty)])
658− _ -> do
659− args <- newNameList "arg" $ length ts
660− (argTys, tvMap) <- reifyConTys jc tes conName
661− let exp = object objBody
662−
663− objBody = [|mconcat|] `appE`
664− ([|intersperse E.comma|] `appE` pairs)
665− pairs | omitNothingFields opts = infixApp maybeFields
666− [|(<>)|]
667− restFields
668− | otherwise = listE (map toPair argCons)
669−
670− argCons = zip3 args argTys ts
671−
672− maybeFields = [|catMaybes|] `appE` listE (map maybeToPair maybes)
673−
674− restFields = listE (map toPair rest)
675−
676− (maybes, rest) = partition isMaybe argCons
677−
678− maybeToPair (arg, argTy, (field, _, _)) =
679− infixApp
680− (infixApp
681− (infixE
682− (Just $ toFieldName field <^> [|E.colon|])
683− [|(<>)|]
684− Nothing)
685− [|(.)|]
686− (dispatchToEncoding jc conName tvMap argTy))
687− [|(<$>)|]
688− (varE arg)
689−
690− toPair (arg, argTy, (field, _, _)) =
691− toFieldName field
692− <:> dispatchToEncoding jc conName tvMap argTy
693− `appE` varE arg
694−
695− toFieldName field = [|E.text|] `appE`
696− ([|T.pack|] `appE` fieldLabelExp opts field)
532+-- | Wrap a list of quoted 'Value's in a quoted 'Array' (of type 'Value').
533+array :: ToJSONFun -> [ExpQ] -> ExpQ
534+array Encoding [] = [|E.emptyArray_|]
535+array Value [] = [|Array V.empty|]
536+array Encoding es = [|E.wrapArray|] `appE` foldr1 (<%>) es
537+array Value es = do
538+ mv <- newName "mv"
539+ let newMV = bindS (varP mv)
540+ ([|VM.unsafeNew|] `appE`
541+ litE (integerL $ fromIntegral (length es)))
542+ stmts = [ noBindS $
543+ [|VM.unsafeWrite|] `appE`
544+ varE mv `appE`
545+ litE (integerL ix) `appE`
546+ e
547+ | (ix, e) <- zip [(0::Integer)..] es
548+ ]
549+ ret = noBindS $ [|return|] `appE` varE mv
550+ [|Array|] `appE`
551+ (varE 'V.create `appE`
552+ doE (newMV:stmts++[ret]))
697553
698− match (conP conName $ map varP args)
699− ( normalB
700− $ if multiCons
701− then case sumEncoding opts of
702− TwoElemArray -> array $
703− encStr opts conName <%> exp
704− TaggedObject{tagFieldName} -> object $
705− ([|E.text (T.pack tagFieldName)|] <:>
706− encStr opts conName) <%>
707− objBody
708− ObjectWithSingleField -> object $
709− encStr opts conName <:> exp
710− else exp
711− ) []
554+-- | Wrap an associative list of keys and quoted values in a quoted 'Object'.
555+objectE :: [(String, ExpQ)] -> ExpQ
556+objectE = fromPairsE . mconcatE . fmap (uncurry pairE)
712557
713−-- Infix constructors.
714−argsToEncoding jc tes opts multiCons (InfixC _ conName _) = do
715− al <- newName "argL"
716− ar <- newName "argR"
717− ([alTy,arTy], tvMap) <- reifyConTys jc tes conName
718− match (infixP (varP al) conName (varP ar))
719− ( normalB
720− $ sumToEncoding opts multiCons conName
721− $ array (foldr1 (<%>) [ dispatchToEncoding jc conName tvMap aTy
722− `appE` varE a
723− | (a,aTy) <- [(al,alTy), (ar,arTy)]
724− ])
725− )
726− []
727−-- Existentially quantified constructors.
728−argsToEncoding jc tes opts multiCons (ForallC _ _ con) =
729− argsToEncoding jc tes opts multiCons con
558+-- | 'mconcat' a list of fixed length.
559+--
560+-- > mconcatE [ [|x|], [|y|], [|z|] ] = [| x <> (y <> z) |]
561+mconcatE :: [ExpQ] -> ExpQ
562+mconcatE [] = [|Monoid.mempty|]
563+mconcatE [x] = x
564+mconcatE (x : xs) = infixApp x [|(Monoid.<>)|] (mconcatE xs)
730565
731−#if MIN_VERSION_template_haskell(2,11,0)
732−-- GADTs.
733−argsToEncoding jc tes opts multiCons (GadtC conNames ts _) =
734− argsToEncoding jc tes opts multiCons $ NormalC (head conNames) ts
566+fromPairsE :: ExpQ -> ExpQ
567+fromPairsE = ([|fromPairs|] `appE`)
735568
736−argsToEncoding jc tes opts multiCons (RecGadtC conNames ts _) =
737− argsToEncoding jc tes opts multiCons $ RecC (head conNames) ts
738−#endif
569+-- | Create (an encoding of) a key-value pair.
570+--
571+-- > pairE "k" [|v|] = [|pair "k" v|]
572+pairE :: String -> ExpQ -> ExpQ
573+pairE k v = [|pair k|] `appE` v
739574
740575--------------------------------------------------------------------------------
741576-- FromJSON
@@ -819,28 +654,41 @@ consFromJSON :: JSONClass
819654 -- ^ Name of the type to which the constructors belong.
820655 -> Options
821656 -- ^ Encoding options
822− -> [Con]
657+ -> [Type]
658+ -- ^ The types from the data type/data family instance declaration
659+ -> [ConstructorInfo]
823660 -- ^ Constructors for which to generate JSON parsing code.
824661 -> Q Exp
825662
826−consFromJSON _ _ _ [] = error $ "Data.Aeson.TH.consFromJSON: "
827− ++ "Not a single constructor given!"
663+consFromJSON _ _ _ _ [] = error $ "Data.Aeson.TH.consFromJSON: "
664+ ++ "Not a single constructor given!"
828665
829−consFromJSON jc tName opts cons = do
666+consFromJSON jc tName opts instTys cons = do
830667 value <- newName "value"
831668 pjs <- newNameList "_pj" $ arityInt jc
832669 pjls <- newNameList "_pjl" $ arityInt jc
833670 let zippedPJs = zip pjs pjls
834671 interleavedPJs = interleave pjs pjls
835− lamE (map varP $ interleavedPJs ++ [value]) $ lamExpr value zippedPJs
672+ lastTyVars = map varTToName $ drop (length instTys - arityInt jc) instTys
673+ tvMap = M.fromList $ zip lastTyVars zippedPJs
674+ lamE (map varP $ interleavedPJs ++ [value]) $ lamExpr value tvMap
836675
837676 where
838− lamExpr value pjs = case cons of
839− [con] -> parseArgs jc pjs tName opts con (Right value)
840− _ -> caseE (varE value) $
677+ checkExi tvMap con = checkExistentialContext jc tvMap
678+ (constructorContext con)
679+ (constructorName con)
680+
681+ lamExpr value tvMap = case cons of
682+ [con]
683+ | not (tagSingleConstructors opts)
684+ -> checkExi tvMap con $ parseArgs jc tvMap tName opts con (Right value)
685+ _ | sumEncoding opts == UntaggedValue
686+ -> parseUntaggedValue tvMap cons value
687+ | otherwise
688+ -> caseE (varE value) $
841689 if allNullaryToStringTag opts && all isNullary cons
842690 then allNullaryMatches
843− else mixedMatches pjs
691+ else mixedMatches tvMap
844692
845693 allNullaryMatches =
846694 [ do txt <- newName "txt"
@@ -849,18 +697,17 @@ consFromJSON jc tName opts cons = do
849697 [ liftM2 (,) (normalG $
850698 infixApp (varE txt)
851699 [|(==)|]
852− ([|T.pack|] `appE`
853− conStringE opts conName)
700+ (conTxt opts conName)
854701 )
855702 ([|pure|] `appE` conE conName)
856703 | con <- cons
857− , let conName = getConName con
704+ , let conName = constructorName con
858705 ]
859706 ++
860707 [ liftM2 (,)
861708 (normalG [|otherwise|])
862709 ( [|noMatchFail|]
863− `appE` (litE $ stringL $ show tName)
710+ `appE` litE (stringL $ show tName)
864711 `appE` ([|T.unpack|] `appE` varE txt)
865712 )
866713 ]
@@ -869,30 +716,31 @@ consFromJSON jc tName opts cons = do
869716 , do other <- newName "other"
870717 match (varP other)
871718 (normalB $ [|noStringFail|]
872− `appE` (litE $ stringL $ show tName)
719+ `appE` litE (stringL $ show tName)
873720 `appE` ([|valueConName|] `appE` varE other)
874721 )
875722 []
876723 ]
877724
878− mixedMatches pjs =
725+ mixedMatches tvMap =
879726 case sumEncoding opts of
880727 TaggedObject {tagFieldName, contentsFieldName} ->
881− parseObject $ parseTaggedObject pjs tagFieldName contentsFieldName
728+ parseObject $ parseTaggedObject tvMap tagFieldName contentsFieldName
729+ UntaggedValue -> error "UntaggedValue: Should be handled already"
882730 ObjectWithSingleField ->
883− parseObject $ parseObjectWithSingleField pjs
731+ parseObject $ parseObjectWithSingleField tvMap
884732 TwoElemArray ->
885733 [ do arr <- newName "array"
886734 match (conP 'Array [varP arr])
887− (guardedB $
735+ (guardedB
888736 [ liftM2 (,) (normalG $ infixApp ([|V.length|] `appE` varE arr)
889737 [|(==)|]
890738 (litE $ integerL 2))
891− (parse2ElemArray pjs arr)
739+ (parse2ElemArray tvMap arr)
892740 , liftM2 (,) (normalG [|otherwise|])
893− (([|not2ElemArray|]
894− `appE` (litE $ stringL $ show tName)
895− `appE` ([|V.length|] `appE` varE arr)))
741+ ([|not2ElemArray|]
742+ `appE` litE (stringL $ show tName)
743+ `appE` ([|V.length|] `appE` varE arr))
896744 ]
897745 )
898746 []
@@ -900,7 +748,7 @@ consFromJSON jc tName opts cons = do
900748 match (varP other)
901749 ( normalB
902750 $ [|noArrayFail|]
903− `appE` (litE $ stringL $ show tName)
751+ `appE` litE (stringL $ show tName)
904752 `appE` ([|valueConName|] `appE` varE other)
905753 )
906754 []
@@ -913,22 +761,47 @@ consFromJSON jc tName opts cons = do
913761 match (varP other)
914762 ( normalB
915763 $ [|noObjectFail|]
916− `appE` (litE $ stringL $ show tName)
764+ `appE` litE (stringL $ show tName)
917765 `appE` ([|valueConName|] `appE` varE other)
918766 )
919767 []
920768 ]
921769
922− parseTaggedObject pjs typFieldName valFieldName obj = do
770+ parseTaggedObject tvMap typFieldName valFieldName obj = do
923771 conKey <- newName "conKey"
924772 doE [ bindS (varP conKey)
925773 (infixApp (varE obj)
926774 [|(.:)|]
927775 ([|T.pack|] `appE` stringE typFieldName))
928− , noBindS $ parseContents pjs conKey (Left (valFieldName, obj)) 'conNotFoundFailTaggedObject
776+ , noBindS $ parseContents tvMap conKey (Left (valFieldName, obj)) 'conNotFoundFailTaggedObject
929777 ]
930778
931− parse2ElemArray pjs arr = do
779+ parseUntaggedValue tvMap cons' conVal =
780+ foldr1 (\e e' -> infixApp e [|(<|>)|] e')
781+ (map (\x -> parseValue tvMap x conVal) cons')
782+
783+ parseValue _tvMap
784+ ConstructorInfo { constructorName = conName
785+ , constructorVariant = NormalConstructor
786+ , constructorFields = [] }
787+ conVal = do
788+ str <- newName "str"
789+ caseE (varE conVal)
790+ [ match (conP 'String [varP str])
791+ (guardedB
792+ [ liftM2 (,) (normalG $ infixApp (varE str) [|(==)|] (conTxt opts conName)
793+ )
794+ ([|pure|] `appE` conE conName)
795+ ]
796+ )
797+ []
798+ , matchFailed tName conName "String"
799+ ]
800+ parseValue tvMap con conVal =
801+ checkExi tvMap con $ parseArgs jc tvMap tName opts con (Right conVal)
802+
803+
804+ parse2ElemArray tvMap arr = do
932805 conKey <- newName "conKey"
933806 conVal <- newName "conVal"
934807 let letIx n ix =
@@ -943,7 +816,7 @@ consFromJSON jc tName opts cons = do
943816 (caseE (varE conKey)
944817 [ do txt <- newName "txt"
945818 match (conP 'String [varP txt])
946− (normalB $ parseContents pjs
819+ (normalB $ parseContents tvMap
947820 txt
948821 (Right conVal)
949822 'conNotFoundFail2ElemArray
@@ -953,30 +826,30 @@ consFromJSON jc tName opts cons = do
953826 match (varP other)
954827 ( normalB
955828 $ [|firstElemNoStringFail|]
956− `appE` (litE $ stringL $ show tName)
829+ `appE` litE (stringL $ show tName)
957830 `appE` ([|valueConName|] `appE` varE other)
958831 )
959832 []
960833 ]
961834 )
962835
963− parseObjectWithSingleField pjs obj = do
836+ parseObjectWithSingleField tvMap obj = do
964837 conKey <- newName "conKey"
965838 conVal <- newName "conVal"
966839 caseE ([e|H.toList|] `appE` varE obj)
967840 [ match (listP [tupP [varP conKey, varP conVal]])
968− (normalB $ parseContents pjs conKey (Right conVal) 'conNotFoundFailObjectSingleField)
841+ (normalB $ parseContents tvMap conKey (Right conVal) 'conNotFoundFailObjectSingleField)
969842 []
970843 , do other <- newName "other"
971844 match (varP other)
972845 (normalB $ [|wrongPairCountFail|]
973− `appE` (litE $ stringL $ show tName)
846+ `appE` litE (stringL $ show tName)
974847 `appE` ([|show . length|] `appE` varE other)
975848 )
976849 []
977850 ]
978851
979− parseContents pjs conKey contents errorFun =
852+ parseContents tvMap conKey contents errorFun =
980853 caseE (varE conKey)
981854 [ match wildP
982855 ( guardedB $
@@ -984,7 +857,8 @@ consFromJSON jc tName opts cons = do
984857 [|(==)|]
985858 ([|T.pack|] `appE`
986859 conNameExp opts con)
987− e <- parseArgs jc pjs tName opts con contents
860+ e <- checkExi tvMap con $
861+ parseArgs jc tvMap tName opts con contents
988862 return (g, e)
989863 | con <- cons
990864 ]
@@ -992,12 +866,12 @@ consFromJSON jc tName opts cons = do
992866 [ liftM2 (,)
993867 (normalG [e|otherwise|])
994868 ( varE errorFun
995− `appE` (litE $ stringL $ show tName)
869+ `appE` litE (stringL $ show tName)
996870 `appE` listE (map ( litE
997871 . stringL
998872 . constructorTagModifier opts
999873 . nameBase
1000− . getConName
874+ . constructorName
1001875 ) cons
1002876 )
1003877 `appE` ([|T.unpack|] `appE` varE conKey)
@@ -1011,13 +885,13 @@ parseNullaryMatches :: Name -> Name -> [Q Match]
1011885parseNullaryMatches tName conName =
1012886 [ do arr <- newName "arr"
1013887 match (conP 'Array [varP arr])
1014− (guardedB $
888+ (guardedB
1015889 [ liftM2 (,) (normalG $ [|V.null|] `appE` varE arr)
1016890 ([|pure|] `appE` conE conName)
1017891 , liftM2 (,) (normalG [|otherwise|])
1018892 (parseTypeMismatch tName conName
1019893 (litE $ stringL "an empty Array")
1020− (infixApp (litE $ stringL $ "Array of length ")
894+ (infixApp (litE $ stringL "Array of length ")
1021895 [|(++)|]
1022896 ([|show . V.length|] `appE` varE arr)
1023897 )
@@ -1046,22 +920,42 @@ parseRecord :: JSONClass
1046920 -> Options
1047921 -> Name
1048922 -> Name
1049− -> [VarStrictType]
923+ -> [Name]
1050924 -> Name
925+ -> Bool
1051926 -> ExpQ
1052−parseRecord jc tvMap argTys opts tName conName ts obj =
927+parseRecord jc tvMap argTys opts tName conName fields obj inTaggedObject =
928+ (if rejectUnknownFields opts
929+ then infixApp checkUnknownRecords [|(>>)|]
930+ else id) $
1053931 foldl' (\a b -> infixApp a [|(<*>)|] b)
1054932 (infixApp (conE conName) [|(<$>)|] x)
1055933 xs
1056934 where
935+ tagFieldNameAppender =
936+ if inTaggedObject then (tagFieldName (sumEncoding opts) :) else id
937+ knownFields = appE [|H.fromList|] $ listE $
938+ map (\knownName -> tupE [appE [|T.pack|] $ litE $ stringL knownName, [|()|]]) $
939+ tagFieldNameAppender $ map nameBase fields
940+ checkUnknownRecords =
941+ caseE (appE [|H.keys|] $ infixApp (varE obj) [|H.difference|] knownFields)
942+ [ match (listP []) (normalB [|return ()|]) []
943+ , newName "unknownFields" >>=
944+ \unknownFields -> match (varP unknownFields)
945+ (normalB $ appE [|fail|] $ infixApp
946+ (litE (stringL "Unknown fields: "))
947+ [|(++)|]
948+ (appE [|show|] (varE unknownFields)))
949+ []
950+ ]
1057951 x:xs = [ [|lookupField|]
1058952 `appE` dispatchParseJSON jc conName tvMap argTy
1059− `appE` (litE $ stringL $ show tName)
1060− `appE` (litE $ stringL $ constructorTagModifier opts $ nameBase conName)
1061− `appE` (varE obj)
1062− `appE` ( [|T.pack|] `appE` fieldLabelExp opts field
953+ `appE` litE (stringL $ show tName)
954+ `appE` litE (stringL $ constructorTagModifier opts $ nameBase conName)
955+ `appE` varE obj
956+ `appE` ( [|T.pack|] `appE` stringE (fieldLabel opts field)
1063957 )
1064− | ((field, _, _), argTy) <- zip ts argTys
958+ | (field, argTy) <- zip fields argTys
1065959 ]
1066960
1067961getValField :: Name -> String -> [MatchQ] -> Q Exp
@@ -1070,7 +964,7 @@ getValField obj valFieldName matches = do
1070964 doE [ bindS (varP val) $ infixApp (varE obj)
1071965 [|(.:)|]
1072966 ([|T.pack|] `appE`
1073− (litE $ stringL valFieldName))
967+ litE (stringL valFieldName))
1074968 , noBindS $ caseE (varE val) matches
1075969 ]
1076970
@@ -1080,67 +974,82 @@ matchCases (Right valName) = caseE (varE valName)
1080974
1081975-- | Generates code to parse the JSON encoding of a single constructor.
1082976parseArgs :: JSONClass -- ^ The FromJSON variant being derived.
1083− -> [(Name, Name)] -- ^ The names of the encoding/decoding function arguments.
977+ -> TyVarMap -- ^ Maps the last type variables to their decoding
978+ -- function arguments.
1084979 -> Name -- ^ Name of the type to which the constructor belongs.
1085980 -> Options -- ^ Encoding options.
1086− -> Con -- ^ Constructor for which to generate JSON parsing code.
981+ -> ConstructorInfo -- ^ Constructor for which to generate JSON parsing code.
1087982 -> Either (String, Name) Name -- ^ Left (valFieldName, objName) or
1088983 -- Right valName
1089984 -> Q Exp
1090985-- Nullary constructors.
1091−parseArgs jc pjs _ _ (NormalC conName []) (Left _) = do
1092− ([], _) <- reifyConTys jc pjs conName
1093− [|pure|] `appE` conE conName
1094−parseArgs jc pjs tName _ (NormalC conName []) (Right valName) = do
1095− ([], _) <- reifyConTys jc pjs conName
1096− caseE (varE valName) $ parseNullaryMatches tName conName
986+parseArgs _ _ _ _
987+ ConstructorInfo { constructorName = conName
988+ , constructorVariant = NormalConstructor
989+ , constructorFields = [] }
990+ (Left _) =
991+ [|pure|] `appE` conE conName
992+parseArgs _ _ tName _
993+ ConstructorInfo { constructorName = conName
994+ , constructorVariant = NormalConstructor
995+ , constructorFields = [] }
996+ (Right valName) =
997+ caseE (varE valName) $ parseNullaryMatches tName conName
1097998
1098999-- Unary constructors.
1099−parseArgs jc pjs _ _ (NormalC conName [_]) contents = do
1100− ([argTy], tvMap) <- reifyConTys jc pjs conName
1101− matchCases contents $ parseUnaryMatches jc tvMap argTy conName
1000+parseArgs jc tvMap _ _
1001+ ConstructorInfo { constructorName = conName
1002+ , constructorVariant = NormalConstructor
1003+ , constructorFields = [argTy] }
1004+ contents = do
1005+ argTy' <- resolveTypeSynonyms argTy
1006+ matchCases contents $ parseUnaryMatches jc tvMap argTy' conName
11021007
11031008-- Polyadic constructors.
1104−parseArgs jc pjs tName _ (NormalC conName ts) contents = do
1105− (argTys, tvMap) <- reifyConTys jc pjs conName
1106− let len = genericLength ts
1107− matchCases contents $ parseProduct jc tvMap argTys tName conName len
1009+parseArgs jc tvMap tName _
1010+ ConstructorInfo { constructorName = conName
1011+ , constructorVariant = NormalConstructor
1012+ , constructorFields = argTys }
1013+ contents = do
1014+ argTys' <- mapM resolveTypeSynonyms argTys
1015+ let len = genericLength argTys'
1016+ matchCases contents $ parseProduct jc tvMap argTys' tName conName len
11081017
11091018-- Records.
1110−parseArgs jc pjs tName opts (RecC conName ts) (Left (_, obj)) = do
1111− (argTys, tvMap) <- reifyConTys jc pjs conName
1112− parseRecord jc tvMap argTys opts tName conName ts obj
1113−parseArgs jc pjs tName opts (RecC conName ts) (Right valName) = case (unwrapUnaryRecords opts,ts) of
1114− (True,[(_,st,ty)])-> parseArgs jc pjs tName opts (NormalC conName [(st,ty)]) (Right valName)
1115− _ -> do
1116− obj <- newName "recObj"
1117− (argTys, tvMap) <- reifyConTys jc pjs conName
1118− caseE (varE valName)
1119− [ match (conP 'Object [varP obj]) (normalB $
1120− parseRecord jc tvMap argTys opts tName conName ts obj) []
1121− , matchFailed tName conName "Object"
1122− ]
1019+parseArgs jc tvMap tName opts
1020+ ConstructorInfo { constructorName = conName
1021+ , constructorVariant = RecordConstructor fields
1022+ , constructorFields = argTys }
1023+ (Left (_, obj)) = do
1024+ argTys' <- mapM resolveTypeSynonyms argTys
1025+ parseRecord jc tvMap argTys' opts tName conName fields obj True
1026+parseArgs jc tvMap tName opts
1027+ info@ConstructorInfo { constructorName = conName
1028+ , constructorVariant = RecordConstructor fields
1029+ , constructorFields = argTys }
1030+ (Right valName) =
1031+ case (unwrapUnaryRecords opts,argTys) of
1032+ (True,[_])-> parseArgs jc tvMap tName opts
1033+ (info{constructorVariant = NormalConstructor})
1034+ (Right valName)
1035+ _ -> do
1036+ obj <- newName "recObj"
1037+ argTys' <- mapM resolveTypeSynonyms argTys
1038+ caseE (varE valName)
1039+ [ match (conP 'Object [varP obj]) (normalB $
1040+ parseRecord jc tvMap argTys' opts tName conName fields obj False) []
1041+ , matchFailed tName conName "Object"
1042+ ]
11231043
11241044-- Infix constructors. Apart from syntax these are the same as
11251045-- polyadic constructors.
1126−parseArgs jc pjs tName _ (InfixC _ conName _) contents = do
1127− (argTys, tvMap) <- reifyConTys jc pjs conName
1128− matchCases contents $ parseProduct jc tvMap argTys tName conName 2
1129−
1130−-- Existentially quantified constructors. We ignore the quantifiers
1131−-- and proceed with the contained constructor.
1132−parseArgs jc pjs tName opts (ForallC _ _ con) contents =
1133− parseArgs jc pjs tName opts con contents
1134−
1135−#if MIN_VERSION_template_haskell(2,11,0)
1136−-- GADTs. We ignore the refined return type and proceed as if it were a
1137−-- NormalC or RecC.
1138−parseArgs jc pjs tName opts (GadtC conNames ts _) contents =
1139− parseArgs jc pjs tName opts (NormalC (head conNames) ts) contents
1140−
1141−parseArgs jc pjs tName opts (RecGadtC conNames ts _) contents =
1142− parseArgs jc pjs tName opts (RecC (head conNames) ts) contents
1143−#endif
1046+parseArgs jc tvMap tName _
1047+ ConstructorInfo { constructorName = conName
1048+ , constructorVariant = InfixConstructor
1049+ , constructorFields = argTys }
1050+ contents = do
1051+ argTys' <- mapM resolveTypeSynonyms argTys
1052+ matchCases contents $ parseProduct jc tvMap argTys' tName conName 2
11441053
11451054-- | Generates code to parse the JSON encoding of an n-ary
11461055-- constructor.
@@ -1173,7 +1082,7 @@ parseProduct jc tvMap argTys tName conName numArgs =
11731082 )
11741083 ( parseTypeMismatch tName conName
11751084 (litE $ stringL $ "Array of length " ++ show numArgs)
1176− ( infixApp (litE $ stringL $ "Array of length ")
1085+ ( infixApp (litE $ stringL "Array of length ")
11771086 [|(++)|]
11781087 ([|show . V.length|] `appE` varE arr)
11791088 )
@@ -1214,9 +1123,14 @@ class LookupField a where
12141123instance OVERLAPPABLE_ LookupField a where
12151124 lookupField = lookupFieldWith
12161125
1217−instance LookupField (Maybe a) where
1126+instance INCOHERENT_ LookupField (Maybe a) where
12181127 lookupField pj _ _ = parseOptionalFieldWith pj
12191128
1129+instance INCOHERENT_ LookupField (Semigroup.Option a) where
1130+ lookupField pj tName rec obj key =
1131+ fmap Semigroup.Option
1132+ (lookupField (fmap Semigroup.getOption . pj) tName rec obj key)
1133+
12201134lookupFieldWith :: (Value -> Parser a) -> String -> String
12211135 -> Object -> T.Text -> Parser a
12221136lookupFieldWith pj tName rec obj key =
@@ -1224,9 +1138,6 @@ lookupFieldWith pj tName rec obj key =
12241138 Nothing -> unknownFieldFail tName rec (T.unpack key)
12251139 Just v -> pj v <?> Key key
12261140
1227−keyValuePairWith :: (v -> Value) -> T.Text -> v -> Pair
1228−keyValuePairWith tj name value = (name, tj value)
1229−
12301141unknownFieldFail :: String -> String -> String -> Parser fail
12311142unknownFieldFail tName rec key =
12321143 fail $ printf "When parsing the record %s of type %s the key %s was not present."
@@ -1295,7 +1206,8 @@ deriveJSONBoth dtj dfj opts name =
12951206 liftM2 (++) (dtj opts name) (dfj opts name)
12961207
12971208-- | Functionality common to @deriveToJSON(1)(2)@ and @deriveFromJSON(1)(2)@.
1298−deriveJSONClass :: [(JSONFun, JSONClass -> Name -> Options -> [Con] -> Q Exp)]
1209+deriveJSONClass :: [(JSONFun, JSONClass -> Name -> Options -> [Type]
1210+ -> [ConstructorInfo] -> Q Exp)]
12991211 -- ^ The class methods and the functions which derive them.
13001212 -> JSONClass
13011213 -- ^ The class for which to generate an instance.
@@ -1305,27 +1217,34 @@ deriveJSONClass :: [(JSONFun, JSONClass -> Name -> Options -> [Con] -> Q Exp)]
13051217 -- ^ Name of the type for which to generate a class instance
13061218 -- declaration.
13071219 -> Q [Dec]
1308−deriveJSONClass consFuns jc opts name =
1309− withType name $ \name' ctxt tvbs cons mbTys ->
1310− fmap (:[]) $ fromCons name' ctxt tvbs cons mbTys
1311− where
1312− fromCons :: Name -> Cxt -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q Dec
1313− fromCons name' ctxt tvbs cons mbTys = do
1220+deriveJSONClass consFuns jc opts name = do
1221+ info <- reifyDatatype name
1222+ case info of
1223+ DatatypeInfo { datatypeContext = ctxt
1224+ , datatypeName = parentName
1225+#if MIN_VERSION_th_abstraction(0,3,0)
1226+ , datatypeInstTypes = instTys
1227+#else
1228+ , datatypeVars = instTys
1229+#endif
1230+ , datatypeVariant = variant
1231+ , datatypeCons = cons
1232+ } -> do
13141233 (instanceCxt, instanceType)
1315− <- buildTypeInstance name' jc ctxt tvbs mbTys
1316− instanceD (return instanceCxt)
1317− (return instanceType)
1318− (methodDecs name' cons)
1319−
1320− methodDecs :: Name -> [Con] -> [Q Dec]
1321− methodDecs name' cons = flip map consFuns $ \(jf, jfMaker) ->
1234+ <- buildTypeInstance parentName jc ctxt instTys variant
1235+ (:[]) <$> instanceD (return instanceCxt)
1236+ (return instanceType)
1237+ (methodDecs parentName instTys cons)
1238+ where
1239+ methodDecs :: Name -> [Type] -> [ConstructorInfo] -> [Q Dec]
1240+ methodDecs parentName instTys cons = flip map consFuns $ \(jf, jfMaker) ->
13221241 funD (jsonFunValName jf (arity jc))
13231242 [ clause []
1324− (normalB $ jfMaker jc name' opts cons)
1243+ (normalB $ jfMaker jc parentName opts instTys cons)
13251244 []
13261245 ]
13271246
1328−mkFunCommon :: (JSONClass -> Name -> Options -> [Con] -> Q Exp)
1247+mkFunCommon :: (JSONClass -> Name -> Options -> [Type] -> [ConstructorInfo] -> Q Exp)
13291248 -- ^ The function which derives the expression.
13301249 -> JSONClass
13311250 -- ^ Which class's method is being derived.
@@ -1334,15 +1253,24 @@ mkFunCommon :: (JSONClass -> Name -> Options -> [Con] -> Q Exp)
13341253 -> Name
13351254 -- ^ Name of the encoded type.
13361255 -> Q Exp
1337−mkFunCommon consFun jc opts name = withType name fromCons
1338− where
1339− fromCons :: Name -> Cxt -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q Exp
1340− fromCons name' ctxt tvbs cons mbTys = do
1341− -- We force buildTypeInstance here since it performs some checks for whether
1342− -- or not the provided datatype's kind matches the derived method's
1343− -- typeclass, and produces errors if it can't.
1344− !_ <- buildTypeInstance name' jc ctxt tvbs mbTys
1345− consFun jc name' opts cons
1256+mkFunCommon consFun jc opts name = do
1257+ info <- reifyDatatype name
1258+ case info of
1259+ DatatypeInfo { datatypeContext = ctxt
1260+ , datatypeName = parentName
1261+#if MIN_VERSION_th_abstraction(0,3,0)
1262+ , datatypeInstTypes = instTys
1263+#else
1264+ , datatypeVars = instTys
1265+#endif
1266+ , datatypeVariant = variant
1267+ , datatypeCons = cons
1268+ } -> do
1269+ -- We force buildTypeInstance here since it performs some checks for whether
1270+ -- or not the provided datatype's kind matches the derived method's
1271+ -- typeclass, and produces errors if it can't.
1272+ !_ <- buildTypeInstance parentName jc ctxt instTys variant
1273+ consFun jc parentName opts instTys cons
13461274
13471275dispatchFunByType :: JSONClass
13481276 -> JSONFun
@@ -1380,205 +1308,44 @@ dispatchFunByType jc jf conName tvMap list ty = do
13801308 if any (`mentionsName` tyVarNames) lhsArgs
13811309 || itf && any (`mentionsName` tyVarNames) tyArgs
13821310 then outOfPlaceTyVarError jc conName
1383− else appsE $ [ varE . jsonFunValOrListName list jf $ toEnum numLastArgs]
1384− ++ zipWith (dispatchFunByType jc jf conName tvMap)
1385− (cycle [False,True])
1386− (interleave rhsArgs rhsArgs)
1387−
1388−dispatchToJSON, dispatchToEncoding, dispatchParseJSON
1311+ else if any (`mentionsName` tyVarNames) rhsArgs
1312+ then appsE $ varE (jsonFunValOrListName list jf $ toEnum numLastArgs)
1313+ : zipWith (dispatchFunByType jc jf conName tvMap)
1314+ (cycle [False,True])
1315+ (interleave rhsArgs rhsArgs)
1316+ else varE $ jsonFunValOrListName list jf Arity0
1317+
1318+dispatchToJSON
1319+ :: ToJSONFun -> JSONClass -> Name -> TyVarMap -> Type -> Q Exp
1320+dispatchToJSON target jc n tvMap =
1321+ dispatchFunByType jc (targetToJSONFun target) n tvMap False
1322+
1323+dispatchParseJSON
13891324 :: JSONClass -> Name -> TyVarMap -> Type -> Q Exp
1390−dispatchToJSON jc n tvMap = dispatchFunByType jc ToJSON n tvMap False
1391−dispatchToEncoding jc n tvMap = dispatchFunByType jc ToEncoding n tvMap False
13921325dispatchParseJSON jc n tvMap = dispatchFunByType jc ParseJSON n tvMap False
13931326
13941327--------------------------------------------------------------------------------
13951328-- Utility functions
13961329--------------------------------------------------------------------------------
13971330
1398−-- | Boilerplate for top level splices.
1399−--
1400−-- The given 'Name' must meet one of two criteria:
1401−--
1402−-- 1. It must be the name of a type constructor of a plain data type or newtype.
1403−-- 2. It must be the name of a data family instance or newtype instance constructor.
1404−
1405−-- Any other value will result in an exception.
1406−withType :: Name
1407− -> (Name -> Cxt -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q a)
1408− -- ^ Function that generates the actual code. Will be applied
1409− -- to the datatype/data family 'Name', datatype context, type
1410− -- variable binders and constructors extracted from the given
1411− -- 'Name'. If the 'Name' is from a data family instance
1412− -- constructor, it will also have its instantiated types;
1413− -- otherwise, it will be 'Nothing'.
1414− -> Q a
1415− -- ^ Resulting value in the 'Q'uasi monad.
1416−withType name f = do
1417− info <- reify name
1418− case info of
1419− TyConI dec ->
1420− case dec of
1421−#if MIN_VERSION_template_haskell(2,11,0)
1422− DataD ctxt _ tvbs _ cons _ -> f name ctxt tvbs cons Nothing
1423− NewtypeD ctxt _ tvbs _ con _ -> f name ctxt tvbs [con] Nothing
1424−#else
1425− DataD ctxt _ tvbs cons _ -> f name ctxt tvbs cons Nothing
1426− NewtypeD ctxt _ tvbs con _ -> f name ctxt tvbs [con] Nothing
1427−#endif
1428− other -> fail $ ns ++ "Unsupported type: " ++ show other
1429−#if MIN_VERSION_template_haskell(2,11,0)
1430− DataConI _ _ parentName -> do
1431−#else
1432− DataConI _ _ parentName _ -> do
1433−#endif
1434− parentInfo <- reify parentName
1435− case parentInfo of
1436−#if MIN_VERSION_template_haskell(2,11,0)
1437− FamilyI (DataFamilyD _ tvbs _) decs ->
1438−#else
1439− FamilyI (FamilyD DataFam _ tvbs _) decs ->
1440−#endif
1441− let instDec = flip find decs $ \dec -> case dec of
1442−#if MIN_VERSION_template_haskell(2,11,0)
1443− DataInstD _ _ _ _ cons _ -> any ((name ==) . getConName) cons
1444− NewtypeInstD _ _ _ _ con _ -> name == getConName con
1445−#else
1446− DataInstD _ _ _ cons _ -> any ((name ==) . getConName) cons
1447− NewtypeInstD _ _ _ con _ -> name == getConName con
1448−#endif
1449− _ -> error $ ns ++ "Must be a data or newtype instance."
1450− in case instDec of
1451−#if MIN_VERSION_template_haskell(2,11,0)
1452− Just (DataInstD ctxt _ instTys _ cons _) -> f parentName ctxt tvbs cons $ Just instTys
1453− Just (NewtypeInstD ctxt _ instTys _ con _) -> f parentName ctxt tvbs [con] $ Just instTys
1454−#else
1455− Just (DataInstD ctxt _ instTys cons _) -> f parentName ctxt tvbs cons $ Just instTys
1456− Just (NewtypeInstD ctxt _ instTys con _) -> f parentName ctxt tvbs [con] $ Just instTys
1457−#endif
1458− _ -> fail $ ns ++
1459− "Could not find data or newtype instance constructor."
1460− _ -> fail $ ns ++ "Data constructor " ++ show name ++
1461− " is not from a data family instance constructor."
1462−#if MIN_VERSION_template_haskell(2,11,0)
1463− FamilyI DataFamilyD{} _ ->
1464−#else
1465− FamilyI (FamilyD DataFam _ _ _) _ ->
1466−#endif
1467− fail $ ns ++
1468− "Cannot use a data family name. Use a data family instance constructor instead."
1469− _ -> fail $ ns ++ "I need the name of a plain data type constructor, "
1470− ++ "or a data family instance constructor."
1471− where
1472− ns :: String
1473− ns = "Data.Aeson.TH.withType: "
1474−
1475−-- | Infer the context and instance head needed for a FromJSON or ToJSON instance.
1331+-- For the given Types, generate an instance context and head.
14761332buildTypeInstance :: Name
14771333 -- ^ The type constructor or data family name
14781334 -> JSONClass
14791335 -- ^ The typeclass to derive
14801336 -> Cxt
14811337 -- ^ The datatype context
1482− -> [TyVarBndr]
1483− -- ^ The type variables from the data type/data family declaration
1484− -> Maybe [Type]
1485− -- ^ 'Just' the types used to instantiate a data family instance,
1486− -- or 'Nothing' if it's a plain data type
1338+ -> [Type]
1339+ -- ^ The types to instantiate the instance with
1340+ -> DatatypeVariant
1341+ -- ^ Are we dealing with a data family instance or not
14871342 -> Q (Cxt, Type)
1488− -- ^ The resulting 'Cxt' and 'Type' to use in a class instance
1489−-- Plain data type/newtype case
1490−buildTypeInstance tyConName jc dataCxt tvbs Nothing =
1491− let varTys :: [Type]
1492− varTys = map tvbToType tvbs
1493− in buildTypeInstanceFromTys tyConName jc dataCxt varTys False
1494−-- Data family instance case
1495−--
1496−-- The CPP is present to work around a couple of annoying old GHC bugs.
1497−-- See Note [Polykinded data families in Template Haskell]
1498−buildTypeInstance dataFamName jc dataCxt tvbs (Just instTysAndKinds) = do
1499−#if !(MIN_VERSION_template_haskell(2,8,0)) || MIN_VERSION_template_haskell(2,10,0)
1500− let instTys :: [Type]
1501− instTys = zipWith stealKindForType tvbs instTysAndKinds
1502−#else
1503− let kindVarNames :: [Name]
1504− kindVarNames = nub $ concatMap (tyVarNamesOfType . tvbKind) tvbs
1505−
1506− numKindVars :: Int
1507− numKindVars = length kindVarNames
1508−
1509− givenKinds, givenKinds' :: [Kind]
1510− givenTys :: [Type]
1511− (givenKinds, givenTys) = splitAt numKindVars instTysAndKinds
1512− givenKinds' = map sanitizeStars givenKinds
1513−
1514− -- A GHC 7.6-specific bug requires us to replace all occurrences of
1515− -- (ConT GHC.Prim.*) with StarT, or else Template Haskell will reject it.
1516− -- Luckily, (ConT GHC.Prim.*) only seems to occur in this one spot.
1517− sanitizeStars :: Kind -> Kind
1518− sanitizeStars = go
1519− where
1520− go :: Kind -> Kind
1521− go (AppT t1 t2) = AppT (go t1) (go t2)
1522− go (SigT t k) = SigT (go t) (go k)
1523− go (ConT n) | n == starKindName = StarT
1524− go t = t
1525−
1526− -- It's quite awkward to import * from GHC.Prim, so we'll just
1527− -- hack our way around it.
1528− starKindName :: Name
1529− starKindName = mkNameG_tc "ghc-prim" "GHC.Prim" "*"
1530−
1531− -- If we run this code with GHC 7.8, we might have to generate extra type
1532− -- variables to compensate for any type variables that Template Haskell
1533− -- eta-reduced away.
1534− -- See Note [Polykinded data families in Template Haskell]
1535− xTypeNames <- newNameList "tExtra" (length tvbs - length givenTys)
1536−
1537− let xTys :: [Type]
1538− xTys = map VarT xTypeNames
1539− -- ^ Because these type variables were eta-reduced away, we can only
1540− -- determine their kind by using stealKindForType. Therefore, we mark
1541− -- them as VarT to ensure they will be given an explicit kind annotation
1542− -- (and so the kind inference machinery has the right information).
1543−
1544− substNamesWithKinds :: [(Name, Kind)] -> Type -> Type
1545− substNamesWithKinds nks t = foldr' (uncurry substNameWithKind) t nks
1546−
1547− -- The types from the data family instance might not have explicit kind
1548− -- annotations, which the kind machinery needs to work correctly. To
1549− -- compensate, we use stealKindForType to explicitly annotate any
1550− -- types without kind annotations.
1551− instTys :: [Type]
1552− instTys = map (substNamesWithKinds (zip kindVarNames givenKinds'))
1553− -- Note that due to a GHC 7.8-specific bug
1554− -- (see Note [Polykinded data families in Template Haskell]),
1555− -- there may be more kind variable names than there are kinds
1556− -- to substitute. But this is OK! If a kind is eta-reduced, it
1557− -- means that is was not instantiated to something more specific,
1558− -- so we need not substitute it. Using stealKindForType will
1559− -- grab the correct kind.
1560− $ zipWith stealKindForType tvbs (givenTys ++ xTys)
1561−#endif
1562− buildTypeInstanceFromTys dataFamName jc dataCxt instTys True
1563−
1564−-- For the given Types, generate an instance context and head.
1565−buildTypeInstanceFromTys :: Name
1566− -- ^ The type constructor or data family name
1567− -> JSONClass
1568− -- ^ The typeclass to derive
1569− -> Cxt
1570− -- ^ The datatype context
1571− -> [Type]
1572− -- ^ The types to instantiate the instance with
1573− -> Bool
1574− -- ^ True if it's a data family, False otherwise
1575− -> Q (Cxt, Type)
1576−buildTypeInstanceFromTys tyConName jc dataCxt varTysOrig isDataFamily = do
1343+buildTypeInstance tyConName jc dataCxt varTysOrig variant = do
15771344 -- Make sure to expand through type/kind synonyms! Otherwise, the
15781345 -- eta-reduction check might get tripped up over type variables in a
15791346 -- synonym that are actually dropped.
15801347 -- (See GHC Trac #11416 for a scenario where this actually happened.)
1581− varTysExp <- mapM expandSyn varTysOrig
1348+ varTysExp <- mapM resolveTypeSynonyms varTysOrig
15821349
15831350 let remainingLength :: Int
15841351 remainingLength = length varTysOrig - arityInt jc
@@ -1591,7 +1358,7 @@ buildTypeInstanceFromTys tyConName jc dataCxt varTysOrig isDataFamily = do
15911358
15921359 -- Check there are enough types to drop and that all of them are either of
15931360 -- kind * or kind k (for some kind variable k). If not, throw an error.
1594− when (remainingLength < 0 || any (== NotKindStar) droppedStarKindStati) $
1361+ when (remainingLength < 0 || elem NotKindStar droppedStarKindStati) $
15951362 derivingKindError jc tyConName
15961363
15971364 let droppedKindVarNames :: [Name]
@@ -1608,7 +1375,7 @@ buildTypeInstanceFromTys tyConName jc dataCxt varTysOrig isDataFamily = do
16081375 -- All of the type variables mentioned in the dropped types
16091376 -- (post-synonym expansion)
16101377 droppedTyVarNames :: [Name]
1611− droppedTyVarNames = concatMap tyVarNamesOfType droppedTysExpSubst
1378+ droppedTyVarNames = freeVariables droppedTysExpSubst
16121379
16131380 -- If any of the dropped types were polykinded, ensure that they are of kind *
16141381 -- after substituting * for the dropped kind variables. If not, throw an error.
@@ -1646,9 +1413,16 @@ buildTypeInstanceFromTys tyConName jc dataCxt varTysOrig isDataFamily = do
16461413 -- instance C (Fam [Char])
16471414 remainingTysOrigSubst :: [Type]
16481415 remainingTysOrigSubst =
1649− map (substNamesWithKindStar (union droppedKindVarNames kvNames'))
1416+ map (substNamesWithKindStar (droppedKindVarNames `union` kvNames'))
16501417 $ take remainingLength varTysOrig
16511418
1419+ isDataFamily :: Bool
1420+ isDataFamily = case variant of
1421+ Datatype -> False
1422+ Newtype -> False
1423+ DataInstance -> True
1424+ NewtypeInstance -> True
1425+
16521426 remainingTysOrigSubst' :: [Type]
16531427 -- See Note [Kind signatures in derived instances] for an explanation
16541428 -- of the isDataFamily check.
@@ -1702,55 +1476,6 @@ deriveConstraint jc t
17021476 jcConstraint = jsonClassName . JSONClass (direction jc)
17031477
17041478{-
1705−Note [Polykinded data families in Template Haskell]
1706−~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1707−
1708−In order to come up with the correct instance context and head for an instance, e.g.,
1709−
1710− instance C a => C (Data a) where ...
1711−
1712−We need to know the exact types and kinds used to instantiate the instance. For
1713−plain old datatypes, this is simple: every type must be a type variable, and
1714−Template Haskell reliably tells us the type variables and their kinds.
1715−
1716−Doing the same for data families proves to be much harder for three reasons:
1717−
1718−1. On any version of Template Haskell, it may not tell you what an instantiated
1719− type's kind is. For instance, in the following data family instance:
1720−
1721− data family Fam (f :: * -> *) (a :: *)
1722− data instance Fam f a
1723−
1724− Then if we use TH's reify function, it would tell us the TyVarBndrs of the
1725− data family declaration are:
1726−
1727− [KindedTV f (AppT (AppT ArrowT StarT) StarT),KindedTV a StarT]
1728−
1729− and the instantiated types of the data family instance are:
1730−
1731− [VarT f1,VarT a1]
1732−
1733− We can't just pass [VarT f1,VarT a1] to buildTypeInstanceFromTys, since we
1734− have no way of knowing their kinds. Luckily, the TyVarBndrs tell us what the
1735− kind is in case an instantiated type isn't a SigT, so we use the stealKindForType
1736− function to ensure all of the instantiated types are SigTs before passing them
1737− to buildTypeInstanceFromTys.
1738−2. On GHC 7.6 and 7.8, a bug is present in which Template Haskell lists all of
1739− the specified kinds of a data family instance efore any of the instantiated
1740− types. Fortunately, this is easy to deal with: you simply count the number of
1741− distinct kind variables in the data family declaration, take that many elements
1742− from the front of the Types list of the data family instance, substitute the
1743− kind variables with their respective instantiated kinds (which you took earlier),
1744− and proceed as normal.
1745−3. On GHC 7.8, an even uglier bug is present (GHC Trac #9692) in which Template
1746− Haskell might not even list all of the Types of a data family instance, since
1747− they are eta-reduced away! And yes, kinds can be eta-reduced too.
1748−
1749− The simplest workaround is to count how many instantiated types are missing from
1750− the list and generate extra type variables to use in their place. Luckily, we
1751− needn't worry much if its kind was eta-reduced away, since using stealKindForType
1752− will get it back.
1753−
17541479Note [Kind signatures in derived instances]
17551480~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17561481
@@ -1828,50 +1553,14 @@ things we can do to make instance contexts that work for 80% of use cases:
18281553 and perform kind substitution as in the other cases.
18291554-}
18301555
1831−-- Determines the types of a constructor's arguments as well as the last type
1832−-- parameters (mapped to their encoding/decoding functions), expanding through
1833−-- any type synonyms.
1834−--
1835−-- The type parameters are determined on a constructor-by-constructor basis since
1836−-- they may be refined to be particular types in a GADT.
1837−reifyConTys :: JSONClass
1838− -> [(Name, Name)]
1839− -> Name
1840− -> Q ([Type], TyVarMap)
1841−reifyConTys jc tpjs conName = do
1842− info <- reify conName
1843− (ctxt, uncTy) <- case info of
1844− DataConI _ ty _
1845−#if !(MIN_VERSION_template_haskell(2,11,0))
1846− _
1847−#endif
1848− -> fmap uncurryTy (expandSyn ty)
1849− _ -> error "Must be a data constructor"
1850− let (argTys, [resTy]) = NE.splitAt (NE.length uncTy - 1) uncTy
1851− unapResTy = unapplyTy resTy
1852− -- If one of the last type variables is refined to a particular type
1853− -- (i.e., not truly polymorphic), we mark it with Nothing and filter
1854− -- it out later, since we only apply encoding/decoding functions to
1855− -- arguments of a type that it (1) one of the last type variables,
1856− -- and (2) of a truly polymorphic type.
1857− jArity = arityInt jc
1858− mbTvNames = map varTToName_maybe $
1859− NE.drop (NE.length unapResTy - jArity) unapResTy
1860− -- We use M.fromList to ensure that if there are any duplicate type
1861− -- variables (as can happen in a GADT), the rightmost type variable gets
1862− -- associated with the show function.
1863− --
1864− -- See Note [Matching functions with GADT type variables]
1865− tvMap = M.fromList
1866− . catMaybes -- Drop refined types
1867− $ zipWith (\mbTvName tpj ->
1868− fmap (\tvName -> (tvName, tpj)) mbTvName)
1869− mbTvNames tpjs
1870− if (any (`predMentionsName` M.keys tvMap) ctxt
1871− || M.size tvMap < jArity)
1872− && not (allowExQuant jc)
1873− then existentialContextError conName
1874− else return (argTys, tvMap)
1556+checkExistentialContext :: JSONClass -> TyVarMap -> Cxt -> Name
1557+ -> Q a -> Q a
1558+checkExistentialContext jc tvMap ctxt conName q =
1559+ if (any (`predMentionsName` M.keys tvMap) ctxt
1560+ || M.size tvMap < arityInt jc)
1561+ && not (allowExQuant jc)
1562+ then existentialContextError conName
1563+ else q
18751564
18761565{-
18771566Note [Matching functions with GADT type variables]
@@ -1911,69 +1600,22 @@ Both.
19111600-- are the function arguments of types (b -> Value) and ([b] -> Value).
19121601type TyVarMap = Map Name (Name, Name)
19131602
1914−-- | If a VarT is missing an explicit kind signature, steal it from a TyVarBndr.
1915−stealKindForType :: TyVarBndr -> Type -> Type
1916−stealKindForType tvb t@VarT{} = SigT t (tvbKind tvb)
1917−stealKindForType _ t = t
1918−
1919−-- | Extracts the kind from a type variable binder.
1920−tvbKind :: TyVarBndr -> Kind
1921−#if MIN_VERSION_template_haskell(2,8,0)
1922−tvbKind (PlainTV _ ) = StarT
1923−#else
1924−tvbKind (PlainTV _ ) = StarK
1925−#endif
1926−tvbKind (KindedTV _ k) = k
1927−
1928−tvbToType :: TyVarBndr -> Type
1929−tvbToType (PlainTV n) = VarT n
1930−tvbToType (KindedTV n k) = SigT (VarT n) k
1931−
19321603-- | Returns True if a Type has kind *.
19331604hasKindStar :: Type -> Bool
19341605hasKindStar VarT{} = True
1935−#if MIN_VERSION_template_haskell(2,8,0)
19361606hasKindStar (SigT _ StarT) = True
1937−#else
1938−hasKindStar (SigT _ StarK) = True
1939−#endif
19401607hasKindStar _ = False
19411608
19421609-- Returns True is a kind is equal to *, or if it is a kind variable.
19431610isStarOrVar :: Kind -> Bool
1944−#if MIN_VERSION_template_haskell(2,8,0)
19451611isStarOrVar StarT = True
19461612isStarOrVar VarT{} = True
1947−#else
1948−isStarOrVar StarK = True
1949−#endif
19501613isStarOrVar _ = False
19511614
19521615-- Generate a list of fresh names with a common prefix, and numbered suffixes.
19531616newNameList :: String -> Int -> Q [Name]
19541617newNameList prefix len = mapM newName [prefix ++ show n | n <- [1..len]]
19551618
1956−-- Gets all of the type/kind variable names mentioned somewhere in a Type.
1957−tyVarNamesOfType :: Type -> [Name]
1958−tyVarNamesOfType = go
1959− where
1960− go :: Type -> [Name]
1961− go (AppT t1 t2) = go t1 ++ go t2
1962− go (SigT t _k) = go t
1963−#if MIN_VERSION_template_haskell(2,8,0)
1964− ++ go _k
1965−#endif
1966− go (VarT n) = [n]
1967− go _ = []
1968−
1969−-- | Gets all of the type/kind variable names mentioned somewhere in a Kind.
1970−tyVarNamesOfKind :: Kind -> [Name]
1971−#if MIN_VERSION_template_haskell(2,8,0)
1972−tyVarNamesOfKind = tyVarNamesOfType
1973−#else
1974−tyVarNamesOfKind _ = [] -- There are no kind variables
1975−#endif
1976−
19771619-- | @hasKindVarChain n kind@ Checks if @kind@ is of the form
19781620-- k_0 -> k_1 -> ... -> k_(n-1), where k0, k1, ..., and k_(n-1) can be * or
19791621-- kind variables.
@@ -1981,7 +1623,7 @@ hasKindVarChain :: Int -> Type -> Maybe [Name]
19811623hasKindVarChain kindArrows t =
19821624 let uk = uncurryKind (tyKind t)
19831625 in if (NE.length uk - 1 == kindArrows) && F.all isStarOrVar uk
1984− then Just (concatMap tyVarNamesOfKind uk)
1626+ then Just (concatMap freeVariables uk)
19851627 else Nothing
19861628
19871629-- | If a Type is a SigT, returns its kind signature. Otherwise, return *.
@@ -1991,26 +1633,15 @@ tyKind _ = starK
19911633
19921634-- | Extract Just the Name from a type variable. If the argument Type is not a
19931635-- type variable, return Nothing.
1994−varTToName_maybe :: Type -> Maybe Name
1995−varTToName_maybe (VarT n) = Just n
1996−varTToName_maybe (SigT t _) = varTToName_maybe t
1997−varTToName_maybe _ = Nothing
1636+varTToNameMaybe :: Type -> Maybe Name
1637+varTToNameMaybe (VarT n) = Just n
1638+varTToNameMaybe (SigT t _) = varTToNameMaybe t
1639+varTToNameMaybe _ = Nothing
19981640
19991641-- | Extract the Name from a type variable. If the argument Type is not a
20001642-- type variable, throw an error.
20011643varTToName :: Type -> Name
2002−varTToName = fromMaybe (error "Not a type variable!") . varTToName_maybe
2003−
2004−-- | Extracts the name from a constructor.
2005−getConName :: Con -> Name
2006−getConName (NormalC name _) = name
2007−getConName (RecC name _) = name
2008−getConName (InfixC _ name _) = name
2009−getConName (ForallC _ _ con) = getConName con
2010−#if MIN_VERSION_template_haskell(2,11,0)
2011−getConName (GadtC names _ _) = head names
2012−getConName (RecGadtC names _ _) = head names
2013−#endif
1644+varTToName = fromMaybe (error "Not a type variable!") . varTToNameMaybe
20141645
20151646interleave :: [a] -> [a] -> [a]
20161647interleave (a1:a1s) (a2:a2s) = a1:a2:interleave a1s a2s
@@ -2036,9 +1667,7 @@ isTyFamily (ConT n) = do
20361667#else
20371668 FamilyI (FamilyD TypeFam _ _ _) _ -> True
20381669#endif
2039−#if MIN_VERSION_template_haskell(2,9,0)
20401670 FamilyI ClosedTypeFamilyD{} _ -> True
2041−#endif
20421671 _ -> False
20431672isTyFamily _ = return False
20441673
@@ -2066,9 +1695,7 @@ mentionsName = go
20661695 go :: Type -> [Name] -> Bool
20671696 go (AppT t1 t2) names = go t1 names || go t2 names
20681697 go (SigT t _k) names = go t names
2069−#if MIN_VERSION_template_haskell(2,8,0)
20701698 || go _k names
2071−#endif
20721699 go (VarT n) names = n `elem` names
20731700 go _ _ = False
20741701
@@ -2124,37 +1751,28 @@ uncurryTy t = ([], t :| [])
21241751
21251752-- | Like uncurryType, except on a kind level.
21261753uncurryKind :: Kind -> NonEmpty Kind
2127−#if MIN_VERSION_template_haskell(2,8,0)
21281754uncurryKind = snd . uncurryTy
2129−#else
2130−uncurryKind (ArrowK k1 k2) = k1 <| uncurryKind k2
2131−uncurryKind k = k :| []
2132−#endif
21331755
21341756createKindChain :: Int -> Kind
21351757createKindChain = go starK
21361758 where
21371759 go :: Kind -> Int -> Kind
2138− go k !0 = k
2139−#if MIN_VERSION_template_haskell(2,8,0)
1760+ go k 0 = k
21401761 go k !n = go (AppT (AppT ArrowT StarT) k) (n - 1)
2141−#else
2142− go k !n = go (ArrowK StarK k) (n - 1)
2143−#endif
21441762
21451763-- | Makes a string literal expression from a constructor's name.
2146−conNameExp :: Options -> Con -> Q Exp
1764+conNameExp :: Options -> ConstructorInfo -> Q Exp
21471765conNameExp opts = litE
21481766 . stringL
21491767 . constructorTagModifier opts
21501768 . nameBase
2151− . getConName
1769+ . constructorName
21521770
2153−-- | Creates a string literal expression from a record field label.
2154−fieldLabelExp :: Options -- ^ Encoding options
2155− -> Name
2156− -> Q Exp
2157−fieldLabelExp opts = litE . stringL . fieldLabelModifier opts . nameBase
1771+-- | Extracts a record field label.
1772+fieldLabel :: Options -- ^ Encoding options
1773+ -> Name
1774+ -> String
1775+fieldLabel opts = fieldLabelModifier opts . nameBase
21581776
21591777-- | The name of the outermost 'Value' constructor.
21601778valueConName :: Value -> String
@@ -2193,76 +1811,14 @@ canEtaReduce remaining dropped =
21931811-- Expanding type synonyms
21941812-------------------------------------------------------------------------------
21951813
2196−-- | Expands all type synonyms in a type. Written by Dan Rosén in the
2197−-- @genifunctors@ package (licensed under BSD3).
2198−expandSyn :: Type -> Q Type
2199−expandSyn (ForallT tvs ctx t) = fmap (ForallT tvs ctx) $ expandSyn t
2200−expandSyn t@AppT{} = expandSynApp t []
2201−expandSyn t@ConT{} = expandSynApp t []
2202−expandSyn (SigT t k) = do t' <- expandSyn t
2203− k' <- expandSynKind k
2204− return (SigT t' k')
2205−expandSyn t = return t
2206−
2207−expandSynKind :: Kind -> Q Kind
2208−#if MIN_VERSION_template_haskell(2,8,0)
2209−expandSynKind = expandSyn
2210−#else
2211−expandSynKind = return -- There are no kind synonyms to deal with
2212−#endif
2213−
2214−expandSynApp :: Type -> [Type] -> Q Type
2215−expandSynApp (AppT t1 t2) ts = do
2216− t2' <- expandSyn t2
2217− expandSynApp t1 (t2':ts)
2218−expandSynApp (ConT n) ts | nameBase n == "[]" = return $ foldl' AppT ListT ts
2219−expandSynApp t@(ConT n) ts = do
2220− info <- reify n
2221− case info of
2222− TyConI (TySynD _ tvs rhs) ->
2223− let (ts', ts'') = splitAt (length tvs) ts
2224− subs = mkSubst tvs ts'
2225− rhs' = substType subs rhs
2226− in expandSynApp rhs' ts''
2227− _ -> return $ foldl' AppT t ts
2228−expandSynApp t ts = do
2229− t' <- expandSyn t
2230− return $ foldl' AppT t' ts
2231−
2232−type TypeSubst = Map Name Type
2233−type KindSubst = Map Name Kind
2234−
2235−mkSubst :: [TyVarBndr] -> [Type] -> TypeSubst
2236−mkSubst vs ts =
2237− let vs' = map un vs
2238− un (PlainTV v) = v
2239− un (KindedTV v _) = v
2240− in M.fromList $ zip vs' ts
2241−
2242−substType :: TypeSubst -> Type -> Type
2243−substType subs (ForallT v c t) = ForallT v c $ substType subs t
2244−substType subs t@(VarT n) = M.findWithDefault t n subs
2245−substType subs (AppT t1 t2) = AppT (substType subs t1) (substType subs t2)
2246−substType subs (SigT t k) = SigT (substType subs t)
2247−#if MIN_VERSION_template_haskell(2,8,0)
2248− (substType subs k)
2249−#else
2250− k
2251−#endif
2252−substType _ t = t
2253−
2254−substKind :: KindSubst -> Type -> Type
2255−#if MIN_VERSION_template_haskell(2,8,0)
2256−substKind = substType
2257−#else
2258−substKind _ t = t -- There are no kind variables!
2259−#endif
1814+applySubstitutionKind :: Map Name Kind -> Type -> Type
1815+applySubstitutionKind = applySubstitution
22601816
22611817substNameWithKind :: Name -> Kind -> Type -> Type
2262−substNameWithKind n k = substKind (M.singleton n k)
1818+substNameWithKind n k = applySubstitutionKind (M.singleton n k)
22631819
22641820substNamesWithKindStar :: [Name] -> Type -> Type
2265−substNamesWithKindStar ns t = foldr' (flip substNameWithKind starK) t ns
1821+substNamesWithKindStar ns t = foldr' (`substNameWithKind` starK) t ns
22661822
22671823-------------------------------------------------------------------------------
22681824-- Error messages
@@ -2345,6 +1901,13 @@ data Direction = To | From
23451901-- | A representation of which typeclass method is being spliced in.
23461902data JSONFun = ToJSON | ToEncoding | ParseJSON
23471903
1904+-- | A refinement of JSONFun to [ToJSON, ToEncoding].
1905+data ToJSONFun = Value | Encoding
1906+
1907+targetToJSONFun :: ToJSONFun -> JSONFun
1908+targetToJSONFun Value = ToJSON
1909+targetToJSONFun Encoding = ToEncoding
1910+
23481911-- | A representation of which typeclass is being derived.
23491912data JSONClass = JSONClass { direction :: Direction, arity :: Arity }
23501913
@@ -2411,13 +1974,10 @@ data StarKindStatus = NotKindStar
24111974
24121975-- | Does a Type have kind * or k (for some kind variable k)?
24131976canRealizeKindStar :: Type -> StarKindStatus
2414−canRealizeKindStar t
2415− | hasKindStar t = KindStar
2416− | otherwise = case t of
2417−#if MIN_VERSION_template_haskell(2,8,0)
2418− SigT _ (VarT k) -> IsKindVar k
2419−#endif
2420− _ -> NotKindStar
1977+canRealizeKindStar t = case t of
1978+ _ | hasKindStar t -> KindStar
1979+ SigT _ (VarT k) -> IsKindVar k
1980+ _ -> NotKindStar
24211981
24221982-- | Returns 'Just' the kind variable 'Name' of a 'StarKindStatus' if it exists.
24231983-- Otherwise, returns 'Nothing'.
Data/Aeson/Text.hs+12−7
@@ -1,4 +1,6 @@
1−{-# LANGUAGE BangPatterns, OverloadedStrings #-}
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE OverloadedStrings #-}
24-- |
35-- Module: Data.Aeson.Text
46-- Copyright: (c) 2012-2016 Bryan O'Sullivan
@@ -13,18 +15,21 @@
1315--
1416-- You can use the conversions to 'Builder's when embedding JSON messages as
1517-- parts of a protocol.
18+
1619module Data.Aeson.Text
17− ( encodeToLazyText
20+ (
21+ encodeToLazyText
1822 , encodeToTextBuilder
1923 ) where
2024
25+import Prelude.Compat
26+
2127import Data.Aeson.Types (Value(..), ToJSON(..))
2228import Data.Aeson.Encoding (encodingToLazyByteString)
23−import Data.Monoid ((<>))
29+import Data.Semigroup ((<>))
2430import Data.Scientific (FPFormat(..), Scientific, base10Exponent)
2531import Data.Text.Lazy.Builder
2632import Data.Text.Lazy.Builder.Scientific (formatScientificBuilder)
27−
2833import Numeric (showHex)
2934import qualified Data.HashMap.Strict as H
3035import qualified Data.Text as T
@@ -36,14 +41,14 @@ import qualified Data.Vector as V
3641--
3742-- /Note:/ uses 'toEncoding'
3843encodeToLazyText :: ToJSON a => a -> LT.Text
39−encodeToLazyText = LT.decodeUtf8 . encodingToLazyByteString . toEncoding
44+encodeToLazyText = LT.decodeUtf8 . encodingToLazyByteString . toEncoding
4045
4146-- | Encode a JSON 'Value' to a "Data.Text" 'Builder', which can be
4247-- embedded efficiently in a text-based protocol.
4348--
4449-- If you are going to immediately encode straight to a
45−-- 'L.ByteString', it is more efficient to use 'encodeToBuilder'
46−-- instead.
50+-- 'L.ByteString', it is more efficient to use 'encode' (lazy ByteString)
51+-- or @'fromEncoding' . 'toEncoding'@ (ByteString.Builder) instead.
4752--
4853-- /Note:/ Uses 'toJSON'
4954encodeToTextBuilder :: ToJSON a => a -> Builder
Data/Aeson/Types.hs+55−7
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12-- |
23-- Module: Data.Aeson.Types
34-- Copyright: (c) 2011-2016 Bryan O'Sullivan
@@ -25,6 +26,7 @@ module Data.Aeson.Types
2526 -- * Convenience types and functions
2627 , DotNetTime(..)
2728 , typeMismatch
29+ , unexpected
2830 -- * Type conversion
2931 , Parser
3032 , Result(..)
@@ -36,14 +38,26 @@ module Data.Aeson.Types
3638 , ToJSON(..)
3739 , KeyValue(..)
3840 , modifyFailure
41+ , prependFailure
42+ , parserThrowError
43+ , parserCatchError
3944
4045 -- ** Keys for maps
4146 , ToJSONKey(..)
4247 , ToJSONKeyFunction(..)
48+ , toJSONKeyText
49+ , contramapToJSONKeyFunction
4350 , FromJSONKey(..)
4451 , FromJSONKeyFunction(..)
4552 , fromJSONKeyCoerce
4653 , coerceFromJSONKeyFunction
54+ , mapFromJSONKeyFunction
55+
56+ -- *** Generic keys
57+ , GToJSONKey()
58+ , genericToJSONKey
59+ , GFromJSONKey()
60+ , genericFromJSONKey
4761
4862 -- ** Liftings to unary and binary type constructors
4963 , FromJSON1(..)
@@ -59,8 +73,10 @@ module Data.Aeson.Types
5973
6074 -- ** Generic JSON classes
6175 , GFromJSON(..)
62− , GToJSON(..)
63− , GToEncoding(..)
76+ , FromArgs(..)
77+ , GToJSON
78+ , GToEncoding
79+ , ToArgs(..)
6480 , Zero
6581 , One
6682 , genericToJSON
@@ -74,9 +90,9 @@ module Data.Aeson.Types
7490 , withObject
7591 , withText
7692 , withArray
77− , withNumber
7893 , withScientific
7994 , withBool
95+ , withEmbeddedJSON
8096
8197 , pairs
8298 , foldable
@@ -85,30 +101,62 @@ module Data.Aeson.Types
85101 , (.:!)
86102 , (.!=)
87103 , object
104+ , parseField
105+ , parseFieldMaybe
106+ , parseFieldMaybe'
107+ , explicitParseField
108+ , explicitParseFieldMaybe
109+ , explicitParseFieldMaybe'
88110
89111 , listEncoding
90112 , listValue
91113 , listParser
92114
93115 -- * Generic and TH encoding configuration
94− , Options(..)
116+ , Options
117+
118+ -- ** Options fields
119+ -- $optionsFields
120+ , fieldLabelModifier
121+ , constructorTagModifier
122+ , allNullaryToStringTag
123+ , omitNothingFields
124+ , sumEncoding
125+ , unwrapUnaryRecords
126+ , tagSingleConstructors
127+ , rejectUnknownFields
128+
129+ -- ** Options utilities
95130 , SumEncoding(..)
96131 , camelTo
97132 , camelTo2
98133 , defaultOptions
99134 , defaultTaggedObject
135+
136+ -- ** Options for object keys
137+ , JSONKeyOptions
138+ , keyModifier
139+ , defaultJSONKeyOptions
140+
141+ -- * Parsing context
142+ , (<?>)
143+ , JSONPath
144+ , JSONPathElement(..)
145+ , formatPath
146+ , formatRelativePath
100147 ) where
101148
102−import Prelude ()
103149import Prelude.Compat
104150
151+import Data.Aeson.Encoding (Encoding, unsafeToEncoding, fromEncoding, Series, pairs)
105152import Data.Aeson.Types.Class
106153import Data.Aeson.Types.Internal
107−import Data.Aeson.Encoding (Encoding, unsafeToEncoding, fromEncoding, Series, pairs)
108−
109154import Data.Foldable (toList)
110155
111156-- | Encode a 'Foldable' as a JSON array.
112157foldable :: (Foldable t, ToJSON a) => t a -> Encoding
113158foldable = toEncoding . toList
114159{-# INLINE foldable #-}
160+
161+-- $optionsFields
162+-- The functions here are in fact record fields of the 'Options' type.
Data/Aeson/Types/Class.hs+30−9
@@ -1,13 +1,11 @@
11{-# LANGUAGE CPP #-}
2−{-# LANGUAGE DefaultSignatures #-}
3−{-# LANGUAGE DeriveFunctor #-}
4−{-# LANGUAGE EmptyDataDecls #-}
2+{-# LANGUAGE ConstraintKinds #-}
53{-# LANGUAGE FlexibleContexts #-}
64{-# LANGUAGE FlexibleInstances #-}
75{-# LANGUAGE GADTs #-}
86{-# LANGUAGE MultiParamTypeClasses #-}
7+{-# LANGUAGE NoImplicitPrelude #-}
98{-# LANGUAGE ScopedTypeVariables #-}
10−{-# LANGUAGE TypeSynonymInstances #-}
119
1210-- |
1311-- Module: Data.Aeson.Types.Class
@@ -38,8 +36,10 @@ module Data.Aeson.Types.Class
3836 , toEncoding2
3937 -- * Generic JSON classes
4038 , GFromJSON(..)
41− , GToJSON(..)
42− , GToEncoding(..)
39+ , FromArgs(..)
40+ , GToJSON
41+ , GToEncoding
42+ , ToArgs(..)
4343 , Zero
4444 , One
4545 , genericToJSON
@@ -51,12 +51,18 @@ module Data.Aeson.Types.Class
5151 -- * Classes and types for map keys
5252 , ToJSONKey(..)
5353 , ToJSONKeyFunction(..)
54+ , toJSONKeyText
5455 , contramapToJSONKeyFunction
5556 , FromJSONKey(..)
5657 , FromJSONKeyFunction(..)
5758 , fromJSONKeyCoerce
5859 , coerceFromJSONKeyFunction
5960 , mapFromJSONKeyFunction
61+ -- ** Generic keys
62+ , GToJSONKey()
63+ , genericToJSONKey
64+ , GFromJSONKey()
65+ , genericFromJSONKey
6066 -- * Object key-value pairs
6167 , KeyValue(..)
6268
@@ -69,20 +75,35 @@ module Data.Aeson.Types.Class
6975 , withObject
7076 , withText
7177 , withArray
72− , withNumber
7378 , withScientific
7479 , withBool
80+ , withEmbeddedJSON
7581
7682 -- * Functions
7783 , fromJSON
7884 , ifromJSON
85+ , typeMismatch
86+ , unexpected
87+ , parseField
88+ , parseFieldMaybe
89+ , parseFieldMaybe'
90+ , explicitParseField
91+ , explicitParseFieldMaybe
92+ , explicitParseFieldMaybe'
93+ -- ** Operators
7994 , (.:)
8095 , (.:?)
8196 , (.:!)
8297 , (.!=)
83− , typeMismatch
8498 ) where
8599
100+
86101import Data.Aeson.Types.FromJSON
87−import Data.Aeson.Types.ToJSON
88102import Data.Aeson.Types.Generic (One, Zero)
103+import Data.Aeson.Types.ToJSON hiding (GToJSON)
104+import qualified Data.Aeson.Types.ToJSON as ToJSON
105+import Data.Aeson.Types.Internal (Value)
106+import Data.Aeson.Encoding (Encoding)
107+
108+type GToJSON = ToJSON.GToJSON Value
109+type GToEncoding = ToJSON.GToJSON Encoding
Data/Aeson/Types/FromJSON.hs+1346−555
@@ -1,29 +1,28 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE DataKinds #-}
3−{-# LANGUAGE DefaultSignatures #-}
4−{-# LANGUAGE FlexibleContexts #-}
5−{-# LANGUAGE FlexibleInstances #-}
6−{-# LANGUAGE GADTs #-}
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE DefaultSignatures #-}
4+{-# LANGUAGE FlexibleContexts #-}
5+{-# LANGUAGE FlexibleInstances #-}
6+{-# LANGUAGE GADTs #-}
77{-# LANGUAGE MultiParamTypeClasses #-}
8−{-# LANGUAGE NamedFieldPuns #-}
9−{-# LANGUAGE OverloadedStrings #-}
10−{-# LANGUAGE RecordWildCards #-}
11−{-# LANGUAGE ScopedTypeVariables #-}
12−{-# LANGUAGE TypeOperators #-}
13−{-# LANGUAGE TypeSynonymInstances #-}
14−{-# LANGUAGE UndecidableInstances #-}
15−{-# LANGUAGE ViewPatterns #-}
16−
17−#if __GLASGOW_HASKELL__ >= 706
18−{-# LANGUAGE PolyKinds #-}
19−#endif
20−
8+{-# LANGUAGE NoImplicitPrelude #-}
9+{-# LANGUAGE OverloadedStrings #-}
10+{-# LANGUAGE PolyKinds #-}
11+{-# LANGUAGE RecordWildCards #-}
12+{-# LANGUAGE ScopedTypeVariables #-}
13+{-# LANGUAGE TypeOperators #-}
14+{-# LANGUAGE TupleSections #-}
15+{-# LANGUAGE UndecidableInstances #-}
16+{-# LANGUAGE ViewPatterns #-}
17+
18+#include "incoherent-compat.h"
2119#include "overlapping-compat.h"
2220
2321-- TODO: Drop this when we remove support for Data.Attoparsec.Number
2422{-# OPTIONS_GHC -fno-warn-deprecations #-}
2523
26−module Data.Aeson.Types.FromJSON (
24+module Data.Aeson.Types.FromJSON
25+ (
2726 -- * Core JSON classes
2827 FromJSON(..)
2928 -- * Liftings to unary and binary type constructors
@@ -33,6 +32,7 @@ module Data.Aeson.Types.FromJSON (
3332 , parseJSON2
3433 -- * Generic JSON classes
3534 , GFromJSON(..)
35+ , FromArgs(..)
3636 , genericParseJSON
3737 , genericLiftParseJSON
3838 -- * Classes and types for map keys
@@ -42,104 +42,121 @@ module Data.Aeson.Types.FromJSON (
4242 , coerceFromJSONKeyFunction
4343 , mapFromJSONKeyFunction
4444
45+ , GFromJSONKey()
46+ , genericFromJSONKey
47+
4548 -- * List functions
4649 , listParser
4750
48− -- * Inspecting @'Value's@
51+ -- * Inspecting @'Value's@
4952 , withObject
5053 , withText
5154 , withArray
52− , withNumber
5355 , withScientific
5456 , withBool
57+ , withEmbeddedJSON
5558
5659 -- * Functions
5760 , fromJSON
5861 , ifromJSON
62+ , typeMismatch
63+ , unexpected
64+ , parseField
65+ , parseFieldMaybe
66+ , parseFieldMaybe'
67+ , explicitParseField
68+ , explicitParseFieldMaybe
69+ , explicitParseFieldMaybe'
70+ , parseIndexedJSON
71+ -- ** Operators
5972 , (.:)
6073 , (.:?)
6174 , (.:!)
6275 , (.!=)
63− , typeMismatch
6476
6577 -- * Internal
6678 , parseOptionalFieldWith
6779 ) where
6880
69−import Prelude ()
70−import Prelude.Compat hiding (foldr)
81+import Prelude.Compat
7182
83+import Control.Applicative ((<|>), Const(..), liftA2)
84+import Control.Monad (zipWithM)
7285import Data.Aeson.Internal.Functions (mapKey)
86+import Data.Aeson.Parser.Internal (eitherDecodeWith, jsonEOF)
7387import Data.Aeson.Types.Generic
7488import Data.Aeson.Types.Internal
75−
76−import qualified Data.Aeson.Parser.Time as Time
77−import qualified Data.Attoparsec.ByteString.Char8 as A (endOfInput, parseOnly,
78− scientific)
79−
80−import Control.Applicative (Const (..), (<|>))
81−import Control.Monad ((<=<))
82−import Data.Attoparsec.Number (Number (..))
83−import Data.Bits (unsafeShiftR)
84−import Data.Fixed (Fixed, HasResolution)
85−import Data.Functor.Identity (Identity (..))
86−import Data.Hashable (Hashable (..))
87−import Data.Int (Int16, Int32, Int64, Int8)
88−import Data.List.NonEmpty (NonEmpty (..))
89−import Data.Maybe (fromMaybe)
90−import Data.Monoid (Dual (..), First (..), Last (..), (<>))
91−import Data.Proxy (Proxy (..))
92−import Data.Ratio (Ratio, (%))
93−import Data.Scientific (Scientific)
94−import Data.Tagged (Tagged (..))
95−import Data.Text (Text, pack, unpack)
96−import Data.Time (Day, LocalTime, NominalDiffTime, TimeOfDay,
97− UTCTime, ZonedTime)
98−import Data.Time.Format (parseTime)
99−import Data.Time.Locale.Compat (defaultTimeLocale)
100−import Data.Traversable as Tr (sequence)
101−import Data.Vector (Vector)
102−import Data.Version (Version, parseVersion)
103−import Data.Word (Word16, Word32, Word64, Word8)
104−import Foreign.Storable (Storable)
89+import Data.Bits (unsafeShiftR)
90+import Data.Fixed (Fixed, HasResolution (resolution), Nano)
91+import Data.Functor.Compose (Compose(..))
92+import Data.Functor.Identity (Identity(..))
93+import Data.Functor.Product (Product(..))
94+import Data.Functor.Sum (Sum(..))
95+import Data.Hashable (Hashable(..))
96+import Data.Int (Int16, Int32, Int64, Int8)
97+import Data.List.NonEmpty (NonEmpty(..))
98+import Data.Maybe (fromMaybe)
99+import Data.Semigroup ((<>))
100+import Data.Proxy (Proxy(..))
101+import Data.Ratio ((%), Ratio)
102+import Data.Scientific (Scientific, base10Exponent)
103+import Data.Tagged (Tagged(..))
104+import Data.Text (Text, pack, unpack)
105+import Data.Time (Day, DiffTime, LocalTime, NominalDiffTime, TimeOfDay, UTCTime, ZonedTime)
106+import Data.Time.Calendar.Compat (CalendarDiffDays (..), DayOfWeek (..))
107+import Data.Time.LocalTime.Compat (CalendarDiffTime (..))
108+import Data.Time.Clock.System.Compat (SystemTime (..))
109+import Data.Time.Format.Compat (parseTimeM, defaultTimeLocale)
110+import Data.Traversable as Tr (sequence)
111+import Data.Vector (Vector)
112+import Data.Version (Version, parseVersion)
113+import Data.Void (Void)
114+import Data.Word (Word16, Word32, Word64, Word8)
115+import Foreign.Storable (Storable)
116+import Foreign.C.Types (CTime (..))
105117import GHC.Generics
106−import Numeric.Natural (Natural)
118+import Numeric.Natural (Natural)
107119import Text.ParserCombinators.ReadP (readP_to_S)
108−
109−import qualified Data.DList as DList
110−import qualified Data.HashMap.Strict as H
111−import qualified Data.HashSet as HashSet
112−import qualified Data.IntMap as IntMap
113−import qualified Data.IntSet as IntSet
114−import qualified Data.Map as M
115−import qualified Data.Scientific as Scientific
116−import qualified Data.Sequence as Seq
117−import qualified Data.Set as Set
118−import qualified Data.Text as T
119−import qualified Data.Text.Encoding as T
120−import qualified Data.Text.Lazy as LT
121−import qualified Data.Tree as Tree
122−import qualified Data.Vector as V
123−import qualified Data.Vector.Generic as VG
120+import Unsafe.Coerce (unsafeCoerce)
121+import qualified Data.Aeson.Parser.Time as Time
122+import qualified Data.Attoparsec.ByteString.Char8 as A (endOfInput, parseOnly, scientific)
123+import qualified Data.ByteString.Lazy as L
124+import qualified Data.DList as DList
125+import qualified Data.HashMap.Strict as H
126+import qualified Data.HashSet as HashSet
127+import qualified Data.IntMap as IntMap
128+import qualified Data.IntSet as IntSet
129+import qualified Data.Map as M
130+import qualified Data.Monoid as Monoid
131+import qualified Data.Scientific as Scientific
132+import qualified Data.Semigroup as Semigroup
133+import qualified Data.Sequence as Seq
134+import qualified Data.Set as Set
135+import qualified Data.Text as T
136+import qualified Data.Text.Encoding as T
137+import qualified Data.Text.Lazy as LT
138+import qualified Data.Tree as Tree
139+import qualified Data.UUID.Types as UUID
140+import qualified Data.Vector as V
141+import qualified Data.Vector.Generic as VG
124142import qualified Data.Vector.Primitive as VP
125−import qualified Data.Vector.Storable as VS
126−import qualified Data.Vector.Unboxed as VU
143+import qualified Data.Vector.Storable as VS
144+import qualified Data.Vector.Unboxed as VU
127145
128−import Unsafe.Coerce (unsafeCoerce)
146+import qualified GHC.Exts as Exts
147+import qualified Data.Primitive.Array as PM
148+import qualified Data.Primitive.SmallArray as PM
149+import qualified Data.Primitive.Types as PM
129150
130−-- Coercible derivations aren't as powerful on GHC 7.8, though supported.
131−#ifndef HAS_COERCIBLE
132−#define HAS_COERCIBLE (__GLASGOW_HASKELL__ >= 709)
151+#if MIN_VERSION_primitive(0,6,4)
152+#if !MIN_VERSION_primitive(0,7,0)
153+import qualified Data.Primitive.UnliftedArray as PM
154+#endif
155+import qualified Data.Primitive.PrimArray as PM
133156#endif
134157
135−#if HAS_COERCIBLE
158+
136159import Data.Coerce (Coercible, coerce)
137−coerce' :: Coercible a b => a -> b
138−coerce' = coerce
139−#else
140−coerce' :: a -> b
141−coerce' = unsafeCoerce
142−#endif
143160
144161parseIndexedJSON :: (Value -> Parser a) -> Int -> Value -> Parser a
145162parseIndexedJSON p idx value = p value <?> Index idx
@@ -148,7 +165,7 @@ parseIndexedJSON p idx value = p value <?> Index idx
148165parseIndexedJSONPair :: (Value -> Parser a) -> (Value -> Parser b) -> Int -> Value -> Parser (a, b)
149166parseIndexedJSONPair keyParser valParser idx value = p value <?> Index idx
150167 where
151− p = withArray "(k,v)" $ \ab ->
168+ p = withArray "(k, v)" $ \ab ->
152169 let n = V.length ab
153170 in if n == 2
154171 then (,) <$> parseJSONElemAtIndex keyParser 0 ab
@@ -160,33 +177,57 @@ parseIndexedJSONPair keyParser valParser idx value = p value <?> Index idx
160177parseJSONElemAtIndex :: (Value -> Parser a) -> Int -> V.Vector Value -> Parser a
161178parseJSONElemAtIndex p idx ary = p (V.unsafeIndex ary idx) <?> Index idx
162179
163−scientificToNumber :: Scientific -> Number
164−scientificToNumber s
165− | e < 0 = D $ Scientific.toRealFloat s
166− | otherwise = I $ c * 10 ^ e
167− where
168− e = Scientific.base10Exponent s
169− c = Scientific.coefficient s
170−{-# INLINE scientificToNumber #-}
171−
172180parseRealFloat :: RealFloat a => String -> Value -> Parser a
173−parseRealFloat _ (Number s) = pure $ Scientific.toRealFloat s
174−parseRealFloat _ Null = pure (0/0)
175−parseRealFloat expected v = typeMismatch expected v
181+parseRealFloat _ (Number s) = pure $ Scientific.toRealFloat s
182+parseRealFloat _ Null = pure (0/0)
183+parseRealFloat name v = prependContext name (unexpected v)
176184{-# INLINE parseRealFloat #-}
177185
186+parseIntegralFromScientific :: forall a. Integral a => Scientific -> Parser a
187+parseIntegralFromScientific s =
188+ case Scientific.floatingOrInteger s :: Either Double a of
189+ Right x -> pure x
190+ Left _ -> fail $ "unexpected floating number " ++ show s
191+{-# INLINE parseIntegralFromScientific #-}
192+
178193parseIntegral :: Integral a => String -> Value -> Parser a
179−parseIntegral expected = withScientific expected $ pure . truncate
194+parseIntegral name =
195+ prependContext name . withBoundedScientific' parseIntegralFromScientific
180196{-# INLINE parseIntegral #-}
181197
198+parseBoundedIntegralFromScientific :: (Bounded a, Integral a) => Scientific -> Parser a
199+parseBoundedIntegralFromScientific s = maybe
200+ (fail $ "value is either floating or will cause over or underflow " ++ show s)
201+ pure
202+ (Scientific.toBoundedInteger s)
203+{-# INLINE parseBoundedIntegralFromScientific #-}
204+
205+parseBoundedIntegral :: (Bounded a, Integral a) => String -> Value -> Parser a
206+parseBoundedIntegral name =
207+ prependContext name . withScientific' parseBoundedIntegralFromScientific
208+{-# INLINE parseBoundedIntegral #-}
209+
182210parseScientificText :: Text -> Parser Scientific
183211parseScientificText
184212 = either fail pure
185213 . A.parseOnly (A.scientific <* A.endOfInput)
186214 . T.encodeUtf8
187215
188−parseIntegralText :: Integral a => Text -> Parser a
189−parseIntegralText t = truncate <$> parseScientificText t
216+parseIntegralText :: Integral a => String -> Text -> Parser a
217+parseIntegralText name t =
218+ prependContext name $
219+ parseScientificText t
220+ >>= rejectLargeExponent
221+ >>= parseIntegralFromScientific
222+ where
223+ rejectLargeExponent :: Scientific -> Parser Scientific
224+ rejectLargeExponent s = withBoundedScientific' pure (Number s)
225+{-# INLINE parseIntegralText #-}
226+
227+parseBoundedIntegralText :: (Bounded a, Integral a) => String -> Text -> Parser a
228+parseBoundedIntegralText name t =
229+ prependContext name $
230+ parseScientificText t >>= parseBoundedIntegralFromScientific
190231
191232parseOptionalFieldWith :: (Value -> Parser (Maybe a))
192233 -> Object -> Text -> Parser (Maybe a)
@@ -205,16 +246,21 @@ class GFromJSON arity f where
205246 -- | This method (applied to 'defaultOptions') is used as the
206247 -- default generic implementation of 'parseJSON' (if the @arity@ is 'Zero')
207248 -- or 'liftParseJSON' (if the @arity@ is 'One').
208− gParseJSON :: Options -> Proxy arity
209− -> (Value -> Parser a) -> (Value -> Parser [a])
210− -> Value -> Parser (f a)
249+ gParseJSON :: Options -> FromArgs arity a -> Value -> Parser (f a)
250+
251+-- | A 'FromArgs' value either stores nothing (for 'FromJSON') or it stores the
252+-- two function arguments that decode occurrences of the type parameter (for
253+-- 'FromJSON1').
254+data FromArgs arity a where
255+ NoFromArgs :: FromArgs Zero a
256+ From1Args :: (Value -> Parser a) -> (Value -> Parser [a]) -> FromArgs One a
211257
212258-- | A configurable generic JSON decoder. This function applied to
213259-- 'defaultOptions' is used as the default for 'parseJSON' when the
214260-- type is an instance of 'Generic'.
215261genericParseJSON :: (Generic a, GFromJSON Zero (Rep a))
216262 => Options -> Value -> Parser a
217−genericParseJSON opts = fmap to . gParseJSON opts proxyZero undefined undefined
263+genericParseJSON opts = fmap to . gParseJSON opts NoFromArgs
218264
219265-- | A configurable generic JSON decoder. This function applied to
220266-- 'defaultOptions' is used as the default for 'liftParseJSON' when the
@@ -222,7 +268,7 @@ genericParseJSON opts = fmap to . gParseJSON opts proxyZero undefined undefined
222268genericLiftParseJSON :: (Generic1 f, GFromJSON One (Rep1 f))
223269 => Options -> (Value -> Parser a) -> (Value -> Parser [a])
224270 -> Value -> Parser (f a)
225−genericLiftParseJSON opts pj pjl = fmap to1 . gParseJSON opts proxyOne pj pjl
271+genericLiftParseJSON opts pj pjl = fmap to1 . gParseJSON opts (From1Args pj pjl)
226272
227273-------------------------------------------------------------------------------
228274-- Class
@@ -241,14 +287,21 @@ genericLiftParseJSON opts pj pjl = fmap to1 . gParseJSON opts proxyOne pj pjl
241287--
242288-- The basic ways to signal a failed conversion are as follows:
243289--
244−-- * 'empty' and 'mzero' work, but are terse and uninformative
290+-- * 'fail' yields a custom error message: it is the recommended way of
291+-- reporting a failure;
245292--
246−-- * 'fail' yields a custom error message
293+-- * 'Control.Applicative.empty' (or 'Control.Monad.mzero') is uninformative:
294+-- use it when the error is meant to be caught by some @('<|>')@;
247295--
248−-- * 'typeMismatch' produces an informative message for cases when the
249−-- value encountered is not of the expected type
296+-- * 'typeMismatch' can be used to report a failure when the encountered value
297+-- is not of the expected JSON type; 'unexpected' is an appropriate alternative
298+-- when more than one type may be expected, or to keep the expected type
299+-- implicit.
250300--
251−-- An example type and instance:
301+-- 'prependFailure' (or 'modifyFailure') add more information to a parser's
302+-- error messages.
303+--
304+-- An example type and instance using 'typeMismatch' and 'prependFailure':
252305--
253306-- @
254307-- \-- Allow ourselves to write 'Text' literals.
@@ -256,15 +309,30 @@ genericLiftParseJSON opts pj pjl = fmap to1 . gParseJSON opts proxyOne pj pjl
256309--
257310-- data Coord = Coord { x :: Double, y :: Double }
258311--
259−-- instance FromJSON Coord where
260−-- parseJSON ('Object' v) = Coord '<$>'
261−-- v '.:' \"x\" '<*>'
262−-- v '.:' \"y\"
312+-- instance 'FromJSON' Coord where
313+-- 'parseJSON' ('Object' v) = Coord
314+-- '<$>' v '.:' \"x\"
315+-- '<*>' v '.:' \"y\"
316+--
317+-- \-- We do not expect a non-'Object' value here.
318+-- \-- We could use 'Control.Applicative.empty' to fail, but 'typeMismatch'
319+-- \-- gives a much more informative error message.
320+-- 'parseJSON' invalid =
321+-- 'prependFailure' "parsing Coord failed, "
322+-- ('typeMismatch' \"Object\" invalid)
323+-- @
263324--
264−-- \-- We do not expect a non-'Object' value here.
265−-- \-- We could use 'mzero' to fail, but 'typeMismatch'
266−-- \-- gives a much more informative error message.
267−-- parseJSON invalid = 'typeMismatch' \"Coord\" invalid
325+-- For this common case of only being concerned with a single
326+-- type of JSON value, the functions 'withObject', 'withScientific', etc.
327+-- are provided. Their use is to be preferred when possible, since
328+-- they are more terse. Using 'withObject', we can rewrite the above instance
329+-- (assuming the same language extension and data type) as:
330+--
331+-- @
332+-- instance 'FromJSON' Coord where
333+-- 'parseJSON' = 'withObject' \"Coord\" $ \\v -> Coord
334+-- '<$>' v '.:' \"x\"
335+-- '<*>' v '.:' \"y\"
268336-- @
269337--
270338-- Instead of manually writing your 'FromJSON' instance, there are two options
@@ -272,7 +340,7 @@ genericLiftParseJSON opts pj pjl = fmap to1 . gParseJSON opts proxyOne pj pjl
272340--
273341-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
274342-- instance at compile time. The generated instance is optimized for your type
275−-- so will probably be more efficient than the following two options:
343+-- so it will probably be more efficient than the following option.
276344--
277345-- * The compiler can provide a default generic implementation for
278346-- 'parseJSON'.
@@ -290,18 +358,21 @@ genericLiftParseJSON opts pj pjl = fmap to1 . gParseJSON opts proxyOne pj pjl
290358--
291359-- data Coord = Coord { x :: Double, y :: Double } deriving 'Generic'
292360--
293−-- instance FromJSON Coord
361+-- instance 'FromJSON' Coord
294362-- @
295363--
296−-- If @DefaultSignatures@ doesn't give exactly the results you want,
297−-- you can customize the generic decoding with only a tiny amount of
298−-- effort, using 'genericParseJSON' with your preferred 'Options':
364+-- The default implementation will be equivalent to
365+-- @parseJSON = 'genericParseJSON' 'defaultOptions'@; if you need different
366+-- options, you can customize the generic decoding by defining:
299367--
300368-- @
301−-- instance FromJSON Coord where
302−-- parseJSON = 'genericParseJSON' 'defaultOptions'
369+-- customOptions = 'defaultOptions'
370+-- { 'fieldLabelModifier' = 'map' 'Data.Char.toUpper'
371+-- }
372+--
373+-- instance 'FromJSON' Coord where
374+-- 'parseJSON' = 'genericParseJSON' customOptions
303375-- @
304−
305376class FromJSON a where
306377 parseJSON :: Value -> Parser a
307378
@@ -309,111 +380,181 @@ class FromJSON a where
309380 parseJSON = genericParseJSON defaultOptions
310381
311382 parseJSONList :: Value -> Parser [a]
312− parseJSONList (Array a)
313− = sequence
314− . zipWith (parseIndexedJSON parseJSON) [0..]
383+ parseJSONList = withArray "[]" $ \a ->
384+ zipWithM (parseIndexedJSON parseJSON) [0..]
315385 . V.toList
316386 $ a
317387
318− parseJSONList v = typeMismatch "[a]" v
319−
320388-------------------------------------------------------------------------------
321389-- Classes and types for map keys
322390-------------------------------------------------------------------------------
323391
392+-- | Read the docs for 'ToJSONKey' first. This class is a conversion
393+-- in the opposite direction. If you have a newtype wrapper around 'Text',
394+-- the recommended way to define instances is with generalized newtype deriving:
395+--
396+-- > newtype SomeId = SomeId { getSomeId :: Text }
397+-- > deriving (Eq,Ord,Hashable,FromJSONKey)
398+--
399+-- If you have a sum of nullary constructors, you may use the generic
400+-- implementation:
401+--
402+-- @
403+-- data Color = Red | Green | Blue
404+-- deriving Generic
405+--
406+-- instance 'FromJSONKey' Color where
407+-- 'fromJSONKey' = 'genericFromJSONKey' 'defaultJSONKeyOptions'
408+-- @
324409class FromJSONKey a where
410+ -- | Strategy for parsing the key of a map-like container.
325411 fromJSONKey :: FromJSONKeyFunction a
326412 default fromJSONKey :: FromJSON a => FromJSONKeyFunction a
327413 fromJSONKey = FromJSONKeyValue parseJSON
414+
415+ -- | This is similar in spirit to the 'readList' method of 'Read'.
416+ -- It makes it possible to give 'String' keys special treatment
417+ -- without using @OverlappingInstances@. End users should always
418+ -- be able to use the default implementation of this method.
328419 fromJSONKeyList :: FromJSONKeyFunction [a]
329420 default fromJSONKeyList :: FromJSON a => FromJSONKeyFunction [a]
330421 fromJSONKeyList = FromJSONKeyValue parseJSON
331422
332−-- | With GHC 7.8 + we carry around 'Coercible Text a' dictionary,
333−-- to have even some amount of safety net.
334−-- Unfortunately we cannot enforce that 'Hashable' instance agree on the type level
423+-- | With GHC 7.8+ we carry around @'Coercible' 'Text' a@ dictionary,
424+-- to give us an assurance that the program will not segfault.
425+-- Unfortunately we cannot enforce that the 'Eq' instances or the
426+-- 'Hashable' instances for 'Text' and @a@ agree.
335427--
336−-- ATM this type is intentionally not exported. FromJSONKeyFunction can be inspected,
337−-- but cannot be constructed.
428+-- At the moment this type is intentionally not exported. 'FromJSONKeyFunction'
429+-- can be inspected, but cannot be constructed.
338430data CoerceText a where
339−#if HAS_COERCIBLE
340431 CoerceText :: Coercible Text a => CoerceText a
341−#else
342− CoerceText :: CoerceText a
343−#endif
344432
433+-- | This type is related to 'ToJSONKeyFunction'. If 'FromJSONKeyValue' is used in the
434+-- 'FromJSONKey' instance, then 'ToJSONKeyValue' should be used in the 'ToJSONKey'
435+-- instance. The other three data constructors for this type all correspond to
436+-- 'ToJSONKeyText'. Strictly speaking, 'FromJSONKeyTextParser' is more powerful than
437+-- 'FromJSONKeyText', which is in turn more powerful than 'FromJSONKeyCoerce'.
438+-- For performance reasons, these exist as three options instead of one.
345439data FromJSONKeyFunction a
346− = FromJSONKeyCoerce (CoerceText a)
347− | FromJSONKeyText (Text -> a)
348− | FromJSONKeyTextParser (Text -> Parser a)
349− | FromJSONKeyValue (Value -> Parser a)
350−
440+ = FromJSONKeyCoerce !(CoerceText a)
441+ -- ^ uses 'coerce' ('unsafeCoerce' in older GHCs)
442+ | FromJSONKeyText !(Text -> a)
443+ -- ^ conversion from 'Text' that always succeeds
444+ | FromJSONKeyTextParser !(Text -> Parser a)
445+ -- ^ conversion from 'Text' that may fail
446+ | FromJSONKeyValue !(Value -> Parser a)
447+ -- ^ conversion for non-textual keys
448+
449+-- | Only law abiding up to interpretation
351450instance Functor FromJSONKeyFunction where
352− fmap h (FromJSONKeyCoerce CoerceText) = FromJSONKeyText (h . coerce')
451+ fmap h (FromJSONKeyCoerce CoerceText) = FromJSONKeyText (h . coerce)
353452 fmap h (FromJSONKeyText f) = FromJSONKeyText (h . f)
354453 fmap h (FromJSONKeyTextParser f) = FromJSONKeyTextParser (fmap h . f)
355454 fmap h (FromJSONKeyValue f) = FromJSONKeyValue (fmap h . f)
356455
357456-- | Construct 'FromJSONKeyFunction' for types coercible from 'Text'. This
358457-- conversion is still unsafe, as 'Hashable' and 'Eq' instances of @a@ should be
458+-- compatible with 'Text' i.e. hash values should be equal for wrapped values as well.
459+-- This property will always be maintained if the 'Hashable' and 'Eq' instances
460+-- are derived with generalized newtype deriving.
359461-- compatible with 'Text' i.e. hash values be equal for wrapped values as well.
462+--
463+-- On pre GHC 7.8 this is unconstrainted function.
360464fromJSONKeyCoerce ::
361−#if HAS_COERCIBLE
362465 Coercible Text a =>
363−#endif
364466 FromJSONKeyFunction a
365467fromJSONKeyCoerce = FromJSONKeyCoerce CoerceText
366468
469+-- | Semantically the same as @coerceFromJSONKeyFunction = fmap coerce = coerce@.
470+--
471+-- See note on 'fromJSONKeyCoerce'.
367472coerceFromJSONKeyFunction ::
368−#if HAS_COERCIBLE
369473 Coercible a b =>
370−#endif
371474 FromJSONKeyFunction a -> FromJSONKeyFunction b
372−coerceFromJSONKeyFunction (FromJSONKeyCoerce CoerceText) = FromJSONKeyCoerce CoerceText
373−coerceFromJSONKeyFunction (FromJSONKeyText f) = FromJSONKeyText (coerce' . f)
374−coerceFromJSONKeyFunction (FromJSONKeyTextParser f) = FromJSONKeyTextParser (fmap coerce' . f)
375−coerceFromJSONKeyFunction (FromJSONKeyValue f) = FromJSONKeyValue (fmap coerce' . f)
475+coerceFromJSONKeyFunction = coerce
376476
377477{-# RULES
378478 "FromJSONKeyCoerce: fmap id" forall (x :: FromJSONKeyFunction a).
379479 fmap id x = x
380480 #-}
381−#if HAS_COERCIBLE
382481{-# RULES
383482 "FromJSONKeyCoerce: fmap coerce" forall x .
384483 fmap coerce x = coerceFromJSONKeyFunction x
385484 #-}
386−#endif
387485
486+-- | Same as 'fmap'. Provided for the consistency with 'ToJSONKeyFunction'.
388487mapFromJSONKeyFunction :: (a -> b) -> FromJSONKeyFunction a -> FromJSONKeyFunction b
389488mapFromJSONKeyFunction = fmap
390489
490+-- | 'fromJSONKey' for 'Generic' types.
491+-- These types must be sums of nullary constructors, whose names will be used
492+-- as keys for JSON objects.
493+--
494+-- See also 'genericToJSONKey'.
495+--
496+-- === __Example__
497+--
498+-- @
499+-- data Color = Red | Green | Blue
500+-- deriving 'Generic'
501+--
502+-- instance 'FromJSONKey' Color where
503+-- 'fromJSONKey' = 'genericFromJSONKey' 'defaultJSONKeyOptions'
504+-- @
505+genericFromJSONKey :: forall a. (Generic a, GFromJSONKey (Rep a))
506+ => JSONKeyOptions
507+ -> FromJSONKeyFunction a
508+genericFromJSONKey opts = FromJSONKeyTextParser $ \t ->
509+ case parseSumFromString (keyModifier opts) t of
510+ Nothing -> fail $
511+ "invalid key " ++ show t ++ ", expected one of " ++ show cnames
512+ Just k -> pure (to k)
513+ where
514+ cnames = unTagged2 (constructorTags (keyModifier opts) :: Tagged2 (Rep a) [String])
515+
516+class (ConstructorNames f, SumFromString f) => GFromJSONKey f where
517+instance (ConstructorNames f, SumFromString f) => GFromJSONKey f where
518+
391519-------------------------------------------------------------------------------
392520-- Functions needed for documentation
393521-------------------------------------------------------------------------------
394522
395523-- | Fail parsing due to a type mismatch, with a descriptive message.
396524--
397−-- Example usage:
525+-- The following wrappers should generally be prefered:
526+-- 'withObject', 'withArray', 'withText', 'withBool'.
398527--
399−-- @
400−-- instance FromJSON Coord where
401−-- parseJSON ('Object' v) = {- type matches, life is good -}
402−-- parseJSON wat = 'typeMismatch' \"Coord\" wat
403−-- @
404−typeMismatch :: String -- ^ The name of the type you are trying to parse.
528+-- ==== Error message example
529+--
530+-- > typeMismatch "Object" (String "oops")
531+-- > -- Error: "expected Object, but encountered String"
532+typeMismatch :: String -- ^ The name of the JSON type being parsed
533+ -- (@\"Object\"@, @\"Array\"@, @\"String\"@, @\"Number\"@,
534+ -- @\"Boolean\"@, or @\"Null\"@).
405535 -> Value -- ^ The actual value encountered.
406536 -> Parser a
407537typeMismatch expected actual =
408− fail $ "expected " ++ expected ++ ", encountered " ++ name
409− where
410− name = case actual of
411− Object _ -> "Object"
412− Array _ -> "Array"
413− String _ -> "String"
414− Number _ -> "Number"
415− Bool _ -> "Boolean"
416− Null -> "Null"
538+ fail $ "expected " ++ expected ++ ", but encountered " ++ typeOf actual
539+
540+-- | Fail parsing due to a type mismatch, when the expected types are implicit.
541+--
542+-- ==== Error message example
543+--
544+-- > unexpected (String "oops")
545+-- > -- Error: "unexpected String"
546+unexpected :: Value -> Parser a
547+unexpected actual = fail $ "unexpected " ++ typeOf actual
548+
549+-- | JSON type of a value, name of the head constructor.
550+typeOf :: Value -> String
551+typeOf v = case v of
552+ Object _ -> "Object"
553+ Array _ -> "Array"
554+ String _ -> "String"
555+ Number _ -> "Number"
556+ Bool _ -> "Boolean"
557+ Null -> "Null"
417558
418559-------------------------------------------------------------------------------
419560-- Lifings of FromJSON and ToJSON to unary and binary type constructors
@@ -426,7 +567,7 @@ typeMismatch expected actual =
426567--
427568-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
428569-- instance at compile time. The generated instance is optimized for your type
429−-- so will probably be more efficient than the following two options:
570+-- so it will probably be more efficient than the following option.
430571--
431572-- * The compiler can provide a default generic implementation for
432573-- 'liftParseJSON'.
@@ -444,16 +585,20 @@ typeMismatch expected actual =
444585--
445586-- data Pair a b = Pair { pairFst :: a, pairSnd :: b } deriving 'Generic1'
446587--
447−-- instance FromJSON a => FromJSON1 (Pair a)
588+-- instance 'FromJSON' a => 'FromJSON1' (Pair a)
448589-- @
449590--
450−-- If @DefaultSignatures@ doesn't give exactly the results you want,
591+-- If the default implementation doesn't give exactly the results you want,
451592-- you can customize the generic decoding with only a tiny amount of
452593-- effort, using 'genericLiftParseJSON' with your preferred 'Options':
453594--
454595-- @
455−-- instance FromJSON a => FromJSON1 (Pair a) where
456−-- liftParseJSON = 'genericLiftParseJSON' 'defaultOptions'
596+-- customOptions = 'defaultOptions'
597+-- { 'fieldLabelModifier' = 'map' 'Data.Char.toUpper'
598+-- }
599+--
600+-- instance 'FromJSON' a => 'FromJSON1' (Pair a) where
601+-- 'liftParseJSON' = 'genericLiftParseJSON' customOptions
457602-- @
458603class FromJSON1 f where
459604 liftParseJSON :: (Value -> Parser a) -> (Value -> Parser [a]) -> Value -> Parser (f a)
@@ -490,9 +635,8 @@ class FromJSON2 f where
490635 -> (Value -> Parser b)
491636 -> (Value -> Parser [b])
492637 -> Value -> Parser [f a b]
493− liftParseJSONList2 fa ga fb gb v = case v of
494− Array vals -> fmap V.toList (V.mapM (liftParseJSON2 fa ga fb gb) vals)
495− _ -> typeMismatch "[a]" v
638+ liftParseJSONList2 fa ga fb gb = withArray "[]" $ \vals ->
639+ fmap V.toList (V.mapM (liftParseJSON2 fa ga fb gb) vals)
496640
497641-- | Lift the standard 'parseJSON' function through the type constructor.
498642parseJSON2 :: (FromJSON2 f, FromJSON a, FromJSON b) => Value -> Parser (f a b)
@@ -503,9 +647,10 @@ parseJSON2 = liftParseJSON2 parseJSON parseJSONList parseJSON parseJSONList
503647-- List functions
504648-------------------------------------------------------------------------------
505649
650+-- | Helper function to use with 'liftParseJSON'. See 'Data.Aeson.ToJSON.listEncoding'.
506651listParser :: (Value -> Parser a) -> Value -> Parser [a]
507652listParser f (Array xs) = fmap V.toList (V.mapM f xs)
508−listParser _ v = typeMismatch "[a]" v
653+listParser _ v = typeMismatch "Array" v
509654{-# INLINE listParser #-}
510655
511656-------------------------------------------------------------------------------
@@ -523,48 +668,139 @@ instance (FromJSON a) => FromJSON [a] where
523668-- Functions
524669-------------------------------------------------------------------------------
525670
526−-- | @withObject expected f value@ applies @f@ to the 'Object' when @value@ is an @Object@
527−-- and fails using @'typeMismatch' expected@ otherwise.
671+-- | Add context to a failure message, indicating the name of the structure
672+-- being parsed.
673+--
674+-- > prependContext "MyType" (fail "[error message]")
675+-- > -- Error: "parsing MyType failed, [error message]"
676+prependContext :: String -> Parser a -> Parser a
677+prependContext name = prependFailure ("parsing " ++ name ++ " failed, ")
678+
679+-- | @'withObject' name f value@ applies @f@ to the 'Object' when @value@
680+-- is an 'Data.Aeson.Object' and fails otherwise.
681+--
682+-- ==== Error message example
683+--
684+-- > withObject "MyType" f (String "oops")
685+-- > -- Error: "parsing MyType failed, expected Object, but encountered String"
528686withObject :: String -> (Object -> Parser a) -> Value -> Parser a
529−withObject _ f (Object obj) = f obj
530−withObject expected _ v = typeMismatch expected v
687+withObject _ f (Object obj) = f obj
688+withObject name _ v = prependContext name (typeMismatch "Object" v)
531689{-# INLINE withObject #-}
532690
533−-- | @withText expected f value@ applies @f@ to the 'Text' when @value@ is a @String@
534−-- and fails using @'typeMismatch' expected@ otherwise.
691+-- | @'withText' name f value@ applies @f@ to the 'Text' when @value@ is a
692+-- 'Data.Aeson.String' and fails otherwise.
693+--
694+-- ==== Error message example
695+--
696+-- > withText "MyType" f Null
697+-- > -- Error: "parsing MyType failed, expected String, but encountered Null"
535698withText :: String -> (Text -> Parser a) -> Value -> Parser a
536−withText _ f (String txt) = f txt
537−withText expected _ v = typeMismatch expected v
699+withText _ f (String txt) = f txt
700+withText name _ v = prependContext name (typeMismatch "String" v)
538701{-# INLINE withText #-}
539702
540−-- | @withArray expected f value@ applies @f@ to the 'Array' when @value@ is an @Array@
541−-- and fails using @'typeMismatch' expected@ otherwise.
703+-- | @'withArray' expected f value@ applies @f@ to the 'Array' when @value@ is
704+-- an 'Data.Aeson.Array' and fails otherwise.
705+--
706+-- ==== Error message example
707+--
708+-- > withArray "MyType" f (String "oops")
709+-- > -- Error: "parsing MyType failed, expected Array, but encountered String"
542710withArray :: String -> (Array -> Parser a) -> Value -> Parser a
543−withArray _ f (Array arr) = f arr
544−withArray expected _ v = typeMismatch expected v
711+withArray _ f (Array arr) = f arr
712+withArray name _ v = prependContext name (typeMismatch "Array" v)
545713{-# INLINE withArray #-}
546714
547−-- | @withNumber expected f value@ applies @f@ to the 'Number' when @value@ is a 'Number'.
548−-- and fails using @'typeMismatch' expected@ otherwise.
549−withNumber :: String -> (Number -> Parser a) -> Value -> Parser a
550−withNumber expected f = withScientific expected (f . scientificToNumber)
551−{-# INLINE withNumber #-}
552−{-# DEPRECATED withNumber "Use withScientific instead" #-}
553−
554−-- | @withScientific expected f value@ applies @f@ to the 'Scientific' number when @value@ is a 'Number'.
555−-- and fails using @'typeMismatch' expected@ otherwise.
715+-- | @'withScientific' name f value@ applies @f@ to the 'Scientific' number
716+-- when @value@ is a 'Data.Aeson.Number' and fails using 'typeMismatch'
717+-- otherwise.
718+--
719+-- /Warning/: If you are converting from a scientific to an unbounded
720+-- type such as 'Integer' you may want to add a restriction on the
721+-- size of the exponent (see 'withBoundedScientific') to prevent
722+-- malicious input from filling up the memory of the target system.
723+--
724+-- ==== Error message example
725+--
726+-- > withScientific "MyType" f (String "oops")
727+-- > -- Error: "parsing MyType failed, expected Number, but encountered String"
556728withScientific :: String -> (Scientific -> Parser a) -> Value -> Parser a
557−withScientific _ f (Number scientific) = f scientific
558−withScientific expected _ v = typeMismatch expected v
729+withScientific _ f (Number scientific) = f scientific
730+withScientific name _ v = prependContext name (typeMismatch "Number" v)
559731{-# INLINE withScientific #-}
560732
561−-- | @withBool expected f value@ applies @f@ to the 'Bool' when @value@ is a @Bool@
562−-- and fails using @'typeMismatch' expected@ otherwise.
733+-- | A variant of 'withScientific' which doesn't use 'prependContext', so that
734+-- such context can be added separately in a way that also applies when the
735+-- continuation @f :: Scientific -> Parser a@ fails.
736+--
737+-- /Warning/: If you are converting from a scientific to an unbounded
738+-- type such as 'Integer' you may want to add a restriction on the
739+-- size of the exponent (see 'withBoundedScientific') to prevent
740+-- malicious input from filling up the memory of the target system.
741+--
742+-- ==== Error message examples
743+--
744+-- > withScientific' f (String "oops")
745+-- > -- Error: "unexpected String"
746+-- >
747+-- > prependContext "MyType" (withScientific' f (String "oops"))
748+-- > -- Error: "parsing MyType failed, unexpected String"
749+withScientific' :: (Scientific -> Parser a) -> Value -> Parser a
750+withScientific' f v = case v of
751+ Number n -> f n
752+ _ -> typeMismatch "Number" v
753+{-# INLINE withScientific' #-}
754+
755+-- | @'withBoundedScientific' name f value@ applies @f@ to the 'Scientific' number
756+-- when @value@ is a 'Number' with exponent less than or equal to 1024.
757+withBoundedScientific :: String -> (Scientific -> Parser a) -> Value -> Parser a
758+withBoundedScientific name f v = withBoundedScientific_ (prependContext name) f v
759+{-# INLINE withBoundedScientific #-}
760+
761+-- | A variant of 'withBoundedScientific' which doesn't use 'prependContext',
762+-- so that such context can be added separately in a way that also applies
763+-- when the continuation @f :: Scientific -> Parser a@ fails.
764+withBoundedScientific' :: (Scientific -> Parser a) -> Value -> Parser a
765+withBoundedScientific' f v = withBoundedScientific_ id f v
766+{-# INLINE withBoundedScientific' #-}
767+
768+-- | A variant of 'withBoundedScientific_' parameterized by a function to apply
769+-- to the 'Parser' in case of failure.
770+withBoundedScientific_ :: (Parser a -> Parser a) -> (Scientific -> Parser a) -> Value -> Parser a
771+withBoundedScientific_ whenFail f (Number scientific) =
772+ if exp10 > 1024
773+ then whenFail (fail msg)
774+ else f scientific
775+ where
776+ exp10 = base10Exponent scientific
777+ msg = "found a number with exponent " ++ show exp10 ++ ", but it must not be greater than 1024"
778+withBoundedScientific_ whenFail _ v =
779+ whenFail (typeMismatch "Number" v)
780+{-# INLINE withBoundedScientific_ #-}
781+
782+-- | @'withBool' expected f value@ applies @f@ to the 'Bool' when @value@ is a
783+-- 'Boolean' and fails otherwise.
784+--
785+-- ==== Error message example
786+--
787+-- > withBool "MyType" f (String "oops")
788+-- > -- Error: "parsing MyType failed, expected Boolean, but encountered String"
563789withBool :: String -> (Bool -> Parser a) -> Value -> Parser a
564−withBool _ f (Bool arr) = f arr
565−withBool expected _ v = typeMismatch expected v
790+withBool _ f (Bool arr) = f arr
791+withBool name _ v = prependContext name (typeMismatch "Boolean" v)
566792{-# INLINE withBool #-}
567793
794+-- | Decode a nested JSON-encoded string.
795+withEmbeddedJSON :: String -> (Value -> Parser a) -> Value -> Parser a
796+withEmbeddedJSON _ innerParser (String txt) =
797+ either fail innerParser $ eitherDecode (L.fromStrict $ T.encodeUtf8 txt)
798+ where
799+ eitherDecode = eitherFormatError . eitherDecodeWith jsonEOF ifromJSON
800+ eitherFormatError = either (Left . uncurry formatError) Right
801+withEmbeddedJSON name _ v = prependContext name (typeMismatch "String" v)
802+{-# INLINE withEmbeddedJSON #-}
803+
568804-- | Convert a value from JSON, failing if the types do not match.
569805fromJSON :: (FromJSON a) => Value -> Result a
570806fromJSON = parse parseJSON
@@ -583,32 +819,68 @@ ifromJSON = iparse parseJSON
583819-- in an object for it to be valid. If the key and value are
584820-- optional, use '.:?' instead.
585821(.:) :: (FromJSON a) => Object -> Text -> Parser a
586−obj .: key = case H.lookup key obj of
587− Nothing -> fail $ "key " ++ show key ++ " not present"
588− Just v -> parseJSON v <?> Key key
822+(.:) = explicitParseField parseJSON
589823{-# INLINE (.:) #-}
590824
591−-- | Retrieve the value associated with the given key of an 'Object'.
592−-- The result is 'Nothing' if the key is not present, or 'empty' if
593−-- the value cannot be converted to the desired type.
825+-- | Retrieve the value associated with the given key of an 'Object'. The
826+-- result is 'Nothing' if the key is not present or if its value is 'Null',
827+-- or 'empty' if the value cannot be converted to the desired type.
594828--
595829-- This accessor is most useful if the key and value can be absent
596830-- from an object without affecting its validity. If the key and
597831-- value are mandatory, use '.:' instead.
598832(.:?) :: (FromJSON a) => Object -> Text -> Parser (Maybe a)
599−obj .:? key = case H.lookup key obj of
600− Nothing -> pure Nothing
601− Just v -> parseJSON v <?> Key key
833+(.:?) = explicitParseFieldMaybe parseJSON
602834{-# INLINE (.:?) #-}
603835
604−-- | Like '.:?', but the resulting parser will fail,
605−-- if the key is present but is 'Null'.
836+-- | Retrieve the value associated with the given key of an 'Object'.
837+-- The result is 'Nothing' if the key is not present or 'empty' if the
838+-- value cannot be converted to the desired type.
839+--
840+-- This differs from '.:?' by attempting to parse 'Null' the same as any
841+-- other JSON value, instead of interpreting it as 'Nothing'.
606842(.:!) :: (FromJSON a) => Object -> Text -> Parser (Maybe a)
607−obj .:! key = case H.lookup key obj of
608− Nothing -> pure Nothing
609− Just v -> Just <$> parseJSON v <?> Key key
843+(.:!) = explicitParseFieldMaybe' parseJSON
610844{-# INLINE (.:!) #-}
611845
846+-- | Function variant of '.:'.
847+parseField :: (FromJSON a) => Object -> Text -> Parser a
848+parseField = (.:)
849+{-# INLINE parseField #-}
850+
851+-- | Function variant of '.:?'.
852+parseFieldMaybe :: (FromJSON a) => Object -> Text -> Parser (Maybe a)
853+parseFieldMaybe = (.:?)
854+{-# INLINE parseFieldMaybe #-}
855+
856+-- | Function variant of '.:!'.
857+parseFieldMaybe' :: (FromJSON a) => Object -> Text -> Parser (Maybe a)
858+parseFieldMaybe' = (.:!)
859+{-# INLINE parseFieldMaybe' #-}
860+
861+-- | Variant of '.:' with explicit parser function.
862+--
863+-- E.g. @'explicitParseField' 'parseJSON1' :: ('FromJSON1' f, 'FromJSON' a) -> 'Object' -> 'Text' -> 'Parser' (f a)@
864+explicitParseField :: (Value -> Parser a) -> Object -> Text -> Parser a
865+explicitParseField p obj key = case H.lookup key obj of
866+ Nothing -> fail $ "key " ++ show key ++ " not found"
867+ Just v -> p v <?> Key key
868+{-# INLINE explicitParseField #-}
869+
870+-- | Variant of '.:?' with explicit parser function.
871+explicitParseFieldMaybe :: (Value -> Parser a) -> Object -> Text -> Parser (Maybe a)
872+explicitParseFieldMaybe p obj key = case H.lookup key obj of
873+ Nothing -> pure Nothing
874+ Just v -> liftParseJSON p (listParser p) v <?> Key key -- listParser isn't used by maybe instance.
875+{-# INLINE explicitParseFieldMaybe #-}
876+
877+-- | Variant of '.:!' with explicit parser function.
878+explicitParseFieldMaybe' :: (Value -> Parser a) -> Object -> Text -> Parser (Maybe a)
879+explicitParseFieldMaybe' p obj key = case H.lookup key obj of
880+ Nothing -> pure Nothing
881+ Just v -> Just <$> p v <?> Key key
882+{-# INLINE explicitParseFieldMaybe' #-}
883+
612884-- | Helper for use in combination with '.:?' to provide default
613885-- values for optional JSON object fields.
614886--
@@ -631,317 +903,554 @@ pmval .!= val = fromMaybe val <$> pmval
631903-- Generic parseJSON
632904-------------------------------------------------------------------------------
633905
906+instance GFromJSON arity V1 where
907+ -- Whereof we cannot format, thereof we cannot parse:
908+ gParseJSON _ _ _ = fail "Attempted to parse empty type"
909+
910+
634911instance OVERLAPPABLE_ (GFromJSON arity a) => GFromJSON arity (M1 i c a) where
635912 -- Meta-information, which is not handled elsewhere, is just added to the
636913 -- parsed value:
637− gParseJSON opts pa pj pjl = fmap M1 . gParseJSON opts pa pj pjl
914+ gParseJSON opts fargs = fmap M1 . gParseJSON opts fargs
915+
916+-- Information for error messages
917+
918+type TypeName = String
919+type ConName = String
920+
921+-- | Add the name of the type being parsed to a parser's error messages.
922+contextType :: TypeName -> Parser a -> Parser a
923+contextType = prependContext
924+
925+-- | Add the tagKey that will be looked up while building an ADT
926+-- | Produce the error equivalent to
927+-- | Left "Error in $: parsing T failed, expected an object with keys "tag" and
928+-- | "contents", where "tag" i-- |s associated to one of ["Foo", "Bar"],
929+-- | The parser returned error was: could not find key "tag"
930+contextTag :: Text -> [String] -> Parser a -> Parser a
931+contextTag tagKey cnames = prependFailure
932+ ("expected Object with key \"" ++ unpack tagKey ++ "\"" ++
933+ " containing one of " ++ show cnames ++ ", ")
934+
935+-- | Add the name of the constructor being parsed to a parser's error messages.
936+contextCons :: ConName -> TypeName -> Parser a -> Parser a
937+contextCons cname tname = prependContext (showCons cname tname)
938+
939+-- | Render a constructor as @\"MyType(MyConstructor)\"@.
940+showCons :: ConName -> TypeName -> String
941+showCons cname tname = tname ++ "(" ++ cname ++ ")"
942+
943+--------------------------------------------------------------------------------
944+
945+-- Parsing single fields
638946
639947instance (FromJSON a) => GFromJSON arity (K1 i a) where
640948 -- Constant values are decoded using their FromJSON instance:
641− gParseJSON _opts _ _ _ = fmap K1 . parseJSON
949+ gParseJSON _opts _ = fmap K1 . parseJSON
642950
643951instance GFromJSON One Par1 where
644952 -- Direct occurrences of the last type parameter are decoded with the
645953 -- function passed in as an argument:
646− gParseJSON _opts _ pj _ = fmap Par1 . pj
954+ gParseJSON _opts (From1Args pj _) = fmap Par1 . pj
647955
648956instance (FromJSON1 f) => GFromJSON One (Rec1 f) where
649957 -- Recursive occurrences of the last type parameter are decoded using their
650958 -- FromJSON1 instance:
651− gParseJSON _opts _ pj pjl = fmap Rec1 . liftParseJSON pj pjl
652−
653−instance GFromJSON arity U1 where
654− -- Empty constructors are expected to be encoded as an empty array:
655− gParseJSON _opts _ _ _ v
656− | isEmptyArray v = pure U1
657− | otherwise = typeMismatch "unit constructor (U1)" v
658−
659−instance (ConsFromJSON arity a) => GFromJSON arity (C1 c a) where
660− -- Constructors need to be decoded differently depending on whether they're
661− -- a record or not. This distinction is made by consParseJSON:
662− gParseJSON opts pa pj pjl = fmap M1 . consParseJSON opts pa pj pjl
663−
664−instance ( FromProduct arity a, FromProduct arity b
665− , ProductSize a, ProductSize b
666− ) => GFromJSON arity (a :*: b) where
667− -- Products are expected to be encoded to an array. Here we check whether we
668− -- got an array of the same size as the product, then parse each of the
669− -- product's elements using parseProduct:
670− gParseJSON opts pa pj pjl = withArray "product (:*:)" $ \arr ->
671− let lenArray = V.length arr
672− lenProduct = (unTagged2 :: Tagged2 (a :*: b) Int -> Int)
673− productSize in
674− if lenArray == lenProduct
675− then parseProduct opts pa arr 0 lenProduct pj pjl
676− else fail $ "When expecting a product of " ++ show lenProduct ++
677− " values, encountered an Array of " ++ show lenArray ++
678− " elements instead"
679−
680−instance ( AllNullary (a :+: b) allNullary
681− , ParseSum arity (a :+: b) allNullary
682− ) => GFromJSON arity (a :+: b) where
683− -- If all constructors of a sum datatype are nullary and the
684− -- 'allNullaryToStringTag' option is set they are expected to be
685− -- encoded as strings. This distinction is made by 'parseSum':
686− gParseJSON opts pa pj pjl =
687− (unTagged :: Tagged allNullary (Parser ((a :+: b) d)) ->
688− (Parser ((a :+: b) d)))
689− . parseSum opts pa pj pjl
959+ gParseJSON _opts (From1Args pj pjl) = fmap Rec1 . liftParseJSON pj pjl
690960
691961instance (FromJSON1 f, GFromJSON One g) => GFromJSON One (f :.: g) where
692962 -- If an occurrence of the last type parameter is nested inside two
693963 -- composed types, it is decoded by using the outermost type's FromJSON1
694964 -- instance to generically decode the innermost type:
695− gParseJSON opts pa pj pjl =
696− let gpj = gParseJSON opts pa pj pjl in
697− fmap Comp1 . liftParseJSON gpj (listParser gpj)
965+ gParseJSON opts fargs =
966+ let gpj = gParseJSON opts fargs in
967+ fmap Comp1 . liftParseJSON gpj (listParser gpj)
968+
969+--------------------------------------------------------------------------------
970+
971+instance (GFromJSON' arity a, Datatype d) => GFromJSON arity (D1 d a) where
972+ -- Meta-information, which is not handled elsewhere, is just added to the
973+ -- parsed value:
974+ gParseJSON opts fargs = fmap M1 . gParseJSON' (tname :* opts :* fargs)
975+ where
976+ tname = moduleName proxy ++ "." ++ datatypeName proxy
977+ proxy = undefined :: M1 _i d _f _p
978+
979+-- | 'GFromJSON', after unwrapping the 'D1' constructor, now carrying the data
980+-- type's name.
981+class GFromJSON' arity f where
982+ gParseJSON' :: TypeName :* Options :* FromArgs arity a
983+ -> Value
984+ -> Parser (f a)
985+
986+-- | Single constructor.
987+instance ( ConsFromJSON arity a
988+ , AllNullary (C1 c a) allNullary
989+ , ParseSum arity (C1 c a) allNullary
990+ , Constructor c
991+ ) => GFromJSON' arity (C1 c a) where
992+ -- The option 'tagSingleConstructors' determines whether to wrap
993+ -- a single-constructor type.
994+ gParseJSON' p@(_ :* opts :* _)
995+ | tagSingleConstructors opts
996+ = (unTagged :: Tagged allNullary (Parser (C1 c a p)) -> Parser (C1 c a p))
997+ . parseSum p
998+ | otherwise = fmap M1 . consParseJSON (cname :* p)
999+ where
1000+ cname = conName (undefined :: M1 _i c _f _p)
1001+
1002+-- | Multiple constructors.
1003+instance ( AllNullary (a :+: b) allNullary
1004+ , ParseSum arity (a :+: b) allNullary
1005+ ) => GFromJSON' arity (a :+: b) where
1006+ -- If all constructors of a sum datatype are nullary and the
1007+ -- 'allNullaryToStringTag' option is set they are expected to be
1008+ -- encoded as strings. This distinction is made by 'parseSum':
1009+ gParseJSON' p =
1010+ (unTagged :: Tagged allNullary (Parser ((a :+: b) _d)) ->
1011+ Parser ((a :+: b) _d))
1012+ . parseSum p
6981013
6991014--------------------------------------------------------------------------------
7001015
7011016class ParseSum arity f allNullary where
702− parseSum :: Options -> Proxy arity
703− -> (Value -> Parser a) -> (Value -> Parser [a])
704− -> Value -> Tagged allNullary (Parser (f a))
705−
706−instance ( SumFromString (a :+: b)
707− , FromPair arity (a :+: b)
708− , FromTaggedObject arity (a :+: b)
709− ) => ParseSum arity (a :+: b) True where
710− parseSum opts pa pj pjl
711− | allNullaryToStringTag opts = Tagged . parseAllNullarySum opts
712− | otherwise = Tagged . parseNonAllNullarySum opts pa pj pjl
713−
714−instance ( FromPair arity (a :+: b)
715− , FromTaggedObject arity (a :+: b)
716− ) => ParseSum arity (a :+: b) False where
717− parseSum opts pa pj pjl = Tagged . parseNonAllNullarySum opts pa pj pjl
1017+ parseSum :: TypeName :* Options :* FromArgs arity a
1018+ -> Value
1019+ -> Tagged allNullary (Parser (f a))
1020+
1021+instance ( ConstructorNames f
1022+ , SumFromString f
1023+ , FromPair arity f
1024+ , FromTaggedObject arity f
1025+ , FromUntaggedValue arity f
1026+ ) => ParseSum arity f True where
1027+ parseSum p@(tname :* opts :* _)
1028+ | allNullaryToStringTag opts = Tagged . parseAllNullarySum tname opts
1029+ | otherwise = Tagged . parseNonAllNullarySum p
1030+
1031+instance ( ConstructorNames f
1032+ , FromPair arity f
1033+ , FromTaggedObject arity f
1034+ , FromUntaggedValue arity f
1035+ ) => ParseSum arity f False where
1036+ parseSum p = Tagged . parseNonAllNullarySum p
7181037
7191038--------------------------------------------------------------------------------
7201039
721−parseAllNullarySum :: SumFromString f => Options -> Value -> Parser (f a)
722−parseAllNullarySum opts = withText "Text" $ \key ->
723− maybe (notFound key) return $
724− parseSumFromString opts key
1040+parseAllNullarySum :: (SumFromString f, ConstructorNames f)
1041+ => TypeName -> Options -> Value -> Parser (f a)
1042+parseAllNullarySum tname opts =
1043+ withText tname $ \tag ->
1044+ maybe (badTag tag) return $
1045+ parseSumFromString modifier tag
1046+ where
1047+ badTag tag = failWithCTags tname modifier $ \cnames ->
1048+ "expected one of the tags " ++ show cnames ++
1049+ ", but found tag " ++ show tag
1050+ modifier = constructorTagModifier opts
1051+
1052+-- | Fail with an informative error message about a mismatched tag.
1053+-- The error message is parameterized by the list of expected tags,
1054+-- to be inferred from the result type of the parser.
1055+failWithCTags
1056+ :: forall f a t. ConstructorNames f
1057+ => TypeName -> (String -> t) -> ([t] -> String) -> Parser (f a)
1058+failWithCTags tname modifier f =
1059+ contextType tname . fail $ f cnames
1060+ where
1061+ cnames = unTagged2 (constructorTags modifier :: Tagged2 f [t])
7251062
7261063class SumFromString f where
727− parseSumFromString :: Options -> Text -> Maybe (f a)
1064+ parseSumFromString :: (String -> String) -> Text -> Maybe (f a)
7281065
7291066instance (SumFromString a, SumFromString b) => SumFromString (a :+: b) where
7301067 parseSumFromString opts key = (L1 <$> parseSumFromString opts key) <|>
7311068 (R1 <$> parseSumFromString opts key)
7321069
7331070instance (Constructor c) => SumFromString (C1 c U1) where
734− parseSumFromString opts key | key == name = Just $ M1 U1
735− | otherwise = Nothing
736− where
737− name = pack $ constructorTagModifier opts $
738− conName (undefined :: t c U1 p)
1071+ parseSumFromString modifier key
1072+ | key == name = Just $ M1 U1
1073+ | otherwise = Nothing
1074+ where
1075+ name = pack $ modifier $ conName (undefined :: M1 _i c _f _p)
7391076
740−--------------------------------------------------------------------------------
1077+-- For genericFromJSONKey
1078+instance SumFromString a => SumFromString (D1 d a) where
1079+ parseSumFromString modifier key = M1 <$> parseSumFromString modifier key
1080+
1081+-- | List of all constructor tags.
1082+constructorTags :: ConstructorNames a => (String -> t) -> Tagged2 a [t]
1083+constructorTags modifier =
1084+ fmap DList.toList (constructorNames' modifier)
1085+
1086+-- | List of all constructor names of an ADT, after a given conversion
1087+-- function. (Better inlining.)
1088+class ConstructorNames a where
1089+ constructorNames' :: (String -> t) -> Tagged2 a (DList.DList t)
1090+
1091+instance (ConstructorNames a, ConstructorNames b) => ConstructorNames (a :+: b) where
1092+ constructorNames' = liftA2 append constructorNames' constructorNames'
1093+ where
1094+ append
1095+ :: Tagged2 a (DList.DList t)
1096+ -> Tagged2 b (DList.DList t)
1097+ -> Tagged2 (a :+: b) (DList.DList t)
1098+ append (Tagged2 xs) (Tagged2 ys) = Tagged2 (DList.append xs ys)
1099+
1100+instance Constructor c => ConstructorNames (C1 c a) where
1101+ constructorNames' f = Tagged2 (pure (f cname))
1102+ where
1103+ cname = conName (undefined :: M1 _i c _f _p)
1104+
1105+-- For genericFromJSONKey
1106+instance ConstructorNames a => ConstructorNames (D1 d a) where
1107+ constructorNames' = retag . constructorNames'
1108+ where
1109+ retag :: Tagged2 a u -> Tagged2 (D1 d a) u
1110+ retag (Tagged2 x) = Tagged2 x
7411111
742−parseNonAllNullarySum :: ( FromPair arity (a :+: b)
743− , FromTaggedObject arity (a :+: b)
744− ) => Options -> Proxy arity
745− -> (Value -> Parser c) -> (Value -> Parser [c])
746− -> Value -> Parser ((a :+: b) c)
747−parseNonAllNullarySum opts pa pj pjl =
1112+--------------------------------------------------------------------------------
1113+parseNonAllNullarySum :: forall f c arity.
1114+ ( FromPair arity f
1115+ , FromTaggedObject arity f
1116+ , FromUntaggedValue arity f
1117+ , ConstructorNames f
1118+ ) => TypeName :* Options :* FromArgs arity c
1119+ -> Value -> Parser (f c)
1120+parseNonAllNullarySum p@(tname :* opts :* _) =
7481121 case sumEncoding opts of
7491122 TaggedObject{..} ->
750− withObject "Object" $ \obj -> do
751− tag <- obj .: pack tagFieldName
752− fromMaybe (notFound tag) $
753− parseFromTaggedObject opts pa contentsFieldName obj pj pjl tag
1123+ withObject tname $ \obj -> do
1124+ tag <- contextType tname . contextTag tagKey cnames_ $ obj .: tagKey
1125+ fromMaybe (badTag tag <?> Key tagKey) $
1126+ parseFromTaggedObject (tag :* contentsFieldName :* p) obj
1127+ where
1128+ tagKey = pack tagFieldName
1129+ badTag tag = failWith_ $ \cnames ->
1130+ "expected tag field to be one of " ++ show cnames ++
1131+ ", but found tag " ++ show tag
1132+ cnames_ = unTagged2 (constructorTags (constructorTagModifier opts) :: Tagged2 f [String])
7541133
7551134 ObjectWithSingleField ->
756− withObject "Object" $ \obj ->
757− case H.toList obj of
758− [pair@(tag, _)] -> fromMaybe (notFound tag) $
759− parsePair opts pa pj pjl pair
760− _ -> fail "Object doesn't have a single field"
1135+ withObject tname $ \obj -> case H.toList obj of
1136+ [(tag, v)] -> maybe (badTag tag) (<?> Key tag) $
1137+ parsePair (tag :* p) v
1138+ _ -> contextType tname . fail $
1139+ "expected an Object with a single pair, but found " ++
1140+ show (H.size obj) ++ " pairs"
1141+ where
1142+ badTag tag = failWith_ $ \cnames ->
1143+ "expected an Object with a single pair where the tag is one of " ++
1144+ show cnames ++ ", but found tag " ++ show tag
7611145
7621146 TwoElemArray ->
763− withArray "Array" $ \arr ->
764− if V.length arr == 2
765− then case V.unsafeIndex arr 0 of
766− String tag -> fromMaybe (notFound tag) $
767− parsePair opts pa pj pjl (tag, V.unsafeIndex arr 1)
768− _ -> fail "First element is not a String"
769− else fail "Array doesn't have 2 elements"
1147+ withArray tname $ \arr -> case V.length arr of
1148+ 2 | String tag <- V.unsafeIndex arr 0 ->
1149+ maybe (badTag tag <?> Index 0) (<?> Index 1) $
1150+ parsePair (tag :* p) (V.unsafeIndex arr 1)
1151+ | otherwise ->
1152+ contextType tname $
1153+ fail "tag element is not a String" <?> Index 0
1154+ len -> contextType tname . fail $
1155+ "expected a 2-element Array, but encountered an Array of length " ++
1156+ show len
1157+ where
1158+ badTag tag = failWith_ $ \cnames ->
1159+ "expected tag of the 2-element Array to be one of " ++
1160+ show cnames ++ ", but found tag " ++ show tag
1161+
1162+ UntaggedValue -> parseUntaggedValue p
1163+ where
1164+ failWith_ = failWithCTags tname (constructorTagModifier opts)
7701165
7711166--------------------------------------------------------------------------------
7721167
7731168class FromTaggedObject arity f where
774− parseFromTaggedObject :: Options -> Proxy arity
775− -> String -> Object
776− -> (Value -> Parser a) -> (Value -> Parser [a])
777− -> Text -> Maybe (Parser (f a))
1169+ -- The first two components of the parameter tuple are: the constructor tag
1170+ -- to match against, and the contents field name.
1171+ parseFromTaggedObject
1172+ :: Text :* String :* TypeName :* Options :* FromArgs arity a
1173+ -> Object
1174+ -> Maybe (Parser (f a))
7781175
7791176instance ( FromTaggedObject arity a, FromTaggedObject arity b) =>
7801177 FromTaggedObject arity (a :+: b) where
781− parseFromTaggedObject opts pa contentsFieldName obj pj pjl tag =
782− (fmap L1 <$> parseFromTaggedObject opts pa contentsFieldName obj pj pjl tag) <|>
783− (fmap R1 <$> parseFromTaggedObject opts pa contentsFieldName obj pj pjl tag)
1178+ parseFromTaggedObject p obj =
1179+ (fmap L1 <$> parseFromTaggedObject p obj) <|>
1180+ (fmap R1 <$> parseFromTaggedObject p obj)
7841181
785−instance ( FromTaggedObject' arity f
1182+instance ( IsRecord f isRecord
1183+ , FromTaggedObject' arity f isRecord
7861184 , Constructor c
7871185 ) => FromTaggedObject arity (C1 c f) where
788− parseFromTaggedObject opts pa contentsFieldName obj pj pjl tag
789− | tag == name = Just $ M1 <$> parseFromTaggedObject'
790− opts pa contentsFieldName pj pjl obj
791− | otherwise = Nothing
792− where
793− name = pack $ constructorTagModifier opts $
794− conName (undefined :: t c f p)
1186+ parseFromTaggedObject (tag :* contentsFieldName :* p@(_ :* opts :* _))
1187+ | tag == tag'
1188+ = Just . fmap M1 .
1189+ (unTagged :: Tagged isRecord (Parser (f a)) -> Parser (f a)) .
1190+ parseFromTaggedObject' (contentsFieldName :* cname :* p)
1191+ | otherwise = const Nothing
1192+ where
1193+ tag' = pack $ constructorTagModifier opts cname
1194+ cname = conName (undefined :: M1 _i c _f _p)
7951195
7961196--------------------------------------------------------------------------------
7971197
798−class FromTaggedObject' arity f where
799− parseFromTaggedObject' :: Options -> Proxy arity -> String
800− -> (Value -> Parser a) -> (Value -> Parser [a])
801− -> Object -> Parser (f a)
802−
803−class FromTaggedObject'' arity f isRecord where
804− parseFromTaggedObject'' :: Options -> Proxy arity -> String
805− -> (Value -> Parser a) -> (Value -> Parser [a])
806− -> Object -> Tagged isRecord (Parser (f a))
807−
808−instance ( IsRecord f isRecord
809− , FromTaggedObject'' arity f isRecord
810− ) => FromTaggedObject' arity f where
811− parseFromTaggedObject' opts pa contentsFieldName pj pjl =
812− (unTagged :: Tagged isRecord (Parser (f a)) -> Parser (f a)) .
813− parseFromTaggedObject'' opts pa contentsFieldName pj pjl
814−
815−instance (FromRecord arity f) => FromTaggedObject'' arity f True where
816− parseFromTaggedObject'' opts pa _ pj pjl =
817− Tagged . parseRecord opts pa Nothing pj pjl
818−
819−instance (GFromJSON arity f) => FromTaggedObject'' arity f False where
820− parseFromTaggedObject'' opts pa contentsFieldName pj pjl = Tagged .
821− (gParseJSON opts pa pj pjl <=< (.: pack contentsFieldName))
1198+class FromTaggedObject' arity f isRecord where
1199+ -- The first component of the parameter tuple is the contents field name.
1200+ parseFromTaggedObject'
1201+ :: String :* ConName :* TypeName :* Options :* FromArgs arity a
1202+ -> Object -> Tagged isRecord (Parser (f a))
1203+
1204+instance (RecordFromJSON arity f, FieldNames f) => FromTaggedObject' arity f True where
1205+ -- Records are unpacked in the tagged object
1206+ parseFromTaggedObject' (_ :* p) = Tagged . recordParseJSON (True :* p)
1207+
1208+instance (ConsFromJSON arity f) => FromTaggedObject' arity f False where
1209+ -- Nonnullary nonrecords are encoded in the contents field
1210+ parseFromTaggedObject' p obj = Tagged $ do
1211+ contents <- contextCons cname tname (obj .: key)
1212+ consParseJSON p' contents <?> Key key
1213+ where
1214+ key = pack contentsFieldName
1215+ contentsFieldName :* p'@(cname :* tname :* _) = p
8221216
823−instance OVERLAPPING_ FromTaggedObject'' arity U1 False where
824− parseFromTaggedObject'' _ _ _ _ _ _ = Tagged (pure U1)
1217+instance OVERLAPPING_ FromTaggedObject' arity U1 False where
1218+ -- Nullary constructors don't need a contents field
1219+ parseFromTaggedObject' _ _ = Tagged (pure U1)
8251220
8261221--------------------------------------------------------------------------------
8271222
1223+-- | Constructors need to be decoded differently depending on whether they're
1224+-- a record or not. This distinction is made by 'ConsParseJSON'.
8281225class ConsFromJSON arity f where
829− consParseJSON :: Options -> Proxy arity
830− -> (Value -> Parser a) -> (Value -> Parser [a])
831− -> Value -> Parser (f a)
1226+ consParseJSON
1227+ :: ConName :* TypeName :* Options :* FromArgs arity a
1228+ -> Value -> Parser (f a)
8321229
8331230class ConsFromJSON' arity f isRecord where
834− consParseJSON' :: Options -> Proxy arity
835− -> (Maybe Text) -- ^ A dummy label
836− -- (Nothing to use proper label)
837− -> (Value -> Parser a) -> (Value -> Parser [a])
838− -> Value -> Tagged isRecord (Parser (f a))
1231+ consParseJSON'
1232+ :: ConName :* TypeName :* Options :* FromArgs arity a
1233+ -> Value -> Tagged isRecord (Parser (f a))
8391234
8401235instance ( IsRecord f isRecord
8411236 , ConsFromJSON' arity f isRecord
8421237 ) => ConsFromJSON arity f where
843− consParseJSON opts pa pj pjl v = let
844− (v2,lab) = case (unwrapUnaryRecords opts,isUnary (undefined :: f a)) of
845− -- use a dummy object with a dummy label
846− (True,True) -> ((object [(pack "dummy",v)]),Just $ pack "dummy")
847− _ ->(v,Nothing)
848− in (unTagged :: Tagged isRecord (Parser (f a)) -> Parser (f a))
849− $ consParseJSON' opts pa lab pj pjl v2
850−
1238+ consParseJSON p =
1239+ (unTagged :: Tagged isRecord (Parser (f a)) -> Parser (f a))
1240+ . consParseJSON' p
1241+
1242+instance OVERLAPPING_
1243+ ( GFromJSON arity a, RecordFromJSON arity (S1 s a)
1244+ ) => ConsFromJSON' arity (S1 s a) True where
1245+ consParseJSON' p@(cname :* tname :* opts :* fargs)
1246+ | unwrapUnaryRecords opts = Tagged . fmap M1 . gParseJSON opts fargs
1247+ | otherwise = Tagged . withObject (showCons cname tname) (recordParseJSON (False :* p))
1248+
1249+instance RecordFromJSON arity f => ConsFromJSON' arity f True where
1250+ consParseJSON' p@(cname :* tname :* _) =
1251+ Tagged . withObject (showCons cname tname) (recordParseJSON (False :* p))
1252+
1253+instance OVERLAPPING_
1254+ ConsFromJSON' arity U1 False where
1255+ -- Empty constructors are expected to be encoded as an empty array:
1256+ consParseJSON' (cname :* tname :* _) v =
1257+ Tagged . contextCons cname tname $ case v of
1258+ Array a | V.null a -> pure U1
1259+ | otherwise -> fail_ a
1260+ _ -> typeMismatch "Array" v
1261+ where
1262+ fail_ a = fail $
1263+ "expected an empty Array, but encountered an Array of length " ++
1264+ show (V.length a)
8511265
852−instance (FromRecord arity f) => ConsFromJSON' arity f True where
853− consParseJSON' opts pa mlab pj pjl = Tagged . (withObject "record (:*:)"
854− $ parseRecord opts pa mlab pj pjl)
1266+instance OVERLAPPING_
1267+ GFromJSON arity f => ConsFromJSON' arity (S1 s f) False where
1268+ consParseJSON' (_ :* _ :* opts :* fargs) =
1269+ Tagged . fmap M1 . gParseJSON opts fargs
8551270
856−instance (GFromJSON arity f) => ConsFromJSON' arity f False where
857− consParseJSON' opts pa _ pj pjl = Tagged . gParseJSON opts pa pj pjl
1271+instance (ProductFromJSON arity f, ProductSize f
1272+ ) => ConsFromJSON' arity f False where
1273+ consParseJSON' p = Tagged . productParseJSON0 p
8581274
8591275--------------------------------------------------------------------------------
8601276
861−class FromRecord arity f where
862− parseRecord :: Options -> Proxy arity
863− -> (Maybe Text) -- ^ A dummy label
864− -- (Nothing to use proper label)
865− -> (Value -> Parser a) -> (Value -> Parser [a])
866− -> Object -> Parser (f a)
867−
868−instance ( FromRecord arity a
869− , FromRecord arity b
870− ) => FromRecord arity (a :*: b) where
871− parseRecord opts pa _ pj pjl obj =
872− (:*:) <$> parseRecord opts pa Nothing pj pjl obj
873− <*> parseRecord opts pa Nothing pj pjl obj
874−
875−instance ( Selector s
876− , GFromJSON arity a
877− ) => FromRecord arity (S1 s a) where
878− parseRecord opts pa lab pj pjl =
879− (<?> Key label) . gParseJSON opts pa pj pjl <=< (.: label)
880− where
881− label = fromMaybe defLabel lab
882− defLabel = pack . fieldLabelModifier opts $
883− selName (undefined :: t s a p)
884−
885−instance OVERLAPPING_ (Selector s, FromJSON a) =>
886− FromRecord arity (S1 s (K1 i (Maybe a))) where
887− parseRecord _ _ (Just lab) _ _ obj = (M1 . K1) <$> obj .:? lab
888− parseRecord opts _ Nothing _ _ obj = (M1 . K1) <$> obj .:? pack label
1277+class FieldNames f where
1278+ fieldNames :: f a -> [Text] -> [Text]
1279+
1280+instance (FieldNames a, FieldNames b) => FieldNames (a :*: b) where
1281+ fieldNames _ =
1282+ fieldNames (undefined :: a x) .
1283+ fieldNames (undefined :: b y)
1284+
1285+instance (Selector s) => FieldNames (S1 s f) where
1286+ fieldNames _ = (pack (selName (undefined :: M1 _i s _f _p)) :)
1287+
1288+class RecordFromJSON arity f where
1289+ recordParseJSON
1290+ :: Bool :* ConName :* TypeName :* Options :* FromArgs arity a
1291+ -> Object -> Parser (f a)
1292+
1293+instance ( FieldNames f
1294+ , RecordFromJSON' arity f
1295+ ) => RecordFromJSON arity f where
1296+ recordParseJSON (fromTaggedSum :* p@(cname :* tname :* opts :* _)) =
1297+ \obj -> checkUnknown obj >> recordParseJSON' p obj
8891298 where
890− label = fieldLabelModifier opts $
891− selName (undefined :: t s (K1 i (Maybe a)) p)
1299+ knownFields :: H.HashMap Text ()
1300+ knownFields = H.fromList $ map (,()) $
1301+ fieldNames (undefined :: f a)
1302+ [pack (tagFieldName (sumEncoding opts)) | fromTaggedSum]
1303+ checkUnknown =
1304+ if not (rejectUnknownFields opts)
1305+ then \_ -> return ()
1306+ else \obj -> case H.keys (H.difference obj knownFields) of
1307+ [] -> return ()
1308+ unknownFields -> contextCons cname tname $
1309+ fail ("unknown fields: " ++ show unknownFields)
1310+
1311+class RecordFromJSON' arity f where
1312+ recordParseJSON'
1313+ :: ConName :* TypeName :* Options :* FromArgs arity a
1314+ -> Object -> Parser (f a)
1315+
1316+instance ( RecordFromJSON' arity a
1317+ , RecordFromJSON' arity b
1318+ ) => RecordFromJSON' arity (a :*: b) where
1319+ recordParseJSON' p obj =
1320+ (:*:) <$> recordParseJSON' p obj
1321+ <*> recordParseJSON' p obj
1322+
1323+instance OVERLAPPABLE_ (Selector s, GFromJSON arity a) =>
1324+ RecordFromJSON' arity (S1 s a) where
1325+ recordParseJSON' (cname :* tname :* opts :* fargs) obj = do
1326+ fv <- contextCons cname tname (obj .: label)
1327+ M1 <$> gParseJSON opts fargs fv <?> Key label
1328+ where
1329+ label = pack $ fieldLabelModifier opts sname
1330+ sname = selName (undefined :: M1 _i s _f _p)
1331+
1332+instance INCOHERENT_ (Selector s, FromJSON a) =>
1333+ RecordFromJSON' arity (S1 s (K1 i (Maybe a))) where
1334+ recordParseJSON' (_ :* _ :* opts :* _) obj = M1 . K1 <$> obj .:? pack label
1335+ where
1336+ label = fieldLabelModifier opts sname
1337+ sname = selName (undefined :: M1 _i s _f _p)
1338+
1339+-- Parse an Option like a Maybe.
1340+instance INCOHERENT_ (Selector s, FromJSON a) =>
1341+ RecordFromJSON' arity (S1 s (K1 i (Semigroup.Option a))) where
1342+ recordParseJSON' p obj = wrap <$> recordParseJSON' p obj
1343+ where
1344+ wrap :: S1 s (K1 i (Maybe a)) p -> S1 s (K1 i (Semigroup.Option a)) p
1345+ wrap (M1 (K1 a)) = M1 (K1 (Semigroup.Option a))
8921346
8931347--------------------------------------------------------------------------------
8941348
895−class FromProduct arity f where
896− parseProduct :: Options -> Proxy arity
1349+productParseJSON0
1350+ :: forall f arity a. (ProductFromJSON arity f, ProductSize f)
1351+ => ConName :* TypeName :* Options :* FromArgs arity a
1352+ -> Value -> Parser (f a)
1353+ -- Products are expected to be encoded to an array. Here we check whether we
1354+ -- got an array of the same size as the product, then parse each of the
1355+ -- product's elements using productParseJSON:
1356+productParseJSON0 p@(cname :* tname :* _ :* _) =
1357+ withArray (showCons cname tname) $ \arr ->
1358+ let lenArray = V.length arr
1359+ lenProduct = (unTagged2 :: Tagged2 f Int -> Int)
1360+ productSize in
1361+ if lenArray == lenProduct
1362+ then productParseJSON p arr 0 lenProduct
1363+ else contextCons cname tname $
1364+ fail $ "expected an Array of length " ++ show lenProduct ++
1365+ ", but encountered an Array of length " ++ show lenArray
1366+
1367+--
1368+
1369+class ProductFromJSON arity f where
1370+ productParseJSON :: ConName :* TypeName :* Options :* FromArgs arity a
8971371 -> Array -> Int -> Int
898− -> (Value -> Parser a) -> (Value -> Parser [a])
8991372 -> Parser (f a)
9001373
901−instance ( FromProduct arity a
902− , FromProduct arity b
903− ) => FromProduct arity (a :*: b) where
904− parseProduct opts pa arr ix len pj pjl =
905− (:*:) <$> parseProduct opts pa arr ix lenL pj pjl
906− <*> parseProduct opts pa arr ixR lenR pj pjl
1374+instance ( ProductFromJSON arity a
1375+ , ProductFromJSON arity b
1376+ ) => ProductFromJSON arity (a :*: b) where
1377+ productParseJSON p arr ix len =
1378+ (:*:) <$> productParseJSON p arr ix lenL
1379+ <*> productParseJSON p arr ixR lenR
9071380 where
9081381 lenL = len `unsafeShiftR` 1
9091382 ixR = ix + lenL
9101383 lenR = len - lenL
9111384
912−instance (GFromJSON arity a) => FromProduct arity (S1 s a) where
913− parseProduct opts pa arr ix _ pj pjl =
914− gParseJSON opts pa pj pjl $ V.unsafeIndex arr ix
1385+instance (GFromJSON arity a) => ProductFromJSON arity (S1 s a) where
1386+ productParseJSON (_ :* _ :* opts :* fargs) arr ix _ =
1387+ M1 <$> gParseJSON opts fargs (V.unsafeIndex arr ix) <?> Index ix
9151388
9161389--------------------------------------------------------------------------------
9171390
9181391class FromPair arity f where
919− parsePair :: Options -> Proxy arity
920− -> (Value -> Parser a) -> (Value -> Parser [a])
921− -> Pair -> Maybe (Parser (f a))
1392+ -- The first component of the parameter tuple is the tag to match.
1393+ parsePair :: Text :* TypeName :* Options :* FromArgs arity a
1394+ -> Value
1395+ -> Maybe (Parser (f a))
9221396
9231397instance ( FromPair arity a
9241398 , FromPair arity b
9251399 ) => FromPair arity (a :+: b) where
926− parsePair opts pa pj pjl pair = (fmap L1 <$> parsePair opts pa pj pjl pair) <|>
927− (fmap R1 <$> parsePair opts pa pj pjl pair)
1400+ parsePair p pair =
1401+ (fmap L1 <$> parsePair p pair) <|>
1402+ (fmap R1 <$> parsePair p pair)
9281403
9291404instance ( Constructor c
930− , GFromJSON arity a
9311405 , ConsFromJSON arity a
9321406 ) => FromPair arity (C1 c a) where
933− parsePair opts pa pj pjl (tag, value)
934− | tag == tag' = Just $ gParseJSON opts pa pj pjl value
1407+ parsePair (tag :* p@(_ :* opts :* _)) v
1408+ | tag == tag' = Just $ M1 <$> consParseJSON (cname :* p) v
9351409 | otherwise = Nothing
936− where
937− tag' = pack $ constructorTagModifier opts $
938− conName (undefined :: t c a p)
1410+ where
1411+ tag' = pack $ constructorTagModifier opts cname
1412+ cname = conName (undefined :: M1 _i c _a _p)
9391413
9401414--------------------------------------------------------------------------------
9411415
942−notFound :: Text -> Parser a
943−notFound key = fail $ "The key \"" ++ unpack key ++ "\" was not found"
944−{-# INLINE notFound #-}
1416+class FromUntaggedValue arity f where
1417+ parseUntaggedValue :: TypeName :* Options :* FromArgs arity a
1418+ -> Value
1419+ -> Parser (f a)
1420+
1421+instance
1422+ ( FromUntaggedValue arity a
1423+ , FromUntaggedValue arity b
1424+ ) => FromUntaggedValue arity (a :+: b)
1425+ where
1426+ parseUntaggedValue p value =
1427+ L1 <$> parseUntaggedValue p value <|>
1428+ R1 <$> parseUntaggedValue p value
1429+
1430+instance OVERLAPPABLE_
1431+ ( ConsFromJSON arity a
1432+ , Constructor c
1433+ ) => FromUntaggedValue arity (C1 c a)
1434+ where
1435+ parseUntaggedValue p = fmap M1 . consParseJSON (cname :* p)
1436+ where
1437+ cname = conName (undefined :: M1 _i c _f _p)
1438+
1439+instance OVERLAPPING_
1440+ ( Constructor c )
1441+ => FromUntaggedValue arity (C1 c U1)
1442+ where
1443+ parseUntaggedValue (tname :* opts :* _) v =
1444+ contextCons cname tname $ case v of
1445+ String tag
1446+ | tag == tag' -> pure $ M1 U1
1447+ | otherwise -> fail_ tag
1448+ _ -> typeMismatch "String" v
1449+ where
1450+ tag' = pack $ constructorTagModifier opts cname
1451+ cname = conName (undefined :: M1 _i c _f _p)
1452+ fail_ tag = fail $
1453+ "expected tag " ++ show tag' ++ ", but found tag " ++ show tag
9451454
9461455-------------------------------------------------------------------------------
9471456-- Instances
@@ -951,13 +1460,6 @@ notFound key = fail $ "The key \"" ++ unpack key ++ "\" was not found"
9511460-- base
9521461-------------------------------------------------------------------------------
9531462
954−instance FromJSON1 Identity where
955− liftParseJSON p _ a = Identity <$> p a
956− {-# INLINE liftParseJSON #-}
957−
958−instance (FromJSON a) => FromJSON (Identity a) where
959− parseJSON = parseJSON1
960− {-# INLINE parseJSON #-}
9611463
9621464instance FromJSON2 Const where
9631465 liftParseJSON2 p _ _ _ = fmap Const . p
@@ -987,6 +1489,10 @@ instance FromJSON2 Either where
9871489 liftParseJSON2 pA _ pB _ (Object (H.toList -> [(key, value)]))
9881490 | key == left = Left <$> pA value <?> Key left
9891491 | key == right = Right <$> pB value <?> Key right
1492+ where
1493+ left, right :: Text
1494+ left = "Left"
1495+ right = "Right"
9901496
9911497 liftParseJSON2 _ _ _ _ _ = fail $
9921498 "expected an object with a single property " ++
@@ -1002,20 +1508,20 @@ instance (FromJSON a, FromJSON b) => FromJSON (Either a b) where
10021508 parseJSON = parseJSON2
10031509 {-# INLINE parseJSON #-}
10041510
1005−left, right :: Text
1006−left = "Left"
1007−right = "Right"
1008−
1511+instance FromJSON Void where
1512+ parseJSON _ = fail "Cannot parse Void"
1513+ {-# INLINE parseJSON #-}
10091514
10101515instance FromJSON Bool where
1011− parseJSON = withBool "Bool" pure
1516+ parseJSON (Bool b) = pure b
1517+ parseJSON v = typeMismatch "Bool" v
10121518 {-# INLINE parseJSON #-}
10131519
10141520instance FromJSONKey Bool where
10151521 fromJSONKey = FromJSONKeyTextParser $ \t -> case t of
10161522 "true" -> pure True
10171523 "false" -> pure False
1018− _ -> fail $ "Cannot parse key into Bool: " ++ T.unpack t
1524+ _ -> fail $ "cannot parse key " ++ show t ++ " into Bool"
10191525
10201526instance FromJSON Ordering where
10211527 parseJSON = withText "Ordering" $ \s ->
@@ -1023,25 +1529,30 @@ instance FromJSON Ordering where
10231529 "LT" -> return LT
10241530 "EQ" -> return EQ
10251531 "GT" -> return GT
1026− _ -> fail "Parsing Ordering value failed: expected \"LT\", \"EQ\", or \"GT\""
1532+ _ -> fail $ "parsing Ordering failed, unexpected " ++ show s ++
1533+ " (expected \"LT\", \"EQ\", or \"GT\")"
10271534
10281535instance FromJSON () where
10291536 parseJSON = withArray "()" $ \v ->
10301537 if V.null v
10311538 then pure ()
1032− else fail "Expected an empty array"
1539+ else prependContext "()" $ fail "expected an empty array"
10331540 {-# INLINE parseJSON #-}
10341541
10351542instance FromJSON Char where
1036− parseJSON = withText "Char" $ \t ->
1037− if T.compareLength t 1 == EQ
1038− then pure $ T.head t
1039− else fail "Expected a string of length 1"
1543+ parseJSON = withText "Char" parseChar
10401544 {-# INLINE parseJSON #-}
10411545
1042− parseJSONList = withText "String" $ pure . T.unpack
1546+ parseJSONList (String s) = pure (T.unpack s)
1547+ parseJSONList v = typeMismatch "String" v
10431548 {-# INLINE parseJSONList #-}
10441549
1550+parseChar :: Text -> Parser Char
1551+parseChar t =
1552+ if T.compareLength t 1 == EQ
1553+ then pure $ T.head t
1554+ else prependContext "Char" $ fail "expected a string of length 1"
1555+
10451556instance FromJSON Double where
10461557 parseJSON = parseRealFloat "Double"
10471558 {-# INLINE parseJSON #-}
@@ -1053,12 +1564,6 @@ instance FromJSONKey Double where
10531564 "-Infinity" -> pure (negate 1/0)
10541565 _ -> Scientific.toRealFloat <$> parseScientificText t
10551566
1056−instance FromJSON Number where
1057− parseJSON (Number s) = pure $ scientificToNumber s
1058− parseJSON Null = pure (D (0/0))
1059− parseJSON v = typeMismatch "Number" v
1060− {-# INLINE parseJSON #-}
1061−
10621567instance FromJSON Float where
10631568 parseJSON = parseRealFloat "Float"
10641569 {-# INLINE parseJSON #-}
@@ -1071,111 +1576,133 @@ instance FromJSONKey Float where
10711576 _ -> Scientific.toRealFloat <$> parseScientificText t
10721577
10731578instance (FromJSON a, Integral a) => FromJSON (Ratio a) where
1074− parseJSON = withObject "Rational" $ \obj ->
1075− (%) <$> obj .: "numerator"
1076− <*> obj .: "denominator"
1579+ parseJSON (Number x)
1580+ | exp10 <= 1024
1581+ , exp10 >= -1024 = return $! realToFrac x
1582+ | otherwise = prependContext "Ratio" $ fail msg
1583+ where
1584+ exp10 = base10Exponent x
1585+ msg = "found a number with exponent " ++ show exp10
1586+ ++ ", but it must not be greater than 1024 or less than -1024"
1587+ parseJSON o = objParser o
1588+ where
1589+ objParser = withObject "Rational" $ \obj -> do
1590+ numerator <- obj .: "numerator"
1591+ denominator <- obj .: "denominator"
1592+ if denominator == 0
1593+ then fail "Ratio denominator was 0"
1594+ else pure $ numerator % denominator
10771595 {-# INLINE parseJSON #-}
10781596
1079−-- | /WARNING:/ Only parse fixed-precision numbers from trusted input
1080−-- since an attacker could easily fill up the memory of the target
1081−-- system by specifying a scientific number with a big exponent like
1082−-- @1e1000000000@.
1597+-- | This instance includes a bounds check to prevent maliciously
1598+-- large inputs to fill up the memory of the target system. You can
1599+-- newtype 'Scientific' and provide your own instance using
1600+-- 'withScientific' if you want to allow larger inputs.
10831601instance HasResolution a => FromJSON (Fixed a) where
1084− parseJSON = withScientific "Fixed" $ pure . realToFrac
1602+ parseJSON = prependContext "Fixed" . withBoundedScientific' (pure . realToFrac)
10851603 {-# INLINE parseJSON #-}
10861604
10871605instance FromJSON Int where
1088− parseJSON = parseIntegral "Int"
1606+ parseJSON = parseBoundedIntegral "Int"
10891607 {-# INLINE parseJSON #-}
10901608
10911609instance FromJSONKey Int where
1092− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1610+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Int"
10931611
1094−-- | /WARNING:/ Only parse Integers from trusted input since an
1095−-- attacker could easily fill up the memory of the target system by
1096−-- specifying a scientific number with a big exponent like
1097−-- @1e1000000000@.
1612+-- | This instance includes a bounds check to prevent maliciously
1613+-- large inputs to fill up the memory of the target system. You can
1614+-- newtype 'Scientific' and provide your own instance using
1615+-- 'withScientific' if you want to allow larger inputs.
10981616instance FromJSON Integer where
1099− parseJSON = withScientific "Integral" $ pure . truncate
1617+ parseJSON = parseIntegral "Integer"
11001618 {-# INLINE parseJSON #-}
11011619
11021620instance FromJSONKey Integer where
1103− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1621+ fromJSONKey = FromJSONKeyTextParser $ parseIntegralText "Integer"
11041622
11051623instance FromJSON Natural where
1106− parseJSON = withScientific "Natural" $ \s ->
1107− if Scientific.coefficient s < 0
1108− then fail $ "Expected a Natural number but got the negative number: " <> show s
1109− else pure $ truncate s
1624+ parseJSON value = do
1625+ integer <- parseIntegral "Natural" value
1626+ parseNatural integer
11101627
11111628instance FromJSONKey Natural where
1112− fromJSONKey = FromJSONKeyTextParser $ \t -> parseScientificText t >>= \s ->
1113− if Scientific.coefficient s < 0
1114− then fail $ "Expected a Natural number but got the negative number: " <> show s
1115− else pure $ truncate s
1629+ fromJSONKey = FromJSONKeyTextParser $ \text -> do
1630+ integer <- parseIntegralText "Natural" text
1631+ parseNatural integer
1632+
1633+parseNatural :: Integer -> Parser Natural
1634+parseNatural integer =
1635+ if integer < 0 then
1636+ fail $ "parsing Natural failed, unexpected negative number " <> show integer
1637+ else
1638+ pure $ fromIntegral integer
11161639
11171640instance FromJSON Int8 where
1118− parseJSON = parseIntegral "Int8"
1641+ parseJSON = parseBoundedIntegral "Int8"
11191642 {-# INLINE parseJSON #-}
11201643
11211644instance FromJSONKey Int8 where
1122− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1645+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Int8"
11231646
11241647instance FromJSON Int16 where
1125− parseJSON = parseIntegral "Int16"
1648+ parseJSON = parseBoundedIntegral "Int16"
11261649 {-# INLINE parseJSON #-}
11271650
11281651instance FromJSONKey Int16 where
1129− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1652+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Int16"
11301653
11311654instance FromJSON Int32 where
1132− parseJSON = parseIntegral "Int32"
1655+ parseJSON = parseBoundedIntegral "Int32"
11331656 {-# INLINE parseJSON #-}
11341657
11351658instance FromJSONKey Int32 where
1136− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1659+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Int32"
11371660
11381661instance FromJSON Int64 where
1139− parseJSON = parseIntegral "Int64"
1662+ parseJSON = parseBoundedIntegral "Int64"
11401663 {-# INLINE parseJSON #-}
11411664
11421665instance FromJSONKey Int64 where
1143− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1666+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Int64"
11441667
11451668instance FromJSON Word where
1146− parseJSON = parseIntegral "Word"
1669+ parseJSON = parseBoundedIntegral "Word"
11471670 {-# INLINE parseJSON #-}
11481671
11491672instance FromJSONKey Word where
1150− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1673+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Word"
11511674
11521675instance FromJSON Word8 where
1153− parseJSON = parseIntegral "Word8"
1676+ parseJSON = parseBoundedIntegral "Word8"
11541677 {-# INLINE parseJSON #-}
11551678
11561679instance FromJSONKey Word8 where
1157− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1680+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Word8"
11581681
11591682instance FromJSON Word16 where
1160− parseJSON = parseIntegral "Word16"
1683+ parseJSON = parseBoundedIntegral "Word16"
11611684 {-# INLINE parseJSON #-}
11621685
11631686instance FromJSONKey Word16 where
1164− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1687+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Word16"
11651688
11661689instance FromJSON Word32 where
1167− parseJSON = parseIntegral "Word32"
1690+ parseJSON = parseBoundedIntegral "Word32"
11681691 {-# INLINE parseJSON #-}
11691692
11701693instance FromJSONKey Word32 where
1171− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1694+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Word32"
11721695
11731696instance FromJSON Word64 where
1174− parseJSON = parseIntegral "Word64"
1697+ parseJSON = parseBoundedIntegral "Word64"
11751698 {-# INLINE parseJSON #-}
11761699
11771700instance FromJSONKey Word64 where
1178− fromJSONKey = FromJSONKeyTextParser parseIntegralText
1701+ fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Word64"
1702+
1703+instance FromJSON CTime where
1704+ parseJSON = fmap CTime . parseJSON
1705+ {-# INLINE parseJSON #-}
11791706
11801707instance FromJSON Text where
11811708 parseJSON = withText "Text" pure
@@ -1184,27 +1711,38 @@ instance FromJSON Text where
11841711instance FromJSONKey Text where
11851712 fromJSONKey = fromJSONKeyCoerce
11861713
1714+
11871715instance FromJSON LT.Text where
11881716 parseJSON = withText "Lazy Text" $ pure . LT.fromStrict
11891717 {-# INLINE parseJSON #-}
11901718
1719+instance FromJSONKey LT.Text where
1720+ fromJSONKey = FromJSONKeyText LT.fromStrict
1721+
1722+
11911723instance FromJSON Version where
1724+ parseJSON = withText "Version" parseVersionText
11921725 {-# INLINE parseJSON #-}
1193− parseJSON = withText "Version" $ go . readP_to_S parseVersion . unpack
1194− where
1195− go [(v,[])] = return v
1196− go (_ : xs) = go xs
1197− go _ = fail $ "could not parse Version"
1726+
1727+instance FromJSONKey Version where
1728+ fromJSONKey = FromJSONKeyTextParser parseVersionText
1729+
1730+parseVersionText :: Text -> Parser Version
1731+parseVersionText = go . readP_to_S parseVersion . unpack
1732+ where
1733+ go [(v,[])] = return v
1734+ go (_ : xs) = go xs
1735+ go _ = fail "parsing Version failed"
11981736
11991737-------------------------------------------------------------------------------
12001738-- semigroups NonEmpty
12011739-------------------------------------------------------------------------------
12021740
12031741instance FromJSON1 NonEmpty where
1204− liftParseJSON p _ = withArray "NonEmpty a" $
1742+ liftParseJSON p _ = withArray "NonEmpty" $
12051743 (>>= ne) . Tr.sequence . zipWith (parseIndexedJSON p) [0..] . V.toList
12061744 where
1207− ne [] = fail "Expected a NonEmpty but got an empty list"
1745+ ne [] = fail "parsing NonEmpty failed, unexpected empty list"
12081746 ne (x:xs) = pure (x :| xs)
12091747 {-# INLINE liftParseJSON #-}
12101748
@@ -1225,7 +1763,7 @@ instance FromJSON Scientific where
12251763-------------------------------------------------------------------------------
12261764
12271765instance FromJSON1 DList.DList where
1228− liftParseJSON p _ = withArray "DList a" $
1766+ liftParseJSON p _ = withArray "DList" $
12291767 fmap DList.fromList .
12301768 Tr.sequence . zipWith (parseIndexedJSON p) [0..] . V.toList
12311769 {-# INLINE liftParseJSON #-}
@@ -1234,12 +1772,89 @@ instance (FromJSON a) => FromJSON (DList.DList a) where
12341772 parseJSON = parseJSON1
12351773 {-# INLINE parseJSON #-}
12361774
1775+-------------------------------------------------------------------------------
1776+-- tranformers - Functors
1777+-------------------------------------------------------------------------------
1778+
1779+instance FromJSON1 Identity where
1780+ liftParseJSON p _ a = Identity <$> p a
1781+ {-# INLINE liftParseJSON #-}
1782+
1783+ liftParseJSONList _ p a = fmap Identity <$> p a
1784+ {-# INLINE liftParseJSONList #-}
1785+
1786+instance (FromJSON a) => FromJSON (Identity a) where
1787+ parseJSON = parseJSON1
1788+ {-# INLINE parseJSON #-}
1789+
1790+ parseJSONList = liftParseJSONList parseJSON parseJSONList
1791+ {-# INLINE parseJSONList #-}
1792+
1793+instance (FromJSONKey a) => FromJSONKey (Identity a) where
1794+ fromJSONKey = coerceFromJSONKeyFunction (fromJSONKey :: FromJSONKeyFunction a)
1795+ fromJSONKeyList = coerceFromJSONKeyFunction (fromJSONKeyList :: FromJSONKeyFunction [a])
1796+
1797+
1798+instance (FromJSON1 f, FromJSON1 g) => FromJSON1 (Compose f g) where
1799+ liftParseJSON p pl a = Compose <$> liftParseJSON g gl a
1800+ where
1801+ g = liftParseJSON p pl
1802+ gl = liftParseJSONList p pl
1803+ {-# INLINE liftParseJSON #-}
1804+
1805+ liftParseJSONList p pl a = map Compose <$> liftParseJSONList g gl a
1806+ where
1807+ g = liftParseJSON p pl
1808+ gl = liftParseJSONList p pl
1809+ {-# INLINE liftParseJSONList #-}
1810+
1811+instance (FromJSON1 f, FromJSON1 g, FromJSON a) => FromJSON (Compose f g a) where
1812+ parseJSON = parseJSON1
1813+ {-# INLINE parseJSON #-}
1814+
1815+ parseJSONList = liftParseJSONList parseJSON parseJSONList
1816+ {-# INLINE parseJSONList #-}
1817+
1818+
1819+instance (FromJSON1 f, FromJSON1 g) => FromJSON1 (Product f g) where
1820+ liftParseJSON p pl a = uncurry Pair <$> liftParseJSON2 px pxl py pyl a
1821+ where
1822+ px = liftParseJSON p pl
1823+ pxl = liftParseJSONList p pl
1824+ py = liftParseJSON p pl
1825+ pyl = liftParseJSONList p pl
1826+ {-# INLINE liftParseJSON #-}
1827+
1828+instance (FromJSON1 f, FromJSON1 g, FromJSON a) => FromJSON (Product f g a) where
1829+ parseJSON = parseJSON1
1830+ {-# INLINE parseJSON #-}
1831+
1832+
1833+instance (FromJSON1 f, FromJSON1 g) => FromJSON1 (Sum f g) where
1834+ liftParseJSON p pl (Object (H.toList -> [(key, value)]))
1835+ | key == inl = InL <$> liftParseJSON p pl value <?> Key inl
1836+ | key == inr = InR <$> liftParseJSON p pl value <?> Key inl
1837+ where
1838+ inl, inr :: Text
1839+ inl = "InL"
1840+ inr = "InR"
1841+
1842+ liftParseJSON _ _ _ = fail $
1843+ "parsing Sum failed, expected an object with a single property " ++
1844+ "where the property key should be either " ++
1845+ "\"InL\" or \"InR\""
1846+ {-# INLINE liftParseJSON #-}
1847+
1848+instance (FromJSON1 f, FromJSON1 g, FromJSON a) => FromJSON (Sum f g a) where
1849+ parseJSON = parseJSON1
1850+ {-# INLINE parseJSON #-}
1851+
12371852-------------------------------------------------------------------------------
12381853-- containers
12391854-------------------------------------------------------------------------------
12401855
12411856instance FromJSON1 Seq.Seq where
1242− liftParseJSON p _ = withArray "Seq a" $
1857+ liftParseJSON p _ = withArray "Seq" $
12431858 fmap Seq.fromList .
12441859 Tr.sequence . zipWith (parseIndexedJSON p) [0..] . V.toList
12451860 {-# INLINE liftParseJSON #-}
@@ -1273,15 +1888,15 @@ instance FromJSON a => FromJSON (IntMap.IntMap a) where
12731888
12741889instance (FromJSONKey k, Ord k) => FromJSON1 (M.Map k) where
12751890 liftParseJSON p _ = case fromJSONKey of
1276− FromJSONKeyCoerce _-> withObject "Map k v" $
1891+ FromJSONKeyCoerce _ -> withObject "Map" $
12771892 fmap (H.foldrWithKey (M.insert . unsafeCoerce) M.empty) . H.traverseWithKey (\k v -> p v <?> Key k)
1278− FromJSONKeyText f -> withObject "Map k v" $
1893+ FromJSONKeyText f -> withObject "Map" $
12791894 fmap (H.foldrWithKey (M.insert . f) M.empty) . H.traverseWithKey (\k v -> p v <?> Key k)
1280− FromJSONKeyTextParser f -> withObject "Map k v" $
1281− H.foldrWithKey (\k v m -> M.insert <$> f k <*> (p v <?> Key k) <*> m) (pure M.empty)
1282− FromJSONKeyValue f -> withArray "Map k v" $ \arr ->
1283− M.fromList <$> (Tr.sequence .
1284− zipWith (parseIndexedJSONPair f p) [0..] . V.toList $ arr)
1895+ FromJSONKeyTextParser f -> withObject "Map" $
1896+ H.foldrWithKey (\k v m -> M.insert <$> f k <?> Key k <*> p v <?> Key k <*> m) (pure M.empty)
1897+ FromJSONKeyValue f -> withArray "Map" $ \arr ->
1898+ fmap M.fromList . Tr.sequence .
1899+ zipWith (parseIndexedJSONPair f p) [0..] . V.toList $ arr
12851900 {-# INLINE liftParseJSON #-}
12861901
12871902instance (FromJSONKey k, Ord k, FromJSON v) => FromJSON (M.Map k v) where
@@ -1301,12 +1916,24 @@ instance (FromJSON v) => FromJSON (Tree.Tree v) where
13011916 parseJSON = parseJSON1
13021917 {-# INLINE parseJSON #-}
13031918
1919+-------------------------------------------------------------------------------
1920+-- uuid
1921+-------------------------------------------------------------------------------
1922+
1923+instance FromJSON UUID.UUID where
1924+ parseJSON = withText "UUID" $
1925+ maybe (fail "invalid UUID") pure . UUID.fromText
1926+
1927+instance FromJSONKey UUID.UUID where
1928+ fromJSONKey = FromJSONKeyTextParser $
1929+ maybe (fail "invalid UUID") pure . UUID.fromText
1930+
13041931-------------------------------------------------------------------------------
13051932-- vector
13061933-------------------------------------------------------------------------------
13071934
13081935instance FromJSON1 Vector where
1309− liftParseJSON p _ = withArray "Vector a" $
1936+ liftParseJSON p _ = withArray "Vector" $
13101937 V.mapM (uncurry $ parseIndexedJSON p) . V.indexed
13111938 {-# INLINE liftParseJSON #-}
13121939
@@ -1320,14 +1947,14 @@ vectorParseJSON s = withArray s $ fmap V.convert . V.mapM (uncurry $ parseIndexe
13201947{-# INLINE vectorParseJSON #-}
13211948
13221949instance (Storable a, FromJSON a) => FromJSON (VS.Vector a) where
1323− parseJSON = vectorParseJSON "Data.Vector.Storable.Vector a"
1950+ parseJSON = vectorParseJSON "Data.Vector.Storable.Vector"
13241951
13251952instance (VP.Prim a, FromJSON a) => FromJSON (VP.Vector a) where
1326− parseJSON = vectorParseJSON "Data.Vector.Primitive.Vector a"
1953+ parseJSON = vectorParseJSON "Data.Vector.Primitive.Vector"
13271954 {-# INLINE parseJSON #-}
13281955
13291956instance (VG.Vector VU.Vector a, FromJSON a) => FromJSON (VU.Vector a) where
1330− parseJSON = vectorParseJSON "Data.Vector.Unboxed.Vector a"
1957+ parseJSON = vectorParseJSON "Data.Vector.Unboxed.Vector"
13311958 {-# INLINE parseJSON #-}
13321959
13331960-------------------------------------------------------------------------------
@@ -1341,15 +1968,15 @@ instance (Eq a, Hashable a, FromJSON a) => FromJSON (HashSet.HashSet a) where
13411968
13421969instance (FromJSONKey k, Eq k, Hashable k) => FromJSON1 (H.HashMap k) where
13431970 liftParseJSON p _ = case fromJSONKey of
1344− FromJSONKeyCoerce _ -> withObject "HashMap ~Text v" $
1971+ FromJSONKeyCoerce _ -> withObject "HashMap ~Text" $
13451972 uc . H.traverseWithKey (\k v -> p v <?> Key k)
1346− FromJSONKeyText f -> withObject "HashMap k v" $
1973+ FromJSONKeyText f -> withObject "HashMap" $
13471974 fmap (mapKey f) . H.traverseWithKey (\k v -> p v <?> Key k)
1348− FromJSONKeyTextParser f -> withObject "HashMap k v" $
1349− H.foldrWithKey (\k v m -> H.insert <$> f k <*> (p v <?> Key k) <*> m) (pure H.empty)
1350− FromJSONKeyValue f -> withArray "Map k v" $ \arr ->
1351− H.fromList <$> (Tr.sequence .
1352− zipWith (parseIndexedJSONPair f p) [0..] . V.toList $ arr)
1975+ FromJSONKeyTextParser f -> withObject "HashMap" $
1976+ H.foldrWithKey (\k v m -> H.insert <$> f k <?> Key k <*> p v <?> Key k <*> m) (pure H.empty)
1977+ FromJSONKeyValue f -> withArray "Map" $ \arr ->
1978+ fmap H.fromList . Tr.sequence .
1979+ zipWith (parseIndexedJSONPair f p) [0..] . V.toList $ arr
13531980 where
13541981 uc :: Parser (H.HashMap Text v) -> Parser (H.HashMap k v)
13551982 uc = unsafeCoerce
@@ -1370,11 +1997,33 @@ instance FromJSON DotNetTime where
13701997 parseJSON = withText "DotNetTime" $ \t ->
13711998 let (s,m) = T.splitAt (T.length t - 5) t
13721999 t' = T.concat [s,".",m]
1373− in case parseTime defaultTimeLocale "/Date(%s%Q)/" (unpack t') of
2000+ in case parseTimeM True defaultTimeLocale "/Date(%s%Q)/" (unpack t') of
13742001 Just d -> pure (DotNetTime d)
13752002 _ -> fail "could not parse .NET time"
13762003 {-# INLINE parseJSON #-}
13772004
2005+-------------------------------------------------------------------------------
2006+-- primitive
2007+-------------------------------------------------------------------------------
2008+
2009+instance FromJSON a => FromJSON (PM.Array a) where
2010+ -- note: we could do better than this if vector exposed the data
2011+ -- constructor in Data.Vector.
2012+ parseJSON = fmap Exts.fromList . parseJSON
2013+
2014+instance FromJSON a => FromJSON (PM.SmallArray a) where
2015+ parseJSON = fmap Exts.fromList . parseJSON
2016+
2017+#if MIN_VERSION_primitive(0,6,4)
2018+instance (PM.Prim a,FromJSON a) => FromJSON (PM.PrimArray a) where
2019+ parseJSON = fmap Exts.fromList . parseJSON
2020+
2021+#if !MIN_VERSION_primitive(0,7,0)
2022+instance (PM.PrimUnlifted a,FromJSON a) => FromJSON (PM.UnliftedArray a) where
2023+ parseJSON = fmap Exts.fromList . parseJSON
2024+#endif
2025+#endif
2026+
13782027-------------------------------------------------------------------------------
13792028-- time
13802029-------------------------------------------------------------------------------
@@ -1400,6 +2049,17 @@ instance FromJSONKey LocalTime where
14002049 fromJSONKey = FromJSONKeyTextParser (Time.run Time.localTime)
14012050
14022051
2052+-- | Supported string formats:
2053+--
2054+-- @YYYY-MM-DD HH:MM Z@
2055+-- @YYYY-MM-DD HH:MM:SS Z@
2056+-- @YYYY-MM-DD HH:MM:SS.SSS Z@
2057+--
2058+-- The first space may instead be a @T@, and the second space is
2059+-- optional. The @Z@ represents UTC. The @Z@ may be replaced with a
2060+-- time zone offset of the form @+0000@ or @-08:00@, where the first
2061+-- two digits are hours, the @:@ is optional and the second two digits
2062+-- (also optional) are minutes.
14032063instance FromJSON ZonedTime where
14042064 parseJSON = withText "ZonedTime" (Time.run Time.zonedTime)
14052065
@@ -1414,41 +2074,168 @@ instance FromJSONKey UTCTime where
14142074 fromJSONKey = FromJSONKeyTextParser (Time.run Time.utcTime)
14152075
14162076
1417−-- | /WARNING:/ Only parse lengths of time from trusted input
1418−-- since an attacker could easily fill up the memory of the target
1419−-- system by specifying a scientific number with a big exponent like
1420−-- @1e1000000000@.
2077+-- | This instance includes a bounds check to prevent maliciously
2078+-- large inputs to fill up the memory of the target system. You can
2079+-- newtype 'Scientific' and provide your own instance using
2080+-- 'withScientific' if you want to allow larger inputs.
14212081instance FromJSON NominalDiffTime where
1422− parseJSON = withScientific "NominalDiffTime" $ pure . realToFrac
2082+ parseJSON = withBoundedScientific "NominalDiffTime" $ pure . realToFrac
14232083 {-# INLINE parseJSON #-}
14242084
2085+
2086+-- | This instance includes a bounds check to prevent maliciously
2087+-- large inputs to fill up the memory of the target system. You can
2088+-- newtype 'Scientific' and provide your own instance using
2089+-- 'withScientific' if you want to allow larger inputs.
2090+instance FromJSON DiffTime where
2091+ parseJSON = withBoundedScientific "DiffTime" $ pure . realToFrac
2092+ {-# INLINE parseJSON #-}
2093+
2094+instance FromJSON SystemTime where
2095+ parseJSON v = prependContext "SystemTime" $ do
2096+ n <- parseJSON v
2097+ let n' = floor (n * fromInteger (resolution n) :: Nano)
2098+ let (secs, nano) = n' `divMod` resolution n
2099+ return (MkSystemTime (fromInteger secs) (fromInteger nano))
2100+
2101+instance FromJSON CalendarDiffTime where
2102+ parseJSON = withObject "CalendarDiffTime" $ \obj -> CalendarDiffTime
2103+ <$> obj .: "months"
2104+ <*> obj .: "time"
2105+
2106+instance FromJSON CalendarDiffDays where
2107+ parseJSON = withObject "CalendarDiffDays" $ \obj -> CalendarDiffDays
2108+ <$> obj .: "months"
2109+ <*> obj .: "days"
2110+
2111+instance FromJSON DayOfWeek where
2112+ parseJSON = withText "DaysOfWeek" parseDayOfWeek
2113+
2114+parseDayOfWeek :: T.Text -> Parser DayOfWeek
2115+parseDayOfWeek t = case T.toLower t of
2116+ "monday" -> return Monday
2117+ "tuesday" -> return Tuesday
2118+ "wednesday" -> return Wednesday
2119+ "thursday" -> return Thursday
2120+ "friday" -> return Friday
2121+ "saturday" -> return Saturday
2122+ "sunday" -> return Sunday
2123+ _ -> fail "Invalid week day"
2124+
2125+instance FromJSONKey DayOfWeek where
2126+ fromJSONKey = FromJSONKeyTextParser parseDayOfWeek
2127+
14252128-------------------------------------------------------------------------------
14262129-- base Monoid/Semigroup
14272130-------------------------------------------------------------------------------
14282131
1429−instance FromJSON1 Dual where
1430− liftParseJSON p _ = fmap Dual . p
2132+instance FromJSON1 Monoid.Dual where
2133+ liftParseJSON p _ = fmap Monoid.Dual . p
2134+ {-# INLINE liftParseJSON #-}
2135+
2136+instance FromJSON a => FromJSON (Monoid.Dual a) where
2137+ parseJSON = parseJSON1
2138+ {-# INLINE parseJSON #-}
2139+
2140+
2141+instance FromJSON1 Monoid.First where
2142+ liftParseJSON p p' = fmap Monoid.First . liftParseJSON p p'
2143+ {-# INLINE liftParseJSON #-}
2144+
2145+instance FromJSON a => FromJSON (Monoid.First a) where
2146+ parseJSON = parseJSON1
2147+ {-# INLINE parseJSON #-}
2148+
2149+
2150+instance FromJSON1 Monoid.Last where
2151+ liftParseJSON p p' = fmap Monoid.Last . liftParseJSON p p'
2152+ {-# INLINE liftParseJSON #-}
2153+
2154+instance FromJSON a => FromJSON (Monoid.Last a) where
2155+ parseJSON = parseJSON1
2156+ {-# INLINE parseJSON #-}
2157+
2158+
2159+instance FromJSON1 Semigroup.Min where
2160+ liftParseJSON p _ a = Semigroup.Min <$> p a
2161+ {-# INLINE liftParseJSON #-}
2162+
2163+ liftParseJSONList _ p a = fmap Semigroup.Min <$> p a
2164+ {-# INLINE liftParseJSONList #-}
2165+
2166+instance (FromJSON a) => FromJSON (Semigroup.Min a) where
2167+ parseJSON = parseJSON1
2168+ {-# INLINE parseJSON #-}
2169+
2170+ parseJSONList = liftParseJSONList parseJSON parseJSONList
2171+ {-# INLINE parseJSONList #-}
2172+
2173+
2174+instance FromJSON1 Semigroup.Max where
2175+ liftParseJSON p _ a = Semigroup.Max <$> p a
14312176 {-# INLINE liftParseJSON #-}
14322177
1433−instance FromJSON a => FromJSON (Dual a) where
2178+ liftParseJSONList _ p a = fmap Semigroup.Max <$> p a
2179+ {-# INLINE liftParseJSONList #-}
2180+
2181+instance (FromJSON a) => FromJSON (Semigroup.Max a) where
14342182 parseJSON = parseJSON1
14352183 {-# INLINE parseJSON #-}
14362184
2185+ parseJSONList = liftParseJSONList parseJSON parseJSONList
2186+ {-# INLINE parseJSONList #-}
2187+
14372188
1438−instance FromJSON1 First where
1439− liftParseJSON p p' = fmap First . liftParseJSON p p'
2189+instance FromJSON1 Semigroup.First where
2190+ liftParseJSON p _ a = Semigroup.First <$> p a
14402191 {-# INLINE liftParseJSON #-}
14412192
1442−instance FromJSON a => FromJSON (First a) where
2193+ liftParseJSONList _ p a = fmap Semigroup.First <$> p a
2194+ {-# INLINE liftParseJSONList #-}
2195+
2196+instance (FromJSON a) => FromJSON (Semigroup.First a) where
14432197 parseJSON = parseJSON1
14442198 {-# INLINE parseJSON #-}
14452199
2200+ parseJSONList = liftParseJSONList parseJSON parseJSONList
2201+ {-# INLINE parseJSONList #-}
2202+
14462203
1447−instance FromJSON1 Last where
1448− liftParseJSON p p' = fmap Last . liftParseJSON p p'
2204+instance FromJSON1 Semigroup.Last where
2205+ liftParseJSON p _ a = Semigroup.Last <$> p a
14492206 {-# INLINE liftParseJSON #-}
14502207
1451−instance FromJSON a => FromJSON (Last a) where
2208+ liftParseJSONList _ p a = fmap Semigroup.Last <$> p a
2209+ {-# INLINE liftParseJSONList #-}
2210+
2211+instance (FromJSON a) => FromJSON (Semigroup.Last a) where
2212+ parseJSON = parseJSON1
2213+ {-# INLINE parseJSON #-}
2214+
2215+ parseJSONList = liftParseJSONList parseJSON parseJSONList
2216+ {-# INLINE parseJSONList #-}
2217+
2218+
2219+instance FromJSON1 Semigroup.WrappedMonoid where
2220+ liftParseJSON p _ a = Semigroup.WrapMonoid <$> p a
2221+ {-# INLINE liftParseJSON #-}
2222+
2223+ liftParseJSONList _ p a = fmap Semigroup.WrapMonoid <$> p a
2224+ {-# INLINE liftParseJSONList #-}
2225+
2226+instance (FromJSON a) => FromJSON (Semigroup.WrappedMonoid a) where
2227+ parseJSON = parseJSON1
2228+ {-# INLINE parseJSON #-}
2229+
2230+ parseJSONList = liftParseJSONList parseJSON parseJSONList
2231+ {-# INLINE parseJSONList #-}
2232+
2233+
2234+instance FromJSON1 Semigroup.Option where
2235+ liftParseJSON p p' = fmap Semigroup.Option . liftParseJSON p p'
2236+ {-# INLINE liftParseJSON #-}
2237+
2238+instance FromJSON a => FromJSON (Semigroup.Option a) where
14522239 parseJSON = parseJSON1
14532240 {-# INLINE parseJSON #-}
14542241
@@ -1456,11 +2243,21 @@ instance FromJSON a => FromJSON (Last a) where
14562243-- tagged
14572244-------------------------------------------------------------------------------
14582245
2246+instance FromJSON1 Proxy where
2247+ {-# INLINE liftParseJSON #-}
2248+ liftParseJSON _ _ = fromNull "Proxy" Proxy
2249+
14592250instance FromJSON (Proxy a) where
14602251 {-# INLINE parseJSON #-}
1461− parseJSON Null = pure Proxy
1462− parseJSON v = typeMismatch "Proxy" v
2252+ parseJSON = fromNull "Proxy" Proxy
2253+
2254+fromNull :: String -> a -> Value -> Parser a
2255+fromNull _ a Null = pure a
2256+fromNull c _ v = prependContext c (typeMismatch "Null" v)
14632257
2258+instance FromJSON2 Tagged where
2259+ liftParseJSON2 _ _ p _ = fmap Tagged . p
2260+ {-# INLINE liftParseJSON2 #-}
14642261
14652262instance FromJSON1 (Tagged a) where
14662263 liftParseJSON p _ = fmap Tagged . p
@@ -1483,23 +2280,17 @@ instance (FromJSON a, FromJSON b, FromJSON c) => FromJSONKey (a,b,c)
14832280instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d) => FromJSONKey (a,b,c,d)
14842281
14852282instance FromJSONKey Char where
1486− fromJSONKey = FromJSONKeyTextParser $ \t ->
1487− if T.length t == 1
1488− then return (T.index t 0)
1489− else typeMismatch "Expected Char but String didn't contain exactly one character" (String t)
2283+ fromJSONKey = FromJSONKeyTextParser parseChar
14902284 fromJSONKeyList = FromJSONKeyText T.unpack
14912285
14922286instance (FromJSONKey a, FromJSON a) => FromJSONKey [a] where
14932287 fromJSONKey = fromJSONKeyList
14942288
1495−instance (FromJSONKey a, FromJSON a) => FromJSONKey (Identity a) where
1496− fromJSONKey = mapFromJSONKeyFunction Identity fromJSONKey
1497−
14982289-------------------------------------------------------------------------------
14992290-- Tuple instances, see tuple-instances-from.hs
15002291-------------------------------------------------------------------------------
15012292
1502−instance FromJSON2 ((,) ) where
2293+instance FromJSON2 (,) where
15032294 liftParseJSON2 pA _ pB _ = withArray "(a, b)" $ \t ->
15042295 let n = V.length t
15052296 in if n == 2
Data/Aeson/Types/Generic.hs+35−22
@@ -1,13 +1,14 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE DataKinds #-}
3−{-# LANGUAGE EmptyDataDecls #-}
4−{-# LANGUAGE FlexibleInstances #-}
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE DeriveFunctor #-}
4+{-# LANGUAGE EmptyDataDecls #-}
5+{-# LANGUAGE FlexibleInstances #-}
56{-# LANGUAGE FunctionalDependencies #-}
6−{-# LANGUAGE KindSignatures #-}
7−{-# LANGUAGE MultiParamTypeClasses #-}
8−{-# LANGUAGE ScopedTypeVariables #-}
9−{-# LANGUAGE TypeOperators #-}
10−{-# LANGUAGE UndecidableInstances #-}
7+{-# LANGUAGE KindSignatures #-}
8+{-# LANGUAGE NoImplicitPrelude #-}
9+{-# LANGUAGE ScopedTypeVariables #-}
10+{-# LANGUAGE TypeOperators #-}
11+{-# LANGUAGE UndecidableInstances #-}
1112
1213#include "overlapping-compat.h"
1314
@@ -23,20 +24,29 @@
2324--
2425-- Helpers for generic derivations.
2526
26−module Data.Aeson.Types.Generic where
27+module Data.Aeson.Types.Generic
28+ (
29+ IsRecord
30+ , AllNullary
31+ , Tagged2(..)
32+ , True
33+ , False
34+ , And
35+ , Zero
36+ , One
37+ , ProductSize(..)
38+ , (:*)(..)
39+ ) where
40+
41+import Prelude.Compat
2742
2843import GHC.Generics
29−import Data.Proxy (Proxy (..))
3044
3145--------------------------------------------------------------------------------
3246
3347class IsRecord (f :: * -> *) isRecord | f -> isRecord
34− where
35− isUnary :: f a -> Bool
36− isUnary = const True
3748
3849instance (IsRecord f isRecord) => IsRecord (f :*: g) isRecord
39− where isUnary = const False
4050#if MIN_VERSION_base(4,9,0)
4151instance OVERLAPPING_ IsRecord (M1 S ('MetaSel 'Nothing u ss ds) f) False
4252#else
@@ -45,9 +55,9 @@ instance OVERLAPPING_ IsRecord (M1 S NoSelector f) False
4555instance (IsRecord f isRecord) => IsRecord (M1 S c f) isRecord
4656instance IsRecord (K1 i c) True
4757instance IsRecord Par1 True
58+instance IsRecord (Rec1 f) True
4859instance IsRecord (f :.: g) True
4960instance IsRecord U1 False
50− where isUnary = const False
5161
5262--------------------------------------------------------------------------------
5363
@@ -62,9 +72,11 @@ instance AllNullary (a :*: b) False
6272instance AllNullary (a :.: b) False
6373instance AllNullary (K1 i c) False
6474instance AllNullary Par1 False
75+instance AllNullary (Rec1 f) False
6576instance AllNullary U1 True
6677
6778newtype Tagged2 (s :: * -> *) b = Tagged2 {unTagged2 :: b}
79+ deriving Functor
6880
6981--------------------------------------------------------------------------------
7082
@@ -86,12 +98,6 @@ data Zero
8698-- | A type-level indicator that 'ToJSON1' or 'FromJSON1' is being derived generically.
8799data One
88100
89−proxyZero :: Proxy Zero
90−proxyZero = Proxy
91−
92−proxyOne :: Proxy One
93−proxyOne = Proxy
94−
95101--------------------------------------------------------------------------------
96102
97103class ProductSize f where
@@ -103,3 +109,10 @@ instance (ProductSize a, ProductSize b) => ProductSize (a :*: b) where
103109
104110instance ProductSize (S1 s a) where
105111 productSize = Tagged2 1
112+
113+--------------------------------------------------------------------------------
114+
115+-- | Simple extensible tuple type to simplify passing around many parameters.
116+data a :* b = a :* b
117+
118+infixr 1 :*
Data/Aeson/Types/Internal.hs+195−32
@@ -1,5 +1,9 @@
1−{-# LANGUAGE CPP, DeriveDataTypeable, GeneralizedNewtypeDeriving, Rank2Types,
2− RecordWildCards #-}
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DeriveDataTypeable #-}
3+{-# LANGUAGE DeriveGeneric #-}
4+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5+{-# LANGUAGE NoImplicitPrelude #-}
6+{-# LANGUAGE Rank2Types #-}
37#if __GLASGOW_HASKELL__ >= 800
48-- a) THQ works on cross-compilers and unregisterised GHCs
59-- b) may make compilation faster as no dynamic loading is ever needed (not sure about this)
@@ -41,16 +45,33 @@ module Data.Aeson.Types.Internal
4145 , parseEither
4246 , parseMaybe
4347 , modifyFailure
48+ , prependFailure
49+ , parserThrowError
50+ , parserCatchError
4451 , formatError
52+ , formatPath
53+ , formatRelativePath
4554 , (<?>)
4655 -- * Constructors and accessors
4756 , object
4857
4958 -- * Generic and TH encoding configuration
50− , Options(..)
59+ , Options(
60+ fieldLabelModifier
61+ , constructorTagModifier
62+ , allNullaryToStringTag
63+ , omitNothingFields
64+ , sumEncoding
65+ , unwrapUnaryRecords
66+ , tagSingleConstructors
67+ , rejectUnknownFields
68+ )
69+
5170 , SumEncoding(..)
71+ , JSONKeyOptions(keyModifier)
5272 , defaultOptions
5373 , defaultTaggedObject
74+ , defaultJSONKeyOptions
5475
5576 -- * Used for changing CamelCase names into something else.
5677 , camelTo
@@ -60,35 +81,34 @@ module Data.Aeson.Types.Internal
6081 , DotNetTime(..)
6182 ) where
6283
84+import Prelude.Compat
85+
86+import Control.Applicative (Alternative(..))
6387import Control.Arrow (first)
64−import Control.Applicative
6588import Control.DeepSeq (NFData(..))
6689import Control.Monad (MonadPlus(..), ap)
67−import qualified Control.Monad.Fail as Fail
6890import Data.Char (isLower, isUpper, toLower, isAlpha, isAlphaNum)
6991import Data.Data (Data)
7092import Data.Foldable (foldl')
7193import Data.HashMap.Strict (HashMap)
7294import Data.Hashable (Hashable(..))
73−import Data.Semigroup (Semigroup((<>)))
95+import Data.List (intercalate)
7496import Data.Scientific (Scientific)
97+import Data.Semigroup (Semigroup((<>)))
7598import Data.String (IsString(..))
7699import Data.Text (Text, pack, unpack)
77100import Data.Time (UTCTime)
78101import Data.Time.Format (FormatTime)
79102import Data.Typeable (Typeable)
80103import Data.Vector (Vector)
104+import GHC.Generics (Generic)
105+import qualified Control.Monad as Monad
106+import qualified Control.Monad.Fail as Fail
81107import qualified Data.HashMap.Strict as H
82108import qualified Data.Scientific as S
83109import qualified Data.Vector as V
84110import qualified Language.Haskell.TH.Syntax as TH
85111
86−#if !MIN_VERSION_base(4,8,0)
87−import Data.Foldable (Foldable(..))
88−import Data.Monoid (Monoid(..))
89−import Data.Traversable (Traversable(..))
90−#endif
91−
92112#if !MIN_VERSION_unordered_containers(0,2,6)
93113import Data.List (sort)
94114#endif
@@ -101,7 +121,7 @@ data JSONPathElement = Key Text
101121 | Index {-# UNPACK #-} !Int
102122 -- ^ JSON path element of an index into an
103123 -- array, \"array[index]\".
104− deriving (Eq, Show, Typeable)
124+ deriving (Eq, Show, Typeable, Ord)
105125type JSONPath = [JSONPathElement]
106126
107127-- | The internal result of running a 'Parser'.
@@ -136,7 +156,7 @@ instance Functor Result where
136156 fmap _ (Error err) = Error err
137157 {-# INLINE fmap #-}
138158
139−instance Monad IResult where
159+instance Monad.Monad IResult where
140160 return = pure
141161 {-# INLINE return #-}
142162
@@ -144,14 +164,16 @@ instance Monad IResult where
144164 IError path err >>= _ = IError path err
145165 {-# INLINE (>>=) #-}
146166
167+#if !(MIN_VERSION_base(4,13,0))
147168 fail = Fail.fail
148169 {-# INLINE fail #-}
170+#endif
149171
150172instance Fail.MonadFail IResult where
151173 fail err = IError [] err
152174 {-# INLINE fail #-}
153175
154−instance Monad Result where
176+instance Monad.Monad Result where
155177 return = pure
156178 {-# INLINE return #-}
157179
@@ -159,8 +181,10 @@ instance Monad Result where
159181 Error err >>= _ = Error err
160182 {-# INLINE (>>=) #-}
161183
184+#if !(MIN_VERSION_base(4,13,0))
162185 fail = Fail.fail
163186 {-# INLINE fail #-}
187+#endif
164188
165189instance Fail.MonadFail Result where
166190 fail err = Error err
@@ -257,7 +281,9 @@ type Failure f r = JSONPath -> String -> f r
257281-- | Success continuation.
258282type Success a f r = a -> f r
259283
260−-- | A JSON parser.
284+-- | A JSON parser. N.B. This might not fit your usual understanding of
285+-- "parser". Instead you might like to think of 'Parser' as a "parse result",
286+-- i.e. a parser to which the input has already been applied.
261287newtype Parser a = Parser {
262288 runParser :: forall f r.
263289 JSONPath
@@ -266,14 +292,17 @@ newtype Parser a = Parser {
266292 -> f r
267293 }
268294
269−instance Monad Parser where
295+instance Monad.Monad Parser where
270296 m >>= g = Parser $ \path kf ks -> let ks' a = runParser (g a) path kf ks
271297 in runParser m path kf ks'
272298 {-# INLINE (>>=) #-}
273299 return = pure
274300 {-# INLINE return #-}
301+
302+#if !(MIN_VERSION_base(4,13,0))
275303 fail = Fail.fail
276304 {-# INLINE fail #-}
305+#endif
277306
278307instance Fail.MonadFail Parser where
279308 fail msg = Parser $ \path kf _ks -> kf (reverse path) msg
@@ -316,8 +345,7 @@ instance Monoid (Parser a) where
316345apP :: Parser (a -> b) -> Parser a -> Parser b
317346apP d e = do
318347 b <- d
319− a <- e
320− return (b a)
348+ b <$> e
321349{-# INLINE apP #-}
322350
323351-- | A JSON \"object\" (key\/value map).
@@ -333,7 +361,7 @@ data Value = Object !Object
333361 | Number !Scientific
334362 | Bool !Bool
335363 | Null
336− deriving (Eq, Read, Show, Typeable, Data)
364+ deriving (Eq, Read, Show, Typeable, Data, Generic)
337365
338366-- | A newtype wrapper for 'UTCTime' that uses the same non-standard
339367-- serialization format as Microsoft .NET, whose
@@ -433,7 +461,17 @@ parseEither m v = runParser (m v) [] onError Right
433461-- | Annotate an error message with a
434462-- <http://goessner.net/articles/JsonPath/ JSONPath> error location.
435463formatError :: JSONPath -> String -> String
436−formatError path msg = "Error in " ++ (format "$" path) ++ ": " ++ msg
464+formatError path msg = "Error in " ++ formatPath path ++ ": " ++ msg
465+
466+-- | Format a <http://goessner.net/articles/JsonPath/ JSONPath> as a 'String',
467+-- representing the root object as @$@.
468+formatPath :: JSONPath -> String
469+formatPath path = "$" ++ formatRelativePath path
470+
471+-- | Format a <http://goessner.net/articles/JsonPath/ JSONPath> as a 'String'
472+-- which represents the path relative to some root object.
473+formatRelativePath :: JSONPath -> String
474+formatRelativePath path = format "" path
437475 where
438476 format :: String -> JSONPath -> String
439477 format pfx [] = pfx
@@ -496,13 +534,40 @@ p <?> pathElem = Parser $ \path kf ks -> runParser p (pathElem:path) kf ks
496534--
497535-- Since 0.6.2.0
498536modifyFailure :: (String -> String) -> Parser a -> Parser a
499−modifyFailure f (Parser p) = Parser $ \path kf ks -> p path (\p' m -> kf p' (f m)) ks
537+modifyFailure f (Parser p) = Parser $ \path kf ks ->
538+ p path (\p' m -> kf p' (f m)) ks
539+
540+-- | If the inner 'Parser' failed, prepend the given string to the failure
541+-- message.
542+--
543+-- @
544+-- 'prependFailure' s = 'modifyFailure' (s '++')
545+-- @
546+prependFailure :: String -> Parser a -> Parser a
547+prependFailure = modifyFailure . (++)
548+
549+-- | Throw a parser error with an additional path.
550+--
551+-- @since 1.2.1.0
552+parserThrowError :: JSONPath -> String -> Parser a
553+parserThrowError path' msg = Parser $ \path kf _ks ->
554+ kf (reverse path ++ path') msg
555+
556+-- | A handler function to handle previous errors and return to normal execution.
557+--
558+-- @since 1.2.1.0
559+parserCatchError :: Parser a -> (JSONPath -> String -> Parser a) -> Parser a
560+parserCatchError (Parser p) handler = Parser $ \path kf ks ->
561+ p path (\e msg -> runParser (handler e msg) path kf ks) ks
500562
501563--------------------------------------------------------------------------------
502564-- Generic and TH encoding configuration
503565--------------------------------------------------------------------------------
504566
505567-- | Options that specify how to encode\/decode your datatype to\/from JSON.
568+--
569+-- Options can be set using record syntax on 'defaultOptions' with the fields
570+-- below.
506571data Options = Options
507572 { fieldLabelModifier :: String -> String
508573 -- ^ Function applied to field labels.
@@ -519,24 +584,67 @@ data Options = Options
519584 -- ^ If 'True' record fields with a 'Nothing' value will be
520585 -- omitted from the resulting object. If 'False' the resulting
521586 -- object will include those fields mapping to @null@.
587+ --
588+ -- === Note
589+ --
590+ -- Setting 'omitNothingFields' to 'True' only affects fields which are of
591+ -- type 'Maybe' /uniformly/ in the 'ToJSON' or 'FromJSON' instance. In
592+ -- particular, if the type of a field is declared as a type variable, it
593+ -- will not be omitted from the JSON object, unless the field is
594+ -- specialized upfront in the instance.
595+ --
596+ -- ==== __Example__
597+ --
598+ -- The generic instance for the following type @Fruit@ depends on whether
599+ -- the instance head is @Fruit a@ or @Fruit (Maybe a)@.
600+ --
601+ -- @
602+ -- data Fruit a =
603+ -- { apples :: a -- A field whose type is a type variable.
604+ -- , oranges :: 'Maybe' Int
605+ -- }
606+ --
607+ -- options :: 'Options'
608+ -- options = 'defaultOptions' { 'omitNothingFields' = 'True' }
609+ --
610+ -- -- apples required, oranges optional
611+ -- -- Even if 'Data.Aeson.fromJSON' is then specialized to (Fruit ('Maybe' a)).
612+ -- instance 'Data.Aeson.FromJSON' a => 'Data.Aeson.FromJSON' (Fruit a) where
613+ -- 'Data.Aeson.fromJSON' = 'Data.Aeson.genericFromJSON' options
614+ --
615+ -- -- apples optional, oranges optional
616+ -- -- In this instance, the field apples is uniformly of type ('Maybe' a).
617+ -- instance 'Data.Aeson.FromJSON' a => 'Data.Aeson.FromJSON' (Fruit ('Maybe' a)) where
618+ -- 'Data.Aeson.fromJSON' = 'Data.Aeson.genericFromJSON' options
619+ -- @
522620 , sumEncoding :: SumEncoding
523621 -- ^ Specifies how to encode constructors of a sum datatype.
524622 , unwrapUnaryRecords :: Bool
525623 -- ^ Hide the field name when a record constructor has only one
526624 -- field, like a newtype.
625+ , tagSingleConstructors :: Bool
626+ -- ^ Encode types with a single constructor as sums,
627+ -- so that `allNullaryToStringTag` and `sumEncoding` apply.
628+ , rejectUnknownFields :: Bool
629+ -- ^ Applies only to 'Data.Aeson.FromJSON' instances. If a field appears in
630+ -- the parsed object map, but does not appear in the target object, parsing
631+ -- will fail, with an error message indicating which fields were unknown.
527632 }
528633
529634instance Show Options where
530− show Options{..} = "Options {" ++
531− "fieldLabelModifier =~ " ++
532− show (fieldLabelModifier "exampleField") ++ ", " ++
533− "constructorTagModifier =~ " ++
534− show (constructorTagModifier "ExampleConstructor") ++ ", " ++
535− "allNullaryToStringTag = " ++ show allNullaryToStringTag ++ ", " ++
536− "omitNothingFields = " ++ show omitNothingFields ++ ", " ++
537− "sumEncoding = " ++ show sumEncoding ++ ", " ++
538− "unwrapUnaryRecords = " ++ show unwrapUnaryRecords ++
539− "}"
635+ show (Options f c a o s u t r) =
636+ "Options {"
637+ ++ intercalate ", "
638+ [ "fieldLabelModifier =~ " ++ show (f "exampleField")
639+ , "constructorTagModifier =~ " ++ show (c "ExampleConstructor")
640+ , "allNullaryToStringTag = " ++ show a
641+ , "omitNothingFields = " ++ show o
642+ , "sumEncoding = " ++ show s
643+ , "unwrapUnaryRecords = " ++ show u
644+ , "tagSingleConstructors = " ++ show t
645+ , "rejectUnknownFields = " ++ show r
646+ ]
647+ ++ "}"
540648
541649-- | Specifies how to encode constructors of a sum datatype.
542650data SumEncoding =
@@ -552,6 +660,20 @@ data SumEncoding =
552660 -- by the encoded value of that field! If the constructor is not a
553661 -- record the encoded constructor contents will be stored under
554662 -- the 'contentsFieldName' field.
663+ | UntaggedValue
664+ -- ^ Constructor names won't be encoded. Instead only the contents of the
665+ -- constructor will be encoded as if the type had a single constructor. JSON
666+ -- encodings have to be disjoint for decoding to work properly.
667+ --
668+ -- When decoding, constructors are tried in the order of definition. If some
669+ -- encodings overlap, the first one defined will succeed.
670+ --
671+ -- /Note:/ Nullary constructors are encoded as strings (using
672+ -- 'constructorTagModifier'). Having a nullary constructor alongside a
673+ -- single field constructor that encodes to a string leads to ambiguity.
674+ --
675+ -- /Note:/ Only the last error is kept when decoding, so in the case of
676+ -- malformed JSON, only an error for the last constructor will be reported.
555677 | ObjectWithSingleField
556678 -- ^ A constructor will be encoded to an object with a single
557679 -- field named after the constructor tag (modified by the
@@ -564,6 +686,33 @@ data SumEncoding =
564686 -- contents of the constructor.
565687 deriving (Eq, Show)
566688
689+-- | Options for encoding keys with 'Data.Aeson.Types.genericFromJSONKey' and
690+-- 'Data.Aeson.Types.genericToJSONKey'.
691+data JSONKeyOptions = JSONKeyOptions
692+ { keyModifier :: String -> String
693+ -- ^ Function applied to keys. Its result is what goes into the encoded
694+ -- 'Value'.
695+ --
696+ -- === __Example__
697+ --
698+ -- The following instances encode the constructor @Bar@ to lower-case keys
699+ -- @\"bar\"@.
700+ --
701+ -- @
702+ -- data Foo = Bar
703+ -- deriving 'Generic'
704+ --
705+ -- opts :: 'JSONKeyOptions'
706+ -- opts = 'defaultJSONKeyOptions' { 'keyModifier' = 'toLower' }
707+ --
708+ -- instance 'ToJSONKey' Foo where
709+ -- 'toJSONKey' = 'genericToJSONKey' opts
710+ --
711+ -- instance 'FromJSONKey' Foo where
712+ -- 'fromJSONKey' = 'genericFromJSONKey' opts
713+ -- @
714+ }
715+
567716-- | Default encoding 'Options':
568717--
569718-- @
@@ -574,6 +723,8 @@ data SumEncoding =
574723-- , 'omitNothingFields' = False
575724-- , 'sumEncoding' = 'defaultTaggedObject'
576725-- , 'unwrapUnaryRecords' = False
726+-- , 'tagSingleConstructors' = False
727+-- , 'rejectUnknownFields' = False
577728-- }
578729-- @
579730defaultOptions :: Options
@@ -584,6 +735,8 @@ defaultOptions = Options
584735 , omitNothingFields = False
585736 , sumEncoding = defaultTaggedObject
586737 , unwrapUnaryRecords = False
738+ , tagSingleConstructors = False
739+ , rejectUnknownFields = False
587740 }
588741
589742-- | Default 'TaggedObject' 'SumEncoding' options:
@@ -600,6 +753,16 @@ defaultTaggedObject = TaggedObject
600753 , contentsFieldName = "contents"
601754 }
602755
756+-- | Default 'JSONKeyOptions':
757+--
758+-- @
759+-- defaultJSONKeyOptions = 'JSONKeyOptions'
760+-- { 'keyModifier' = 'id'
761+-- }
762+-- @
763+defaultJSONKeyOptions :: JSONKeyOptions
764+defaultJSONKeyOptions = JSONKeyOptions id
765+
603766-- | Converts from CamelCase to another lower case, interspersing
604767-- the character between all capital letters and their previous
605768-- entries, except those capital letters that appear together,
Data/Aeson/Types/ToJSON.hs+1184−790
@@ -1,29 +1,27 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE DataKinds #-}
3−{-# LANGUAGE DefaultSignatures #-}
4−{-# LANGUAGE FlexibleContexts #-}
5−{-# LANGUAGE FlexibleInstances #-}
6−{-# LANGUAGE GADTs #-}
7−{-# LANGUAGE MultiParamTypeClasses #-}
8−{-# LANGUAGE NamedFieldPuns #-}
9−{-# LANGUAGE OverloadedStrings #-}
10−{-# LANGUAGE PatternGuards #-}
11−{-# LANGUAGE RecordWildCards #-}
12−{-# LANGUAGE ScopedTypeVariables #-}
13−{-# LANGUAGE TypeOperators #-}
14−{-# LANGUAGE TypeSynonymInstances #-}
15−{-# LANGUAGE UndecidableInstances #-}
16−
17−#if __GLASGOW_HASKELL__ >= 706
18−{-# LANGUAGE PolyKinds #-}
19−#endif
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DefaultSignatures #-}
3+{-# LANGUAGE EmptyDataDecls #-}
4+{-# LANGUAGE FlexibleContexts #-}
5+{-# LANGUAGE FlexibleInstances #-}
6+{-# LANGUAGE FunctionalDependencies #-}
7+{-# LANGUAGE GADTs #-}
8+{-# LANGUAGE NoImplicitPrelude #-}
9+{-# LANGUAGE OverloadedStrings #-}
10+{-# LANGUAGE PatternGuards #-}
11+{-# LANGUAGE PolyKinds #-}
12+{-# LANGUAGE RecordWildCards #-}
13+{-# LANGUAGE ScopedTypeVariables #-}
14+{-# LANGUAGE TypeOperators #-}
15+{-# LANGUAGE UndecidableInstances #-}
2016
2117#include "overlapping-compat.h"
18+#include "incoherent-compat.h"
2219
2320-- TODO: Drop this when we remove support for Data.Attoparsec.Number
2421{-# OPTIONS_GHC -fno-warn-deprecations #-}
2522
26−module Data.Aeson.Types.ToJSON (
23+module Data.Aeson.Types.ToJSON
24+ (
2725 -- * Core JSON classes
2826 ToJSON(..)
2927 -- * Liftings to unary and binary type constructors
@@ -35,7 +33,7 @@ module Data.Aeson.Types.ToJSON (
3533 , toEncoding2
3634 -- * Generic JSON classes
3735 , GToJSON(..)
38− , GToEncoding(..)
36+ , ToArgs(..)
3937 , genericToJSON
4038 , genericToEncoding
4139 , genericLiftToJSON
@@ -43,77 +41,104 @@ module Data.Aeson.Types.ToJSON (
4341 -- * Classes and types for map keys
4442 , ToJSONKey(..)
4543 , ToJSONKeyFunction(..)
44+ , toJSONKeyText
4645 , contramapToJSONKeyFunction
46+
47+ , GToJSONKey()
48+ , genericToJSONKey
49+
4750 -- * Object key-value pairs
4851 , KeyValue(..)
52+ , KeyValuePair(..)
53+ , FromPairs(..)
4954 -- * Functions needed for documentation
5055 -- * Encoding functions
5156 , listEncoding
5257 , listValue
5358 ) where
5459
55−import Prelude ()
5660import Prelude.Compat
5761
58−import Data.Aeson.Encoding.Internal (Encoding (..), Series, dict, emptyArray_,
59− tuple, (>*<))
62+import Control.Applicative (Const(..))
63+import Control.Monad.ST (ST)
64+import Data.Aeson.Encoding (Encoding, Encoding', Series, dict, emptyArray_)
65+import Data.Aeson.Encoding.Internal ((>*<))
6066import Data.Aeson.Internal.Functions (mapHashKeyVal, mapKeyVal)
61−import Data.Aeson.Types.Generic
67+import Data.Aeson.Types.Generic (AllNullary, False, IsRecord, One, ProductSize, Tagged2(..), True, Zero, productSize)
6268import Data.Aeson.Types.Internal
63−
64−-- We need internal here for generic deriving
65−import qualified Data.Aeson.Encoding.Internal as E
66−
67−import Control.Applicative (Const (..))
68−import Control.Monad.ST (ST)
69−import Data.Attoparsec.Number (Number (..))
70−import Data.Bits (unsafeShiftR)
71−import Data.DList (DList)
72−import Data.Fixed (Fixed, HasResolution)
73−import Data.Foldable (toList)
74−import Data.Functor.Identity (Identity (..))
75−import Data.Int (Int16, Int32, Int64, Int8)
76−import Data.List (intersperse)
77−import Data.List.NonEmpty (NonEmpty (..))
78−import Data.Monoid (Dual (..), First (..), Last (..), (<>))
79−import Data.Proxy (Proxy (..))
80−import Data.Ratio (Ratio, denominator, numerator)
81−import Data.Scientific (Scientific)
82−import Data.Tagged (Tagged (..))
83−import Data.Text (Text, pack)
84−import Data.Time (Day, LocalTime, NominalDiffTime, TimeOfDay,
85− UTCTime, ZonedTime)
86−import Data.Time.Format (FormatTime, formatTime)
87−import Data.Time.Locale.Compat (defaultTimeLocale)
88−import Data.Vector (Vector)
89−import Data.Version (Version, showVersion)
90−import Data.Word (Word16, Word32, Word64, Word8)
91−import Foreign.Storable (Storable)
69+import Data.Attoparsec.Number (Number(..))
70+import Data.Bits (unsafeShiftR)
71+import Data.DList (DList)
72+import Data.Fixed (Fixed, HasResolution, Nano)
73+import Data.Foldable (toList)
74+import Data.Functor.Compose (Compose(..))
75+import Data.Functor.Contravariant (Contravariant (..))
76+import Data.Functor.Identity (Identity(..))
77+import Data.Functor.Product (Product(..))
78+import Data.Functor.Sum (Sum(..))
79+import Data.Int (Int16, Int32, Int64, Int8)
80+import Data.List (intersperse)
81+import Data.List.NonEmpty (NonEmpty(..))
82+import Data.Semigroup ((<>))
83+import Data.Proxy (Proxy(..))
84+import Data.Ratio (Ratio, denominator, numerator)
85+import Data.Scientific (Scientific)
86+import Data.Tagged (Tagged(..))
87+import Data.Text (Text, pack)
88+import Data.Time (Day, DiffTime, LocalTime, NominalDiffTime, TimeOfDay, UTCTime, ZonedTime)
89+import Data.Time.Calendar.Compat (CalendarDiffDays (..), DayOfWeek (..))
90+import Data.Time.LocalTime.Compat (CalendarDiffTime (..))
91+import Data.Time.Clock.System.Compat (SystemTime (..))
92+import Data.Time.Format.Compat (FormatTime, formatTime, defaultTimeLocale)
93+import Data.Vector (Vector)
94+import Data.Version (Version, showVersion)
95+import Data.Void (Void, absurd)
96+import Data.Word (Word16, Word32, Word64, Word8)
97+import Foreign.Storable (Storable)
98+import Foreign.C.Types (CTime (..))
9299import GHC.Generics
93−import Numeric.Natural (Natural)
94−
95−import qualified Data.ByteString.Builder as B (toLazyByteString)
96−import qualified Data.ByteString.Lazy as L
97−import qualified Data.DList as DList
98−import qualified Data.HashMap.Strict as H
99−import qualified Data.HashSet as HashSet
100−import qualified Data.IntMap as IntMap
101−import qualified Data.IntSet as IntSet
102−import qualified Data.List.NonEmpty as NE
103−import qualified Data.Map as M
104−import qualified Data.Scientific as Scientific
105−import qualified Data.Sequence as Seq
106−import qualified Data.Set as Set
107−import qualified Data.Text as T
108−import qualified Data.Text.Encoding as T
109−import qualified Data.Text.Lazy as LT
110−import qualified Data.Tree as Tree
111−import qualified Data.Vector as V
112−import qualified Data.Vector.Generic as VG
113−import qualified Data.Vector.Mutable as VM
114−import qualified Data.Vector.Primitive as VP
115−import qualified Data.Vector.Storable as VS
116−import qualified Data.Vector.Unboxed as VU
100+import Numeric.Natural (Natural)
101+import qualified Data.Aeson.Encoding as E
102+import qualified Data.Aeson.Encoding.Internal as E (InArray, comma, econcat, retagEncoding)
103+import qualified Data.ByteString.Lazy as L
104+import qualified Data.DList as DList
105+import qualified Data.HashMap.Strict as H
106+import qualified Data.HashSet as HashSet
107+import qualified Data.IntMap as IntMap
108+import qualified Data.IntSet as IntSet
109+import qualified Data.List.NonEmpty as NE
110+import qualified Data.Map as M
111+import qualified Data.Monoid as Monoid
112+import qualified Data.Scientific as Scientific
113+import qualified Data.Semigroup as Semigroup
114+import qualified Data.Sequence as Seq
115+import qualified Data.Set as Set
116+import qualified Data.Text as T
117+import qualified Data.Text.Encoding as T
118+import qualified Data.Text.Lazy as LT
119+import qualified Data.Tree as Tree
120+import qualified Data.UUID.Types as UUID
121+import qualified Data.Vector as V
122+import qualified Data.Vector.Generic as VG
123+import qualified Data.Vector.Mutable as VM
124+import qualified Data.Vector.Primitive as VP
125+import qualified Data.Vector.Storable as VS
126+import qualified Data.Vector.Unboxed as VU
127+
128+import qualified Data.Aeson.Encoding.Builder as EB
129+import qualified Data.ByteString.Builder as B
130+
131+import qualified GHC.Exts as Exts
132+import qualified Data.Primitive.Array as PM
133+import qualified Data.Primitive.SmallArray as PM
134+import qualified Data.Primitive.Types as PM
135+
136+#if MIN_VERSION_primitive(0,6,4)
137+#if !MIN_VERSION_primitive(0,7,0)
138+import qualified Data.Primitive.UnliftedArray as PM
139+#endif
140+import qualified Data.Primitive.PrimArray as PM
141+#endif
117142
118143toJSONPair :: (a -> Value) -> (b -> Value) -> (a, b) -> Value
119144toJSONPair a b = liftToJSON2 a (listValue a) b (listValue b)
@@ -131,51 +156,53 @@ realFloatToJSON d
131156
132157-- | Class of generic representation types that can be converted to
133158-- JSON.
134−class GToJSON arity f where
159+class GToJSON enc arity f where
135160 -- | This method (applied to 'defaultOptions') is used as the
136− -- default generic implementation of 'toJSON' (if the @arity@ is 'Zero')
137− -- or 'liftToJSON' (if the @arity@ is 'One').
138− gToJSON :: Options -> Proxy arity
139− -> (a -> Value) -> ([a] -> Value) -> f a -> Value
140−
141−-- | Class of generic representation types that can be converted to
142−-- a JSON 'Encoding'.
143−class GToEncoding arity f where
144− -- | This method (applied to 'defaultOptions') can be used as the
145− -- default generic implementation of 'toEncoding' (if the @arity@ is 'Zero')
146− -- or 'liftToEncoding' (if the @arity@ is 'One').
147− gToEncoding :: Options -> Proxy arity
148− -> (a -> Encoding) -> ([a] -> Encoding) -> f a -> Encoding
161+ -- default generic implementation of 'toJSON'
162+ -- (with @enc ~ 'Value'@ and @arity ~ 'Zero'@)
163+ -- and 'liftToJSON' (if the @arity@ is 'One').
164+ --
165+ -- It also provides a generic implementation of 'toEncoding'
166+ -- (with @enc ~ 'Encoding'@ and @arity ~ 'Zero'@)
167+ -- and 'liftToEncoding' (if the @arity@ is 'One').
168+ gToJSON :: Options -> ToArgs enc arity a -> f a -> enc
169+
170+-- | A 'ToArgs' value either stores nothing (for 'ToJSON') or it stores the two
171+-- function arguments that encode occurrences of the type parameter (for
172+-- 'ToJSON1').
173+data ToArgs res arity a where
174+ NoToArgs :: ToArgs res Zero a
175+ To1Args :: (a -> res) -> ([a] -> res) -> ToArgs res One a
149176
150177-- | A configurable generic JSON creator. This function applied to
151178-- 'defaultOptions' is used as the default for 'toJSON' when the type
152179-- is an instance of 'Generic'.
153−genericToJSON :: (Generic a, GToJSON Zero (Rep a))
180+genericToJSON :: (Generic a, GToJSON Value Zero (Rep a))
154181 => Options -> a -> Value
155−genericToJSON opts = gToJSON opts proxyZero undefined undefined . from
182+genericToJSON opts = gToJSON opts NoToArgs . from
156183
157184-- | A configurable generic JSON creator. This function applied to
158185-- 'defaultOptions' is used as the default for 'liftToJSON' when the type
159186-- is an instance of 'Generic1'.
160−genericLiftToJSON :: (Generic1 f, GToJSON One (Rep1 f))
187+genericLiftToJSON :: (Generic1 f, GToJSON Value One (Rep1 f))
161188 => Options -> (a -> Value) -> ([a] -> Value)
162189 -> f a -> Value
163−genericLiftToJSON opts tj tjl = gToJSON opts proxyOne tj tjl . from1
190+genericLiftToJSON opts tj tjl = gToJSON opts (To1Args tj tjl) . from1
164191
165192-- | A configurable generic JSON encoder. This function applied to
166193-- 'defaultOptions' is used as the default for 'toEncoding' when the type
167194-- is an instance of 'Generic'.
168−genericToEncoding :: (Generic a, GToEncoding Zero (Rep a))
195+genericToEncoding :: (Generic a, GToJSON Encoding Zero (Rep a))
169196 => Options -> a -> Encoding
170−genericToEncoding opts = gToEncoding opts proxyZero undefined undefined . from
197+genericToEncoding opts = gToJSON opts NoToArgs . from
171198
172199-- | A configurable generic JSON encoder. This function applied to
173200-- 'defaultOptions' is used as the default for 'liftToEncoding' when the type
174201-- is an instance of 'Generic1'.
175−genericLiftToEncoding :: (Generic1 f, GToEncoding One (Rep1 f))
202+genericLiftToEncoding :: (Generic1 f, GToJSON Encoding One (Rep1 f))
176203 => Options -> (a -> Encoding) -> ([a] -> Encoding)
177204 -> f a -> Encoding
178−genericLiftToEncoding opts te tel = gToEncoding opts proxyOne te tel . from1
205+genericLiftToEncoding opts te tel = gToJSON opts (To1Args te tel) . from1
179206
180207-------------------------------------------------------------------------------
181208-- Class
@@ -183,6 +210,9 @@ genericLiftToEncoding opts te tel = gToEncoding opts proxyOne te tel . from1
183210
184211-- | A type that can be converted to JSON.
185212--
213+-- Instances in general /must/ specify 'toJSON' and /should/ (but don't need
214+-- to) specify 'toEncoding'.
215+--
186216-- An example type and instance:
187217--
188218-- @
@@ -191,10 +221,10 @@ genericLiftToEncoding opts te tel = gToEncoding opts proxyOne te tel . from1
191221--
192222-- data Coord = Coord { x :: Double, y :: Double }
193223--
194−-- instance ToJSON Coord where
195−-- toJSON (Coord x y) = 'object' [\"x\" '.=' x, \"y\" '.=' y]
224+-- instance 'ToJSON' Coord where
225+-- 'toJSON' (Coord x y) = 'object' [\"x\" '.=' x, \"y\" '.=' y]
196226--
197−-- toEncoding (Coord x y) = 'pairs' (\"x\" '.=' x '<>' \"y\" '.=' y)
227+-- 'toEncoding' (Coord x y) = 'pairs' (\"x\" '.=' x '<>' \"y\" '.=' y)
198228-- @
199229--
200230-- Instead of manually writing your 'ToJSON' instance, there are two options
@@ -202,17 +232,15 @@ genericLiftToEncoding opts te tel = gToEncoding opts proxyOne te tel . from1
202232--
203233-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
204234-- instance at compile time. The generated instance is optimized for your type
205−-- so will probably be more efficient than the following two options:
235+-- so it will probably be more efficient than the following option.
206236--
207237-- * The compiler can provide a default generic implementation for
208238-- 'toJSON'.
209239--
210240-- To use the second, simply add a @deriving 'Generic'@ clause to your
211−-- datatype and declare a 'ToJSON' instance for your datatype without giving
212−-- definitions for 'toJSON' or 'toEncoding'.
213−--
214−-- For example, the previous example can be simplified to a more
215−-- minimal instance:
241+-- datatype and declare a 'ToJSON' instance. If you require nothing other than
242+-- 'defaultOptions', it is sufficient to write (and this is the only
243+-- alternative where the default 'toJSON' implementation is sufficient):
216244--
217245-- @
218246-- {-\# LANGUAGE DeriveGeneric \#-}
@@ -221,35 +249,46 @@ genericLiftToEncoding opts te tel = gToEncoding opts proxyOne te tel . from1
221249--
222250-- data Coord = Coord { x :: Double, y :: Double } deriving 'Generic'
223251--
224−-- instance ToJSON Coord where
225−-- toEncoding = 'genericToEncoding' 'defaultOptions'
252+-- instance 'ToJSON' Coord where
253+-- 'toEncoding' = 'genericToEncoding' 'defaultOptions'
226254-- @
227255--
228−-- Why do we provide an implementation for 'toEncoding' here? The
229−-- 'toEncoding' function is a relatively new addition to this class.
230−-- To allow users of older versions of this library to upgrade without
231−-- having to edit all of their instances or encounter surprising
232−-- incompatibilities, the default implementation of 'toEncoding' uses
233−-- 'toJSON'. This produces correct results, but since it performs an
234−-- intermediate conversion to a 'Value', it will be less efficient
235−-- than directly emitting an 'Encoding'. Our one-liner definition of
236−-- 'toEncoding' above bypasses the intermediate 'Value'.
237−--
238−-- If @DefaultSignatures@ doesn't give exactly the results you want,
239−-- you can customize the generic encoding with only a tiny amount of
240−-- effort, using 'genericToJSON' and 'genericToEncoding' with your
241−-- preferred 'Options':
256+-- If on the other hand you wish to customize the generic decoding, you have
257+-- to implement both methods:
242258--
243259-- @
244−-- instance ToJSON Coord where
245−-- toJSON = 'genericToJSON' 'defaultOptions'
246−-- toEncoding = 'genericToEncoding' 'defaultOptions'
260+-- customOptions = 'defaultOptions'
261+-- { 'fieldLabelModifier' = 'map' 'Data.Char.toUpper'
262+-- }
263+--
264+-- instance 'ToJSON' Coord where
265+-- 'toJSON' = 'genericToJSON' customOptions
266+-- 'toEncoding' = 'genericToEncoding' customOptions
247267-- @
268+--
269+-- Previous versions of this library only had the 'toJSON' method. Adding
270+-- 'toEncoding' had two reasons:
271+--
272+-- 1. toEncoding is more efficient for the common case that the output of
273+-- 'toJSON' is directly serialized to a @ByteString@.
274+-- Further, expressing either method in terms of the other would be
275+-- non-optimal.
276+--
277+-- 2. The choice of defaults allows a smooth transition for existing users:
278+-- Existing instances that do not define 'toEncoding' still
279+-- compile and have the correct semantics. This is ensured by making
280+-- the default implementation of 'toEncoding' use 'toJSON'. This produces
281+-- correct results, but since it performs an intermediate conversion to a
282+-- 'Value', it will be less efficient than directly emitting an 'Encoding'.
283+-- (this also means that specifying nothing more than
284+-- @instance ToJSON Coord@ would be sufficient as a generically decoding
285+-- instance, but there probably exists no good reason to not specify
286+-- 'toEncoding' in new instances.)
248287class ToJSON a where
249288 -- | Convert a Haskell value to a JSON-friendly intermediate type.
250289 toJSON :: a -> Value
251290
252− default toJSON :: (Generic a, GToJSON Zero (Rep a)) => a -> Value
291+ default toJSON :: (Generic a, GToJSON Value Zero (Rep a)) => a -> Value
253292 toJSON = genericToJSON defaultOptions
254293
255294 -- | Encode a Haskell value as JSON.
@@ -266,8 +305,8 @@ class ToJSON a where
266305 -- extension, and then have GHC generate a method body as follows.
267306 --
268307 -- @
269− -- instance ToJSON Coord where
270− -- toEncoding = 'genericToEncoding' 'defaultOptions'
308+ -- instance 'ToJSON' Coord where
309+ -- 'toEncoding' = 'genericToEncoding' 'defaultOptions'
271310 -- @
272311
273312 toEncoding :: a -> Encoding
@@ -299,13 +338,20 @@ instance KeyValue Pair where
299338 name .= value = (name, toJSON value)
300339 {-# INLINE (.=) #-}
301340
341+-- | Constructs a singleton 'H.HashMap'. For calling functions that
342+-- demand an 'Object' for constructing objects. To be used in
343+-- conjunction with 'mconcat'. Prefer to use 'object' where possible.
344+instance KeyValue Object where
345+ name .= value = H.singleton name (toJSON value)
346+ {-# INLINE (.=) #-}
347+
302348-------------------------------------------------------------------------------
303349-- Classes and types for map keys
304350-------------------------------------------------------------------------------
305351
306352-- | Typeclass for types that can be used as the key of a map-like container
307353-- (like 'Map' or 'HashMap'). For example, since 'Text' has a 'ToJSONKey'
308−-- instance and 'Char' has a 'ToJSON' instance, we can encode a value of
354+-- instance and 'Char' has a 'ToJSON' instance, we can encode a value of
309355-- type 'Map' 'Text' 'Char':
310356--
311357-- >>> LBC8.putStrLn $ encode $ Map.fromList [("foo" :: Text, 'a')]
@@ -351,16 +397,16 @@ instance KeyValue Pair where
351397-- >>> let m = Map.fromList [(Foo 4 "bar",'a'),(Foo 6 "arg",'b')]
352398-- >>> LBC8.putStrLn $ encode m
353399-- [[{"fooName":"bar","fooAge":4},"a"],[{"fooName":"arg","fooAge":6},"b"]]
354−--
400+--
355401-- The next case to consider is if we have a type that is a
356402-- newtype wrapper around 'Text'. The recommended approach is to use
357403-- generalized newtype deriving:
358404--
359−-- > newtype RecordId = RecordId { getRecordId :: Text}
405+-- > newtype RecordId = RecordId { getRecordId :: Text }
360406-- > deriving (Eq,Ord,ToJSONKey)
361−--
407+--
362408-- Then we may write:
363−--
409+--
364410-- >>> LBC8.putStrLn $ encode $ Map.fromList [(RecordId "abc",'a')]
365411-- {"abc":"a"}
366412--
@@ -371,14 +417,24 @@ instance KeyValue Pair where
371417--
372418-- It is possible to get the 'ToJSONKey' instance for free as we did
373419-- with 'Foo'. However, in this case, we have a natural way to go to
374−-- and from 'Text' that does not require any escape sequences. So, in
375−-- this example, 'ToJSONKeyText' will be used instead of 'ToJSONKeyValue'.
420+-- and from 'Text' that does not require any escape sequences. So
421+-- 'ToJSONKeyText' can be used instead of 'ToJSONKeyValue' to encode maps
422+-- as objects instead of arrays of pairs. This instance may be
423+-- implemented using generics as follows:
424+--
425+-- @
426+-- instance 'ToJSONKey' Color where
427+-- 'toJSONKey' = 'genericToJSONKey' 'defaultJSONKeyOptions'
428+-- @
429+--
430+-- === __Low-level implementations__
431+--
376432-- The 'Show' instance can be used to help write 'ToJSONKey':
377433--
378434-- > instance ToJSONKey Color where
379435-- > toJSONKey = ToJSONKeyText f g
380436-- > where f = Text.pack . show
381−-- > g = text . Text.pack . show
437+-- > g = text . Text.pack . show
382438-- > -- text function is from Data.Aeson.Encoding
383439--
384440-- The situation of needing to turning function @a -> Text@ into
@@ -387,7 +443,7 @@ instance KeyValue Pair where
387443--
388444-- > instance ToJSONKey Color where
389445-- > toJSONKey = toJSONKeyText (Text.pack . show)
390−--
446+--
391447-- The performance of the above instance can be improved by
392448-- not using 'String' as an intermediate step when converting to
393449-- 'Text'. One option for improving performance would be to use
@@ -396,7 +452,7 @@ instance KeyValue Pair where
396452-- builder) is generated by encoding the 'Text' to a 'ByteString',
397453-- an intermediate step that could be avoided. The fastest possible
398454-- implementation would be:
399−--
455+--
400456-- > -- Assuming that OverloadedStrings is enabled
401457-- > instance ToJSONKey Color where
402458-- > toJSONKey = ToJSONKeyText f g
@@ -410,26 +466,78 @@ instance KeyValue Pair where
410466-- maximize performance.
411467
412468class ToJSONKey a where
413− -- | Provides a way to use a data type as the key for a map-like
414− -- container.
469+ -- | Strategy for rendering the key for a map-like container.
415470 toJSONKey :: ToJSONKeyFunction a
416471 default toJSONKey :: ToJSON a => ToJSONKeyFunction a
417− toJSONKey = ToJSONKeyValue (toJSON, toEncoding)
472+ toJSONKey = ToJSONKeyValue toJSON toEncoding
473+
418474 -- | This is similar in spirit to the 'showsList' method of 'Show'.
419475 -- It makes it possible to give 'String' keys special treatment
420− -- without using @OverlappingInstances@.
476+ -- without using @OverlappingInstances@. End users should always
477+ -- be able to use the default implementation of this method.
421478 toJSONKeyList :: ToJSONKeyFunction [a]
422479 default toJSONKeyList :: ToJSON a => ToJSONKeyFunction [a]
423− toJSONKeyList = ToJSONKeyValue (toJSON, toEncoding)
480+ toJSONKeyList = ToJSONKeyValue toJSON toEncoding
424481
425482data ToJSONKeyFunction a
426− = ToJSONKeyText (a -> Text, a -> Encoding) -- ^ key is encoded to string, produces object
427− | ToJSONKeyValue (a -> Value, a -> Encoding) -- ^ key is encoded to value, produces array
483+ = ToJSONKeyText !(a -> Text) !(a -> Encoding' Text)
484+ -- ^ key is encoded to string, produces object
485+ | ToJSONKeyValue !(a -> Value) !(a -> Encoding)
486+ -- ^ key is encoded to value, produces array
487+
488+-- | Helper for creating textual keys.
489+--
490+-- @
491+-- instance 'ToJSONKey' MyKey where
492+-- 'toJSONKey' = 'toJSONKeyText' myKeyToText
493+-- where
494+-- myKeyToText = Text.pack . show -- or showt from text-show
495+-- @
496+toJSONKeyText :: (a -> Text) -> ToJSONKeyFunction a
497+toJSONKeyText f = ToJSONKeyText f (E.text . f)
498+
499+-- | TODO: should this be exported?
500+toJSONKeyTextEnc :: (a -> Encoding' Text) -> ToJSONKeyFunction a
501+toJSONKeyTextEnc e = ToJSONKeyText tot e
502+ where
503+ -- TODO: dropAround is also used in stringEncoding, which is unfortunate atm
504+ tot = T.dropAround (== '"')
505+ . T.decodeLatin1
506+ . L.toStrict
507+ . E.encodingToLazyByteString
508+ . e
509+
510+instance Contravariant ToJSONKeyFunction where
511+ contramap = contramapToJSONKeyFunction
428512
513+-- | Contravariant map, as 'ToJSONKeyFunction' is a contravariant functor.
429514contramapToJSONKeyFunction :: (b -> a) -> ToJSONKeyFunction a -> ToJSONKeyFunction b
430515contramapToJSONKeyFunction h x = case x of
431− ToJSONKeyText (f,g) -> ToJSONKeyText (f . h, g . h)
432− ToJSONKeyValue (f,g) -> ToJSONKeyValue (f . h, g . h)
516+ ToJSONKeyText f g -> ToJSONKeyText (f . h) (g . h)
517+ ToJSONKeyValue f g -> ToJSONKeyValue (f . h) (g . h)
518+
519+-- 'toJSONKey' for 'Generic' types.
520+-- Deriving is supported for enumeration types, i.e. the sums of nullary
521+-- constructors. The names of constructors will be used as keys for JSON
522+-- objects.
523+--
524+-- See also 'genericFromJSONKey'.
525+--
526+-- === __Example__
527+--
528+-- @
529+-- data Color = Red | Green | Blue
530+-- deriving 'Generic'
531+--
532+-- instance 'ToJSONKey' Color where
533+-- 'toJSONKey' = 'genericToJSONKey' 'defaultJSONKeyOptions'
534+-- @
535+genericToJSONKey :: (Generic a, GToJSONKey (Rep a))
536+ => JSONKeyOptions -> ToJSONKeyFunction a
537+genericToJSONKey opts = toJSONKeyText (pack . keyModifier opts . getConName . from)
538+
539+class GetConName f => GToJSONKey f
540+instance GetConName f => GToJSONKey f
433541
434542-------------------------------------------------------------------------------
435543-- Lifings of FromJSON and ToJSON to unary and binary type constructors
@@ -443,7 +551,7 @@ contramapToJSONKeyFunction h x = case x of
443551--
444552-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
445553-- instance at compile time. The generated instance is optimized for your type
446−-- so will probably be more efficient than the following two options:
554+-- so it will probably be more efficient than the following option.
447555--
448556-- * The compiler can provide a default generic implementation for
449557-- 'toJSON1'.
@@ -461,23 +569,29 @@ contramapToJSONKeyFunction h x = case x of
461569--
462570-- data Pair = Pair { pairFst :: a, pairSnd :: b } deriving 'Generic1'
463571--
464−-- instance ToJSON a => ToJSON1 (Pair a)
572+-- instance 'ToJSON' a => 'ToJSON1' (Pair a)
465573-- @
466574--
467−-- If @DefaultSignatures@ doesn't give exactly the results you want,
575+-- If the default implementation doesn't give exactly the results you want,
468576-- you can customize the generic encoding with only a tiny amount of
469577-- effort, using 'genericLiftToJSON' and 'genericLiftToEncoding' with
470578-- your preferred 'Options':
471579--
472580-- @
473−-- instance ToJSON a => ToJSON1 (Pair a) where
474−-- liftToJSON = 'genericLiftToJSON' 'defaultOptions'
475−-- liftToEncoding = 'genericLiftToEncoding' 'defaultOptions'
581+-- customOptions = 'defaultOptions'
582+-- { 'fieldLabelModifier' = 'map' 'Data.Char.toUpper'
583+-- }
584+--
585+-- instance 'ToJSON' a => 'ToJSON1' (Pair a) where
586+-- 'liftToJSON' = 'genericLiftToJSON' customOptions
587+-- 'liftToEncoding' = 'genericLiftToEncoding' customOptions
476588-- @
589+--
590+-- See also 'ToJSON'.
477591class ToJSON1 f where
478592 liftToJSON :: (a -> Value) -> ([a] -> Value) -> f a -> Value
479593
480− default liftToJSON :: (Generic1 f, GToJSON One (Rep1 f))
594+ default liftToJSON :: (Generic1 f, GToJSON Value One (Rep1 f))
481595 => (a -> Value) -> ([a] -> Value) -> f a -> Value
482596 liftToJSON = genericLiftToJSON defaultOptions
483597
@@ -486,7 +600,7 @@ class ToJSON1 f where
486600
487601 liftToEncoding :: (a -> Encoding) -> ([a] -> Encoding) -> f a -> Encoding
488602
489− default liftToEncoding :: (Generic1 f, GToEncoding One (Rep1 f))
603+ default liftToEncoding :: (Generic1 f, GToJSON Encoding One (Rep1 f))
490604 => (a -> Encoding) -> ([a] -> Encoding)
491605 -> f a -> Encoding
492606 liftToEncoding = genericLiftToEncoding defaultOptions
@@ -534,9 +648,25 @@ toEncoding2 = liftToEncoding2 toEncoding toEncodingList toEncoding toEncodingLis
534648-- Encoding functions
535649-------------------------------------------------------------------------------
536650
651+-- | Helper function to use with 'liftToEncoding'.
652+-- Useful when writing own 'ToJSON1' instances.
653+--
654+-- @
655+-- newtype F a = F [a]
656+--
657+-- -- This instance encodes 'String' as an array of chars
658+-- instance 'ToJSON1' F where
659+-- 'liftToJSON' tj _ (F xs) = 'liftToJSON' tj ('listValue' tj) xs
660+-- 'liftToEncoding' te _ (F xs) = 'liftToEncoding' te ('listEncoding' te) xs
661+--
662+-- instance 'Data.Aeson.FromJSON.FromJSON1' F where
663+-- 'Data.Aeson.FromJSON.liftParseJSON' p _ v = F \<$\> 'Data.Aeson.FromJSON.liftParseJSON' p ('Data.Aeson.FromJSON.listParser' p) v
664+-- @
537665listEncoding :: (a -> Encoding) -> [a] -> Encoding
538666listEncoding = E.list
667+{-# INLINE listEncoding #-}
539668
669+-- | Helper function to use with 'liftToJSON', see 'listEncoding'.
540670listValue :: (a -> Value) -> [a] -> Value
541671listValue f = Array . V.fromList . map f
542672{-# INLINE listValue #-}
@@ -555,6 +685,11 @@ instance ToJSON1 [] where
555685 {-# INLINE liftToEncoding #-}
556686
557687instance (ToJSON a) => ToJSON [a] where
688+ {-# SPECIALIZE instance ToJSON String #-}
689+ {-# SPECIALIZE instance ToJSON [String] #-}
690+ {-# SPECIALIZE instance ToJSON [Array] #-}
691+ {-# SPECIALIZE instance ToJSON [Object] #-}
692+
558693 toJSON = toJSON1
559694 {-# INLINE toJSON #-}
560695
@@ -565,283 +700,260 @@ instance (ToJSON a) => ToJSON [a] where
565700-- Generic toJSON / toEncoding
566701-------------------------------------------------------------------------------
567702
703+instance OVERLAPPABLE_ (GToJSON enc arity a) => GToJSON enc arity (M1 i c a) where
704+ -- Meta-information, which is not handled elsewhere, is ignored:
705+ gToJSON opts targs = gToJSON opts targs . unM1
706+ {-# INLINE gToJSON #-}
707+
708+instance GToJSON enc One Par1 where
709+ -- Direct occurrences of the last type parameter are encoded with the
710+ -- function passed in as an argument:
711+ gToJSON _opts (To1Args tj _) = tj . unPar1
712+ {-# INLINE gToJSON #-}
713+
714+instance ( ConsToJSON enc arity a
715+ , AllNullary (C1 c a) allNullary
716+ , SumToJSON enc arity (C1 c a) allNullary
717+ ) => GToJSON enc arity (D1 d (C1 c a)) where
718+ -- The option 'tagSingleConstructors' determines whether to wrap
719+ -- a single-constructor type.
720+ gToJSON opts targs
721+ | tagSingleConstructors opts = (unTagged :: Tagged allNullary enc -> enc)
722+ . sumToJSON opts targs
723+ . unM1
724+ | otherwise = consToJSON opts targs . unM1 . unM1
725+ {-# INLINE gToJSON #-}
726+
727+instance (ConsToJSON enc arity a) => GToJSON enc arity (C1 c a) where
728+ -- Constructors need to be encoded differently depending on whether they're
729+ -- a record or not. This distinction is made by 'consToJSON':
730+ gToJSON opts targs = consToJSON opts targs . unM1
731+ {-# INLINE gToJSON #-}
732+
733+instance ( AllNullary (a :+: b) allNullary
734+ , SumToJSON enc arity (a :+: b) allNullary
735+ ) => GToJSON enc arity (a :+: b)
736+ where
737+ -- If all constructors of a sum datatype are nullary and the
738+ -- 'allNullaryToStringTag' option is set they are encoded to
739+ -- strings. This distinction is made by 'sumToJSON':
740+ gToJSON opts targs = (unTagged :: Tagged allNullary enc -> enc)
741+ . sumToJSON opts targs
742+ {-# INLINE gToJSON #-}
743+
568744--------------------------------------------------------------------------------
569745-- Generic toJSON
570746
571−instance OVERLAPPABLE_ (GToJSON arity a) => GToJSON arity (M1 i c a) where
572− -- Meta-information, which is not handled elsewhere, is ignored:
573− gToJSON opts pa tj tjl = gToJSON opts pa tj tjl . unM1
747+-- Note: Refactoring 'ToJSON a' to 'ToJSON enc a' (and 'ToJSON1' similarly) is
748+-- possible but makes error messages a bit harder to understand for missing
749+-- instances.
574750
575−instance (ToJSON a) => GToJSON arity (K1 i a) where
576− -- Constant values are encoded using their ToJSON instance:
577− gToJSON _opts _ _ _ = toJSON . unK1
751+instance GToJSON Value arity V1 where
752+ -- Empty values do not exist, which makes the job of formatting them
753+ -- rather easy:
754+ gToJSON _ _ x = x `seq` error "case: V1"
755+ {-# INLINE gToJSON #-}
578756
579−instance GToJSON One Par1 where
580− -- Direct occurrences of the last type parameter are encoded with the
581− -- function passed in as an argument:
582− gToJSON _opts _ tj _ = tj . unPar1
757+instance ToJSON a => GToJSON Value arity (K1 i a) where
758+ -- Constant values are encoded using their ToJSON instance:
759+ gToJSON _opts _ = toJSON . unK1
760+ {-# INLINE gToJSON #-}
583761
584−instance (ToJSON1 f) => GToJSON One (Rec1 f) where
762+instance ToJSON1 f => GToJSON Value One (Rec1 f) where
585763 -- Recursive occurrences of the last type parameter are encoded using their
586764 -- ToJSON1 instance:
587− gToJSON _opts _ tj tjl = liftToJSON tj tjl . unRec1
765+ gToJSON _opts (To1Args tj tjl) = liftToJSON tj tjl . unRec1
766+ {-# INLINE gToJSON #-}
588767
589−instance GToJSON arity U1 where
768+instance GToJSON Value arity U1 where
590769 -- Empty constructors are encoded to an empty array:
591− gToJSON _opts _ _ _ _ = emptyArray
592−
593−instance (ConsToJSON arity a) => GToJSON arity (C1 c a) where
594− -- Constructors need to be encoded differently depending on whether they're
595− -- a record or not. This distinction is made by 'consToJSON':
596− gToJSON opts pa tj tjl = consToJSON opts pa tj tjl . unM1
770+ gToJSON _opts _ _ = emptyArray
771+ {-# INLINE gToJSON #-}
597772
598773instance ( WriteProduct arity a, WriteProduct arity b
599774 , ProductSize a, ProductSize b
600− ) => GToJSON arity (a :*: b) where
775+ ) => GToJSON Value arity (a :*: b)
776+ where
601777 -- Products are encoded to an array. Here we allocate a mutable vector of
602778 -- the same size as the product and write the product's elements to it using
603779 -- 'writeProduct':
604− gToJSON opts pa tj tjl p =
780+ gToJSON opts targs p =
605781 Array $ V.create $ do
606782 mv <- VM.unsafeNew lenProduct
607− writeProduct opts pa mv 0 lenProduct tj tjl p
783+ writeProduct opts targs mv 0 lenProduct p
608784 return mv
609785 where
610786 lenProduct = (unTagged2 :: Tagged2 (a :*: b) Int -> Int)
611787 productSize
788+ {-# INLINE gToJSON #-}
612789
613−instance ( AllNullary (a :+: b) allNullary
614− , SumToJSON arity (a :+: b) allNullary
615− ) => GToJSON arity (a :+: b) where
616− -- If all constructors of a sum datatype are nullary and the
617− -- 'allNullaryToStringTag' option is set they are encoded to
618− -- strings. This distinction is made by 'sumToJSON':
619− gToJSON opts pa tj tjl = (unTagged :: Tagged allNullary Value -> Value)
620− . sumToJSON opts pa tj tjl
621−
622−instance (ToJSON1 f, GToJSON One g) => GToJSON One (f :.: g) where
790+instance ( ToJSON1 f
791+ , GToJSON Value One g
792+ ) => GToJSON Value One (f :.: g)
793+ where
623794 -- If an occurrence of the last type parameter is nested inside two
624795 -- composed types, it is encoded by using the outermost type's ToJSON1
625796 -- instance to generically encode the innermost type:
626− gToJSON opts pa tj tjl =
627− let gtj = gToJSON opts pa tj tjl in
797+ gToJSON opts targs =
798+ let gtj = gToJSON opts targs in
628799 liftToJSON gtj (listValue gtj) . unComp1
800+ {-# INLINE gToJSON #-}
629801
630802--------------------------------------------------------------------------------
631803-- Generic toEncoding
632804
633−instance OVERLAPPABLE_ (GToEncoding arity a) => GToEncoding arity (M1 i c a) where
634− -- Meta-information, which is not handled elsewhere, is ignored:
635− gToEncoding opts pa te tel = gToEncoding opts pa te tel . unM1
636−
637−instance (ToJSON a) => GToEncoding arity (K1 i a) where
805+instance ToJSON a => GToJSON Encoding arity (K1 i a) where
638806 -- Constant values are encoded using their ToJSON instance:
639− gToEncoding _opts _ _ _ = toEncoding . unK1
640−
641−instance GToEncoding One Par1 where
642− -- Direct occurrences of the last type parameter are encoded with the
643− -- function passed in as an argument:
644− gToEncoding _opts _ te _ = te . unPar1
807+ gToJSON _opts _ = toEncoding . unK1
808+ {-# INLINE gToJSON #-}
645809
646−instance (ToJSON1 f) => GToEncoding One (Rec1 f) where
810+instance ToJSON1 f => GToJSON Encoding One (Rec1 f) where
647811 -- Recursive occurrences of the last type parameter are encoded using their
648812 -- ToEncoding1 instance:
649− gToEncoding _opts _ te tel = liftToEncoding te tel . unRec1
813+ gToJSON _opts (To1Args te tel) = liftToEncoding te tel . unRec1
814+ {-# INLINE gToJSON #-}
650815
651−instance GToEncoding arity U1 where
816+instance GToJSON Encoding arity U1 where
652817 -- Empty constructors are encoded to an empty array:
653− gToEncoding _opts _ _ _ _ = E.emptyArray_
654−
655−instance (ConsToEncoding arity a) => GToEncoding arity (C1 c a) where
656− -- Constructors need to be encoded differently depending on whether they're
657− -- a record or not. This distinction is made by 'consToEncoding':
658− gToEncoding opts pa te tel = consToEncoding opts pa te tel . unM1
818+ gToJSON _opts _ _ = E.emptyArray_
819+ {-# INLINE gToJSON #-}
659820
660821instance ( EncodeProduct arity a
661822 , EncodeProduct arity b
662− ) => GToEncoding arity (a :*: b) where
823+ ) => GToJSON Encoding arity (a :*: b)
824+ where
663825 -- Products are encoded to an array. Here we allocate a mutable vector of
664826 -- the same size as the product and write the product's elements to it using
665827 -- 'encodeProduct':
666− gToEncoding opts pa te tel p = E.tuple $ encodeProduct opts pa te tel p
667−
668−instance ( AllNullary (a :+: b) allNullary
669− , SumToEncoding arity (a :+: b) allNullary
670− ) => GToEncoding arity (a :+: b) where
671− -- If all constructors of a sum datatype are nullary and the
672− -- 'allNullaryToStringTag' option is set they are encoded to
673− -- strings. This distinction is made by 'sumToEncoding':
674− gToEncoding opts pa te tel
675− = (unTagged :: Tagged allNullary Encoding -> Encoding)
676− . sumToEncoding opts pa te tel
828+ gToJSON opts targs p = E.list E.retagEncoding [encodeProduct opts targs p]
829+ {-# INLINE gToJSON #-}
677830
678−instance (ToJSON1 f, GToEncoding One g) => GToEncoding One (f :.: g) where
831+instance ( ToJSON1 f
832+ , GToJSON Encoding One g
833+ ) => GToJSON Encoding One (f :.: g)
834+ where
679835 -- If an occurrence of the last type parameter is nested inside two
680836 -- composed types, it is encoded by using the outermost type's ToJSON1
681837 -- instance to generically encode the innermost type:
682− gToEncoding opts pa te tel =
683− let gte = gToEncoding opts pa te tel in
838+ gToJSON opts targs =
839+ let gte = gToJSON opts targs in
684840 liftToEncoding gte (listEncoding gte) . unComp1
841+ {-# INLINE gToJSON #-}
685842
686843--------------------------------------------------------------------------------
687844
688−class SumToJSON arity f allNullary where
689− sumToJSON :: Options -> Proxy arity
690− -> (a -> Value) -> ([a] -> Value)
691− -> f a -> Tagged allNullary Value
692−
693−instance ( GetConName f
694− , TaggedObjectPairs arity f
695− , ObjectWithSingleFieldObj arity f
696− , TwoElemArrayObj arity f
697− ) => SumToJSON arity f True where
698− sumToJSON opts pa tj tjl
699− | allNullaryToStringTag opts = Tagged . String . pack
845+class SumToJSON enc arity f allNullary where
846+ sumToJSON :: Options -> ToArgs enc arity a
847+ -> f a -> Tagged allNullary enc
848+
849+instance ( GetConName f
850+ , FromString enc
851+ , TaggedObject enc arity f
852+ , SumToJSON' ObjectWithSingleField enc arity f
853+ , SumToJSON' TwoElemArray enc arity f
854+ , SumToJSON' UntaggedValue enc arity f
855+ ) => SumToJSON enc arity f True
856+ where
857+ sumToJSON opts targs
858+ | allNullaryToStringTag opts = Tagged . fromString
700859 . constructorTagModifier opts . getConName
701− | otherwise = Tagged . nonAllNullarySumToJSON opts pa tj tjl
702−
703−instance ( TwoElemArrayObj arity f
704− , TaggedObjectPairs arity f
705− , ObjectWithSingleFieldObj arity f
706− ) => SumToJSON arity f False where
707− sumToJSON opts pa tj tjl = Tagged . nonAllNullarySumToJSON opts pa tj tjl
708−
709−nonAllNullarySumToJSON :: ( TwoElemArrayObj arity f
710− , TaggedObjectPairs arity f
711− , ObjectWithSingleFieldObj arity f
712− ) => Options -> Proxy arity
713− -> (a -> Value) -> ([a] -> Value)
714− -> f a -> Value
715−nonAllNullarySumToJSON opts pa tj tjl =
860+ | otherwise = Tagged . nonAllNullarySumToJSON opts targs
861+
862+instance ( TaggedObject enc arity f
863+ , SumToJSON' ObjectWithSingleField enc arity f
864+ , SumToJSON' TwoElemArray enc arity f
865+ , SumToJSON' UntaggedValue enc arity f
866+ ) => SumToJSON enc arity f False
867+ where
868+ sumToJSON opts targs = Tagged . nonAllNullarySumToJSON opts targs
869+
870+nonAllNullarySumToJSON :: ( TaggedObject enc arity f
871+ , SumToJSON' ObjectWithSingleField enc arity f
872+ , SumToJSON' TwoElemArray enc arity f
873+ , SumToJSON' UntaggedValue enc arity f
874+ ) => Options -> ToArgs enc arity a
875+ -> f a -> enc
876+nonAllNullarySumToJSON opts targs =
716877 case sumEncoding opts of
717− TaggedObject{..} ->
718− object . taggedObjectPairs opts pa tagFieldName contentsFieldName tj tjl
719− ObjectWithSingleField -> Object . objectWithSingleFieldObj opts pa tj tjl
720− TwoElemArray -> Array . twoElemArrayObj opts pa tj tjl
721−
722−--------------------------------------------------------------------------------
723878
724−class SumToEncoding arity f allNullary where
725− sumToEncoding :: Options -> Proxy arity
726− -> (a -> Encoding) -> ([a] -> Encoding)
727− -> f a -> Tagged allNullary Encoding
728−
729−instance ( GetConName f
730− , TaggedObjectEnc arity f
731− , ObjectWithSingleFieldEnc arity f
732− , TwoElemArrayEnc arity f
733− ) => SumToEncoding arity f True where
734− sumToEncoding opts pa te tel
735− | allNullaryToStringTag opts = Tagged . toEncoding .
736− constructorTagModifier opts . getConName
737− | otherwise = Tagged . nonAllNullarySumToEncoding opts pa te tel
738−
739−instance ( TwoElemArrayEnc arity f
740− , TaggedObjectEnc arity f
741− , ObjectWithSingleFieldEnc arity f
742− ) => SumToEncoding arity f False where
743− sumToEncoding opts pa te tel = Tagged . nonAllNullarySumToEncoding opts pa te tel
744−
745−nonAllNullarySumToEncoding :: ( TwoElemArrayEnc arity f
746− , TaggedObjectEnc arity f
747− , ObjectWithSingleFieldEnc arity f
748− ) => Options -> Proxy arity
749− -> (a -> Encoding) -> ([a] -> Encoding)
750− -> f a -> Encoding
751−nonAllNullarySumToEncoding opts pa te tel =
752− case sumEncoding opts of
753879 TaggedObject{..} ->
754− taggedObjectEnc opts pa tagFieldName contentsFieldName te tel
755− ObjectWithSingleField -> objectWithSingleFieldEnc opts pa te tel
756− TwoElemArray -> twoElemArrayEnc opts pa te tel
880+ taggedObject opts targs tagFieldName contentsFieldName
757881
758−--------------------------------------------------------------------------------
882+ ObjectWithSingleField ->
883+ (unTagged :: Tagged ObjectWithSingleField enc -> enc)
884+ . sumToJSON' opts targs
759885
760−class TaggedObjectPairs arity f where
761− taggedObjectPairs :: Options -> Proxy arity
762− -> String -> String
763− -> (a -> Value) -> ([a] -> Value)
764− -> f a -> [Pair]
765−
766−instance ( TaggedObjectPairs arity a
767− , TaggedObjectPairs arity b
768− ) => TaggedObjectPairs arity (a :+: b) where
769− taggedObjectPairs opts pa tagFieldName contentsFieldName tj tjl (L1 x) =
770− taggedObjectPairs opts pa tagFieldName contentsFieldName tj tjl x
771− taggedObjectPairs opts pa tagFieldName contentsFieldName tj tjl (R1 x) =
772− taggedObjectPairs opts pa tagFieldName contentsFieldName tj tjl x
773−
774−instance ( IsRecord a isRecord
775− , TaggedObjectPairs' arity a isRecord
776− , Constructor c
777− ) => TaggedObjectPairs arity (C1 c a) where
778− taggedObjectPairs opts pa tagFieldName contentsFieldName tj tjl =
779− (pack tagFieldName .= constructorTagModifier opts
780− (conName (undefined :: t c a p)) :) .
781− (unTagged :: Tagged isRecord [Pair] -> [Pair]) .
782− taggedObjectPairs' opts pa contentsFieldName tj tjl . unM1
886+ TwoElemArray ->
887+ (unTagged :: Tagged TwoElemArray enc -> enc)
888+ . sumToJSON' opts targs
889+
890+ UntaggedValue ->
891+ (unTagged :: Tagged UntaggedValue enc -> enc)
892+ . sumToJSON' opts targs
783893
784−class TaggedObjectPairs' arity f isRecord where
785− taggedObjectPairs' :: Options -> Proxy arity
786− -> String -> (a -> Value) -> ([a] -> Value)
787− -> f a -> Tagged isRecord [Pair]
894+--------------------------------------------------------------------------------
788895
789−instance OVERLAPPING_ TaggedObjectPairs' arity U1 False where
790− taggedObjectPairs' _ _ _ _ _ _ = Tagged []
896+class FromString enc where
897+ fromString :: String -> enc
791898
792−instance (RecordToPairs arity f) => TaggedObjectPairs' arity f True where
793− taggedObjectPairs' opts pa _ tj tjl =
794− Tagged . toList . recordToPairs opts pa tj tjl
899+instance FromString Encoding where
900+ fromString = toEncoding
795901
796−instance (GToJSON arity f) => TaggedObjectPairs' arity f False where
797− taggedObjectPairs' opts pa contentsFieldName tj tjl =
798− Tagged . (:[]) . (pack contentsFieldName .=) . gToJSON opts pa tj tjl
902+instance FromString Value where
903+ fromString = String . pack
799904
800905--------------------------------------------------------------------------------
801906
802−class TaggedObjectEnc arity f where
803− taggedObjectEnc :: Options -> Proxy arity
804− -> String -> String
805− -> (a -> Encoding) -> ([a] -> Encoding)
806− -> f a -> Encoding
807−
808−instance ( TaggedObjectEnc arity a
809− , TaggedObjectEnc arity b
810− ) => TaggedObjectEnc arity (a :+: b) where
811− taggedObjectEnc opts pa tagFieldName contentsFieldName te tel (L1 x) =
812− taggedObjectEnc opts pa tagFieldName contentsFieldName te tel x
813− taggedObjectEnc opts pa tagFieldName contentsFieldName te tel (R1 x) =
814− taggedObjectEnc opts pa tagFieldName contentsFieldName te tel x
815−
816−instance ( IsRecord a isRecord
817− , TaggedObjectEnc' arity a isRecord
907+class TaggedObject enc arity f where
908+ taggedObject :: Options -> ToArgs enc arity a
909+ -> String -> String
910+ -> f a -> enc
911+
912+instance ( TaggedObject enc arity a
913+ , TaggedObject enc arity b
914+ ) => TaggedObject enc arity (a :+: b)
915+ where
916+ taggedObject opts targs tagFieldName contentsFieldName (L1 x) =
917+ taggedObject opts targs tagFieldName contentsFieldName x
918+ taggedObject opts targs tagFieldName contentsFieldName (R1 x) =
919+ taggedObject opts targs tagFieldName contentsFieldName x
920+
921+instance ( IsRecord a isRecord
922+ , TaggedObject' enc pairs arity a isRecord
923+ , FromPairs enc pairs
924+ , FromString enc
925+ , KeyValuePair enc pairs
818926 , Constructor c
819− ) => TaggedObjectEnc arity (C1 c a) where
820− taggedObjectEnc opts pa tagFieldName contentsFieldName te tel v =
821− E.openCurly <>
822− (toEncoding tagFieldName <>
823− E.colon <>
824− toEncoding (constructorTagModifier opts (conName (undefined :: t c a p)))) <>
825− ((unTagged :: Tagged isRecord Encoding -> Encoding) .
826− taggedObjectEnc' opts pa contentsFieldName te tel . unM1 $ v) <>
827− E.closeCurly
828−
829−class TaggedObjectEnc' arity f isRecord where
830− taggedObjectEnc' :: Options -> Proxy arity
831− -> String -> (a -> Encoding) -> ([a] -> Encoding)
832− -> f a -> Tagged isRecord Encoding
833−
834−instance OVERLAPPING_ TaggedObjectEnc' arity U1 False where
835− taggedObjectEnc' _ _ _ _ _ _ = Tagged mempty
836−
837−instance (RecordToEncoding arity f) => TaggedObjectEnc' arity f True where
838− taggedObjectEnc' opts pa _ te tel = Tagged . (E.comma <>) . fst
839− . recordToEncoding opts pa te tel
840−
841−instance (GToEncoding arity f) => TaggedObjectEnc' arity f False where
842− taggedObjectEnc' opts pa contentsFieldName te tel =
843− Tagged . (\z -> E.comma <> toEncoding contentsFieldName <> E.colon <> z) .
844− gToEncoding opts pa te tel
927+ ) => TaggedObject enc arity (C1 c a)
928+ where
929+ taggedObject opts targs tagFieldName contentsFieldName =
930+ fromPairs . mappend tag . contents
931+ where
932+ tag = tagFieldName `pair`
933+ (fromString (constructorTagModifier opts (conName (undefined :: t c a p)))
934+ :: enc)
935+ contents =
936+ (unTagged :: Tagged isRecord pairs -> pairs) .
937+ taggedObject' opts targs contentsFieldName . unM1
938+
939+class TaggedObject' enc pairs arity f isRecord where
940+ taggedObject' :: Options -> ToArgs enc arity a
941+ -> String -> f a -> Tagged isRecord pairs
942+
943+instance ( GToJSON enc arity f
944+ , KeyValuePair enc pairs
945+ ) => TaggedObject' enc pairs arity f False
946+ where
947+ taggedObject' opts targs contentsFieldName =
948+ Tagged . (contentsFieldName `pair`) . gToJSON opts targs
949+
950+instance OVERLAPPING_ Monoid pairs => TaggedObject' enc pairs arity U1 False where
951+ taggedObject' _ _ _ _ = Tagged mempty
952+
953+instance ( RecordToPairs enc pairs arity f
954+ ) => TaggedObject' enc pairs arity f True
955+ where
956+ taggedObject' opts targs _ = Tagged . recordToPairs opts targs
845957
846958--------------------------------------------------------------------------------
847959
@@ -856,283 +968,242 @@ instance (GetConName a, GetConName b) => GetConName (a :+: b) where
856968instance (Constructor c) => GetConName (C1 c a) where
857969 getConName = conName
858970
971+-- For genericToJSONKey
972+instance GetConName a => GetConName (D1 d a) where
973+ getConName (M1 x) = getConName x
974+
859975--------------------------------------------------------------------------------
860976
861−class TwoElemArrayObj arity f where
862− twoElemArrayObj :: Options -> Proxy arity
863− -> (a -> Value) -> ([a] -> Value)
864− -> f a -> V.Vector Value
977+-- Reflection of SumEncoding variants
865978
866−instance ( TwoElemArrayObj arity a
867− , TwoElemArrayObj arity b
868− ) => TwoElemArrayObj arity (a :+: b) where
869− twoElemArrayObj opts pa tj tjl (L1 x) = twoElemArrayObj opts pa tj tjl x
870− twoElemArrayObj opts pa tj tjl (R1 x) = twoElemArrayObj opts pa tj tjl x
979+data ObjectWithSingleField
980+data TwoElemArray
981+data UntaggedValue
871982
872−instance ( GToJSON arity a
873− , ConsToJSON arity a
983+--------------------------------------------------------------------------------
984+
985+class SumToJSON' s enc arity f where
986+ sumToJSON' :: Options -> ToArgs enc arity a
987+ -> f a -> Tagged s enc
988+
989+instance ( SumToJSON' s enc arity a
990+ , SumToJSON' s enc arity b
991+ ) => SumToJSON' s enc arity (a :+: b)
992+ where
993+ sumToJSON' opts targs (L1 x) = sumToJSON' opts targs x
994+ sumToJSON' opts targs (R1 x) = sumToJSON' opts targs x
995+
996+--------------------------------------------------------------------------------
997+
998+instance ( GToJSON Value arity a
999+ , ConsToJSON Value arity a
8741000 , Constructor c
875− ) => TwoElemArrayObj arity (C1 c a) where
876− twoElemArrayObj opts pa tj tjl x = V.create $ do
1001+ ) => SumToJSON' TwoElemArray Value arity (C1 c a) where
1002+ sumToJSON' opts targs x = Tagged $ Array $ V.create $ do
8771003 mv <- VM.unsafeNew 2
8781004 VM.unsafeWrite mv 0 $ String $ pack $ constructorTagModifier opts
8791005 $ conName (undefined :: t c a p)
880− VM.unsafeWrite mv 1 $ gToJSON opts pa tj tjl x
1006+ VM.unsafeWrite mv 1 $ gToJSON opts targs x
8811007 return mv
8821008
8831009--------------------------------------------------------------------------------
8841010
885−class TwoElemArrayEnc arity f where
886− twoElemArrayEnc :: Options -> Proxy arity
887− -> (a -> Encoding) -> ([a] -> Encoding)
888− -> f a -> Encoding
889−
890−instance ( TwoElemArrayEnc arity a
891− , TwoElemArrayEnc arity b
892− ) => TwoElemArrayEnc arity (a :+: b) where
893− twoElemArrayEnc opts pa te tel (L1 x) = twoElemArrayEnc opts pa te tel x
894− twoElemArrayEnc opts pa te tel (R1 x) = twoElemArrayEnc opts pa te tel x
895−
896−instance ( GToEncoding arity a
897− , ConsToEncoding arity a
1011+instance ( GToJSON Encoding arity a
1012+ , ConsToJSON Encoding arity a
8981013 , Constructor c
899− ) => TwoElemArrayEnc arity (C1 c a) where
900− twoElemArrayEnc opts pa te tel x = E.tuple $
901− toEncoding (constructorTagModifier opts (conName (undefined :: t c a p))) >*<
902− gToEncoding opts pa te tel x
903−
904−--------------------------------------------------------------------------------
905−
906−class ConsToJSON arity f where
907− consToJSON :: Options -> Proxy arity
908− -> (a -> Value) -> ([a] -> Value)
909− -> f a -> Value
910−
911−class ConsToJSON' arity f isRecord where
912− consToJSON' :: Options -> Proxy arity
913− -> Bool -- ^ Are we a record with one field?
914− -> (a -> Value) -> ([a] -> Value)
915− -> f a -> Tagged isRecord Value
916−
917−instance ( IsRecord f isRecord
918− , ConsToJSON' arity f isRecord
919− ) => ConsToJSON arity f where
920− consToJSON opts pa tj tjl =
921− (unTagged :: Tagged isRecord Value -> Value)
922− . consToJSON' opts pa (isUnary (undefined :: f a)) tj tjl
923−
924−instance (RecordToPairs arity f) => ConsToJSON' arity f True where
925− consToJSON' opts pa isUn tj tjl f = let
926− vals = toList $ recordToPairs opts pa tj tjl f
927− in case (unwrapUnaryRecords opts,isUn,vals) of
928− (True,True,[(_,val)]) -> Tagged val
929− _ -> Tagged $ object vals
930−
931−instance GToJSON arity f => ConsToJSON' arity f False where
932− consToJSON' opts pa _ tj tjl = Tagged . gToJSON opts pa tj tjl
1014+ ) => SumToJSON' TwoElemArray Encoding arity (C1 c a)
1015+ where
1016+ sumToJSON' opts targs x = Tagged $ E.list id
1017+ [ toEncoding (constructorTagModifier opts (conName (undefined :: t c a p)))
1018+ , gToJSON opts targs x
1019+ ]
9331020
9341021--------------------------------------------------------------------------------
9351022
936−class ConsToEncoding arity f where
937− consToEncoding :: Options -> Proxy arity
938− -> (a -> Encoding) -> ([a] -> Encoding)
939− -> f a -> Encoding
1023+class ConsToJSON enc arity f where
1024+ consToJSON :: Options -> ToArgs enc arity a
1025+ -> f a -> enc
9401026
941−class ConsToEncoding' arity f isRecord where
942− consToEncoding' :: Options -> Proxy arity
943− -> Bool -- ^ Are we a record with one field?
944− -> (a -> Encoding) -> ([a] -> Encoding)
945− -> f a -> Tagged isRecord Encoding
1027+class ConsToJSON' enc arity f isRecord where
1028+ consToJSON' :: Options -> ToArgs enc arity a
1029+ -> f a -> Tagged isRecord enc
9461030
9471031instance ( IsRecord f isRecord
948− , ConsToEncoding' arity f isRecord
949− ) => ConsToEncoding arity f where
950− consToEncoding opts pa te tel =
951− (unTagged :: Tagged isRecord Encoding -> Encoding)
952− . consToEncoding' opts pa (isUnary (undefined :: f a)) te tel
953−
954−instance (RecordToEncoding arity f) => ConsToEncoding' arity f True where
955− consToEncoding' opts pa isUn te tel x =
956− let (enc, mbVal) = recordToEncoding opts pa te tel x
957− in case (unwrapUnaryRecords opts, isUn, mbVal) of
958− (True, True, Just val) -> Tagged val
959− _ -> Tagged $ E.wrapObject enc
960−
961−instance GToEncoding arity f => ConsToEncoding' arity f False where
962− consToEncoding' opts pa _ te tel = Tagged . gToEncoding opts pa te tel
963−
964−--------------------------------------------------------------------------------
965−
966−class RecordToPairs arity f where
967− recordToPairs :: Options -> Proxy arity
968− -> (a -> Value) -> ([a] -> Value)
969− -> f a -> DList Pair
970−
971−instance ( RecordToPairs arity a
972− , RecordToPairs arity b
973− ) => RecordToPairs arity (a :*: b) where
974− recordToPairs opts pa tj tjl (a :*: b) = recordToPairs opts pa tj tjl a <>
975− recordToPairs opts pa tj tjl b
976−
977−instance (Selector s, GToJSON arity a) => RecordToPairs arity (S1 s a) where
978− recordToPairs = fieldToPair
979−
980−instance OVERLAPPING_ (Selector s, ToJSON a) =>
981− RecordToPairs arity (S1 s (K1 i (Maybe a))) where
982− recordToPairs opts _ _ _ (M1 k1) | omitNothingFields opts
983− , K1 Nothing <- k1 = DList.empty
984− recordToPairs opts pa tj tjl m1 = fieldToPair opts pa tj tjl m1
985−
986−fieldToPair :: (Selector s, GToJSON arity a)
987− => Options -> Proxy arity
988− -> (p -> Value) -> ([p] -> Value)
989− -> S1 s a p -> DList Pair
990−fieldToPair opts pa tj tjl m1 = pure ( pack $ fieldLabelModifier opts $ selName m1
991− , gToJSON opts pa tj tjl (unM1 m1)
992− )
1032+ , ConsToJSON' enc arity f isRecord
1033+ ) => ConsToJSON enc arity f
1034+ where
1035+ consToJSON opts targs =
1036+ (unTagged :: Tagged isRecord enc -> enc)
1037+ . consToJSON' opts targs
1038+ {-# INLINE consToJSON #-}
1039+
1040+instance OVERLAPPING_
1041+ ( RecordToPairs enc pairs arity (S1 s f)
1042+ , FromPairs enc pairs
1043+ , GToJSON enc arity f
1044+ ) => ConsToJSON' enc arity (S1 s f) True
1045+ where
1046+ consToJSON' opts targs
1047+ | unwrapUnaryRecords opts = Tagged . gToJSON opts targs
1048+ | otherwise = Tagged . fromPairs . recordToPairs opts targs
1049+ {-# INLINE consToJSON' #-}
1050+
1051+instance ( RecordToPairs enc pairs arity f
1052+ , FromPairs enc pairs
1053+ ) => ConsToJSON' enc arity f True
1054+ where
1055+ consToJSON' opts targs = Tagged . fromPairs . recordToPairs opts targs
1056+ {-# INLINE consToJSON' #-}
1057+
1058+instance GToJSON enc arity f => ConsToJSON' enc arity f False where
1059+ consToJSON' opts targs = Tagged . gToJSON opts targs
1060+ {-# INLINE consToJSON' #-}
9931061
9941062--------------------------------------------------------------------------------
9951063
996−class RecordToEncoding arity f where
1064+class RecordToPairs enc pairs arity f where
9971065 -- 1st element: whole thing
9981066 -- 2nd element: in case the record has only 1 field, just the value
9991067 -- of the field (without the key); 'Nothing' otherwise
1000− recordToEncoding :: Options -> Proxy arity
1001− -> (a -> Encoding) -> ([a] -> Encoding)
1002− -> f a -> (Encoding, Maybe Encoding)
1003−
1004−instance ( RecordToEncoding arity a
1005− , RecordToEncoding arity b
1006− ) => RecordToEncoding arity (a :*: b) where
1007− recordToEncoding opts pa te tel (a :*: b) | omitNothingFields opts =
1008− (mconcat $ intersperse E.comma $
1009− filter (not . E.nullEncoding)
1010− [ fst (recordToEncoding opts pa te tel a)
1011− , fst (recordToEncoding opts pa te tel b) ]
1012− , Nothing)
1013− recordToEncoding opts pa te tel (a :*: b) =
1014− (fst (recordToEncoding opts pa te tel a) <> E.comma <>
1015− fst (recordToEncoding opts pa te tel b),
1016− Nothing)
1017−
1018−instance (Selector s, GToEncoding arity a) => RecordToEncoding arity (S1 s a) where
1019− recordToEncoding = fieldToEncoding
1020−
1021−instance OVERLAPPING_ (Selector s, ToJSON a) =>
1022− RecordToEncoding arity (S1 s (K1 i (Maybe a))) where
1023− recordToEncoding opts _ _ _ (M1 k1) | omitNothingFields opts
1024− , K1 Nothing <- k1 = (mempty, Nothing)
1025− recordToEncoding opts pa te tel m1 = fieldToEncoding opts pa te tel m1
1026−
1027−fieldToEncoding :: (Selector s, GToEncoding arity a)
1028− => Options -> Proxy arity
1029− -> (p -> Encoding) -> ([p] -> Encoding)
1030− -> S1 s a p -> (Encoding, Maybe Encoding)
1031−fieldToEncoding opts pa te tel m1 =
1032− let keyBuilder = toEncoding (fieldLabelModifier opts $ selName m1)
1033− valueBuilder = gToEncoding opts pa te tel (unM1 m1)
1034− in (keyBuilder <> E.colon <> valueBuilder, Just valueBuilder)
1068+ recordToPairs :: Options -> ToArgs enc arity a
1069+ -> f a -> pairs
1070+
1071+instance ( Monoid pairs
1072+ , RecordToPairs enc pairs arity a
1073+ , RecordToPairs enc pairs arity b
1074+ ) => RecordToPairs enc pairs arity (a :*: b)
1075+ where
1076+ recordToPairs opts (targs :: ToArgs enc arity p) (a :*: b) =
1077+ pairsOf a `mappend` pairsOf b
1078+ where
1079+ pairsOf :: (RecordToPairs enc pairs arity f) => f p -> pairs
1080+ pairsOf = recordToPairs opts targs
1081+ {-# INLINE recordToPairs #-}
1082+
1083+instance ( Selector s
1084+ , GToJSON enc arity a
1085+ , KeyValuePair enc pairs
1086+ ) => RecordToPairs enc pairs arity (S1 s a)
1087+ where
1088+ recordToPairs = fieldToPair
1089+ {-# INLINE recordToPairs #-}
1090+
1091+instance INCOHERENT_
1092+ ( Selector s
1093+ , GToJSON enc arity (K1 i (Maybe a))
1094+ , KeyValuePair enc pairs
1095+ , Monoid pairs
1096+ ) => RecordToPairs enc pairs arity (S1 s (K1 i (Maybe a)))
1097+ where
1098+ recordToPairs opts _ (M1 k1) | omitNothingFields opts
1099+ , K1 Nothing <- k1 = mempty
1100+ recordToPairs opts targs m1 = fieldToPair opts targs m1
1101+ {-# INLINE recordToPairs #-}
1102+
1103+instance INCOHERENT_
1104+ ( Selector s
1105+ , GToJSON enc arity (K1 i (Maybe a))
1106+ , KeyValuePair enc pairs
1107+ , Monoid pairs
1108+ ) => RecordToPairs enc pairs arity (S1 s (K1 i (Semigroup.Option a)))
1109+ where
1110+ recordToPairs opts targs = recordToPairs opts targs . unwrap
1111+ where
1112+ unwrap :: S1 s (K1 i (Semigroup.Option a)) p -> S1 s (K1 i (Maybe a)) p
1113+ unwrap (M1 (K1 (Semigroup.Option a))) = M1 (K1 a)
1114+ {-# INLINE recordToPairs #-}
1115+
1116+fieldToPair :: (Selector s
1117+ , GToJSON enc arity a
1118+ , KeyValuePair enc pairs)
1119+ => Options -> ToArgs enc arity p
1120+ -> S1 s a p -> pairs
1121+fieldToPair opts targs m1 =
1122+ let key = fieldLabelModifier opts (selName m1)
1123+ value = gToJSON opts targs (unM1 m1)
1124+ in key `pair` value
1125+{-# INLINE fieldToPair #-}
10351126
10361127--------------------------------------------------------------------------------
10371128
10381129class WriteProduct arity f where
10391130 writeProduct :: Options
1040− -> Proxy arity
1131+ -> ToArgs Value arity a
10411132 -> VM.MVector s Value
10421133 -> Int -- ^ index
10431134 -> Int -- ^ length
1044− -> (a -> Value)
1045− -> ([a] -> Value)
10461135 -> f a
10471136 -> ST s ()
10481137
10491138instance ( WriteProduct arity a
10501139 , WriteProduct arity b
10511140 ) => WriteProduct arity (a :*: b) where
1052− writeProduct opts pa mv ix len tj tjl (a :*: b) = do
1053− writeProduct opts pa mv ix lenL tj tjl a
1054− writeProduct opts pa mv ixR lenR tj tjl b
1141+ writeProduct opts targs mv ix len (a :*: b) = do
1142+ writeProduct opts targs mv ix lenL a
1143+ writeProduct opts targs mv ixR lenR b
10551144 where
10561145 lenL = len `unsafeShiftR` 1
10571146 lenR = len - lenL
10581147 ixR = ix + lenL
1148+ {-# INLINE writeProduct #-}
10591149
1060−instance OVERLAPPABLE_ (GToJSON arity a) => WriteProduct arity a where
1061− writeProduct opts pa mv ix _ tj tjl =
1062− VM.unsafeWrite mv ix . gToJSON opts pa tj tjl
1150+instance OVERLAPPABLE_ (GToJSON Value arity a) => WriteProduct arity a where
1151+ writeProduct opts targs mv ix _ =
1152+ VM.unsafeWrite mv ix . gToJSON opts targs
1153+ {-# INLINE writeProduct #-}
10631154
10641155--------------------------------------------------------------------------------
10651156
10661157class EncodeProduct arity f where
1067− encodeProduct :: Options -> Proxy arity
1068− -> (a -> Encoding) -> ([a] -> Encoding)
1069− -> f a -> Encoding
1158+ encodeProduct :: Options -> ToArgs Encoding arity a
1159+ -> f a -> Encoding' E.InArray
10701160
10711161instance ( EncodeProduct arity a
10721162 , EncodeProduct arity b
10731163 ) => EncodeProduct arity (a :*: b) where
1074− encodeProduct opts pa te tel (a :*: b) | omitNothingFields opts =
1075− mconcat $ intersperse E.comma $
1164+ encodeProduct opts targs (a :*: b) | omitNothingFields opts =
1165+ E.econcat $ intersperse E.comma $
10761166 filter (not . E.nullEncoding)
1077− [encodeProduct opts pa te tel a, encodeProduct opts pa te tel b]
1078− encodeProduct opts pa te tel (a :*: b) = encodeProduct opts pa te tel a <>
1079− E.comma <>
1080− encodeProduct opts pa te tel b
1167+ [encodeProduct opts targs a, encodeProduct opts targs b]
1168+ encodeProduct opts targs (a :*: b) =
1169+ encodeProduct opts targs a >*<
1170+ encodeProduct opts targs b
1171+ {-# INLINE encodeProduct #-}
10811172
1082−instance OVERLAPPABLE_ (GToEncoding arity a) => EncodeProduct arity a where
1083− encodeProduct opts = gToEncoding opts
1173+instance OVERLAPPABLE_ (GToJSON Encoding arity a) => EncodeProduct arity a where
1174+ encodeProduct opts targs a = E.retagEncoding $ gToJSON opts targs a
1175+ {-# INLINE encodeProduct #-}
10841176
10851177--------------------------------------------------------------------------------
10861178
1087−class ObjectWithSingleFieldObj arity f where
1088− objectWithSingleFieldObj :: Options -> Proxy arity
1089− -> (a -> Value) -> ([a] -> Value)
1090− -> f a -> Object
1091−
1092−instance ( ObjectWithSingleFieldObj arity a
1093− , ObjectWithSingleFieldObj arity b
1094− ) => ObjectWithSingleFieldObj arity (a :+: b) where
1095− objectWithSingleFieldObj opts pa tj tjl (L1 x) =
1096− objectWithSingleFieldObj opts pa tj tjl x
1097− objectWithSingleFieldObj opts pa tj tjl (R1 x) =
1098− objectWithSingleFieldObj opts pa tj tjl x
1099−
1100−instance ( GToJSON arity a
1101− , ConsToJSON arity a
1179+instance ( GToJSON enc arity a
1180+ , ConsToJSON enc arity a
1181+ , FromPairs enc pairs
1182+ , KeyValuePair enc pairs
11021183 , Constructor c
1103− ) => ObjectWithSingleFieldObj arity (C1 c a) where
1104− objectWithSingleFieldObj opts pa tj tjl = H.singleton typ . gToJSON opts pa tj tjl
1184+ ) => SumToJSON' ObjectWithSingleField enc arity (C1 c a)
1185+ where
1186+ sumToJSON' opts targs =
1187+ Tagged . fromPairs . (typ `pair`) . gToJSON opts targs
11051188 where
1106− typ = pack $ constructorTagModifier opts $
1189+ typ = constructorTagModifier opts $
11071190 conName (undefined :: t c a p)
11081191
11091192--------------------------------------------------------------------------------
11101193
1111−class ObjectWithSingleFieldEnc arity f where
1112− objectWithSingleFieldEnc :: Options -> Proxy arity
1113− -> (a -> Encoding) -> ([a] -> Encoding)
1114− -> f a -> Encoding
1115−
1116−instance ( ObjectWithSingleFieldEnc arity a
1117− , ObjectWithSingleFieldEnc arity b
1118− ) => ObjectWithSingleFieldEnc arity (a :+: b) where
1119− objectWithSingleFieldEnc opts pa te tel (L1 x) =
1120− objectWithSingleFieldEnc opts pa te tel x
1121− objectWithSingleFieldEnc opts pa te tel (R1 x) =
1122− objectWithSingleFieldEnc opts pa te tel x
1123−
1124−instance ( GToEncoding arity a
1125− , ConsToEncoding arity a
1126− , Constructor c
1127− ) => ObjectWithSingleFieldEnc arity (C1 c a) where
1128− objectWithSingleFieldEnc opts pa te tel v =
1129− E.openCurly <>
1130− toEncoding
1131− (constructorTagModifier opts
1132− (conName (undefined :: t c a p))) <>
1133− E.colon <>
1134− gToEncoding opts pa te tel v <>
1135− E.closeCurly
1194+instance OVERLAPPABLE_
1195+ ( ConsToJSON enc arity a
1196+ ) => SumToJSON' UntaggedValue enc arity (C1 c a)
1197+ where
1198+ sumToJSON' opts targs = Tagged . gToJSON opts targs
1199+
1200+instance OVERLAPPING_
1201+ ( Constructor c
1202+ , FromString enc
1203+ ) => SumToJSON' UntaggedValue enc arity (C1 c U1)
1204+ where
1205+ sumToJSON' opts _ _ = Tagged . fromString $
1206+ constructorTagModifier opts $ conName (undefined :: t c U1 p)
11361207
11371208-------------------------------------------------------------------------------
11381209-- Instances
@@ -1142,21 +1213,6 @@ instance ( GToEncoding arity a
11421213-- base
11431214-------------------------------------------------------------------------------
11441215
1145−instance ToJSON1 Identity where
1146− liftToJSON t _ (Identity a) = t a
1147− {-# INLINE liftToJSON #-}
1148−
1149− liftToEncoding t _ (Identity a) = t a
1150− {-# INLINE liftToEncoding #-}
1151−
1152−instance (ToJSON a) => ToJSON (Identity a) where
1153− toJSON = toJSON1
1154− {-# INLINE toJSON #-}
1155−
1156− toEncoding = toEncoding1
1157− {-# INLINE toEncoding #-}
1158−
1159−
11601216instance ToJSON2 Const where
11611217 liftToJSON2 t _ _ _ (Const x) = t x
11621218 {-# INLINE liftToJSON2 #-}
@@ -1197,8 +1253,8 @@ instance (ToJSON a) => ToJSON (Maybe a) where
11971253
11981254
11991255instance ToJSON2 Either where
1200− liftToJSON2 toA _ _toB _ (Left a) = Object $ H.singleton left (toA a)
1201− liftToJSON2 _toA _ toB _ (Right b) = Object $ H.singleton right (toB b)
1256+ liftToJSON2 toA _ _toB _ (Left a) = Object $ H.singleton "Left" (toA a)
1257+ liftToJSON2 _toA _ toB _ (Right b) = Object $ H.singleton "Right" (toB b)
12021258 {-# INLINE liftToJSON2 #-}
12031259
12041260 liftToEncoding2 toA _ _toB _ (Left a) = E.pairs $ E.pair "Left" $ toA a
@@ -1220,9 +1276,12 @@ instance (ToJSON a, ToJSON b) => ToJSON (Either a b) where
12201276 toEncoding = toEncoding2
12211277 {-# INLINE toEncoding #-}
12221278
1223−left, right :: Text
1224−left = "Left"
1225−right = "Right"
1279+instance ToJSON Void where
1280+ toJSON = absurd
1281+ {-# INLINE toJSON #-}
1282+
1283+ toEncoding = absurd
1284+ {-# INLINE toEncoding #-}
12261285
12271286
12281287instance ToJSON Bool where
@@ -1233,10 +1292,7 @@ instance ToJSON Bool where
12331292 {-# INLINE toEncoding #-}
12341293
12351294instance ToJSONKey Bool where
1236− toJSONKey = ToJSONKeyText
1237− ( (\x -> if x then "true" else "false")
1238− , (\x -> toEncoding $ if x then ("true" :: Text) else "false")
1239− )
1295+ toJSONKey = toJSONKeyText $ \x -> if x then "true" else "false"
12401296
12411297
12421298instance ToJSON Ordering where
@@ -1412,7 +1468,6 @@ instance ToJSONKey Int64 where
14121468 toJSONKey = toJSONKeyTextEnc E.int64Text
14131469 {-# INLINE toJSONKey #-}
14141470
1415−
14161471instance ToJSON Word where
14171472 toJSON = Number . fromIntegral
14181473 {-# INLINE toJSON #-}
@@ -1472,6 +1527,12 @@ instance ToJSONKey Word64 where
14721527 toJSONKey = toJSONKeyTextEnc E.word64Text
14731528 {-# INLINE toJSONKey #-}
14741529
1530+instance ToJSON CTime where
1531+ toJSON (CTime i) = toJSON i
1532+ {-# INLINE toJSON #-}
1533+
1534+ toEncoding (CTime i) = toEncoding i
1535+ {-# INLINE toEncoding #-}
14751536
14761537instance ToJSON Text where
14771538 toJSON = String
@@ -1481,9 +1542,10 @@ instance ToJSON Text where
14811542 {-# INLINE toEncoding #-}
14821543
14831544instance ToJSONKey Text where
1484− toJSONKey = ToJSONKeyText (id, toEncoding)
1545+ toJSONKey = toJSONKeyText id
14851546 {-# INLINE toJSONKey #-}
14861547
1548+
14871549instance ToJSON LT.Text where
14881550 toJSON = String . LT.toStrict
14891551 {-# INLINE toJSON #-}
@@ -1491,6 +1553,10 @@ instance ToJSON LT.Text where
14911553 toEncoding = E.lazyText
14921554 {-# INLINE toEncoding #-}
14931555
1556+instance ToJSONKey LT.Text where
1557+ toJSONKey = toJSONKeyText LT.toStrict
1558+
1559+
14941560instance ToJSON Version where
14951561 toJSON = toJSON . showVersion
14961562 {-# INLINE toJSON #-}
@@ -1498,6 +1564,9 @@ instance ToJSON Version where
14981564 toEncoding = toEncoding . showVersion
14991565 {-# INLINE toEncoding #-}
15001566
1567+instance ToJSONKey Version where
1568+ toJSONKey = toJSONKeyText (T.pack . showVersion)
1569+
15011570-------------------------------------------------------------------------------
15021571-- semigroups NonEmpty
15031572-------------------------------------------------------------------------------
@@ -1548,6 +1617,116 @@ instance (ToJSON a) => ToJSON (DList.DList a) where
15481617 toEncoding = toEncoding1
15491618 {-# INLINE toEncoding #-}
15501619
1620+-------------------------------------------------------------------------------
1621+-- transformers - Functors
1622+-------------------------------------------------------------------------------
1623+
1624+instance ToJSON1 Identity where
1625+ liftToJSON t _ (Identity a) = t a
1626+ {-# INLINE liftToJSON #-}
1627+
1628+ liftToJSONList _ tl xs = tl (map runIdentity xs)
1629+ {-# INLINE liftToJSONList #-}
1630+
1631+ liftToEncoding t _ (Identity a) = t a
1632+ {-# INLINE liftToEncoding #-}
1633+
1634+ liftToEncodingList _ tl xs = tl (map runIdentity xs)
1635+ {-# INLINE liftToEncodingList #-}
1636+
1637+instance (ToJSON a) => ToJSON (Identity a) where
1638+ toJSON = toJSON1
1639+ {-# INLINE toJSON #-}
1640+
1641+ toJSONList = liftToJSONList toJSON toJSONList
1642+ {-# INLINE toJSONList #-}
1643+
1644+ toEncoding = toEncoding1
1645+ {-# INLINE toEncoding #-}
1646+
1647+ toEncodingList = liftToEncodingList toEncoding toEncodingList
1648+ {-# INLINE toEncodingList #-}
1649+
1650+instance (ToJSONKey a) => ToJSONKey (Identity a) where
1651+ toJSONKey = contramapToJSONKeyFunction runIdentity toJSONKey
1652+ toJSONKeyList = contramapToJSONKeyFunction (map runIdentity) toJSONKeyList
1653+
1654+
1655+instance (ToJSON1 f, ToJSON1 g) => ToJSON1 (Compose f g) where
1656+ liftToJSON tv tvl (Compose x) = liftToJSON g gl x
1657+ where
1658+ g = liftToJSON tv tvl
1659+ gl = liftToJSONList tv tvl
1660+ {-# INLINE liftToJSON #-}
1661+
1662+ liftToJSONList te tel xs = liftToJSONList g gl (map getCompose xs)
1663+ where
1664+ g = liftToJSON te tel
1665+ gl = liftToJSONList te tel
1666+ {-# INLINE liftToJSONList #-}
1667+
1668+ liftToEncoding te tel (Compose x) = liftToEncoding g gl x
1669+ where
1670+ g = liftToEncoding te tel
1671+ gl = liftToEncodingList te tel
1672+ {-# INLINE liftToEncoding #-}
1673+
1674+ liftToEncodingList te tel xs = liftToEncodingList g gl (map getCompose xs)
1675+ where
1676+ g = liftToEncoding te tel
1677+ gl = liftToEncodingList te tel
1678+ {-# INLINE liftToEncodingList #-}
1679+
1680+instance (ToJSON1 f, ToJSON1 g, ToJSON a) => ToJSON (Compose f g a) where
1681+ toJSON = toJSON1
1682+ {-# INLINE toJSON #-}
1683+
1684+ toJSONList = liftToJSONList toJSON toJSONList
1685+ {-# INLINE toJSONList #-}
1686+
1687+ toEncoding = toEncoding1
1688+ {-# INLINE toEncoding #-}
1689+
1690+ toEncodingList = liftToEncodingList toEncoding toEncodingList
1691+ {-# INLINE toEncodingList #-}
1692+
1693+
1694+instance (ToJSON1 f, ToJSON1 g) => ToJSON1 (Product f g) where
1695+ liftToJSON tv tvl (Pair x y) = liftToJSON2 tx txl ty tyl (x, y)
1696+ where
1697+ tx = liftToJSON tv tvl
1698+ txl = liftToJSONList tv tvl
1699+ ty = liftToJSON tv tvl
1700+ tyl = liftToJSONList tv tvl
1701+
1702+ liftToEncoding te tel (Pair x y) = liftToEncoding2 tx txl ty tyl (x, y)
1703+ where
1704+ tx = liftToEncoding te tel
1705+ txl = liftToEncodingList te tel
1706+ ty = liftToEncoding te tel
1707+ tyl = liftToEncodingList te tel
1708+
1709+instance (ToJSON1 f, ToJSON1 g, ToJSON a) => ToJSON (Product f g a) where
1710+ toJSON = toJSON1
1711+ {-# INLINE toJSON #-}
1712+
1713+ toEncoding = toEncoding1
1714+ {-# INLINE toEncoding #-}
1715+
1716+instance (ToJSON1 f, ToJSON1 g) => ToJSON1 (Sum f g) where
1717+ liftToJSON tv tvl (InL x) = Object $ H.singleton "InL" (liftToJSON tv tvl x)
1718+ liftToJSON tv tvl (InR y) = Object $ H.singleton "InR" (liftToJSON tv tvl y)
1719+
1720+ liftToEncoding te tel (InL x) = E.pairs $ E.pair "InL" $ liftToEncoding te tel x
1721+ liftToEncoding te tel (InR y) = E.pairs $ E.pair "InR" $ liftToEncoding te tel y
1722+
1723+instance (ToJSON1 f, ToJSON1 g, ToJSON a) => ToJSON (Sum f g a) where
1724+ toJSON = toJSON1
1725+ {-# INLINE toJSON #-}
1726+
1727+ toEncoding = toEncoding1
1728+ {-# INLINE toEncoding #-}
1729+
15511730-------------------------------------------------------------------------------
15521731-- containers
15531732-------------------------------------------------------------------------------
@@ -1613,17 +1792,15 @@ instance ToJSON a => ToJSON (IntMap.IntMap a) where
16131792
16141793instance ToJSONKey k => ToJSON1 (M.Map k) where
16151794 liftToJSON g _ = case toJSONKey of
1616− ToJSONKeyText (f,_) -> Object . mapHashKeyVal f g
1617− ToJSONKeyValue (f,_) -> Array . V.fromList . map (toJSONPair f g) . M.toList
1795+ ToJSONKeyText f _ -> Object . mapHashKeyVal f g
1796+ ToJSONKeyValue f _ -> Array . V.fromList . map (toJSONPair f g) . M.toList
16181797 {-# INLINE liftToJSON #-}
16191798
1620− -- liftToEncoding :: forall a. (a -> Encoding) -> ([a] -> Encoding) -> M.Map k a -> Encoding
16211799 liftToEncoding g _ = case toJSONKey of
1622− ToJSONKeyText (_,f) -> dict f g M.foldrWithKey
1623− ToJSONKeyValue (_,f) -> listEncoding (pairEncoding f) . M.toList
1800+ ToJSONKeyText _ f -> dict f g M.foldrWithKey
1801+ ToJSONKeyValue _ f -> listEncoding (pairEncoding f) . M.toList
16241802 where
1625− -- pairEncoding :: (k -> Encoding) -> (k, a) -> Encoding
1626− pairEncoding f (a, b) = tuple $ f a >*< g b
1803+ pairEncoding f (a, b) = E.list id [f a, g b]
16271804 {-# INLINE liftToEncoding #-}
16281805
16291806
@@ -1661,6 +1838,17 @@ instance (ToJSON v) => ToJSON (Tree.Tree v) where
16611838 toEncoding = toEncoding1
16621839 {-# INLINE toEncoding #-}
16631840
1841+-------------------------------------------------------------------------------
1842+-- uuid
1843+-------------------------------------------------------------------------------
1844+
1845+instance ToJSON UUID.UUID where
1846+ toJSON = toJSON . UUID.toText
1847+ toEncoding = E.unsafeToEncoding . EB.quote . B.byteString . UUID.toASCIIBytes
1848+
1849+instance ToJSONKey UUID.UUID where
1850+ toJSONKey = ToJSONKeyText UUID.toText $
1851+ E.unsafeToEncoding . EB.quote . B.byteString . UUID.toASCIIBytes
16641852
16651853-------------------------------------------------------------------------------
16661854-- vector
@@ -1674,10 +1862,12 @@ instance ToJSON1 Vector where
16741862 {-# INLINE liftToEncoding #-}
16751863
16761864instance (ToJSON a) => ToJSON (Vector a) where
1677− toJSON = Array . V.map toJSON
1865+ {-# SPECIALIZE instance ToJSON Array #-}
1866+
1867+ toJSON = toJSON1
16781868 {-# INLINE toJSON #-}
16791869
1680− toEncoding = encodeVector
1870+ toEncoding = toEncoding1
16811871 {-# INLINE toEncoding #-}
16821872
16831873encodeVector :: (ToJSON a, VG.Vector v a) => v a -> Encoding
@@ -1732,20 +1922,21 @@ instance (ToJSON a) => ToJSON (HashSet.HashSet a) where
17321922
17331923instance ToJSONKey k => ToJSON1 (H.HashMap k) where
17341924 liftToJSON g _ = case toJSONKey of
1735− ToJSONKeyText (f,_) -> Object . mapKeyVal f g
1736− ToJSONKeyValue (f,_) -> Array . V.fromList . map (toJSONPair f g) . H.toList
1925+ ToJSONKeyText f _ -> Object . mapKeyVal f g
1926+ ToJSONKeyValue f _ -> Array . V.fromList . map (toJSONPair f g) . H.toList
17371927 {-# INLINE liftToJSON #-}
17381928
17391929 -- liftToEncoding :: forall a. (a -> Encoding) -> ([a] -> Encoding) -> H.HashMap k a -> Encoding
17401930 liftToEncoding g _ = case toJSONKey of
1741− ToJSONKeyText (_,f) -> dict f g H.foldrWithKey
1742− ToJSONKeyValue (_,f) -> listEncoding (pairEncoding f) . H.toList
1931+ ToJSONKeyText _ f -> dict f g H.foldrWithKey
1932+ ToJSONKeyValue _ f -> listEncoding (pairEncoding f) . H.toList
17431933 where
1744− -- pairEncoding :: (k -> Encoding) -> (k, a) -> Encoding
1745− pairEncoding f (a, b) = tuple $ f a >*< g b
1934+ pairEncoding f (a, b) = E.list id [f a, g b]
17461935 {-# INLINE liftToEncoding #-}
17471936
17481937instance (ToJSON v, ToJSONKey k) => ToJSON (H.HashMap k v) where
1938+ {-# SPECIALIZE instance ToJSON Object #-}
1939+
17491940 toJSON = toJSON1
17501941 {-# INLINE toJSON #-}
17511942
@@ -1775,6 +1966,32 @@ dotNetTime (DotNetTime t) = secs ++ formatMillis t ++ ")/"
17751966formatMillis :: (FormatTime t) => t -> String
17761967formatMillis = take 3 . formatTime defaultTimeLocale "%q"
17771968
1969+-------------------------------------------------------------------------------
1970+-- primitive
1971+-------------------------------------------------------------------------------
1972+
1973+instance ToJSON a => ToJSON (PM.Array a) where
1974+ -- note: we could do better than this if vector exposed the data
1975+ -- constructor in Data.Vector.
1976+ toJSON = toJSON . Exts.toList
1977+ toEncoding = toEncoding . Exts.toList
1978+
1979+instance ToJSON a => ToJSON (PM.SmallArray a) where
1980+ toJSON = toJSON . Exts.toList
1981+ toEncoding = toEncoding . Exts.toList
1982+
1983+#if (MIN_VERSION_primitive(0,6,4))
1984+instance (PM.Prim a,ToJSON a) => ToJSON (PM.PrimArray a) where
1985+ toJSON = toJSON . Exts.toList
1986+ toEncoding = toEncoding . Exts.toList
1987+
1988+#if !MIN_VERSION_primitive(0,7,0)
1989+instance (PM.PrimUnlifted a,ToJSON a) => ToJSON (PM.UnliftedArray a) where
1990+ toJSON = toJSON . Exts.toList
1991+ toEncoding = toEncoding . Exts.toList
1992+#endif
1993+#endif
1994+
17781995-------------------------------------------------------------------------------
17791996-- time
17801997-------------------------------------------------------------------------------
@@ -1819,15 +2036,15 @@ instance ToJSONKey UTCTime where
18192036 toJSONKey = toJSONKeyTextEnc E.utcTime
18202037
18212038-- | Encode something t a JSON string.
1822−stringEncoding :: Encoding -> Value
2039+stringEncoding :: Encoding' Text -> Value
18232040stringEncoding = String
18242041 . T.dropAround (== '"')
18252042 . T.decodeLatin1
18262043 . L.toStrict
1827− . B.toLazyByteString
1828− . fromEncoding
2044+ . E.encodingToLazyByteString
18292045{-# INLINE stringEncoding #-}
18302046
2047+
18312048instance ToJSON NominalDiffTime where
18322049 toJSON = Number . realToFrac
18332050 {-# INLINE toJSON #-}
@@ -1835,18 +2052,70 @@ instance ToJSON NominalDiffTime where
18352052 toEncoding = E.scientific . realToFrac
18362053 {-# INLINE toEncoding #-}
18372054
2055+
2056+instance ToJSON DiffTime where
2057+ toJSON = Number . realToFrac
2058+ {-# INLINE toJSON #-}
2059+
2060+ toEncoding = E.scientific . realToFrac
2061+ {-# INLINE toEncoding #-}
2062+
2063+-- | Encoded as number
2064+instance ToJSON SystemTime where
2065+ toJSON (MkSystemTime secs nsecs) =
2066+ toJSON (fromIntegral secs + fromIntegral nsecs / 1000000000 :: Nano)
2067+ toEncoding (MkSystemTime secs nsecs) =
2068+ toEncoding (fromIntegral secs + fromIntegral nsecs / 1000000000 :: Nano)
2069+
2070+instance ToJSON CalendarDiffTime where
2071+ toJSON (CalendarDiffTime m nt) = object
2072+ [ "months" .= m
2073+ , "time" .= nt
2074+ ]
2075+ toEncoding (CalendarDiffTime m nt) = E.pairs
2076+ ("months" .= m <> "time" .= nt)
2077+
2078+instance ToJSON CalendarDiffDays where
2079+ toJSON (CalendarDiffDays m d) = object
2080+ [ "months" .= m
2081+ , "days" .= d
2082+ ]
2083+ toEncoding (CalendarDiffDays m d) = E.pairs
2084+ ("months" .= m <> "days" .= d)
2085+
2086+instance ToJSON DayOfWeek where
2087+ toJSON Monday = "monday"
2088+ toJSON Tuesday = "tuesday"
2089+ toJSON Wednesday = "wednesday"
2090+ toJSON Thursday = "thursday"
2091+ toJSON Friday = "friday"
2092+ toJSON Saturday = "saturday"
2093+ toJSON Sunday = "sunday"
2094+
2095+toEncodingDayOfWeek :: DayOfWeek -> E.Encoding' Text
2096+toEncodingDayOfWeek Monday = E.unsafeToEncoding "\"monday\""
2097+toEncodingDayOfWeek Tuesday = E.unsafeToEncoding "\"tuesday\""
2098+toEncodingDayOfWeek Wednesday = E.unsafeToEncoding "\"wednesday\""
2099+toEncodingDayOfWeek Thursday = E.unsafeToEncoding "\"thursday\""
2100+toEncodingDayOfWeek Friday = E.unsafeToEncoding "\"friday\""
2101+toEncodingDayOfWeek Saturday = E.unsafeToEncoding "\"saturday\""
2102+toEncodingDayOfWeek Sunday = E.unsafeToEncoding "\"sunday\""
2103+
2104+instance ToJSONKey DayOfWeek where
2105+ toJSONKey = toJSONKeyTextEnc toEncodingDayOfWeek
2106+
18382107-------------------------------------------------------------------------------
18392108-- base Monoid/Semigroup
18402109-------------------------------------------------------------------------------
18412110
1842−instance ToJSON1 Dual where
1843− liftToJSON t _ = t . getDual
2111+instance ToJSON1 Monoid.Dual where
2112+ liftToJSON t _ = t . Monoid.getDual
18442113 {-# INLINE liftToJSON #-}
18452114
1846− liftToEncoding t _ = t . getDual
2115+ liftToEncoding t _ = t . Monoid.getDual
18472116 {-# INLINE liftToEncoding #-}
18482117
1849−instance ToJSON a => ToJSON (Dual a) where
2118+instance ToJSON a => ToJSON (Monoid.Dual a) where
18502119 toJSON = toJSON1
18512120 {-# INLINE toJSON #-}
18522121
@@ -1854,14 +2123,14 @@ instance ToJSON a => ToJSON (Dual a) where
18542123 {-# INLINE toEncoding #-}
18552124
18562125
1857−instance ToJSON1 First where
1858− liftToJSON t to' = liftToJSON t to' . getFirst
2126+instance ToJSON1 Monoid.First where
2127+ liftToJSON t to' = liftToJSON t to' . Monoid.getFirst
18592128 {-# INLINE liftToJSON #-}
18602129
1861− liftToEncoding t to' = liftToEncoding t to' . getFirst
2130+ liftToEncoding t to' = liftToEncoding t to' . Monoid.getFirst
18622131 {-# INLINE liftToEncoding #-}
18632132
1864−instance ToJSON a => ToJSON (First a) where
2133+instance ToJSON a => ToJSON (Monoid.First a) where
18652134 toJSON = toJSON1
18662135 {-# INLINE toJSON #-}
18672136
@@ -1869,14 +2138,103 @@ instance ToJSON a => ToJSON (First a) where
18692138 {-# INLINE toEncoding #-}
18702139
18712140
1872−instance ToJSON1 Last where
1873− liftToJSON t to' = liftToJSON t to' . getLast
2141+instance ToJSON1 Monoid.Last where
2142+ liftToJSON t to' = liftToJSON t to' . Monoid.getLast
18742143 {-# INLINE liftToJSON #-}
18752144
1876− liftToEncoding t to' = liftToEncoding t to' . getLast
2145+ liftToEncoding t to' = liftToEncoding t to' . Monoid.getLast
18772146 {-# INLINE liftToEncoding #-}
18782147
1879−instance ToJSON a => ToJSON (Last a) where
2148+instance ToJSON a => ToJSON (Monoid.Last a) where
2149+ toJSON = toJSON1
2150+ {-# INLINE toJSON #-}
2151+
2152+ toEncoding = toEncoding1
2153+ {-# INLINE toEncoding #-}
2154+
2155+
2156+instance ToJSON1 Semigroup.Min where
2157+ liftToJSON t _ (Semigroup.Min x) = t x
2158+ {-# INLINE liftToJSON #-}
2159+
2160+ liftToEncoding t _ (Semigroup.Min x) = t x
2161+ {-# INLINE liftToEncoding #-}
2162+
2163+instance ToJSON a => ToJSON (Semigroup.Min a) where
2164+ toJSON = toJSON1
2165+ {-# INLINE toJSON #-}
2166+
2167+ toEncoding = toEncoding1
2168+ {-# INLINE toEncoding #-}
2169+
2170+
2171+instance ToJSON1 Semigroup.Max where
2172+ liftToJSON t _ (Semigroup.Max x) = t x
2173+ {-# INLINE liftToJSON #-}
2174+
2175+ liftToEncoding t _ (Semigroup.Max x) = t x
2176+ {-# INLINE liftToEncoding #-}
2177+
2178+instance ToJSON a => ToJSON (Semigroup.Max a) where
2179+ toJSON = toJSON1
2180+ {-# INLINE toJSON #-}
2181+
2182+ toEncoding = toEncoding1
2183+ {-# INLINE toEncoding #-}
2184+
2185+instance ToJSON1 Semigroup.First where
2186+ liftToJSON t _ (Semigroup.First x) = t x
2187+ {-# INLINE liftToJSON #-}
2188+
2189+ liftToEncoding t _ (Semigroup.First x) = t x
2190+ {-# INLINE liftToEncoding #-}
2191+
2192+instance ToJSON a => ToJSON (Semigroup.First a) where
2193+ toJSON = toJSON1
2194+ {-# INLINE toJSON #-}
2195+
2196+ toEncoding = toEncoding1
2197+ {-# INLINE toEncoding #-}
2198+
2199+
2200+instance ToJSON1 Semigroup.Last where
2201+ liftToJSON t _ (Semigroup.Last x) = t x
2202+ {-# INLINE liftToJSON #-}
2203+
2204+ liftToEncoding t _ (Semigroup.Last x) = t x
2205+ {-# INLINE liftToEncoding #-}
2206+
2207+instance ToJSON a => ToJSON (Semigroup.Last a) where
2208+ toJSON = toJSON1
2209+ {-# INLINE toJSON #-}
2210+
2211+ toEncoding = toEncoding1
2212+ {-# INLINE toEncoding #-}
2213+
2214+
2215+instance ToJSON1 Semigroup.WrappedMonoid where
2216+ liftToJSON t _ (Semigroup.WrapMonoid x) = t x
2217+ {-# INLINE liftToJSON #-}
2218+
2219+ liftToEncoding t _ (Semigroup.WrapMonoid x) = t x
2220+ {-# INLINE liftToEncoding #-}
2221+
2222+instance ToJSON a => ToJSON (Semigroup.WrappedMonoid a) where
2223+ toJSON = toJSON1
2224+ {-# INLINE toJSON #-}
2225+
2226+ toEncoding = toEncoding1
2227+ {-# INLINE toEncoding #-}
2228+
2229+
2230+instance ToJSON1 Semigroup.Option where
2231+ liftToJSON t to' = liftToJSON t to' . Semigroup.getOption
2232+ {-# INLINE liftToJSON #-}
2233+
2234+ liftToEncoding t to' = liftToEncoding t to' . Semigroup.getOption
2235+ {-# INLINE liftToEncoding #-}
2236+
2237+instance ToJSON a => ToJSON (Semigroup.Option a) where
18802238 toJSON = toJSON1
18812239 {-# INLINE toJSON #-}
18822240
@@ -1887,6 +2245,13 @@ instance ToJSON a => ToJSON (Last a) where
18872245-- tagged
18882246-------------------------------------------------------------------------------
18892247
2248+instance ToJSON1 Proxy where
2249+ liftToJSON _ _ _ = Null
2250+ {-# INLINE liftToJSON #-}
2251+
2252+ liftToEncoding _ _ _ = E.null_
2253+ {-# INLINE liftToEncoding #-}
2254+
18902255instance ToJSON (Proxy a) where
18912256 toJSON _ = Null
18922257 {-# INLINE toJSON #-}
@@ -1895,6 +2260,13 @@ instance ToJSON (Proxy a) where
18952260 {-# INLINE toEncoding #-}
18962261
18972262
2263+instance ToJSON2 Tagged where
2264+ liftToJSON2 _ _ t _ (Tagged x) = t x
2265+ {-# INLINE liftToJSON2 #-}
2266+
2267+ liftToEncoding2 _ _ t _ (Tagged x) = t x
2268+ {-# INLINE liftToEncoding2 #-}
2269+
18982270instance ToJSON1 (Tagged a) where
18992271 liftToJSON t _ (Tagged x) = t x
19002272 {-# INLINE liftToJSON #-}
@@ -1909,7 +2281,6 @@ instance ToJSON b => ToJSON (Tagged a b) where
19092281 toEncoding = toEncoding1
19102282 {-# INLINE toEncoding #-}
19112283
1912−
19132284instance ToJSONKey b => ToJSONKey (Tagged a b) where
19142285 toJSONKey = contramapToJSONKeyFunction unTagged toJSONKey
19152286 toJSONKeyList = contramapToJSONKeyFunction (fmap unTagged) toJSONKeyList
@@ -1918,34 +2289,22 @@ instance ToJSONKey b => ToJSONKey (Tagged a b) where
19182289-- Instances for converting t map keys
19192290-------------------------------------------------------------------------------
19202291
1921−-- | TODO: Move ToJSONKEyFunction to .Types(.Internal),
1922−-- export and document this function from there
1923−toJSONKeyTextEnc :: (a -> Encoding) -> ToJSONKeyFunction a
1924−toJSONKeyTextEnc e = ToJSONKeyText
1925− -- TODO: dropAround is also used in stringEncoding, which is unfortunate atm
1926− ( T.dropAround (== '"') . T.decodeLatin1 . L.toStrict . B.toLazyByteString . fromEncoding . e
1927− , e
1928− )
1929−
19302292instance (ToJSON a, ToJSON b) => ToJSONKey (a,b)
19312293instance (ToJSON a, ToJSON b, ToJSON c) => ToJSONKey (a,b,c)
19322294instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d) => ToJSONKey (a,b,c,d)
19332295
19342296instance ToJSONKey Char where
1935− toJSONKey = ToJSONKeyText (T.singleton, toEncoding)
1936− toJSONKeyList = ToJSONKeyText (T.pack, toEncoding . T.pack)
2297+ toJSONKey = ToJSONKeyText T.singleton (E.string . (:[]))
2298+ toJSONKeyList = toJSONKeyText T.pack
19372299
19382300instance (ToJSONKey a, ToJSON a) => ToJSONKey [a] where
19392301 toJSONKey = toJSONKeyList
19402302
1941−instance (ToJSONKey a, ToJSON a) => ToJSONKey (Identity a) where
1942− toJSONKey = contramapToJSONKeyFunction runIdentity toJSONKey
1943−
19442303-------------------------------------------------------------------------------
1945−-- Tuple instances, see tuple-instances-to.hs
2304+-- Tuple instances
19462305-------------------------------------------------------------------------------
19472306
1948−instance ToJSON2 ((,) ) where
2307+instance ToJSON2 (,) where
19492308 liftToJSON2 toA _ toB _ (a, b) = Array $ V.create $ do
19502309 mv <- VM.unsafeNew 2
19512310 VM.unsafeWrite mv 0 (toA a)
@@ -1953,9 +2312,7 @@ instance ToJSON2 ((,) ) where
19532312 return mv
19542313 {-# INLINE liftToJSON2 #-}
19552314
1956− liftToEncoding2 toA _ toB _ (a, b) = tuple $
1957− toA a >*<
1958− toB b
2315+ liftToEncoding2 toA _ toB _ (a, b) = E.list id [toA a, toB b]
19592316 {-# INLINE liftToEncoding2 #-}
19602317
19612318instance (ToJSON a) => ToJSON1 ((,) a) where
@@ -1979,10 +2336,11 @@ instance (ToJSON a) => ToJSON2 ((,,) a) where
19792336 return mv
19802337 {-# INLINE liftToJSON2 #-}
19812338
1982− liftToEncoding2 toB _ toC _ (a, b, c) = tuple $
1983− toEncoding a >*<
1984− toB b >*<
1985− toC c
2339+ liftToEncoding2 toB _ toC _ (a, b, c) = E.list id
2340+ [ toEncoding a
2341+ , toB b
2342+ , toC c
2343+ ]
19862344 {-# INLINE liftToEncoding2 #-}
19872345
19882346instance (ToJSON a, ToJSON b) => ToJSON1 ((,,) a b) where
@@ -2007,11 +2365,12 @@ instance (ToJSON a, ToJSON b) => ToJSON2 ((,,,) a b) where
20072365 return mv
20082366 {-# INLINE liftToJSON2 #-}
20092367
2010− liftToEncoding2 toC _ toD _ (a, b, c, d) = tuple $
2011− toEncoding a >*<
2012− toEncoding b >*<
2013− toC c >*<
2014− toD d
2368+ liftToEncoding2 toC _ toD _ (a, b, c, d) = E.list id
2369+ [ toEncoding a
2370+ , toEncoding b
2371+ , toC c
2372+ , toD d
2373+ ]
20152374 {-# INLINE liftToEncoding2 #-}
20162375
20172376instance (ToJSON a, ToJSON b, ToJSON c) => ToJSON1 ((,,,) a b c) where
@@ -2037,12 +2396,13 @@ instance (ToJSON a, ToJSON b, ToJSON c) => ToJSON2 ((,,,,) a b c) where
20372396 return mv
20382397 {-# INLINE liftToJSON2 #-}
20392398
2040− liftToEncoding2 toD _ toE _ (a, b, c, d, e) = tuple $
2041− toEncoding a >*<
2042− toEncoding b >*<
2043− toEncoding c >*<
2044− toD d >*<
2045− toE e
2399+ liftToEncoding2 toD _ toE _ (a, b, c, d, e) = E.list id
2400+ [ toEncoding a
2401+ , toEncoding b
2402+ , toEncoding c
2403+ , toD d
2404+ , toE e
2405+ ]
20462406 {-# INLINE liftToEncoding2 #-}
20472407
20482408instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d) => ToJSON1 ((,,,,) a b c d) where
@@ -2069,13 +2429,14 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d) => ToJSON2 ((,,,,,) a b c d) w
20692429 return mv
20702430 {-# INLINE liftToJSON2 #-}
20712431
2072− liftToEncoding2 toE _ toF _ (a, b, c, d, e, f) = tuple $
2073− toEncoding a >*<
2074− toEncoding b >*<
2075− toEncoding c >*<
2076− toEncoding d >*<
2077− toE e >*<
2078− toF f
2432+ liftToEncoding2 toE _ toF _ (a, b, c, d, e, f) = E.list id
2433+ [ toEncoding a
2434+ , toEncoding b
2435+ , toEncoding c
2436+ , toEncoding d
2437+ , toE e
2438+ , toF f
2439+ ]
20792440 {-# INLINE liftToEncoding2 #-}
20802441
20812442instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e) => ToJSON1 ((,,,,,) a b c d e) where
@@ -2103,14 +2464,15 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e) => ToJSON2 ((,,,,,,)
21032464 return mv
21042465 {-# INLINE liftToJSON2 #-}
21052466
2106− liftToEncoding2 toF _ toG _ (a, b, c, d, e, f, g) = tuple $
2107− toEncoding a >*<
2108− toEncoding b >*<
2109− toEncoding c >*<
2110− toEncoding d >*<
2111− toEncoding e >*<
2112− toF f >*<
2113− toG g
2467+ liftToEncoding2 toF _ toG _ (a, b, c, d, e, f, g) = E.list id
2468+ [ toEncoding a
2469+ , toEncoding b
2470+ , toEncoding c
2471+ , toEncoding d
2472+ , toEncoding e
2473+ , toF f
2474+ , toG g
2475+ ]
21142476 {-# INLINE liftToEncoding2 #-}
21152477
21162478instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f) => ToJSON1 ((,,,,,,) a b c d e f) where
@@ -2139,15 +2501,16 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f) => ToJSON2
21392501 return mv
21402502 {-# INLINE liftToJSON2 #-}
21412503
2142− liftToEncoding2 toG _ toH _ (a, b, c, d, e, f, g, h) = tuple $
2143− toEncoding a >*<
2144− toEncoding b >*<
2145− toEncoding c >*<
2146− toEncoding d >*<
2147− toEncoding e >*<
2148− toEncoding f >*<
2149− toG g >*<
2150− toH h
2504+ liftToEncoding2 toG _ toH _ (a, b, c, d, e, f, g, h) = E.list id
2505+ [ toEncoding a
2506+ , toEncoding b
2507+ , toEncoding c
2508+ , toEncoding d
2509+ , toEncoding e
2510+ , toEncoding f
2511+ , toG g
2512+ , toH h
2513+ ]
21512514 {-# INLINE liftToEncoding2 #-}
21522515
21532516instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g) => ToJSON1 ((,,,,,,,) a b c d e f g) where
@@ -2177,16 +2540,17 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g)
21772540 return mv
21782541 {-# INLINE liftToJSON2 #-}
21792542
2180− liftToEncoding2 toH _ toI _ (a, b, c, d, e, f, g, h, i) = tuple $
2181− toEncoding a >*<
2182− toEncoding b >*<
2183− toEncoding c >*<
2184− toEncoding d >*<
2185− toEncoding e >*<
2186− toEncoding f >*<
2187− toEncoding g >*<
2188− toH h >*<
2189− toI i
2543+ liftToEncoding2 toH _ toI _ (a, b, c, d, e, f, g, h, i) = E.list id
2544+ [ toEncoding a
2545+ , toEncoding b
2546+ , toEncoding c
2547+ , toEncoding d
2548+ , toEncoding e
2549+ , toEncoding f
2550+ , toEncoding g
2551+ , toH h
2552+ , toI i
2553+ ]
21902554 {-# INLINE liftToEncoding2 #-}
21912555
21922556instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g, ToJSON h) => ToJSON1 ((,,,,,,,,) a b c d e f g h) where
@@ -2217,17 +2581,18 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g,
22172581 return mv
22182582 {-# INLINE liftToJSON2 #-}
22192583
2220− liftToEncoding2 toI _ toJ _ (a, b, c, d, e, f, g, h, i, j) = tuple $
2221− toEncoding a >*<
2222− toEncoding b >*<
2223− toEncoding c >*<
2224− toEncoding d >*<
2225− toEncoding e >*<
2226− toEncoding f >*<
2227− toEncoding g >*<
2228− toEncoding h >*<
2229− toI i >*<
2230− toJ j
2584+ liftToEncoding2 toI _ toJ _ (a, b, c, d, e, f, g, h, i, j) = E.list id
2585+ [ toEncoding a
2586+ , toEncoding b
2587+ , toEncoding c
2588+ , toEncoding d
2589+ , toEncoding e
2590+ , toEncoding f
2591+ , toEncoding g
2592+ , toEncoding h
2593+ , toI i
2594+ , toJ j
2595+ ]
22312596 {-# INLINE liftToEncoding2 #-}
22322597
22332598instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g, ToJSON h, ToJSON i) => ToJSON1 ((,,,,,,,,,) a b c d e f g h i) where
@@ -2259,18 +2624,19 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g,
22592624 return mv
22602625 {-# INLINE liftToJSON2 #-}
22612626
2262− liftToEncoding2 toJ _ toK _ (a, b, c, d, e, f, g, h, i, j, k) = tuple $
2263− toEncoding a >*<
2264− toEncoding b >*<
2265− toEncoding c >*<
2266− toEncoding d >*<
2267− toEncoding e >*<
2268− toEncoding f >*<
2269− toEncoding g >*<
2270− toEncoding h >*<
2271− toEncoding i >*<
2272− toJ j >*<
2273− toK k
2627+ liftToEncoding2 toJ _ toK _ (a, b, c, d, e, f, g, h, i, j, k) = E.list id
2628+ [ toEncoding a
2629+ , toEncoding b
2630+ , toEncoding c
2631+ , toEncoding d
2632+ , toEncoding e
2633+ , toEncoding f
2634+ , toEncoding g
2635+ , toEncoding h
2636+ , toEncoding i
2637+ , toJ j
2638+ , toK k
2639+ ]
22742640 {-# INLINE liftToEncoding2 #-}
22752641
22762642instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g, ToJSON h, ToJSON i, ToJSON j) => ToJSON1 ((,,,,,,,,,,) a b c d e f g h i j) where
@@ -2303,19 +2669,20 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g,
23032669 return mv
23042670 {-# INLINE liftToJSON2 #-}
23052671
2306− liftToEncoding2 toK _ toL _ (a, b, c, d, e, f, g, h, i, j, k, l) = tuple $
2307− toEncoding a >*<
2308− toEncoding b >*<
2309− toEncoding c >*<
2310− toEncoding d >*<
2311− toEncoding e >*<
2312− toEncoding f >*<
2313− toEncoding g >*<
2314− toEncoding h >*<
2315− toEncoding i >*<
2316− toEncoding j >*<
2317− toK k >*<
2318− toL l
2672+ liftToEncoding2 toK _ toL _ (a, b, c, d, e, f, g, h, i, j, k, l) = E.list id
2673+ [ toEncoding a
2674+ , toEncoding b
2675+ , toEncoding c
2676+ , toEncoding d
2677+ , toEncoding e
2678+ , toEncoding f
2679+ , toEncoding g
2680+ , toEncoding h
2681+ , toEncoding i
2682+ , toEncoding j
2683+ , toK k
2684+ , toL l
2685+ ]
23192686 {-# INLINE liftToEncoding2 #-}
23202687
23212688instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g, ToJSON h, ToJSON i, ToJSON j, ToJSON k) => ToJSON1 ((,,,,,,,,,,,) a b c d e f g h i j k) where
@@ -2349,20 +2716,21 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g,
23492716 return mv
23502717 {-# INLINE liftToJSON2 #-}
23512718
2352− liftToEncoding2 toL _ toM _ (a, b, c, d, e, f, g, h, i, j, k, l, m) = tuple $
2353− toEncoding a >*<
2354− toEncoding b >*<
2355− toEncoding c >*<
2356− toEncoding d >*<
2357− toEncoding e >*<
2358− toEncoding f >*<
2359− toEncoding g >*<
2360− toEncoding h >*<
2361− toEncoding i >*<
2362− toEncoding j >*<
2363− toEncoding k >*<
2364− toL l >*<
2365− toM m
2719+ liftToEncoding2 toL _ toM _ (a, b, c, d, e, f, g, h, i, j, k, l, m) = E.list id
2720+ [ toEncoding a
2721+ , toEncoding b
2722+ , toEncoding c
2723+ , toEncoding d
2724+ , toEncoding e
2725+ , toEncoding f
2726+ , toEncoding g
2727+ , toEncoding h
2728+ , toEncoding i
2729+ , toEncoding j
2730+ , toEncoding k
2731+ , toL l
2732+ , toM m
2733+ ]
23662734 {-# INLINE liftToEncoding2 #-}
23672735
23682736instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g, ToJSON h, ToJSON i, ToJSON j, ToJSON k, ToJSON l) => ToJSON1 ((,,,,,,,,,,,,) a b c d e f g h i j k l) where
@@ -2397,21 +2765,22 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g,
23972765 return mv
23982766 {-# INLINE liftToJSON2 #-}
23992767
2400− liftToEncoding2 toM _ toN _ (a, b, c, d, e, f, g, h, i, j, k, l, m, n) = tuple $
2401− toEncoding a >*<
2402− toEncoding b >*<
2403− toEncoding c >*<
2404− toEncoding d >*<
2405− toEncoding e >*<
2406− toEncoding f >*<
2407− toEncoding g >*<
2408− toEncoding h >*<
2409− toEncoding i >*<
2410− toEncoding j >*<
2411− toEncoding k >*<
2412− toEncoding l >*<
2413− toM m >*<
2414− toN n
2768+ liftToEncoding2 toM _ toN _ (a, b, c, d, e, f, g, h, i, j, k, l, m, n) = E.list id
2769+ [ toEncoding a
2770+ , toEncoding b
2771+ , toEncoding c
2772+ , toEncoding d
2773+ , toEncoding e
2774+ , toEncoding f
2775+ , toEncoding g
2776+ , toEncoding h
2777+ , toEncoding i
2778+ , toEncoding j
2779+ , toEncoding k
2780+ , toEncoding l
2781+ , toM m
2782+ , toN n
2783+ ]
24152784 {-# INLINE liftToEncoding2 #-}
24162785
24172786instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g, ToJSON h, ToJSON i, ToJSON j, ToJSON k, ToJSON l, ToJSON m) => ToJSON1 ((,,,,,,,,,,,,,) a b c d e f g h i j k l m) where
@@ -2447,22 +2816,23 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g,
24472816 return mv
24482817 {-# INLINE liftToJSON2 #-}
24492818
2450− liftToEncoding2 toN _ toO _ (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) = tuple $
2451− toEncoding a >*<
2452− toEncoding b >*<
2453− toEncoding c >*<
2454− toEncoding d >*<
2455− toEncoding e >*<
2456− toEncoding f >*<
2457− toEncoding g >*<
2458− toEncoding h >*<
2459− toEncoding i >*<
2460− toEncoding j >*<
2461− toEncoding k >*<
2462− toEncoding l >*<
2463− toEncoding m >*<
2464− toN n >*<
2465− toO o
2819+ liftToEncoding2 toN _ toO _ (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) = E.list id
2820+ [ toEncoding a
2821+ , toEncoding b
2822+ , toEncoding c
2823+ , toEncoding d
2824+ , toEncoding e
2825+ , toEncoding f
2826+ , toEncoding g
2827+ , toEncoding h
2828+ , toEncoding i
2829+ , toEncoding j
2830+ , toEncoding k
2831+ , toEncoding l
2832+ , toEncoding m
2833+ , toN n
2834+ , toO o
2835+ ]
24662836 {-# INLINE liftToEncoding2 #-}
24672837
24682838instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g, ToJSON h, ToJSON i, ToJSON j, ToJSON k, ToJSON l, ToJSON m, ToJSON n) => ToJSON1 ((,,,,,,,,,,,,,,) a b c d e f g h i j k l m n) where
@@ -2476,3 +2846,27 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g,
24762846 {-# INLINE toJSON #-}
24772847 toEncoding = toEncoding2
24782848 {-# INLINE toEncoding #-}
2849+
2850+--------------------------------------------------------------------------------
2851+
2852+-- | Wrap a list of pairs as an object.
2853+class Monoid pairs => FromPairs enc pairs | enc -> pairs where
2854+ fromPairs :: pairs -> enc
2855+
2856+instance (a ~ Value) => FromPairs (Encoding' a) Series where
2857+ fromPairs = E.pairs
2858+
2859+instance FromPairs Value (DList Pair) where
2860+ fromPairs = object . toList
2861+
2862+-- | Like 'KeyValue' but the value is already converted to JSON
2863+-- ('Value' or 'Encoding'), and the result actually represents lists of pairs
2864+-- so it can be readily concatenated.
2865+class Monoid kv => KeyValuePair v kv where
2866+ pair :: String -> v -> kv
2867+
2868+instance (v ~ Value) => KeyValuePair v (DList Pair) where
2869+ pair k v = DList.singleton (pack k .= v)
2870+
2871+instance (e ~ Encoding) => KeyValuePair e Series where
2872+ pair = E.pairStr
Makefilenew file+2
@@ -0,0 +1,2 @@
1+lint:
2+ ./run-hlint.sh --cpp-include include/ --cpp-file travis/cabal_macros.h Data/ attoparsec-iso8601/ benchmarks/ examples/ ffi/ pure/ tests/
README.markdown+3−4
@@ -15,14 +15,13 @@ Master [git repository](http://github.com/bos/aeson):
1515
1616* `git clone git://github.com/bos/aeson.git`
1717
18−There's also a [Mercurial mirror](http://bitbucket.org/bos/aeson):
18+See what's changed in recent (and upcoming) releases:
1919
20−* `hg clone http://bitbucket.org/bos/aeson`
20+* https://github.com/bos/aeson/blob/master/changelog.md
2121
2222(You can create and contribute changes using either git or Mercurial.)
2323
2424
2525# Authors
2626
27−This library is written and maintained by Bryan O'Sullivan,
28−<bos@serpentine.com>.
27+This library was originally written by Bryan O'Sullivan.
aeson.cabal+136−61
@@ -1,12 +1,12 @@
11name: aeson
2−version: 1.0.0.0
2+version: 1.4.6.0
33license: BSD3
44license-file: LICENSE
55category: Text, Web, JSON
66copyright: (c) 2011-2016 Bryan O'Sullivan
77 (c) 2011 MailRank, Inc.
88author: Bryan O'Sullivan <bos@serpentine.com>
9−maintainer: Bryan O'Sullivan <bos@serpentine.com>
9+maintainer: Adam Bergmark <adam@bergmark.nl>
1010stability: experimental
1111tested-with: GHC == 7.4.2, GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.1
1212synopsis: Fast JSON parsing and encoding
@@ -21,23 +21,10 @@ description:
2121 To get started, see the documentation for the @Data.Aeson@ module
2222 below.
2323 .
24− Parsing performance on a late 2013 MacBook Pro (2.6GHz Core i7),
25− running 64-bit GHC 7.10.1, for mostly-English tweets from Twitter's
26− JSON search API:
27− .
28− * 6.4 KB payloads, English: 7570 msg\/sec (47.6 MB\/sec)
29− .
30− * 14.6 KB payloads, Japanese: 3261 msg\/sec (46.6 MB\/sec)
31− .
32− Encoding performance on the same machine and data:
33− .
34− * 6.4 KB payloads, English: 22738 msg\/sec (142.9 MB\/sec)
35− .
36− * 14.6 KB payloads, Japanese: 15911 msg\/sec (227.4 MB\/sec)
37− .
3824 (A note on naming: in Greek mythology, Aeson was the father of Jason.)
3925
4026extra-source-files:
27+ *.yaml
4128 README.markdown
4229 benchmarks/*.cabal
4330 benchmarks/*.hs
@@ -46,20 +33,41 @@ extra-source-files:
4633 benchmarks/Makefile
4734 benchmarks/Typed/*.hs
4835 benchmarks/json-data/*.json
49− include/overlapping-compat.h
36+ cbits/*.c
5037 changelog.md
5138 examples/*.cabal
5239 examples/*.hs
5340 examples/Twitter/*.hs
41+ ffi/Data/Aeson/Parser/*.hs
5442 include/*.h
43+ tests/JSONTestSuite/test_parsing/*.json
44+ tests/JSONTestSuite/test_transform/*.json
45+ tests/golden/*.expected
46+ pure/Data/Aeson/Parser/*.hs
5547
5648flag developer
5749 description: operate in developer mode
5850 default: False
5951 manual: True
6052
53+flag fast
54+ description: compile without optimizations
55+ default: False
56+ manual: True
57+
58+flag bytestring-builder
59+ description: Depend on the bytestring-builder package for backwards compatibility.
60+ default: False
61+ manual: False
62+
63+flag cffi
64+ description: Controls whether to include c-ffi bits or pure haskell. Default to False for security.
65+ default: False
66+ manual: True
67+
6168library
6269 default-language: Haskell2010
70+ hs-source-dirs: . attoparsec-iso8601/
6371
6472 exposed-modules:
6573 Data.Aeson
@@ -68,10 +76,12 @@ library
6876 Data.Aeson.Text
6977 Data.Aeson.Types
7078 Data.Aeson.TH
79+ Data.Aeson.QQ.Simple
7180
7281 Data.Aeson.Encoding.Internal
7382 Data.Aeson.Internal
7483 Data.Aeson.Internal.Time
84+ Data.Aeson.Parser.Internal
7585
7686 -- Deprecated modules
7787 exposed-modules:
@@ -80,112 +90,177 @@ library
8090 other-modules:
8191 Data.Aeson.Encoding.Builder
8292 Data.Aeson.Internal.Functions
83− Data.Aeson.Parser.Internal
93+ Data.Aeson.Parser.Unescape
8494 Data.Aeson.Parser.Time
8595 Data.Aeson.Types.FromJSON
8696 Data.Aeson.Types.Generic
8797 Data.Aeson.Types.ToJSON
8898 Data.Aeson.Types.Class
8999 Data.Aeson.Types.Internal
100+ Data.Attoparsec.Time
101+ Data.Attoparsec.Time.Internal
90102
103+ -- GHC bundled libs
91104 build-depends:
92− attoparsec >= 0.13.0.1,
93− base >= 4.5 && < 5,
94− base-compat >= 0.9.1 && < 0.10,
95− bytestring >= 0.10.4.0,
96− containers >= 0.2.4.1,
97− deepseq >= 1.3,
98− dlist >= 0.2,
99− ghc-prim >= 0.2,
100− hashable >= 1.1.2.0,
101− scientific >= 0.3.1 && < 0.4,
102− tagged >=0.8.3 && <0.9,
103− template-haskell >= 2.7,
104− text >= 1.1.1.0,
105− time >= 1.1.1.4,
106− time-locale-compat >= 0.1.1 && < 0.2,
107− unordered-containers >= 0.2.5.0,
108− vector >= 0.8
105+ base >= 4.7.0.0 && < 5,
106+ bytestring >= 0.10.4.0 && < 0.11,
107+ containers >= 0.5.5.1 && < 0.7,
108+ deepseq >= 1.3.0.0 && < 1.5,
109+ ghc-prim >= 0.2 && < 0.6,
110+ template-haskell >= 2.9.0.0 && < 2.16,
111+ text >= 1.2.3.0 && < 1.3,
112+ time >= 1.4 && < 1.10
113+
114+ if impl(ghc >= 8.0)
115+ build-depends: bytestring >= 0.10.8.1
116+
117+ -- Compat
118+ build-depends:
119+ base-compat >= 0.9.1 && < 0.12,
120+ time-compat >= 1.9.2.2 && < 1.10
121+
122+ if !impl(ghc >= 8.6)
123+ build-depends:
124+ contravariant >=1.4.1 && <1.6
109125
110126 if !impl(ghc >= 8.0)
111127 -- `Data.Semigroup` and `Control.Monad.Fail` and `Control.Monad.IO.Class` are available in base only since GHC 8.0 / base 4.9
112128 build-depends:
113− semigroups >= 0.16.1 && < 0.19,
114− transformers >= 0.2.2.0,
129+ semigroups >= 0.18.5 && < 0.20,
130+ transformers >= 0.3.0.0 && < 0.6,
131+ transformers-compat >= 0.6.2 && < 0.7,
115132 fail == 4.9.*
116133
117134 if !impl(ghc >= 7.10)
118135 -- `Numeric.Natural` is available in base only since GHC 7.10 / base 4.8
119− build-depends: nats >= 1 && < 1.2
136+ build-depends: nats >= 1.1.1 && < 1.2,
137+ void >= 0.7.2 && < 0.8
138+
139+ -- cannot use latest version
140+ build-depends:
141+ unordered-containers >= 0.2.8.0 && < 0.3,
142+
143+ -- not in LTS-12.10
144+ tagged >= 0.8.5 && < 0.9,
145+ primitive >= 0.6.3.0 && < 0.8
146+
147+ -- Other dependencies
148+ build-depends:
149+ attoparsec >= 0.13.2.2 && < 0.14,
150+ dlist >= 0.8.0.4 && < 0.9,
151+ hashable >= 1.2.7.0 && < 1.4,
152+ scientific >= 0.3.6.2 && < 0.4,
153+ th-abstraction >= 0.2.8.0 && < 0.4,
154+ uuid-types >= 1.0.3 && < 1.1,
155+ vector >= 0.12.0.1 && < 0.13
156+
157+ ghc-options: -Wall
120158
121159 if flag(developer)
122160 ghc-options: -Werror
123161 ghc-prof-options: -auto-all
124162
125− ghc-options: -O2 -Wall
163+ if flag(fast)
164+ ghc-options: -O0
165+ else
166+ ghc-options: -O2
126167
127168 include-dirs: include
169+ if impl(ghcjs) || !flag(cffi)
170+ hs-source-dirs: pure
171+ other-modules: Data.Aeson.Parser.UnescapePure
172+ else
173+ c-sources: cbits/unescape_string.c
174+ cpp-options: -DCFFI
175+ hs-source-dirs: ffi
176+ other-modules: Data.Aeson.Parser.UnescapeFFI
128177
129178test-suite tests
130179 default-language: Haskell2010
131− type: exitcode-stdio-1.0
132− hs-source-dirs: tests
133− main-is: Tests.hs
180+ type: exitcode-stdio-1.0
181+ hs-source-dirs: tests ffi pure
182+ main-is: Tests.hs
183+ c-sources: cbits/unescape_string.c
184+ ghc-options: -Wall -threaded -rtsopts
185+
134186 other-modules:
187+ Data.Aeson.Parser.UnescapeFFI
188+ Data.Aeson.Parser.UnescapePure
135189 DataFamilies.Properties
136190 DataFamilies.Instances
137191 DataFamilies.Encoders
138192 DataFamilies.Types
139193 Encoders
194+ ErrorMessages
140195 Functions
141196 Instances
142197 Options
198+ PropUtils
143199 Properties
200+ PropertyGeneric
201+ PropertyKeys
202+ PropertyRoundTrip
203+ PropertyRTFunctors
204+ PropertyTH
205+ SerializationFormatSpec
144206 Types
145207 UnitTests
146208 UnitTests.NullaryConstructors
147209
148− ghc-options: -Wall -threaded -rtsopts
149−
150210 build-depends:
151− HUnit,
152− QuickCheck >= 2.7 && <2.8.3,
211+ QuickCheck >= 2.10.0.1 && < 2.14,
153212 aeson,
213+ integer-logarithms >= 1 && <1.1,
154214 attoparsec,
155215 base,
156216 base-compat,
157− base-orphans >= 0.5.3 && <0.6,
158− bytestring,
217+ base-orphans >= 0.5.3 && <0.9,
218+ base16-bytestring,
159219 containers,
220+ directory,
160221 dlist,
161− generic-deriving >= 1.10 && < 1.11,
222+ Diff >= 0.4 && < 0.5,
223+ filepath,
224+ generic-deriving >= 1.10 && < 1.14,
162225 ghc-prim >= 0.2,
163− hashable >= 1.1.2.0,
226+ hashable >= 1.2.4.0,
227+ scientific,
164228 tagged,
165229 template-haskell,
166− test-framework,
167− test-framework-hunit,
168− test-framework-quickcheck2,
230+ tasty,
231+ tasty-golden,
232+ tasty-hunit,
233+ tasty-quickcheck,
169234 text,
170235 time,
171− time-locale-compat,
236+ time-compat,
172237 unordered-containers,
238+ uuid-types,
173239 vector,
174− quickcheck-instances >=0.3.12
240+ quickcheck-instances >= 0.3.21 && <0.4
241+
242+ if flag(bytestring-builder)
243+ build-depends: bytestring >= 0.9 && < 0.10.4,
244+ bytestring-builder >= 0.10.4 && < 1
245+ else
246+ build-depends: bytestring >= 0.10.4
175247
176248 if !impl(ghc >= 8.0)
177− build-depends: semigroups >= 0.16.1 && < 0.19
249+ build-depends:
250+ semigroups >= 0.18.2 && < 0.20,
251+ transformers >= 0.2.2.0,
252+ transformers-compat >= 0.3
178253
179254 if !impl(ghc >= 7.10)
180− build-depends: nats >=1 && <1.2
255+ build-depends: nats >=1 && <1.2,
256+ void >=0.7.2 && <0.8
181257
182258 if impl(ghc >= 7.8)
183259 build-depends: hashable-time >= 0.2 && <0.3
184260
261+ if flag(fast)
262+ ghc-options: -fno-enable-rewrite-rules
263+
185264source-repository head
186265 type: git
187266 location: git://github.com/bos/aeson.git
188−
189−source-repository head
190− type: mercurial
191− location: https://bitbucket.org/bos/aeson
attoparsec-iso8601/Data/Attoparsec/Time.hsnew file+148
@@ -0,0 +1,148 @@
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE ScopedTypeVariables #-}
4+-- |
5+-- Module: Data.Aeson.Parser.Time
6+-- Copyright: (c) 2015-2016 Bryan O'Sullivan
7+-- License: BSD3
8+-- Maintainer: Bryan O'Sullivan <bos@serpentine.com>
9+-- Stability: experimental
10+-- Portability: portable
11+--
12+-- Parsers for parsing dates and times.
13+
14+module Data.Attoparsec.Time
15+ (
16+ day
17+ , localTime
18+ , timeOfDay
19+ , timeZone
20+ , utcTime
21+ , zonedTime
22+ ) where
23+
24+import Prelude.Compat
25+
26+import Control.Applicative ((<|>))
27+import Control.Monad (void, when)
28+import Data.Attoparsec.Text as A
29+import Data.Attoparsec.Time.Internal (toPico)
30+import Data.Bits ((.&.))
31+import Data.Char (isDigit, ord)
32+import Data.Fixed (Pico)
33+import Data.Int (Int64)
34+import Data.Maybe (fromMaybe)
35+import Data.Time.Calendar (Day, fromGregorianValid)
36+import Data.Time.Clock (UTCTime(..))
37+import qualified Data.Text as T
38+import qualified Data.Time.LocalTime as Local
39+
40+-- | Parse a date of the form @[+,-]YYYY-MM-DD@.
41+day :: Parser Day
42+day = do
43+ absOrNeg <- negate <$ char '-' <|> id <$ char '+' <|> pure id
44+ y <- (decimal <* char '-') <|> fail "date must be of form [+,-]YYYY-MM-DD"
45+ m <- (twoDigits <* char '-') <|> fail "date must be of form [+,-]YYYY-MM-DD"
46+ d <- twoDigits <|> fail "date must be of form [+,-]YYYY-MM-DD"
47+ maybe (fail "invalid date") return (fromGregorianValid (absOrNeg y) m d)
48+
49+-- | Parse a two-digit integer (e.g. day of month, hour).
50+twoDigits :: Parser Int
51+twoDigits = do
52+ a <- digit
53+ b <- digit
54+ let c2d c = ord c .&. 15
55+ return $! c2d a * 10 + c2d b
56+
57+-- | Parse a time of the form @HH:MM[:SS[.SSS]]@.
58+timeOfDay :: Parser Local.TimeOfDay
59+timeOfDay = do
60+ h <- twoDigits
61+ m <- char ':' *> twoDigits
62+ s <- option 0 (char ':' *> seconds)
63+ if h < 24 && m < 60 && s < 61
64+ then return (Local.TimeOfDay h m s)
65+ else fail "invalid time"
66+
67+data T = T {-# UNPACK #-} !Int {-# UNPACK #-} !Int64
68+
69+-- | Parse a count of seconds, with the integer part being two digits
70+-- long.
71+seconds :: Parser Pico
72+seconds = do
73+ real <- twoDigits
74+ mc <- peekChar
75+ case mc of
76+ Just '.' -> do
77+ t <- anyChar *> takeWhile1 isDigit
78+ return $! parsePicos real t
79+ _ -> return $! fromIntegral real
80+ where
81+ parsePicos a0 t = toPico (fromIntegral (t' * 10^n))
82+ where T n t' = T.foldl' step (T 12 (fromIntegral a0)) t
83+ step ma@(T m a) c
84+ | m <= 0 = ma
85+ | otherwise = T (m-1) (10 * a + fromIntegral (ord c) .&. 15)
86+
87+-- | Parse a time zone, and return 'Nothing' if the offset from UTC is
88+-- zero. (This makes some speedups possible.)
89+timeZone :: Parser (Maybe Local.TimeZone)
90+timeZone = do
91+ let maybeSkip c = do ch <- peekChar'; when (ch == c) (void anyChar)
92+ maybeSkip ' '
93+ ch <- satisfy $ \c -> c == 'Z' || c == '+' || c == '-'
94+ if ch == 'Z'
95+ then return Nothing
96+ else do
97+ h <- twoDigits
98+ mm <- peekChar
99+ m <- case mm of
100+ Just ':' -> anyChar *> twoDigits
101+ Just d | isDigit d -> twoDigits
102+ _ -> return 0
103+ let off | ch == '-' = negate off0
104+ | otherwise = off0
105+ off0 = h * 60 + m
106+ case undefined of
107+ _ | off == 0 ->
108+ return Nothing
109+ | off < -720 || off > 840 || m > 59 ->
110+ fail "invalid time zone offset"
111+ | otherwise ->
112+ let !tz = Local.minutesToTimeZone off
113+ in return (Just tz)
114+
115+-- | Parse a date and time, of the form @YYYY-MM-DD HH:MM[:SS[.SSS]]@.
116+-- The space may be replaced with a @T@. The number of seconds is optional
117+-- and may be followed by a fractional component.
118+localTime :: Parser Local.LocalTime
119+localTime = Local.LocalTime <$> day <* daySep <*> timeOfDay
120+ where daySep = satisfy (\c -> c == 'T' || c == ' ')
121+
122+-- | Behaves as 'zonedTime', but converts any time zone offset into a
123+-- UTC time.
124+utcTime :: Parser UTCTime
125+utcTime = do
126+ lt@(Local.LocalTime d t) <- localTime
127+ mtz <- timeZone
128+ case mtz of
129+ Nothing -> let !tt = Local.timeOfDayToTime t
130+ in return (UTCTime d tt)
131+ Just tz -> return $! Local.localTimeToUTC tz lt
132+
133+-- | Parse a date with time zone info. Acceptable formats:
134+--
135+-- @YYYY-MM-DD HH:MM Z@
136+-- @YYYY-MM-DD HH:MM:SS Z@
137+-- @YYYY-MM-DD HH:MM:SS.SSS Z@
138+--
139+-- The first space may instead be a @T@, and the second space is
140+-- optional. The @Z@ represents UTC. The @Z@ may be replaced with a
141+-- time zone offset of the form @+0000@ or @-08:00@, where the first
142+-- two digits are hours, the @:@ is optional and the second two digits
143+-- (also optional) are minutes.
144+zonedTime :: Parser Local.ZonedTime
145+zonedTime = Local.ZonedTime <$> localTime <*> (fromMaybe utc <$> timeZone)
146+
147+utc :: Local.TimeZone
148+utc = Local.TimeZone 0 False ""
attoparsec-iso8601/Data/Attoparsec/Time/Internal.hsnew file+64
@@ -0,0 +1,64 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+-- |
4+-- Module: Data.Aeson.Internal.Time
5+-- Copyright: (c) 2015-2016 Bryan O'Sullivan
6+-- License: BSD3
7+-- Maintainer: Bryan O'Sullivan <bos@serpentine.com>
8+-- Stability: experimental
9+-- Portability: portable
10+
11+module Data.Attoparsec.Time.Internal
12+ (
13+ TimeOfDay64(..)
14+ , fromPico
15+ , toPico
16+ , diffTimeOfDay64
17+ , toTimeOfDay64
18+ ) where
19+
20+import Prelude.Compat
21+
22+import Data.Int (Int64)
23+import Data.Time
24+import Unsafe.Coerce (unsafeCoerce)
25+
26+#if MIN_VERSION_time(1,6,0)
27+
28+import Data.Time.Clock (diffTimeToPicoseconds)
29+
30+#endif
31+
32+import Data.Fixed (Pico, Fixed(MkFixed))
33+
34+#if !MIN_VERSION_time(1,6,0)
35+
36+diffTimeToPicoseconds :: DiffTime -> Integer
37+diffTimeToPicoseconds = unsafeCoerce
38+
39+#endif
40+
41+toPico :: Integer -> Pico
42+toPico = MkFixed
43+
44+fromPico :: Pico -> Integer
45+fromPico (MkFixed i) = i
46+
47+-- | Like TimeOfDay, but using a fixed-width integer for seconds.
48+data TimeOfDay64 = TOD {-# UNPACK #-} !Int
49+ {-# UNPACK #-} !Int
50+ {-# UNPACK #-} !Int64
51+
52+posixDayLength :: DiffTime
53+posixDayLength = 86400
54+
55+diffTimeOfDay64 :: DiffTime -> TimeOfDay64
56+diffTimeOfDay64 t
57+ | t >= posixDayLength = TOD 23 59 (60000000000000 + pico (t - posixDayLength))
58+ | otherwise = TOD (fromIntegral h) (fromIntegral m) s
59+ where (h,mp) = pico t `quotRem` 3600000000000000
60+ (m,s) = mp `quotRem` 60000000000000
61+ pico = fromIntegral . diffTimeToPicoseconds
62+
63+toTimeOfDay64 :: TimeOfDay -> TimeOfDay64
64+toTimeOfDay64 (TimeOfDay h m s) = TOD h m (fromIntegral (fromPico s))
attoparsec-iso8601/LICENSEnew file+30
@@ -0,0 +1,30 @@
1+Copyright (c) 2011, MailRank, Inc.
2+
3+All rights reserved.
4+
5+Redistribution and use in source and binary forms, with or without
6+modification, are permitted provided that the following conditions
7+are met:
8+
9+1. Redistributions of source code must retain the above copyright
10+ notice, this list of conditions and the following disclaimer.
11+
12+2. Redistributions in binary form must reproduce the above copyright
13+ notice, this list of conditions and the following disclaimer in the
14+ documentation and/or other materials provided with the distribution.
15+
16+3. Neither the name of the author nor the names of his contributors
17+ may be used to endorse or promote products derived from this software
18+ without specific prior written permission.
19+
20+THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
21+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
24+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30+POSSIBILITY OF SUCH DAMAGE.
attoparsec-iso8601/README.mdnew file+19
@@ -0,0 +1,19 @@
1+Parsing of ISO 8601 dates.
2+
3+This package is used to parse dates in aeson. It is split into a
4+separate package to be shared by other projects that want to parse
5+dates like aeson does.
6+
7+For now, this project is located in the aeson repository and aeson
8+itself uses the source of this package without pulling in the package
9+as a dependency.
10+
11+## Stability
12+
13+Since aeson depends on this package we want to be very careful about
14+changing the format.
15+
16+There may be breaking changes if we find that the format is
17+incorrectly too lenient. We consider widening of the allowed input a
18+non-breaking addition since all previously valid input will still
19+parse correctly.
attoparsec-iso8601/attoparsec-iso8601.cabalnew file+55
@@ -0,0 +1,55 @@
1+name: attoparsec-iso8601
2+version: 1.0.1.0
3+synopsis: Parsing of ISO 8601 dates, originally from aeson.
4+description: Parsing of ISO 8601 dates, originally from aeson.
5+license: BSD3
6+license-file: LICENSE
7+category: Parsing
8+copyright: (c) 2011-2016 Bryan O'Sullivan
9+ (c) 2011 MailRank, Inc.
10+author: Bryan O'Sullivan <bos@serpentine.com>
11+maintainer: Adam Bergmark <adam@bergmark.nl>
12+stability: experimental
13+cabal-version: >=1.10
14+homepage: https://github.com/bos/aeson
15+bug-reports: https://github.com/bos/aeson/issues
16+build-type: Simple
17+extra-source-files:
18+ README.md
19+
20+flag developer
21+ description: operate in developer mode
22+ default: False
23+ manual: True
24+
25+flag fast
26+ description: compile without optimizations
27+ default: False
28+ manual: True
29+
30+library
31+ hs-source-dirs: .
32+ default-language: Haskell2010
33+ ghc-options: -Wall
34+ exposed-modules:
35+ Data.Attoparsec.Time.Internal
36+ Data.Attoparsec.Time
37+ build-depends:
38+ attoparsec >= 0.13.0.1,
39+ base >= 4.7 && < 5,
40+ base-compat >= 0.9.1 && < 0.12,
41+ text >= 1.1.1.0,
42+ time >= 1.1.1.4
43+
44+ if flag(fast)
45+ ghc-options: -O0
46+ else
47+ ghc-options: -O2
48+
49+ if flag(developer)
50+ ghc-options: -Werror
51+ ghc-prof-options: -auto-all
52+
53+source-repository head
54+ type: git
55+ location: git://github.com/bos/aeson.git
attoparsec-iso8601/changelog.mdnew file+5
@@ -0,0 +1,5 @@
1+For the latest version of this document, please see [https://github.com/bos/aeson/blob/master/attoparsec-iso8601/changelog.md](https://github.com/bos/aeson/blob/master/attoparsec-iso8601/changelog.md).
2+
3+### 1.0.1.0
4+
5+* Fixes handling of `UTCTime` wrt. leap seconds , thanks to Adam Schønemann
benchmarks/AesonCompareAutoInstances.hsdeleted−231
@@ -1,231 +0,0 @@
1−{-# LANGUAGE DeriveDataTypeable, DeriveGeneric, TemplateHaskell #-}
2−
3−module Main where
4−
5−--------------------------------------------------------------------------------
6−
7−import Criterion.Main hiding (defaultOptions)
8−
9−import Control.DeepSeq (NFData, rnf, deepseq)
10−
11−import Data.Typeable (Typeable)
12−import Data.Data (Data)
13−import GHC.Generics (Generic)
14−
15−import Data.Aeson.Types
16−import Data.Aeson.TH
17−import qualified Data.Aeson.Generic as G (fromJSON, toJSON)
18−
19−import Data.Aeson.Encode
20−
21−import Options
22−
23−--------------------------------------------------------------------------------
24−
25−data D a = Nullary
26− | Unary Int
27− | Product String Char a
28− | Record { testOne :: Double
29− , testTwo :: Bool
30− , testThree :: D a
31− }
32− deriving (Show, Eq, Data, Typeable)
33−
34−deriveJSON opts ''D
35−
36−instance NFData a => NFData (D a) where
37− rnf Nullary = ()
38− rnf (Unary n) = rnf n
39− rnf (Product s c x) = s `deepseq` c `deepseq` rnf x
40− rnf (Record d b y) = d `deepseq` b `deepseq` rnf y
41−
42−type T = D (D (D ()))
43−
44−d :: T
45−d = Record
46− { testOne = 1234.56789
47− , testTwo = True
48− , testThree = Product "Hello World!" 'a' $
49− Record
50− { testOne = 9876.54321
51− , testTwo = False
52− , testThree = Product "Yeehaa!!!" '\n' Nullary
53− }
54− }
55−
56−--------------------------------------------------------------------------------
57−
58−data D' a = Nullary'
59− | Unary' Int
60− | Product' String Char a
61− | Record' { testOne' :: Double
62− , testTwo' :: Bool
63− , testThree' :: D' a
64− }
65− deriving (Show, Eq, Generic, Data, Typeable)
66−
67−instance ToJSON a => ToJSON (D' a) where
68− toJSON = genericToJSON opts
69−
70−instance FromJSON a => FromJSON (D' a) where
71− parseJSON = genericParseJSON opts
72−
73−instance NFData a => NFData (D' a) where
74− rnf Nullary' = ()
75− rnf (Unary' n) = rnf n
76− rnf (Product' s c x) = s `deepseq` c `deepseq` rnf x
77− rnf (Record' d b y) = d `deepseq` b `deepseq` rnf y
78−
79−type T' = D' (D' (D' ()))
80−
81−d' :: T'
82−d' = Record'
83− { testOne' = 1234.56789
84− , testTwo' = True
85− , testThree' = Product' "Hello World!" 'a' $
86− Record'
87− { testOne' = 9876.54321
88− , testTwo' = False
89− , testThree' = Product' "Yeehaa!!!" '\n' Nullary'
90− }
91− }
92−
93−--------------------------------------------------------------------------------
94−
95−data BigRecord = BigRecord
96− { field01 :: !Int, field02 :: !Int, field03 :: !Int, field04 :: !Int, field05 :: !Int
97− , field06 :: !Int, field07 :: !Int, field08 :: !Int, field09 :: !Int, field10 :: !Int
98− , field11 :: !Int, field12 :: !Int, field13 :: !Int, field14 :: !Int, field15 :: !Int
99− , field16 :: !Int, field17 :: !Int, field18 :: !Int, field19 :: !Int, field20 :: !Int
100− , field21 :: !Int, field22 :: !Int, field23 :: !Int, field24 :: !Int, field25 :: !Int
101− } deriving (Show, Eq, Generic, Data, Typeable)
102−
103−instance NFData BigRecord
104−
105−bigRecord = BigRecord 1 2 3 4 5
106− 6 7 8 9 10
107− 11 12 13 14 15
108− 16 17 18 19 20
109− 21 22 23 24 25
110−
111−gBigRecordToJSON :: BigRecord -> Value
112−gBigRecordToJSON = genericToJSON opts
113−
114−gBigRecordFromJSON :: Value -> Result BigRecord
115−gBigRecordFromJSON = parse $ genericParseJSON opts
116−
117−thBigRecordToJSON :: BigRecord -> Value
118−thBigRecordToJSON = $(mkToJSON opts ''BigRecord)
119−
120−thBigRecordFromJSON :: Value -> Result BigRecord
121−thBigRecordFromJSON = parse $(mkParseJSON opts ''BigRecord)
122−
123−--------------------------------------------------------------------------------
124−
125−data BigProduct = BigProduct
126− !Int !Int !Int !Int !Int
127− !Int !Int !Int !Int !Int
128− !Int !Int !Int !Int !Int
129− !Int !Int !Int !Int !Int
130− !Int !Int !Int !Int !Int
131− deriving (Show, Eq, Generic, Data, Typeable)
132−
133−instance NFData BigProduct
134−
135−bigProduct = BigProduct 1 2 3 4 5
136− 6 7 8 9 10
137− 11 12 13 14 15
138− 16 17 18 19 20
139− 21 22 23 24 25
140−
141−gBigProductToJSON :: BigProduct -> Value
142−gBigProductToJSON = genericToJSON opts
143−
144−gBigProductFromJSON :: Value -> Result BigProduct
145−gBigProductFromJSON = parse $ genericParseJSON opts
146−
147−thBigProductToJSON :: BigProduct -> Value
148−thBigProductToJSON = $(mkToJSON opts ''BigProduct)
149−
150−thBigProductFromJSON :: Value -> Result BigProduct
151−thBigProductFromJSON = parse $(mkParseJSON opts ''BigProduct)
152−
153−--------------------------------------------------------------------------------
154−
155−data BigSum = F01 | F02 | F03 | F04 | F05
156− | F06 | F07 | F08 | F09 | F10
157− | F11 | F12 | F13 | F14 | F15
158− | F16 | F17 | F18 | F19 | F20
159− | F21 | F22 | F23 | F24 | F25
160− deriving (Show, Eq, Generic, Data, Typeable)
161−
162−instance NFData BigSum
163−
164−bigSum = F25
165−
166−gBigSumToJSON :: BigSum -> Value
167−gBigSumToJSON = genericToJSON opts
168−
169−gBigSumFromJSON :: Value -> Result BigSum
170−gBigSumFromJSON = parse $ genericParseJSON opts
171−
172−thBigSumToJSON :: BigSum -> Value
173−thBigSumToJSON = $(mkToJSON opts ''BigSum)
174−
175−thBigSumFromJSON :: Value -> Result BigSum
176−thBigSumFromJSON = parse $(mkParseJSON opts ''BigSum)
177−
178−--------------------------------------------------------------------------------
179−
180−type FJ a = Value -> Result a
181−
182−main :: IO ()
183−main = defaultMain
184− [ let v = toJSON d
185− in (d, d', v) `deepseq`
186− bgroup "D"
187− [ group "toJSON" (nf toJSON d)
188− (nf G.toJSON d)
189− (nf toJSON d')
190− , group "fromJSON" (nf ( fromJSON :: FJ T ) v)
191− (nf (G.fromJSON :: FJ T ) v)
192− (nf ( fromJSON :: FJ T') v)
193− ]
194− , let v = thBigRecordToJSON bigRecord
195− in bigRecord `deepseq` v `deepseq`
196− bgroup "BigRecord"
197− [ group "toJSON" (nf thBigRecordToJSON bigRecord)
198− (nf G.toJSON bigRecord)
199− (nf gBigRecordToJSON bigRecord)
200− , group "fromJSON" (nf (thBigRecordFromJSON :: FJ BigRecord) v)
201− (nf (G.fromJSON :: FJ BigRecord) v)
202− (nf (gBigRecordFromJSON :: FJ BigRecord) v)
203− ]
204− , let v = thBigProductToJSON bigProduct
205− in bigProduct `deepseq` v `deepseq`
206− bgroup "BigProduct"
207− [ group "toJSON" (nf thBigProductToJSON bigProduct)
208− (nf G.toJSON bigProduct)
209− (nf gBigProductToJSON bigProduct)
210− , group "fromJSON" (nf (thBigProductFromJSON :: FJ BigProduct) v)
211− (nf (G.fromJSON :: FJ BigProduct) v)
212− (nf (gBigProductFromJSON :: FJ BigProduct) v)
213− ]
214− , let v = thBigSumToJSON bigSum
215− in bigSum `deepseq` v `deepseq`
216− bgroup "BigSum"
217− [ group "toJSON" (nf thBigSumToJSON bigSum)
218− (nf G.toJSON bigSum)
219− (nf gBigSumToJSON bigSum)
220− , group "fromJSON" (nf (thBigSumFromJSON :: FJ BigSum) v)
221− (nf (G.fromJSON :: FJ BigSum) v)
222− (nf (gBigSumFromJSON :: FJ BigSum) v)
223− ]
224− ]
225−
226−group n th syb gen = bcompare
227− [ bgroup n [ bench "th" th
228− , bench "syb" syb
229− , bench "generic" gen
230− ]
231− ]
benchmarks/AesonEncode.hs+12−6
@@ -1,7 +1,13 @@
1−{-# LANGUAGE BangPatterns, OverloadedStrings #-}
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE OverloadedStrings #-}
24
3−import Control.Exception
4−import Control.Monad
5+module Main (main) where
6+
7+import Prelude.Compat
8+
9+import Control.DeepSeq
10+import Control.Monad (forM_)
511import Data.Aeson
612import Data.Attoparsec.ByteString (IResult(..), parseWith)
713import Data.Char (isDigit)
@@ -9,7 +15,6 @@ import Data.Time.Clock
915import System.Environment (getArgs)
1016import System.IO
1117import qualified Data.ByteString as B
12−import Control.DeepSeq
1318
1419main :: IO ()
1520main = do
@@ -17,8 +22,9 @@ main = do
1722 let (cnt,args) = case args0 of
1823 (i:c:a) | all isDigit i && all isDigit c -> (c,a)
1924 (c:a) -> (c,a)
25+ [] -> error "Unexpected empty list"
2026 let count = read cnt :: Int
21− forM_ args $ \arg -> bracket (openFile arg ReadMode) hClose $ \h -> do
27+ forM_ args $ \arg -> withFile arg ReadMode $ \h -> do
2228 putStrLn $ arg ++ ":"
2329 let refill = B.hGet h 16384
2430 result0 <- parseWith refill json =<< refill
@@ -28,7 +34,7 @@ main = do
2834 start <- getCurrentTime
2935 let loop !n r
3036 | n >= count = return ()
31− | otherwise = {-# SCC "loop" #-} do
37+ | otherwise = {-# SCC "loop" #-}
3238 rnf (encode r) `seq` loop (n+1) r
3339 loop 0 r0
3440 delta <- flip diffUTCTime start `fmap` getCurrentTime
benchmarks/AesonFoldable.hsnew file+86
@@ -0,0 +1,86 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+
4+module Main (main) where
5+
6+import Criterion.Main
7+
8+import Prelude.Compat
9+
10+import Data.Foldable (toList)
11+import qualified Data.Aeson as A
12+import qualified Data.Sequence as S
13+import qualified Data.Vector as V
14+import qualified Data.Vector.Unboxed as U
15+
16+-------------------------------------------------------------------------------
17+-- List
18+-------------------------------------------------------------------------------
19+
20+newtype L f = L { getL :: f Int }
21+
22+instance Foldable f => A.ToJSON (L f) where
23+ toJSON = error "do not use this"
24+ toEncoding = A.toEncoding . toList . getL
25+
26+-------------------------------------------------------------------------------
27+-- Foldable
28+-------------------------------------------------------------------------------
29+
30+newtype F f = F { getF :: f Int }
31+
32+instance Foldable f => A.ToJSON (F f) where
33+ toJSON = error "do not use this"
34+ toEncoding = A.foldable . getF
35+
36+-------------------------------------------------------------------------------
37+-- Values
38+-------------------------------------------------------------------------------
39+
40+valueList :: [Int]
41+valueList = [1..1000]
42+
43+valueSeq :: S.Seq Int
44+valueSeq = S.fromList valueList
45+
46+valueVector :: V.Vector Int
47+valueVector = V.fromList valueList
48+
49+valueUVector :: U.Vector Int
50+valueUVector = U.fromList valueList
51+
52+-------------------------------------------------------------------------------
53+-- Main
54+-------------------------------------------------------------------------------
55+
56+benchEncode
57+ :: A.ToJSON a
58+ => String
59+ -> a
60+ -> Benchmark
61+benchEncode name val
62+ = bench ("A " ++ name) $ nf A.encode val
63+
64+main :: IO ()
65+main = defaultMain
66+ [ bgroup "encode"
67+ [ bgroup "List"
68+ [ benchEncode "-" valueList
69+ , benchEncode "L" $ L valueList
70+ , benchEncode "F" $ F valueList
71+ ]
72+ , bgroup "Seq"
73+ [ benchEncode "-" valueSeq
74+ , benchEncode "L" $ L valueSeq
75+ , benchEncode "F" $ F valueSeq
76+ ]
77+ , bgroup "Vector"
78+ [ benchEncode "-" valueVector
79+ , benchEncode "L" $ L valueVector
80+ , benchEncode "F" $ F valueVector
81+ ]
82+ , bgroup "Vector.Unboxed"
83+ [ benchEncode "-" valueUVector
84+ ]
85+ ]
86+ ]
benchmarks/AesonMap.hs+28−17
@@ -1,16 +1,24 @@
1−{-# LANGUAGE OverloadedStrings, RankNTypes #-}
1+{-# LANGUAGE FlexibleContexts #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE RankNTypes #-}
4+
5+{-# OPTIONS_GHC -fno-warn-orphans #-}
6+
7+module Main (main) where
8+
9+import Prelude.Compat
210
311import Control.DeepSeq
412import Criterion.Main
5−import Data.Aeson
6−import Data.Aeson.Types (fromJSONKeyCoerce)
713import Data.Hashable
814import Data.Proxy (Proxy (..))
915import Data.Tagged (Tagged (..))
16+import Data.Aeson
17+import Data.Aeson.Types (fromJSONKeyCoerce)
1018import qualified Data.ByteString.Lazy as LBS
11−import qualified Data.Text as T
12−import qualified Data.Map as M
1319import qualified Data.HashMap.Strict as HM
20+import qualified Data.Map as M
21+import qualified Data.Text as T
1422
1523value :: Int -> HM.HashMap T.Text T.Text
1624value n = HM.fromList $ map f [1..n]
@@ -35,6 +43,7 @@ instance NFData T1 where
3543 rnf (T1 t) = rnf t
3644instance Hashable T1 where
3745 hashWithSalt salt (T1 t) = hashWithSalt salt t
46+
3847instance FromJSON T1 where
3948 parseJSON = withText "T1" $ pure . T1
4049instance FromJSONKey T1 where
@@ -51,6 +60,7 @@ instance NFData T2 where
5160 rnf (T2 t) = rnf t
5261instance Hashable T2 where
5362 hashWithSalt salt (T2 t) = hashWithSalt salt t
63+
5464instance FromJSON T2 where
5565 parseJSON = withText "T2" $ pure . T2
5666instance FromJSONKey T2 where
@@ -67,6 +77,7 @@ instance NFData T3 where
6777 rnf (T3 t) = rnf t
6878instance Hashable T3 where
6979 hashWithSalt salt (T3 t) = hashWithSalt salt t
80+
7081instance FromJSON T3 where
7182 parseJSON = withText "T3" $ pure . T3
7283instance FromJSONKey T3 where
@@ -83,28 +94,28 @@ value1000 = value 1000
8394value10000 = value 10000
8495
8596encodedValue10 :: LBS.ByteString
86−encodedValue10 = encode $ value10
97+encodedValue10 = encode value10
8798
8899encodedValue100 :: LBS.ByteString
89−encodedValue100 = encode $ value100
100+encodedValue100 = encode value100
90101
91102encodedValue1000 :: LBS.ByteString
92−encodedValue1000 = encode $ value1000
103+encodedValue1000 = encode value1000
93104
94105encodedValue10000 :: LBS.ByteString
95−encodedValue10000 = encode $ value10000
106+encodedValue10000 = encode value10000
96107
97108-------------------------------------------------------------------------------
98109-- Helpers
99110-------------------------------------------------------------------------------
100111
101112decodeHM
102− :: (FromJSONKey k, Eq k, Hashable k)
113+ :: (FromJSON (HM.HashMap k T.Text), Eq k, Hashable k)
103114 => Proxy k -> LBS.ByteString -> Maybe (HM.HashMap k T.Text)
104115decodeHM _ = decode
105116
106117decodeMap
107− :: (FromJSONKey k, Ord k)
118+ :: (FromJSON (M.Map k T.Text), Ord k)
108119 => Proxy k -> LBS.ByteString -> Maybe (M.Map k T.Text)
109120decodeMap _ = decode
110121
@@ -147,10 +158,10 @@ benchDecodeMap
147158 -> LBS.ByteString
148159 -> Benchmark
149160benchDecodeMap name val = bgroup name
150− [ bench "Text" $ nf (decodeMap proxyText) val
151− , bench "Identity" $ nf (decodeMap proxyT1) val
152− , bench "Coerce" $ nf (decodeMap proxyT2) val
153− , bench "Parser" $ nf (decodeMap proxyT3) val
161+ [ bench "Text" $ nf (decodeMap proxyText) val
162+ , bench "Identity" $ nf (decodeMap proxyT1) val
163+ , bench "Coerce" $ nf (decodeMap proxyT2) val
164+ , bench "Parser" $ nf (decodeMap proxyT3) val
154165 ]
155166
156167benchEncodeHM
@@ -158,7 +169,7 @@ benchEncodeHM
158169 -> HM.HashMap T.Text T.Text
159170 -> Benchmark
160171benchEncodeHM name val = bgroup name
161− [ bench "Text" $ nf encode val
172+ [ bench "Text" $ nf encode val
162173 ]
163174
164175benchEncodeMap
@@ -166,7 +177,7 @@ benchEncodeMap
166177 -> HM.HashMap T.Text T.Text
167178 -> Benchmark
168179benchEncodeMap name val = bgroup name
169− [ bench "Text" $ nf encode val'
180+ [ bench "Text" $ nf encode val'
170181 ]
171182 where
172183 val' :: M.Map T.Text T.Text
benchmarks/AesonParse.hs+9−4
@@ -1,8 +1,13 @@
1−{-# LANGUAGE BangPatterns, OverloadedStrings #-}
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+
5+module Main (main) where
6+
7+import Prelude.Compat
28
3−import Control.Exception
4−import Control.Monad
59import Data.Aeson
10+import Control.Monad
611import Data.Attoparsec.ByteString (IResult(..), parseWith)
712import Data.Time.Clock
813import System.Environment (getArgs)
@@ -14,7 +19,7 @@ main = do
1419 (bs:cnt:args) <- getArgs
1520 let count = read cnt :: Int
1621 blkSize = read bs
17− forM_ args $ \arg -> bracket (openFile arg ReadMode) hClose $ \h -> do
22+ forM_ args $ \arg -> withFile arg ReadMode $ \h -> do
1823 putStrLn $ arg ++ ":"
1924 start <- getCurrentTime
2025 let loop !good !bad
benchmarks/AesonTuples.hs+5−3
@@ -1,9 +1,11 @@
1−module Main where
1+{-# LANGUAGE NoImplicitPrelude #-}
22
3−--------------------------------------------------------------------------------
3+module Main (main) where
4+
5+import Prelude.Compat
46
5−import Criterion.Main
67import Control.DeepSeq (deepseq)
8+import Criterion.Main
79import Data.Aeson
810
911--------------------------------------------------------------------------------
benchmarks/Auto/G/BigProduct.hsnew file+33
@@ -0,0 +1,33 @@
1+{-# LANGUAGE DeriveGeneric #-}
2+
3+module Auto.G.BigProduct where
4+
5+import Control.DeepSeq
6+import Data.Aeson
7+import GHC.Generics (Generic)
8+import Options
9+
10+data BigProduct = BigProduct
11+ !Int !Int !Int !Int !Int
12+ !Int !Int !Int !Int !Int
13+ !Int !Int !Int !Int !Int
14+ !Int !Int !Int !Int !Int
15+ !Int !Int !Int !Int !Int
16+ deriving (Show, Eq, Generic)
17+
18+instance NFData BigProduct where
19+ rnf a = a `seq` ()
20+
21+instance ToJSON BigProduct where
22+ toJSON = genericToJSON opts
23+ toEncoding = genericToEncoding opts
24+
25+instance FromJSON BigProduct where
26+ parseJSON = genericParseJSON opts
27+
28+bigProduct :: BigProduct
29+bigProduct = BigProduct 1 2 3 4 5
30+ 6 7 8 9 10
31+ 11 12 13 14 15
32+ 16 17 18 19 20
33+ 21 22 23 24 25
benchmarks/Auto/G/BigRecord.hsnew file+33
@@ -0,0 +1,33 @@
1+{-# LANGUAGE DeriveGeneric #-}
2+
3+module Auto.G.BigRecord where
4+
5+import Control.DeepSeq
6+import Data.Aeson
7+import GHC.Generics (Generic)
8+import Options
9+
10+data BigRecord = BigRecord
11+ { field01 :: !Int, field02 :: !Int, field03 :: !Int, field04 :: !Int, field05 :: !Int
12+ , field06 :: !Int, field07 :: !Int, field08 :: !Int, field09 :: !Int, field10 :: !Int
13+ , field11 :: !Int, field12 :: !Int, field13 :: !Int, field14 :: !Int, field15 :: !Int
14+ , field16 :: !Int, field17 :: !Int, field18 :: !Int, field19 :: !Int, field20 :: !Int
15+ , field21 :: !Int, field22 :: !Int, field23 :: !Int, field24 :: !Int, field25 :: !Int
16+ } deriving (Show, Eq, Generic)
17+
18+instance NFData BigRecord where
19+ rnf a = a `seq` ()
20+
21+instance ToJSON BigRecord where
22+ toJSON = genericToJSON opts
23+ toEncoding = genericToEncoding opts
24+
25+instance FromJSON BigRecord where
26+ parseJSON = genericParseJSON opts
27+
28+bigRecord :: BigRecord
29+bigRecord = BigRecord 1 2 3 4 5
30+ 6 7 8 9 10
31+ 11 12 13 14 15
32+ 16 17 18 19 20
33+ 21 22 23 24 25
benchmarks/Auto/G/BigSum.hsnew file+28
@@ -0,0 +1,28 @@
1+{-# LANGUAGE DeriveGeneric #-}
2+
3+module Auto.G.BigSum where
4+
5+import Control.DeepSeq
6+import Data.Aeson
7+import GHC.Generics (Generic)
8+import Options
9+
10+data BigSum = F01 | F02 | F03 | F04 | F05
11+ | F06 | F07 | F08 | F09 | F10
12+ | F11 | F12 | F13 | F14 | F15
13+ | F16 | F17 | F18 | F19 | F20
14+ | F21 | F22 | F23 | F24 | F25
15+ deriving (Show, Eq, Generic)
16+
17+instance NFData BigSum where
18+ rnf a = a `seq` ()
19+
20+instance ToJSON BigSum where
21+ toJSON = genericToJSON opts
22+ toEncoding = genericToEncoding opts
23+
24+instance FromJSON BigSum where
25+ parseJSON = genericParseJSON opts
26+
27+bigSum :: BigSum
28+bigSum = F25
benchmarks/Auto/G/D.hsnew file+44
@@ -0,0 +1,44 @@
1+{-# LANGUAGE DeriveGeneric #-}
2+
3+module Auto.G.D where
4+
5+import Control.DeepSeq
6+import Data.Aeson
7+import GHC.Generics (Generic)
8+import Options
9+
10+data D a = Nullary
11+ | Unary Int
12+ | Product String Char a
13+ | Record { testOne :: Double
14+ , testTwo :: Bool
15+ , testThree :: D a
16+ }
17+ deriving (Show, Eq, Generic)
18+
19+instance NFData a => NFData (D a) where
20+ rnf Nullary = ()
21+ rnf (Unary n) = rnf n
22+ rnf (Product s c x) = s `deepseq` c `deepseq` rnf x
23+ rnf (Record a b y) = a `deepseq` b `deepseq` rnf y
24+
25+instance ToJSON a => ToJSON (D a) where
26+ toJSON = genericToJSON opts
27+ toEncoding = genericToEncoding opts
28+
29+instance FromJSON a => FromJSON (D a) where
30+ parseJSON = genericParseJSON opts
31+
32+type T = D (D (D ()))
33+
34+d :: T
35+d = Record
36+ { testOne = 1234.56789
37+ , testTwo = True
38+ , testThree = Product "Hello World!" 'a'
39+ Record
40+ { testOne = 9876.54321
41+ , testTwo = False
42+ , testThree = Product "Yeehaa!!!" '\n' Nullary
43+ }
44+ }
benchmarks/Auto/T/BigProduct.hsnew file+27
@@ -0,0 +1,27 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+module Auto.T.BigProduct where
4+
5+import Control.DeepSeq
6+import Data.Aeson.TH
7+import Options
8+
9+data BigProduct = BigProduct
10+ !Int !Int !Int !Int !Int
11+ !Int !Int !Int !Int !Int
12+ !Int !Int !Int !Int !Int
13+ !Int !Int !Int !Int !Int
14+ !Int !Int !Int !Int !Int
15+ deriving (Show, Eq)
16+
17+instance NFData BigProduct where
18+ rnf a = a `seq` ()
19+
20+deriveJSON opts ''BigProduct
21+
22+bigProduct :: BigProduct
23+bigProduct = BigProduct 1 2 3 4 5
24+ 6 7 8 9 10
25+ 11 12 13 14 15
26+ 16 17 18 19 20
27+ 21 22 23 24 25
benchmarks/Auto/T/BigRecord.hsnew file+27
@@ -0,0 +1,27 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+module Auto.T.BigRecord where
4+
5+import Control.DeepSeq
6+import Data.Aeson.TH
7+import Options
8+
9+data BigRecord = BigRecord
10+ { field01 :: !Int, field02 :: !Int, field03 :: !Int, field04 :: !Int, field05 :: !Int
11+ , field06 :: !Int, field07 :: !Int, field08 :: !Int, field09 :: !Int, field10 :: !Int
12+ , field11 :: !Int, field12 :: !Int, field13 :: !Int, field14 :: !Int, field15 :: !Int
13+ , field16 :: !Int, field17 :: !Int, field18 :: !Int, field19 :: !Int, field20 :: !Int
14+ , field21 :: !Int, field22 :: !Int, field23 :: !Int, field24 :: !Int, field25 :: !Int
15+ } deriving (Show, Eq)
16+
17+instance NFData BigRecord where
18+ rnf a = a `seq` ()
19+
20+deriveJSON opts ''BigRecord
21+
22+bigRecord :: BigRecord
23+bigRecord = BigRecord 1 2 3 4 5
24+ 6 7 8 9 10
25+ 11 12 13 14 15
26+ 16 17 18 19 20
27+ 21 22 23 24 25
benchmarks/Auto/T/BigSum.hsnew file+22
@@ -0,0 +1,22 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+module Auto.T.BigSum where
4+
5+import Control.DeepSeq
6+import Data.Aeson.TH
7+import Options
8+
9+data BigSum = F01 | F02 | F03 | F04 | F05
10+ | F06 | F07 | F08 | F09 | F10
11+ | F11 | F12 | F13 | F14 | F15
12+ | F16 | F17 | F18 | F19 | F20
13+ | F21 | F22 | F23 | F24 | F25
14+ deriving (Show, Eq)
15+
16+instance NFData BigSum where
17+ rnf a = a `seq` ()
18+
19+deriveJSON opts ''BigSum
20+
21+bigSum :: BigSum
22+bigSum = F25
benchmarks/Auto/T/D.hsnew file+38
@@ -0,0 +1,38 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+module Auto.T.D where
4+
5+import Control.DeepSeq
6+import Data.Aeson.TH
7+import Options
8+
9+data D a = Nullary
10+ | Unary Int
11+ | Product String Char a
12+ | Record { testOne :: Double
13+ , testTwo :: Bool
14+ , testThree :: D a
15+ }
16+ deriving (Show, Eq)
17+
18+instance NFData a => NFData (D a) where
19+ rnf Nullary = ()
20+ rnf (Unary n) = rnf n
21+ rnf (Product s c x) = s `deepseq` c `deepseq` rnf x
22+ rnf (Record a b y) = a `deepseq` b `deepseq` rnf y
23+
24+deriveJSON opts ''D
25+
26+type T = D (D (D ()))
27+
28+d :: T
29+d = Record
30+ { testOne = 1234.56789
31+ , testTwo = True
32+ , testThree = Product "Hello World!" 'a'
33+ Record
34+ { testOne = 9876.54321
35+ , testTwo = False
36+ , testThree = Product "Yeehaa!!!" '\n' Nullary
37+ }
38+ }
benchmarks/AutoCompare.hsnew file+73
@@ -0,0 +1,73 @@
1+{-# LANGUAGE RankNTypes #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+
4+module Main (main) where
5+
6+import Control.DeepSeq
7+import Control.Monad
8+import Criterion.Main
9+import Data.Aeson
10+
11+import qualified Auto.T.D as T
12+import qualified Auto.T.BigRecord as T
13+import qualified Auto.T.BigProduct as T
14+import qualified Auto.T.BigSum as T
15+import qualified Auto.G.D as G
16+import qualified Auto.G.BigRecord as G
17+import qualified Auto.G.BigProduct as G
18+import qualified Auto.G.BigSum as G
19+
20+--------------------------------------------------------------------------------
21+
22+runBench :: IO ()
23+runBench = defaultMain
24+ [ compareBench "D" T.d G.d
25+ , compareBench "BigRecord" T.bigRecord G.bigRecord
26+ , compareBench "BigProduct" T.bigProduct G.bigProduct
27+ , compareBench "BigSum" T.bigSum G.bigSum
28+ ]
29+
30+group :: String -> Benchmarkable -> Benchmarkable -> Benchmark
31+group n th gen = bgroup n [ bench "th" th
32+ , bench "generic" gen
33+ ]
34+
35+compareBench
36+ :: forall a b
37+ . (ToJSON a, FromJSON a, NFData a, ToJSON b, FromJSON b, NFData b)
38+ => String -> a -> b -> Benchmark
39+compareBench name a b = v `deepseq` bgroup name
40+ [ group "toJSON" (nf toJSON a)
41+ (nf toJSON b)
42+ , group "encode" (nf encode a)
43+ (nf encode b)
44+ , group "fromJSON" (nf (fromJSON :: Value -> Result a) v)
45+ (nf (fromJSON :: Value -> Result b) v)
46+ ] where
47+ v = toJSON a -- == toJSON b
48+
49+sanityCheck :: IO ()
50+sanityCheck = do
51+ check T.d
52+ check G.d
53+ check T.bigRecord
54+ check G.bigRecord
55+ check T.bigProduct
56+ check G.bigProduct
57+ check T.bigSum
58+ check G.bigSum
59+
60+check :: (Show a, Eq a, FromJSON a, ToJSON a)
61+ => a -> IO ()
62+check x = do
63+ unless (Success x == (fromJSON . toJSON) x) $ fail $ "toJSON: " ++ show x
64+ unless (Success x == (decode_ . encode) x) $ fail $ "encode: " ++ show x
65+ where
66+ decode_ s = case decode s of
67+ Just v -> fromJSON v
68+ Nothing -> fail ""
69+
70+main :: IO ()
71+main = do
72+ sanityCheck
73+ runBench
benchmarks/Compare.hs+12−3
@@ -1,17 +1,24 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
13{-# LANGUAGE ScopedTypeVariables #-}
24
35module Main (main) where
46
7+import Prelude.Compat
8+
59import Compare.BufferBuilder ()
6−import Compare.JsonBuilder ()
710import Criterion.Main
811import Data.BufferBuilder.Json
9−import Data.Json.Builder
1012import Twitter
1113import Twitter.Manual ()
1214import Typed.Common
13−import qualified Compare.JsonBench as JsonBench
1415import qualified Data.Aeson as Aeson
16+import qualified Compare.JsonBench as JsonBench
17+
18+#ifdef MIN_VERSION_json_builder
19+import Data.Json.Builder
20+import Compare.JsonBuilder ()
21+#endif
1522
1623main :: IO ()
1724main =
@@ -20,7 +27,9 @@ main =
2027 bgroup "twitter" [
2128 bench "aeson" $ nf Aeson.encode twtr
2229 , bench "buffer-builder" $ nf encodeJson twtr
30+#ifdef MIN_VERSION_json_builder
2331 , bench "json-builder" $ nf toJsonLBS twtr
32+#endif
2433 ]
2534 , JsonBench.benchmarks
2635 ]
benchmarks/Compare/BufferBuilder.hs+9−4
@@ -1,12 +1,17 @@
1−{-# LANGUAGE OverloadedStrings, RecordWildCards #-}
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE RecordWildCards #-}
4+
5+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
26{-# OPTIONS_GHC -fno-warn-orphans #-}
37
48module Compare.BufferBuilder () where
59
10+import Prelude.Compat hiding ((<>))
11+
612import Data.BufferBuilder.Json
7−import Data.Monoid ((<>))
813import Data.Int (Int64)
9−import Prelude hiding (id)
14+import Data.Monoid ((<>))
1015import Twitter
1116import qualified Data.BufferBuilder.Utf8 as UB
1217
@@ -37,7 +42,7 @@ instance ToJson Story where
3742 <> "metadata" .= metadata
3843 <> "to_user_id" .= to_user_id
3944 <> "text" .= text
40− <> "id" .= id
45+ <> "id" .= id_
4146 <> "from_user_id" .= from_user_id
4247 <> "geo" .= geo
4348 <> "iso_language_code" .= iso_language_code
benchmarks/Compare/JsonBench.hs+21−7
@@ -1,22 +1,32 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE BangPatterns #-}
3+{-# LANGUAGE MagicHash #-}
4+{-# LANGUAGE NoImplicitPrelude #-}
5+{-# LANGUAGE OverloadedStrings #-}
6+{-# LANGUAGE RecordWildCards #-}
7+{-# LANGUAGE ScopedTypeVariables #-}
8+
19-- Adapted from a buffer-builder benchmark:
210--
311-- https://github.com/chadaustin/buffer-builder/blob/master/test.json
412
5−{-# LANGUAGE BangPatterns, OverloadedStrings, RecordWildCards #-}
6−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
7−{-# LANGUAGE MagicHash, ScopedTypeVariables #-}
8−
913module Compare.JsonBench (benchmarks) where
1014
15+import Prelude.Compat hiding ((<>))
16+
1117import Control.DeepSeq (NFData(..))
1218import Criterion
1319import Data.Aeson ((.:))
1420import Data.Monoid ((<>))
1521import Data.Text (Text)
1622import Typed.Common (load)
23+import qualified Control.Monad.Fail as Fail
1724import qualified Data.Aeson as Aeson
1825import qualified Data.BufferBuilder.Json as Json
26+
27+#ifdef MIN_VERSION_json_builder
1928import qualified Data.Json.Builder as JB
29+#endif
2030
2131data EyeColor = Green | Blue | Brown
2232 deriving (Eq, Show)
@@ -59,10 +69,10 @@ instance NFData Gender where rnf !_ = ()
5969instance NFData Fruit where rnf !_ = ()
6070
6171instance NFData Friend where
62− rnf Friend {..} = (rnf fId) `seq` (rnf fName) `seq` ()
72+ rnf Friend {..} = rnf fId `seq` rnf fName
6373
6474instance NFData User where
65− rnf User {..} = (rnf uId) `seq` (rnf uIndex) `seq` (rnf uGuid) `seq` (rnf uIsActive) `seq` (rnf uBalance) `seq` (rnf uPicture) `seq` (rnf uAge) `seq` (rnf uEyeColor) `seq` (rnf uName) `seq` (rnf uGender) `seq` (rnf uCompany) `seq` (rnf uEmail) `seq` (rnf uPhone) `seq` (rnf uAddress) `seq` (rnf uAbout) `seq` (rnf uRegistered) `seq` (rnf uLatitude) `seq` (rnf uLongitude) `seq` (rnf uTags) `seq` (rnf uFriends) `seq` (rnf uGreeting) `seq` (rnf uFavouriteFruit) `seq` ()
75+ rnf User {..} = rnf uId `seq` rnf uIndex `seq` rnf uGuid `seq` rnf uIsActive `seq` rnf uBalance `seq` rnf uPicture `seq` rnf uAge `seq` rnf uEyeColor `seq` rnf uName `seq` rnf uGender `seq` rnf uCompany `seq` rnf uEmail `seq` rnf uPhone `seq` rnf uAddress `seq` rnf uAbout `seq` rnf uRegistered `seq` rnf uLatitude `seq` rnf uLongitude `seq` rnf uTags `seq` rnf uFriends `seq` rnf uGreeting `seq` rnf uFavouriteFruit
6676
6777eyeColorTable :: [(Text, EyeColor)]
6878eyeColorTable = [("brown", Brown), ("green", Green), ("blue", Blue)]
@@ -73,7 +83,7 @@ genderTable = [("male", Male), ("female", Female)]
7383fruitTable :: [(Text, Fruit)]
7484fruitTable = [("apple", Apple), ("strawberry", Strawberry), ("banana", Banana)]
7585
76−enumFromJson :: Monad m => String -> [(Text, enum)] -> (json -> m Text) -> json -> m enum
86+enumFromJson :: Fail.MonadFail m => String -> [(Text, enum)] -> (json -> m Text) -> json -> m enum
7787enumFromJson enumName table extract v = do
7888 s <- extract v
7989 case lookup s table of
@@ -263,6 +273,7 @@ instance Json.ToJson User where
263273 <> "greeting"# Json..=# uGreeting
264274 <> "favoriteFruit"# Json..=# uFavouriteFruit
265275
276+#ifdef MIN_VERSION_json_builder
266277---- json-builder instances ----
267278
268279instance JB.Value EyeColor where
@@ -314,6 +325,7 @@ instance JB.Value User where
314325 <> t "friends" `JB.row` uFriends
315326 <> t "greeting" `JB.row` uGreeting
316327 <> t "favoriteFruit" `JB.row` uFavouriteFruit
328+#endif
317329
318330benchmarks :: Benchmark
319331benchmarks = env (load "json-data/buffer-builder.json") $
@@ -321,5 +333,7 @@ benchmarks = env (load "json-data/buffer-builder.json") $
321333 bgroup "json-bench" [
322334 bench "aeson" $ nf Aeson.encode parsedUserList
323335 , bench "buffer-builder" $ nf Json.encodeJson parsedUserList
336+#ifdef MIN_VERSION_json_builder
324337 , bench "json-builder" $ nf JB.toJsonLBS parsedUserList
338+#endif
325339 ]
benchmarks/Compare/JsonBuilder.hs+6−2
@@ -1,11 +1,15 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE RecordWildCards #-}
3+
4+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
25{-# OPTIONS_GHC -fno-warn-orphans #-}
36
47module Compare.JsonBuilder () where
58
9+import Prelude.Compat hiding ((<>))
10+
611import Data.Json.Builder
712import Data.Monoid ((<>))
8−import Prelude hiding (id)
913import Twitter
1014
1115instance JsObject Metadata where
@@ -36,7 +40,7 @@ instance JsObject Story where
3640 row "metadata" metadata <>
3741 row "to_user_id" to_user_id <>
3842 row "text" text <>
39− row "id" id <>
43+ row "id" id_ <>
4044 row "from_user_id" from_user_id <>
4145 row "geo" geo <>
4246 row "iso_language_code" iso_language_code <>
benchmarks/CompareWithJSON.hs+38−21
@@ -1,16 +1,25 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
13{-# OPTIONS_GHC -fno-warn-orphans #-}
24
5+module Main (main) where
6+
7+import Prelude.Compat
8+
39import Blaze.ByteString.Builder (toLazyByteString)
410import Blaze.ByteString.Builder.Char.Utf8 (fromString)
511import Control.DeepSeq (NFData(rnf))
612import Criterion.Main
13+import Data.Maybe (fromMaybe)
714import qualified Data.Aeson as A
815import qualified Data.Aeson.Text as A
16+import qualified Data.Aeson.Parser.Internal as I
17+import qualified Data.ByteString as BS
918import qualified Data.ByteString.Lazy as BL
10−import qualified Text.JSON as J
1119import qualified Data.Text.Lazy as TL
1220import qualified Data.Text.Lazy.Builder as TLB
1321import qualified Data.Text.Lazy.Encoding as TLE
22+import qualified Text.JSON as J
1423
1524instance (NFData v) => NFData (J.JSObject v) where
1625 rnf o = rnf (J.fromJSObject o)
@@ -18,7 +27,7 @@ instance (NFData v) => NFData (J.JSObject v) where
1827instance NFData J.JSValue where
1928 rnf J.JSNull = ()
2029 rnf (J.JSBool b) = rnf b
21− rnf (J.JSRational a b) = rnf a `seq` rnf b `seq` ()
30+ rnf (J.JSRational a b) = rnf a `seq` rnf b
2231 rnf (J.JSString s) = rnf (J.fromJSString s)
2332 rnf (J.JSArray lst) = rnf lst
2433 rnf (J.JSObject o) = rnf o
@@ -29,15 +38,18 @@ decodeJ s =
2938 J.Ok v -> v
3039 J.Error _ -> error "fail to parse via JSON"
3140
32−decodeA :: BL.ByteString -> A.Value
33−decodeA s = case A.decode s of
34− Just v -> v
35− Nothing -> error "fail to parse via Aeson"
41+decode :: BL.ByteString -> A.Value
42+decode s = fromMaybe (error "fail to parse via Aeson") $ A.decode s
43+
44+decode' :: BL.ByteString -> A.Value
45+decode' s = fromMaybe (error "fail to parse via Aeson") $ A.decode' s
46+
47+decodeS :: BS.ByteString -> A.Value
48+decodeS s = fromMaybe (error "fail to parse via Aeson") $ A.decodeStrict' s
3649
37−decodeA' :: BL.ByteString -> A.Value
38−decodeA' s = case A.decode' s of
39− Just v -> v
40− Nothing -> error "fail to parse via Aeson"
50+decodeIP :: BL.ByteString -> A.Value
51+decodeIP s = fromMaybe (error "fail to parse via Parser.decodeWith") $
52+ I.decodeWith I.jsonEOF A.fromJSON s
4153
4254encodeJ :: J.JSValue -> BL.ByteString
4355encodeJ = toLazyByteString . fromString . J.encode
@@ -53,32 +65,37 @@ main = do
5365 let enFile = "json-data/twitter100.json"
5466 jpFile = "json-data/jp100.json"
5567 enA <- BL.readFile enFile
68+ enS <- BS.readFile enFile
5669 enJ <- readFile enFile
5770 jpA <- BL.readFile jpFile
71+ jpS <- BS.readFile jpFile
5872 jpJ <- readFile jpFile
5973 defaultMain [
6074 bgroup "decode" [
6175 bgroup "en" [
62− bench "aeson/lazy" $ nf decodeA enA
63− , bench "aeson/strict" $ nf decodeA' enA
64− , bench "json" $ nf decodeJ enJ
76+ bench "aeson/lazy" $ nf decode enA
77+ , bench "aeson/strict" $ nf decode' enA
78+ , bench "aeson/stricter" $ nf decodeS enS
79+ , bench "aeson/parser" $ nf decodeIP enA
80+ , bench "json" $ nf decodeJ enJ
6581 ]
6682 , bgroup "jp" [
67− bench "aeson" $ nf decodeA jpA
68− , bench "json" $ nf decodeJ jpJ
83+ bench "aeson" $ nf decode jpA
84+ , bench "aeson/stricter" $ nf decodeS jpS
85+ , bench "json" $ nf decodeJ jpJ
6986 ]
7087 ]
7188 , bgroup "encode" [
7289 bgroup "en" [
73− bench "aeson-to-bytestring" $ nf A.encode (decodeA enA)
74− , bench "aeson-via-text-to-bytestring" $ nf encodeViaText (decodeA enA)
75− , bench "aeson-to-text" $ nf encodeToText (decodeA enA)
90+ bench "aeson-to-bytestring" $ nf A.encode (decode enA)
91+ , bench "aeson-via-text-to-bytestring" $ nf encodeViaText (decode enA)
92+ , bench "aeson-to-text" $ nf encodeToText (decode enA)
7693 , bench "json" $ nf encodeJ (decodeJ enJ)
7794 ]
7895 , bgroup "jp" [
79− bench "aeson-to-bytestring" $ nf A.encode (decodeA jpA)
80− , bench "aeson-via-text-to-bytestring" $ nf encodeViaText (decodeA jpA)
81− , bench "aeson-to-text" $ nf encodeToText (decodeA jpA)
96+ bench "aeson-to-bytestring" $ nf A.encode (decode jpA)
97+ , bench "aeson-via-text-to-bytestring" $ nf encodeViaText (decode jpA)
98+ , bench "aeson-to-text" $ nf encodeToText (decode jpA)
8299 , bench "json" $ nf encodeJ (decodeJ jpJ)
83100 ]
84101 ]
benchmarks/Dates.hs+14−9
@@ -1,4 +1,9 @@
1−import Control.Applicative ((<$>))
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
3+module Main (main) where
4+
5+import Prelude.Compat
6+
27import Criterion.Main
38import Data.Aeson (decode, encode)
49import Data.Time.Clock (UTCTime)
@@ -18,22 +23,22 @@ main = do
1823 defaultMain [
1924 bgroup "decode" [
2025 bgroup "UTCTime" [
21− env file1 $ \ ~bs -> bench "whole" $ nf utcTime bs
22− , env file2 $ \ ~bs -> bench "fractional" $ nf utcTime bs
26+ env file1 $ \bs -> bench "whole" $ nf utcTime bs
27+ , env file2 $ \bs -> bench "fractional" $ nf utcTime bs
2328 ]
2429 , bgroup "ZonedTime" [
25− env file1 $ \ ~bs -> bench "whole" $ nf zTime bs
26− , env file2 $ \ ~bs -> bench "fractional" $ nf zTime bs
30+ env file1 $ \bs -> bench "whole" $ nf zTime bs
31+ , env file2 $ \bs -> bench "fractional" $ nf zTime bs
2732 ]
2833 ]
2934 , bgroup "encode" [
3035 bgroup "UTCTime" [
31− env (utcTime <$> file1) $ \ ~ts -> bench "whole" $ nf encode ts
32− , env (utcTime <$> file2) $ \ ~ts -> bench "fractional" $ nf encode ts
36+ env (utcTime <$> file1) $ \ts -> bench "whole" $ nf encode ts
37+ , env (utcTime <$> file2) $ \ts -> bench "fractional" $ nf encode ts
3338 ]
3439 , bgroup "ZonedTime" [
35− env (zTime <$> file1) $ \ ~ts -> bench "whole" $ nf encode ts
36− , env (zTime <$> file2) $ \ ~ts -> bench "fractional" $ nf encode ts
40+ env (zTime <$> file1) $ \ts -> bench "whole" $ nf encode ts
41+ , env (zTime <$> file2) $ \ts -> bench "fractional" $ nf encode ts
3742 ]
3843 ]
3944 ]
benchmarks/Escape.hsnew file+32
@@ -0,0 +1,32 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+
4+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
5+
6+module Main (main) where
7+
8+import Prelude.Compat
9+
10+import Criterion.Main
11+import qualified Data.Aeson.Parser.UnescapeFFI as FFI
12+import qualified Data.Aeson.Parser.UnescapePure as Pure
13+
14+import qualified Data.ByteString.Char8 as BS
15+import System.Environment (getArgs, withArgs)
16+
17+main :: IO ()
18+main = do
19+ args_ <- getArgs
20+ let (args, p, n) =
21+ case args_ of
22+ "--pattern" : p : args_ -> k p args_
23+ _ -> k "\\\"" args_
24+ k p args_ =
25+ case args_ of
26+ "--repeat" : n : args_ -> (args_, p, read n)
27+ args_ -> (args_, p, 10000)
28+ input = BS.concat $ replicate n $ BS.pack p
29+ withArgs args $ defaultMain
30+ [ bench "ffi" $ whnf FFI.unescapeText input
31+ , bench "pure" $ whnf Pure.unescapeText input
32+ ]
benchmarks/Issue673.hsnew file+165
@@ -0,0 +1,165 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+
4+module Main (
5+ main,
6+ input17,
7+ input32,
8+ input64,
9+ input128,
10+ input256,
11+ input2048,
12+ input4096,
13+ input8192,
14+ input16384,
15+ ) where
16+
17+import Criterion.Main
18+import Prelude.Compat
19+import Data.Int (Int64)
20+import Data.Scientific (Scientific)
21+import Data.Semigroup ((<>))
22+import Data.Aeson.Parser (scientific)
23+
24+import qualified Data.Attoparsec.ByteString.Lazy as AttoL
25+import qualified Data.Attoparsec.ByteString.Char8 as Atto8
26+import qualified Data.Aeson as A
27+import qualified Data.ByteString as BS
28+import qualified Data.ByteString.Lazy as LBS
29+import qualified Data.ByteString.Lazy.Char8 as LBS8
30+
31+decodeInt :: LBS.ByteString -> Maybe Int
32+decodeInt = A.decode
33+
34+decodeString :: LBS.ByteString -> Maybe String
35+decodeString = A.decode
36+
37+decodeScientific :: LBS.ByteString -> Maybe Scientific
38+decodeScientific = A.decode
39+
40+decodeViaRead :: LBS.ByteString -> Integer
41+decodeViaRead = read . LBS8.unpack
42+
43+decodeAtto :: LBS.ByteString -> Maybe Scientific
44+decodeAtto
45+ = parseOnly (scientific <* AttoL.endOfInput)
46+ where
47+ parseOnly p lbs = case AttoL.parse p lbs of
48+ AttoL.Done _ r -> Just r
49+ AttoL.Fail {} -> Nothing
50+
51+decodeAtto8 :: LBS.ByteString -> Maybe Scientific
52+decodeAtto8
53+ = parseOnly (Atto8.scientific <* AttoL.endOfInput)
54+ where
55+ parseOnly p lbs = case AttoL.parse p lbs of
56+ AttoL.Done _ r -> Just r
57+ AttoL.Fail {} -> Nothing
58+
59+generate :: Int64 -> LBS.ByteString
60+generate n = LBS8.replicate n '1'
61+
62+input17 :: LBS.ByteString
63+input17 = generate 17
64+
65+input32 :: LBS.ByteString
66+input32 = generate 32
67+
68+input64 :: LBS.ByteString
69+input64 = generate 64
70+
71+input128 :: LBS.ByteString
72+input128 = generate 128
73+
74+input256 :: LBS.ByteString
75+input256 = generate 256
76+
77+input2048 :: LBS.ByteString
78+input2048 = generate 2048
79+
80+input4096 :: LBS.ByteString
81+input4096 = generate 4096
82+
83+input8192 :: LBS.ByteString
84+input8192 = generate 8192
85+
86+input16384 :: LBS.ByteString
87+input16384 = generate 16384
88+
89+
90+main :: IO ()
91+main = defaultMain
92+ -- works on 64bit
93+ [ benchPair "17" input17
94+ -- , benchPair "32" input32
95+ -- , benchPair "64" input64
96+ -- , benchPair "128" input128
97+ -- , benchPair "256" input256
98+ , benchPair "2048" input2048
99+ , benchPair "4096" input4096
100+ , benchPair "8192" input8192
101+ , benchPair "16384" input16384
102+ ]
103+ where
104+ benchPair name input = bgroup name
105+ [ bench "Int" $ whnf decodeInt input
106+ , bench "Simple" $ whnf bsToIntegerSimple (LBS.toStrict input)
107+ , bench "Optim" $ whnf bsToInteger (LBS.toStrict input)
108+ , bench "Read" $ whnf decodeViaRead input
109+ , bench "Scientific" $ whnf decodeScientific input
110+ , bench "parserA" $ whnf decodeAtto input
111+ , bench "parserS" $ whnf decodeAtto8 input
112+ , bench "String" $ whnf decodeString $ "\"" <> input <> "\""
113+ ]
114+
115+-------------------------------------------------------------------------------
116+-- better fromInteger
117+-------------------------------------------------------------------------------
118+
119+bsToInteger :: BS.ByteString -> Integer
120+bsToInteger bs
121+ | l > 40 = valInteger 10 l [ fromIntegral (w - 48) | w <- BS.unpack bs ]
122+ | otherwise = bsToIntegerSimple bs
123+ where
124+ l = BS.length bs
125+
126+bsToIntegerSimple :: BS.ByteString -> Integer
127+bsToIntegerSimple = BS.foldl' step 0 where
128+ step a b = a * 10 + fromIntegral (b - 48) -- 48 = '0'
129+
130+-- A sub-quadratic algorithm for Integer. Pairs of adjacent radix b
131+-- digits are combined into a single radix b^2 digit. This process is
132+-- repeated until we are left with a single digit. This algorithm
133+-- performs well only on large inputs, so we use the simple algorithm
134+-- for smaller inputs.
135+valInteger :: Integer -> Int -> [Integer] -> Integer
136+valInteger = go
137+ where
138+ go :: Integer -> Int -> [Integer] -> Integer
139+ go _ _ [] = 0
140+ go _ _ [d] = d
141+ go b l ds
142+ | l > 40 = b' `seq` go b' l' (combine b ds')
143+ | otherwise = valSimple b ds
144+ where
145+ -- ensure that we have an even number of digits
146+ -- before we call combine:
147+ ds' = if even l then ds else 0 : ds
148+ b' = b * b
149+ l' = (l + 1) `quot` 2
150+
151+ combine b (d1 : d2 : ds) = d `seq` (d : combine b ds)
152+ where
153+ d = d1 * b + d2
154+ combine _ [] = []
155+ combine _ [_] = errorWithoutStackTrace "this should not happen"
156+
157+-- The following algorithm is only linear for types whose Num operations
158+-- are in constant time.
159+valSimple :: Integer -> [Integer] -> Integer
160+valSimple base = go 0
161+ where
162+ go r [] = r
163+ go r (d : ds) = r' `seq` go r' ds
164+ where
165+ r' = r * base + fromIntegral d
benchmarks/JsonParse.hs+10−3
@@ -1,16 +1,23 @@
1−{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE ScopedTypeVariables #-}
4+
25{-# OPTIONS_GHC -fno-warn-orphans #-}
36
7+module Main (main) where
8+
9+import Prelude.Compat
10+
411import Control.DeepSeq
512import Control.Monad
6−import Text.JSON
713import Data.Time.Clock
814import System.Environment (getArgs)
15+import Text.JSON
916
1017instance NFData JSValue where
1118 rnf JSNull = ()
1219 rnf (JSBool b) = rnf b
13− rnf (JSRational b r) = rnf b `seq` rnf r `seq` ()
20+ rnf (JSRational b r) = rnf b `seq` rnf r
1421 rnf (JSString s) = rnf (fromJSString s)
1522 rnf (JSArray vs) = rnf vs
1623 rnf (JSObject kvs) = rnf (fromJSObject kvs)
benchmarks/Micro.hs+10−6
@@ -1,18 +1,22 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
13module Main (main) where
24
5+import Prelude.Compat
6+
37import Criterion.Main
4−import qualified Data.Aeson.Encoding.Builder as AB
5−import qualified Data.ByteString.Builder as B
6−import qualified Data.Text as T
78
9+-- Encoding is a newtype wrapper around Builder
10+import Data.Aeson.Encoding (text, string, encodingToLazyByteString)
11+import qualified Data.Text as T
812
913main :: IO ()
1014main = do
1115 let txt = "append (append b (primBounded w1 x1)) (primBounded w2 x2)"
1216 defaultMain [
1317 bgroup "string" [
14− bench "text" $ nf (B.toLazyByteString . AB.text) (T.pack txt)
15− , bench "string direct" $ nf (B.toLazyByteString . AB.string) txt
16− , bench "string via text" $ nf (B.toLazyByteString . AB.text . T.pack) txt
18+ bench "text" $ nf (encodingToLazyByteString . text) (T.pack txt)
19+ , bench "string direct" $ nf (encodingToLazyByteString . string) txt
20+ , bench "string via text" $ nf (encodingToLazyByteString . text . T.pack) txt
1721 ]
1822 ]
benchmarks/Options.hs+1−1
@@ -1,4 +1,4 @@
1−module Options where
1+module Options (opts) where
22
33import Data.Aeson.Types
44
benchmarks/ReadFile.hs+8−2
@@ -1,4 +1,10 @@
1−{-# LANGUAGE BangPatterns, OverloadedStrings #-}
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+
5+module Main (main) where
6+
7+import Prelude.Compat
28
39import Control.DeepSeq
410import Control.Exception
@@ -14,7 +20,7 @@ import qualified Data.ByteString as B
1420main = do
1521 (cnt:args) <- getArgs
1622 let count = read cnt :: Int
17− forM_ args $ \arg -> bracket (openFile arg ReadMode) hClose $ \h -> do
23+ forM_ args $ \arg -> withFile arg ReadMode $ \h -> do
1824 putStrLn $ arg ++ ":"
1925 start <- getCurrentTime
2026 let loop !n
benchmarks/Typed.hs+7
@@ -1,5 +1,9 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
13module Main (main) where
24
5+import Prelude.Compat
6+
37import Criterion.Main
48import qualified Typed.Generic as Generic
59import qualified Typed.Manual as Manual
@@ -10,4 +14,7 @@ main = defaultMain [
1014 Generic.benchmarks
1115 , Manual.benchmarks
1216 , TH.benchmarks
17+ , Generic.decodeBenchmarks
18+ , Manual.decodeBenchmarks
19+ , TH.decodeBenchmarks
1320 ]
benchmarks/Typed/Common.hs+9−3
@@ -1,10 +1,16 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
3+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
4+
15module Typed.Common (load) where
26
3−import Data.Aeson hiding (Result)
7+import Prelude.Compat
8+
49import Data.ByteString.Lazy as L
5−import Control.Applicative
6−import System.IO
710import System.Exit
11+import System.IO
12+
13+import Data.Aeson hiding (Result)
814
915load :: FromJSON a => FilePath -> IO a
1016load fileName = do
benchmarks/Typed/Generic.hs+23−8
@@ -1,11 +1,13 @@
1−module Typed.Generic (benchmarks) where
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
3+module Typed.Generic (benchmarks, decodeBenchmarks) where
4+
5+import Prelude.Compat
26
3−import Control.Applicative
4−import Criterion
57import Data.Aeson hiding (Result)
6−import Data.ByteString.Builder as B
8+import Criterion
79import Data.ByteString.Lazy as L
8−import Twitter.TH
10+import Twitter.Generic
911import Typed.Common
1012
1113encodeDirect :: Result -> L.ByteString
@@ -17,13 +19,26 @@ encodeViaValue = encode . toJSON
1719benchmarks :: Benchmark
1820benchmarks =
1921 env ((,) <$> load "json-data/twitter100.json" <*> load "json-data/jp100.json") $ \ ~(twitter100, jp100) ->
20− bgroup "generic" [
22+ bgroup "encodeGeneric" [
2123 bgroup "direct" [
2224 bench "twitter100" $ nf encodeDirect twitter100
23− , bench "jp100" $ nf encodeDirect jp100
25+ , bench "jp100" $ nf encodeDirect jp100
2426 ]
2527 , bgroup "viaValue" [
2628 bench "twitter100" $ nf encodeViaValue twitter100
27− , bench "jp100" $ nf encodeViaValue jp100
29+ , bench "jp100" $ nf encodeViaValue jp100
30+ ]
31+ ]
32+
33+decodeDirect :: L.ByteString -> Maybe Result
34+decodeDirect = decode
35+
36+decodeBenchmarks :: Benchmark
37+decodeBenchmarks =
38+ env ((,) <$> L.readFile "json-data/twitter100.json" <*> L.readFile "json-data/jp100.json") $ \ ~(twitter100, jp100) ->
39+ bgroup "decodeGeneric"
40+ [ bgroup "direct"
41+ [ bench "twitter100" $ nf decodeDirect twitter100
42+ , bench "jp100" $ nf decodeDirect jp100
2843 ]
2944 ]
benchmarks/Typed/Manual.hs+22−7
@@ -1,9 +1,11 @@
1−module Typed.Manual (benchmarks) where
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
3+module Typed.Manual (benchmarks, decodeBenchmarks) where
4+
5+import Prelude.Compat
26
3−import Control.Applicative
4−import Criterion
57import Data.Aeson hiding (Result)
6−import Data.ByteString.Builder as B
8+import Criterion
79import Data.ByteString.Lazy as L
810import Twitter.Manual
911import Typed.Common
@@ -17,13 +19,26 @@ encodeViaValue = encode . toJSON
1719benchmarks :: Benchmark
1820benchmarks =
1921 env ((,) <$> load "json-data/twitter100.json" <*> load "json-data/jp100.json") $ \ ~(twitter100, jp100) ->
20− bgroup "manual" [
22+ bgroup "encodeManual" [
2123 bgroup "direct" [
2224 bench "twitter100" $ nf encodeDirect twitter100
23− , bench "jp100" $ nf encodeDirect jp100
25+ , bench "jp100" $ nf encodeDirect jp100
2426 ]
2527 , bgroup "viaValue" [
2628 bench "twitter100" $ nf encodeViaValue twitter100
27− , bench "jp100" $ nf encodeViaValue jp100
29+ , bench "jp100" $ nf encodeViaValue jp100
30+ ]
31+ ]
32+
33+decodeDirect :: L.ByteString -> Maybe Result
34+decodeDirect = decode
35+
36+decodeBenchmarks :: Benchmark
37+decodeBenchmarks =
38+ env ((,) <$> L.readFile "json-data/twitter100.json" <*> L.readFile "json-data/jp100.json") $ \ ~(twitter100, jp100) ->
39+ bgroup "decodeManual"
40+ [ bgroup "direct"
41+ [ bench "twitter100" $ nf decodeDirect twitter100
42+ , bench "jp100" $ nf decodeDirect jp100
2843 ]
2944 ]
benchmarks/Typed/TH.hs+22−7
@@ -1,9 +1,11 @@
1−module Typed.TH (benchmarks) where
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
3+module Typed.TH (benchmarks, decodeBenchmarks) where
4+
5+import Prelude.Compat
26
3−import Control.Applicative
4−import Criterion
57import Data.Aeson hiding (Result)
6−import Data.ByteString.Builder as B
8+import Criterion
79import Data.ByteString.Lazy as L
810import Twitter.TH
911import Typed.Common
@@ -17,13 +19,26 @@ encodeViaValue = encode . toJSON
1719benchmarks :: Benchmark
1820benchmarks =
1921 env ((,) <$> load "json-data/twitter100.json" <*> load "json-data/jp100.json") $ \ ~(twitter100, jp100) ->
20− bgroup "th" [
22+ bgroup "encodeTH" [
2123 bgroup "direct" [
2224 bench "twitter100" $ nf encodeDirect twitter100
23− , bench "jp100" $ nf encodeDirect jp100
25+ , bench "jp100" $ nf encodeDirect jp100
2426 ]
2527 , bgroup "viaValue" [
2628 bench "twitter100" $ nf encodeViaValue twitter100
27− , bench "jp100" $ nf encodeViaValue jp100
29+ , bench "jp100" $ nf encodeViaValue jp100
30+ ]
31+ ]
32+
33+decodeDirect :: L.ByteString -> Maybe Result
34+decodeDirect = decode
35+
36+decodeBenchmarks :: Benchmark
37+decodeBenchmarks =
38+ env ((,) <$> L.readFile "json-data/twitter100.json" <*> L.readFile "json-data/jp100.json") $ \ ~(twitter100, jp100) ->
39+ bgroup "decodeTH"
40+ [ bgroup "direct"
41+ [ bench "twitter100" $ nf decodeDirect twitter100
42+ , bench "jp100" $ nf decodeDirect jp100
2843 ]
2944 ]
benchmarks/aeson-benchmarks.cabal+226−60
@@ -1,91 +1,193 @@
11name: aeson-benchmarks
22version: 0
33build-type: Simple
4+cabal-version: >=1.10
45
5−cabal-version: >=1.8
6+flag bytestring-builder
7+ description: Depend on the bytestring-builder package for backwards compatibility.
8+ default: False
9+ manual: False
10+
11+flag local-aeson
12+ description: Build the local version of aeson, to avoid rebuilding aeson's
13+ reverse dependencies for benchmarking (statistics, criterion).
14+ default: True
15+ manual: True
616
717library
8− hs-source-dirs: .. .
9−
10− exposed-modules:
11− Data.Aeson
12− Data.Aeson.Encoding
13− Data.Aeson.Parser
14− Data.Aeson.Text
15− Data.Aeson.Types
16− Data.Aeson.TH
17−
18− Data.Aeson.Encoding.Internal
19− Data.Aeson.Internal
20− Data.Aeson.Internal.Time
21−
22− Data.Aeson.Encoding.Builder
23− Data.Aeson.Internal.Functions
24− Data.Aeson.Parser.Internal
25− Data.Aeson.Parser.Time
26− Data.Aeson.Types.FromJSON
27− Data.Aeson.Types.Generic
28− Data.Aeson.Types.ToJSON
29− Data.Aeson.Types.Class
30− Data.Aeson.Types.Internal
18+ default-language: Haskell2010
19+
20+ if flag(bytestring-builder)
21+ build-depends: bytestring >= 0.9 && < 0.10.4,
22+ bytestring-builder >= 0.10.4 && < 1
23+ else
24+ build-depends: bytestring >= 0.10.4
25+
26+ if flag(local-aeson)
27+
28+ hs-source-dirs: .. ../ffi ../pure ../attoparsec-iso8601
29+ c-sources: ../cbits/unescape_string.c
30+ build-depends:
31+ attoparsec,
32+ base,
33+ base-compat,
34+ containers,
35+ deepseq,
36+ dlist,
37+ fail,
38+ ghc-prim,
39+ hashable,
40+ mtl,
41+ primitive,
42+ scientific,
43+ syb,
44+ tagged,
45+ template-haskell,
46+ text,
47+ th-abstraction,
48+ time-compat,
49+ time,
50+ transformers,
51+ unordered-containers,
52+ uuid-types,
53+ vector
54+
55+ if !impl(ghc >= 8.6)
56+ build-depends: contravariant
57+
58+ if !impl(ghc >= 8.0)
59+ -- `Data.Semigroup` is available in base only since GHC 8.0 / base 4.9
60+ build-depends: semigroups,
61+ transformers-compat
62+
63+ if !impl(ghc >= 7.10)
64+ -- `Numeric.Natural` is available in base only since GHC 7.10 / base 4.8
65+ build-depends: nats,
66+ void
67+
68+ include-dirs: ../include
69+
70+ ghc-options: -O2 -Wall
71+ cpp-options: -DGENERICS
72+
73+ exposed-modules:
74+ Data.Aeson
75+ Data.Aeson.Encoding
76+ Data.Aeson.Encoding.Builder
77+ Data.Aeson.Encoding.Internal
78+ Data.Aeson.Internal
79+ Data.Aeson.Internal.Functions
80+ Data.Aeson.Internal.Time
81+ Data.Aeson.Parser
82+ Data.Aeson.Parser.Internal
83+ Data.Aeson.Parser.Time
84+ Data.Aeson.Parser.Unescape
85+ Data.Aeson.Parser.UnescapeFFI
86+ Data.Aeson.Parser.UnescapePure
87+ Data.Aeson.TH
88+ Data.Aeson.Text
89+ Data.Aeson.Types
90+ Data.Aeson.Types.Class
91+ Data.Aeson.Types.FromJSON
92+ Data.Aeson.Types.Generic
93+ Data.Aeson.Types.Internal
94+ Data.Aeson.Types.ToJSON
95+ Data.Attoparsec.Time
96+ Data.Attoparsec.Time.Internal
97+
98+ else
3199
100+ build-depends: aeson
101+
102+ reexported-modules:
103+ Data.Aeson,
104+ Data.Aeson.Encoding,
105+ Data.Aeson.Parser.Internal,
106+ Data.Aeson.Text,
107+ Data.Aeson.TH,
108+ Data.Aeson.Types
109+
110+executable aeson-benchmark-auto-compare
111+ default-language: Haskell2010
112+ main-is: AutoCompare.hs
113+ hs-source-dirs: .
114+ ghc-options: -Wall -O2 -rtsopts
115+ other-modules:
116+ Auto.T.D
117+ Auto.T.BigRecord
118+ Auto.T.BigProduct
119+ Auto.T.BigSum
120+ Auto.G.D
121+ Auto.G.BigRecord
122+ Auto.G.BigProduct
123+ Auto.G.BigSum
124+ Options
32125 build-depends:
33− attoparsec >= 0.13.0.1,
34− base == 4.*,
35− base-compat >= 0.9.1 && <0.10,
36− time-locale-compat >=0.1.1 && <0.2,
37− bytestring >= 0.10.4.0,
38− containers,
126+ aeson-benchmarks,
127+ base,
128+ criterion,
39129 deepseq,
40− dlist >= 0.2,
41− fail == 4.9.*,
42− ghc-prim >= 0.2,
43− hashable >= 1.1.2.0,
44− mtl,
45− scientific >= 0.3.1 && < 0.4,
46− syb,
47− tagged >=0.8.3 && <0.9,
48− template-haskell >= 2.4,
49− text >= 1.1.1.0,
50− time,
51− transformers,
52− unordered-containers >= 0.2.3.0,
53− vector >= 0.7.1
54−
55− if impl(ghc >=7.8)
56− cpp-options: -DHAS_COERCIBLE
57−
58− if !impl(ghc >= 8.0)
59− -- `Data.Semigroup` is available in base only since GHC 8.0 / base 4.9
60− build-depends: semigroups >= 0.16.1 && < 0.19
61−
62− include-dirs: ../include
63−
64− ghc-options: -O2 -Wall
65− cpp-options: -DGENERICS
130+ template-haskell
131+
132+executable aeson-benchmark-escape
133+ default-language: Haskell2010
134+ main-is: Escape.hs
135+ hs-source-dirs: ../examples .
136+ ghc-options: -Wall -O2 -rtsopts
137+ if flag(local-aeson)
138+ build-depends:
139+ aeson-benchmarks,
140+ base,
141+ base-compat,
142+ bytestring,
143+ criterion >= 1.0,
144+ deepseq,
145+ ghc-prim,
146+ text
147+ else
148+ -- Disabled because of inaccessible internals
149+ buildable: False
66150
67151executable aeson-benchmark-compare
152+ default-language: Haskell2010
68153 main-is: Compare.hs
69154 hs-source-dirs: ../examples .
70155 ghc-options: -Wall -O2 -rtsopts
156+ other-modules:
157+ Compare.BufferBuilder
158+ Compare.JsonBench
159+ Twitter
160+ Twitter.Manual
161+ Typed.Common
71162 build-depends:
72163 aeson-benchmarks,
73164 base,
165+ base-compat,
74166 buffer-builder,
75167 bytestring,
76168 criterion >= 1.0,
77169 deepseq,
78170 ghc-prim,
79− json-builder,
80171 text
81172
173+ if impl(ghc < 8.4)
174+ other-modules:
175+ Compare.JsonBuilder
176+ build-depends:
177+ json-builder
178+ if impl(ghc < 8.0)
179+ build-depends:
180+ semigroups
181+
82182executable aeson-benchmark-micro
183+ default-language: Haskell2010
83184 main-is: Micro.hs
84185 hs-source-dirs: ../examples .
85186 ghc-options: -Wall -O2 -rtsopts
86187 build-depends:
87188 aeson-benchmarks,
88189 base,
190+ base-compat,
89191 bytestring,
90192 criterion >= 1.0,
91193 deepseq,
@@ -93,25 +195,46 @@ executable aeson-benchmark-micro
93195 text
94196
95197executable aeson-benchmark-typed
198+ default-language: Haskell2010
96199 main-is: Typed.hs
97200 hs-source-dirs: ../examples .
98201 ghc-options: -Wall -O2 -rtsopts
202+ other-modules:
203+ Twitter
204+ Twitter.Generic
205+ Twitter.Manual
206+ Twitter.Options
207+ Twitter.TH
208+ Typed.Common
209+ Typed.Generic
210+ Typed.Manual
211+ Typed.TH
99212 build-depends:
100213 aeson-benchmarks,
101214 base,
102− bytestring,
215+ base-compat,
103216 criterion >= 1.0,
104217 deepseq,
105218 ghc-prim,
106219 text,
107220 time
108221
222+ if flag(bytestring-builder)
223+ build-depends: bytestring >= 0.9 && < 0.10.4,
224+ bytestring-builder >= 0.10.4 && < 1
225+ else
226+ build-depends: bytestring >= 0.10.4
227+ if impl(ghc < 8.0)
228+ build-depends: semigroups
229+
109230executable aeson-benchmark-compare-with-json
231+ default-language: Haskell2010
110232 main-is: CompareWithJSON.hs
111233 ghc-options: -Wall -O2 -rtsopts
112234 build-depends:
113235 aeson-benchmarks,
114236 base,
237+ base-compat,
115238 blaze-builder,
116239 bytestring,
117240 criterion,
@@ -120,53 +243,65 @@ executable aeson-benchmark-compare-with-json
120243 text
121244
122245executable aeson-benchmark-aeson-encode
246+ default-language: Haskell2010
123247 main-is: AesonEncode.hs
124248 ghc-options: -Wall -O2 -rtsopts
125249 build-depends:
126250 aeson-benchmarks,
127251 attoparsec,
128252 base,
253+ base-compat,
129254 bytestring,
130255 deepseq,
131256 time
132257
133258executable aeson-benchmark-aeson-parse
259+ default-language: Haskell2010
134260 main-is: AesonParse.hs
135261 ghc-options: -Wall -O2 -rtsopts
136262 build-depends:
137263 aeson-benchmarks,
138264 attoparsec,
139265 base,
266+ base-compat,
140267 bytestring,
141268 time
142269
143270executable aeson-benchmark-json-parse
271+ default-language: Haskell2010
144272 main-is: JsonParse.hs
145273 ghc-options: -Wall -O2 -rtsopts
146274 build-depends:
147275 base,
276+ base-compat,
148277 deepseq,
149278 json,
150279 time
151280
152281executable aeson-benchmark-dates
282+ default-language: Haskell2010
153283 main-is: Dates.hs
154284 ghc-options: -Wall -O2 -rtsopts
155285 build-depends:
156286 base,
287+ base-compat,
157288 bytestring,
158289 criterion,
159290 deepseq,
160291 aeson-benchmarks,
161292 text,
162293 time
294+ if impl(ghc >= 8.2)
295+ ghc-options: -Wno-simplifiable-class-constraints
163296
164297executable aeson-benchmark-map
298+ default-language: Haskell2010
165299 main-is: AesonMap.hs
166300 ghc-options: -Wall -O2 -rtsopts
167301 build-depends:
168302 aeson-benchmarks,
169303 base,
304+ base-compat,
170305 criterion >= 1.0,
171306 bytestring,
172307 containers,
@@ -174,6 +309,37 @@ executable aeson-benchmark-map
174309 hashable,
175310 tagged,
176311 text,
177− transformers,
178− transformers-compat,
179312 unordered-containers
313+
314+executable aeson-benchmark-foldable
315+ default-language: Haskell2010
316+ main-is: AesonFoldable.hs
317+ ghc-options: -Wall -O2 -rtsopts
318+ build-depends:
319+ aeson-benchmarks,
320+ base,
321+ base-compat,
322+ criterion >= 1.0,
323+ bytestring,
324+ containers,
325+ deepseq,
326+ hashable,
327+ tagged,
328+ text,
329+ unordered-containers,
330+ vector
331+
332+executable aeson-issue-673
333+ default-language: Haskell2010
334+ main-is: Issue673.hs
335+ ghc-options: -Wall -O1 -rtsopts
336+ build-depends:
337+ aeson-benchmarks,
338+ attoparsec,
339+ base,
340+ bytestring,
341+ scientific,
342+ base-compat,
343+ criterion >= 1.0
344+ if impl(ghc < 8.0)
345+ build-depends: semigroups
cabal.projectnew file+5
@@ -0,0 +1,5 @@
1+with-compiler: ghc
2+packages: .
3+packages: attoparsec-iso8601
4+-- packages: benchmarks
5+tests: true
cbits/unescape_string.cnew file+149
@@ -0,0 +1,149 @@
1+// Copyright (c) 2008-2009 Bjoern Hoehrmann
2+// Copyright (c) 2015, Ondrej Palkovsky
3+// Copyright (c) 2016, Winterland
4+
5+#include <string.h>
6+#include <stdio.h>
7+#include <stdint.h>
8+
9+
10+#define UTF8_ACCEPT 0
11+#define UTF8_REJECT 12
12+
13+static const uint8_t utf8d[] = {
14+ // The first part of the table maps bytes to character classes that
15+ // to reduce the size of the transition table and create bitmasks.
16+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
17+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
18+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
19+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
20+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
21+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
22+ 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
23+ 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
24+
25+ // The second part is a transition table that maps a combination
26+ // of a state of the automaton and a character class to a state.
27+ 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
28+ 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
29+ 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
30+ 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
31+ 12,36,12,12,12,12,12,12,12,12,12,12,
32+};
33+
34+static inline uint32_t decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
35+ uint32_t type = utf8d[byte];
36+
37+ *codep = (*state != UTF8_ACCEPT) ?
38+ (byte & 0x3fu) | (*codep << 6) :
39+ (0xff >> type) & (byte);
40+
41+ *state = utf8d[256 + *state + type];
42+ return *state;
43+}
44+
45+static inline uint16_t decode_hex(uint32_t c)
46+{
47+ if (c >= '0' && c <= '9') return c - '0';
48+ else if (c >= 'a' && c <= 'f') return c - 'a' + 10;
49+ else if (c >= 'A' && c <= 'F') return c - 'A' + 10;
50+ return 0xFFFF; // Should not happen
51+}
52+
53+// Decode, return non-zero value on error
54+int _js_decode_string(uint16_t *const dest, size_t *destoff,
55+ const uint8_t *s, const uint8_t *const srcend)
56+{
57+ uint16_t *d = dest + *destoff;
58+ uint32_t state = 0;
59+ uint32_t codepoint;
60+
61+ uint8_t surrogate = 0;
62+ uint16_t temp_hex = 0;
63+ uint16_t unidata;
64+
65+ // Optimized version of dispatch when just an ASCII char is expected
66+ #define DISPATCH_ASCII(label) {\
67+ if (s >= srcend) {\
68+ return -1;\
69+ }\
70+ codepoint = *s++;\
71+ goto label;\
72+ }
73+
74+ standard:
75+ // Test end of stream
76+ while (s < srcend) {
77+ if (decode(&state, &codepoint, *s++) != UTF8_ACCEPT) {
78+ if (state == UTF8_REJECT) { return -1; }
79+ continue;
80+ }
81+
82+ if (codepoint == '\\')
83+ DISPATCH_ASCII(backslash)
84+ else if (codepoint <= 0xffff)
85+ *d++ = (uint16_t) codepoint;
86+ else {
87+ *d++ = (uint16_t) (0xD7C0 + (codepoint >> 10));
88+ *d++ = (uint16_t) (0xDC00 + (codepoint & 0x3FF));
89+ }
90+ }
91+ *destoff = d - dest;
92+ // Exit point
93+ return (state != UTF8_ACCEPT);
94+ backslash:
95+ switch (codepoint) {
96+ case '"':
97+ case '\\':
98+ case '/':
99+ *d++ = (uint16_t) codepoint;
100+ goto standard;
101+ break;
102+ case 'b': *d++ = '\b';goto standard;
103+ case 'f': *d++ = '\f';goto standard;
104+ case 'n': *d++ = '\n';goto standard;
105+ case 'r': *d++ = '\r';goto standard;
106+ case 't': *d++ = '\t';goto standard;
107+ case 'u': DISPATCH_ASCII(unicode1);;break;
108+ default:
109+ return -1;
110+ }
111+ unicode1:
112+ temp_hex = decode_hex(codepoint);
113+ if (temp_hex == 0xFFFF) { return -1; }
114+ else unidata = temp_hex << 12;
115+ DISPATCH_ASCII(unicode2);
116+ unicode2:
117+ temp_hex = decode_hex(codepoint);
118+ if (temp_hex == 0xFFFF) { return -1; }
119+ else unidata |= temp_hex << 8;
120+ DISPATCH_ASCII(unicode3);
121+ unicode3:
122+ temp_hex = decode_hex(codepoint);
123+ if (temp_hex == 0xFFFF) { return -1; }
124+ else unidata |= temp_hex << 4;
125+ DISPATCH_ASCII(unicode4);
126+ unicode4:
127+ temp_hex = decode_hex(codepoint);
128+ if (temp_hex == 0xFFFF) { return -1; }
129+ else unidata |= temp_hex;
130+ *d++ = (uint16_t) unidata;
131+
132+ if (surrogate) {
133+ if (unidata < 0xDC00 || unidata > 0xDFFF) // is not low surrogate
134+ return -1;
135+ surrogate = 0;
136+ } else if (unidata >= 0xD800 && unidata <= 0xDBFF ) { // is high surrogate
137+ surrogate = 1;
138+ DISPATCH_ASCII(surrogate1);
139+ } else if (unidata >= 0xDC00 && unidata <= 0xDFFF) { // is low surrogate
140+ return -1;
141+ }
142+ goto standard;
143+ surrogate1:
144+ if (codepoint != '\\') { return -1; }
145+ DISPATCH_ASCII(surrogate2)
146+ surrogate2:
147+ if (codepoint != 'u') { return -1; }
148+ DISPATCH_ASCII(unicode1)
149+}
changelog.md+312−19
@@ -1,41 +1,334 @@
11For the latest version of this document, please see [https://github.com/bos/aeson/blob/master/changelog.md](https://github.com/bos/aeson/blob/master/changelog.md).
22
3+### upcoming
4+
5+* `FromJSON` instance of `Ratio a` now parses numbers in addtion to
6+ standard `{numerator=..., denumerator=...}` encoding.
7+
8+### 1.4.6.0
9+
10+* Provide a clearer error message when a required tagKey for a constructor is missing, thanks to Guru Devanla.
11+ The error message now looks like this: `Error in $: parsing Types.SomeType failed, expected Object with key "tag" containing one of ["nullary","unary","product","record","list"], key "tag" not found`
12+
13+* Add `formatPath` and `formatRelativePath` functions to turn a `JSONPath` into a `String`, thanks to Robbie McMichael
14+
15+
16+### 1.4.5.0
17+
18+* Expose `(<?>)`, `JSONPath` and `JSONPathElement(..)` from `Data.Aeson.Types`. Previously only available through internal modules. Thanks to Luke Clifton.
19+
20+* Support for base-compat 0.11, thanks to Ryan Scott.
21+
22+* Travis build for GHC 8.8, thanks to Oleg Grenrus.
23+
24+### 1.4.4.0
25+
26+**New features**:
27+
28+* Adds a parameterized parser `jsonWith` that can be used to choose how to handle duplicate keys in objects, thanks to Xia Li-Yao.
29+
30+* Add generic implementations of `FromJSONKey` and `ToJSONKey`, thanks to Xia Li-Yao. Example:
31+
32+```haskell
33+data Foo = Bar
34+ deriving Generic
35+
36+opts :: JSONKeyOptions
37+opts = defaultJSONKeyOptions { keyModifier = toLower }
38+
39+instance ToJSONKey Foo where
40+ toJSONKey = genericToJSONKey opts
41+
42+instance FromJSONKey Foo where
43+ fromJSONKey = genericFromJSONKey opts
44+```
45+
46+**Minor**:
47+* aeson now uses `time-compat` instead of `time-locale-compat`, thanks to Oleg Grenrus.
48+* Prepare for `MonadFail` breakages in GHC 8.8, thanks to Oleg Grenrus.
49+* Require `bytestring >= 0.10.8.1` for newer GHCs to avoid build failures, thanks to Oleg Grenrus.
50+* Support `primitive 0.7.*`, thanks to Adam Bergmark.
51+* Allow `semigroups 0.19.*` and `hashable 1.3.*`, thanks to Oleg Grenrus.
52+* Fix a typo in the error message when parsing `NonEmpty`, thanks to Colin Woodbury.
53+* Document surprising behavior when using `omitNothingFields` with type variables, thanks to Xia Li-Yao.
54+
55+**Internal changes**:
56+* Code cleanup by Oleg Grenrus
57+* Fix dependencies of the benchmarks on older GHC's, thanks to Xia Li-Yao.
58+
59+### 1.4.3.0
60+* Improve error messages for FromJSON in existing instances and GHC Generic implementation. Thanks to Xia Li-Yao & Igor Pashev.
61+* Tweak error-reporting combinators and their documentation. Thanks to Xia Li-Yao.
62+ * `typeMismatch` is now about comparing JSON types (i.e., the expected and actual names of the Value constructor).
63+ * `withObject` and other `with*` combinators now also mention the JSON types they expect
64+ * New `unexpected` and `prependFailure` combinators.
65+* Add `Contravariant` `ToJSONKeyFunction` instance. Thanks to Oleg Grenrus.
66+* Add `KeyValue` instance for `Object`. Thanks to Robert Hensing.
67+* Improve performance when parsing certain large numbers, thanks to Oleg Grenrus.
68+* Add `Data.Aeson.QQ.Simple` - A limited version of aeson-qq. Thanks to Oleg Grenrus.
69+* Exposes internal helper functions like `<?>`, `JSONPath`, and `parseIndexedJSON` from `Data.Aeson` module. Thanks to Abid Uzair.
70+* Better error messages when there are syntax errors parsing objects and arrays. Thanks to Fintan Halpenny.
71+* Support building with `th-abstraction-0.3.0.0` or later. Thanks to Ryan Scott.
72+
73+### 1.4.2.0
74+
75+* Add `Data.Aeson.QQ.Simple` which is a simpler version of the `aeson-qq` package, it does not support interpolation, thanks to Oleg Grenrus.
76+* Add `Contravariant ToJSONKeyFunction` instance, thanks to Oleg Grenrus.
77+* Add `KeyValue Object` instance, thanks to Robert Hensing
78+* Improved performance when parsing large numbers, thanks to Oleg Grenrus.
79+
80+### 1.4.1.0
81+
82+* Optimizations of generics, thanks to Rémy Oudompheng, here are some numbers for GHC 8.4:
83+ * Compilation time: G/BigProduct.hs is 25% faster, G/BigRecord.hs is 2x faster.
84+ * Runtime performance: BigRecord/toJSON/generic and BigProduct/encode/generic are more than 2x faster.
85+* Added To/FromJSON instances for `Void` and Generics's `V1`, thanks to Will Yager
86+* Added To/FromJSON instances for `primitive`'s `Array`, `SmallArray`, `PrimArray` and `UnliftedArray`, thanks to Andrew Thad.
87+* Fixes handling of `UTCTime` wrt. leap seconds , thanks to Adam Schønemann
88+* Warning and documentation fixes thanks to tom-bop, Gabor Greif, Ian Jeffries, and Mateusz Curyło.
89+
90+## 1.4.0.0
91+
92+This release introduces bounds on the size of `Scientific` numbers when they are converted to other arbitrary precision types that do not represent them efficiently in memory.
93+
94+This means that trying to decode a number such as `1e1000000000` into an `Integer` will now fail instead of using a lot of memory. If you need to represent large numbers you can add a newtype (preferably over `Scientific`) and providing a parser using `withScientific`.
95+
96+The following instances are affected by this:
97+* `FromJSON Natural`
98+* `FromJSONKey Natural`
99+* `FromJSON Integer`
100+* `FromJSONKey Integer`
101+* `FromJSON NominalDiffTime`
102+
103+For the same reasons the following instances & functions have been removed:
104+* Remove `FromJSON Data.Attoparsec.Number` instance. Note that `Data.Attoparsec.Number` is deprecated.
105+* Remove deprecated `withNumber`, use `withScientific` instead.
106+
107+Finally, encoding integral values with large exponents now uses scientific notation, this saves space for large numbers.
108+
109+#### 1.3.1.1
110+
111+* Catch 0 denominators when parsing Ratio
112+
113+### 1.3.1.0
114+
115+* Fix bug in generically derived `FromJSON` instances that are using `unwrapUnaryRecords`, thanks to Xia Li-yao
116+* Allow base-compat 0.10.*, thanks to Oleg Grenrus
117+
118+## 1.3.0.0
119+
120+Breaking changes:
121+* `GKeyValue` has been renamed to `KeyValuePair`, thanks to Xia Li-yao
122+* Removed unused `FromJSON` constraint in `withEmbeddedJson`, thanks to Tristan Seligmann
123+
124+Other improvements:
125+* Optimizations of TH toEncoding, thanks to Xia Li-yao
126+* Optimizations of hex decoding when using the default/pure unescape implementation, thanks to Xia Li-yao
127+* Improved error message on `Day` parse failures, thanks to Gershom Bazerman
128+* Add `encodeFile` as well as `decodeFile*` variants, thanks to Markus Hauck
129+* Documentation fixes, thanks to Lennart Spitzner
130+* CPP cleanup, thanks to Ryan Scott
131+
132+### 1.2.4.0
133+
134+* Add `Ord` instance for `JSONPathElement`, thanks to Simon Hengel.
135+
136+
137+### 1.2.3.0
138+
139+* Added `withEmbeddedJSON` to help parse JSON embedded inside a JSON string, thanks to Jesse Kempf.
140+* Memory usage improvements to the default (pure) parser, thanks to Jonathan Paugh. Also thanks to Neil Mitchell & Oleg Grenrus for contributing a benchmark.
141+* `omitNothingFields` now works for the `Option` newtype, thanks to Xia Li-yao.
142+* Some documentation fixes, thanks to Jonathan Paug & Philippe Crama.
143+
144+### 1.2.2.0
145+
146+* Add `FromJSON` and `ToJSON` instances for
147+ * `DiffTime`, thanks to Víctor López Juan.
148+ * `CTime`, thanks to Daniel Díaz.
149+* Fix handling of fractions when parsing Natural, thanks to Yuriy Syrovetskiy.
150+* Change text in error messages for Integral types to make them follow the common pattern, thanks to Yuriy Syrovetskiy.
151+* Add missing `INCOHERENT` pragma for `RecordToPair`, thanks to Xia Li-yao.
152+* Everything related to `Options` is now exported from `Data.Aeson`, thanks to Xia Li-yao.
153+* Optimizations to not escape text in clear cases, thanks to Oleg Grenrus.
154+* Some documentation fixes, thanks to Phil de Joux & Xia Li-yao.
155+
156+### 1.2.1.0
157+
158+* Add `parserThrowError` and `parserCatchError` combinators, thanks to Oleg Grenrus.
159+
160+* Add `Generic` instance for `Value`, thanks to Xia Li-yao.
161+
162+* Fix a mistake in the 1.2.0.0 changelog, the `cffi` flag is disabled by default! Thanks to dbaynard.
163+
164+## 1.2.0.0
165+
166+* `tagSingleConstructors`, an option to encode single-constructor types as tagged sums was added to `Options`. It is disabled by default for backward compatibility.
167+
168+* The `cffi` flag is now turned off (`False`) by default, this means C FFI code is no longer used by default. You can flip the flag to get C implementation.
169+
170+* The `Options` constructor is no longer exposed to prevent new options from being breaking changes, use `defaultOptions` instead.
171+
172+* The contents of `GToJSON` and `GToEncoding` are no longer exposed.
173+
174+* Some INLINE pragmas were removed to avoid GHC running out of simplifier ticks.
175+
176+### 1.1.2.0
177+
178+* Fix an accidental change in the format of `deriveJSON`. Thanks to Xia Li-yao!
179+
180+* Documentation improvements regarding `ToJSON`, `FromJSON`, and `SumEncoding`. Thanks to Xia Li-yao and Lennart Spitzner!
181+
182+### 1.1.1.0
183+
184+* Added a pure implementation of the C FFI code, the C FFI code. If you wish to use the pure haskell version set the `cffi` flag to `False`. This should make aeson compile when C isn't available, such as for GHCJS. Thanks to James Parker & Marcin Tolysz!
185+
186+* Using the `fast` flag can no longer cause a test case to fail. As far as we know this didn't affect any users of the library itself. Thanks to Xia Li-yao!
187+
188+## 1.1.0.0
189+
190+* Added instances for `UUID`.
191+
192+* The operators for parsing fields now have named aliases:
193+ - `.:` => `parseField`
194+ - `.:?` => `parseFieldMaybe`
195+ - `.:!` => `parseFieldMaybe'`
196+ - These functions now also have variants with explicit parser functions: `explicitParseField`, `explicitParseFieldMaybe`, "explicitParseFieldMaybe'`
197+Thanks to Oleg Grenrus.
198+
199+* `ToJSONKey (Identity a)` and `FromJSONKey (Identity a)` no longer require the unnecessary `FromJSON a` constraint. Thanks to Oleg Grenrus.
200+
201+* Added `Data.Aeson.Encoding.pair'` which is a more general version of `Data.Aeson.Encoding.pair`. Thanks to Andrew Martin.
202+
203+* `Day`s BCE are properly encoded and `+` is now a valid prefix for `Day`s CE. Thanks to Matt Parsons.
204+
205+* Some commonly used ToJSON instances are now specialized in order to improve compile time. Thanks to Bartosz Nitka.
206+
207+
208+[JSONTestSuite](https://github.com/nst/JSONTestSuite) cleanups, all
209+motivated by tighter RFC 7159 compliance:
210+
211+* The parser now rejects numbers for which
212+ [the integer portion contains a leading zero](https://github.com/bos/aeson/commit/3fb7c155f2255482b1b9566ec5c1eaf9895d630e).
213+* The parser now rejects numbers for which
214+ [a decimal point is not followed by at least one digit](https://github.com/bos/aeson/commit/ecfca35a45286dbe2bbaf5f62354be393bc59b66),
215+* The parser now rejects documents that contain [whitespace outside the
216+ set {space, newline, carriage return, tab}](https://github.com/bos/aeson/commit/8ef622c2ad8d4a109884e17c2792238a2a320e44).
217+
218+Over 90% of JSONTestSuite tests currently pass. The remainder can be
219+categorised as follows:
220+
221+* The string parser is strict with Unicode compliance where the RFC
222+ leaves room for implementation-defined behaviour (tests prefixed
223+ with "`i_string_`". (This is necessary because the `text` library
224+ cannot accommodate invalid Unicode.)
225+
226+* The parser does not (and will not) support UTF-16, UTF-32, or byte
227+ order marks (BOM).
228+* The parser accepts unescaped control characters, even though the RFC
229+ states that control characters must be escaped. (This may change at
230+ some point, but doesn't seem important.)
231+
232+#### 1.0.2.1
233+
234+* Fixes a regression where a bunch of valid characters caused an
235+ "Invalid UTF8-Stream" error when decoding. Thanks to Vladimir
236+ Shabanov who investigated and fixed this.
237+
238+### 1.0.2.0
239+
240+* Fixes a regression where it was no longer possible to derive
241+ instances for types such as `data T a = T { f1 :: a, f2 :: Maybe a
242+ }`.
243+
244+Thanks to Sean Leather for fixing this, and to Ryan Scott for helping out.
245+
246+### 1.0.1.0
247+
248+* Decoding performance has been significantly improved (see
249+ https://github.com/bos/aeson/pull/452). Thanks to @winterland1989.
250+
251+* Add `ToJSON`/`FromJSON` instances for newtypes from
252+ `Data.Semigroup`: `Min`, `Max`, `First`, `Last`, `WrappedMonoid`,
253+ `Option`. Thanks to Lennart Spitzner.
254+
255+* Make the documentation for `.:!` more accurate. Thanks to Ian Jeffries.
256+
3257# 1.0.0.0
4258
5−* Added list specific members to `ToJSON` and `FromJSON` classes. In the same
6− way `Read` / `Show` handle lists specifically. This removes need for
7− overlapping instances to handle `String`.
259+Major enhancements:
8260
9−* Added higher rank classes: `ToJSON1`, `ToJSON2`, `FromJSON1`, and `FromJSON2`.
261+* Introduced new `FromJSONKey` and `ToJSONKey` type classes that are
262+ used to encode maps without going through HashMap. This also allows arbitrary
263+ serialization of keys where a string-like key will encode into an object and
264+ other keys will encode into an array of key-value tuples.
10265
11−* Modified instances for `Map` and `HashMap`. Introduced new `FromJSONKey` and
12− `ToJSONKey` type classes.
266+* Added higher rank classes: `ToJSON1`, `ToJSON2`, `FromJSON1`, and
267+ `FromJSON2`.
13268
14−* Export `decodeWith`, `decodeStrictWith`, `eitherDecodeWith`, and
15− `eitherDecodeStrictWith` from `Data.Aeson.Parser`. This allows
16− decoding using explicit parsers instead of using `FromJSON`
17− instances.
269+* Added `Data.Aeson.Encoding` with functions to safely write `ToJSON`
270+ instances using `toEncoding`.
18271
19−* Remove the `contents` field encoding with `allNullaryToStringTag = False`,
20− giving us `{ "tag" : "c1" }` instead of `{ "tag" : "c1", contents : [] }`.
21− The contents field is optional when parsing so this is only a breaking change for ToJSON.
272+Other enhancements:
22273
23−* Fix a bug where `genericToEncoding` with `unwrapUnaryRecords = True`
24− would produce an invalid encoding: `"unwrap\":""`.
274+* A Cabal `fast` flag was added to disable building with optimizations. This drastically speeds up compiling both aeson ***and*** libraries using aeson so it is recommended to enable it during development. With cabal-install you can `cabal install aeson -ffast` and with stack you can add a flag section to your stack.yaml:
275+```
276+flags:
277+ aeson:
278+ fast: true
279+```
280+
281+* Added list specific members to `ToJSON` and `FromJSON` classes. In
282+ the same way `Read` and `Show` handle lists specifically. This
283+ removes need for overlapping instances to handle `String`.
284+
285+* Added a new `sumEncoding` option `UntaggedValue` which prevents
286+ objects from being tagged with the constructor name.
287+
288+* JSONPaths are now tracked in instances derived with template-haskell
289+ and generics.
25290
26291* Get rid of redundancy of JSONPath error messages in nested records.
27292
28293 `eitherDecode "{\"x\":{\"a\": [1,2,true]}}" :: Either String Y`
29− previously yielded `Error in $.x.a[2]: failed to parse field" x:
30− failed to parse field a: expected Int, encountered Boolean` and now
31− yields `Error in $.x.a[2]: expected Int, encountered Boolean"`.
294+ previously yielded
295+ `Error in $.x.a[2]: failed to parse field" x: failed to parse field a: expected Int, encountered Boolean`
296+ and now yields `Error in $.x.a[2]: expected Int, encountered Boolean"`.
32297
33298 Some users might prefer to insert `modifyFailure` themselves to
34299 customize error messages, which previously prevented the use of
35300 `(.:)`.
36301
302+* Backwards compatibility with `bytestring-0.9` using the
303+ `bytestring-builder` compatibility package.
304+
305+* Export `decodeWith`, `decodeStrictWith`, `eitherDecodeWith`, and
306+ `eitherDecodeStrictWith` from `Data.Aeson.Parser`. This allows
307+ decoding using explicit parsers instead of using `FromJSON`
308+ instances.
309+
310+* Un-orphan internal instances to render them in haddocks.
311+
312+Other changes:
313+
314+* Integral `FromJSON` instances now only accept integral
315+ values. E.g. parsing `3.14` to `Int` fails instead of succeeding
316+ with the value `3`.
317+
318+* Over/underflows are now caught for bounded numeric types.
319+
320+* Remove the `contents` field encoding with `allNullaryToStringTag = False`,
321+ giving us `{ "tag" : "c1" }` instead of `{ "tag" : "c1", contents : [] }`.
322+ The contents field is optional when parsing so this is only a breaking
323+ change for ToJSON instances.
324+
325+* Fix a bug where `genericToEncoding` with `unwrapUnaryRecords = True`
326+ would produce an invalid encoding: `"unwrap\":""`.
327+
37328* `ToJSON` instances using `genericToEncoding` and `omitNothingFields`
38− no longer produces invalid JSON.
329+ no longer produce invalid JSON.
330+
331+* Added instances for `DList`, `Compose`, `Product`, `Sum`.
39332
40333### 0.11.2.0
41334
examples/Generic.hs+7−5
@@ -6,17 +6,19 @@
66-- automatically derive the Generic class for us.
77
88{-# LANGUAGE DeriveGeneric #-}
9−
9+{-# LANGUAGE NoImplicitPrelude #-}
1010{-# LANGUAGE OverloadedStrings #-}
1111
12+module Main (main) where
13+
14+import Prelude.Compat
15+
1216import Data.Aeson (FromJSON, ToJSON, decode, encode)
1317import qualified Data.ByteString.Lazy.Char8 as BL
18+import GHC.Generics (Generic)
1419
1520-- To decode or encode a value using the generic machinery, we must
1621-- make the type an instance of the Generic class.
17−
18−import GHC.Generics (Generic)
19−
2022data Coord = Coord { x :: Double, y :: Double }
2123 deriving (Show, Generic)
2224
@@ -31,5 +33,5 @@ main :: IO ()
3133main = do
3234 let req = decode "{\"x\":3.0,\"y\":-1.0}" :: Maybe Coord
3335 print req
34− let reply = Coord 123.4 20
36+ let reply = Coord { x = 123.4, y = 20 }
3537 BL.putStrLn (encode reply)
examples/Simplest.hs+8−2
@@ -1,6 +1,12 @@
1−{-# LANGUAGE OverloadedStrings, RecordWildCards #-}
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE RecordWildCards #-}
24
3−import Control.Applicative ((<$>), (<*>), empty)
5+module Main (main) where
6+
7+import Prelude.Compat
8+
9+import Control.Applicative (empty)
410import Data.Aeson
511import Data.Monoid
612import qualified Data.ByteString.Lazy.Char8 as BL
examples/TemplateHaskell.hs+6−3
@@ -1,10 +1,13 @@
11-- We can use Template Haskell (TH) to generate instances of the
22-- FromJSON and ToJSON classes automatically. This is the fastest way
33-- to add JSON support for a type.
4−
4+{-# LANGUAGE NoImplicitPrelude #-}
5+{-# LANGUAGE OverloadedStrings #-}
56{-# LANGUAGE TemplateHaskell #-}
67
7−{-# LANGUAGE OverloadedStrings #-}
8+module Main (main) where
9+
10+import Prelude.Compat
811
912import Data.Aeson (decode, encode)
1013import Data.Aeson.TH (deriveJSON, defaultOptions)
@@ -21,5 +24,5 @@ main :: IO ()
2124main = do
2225 let req = decode "{\"x\":3.0,\"y\":-1.0}" :: Maybe Coord
2326 print req
24− let reply = Coord 123.4 20
27+ let reply = Coord { x = 123.4, y = 20 }
2528 BL.putStrLn (encode reply)
examples/Twitter.hs+12−6
@@ -8,22 +8,28 @@
88-- renamed "type" to "type_" in the *.json files, to avoid overlap
99-- with a Haskell reserved keyword.
1010
11−{-# LANGUAGE DeriveDataTypeable, DeriveGeneric #-}
11+{-# LANGUAGE DeriveDataTypeable #-}
12+{-# LANGUAGE DeriveGeneric #-}
13+{-# LANGUAGE NoImplicitPrelude #-}
1214
13−module Twitter (
15+module Twitter
16+ (
1417 Metadata(..)
1518 , Geo(..)
1619 , Story(..)
1720 , Result(..)
1821 ) where
1922
23+import Prelude.Compat
24+
25+import Control.DeepSeq
2026import Data.Data (Typeable, Data)
2127import Data.Int (Int64)
2228import Data.Text (Text)
23−-- import Data.Time (ZonedTime)
2429import GHC.Generics (Generic)
25−import Prelude hiding (id)
26−import Control.DeepSeq
30+
31+{-# ANN module "Hlint: ignore Use camelCase" #-}
32+{-# ANN module "Hlint: ignore Use newtype instead of data" #-}
2733
2834data Metadata = Metadata {
2935 result_type :: Text
@@ -47,7 +53,7 @@ data Story = Story {
4753 , metadata :: Metadata
4854 , to_user_id :: Maybe Int64
4955 , text :: Text
50− , id :: Int64
56+ , id_ :: Int64
5157 , from_user_id :: Int64
5258 , geo :: Maybe Geo
5359 , iso_language_code :: Text
examples/Twitter/Generic.hs+27−9
@@ -1,5 +1,7 @@
11-- Use GHC generics to automatically generate good instances.
22
3+{-# LANGUAGE NoImplicitPrelude #-}
4+
35{-# OPTIONS_GHC -fno-warn-orphans #-}
46
57module Twitter.Generic
@@ -10,17 +12,33 @@ module Twitter.Generic
1012 , Result(..)
1113 ) where
1214
13−import Data.Aeson (ToJSON, FromJSON)
15+import Prelude.Compat ()
16+
1417import Twitter
18+import Twitter.Options
19+
20+import Data.Aeson (ToJSON (..), FromJSON (..), genericToJSON, genericToEncoding, genericParseJSON)
1521
16−instance ToJSON Metadata
17−instance FromJSON Metadata
22+instance ToJSON Metadata where
23+ toJSON = genericToJSON twitterOptions
24+ toEncoding = genericToEncoding twitterOptions
25+instance FromJSON Metadata where
26+ parseJSON = genericParseJSON twitterOptions
1827
19−instance ToJSON Geo
20−instance FromJSON Geo
28+instance ToJSON Geo where
29+ toJSON = genericToJSON twitterOptions
30+ toEncoding = genericToEncoding twitterOptions
31+instance FromJSON Geo where
32+ parseJSON = genericParseJSON twitterOptions
2133
22−instance ToJSON Story
23−instance FromJSON Story
34+instance ToJSON Story where
35+ toJSON = genericToJSON twitterOptions
36+ toEncoding = genericToEncoding twitterOptions
37+instance FromJSON Story where
38+ parseJSON = genericParseJSON twitterOptions
2439
25−instance ToJSON Result
26−instance FromJSON Result
40+instance ToJSON Result where
41+ toJSON = genericToJSON twitterOptions
42+ toEncoding = genericToEncoding twitterOptions
43+instance FromJSON Result where
44+ parseJSON = genericParseJSON twitterOptions
examples/Twitter/Manual.hs+11−6
@@ -1,6 +1,8 @@
11-- Manually write instances.
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+{-# LANGUAGE RecordWildCards #-}
25
3−{-# LANGUAGE OverloadedStrings, RecordWildCards #-}
46{-# OPTIONS_GHC -fno-warn-orphans #-}
57
68module Twitter.Manual
@@ -11,13 +13,16 @@ module Twitter.Manual
1113 , Result(..)
1214 ) where
1315
16+import Prelude.Compat
17+
1418import Control.Applicative
15−import Data.Aeson hiding (Result)
16−import Data.Monoid ((<>))
17−import Prelude hiding (id)
19+import Data.Semigroup ((<>))
1820import Twitter
1921
22+import Data.Aeson hiding (Result)
23+
2024instance ToJSON Metadata where
25+
2126 toJSON Metadata{..} = object [
2227 "result_type" .= result_type
2328 ]
@@ -55,7 +60,7 @@ instance ToJSON Story where
5560 , "metadata" .= metadata
5661 , "to_user_id" .= to_user_id
5762 , "text" .= text
58− , "id" .= id
63+ , "id" .= id_
5964 , "from_user_id" .= from_user_id
6065 , "geo" .= geo
6166 , "iso_language_code" .= iso_language_code
@@ -72,7 +77,7 @@ instance ToJSON Story where
7277 <> "metadata" .= metadata
7378 <> "to_user_id" .= to_user_id
7479 <> "text" .= text
75− <> "id" .= id
80+ <> "id" .= id_
7681 <> "from_user_id" .= from_user_id
7782 <> "geo" .= geo
7883 <> "iso_language_code" .= iso_language_code
examples/Twitter/Options.hsnew file+10
@@ -0,0 +1,10 @@
1+module Twitter.Options (module Twitter.Options) where
2+
3+import Data.Aeson
4+
5+twitterOptions :: Options
6+twitterOptions = defaultOptions
7+ { fieldLabelModifier = \x -> case x of
8+ "id_" -> "id"
9+ _ -> x
10+ }
examples/Twitter/TH.hs+10−5
@@ -1,6 +1,8 @@
11-- Use Template Haskell to generate good instances.
22
3+{-# LANGUAGE NoImplicitPrelude #-}
34{-# LANGUAGE TemplateHaskell #-}
5+
46{-# OPTIONS_GHC -fno-warn-orphans #-}
57
68module Twitter.TH
@@ -11,10 +13,13 @@ module Twitter.TH
1113 , Result(..)
1214 ) where
1315
14−import Data.Aeson.TH
16+
1517import Twitter
18+import Twitter.Options
19+
20+import Data.Aeson.TH
1621
17−$(deriveJSON defaultOptions ''Metadata)
18−$(deriveJSON defaultOptions ''Geo)
19−$(deriveJSON defaultOptions ''Story)
20−$(deriveJSON defaultOptions ''Result)
22+$(deriveJSON twitterOptions ''Metadata)
23+$(deriveJSON twitterOptions ''Geo)
24+$(deriveJSON twitterOptions ''Story)
25+$(deriveJSON twitterOptions ''Result)
examples/aeson-examples.cabal+3
@@ -9,6 +9,7 @@ executable aeson-example-generic
99 build-depends:
1010 aeson >= 0.10,
1111 base,
12+ base-compat,
1213 bytestring,
1314 ghc-prim
1415
@@ -18,6 +19,7 @@ executable aeson-example-simplest
1819 build-depends:
1920 aeson,
2021 base,
22+ base-compat,
2123 bytestring
2224
2325executable aeson-example-th
@@ -26,4 +28,5 @@ executable aeson-example-th
2628 build-depends:
2729 aeson,
2830 base,
31+ base-compat,
2932 bytestring
ffi/Data/Aeson/Parser/UnescapeFFI.hsnew file+52
@@ -0,0 +1,52 @@
1+{-# LANGUAGE ForeignFunctionInterface #-}
2+{-# LANGUAGE MagicHash #-}
3+{-# LANGUAGE UnliftedFFITypes #-}
4+
5+module Data.Aeson.Parser.UnescapeFFI
6+ (
7+ unescapeText
8+ ) where
9+
10+import Control.Exception (evaluate, throw, try)
11+import Control.Monad.ST.Unsafe (unsafeIOToST, unsafeSTToIO)
12+import Data.ByteString as B
13+import Data.ByteString.Internal as B
14+import Data.Text.Encoding.Error (UnicodeException (..))
15+import Data.Text.Internal (Text (..))
16+import Data.Text.Internal.Private (runText)
17+import Data.Text.Unsafe (unsafeDupablePerformIO)
18+import Data.Word (Word8)
19+import Foreign.C.Types (CInt (..), CSize (..))
20+import Foreign.ForeignPtr (withForeignPtr)
21+import Foreign.Marshal.Utils (with)
22+import Foreign.Ptr (Ptr, plusPtr)
23+import Foreign.Storable (peek)
24+import GHC.Base (MutableByteArray#)
25+import qualified Data.Text.Array as A
26+
27+foreign import ccall unsafe "_js_decode_string" c_js_decode
28+ :: MutableByteArray# s -> Ptr CSize
29+ -> Ptr Word8 -> Ptr Word8 -> IO CInt
30+
31+unescapeText' :: ByteString -> Text
32+unescapeText' (PS fp off len) = runText $ \done -> do
33+ let go dest = withForeignPtr fp $ \ptr ->
34+ with (0::CSize) $ \destOffPtr -> do
35+ let end = ptr `plusPtr` (off + len)
36+ loop curPtr = do
37+ res <- c_js_decode (A.maBA dest) destOffPtr curPtr end
38+ case res of
39+ 0 -> do
40+ n <- peek destOffPtr
41+ unsafeSTToIO (done dest (fromIntegral n))
42+ _ ->
43+ throw (DecodeError desc Nothing)
44+ loop (ptr `plusPtr` off)
45+ (unsafeIOToST . go) =<< A.new len
46+ where
47+ desc = "Data.Text.Internal.Encoding.decodeUtf8: Invalid UTF-8 stream"
48+{-# INLINE unescapeText' #-}
49+
50+unescapeText :: ByteString -> Either UnicodeException Text
51+unescapeText = unsafeDupablePerformIO . try . evaluate . unescapeText'
52+{-# INLINE unescapeText #-}
include/incoherent-compat.hnew file+7
@@ -0,0 +1,7 @@
1+#if __GLASGOW_HASKELL__ >= 710
2+#define INCOHERENT_ {-# INCOHERENT #-}
3+#else
4+-- This causes some type class instances to break:
5+-- {-# LANGUAGE IncoherentInstances #-}
6+#define INCOHERENT_
7+#endif
include/overlapping-compat.h−7
@@ -1,15 +1,8 @@
11#if __GLASGOW_HASKELL__ >= 710
22#define OVERLAPPABLE_ {-# OVERLAPPABLE #-}
33#define OVERLAPPING_ {-# OVERLAPPING #-}
4−#ifdef NEEDS_INCOHERENT
5−#define INCOHERENT_ {-# INCOHERENT #-}
6−#endif
74#else
85{-# LANGUAGE OverlappingInstances #-}
96#define OVERLAPPABLE_
107#define OVERLAPPING_
11−#ifdef NEEDS_INCOHERENT
12−{-# LANGUAGE IncoherentInstances #-}
13−#define INCOHERENT_
14−#endif
158#endif
pure/Data/Aeson/Parser/UnescapePure.hsnew file+254
@@ -0,0 +1,254 @@
1+-- WARNING: This file is security sensitive as it uses unsafeWrite which does
2+-- not check bounds. Any changes should be made with care and we would love to
3+-- get informed about them, just cc us in any PR targetting this file: @eskimor @jprider63
4+-- We would be happy to review the changes!
5+
6+-- The security check at the end (pos > length) only works if pos grows
7+-- monotonously, if this condition does not hold, the check is flawed.
8+module Data.Aeson.Parser.UnescapePure
9+ (
10+ unescapeText
11+ ) where
12+
13+import Control.Exception (evaluate, throw, try)
14+import Control.Monad (when)
15+import Data.ByteString as B
16+import Data.Bits (Bits, shiftL, shiftR, (.&.), (.|.))
17+import Data.Text (Text)
18+import qualified Data.Text.Array as A
19+import Data.Text.Encoding.Error (UnicodeException (..))
20+import Data.Text.Internal.Private (runText)
21+import Data.Text.Unsafe (unsafeDupablePerformIO)
22+import Data.Word (Word8, Word16, Word32)
23+import GHC.ST (ST)
24+
25+-- Different UTF states.
26+data Utf =
27+ UtfGround
28+ | UtfTail1
29+ | UtfU32e0
30+ | UtfTail2
31+ | UtfU32ed
32+ | Utf843f0
33+ | UtfTail3
34+ | Utf843f4
35+ deriving (Eq)
36+
37+data State =
38+ StateNone
39+ | StateUtf !Utf !Word32
40+ | StateBackslash
41+ | StateU0
42+ | StateU1 !Word16
43+ | StateU2 !Word16
44+ | StateU3 !Word16
45+ | StateS0
46+ | StateS1
47+ | StateSU0
48+ | StateSU1 !Word16
49+ | StateSU2 !Word16
50+ | StateSU3 !Word16
51+ deriving (Eq)
52+
53+-- References:
54+-- http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
55+-- https://github.com/jwilm/vte/blob/master/utf8parse/src/table.rs.in
56+
57+setByte1 :: (Num a, Bits b, Bits a, Integral b) => a -> b -> a
58+setByte1 point word = point .|. fromIntegral (word .&. 0x3f)
59+{-# INLINE setByte1 #-}
60+
61+setByte2 :: (Num a, Bits b, Bits a, Integral b) => a -> b -> a
62+setByte2 point word = point .|. (fromIntegral (word .&. 0x3f) `shiftL` 6)
63+{-# INLINE setByte2 #-}
64+
65+setByte2Top :: (Num a, Bits b, Bits a, Integral b) => a -> b -> a
66+setByte2Top point word = point .|. (fromIntegral (word .&. 0x1f) `shiftL` 6)
67+{-# INLINE setByte2Top #-}
68+
69+setByte3 :: (Num a, Bits b, Bits a, Integral b) => a -> b -> a
70+setByte3 point word = point .|. (fromIntegral (word .&. 0x3f) `shiftL` 12)
71+{-# INLINE setByte3 #-}
72+
73+setByte3Top :: (Num a, Bits b, Bits a, Integral b) => a -> b -> a
74+setByte3Top point word = point .|. (fromIntegral (word .&. 0xf) `shiftL` 12)
75+{-# INLINE setByte3Top #-}
76+
77+setByte4 :: (Num a, Bits b, Bits a, Integral b) => a -> b -> a
78+setByte4 point word = point .|. (fromIntegral (word .&. 0x7) `shiftL` 18)
79+{-# INLINE setByte4 #-}
80+
81+decode :: Utf -> Word32 -> Word8 -> (Utf, Word32)
82+decode UtfGround point word = case word of
83+ w | 0x00 <= w && w <= 0x7f -> (UtfGround, fromIntegral word)
84+ w | 0xc2 <= w && w <= 0xdf -> (UtfTail1, setByte2Top point word)
85+ 0xe0 -> (UtfU32e0, setByte3Top point word)
86+ w | 0xe1 <= w && w <= 0xec -> (UtfTail2, setByte3Top point word)
87+ 0xed -> (UtfU32ed, setByte3Top point word)
88+ w | 0xee <= w && w <= 0xef -> (UtfTail2, setByte3Top point word)
89+ 0xf0 -> (Utf843f0, setByte4 point word)
90+ w | 0xf1 <= w && w <= 0xf3 -> (UtfTail3, setByte4 point word)
91+ 0xf4 -> (Utf843f4, setByte4 point word)
92+ _ -> throwDecodeError
93+
94+decode UtfU32e0 point word = case word of
95+ w | 0xa0 <= w && w <= 0xbf -> (UtfTail1, setByte2 point word)
96+ _ -> throwDecodeError
97+
98+decode UtfU32ed point word = case word of
99+ w | 0x80 <= w && w <= 0x9f -> (UtfTail1, setByte2 point word)
100+ _ -> throwDecodeError
101+
102+decode Utf843f0 point word = case word of
103+ w | 0x90 <= w && w <= 0xbf -> (UtfTail2, setByte3 point word)
104+ _ -> throwDecodeError
105+
106+decode Utf843f4 point word = case word of
107+ w | 0x80 <= w && w <= 0x8f -> (UtfTail2, setByte3 point word)
108+ _ -> throwDecodeError
109+
110+decode UtfTail3 point word = case word of
111+ w | 0x80 <= w && w <= 0xbf -> (UtfTail2, setByte3 point word)
112+ _ -> throwDecodeError
113+
114+decode UtfTail2 point word = case word of
115+ w | 0x80 <= w && w <= 0xbf -> (UtfTail1, setByte2 point word)
116+ _ -> throwDecodeError
117+
118+decode UtfTail1 point word = case word of
119+ w | 0x80 <= w && w <= 0xbf -> (UtfGround, setByte1 point word)
120+ _ -> throwDecodeError
121+
122+decodeHex :: Word8 -> Word16
123+decodeHex x
124+ | 48 <= x && x <= 57 = fromIntegral x - 48 -- 0-9
125+ | 65 <= x && x <= 70 = fromIntegral x - 55 -- A-F
126+ | 97 <= x && x <= 102 = fromIntegral x - 87 -- a-f
127+ | otherwise = throwDecodeError
128+
129+unescapeText' :: ByteString -> Text
130+unescapeText' bs = runText $ \done -> do
131+ dest <- A.new len
132+
133+ (pos, finalState) <- loop dest (0, StateNone) 0
134+
135+ -- Check final state. Currently pos gets only increased over time, so this check should catch overflows.
136+ when ( finalState /= StateNone || pos > len)
137+ throwDecodeError
138+
139+ done dest pos -- TODO: pos, pos-1??? XXX
140+
141+ where
142+ len = B.length bs
143+
144+ runUtf dest pos st point c = case decode st point c of
145+ (UtfGround, 92) -> -- Backslash
146+ return (pos, StateBackslash)
147+ (UtfGround, w) | w <= 0xffff ->
148+ writeAndReturn dest pos (fromIntegral w) StateNone
149+ (UtfGround, w) -> do
150+ write dest pos (0xd7c0 + fromIntegral (w `shiftR` 10))
151+ writeAndReturn dest (pos + 1) (0xdc00 + fromIntegral (w .&. 0x3ff)) StateNone
152+ (st', p) ->
153+ return (pos, StateUtf st' p)
154+
155+ loop :: A.MArray s -> (Int, State) -> Int -> ST s (Int, State)
156+ loop _ ps i | i >= len = return ps
157+ loop dest ps i = do
158+ let c = B.index bs i -- JP: We can use unsafe index once we prove bounds with Liquid Haskell.
159+ ps' <- f dest ps c
160+ loop dest ps' $ i+1
161+
162+ -- No pending state.
163+ f dest (pos, StateNone) c = runUtf dest pos UtfGround 0 c
164+
165+ -- In the middle of parsing a UTF string.
166+ f dest (pos, StateUtf st point) c = runUtf dest pos st point c
167+
168+ -- In the middle of escaping a backslash.
169+ f dest (pos, StateBackslash) 34 = writeAndReturn dest pos 34 StateNone -- "
170+ f dest (pos, StateBackslash) 92 = writeAndReturn dest pos 92 StateNone -- Backslash
171+ f dest (pos, StateBackslash) 47 = writeAndReturn dest pos 47 StateNone -- /
172+ f dest (pos, StateBackslash) 98 = writeAndReturn dest pos 8 StateNone -- b
173+ f dest (pos, StateBackslash) 102 = writeAndReturn dest pos 12 StateNone -- f
174+ f dest (pos, StateBackslash) 110 = writeAndReturn dest pos 10 StateNone -- n
175+ f dest (pos, StateBackslash) 114 = writeAndReturn dest pos 13 StateNone -- r
176+ f dest (pos, StateBackslash) 116 = writeAndReturn dest pos 9 StateNone -- t
177+ f _ (pos, StateBackslash) 117 = return (pos, StateU0) -- u
178+ f _ ( _, StateBackslash) _ = throwDecodeError
179+
180+ -- Processing '\u'.
181+ f _ (pos, StateU0) c =
182+ let w = decodeHex c in
183+ return (pos, StateU1 (w `shiftL` 12))
184+
185+ f _ (pos, StateU1 w') c =
186+ let w = decodeHex c in
187+ return (pos, StateU2 (w' .|. (w `shiftL` 8)))
188+
189+ f _ (pos, StateU2 w') c =
190+ let w = decodeHex c in
191+ return (pos, StateU3 (w' .|. (w `shiftL` 4)))
192+
193+ f dest (pos, StateU3 w') c =
194+ let w = decodeHex c in
195+ let u = w' .|. w in
196+
197+ -- Get next state based on surrogates.
198+ let st
199+ | u >= 0xd800 && u <= 0xdbff = -- High surrogate.
200+ StateS0
201+ | u >= 0xdc00 && u <= 0xdfff = -- Low surrogate.
202+ throwDecodeError
203+ | otherwise =
204+ StateNone
205+ in
206+ writeAndReturn dest pos u st
207+
208+ -- Handle surrogates.
209+ f _ (pos, StateS0) 92 = return (pos, StateS1) -- Backslash
210+ f _ ( _, StateS0) _ = throwDecodeError
211+
212+ f _ (pos, StateS1) 117 = return (pos, StateSU0) -- u
213+ f _ ( _, StateS1) _ = throwDecodeError
214+
215+ f _ (pos, StateSU0) c =
216+ let w = decodeHex c in
217+ return (pos, StateSU1 (w `shiftL` 12))
218+
219+ f _ (pos, StateSU1 w') c =
220+ let w = decodeHex c in
221+ return (pos, StateSU2 (w' .|. (w `shiftL` 8)))
222+
223+ f _ (pos, StateSU2 w') c =
224+ let w = decodeHex c in
225+ return (pos, StateSU3 (w' .|. (w `shiftL` 4)))
226+
227+ f dest (pos, StateSU3 w') c =
228+ let w = decodeHex c in
229+ let u = w' .|. w in
230+
231+ -- Check if not low surrogate.
232+ if u < 0xdc00 || u > 0xdfff then
233+ throwDecodeError
234+ else
235+ writeAndReturn dest pos u StateNone
236+
237+write :: A.MArray s -> Int -> Word16 -> ST s ()
238+write dest pos char =
239+ A.unsafeWrite dest pos char
240+{-# INLINE write #-}
241+
242+writeAndReturn :: A.MArray s -> Int -> Word16 -> t -> ST s (Int, t)
243+writeAndReturn dest pos char res = do
244+ write dest pos char
245+ return (pos + 1, res)
246+{-# INLINE writeAndReturn #-}
247+
248+throwDecodeError :: a
249+throwDecodeError =
250+ let desc = "Data.Text.Internal.Encoding.decodeUtf8: Invalid UTF-8 stream" in
251+ throw (DecodeError desc Nothing)
252+
253+unescapeText :: ByteString -> Either UnicodeException Text
254+unescapeText = unsafeDupablePerformIO . try . evaluate . unescapeText'
run-hlint.shnew file+7
@@ -0,0 +1,7 @@
1+#!/bin/bash
2+
3+if hash hlint 2>/dev/null; then
4+ hlint "$@"
5+else
6+ ./hlint.sh "$@"
7+fi
stack-bench.yamlnew file+12
@@ -0,0 +1,12 @@
1+resolver: nightly-2019-09-21
2+# We use aeson in the snapshot to
3+# - avoid recompilation of criterion
4+# - compare against it
5+# - '.'
6+#
7+# Also we use separate working directory to avoid "unregistering aeson"
8+# caused recompilations
9+work-dir: .stack-work-bench
10+packages:
11+- benchmarks
12+extra-deps: []
stack-ffi-unescape.yamlnew file+9
@@ -0,0 +1,9 @@
1+resolver: nightly-2019-09-21
2+packages:
3+- '.'
4+flags:
5+ aeson:
6+ fast: true
7+ cffi: true
8+extra-deps:
9+- Diff-0.4.0
stack-lts12.yamlnew file+15
@@ -0,0 +1,15 @@
1+resolver: lts-12.26
2+packages:
3+- '.'
4+- attoparsec-iso8601
5+flags:
6+ aeson:
7+ fast: true
8+ cffi: true
9+extra-deps:
10+- base-orphans-0.8.1
11+- hashable-time-0.2.0.1
12+- QuickCheck-2.13.1
13+- quickcheck-instances-0.3.21
14+- splitmix-0.0.2
15+- time-compat-1.9.2.2
stack-nightly.yamlnew file+11
@@ -0,0 +1,11 @@
1+resolver: nightly-2019-10-14
2+packages:
3+- '.'
4+- attoparsec-iso8601
5+flags:
6+ aeson:
7+ fast: true
8+ attoparsec-iso8601:
9+ fast: true
10+extra-deps:
11+- generic-deriving-1.12.4
stack.yamldeleted−7
@@ -1,7 +0,0 @@
1−resolver: lts-5.16
2−packages:
3−- '.'
4−- benchmarks
5−extra-deps:
6−- generic-deriving-1.10.4.1
7−flags: {}
tests/DataFamilies/Encoders.hs+5−2
@@ -1,13 +1,16 @@
11{-# LANGUAGE CPP #-}
22{-# LANGUAGE GADTs #-}
3+{-# LANGUAGE NoImplicitPrelude #-}
34{-# LANGUAGE TemplateHaskell #-}
45
5−module DataFamilies.Encoders where
6+module DataFamilies.Encoders (module DataFamilies.Encoders) where
7+
8+import Prelude.Compat
69
710import Data.Aeson.TH
811import Data.Aeson.Types
9−import Options
1012import DataFamilies.Types
13+import Options
1114
1215--------------------------------------------------------------------------------
1316-- Nullary encoders/decoders
tests/DataFamilies/Instances.hs+6−3
@@ -1,17 +1,19 @@
11{-# LANGUAGE FlexibleInstances #-}
22{-# LANGUAGE GADTs #-}
3+{-# LANGUAGE NoImplicitPrelude #-}
34{-# LANGUAGE TemplateHaskell #-}
45{-# LANGUAGE TypeFamilies #-}
6+
57{-# OPTIONS_GHC -fno-warn-orphans #-}
68
7−module DataFamilies.Instances where
9+module DataFamilies.Instances () where
10+
11+import Prelude.Compat
812
9−import Control.Applicative
1013import Data.Aeson.TH
1114import Data.Aeson.Types (FromJSON(..))
1215import DataFamilies.Types
1316import Test.QuickCheck (Arbitrary(..), elements, oneof)
14−import Prelude
1517
1618instance (Arbitrary a) => Arbitrary (Approx a) where
1719 arbitrary = Approx <$> arbitrary
@@ -24,6 +26,7 @@ instance Arbitrary a => Arbitrary (SomeType c () a) where
2426 , Unary <$> arbitrary
2527 , Product <$> arbitrary <*> arbitrary <*> arbitrary
2628 , Record <$> arbitrary <*> arbitrary <*> arbitrary
29+ , List <$> arbitrary
2730 ]
2831
2932instance Arbitrary (GADT String) where
tests/DataFamilies/Properties.hs+7−4
@@ -1,18 +1,21 @@
11{-# LANGUAGE CPP #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
23
34module DataFamilies.Properties (tests) where
45
6+import Prelude.Compat
7+
58import DataFamilies.Encoders
69import DataFamilies.Instances ()
10+import PropUtils
711
8−import Properties hiding (tests)
912
10−import Test.Framework (Test, testGroup)
11−import Test.Framework.Providers.QuickCheck2 (testProperty)
13+import Test.Tasty (TestTree, testGroup)
14+import Test.Tasty.QuickCheck (testProperty)
1215
1316--------------------------------------------------------------------------------
1417
15−tests :: Test
18+tests :: TestTree
1619tests = testGroup "data families" [
1720 testGroup "template-haskell" [
1821 testGroup "toJSON" [
tests/DataFamilies/Types.hs+8−3
@@ -1,14 +1,17 @@
11-- DataKinds is needed for deriveAll0 calls on GHC 8
22{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE DeriveGeneric #-}
34{-# LANGUAGE FlexibleInstances #-}
45{-# LANGUAGE GADTs #-}
56{-# LANGUAGE GeneralizedNewtypeDeriving #-}
7+{-# LANGUAGE NoImplicitPrelude #-}
68{-# LANGUAGE StandaloneDeriving #-}
7−{-# LANGUAGE DeriveGeneric #-}
89{-# LANGUAGE TemplateHaskell #-}
910{-# LANGUAGE TypeFamilies #-}
1011
11−module DataFamilies.Types where
12+module DataFamilies.Types (module DataFamilies.Types) where
13+
14+import Prelude.Compat
1215
1316import Generics.Deriving.TH (deriveAll0)
1417import Types (ApproxEq(..))
@@ -24,7 +27,9 @@ data instance SomeType c () a = Nullary
2427 | Record { testOne :: Double
2528 , testTwo :: Maybe Bool
2629 , testThree :: Maybe a
27− } deriving (Eq, Show)
30+ }
31+ | List [a]
32+ deriving (Eq, Show)
2833
2934data family Approx a
3035newtype instance Approx a = Approx { fromApprox :: a }
tests/Encoders.hs+232−7
@@ -1,7 +1,12 @@
1+{-# LANGUAGE CPP #-}
12{-# LANGUAGE GADTs #-}
3+{-# LANGUAGE NoImplicitPrelude #-}
24{-# LANGUAGE TemplateHaskell #-}
35
4−module Encoders where
6+module Encoders (module Encoders) where
7+
8+import Prelude.Compat
9+import Data.Text (Text)
510
611import Data.Aeson.TH
712import Data.Aeson.Types
@@ -92,20 +97,49 @@ gNullaryToEncodingObjectWithSingleField = genericToEncoding optsObjectWithSingle
9297gNullaryParseJSONObjectWithSingleField :: Value -> Parser Nullary
9398gNullaryParseJSONObjectWithSingleField = genericParseJSON optsObjectWithSingleField
9499
100+keyOptions :: JSONKeyOptions
101+keyOptions = defaultJSONKeyOptions { keyModifier = ('k' :) }
102+
103+gNullaryToJSONKey :: Nullary -> Either String Text
104+gNullaryToJSONKey x = case genericToJSONKey keyOptions of
105+ ToJSONKeyText p _ -> Right (p x)
106+ _ -> Left "Should be a ToJSONKeyText"
107+
108+gNullaryFromJSONKey :: Text -> Parser Nullary
109+gNullaryFromJSONKey t = case genericFromJSONKey keyOptions of
110+ FromJSONKeyTextParser p -> p t
111+ _ -> fail "Not a TextParser"
95112
96113--------------------------------------------------------------------------------
97114-- SomeType encoders/decoders
98115--------------------------------------------------------------------------------
99116
117+-- Unary types
118+type LiftToJSON f a =
119+ (a -> Value) -> ([a] -> Value) -> f a -> Value
120+type LiftToEncoding f a =
121+ (a -> Encoding) -> ([a] -> Encoding) -> f a -> Encoding
122+type LiftParseJSON f a =
123+ (Value -> Parser a) -> (Value -> Parser [a]) -> Value -> Parser (f a)
124+
100125thSomeTypeToJSON2ElemArray :: SomeType Int -> Value
101126thSomeTypeToJSON2ElemArray = $(mkToJSON opts2ElemArray ''SomeType)
102127
103128thSomeTypeToEncoding2ElemArray :: SomeType Int -> Encoding
104129thSomeTypeToEncoding2ElemArray = $(mkToEncoding opts2ElemArray ''SomeType)
105130
131+thSomeTypeLiftToJSON2ElemArray :: LiftToJSON SomeType a
132+thSomeTypeLiftToJSON2ElemArray = $(mkLiftToJSON opts2ElemArray ''SomeType)
133+
134+thSomeTypeLiftToEncoding2ElemArray :: LiftToEncoding SomeType a
135+thSomeTypeLiftToEncoding2ElemArray = $(mkLiftToEncoding opts2ElemArray ''SomeType)
136+
106137thSomeTypeParseJSON2ElemArray :: Value -> Parser (SomeType Int)
107138thSomeTypeParseJSON2ElemArray = $(mkParseJSON opts2ElemArray ''SomeType)
108139
140+thSomeTypeLiftParseJSON2ElemArray :: LiftParseJSON SomeType a
141+thSomeTypeLiftParseJSON2ElemArray = $(mkLiftParseJSON opts2ElemArray ''SomeType)
142+
109143
110144thSomeTypeToJSONTaggedObject :: SomeType Int -> Value
111145thSomeTypeToJSONTaggedObject = $(mkToJSON optsTaggedObject ''SomeType)
@@ -113,21 +147,36 @@ thSomeTypeToJSONTaggedObject = $(mkToJSON optsTaggedObject ''SomeType)
113147thSomeTypeToEncodingTaggedObject :: SomeType Int -> Encoding
114148thSomeTypeToEncodingTaggedObject = $(mkToEncoding optsTaggedObject ''SomeType)
115149
150+thSomeTypeLiftToJSONTaggedObject :: LiftToJSON SomeType a
151+thSomeTypeLiftToJSONTaggedObject = $(mkLiftToJSON optsTaggedObject ''SomeType)
152+
153+thSomeTypeLiftToEncodingTaggedObject :: LiftToEncoding SomeType a
154+thSomeTypeLiftToEncodingTaggedObject = $(mkLiftToEncoding optsTaggedObject ''SomeType)
155+
116156thSomeTypeParseJSONTaggedObject :: Value -> Parser (SomeType Int)
117157thSomeTypeParseJSONTaggedObject = $(mkParseJSON optsTaggedObject ''SomeType)
118158
159+thSomeTypeLiftParseJSONTaggedObject :: LiftParseJSON SomeType a
160+thSomeTypeLiftParseJSONTaggedObject = $(mkLiftParseJSON optsTaggedObject ''SomeType)
161+
119162
120163thSomeTypeToJSONObjectWithSingleField :: SomeType Int -> Value
121−thSomeTypeToJSONObjectWithSingleField =
122− $(mkToJSON optsObjectWithSingleField ''SomeType)
164+thSomeTypeToJSONObjectWithSingleField = $(mkToJSON optsObjectWithSingleField ''SomeType)
123165
124166thSomeTypeToEncodingObjectWithSingleField :: SomeType Int -> Encoding
125−thSomeTypeToEncodingObjectWithSingleField =
126− $(mkToEncoding optsObjectWithSingleField ''SomeType)
167+thSomeTypeToEncodingObjectWithSingleField = $(mkToEncoding optsObjectWithSingleField ''SomeType)
168+
169+thSomeTypeLiftToJSONObjectWithSingleField :: LiftToJSON SomeType a
170+thSomeTypeLiftToJSONObjectWithSingleField = $(mkLiftToJSON optsObjectWithSingleField ''SomeType)
171+
172+thSomeTypeLiftToEncodingObjectWithSingleField :: LiftToEncoding SomeType a
173+thSomeTypeLiftToEncodingObjectWithSingleField = $(mkLiftToEncoding optsObjectWithSingleField ''SomeType)
127174
128175thSomeTypeParseJSONObjectWithSingleField :: Value -> Parser (SomeType Int)
129−thSomeTypeParseJSONObjectWithSingleField =
130− $(mkParseJSON optsObjectWithSingleField ''SomeType)
176+thSomeTypeParseJSONObjectWithSingleField = $(mkParseJSON optsObjectWithSingleField ''SomeType)
177+
178+thSomeTypeLiftParseJSONObjectWithSingleField :: LiftParseJSON SomeType a
179+thSomeTypeLiftParseJSONObjectWithSingleField = $(mkLiftParseJSON optsObjectWithSingleField ''SomeType)
131180
132181
133182gSomeTypeToJSON2ElemArray :: SomeType Int -> Value
@@ -139,6 +188,15 @@ gSomeTypeToEncoding2ElemArray = genericToEncoding opts2ElemArray
139188gSomeTypeParseJSON2ElemArray :: Value -> Parser (SomeType Int)
140189gSomeTypeParseJSON2ElemArray = genericParseJSON opts2ElemArray
141190
191+gSomeTypeLiftToEncoding2ElemArray :: LiftToEncoding SomeType a
192+gSomeTypeLiftToEncoding2ElemArray = genericLiftToEncoding opts2ElemArray
193+
194+gSomeTypeLiftToJSON2ElemArray :: LiftToJSON SomeType a
195+gSomeTypeLiftToJSON2ElemArray = genericLiftToJSON opts2ElemArray
196+
197+gSomeTypeLiftParseJSON2ElemArray :: LiftParseJSON SomeType a
198+gSomeTypeLiftParseJSON2ElemArray = genericLiftParseJSON opts2ElemArray
199+
142200
143201gSomeTypeToJSONTaggedObject :: SomeType Int -> Value
144202gSomeTypeToJSONTaggedObject = genericToJSON optsTaggedObject
@@ -149,6 +207,15 @@ gSomeTypeToEncodingTaggedObject = genericToEncoding optsTaggedObject
149207gSomeTypeParseJSONTaggedObject :: Value -> Parser (SomeType Int)
150208gSomeTypeParseJSONTaggedObject = genericParseJSON optsTaggedObject
151209
210+gSomeTypeLiftToEncodingTaggedObject :: LiftToEncoding SomeType a
211+gSomeTypeLiftToEncodingTaggedObject = genericLiftToEncoding optsTaggedObject
212+
213+gSomeTypeLiftToJSONTaggedObject :: LiftToJSON SomeType a
214+gSomeTypeLiftToJSONTaggedObject = genericLiftToJSON optsTaggedObject
215+
216+gSomeTypeLiftParseJSONTaggedObject :: LiftParseJSON SomeType a
217+gSomeTypeLiftParseJSONTaggedObject = genericLiftParseJSON optsTaggedObject
218+
152219
153220gSomeTypeToJSONObjectWithSingleField :: SomeType Int -> Value
154221gSomeTypeToJSONObjectWithSingleField = genericToJSON optsObjectWithSingleField
@@ -159,6 +226,15 @@ gSomeTypeToEncodingObjectWithSingleField = genericToEncoding optsObjectWithSingl
159226gSomeTypeParseJSONObjectWithSingleField :: Value -> Parser (SomeType Int)
160227gSomeTypeParseJSONObjectWithSingleField = genericParseJSON optsObjectWithSingleField
161228
229+gSomeTypeLiftToEncodingObjectWithSingleField :: LiftToEncoding SomeType a
230+gSomeTypeLiftToEncodingObjectWithSingleField = genericLiftToEncoding optsObjectWithSingleField
231+
232+gSomeTypeLiftToJSONObjectWithSingleField :: LiftToJSON SomeType a
233+gSomeTypeLiftToJSONObjectWithSingleField = genericLiftToJSON optsObjectWithSingleField
234+
235+gSomeTypeLiftParseJSONObjectWithSingleField :: LiftParseJSON SomeType a
236+gSomeTypeLiftParseJSONObjectWithSingleField = genericLiftParseJSON optsObjectWithSingleField
237+
162238
163239gSomeTypeToJSONOmitNothingFields :: SomeType Int -> Value
164240gSomeTypeToJSONOmitNothingFields = genericToJSON optsOmitNothingFields
@@ -167,6 +243,104 @@ gSomeTypeToEncodingOmitNothingFields :: SomeType Int -> Encoding
167243gSomeTypeToEncodingOmitNothingFields = genericToEncoding optsOmitNothingFields
168244
169245
246+thSomeTypeParseJSONRejectUnknownFields :: Value -> Parser (SomeType Int)
247+thSomeTypeParseJSONRejectUnknownFields = $(mkParseJSON optsRejectUnknownFields ''SomeType)
248+
249+gSomeTypeParseJSONRejectUnknownFields :: Value -> Parser (SomeType Int)
250+gSomeTypeParseJSONRejectUnknownFields = genericParseJSON optsRejectUnknownFields
251+
252+
253+--------------------------------------------------------------------------------
254+-- Foo decoders
255+--------------------------------------------------------------------------------
256+
257+thFooParseJSONRejectUnknownFields :: Value -> Parser Foo
258+thFooParseJSONRejectUnknownFields = $(mkParseJSON optsRejectUnknownFields ''Foo)
259+
260+gFooParseJSONRejectUnknownFields :: Value -> Parser Foo
261+gFooParseJSONRejectUnknownFields = genericParseJSON optsRejectUnknownFields
262+
263+
264+thFooParseJSONRejectUnknownFieldsTagged :: Value -> Parser Foo
265+thFooParseJSONRejectUnknownFieldsTagged = $(mkParseJSON optsRejectUnknownFieldsTagged ''Foo)
266+
267+gFooParseJSONRejectUnknownFieldsTagged :: Value -> Parser Foo
268+gFooParseJSONRejectUnknownFieldsTagged = genericParseJSON optsRejectUnknownFieldsTagged
269+
270+
271+--------------------------------------------------------------------------------
272+-- Option fields
273+--------------------------------------------------------------------------------
274+
275+thOptionFieldToJSON :: OptionField -> Value
276+thOptionFieldToJSON = $(mkToJSON optsOptionField 'OptionField)
277+
278+thOptionFieldToEncoding :: OptionField -> Encoding
279+thOptionFieldToEncoding = $(mkToEncoding optsOptionField 'OptionField)
280+
281+thOptionFieldParseJSON :: Value -> Parser OptionField
282+thOptionFieldParseJSON = $(mkParseJSON optsOptionField 'OptionField)
283+
284+gOptionFieldToJSON :: OptionField -> Value
285+gOptionFieldToJSON = genericToJSON optsOptionField
286+
287+gOptionFieldToEncoding :: OptionField -> Encoding
288+gOptionFieldToEncoding = genericToEncoding optsOptionField
289+
290+gOptionFieldParseJSON :: Value -> Parser OptionField
291+gOptionFieldParseJSON = genericParseJSON optsOptionField
292+
293+thMaybeFieldToJSON :: MaybeField -> Value
294+thMaybeFieldToJSON = $(mkToJSON optsOptionField 'MaybeField)
295+
296+
297+--------------------------------------------------------------------------------
298+-- IncoherentInstancesNeeded
299+--------------------------------------------------------------------------------
300+
301+-- | This test demonstrates the need for IncoherentInstances. See the definition
302+-- of 'IncoherentInstancesNeeded' for a discussion of the issue.
303+--
304+-- NOTE 1: We only need to compile this test. We do not need to run it.
305+--
306+-- NOTE 2: We actually only use the INCOHERENT pragma on specific instances
307+-- instead of the IncoherentInstances language extension. Therefore, this is
308+-- only supported on GHC versions >= 7.10.
309+#if __GLASGOW_HASKELL__ >= 710
310+incoherentInstancesNeededParseJSONString :: FromJSON a => Value -> Parser (IncoherentInstancesNeeded a)
311+incoherentInstancesNeededParseJSONString = case () of
312+ _ | True -> $(mkParseJSON defaultOptions ''IncoherentInstancesNeeded)
313+ | False -> genericParseJSON defaultOptions
314+
315+incoherentInstancesNeededToJSON :: ToJSON a => IncoherentInstancesNeeded a -> Value
316+incoherentInstancesNeededToJSON = case () of
317+ _ | True -> $(mkToJSON defaultOptions ''IncoherentInstancesNeeded)
318+ | False -> genericToJSON defaultOptions
319+#endif
320+
321+-------------------------------------------------------------------------------
322+-- EitherTextInt encoders/decodes
323+-------------------------------------------------------------------------------
324+
325+thEitherTextIntToJSONUntaggedValue :: EitherTextInt -> Value
326+thEitherTextIntToJSONUntaggedValue = $(mkToJSON optsUntaggedValue ''EitherTextInt)
327+
328+thEitherTextIntToEncodingUntaggedValue :: EitherTextInt -> Encoding
329+thEitherTextIntToEncodingUntaggedValue = $(mkToEncoding optsUntaggedValue ''EitherTextInt)
330+
331+thEitherTextIntParseJSONUntaggedValue :: Value -> Parser EitherTextInt
332+thEitherTextIntParseJSONUntaggedValue = $(mkParseJSON optsUntaggedValue ''EitherTextInt)
333+
334+
335+gEitherTextIntToJSONUntaggedValue :: EitherTextInt -> Value
336+gEitherTextIntToJSONUntaggedValue = genericToJSON optsUntaggedValue
337+
338+gEitherTextIntToEncodingUntaggedValue :: EitherTextInt -> Encoding
339+gEitherTextIntToEncodingUntaggedValue = genericToEncoding optsUntaggedValue
340+
341+gEitherTextIntParseJSONUntaggedValue :: Value -> Parser EitherTextInt
342+gEitherTextIntParseJSONUntaggedValue = genericParseJSON optsUntaggedValue
343+
170344--------------------------------------------------------------------------------
171345-- Approx encoders/decoders
172346--------------------------------------------------------------------------------
@@ -231,3 +405,54 @@ thGADTToEncodingDefault = $(mkToEncoding defaultOptions ''GADT)
231405
232406thGADTParseJSONDefault :: Value -> Parser (GADT String)
233407thGADTParseJSONDefault = $(mkParseJSON defaultOptions ''GADT)
408+
409+--------------------------------------------------------------------------------
410+-- OneConstructor encoders/decoders
411+--------------------------------------------------------------------------------
412+
413+thOneConstructorToJSONDefault :: OneConstructor -> Value
414+thOneConstructorToJSONDefault = $(mkToJSON defaultOptions ''OneConstructor)
415+
416+thOneConstructorToEncodingDefault :: OneConstructor -> Encoding
417+thOneConstructorToEncodingDefault = $(mkToEncoding defaultOptions ''OneConstructor)
418+
419+thOneConstructorParseJSONDefault :: Value -> Parser OneConstructor
420+thOneConstructorParseJSONDefault = $(mkParseJSON defaultOptions ''OneConstructor)
421+
422+thOneConstructorToJSONTagged :: OneConstructor -> Value
423+thOneConstructorToJSONTagged = $(mkToJSON optsTagSingleConstructors ''OneConstructor)
424+
425+thOneConstructorToEncodingTagged :: OneConstructor -> Encoding
426+thOneConstructorToEncodingTagged = $(mkToEncoding optsTagSingleConstructors ''OneConstructor)
427+
428+thOneConstructorParseJSONTagged :: Value -> Parser OneConstructor
429+thOneConstructorParseJSONTagged = $(mkParseJSON optsTagSingleConstructors ''OneConstructor)
430+
431+
432+gOneConstructorToJSONDefault :: OneConstructor -> Value
433+gOneConstructorToJSONDefault = genericToJSON defaultOptions
434+
435+gOneConstructorToEncodingDefault :: OneConstructor -> Encoding
436+gOneConstructorToEncodingDefault = genericToEncoding defaultOptions
437+
438+gOneConstructorParseJSONDefault :: Value -> Parser OneConstructor
439+gOneConstructorParseJSONDefault = genericParseJSON defaultOptions
440+
441+gOneConstructorToJSONTagged :: OneConstructor -> Value
442+gOneConstructorToJSONTagged = genericToJSON optsTagSingleConstructors
443+
444+gOneConstructorToEncodingTagged :: OneConstructor -> Encoding
445+gOneConstructorToEncodingTagged = genericToEncoding optsTagSingleConstructors
446+
447+gOneConstructorParseJSONTagged :: Value -> Parser OneConstructor
448+gOneConstructorParseJSONTagged = genericParseJSON optsTagSingleConstructors
449+
450+--------------------------------------------------------------------------------
451+-- Product2 encoders/decoders
452+--------------------------------------------------------------------------------
453+
454+thProduct2ParseJSON :: Value -> Parser (Product2 Int Bool)
455+thProduct2ParseJSON = $(mkParseJSON defaultOptions ''Product2)
456+
457+gProduct2ParseJSON :: Value -> Parser (Product2 Int Bool)
458+gProduct2ParseJSON = genericParseJSON defaultOptions
tests/ErrorMessages.hsnew file+224
@@ -0,0 +1,224 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE ScopedTypeVariables #-}
4+
5+module ErrorMessages
6+ (
7+ tests
8+ ) where
9+
10+import Prelude.Compat
11+
12+import Data.Aeson (FromJSON(..), Value, json)
13+import Data.Aeson.Types (Parser)
14+import Data.Aeson.Parser (eitherDecodeWith)
15+import Data.Aeson.Internal (formatError, iparse)
16+import Data.Algorithm.Diff (PolyDiff (..), getGroupedDiff)
17+import Data.Proxy (Proxy(..))
18+import Data.Semigroup ((<>))
19+import Data.Sequence (Seq)
20+import Instances ()
21+import Numeric.Natural (Natural)
22+import Test.Tasty (TestTree, TestName)
23+import Test.Tasty.Golden.Advanced (goldenTest)
24+import qualified Data.ByteString.Lazy.Char8 as L
25+import qualified Data.HashMap.Strict as HM
26+
27+import Encoders
28+import Types
29+
30+tests :: [TestTree]
31+tests =
32+ [ aesonGoldenTest "simple" "tests/golden/simple.expected" output
33+ , aesonGoldenTest "generic" "tests/golden/generic.expected" (outputGeneric G)
34+ ]
35+
36+output :: Output
37+output = concat
38+ [ testFor "Int" (Proxy :: Proxy Int)
39+ [ "\"\""
40+ , "[]"
41+ , "{}"
42+ , "null"
43+ ]
44+
45+ , testFor "Integer" (Proxy :: Proxy Integer)
46+ [ "44.44"
47+ ]
48+
49+ , testFor "Natural" (Proxy :: Proxy Natural)
50+ [ "44.44"
51+ , "-50"
52+ ]
53+
54+ , testFor "String" (Proxy :: Proxy String)
55+ [ "1"
56+ , "[]"
57+ , "{}"
58+ , "null"
59+ ]
60+
61+ , testFor "HashMap" (Proxy :: Proxy (HM.HashMap String Int))
62+ [ "\"\""
63+ , "[]"
64+ ]
65+
66+ -- issue #356
67+ , testFor "Either" (Proxy :: Proxy (Int, Either (Int, Bool) ()))
68+ [ "[1,{\"Left\":[2,3]}]"
69+ ]
70+
71+ -- issue #358
72+ , testFor "Seq" (Proxy :: Proxy (Seq Int))
73+ [ "[0,1,true]"
74+ ]
75+ ]
76+
77+data Choice = TH | G
78+
79+outputGeneric :: Choice -> Output
80+outputGeneric choice = concat
81+ [ testWith "OneConstructor"
82+ (select
83+ thOneConstructorParseJSONDefault
84+ gOneConstructorParseJSONDefault)
85+ [ "\"X\""
86+ , "[0]"
87+ ]
88+
89+ , testWith "Nullary"
90+ (select
91+ thNullaryParseJSONString
92+ gNullaryParseJSONString)
93+ [ "\"X\""
94+ , "[]"
95+ ]
96+
97+ , testWithSomeType "SomeType (tagged)"
98+ (select
99+ thSomeTypeParseJSONTaggedObject
100+ gSomeTypeParseJSONTaggedObject)
101+ [ "{\"tag\": \"unary\", \"contents\": true}"
102+ , "{\"tag\": \"unary\"}"
103+ , "{\"tag\": \"record\"}"
104+ , "{\"tag\": \"record\", \"testone\": true, \"testtwo\": null, \"testthree\": null}"
105+ , "{\"tag\": \"X\"}"
106+ , "{}"
107+ , "[]"
108+ ]
109+
110+ , testWithSomeType "SomeType (single-field)"
111+ (select
112+ thSomeTypeParseJSONObjectWithSingleField
113+ gSomeTypeParseJSONObjectWithSingleField)
114+ [ "{\"unary\": {}}"
115+ , "{\"unary\": []}"
116+ , "{\"X\": []}"
117+ , "{\"record\": {}, \"W\":{}}"
118+ , "{}"
119+ , "[]"
120+ , "{\"unary\""
121+ , "{\"unary\":"
122+ , "{\"unary\":1"
123+ ]
124+
125+ , testWithSomeType "SomeType (two-element array)"
126+ (select
127+ thSomeTypeParseJSON2ElemArray
128+ gSomeTypeParseJSON2ElemArray)
129+ [ "[\"unary\", true]"
130+ , "[\"record\", null]"
131+ , "[\"X\", 0]"
132+ , "[null, 0]"
133+ , "[]"
134+ , "{}"
135+ , "[1"
136+ , "[1,"
137+ ]
138+
139+ , testWithSomeType "SomeType (reject unknown fields)"
140+ (select
141+ thSomeTypeParseJSONRejectUnknownFields
142+ gSomeTypeParseJSONRejectUnknownFields)
143+ [ "{\"tag\": \"record\", \"testOne\": 1.0, \"testZero\": 1}"
144+ , "{\"testZero\": 1}"
145+ , "{\"tag\": \"record\", \"testone\": true, \"testtwo\": null, \"testthree\": null}"
146+ ]
147+
148+ , testWithFoo "Foo (reject unknown fields)"
149+ (select
150+ thFooParseJSONRejectUnknownFields
151+ gFooParseJSONRejectUnknownFields)
152+ [ "{\"tag\": \"foo\"}"
153+ ]
154+
155+ , testWithFoo "Foo (reject unknown fields, tagged single)"
156+ (select
157+ thFooParseJSONRejectUnknownFieldsTagged
158+ gFooParseJSONRejectUnknownFieldsTagged)
159+ [ "{\"tag\": \"foo\", \"unknownField\": 0}"
160+ ]
161+
162+ , testWith "EitherTextInt"
163+ (select
164+ thEitherTextIntParseJSONUntaggedValue
165+ gEitherTextIntParseJSONUntaggedValue)
166+ [ "\"X\""
167+ , "[]"
168+ ]
169+
170+ , testWith "Product2 Int Bool"
171+ (select
172+ thProduct2ParseJSON
173+ gProduct2ParseJSON)
174+ [ "[1, null]"
175+ , "[]"
176+ , "{}"
177+ ]
178+ ]
179+ where
180+ select a b = case choice of
181+ TH -> a
182+ G -> b
183+
184+-- Test infrastructure
185+
186+type Output = [String]
187+
188+outputLine :: String -> Output
189+outputLine = pure
190+
191+aesonGoldenTest :: TestName -> FilePath -> Output -> TestTree
192+aesonGoldenTest name ref out = goldenTest name (L.readFile ref) act cmp upd
193+ where
194+ act = pure (L.pack (unlines out))
195+ upd = L.writeFile ref
196+ cmp x y | x == y = return Nothing
197+ cmp x y = return $ Just $ unlines $
198+ concatMap f (getGroupedDiff (L.lines x) (L.lines y))
199+ where
200+ f (First xs) = map (cons3 '-' . L.unpack) xs
201+ f (Second ys) = map (cons3 '+' . L.unpack) ys
202+ -- we print unchanged lines too. It shouldn't be a problem while we have
203+ -- reasonably small examples
204+ f (Both xs _) = map (cons3 ' ' . L.unpack) xs
205+ -- we add three characters, so the changed lines are easier to spot
206+ cons3 c cs = c : c : c : ' ' : cs
207+
208+testWith :: Show a => String -> (Value -> Parser a) -> [L.ByteString] -> Output
209+testWith name parser ts =
210+ outputLine name <>
211+ foldMap (\s ->
212+ case eitherDecodeWith json (iparse parser) s of
213+ Left err -> outputLine $ uncurry formatError err
214+ Right a -> outputLine $ show a) ts
215+
216+testFor :: forall a proxy. (FromJSON a, Show a)
217+ => String -> proxy a -> [L.ByteString] -> Output
218+testFor name _ = testWith name (parseJSON :: Value -> Parser a)
219+
220+testWithSomeType :: String -> (Value -> Parser (SomeType Int)) -> [L.ByteString] -> Output
221+testWithSomeType = testWith
222+
223+testWithFoo :: String -> (Value -> Parser Foo) -> [L.ByteString] -> Output
224+testWithFoo = testWith
tests/Functions.hs+9−1
@@ -1,4 +1,12 @@
1−module Functions where
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
3+module Functions
4+ (
5+ approxEq
6+ , approxEqWith
7+ ) where
8+
9+import Prelude.Compat
210
311approxEq :: (Fractional a, Ord a) => a -> a -> Bool
412approxEq = approxEqWith 1e-15 1e-15
tests/Instances.hs+38−53
@@ -1,45 +1,35 @@
1−{-# LANGUAGE CPP #-}
1+{-# LANGUAGE FlexibleContexts #-}
22{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE NoImplicitPrelude #-}
34{-# LANGUAGE OverloadedStrings #-}
45{-# LANGUAGE RecordWildCards #-}
5−{-# LANGUAGE StandaloneDeriving #-}
6+
67{-# OPTIONS_GHC -fno-warn-orphans #-}
78
8−module Instances where
9+module Instances () where
910
10−import Prelude ()
1111import Prelude.Compat
1212
13−import Types
14−import Data.Function (on)
13+import Control.Applicative (empty)
1514import Control.Monad
16−import Test.QuickCheck (Arbitrary(..), getNonNegative, elements,
17− listOf1, oneof, resize)
18−import Data.Time.Clock (UTCTime(..))
19−import Data.Time (ZonedTime(..), TimeZone(..))
20−import Data.List.NonEmpty (NonEmpty(..))
21−import Data.Version
2215import Data.Aeson.Types
23−import Control.Applicative (Const(..), empty)
24−import Data.Tagged (Tagged(..))
25−import Data.Proxy (Proxy(..))
16+import Data.Function (on)
17+import Data.Time (ZonedTime(..), TimeZone(..))
18+import Data.Time.Clock (UTCTime(..))
2619import Functions
20+import Test.QuickCheck (Arbitrary(..), elements, oneof)
21+import Types
2722import qualified Data.DList as DList
23+import qualified Data.HashMap.Strict as HM
2824
2925import Data.Orphans ()
3026import Test.QuickCheck.Instances ()
31−#if MIN_VERSION_base(4,7,0)
3227import Data.Hashable.Time ()
33−#endif
34−
35−#if !MIN_VERSION_base(4,8,0) && !MIN_VERSION_QuickCheck(2,8,3)
36−import Numeric.Natural
37−#endif
3828
3929-- "System" types.
4030
4131instance Arbitrary DotNetTime where
42− arbitrary = DotNetTime `liftM` arbitrary
32+ arbitrary = DotNetTime `fmap` arbitrary
4333 shrink = map DotNetTime . shrink . fromDotNetTime
4434
4535-- | Compare timezone part only on 'timeZoneMinutes'
@@ -57,8 +47,20 @@ instance ApproxEq UTCTime where
5747instance ApproxEq DotNetTime where
5848 (=~) = (=~) `on` fromDotNetTime
5949
50+instance ApproxEq Float where
51+ a =~ b
52+ | isNaN a && isNaN b = True
53+ | otherwise = approxEq a b
54+
6055instance ApproxEq Double where
61− (=~) = approxEq
56+ a =~ b
57+ | isNaN a && isNaN b = True
58+ | otherwise = approxEq a b
59+
60+instance (ApproxEq k, Eq v) => ApproxEq (HM.HashMap k v) where
61+ a =~ b = and $ zipWith eq (HM.toList a) (HM.toList b)
62+ where
63+ eq (x,y) (u,v) = x =~ u && y == v
6264
6365-- Test-related types.
6466
@@ -137,46 +139,29 @@ instance Arbitrary a => Arbitrary (SomeType a) where
137139 , Unary <$> arbitrary
138140 , Product <$> arbitrary <*> arbitrary <*> arbitrary
139141 , Record <$> arbitrary <*> arbitrary <*> arbitrary
142+ , List <$> arbitrary
140143 ]
141144
145+instance Arbitrary EitherTextInt where
146+ arbitrary = oneof
147+ [ LeftBool <$> arbitrary
148+ , RightInt <$> arbitrary
149+ , BothTextInt <$> arbitrary <*> arbitrary
150+ , pure NoneNullary
151+ ]
152+
142153instance Arbitrary (GADT String) where
143154 arbitrary = GADT <$> arbitrary
144155
156+instance Arbitrary OptionField where
157+ arbitrary = OptionField <$> arbitrary
158+
159+
145160instance ApproxEq Char where
146161 (=~) = (==)
147162
148163instance (ApproxEq a) => ApproxEq [a] where
149164 a =~ b = length a == length b && all (uncurry (=~)) (zip a b)
150165
151−instance Arbitrary Version where
152− arbitrary = makeVersion . fmap getNonNegative <$> resize 4 (listOf1 arbitrary)
153−
154−instance Arbitrary a => Arbitrary (NonEmpty a) where
155− arbitrary = (:|) <$> arbitrary <*> arbitrary
156−
157−-- Version tags are deprecated, so we avoid using them in the Arbitrary
158−-- instance. However, the recommended constructor 'makeVersion' is not
159−-- exported by "Data.Version" until base-4.8.0.0. For previous versions,
160−-- a definition is given below.
161−
162−#if !MIN_VERSION_base(4,8,0)
163−makeVersion :: [Int] -> Version
164−makeVersion b = Version b []
165−#endif
166−
167−#if !MIN_VERSION_base(4,8,0) && !MIN_VERSION_QuickCheck(2,8,3)
168−instance Arbitrary Natural where
169− arbitrary = fromInteger . abs <$> arbitrary
170−#endif
171−
172−instance Arbitrary (Proxy a) where
173− arbitrary = pure Proxy
174−
175−instance Arbitrary b => Arbitrary (Tagged a b) where
176− arbitrary = Tagged <$> arbitrary
177−
178−instance Arbitrary a => Arbitrary (Const a b) where
179− arbitrary = Const <$> arbitrary
180−
181166instance Arbitrary a => Arbitrary (DList.DList a) where
182167 arbitrary = DList.fromList <$> arbitrary
tests/JSONTestSuite/LICENSEnew file+21
@@ -0,0 +1,21 @@
1+MIT License
2+
3+Copyright (c) 2016 Nicolas Seriot
4+
5+Permission is hereby granted, free of charge, to any person obtaining a copy
6+of this software and associated documentation files (the "Software"), to deal
7+in the Software without restriction, including without limitation the rights
8+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+copies of the Software, and to permit persons to whom the Software is
10+furnished to do so, subject to the following conditions:
11+
12+The above copyright notice and this permission notice shall be included in all
13+copies or substantial portions of the Software.
14+
15+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+SOFTWARE.
tests/JSONTestSuite/README.mdnew file+50
@@ -0,0 +1,50 @@
1+# JSON Parsing Test Suite
2+A comprehensive test suite for RFC 7159 compliant JSON parsers
3+
4+This repository was created as an appendix to the article [Parsing JSON is a Minefield 💣](http://seriot.ch/parsing_json.php).
5+
6+**/parsers/**
7+
8+This directory contains several parsers and tiny wrappers to turn the parsers into JSON validators, by returning a specific value.
9+
10+- `0` the parser did accept the content
11+- `1` the parser did reject the content
12+- `>=1` the process did crash
13+- `timeout` happens after 5 seconds
14+
15+**/test\_parsing/**
16+
17+The name of these files tell if their contents should be accepted or rejected.
18+
19+- `y_` content must be accepted by parsers
20+- `n_` content must be rejected by parsers
21+- `i_` parsers are free to accept or reject content
22+
23+**/test\_transform/**
24+
25+These files contain weird structures and characters that parsers may understand differently, eg:
26+
27+- huge numbers
28+- dictionaries with similar keys
29+- NULL characters
30+- escaped invalid strings
31+
32+These files were used to produce `results/transform.html`.
33+
34+**/run_tests.py**
35+
36+Run all parsers with all files:
37+
38+ $ python3 run_tests.py
39+
40+Run all parsers with a specific file:
41+
42+ $ python3 run_tests.py file.json
43+
44+The script writes logs in `results/logs.txt`.
45+
46+The script then reads `logs.txt` and generates `results/parsing.html`.
47+
48+**/results/**
49+
50+<img src="results/pruned_results.png" alt="JSON Parsing Tests" />
tests/JSONTestSuite/parsers/test-AppleJSONSerialization/bin/test-AppleJSONSerializationnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/project.pbxprojnew file+260
@@ -0,0 +1,260 @@
1+// !$*UTF8*$!
2+{
3+ archiveVersion = 1;
4+ classes = {
5+ };
6+ objectVersion = 46;
7+ objects = {
8+
9+/* Begin PBXBuildFile section */
10+ 03997F941D70CE0C0001C89F /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03997F931D70CE0C0001C89F /* main.swift */; };
11+/* End PBXBuildFile section */
12+
13+/* Begin PBXCopyFilesBuildPhase section */
14+ 03997F8E1D70CE0C0001C89F /* CopyFiles */ = {
15+ isa = PBXCopyFilesBuildPhase;
16+ buildActionMask = 2147483647;
17+ dstPath = /usr/share/man/man1/;
18+ dstSubfolderSpec = 0;
19+ files = (
20+ );
21+ runOnlyForDeploymentPostprocessing = 1;
22+ };
23+/* End PBXCopyFilesBuildPhase section */
24+
25+/* Begin PBXFileReference section */
26+ 03997F901D70CE0C0001C89F /* test-AppleJSONSerialization */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "test-AppleJSONSerialization"; sourceTree = BUILT_PRODUCTS_DIR; };
27+ 03997F931D70CE0C0001C89F /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
28+/* End PBXFileReference section */
29+
30+/* Begin PBXFrameworksBuildPhase section */
31+ 03997F8D1D70CE0C0001C89F /* Frameworks */ = {
32+ isa = PBXFrameworksBuildPhase;
33+ buildActionMask = 2147483647;
34+ files = (
35+ );
36+ runOnlyForDeploymentPostprocessing = 0;
37+ };
38+/* End PBXFrameworksBuildPhase section */
39+
40+/* Begin PBXGroup section */
41+ 03997F871D70CE0C0001C89F = {
42+ isa = PBXGroup;
43+ children = (
44+ 03997F921D70CE0C0001C89F /* test-AppleJSONSerialization */,
45+ 03997F911D70CE0C0001C89F /* Products */,
46+ );
47+ sourceTree = "<group>";
48+ };
49+ 03997F911D70CE0C0001C89F /* Products */ = {
50+ isa = PBXGroup;
51+ children = (
52+ 03997F901D70CE0C0001C89F /* test-AppleJSONSerialization */,
53+ );
54+ name = Products;
55+ sourceTree = "<group>";
56+ };
57+ 03997F921D70CE0C0001C89F /* test-AppleJSONSerialization */ = {
58+ isa = PBXGroup;
59+ children = (
60+ 03997F931D70CE0C0001C89F /* main.swift */,
61+ );
62+ path = "test-AppleJSONSerialization";
63+ sourceTree = "<group>";
64+ };
65+/* End PBXGroup section */
66+
67+/* Begin PBXNativeTarget section */
68+ 03997F8F1D70CE0C0001C89F /* test-AppleJSONSerialization */ = {
69+ isa = PBXNativeTarget;
70+ buildConfigurationList = 03997F971D70CE0C0001C89F /* Build configuration list for PBXNativeTarget "test-AppleJSONSerialization" */;
71+ buildPhases = (
72+ 03997F8C1D70CE0C0001C89F /* Sources */,
73+ 03997F8D1D70CE0C0001C89F /* Frameworks */,
74+ 03997F8E1D70CE0C0001C89F /* CopyFiles */,
75+ );
76+ buildRules = (
77+ );
78+ dependencies = (
79+ );
80+ name = "test-AppleJSONSerialization";
81+ productName = "test-AppleJSONSerialization";
82+ productReference = 03997F901D70CE0C0001C89F /* test-AppleJSONSerialization */;
83+ productType = "com.apple.product-type.tool";
84+ };
85+/* End PBXNativeTarget section */
86+
87+/* Begin PBXProject section */
88+ 03997F881D70CE0C0001C89F /* Project object */ = {
89+ isa = PBXProject;
90+ attributes = {
91+ LastSwiftUpdateCheck = 0800;
92+ LastUpgradeCheck = 0800;
93+ ORGANIZATIONNAME = "Nicolas Seriot";
94+ TargetAttributes = {
95+ 03997F8F1D70CE0C0001C89F = {
96+ CreatedOnToolsVersion = 8.0;
97+ DevelopmentTeam = VBYRKYS73S;
98+ ProvisioningStyle = Automatic;
99+ };
100+ };
101+ };
102+ buildConfigurationList = 03997F8B1D70CE0C0001C89F /* Build configuration list for PBXProject "test-AppleJSONSerialization" */;
103+ compatibilityVersion = "Xcode 3.2";
104+ developmentRegion = English;
105+ hasScannedForEncodings = 0;
106+ knownRegions = (
107+ en,
108+ );
109+ mainGroup = 03997F871D70CE0C0001C89F;
110+ productRefGroup = 03997F911D70CE0C0001C89F /* Products */;
111+ projectDirPath = "";
112+ projectRoot = "";
113+ targets = (
114+ 03997F8F1D70CE0C0001C89F /* test-AppleJSONSerialization */,
115+ );
116+ };
117+/* End PBXProject section */
118+
119+/* Begin PBXSourcesBuildPhase section */
120+ 03997F8C1D70CE0C0001C89F /* Sources */ = {
121+ isa = PBXSourcesBuildPhase;
122+ buildActionMask = 2147483647;
123+ files = (
124+ 03997F941D70CE0C0001C89F /* main.swift in Sources */,
125+ );
126+ runOnlyForDeploymentPostprocessing = 0;
127+ };
128+/* End PBXSourcesBuildPhase section */
129+
130+/* Begin XCBuildConfiguration section */
131+ 03997F951D70CE0C0001C89F /* Debug */ = {
132+ isa = XCBuildConfiguration;
133+ buildSettings = {
134+ ALWAYS_SEARCH_USER_PATHS = NO;
135+ CLANG_ANALYZER_NONNULL = YES;
136+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
137+ CLANG_CXX_LIBRARY = "libc++";
138+ CLANG_ENABLE_MODULES = YES;
139+ CLANG_ENABLE_OBJC_ARC = YES;
140+ CLANG_WARN_BOOL_CONVERSION = YES;
141+ CLANG_WARN_CONSTANT_CONVERSION = YES;
142+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
143+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
144+ CLANG_WARN_EMPTY_BODY = YES;
145+ CLANG_WARN_ENUM_CONVERSION = YES;
146+ CLANG_WARN_INFINITE_RECURSION = YES;
147+ CLANG_WARN_INT_CONVERSION = YES;
148+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
149+ CLANG_WARN_SUSPICIOUS_MOVES = YES;
150+ CLANG_WARN_UNREACHABLE_CODE = YES;
151+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
152+ CODE_SIGN_IDENTITY = "-";
153+ COPY_PHASE_STRIP = NO;
154+ DEBUG_INFORMATION_FORMAT = dwarf;
155+ ENABLE_STRICT_OBJC_MSGSEND = YES;
156+ ENABLE_TESTABILITY = YES;
157+ GCC_C_LANGUAGE_STANDARD = gnu99;
158+ GCC_DYNAMIC_NO_PIC = NO;
159+ GCC_NO_COMMON_BLOCKS = YES;
160+ GCC_OPTIMIZATION_LEVEL = 0;
161+ GCC_PREPROCESSOR_DEFINITIONS = (
162+ "DEBUG=1",
163+ "$(inherited)",
164+ );
165+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
166+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
167+ GCC_WARN_UNDECLARED_SELECTOR = YES;
168+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
169+ GCC_WARN_UNUSED_FUNCTION = YES;
170+ GCC_WARN_UNUSED_VARIABLE = YES;
171+ MACOSX_DEPLOYMENT_TARGET = 10.11;
172+ MTL_ENABLE_DEBUG_INFO = YES;
173+ ONLY_ACTIVE_ARCH = YES;
174+ SDKROOT = macosx;
175+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
176+ };
177+ name = Debug;
178+ };
179+ 03997F961D70CE0C0001C89F /* Release */ = {
180+ isa = XCBuildConfiguration;
181+ buildSettings = {
182+ ALWAYS_SEARCH_USER_PATHS = NO;
183+ CLANG_ANALYZER_NONNULL = YES;
184+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
185+ CLANG_CXX_LIBRARY = "libc++";
186+ CLANG_ENABLE_MODULES = YES;
187+ CLANG_ENABLE_OBJC_ARC = YES;
188+ CLANG_WARN_BOOL_CONVERSION = YES;
189+ CLANG_WARN_CONSTANT_CONVERSION = YES;
190+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
191+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
192+ CLANG_WARN_EMPTY_BODY = YES;
193+ CLANG_WARN_ENUM_CONVERSION = YES;
194+ CLANG_WARN_INFINITE_RECURSION = YES;
195+ CLANG_WARN_INT_CONVERSION = YES;
196+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
197+ CLANG_WARN_SUSPICIOUS_MOVES = YES;
198+ CLANG_WARN_UNREACHABLE_CODE = YES;
199+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
200+ CODE_SIGN_IDENTITY = "-";
201+ COPY_PHASE_STRIP = NO;
202+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
203+ ENABLE_NS_ASSERTIONS = NO;
204+ ENABLE_STRICT_OBJC_MSGSEND = YES;
205+ GCC_C_LANGUAGE_STANDARD = gnu99;
206+ GCC_NO_COMMON_BLOCKS = YES;
207+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
208+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
209+ GCC_WARN_UNDECLARED_SELECTOR = YES;
210+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
211+ GCC_WARN_UNUSED_FUNCTION = YES;
212+ GCC_WARN_UNUSED_VARIABLE = YES;
213+ MACOSX_DEPLOYMENT_TARGET = 10.11;
214+ MTL_ENABLE_DEBUG_INFO = NO;
215+ SDKROOT = macosx;
216+ };
217+ name = Release;
218+ };
219+ 03997F981D70CE0C0001C89F /* Debug */ = {
220+ isa = XCBuildConfiguration;
221+ buildSettings = {
222+ DEVELOPMENT_TEAM = VBYRKYS73S;
223+ PRODUCT_NAME = "$(TARGET_NAME)";
224+ SWIFT_VERSION = 3.0;
225+ };
226+ name = Debug;
227+ };
228+ 03997F991D70CE0C0001C89F /* Release */ = {
229+ isa = XCBuildConfiguration;
230+ buildSettings = {
231+ DEVELOPMENT_TEAM = VBYRKYS73S;
232+ PRODUCT_NAME = "$(TARGET_NAME)";
233+ SWIFT_VERSION = 3.0;
234+ };
235+ name = Release;
236+ };
237+/* End XCBuildConfiguration section */
238+
239+/* Begin XCConfigurationList section */
240+ 03997F8B1D70CE0C0001C89F /* Build configuration list for PBXProject "test-AppleJSONSerialization" */ = {
241+ isa = XCConfigurationList;
242+ buildConfigurations = (
243+ 03997F951D70CE0C0001C89F /* Debug */,
244+ 03997F961D70CE0C0001C89F /* Release */,
245+ );
246+ defaultConfigurationIsVisible = 0;
247+ defaultConfigurationName = Release;
248+ };
249+ 03997F971D70CE0C0001C89F /* Build configuration list for PBXNativeTarget "test-AppleJSONSerialization" */ = {
250+ isa = XCConfigurationList;
251+ buildConfigurations = (
252+ 03997F981D70CE0C0001C89F /* Debug */,
253+ 03997F991D70CE0C0001C89F /* Release */,
254+ );
255+ defaultConfigurationIsVisible = 0;
256+ };
257+/* End XCConfigurationList section */
258+ };
259+ rootObject = 03997F881D70CE0C0001C89F /* Project object */;
260+}
tests/JSONTestSuite/parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Workspace
3+ version = "1.0">
4+ <FileRef
5+ location = "self:test-AppleJSONSerialization.xcodeproj">
6+ </FileRef>
7+</Workspace>
tests/JSONTestSuite/parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test-AppleJSONSerialization.xcschemenew file+91
@@ -0,0 +1,91 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Scheme
3+ LastUpgradeVersion = "0800"
4+ version = "1.3">
5+ <BuildAction
6+ parallelizeBuildables = "YES"
7+ buildImplicitDependencies = "YES">
8+ <BuildActionEntries>
9+ <BuildActionEntry
10+ buildForTesting = "YES"
11+ buildForRunning = "YES"
12+ buildForProfiling = "YES"
13+ buildForArchiving = "YES"
14+ buildForAnalyzing = "YES">
15+ <BuildableReference
16+ BuildableIdentifier = "primary"
17+ BlueprintIdentifier = "03997F8F1D70CE0C0001C89F"
18+ BuildableName = "test-AppleJSONSerialization"
19+ BlueprintName = "test-AppleJSONSerialization"
20+ ReferencedContainer = "container:test-AppleJSONSerialization.xcodeproj">
21+ </BuildableReference>
22+ </BuildActionEntry>
23+ </BuildActionEntries>
24+ </BuildAction>
25+ <TestAction
26+ buildConfiguration = "Debug"
27+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+ shouldUseLaunchSchemeArgsEnv = "YES">
30+ <Testables>
31+ </Testables>
32+ <MacroExpansion>
33+ <BuildableReference
34+ BuildableIdentifier = "primary"
35+ BlueprintIdentifier = "03997F8F1D70CE0C0001C89F"
36+ BuildableName = "test-AppleJSONSerialization"
37+ BlueprintName = "test-AppleJSONSerialization"
38+ ReferencedContainer = "container:test-AppleJSONSerialization.xcodeproj">
39+ </BuildableReference>
40+ </MacroExpansion>
41+ <AdditionalOptions>
42+ </AdditionalOptions>
43+ </TestAction>
44+ <LaunchAction
45+ buildConfiguration = "Debug"
46+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
48+ launchStyle = "0"
49+ useCustomWorkingDirectory = "NO"
50+ ignoresPersistentStateOnLaunch = "NO"
51+ debugDocumentVersioning = "YES"
52+ debugServiceExtension = "internal"
53+ allowLocationSimulation = "YES">
54+ <BuildableProductRunnable
55+ runnableDebuggingMode = "0">
56+ <BuildableReference
57+ BuildableIdentifier = "primary"
58+ BlueprintIdentifier = "03997F8F1D70CE0C0001C89F"
59+ BuildableName = "test-AppleJSONSerialization"
60+ BlueprintName = "test-AppleJSONSerialization"
61+ ReferencedContainer = "container:test-AppleJSONSerialization.xcodeproj">
62+ </BuildableReference>
63+ </BuildableProductRunnable>
64+ <AdditionalOptions>
65+ </AdditionalOptions>
66+ </LaunchAction>
67+ <ProfileAction
68+ buildConfiguration = "Release"
69+ shouldUseLaunchSchemeArgsEnv = "YES"
70+ savedToolIdentifier = ""
71+ useCustomWorkingDirectory = "NO"
72+ debugDocumentVersioning = "YES">
73+ <BuildableProductRunnable
74+ runnableDebuggingMode = "0">
75+ <BuildableReference
76+ BuildableIdentifier = "primary"
77+ BlueprintIdentifier = "03997F8F1D70CE0C0001C89F"
78+ BuildableName = "test-AppleJSONSerialization"
79+ BlueprintName = "test-AppleJSONSerialization"
80+ ReferencedContainer = "container:test-AppleJSONSerialization.xcodeproj">
81+ </BuildableReference>
82+ </BuildableProductRunnable>
83+ </ProfileAction>
84+ <AnalyzeAction
85+ buildConfiguration = "Debug">
86+ </AnalyzeAction>
87+ <ArchiveAction
88+ buildConfiguration = "Release"
89+ revealArchiveInOrganizer = "YES">
90+ </ArchiveAction>
91+</Scheme>
tests/JSONTestSuite/parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22
@@ -0,0 +1,22 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+<dict>
5+ <key>SchemeUserState</key>
6+ <dict>
7+ <key>test-AppleJSONSerialization.xcscheme</key>
8+ <dict>
9+ <key>orderHint</key>
10+ <integer>0</integer>
11+ </dict>
12+ </dict>
13+ <key>SuppressBuildableAutocreation</key>
14+ <dict>
15+ <key>03997F8F1D70CE0C0001C89F</key>
16+ <dict>
17+ <key>primary</key>
18+ <true/>
19+ </dict>
20+ </dict>
21+</dict>
22+</plist>
tests/JSONTestSuite/parsers/test-AppleJSONSerialization/test-AppleJSONSerialization/main.swiftnew file+34
@@ -0,0 +1,34 @@
1+//
2+// main.swift
3+// test-AppleJSONSerialization
4+//
5+// Created by nst on 26/08/16.
6+// Copyright © 2016 Nicolas Seriot. All rights reserved.
7+//
8+
9+import Foundation
10+
11+func main() {
12+
13+ guard ProcessInfo.processInfo.arguments.count == 2 else {
14+ let url = NSURL(fileURLWithPath: ProcessInfo.processInfo.arguments[0])
15+ guard let programName = url.lastPathComponent else { exit(1) }
16+ print("Usage: ./\(programName) file.json")
17+ exit(1)
18+ }
19+
20+ let path = ProcessInfo.processInfo.arguments[1]
21+ let url = NSURL.fileURL(withPath:path)
22+
23+ do {
24+ let data = try Data(contentsOf:url)
25+
26+ let _ = try JSONSerialization.jsonObject(with: data, options: [.allowFragments])
27+
28+ exit(0)
29+ } catch {
30+ exit(1)
31+ }
32+}
33+
34+main()
tests/JSONTestSuite/parsers/test_Bash_JSON/JSON.shnew file+208
@@ -0,0 +1,208 @@
1+#!/bin/sh
2+
3+throw() {
4+ echo "$*" >&2
5+ exit 1
6+}
7+
8+BRIEF=0
9+LEAFONLY=0
10+PRUNE=0
11+NO_HEAD=0
12+NORMALIZE_SOLIDUS=0
13+
14+usage() {
15+ echo
16+ echo "Usage: JSON.sh [-b] [-l] [-p] [-s] [-h]"
17+ echo
18+ echo "-p - Prune empty. Exclude fields with empty values."
19+ echo "-l - Leaf only. Only show leaf nodes, which stops data duplication."
20+ echo "-b - Brief. Combines 'Leaf only' and 'Prune empty' options."
21+ echo "-n - No-head. Do not show nodes that have no path (lines that start with [])."
22+ echo "-s - Remove escaping of the solidus symbol (straight slash)."
23+ echo "-h - This help text."
24+ echo
25+}
26+
27+parse_options() {
28+ set -- "$@"
29+ local ARGN=$#
30+ while [ "$ARGN" -ne 0 ]
31+ do
32+ case $1 in
33+ -h) usage
34+ exit 0
35+ ;;
36+ -b) BRIEF=1
37+ LEAFONLY=1
38+ PRUNE=1
39+ ;;
40+ -l) LEAFONLY=1
41+ ;;
42+ -p) PRUNE=1
43+ ;;
44+ -n) NO_HEAD=1
45+ ;;
46+ -s) NORMALIZE_SOLIDUS=1
47+ ;;
48+ ?*) echo "ERROR: Unknown option."
49+ usage
50+ exit 0
51+ ;;
52+ esac
53+ shift 1
54+ ARGN=$((ARGN-1))
55+ done
56+}
57+
58+awk_egrep () {
59+ local pattern_string=$1
60+
61+ gawk '{
62+ while ($0) {
63+ start=match($0, pattern);
64+ token=substr($0, start, RLENGTH);
65+ print token;
66+ $0=substr($0, start+RLENGTH);
67+ }
68+ }' pattern="$pattern_string"
69+}
70+
71+tokenize () {
72+ local GREP
73+ local ESCAPE
74+ local CHAR
75+
76+ if echo "test string" | egrep -ao --color=never "test" >/dev/null 2>&1
77+ then
78+ GREP='egrep -ao --color=never'
79+ else
80+ GREP='egrep -ao'
81+ fi
82+
83+ if echo "test string" | egrep -o "test" >/dev/null 2>&1
84+ then
85+ ESCAPE='(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})'
86+ CHAR='[^[:cntrl:]"\\]'
87+ else
88+ GREP=awk_egrep
89+ ESCAPE='(\\\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})'
90+ CHAR='[^[:cntrl:]"\\\\]'
91+ fi
92+
93+ local STRING="\"$CHAR*($ESCAPE$CHAR*)*\""
94+ local NUMBER='-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?'
95+ local KEYWORD='null|false|true'
96+ local SPACE='[[:space:]]+'
97+
98+ # Force zsh to expand $A into multiple words
99+ local is_wordsplit_disabled=$(unsetopt 2>/dev/null | grep -c '^shwordsplit$')
100+ if [ $is_wordsplit_disabled != 0 ]; then setopt shwordsplit; fi
101+ $GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | egrep -v "^$SPACE$"
102+ if [ $is_wordsplit_disabled != 0 ]; then unsetopt shwordsplit; fi
103+}
104+
105+parse_array () {
106+ local index=0
107+ local ary=''
108+ read -r token
109+ case "$token" in
110+ ']') ;;
111+ *)
112+ while :
113+ do
114+ parse_value "$1" "$index"
115+ index=$((index+1))
116+ ary="$ary""$value"
117+ read -r token
118+ case "$token" in
119+ ']') break ;;
120+ ',') ary="$ary," ;;
121+ *) throw "EXPECTED , or ] GOT ${token:-EOF}" ;;
122+ esac
123+ read -r token
124+ done
125+ ;;
126+ esac
127+ [ "$BRIEF" -eq 0 ] && value=$(printf '[%s]' "$ary") || value=
128+ :
129+}
130+
131+parse_object () {
132+ local key
133+ local obj=''
134+ read -r token
135+ case "$token" in
136+ '}') ;;
137+ *)
138+ while :
139+ do
140+ case "$token" in
141+ '"'*'"') key=$token ;;
142+ *) throw "EXPECTED string GOT ${token:-EOF}" ;;
143+ esac
144+ read -r token
145+ case "$token" in
146+ ':') ;;
147+ *) throw "EXPECTED : GOT ${token:-EOF}" ;;
148+ esac
149+ read -r token
150+ parse_value "$1" "$key"
151+ obj="$obj$key:$value"
152+ read -r token
153+ case "$token" in
154+ '}') break ;;
155+ ',') obj="$obj," ;;
156+ *) throw "EXPECTED , or } GOT ${token:-EOF}" ;;
157+ esac
158+ read -r token
159+ done
160+ ;;
161+ esac
162+ [ "$BRIEF" -eq 0 ] && value=$(printf '{%s}' "$obj") || value=
163+ :
164+}
165+
166+parse_value () {
167+ local jpath="${1:+$1,}$2" isleaf=0 isempty=0 print=0
168+ case "$token" in
169+ '{') parse_object "$jpath" ;;
170+ '[') parse_array "$jpath" ;;
171+ # At this point, the only valid single-character tokens are digits.
172+ ''|[!0-9]) throw "EXPECTED value GOT ${token:-EOF}" ;;
173+ *) value=$token
174+ # if asked, replace solidus ("\/") in json strings with normalized value: "/"
175+ [ "$NORMALIZE_SOLIDUS" -eq 1 ] && value=$(echo "$value" | sed 's#\\/#/#g')
176+ isleaf=1
177+ [ "$value" = '""' ] && isempty=1
178+ ;;
179+ esac
180+ [ "$value" = '' ] && return
181+ [ "$NO_HEAD" -eq 1 ] && [ -z "$jpath" ] && return
182+
183+ [ "$LEAFONLY" -eq 0 ] && [ "$PRUNE" -eq 0 ] && print=1
184+ [ "$LEAFONLY" -eq 1 ] && [ "$isleaf" -eq 1 ] && [ $PRUNE -eq 0 ] && print=1
185+ [ "$LEAFONLY" -eq 0 ] && [ "$PRUNE" -eq 1 ] && [ "$isempty" -eq 0 ] && print=1
186+ [ "$LEAFONLY" -eq 1 ] && [ "$isleaf" -eq 1 ] && \
187+ [ $PRUNE -eq 1 ] && [ $isempty -eq 0 ] && print=1
188+ [ "$print" -eq 1 ] && printf "[%s]\t%s\n" "$jpath" "$value"
189+ :
190+}
191+
192+parse () {
193+ read -r token
194+ parse_value
195+ read -r token
196+ case "$token" in
197+ '') ;;
198+ *) throw "EXPECTED EOF GOT $token" ;;
199+ esac
200+}
201+
202+if ([ "$0" = "$BASH_SOURCE" ] || ! [ -n "$BASH_SOURCE" ]);
203+then
204+ parse_options "$@"
205+ tokenize | parse
206+fi
207+
208+# vi: expandtab sw=2 ts=2
tests/JSONTestSuite/parsers/test_Freddy_20160830/bin/test_Freddynew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy.xcodeproj/project.pbxprojnew file+300
@@ -0,0 +1,300 @@
1+// !$*UTF8*$!
2+{
3+ archiveVersion = 1;
4+ classes = {
5+ };
6+ objectVersion = 46;
7+ objects = {
8+
9+/* Begin PBXBuildFile section */
10+ 03D84ABB1D5B0A1000776402 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03D84ABA1D5B0A1000776402 /* main.swift */; };
11+ 03F8F7811D5B75600021630C /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F7781D5B75600021630C /* JSON.swift */; };
12+ 03F8F7821D5B75600021630C /* JSONDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F7791D5B75600021630C /* JSONDecodable.swift */; };
13+ 03F8F7831D5B75600021630C /* JSONEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77A1D5B75600021630C /* JSONEncodable.swift */; };
14+ 03F8F7841D5B75600021630C /* JSONEncodingDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77B1D5B75600021630C /* JSONEncodingDetector.swift */; };
15+ 03F8F7851D5B75600021630C /* JSONLiteralConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77C1D5B75600021630C /* JSONLiteralConvertible.swift */; };
16+ 03F8F7861D5B75600021630C /* JSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77D1D5B75600021630C /* JSONParser.swift */; };
17+ 03F8F7871D5B75600021630C /* JSONParsing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77E1D5B75600021630C /* JSONParsing.swift */; };
18+ 03F8F7881D5B75600021630C /* JSONSerializing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77F1D5B75600021630C /* JSONSerializing.swift */; };
19+ 03F8F7891D5B75600021630C /* JSONSubscripting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F7801D5B75600021630C /* JSONSubscripting.swift */; };
20+/* End PBXBuildFile section */
21+
22+/* Begin PBXCopyFilesBuildPhase section */
23+ 03D84AB51D5B0A1000776402 /* CopyFiles */ = {
24+ isa = PBXCopyFilesBuildPhase;
25+ buildActionMask = 2147483647;
26+ dstPath = /usr/share/man/man1;
27+ dstSubfolderSpec = 0;
28+ files = (
29+ );
30+ runOnlyForDeploymentPostprocessing = 1;
31+ };
32+/* End PBXCopyFilesBuildPhase section */
33+
34+/* Begin PBXFileReference section */
35+ 03D84AB71D5B0A1000776402 /* test_Freddy */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_Freddy; sourceTree = BUILT_PRODUCTS_DIR; };
36+ 03D84ABA1D5B0A1000776402 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
37+ 03F8F7781D5B75600021630C /* JSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSON.swift; path = test_Freddy/JSON.swift; sourceTree = "<group>"; };
38+ 03F8F7791D5B75600021630C /* JSONDecodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONDecodable.swift; path = test_Freddy/JSONDecodable.swift; sourceTree = "<group>"; };
39+ 03F8F77A1D5B75600021630C /* JSONEncodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONEncodable.swift; path = test_Freddy/JSONEncodable.swift; sourceTree = "<group>"; };
40+ 03F8F77B1D5B75600021630C /* JSONEncodingDetector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONEncodingDetector.swift; path = test_Freddy/JSONEncodingDetector.swift; sourceTree = "<group>"; };
41+ 03F8F77C1D5B75600021630C /* JSONLiteralConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONLiteralConvertible.swift; path = test_Freddy/JSONLiteralConvertible.swift; sourceTree = "<group>"; };
42+ 03F8F77D1D5B75600021630C /* JSONParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONParser.swift; path = test_Freddy/JSONParser.swift; sourceTree = "<group>"; };
43+ 03F8F77E1D5B75600021630C /* JSONParsing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONParsing.swift; path = test_Freddy/JSONParsing.swift; sourceTree = "<group>"; };
44+ 03F8F77F1D5B75600021630C /* JSONSerializing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONSerializing.swift; path = test_Freddy/JSONSerializing.swift; sourceTree = "<group>"; };
45+ 03F8F7801D5B75600021630C /* JSONSubscripting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONSubscripting.swift; path = test_Freddy/JSONSubscripting.swift; sourceTree = "<group>"; };
46+/* End PBXFileReference section */
47+
48+/* Begin PBXFrameworksBuildPhase section */
49+ 03D84AB41D5B0A1000776402 /* Frameworks */ = {
50+ isa = PBXFrameworksBuildPhase;
51+ buildActionMask = 2147483647;
52+ files = (
53+ );
54+ runOnlyForDeploymentPostprocessing = 0;
55+ };
56+/* End PBXFrameworksBuildPhase section */
57+
58+/* Begin PBXGroup section */
59+ 03D84AAE1D5B0A1000776402 = {
60+ isa = PBXGroup;
61+ children = (
62+ 03F8F7781D5B75600021630C /* JSON.swift */,
63+ 03F8F7791D5B75600021630C /* JSONDecodable.swift */,
64+ 03F8F77A1D5B75600021630C /* JSONEncodable.swift */,
65+ 03F8F77B1D5B75600021630C /* JSONEncodingDetector.swift */,
66+ 03F8F77C1D5B75600021630C /* JSONLiteralConvertible.swift */,
67+ 03F8F77D1D5B75600021630C /* JSONParser.swift */,
68+ 03F8F77E1D5B75600021630C /* JSONParsing.swift */,
69+ 03F8F77F1D5B75600021630C /* JSONSerializing.swift */,
70+ 03F8F7801D5B75600021630C /* JSONSubscripting.swift */,
71+ 03D84AB91D5B0A1000776402 /* test_Freddy */,
72+ 03D84AB81D5B0A1000776402 /* Products */,
73+ );
74+ sourceTree = "<group>";
75+ };
76+ 03D84AB81D5B0A1000776402 /* Products */ = {
77+ isa = PBXGroup;
78+ children = (
79+ 03D84AB71D5B0A1000776402 /* test_Freddy */,
80+ );
81+ name = Products;
82+ sourceTree = "<group>";
83+ };
84+ 03D84AB91D5B0A1000776402 /* test_Freddy */ = {
85+ isa = PBXGroup;
86+ children = (
87+ 03D84ABA1D5B0A1000776402 /* main.swift */,
88+ );
89+ path = test_Freddy;
90+ sourceTree = "<group>";
91+ };
92+/* End PBXGroup section */
93+
94+/* Begin PBXNativeTarget section */
95+ 03D84AB61D5B0A1000776402 /* test_Freddy */ = {
96+ isa = PBXNativeTarget;
97+ buildConfigurationList = 03D84ABE1D5B0A1000776402 /* Build configuration list for PBXNativeTarget "test_Freddy" */;
98+ buildPhases = (
99+ 03D84AB31D5B0A1000776402 /* Sources */,
100+ 03D84AB41D5B0A1000776402 /* Frameworks */,
101+ 03D84AB51D5B0A1000776402 /* CopyFiles */,
102+ );
103+ buildRules = (
104+ );
105+ dependencies = (
106+ );
107+ name = test_Freddy;
108+ productName = test_Freddy;
109+ productReference = 03D84AB71D5B0A1000776402 /* test_Freddy */;
110+ productType = "com.apple.product-type.tool";
111+ };
112+/* End PBXNativeTarget section */
113+
114+/* Begin PBXProject section */
115+ 03D84AAF1D5B0A1000776402 /* Project object */ = {
116+ isa = PBXProject;
117+ attributes = {
118+ LastSwiftUpdateCheck = 0800;
119+ LastUpgradeCheck = 0800;
120+ ORGANIZATIONNAME = "Nicolas Seriot";
121+ TargetAttributes = {
122+ 03D84AB61D5B0A1000776402 = {
123+ CreatedOnToolsVersion = 8.0;
124+ DevelopmentTeam = VBYRKYS73S;
125+ DevelopmentTeamName = "Nicolas Seriot";
126+ ProvisioningStyle = Automatic;
127+ };
128+ };
129+ };
130+ buildConfigurationList = 03D84AB21D5B0A1000776402 /* Build configuration list for PBXProject "test_Freddy" */;
131+ compatibilityVersion = "Xcode 3.2";
132+ developmentRegion = English;
133+ hasScannedForEncodings = 0;
134+ knownRegions = (
135+ en,
136+ );
137+ mainGroup = 03D84AAE1D5B0A1000776402;
138+ productRefGroup = 03D84AB81D5B0A1000776402 /* Products */;
139+ projectDirPath = "";
140+ projectRoot = "";
141+ targets = (
142+ 03D84AB61D5B0A1000776402 /* test_Freddy */,
143+ );
144+ };
145+/* End PBXProject section */
146+
147+/* Begin PBXSourcesBuildPhase section */
148+ 03D84AB31D5B0A1000776402 /* Sources */ = {
149+ isa = PBXSourcesBuildPhase;
150+ buildActionMask = 2147483647;
151+ files = (
152+ 03F8F7881D5B75600021630C /* JSONSerializing.swift in Sources */,
153+ 03F8F7821D5B75600021630C /* JSONDecodable.swift in Sources */,
154+ 03F8F7851D5B75600021630C /* JSONLiteralConvertible.swift in Sources */,
155+ 03F8F7871D5B75600021630C /* JSONParsing.swift in Sources */,
156+ 03F8F7861D5B75600021630C /* JSONParser.swift in Sources */,
157+ 03F8F7831D5B75600021630C /* JSONEncodable.swift in Sources */,
158+ 03D84ABB1D5B0A1000776402 /* main.swift in Sources */,
159+ 03F8F7811D5B75600021630C /* JSON.swift in Sources */,
160+ 03F8F7891D5B75600021630C /* JSONSubscripting.swift in Sources */,
161+ 03F8F7841D5B75600021630C /* JSONEncodingDetector.swift in Sources */,
162+ );
163+ runOnlyForDeploymentPostprocessing = 0;
164+ };
165+/* End PBXSourcesBuildPhase section */
166+
167+/* Begin XCBuildConfiguration section */
168+ 03D84ABC1D5B0A1000776402 /* Debug */ = {
169+ isa = XCBuildConfiguration;
170+ buildSettings = {
171+ ALWAYS_SEARCH_USER_PATHS = NO;
172+ CLANG_ANALYZER_NONNULL = YES;
173+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
174+ CLANG_CXX_LIBRARY = "libc++";
175+ CLANG_ENABLE_MODULES = YES;
176+ CLANG_ENABLE_OBJC_ARC = YES;
177+ CLANG_WARN_BOOL_CONVERSION = YES;
178+ CLANG_WARN_CONSTANT_CONVERSION = YES;
179+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
180+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
181+ CLANG_WARN_EMPTY_BODY = YES;
182+ CLANG_WARN_ENUM_CONVERSION = YES;
183+ CLANG_WARN_INT_CONVERSION = YES;
184+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
185+ CLANG_WARN_UNREACHABLE_CODE = YES;
186+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
187+ CODE_SIGN_IDENTITY = "-";
188+ COPY_PHASE_STRIP = NO;
189+ DEBUG_INFORMATION_FORMAT = dwarf;
190+ ENABLE_STRICT_OBJC_MSGSEND = YES;
191+ ENABLE_TESTABILITY = YES;
192+ GCC_C_LANGUAGE_STANDARD = gnu99;
193+ GCC_DYNAMIC_NO_PIC = NO;
194+ GCC_NO_COMMON_BLOCKS = YES;
195+ GCC_OPTIMIZATION_LEVEL = 0;
196+ GCC_PREPROCESSOR_DEFINITIONS = (
197+ "DEBUG=1",
198+ "$(inherited)",
199+ );
200+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
201+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
202+ GCC_WARN_UNDECLARED_SELECTOR = YES;
203+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
204+ GCC_WARN_UNUSED_FUNCTION = YES;
205+ GCC_WARN_UNUSED_VARIABLE = YES;
206+ MACOSX_DEPLOYMENT_TARGET = 10.11;
207+ MTL_ENABLE_DEBUG_INFO = YES;
208+ ONLY_ACTIVE_ARCH = YES;
209+ SDKROOT = macosx;
210+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
211+ };
212+ name = Debug;
213+ };
214+ 03D84ABD1D5B0A1000776402 /* Release */ = {
215+ isa = XCBuildConfiguration;
216+ buildSettings = {
217+ ALWAYS_SEARCH_USER_PATHS = NO;
218+ CLANG_ANALYZER_NONNULL = YES;
219+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
220+ CLANG_CXX_LIBRARY = "libc++";
221+ CLANG_ENABLE_MODULES = YES;
222+ CLANG_ENABLE_OBJC_ARC = YES;
223+ CLANG_WARN_BOOL_CONVERSION = YES;
224+ CLANG_WARN_CONSTANT_CONVERSION = YES;
225+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
226+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
227+ CLANG_WARN_EMPTY_BODY = YES;
228+ CLANG_WARN_ENUM_CONVERSION = YES;
229+ CLANG_WARN_INT_CONVERSION = YES;
230+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
231+ CLANG_WARN_UNREACHABLE_CODE = YES;
232+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
233+ CODE_SIGN_IDENTITY = "-";
234+ COPY_PHASE_STRIP = NO;
235+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
236+ ENABLE_NS_ASSERTIONS = NO;
237+ ENABLE_STRICT_OBJC_MSGSEND = YES;
238+ GCC_C_LANGUAGE_STANDARD = gnu99;
239+ GCC_NO_COMMON_BLOCKS = YES;
240+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
241+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
242+ GCC_WARN_UNDECLARED_SELECTOR = YES;
243+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
244+ GCC_WARN_UNUSED_FUNCTION = YES;
245+ GCC_WARN_UNUSED_VARIABLE = YES;
246+ MACOSX_DEPLOYMENT_TARGET = 10.11;
247+ MTL_ENABLE_DEBUG_INFO = NO;
248+ SDKROOT = macosx;
249+ };
250+ name = Release;
251+ };
252+ 03D84ABF1D5B0A1000776402 /* Debug */ = {
253+ isa = XCBuildConfiguration;
254+ buildSettings = {
255+ FRAMEWORK_SEARCH_PATHS = (
256+ "$(inherited)",
257+ "$(PROJECT_DIR)",
258+ );
259+ PRODUCT_NAME = "$(TARGET_NAME)";
260+ SWIFT_VERSION = 2.3;
261+ };
262+ name = Debug;
263+ };
264+ 03D84AC01D5B0A1000776402 /* Release */ = {
265+ isa = XCBuildConfiguration;
266+ buildSettings = {
267+ FRAMEWORK_SEARCH_PATHS = (
268+ "$(inherited)",
269+ "$(PROJECT_DIR)",
270+ );
271+ PRODUCT_NAME = "$(TARGET_NAME)";
272+ SWIFT_VERSION = 2.3;
273+ };
274+ name = Release;
275+ };
276+/* End XCBuildConfiguration section */
277+
278+/* Begin XCConfigurationList section */
279+ 03D84AB21D5B0A1000776402 /* Build configuration list for PBXProject "test_Freddy" */ = {
280+ isa = XCConfigurationList;
281+ buildConfigurations = (
282+ 03D84ABC1D5B0A1000776402 /* Debug */,
283+ 03D84ABD1D5B0A1000776402 /* Release */,
284+ );
285+ defaultConfigurationIsVisible = 0;
286+ defaultConfigurationName = Release;
287+ };
288+ 03D84ABE1D5B0A1000776402 /* Build configuration list for PBXNativeTarget "test_Freddy" */ = {
289+ isa = XCConfigurationList;
290+ buildConfigurations = (
291+ 03D84ABF1D5B0A1000776402 /* Debug */,
292+ 03D84AC01D5B0A1000776402 /* Release */,
293+ );
294+ defaultConfigurationIsVisible = 0;
295+ defaultConfigurationName = Release;
296+ };
297+/* End XCConfigurationList section */
298+ };
299+ rootObject = 03D84AAF1D5B0A1000776402 /* Project object */;
300+}
tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Workspace
3+ version = "1.0">
4+ <FileRef
5+ location = "self:test_Freddy.xcodeproj">
6+ </FileRef>
7+</Workspace>
tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy.xcodeproj/project.xcworkspace/xcshareddata/test_Freddy.xcscmblueprintnew file+30
@@ -0,0 +1,30 @@
1+{
2+ "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A",
3+ "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
4+
5+ },
6+ "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
7+ "6ADA245F937D8ED6D99F5A7865E19F5267A169E2" : 0,
8+ "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A" : 0
9+ },
10+ "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "7B3DFA55-F9BF-41D8-8FD5-204D3162EB03",
11+ "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
12+ "6ADA245F937D8ED6D99F5A7865E19F5267A169E2" : "dropbox\/JSON\/test_Freddy\/Vendor\/Freddy\/",
13+ "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A" : "dropbox\/"
14+ },
15+ "DVTSourceControlWorkspaceBlueprintNameKey" : "test_Freddy",
16+ "DVTSourceControlWorkspaceBlueprintVersion" : 204,
17+ "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "JSON\/test_Freddy\/test_Freddy.xcodeproj",
18+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
19+ {
20+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/bignerdranch\/Freddy.git",
21+ "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
22+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "6ADA245F937D8ED6D99F5A7865E19F5267A169E2"
23+ },
24+ {
25+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "\/Users\/nst\/Dropbox\/dropbox.git",
26+ "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
27+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A"
28+ }
29+ ]
30+}
tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_Freddy.xcschemenew file+91
@@ -0,0 +1,91 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Scheme
3+ LastUpgradeVersion = "0800"
4+ version = "1.3">
5+ <BuildAction
6+ parallelizeBuildables = "YES"
7+ buildImplicitDependencies = "YES">
8+ <BuildActionEntries>
9+ <BuildActionEntry
10+ buildForTesting = "YES"
11+ buildForRunning = "YES"
12+ buildForProfiling = "YES"
13+ buildForArchiving = "YES"
14+ buildForAnalyzing = "YES">
15+ <BuildableReference
16+ BuildableIdentifier = "primary"
17+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
18+ BuildableName = "test_Freddy"
19+ BlueprintName = "test_Freddy"
20+ ReferencedContainer = "container:test_Freddy.xcodeproj">
21+ </BuildableReference>
22+ </BuildActionEntry>
23+ </BuildActionEntries>
24+ </BuildAction>
25+ <TestAction
26+ buildConfiguration = "Debug"
27+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+ shouldUseLaunchSchemeArgsEnv = "YES">
30+ <Testables>
31+ </Testables>
32+ <MacroExpansion>
33+ <BuildableReference
34+ BuildableIdentifier = "primary"
35+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
36+ BuildableName = "test_Freddy"
37+ BlueprintName = "test_Freddy"
38+ ReferencedContainer = "container:test_Freddy.xcodeproj">
39+ </BuildableReference>
40+ </MacroExpansion>
41+ <AdditionalOptions>
42+ </AdditionalOptions>
43+ </TestAction>
44+ <LaunchAction
45+ buildConfiguration = "Debug"
46+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
48+ launchStyle = "0"
49+ useCustomWorkingDirectory = "NO"
50+ ignoresPersistentStateOnLaunch = "NO"
51+ debugDocumentVersioning = "YES"
52+ debugServiceExtension = "internal"
53+ allowLocationSimulation = "YES">
54+ <BuildableProductRunnable
55+ runnableDebuggingMode = "0">
56+ <BuildableReference
57+ BuildableIdentifier = "primary"
58+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
59+ BuildableName = "test_Freddy"
60+ BlueprintName = "test_Freddy"
61+ ReferencedContainer = "container:test_Freddy.xcodeproj">
62+ </BuildableReference>
63+ </BuildableProductRunnable>
64+ <AdditionalOptions>
65+ </AdditionalOptions>
66+ </LaunchAction>
67+ <ProfileAction
68+ buildConfiguration = "Release"
69+ shouldUseLaunchSchemeArgsEnv = "YES"
70+ savedToolIdentifier = ""
71+ useCustomWorkingDirectory = "NO"
72+ debugDocumentVersioning = "YES">
73+ <BuildableProductRunnable
74+ runnableDebuggingMode = "0">
75+ <BuildableReference
76+ BuildableIdentifier = "primary"
77+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
78+ BuildableName = "test_Freddy"
79+ BlueprintName = "test_Freddy"
80+ ReferencedContainer = "container:test_Freddy.xcodeproj">
81+ </BuildableReference>
82+ </BuildableProductRunnable>
83+ </ProfileAction>
84+ <AnalyzeAction
85+ buildConfiguration = "Debug">
86+ </AnalyzeAction>
87+ <ArchiveAction
88+ buildConfiguration = "Release"
89+ revealArchiveInOrganizer = "YES">
90+ </ArchiveAction>
91+</Scheme>
tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22
@@ -0,0 +1,22 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+<dict>
5+ <key>SchemeUserState</key>
6+ <dict>
7+ <key>test_Freddy.xcscheme</key>
8+ <dict>
9+ <key>orderHint</key>
10+ <integer>0</integer>
11+ </dict>
12+ </dict>
13+ <key>SuppressBuildableAutocreation</key>
14+ <dict>
15+ <key>03D84AB61D5B0A1000776402</key>
16+ <dict>
17+ <key>primary</key>
18+ <true/>
19+ </dict>
20+ </dict>
21+</dict>
22+</plist>
tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSON.swiftnew file+95
@@ -0,0 +1,95 @@
1+//
2+// JSON.swift
3+// Freddy
4+//
5+// Created by Matthew D. Mathias on 3/17/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+/// An enum to describe the structure of JSON.
10+public enum JSON {
11+ /// A case for denoting an array with an associated value of `[JSON]`
12+ case Array([JSON])
13+ /// A case for denoting a dictionary with an associated value of `[Swift.String: JSON]`
14+ case Dictionary([Swift.String: JSON])
15+ /// A case for denoting a double with an associated value of `Swift.Double`.
16+ case Double(Swift.Double)
17+ /// A case for denoting an integer with an associated value of `Swift.Int`.
18+ case Int(Swift.Int)
19+ /// A case for denoting a string with an associated value of `Swift.String`.
20+ case String(Swift.String)
21+ /// A case for denoting a boolean with an associated value of `Swift.Bool`.
22+ case Bool(Swift.Bool)
23+ /// A case for denoting null.
24+ case Null
25+}
26+
27+// MARK: - Errors
28+
29+extension JSON {
30+
31+ /// An enum to encapsulate errors that may arise in working with `JSON`.
32+ public enum Error: ErrorType {
33+ /// The `index` is out of bounds for a JSON array
34+ case IndexOutOfBounds(index: Swift.Int)
35+
36+ /// The `key` was not found in the JSON dictionary
37+ case KeyNotFound(key: Swift.String)
38+
39+ /// The JSON is not subscriptable with `type`
40+ case UnexpectedSubscript(type: JSONPathType.Type)
41+
42+ /// Unexpected JSON `value` was found that is not convertible `to` type
43+ case ValueNotConvertible(value: JSON, to: Any.Type)
44+ }
45+
46+}
47+
48+// MARK: - Test Equality
49+
50+/// Return `true` if `lhs` is equal to `rhs`.
51+public func ==(lhs: JSON, rhs: JSON) -> Bool {
52+ switch (lhs, rhs) {
53+ case (.Array(let arrL), .Array(let arrR)):
54+ return arrL == arrR
55+ case (.Dictionary(let dictL), .Dictionary(let dictR)):
56+ return dictL == dictR
57+ case (.String(let strL), .String(let strR)):
58+ return strL == strR
59+ case (.Double(let dubL), .Double(let dubR)):
60+ return dubL == dubR
61+ case (.Double(let dubL), .Int(let intR)):
62+ return dubL == Double(intR)
63+ case (.Int(let intL), .Int(let intR)):
64+ return intL == intR
65+ case (.Int(let intL), .Double(let dubR)):
66+ return Double(intL) == dubR
67+ case (.Bool(let bL), .Bool(let bR)):
68+ return bL == bR
69+ case (.Null, .Null):
70+ return true
71+ default:
72+ return false
73+ }
74+}
75+
76+extension JSON: Equatable {}
77+
78+// MARK: - Printing
79+
80+extension JSON: CustomStringConvertible {
81+
82+ /// A textual representation of `self`.
83+ public var description: Swift.String {
84+ switch self {
85+ case .Array(let arr): return Swift.String(arr)
86+ case .Dictionary(let dict): return Swift.String(dict)
87+ case .String(let string): return string
88+ case .Double(let double): return Swift.String(double)
89+ case .Int(let int): return Swift.String(int)
90+ case .Bool(let bool): return Swift.String(bool)
91+ case .Null: return "null"
92+ }
93+ }
94+
95+}
tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSONDecodable.swiftnew file+177
@@ -0,0 +1,177 @@
1+//
2+// JSONDecodable.swift
3+// Freddy
4+//
5+// Created by Matthew D. Mathias on 3/24/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+/// A protocol to provide functionality for creating a model object with a `JSON`
10+/// value.
11+public protocol JSONDecodable {
12+
13+ /// Creates an instance of the model with a `JSON` instance.
14+ /// - parameter json: An instance of a `JSON` value from which to
15+ /// construct an instance of the implementing type.
16+ /// - throws: Any `JSON.Error` for errors derived from inspecting the
17+ /// `JSON` value, or any other error involved in decoding.
18+ init(json: JSON) throws
19+
20+}
21+
22+extension Double: JSONDecodable {
23+
24+ /// An initializer to create an instance of `Double` from a `JSON` value.
25+ /// - parameter json: An instance of `JSON`.
26+ /// - throws: The initializer will throw an instance of `JSON.Error` if
27+ /// an instance of `Double` cannot be created from the `JSON` value that was
28+ /// passed to this initializer.
29+ public init(json: JSON) throws {
30+ switch json {
31+ case let .Double(double):
32+ self = double
33+ case let .Int(int):
34+ self = Swift.Double(int)
35+ default:
36+ throw JSON.Error.ValueNotConvertible(value: json, to: Swift.Double)
37+ }
38+ }
39+
40+}
41+
42+extension Int: JSONDecodable {
43+
44+ /// An initializer to create an instance of `Int` from a `JSON` value.
45+ /// - parameter json: An instance of `JSON`.
46+ /// - throws: The initializer will throw an instance of `JSON.Error` if
47+ /// an instance of `Int` cannot be created from the `JSON` value that was
48+ /// passed to this initializer.
49+ public init(json: JSON) throws {
50+ switch json {
51+ case let .Double(double) where double <= Double(Swift.Int.max):
52+ self = Swift.Int(double)
53+ case let .Int(int):
54+ self = int
55+ default:
56+ throw JSON.Error.ValueNotConvertible(value: json, to: Swift.Int)
57+ }
58+ }
59+
60+}
61+
62+extension String: JSONDecodable {
63+
64+ /// An initializer to create an instance of `String` from a `JSON` value.
65+ /// - parameter json: An instance of `JSON`.
66+ /// - throws: The initializer will throw an instance of `JSON.Error` if
67+ /// an instance of `String` cannot be created from the `JSON` value that was
68+ /// passed to this initializer.
69+ public init(json: JSON) throws {
70+
71+ switch json {
72+ case let .String(string):
73+ self = string
74+ case let .Int(int):
75+ self = String(int)
76+ case let .Bool(bool):
77+ self = String(bool)
78+ case let .Double(double):
79+ self = String(double)
80+ default:
81+ throw JSON.Error.ValueNotConvertible(value: json, to: Swift.String)
82+ }
83+ }
84+
85+}
86+
87+extension Bool: JSONDecodable {
88+
89+ /// An initializer to create an instance of `Bool` from a `JSON` value.
90+ /// - parameter json: An instance of `JSON`.
91+ /// - throws: The initializer will throw an instance of `JSON.Error` if
92+ /// an instance of `Bool` cannot be created from the `JSON` value that was
93+ /// passed to this initializer.
94+ public init(json: JSON) throws {
95+ guard case let .Bool(bool) = json else {
96+ throw JSON.Error.ValueNotConvertible(value: json, to: Swift.Bool)
97+ }
98+ self = bool
99+ }
100+
101+}
102+
103+extension RawRepresentable where RawValue: JSONDecodable {
104+
105+ /// An initializer to create an instance of `RawRepresentable` from a `JSON` value.
106+ /// - parameter json: An instance of `JSON`.
107+ /// - throws: The initializer will throw an instance of `JSON.Error` if
108+ /// an instance of `RawRepresentable` cannot be created from the `JSON` value that was
109+ /// passed to this initializer.
110+ public init(json: JSON) throws {
111+ let raw = try json.decode(type: RawValue.self)
112+ guard let value = Self(rawValue: raw) else {
113+ throw JSON.Error.ValueNotConvertible(value: json, to: Self.self)
114+ }
115+ self = value
116+ }
117+}
118+
119+internal extension JSON {
120+
121+ /// Retrieves a `[JSON]` from the JSON.
122+ /// - parameter: A `JSON` to be used to create the returned `Array`.
123+ /// - returns: An `Array` of `JSON` elements
124+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`.
125+ /// - seealso: `JSON.decode(_:type:)`
126+ static func getArray(json: JSON) throws -> [JSON] {
127+ // Ideally should be expressed as a conditional protocol implementation on Swift.Array.
128+ guard case let .Array(array) = json else {
129+ throw Error.ValueNotConvertible(value: json, to: Swift.Array<JSON>)
130+ }
131+ return array
132+ }
133+
134+ /// Retrieves a `[String: JSON]` from the JSON.
135+ /// - parameter: A `JSON` to be used to create the returned `Dictionary`.
136+ /// - returns: An `Dictionary` of `String` mapping to `JSON` elements
137+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`.
138+ /// - seealso: `JSON.decode(_:type:)`
139+ static func getDictionary(json: JSON) throws -> [Swift.String: JSON] {
140+ // Ideally should be expressed as a conditional protocol implementation on Swift.Dictionary.
141+ guard case let .Dictionary(dictionary) = json else {
142+ throw Error.ValueNotConvertible(value: json, to: Swift.Dictionary<Swift.String, JSON>)
143+ }
144+ return dictionary
145+ }
146+
147+ /// Attempts to decode many values from a descendant JSON array at a path
148+ /// into JSON.
149+ /// - parameter: A `JSON` to be used to create the returned `Array` of some type conforming to `JSONDecodable`.
150+ /// - returns: An `Array` of `Decoded` elements.
151+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`, as
152+ /// well as any error that arises from decoding the contained values.
153+ /// - seealso: `JSON.decode(_:type:)`
154+ static func getArrayOf<Decoded: JSONDecodable>(json: JSON) throws -> [Decoded] {
155+ // Ideally should be expressed as a conditional protocol implementation on Swift.Dictionary.
156+ // This implementation also doesn't do the `type = Type.self` trick.
157+ return try getArray(json).map(Decoded.init)
158+ }
159+
160+ /// Attempts to decode many values from a descendant JSON object at a path
161+ /// into JSON.
162+ /// - returns: A `Dictionary` of string keys and `Decoded` values.
163+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)` or
164+ /// any error that arises from decoding the contained values.
165+ /// - seealso: `JSON.decode(_:type:)`
166+ static func getDictionaryOf<Decoded: JSONDecodable>(json: JSON) throws -> [Swift.String: Decoded] {
167+ guard case let .Dictionary(dictionary) = json else {
168+ throw Error.ValueNotConvertible(value: json, to: Swift.Dictionary<Swift.String, Decoded>)
169+ }
170+ var decodedDictionary = Swift.Dictionary<Swift.String, Decoded>(minimumCapacity: dictionary.count)
171+ for (key, value) in dictionary {
172+ decodedDictionary[key] = try Decoded(json: value)
173+ }
174+ return decodedDictionary
175+ }
176+
177+}
tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSONEncodable.swiftnew file+83
@@ -0,0 +1,83 @@
1+//
2+// JSONEncodable.swift
3+// Freddy
4+//
5+// Created by Matthew Mathias on 1/4/16.
6+// Copyright © 2016 Big Nerd Ranch. All rights reserved.
7+//
8+
9+import Foundation
10+
11+/// A protocol to facilitate encoding and decoding of `JSON`.
12+public protocol JSONEncodable {
13+ /// Converts an instance of a conforming type to `JSON`.
14+ /// - returns: An instance of `JSON`.
15+ /// - Note: If conforming to `JSONEncodable` with a custom type of your own, you should return an instance of
16+ /// `JSON.Dictionary`.
17+ func toJSON() -> JSON
18+}
19+
20+extension Array where Element: JSONEncodable {
21+ /// Converts an instance of `Array` whose elements conform to `JSONEncodable` to `JSON`.
22+ /// - returns: An instance of `JSON` where the enum case is `.Array`.
23+ public func toJSON() -> JSON {
24+ let arrayOfJSON = self.map { $0.toJSON() }
25+ return .Array(arrayOfJSON)
26+ }
27+}
28+
29+extension Dictionary where Value: JSONEncodable {
30+ /// Converts an instance of `Dictionary` whose values conform to `JSONEncodable` to `JSON`. The keys in the resulting
31+ /// `JSON.Dictionary` will be of type `String`.
32+ /// - returns: An instance of `JSON` where the enum case is `.Dictionary`.
33+ public func toJSON() -> JSON {
34+ var jsonDictionary = [String: JSON]()
35+
36+ for (k, v) in self {
37+ let key = String(k)
38+ jsonDictionary[key] = v.toJSON()
39+ }
40+
41+ return .Dictionary(jsonDictionary)
42+ }
43+}
44+
45+extension Int: JSONEncodable {
46+ /// Converts an instance of a conforming type to `JSON`.
47+ /// - returns: An instance of `JSON` where the enum case is `.Int`.
48+ public func toJSON() -> JSON {
49+ return .Int(self)
50+ }
51+}
52+
53+extension Double: JSONEncodable {
54+ /// Converts an instance of a conforming type to `JSON`.
55+ /// - returns: An instance of `JSON` where the enum case is `.Double`.
56+ public func toJSON() -> JSON {
57+ return .Double(self)
58+ }
59+}
60+
61+extension String: JSONEncodable {
62+ /// Converts an instance of a conforming type to `JSON`.
63+ /// - returns: An instance of `JSON` where the enum case is `.String`.
64+ public func toJSON() -> JSON {
65+ return .String(self)
66+ }
67+}
68+
69+extension Bool: JSONEncodable {
70+ /// Converts an instance of a conforming type to `JSON`.
71+ /// - returns: An instance of `JSON` where the enum case is `.Bool`.
72+ public func toJSON() -> JSON {
73+ return .Bool(self)
74+ }
75+}
76+
77+extension RawRepresentable where RawValue: JSONEncodable {
78+ /// Converts an instance of a conforming type to `JSON`.
79+ /// - returns: An instance of `JSON` where the enum case is whatever the underlying `RawValue` converts to.
80+ public func toJSON() -> JSON {
81+ return rawValue.toJSON()
82+ }
83+}
tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSONEncodingDetector.swiftnew file+110
@@ -0,0 +1,110 @@
1+//
2+// JSONEncodingDetector.swift
3+// Freddy
4+//
5+// Created by Robert Edwards on 1/27/16.
6+// Copyright © 2016 Big Nerd Ranch. All rights reserved.
7+//
8+
9+/// Struct for attempting to detect the Unicode encoding used with the data supplied to the JSONParser
10+public struct JSONEncodingDetector {
11+
12+ //// The Unicode encodings looked for during detection
13+ public enum Encoding {
14+ //// UTF-8
15+ case UTF8
16+ //// UTF-16 Little Endian
17+ case UTF16LE
18+ //// UTF-16 Big Endian
19+ case UTF16BE
20+ //// UTF-32 Little Endian
21+ case UTF32LE
22+ //// UTF-32 Big Endian
23+ case UTF32BE
24+ }
25+
26+ //// The Unicode encodings supported by JSONParser.swift
27+ public static let supportedEncodings: [Encoding] = [.UTF8]
28+
29+ typealias ByteStreamPrefixInformation = (encoding: Encoding, byteOrderMarkLength: Int)
30+
31+ //// Attempts to detect the Unicode encoding used for a given set of data.
32+ ////
33+ //// This function initially looks for a Byte Order Mark in the following form:
34+ ////
35+ //// Bytes | Encoding Form
36+ //// --------------|----------------
37+ //// 00 00 FE FF | UTF-32, big-endian
38+ //// FF FE 00 00 | UTF-32, little-endian
39+ //// FE FF | UTF-16, big-endian
40+ //// FF FE | UTF-16, little-endian
41+ //// EF BB BF | UTF-8
42+ ////
43+ //// If a BOM is not found then we detect using the following approach described in
44+ //// the JSON RFC http://www.ietf.org/rfc/rfc4627.txt:
45+ ////
46+ //// Since the first two characters of a JSON text will always be ASCII
47+ //// characters [RFC0020], it is possible to determine whether an octet
48+ //// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
49+ //// at the pattern of nulls in the first four octets.
50+ ////
51+ //// 00 00 00 xx UTF-32BE
52+ //// 00 xx 00 xx UTF-16BE
53+ //// xx 00 00 00 UTF-32LE
54+ //// xx 00 xx 00 UTF-16LE
55+ //// xx xx xx xx UTF-8
56+ ////
57+ //// - parameter header: The front Slice of data being read and evaluated.
58+ //// - returns: A tuple containing the detected Unicode encoding and the lenght of the byte order mark.
59+ static func detectEncoding(header: Slice<UnsafeBufferPointer<UInt8>>) -> ByteStreamPrefixInformation {
60+
61+ guard let prefix = prefixFromHeader(header) else {
62+ return (.UTF8, 0)
63+ }
64+
65+ if let prefixInfo = JSONEncodingDetector.encodingFromBOM(prefix) {
66+ return prefixInfo
67+ } else {
68+ switch prefix {
69+ case(0, 0, 0?, _):
70+ return (.UTF32BE, 0)
71+ case(_, 0, 0?, 0?):
72+ return (.UTF32LE, 0)
73+ case (0, _, 0?, _), (0, _, _, _):
74+ return (.UTF16BE, 0)
75+ case (_, 0, _, 0?), (_, 0, _, _):
76+ return (.UTF16LE, 0)
77+ default:
78+ return (.UTF8, 0)
79+ }
80+ }
81+ }
82+
83+ private typealias EncodingBytePrefix = (UInt8, UInt8, UInt8?, UInt8?)
84+
85+ private static func prefixFromHeader(header: Slice<UnsafeBufferPointer<UInt8>>) -> EncodingBytePrefix? {
86+ if header.count >= 4 {
87+ return(header[0], header[1], header[2], header[3])
88+ } else if header.count >= 2 {
89+ return (header[0], header[1], nil, nil)
90+ }
91+ return nil
92+ }
93+
94+ private static func encodingFromBOM(prefix: EncodingBytePrefix) -> ByteStreamPrefixInformation? {
95+ switch prefix {
96+ case(0xFE, 0xFF, _, _):
97+ return (.UTF16BE, 2)
98+ case(0x00, 0x00, 0xFE?, 0xFF?):
99+ return (.UTF32BE, 4)
100+ case(0xEF, 0xBB, 0xBF?, _):
101+ return (.UTF8, 3)
102+ case(0xFF, 0xFE, 0?, 0?):
103+ return (.UTF32LE, 4)
104+ case(0xFF, 0xFE, _, _):
105+ return (.UTF16LE, 2)
106+ default:
107+ return nil
108+ }
109+ }
110+}
tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSONLiteralConvertible.swiftnew file+130
@@ -0,0 +1,130 @@
1+//
2+// JSONLiteralConvertible.swift
3+// Freddy
4+//
5+// Created by Zachary Waldowski on 5/11/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+// MARK: - ArrayLiteralConvertible
10+
11+extension JSON: ArrayLiteralConvertible {
12+
13+ /// Create an instance by copying each element of the `collection` into a
14+ /// new `Array`.
15+ public init<Collection: CollectionType where Collection.Generator.Element == JSON>(_ collection: Collection) {
16+ self = .Array(Swift.Array(collection))
17+ }
18+
19+ /// Create an instance initialized with `elements`.
20+ public init(arrayLiteral elements: JSON...) {
21+ self.init(elements)
22+ }
23+
24+}
25+
26+// MARK: - DictionaryLiteralConvertible
27+
28+extension JSON: DictionaryLiteralConvertible {
29+
30+ /// Create an instance by copying each key/value pair of the `pairs` into
31+ /// a new `Dictionary`.
32+ public init<Dictionary: SequenceType where Dictionary.Generator.Element == (Swift.String, JSON)>(_ pairs: Dictionary) {
33+ var dictionary = Swift.Dictionary<Swift.String, JSON>(minimumCapacity: pairs.underestimateCount())
34+ for (key, value) in pairs {
35+ dictionary[key] = value
36+ }
37+ self = .Dictionary(dictionary)
38+ }
39+
40+ /// Create an instance initialized with `pairs`.
41+ public init(dictionaryLiteral pairs: (Swift.String, JSON)...) {
42+ self.init(pairs)
43+ }
44+
45+}
46+
47+// MARK: - FloatLiteralConvertible
48+
49+extension JSON: FloatLiteralConvertible {
50+
51+ /// Create an instance initialized to `Double` `value`.
52+ public init(_ value: Swift.Double) {
53+ self = .Double(value)
54+ }
55+
56+ /// Create a literal instance initialized to `value`.
57+ public init(floatLiteral value: Swift.Double) {
58+ self.init(value)
59+ }
60+
61+}
62+
63+// MARK: - IntegerLiteralConvertible
64+
65+extension JSON: IntegerLiteralConvertible {
66+
67+ /// Create an instance initialized to `Int` by `value`.
68+ public init(_ value: Swift.Int) {
69+ self = .Int(value)
70+ }
71+
72+ /// Create a literal instance initialized to `value`.
73+ public init(integerLiteral value: Swift.Int) {
74+ self.init(value)
75+ }
76+
77+}
78+
79+// MARK: - StringLiteralConvertible
80+
81+extension JSON: StringLiteralConvertible {
82+
83+ /// Create an instance initialized to `String` by `text`.
84+ public init(_ text: Swift.String) {
85+ self = .String(text)
86+ }
87+
88+ /// Create a literal instance initialized to `value`.
89+ public init(stringLiteral value: StringLiteralType) {
90+ self.init(value)
91+ }
92+
93+ /// Create a literal instance initialized to `value`.
94+ public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
95+ self.init(value)
96+ }
97+
98+ /// Create a literal instance initialized to `value`.
99+ public init(unicodeScalarLiteral value: StringLiteralType) {
100+ self.init(value)
101+ }
102+
103+}
104+
105+// MARK: - BooleanLiteralConvertible
106+
107+extension JSON: BooleanLiteralConvertible {
108+
109+ /// Create an instance initialized to `Bool` by `value`.
110+ public init(_ value: Swift.Bool) {
111+ self = .Bool(value)
112+ }
113+
114+ /// Create a literal instance initialized to `value`.
115+ public init(booleanLiteral value: Swift.Bool) {
116+ self.init(value)
117+ }
118+
119+}
120+
121+// MARK: - NilLiteralConvertible
122+
123+extension JSON: NilLiteralConvertible {
124+
125+ /// Create an instance initialized with `nil`.
126+ public init(nilLiteral: ()) {
127+ self = .Null
128+ }
129+
130+}
tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSONParser.swiftnew file+907
@@ -0,0 +1,907 @@
1+//
2+// JSONParser.swift
3+// Freddy
4+//
5+// Created by John Gallagher on 4/18/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+import Foundation
10+
11+private struct Literal {
12+ static let BACKSLASH = UInt8(ascii: "\\")
13+ static let BACKSPACE = UInt8(ascii: "\u{0008}")
14+ static let COLON = UInt8(ascii: ":")
15+ static let COMMA = UInt8(ascii: ",")
16+ static let DOUBLE_QUOTE = UInt8(ascii: "\"")
17+ static let FORMFEED = UInt8(ascii: "\u{000c}")
18+ static let LEFT_BRACE = UInt8(ascii: "{")
19+ static let LEFT_BRACKET = UInt8(ascii: "[")
20+ static let MINUS = UInt8(ascii: "-")
21+ static let NEWLINE = UInt8(ascii: "\n")
22+ static let PERIOD = UInt8(ascii: ".")
23+ static let PLUS = UInt8(ascii: "+")
24+ static let RETURN = UInt8(ascii: "\r")
25+ static let RIGHT_BRACE = UInt8(ascii: "}")
26+ static let RIGHT_BRACKET = UInt8(ascii: "]")
27+ static let SLASH = UInt8(ascii: "/")
28+ static let SPACE = UInt8(ascii: " ")
29+ static let TAB = UInt8(ascii: "\t")
30+
31+ static let a = UInt8(ascii: "a")
32+ static let b = UInt8(ascii: "b")
33+ static let c = UInt8(ascii: "c")
34+ static let d = UInt8(ascii: "d")
35+ static let e = UInt8(ascii: "e")
36+ static let f = UInt8(ascii: "f")
37+ static let l = UInt8(ascii: "l")
38+ static let n = UInt8(ascii: "n")
39+ static let r = UInt8(ascii: "r")
40+ static let s = UInt8(ascii: "s")
41+ static let t = UInt8(ascii: "t")
42+ static let u = UInt8(ascii: "u")
43+
44+ static let A = UInt8(ascii: "A")
45+ static let B = UInt8(ascii: "B")
46+ static let C = UInt8(ascii: "C")
47+ static let D = UInt8(ascii: "D")
48+ static let E = UInt8(ascii: "E")
49+ static let F = UInt8(ascii: "F")
50+
51+ static let zero = UInt8(ascii: "0")
52+ static let one = UInt8(ascii: "1")
53+ static let two = UInt8(ascii: "2")
54+ static let three = UInt8(ascii: "3")
55+ static let four = UInt8(ascii: "4")
56+ static let five = UInt8(ascii: "5")
57+ static let six = UInt8(ascii: "6")
58+ static let seven = UInt8(ascii: "7")
59+ static let eight = UInt8(ascii: "8")
60+ static let nine = UInt8(ascii: "9")
61+}
62+
63+private let ParserMaximumDepth = 512
64+
65+
66+/// A pure Swift JSON parser. This parser is much faster than the
67+/// `NSJSONSerialization`-based parser (due to the overhead of having to
68+/// dynamically cast the Objective-C objects to determine their type); however,
69+/// it is much newer and has restrictions that the `NSJSONSerialization` parser
70+/// does not. Two restrictions in particular are that it requires UTF-8 data as
71+/// input and it does not allow trailing commas in arrays or dictionaries.
72+public struct JSONParser {
73+
74+ private enum Sign: Int {
75+ case Positive = 1
76+ case Negative = -1
77+ }
78+
79+ private let input: UnsafeBufferPointer<UInt8>
80+ private let owner: Any?
81+ private var loc = 0
82+ private var depth = 0
83+
84+ private init<T>(buffer: UnsafeBufferPointer<UInt8>, owner: T) {
85+ self.input = buffer
86+ self.owner = owner
87+ }
88+
89+ /// Decode the root element of the `JSON` stream. This may be any fragment
90+ /// or a structural element, per RFC 7159.
91+ ///
92+ /// The beginning bytes are used to determine the stream's encoding.
93+ /// `JSONParser` currently only supports UTF-8 encoding, with or without
94+ /// a byte-order mark.
95+ ///
96+ /// - throws: `JSONParser.Error` for any decoding failures, including a
97+ /// source location if needed.
98+ public mutating func parse() throws -> JSON {
99+ try guardAgainstUnsupportedEncodings()
100+ let value = try parseValue()
101+ skipWhitespace()
102+ guard loc == input.count else {
103+ throw Error.EndOfStreamGarbage(offset: loc)
104+ }
105+ return value
106+ }
107+
108+ private mutating func parseValue() throws -> JSON {
109+ guard depth <= ParserMaximumDepth else {
110+ throw Error.ExceededNestingLimit(offset: loc)
111+ }
112+
113+ guard input.count > 0 else {
114+ throw Error.EndOfStreamUnexpected
115+ }
116+
117+ advancing: while loc < input.count {
118+ do {
119+ switch input[loc] {
120+ case Literal.LEFT_BRACKET:
121+ depth += 1
122+ defer { depth -= 1 }
123+ return try decodeArray()
124+
125+ case Literal.LEFT_BRACE:
126+ depth += 1
127+ defer { depth -= 1 }
128+ return try decodeObject()
129+
130+ case Literal.DOUBLE_QUOTE:
131+ return try decodeString()
132+
133+ case Literal.f:
134+ return try decodeFalse()
135+
136+ case Literal.n:
137+ return try decodeNull()
138+
139+ case Literal.t:
140+ return try decodeTrue()
141+
142+ case Literal.MINUS:
143+ return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .LeadingMinus))
144+
145+ case Literal.zero:
146+ return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .LeadingZero))
147+
148+ case Literal.one...Literal.nine:
149+ return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .PreDecimalDigits))
150+
151+ case Literal.SPACE, Literal.TAB, Literal.RETURN, Literal.NEWLINE:
152+ loc = loc.successor()
153+
154+ default:
155+ break advancing
156+ }
157+ } catch let InternalError.NumberOverflow(offset: start) {
158+ return try decodeNumberAsString(start)
159+ }
160+ }
161+
162+ if loc < input.count {
163+ throw Error.ValueInvalid(offset: loc, character: UnicodeScalar(input[loc]))
164+ } else {
165+ throw Error.EndOfStreamUnexpected
166+ }
167+ }
168+
169+ private mutating func skipWhitespace() {
170+ while loc < input.count {
171+ switch input[loc] {
172+ case Literal.SPACE, Literal.TAB, Literal.RETURN, Literal.NEWLINE:
173+ loc = loc.successor()
174+
175+ default:
176+ return
177+ }
178+ }
179+ }
180+
181+ private mutating func guardAgainstUnsupportedEncodings() throws {
182+ let header = input.prefix(4)
183+ let encodingPrefixInformation = JSONEncodingDetector.detectEncoding(header)
184+ guard JSONEncodingDetector.supportedEncodings.contains(encodingPrefixInformation.encoding) else {
185+ throw Error.InvalidUnicodeStreamEncoding(detectedEncoding: encodingPrefixInformation.encoding)
186+ }
187+ loc = loc.advancedBy(encodingPrefixInformation.byteOrderMarkLength)
188+ }
189+
190+ private mutating func decodeNull() throws -> JSON {
191+ guard loc.advancedBy(3, limit: input.count) != input.count else {
192+ throw Error.LiteralNilMisspelled(offset: loc)
193+ }
194+
195+ if input[loc+1] != Literal.u
196+ || input[loc+2] != Literal.l
197+ || input[loc+3] != Literal.l {
198+ throw Error.LiteralNilMisspelled(offset: loc)
199+ }
200+
201+ loc += 4
202+ return .Null
203+ }
204+
205+ private mutating func decodeTrue() throws -> JSON {
206+ guard loc.advancedBy(3, limit: input.count) != input.count else {
207+ throw Error.LiteralTrueMisspelled(offset: loc)
208+ }
209+
210+ if input[loc+1] != Literal.r
211+ || input[loc+2] != Literal.u
212+ || input[loc+3] != Literal.e {
213+ throw Error.LiteralTrueMisspelled(offset: loc)
214+ }
215+
216+ loc += 4
217+ return .Bool(true)
218+ }
219+
220+ private mutating func decodeFalse() throws -> JSON {
221+ guard loc.advancedBy(4, limit: input.count) != input.count else {
222+ throw Error.LiteralFalseMisspelled(offset: loc)
223+ }
224+
225+ if input[loc+1] != Literal.a
226+ || input[loc+2] != Literal.l
227+ || input[loc+3] != Literal.s
228+ || input[loc+4] != Literal.e {
229+ throw Error.LiteralFalseMisspelled(offset: loc)
230+ }
231+
232+ loc += 5
233+ return .Bool(false)
234+ }
235+
236+ private var stringDecodingBuffer = [UInt8]()
237+ private mutating func decodeString() throws -> JSON {
238+ let start = loc
239+ loc = loc.successor()
240+ stringDecodingBuffer.removeAll(keepCapacity: true)
241+ while loc < input.count {
242+ switch input[loc] {
243+ case Literal.BACKSLASH:
244+ loc = loc.successor()
245+ switch input[loc] {
246+ case Literal.DOUBLE_QUOTE: stringDecodingBuffer.append(Literal.DOUBLE_QUOTE)
247+ case Literal.BACKSLASH: stringDecodingBuffer.append(Literal.BACKSLASH)
248+ case Literal.SLASH: stringDecodingBuffer.append(Literal.SLASH)
249+ case Literal.b: stringDecodingBuffer.append(Literal.BACKSPACE)
250+ case Literal.f: stringDecodingBuffer.append(Literal.FORMFEED)
251+ case Literal.r: stringDecodingBuffer.append(Literal.RETURN)
252+ case Literal.t: stringDecodingBuffer.append(Literal.TAB)
253+ case Literal.n: stringDecodingBuffer.append(Literal.NEWLINE)
254+ case Literal.u:
255+ loc = loc.successor()
256+ try readUnicodeEscape(start: loc - 2)
257+
258+ // readUnicodeEscape() advances loc on its own, so we'll `continue` now
259+ // to skip the typical "advance past this character" for all the other escapes
260+ continue
261+
262+ default:
263+ throw Error.ControlCharacterUnrecognized(offset: loc)
264+ }
265+ loc = loc.successor()
266+
267+ case Literal.DOUBLE_QUOTE:
268+ loc = loc.successor()
269+ stringDecodingBuffer.append(0)
270+
271+ guard let string = (stringDecodingBuffer.withUnsafeBufferPointer {
272+ String.fromCString(UnsafePointer($0.baseAddress))
273+ }) else {
274+ throw Error.UnicodeEscapeInvalid(offset: start)
275+ }
276+
277+ return .String(string)
278+
279+ case let other:
280+ stringDecodingBuffer.append(other)
281+ loc = loc.successor()
282+ }
283+ }
284+
285+ throw Error.EndOfStreamUnexpected
286+ }
287+
288+ private mutating func readCodeUnit() -> UInt16? {
289+ guard loc + 4 <= input.count else {
290+ return nil
291+ }
292+ var codeUnit: UInt16 = 0
293+ for c in input[loc..<loc+4] {
294+ let nibble: UInt16
295+
296+ switch c {
297+ case Literal.zero...Literal.nine:
298+ nibble = UInt16(c - Literal.zero)
299+
300+ case Literal.a...Literal.f:
301+ nibble = 10 + UInt16(c - Literal.a)
302+
303+ case Literal.A...Literal.F:
304+ nibble = 10 + UInt16(c - Literal.A)
305+
306+ default:
307+ return nil
308+ }
309+ codeUnit = (codeUnit << 4) | nibble
310+ }
311+ loc += 4
312+ return codeUnit
313+ }
314+
315+ private mutating func readUnicodeEscape(start start: Int) throws {
316+ guard let codeUnit = readCodeUnit() else {
317+ throw Error.UnicodeEscapeInvalid(offset: start)
318+ }
319+
320+ let codeUnits: [UInt16]
321+
322+ if UTF16.isLeadSurrogate(codeUnit) {
323+ // First half of a UTF16 surrogate pair - we must parse another code unit and combine them
324+
325+ // First confirm and skip over that we have another "\u"
326+ guard loc + 6 <= input.count && input[loc] == Literal.BACKSLASH && input[loc+1] == Literal.u else {
327+ throw Error.UnicodeEscapeInvalid(offset: start)
328+ }
329+ loc += 2
330+
331+ // Ensure the second code unit is valid for the surrogate pair
332+ guard let secondCodeUnit = readCodeUnit() where UTF16.isTrailSurrogate(secondCodeUnit) else {
333+ throw Error.UnicodeEscapeInvalid(offset: start)
334+ }
335+
336+ codeUnits = [codeUnit, secondCodeUnit]
337+ } else {
338+ codeUnits = [codeUnit]
339+ }
340+
341+ let transcodeHadError = transcode(UTF16.self, UTF8.self, codeUnits.generate(), { self.stringDecodingBuffer.append($0) }, stopOnError: true)
342+
343+ if transcodeHadError {
344+ throw Error.UnicodeEscapeInvalid(offset: start)
345+ }
346+ }
347+
348+ private mutating func decodeArray() throws -> JSON {
349+ let start = loc
350+ loc = loc.successor()
351+ var items = [JSON]()
352+
353+ while loc < input.count {
354+ skipWhitespace()
355+
356+ if loc < input.count && input[loc] == Literal.RIGHT_BRACKET {
357+ loc = loc.successor()
358+ return .Array(items)
359+ }
360+
361+ if !items.isEmpty {
362+ guard loc < input.count && input[loc] == Literal.COMMA else {
363+ throw Error.CollectionMissingSeparator(offset: start)
364+ }
365+ loc = loc.successor()
366+ }
367+
368+ items.append(try parseValue())
369+ }
370+
371+ throw Error.EndOfStreamUnexpected
372+ }
373+
374+ // Decoding objects can be recursive, so we have to keep more than one
375+ // buffer around for building up key/value pairs (to reduce allocations
376+ // when parsing large JSON documents).
377+ //
378+ // Rough estimate of the difference between this and using a fresh
379+ // [(String,JSON)] for the `pairs` variable in decodeObject() below is
380+ // about 12% on an iPhone 5.
381+ private struct DecodeObjectBuffers {
382+ var buffers = [[(String,JSON)]]()
383+
384+ mutating func getBuffer() -> [(String,JSON)] {
385+ if !buffers.isEmpty {
386+ var buffer = buffers.removeLast()
387+ buffer.removeAll(keepCapacity: true)
388+ return buffer
389+ }
390+ return [(String,JSON)]()
391+ }
392+
393+ mutating func putBuffer(buffer: [(String,JSON)]) {
394+ buffers.append(buffer)
395+ }
396+ }
397+
398+ private var decodeObjectBuffers = DecodeObjectBuffers()
399+
400+ private mutating func decodeObject() throws -> JSON {
401+ let start = loc
402+ loc = loc.successor()
403+ var pairs = decodeObjectBuffers.getBuffer()
404+
405+ while loc < input.count {
406+ skipWhitespace()
407+
408+ if loc < input.count && input[loc] == Literal.RIGHT_BRACE {
409+ loc = loc.successor()
410+ var obj = [String:JSON](minimumCapacity: pairs.count)
411+ for (k, v) in pairs {
412+ obj[k] = v
413+ }
414+ decodeObjectBuffers.putBuffer(pairs)
415+ return .Dictionary(obj)
416+ }
417+
418+ if !pairs.isEmpty {
419+ guard loc < input.count && input[loc] == Literal.COMMA else {
420+ throw Error.CollectionMissingSeparator(offset: start)
421+ }
422+ loc = loc.successor()
423+
424+ skipWhitespace()
425+ }
426+
427+ guard loc < input.count && input[loc] == Literal.DOUBLE_QUOTE else {
428+ throw Error.DictionaryMissingKey(offset: start)
429+ }
430+
431+ let key = try decodeString().string()
432+ skipWhitespace()
433+
434+ guard loc < input.count && input[loc] == Literal.COLON else {
435+ throw Error.CollectionMissingSeparator(offset: start)
436+ }
437+ loc = loc.successor()
438+
439+ pairs.append((key, try parseValue()))
440+ }
441+
442+ throw Error.EndOfStreamUnexpected
443+ }
444+
445+ private mutating func decodeIntegralValue(parser: NumberParser) throws -> JSON {
446+ var sign = Sign.Positive
447+ var parser = parser
448+ var value = 0
449+
450+ // This would be more natural as `while true { ... }` with a meaningful .Done case,
451+ // but that causes compile time explosion in Swift 2.2. :-|
452+ while parser.state != .Done {
453+ switch parser.state {
454+ case .LeadingMinus:
455+ sign = .Negative
456+ try parser.parseNegative()
457+
458+ case .LeadingZero:
459+ parser.parseLeadingZero()
460+
461+ case .PreDecimalDigits:
462+ try parser.parsePreDecimalDigits { c in
463+ guard case let (exponent, false) = Int.multiplyWithOverflow(10, value) else {
464+ throw InternalError.NumberOverflow(offset: parser.start)
465+ }
466+
467+ guard case let (newValue, false) = Int.addWithOverflow(exponent, Int(c - Literal.zero)) else {
468+ throw InternalError.NumberOverflow(offset: parser.start)
469+ }
470+
471+ value = newValue
472+ }
473+
474+ case .Decimal, .Exponent:
475+ return try detectingFloatingPointErrors(parser.start) {
476+ try decodeFloatingPointValue(parser, sign: sign, value: Double(value))
477+ }
478+
479+ case .PostDecimalDigits, .ExponentSign, .ExponentDigits:
480+ assertionFailure("Invalid internal state while parsing number")
481+
482+ case .Done:
483+ fatalError("impossible condition")
484+ }
485+ }
486+
487+ guard case let (signedValue, false) = Int.multiplyWithOverflow(sign.rawValue, value) else {
488+ throw InternalError.NumberOverflow(offset: parser.start)
489+ }
490+
491+ loc = parser.loc
492+ return .Int(signedValue)
493+ }
494+
495+ private mutating func decodeFloatingPointValue(parser: NumberParser, sign: Sign, value: Double) throws -> JSON {
496+ var parser = parser
497+ var value = value
498+ var exponentSign = Sign.Positive
499+ var exponent = Double(0)
500+ var position = 0.1
501+
502+ // This would be more natural as `while true { ... }` with a meaningful .Done case,
503+ // but that causes compile time explosion in Swift 2.2. :-|
504+ while parser.state != .Done {
505+ switch parser.state {
506+ case .LeadingMinus, .LeadingZero, .PreDecimalDigits:
507+ assertionFailure("Invalid internal state while parsing number")
508+
509+ case .Decimal:
510+ try parser.parseDecimal()
511+
512+ case .PostDecimalDigits:
513+ parser.parsePostDecimalDigits { c in
514+ value += position * Double(c - Literal.zero)
515+ position /= 10
516+ }
517+
518+ case .Exponent:
519+ exponentSign = try parser.parseExponent()
520+
521+ case .ExponentSign:
522+ try parser.parseExponentSign()
523+
524+ case .ExponentDigits:
525+ parser.parseExponentDigits { c in
526+ exponent = exponent * 10 + Double(c - Literal.zero)
527+ }
528+
529+ case .Done:
530+ fatalError("impossible condition")
531+ }
532+ }
533+
534+ loc = parser.loc
535+ return .Double(Double(sign.rawValue) * value * pow(10, Double(exponentSign.rawValue) * exponent))
536+ }
537+
538+ private mutating func decodeNumberAsString(start: Int) throws -> JSON {
539+ var parser: NumberParser = {
540+ let state: NumberParser.State
541+ switch input[start] {
542+ case Literal.MINUS: state = .LeadingMinus
543+ case Literal.zero: state = .LeadingZero
544+ case Literal.one...Literal.nine: state = .PreDecimalDigits
545+ default:
546+ fatalError("Internal error: decodeNumber called on not-a-number")
547+ }
548+ return NumberParser(loc: start, input: input, state: state)
549+ }()
550+
551+ stringDecodingBuffer.removeAll(keepCapacity: true)
552+
553+ while true {
554+ switch parser.state {
555+ case .LeadingMinus:
556+ try parser.parseNegative()
557+ stringDecodingBuffer.append(Literal.MINUS)
558+
559+ case .LeadingZero:
560+ parser.parseLeadingZero()
561+ stringDecodingBuffer.append(Literal.zero)
562+
563+ case .PreDecimalDigits:
564+ parser.parsePreDecimalDigits { stringDecodingBuffer.append($0) }
565+
566+ case .Decimal:
567+ try parser.parseDecimal()
568+ stringDecodingBuffer.append(Literal.PERIOD)
569+
570+ case .PostDecimalDigits:
571+ parser.parsePostDecimalDigits { stringDecodingBuffer.append($0) }
572+
573+ case .Exponent:
574+ stringDecodingBuffer.append(input[parser.loc])
575+ _ = try parser.parseExponent()
576+
577+ case .ExponentSign:
578+ stringDecodingBuffer.append(input[parser.loc])
579+ try parser.parseExponentSign()
580+
581+ case .ExponentDigits:
582+ parser.parseExponentDigits { stringDecodingBuffer.append($0) }
583+
584+ case .Done:
585+ stringDecodingBuffer.append(0)
586+ guard let string = (stringDecodingBuffer.withUnsafeBufferPointer {
587+ String.fromCString(UnsafePointer($0.baseAddress))
588+ }) else {
589+ // Should never fail - any problems with the number string should
590+ // result in thrown errors above
591+ fatalError("Internal error: Invalid numeric string")
592+ }
593+
594+ loc = parser.loc
595+ return .String(string)
596+ }
597+ }
598+ }
599+
600+ private func detectingFloatingPointErrors<T>(loc: Int, @noescape _ f: () throws -> T) throws -> T {
601+ let flags = FE_UNDERFLOW | FE_OVERFLOW
602+ feclearexcept(flags)
603+ let value = try f()
604+ guard fetestexcept(flags) == 0 else {
605+ throw InternalError.NumberOverflow(offset: loc)
606+ }
607+ return value
608+ }
609+}
610+
611+private struct NumberParser {
612+ enum State {
613+ case LeadingMinus
614+ case LeadingZero
615+ case PreDecimalDigits
616+ case Decimal
617+ case PostDecimalDigits
618+ case Exponent
619+ case ExponentSign
620+ case ExponentDigits
621+ case Done
622+ }
623+
624+ let start: Int
625+ var loc = 0
626+ var state: State
627+ let input: UnsafeBufferPointer<UInt8>
628+
629+ init(loc: Int, input: UnsafeBufferPointer<UInt8>, state: State) {
630+ assert(loc < input.count, "Invalid input to NumberParser")
631+ self.start = loc
632+ self.loc = loc
633+ self.input = input
634+ self.state = state
635+ }
636+
637+ mutating func parseNegative() throws {
638+ assert(state == .LeadingMinus, "Unexpected state entering parseNegative")
639+
640+ loc = loc.successor()
641+ guard loc < input.count else {
642+ throw JSONParser.Error.EndOfStreamUnexpected
643+ }
644+
645+ switch input[loc] {
646+ case Literal.zero:
647+ state = .LeadingZero
648+
649+ case Literal.one...Literal.nine:
650+ state = .PreDecimalDigits
651+
652+ default:
653+ throw JSONParser.Error.NumberSymbolMissingDigits(offset: start)
654+ }
655+ }
656+
657+ mutating func parseLeadingZero() {
658+ assert(state == .LeadingZero, "Unexpected state entering parseLeadingZero")
659+
660+ loc = loc.successor()
661+ guard loc < input.count else {
662+ state = .Done
663+ return
664+ }
665+
666+ guard input[loc] == Literal.PERIOD else {
667+ state = .Done
668+ return
669+ }
670+
671+ state = .Decimal
672+ }
673+
674+ mutating func parsePreDecimalDigits(@noescape f: (UInt8) throws -> Void) rethrows {
675+ assert(state == .PreDecimalDigits, "Unexpected state entering parsePreDecimalDigits")
676+ advancing: while loc < input.count {
677+ let c = input[loc]
678+ switch c {
679+ case Literal.zero...Literal.nine:
680+ try f(c)
681+ loc = loc.successor()
682+
683+ case Literal.PERIOD:
684+ state = .Decimal
685+ return
686+
687+ case Literal.e, Literal.E:
688+ state = .Exponent
689+ return
690+
691+ default:
692+ break advancing
693+ }
694+ }
695+
696+ state = .Done
697+ }
698+
699+ mutating func parseDecimal() throws {
700+ assert(state == .Decimal, "Unexpected state entering parseDecimal")
701+ loc = loc.successor()
702+ guard loc < input.count else {
703+ throw JSONParser.Error.EndOfStreamUnexpected
704+ }
705+
706+ switch input[loc] {
707+ case Literal.zero...Literal.nine:
708+ state = .PostDecimalDigits
709+
710+ default:
711+ throw JSONParser.Error.NumberMissingFractionalDigits(offset: start)
712+ }
713+ }
714+
715+ mutating func parsePostDecimalDigits(@noescape f: (UInt8) throws -> Void) rethrows {
716+ assert(state == .PostDecimalDigits, "Unexpected state entering parsePostDecimalDigits")
717+
718+ advancing: while loc < input.count {
719+ let c = input[loc]
720+ switch c {
721+ case Literal.zero...Literal.nine:
722+ try f(c)
723+ loc = loc.successor()
724+
725+ case Literal.e, Literal.E:
726+ state = .Exponent
727+ return
728+
729+ default:
730+ break advancing
731+ }
732+ }
733+
734+ state = .Done
735+ }
736+
737+ mutating func parseExponent() throws -> JSONParser.Sign {
738+ assert(state == .Exponent, "Unexpected state entering parseExponent")
739+
740+ loc = loc.successor()
741+ guard loc < input.count else {
742+ throw JSONParser.Error.EndOfStreamUnexpected
743+ }
744+
745+ switch input[loc] {
746+ case Literal.zero...Literal.nine:
747+ state = .ExponentDigits
748+
749+ case Literal.PLUS:
750+ state = .ExponentSign
751+
752+ case Literal.MINUS:
753+ state = .ExponentSign
754+ return .Negative
755+
756+ default:
757+ throw JSONParser.Error.NumberSymbolMissingDigits(offset: start)
758+ }
759+
760+ return .Positive
761+ }
762+
763+ mutating func parseExponentSign() throws {
764+ assert(state == .ExponentSign, "Unexpected state entering parseExponentSign")
765+ loc = loc.successor()
766+ guard loc < input.count else {
767+ throw JSONParser.Error.EndOfStreamUnexpected
768+ }
769+
770+ switch input[loc] {
771+ case Literal.zero...Literal.nine:
772+ state = .ExponentDigits
773+
774+ default:
775+ throw JSONParser.Error.NumberSymbolMissingDigits(offset: start)
776+ }
777+ }
778+
779+ mutating func parseExponentDigits(@noescape f: (UInt8) throws -> Void) rethrows {
780+ assert(state == .ExponentDigits, "Unexpected state entering parseExponentDigits")
781+ advancing: while loc < input.count {
782+ let c = input[loc]
783+ switch c {
784+ case Literal.zero...Literal.nine:
785+ try f(c)
786+ loc = loc.successor()
787+
788+ default:
789+ break advancing
790+ }
791+ }
792+
793+ state = .Done
794+ }
795+}
796+
797+public extension JSONParser {
798+
799+ /// Creates a `JSONParser` ready to parse UTF-8 encoded `NSData`.
800+ ///
801+ /// If the data is mutable, it is copied before parsing. The data's lifetime
802+ /// is extended for the duration of parsing.
803+ init(utf8Data inData: NSData) {
804+ let data = inData.copy() as! NSData
805+ let buffer = UnsafeBufferPointer(start: UnsafePointer<UInt8>(data.bytes), count: data.length)
806+ self.init(buffer: buffer, owner: data)
807+ }
808+
809+ /// Creates a `JSONParser` from the code units represented by the `string`.
810+ ///
811+ /// The synthesized string is lifetime-extended for the duration of parsing.
812+ init(string: String) {
813+ let codePoints = string.nulTerminatedUTF8
814+ let buffer = codePoints.withUnsafeBufferPointer { nulTerminatedBuffer in
815+ // don't want to include the nul termination in the buffer - trim it off
816+ UnsafeBufferPointer(start: nulTerminatedBuffer.baseAddress, count: nulTerminatedBuffer.count - 1)
817+ }
818+ self.init(buffer: buffer, owner: codePoints)
819+ }
820+
821+}
822+
823+extension JSONParser: JSONParserType {
824+
825+ /// Creates an instance of `JSON` from UTF-8 encoded `NSData`.
826+ /// - parameter data: An instance of `NSData` to parse `JSON` from.
827+ /// - throws: Any `JSONParser.Error` that arises during decoding.
828+ /// - seealso: JSONParser.parse()
829+ public static func createJSONFromData(data: NSData) throws -> JSON {
830+ var parser = JSONParser(utf8Data: data)
831+ return try parser.parse()
832+ }
833+
834+}
835+
836+// MARK: - Errors
837+
838+extension JSONParser {
839+
840+ /// Enumeration describing possible errors that occur while parsing a JSON
841+ /// document. Most errors include an associated `offset`, representing the
842+ /// offset into the UTF-8 characters making up the document where the error
843+ /// occurred.
844+ public enum Error: ErrorType {
845+ /// The parser ran out of data prematurely. This usually means a value
846+ /// was not escaped, such as a string literal not ending with a double
847+ /// quote.
848+ case EndOfStreamUnexpected
849+
850+ /// Unexpected non-whitespace data was left around `offset` after
851+ /// parsing all valid JSON.
852+ case EndOfStreamGarbage(offset: Int)
853+
854+ /// Too many nested objects or arrays occured at the literal started
855+ /// around `offset`.
856+ case ExceededNestingLimit(offset: Int)
857+
858+ /// A `character` was not a valid start of a value around `offset`.
859+ case ValueInvalid(offset: Int, character: UnicodeScalar)
860+
861+ /// Badly-formed Unicode escape sequence at `offset`. A Unicode escape
862+ /// uses the text "\u" followed by 4 hex digits, such as "\uF09F\uA684"
863+ /// to represent U+1F984, "UNICORN FACE".
864+ case UnicodeEscapeInvalid(offset: Int)
865+
866+ /// Badly-formed control character around `offset`. JSON supports
867+ /// backslash-escaped double quotes, slashes, whitespace control codes,
868+ /// and Unicode escape sequences.
869+ case ControlCharacterUnrecognized(offset: Int)
870+
871+ /// Invalid token, expected `null` around `offset`
872+ case LiteralNilMisspelled(offset: Int)
873+
874+ /// Invalid token, expected `true` around `offset`
875+ case LiteralTrueMisspelled(offset: Int)
876+
877+ /// Invalid token, expected `false` around `offset`
878+ case LiteralFalseMisspelled(offset: Int)
879+
880+ /// Badly-formed collection at given `offset`, expected `,` or `:`
881+ case CollectionMissingSeparator(offset: Int)
882+
883+ /// While parsing an object literal, a value was found without a key
884+ /// around `offset`. The start of a string literal was expected.
885+ case DictionaryMissingKey(offset: Int)
886+
887+ /// Badly-formed number with no digits around `offset`. After a decimal
888+ /// point, a number must include some number of digits.
889+ case NumberMissingFractionalDigits(offset: Int)
890+
891+ /// Badly-formed number with symbols ("-" or "e") but no following
892+ /// digits around `offset`.
893+ case NumberSymbolMissingDigits(offset: Int)
894+
895+ /// Supplied data is encoded in an unsupported format.
896+ case InvalidUnicodeStreamEncoding(detectedEncoding: JSONEncodingDetector.Encoding)
897+ }
898+
899+ private enum InternalError: ErrorType {
900+ /// Attempted to parse an integer outside the range of [Int.min, Int.max]
901+ /// or a double outside the range of representable doubles. Note that
902+ /// for doubles, this could be an overflow or an underflow - we don't
903+ /// get enough information from Swift here to know which it is. The number
904+ /// causing the overflow/underflow began at `offset`.
905+ case NumberOverflow(offset: Int)
906+ }
907+}
tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSONParsing.swiftnew file+126
@@ -0,0 +1,126 @@
1+//
2+// JSONParsing.swift
3+// Freddy
4+//
5+// Created by Matthew D. Mathias on 3/17/15.
6+// Copyright © 2015 Big Nerd Ranch. All rights reserved.
7+//
8+
9+import Foundation
10+
11+// MARK: - Deserialize JSON
12+
13+/// Protocol describing a backend parser that can produce `JSON` from `NSData`.
14+public protocol JSONParserType {
15+
16+ /// Creates an instance of `JSON` from `NSData`.
17+ /// - parameter data: An instance of `NSData` to use to create `JSON`.
18+ /// - throws: An error that may arise from calling `JSONObjectWithData(_:options:)` on `NSJSONSerialization` with the given data.
19+ /// - returns: An instance of `JSON`.
20+ static func createJSONFromData(data: NSData) throws -> JSON
21+
22+}
23+
24+extension JSON {
25+
26+ /// Create `JSON` from UTF-8 `data`. By default, parses using the
27+ /// Swift-native `JSONParser` backend.
28+ public init(data: NSData, usingParser parser: JSONParserType.Type = JSONParser.self) throws {
29+ self = try parser.createJSONFromData(data)
30+ }
31+
32+ /// Create `JSON` from UTF-8 `string`.
33+ public init(jsonString: Swift.String, usingParser parser: JSONParserType.Type = JSONParser.self) throws {
34+ self = try parser.createJSONFromData((jsonString as NSString).dataUsingEncoding(NSUTF8StringEncoding) ?? NSData())
35+ }
36+}
37+
38+// MARK: - NSJSONSerialization
39+
40+extension NSJSONSerialization: JSONParserType {
41+
42+ // MARK: Decode NSData
43+
44+ /// Use the built-in, Objective-C based JSON parser to create `JSON`.
45+ /// - parameter data: An instance of `NSData`.
46+ /// - returns: An instance of `JSON`.
47+ /// - throws: An error that may arise if the `NSData` cannot be parsed into an object.
48+ public static func createJSONFromData(data: NSData) throws -> JSON {
49+ return makeJSON(try NSJSONSerialization.JSONObjectWithData(data, options: []))
50+ }
51+
52+ // MARK: Make JSON
53+
54+ /// Makes a `JSON` object by matching its argument to a case in the `JSON` enum.
55+ /// - parameter object: The instance of `AnyObject` returned from serializing the JSON.
56+ /// - returns: An instance of `JSON` matching the JSON given to the function.
57+ private static func makeJSON(object: AnyObject) -> JSON {
58+ switch object {
59+ case let n as NSNumber:
60+ let numberType = CFNumberGetType(n)
61+ switch numberType {
62+ case .CharType:
63+ return .Bool(n.boolValue)
64+
65+ case .ShortType, .IntType, .LongType, .CFIndexType, .NSIntegerType, .SInt8Type, .SInt16Type, .SInt32Type:
66+ return .Int(n.integerValue)
67+
68+ case .SInt64Type, .LongLongType /* overflows 32-bit Int */:
69+ #if /* 32-bit arch */ arch(arm) || arch(i386)
70+ // Why double, when the Freddy parser would bump to String?
71+ //
72+ // Returning Double avoids making the type depend on whether you're running
73+ // 32-bit or 64-bit code when using the NSJSONSerialization parser.
74+ // NSJSONSerialization appears to bump numbers larger than Int.max to Double on
75+ // 64-bit platforms but use .SInt64Type on 32-bit platforms.
76+ // If we returned a String here, you'd get a String value on 32-bit,
77+ // but a Double value on 64-bit. Instead, we return Double.
78+ //
79+ // This means that, if you switch parsers,
80+ // you'll have to switch from .double to .string for pulling out
81+ // overflowing values, but if you stick with a single parser,
82+ // you at least won't have architecture-dependent lookups!
83+ return .Double(n.doubleValue)
84+ #else
85+ return .Int(n.integerValue)
86+ #endif
87+
88+ case .Float32Type, .Float64Type, .FloatType, .DoubleType, .CGFloatType:
89+ return .Double(n.doubleValue)
90+ }
91+
92+ case let arr as [AnyObject]:
93+ return makeJSONArray(arr)
94+
95+ case let dict as [Swift.String: AnyObject]:
96+ return makeJSONDictionary(dict)
97+
98+ case let s as Swift.String:
99+ return .String(s)
100+
101+ default:
102+ return .Null
103+ }
104+ }
105+
106+ // MARK: Make a JSON Array
107+
108+ /// Makes a `JSON` array from the object passed in.
109+ /// - parameter jsonArray: The array to transform into a `JSON`.
110+ /// - returns: An instance of `JSON` matching the array.
111+ private static func makeJSONArray(jsonArray: [AnyObject]) -> JSON {
112+ return .Array(jsonArray.map(makeJSON))
113+ }
114+
115+ // MARK: Make a JSON Dictionary
116+
117+ /// Makes a `JSON` dictionary from the Cocoa dictionary passed in.
118+ /// - parameter jsonDict: The dictionary to transform into `JSON`.
119+ /// - returns: An instance of `JSON` matching the dictionary.
120+ private static func makeJSONDictionary(jsonDict: [Swift.String: AnyObject]) -> JSON {
121+ return JSON(jsonDict.lazy.map { (key, value) in
122+ (key, makeJSON(value))
123+ })
124+ }
125+
126+}
tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSONSerializing.swiftnew file+43
@@ -0,0 +1,43 @@
1+// Copyright (C) 2016 Big Nerd Ranch, Inc. Licensed under the MIT license WITHOUT ANY WARRANTY.
2+
3+import Foundation
4+
5+// MARK: - Serialize JSON
6+
7+extension JSON {
8+
9+ /// Attempt to serialize `JSON` into an `NSData`.
10+ /// - returns: A byte-stream containing the `JSON` ready for wire transfer.
11+ /// - throws: Errors that arise from `NSJSONSerialization`.
12+ /// - see: Foundation.NSJSONSerialization
13+ public func serialize() throws -> NSData {
14+ let obj: AnyObject = toNSJSONSerializationObject()
15+ return try NSJSONSerialization.dataWithJSONObject(obj, options: [])
16+ }
17+
18+ /// A function to help with the serialization of `JSON`.
19+ /// - returns: An `AnyObject` suitable for `NSJSONSerialization`'s use.
20+ private func toNSJSONSerializationObject() -> AnyObject {
21+ switch self {
22+ case .Array(let jsonArray):
23+ return jsonArray.map { $0.toNSJSONSerializationObject() }
24+ case .Dictionary(let jsonDictionary):
25+ var cocoaDictionary = Swift.Dictionary<Swift.String, AnyObject>(minimumCapacity: jsonDictionary.count)
26+ for (key, json) in jsonDictionary {
27+ cocoaDictionary[key] = json.toNSJSONSerializationObject()
28+ }
29+ return cocoaDictionary
30+ case .String(let str):
31+ return str
32+ case .Double(let num):
33+ return num
34+ case .Int(let int):
35+ return int
36+ case .Bool(let b):
37+ return b
38+ case .Null:
39+ return NSNull()
40+ }
41+
42+ }
43+}
tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/JSONSubscripting.swiftnew file+705
@@ -0,0 +1,705 @@
1+//
2+// JSONSubscripting.swift
3+// Freddy
4+//
5+// Created by Zachary Waldowski on 8/15/15.
6+// Copyright © 2015 Big Nerd Ranch. All rights reserved.
7+//
8+
9+// MARK: JSONPathType
10+
11+/// A protocol used to define a path within an instance of `JSON` that leads to some desired value.
12+///
13+/// A custom type, such as a `RawRepresentable` enum, may be made to conform to `JSONPathType`
14+/// and used with the subscript APIs.
15+public protocol JSONPathType {
16+ /// Use `self` to key into a `dictionary`.
17+ ///
18+ /// Unlike Swift dictionaries, failing to find a value for a key should throw
19+ /// an error rather than convert to `nil`.
20+ ///
21+ /// Upon failure, implementers should throw an error from `JSON.Error`.
22+ func valueInDictionary(dictionary: [Swift.String : JSON]) throws -> JSON
23+
24+ /// Use `self` to index into an `array`.
25+ ///
26+ /// Unlike Swift array, attempting to index outside the collection's bounds
27+ /// should throw an error rather than crash.
28+ ///
29+ /// Upon failure, implementers should throw an error from `JSON.Error`.
30+ func valueInArray(array: [JSON]) throws -> JSON
31+}
32+
33+extension JSONPathType {
34+
35+ /// The default behavior for keying into a dictionary is to throw
36+ /// `JSON.Error.UnexpectedSubscript`.
37+ public func valueInDictionary(dictionary: [Swift.String : JSON]) throws -> JSON {
38+ throw JSON.Error.UnexpectedSubscript(type: Self.self)
39+ }
40+
41+ /// The default behavior for indexing into an array is to throw
42+ /// `JSON.Error.UnexpectedSubscript`.
43+ public func valueInArray(array: [JSON]) throws -> JSON {
44+ throw JSON.Error.UnexpectedSubscript(type: Self.self)
45+ }
46+
47+}
48+
49+extension String: JSONPathType {
50+
51+ /// A method used to retrieve a value from a given dictionary for a specific key.
52+ /// - parameter dictionary: A `Dictionary` with `String` keys and `JSON` values.
53+ /// - throws: `.KeyNotFound` with an associated value of `self`, where `self` is a `String`,
54+ /// should the key not be present within the `JSON`.
55+ /// - returns: The `JSON` value associated with the given key.
56+ public func valueInDictionary(dictionary: [Swift.String : JSON]) throws -> JSON {
57+ guard let next = dictionary[self] else {
58+ throw JSON.Error.KeyNotFound(key: self)
59+ }
60+ return next
61+ }
62+
63+}
64+
65+extension Int: JSONPathType {
66+
67+ /// A method used to retrieve a value from a given array for a specific index.
68+ /// - parameter array: An `Array` of `JSON`.
69+ /// - throws: `.IndexOutOfBounds` with an associated value of `self`, where `self` is an `Int`,
70+ /// should the index not be within the valid range for the array of `JSON`.
71+ /// - returns: The `JSON` value found at the given index.
72+ public func valueInArray(array: [JSON]) throws -> JSON {
73+ guard case array.indices = self else {
74+ throw JSON.Error.IndexOutOfBounds(index: self)
75+ }
76+ return array[self]
77+ }
78+
79+}
80+
81+// MARK: - Subscripting core
82+
83+private extension JSON {
84+
85+ enum SubscriptError: ErrorType {
86+ case SubscriptIntoNull(JSONPathType)
87+ }
88+
89+ func valueForPathFragment(fragment: JSONPathType, detectNull: Swift.Bool) throws -> JSON {
90+ switch self {
91+ case .Null where detectNull:
92+ throw SubscriptError.SubscriptIntoNull(fragment)
93+ case let .Dictionary(dict):
94+ return try fragment.valueInDictionary(dict)
95+ case let .Array(array):
96+ return try fragment.valueInArray(array)
97+ default:
98+ throw Error.UnexpectedSubscript(type: fragment.dynamicType)
99+ }
100+ }
101+
102+ func valueAtPath(path: [JSONPathType], detectNull: Swift.Bool = false) throws -> JSON {
103+ var result = self
104+ for fragment in path {
105+ result = try result.valueForPathFragment(fragment, detectNull: detectNull)
106+ }
107+ return result
108+ }
109+
110+}
111+
112+// MARK: - Subscripting operator
113+
114+extension JSON {
115+
116+ public subscript(key: Swift.String) -> JSON? {
117+ return try? valueForPathFragment(key, detectNull: false)
118+ }
119+
120+ public subscript(index: Swift.Int) -> JSON? {
121+ return try? valueForPathFragment(index, detectNull: false)
122+ }
123+
124+}
125+
126+// MARK: - Simple member unpacking
127+
128+extension JSON {
129+
130+ /// Attempts to decode into the returning type from a path into JSON.
131+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`.
132+ /// - parameter type: If the context this method is called from does not
133+ /// make the return type clear, pass a type implementing `JSONDecodable`
134+ /// to disambiguate the type to decode with.
135+ /// - returns: An initialized member from the inner JSON.
136+ /// - throws: One of the following errors contained in `JSON.Error`:
137+ /// * `KeyNotFound`: A given `String` key does not exist inside a
138+ /// descendant `JSON` dictionary.
139+ /// * `IndexOutOfBounds`: A given `Int` index is outside the bounds of a
140+ /// descendant `JSON` array.
141+ /// * `UnexpectedSubscript`: A given subscript cannot be used with the
142+ /// corresponding `JSON` value.
143+ /// * `TypeNotConvertible`: The target value's type inside of
144+ /// the `JSON` instance does not match `Decoded`.
145+ public func decode<Decoded: JSONDecodable>(path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> Decoded {
146+ return try Decoded(json: valueAtPath(path))
147+ }
148+
149+ /// Retrieves a `Double` from a path into JSON.
150+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
151+ /// - returns: A floating-point `Double`
152+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
153+ /// - seealso: `JSON.decode(_:type:)`
154+ public func double(path: JSONPathType...) throws -> Swift.Double {
155+ return try Swift.Double(json: valueAtPath(path))
156+ }
157+
158+ /// Retrieves an `Int` from a path into JSON.
159+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
160+ /// - returns: A numeric `Int`
161+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
162+ /// - seealso: `JSON.decode(_:type:)`
163+ public func int(path: JSONPathType...) throws -> Swift.Int {
164+ return try Swift.Int(json: valueAtPath(path))
165+ }
166+
167+ /// Retrieves a `String` from a path into JSON.
168+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
169+ /// - returns: A textual `String`
170+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
171+ /// - seealso: `JSON.decode(_:type:)`
172+ public func string(path: JSONPathType...) throws -> Swift.String {
173+ return try Swift.String(json: valueAtPath(path))
174+ }
175+
176+ /// Retrieves a `Bool` from a path into JSON.
177+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
178+ /// - returns: A truthy `Bool`
179+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
180+ /// - seealso: `JSON.decode(_:type:)`
181+ public func bool(path: JSONPathType...) throws -> Swift.Bool {
182+ return try Swift.Bool(json: valueAtPath(path))
183+ }
184+
185+ /// Retrieves a `[JSON]` from a path into JSON.
186+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
187+ /// - returns: An `Array` of `JSON` elements
188+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
189+ /// - seealso: `JSON.decode(_:type:)`
190+ public func array(path: JSONPathType...) throws -> [JSON] {
191+ return try JSON.getArray(valueAtPath(path))
192+ }
193+
194+ /// Attempts to decode many values from a descendant JSON array at a path
195+ /// into JSON.
196+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
197+ /// - parameter type: If the context this method is called from does not
198+ /// make the return type clear, pass a type implementing `JSONDecodable`
199+ /// to disambiguate the type to decode with.
200+ /// - returns: An `Array` of decoded elements
201+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`, or
202+ /// any error that arises from decoding the contained values.
203+ /// - seealso: `JSON.decode(_:type:)`
204+ public func arrayOf<Decoded: JSONDecodable>(path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> [Decoded] {
205+ return try JSON.getArrayOf(valueAtPath(path))
206+ }
207+
208+ /// Retrieves a `[String: JSON]` from a path into JSON.
209+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
210+ /// - returns: An `Dictionary` of `String` mapping to `JSON` elements
211+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
212+ /// - seealso: `JSON.decode(_:type:)`
213+ public func dictionary(path: JSONPathType...) throws -> [Swift.String: JSON] {
214+ return try JSON.getDictionary(valueAtPath(path))
215+ }
216+
217+ /// Attempts to decode many values from a descendant JSON object at a path
218+ /// into JSON.
219+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
220+ /// - parameter type: If the context this method is called from does not
221+ /// make the return type clear, pass a type implementing `JSONDecodable`
222+ /// to disambiguate the value type to decode with.
223+ /// - returns: A `Dictionary` of `String` keys and decoded values.
224+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)` or
225+ /// any error that arises from decoding the contained values.
226+ /// - seealso: `JSON.decode(_:type:)`
227+ public func dictionaryOf<Decoded: JSONDecodable>(path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> [Swift.String: Decoded] {
228+ return try JSON.getDictionaryOf(valueAtPath(path))
229+ }
230+
231+}
232+
233+// MARK: - NotFound-Or-Null-to-Optional unpacking
234+
235+extension JSON {
236+
237+ /// An `OptionSetType` used to represent the different options available for subscripting `JSON` with `null` values or missing keys.
238+ /// * `.NullBecomesNil` - Treat `null` values as `nil`.
239+ /// * `.MissingKeyBecomesNil` - Treat missing keys as `nil`.
240+ public struct SubscriptingOptions: OptionSetType {
241+ public let rawValue: Swift.Int
242+ public init(rawValue: Swift.Int) {
243+ self.rawValue = rawValue
244+ }
245+
246+ /// Treat `null` values as `nil`.
247+ public static let NullBecomesNil = SubscriptingOptions(rawValue: 1 << 0)
248+ /// Treat missing keys as `nil`.
249+ public static let MissingKeyBecomesNil = SubscriptingOptions(rawValue: 1 << 1)
250+ }
251+
252+ private func mapOptionalAtPath<Value>(path: [JSONPathType], alongPath: SubscriptingOptions, @noescape transform: JSON throws -> Value) throws -> Value? {
253+ let detectNull = alongPath.contains(.NullBecomesNil)
254+ let detectNotFound = alongPath.contains(.MissingKeyBecomesNil)
255+ var json: JSON?
256+ do {
257+ json = try valueAtPath(path, detectNull: detectNull)
258+ return try json.map(transform)
259+ } catch Error.IndexOutOfBounds where detectNotFound {
260+ return nil
261+ } catch Error.KeyNotFound where detectNotFound {
262+ return nil
263+ } catch Error.ValueNotConvertible where detectNull && json == .Null {
264+ return nil
265+ } catch SubscriptError.SubscriptIntoNull where detectNull {
266+ return nil
267+ }
268+ }
269+}
270+
271+extension JSON {
272+
273+ /// Optionally decodes into the returning type from a path into JSON.
274+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
275+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
276+ /// - parameter type: If the context this method is called from does not
277+ /// make the return type clear, pass a type implementing `JSONDecodable`
278+ /// to disambiguate the type to decode with.
279+ /// - returns: A decoded value from the inner JSON if found, or `nil`.
280+ /// - throws: One of the following errors contained in `JSON.Error`:
281+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
282+ /// `JSON` dictionary.
283+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
284+ /// descendant `JSON` array.
285+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
286+ /// corresponding `JSON` value.
287+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
288+ /// instance does not match the decoded value.
289+ /// * Any error that arises from decoding the value.
290+ public func decode<Decoded: JSONDecodable>(path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> Decoded? {
291+ return try mapOptionalAtPath(path, alongPath: options, transform: Decoded.init)
292+ }
293+
294+ /// Optionally retrieves a `Double` from a path into JSON.
295+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`.
296+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
297+ /// - returns: A `Double` if a value could be found, otherwise `nil`.
298+ /// - throws: One of the following errors contained in `JSON.Error`:
299+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
300+ /// `JSON` dictionary.
301+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
302+ /// descendant `JSON` array.
303+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
304+ /// corresponding `JSON` value.
305+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
306+ /// instance does not match the decoded value.
307+ public func double(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Swift.Double? {
308+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Double.init)
309+ }
310+
311+ /// Optionally retrieves a `Int` from a path into JSON.
312+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
313+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
314+ /// - returns: A numeric `Int` if a value could be found, otherwise `nil`.
315+ /// - throws: One of the following errors contained in `JSON.Error`:
316+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
317+ /// `JSON` dictionary.
318+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
319+ /// descendant `JSON` array.
320+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
321+ /// corresponding `JSON` value.
322+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
323+ /// instance does not match the decoded value.
324+ public func int(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Swift.Int? {
325+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Int.init)
326+ }
327+
328+ /// Optionally retrieves a `String` from a path into JSON.
329+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
330+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
331+ /// - returns: A text `String` if a value could be found, otherwise `nil`.
332+ /// - throws: One of the following errors contained in `JSON.Error`:
333+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
334+ /// `JSON` dictionary.
335+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
336+ /// descendant `JSON` array.
337+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
338+ /// corresponding `JSON` value.
339+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
340+ /// instance does not match the decoded value.
341+ public func string(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Swift.String? {
342+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.String.init)
343+ }
344+
345+ /// Optionally retrieves a `Bool` from a path into JSON.
346+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
347+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
348+ /// - returns: A truthy `Bool` if a value could be found, otherwise `nil`.
349+ /// - throws: One of the following errors contained in `JSON.Error`:
350+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
351+ /// `JSON` dictionary.
352+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
353+ /// descendant `JSON` array.
354+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
355+ /// corresponding `JSON` value.
356+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
357+ /// instance does not match the decoded value.
358+ public func bool(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Swift.Bool? {
359+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Bool.init)
360+ }
361+
362+ /// Optionally retrieves a `[JSON]` from a path into the recieving structure.
363+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
364+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
365+ /// - returns: An `Array` of `JSON` elements if a value could be found,
366+ /// otherwise `nil`.
367+ /// - throws: One of the following errors contained in `JSON.Error`:
368+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
369+ /// `JSON` dictionary.
370+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
371+ /// descendant `JSON` array.
372+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
373+ /// corresponding `JSON` value.
374+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
375+ /// instance does not match the decoded value.
376+ public func array(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> [JSON]? {
377+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArray)
378+ }
379+
380+ /// Optionally decodes many values from a descendant array at a path into
381+ /// JSON.
382+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
383+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
384+ /// - parameter type: If the context this method is called from does not
385+ /// make the return type clear, pass a type implementing `JSONDecodable`
386+ /// to disambiguate the value type to decode with.
387+ /// - returns: An `Array` of decoded elements if found, otherwise `nil`.
388+ /// - throws: One of the following errors contained in `JSON.Error`:
389+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
390+ /// `JSON` dictionary.
391+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
392+ /// descendant `JSON` array.
393+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
394+ /// corresponding `JSON` value.
395+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
396+ /// instance does not match the decoded value.
397+ /// * Any error that arises from decoding the value.
398+ public func arrayOf<Decoded: JSONDecodable>(path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> [Decoded]? {
399+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArrayOf)
400+ }
401+
402+ /// Optionally retrieves a `[String: JSON]` from a path into the recieving
403+ /// structure.
404+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
405+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
406+ /// - returns: A `Dictionary` of `String` mapping to `JSON` elements if a
407+ /// value could be found, otherwise `nil`.
408+ /// - throws: One of the following errors contained in `JSON.Error`:
409+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
410+ /// `JSON` dictionary.
411+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
412+ /// descendant `JSON` array.
413+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
414+ /// corresponding `JSON` value.
415+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
416+ /// instance does not match the decoded value.
417+ public func dictionary(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> [Swift.String: JSON]? {
418+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getDictionary)
419+ }
420+
421+ /// Optionally attempts to decode many values from a descendant object at a path
422+ /// into JSON.
423+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
424+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
425+ /// - parameter type: If the context this method is called from does not
426+ /// make the return type clear, pass a type implementing `JSONDecodable`
427+ /// to disambiguate the value type to decode with.
428+ /// - returns: A `Dictionary` of `String` mapping to decoded elements if a
429+ /// value could be found, otherwise `nil`.
430+ /// - throws: One of the following errors contained in `JSON.Error`:
431+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
432+ /// `JSON` dictionary.
433+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
434+ /// descendant `JSON` array.
435+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
436+ /// corresponding `JSON` value.
437+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
438+ /// instance does not match the decoded value.
439+ /// * Any error that arises from decoding the value.
440+ public func dictionaryOf<Decoded: JSONDecodable>(path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> [Swift.String: Decoded]? {
441+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getDictionaryOf)
442+ }
443+
444+}
445+
446+// MARK: - Missing-with-fallback unpacking
447+
448+extension JSON {
449+
450+ private func mapOptionalAtPath<Value>(path: [JSONPathType], @noescape fallback: () -> Value, @noescape transform: JSON throws -> Value) throws -> Value {
451+ return try mapOptionalAtPath(path, alongPath: .MissingKeyBecomesNil, transform: transform) ?? fallback()
452+ }
453+
454+ /// Attempts to decode into the returning type from a path into
455+ /// JSON, or returns a fallback if not found.
456+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
457+ /// - parameter fallback: Value to use when one is missing at the subscript.
458+ /// - returns: An initialized member from the inner JSON.
459+ /// - throws: One of the following errors contained in `JSON.Error`:
460+ /// * `UnexpectedSubscript`: A given subscript cannot be used with the
461+ /// corresponding `JSON` value.
462+ /// * `TypeNotConvertible`: The target value's type inside of
463+ /// the `JSON` instance does not match `Decoded`.
464+ public func decode<Decoded: JSONDecodable>(path: JSONPathType..., @autoclosure or fallback: () -> Decoded) throws -> Decoded {
465+ return try mapOptionalAtPath(path, fallback: fallback, transform: Decoded.init)
466+ }
467+
468+ /// Retrieves a `Double` from a path into JSON or a fallback if not found.
469+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
470+ /// - parameter fallback: `Double` to use when one is missing at the subscript.
471+ /// - returns: A floating-point `Double`
472+ /// - throws: One of the `JSON.Error` cases thrown by calling `mapOptionalAtPath(_:fallback:transform:)`.
473+ /// - seealso: `optionalAtPath(_:ifNotFound)`.
474+ public func double(path: JSONPathType..., @autoclosure or fallback: () -> Swift.Double) throws -> Swift.Double {
475+ return try mapOptionalAtPath(path, fallback: fallback, transform: Swift.Double.init)
476+ }
477+
478+ /// Retrieves an `Int` from a path into JSON or a fallback if not found.
479+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
480+ /// - parameter fallback: `Int` to use when one is missing at the subscript.
481+ /// - returns: A numeric `Int`
482+ /// - throws: One of the following errors contained in `JSON.Error`:
483+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
484+ /// `JSON` dictionary.
485+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
486+ /// descendant `JSON` array.
487+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
488+ /// corresponding `JSON` value.
489+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
490+ /// instance does not match the decoded value.
491+ public func int(path: JSONPathType..., @autoclosure or fallback: () -> Swift.Int) throws -> Swift.Int {
492+ return try mapOptionalAtPath(path, fallback: fallback, transform: Swift.Int.init)
493+ }
494+
495+ /// Retrieves a `String` from a path into JSON or a fallback if not found.
496+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
497+ /// - parameter fallback: `String` to use when one is missing at the subscript.
498+ /// - returns: A textual `String`
499+ /// - throws: One of the following errors contained in `JSON.Error`:
500+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
501+ /// `JSON` dictionary.
502+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
503+ /// descendant `JSON` array.
504+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
505+ /// corresponding `JSON` value.
506+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
507+ /// instance does not match the decoded value.
508+ public func string(path: JSONPathType..., @autoclosure or fallback: () -> Swift.String) throws -> Swift.String {
509+ return try mapOptionalAtPath(path, fallback: fallback, transform: Swift.String.init)
510+ }
511+
512+ /// Retrieves a `Bool` from a path into JSON or a fallback if not found.
513+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
514+ /// - parameter fallback: `Bool` to use when one is missing at the subscript.
515+ /// - returns: A truthy `Bool`
516+ /// - throws: One of the following errors contained in `JSON.Error`:
517+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
518+ /// `JSON` dictionary.
519+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
520+ /// descendant `JSON` array.
521+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
522+ /// corresponding `JSON` value.
523+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
524+ /// instance does not match the decoded value.
525+ public func bool(path: JSONPathType..., @autoclosure or fallback: () -> Swift.Bool) throws -> Swift.Bool {
526+ return try mapOptionalAtPath(path, fallback: fallback, transform: Swift.Bool.init)
527+ }
528+
529+ /// Retrieves a `[JSON]` from a path into JSON or a fallback if not found.
530+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
531+ /// - parameter fallback: `Array` to use when one is missing at the subscript.
532+ /// - returns: An `Array` of `JSON` elements
533+ /// - throws: One of the following errors contained in `JSON.Error`:
534+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
535+ /// `JSON` dictionary.
536+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
537+ /// descendant `JSON` array.
538+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
539+ /// corresponding `JSON` value.
540+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
541+ /// instance does not match the decoded value.
542+ public func array(path: JSONPathType..., @autoclosure or fallback: () -> [JSON]) throws -> [JSON] {
543+ return try mapOptionalAtPath(path, fallback: fallback, transform: JSON.getArray)
544+ }
545+
546+ /// Attempts to decodes many values from a desendant JSON array at a path
547+ /// into the recieving structure, returning a fallback if not found.
548+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
549+ /// - parameter fallback: `Array` to use when one is missing at the subscript.
550+ /// - returns: An `Array` of decoded elements
551+ /// - throws: One of the following errors contained in `JSON.Error`:
552+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
553+ /// `JSON` dictionary.
554+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
555+ /// descendant `JSON` array.
556+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
557+ /// corresponding `JSON` value.
558+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
559+ /// instance does not match the decoded value.
560+ /// * Any error that arises from decoding the value.
561+ public func arrayOf<Decoded: JSONDecodable>(path: JSONPathType..., @autoclosure or fallback: () -> [Decoded]) throws -> [Decoded] {
562+ return try mapOptionalAtPath(path, fallback: fallback, transform: JSON.getArrayOf)
563+ }
564+
565+ /// Retrieves a `[String: JSON]` from a path into JSON or a fallback if not
566+ /// found.
567+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
568+ /// - parameter fallback: `Dictionary` to use when one is missing at the subscript.
569+ /// - returns: An `Dictionary` of `String` mapping to `JSON` elements
570+ /// - throws: One of the following errors contained in `JSON.Error`:
571+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
572+ /// `JSON` dictionary.
573+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
574+ /// descendant `JSON` array.
575+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
576+ /// corresponding `JSON` value.
577+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
578+ /// instance does not match the decoded value.
579+ public func dictionary(path: JSONPathType..., @autoclosure or fallback: () -> [Swift.String: JSON]) throws -> [Swift.String: JSON] {
580+ return try mapOptionalAtPath(path, fallback: fallback, transform: JSON.getDictionary)
581+ }
582+
583+ /// Attempts to decode many values from a descendant JSON object at a path
584+ /// into the receiving structure, returning a fallback if not found.
585+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
586+ /// - parameter fallback: Value to use when one is missing at the subscript
587+ /// - returns: A `Dictionary` of `String` mapping to decoded elements.
588+ /// - throws: One of the following errors contained in `JSON.Error`:
589+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
590+ /// `JSON` dictionary.
591+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
592+ /// descendant `JSON` array.
593+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
594+ /// corresponding `JSON` value.
595+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
596+ /// instance does not match the decoded value.
597+ /// * Any error that arises from decoding the value.
598+ public func dictionaryOf<Decoded: JSONDecodable>(path: JSONPathType..., @autoclosure or fallback: () -> [Swift.String: Decoded]) throws -> [Swift.String: Decoded] {
599+ return try mapOptionalAtPath(path, fallback: fallback, transform: JSON.getDictionaryOf)
600+ }
601+
602+
603+}
604+
605+// MARK: - Deprecated methods
606+
607+extension JSON {
608+
609+ @available(*, deprecated, message="Use 'decode(_:alongPath:type:)' with options '[.MissingKeyBecomesNil]'")
610+ public func decode<Decoded: JSONDecodable>(path: JSONPathType..., ifNotFound: Swift.Bool, type: Decoded.Type = Decoded.self) throws -> Decoded? {
611+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
612+ return try mapOptionalAtPath(path, alongPath: options, transform: Decoded.init)
613+ }
614+
615+ @available(*, deprecated, message="Use 'decode(_:alongPath:type:)' with options '[.NullBecomesNil]'")
616+ public func decode<Decoded: JSONDecodable>(path: JSONPathType..., ifNull: Swift.Bool, type: Decoded.Type = Decoded.self) throws -> Decoded? {
617+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
618+ return try mapOptionalAtPath(path, alongPath: options, transform: Decoded.init)
619+ }
620+
621+ @available(*, deprecated, message="Use 'double(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
622+ public func double(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> Swift.Double? {
623+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
624+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Double.init)
625+ }
626+
627+ @available(*, deprecated, message="Use 'double(_:alongPath:)' with options '[.NullBecomesNil]'")
628+ public func double(path: JSONPathType..., ifNull: Swift.Bool) throws -> Swift.Double? {
629+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
630+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Double.init)
631+ }
632+
633+ @available(*, deprecated, message="Use 'int(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
634+ public func int(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> Swift.Int? {
635+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
636+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Int.init)
637+ }
638+
639+ @available(*, deprecated, message="Use 'int(_:alongPath:)' with options '[.NullBecomesNil]'")
640+ public func int(path: JSONPathType..., ifNull: Swift.Bool) throws -> Swift.Int? {
641+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
642+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Int.init)
643+ }
644+
645+ @available(*, deprecated, message="Use 'string(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
646+ public func string(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> Swift.String? {
647+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
648+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.String.init)
649+ }
650+
651+ @available(*, deprecated, message="Use 'string(_:alongPath:)' with options '[.NullBecomesNil]'")
652+ public func string(path: JSONPathType..., ifNull: Swift.Bool) throws -> Swift.String? {
653+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
654+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.String.init)
655+ }
656+
657+ @available(*, deprecated, message="Use 'bool(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
658+ public func bool(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> Swift.Bool? {
659+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
660+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Bool.init)
661+ }
662+
663+ @available(*, deprecated, message="Use 'bool(_:alongPath:)' with options '[.NullBecomesNil]'")
664+ public func bool(path: JSONPathType..., ifNull: Swift.Bool) throws -> Swift.Bool? {
665+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
666+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Bool.init)
667+ }
668+
669+ @available(*, deprecated, message="Use 'array(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
670+ public func array(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> [JSON]? {
671+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
672+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArray)
673+ }
674+
675+ @available(*, deprecated, message="Use 'array(_:alongPath:)' with options '[.NullBecomesNil]'")
676+ public func array(path: JSONPathType..., ifNull: Swift.Bool) throws -> [JSON]? {
677+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
678+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArray)
679+ }
680+
681+ @available(*, deprecated, message="Use 'arrayOf(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
682+ public func arrayOf<Decoded: JSONDecodable>(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> [Decoded]? {
683+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
684+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArrayOf)
685+ }
686+
687+ @available(*, deprecated, message="Use 'arrayOf(_:alongPath:)' with options '[.NullBecomesNil]'")
688+ public func arrayOf<Decoded: JSONDecodable>(path: JSONPathType..., ifNull: Swift.Bool) throws -> [Decoded]? {
689+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
690+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArrayOf)
691+ }
692+
693+ @available(*, deprecated, message="Use 'dictionary(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
694+ public func dictionary(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> [Swift.String: JSON]? {
695+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
696+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getDictionary)
697+ }
698+
699+ @available(*, deprecated, message="Use 'dictionary(_:alongPath:)' with options '[.NullBecomesNil]'")
700+ public func dictionary(path: JSONPathType..., ifNull: Swift.Bool) throws -> [Swift.String: JSON]? {
701+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
702+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getDictionary)
703+ }
704+
705+}
tests/JSONTestSuite/parsers/test_Freddy_20160830/test_Freddy/main.swiftnew file+37
@@ -0,0 +1,37 @@
1+//
2+// main.swift
3+// test_Freddy
4+//
5+// Created by nst on 10/08/16.
6+// Copyright © 2016 Nicolas Seriot. All rights reserved.
7+//
8+
9+import Foundation
10+
11+func main() {
12+
13+ guard Process.arguments.count == 2 else {
14+ let url = NSURL(fileURLWithPath: Process.arguments[0])
15+ guard let programName = url.lastPathComponent else { exit(1) }
16+ print("Usage: ./\(programName) file.json")
17+ exit(1)
18+ }
19+
20+ let path = Process.arguments[1]
21+ let url = NSURL.fileURLWithPath(path)
22+
23+ guard let data = NSData(contentsOfURL:url) else {
24+ print("*** CANNOT READ DATA AT \(url)")
25+ return
26+ }
27+
28+ var p = JSONParser(utf8Data: data)
29+ do {
30+ try p.parse()
31+ exit(0)
32+ } catch {
33+ exit(1)
34+ }
35+}
36+
37+main()
tests/JSONTestSuite/parsers/test_Freddy_20161018/bin/test_Freddynew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy.xcodeproj/project.pbxprojnew file+300
@@ -0,0 +1,300 @@
1+// !$*UTF8*$!
2+{
3+ archiveVersion = 1;
4+ classes = {
5+ };
6+ objectVersion = 46;
7+ objects = {
8+
9+/* Begin PBXBuildFile section */
10+ 03D84ABB1D5B0A1000776402 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03D84ABA1D5B0A1000776402 /* main.swift */; };
11+ 03F8F7811D5B75600021630C /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F7781D5B75600021630C /* JSON.swift */; };
12+ 03F8F7821D5B75600021630C /* JSONDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F7791D5B75600021630C /* JSONDecodable.swift */; };
13+ 03F8F7831D5B75600021630C /* JSONEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77A1D5B75600021630C /* JSONEncodable.swift */; };
14+ 03F8F7841D5B75600021630C /* JSONEncodingDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77B1D5B75600021630C /* JSONEncodingDetector.swift */; };
15+ 03F8F7851D5B75600021630C /* JSONLiteralConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77C1D5B75600021630C /* JSONLiteralConvertible.swift */; };
16+ 03F8F7861D5B75600021630C /* JSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77D1D5B75600021630C /* JSONParser.swift */; };
17+ 03F8F7871D5B75600021630C /* JSONParsing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77E1D5B75600021630C /* JSONParsing.swift */; };
18+ 03F8F7881D5B75600021630C /* JSONSerializing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77F1D5B75600021630C /* JSONSerializing.swift */; };
19+ 03F8F7891D5B75600021630C /* JSONSubscripting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F7801D5B75600021630C /* JSONSubscripting.swift */; };
20+/* End PBXBuildFile section */
21+
22+/* Begin PBXCopyFilesBuildPhase section */
23+ 03D84AB51D5B0A1000776402 /* CopyFiles */ = {
24+ isa = PBXCopyFilesBuildPhase;
25+ buildActionMask = 2147483647;
26+ dstPath = /usr/share/man/man1;
27+ dstSubfolderSpec = 0;
28+ files = (
29+ );
30+ runOnlyForDeploymentPostprocessing = 1;
31+ };
32+/* End PBXCopyFilesBuildPhase section */
33+
34+/* Begin PBXFileReference section */
35+ 03D84AB71D5B0A1000776402 /* test_Freddy */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_Freddy; sourceTree = BUILT_PRODUCTS_DIR; };
36+ 03D84ABA1D5B0A1000776402 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
37+ 03F8F7781D5B75600021630C /* JSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSON.swift; path = test_Freddy/JSON.swift; sourceTree = "<group>"; };
38+ 03F8F7791D5B75600021630C /* JSONDecodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONDecodable.swift; path = test_Freddy/JSONDecodable.swift; sourceTree = "<group>"; };
39+ 03F8F77A1D5B75600021630C /* JSONEncodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONEncodable.swift; path = test_Freddy/JSONEncodable.swift; sourceTree = "<group>"; };
40+ 03F8F77B1D5B75600021630C /* JSONEncodingDetector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONEncodingDetector.swift; path = test_Freddy/JSONEncodingDetector.swift; sourceTree = "<group>"; };
41+ 03F8F77C1D5B75600021630C /* JSONLiteralConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONLiteralConvertible.swift; path = test_Freddy/JSONLiteralConvertible.swift; sourceTree = "<group>"; };
42+ 03F8F77D1D5B75600021630C /* JSONParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONParser.swift; path = test_Freddy/JSONParser.swift; sourceTree = "<group>"; };
43+ 03F8F77E1D5B75600021630C /* JSONParsing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONParsing.swift; path = test_Freddy/JSONParsing.swift; sourceTree = "<group>"; };
44+ 03F8F77F1D5B75600021630C /* JSONSerializing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONSerializing.swift; path = test_Freddy/JSONSerializing.swift; sourceTree = "<group>"; };
45+ 03F8F7801D5B75600021630C /* JSONSubscripting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONSubscripting.swift; path = test_Freddy/JSONSubscripting.swift; sourceTree = "<group>"; };
46+/* End PBXFileReference section */
47+
48+/* Begin PBXFrameworksBuildPhase section */
49+ 03D84AB41D5B0A1000776402 /* Frameworks */ = {
50+ isa = PBXFrameworksBuildPhase;
51+ buildActionMask = 2147483647;
52+ files = (
53+ );
54+ runOnlyForDeploymentPostprocessing = 0;
55+ };
56+/* End PBXFrameworksBuildPhase section */
57+
58+/* Begin PBXGroup section */
59+ 03D84AAE1D5B0A1000776402 = {
60+ isa = PBXGroup;
61+ children = (
62+ 03F8F7781D5B75600021630C /* JSON.swift */,
63+ 03F8F7791D5B75600021630C /* JSONDecodable.swift */,
64+ 03F8F77A1D5B75600021630C /* JSONEncodable.swift */,
65+ 03F8F77B1D5B75600021630C /* JSONEncodingDetector.swift */,
66+ 03F8F77C1D5B75600021630C /* JSONLiteralConvertible.swift */,
67+ 03F8F77D1D5B75600021630C /* JSONParser.swift */,
68+ 03F8F77E1D5B75600021630C /* JSONParsing.swift */,
69+ 03F8F77F1D5B75600021630C /* JSONSerializing.swift */,
70+ 03F8F7801D5B75600021630C /* JSONSubscripting.swift */,
71+ 03D84AB91D5B0A1000776402 /* test_Freddy */,
72+ 03D84AB81D5B0A1000776402 /* Products */,
73+ );
74+ sourceTree = "<group>";
75+ };
76+ 03D84AB81D5B0A1000776402 /* Products */ = {
77+ isa = PBXGroup;
78+ children = (
79+ 03D84AB71D5B0A1000776402 /* test_Freddy */,
80+ );
81+ name = Products;
82+ sourceTree = "<group>";
83+ };
84+ 03D84AB91D5B0A1000776402 /* test_Freddy */ = {
85+ isa = PBXGroup;
86+ children = (
87+ 03D84ABA1D5B0A1000776402 /* main.swift */,
88+ );
89+ path = test_Freddy;
90+ sourceTree = "<group>";
91+ };
92+/* End PBXGroup section */
93+
94+/* Begin PBXNativeTarget section */
95+ 03D84AB61D5B0A1000776402 /* test_Freddy */ = {
96+ isa = PBXNativeTarget;
97+ buildConfigurationList = 03D84ABE1D5B0A1000776402 /* Build configuration list for PBXNativeTarget "test_Freddy" */;
98+ buildPhases = (
99+ 03D84AB31D5B0A1000776402 /* Sources */,
100+ 03D84AB41D5B0A1000776402 /* Frameworks */,
101+ 03D84AB51D5B0A1000776402 /* CopyFiles */,
102+ );
103+ buildRules = (
104+ );
105+ dependencies = (
106+ );
107+ name = test_Freddy;
108+ productName = test_Freddy;
109+ productReference = 03D84AB71D5B0A1000776402 /* test_Freddy */;
110+ productType = "com.apple.product-type.tool";
111+ };
112+/* End PBXNativeTarget section */
113+
114+/* Begin PBXProject section */
115+ 03D84AAF1D5B0A1000776402 /* Project object */ = {
116+ isa = PBXProject;
117+ attributes = {
118+ LastSwiftUpdateCheck = 0800;
119+ LastUpgradeCheck = 0800;
120+ ORGANIZATIONNAME = "Nicolas Seriot";
121+ TargetAttributes = {
122+ 03D84AB61D5B0A1000776402 = {
123+ CreatedOnToolsVersion = 8.0;
124+ DevelopmentTeam = VBYRKYS73S;
125+ DevelopmentTeamName = "Nicolas Seriot";
126+ ProvisioningStyle = Automatic;
127+ };
128+ };
129+ };
130+ buildConfigurationList = 03D84AB21D5B0A1000776402 /* Build configuration list for PBXProject "test_Freddy" */;
131+ compatibilityVersion = "Xcode 3.2";
132+ developmentRegion = English;
133+ hasScannedForEncodings = 0;
134+ knownRegions = (
135+ en,
136+ );
137+ mainGroup = 03D84AAE1D5B0A1000776402;
138+ productRefGroup = 03D84AB81D5B0A1000776402 /* Products */;
139+ projectDirPath = "";
140+ projectRoot = "";
141+ targets = (
142+ 03D84AB61D5B0A1000776402 /* test_Freddy */,
143+ );
144+ };
145+/* End PBXProject section */
146+
147+/* Begin PBXSourcesBuildPhase section */
148+ 03D84AB31D5B0A1000776402 /* Sources */ = {
149+ isa = PBXSourcesBuildPhase;
150+ buildActionMask = 2147483647;
151+ files = (
152+ 03F8F7881D5B75600021630C /* JSONSerializing.swift in Sources */,
153+ 03F8F7821D5B75600021630C /* JSONDecodable.swift in Sources */,
154+ 03F8F7851D5B75600021630C /* JSONLiteralConvertible.swift in Sources */,
155+ 03F8F7871D5B75600021630C /* JSONParsing.swift in Sources */,
156+ 03F8F7861D5B75600021630C /* JSONParser.swift in Sources */,
157+ 03F8F7831D5B75600021630C /* JSONEncodable.swift in Sources */,
158+ 03D84ABB1D5B0A1000776402 /* main.swift in Sources */,
159+ 03F8F7811D5B75600021630C /* JSON.swift in Sources */,
160+ 03F8F7891D5B75600021630C /* JSONSubscripting.swift in Sources */,
161+ 03F8F7841D5B75600021630C /* JSONEncodingDetector.swift in Sources */,
162+ );
163+ runOnlyForDeploymentPostprocessing = 0;
164+ };
165+/* End PBXSourcesBuildPhase section */
166+
167+/* Begin XCBuildConfiguration section */
168+ 03D84ABC1D5B0A1000776402 /* Debug */ = {
169+ isa = XCBuildConfiguration;
170+ buildSettings = {
171+ ALWAYS_SEARCH_USER_PATHS = NO;
172+ CLANG_ANALYZER_NONNULL = YES;
173+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
174+ CLANG_CXX_LIBRARY = "libc++";
175+ CLANG_ENABLE_MODULES = YES;
176+ CLANG_ENABLE_OBJC_ARC = YES;
177+ CLANG_WARN_BOOL_CONVERSION = YES;
178+ CLANG_WARN_CONSTANT_CONVERSION = YES;
179+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
180+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
181+ CLANG_WARN_EMPTY_BODY = YES;
182+ CLANG_WARN_ENUM_CONVERSION = YES;
183+ CLANG_WARN_INT_CONVERSION = YES;
184+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
185+ CLANG_WARN_UNREACHABLE_CODE = YES;
186+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
187+ CODE_SIGN_IDENTITY = "-";
188+ COPY_PHASE_STRIP = NO;
189+ DEBUG_INFORMATION_FORMAT = dwarf;
190+ ENABLE_STRICT_OBJC_MSGSEND = YES;
191+ ENABLE_TESTABILITY = YES;
192+ GCC_C_LANGUAGE_STANDARD = gnu99;
193+ GCC_DYNAMIC_NO_PIC = NO;
194+ GCC_NO_COMMON_BLOCKS = YES;
195+ GCC_OPTIMIZATION_LEVEL = 0;
196+ GCC_PREPROCESSOR_DEFINITIONS = (
197+ "DEBUG=1",
198+ "$(inherited)",
199+ );
200+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
201+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
202+ GCC_WARN_UNDECLARED_SELECTOR = YES;
203+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
204+ GCC_WARN_UNUSED_FUNCTION = YES;
205+ GCC_WARN_UNUSED_VARIABLE = YES;
206+ MACOSX_DEPLOYMENT_TARGET = 10.11;
207+ MTL_ENABLE_DEBUG_INFO = YES;
208+ ONLY_ACTIVE_ARCH = YES;
209+ SDKROOT = macosx;
210+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
211+ };
212+ name = Debug;
213+ };
214+ 03D84ABD1D5B0A1000776402 /* Release */ = {
215+ isa = XCBuildConfiguration;
216+ buildSettings = {
217+ ALWAYS_SEARCH_USER_PATHS = NO;
218+ CLANG_ANALYZER_NONNULL = YES;
219+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
220+ CLANG_CXX_LIBRARY = "libc++";
221+ CLANG_ENABLE_MODULES = YES;
222+ CLANG_ENABLE_OBJC_ARC = YES;
223+ CLANG_WARN_BOOL_CONVERSION = YES;
224+ CLANG_WARN_CONSTANT_CONVERSION = YES;
225+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
226+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
227+ CLANG_WARN_EMPTY_BODY = YES;
228+ CLANG_WARN_ENUM_CONVERSION = YES;
229+ CLANG_WARN_INT_CONVERSION = YES;
230+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
231+ CLANG_WARN_UNREACHABLE_CODE = YES;
232+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
233+ CODE_SIGN_IDENTITY = "-";
234+ COPY_PHASE_STRIP = NO;
235+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
236+ ENABLE_NS_ASSERTIONS = NO;
237+ ENABLE_STRICT_OBJC_MSGSEND = YES;
238+ GCC_C_LANGUAGE_STANDARD = gnu99;
239+ GCC_NO_COMMON_BLOCKS = YES;
240+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
241+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
242+ GCC_WARN_UNDECLARED_SELECTOR = YES;
243+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
244+ GCC_WARN_UNUSED_FUNCTION = YES;
245+ GCC_WARN_UNUSED_VARIABLE = YES;
246+ MACOSX_DEPLOYMENT_TARGET = 10.11;
247+ MTL_ENABLE_DEBUG_INFO = NO;
248+ SDKROOT = macosx;
249+ };
250+ name = Release;
251+ };
252+ 03D84ABF1D5B0A1000776402 /* Debug */ = {
253+ isa = XCBuildConfiguration;
254+ buildSettings = {
255+ FRAMEWORK_SEARCH_PATHS = (
256+ "$(inherited)",
257+ "$(PROJECT_DIR)",
258+ );
259+ PRODUCT_NAME = "$(TARGET_NAME)";
260+ SWIFT_VERSION = 3.0;
261+ };
262+ name = Debug;
263+ };
264+ 03D84AC01D5B0A1000776402 /* Release */ = {
265+ isa = XCBuildConfiguration;
266+ buildSettings = {
267+ FRAMEWORK_SEARCH_PATHS = (
268+ "$(inherited)",
269+ "$(PROJECT_DIR)",
270+ );
271+ PRODUCT_NAME = "$(TARGET_NAME)";
272+ SWIFT_VERSION = 3.0;
273+ };
274+ name = Release;
275+ };
276+/* End XCBuildConfiguration section */
277+
278+/* Begin XCConfigurationList section */
279+ 03D84AB21D5B0A1000776402 /* Build configuration list for PBXProject "test_Freddy" */ = {
280+ isa = XCConfigurationList;
281+ buildConfigurations = (
282+ 03D84ABC1D5B0A1000776402 /* Debug */,
283+ 03D84ABD1D5B0A1000776402 /* Release */,
284+ );
285+ defaultConfigurationIsVisible = 0;
286+ defaultConfigurationName = Release;
287+ };
288+ 03D84ABE1D5B0A1000776402 /* Build configuration list for PBXNativeTarget "test_Freddy" */ = {
289+ isa = XCConfigurationList;
290+ buildConfigurations = (
291+ 03D84ABF1D5B0A1000776402 /* Debug */,
292+ 03D84AC01D5B0A1000776402 /* Release */,
293+ );
294+ defaultConfigurationIsVisible = 0;
295+ defaultConfigurationName = Release;
296+ };
297+/* End XCConfigurationList section */
298+ };
299+ rootObject = 03D84AAF1D5B0A1000776402 /* Project object */;
300+}
tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Workspace
3+ version = "1.0">
4+ <FileRef
5+ location = "self:test_Freddy.xcodeproj">
6+ </FileRef>
7+</Workspace>
tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy.xcodeproj/project.xcworkspace/xcshareddata/test_Freddy.xcscmblueprintnew file+30
@@ -0,0 +1,30 @@
1+{
2+ "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A",
3+ "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
4+
5+ },
6+ "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
7+ "6ADA245F937D8ED6D99F5A7865E19F5267A169E2" : 0,
8+ "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A" : 0
9+ },
10+ "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "7B3DFA55-F9BF-41D8-8FD5-204D3162EB03",
11+ "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
12+ "6ADA245F937D8ED6D99F5A7865E19F5267A169E2" : "dropbox\/JSON\/test_Freddy\/Vendor\/Freddy\/",
13+ "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A" : "dropbox\/"
14+ },
15+ "DVTSourceControlWorkspaceBlueprintNameKey" : "test_Freddy",
16+ "DVTSourceControlWorkspaceBlueprintVersion" : 204,
17+ "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "JSON\/test_Freddy\/test_Freddy.xcodeproj",
18+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
19+ {
20+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/bignerdranch\/Freddy.git",
21+ "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
22+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "6ADA245F937D8ED6D99F5A7865E19F5267A169E2"
23+ },
24+ {
25+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "\/Users\/nst\/Dropbox\/dropbox.git",
26+ "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
27+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A"
28+ }
29+ ]
30+}
tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_Freddy.xcschemenew file+91
@@ -0,0 +1,91 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Scheme
3+ LastUpgradeVersion = "0800"
4+ version = "1.3">
5+ <BuildAction
6+ parallelizeBuildables = "YES"
7+ buildImplicitDependencies = "YES">
8+ <BuildActionEntries>
9+ <BuildActionEntry
10+ buildForTesting = "YES"
11+ buildForRunning = "YES"
12+ buildForProfiling = "YES"
13+ buildForArchiving = "YES"
14+ buildForAnalyzing = "YES">
15+ <BuildableReference
16+ BuildableIdentifier = "primary"
17+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
18+ BuildableName = "test_Freddy"
19+ BlueprintName = "test_Freddy"
20+ ReferencedContainer = "container:test_Freddy.xcodeproj">
21+ </BuildableReference>
22+ </BuildActionEntry>
23+ </BuildActionEntries>
24+ </BuildAction>
25+ <TestAction
26+ buildConfiguration = "Debug"
27+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+ shouldUseLaunchSchemeArgsEnv = "YES">
30+ <Testables>
31+ </Testables>
32+ <MacroExpansion>
33+ <BuildableReference
34+ BuildableIdentifier = "primary"
35+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
36+ BuildableName = "test_Freddy"
37+ BlueprintName = "test_Freddy"
38+ ReferencedContainer = "container:test_Freddy.xcodeproj">
39+ </BuildableReference>
40+ </MacroExpansion>
41+ <AdditionalOptions>
42+ </AdditionalOptions>
43+ </TestAction>
44+ <LaunchAction
45+ buildConfiguration = "Debug"
46+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
48+ launchStyle = "0"
49+ useCustomWorkingDirectory = "NO"
50+ ignoresPersistentStateOnLaunch = "NO"
51+ debugDocumentVersioning = "YES"
52+ debugServiceExtension = "internal"
53+ allowLocationSimulation = "YES">
54+ <BuildableProductRunnable
55+ runnableDebuggingMode = "0">
56+ <BuildableReference
57+ BuildableIdentifier = "primary"
58+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
59+ BuildableName = "test_Freddy"
60+ BlueprintName = "test_Freddy"
61+ ReferencedContainer = "container:test_Freddy.xcodeproj">
62+ </BuildableReference>
63+ </BuildableProductRunnable>
64+ <AdditionalOptions>
65+ </AdditionalOptions>
66+ </LaunchAction>
67+ <ProfileAction
68+ buildConfiguration = "Release"
69+ shouldUseLaunchSchemeArgsEnv = "YES"
70+ savedToolIdentifier = ""
71+ useCustomWorkingDirectory = "NO"
72+ debugDocumentVersioning = "YES">
73+ <BuildableProductRunnable
74+ runnableDebuggingMode = "0">
75+ <BuildableReference
76+ BuildableIdentifier = "primary"
77+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
78+ BuildableName = "test_Freddy"
79+ BlueprintName = "test_Freddy"
80+ ReferencedContainer = "container:test_Freddy.xcodeproj">
81+ </BuildableReference>
82+ </BuildableProductRunnable>
83+ </ProfileAction>
84+ <AnalyzeAction
85+ buildConfiguration = "Debug">
86+ </AnalyzeAction>
87+ <ArchiveAction
88+ buildConfiguration = "Release"
89+ revealArchiveInOrganizer = "YES">
90+ </ArchiveAction>
91+</Scheme>
tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22
@@ -0,0 +1,22 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+<dict>
5+ <key>SchemeUserState</key>
6+ <dict>
7+ <key>test_Freddy.xcscheme</key>
8+ <dict>
9+ <key>orderHint</key>
10+ <integer>0</integer>
11+ </dict>
12+ </dict>
13+ <key>SuppressBuildableAutocreation</key>
14+ <dict>
15+ <key>03D84AB61D5B0A1000776402</key>
16+ <dict>
17+ <key>primary</key>
18+ <true/>
19+ </dict>
20+ </dict>
21+</dict>
22+</plist>
tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSON.swiftnew file+98
@@ -0,0 +1,98 @@
1+//
2+// JSON.swift
3+// Freddy
4+//
5+// Created by Matthew D. Mathias on 3/17/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+/// An enum to describe the structure of JSON.
10+public enum JSON {
11+ /// A case for denoting an array with an associated value of `[JSON]`
12+ case array([JSON])
13+ /// A case for denoting a dictionary with an associated value of `[Swift.String: JSON]`
14+ case dictionary([String: JSON])
15+ /// A case for denoting a double with an associated value of `Swift.Double`.
16+ case double(Double)
17+ /// A case for denoting an integer with an associated value of `Swift.Int`.
18+ case int(Int)
19+ /// A case for denoting a string with an associated value of `Swift.String`.
20+ case string(String)
21+ /// A case for denoting a boolean with an associated value of `Swift.Bool`.
22+ case bool(Bool)
23+ /// A case for denoting null.
24+ case null
25+}
26+
27+// MARK: - Errors
28+
29+extension JSON {
30+
31+ /// An enum to encapsulate errors that may arise in working with `JSON`.
32+ public enum Error: Swift.Error {
33+ /// The `index` is out of bounds for a JSON array
34+ case indexOutOfBounds(index: Int)
35+
36+ /// The `key` was not found in the JSON dictionary
37+ case keyNotFound(key: String)
38+
39+ /// The JSON is not subscriptable with `type`
40+ case unexpectedSubscript(type: JSONPathType.Type)
41+
42+ /// Unexpected JSON `value` was found that is not convertible `to` type
43+ case valueNotConvertible(value: JSON, to: Any.Type)
44+
45+ /// The JSON is not serializable to a `String`.
46+ case stringSerializationError
47+ }
48+
49+}
50+
51+// MARK: - Test Equality
52+
53+/// Return `true` if `lhs` is equal to `rhs`.
54+public func ==(lhs: JSON, rhs: JSON) -> Bool {
55+ switch (lhs, rhs) {
56+ case (.array(let arrL), .array(let arrR)):
57+ return arrL == arrR
58+ case (.dictionary(let dictL), .dictionary(let dictR)):
59+ return dictL == dictR
60+ case (.string(let strL), .string(let strR)):
61+ return strL == strR
62+ case (.double(let dubL), .double(let dubR)):
63+ return dubL == dubR
64+ case (.double(let dubL), .int(let intR)):
65+ return dubL == Double(intR)
66+ case (.int(let intL), .int(let intR)):
67+ return intL == intR
68+ case (.int(let intL), .double(let dubR)):
69+ return Double(intL) == dubR
70+ case (.bool(let bL), .bool(let bR)):
71+ return bL == bR
72+ case (.null, .null):
73+ return true
74+ default:
75+ return false
76+ }
77+}
78+
79+extension JSON: Equatable {}
80+
81+// MARK: - Printing
82+
83+extension JSON: CustomStringConvertible {
84+
85+ /// A textual representation of `self`.
86+ public var description: Swift.String {
87+ switch self {
88+ case .array(let arr): return String(describing: arr)
89+ case .dictionary(let dict): return String(describing: dict)
90+ case .string(let string): return string
91+ case .double(let double): return String(describing: double)
92+ case .int(let int): return String(describing: int)
93+ case .bool(let bool): return String(describing: bool)
94+ case .null: return "null"
95+ }
96+ }
97+
98+}
tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONDecodable.swiftnew file+186
@@ -0,0 +1,186 @@
1+//
2+// JSONDecodable.swift
3+// Freddy
4+//
5+// Created by Matthew D. Mathias on 3/24/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+/// A protocol to provide functionality for creating a model object with a `JSON`
10+/// value.
11+public protocol JSONDecodable {
12+
13+ /// Creates an instance of the model with a `JSON` instance.
14+ /// - parameter json: An instance of a `JSON` value from which to
15+ /// construct an instance of the implementing type.
16+ /// - throws: Any `JSON.Error` for errors derived from inspecting the
17+ /// `JSON` value, or any other error involved in decoding.
18+ init(json: JSON) throws
19+
20+}
21+
22+extension Double: JSONDecodable {
23+
24+ /// An initializer to create an instance of `Double` from a `JSON` value.
25+ /// - parameter json: An instance of `JSON`.
26+ /// - throws: The initializer will throw an instance of `JSON.Error` if
27+ /// an instance of `Double` cannot be created from the `JSON` value that was
28+ /// passed to this initializer.
29+ public init(json: JSON) throws {
30+ if case let .double(double) = json {
31+ self = double
32+ } else if case let .int(int) = json {
33+ self = Double(int)
34+ } else if case let .string(string) = json, let s = Double(string) {
35+ self = s
36+ } else {
37+ throw JSON.Error.valueNotConvertible(value: json, to: Double.self)
38+ }
39+ }
40+
41+}
42+
43+extension Int: JSONDecodable {
44+
45+ /// An initializer to create an instance of `Int` from a `JSON` value.
46+ /// - parameter json: An instance of `JSON`.
47+ /// - throws: The initializer will throw an instance of `JSON.Error` if
48+ /// an instance of `Int` cannot be created from the `JSON` value that was
49+ /// passed to this initializer.
50+ public init(json: JSON) throws {
51+
52+ if case let .double(double) = json, double <= Double(Int.max) {
53+ self = Int(double)
54+ } else if case let .int(int) = json {
55+ self = int
56+ } else if case let .string(string) = json, let int = Int(string) {
57+ self = int
58+ } else if case let .string(string) = json,
59+ let double = Double(string),
60+ let decimalSeparator = string.characters.index(of: "."),
61+ let int = Int(String(string.characters.prefix(upTo: decimalSeparator))),
62+ double == Double(int) {
63+ self = int
64+ } else {
65+ throw JSON.Error.valueNotConvertible(value: json, to: Int.self)
66+ }
67+ }
68+
69+}
70+
71+extension String: JSONDecodable {
72+
73+ /// An initializer to create an instance of `String` from a `JSON` value.
74+ /// - parameter json: An instance of `JSON`.
75+ /// - throws: The initializer will throw an instance of `JSON.Error` if
76+ /// an instance of `String` cannot be created from the `JSON` value that was
77+ /// passed to this initializer.
78+ public init(json: JSON) throws {
79+ switch json {
80+ case let .string(string):
81+ self = string
82+ case let .int(int):
83+ self = String(int)
84+ case let .bool(bool):
85+ self = String(bool)
86+ case let .double(double):
87+ self = String(double)
88+ default:
89+ throw JSON.Error.valueNotConvertible(value: json, to: String.self)
90+ }
91+ }
92+
93+}
94+
95+extension Bool: JSONDecodable {
96+
97+ /// An initializer to create an instance of `Bool` from a `JSON` value.
98+ /// - parameter json: An instance of `JSON`.
99+ /// - throws: The initializer will throw an instance of `JSON.Error` if
100+ /// an instance of `Bool` cannot be created from the `JSON` value that was
101+ /// passed to this initializer.
102+ public init(json: JSON) throws {
103+ guard case let .bool(bool) = json else {
104+ throw JSON.Error.valueNotConvertible(value: json, to: Bool.self)
105+ }
106+ self = bool
107+ }
108+
109+}
110+
111+extension RawRepresentable where RawValue: JSONDecodable {
112+
113+ /// An initializer to create an instance of `RawRepresentable` from a `JSON` value.
114+ /// - parameter json: An instance of `JSON`.
115+ /// - throws: The initializer will throw an instance of `JSON.Error` if
116+ /// an instance of `RawRepresentable` cannot be created from the `JSON` value that was
117+ /// passed to this initializer.
118+ public init(json: JSON) throws {
119+ let raw = try json.decode(type: RawValue.self)
120+ guard let value = Self(rawValue: raw) else {
121+ throw JSON.Error.valueNotConvertible(value: json, to: Self.self)
122+ }
123+ self = value
124+ }
125+}
126+
127+internal extension JSON {
128+
129+ /// Retrieves a `[JSON]` from the JSON.
130+ /// - parameter: A `JSON` to be used to create the returned `Array`.
131+ /// - returns: An `Array` of `JSON` elements
132+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`.
133+ /// - seealso: `JSON.decode(_:type:)`
134+ static func getArray(from json: JSON) throws -> [JSON] {
135+ // Ideally should be expressed as a conditional protocol implementation on Swift.Array.
136+ guard case let .array(array) = json else {
137+ throw Error.valueNotConvertible(value: json, to: Swift.Array<JSON>)
138+ }
139+ return array
140+ }
141+
142+ /// Retrieves a `[String: JSON]` from the JSON.
143+ /// - parameter: A `JSON` to be used to create the returned `Dictionary`.
144+ /// - returns: An `Dictionary` of `String` mapping to `JSON` elements
145+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`.
146+ /// - seealso: `JSON.decode(_:type:)`
147+ static func getDictionary(from json: JSON) throws -> [String: JSON] {
148+ // Ideally should be expressed as a conditional protocol implementation on Swift.Dictionary.
149+ guard case let .dictionary(dictionary) = json else {
150+ throw Error.valueNotConvertible(value: json, to: Swift.Dictionary<String, JSON>)
151+ }
152+ return dictionary
153+ }
154+
155+ /// Attempts to decode many values from a descendant JSON array at a path
156+ /// into JSON.
157+ /// - parameter json: A `JSON` to be used to create the returned `Array` of some type conforming to `JSONDecodable`.
158+ /// - returns: An `Array` of `Decoded` elements.
159+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`, as
160+ /// well as any error that arises from decoding the contained values.
161+ /// - seealso: `JSON.decode(_:type:)`
162+ static func decodedArray<Decoded: JSONDecodable>(from json: JSON) throws -> [Decoded] {
163+ // Ideally should be expressed as a conditional protocol implementation on Swift.Dictionary.
164+ // This implementation also doesn't do the `type = Type.self` trick.
165+ return try getArray(from: json).map(Decoded.init)
166+ }
167+
168+ /// Attempts to decode many values from a descendant JSON object at a path
169+ /// into JSON.
170+ /// - parameter json: A `JSON` to be used to create the returned `Dictionary` of some type conforming to `JSONDecodable`.
171+ /// - returns: A `Dictionary` of string keys and `Decoded` values.
172+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)` or
173+ /// any error that arises from decoding the contained values.
174+ /// - seealso: `JSON.decode(_:type:)`
175+ static func decodedDictionary<Decoded: JSONDecodable>(from json: JSON) throws -> [Swift.String: Decoded] {
176+ guard case let .dictionary(dictionary) = json else {
177+ throw Error.valueNotConvertible(value: json, to: Swift.Dictionary<String, Decoded>)
178+ }
179+ var decodedDictionary = Swift.Dictionary<String, Decoded>(minimumCapacity: dictionary.count)
180+ for (key, value) in dictionary {
181+ decodedDictionary[key] = try Decoded(json: value)
182+ }
183+ return decodedDictionary
184+ }
185+
186+}
tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONEncodable.swiftnew file+83
@@ -0,0 +1,83 @@
1+//
2+// JSONEncodable.swift
3+// Freddy
4+//
5+// Created by Matthew Mathias on 1/4/16.
6+// Copyright © 2016 Big Nerd Ranch. All rights reserved.
7+//
8+
9+import Foundation
10+
11+/// A protocol to facilitate encoding and decoding of `JSON`.
12+public protocol JSONEncodable {
13+ /// Converts an instance of a conforming type to `JSON`.
14+ /// - returns: An instance of `JSON`.
15+ /// - Note: If conforming to `JSONEncodable` with a custom type of your own, you should return an instance of
16+ /// `JSON.dictionary`.
17+ func toJSON() -> JSON
18+}
19+
20+extension Array where Element: JSONEncodable {
21+ /// Converts an instance of `Array` whose elements conform to `JSONEncodable` to `JSON`.
22+ /// - returns: An instance of `JSON` where the enum case is `.array`.
23+ public func toJSON() -> JSON {
24+ let arrayOfJSON = self.map { $0.toJSON() }
25+ return .array(arrayOfJSON)
26+ }
27+}
28+
29+extension Dictionary where Value: JSONEncodable {
30+ /// Converts an instance of `Dictionary` whose values conform to `JSONEncodable` to `JSON`. The keys in the resulting
31+ /// `JSON.dictionary` will be of type `String`.
32+ /// - returns: An instance of `JSON` where the enum case is `.dictionary`.
33+ public func toJSON() -> JSON {
34+ var jsonDictionary = [String: JSON]()
35+
36+ for (k, v) in self {
37+ let key = String(describing: k)
38+ jsonDictionary[key] = v.toJSON()
39+ }
40+
41+ return .dictionary(jsonDictionary)
42+ }
43+}
44+
45+extension Int: JSONEncodable {
46+ /// Converts an instance of a conforming type to `JSON`.
47+ /// - returns: An instance of `JSON` where the enum case is `.int`.
48+ public func toJSON() -> JSON {
49+ return .int(self)
50+ }
51+}
52+
53+extension Double: JSONEncodable {
54+ /// Converts an instance of a conforming type to `JSON`.
55+ /// - returns: An instance of `JSON` where the enum case is `.double`.
56+ public func toJSON() -> JSON {
57+ return .double(self)
58+ }
59+}
60+
61+extension String: JSONEncodable {
62+ /// Converts an instance of a conforming type to `JSON`.
63+ /// - returns: An instance of `JSON` where the enum case is `.string`.
64+ public func toJSON() -> JSON {
65+ return .string(self)
66+ }
67+}
68+
69+extension Bool: JSONEncodable {
70+ /// Converts an instance of a conforming type to `JSON`.
71+ /// - returns: An instance of `JSON` where the enum case is `.bool`.
72+ public func toJSON() -> JSON {
73+ return .bool(self)
74+ }
75+}
76+
77+extension RawRepresentable where RawValue: JSONEncodable {
78+ /// Converts an instance of a conforming type to `JSON`.
79+ /// - returns: An instance of `JSON` where the enum case is whatever the underlying `RawValue` converts to.
80+ public func toJSON() -> JSON {
81+ return rawValue.toJSON()
82+ }
83+}
tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONEncodingDetector.swiftnew file+110
@@ -0,0 +1,110 @@
1+//
2+// JSONEncodingDetector.swift
3+// Freddy
4+//
5+// Created by Robert Edwards on 1/27/16.
6+// Copyright © 2016 Big Nerd Ranch. All rights reserved.
7+//
8+
9+/// Struct for attempting to detect the Unicode encoding used with the data supplied to the JSONParser
10+public struct JSONEncodingDetector {
11+
12+ //// The Unicode encodings looked for during detection
13+ public enum Encoding {
14+ //// UTF-8
15+ case utf8
16+ //// UTF-16 Little Endian
17+ case utf16LE
18+ //// UTF-16 Big Endian
19+ case utf16BE
20+ //// UTF-32 Little Endian
21+ case utf32LE
22+ //// UTF-32 Big Endian
23+ case utf32BE
24+ }
25+
26+ //// The Unicode encodings supported by JSONParser.swift
27+ public static let supportedEncodings: [Encoding] = [.utf8]
28+
29+ typealias ByteStreamPrefixInformation = (encoding: Encoding, byteOrderMarkLength: Int)
30+
31+ //// Attempts to detect the Unicode encoding used for a given set of data.
32+ ////
33+ //// This function initially looks for a Byte Order Mark in the following form:
34+ ////
35+ //// Bytes | Encoding Form
36+ //// --------------|----------------
37+ //// 00 00 FE FF | UTF-32, big-endian
38+ //// FF FE 00 00 | UTF-32, little-endian
39+ //// FE FF | UTF-16, big-endian
40+ //// FF FE | UTF-16, little-endian
41+ //// EF BB BF | UTF-8
42+ ////
43+ //// If a BOM is not found then we detect using the following approach described in
44+ //// the JSON RFC http://www.ietf.org/rfc/rfc4627.txt:
45+ ////
46+ //// Since the first two characters of a JSON text will always be ASCII
47+ //// characters [RFC0020], it is possible to determine whether an octet
48+ //// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
49+ //// at the pattern of nulls in the first four octets.
50+ ////
51+ //// 00 00 00 xx UTF-32BE
52+ //// 00 xx 00 xx UTF-16BE
53+ //// xx 00 00 00 UTF-32LE
54+ //// xx 00 xx 00 UTF-16LE
55+ //// xx xx xx xx UTF-8
56+ ////
57+ //// - parameter header: The front Slice of data being read and evaluated.
58+ //// - returns: A tuple containing the detected Unicode encoding and the lenght of the byte order mark.
59+ static func detectEncoding(_ header: RandomAccessSlice<UnsafeBufferPointer<UInt8>>) -> ByteStreamPrefixInformation {
60+
61+ guard let prefix = prefixFromHeader(header) else {
62+ return (.utf8, 0)
63+ }
64+
65+ if let prefixInfo = JSONEncodingDetector.encodingFromBOM(prefix) {
66+ return prefixInfo
67+ } else {
68+ switch prefix {
69+ case(0, 0, 0?, _):
70+ return (.utf32BE, 0)
71+ case(_, 0, 0?, 0?):
72+ return (.utf32LE, 0)
73+ case (0, _, 0?, _), (0, _, _, _):
74+ return (.utf16BE, 0)
75+ case (_, 0, _, 0?), (_, 0, _, _):
76+ return (.utf16LE, 0)
77+ default:
78+ return (.utf8, 0)
79+ }
80+ }
81+ }
82+
83+ private typealias EncodingBytePrefix = (UInt8, UInt8, UInt8?, UInt8?)
84+
85+ private static func prefixFromHeader(_ header: RandomAccessSlice<UnsafeBufferPointer<UInt8>>) -> EncodingBytePrefix? {
86+ if header.count >= 4 {
87+ return(header[0], header[1], header[2], header[3])
88+ } else if header.count >= 2 {
89+ return (header[0], header[1], nil, nil)
90+ }
91+ return nil
92+ }
93+
94+ private static func encodingFromBOM(_ prefix: EncodingBytePrefix) -> ByteStreamPrefixInformation? {
95+ switch prefix {
96+ case(0xFE, 0xFF, _, _):
97+ return (.utf16BE, 2)
98+ case(0x00, 0x00, 0xFE?, 0xFF?):
99+ return (.utf32BE, 4)
100+ case(0xEF, 0xBB, 0xBF?, _):
101+ return (.utf8, 3)
102+ case(0xFF, 0xFE, 0?, 0?):
103+ return (.utf32LE, 4)
104+ case(0xFF, 0xFE, _, _):
105+ return (.utf16LE, 2)
106+ default:
107+ return nil
108+ }
109+ }
110+}
tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONLiteralConvertible.swiftnew file+134
@@ -0,0 +1,134 @@
1+//
2+// JSONLiteralConvertible.swift
3+// Freddy
4+//
5+// Created by Zachary Waldowski on 5/11/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+// MARK: - ArrayLiteralConvertible
10+
11+extension JSON: ExpressibleByArrayLiteral {
12+
13+ /// Create an instance by copying each element of the `collection` into a
14+ /// new `Array`.
15+ public init<Collection: Swift.Collection>(_ collection: Collection) where Collection.Iterator.Element == JSON {
16+ self = .array(Swift.Array(collection))
17+ }
18+
19+ /// Create an instance initialized with `elements`.
20+ public init(arrayLiteral elements: JSON...) {
21+ self.init(elements)
22+ }
23+
24+}
25+
26+// MARK: - DictionaryLiteralConvertible
27+
28+extension JSON: ExpressibleByDictionaryLiteral {
29+
30+ /// Create an instance by copying each key/value pair of the `pairs` into
31+ /// a new `Dictionary`.
32+ public init<Dictionary: Sequence>(_ pairs: Dictionary) where Dictionary.Iterator.Element == (Swift.String, JSON) {
33+ var dictionary = Swift.Dictionary<Swift.String, JSON>(minimumCapacity: pairs.underestimatedCount)
34+ for (key, value) in pairs {
35+ dictionary[key] = value
36+ }
37+ self.init(dictionary)
38+ }
39+
40+ /// Create an instance initialized with `pairs`.
41+ public init(dictionaryLiteral pairs: (Swift.String, JSON)...) {
42+ self.init(pairs)
43+ }
44+
45+ /// Create an instance initialized to `dictionary`.
46+ public init(_ dictionary: Swift.Dictionary<Swift.String, JSON>) {
47+ self = .dictionary(dictionary)
48+ }
49+}
50+
51+// MARK: - FloatLiteralConvertible
52+
53+extension JSON: ExpressibleByFloatLiteral {
54+
55+ /// Create an instance initialized to `Double` `value`.
56+ public init(_ value: Swift.Double) {
57+ self = .double(value)
58+ }
59+
60+ /// Create a literal instance initialized to `value`.
61+ public init(floatLiteral value: Swift.Double) {
62+ self.init(value)
63+ }
64+
65+}
66+
67+// MARK: - IntegerLiteralConvertible
68+
69+extension JSON: ExpressibleByIntegerLiteral {
70+
71+ /// Create an instance initialized to `Int` by `value`.
72+ public init(_ value: Swift.Int) {
73+ self = .int(value)
74+ }
75+
76+ /// Create a literal instance initialized to `value`.
77+ public init(integerLiteral value: Swift.Int) {
78+ self.init(value)
79+ }
80+
81+}
82+
83+// MARK: - StringLiteralConvertible
84+
85+extension JSON: ExpressibleByStringLiteral {
86+
87+ /// Create an instance initialized to `String` by `text`.
88+ public init(_ text: Swift.String) {
89+ self = .string(text)
90+ }
91+
92+ /// Create a literal instance initialized to `value`.
93+ public init(stringLiteral value: StringLiteralType) {
94+ self.init(value)
95+ }
96+
97+ /// Create a literal instance initialized to `value`.
98+ public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
99+ self.init(value)
100+ }
101+
102+ /// Create a literal instance initialized to `value`.
103+ public init(unicodeScalarLiteral value: StringLiteralType) {
104+ self.init(value)
105+ }
106+
107+}
108+
109+// MARK: - BooleanLiteralConvertible
110+
111+extension JSON: ExpressibleByBooleanLiteral {
112+
113+ /// Create an instance initialized to `Bool` by `value`.
114+ public init(_ value: Swift.Bool) {
115+ self = .bool(value)
116+ }
117+
118+ /// Create a literal instance initialized to `value`.
119+ public init(booleanLiteral value: Swift.Bool) {
120+ self.init(value)
121+ }
122+
123+}
124+
125+// MARK: - NilLiteralConvertible
126+
127+extension JSON: ExpressibleByNilLiteral {
128+
129+ /// Create an instance initialized with `nil`.
130+ public init(nilLiteral: ()) {
131+ self = .null
132+ }
133+
134+}
tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONParser.swiftnew file+918
@@ -0,0 +1,918 @@
1+//
2+// JSONParser.swift
3+// Freddy
4+//
5+// Created by John Gallagher on 4/18/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+import Foundation
10+
11+private struct Literal {
12+ static let BACKSLASH = UInt8(ascii: "\\")
13+ static let BACKSPACE = UInt8(ascii: "\u{0008}")
14+ static let COLON = UInt8(ascii: ":")
15+ static let COMMA = UInt8(ascii: ",")
16+ static let DOUBLE_QUOTE = UInt8(ascii: "\"")
17+ static let FORMFEED = UInt8(ascii: "\u{000c}")
18+ static let LEFT_BRACE = UInt8(ascii: "{")
19+ static let LEFT_BRACKET = UInt8(ascii: "[")
20+ static let MINUS = UInt8(ascii: "-")
21+ static let NEWLINE = UInt8(ascii: "\n")
22+ static let PERIOD = UInt8(ascii: ".")
23+ static let PLUS = UInt8(ascii: "+")
24+ static let RETURN = UInt8(ascii: "\r")
25+ static let RIGHT_BRACE = UInt8(ascii: "}")
26+ static let RIGHT_BRACKET = UInt8(ascii: "]")
27+ static let SLASH = UInt8(ascii: "/")
28+ static let SPACE = UInt8(ascii: " ")
29+ static let TAB = UInt8(ascii: "\t")
30+
31+ static let a = UInt8(ascii: "a")
32+ static let b = UInt8(ascii: "b")
33+ static let c = UInt8(ascii: "c")
34+ static let d = UInt8(ascii: "d")
35+ static let e = UInt8(ascii: "e")
36+ static let f = UInt8(ascii: "f")
37+ static let l = UInt8(ascii: "l")
38+ static let n = UInt8(ascii: "n")
39+ static let r = UInt8(ascii: "r")
40+ static let s = UInt8(ascii: "s")
41+ static let t = UInt8(ascii: "t")
42+ static let u = UInt8(ascii: "u")
43+
44+ static let A = UInt8(ascii: "A")
45+ static let B = UInt8(ascii: "B")
46+ static let C = UInt8(ascii: "C")
47+ static let D = UInt8(ascii: "D")
48+ static let E = UInt8(ascii: "E")
49+ static let F = UInt8(ascii: "F")
50+
51+ static let zero = UInt8(ascii: "0")
52+ static let one = UInt8(ascii: "1")
53+ static let two = UInt8(ascii: "2")
54+ static let three = UInt8(ascii: "3")
55+ static let four = UInt8(ascii: "4")
56+ static let five = UInt8(ascii: "5")
57+ static let six = UInt8(ascii: "6")
58+ static let seven = UInt8(ascii: "7")
59+ static let eight = UInt8(ascii: "8")
60+ static let nine = UInt8(ascii: "9")
61+}
62+
63+private let ParserMaximumDepth = 512
64+
65+
66+/// A pure Swift JSON parser. This parser is much faster than the
67+/// `NSJSONSerialization`-based parser (due to the overhead of having to
68+/// dynamically cast the Objective-C objects to determine their type); however,
69+/// it is much newer and has restrictions that the `NSJSONSerialization` parser
70+/// does not. Two restrictions in particular are that it requires UTF-8 data as
71+/// input and it does not allow trailing commas in arrays or dictionaries.
72+public struct JSONParser {
73+
74+ fileprivate enum Sign: Int {
75+ case positive = 1
76+ case negative = -1
77+ }
78+
79+ private let input: UnsafeBufferPointer<UInt8>
80+ private var loc = 0
81+ private var depth = 0
82+
83+ fileprivate init(input: UnsafeBufferPointer<UInt8>) {
84+ self.input = input
85+ }
86+
87+ /// Decode the root element of the `JSON` stream. This may be any fragment
88+ /// or a structural element, per RFC 7159.
89+ ///
90+ /// The beginning bytes are used to determine the stream's encoding.
91+ /// `JSONParser` currently only supports UTF-8 encoding, with or without
92+ /// a byte-order mark.
93+ ///
94+ /// - throws: `JSONParser.Error` for any decoding failures, including a
95+ /// source location if needed.
96+ public mutating func parse() throws -> JSON {
97+ try guardAgainstUnsupportedEncodings()
98+ let value = try parseValue()
99+ skipWhitespace()
100+ guard loc == input.count else {
101+ throw Error.endOfStreamGarbage(offset: loc)
102+ }
103+ return value
104+ }
105+
106+ private mutating func parseValue() throws -> JSON {
107+ guard depth <= ParserMaximumDepth else {
108+ throw Error.exceededNestingLimit(offset: loc)
109+ }
110+
111+ guard input.count > 0 else {
112+ throw Error.endOfStreamUnexpected
113+ }
114+
115+ advancing: while loc < input.count {
116+ do {
117+ switch input[loc] {
118+ case Literal.LEFT_BRACKET:
119+ depth += 1
120+ defer { depth -= 1 }
121+ return try decodeArray()
122+
123+ case Literal.LEFT_BRACE:
124+ depth += 1
125+ defer { depth -= 1 }
126+ return try decodeObject()
127+
128+ case Literal.DOUBLE_QUOTE:
129+ return try decodeString()
130+
131+ case Literal.f:
132+ return try decodeFalse()
133+
134+ case Literal.n:
135+ return try decodeNull()
136+
137+ case Literal.t:
138+ return try decodeTrue()
139+
140+ case Literal.MINUS:
141+ return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .leadingMinus))
142+
143+ case Literal.zero:
144+ return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .leadingZero))
145+
146+ case Literal.one...Literal.nine:
147+ return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .preDecimalDigits))
148+
149+ case Literal.SPACE, Literal.TAB, Literal.RETURN, Literal.NEWLINE:
150+ loc = (loc + 1)
151+
152+ default:
153+ break advancing
154+ }
155+ } catch let InternalError.numberOverflow(offset: start) {
156+ return try decodeNumberAsString(from: start)
157+ }
158+ }
159+ if loc < input.count {
160+ throw Error.valueInvalid(offset: loc, character: UnicodeScalar(input[loc]))
161+ } else {
162+ throw Error.endOfStreamUnexpected
163+ }
164+ }
165+
166+ private mutating func skipWhitespace() {
167+ while loc < input.count {
168+ switch input[loc] {
169+ case Literal.SPACE, Literal.TAB, Literal.RETURN, Literal.NEWLINE:
170+ loc = (loc + 1)
171+ default:
172+ return
173+ }
174+ }
175+ }
176+
177+ private mutating func guardAgainstUnsupportedEncodings() throws {
178+ let header = input.prefix(4)
179+ let encodingPrefixInformation = JSONEncodingDetector.detectEncoding(header)
180+ guard JSONEncodingDetector.supportedEncodings.contains(encodingPrefixInformation.encoding) else {
181+ throw Error.invalidUnicodeStreamEncoding(detectedEncoding: encodingPrefixInformation.encoding)
182+ }
183+ loc = loc.advanced(by: encodingPrefixInformation.byteOrderMarkLength)
184+ }
185+
186+ private mutating func decodeNull() throws -> JSON {
187+ guard input.index(loc, offsetBy: 3, limitedBy: input.count) != input.count else {
188+ throw Error.literalNilMisspelled(offset: loc)
189+ }
190+
191+ if input[loc+1] != Literal.u
192+ || input[loc+2] != Literal.l
193+ || input[loc+3] != Literal.l {
194+ throw Error.literalNilMisspelled(offset: loc)
195+ }
196+
197+ loc += 4
198+ return .null
199+ }
200+
201+ private mutating func decodeTrue() throws -> JSON {
202+ guard input.index(loc, offsetBy: 3, limitedBy: input.count) != input.count else {
203+ throw Error.literalNilMisspelled(offset: loc)
204+ }
205+
206+ if input[loc+1] != Literal.r
207+ || input[loc+2] != Literal.u
208+ || input[loc+3] != Literal.e {
209+ throw Error.literalTrueMisspelled(offset: loc)
210+ }
211+
212+ loc += 4
213+ return .bool(true)
214+ }
215+
216+ private mutating func decodeFalse() throws -> JSON {
217+ guard input.index(loc, offsetBy: 4, limitedBy: input.count) != input.count else {
218+ throw Error.literalNilMisspelled(offset: loc)
219+ }
220+
221+ if input[loc+1] != Literal.a
222+ || input[loc+2] != Literal.l
223+ || input[loc+3] != Literal.s
224+ || input[loc+4] != Literal.e {
225+ throw Error.literalFalseMisspelled(offset: loc)
226+ }
227+
228+ loc += 5
229+ return .bool(false)
230+ }
231+
232+ private var stringDecodingBuffer = [UInt8]()
233+ private mutating func decodeString() throws -> JSON {
234+ loc = (loc + 1)
235+ stringDecodingBuffer.removeAll(keepingCapacity: true)
236+ while loc < input.count {
237+ switch input[loc] {
238+ case Literal.BACKSLASH:
239+ loc = (loc + 1)
240+ switch input[loc] {
241+ case Literal.DOUBLE_QUOTE: stringDecodingBuffer.append(Literal.DOUBLE_QUOTE)
242+ case Literal.BACKSLASH: stringDecodingBuffer.append(Literal.BACKSLASH)
243+ case Literal.SLASH: stringDecodingBuffer.append(Literal.SLASH)
244+ case Literal.b: stringDecodingBuffer.append(Literal.BACKSPACE)
245+ case Literal.f: stringDecodingBuffer.append(Literal.FORMFEED)
246+ case Literal.r: stringDecodingBuffer.append(Literal.RETURN)
247+ case Literal.t: stringDecodingBuffer.append(Literal.TAB)
248+ case Literal.n: stringDecodingBuffer.append(Literal.NEWLINE)
249+ case Literal.u:
250+ loc = (loc + 1)
251+ try readUnicodeEscape(start: loc - 2)
252+
253+ // readUnicodeEscape() advances loc on its own, so we'll `continue` now
254+ // to skip the typical "advance past this character" for all the other escapes
255+ continue
256+
257+ default:
258+ throw Error.controlCharacterUnrecognized(offset: loc)
259+ }
260+ loc = (loc + 1)
261+
262+ case Literal.DOUBLE_QUOTE:
263+ loc = (loc + 1)
264+ stringDecodingBuffer.append(0)
265+
266+ let string = stringDecodingBuffer.withUnsafeBufferPointer {
267+ String(cString: UnsafePointer($0.baseAddress!))
268+ }
269+
270+ return .string(string)
271+
272+ case let other:
273+ stringDecodingBuffer.append(other)
274+ loc = (loc + 1)
275+ }
276+ }
277+
278+ throw Error.endOfStreamUnexpected
279+ }
280+
281+ private mutating func readCodeUnit() -> UInt16? {
282+ guard loc + 4 <= input.count else {
283+ return nil
284+ }
285+ var codeUnit: UInt16 = 0
286+ for c in input[loc..<loc+4] {
287+ let nibble: UInt16
288+
289+ switch c {
290+ case Literal.zero...Literal.nine:
291+ nibble = UInt16(c - Literal.zero)
292+
293+ case Literal.a...Literal.f:
294+ nibble = 10 + UInt16(c - Literal.a)
295+
296+ case Literal.A...Literal.F:
297+ nibble = 10 + UInt16(c - Literal.A)
298+
299+ default:
300+ return nil
301+ }
302+ codeUnit = (codeUnit << 4) | nibble
303+ }
304+ loc += 4
305+ return codeUnit
306+ }
307+
308+ private mutating func readUnicodeEscape(start: Int) throws {
309+ guard let codeUnit = readCodeUnit() else {
310+ throw Error.unicodeEscapeInvalid(offset: start)
311+ }
312+
313+ let codeUnits: [UInt16]
314+
315+ if UTF16.isLeadSurrogate(codeUnit) {
316+ // First half of a UTF16 surrogate pair - we must parse another code unit and combine them
317+
318+ // First confirm and skip over that we have another "\u"
319+ guard loc + 6 <= input.count && input[loc] == Literal.BACKSLASH && input[loc+1] == Literal.u else {
320+ throw Error.unicodeEscapeInvalid(offset: start)
321+ }
322+ loc += 2
323+
324+ // Ensure the second code unit is valid for the surrogate pair
325+ guard let secondCodeUnit = readCodeUnit(), UTF16.isTrailSurrogate(secondCodeUnit) else {
326+ throw Error.unicodeEscapeInvalid(offset: start)
327+ }
328+
329+ codeUnits = [codeUnit, secondCodeUnit]
330+ } else {
331+ codeUnits = [codeUnit]
332+ }
333+
334+ let transcodeHadError = transcode(codeUnits.makeIterator(), from: UTF16.self, to: UTF8.self, stoppingOnError: true) { (outputEncodingCodeUnit) in
335+ self.stringDecodingBuffer.append(outputEncodingCodeUnit)
336+ }
337+
338+ if transcodeHadError {
339+ throw Error.unicodeEscapeInvalid(offset: start)
340+ }
341+ }
342+
343+ private mutating func decodeArray() throws -> JSON {
344+ let start = loc
345+ loc = (loc + 1)
346+ var items = [JSON]()
347+
348+ while loc < input.count {
349+ skipWhitespace()
350+
351+ if loc < input.count && input[loc] == Literal.RIGHT_BRACKET {
352+ loc = (loc + 1)
353+ return .array(items)
354+ }
355+
356+ if !items.isEmpty {
357+ guard loc < input.count && input[loc] == Literal.COMMA else {
358+ throw Error.collectionMissingSeparator(offset: start)
359+ }
360+ loc = (loc + 1)
361+ }
362+
363+ items.append(try parseValue())
364+ }
365+
366+ throw Error.endOfStreamUnexpected
367+ }
368+
369+ // Decoding objects can be recursive, so we have to keep more than one
370+ // buffer around for building up key/value pairs (to reduce allocations
371+ // when parsing large JSON documents).
372+ //
373+ // Rough estimate of the difference between this and using a fresh
374+ // [(String,JSON)] for the `pairs` variable in decodeObject() below is
375+ // about 12% on an iPhone 5.
376+ private struct DecodeObjectBuffers {
377+ var buffers = [[(String,JSON)]]()
378+
379+ mutating func getBuffer() -> [(String,JSON)] {
380+ if !buffers.isEmpty {
381+ var buffer = buffers.removeLast()
382+ buffer.removeAll(keepingCapacity: true)
383+ return buffer
384+ }
385+ return [(String,JSON)]()
386+ }
387+
388+ mutating func putBuffer(_ buffer: [(String,JSON)]) {
389+ buffers.append(buffer)
390+ }
391+ }
392+
393+ private var decodeObjectBuffers = DecodeObjectBuffers()
394+
395+ private mutating func decodeObject() throws -> JSON {
396+ let start = loc
397+ loc = (loc + 1)
398+ var pairs = decodeObjectBuffers.getBuffer()
399+
400+ while loc < input.count {
401+ skipWhitespace()
402+
403+ if loc < input.count && input[loc] == Literal.RIGHT_BRACE {
404+ loc = (loc + 1)
405+ var obj = [String:JSON](minimumCapacity: pairs.count)
406+ for (k, v) in pairs {
407+ obj[k] = v
408+ }
409+ decodeObjectBuffers.putBuffer(pairs)
410+ return .dictionary(obj)
411+ }
412+
413+ if !pairs.isEmpty {
414+ guard loc < input.count && input[loc] == Literal.COMMA else {
415+ throw Error.collectionMissingSeparator(offset: start)
416+ }
417+ loc = (loc + 1)
418+
419+ skipWhitespace()
420+ }
421+
422+ guard loc < input.count && input[loc] == Literal.DOUBLE_QUOTE else {
423+ throw Error.dictionaryMissingKey(offset: start)
424+ }
425+
426+ let key = try decodeString().getString()
427+ skipWhitespace()
428+
429+ guard loc < input.count && input[loc] == Literal.COLON else {
430+ throw Error.collectionMissingSeparator(offset: start)
431+ }
432+ loc = (loc + 1)
433+
434+ pairs.append((key, try parseValue()))
435+ }
436+
437+ throw Error.endOfStreamUnexpected
438+ }
439+
440+ private mutating func decodeIntegralValue(_ parser: NumberParser) throws -> JSON {
441+ var sign = Sign.positive
442+ var parser = parser
443+ var value = 0
444+
445+ // This would be more natural as `while true { ... }` with a meaningful .Done case,
446+ // but that causes compile time explosion in Swift 2.2. :-|
447+ while parser.state != .done {
448+ switch parser.state {
449+ case .leadingMinus:
450+ sign = .negative
451+ try parser.parseNegative()
452+
453+ case .leadingZero:
454+ parser.parseLeadingZero()
455+
456+ case .preDecimalDigits:
457+ try parser.parsePreDecimalDigits { c in
458+ guard case let (exponent, false) = Int.multiplyWithOverflow(10, value) else {
459+ throw InternalError.numberOverflow(offset: parser.start)
460+ }
461+
462+ guard case let (newValue, false) = Int.addWithOverflow(exponent, Int(c - Literal.zero)) else {
463+ throw InternalError.numberOverflow(offset: parser.start)
464+ }
465+
466+ value = newValue
467+ }
468+
469+ case .decimal, .exponent:
470+ return try detectingFloatingPointErrors(start: parser.start) {
471+ try decodeFloatingPointValue(parser, sign: sign, value: Double(value))
472+ }
473+
474+ case .postDecimalDigits, .exponentSign, .exponentDigits:
475+ assertionFailure("Invalid internal state while parsing number")
476+
477+ case .done:
478+ fatalError("impossible condition")
479+ }
480+ }
481+
482+ guard case let (signedValue, false) = Int.multiplyWithOverflow(sign.rawValue, value) else {
483+ throw InternalError.numberOverflow(offset: parser.start)
484+ }
485+
486+ loc = parser.loc
487+ return .int(signedValue)
488+ }
489+
490+ private mutating func decodeFloatingPointValue(_ parser: NumberParser, sign: Sign, value: Double) throws -> JSON {
491+ var parser = parser
492+ var value = value
493+ var exponentSign = Sign.positive
494+ var exponent = Double(0)
495+ var position = 0.1
496+
497+ // This would be more natural as `while true { ... }` with a meaningful .Done case,
498+ // but that causes compile time explosion in Swift 2.2. :-|
499+ while parser.state != .done {
500+ switch parser.state {
501+ case .leadingMinus, .leadingZero, .preDecimalDigits:
502+ assertionFailure("Invalid internal state while parsing number")
503+
504+ case .decimal:
505+ try parser.parseDecimal()
506+
507+ case .postDecimalDigits:
508+ parser.parsePostDecimalDigits { c in
509+ value += position * Double(c - Literal.zero)
510+ position /= 10
511+ }
512+
513+ case .exponent:
514+ exponentSign = try parser.parseExponent()
515+
516+ case .exponentSign:
517+ try parser.parseExponentSign()
518+
519+ case .exponentDigits:
520+ parser.parseExponentDigits { c in
521+ exponent = exponent * 10 + Double(c - Literal.zero)
522+ }
523+
524+ case .done:
525+ fatalError("impossible condition")
526+ }
527+ }
528+
529+ loc = parser.loc
530+ return .double(Double(sign.rawValue) * value * pow(10, Double(exponentSign.rawValue) * exponent))
531+ }
532+
533+
534+ private mutating func decodeNumberAsString(from position: Int) throws -> JSON {
535+ var parser: NumberParser = {
536+ let state: NumberParser.State
537+ switch input[position] {
538+ case Literal.MINUS: state = .leadingMinus
539+ case Literal.zero: state = .leadingZero
540+ case Literal.one...Literal.nine: state = .preDecimalDigits
541+ default:
542+ fatalError("Internal error: decodeNumber called on not-a-number")
543+ }
544+ return NumberParser(loc: position, input: input, state: state)
545+ }()
546+
547+ stringDecodingBuffer.removeAll(keepingCapacity: true)
548+
549+ while true {
550+ switch parser.state {
551+ case .leadingMinus:
552+ try parser.parseNegative()
553+ stringDecodingBuffer.append(Literal.MINUS)
554+
555+ case .leadingZero:
556+ parser.parseLeadingZero()
557+ stringDecodingBuffer.append(Literal.zero)
558+
559+ case .preDecimalDigits:
560+ parser.parsePreDecimalDigits { stringDecodingBuffer.append($0) }
561+
562+ case .decimal:
563+ try parser.parseDecimal()
564+ stringDecodingBuffer.append(Literal.PERIOD)
565+
566+ case .postDecimalDigits:
567+ parser.parsePostDecimalDigits { stringDecodingBuffer.append($0) }
568+
569+ case .exponent:
570+ stringDecodingBuffer.append(input[parser.loc])
571+ _ = try parser.parseExponent()
572+
573+ case .exponentSign:
574+ stringDecodingBuffer.append(input[parser.loc])
575+ try parser.parseExponentSign()
576+
577+ case .exponentDigits:
578+ parser.parseExponentDigits { stringDecodingBuffer.append($0) }
579+
580+ case .done:
581+ stringDecodingBuffer.append(0)
582+ let string = stringDecodingBuffer.withUnsafeBufferPointer {
583+ String(cString: UnsafePointer($0.baseAddress!))
584+ }
585+
586+ loc = parser.loc
587+ return .string(string)
588+ }
589+ }
590+ }
591+
592+ private func detectingFloatingPointErrors<T>(start loc: Int, _ f: () throws -> T) throws -> T {
593+ let flags = FE_UNDERFLOW | FE_OVERFLOW
594+ feclearexcept(flags)
595+ let value = try f()
596+ guard fetestexcept(flags) == 0 else {
597+ throw InternalError.numberOverflow(offset: loc)
598+ }
599+ return value
600+ }
601+}
602+
603+private struct NumberParser {
604+ enum State {
605+ case leadingMinus
606+ case leadingZero
607+ case preDecimalDigits
608+ case decimal
609+ case postDecimalDigits
610+ case exponent
611+ case exponentSign
612+ case exponentDigits
613+ case done
614+ }
615+
616+ let start: Int
617+ var loc = 0
618+ var state: State
619+ let input: UnsafeBufferPointer<UInt8>
620+
621+ init(loc: Int, input: UnsafeBufferPointer<UInt8>, state: State) {
622+ assert(loc < input.count, "Invalid input to NumberParser")
623+ self.start = loc
624+ self.loc = loc
625+ self.input = input
626+ self.state = state
627+ }
628+
629+ mutating func parseNegative() throws {
630+ assert(state == .leadingMinus, "Unexpected state entering parseNegative")
631+
632+ loc = (loc + 1)
633+ guard loc < input.count else {
634+ throw JSONParser.Error.endOfStreamUnexpected
635+ }
636+
637+ switch input[loc] {
638+ case Literal.zero:
639+ state = .leadingZero
640+
641+ case Literal.one...Literal.nine:
642+ state = .preDecimalDigits
643+
644+ default:
645+ throw JSONParser.Error.numberSymbolMissingDigits(offset: start)
646+ }
647+ }
648+
649+ mutating func parseLeadingZero() {
650+ assert(state == .leadingZero, "Unexpected state entering parseLeadingZero")
651+
652+ loc = (loc + 1)
653+ guard loc < input.count else {
654+ state = .done
655+ return
656+ }
657+
658+ switch input[loc] {
659+ case Literal.PERIOD:
660+ state = .decimal
661+
662+ case Literal.e, Literal.E:
663+ state = .exponent
664+
665+ default:
666+ state = .done
667+ }
668+ }
669+
670+ mutating func parsePreDecimalDigits(f: (UInt8) throws -> Void) rethrows {
671+ assert(state == .preDecimalDigits, "Unexpected state entering parsePreDecimalDigits")
672+ advancing: while loc < input.count {
673+ let c = input[loc]
674+ switch c {
675+ case Literal.zero...Literal.nine:
676+ try f(c)
677+ loc = (loc + 1)
678+
679+ case Literal.PERIOD:
680+ state = .decimal
681+ return
682+
683+ case Literal.e, Literal.E:
684+ state = .exponent
685+ return
686+
687+ default:
688+ break advancing
689+ }
690+ }
691+
692+ state = .done
693+ }
694+
695+ mutating func parseDecimal() throws {
696+ assert(state == .decimal, "Unexpected state entering parseDecimal")
697+ loc = (loc + 1)
698+ guard loc < input.count else {
699+ throw JSONParser.Error.endOfStreamUnexpected
700+ }
701+
702+ switch input[loc] {
703+ case Literal.zero...Literal.nine:
704+ state = .postDecimalDigits
705+
706+ default:
707+ throw JSONParser.Error.numberMissingFractionalDigits(offset: start)
708+ }
709+ }
710+
711+ mutating func parsePostDecimalDigits(f: (UInt8) throws -> Void) rethrows {
712+ assert(state == .postDecimalDigits, "Unexpected state entering parsePostDecimalDigits")
713+
714+ advancing: while loc < input.count {
715+ let c = input[loc]
716+ switch c {
717+ case Literal.zero...Literal.nine:
718+ try f(c)
719+ loc = (loc + 1)
720+
721+ case Literal.e, Literal.E:
722+ state = .exponent
723+ return
724+
725+ default:
726+ break advancing
727+ }
728+ }
729+
730+ state = .done
731+ }
732+
733+ mutating func parseExponent() throws -> JSONParser.Sign {
734+ assert(state == .exponent, "Unexpected state entering parseExponent")
735+
736+ loc = (loc + 1)
737+ guard loc < input.count else {
738+ throw JSONParser.Error.endOfStreamUnexpected
739+ }
740+
741+ switch input[loc] {
742+ case Literal.zero...Literal.nine:
743+ state = .exponentDigits
744+
745+ case Literal.PLUS:
746+ state = .exponentSign
747+
748+ case Literal.MINUS:
749+ state = .exponentSign
750+ return .negative
751+
752+ default:
753+ throw JSONParser.Error.numberSymbolMissingDigits(offset: start)
754+ }
755+
756+ return .positive
757+ }
758+
759+ mutating func parseExponentSign() throws {
760+ assert(state == .exponentSign, "Unexpected state entering parseExponentSign")
761+ loc = (loc + 1)
762+ guard loc < input.count else {
763+ throw JSONParser.Error.endOfStreamUnexpected
764+ }
765+
766+ switch input[loc] {
767+ case Literal.zero...Literal.nine:
768+ state = .exponentDigits
769+
770+ default:
771+ throw JSONParser.Error.numberSymbolMissingDigits(offset: start)
772+ }
773+ }
774+
775+ mutating func parseExponentDigits(f: (UInt8) throws -> Void) rethrows {
776+ assert(state == .exponentDigits, "Unexpected state entering parseExponentDigits")
777+ advancing: while loc < input.count {
778+ let c = input[loc]
779+ switch c {
780+ case Literal.zero...Literal.nine:
781+ try f(c)
782+ loc = (loc + 1)
783+
784+ default:
785+ break advancing
786+ }
787+ }
788+
789+ state = .done
790+ }
791+}
792+
793+public extension JSONParser {
794+
795+ /// Creates a `JSONParser` ready to parse UTF-8 encoded `Data`.
796+ ///
797+ /// If the data is mutable, it is copied before parsing. The data's lifetime
798+ /// is extended for the duration of parsing.
799+ @available(*, unavailable, message: "Replaced with parse(utf8:)")
800+ init(utf8Data inData: Data) {
801+ fatalError("unavailable code cannot be executed")
802+ }
803+
804+ /// Creates a `JSONParser` from the code units represented by the `string`.
805+ ///
806+ /// The synthesized string is lifetime-extended for the duration of parsing.
807+ @available(*, unavailable, message: "Replaced with parse(utf8:)")
808+ init(string: String) {
809+ fatalError("unavailable code cannot be executed")
810+ }
811+
812+ /// Creates an instance of `JSON` from UTF-8 encoded `data`.
813+ static func parse(utf8 data: Data) throws -> JSON {
814+ return try data.withUnsafeBytes { (ptr: UnsafePointer<UInt8>) -> JSON in
815+ let buffer = UnsafeBufferPointer(start: ptr, count: data.count)
816+ var parser = JSONParser(input: buffer)
817+ return try parser.parse()
818+ }
819+ }
820+
821+ /// Creates an instance of `JSON` from `string`.
822+ static func parse(_ string: String) throws -> JSON {
823+ return try string.utf8CString.withUnsafeBufferPointer { (nulTerminatedBuffer) throws -> JSON in
824+ return try nulTerminatedBuffer.baseAddress!.withMemoryRebound(to: UInt8.self, capacity: nulTerminatedBuffer.count) { (utf8Base) throws -> JSON in
825+ // don't want to include the nul termination in the buffer - trim it off
826+ let buffer = UnsafeBufferPointer(start: utf8Base, count: nulTerminatedBuffer.count - 1)
827+ var parser = JSONParser(input: buffer)
828+ return try parser.parse()
829+ }
830+ }
831+ }
832+
833+}
834+
835+extension JSONParser: JSONParserType {
836+
837+ /// Creates an instance of `JSON` from UTF-8 encoded `Data`.
838+ /// - parameter data: An instance of `Data` to parse `JSON` from.
839+ /// - throws: Any `JSONParser.Error` that arises during decoding.
840+ /// - seealso: JSONParser.parse()
841+ public static func createJSON(from data: Data) throws -> JSON {
842+ return try parse(utf8: data)
843+ }
844+
845+}
846+
847+// MARK: - Errors
848+
849+extension JSONParser {
850+
851+ /// Enumeration describing possible errors that occur while parsing a JSON
852+ /// document. Most errors include an associated `offset`, representing the
853+ /// offset into the UTF-8 characters making up the document where the error
854+ /// occurred.
855+ public enum Error: Swift.Error {
856+ /// The parser ran out of data prematurely. This usually means a value
857+ /// was not escaped, such as a string literal not ending with a double
858+ /// quote.
859+ case endOfStreamUnexpected
860+
861+ /// Unexpected non-whitespace data was left around `offset` after
862+ /// parsing all valid JSON.
863+ case endOfStreamGarbage(offset: Int)
864+
865+ /// Too many nested objects or arrays occured at the literal started
866+ /// around `offset`.
867+ case exceededNestingLimit(offset: Int)
868+
869+ /// A `character` was not a valid start of a value around `offset`.
870+ case valueInvalid(offset: Int, character: UnicodeScalar)
871+
872+ /// Badly-formed Unicode escape sequence at `offset`. A Unicode escape
873+ /// uses the text "\u" followed by 4 hex digits, such as "\uF09F\uA684"
874+ /// to represent U+1F984, "UNICORN FACE".
875+ case unicodeEscapeInvalid(offset: Int)
876+
877+ /// Badly-formed control character around `offset`. JSON supports
878+ /// backslash-escaped double quotes, slashes, whitespace control codes,
879+ /// and Unicode escape sequences.
880+ case controlCharacterUnrecognized(offset: Int)
881+
882+ /// Invalid token, expected `null` around `offset`
883+ case literalNilMisspelled(offset: Int)
884+
885+ /// Invalid token, expected `true` around `offset`
886+ case literalTrueMisspelled(offset: Int)
887+
888+ /// Invalid token, expected `false` around `offset`
889+ case literalFalseMisspelled(offset: Int)
890+
891+ /// Badly-formed collection at given `offset`, expected `,` or `:`
892+ case collectionMissingSeparator(offset: Int)
893+
894+ /// While parsing an object literal, a value was found without a key
895+ /// around `offset`. The start of a string literal was expected.
896+ case dictionaryMissingKey(offset: Int)
897+
898+ /// Badly-formed number with no digits around `offset`. After a decimal
899+ /// point, a number must include some number of digits.
900+ case numberMissingFractionalDigits(offset: Int)
901+
902+ /// Badly-formed number with symbols ("-" or "e") but no following
903+ /// digits around `offset`.
904+ case numberSymbolMissingDigits(offset: Int)
905+
906+ /// Supplied data is encoded in an unsupported format.
907+ case invalidUnicodeStreamEncoding(detectedEncoding: JSONEncodingDetector.Encoding)
908+ }
909+
910+ fileprivate enum InternalError: Swift.Error {
911+ /// Attempted to parse an integer outside the range of [Int.min, Int.max]
912+ /// or a double outside the range of representable doubles. Note that
913+ /// for doubles, this could be an overflow or an underflow - we don't
914+ /// get enough information from Swift here to know which it is. The number
915+ /// causing the overflow/underflow began at `offset`.
916+ case numberOverflow(offset: Int)
917+ }
918+}
tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONParsing.swiftnew file+126
@@ -0,0 +1,126 @@
1+//
2+// JSONParsing.swift
3+// Freddy
4+//
5+// Created by Matthew D. Mathias on 3/17/15.
6+// Copyright © 2015 Big Nerd Ranch. All rights reserved.
7+//
8+
9+import Foundation
10+
11+// MARK: - Deserialize JSON
12+
13+/// Protocol describing a backend parser that can produce `JSON` from `Data`.
14+public protocol JSONParserType {
15+
16+ /// Creates an instance of `JSON` from `Data`.
17+ /// - parameter data: An instance of `Data` to use to create `JSON`.
18+ /// - throws: An error that may arise from calling `JSONObjectWithData(_:options:)` on `NSJSONSerialization` with the given data.
19+ /// - returns: An instance of `JSON`.
20+ static func createJSON(from data: Data) throws -> JSON
21+
22+}
23+
24+extension JSON {
25+
26+ /// Create `JSON` from UTF-8 `data`. By default, parses using the
27+ /// Swift-native `JSONParser` backend.
28+ public init(data: Data, usingParser parser: JSONParserType.Type = JSONParser.self) throws {
29+ self = try parser.createJSON(from: data)
30+ }
31+
32+ /// Create `JSON` from UTF-8 `string`.
33+ public init(jsonString: Swift.String, usingParser parser: JSONParserType.Type = JSONParser.self) throws {
34+ self = try parser.createJSON(from: jsonString.data(using: Swift.String.Encoding.utf8) ?? Data())
35+ }
36+}
37+
38+// MARK: - NSJSONSerialization
39+
40+extension JSONSerialization: JSONParserType {
41+
42+ // MARK: Decode Data
43+
44+ /// Use the built-in, Objective-C based JSON parser to create `JSON`.
45+ /// - parameter data: An instance of `Data`.
46+ /// - returns: An instance of `JSON`.
47+ /// - throws: An error that may arise if the `Data` cannot be parsed into an object.
48+ public static func createJSON(from data: Data) throws -> JSON {
49+ return makeJSON(with: try JSONSerialization.jsonObject(with: data, options: []))
50+ }
51+
52+ // MARK: Make JSON
53+
54+ /// Makes a `JSON` object by matching its argument to a case in the `JSON` enum.
55+ /// - parameter object: The instance of `Any` returned from serializing the JSON.
56+ /// - returns: An instance of `JSON` matching the JSON given to the function.
57+ private static func makeJSON(with object: Any) -> JSON {
58+ switch object {
59+ case let n as NSNumber:
60+ let numberType = CFNumberGetType(n)
61+ switch numberType {
62+ case .charType:
63+ return .bool(n.boolValue)
64+
65+ case .shortType, .intType, .longType, .cfIndexType, .nsIntegerType, .sInt8Type, .sInt16Type, .sInt32Type:
66+ return .int(n.intValue)
67+
68+ case .sInt64Type, .longLongType /* overflows 32-bit Int */:
69+ #if /* 32-bit arch */ arch(arm) || arch(i386)
70+ // Why double, when the Freddy parser would bump to String?
71+ //
72+ // Returning Double avoids making the type depend on whether you're running
73+ // 32-bit or 64-bit code when using the NSJSONSerialization parser.
74+ // NSJSONSerialization appears to bump numbers larger than Int.max to Double on
75+ // 64-bit platforms but use .SInt64Type on 32-bit platforms.
76+ // If we returned a String here, you'd get a String value on 32-bit,
77+ // but a Double value on 64-bit. Instead, we return Double.
78+ //
79+ // This means that, if you switch parsers,
80+ // you'll have to switch from .double to .string for pulling out
81+ // overflowing values, but if you stick with a single parser,
82+ // you at least won't have architecture-dependent lookups!
83+ return .double(n.doubleValue)
84+ #else
85+ return .int(n.intValue)
86+ #endif
87+
88+ case .float32Type, .float64Type, .floatType, .doubleType, .cgFloatType:
89+ return .double(n.doubleValue)
90+ }
91+
92+ case let arr as [Any]:
93+ return makeJSONArray(arr)
94+
95+ case let dict as [Swift.String: Any]:
96+ return makeJSONDictionary(dict)
97+
98+ case let s as Swift.String:
99+ return .string(s)
100+
101+ default:
102+ return .null
103+ }
104+ }
105+
106+ // MARK: Make a JSON Array
107+
108+ /// Makes a `JSON` array from the object passed in.
109+ /// - parameter jsonArray: The array to transform into a `JSON`.
110+ /// - returns: An instance of `JSON` matching the array.
111+ private static func makeJSONArray(_ jsonArray: [Any]) -> JSON {
112+ return .array(jsonArray.map(makeJSON))
113+ }
114+
115+ // MARK: Make a JSON Dictionary
116+
117+ /// Makes a `JSON` dictionary from the Cocoa dictionary passed in.
118+ /// - parameter jsonDict: The dictionary to transform into `JSON`.
119+ /// - returns: An instance of `JSON` matching the dictionary.
120+ private static func makeJSONDictionary(_ jsonDict: [Swift.String: Any]) -> JSON {
121+ return JSON(jsonDict.lazy.map { (key, value) in
122+ (key, makeJSON(with: value))
123+ })
124+ }
125+
126+}
tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONSerializing.swiftnew file+54

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONSubscripting.swiftnew file+613

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/main.swiftnew file+40

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/bin/test_Freddy_2_1_0new file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/project.pbxprojnew file+300

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/project.xcworkspace/xcshareddata/test_Freddy.xcscmblueprintnew file+30

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_Freddy.xcschemenew file+91

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSON.swiftnew file+95

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSONDecodable.swiftnew file+151

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSONEncodable.swiftnew file+83

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSONEncodingDetector.swiftnew file+110

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSONLiteralConvertible.swiftnew file+130

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSONParser.swiftnew file+903

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSONParsing.swiftnew file+126

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSONSerializing.swiftnew file+43

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/JSONSubscripting.swiftnew file+643

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Freddy_2_1_0/test_Freddy/main.swiftnew file+37

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_JSONKit/JSONKit.hnew file+251

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_JSONKit/JSONKit.mnew file+3065

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_JSONKit/bin/test-JSONKitnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_JSONKit/test-JSONKit.xcodeproj/project.pbxprojnew file+252

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_JSONKit/test-JSONKit.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_JSONKit/test-JSONKit.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_JSONKit/test-JSONKit.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test-JSONKit.xcschemenew file+91

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_JSONKit/test-JSONKit.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_JSONKit/test-JSONKit/main.mnew file+73

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Json.NET/Program.csnew file+46

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Json.NET/bin/Release/netcoreapp1.0/publish/Newtonsoft.Json.dllnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Json.NET/bin/Release/netcoreapp1.0/publish/System.Runtime.Serialization.Primitives.dllnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Json.NET/bin/Release/netcoreapp1.0/publish/test_Json.NET.deps.jsonnew file+49

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Json.NET/bin/Release/netcoreapp1.0/publish/test_Json.NET.dllnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Json.NET/bin/Release/netcoreapp1.0/publish/test_Json.NET.pdbnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Json.NET/bin/Release/netcoreapp1.0/publish/test_Json.NET.runtimeconfig.jsonnew file+8

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Json.NET/project.jsonnew file+21

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Json.NET/project.lock.jsonnew file+6741

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Lua_JSON/JSON.luanew file+1451

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Lua_JSON/test_JSON.luanew file+22

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/bin/test_ObjCNSJSONSerializernew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/project.pbxprojnew file+246

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_ObjCNSJSONSerializer.xcschemenew file+97

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/a.outnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/a.out.dSYM/Contents/Info.plistnew file+20

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/a.out.dSYM/Contents/Resources/DWARF/a.outnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/findings_dir/plot_datanew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/main.mnew file+32

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/Accessors.swiftnew file+255

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/DecimalNumber.swiftnew file+236

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/Decoder.swiftnew file+294

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/Encoder.swiftnew file+167

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/JSON.swiftnew file+170

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/JSONError.swiftnew file+1619

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/JSONObject.swiftnew file+215

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/ObjectiveC.swiftnew file+233

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/Parser.swiftnew file+674

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/bin/test_PMJSONnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/test_PMJSON.xcodeproj/project.pbxprojnew file+296

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/test_PMJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/test_PMJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/test_PMJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_PMJSON.xcschemenew file+97

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/test_PMJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_1_0/test_PMJSON/main.swiftnew file+46

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/Accessors.swiftnew file+255

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/DecimalNumber.swiftnew file+236

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/Decoder.swiftnew file+502

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/Encoder.swiftnew file+215

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/JSON.swiftnew file+170

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/JSONError.swiftnew file+1619

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/JSONObject.swiftnew file+215

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/ObjectiveC.swiftnew file+331

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/Parser.swiftnew file+745

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/bin/test_PMJSONnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/test_PMJSON.xcodeproj/project.pbxprojnew file+296

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/test_PMJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/test_PMJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/test_PMJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_PMJSON.xcschemenew file+97

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/test_PMJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_PMJSON_1_2_0/test_PMJSON/main.swiftnew file+46

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/SBJson4.hnew file+35

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/SBJson4Parser.hnew file+248

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/SBJson4Parser.mnew file+287

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamParser.hnew file+131

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamParser.mnew file+317

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamParserState.hnew file+82

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamParserState.mnew file+355

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamTokeniser.hnew file+40

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamTokeniser.mnew file+395

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamWriter.hnew file+210

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamWriter.mnew file+358

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamWriterState.hnew file+69

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/SBJson4StreamWriterState.mnew file+147

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/SBJson4Writer.hnew file+103

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/SBJson4Writer.mnew file+102

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/bin/test_SBJSONnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_SBJSON/test_SBJSON.xcodeproj/project.pbxprojnew file+290

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/test_SBJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/test_SBJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_SBJSON/test_SBJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlistnew file+5

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/test_SBJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_SBJSON.xcschemenew file+91

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/test_SBJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_SBJSON/test_SBJSON/main.mnew file+38

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_STJSON/STJSON.xcodeproj/project.pbxprojnew file+361

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_STJSON/STJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_STJSON/STJSON.xcodeproj/project.xcworkspace/xcshareddata/STJSON.xcscmblueprintnew file+30

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_STJSON/STJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_STJSON/STJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/STJSON.xcschemenew file+91

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_STJSON/STJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/STJSONTests.xcschemenew file+56

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_STJSON/STJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+32

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_STJSON/STJSON/STJSONParser.swiftnew file+663

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_STJSON/STJSON/main.swiftnew file+47

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_STJSON/STJSONTests/Info.plistnew file+22

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_STJSON/STJSONTests/STJSONTests.swiftnew file+92

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_STJSON/bin/STJSONnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Info.plistnew file+563

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/MacOS/Squeaknew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/English.lproj/Localizable.stringsnew file+9

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/English.lproj/MainMenu.nibnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/Squeak.icnsnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/SqueakChanges.icnsnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/SqueakGeneric.icnsnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/SqueakImage.icnsnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/SqueakPlugin.icnsnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/SqueakProject.icnsnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/SqueakScript.icnsnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak.app/Contents/Resources/SqueakSources.icnsnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/Squeak5.1-16549-32bit.imagenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_Squeak_JSON_tonyg/test_JSON.stnew file+9

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_TouchJSON/bin/test_TouchJSONnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_TouchJSON/test_TouchJSON.xcodeproj/project.pbxprojnew file+262

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_TouchJSON/test_TouchJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_TouchJSON/test_TouchJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_TouchJSON/test_TouchJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_TouchJSON.xcschemenew file+97

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_TouchJSON/test_TouchJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_TouchJSON/test_TouchJSON/CJSONDeserializer.hnew file+96

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_TouchJSON/test_TouchJSON/CJSONDeserializer.mnew file+1240

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_TouchJSON/test_TouchJSON/main.mnew file+25

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_cJSON/bin/test-cJSONnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_cJSON/cJSON.cnew file+754

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_cJSON/cJSON.hnew file+153

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_cJSON/test-cJSON.xcodeproj/project.pbxprojnew file+257

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_cJSON/test-cJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_cJSON/test-cJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_cJSON/test-cJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlistnew file+5

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_cJSON/test-cJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test-cJSON.xcschemenew file+91

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_cJSON/test-cJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_cJSON/test-cJSON/main.cnew file+69

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/bin/test_ccannew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/common.hnew file+18

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_10.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_101.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_11.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_12.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_125.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_127.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_13.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_136.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_137.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_139.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_14.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_140.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_145.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_147.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_149.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_15.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_150.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_151.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_153.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_154.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_155.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_156.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_157.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_158.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_159.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_16.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_160.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_161.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_162.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_163.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_164.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_165.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_169.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_17.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_171.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_172.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_173.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_175.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_176.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_177.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_178.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_179.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_18.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_180.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_181.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_183.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_184.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_185.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_186.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_187.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_188.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_189.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_19.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_190.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_191.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_192.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_193.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_194.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_195.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_197.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_198.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_199.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_2.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_20.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_200.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_201.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_202.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_203.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_204.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_205.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_206.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_207.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_208.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_209.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_21.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_210.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_211.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_212.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_213.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_214.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_216.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_217.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_218.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_219.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_22.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_220.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_221.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_222.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_223.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_23.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_24.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_25.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_26.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_27.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_28.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_29.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_3.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_30.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_31.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_32.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_33.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_34.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_35.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_36.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_37.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_4.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_40.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_44.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_46.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_5.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_54.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_55.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_59.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_6.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_63.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_64.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_66.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_69.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_7.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_77.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_78.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_79.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_8.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_80.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_81.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_82.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_83.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_85.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_86.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_87.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_9.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/n_91.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_100.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_102.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_103.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_104.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_105.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_106.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_107.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_108.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_109.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_110.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_111.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_112.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_113.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_114.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_115.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_116.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_117.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_118.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_119.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_120.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_121.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_122.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_123.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_124.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_126.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_128.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_129.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_130.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_131.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_132.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_133.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_134.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_135.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_138.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_141.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_142.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_143.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_144.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_146.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_148.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_152.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_166.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_167.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_168.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_170.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_174.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_182.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_196.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_215.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_38.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_39.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_41.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_42.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_43.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_45.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_47.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_48.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_49.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_50.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_51.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_52.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_53.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_56.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_57.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_58.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_60.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_61.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_62.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_65.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_67.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_68.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_70.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_71.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_72.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_73.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_74.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_75.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_76.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_84.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_88.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_89.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_90.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_92.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_93.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_94.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_95.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_96.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_97.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_98.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/nst_files/y_99.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/run-construction.cnew file+191

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/run-decode-encode.cnew file+77

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/run-stringify.cnew file+108

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/run-validate.cnew file+49

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/test-stringsnew file+224

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/test-strings-reencodednew file+90

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/_test/x.pynew file+21

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/json.cnew file+1381

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/json/json.hnew file+117

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/project.pbxprojnew file+262

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_ccan.xcschemenew file+91

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_ccan_json/test_ccan/test_ccan/main.cnew file+44

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_dkjson.luanew file+25

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_go/test_jsonnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_go/test_json.gonew file+30

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_haskell-aeson/.gitignorenew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_haskell-aeson/package.yamlnew file+12

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_haskell-aeson/src/Main.hsnew file+29

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_haskell-aeson/stack.yamlnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_haskell-aeson/testaesonnew file+8

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_haskell-aeson/testaeson.cabalnew file+21

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/bin/test_janssonnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_jansson/dump.cnew file+467

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/error.cnew file+63

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/hashtable.cnew file+356

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/hashtable.hnew file+184

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/hashtable_seed.cnew file+277

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/jansson.hnew file+298

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/jansson_config.hnew file+43

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/jansson_private.hnew file+109

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/load.cnew file+1110

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/lookup3.hnew file+381

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/memory.cnew file+69

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/pack_unpack.cnew file+871

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/strbuffer.cnew file+111

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/strbuffer.hnew file+34

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/strconv.cnew file+145

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/test_jansson.xcodeproj/project.pbxprojnew file+309

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/test_jansson.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/test_jansson.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_jansson/test_jansson.xcodeproj/xcuserdata/nst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlistnew file+5

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/test_jansson.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_jansson.xcschemenew file+91

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/test_jansson.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/test_jansson/main.cnew file+208

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/utf.cnew file+187

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/utf.hnew file+27

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jansson/value.cnew file+1048

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_java_com_leastfixedpoint_json_1_0/META-INF/MANIFEST.MFnew file+3

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_java_com_leastfixedpoint_json_1_0/README.txtnew file+5

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_java_com_leastfixedpoint_json_1_0/TestJSONParsing.classnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_java_com_leastfixedpoint_json_1_0/TestJSONParsing.jarnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_java_com_leastfixedpoint_json_1_0/TestJSONParsing.javanew file+40

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_java_com_leastfixedpoint_json_1_0/com.leastfixedpoint.json-1.0.jarnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_java_gson_2_7/META-INF/MANIFEST.MFnew file+3

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_java_gson_2_7/README.txtnew file+5

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_java_gson_2_7/TestJSONParsing.classnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_java_gson_2_7/TestJSONParsing.jarnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_java_gson_2_7/TestJSONParsing.javanew file+51

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_java_gson_2_7/gson-2.7.jarnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_java_jackson_2_8_4/META-INF/MANIFEST.MFnew file+3

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_java_jackson_2_8_4/README.txtnew file+5

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_java_jackson_2_8_4/TestJSONParsing.classnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_java_jackson_2_8_4/TestJSONParsing.jarnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_java_jackson_2_8_4/TestJSONParsing.javanew file+48

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_java_jackson_2_8_4/jackson-annotations-2.2.3.jarnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_java_jackson_2_8_4/jackson-core-2.8.4.jarnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_java_jackson_2_8_4/jackson-databind-2.3.1.jarnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_java_nanojson_1_0/META-INF/MANIFEST.MFnew file+3

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_java_nanojson_1_0/README.txtnew file+5

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_java_nanojson_1_0/TestJSONParsing.classnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_java_nanojson_1_0/TestJSONParsing.jarnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_java_nanojson_1_0/TestJSONParsing.javanew file+45

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_java_nanojson_1_0/nanojson-1.0.jarnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_java_simple_json_1_1_1/META-INF/MANIFEST.MFnew file+3

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_java_simple_json_1_1_1/README.txtnew file+3

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_java_simple_json_1_1_1/TestJSONParsing.classnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_java_simple_json_1_1_1/TestJSONParsing.jarnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_java_simple_json_1_1_1/TestJSONParsing.javanew file+43

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_java_simple_json_1_1_1/json-simple-1.1.1.jarnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_jsmn/bin/test_jsmnnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_jsmn/jsmn.cnew file+311

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsmn/jsmn.hnew file+76

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/project.pbxprojnew file+253

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/xcuserdata/nst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlistnew file+23

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_jsmn.xcschemenew file+101

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsmn/test_jsmn/test_jsmn/main.cnew file+50

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-jq.pynew file+34

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-parser/bin/test_json-parsernew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_json-parser/test_json-parser.xcodeproj/project.pbxprojnew file+258

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-parser/test_json-parser.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-parser/test_json-parser.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_json-parser/test_json-parser.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_json-parser.xcschemenew file+91

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-parser/test_json-parser.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-parser/test_json-parser/json.cnew file+1011

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-parser/test_json-parser/json.hnew file+283

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-parser/test_json-parser/main.cnew file+66

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust-serde_json/rj/.gitignorenew file+2

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust-serde_json/rj/Cargo.tomlnew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust-serde_json/rj/READMEnew file+2

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust-serde_json/rj/src/main.rsnew file+30

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust/Cargo.locknew file+14

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust/Cargo.tomlnew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust/READMEnew file+2

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust/src/main.rsnew file+42

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/.cargo-locknew file

No changes to the content.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/json-74a82b4ec4439e90/dep-lib-jsonnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/json-74a82b4ec4439e90/lib-jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/json-74a82b4ec4439e90/lib-json.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-b5d63a9d8da2968e/bin-tjnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-b5d63a9d8da2968e/bin-tj.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-b5d63a9d8da2968e/dep-bin-tjnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-bb890ae6f101bb25/bin-tjnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-bb890ae6f101bb25/bin-tj.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-bb890ae6f101bb25/dep-bin-tjnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-bf24d0bdc8d0f4d6/bin-tjnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-bf24d0bdc8d0f4d6/bin-tj.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/.fingerprint/tj-bf24d0bdc8d0f4d6/dep-bin-tjnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/deps/libjson-6bbf4c11dd6d7c25.rlibnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/tjnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/tj.dSYM/Contents/Info.plistnew file+20

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rust/target/debug/tj.dSYM/Contents/Resources/DWARF/tjnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/Cargo.locknew file+14

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/Cargo.tomlnew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/READMEnew file+2

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/src/main.rsnew file+32

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.cargo-locknew file

No changes to the content.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-8f8b750d20f3bf10/bin-rjnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-8f8b750d20f3bf10/bin-rj.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-8f8b750d20f3bf10/dep-bin-rjnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-da0f8f63b87cf531/bin-rjnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-da0f8f63b87cf531/bin-rj.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-da0f8f63b87cf531/dep-bin-rjnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rustc-serialize-80c565222c5ccdbb/dep-lib-rustc-serializenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rustc-serialize-80c565222c5ccdbb/lib-rustc-serializenew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rustc-serialize-80c565222c5ccdbb/lib-rustc-serialize.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/deps/librustc_serialize-3561541d79c18212.rlibnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/rjnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/rj.dSYM/Contents/Info.plistnew file+20

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json-rustc_serialize/rj/target/debug/rj.dSYM/Contents/Resources/DWARF/rjnew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_json.crnew file+19

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json.jsnew file+13

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json.phpnew file+21

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json.plnew file+32

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json.pynew file+39

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json.rbnew file+23

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsonChecker/bin/jsonCheckernew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_jsonChecker/jsonChecker/JSON_checker.cnew file+400

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsonChecker/jsonChecker/JSON_checker.hnew file+13

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/project.pbxprojnew file+253

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/jsonChecker.xcschemenew file+91

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsonChecker/jsonChecker/jsonChecker/main.cnew file+53

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsonChecker2/FSM.rtfnew file+103

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsonChecker2/bin/jsonChecker2new file

Binary file not shown.

tests/JSONTestSuite/parsers/test_jsonChecker2/jsonChecker2/JSON_checker.cnew file+402

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsonChecker2/jsonChecker2/JSON_checker.hnew file+13

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsonChecker2/jsonChecker2/jsonChecker/main.cnew file+53

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/project.pbxprojnew file+253

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

tests/JSONTestSuite/parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/jsonChecker.xcschemenew file+97

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json_re.rbnew file+33

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_json_xs.plnew file+28

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_jsonlite.rnew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_oj_compat.rbnew file+25

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_oj_strict.rbnew file+25

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_qt/build.shnew file+4

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_qt/main.cppnew file+25

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_qt/test_qt.pronew file+12

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_rjson.rnew file+7

This diff is too big to show here.

tests/JSONTestSuite/parsers/test_yajl.rbnew file+24

This diff is too big to show here.

tests/JSONTestSuite/results/logs.txtnew file+2048

This diff is too big to show here.

tests/JSONTestSuite/results/parsing.htmlnew file+2816

This diff is too big to show here.

tests/JSONTestSuite/results/parsing_pruned.htmlnew file+2661

This diff is too big to show here.

tests/JSONTestSuite/results/pruned_results.pngnew file

Binary file not shown.

tests/JSONTestSuite/results/style.cssnew file+89

This diff is too big to show here.

tests/JSONTestSuite/results/transform.htmlnew file+1492

This diff is too big to show here.

tests/JSONTestSuite/run_tests.pynew file+673

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_object_key_lone_2nd_surrogate.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_string_1st_surrogate_but_2nd_missing.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_string_1st_valid_surrogate_2nd_invalid.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_string_UTF-16LE_with_BOM.jsonnew file

Binary file not shown.

tests/JSONTestSuite/test_parsing/i_string_UTF-8_invalid_sequence.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_string_incomplete_surrogate_and_escape_valid.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_string_incomplete_surrogate_pair.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_string_incomplete_surrogates_escape_valid.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_string_invalid_lonely_surrogate.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_string_invalid_surrogate.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_string_inverted_surrogates_U+1D11E.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_string_lone_second_surrogate.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_string_not_in_unicode_range.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_string_truncated-utf-8.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_string_unicode_U+10FFFE_nonchar.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_string_unicode_U+1FFFE_nonchar.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_string_unicode_U+FDD0_nonchar.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_string_unicode_U+FFFE_nonchar.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_structure_500_nested_arrays.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/i_structure_UTF-8_BOM_empty_object.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_1_true_without_comma.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_a_invalid_utf8.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_colon_instead_of_comma.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_comma_after_close.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_comma_and_number.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_double_comma.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_double_extra_comma.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_extra_close.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_extra_comma.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_incomplete.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_incomplete_invalid_value.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_inner_array_no_comma.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_invalid_utf8.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_items_separated_by_semicolon.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_just_comma.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_just_minus.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_missing_value.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_newlines_unclosed.jsonnew file+3

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_number_and_comma.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_number_and_several_commas.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_spaces_vertical_tab_formfeed.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_star_inside.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_unclosed.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_unclosed_trailing_comma.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_unclosed_with_new_lines.jsonnew file+3

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_array_unclosed_with_object_inside.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_incomplete_false.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_incomplete_null.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_incomplete_true.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_++.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_+1.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_+Inf.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_-01.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_-1.0..jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_-2..jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_-NaN.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_.-1.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_.2e-3.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_0.1.2.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_0.3e+.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_0.3e.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_0.e1.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_0_capital_E+.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_0_capital_E.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_0e+.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_0e.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_1.0e+.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_1.0e-.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_1.0e.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_1_000.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_1eE2.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_2.e+3.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_2.e-3.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_2.e3.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_9.e+.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_Inf.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_NaN.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_U+FF11_fullwidth_digit_one.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_expression.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_hex_1_digit.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_hex_2_digits.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_infinity.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_invalid+-.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_invalid-negative-real.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_invalid-utf-8-in-bigger-int.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_invalid-utf-8-in-exponent.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_invalid-utf-8-in-int.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_minus_infinity.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_minus_sign_with_trailing_garbage.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_minus_space_1.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_neg_int_starting_with_zero.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_neg_real_without_int_part.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_neg_with_garbage_at_end.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_real_garbage_after_e.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_real_with_invalid_utf8_after_e.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_real_without_fractional_part.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_starting_with_dot.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_then_00.jsonnew file

Binary file not shown.

tests/JSONTestSuite/test_parsing/n_number_with_alpha.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_with_alpha_char.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_number_with_leading_zero.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_bad_value.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_bracket_key.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_comma_instead_of_colon.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_double_colon.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_emoji.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_garbage_at_end.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_key_with_single_quotes.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_missing_colon.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_missing_key.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_missing_semicolon.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_missing_value.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_no-colon.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_non_string_key.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_non_string_key_but_huge_number_instead.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_pi_in_key_and_trailing_comma.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_repeated_null_null.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_several_trailing_commas.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_single_quote.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_trailing_comma.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_trailing_comment.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_trailing_comment_open.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_trailing_comment_slash_open.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_trailing_comment_slash_open_incomplete.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_two_commas_in_a_row.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_unquoted_key.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_unterminated-value.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_with_single_string.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_object_with_trailing_garbage.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_single_space.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_1_surrogate_then_escape u.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_1_surrogate_then_escape u1.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_1_surrogate_then_escape u1x.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_1_surrogate_then_escape.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_UTF8_surrogate_U+D800.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_accentuated_char_no_quotes.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_backslash_00.jsonnew file

Binary file not shown.

tests/JSONTestSuite/test_parsing/n_string_escape_x.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_escaped_backslash_bad.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_escaped_ctrl_char_tab.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_escaped_emoji.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_incomplete_escape.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_incomplete_escaped_character.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_incomplete_surrogate.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_incomplete_surrogate_escape_invalid.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_invalid-utf-8-in-escape.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_invalid_backslash_esc.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_invalid_unicode_escape.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_invalid_utf-8.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_invalid_utf8_after_escape.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_iso_latin_1.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_leading_uescaped_thinspace.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_lone_utf8_continuation_byte.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_no_quotes_with_bad_escape.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_overlong_sequence_2_bytes.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_overlong_sequence_6_bytes.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_overlong_sequence_6_bytes_null.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_single_doublequote.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_single_quote.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_single_string_no_double_quotes.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_start_escape_unclosed.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_unescaped_crtl_char.jsonnew file

Binary file not shown.

tests/JSONTestSuite/test_parsing/n_string_unescaped_newline.jsonnew file+2

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_unescaped_tab.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_unicode_CapitalU.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_string_with_trailing_garbage.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_..jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_100000_opening_arrays.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_U+2060_word_joined.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_UTF8_BOM_no_data.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_array_trailing_garbage.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_array_with_extra_array_close.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_array_with_unclosed_string.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_ascii-unicode-identifier.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_capitalized_True.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_close_unopened_array.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_comma_instead_of_closing_brace.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_double_array.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_end_array.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_incomplete_UTF8_BOM.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_lone-invalid-utf-8.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_lone-open-bracket.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_no_data.jsonnew file

No changes to the content.

tests/JSONTestSuite/test_parsing/n_structure_null-byte-outside-string.jsonnew file

Binary file not shown.

tests/JSONTestSuite/test_parsing/n_structure_null.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_number_with_trailing_garbage.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_object_followed_by_closing_object.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_object_unclosed_no_value.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_object_with_comment.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_object_with_trailing_garbage.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_open_array_apostrophe.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_open_array_comma.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_open_array_object.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_open_array_open_object.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_open_array_open_string.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_open_array_string.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_open_object.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_open_object_close_array.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_open_object_comma.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_open_object_open_array.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_open_object_open_string.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_open_object_string_with_apostrophes.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_open_open.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_single_point.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_single_star.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_trailing_#.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_uescaped_LF_before_string.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_unclosed_array.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_unclosed_array_partial_null.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_unclosed_array_unfinished_false.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_unclosed_array_unfinished_true.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_unclosed_object.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_unicode-identifier.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_whitespace_U+2060_word_joiner.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/n_structure_whitespace_formfeed.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_array_arraysWithSpaces.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_array_empty-string.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_array_empty.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_array_ending_with_newline.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_array_false.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_array_heterogeneous.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_array_null.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_array_with_1_and_newline.jsonnew file+2

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_array_with_leading_space.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_array_with_several_null.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_array_with_trailing_space.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_0e+1.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_0e1.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_after_space.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_double_close_to_zero.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_double_huge_neg_exp.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_huge_exp.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_int_with_exp.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_minus_zero.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_neg_int_huge_exp.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_negative_int.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_negative_one.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_negative_zero.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_pos_double_huge_exp.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_real_capital_e.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_real_capital_e_neg_exp.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_real_capital_e_pos_exp.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_real_exponent.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_real_fraction_exponent.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_real_neg_exp.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_real_neg_overflow.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_real_pos_exponent.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_real_pos_overflow.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_real_underflow.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_simple_int.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_simple_real.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_too_big_neg_int.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_too_big_pos_int.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_number_very_big_negative_int.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_object.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_object_basic.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_object_duplicated_key.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_object_duplicated_key_and_value.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_object_empty.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_object_empty_key.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_object_escaped_null_in_key.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_object_extreme_numbers.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_object_long_strings.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_object_simple.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_object_string_unicode.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_object_with_newlines.jsonnew file+3

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_1_2_3_bytes_UTF-8_sequences.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_accepted_surrogate_pair.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_accepted_surrogate_pairs.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_allowed_escapes.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_backslash_and_u_escaped_zero.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_backslash_doublequotes.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_comments.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_double_escape_a.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_double_escape_n.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_escaped_control_character.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_escaped_noncharacter.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_in_array.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_in_array_with_leading_space.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_last_surrogates_1_and_2.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_newline_uescaped.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_nonCharacterInUTF-8_U+10FFFF.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_nonCharacterInUTF-8_U+1FFFF.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_nonCharacterInUTF-8_U+FFFF.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_null_escape.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_one-byte-utf-8.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_pi.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_simple_ascii.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_space.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_three-byte-utf-8.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_two-byte-utf-8.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_u+2028_line_sep.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_u+2029_par_sep.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_uEscape.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_unescaped_char_delete.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_unicode.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_unicodeEscapedBackslash.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_unicode_2.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_unicode_U+2064_invisible_plus.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_unicode_escaped_double_quote.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_utf16BE_no_BOM.jsonnew file

Binary file not shown.

tests/JSONTestSuite/test_parsing/y_string_utf16LE_no_BOM.jsonnew file

Binary file not shown.

tests/JSONTestSuite/test_parsing/y_string_utf8.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_string_with_del_character.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_structure_lonely_false.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_structure_lonely_int.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_structure_lonely_negative_real.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_structure_lonely_null.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_structure_lonely_string.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_structure_lonely_true.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_structure_string_empty.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_structure_trailing_newline.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_structure_true_in_array.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_parsing/y_structure_whitespace_array.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/number_1.0.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/number_1.000000000000000005.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/number_1000000000000000.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/number_10000000000000000999.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/number_1e-999.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/number_1e6.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/object_key_nfc_nfd.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/object_key_nfd_nfc.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/object_same_key_different_values.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/object_same_key_same_value.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/object_same_key_unclear_values.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/string_1_escaped_invalid_codepoint.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/string_1_invalid_codepoint.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/string_2_escaped_invalid_codepoints.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/string_2_invalid_codepoints.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/string_3_escaped_invalid_codepoints.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/string_3_invalid_codepoints.jsonnew file+1

This diff is too big to show here.

tests/JSONTestSuite/test_transform/string_with_escaped_NULL.jsonnew file+1

This diff is too big to show here.

tests/Options.hs+33−1

This diff is too big to show here.

tests/PropUtils.hsnew file+208

This diff is too big to show here.

tests/Properties.hs+17−297

This diff is too big to show here.

tests/PropertyGeneric.hsnew file+116

This diff is too big to show here.

tests/PropertyKeys.hsnew file+40

This diff is too big to show here.

tests/PropertyRTFunctors.hsnew file+51

This diff is too big to show here.

tests/PropertyRoundTrip.hsnew file+74

This diff is too big to show here.

tests/PropertyTH.hsnew file+130

This diff is too big to show here.

tests/SerializationFormatSpec.hsnew file+294

This diff is too big to show here.

tests/Tests.hs+7−2

This diff is too big to show here.

tests/Types.hs+93−4

This diff is too big to show here.

tests/UnitTests.hs+459−110

This diff is too big to show here.

tests/UnitTests/NullaryConstructors.hs+14−3

This diff is too big to show here.

tests/golden/generic.expectednew file+48

This diff is too big to show here.

tests/golden/simple.expectednew file+22

This diff is too big to show here.

travis/cabal_macros.hnew file+448

This diff is too big to show here.

travis/install.sh+11

This diff is too big to show here.

travis/script.sh+8−1

This diff is too big to show here.