| ... | @@ -15,12 +15,16 @@ pub const WriteStream = @import("json/write_stream.zig").WriteStream; | ... | @@ -15,12 +15,16 @@ pub const WriteStream = @import("json/write_stream.zig").WriteStream; |
| 15 | /// Use `token.slice()` on the input at the current position to get the current slice. | 15 | /// Use `token.slice()` on the input at the current position to get the current slice. |
| 16 | pub const Token = struct { | 16 | pub const Token = struct { |
| 17 | id: Id, | 17 | id: Id, |
| | 18 | |
| 18 | /// How many bytes do we skip before counting | 19 | /// How many bytes do we skip before counting |
| 19 | offset: u1, | 20 | offset: u1, |
| | 21 | |
| 20 | /// Whether string contains an escape sequence and cannot be zero-copied | 22 | /// Whether string contains an escape sequence and cannot be zero-copied |
| 21 | string_has_escape: bool, | 23 | string_has_escape: bool, |
| | 24 | |
| 22 | /// Whether number is simple and can be represented by an integer (i.e. no `.` or `e`) | 25 | /// Whether number is simple and can be represented by an integer (i.e. no `.` or `e`) |
| 23 | number_is_integer: bool, | 26 | number_is_integer: bool, |
| | 27 | |
| 24 | /// How many bytes from the current position behind the start of this token is. | 28 | /// How many bytes from the current position behind the start of this token is. |
| 25 | count: usize, | 29 | count: usize, |
| 26 | | 30 | |
| ... | @@ -1299,54 +1303,52 @@ pub const Parser = struct { | ... | @@ -1299,54 +1303,52 @@ pub const Parser = struct { |
| 1299 | fn unescapeStringAlloc(alloc: *Allocator, input: []const u8) ![]u8 { | 1303 | fn unescapeStringAlloc(alloc: *Allocator, input: []const u8) ![]u8 { |
| 1300 | const output = try alloc.alloc(u8, input.len); | 1304 | const output = try alloc.alloc(u8, input.len); |
| 1301 | errdefer alloc.free(output); | 1305 | errdefer alloc.free(output); |
| 1302 | | 1306 | |
| 1303 | var inIndex: usize = 0; | 1307 | var inIndex: usize = 0; |
| 1304 | var outIndex: usize = 0; | 1308 | var outIndex: usize = 0; |
| 1305 | | 1309 | |
| 1306 | while(inIndex < input.len) { | 1310 | while (inIndex < input.len) { |
| 1307 | if(input[inIndex] != '\\'){ | 1311 | if (input[inIndex] != '\\') { |
| 1308 | // not an escape sequence | 1312 | // not an escape sequence |
| 1309 | output[outIndex] = input[inIndex]; | 1313 | output[outIndex] = input[inIndex]; |
| 1310 | inIndex += 1; | 1314 | inIndex += 1; |
| 1311 | outIndex += 1; | 1315 | outIndex += 1; |
| 1312 | } else if(input[inIndex + 1] != 'u'){ | 1316 | } else if (input[inIndex + 1] != 'u') { |
| 1313 | // a simple escape sequence | 1317 | // a simple escape sequence |
| 1314 | output[outIndex] = @as(u8, | 1318 | output[outIndex] = @as(u8, switch (input[inIndex + 1]) { |
| 1315 | switch(input[inIndex + 1]){ | 1319 | '\\' => '\\', |
| 1316 | '\\' => '\\', | 1320 | '/' => '/', |
| 1317 | '/' => '/', | 1321 | 'n' => '\n', |
| 1318 | 'n' => '\n', | 1322 | 'r' => '\r', |
| 1319 | 'r' => '\r', | 1323 | 't' => '\t', |
| 1320 | 't' => '\t', | 1324 | 'f' => 12, |
| 1321 | 'f' => 12, | 1325 | 'b' => 8, |
| 1322 | 'b' => 8, | 1326 | '"' => '"', |
| 1323 | '"' => '"', | 1327 | else => unreachable, |
| 1324 | else => unreachable | 1328 | }); |
| 1325 | } | | |
| 1326 | ); | | |
| 1327 | inIndex += 2; | 1329 | inIndex += 2; |
| 1328 | outIndex += 1; | 1330 | outIndex += 1; |
| 1329 | } else { | 1331 | } else { |
| 1330 | // a unicode escape sequence | 1332 | // a unicode escape sequence |
| 1331 | const firstCodeUnit = std.fmt.parseInt(u16, input[inIndex+2 .. inIndex+6], 16) catch unreachable; | 1333 | const firstCodeUnit = std.fmt.parseInt(u16, input[inIndex + 2 .. inIndex + 6], 16) catch unreachable; |
| 1332 | | 1334 | |
| 1333 | // guess optimistically that it's not a surrogate pair | 1335 | // guess optimistically that it's not a surrogate pair |
| 1334 | if(std.unicode.utf8Encode(firstCodeUnit, output[outIndex..])) |byteCount| { | 1336 | if (std.unicode.utf8Encode(firstCodeUnit, output[outIndex..])) |byteCount| { |
| 1335 | outIndex += byteCount; | 1337 | outIndex += byteCount; |
| 1336 | inIndex += 6; | 1338 | inIndex += 6; |
| 1337 | } else |err| { | 1339 | } else |err| { |
| 1338 | // it might be a surrogate pair | 1340 | // it might be a surrogate pair |
| 1339 | if(err != error.Utf8CannotEncodeSurrogateHalf) { | 1341 | if (err != error.Utf8CannotEncodeSurrogateHalf) { |
| 1340 | return error.InvalidUnicodeHexSymbol; | 1342 | return error.InvalidUnicodeHexSymbol; |
| 1341 | } | 1343 | } |
| 1342 | // check if a second code unit is present | 1344 | // check if a second code unit is present |
| 1343 | if(inIndex + 7 >= input.len or input[inIndex + 6] != '\\' or input[inIndex + 7] != 'u'){ | 1345 | if (inIndex + 7 >= input.len or input[inIndex + 6] != '\\' or input[inIndex + 7] != 'u') { |
| 1344 | return error.InvalidUnicodeHexSymbol; | 1346 | return error.InvalidUnicodeHexSymbol; |
| 1345 | } | 1347 | } |
| 1346 | | 1348 | |
| 1347 | const secondCodeUnit = std.fmt.parseInt(u16, input[inIndex+8 .. inIndex+12], 16) catch unreachable; | 1349 | const secondCodeUnit = std.fmt.parseInt(u16, input[inIndex + 8 .. inIndex + 12], 16) catch unreachable; |
| 1348 | | 1350 | |
| 1349 | if(std.unicode.utf16leToUtf8(output[outIndex..], &[2]u16{ firstCodeUnit, secondCodeUnit })) |byteCount| { | 1351 | if (std.unicode.utf16leToUtf8(output[outIndex..], &[2]u16{ firstCodeUnit, secondCodeUnit })) |byteCount| { |
| 1350 | outIndex += byteCount; | 1352 | outIndex += byteCount; |
| 1351 | inIndex += 12; | 1353 | inIndex += 12; |
| 1352 | } else |_| { | 1354 | } else |_| { |