on master help sign in
1052 files changed+71716−4029
since splitsnapshots
unifiedsplit
.gitattributes+1 .gitignore+10 .hlint.yaml+11 .travis.yml+43−16 CONTRIBUTING.md+52 Data/Aeson.hs+82−12 Data/Aeson/Encode.hs+2−1 Data/Aeson/Encoding.hs+4−1 Data/Aeson/Encoding/Builder.hs+13−87 Data/Aeson/Encoding/Internal.hs+14−3 Data/Aeson/Internal.hs+1−1 Data/Aeson/Internal/Functions.hs+1−1 Data/Aeson/Internal/Time.hs+1−41 Data/Aeson/Parser.hs+13−4 Data/Aeson/Parser/Internal.hs+320−193 Data/Aeson/Parser/Time.hs+19−102 Data/Aeson/Parser/Unescape.hs+11 Data/Aeson/QQ/Simple.hs+25 Data/Aeson/TH.hs+447−897 Data/Aeson/Text.hs+5−4 Data/Aeson/Types.hs+49−5 Data/Aeson/Types/Class.hs+26−7 Data/Aeson/Types/FromJSON.hs+1079−464 Data/Aeson/Types/Generic.hs+12−8 Data/Aeson/Types/Internal.hs+175−26 Data/Aeson/Types/ToJSON.hs+729−546 Makefile+2 README.markdown+3−4 aeson.cabal+108−63 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−229 benchmarks/AesonEncode.hs+4−5 benchmarks/AesonFoldable.hs+14−42 benchmarks/AesonMap.hs+39−56 benchmarks/AesonParse.hs+3−5 benchmarks/AesonTuples.hs+1−2 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+10−5 benchmarks/Compare/BufferBuilder.hs+2−3 benchmarks/Compare/JsonBench.hs+18−10 benchmarks/Compare/JsonBuilder.hs+2−3 benchmarks/CompareWithJSON.hs+33−21 benchmarks/Dates.hs+10−9 benchmarks/Escape.hs+32 benchmarks/Issue673.hs+165 benchmarks/JsonParse.hs+3−2 benchmarks/Micro.hs+8−6 benchmarks/Options.hs+1−4 benchmarks/ReadFile.hs+2−2 benchmarks/Typed.hs+5−1 benchmarks/Typed/Common.hs+1−8 benchmarks/Typed/Generic.hs+27−25 benchmarks/Typed/Manual.hs+26−24 benchmarks/Typed/TH.hs+26−24 benchmarks/aeson-benchmarks.cabal+183−62 cabal.project+5 cbits/unescape_string.c+149 changelog.md+257−1 examples/Generic.hs+1−1 examples/Simplest.hs+1−1 examples/TemplateHaskell.hs+1−1 examples/Twitter.hs+4−2 examples/Twitter/Generic.hs+31−37 examples/Twitter/Manual.hs+3−136 examples/Twitter/Options.hs+10 examples/Twitter/TH.hs+7−19 ffi/Data/Aeson/Parser/UnescapeFFI.hs+52 include/incoherent-compat.h+7 pure/Data/Aeson/Parser/UnescapePure.hs+254 run-hlint.sh+7 stack-bench.yaml+10−6 stack-ffi-unescape.yaml+9 stack-lts12.yaml+15 stack-lts6.yaml−12 stack-nightly.yaml+6−7 tests/DataFamilies/Encoders.hs+2−2 tests/DataFamilies/Instances.hs+2−1 tests/DataFamilies/Properties.hs+6−5 tests/DataFamilies/Types.hs+2−2 tests/Encoders.hs+142−8 tests/ErrorMessages.hs+224 tests/Functions.hs+2−1 tests/Instances.hs+9−55 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+26−2 tests/PropUtils.hs+208 tests/Properties.hs+17−444 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+5−3 tests/Types.hs+70−5 tests/UnitTests.hs+424−240 tests/UnitTests/NullaryConstructors.hs+8−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+10
@@ -1,11 +1,21 @@
11dist
2+dist-newstyle
3+.ghc.environment.*
24.cabal-sandbox/
35cabal.sandbox.config
46.stack-work/
7+.stack-work-bench/
8+*.yaml.lock
59
610*.o
711*.hi
812*.nix
13+*.swp
14+.\#*
15+\#*
16+
17+# Emacs backup files
18+*~
919
1020benchmarks/AesonEncode
1121
.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.18 GHCVER=7.4.2
23− compiler: ": #GHC 7.4.2"
24− addons: {apt: {packages: [cabal-install-1.18,ghc-7.4.2], sources: [hvr-ghc]}}
25− - env: BUILD=cabal CABALVER=1.18 GHCVER=7.6.3
26− compiler: ": #GHC 7.6.3"
27− addons: {apt: {packages: [cabal-install-1.18,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 STACK_YAML=stack-bench.yaml
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.md+52
@@ -1,3 +1,17 @@
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+
115# Style guide
216
317* 4 space indentation
@@ -44,3 +58,41 @@ import Foo as F
4458import Qux (Q(..), q)
4559import qualified A
4660```
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+82−12
@@ -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
@@ -76,8 +89,8 @@ module Data.Aeson
7689 -- ** Generic JSON classes and options
7790 , GFromJSON(..)
7891 , FromArgs(..)
79− , GToJSON(..)
80− , GToEncoding(..)
92+ , GToJSON
93+ , GToEncoding
8194 , ToArgs(..)
8295 , Zero
8396 , One
@@ -87,15 +100,34 @@ module Data.Aeson
87100 , genericLiftToEncoding
88101 , genericParseJSON
89102 , genericLiftParseJSON
103+ -- ** Generic and TH encoding configuration
104+ , Options
90105 , 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
91123
92124 -- * Inspecting @'Value's@
93125 , withObject
94126 , withText
95127 , withArray
96− , withNumber
97128 , withScientific
98129 , withBool
130+ , withEmbeddedJSON
99131 -- * Constructors and accessors
100132 , Series
101133 , pairs
@@ -108,16 +140,16 @@ module Data.Aeson
108140 -- * Parsing
109141 , json
110142 , json'
143+ , parseIndexedJSON
111144 ) where
112145
113−import Prelude ()
114146import Prelude.Compat
115147
116−import Data.Aeson.Types.FromJSON (ifromJSON)
148+import Data.Aeson.Types.FromJSON (ifromJSON, parseIndexedJSON)
117149import Data.Aeson.Encoding (encodingToLazyByteString)
118150import Data.Aeson.Parser.Internal (decodeWith, decodeStrictWith, eitherDecodeWith, eitherDecodeStrictWith, jsonEOF, json, jsonEOF', json')
119151import Data.Aeson.Types
120−import Data.Aeson.Types.Internal (JSONPath, formatError)
152+import Data.Aeson.Types.Internal (JSONPath, formatError, (<?>))
121153import qualified Data.ByteString as B
122154import qualified Data.ByteString.Lazy as L
123155
@@ -127,6 +159,10 @@ import qualified Data.ByteString.Lazy as L
127159encode :: (ToJSON a) => a -> L.ByteString
128160encode = encodingToLazyByteString . toEncoding
129161
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+
130166-- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.
131167-- If this fails due to incomplete or invalid input, 'Nothing' is
132168-- returned.
@@ -153,6 +189,18 @@ decodeStrict :: (FromJSON a) => B.ByteString -> Maybe a
153189decodeStrict = decodeStrictWith jsonEOF fromJSON
154190{-# INLINE decodeStrict #-}
155191
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+
156204-- | Efficiently deserialize a JSON value from a lazy 'L.ByteString'.
157205-- If this fails due to incomplete or invalid input, 'Nothing' is
158206-- returned.
@@ -179,6 +227,18 @@ decodeStrict' :: (FromJSON a) => B.ByteString -> Maybe a
179227decodeStrict' = decodeStrictWith jsonEOF' fromJSON
180228{-# INLINE decodeStrict' #-}
181229
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+
182242eitherFormatError :: Either (JSONPath, String) a -> Either String a
183243eitherFormatError = either (Left . uncurry formatError) Right
184244{-# INLINE eitherFormatError #-}
@@ -194,6 +254,12 @@ eitherDecodeStrict =
194254 eitherFormatError . eitherDecodeStrictWith jsonEOF ifromJSON
195255{-# INLINE eitherDecodeStrict #-}
196256
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+
197263-- | Like 'decode'' but returns an error message when decoding fails.
198264eitherDecode' :: (FromJSON a) => L.ByteString -> Either String a
199265eitherDecode' = eitherFormatError . eitherDecodeWith jsonEOF' ifromJSON
@@ -205,6 +271,12 @@ eitherDecodeStrict' =
205271 eitherFormatError . eitherDecodeStrictWith jsonEOF' ifromJSON
206272{-# INLINE eitherDecodeStrict' #-}
207273
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+
208280-- $use
209281--
210282-- This section contains basic information on the different ways to
@@ -274,11 +346,9 @@ eitherDecodeStrict' =
274346-- > {-# LANGUAGE OverloadedStrings #-}
275347-- >
276348-- > instance FromJSON Person where
277−-- > parseJSON (Object v) = Person <$>
278−-- > v .: "name" <*>
279−-- > v .: "age"
280−-- > -- A non-Object value is of the wrong type, so fail.
281−-- > parseJSON _ = empty
349+-- > parseJSON = withObject "Person" $ \v -> Person
350+-- > <$> v .: "name"
351+-- > <*> v .: "age"
282352--
283353-- We can now parse the JSON data like so:
284354--
@@ -368,7 +438,7 @@ eitherDecodeStrict' =
368438-- The 'Object' type contains JSON objects:
369439--
370440-- > λ> decode "{\"name\":\"Dave\",\"age\":2}" :: Maybe Object
371−-- > Just (fromList) [("name",String "Dave"),("age",Number 2)]
441+-- > Just (fromList [("name",String "Dave"),("age",Number 2)])
372442--
373443-- You can extract values from it with a parser using 'parse',
374444-- 'parseEither' or, in this example, 'parseMaybe':
Data/Aeson/Encode.hs+2−1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12-- |
23-- Module: Data.Aeson.Encode
34-- Copyright: (c) 2012-2016 Bryan O'Sullivan
@@ -8,13 +9,13 @@
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" #-}
1214 (
1315 encode
1416 , encodeToTextBuilder
1517 ) where
1618
17−import Prelude ()
1819
1920import Data.ByteString.Lazy (ByteString)
2021import Data.Text.Lazy.Builder (Builder)
Data/Aeson/Encoding.hs+4−1
@@ -1,8 +1,10 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12-- |
23--
34-- Functions in this module return well-formed 'Encoding''.
45-- Polymorphic variants, which return @'Encoding' a@, return a textual JSON
56-- value, so it can be used as both @'Encoding'' 'Text'@ and @'Encoding' = 'Encoding'' 'Value'@.
7+
68module Data.Aeson.Encoding
79 (
810 -- * Encoding
@@ -14,6 +16,8 @@ module Data.Aeson.Encoding
1416 , Series
1517 , pairs
1618 , pair
19+ , pairStr
20+ , pair'
1721 -- * Predicates
1822 , nullEncoding
1923 -- * Encoding constructors
@@ -47,6 +51,5 @@ module Data.Aeson.Encoding
4751 , value
4852 ) where
4953
50−import Prelude ()
5154
5255import Data.Aeson.Encoding.Internal
Data/Aeson/Encoding/Builder.hs+13−87
@@ -1,7 +1,6 @@
11{-# LANGUAGE BangPatterns #-}
2−{-# LANGUAGE CPP #-}
3−{-# LANGUAGE OverloadedStrings #-}
4−
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE TupleSections #-}
54-- |
65-- Module: Data.Aeson.Encoding.Builder
76-- Copyright: (c) 2011 MailRank, Inc.
@@ -37,7 +36,6 @@ module Data.Aeson.Encoding.Builder
3736 , ascii5
3837 ) where
3938
40−import Prelude ()
4139import Prelude.Compat
4240
4341import Data.Aeson.Internal.Time
@@ -46,8 +44,9 @@ import Data.ByteString.Builder as B
4644import Data.ByteString.Builder.Prim as BP
4745import Data.ByteString.Builder.Scientific (scientificBuilder)
4846import Data.Char (chr, ord)
49−import Data.Monoid ((<>))
47+import Data.Semigroup ((<>))
5048import Data.Scientific (Scientific, base10Exponent, coefficient)
49+import Data.Text.Encoding (encodeUtf8BuilderEscaped)
5150import Data.Time (UTCTime(..))
5251import Data.Time.Calendar (Day(..), toGregorian)
5352import Data.Time.LocalTime
@@ -56,20 +55,6 @@ import qualified Data.HashMap.Strict as HMS
5655import qualified Data.Text as T
5756import qualified Data.Vector as V
5857
59−#if MIN_VERSION_bytestring(0,10,4)
60−import Data.Text.Encoding (encodeUtf8BuilderEscaped)
61−#else
62−import Data.Bits ((.&.))
63−import Data.Text.Internal (Text(..))
64−import Data.Text.Internal.Unsafe.Shift (shiftR)
65−import Foreign.Ptr (minusPtr, plusPtr)
66−import Foreign.Storable (poke)
67−import qualified Data.ByteString.Builder.Internal as B
68−import qualified Data.ByteString.Builder.Prim.Internal as BP
69−import qualified Data.Text.Array as A
70−import qualified Data.Text.Internal.Encoding.Utf16 as U16
71−#endif
72−
7358-- | Encode a JSON value to a "Data.ByteString" 'B.Builder'.
7459--
7560-- Use this function if you are encoding over the wire, or need to
@@ -148,7 +133,7 @@ c2w c = fromIntegral (ord c)
148133-- | Encode a JSON number.
149134scientific :: Scientific -> Builder
150135scientific s
151− | e < 0 = scientificBuilder s
136+ | e < 0 || e > 1024 = scientificBuilder s
152137 | otherwise = B.integerDec (coefficient s * 10 ^ e)
153138 where
154139 e = base10Exponent s
@@ -193,12 +178,13 @@ day dd = encodeYear yr <>
193178 !(T dh dl) = twoDigits d
194179 encodeYear y
195180 | y >= 1000 = B.integerDec y
196− | y > 0 =
197− let (ab,c) = fromIntegral y `quotRem` 10
198− (a,b) = ab `quotRem` 10
199− in BP.primBounded (ascii4 ('0',(digit a,(digit b,digit c)))) ()
200− | otherwise =
201− 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)))
202188{-# INLINE day #-}
203189
204190timeOfDay :: TimeOfDay -> Builder
@@ -215,7 +201,7 @@ timeOfDay64 (TOD h m s)
215201 !(T mh ml) = twoDigits m
216202 !(T sh sl) = twoDigits (fromIntegral real)
217203 (real,frac) = s `quotRem` pico
218− showFrac = (\x -> ('.', x)) >$< (BP.liftFixedToBounded BP.char7 >*< trunc12)
204+ showFrac = ('.',) >$< (BP.liftFixedToBounded BP.char7 >*< trunc12)
219205 trunc12 = (`quotRem` micro) >$<
220206 BP.condB (\(_,y) -> y == 0) (fst >$< trunc6) (digits6 >*< trunc6)
221207 digits6 = ((`quotRem` milli) . fromIntegral) >$< (digits3 >*< digits3)
@@ -233,7 +219,6 @@ timeOfDay64 (TOD h m s)
233219 pico = 1000000000000 -- number of picoseconds in 1 second
234220 micro = 1000000 -- number of microseconds in 1 second
235221 milli = 1000 -- number of milliseconds in 1 second
236−{-# INLINE timeOfDay64 #-}
237222
238223timeZone :: TimeZone -> Builder
239224timeZone (TimeZone off _ _)
@@ -269,62 +254,3 @@ twoDigits a = T (digit hi) (digit lo)
269254
270255digit :: Int -> Char
271256digit x = chr (x + 48)
272−
273−#if !(MIN_VERSION_bytestring(0,10,4))
274−-- | Encode text using UTF-8 encoding and escape the ASCII characters using
275−-- a 'BP.BoundedPrim'.
276−--
277−-- Use this function is to implement efficient encoders for text-based formats
278−-- like JSON or HTML.
279−{-# INLINE encodeUtf8BuilderEscaped #-}
280−-- TODO: Extend documentation with references to source code in @blaze-html@
281−-- or @aeson@ that uses this function.
282−encodeUtf8BuilderEscaped :: BP.BoundedPrim Word8 -> Text -> B.Builder
283−encodeUtf8BuilderEscaped be =
284− -- manual eta-expansion to ensure inlining works as expected
285− \txt -> B.builder (mkBuildstep txt)
286− where
287− bound = max 4 $ BP.sizeBound be
288−
289− mkBuildstep (Text arr off len) !k =
290− outerLoop off
291− where
292− iend = off + len
293−
294− outerLoop !i0 !br@(B.BufferRange op0 ope)
295− | i0 >= iend = k br
296− | outRemaining > 0 = goPartial (i0 + min outRemaining inpRemaining)
297− -- TODO: Use a loop with an integrated bound's check if outRemaining
298− -- is smaller than 8, as this will save on divisions.
299− | otherwise = return $ B.bufferFull bound op0 (outerLoop i0)
300− where
301− outRemaining = (ope `minusPtr` op0) `div` bound
302− inpRemaining = iend - i0
303−
304− goPartial !iendTmp = go i0 op0
305− where
306− go !i !op
307− | i < iendTmp = case A.unsafeIndex arr i of
308− w | w <= 0x7F -> do
309− BP.runB be (fromIntegral w) op >>= go (i + 1)
310− | w <= 0x7FF -> do
311− poke8 0 $ (w `shiftR` 6) + 0xC0
312− poke8 1 $ (w .&. 0x3f) + 0x80
313− go (i + 1) (op `plusPtr` 2)
314− | 0xD800 <= w && w <= 0xDBFF -> do
315− let c = ord $ U16.chr2 w (A.unsafeIndex arr (i+1))
316− poke8 0 $ (c `shiftR` 18) + 0xF0
317− poke8 1 $ ((c `shiftR` 12) .&. 0x3F) + 0x80
318− poke8 2 $ ((c `shiftR` 6) .&. 0x3F) + 0x80
319− poke8 3 $ (c .&. 0x3F) + 0x80
320− go (i + 2) (op `plusPtr` 4)
321− | otherwise -> do
322− poke8 0 $ (w `shiftR` 12) + 0xE0
323− poke8 1 $ ((w `shiftR` 6) .&. 0x3F) + 0x80
324− poke8 2 $ (w .&. 0x3F) + 0x80
325− go (i + 1) (op `plusPtr` 3)
326− | otherwise =
327− outerLoop i (B.BufferRange op ope)
328− where
329− poke8 j v = poke (op `plusPtr` j) (fromIntegral v :: Word8)
330−#endif
Data/Aeson/Encoding/Internal.hs+14−3
@@ -1,7 +1,9 @@
11{-# LANGUAGE DeriveDataTypeable #-}
22{-# LANGUAGE EmptyDataDecls #-}
3+{-# LANGUAGE NoImplicitPrelude #-}
34{-# LANGUAGE OverloadedStrings #-}
45{-# LANGUAGE RankNTypes #-}
6+
57module Data.Aeson.Encoding.Internal
68 (
79 -- * Encoding
@@ -13,6 +15,8 @@ module Data.Aeson.Encoding.Internal
1315 , Series (..)
1416 , pairs
1517 , pair
18+ , pairStr
19+ , pair'
1620 -- * Predicates
1721 , nullEncoding
1822 -- * Encoding constructors
@@ -53,7 +57,6 @@ module Data.Aeson.Encoding.Internal
5357 , comma, colon, openBracket, closeBracket, openCurly, closeCurly
5458 ) where
5559
56−import Prelude ()
5760import Prelude.Compat
5861
5962import Data.Aeson.Types.Internal (Value)
@@ -79,7 +82,7 @@ newtype Encoding' tag = Encoding {
7982 -- ^ Acquire the underlying bytestring builder.
8083 } deriving (Typeable)
8184
82−-- | Often used synonnym for 'Encoding''.
85+-- | Often used synonym for 'Encoding''.
8386type Encoding = Encoding' Value
8487
8588-- | Make Encoding from Builder.
@@ -122,7 +125,15 @@ data Series = Empty
122125 deriving (Typeable)
123126
124127pair :: Text -> Encoding -> Series
125−pair name val = Value $ retagEncoding $ 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
126137
127138instance Semigroup Series where
128139 Empty <> a = a
Data/Aeson/Internal.hs+1−1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12-- |
23-- Module: Data.Aeson.Internal
34-- Copyright: (c) 2015-2016 Bryan O'Sullivan
@@ -22,7 +23,6 @@ module Data.Aeson.Internal
2223 , iparse
2324 ) where
2425
25−import Prelude ()
2626
2727import Data.Aeson.Types.Internal
2828import Data.Aeson.Types.FromJSON (ifromJSON)
Data/Aeson/Internal/Functions.hs+1−1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12-- |
23-- Module: Data.Aeson.Functions
34-- Copyright: (c) 2011-2016 Bryan O'Sullivan
@@ -14,7 +15,6 @@ module Data.Aeson.Internal.Functions
1415 , mapKey
1516 ) where
1617
17−import Prelude ()
1818import Prelude.Compat
1919
2020import Data.Hashable (Hashable)
Data/Aeson/Internal/Time.hs+1−41
@@ -17,44 +17,4 @@ module Data.Aeson.Internal.Time
1717 , toTimeOfDay64
1818 ) where
1919
20−import Prelude ()
21−import Prelude.Compat
22−
23−import Data.Fixed (Pico)
24−import Data.Int (Int64)
25−import Data.Time
26−import Unsafe.Coerce (unsafeCoerce)
27−
28−#if MIN_VERSION_base(4,7,0)
29−
30−import Data.Fixed (Fixed(MkFixed))
31−
32−toPico :: Integer -> Pico
33−toPico = MkFixed
34−
35−fromPico :: Pico -> Integer
36−fromPico (MkFixed i) = i
37−
38−#else
39−
40−toPico :: Integer -> Pico
41−toPico = unsafeCoerce
42−
43−fromPico :: Pico -> Integer
44−fromPico = unsafeCoerce
45−
46−#endif
47−
48−-- | Like TimeOfDay, but using a fixed-width integer for seconds.
49−data TimeOfDay64 = TOD {-# UNPACK #-} !Int
50− {-# UNPACK #-} !Int
51− {-# UNPACK #-} !Int64
52−
53−diffTimeOfDay64 :: DiffTime -> TimeOfDay64
54−diffTimeOfDay64 t = TOD (fromIntegral h) (fromIntegral m) s
55− where (h,mp) = fromIntegral pico `quotRem` 3600000000000000
56− (m,s) = mp `quotRem` 60000000000000
57− pico = unsafeCoerce t :: Integer
58−
59−toTimeOfDay64 :: TimeOfDay -> TimeOfDay64
60−toTimeOfDay64 (TimeOfDay h m s) = TOD h m (fromIntegral (fromPico s))
20+import Data.Attoparsec.Time.Internal
Data/Aeson/Parser.hs+13−4
@@ -1,5 +1,4 @@
1−{-# LANGUAGE 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 Prelude ()
5059
51−import Data.Aeson.Parser.Internal (decodeStrictWith, decodeWith, eitherDecodeStrictWith, eitherDecodeWith, json, json', jstring, value, value')
60+import Data.Aeson.Parser.Internal
5261
5362-- $lazy
5463--
Data/Aeson/Parser/Internal.hs+320−193
@@ -1,10 +1,14 @@
11{-# LANGUAGE BangPatterns #-}
22{-# LANGUAGE CPP #-}
3+{-# LANGUAGE NoImplicitPrelude #-}
34{-# LANGUAGE OverloadedStrings #-}
45#if MIN_VERSION_ghc_prim(0,3,1)
56{-# LANGUAGE MagicHash #-}
67#endif
7−
8+#if __GLASGOW_HASKELL__ <= 710 && __GLASGOW_HASKELL__ >= 706
9+-- Work around a compiler bug
10+{-# OPTIONS_GHC -fsimpl-tick-factor=200 #-}
11+#endif
812-- |
913-- Module: Data.Aeson.Parser.Internal
1014-- Copyright: (c) 2011-2016 Bryan O'Sullivan
@@ -21,50 +25,56 @@ module Data.Aeson.Parser.Internal
2125 (
2226 -- * Lazy parsers
2327 json, jsonEOF
28+ , jsonWith
29+ , jsonLast
30+ , jsonAccum
31+ , jsonNoDup
2432 , value
2533 , jstring
34+ , jstring_
35+ , scientific
2636 -- * Strict parsers
2737 , json', jsonEOF'
38+ , jsonWith'
39+ , jsonLast'
40+ , jsonAccum'
41+ , jsonNoDup'
2842 , value'
2943 -- * Helpers
3044 , decodeWith
3145 , decodeStrictWith
3246 , eitherDecodeWith
3347 , eitherDecodeStrictWith
48+ -- ** Handling objects with duplicate keys
49+ , fromListAccum
50+ , parseListNoDup
3451 ) where
3552
36−import Prelude ()
3753import Prelude.Compat
3854
39−import Control.Monad.IO.Class (liftIO)
40−import Data.Aeson.Types.Internal (IResult(..), JSONPath, Result(..), Value(..))
41−import Data.Attoparsec.ByteString.Char8 (Parser, char, endOfInput, scientific, skipSpace, string)
42−import Data.Bits ((.|.), shiftL)
43−import Data.ByteString.Internal (ByteString(..))
44−import Data.Char (chr)
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)
4562import Data.Text (Text)
46−import Data.Text.Encoding (decodeUtf8')
47−import Data.Text.Internal.Encoding.Utf8 (ord2, ord3, ord4)
48−import Data.Text.Internal.Unsafe.Char (ord)
49−import Data.Vector as Vector (Vector, empty, fromList, reverse)
50−import Data.Word (Word8)
51−import Foreign.ForeignPtr (withForeignPtr)
52−import Foreign.Marshal.Utils (copyBytes)
53−import Foreign.Ptr (Ptr, minusPtr, plusPtr)
54−import Foreign.Storable (poke)
55−import System.IO.Unsafe (unsafePerformIO)
63+import Data.Vector (Vector)
64+import qualified Data.Vector as Vector (empty, fromList, fromListN, reverse)
5665import qualified Data.Attoparsec.ByteString as A
5766import qualified Data.Attoparsec.Lazy as L
58−import qualified Data.Attoparsec.Zepto as Z
5967import qualified Data.ByteString as B
60−import qualified Data.ByteString.Internal as B
61−import qualified Data.ByteString.Lazy as L
6268import qualified Data.ByteString.Unsafe as B
69+import qualified Data.ByteString.Lazy as L
6370import qualified Data.HashMap.Strict as H
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))
189254
190−-- | Strict version of 'value'. See also 'json''.
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
280+
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 -> copyBytes 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− copyBytes 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+19−102
@@ -1,15 +1,4 @@
1−{-# LANGUAGE BangPatterns #-}
2−{-# LANGUAGE ScopedTypeVariables #-}
3−
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.
1+{-# LANGUAGE NoImplicitPrelude #-}
132
143module Data.Aeson.Parser.Time
154 (
@@ -22,121 +11,51 @@ module Data.Aeson.Parser.Time
2211 , zonedTime
2312 ) where
2413
25−import Prelude ()
2614import Prelude.Compat
2715
28−import Control.Monad (void, when)
29−import Data.Aeson.Internal.Time (toPico)
30−import Data.Attoparsec.Text as A
31−import Data.Bits ((.&.))
32−import Data.Char (isDigit, ord)
33−import Data.Fixed (Pico)
34−import Data.Int (Int64)
35−import Data.Maybe (fromMaybe)
16+import Data.Attoparsec.Text (Parser)
3617import Data.Text (Text)
37−import Data.Time.Calendar (Day, fromGregorianValid)
18+import Data.Time.Calendar (Day)
3819import Data.Time.Clock (UTCTime(..))
3920import qualified Data.Aeson.Types.Internal as Aeson
40−import qualified Data.Text as T
21+import qualified Data.Attoparsec.Text as A
22+import qualified Data.Attoparsec.Time as T
4123import qualified Data.Time.LocalTime as Local
4224
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+447−897
@@ -13,6 +13,7 @@
1313{-# LANGUAGE TemplateHaskell #-}
1414#endif
1515
16+#include "incoherent-compat.h"
1617#include "overlapping-compat.h"
1718
1819{-|
@@ -84,7 +85,6 @@ $('deriveJSON' 'defaultOptions' ''(,,,))
8485@
8586
8687-}
87−
8888module Data.Aeson.TH
8989 (
9090 -- * Encoding configuration
@@ -116,49 +116,42 @@ module Data.Aeson.TH
116116 , mkLiftParseJSON2
117117 ) where
118118
119−import Prelude ()
120−import Prelude.Compat hiding (exp)
119+import Prelude.Compat
121120
122121import Control.Applicative ((<|>))
123−import Data.Aeson (Object, (.=), (.:), FromJSON(..), FromJSON1(..), FromJSON2(..), ToJSON(..), ToJSON1(..), ToJSON2(..))
122+import Data.Aeson (Object, (.:), FromJSON(..), FromJSON1(..), FromJSON2(..), ToJSON(..), ToJSON1(..), ToJSON2(..))
124123import Data.Aeson.Types (Options(..), Parser, SumEncoding(..), Value(..), defaultOptions, defaultTaggedObject)
125−import Data.Aeson.Types.Internal ((<?>), Pair, JSONPathElement(Key))
124+import Data.Aeson.Types.Internal ((<?>), JSONPathElement(Key))
126125import Data.Aeson.Types.FromJSON (parseOptionalFieldWith)
126+import Data.Aeson.Types.ToJSON (fromPairs, pair)
127127import Control.Monad (liftM2, unless, when)
128128import Data.Foldable (foldr')
129129#if MIN_VERSION_template_haskell(2,8,0) && !MIN_VERSION_template_haskell(2,10,0)
130130import Data.List (nub)
131131#endif
132−import Data.List (find, foldl', genericLength , intercalate , intersperse, partition, union)
132+import Data.List (foldl', genericLength, intercalate, partition, union)
133133import Data.List.NonEmpty ((<|), NonEmpty((:|)))
134134import Data.Map (Map)
135135import Data.Maybe (catMaybes, fromMaybe, mapMaybe)
136+import qualified Data.Monoid as Monoid
136137import Data.Set (Set)
137−#if MIN_VERSION_template_haskell(2,8,0)
138138import Language.Haskell.TH hiding (Arity)
139−#else
140−import Language.Haskell.TH
141−#endif
142−import Language.Haskell.TH.Syntax (VarStrictType)
143−#if MIN_VERSION_template_haskell(2,7,0) && !(MIN_VERSION_template_haskell(2,8,0))
144−import Language.Haskell.TH.Lib (starK)
145−#endif
139+import Language.Haskell.TH.Datatype
146140#if MIN_VERSION_template_haskell(2,8,0) && !(MIN_VERSION_template_haskell(2,10,0))
147141import Language.Haskell.TH.Syntax (mkNameG_tc)
148142#endif
149143import Text.Printf (printf)
150−import qualified Data.Aeson as A
151144import qualified Data.Aeson.Encoding.Internal as E
152145import qualified Data.Foldable as F (all)
153−import qualified Data.HashMap.Strict as H (lookup, toList)
154−import qualified Data.List.NonEmpty as NE (drop, length, reverse, splitAt)
155−import qualified Data.Map as M (fromList, findWithDefault, keys, lookup , singleton, size)
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(..))
156150import qualified Data.Set as Set (empty, insert, member)
157151import qualified Data.Text as T (Text, pack, unpack)
158−import qualified Data.Vector as V (unsafeIndex, null, length, create, fromList)
152+import qualified Data.Vector as V (unsafeIndex, null, length, create, empty)
159153import qualified Data.Vector.Mutable as VM (unsafeNew, unsafeWrite)
160154
161−
162155--------------------------------------------------------------------------------
163156-- Convenience
164157--------------------------------------------------------------------------------
@@ -252,8 +245,8 @@ deriveToJSONCommon :: JSONClass
252245 -> Name
253246 -- ^ Name of the type for which to generate an instance.
254247 -> Q [Dec]
255−deriveToJSONCommon = deriveJSONClass [ (ToJSON, \jc _ -> consToValue jc)
256− , (ToEncoding, \jc _ -> consToEncoding jc)
248+deriveToJSONCommon = deriveJSONClass [ (ToJSON, \jc _ -> consToValue Value jc)
249+ , (ToEncoding, \jc _ -> consToValue Encoding jc)
257250 ]
258251
259252-- | Generates a lambda expression which encodes the given data type or
@@ -283,7 +276,7 @@ mkToJSONCommon :: JSONClass -- ^ Which class's method is being derived.
283276 -> Options -- ^ Encoding options.
284277 -> Name -- ^ Name of the encoded type.
285278 -> Q Exp
286−mkToJSONCommon = mkFunCommon (\jc _ -> consToValue jc)
279+mkToJSONCommon = mkFunCommon (\jc _ -> consToValue Value jc)
287280
288281-- | Generates a lambda expression which encodes the given data type or
289282-- data family instance constructor as a JSON string.
@@ -312,413 +305,272 @@ mkToEncodingCommon :: JSONClass -- ^ Which class's method is being derived.
312305 -> Options -- ^ Encoding options.
313306 -> Name -- ^ Name of the encoded type.
314307 -> Q Exp
315−mkToEncodingCommon = mkFunCommon (\jc _ -> consToEncoding jc)
308+mkToEncodingCommon = mkFunCommon (\jc _ -> consToValue Encoding jc)
316309
317310-- | Helper function used by both 'deriveToJSON' and 'mkToJSON'. Generates
318−-- code to generate a 'Value' of a number of constructors. All constructors
319−-- must be from the same type.
320−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
321316 -- ^ The ToJSON variant being derived.
322317 -> Options
323318 -- ^ Encoding options.
324− -> [Con]
319+ -> [Type]
320+ -- ^ The types from the data type/data family instance declaration
321+ -> [ConstructorInfo]
325322 -- ^ Constructors for which to generate JSON generating code.
326323 -> Q Exp
327324
328−consToValue _ _ [] = error $ "Data.Aeson.TH.consToValue: "
329− ++ "Not a single constructor given!"
325+consToValue _ _ _ _ [] = error $ "Data.Aeson.TH.consToValue: "
326+ ++ "Not a single constructor given!"
330327
331−consToValue jc opts cons = do
328+consToValue target jc opts instTys cons = do
332329 value <- newName "value"
333330 tjs <- newNameList "_tj" $ arityInt jc
334331 tjls <- newNameList "_tjl" $ arityInt jc
335332 let zippedTJs = zip tjs tjls
336333 interleavedTJs = interleave tjs tjls
334+ lastTyVars = map varTToName $ drop (length instTys - arityInt jc) instTys
335+ tvMap = M.fromList $ zip lastTyVars zippedTJs
337336 lamE (map varP $ interleavedTJs ++ [value]) $
338− caseE (varE value) (matches zippedTJs)
337+ caseE (varE value) (matches tvMap)
339338 where
340− matches tjs = case cons of
339+ matches tvMap = case cons of
341340 -- A single constructor is directly encoded. The constructor itself may be
342341 -- forgotten.
343− [con] -> [argsToValue jc tjs opts False con]
342+ [con] | not (tagSingleConstructors opts) -> [argsToValue target jc tvMap opts False con]
344343 _ | allNullaryToStringTag opts && all isNullary cons ->
345− [ match (conP conName []) (normalB $ conStr opts conName) []
344+ [ match (conP conName []) (normalB $ conStr target opts conName) []
346345 | con <- cons
347− , let conName = getConName con
346+ , let conName = constructorName con
348347 ]
349− | otherwise -> [argsToValue jc tjs opts True con | con <- cons]
348+ | otherwise -> [argsToValue target jc tvMap opts True con | con <- cons]
350349
351−conStr :: Options -> Name -> Q Exp
352−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
353354
355+-- | Name of the constructor as a quoted 'Text'.
354356conTxt :: Options -> Name -> Q Exp
355−conTxt opts = appE [|T.pack|] . conStringE opts
356−
357−conStringE :: Options -> Name -> Q Exp
358−conStringE opts = stringE . constructorTagModifier opts . nameBase
359−
360−-- | Helper function used by both 'deriveToJSON' and 'mkToEncoding'. Generates
361−-- code to write out a value for a number of constructors. All constructors
362−-- must be from the same type.
363−consToEncoding :: JSONClass
364− -- ^ The ToJSON variant being derived.
365− -> Options
366− -- ^ Encoding options.
367− -> [Con]
368− -- ^ Constructors for which to generate JSON generating code.
369− -> Q Exp
370−
371−consToEncoding _ _ [] = error $ "Data.Aeson.TH.consToEncoding: "
372− ++ "Not a single constructor given!"
373−
374−consToEncoding jc opts cons = do
375− value <- newName "value"
376− tes <- newNameList "_te" $ arityInt jc
377− tels <- newNameList "_tel" $ arityInt jc
378− let zippedTEs = zip tes tels
379− interleavedTEs = interleave tes tels
380− lamE (map varP $ interleavedTEs ++ [value]) $
381− caseE (varE value) (matches zippedTEs)
382− where
383− matches tes = case cons of
384− -- A single constructor is directly encoded. The constructor itself may be
385− -- forgotten.
386− [con] -> [argsToEncoding jc tes opts False con]
387− -- Encode just the name of the constructor of a sum type iff all the
388− -- constructors are nullary.
389− _ | allNullaryToStringTag opts && all isNullary cons ->
390− [ match (conP conName [])
391− (normalB $ encStr opts conName) []
392− | con <- cons
393− , let conName = getConName con
394− ]
395− | otherwise -> [argsToEncoding jc tes opts True con | con <- cons]
357+conTxt opts = appE [|T.pack|] . stringE . conString opts
396358
397−encStr :: Options -> Name -> Q Exp
398−encStr opts = appE [|E.text|] . conTxt opts
359+-- | Name of the constructor.
360+conString :: Options -> Name -> String
361+conString opts = constructorTagModifier opts . nameBase
399362
400363-- | If constructor is nullary.
401−isNullary :: Con -> Bool
402−isNullary (NormalC _ []) = True
364+isNullary :: ConstructorInfo -> Bool
365+isNullary ConstructorInfo { constructorVariant = NormalConstructor
366+ , constructorFields = tys } = null tys
403367isNullary _ = False
404368
405−sumToValue :: Options -> Bool -> Name -> Q Exp -> Q Exp
406−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
407410 | multiCons =
408411 case sumEncoding opts of
409412 TwoElemArray ->
410− [|Array|] `appE` ([|V.fromList|] `appE` listE [conStr opts conName, exp])
413+ array target [conStr target opts conName, value]
411414 TaggedObject{tagFieldName, contentsFieldName} ->
412− [|A.object|] `appE` listE
413− [ infixApp [|T.pack tagFieldName|] [|(.=)|] (conStr opts conName)
414− , infixApp [|T.pack contentsFieldName|] [|(.=)|] exp
415− ]
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
416421 ObjectWithSingleField ->
417− [|A.object|] `appE` listE
418− [ infixApp (conTxt opts conName) [|(.=)|] exp
419− ]
420− UntaggedValue -> exp
421− | otherwise = exp
422−
423−nullarySumToValue :: Options -> Bool -> Name -> Q Exp
424−nullarySumToValue opts multiCons conName =
425− case sumEncoding opts of
426− TaggedObject{tagFieldName} ->
427− [|A.object|] `appE` listE
428− [ infixApp [|T.pack tagFieldName|] [|(.=)|] (conStr opts conName)
429− ]
430− UntaggedValue -> conStr opts conName
431− _ -> 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
432426
433427-- | Generates code to generate the JSON encoding of a single constructor.
434−argsToValue :: JSONClass -> [(Name, Name)] -> Options -> Bool -> Con -> Q Match
435−-- Nullary constructors. Generates code that explicitly matches against the
436−-- constructor even though it doesn't contain data. This is useful to prevent
437−-- type errors.
438−argsToValue jc tjs opts multiCons (NormalC conName []) = do
439− ([], _) <- reifyConTys jc tjs conName
440− match (conP conName [])
441− (normalB (nullarySumToValue opts multiCons conName))
442− []
428+argsToValue :: ToJSONFun -> JSONClass -> TyVarMap -> Options -> Bool -> ConstructorInfo -> Q Match
443429
444430-- Polyadic constructors with special case for unary constructors.
445−argsToValue jc tjs opts multiCons (NormalC conName ts) = do
446− (argTys, tvMap) <- reifyConTys jc tjs conName
447− 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'
448437 args <- newNameList "arg" len
449− js <- case [ dispatchToJSON jc conName tvMap argTy
450− `appE` varE arg
451− | (arg, argTy) <- zip args argTys
452− ] of
453− -- Single argument is directly converted.
454− [e] -> return e
455− -- Multiple arguments are converted to a JSON array.
456− es -> do
457− mv <- newName "mv"
458− let newMV = bindS (varP mv)
459− ([|VM.unsafeNew|] `appE`
460− litE (integerL $ fromIntegral len))
461− stmts = [ noBindS $
462− [|VM.unsafeWrite|] `appE`
463− varE mv `appE`
464− litE (integerL ix) `appE`
465− e
466− | (ix, e) <- zip [(0::Integer)..] es
467− ]
468− ret = noBindS $ [|return|] `appE` varE mv
469− return $ [|Array|] `appE`
470− (varE 'V.create `appE`
471− 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+
472447 match (conP conName $ map varP args)
473− (normalB $ sumToValue opts multiCons conName js)
448+ (normalB $ opaqueSumToValue target opts multiCons (null argTys') conName js)
474449 []
475450
476451-- Records.
477−argsToValue jc tjs opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts, not multiCons, ts) of
478− (True,True,[(_,st,ty)]) -> argsToValue jc tjs opts multiCons (NormalC conName [(st,ty)])
479− _ -> do
480− (argTys, tvMap) <- reifyConTys jc tjs conName
481− args <- newNameList "arg" $ length ts
482− let exp = [|A.object|] `appE` pairs
483−
484− pairs | omitNothingFields opts = infixApp maybeFields
485− [|(++)|]
486− restFields
487− | otherwise = listE $ map toPair argCons
488−
489− argCons = zip3 args argTys ts
490−
491− maybeFields = [|catMaybes|] `appE` listE (map maybeToPair maybes)
492−
493− restFields = listE $ map toPair rest
494−
495− (maybes, rest) = partition isMaybe argCons
496−
497− maybeToPair (arg, argTy, (field, _, _)) =
498− infixApp ([|keyValuePairWith|]
499− `appE` dispatchToJSON jc conName tvMap argTy
500− `appE` toFieldName field)
501− [|(<$>)|]
502− (varE arg)
503−
504− toPair (arg, argTy, (field, _, _)) =
505− [|keyValuePairWith|]
506− `appE` dispatchToJSON jc conName tvMap argTy
507− `appE` toFieldName field
508− `appE` varE arg
509−
510− toFieldName field = [|T.pack|] `appE` fieldLabelExp opts field
511−
512− match (conP conName $ map varP args)
513− ( normalB
514− $ if multiCons
515− then case sumEncoding opts of
516− TwoElemArray -> [|toJSON|] `appE` tupE [conStr opts conName, exp]
517− TaggedObject{tagFieldName} ->
518− [|A.object|] `appE`
519− -- TODO: Maybe throw an error in case
520− -- tagFieldName overwrites a field in pairs.
521− infixApp (infixApp [|T.pack tagFieldName|]
522− [|(.=)|]
523− (conStr opts conName))
524− [|(:)|]
525− pairs
526− ObjectWithSingleField ->
527− [|A.object|] `appE` listE
528− [ infixApp (conTxt opts conName) [|(.=)|] exp ]
529− UntaggedValue -> exp
530− else exp
531− ) []
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+ []
532493
533494-- Infix constructors.
534−argsToValue jc tjs opts multiCons (InfixC _ conName _) = do
535− ([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
536500 al <- newName "argL"
537501 ar <- newName "argR"
538502 match (infixP (varP al) conName (varP ar))
539503 ( normalB
540− $ sumToValue opts multiCons conName
541− $ [|toJSON|] `appE` listE [ dispatchToJSON jc conName tvMap aTy
542− `appE` varE a
543− | (a, aTy) <- [(al,alTy), (ar,arTy)]
544− ]
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+ ]
545510 )
546511 []
547−-- Existentially quantified constructors.
548−argsToValue jc tjs opts multiCons (ForallC _ _ con) =
549− argsToValue jc tjs opts multiCons con
550512
551−#if MIN_VERSION_template_haskell(2,11,0)
552−-- GADTs.
553−argsToValue jc tjs opts multiCons (GadtC conNames ts _) =
554− 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
555516
556−argsToValue jc tjs opts multiCons (RecGadtC conNames ts _) =
557− argsToValue jc tjs opts multiCons $ RecC (head conNames) ts
558−#endif
517+isOption :: (a, Type, b) -> Bool
518+isOption (_, AppT (ConT t) _, _) = t == ''Semigroup.Option
519+isOption _ = False
559520
560−isMaybe :: (a, b, (c, d, Type)) -> Bool
561−isMaybe (_, _, (_, _, AppT (ConT t) _)) = t == ''Maybe
562−isMaybe _ = False
521+optionToMaybe :: (ExpQ, b, c) -> (ExpQ, b, c)
522+optionToMaybe (a, b, c) = ([|Semigroup.getOption|] `appE` a, b, c)
563523
564524(<^>) :: ExpQ -> ExpQ -> ExpQ
565525(<^>) a b = infixApp a [|(E.><)|] b
566526infixr 6 <^>
567527
568−(<:>) :: ExpQ -> ExpQ -> ExpQ
569−(<:>) a b = a <^> [|E.colon|] <^> b
570−infixr 5 <:>
571−
572528(<%>) :: ExpQ -> ExpQ -> ExpQ
573529(<%>) a b = a <^> [|E.comma|] <^> b
574530infixr 4 <%>
575531
576−array :: ExpQ -> ExpQ
577−array exp = [|E.wrapArray|] `appE` exp
578−
579−object :: ExpQ -> ExpQ
580−object exp = [|E.wrapObject|] `appE` exp
581−
582−sumToEncoding :: Options -> Bool -> Name -> Q Exp -> Q Exp
583−sumToEncoding opts multiCons conName exp
584− | multiCons =
585− let fexp = exp in
586− case sumEncoding opts of
587− TwoElemArray ->
588− array (encStr opts conName <%> fexp)
589− TaggedObject{tagFieldName, contentsFieldName} ->
590− object $
591− ([|E.text (T.pack tagFieldName)|] <:> encStr opts conName) <%>
592− ([|E.text (T.pack contentsFieldName)|] <:> fexp)
593− ObjectWithSingleField ->
594− object (encStr opts conName <:> fexp)
595− UntaggedValue -> exp
596− | otherwise = exp
597−
598−nullarySumToEncoding :: Options -> Bool -> Name -> Q Exp
599−nullarySumToEncoding opts multiCons conName =
600− case sumEncoding opts of
601− TaggedObject{tagFieldName} ->
602− object $
603− [|E.text (T.pack tagFieldName)|] <:> encStr opts conName
604− UntaggedValue -> encStr opts conName
605− _ -> sumToEncoding opts multiCons conName [e|toEncoding ([] :: [()])|]
606−
607−-- | Generates code to generate the JSON encoding of a single constructor.
608−argsToEncoding :: JSONClass -> [(Name, Name)] -> Options -> Bool -> Con -> Q Match
609−-- Nullary constructors. Generates code that explicitly matches against the
610−-- constructor even though it doesn't contain data. This is useful to prevent
611−-- type errors.
612−argsToEncoding jc tes opts multiCons (NormalC conName []) = do
613− ([], _) <- reifyConTys jc tes conName
614− match (conP conName [])
615− (normalB (nullarySumToEncoding opts multiCons conName))
616− []
617−
618−-- Polyadic constructors with special case for unary constructors.
619−argsToEncoding jc tes opts multiCons (NormalC conName ts) = do
620− (argTys, tvMap) <- reifyConTys jc tes conName
621− let len = length ts
622− args <- newNameList "arg" len
623− js <- case zip args argTys of
624− -- Single argument is directly converted.
625− [(e,eTy)] -> return (dispatchToEncoding jc conName tvMap eTy
626− `appE` varE e)
627− -- Multiple arguments are converted to a JSON array.
628− es ->
629− return (array (foldr1 (<%>) [ dispatchToEncoding jc conName tvMap xTy
630− `appE` varE x
631− | (x,xTy) <- es
632− ]))
633− match (conP conName $ map varP args)
634− (normalB $ sumToEncoding opts multiCons conName js)
635− []
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]))
636553
637−-- Records.
638−argsToEncoding jc tes opts multiCons (RecC conName ts) = case (unwrapUnaryRecords opts, not multiCons, ts) of
639− (True,True,[(_,st,ty)]) -> argsToEncoding jc tes opts multiCons (NormalC conName [(st,ty)])
640− _ -> do
641− args <- newNameList "arg" $ length ts
642− (argTys, tvMap) <- reifyConTys jc tes conName
643− let exp = object objBody
644−
645− objBody = [|E.econcat|] `appE`
646− ([|intersperse E.comma|] `appE` pairs)
647− pairs | omitNothingFields opts = infixApp maybeFields
648− [|(++)|]
649− restFields
650− | otherwise = listE (map toPair argCons)
651−
652− argCons = zip3 args argTys ts
653−
654− maybeFields = [|catMaybes|] `appE` listE (map maybeToPair maybes)
655−
656− restFields = listE (map toPair rest)
657−
658− (maybes, rest) = partition isMaybe argCons
659−
660− maybeToPair (arg, argTy, (field, _, _)) =
661− infixApp
662− (infixApp
663− (infixE
664− (Just $ toFieldName field <^> [|E.colon|])
665− [|(E.><)|]
666− Nothing)
667− [|(.)|]
668− (dispatchToEncoding jc conName tvMap argTy))
669− [|(<$>)|]
670− (varE arg)
671−
672− toPair (arg, argTy, (field, _, _)) =
673− toFieldName field
674− <:> dispatchToEncoding jc conName tvMap argTy
675− `appE` varE arg
676−
677− toFieldName field = [|E.text|] `appE`
678− ([|T.pack|] `appE` fieldLabelExp opts field)
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)
679557
680− match (conP conName $ map varP args)
681− ( normalB
682− $ if multiCons
683− then case sumEncoding opts of
684− TwoElemArray -> array $
685− encStr opts conName <%> exp
686− TaggedObject{tagFieldName} -> object $
687− ([|E.text (T.pack tagFieldName)|] <:>
688− encStr opts conName) <%>
689− objBody
690− ObjectWithSingleField -> object $
691− encStr opts conName <:> exp
692− UntaggedValue -> exp
693− else exp
694− ) []
695−
696−-- Infix constructors.
697−argsToEncoding jc tes opts multiCons (InfixC _ conName _) = do
698− al <- newName "argL"
699− ar <- newName "argR"
700− ([alTy,arTy], tvMap) <- reifyConTys jc tes conName
701− match (infixP (varP al) conName (varP ar))
702− ( normalB
703− $ sumToEncoding opts multiCons conName
704− $ array (foldr1 (<%>) [ dispatchToEncoding jc conName tvMap aTy
705− `appE` varE a
706− | (a,aTy) <- [(al,alTy), (ar,arTy)]
707− ])
708− )
709− []
710−-- Existentially quantified constructors.
711−argsToEncoding jc tes opts multiCons (ForallC _ _ con) =
712− 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)
713565
714−#if MIN_VERSION_template_haskell(2,11,0)
715−-- GADTs.
716−argsToEncoding jc tes opts multiCons (GadtC conNames ts _) =
717− argsToEncoding jc tes opts multiCons $ NormalC (head conNames) ts
566+fromPairsE :: ExpQ -> ExpQ
567+fromPairsE = ([|fromPairs|] `appE`)
718568
719−argsToEncoding jc tes opts multiCons (RecGadtC conNames ts _) =
720− argsToEncoding jc tes opts multiCons $ RecC (head conNames) ts
721−#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
722574
723575--------------------------------------------------------------------------------
724576-- FromJSON
@@ -802,31 +654,41 @@ consFromJSON :: JSONClass
802654 -- ^ Name of the type to which the constructors belong.
803655 -> Options
804656 -- ^ Encoding options
805− -> [Con]
657+ -> [Type]
658+ -- ^ The types from the data type/data family instance declaration
659+ -> [ConstructorInfo]
806660 -- ^ Constructors for which to generate JSON parsing code.
807661 -> Q Exp
808662
809−consFromJSON _ _ _ [] = error $ "Data.Aeson.TH.consFromJSON: "
810− ++ "Not a single constructor given!"
663+consFromJSON _ _ _ _ [] = error $ "Data.Aeson.TH.consFromJSON: "
664+ ++ "Not a single constructor given!"
811665
812−consFromJSON jc tName opts cons = do
666+consFromJSON jc tName opts instTys cons = do
813667 value <- newName "value"
814668 pjs <- newNameList "_pj" $ arityInt jc
815669 pjls <- newNameList "_pjl" $ arityInt jc
816670 let zippedPJs = zip pjs pjls
817671 interleavedPJs = interleave pjs pjls
818− 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
819675
820676 where
821− lamExpr value pjs = case cons of
822− [con] -> parseArgs jc pjs tName opts con (Right 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)
823685 _ | sumEncoding opts == UntaggedValue
824− -> parseUntaggedValue pjs cons value
686+ -> parseUntaggedValue tvMap cons value
825687 | otherwise
826688 -> caseE (varE value) $
827689 if allNullaryToStringTag opts && all isNullary cons
828690 then allNullaryMatches
829− else mixedMatches pjs
691+ else mixedMatches tvMap
830692
831693 allNullaryMatches =
832694 [ do txt <- newName "txt"
@@ -835,12 +697,11 @@ consFromJSON jc tName opts cons = do
835697 [ liftM2 (,) (normalG $
836698 infixApp (varE txt)
837699 [|(==)|]
838− ([|T.pack|] `appE`
839− conStringE opts conName)
700+ (conTxt opts conName)
840701 )
841702 ([|pure|] `appE` conE conName)
842703 | con <- cons
843− , let conName = getConName con
704+ , let conName = constructorName con
844705 ]
845706 ++
846707 [ liftM2 (,)
@@ -861,13 +722,13 @@ consFromJSON jc tName opts cons = do
861722 []
862723 ]
863724
864− mixedMatches pjs =
725+ mixedMatches tvMap =
865726 case sumEncoding opts of
866727 TaggedObject {tagFieldName, contentsFieldName} ->
867− parseObject $ parseTaggedObject pjs tagFieldName contentsFieldName
728+ parseObject $ parseTaggedObject tvMap tagFieldName contentsFieldName
868729 UntaggedValue -> error "UntaggedValue: Should be handled already"
869730 ObjectWithSingleField ->
870− parseObject $ parseObjectWithSingleField pjs
731+ parseObject $ parseObjectWithSingleField tvMap
871732 TwoElemArray ->
872733 [ do arr <- newName "array"
873734 match (conP 'Array [varP arr])
@@ -875,7 +736,7 @@ consFromJSON jc tName opts cons = do
875736 [ liftM2 (,) (normalG $ infixApp ([|V.length|] `appE` varE arr)
876737 [|(==)|]
877738 (litE $ integerL 2))
878− (parse2ElemArray pjs arr)
739+ (parse2ElemArray tvMap arr)
879740 , liftM2 (,) (normalG [|otherwise|])
880741 ([|not2ElemArray|]
881742 `appE` litE (stringL $ show tName)
@@ -906,25 +767,29 @@ consFromJSON jc tName opts cons = do
906767 []
907768 ]
908769
909− parseTaggedObject pjs typFieldName valFieldName obj = do
770+ parseTaggedObject tvMap typFieldName valFieldName obj = do
910771 conKey <- newName "conKey"
911772 doE [ bindS (varP conKey)
912773 (infixApp (varE obj)
913774 [|(.:)|]
914775 ([|T.pack|] `appE` stringE typFieldName))
915− , noBindS $ parseContents pjs conKey (Left (valFieldName, obj)) 'conNotFoundFailTaggedObject
776+ , noBindS $ parseContents tvMap conKey (Left (valFieldName, obj)) 'conNotFoundFailTaggedObject
916777 ]
917778
918− parseUntaggedValue pjs cons' conVal =
779+ parseUntaggedValue tvMap cons' conVal =
919780 foldr1 (\e e' -> infixApp e [|(<|>)|] e')
920− (map (\x -> parseValue pjs x conVal) cons')
781+ (map (\x -> parseValue tvMap x conVal) cons')
921782
922− parseValue _pjs (NormalC conName []) conVal = do
783+ parseValue _tvMap
784+ ConstructorInfo { constructorName = conName
785+ , constructorVariant = NormalConstructor
786+ , constructorFields = [] }
787+ conVal = do
923788 str <- newName "str"
924789 caseE (varE conVal)
925790 [ match (conP 'String [varP str])
926791 (guardedB
927− [ liftM2 (,) (normalG $ infixApp (varE str) [|(==)|] ([|T.pack|] `appE` conStringE opts conName)
792+ [ liftM2 (,) (normalG $ infixApp (varE str) [|(==)|] (conTxt opts conName)
928793 )
929794 ([|pure|] `appE` conE conName)
930795 ]
@@ -932,11 +797,11 @@ consFromJSON jc tName opts cons = do
932797 []
933798 , matchFailed tName conName "String"
934799 ]
935− parseValue pjs con conVal =
936− parseArgs jc pjs tName opts con (Right conVal)
800+ parseValue tvMap con conVal =
801+ checkExi tvMap con $ parseArgs jc tvMap tName opts con (Right conVal)
937802
938803
939− parse2ElemArray pjs arr = do
804+ parse2ElemArray tvMap arr = do
940805 conKey <- newName "conKey"
941806 conVal <- newName "conVal"
942807 let letIx n ix =
@@ -951,7 +816,7 @@ consFromJSON jc tName opts cons = do
951816 (caseE (varE conKey)
952817 [ do txt <- newName "txt"
953818 match (conP 'String [varP txt])
954− (normalB $ parseContents pjs
819+ (normalB $ parseContents tvMap
955820 txt
956821 (Right conVal)
957822 'conNotFoundFail2ElemArray
@@ -968,12 +833,12 @@ consFromJSON jc tName opts cons = do
968833 ]
969834 )
970835
971− parseObjectWithSingleField pjs obj = do
836+ parseObjectWithSingleField tvMap obj = do
972837 conKey <- newName "conKey"
973838 conVal <- newName "conVal"
974839 caseE ([e|H.toList|] `appE` varE obj)
975840 [ match (listP [tupP [varP conKey, varP conVal]])
976− (normalB $ parseContents pjs conKey (Right conVal) 'conNotFoundFailObjectSingleField)
841+ (normalB $ parseContents tvMap conKey (Right conVal) 'conNotFoundFailObjectSingleField)
977842 []
978843 , do other <- newName "other"
979844 match (varP other)
@@ -984,7 +849,7 @@ consFromJSON jc tName opts cons = do
984849 []
985850 ]
986851
987− parseContents pjs conKey contents errorFun =
852+ parseContents tvMap conKey contents errorFun =
988853 caseE (varE conKey)
989854 [ match wildP
990855 ( guardedB $
@@ -992,7 +857,8 @@ consFromJSON jc tName opts cons = do
992857 [|(==)|]
993858 ([|T.pack|] `appE`
994859 conNameExp opts con)
995− e <- parseArgs jc pjs tName opts con contents
860+ e <- checkExi tvMap con $
861+ parseArgs jc tvMap tName opts con contents
996862 return (g, e)
997863 | con <- cons
998864 ]
@@ -1005,7 +871,7 @@ consFromJSON jc tName opts cons = do
1005871 . stringL
1006872 . constructorTagModifier opts
1007873 . nameBase
1008− . getConName
874+ . constructorName
1009875 ) cons
1010876 )
1011877 `appE` ([|T.unpack|] `appE` varE conKey)
@@ -1054,22 +920,42 @@ parseRecord :: JSONClass
1054920 -> Options
1055921 -> Name
1056922 -> Name
1057− -> [VarStrictType]
923+ -> [Name]
1058924 -> Name
925+ -> Bool
1059926 -> ExpQ
1060−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) $
1061931 foldl' (\a b -> infixApp a [|(<*>)|] b)
1062932 (infixApp (conE conName) [|(<$>)|] x)
1063933 xs
1064934 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+ ]
1065951 x:xs = [ [|lookupField|]
1066952 `appE` dispatchParseJSON jc conName tvMap argTy
1067953 `appE` litE (stringL $ show tName)
1068954 `appE` litE (stringL $ constructorTagModifier opts $ nameBase conName)
1069955 `appE` varE obj
1070− `appE` ( [|T.pack|] `appE` fieldLabelExp opts field
956+ `appE` ( [|T.pack|] `appE` stringE (fieldLabel opts field)
1071957 )
1072− | ((field, _, _), argTy) <- zip ts argTys
958+ | (field, argTy) <- zip fields argTys
1073959 ]
1074960
1075961getValField :: Name -> String -> [MatchQ] -> Q Exp
@@ -1088,67 +974,82 @@ matchCases (Right valName) = caseE (varE valName)
1088974
1089975-- | Generates code to parse the JSON encoding of a single constructor.
1090976parseArgs :: JSONClass -- ^ The FromJSON variant being derived.
1091− -> [(Name, Name)] -- ^ The names of the encoding/decoding function arguments.
977+ -> TyVarMap -- ^ Maps the last type variables to their decoding
978+ -- function arguments.
1092979 -> Name -- ^ Name of the type to which the constructor belongs.
1093980 -> Options -- ^ Encoding options.
1094− -> Con -- ^ Constructor for which to generate JSON parsing code.
981+ -> ConstructorInfo -- ^ Constructor for which to generate JSON parsing code.
1095982 -> Either (String, Name) Name -- ^ Left (valFieldName, objName) or
1096983 -- Right valName
1097984 -> Q Exp
1098985-- Nullary constructors.
1099−parseArgs jc pjs _ _ (NormalC conName []) (Left _) = do
1100− ([], _) <- reifyConTys jc pjs conName
1101− [|pure|] `appE` conE conName
1102−parseArgs jc pjs tName _ (NormalC conName []) (Right valName) = do
1103− ([], _) <- reifyConTys jc pjs conName
1104− 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
1105998
1106999-- Unary constructors.
1107−parseArgs jc pjs _ _ (NormalC conName [_]) contents = do
1108− ([argTy], tvMap) <- reifyConTys jc pjs conName
1109− 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
11101007
11111008-- Polyadic constructors.
1112−parseArgs jc pjs tName _ (NormalC conName ts) contents = do
1113− (argTys, tvMap) <- reifyConTys jc pjs conName
1114− let len = genericLength ts
1115− 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
11161017
11171018-- Records.
1118−parseArgs jc pjs tName opts (RecC conName ts) (Left (_, obj)) = do
1119− (argTys, tvMap) <- reifyConTys jc pjs conName
1120− parseRecord jc tvMap argTys opts tName conName ts obj
1121−parseArgs jc pjs tName opts (RecC conName ts) (Right valName) = case (unwrapUnaryRecords opts,ts) of
1122− (True,[(_,st,ty)])-> parseArgs jc pjs tName opts (NormalC conName [(st,ty)]) (Right valName)
1123− _ -> do
1124− obj <- newName "recObj"
1125− (argTys, tvMap) <- reifyConTys jc pjs conName
1126− caseE (varE valName)
1127− [ match (conP 'Object [varP obj]) (normalB $
1128− parseRecord jc tvMap argTys opts tName conName ts obj) []
1129− , matchFailed tName conName "Object"
1130− ]
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+ ]
11311043
11321044-- Infix constructors. Apart from syntax these are the same as
11331045-- polyadic constructors.
1134−parseArgs jc pjs tName _ (InfixC _ conName _) contents = do
1135− (argTys, tvMap) <- reifyConTys jc pjs conName
1136− matchCases contents $ parseProduct jc tvMap argTys tName conName 2
1137−
1138−-- Existentially quantified constructors. We ignore the quantifiers
1139−-- and proceed with the contained constructor.
1140−parseArgs jc pjs tName opts (ForallC _ _ con) contents =
1141− parseArgs jc pjs tName opts con contents
1142−
1143−#if MIN_VERSION_template_haskell(2,11,0)
1144−-- GADTs. We ignore the refined return type and proceed as if it were a
1145−-- NormalC or RecC.
1146−parseArgs jc pjs tName opts (GadtC conNames ts _) contents =
1147− parseArgs jc pjs tName opts (NormalC (head conNames) ts) contents
1148−
1149−parseArgs jc pjs tName opts (RecGadtC conNames ts _) contents =
1150− parseArgs jc pjs tName opts (RecC (head conNames) ts) contents
1151−#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
11521053
11531054-- | Generates code to parse the JSON encoding of an n-ary
11541055-- constructor.
@@ -1222,9 +1123,14 @@ class LookupField a where
12221123instance OVERLAPPABLE_ LookupField a where
12231124 lookupField = lookupFieldWith
12241125
1225−instance LookupField (Maybe a) where
1126+instance INCOHERENT_ LookupField (Maybe a) where
12261127 lookupField pj _ _ = parseOptionalFieldWith pj
12271128
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+
12281134lookupFieldWith :: (Value -> Parser a) -> String -> String
12291135 -> Object -> T.Text -> Parser a
12301136lookupFieldWith pj tName rec obj key =
@@ -1232,9 +1138,6 @@ lookupFieldWith pj tName rec obj key =
12321138 Nothing -> unknownFieldFail tName rec (T.unpack key)
12331139 Just v -> pj v <?> Key key
12341140
1235−keyValuePairWith :: (v -> Value) -> T.Text -> v -> Pair
1236−keyValuePairWith tj name value = (name, tj value)
1237−
12381141unknownFieldFail :: String -> String -> String -> Parser fail
12391142unknownFieldFail tName rec key =
12401143 fail $ printf "When parsing the record %s of type %s the key %s was not present."
@@ -1303,7 +1206,8 @@ deriveJSONBoth dtj dfj opts name =
13031206 liftM2 (++) (dtj opts name) (dfj opts name)
13041207
13051208-- | Functionality common to @deriveToJSON(1)(2)@ and @deriveFromJSON(1)(2)@.
1306−deriveJSONClass :: [(JSONFun, JSONClass -> Name -> Options -> [Con] -> Q Exp)]
1209+deriveJSONClass :: [(JSONFun, JSONClass -> Name -> Options -> [Type]
1210+ -> [ConstructorInfo] -> Q Exp)]
13071211 -- ^ The class methods and the functions which derive them.
13081212 -> JSONClass
13091213 -- ^ The class for which to generate an instance.
@@ -1313,27 +1217,34 @@ deriveJSONClass :: [(JSONFun, JSONClass -> Name -> Options -> [Con] -> Q Exp)]
13131217 -- ^ Name of the type for which to generate a class instance
13141218 -- declaration.
13151219 -> Q [Dec]
1316−deriveJSONClass consFuns jc opts name =
1317− withType name $ \name' ctxt tvbs cons mbTys ->
1318− (:[]) <$> fromCons name' ctxt tvbs cons mbTys
1319− where
1320− fromCons :: Name -> Cxt -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q Dec
1321− 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
13221233 (instanceCxt, instanceType)
1323− <- buildTypeInstance name' jc ctxt tvbs mbTys
1324− instanceD (return instanceCxt)
1325− (return instanceType)
1326− (methodDecs name' cons)
1327−
1328− methodDecs :: Name -> [Con] -> [Q Dec]
1329− 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) ->
13301241 funD (jsonFunValName jf (arity jc))
13311242 [ clause []
1332− (normalB $ jfMaker jc name' opts cons)
1243+ (normalB $ jfMaker jc parentName opts instTys cons)
13331244 []
13341245 ]
13351246
1336−mkFunCommon :: (JSONClass -> Name -> Options -> [Con] -> Q Exp)
1247+mkFunCommon :: (JSONClass -> Name -> Options -> [Type] -> [ConstructorInfo] -> Q Exp)
13371248 -- ^ The function which derives the expression.
13381249 -> JSONClass
13391250 -- ^ Which class's method is being derived.
@@ -1342,15 +1253,24 @@ mkFunCommon :: (JSONClass -> Name -> Options -> [Con] -> Q Exp)
13421253 -> Name
13431254 -- ^ Name of the encoded type.
13441255 -> Q Exp
1345−mkFunCommon consFun jc opts name = withType name fromCons
1346− where
1347− fromCons :: Name -> Cxt -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q Exp
1348− fromCons name' ctxt tvbs cons mbTys = do
1349− -- We force buildTypeInstance here since it performs some checks for whether
1350− -- or not the provided datatype's kind matches the derived method's
1351− -- typeclass, and produces errors if it can't.
1352− !_ <- buildTypeInstance name' jc ctxt tvbs mbTys
1353− 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
13541274
13551275dispatchFunByType :: JSONClass
13561276 -> JSONFun
@@ -1395,200 +1315,37 @@ dispatchFunByType jc jf conName tvMap list ty = do
13951315 (interleave rhsArgs rhsArgs)
13961316 else varE $ jsonFunValOrListName list jf Arity0
13971317
1398−dispatchToJSON, dispatchToEncoding, dispatchParseJSON
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
13991324 :: JSONClass -> Name -> TyVarMap -> Type -> Q Exp
1400−dispatchToJSON jc n tvMap = dispatchFunByType jc ToJSON n tvMap False
1401−dispatchToEncoding jc n tvMap = dispatchFunByType jc ToEncoding n tvMap False
14021325dispatchParseJSON jc n tvMap = dispatchFunByType jc ParseJSON n tvMap False
14031326
14041327--------------------------------------------------------------------------------
14051328-- Utility functions
14061329--------------------------------------------------------------------------------
14071330
1408−-- | Boilerplate for top level splices.
1409−--
1410−-- The given 'Name' must meet one of two criteria:
1411−--
1412−-- 1. It must be the name of a type constructor of a plain data type or newtype.
1413−-- 2. It must be the name of a data family instance or newtype instance constructor.
1414−
1415−-- Any other value will result in an exception.
1416−withType :: Name
1417− -> (Name -> Cxt -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q a)
1418− -- ^ Function that generates the actual code. Will be applied
1419− -- to the datatype/data family 'Name', datatype context, type
1420− -- variable binders and constructors extracted from the given
1421− -- 'Name'. If the 'Name' is from a data family instance
1422− -- constructor, it will also have its instantiated types;
1423− -- otherwise, it will be 'Nothing'.
1424− -> Q a
1425− -- ^ Resulting value in the 'Q'uasi monad.
1426−withType name f = do
1427− info <- reify name
1428− case info of
1429− TyConI dec ->
1430− case dec of
1431−#if MIN_VERSION_template_haskell(2,11,0)
1432− DataD ctxt _ tvbs _ cons _ -> f name ctxt tvbs cons Nothing
1433− NewtypeD ctxt _ tvbs _ con _ -> f name ctxt tvbs [con] Nothing
1434−#else
1435− DataD ctxt _ tvbs cons _ -> f name ctxt tvbs cons Nothing
1436− NewtypeD ctxt _ tvbs con _ -> f name ctxt tvbs [con] Nothing
1437−#endif
1438− other -> fail $ ns ++ "Unsupported type: " ++ show other
1439−#if MIN_VERSION_template_haskell(2,11,0)
1440− DataConI _ _ parentName -> do
1441−#else
1442− DataConI _ _ parentName _ -> do
1443−#endif
1444− parentInfo <- reify parentName
1445− case parentInfo of
1446−#if MIN_VERSION_template_haskell(2,11,0)
1447− FamilyI (DataFamilyD _ tvbs _) decs ->
1448−#else
1449− FamilyI (FamilyD DataFam _ tvbs _) decs ->
1450−#endif
1451− let instDec = flip find decs $ \dec -> case dec of
1452−#if MIN_VERSION_template_haskell(2,11,0)
1453− DataInstD _ _ _ _ cons _ -> any ((name ==) . getConName) cons
1454− NewtypeInstD _ _ _ _ con _ -> name == getConName con
1455−#else
1456− DataInstD _ _ _ cons _ -> any ((name ==) . getConName) cons
1457− NewtypeInstD _ _ _ con _ -> name == getConName con
1458−#endif
1459− _ -> error $ ns ++ "Must be a data or newtype instance."
1460− in case instDec of
1461−#if MIN_VERSION_template_haskell(2,11,0)
1462− Just (DataInstD ctxt _ instTys _ cons _) -> f parentName ctxt tvbs cons $ Just instTys
1463− Just (NewtypeInstD ctxt _ instTys _ con _) -> f parentName ctxt tvbs [con] $ Just instTys
1464−#else
1465− Just (DataInstD ctxt _ instTys cons _) -> f parentName ctxt tvbs cons $ Just instTys
1466− Just (NewtypeInstD ctxt _ instTys con _) -> f parentName ctxt tvbs [con] $ Just instTys
1467−#endif
1468− _ -> fail $ ns ++
1469− "Could not find data or newtype instance constructor."
1470− _ -> fail $ ns ++ "Data constructor " ++ show name ++
1471− " is not from a data family instance constructor."
1472−#if MIN_VERSION_template_haskell(2,11,0)
1473− FamilyI DataFamilyD{} _ ->
1474−#else
1475− FamilyI (FamilyD DataFam _ _ _) _ ->
1476−#endif
1477− fail $ ns ++
1478− "Cannot use a data family name. Use a data family instance constructor instead."
1479− _ -> fail $ ns ++ "I need the name of a plain data type constructor, "
1480− ++ "or a data family instance constructor."
1481− where
1482− ns :: String
1483− ns = "Data.Aeson.TH.withType: "
1484−
1485−-- | Infer the context and instance head needed for a FromJSON or ToJSON instance.
1331+-- For the given Types, generate an instance context and head.
14861332buildTypeInstance :: Name
14871333 -- ^ The type constructor or data family name
14881334 -> JSONClass
14891335 -- ^ The typeclass to derive
14901336 -> Cxt
14911337 -- ^ The datatype context
1492− -> [TyVarBndr]
1493− -- ^ The type variables from the data type/data family declaration
1494− -> Maybe [Type]
1495− -- ^ 'Just' the types used to instantiate a data family instance,
1496− -- 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
14971342 -> Q (Cxt, Type)
1498− -- ^ The resulting 'Cxt' and 'Type' to use in a class instance
1499−-- Plain data type/newtype case
1500−buildTypeInstance tyConName jc dataCxt tvbs Nothing =
1501− let varTys :: [Type]
1502− varTys = map tvbToType tvbs
1503− in buildTypeInstanceFromTys tyConName jc dataCxt varTys False
1504−-- Data family instance case
1505−--
1506−-- The CPP is present to work around a couple of annoying old GHC bugs.
1507−-- See Note [Polykinded data families in Template Haskell]
1508−buildTypeInstance dataFamName jc dataCxt tvbs (Just instTysAndKinds) = do
1509−#if !(MIN_VERSION_template_haskell(2,8,0)) || MIN_VERSION_template_haskell(2,10,0)
1510− let instTys :: [Type]
1511− instTys = zipWith stealKindForType tvbs instTysAndKinds
1512−#else
1513− let kindVarNames :: [Name]
1514− kindVarNames = nub $ concatMap (tyVarNamesOfType . tvbKind) tvbs
1515−
1516− numKindVars :: Int
1517− numKindVars = length kindVarNames
1518−
1519− givenKinds, givenKinds' :: [Kind]
1520− givenTys :: [Type]
1521− (givenKinds, givenTys) = splitAt numKindVars instTysAndKinds
1522− givenKinds' = map sanitizeStars givenKinds
1523−
1524− -- A GHC 7.6-specific bug requires us to replace all occurrences of
1525− -- (ConT GHC.Prim.*) with StarT, or else Template Haskell will reject it.
1526− -- Luckily, (ConT GHC.Prim.*) only seems to occur in this one spot.
1527− sanitizeStars :: Kind -> Kind
1528− sanitizeStars = go
1529− where
1530− go :: Kind -> Kind
1531− go (AppT t1 t2) = AppT (go t1) (go t2)
1532− go (SigT t k) = SigT (go t) (go k)
1533− go (ConT n) | n == starKindName = StarT
1534− go t = t
1535−
1536− -- It's quite awkward to import * from GHC.Prim, so we'll just
1537− -- hack our way around it.
1538− starKindName :: Name
1539− starKindName = mkNameG_tc "ghc-prim" "GHC.Prim" "*"
1540−
1541− -- If we run this code with GHC 7.8, we might have to generate extra type
1542− -- variables to compensate for any type variables that Template Haskell
1543− -- eta-reduced away.
1544− -- See Note [Polykinded data families in Template Haskell]
1545− xTypeNames <- newNameList "tExtra" (length tvbs - length givenTys)
1546−
1547− let xTys :: [Type]
1548− xTys = map VarT xTypeNames
1549− -- ^ Because these type variables were eta-reduced away, we can only
1550− -- determine their kind by using stealKindForType. Therefore, we mark
1551− -- them as VarT to ensure they will be given an explicit kind annotation
1552− -- (and so the kind inference machinery has the right information).
1553−
1554− substNamesWithKinds :: [(Name, Kind)] -> Type -> Type
1555− substNamesWithKinds nks t = foldr' (uncurry substNameWithKind) t nks
1556−
1557− -- The types from the data family instance might not have explicit kind
1558− -- annotations, which the kind machinery needs to work correctly. To
1559− -- compensate, we use stealKindForType to explicitly annotate any
1560− -- types without kind annotations.
1561− instTys :: [Type]
1562− instTys = map (substNamesWithKinds (zip kindVarNames givenKinds'))
1563− -- Note that due to a GHC 7.8-specific bug
1564− -- (see Note [Polykinded data families in Template Haskell]),
1565− -- there may be more kind variable names than there are kinds
1566− -- to substitute. But this is OK! If a kind is eta-reduced, it
1567− -- means that is was not instantiated to something more specific,
1568− -- so we need not substitute it. Using stealKindForType will
1569− -- grab the correct kind.
1570− $ zipWith stealKindForType tvbs (givenTys ++ xTys)
1571−#endif
1572− buildTypeInstanceFromTys dataFamName jc dataCxt instTys True
1573−
1574−-- For the given Types, generate an instance context and head.
1575−buildTypeInstanceFromTys :: Name
1576− -- ^ The type constructor or data family name
1577− -> JSONClass
1578− -- ^ The typeclass to derive
1579− -> Cxt
1580− -- ^ The datatype context
1581− -> [Type]
1582− -- ^ The types to instantiate the instance with
1583− -> Bool
1584− -- ^ True if it's a data family, False otherwise
1585− -> Q (Cxt, Type)
1586−buildTypeInstanceFromTys tyConName jc dataCxt varTysOrig isDataFamily = do
1343+buildTypeInstance tyConName jc dataCxt varTysOrig variant = do
15871344 -- Make sure to expand through type/kind synonyms! Otherwise, the
15881345 -- eta-reduction check might get tripped up over type variables in a
15891346 -- synonym that are actually dropped.
15901347 -- (See GHC Trac #11416 for a scenario where this actually happened.)
1591− varTysExp <- mapM expandSyn varTysOrig
1348+ varTysExp <- mapM resolveTypeSynonyms varTysOrig
15921349
15931350 let remainingLength :: Int
15941351 remainingLength = length varTysOrig - arityInt jc
@@ -1618,7 +1375,7 @@ buildTypeInstanceFromTys tyConName jc dataCxt varTysOrig isDataFamily = do
16181375 -- All of the type variables mentioned in the dropped types
16191376 -- (post-synonym expansion)
16201377 droppedTyVarNames :: [Name]
1621− droppedTyVarNames = concatMap tyVarNamesOfType droppedTysExpSubst
1378+ droppedTyVarNames = freeVariables droppedTysExpSubst
16221379
16231380 -- If any of the dropped types were polykinded, ensure that they are of kind *
16241381 -- after substituting * for the dropped kind variables. If not, throw an error.
@@ -1656,9 +1413,16 @@ buildTypeInstanceFromTys tyConName jc dataCxt varTysOrig isDataFamily = do
16561413 -- instance C (Fam [Char])
16571414 remainingTysOrigSubst :: [Type]
16581415 remainingTysOrigSubst =
1659− map (substNamesWithKindStar (union droppedKindVarNames kvNames'))
1416+ map (substNamesWithKindStar (droppedKindVarNames `union` kvNames'))
16601417 $ take remainingLength varTysOrig
16611418
1419+ isDataFamily :: Bool
1420+ isDataFamily = case variant of
1421+ Datatype -> False
1422+ Newtype -> False
1423+ DataInstance -> True
1424+ NewtypeInstance -> True
1425+
16621426 remainingTysOrigSubst' :: [Type]
16631427 -- See Note [Kind signatures in derived instances] for an explanation
16641428 -- of the isDataFamily check.
@@ -1712,55 +1476,6 @@ deriveConstraint jc t
17121476 jcConstraint = jsonClassName . JSONClass (direction jc)
17131477
17141478{-
1715−Note [Polykinded data families in Template Haskell]
1716−~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1717−
1718−In order to come up with the correct instance context and head for an instance, e.g.,
1719−
1720− instance C a => C (Data a) where ...
1721−
1722−We need to know the exact types and kinds used to instantiate the instance. For
1723−plain old datatypes, this is simple: every type must be a type variable, and
1724−Template Haskell reliably tells us the type variables and their kinds.
1725−
1726−Doing the same for data families proves to be much harder for three reasons:
1727−
1728−1. On any version of Template Haskell, it may not tell you what an instantiated
1729− type's kind is. For instance, in the following data family instance:
1730−
1731− data family Fam (f :: * -> *) (a :: *)
1732− data instance Fam f a
1733−
1734− Then if we use TH's reify function, it would tell us the TyVarBndrs of the
1735− data family declaration are:
1736−
1737− [KindedTV f (AppT (AppT ArrowT StarT) StarT),KindedTV a StarT]
1738−
1739− and the instantiated types of the data family instance are:
1740−
1741− [VarT f1,VarT a1]
1742−
1743− We can't just pass [VarT f1,VarT a1] to buildTypeInstanceFromTys, since we
1744− have no way of knowing their kinds. Luckily, the TyVarBndrs tell us what the
1745− kind is in case an instantiated type isn't a SigT, so we use the stealKindForType
1746− function to ensure all of the instantiated types are SigTs before passing them
1747− to buildTypeInstanceFromTys.
1748−2. On GHC 7.6 and 7.8, a bug is present in which Template Haskell lists all of
1749− the specified kinds of a data family instance efore any of the instantiated
1750− types. Fortunately, this is easy to deal with: you simply count the number of
1751− distinct kind variables in the data family declaration, take that many elements
1752− from the front of the Types list of the data family instance, substitute the
1753− kind variables with their respective instantiated kinds (which you took earlier),
1754− and proceed as normal.
1755−3. On GHC 7.8, an even uglier bug is present (GHC Trac #9692) in which Template
1756− Haskell might not even list all of the Types of a data family instance, since
1757− they are eta-reduced away! And yes, kinds can be eta-reduced too.
1758−
1759− The simplest workaround is to count how many instantiated types are missing from
1760− the list and generate extra type variables to use in their place. Luckily, we
1761− needn't worry much if its kind was eta-reduced away, since using stealKindForType
1762− will get it back.
1763−
17641479Note [Kind signatures in derived instances]
17651480~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17661481
@@ -1838,50 +1553,14 @@ things we can do to make instance contexts that work for 80% of use cases:
18381553 and perform kind substitution as in the other cases.
18391554-}
18401555
1841−-- Determines the types of a constructor's arguments as well as the last type
1842−-- parameters (mapped to their encoding/decoding functions), expanding through
1843−-- any type synonyms.
1844−--
1845−-- The type parameters are determined on a constructor-by-constructor basis since
1846−-- they may be refined to be particular types in a GADT.
1847−reifyConTys :: JSONClass
1848− -> [(Name, Name)]
1849− -> Name
1850− -> Q ([Type], TyVarMap)
1851−reifyConTys jc tpjs conName = do
1852− info <- reify conName
1853− (ctxt, uncTy) <- case info of
1854− DataConI _ ty _
1855−#if !(MIN_VERSION_template_haskell(2,11,0))
1856− _
1857−#endif
1858− -> fmap uncurryTy (expandSyn ty)
1859− _ -> error "Must be a data constructor"
1860− let (argTys, [resTy]) = NE.splitAt (NE.length uncTy - 1) uncTy
1861− unapResTy = unapplyTy resTy
1862− -- If one of the last type variables is refined to a particular type
1863− -- (i.e., not truly polymorphic), we mark it with Nothing and filter
1864− -- it out later, since we only apply encoding/decoding functions to
1865− -- arguments of a type that it (1) one of the last type variables,
1866− -- and (2) of a truly polymorphic type.
1867− jArity = arityInt jc
1868− mbTvNames = map varTToNameMaybe $
1869− NE.drop (NE.length unapResTy - jArity) unapResTy
1870− -- We use M.fromList to ensure that if there are any duplicate type
1871− -- variables (as can happen in a GADT), the rightmost type variable gets
1872− -- associated with the show function.
1873− --
1874− -- See Note [Matching functions with GADT type variables]
1875− tvMap = M.fromList
1876− . catMaybes -- Drop refined types
1877− $ zipWith (\mbTvName tpj ->
1878− fmap (\tvName -> (tvName, tpj)) mbTvName)
1879− mbTvNames tpjs
1880− if (any (`predMentionsName` M.keys tvMap) ctxt
1881− || M.size tvMap < jArity)
1882− && not (allowExQuant jc)
1883− then existentialContextError conName
1884− 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
18851564
18861565{-
18871566Note [Matching functions with GADT type variables]
@@ -1921,69 +1600,22 @@ Both.
19211600-- are the function arguments of types (b -> Value) and ([b] -> Value).
19221601type TyVarMap = Map Name (Name, Name)
19231602
1924−-- | If a VarT is missing an explicit kind signature, steal it from a TyVarBndr.
1925−stealKindForType :: TyVarBndr -> Type -> Type
1926−stealKindForType tvb t@VarT{} = SigT t (tvbKind tvb)
1927−stealKindForType _ t = t
1928−
1929−-- | Extracts the kind from a type variable binder.
1930−tvbKind :: TyVarBndr -> Kind
1931−#if MIN_VERSION_template_haskell(2,8,0)
1932−tvbKind (PlainTV _ ) = StarT
1933−#else
1934−tvbKind (PlainTV _ ) = StarK
1935−#endif
1936−tvbKind (KindedTV _ k) = k
1937−
1938−tvbToType :: TyVarBndr -> Type
1939−tvbToType (PlainTV n) = VarT n
1940−tvbToType (KindedTV n k) = SigT (VarT n) k
1941−
19421603-- | Returns True if a Type has kind *.
19431604hasKindStar :: Type -> Bool
19441605hasKindStar VarT{} = True
1945−#if MIN_VERSION_template_haskell(2,8,0)
19461606hasKindStar (SigT _ StarT) = True
1947−#else
1948−hasKindStar (SigT _ StarK) = True
1949−#endif
19501607hasKindStar _ = False
19511608
19521609-- Returns True is a kind is equal to *, or if it is a kind variable.
19531610isStarOrVar :: Kind -> Bool
1954−#if MIN_VERSION_template_haskell(2,8,0)
19551611isStarOrVar StarT = True
19561612isStarOrVar VarT{} = True
1957−#else
1958−isStarOrVar StarK = True
1959−#endif
19601613isStarOrVar _ = False
19611614
19621615-- Generate a list of fresh names with a common prefix, and numbered suffixes.
19631616newNameList :: String -> Int -> Q [Name]
19641617newNameList prefix len = mapM newName [prefix ++ show n | n <- [1..len]]
19651618
1966−-- Gets all of the type/kind variable names mentioned somewhere in a Type.
1967−tyVarNamesOfType :: Type -> [Name]
1968−tyVarNamesOfType = go
1969− where
1970− go :: Type -> [Name]
1971− go (AppT t1 t2) = go t1 ++ go t2
1972− go (SigT t _k) = go t
1973−#if MIN_VERSION_template_haskell(2,8,0)
1974− ++ go _k
1975−#endif
1976− go (VarT n) = [n]
1977− go _ = []
1978−
1979−-- | Gets all of the type/kind variable names mentioned somewhere in a Kind.
1980−tyVarNamesOfKind :: Kind -> [Name]
1981−#if MIN_VERSION_template_haskell(2,8,0)
1982−tyVarNamesOfKind = tyVarNamesOfType
1983−#else
1984−tyVarNamesOfKind _ = [] -- There are no kind variables
1985−#endif
1986−
19871619-- | @hasKindVarChain n kind@ Checks if @kind@ is of the form
19881620-- k_0 -> k_1 -> ... -> k_(n-1), where k0, k1, ..., and k_(n-1) can be * or
19891621-- kind variables.
@@ -1991,7 +1623,7 @@ hasKindVarChain :: Int -> Type -> Maybe [Name]
19911623hasKindVarChain kindArrows t =
19921624 let uk = uncurryKind (tyKind t)
19931625 in if (NE.length uk - 1 == kindArrows) && F.all isStarOrVar uk
1994− then Just (concatMap tyVarNamesOfKind uk)
1626+ then Just (concatMap freeVariables uk)
19951627 else Nothing
19961628
19971629-- | If a Type is a SigT, returns its kind signature. Otherwise, return *.
@@ -2011,17 +1643,6 @@ varTToNameMaybe _ = Nothing
20111643varTToName :: Type -> Name
20121644varTToName = fromMaybe (error "Not a type variable!") . varTToNameMaybe
20131645
2014−-- | Extracts the name from a constructor.
2015−getConName :: Con -> Name
2016−getConName (NormalC name _) = name
2017−getConName (RecC name _) = name
2018−getConName (InfixC _ name _) = name
2019−getConName (ForallC _ _ con) = getConName con
2020−#if MIN_VERSION_template_haskell(2,11,0)
2021−getConName (GadtC names _ _) = head names
2022−getConName (RecGadtC names _ _) = head names
2023−#endif
2024−
20251646interleave :: [a] -> [a] -> [a]
20261647interleave (a1:a1s) (a2:a2s) = a1:a2:interleave a1s a2s
20271648interleave _ _ = []
@@ -2046,9 +1667,7 @@ isTyFamily (ConT n) = do
20461667#else
20471668 FamilyI (FamilyD TypeFam _ _ _) _ -> True
20481669#endif
2049−#if MIN_VERSION_template_haskell(2,9,0)
20501670 FamilyI ClosedTypeFamilyD{} _ -> True
2051−#endif
20521671 _ -> False
20531672isTyFamily _ = return False
20541673
@@ -2076,9 +1695,7 @@ mentionsName = go
20761695 go :: Type -> [Name] -> Bool
20771696 go (AppT t1 t2) names = go t1 names || go t2 names
20781697 go (SigT t _k) names = go t names
2079−#if MIN_VERSION_template_haskell(2,8,0)
20801698 || go _k names
2081−#endif
20821699 go (VarT n) names = n `elem` names
20831700 go _ _ = False
20841701
@@ -2134,37 +1751,28 @@ uncurryTy t = ([], t :| [])
21341751
21351752-- | Like uncurryType, except on a kind level.
21361753uncurryKind :: Kind -> NonEmpty Kind
2137−#if MIN_VERSION_template_haskell(2,8,0)
21381754uncurryKind = snd . uncurryTy
2139−#else
2140−uncurryKind (ArrowK k1 k2) = k1 <| uncurryKind k2
2141−uncurryKind k = k :| []
2142−#endif
21431755
21441756createKindChain :: Int -> Kind
21451757createKindChain = go starK
21461758 where
21471759 go :: Kind -> Int -> Kind
2148− go k !0 = k
2149−#if MIN_VERSION_template_haskell(2,8,0)
1760+ go k 0 = k
21501761 go k !n = go (AppT (AppT ArrowT StarT) k) (n - 1)
2151−#else
2152− go k !n = go (ArrowK StarK k) (n - 1)
2153−#endif
21541762
21551763-- | Makes a string literal expression from a constructor's name.
2156−conNameExp :: Options -> Con -> Q Exp
1764+conNameExp :: Options -> ConstructorInfo -> Q Exp
21571765conNameExp opts = litE
21581766 . stringL
21591767 . constructorTagModifier opts
21601768 . nameBase
2161− . getConName
1769+ . constructorName
21621770
2163−-- | Creates a string literal expression from a record field label.
2164−fieldLabelExp :: Options -- ^ Encoding options
2165− -> Name
2166− -> Q Exp
2167−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
21681776
21691777-- | The name of the outermost 'Value' constructor.
21701778valueConName :: Value -> String
@@ -2203,76 +1811,14 @@ canEtaReduce remaining dropped =
22031811-- Expanding type synonyms
22041812-------------------------------------------------------------------------------
22051813
2206−-- | Expands all type synonyms in a type. Written by Dan Rosén in the
2207−-- @genifunctors@ package (licensed under BSD3).
2208−expandSyn :: Type -> Q Type
2209−expandSyn (ForallT tvs ctx t) = ForallT tvs ctx <$> expandSyn t
2210−expandSyn t@AppT{} = expandSynApp t []
2211−expandSyn t@ConT{} = expandSynApp t []
2212−expandSyn (SigT t k) = do t' <- expandSyn t
2213− k' <- expandSynKind k
2214− return (SigT t' k')
2215−expandSyn t = return t
2216−
2217−expandSynKind :: Kind -> Q Kind
2218−#if MIN_VERSION_template_haskell(2,8,0)
2219−expandSynKind = expandSyn
2220−#else
2221−expandSynKind = return -- There are no kind synonyms to deal with
2222−#endif
2223−
2224−expandSynApp :: Type -> [Type] -> Q Type
2225−expandSynApp (AppT t1 t2) ts = do
2226− t2' <- expandSyn t2
2227− expandSynApp t1 (t2':ts)
2228−expandSynApp (ConT n) ts | nameBase n == "[]" = return $ foldl' AppT ListT ts
2229−expandSynApp t@(ConT n) ts = do
2230− info <- reify n
2231− case info of
2232− TyConI (TySynD _ tvs rhs) ->
2233− let (ts', ts'') = splitAt (length tvs) ts
2234− subs = mkSubst tvs ts'
2235− rhs' = substType subs rhs
2236− in expandSynApp rhs' ts''
2237− _ -> return $ foldl' AppT t ts
2238−expandSynApp t ts = do
2239− t' <- expandSyn t
2240− return $ foldl' AppT t' ts
2241−
2242−type TypeSubst = Map Name Type
2243−type KindSubst = Map Name Kind
2244−
2245−mkSubst :: [TyVarBndr] -> [Type] -> TypeSubst
2246−mkSubst vs ts =
2247− let vs' = map un vs
2248− un (PlainTV v) = v
2249− un (KindedTV v _) = v
2250− in M.fromList $ zip vs' ts
2251−
2252−substType :: TypeSubst -> Type -> Type
2253−substType subs (ForallT v c t) = ForallT v c $ substType subs t
2254−substType subs t@(VarT n) = M.findWithDefault t n subs
2255−substType subs (AppT t1 t2) = AppT (substType subs t1) (substType subs t2)
2256−substType subs (SigT t k) = SigT (substType subs t)
2257−#if MIN_VERSION_template_haskell(2,8,0)
2258− (substType subs k)
2259−#else
2260− k
2261−#endif
2262−substType _ t = t
2263−
2264−substKind :: KindSubst -> Type -> Type
2265−#if MIN_VERSION_template_haskell(2,8,0)
2266−substKind = substType
2267−#else
2268−substKind _ t = t -- There are no kind variables!
2269−#endif
1814+applySubstitutionKind :: Map Name Kind -> Type -> Type
1815+applySubstitutionKind = applySubstitution
22701816
22711817substNameWithKind :: Name -> Kind -> Type -> Type
2272−substNameWithKind n k = substKind (M.singleton n k)
1818+substNameWithKind n k = applySubstitutionKind (M.singleton n k)
22731819
22741820substNamesWithKindStar :: [Name] -> Type -> Type
2275−substNamesWithKindStar ns t = foldr' (flip substNameWithKind starK) t ns
1821+substNamesWithKindStar ns t = foldr' (`substNameWithKind` starK) t ns
22761822
22771823-------------------------------------------------------------------------------
22781824-- Error messages
@@ -2355,6 +1901,13 @@ data Direction = To | From
23551901-- | A representation of which typeclass method is being spliced in.
23561902data JSONFun = ToJSON | ToEncoding | ParseJSON
23571903
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+
23581911-- | A representation of which typeclass is being derived.
23591912data JSONClass = JSONClass { direction :: Direction, arity :: Arity }
23601913
@@ -2421,13 +1974,10 @@ data StarKindStatus = NotKindStar
24211974
24221975-- | Does a Type have kind * or k (for some kind variable k)?
24231976canRealizeKindStar :: Type -> StarKindStatus
2424−canRealizeKindStar t
2425− | hasKindStar t = KindStar
2426− | otherwise = case t of
2427−#if MIN_VERSION_template_haskell(2,8,0)
2428− SigT _ (VarT k) -> IsKindVar k
2429−#endif
2430− _ -> NotKindStar
1977+canRealizeKindStar t = case t of
1978+ _ | hasKindStar t -> KindStar
1979+ SigT _ (VarT k) -> IsKindVar k
1980+ _ -> NotKindStar
24311981
24321982-- | Returns 'Just' the kind variable 'Name' of a 'StarKindStatus' if it exists.
24331983-- Otherwise, returns 'Nothing'.
Data/Aeson/Text.hs+5−4
@@ -1,4 +1,5 @@
11{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
23{-# LANGUAGE OverloadedStrings #-}
34-- |
45-- Module: Data.Aeson.Text
@@ -14,18 +15,18 @@
1415--
1516-- You can use the conversions to 'Builder's when embedding JSON messages as
1617-- parts of a protocol.
18+
1719module Data.Aeson.Text
1820 (
1921 encodeToLazyText
2022 , encodeToTextBuilder
2123 ) where
2224
23−import Prelude ()
2425import Prelude.Compat
2526
2627import Data.Aeson.Types (Value(..), ToJSON(..))
2728import Data.Aeson.Encoding (encodingToLazyByteString)
28−import Data.Monoid ((<>))
29+import Data.Semigroup ((<>))
2930import Data.Scientific (FPFormat(..), Scientific, base10Exponent)
3031import Data.Text.Lazy.Builder
3132import Data.Text.Lazy.Builder.Scientific (formatScientificBuilder)
@@ -46,8 +47,8 @@ encodeToLazyText = LT.decodeUtf8 . encodingToLazyByteString . toEncoding
4647-- embedded efficiently in a text-based protocol.
4748--
4849-- If you are going to immediately encode straight to a
49−-- 'L.ByteString', it is more efficient to use 'encodeToBuilder'
50−-- instead.
50+-- 'L.ByteString', it is more efficient to use 'encode' (lazy ByteString)
51+-- or @'fromEncoding' . 'toEncoding'@ (ByteString.Builder) instead.
5152--
5253-- /Note:/ Uses 'toJSON'
5354encodeToTextBuilder :: ToJSON a => a -> Builder
Data/Aeson/Types.hs+49−5
@@ -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,6 +38,9 @@ module Data.Aeson.Types
3638 , ToJSON(..)
3739 , KeyValue(..)
3840 , modifyFailure
41+ , prependFailure
42+ , parserThrowError
43+ , parserCatchError
3944
4045 -- ** Keys for maps
4146 , ToJSONKey(..)
@@ -48,6 +53,12 @@ module Data.Aeson.Types
4853 , coerceFromJSONKeyFunction
4954 , mapFromJSONKeyFunction
5055
56+ -- *** Generic keys
57+ , GToJSONKey()
58+ , genericToJSONKey
59+ , GFromJSONKey()
60+ , genericFromJSONKey
61+
5162 -- ** Liftings to unary and binary type constructors
5263 , FromJSON1(..)
5364 , parseJSON1
@@ -63,8 +74,8 @@ module Data.Aeson.Types
6374 -- ** Generic JSON classes
6475 , GFromJSON(..)
6576 , FromArgs(..)
66− , GToJSON(..)
67− , GToEncoding(..)
77+ , GToJSON
78+ , GToEncoding
6879 , ToArgs(..)
6980 , Zero
7081 , One
@@ -79,9 +90,9 @@ module Data.Aeson.Types
7990 , withObject
8091 , withText
8192 , withArray
82− , withNumber
8393 , withScientific
8494 , withBool
95+ , withEmbeddedJSON
8596
8697 , pairs
8798 , foldable
@@ -90,21 +101,51 @@ module Data.Aeson.Types
90101 , (.:!)
91102 , (.!=)
92103 , object
104+ , parseField
105+ , parseFieldMaybe
106+ , parseFieldMaybe'
107+ , explicitParseField
108+ , explicitParseFieldMaybe
109+ , explicitParseFieldMaybe'
93110
94111 , listEncoding
95112 , listValue
96113 , listParser
97114
98115 -- * Generic and TH encoding configuration
99− , 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
100130 , SumEncoding(..)
101131 , camelTo
102132 , camelTo2
103133 , defaultOptions
104134 , 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
105147 ) where
106148
107−import Prelude ()
108149import Prelude.Compat
109150
110151import Data.Aeson.Encoding (Encoding, unsafeToEncoding, fromEncoding, Series, pairs)
@@ -116,3 +157,6 @@ import Data.Foldable (toList)
116157foldable :: (Foldable t, ToJSON a) => t a -> Encoding
117158foldable = toEncoding . toList
118159{-# INLINE foldable #-}
160+
161+-- $optionsFields
162+-- The functions here are in fact record fields of the 'Options' type.
Data/Aeson/Types/Class.hs+26−7
@@ -1,10 +1,11 @@
11{-# LANGUAGE CPP #-}
2+{-# LANGUAGE ConstraintKinds #-}
23{-# LANGUAGE FlexibleContexts #-}
34{-# LANGUAGE FlexibleInstances #-}
45{-# LANGUAGE GADTs #-}
56{-# LANGUAGE MultiParamTypeClasses #-}
7+{-# LANGUAGE NoImplicitPrelude #-}
68{-# LANGUAGE ScopedTypeVariables #-}
7−{-# LANGUAGE TypeSynonymInstances #-}
89
910-- |
1011-- Module: Data.Aeson.Types.Class
@@ -36,8 +37,8 @@ module Data.Aeson.Types.Class
3637 -- * Generic JSON classes
3738 , GFromJSON(..)
3839 , FromArgs(..)
39− , GToJSON(..)
40− , GToEncoding(..)
40+ , GToJSON
41+ , GToEncoding
4142 , ToArgs(..)
4243 , Zero
4344 , One
@@ -57,6 +58,11 @@ module Data.Aeson.Types.Class
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,22 +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
86−import Prelude ()
87100
88101import Data.Aeson.Types.FromJSON
89102import Data.Aeson.Types.Generic (One, Zero)
90−import Data.Aeson.Types.ToJSON
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+1079−464
@@ -5,19 +5,17 @@
55{-# LANGUAGE FlexibleInstances #-}
66{-# LANGUAGE GADTs #-}
77{-# LANGUAGE MultiParamTypeClasses #-}
8−{-# LANGUAGE NamedFieldPuns #-}
8+{-# LANGUAGE NoImplicitPrelude #-}
99{-# LANGUAGE OverloadedStrings #-}
10+{-# LANGUAGE PolyKinds #-}
1011{-# LANGUAGE RecordWildCards #-}
1112{-# LANGUAGE ScopedTypeVariables #-}
1213{-# LANGUAGE TypeOperators #-}
13−{-# LANGUAGE TypeSynonymInstances #-}
14+{-# LANGUAGE TupleSections #-}
1415{-# LANGUAGE UndecidableInstances #-}
1516{-# LANGUAGE ViewPatterns #-}
1617
17−#if __GLASGOW_HASKELL__ >= 706
18−{-# LANGUAGE PolyKinds #-}
19−#endif
20−
18+#include "incoherent-compat.h"
2119#include "overlapping-compat.h"
2220
2321-- TODO: Drop this when we remove support for Data.Attoparsec.Number
@@ -44,6 +42,9 @@ module Data.Aeson.Types.FromJSON
4442 , coerceFromJSONKeyFunction
4543 , mapFromJSONKeyFunction
4644
45+ , GFromJSONKey()
46+ , genericFromJSONKey
47+
4748 -- * List functions
4849 , listParser
4950
@@ -51,34 +52,42 @@ module Data.Aeson.Types.FromJSON
5152 , withObject
5253 , withText
5354 , withArray
54− , withNumber
5555 , withScientific
5656 , withBool
57+ , withEmbeddedJSON
5758
5859 -- * Functions
5960 , fromJSON
6061 , ifromJSON
62+ , typeMismatch
63+ , unexpected
64+ , parseField
65+ , parseFieldMaybe
66+ , parseFieldMaybe'
67+ , explicitParseField
68+ , explicitParseFieldMaybe
69+ , explicitParseFieldMaybe'
70+ , parseIndexedJSON
71+ -- ** Operators
6172 , (.:)
6273 , (.:?)
6374 , (.:!)
6475 , (.!=)
65− , typeMismatch
6676
6777 -- * Internal
6878 , parseOptionalFieldWith
6979 ) where
7080
71−import Prelude ()
7281import Prelude.Compat
7382
74−import Control.Applicative ((<|>), Const(..))
75−import Control.Monad ((<=<), zipWithM)
83+import Control.Applicative ((<|>), Const(..), liftA2)
84+import Control.Monad (zipWithM)
7685import Data.Aeson.Internal.Functions (mapKey)
86+import Data.Aeson.Parser.Internal (eitherDecodeWith, jsonEOF)
7787import Data.Aeson.Types.Generic
7888import Data.Aeson.Types.Internal
79−import Data.Attoparsec.Number (Number(..))
8089import Data.Bits (unsafeShiftR)
81−import Data.Fixed (Fixed, HasResolution)
90+import Data.Fixed (Fixed, HasResolution (resolution), Nano)
8291import Data.Functor.Compose (Compose(..))
8392import Data.Functor.Identity (Identity(..))
8493import Data.Functor.Product (Product(..))
@@ -87,57 +96,67 @@ import Data.Hashable (Hashable(..))
8796import Data.Int (Int16, Int32, Int64, Int8)
8897import Data.List.NonEmpty (NonEmpty(..))
8998import Data.Maybe (fromMaybe)
90−import Data.Monoid ((<>), Dual(..), First (..), Last (..))
99+import Data.Semigroup ((<>))
91100import Data.Proxy (Proxy(..))
92101import Data.Ratio ((%), Ratio)
93−import Data.Scientific (Scientific)
102+import Data.Scientific (Scientific, base10Exponent)
94103import Data.Tagged (Tagged(..))
95104import Data.Text (Text, pack, unpack)
96−import Data.Time (Day, LocalTime, NominalDiffTime, TimeOfDay, UTCTime, ZonedTime)
97−import Data.Time.Format (parseTime)
98−import Data.Time.Locale.Compat (defaultTimeLocale)
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)
99110import Data.Traversable as Tr (sequence)
100111import Data.Vector (Vector)
101112import Data.Version (Version, parseVersion)
113+import Data.Void (Void)
102114import Data.Word (Word16, Word32, Word64, Word8)
103115import Foreign.Storable (Storable)
116+import Foreign.C.Types (CTime (..))
104117import GHC.Generics
105118import Numeric.Natural (Natural)
106119import Text.ParserCombinators.ReadP (readP_to_S)
120+import Unsafe.Coerce (unsafeCoerce)
107121import qualified Data.Aeson.Parser.Time as Time
108122import qualified Data.Attoparsec.ByteString.Char8 as A (endOfInput, parseOnly, scientific)
123+import qualified Data.ByteString.Lazy as L
109124import qualified Data.DList as DList
110125import qualified Data.HashMap.Strict as H
111126import qualified Data.HashSet as HashSet
112127import qualified Data.IntMap as IntMap
113128import qualified Data.IntSet as IntSet
114129import qualified Data.Map as M
130+import qualified Data.Monoid as Monoid
115131import qualified Data.Scientific as Scientific
132+import qualified Data.Semigroup as Semigroup
116133import qualified Data.Sequence as Seq
117134import qualified Data.Set as Set
118135import qualified Data.Text as T
119136import qualified Data.Text.Encoding as T
120137import qualified Data.Text.Lazy as LT
121138import qualified Data.Tree as Tree
139+import qualified Data.UUID.Types as UUID
122140import qualified Data.Vector as V
123141import qualified Data.Vector.Generic as VG
124142import qualified Data.Vector.Primitive as VP
125143import qualified Data.Vector.Storable as VS
126144import qualified Data.Vector.Unboxed as VU
127−import Unsafe.Coerce (unsafeCoerce)
128145
129−#ifndef HAS_COERCIBLE
130−#define HAS_COERCIBLE (__GLASGOW_HASKELL__ >= 707)
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
150+
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
131156#endif
132157
133−#if HAS_COERCIBLE
158+
134159import Data.Coerce (Coercible, coerce)
135−coerce' :: Coercible a b => a -> b
136−coerce' = coerce
137−#else
138−coerce' :: a -> b
139−coerce' = unsafeCoerce
140−#endif
141160
142161parseIndexedJSON :: (Value -> Parser a) -> Int -> Value -> Parser a
143162parseIndexedJSON p idx value = p value <?> Index idx
@@ -146,7 +165,7 @@ parseIndexedJSON p idx value = p value <?> Index idx
146165parseIndexedJSONPair :: (Value -> Parser a) -> (Value -> Parser b) -> Int -> Value -> Parser (a, b)
147166parseIndexedJSONPair keyParser valParser idx value = p value <?> Index idx
148167 where
149− p = withArray "(k,v)" $ \ab ->
168+ p = withArray "(k, v)" $ \ab ->
150169 let n = V.length ab
151170 in if n == 2
152171 then (,) <$> parseJSONElemAtIndex keyParser 0 ab
@@ -158,43 +177,34 @@ parseIndexedJSONPair keyParser valParser idx value = p value <?> Index idx
158177parseJSONElemAtIndex :: (Value -> Parser a) -> Int -> V.Vector Value -> Parser a
159178parseJSONElemAtIndex p idx ary = p (V.unsafeIndex ary idx) <?> Index idx
160179
161−scientificToNumber :: Scientific -> Number
162−scientificToNumber s
163− | e < 0 = D $ Scientific.toRealFloat s
164− | otherwise = I $ c * 10 ^ e
165− where
166− e = Scientific.base10Exponent s
167− c = Scientific.coefficient s
168−{-# INLINE scientificToNumber #-}
169−
170180parseRealFloat :: RealFloat a => String -> Value -> Parser a
171−parseRealFloat _ (Number s) = pure $ Scientific.toRealFloat s
172−parseRealFloat _ Null = pure (0/0)
173−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)
174184{-# INLINE parseRealFloat #-}
175185
176−parseIntegralFromScientific :: forall a. Integral a => String -> Scientific -> Parser a
177−parseIntegralFromScientific expected s =
186+parseIntegralFromScientific :: forall a. Integral a => Scientific -> Parser a
187+parseIntegralFromScientific s =
178188 case Scientific.floatingOrInteger s :: Either Double a of
179189 Right x -> pure x
180− Left _ -> fail $ "Floating number specified for " ++ expected ++ ": " ++ show s
190+ Left _ -> fail $ "unexpected floating number " ++ show s
181191{-# INLINE parseIntegralFromScientific #-}
182192
183193parseIntegral :: Integral a => String -> Value -> Parser a
184−parseIntegral expected =
185− withScientific expected $ parseIntegralFromScientific expected
194+parseIntegral name =
195+ prependContext name . withBoundedScientific' parseIntegralFromScientific
186196{-# INLINE parseIntegral #-}
187197
188−parseBoundedIntegralFromScientific :: (Bounded a, Integral a) => String -> Scientific -> Parser a
189−parseBoundedIntegralFromScientific expected s = maybe
190− (fail $ expected ++ " is either floating or will cause over or underflow: " ++ show s)
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)
191201 pure
192202 (Scientific.toBoundedInteger s)
193203{-# INLINE parseBoundedIntegralFromScientific #-}
194204
195205parseBoundedIntegral :: (Bounded a, Integral a) => String -> Value -> Parser a
196−parseBoundedIntegral expected =
197− withScientific expected $ parseBoundedIntegralFromScientific expected
206+parseBoundedIntegral name =
207+ prependContext name . withScientific' parseBoundedIntegralFromScientific
198208{-# INLINE parseBoundedIntegral #-}
199209
200210parseScientificText :: Text -> Parser Scientific
@@ -204,13 +214,20 @@ parseScientificText
204214 . T.encodeUtf8
205215
206216parseIntegralText :: Integral a => String -> Text -> Parser a
207−parseIntegralText expected t =
208− parseScientificText t >>= parseIntegralFromScientific expected
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)
209225{-# INLINE parseIntegralText #-}
210226
211227parseBoundedIntegralText :: (Bounded a, Integral a) => String -> Text -> Parser a
212−parseBoundedIntegralText expected t =
213− parseScientificText t >>= parseBoundedIntegralFromScientific expected
228+parseBoundedIntegralText name t =
229+ prependContext name $
230+ parseScientificText t >>= parseBoundedIntegralFromScientific
214231
215232parseOptionalFieldWith :: (Value -> Parser (Maybe a))
216233 -> Object -> Text -> Parser (Maybe a)
@@ -270,14 +287,21 @@ genericLiftParseJSON opts pj pjl = fmap to1 . gParseJSON opts (From1Args pj pjl)
270287--
271288-- The basic ways to signal a failed conversion are as follows:
272289--
273−-- * '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;
292+--
293+-- * 'Control.Applicative.empty' (or 'Control.Monad.mzero') is uninformative:
294+-- use it when the error is meant to be caught by some @('<|>')@;
274295--
275−-- * 'fail' yields a custom error message
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.
276300--
277−-- * 'typeMismatch' produces an informative message for cases when the
278−-- value encountered is not of the expected type
301+-- 'prependFailure' (or 'modifyFailure') add more information to a parser's
302+-- error messages.
279303--
280−-- An example type and instance:
304+-- An example type and instance using 'typeMismatch' and 'prependFailure':
281305--
282306-- @
283307-- \-- Allow ourselves to write 'Text' literals.
@@ -285,15 +309,30 @@ genericLiftParseJSON opts pj pjl = fmap to1 . gParseJSON opts (From1Args pj pjl)
285309--
286310-- data Coord = Coord { x :: Double, y :: Double }
287311--
288−-- instance FromJSON Coord where
289−-- parseJSON ('Object' v) = Coord '<$>'
290−-- v '.:' \"x\" '<*>'
291−-- v '.:' \"y\"
312+-- instance 'FromJSON' Coord where
313+-- 'parseJSON' ('Object' v) = Coord
314+-- '<$>' v '.:' \"x\"
315+-- '<*>' v '.:' \"y\"
292316--
293−-- \-- We do not expect a non-'Object' value here.
294−-- \-- We could use 'mzero' to fail, but 'typeMismatch'
295−-- \-- gives a much more informative error message.
296−-- parseJSON invalid = 'typeMismatch' \"Coord\" invalid
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+-- @
324+--
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\"
297336-- @
298337--
299338-- Instead of manually writing your 'FromJSON' instance, there are two options
@@ -301,7 +340,7 @@ genericLiftParseJSON opts pj pjl = fmap to1 . gParseJSON opts (From1Args pj pjl)
301340--
302341-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
303342-- instance at compile time. The generated instance is optimized for your type
304−-- so will probably be more efficient than the following two options:
343+-- so it will probably be more efficient than the following option.
305344--
306345-- * The compiler can provide a default generic implementation for
307346-- 'parseJSON'.
@@ -319,18 +358,21 @@ genericLiftParseJSON opts pj pjl = fmap to1 . gParseJSON opts (From1Args pj pjl)
319358--
320359-- data Coord = Coord { x :: Double, y :: Double } deriving 'Generic'
321360--
322−-- instance FromJSON Coord
361+-- instance 'FromJSON' Coord
323362-- @
324363--
325−-- If @DefaultSignatures@ doesn't give exactly the results you want,
326−-- you can customize the generic decoding with only a tiny amount of
327−-- 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:
328367--
329368-- @
330−-- instance FromJSON Coord where
331−-- parseJSON = 'genericParseJSON' 'defaultOptions'
369+-- customOptions = 'defaultOptions'
370+-- { 'fieldLabelModifier' = 'map' 'Data.Char.toUpper'
371+-- }
372+--
373+-- instance 'FromJSON' Coord where
374+-- 'parseJSON' = 'genericParseJSON' customOptions
332375-- @
333−
334376class FromJSON a where
335377 parseJSON :: Value -> Parser a
336378
@@ -338,13 +380,11 @@ class FromJSON a where
338380 parseJSON = genericParseJSON defaultOptions
339381
340382 parseJSONList :: Value -> Parser [a]
341− parseJSONList (Array a)
342− = zipWithM (parseIndexedJSON parseJSON) [0..]
383+ parseJSONList = withArray "[]" $ \a ->
384+ zipWithM (parseIndexedJSON parseJSON) [0..]
343385 . V.toList
344386 $ a
345387
346− parseJSONList v = typeMismatch "[a]" v
347−
348388-------------------------------------------------------------------------------
349389-- Classes and types for map keys
350390-------------------------------------------------------------------------------
@@ -356,6 +396,16 @@ class FromJSON a where
356396-- > newtype SomeId = SomeId { getSomeId :: Text }
357397-- > deriving (Eq,Ord,Hashable,FromJSONKey)
358398--
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+-- @
359409class FromJSONKey a where
360410 -- | Strategy for parsing the key of a map-like container.
361411 fromJSONKey :: FromJSONKeyFunction a
@@ -378,11 +428,7 @@ class FromJSONKey a where
378428-- At the moment this type is intentionally not exported. 'FromJSONKeyFunction'
379429-- can be inspected, but cannot be constructed.
380430data CoerceText a where
381−#if HAS_COERCIBLE
382431 CoerceText :: Coercible Text a => CoerceText a
383−#else
384− CoerceText :: CoerceText a
385−#endif
386432
387433-- | This type is related to 'ToJSONKeyFunction'. If 'FromJSONKeyValue' is used in the
388434-- 'FromJSONKey' instance, then 'ToJSONKeyValue' should be used in the 'ToJSONKey'
@@ -402,7 +448,7 @@ data FromJSONKeyFunction a
402448
403449-- | Only law abiding up to interpretation
404450instance Functor FromJSONKeyFunction where
405− fmap h (FromJSONKeyCoerce CoerceText) = FromJSONKeyText (h . coerce')
451+ fmap h (FromJSONKeyCoerce CoerceText) = FromJSONKeyText (h . coerce)
406452 fmap h (FromJSONKeyText f) = FromJSONKeyText (h . f)
407453 fmap h (FromJSONKeyTextParser f) = FromJSONKeyTextParser (fmap h . f)
408454 fmap h (FromJSONKeyValue f) = FromJSONKeyValue (fmap h . f)
@@ -416,9 +462,7 @@ instance Functor FromJSONKeyFunction where
416462--
417463-- On pre GHC 7.8 this is unconstrainted function.
418464fromJSONKeyCoerce ::
419−#if HAS_COERCIBLE
420465 Coercible Text a =>
421−#endif
422466 FromJSONKeyFunction a
423467fromJSONKeyCoerce = FromJSONKeyCoerce CoerceText
424468
@@ -426,60 +470,91 @@ fromJSONKeyCoerce = FromJSONKeyCoerce CoerceText
426470--
427471-- See note on 'fromJSONKeyCoerce'.
428472coerceFromJSONKeyFunction ::
429−#if HAS_COERCIBLE
430473 Coercible a b =>
431−#endif
432474 FromJSONKeyFunction a -> FromJSONKeyFunction b
433−#if HAS_COERCIBLE
434475coerceFromJSONKeyFunction = coerce
435−#else
436−coerceFromJSONKeyFunction (FromJSONKeyCoerce CoerceText) = FromJSONKeyCoerce CoerceText
437−coerceFromJSONKeyFunction (FromJSONKeyText f) = FromJSONKeyText (coerce' . f)
438−coerceFromJSONKeyFunction (FromJSONKeyTextParser f) = FromJSONKeyTextParser (fmap coerce' . f)
439−coerceFromJSONKeyFunction (FromJSONKeyValue f) = FromJSONKeyValue (fmap coerce' . f)
440−#endif
441476
442477{-# RULES
443478 "FromJSONKeyCoerce: fmap id" forall (x :: FromJSONKeyFunction a).
444479 fmap id x = x
445480 #-}
446−#if HAS_COERCIBLE
447481{-# RULES
448482 "FromJSONKeyCoerce: fmap coerce" forall x .
449483 fmap coerce x = coerceFromJSONKeyFunction x
450484 #-}
451−#endif
452485
453486-- | Same as 'fmap'. Provided for the consistency with 'ToJSONKeyFunction'.
454487mapFromJSONKeyFunction :: (a -> b) -> FromJSONKeyFunction a -> FromJSONKeyFunction b
455488mapFromJSONKeyFunction = fmap
456489
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+
457519-------------------------------------------------------------------------------
458520-- Functions needed for documentation
459521-------------------------------------------------------------------------------
460522
461523-- | Fail parsing due to a type mismatch, with a descriptive message.
462524--
463−-- Example usage:
525+-- The following wrappers should generally be prefered:
526+-- 'withObject', 'withArray', 'withText', 'withBool'.
464527--
465−-- @
466−-- instance FromJSON Coord where
467−-- parseJSON ('Object' v) = {- type matches, life is good -}
468−-- parseJSON wat = 'typeMismatch' \"Coord\" wat
469−-- @
470−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\"@).
471535 -> Value -- ^ The actual value encountered.
472536 -> Parser a
473537typeMismatch expected actual =
474− fail $ "expected " ++ expected ++ ", encountered " ++ name
475− where
476− name = case actual of
477− Object _ -> "Object"
478− Array _ -> "Array"
479− String _ -> "String"
480− Number _ -> "Number"
481− Bool _ -> "Boolean"
482− 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"
483558
484559-------------------------------------------------------------------------------
485560-- Lifings of FromJSON and ToJSON to unary and binary type constructors
@@ -492,7 +567,7 @@ typeMismatch expected actual =
492567--
493568-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
494569-- instance at compile time. The generated instance is optimized for your type
495−-- so will probably be more efficient than the following two options:
570+-- so it will probably be more efficient than the following option.
496571--
497572-- * The compiler can provide a default generic implementation for
498573-- 'liftParseJSON'.
@@ -510,16 +585,20 @@ typeMismatch expected actual =
510585--
511586-- data Pair a b = Pair { pairFst :: a, pairSnd :: b } deriving 'Generic1'
512587--
513−-- instance FromJSON a => FromJSON1 (Pair a)
588+-- instance 'FromJSON' a => 'FromJSON1' (Pair a)
514589-- @
515590--
516−-- If @DefaultSignatures@ doesn't give exactly the results you want,
591+-- If the default implementation doesn't give exactly the results you want,
517592-- you can customize the generic decoding with only a tiny amount of
518593-- effort, using 'genericLiftParseJSON' with your preferred 'Options':
519594--
520595-- @
521−-- instance FromJSON a => FromJSON1 (Pair a) where
522−-- 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
523602-- @
524603class FromJSON1 f where
525604 liftParseJSON :: (Value -> Parser a) -> (Value -> Parser [a]) -> Value -> Parser (f a)
@@ -556,9 +635,8 @@ class FromJSON2 f where
556635 -> (Value -> Parser b)
557636 -> (Value -> Parser [b])
558637 -> Value -> Parser [f a b]
559− liftParseJSONList2 fa ga fb gb v = case v of
560− Array vals -> fmap V.toList (V.mapM (liftParseJSON2 fa ga fb gb) vals)
561− _ -> typeMismatch "[a]" v
638+ liftParseJSONList2 fa ga fb gb = withArray "[]" $ \vals ->
639+ fmap V.toList (V.mapM (liftParseJSON2 fa ga fb gb) vals)
562640
563641-- | Lift the standard 'parseJSON' function through the type constructor.
564642parseJSON2 :: (FromJSON2 f, FromJSON a, FromJSON b) => Value -> Parser (f a b)
@@ -572,7 +650,7 @@ parseJSON2 = liftParseJSON2 parseJSON parseJSONList parseJSON parseJSONList
572650-- | Helper function to use with 'liftParseJSON'. See 'Data.Aeson.ToJSON.listEncoding'.
573651listParser :: (Value -> Parser a) -> Value -> Parser [a]
574652listParser f (Array xs) = fmap V.toList (V.mapM f xs)
575−listParser _ v = typeMismatch "[a]" v
653+listParser _ v = typeMismatch "Array" v
576654{-# INLINE listParser #-}
577655
578656-------------------------------------------------------------------------------
@@ -590,48 +668,139 @@ instance (FromJSON a) => FromJSON [a] where
590668-- Functions
591669-------------------------------------------------------------------------------
592670
593−-- | @withObject expected f value@ applies @f@ to the 'Object' when @value@ is an @Object@
594−-- 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"
595686withObject :: String -> (Object -> Parser a) -> Value -> Parser a
596−withObject _ f (Object obj) = f obj
597−withObject expected _ v = typeMismatch expected v
687+withObject _ f (Object obj) = f obj
688+withObject name _ v = prependContext name (typeMismatch "Object" v)
598689{-# INLINE withObject #-}
599690
600−-- | @withText expected f value@ applies @f@ to the 'Text' when @value@ is a @String@
601−-- 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"
602698withText :: String -> (Text -> Parser a) -> Value -> Parser a
603−withText _ f (String txt) = f txt
604−withText expected _ v = typeMismatch expected v
699+withText _ f (String txt) = f txt
700+withText name _ v = prependContext name (typeMismatch "String" v)
605701{-# INLINE withText #-}
606702
607−-- | @withArray expected f value@ applies @f@ to the 'Array' when @value@ is an @Array@
608−-- 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"
609710withArray :: String -> (Array -> Parser a) -> Value -> Parser a
610−withArray _ f (Array arr) = f arr
611−withArray expected _ v = typeMismatch expected v
711+withArray _ f (Array arr) = f arr
712+withArray name _ v = prependContext name (typeMismatch "Array" v)
612713{-# INLINE withArray #-}
613714
614−-- | @withNumber expected f value@ applies @f@ to the 'Number' when @value@ is a 'Number'.
615−-- and fails using @'typeMismatch' expected@ otherwise.
616−withNumber :: String -> (Number -> Parser a) -> Value -> Parser a
617−withNumber expected f = withScientific expected (f . scientificToNumber)
618−{-# INLINE withNumber #-}
619−{-# DEPRECATED withNumber "Use withScientific instead" #-}
620−
621−-- | @withScientific expected f value@ applies @f@ to the 'Scientific' number when @value@ is a 'Number'.
622−-- 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"
623728withScientific :: String -> (Scientific -> Parser a) -> Value -> Parser a
624−withScientific _ f (Number scientific) = f scientific
625−withScientific expected _ v = typeMismatch expected v
729+withScientific _ f (Number scientific) = f scientific
730+withScientific name _ v = prependContext name (typeMismatch "Number" v)
626731{-# INLINE withScientific #-}
627732
628−-- | @withBool expected f value@ applies @f@ to the 'Bool' when @value@ is a @Bool@
629−-- 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"
630789withBool :: String -> (Bool -> Parser a) -> Value -> Parser a
631−withBool _ f (Bool arr) = f arr
632−withBool expected _ v = typeMismatch expected v
790+withBool _ f (Bool arr) = f arr
791+withBool name _ v = prependContext name (typeMismatch "Boolean" v)
633792{-# INLINE withBool #-}
634793
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+
635804-- | Convert a value from JSON, failing if the types do not match.
636805fromJSON :: (FromJSON a) => Value -> Result a
637806fromJSON = parse parseJSON
@@ -650,32 +819,68 @@ ifromJSON = iparse parseJSON
650819-- in an object for it to be valid. If the key and value are
651820-- optional, use '.:?' instead.
652821(.:) :: (FromJSON a) => Object -> Text -> Parser a
653−obj .: key = case H.lookup key obj of
654− Nothing -> fail $ "key " ++ show key ++ " not present"
655− Just v -> parseJSON v <?> Key key
822+(.:) = explicitParseField parseJSON
656823{-# INLINE (.:) #-}
657824
658−-- | Retrieve the value associated with the given key of an 'Object'. The
659−-- result is 'Nothing' if the key is not present or value is 'Null', or 'empty'
660−-- if 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.
661828--
662829-- This accessor is most useful if the key and value can be absent
663830-- from an object without affecting its validity. If the key and
664831-- value are mandatory, use '.:' instead.
665832(.:?) :: (FromJSON a) => Object -> Text -> Parser (Maybe a)
666−obj .:? key = case H.lookup key obj of
667− Nothing -> pure Nothing
668− Just v -> parseJSON v <?> Key key
833+(.:?) = explicitParseFieldMaybe parseJSON
669834{-# INLINE (.:?) #-}
670835
671−-- | Like '.:?', but the resulting parser will fail,
672−-- 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'.
673842(.:!) :: (FromJSON a) => Object -> Text -> Parser (Maybe a)
674−obj .:! key = case H.lookup key obj of
675− Nothing -> pure Nothing
676− Just v -> Just <$> parseJSON v <?> Key key
843+(.:!) = explicitParseFieldMaybe' parseJSON
677844{-# INLINE (.:!) #-}
678845
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+
679884-- | Helper for use in combination with '.:?' to provide default
680885-- values for optional JSON object fields.
681886--
@@ -698,11 +903,47 @@ pmval .!= val = fromMaybe val <$> pmval
698903-- Generic parseJSON
699904-------------------------------------------------------------------------------
700905
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+
701911instance OVERLAPPABLE_ (GFromJSON arity a) => GFromJSON arity (M1 i c a) where
702912 -- Meta-information, which is not handled elsewhere, is just added to the
703913 -- parsed value:
704914 gParseJSON opts fargs = fmap M1 . gParseJSON opts fargs
705915
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
946+
706947instance (FromJSON a) => GFromJSON arity (K1 i a) where
707948 -- Constant values are decoded using their FromJSON instance:
708949 gParseJSON _opts _ = fmap K1 . parseJSON
@@ -717,327 +958,499 @@ instance (FromJSON1 f) => GFromJSON One (Rec1 f) where
717958 -- FromJSON1 instance:
718959 gParseJSON _opts (From1Args pj pjl) = fmap Rec1 . liftParseJSON pj pjl
719960
720−instance GFromJSON arity U1 where
721− -- Empty constructors are expected to be encoded as an empty array:
722− gParseJSON _opts _ v
723− | isEmptyArray v = pure U1
724− | otherwise = typeMismatch "unit constructor (U1)" v
725−
726−instance (ConsFromJSON arity a) => GFromJSON arity (C1 c a) where
727− -- Constructors need to be decoded differently depending on whether they're
728− -- a record or not. This distinction is made by consParseJSON:
729− gParseJSON opts fargs = fmap M1 . consParseJSON opts fargs
730−
731−instance ( FromProduct arity a, FromProduct arity b
732− , ProductSize a, ProductSize b
733− ) => GFromJSON arity (a :*: b) where
734− -- Products are expected to be encoded to an array. Here we check whether we
735− -- got an array of the same size as the product, then parse each of the
736− -- product's elements using parseProduct:
737− gParseJSON opts fargs = withArray "product (:*:)" $ \arr ->
738− let lenArray = V.length arr
739− lenProduct = (unTagged2 :: Tagged2 (a :*: b) Int -> Int)
740− productSize in
741− if lenArray == lenProduct
742− then parseProduct opts fargs arr 0 lenProduct
743− else fail $ "When expecting a product of " ++ show lenProduct ++
744− " values, encountered an Array of " ++ show lenArray ++
745− " elements instead"
746−
747−instance ( AllNullary (a :+: b) allNullary
748− , ParseSum arity (a :+: b) allNullary
749− ) => GFromJSON arity (a :+: b) where
750− -- If all constructors of a sum datatype are nullary and the
751− -- 'allNullaryToStringTag' option is set they are expected to be
752− -- encoded as strings. This distinction is made by 'parseSum':
753− gParseJSON opts fargs =
754− (unTagged :: Tagged allNullary (Parser ((a :+: b) d)) ->
755− Parser ((a :+: b) d))
756− . parseSum opts fargs
757−
758961instance (FromJSON1 f, GFromJSON One g) => GFromJSON One (f :.: g) where
759962 -- If an occurrence of the last type parameter is nested inside two
760963 -- composed types, it is decoded by using the outermost type's FromJSON1
761964 -- instance to generically decode the innermost type:
762965 gParseJSON opts fargs =
763− let gpj = gParseJSON opts fargs in
764− fmap Comp1 . liftParseJSON gpj (listParser gpj)
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
7651013
7661014--------------------------------------------------------------------------------
7671015
7681016class ParseSum arity f allNullary where
769− parseSum :: Options -> FromArgs arity a
770− -> Value -> Tagged allNullary (Parser (f a))
771−
772−instance ( SumFromString (a :+: b)
773− , FromPair arity (a :+: b)
774− , FromTaggedObject arity (a :+: b)
775− , FromUntaggedValue arity (a :+: b)
776− ) => ParseSum arity (a :+: b) True where
777− parseSum opts fargs
778− | allNullaryToStringTag opts = Tagged . parseAllNullarySum opts
779− | otherwise = Tagged . parseNonAllNullarySum opts fargs
780−
781−instance ( FromPair arity (a :+: b)
782− , FromTaggedObject arity (a :+: b)
783− , FromUntaggedValue arity (a :+: b)
784− ) => ParseSum arity (a :+: b) False where
785− parseSum opts fargs = Tagged . parseNonAllNullarySum opts fargs
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
7861037
7871038--------------------------------------------------------------------------------
7881039
789−parseAllNullarySum :: SumFromString f => Options -> Value -> Parser (f a)
790−parseAllNullarySum opts = withText "Text" $ \key ->
791− maybe (notFound key) return $
792− 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])
7931062
7941063class SumFromString f where
795− parseSumFromString :: Options -> Text -> Maybe (f a)
1064+ parseSumFromString :: (String -> String) -> Text -> Maybe (f a)
7961065
7971066instance (SumFromString a, SumFromString b) => SumFromString (a :+: b) where
7981067 parseSumFromString opts key = (L1 <$> parseSumFromString opts key) <|>
7991068 (R1 <$> parseSumFromString opts key)
8001069
8011070instance (Constructor c) => SumFromString (C1 c U1) where
802− parseSumFromString opts key | key == name = Just $ M1 U1
803− | otherwise = Nothing
804− where
805− name = pack $ constructorTagModifier opts $
806− 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)
8071076
808−--------------------------------------------------------------------------------
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)
8091090
810−parseNonAllNullarySum :: ( FromPair arity (a :+: b)
811− , FromTaggedObject arity (a :+: b)
812− , FromUntaggedValue arity (a :+: b)
813− ) => Options -> FromArgs arity c
814− -> Value -> Parser ((a :+: b) c)
815−parseNonAllNullarySum opts fargs =
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
1111+
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 :* _) =
8161121 case sumEncoding opts of
8171122 TaggedObject{..} ->
818− withObject "Object" $ \obj -> do
819− tag <- obj .: pack tagFieldName
820− fromMaybe (notFound tag) $
821− parseFromTaggedObject opts fargs contentsFieldName obj 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])
8221133
8231134 ObjectWithSingleField ->
824− withObject "Object" $ \obj ->
825− case H.toList obj of
826− [pair@(tag, _)] -> fromMaybe (notFound tag) $
827− parsePair opts fargs pair
828− _ -> 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
8291145
8301146 TwoElemArray ->
831− withArray "Array" $ \arr ->
832− if V.length arr == 2
833− then case V.unsafeIndex arr 0 of
834− String tag -> fromMaybe (notFound tag) $
835− parsePair opts fargs (tag, V.unsafeIndex arr 1)
836− _ -> fail "First element is not a String"
837− 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
8381161
839− UntaggedValue -> parseUntaggedValue opts fargs
1162+ UntaggedValue -> parseUntaggedValue p
1163+ where
1164+ failWith_ = failWithCTags tname (constructorTagModifier opts)
8401165
8411166--------------------------------------------------------------------------------
8421167
8431168class FromTaggedObject arity f where
844− parseFromTaggedObject :: Options -> FromArgs arity a
845− -> String -> Object
846− -> 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))
8471175
8481176instance ( FromTaggedObject arity a, FromTaggedObject arity b) =>
8491177 FromTaggedObject arity (a :+: b) where
850− parseFromTaggedObject opts fargs contentsFieldName obj tag =
851− (fmap L1 <$> parseFromTaggedObject opts fargs contentsFieldName obj tag) <|>
852− (fmap R1 <$> parseFromTaggedObject opts fargs contentsFieldName obj tag)
1178+ parseFromTaggedObject p obj =
1179+ (fmap L1 <$> parseFromTaggedObject p obj) <|>
1180+ (fmap R1 <$> parseFromTaggedObject p obj)
8531181
854−instance ( FromTaggedObject' arity f
1182+instance ( IsRecord f isRecord
1183+ , FromTaggedObject' arity f isRecord
8551184 , Constructor c
8561185 ) => FromTaggedObject arity (C1 c f) where
857− parseFromTaggedObject opts fargs contentsFieldName obj tag
858− | tag == name = Just $ M1 <$> parseFromTaggedObject'
859− opts fargs contentsFieldName obj
860− | otherwise = Nothing
861− where
862− name = pack $ constructorTagModifier opts $
863− 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)
8641195
8651196--------------------------------------------------------------------------------
8661197
867−class FromTaggedObject' arity f where
868− parseFromTaggedObject' :: Options -> FromArgs arity a -> String
869− -> Object -> Parser (f a)
870−
871−class FromTaggedObject'' arity f isRecord where
872− parseFromTaggedObject'' :: Options -> FromArgs arity a -> String
873− -> Object -> Tagged isRecord (Parser (f a))
874−
875−instance ( IsRecord f isRecord
876− , FromTaggedObject'' arity f isRecord
877− ) => FromTaggedObject' arity f where
878− parseFromTaggedObject' opts fargs contentsFieldName =
879− (unTagged :: Tagged isRecord (Parser (f a)) -> Parser (f a)) .
880− parseFromTaggedObject'' opts fargs contentsFieldName
881−
882−instance (FromRecord arity f) => FromTaggedObject'' arity f True where
883− parseFromTaggedObject'' opts fargs _ =
884− Tagged . parseRecord opts fargs Nothing
885−
886−instance (GFromJSON arity f) => FromTaggedObject'' arity f False where
887− parseFromTaggedObject'' opts fargs contentsFieldName = Tagged .
888− (gParseJSON opts fargs <=< (.: 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
8891216
890−instance OVERLAPPING_ FromTaggedObject'' arity U1 False where
891− 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)
8921220
8931221--------------------------------------------------------------------------------
8941222
1223+-- | Constructors need to be decoded differently depending on whether they're
1224+-- a record or not. This distinction is made by 'ConsParseJSON'.
8951225class ConsFromJSON arity f where
896− consParseJSON :: Options -> FromArgs arity a
897− -> Value -> Parser (f a)
1226+ consParseJSON
1227+ :: ConName :* TypeName :* Options :* FromArgs arity a
1228+ -> Value -> Parser (f a)
8981229
8991230class ConsFromJSON' arity f isRecord where
900− consParseJSON' :: Options -> FromArgs arity a
901− -> Maybe Text -- ^ A dummy label
902− -- (Nothing to use proper label)
903− -> Value -> Tagged isRecord (Parser (f a))
1231+ consParseJSON'
1232+ :: ConName :* TypeName :* Options :* FromArgs arity a
1233+ -> Value -> Tagged isRecord (Parser (f a))
9041234
9051235instance ( IsRecord f isRecord
9061236 , ConsFromJSON' arity f isRecord
9071237 ) => ConsFromJSON arity f where
908− consParseJSON opts fargs v = let
909− (v2,lab) = case (unwrapUnaryRecords opts,isUnary (undefined :: f a)) of
910− -- use a dummy object with a dummy label
911− (True,True) -> (object [(pack "dummy",v)], Just $ pack "dummy")
912− _ ->(v,Nothing)
913− in (unTagged :: Tagged isRecord (Parser (f a)) -> Parser (f a))
914− $ consParseJSON' opts fargs lab v2
1238+ consParseJSON p =
1239+ (unTagged :: Tagged isRecord (Parser (f a)) -> Parser (f a))
1240+ . consParseJSON' p
9151241
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))
9161248
917−instance (FromRecord arity f) => ConsFromJSON' arity f True where
918− consParseJSON' opts fargs mlab = Tagged . withObject "record (:*:)"
919− (parseRecord opts fargs mlab)
1249+instance RecordFromJSON arity f => ConsFromJSON' arity f True where
1250+ consParseJSON' p@(cname :* tname :* _) =
1251+ Tagged . withObject (showCons cname tname) (recordParseJSON (False :* p))
9201252
921−instance (GFromJSON arity f) => ConsFromJSON' arity f False where
922− consParseJSON' opts fargs _ = Tagged . gParseJSON opts fargs
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)
1265+
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
1270+
1271+instance (ProductFromJSON arity f, ProductSize f
1272+ ) => ConsFromJSON' arity f False where
1273+ consParseJSON' p = Tagged . productParseJSON0 p
9231274
9241275--------------------------------------------------------------------------------
9251276
926−class FromRecord arity f where
927− parseRecord :: Options -> FromArgs arity a
928− -> Maybe Text -- ^ A dummy label
929− -- (Nothing to use proper label)
930− -> Object -> Parser (f a)
931−
932−instance ( FromRecord arity a
933− , FromRecord arity b
934− ) => FromRecord arity (a :*: b) where
935− parseRecord opts fargs _ obj =
936− (:*:) <$> parseRecord opts fargs Nothing obj
937− <*> parseRecord opts fargs Nothing obj
938−
939−instance ( Selector s
940− , GFromJSON arity a
941− ) => FromRecord arity (S1 s a) where
942− parseRecord opts fargs lab =
943− (<?> Key label) . gParseJSON opts fargs <=< (.: label)
944− where
945− label = fromMaybe defLabel lab
946− defLabel = pack . fieldLabelModifier opts $
947− selName (undefined :: t s a p)
948−
949−instance OVERLAPPING_ (Selector s, FromJSON a) =>
950− FromRecord arity (S1 s (K1 i (Maybe a))) where
951− parseRecord _ _ (Just lab) obj = (M1 . K1) <$> obj .:? lab
952− 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
9531298 where
954− label = fieldLabelModifier opts $
955− 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))
9561346
9571347--------------------------------------------------------------------------------
9581348
959−class FromProduct arity f where
960− parseProduct :: Options -> FromArgs arity a
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
9611371 -> Array -> Int -> Int
9621372 -> Parser (f a)
9631373
964−instance ( FromProduct arity a
965− , FromProduct arity b
966− ) => FromProduct arity (a :*: b) where
967− parseProduct opts fargs arr ix len =
968− (:*:) <$> parseProduct opts fargs arr ix lenL
969− <*> parseProduct opts fargs arr ixR lenR
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
9701380 where
9711381 lenL = len `unsafeShiftR` 1
9721382 ixR = ix + lenL
9731383 lenR = len - lenL
9741384
975−instance (GFromJSON arity a) => FromProduct arity (S1 s a) where
976− parseProduct opts fargs arr ix _ =
977− gParseJSON opts fargs $ 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
9781388
9791389--------------------------------------------------------------------------------
9801390
9811391class FromPair arity f where
982− parsePair :: Options -> FromArgs arity a
983− -> 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))
9841396
9851397instance ( FromPair arity a
9861398 , FromPair arity b
9871399 ) => FromPair arity (a :+: b) where
988− parsePair opts fargs pair = (fmap L1 <$> parsePair opts fargs pair) <|>
989− (fmap R1 <$> parsePair opts fargs pair)
1400+ parsePair p pair =
1401+ (fmap L1 <$> parsePair p pair) <|>
1402+ (fmap R1 <$> parsePair p pair)
9901403
9911404instance ( Constructor c
992− , GFromJSON arity a
9931405 , ConsFromJSON arity a
9941406 ) => FromPair arity (C1 c a) where
995− parsePair opts fargs (tag, value)
996− | tag == tag' = Just $ gParseJSON opts fargs value
1407+ parsePair (tag :* p@(_ :* opts :* _)) v
1408+ | tag == tag' = Just $ M1 <$> consParseJSON (cname :* p) v
9971409 | otherwise = Nothing
998− where
999− tag' = pack $ constructorTagModifier opts $
1000− conName (undefined :: t c a p)
1410+ where
1411+ tag' = pack $ constructorTagModifier opts cname
1412+ cname = conName (undefined :: M1 _i c _a _p)
10011413
10021414--------------------------------------------------------------------------------
10031415
10041416class FromUntaggedValue arity f where
1005− parseUntaggedValue :: Options -> FromArgs arity a
1006− -> Value -> Parser (f a)
1417+ parseUntaggedValue :: TypeName :* Options :* FromArgs arity a
1418+ -> Value
1419+ -> Parser (f a)
10071420
10081421instance
10091422 ( FromUntaggedValue arity a
10101423 , FromUntaggedValue arity b
10111424 ) => FromUntaggedValue arity (a :+: b)
10121425 where
1013− parseUntaggedValue opts fargs value =
1014− L1 <$> parseUntaggedValue opts fargs value <|>
1015− R1 <$> parseUntaggedValue opts fargs value
1426+ parseUntaggedValue p value =
1427+ L1 <$> parseUntaggedValue p value <|>
1428+ R1 <$> parseUntaggedValue p value
10161429
10171430instance OVERLAPPABLE_
1018− ( GFromJSON arity a
1019− , ConsFromJSON arity a
1431+ ( ConsFromJSON arity a
1432+ , Constructor c
10201433 ) => FromUntaggedValue arity (C1 c a)
10211434 where
1022− parseUntaggedValue = gParseJSON
1435+ parseUntaggedValue p = fmap M1 . consParseJSON (cname :* p)
1436+ where
1437+ cname = conName (undefined :: M1 _i c _f _p)
10231438
10241439instance OVERLAPPING_
10251440 ( Constructor c )
10261441 => FromUntaggedValue arity (C1 c U1)
10271442 where
1028− parseUntaggedValue opts _ (String s)
1029− | s == pack (constructorTagModifier opts (conName (undefined :: t c U1 p))) =
1030− pure $ M1 U1
1031− | otherwise =
1032− fail $ "Invalid tag: " ++ unpack s
1033− parseUntaggedValue _ _ v = typeMismatch (conName (undefined :: t c U1 p)) v
1034−
1035−
1036−--------------------------------------------------------------------------------
1037−
1038−notFound :: Text -> Parser a
1039−notFound key = fail $ "The key \"" ++ unpack key ++ "\" was not found"
1040−{-# INLINE notFound #-}
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
10411454
10421455-------------------------------------------------------------------------------
10431456-- Instances
@@ -1095,17 +1508,20 @@ instance (FromJSON a, FromJSON b) => FromJSON (Either a b) where
10951508 parseJSON = parseJSON2
10961509 {-# INLINE parseJSON #-}
10971510
1098−
1511+instance FromJSON Void where
1512+ parseJSON _ = fail "Cannot parse Void"
1513+ {-# INLINE parseJSON #-}
10991514
11001515instance FromJSON Bool where
1101− parseJSON = withBool "Bool" pure
1516+ parseJSON (Bool b) = pure b
1517+ parseJSON v = typeMismatch "Bool" v
11021518 {-# INLINE parseJSON #-}
11031519
11041520instance FromJSONKey Bool where
11051521 fromJSONKey = FromJSONKeyTextParser $ \t -> case t of
11061522 "true" -> pure True
11071523 "false" -> pure False
1108− _ -> fail $ "Cannot parse key into Bool: " ++ T.unpack t
1524+ _ -> fail $ "cannot parse key " ++ show t ++ " into Bool"
11091525
11101526instance FromJSON Ordering where
11111527 parseJSON = withText "Ordering" $ \s ->
@@ -1113,25 +1529,30 @@ instance FromJSON Ordering where
11131529 "LT" -> return LT
11141530 "EQ" -> return EQ
11151531 "GT" -> return GT
1116− _ -> fail "Parsing Ordering value failed: expected \"LT\", \"EQ\", or \"GT\""
1532+ _ -> fail $ "parsing Ordering failed, unexpected " ++ show s ++
1533+ " (expected \"LT\", \"EQ\", or \"GT\")"
11171534
11181535instance FromJSON () where
11191536 parseJSON = withArray "()" $ \v ->
11201537 if V.null v
11211538 then pure ()
1122− else fail "Expected an empty array"
1539+ else prependContext "()" $ fail "expected an empty array"
11231540 {-# INLINE parseJSON #-}
11241541
11251542instance FromJSON Char where
1126− parseJSON = withText "Char" $ \t ->
1127− if T.compareLength t 1 == EQ
1128− then pure $ T.head t
1129− else fail "Expected a string of length 1"
1543+ parseJSON = withText "Char" parseChar
11301544 {-# INLINE parseJSON #-}
11311545
1132− parseJSONList = withText "String" $ pure . T.unpack
1546+ parseJSONList (String s) = pure (T.unpack s)
1547+ parseJSONList v = typeMismatch "String" v
11331548 {-# INLINE parseJSONList #-}
11341549
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+
11351556instance FromJSON Double where
11361557 parseJSON = parseRealFloat "Double"
11371558 {-# INLINE parseJSON #-}
@@ -1143,12 +1564,6 @@ instance FromJSONKey Double where
11431564 "-Infinity" -> pure (negate 1/0)
11441565 _ -> Scientific.toRealFloat <$> parseScientificText t
11451566
1146−instance FromJSON Number where
1147− parseJSON (Number s) = pure $ scientificToNumber s
1148− parseJSON Null = pure (D (0/0))
1149− parseJSON v = typeMismatch "Number" v
1150− {-# INLINE parseJSON #-}
1151−
11521567instance FromJSON Float where
11531568 parseJSON = parseRealFloat "Float"
11541569 {-# INLINE parseJSON #-}
@@ -1161,17 +1576,30 @@ instance FromJSONKey Float where
11611576 _ -> Scientific.toRealFloat <$> parseScientificText t
11621577
11631578instance (FromJSON a, Integral a) => FromJSON (Ratio a) where
1164− parseJSON = withObject "Rational" $ \obj ->
1165− (%) <$> obj .: "numerator"
1166− <*> obj .: "denominator"
1167− {-# INLINE parseJSON #-}
1168−
1169−-- | /WARNING:/ Only parse fixed-precision numbers from trusted input
1170−-- since an attacker could easily fill up the memory of the target
1171−-- system by specifying a scientific number with a big exponent like
1172−-- @1e1000000000@.
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
1595+ {-# INLINE parseJSON #-}
1596+
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.
11731601instance HasResolution a => FromJSON (Fixed a) where
1174− parseJSON = withScientific "Fixed" $ pure . realToFrac
1602+ parseJSON = prependContext "Fixed" . withBoundedScientific' (pure . realToFrac)
11751603 {-# INLINE parseJSON #-}
11761604
11771605instance FromJSON Int where
@@ -1181,10 +1609,10 @@ instance FromJSON Int where
11811609instance FromJSONKey Int where
11821610 fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Int"
11831611
1184−-- | /WARNING:/ Only parse Integers from trusted input since an
1185−-- attacker could easily fill up the memory of the target system by
1186−-- specifying a scientific number with a big exponent like
1187−-- @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.
11881616instance FromJSON Integer where
11891617 parseJSON = parseIntegral "Integer"
11901618 {-# INLINE parseJSON #-}
@@ -1193,16 +1621,21 @@ instance FromJSONKey Integer where
11931621 fromJSONKey = FromJSONKeyTextParser $ parseIntegralText "Integer"
11941622
11951623instance FromJSON Natural where
1196− parseJSON = withScientific "Natural" $ \s ->
1197− if Scientific.coefficient s < 0
1198− then fail $ "Expected a Natural number but got the negative number: " <> show s
1199− else pure $ truncate s
1624+ parseJSON value = do
1625+ integer <- parseIntegral "Natural" value
1626+ parseNatural integer
12001627
12011628instance FromJSONKey Natural where
1202− fromJSONKey = FromJSONKeyTextParser $ \t -> parseScientificText t >>= \s ->
1203− if Scientific.coefficient s < 0
1204− then fail $ "Expected a Natural number but got the negative number: " <> show s
1205− 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
12061639
12071640instance FromJSON Int8 where
12081641 parseJSON = parseBoundedIntegral "Int8"
@@ -1267,6 +1700,9 @@ instance FromJSON Word64 where
12671700instance FromJSONKey Word64 where
12681701 fromJSONKey = FromJSONKeyTextParser $ parseBoundedIntegralText "Word64"
12691702
1703+instance FromJSON CTime where
1704+ parseJSON = fmap CTime . parseJSON
1705+ {-# INLINE parseJSON #-}
12701706
12711707instance FromJSON Text where
12721708 parseJSON = withText "Text" pure
@@ -1296,17 +1732,17 @@ parseVersionText = go . readP_to_S parseVersion . unpack
12961732 where
12971733 go [(v,[])] = return v
12981734 go (_ : xs) = go xs
1299− go _ = fail "could not parse Version"
1735+ go _ = fail "parsing Version failed"
13001736
13011737-------------------------------------------------------------------------------
13021738-- semigroups NonEmpty
13031739-------------------------------------------------------------------------------
13041740
13051741instance FromJSON1 NonEmpty where
1306− liftParseJSON p _ = withArray "NonEmpty a" $
1742+ liftParseJSON p _ = withArray "NonEmpty" $
13071743 (>>= ne) . Tr.sequence . zipWith (parseIndexedJSON p) [0..] . V.toList
13081744 where
1309− ne [] = fail "Expected a NonEmpty but got an empty list"
1745+ ne [] = fail "parsing NonEmpty failed, unexpected empty list"
13101746 ne (x:xs) = pure (x :| xs)
13111747 {-# INLINE liftParseJSON #-}
13121748
@@ -1327,7 +1763,7 @@ instance FromJSON Scientific where
13271763-------------------------------------------------------------------------------
13281764
13291765instance FromJSON1 DList.DList where
1330− liftParseJSON p _ = withArray "DList a" $
1766+ liftParseJSON p _ = withArray "DList" $
13311767 fmap DList.fromList .
13321768 Tr.sequence . zipWith (parseIndexedJSON p) [0..] . V.toList
13331769 {-# INLINE liftParseJSON #-}
@@ -1354,7 +1790,7 @@ instance (FromJSON a) => FromJSON (Identity a) where
13541790 parseJSONList = liftParseJSONList parseJSON parseJSONList
13551791 {-# INLINE parseJSONList #-}
13561792
1357−instance (FromJSONKey a, FromJSON a) => FromJSONKey (Identity a) where
1793+instance (FromJSONKey a) => FromJSONKey (Identity a) where
13581794 fromJSONKey = coerceFromJSONKeyFunction (fromJSONKey :: FromJSONKeyFunction a)
13591795 fromJSONKeyList = coerceFromJSONKeyFunction (fromJSONKeyList :: FromJSONKeyFunction [a])
13601796
@@ -1404,7 +1840,7 @@ instance (FromJSON1 f, FromJSON1 g) => FromJSON1 (Sum f g) where
14041840 inr = "InR"
14051841
14061842 liftParseJSON _ _ _ = fail $
1407− "expected an object with a single property " ++
1843+ "parsing Sum failed, expected an object with a single property " ++
14081844 "where the property key should be either " ++
14091845 "\"InL\" or \"InR\""
14101846 {-# INLINE liftParseJSON #-}
@@ -1418,7 +1854,7 @@ instance (FromJSON1 f, FromJSON1 g, FromJSON a) => FromJSON (Sum f g a) where
14181854-------------------------------------------------------------------------------
14191855
14201856instance FromJSON1 Seq.Seq where
1421− liftParseJSON p _ = withArray "Seq a" $
1857+ liftParseJSON p _ = withArray "Seq" $
14221858 fmap Seq.fromList .
14231859 Tr.sequence . zipWith (parseIndexedJSON p) [0..] . V.toList
14241860 {-# INLINE liftParseJSON #-}
@@ -1452,15 +1888,15 @@ instance FromJSON a => FromJSON (IntMap.IntMap a) where
14521888
14531889instance (FromJSONKey k, Ord k) => FromJSON1 (M.Map k) where
14541890 liftParseJSON p _ = case fromJSONKey of
1455− FromJSONKeyCoerce _-> withObject "Map k v" $
1891+ FromJSONKeyCoerce _ -> withObject "Map" $
14561892 fmap (H.foldrWithKey (M.insert . unsafeCoerce) M.empty) . H.traverseWithKey (\k v -> p v <?> Key k)
1457− FromJSONKeyText f -> withObject "Map k v" $
1893+ FromJSONKeyText f -> withObject "Map" $
14581894 fmap (H.foldrWithKey (M.insert . f) M.empty) . H.traverseWithKey (\k v -> p v <?> Key k)
1459− FromJSONKeyTextParser f -> withObject "Map k v" $
1895+ FromJSONKeyTextParser f -> withObject "Map" $
14601896 H.foldrWithKey (\k v m -> M.insert <$> f k <?> Key k <*> p v <?> Key k <*> m) (pure M.empty)
1461− FromJSONKeyValue f -> withArray "Map k v" $ \arr ->
1462− M.fromList <$> (Tr.sequence .
1463− zipWith (parseIndexedJSONPair f p) [0..] . V.toList $ arr)
1897+ FromJSONKeyValue f -> withArray "Map" $ \arr ->
1898+ fmap M.fromList . Tr.sequence .
1899+ zipWith (parseIndexedJSONPair f p) [0..] . V.toList $ arr
14641900 {-# INLINE liftParseJSON #-}
14651901
14661902instance (FromJSONKey k, Ord k, FromJSON v) => FromJSON (M.Map k v) where
@@ -1480,12 +1916,24 @@ instance (FromJSON v) => FromJSON (Tree.Tree v) where
14801916 parseJSON = parseJSON1
14811917 {-# INLINE parseJSON #-}
14821918
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+
14831931-------------------------------------------------------------------------------
14841932-- vector
14851933-------------------------------------------------------------------------------
14861934
14871935instance FromJSON1 Vector where
1488− liftParseJSON p _ = withArray "Vector a" $
1936+ liftParseJSON p _ = withArray "Vector" $
14891937 V.mapM (uncurry $ parseIndexedJSON p) . V.indexed
14901938 {-# INLINE liftParseJSON #-}
14911939
@@ -1499,14 +1947,14 @@ vectorParseJSON s = withArray s $ fmap V.convert . V.mapM (uncurry $ parseIndexe
14991947{-# INLINE vectorParseJSON #-}
15001948
15011949instance (Storable a, FromJSON a) => FromJSON (VS.Vector a) where
1502− parseJSON = vectorParseJSON "Data.Vector.Storable.Vector a"
1950+ parseJSON = vectorParseJSON "Data.Vector.Storable.Vector"
15031951
15041952instance (VP.Prim a, FromJSON a) => FromJSON (VP.Vector a) where
1505− parseJSON = vectorParseJSON "Data.Vector.Primitive.Vector a"
1953+ parseJSON = vectorParseJSON "Data.Vector.Primitive.Vector"
15061954 {-# INLINE parseJSON #-}
15071955
15081956instance (VG.Vector VU.Vector a, FromJSON a) => FromJSON (VU.Vector a) where
1509− parseJSON = vectorParseJSON "Data.Vector.Unboxed.Vector a"
1957+ parseJSON = vectorParseJSON "Data.Vector.Unboxed.Vector"
15101958 {-# INLINE parseJSON #-}
15111959
15121960-------------------------------------------------------------------------------
@@ -1520,15 +1968,15 @@ instance (Eq a, Hashable a, FromJSON a) => FromJSON (HashSet.HashSet a) where
15201968
15211969instance (FromJSONKey k, Eq k, Hashable k) => FromJSON1 (H.HashMap k) where
15221970 liftParseJSON p _ = case fromJSONKey of
1523− FromJSONKeyCoerce _ -> withObject "HashMap ~Text v" $
1971+ FromJSONKeyCoerce _ -> withObject "HashMap ~Text" $
15241972 uc . H.traverseWithKey (\k v -> p v <?> Key k)
1525− FromJSONKeyText f -> withObject "HashMap k v" $
1973+ FromJSONKeyText f -> withObject "HashMap" $
15261974 fmap (mapKey f) . H.traverseWithKey (\k v -> p v <?> Key k)
1527− FromJSONKeyTextParser f -> withObject "HashMap k v" $
1975+ FromJSONKeyTextParser f -> withObject "HashMap" $
15281976 H.foldrWithKey (\k v m -> H.insert <$> f k <?> Key k <*> p v <?> Key k <*> m) (pure H.empty)
1529− FromJSONKeyValue f -> withArray "Map k v" $ \arr ->
1530− H.fromList <$> (Tr.sequence .
1531− zipWith (parseIndexedJSONPair f p) [0..] . V.toList $ arr)
1977+ FromJSONKeyValue f -> withArray "Map" $ \arr ->
1978+ fmap H.fromList . Tr.sequence .
1979+ zipWith (parseIndexedJSONPair f p) [0..] . V.toList $ arr
15321980 where
15331981 uc :: Parser (H.HashMap Text v) -> Parser (H.HashMap k v)
15341982 uc = unsafeCoerce
@@ -1549,11 +1997,33 @@ instance FromJSON DotNetTime where
15491997 parseJSON = withText "DotNetTime" $ \t ->
15501998 let (s,m) = T.splitAt (T.length t - 5) t
15511999 t' = T.concat [s,".",m]
1552− in case parseTime defaultTimeLocale "/Date(%s%Q)/" (unpack t') of
2000+ in case parseTimeM True defaultTimeLocale "/Date(%s%Q)/" (unpack t') of
15532001 Just d -> pure (DotNetTime d)
15542002 _ -> fail "could not parse .NET time"
15552003 {-# INLINE parseJSON #-}
15562004
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+
15572027-------------------------------------------------------------------------------
15582028-- time
15592029-------------------------------------------------------------------------------
@@ -1579,6 +2049,17 @@ instance FromJSONKey LocalTime where
15792049 fromJSONKey = FromJSONKeyTextParser (Time.run Time.localTime)
15802050
15812051
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.
15822063instance FromJSON ZonedTime where
15832064 parseJSON = withText "ZonedTime" (Time.run Time.zonedTime)
15842065
@@ -1593,41 +2074,168 @@ instance FromJSONKey UTCTime where
15932074 fromJSONKey = FromJSONKeyTextParser (Time.run Time.utcTime)
15942075
15952076
1596−-- | /WARNING:/ Only parse lengths of time from trusted input
1597−-- since an attacker could easily fill up the memory of the target
1598−-- system by specifying a scientific number with a big exponent like
1599−-- @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.
16002081instance FromJSON NominalDiffTime where
1601− parseJSON = withScientific "NominalDiffTime" $ pure . realToFrac
2082+ parseJSON = withBoundedScientific "NominalDiffTime" $ pure . realToFrac
16022083 {-# INLINE parseJSON #-}
16032084
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+
16042128-------------------------------------------------------------------------------
16052129-- base Monoid/Semigroup
16062130-------------------------------------------------------------------------------
16072131
1608−instance FromJSON1 Dual where
1609− 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
2176+ {-# INLINE liftParseJSON #-}
2177+
2178+ liftParseJSONList _ p a = fmap Semigroup.Max <$> p a
2179+ {-# INLINE liftParseJSONList #-}
2180+
2181+instance (FromJSON a) => FromJSON (Semigroup.Max a) where
2182+ parseJSON = parseJSON1
2183+ {-# INLINE parseJSON #-}
2184+
2185+ parseJSONList = liftParseJSONList parseJSON parseJSONList
2186+ {-# INLINE parseJSONList #-}
2187+
2188+
2189+instance FromJSON1 Semigroup.First where
2190+ liftParseJSON p _ a = Semigroup.First <$> p a
16102191 {-# INLINE liftParseJSON #-}
16112192
1612−instance FromJSON a => FromJSON (Dual a) where
2193+ liftParseJSONList _ p a = fmap Semigroup.First <$> p a
2194+ {-# INLINE liftParseJSONList #-}
2195+
2196+instance (FromJSON a) => FromJSON (Semigroup.First a) where
16132197 parseJSON = parseJSON1
16142198 {-# INLINE parseJSON #-}
16152199
2200+ parseJSONList = liftParseJSONList parseJSON parseJSONList
2201+ {-# INLINE parseJSONList #-}
2202+
16162203
1617−instance FromJSON1 First where
1618− liftParseJSON p p' = fmap First . liftParseJSON p p'
2204+instance FromJSON1 Semigroup.Last where
2205+ liftParseJSON p _ a = Semigroup.Last <$> p a
16192206 {-# INLINE liftParseJSON #-}
16202207
1621−instance FromJSON a => FromJSON (First a) where
2208+ liftParseJSONList _ p a = fmap Semigroup.Last <$> p a
2209+ {-# INLINE liftParseJSONList #-}
2210+
2211+instance (FromJSON a) => FromJSON (Semigroup.Last a) where
16222212 parseJSON = parseJSON1
16232213 {-# INLINE parseJSON #-}
16242214
2215+ parseJSONList = liftParseJSONList parseJSON parseJSONList
2216+ {-# INLINE parseJSONList #-}
16252217
1626−instance FromJSON1 Last where
1627− liftParseJSON p p' = fmap Last . liftParseJSON p p'
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'
16282236 {-# INLINE liftParseJSON #-}
16292237
1630−instance FromJSON a => FromJSON (Last a) where
2238+instance FromJSON a => FromJSON (Semigroup.Option a) where
16312239 parseJSON = parseJSON1
16322240 {-# INLINE parseJSON #-}
16332241
@@ -1635,11 +2243,21 @@ instance FromJSON a => FromJSON (Last a) where
16352243-- tagged
16362244-------------------------------------------------------------------------------
16372245
2246+instance FromJSON1 Proxy where
2247+ {-# INLINE liftParseJSON #-}
2248+ liftParseJSON _ _ = fromNull "Proxy" Proxy
2249+
16382250instance FromJSON (Proxy a) where
16392251 {-# INLINE parseJSON #-}
1640− parseJSON Null = pure Proxy
1641− parseJSON v = typeMismatch "Proxy" v
2252+ parseJSON = fromNull "Proxy" Proxy
16422253
2254+fromNull :: String -> a -> Value -> Parser a
2255+fromNull _ a Null = pure a
2256+fromNull c _ v = prependContext c (typeMismatch "Null" v)
2257+
2258+instance FromJSON2 Tagged where
2259+ liftParseJSON2 _ _ p _ = fmap Tagged . p
2260+ {-# INLINE liftParseJSON2 #-}
16432261
16442262instance FromJSON1 (Tagged a) where
16452263 liftParseJSON p _ = fmap Tagged . p
@@ -1662,10 +2280,7 @@ instance (FromJSON a, FromJSON b, FromJSON c) => FromJSONKey (a,b,c)
16622280instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d) => FromJSONKey (a,b,c,d)
16632281
16642282instance FromJSONKey Char where
1665− fromJSONKey = FromJSONKeyTextParser $ \t ->
1666− if T.length t == 1
1667− then return (T.index t 0)
1668− else typeMismatch "Expected Char but String didn't contain exactly one character" (String t)
2283+ fromJSONKey = FromJSONKeyTextParser parseChar
16692284 fromJSONKeyList = FromJSONKeyText T.unpack
16702285
16712286instance (FromJSONKey a, FromJSON a) => FromJSONKey [a] where
Data/Aeson/Types/Generic.hs+12−8
@@ -1,10 +1,11 @@
11{-# LANGUAGE CPP #-}
22{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE DeriveFunctor #-}
34{-# LANGUAGE EmptyDataDecls #-}
45{-# LANGUAGE FlexibleInstances #-}
56{-# LANGUAGE FunctionalDependencies #-}
67{-# LANGUAGE KindSignatures #-}
7−{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE NoImplicitPrelude #-}
89{-# LANGUAGE ScopedTypeVariables #-}
910{-# LANGUAGE TypeOperators #-}
1011{-# LANGUAGE UndecidableInstances #-}
@@ -25,7 +26,7 @@
2526
2627module Data.Aeson.Types.Generic
2728 (
28− IsRecord(..)
29+ IsRecord
2930 , AllNullary
3031 , Tagged2(..)
3132 , True
@@ -34,9 +35,9 @@ module Data.Aeson.Types.Generic
3435 , Zero
3536 , One
3637 , ProductSize(..)
38+ , (:*)(..)
3739 ) where
3840
39−import Prelude ()
4041import Prelude.Compat
4142
4243import GHC.Generics
@@ -44,12 +45,8 @@ import GHC.Generics
4445--------------------------------------------------------------------------------
4546
4647class IsRecord (f :: * -> *) isRecord | f -> isRecord
47− where
48− isUnary :: f a -> Bool
49− isUnary = const True
5048
5149instance (IsRecord f isRecord) => IsRecord (f :*: g) isRecord
52− where isUnary = const False
5350#if MIN_VERSION_base(4,9,0)
5451instance OVERLAPPING_ IsRecord (M1 S ('MetaSel 'Nothing u ss ds) f) False
5552#else
@@ -61,7 +58,6 @@ instance IsRecord Par1 True
6158instance IsRecord (Rec1 f) True
6259instance IsRecord (f :.: g) True
6360instance IsRecord U1 False
64− where isUnary = const False
6561
6662--------------------------------------------------------------------------------
6763
@@ -80,6 +76,7 @@ instance AllNullary (Rec1 f) False
8076instance AllNullary U1 True
8177
8278newtype Tagged2 (s :: * -> *) b = Tagged2 {unTagged2 :: b}
79+ deriving Functor
8380
8481--------------------------------------------------------------------------------
8582
@@ -112,3 +109,10 @@ instance (ProductSize a, ProductSize b) => ProductSize (a :*: b) where
112109
113110instance ProductSize (S1 s a) where
114111 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+175−26
@@ -1,8 +1,9 @@
11{-# LANGUAGE CPP #-}
22{-# LANGUAGE DeriveDataTypeable #-}
3+{-# LANGUAGE DeriveGeneric #-}
34{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5+{-# LANGUAGE NoImplicitPrelude #-}
46{-# LANGUAGE Rank2Types #-}
5−{-# LANGUAGE RecordWildCards #-}
67#if __GLASGOW_HASKELL__ >= 800
78-- a) THQ works on cross-compilers and unregisterised GHCs
89-- b) may make compilation faster as no dynamic loading is ever needed (not sure about this)
@@ -44,16 +45,33 @@ module Data.Aeson.Types.Internal
4445 , parseEither
4546 , parseMaybe
4647 , modifyFailure
48+ , prependFailure
49+ , parserThrowError
50+ , parserCatchError
4751 , formatError
52+ , formatPath
53+ , formatRelativePath
4854 , (<?>)
4955 -- * Constructors and accessors
5056 , object
5157
5258 -- * Generic and TH encoding configuration
53− , Options(..)
59+ , Options(
60+ fieldLabelModifier
61+ , constructorTagModifier
62+ , allNullaryToStringTag
63+ , omitNothingFields
64+ , sumEncoding
65+ , unwrapUnaryRecords
66+ , tagSingleConstructors
67+ , rejectUnknownFields
68+ )
69+
5470 , SumEncoding(..)
71+ , JSONKeyOptions(keyModifier)
5572 , defaultOptions
5673 , defaultTaggedObject
74+ , defaultJSONKeyOptions
5775
5876 -- * Used for changing CamelCase names into something else.
5977 , camelTo
@@ -63,7 +81,6 @@ module Data.Aeson.Types.Internal
6381 , DotNetTime(..)
6482 ) where
6583
66−import Prelude ()
6784import Prelude.Compat
6885
6986import Control.Applicative (Alternative(..))
@@ -75,6 +92,7 @@ import Data.Data (Data)
7592import Data.Foldable (foldl')
7693import Data.HashMap.Strict (HashMap)
7794import Data.Hashable (Hashable(..))
95+import Data.List (intercalate)
7896import Data.Scientific (Scientific)
7997import Data.Semigroup (Semigroup((<>)))
8098import Data.String (IsString(..))
@@ -83,6 +101,8 @@ import Data.Time (UTCTime)
83101import Data.Time.Format (FormatTime)
84102import Data.Typeable (Typeable)
85103import Data.Vector (Vector)
104+import GHC.Generics (Generic)
105+import qualified Control.Monad as Monad
86106import qualified Control.Monad.Fail as Fail
87107import qualified Data.HashMap.Strict as H
88108import qualified Data.Scientific as S
@@ -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 =
@@ -554,18 +662,18 @@ data SumEncoding =
554662 -- the 'contentsFieldName' field.
555663 | UntaggedValue
556664 -- ^ Constructor names won't be encoded. Instead only the contents of the
557− -- constructor will be encoded as if the type had single constructor. JSON
665+ -- constructor will be encoded as if the type had a single constructor. JSON
558666 -- encodings have to be disjoint for decoding to work properly.
559667 --
560668 -- When decoding, constructors are tried in the order of definition. If some
561669 -- encodings overlap, the first one defined will succeed.
562670 --
563− -- /Note:/ Nullary constructors are encoded as the string (using
671+ -- /Note:/ Nullary constructors are encoded as strings (using
564672 -- 'constructorTagModifier'). Having a nullary constructor alongside a
565673 -- single field constructor that encodes to a string leads to ambiguity.
566674 --
567675 -- /Note:/ Only the last error is kept when decoding, so in the case of
568− -- mailformed JSON, only an error for the last constructor will be reported.
676+ -- malformed JSON, only an error for the last constructor will be reported.
569677 | ObjectWithSingleField
570678 -- ^ A constructor will be encoded to an object with a single
571679 -- field named after the constructor tag (modified by the
@@ -578,6 +686,33 @@ data SumEncoding =
578686 -- contents of the constructor.
579687 deriving (Eq, Show)
580688
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+
581716-- | Default encoding 'Options':
582717--
583718-- @
@@ -588,6 +723,8 @@ data SumEncoding =
588723-- , 'omitNothingFields' = False
589724-- , 'sumEncoding' = 'defaultTaggedObject'
590725-- , 'unwrapUnaryRecords' = False
726+-- , 'tagSingleConstructors' = False
727+-- , 'rejectUnknownFields' = False
591728-- }
592729-- @
593730defaultOptions :: Options
@@ -598,6 +735,8 @@ defaultOptions = Options
598735 , omitNothingFields = False
599736 , sumEncoding = defaultTaggedObject
600737 , unwrapUnaryRecords = False
738+ , tagSingleConstructors = False
739+ , rejectUnknownFields = False
601740 }
602741
603742-- | Default 'TaggedObject' 'SumEncoding' options:
@@ -614,6 +753,16 @@ defaultTaggedObject = TaggedObject
614753 , contentsFieldName = "contents"
615754 }
616755
756+-- | Default 'JSONKeyOptions':
757+--
758+-- @
759+-- defaultJSONKeyOptions = 'JSONKeyOptions'
760+-- { 'keyModifier' = 'id'
761+-- }
762+-- @
763+defaultJSONKeyOptions :: JSONKeyOptions
764+defaultJSONKeyOptions = JSONKeyOptions id
765+
617766-- | Converts from CamelCase to another lower case, interspersing
618767-- the character between all capital letters and their previous
619768-- entries, except those capital letters that appear together,
Data/Aeson/Types/ToJSON.hs+729−546
@@ -1,25 +1,21 @@
1−{-# LANGUAGE BangPatterns #-}
21{-# LANGUAGE CPP #-}
3−{-# LANGUAGE DataKinds #-}
42{-# LANGUAGE DefaultSignatures #-}
3+{-# LANGUAGE EmptyDataDecls #-}
54{-# LANGUAGE FlexibleContexts #-}
65{-# LANGUAGE FlexibleInstances #-}
6+{-# LANGUAGE FunctionalDependencies #-}
77{-# LANGUAGE GADTs #-}
8−{-# LANGUAGE MultiParamTypeClasses #-}
9−{-# LANGUAGE NamedFieldPuns #-}
8+{-# LANGUAGE NoImplicitPrelude #-}
109{-# LANGUAGE OverloadedStrings #-}
1110{-# LANGUAGE PatternGuards #-}
11+{-# LANGUAGE PolyKinds #-}
1212{-# LANGUAGE RecordWildCards #-}
1313{-# LANGUAGE ScopedTypeVariables #-}
1414{-# LANGUAGE TypeOperators #-}
15−{-# LANGUAGE TypeSynonymInstances #-}
1615{-# LANGUAGE UndecidableInstances #-}
1716
18−#if __GLASGOW_HASKELL__ >= 706
19−{-# LANGUAGE PolyKinds #-}
20−#endif
21−
2217#include "overlapping-compat.h"
18+#include "incoherent-compat.h"
2319
2420-- TODO: Drop this when we remove support for Data.Attoparsec.Number
2521{-# OPTIONS_GHC -fno-warn-deprecations #-}
@@ -37,7 +33,6 @@ module Data.Aeson.Types.ToJSON
3733 , toEncoding2
3834 -- * Generic JSON classes
3935 , GToJSON(..)
40− , GToEncoding(..)
4136 , ToArgs(..)
4237 , genericToJSON
4338 , genericToEncoding
@@ -48,54 +43,63 @@ module Data.Aeson.Types.ToJSON
4843 , ToJSONKeyFunction(..)
4944 , toJSONKeyText
5045 , contramapToJSONKeyFunction
46+
47+ , GToJSONKey()
48+ , genericToJSONKey
49+
5150 -- * Object key-value pairs
5251 , KeyValue(..)
52+ , KeyValuePair(..)
53+ , FromPairs(..)
5354 -- * Functions needed for documentation
5455 -- * Encoding functions
5556 , listEncoding
5657 , listValue
5758 ) where
5859
59−import Prelude ()
6060import Prelude.Compat
6161
6262import Control.Applicative (Const(..))
6363import Control.Monad.ST (ST)
6464import Data.Aeson.Encoding (Encoding, Encoding', Series, dict, emptyArray_)
65−import Data.Aeson.Encoding.Internal ((>*<), (><))
65+import Data.Aeson.Encoding.Internal ((>*<))
6666import Data.Aeson.Internal.Functions (mapHashKeyVal, mapKeyVal)
67−import Data.Aeson.Types.Generic (AllNullary, False, IsRecord(..), One, ProductSize, Tagged2(..), True, Zero, productSize)
67+import Data.Aeson.Types.Generic (AllNullary, False, IsRecord, One, ProductSize, Tagged2(..), True, Zero, productSize)
6868import Data.Aeson.Types.Internal
6969import Data.Attoparsec.Number (Number(..))
7070import Data.Bits (unsafeShiftR)
7171import Data.DList (DList)
72−import Data.Fixed (Fixed, HasResolution)
72+import Data.Fixed (Fixed, HasResolution, Nano)
7373import Data.Foldable (toList)
7474import Data.Functor.Compose (Compose(..))
75+import Data.Functor.Contravariant (Contravariant (..))
7576import Data.Functor.Identity (Identity(..))
7677import Data.Functor.Product (Product(..))
7778import Data.Functor.Sum (Sum(..))
7879import Data.Int (Int16, Int32, Int64, Int8)
7980import Data.List (intersperse)
8081import Data.List.NonEmpty (NonEmpty(..))
81−import Data.Monoid ((<>), Dual(..), First(..), Last(..))
82+import Data.Semigroup ((<>))
8283import Data.Proxy (Proxy(..))
8384import Data.Ratio (Ratio, denominator, numerator)
8485import Data.Scientific (Scientific)
8586import Data.Tagged (Tagged(..))
8687import Data.Text (Text, pack)
87−import Data.Time (Day, LocalTime, NominalDiffTime, TimeOfDay, UTCTime, ZonedTime)
88−import Data.Time.Format (FormatTime, formatTime)
89−import Data.Time.Locale.Compat (defaultTimeLocale)
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)
9093import Data.Vector (Vector)
9194import Data.Version (Version, showVersion)
95+import Data.Void (Void, absurd)
9296import Data.Word (Word16, Word32, Word64, Word8)
9397import Foreign.Storable (Storable)
98+import Foreign.C.Types (CTime (..))
9499import GHC.Generics
95100import Numeric.Natural (Natural)
96101import qualified Data.Aeson.Encoding as E
97−import qualified Data.Aeson.Encoding.Internal as E (InArray, colon, comma, econcat, empty, retagEncoding, wrapObject)
98−import qualified Data.ByteString as S
102+import qualified Data.Aeson.Encoding.Internal as E (InArray, comma, econcat, retagEncoding)
99103import qualified Data.ByteString.Lazy as L
100104import qualified Data.DList as DList
101105import qualified Data.HashMap.Strict as H
@@ -104,13 +108,16 @@ import qualified Data.IntMap as IntMap
104108import qualified Data.IntSet as IntSet
105109import qualified Data.List.NonEmpty as NE
106110import qualified Data.Map as M
111+import qualified Data.Monoid as Monoid
107112import qualified Data.Scientific as Scientific
113+import qualified Data.Semigroup as Semigroup
108114import qualified Data.Sequence as Seq
109115import qualified Data.Set as Set
110116import qualified Data.Text as T
111117import qualified Data.Text.Encoding as T
112118import qualified Data.Text.Lazy as LT
113119import qualified Data.Tree as Tree
120+import qualified Data.UUID.Types as UUID
114121import qualified Data.Vector as V
115122import qualified Data.Vector.Generic as VG
116123import qualified Data.Vector.Mutable as VM
@@ -118,12 +125,19 @@ import qualified Data.Vector.Primitive as VP
118125import qualified Data.Vector.Storable as VS
119126import qualified Data.Vector.Unboxed as VU
120127
121−#if !(MIN_VERSION_bytestring(0,10,0))
122−import Foreign.ForeignPtr (withForeignPtr)
123−import Foreign.Marshal.Utils (copyBytes)
124−import Foreign.Ptr (plusPtr)
125−import qualified Data.ByteString.Internal as S
126−import qualified Data.ByteString.Lazy.Internal as L
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
127141#endif
128142
129143toJSONPair :: (a -> Value) -> (b -> Value) -> (a, b) -> Value
@@ -142,19 +156,16 @@ realFloatToJSON d
142156
143157-- | Class of generic representation types that can be converted to
144158-- JSON.
145−class GToJSON arity f where
159+class GToJSON enc arity f where
146160 -- | This method (applied to 'defaultOptions') is used as the
147− -- default generic implementation of 'toJSON' (if the @arity@ is 'Zero')
148− -- or 'liftToJSON' (if the @arity@ is 'One').
149− gToJSON :: Options -> ToArgs Value arity a -> f a -> Value
150−
151−-- | Class of generic representation types that can be converted to
152−-- a JSON 'Encoding'.
153−class GToEncoding arity f where
154− -- | This method (applied to 'defaultOptions') can be used as the
155− -- default generic implementation of 'toEncoding' (if the @arity@ is 'Zero')
156− -- or 'liftToEncoding' (if the @arity@ is 'One').
157− gToEncoding :: Options -> ToArgs Encoding arity a -> 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
158169
159170-- | A 'ToArgs' value either stores nothing (for 'ToJSON') or it stores the two
160171-- function arguments that encode occurrences of the type parameter (for
@@ -166,14 +177,14 @@ data ToArgs res arity a where
166177-- | A configurable generic JSON creator. This function applied to
167178-- 'defaultOptions' is used as the default for 'toJSON' when the type
168179-- is an instance of 'Generic'.
169−genericToJSON :: (Generic a, GToJSON Zero (Rep a))
180+genericToJSON :: (Generic a, GToJSON Value Zero (Rep a))
170181 => Options -> a -> Value
171182genericToJSON opts = gToJSON opts NoToArgs . from
172183
173184-- | A configurable generic JSON creator. This function applied to
174185-- 'defaultOptions' is used as the default for 'liftToJSON' when the type
175186-- is an instance of 'Generic1'.
176−genericLiftToJSON :: (Generic1 f, GToJSON One (Rep1 f))
187+genericLiftToJSON :: (Generic1 f, GToJSON Value One (Rep1 f))
177188 => Options -> (a -> Value) -> ([a] -> Value)
178189 -> f a -> Value
179190genericLiftToJSON opts tj tjl = gToJSON opts (To1Args tj tjl) . from1
@@ -181,17 +192,17 @@ genericLiftToJSON opts tj tjl = gToJSON opts (To1Args tj tjl) . from1
181192-- | A configurable generic JSON encoder. This function applied to
182193-- 'defaultOptions' is used as the default for 'toEncoding' when the type
183194-- is an instance of 'Generic'.
184−genericToEncoding :: (Generic a, GToEncoding Zero (Rep a))
195+genericToEncoding :: (Generic a, GToJSON Encoding Zero (Rep a))
185196 => Options -> a -> Encoding
186−genericToEncoding opts = gToEncoding opts NoToArgs . from
197+genericToEncoding opts = gToJSON opts NoToArgs . from
187198
188199-- | A configurable generic JSON encoder. This function applied to
189200-- 'defaultOptions' is used as the default for 'liftToEncoding' when the type
190201-- is an instance of 'Generic1'.
191−genericLiftToEncoding :: (Generic1 f, GToEncoding One (Rep1 f))
202+genericLiftToEncoding :: (Generic1 f, GToJSON Encoding One (Rep1 f))
192203 => Options -> (a -> Encoding) -> ([a] -> Encoding)
193204 -> f a -> Encoding
194−genericLiftToEncoding opts te tel = gToEncoding opts (To1Args te tel) . from1
205+genericLiftToEncoding opts te tel = gToJSON opts (To1Args te tel) . from1
195206
196207-------------------------------------------------------------------------------
197208-- Class
@@ -199,6 +210,9 @@ genericLiftToEncoding opts te tel = gToEncoding opts (To1Args te tel) . from1
199210
200211-- | A type that can be converted to JSON.
201212--
213+-- Instances in general /must/ specify 'toJSON' and /should/ (but don't need
214+-- to) specify 'toEncoding'.
215+--
202216-- An example type and instance:
203217--
204218-- @
@@ -207,10 +221,10 @@ genericLiftToEncoding opts te tel = gToEncoding opts (To1Args te tel) . from1
207221--
208222-- data Coord = Coord { x :: Double, y :: Double }
209223--
210−-- instance ToJSON Coord where
211−-- toJSON (Coord x y) = 'object' [\"x\" '.=' x, \"y\" '.=' y]
224+-- instance 'ToJSON' Coord where
225+-- 'toJSON' (Coord x y) = 'object' [\"x\" '.=' x, \"y\" '.=' y]
212226--
213−-- toEncoding (Coord x y) = 'pairs' (\"x\" '.=' x '<>' \"y\" '.=' y)
227+-- 'toEncoding' (Coord x y) = 'pairs' (\"x\" '.=' x '<>' \"y\" '.=' y)
214228-- @
215229--
216230-- Instead of manually writing your 'ToJSON' instance, there are two options
@@ -218,17 +232,15 @@ genericLiftToEncoding opts te tel = gToEncoding opts (To1Args te tel) . from1
218232--
219233-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
220234-- instance at compile time. The generated instance is optimized for your type
221−-- so will probably be more efficient than the following two options:
235+-- so it will probably be more efficient than the following option.
222236--
223237-- * The compiler can provide a default generic implementation for
224238-- 'toJSON'.
225239--
226240-- To use the second, simply add a @deriving 'Generic'@ clause to your
227−-- datatype and declare a 'ToJSON' instance for your datatype without giving
228−-- definitions for 'toJSON' or 'toEncoding'.
229−--
230−-- For example, the previous example can be simplified to a more
231−-- 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):
232244--
233245-- @
234246-- {-\# LANGUAGE DeriveGeneric \#-}
@@ -237,35 +249,46 @@ genericLiftToEncoding opts te tel = gToEncoding opts (To1Args te tel) . from1
237249--
238250-- data Coord = Coord { x :: Double, y :: Double } deriving 'Generic'
239251--
240−-- instance ToJSON Coord where
241−-- toEncoding = 'genericToEncoding' 'defaultOptions'
252+-- instance 'ToJSON' Coord where
253+-- 'toEncoding' = 'genericToEncoding' 'defaultOptions'
242254-- @
243255--
244−-- Why do we provide an implementation for 'toEncoding' here? The
245−-- 'toEncoding' function is a relatively new addition to this class.
246−-- To allow users of older versions of this library to upgrade without
247−-- having to edit all of their instances or encounter surprising
248−-- incompatibilities, the default implementation of 'toEncoding' uses
249−-- 'toJSON'. This produces correct results, but since it performs an
250−-- intermediate conversion to a 'Value', it will be less efficient
251−-- than directly emitting an 'Encoding'. Our one-liner definition of
252−-- 'toEncoding' above bypasses the intermediate 'Value'.
253−--
254−-- If @DefaultSignatures@ doesn't give exactly the results you want,
255−-- you can customize the generic encoding with only a tiny amount of
256−-- effort, using 'genericToJSON' and 'genericToEncoding' with your
257−-- preferred 'Options':
256+-- If on the other hand you wish to customize the generic decoding, you have
257+-- to implement both methods:
258258--
259259-- @
260−-- instance ToJSON Coord where
261−-- toJSON = 'genericToJSON' 'defaultOptions'
262−-- 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
263267-- @
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.)
264287class ToJSON a where
265288 -- | Convert a Haskell value to a JSON-friendly intermediate type.
266289 toJSON :: a -> Value
267290
268− default toJSON :: (Generic a, GToJSON Zero (Rep a)) => a -> Value
291+ default toJSON :: (Generic a, GToJSON Value Zero (Rep a)) => a -> Value
269292 toJSON = genericToJSON defaultOptions
270293
271294 -- | Encode a Haskell value as JSON.
@@ -282,8 +305,8 @@ class ToJSON a where
282305 -- extension, and then have GHC generate a method body as follows.
283306 --
284307 -- @
285− -- instance ToJSON Coord where
286− -- toEncoding = 'genericToEncoding' 'defaultOptions'
308+ -- instance 'ToJSON' Coord where
309+ -- 'toEncoding' = 'genericToEncoding' 'defaultOptions'
287310 -- @
288311
289312 toEncoding :: a -> Encoding
@@ -315,6 +338,13 @@ instance KeyValue Pair where
315338 name .= value = (name, toJSON value)
316339 {-# INLINE (.=) #-}
317340
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+
318348-------------------------------------------------------------------------------
319349-- Classes and types for map keys
320350-------------------------------------------------------------------------------
@@ -372,7 +402,7 @@ instance KeyValue Pair where
372402-- newtype wrapper around 'Text'. The recommended approach is to use
373403-- generalized newtype deriving:
374404--
375−-- > newtype RecordId = RecordId { getRecordId :: Text}
405+-- > newtype RecordId = RecordId { getRecordId :: Text }
376406-- > deriving (Eq,Ord,ToJSONKey)
377407--
378408-- Then we may write:
@@ -387,8 +417,18 @@ instance KeyValue Pair where
387417--
388418-- It is possible to get the 'ToJSONKey' instance for free as we did
389419-- with 'Foo'. However, in this case, we have a natural way to go to
390−-- and from 'Text' that does not require any escape sequences. So, in
391−-- 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+--
392432-- The 'Show' instance can be used to help write 'ToJSONKey':
393433--
394434-- > instance ToJSONKey Color where
@@ -463,16 +503,42 @@ toJSONKeyTextEnc e = ToJSONKeyText tot e
463503 -- TODO: dropAround is also used in stringEncoding, which is unfortunate atm
464504 tot = T.dropAround (== '"')
465505 . T.decodeLatin1
466− . lazyToStrictByteString
506+ . L.toStrict
467507 . E.encodingToLazyByteString
468508 . e
469509
510+instance Contravariant ToJSONKeyFunction where
511+ contramap = contramapToJSONKeyFunction
512+
470513-- | Contravariant map, as 'ToJSONKeyFunction' is a contravariant functor.
471514contramapToJSONKeyFunction :: (b -> a) -> ToJSONKeyFunction a -> ToJSONKeyFunction b
472515contramapToJSONKeyFunction h x = case x of
473516 ToJSONKeyText f g -> ToJSONKeyText (f . h) (g . h)
474517 ToJSONKeyValue f g -> ToJSONKeyValue (f . h) (g . h)
475518
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
541+
476542-------------------------------------------------------------------------------
477543-- Lifings of FromJSON and ToJSON to unary and binary type constructors
478544-------------------------------------------------------------------------------
@@ -485,7 +551,7 @@ contramapToJSONKeyFunction h x = case x of
485551--
486552-- * "Data.Aeson.TH" provides Template Haskell functions which will derive an
487553-- instance at compile time. The generated instance is optimized for your type
488−-- so will probably be more efficient than the following two options:
554+-- so it will probably be more efficient than the following option.
489555--
490556-- * The compiler can provide a default generic implementation for
491557-- 'toJSON1'.
@@ -503,23 +569,29 @@ contramapToJSONKeyFunction h x = case x of
503569--
504570-- data Pair = Pair { pairFst :: a, pairSnd :: b } deriving 'Generic1'
505571--
506−-- instance ToJSON a => ToJSON1 (Pair a)
572+-- instance 'ToJSON' a => 'ToJSON1' (Pair a)
507573-- @
508574--
509−-- If @DefaultSignatures@ doesn't give exactly the results you want,
575+-- If the default implementation doesn't give exactly the results you want,
510576-- you can customize the generic encoding with only a tiny amount of
511577-- effort, using 'genericLiftToJSON' and 'genericLiftToEncoding' with
512578-- your preferred 'Options':
513579--
514580-- @
515−-- instance ToJSON a => ToJSON1 (Pair a) where
516−-- liftToJSON = 'genericLiftToJSON' 'defaultOptions'
517−-- 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
518588-- @
589+--
590+-- See also 'ToJSON'.
519591class ToJSON1 f where
520592 liftToJSON :: (a -> Value) -> ([a] -> Value) -> f a -> Value
521593
522− default liftToJSON :: (Generic1 f, GToJSON One (Rep1 f))
594+ default liftToJSON :: (Generic1 f, GToJSON Value One (Rep1 f))
523595 => (a -> Value) -> ([a] -> Value) -> f a -> Value
524596 liftToJSON = genericLiftToJSON defaultOptions
525597
@@ -528,7 +600,7 @@ class ToJSON1 f where
528600
529601 liftToEncoding :: (a -> Encoding) -> ([a] -> Encoding) -> f a -> Encoding
530602
531− default liftToEncoding :: (Generic1 f, GToEncoding One (Rep1 f))
603+ default liftToEncoding :: (Generic1 f, GToJSON Encoding One (Rep1 f))
532604 => (a -> Encoding) -> ([a] -> Encoding)
533605 -> f a -> Encoding
534606 liftToEncoding = genericLiftToEncoding defaultOptions
@@ -582,7 +654,7 @@ toEncoding2 = liftToEncoding2 toEncoding toEncodingList toEncoding toEncodingLis
582654-- @
583655-- newtype F a = F [a]
584656--
585−-- -- This instance encodes String as an array of chars
657+-- -- This instance encodes 'String' as an array of chars
586658-- instance 'ToJSON1' F where
587659-- 'liftToJSON' tj _ (F xs) = 'liftToJSON' tj ('listValue' tj) xs
588660-- 'liftToEncoding' te _ (F xs) = 'liftToEncoding' te ('listEncoding' te) xs
@@ -613,6 +685,11 @@ instance ToJSON1 [] where
613685 {-# INLINE liftToEncoding #-}
614686
615687instance (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+
616693 toJSON = toJSON1
617694 {-# INLINE toJSON #-}
618695
@@ -623,39 +700,80 @@ instance (ToJSON a) => ToJSON [a] where
623700-- Generic toJSON / toEncoding
624701-------------------------------------------------------------------------------
625702
626−--------------------------------------------------------------------------------
627−-- Generic toJSON
628−
629−instance OVERLAPPABLE_ (GToJSON arity a) => GToJSON arity (M1 i c a) where
703+instance OVERLAPPABLE_ (GToJSON enc arity a) => GToJSON enc arity (M1 i c a) where
630704 -- Meta-information, which is not handled elsewhere, is ignored:
631705 gToJSON opts targs = gToJSON opts targs . unM1
706+ {-# INLINE gToJSON #-}
632707
633−instance (ToJSON a) => GToJSON arity (K1 i a) where
634− -- Constant values are encoded using their ToJSON instance:
635− gToJSON _opts _ = toJSON . unK1
636−
637−instance GToJSON One Par1 where
708+instance GToJSON enc One Par1 where
638709 -- Direct occurrences of the last type parameter are encoded with the
639710 -- function passed in as an argument:
640711 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 #-}
641743
642−instance (ToJSON1 f) => GToJSON One (Rec1 f) where
744+--------------------------------------------------------------------------------
745+-- Generic toJSON
746+
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.
750+
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 #-}
756+
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 #-}
761+
762+instance ToJSON1 f => GToJSON Value One (Rec1 f) where
643763 -- Recursive occurrences of the last type parameter are encoded using their
644764 -- ToJSON1 instance:
645765 gToJSON _opts (To1Args tj tjl) = liftToJSON tj tjl . unRec1
766+ {-# INLINE gToJSON #-}
646767
647−instance GToJSON arity U1 where
768+instance GToJSON Value arity U1 where
648769 -- Empty constructors are encoded to an empty array:
649770 gToJSON _opts _ _ = emptyArray
650−
651−instance (ConsToJSON arity a) => GToJSON arity (C1 c a) where
652− -- Constructors need to be encoded differently depending on whether they're
653− -- a record or not. This distinction is made by 'consToJSON':
654− gToJSON opts targs = consToJSON opts targs . unM1
771+ {-# INLINE gToJSON #-}
655772
656773instance ( WriteProduct arity a, WriteProduct arity b
657774 , ProductSize a, ProductSize b
658− ) => GToJSON arity (a :*: b) where
775+ ) => GToJSON Value arity (a :*: b)
776+ where
659777 -- Products are encoded to an array. Here we allocate a mutable vector of
660778 -- the same size as the product and write the product's elements to it using
661779 -- 'writeProduct':
@@ -667,237 +785,175 @@ instance ( WriteProduct arity a, WriteProduct arity b
667785 where
668786 lenProduct = (unTagged2 :: Tagged2 (a :*: b) Int -> Int)
669787 productSize
788+ {-# INLINE gToJSON #-}
670789
671−instance ( AllNullary (a :+: b) allNullary
672− , SumToJSON arity (a :+: b) allNullary
673− ) => GToJSON arity (a :+: b) where
674− -- If all constructors of a sum datatype are nullary and the
675− -- 'allNullaryToStringTag' option is set they are encoded to
676− -- strings. This distinction is made by 'sumToJSON':
677− gToJSON opts targs = (unTagged :: Tagged allNullary Value -> Value)
678− . sumToJSON opts targs
679−
680−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
681794 -- If an occurrence of the last type parameter is nested inside two
682795 -- composed types, it is encoded by using the outermost type's ToJSON1
683796 -- instance to generically encode the innermost type:
684797 gToJSON opts targs =
685798 let gtj = gToJSON opts targs in
686799 liftToJSON gtj (listValue gtj) . unComp1
800+ {-# INLINE gToJSON #-}
687801
688802--------------------------------------------------------------------------------
689803-- Generic toEncoding
690804
691−instance OVERLAPPABLE_ (GToEncoding arity a) => GToEncoding arity (M1 i c a) where
692− -- Meta-information, which is not handled elsewhere, is ignored:
693− gToEncoding opts targs = gToEncoding opts targs . unM1
694−
695−instance (ToJSON a) => GToEncoding arity (K1 i a) where
805+instance ToJSON a => GToJSON Encoding arity (K1 i a) where
696806 -- Constant values are encoded using their ToJSON instance:
697− gToEncoding _opts _ = toEncoding . unK1
807+ gToJSON _opts _ = toEncoding . unK1
808+ {-# INLINE gToJSON #-}
698809
699−instance GToEncoding One Par1 where
700− -- Direct occurrences of the last type parameter are encoded with the
701− -- function passed in as an argument:
702− gToEncoding _opts (To1Args te _) = te . unPar1
703−
704−instance (ToJSON1 f) => GToEncoding One (Rec1 f) where
810+instance ToJSON1 f => GToJSON Encoding One (Rec1 f) where
705811 -- Recursive occurrences of the last type parameter are encoded using their
706812 -- ToEncoding1 instance:
707− gToEncoding _opts (To1Args te tel) = liftToEncoding te tel . unRec1
813+ gToJSON _opts (To1Args te tel) = liftToEncoding te tel . unRec1
814+ {-# INLINE gToJSON #-}
708815
709−instance GToEncoding arity U1 where
816+instance GToJSON Encoding arity U1 where
710817 -- Empty constructors are encoded to an empty array:
711− gToEncoding _opts _ _ = E.emptyArray_
712−
713−instance (ConsToEncoding arity a) => GToEncoding arity (C1 c a) where
714− -- Constructors need to be encoded differently depending on whether they're
715− -- a record or not. This distinction is made by 'consToEncoding':
716− gToEncoding opts targs = consToEncoding opts targs . unM1
818+ gToJSON _opts _ _ = E.emptyArray_
819+ {-# INLINE gToJSON #-}
717820
718821instance ( EncodeProduct arity a
719822 , EncodeProduct arity b
720− ) => GToEncoding arity (a :*: b) where
823+ ) => GToJSON Encoding arity (a :*: b)
824+ where
721825 -- Products are encoded to an array. Here we allocate a mutable vector of
722826 -- the same size as the product and write the product's elements to it using
723827 -- 'encodeProduct':
724− gToEncoding opts targs p = E.list E.retagEncoding [encodeProduct opts targs p]
725−
726−instance ( AllNullary (a :+: b) allNullary
727− , SumToEncoding arity (a :+: b) allNullary
728− ) => GToEncoding arity (a :+: b) where
729− -- If all constructors of a sum datatype are nullary and the
730− -- 'allNullaryToStringTag' option is set they are encoded to
731− -- strings. This distinction is made by 'sumToEncoding':
732− gToEncoding opts targs
733− = (unTagged :: Tagged allNullary Encoding -> Encoding)
734− . sumToEncoding opts targs
828+ gToJSON opts targs p = E.list E.retagEncoding [encodeProduct opts targs p]
829+ {-# INLINE gToJSON #-}
735830
736−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
737835 -- If an occurrence of the last type parameter is nested inside two
738836 -- composed types, it is encoded by using the outermost type's ToJSON1
739837 -- instance to generically encode the innermost type:
740− gToEncoding opts targs =
741− let gte = gToEncoding opts targs in
838+ gToJSON opts targs =
839+ let gte = gToJSON opts targs in
742840 liftToEncoding gte (listEncoding gte) . unComp1
841+ {-# INLINE gToJSON #-}
743842
744843--------------------------------------------------------------------------------
745844
746−class SumToJSON arity f allNullary where
747− sumToJSON :: Options -> ToArgs Value arity a
748− -> f a -> Tagged allNullary Value
749−
750−instance ( GetConName f
751− , TaggedObjectPairs arity f
752− , ObjectWithSingleFieldObj arity f
753− , TwoElemArrayObj arity f
754− , UntaggedValueObj arity f
755− ) => SumToJSON arity f True where
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
756857 sumToJSON opts targs
757− | allNullaryToStringTag opts = Tagged . String . pack
858+ | allNullaryToStringTag opts = Tagged . fromString
758859 . constructorTagModifier opts . getConName
759860 | otherwise = Tagged . nonAllNullarySumToJSON opts targs
760861
761−instance ( TwoElemArrayObj arity f
762− , TaggedObjectPairs arity f
763− , ObjectWithSingleFieldObj arity f
764− , UntaggedValueObj arity f
765− ) => SumToJSON arity f False where
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
766868 sumToJSON opts targs = Tagged . nonAllNullarySumToJSON opts targs
767869
768−nonAllNullarySumToJSON :: ( TwoElemArrayObj arity f
769− , TaggedObjectPairs arity f
770− , ObjectWithSingleFieldObj arity f
771− , UntaggedValueObj arity f
772− ) => Options -> ToArgs Value arity a
773− -> f a -> Value
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
774876nonAllNullarySumToJSON opts targs =
775877 case sumEncoding opts of
776− TaggedObject{..} ->
777− object . taggedObjectPairs opts targs tagFieldName contentsFieldName
778− ObjectWithSingleField -> Object . objectWithSingleFieldObj opts targs
779− TwoElemArray -> Array . twoElemArrayObj opts targs
780− UntaggedValue -> untaggedValueObj opts targs
781878
782−--------------------------------------------------------------------------------
783−
784−class SumToEncoding arity f allNullary where
785− sumToEncoding :: Options -> ToArgs Encoding arity a
786− -> f a -> Tagged allNullary Encoding
787−
788−instance ( GetConName f
789− , TaggedObjectEnc arity f
790− , ObjectWithSingleFieldEnc arity f
791− , TwoElemArrayEnc arity f
792− , UntaggedValueEnc arity f
793− ) => SumToEncoding arity f True where
794− sumToEncoding opts targs
795− | allNullaryToStringTag opts = Tagged . toEncoding .
796− constructorTagModifier opts . getConName
797− | otherwise = Tagged . nonAllNullarySumToEncoding opts targs
798−
799−instance ( TwoElemArrayEnc arity f
800− , TaggedObjectEnc arity f
801− , ObjectWithSingleFieldEnc arity f
802− , UntaggedValueEnc arity f
803− ) => SumToEncoding arity f False where
804− sumToEncoding opts targs = Tagged . nonAllNullarySumToEncoding opts targs
805−
806−nonAllNullarySumToEncoding :: ( TwoElemArrayEnc arity f
807− , TaggedObjectEnc arity f
808− , ObjectWithSingleFieldEnc arity f
809− , UntaggedValueEnc arity f
810− ) => Options -> ToArgs Encoding arity a
811− -> f a -> Encoding
812−nonAllNullarySumToEncoding opts targs =
813− case sumEncoding opts of
814879 TaggedObject{..} ->
815− taggedObjectEnc opts targs tagFieldName contentsFieldName
816− ObjectWithSingleField -> objectWithSingleFieldEnc opts targs
817− TwoElemArray -> twoElemArrayEnc opts targs
818− UntaggedValue -> untaggedValueEnc opts targs
880+ taggedObject opts targs tagFieldName contentsFieldName
819881
820−--------------------------------------------------------------------------------
882+ ObjectWithSingleField ->
883+ (unTagged :: Tagged ObjectWithSingleField enc -> enc)
884+ . sumToJSON' opts targs
821885
822−class TaggedObjectPairs arity f where
823− taggedObjectPairs :: Options -> ToArgs Value arity a
824− -> String -> String
825− -> f a -> [Pair]
826−
827−instance ( TaggedObjectPairs arity a
828− , TaggedObjectPairs arity b
829− ) => TaggedObjectPairs arity (a :+: b) where
830− taggedObjectPairs opts targs tagFieldName contentsFieldName (L1 x) =
831− taggedObjectPairs opts targs tagFieldName contentsFieldName x
832− taggedObjectPairs opts targs tagFieldName contentsFieldName (R1 x) =
833− taggedObjectPairs opts targs tagFieldName contentsFieldName x
834−
835−instance ( IsRecord a isRecord
836− , TaggedObjectPairs' arity a isRecord
837− , Constructor c
838− ) => TaggedObjectPairs arity (C1 c a) where
839− taggedObjectPairs opts targs tagFieldName contentsFieldName =
840− (pack tagFieldName .= constructorTagModifier opts
841− (conName (undefined :: t c a p)) :) .
842− (unTagged :: Tagged isRecord [Pair] -> [Pair]) .
843− taggedObjectPairs' opts targs contentsFieldName . unM1
886+ TwoElemArray ->
887+ (unTagged :: Tagged TwoElemArray enc -> enc)
888+ . sumToJSON' opts targs
844889
845−class TaggedObjectPairs' arity f isRecord where
846− taggedObjectPairs' :: Options -> ToArgs Value arity a
847− -> String -> f a -> Tagged isRecord [Pair]
890+ UntaggedValue ->
891+ (unTagged :: Tagged UntaggedValue enc -> enc)
892+ . sumToJSON' opts targs
893+
894+--------------------------------------------------------------------------------
848895
849−instance OVERLAPPING_ TaggedObjectPairs' arity U1 False where
850− taggedObjectPairs' _ _ _ _ = Tagged []
896+class FromString enc where
897+ fromString :: String -> enc
851898
852−instance (RecordToPairs arity f) => TaggedObjectPairs' arity f True where
853− taggedObjectPairs' opts targs _ =
854− Tagged . toList . recordToPairs opts targs
899+instance FromString Encoding where
900+ fromString = toEncoding
855901
856−instance (GToJSON arity f) => TaggedObjectPairs' arity f False where
857− taggedObjectPairs' opts targs contentsFieldName =
858− Tagged . (:[]) . (pack contentsFieldName .=) . gToJSON opts targs
902+instance FromString Value where
903+ fromString = String . pack
859904
860905--------------------------------------------------------------------------------
861906
862−class TaggedObjectEnc arity f where
863− taggedObjectEnc :: Options -> ToArgs Encoding arity a
864− -> String -> String
865− -> f a -> Encoding
866−
867−instance ( TaggedObjectEnc arity a
868− , TaggedObjectEnc arity b
869− ) => TaggedObjectEnc arity (a :+: b) where
870− taggedObjectEnc opts targs tagFieldName contentsFieldName (L1 x) =
871− taggedObjectEnc opts targs tagFieldName contentsFieldName x
872− taggedObjectEnc opts targs tagFieldName contentsFieldName (R1 x) =
873− taggedObjectEnc opts targs tagFieldName contentsFieldName x
874−
875−instance ( IsRecord a isRecord
876− , 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
877926 , Constructor c
878− ) => TaggedObjectEnc arity (C1 c a) where
879− taggedObjectEnc opts targs tagFieldName contentsFieldName v = E.pairs (E.pair key val)
927+ ) => TaggedObject enc arity (C1 c a)
928+ where
929+ taggedObject opts targs tagFieldName contentsFieldName =
930+ fromPairs . mappend tag . contents
880931 where
881− key :: Text
882− key = pack tagFieldName
883− val = toEncoding (constructorTagModifier opts (conName (undefined :: t c a p)))
884− >< ((unTagged :: Tagged isRecord Encoding -> Encoding) . taggedObjectEnc' opts targs contentsFieldName . unM1 $ v)
885−
886−class TaggedObjectEnc' arity f isRecord where
887− taggedObjectEnc' :: Options -> ToArgs Encoding arity a
888− -> String -> f a -> Tagged isRecord Encoding
889−
890−instance OVERLAPPING_ TaggedObjectEnc' arity U1 False where
891− taggedObjectEnc' _ _ _ _ = Tagged E.empty
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
892949
893−instance (RecordToEncoding arity f) => TaggedObjectEnc' arity f True where
894− taggedObjectEnc' opts targs _ = Tagged . (E.comma ><) . fst
895− . recordToEncoding opts targs
950+instance OVERLAPPING_ Monoid pairs => TaggedObject' enc pairs arity U1 False where
951+ taggedObject' _ _ _ _ = Tagged mempty
896952
897−instance (GToEncoding arity f) => TaggedObjectEnc' arity f False where
898− taggedObjectEnc' opts targs contentsFieldName =
899− Tagged . (\z -> E.comma >< toEncoding contentsFieldName >< E.colon >< z) .
900− gToEncoding opts targs
953+instance ( RecordToPairs enc pairs arity f
954+ ) => TaggedObject' enc pairs arity f True
955+ where
956+ taggedObject' opts targs _ = Tagged . recordToPairs opts targs
901957
902958--------------------------------------------------------------------------------
903959
@@ -912,23 +968,38 @@ instance (GetConName a, GetConName b) => GetConName (a :+: b) where
912968instance (Constructor c) => GetConName (C1 c a) where
913969 getConName = conName
914970
971+-- For genericToJSONKey
972+instance GetConName a => GetConName (D1 d a) where
973+ getConName (M1 x) = getConName x
974+
915975--------------------------------------------------------------------------------
916976
917−class TwoElemArrayObj arity f where
918− twoElemArrayObj :: Options -> ToArgs Value arity a
919− -> f a -> V.Vector Value
977+-- Reflection of SumEncoding variants
920978
921−instance ( TwoElemArrayObj arity a
922− , TwoElemArrayObj arity b
923− ) => TwoElemArrayObj arity (a :+: b) where
924− twoElemArrayObj opts targs (L1 x) = twoElemArrayObj opts targs x
925− twoElemArrayObj opts targs (R1 x) = twoElemArrayObj opts targs x
979+data ObjectWithSingleField
980+data TwoElemArray
981+data UntaggedValue
926982
927−instance ( GToJSON arity a
928− , 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
9291000 , Constructor c
930− ) => TwoElemArrayObj arity (C1 c a) where
931− twoElemArrayObj opts targs x = V.create $ do
1001+ ) => SumToJSON' TwoElemArray Value arity (C1 c a) where
1002+ sumToJSON' opts targs x = Tagged $ Array $ V.create $ do
9321003 mv <- VM.unsafeNew 2
9331004 VM.unsafeWrite mv 0 $ String $ pack $ constructorTagModifier opts
9341005 $ conName (undefined :: t c a p)
@@ -937,149 +1008,121 @@ instance ( GToJSON arity a
9371008
9381009--------------------------------------------------------------------------------
9391010
940−class TwoElemArrayEnc arity f where
941− twoElemArrayEnc :: Options -> ToArgs Encoding arity a
942− -> f a -> Encoding
943−
944−instance ( TwoElemArrayEnc arity a
945− , TwoElemArrayEnc arity b
946− ) => TwoElemArrayEnc arity (a :+: b) where
947− twoElemArrayEnc opts targs (L1 x) = twoElemArrayEnc opts targs x
948− twoElemArrayEnc opts targs (R1 x) = twoElemArrayEnc opts targs x
949−
950−instance ( GToEncoding arity a
951− , ConsToEncoding arity a
1011+instance ( GToJSON Encoding arity a
1012+ , ConsToJSON Encoding arity a
9521013 , Constructor c
953− ) => TwoElemArrayEnc arity (C1 c a) where
954− twoElemArrayEnc opts targs x = E.list id
1014+ ) => SumToJSON' TwoElemArray Encoding arity (C1 c a)
1015+ where
1016+ sumToJSON' opts targs x = Tagged $ E.list id
9551017 [ toEncoding (constructorTagModifier opts (conName (undefined :: t c a p)))
956− , gToEncoding opts targs x
1018+ , gToJSON opts targs x
9571019 ]
9581020
9591021--------------------------------------------------------------------------------
9601022
961−class ConsToJSON arity f where
962− consToJSON :: Options -> ToArgs Value arity a
963− -> f a -> Value
1023+class ConsToJSON enc arity f where
1024+ consToJSON :: Options -> ToArgs enc arity a
1025+ -> f a -> enc
9641026
965−class ConsToJSON' arity f isRecord where
966− consToJSON' :: Options -> ToArgs Value arity a
967− -> Bool -- ^ Are we a record with one field?
968− -> f a -> Tagged isRecord Value
1027+class ConsToJSON' enc arity f isRecord where
1028+ consToJSON' :: Options -> ToArgs enc arity a
1029+ -> f a -> Tagged isRecord enc
9691030
970−instance ( IsRecord f isRecord
971− , ConsToJSON' arity f isRecord
972− ) => ConsToJSON arity f where
1031+instance ( IsRecord f isRecord
1032+ , ConsToJSON' enc arity f isRecord
1033+ ) => ConsToJSON enc arity f
1034+ where
9731035 consToJSON opts targs =
974− (unTagged :: Tagged isRecord Value -> Value)
975− . consToJSON' opts targs (isUnary (undefined :: f a))
976−
977−instance (RecordToPairs arity f) => ConsToJSON' arity f True where
978− consToJSON' opts targs isUn f = let
979− vals = toList $ recordToPairs opts targs f
980− in case (unwrapUnaryRecords opts,isUn,vals) of
981− (True,True,[(_,val)]) -> Tagged val
982− _ -> Tagged $ object vals
1036+ (unTagged :: Tagged isRecord enc -> enc)
1037+ . consToJSON' opts targs
1038+ {-# INLINE consToJSON #-}
9831039
984−instance GToJSON arity f => ConsToJSON' arity f False where
985− consToJSON' opts targs _ = Tagged . gToJSON opts targs
986−
987−--------------------------------------------------------------------------------
988−
989−class ConsToEncoding arity f where
990− consToEncoding :: Options -> ToArgs Encoding arity a
991− -> f a -> Encoding
992−
993−class ConsToEncoding' arity f isRecord where
994− consToEncoding' :: Options -> ToArgs Encoding arity a
995− -> Bool -- ^ Are we a record with one field?
996− -> f a -> Tagged isRecord Encoding
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' #-}
9971057
998−instance ( IsRecord f isRecord
999− , ConsToEncoding' arity f isRecord
1000− ) => ConsToEncoding arity f where
1001− consToEncoding opts targs =
1002− (unTagged :: Tagged isRecord Encoding -> Encoding)
1003− . consToEncoding' opts targs (isUnary (undefined :: f a))
1004−
1005−instance (RecordToEncoding arity f) => ConsToEncoding' arity f True where
1006− consToEncoding' opts targs isUn x =
1007− let (enc, mbVal) = recordToEncoding opts targs x
1008− in case (unwrapUnaryRecords opts, isUn, mbVal) of
1009− (True, True, Just val) -> Tagged val
1010− _ -> Tagged $ E.wrapObject enc
1011−
1012−instance GToEncoding arity f => ConsToEncoding' arity f False where
1013− consToEncoding' opts targs _ = Tagged . gToEncoding opts targs
1058+instance GToJSON enc arity f => ConsToJSON' enc arity f False where
1059+ consToJSON' opts targs = Tagged . gToJSON opts targs
1060+ {-# INLINE consToJSON' #-}
10141061
10151062--------------------------------------------------------------------------------
10161063
1017−class RecordToPairs arity f where
1018− recordToPairs :: Options -> ToArgs Value arity a
1019− -> f a -> DList Pair
1020−
1021−instance ( RecordToPairs arity a
1022− , RecordToPairs arity b
1023− ) => RecordToPairs arity (a :*: b) where
1024− recordToPairs opts targs (a :*: b) = recordToPairs opts targs a <>
1025− recordToPairs opts targs b
1064+class RecordToPairs enc pairs arity f where
1065+ -- 1st element: whole thing
1066+ -- 2nd element: in case the record has only 1 field, just the value
1067+ -- of the field (without the key); 'Nothing' otherwise
1068+ recordToPairs :: Options -> ToArgs enc arity a
1069+ -> f a -> pairs
10261070
1027−instance (Selector s, GToJSON arity a) => RecordToPairs arity (S1 s a) where
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
10281088 recordToPairs = fieldToPair
1029−
1030−instance OVERLAPPING_ (Selector s, ToJSON a) =>
1031− RecordToPairs arity (S1 s (K1 i (Maybe a))) where
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
10321098 recordToPairs opts _ (M1 k1) | omitNothingFields opts
1033− , K1 Nothing <- k1 = DList.empty
1099+ , K1 Nothing <- k1 = mempty
10341100 recordToPairs opts targs m1 = fieldToPair opts targs m1
1035−
1036−fieldToPair :: (Selector s, GToJSON arity a)
1037− => Options -> ToArgs Value arity p
1038− -> S1 s a p -> DList Pair
1039−fieldToPair opts targs m1 = pure ( pack $ fieldLabelModifier opts $ selName m1
1040− , gToJSON opts targs (unM1 m1)
1041− )
1042−
1043−--------------------------------------------------------------------------------
1044−
1045−class RecordToEncoding arity f where
1046− -- 1st element: whole thing
1047− -- 2nd element: in case the record has only 1 field, just the value
1048− -- of the field (without the key); 'Nothing' otherwise
1049− recordToEncoding :: Options -> ToArgs Encoding arity a
1050− -> f a -> (Encoding, Maybe Encoding)
1051−
1052−instance ( RecordToEncoding arity a
1053− , RecordToEncoding arity b
1054− ) => RecordToEncoding arity (a :*: b) where
1055− recordToEncoding opts targs (a :*: b) | omitNothingFields opts =
1056− (E.econcat $ intersperse E.comma $
1057− filter (not . E.nullEncoding)
1058− [ fst (recordToEncoding opts targs a)
1059− , fst (recordToEncoding opts targs b) ]
1060− , Nothing)
1061− recordToEncoding opts targs (a :*: b) =
1062− (fst (recordToEncoding opts targs a) >< E.comma ><
1063− fst (recordToEncoding opts targs b),
1064− Nothing)
1065−
1066−
1067−instance (Selector s, GToEncoding arity a) => RecordToEncoding arity (S1 s a) where
1068− recordToEncoding = fieldToEncoding
1069−
1070−instance OVERLAPPING_ (Selector s, ToJSON a) =>
1071− RecordToEncoding arity (S1 s (K1 i (Maybe a))) where
1072− recordToEncoding opts _ (M1 k1) | omitNothingFields opts
1073− , K1 Nothing <- k1 = (E.empty, Nothing)
1074− recordToEncoding opts targs m1 = fieldToEncoding opts targs m1
1075−
1076−fieldToEncoding :: (Selector s, GToEncoding arity a)
1077− => Options -> ToArgs Encoding arity p
1078− -> S1 s a p -> (Encoding, Maybe Encoding)
1079−fieldToEncoding opts targs m1 =
1080− let keyBuilder = toEncoding (fieldLabelModifier opts $ selName m1)
1081− valueBuilder = gToEncoding opts targs (unM1 m1)
1082− in (keyBuilder >< E.colon >< valueBuilder, Just valueBuilder)
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 #-}
10831126
10841127--------------------------------------------------------------------------------
10851128
@@ -1102,10 +1145,12 @@ instance ( WriteProduct arity a
11021145 lenL = len `unsafeShiftR` 1
11031146 lenR = len - lenL
11041147 ixR = ix + lenL
1148+ {-# INLINE writeProduct #-}
11051149
1106−instance OVERLAPPABLE_ (GToJSON arity a) => WriteProduct arity a where
1150+instance OVERLAPPABLE_ (GToJSON Value arity a) => WriteProduct arity a where
11071151 writeProduct opts targs mv ix _ =
11081152 VM.unsafeWrite mv ix . gToJSON opts targs
1153+ {-# INLINE writeProduct #-}
11091154
11101155--------------------------------------------------------------------------------
11111156
@@ -1123,110 +1168,41 @@ instance ( EncodeProduct arity a
11231168 encodeProduct opts targs (a :*: b) =
11241169 encodeProduct opts targs a >*<
11251170 encodeProduct opts targs b
1171+ {-# INLINE encodeProduct #-}
11261172
1127−instance OVERLAPPABLE_ (GToEncoding arity a) => EncodeProduct arity a where
1128− encodeProduct opts targs a = E.retagEncoding $ gToEncoding opts targs a
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 #-}
11291176
11301177--------------------------------------------------------------------------------
11311178
1132−class ObjectWithSingleFieldObj arity f where
1133− objectWithSingleFieldObj :: Options -> ToArgs Value arity a
1134− -> f a -> Object
1135−
1136−instance ( ObjectWithSingleFieldObj arity a
1137− , ObjectWithSingleFieldObj arity b
1138− ) => ObjectWithSingleFieldObj arity (a :+: b) where
1139− objectWithSingleFieldObj opts targs (L1 x) =
1140− objectWithSingleFieldObj opts targs x
1141− objectWithSingleFieldObj opts targs (R1 x) =
1142− objectWithSingleFieldObj opts targs x
1143−
1144−instance ( GToJSON arity a
1145− , ConsToJSON arity a
1179+instance ( GToJSON enc arity a
1180+ , ConsToJSON enc arity a
1181+ , FromPairs enc pairs
1182+ , KeyValuePair enc pairs
11461183 , Constructor c
1147− ) => ObjectWithSingleFieldObj arity (C1 c a) where
1148− objectWithSingleFieldObj opts targs = H.singleton typ . gToJSON opts targs
1184+ ) => SumToJSON' ObjectWithSingleField enc arity (C1 c a)
1185+ where
1186+ sumToJSON' opts targs =
1187+ Tagged . fromPairs . (typ `pair`) . gToJSON opts targs
11491188 where
1150− typ = pack $ constructorTagModifier opts $
1189+ typ = constructorTagModifier opts $
11511190 conName (undefined :: t c a p)
11521191
11531192--------------------------------------------------------------------------------
11541193
1155−class ObjectWithSingleFieldEnc arity f where
1156− objectWithSingleFieldEnc :: Options -> ToArgs Encoding arity a
1157− -> f a -> Encoding
1158−
1159−instance ( ObjectWithSingleFieldEnc arity a
1160− , ObjectWithSingleFieldEnc arity b
1161− ) => ObjectWithSingleFieldEnc arity (a :+: b) where
1162− objectWithSingleFieldEnc opts targs (L1 x) =
1163− objectWithSingleFieldEnc opts targs x
1164− objectWithSingleFieldEnc opts targs (R1 x) =
1165− objectWithSingleFieldEnc opts targs x
1166−
1167−instance ( GToEncoding arity a
1168− , ConsToEncoding arity a
1169− , Constructor c
1170− ) => ObjectWithSingleFieldEnc arity (C1 c a) where
1171− objectWithSingleFieldEnc opts targs v = E.pairs (E.pair key val)
1172− where
1173− key :: Text
1174− key = pack (constructorTagModifier opts (conName (undefined :: t c a p)))
1175− val :: Encoding' Value
1176− val = gToEncoding opts targs v
1177−
1178−--------------------------------------------------------------------------------
1179−
1180−class UntaggedValueObj arity f where
1181− untaggedValueObj :: Options -> ToArgs Value arity a
1182− -> f a -> Value
1183−
1184−instance
1185− ( UntaggedValueObj arity a
1186− , UntaggedValueObj arity b
1187− ) => UntaggedValueObj arity (a :+: b)
1188− where
1189− untaggedValueObj opts targs (L1 x) = untaggedValueObj opts targs x
1190− untaggedValueObj opts targs (R1 x) = untaggedValueObj opts targs x
1191−
1192−instance OVERLAPPABLE_
1193− ( GToJSON arity a
1194− , ConsToJSON arity a
1195− ) => UntaggedValueObj arity (C1 c a) where
1196− untaggedValueObj = gToJSON
1197−
1198−instance OVERLAPPING_
1199− ( Constructor c )
1200− => UntaggedValueObj arity (C1 c U1)
1201− where
1202− untaggedValueObj opts _ _ = toJSON $
1203− constructorTagModifier opts $ conName (undefined :: t c U1 p)
1204−
1205−--------------------------------------------------------------------------------
1206−
1207−class UntaggedValueEnc arity f where
1208− untaggedValueEnc :: Options -> ToArgs Encoding arity a
1209− -> f a -> Encoding
1210−instance
1211− ( UntaggedValueEnc arity a
1212− , UntaggedValueEnc arity b
1213− ) => UntaggedValueEnc arity (a :+: b)
1214− where
1215− untaggedValueEnc opts targs (L1 x) = untaggedValueEnc opts targs x
1216− untaggedValueEnc opts targs (R1 x) = untaggedValueEnc opts targs x
1217−
12181194instance OVERLAPPABLE_
1219− ( GToEncoding arity a
1220− , ConsToEncoding arity a
1221− ) => UntaggedValueEnc arity (C1 c a)
1195+ ( ConsToJSON enc arity a
1196+ ) => SumToJSON' UntaggedValue enc arity (C1 c a)
12221197 where
1223− untaggedValueEnc = gToEncoding
1198+ sumToJSON' opts targs = Tagged . gToJSON opts targs
12241199
12251200instance OVERLAPPING_
1226− ( Constructor c )
1227− => UntaggedValueEnc arity (C1 c U1)
1201+ ( Constructor c
1202+ , FromString enc
1203+ ) => SumToJSON' UntaggedValue enc arity (C1 c U1)
12281204 where
1229− untaggedValueEnc opts _ _ = toEncoding $
1205+ sumToJSON' opts _ _ = Tagged . fromString $
12301206 constructorTagModifier opts $ conName (undefined :: t c U1 p)
12311207
12321208-------------------------------------------------------------------------------
@@ -1300,6 +1276,13 @@ instance (ToJSON a, ToJSON b) => ToJSON (Either a b) where
13001276 toEncoding = toEncoding2
13011277 {-# INLINE toEncoding #-}
13021278
1279+instance ToJSON Void where
1280+ toJSON = absurd
1281+ {-# INLINE toJSON #-}
1282+
1283+ toEncoding = absurd
1284+ {-# INLINE toEncoding #-}
1285+
13031286
13041287instance ToJSON Bool where
13051288 toJSON = Bool
@@ -1485,7 +1468,6 @@ instance ToJSONKey Int64 where
14851468 toJSONKey = toJSONKeyTextEnc E.int64Text
14861469 {-# INLINE toJSONKey #-}
14871470
1488−
14891471instance ToJSON Word where
14901472 toJSON = Number . fromIntegral
14911473 {-# INLINE toJSON #-}
@@ -1545,6 +1527,12 @@ instance ToJSONKey Word64 where
15451527 toJSONKey = toJSONKeyTextEnc E.word64Text
15461528 {-# INLINE toJSONKey #-}
15471529
1530+instance ToJSON CTime where
1531+ toJSON (CTime i) = toJSON i
1532+ {-# INLINE toJSON #-}
1533+
1534+ toEncoding (CTime i) = toEncoding i
1535+ {-# INLINE toEncoding #-}
15481536
15491537instance ToJSON Text where
15501538 toJSON = String
@@ -1659,7 +1647,7 @@ instance (ToJSON a) => ToJSON (Identity a) where
16591647 toEncodingList = liftToEncodingList toEncoding toEncodingList
16601648 {-# INLINE toEncodingList #-}
16611649
1662−instance (ToJSONKey a, ToJSON a) => ToJSONKey (Identity a) where
1650+instance (ToJSONKey a) => ToJSONKey (Identity a) where
16631651 toJSONKey = contramapToJSONKeyFunction runIdentity toJSONKey
16641652 toJSONKeyList = contramapToJSONKeyFunction (map runIdentity) toJSONKeyList
16651653
@@ -1850,6 +1838,17 @@ instance (ToJSON v) => ToJSON (Tree.Tree v) where
18501838 toEncoding = toEncoding1
18511839 {-# INLINE toEncoding #-}
18521840
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
18531852
18541853-------------------------------------------------------------------------------
18551854-- vector
@@ -1863,6 +1862,8 @@ instance ToJSON1 Vector where
18631862 {-# INLINE liftToEncoding #-}
18641863
18651864instance (ToJSON a) => ToJSON (Vector a) where
1865+ {-# SPECIALIZE instance ToJSON Array #-}
1866+
18661867 toJSON = toJSON1
18671868 {-# INLINE toJSON #-}
18681869
@@ -1934,6 +1935,8 @@ instance ToJSONKey k => ToJSON1 (H.HashMap k) where
19341935 {-# INLINE liftToEncoding #-}
19351936
19361937instance (ToJSON v, ToJSONKey k) => ToJSON (H.HashMap k v) where
1938+ {-# SPECIALIZE instance ToJSON Object #-}
1939+
19371940 toJSON = toJSON1
19381941 {-# INLINE toJSON #-}
19391942
@@ -1963,6 +1966,32 @@ dotNetTime (DotNetTime t) = secs ++ formatMillis t ++ ")/"
19631966formatMillis :: (FormatTime t) => t -> String
19641967formatMillis = take 3 . formatTime defaultTimeLocale "%q"
19651968
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+
19661995-------------------------------------------------------------------------------
19671996-- time
19681997-------------------------------------------------------------------------------
@@ -2011,10 +2040,11 @@ stringEncoding :: Encoding' Text -> Value
20112040stringEncoding = String
20122041 . T.dropAround (== '"')
20132042 . T.decodeLatin1
2014− . lazyToStrictByteString
2043+ . L.toStrict
20152044 . E.encodingToLazyByteString
20162045{-# INLINE stringEncoding #-}
20172046
2047+
20182048instance ToJSON NominalDiffTime where
20192049 toJSON = Number . realToFrac
20202050 {-# INLINE toJSON #-}
@@ -2022,18 +2052,85 @@ instance ToJSON NominalDiffTime where
20222052 toEncoding = E.scientific . realToFrac
20232053 {-# INLINE toEncoding #-}
20242054
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+
20252107-------------------------------------------------------------------------------
20262108-- base Monoid/Semigroup
20272109-------------------------------------------------------------------------------
20282110
2029−instance ToJSON1 Dual where
2030− liftToJSON t _ = t . getDual
2111+instance ToJSON1 Monoid.Dual where
2112+ liftToJSON t _ = t . Monoid.getDual
2113+ {-# INLINE liftToJSON #-}
2114+
2115+ liftToEncoding t _ = t . Monoid.getDual
2116+ {-# INLINE liftToEncoding #-}
2117+
2118+instance ToJSON a => ToJSON (Monoid.Dual a) where
2119+ toJSON = toJSON1
2120+ {-# INLINE toJSON #-}
2121+
2122+ toEncoding = toEncoding1
2123+ {-# INLINE toEncoding #-}
2124+
2125+
2126+instance ToJSON1 Monoid.First where
2127+ liftToJSON t to' = liftToJSON t to' . Monoid.getFirst
20312128 {-# INLINE liftToJSON #-}
20322129
2033− liftToEncoding t _ = t . getDual
2130+ liftToEncoding t to' = liftToEncoding t to' . Monoid.getFirst
20342131 {-# INLINE liftToEncoding #-}
20352132
2036−instance ToJSON a => ToJSON (Dual a) where
2133+instance ToJSON a => ToJSON (Monoid.First a) where
20372134 toJSON = toJSON1
20382135 {-# INLINE toJSON #-}
20392136
@@ -2041,14 +2138,14 @@ instance ToJSON a => ToJSON (Dual a) where
20412138 {-# INLINE toEncoding #-}
20422139
20432140
2044−instance ToJSON1 First where
2045− liftToJSON t to' = liftToJSON t to' . getFirst
2141+instance ToJSON1 Monoid.Last where
2142+ liftToJSON t to' = liftToJSON t to' . Monoid.getLast
20462143 {-# INLINE liftToJSON #-}
20472144
2048− liftToEncoding t to' = liftToEncoding t to' . getFirst
2145+ liftToEncoding t to' = liftToEncoding t to' . Monoid.getLast
20492146 {-# INLINE liftToEncoding #-}
20502147
2051−instance ToJSON a => ToJSON (First a) where
2148+instance ToJSON a => ToJSON (Monoid.Last a) where
20522149 toJSON = toJSON1
20532150 {-# INLINE toJSON #-}
20542151
@@ -2056,14 +2153,88 @@ instance ToJSON a => ToJSON (First a) where
20562153 {-# INLINE toEncoding #-}
20572154
20582155
2059−instance ToJSON1 Last where
2060− liftToJSON t to' = liftToJSON t to' . getLast
2156+instance ToJSON1 Semigroup.Min where
2157+ liftToJSON t _ (Semigroup.Min x) = t x
20612158 {-# INLINE liftToJSON #-}
20622159
2063− liftToEncoding t to' = liftToEncoding t to' . getLast
2160+ liftToEncoding t _ (Semigroup.Min x) = t x
20642161 {-# INLINE liftToEncoding #-}
20652162
2066−instance ToJSON a => ToJSON (Last a) where
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
20672238 toJSON = toJSON1
20682239 {-# INLINE toJSON #-}
20692240
@@ -2074,6 +2245,13 @@ instance ToJSON a => ToJSON (Last a) where
20742245-- tagged
20752246-------------------------------------------------------------------------------
20762247
2248+instance ToJSON1 Proxy where
2249+ liftToJSON _ _ _ = Null
2250+ {-# INLINE liftToJSON #-}
2251+
2252+ liftToEncoding _ _ _ = E.null_
2253+ {-# INLINE liftToEncoding #-}
2254+
20772255instance ToJSON (Proxy a) where
20782256 toJSON _ = Null
20792257 {-# INLINE toJSON #-}
@@ -2082,6 +2260,13 @@ instance ToJSON (Proxy a) where
20822260 {-# INLINE toEncoding #-}
20832261
20842262
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+
20852270instance ToJSON1 (Tagged a) where
20862271 liftToJSON t _ (Tagged x) = t x
20872272 {-# INLINE liftToJSON #-}
@@ -2096,7 +2281,6 @@ instance ToJSON b => ToJSON (Tagged a b) where
20962281 toEncoding = toEncoding1
20972282 {-# INLINE toEncoding #-}
20982283
2099−
21002284instance ToJSONKey b => ToJSONKey (Tagged a b) where
21012285 toJSONKey = contramapToJSONKeyFunction unTagged toJSONKey
21022286 toJSONKeyList = contramapToJSONKeyFunction (fmap unTagged) toJSONKeyList
@@ -2663,27 +2847,26 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f, ToJSON g,
26632847 toEncoding = toEncoding2
26642848 {-# INLINE toEncoding #-}
26652849
2666−-------------------------------------------------------------------------------
2667−-- pre-bytestring-0.10 compatibility
2668−-------------------------------------------------------------------------------
2850+--------------------------------------------------------------------------------
26692851
2670−{-# INLINE lazyToStrictByteString #-}
2671−lazyToStrictByteString :: L.ByteString -> S.ByteString
2672−#if MIN_VERSION_bytestring(0,10,0)
2673−lazyToStrictByteString = L.toStrict
2674−#else
2675−lazyToStrictByteString = packChunks
2852+-- | Wrap a list of pairs as an object.
2853+class Monoid pairs => FromPairs enc pairs | enc -> pairs where
2854+ fromPairs :: pairs -> enc
26762855
2677−-- packChunks is taken from the blaze-builder package.
2856+instance (a ~ Value) => FromPairs (Encoding' a) Series where
2857+ fromPairs = E.pairs
26782858
2679−-- | Pack the chunks of a lazy bytestring into a single strict bytestring.
2680−packChunks :: L.ByteString -> S.ByteString
2681−packChunks lbs = do
2682− S.unsafeCreate (fromIntegral $ L.length lbs) (copyChunks lbs)
2683− where
2684− copyChunks !L.Empty !_pf = return ()
2685− copyChunks !(L.Chunk (S.PS fpbuf o l) lbs') !pf = do
2686− withForeignPtr fpbuf $ \pbuf ->
2687− copyBytes pf (pbuf `plusPtr` o) l
2688− copyChunks lbs' (pf `plusPtr` l)
2689−#endif
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+108−63
@@ -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,12 +33,17 @@ 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
@@ -68,8 +60,14 @@ flag bytestring-builder
6860 default: False
6961 manual: False
7062
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+
7168library
7269 default-language: Haskell2010
70+ hs-source-dirs: . attoparsec-iso8601/
7371
7472 exposed-modules:
7573 Data.Aeson
@@ -78,10 +76,12 @@ library
7876 Data.Aeson.Text
7977 Data.Aeson.Types
8078 Data.Aeson.TH
79+ Data.Aeson.QQ.Simple
8180
8281 Data.Aeson.Encoding.Internal
8382 Data.Aeson.Internal
8483 Data.Aeson.Internal.Time
84+ Data.Aeson.Parser.Internal
8585
8686 -- Deprecated modules
8787 exposed-modules:
@@ -90,49 +90,69 @@ library
9090 other-modules:
9191 Data.Aeson.Encoding.Builder
9292 Data.Aeson.Internal.Functions
93− Data.Aeson.Parser.Internal
93+ Data.Aeson.Parser.Unescape
9494 Data.Aeson.Parser.Time
9595 Data.Aeson.Types.FromJSON
9696 Data.Aeson.Types.Generic
9797 Data.Aeson.Types.ToJSON
9898 Data.Aeson.Types.Class
9999 Data.Aeson.Types.Internal
100+ Data.Attoparsec.Time
101+ Data.Attoparsec.Time.Internal
100102
103+ -- GHC bundled libs
101104 build-depends:
102− attoparsec >= 0.13.0.1,
103− base >= 4.5 && < 5,
104− base-compat >= 0.9.1 && < 0.10,
105− containers >= 0.2.4.1,
106− deepseq >= 1.3,
107− dlist >= 0.2,
108− ghc-prim >= 0.2,
109− hashable >= 1.1.2.0,
110− scientific >= 0.3.4.7 && < 0.4,
111− tagged >=0.8.3 && <0.9,
112− template-haskell >= 2.7,
113− text >= 1.1.1.0,
114− time >= 1.1.1.4,
115− time-locale-compat >= 0.1.1 && < 0.2,
116− unordered-containers >= 0.2.5.0,
117− 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
118113
119− if flag(bytestring-builder)
120− build-depends: bytestring >= 0.9 && < 0.10.4,
121− bytestring-builder >= 0.10.4 && < 1
122− else
123− build-depends: bytestring >= 0.10.4
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
124125
125126 if !impl(ghc >= 8.0)
126127 -- `Data.Semigroup` and `Control.Monad.Fail` and `Control.Monad.IO.Class` are available in base only since GHC 8.0 / base 4.9
127128 build-depends:
128− semigroups >= 0.18.2 && < 0.19,
129− transformers >= 0.2.2.0,
130− transformers-compat >= 0.3,
129+ semigroups >= 0.18.5 && < 0.20,
130+ transformers >= 0.3.0.0 && < 0.6,
131+ transformers-compat >= 0.6.2 && < 0.7,
131132 fail == 4.9.*
132133
133134 if !impl(ghc >= 7.10)
134135 -- `Numeric.Natural` is available in base only since GHC 7.10 / base 4.8
135− 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
136156
137157 ghc-options: -Wall
138158
@@ -146,53 +166,78 @@ library
146166 ghc-options: -O2
147167
148168 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
149177
150178test-suite tests
151179 default-language: Haskell2010
152− type: exitcode-stdio-1.0
153− hs-source-dirs: tests
154− 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+
155186 other-modules:
187+ Data.Aeson.Parser.UnescapeFFI
188+ Data.Aeson.Parser.UnescapePure
156189 DataFamilies.Properties
157190 DataFamilies.Instances
158191 DataFamilies.Encoders
159192 DataFamilies.Types
160193 Encoders
194+ ErrorMessages
161195 Functions
162196 Instances
163197 Options
198+ PropUtils
164199 Properties
200+ PropertyGeneric
201+ PropertyKeys
202+ PropertyRoundTrip
203+ PropertyRTFunctors
204+ PropertyTH
205+ SerializationFormatSpec
165206 Types
166207 UnitTests
167208 UnitTests.NullaryConstructors
168209
169− ghc-options: -Wall -threaded -rtsopts
170−
171210 build-depends:
172− HUnit,
173− QuickCheck >= 2.7 && <2.10,
211+ QuickCheck >= 2.10.0.1 && < 2.14,
174212 aeson,
213+ integer-logarithms >= 1 && <1.1,
175214 attoparsec,
176215 base,
177216 base-compat,
178− base-orphans >= 0.5.3 && <0.6,
217+ base-orphans >= 0.5.3 && <0.9,
218+ base16-bytestring,
179219 containers,
220+ directory,
180221 dlist,
181− generic-deriving >= 1.10 && < 1.11,
222+ Diff >= 0.4 && < 0.5,
223+ filepath,
224+ generic-deriving >= 1.10 && < 1.14,
182225 ghc-prim >= 0.2,
183226 hashable >= 1.2.4.0,
184227 scientific,
185228 tagged,
186229 template-haskell,
187− test-framework,
188− test-framework-hunit,
189− test-framework-quickcheck2,
230+ tasty,
231+ tasty-golden,
232+ tasty-hunit,
233+ tasty-quickcheck,
190234 text,
191235 time,
192− time-locale-compat,
236+ time-compat,
193237 unordered-containers,
238+ uuid-types,
194239 vector,
195− quickcheck-instances >=0.3.12
240+ quickcheck-instances >= 0.3.21 && <0.4
196241
197242 if flag(bytestring-builder)
198243 build-depends: bytestring >= 0.9 && < 0.10.4,
@@ -202,20 +247,20 @@ test-suite tests
202247
203248 if !impl(ghc >= 8.0)
204249 build-depends:
205− semigroups >= 0.18.2 && < 0.19,
250+ semigroups >= 0.18.2 && < 0.20,
206251 transformers >= 0.2.2.0,
207252 transformers-compat >= 0.3
208253
209254 if !impl(ghc >= 7.10)
210− build-depends: nats >=1 && <1.2
255+ build-depends: nats >=1 && <1.2,
256+ void >=0.7.2 && <0.8
211257
212258 if impl(ghc >= 7.8)
213259 build-depends: hashable-time >= 0.2 && <0.3
214260
261+ if flag(fast)
262+ ghc-options: -fno-enable-rewrite-rules
263+
215264source-repository head
216265 type: git
217266 location: git://github.com/bos/aeson.git
218−
219−source-repository head
220− type: mercurial
221− 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−229
@@ -1,229 +0,0 @@
1−{-# LANGUAGE DeriveDataTypeable #-}
2−{-# LANGUAGE DeriveGeneric #-}
3−{-# LANGUAGE TemplateHaskell #-}
4−
5−module Main (main) where
6−
7−import Prelude ()
8−import Prelude.Compat
9−
10−import Control.DeepSeq (NFData, rnf, deepseq)
11−import Criterion.Main hiding (defaultOptions)
12−import Data.Aeson.Encode
13−import Data.Aeson.TH
14−import Data.Aeson.Types
15−import Data.Data (Data)
16−import Data.Typeable (Typeable)
17−import GHC.Generics (Generic)
18−import Options
19−import qualified Data.Aeson.Generic as G (fromJSON, toJSON)
20−
21−--------------------------------------------------------------------------------
22−
23−data D a = Nullary
24− | Unary Int
25− | Product String Char a
26− | Record { testOne :: Double
27− , testTwo :: Bool
28− , testThree :: D a
29− }
30− deriving (Show, Eq, Data, Typeable)
31−
32−deriveJSON opts ''D
33−
34−instance NFData a => NFData (D a) where
35− rnf Nullary = ()
36− rnf (Unary n) = rnf n
37− rnf (Product s c x) = s `deepseq` c `deepseq` rnf x
38− rnf (Record d b y) = d `deepseq` b `deepseq` rnf y
39−
40−type T = D (D (D ()))
41−
42−d :: T
43−d = Record
44− { testOne = 1234.56789
45− , testTwo = True
46− , testThree = Product "Hello World!" 'a' $
47− Record
48− { testOne = 9876.54321
49− , testTwo = False
50− , testThree = Product "Yeehaa!!!" '\n' Nullary
51− }
52− }
53−
54−--------------------------------------------------------------------------------
55−
56−data D' a = Nullary'
57− | Unary' Int
58− | Product' String Char a
59− | Record' { testOne' :: Double
60− , testTwo' :: Bool
61− , testThree' :: D' a
62− }
63− deriving (Show, Eq, Generic, Data, Typeable)
64−
65−instance ToJSON a => ToJSON (D' a) where
66− toJSON = genericToJSON opts
67−
68−instance FromJSON a => FromJSON (D' a) where
69− parseJSON = genericParseJSON opts
70−
71−instance NFData a => NFData (D' a) where
72− rnf Nullary' = ()
73− rnf (Unary' n) = rnf n
74− rnf (Product' s c x) = s `deepseq` c `deepseq` rnf x
75− rnf (Record' d b y) = d `deepseq` b `deepseq` rnf y
76−
77−type T' = D' (D' (D' ()))
78−
79−d' :: T'
80−d' = Record'
81− { testOne' = 1234.56789
82− , testTwo' = True
83− , testThree' = Product' "Hello World!" 'a' $
84− Record'
85− { testOne' = 9876.54321
86− , testTwo' = False
87− , testThree' = Product' "Yeehaa!!!" '\n' Nullary'
88− }
89− }
90−
91−--------------------------------------------------------------------------------
92−
93−data BigRecord = BigRecord
94− { field01 :: !Int, field02 :: !Int, field03 :: !Int, field04 :: !Int, field05 :: !Int
95− , field06 :: !Int, field07 :: !Int, field08 :: !Int, field09 :: !Int, field10 :: !Int
96− , field11 :: !Int, field12 :: !Int, field13 :: !Int, field14 :: !Int, field15 :: !Int
97− , field16 :: !Int, field17 :: !Int, field18 :: !Int, field19 :: !Int, field20 :: !Int
98− , field21 :: !Int, field22 :: !Int, field23 :: !Int, field24 :: !Int, field25 :: !Int
99− } deriving (Show, Eq, Generic, Data, Typeable)
100−
101−instance NFData BigRecord
102−
103−bigRecord = BigRecord 1 2 3 4 5
104− 6 7 8 9 10
105− 11 12 13 14 15
106− 16 17 18 19 20
107− 21 22 23 24 25
108−
109−gBigRecordToJSON :: BigRecord -> Value
110−gBigRecordToJSON = genericToJSON opts
111−
112−gBigRecordFromJSON :: Value -> Result BigRecord
113−gBigRecordFromJSON = parse $ genericParseJSON opts
114−
115−thBigRecordToJSON :: BigRecord -> Value
116−thBigRecordToJSON = $(mkToJSON opts ''BigRecord)
117−
118−thBigRecordFromJSON :: Value -> Result BigRecord
119−thBigRecordFromJSON = parse $(mkParseJSON opts ''BigRecord)
120−
121−--------------------------------------------------------------------------------
122−
123−data BigProduct = BigProduct
124− !Int !Int !Int !Int !Int
125− !Int !Int !Int !Int !Int
126− !Int !Int !Int !Int !Int
127− !Int !Int !Int !Int !Int
128− !Int !Int !Int !Int !Int
129− deriving (Show, Eq, Generic, Data, Typeable)
130−
131−instance NFData BigProduct
132−
133−bigProduct = BigProduct 1 2 3 4 5
134− 6 7 8 9 10
135− 11 12 13 14 15
136− 16 17 18 19 20
137− 21 22 23 24 25
138−
139−gBigProductToJSON :: BigProduct -> Value
140−gBigProductToJSON = genericToJSON opts
141−
142−gBigProductFromJSON :: Value -> Result BigProduct
143−gBigProductFromJSON = parse $ genericParseJSON opts
144−
145−thBigProductToJSON :: BigProduct -> Value
146−thBigProductToJSON = $(mkToJSON opts ''BigProduct)
147−
148−thBigProductFromJSON :: Value -> Result BigProduct
149−thBigProductFromJSON = parse $(mkParseJSON opts ''BigProduct)
150−
151−--------------------------------------------------------------------------------
152−
153−data BigSum = F01 | F02 | F03 | F04 | F05
154− | F06 | F07 | F08 | F09 | F10
155− | F11 | F12 | F13 | F14 | F15
156− | F16 | F17 | F18 | F19 | F20
157− | F21 | F22 | F23 | F24 | F25
158− deriving (Show, Eq, Generic, Data, Typeable)
159−
160−instance NFData BigSum
161−
162−bigSum = F25
163−
164−gBigSumToJSON :: BigSum -> Value
165−gBigSumToJSON = genericToJSON opts
166−
167−gBigSumFromJSON :: Value -> Result BigSum
168−gBigSumFromJSON = parse $ genericParseJSON opts
169−
170−thBigSumToJSON :: BigSum -> Value
171−thBigSumToJSON = $(mkToJSON opts ''BigSum)
172−
173−thBigSumFromJSON :: Value -> Result BigSum
174−thBigSumFromJSON = parse $(mkParseJSON opts ''BigSum)
175−
176−--------------------------------------------------------------------------------
177−
178−type FJ a = Value -> Result a
179−
180−main :: IO ()
181−main = defaultMain
182− [ let v = toJSON d
183− in (d, d', v) `deepseq`
184− bgroup "D"
185− [ group "toJSON" (nf toJSON d)
186− (nf G.toJSON d)
187− (nf toJSON d')
188− , group "fromJSON" (nf ( fromJSON :: FJ T ) v)
189− (nf (G.fromJSON :: FJ T ) v)
190− (nf ( fromJSON :: FJ T') v)
191− ]
192− , let v = thBigRecordToJSON bigRecord
193− in bigRecord `deepseq` v `deepseq`
194− bgroup "BigRecord"
195− [ group "toJSON" (nf thBigRecordToJSON bigRecord)
196− (nf G.toJSON bigRecord)
197− (nf gBigRecordToJSON bigRecord)
198− , group "fromJSON" (nf (thBigRecordFromJSON :: FJ BigRecord) v)
199− (nf (G.fromJSON :: FJ BigRecord) v)
200− (nf (gBigRecordFromJSON :: FJ BigRecord) v)
201− ]
202− , let v = thBigProductToJSON bigProduct
203− in bigProduct `deepseq` v `deepseq`
204− bgroup "BigProduct"
205− [ group "toJSON" (nf thBigProductToJSON bigProduct)
206− (nf G.toJSON bigProduct)
207− (nf gBigProductToJSON bigProduct)
208− , group "fromJSON" (nf (thBigProductFromJSON :: FJ BigProduct) v)
209− (nf (G.fromJSON :: FJ BigProduct) v)
210− (nf (gBigProductFromJSON :: FJ BigProduct) v)
211− ]
212− , let v = thBigSumToJSON bigSum
213− in bigSum `deepseq` v `deepseq`
214− bgroup "BigSum"
215− [ group "toJSON" (nf thBigSumToJSON bigSum)
216− (nf G.toJSON bigSum)
217− (nf gBigSumToJSON bigSum)
218− , group "fromJSON" (nf (thBigSumFromJSON :: FJ BigSum) v)
219− (nf (G.fromJSON :: FJ BigSum) v)
220− (nf (gBigSumFromJSON :: FJ BigSum) v)
221− ]
222− ]
223−
224−group n th syb gen = bcompare
225− [ bgroup n [ bench "th" th
226− , bench "syb" syb
227− , bench "generic" gen
228− ]
229− ]
benchmarks/AesonEncode.hs+4−5
@@ -1,14 +1,13 @@
11{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
23{-# LANGUAGE OverloadedStrings #-}
34
45module Main (main) where
56
6−import Prelude ()
77import Prelude.Compat
88
99import Control.DeepSeq
10−import Control.Exception
11−import Control.Monad
10+import Control.Monad (forM_)
1211import Data.Aeson
1312import Data.Attoparsec.ByteString (IResult(..), parseWith)
1413import Data.Char (isDigit)
@@ -25,7 +24,7 @@ main = do
2524 (c:a) -> (c,a)
2625 [] -> error "Unexpected empty list"
2726 let count = read cnt :: Int
28− forM_ args $ \arg -> bracket (openFile arg ReadMode) hClose $ \h -> do
27+ forM_ args $ \arg -> withFile arg ReadMode $ \h -> do
2928 putStrLn $ arg ++ ":"
3029 let refill = B.hGet h 16384
3130 result0 <- parseWith refill json =<< refill
@@ -35,7 +34,7 @@ main = do
3534 start <- getCurrentTime
3635 let loop !n r
3736 | n >= count = return ()
38− | otherwise = {-# SCC "loop" #-} do
37+ | otherwise = {-# SCC "loop" #-}
3938 rnf (encode r) `seq` loop (n+1) r
4039 loop 0 r0
4140 delta <- flip diffUTCTime start `fmap` getCurrentTime
benchmarks/AesonFoldable.hs+14−42
@@ -1,16 +1,14 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE PackageImports #-}
33
44module Main (main) where
55
66import Criterion.Main
77
8−import Prelude ()
98import Prelude.Compat
109
1110import Data.Foldable (toList)
12−import qualified "aeson" Data.Aeson as A
13−import qualified "aeson-benchmarks" Data.Aeson as B
11+import qualified Data.Aeson as A
1412import qualified Data.Sequence as S
1513import qualified Data.Vector as V
1614import qualified Data.Vector.Unboxed as U
@@ -21,10 +19,6 @@ import qualified Data.Vector.Unboxed as U
2119
2220newtype L f = L { getL :: f Int }
2321
24−instance Foldable f => B.ToJSON (L f) where
25− toJSON = error "do not use this"
26− toEncoding = B.toEncoding . toList . getL
27−
2822instance Foldable f => A.ToJSON (L f) where
2923 toJSON = error "do not use this"
3024 toEncoding = A.toEncoding . toList . getL
@@ -35,10 +29,6 @@ instance Foldable f => A.ToJSON (L f) where
3529
3630newtype F f = F { getF :: f Int }
3731
38−instance Foldable f => B.ToJSON (F f) where
39− toJSON = error "do not use this"
40− toEncoding = B.foldable . getF
41−
4232instance Foldable f => A.ToJSON (F f) where
4333 toJSON = error "do not use this"
4434 toEncoding = A.foldable . getF
@@ -63,52 +53,34 @@ valueUVector = U.fromList valueList
6353-- Main
6454-------------------------------------------------------------------------------
6555
66−benchEncodeA
56+benchEncode
6757 :: A.ToJSON a
6858 => String
6959 -> a
7060 -> Benchmark
71−benchEncodeA name val
61+benchEncode name val
7262 = bench ("A " ++ name) $ nf A.encode val
7363
74−benchEncodeB
75− :: B.ToJSON a
76− => String
77− -> a
78− -> Benchmark
79−benchEncodeB name val
80− = bench ("B " ++ name) $ nf B.encode val
81−
8264main :: IO ()
8365main = defaultMain
8466 [ bgroup "encode"
8567 [ bgroup "List"
86− [ benchEncodeB "-" valueList
87− , benchEncodeB "L" $ L valueList
88− , benchEncodeB "F" $ F valueList
89− , benchEncodeA "-" valueList
90− , benchEncodeA "L" $ L valueList
91− , benchEncodeA "F" $ F valueList
68+ [ benchEncode "-" valueList
69+ , benchEncode "L" $ L valueList
70+ , benchEncode "F" $ F valueList
9271 ]
9372 , bgroup "Seq"
94− [ benchEncodeB "-" valueSeq
95− , benchEncodeB "L" $ L valueSeq
96− , benchEncodeB "F" $ F valueSeq
97− , benchEncodeA "-" valueSeq
98− , benchEncodeA "L" $ L valueSeq
99− , benchEncodeA "F" $ F valueSeq
73+ [ benchEncode "-" valueSeq
74+ , benchEncode "L" $ L valueSeq
75+ , benchEncode "F" $ F valueSeq
10076 ]
10177 , bgroup "Vector"
102− [ benchEncodeB "-" valueVector
103− , benchEncodeB "L" $ L valueVector
104− , benchEncodeB "F" $ F valueVector
105− , benchEncodeA "-" valueVector
106− , benchEncodeA "L" $ L valueVector
107− , benchEncodeA "F" $ F valueVector
78+ [ benchEncode "-" valueVector
79+ , benchEncode "L" $ L valueVector
80+ , benchEncode "F" $ F valueVector
10881 ]
10982 , bgroup "Vector.Unboxed"
110− [ benchEncodeB "-" valueUVector
111− , benchEncodeA "-" valueUVector
83+ [ benchEncode "-" valueUVector
11284 ]
11385 ]
11486 ]
benchmarks/AesonMap.hs+39−56
@@ -1,13 +1,11 @@
11{-# LANGUAGE FlexibleContexts #-}
2−{-# LANGUAGE OverloadedStrings #-}
3−{-# LANGUAGE PackageImports #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
43{-# LANGUAGE RankNTypes #-}
54
65{-# OPTIONS_GHC -fno-warn-orphans #-}
76
87module Main (main) where
98
10−import Prelude ()
119import Prelude.Compat
1210
1311import Control.DeepSeq
@@ -15,9 +13,8 @@ import Criterion.Main
1513import Data.Hashable
1614import Data.Proxy (Proxy (..))
1715import Data.Tagged (Tagged (..))
18−import qualified "aeson" Data.Aeson as A
19−import qualified "aeson-benchmarks" Data.Aeson as B
20−import qualified "aeson-benchmarks" Data.Aeson.Types as B (fromJSONKeyCoerce)
16+import Data.Aeson
17+import Data.Aeson.Types (fromJSONKeyCoerce)
2118import qualified Data.ByteString.Lazy as LBS
2219import qualified Data.HashMap.Strict as HM
2320import qualified Data.Map as M
@@ -47,10 +44,10 @@ instance NFData T1 where
4744instance Hashable T1 where
4845 hashWithSalt salt (T1 t) = hashWithSalt salt t
4946
50−instance B.FromJSON T1 where
51− parseJSON = B.withText "T1" $ pure . T1
52−instance B.FromJSONKey T1 where
53− fromJSONKey = B.FromJSONKeyText T1
47+instance FromJSON T1 where
48+ parseJSON = withText "T1" $ pure . T1
49+instance FromJSONKey T1 where
50+ fromJSONKey = FromJSONKeyText T1
5451
5552-------------------------------------------------------------------------------
5653-- Coerce
@@ -64,10 +61,10 @@ instance NFData T2 where
6461instance Hashable T2 where
6562 hashWithSalt salt (T2 t) = hashWithSalt salt t
6663
67−instance B.FromJSON T2 where
68− parseJSON = B.withText "T2" $ pure . T2
69−instance B.FromJSONKey T2 where
70− fromJSONKey = B.fromJSONKeyCoerce
64+instance FromJSON T2 where
65+ parseJSON = withText "T2" $ pure . T2
66+instance FromJSONKey T2 where
67+ fromJSONKey = fromJSONKeyCoerce
7168
7269-------------------------------------------------------------------------------
7370-- TextParser
@@ -81,10 +78,10 @@ instance NFData T3 where
8178instance Hashable T3 where
8279 hashWithSalt salt (T3 t) = hashWithSalt salt t
8380
84−instance B.FromJSON T3 where
85− parseJSON = B.withText "T3" $ pure . T3
86−instance B.FromJSONKey T3 where
87− fromJSONKey = B.FromJSONKeyTextParser (pure . T3)
81+instance FromJSON T3 where
82+ parseJSON = withText "T3" $ pure . T3
83+instance FromJSONKey T3 where
84+ fromJSONKey = FromJSONKeyTextParser (pure . T3)
8885
8986-------------------------------------------------------------------------------
9087-- Values
@@ -97,40 +94,30 @@ value1000 = value 1000
9794value10000 = value 10000
9895
9996encodedValue10 :: LBS.ByteString
100−encodedValue10 = B.encode $ value10
97+encodedValue10 = encode value10
10198
10299encodedValue100 :: LBS.ByteString
103−encodedValue100 = B.encode $ value100
100+encodedValue100 = encode value100
104101
105102encodedValue1000 :: LBS.ByteString
106−encodedValue1000 = B.encode $ value1000
103+encodedValue1000 = encode value1000
107104
108105encodedValue10000 :: LBS.ByteString
109−encodedValue10000 = B.encode $ value10000
106+encodedValue10000 = encode value10000
110107
111108-------------------------------------------------------------------------------
112109-- Helpers
113110-------------------------------------------------------------------------------
114111
115−decodeHMB
116− :: (B.FromJSONKey k, Eq k, Hashable k)
112+decodeHM
113+ :: (FromJSON (HM.HashMap k T.Text), Eq k, Hashable k)
117114 => Proxy k -> LBS.ByteString -> Maybe (HM.HashMap k T.Text)
118−decodeHMB _ = B.decode
115+decodeHM _ = decode
119116
120−decodeHMA
121− :: (A.FromJSON (HM.HashMap k T.Text), Eq k, Hashable k)
122− => Proxy k -> LBS.ByteString -> Maybe (HM.HashMap k T.Text)
123−decodeHMA _ = A.decode
124−
125−decodeMapB
126− :: (B.FromJSONKey k, Ord k)
127− => Proxy k -> LBS.ByteString -> Maybe (M.Map k T.Text)
128−decodeMapB _ = B.decode
129−
130−decodeMapA
131− :: (A.FromJSON (M.Map k T.Text), Ord k)
117+decodeMap
118+ :: (FromJSON (M.Map k T.Text), Ord k)
132119 => Proxy k -> LBS.ByteString -> Maybe (M.Map k T.Text)
133−decodeMapA _ = A.decode
120+decodeMap _ = decode
134121
135122proxyText :: Proxy T.Text
136123proxyText = Proxy
@@ -156,15 +143,14 @@ benchDecodeHM
156143 -> LBS.ByteString
157144 -> Benchmark
158145benchDecodeHM name val = bgroup name
159− [ bench "Text" $ nf (decodeHMB proxyText) val
160− , bench "Identity" $ nf (decodeHMB proxyT1) val
161− , bench "Coerce" $ nf (decodeHMB proxyT2) val
162− , bench "Parser" $ nf (decodeHMB proxyT3) val
163− , bench "aeson-0.11" $ nf (decodeHMA proxyText) val
164− , bench "Tagged Text" $ nf (decodeHMB $ proxyTagged proxyText) val
165− , bench "Tagged Identity" $ nf (decodeHMB $ proxyTagged proxyT1) val
166− , bench "Tagged Coerce" $ nf (decodeHMB $ proxyTagged proxyT2) val
167− , bench "Tagged Parser" $ nf (decodeHMB $ proxyTagged proxyT3) val
146+ [ bench "Text" $ nf (decodeHM proxyText) val
147+ , bench "Identity" $ nf (decodeHM proxyT1) val
148+ , bench "Coerce" $ nf (decodeHM proxyT2) val
149+ , bench "Parser" $ nf (decodeHM proxyT3) val
150+ , bench "Tagged Text" $ nf (decodeHM $ proxyTagged proxyText) val
151+ , bench "Tagged Identity" $ nf (decodeHM $ proxyTagged proxyT1) val
152+ , bench "Tagged Coerce" $ nf (decodeHM $ proxyTagged proxyT2) val
153+ , bench "Tagged Parser" $ nf (decodeHM $ proxyTagged proxyT3) val
168154 ]
169155
170156benchDecodeMap
@@ -172,11 +158,10 @@ benchDecodeMap
172158 -> LBS.ByteString
173159 -> Benchmark
174160benchDecodeMap name val = bgroup name
175− [ bench "Text" $ nf (decodeMapB proxyText) val
176− , bench "Identity" $ nf (decodeMapB proxyT1) val
177− , bench "Coerce" $ nf (decodeMapB proxyT2) val
178− , bench "Parser" $ nf (decodeMapB proxyT3) val
179− , bench "aeson-0.11" $ nf (decodeMapA proxyText) 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
180165 ]
181166
182167benchEncodeHM
@@ -184,8 +169,7 @@ benchEncodeHM
184169 -> HM.HashMap T.Text T.Text
185170 -> Benchmark
186171benchEncodeHM name val = bgroup name
187− [ bench "Text" $ nf B.encode val
188− , bench "aeson-0.11" $ nf A.encode val
172+ [ bench "Text" $ nf encode val
189173 ]
190174
191175benchEncodeMap
@@ -193,8 +177,7 @@ benchEncodeMap
193177 -> HM.HashMap T.Text T.Text
194178 -> Benchmark
195179benchEncodeMap name val = bgroup name
196− [ bench "Text" $ nf B.encode val'
197− , bench "aeson-0.11" $ nf A.encode val'
180+ [ bench "Text" $ nf encode val'
198181 ]
199182 where
200183 val' :: M.Map T.Text T.Text
benchmarks/AesonParse.hs+3−5
@@ -1,14 +1,12 @@
11{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
23{-# LANGUAGE OverloadedStrings #-}
3−{-# LANGUAGE PackageImports #-}
44
55module Main (main) where
66
7−import Prelude ()
87import Prelude.Compat
98
10−import "aeson-benchmarks" Data.Aeson
11−import Control.Exception
9+import Data.Aeson
1210import Control.Monad
1311import Data.Attoparsec.ByteString (IResult(..), parseWith)
1412import Data.Time.Clock
@@ -21,7 +19,7 @@ main = do
2119 (bs:cnt:args) <- getArgs
2220 let count = read cnt :: Int
2321 blkSize = read bs
24− forM_ args $ \arg -> bracket (openFile arg ReadMode) hClose $ \h -> do
22+ forM_ args $ \arg -> withFile arg ReadMode $ \h -> do
2523 putStrLn $ arg ++ ":"
2624 start <- getCurrentTime
2725 let loop !good !bad
benchmarks/AesonTuples.hs+1−2
@@ -1,8 +1,7 @@
1−module Main where
1+{-# LANGUAGE NoImplicitPrelude #-}
22
33module Main (main) where
44
5−import Prelude ()
65import Prelude.Compat
76
87import Control.DeepSeq (deepseq)
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+10−5
@@ -1,22 +1,25 @@
1−{-# LANGUAGE PackageImports #-}
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
23{-# LANGUAGE ScopedTypeVariables #-}
34
45module Main (main) where
56
6−import Prelude ()
77import Prelude.Compat
88
99import Compare.BufferBuilder ()
10−import Compare.JsonBuilder ()
1110import Criterion.Main
1211import Data.BufferBuilder.Json
13−import Data.Json.Builder
1412import Twitter
1513import Twitter.Manual ()
1614import Typed.Common
17−import qualified "aeson-benchmarks" Data.Aeson as Aeson
15+import qualified Data.Aeson as Aeson
1816import qualified Compare.JsonBench as JsonBench
1917
18+#ifdef MIN_VERSION_json_builder
19+import Data.Json.Builder
20+import Compare.JsonBuilder ()
21+#endif
22+
2023main :: IO ()
2124main =
2225 defaultMain [
@@ -24,7 +27,9 @@ main =
2427 bgroup "twitter" [
2528 bench "aeson" $ nf Aeson.encode twtr
2629 , bench "buffer-builder" $ nf encodeJson twtr
30+#ifdef MIN_VERSION_json_builder
2731 , bench "json-builder" $ nf toJsonLBS twtr
32+#endif
2833 ]
2934 , JsonBench.benchmarks
3035 ]
benchmarks/Compare/BufferBuilder.hs+2−3
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-# LANGUAGE RecordWildCards #-}
34
@@ -6,13 +7,11 @@
67
78module Compare.BufferBuilder () where
89
9−import Prelude ()
10−import Prelude.Compat
10+import Prelude.Compat hiding ((<>))
1111
1212import Data.BufferBuilder.Json
1313import Data.Int (Int64)
1414import Data.Monoid ((<>))
15−import Prelude hiding (id)
1615import Twitter
1716import qualified Data.BufferBuilder.Utf8 as UB
1817
benchmarks/Compare/JsonBench.hs+18−10
@@ -1,18 +1,18 @@
1−-- Adapted from a buffer-builder benchmark:
2−--
3−-- https://github.com/chadaustin/buffer-builder/blob/master/test.json
4−
1+{-# LANGUAGE CPP #-}
52{-# LANGUAGE BangPatterns #-}
6−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
73{-# LANGUAGE MagicHash #-}
4+{-# LANGUAGE NoImplicitPrelude #-}
85{-# LANGUAGE OverloadedStrings #-}
96{-# LANGUAGE RecordWildCards #-}
107{-# LANGUAGE ScopedTypeVariables #-}
118
9+-- Adapted from a buffer-builder benchmark:
10+--
11+-- https://github.com/chadaustin/buffer-builder/blob/master/test.json
12+
1213module Compare.JsonBench (benchmarks) where
1314
14−import Prelude ()
15−import Prelude.Compat
15+import Prelude.Compat hiding ((<>))
1616
1717import Control.DeepSeq (NFData(..))
1818import Criterion
@@ -20,9 +20,13 @@ import Data.Aeson ((.:))
2020import Data.Monoid ((<>))
2121import Data.Text (Text)
2222import Typed.Common (load)
23+import qualified Control.Monad.Fail as Fail
2324import qualified Data.Aeson as Aeson
2425import qualified Data.BufferBuilder.Json as Json
26+
27+#ifdef MIN_VERSION_json_builder
2528import qualified Data.Json.Builder as JB
29+#endif
2630
2731data EyeColor = Green | Blue | Brown
2832 deriving (Eq, Show)
@@ -65,10 +69,10 @@ instance NFData Gender where rnf !_ = ()
6569instance NFData Fruit where rnf !_ = ()
6670
6771instance NFData Friend where
68− rnf Friend {..} = (rnf fId) `seq` (rnf fName) `seq` ()
72+ rnf Friend {..} = rnf fId `seq` rnf fName
6973
7074instance NFData User where
71− 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
7276
7377eyeColorTable :: [(Text, EyeColor)]
7478eyeColorTable = [("brown", Brown), ("green", Green), ("blue", Blue)]
@@ -79,7 +83,7 @@ genderTable = [("male", Male), ("female", Female)]
7983fruitTable :: [(Text, Fruit)]
8084fruitTable = [("apple", Apple), ("strawberry", Strawberry), ("banana", Banana)]
8185
82−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
8387enumFromJson enumName table extract v = do
8488 s <- extract v
8589 case lookup s table of
@@ -269,6 +273,7 @@ instance Json.ToJson User where
269273 <> "greeting"# Json..=# uGreeting
270274 <> "favoriteFruit"# Json..=# uFavouriteFruit
271275
276+#ifdef MIN_VERSION_json_builder
272277---- json-builder instances ----
273278
274279instance JB.Value EyeColor where
@@ -320,6 +325,7 @@ instance JB.Value User where
320325 <> t "friends" `JB.row` uFriends
321326 <> t "greeting" `JB.row` uGreeting
322327 <> t "favoriteFruit" `JB.row` uFavouriteFruit
328+#endif
323329
324330benchmarks :: Benchmark
325331benchmarks = env (load "json-data/buffer-builder.json") $
@@ -327,5 +333,7 @@ benchmarks = env (load "json-data/buffer-builder.json") $
327333 bgroup "json-bench" [
328334 bench "aeson" $ nf Aeson.encode parsedUserList
329335 , bench "buffer-builder" $ nf Json.encodeJson parsedUserList
336+#ifdef MIN_VERSION_json_builder
330337 , bench "json-builder" $ nf JB.toJsonLBS parsedUserList
338+#endif
331339 ]
benchmarks/Compare/JsonBuilder.hs+2−3
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE RecordWildCards #-}
23
34{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
@@ -5,12 +6,10 @@
56
67module Compare.JsonBuilder () where
78
8−import Prelude ()
9−import Prelude.Compat
9+import Prelude.Compat hiding ((<>))
1010
1111import Data.Json.Builder
1212import Data.Monoid ((<>))
13−import Prelude hiding (id)
1413import Twitter
1514
1615instance JsObject Metadata where
benchmarks/CompareWithJSON.hs+33−21
@@ -1,16 +1,20 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
13{-# OPTIONS_GHC -fno-warn-orphans #-}
24
35module Main (main) where
46
5−import Prelude ()
67import Prelude.Compat
78
89import Blaze.ByteString.Builder (toLazyByteString)
910import Blaze.ByteString.Builder.Char.Utf8 (fromString)
1011import Control.DeepSeq (NFData(rnf))
1112import Criterion.Main
13+import Data.Maybe (fromMaybe)
1214import qualified Data.Aeson as A
1315import qualified Data.Aeson.Text as A
16+import qualified Data.Aeson.Parser.Internal as I
17+import qualified Data.ByteString as BS
1418import qualified Data.ByteString.Lazy as BL
1519import qualified Data.Text.Lazy as TL
1620import qualified Data.Text.Lazy.Builder as TLB
@@ -23,7 +27,7 @@ instance (NFData v) => NFData (J.JSObject v) where
2327instance NFData J.JSValue where
2428 rnf J.JSNull = ()
2529 rnf (J.JSBool b) = rnf b
26− rnf (J.JSRational a b) = rnf a `seq` rnf b `seq` ()
30+ rnf (J.JSRational a b) = rnf a `seq` rnf b
2731 rnf (J.JSString s) = rnf (J.fromJSString s)
2832 rnf (J.JSArray lst) = rnf lst
2933 rnf (J.JSObject o) = rnf o
@@ -34,15 +38,18 @@ decodeJ s =
3438 J.Ok v -> v
3539 J.Error _ -> error "fail to parse via JSON"
3640
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"
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
4149
42−decodeA' :: BL.ByteString -> A.Value
43−decodeA' s = case A.decode' s of
44− Just v -> v
45− 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
4653
4754encodeJ :: J.JSValue -> BL.ByteString
4855encodeJ = toLazyByteString . fromString . J.encode
@@ -58,32 +65,37 @@ main = do
5865 let enFile = "json-data/twitter100.json"
5966 jpFile = "json-data/jp100.json"
6067 enA <- BL.readFile enFile
68+ enS <- BS.readFile enFile
6169 enJ <- readFile enFile
6270 jpA <- BL.readFile jpFile
71+ jpS <- BS.readFile jpFile
6372 jpJ <- readFile jpFile
6473 defaultMain [
6574 bgroup "decode" [
6675 bgroup "en" [
67− bench "aeson/lazy" $ nf decodeA enA
68− , bench "aeson/strict" $ nf decodeA' enA
69− , 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
7081 ]
7182 , bgroup "jp" [
72− bench "aeson" $ nf decodeA jpA
73− , bench "json" $ nf decodeJ jpJ
83+ bench "aeson" $ nf decode jpA
84+ , bench "aeson/stricter" $ nf decodeS jpS
85+ , bench "json" $ nf decodeJ jpJ
7486 ]
7587 ]
7688 , bgroup "encode" [
7789 bgroup "en" [
78− bench "aeson-to-bytestring" $ nf A.encode (decodeA enA)
79− , bench "aeson-via-text-to-bytestring" $ nf encodeViaText (decodeA enA)
80− , 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)
8193 , bench "json" $ nf encodeJ (decodeJ enJ)
8294 ]
8395 , bgroup "jp" [
84− bench "aeson-to-bytestring" $ nf A.encode (decodeA jpA)
85− , bench "aeson-via-text-to-bytestring" $ nf encodeViaText (decodeA jpA)
86− , 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)
8799 , bench "json" $ nf encodeJ (decodeJ jpJ)
88100 ]
89101 ]
benchmarks/Dates.hs+10−9
@@ -1,6 +1,7 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
13module Main (main) where
24
3−import Prelude ()
45import Prelude.Compat
56
67import Criterion.Main
@@ -22,22 +23,22 @@ main = do
2223 defaultMain [
2324 bgroup "decode" [
2425 bgroup "UTCTime" [
25− env file1 $ \ ~bs -> bench "whole" $ nf utcTime bs
26− , 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
2728 ]
2829 , bgroup "ZonedTime" [
29− env file1 $ \ ~bs -> bench "whole" $ nf zTime bs
30− , 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
3132 ]
3233 ]
3334 , bgroup "encode" [
3435 bgroup "UTCTime" [
35− env (utcTime <$> file1) $ \ ~ts -> bench "whole" $ nf encode ts
36− , 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
3738 ]
3839 , bgroup "ZonedTime" [
39− env (zTime <$> file1) $ \ ~ts -> bench "whole" $ nf encode ts
40− , 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
4142 ]
4243 ]
4344 ]
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+3−2
@@ -1,10 +1,11 @@
11{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
23{-# LANGUAGE ScopedTypeVariables #-}
4+
35{-# OPTIONS_GHC -fno-warn-orphans #-}
46
57module Main (main) where
68
7−import Prelude ()
89import Prelude.Compat
910
1011import Control.DeepSeq
@@ -16,7 +17,7 @@ import Text.JSON
1617instance NFData JSValue where
1718 rnf JSNull = ()
1819 rnf (JSBool b) = rnf b
19− rnf (JSRational b r) = rnf b `seq` rnf r `seq` ()
20+ rnf (JSRational b r) = rnf b `seq` rnf r
2021 rnf (JSString s) = rnf (fromJSString s)
2122 rnf (JSArray vs) = rnf vs
2223 rnf (JSObject kvs) = rnf (fromJSObject kvs)
benchmarks/Micro.hs+8−6
@@ -1,11 +1,13 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
13module Main (main) where
24
3−import Prelude ()
45import Prelude.Compat
56
67import Criterion.Main
7−import qualified Data.Aeson.Encoding.Builder as AB
8−import qualified Data.ByteString.Builder as B
8+
9+-- Encoding is a newtype wrapper around Builder
10+import Data.Aeson.Encoding (text, string, encodingToLazyByteString)
911import qualified Data.Text as T
1012
1113main :: IO ()
@@ -13,8 +15,8 @@ main = do
1315 let txt = "append (append b (primBounded w1 x1)) (primBounded w2 x2)"
1416 defaultMain [
1517 bgroup "string" [
16− bench "text" $ nf (B.toLazyByteString . AB.text) (T.pack txt)
17− , bench "string direct" $ nf (B.toLazyByteString . AB.string) txt
18− , 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
1921 ]
2022 ]
benchmarks/Options.hs+1−4
@@ -1,7 +1,4 @@
1−module Options () where
2−
3−import Prelude ()
4−import Prelude.Compat
1+module Options (opts) where
52
63import Data.Aeson.Types
74
benchmarks/ReadFile.hs+2−2
@@ -1,9 +1,9 @@
11{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
23{-# LANGUAGE OverloadedStrings #-}
34
45module Main (main) where
56
6−import Prelude ()
77import Prelude.Compat
88
99import Control.DeepSeq
@@ -20,7 +20,7 @@ import qualified Data.ByteString as B
2020main = do
2121 (cnt:args) <- getArgs
2222 let count = read cnt :: Int
23− forM_ args $ \arg -> bracket (openFile arg ReadMode) hClose $ \h -> do
23+ forM_ args $ \arg -> withFile arg ReadMode $ \h -> do
2424 putStrLn $ arg ++ ":"
2525 start <- getCurrentTime
2626 let loop !n
benchmarks/Typed.hs+5−1
@@ -1,6 +1,7 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
13module Main (main) where
24
3−import Prelude ()
45import Prelude.Compat
56
67import Criterion.Main
@@ -13,4 +14,7 @@ main = defaultMain [
1314 Generic.benchmarks
1415 , Manual.benchmarks
1516 , TH.benchmarks
17+ , Generic.decodeBenchmarks
18+ , Manual.decodeBenchmarks
19+ , TH.decodeBenchmarks
1620 ]
benchmarks/Typed/Common.hs+1−8
@@ -1,23 +1,16 @@
1−{-# LANGUAGE CPP #-}
2−{-# LANGUAGE PackageImports #-}
1+{-# LANGUAGE NoImplicitPrelude #-}
32
43{-# OPTIONS_GHC -fno-warn-unused-imports #-}
54
65module Typed.Common (load) where
76
8−import Prelude ()
97import Prelude.Compat
108
119import Data.ByteString.Lazy as L
1210import System.Exit
1311import System.IO
1412
15−#ifndef HAS_BOTH_AESON_AND_BENCHMARKS
1613import Data.Aeson hiding (Result)
17−#else
18−import "aeson" Data.Aeson hiding (Result)
19−import qualified "aeson-benchmarks" Data.Aeson as B
20−#endif
2114
2215load :: FromJSON a => FilePath -> IO a
2316load fileName = do
benchmarks/Typed/Generic.hs+27−25
@@ -1,42 +1,44 @@
1−{-# LANGUAGE PackageImports #-}
2−module Typed.Generic (benchmarks) where
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
3+module Typed.Generic (benchmarks, decodeBenchmarks) where
34
4−import Prelude ()
55import Prelude.Compat
66
7−import "aeson" Data.Aeson hiding (Result)
7+import Data.Aeson hiding (Result)
88import Criterion
99import Data.ByteString.Lazy as L
10−import Twitter.TH
10+import Twitter.Generic
1111import Typed.Common
12−import qualified "aeson-benchmarks" Data.Aeson as B
13−
14−encodeDirectA :: Result -> L.ByteString
15−encodeDirectA = encode
1612
17−encodeViaValueA :: Result -> L.ByteString
18−encodeViaValueA = encode . toJSON
13+encodeDirect :: Result -> L.ByteString
14+encodeDirect = encode
1915
20−encodeDirectB :: Result -> L.ByteString
21−encodeDirectB = B.encode
22−
23−encodeViaValueB :: Result -> L.ByteString
24−encodeViaValueB = B.encode . B.toJSON
16+encodeViaValue :: Result -> L.ByteString
17+encodeViaValue = encode . toJSON
2518
2619benchmarks :: Benchmark
2720benchmarks =
2821 env ((,) <$> load "json-data/twitter100.json" <*> load "json-data/jp100.json") $ \ ~(twitter100, jp100) ->
29− bgroup "generic" [
22+ bgroup "encodeGeneric" [
3023 bgroup "direct" [
31− bench "twitter100" $ nf encodeDirectB twitter100
32− , bench "jp100" $ nf encodeDirectB jp100
33− , bench "twitter100 baseline" $ nf encodeDirectA twitter100
34− , bench "jp100 baseline" $ nf encodeDirectA jp100
24+ bench "twitter100" $ nf encodeDirect twitter100
25+ , bench "jp100" $ nf encodeDirect jp100
3526 ]
3627 , bgroup "viaValue" [
37− bench "twitter100" $ nf encodeViaValueB twitter100
38− , bench "jp100" $ nf encodeViaValueB jp100
39− , bench "twitter100 baseline" $ nf encodeViaValueA twitter100
40− , bench "jp100 baseline" $ nf encodeViaValueA jp100
28+ bench "twitter100" $ nf encodeViaValue twitter100
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
4143 ]
4244 ]
benchmarks/Typed/Manual.hs+26−24
@@ -1,42 +1,44 @@
1−{-# LANGUAGE PackageImports #-}
2−module Typed.Manual (benchmarks) where
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
3+module Typed.Manual (benchmarks, decodeBenchmarks) where
34
4−import Prelude ()
55import Prelude.Compat
66
7−import "aeson" Data.Aeson hiding (Result)
7+import Data.Aeson hiding (Result)
88import Criterion
99import Data.ByteString.Lazy as L
1010import Twitter.Manual
1111import Typed.Common
12−import qualified "aeson-benchmarks" Data.Aeson as B
13−
14−encodeDirectA :: Result -> L.ByteString
15−encodeDirectA = encode
1612
17−encodeViaValueA :: Result -> L.ByteString
18−encodeViaValueA = encode . toJSON
13+encodeDirect :: Result -> L.ByteString
14+encodeDirect = encode
1915
20−encodeDirectB :: Result -> L.ByteString
21−encodeDirectB = B.encode
22−
23−encodeViaValueB :: Result -> L.ByteString
24−encodeViaValueB = B.encode . B.toJSON
16+encodeViaValue :: Result -> L.ByteString
17+encodeViaValue = encode . toJSON
2518
2619benchmarks :: Benchmark
2720benchmarks =
2821 env ((,) <$> load "json-data/twitter100.json" <*> load "json-data/jp100.json") $ \ ~(twitter100, jp100) ->
29− bgroup "manual" [
22+ bgroup "encodeManual" [
3023 bgroup "direct" [
31− bench "twitter100" $ nf encodeDirectB twitter100
32− , bench "jp100" $ nf encodeDirectB jp100
33− , bench "twitter100 baseline" $ nf encodeDirectA twitter100
34− , bench "jp100 baseline" $ nf encodeDirectA jp100
24+ bench "twitter100" $ nf encodeDirect twitter100
25+ , bench "jp100" $ nf encodeDirect jp100
3526 ]
3627 , bgroup "viaValue" [
37− bench "twitter100" $ nf encodeViaValueB twitter100
38− , bench "jp100" $ nf encodeViaValueB jp100
39− , bench "twitter100 baseline" $ nf encodeViaValueA twitter100
40− , bench "jp100 baseline" $ nf encodeViaValueA jp100
28+ bench "twitter100" $ nf encodeViaValue twitter100
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
4143 ]
4244 ]
benchmarks/Typed/TH.hs+26−24
@@ -1,42 +1,44 @@
1−{-# LANGUAGE PackageImports #-}
2−module Typed.TH (benchmarks) where
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
3+module Typed.TH (benchmarks, decodeBenchmarks) where
34
4−import Prelude ()
55import Prelude.Compat
66
7−import "aeson" Data.Aeson hiding (Result)
7+import Data.Aeson hiding (Result)
88import Criterion
99import Data.ByteString.Lazy as L
1010import Twitter.TH
1111import Typed.Common
12−import qualified "aeson-benchmarks" Data.Aeson as B
13−
14−encodeDirectA :: Result -> L.ByteString
15−encodeDirectA = encode
1612
17−encodeViaValueA :: Result -> L.ByteString
18−encodeViaValueA = encode . toJSON
13+encodeDirect :: Result -> L.ByteString
14+encodeDirect = encode
1915
20−encodeDirectB :: Result -> L.ByteString
21−encodeDirectB = B.encode
22−
23−encodeViaValueB :: Result -> L.ByteString
24−encodeViaValueB = B.encode . B.toJSON
16+encodeViaValue :: Result -> L.ByteString
17+encodeViaValue = encode . toJSON
2518
2619benchmarks :: Benchmark
2720benchmarks =
2821 env ((,) <$> load "json-data/twitter100.json" <*> load "json-data/jp100.json") $ \ ~(twitter100, jp100) ->
29− bgroup "th" [
22+ bgroup "encodeTH" [
3023 bgroup "direct" [
31− bench "twitter100" $ nf encodeDirectB twitter100
32− , bench "jp100" $ nf encodeDirectB jp100
33− , bench "twitter100 baseline" $ nf encodeDirectA twitter100
34− , bench "jp100 baseline" $ nf encodeDirectA jp100
24+ bench "twitter100" $ nf encodeDirect twitter100
25+ , bench "jp100" $ nf encodeDirect jp100
3526 ]
3627 , bgroup "viaValue" [
37− bench "twitter100" $ nf encodeViaValueA twitter100
38− , bench "jp100" $ nf encodeViaValueA jp100
39− , bench "twitter100 baseline" $ nf encodeViaValueB twitter100
40− , bench "jp100 baseline" $ nf encodeViaValueB jp100
28+ bench "twitter100" $ nf encodeViaValue twitter100
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
4143 ]
4244 ]
benchmarks/aeson-benchmarks.cabal+183−62
@@ -1,60 +1,21 @@
11name: aeson-benchmarks
22version: 0
33build-type: Simple
4−
5−cabal-version: >=1.8
4+cabal-version: >=1.10
65
76flag bytestring-builder
87 description: Depend on the bytestring-builder package for backwards compatibility.
98 default: False
109 manual: False
1110
12−library
13− hs-source-dirs: .. .
14−
15− exposed-modules:
16− Data.Aeson
17− Data.Aeson.Encoding
18− Data.Aeson.Parser
19− Data.Aeson.Text
20− Data.Aeson.Types
21− Data.Aeson.TH
22−
23− Data.Aeson.Encoding.Internal
24− Data.Aeson.Internal
25− Data.Aeson.Internal.Time
26−
27− Data.Aeson.Encoding.Builder
28− Data.Aeson.Internal.Functions
29− Data.Aeson.Parser.Internal
30− Data.Aeson.Parser.Time
31− Data.Aeson.Types.FromJSON
32− Data.Aeson.Types.Generic
33− Data.Aeson.Types.ToJSON
34− Data.Aeson.Types.Class
35− Data.Aeson.Types.Internal
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
3616
37− build-depends:
38− attoparsec >= 0.13.0.1,
39− base == 4.*,
40− base-compat >= 0.9.1 && <0.10,
41− time-locale-compat >=0.1.1 && <0.2,
42− containers,
43− deepseq,
44− dlist >= 0.2,
45− fail == 4.9.*,
46− ghc-prim >= 0.2,
47− hashable >= 1.1.2.0,
48− mtl,
49− scientific >= 0.3.4.7 && < 0.4,
50− syb,
51− tagged >=0.8.3 && <0.9,
52− template-haskell >= 2.4,
53− text >= 1.1.1.0,
54− time,
55− transformers,
56− unordered-containers >= 0.2.3.0,
57− vector >= 0.7.1
17+library
18+ default-language: Haskell2010
5819
5920 if flag(bytestring-builder)
6021 build-depends: bytestring >= 0.9 && < 0.10.4,
@@ -62,22 +23,142 @@ library
6223 else
6324 build-depends: bytestring >= 0.10.4
6425
65− if impl(ghc >=7.8)
66− cpp-options: -DHAS_COERCIBLE
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
6762
68− if !impl(ghc >= 8.0)
69− -- `Data.Semigroup` is available in base only since GHC 8.0 / base 4.9
70− build-depends: semigroups >= 0.18.2 && < 0.19
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
7167
72− include-dirs: ../include
68+ include-dirs: ../include
7369
74− ghc-options: -O2 -Wall
75− cpp-options: -DGENERICS
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
99+
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
125+ build-depends:
126+ aeson-benchmarks,
127+ base,
128+ criterion,
129+ deepseq,
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
76150
77151executable aeson-benchmark-compare
152+ default-language: Haskell2010
78153 main-is: Compare.hs
79154 hs-source-dirs: ../examples .
80155 ghc-options: -Wall -O2 -rtsopts
156+ other-modules:
157+ Compare.BufferBuilder
158+ Compare.JsonBench
159+ Twitter
160+ Twitter.Manual
161+ Typed.Common
81162 build-depends:
82163 aeson-benchmarks,
83164 base,
@@ -87,10 +168,19 @@ executable aeson-benchmark-compare
87168 criterion >= 1.0,
88169 deepseq,
89170 ghc-prim,
90− json-builder,
91171 text
92172
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+
93182executable aeson-benchmark-micro
183+ default-language: Haskell2010
94184 main-is: Micro.hs
95185 hs-source-dirs: ../examples .
96186 ghc-options: -Wall -O2 -rtsopts
@@ -105,14 +195,21 @@ executable aeson-benchmark-micro
105195 text
106196
107197executable aeson-benchmark-typed
198+ default-language: Haskell2010
108199 main-is: Typed.hs
109200 hs-source-dirs: ../examples .
110201 ghc-options: -Wall -O2 -rtsopts
111− -- We must help ourself in situations when there is both
112− -- aeson and aeson-benchmakrs
113− cpp-options: -DHAS_BOTH_AESON_AND_BENCHMARKS
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
114212 build-depends:
115− aeson,
116213 aeson-benchmarks,
117214 base,
118215 base-compat,
@@ -127,8 +224,11 @@ executable aeson-benchmark-typed
127224 bytestring-builder >= 0.10.4 && < 1
128225 else
129226 build-depends: bytestring >= 0.10.4
227+ if impl(ghc < 8.0)
228+ build-depends: semigroups
130229
131230executable aeson-benchmark-compare-with-json
231+ default-language: Haskell2010
132232 main-is: CompareWithJSON.hs
133233 ghc-options: -Wall -O2 -rtsopts
134234 build-depends:
@@ -143,6 +243,7 @@ executable aeson-benchmark-compare-with-json
143243 text
144244
145245executable aeson-benchmark-aeson-encode
246+ default-language: Haskell2010
146247 main-is: AesonEncode.hs
147248 ghc-options: -Wall -O2 -rtsopts
148249 build-depends:
@@ -155,6 +256,7 @@ executable aeson-benchmark-aeson-encode
155256 time
156257
157258executable aeson-benchmark-aeson-parse
259+ default-language: Haskell2010
158260 main-is: AesonParse.hs
159261 ghc-options: -Wall -O2 -rtsopts
160262 build-depends:
@@ -166,6 +268,7 @@ executable aeson-benchmark-aeson-parse
166268 time
167269
168270executable aeson-benchmark-json-parse
271+ default-language: Haskell2010
169272 main-is: JsonParse.hs
170273 ghc-options: -Wall -O2 -rtsopts
171274 build-depends:
@@ -176,6 +279,7 @@ executable aeson-benchmark-json-parse
176279 time
177280
178281executable aeson-benchmark-dates
282+ default-language: Haskell2010
179283 main-is: Dates.hs
180284 ghc-options: -Wall -O2 -rtsopts
181285 build-depends:
@@ -187,12 +291,14 @@ executable aeson-benchmark-dates
187291 aeson-benchmarks,
188292 text,
189293 time
294+ if impl(ghc >= 8.2)
295+ ghc-options: -Wno-simplifiable-class-constraints
190296
191297executable aeson-benchmark-map
298+ default-language: Haskell2010
192299 main-is: AesonMap.hs
193300 ghc-options: -Wall -O2 -rtsopts
194301 build-depends:
195− aeson,
196302 aeson-benchmarks,
197303 base,
198304 base-compat,
@@ -206,10 +312,10 @@ executable aeson-benchmark-map
206312 unordered-containers
207313
208314executable aeson-benchmark-foldable
315+ default-language: Haskell2010
209316 main-is: AesonFoldable.hs
210317 ghc-options: -Wall -O2 -rtsopts
211318 build-depends:
212− aeson,
213319 aeson-benchmarks,
214320 base,
215321 base-compat,
@@ -222,3 +328,18 @@ executable aeson-benchmark-foldable
222328 text,
223329 unordered-containers,
224330 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+257−1
@@ -1,11 +1,267 @@
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
5259Major enhancements:
6260
7261* Introduced new `FromJSONKey` and `ToJSONKey` type classes that are
8− used to encode maps without going through HashMap
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.
9265
10266* Added higher rank classes: `ToJSON1`, `ToJSON2`, `FromJSON1`, and
11267 `FromJSON2`.
examples/Generic.hs+1−1
@@ -6,11 +6,11 @@
66-- automatically derive the Generic class for us.
77
88{-# LANGUAGE DeriveGeneric #-}
9+{-# LANGUAGE NoImplicitPrelude #-}
910{-# LANGUAGE OverloadedStrings #-}
1011
1112module Main (main) where
1213
13−import Prelude ()
1414import Prelude.Compat
1515
1616import Data.Aeson (FromJSON, ToJSON, decode, encode)
examples/Simplest.hs+1−1
@@ -1,9 +1,9 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-# LANGUAGE RecordWildCards #-}
34
45module Main (main) where
56
6−import Prelude ()
77import Prelude.Compat
88
99import Control.Applicative (empty)
examples/TemplateHaskell.hs+1−1
@@ -1,12 +1,12 @@
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+{-# LANGUAGE NoImplicitPrelude #-}
45{-# LANGUAGE OverloadedStrings #-}
56{-# LANGUAGE TemplateHaskell #-}
67
78module Main (main) where
89
9−import Prelude ()
1010import Prelude.Compat
1111
1212import Data.Aeson (decode, encode)
examples/Twitter.hs+4−2
@@ -10,6 +10,7 @@
1010
1111{-# LANGUAGE DeriveDataTypeable #-}
1212{-# LANGUAGE DeriveGeneric #-}
13+{-# LANGUAGE NoImplicitPrelude #-}
1314
1415module Twitter
1516 (
@@ -19,7 +20,6 @@ module Twitter
1920 , Result(..)
2021 ) where
2122
22−import Prelude ()
2323import Prelude.Compat
2424
2525import Control.DeepSeq
@@ -27,7 +27,9 @@ import Data.Data (Typeable, Data)
2727import Data.Int (Int64)
2828import Data.Text (Text)
2929import GHC.Generics (Generic)
30−import Prelude hiding (id)
30+
31+{-# ANN module "Hlint: ignore Use camelCase" #-}
32+{-# ANN module "Hlint: ignore Use newtype instead of data" #-}
3133
3234data Metadata = Metadata {
3335 result_type :: Text
examples/Twitter/Generic.hs+31−37
@@ -1,6 +1,7 @@
11-- Use GHC generics to automatically generate good instances.
2−{-# LANGUAGE CPP #-}
3−{-# LANGUAGE PackageImports #-}
2+
3+{-# LANGUAGE NoImplicitPrelude #-}
4+
45{-# OPTIONS_GHC -fno-warn-orphans #-}
56
67module Twitter.Generic
@@ -11,40 +12,33 @@ module Twitter.Generic
1112 , Result(..)
1213 ) where
1314
14−import Prelude ()
15−import Prelude.Compat
15+import Prelude.Compat ()
1616
1717import Twitter
18−
19−#ifndef HAS_BOTH_AESON_AND_BENCHMARKS
20−import Data.Aeson (ToJSON, FromJSON)
21−#else
22−import "aeson" Data.Aeson (ToJSON, FromJSON)
23−import qualified "aeson-benchmarks" Data.Aeson as B
24−#endif
25−
26−instance ToJSON Metadata
27−instance FromJSON Metadata
28−
29−instance ToJSON Geo
30−instance FromJSON Geo
31−
32−instance ToJSON Story
33−instance FromJSON Story
34−
35−instance ToJSON Result
36−instance FromJSON Result
37−
38−#ifdef HAS_BOTH_AESON_AND_BENCHMARKS
39−instance B.ToJSON Metadata
40−instance B.FromJSON Metadata
41−
42−instance B.ToJSON Geo
43−instance B.FromJSON Geo
44−
45−instance B.ToJSON Story
46−instance B.FromJSON Story
47−
48−instance B.ToJSON Result
49−instance B.FromJSON Result
50−#endif
18+import Twitter.Options
19+
20+import Data.Aeson (ToJSON (..), FromJSON (..), genericToJSON, genericToEncoding, genericParseJSON)
21+
22+instance ToJSON Metadata where
23+ toJSON = genericToJSON twitterOptions
24+ toEncoding = genericToEncoding twitterOptions
25+instance FromJSON Metadata where
26+ parseJSON = genericParseJSON twitterOptions
27+
28+instance ToJSON Geo where
29+ toJSON = genericToJSON twitterOptions
30+ toEncoding = genericToEncoding twitterOptions
31+instance FromJSON Geo where
32+ parseJSON = genericParseJSON twitterOptions
33+
34+instance ToJSON Story where
35+ toJSON = genericToJSON twitterOptions
36+ toEncoding = genericToEncoding twitterOptions
37+instance FromJSON Story where
38+ parseJSON = genericParseJSON twitterOptions
39+
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+3−136
@@ -1,9 +1,8 @@
11-- Manually write instances.
2−
3−{-# LANGUAGE CPP #-}
4−{-# LANGUAGE PackageImports #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
53{-# LANGUAGE OverloadedStrings #-}
64{-# LANGUAGE RecordWildCards #-}
5+
76{-# OPTIONS_GHC -fno-warn-orphans #-}
87
98module Twitter.Manual
@@ -14,20 +13,13 @@ module Twitter.Manual
1413 , Result(..)
1514 ) where
1615
17−import Prelude ()
1816import Prelude.Compat
1917
2018import Control.Applicative
21−import Data.Monoid ((<>))
22−import Prelude hiding (id)
19+import Data.Semigroup ((<>))
2320import Twitter
2421
25−#ifndef HAS_BOTH_AESON_AND_BENCHMARKS
2622import Data.Aeson hiding (Result)
27−#else
28−import "aeson" Data.Aeson hiding (Result)
29−import qualified "aeson-benchmarks" Data.Aeson as B
30−#endif
3123
3224instance ToJSON Metadata where
3325
@@ -152,128 +144,3 @@ instance FromJSON Result where
152144 <*> v .: "max_id_str"
153145 <*> v .: "query"
154146 parseJSON _ = empty
155−
156−#ifdef HAS_BOTH_AESON_AND_BENCHMARKS
157−instance B.ToJSON Metadata where
158− toJSON Metadata{..} = B.object [
159− "result_type" B..= result_type
160− ]
161−
162− toEncoding Metadata{..} = B.pairs $
163− "result_type" B..= result_type
164−
165−instance B.FromJSON Metadata where
166− parseJSON (B.Object v) = Metadata <$> v B..: "result_type"
167− parseJSON _ = empty
168−
169−instance B.ToJSON Geo where
170− toJSON Geo{..} = B.object [
171− "type_" B..= type_
172− , "coordinates" B..= coordinates
173− ]
174−
175− toEncoding Geo{..} = B.pairs $
176− "type_" B..= type_
177− <> "coordinates" B..= coordinates
178−
179−instance B.FromJSON Geo where
180− parseJSON (B.Object v) = Geo <$>
181− v B..: "type_"
182− <*> v B..: "coordinates"
183− parseJSON _ = empty
184−
185−instance B.ToJSON Story where
186− toJSON Story{..} = B.object [
187− "from_user_id_str" B..= from_user_id_str
188− , "profile_image_url" B..= profile_image_url
189− , "created_at" B..= created_at
190− , "from_user" B..= from_user
191− , "id_str" B..= id_str
192− , "metadata" B..= metadata
193− , "to_user_id" B..= to_user_id
194− , "text" B..= text
195− , "id" B..= id_
196− , "from_user_id" B..= from_user_id
197− , "geo" B..= geo
198− , "iso_language_code" B..= iso_language_code
199− , "to_user_id_str" B..= to_user_id_str
200− , "source" B..= source
201− ]
202−
203− toEncoding Story{..} = B.pairs $
204− "from_user_id_str" B..= from_user_id_str
205− <> "profile_image_url" B..= profile_image_url
206− <> "created_at" B..= created_at
207− <> "from_user" B..= from_user
208− <> "id_str" B..= id_str
209− <> "metadata" B..= metadata
210− <> "to_user_id" B..= to_user_id
211− <> "text" B..= text
212− <> "id" B..= id_
213− <> "from_user_id" B..= from_user_id
214− <> "geo" B..= geo
215− <> "iso_language_code" B..= iso_language_code
216− <> "to_user_id_str" B..= to_user_id_str
217− <> "source" B..= source
218−
219−instance B.FromJSON Story where
220− parseJSON (B.Object v) = Story <$>
221− v B..: "from_user_id_str"
222− <*> v B..: "profile_image_url"
223− <*> v B..: "created_at"
224− <*> v B..: "from_user"
225− <*> v B..: "id_str"
226− <*> v B..: "metadata"
227− <*> v B..: "to_user_id"
228− <*> v B..: "text"
229− <*> v B..: "id"
230− <*> v B..: "from_user_id"
231− <*> v B..: "geo"
232− <*> v B..: "iso_language_code"
233− <*> v B..: "to_user_id_str"
234− <*> v B..: "source"
235− parseJSON _ = empty
236−
237−instance B.ToJSON Result where
238− toJSON Result{..} = B.object [
239− "results" B..= results
240− , "max_id" B..= max_id
241− , "since_id" B..= since_id
242− , "refresh_url" B..= refresh_url
243− , "next_page" B..= next_page
244− , "results_per_page" B..= results_per_page
245− , "page" B..= page
246− , "completed_in" B..= completed_in
247− , "since_id_str" B..= since_id_str
248− , "max_id_str" B..= max_id_str
249− , "query" B..= query
250− ]
251−
252− toEncoding Result{..} = B.pairs $
253− "results" B..= results
254− <> "max_id" B..= max_id
255− <> "since_id" B..= since_id
256− <> "refresh_url" B..= refresh_url
257− <> "next_page" B..= next_page
258− <> "results_per_page" B..= results_per_page
259− <> "page" B..= page
260− <> "completed_in" B..= completed_in
261− <> "since_id_str" B..= since_id_str
262− <> "max_id_str" B..= max_id_str
263− <> "query" B..= query
264−
265−instance B.FromJSON Result where
266− parseJSON (B.Object v) = Result <$>
267− v B..: "results"
268− <*> v B..: "max_id"
269− <*> v B..: "since_id"
270− <*> v B..: "refresh_url"
271− <*> v B..: "next_page"
272− <*> v B..: "results_per_page"
273− <*> v B..: "page"
274− <*> v B..: "completed_in"
275− <*> v B..: "since_id_str"
276− <*> v B..: "max_id_str"
277− <*> v B..: "query"
278− parseJSON _ = empty
279−#endif
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+7−19
@@ -1,8 +1,8 @@
11-- Use Template Haskell to generate good instances.
22
3−{-# LANGUAGE CPP #-}
4−{-# LANGUAGE PackageImports #-}
3+{-# LANGUAGE NoImplicitPrelude #-}
54{-# LANGUAGE TemplateHaskell #-}
5+
66{-# OPTIONS_GHC -fno-warn-orphans #-}
77
88module Twitter.TH
@@ -13,25 +13,13 @@ module Twitter.TH
1313 , Result(..)
1414 ) where
1515
16−import Prelude ()
1716
1817import Twitter
18+import Twitter.Options
1919
20−#ifndef HAS_BOTH_AESON_AND_BENCHMARKS
2120import Data.Aeson.TH
22−#else
23−import "aeson" Data.Aeson.TH
24−import qualified "aeson-benchmarks" Data.Aeson.TH as B
25−#endif
26−
27−$(deriveJSON defaultOptions ''Metadata)
28−$(deriveJSON defaultOptions ''Geo)
29−$(deriveJSON defaultOptions ''Story)
30−$(deriveJSON defaultOptions ''Result)
3121
32−#ifdef HAS_BOTH_AESON_AND_BENCHMARKS
33−$(B.deriveJSON B.defaultOptions ''Metadata)
34−$(B.deriveJSON B.defaultOptions ''Geo)
35−$(B.deriveJSON B.defaultOptions ''Story)
36−$(B.deriveJSON B.defaultOptions ''Result)
37−#endif
22+$(deriveJSON twitterOptions ''Metadata)
23+$(deriveJSON twitterOptions ''Geo)
24+$(deriveJSON twitterOptions ''Story)
25+$(deriveJSON twitterOptions ''Result)
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
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.yaml+10−6
@@ -1,8 +1,12 @@
1−resolver: lts-6.5
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
210packages:
311- benchmarks
4−extra-deps:
5−- semigroups-0.18.2
6−flags:
7− semigroups:
8− bytestring-builder: false
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-lts6.yamldeleted−12
@@ -1,12 +0,0 @@
1−resolver: lts-6.9
2−packages:
3−- '.'
4−- benchmarks
5−- examples
6−extra-deps:
7−- semigroups-0.18.2
8−flags:
9− aeson:
10− fast: true
11− semigroups:
12− bytestring-builder: false
stack-nightly.yaml+6−7
@@ -1,12 +1,11 @@
1−resolver: nightly-2016-07-30
1+resolver: nightly-2019-10-14
22packages:
33- '.'
4−- benchmarks
5−- examples
6−extra-deps:
7−- buffer-builder-0.2.4.3
8−- json-0.9.1
9−- json-builder-0.3
4+- attoparsec-iso8601
105flags:
116 aeson:
127 fast: true
8+ attoparsec-iso8601:
9+ fast: true
10+extra-deps:
11+- generic-deriving-1.12.4
tests/DataFamilies/Encoders.hs+2−2
@@ -1,10 +1,10 @@
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
67
7−import Prelude ()
88import Prelude.Compat
99
1010import Data.Aeson.TH
tests/DataFamilies/Instances.hs+2−1
@@ -1,12 +1,13 @@
11{-# LANGUAGE FlexibleInstances #-}
22{-# LANGUAGE GADTs #-}
3+{-# LANGUAGE NoImplicitPrelude #-}
34{-# LANGUAGE TemplateHaskell #-}
45{-# LANGUAGE TypeFamilies #-}
6+
57{-# OPTIONS_GHC -fno-warn-orphans #-}
68
79module DataFamilies.Instances () where
810
9−import Prelude ()
1011import Prelude.Compat
1112
1213import Data.Aeson.TH
tests/DataFamilies/Properties.hs+6−5
@@ -1,20 +1,21 @@
11{-# LANGUAGE CPP #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
23
34module DataFamilies.Properties (tests) where
45
5−import Prelude ()
66import Prelude.Compat
77
88import DataFamilies.Encoders
99import DataFamilies.Instances ()
10−import Properties hiding (tests)
10+import PropUtils
1111
12−import Test.Framework (Test, testGroup)
13−import Test.Framework.Providers.QuickCheck2 (testProperty)
12+
13+import Test.Tasty (TestTree, testGroup)
14+import Test.Tasty.QuickCheck (testProperty)
1415
1516--------------------------------------------------------------------------------
1617
17−tests :: Test
18+tests :: TestTree
1819tests = testGroup "data families" [
1920 testGroup "template-haskell" [
2021 testGroup "toJSON" [
tests/DataFamilies/Types.hs+2−2
@@ -4,13 +4,13 @@
44{-# LANGUAGE FlexibleInstances #-}
55{-# LANGUAGE GADTs #-}
66{-# LANGUAGE GeneralizedNewtypeDeriving #-}
7+{-# LANGUAGE NoImplicitPrelude #-}
78{-# LANGUAGE StandaloneDeriving #-}
89{-# LANGUAGE TemplateHaskell #-}
910{-# LANGUAGE TypeFamilies #-}
1011
11−module DataFamilies.Types where
12+module DataFamilies.Types (module DataFamilies.Types) where
1213
13−import Prelude ()
1414import Prelude.Compat
1515
1616import Generics.Deriving.TH (deriveAll0)
tests/Encoders.hs+142−8
@@ -1,11 +1,12 @@
11{-# LANGUAGE CPP #-}
22{-# LANGUAGE GADTs #-}
3+{-# LANGUAGE NoImplicitPrelude #-}
34{-# LANGUAGE TemplateHaskell #-}
45
5−module Encoders where
6+module Encoders (module Encoders) where
67
7−import Prelude ()
88import Prelude.Compat
9+import Data.Text (Text)
910
1011import Data.Aeson.TH
1112import Data.Aeson.Types
@@ -96,6 +97,18 @@ gNullaryToEncodingObjectWithSingleField = genericToEncoding optsObjectWithSingle
9697gNullaryParseJSONObjectWithSingleField :: Value -> Parser Nullary
9798gNullaryParseJSONObjectWithSingleField = genericParseJSON optsObjectWithSingleField
9899
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"
99112
100113--------------------------------------------------------------------------------
101114-- SomeType encoders/decoders
@@ -175,7 +188,6 @@ gSomeTypeToEncoding2ElemArray = genericToEncoding opts2ElemArray
175188gSomeTypeParseJSON2ElemArray :: Value -> Parser (SomeType Int)
176189gSomeTypeParseJSON2ElemArray = genericParseJSON opts2ElemArray
177190
178−#if __GLASGOW_HASKELL__ >= 706
179191gSomeTypeLiftToEncoding2ElemArray :: LiftToEncoding SomeType a
180192gSomeTypeLiftToEncoding2ElemArray = genericLiftToEncoding opts2ElemArray
181193
@@ -184,7 +196,6 @@ gSomeTypeLiftToJSON2ElemArray = genericLiftToJSON opts2ElemArray
184196
185197gSomeTypeLiftParseJSON2ElemArray :: LiftParseJSON SomeType a
186198gSomeTypeLiftParseJSON2ElemArray = genericLiftParseJSON opts2ElemArray
187−#endif
188199
189200
190201gSomeTypeToJSONTaggedObject :: SomeType Int -> Value
@@ -196,7 +207,6 @@ gSomeTypeToEncodingTaggedObject = genericToEncoding optsTaggedObject
196207gSomeTypeParseJSONTaggedObject :: Value -> Parser (SomeType Int)
197208gSomeTypeParseJSONTaggedObject = genericParseJSON optsTaggedObject
198209
199−#if __GLASGOW_HASKELL__ >= 706
200210gSomeTypeLiftToEncodingTaggedObject :: LiftToEncoding SomeType a
201211gSomeTypeLiftToEncodingTaggedObject = genericLiftToEncoding optsTaggedObject
202212
@@ -205,7 +215,6 @@ gSomeTypeLiftToJSONTaggedObject = genericLiftToJSON optsTaggedObject
205215
206216gSomeTypeLiftParseJSONTaggedObject :: LiftParseJSON SomeType a
207217gSomeTypeLiftParseJSONTaggedObject = genericLiftParseJSON optsTaggedObject
208−#endif
209218
210219
211220gSomeTypeToJSONObjectWithSingleField :: SomeType Int -> Value
@@ -217,7 +226,6 @@ gSomeTypeToEncodingObjectWithSingleField = genericToEncoding optsObjectWithSingl
217226gSomeTypeParseJSONObjectWithSingleField :: Value -> Parser (SomeType Int)
218227gSomeTypeParseJSONObjectWithSingleField = genericParseJSON optsObjectWithSingleField
219228
220−#if __GLASGOW_HASKELL__ >= 706
221229gSomeTypeLiftToEncodingObjectWithSingleField :: LiftToEncoding SomeType a
222230gSomeTypeLiftToEncodingObjectWithSingleField = genericLiftToEncoding optsObjectWithSingleField
223231
@@ -226,7 +234,6 @@ gSomeTypeLiftToJSONObjectWithSingleField = genericLiftToJSON optsObjectWithSingl
226234
227235gSomeTypeLiftParseJSONObjectWithSingleField :: LiftParseJSON SomeType a
228236gSomeTypeLiftParseJSONObjectWithSingleField = genericLiftParseJSON optsObjectWithSingleField
229−#endif
230237
231238
232239gSomeTypeToJSONOmitNothingFields :: SomeType Int -> Value
@@ -235,6 +242,82 @@ gSomeTypeToJSONOmitNothingFields = genericToJSON optsOmitNothingFields
235242gSomeTypeToEncodingOmitNothingFields :: SomeType Int -> Encoding
236243gSomeTypeToEncodingOmitNothingFields = genericToEncoding optsOmitNothingFields
237244
245+
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+
238321-------------------------------------------------------------------------------
239322-- EitherTextInt encoders/decodes
240323-------------------------------------------------------------------------------
@@ -322,3 +405,54 @@ thGADTToEncodingDefault = $(mkToEncoding defaultOptions ''GADT)
322405
323406thGADTParseJSONDefault :: Value -> Parser (GADT String)
324407thGADTParseJSONDefault = $(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+2−1
@@ -1,10 +1,11 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
13module Functions
24 (
35 approxEq
46 , approxEqWith
57 ) where
68
7−import Prelude ()
89import Prelude.Compat
910
1011approxEq :: (Fractional a, Ord a) => a -> a -> Bool
tests/Instances.hs+9−55
@@ -1,48 +1,35 @@
1−{-# LANGUAGE CPP #-}
21{-# LANGUAGE FlexibleContexts #-}
32{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE NoImplicitPrelude #-}
44{-# LANGUAGE OverloadedStrings #-}
55{-# LANGUAGE RecordWildCards #-}
6−{-# LANGUAGE StandaloneDeriving #-}
6+
77{-# OPTIONS_GHC -fno-warn-orphans #-}
88
99module Instances () where
1010
11−import Prelude ()
1211import Prelude.Compat
1312
14−import Control.Applicative (Const(..), empty)
13+import Control.Applicative (empty)
1514import Control.Monad
1615import Data.Aeson.Types
1716import Data.Function (on)
18−import Data.Functor.Compose (Compose (..))
19−import Data.Functor.Identity (Identity (..))
20−import Data.List.NonEmpty (NonEmpty(..))
21−import Data.Proxy (Proxy(..))
22−import Data.Tagged (Tagged(..))
2317import Data.Time (ZonedTime(..), TimeZone(..))
2418import Data.Time.Clock (UTCTime(..))
25−import Data.Version
2619import Functions
27−import Test.QuickCheck (Arbitrary(..), getNonNegative, elements, listOf1, oneof, resize)
20+import Test.QuickCheck (Arbitrary(..), elements, oneof)
2821import Types
2922import qualified Data.DList as DList
3023import qualified Data.HashMap.Strict as HM
3124
3225import Data.Orphans ()
3326import Test.QuickCheck.Instances ()
34−#if MIN_VERSION_base(4,7,0)
3527import Data.Hashable.Time ()
36−#endif
37−
38−#if !MIN_VERSION_base(4,8,0) && !MIN_VERSION_QuickCheck(2,8,3)
39−import Numeric.Natural
40−#endif
4128
4229-- "System" types.
4330
4431instance Arbitrary DotNetTime where
45− arbitrary = DotNetTime `liftM` arbitrary
32+ arbitrary = DotNetTime `fmap` arbitrary
4633 shrink = map DotNetTime . shrink . fromDotNetTime
4734
4835-- | Compare timezone part only on 'timeZoneMinutes'
@@ -166,48 +153,15 @@ instance Arbitrary EitherTextInt where
166153instance Arbitrary (GADT String) where
167154 arbitrary = GADT <$> arbitrary
168155
156+instance Arbitrary OptionField where
157+ arbitrary = OptionField <$> arbitrary
158+
159+
169160instance ApproxEq Char where
170161 (=~) = (==)
171162
172163instance (ApproxEq a) => ApproxEq [a] where
173164 a =~ b = length a == length b && all (uncurry (=~)) (zip a b)
174165
175−instance Arbitrary Version where
176− arbitrary = makeVersion . fmap getNonNegative <$> resize 4 (listOf1 arbitrary)
177−
178−instance Arbitrary a => Arbitrary (NonEmpty a) where
179− arbitrary = (:|) <$> arbitrary <*> arbitrary
180−
181−-- Version tags are deprecated, so we avoid using them in the Arbitrary
182−-- instance. However, the recommended constructor 'makeVersion' is not
183−-- exported by "Data.Version" until base-4.8.0.0. For previous versions,
184−-- a definition is given below.
185−
186−#if !MIN_VERSION_base(4,8,0)
187−makeVersion :: [Int] -> Version
188−makeVersion b = Version b []
189−#endif
190−
191−#if !MIN_VERSION_base(4,8,0) && !MIN_VERSION_QuickCheck(2,8,3)
192−instance Arbitrary Natural where
193− arbitrary = fromInteger . abs <$> arbitrary
194−#endif
195−
196−instance Arbitrary (Proxy a) where
197− arbitrary = pure Proxy
198−
199−instance Arbitrary b => Arbitrary (Tagged a b) where
200− arbitrary = Tagged <$> arbitrary
201−
202−instance Arbitrary a => Arbitrary (Const a b) where
203− arbitrary = Const <$> arbitrary
204−
205166instance Arbitrary a => Arbitrary (DList.DList a) where
206167 arbitrary = DList.fromList <$> arbitrary
207−
208−-- would like to have -- https://github.com/nick8325/quickcheck/issues/73
209−instance Arbitrary a => Arbitrary (Identity a) where
210− arbitrary = Identity <$> arbitrary
211−
212−instance Arbitrary (f (g a)) => Arbitrary (Compose f g a) where
213− arbitrary = Compose <$> 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
@@ -0,0 +1,54 @@
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 `Data`.
10+ /// - returns: A byte-stream containing the `JSON` ready for wire transfer.
11+ /// - throws: Errors that arise from `JSONSerialization`.
12+ /// - see: Foundation.JSONSerialization
13+ public func serialize() throws -> Data {
14+ return try JSONSerialization.data(withJSONObject: toJSONSerializationValue(), options: [])
15+ }
16+
17+ /// Attempt to serialize `JSON` into a `String`.
18+ /// - returns: A `String` containing the `JSON`.
19+ /// - throws: A `JSON.Error.StringSerializationError` or errors that arise from `JSONSerialization`.
20+ /// - see: Foundation.JSONSerialization
21+ public func serializeString() throws -> String {
22+ let data = try self.serialize()
23+ guard let json = String(data: data, encoding: String.Encoding.utf8) else {
24+ throw Error.stringSerializationError
25+ }
26+ return json
27+ }
28+
29+ /// A function to help with the serialization of `JSON`.
30+ /// - returns: An `Any` suitable for `JSONSerialization`'s use.
31+ private func toJSONSerializationValue() -> Any {
32+ switch self {
33+ case .array(let jsonArray):
34+ return jsonArray.map { $0.toJSONSerializationValue() }
35+ case .dictionary(let jsonDictionary):
36+ var cocoaDictionary = Swift.Dictionary<Swift.String, Any>(minimumCapacity: jsonDictionary.count)
37+ for (key, json) in jsonDictionary {
38+ cocoaDictionary[key] = json.toJSONSerializationValue()
39+ }
40+ return cocoaDictionary
41+ case .string(let str):
42+ return str
43+ case .double(let num):
44+ return NSNumber(value: num)
45+ case .int(let int):
46+ return NSNumber(value: int)
47+ case .bool(let b):
48+ return NSNumber(value: b)
49+ case .null:
50+ return NSNull()
51+ }
52+
53+ }
54+}
tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/JSONSubscripting.swiftnew file+613
@@ -0,0 +1,613 @@
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 value(in dictionary: [String : JSON]) throws -> JSON
23+
24+ /// Use `self` to index into an `array`.
25+ ///
26+ /// Unlike Swift arrays, 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 value(in 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 value(in dictionary: [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 value(in 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 value(in dictionary: [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 value(in 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: Swift.Error {
86+ case subscriptIntoNull(JSONPathType)
87+ }
88+
89+ func value(for pathFragment: JSONPathType, detectingNull: Bool) throws -> JSON {
90+ switch self {
91+ case .null where detectingNull:
92+ throw SubscriptError.subscriptIntoNull(pathFragment)
93+ case let .dictionary(dict):
94+ return try pathFragment.value(in: dict)
95+ case let .array(array):
96+ return try pathFragment.value(in: array)
97+ default:
98+ throw Error.unexpectedSubscript(type: type(of: pathFragment))
99+ }
100+ }
101+
102+ func value(at path: [JSONPathType], detectingNull: Bool = false) throws -> JSON {
103+ var result = self
104+ for pathFragment in path {
105+ result = try result.value(for: pathFragment, detectingNull: detectingNull)
106+ }
107+ return result
108+ }
109+
110+}
111+
112+// MARK: - Subscripting operator
113+
114+extension JSON {
115+
116+ public subscript(key: String) -> JSON? {
117+ return try? value(for: key, detectingNull: false)
118+ }
119+
120+ public subscript(index: Int) -> JSON? {
121+ return try? value(for: index, detectingNull: 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>(at path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> Decoded {
146+ return try Decoded(json: value(at: 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(at:type:)`.
153+ /// - seealso: `JSON.decode(at:type:)`
154+ public func getDouble(at path: JSONPathType...) throws -> Double {
155+ return try Double(json: value(at: 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(at:type:)`.
162+ /// - seealso: `JSON.decode(at:type:)`
163+ public func getInt(at path: JSONPathType...) throws -> Int {
164+ return try Int(json: value(at: 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(at:type:)`.
171+ /// - seealso: `JSON.decode(at:type:)`
172+ public func getString(at path: JSONPathType...) throws -> String {
173+ return try String(json: value(at: 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(at:type:)`.
180+ /// - seealso: `JSON.decode(at:type:)`
181+ public func getBool(at path: JSONPathType...) throws -> Bool {
182+ return try Bool(json: value(at: 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(at:type:)`.
189+ /// - seealso: `JSON.decode(at:type:)`
190+ public func getArray(at path: JSONPathType...) throws -> [JSON] {
191+ return try JSON.getArray(from: value(at: 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(at:type:)`, or
202+ /// any error that arises from decoding the contained values.
203+ /// - seealso: `JSON.decode(at:type:)`
204+ public func decodedArray<Decoded: JSONDecodable>(at path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> [Decoded] {
205+ return try JSON.decodedArray(from: value(at: 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(at:type:)`.
212+ /// - seealso: `JSON.decode(at:type:)`
213+ public func getDictionary(at path: JSONPathType...) throws -> [String: JSON] {
214+ return try JSON.getDictionary(from: value(at: 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(at:type:)` or
225+ /// any error that arises from decoding the contained values.
226+ /// - seealso: `JSON.decode(at:type:)`
227+ public func decodedDictionary<Decoded: JSONDecodable>(at path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> [String: Decoded] {
228+ return try JSON.decodedDictionary(from: value(at: 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: OptionSet {
241+ public let rawValue: Int
242+ public init(rawValue: 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+ fileprivate func mapOptional<Value>(at path: [JSONPathType], alongPath options: SubscriptingOptions, transform: (JSON) throws -> Value) throws -> Value? {
253+ let detectNull = options.contains(.NullBecomesNil)
254+ let detectNotFound = options.contains(.MissingKeyBecomesNil)
255+ var json: JSON?
256+ do {
257+ json = try value(at: path, detectingNull: 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+ /// Decodes a `JSON` instance if it is not `.Null`, throws otherwise.
274+ /// - parameter json: An instance of `JSON`.
275+ /// - returns: An instance of some type that conforms to `JSONDecodable`.
276+ /// - throws: `Error.ValueNotConvertible` if the `JSON` instance is `.Null`.
277+ private static func getDecoded<Decoded: JSONDecodable>(json: JSON) throws -> Decoded {
278+ guard json != .null else {
279+ throw Error.valueNotConvertible(value: json, to: Decoded.self)
280+ }
281+ return try Decoded.init(json: json)
282+ }
283+
284+ /// Optionally decodes into the returning type from a path into JSON.
285+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
286+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
287+ /// - parameter type: If the context this method is called from does not
288+ /// make the return type clear, pass a type implementing `JSONDecodable`
289+ /// to disambiguate the type to decode with.
290+ /// - returns: A decoded value from the inner JSON if found, or `nil`.
291+ /// - throws: One of the following errors contained in `JSON.Error`:
292+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
293+ /// `JSON` dictionary.
294+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
295+ /// descendant `JSON` array.
296+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
297+ /// corresponding `JSON` value.
298+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
299+ /// instance does not match the decoded value.
300+ /// * Any error that arises from decoding the value.
301+ public func decode<Decoded: JSONDecodable>(at path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> Decoded? {
302+ return try mapOptional(at: path, alongPath: options, transform: JSON.getDecoded)
303+ }
304+
305+ /// Optionally retrieves a `Double` from a path into JSON.
306+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`.
307+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
308+ /// - returns: A `Double` if a value could be found, otherwise `nil`.
309+ /// - throws: One of the following errors contained in `JSON.Error`:
310+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
311+ /// `JSON` dictionary.
312+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
313+ /// descendant `JSON` array.
314+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
315+ /// corresponding `JSON` value.
316+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
317+ /// instance does not match the decoded value.
318+ public func getDouble(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Double? {
319+ return try mapOptional(at: path, alongPath: options, transform: Double.init)
320+ }
321+
322+ /// Optionally retrieves a `Int` from a path into JSON.
323+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
324+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
325+ /// - returns: A numeric `Int` if a value could be found, otherwise `nil`.
326+ /// - throws: One of the following errors contained in `JSON.Error`:
327+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
328+ /// `JSON` dictionary.
329+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
330+ /// descendant `JSON` array.
331+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
332+ /// corresponding `JSON` value.
333+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
334+ /// instance does not match the decoded value.
335+ public func getInt(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Int? {
336+ return try mapOptional(at: path, alongPath: options, transform: Int.init)
337+ }
338+
339+ /// Optionally retrieves a `String` from a path into JSON.
340+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
341+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
342+ /// - returns: A text `String` if a value could be found, otherwise `nil`.
343+ /// - throws: One of the following errors contained in `JSON.Error`:
344+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
345+ /// `JSON` dictionary.
346+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
347+ /// descendant `JSON` array.
348+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
349+ /// corresponding `JSON` value.
350+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
351+ /// instance does not match the decoded value.
352+ public func getString(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> String? {
353+ return try mapOptional(at: path, alongPath: options, transform: String.init)
354+ }
355+
356+ /// Optionally retrieves a `Bool` from a path into JSON.
357+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
358+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
359+ /// - returns: A truthy `Bool` if a value could be found, otherwise `nil`.
360+ /// - throws: One of the following errors contained in `JSON.Error`:
361+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
362+ /// `JSON` dictionary.
363+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
364+ /// descendant `JSON` array.
365+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
366+ /// corresponding `JSON` value.
367+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
368+ /// instance does not match the decoded value.
369+ public func getBool(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Bool? {
370+ return try mapOptional(at: path, alongPath: options, transform: Bool.init)
371+ }
372+
373+ /// Optionally retrieves a `[JSON]` from a path into the recieving structure.
374+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
375+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
376+ /// - returns: An `Array` of `JSON` elements if a value could be found,
377+ /// otherwise `nil`.
378+ /// - throws: One of the following errors contained in `JSON.Error`:
379+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
380+ /// `JSON` dictionary.
381+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
382+ /// descendant `JSON` array.
383+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
384+ /// corresponding `JSON` value.
385+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
386+ /// instance does not match the decoded value.
387+ public func getArray(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> [JSON]? {
388+ return try mapOptional(at: path, alongPath: options, transform: JSON.getArray)
389+ }
390+
391+ /// Optionally decodes many values from a descendant array at a path into
392+ /// JSON.
393+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
394+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
395+ /// - parameter type: If the context this method is called from does not
396+ /// make the return type clear, pass a type implementing `JSONDecodable`
397+ /// to disambiguate the value type to decode with.
398+ /// - returns: An `Array` of decoded elements if found, otherwise `nil`.
399+ /// - throws: One of the following errors contained in `JSON.Error`:
400+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
401+ /// `JSON` dictionary.
402+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
403+ /// descendant `JSON` array.
404+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
405+ /// corresponding `JSON` value.
406+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
407+ /// instance does not match the decoded value.
408+ /// * Any error that arises from decoding the value.
409+ public func decodedArray<Decoded: JSONDecodable>(at path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> [Decoded]? {
410+ return try mapOptional(at: path, alongPath: options, transform: JSON.decodedArray)
411+ }
412+
413+ /// Optionally retrieves a `[String: JSON]` from a path into the recieving
414+ /// structure.
415+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
416+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
417+ /// - returns: A `Dictionary` of `String` mapping to `JSON` elements if a
418+ /// value could be found, otherwise `nil`.
419+ /// - throws: One of the following errors contained in `JSON.Error`:
420+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
421+ /// `JSON` dictionary.
422+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
423+ /// descendant `JSON` array.
424+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
425+ /// corresponding `JSON` value.
426+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
427+ /// instance does not match the decoded value.
428+ public func getDictionary(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> [String: JSON]? {
429+ return try mapOptional(at: path, alongPath: options, transform: JSON.getDictionary)
430+ }
431+
432+ /// Optionally attempts to decode many values from a descendant object at a path
433+ /// into JSON.
434+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
435+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
436+ /// - parameter type: If the context this method is called from does not
437+ /// make the return type clear, pass a type implementing `JSONDecodable`
438+ /// to disambiguate the value type to decode with.
439+ /// - returns: A `Dictionary` of `String` mapping to decoded elements if a
440+ /// value could be found, otherwise `nil`.
441+ /// - throws: One of the following errors contained in `JSON.Error`:
442+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
443+ /// `JSON` dictionary.
444+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
445+ /// descendant `JSON` array.
446+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
447+ /// corresponding `JSON` value.
448+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
449+ /// instance does not match the decoded value.
450+ /// * Any error that arises from decoding the value.
451+ public func decodedDictionary<Decoded: JSONDecodable>(at path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> [String: Decoded]? {
452+ return try mapOptional(at: path, alongPath: options, transform: JSON.decodedDictionary)
453+ }
454+
455+}
456+
457+// MARK: - Missing-with-fallback unpacking
458+
459+extension JSON {
460+
461+ fileprivate func mapOptional<Value>(at path: [JSONPathType], fallback: () -> Value, transform: (JSON) throws -> Value) throws -> Value {
462+ return try mapOptional(at: path, alongPath: .MissingKeyBecomesNil, transform: transform) ?? fallback()
463+ }
464+
465+ /// Attempts to decode into the returning type from a path into
466+ /// JSON, or returns a fallback if not found.
467+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
468+ /// - parameter fallback: Value to use when one is missing at the subscript.
469+ /// - returns: An initialized member from the inner JSON.
470+ /// - throws: One of the following errors contained in `JSON.Error`:
471+ /// * `UnexpectedSubscript`: A given subscript cannot be used with the
472+ /// corresponding `JSON` value.
473+ /// * `TypeNotConvertible`: The target value's type inside of
474+ /// the `JSON` instance does not match `Decoded`.
475+ public func decode<Decoded: JSONDecodable>(at path: JSONPathType..., or fallback: @autoclosure() -> Decoded) throws -> Decoded {
476+ return try mapOptional(at: path, fallback: fallback, transform: Decoded.init)
477+ }
478+
479+ /// Retrieves a `Double` from a path into JSON or a fallback if not found.
480+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
481+ /// - parameter fallback: `Double` to use when one is missing at the subscript.
482+ /// - returns: A floating-point `Double`
483+ /// - throws: One of the `JSON.Error` cases thrown by calling `mapOptional(at:fallback:transform:)`.
484+ public func getDouble(at path: JSONPathType..., or fallback: @autoclosure() -> Double) throws -> Double {
485+ return try mapOptional(at: path, fallback: fallback, transform: Double.init)
486+ }
487+
488+ /// Retrieves an `Int` from a path into JSON or a fallback if not found.
489+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
490+ /// - parameter fallback: `Int` to use when one is missing at the subscript.
491+ /// - returns: A numeric `Int`
492+ /// - throws: One of the following errors contained in `JSON.Error`:
493+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
494+ /// `JSON` dictionary.
495+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
496+ /// descendant `JSON` array.
497+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
498+ /// corresponding `JSON` value.
499+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
500+ /// instance does not match the decoded value.
501+ public func getInt(at path: JSONPathType..., or fallback: @autoclosure() -> Int) throws -> Int {
502+ return try mapOptional(at: path, fallback: fallback, transform: Int.init)
503+ }
504+
505+ /// Retrieves a `String` from a path into JSON or a fallback if not found.
506+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
507+ /// - parameter fallback: `String` to use when one is missing at the subscript.
508+ /// - returns: A textual `String`
509+ /// - throws: One of the following errors contained in `JSON.Error`:
510+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
511+ /// `JSON` dictionary.
512+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
513+ /// descendant `JSON` array.
514+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
515+ /// corresponding `JSON` value.
516+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
517+ /// instance does not match the decoded value.
518+ public func getString(at path: JSONPathType..., or fallback: @autoclosure() -> String) throws -> String {
519+ return try mapOptional(at: path, fallback: fallback, transform: String.init)
520+ }
521+
522+ /// Retrieves a `Bool` from a path into JSON or a fallback if not found.
523+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
524+ /// - parameter fallback: `Bool` to use when one is missing at the subscript.
525+ /// - returns: A truthy `Bool`
526+ /// - throws: One of the following errors contained in `JSON.Error`:
527+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
528+ /// `JSON` dictionary.
529+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
530+ /// descendant `JSON` array.
531+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
532+ /// corresponding `JSON` value.
533+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
534+ /// instance does not match the decoded value.
535+ public func getBool(at path: JSONPathType..., or fallback: @autoclosure() -> Bool) throws -> Bool {
536+ return try mapOptional(at: path, fallback: fallback, transform: Bool.init)
537+ }
538+
539+ /// Retrieves a `[JSON]` from a path into JSON or a fallback if not found.
540+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
541+ /// - parameter fallback: `Array` to use when one is missing at the subscript.
542+ /// - returns: An `Array` of `JSON` elements
543+ /// - throws: One of the following errors contained in `JSON.Error`:
544+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
545+ /// `JSON` dictionary.
546+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
547+ /// descendant `JSON` array.
548+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
549+ /// corresponding `JSON` value.
550+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
551+ /// instance does not match the decoded value.
552+ public func getArray(at path: JSONPathType..., or fallback: @autoclosure() -> [JSON]) throws -> [JSON] {
553+ return try mapOptional(at: path, fallback: fallback, transform: JSON.getArray)
554+ }
555+
556+ /// Attempts to decodes many values from a desendant JSON array at a path
557+ /// into the recieving structure, returning a fallback if not found.
558+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
559+ /// - parameter fallback: `Array` to use when one is missing at the subscript.
560+ /// - returns: An `Array` of decoded elements
561+ /// - throws: One of the following errors contained in `JSON.Error`:
562+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
563+ /// `JSON` dictionary.
564+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
565+ /// descendant `JSON` array.
566+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
567+ /// corresponding `JSON` value.
568+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
569+ /// instance does not match the decoded value.
570+ /// * Any error that arises from decoding the value.
571+ public func decodedArray<Decoded: JSONDecodable>(at path: JSONPathType..., or fallback: @autoclosure() -> [Decoded]) throws -> [Decoded] {
572+ return try mapOptional(at: path, fallback: fallback, transform: JSON.decodedArray)
573+ }
574+
575+ /// Retrieves a `[String: JSON]` from a path into JSON or a fallback if not
576+ /// found.
577+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
578+ /// - parameter fallback: `Dictionary` to use when one is missing at the subscript.
579+ /// - returns: An `Dictionary` of `String` mapping to `JSON` elements
580+ /// - throws: One of the following errors contained in `JSON.Error`:
581+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
582+ /// `JSON` dictionary.
583+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
584+ /// descendant `JSON` array.
585+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
586+ /// corresponding `JSON` value.
587+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
588+ /// instance does not match the decoded value.
589+ public func getDictionary(at path: JSONPathType..., or fallback: @autoclosure() -> [String: JSON]) throws -> [String: JSON] {
590+ return try mapOptional(at: path, fallback: fallback, transform: JSON.getDictionary)
591+ }
592+
593+ /// Attempts to decode many values from a descendant JSON object at a path
594+ /// into the receiving structure, returning a fallback if not found.
595+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
596+ /// - parameter fallback: Value to use when one is missing at the subscript
597+ /// - returns: A `Dictionary` of `String` mapping to decoded elements.
598+ /// - throws: One of the following errors contained in `JSON.Error`:
599+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
600+ /// `JSON` dictionary.
601+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
602+ /// descendant `JSON` array.
603+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
604+ /// corresponding `JSON` value.
605+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
606+ /// instance does not match the decoded value.
607+ /// * Any error that arises from decoding the value.
608+ public func decodedDictionary<Decoded: JSONDecodable>(at path: JSONPathType..., or fallback: @autoclosure() -> [String: Decoded]) throws -> [String: Decoded] {
609+ return try mapOptional(at: path, fallback: fallback, transform: JSON.decodedDictionary)
610+ }
611+
612+
613+}
tests/JSONTestSuite/parsers/test_Freddy_20161018/test_Freddy/main.swiftnew file+40
@@ -0,0 +1,40 @@
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 ProcessInfo.processInfo.arguments.count == 2 else {
14+ let url = URL(fileURLWithPath: ProcessInfo.processInfo.arguments[0])
15+ let programName = url.lastPathComponent
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+ do {
26+ let o = try JSONParser.parse(utf8: data)
27+ exit(0)
28+ } catch {
29+ exit(1)
30+ }
31+
32+ } catch let e {
33+ print("*** CANNOT READ DATA AT \(url)")
34+ print(e)
35+ exit(1)
36+ }
37+
38+}
39+
40+main()
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
@@ -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_2_1_0/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_2_1_0/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_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
@@ -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_2_1_0/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_2_1_0/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_2_1_0/test_Freddy/JSONDecodable.swiftnew file+151
@@ -0,0 +1,151 @@
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+ guard case let .String(string) = json else {
71+ throw JSON.Error.ValueNotConvertible(value: json, to: Swift.String)
72+ }
73+ self = string
74+ }
75+
76+}
77+
78+extension Bool: JSONDecodable {
79+
80+ /// An initializer to create an instance of `Bool` from a `JSON` value.
81+ /// - parameter json: An instance of `JSON`.
82+ /// - throws: The initializer will throw an instance of `JSON.Error` if
83+ /// an instance of `Bool` cannot be created from the `JSON` value that was
84+ /// passed to this initializer.
85+ public init(json: JSON) throws {
86+ guard case let .Bool(bool) = json else {
87+ throw JSON.Error.ValueNotConvertible(value: json, to: Swift.Bool)
88+ }
89+ self = bool
90+ }
91+
92+}
93+
94+extension RawRepresentable where RawValue: JSONDecodable {
95+
96+ /// An initializer to create an instance of `RawRepresentable` from a `JSON` value.
97+ /// - parameter json: An instance of `JSON`.
98+ /// - throws: The initializer will throw an instance of `JSON.Error` if
99+ /// an instance of `RawRepresentable` cannot be created from the `JSON` value that was
100+ /// passed to this initializer.
101+ public init(json: JSON) throws {
102+ let raw = try json.decode(type: RawValue.self)
103+ guard let value = Self(rawValue: raw) else {
104+ throw JSON.Error.ValueNotConvertible(value: json, to: Self.self)
105+ }
106+ self = value
107+ }
108+}
109+
110+internal extension JSON {
111+
112+ /// Retrieves a `[JSON]` from the JSON.
113+ /// - returns: An `Array` of `JSON` elements
114+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`.
115+ /// - seealso: `JSON.decode(_:type:)`
116+ static func getArray(json: JSON) throws -> [JSON] {
117+ // Ideally should be expressed as a conditional protocol implementation on Swift.Array.
118+ guard case let .Array(array) = json else {
119+ throw Error.ValueNotConvertible(value: json, to: Swift.Array<JSON>)
120+ }
121+ return array
122+ }
123+
124+ /// Retrieves a `[String: JSON]` from the JSON.
125+ /// - returns: An `Dictionary` of `String` mapping to `JSON` elements
126+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`.
127+ /// - seealso: `JSON.decode(_:type:)`
128+ static func getDictionary(json: JSON) throws -> [Swift.String: JSON] {
129+ // Ideally should be expressed as a conditional protocol implementation on Swift.Dictionary.
130+ guard case let .Dictionary(dictionary) = json else {
131+ throw Error.ValueNotConvertible(value: json, to: Swift.Dictionary<Swift.String, JSON>)
132+ }
133+ return dictionary
134+ }
135+
136+ /// Attempts to decode many values from a descendant JSON array at a path
137+ /// into JSON.
138+ /// - parameter type: If the context this method is called from does not
139+ /// make the return type clear, pass a type implementing `JSONDecodable`
140+ /// to disambiguate the type to decode with.
141+ /// - returns: An `Array` of decoded elements
142+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`, as
143+ /// well as any error that arises from decoding the contained values.
144+ /// - seealso: `JSON.decode(_:type:)`
145+ static func getArrayOf<Decoded: JSONDecodable>(json: JSON) throws -> [Decoded] {
146+ // Ideally should be expressed as a conditional protocol implementation on Swift.Dictionary.
147+ // This implementation also doesn't do the `type = Type.self` trick.
148+ return try getArray(json).map(Decoded.init)
149+ }
150+
151+}
tests/JSONTestSuite/parsers/test_Freddy_2_1_0/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_2_1_0/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_2_1_0/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_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+26−2

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−444

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+5−3

This diff is too big to show here.

tests/Types.hs+70−5

This diff is too big to show here.

tests/UnitTests.hs+424−240

This diff is too big to show here.

tests/UnitTests/NullaryConstructors.hs+8−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.