| ... | @@ -1471,7 +1471,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options: | ... | @@ -1471,7 +1471,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options: |
| 1471 | var fields_seen = [_]bool{false} ** structInfo.fields.len; | 1471 | var fields_seen = [_]bool{false} ** structInfo.fields.len; |
| 1472 | errdefer { | 1472 | errdefer { |
| 1473 | inline for (structInfo.fields) |field, i| { | 1473 | inline for (structInfo.fields) |field, i| { |
| 1474 | if (fields_seen[i]) { | 1474 | if (fields_seen[i] and !field.is_comptime) { |
| 1475 | parseFree(field.field_type, @field(r, field.name), options); | 1475 | parseFree(field.field_type, @field(r, field.name), options); |
| 1476 | } | 1476 | } |
| 1477 | } | 1477 | } |
| ... | @@ -1504,7 +1504,15 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options: | ... | @@ -1504,7 +1504,15 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options: |
| 1504 | parseFree(field.field_type, @field(r, field.name), options); | 1504 | parseFree(field.field_type, @field(r, field.name), options); |
| 1505 | } | 1505 | } |
| 1506 | } | 1506 | } |
| 1507 | @field(r, field.name) = try parse(field.field_type, tokens, options); | 1507 | if (field.is_comptime) { |
| | 1508 | const value = try parse(field.field_type, tokens, options); |
| | 1509 | defer parseFree(field.field_type, value, options); |
| | 1510 | if (value != @field(r, field.name)) { |
| | 1511 | return error.UnexpectedValue; |
| | 1512 | } |
| | 1513 | } else { |
| | 1514 | @field(r, field.name) = try parse(field.field_type, tokens, options); |
| | 1515 | } |
| 1508 | fields_seen[i] = true; | 1516 | fields_seen[i] = true; |
| 1509 | found = true; | 1517 | found = true; |
| 1510 | break; | 1518 | break; |
| ... | @@ -1518,7 +1526,9 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options: | ... | @@ -1518,7 +1526,9 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options: |
| 1518 | inline for (structInfo.fields) |field, i| { | 1526 | inline for (structInfo.fields) |field, i| { |
| 1519 | if (!fields_seen[i]) { | 1527 | if (!fields_seen[i]) { |
| 1520 | if (field.default_value) |default| { | 1528 | if (field.default_value) |default| { |
| 1521 | @field(r, field.name) = default; | 1529 | if (!field.is_comptime) { |
| | 1530 | @field(r, field.name) = default; |
| | 1531 | } |
| 1522 | } else { | 1532 | } else { |
| 1523 | return error.MissingField; | 1533 | return error.MissingField; |
| 1524 | } | 1534 | } |
| ... | @@ -1789,6 +1799,19 @@ test "parseFree descends into tagged union" { | ... | @@ -1789,6 +1799,19 @@ test "parseFree descends into tagged union" { |
| 1789 | testing.expectEqual(@as(usize, 1), fail_alloc.deallocations); | 1799 | testing.expectEqual(@as(usize, 1), fail_alloc.deallocations); |
| 1790 | } | 1800 | } |
| 1791 | | 1801 | |
| | 1802 | test "parse with comptime field" { |
| | 1803 | const T = struct { |
| | 1804 | comptime a: i32 = 0, |
| | 1805 | b: bool, |
| | 1806 | }; |
| | 1807 | testing.expectEqual(T{ .a = 0, .b = true }, try parse(T, &TokenStream.init( |
| | 1808 | \\{ |
| | 1809 | \\ "a": 0, |
| | 1810 | \\ "b": true |
| | 1811 | \\} |
| | 1812 | ), ParseOptions{})); |
| | 1813 | } |
| | 1814 | |
| 1792 | test "parse into struct with no fields" { | 1815 | test "parse into struct with no fields" { |
| 1793 | const T = struct {}; | 1816 | const T = struct {}; |
| 1794 | testing.expectEqual(T{}, try parse(T, &TokenStream.init("{}"), ParseOptions{})); | 1817 | testing.expectEqual(T{}, try parse(T, &TokenStream.init("{}"), ParseOptions{})); |