| ... | ... | @@ -6,6 +6,8 @@ |
| 6 | 6 | //! * `fromZoir`/`fromZoirAlloc` |
| 7 | 7 | //! * `fromZoirNode`/`fromZoirNodeAlloc` |
| 8 | 8 | //! |
| 9 | //! To update an existing values, see the `updateFrom*` variants. |
| 10 | //! |
| 9 | 11 | //! For lower level control over parsing, see `std.zig.Zoir`. |
| 10 | 12 | |
| 11 | 13 | const std = @import("std"); |
| ... | ... | @@ -23,14 +25,39 @@ const ArrayList = std.ArrayList; |
| 23 | 25 | /// Rename when adding or removing support for a type. |
| 24 | 26 | const valid_types = {}; |
| 25 | 27 | |
| 26 | | /// Configuration for the runtime parser. |
| 27 | | pub const Options = struct { |
| 28 | /// Deprecated. |
| 29 | pub const Options = FromOptions; |
| 30 | |
| 31 | /// Configuration for the `from*` functions. |
| 32 | pub const FromOptions = struct { |
| 28 | 33 | /// If true, unknown fields do not error. |
| 29 | 34 | ignore_unknown_fields: bool = false, |
| 30 | 35 | /// If true, the parser cleans up partially parsed values on error. This requires some extra |
| 31 | 36 | /// bookkeeping, so you may want to turn it off if you don't need this feature (e.g. because |
| 32 | 37 | /// you're using arena allocation.) |
| 33 | 38 | free_on_error: bool = true, |
| 39 | |
| 40 | fn toParserOptions(self: FromOptions) Parser.Options { |
| 41 | return .{ |
| 42 | .ignore_unknown_fields = self.ignore_unknown_fields, |
| 43 | .ignore_missing_fields = false, |
| 44 | .free_on_error = self.free_on_error, |
| 45 | }; |
| 46 | } |
| 47 | }; |
| 48 | |
| 49 | /// Configuration for the `updateFrom*` variants. |
| 50 | pub const UpdateFromOptions = struct { |
| 51 | /// If true, unknown fields do not error. |
| 52 | ignore_unknown_fields: bool = false, |
| 53 | |
| 54 | fn toParserOptions(self: UpdateFromOptions) Parser.Options { |
| 55 | return .{ |
| 56 | .ignore_unknown_fields = self.ignore_unknown_fields, |
| 57 | .ignore_missing_fields = true, |
| 58 | .free_on_error = false, |
| 59 | }; |
| 60 | } |
| 34 | 61 | }; |
| 35 | 62 | |
| 36 | 63 | pub const Error = union(enum) { |
| ... | ... | @@ -260,50 +287,92 @@ pub const Diagnostics = struct { |
| 260 | 287 | /// |
| 261 | 288 | /// An allocator is still required for temporary allocations made during parsing. |
| 262 | 289 | pub fn fromSlice( |
| 290 | /// The type to deserialize into. Only the following types are supported, unsupported types will |
| 291 | /// result in a compiler error: |
| 292 | /// |
| 293 | /// * Optionals of supported types |
| 294 | /// * Booleans |
| 295 | /// * Integers except for `comptime_int` |
| 296 | /// * Floats except for `comptime_float` |
| 297 | /// * Enums |
| 298 | /// * Single item pointers to supported types |
| 299 | /// * Slices of supported types |
| 300 | /// * Arrays of supported types |
| 301 | /// * Vectors of supported types |
| 302 | /// * Structures of supported types |
| 303 | /// * Tuples of supported types |
| 304 | /// * Unions |
| 263 | 305 | T: type, |
| 264 | 306 | gpa: Allocator, |
| 265 | 307 | source: [:0]const u8, |
| 266 | 308 | diag: ?*Diagnostics, |
| 267 | | options: Options, |
| 309 | options: FromOptions, |
| 268 | 310 | ) error{ OutOfMemory, ParseZon }!T { |
| 269 | 311 | comptime assert(!requiresAllocator(T)); |
| 270 | 312 | return fromSliceAlloc(T, gpa, source, diag, options); |
| 271 | 313 | } |
| 272 | 314 | |
| 315 | /// Similar to `fromSlice`, but updates an existing value `current`. Fields not specified by ZON are |
| 316 | /// left at their current values. Pointers are replaced with new values not mutated in place. |
| 317 | pub fn updateFromSlice( |
| 318 | T: type, |
| 319 | gpa: Allocator, |
| 320 | current: *T, |
| 321 | source: [:0]const u8, |
| 322 | diag: ?*Diagnostics, |
| 323 | options: UpdateFromOptions, |
| 324 | ) error{ OutOfMemory, ParseZon }!void { |
| 325 | comptime assert(!requiresAllocator(T)); |
| 326 | try updateFromSliceAlloc(T, gpa, current, source, diag, options); |
| 327 | } |
| 328 | |
| 273 | 329 | /// Like `fromSlice`, but the result may contain pointers. To automatically free the result, see |
| 274 | 330 | /// `free`. |
| 275 | 331 | pub fn fromSliceAlloc( |
| 276 | | /// The type to deserialize into. May not be or contain any of the following types: |
| 277 | | /// * Any comptime-only type, except in a comptime field |
| 278 | | /// * `type` |
| 279 | | /// * `void`, except as a union payload |
| 280 | | /// * `noreturn` |
| 281 | | /// * An error set/error union |
| 282 | | /// * A many-pointer or C-pointer |
| 283 | | /// * An opaque type, including `anyopaque` |
| 284 | | /// * An async frame type, including `anyframe` and `anyframe->T` |
| 285 | | /// * A function |
| 286 | | /// |
| 287 | | /// All other types are valid. Unsupported types will fail at compile time. |
| 288 | 332 | T: type, |
| 289 | 333 | gpa: Allocator, |
| 290 | 334 | source: [:0]const u8, |
| 291 | 335 | diag: ?*Diagnostics, |
| 292 | | options: Options, |
| 336 | options: FromOptions, |
| 293 | 337 | ) error{ OutOfMemory, ParseZon }!T { |
| 338 | var result: T = undefined; |
| 339 | try parseSliceAlloc(T, &result, gpa, source, diag, options.toParserOptions()); |
| 340 | return result; |
| 341 | } |
| 342 | |
| 343 | /// Like updateFromSlice`, but the result may contain pointers. Requires an arena for cleanup. |
| 344 | pub fn updateFromSliceAlloc( |
| 345 | T: type, |
| 346 | arena: Allocator, |
| 347 | current: *T, |
| 348 | source: [:0]const u8, |
| 349 | diag: ?*Diagnostics, |
| 350 | options: UpdateFromOptions, |
| 351 | ) error{ OutOfMemory, ParseZon }!void { |
| 352 | try parseSliceAlloc(T, current, arena, source, diag, options.toParserOptions()); |
| 353 | } |
| 354 | |
| 355 | fn parseSliceAlloc( |
| 356 | T: type, |
| 357 | current: *T, |
| 358 | arena: Allocator, |
| 359 | source: [:0]const u8, |
| 360 | diag: ?*Diagnostics, |
| 361 | options: Parser.Options, |
| 362 | ) error{ OutOfMemory, ParseZon }!void { |
| 294 | 363 | if (diag) |s| s.assertEmpty(); |
| 295 | 364 | |
| 296 | | var ast = try std.zig.Ast.parse(gpa, source, .{ .mode = .zon }); |
| 297 | | defer if (diag == null) ast.deinit(gpa); |
| 365 | var ast = try std.zig.Ast.parse(arena, source, .{ .mode = .zon }); |
| 366 | defer if (diag == null) ast.deinit(arena); |
| 298 | 367 | if (diag) |s| s.ast = ast; |
| 299 | 368 | |
| 300 | 369 | // If there's no diagnostics, Zoir exists for the lifetime of this function. If there is a |
| 301 | 370 | // diagnostics, ownership is transferred to diagnostics. |
| 302 | | var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false }); |
| 303 | | defer if (diag == null) zoir.deinit(gpa); |
| 371 | var zoir = try ZonGen.generate(arena, ast, .{ .parse_str_lits = false }); |
| 372 | defer if (diag == null) zoir.deinit(arena); |
| 304 | 373 | |
| 305 | 374 | if (diag) |s| s.* = .{}; |
| 306 | | return fromZoirAlloc(T, gpa, ast, zoir, diag, options); |
| 375 | try parseZoirAlloc(T, arena, current, ast, zoir, diag, options); |
| 307 | 376 | } |
| 308 | 377 | |
| 309 | 378 | /// Like `fromSlice`, but operates on `Zoir` instead of ZON source. |
| ... | ... | @@ -312,7 +381,7 @@ pub fn fromZoir( |
| 312 | 381 | ast: Ast, |
| 313 | 382 | zoir: Zoir, |
| 314 | 383 | diag: ?*Diagnostics, |
| 315 | | options: Options, |
| 384 | options: FromOptions, |
| 316 | 385 | ) error{ParseZon}!T { |
| 317 | 386 | comptime assert(!requiresAllocator(T)); |
| 318 | 387 | var buf: [0]u8 = .{}; |
| ... | ... | @@ -330,6 +399,32 @@ pub fn fromZoir( |
| 330 | 399 | }; |
| 331 | 400 | } |
| 332 | 401 | |
| 402 | /// Like `updateSlice`, but operates on `Zoir` instead of ZON source. |
| 403 | pub fn updateFromZoir( |
| 404 | T: type, |
| 405 | current: *T, |
| 406 | ast: Ast, |
| 407 | zoir: Zoir, |
| 408 | diag: ?*Diagnostics, |
| 409 | options: UpdateFromOptions, |
| 410 | ) error{ParseZon}!void { |
| 411 | comptime assert(!requiresAllocator(T)); |
| 412 | var buf: [0]u8 = .{}; |
| 413 | var failing_allocator = std.heap.FixedBufferAllocator.init(&buf); |
| 414 | updateFromZoirAlloc( |
| 415 | T, |
| 416 | failing_allocator.allocator(), |
| 417 | current, |
| 418 | ast, |
| 419 | zoir, |
| 420 | diag, |
| 421 | options, |
| 422 | ) catch |err| switch (err) { |
| 423 | error.OutOfMemory => unreachable, // Checked by comptime assertion above |
| 424 | else => |e| return e, |
| 425 | }; |
| 426 | } |
| 427 | |
| 333 | 428 | /// Like `fromSliceAlloc`, but operates on `Zoir` instead of ZON source. |
| 334 | 429 | pub fn fromZoirAlloc( |
| 335 | 430 | T: type, |
| ... | ... | @@ -337,11 +432,36 @@ pub fn fromZoirAlloc( |
| 337 | 432 | ast: Ast, |
| 338 | 433 | zoir: Zoir, |
| 339 | 434 | diag: ?*Diagnostics, |
| 340 | | options: Options, |
| 435 | options: FromOptions, |
| 341 | 436 | ) error{ OutOfMemory, ParseZon }!T { |
| 342 | 437 | return fromZoirNodeAlloc(T, gpa, ast, zoir, .root, diag, options); |
| 343 | 438 | } |
| 344 | 439 | |
| 440 | /// Like updateSliceAlloc`, but operates on `Zoir` instead of ZON source. |
| 441 | pub fn updateFromZoirAlloc( |
| 442 | T: type, |
| 443 | arena: Allocator, |
| 444 | current: *T, |
| 445 | ast: Ast, |
| 446 | zoir: Zoir, |
| 447 | diag: ?*Diagnostics, |
| 448 | options: UpdateFromOptions, |
| 449 | ) error{ OutOfMemory, ParseZon }!void { |
| 450 | try parseZoirAlloc(T, arena, current, ast, zoir, diag, options.toParserOptions()); |
| 451 | } |
| 452 | |
| 453 | fn parseZoirAlloc( |
| 454 | T: type, |
| 455 | gpa: Allocator, |
| 456 | current: *T, |
| 457 | ast: Ast, |
| 458 | zoir: Zoir, |
| 459 | diag: ?*Diagnostics, |
| 460 | options: Parser.Options, |
| 461 | ) error{ OutOfMemory, ParseZon }!void { |
| 462 | try parseZoirNodeAlloc(T, gpa, current, ast, zoir, .root, diag, options); |
| 463 | } |
| 464 | |
| 345 | 465 | /// Like `fromZoir`, but the parse starts at `node` instead of root. |
| 346 | 466 | pub fn fromZoirNode( |
| 347 | 467 | T: type, |
| ... | ... | @@ -349,7 +469,7 @@ pub fn fromZoirNode( |
| 349 | 469 | zoir: Zoir, |
| 350 | 470 | node: Zoir.Node.Index, |
| 351 | 471 | diag: ?*Diagnostics, |
| 352 | | options: Options, |
| 472 | options: FromOptions, |
| 353 | 473 | ) error{ParseZon}!T { |
| 354 | 474 | comptime assert(!requiresAllocator(T)); |
| 355 | 475 | var buf: [0]u8 = .{}; |
| ... | ... | @@ -368,6 +488,34 @@ pub fn fromZoirNode( |
| 368 | 488 | }; |
| 369 | 489 | } |
| 370 | 490 | |
| 491 | /// Like `updateZoir`, but the parse starts at `node` instead of root. |
| 492 | pub fn updateFromZoirNode( |
| 493 | T: type, |
| 494 | current: *T, |
| 495 | ast: Ast, |
| 496 | zoir: Zoir, |
| 497 | node: Zoir.Node.Index, |
| 498 | diag: ?*Diagnostics, |
| 499 | options: UpdateFromOptions, |
| 500 | ) error{ParseZon}!void { |
| 501 | comptime assert(!requiresAllocator(T)); |
| 502 | var buf: [0]u8 = .{}; |
| 503 | var failing_allocator = std.heap.FixedBufferAllocator.init(&buf); |
| 504 | updateFromZoirNodeAlloc( |
| 505 | T, |
| 506 | failing_allocator.allocator(), |
| 507 | current, |
| 508 | ast, |
| 509 | zoir, |
| 510 | node, |
| 511 | diag, |
| 512 | options, |
| 513 | ) catch |err| switch (err) { |
| 514 | error.OutOfMemory => unreachable, // Checked by comptime assertion above |
| 515 | else => |e| return e, |
| 516 | }; |
| 517 | } |
| 518 | |
| 371 | 519 | /// Like `fromZoirAlloc`, but the parse starts at `node` instead of root. |
| 372 | 520 | pub fn fromZoirNodeAlloc( |
| 373 | 521 | T: type, |
| ... | ... | @@ -376,8 +524,37 @@ pub fn fromZoirNodeAlloc( |
| 376 | 524 | zoir: Zoir, |
| 377 | 525 | node: Zoir.Node.Index, |
| 378 | 526 | diag: ?*Diagnostics, |
| 379 | | options: Options, |
| 527 | options: FromOptions, |
| 380 | 528 | ) error{ OutOfMemory, ParseZon }!T { |
| 529 | var out: T = undefined; |
| 530 | try parseZoirNodeAlloc(T, gpa, &out, ast, zoir, node, diag, options.toParserOptions()); |
| 531 | return out; |
| 532 | } |
| 533 | |
| 534 | /// Like `updateZoirNodeAlloc`, but the parse starts at `node` instead of root. |
| 535 | pub fn updateFromZoirNodeAlloc( |
| 536 | T: type, |
| 537 | arena: Allocator, |
| 538 | current: *T, |
| 539 | ast: Ast, |
| 540 | zoir: Zoir, |
| 541 | node: Zoir.Node.Index, |
| 542 | diag: ?*Diagnostics, |
| 543 | options: UpdateFromOptions, |
| 544 | ) error{ OutOfMemory, ParseZon }!void { |
| 545 | return parseZoirNodeAlloc(T, arena, current, ast, zoir, node, diag, options.toParserOptions()); |
| 546 | } |
| 547 | |
| 548 | fn parseZoirNodeAlloc( |
| 549 | T: type, |
| 550 | gpa: Allocator, |
| 551 | out: *T, |
| 552 | ast: Ast, |
| 553 | zoir: Zoir, |
| 554 | node: Zoir.Node.Index, |
| 555 | diag: ?*Diagnostics, |
| 556 | options: Parser.Options, |
| 557 | ) error{ OutOfMemory, ParseZon }!void { |
| 381 | 558 | comptime assert(canParseType(T)); |
| 382 | 559 | |
| 383 | 560 | if (diag) |s| { |
| ... | ... | @@ -398,9 +575,7 @@ pub fn fromZoirNodeAlloc( |
| 398 | 575 | .diag = diag, |
| 399 | 576 | }; |
| 400 | 577 | |
| 401 | | var out: T = undefined; |
| 402 | | try parser.parseExprInto(node, &out); |
| 403 | | return out; |
| 578 | try parser.parseExprInto(node, out); |
| 404 | 579 | } |
| 405 | 580 | |
| 406 | 581 | /// Frees ZON values. |
| ... | ... | @@ -486,7 +661,14 @@ const Parser = struct { |
| 486 | 661 | ast: Ast, |
| 487 | 662 | zoir: Zoir, |
| 488 | 663 | diag: ?*Diagnostics, |
| 489 | | options: Options, |
| 664 | options: Parser.Options, |
| 665 | pointer_depth: usize = 0, |
| 666 | |
| 667 | pub const Options = struct { |
| 668 | ignore_unknown_fields: bool, |
| 669 | free_on_error: bool, |
| 670 | ignore_missing_fields: bool, |
| 671 | }; |
| 490 | 672 | |
| 491 | 673 | const ParseExprError = error{ ParseZon, OutOfMemory }; |
| 492 | 674 | |
| ... | ... | @@ -529,6 +711,8 @@ const Parser = struct { |
| 529 | 711 | ); |
| 530 | 712 | errdefer self.gpa.free(slice); |
| 531 | 713 | const ptr = &slice[0]; |
| 714 | self.pointer_depth += 1; |
| 715 | defer self.pointer_depth -= 1; |
| 532 | 716 | try self.parseExprInnerInto(node, ptr); |
| 533 | 717 | out.* = ptr; |
| 534 | 718 | }, |
| ... | ... | @@ -883,17 +1067,19 @@ const Parser = struct { |
| 883 | 1067 | } |
| 884 | 1068 | |
| 885 | 1069 | // Fill in any missing default fields |
| 886 | | inline for (field_found, 0..) |found, i| { |
| 887 | | if (!found) { |
| 888 | | const field_attrs = info.field_attrs[i]; |
| 889 | | if (field_attrs.defaultValue(info.field_types[i])) |default| { |
| 890 | | @field(out, info.field_names[i]) = default; |
| 891 | | } else { |
| 892 | | return self.failNodeFmt( |
| 893 | | node, |
| 894 | | "missing required field {s}", |
| 895 | | .{info.field_names[i]}, |
| 896 | | ); |
| 1070 | if (!self.options.ignore_missing_fields or self.pointer_depth > 0) { |
| 1071 | inline for (field_found, 0..) |found, i| { |
| 1072 | if (!found) { |
| 1073 | const field_attrs = info.field_attrs[i]; |
| 1074 | if (field_attrs.defaultValue(info.field_types[i])) |default| { |
| 1075 | @field(out, info.field_names[i]) = default; |
| 1076 | } else { |
| 1077 | return self.failNodeFmt( |
| 1078 | node, |
| 1079 | "missing required field {s}", |
| 1080 | .{info.field_names[i]}, |
| 1081 | ); |
| 1082 | } |
| 897 | 1083 | } |
| 898 | 1084 | } |
| 899 | 1085 | } |
| ... | ... | @@ -3598,3 +3784,198 @@ test "std.zon aligned pointers" { |
| 3598 | 3784 | defer free(gpa, found); |
| 3599 | 3785 | try std.testing.expectEqualDeep(expected.inner, found.inner); |
| 3600 | 3786 | } |
| 3787 | |
| 3788 | test "std.zon update semantics" { |
| 3789 | // Test that the update logic works as expected |
| 3790 | |
| 3791 | var arena_allocator: std.heap.ArenaAllocator = .init(std.testing.allocator); |
| 3792 | defer arena_allocator.deinit(); |
| 3793 | const arena = arena_allocator.allocator(); |
| 3794 | |
| 3795 | const Vector = struct { x: f32, y: f32, z: f32 }; |
| 3796 | const MyStruct = struct { |
| 3797 | foo: u32 = 123, |
| 3798 | bar: bool, |
| 3799 | baz: struct { |
| 3800 | a: [2]u32, |
| 3801 | b: enum { c, d } = .d, |
| 3802 | }, |
| 3803 | ptr: *Vector, |
| 3804 | optional: ?u32 = null, |
| 3805 | str: []const u8 = "hello, world", |
| 3806 | }; |
| 3807 | |
| 3808 | var v: Vector = .{ .x = 1, .y = 2, .z = 3 }; |
| 3809 | var expected: MyStruct = .{ |
| 3810 | .foo = 10, |
| 3811 | .bar = true, |
| 3812 | .baz = .{ .a = .{ 1, 2 }, .b = .c }, |
| 3813 | .ptr = &v, |
| 3814 | }; |
| 3815 | var found = expected; |
| 3816 | |
| 3817 | try updateFromSliceAlloc( |
| 3818 | MyStruct, |
| 3819 | arena, |
| 3820 | &found, |
| 3821 | ".{}", |
| 3822 | null, |
| 3823 | .{}, |
| 3824 | ); |
| 3825 | try std.testing.expectEqual(expected, found); |
| 3826 | |
| 3827 | try updateFromSliceAlloc( |
| 3828 | MyStruct, |
| 3829 | arena, |
| 3830 | &found, |
| 3831 | ".{ .bar = false }", |
| 3832 | null, |
| 3833 | .{}, |
| 3834 | ); |
| 3835 | expected.bar = false; |
| 3836 | try std.testing.expectEqual(expected, found); |
| 3837 | |
| 3838 | try updateFromSliceAlloc( |
| 3839 | MyStruct, |
| 3840 | arena, |
| 3841 | &found, |
| 3842 | ".{ .baz = .{ .a = .{ 2, 4 } } }", |
| 3843 | null, |
| 3844 | .{}, |
| 3845 | ); |
| 3846 | expected.baz.a[0] = 2; |
| 3847 | expected.baz.a[1] = 4; |
| 3848 | try std.testing.expectEqual(expected, found); |
| 3849 | |
| 3850 | try updateFromSliceAlloc( |
| 3851 | MyStruct, |
| 3852 | arena, |
| 3853 | &found, |
| 3854 | ".{ .foo = 11, .baz = .{ .b = .d } }", |
| 3855 | null, |
| 3856 | .{}, |
| 3857 | ); |
| 3858 | expected.foo = 11; |
| 3859 | expected.baz.b = .d; |
| 3860 | try std.testing.expectEqual(expected, found); |
| 3861 | |
| 3862 | try updateFromSliceAlloc( |
| 3863 | MyStruct, |
| 3864 | arena, |
| 3865 | &found, |
| 3866 | ".{ .optional = 10 }", |
| 3867 | null, |
| 3868 | .{}, |
| 3869 | ); |
| 3870 | expected.optional = 10; |
| 3871 | try std.testing.expectEqual(expected, found); |
| 3872 | |
| 3873 | try updateFromSliceAlloc( |
| 3874 | MyStruct, |
| 3875 | arena, |
| 3876 | &found, |
| 3877 | ".{ .optional = null }", |
| 3878 | null, |
| 3879 | .{}, |
| 3880 | ); |
| 3881 | expected.optional = null; |
| 3882 | try std.testing.expectEqual(expected, found); |
| 3883 | |
| 3884 | try updateFromSliceAlloc( |
| 3885 | MyStruct, |
| 3886 | arena, |
| 3887 | &found, |
| 3888 | ".{ .ptr = .{ .x = 10, .y = 20, .z = 30 } }", |
| 3889 | null, |
| 3890 | .{}, |
| 3891 | ); |
| 3892 | expected.ptr.x = 10; |
| 3893 | expected.ptr.y = 20; |
| 3894 | expected.ptr.z = 30; |
| 3895 | try std.testing.expectEqualDeep(expected, found); |
| 3896 | |
| 3897 | try updateFromSliceAlloc( |
| 3898 | MyStruct, |
| 3899 | arena, |
| 3900 | &found, |
| 3901 | ".{ .str = \"foo\" }", |
| 3902 | null, |
| 3903 | .{}, |
| 3904 | ); |
| 3905 | expected.str = "foo"; |
| 3906 | try std.testing.expectEqualDeep(expected, found); |
| 3907 | } |
| 3908 | |
| 3909 | test "std.zon variants" { |
| 3910 | // Just a smoke test, we don't need to test each variant thoroughly because they all call into |
| 3911 | // the same code. |
| 3912 | |
| 3913 | var arena_allocator: std.heap.ArenaAllocator = .init(std.testing.allocator); |
| 3914 | defer arena_allocator.deinit(); |
| 3915 | const arena = arena_allocator.allocator(); |
| 3916 | |
| 3917 | const Struct = struct { a: u32, b: u32 }; |
| 3918 | const start: Struct = .{ .a = 10, .b = 20 }; |
| 3919 | const end: Struct = .{ .a = 100, .b = 20 }; |
| 3920 | |
| 3921 | // Update |
| 3922 | { |
| 3923 | const ast = try std.zig.Ast.parse(arena, ".{ .a = 100 }", .{ .mode = .zon }); |
| 3924 | const zoir = try ZonGen.generate(arena, ast, .{ .parse_str_lits = false }); |
| 3925 | |
| 3926 | var curr = start; |
| 3927 | try updateFromSlice(Struct, arena, &curr, ".{ .a = 100 }", null, .{}); |
| 3928 | try std.testing.expectEqual(end, curr); |
| 3929 | |
| 3930 | curr = start; |
| 3931 | try updateFromSliceAlloc(Struct, arena, &curr, ".{ .a = 100 }", null, .{}); |
| 3932 | try std.testing.expectEqual(end, curr); |
| 3933 | |
| 3934 | curr = start; |
| 3935 | try updateFromZoir(Struct, &curr, ast, zoir, null, .{}); |
| 3936 | try std.testing.expectEqual(end, curr); |
| 3937 | |
| 3938 | curr = start; |
| 3939 | try updateFromZoirAlloc(Struct, arena, &curr, ast, zoir, null, .{}); |
| 3940 | try std.testing.expectEqual(end, curr); |
| 3941 | |
| 3942 | curr = start; |
| 3943 | try updateFromZoirNode(Struct, &curr, ast, zoir, .root, null, .{}); |
| 3944 | try std.testing.expectEqual(end, curr); |
| 3945 | |
| 3946 | curr = start; |
| 3947 | try updateFromZoirNodeAlloc(Struct, arena, &curr, ast, zoir, .root, null, .{}); |
| 3948 | try std.testing.expectEqual(end, curr); |
| 3949 | } |
| 3950 | |
| 3951 | // From |
| 3952 | { |
| 3953 | const ast = try std.zig.Ast.parse(arena, ".{ .a = 100, .b = 20 }", .{ .mode = .zon }); |
| 3954 | const zoir = try ZonGen.generate(arena, ast, .{ .parse_str_lits = false }); |
| 3955 | |
| 3956 | try std.testing.expectEqual( |
| 3957 | end, |
| 3958 | try fromSlice(Struct, arena, ".{ .a = 100, .b = 20 }", null, .{}), |
| 3959 | ); |
| 3960 | try std.testing.expectEqual( |
| 3961 | end, |
| 3962 | try fromSliceAlloc(Struct, arena, ".{ .a = 100, .b = 20 }", null, .{}), |
| 3963 | ); |
| 3964 | try std.testing.expectEqual( |
| 3965 | try fromZoir(Struct, ast, zoir, null, .{}), |
| 3966 | end, |
| 3967 | ); |
| 3968 | try std.testing.expectEqual( |
| 3969 | try fromZoirAlloc(Struct, arena, ast, zoir, null, .{}), |
| 3970 | end, |
| 3971 | ); |
| 3972 | try std.testing.expectEqual( |
| 3973 | try fromZoirNode(Struct, ast, zoir, .root, null, .{}), |
| 3974 | end, |
| 3975 | ); |
| 3976 | try std.testing.expectEqual( |
| 3977 | try fromZoirNodeAlloc(Struct, arena, ast, zoir, .root, null, .{}), |
| 3978 | end, |
| 3979 | ); |
| 3980 | } |
| 3981 | } |