| ... | @@ -398,7 +398,9 @@ pub fn fromZoirNodeAlloc( | ... | @@ -398,7 +398,9 @@ pub fn fromZoirNodeAlloc( |
| 398 | .diag = diag, | 398 | .diag = diag, |
| 399 | }; | 399 | }; |
| 400 | | 400 | |
| 401 | return parser.parseExpr(T, node); | 401 | var out: T = undefined; |
| | 402 | try parser.parseExprInto(node, &out); |
| | 403 | return out; |
| 402 | } | 404 | } |
| 403 | | 405 | |
| 404 | /// Frees ZON values. | 406 | /// Frees ZON values. |
| ... | @@ -488,34 +490,36 @@ const Parser = struct { | ... | @@ -488,34 +490,36 @@ const Parser = struct { |
| 488 | | 490 | |
| 489 | const ParseExprError = error{ ParseZon, OutOfMemory }; | 491 | const ParseExprError = error{ ParseZon, OutOfMemory }; |
| 490 | | 492 | |
| 491 | fn parseExpr(self: *@This(), T: type, node: Zoir.Node.Index) ParseExprError!T { | 493 | fn parseExprInto(self: *@This(), node: Zoir.Node.Index, out: anytype) ParseExprError!void { |
| 492 | return self.parseExprInner(T, node) catch |err| switch (err) { | 494 | return self.parseExprInnerInto(node, out) catch |err| switch (err) { |
| 493 | error.WrongType => return self.failExpectedType(T, node), | 495 | error.WrongType => return self.failExpectedType(@TypeOf(out.*), node), |
| 494 | else => |e| return e, | 496 | else => |e| return e, |
| 495 | }; | 497 | }; |
| 496 | } | 498 | } |
| 497 | | 499 | |
| 498 | const ParseExprInnerError = error{ ParseZon, OutOfMemory, WrongType }; | 500 | const ParseExprInnerError = error{ ParseZon, OutOfMemory, WrongType }; |
| 499 | | 501 | |
| 500 | fn parseExprInner( | 502 | fn parseExprInnerInto( |
| 501 | self: *@This(), | 503 | self: *@This(), |
| 502 | T: type, | | |
| 503 | node: Zoir.Node.Index, | 504 | node: Zoir.Node.Index, |
| 504 | ) ParseExprInnerError!T { | 505 | out: anytype, |
| 505 | if (T == Zoir.Node.Index) { | 506 | ) ParseExprInnerError!void { |
| 506 | return node; | 507 | if (@TypeOf(out.*) == Zoir.Node.Index) { |
| | 508 | out.* = node; |
| | 509 | return; |
| 507 | } | 510 | } |
| 508 | | 511 | |
| 509 | switch (@typeInfo(T)) { | 512 | switch (@typeInfo(@TypeOf(out.*))) { |
| 510 | .optional => |optional| if (node.get(self.zoir) == .null) { | 513 | .optional => |optional| if (node.get(self.zoir) == .null) { |
| 511 | return null; | 514 | out.* = null; |
| 512 | } else { | 515 | } else { |
| 513 | return try self.parseExprInner(optional.child, node); | 516 | out.* = @as(optional.child, undefined); // Make non-null |
| | 517 | try self.parseExprInnerInto(node, &out.*.?); // Parse value into non-null pointer |
| 514 | }, | 518 | }, |
| 515 | .bool => return self.parseBool(node), | 519 | .bool => out.* = try self.parseBool(node), |
| 516 | .int => return self.parseInt(T, node), | 520 | .int => out.* = try self.parseInt(@TypeOf(out.*), node), |
| 517 | .float => return self.parseFloat(T, node), | 521 | .float => out.* = try self.parseFloat(@TypeOf(out.*), node), |
| 518 | .@"enum" => return self.parseEnumLiteral(T, node), | 522 | .@"enum" => out.* = try self.parseEnumLiteral(@TypeOf(out.*), node), |
| 519 | .pointer => |pointer| switch (pointer.size) { | 523 | .pointer => |pointer| switch (pointer.size) { |
| 520 | .one => { | 524 | .one => { |
| 521 | const slice = try self.gpa.alignedAlloc( | 525 | const slice = try self.gpa.alignedAlloc( |
| ... | @@ -524,23 +528,20 @@ const Parser = struct { | ... | @@ -524,23 +528,20 @@ const Parser = struct { |
| 524 | 1, | 528 | 1, |
| 525 | ); | 529 | ); |
| 526 | errdefer self.gpa.free(slice); | 530 | errdefer self.gpa.free(slice); |
| 527 | const result = &slice[0]; | 531 | const ptr = &slice[0]; |
| 528 | result.* = try self.parseExprInner(pointer.child, node); | 532 | try self.parseExprInnerInto(node, ptr); |
| 529 | return result; | 533 | out.* = ptr; |
| 530 | }, | 534 | }, |
| 531 | .slice => return self.parseSlicePointer(T, node), | 535 | .slice => out.* = try self.parseSlicePointer(@TypeOf(out.*), node), |
| 532 | else => comptime unreachable, | 536 | else => comptime unreachable, |
| 533 | }, | 537 | }, |
| 534 | .array => return self.parseArray(T, node), | 538 | .array => try self.parseArrayInto(node, out), |
| 535 | .vector => |vector| { | 539 | .vector => try self.parseVectorInto(node, out), |
| 536 | const A = [vector.len]vector.child; | | |
| 537 | return try self.parseArray(A, node); | | |
| 538 | }, | | |
| 539 | .@"struct" => |@"struct"| if (@"struct".is_tuple) | 540 | .@"struct" => |@"struct"| if (@"struct".is_tuple) |
| 540 | return self.parseTuple(T, node) | 541 | try self.parseTupleInto(node, out) |
| 541 | else | 542 | else |
| 542 | return self.parseStruct(T, node), | 543 | try self.parseStructInto(node, out), |
| 543 | .@"union" => return self.parseUnion(T, node), | 544 | .@"union" => try self.parseUnionInto(node, out), |
| 544 | | 545 | |
| 545 | else => comptime unreachable, | 546 | else => comptime unreachable, |
| 546 | } | 547 | } |
| ... | @@ -758,53 +759,61 @@ const Parser = struct { | ... | @@ -758,53 +759,61 @@ const Parser = struct { |
| 758 | free(self.gpa, item); | 759 | free(self.gpa, item); |
| 759 | } | 760 | } |
| 760 | }; | 761 | }; |
| 761 | elem.* = try self.parseExpr(pointer.child, nodes.at(@intCast(i))); | 762 | try self.parseExprInto(nodes.at(@intCast(i)), elem); |
| 762 | } | 763 | } |
| 763 | | 764 | |
| 764 | return slice; | 765 | return slice; |
| 765 | } | 766 | } |
| 766 | | 767 | |
| 767 | fn parseArray(self: *@This(), T: type, node: Zoir.Node.Index) !T { | 768 | fn parseArrayInto(self: *@This(), node: Zoir.Node.Index, out: anytype) !void { |
| 768 | const nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) { | 769 | const nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) { |
| 769 | .array_literal => |nodes| nodes, | 770 | .array_literal => |nodes| nodes, |
| 770 | .empty_literal => .{ .start = node, .len = 0 }, | 771 | .empty_literal => .{ .start = node, .len = 0 }, |
| 771 | else => return error.WrongType, | 772 | else => return error.WrongType, |
| 772 | }; | 773 | }; |
| 773 | | 774 | |
| 774 | const array_info = @typeInfo(T).array; | 775 | const array = @typeInfo(@TypeOf(out.*)).array; |
| 775 | | 776 | |
| 776 | // Check if the size matches | 777 | // Check if the size matches |
| 777 | if (nodes.len < array_info.len) { | 778 | if (nodes.len < array.len) { |
| 778 | return self.failNodeFmt( | 779 | return self.failNodeFmt( |
| 779 | node, | 780 | node, |
| 780 | "expected {} array elements; found {}", | 781 | "expected {} array elements; found {}", |
| 781 | .{ array_info.len, nodes.len }, | 782 | .{ array.len, nodes.len }, |
| 782 | ); | 783 | ); |
| 783 | } else if (nodes.len > array_info.len) { | 784 | } else if (nodes.len > array.len) { |
| 784 | return self.failNodeFmt( | 785 | return self.failNodeFmt( |
| 785 | nodes.at(array_info.len), | 786 | nodes.at(array.len), |
| 786 | "index {} outside of array of length {}", | 787 | "index {} outside of array of length {}", |
| 787 | .{ array_info.len, array_info.len }, | 788 | .{ array.len, array.len }, |
| 788 | ); | 789 | ); |
| 789 | } | 790 | } |
| 790 | | 791 | |
| 791 | // Parse the elements and return the array | 792 | // Parse the elements and return the array |
| 792 | var result: T = undefined; | 793 | inline for (out, 0..) |*elem, i| { |
| 793 | for (&result, 0..) |*elem, i| { | | |
| 794 | // If we fail to parse this field, free all fields before it | 794 | // If we fail to parse this field, free all fields before it |
| 795 | errdefer if (self.options.free_on_error) { | 795 | errdefer if (self.options.free_on_error) { |
| 796 | for (result[0..i]) |item| { | 796 | for (out[0..i]) |item| { |
| 797 | free(self.gpa, item); | 797 | free(self.gpa, item); |
| 798 | } | 798 | } |
| 799 | }; | 799 | }; |
| 800 | | 800 | |
| 801 | elem.* = try self.parseExpr(array_info.child, nodes.at(@intCast(i))); | 801 | try self.parseExprInto(nodes.at(@intCast(i)), elem); |
| | 802 | } |
| | 803 | |
| | 804 | if (array.sentinel()) |s| { |
| | 805 | out[array.len] = s; |
| 802 | } | 806 | } |
| 803 | if (array_info.sentinel()) |s| result[result.len] = s; | | |
| 804 | return result; | | |
| 805 | } | 807 | } |
| 806 | | 808 | |
| 807 | fn parseStruct(self: *@This(), T: type, node: Zoir.Node.Index) !T { | 809 | fn parseVectorInto(self: *@This(), node: Zoir.Node.Index, out: anytype) !void { |
| | 810 | const vector = @typeInfo(@TypeOf(out.*)).vector; |
| | 811 | var array: [vector.len]vector.child = undefined; |
| | 812 | try self.parseArrayInto(node, &array); |
| | 813 | out.* = array; |
| | 814 | } |
| | 815 | |
| | 816 | fn parseStructInto(self: *@This(), node: Zoir.Node.Index, out: anytype) !void { |
| 808 | const repr = node.get(self.zoir); | 817 | const repr = node.get(self.zoir); |
| 809 | const fields: @FieldType(Zoir.Node, "struct_literal") = switch (repr) { | 818 | const fields: @FieldType(Zoir.Node, "struct_literal") = switch (repr) { |
| 810 | .struct_literal => |nodes| nodes, | 819 | .struct_literal => |nodes| nodes, |
| ... | @@ -812,7 +821,7 @@ const Parser = struct { | ... | @@ -812,7 +821,7 @@ const Parser = struct { |
| 812 | else => return error.WrongType, | 821 | else => return error.WrongType, |
| 813 | }; | 822 | }; |
| 814 | | 823 | |
| 815 | const info = @typeInfo(T).@"struct"; | 824 | const info = @typeInfo(@TypeOf(out.*)).@"struct"; |
| 816 | | 825 | |
| 817 | // Build a map from field name to index. | 826 | // Build a map from field name to index. |
| 818 | // The special value `comptime_field` indicates that this is actually a comptime field. | 827 | // The special value `comptime_field` indicates that this is actually a comptime field. |
| ... | @@ -826,7 +835,6 @@ const Parser = struct { | ... | @@ -826,7 +835,6 @@ const Parser = struct { |
| 826 | }; | 835 | }; |
| 827 | | 836 | |
| 828 | // Parse the struct | 837 | // Parse the struct |
| 829 | var result: T = undefined; | | |
| 830 | var field_found: [info.field_names.len]bool = @splat(false); | 838 | var field_found: [info.field_names.len]bool = @splat(false); |
| 831 | | 839 | |
| 832 | // If we fail partway through, free all already initialized fields | 840 | // If we fail partway through, free all already initialized fields |
| ... | @@ -836,7 +844,7 @@ const Parser = struct { | ... | @@ -836,7 +844,7 @@ const Parser = struct { |
| 836 | switch (field_indices.get(name_runtime.get(self.zoir)) orelse continue) { | 844 | switch (field_indices.get(name_runtime.get(self.zoir)) orelse continue) { |
| 837 | inline 0...(info.field_names.len - 1) => |name_index| { | 845 | inline 0...(info.field_names.len - 1) => |name_index| { |
| 838 | const name = info.field_names[name_index]; | 846 | const name = info.field_names[name_index]; |
| 839 | free(self.gpa, @field(result, name)); | 847 | free(self.gpa, @field(out, name)); |
| 840 | }, | 848 | }, |
| 841 | else => unreachable, // Can't be out of bounds | 849 | else => unreachable, // Can't be out of bounds |
| 842 | } | 850 | } |
| ... | @@ -848,7 +856,7 @@ const Parser = struct { | ... | @@ -848,7 +856,7 @@ const Parser = struct { |
| 848 | const name = fields.names[i].get(self.zoir); | 856 | const name = fields.names[i].get(self.zoir); |
| 849 | const field_index = field_indices.get(name) orelse { | 857 | const field_index = field_indices.get(name) orelse { |
| 850 | if (self.options.ignore_unknown_fields) continue; | 858 | if (self.options.ignore_unknown_fields) continue; |
| 851 | return self.failUnexpected(T, "field", node, i, name); | 859 | return self.failUnexpected(@TypeOf(out.*), "field", node, i, name); |
| 852 | }; | 860 | }; |
| 853 | if (field_index == comptime_field) { | 861 | if (field_index == comptime_field) { |
| 854 | return self.failComptimeField(node, i); | 862 | return self.failComptimeField(node, i); |
| ... | @@ -863,9 +871,9 @@ const Parser = struct { | ... | @@ -863,9 +871,9 @@ const Parser = struct { |
| 863 | inline 0...(info.field_names.len - 1) => |j| { | 871 | inline 0...(info.field_names.len - 1) => |j| { |
| 864 | if (info.field_attrs[j].@"comptime") unreachable; | 872 | if (info.field_attrs[j].@"comptime") unreachable; |
| 865 | | 873 | |
| 866 | @field(result, info.field_names[j]) = try self.parseExpr( | 874 | try self.parseExprInto( |
| 867 | info.field_types[j], | | |
| 868 | fields.vals.at(@intCast(i)), | 875 | fields.vals.at(@intCast(i)), |
| | 876 | &@field(out, info.field_names[j]), |
| 869 | ); | 877 | ); |
| 870 | }, | 878 | }, |
| 871 | else => unreachable, // Can't be out of bounds | 879 | else => unreachable, // Can't be out of bounds |
| ... | @@ -879,7 +887,7 @@ const Parser = struct { | ... | @@ -879,7 +887,7 @@ const Parser = struct { |
| 879 | if (!found) { | 887 | if (!found) { |
| 880 | const field_attrs = info.field_attrs[i]; | 888 | const field_attrs = info.field_attrs[i]; |
| 881 | if (field_attrs.defaultValue(info.field_types[i])) |default| { | 889 | if (field_attrs.defaultValue(info.field_types[i])) |default| { |
| 882 | @field(result, info.field_names[i]) = default; | 890 | @field(out, info.field_names[i]) = default; |
| 883 | } else { | 891 | } else { |
| 884 | return self.failNodeFmt( | 892 | return self.failNodeFmt( |
| 885 | node, | 893 | node, |
| ... | @@ -889,19 +897,16 @@ const Parser = struct { | ... | @@ -889,19 +897,16 @@ const Parser = struct { |
| 889 | } | 897 | } |
| 890 | } | 898 | } |
| 891 | } | 899 | } |
| 892 | | | |
| 893 | return result; | | |
| 894 | } | 900 | } |
| 895 | | 901 | |
| 896 | fn parseTuple(self: *@This(), T: type, node: Zoir.Node.Index) !T { | 902 | fn parseTupleInto(self: *@This(), node: Zoir.Node.Index, out: anytype) !void { |
| 897 | const nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) { | 903 | const nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) { |
| 898 | .array_literal => |nodes| nodes, | 904 | .array_literal => |nodes| nodes, |
| 899 | .empty_literal => .{ .start = node, .len = 0 }, | 905 | .empty_literal => .{ .start = node, .len = 0 }, |
| 900 | else => return error.WrongType, | 906 | else => return error.WrongType, |
| 901 | }; | 907 | }; |
| 902 | | 908 | |
| 903 | var result: T = undefined; | 909 | const info = @typeInfo(@TypeOf(out.*)).@"struct"; |
| 904 | const info = @typeInfo(T).@"struct"; | | |
| 905 | | 910 | |
| 906 | if (nodes.len > info.field_names.len) { | 911 | if (nodes.len > info.field_names.len) { |
| 907 | return self.failNodeFmt( | 912 | return self.failNodeFmt( |
| ... | @@ -915,7 +920,7 @@ const Parser = struct { | ... | @@ -915,7 +920,7 @@ const Parser = struct { |
| 915 | // Check if we're out of bounds | 920 | // Check if we're out of bounds |
| 916 | if (i >= nodes.len) { | 921 | if (i >= nodes.len) { |
| 917 | if (info.field_attrs[i].defaultValue(info.field_types[i])) |default| { | 922 | if (info.field_attrs[i].defaultValue(info.field_types[i])) |default| { |
| 918 | @field(result, info.field_names[i]) = default; | 923 | @field(out.*, info.field_names[i]) = default; |
| 919 | } else { | 924 | } else { |
| 920 | return self.failNodeFmt(node, "missing tuple field with index {}", .{i}); | 925 | return self.failNodeFmt(node, "missing tuple field with index {}", .{i}); |
| 921 | } | 926 | } |
| ... | @@ -924,23 +929,21 @@ const Parser = struct { | ... | @@ -924,23 +929,21 @@ const Parser = struct { |
| 924 | errdefer if (self.options.free_on_error) { | 929 | errdefer if (self.options.free_on_error) { |
| 925 | inline for (0..i) |j| { | 930 | inline for (0..i) |j| { |
| 926 | if (j >= i) break; | 931 | if (j >= i) break; |
| 927 | free(self.gpa, result[j]); | 932 | free(self.gpa, out[j]); |
| 928 | } | 933 | } |
| 929 | }; | 934 | }; |
| 930 | | 935 | |
| 931 | if (info.field_attrs[i].@"comptime") { | 936 | if (info.field_attrs[i].@"comptime") { |
| 932 | return self.failComptimeField(node, i); | 937 | return self.failComptimeField(node, i); |
| 933 | } else { | 938 | } else { |
| 934 | result[i] = try self.parseExpr(info.field_types[i], nodes.at(i)); | 939 | try self.parseExprInto(nodes.at(i), &out[i]); |
| 935 | } | 940 | } |
| 936 | } | 941 | } |
| 937 | } | 942 | } |
| 938 | | | |
| 939 | return result; | | |
| 940 | } | 943 | } |
| 941 | | 944 | |
| 942 | fn parseUnion(self: *@This(), T: type, node: Zoir.Node.Index) !T { | 945 | fn parseUnionInto(self: *@This(), node: Zoir.Node.Index, out: anytype) !void { |
| 943 | const @"union" = @typeInfo(T).@"union"; | 946 | const @"union" = @typeInfo(@TypeOf(out.*)).@"union"; |
| 944 | | 947 | |
| 945 | if (@"union".field_names.len == 0) comptime unreachable; | 948 | if (@"union".field_names.len == 0) comptime unreachable; |
| 946 | | 949 | |
| ... | @@ -966,7 +969,7 @@ const Parser = struct { | ... | @@ -966,7 +969,7 @@ const Parser = struct { |
| 966 | const field_index = b: { | 969 | const field_index = b: { |
| 967 | const field_name_str = field_name.get(self.zoir); | 970 | const field_name_str = field_name.get(self.zoir); |
| 968 | break :b field_indices.get(field_name_str) orelse | 971 | break :b field_indices.get(field_name_str) orelse |
| 969 | return self.failUnexpected(T, "field", node, null, field_name_str); | 972 | return self.failUnexpected(@TypeOf(out.*), "field", node, null, field_name_str); |
| 970 | }; | 973 | }; |
| 971 | | 974 | |
| 972 | // Initialize the union from the given field. | 975 | // Initialize the union from the given field. |
| ... | @@ -977,7 +980,7 @@ const Parser = struct { | ... | @@ -977,7 +980,7 @@ const Parser = struct { |
| 977 | return self.failNode(node, "expected union"); | 980 | return self.failNode(node, "expected union"); |
| 978 | | 981 | |
| 979 | // Instantiate the union | 982 | // Instantiate the union |
| 980 | return @unionInit(T, @"union".field_names[i], {}); | 983 | out.* = @unionInit(@TypeOf(out.*), @"union".field_names[i], {}); |
| 981 | }, | 984 | }, |
| 982 | else => unreachable, // Can't be out of bounds | 985 | else => unreachable, // Can't be out of bounds |
| 983 | } | 986 | } |
| ... | @@ -992,15 +995,15 @@ const Parser = struct { | ... | @@ -992,15 +995,15 @@ const Parser = struct { |
| 992 | const field_name_str = field_name.get(self.zoir); | 995 | const field_name_str = field_name.get(self.zoir); |
| 993 | const field_val = struct_fields.vals.at(0); | 996 | const field_val = struct_fields.vals.at(0); |
| 994 | const field_index = field_indices.get(field_name_str) orelse | 997 | const field_index = field_indices.get(field_name_str) orelse |
| 995 | return self.failUnexpected(T, "field", node, 0, field_name_str); | 998 | return self.failUnexpected(@TypeOf(out.*), "field", node, 0, field_name_str); |
| 996 | | 999 | |
| 997 | switch (field_index) { | 1000 | switch (field_index) { |
| 998 | inline 0...@"union".field_names.len - 1 => |i| { | 1001 | inline 0...@"union".field_names.len - 1 => |i| { |
| 999 | if (@"union".field_types[i] == void) { | 1002 | if (@"union".field_types[i] == void) { |
| 1000 | return self.failNode(field_val, "expected type 'void'"); | 1003 | return self.failNode(field_val, "expected type 'void'"); |
| 1001 | } else { | 1004 | } else { |
| 1002 | const value = try self.parseExpr(@"union".field_types[i], field_val); | 1005 | out.* = @unionInit(@TypeOf(out.*), @"union".field_names[i], undefined); |
| 1003 | return @unionInit(T, @"union".field_names[i], value); | 1006 | try self.parseExprInto(field_val, &@field(out.*, @"union".field_names[i])); |
| 1004 | } | 1007 | } |
| 1005 | }, | 1008 | }, |
| 1006 | else => unreachable, // Can't be out of bounds | 1009 | else => unreachable, // Can't be out of bounds |