| ... | @@ -287,7 +287,7 @@ pub fn innerParse( | ... | @@ -287,7 +287,7 @@ pub fn innerParse( |
| 287 | const field_name = switch (name_token.?) { | 287 | const field_name = switch (name_token.?) { |
| 288 | inline .string, .allocated_string => |slice| slice, | 288 | inline .string, .allocated_string => |slice| slice, |
| 289 | else => { | 289 | else => { |
| 290 | if (options.diagnostics) |diag| diag.recordContext("tagged union requires a field to identify the active tag"); | 290 | if (options.diagnostics) |diag| diag.setMessage("tagged union requires a field to identify the active tag"); |
| 291 | return error.MissingField; | 291 | return error.MissingField; |
| 292 | }, | 292 | }, |
| 293 | }; | 293 | }; |
| ... | @@ -305,7 +305,7 @@ pub fn innerParse( | ... | @@ -305,7 +305,7 @@ pub fn innerParse( |
| 305 | else => |t| return typeError(options.diagnostics, t, "void payload ('{}')"), | 305 | else => |t| return typeError(options.diagnostics, t, "void payload ('{}')"), |
| 306 | } | 306 | } |
| 307 | if (.object_end != try source.next()) { | 307 | if (.object_end != try source.next()) { |
| 308 | if (options.diagnostics) |diag| diag.recordContext("void payload '{}' should have no fields"); | 308 | if (options.diagnostics) |diag| diag.setMessage("void payload '{}' should have no fields"); |
| 309 | return error.UnknownField; | 309 | return error.UnknownField; |
| 310 | } | 310 | } |
| 311 | result = @unionInit(T, u_field.name, {}); | 311 | result = @unionInit(T, u_field.name, {}); |
| ... | @@ -317,12 +317,12 @@ pub fn innerParse( | ... | @@ -317,12 +317,12 @@ pub fn innerParse( |
| 317 | } | 317 | } |
| 318 | } else { | 318 | } else { |
| 319 | // Didn't match anything. | 319 | // Didn't match anything. |
| 320 | if (options.diagnostics) |diag| diag.recordContext("unrecognized tag name"); | 320 | if (options.diagnostics) |diag| diag.setMessage("unrecognized tag name"); |
| 321 | return error.UnknownField; | 321 | return error.UnknownField; |
| 322 | } | 322 | } |
| 323 | | 323 | |
| 324 | if (.object_end != try source.next()) { | 324 | if (.object_end != try source.next()) { |
| 325 | if (options.diagnostics) |diag| diag.recordContext("tagged union requires only one field"); | 325 | if (options.diagnostics) |diag| diag.setMessage("tagged union requires only one field"); |
| 326 | return error.UnknownField; | 326 | return error.UnknownField; |
| 327 | } | 327 | } |
| 328 | | 328 | |
| ... | @@ -339,7 +339,7 @@ pub fn innerParse( | ... | @@ -339,7 +339,7 @@ pub fn innerParse( |
| 339 | var r: T = undefined; | 339 | var r: T = undefined; |
| 340 | inline for (0..structInfo.fields.len) |i| { | 340 | inline for (0..structInfo.fields.len) |i| { |
| 341 | if (.array_end == try source.peekNextTokenType()) { | 341 | if (.array_end == try source.peekNextTokenType()) { |
| 342 | if (options.diagnostics) |diag| diag.recordContext(std.fmt.comptimePrint( | 342 | if (options.diagnostics) |diag| diag.setMessage(std.fmt.comptimePrint( |
| 343 | "tuple too short. expected length: {}", | 343 | "tuple too short. expected length: {}", |
| 344 | .{structInfo.fields.len}, | 344 | .{structInfo.fields.len}, |
| 345 | )); | 345 | )); |
| ... | @@ -349,7 +349,7 @@ pub fn innerParse( | ... | @@ -349,7 +349,7 @@ pub fn innerParse( |
| 349 | } | 349 | } |
| 350 | | 350 | |
| 351 | if (.array_end != try source.next()) { | 351 | if (.array_end != try source.next()) { |
| 352 | if (options.diagnostics) |diag| diag.recordContext(std.fmt.comptimePrint( | 352 | if (options.diagnostics) |diag| diag.setMessage(std.fmt.comptimePrint( |
| 353 | "tuple too long. expected length: {}", | 353 | "tuple too long. expected length: {}", |
| 354 | .{structInfo.fields.len}, | 354 | .{structInfo.fields.len}, |
| 355 | )); | 355 | )); |
| ... | @@ -398,7 +398,7 @@ pub fn innerParse( | ... | @@ -398,7 +398,7 @@ pub fn innerParse( |
| 398 | break; | 398 | break; |
| 399 | }, | 399 | }, |
| 400 | .@"error" => { | 400 | .@"error" => { |
| 401 | if (options.diagnostics) |diag| diag.recordContext("duplicate field name: " ++ field.name); | 401 | if (options.diagnostics) |diag| diag.setMessage("duplicate field name: " ++ field.name); |
| 402 | return error.DuplicateField; | 402 | return error.DuplicateField; |
| 403 | }, | 403 | }, |
| 404 | .use_last => {}, | 404 | .use_last => {}, |
| ... | @@ -414,7 +414,7 @@ pub fn innerParse( | ... | @@ -414,7 +414,7 @@ pub fn innerParse( |
| 414 | if (options.ignore_unknown_fields) { | 414 | if (options.ignore_unknown_fields) { |
| 415 | try source.skipValue(); | 415 | try source.skipValue(); |
| 416 | } else { | 416 | } else { |
| 417 | if (options.diagnostics) |diag| diag.recordContext("unrecognized field name"); | 417 | if (options.diagnostics) |diag| diag.setMessage("unrecognized field name"); |
| 418 | return error.UnknownField; | 418 | return error.UnknownField; |
| 419 | } | 419 | } |
| 420 | } | 420 | } |
| ... | @@ -438,32 +438,54 @@ pub fn innerParse( | ... | @@ -438,32 +438,54 @@ pub fn innerParse( |
| 438 | while (true) { | 438 | while (true) { |
| 439 | switch (try source.next()) { | 439 | switch (try source.next()) { |
| 440 | .string => |slice| { | 440 | .string => |slice| { |
| 441 | if (i + slice.len != r.len) return error.LengthMismatch; | 441 | if (i + slice.len > r.len) { |
| | 442 | if (options.diagnostics) |diag| diag.setMessage(std.fmt.comptimePrint("string too long for fixed length array. expected length: {}", .{r.len})); |
| | 443 | return error.LengthMismatch; |
| | 444 | } |
| | 445 | if (i + slice.len < r.len) { |
| | 446 | if (options.diagnostics) |diag| diag.setMessage(std.fmt.comptimePrint("string too short for fixed length array. expected length: {}", .{r.len})); |
| | 447 | return error.LengthMismatch; |
| | 448 | } |
| 442 | @memcpy(r[i..][0..slice.len], slice); | 449 | @memcpy(r[i..][0..slice.len], slice); |
| 443 | break; | 450 | break; |
| 444 | }, | 451 | }, |
| 445 | .partial_string => |slice| { | 452 | .partial_string => |slice| { |
| 446 | if (i + slice.len > r.len) return error.LengthMismatch; | 453 | if (i + slice.len > r.len) { |
| | 454 | if (options.diagnostics) |diag| diag.setMessage(std.fmt.comptimePrint("string too long for fixed length array. expected length: {}", .{r.len})); |
| | 455 | return error.LengthMismatch; |
| | 456 | } |
| 447 | @memcpy(r[i..][0..slice.len], slice); | 457 | @memcpy(r[i..][0..slice.len], slice); |
| 448 | i += slice.len; | 458 | i += slice.len; |
| 449 | }, | 459 | }, |
| 450 | .partial_string_escaped_1 => |arr| { | 460 | .partial_string_escaped_1 => |arr| { |
| 451 | if (i + arr.len > r.len) return error.LengthMismatch; | 461 | if (i + arr.len > r.len) { |
| | 462 | if (options.diagnostics) |diag| diag.setMessage(std.fmt.comptimePrint("string too long for fixed length array. expected length: {}", .{r.len})); |
| | 463 | return error.LengthMismatch; |
| | 464 | } |
| 452 | @memcpy(r[i..][0..arr.len], arr[0..]); | 465 | @memcpy(r[i..][0..arr.len], arr[0..]); |
| 453 | i += arr.len; | 466 | i += arr.len; |
| 454 | }, | 467 | }, |
| 455 | .partial_string_escaped_2 => |arr| { | 468 | .partial_string_escaped_2 => |arr| { |
| 456 | if (i + arr.len > r.len) return error.LengthMismatch; | 469 | if (i + arr.len > r.len) { |
| | 470 | if (options.diagnostics) |diag| diag.setMessage(std.fmt.comptimePrint("string too long for fixed length array. expected length: {}", .{r.len})); |
| | 471 | return error.LengthMismatch; |
| | 472 | } |
| 457 | @memcpy(r[i..][0..arr.len], arr[0..]); | 473 | @memcpy(r[i..][0..arr.len], arr[0..]); |
| 458 | i += arr.len; | 474 | i += arr.len; |
| 459 | }, | 475 | }, |
| 460 | .partial_string_escaped_3 => |arr| { | 476 | .partial_string_escaped_3 => |arr| { |
| 461 | if (i + arr.len > r.len) return error.LengthMismatch; | 477 | if (i + arr.len > r.len) { |
| | 478 | if (options.diagnostics) |diag| diag.setMessage(std.fmt.comptimePrint("string too long for fixed length array. expected length: {}", .{r.len})); |
| | 479 | return error.LengthMismatch; |
| | 480 | } |
| 462 | @memcpy(r[i..][0..arr.len], arr[0..]); | 481 | @memcpy(r[i..][0..arr.len], arr[0..]); |
| 463 | i += arr.len; | 482 | i += arr.len; |
| 464 | }, | 483 | }, |
| 465 | .partial_string_escaped_4 => |arr| { | 484 | .partial_string_escaped_4 => |arr| { |
| 466 | if (i + arr.len > r.len) return error.LengthMismatch; | 485 | if (i + arr.len > r.len) { |
| | 486 | if (options.diagnostics) |diag| diag.setMessage(std.fmt.comptimePrint("string too long for fixed length array. expected length: {}", .{r.len})); |
| | 487 | return error.LengthMismatch; |
| | 488 | } |
| 467 | @memcpy(r[i..][0..arr.len], arr[0..]); | 489 | @memcpy(r[i..][0..arr.len], arr[0..]); |
| 468 | i += arr.len; | 490 | i += arr.len; |
| 469 | }, | 491 | }, |
| ... | @@ -568,11 +590,17 @@ fn internalParseArray( | ... | @@ -568,11 +590,17 @@ fn internalParseArray( |
| 568 | var r: T = undefined; | 590 | var r: T = undefined; |
| 569 | var i: usize = 0; | 591 | var i: usize = 0; |
| 570 | while (i < len) : (i += 1) { | 592 | while (i < len) : (i += 1) { |
| 571 | if (.array_end == try source.peekNextTokenType()) return error.LengthMismatch; | 593 | if (.array_end == try source.peekNextTokenType()) { |
| | 594 | if (options.diagnostics) |diag| diag.setMessage(std.fmt.comptimePrint("not enough items for fixed length array. expected length: {}", .{len})); |
| | 595 | return error.LengthMismatch; |
| | 596 | } |
| 572 | r[i] = try innerParse(Child, allocator, source, options); | 597 | r[i] = try innerParse(Child, allocator, source, options); |
| 573 | } | 598 | } |
| 574 | | 599 | |
| 575 | if (.array_end != try source.next()) return error.LengthMismatch; | 600 | if (.array_end != try source.next()) { |
| | 601 | if (options.diagnostics) |diag| diag.setMessage(std.fmt.comptimePrint("too many items for fixed length array. expected length: {}", .{len})); |
| | 602 | return error.LengthMismatch; |
| | 603 | } |
| 576 | | 604 | |
| 577 | return r; | 605 | return r; |
| 578 | } | 606 | } |
| ... | @@ -622,7 +650,7 @@ fn typeError(diagnostics: ?*Diagnostics, token: anytype, comptime expected: []co | ... | @@ -622,7 +650,7 @@ fn typeError(diagnostics: ?*Diagnostics, token: anytype, comptime expected: []co |
| 622 | .array_end => unreachable, // type errors happen at the start of a value. | 650 | .array_end => unreachable, // type errors happen at the start of a value. |
| 623 | .end_of_document => unreachable, // type errors happen at the start of a value. | 651 | .end_of_document => unreachable, // type errors happen at the start of a value. |
| 624 | }; | 652 | }; |
| 625 | diag.recordContext(s); | 653 | diag.setMessage(s); |
| 626 | } | 654 | } |
| 627 | return error.UnexpectedToken; | 655 | return error.UnexpectedToken; |
| 628 | } | 656 | } |
| ... | @@ -880,7 +908,7 @@ fn fillDefaultStructValues(comptime T: type, options: ParseOptions, r: *T, field | ... | @@ -880,7 +908,7 @@ fn fillDefaultStructValues(comptime T: type, options: ParseOptions, r: *T, field |
| 880 | const default = @as(*align(1) const field.type, @ptrCast(default_ptr)).*; | 908 | const default = @as(*align(1) const field.type, @ptrCast(default_ptr)).*; |
| 881 | @field(r, field.name) = default; | 909 | @field(r, field.name) = default; |
| 882 | } else { | 910 | } else { |
| 883 | if (options.diagnostics) |diag| diag.recordContext("missing field: " ++ @typeName(T) ++ "." ++ field.name); | 911 | if (options.diagnostics) |diag| diag.setMessage("missing field: " ++ @typeName(T) ++ "." ++ field.name); |
| 884 | return error.MissingField; | 912 | return error.MissingField; |
| 885 | } | 913 | } |
| 886 | } | 914 | } |