diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-05-15 21:44:38 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-05-15 21:44:38 -0700 |
| commit | 597082adf45cebbf2c6a81c3f732b6d2ce4a1435 (patch) | |
| tree | 9309977e204cceaac2c18efbea2153a69f86d1f4 /lib/std/json.zig | |
| parent | 07606d12daabe8c201dba3d5b27e702ce58d0ffb (diff) | |
| parent | d98e39fa6864f287bc50f265f98b7195849afa68 (diff) | |
| download | zig-597082adf45cebbf2c6a81c3f732b6d2ce4a1435.tar.gz zig-597082adf45cebbf2c6a81c3f732b6d2ce4a1435.zip | |
Merge remote-tracking branch 'origin/master' into stage2-whole-file-astgen
Conflicts:
* build.zig
* src/Compilation.zig
* src/codegen/spirv/spec.zig
* src/link/SpirV.zig
* test/stage2/darwin.zig
- this one might be problematic; start.zig looks for `main` in the
root source file, not `_main`. Not sure why there is an underscore
there in master branch.
Diffstat (limited to 'lib/std/json.zig')
| -rw-r--r-- | lib/std/json.zig | 55 |
1 files changed, 45 insertions, 10 deletions
diff --git a/lib/std/json.zig b/lib/std/json.zig index 109167bbc1..56d379f9f8 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -623,7 +623,7 @@ pub const StreamingParser = struct { .ObjectSeparator => switch (c) { ':' => { - p.state = .ValueBegin; + p.state = .ValueBeginNoClosing; p.after_string_state = .ValueEnd; }, 0x09, 0x0A, 0x0D, 0x20 => { @@ -1205,6 +1205,13 @@ test "json.token mismatched close" { try testing.expectError(error.UnexpectedClosingBrace, p.next()); } +test "json.token premature object close" { + var p = TokenStream.init("{ \"key\": }"); + try checkNext(&p, .ObjectBegin); + try checkNext(&p, .String); + try testing.expectError(error.InvalidValueBegin, p.next()); +} + /// Validate a JSON string. This does not limit number precision so a decoder may not necessarily /// be able to decode the string even if this returns true. pub fn validate(s: []const u8) bool { @@ -1566,11 +1573,16 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options: // .UseLast => {}, // } if (options.duplicate_field_behavior == .UseFirst) { + // unconditonally ignore value. for comptime fields, this skips check against default_value + parseFree(field.field_type, try parse(field.field_type, tokens, options), options); + found = true; break; } else if (options.duplicate_field_behavior == .Error) { return error.DuplicateJSONField; } else if (options.duplicate_field_behavior == .UseLast) { - parseFree(field.field_type, @field(r, field.name), options); + if (!field.is_comptime) { + parseFree(field.field_type, @field(r, field.name), options); + } fields_seen[i] = false; } } @@ -1724,7 +1736,9 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void { }, .Struct => |structInfo| { inline for (structInfo.fields) |field| { - parseFree(field.field_type, @field(value, field.name), options); + if (!field.is_comptime) { + parseFree(field.field_type, @field(value, field.name), options); + } } }, .Array => |arrayInfo| { @@ -1901,14 +1915,19 @@ test "parse with comptime field" { }, }; - const r = try std.json.parse(T, &std.json.TokenStream.init( + const options = ParseOptions{ + .allocator = std.testing.allocator, + }; + + const r = try parse(T, &TokenStream.init( \\{ \\ "kind": "float", \\ "b": 1.0 \\} - ), .{ - .allocator = std.testing.allocator, - }); + ), options); + + // check that parseFree doesn't try to free comptime fields + parseFree(T, r, options); } } @@ -1995,17 +2014,33 @@ test "parse into struct with duplicate field" { const ballast = try testing.allocator.alloc(u64, 1); defer testing.allocator.free(ballast); - const options = ParseOptions{ + const options_first = ParseOptions{ + .allocator = testing.allocator, + .duplicate_field_behavior = .UseFirst + }; + + const options_last = ParseOptions{ .allocator = testing.allocator, .duplicate_field_behavior = .UseLast, }; + const str = "{ \"a\": 1, \"a\": 0.25 }"; const T1 = struct { a: *u64 }; - try testing.expectError(error.UnexpectedToken, parse(T1, &TokenStream.init(str), options)); + // both .UseFirst and .UseLast should fail because second "a" value isn't a u64 + try testing.expectError(error.UnexpectedToken, parse(T1, &TokenStream.init(str), options_first)); + try testing.expectError(error.UnexpectedToken, parse(T1, &TokenStream.init(str), options_last)); const T2 = struct { a: f64 }; - try testing.expectEqual(T2{ .a = 0.25 }, try parse(T2, &TokenStream.init(str), options)); + try testing.expectEqual(T2{ .a = 1.0 }, try parse(T2, &TokenStream.init(str), options_first)); + try testing.expectEqual(T2{ .a = 0.25 }, try parse(T2, &TokenStream.init(str), options_last)); + + const T3 = struct { comptime a: f64 = 1.0 }; + // .UseFirst should succeed because second "a" value is unconditionally ignored (even though != 1.0) + const t3 = T3{ .a = 1.0 }; + try testing.expectEqual(t3, try parse(T3, &TokenStream.init(str), options_first)); + // .UseLast should fail because second "a" value is 0.25 which is not equal to default value of 1.0 + try testing.expectError(error.UnexpectedValue, parse(T3, &TokenStream.init(str), options_last)); } /// A non-stream JSON parser which constructs a tree of Value's. |
