authorgravatar for emil@lerch.orgEmil Lerch <emil@lerch.org> 2021-06-24 17:07:58-07:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-06-26 10:10:36+03:00
log2ac769eab9b7dba4cd38e5de01dfa6400f7ebd5b
treee6f6bf4b763c9a22c5b6dcf69ec5ac52efb51d19
parentdacc5e624eb28570fe517b1f00ddc6287e2c5249

allow json scientific notation to coerce to integers as long as they actually resolve to int type


1 files changed, 14 insertions(+), 4 deletions(-)

lib/std/json.zig+14-4
...@@ -1551,8 +1551,11 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:...@@ -1551,8 +1551,11 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:
1551 .Number => |n| n,1551 .Number => |n| n,
1552 else => return error.UnexpectedToken,1552 else => return error.UnexpectedToken,
1553 };1553 };
1554 if (!numberToken.is_integer) return error.UnexpectedToken;1554 if (numberToken.is_integer)
1555 return try std.fmt.parseInt(T, numberToken.slice(tokens.slice, tokens.i - 1), 10);1555 return try std.fmt.parseInt(T, numberToken.slice(tokens.slice, tokens.i - 1), 10);
1556 const float = try std.fmt.parseFloat(f128, numberToken.slice(tokens.slice, tokens.i - 1));
1557 if (std.math.round(float) != float) return error.InvalidNumber;
1558 return @floatToInt(T, float);
1556 },1559 },
1557 .Optional => |optionalInfo| {1560 .Optional => |optionalInfo| {
1558 if (token == .Null) {1561 if (token == .Null) {
...@@ -2122,8 +2125,8 @@ test "parse into struct with duplicate field" {...@@ -2122,8 +2125,8 @@ test "parse into struct with duplicate field" {
21222125
2123 const T1 = struct { a: *u64 };2126 const T1 = struct { a: *u64 };
2124 // both .UseFirst and .UseLast should fail because second "a" value isn't a u642127 // both .UseFirst and .UseLast should fail because second "a" value isn't a u64
2125 try testing.expectError(error.UnexpectedToken, parse(T1, &TokenStream.init(str), options_first));2128 try testing.expectError(error.InvalidNumber, parse(T1, &TokenStream.init(str), options_first));
2126 try testing.expectError(error.UnexpectedToken, parse(T1, &TokenStream.init(str), options_last));2129 try testing.expectError(error.InvalidNumber, parse(T1, &TokenStream.init(str), options_last));
21272130
2128 const T2 = struct { a: f64 };2131 const T2 = struct { a: f64 };
2129 try testing.expectEqual(T2{ .a = 1.0 }, try parse(T2, &TokenStream.init(str), options_first));2132 try testing.expectEqual(T2{ .a = 1.0 }, try parse(T2, &TokenStream.init(str), options_first));
...@@ -2609,6 +2612,13 @@ test "integer after float has proper type" {...@@ -2609,6 +2612,13 @@ test "integer after float has proper type" {
2609 try std.testing.expect(json.Object.get("ints").?.Array.items[0] == .Integer);2612 try std.testing.expect(json.Object.get("ints").?.Array.items[0] == .Integer);
2610}2613}
26112614
2615test "parse exponential into int" {
2616 const T = struct { int: i64 };
2617 const r = try parse(T, &TokenStream.init("{ \"int\": 4.2e2 }"), ParseOptions{});
2618 try testing.expectEqual(@as(i64, 420), r.int);
2619 try testing.expectError(error.InvalidNumber, parse(T, &TokenStream.init("{ \"int\": 0.042e2 }"), ParseOptions{}));
2620}
2621
2612test "escaped characters" {2622test "escaped characters" {
2613 var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);2623 var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
2614 defer arena_allocator.deinit();2624 defer arena_allocator.deinit();