diff --git a/lib/std/json/dynamic_test.zig b/lib/std/json/dynamic_test.zig index ad737502ed56..23586066fd1b 100644 --- a/lib/std/json/dynamic_test.zig +++ b/lib/std/json/dynamic_test.zig @@ -339,6 +339,17 @@ test "many object keys" { try testing.expectEqualStrings("v5", parsed.value.object.get("k5").?.string); } +test "negative zero" { + const doc = "-0"; + var fbs = std.io.fixedBufferStream(doc); + var reader = smallBufferJsonReader(testing.allocator, fbs.reader()); + defer reader.deinit(); + var parsed = try parseFromTokenSource(Value, testing.allocator, &reader, .{}); + defer parsed.deinit(); + + try testing.expect(parsed.value.float == 0 and std.math.signbit(parsed.value.float)); +} + fn smallBufferJsonReader(allocator: Allocator, io_reader: anytype) JsonReader(16, @TypeOf(io_reader)) { return JsonReader(16, @TypeOf(io_reader)).init(allocator, io_reader); } diff --git a/lib/std/json/scanner.zig b/lib/std/json/scanner.zig index 2f6a0ce6be6e..54b661113b00 100644 --- a/lib/std/json/scanner.zig +++ b/lib/std/json/scanner.zig @@ -1700,11 +1700,12 @@ fn appendSlice(list: *std.ArrayList(u8), buf: []const u8, max_value_len: usize) } /// For the slice you get from a `Token.number` or `Token.allocated_number`, -/// this function returns true if the number doesn't contain any fraction or exponent components. +/// this function returns true if the number doesn't contain any fraction or exponent components, and is not `-0`. /// Note, the numeric value encoded by the value may still be an integer, such as `1.0`. /// This function is meant to give a hint about whether integer parsing or float parsing should be used on the value. /// This function will not give meaningful results on non-numeric input. pub fn isNumberFormattedLikeAnInteger(value: []const u8) bool { + if (std.mem.eql(u8, value, "-0")) return false; return std.mem.indexOfAny(u8, value, ".eE") == null; } diff --git a/lib/std/json/scanner_test.zig b/lib/std/json/scanner_test.zig index 8ab7f5e7153e..b11ae7464dc6 100644 --- a/lib/std/json/scanner_test.zig +++ b/lib/std/json/scanner_test.zig @@ -7,6 +7,7 @@ const TokenType = @import("./scanner.zig").TokenType; const Diagnostics = @import("./scanner.zig").Diagnostics; const Error = @import("./scanner.zig").Error; const validate = @import("./scanner.zig").validate; +const isNumberFormattedLikeAnInteger = @import("./scanner.zig").isNumberFormattedLikeAnInteger; const example_document_str = \\{ @@ -465,3 +466,15 @@ test "enableDiagnostics" { try testDiagnostics(error.SyntaxError, 1, s.len, s.len - 1, s); } } + +test isNumberFormattedLikeAnInteger { + try std.testing.expect(isNumberFormattedLikeAnInteger("0")); + try std.testing.expect(isNumberFormattedLikeAnInteger("1")); + try std.testing.expect(isNumberFormattedLikeAnInteger("123")); + try std.testing.expect(!isNumberFormattedLikeAnInteger("-0")); + try std.testing.expect(!isNumberFormattedLikeAnInteger("0.0")); + try std.testing.expect(!isNumberFormattedLikeAnInteger("1.0")); + try std.testing.expect(!isNumberFormattedLikeAnInteger("1.23")); + try std.testing.expect(!isNumberFormattedLikeAnInteger("1e10")); + try std.testing.expect(!isNumberFormattedLikeAnInteger("1E10")); +}