| ... | @@ -1418,7 +1418,10 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options: | ... | @@ -1418,7 +1418,10 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options: |
| 1418 | if (unionInfo.tag_type) |_| { | 1418 | if (unionInfo.tag_type) |_| { |
| 1419 | // try each of the union fields until we find one that matches | 1419 | // try each of the union fields until we find one that matches |
| 1420 | inline for (unionInfo.fields) |u_field| { | 1420 | inline for (unionInfo.fields) |u_field| { |
| 1421 | if (parseInternal(u_field.field_type, token, tokens, options)) |value| { | 1421 | // take a copy of tokens so we can withhold mutations until success |
| | 1422 | var tokens_copy = tokens.*; |
| | 1423 | if (parseInternal(u_field.field_type, token, &tokens_copy, options)) |value| { |
| | 1424 | tokens.* = tokens_copy; |
| 1422 | return @unionInit(T, u_field.name, value); | 1425 | return @unionInit(T, u_field.name, value); |
| 1423 | } else |err| { | 1426 | } else |err| { |
| 1424 | // Bubble up error.OutOfMemory | 1427 | // Bubble up error.OutOfMemory |
| ... | @@ -1733,6 +1736,14 @@ test "parse into tagged union" { | ... | @@ -1733,6 +1736,14 @@ test "parse into tagged union" { |
| 1733 | }; | 1736 | }; |
| 1734 | testing.expectEqual(T{ .x = 42 }, try parse(T, &TokenStream.init("42"), ParseOptions{})); | 1737 | testing.expectEqual(T{ .x = 42 }, try parse(T, &TokenStream.init("42"), ParseOptions{})); |
| 1735 | } | 1738 | } |
| | 1739 | |
| | 1740 | { // needs to back out when first union member doesn't match |
| | 1741 | const T = union(enum) { |
| | 1742 | A: struct { x: u32 }, |
| | 1743 | B: struct { y: u32 }, |
| | 1744 | }; |
| | 1745 | testing.expectEqual(T{ .B = .{.y = 42} }, try parse(T, &TokenStream.init("{\"y\":42}"), ParseOptions{})); |
| | 1746 | } |
| 1736 | } | 1747 | } |
| 1737 | | 1748 | |
| 1738 | test "parseFree descends into tagged union" { | 1749 | test "parseFree descends into tagged union" { |