authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-09-30 14:02:25-07:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-09-30 14:02:25-07:00
logcab5fea319542aa09e824f8957bbd26eb1d54657
tree86499f371b0d6d4f6883b7ec5c5d6ba6c82815f6
parent19261544c62d5dab72654788f19e99b522fd46fa
parentaa0504ac574cafd3a6ff3cf716bac537fe3689d7
signature Commit is signed but in an unrecognized format.

Merge pull request https://codeberg.org/ziglang/zig/pulls/36204 into master


7 files changed, 2981 insertions(+), 1575 deletions(-)

lib/std/mem/Allocator.zig+21-1
......@@ -168,11 +168,31 @@ pub inline fn rawFree(a: Allocator, memory: []u8, alignment: Alignment, ret_addr
168168/// Returns a pointer to undefined memory.
169169/// Call `destroy` with the result to free the memory.
170170pub fn create(a: Allocator, comptime T: type) Error!*T {
171 return a.createAdvancedWithRetAddr(T, null, @returnAddress());
172}
173
174pub fn alignedCreate(
175 self: Allocator,
176 comptime T: type,
177 /// null means naturally aligned
178 comptime alignment: ?Alignment,
179) Error!*align(if (alignment) |a| a.toByteUnits() else @alignOf(T)) T {
180 return self.createAdvancedWithRetAddr(T, alignment, @returnAddress());
181}
182
183pub inline fn createAdvancedWithRetAddr(
184 self: Allocator,
185 comptime T: type,
186 /// null means naturally aligned
187 comptime alignment: ?Alignment,
188 return_address: usize,
189) Error!*align(if (alignment) |a| a.toByteUnits() else @alignOf(T)) T {
171190 if (@sizeOf(T) == 0) {
172191 const ptr = comptime std.mem.alignBackward(usize, math.maxInt(usize), @alignOf(T));
173192 return @ptrFromInt(ptr);
174193 }
175 const ptr: *T = @ptrCast(try a.allocBytesAligned(.of(T), @sizeOf(T), @returnAddress()));
194 const a: Alignment = alignment orelse comptime .of(T);
195 const ptr: *align(a.toByteUnits()) T = @ptrCast(try self.allocBytesAligned(a, @sizeOf(T), return_address));
176196 return ptr;
177197}
178198
lib/std/zig/ErrorBundle.zig+2-2
......@@ -634,7 +634,7 @@ pub const Wip = struct {
634634 const err_loc = std.zig.findLineColumn(source, err_span.main);
635635
636636 try eb.addRootErrorMessage(.{
637 .msg = try eb.addString(err.msg.get(zoir)),
637 .msg = try eb.addString(err.msg.get(&zoir)),
638638 .src_loc = try eb.addSourceLocation(.{
639639 .src_path = try eb.addString(src_path),
640640 .span_start = err_span.start,
......@@ -664,7 +664,7 @@ pub const Wip = struct {
664664
665665 // This line can cause `wip.extra.items` to be resized.
666666 const note_index = @backingInt(try eb.addErrorMessage(.{
667 .msg = try eb.addString(note.msg.get(zoir)),
667 .msg = try eb.addString(note.msg.get(&zoir)),
668668 .src_loc = try eb.addSourceLocation(.{
669669 .src_path = try eb.addString(src_path),
670670 .span_start = note_span.start,
lib/std/zig/Zoir.zig+6-6
......@@ -42,7 +42,7 @@ pub const Header = extern struct {
4242 }
4343};
4444
45pub fn hasCompileErrors(zoir: Zoir) bool {
45pub fn hasCompileErrors(zoir: *const Zoir) bool {
4646 if (zoir.compile_errors.len > 0) {
4747 assert(zoir.nodes.len == 0);
4848 assert(zoir.extra.len == 0);
......@@ -54,7 +54,7 @@ pub fn hasCompileErrors(zoir: Zoir) bool {
5454 }
5555}
5656
57pub fn deinit(zoir: Zoir, gpa: Allocator) void {
57pub fn deinit(zoir: *const Zoir, gpa: Allocator) void {
5858 var nodes = zoir.nodes;
5959 nodes.deinit(gpa);
6060
......@@ -105,7 +105,7 @@ pub const Node = union(enum) {
105105 root = 0,
106106 _,
107107
108 pub fn get(idx: Index, zoir: Zoir) Node {
108 pub fn get(idx: Index, zoir: *const Zoir) Node {
109109 const repr = zoir.nodes.get(@backingInt(idx));
110110 return switch (repr.tag) {
111111 .true => .true,
......@@ -151,7 +151,7 @@ pub const Node = union(enum) {
151151 };
152152 }
153153
154 pub fn getAstNode(idx: Index, zoir: Zoir) std.zig.Ast.Node.Index {
154 pub fn getAstNode(idx: Index, zoir: *const Zoir) std.zig.Ast.Node.Index {
155155 return zoir.nodes.items(.ast_node)[@backingInt(idx)];
156156 }
157157
......@@ -227,7 +227,7 @@ pub const Node = union(enum) {
227227
228228pub const NullTerminatedString = enum(u32) {
229229 _,
230 pub fn get(nts: NullTerminatedString, zoir: Zoir) [:0]const u8 {
230 pub fn get(nts: NullTerminatedString, zoir: *const Zoir) [:0]const u8 {
231231 const idx = std.mem.findScalar(u8, zoir.string_bytes[@backingInt(nts)..], 0).?;
232232 return zoir.string_bytes[@backingInt(nts)..][0..idx :0];
233233 }
......@@ -244,7 +244,7 @@ pub const CompileError = extern struct {
244244 first_note: u32,
245245 note_count: u32,
246246
247 pub fn getNotes(err: CompileError, zoir: Zoir) []const Note {
247 pub fn getNotes(err: CompileError, zoir: *const Zoir) []const Note {
248248 return zoir.error_notes[err.first_note..][0..err.note_count];
249249 }
250250
lib/std/zig/ZonGen.zig+4-4
......@@ -490,7 +490,7 @@ fn appendIdentStr(zg: *ZonGen, ident_token: Ast.TokenIndex) error{ OutOfMemory,
490490}
491491
492492/// Estimates the size of a string node without parsing it.
493pub fn strLitSizeHint(tree: Ast, node: Ast.Node.Index) usize {
493pub fn strLitSizeHint(tree: *const Ast, node: Ast.Node.Index) usize {
494494 switch (tree.nodeTag(node)) {
495495 // Parsed string literals are typically around the size of the raw strings.
496496 .string_literal => {
......@@ -515,7 +515,7 @@ pub fn strLitSizeHint(tree: Ast, node: Ast.Node.Index) usize {
515515
516516/// Parses the given node as a string literal.
517517pub fn parseStrLit(
518 tree: Ast,
518 tree: *const Ast,
519519 node: Ast.Node.Index,
520520 writer: *Writer,
521521) Writer.Error!std.zig.string_literal.Result {
......@@ -559,12 +559,12 @@ fn strLitAsString(zg: *ZonGen, str_node: Ast.Node.Index) error{ OutOfMemory, Bad
559559 const gpa = zg.gpa;
560560 const string_bytes = &zg.string_bytes;
561561 const str_index: u32 = @intCast(zg.string_bytes.items.len);
562 const size_hint = strLitSizeHint(zg.tree, str_node);
562 const size_hint = strLitSizeHint(&zg.tree, str_node);
563563 try string_bytes.ensureUnusedCapacity(gpa, size_hint);
564564 const result = r: {
565565 var aw: Writer.Allocating = .fromArrayList(gpa, &zg.string_bytes);
566566 defer zg.string_bytes = aw.toArrayList();
567 break :r parseStrLit(zg.tree, str_node, &aw.writer) catch |err| switch (err) {
567 break :r parseStrLit(&zg.tree, str_node, &aw.writer) catch |err| switch (err) {
568568 error.WriteFailed => return error.OutOfMemory,
569569 };
570570 };
lib/std/zon/parse.zig+2921-1535
......@@ -1,14 +1,13 @@
1//! The simplest way to parse ZON at runtime is to use `fromSlice`/`fromSliceAlloc`.
1//! Use `fromSlice`/`fromSlice` to parse a ZON string into a Zig value. Human readable errors
2//! are written to an out parameter.
23//!
3//! Note that if you need to parse ZON at compile time, you may use `@import`.
4//! If your data is already available in tree form, consider `fromZoir`/`fromZoir`.
45//!
5//! Parsing from individual Zoir nodes is also available:
6//! * `fromZoir`/`fromZoirAlloc`
7//! * `fromZoirNode`/`fromZoirNodeAlloc`
8//!
9//! For lower level control over parsing, see `std.zig.Zoir`.
6//! To parse into an existing value, see the `updateFrom*` variants. For lower level control over
7//! parsing, see `std.zig.ZonGen`. For importing ZON at compile time, use `@import`.
108
119const std = @import("std");
10const builtin = @import("builtin");
1211const Allocator = std.mem.Allocator;
1312const Ast = std.zig.Ast;
1413const Zoir = std.zig.Zoir;
......@@ -19,443 +18,474 @@ const StrLitErr = std.zig.string_literal.Error;
1918const NumberLiteralError = std.zig.number_literal.Error;
2019const assert = std.debug.assert;
2120const ArrayList = std.ArrayList;
21const ArenaAllocator = std.heap.ArenaAllocator;
2222
2323/// Rename when adding or removing support for a type.
2424const valid_types = {};
2525
26/// Configuration for the runtime parser.
27pub const Options = struct {
28 /// If true, unknown fields do not error.
29 ignore_unknown_fields: bool = false,
30 /// If true, the parser cleans up partially parsed values on error. This requires some extra
31 /// bookkeeping, so you may want to turn it off if you don't need this feature (e.g. because
32 /// you're using arena allocation.)
33 free_on_error: bool = true,
34};
26/// Errors encountered while parsing ZON. See `log` and `fatal` for reporting errors to the user.
27pub const Diagnostics = struct {
28 errors: []const Error,
3529
36pub const Error = union(enum) {
37 zoir: Zoir.CompileError,
38 type_check: Error.TypeCheckFailure,
39
40 pub const Note = union(enum) {
41 zoir: Zoir.CompileError.Note,
42 type_check: TypeCheckFailure.Note,
43
44 pub const Iterator = struct {
45 index: usize = 0,
46 err: Error,
47 diag: *const Diagnostics,
48
49 pub fn next(self: *@This()) ?Note {
50 switch (self.err) {
51 .zoir => |err| {
52 if (self.index >= err.note_count) return null;
53 const note = err.getNotes(self.diag.zoir)[self.index];
54 self.index += 1;
55 return .{ .zoir = note };
56 },
57 .type_check => |err| {
58 if (self.index >= err.getNoteCount()) return null;
59 const note = err.getNote(self.index);
60 self.index += 1;
61 return .{ .type_check = note };
62 },
63 }
64 }
30 /// Log the failure with `std.log.err`.
31 pub fn log(self: *const Diagnostics, path: []const u8) void {
32 std.log.err("{f}", .{self.fmt(path)});
33 }
34
35 test log {
36 const gpa = std.testing.allocator;
37 var arena_allocator: ArenaAllocator = .init(gpa);
38 defer arena_allocator.deinit();
39 const arena = arena_allocator.allocator();
40 var diagnostics: Diagnostics = undefined;
41
42 const MyType = struct {
43 foo: u32,
44 bar: u32,
6545 };
6646
67 fn formatMessage(self: []const u8, w: *std.Io.Writer) std.Io.Writer.Error!void {
68 // Just writes the string for now, but we're keeping this behind a formatter so we have
69 // the option to extend it in the future to print more advanced messages (like `Error`
70 // does) without breaking the API.
71 try w.writeAll(self);
72 }
47 const parsed: MyType = fromSliceNoAlloc(MyType, .{
48 .gpa = gpa,
49 .arena = arena,
50 .source = ".{ .foo = 1, .bar = 2 }",
51 .diagnostics = &diagnostics,
52 }) catch |err| switch (err) {
53 error.OutOfMemory => return error.OutOfMemory,
54 error.ParseZon => b: {
55 diagnostics.log("input.zon");
56 break :b .{ .foo = 0, .bar = 0 };
57 },
58 };
59 _ = parsed;
60 }
7361
74 pub fn fmtMessage(self: Note, diag: *const Diagnostics) std.fmt.Alt([]const u8, Note.formatMessage) {
75 return .{ .data = switch (self) {
76 .zoir => |note| note.msg.get(diag.zoir),
77 .type_check => |note| note.msg,
78 } };
79 }
62 /// Log the failure with `std.log.err`, and then terminate the process with exit code 1.
63 pub fn fatal(self: *const Diagnostics, path: []const u8) noreturn {
64 std.process.fatal("{f}", .{self.fmt(path)});
65 }
8066
81 pub fn getLocation(self: Note, diag: *const Diagnostics) Ast.Location {
82 switch (self) {
83 .zoir => |note| return zoirErrorLocation(diag.ast, note.token, note.node_or_offset),
84 .type_check => |note| return diag.ast.tokenLocation(note.offset, note.token),
85 }
67 test fatal {
68 const gpa = std.testing.allocator;
69 var arena_allocator: ArenaAllocator = .init(gpa);
70 defer arena_allocator.deinit();
71 const arena = arena_allocator.allocator();
72 var diagnostics: Diagnostics = undefined;
73
74 const MyType = struct {
75 foo: u32,
76 bar: u32,
77 };
78
79 const parsed = fromSliceNoAlloc(MyType, .{
80 .gpa = gpa,
81 .arena = arena,
82 .source = ".{ .foo = 1, .bar = 2 }",
83 .diagnostics = &diagnostics,
84 }) catch |err| switch (err) {
85 error.OutOfMemory => return error.OutOfMemory,
86 error.ParseZon => diagnostics.fatal("input.zon"),
87 };
88 _ = parsed;
89 }
90
91 /// Formats a human readable description of any errors.
92 pub fn fmt(self: *const Diagnostics, path: []const u8) Formatter {
93 return .{
94 .errors = self.errors,
95 .path = path,
96 };
97 }
98
99 fn astLoc(
100 ast: *const Ast,
101 maybe_token: Ast.OptionalTokenIndex,
102 node_or_offset: u32,
103 ) Ast.Location {
104 if (maybe_token.unwrap()) |token| {
105 var loc = ast.tokenLocation(0, token);
106 loc.column += node_or_offset;
107 return loc;
108 } else {
109 const ast_node: Ast.Node.Index = @fromBackingInt(@intCast(node_or_offset));
110 const token = ast.nodeMainToken(ast_node);
111 return ast.tokenLocation(0, token);
86112 }
87 };
113 }
88114
89 pub const Iterator = struct {
90 index: usize = 0,
91 diag: *const Diagnostics,
115 pub const Formatter = struct {
116 path: []const u8,
117 errors: []const Error,
92118
93 pub fn next(self: *@This()) ?Error {
94 if (self.index < self.diag.zoir.compile_errors.len) {
95 const result: Error = .{ .zoir = self.diag.zoir.compile_errors[self.index] };
96 self.index += 1;
97 return result;
98 }
119 pub fn format(self: *const @This(), w: *std.Io.Writer) std.Io.Writer.Error!void {
120 for (self.errors) |e| {
121 try w.print("{s}:", .{self.path});
122 try w.print("{d}:{d}: error: {s}\n", .{
123 e.loc.line + 1,
124 e.loc.column + 1,
125 e.msg,
126 });
99127
100 if (self.diag.type_check) |err| {
101 if (self.index == self.diag.zoir.compile_errors.len) {
102 const result: Error = .{ .type_check = err };
103 self.index += 1;
104 return result;
128 for (e.notes) |note| {
129 try w.print("{s}:", .{self.path});
130 try w.print("{d}:{d}: note: {s}\n", .{
131 note.loc.line + 1,
132 note.loc.column + 1,
133 note.msg,
134 });
105135 }
106136 }
107
108 return null;
109137 }
110138 };
111139
112 const TypeCheckFailure = struct {
113 const Note = struct {
114 token: Ast.TokenIndex,
115 offset: u32,
116 msg: []const u8,
117 owned: bool,
140 pub const Error = struct {
141 msg: []const u8,
142 loc: Ast.Location,
143 token: Ast.OptionalTokenIndex,
144 /// If `token == .none`, this is an `Ast.Node.Index`.
145 /// Otherwise, this is a byte offset into `token`.
146 node_or_offset: u32,
147 notes: []Note,
118148
119 fn deinit(self: @This(), gpa: Allocator) void {
120 if (self.owned) gpa.free(self.msg);
121 }
149 const Options = struct {
150 msg: []const u8,
151 token: Ast.OptionalTokenIndex,
152 node_or_offset: u32,
153 notes: []Note,
122154 };
123155
124 message: []const u8,
125 owned: bool,
126 token: Ast.TokenIndex,
127 offset: u32,
128 note: ?@This().Note,
129
130 fn deinit(self: @This(), gpa: Allocator) void {
131 if (self.note) |note| note.deinit(gpa);
132 if (self.owned) gpa.free(self.message);
156 fn init(ast: *const Ast, options: Error.Options) Error {
157 return .{
158 .msg = options.msg,
159 .loc = astLoc(ast, options.token, options.node_or_offset),
160 .token = options.token,
161 .node_or_offset = options.node_or_offset,
162 .notes = options.notes,
163 };
133164 }
165 };
134166
135 fn getNoteCount(self: @This()) usize {
136 return @intFromBool(self.note != null);
137 }
167 pub const Note = struct {
168 msg: []const u8,
169 loc: Ast.Location,
170 token: Ast.OptionalTokenIndex,
171 /// If `token == .none`, this is an `Ast.Node.Index`.
172 /// Otherwise, this is a byte offset into `token`.
173 node_or_offset: u32,
138174
139 fn getNote(self: @This(), index: usize) @This().Note {
140 assert(index == 0);
141 return self.note.?;
175 const Options = struct {
176 msg: []const u8,
177 token: Ast.OptionalTokenIndex,
178 node_or_offset: u32,
179 };
180
181 fn init(ast: *const Ast, options: Note.Options) @This() {
182 return .{
183 .msg = options.msg,
184 .loc = astLoc(ast, options.token, options.node_or_offset),
185 .token = options.token,
186 .node_or_offset = options.node_or_offset,
187 };
142188 }
143189 };
190};
144191
145 const FormatMessage = struct {
146 err: Error,
147 diag: *const Diagnostics,
148 };
192pub const Options = struct {
193 /// Used for scratch allocations.
194 gpa: Allocator,
195 /// Used for allocating diagnostics and results.
196 arena: Allocator,
197 /// The ZON source to parse.
198 source: [:0]const u8,
199 /// Initialized by the callee with a human readable description of any parse errors that
200 /// occured.
201 diagnostics: *Diagnostics,
202 /// If true, unknown fields do not error.
203 ignore_unknown_fields: bool = false,
204};
149205
150 fn formatMessage(self: FormatMessage, w: *std.Io.Writer) std.Io.Writer.Error!void {
151 switch (self.err) {
152 .zoir => |err| try w.writeAll(err.msg.get(self.diag.zoir)),
153 .type_check => |tc| try w.writeAll(tc.message),
154 }
155 }
206/// Parses the given slice as ZON, writing any errors to `options.diagnostics`.
207pub fn fromSlice(T: type, options: Options) error{ OutOfMemory, ParseZon }!T {
208 var value: T = undefined;
209 try fromSliceInner(T, &value, false, options);
210 return value;
211}
156212
157 pub fn fmtMessage(self: @This(), diag: *const Diagnostics) std.fmt.Alt(FormatMessage, formatMessage) {
158 return .{ .data = .{
159 .err = self,
160 .diag = diag,
161 } };
162 }
213test fromSlice {
214 const gpa = std.testing.allocator;
215 var arena_allocator: ArenaAllocator = .init(gpa);
216 defer arena_allocator.deinit();
217 const arena = arena_allocator.allocator();
218
219 const TextureOptions = struct {
220 const AddressMode = enum { clamp, reflect, wrap, zero };
221 address_mode: struct { u: AddressMode = .wrap, v: AddressMode = .wrap },
222 mipmaps: bool = true,
223 premultiply: bool = true,
224 };
163225
164 pub fn getLocation(self: @This(), diag: *const Diagnostics) Ast.Location {
165 return switch (self) {
166 .zoir => |err| return zoirErrorLocation(
167 diag.ast,
168 err.token,
169 err.node_or_offset,
170 ),
171 .type_check => |err| return diag.ast.tokenLocation(err.offset, err.token),
172 };
173 }
226 const source =
227 \\.{
228 \\ .address_mode = .{ .u = .clamp },
229 \\ .mipmaps = false,
230 \\}
231 ;
174232
175 pub fn iterateNotes(self: @This(), diag: *const Diagnostics) Note.Iterator {
176 return .{ .err = self, .diag = diag };
177 }
233 var diagnostics: Diagnostics = undefined;
234 const options = fromSlice(TextureOptions, .{
235 .gpa = gpa,
236 .arena = arena,
237 .source = source,
238 .diagnostics = &diagnostics,
239 }) catch |err| switch (err) {
240 error.OutOfMemory => return err,
241 error.ParseZon => {
242 diagnostics.log("texture_options.zon");
243 return err;
244 },
245 };
178246
179 fn zoirErrorLocation(ast: Ast, maybe_token: Ast.OptionalTokenIndex, node_or_offset: u32) Ast.Location {
180 if (maybe_token.unwrap()) |token| {
181 var location = ast.tokenLocation(0, token);
182 location.column += node_or_offset;
183 return location;
184 } else {
185 const ast_node: Ast.Node.Index = @fromBackingInt(@intCast(node_or_offset));
186 const token = ast.nodeMainToken(ast_node);
187 return ast.tokenLocation(0, token);
188 }
189 }
190};
247 try std.testing.expectEqualDeep(TextureOptions{
248 .address_mode = .{ .u = .clamp, .v = .wrap },
249 .mipmaps = false,
250 .premultiply = true,
251 }, options);
252}
191253
192/// Information about the success or failure of a parse.
193pub const Diagnostics = struct {
194 ast: Ast = .{
195 .source = "",
196 .tokens = .empty,
197 .nodes = .empty,
198 .extra_data = &.{},
199 .mode = .zon,
200 .errors = &.{},
201 },
202 zoir: Zoir = .{
203 .nodes = .empty,
204 .extra = &.{},
205 .limbs = &.{},
206 .string_bytes = &.{},
207 .compile_errors = &.{},
208 .error_notes = &.{},
209 },
210 type_check: ?Error.TypeCheckFailure = null,
211
212 fn assertEmpty(self: Diagnostics) void {
213 assert(self.ast.tokens.len == 0);
214 assert(self.zoir.nodes.len == 0);
215 assert(self.type_check == null);
216 }
217
218 pub fn deinit(self: *Diagnostics, gpa: Allocator) void {
219 self.ast.deinit(gpa);
220 self.zoir.deinit(gpa);
221 if (self.type_check) |tc| tc.deinit(gpa);
222 self.* = undefined;
223 }
224
225 pub fn iterateErrors(self: *const Diagnostics) Error.Iterator {
226 return .{ .diag = self };
227 }
228
229 pub fn format(self: *const @This(), w: *std.Io.Writer) std.Io.Writer.Error!void {
230 var errors = self.iterateErrors();
231 while (errors.next()) |err| {
232 const loc = err.getLocation(self);
233 const msg = err.fmtMessage(self);
234 try w.print("{d}:{d}: error: {f}\n", .{ loc.line + 1, loc.column + 1, msg });
235
236 var notes = err.iterateNotes(self);
237 while (notes.next()) |note| {
238 const note_loc = note.getLocation(self);
239 const note_msg = note.fmtMessage(self);
240 try w.print("{d}:{d}: note: {f}\n", .{
241 note_loc.line + 1,
242 note_loc.column + 1,
243 note_msg,
244 });
245 }
246 }
247 }
248};
254/// Like `fromSlice` but the result type may not contain pointers, allowing it to outlive
255/// `options.arena`.
256pub fn fromSliceNoAlloc(T: type, options: Options) error{ OutOfMemory, ParseZon }!T {
257 comptime assert(!requiresAllocator(T));
258 return fromSlice(T, options);
259}
249260
250/// Parses the given slice as ZON.
251///
252/// Returns `error.OutOfMemory` on allocation failure, or `error.ParseZon` error if the ZON is
253/// invalid or can not be deserialized into type `T`.
254///
255/// When the parser returns `error.ParseZon`, it will also store a human readable explanation in
256/// `diag` if non null. If diag is not null, it must be initialized to `.{}`.
257///
258/// Asserts at compile time that the result type doesn't contain pointers. As such, the result
259/// doesn't need to be freed.
261/// Similar to `fromSlice`, but updates the existing contents of `value` in place. Fields
262/// unspecified by ZON are left unchanged.
260263///
261/// An allocator is still required for temporary allocations made during parsing.
262pub fn fromSlice(
264/// Assumes that `value` points to a fully initialized value prior to this call. Slices and untagged
265/// unions are replaced in their entirey when specified. On error, `value` remains valid, but may be
266/// partially updated.
267pub fn updateFromSlice(
263268 T: type,
264 gpa: Allocator,
265 source: [:0]const u8,
266 diag: ?*Diagnostics,
269 value: *T,
267270 options: Options,
268) error{ OutOfMemory, ParseZon }!T {
269 comptime assert(!requiresAllocator(T));
270 return fromSliceAlloc(T, gpa, source, diag, options);
271) error{ OutOfMemory, ParseZon }!void {
272 try fromSliceInner(T, value, true, options);
271273}
272274
273/// Like `fromSlice`, but the result may contain pointers. To automatically free the result, see
274/// `free`.
275pub 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 T: type,
289 gpa: Allocator,
290 source: [:0]const u8,
291 diag: ?*Diagnostics,
292 options: Options,
293) error{ OutOfMemory, ParseZon }!T {
294 if (diag) |s| s.assertEmpty();
275test updateFromSlice {
276 const gpa = std.testing.allocator;
277 var arena_allocator: ArenaAllocator = .init(gpa);
278 defer arena_allocator.deinit();
279 const arena = arena_allocator.allocator();
280
281 const MyTextEditorConfig = struct {
282 indentation: enum { spaces, tabs },
283 columns: []const u16,
284 dark_mode: enum { auto, dark, light },
285 theme: []const u8,
286 };
295287
296 var ast = try std.zig.Ast.parse(gpa, source, .{ .mode = .zon });
297 defer if (diag == null) ast.deinit(gpa);
298 if (diag) |s| s.ast = ast;
288 const global_config =
289 \\.{
290 \\ .indentation = .spaces,
291 \\ .columns = .{ 100 },
292 \\ .dark_mode = .dark,
293 \\}
294 ;
295 const project_config =
296 \\.{
297 \\ .indentation = .tabs,
298 \\}
299 ;
300
301 var config: MyTextEditorConfig = .{
302 .indentation = .spaces,
303 .columns = &.{},
304 .dark_mode = .auto,
305 .theme = "default",
306 };
299307
300 // If there's no diagnostics, Zoir exists for the lifetime of this function. If there is a
301 // 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);
308 var diagnostics: Diagnostics = undefined;
309 updateFromSlice(MyTextEditorConfig, &config, .{
310 .gpa = gpa,
311 .arena = arena,
312 .source = global_config,
313 .diagnostics = &diagnostics,
314 }) catch |err| switch (err) {
315 error.OutOfMemory => return err,
316 error.ParseZon => {
317 diagnostics.log("global_config.zon");
318 return err;
319 },
320 };
321 updateFromSlice(MyTextEditorConfig, &config, .{
322 .gpa = gpa,
323 .arena = arena,
324 .source = project_config,
325 .diagnostics = &diagnostics,
326 }) catch |err| switch (err) {
327 error.OutOfMemory => return err,
328 error.ParseZon => {
329 diagnostics.log("project_config.zon");
330 return err;
331 },
332 };
304333
305 if (diag) |s| s.* = .{};
306 return fromZoirAlloc(T, gpa, ast, zoir, diag, options);
334 try std.testing.expectEqualDeep(MyTextEditorConfig{
335 .indentation = .tabs,
336 .columns = &.{100},
337 .dark_mode = .dark,
338 .theme = "default",
339 }, config);
307340}
308341
309/// Like `fromSlice`, but operates on `Zoir` instead of ZON source.
310pub fn fromZoir(
342/// Like `updateFromSlice` but the `T` may not contain pointers, allowing `value` to outlive
343/// `options.arena`.
344pub fn updateFromSliceNoAlloc(
311345 T: type,
312 ast: Ast,
313 zoir: Zoir,
314 diag: ?*Diagnostics,
346 value: *T,
315347 options: Options,
316) error{ParseZon}!T {
348) error{ OutOfMemory, ParseZon }!void {
317349 comptime assert(!requiresAllocator(T));
318 var buf: [0]u8 = .{};
319 var failing_allocator = std.heap.FixedBufferAllocator.init(&buf);
320 return fromZoirAlloc(
321 T,
322 failing_allocator.allocator(),
323 ast,
324 zoir,
325 diag,
326 options,
327 ) catch |err| switch (err) {
328 error.OutOfMemory => unreachable, // Checked by comptime assertion above
329 else => |e| return e,
330 };
350 try fromSliceInner(T, value, true, options);
331351}
332352
333/// Like `fromSliceAlloc`, but operates on `Zoir` instead of ZON source.
334pub fn fromZoirAlloc(
353fn fromSliceInner(
335354 T: type,
336 gpa: Allocator,
337 ast: Ast,
338 zoir: Zoir,
339 diag: ?*Diagnostics,
355 value: *T,
356 initialized: bool,
340357 options: Options,
341) error{ OutOfMemory, ParseZon }!T {
342 return fromZoirNodeAlloc(T, gpa, ast, zoir, .root, diag, options);
358) error{ OutOfMemory, ParseZon }!void {
359 var errors: std.ArrayList(Diagnostics.Error) = .empty;
360 defer options.diagnostics.* = .{ .errors = errors.items };
361
362 var ast = try std.zig.Ast.parse(options.gpa, options.source, .{ .mode = .zon });
363 defer ast.deinit(options.gpa);
364
365 var zoir = try ZonGen.generate(options.gpa, ast, .{ .parse_str_lits = false });
366 defer zoir.deinit(options.gpa);
367
368 try inner(T, value, initialized, .{
369 .arena = options.arena,
370 .ast = &ast,
371 .zoir = &zoir,
372 .node = .root,
373 .errors = &errors,
374 .ignore_unknown_fields = options.ignore_unknown_fields,
375 });
376}
377
378pub const FromZoirOptions = struct {
379 /// Used for allocating diagnostics and results.
380 arena: Allocator,
381 /// The AST for this ZON value.
382 ast: *const Ast,
383 /// The zig object intermediate representation of this ZON value.
384 zoir: *const Zoir,
385 /// The node to start parsing at.
386 node: Zoir.Node.Index = .root,
387 /// Initialized by the callee with a human readable description of any parse errors that
388 /// occured.
389 diagnostics: *Diagnostics,
390 /// If true, unknown fields do not error.
391 ignore_unknown_fields: bool = false,
392};
393
394/// Like `fromSlice`, but operates on `Zoir` instead of ZON source.
395pub fn fromZoir(T: type, options: FromZoirOptions) error{ OutOfMemory, ParseZon }!T {
396 var value: T = undefined;
397 try fromZoirInner(T, &value, false, options);
398 return value;
343399}
344400
345/// Like `fromZoir`, but the parse starts at `node` instead of root.
346pub fn fromZoirNode(
401/// Like `fromSliceNoAlloc`, but operates on `Zoir` instead of ZON source.
402pub fn fromZoirNoAlloc(T: type, options: FromZoirOptions) error{ OutOfMemory, ParseZon }!T {
403 comptime assert(!requiresAllocator(T));
404 return fromZoir(T, options);
405}
406
407/// Like `updateFromSlice`, but operates on `Zoir` instead of ZON source.
408pub fn updateFromZoir(
347409 T: type,
348 ast: Ast,
349 zoir: Zoir,
350 node: Zoir.Node.Index,
351 diag: ?*Diagnostics,
352 options: Options,
353) error{ParseZon}!T {
410 value: *T,
411 options: FromZoirOptions,
412) error{ OutOfMemory, ParseZon }!void {
413 return fromZoirInner(T, value, true, options);
414}
415
416/// Like `updateFromSliceNoAlloc`, but operates on `Zoir` instead of ZON source.
417pub fn updateFromZoirNoAlloc(
418 T: type,
419 value: *T,
420 options: FromZoirOptions,
421) error{ OutOfMemory, ParseZon }!void {
354422 comptime assert(!requiresAllocator(T));
355 var buf: [0]u8 = .{};
356 var failing_allocator = std.heap.FixedBufferAllocator.init(&buf);
357 return fromZoirNodeAlloc(
358 T,
359 failing_allocator.allocator(),
360 ast,
361 zoir,
362 node,
363 diag,
364 options,
365 ) catch |err| switch (err) {
366 error.OutOfMemory => unreachable, // Checked by comptime assertion above
367 else => |e| return e,
368 };
423 return updateFromZoir(T, value, options);
369424}
370425
371/// Like `fromZoirAlloc`, but the parse starts at `node` instead of root.
372pub fn fromZoirNodeAlloc(
426fn fromZoirInner(
373427 T: type,
374 gpa: Allocator,
375 ast: Ast,
376 zoir: Zoir,
377 node: Zoir.Node.Index,
378 diag: ?*Diagnostics,
379 options: Options,
380) error{ OutOfMemory, ParseZon }!T {
381 comptime assert(canParseType(T));
428 value: *T,
429 initialized: bool,
430 options: FromZoirOptions,
431) error{ OutOfMemory, ParseZon }!void {
432 var errors: std.ArrayList(Diagnostics.Error) = .empty;
433 defer options.diagnostics.* = .{ .errors = errors.items };
434 return inner(T, value, initialized, .{
435 .arena = options.arena,
436 .ast = options.ast,
437 .zoir = options.zoir,
438 .errors = &errors,
439 .ignore_unknown_fields = options.ignore_unknown_fields,
440 });
441}
382442
383 if (diag) |s| {
384 s.assertEmpty();
385 s.ast = ast;
386 s.zoir = zoir;
387 }
443const InnerOptions = struct {
444 arena: Allocator,
445 ast: *const Ast,
446 zoir: *const Zoir,
447 node: Zoir.Node.Index = .root,
448 errors: *std.ArrayList(Diagnostics.Error),
449 ignore_unknown_fields: bool,
450};
451
452fn inner(
453 T: type,
454 value: *T,
455 initialized: bool,
456 options: InnerOptions,
457) error{ OutOfMemory, ParseZon }!void {
458 comptime assert(canParseType(T));
388459
389 if (zoir.hasCompileErrors()) {
460 if (options.zoir.hasCompileErrors()) {
461 for (options.zoir.compile_errors) |e| {
462 var notes: std.ArrayList(Diagnostics.Note) = .empty;
463 for (e.getNotes(options.zoir)) |note| {
464 try notes.append(options.arena, .init(options.ast, .{
465 .msg = try options.arena.dupe(u8, note.msg.get(options.zoir)),
466 .token = note.token,
467 .node_or_offset = note.node_or_offset,
468 }));
469 }
470 try options.errors.append(options.arena, .init(options.ast, .{
471 .msg = try options.arena.dupe(u8, e.msg.get(options.zoir)),
472 .token = e.token,
473 .node_or_offset = e.node_or_offset,
474 .notes = notes.items,
475 }));
476 }
390477 return error.ParseZon;
391478 }
392479
393480 var parser: Parser = .{
394 .gpa = gpa,
395 .ast = ast,
396 .zoir = zoir,
397 .options = options,
398 .diag = diag,
481 .arena = options.arena,
482 .ast = options.ast,
483 .zoir = options.zoir,
484 .ignore_unknown_fields = options.ignore_unknown_fields,
485 .errors = options.errors,
399486 };
400487
401 return parser.parseExpr(T, node);
402}
403
404/// Frees ZON values.
405///
406/// Provided for convenience, you may also free these values on your own using the same allocator
407/// passed into the parser.
408///
409/// Asserts at comptime that sufficient information is available via the type system to free this
410/// value. Untagged unions, for example, will fail this assert.
411pub fn free(gpa: Allocator, value: anytype) void {
412 const Value = @TypeOf(value);
413
414 _ = valid_types;
415 switch (@typeInfo(Value)) {
416 .bool, .int, .float, .@"enum" => {},
417 .pointer => |pointer| {
418 switch (pointer.size) {
419 .one => {
420 free(gpa, value.*);
421 gpa.destroy(value);
422 },
423 .slice => {
424 for (value) |item| {
425 free(gpa, item);
426 }
427 gpa.free(value);
428 },
429 .many, .c => comptime unreachable,
430 }
431 },
432 .array => {
433 freeArray(gpa, @TypeOf(value), &value);
434 },
435 .vector => |vector| {
436 const array: [vector.len]vector.child = value;
437 freeArray(gpa, @TypeOf(array), &array);
438 },
439 .@"struct" => |@"struct"| inline for (@"struct".field_names) |field_name| {
440 free(gpa, @field(value, field_name));
441 },
442 .@"union" => |@"union"| if (@"union".tag_type == null) {
443 if (comptime requiresAllocator(Value)) unreachable;
444 } else switch (value) {
445 inline else => |_, tag| {
446 free(gpa, @field(value, @tagName(tag)));
447 },
448 },
449 .optional => if (value) |some| {
450 free(gpa, some);
451 },
452 .void => {},
453 else => comptime unreachable,
454 }
455}
456
457fn freeArray(gpa: Allocator, comptime A: type, array: *const A) void {
458 for (array) |elem| free(gpa, elem);
488 try parser.parseExprInto(options.node, value, initialized);
459489}
460490
461491fn requiresAllocator(T: type) bool {
......@@ -480,62 +510,93 @@ fn requiresAllocator(T: type) bool {
480510}
481511
482512const Parser = struct {
483 gpa: Allocator,
484 ast: Ast,
485 zoir: Zoir,
486 diag: ?*Diagnostics,
487 options: Options,
513 arena: Allocator,
514 ast: *const Ast,
515 zoir: *const Zoir,
516 errors: *std.ArrayList(Diagnostics.Error),
517 ignore_unknown_fields: bool,
488518
489519 const ParseExprError = error{ ParseZon, OutOfMemory };
490520
491 fn parseExpr(self: *@This(), T: type, node: Zoir.Node.Index) ParseExprError!T {
492 return self.parseExprInner(T, node) catch |err| switch (err) {
493 error.WrongType => return self.failExpectedType(T, node),
521 fn parseExprInto(
522 self: *Parser,
523 node: Zoir.Node.Index,
524 out: anytype,
525 initialized: bool,
526 ) ParseExprError!void {
527 return self.parseExprIntoInner(node, out, initialized) catch |err| switch (err) {
528 error.WrongType => return self.failExpectedType(@TypeOf(out.*), node),
494529 else => |e| return e,
495530 };
496531 }
497532
498533 const ParseExprInnerError = error{ ParseZon, OutOfMemory, WrongType };
499534
500 fn parseExprInner(
535 fn parseExprIntoInner(
501536 self: *@This(),
502 T: type,
503537 node: Zoir.Node.Index,
504 ) ParseExprInnerError!T {
505 if (T == Zoir.Node.Index) {
506 return node;
538 out: anytype,
539 initialized: bool,
540 ) ParseExprInnerError!void {
541 if (@TypeOf(out.*) == Zoir.Node.Index) {
542 out.* = node;
543 return;
507544 }
508545
509 switch (@typeInfo(T)) {
546 switch (@typeInfo(@TypeOf(out.*))) {
510547 .optional => |optional| if (node.get(self.zoir) == .null) {
511 return null;
548 out.* = null;
549 } else if (initialized and out.* != null) {
550 try self.parseExprIntoInner(node, &out.*.?, true);
512551 } else {
513 return try self.parseExprInner(optional.child, node);
552 var some: optional.child = undefined;
553 try self.parseExprIntoInner(node, &some, false);
554 out.* = some;
514555 },
515 .bool => return self.parseBool(node),
516 .int => return self.parseInt(T, node),
517 .float => return self.parseFloat(T, node),
518 .@"enum" => return self.parseEnumLiteral(T, node),
556 .bool => out.* = try self.parseBool(node),
557 .int => out.* = try self.parseInt(@TypeOf(out.*), node),
558 .float => out.* = try self.parseFloat(@TypeOf(out.*), node),
559 .@"enum" => out.* = try self.parseEnumLiteral(@TypeOf(out.*), node),
519560 .pointer => |pointer| switch (pointer.size) {
520561 .one => {
521 const result = try self.gpa.create(pointer.child);
522 errdefer self.gpa.destroy(result);
523 result.* = try self.parseExprInner(pointer.child, node);
524 return result;
562 // Get a pointer to update
563 const new = b: {
564 // If the existing value is initialized and non const, use it
565 if (initialized and !pointer.attrs.@"const") break :b out.*;
566 // Otherwise, allocate new memory
567 const new = try self.arena.alignedCreate(
568 pointer.child,
569 if (pointer.attrs.@"align") |a| .fromByteUnits(a) else null,
570 );
571 // If the original value was initialized, dupe it into the new memory
572 if (initialized) new.* = out.*.*;
573 break :b new;
574 };
575 try self.parseExprIntoInner(
576 node,
577 new,
578 initialized,
579 );
580 out.* = new;
581 },
582 .slice => {
583 // Slices are replaced wholesale since ZON doesn't have syntax for specifying
584 // just a part of a slice.
585 const new = b: {
586 const new = try self.parseSlicePointer(@TypeOf(out.*), node);
587 break :b new;
588 };
589 out.* = new;
525590 },
526 .slice => return self.parseSlicePointer(T, node),
527591 else => comptime unreachable,
528592 },
529 .array => return self.parseArray(T, node),
530 .vector => |vector| {
531 const A = [vector.len]vector.child;
532 return try self.parseArray(A, node);
533 },
593 .array => try self.parseArrayInto(node, out),
594 .vector => try self.parseVectorInto(node, out),
534595 .@"struct" => |@"struct"| if (@"struct".is_tuple)
535 return self.parseTuple(T, node)
596 try self.parseTupleInto(node, out)
536597 else
537 return self.parseStruct(T, node),
538 .@"union" => return self.parseUnion(T, node),
598 try self.parseStructInto(node, out, initialized),
599 .@"union" => try self.parseUnionInto(node, out, initialized),
539600
540601 else => comptime unreachable,
541602 }
......@@ -545,7 +606,7 @@ const Parser = struct {
545606 /// example, `**?**u8` becomes `?u8`, and types that involve user specified type names are just
546607 /// referred to by the type of container.
547608 fn failExpectedType(
548 self: @This(),
609 self: Parser,
549610 T: type,
550611 node: Zoir.Node.Index,
551612 ) error{ ParseZon, OutOfMemory } {
......@@ -554,7 +615,7 @@ const Parser = struct {
554615 }
555616
556617 fn failExpectedTypeInner(
557 self: @This(),
618 self: Parser,
558619 T: type,
559620 opt: bool,
560621 node: Zoir.Node.Index,
......@@ -624,7 +685,7 @@ const Parser = struct {
624685 }
625686 }
626687
627 fn parseBool(self: @This(), node: Zoir.Node.Index) !bool {
688 fn parseBool(self: Parser, node: Zoir.Node.Index) !bool {
628689 switch (node.get(self.zoir)) {
629690 .true => return true,
630691 .false => return false,
......@@ -632,7 +693,7 @@ const Parser = struct {
632693 }
633694 }
634695
635 fn parseInt(self: @This(), T: type, node: Zoir.Node.Index) !T {
696 fn parseInt(self: Parser, T: type, node: Zoir.Node.Index) !T {
636697 switch (node.get(self.zoir)) {
637698 .int_literal => |int| switch (int) {
638699 .small => |val| return std.math.cast(T, val) orelse
......@@ -649,7 +710,7 @@ const Parser = struct {
649710 }
650711 }
651712
652 fn parseFloat(self: @This(), T: type, node: Zoir.Node.Index) !T {
713 fn parseFloat(self: Parser, T: type, node: Zoir.Node.Index) !T {
653714 switch (node.get(self.zoir)) {
654715 .int_literal => |int| switch (int) {
655716 .small => |val| return @floatFromInt(val),
......@@ -664,7 +725,7 @@ const Parser = struct {
664725 }
665726 }
666727
667 fn parseEnumLiteral(self: @This(), T: type, node: Zoir.Node.Index) !T {
728 fn parseEnumLiteral(self: Parser, T: type, node: Zoir.Node.Index) !T {
668729 switch (node.get(self.zoir)) {
669730 .enum_literal => |field_name| {
670731 // Create a comptime string map for the enum fields
......@@ -684,7 +745,7 @@ const Parser = struct {
684745 }
685746 }
686747
687 fn parseSlicePointer(self: *@This(), T: type, node: Zoir.Node.Index) ParseExprInnerError!T {
748 fn parseSlicePointer(self: *Parser, T: type, node: Zoir.Node.Index) ParseExprInnerError!T {
688749 switch (node.get(self.zoir)) {
689750 .string_literal => return self.parseString(T, node),
690751 .array_literal => |nodes| return self.parseSlice(T, nodes),
......@@ -693,13 +754,13 @@ const Parser = struct {
693754 }
694755 }
695756
696 fn parseString(self: *@This(), T: type, node: Zoir.Node.Index) ParseExprInnerError!T {
757 fn parseString(self: *Parser, T: type, node: Zoir.Node.Index) ParseExprInnerError!T {
697758 const ast_node = node.getAstNode(self.zoir);
698759 const pointer = @typeInfo(T).pointer;
699760 var size_hint = ZonGen.strLitSizeHint(self.ast, ast_node);
700761 if (pointer.sentinel() != null) size_hint += 1;
701762
702 var aw: std.Io.Writer.Allocating = .init(self.gpa);
763 var aw: std.Io.Writer.Allocating = .init(self.arena);
703764 try aw.ensureUnusedCapacity(size_hint);
704765 defer aw.deinit();
705766 const result = ZonGen.parseStrLit(self.ast, ast_node, &aw.writer) catch return error.OutOfMemory;
......@@ -728,7 +789,7 @@ const Parser = struct {
728789 }
729790 }
730791
731 fn parseSlice(self: *@This(), T: type, nodes: Zoir.Node.Index.Range) !T {
792 fn parseSlice(self: *Parser, T: type, nodes: Zoir.Node.Index.Range) !T {
732793 const pointer = @typeInfo(T).pointer;
733794
734795 // Make sure we're working with a slice
......@@ -738,68 +799,68 @@ const Parser = struct {
738799 }
739800
740801 // Allocate the slice
741 const slice = try self.gpa.allocWithOptions(
802 const slice = try self.arena.allocWithOptions(
742803 pointer.child,
743804 nodes.len,
744805 .fromByteUnitsOptional(pointer.attrs.@"align"),
745806 pointer.sentinel(),
746807 );
747 errdefer self.gpa.free(slice);
748808
749809 // Parse the elements and return the slice
750810 for (slice, 0..) |*elem, i| {
751 errdefer if (self.options.free_on_error) {
752 for (slice[0..i]) |item| {
753 free(self.gpa, item);
754 }
755 };
756 elem.* = try self.parseExpr(pointer.child, nodes.at(@intCast(i)));
811 try self.parseExprInto(nodes.at(@intCast(i)), elem, false);
757812 }
758813
759814 return slice;
760815 }
761816
762 fn parseArray(self: *@This(), T: type, node: Zoir.Node.Index) !T {
817 fn parseArrayInto(self: *Parser, node: Zoir.Node.Index, out: anytype) !void {
763818 const nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) {
764819 .array_literal => |nodes| nodes,
765820 .empty_literal => .{ .start = node, .len = 0 },
766821 else => return error.WrongType,
767822 };
768823
769 const array_info = @typeInfo(T).array;
824 const array = @typeInfo(@TypeOf(out.*)).array;
770825
771826 // Check if the size matches
772 if (nodes.len < array_info.len) {
827 if (nodes.len < array.len) {
773828 return self.failNodeFmt(
774829 node,
775830 "expected {} array elements; found {}",
776 .{ array_info.len, nodes.len },
831 .{ array.len, nodes.len },
777832 );
778 } else if (nodes.len > array_info.len) {
833 } else if (nodes.len > array.len) {
779834 return self.failNodeFmt(
780 nodes.at(array_info.len),
835 nodes.at(array.len),
781836 "index {} outside of array of length {}",
782 .{ array_info.len, array_info.len },
837 .{ array.len, array.len },
783838 );
784839 }
785840
786841 // Parse the elements and return the array
787 var result: T = undefined;
788 for (&result, 0..) |*elem, i| {
789 // If we fail to parse this field, free all fields before it
790 errdefer if (self.options.free_on_error) {
791 for (result[0..i]) |item| {
792 free(self.gpa, item);
793 }
794 };
842 for (out, 0..) |*elem, i| {
843 try self.parseExprInto(nodes.at(@intCast(i)), elem, false);
844 }
795845
796 elem.* = try self.parseExpr(array_info.child, nodes.at(@intCast(i)));
846 if (array.sentinel()) |s| {
847 out[array.len] = s;
797848 }
798 if (array_info.sentinel()) |s| result[result.len] = s;
799 return result;
800849 }
801850
802 fn parseStruct(self: *@This(), T: type, node: Zoir.Node.Index) !T {
851 fn parseVectorInto(self: *Parser, node: Zoir.Node.Index, out: anytype) !void {
852 const vector = @typeInfo(@TypeOf(out.*)).vector;
853 var array: [vector.len]vector.child = undefined;
854 try self.parseArrayInto(node, &array);
855 out.* = array;
856 }
857
858 fn parseStructInto(
859 self: *Parser,
860 node: Zoir.Node.Index,
861 out: anytype,
862 initialized: bool,
863 ) !void {
803864 const repr = node.get(self.zoir);
804865 const fields: @FieldType(Zoir.Node, "struct_literal") = switch (repr) {
805866 .struct_literal => |nodes| nodes,
......@@ -807,7 +868,7 @@ const Parser = struct {
807868 else => return error.WrongType,
808869 };
809870
810 const info = @typeInfo(T).@"struct";
871 const info = @typeInfo(@TypeOf(out.*)).@"struct";
811872
812873 // Build a map from field name to index.
813874 // The special value `comptime_field` indicates that this is actually a comptime field.
......@@ -821,29 +882,12 @@ const Parser = struct {
821882 };
822883
823884 // Parse the struct
824 var result: T = undefined;
825885 var field_found: [info.field_names.len]bool = @splat(false);
826
827 // If we fail partway through, free all already initialized fields
828 var initialized: usize = 0;
829 errdefer if (self.options.free_on_error and info.field_names.len > 0) {
830 for (fields.names[0..initialized]) |name_runtime| {
831 switch (field_indices.get(name_runtime.get(self.zoir)) orelse continue) {
832 inline 0...(info.field_names.len - 1) => |name_index| {
833 const name = info.field_names[name_index];
834 free(self.gpa, @field(result, name));
835 },
836 else => unreachable, // Can't be out of bounds
837 }
838 }
839 };
840
841 // Fill in the fields we found
842886 for (0..fields.names.len) |i| {
843887 const name = fields.names[i].get(self.zoir);
844888 const field_index = field_indices.get(name) orelse {
845 if (self.options.ignore_unknown_fields) continue;
846 return self.failUnexpected(T, "field", node, i, name);
889 if (self.ignore_unknown_fields) continue;
890 return self.failUnexpected(@TypeOf(out.*), "field", node, i, name);
847891 };
848892 if (field_index == comptime_field) {
849893 return self.failComptimeField(node, i);
......@@ -857,46 +901,43 @@ const Parser = struct {
857901 switch (field_index) {
858902 inline 0...(info.field_names.len - 1) => |j| {
859903 if (info.field_attrs[j].@"comptime") unreachable;
860
861 @field(result, info.field_names[j]) = try self.parseExpr(
862 info.field_types[j],
904 try self.parseExprInto(
863905 fields.vals.at(@intCast(i)),
906 &@field(out, info.field_names[j]),
907 initialized,
864908 );
865909 },
866910 else => unreachable, // Can't be out of bounds
867911 }
868
869 initialized += 1;
870912 }
871913
872914 // Fill in any missing default fields
873 inline for (field_found, 0..) |found, i| {
874 if (!found) {
875 const field_attrs = info.field_attrs[i];
876 if (field_attrs.defaultValue(info.field_types[i])) |default| {
877 @field(result, info.field_names[i]) = default;
878 } else {
879 return self.failNodeFmt(
880 node,
881 "missing required field {s}",
882 .{info.field_names[i]},
883 );
915 if (!initialized) {
916 inline for (field_found, 0..) |found, i| {
917 if (!found) {
918 const field_attrs = info.field_attrs[i];
919 if (field_attrs.defaultValue(info.field_types[i])) |default| {
920 @field(out, info.field_names[i]) = default;
921 } else {
922 return self.failNodeFmt(
923 node,
924 "missing required field {s}",
925 .{info.field_names[i]},
926 );
927 }
884928 }
885929 }
886930 }
887
888 return result;
889931 }
890932
891 fn parseTuple(self: *@This(), T: type, node: Zoir.Node.Index) !T {
933 fn parseTupleInto(self: *Parser, node: Zoir.Node.Index, out: anytype) !void {
892934 const nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) {
893935 .array_literal => |nodes| nodes,
894936 .empty_literal => .{ .start = node, .len = 0 },
895937 else => return error.WrongType,
896938 };
897939
898 var result: T = undefined;
899 const info = @typeInfo(T).@"struct";
940 const info = @typeInfo(@TypeOf(out.*)).@"struct";
900941
901942 if (nodes.len > info.field_names.len) {
902943 return self.failNodeFmt(
......@@ -910,38 +951,36 @@ const Parser = struct {
910951 // Check if we're out of bounds
911952 if (i >= nodes.len) {
912953 if (info.field_attrs[i].defaultValue(info.field_types[i])) |default| {
913 @field(result, info.field_names[i]) = default;
954 @field(out.*, info.field_names[i]) = default;
914955 } else {
915956 return self.failNodeFmt(node, "missing tuple field with index {}", .{i});
916957 }
917958 } else {
918 // If we fail to parse this field, free all fields before it
919 errdefer if (self.options.free_on_error) {
920 inline for (0..i) |j| {
921 if (j >= i) break;
922 free(self.gpa, result[j]);
923 }
924 };
925
926959 if (info.field_attrs[i].@"comptime") {
927960 return self.failComptimeField(node, i);
928961 } else {
929 result[i] = try self.parseExpr(info.field_types[i], nodes.at(i));
962 try self.parseExprInto(nodes.at(i), &out[i], false);
930963 }
931964 }
932965 }
933
934 return result;
935966 }
936967
937 fn parseUnion(self: *@This(), T: type, node: Zoir.Node.Index) !T {
938 const @"union" = @typeInfo(T).@"union";
968 fn parseUnionInto(
969 self: *Parser,
970 node: Zoir.Node.Index,
971 out: anytype,
972 initialized: bool,
973 ) !void {
974 const @"union" = @typeInfo(@TypeOf(out.*)).@"union";
939975
940976 if (@"union".field_names.len == 0) comptime unreachable;
941977
942978 // Gather info on the fields
943979 const field_indices = b: {
944 comptime var kvs_list: [@"union".field_names.len]struct { []const u8, usize } = undefined;
980 comptime var kvs_list: [@"union".field_names.len]struct {
981 []const u8,
982 usize,
983 } = undefined;
945984 inline for (@"union".field_names, 0..) |field_name, i| {
946985 kvs_list[i] = .{ field_name, i };
947986 }
......@@ -961,7 +1000,13 @@ const Parser = struct {
9611000 const field_index = b: {
9621001 const field_name_str = field_name.get(self.zoir);
9631002 break :b field_indices.get(field_name_str) orelse
964 return self.failUnexpected(T, "field", node, null, field_name_str);
1003 return self.failUnexpected(
1004 @TypeOf(out.*),
1005 "field",
1006 node,
1007 null,
1008 field_name_str,
1009 );
9651010 };
9661011
9671012 // Initialize the union from the given field.
......@@ -972,7 +1017,7 @@ const Parser = struct {
9721017 return self.failNode(node, "expected union");
9731018
9741019 // Instantiate the union
975 return @unionInit(T, @"union".field_names[i], {});
1020 out.* = @unionInit(@TypeOf(out.*), @"union".field_names[i], {});
9761021 },
9771022 else => unreachable, // Can't be out of bounds
9781023 }
......@@ -987,15 +1032,32 @@ const Parser = struct {
9871032 const field_name_str = field_name.get(self.zoir);
9881033 const field_val = struct_fields.vals.at(0);
9891034 const field_index = field_indices.get(field_name_str) orelse
990 return self.failUnexpected(T, "field", node, 0, field_name_str);
1035 return self.failUnexpected(@TypeOf(out.*), "field", node, 0, field_name_str);
9911036
9921037 switch (field_index) {
9931038 inline 0...@"union".field_names.len - 1 => |i| {
9941039 if (@"union".field_types[i] == void) {
9951040 return self.failNode(field_val, "expected type 'void'");
9961041 } else {
997 const value = try self.parseExpr(@"union".field_types[i], field_val);
998 return @unionInit(T, @"union".field_names[i], value);
1042 const field_initialized = b: {
1043 if (!initialized) break :b false;
1044 if (@"union".tag_type == null) break :b false;
1045 const tag = @field(@"union".tag_type.?, @"union".field_names[i]);
1046 if (out.* != tag) break :b false;
1047 break :b true;
1048 };
1049 if (!field_initialized) {
1050 out.* = @unionInit(
1051 @TypeOf(out.*),
1052 @"union".field_names[i],
1053 undefined,
1054 );
1055 }
1056 try self.parseExprInto(
1057 field_val,
1058 &@field(out.*, @"union".field_names[i]),
1059 field_initialized,
1060 );
9991061 }
10001062 },
10011063 else => unreachable, // Can't be out of bounds
......@@ -1006,41 +1068,37 @@ const Parser = struct {
10061068 }
10071069
10081070 fn failTokenFmt(
1009 self: @This(),
1071 self: Parser,
10101072 token: Ast.TokenIndex,
10111073 offset: u32,
10121074 comptime fmt: []const u8,
10131075 args: anytype,
10141076 ) error{ OutOfMemory, ParseZon } {
10151077 @branchHint(.cold);
1016 return self.failTokenFmtNote(token, offset, fmt, args, null);
1078 return self.failTokenFmtNote(token, offset, fmt, args, &.{});
10171079 }
10181080
10191081 fn failTokenFmtNote(
1020 self: @This(),
1082 self: Parser,
10211083 token: Ast.TokenIndex,
10221084 offset: u32,
10231085 comptime fmt: []const u8,
10241086 args: anytype,
1025 note: ?Error.TypeCheckFailure.Note,
1087 notes: []Diagnostics.Note,
10261088 ) error{ OutOfMemory, ParseZon } {
10271089 @branchHint(.cold);
10281090 comptime assert(args.len > 0);
1029 if (self.diag) |s| s.type_check = .{
1030 .token = token,
1031 .offset = offset,
1032 .message = std.fmt.allocPrint(self.gpa, fmt, args) catch |err| {
1033 if (note) |n| n.deinit(self.gpa);
1034 return err;
1035 },
1036 .owned = true,
1037 .note = note,
1038 };
1091 try self.errors.append(self.arena, .init(self.ast, .{
1092 .token = .fromToken(token),
1093 .node_or_offset = offset,
1094 .msg = try std.fmt.allocPrint(self.arena, fmt, args),
1095 .notes = notes,
1096 }));
10391097 return error.ParseZon;
10401098 }
10411099
10421100 fn failNodeFmt(
1043 self: @This(),
1101 self: Parser,
10441102 node: Zoir.Node.Index,
10451103 comptime fmt: []const u8,
10461104 args: anytype,
......@@ -1051,32 +1109,31 @@ const Parser = struct {
10511109 }
10521110
10531111 fn failToken(
1054 self: @This(),
1055 failure: Error.TypeCheckFailure,
1056 ) error{ParseZon} {
1112 self: Parser,
1113 failure: Diagnostics.Error,
1114 ) error{ OutOfMemory, ParseZon } {
10571115 @branchHint(.cold);
1058 if (self.diag) |s| s.type_check = failure;
1116 try self.errors.append(self.arena, failure);
10591117 return error.ParseZon;
10601118 }
10611119
10621120 fn failNode(
1063 self: @This(),
1121 self: Parser,
10641122 node: Zoir.Node.Index,
1065 message: []const u8,
1066 ) error{ParseZon} {
1123 msg: []const u8,
1124 ) error{ OutOfMemory, ParseZon } {
10671125 @branchHint(.cold);
10681126 const token = self.ast.nodeMainToken(node.getAstNode(self.zoir));
1069 return self.failToken(.{
1070 .token = token,
1071 .offset = 0,
1072 .message = message,
1073 .owned = false,
1074 .note = null,
1075 });
1127 return self.failToken(.init(self.ast, .{
1128 .token = .fromToken(token),
1129 .node_or_offset = 0,
1130 .msg = msg,
1131 .notes = &.{},
1132 }));
10761133 }
10771134
10781135 fn failCannotRepresent(
1079 self: @This(),
1136 self: Parser,
10801137 T: type,
10811138 node: Zoir.Node.Index,
10821139 ) error{ OutOfMemory, ParseZon } {
......@@ -1085,7 +1142,7 @@ const Parser = struct {
10851142 }
10861143
10871144 fn failUnexpected(
1088 self: @This(),
1145 self: Parser,
10891146 T: type,
10901147 item_kind: []const u8,
10911148 node: Zoir.Node.Index,
......@@ -1093,8 +1150,6 @@ const Parser = struct {
10931150 name: []const u8,
10941151 ) error{ OutOfMemory, ParseZon } {
10951152 @branchHint(.cold);
1096 if (self.diag == null) return error.ParseZon;
1097 const gpa = self.gpa;
10981153 const token = if (field) |f| b: {
10991154 var buf: [2]Ast.Node.Index = undefined;
11001155 const struct_init = self.ast.fullStructInit(&buf, node.getAstNode(self.zoir)).?;
......@@ -1103,38 +1158,35 @@ const Parser = struct {
11031158 } else self.ast.nodeMainToken(node.getAstNode(self.zoir));
11041159 switch (@typeInfo(T)) {
11051160 inline .@"struct", .@"union", .@"enum" => |info| {
1106 const note: Error.TypeCheckFailure.Note = if (info.field_names.len == 0) b: {
1107 break :b .{
1108 .token = token,
1109 .offset = 0,
1161 var notes: std.ArrayList(Diagnostics.Note) = .empty;
1162 if (info.field_names.len == 0) {
1163 try notes.append(self.arena, .init(self.ast, .{
1164 .token = .fromToken(token),
1165 .node_or_offset = 0,
11101166 .msg = "none expected",
1111 .owned = false,
1112 };
1113 } else b: {
1114 const msg = "supported: ";
1115 var buf: std.ArrayList(u8) = try .initCapacity(gpa, 64);
1116 defer buf.deinit(gpa);
1117 try buf.appendSlice(gpa, msg);
1167 }));
1168 } else {
1169 var aw: std.Io.Writer.Allocating = .init(self.arena);
1170 aw.writer.writeAll("supported: ") catch return error.OutOfMemory;
11181171 inline for (info.field_names, 0..) |field_name, i| {
1119 if (i != 0) try buf.appendSlice(gpa, ", ");
1120 try buf.print(gpa, "'{f}'", .{std.zig.fmtIdFlags(field_name, .{
1172 if (i != 0) aw.writer.writeAll(", ") catch return error.OutOfMemory;
1173 aw.writer.print("'{f}'", .{std.zig.fmtIdFlags(field_name, .{
11211174 .allow_primitive = true,
11221175 .allow_underscore = true,
1123 })});
1176 })}) catch return error.OutOfMemory;
11241177 }
1125 break :b .{
1126 .token = token,
1127 .offset = 0,
1128 .msg = try buf.toOwnedSlice(gpa),
1129 .owned = true,
1130 };
1131 };
1178 try notes.append(self.arena, .init(self.ast, .{
1179 .token = .fromToken(token),
1180 .node_or_offset = 0,
1181 .msg = try aw.toOwnedSlice(),
1182 }));
1183 }
11321184 return self.failTokenFmtNote(
11331185 token,
11341186 0,
11351187 "unexpected {s} '{s}'",
11361188 .{ item_kind, name },
1137 note,
1189 notes.items,
11381190 );
11391191 },
11401192 else => comptime unreachable,
......@@ -1145,12 +1197,11 @@ const Parser = struct {
11451197 // the value matched, but doing so doesn't seem to support any real use cases
11461198 // so isn't worth the complexity at the moment.
11471199 fn failComptimeField(
1148 self: @This(),
1200 self: Parser,
11491201 node: Zoir.Node.Index,
11501202 field: usize,
11511203 ) error{ OutOfMemory, ParseZon } {
11521204 @branchHint(.cold);
1153 if (self.diag == null) return error.ParseZon;
11541205 const ast_node = node.getAstNode(self.zoir);
11551206 var buf: [2]Ast.Node.Index = undefined;
11561207 const token = if (self.ast.fullStructInit(&buf, ast_node)) |struct_init| b: {
......@@ -1161,13 +1212,12 @@ const Parser = struct {
11611212 const value_node = array_init.ast.elements[field];
11621213 break :b self.ast.firstToken(value_node);
11631214 };
1164 return self.failToken(.{
1165 .token = token,
1166 .offset = 0,
1167 .message = "cannot initialize comptime field",
1168 .owned = false,
1169 .note = null,
1170 });
1215 return self.failToken(.init(self.ast, .{
1216 .token = .fromToken(token),
1217 .node_or_offset = 0,
1218 .msg = "cannot initialize comptime field",
1219 .notes = &.{},
1220 }));
11711221 }
11721222};
11731223
......@@ -1329,106 +1379,198 @@ test "std.zon requiresAllocator" {
13291379
13301380test "std.zon ast errors" {
13311381 const gpa = std.testing.allocator;
1332 var diag: Diagnostics = .{};
1333 defer diag.deinit(gpa);
1382 var arena_allocator: ArenaAllocator = .init(gpa);
1383 defer arena_allocator.deinit();
1384 const arena = arena_allocator.allocator();
1385 var diagnostics: Diagnostics = undefined;
13341386 try std.testing.expectError(
13351387 error.ParseZon,
1336 fromSlice(struct {}, gpa, ".{.x = 1 .y = 2}", &diag, .{}),
1388 fromSliceNoAlloc(struct {}, .{
1389 .gpa = gpa,
1390 .arena = arena,
1391 .source = ".{.x = 1 .y = 2}",
1392 .diagnostics = &diagnostics,
1393 }),
13371394 );
1338 try std.testing.expectFmt("1:13: error: expected ',' after initializer\n", "{f}", .{diag});
1395 try std.testing.expectFmt(
1396 \\input.zon:1:13: error: expected ',' after initializer
1397 \\
1398 , "{f}", .{diagnostics.fmt("input.zon")});
13391399}
13401400
13411401test "std.zon comments" {
13421402 const gpa = std.testing.allocator;
1403 var arena_allocator: ArenaAllocator = .init(gpa);
1404 defer arena_allocator.deinit();
1405 const arena = arena_allocator.allocator();
1406 var diagnostics: Diagnostics = undefined;
13431407
1344 try std.testing.expectEqual(@as(u8, 10), fromSlice(u8, gpa,
1408 try std.testing.expectEqual(@as(u8, 10), fromSliceNoAlloc(u8, .{
1409 .gpa = gpa,
1410 .arena = arena,
1411 .source =
13451412 \\// comment
13461413 \\10 // comment
13471414 \\// comment
1348 , null, .{}));
1415 ,
1416 .diagnostics = &diagnostics,
1417 }));
13491418
13501419 {
1351 var diag: Diagnostics = .{};
1352 defer diag.deinit(gpa);
1353 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa,
1420 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
1421 .gpa = gpa,
1422 .arena = arena,
1423 .source =
13541424 \\//! comment
13551425 \\10 // comment
13561426 \\// comment
1357 , &diag, .{}));
1427 ,
1428 .diagnostics = &diagnostics,
1429 }));
13581430 try std.testing.expectFmt(
1359 "1:1: error: expected expression, found 'a document comment'\n",
1360 "{f}",
1361 .{diag},
1362 );
1431 \\input.zon:1:1: error: expected expression, found 'a document comment'
1432 \\
1433 , "{f}", .{diagnostics.fmt("input.zon")});
13631434 }
13641435}
13651436
13661437test "std.zon failure/oom formatting" {
13671438 const gpa = std.testing.allocator;
1368 var failing_allocator = std.testing.FailingAllocator.init(gpa, .{
1369 .fail_index = 0,
1370 .resize_fail_index = 0,
1371 });
1372 var diag: Diagnostics = .{};
1373 defer diag.deinit(gpa);
1374 try std.testing.expectError(error.OutOfMemory, fromSliceAlloc(
1375 []const u8,
1376 failing_allocator.allocator(),
1377 "\"foo\"",
1378 &diag,
1379 .{},
1380 ));
1381 try std.testing.expectFmt("", "{f}", .{diag});
1439 var arena_allocator: ArenaAllocator = .init(gpa);
1440 defer arena_allocator.deinit();
1441 const arena = arena_allocator.allocator();
1442 var diagnostics: Diagnostics = undefined;
1443
1444 try std.testing.expectError(error.OutOfMemory, fromSlice([]const u8, .{
1445 .gpa = .failing,
1446 .arena = arena,
1447 .source = "\"foo\"",
1448 .diagnostics = &diagnostics,
1449 }));
1450 try std.testing.expectFmt(
1451 \\
1452 , "{f}", .{diagnostics.fmt("input.zon")});
13821453}
13831454
1384test "std.zon fromSliceAlloc syntax error" {
1455test "std.zon fromSlice syntax error" {
1456 const gpa = std.testing.allocator;
1457 var arena_allocator: ArenaAllocator = .init(gpa);
1458 defer arena_allocator.deinit();
1459 const arena = arena_allocator.allocator();
1460 var diagnostics: Diagnostics = undefined;
13851461 try std.testing.expectError(
13861462 error.ParseZon,
1387 fromSlice(u8, std.testing.allocator, ".{", null, .{}),
1463 fromSliceNoAlloc(u8, .{
1464 .gpa = gpa,
1465 .arena = arena,
1466 .source = ".{",
1467 .diagnostics = &diagnostics,
1468 }),
13881469 );
1470 try std.testing.expectFmt(
1471 \\input.zon:1:3: error: expected expression, found 'EOF'
1472 \\
1473 , "{f}", .{diagnostics.fmt("input.zon")});
13891474}
13901475
13911476test "std.zon optional" {
13921477 const gpa = std.testing.allocator;
1478 var arena_allocator: ArenaAllocator = .init(gpa);
1479 defer arena_allocator.deinit();
1480 const arena = arena_allocator.allocator();
1481 var diagnostics: Diagnostics = undefined;
13931482
13941483 // Basic usage
13951484 {
1396 const none = try fromSlice(?u32, gpa, "null", null, .{});
1485 const none = try fromSliceNoAlloc(?u32, .{
1486 .gpa = gpa,
1487 .arena = arena,
1488 .source = "null",
1489 .diagnostics = &diagnostics,
1490 });
13971491 try std.testing.expect(none == null);
1398 const some = try fromSlice(?u32, gpa, "1", null, .{});
1492 const some = try fromSliceNoAlloc(?u32, .{
1493 .gpa = gpa,
1494 .arena = arena,
1495 .source = "1",
1496 .diagnostics = &diagnostics,
1497 });
13991498 try std.testing.expect(some.? == 1);
14001499 }
14011500
14021501 // Deep free
14031502 {
1404 const none = try fromSliceAlloc(?[]const u8, gpa, "null", null, .{});
1503 const none = try fromSlice(?[]const u8, .{
1504 .gpa = gpa,
1505 .arena = arena,
1506 .source = "null",
1507 .diagnostics = &diagnostics,
1508 });
14051509 try std.testing.expect(none == null);
1406 const some = try fromSliceAlloc(?[]const u8, gpa, "\"foo\"", null, .{});
1407 defer free(gpa, some);
1510 const some = try fromSlice(?[]const u8, .{
1511 .gpa = gpa,
1512 .arena = arena,
1513 .source = "\"foo\"",
1514 .diagnostics = &diagnostics,
1515 });
14081516 try std.testing.expectEqualStrings("foo", some.?);
14091517 }
14101518}
14111519
14121520test "std.zon unions" {
14131521 const gpa = std.testing.allocator;
1522 var arena_allocator: ArenaAllocator = .init(gpa);
1523 defer arena_allocator.deinit();
1524 const arena = arena_allocator.allocator();
1525 var diagnostics: Diagnostics = undefined;
14141526
14151527 // Unions
14161528 {
14171529 const Tagged = union(enum) { x: f32, @"y y": bool, z, @"z z" };
14181530 const Untagged = union { x: f32, @"y y": bool, z: void, @"z z": void };
14191531
1420 const tagged_x = try fromSlice(Tagged, gpa, ".{.x = 1.5}", null, .{});
1532 const tagged_x = try fromSliceNoAlloc(Tagged, .{
1533 .gpa = gpa,
1534 .arena = arena,
1535 .source = ".{.x = 1.5}",
1536 .diagnostics = &diagnostics,
1537 });
14211538 try std.testing.expectEqual(Tagged{ .x = 1.5 }, tagged_x);
1422 const tagged_y = try fromSlice(Tagged, gpa, ".{.@\"y y\" = true}", null, .{});
1539 const tagged_y = try fromSliceNoAlloc(Tagged, .{
1540 .gpa = gpa,
1541 .arena = arena,
1542 .source = ".{.@\"y y\" = true}",
1543 .diagnostics = &diagnostics,
1544 });
14231545 try std.testing.expectEqual(Tagged{ .@"y y" = true }, tagged_y);
1424 const tagged_z_shorthand = try fromSlice(Tagged, gpa, ".z", null, .{});
1546 const tagged_z_shorthand = try fromSliceNoAlloc(Tagged, .{
1547 .gpa = gpa,
1548 .arena = arena,
1549 .source = ".z",
1550 .diagnostics = &diagnostics,
1551 });
14251552 try std.testing.expectEqual(@as(Tagged, .z), tagged_z_shorthand);
1426 const tagged_zz_shorthand = try fromSlice(Tagged, gpa, ".@\"z z\"", null, .{});
1553 const tagged_zz_shorthand = try fromSliceNoAlloc(Tagged, .{
1554 .gpa = gpa,
1555 .arena = arena,
1556 .source = ".@\"z z\"",
1557 .diagnostics = &diagnostics,
1558 });
14271559 try std.testing.expectEqual(@as(Tagged, .@"z z"), tagged_zz_shorthand);
14281560
1429 const untagged_x = try fromSlice(Untagged, gpa, ".{.x = 1.5}", null, .{});
1561 const untagged_x = try fromSliceNoAlloc(Untagged, .{
1562 .gpa = gpa,
1563 .arena = arena,
1564 .source = ".{.x = 1.5}",
1565 .diagnostics = &diagnostics,
1566 });
14301567 try std.testing.expect(untagged_x.x == 1.5);
1431 const untagged_y = try fromSlice(Untagged, gpa, ".{.@\"y y\" = true}", null, .{});
1568 const untagged_y = try fromSliceNoAlloc(Untagged, .{
1569 .gpa = gpa,
1570 .arena = arena,
1571 .source = ".{.@\"y y\" = true}",
1572 .diagnostics = &diagnostics,
1573 });
14321574 try std.testing.expect(untagged_y.@"y y");
14331575 }
14341576
......@@ -1436,106 +1578,149 @@ test "std.zon unions" {
14361578 {
14371579 const Union = union(enum) { bar: []const u8, baz: bool };
14381580
1439 const noalloc = try fromSliceAlloc(Union, gpa, ".{.baz = false}", null, .{});
1581 const noalloc = try fromSlice(Union, .{
1582 .gpa = gpa,
1583 .arena = arena,
1584 .source = ".{.baz = false}",
1585 .diagnostics = &diagnostics,
1586 });
14401587 try std.testing.expectEqual(Union{ .baz = false }, noalloc);
14411588
1442 const alloc = try fromSliceAlloc(Union, gpa, ".{.bar = \"qux\"}", null, .{});
1443 defer free(gpa, alloc);
1589 const alloc = try fromSlice(Union, .{
1590 .gpa = gpa,
1591 .arena = arena,
1592 .source = ".{.bar = \"qux\"}",
1593 .diagnostics = &diagnostics,
1594 });
14441595 try std.testing.expectEqualDeep(Union{ .bar = "qux" }, alloc);
14451596 }
14461597
14471598 // Unknown field
14481599 {
14491600 const Union = union { x: f32, y: f32 };
1450 var diag: Diagnostics = .{};
1451 defer diag.deinit(gpa);
14521601 try std.testing.expectError(
14531602 error.ParseZon,
1454 fromSliceAlloc(Union, gpa, ".{.z=2.5}", &diag, .{}),
1603 fromSlice(Union, .{
1604 .gpa = gpa,
1605 .arena = arena,
1606 .source = ".{.z=2.5}",
1607 .diagnostics = &diagnostics,
1608 }),
14551609 );
14561610 try std.testing.expectFmt(
1457 \\1:4: error: unexpected field 'z'
1458 \\1:4: note: supported: 'x', 'y'
1611 \\input.zon:1:4: error: unexpected field 'z'
1612 \\input.zon:1:4: note: supported: 'x', 'y'
14591613 \\
1460 ,
1461 "{f}",
1462 .{diag},
1463 );
1614 , "{f}", .{diagnostics.fmt("input.zon")});
14641615 }
14651616
14661617 // Explicit void field
14671618 {
14681619 const Union = union(enum) { x: void };
1469 var diag: Diagnostics = .{};
1470 defer diag.deinit(gpa);
14711620 try std.testing.expectError(
14721621 error.ParseZon,
1473 fromSliceAlloc(Union, gpa, ".{.x=1}", &diag, .{}),
1622 fromSlice(Union, .{
1623 .gpa = gpa,
1624 .arena = arena,
1625 .source = ".{.x=1}",
1626 .diagnostics = &diagnostics,
1627 }),
14741628 );
1475 try std.testing.expectFmt("1:6: error: expected type 'void'\n", "{f}", .{diag});
1629 try std.testing.expectFmt(
1630 \\input.zon:1:6: error: expected type 'void'
1631 \\
1632 , "{f}", .{diagnostics.fmt("input.zon")});
14761633 }
14771634
14781635 // Extra field
14791636 {
14801637 const Union = union { x: f32, y: bool };
1481 var diag: Diagnostics = .{};
1482 defer diag.deinit(gpa);
14831638 try std.testing.expectError(
14841639 error.ParseZon,
1485 fromSliceAlloc(Union, gpa, ".{.x = 1.5, .y = true}", &diag, .{}),
1640 fromSlice(Union, .{
1641 .gpa = gpa,
1642 .arena = arena,
1643 .source = ".{.x = 1.5, .y = true}",
1644 .diagnostics = &diagnostics,
1645 }),
14861646 );
1487 try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});
1647 try std.testing.expectFmt(
1648 \\input.zon:1:2: error: expected union
1649 \\
1650 , "{f}", .{diagnostics.fmt("input.zon")});
14881651 }
14891652
14901653 // No fields
14911654 {
14921655 const Union = union { x: f32, y: bool };
1493 var diag: Diagnostics = .{};
1494 defer diag.deinit(gpa);
14951656 try std.testing.expectError(
14961657 error.ParseZon,
1497 fromSliceAlloc(Union, gpa, ".{}", &diag, .{}),
1658 fromSlice(Union, .{
1659 .gpa = gpa,
1660 .arena = arena,
1661 .source = ".{}",
1662 .diagnostics = &diagnostics,
1663 }),
14981664 );
1499 try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});
1665 try std.testing.expectFmt(
1666 \\input.zon:1:2: error: expected union
1667 \\
1668 , "{f}", .{diagnostics.fmt("input.zon")});
15001669 }
15011670
15021671 // Enum literals cannot coerce into untagged unions
15031672 {
15041673 const Union = union { x: void };
1505 var diag: Diagnostics = .{};
1506 defer diag.deinit(gpa);
1507 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".x", &diag, .{}));
1508 try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});
1674 try std.testing.expectError(error.ParseZon, fromSlice(Union, .{
1675 .gpa = gpa,
1676 .arena = arena,
1677 .source = ".x",
1678 .diagnostics = &diagnostics,
1679 }));
1680 try std.testing.expectFmt(
1681 \\input.zon:1:2: error: expected union
1682 \\
1683 , "{f}", .{diagnostics.fmt("input.zon")});
15091684 }
15101685
15111686 // Unknown field for enum literal coercion
15121687 {
15131688 const Union = union(enum) { x: void };
1514 var diag: Diagnostics = .{};
1515 defer diag.deinit(gpa);
1516 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".y", &diag, .{}));
1689 try std.testing.expectError(error.ParseZon, fromSlice(Union, .{
1690 .gpa = gpa,
1691 .arena = arena,
1692 .source = ".y",
1693 .diagnostics = &diagnostics,
1694 }));
15171695 try std.testing.expectFmt(
1518 \\1:2: error: unexpected field 'y'
1519 \\1:2: note: supported: 'x'
1696 \\input.zon:1:2: error: unexpected field 'y'
1697 \\input.zon:1:2: note: supported: 'x'
15201698 \\
1521 ,
1522 "{f}",
1523 .{diag},
1524 );
1699 , "{f}", .{diagnostics.fmt("input.zon")});
15251700 }
15261701
15271702 // Non void field for enum literal coercion
15281703 {
15291704 const Union = union(enum) { x: f32 };
1530 var diag: Diagnostics = .{};
1531 defer diag.deinit(gpa);
1532 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".x", &diag, .{}));
1533 try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});
1705 try std.testing.expectError(error.ParseZon, fromSlice(Union, .{
1706 .gpa = gpa,
1707 .arena = arena,
1708 .source = ".x",
1709 .diagnostics = &diagnostics,
1710 }));
1711 try std.testing.expectFmt(
1712 \\input.zon:1:2: error: expected union
1713 \\
1714 , "{f}", .{diagnostics.fmt("input.zon")});
15341715 }
15351716}
15361717
15371718test "std.zon structs" {
15381719 const gpa = std.testing.allocator;
1720 var arena_allocator: ArenaAllocator = .init(gpa);
1721 defer arena_allocator.deinit();
1722 const arena = arena_allocator.allocator();
1723 var diagnostics: Diagnostics = undefined;
15391724
15401725 // Structs (various sizes tested since they're parsed differently)
15411726 {
......@@ -1544,16 +1729,36 @@ test "std.zon structs" {
15441729 const Vec2 = struct { x: f32, y: f32 };
15451730 const Vec3 = struct { x: f32, y: f32, z: f32 };
15461731
1547 const zero = try fromSlice(Vec0, gpa, ".{}", null, .{});
1732 const zero = try fromSliceNoAlloc(Vec0, .{
1733 .gpa = gpa,
1734 .arena = arena,
1735 .source = ".{}",
1736 .diagnostics = &diagnostics,
1737 });
15481738 try std.testing.expectEqual(Vec0{}, zero);
15491739
1550 const one = try fromSlice(Vec1, gpa, ".{.x = 1.2}", null, .{});
1740 const one = try fromSliceNoAlloc(Vec1, .{
1741 .gpa = gpa,
1742 .arena = arena,
1743 .source = ".{.x = 1.2}",
1744 .diagnostics = &diagnostics,
1745 });
15511746 try std.testing.expectEqual(Vec1{ .x = 1.2 }, one);
15521747
1553 const two = try fromSlice(Vec2, gpa, ".{.x = 1.2, .y = 3.4}", null, .{});
1748 const two = try fromSliceNoAlloc(Vec2, .{
1749 .gpa = gpa,
1750 .arena = arena,
1751 .source = ".{.x = 1.2, .y = 3.4}",
1752 .diagnostics = &diagnostics,
1753 });
15541754 try std.testing.expectEqual(Vec2{ .x = 1.2, .y = 3.4 }, two);
15551755
1556 const three = try fromSlice(Vec3, gpa, ".{.x = 1.2, .y = 3.4, .z = 5.6}", null, .{});
1756 const three = try fromSliceNoAlloc(Vec3, .{
1757 .gpa = gpa,
1758 .arena = arena,
1759 .source = ".{.x = 1.2, .y = 3.4, .z = 5.6}",
1760 .diagnostics = &diagnostics,
1761 });
15571762 try std.testing.expectEqual(Vec3{ .x = 1.2, .y = 3.4, .z = 5.6 }, three);
15581763 }
15591764
......@@ -1561,57 +1766,62 @@ test "std.zon structs" {
15611766 {
15621767 const Foo = struct { bar: []const u8, baz: []const []const u8 };
15631768
1564 const parsed = try fromSliceAlloc(
1565 Foo,
1566 gpa,
1567 ".{.bar = \"qux\", .baz = .{\"a\", \"b\"}}",
1568 null,
1569 .{},
1570 );
1571 defer free(gpa, parsed);
1769 const parsed = try fromSlice(Foo, .{
1770 .gpa = gpa,
1771 .arena = arena,
1772 .source = ".{.bar = \"qux\", .baz = .{\"a\", \"b\"}}",
1773 .diagnostics = &diagnostics,
1774 });
15721775 try std.testing.expectEqualDeep(Foo{ .bar = "qux", .baz = &.{ "a", "b" } }, parsed);
15731776 }
15741777
15751778 // Unknown field
15761779 {
15771780 const Vec2 = struct { x: f32, y: f32 };
1578 var diag: Diagnostics = .{};
1579 defer diag.deinit(gpa);
15801781 try std.testing.expectError(
15811782 error.ParseZon,
1582 fromSlice(Vec2, gpa, ".{.x=1.5, .z=2.5}", &diag, .{}),
1783 fromSliceNoAlloc(Vec2, .{
1784 .gpa = gpa,
1785 .arena = arena,
1786 .source = ".{.x=1.5, .z=2.5}",
1787 .diagnostics = &diagnostics,
1788 }),
15831789 );
15841790 try std.testing.expectFmt(
1585 \\1:12: error: unexpected field 'z'
1586 \\1:12: note: supported: 'x', 'y'
1791 \\input.zon:1:12: error: unexpected field 'z'
1792 \\input.zon:1:12: note: supported: 'x', 'y'
15871793 \\
1588 ,
1589 "{f}",
1590 .{diag},
1591 );
1794 , "{f}", .{diagnostics.fmt("input.zon")});
15921795 }
15931796
15941797 // Duplicate field
15951798 {
15961799 const Vec2 = struct { x: f32, y: f32 };
1597 var diag: Diagnostics = .{};
1598 defer diag.deinit(gpa);
15991800 try std.testing.expectError(
16001801 error.ParseZon,
1601 fromSlice(Vec2, gpa, ".{.x=1.5, .x=2.5, .x=3.5}", &diag, .{}),
1802 fromSliceNoAlloc(Vec2, .{
1803 .gpa = gpa,
1804 .arena = arena,
1805 .source = ".{.x=1.5, .x=2.5, .x=3.5}",
1806 .diagnostics = &diagnostics,
1807 }),
16021808 );
16031809 try std.testing.expectFmt(
1604 \\1:4: error: duplicate struct field name
1605 \\1:12: note: duplicate name here
1810 \\input.zon:1:4: error: duplicate struct field name
1811 \\input.zon:1:12: note: duplicate name here
16061812 \\
1607 , "{f}", .{diag});
1813 , "{f}", .{diagnostics.fmt("input.zon")});
16081814 }
16091815
16101816 // Ignore unknown fields
16111817 {
16121818 const Vec2 = struct { x: f32, y: f32 = 2.0 };
1613 const parsed = try fromSlice(Vec2, gpa, ".{ .x = 1.0, .z = 3.0 }", null, .{
1819 const parsed = try fromSliceNoAlloc(Vec2, .{
1820 .gpa = gpa,
1821 .arena = arena,
1822 .source = ".{ .x = 1.0, .z = 3.0 }",
16141823 .ignore_unknown_fields = true,
1824 .diagnostics = &diagnostics,
16151825 });
16161826 try std.testing.expectEqual(Vec2{ .x = 1.0, .y = 2.0 }, parsed);
16171827 }
......@@ -1619,70 +1829,102 @@ test "std.zon structs" {
16191829 // Unknown field when struct has no fields (regression test)
16201830 {
16211831 const Vec2 = struct {};
1622 var diag: Diagnostics = .{};
1623 defer diag.deinit(gpa);
16241832 try std.testing.expectError(
16251833 error.ParseZon,
1626 fromSlice(Vec2, gpa, ".{.x=1.5, .z=2.5}", &diag, .{}),
1834 fromSliceNoAlloc(Vec2, .{
1835 .gpa = gpa,
1836 .arena = arena,
1837 .source = ".{.x=1.5, .z=2.5}",
1838 .diagnostics = &diagnostics,
1839 }),
16271840 );
16281841 try std.testing.expectFmt(
1629 \\1:4: error: unexpected field 'x'
1630 \\1:4: note: none expected
1842 \\input.zon:1:4: error: unexpected field 'x'
1843 \\input.zon:1:4: note: none expected
16311844 \\
1632 , "{f}", .{diag});
1845 , "{f}", .{diagnostics.fmt("input.zon")});
16331846 }
16341847
16351848 // Missing field
16361849 {
16371850 const Vec2 = struct { x: f32, y: f32 };
1638 var diag: Diagnostics = .{};
1639 defer diag.deinit(gpa);
16401851 try std.testing.expectError(
16411852 error.ParseZon,
1642 fromSlice(Vec2, gpa, ".{.x=1.5}", &diag, .{}),
1853 fromSliceNoAlloc(Vec2, .{
1854 .gpa = gpa,
1855 .arena = arena,
1856 .source = ".{.x=1.5}",
1857 .diagnostics = &diagnostics,
1858 }),
16431859 );
1644 try std.testing.expectFmt("1:2: error: missing required field y\n", "{f}", .{diag});
1860 try std.testing.expectFmt(
1861 \\input.zon:1:2: error: missing required field y
1862 \\
1863 , "{f}", .{diagnostics.fmt("input.zon")});
16451864 }
16461865
16471866 // Default field
16481867 {
16491868 const Vec2 = struct { x: f32, y: f32 = 1.5 };
1650 const parsed = try fromSlice(Vec2, gpa, ".{.x = 1.2}", null, .{});
1869 const parsed = try fromSliceNoAlloc(Vec2, .{
1870 .gpa = gpa,
1871 .arena = arena,
1872 .source = ".{.x = 1.2}",
1873 .diagnostics = &diagnostics,
1874 });
16511875 try std.testing.expectEqual(Vec2{ .x = 1.2, .y = 1.5 }, parsed);
16521876 }
16531877
16541878 // Comptime field
16551879 {
16561880 const Vec2 = struct { x: f32, comptime y: f32 = 1.5 };
1657 const parsed = try fromSlice(Vec2, gpa, ".{.x = 1.2}", null, .{});
1881 const parsed = try fromSliceNoAlloc(Vec2, .{
1882 .gpa = gpa,
1883 .arena = arena,
1884 .source = ".{.x = 1.2}",
1885 .diagnostics = &diagnostics,
1886 });
16581887 try std.testing.expectEqual(Vec2{ .x = 1.2, .y = 1.5 }, parsed);
16591888 }
16601889
16611890 // Comptime field assignment
16621891 {
16631892 const Vec2 = struct { x: f32, comptime y: f32 = 1.5 };
1664 var diag: Diagnostics = .{};
1665 defer diag.deinit(gpa);
1666 const parsed = fromSlice(Vec2, gpa, ".{.x = 1.2, .y = 1.5}", &diag, .{});
1893 const parsed = fromSliceNoAlloc(Vec2, .{
1894 .gpa = gpa,
1895 .arena = arena,
1896 .source = ".{.x = 1.2, .y = 1.5}",
1897 .diagnostics = &diagnostics,
1898 });
16671899 try std.testing.expectError(error.ParseZon, parsed);
16681900 try std.testing.expectFmt(
1669 \\1:18: error: cannot initialize comptime field
1901 \\input.zon:1:18: error: cannot initialize comptime field
16701902 \\
1671 , "{f}", .{diag});
1903 , "{f}", .{diagnostics.fmt("input.zon")});
16721904 }
16731905
16741906 // Enum field (regression test, we were previously getting the field name in an
16751907 // incorrect way that broke for enum values)
16761908 {
16771909 const Vec0 = struct { x: enum { x } };
1678 const parsed = try fromSlice(Vec0, gpa, ".{ .x = .x }", null, .{});
1910 const parsed = try fromSliceNoAlloc(Vec0, .{
1911 .gpa = gpa,
1912 .arena = arena,
1913 .source = ".{ .x = .x }",
1914 .diagnostics = &diagnostics,
1915 });
16791916 try std.testing.expectEqual(Vec0{ .x = .x }, parsed);
16801917 }
16811918
16821919 // Enum field and struct field with @
16831920 {
16841921 const Vec0 = struct { @"x x": enum { @"x x" } };
1685 const parsed = try fromSlice(Vec0, gpa, ".{ .@\"x x\" = .@\"x x\" }", null, .{});
1922 const parsed = try fromSliceNoAlloc(Vec0, .{
1923 .gpa = gpa,
1924 .arena = arena,
1925 .source = ".{ .@\"x x\" = .@\"x x\" }",
1926 .diagnostics = &diagnostics,
1927 });
16861928 try std.testing.expectEqual(Vec0{ .@"x x" = .@"x x" }, parsed);
16871929 }
16881930
......@@ -1690,79 +1932,92 @@ test "std.zon structs" {
16901932 {
16911933 // Structs
16921934 {
1693 var diag: Diagnostics = .{};
1694 defer diag.deinit(gpa);
1695 const parsed = fromSlice(struct {}, gpa, "Empty{}", &diag, .{});
1935 const parsed = fromSliceNoAlloc(struct {}, .{
1936 .gpa = gpa,
1937 .arena = arena,
1938 .source = "Empty{}",
1939 .diagnostics = &diagnostics,
1940 });
16961941 try std.testing.expectError(error.ParseZon, parsed);
16971942 try std.testing.expectFmt(
1698 \\1:1: error: types are not available in ZON
1699 \\1:1: note: replace the type with '.'
1943 \\input.zon:1:1: error: types are not available in ZON
1944 \\input.zon:1:1: note: replace the type with '.'
17001945 \\
1701 , "{f}", .{diag});
1946 , "{f}", .{diagnostics.fmt("input.zon")});
17021947 }
17031948
17041949 // Arrays
17051950 {
1706 var diag: Diagnostics = .{};
1707 defer diag.deinit(gpa);
1708 const parsed = fromSlice([3]u8, gpa, "[3]u8{1, 2, 3}", &diag, .{});
1951 const parsed = fromSliceNoAlloc([3]u8, .{
1952 .gpa = gpa,
1953 .arena = arena,
1954 .source = "[3]u8{1, 2, 3}",
1955 .diagnostics = &diagnostics,
1956 });
17091957 try std.testing.expectError(error.ParseZon, parsed);
17101958 try std.testing.expectFmt(
1711 \\1:1: error: types are not available in ZON
1712 \\1:1: note: replace the type with '.'
1959 \\input.zon:1:1: error: types are not available in ZON
1960 \\input.zon:1:1: note: replace the type with '.'
17131961 \\
1714 , "{f}", .{diag});
1962 , "{f}", .{diagnostics.fmt("input.zon")});
17151963 }
17161964
17171965 // Slices
17181966 {
1719 var diag: Diagnostics = .{};
1720 defer diag.deinit(gpa);
1721 const parsed = fromSliceAlloc([]u8, gpa, "[]u8{1, 2, 3}", &diag, .{});
1967 const parsed = fromSlice([]u8, .{
1968 .gpa = gpa,
1969 .arena = arena,
1970 .source = "[]u8{1, 2, 3}",
1971 .diagnostics = &diagnostics,
1972 });
17221973 try std.testing.expectError(error.ParseZon, parsed);
17231974 try std.testing.expectFmt(
1724 \\1:1: error: types are not available in ZON
1725 \\1:1: note: replace the type with '.'
1975 \\input.zon:1:1: error: types are not available in ZON
1976 \\input.zon:1:1: note: replace the type with '.'
17261977 \\
1727 , "{f}", .{diag});
1978 , "{f}", .{diagnostics.fmt("input.zon")});
17281979 }
17291980
17301981 // Tuples
17311982 {
1732 var diag: Diagnostics = .{};
1733 defer diag.deinit(gpa);
1734 const parsed = fromSlice(
1735 struct { u8, u8, u8 },
1736 gpa,
1737 "Tuple{1, 2, 3}",
1738 &diag,
1739 .{},
1740 );
1983 const parsed = fromSliceNoAlloc(struct { u8, u8, u8 }, .{
1984 .gpa = gpa,
1985 .arena = arena,
1986 .source = "Tuple{1, 2, 3}",
1987 .diagnostics = &diagnostics,
1988 });
17411989 try std.testing.expectError(error.ParseZon, parsed);
17421990 try std.testing.expectFmt(
1743 \\1:1: error: types are not available in ZON
1744 \\1:1: note: replace the type with '.'
1991 \\input.zon:1:1: error: types are not available in ZON
1992 \\input.zon:1:1: note: replace the type with '.'
17451993 \\
1746 , "{f}", .{diag});
1994 , "{f}", .{diagnostics.fmt("input.zon")});
17471995 }
17481996
17491997 // Nested
17501998 {
1751 var diag: Diagnostics = .{};
1752 defer diag.deinit(gpa);
1753 const parsed = fromSlice(struct {}, gpa, ".{ .x = Tuple{1, 2, 3} }", &diag, .{});
1999 const parsed = fromSliceNoAlloc(struct {}, .{
2000 .gpa = gpa,
2001 .arena = arena,
2002 .source = ".{ .x = Tuple{1, 2, 3} }",
2003 .diagnostics = &diagnostics,
2004 });
17542005 try std.testing.expectError(error.ParseZon, parsed);
17552006 try std.testing.expectFmt(
1756 \\1:9: error: types are not available in ZON
1757 \\1:9: note: replace the type with '.'
2007 \\input.zon:1:9: error: types are not available in ZON
2008 \\input.zon:1:9: note: replace the type with '.'
17582009 \\
1759 , "{f}", .{diag});
2010 , "{f}", .{diagnostics.fmt("input.zon")});
17602011 }
17612012 }
17622013}
17632014
17642015test "std.zon tuples" {
17652016 const gpa = std.testing.allocator;
2017 var arena_allocator: ArenaAllocator = .init(gpa);
2018 defer arena_allocator.deinit();
2019 const arena = arena_allocator.allocator();
2020 var diagnostics: Diagnostics = undefined;
17662021
17672022 // Structs (various sizes tested since they're parsed differently)
17682023 {
......@@ -1771,152 +2026,262 @@ test "std.zon tuples" {
17712026 const Tuple2 = struct { f32, bool };
17722027 const Tuple3 = struct { f32, bool, u8 };
17732028
1774 const zero = try fromSlice(Tuple0, gpa, ".{}", null, .{});
2029 const zero = try fromSliceNoAlloc(Tuple0, .{
2030 .gpa = gpa,
2031 .arena = arena,
2032 .source = ".{}",
2033 .diagnostics = &diagnostics,
2034 });
17752035 try std.testing.expectEqual(Tuple0{}, zero);
17762036
1777 const one = try fromSlice(Tuple1, gpa, ".{1.2}", null, .{});
2037 const one = try fromSliceNoAlloc(Tuple1, .{
2038 .gpa = gpa,
2039 .arena = arena,
2040 .source = ".{1.2}",
2041 .diagnostics = &diagnostics,
2042 });
17782043 try std.testing.expectEqual(Tuple1{1.2}, one);
17792044
1780 const two = try fromSlice(Tuple2, gpa, ".{1.2, true}", null, .{});
2045 const two = try fromSliceNoAlloc(Tuple2, .{
2046 .gpa = gpa,
2047 .arena = arena,
2048 .source = ".{1.2, true}",
2049 .diagnostics = &diagnostics,
2050 });
17812051 try std.testing.expectEqual(Tuple2{ 1.2, true }, two);
17822052
1783 const three = try fromSlice(Tuple3, gpa, ".{1.2, false, 3}", null, .{});
2053 const three = try fromSliceNoAlloc(Tuple3, .{
2054 .gpa = gpa,
2055 .arena = arena,
2056 .source = ".{1.2, false, 3}",
2057 .diagnostics = &diagnostics,
2058 });
17842059 try std.testing.expectEqual(Tuple3{ 1.2, false, 3 }, three);
17852060 }
17862061
17872062 // Deep free
17882063 {
17892064 const Tuple = struct { []const u8, []const u8 };
1790 const parsed = try fromSliceAlloc(Tuple, gpa, ".{\"hello\", \"world\"}", null, .{});
1791 defer free(gpa, parsed);
2065 const parsed = try fromSlice(Tuple, .{
2066 .gpa = gpa,
2067 .arena = arena,
2068 .source = ".{\"hello\", \"world\"}",
2069 .diagnostics = &diagnostics,
2070 });
17922071 try std.testing.expectEqualDeep(Tuple{ "hello", "world" }, parsed);
17932072 }
17942073
17952074 // Extra field
17962075 {
17972076 const Tuple = struct { f32, bool };
1798 var diag: Diagnostics = .{};
1799 defer diag.deinit(gpa);
18002077 try std.testing.expectError(
18012078 error.ParseZon,
1802 fromSlice(Tuple, gpa, ".{0.5, true, 123}", &diag, .{}),
2079 fromSliceNoAlloc(Tuple, .{
2080 .gpa = gpa,
2081 .arena = arena,
2082 .source = ".{0.5, true, 123}",
2083 .diagnostics = &diagnostics,
2084 }),
18032085 );
1804 try std.testing.expectFmt("1:14: error: index 2 outside of tuple length 2\n", "{f}", .{diag});
2086 try std.testing.expectFmt(
2087 \\input.zon:1:14: error: index 2 outside of tuple length 2
2088 \\
2089 , "{f}", .{diagnostics.fmt("input.zon")});
18052090 }
18062091
18072092 // Extra field
18082093 {
18092094 const Tuple = struct { f32, bool };
1810 var diag: Diagnostics = .{};
1811 defer diag.deinit(gpa);
18122095 try std.testing.expectError(
18132096 error.ParseZon,
1814 fromSlice(Tuple, gpa, ".{0.5}", &diag, .{}),
2097 fromSliceNoAlloc(Tuple, .{
2098 .gpa = gpa,
2099 .arena = arena,
2100 .source = ".{0.5}",
2101 .diagnostics = &diagnostics,
2102 }),
18152103 );
18162104 try std.testing.expectFmt(
1817 "1:2: error: missing tuple field with index 1\n",
1818 "{f}",
1819 .{diag},
1820 );
2105 \\input.zon:1:2: error: missing tuple field with index 1
2106 \\
2107 , "{f}", .{diagnostics.fmt("input.zon")});
18212108 }
18222109
18232110 // Tuple with unexpected field names
18242111 {
18252112 const Tuple = struct { f32 };
1826 var diag: Diagnostics = .{};
1827 defer diag.deinit(gpa);
18282113 try std.testing.expectError(
18292114 error.ParseZon,
1830 fromSlice(Tuple, gpa, ".{.foo = 10.0}", &diag, .{}),
2115 fromSliceNoAlloc(Tuple, .{
2116 .gpa = gpa,
2117 .arena = arena,
2118 .source = ".{.foo = 10.0}",
2119 .diagnostics = &diagnostics,
2120 }),
18312121 );
1832 try std.testing.expectFmt("1:2: error: expected tuple\n", "{f}", .{diag});
2122 try std.testing.expectFmt(
2123 \\input.zon:1:2: error: expected tuple
2124 \\
2125 , "{f}", .{diagnostics.fmt("input.zon")});
18332126 }
18342127
18352128 // Struct with missing field names
18362129 {
18372130 const Struct = struct { foo: f32 };
1838 var diag: Diagnostics = .{};
1839 defer diag.deinit(gpa);
18402131 try std.testing.expectError(
18412132 error.ParseZon,
1842 fromSlice(Struct, gpa, ".{10.0}", &diag, .{}),
2133 fromSliceNoAlloc(Struct, .{
2134 .gpa = gpa,
2135 .arena = arena,
2136 .source = ".{10.0}",
2137 .diagnostics = &diagnostics,
2138 }),
18432139 );
1844 try std.testing.expectFmt("1:2: error: expected struct\n", "{f}", .{diag});
2140 try std.testing.expectFmt(
2141 \\input.zon:1:2: error: expected struct
2142 \\
2143 , "{f}", .{diagnostics.fmt("input.zon")});
18452144 }
18462145
18472146 // Comptime field
18482147 {
18492148 const Vec2 = struct { f32, comptime f32 = 1.5 };
1850 const parsed = try fromSlice(Vec2, gpa, ".{ 1.2 }", null, .{});
2149 const parsed = try fromSliceNoAlloc(Vec2, .{
2150 .gpa = gpa,
2151 .arena = arena,
2152 .source = ".{ 1.2 }",
2153 .diagnostics = &diagnostics,
2154 });
18512155 try std.testing.expectEqual(Vec2{ 1.2, 1.5 }, parsed);
18522156 }
18532157
18542158 // Comptime field assignment
18552159 {
18562160 const Vec2 = struct { f32, comptime f32 = 1.5 };
1857 var diag: Diagnostics = .{};
1858 defer diag.deinit(gpa);
1859 const parsed = fromSlice(Vec2, gpa, ".{ 1.2, 1.5}", &diag, .{});
2161 const parsed = fromSliceNoAlloc(Vec2, .{
2162 .gpa = gpa,
2163 .arena = arena,
2164 .source = ".{ 1.2, 1.5}",
2165 .diagnostics = &diagnostics,
2166 });
18602167 try std.testing.expectError(error.ParseZon, parsed);
18612168 try std.testing.expectFmt(
1862 \\1:9: error: cannot initialize comptime field
2169 \\input.zon:1:9: error: cannot initialize comptime field
18632170 \\
1864 , "{f}", .{diag});
2171 , "{f}", .{diagnostics.fmt("input.zon")});
18652172 }
18662173}
18672174
18682175// Test sizes 0 to 3 since small sizes get parsed differently
18692176test "std.zon arrays and slices" {
18702177 const gpa = std.testing.allocator;
2178 var arena_allocator: ArenaAllocator = .init(gpa);
2179 defer arena_allocator.deinit();
2180 const arena = arena_allocator.allocator();
2181 var diagnostics: Diagnostics = undefined;
18712182
18722183 // Literals
18732184 {
18742185 // Arrays
18752186 {
1876 const zero = try fromSlice([0]u8, gpa, ".{}", null, .{});
2187 const zero = try fromSliceNoAlloc([0]u8, .{
2188 .gpa = gpa,
2189 .arena = arena,
2190 .source = ".{}",
2191 .diagnostics = &diagnostics,
2192 });
18772193 try std.testing.expectEqualSlices(u8, &@as([0]u8, .{}), &zero);
18782194
1879 const one = try fromSlice([1]u8, gpa, ".{'a'}", null, .{});
2195 const one = try fromSliceNoAlloc([1]u8, .{
2196 .gpa = gpa,
2197 .arena = arena,
2198 .source = ".{'a'}",
2199 .diagnostics = &diagnostics,
2200 });
18802201 try std.testing.expectEqualSlices(u8, &@as([1]u8, .{'a'}), &one);
18812202
1882 const two = try fromSlice([2]u8, gpa, ".{'a', 'b'}", null, .{});
2203 const two = try fromSliceNoAlloc([2]u8, .{
2204 .gpa = gpa,
2205 .arena = arena,
2206 .source = ".{'a', 'b'}",
2207 .diagnostics = &diagnostics,
2208 });
18832209 try std.testing.expectEqualSlices(u8, &@as([2]u8, .{ 'a', 'b' }), &two);
18842210
1885 const two_comma = try fromSlice([2]u8, gpa, ".{'a', 'b',}", null, .{});
2211 const two_comma = try fromSliceNoAlloc([2]u8, .{
2212 .gpa = gpa,
2213 .arena = arena,
2214 .source = ".{'a', 'b',}",
2215 .diagnostics = &diagnostics,
2216 });
18862217 try std.testing.expectEqualSlices(u8, &@as([2]u8, .{ 'a', 'b' }), &two_comma);
18872218
1888 const three = try fromSlice([3]u8, gpa, ".{'a', 'b', 'c'}", null, .{});
2219 const three = try fromSliceNoAlloc([3]u8, .{
2220 .gpa = gpa,
2221 .arena = arena,
2222 .source = ".{'a', 'b', 'c'}",
2223 .diagnostics = &diagnostics,
2224 });
18892225 try std.testing.expectEqualSlices(u8, &.{ 'a', 'b', 'c' }, &three);
18902226
1891 const sentinel = try fromSlice([3:'z']u8, gpa, ".{'a', 'b', 'c'}", null, .{});
2227 const sentinel = try fromSliceNoAlloc([3:'z']u8, .{
2228 .gpa = gpa,
2229 .arena = arena,
2230 .source = ".{'a', 'b', 'c'}",
2231 .diagnostics = &diagnostics,
2232 });
18922233 const expected_sentinel: [3:'z']u8 = .{ 'a', 'b', 'c' };
18932234 try std.testing.expectEqualSlices(u8, &expected_sentinel, &sentinel);
18942235 }
18952236
18962237 // Slice literals
18972238 {
1898 const zero = try fromSliceAlloc([]const u8, gpa, ".{}", null, .{});
1899 defer free(gpa, zero);
2239 const zero = try fromSlice([]const u8, .{
2240 .gpa = gpa,
2241 .arena = arena,
2242 .source = ".{}",
2243 .diagnostics = &diagnostics,
2244 });
19002245 try std.testing.expectEqualSlices(u8, @as([]const u8, &.{}), zero);
19012246
1902 const one = try fromSliceAlloc([]u8, gpa, ".{'a'}", null, .{});
1903 defer free(gpa, one);
2247 const one = try fromSlice([]u8, .{
2248 .gpa = gpa,
2249 .arena = arena,
2250 .source = ".{'a'}",
2251 .diagnostics = &diagnostics,
2252 });
19042253 try std.testing.expectEqualSlices(u8, &.{'a'}, one);
19052254
1906 const two = try fromSliceAlloc([]const u8, gpa, ".{'a', 'b'}", null, .{});
1907 defer free(gpa, two);
2255 const two = try fromSlice([]const u8, .{
2256 .gpa = gpa,
2257 .arena = arena,
2258 .source = ".{'a', 'b'}",
2259 .diagnostics = &diagnostics,
2260 });
19082261 try std.testing.expectEqualSlices(u8, &.{ 'a', 'b' }, two);
19092262
1910 const two_comma = try fromSliceAlloc([]const u8, gpa, ".{'a', 'b',}", null, .{});
1911 defer free(gpa, two_comma);
2263 const two_comma = try fromSlice([]const u8, .{
2264 .gpa = gpa,
2265 .arena = arena,
2266 .source = ".{'a', 'b',}",
2267 .diagnostics = &diagnostics,
2268 });
19122269 try std.testing.expectEqualSlices(u8, &.{ 'a', 'b' }, two_comma);
19132270
1914 const three = try fromSliceAlloc([]u8, gpa, ".{'a', 'b', 'c'}", null, .{});
1915 defer free(gpa, three);
2271 const three = try fromSlice([]u8, .{
2272 .gpa = gpa,
2273 .arena = arena,
2274 .source = ".{'a', 'b', 'c'}",
2275 .diagnostics = &diagnostics,
2276 });
19162277 try std.testing.expectEqualSlices(u8, &.{ 'a', 'b', 'c' }, three);
19172278
1918 const sentinel = try fromSliceAlloc([:'z']const u8, gpa, ".{'a', 'b', 'c'}", null, .{});
1919 defer free(gpa, sentinel);
2279 const sentinel = try fromSlice([:'z']const u8, .{
2280 .gpa = gpa,
2281 .arena = arena,
2282 .source = ".{'a', 'b', 'c'}",
2283 .diagnostics = &diagnostics,
2284 });
19202285 const expected_sentinel: [:'z']const u8 = &.{ 'a', 'b', 'c' };
19212286 try std.testing.expectEqualSlices(u8, expected_sentinel, sentinel);
19222287 }
......@@ -1926,16 +2291,24 @@ test "std.zon arrays and slices" {
19262291 {
19272292 // Arrays
19282293 {
1929 const parsed = try fromSliceAlloc([1][]const u8, gpa, ".{\"abc\"}", null, .{});
1930 defer free(gpa, parsed);
2294 const parsed = try fromSlice([1][]const u8, .{
2295 .gpa = gpa,
2296 .arena = arena,
2297 .source = ".{\"abc\"}",
2298 .diagnostics = &diagnostics,
2299 });
19312300 const expected: [1][]const u8 = .{"abc"};
19322301 try std.testing.expectEqualDeep(expected, parsed);
19332302 }
19342303
19352304 // Slice literals
19362305 {
1937 const parsed = try fromSliceAlloc([]const []const u8, gpa, ".{\"abc\"}", null, .{});
1938 defer free(gpa, parsed);
2306 const parsed = try fromSlice([]const []const u8, .{
2307 .gpa = gpa,
2308 .arena = arena,
2309 .source = ".{\"abc\"}",
2310 .diagnostics = &diagnostics,
2311 });
19392312 const expected: []const []const u8 = &.{"abc"};
19402313 try std.testing.expectEqualDeep(expected, parsed);
19412314 }
......@@ -1945,7 +2318,12 @@ test "std.zon arrays and slices" {
19452318 {
19462319 // Arrays
19472320 {
1948 const sentinel = try fromSlice([1:2]u8, gpa, ".{1}", null, .{});
2321 const sentinel = try fromSliceNoAlloc([1:2]u8, .{
2322 .gpa = gpa,
2323 .arena = arena,
2324 .source = ".{1}",
2325 .diagnostics = &diagnostics,
2326 });
19492327 try std.testing.expectEqual(@as(usize, 1), sentinel.len);
19502328 try std.testing.expectEqual(@as(u8, 1), sentinel[0]);
19512329 try std.testing.expectEqual(@as(u8, 2), sentinel[1]);
......@@ -1953,8 +2331,12 @@ test "std.zon arrays and slices" {
19532331
19542332 // Slice literals
19552333 {
1956 const sentinel = try fromSliceAlloc([:2]align(4) u8, gpa, ".{1}", null, .{});
1957 defer free(gpa, sentinel);
2334 const sentinel = try fromSlice([:2]align(4) u8, .{
2335 .gpa = gpa,
2336 .arena = arena,
2337 .source = ".{1}",
2338 .diagnostics = &diagnostics,
2339 });
19582340 try std.testing.expectEqual(@as(usize, 1), sentinel.len);
19592341 try std.testing.expectEqual(@as(u8, 1), sentinel[0]);
19602342 try std.testing.expectEqual(@as(u8, 2), sentinel[1]);
......@@ -1963,86 +2345,106 @@ test "std.zon arrays and slices" {
19632345
19642346 // Expect 0 find 3
19652347 {
1966 var diag: Diagnostics = .{};
1967 defer diag.deinit(gpa);
19682348 try std.testing.expectError(
19692349 error.ParseZon,
1970 fromSlice([0]u8, gpa, ".{'a', 'b', 'c'}", &diag, .{}),
2350 fromSliceNoAlloc([0]u8, .{
2351 .gpa = gpa,
2352 .arena = arena,
2353 .source = ".{'a', 'b', 'c'}",
2354 .diagnostics = &diagnostics,
2355 }),
19712356 );
19722357 try std.testing.expectFmt(
1973 "1:3: error: index 0 outside of array of length 0\n",
1974 "{f}",
1975 .{diag},
1976 );
2358 \\input.zon:1:3: error: index 0 outside of array of length 0
2359 \\
2360 , "{f}", .{diagnostics.fmt("input.zon")});
19772361 }
19782362
19792363 // Expect 1 find 2
19802364 {
1981 var diag: Diagnostics = .{};
1982 defer diag.deinit(gpa);
19832365 try std.testing.expectError(
19842366 error.ParseZon,
1985 fromSlice([1]u8, gpa, ".{'a', 'b'}", &diag, .{}),
2367 fromSliceNoAlloc([1]u8, .{
2368 .gpa = gpa,
2369 .arena = arena,
2370 .source = ".{'a', 'b'}",
2371 .diagnostics = &diagnostics,
2372 }),
19862373 );
19872374 try std.testing.expectFmt(
1988 "1:8: error: index 1 outside of array of length 1\n",
1989 "{f}",
1990 .{diag},
1991 );
2375 \\input.zon:1:8: error: index 1 outside of array of length 1
2376 \\
2377 , "{f}", .{diagnostics.fmt("input.zon")});
19922378 }
19932379
19942380 // Expect 2 find 1
19952381 {
1996 var diag: Diagnostics = .{};
1997 defer diag.deinit(gpa);
19982382 try std.testing.expectError(
19992383 error.ParseZon,
2000 fromSlice([2]u8, gpa, ".{'a'}", &diag, .{}),
2384 fromSliceNoAlloc([2]u8, .{
2385 .gpa = gpa,
2386 .arena = arena,
2387 .source = ".{'a'}",
2388 .diagnostics = &diagnostics,
2389 }),
20012390 );
20022391 try std.testing.expectFmt(
2003 "1:2: error: expected 2 array elements; found 1\n",
2004 "{f}",
2005 .{diag},
2006 );
2392 \\input.zon:1:2: error: expected 2 array elements; found 1
2393 \\
2394 , "{f}", .{diagnostics.fmt("input.zon")});
20072395 }
20082396
20092397 // Expect 3 find 0
20102398 {
2011 var diag: Diagnostics = .{};
2012 defer diag.deinit(gpa);
20132399 try std.testing.expectError(
20142400 error.ParseZon,
2015 fromSlice([3]u8, gpa, ".{}", &diag, .{}),
2401 fromSliceNoAlloc([3]u8, .{
2402 .gpa = gpa,
2403 .arena = arena,
2404 .source = ".{}",
2405 .diagnostics = &diagnostics,
2406 }),
20162407 );
20172408 try std.testing.expectFmt(
2018 "1:2: error: expected 3 array elements; found 0\n",
2019 "{f}",
2020 .{diag},
2021 );
2409 \\input.zon:1:2: error: expected 3 array elements; found 0
2410 \\
2411 , "{f}", .{diagnostics.fmt("input.zon")});
20222412 }
20232413
20242414 // Wrong inner type
20252415 {
20262416 // Array
20272417 {
2028 var diag: Diagnostics = .{};
2029 defer diag.deinit(gpa);
20302418 try std.testing.expectError(
20312419 error.ParseZon,
2032 fromSlice([3]bool, gpa, ".{'a', 'b', 'c'}", &diag, .{}),
2420 fromSliceNoAlloc([3]bool, .{
2421 .gpa = gpa,
2422 .arena = arena,
2423 .source = ".{'a', 'b', 'c'}",
2424 .diagnostics = &diagnostics,
2425 }),
20332426 );
2034 try std.testing.expectFmt("1:3: error: expected type 'bool'\n", "{f}", .{diag});
2427 try std.testing.expectFmt(
2428 \\input.zon:1:3: error: expected type 'bool'
2429 \\
2430 , "{f}", .{diagnostics.fmt("input.zon")});
20352431 }
20362432
20372433 // Slice
20382434 {
2039 var diag: Diagnostics = .{};
2040 defer diag.deinit(gpa);
20412435 try std.testing.expectError(
20422436 error.ParseZon,
2043 fromSliceAlloc([]bool, gpa, ".{'a', 'b', 'c'}", &diag, .{}),
2437 fromSlice([]bool, .{
2438 .gpa = gpa,
2439 .arena = arena,
2440 .source = ".{'a', 'b', 'c'}",
2441 .diagnostics = &diagnostics,
2442 }),
20442443 );
2045 try std.testing.expectFmt("1:3: error: expected type 'bool'\n", "{f}", .{diag});
2444 try std.testing.expectFmt(
2445 \\input.zon:1:3: error: expected type 'bool'
2446 \\
2447 , "{f}", .{diagnostics.fmt("input.zon")});
20462448 }
20472449 }
20482450
......@@ -2050,87 +2452,109 @@ test "std.zon arrays and slices" {
20502452 {
20512453 // Array
20522454 {
2053 var diag: Diagnostics = .{};
2054 defer diag.deinit(gpa);
20552455 try std.testing.expectError(
20562456 error.ParseZon,
2057 fromSlice([3]u8, gpa, "'a'", &diag, .{}),
2457 fromSliceNoAlloc([3]u8, .{
2458 .gpa = gpa,
2459 .arena = arena,
2460 .source = "'a'",
2461 .diagnostics = &diagnostics,
2462 }),
20582463 );
2059 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2464 try std.testing.expectFmt(
2465 \\input.zon:1:1: error: expected array
2466 \\
2467 , "{f}", .{diagnostics.fmt("input.zon")});
20602468 }
20612469
20622470 // Slice
20632471 {
2064 var diag: Diagnostics = .{};
2065 defer diag.deinit(gpa);
20662472 try std.testing.expectError(
20672473 error.ParseZon,
2068 fromSliceAlloc([]u8, gpa, "'a'", &diag, .{}),
2474 fromSlice([]u8, .{ .gpa = gpa, .arena = arena, .source = "'a'", .diagnostics = &diagnostics }),
20692475 );
2070 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2476 try std.testing.expectFmt(
2477 \\input.zon:1:1: error: expected array
2478 \\
2479 , "{f}", .{diagnostics.fmt("input.zon")});
20712480 }
20722481 }
20732482
20742483 // Address of is not allowed (indirection for slices in ZON is implicit)
20752484 {
2076 var diag: Diagnostics = .{};
2077 defer diag.deinit(gpa);
20782485 try std.testing.expectError(
20792486 error.ParseZon,
2080 fromSliceAlloc([]u8, gpa, " &.{'a', 'b', 'c'}", &diag, .{}),
2487 fromSlice([]u8, .{ .gpa = gpa, .arena = arena, .source = " &.{'a', 'b', 'c'}", .diagnostics = &diagnostics }),
20812488 );
20822489 try std.testing.expectFmt(
2083 "1:3: error: pointers are not available in ZON\n",
2084 "{f}",
2085 .{diag},
2086 );
2490 \\input.zon:1:3: error: pointers are not available in ZON
2491 \\
2492 , "{f}", .{diagnostics.fmt("input.zon")});
20872493 }
20882494}
20892495
20902496test "std.zon string literal" {
20912497 const gpa = std.testing.allocator;
2498 var arena_allocator: ArenaAllocator = .init(gpa);
2499 defer arena_allocator.deinit();
2500 const arena = arena_allocator.allocator();
2501 var diagnostics: Diagnostics = undefined;
20922502
20932503 // Basic string literal
20942504 {
2095 const parsed = try fromSliceAlloc([]const u8, gpa, "\"abc\"", null, .{});
2096 defer free(gpa, parsed);
2505 const parsed = try fromSlice([]const u8, .{
2506 .gpa = gpa,
2507 .arena = arena,
2508 .source = "\"abc\"",
2509 .diagnostics = &diagnostics,
2510 });
20972511 try std.testing.expectEqualStrings(@as([]const u8, "abc"), parsed);
20982512 }
20992513
21002514 // String literal with escape characters
21012515 {
2102 const parsed = try fromSliceAlloc([]const u8, gpa, "\"ab\\nc\"", null, .{});
2103 defer free(gpa, parsed);
2516 const parsed = try fromSlice([]const u8, .{
2517 .gpa = gpa,
2518 .arena = arena,
2519 .source = "\"ab\\nc\"",
2520 .diagnostics = &diagnostics,
2521 });
21042522 try std.testing.expectEqualStrings(@as([]const u8, "ab\nc"), parsed);
21052523 }
21062524
21072525 // String literal with embedded null
21082526 {
2109 const parsed = try fromSliceAlloc([]const u8, gpa, "\"ab\\x00c\"", null, .{});
2110 defer free(gpa, parsed);
2527 const parsed = try fromSlice([]const u8, .{
2528 .gpa = gpa,
2529 .arena = arena,
2530 .source = "\"ab\\x00c\"",
2531 .diagnostics = &diagnostics,
2532 });
21112533 try std.testing.expectEqualStrings(@as([]const u8, "ab\x00c"), parsed);
21122534 }
21132535
21142536 // Passing string literal to a mutable slice
21152537 {
21162538 {
2117 var diag: Diagnostics = .{};
2118 defer diag.deinit(gpa);
21192539 try std.testing.expectError(
21202540 error.ParseZon,
2121 fromSliceAlloc([]u8, gpa, "\"abcd\"", &diag, .{}),
2541 fromSlice([]u8, .{ .gpa = gpa, .arena = arena, .source = "\"abcd\"", .diagnostics = &diagnostics }),
21222542 );
2123 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2543 try std.testing.expectFmt(
2544 \\input.zon:1:1: error: expected array
2545 \\
2546 , "{f}", .{diagnostics.fmt("input.zon")});
21242547 }
21252548
21262549 {
2127 var diag: Diagnostics = .{};
2128 defer diag.deinit(gpa);
21292550 try std.testing.expectError(
21302551 error.ParseZon,
2131 fromSliceAlloc([]u8, gpa, "\\\\abcd", &diag, .{}),
2552 fromSlice([]u8, .{ .gpa = gpa, .arena = arena, .source = "\\\\abcd", .diagnostics = &diagnostics }),
21322553 );
2133 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2554 try std.testing.expectFmt(
2555 \\input.zon:1:1: error: expected array
2556 \\
2557 , "{f}", .{diagnostics.fmt("input.zon")});
21342558 }
21352559 }
21362560
......@@ -2141,50 +2565,58 @@ test "std.zon string literal" {
21412565 defer ast.deinit(gpa);
21422566 var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false });
21432567 defer zoir.deinit(gpa);
2144 var diag: Diagnostics = .{};
2145 defer diag.deinit(gpa);
21462568 try std.testing.expectError(
21472569 error.ParseZon,
2148 fromSlice([4:0]u8, gpa, "\"abcd\"", &diag, .{}),
2570 fromSliceNoAlloc([4:0]u8, .{
2571 .gpa = gpa,
2572 .arena = arena,
2573 .source = "\"abcd\"",
2574 .diagnostics = &diagnostics,
2575 }),
21492576 );
2150 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2577 try std.testing.expectFmt(
2578 \\input.zon:1:1: error: expected array
2579 \\
2580 , "{f}", .{diagnostics.fmt("input.zon")});
21512581 }
21522582
21532583 {
2154 var diag: Diagnostics = .{};
2155 defer diag.deinit(gpa);
21562584 try std.testing.expectError(
21572585 error.ParseZon,
2158 fromSlice([4:0]u8, gpa, "\\\\abcd", &diag, .{}),
2586 fromSliceNoAlloc([4:0]u8, .{
2587 .gpa = gpa,
2588 .arena = arena,
2589 .source = "\\\\abcd",
2590 .diagnostics = &diagnostics,
2591 }),
21592592 );
2160 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2593 try std.testing.expectFmt(
2594 \\input.zon:1:1: error: expected array
2595 \\
2596 , "{f}", .{diagnostics.fmt("input.zon")});
21612597 }
21622598 }
21632599
21642600 // Zero terminated slices
21652601 {
21662602 {
2167 const parsed: [:0]const u8 = try fromSliceAlloc(
2168 [:0]const u8,
2169 gpa,
2170 "\"abc\"",
2171 null,
2172 .{},
2173 );
2174 defer free(gpa, parsed);
2603 const parsed: [:0]const u8 = try fromSlice([:0]const u8, .{
2604 .gpa = gpa,
2605 .arena = arena,
2606 .source = "\"abc\"",
2607 .diagnostics = &diagnostics,
2608 });
21752609 try std.testing.expectEqualStrings("abc", parsed);
21762610 try std.testing.expectEqual(@as(u8, 0), parsed[3]);
21772611 }
21782612
21792613 {
2180 const parsed: [:0]const u8 = try fromSliceAlloc(
2181 [:0]const u8,
2182 gpa,
2183 "\\\\abc",
2184 null,
2185 .{},
2186 );
2187 defer free(gpa, parsed);
2614 const parsed: [:0]const u8 = try fromSlice([:0]const u8, .{
2615 .gpa = gpa,
2616 .arena = arena,
2617 .source = "\\\\abc",
2618 .diagnostics = &diagnostics,
2619 });
21882620 try std.testing.expectEqualStrings("abc", parsed);
21892621 try std.testing.expectEqual(@as(u8, 0), parsed[3]);
21902622 }
......@@ -2193,102 +2625,121 @@ test "std.zon string literal" {
21932625 // Other value terminated slices
21942626 {
21952627 {
2196 var diag: Diagnostics = .{};
2197 defer diag.deinit(gpa);
21982628 try std.testing.expectError(
21992629 error.ParseZon,
2200 fromSliceAlloc([:1]const u8, gpa, "\"foo\"", &diag, .{}),
2630 fromSlice([:1]const u8, .{ .gpa = gpa, .arena = arena, .source = "\"foo\"", .diagnostics = &diagnostics }),
22012631 );
2202 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2632 try std.testing.expectFmt(
2633 \\input.zon:1:1: error: expected array
2634 \\
2635 , "{f}", .{diagnostics.fmt("input.zon")});
22032636 }
22042637
22052638 {
2206 var diag: Diagnostics = .{};
2207 defer diag.deinit(gpa);
22082639 try std.testing.expectError(
22092640 error.ParseZon,
2210 fromSliceAlloc([:1]const u8, gpa, "\\\\foo", &diag, .{}),
2641 fromSlice([:1]const u8, .{ .gpa = gpa, .arena = arena, .source = "\\\\foo", .diagnostics = &diagnostics }),
22112642 );
2212 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2643 try std.testing.expectFmt(
2644 \\input.zon:1:1: error: expected array
2645 \\
2646 , "{f}", .{diagnostics.fmt("input.zon")});
22132647 }
22142648 }
22152649
22162650 // Expecting string literal, getting something else
22172651 {
2218 var diag: Diagnostics = .{};
2219 defer diag.deinit(gpa);
22202652 try std.testing.expectError(
22212653 error.ParseZon,
2222 fromSliceAlloc([]const u8, gpa, "true", &diag, .{}),
2654 fromSlice([]const u8, .{ .gpa = gpa, .arena = arena, .source = "true", .diagnostics = &diagnostics }),
22232655 );
2224 try std.testing.expectFmt("1:1: error: expected string\n", "{f}", .{diag});
2656 try std.testing.expectFmt(
2657 \\input.zon:1:1: error: expected string
2658 \\
2659 , "{f}", .{diagnostics.fmt("input.zon")});
22252660 }
22262661
22272662 // Expecting string literal, getting an incompatible tuple
22282663 {
2229 var diag: Diagnostics = .{};
2230 defer diag.deinit(gpa);
22312664 try std.testing.expectError(
22322665 error.ParseZon,
2233 fromSliceAlloc([]const u8, gpa, ".{false}", &diag, .{}),
2666 fromSlice([]const u8, .{ .gpa = gpa, .arena = arena, .source = ".{false}", .diagnostics = &diagnostics }),
22342667 );
2235 try std.testing.expectFmt("1:3: error: expected type 'u8'\n", "{f}", .{diag});
2668 try std.testing.expectFmt(
2669 \\input.zon:1:3: error: expected type 'u8'
2670 \\
2671 , "{f}", .{diagnostics.fmt("input.zon")});
22362672 }
22372673
22382674 // Invalid string literal
22392675 {
2240 var diag: Diagnostics = .{};
2241 defer diag.deinit(gpa);
22422676 try std.testing.expectError(
22432677 error.ParseZon,
2244 fromSliceAlloc([]const i8, gpa, "\"\\a\"", &diag, .{}),
2678 fromSlice([]const i8, .{ .gpa = gpa, .arena = arena, .source = "\"\\a\"", .diagnostics = &diagnostics }),
22452679 );
2246 try std.testing.expectFmt("1:3: error: invalid escape character: 'a'\n", "{f}", .{diag});
2680 try std.testing.expectFmt(
2681 \\input.zon:1:3: error: invalid escape character: 'a'
2682 \\
2683 , "{f}", .{diagnostics.fmt("input.zon")});
22472684 }
22482685
22492686 // Slice wrong child type
22502687 {
22512688 {
2252 var diag: Diagnostics = .{};
2253 defer diag.deinit(gpa);
22542689 try std.testing.expectError(
22552690 error.ParseZon,
2256 fromSliceAlloc([]const i8, gpa, "\"a\"", &diag, .{}),
2691 fromSlice([]const i8, .{ .gpa = gpa, .arena = arena, .source = "\"a\"", .diagnostics = &diagnostics }),
22572692 );
2258 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2693 try std.testing.expectFmt(
2694 \\input.zon:1:1: error: expected array
2695 \\
2696 , "{f}", .{diagnostics.fmt("input.zon")});
22592697 }
22602698
22612699 {
2262 var diag: Diagnostics = .{};
2263 defer diag.deinit(gpa);
22642700 try std.testing.expectError(
22652701 error.ParseZon,
2266 fromSliceAlloc([]const i8, gpa, "\\\\a", &diag, .{}),
2702 fromSlice([]const i8, .{ .gpa = gpa, .arena = arena, .source = "\\\\a", .diagnostics = &diagnostics }),
22672703 );
2268 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2704 try std.testing.expectFmt(
2705 \\input.zon:1:1: error: expected array
2706 \\
2707 , "{f}", .{diagnostics.fmt("input.zon")});
22692708 }
22702709 }
22712710
22722711 // Bad alignment
22732712 {
22742713 {
2275 var diag: Diagnostics = .{};
2276 defer diag.deinit(gpa);
22772714 try std.testing.expectError(
22782715 error.ParseZon,
2279 fromSliceAlloc([]align(2) const u8, gpa, "\"abc\"", &diag, .{}),
2716 fromSlice([]align(2) const u8, .{
2717 .gpa = gpa,
2718 .arena = arena,
2719 .source = "\"abc\"",
2720 .diagnostics = &diagnostics,
2721 }),
22802722 );
2281 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2723 try std.testing.expectFmt(
2724 \\input.zon:1:1: error: expected array
2725 \\
2726 , "{f}", .{diagnostics.fmt("input.zon")});
22822727 }
22832728
22842729 {
2285 var diag: Diagnostics = .{};
2286 defer diag.deinit(gpa);
22872730 try std.testing.expectError(
22882731 error.ParseZon,
2289 fromSliceAlloc([]align(2) const u8, gpa, "\\\\abc", &diag, .{}),
2732 fromSlice([]align(2) const u8, .{
2733 .gpa = gpa,
2734 .arena = arena,
2735 .source = "\\\\abc",
2736 .diagnostics = &diagnostics,
2737 }),
22902738 );
2291 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2739 try std.testing.expectFmt(
2740 \\input.zon:1:1: error: expected array
2741 \\
2742 , "{f}", .{diagnostics.fmt("input.zon")});
22922743 }
22932744 }
22942745
......@@ -2301,7 +2752,10 @@ test "std.zon string literal" {
23012752 message2: String,
23022753 message3: String,
23032754 };
2304 const parsed = try fromSliceAlloc(S, gpa,
2755 const parsed = try fromSlice(S, .{
2756 .gpa = gpa,
2757 .arena = arena,
2758 .source =
23052759 \\.{
23062760 \\ .message =
23072761 \\ \\hello, world!
......@@ -2318,8 +2772,9 @@ test "std.zon string literal" {
23182772 \\ \\
23192773 \\ \\and this.
23202774 \\}
2321 , null, .{});
2322 defer free(gpa, parsed);
2775 ,
2776 .diagnostics = &diagnostics,
2777 });
23232778 try std.testing.expectEqualStrings(
23242779 "hello, world!\nthis is a multiline string!\n\n...",
23252780 parsed.message,
......@@ -2332,6 +2787,10 @@ test "std.zon string literal" {
23322787
23332788test "std.zon enum literals" {
23342789 const gpa = std.testing.allocator;
2790 var arena_allocator: ArenaAllocator = .init(gpa);
2791 defer arena_allocator.deinit();
2792 const arena = arena_allocator.allocator();
2793 var diagnostics: Diagnostics = undefined;
23352794
23362795 const Enum = enum {
23372796 foo,
......@@ -2341,104 +2800,155 @@ test "std.zon enum literals" {
23412800 };
23422801
23432802 // Tags that exist
2344 try std.testing.expectEqual(Enum.foo, try fromSlice(Enum, gpa, ".foo", null, .{}));
2345 try std.testing.expectEqual(Enum.bar, try fromSlice(Enum, gpa, ".bar", null, .{}));
2346 try std.testing.expectEqual(Enum.baz, try fromSlice(Enum, gpa, ".baz", null, .{}));
2803 try std.testing.expectEqual(Enum.foo, try fromSliceNoAlloc(Enum, .{
2804 .gpa = gpa,
2805 .arena = arena,
2806 .source = ".foo",
2807 .diagnostics = &diagnostics,
2808 }));
2809 try std.testing.expectEqual(Enum.bar, try fromSliceNoAlloc(Enum, .{
2810 .gpa = gpa,
2811 .arena = arena,
2812 .source = ".bar",
2813 .diagnostics = &diagnostics,
2814 }));
2815 try std.testing.expectEqual(Enum.baz, try fromSliceNoAlloc(Enum, .{
2816 .gpa = gpa,
2817 .arena = arena,
2818 .source = ".baz",
2819 .diagnostics = &diagnostics,
2820 }));
23472821 try std.testing.expectEqual(
23482822 Enum.@"ab\nc",
2349 try fromSlice(Enum, gpa, ".@\"ab\\nc\"", null, .{}),
2823 try fromSliceNoAlloc(Enum, .{
2824 .gpa = gpa,
2825 .arena = arena,
2826 .source = ".@\"ab\\nc\"",
2827 .diagnostics = &diagnostics,
2828 }),
23502829 );
23512830
23522831 // Bad tag
23532832 {
2354 var diag: Diagnostics = .{};
2355 defer diag.deinit(gpa);
23562833 try std.testing.expectError(
23572834 error.ParseZon,
2358 fromSlice(Enum, gpa, ".qux", &diag, .{}),
2835 fromSliceNoAlloc(Enum, .{
2836 .gpa = gpa,
2837 .arena = arena,
2838 .source = ".qux",
2839 .diagnostics = &diagnostics,
2840 }),
23592841 );
23602842 try std.testing.expectFmt(
2361 \\1:2: error: unexpected enum literal 'qux'
2362 \\1:2: note: supported: 'foo', 'bar', 'baz', '@"ab\nc"'
2843 \\input.zon:1:2: error: unexpected enum literal 'qux'
2844 \\input.zon:1:2: note: supported: 'foo', 'bar', 'baz', '@"ab\nc"'
23632845 \\
2364 ,
2365 "{f}",
2366 .{diag},
2367 );
2846 , "{f}", .{diagnostics.fmt("input.zon")});
23682847 }
23692848
23702849 // Bad tag that's too long for parser
23712850 {
2372 var diag: Diagnostics = .{};
2373 defer diag.deinit(gpa);
23742851 try std.testing.expectError(
23752852 error.ParseZon,
2376 fromSlice(Enum, gpa, ".@\"foobarbaz\"", &diag, .{}),
2853 fromSliceNoAlloc(Enum, .{
2854 .gpa = gpa,
2855 .arena = arena,
2856 .source = ".@\"foobarbaz\"",
2857 .diagnostics = &diagnostics,
2858 }),
23772859 );
23782860 try std.testing.expectFmt(
2379 \\1:2: error: unexpected enum literal 'foobarbaz'
2380 \\1:2: note: supported: 'foo', 'bar', 'baz', '@"ab\nc"'
2861 \\input.zon:1:2: error: unexpected enum literal 'foobarbaz'
2862 \\input.zon:1:2: note: supported: 'foo', 'bar', 'baz', '@"ab\nc"'
23812863 \\
2382 ,
2383 "{f}",
2384 .{diag},
2385 );
2864 , "{f}", .{diagnostics.fmt("input.zon")});
23862865 }
23872866
23882867 // Bad type
23892868 {
2390 var diag: Diagnostics = .{};
2391 defer diag.deinit(gpa);
23922869 try std.testing.expectError(
23932870 error.ParseZon,
2394 fromSlice(Enum, gpa, "true", &diag, .{}),
2871 fromSliceNoAlloc(Enum, .{
2872 .gpa = gpa,
2873 .arena = arena,
2874 .source = "true",
2875 .diagnostics = &diagnostics,
2876 }),
23952877 );
2396 try std.testing.expectFmt("1:1: error: expected enum literal\n", "{f}", .{diag});
2878 try std.testing.expectFmt(
2879 \\input.zon:1:1: error: expected enum literal
2880 \\
2881 , "{f}", .{diagnostics.fmt("input.zon")});
23972882 }
23982883
23992884 // Test embedded nulls in an identifier
24002885 {
2401 var diag: Diagnostics = .{};
2402 defer diag.deinit(gpa);
24032886 try std.testing.expectError(
24042887 error.ParseZon,
2405 fromSlice(Enum, gpa, ".@\"\\x00\"", &diag, .{}),
2888 fromSliceNoAlloc(Enum, .{
2889 .gpa = gpa,
2890 .arena = arena,
2891 .source = ".@\"\\x00\"",
2892 .diagnostics = &diagnostics,
2893 }),
24062894 );
24072895 try std.testing.expectFmt(
2408 "1:2: error: identifier cannot contain null bytes\n",
2409 "{f}",
2410 .{diag},
2411 );
2896 \\input.zon:1:2: error: identifier cannot contain null bytes
2897 \\
2898 , "{f}", .{diagnostics.fmt("input.zon")});
24122899 }
24132900}
24142901
24152902test "std.zon parse bool" {
24162903 const gpa = std.testing.allocator;
2904 var arena_allocator: ArenaAllocator = .init(gpa);
2905 defer arena_allocator.deinit();
2906 const arena = arena_allocator.allocator();
2907 var diagnostics: Diagnostics = undefined;
24172908
24182909 // Correct bools
2419 try std.testing.expectEqual(true, try fromSlice(bool, gpa, "true", null, .{}));
2420 try std.testing.expectEqual(false, try fromSlice(bool, gpa, "false", null, .{}));
2910 try std.testing.expectEqual(true, try fromSliceNoAlloc(bool, .{
2911 .gpa = gpa,
2912 .arena = arena,
2913 .source = "true",
2914 .diagnostics = &diagnostics,
2915 }));
2916 try std.testing.expectEqual(false, try fromSliceNoAlloc(bool, .{
2917 .gpa = gpa,
2918 .arena = arena,
2919 .source = "false",
2920 .diagnostics = &diagnostics,
2921 }));
24212922
24222923 // Errors
24232924 {
2424 var diag: Diagnostics = .{};
2425 defer diag.deinit(gpa);
24262925 try std.testing.expectError(
24272926 error.ParseZon,
2428 fromSlice(bool, gpa, " foo", &diag, .{}),
2927 fromSliceNoAlloc(bool, .{
2928 .gpa = gpa,
2929 .arena = arena,
2930 .source = " foo",
2931 .diagnostics = &diagnostics,
2932 }),
24292933 );
24302934 try std.testing.expectFmt(
2431 \\1:2: error: invalid expression
2432 \\1:2: note: ZON allows identifiers 'true', 'false', 'null', 'inf', and 'nan'
2433 \\1:2: note: precede identifier with '.' for an enum literal
2935 \\input.zon:1:2: error: invalid expression
2936 \\input.zon:1:2: note: ZON allows identifiers 'true', 'false', 'null', 'inf', and 'nan'
2937 \\input.zon:1:2: note: precede identifier with '.' for an enum literal
24342938 \\
2435 , "{f}", .{diag});
2939 , "{f}", .{diagnostics.fmt("input.zon")});
24362940 }
24372941 {
2438 var diag: Diagnostics = .{};
2439 defer diag.deinit(gpa);
2440 try std.testing.expectError(error.ParseZon, fromSlice(bool, gpa, "123", &diag, .{}));
2441 try std.testing.expectFmt("1:1: error: expected type 'bool'\n", "{f}", .{diag});
2942 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(bool, .{
2943 .gpa = gpa,
2944 .arena = arena,
2945 .source = "123",
2946 .diagnostics = &diagnostics,
2947 }));
2948 try std.testing.expectFmt(
2949 \\input.zon:1:1: error: expected type 'bool'
2950 \\
2951 , "{f}", .{diagnostics.fmt("input.zon")});
24422952 }
24432953}
24442954
......@@ -2466,493 +2976,782 @@ test "std.zon intFromFloatExact" {
24662976
24672977test "std.zon parse int" {
24682978 const gpa = std.testing.allocator;
2979 var arena_allocator: ArenaAllocator = .init(gpa);
2980 defer arena_allocator.deinit();
2981 const arena = arena_allocator.allocator();
2982 var diagnostics: Diagnostics = undefined;
24692983
24702984 // Test various numbers and types
2471 try std.testing.expectEqual(@as(u8, 10), try fromSlice(u8, gpa, "10", null, .{}));
2472 try std.testing.expectEqual(@as(i16, 24), try fromSlice(i16, gpa, "24", null, .{}));
2473 try std.testing.expectEqual(@as(i14, -4), try fromSlice(i14, gpa, "-4", null, .{}));
2474 try std.testing.expectEqual(@as(i32, -123), try fromSlice(i32, gpa, "-123", null, .{}));
2985 try std.testing.expectEqual(@as(u8, 10), try fromSliceNoAlloc(u8, .{
2986 .gpa = gpa,
2987 .arena = arena,
2988 .source = "10",
2989 .diagnostics = &diagnostics,
2990 }));
2991 try std.testing.expectEqual(@as(i16, 24), try fromSliceNoAlloc(i16, .{
2992 .gpa = gpa,
2993 .arena = arena,
2994 .source = "24",
2995 .diagnostics = &diagnostics,
2996 }));
2997 try std.testing.expectEqual(@as(i14, -4), try fromSliceNoAlloc(i14, .{
2998 .gpa = gpa,
2999 .arena = arena,
3000 .source = "-4",
3001 .diagnostics = &diagnostics,
3002 }));
3003 try std.testing.expectEqual(@as(i32, -123), try fromSliceNoAlloc(i32, .{
3004 .gpa = gpa,
3005 .arena = arena,
3006 .source = "-123",
3007 .diagnostics = &diagnostics,
3008 }));
24753009
24763010 // Test limits
2477 try std.testing.expectEqual(@as(i8, 127), try fromSlice(i8, gpa, "127", null, .{}));
2478 try std.testing.expectEqual(@as(i8, -128), try fromSlice(i8, gpa, "-128", null, .{}));
3011 try std.testing.expectEqual(@as(i8, 127), try fromSliceNoAlloc(i8, .{
3012 .gpa = gpa,
3013 .arena = arena,
3014 .source = "127",
3015 .diagnostics = &diagnostics,
3016 }));
3017 try std.testing.expectEqual(@as(i8, -128), try fromSliceNoAlloc(i8, .{
3018 .gpa = gpa,
3019 .arena = arena,
3020 .source = "-128",
3021 .diagnostics = &diagnostics,
3022 }));
24793023
24803024 // Test characters
2481 try std.testing.expectEqual(@as(u8, 'a'), try fromSlice(u8, gpa, "'a'", null, .{}));
2482 try std.testing.expectEqual(@as(u8, 'z'), try fromSlice(u8, gpa, "'z'", null, .{}));
3025 try std.testing.expectEqual(@as(u8, 'a'), try fromSliceNoAlloc(u8, .{
3026 .gpa = gpa,
3027 .arena = arena,
3028 .source = "'a'",
3029 .diagnostics = &diagnostics,
3030 }));
3031 try std.testing.expectEqual(@as(u8, 'z'), try fromSliceNoAlloc(u8, .{
3032 .gpa = gpa,
3033 .arena = arena,
3034 .source = "'z'",
3035 .diagnostics = &diagnostics,
3036 }));
24833037
24843038 // Test big integers
24853039 try std.testing.expectEqual(
24863040 @as(u65, 36893488147419103231),
2487 try fromSlice(u65, gpa, "36893488147419103231", null, .{}),
3041 try fromSliceNoAlloc(u65, .{
3042 .gpa = gpa,
3043 .arena = arena,
3044 .source = "36893488147419103231",
3045 .diagnostics = &diagnostics,
3046 }),
24883047 );
24893048 try std.testing.expectEqual(
24903049 @as(u65, 36893488147419103231),
2491 try fromSlice(u65, gpa, "368934_881_474191032_31", null, .{}),
3050 try fromSliceNoAlloc(u65, .{
3051 .gpa = gpa,
3052 .arena = arena,
3053 .source = "368934_881_474191032_31",
3054 .diagnostics = &diagnostics,
3055 }),
24923056 );
24933057 try std.testing.expectEqual(
24943058 @as(u128, 340282366920938463463374607431768211455),
2495 try fromSlice(u128, gpa, "340282366920938463463374607431768211455", null, .{}),
3059 try fromSliceNoAlloc(u128, .{
3060 .gpa = gpa,
3061 .arena = arena,
3062 .source = "340282366920938463463374607431768211455",
3063 .diagnostics = &diagnostics,
3064 }),
24963065 );
24973066
24983067 // Test big integer limits
24993068 try std.testing.expectEqual(
25003069 @as(i66, 36893488147419103231),
2501 try fromSlice(i66, gpa, "36893488147419103231", null, .{}),
3070 try fromSliceNoAlloc(i66, .{
3071 .gpa = gpa,
3072 .arena = arena,
3073 .source = "36893488147419103231",
3074 .diagnostics = &diagnostics,
3075 }),
25023076 );
25033077 try std.testing.expectEqual(
25043078 @as(i66, -36893488147419103232),
2505 try fromSlice(i66, gpa, "-36893488147419103232", null, .{}),
3079 try fromSliceNoAlloc(i66, .{
3080 .gpa = gpa,
3081 .arena = arena,
3082 .source = "-36893488147419103232",
3083 .diagnostics = &diagnostics,
3084 }),
25063085 );
25073086 {
2508 var diag: Diagnostics = .{};
2509 defer diag.deinit(gpa);
2510 try std.testing.expectError(error.ParseZon, fromSlice(
2511 i66,
2512 gpa,
2513 "36893488147419103232",
2514 &diag,
2515 .{},
2516 ));
2517 try std.testing.expectFmt(
2518 "1:1: error: type 'i66' cannot represent value\n",
2519 "{f}",
2520 .{diag},
2521 );
3087 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i66, .{
3088 .gpa = gpa,
3089 .arena = arena,
3090 .source = "36893488147419103232",
3091 .diagnostics = &diagnostics,
3092 }));
3093 try std.testing.expectFmt(
3094 \\input.zon:1:1: error: type 'i66' cannot represent value
3095 \\
3096 , "{f}", .{diagnostics.fmt("input.zon")});
25223097 }
25233098 {
2524 var diag: Diagnostics = .{};
2525 defer diag.deinit(gpa);
2526 try std.testing.expectError(error.ParseZon, fromSlice(
2527 i66,
2528 gpa,
2529 "-36893488147419103233",
2530 &diag,
2531 .{},
2532 ));
3099 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i66, .{
3100 .gpa = gpa,
3101 .arena = arena,
3102 .source = "-36893488147419103233",
3103 .diagnostics = &diagnostics,
3104 }));
25333105 try std.testing.expectFmt(
2534 "1:1: error: type 'i66' cannot represent value\n",
2535 "{f}",
2536 .{diag},
2537 );
3106 \\input.zon:1:1: error: type 'i66' cannot represent value
3107 \\
3108 , "{f}", .{diagnostics.fmt("input.zon")});
25383109 }
25393110
25403111 // Test parsing whole number floats as integers
2541 try std.testing.expectEqual(@as(i8, -1), try fromSlice(i8, gpa, "-1.0", null, .{}));
2542 try std.testing.expectEqual(@as(i8, 123), try fromSlice(i8, gpa, "123.0", null, .{}));
3112 try std.testing.expectEqual(@as(i8, -1), try fromSliceNoAlloc(i8, .{
3113 .gpa = gpa,
3114 .arena = arena,
3115 .source = "-1.0",
3116 .diagnostics = &diagnostics,
3117 }));
3118 try std.testing.expectEqual(@as(i8, 123), try fromSliceNoAlloc(i8, .{
3119 .gpa = gpa,
3120 .arena = arena,
3121 .source = "123.0",
3122 .diagnostics = &diagnostics,
3123 }));
25433124
25443125 // Test non-decimal integers
2545 try std.testing.expectEqual(@as(i16, 0xff), try fromSlice(i16, gpa, "0xff", null, .{}));
2546 try std.testing.expectEqual(@as(i16, -0xff), try fromSlice(i16, gpa, "-0xff", null, .{}));
2547 try std.testing.expectEqual(@as(i16, 0o77), try fromSlice(i16, gpa, "0o77", null, .{}));
2548 try std.testing.expectEqual(@as(i16, -0o77), try fromSlice(i16, gpa, "-0o77", null, .{}));
2549 try std.testing.expectEqual(@as(i16, 0b11), try fromSlice(i16, gpa, "0b11", null, .{}));
2550 try std.testing.expectEqual(@as(i16, -0b11), try fromSlice(i16, gpa, "-0b11", null, .{}));
3126 try std.testing.expectEqual(@as(i16, 0xff), try fromSliceNoAlloc(i16, .{
3127 .gpa = gpa,
3128 .arena = arena,
3129 .source = "0xff",
3130 .diagnostics = &diagnostics,
3131 }));
3132 try std.testing.expectEqual(@as(i16, -0xff), try fromSliceNoAlloc(i16, .{
3133 .gpa = gpa,
3134 .arena = arena,
3135 .source = "-0xff",
3136 .diagnostics = &diagnostics,
3137 }));
3138 try std.testing.expectEqual(@as(i16, 0o77), try fromSliceNoAlloc(i16, .{
3139 .gpa = gpa,
3140 .arena = arena,
3141 .source = "0o77",
3142 .diagnostics = &diagnostics,
3143 }));
3144 try std.testing.expectEqual(@as(i16, -0o77), try fromSliceNoAlloc(i16, .{
3145 .gpa = gpa,
3146 .arena = arena,
3147 .source = "-0o77",
3148 .diagnostics = &diagnostics,
3149 }));
3150 try std.testing.expectEqual(@as(i16, 0b11), try fromSliceNoAlloc(i16, .{
3151 .gpa = gpa,
3152 .arena = arena,
3153 .source = "0b11",
3154 .diagnostics = &diagnostics,
3155 }));
3156 try std.testing.expectEqual(@as(i16, -0b11), try fromSliceNoAlloc(i16, .{
3157 .gpa = gpa,
3158 .arena = arena,
3159 .source = "-0b11",
3160 .diagnostics = &diagnostics,
3161 }));
25513162
25523163 // Test non-decimal big integers
2553 try std.testing.expectEqual(@as(u65, 0x1ffffffffffffffff), try fromSlice(
2554 u65,
2555 gpa,
2556 "0x1ffffffffffffffff",
2557 null,
2558 .{},
2559 ));
2560 try std.testing.expectEqual(@as(i66, 0x1ffffffffffffffff), try fromSlice(
2561 i66,
2562 gpa,
2563 "0x1ffffffffffffffff",
2564 null,
2565 .{},
2566 ));
2567 try std.testing.expectEqual(@as(i66, -0x1ffffffffffffffff), try fromSlice(
2568 i66,
2569 gpa,
2570 "-0x1ffffffffffffffff",
2571 null,
2572 .{},
2573 ));
2574 try std.testing.expectEqual(@as(u65, 0x1ffffffffffffffff), try fromSlice(
2575 u65,
2576 gpa,
2577 "0o3777777777777777777777",
2578 null,
2579 .{},
2580 ));
2581 try std.testing.expectEqual(@as(i66, 0x1ffffffffffffffff), try fromSlice(
2582 i66,
2583 gpa,
2584 "0o3777777777777777777777",
2585 null,
2586 .{},
2587 ));
2588 try std.testing.expectEqual(@as(i66, -0x1ffffffffffffffff), try fromSlice(
2589 i66,
2590 gpa,
2591 "-0o3777777777777777777777",
2592 null,
2593 .{},
2594 ));
2595 try std.testing.expectEqual(@as(u65, 0x1ffffffffffffffff), try fromSlice(
2596 u65,
2597 gpa,
2598 "0b11111111111111111111111111111111111111111111111111111111111111111",
2599 null,
2600 .{},
2601 ));
2602 try std.testing.expectEqual(@as(i66, 0x1ffffffffffffffff), try fromSlice(
2603 i66,
2604 gpa,
2605 "0b11111111111111111111111111111111111111111111111111111111111111111",
2606 null,
2607 .{},
2608 ));
2609 try std.testing.expectEqual(@as(i66, -0x1ffffffffffffffff), try fromSlice(
2610 i66,
2611 gpa,
2612 "-0b11111111111111111111111111111111111111111111111111111111111111111",
2613 null,
2614 .{},
2615 ));
3164 try std.testing.expectEqual(@as(u65, 0x1ffffffffffffffff), try fromSliceNoAlloc(u65, .{
3165 .gpa = gpa,
3166 .arena = arena,
3167 .source = "0x1ffffffffffffffff",
3168 .diagnostics = &diagnostics,
3169 }));
3170 try std.testing.expectEqual(@as(i66, 0x1ffffffffffffffff), try fromSliceNoAlloc(i66, .{
3171 .gpa = gpa,
3172 .arena = arena,
3173 .source = "0x1ffffffffffffffff",
3174 .diagnostics = &diagnostics,
3175 }));
3176 try std.testing.expectEqual(@as(i66, -0x1ffffffffffffffff), try fromSliceNoAlloc(i66, .{
3177 .gpa = gpa,
3178 .arena = arena,
3179 .source = "-0x1ffffffffffffffff",
3180 .diagnostics = &diagnostics,
3181 }));
3182 try std.testing.expectEqual(@as(u65, 0x1ffffffffffffffff), try fromSliceNoAlloc(u65, .{
3183 .gpa = gpa,
3184 .arena = arena,
3185 .source = "0o3777777777777777777777",
3186 .diagnostics = &diagnostics,
3187 }));
3188 try std.testing.expectEqual(@as(i66, 0x1ffffffffffffffff), try fromSliceNoAlloc(i66, .{
3189 .gpa = gpa,
3190 .arena = arena,
3191 .source = "0o3777777777777777777777",
3192 .diagnostics = &diagnostics,
3193 }));
3194 try std.testing.expectEqual(@as(i66, -0x1ffffffffffffffff), try fromSliceNoAlloc(i66, .{
3195 .gpa = gpa,
3196 .arena = arena,
3197 .source = "-0o3777777777777777777777",
3198 .diagnostics = &diagnostics,
3199 }));
3200 try std.testing.expectEqual(@as(u65, 0x1ffffffffffffffff), try fromSliceNoAlloc(u65, .{
3201 .gpa = gpa,
3202 .arena = arena,
3203 .source = "0b11111111111111111111111111111111111111111111111111111111111111111",
3204 .diagnostics = &diagnostics,
3205 }));
3206 try std.testing.expectEqual(@as(i66, 0x1ffffffffffffffff), try fromSliceNoAlloc(i66, .{
3207 .gpa = gpa,
3208 .arena = arena,
3209 .source = "0b11111111111111111111111111111111111111111111111111111111111111111",
3210 .diagnostics = &diagnostics,
3211 }));
3212 try std.testing.expectEqual(@as(i66, -0x1ffffffffffffffff), try fromSliceNoAlloc(i66, .{
3213 .gpa = gpa,
3214 .arena = arena,
3215 .source = "-0b11111111111111111111111111111111111111111111111111111111111111111",
3216 .diagnostics = &diagnostics,
3217 }));
26163218
26173219 // Number with invalid character in the middle
26183220 {
2619 var diag: Diagnostics = .{};
2620 defer diag.deinit(gpa);
2621 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "32a32", &diag, .{}));
3221 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
3222 .gpa = gpa,
3223 .arena = arena,
3224 .source = "32a32",
3225 .diagnostics = &diagnostics,
3226 }));
26223227 try std.testing.expectFmt(
2623 "1:3: error: invalid digit 'a' for decimal base\n",
2624 "{f}",
2625 .{diag},
2626 );
3228 \\input.zon:1:3: error: invalid digit 'a' for decimal base
3229 \\
3230 , "{f}", .{diagnostics.fmt("input.zon")});
26273231 }
26283232
26293233 // Failing to parse as int
26303234 {
2631 var diag: Diagnostics = .{};
2632 defer diag.deinit(gpa);
2633 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "true", &diag, .{}));
2634 try std.testing.expectFmt("1:1: error: expected type 'u8'\n", "{f}", .{diag});
3235 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
3236 .gpa = gpa,
3237 .arena = arena,
3238 .source = "true",
3239 .diagnostics = &diagnostics,
3240 }));
3241 try std.testing.expectFmt(
3242 \\input.zon:1:1: error: expected type 'u8'
3243 \\
3244 , "{f}", .{diagnostics.fmt("input.zon")});
26353245 }
26363246
26373247 // Failing because an int is out of range
26383248 {
2639 var diag: Diagnostics = .{};
2640 defer diag.deinit(gpa);
2641 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "256", &diag, .{}));
3249 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
3250 .gpa = gpa,
3251 .arena = arena,
3252 .source = "256",
3253 .diagnostics = &diagnostics,
3254 }));
26423255 try std.testing.expectFmt(
2643 "1:1: error: type 'u8' cannot represent value\n",
2644 "{f}",
2645 .{diag},
2646 );
3256 \\input.zon:1:1: error: type 'u8' cannot represent value
3257 \\
3258 , "{f}", .{diagnostics.fmt("input.zon")});
26473259 }
26483260
26493261 // Failing because a negative int is out of range
26503262 {
2651 var diag: Diagnostics = .{};
2652 defer diag.deinit(gpa);
2653 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "-129", &diag, .{}));
3263 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i8, .{
3264 .gpa = gpa,
3265 .arena = arena,
3266 .source = "-129",
3267 .diagnostics = &diagnostics,
3268 }));
26543269 try std.testing.expectFmt(
2655 "1:1: error: type 'i8' cannot represent value\n",
2656 "{f}",
2657 .{diag},
2658 );
3270 \\input.zon:1:1: error: type 'i8' cannot represent value
3271 \\
3272 , "{f}", .{diagnostics.fmt("input.zon")});
26593273 }
26603274
26613275 // Failing because an unsigned int is negative
26623276 {
2663 var diag: Diagnostics = .{};
2664 defer diag.deinit(gpa);
2665 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "-1", &diag, .{}));
3277 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
3278 .gpa = gpa,
3279 .arena = arena,
3280 .source = "-1",
3281 .diagnostics = &diagnostics,
3282 }));
26663283 try std.testing.expectFmt(
2667 "1:1: error: type 'u8' cannot represent value\n",
2668 "{f}",
2669 .{diag},
2670 );
3284 \\input.zon:1:1: error: type 'u8' cannot represent value
3285 \\
3286 , "{f}", .{diagnostics.fmt("input.zon")});
26713287 }
26723288
26733289 // Failing because a float is non-whole
26743290 {
2675 var diag: Diagnostics = .{};
2676 defer diag.deinit(gpa);
2677 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "1.5", &diag, .{}));
3291 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
3292 .gpa = gpa,
3293 .arena = arena,
3294 .source = "1.5",
3295 .diagnostics = &diagnostics,
3296 }));
26783297 try std.testing.expectFmt(
2679 "1:1: error: type 'u8' cannot represent value\n",
2680 "{f}",
2681 .{diag},
2682 );
3298 \\input.zon:1:1: error: type 'u8' cannot represent value
3299 \\
3300 , "{f}", .{diagnostics.fmt("input.zon")});
26833301 }
26843302
26853303 // Failing because a float is negative
26863304 {
2687 var diag: Diagnostics = .{};
2688 defer diag.deinit(gpa);
2689 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "-1.0", &diag, .{}));
3305 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
3306 .gpa = gpa,
3307 .arena = arena,
3308 .source = "-1.0",
3309 .diagnostics = &diagnostics,
3310 }));
26903311 try std.testing.expectFmt(
2691 "1:1: error: type 'u8' cannot represent value\n",
2692 "{f}",
2693 .{diag},
2694 );
3312 \\input.zon:1:1: error: type 'u8' cannot represent value
3313 \\
3314 , "{f}", .{diagnostics.fmt("input.zon")});
26953315 }
26963316
26973317 // Negative integer zero
26983318 {
2699 var diag: Diagnostics = .{};
2700 defer diag.deinit(gpa);
2701 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "-0", &diag, .{}));
3319 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i8, .{
3320 .gpa = gpa,
3321 .arena = arena,
3322 .source = "-0",
3323 .diagnostics = &diagnostics,
3324 }));
27023325 try std.testing.expectFmt(
2703 \\1:2: error: integer literal '-0' is ambiguous
2704 \\1:2: note: use '0' for an integer zero
2705 \\1:2: note: use '-0.0' for a floating-point signed zero
3326 \\input.zon:1:2: error: integer literal '-0' is ambiguous
3327 \\input.zon:1:2: note: use '0' for an integer zero
3328 \\input.zon:1:2: note: use '-0.0' for a floating-point signed zero
27063329 \\
2707 , "{f}", .{diag});
3330 , "{f}", .{diagnostics.fmt("input.zon")});
27083331 }
27093332
27103333 // Negative integer zero casted to float
27113334 {
2712 var diag: Diagnostics = .{};
2713 defer diag.deinit(gpa);
2714 try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-0", &diag, .{}));
3335 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(f32, .{
3336 .gpa = gpa,
3337 .arena = arena,
3338 .source = "-0",
3339 .diagnostics = &diagnostics,
3340 }));
27153341 try std.testing.expectFmt(
2716 \\1:2: error: integer literal '-0' is ambiguous
2717 \\1:2: note: use '0' for an integer zero
2718 \\1:2: note: use '-0.0' for a floating-point signed zero
3342 \\input.zon:1:2: error: integer literal '-0' is ambiguous
3343 \\input.zon:1:2: note: use '0' for an integer zero
3344 \\input.zon:1:2: note: use '-0.0' for a floating-point signed zero
27193345 \\
2720 , "{f}", .{diag});
3346 , "{f}", .{diagnostics.fmt("input.zon")});
27213347 }
27223348
27233349 // Negative float 0 is allowed
27243350 try std.testing.expect(
2725 std.math.isNegativeZero(try fromSlice(f32, gpa, "-0.0", null, .{})),
3351 std.math.isNegativeZero(try fromSliceNoAlloc(f32, .{
3352 .gpa = gpa,
3353 .arena = arena,
3354 .source = "-0.0",
3355 .diagnostics = &diagnostics,
3356 })),
27263357 );
2727 try std.testing.expect(std.math.isPositiveZero(try fromSlice(f32, gpa, "0.0", null, .{})));
3358 try std.testing.expect(std.math.isPositiveZero(try fromSliceNoAlloc(f32, .{
3359 .gpa = gpa,
3360 .arena = arena,
3361 .source = "0.0",
3362 .diagnostics = &diagnostics,
3363 })));
27283364
27293365 // Double negation is not allowed
27303366 {
2731 var diag: Diagnostics = .{};
2732 defer diag.deinit(gpa);
2733 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "--2", &diag, .{}));
3367 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i8, .{
3368 .gpa = gpa,
3369 .arena = arena,
3370 .source = "--2",
3371 .diagnostics = &diagnostics,
3372 }));
27343373 try std.testing.expectFmt(
2735 "1:1: error: expected number or 'inf' after '-'\n",
2736 "{f}",
2737 .{diag},
2738 );
3374 \\input.zon:1:1: error: expected number or 'inf' after '-'
3375 \\
3376 , "{f}", .{diagnostics.fmt("input.zon")});
27393377 }
27403378
27413379 {
2742 var diag: Diagnostics = .{};
2743 defer diag.deinit(gpa);
27443380 try std.testing.expectError(
27453381 error.ParseZon,
2746 fromSlice(f32, gpa, "--2.0", &diag, .{}),
3382 fromSliceNoAlloc(f32, .{
3383 .gpa = gpa,
3384 .arena = arena,
3385 .source = "--2.0",
3386 .diagnostics = &diagnostics,
3387 }),
27473388 );
27483389 try std.testing.expectFmt(
2749 "1:1: error: expected number or 'inf' after '-'\n",
2750 "{f}",
2751 .{diag},
2752 );
3390 \\input.zon:1:1: error: expected number or 'inf' after '-'
3391 \\
3392 , "{f}", .{diagnostics.fmt("input.zon")});
27533393 }
27543394
27553395 // Invalid int literal
27563396 {
2757 var diag: Diagnostics = .{};
2758 defer diag.deinit(gpa);
2759 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "0xg", &diag, .{}));
2760 try std.testing.expectFmt("1:3: error: invalid digit 'g' for hex base\n", "{f}", .{diag});
3397 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
3398 .gpa = gpa,
3399 .arena = arena,
3400 .source = "0xg",
3401 .diagnostics = &diagnostics,
3402 }));
3403 try std.testing.expectFmt(
3404 \\input.zon:1:3: error: invalid digit 'g' for hex base
3405 \\
3406 , "{f}", .{diagnostics.fmt("input.zon")});
27613407 }
27623408
27633409 // Notes on invalid int literal
27643410 {
2765 var diag: Diagnostics = .{};
2766 defer diag.deinit(gpa);
2767 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "0123", &diag, .{}));
3411 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
3412 .gpa = gpa,
3413 .arena = arena,
3414 .source = "0123",
3415 .diagnostics = &diagnostics,
3416 }));
27683417 try std.testing.expectFmt(
2769 \\1:1: error: number '0123' has leading zero
2770 \\1:1: note: use '0o' prefix for octal literals
3418 \\input.zon:1:1: error: number '0123' has leading zero
3419 \\input.zon:1:1: note: use '0o' prefix for octal literals
27713420 \\
2772 , "{f}", .{diag});
3421 , "{f}", .{diagnostics.fmt("input.zon")});
27733422 }
27743423}
27753424
27763425test "std.zon negative char" {
27773426 const gpa = std.testing.allocator;
2778
2779 {
2780 var diag: Diagnostics = .{};
2781 defer diag.deinit(gpa);
2782 try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-'a'", &diag, .{}));
3427 var arena_allocator: ArenaAllocator = .init(gpa);
3428 defer arena_allocator.deinit();
3429 const arena = arena_allocator.allocator();
3430 var diagnostics: Diagnostics = undefined;
3431
3432 {
3433 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(f32, .{
3434 .gpa = gpa,
3435 .arena = arena,
3436 .source = "-'a'",
3437 .diagnostics = &diagnostics,
3438 }));
27833439 try std.testing.expectFmt(
2784 "1:1: error: expected number or 'inf' after '-'\n",
2785 "{f}",
2786 .{diag},
2787 );
3440 \\input.zon:1:1: error: expected number or 'inf' after '-'
3441 \\
3442 , "{f}", .{diagnostics.fmt("input.zon")});
27883443 }
27893444 {
2790 var diag: Diagnostics = .{};
2791 defer diag.deinit(gpa);
2792 try std.testing.expectError(error.ParseZon, fromSlice(i16, gpa, "-'a'", &diag, .{}));
3445 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i16, .{
3446 .gpa = gpa,
3447 .arena = arena,
3448 .source = "-'a'",
3449 .diagnostics = &diagnostics,
3450 }));
27933451 try std.testing.expectFmt(
2794 "1:1: error: expected number or 'inf' after '-'\n",
2795 "{f}",
2796 .{diag},
2797 );
3452 \\input.zon:1:1: error: expected number or 'inf' after '-'
3453 \\
3454 , "{f}", .{diagnostics.fmt("input.zon")});
27983455 }
27993456}
28003457
28013458test "std.zon parse float" {
3459 if (builtin.cpu.arch == .x86) return error.SkipZigTest;
3460
28023461 const gpa = std.testing.allocator;
3462 var arena_allocator: ArenaAllocator = .init(gpa);
3463 defer arena_allocator.deinit();
3464 const arena = arena_allocator.allocator();
3465 var diagnostics: Diagnostics = undefined;
28033466
28043467 // Test decimals
2805 try std.testing.expectEqual(@as(f16, 0.5), try fromSlice(f16, gpa, "0.5", null, .{}));
3468 try std.testing.expectEqual(@as(f16, 0.5), try fromSliceNoAlloc(f16, .{
3469 .gpa = gpa,
3470 .arena = arena,
3471 .source = "0.5",
3472 .diagnostics = &diagnostics,
3473 }));
28063474 try std.testing.expectEqual(
28073475 @as(f32, 123.456),
2808 try fromSlice(f32, gpa, "123.456", null, .{}),
3476 try fromSliceNoAlloc(f32, .{
3477 .gpa = gpa,
3478 .arena = arena,
3479 .source = "123.456",
3480 .diagnostics = &diagnostics,
3481 }),
28093482 );
28103483 try std.testing.expectEqual(
28113484 @as(f64, -123.456),
2812 try fromSlice(f64, gpa, "-123.456", null, .{}),
3485 try fromSliceNoAlloc(f64, .{
3486 .gpa = gpa,
3487 .arena = arena,
3488 .source = "-123.456",
3489 .diagnostics = &diagnostics,
3490 }),
28133491 );
2814 try std.testing.expectEqual(@as(f128, 42.5), try fromSlice(f128, gpa, "42.5", null, .{}));
3492 try std.testing.expectEqual(@as(f128, 42.5), try fromSliceNoAlloc(f128, .{
3493 .gpa = gpa,
3494 .arena = arena,
3495 .source = "42.5",
3496 .diagnostics = &diagnostics,
3497 }));
28153498
28163499 // Test whole numbers with and without decimals
2817 try std.testing.expectEqual(@as(f16, 5.0), try fromSlice(f16, gpa, "5.0", null, .{}));
2818 try std.testing.expectEqual(@as(f16, 5.0), try fromSlice(f16, gpa, "5", null, .{}));
2819 try std.testing.expectEqual(@as(f32, -102), try fromSlice(f32, gpa, "-102.0", null, .{}));
2820 try std.testing.expectEqual(@as(f32, -102), try fromSlice(f32, gpa, "-102", null, .{}));
3500 try std.testing.expectEqual(@as(f16, 5.0), try fromSliceNoAlloc(f16, .{
3501 .gpa = gpa,
3502 .arena = arena,
3503 .source = "5.0",
3504 .diagnostics = &diagnostics,
3505 }));
3506 try std.testing.expectEqual(@as(f16, 5.0), try fromSliceNoAlloc(f16, .{
3507 .gpa = gpa,
3508 .arena = arena,
3509 .source = "5",
3510 .diagnostics = &diagnostics,
3511 }));
3512 try std.testing.expectEqual(@as(f32, -102), try fromSliceNoAlloc(f32, .{
3513 .gpa = gpa,
3514 .arena = arena,
3515 .source = "-102.0",
3516 .diagnostics = &diagnostics,
3517 }));
3518 try std.testing.expectEqual(@as(f32, -102), try fromSliceNoAlloc(f32, .{
3519 .gpa = gpa,
3520 .arena = arena,
3521 .source = "-102",
3522 .diagnostics = &diagnostics,
3523 }));
28213524
28223525 // Test characters and negated characters
2823 try std.testing.expectEqual(@as(f32, 'a'), try fromSlice(f32, gpa, "'a'", null, .{}));
2824 try std.testing.expectEqual(@as(f32, 'z'), try fromSlice(f32, gpa, "'z'", null, .{}));
3526 try std.testing.expectEqual(@as(f32, 'a'), try fromSliceNoAlloc(f32, .{
3527 .gpa = gpa,
3528 .arena = arena,
3529 .source = "'a'",
3530 .diagnostics = &diagnostics,
3531 }));
3532 try std.testing.expectEqual(@as(f32, 'z'), try fromSliceNoAlloc(f32, .{
3533 .gpa = gpa,
3534 .arena = arena,
3535 .source = "'z'",
3536 .diagnostics = &diagnostics,
3537 }));
28253538
28263539 // Test big integers
28273540 try std.testing.expectEqual(
28283541 @as(f32, 36893488147419103231.0),
2829 try fromSlice(f32, gpa, "36893488147419103231", null, .{}),
3542 try fromSliceNoAlloc(f32, .{
3543 .gpa = gpa,
3544 .arena = arena,
3545 .source = "36893488147419103231",
3546 .diagnostics = &diagnostics,
3547 }),
28303548 );
28313549 try std.testing.expectEqual(
28323550 @as(f32, -36893488147419103231.0),
2833 try fromSlice(f32, gpa, "-36893488147419103231", null, .{}),
3551 try fromSliceNoAlloc(f32, .{
3552 .gpa = gpa,
3553 .arena = arena,
3554 .source = "-36893488147419103231",
3555 .diagnostics = &diagnostics,
3556 }),
28343557 );
2835 try std.testing.expectEqual(@as(f128, 0x1ffffffffffffffff), try fromSlice(
2836 f128,
2837 gpa,
2838 "0x1ffffffffffffffff",
2839 null,
2840 .{},
2841 ));
2842 try std.testing.expectEqual(@as(f32, @floatFromInt(0x1ffffffffffffffff)), try fromSlice(
2843 f32,
2844 gpa,
2845 "0x1ffffffffffffffff",
2846 null,
2847 .{},
2848 ));
3558 try std.testing.expectEqual(@as(f128, 0x1ffffffffffffffff), try fromSliceNoAlloc(f128, .{
3559 .gpa = gpa,
3560 .arena = arena,
3561 .source = "0x1ffffffffffffffff",
3562 .diagnostics = &diagnostics,
3563 }));
3564 try std.testing.expectEqual(@as(f32, @floatFromInt(0x1ffffffffffffffff)), try fromSliceNoAlloc(f32, .{
3565 .gpa = gpa,
3566 .arena = arena,
3567 .source = "0x1ffffffffffffffff",
3568 .diagnostics = &diagnostics,
3569 }));
28493570
28503571 // Exponents, underscores
28513572 try std.testing.expectEqual(
28523573 @as(f32, 123.0E+77),
2853 try fromSlice(f32, gpa, "12_3.0E+77", null, .{}),
3574 try fromSliceNoAlloc(f32, .{
3575 .gpa = gpa,
3576 .arena = arena,
3577 .source = "12_3.0E+77",
3578 .diagnostics = &diagnostics,
3579 }),
28543580 );
28553581
28563582 // Hexadecimal
28573583 try std.testing.expectEqual(
28583584 @as(f32, 0x103.70p-5),
2859 try fromSlice(f32, gpa, "0x103.70p-5", null, .{}),
3585 try fromSliceNoAlloc(f32, .{
3586 .gpa = gpa,
3587 .arena = arena,
3588 .source = "0x103.70p-5",
3589 .diagnostics = &diagnostics,
3590 }),
28603591 );
28613592 try std.testing.expectEqual(
28623593 @as(f32, -0x103.70),
2863 try fromSlice(f32, gpa, "-0x103.70", null, .{}),
3594 try fromSliceNoAlloc(f32, .{
3595 .gpa = gpa,
3596 .arena = arena,
3597 .source = "-0x103.70",
3598 .diagnostics = &diagnostics,
3599 }),
28643600 );
28653601 try std.testing.expectEqual(
28663602 @as(f32, 0x1234_5678.9ABC_CDEFp-10),
2867 try fromSlice(f32, gpa, "0x1234_5678.9ABC_CDEFp-10", null, .{}),
3603 try fromSliceNoAlloc(f32, .{
3604 .gpa = gpa,
3605 .arena = arena,
3606 .source = "0x1234_5678.9ABC_CDEFp-10",
3607 .diagnostics = &diagnostics,
3608 }),
28683609 );
28693610
28703611 // inf, nan
2871 try std.testing.expect(std.math.isPositiveInf(try fromSlice(f32, gpa, "inf", null, .{})));
2872 try std.testing.expect(std.math.isNegativeInf(try fromSlice(f32, gpa, "-inf", null, .{})));
2873 try std.testing.expect(std.math.isNan(try fromSlice(f32, gpa, "nan", null, .{})));
3612 try std.testing.expect(std.math.isPositiveInf(try fromSliceNoAlloc(f32, .{
3613 .gpa = gpa,
3614 .arena = arena,
3615 .source = "inf",
3616 .diagnostics = &diagnostics,
3617 })));
3618 try std.testing.expect(std.math.isNegativeInf(try fromSliceNoAlloc(f32, .{
3619 .gpa = gpa,
3620 .arena = arena,
3621 .source = "-inf",
3622 .diagnostics = &diagnostics,
3623 })));
3624 try std.testing.expect(std.math.isNan(try fromSliceNoAlloc(f32, .{
3625 .gpa = gpa,
3626 .arena = arena,
3627 .source = "nan",
3628 .diagnostics = &diagnostics,
3629 })));
28743630
28753631 // Negative nan not allowed
28763632 {
2877 var diag: Diagnostics = .{};
2878 defer diag.deinit(gpa);
2879 try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-nan", &diag, .{}));
3633 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(f32, .{
3634 .gpa = gpa,
3635 .arena = arena,
3636 .source = "-nan",
3637 .diagnostics = &diagnostics,
3638 }));
28803639 try std.testing.expectFmt(
2881 "1:1: error: expected number or 'inf' after '-'\n",
2882 "{f}",
2883 .{diag},
2884 );
3640 \\input.zon:1:1: error: expected number or 'inf' after '-'
3641 \\
3642 , "{f}", .{diagnostics.fmt("input.zon")});
28853643 }
28863644
28873645 // nan as int not allowed
28883646 {
2889 var diag: Diagnostics = .{};
2890 defer diag.deinit(gpa);
2891 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "nan", &diag, .{}));
2892 try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag});
3647 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i8, .{
3648 .gpa = gpa,
3649 .arena = arena,
3650 .source = "nan",
3651 .diagnostics = &diagnostics,
3652 }));
3653 try std.testing.expectFmt(
3654 \\input.zon:1:1: error: expected type 'i8'
3655 \\
3656 , "{f}", .{diagnostics.fmt("input.zon")});
28933657 }
28943658
28953659 // nan as int not allowed
28963660 {
2897 var diag: Diagnostics = .{};
2898 defer diag.deinit(gpa);
2899 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "nan", &diag, .{}));
2900 try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag});
3661 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i8, .{
3662 .gpa = gpa,
3663 .arena = arena,
3664 .source = "nan",
3665 .diagnostics = &diagnostics,
3666 }));
3667 try std.testing.expectFmt(
3668 \\input.zon:1:1: error: expected type 'i8'
3669 \\
3670 , "{f}", .{diagnostics.fmt("input.zon")});
29013671 }
29023672
29033673 // inf as int not allowed
29043674 {
2905 var diag: Diagnostics = .{};
2906 defer diag.deinit(gpa);
2907 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "inf", &diag, .{}));
2908 try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag});
3675 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i8, .{
3676 .gpa = gpa,
3677 .arena = arena,
3678 .source = "inf",
3679 .diagnostics = &diagnostics,
3680 }));
3681 try std.testing.expectFmt(
3682 \\input.zon:1:1: error: expected type 'i8'
3683 \\
3684 , "{f}", .{diagnostics.fmt("input.zon")});
29093685 }
29103686
29113687 // -inf as int not allowed
29123688 {
2913 var diag: Diagnostics = .{};
2914 defer diag.deinit(gpa);
2915 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "-inf", &diag, .{}));
2916 try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag});
3689 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i8, .{
3690 .gpa = gpa,
3691 .arena = arena,
3692 .source = "-inf",
3693 .diagnostics = &diagnostics,
3694 }));
3695 try std.testing.expectFmt(
3696 \\input.zon:1:1: error: expected type 'i8'
3697 \\
3698 , "{f}", .{diagnostics.fmt("input.zon")});
29173699 }
29183700
29193701 // Bad identifier as float
29203702 {
2921 var diag: Diagnostics = .{};
2922 defer diag.deinit(gpa);
2923 try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "foo", &diag, .{}));
3703 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(f32, .{
3704 .gpa = gpa,
3705 .arena = arena,
3706 .source = "foo",
3707 .diagnostics = &diagnostics,
3708 }));
29243709 try std.testing.expectFmt(
2925 \\1:1: error: invalid expression
2926 \\1:1: note: ZON allows identifiers 'true', 'false', 'null', 'inf', and 'nan'
2927 \\1:1: note: precede identifier with '.' for an enum literal
3710 \\input.zon:1:1: error: invalid expression
3711 \\input.zon:1:1: note: ZON allows identifiers 'true', 'false', 'null', 'inf', and 'nan'
3712 \\input.zon:1:1: note: precede identifier with '.' for an enum literal
29283713 \\
2929 , "{f}", .{diag});
3714 , "{f}", .{diagnostics.fmt("input.zon")});
29303715 }
29313716
29323717 {
2933 var diag: Diagnostics = .{};
2934 defer diag.deinit(gpa);
2935 try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-foo", &diag, .{}));
3718 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(f32, .{
3719 .gpa = gpa,
3720 .arena = arena,
3721 .source = "-foo",
3722 .diagnostics = &diagnostics,
3723 }));
29363724 try std.testing.expectFmt(
2937 "1:1: error: expected number or 'inf' after '-'\n",
2938 "{f}",
2939 .{diag},
2940 );
3725 \\input.zon:1:1: error: expected number or 'inf' after '-'
3726 \\
3727 , "{f}", .{diagnostics.fmt("input.zon")});
29413728 }
29423729
29433730 // Non float as float
29443731 {
2945 var diag: Diagnostics = .{};
2946 defer diag.deinit(gpa);
29473732 try std.testing.expectError(
29483733 error.ParseZon,
2949 fromSlice(f32, gpa, "\"foo\"", &diag, .{}),
3734 fromSliceNoAlloc(f32, .{
3735 .gpa = gpa,
3736 .arena = arena,
3737 .source = "\"foo\"",
3738 .diagnostics = &diagnostics,
3739 }),
29503740 );
2951 try std.testing.expectFmt("1:1: error: expected type 'f32'\n", "{f}", .{diag});
3741 try std.testing.expectFmt(
3742 \\input.zon:1:1: error: expected type 'f32'
3743 \\
3744 , "{f}", .{diagnostics.fmt("input.zon")});
29523745 }
29533746}
29543747
29553748test "std.zon free on error" {
3749 const gpa = std.testing.allocator;
3750 var arena_allocator: ArenaAllocator = .init(gpa);
3751 defer arena_allocator.deinit();
3752 const arena = arena_allocator.allocator();
3753 var diagnostics: Diagnostics = undefined;
3754
29563755 // Test freeing partially allocated structs
29573756 {
29583757 const Struct = struct {
......@@ -2960,13 +3759,18 @@ test "std.zon free on error" {
29603759 y: []const u8,
29613760 z: bool,
29623761 };
2963 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, std.testing.allocator,
3762 try std.testing.expectError(error.ParseZon, fromSlice(Struct, .{
3763 .gpa = gpa,
3764 .arena = arena,
3765 .source =
29643766 \\.{
29653767 \\ .x = "hello",
29663768 \\ .y = "world",
29673769 \\ .z = "fail",
29683770 \\}
2969 , null, .{}));
3771 ,
3772 .diagnostics = &diagnostics,
3773 }));
29703774 }
29713775
29723776 // Test freeing partially allocated tuples
......@@ -2976,358 +3780,418 @@ test "std.zon free on error" {
29763780 []const u8,
29773781 bool,
29783782 };
2979 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, std.testing.allocator,
3783 try std.testing.expectError(error.ParseZon, fromSlice(Struct, .{
3784 .gpa = gpa,
3785 .arena = arena,
3786 .source =
29803787 \\.{
29813788 \\ "hello",
29823789 \\ "world",
29833790 \\ "fail",
29843791 \\}
2985 , null, .{}));
3792 ,
3793 .diagnostics = &diagnostics,
3794 }));
29863795 }
29873796
29883797 // Test freeing structs with missing fields
2989 {
2990 const Struct = struct {
2991 x: []const u8,
2992 y: bool,
2993 };
2994 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, std.testing.allocator,
2995 \\.{
2996 \\ .x = "hello",
2997 \\}
2998 , null, .{}));
2999 }
3798 const Struct = struct {
3799 x: []const u8,
3800 y: bool,
3801 };
3802 try std.testing.expectError(error.ParseZon, fromSlice(Struct, .{
3803 .gpa = gpa,
3804 .arena = arena,
3805 .source =
3806 \\.{
3807 \\ .x = "hello",
3808 \\}
3809 ,
3810 .diagnostics = &diagnostics,
3811 }));
30003812
30013813 // Test freeing partially allocated arrays
3002 {
3003 try std.testing.expectError(error.ParseZon, fromSliceAlloc(
3004 [3][]const u8,
3005 std.testing.allocator,
3006 \\.{
3007 \\ "hello",
3008 \\ false,
3009 \\ false,
3010 \\}
3814 try std.testing.expectError(error.ParseZon, fromSlice([3][]const u8, .{
3815 .gpa = gpa,
3816 .arena = arena,
3817 .source =
3818 \\.{
3819 \\ "hello",
3820 \\ false,
3821 \\ false,
3822 \\}
30113823 ,
3012 null,
3013 .{},
3014 ));
3015 }
3824 .diagnostics = &diagnostics,
3825 }));
30163826
30173827 // Test freeing partially allocated slices
3018 {
3019 try std.testing.expectError(error.ParseZon, fromSliceAlloc(
3020 [][]const u8,
3021 std.testing.allocator,
3022 \\.{
3023 \\ "hello",
3024 \\ "world",
3025 \\ false,
3026 \\}
3828 try std.testing.expectError(error.ParseZon, fromSlice([][]const u8, .{
3829 .gpa = gpa,
3830 .arena = arena,
3831 .source =
3832 \\.{
3833 \\ "hello",
3834 \\ "world",
3835 \\ false,
3836 \\}
30273837 ,
3028 null,
3029 .{},
3030 ));
3031 }
3838 .diagnostics = &diagnostics,
3839 }));
30323840
30333841 // We can parse types that can't be freed, as long as they contain no allocations, e.g. untagged
30343842 // unions.
30353843 try std.testing.expectEqual(
30363844 @as(f32, 1.5),
3037 (try fromSlice(union { x: f32 }, std.testing.allocator, ".{ .x = 1.5 }", null, .{})).x,
3845 (try fromSliceNoAlloc(union { x: f32 }, .{
3846 .gpa = gpa,
3847 .arena = arena,
3848 .source = ".{ .x = 1.5 }",
3849 .diagnostics = &diagnostics,
3850 })).x,
30383851 );
30393852
30403853 // We can also parse types that can't be freed if it's impossible for an error to occur after
30413854 // the allocation, as is the case here.
30423855 {
3043 const result = try fromSliceAlloc(
3044 union { x: []const u8 },
3045 std.testing.allocator,
3046 ".{ .x = \"foo\" }",
3047 null,
3048 .{},
3049 );
3050 defer free(std.testing.allocator, result.x);
3856 const result = try fromSlice(union { x: []const u8 }, .{
3857 .gpa = gpa,
3858 .arena = arena,
3859 .source = ".{ .x = \"foo\" }",
3860 .diagnostics = &diagnostics,
3861 });
30513862 try std.testing.expectEqualStrings("foo", result.x);
30523863 }
3053
3054 // However, if it's possible we could get an error requiring we free the value, but the value
3055 // cannot be freed (e.g. untagged unions) then we need to turn off `free_on_error` for it to
3056 // compile.
3057 {
3058 const S = struct {
3059 union { x: []const u8 },
3060 bool,
3061 };
3062 const result = try fromSliceAlloc(
3063 S,
3064 std.testing.allocator,
3065 ".{ .{ .x = \"foo\" }, true }",
3066 null,
3067 .{ .free_on_error = false },
3068 );
3069 defer free(std.testing.allocator, result[0].x);
3070 try std.testing.expectEqualStrings("foo", result[0].x);
3071 try std.testing.expect(result[1]);
3072 }
3073
3074 // Again but for structs.
3075 {
3076 const S = struct {
3077 a: union { x: []const u8 },
3078 b: bool,
3079 };
3080 const result = try fromSliceAlloc(
3081 S,
3082 std.testing.allocator,
3083 ".{ .a = .{ .x = \"foo\" }, .b = true }",
3084 null,
3085 .{
3086 .free_on_error = false,
3087 },
3088 );
3089 defer free(std.testing.allocator, result.a.x);
3090 try std.testing.expectEqualStrings("foo", result.a.x);
3091 try std.testing.expect(result.b);
3092 }
3093
3094 // Again but for arrays.
3095 {
3096 const S = [2]union { x: []const u8 };
3097 const result = try fromSliceAlloc(
3098 S,
3099 std.testing.allocator,
3100 ".{ .{ .x = \"foo\" }, .{ .x = \"bar\" } }",
3101 null,
3102 .{
3103 .free_on_error = false,
3104 },
3105 );
3106 defer free(std.testing.allocator, result[0].x);
3107 defer free(std.testing.allocator, result[1].x);
3108 try std.testing.expectEqualStrings("foo", result[0].x);
3109 try std.testing.expectEqualStrings("bar", result[1].x);
3110 }
3111
3112 // Again but for slices.
3113 {
3114 const S = []union { x: []const u8 };
3115 const result = try fromSliceAlloc(
3116 S,
3117 std.testing.allocator,
3118 ".{ .{ .x = \"foo\" }, .{ .x = \"bar\" } }",
3119 null,
3120 .{
3121 .free_on_error = false,
3122 },
3123 );
3124 defer std.testing.allocator.free(result);
3125 defer free(std.testing.allocator, result[0].x);
3126 defer free(std.testing.allocator, result[1].x);
3127 try std.testing.expectEqualStrings("foo", result[0].x);
3128 try std.testing.expectEqualStrings("bar", result[1].x);
3129 }
31303864}
31313865
31323866test "std.zon vector" {
3133 const builtin = @import("builtin");
3867 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/15330
31343868 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .s390x) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/25957
31353869
31363870 const gpa = std.testing.allocator;
3871 var arena_allocator: ArenaAllocator = .init(gpa);
3872 defer arena_allocator.deinit();
3873 const arena = arena_allocator.allocator();
3874 var diagnostics: Diagnostics = undefined;
31373875
31383876 // Passing cases
31393877 try std.testing.expectEqual(
31403878 @Vector(0, bool){},
3141 try fromSlice(@Vector(0, bool), gpa, ".{}", null, .{}),
3879 try fromSliceNoAlloc(@Vector(0, bool), .{
3880 .gpa = gpa,
3881 .arena = arena,
3882 .source = ".{}",
3883 .diagnostics = &diagnostics,
3884 }),
31423885 );
31433886 try std.testing.expectEqual(
31443887 @Vector(3, bool){ true, false, true },
3145 try fromSlice(@Vector(3, bool), gpa, ".{true, false, true}", null, .{}),
3888 try fromSliceNoAlloc(@Vector(3, bool), .{
3889 .gpa = gpa,
3890 .arena = arena,
3891 .source = ".{true, false, true}",
3892 .diagnostics = &diagnostics,
3893 }),
31463894 );
31473895
31483896 try std.testing.expectEqual(
31493897 @Vector(0, f32){},
3150 try fromSlice(@Vector(0, f32), gpa, ".{}", null, .{}),
3898 try fromSliceNoAlloc(@Vector(0, f32), .{
3899 .gpa = gpa,
3900 .arena = arena,
3901 .source = ".{}",
3902 .diagnostics = &diagnostics,
3903 }),
31513904 );
31523905 try std.testing.expectEqual(
31533906 @Vector(3, f32){ 1.5, 2.5, 3.5 },
3154 try fromSlice(@Vector(3, f32), gpa, ".{1.5, 2.5, 3.5}", null, .{}),
3907 try fromSliceNoAlloc(@Vector(3, f32), .{
3908 .gpa = gpa,
3909 .arena = arena,
3910 .source = ".{1.5, 2.5, 3.5}",
3911 .diagnostics = &diagnostics,
3912 }),
31553913 );
31563914
31573915 try std.testing.expectEqual(
31583916 @Vector(0, u8){},
3159 try fromSlice(@Vector(0, u8), gpa, ".{}", null, .{}),
3917 try fromSliceNoAlloc(@Vector(0, u8), .{
3918 .gpa = gpa,
3919 .arena = arena,
3920 .source = ".{}",
3921 .diagnostics = &diagnostics,
3922 }),
31603923 );
31613924 try std.testing.expectEqual(
31623925 @Vector(3, u8){ 2, 4, 6 },
3163 try fromSlice(@Vector(3, u8), gpa, ".{2, 4, 6}", null, .{}),
3926 try fromSliceNoAlloc(@Vector(3, u8), .{
3927 .gpa = gpa,
3928 .arena = arena,
3929 .source = ".{2, 4, 6}",
3930 .diagnostics = &diagnostics,
3931 }),
31643932 );
31653933
31663934 {
31673935 try std.testing.expectEqual(
31683936 @Vector(0, *const u8){},
3169 try fromSliceAlloc(@Vector(0, *const u8), gpa, ".{}", null, .{}),
3937 try fromSlice(@Vector(0, *const u8), .{
3938 .gpa = gpa,
3939 .arena = arena,
3940 .source = ".{}",
3941 .diagnostics = &diagnostics,
3942 }),
31703943 );
3171 const pointers = try fromSliceAlloc(@Vector(3, *const u8), gpa, ".{2, 4, 6}", null, .{});
3172 defer free(gpa, pointers);
3944 const pointers = try fromSlice(@Vector(3, *const u8), .{
3945 .gpa = gpa,
3946 .arena = arena,
3947 .source = ".{2, 4, 6}",
3948 .diagnostics = &diagnostics,
3949 });
31733950 try std.testing.expectEqualDeep(@Vector(3, *const u8){ &2, &4, &6 }, pointers);
31743951 }
31753952
31763953 {
31773954 try std.testing.expectEqual(
31783955 @Vector(0, ?*const u8){},
3179 try fromSliceAlloc(@Vector(0, ?*const u8), gpa, ".{}", null, .{}),
3956 try fromSlice(@Vector(0, ?*const u8), .{
3957 .gpa = gpa,
3958 .arena = arena,
3959 .source = ".{}",
3960 .diagnostics = &diagnostics,
3961 }),
31803962 );
3181 const pointers = try fromSliceAlloc(@Vector(3, ?*const u8), gpa, ".{2, null, 6}", null, .{});
3182 defer free(gpa, pointers);
3963 const pointers = try fromSlice(@Vector(3, ?*const u8), .{
3964 .gpa = gpa,
3965 .arena = arena,
3966 .source = ".{2, null, 6}",
3967 .diagnostics = &diagnostics,
3968 });
31833969 try std.testing.expectEqualDeep(@Vector(3, ?*const u8){ &2, null, &6 }, pointers);
31843970 }
31853971
31863972 // Too few fields
31873973 {
3188 var diag: Diagnostics = .{};
3189 defer diag.deinit(gpa);
31903974 try std.testing.expectError(
31913975 error.ParseZon,
3192 fromSlice(@Vector(2, f32), gpa, ".{0.5}", &diag, .{}),
3976 fromSliceNoAlloc(@Vector(2, f32), .{
3977 .gpa = gpa,
3978 .arena = arena,
3979 .source = ".{0.5}",
3980 .diagnostics = &diagnostics,
3981 }),
31933982 );
31943983 try std.testing.expectFmt(
3195 "1:2: error: expected 2 array elements; found 1\n",
3196 "{f}",
3197 .{diag},
3198 );
3984 \\input.zon:1:2: error: expected 2 array elements; found 1
3985 \\
3986 , "{f}", .{diagnostics.fmt("input.zon")});
31993987 }
32003988
32013989 // Too many fields
32023990 {
3203 var diag: Diagnostics = .{};
3204 defer diag.deinit(gpa);
32053991 try std.testing.expectError(
32063992 error.ParseZon,
3207 fromSlice(@Vector(2, f32), gpa, ".{0.5, 1.5, 2.5}", &diag, .{}),
3993 fromSliceNoAlloc(@Vector(2, f32), .{
3994 .gpa = gpa,
3995 .arena = arena,
3996 .source = ".{0.5, 1.5, 2.5}",
3997 .diagnostics = &diagnostics,
3998 }),
32083999 );
32094000 try std.testing.expectFmt(
3210 "1:13: error: index 2 outside of array of length 2\n",
3211 "{f}",
3212 .{diag},
3213 );
4001 \\input.zon:1:13: error: index 2 outside of array of length 2
4002 \\
4003 , "{f}", .{diagnostics.fmt("input.zon")});
32144004 }
32154005
32164006 // Wrong type fields
32174007 {
3218 var diag: Diagnostics = .{};
3219 defer diag.deinit(gpa);
32204008 try std.testing.expectError(
32214009 error.ParseZon,
3222 fromSlice(@Vector(3, f32), gpa, ".{0.5, true, 2.5}", &diag, .{}),
4010 fromSliceNoAlloc(@Vector(3, f32), .{
4011 .gpa = gpa,
4012 .arena = arena,
4013 .source = ".{0.5, true, 2.5}",
4014 .diagnostics = &diagnostics,
4015 }),
32234016 );
32244017 try std.testing.expectFmt(
3225 "1:8: error: expected type 'f32'\n",
3226 "{f}",
3227 .{diag},
3228 );
4018 \\input.zon:1:8: error: expected type 'f32'
4019 \\
4020 , "{f}", .{diagnostics.fmt("input.zon")});
32294021 }
32304022
32314023 // Wrong type
32324024 {
3233 var diag: Diagnostics = .{};
3234 defer diag.deinit(gpa);
32354025 try std.testing.expectError(
32364026 error.ParseZon,
3237 fromSlice(@Vector(3, u8), gpa, "true", &diag, .{}),
4027 fromSliceNoAlloc(@Vector(3, u8), .{
4028 .gpa = gpa,
4029 .arena = arena,
4030 .source = "true",
4031 .diagnostics = &diagnostics,
4032 }),
32384033 );
3239 try std.testing.expectFmt("1:1: error: expected type '@Vector(3, u8)'\n", "{f}", .{diag});
4034 try std.testing.expectFmt(
4035 \\input.zon:1:1: error: expected type '@Vector(3, u8)'
4036 \\
4037 , "{f}", .{diagnostics.fmt("input.zon")});
32404038 }
32414039
32424040 // Elements should get freed on error
32434041 {
3244 var diag: Diagnostics = .{};
3245 defer diag.deinit(gpa);
32464042 try std.testing.expectError(
32474043 error.ParseZon,
3248 fromSliceAlloc(@Vector(3, *u8), gpa, ".{1, true, 3}", &diag, .{}),
4044 fromSlice(@Vector(3, *u8), .{
4045 .gpa = gpa,
4046 .arena = arena,
4047 .source = ".{1, true, 3}",
4048 .diagnostics = &diagnostics,
4049 }),
32494050 );
3250 try std.testing.expectFmt("1:6: error: expected type 'u8'\n", "{f}", .{diag});
4051 try std.testing.expectFmt(
4052 \\input.zon:1:6: error: expected type 'u8'
4053 \\
4054 , "{f}", .{diagnostics.fmt("input.zon")});
32514055 }
32524056}
32534057
32544058test "std.zon add pointers" {
32554059 const gpa = std.testing.allocator;
4060 var arena_allocator: ArenaAllocator = .init(gpa);
4061 defer arena_allocator.deinit();
4062 const arena = arena_allocator.allocator();
4063 var diagnostics: Diagnostics = undefined;
32564064
32574065 // Primitive with varying levels of pointers
32584066 {
3259 const result = try fromSliceAlloc(*u32, gpa, "10", null, .{});
3260 defer free(gpa, result);
4067 const result = try fromSlice(*u32, .{
4068 .gpa = gpa,
4069 .arena = arena,
4070 .source = "10",
4071 .diagnostics = &diagnostics,
4072 });
32614073 try std.testing.expectEqual(@as(u32, 10), result.*);
32624074 }
32634075
32644076 {
3265 const result = try fromSliceAlloc(**u32, gpa, "10", null, .{});
3266 defer free(gpa, result);
4077 const result = try fromSlice(**u32, .{
4078 .gpa = gpa,
4079 .arena = arena,
4080 .source = "10",
4081 .diagnostics = &diagnostics,
4082 });
32674083 try std.testing.expectEqual(@as(u32, 10), result.*.*);
32684084 }
32694085
32704086 {
3271 const result = try fromSliceAlloc(***u32, gpa, "10", null, .{});
3272 defer free(gpa, result);
4087 const result = try fromSlice(***u32, .{
4088 .gpa = gpa,
4089 .arena = arena,
4090 .source = "10",
4091 .diagnostics = &diagnostics,
4092 });
32734093 try std.testing.expectEqual(@as(u32, 10), result.*.*.*);
32744094 }
32754095
32764096 // Primitive optional with varying levels of pointers
32774097 {
3278 const some = try fromSliceAlloc(?*u32, gpa, "10", null, .{});
3279 defer free(gpa, some);
4098 const some = try fromSlice(?*u32, .{
4099 .gpa = gpa,
4100 .arena = arena,
4101 .source = "10",
4102 .diagnostics = &diagnostics,
4103 });
32804104 try std.testing.expectEqual(@as(u32, 10), some.?.*);
32814105
3282 const none = try fromSliceAlloc(?*u32, gpa, "null", null, .{});
3283 defer free(gpa, none);
4106 const none = try fromSlice(?*u32, .{
4107 .gpa = gpa,
4108 .arena = arena,
4109 .source = "null",
4110 .diagnostics = &diagnostics,
4111 });
32844112 try std.testing.expectEqual(null, none);
32854113 }
32864114
32874115 {
3288 const some = try fromSliceAlloc(*?u32, gpa, "10", null, .{});
3289 defer free(gpa, some);
4116 const some = try fromSlice(*?u32, .{
4117 .gpa = gpa,
4118 .arena = arena,
4119 .source = "10",
4120 .diagnostics = &diagnostics,
4121 });
32904122 try std.testing.expectEqual(@as(u32, 10), some.*.?);
32914123
3292 const none = try fromSliceAlloc(*?u32, gpa, "null", null, .{});
3293 defer free(gpa, none);
4124 const none = try fromSlice(*?u32, .{
4125 .gpa = gpa,
4126 .arena = arena,
4127 .source = "null",
4128 .diagnostics = &diagnostics,
4129 });
32944130 try std.testing.expectEqual(null, none.*);
32954131 }
32964132
32974133 {
3298 const some = try fromSliceAlloc(?**u32, gpa, "10", null, .{});
3299 defer free(gpa, some);
4134 const some = try fromSlice(?**u32, .{
4135 .gpa = gpa,
4136 .arena = arena,
4137 .source = "10",
4138 .diagnostics = &diagnostics,
4139 });
33004140 try std.testing.expectEqual(@as(u32, 10), some.?.*.*);
33014141
3302 const none = try fromSliceAlloc(?**u32, gpa, "null", null, .{});
3303 defer free(gpa, none);
4142 const none = try fromSlice(?**u32, .{
4143 .gpa = gpa,
4144 .arena = arena,
4145 .source = "null",
4146 .diagnostics = &diagnostics,
4147 });
33044148 try std.testing.expectEqual(null, none);
33054149 }
33064150
33074151 {
3308 const some = try fromSliceAlloc(*?*u32, gpa, "10", null, .{});
3309 defer free(gpa, some);
4152 const some = try fromSlice(*?*u32, .{
4153 .gpa = gpa,
4154 .arena = arena,
4155 .source = "10",
4156 .diagnostics = &diagnostics,
4157 });
33104158 try std.testing.expectEqual(@as(u32, 10), some.*.?.*);
33114159
3312 const none = try fromSliceAlloc(*?*u32, gpa, "null", null, .{});
3313 defer free(gpa, none);
4160 const none = try fromSlice(*?*u32, .{
4161 .gpa = gpa,
4162 .arena = arena,
4163 .source = "null",
4164 .diagnostics = &diagnostics,
4165 });
33144166 try std.testing.expectEqual(null, none.*);
33154167 }
33164168
33174169 {
3318 const some = try fromSliceAlloc(**?u32, gpa, "10", null, .{});
3319 defer free(gpa, some);
4170 const some = try fromSlice(**?u32, .{
4171 .gpa = gpa,
4172 .arena = arena,
4173 .source = "10",
4174 .diagnostics = &diagnostics,
4175 });
33204176 try std.testing.expectEqual(@as(u32, 10), some.*.*.?);
33214177
3322 const none = try fromSliceAlloc(**?u32, gpa, "null", null, .{});
3323 defer free(gpa, none);
4178 const none = try fromSlice(**?u32, .{
4179 .gpa = gpa,
4180 .arena = arena,
4181 .source = "null",
4182 .diagnostics = &diagnostics,
4183 });
33244184 try std.testing.expectEqual(null, none.*.*);
33254185 }
33264186
33274187 // Pointer to an array
33284188 {
3329 const result = try fromSliceAlloc(*[3]u8, gpa, ".{ 1, 2, 3 }", null, .{});
3330 defer free(gpa, result);
4189 const result = try fromSlice(*[3]u8, .{
4190 .gpa = gpa,
4191 .arena = arena,
4192 .source = ".{ 1, 2, 3 }",
4193 .diagnostics = &diagnostics,
4194 });
33314195 try std.testing.expectEqual([3]u8{ 1, 2, 3 }, result.*);
33324196 }
33334197
......@@ -3349,7 +4213,10 @@ test "std.zon add pointers" {
33494213 .f2 = &null,
33504214 };
33514215
3352 const found = try fromSliceAlloc(?*Outer, gpa,
4216 const found = try fromSlice(?*Outer, .{
4217 .gpa = gpa,
4218 .arena = arena,
4219 .source =
33534220 \\.{
33544221 \\ .f1 = .{
33554222 \\ .f1 = null,
......@@ -3357,146 +4224,229 @@ test "std.zon add pointers" {
33574224 \\ },
33584225 \\ .f2 = null,
33594226 \\}
3360 , null, .{});
3361 defer free(gpa, found);
4227 ,
4228 .diagnostics = &diagnostics,
4229 });
33624230
33634231 try std.testing.expectEqualDeep(expected, found.?.*);
33644232 }
33654233
33664234 // Test that optional types are flattened correctly in errors
33674235 {
3368 var diag: Diagnostics = .{};
3369 defer diag.deinit(gpa);
33704236 try std.testing.expectError(
33714237 error.ParseZon,
3372 fromSliceAlloc(*const ?*const u8, gpa, "true", &diag, .{}),
4238 fromSlice(*const ?*const u8, .{
4239 .gpa = gpa,
4240 .arena = arena,
4241 .source = "true",
4242 .diagnostics = &diagnostics,
4243 }),
33734244 );
3374 try std.testing.expectFmt("1:1: error: expected type '?u8'\n", "{f}", .{diag});
4245 try std.testing.expectFmt(
4246 \\input.zon:1:1: error: expected type '?u8'
4247 \\
4248 , "{f}", .{diagnostics.fmt("input.zon")});
33754249 }
33764250
33774251 {
3378 var diag: Diagnostics = .{};
3379 defer diag.deinit(gpa);
33804252 try std.testing.expectError(
33814253 error.ParseZon,
3382 fromSliceAlloc(*const ?*const f32, gpa, "true", &diag, .{}),
4254 fromSlice(*const ?*const f32, .{
4255 .gpa = gpa,
4256 .arena = arena,
4257 .source = "true",
4258 .diagnostics = &diagnostics,
4259 }),
33834260 );
3384 try std.testing.expectFmt("1:1: error: expected type '?f32'\n", "{f}", .{diag});
4261 try std.testing.expectFmt(
4262 \\input.zon:1:1: error: expected type '?f32'
4263 \\
4264 , "{f}", .{diagnostics.fmt("input.zon")});
33854265 }
33864266
33874267 {
3388 var diag: Diagnostics = .{};
3389 defer diag.deinit(gpa);
33904268 try std.testing.expectError(
33914269 error.ParseZon,
3392 fromSliceAlloc(*const ?*const @Vector(3, u8), gpa, "true", &diag, .{}),
4270 fromSlice(*const ?*const @Vector(3, u8), .{
4271 .gpa = gpa,
4272 .arena = arena,
4273 .source = "true",
4274 .diagnostics = &diagnostics,
4275 }),
33934276 );
3394 try std.testing.expectFmt("1:1: error: expected type '?@Vector(3, u8)'\n", "{f}", .{diag});
4277 try std.testing.expectFmt(
4278 \\input.zon:1:1: error: expected type '?@Vector(3, u8)'
4279 \\
4280 , "{f}", .{diagnostics.fmt("input.zon")});
33954281 }
33964282
33974283 {
3398 var diag: Diagnostics = .{};
3399 defer diag.deinit(gpa);
34004284 try std.testing.expectError(
34014285 error.ParseZon,
3402 fromSliceAlloc(*const ?*const bool, gpa, "10", &diag, .{}),
4286 fromSlice(*const ?*const bool, .{
4287 .gpa = gpa,
4288 .arena = arena,
4289 .source = "10",
4290 .diagnostics = &diagnostics,
4291 }),
34034292 );
3404 try std.testing.expectFmt("1:1: error: expected type '?bool'\n", "{f}", .{diag});
4293 try std.testing.expectFmt(
4294 \\input.zon:1:1: error: expected type '?bool'
4295 \\
4296 , "{f}", .{diagnostics.fmt("input.zon")});
34054297 }
34064298
34074299 {
3408 var diag: Diagnostics = .{};
3409 defer diag.deinit(gpa);
34104300 try std.testing.expectError(
34114301 error.ParseZon,
3412 fromSliceAlloc(*const ?*const struct { a: i32 }, gpa, "true", &diag, .{}),
4302 fromSlice(*const ?*const struct { a: i32 }, .{
4303 .gpa = gpa,
4304 .arena = arena,
4305 .source = "true",
4306 .diagnostics = &diagnostics,
4307 }),
34134308 );
3414 try std.testing.expectFmt("1:1: error: expected optional struct\n", "{f}", .{diag});
4309 try std.testing.expectFmt(
4310 \\input.zon:1:1: error: expected optional struct
4311 \\
4312 , "{f}", .{diagnostics.fmt("input.zon")});
34154313 }
34164314
34174315 {
3418 var diag: Diagnostics = .{};
3419 defer diag.deinit(gpa);
34204316 try std.testing.expectError(
34214317 error.ParseZon,
3422 fromSliceAlloc(*const ?*const struct { i32 }, gpa, "true", &diag, .{}),
4318 fromSlice(*const ?*const struct { i32 }, .{
4319 .gpa = gpa,
4320 .arena = arena,
4321 .source = "true",
4322 .diagnostics = &diagnostics,
4323 }),
34234324 );
3424 try std.testing.expectFmt("1:1: error: expected optional tuple\n", "{f}", .{diag});
4325 try std.testing.expectFmt(
4326 \\input.zon:1:1: error: expected optional tuple
4327 \\
4328 , "{f}", .{diagnostics.fmt("input.zon")});
34254329 }
34264330
34274331 {
3428 var diag: Diagnostics = .{};
3429 defer diag.deinit(gpa);
34304332 try std.testing.expectError(
34314333 error.ParseZon,
3432 fromSliceAlloc(*const ?*const union { x: void }, gpa, "true", &diag, .{}),
4334 fromSlice(*const ?*const union { x: void }, .{
4335 .gpa = gpa,
4336 .arena = arena,
4337 .source = "true",
4338 .diagnostics = &diagnostics,
4339 }),
34334340 );
3434 try std.testing.expectFmt("1:1: error: expected optional union\n", "{f}", .{diag});
4341 try std.testing.expectFmt(
4342 \\input.zon:1:1: error: expected optional union
4343 \\
4344 , "{f}", .{diagnostics.fmt("input.zon")});
34354345 }
34364346
34374347 {
3438 var diag: Diagnostics = .{};
3439 defer diag.deinit(gpa);
34404348 try std.testing.expectError(
34414349 error.ParseZon,
3442 fromSliceAlloc(*const ?*const [3]u8, gpa, "true", &diag, .{}),
4350 fromSlice(*const ?*const [3]u8, .{
4351 .gpa = gpa,
4352 .arena = arena,
4353 .source = "true",
4354 .diagnostics = &diagnostics,
4355 }),
34434356 );
3444 try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag});
4357 try std.testing.expectFmt(
4358 \\input.zon:1:1: error: expected optional array
4359 \\
4360 , "{f}", .{diagnostics.fmt("input.zon")});
34454361 }
34464362
34474363 {
3448 var diag: Diagnostics = .{};
3449 defer diag.deinit(gpa);
34504364 try std.testing.expectError(
34514365 error.ParseZon,
3452 fromSliceAlloc(?[3]u8, gpa, "true", &diag, .{}),
4366 fromSlice(?[3]u8, .{
4367 .gpa = gpa,
4368 .arena = arena,
4369 .source = "true",
4370 .diagnostics = &diagnostics,
4371 }),
34534372 );
3454 try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag});
4373 try std.testing.expectFmt(
4374 \\input.zon:1:1: error: expected optional array
4375 \\
4376 , "{f}", .{diagnostics.fmt("input.zon")});
34554377 }
34564378
34574379 {
3458 var diag: Diagnostics = .{};
3459 defer diag.deinit(gpa);
34604380 try std.testing.expectError(
34614381 error.ParseZon,
3462 fromSliceAlloc(*const ?*const []u8, gpa, "true", &diag, .{}),
4382 fromSlice(*const ?*const []u8, .{
4383 .gpa = gpa,
4384 .arena = arena,
4385 .source = "true",
4386 .diagnostics = &diagnostics,
4387 }),
34634388 );
3464 try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag});
4389 try std.testing.expectFmt(
4390 \\input.zon:1:1: error: expected optional array
4391 \\
4392 , "{f}", .{diagnostics.fmt("input.zon")});
34654393 }
34664394
34674395 {
3468 var diag: Diagnostics = .{};
3469 defer diag.deinit(gpa);
34704396 try std.testing.expectError(
34714397 error.ParseZon,
3472 fromSliceAlloc(?[]u8, gpa, "true", &diag, .{}),
4398 fromSlice(?[]u8, .{
4399 .gpa = gpa,
4400 .arena = arena,
4401 .source = "true",
4402 .diagnostics = &diagnostics,
4403 }),
34734404 );
3474 try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag});
4405 try std.testing.expectFmt(
4406 \\input.zon:1:1: error: expected optional array
4407 \\
4408 , "{f}", .{diagnostics.fmt("input.zon")});
34754409 }
34764410
34774411 {
3478 var diag: Diagnostics = .{};
3479 defer diag.deinit(gpa);
34804412 try std.testing.expectError(
34814413 error.ParseZon,
3482 fromSliceAlloc(*const ?*const []const u8, gpa, "true", &diag, .{}),
4414 fromSlice(*const ?*const []const u8, .{
4415 .gpa = gpa,
4416 .arena = arena,
4417 .source = "true",
4418 .diagnostics = &diagnostics,
4419 }),
34834420 );
3484 try std.testing.expectFmt("1:1: error: expected optional string\n", "{f}", .{diag});
4421 try std.testing.expectFmt(
4422 \\input.zon:1:1: error: expected optional string
4423 \\
4424 , "{f}", .{diagnostics.fmt("input.zon")});
34854425 }
34864426
34874427 {
3488 var diag: Diagnostics = .{};
3489 defer diag.deinit(gpa);
34904428 try std.testing.expectError(
34914429 error.ParseZon,
3492 fromSliceAlloc(*const ?*const enum { foo }, gpa, "true", &diag, .{}),
4430 fromSlice(*const ?*const enum { foo }, .{
4431 .gpa = gpa,
4432 .arena = arena,
4433 .source = "true",
4434 .diagnostics = &diagnostics,
4435 }),
34934436 );
3494 try std.testing.expectFmt("1:1: error: expected optional enum literal\n", "{f}", .{diag});
4437 try std.testing.expectFmt(
4438 \\input.zon:1:1: error: expected optional enum literal
4439 \\
4440 , "{f}", .{diagnostics.fmt("input.zon")});
34954441 }
34964442}
34974443
34984444test "std.zon stop on node" {
34994445 const gpa = std.testing.allocator;
4446 var arena_allocator: ArenaAllocator = .init(gpa);
4447 defer arena_allocator.deinit();
4448 const arena = arena_allocator.allocator();
4449 var diagnostics: Diagnostics = undefined;
35004450
35014451 {
35024452 const Vec2 = struct {
......@@ -3504,27 +4454,55 @@ test "std.zon stop on node" {
35044454 y: f32,
35054455 };
35064456
3507 var diag: Diagnostics = .{};
3508 defer diag.deinit(gpa);
3509 const result = try fromSlice(Vec2, gpa, ".{ .x = 1.5, .y = 2.5 }", &diag, .{});
4457 var ast = try std.zig.Ast.parse(gpa, ".{ .x = 1.5, .y = 2.5 }", .{ .mode = .zon });
4458 defer ast.deinit(gpa);
4459
4460 var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false });
4461 defer zoir.deinit(gpa);
4462
4463 const result = try fromZoirNoAlloc(Vec2, .{
4464 .arena = arena,
4465 .ast = &ast,
4466 .zoir = &zoir,
4467 .diagnostics = &diagnostics,
4468 });
4469
35104470 try std.testing.expectEqual(result.y, 2.5);
3511 try std.testing.expectEqual(Zoir.Node{ .float_literal = 1.5 }, result.x.get(diag.zoir));
4471 try std.testing.expectEqual(Zoir.Node{ .float_literal = 1.5 }, result.x.get(&zoir));
35124472 }
35134473
35144474 {
3515 var diag: Diagnostics = .{};
3516 defer diag.deinit(gpa);
3517 const result = try fromSlice(Zoir.Node.Index, gpa, "1.23", &diag, .{});
3518 try std.testing.expectEqual(Zoir.Node{ .float_literal = 1.23 }, result.get(diag.zoir));
4475 var ast = try std.zig.Ast.parse(gpa, "1.23", .{ .mode = .zon });
4476 defer ast.deinit(gpa);
4477
4478 var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false });
4479 defer zoir.deinit(gpa);
4480
4481 const result = try fromZoirNoAlloc(Zoir.Node.Index, .{
4482 .arena = arena,
4483 .ast = &ast,
4484 .zoir = &zoir,
4485 .diagnostics = &diagnostics,
4486 });
4487 try std.testing.expectEqual(Zoir.Node{ .float_literal = 1.23 }, result.get(&zoir));
35194488 }
35204489}
35214490
35224491test "std.zon no alloc" {
35234492 const gpa = std.testing.allocator;
4493 var arena_allocator: ArenaAllocator = .init(gpa);
4494 defer arena_allocator.deinit();
4495 const arena = arena_allocator.allocator();
4496 var diagnostics: Diagnostics = undefined;
35244497
35254498 try std.testing.expectEqual(
35264499 [3]u8{ 1, 2, 3 },
3527 try fromSlice([3]u8, gpa, ".{ 1, 2, 3 }", null, .{}),
4500 try fromSliceNoAlloc([3]u8, .{
4501 .gpa = gpa,
4502 .arena = arena,
4503 .source = ".{ 1, 2, 3 }",
4504 .diagnostics = &diagnostics,
4505 }),
35284506 );
35294507
35304508 const Nested = struct { u8, u8, struct { u8, u8 } };
......@@ -3537,34 +4515,442 @@ test "std.zon no alloc" {
35374515
35384516 try std.testing.expectEqual(
35394517 Nested{ 1, 2, .{ 3, 4 } },
3540 try fromZoir(Nested, ast, zoir, null, .{}),
4518 try fromZoirNoAlloc(Nested, .{
4519 .arena = arena,
4520 .ast = &ast,
4521 .zoir = &zoir,
4522 .diagnostics = &diagnostics,
4523 }),
35414524 );
4525}
35424526
3543 try std.testing.expectEqual(
3544 Nested{ 1, 2, .{ 3, 4 } },
3545 try fromZoirNode(Nested, ast, zoir, .root, null, .{}),
3546 );
4527test "std.zon aligned pointers" {
4528 const gpa = std.testing.allocator;
4529 var arena_allocator: ArenaAllocator = .init(gpa);
4530 defer arena_allocator.deinit();
4531 const arena = arena_allocator.allocator();
4532 var diagnostics: Diagnostics = undefined;
4533
4534 const n: u8 align(8) = 10;
4535 const Foo = struct {
4536 inner: *align(8) const u8,
4537 };
4538
4539 const expected: Foo = .{
4540 .inner = &n,
4541 };
4542 const found = try fromSlice(Foo, .{
4543 .gpa = gpa,
4544 .arena = arena,
4545 .source = ".{ .inner = 10 }",
4546 .diagnostics = &diagnostics,
4547 });
4548 try std.testing.expectEqualDeep(expected.inner, found.inner);
35474549}
35484550
3549test "std.zon errors without diagnostics" {
4551test "std.zon update basic" {
35504552 const gpa = std.testing.allocator;
4553 var arena_allocator: ArenaAllocator = .init(gpa);
4554 defer arena_allocator.deinit();
4555 const arena = arena_allocator.allocator();
4556 var diagnostics: Diagnostics = undefined;
4557
4558 const Vector = struct { x: f32, y: f32, z: f32 };
4559 const MyStruct = struct {
4560 foo: u32 = 123,
4561 bar: bool,
4562 baz: struct {
4563 a: [2]u32,
4564 b: enum { c, d } = .d,
4565 },
4566 ptr: *Vector,
4567 optional: ?u32 = null,
4568 str: []const u8,
4569 };
35514570
3552 const Enum = enum {
3553 foo,
3554 bar,
3555 baz,
4571 var v1: Vector = .{ .x = 1, .y = 2, .z = 3 };
4572 var expected: MyStruct = .{
4573 .foo = 10,
4574 .bar = true,
4575 .baz = .{ .a = .{ 1, 2 }, .b = .c },
4576 .ptr = &v1,
4577 .str = "hello, world",
4578 };
4579 var v2: Vector = .{ .x = 1, .y = 2, .z = 3 };
4580 var found: MyStruct = .{
4581 .foo = 10,
4582 .bar = true,
4583 .baz = .{ .a = .{ 1, 2 }, .b = .c },
4584 .ptr = &v2,
4585 .str = "hello, world",
35564586 };
3557 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Enum, gpa, ".nothing", null, .{}));
35584587
3559 const Struct = struct {
3560 name: []const u8,
4588 try updateFromSlice(MyStruct, &found, .{
4589 .gpa = gpa,
4590 .arena = arena,
4591 .source = ".{}",
4592 .diagnostics = &diagnostics,
4593 });
4594 try std.testing.expectEqualDeep(expected, found);
4595
4596 try updateFromSlice(MyStruct, &found, .{
4597 .gpa = gpa,
4598 .arena = arena,
4599 .source = ".{ .bar = false }",
4600 .diagnostics = &diagnostics,
4601 });
4602 expected.bar = false;
4603 try std.testing.expectEqualDeep(expected, found);
4604
4605 try updateFromSlice(MyStruct, &found, .{
4606 .gpa = gpa,
4607 .arena = arena,
4608 .source = ".{ .baz = .{ .a = .{ 2, 4 } } }",
4609 .diagnostics = &diagnostics,
4610 });
4611 expected.baz.a[0] = 2;
4612 expected.baz.a[1] = 4;
4613 try std.testing.expectEqualDeep(expected, found);
4614
4615 try updateFromSlice(MyStruct, &found, .{
4616 .gpa = gpa,
4617 .arena = arena,
4618 .source = ".{ .foo = 11, .baz = .{ .b = .d } }",
4619 .diagnostics = &diagnostics,
4620 });
4621 expected.foo = 11;
4622 expected.baz.b = .d;
4623 try std.testing.expectEqualDeep(expected, found);
4624
4625 try updateFromSlice(MyStruct, &found, .{
4626 .gpa = gpa,
4627 .arena = arena,
4628 .source = ".{ .optional = 10 }",
4629 .diagnostics = &diagnostics,
4630 });
4631 expected.optional = 10;
4632 try std.testing.expectEqualDeep(expected, found);
4633
4634 try updateFromSlice(MyStruct, &found, .{
4635 .gpa = gpa,
4636 .arena = arena,
4637 .source = ".{ .optional = null }",
4638 .diagnostics = &diagnostics,
4639 });
4640 expected.optional = null;
4641 try std.testing.expectEqualDeep(expected, found);
4642
4643 try updateFromSlice(MyStruct, &found, .{
4644 .gpa = gpa,
4645 .arena = arena,
4646 .source = ".{ .ptr = .{ .x = 10, .y = 20, .z = 30 } }",
4647 .diagnostics = &diagnostics,
4648 });
4649 expected.ptr.x = 10;
4650 expected.ptr.y = 20;
4651 expected.ptr.z = 30;
4652 try std.testing.expectEqualDeep(expected, found);
4653
4654 try updateFromSlice(MyStruct, &found, .{
4655 .gpa = gpa,
4656 .arena = arena,
4657 .source = ".{ .str = \"foo\" }",
4658 .diagnostics = &diagnostics,
4659 });
4660 expected.str = "foo";
4661 try std.testing.expectEqualDeep(expected, found);
4662}
4663
4664test "std.zon update optionals" {
4665 const gpa = std.testing.allocator;
4666 var arena_allocator: ArenaAllocator = .init(gpa);
4667 defer arena_allocator.deinit();
4668 const arena = arena_allocator.allocator();
4669 var diagnostics: Diagnostics = undefined;
4670
4671 const MyStruct = struct {
4672 foo: ?struct { bar: u32 = 1, baz: u32 = 2, qux: u32 },
35614673 };
3562 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, gpa, ".{ .name = \"Alice\", .age = 25 }", null, .{}));
35634674
3564 const Union = union(enum) {
3565 x,
3566 y: u32,
4675 // Updating an optional that starts out null should fill in any default fields we left off
4676 {
4677 var expected: MyStruct = .{ .foo = null };
4678 var found = expected;
4679 try updateFromSliceNoAlloc(MyStruct, &found, .{
4680 .gpa = gpa,
4681 .arena = arena,
4682 .source = ".{ .foo = .{ .qux = 3 } }",
4683 .diagnostics = &diagnostics,
4684 });
4685 expected.foo = .{ .qux = 3 };
4686 try std.testing.expectEqual(expected, found);
4687 }
4688
4689 // Updating an optional that starts out null should error if we leave off required fields.
4690 {
4691 var found: MyStruct = .{ .foo = null };
4692 try std.testing.expectError(error.ParseZon, updateFromSliceNoAlloc(MyStruct, &found, .{
4693 .gpa = gpa,
4694 .arena = arena,
4695 .source = ".{ .foo = .{} }",
4696 .diagnostics = &diagnostics,
4697 }));
4698 try std.testing.expectFmt(
4699 \\input.zon:1:12: error: missing required field qux
4700 \\
4701 , "{f}", .{diagnostics.fmt("input.zon")});
4702 }
4703
4704 // Updating an optional that starts out non-null should preserve any values we leave off. It's
4705 // also okay to leave off required fields since they were already set.
4706 {
4707 var expected: MyStruct = .{
4708 .foo = .{ .bar = 10, .baz = 20, .qux = 30 },
4709 };
4710 var found = expected;
4711 try updateFromSliceNoAlloc(MyStruct, &found, .{
4712 .gpa = gpa,
4713 .arena = arena,
4714 .source = ".{ .foo = .{ .baz = 200 } }",
4715 .diagnostics = &diagnostics,
4716 });
4717 expected.foo.?.baz = 200;
4718 try std.testing.expectEqual(expected, found);
4719 }
4720}
4721
4722test "std.zon update optional pointers" {
4723 const gpa = std.testing.allocator;
4724 var arena_allocator: ArenaAllocator = .init(gpa);
4725 defer arena_allocator.deinit();
4726 const arena = arena_allocator.allocator();
4727 var diagnostics: Diagnostics = undefined;
4728
4729 const MyStruct = struct {
4730 foo: ?*const struct { bar: u32 = 1, baz: u32 = 2, qux: u32 },
35674731 };
3568 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".a", null, .{}));
3569 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".{ .b = 8 }", null, .{}));
4732
4733 // Just a smoke test since its the combination of behavior we've already tested separately
4734 {
4735 var expected: MyStruct = .{ .foo = null };
4736 var found = expected;
4737 try updateFromSlice(MyStruct, &found, .{
4738 .gpa = gpa,
4739 .arena = arena,
4740 .source = ".{ .foo = .{ .qux = 3 } }",
4741 .diagnostics = &diagnostics,
4742 });
4743 expected.foo = &.{ .qux = 3 };
4744 try std.testing.expectEqualDeep(expected, found);
4745 }
4746}
4747
4748test "std.zon update pointers" {
4749 const gpa = std.testing.allocator;
4750 var arena_allocator: ArenaAllocator = .init(gpa);
4751 defer arena_allocator.deinit();
4752 const arena = arena_allocator.allocator();
4753 var diagnostics: Diagnostics = undefined;
4754
4755 // Updating a pointer should leave fields we don't specify unchanged
4756 {
4757 const MyStruct = struct {
4758 foo: *struct { bar: u32 = 10, baz: u32 = 20, qux: u32 },
4759 };
4760 var ptr: @typeInfo(@FieldType(MyStruct, "foo")).pointer.child = .{ .qux = 3 };
4761 var expected: MyStruct = .{ .foo = &ptr };
4762 var found = expected;
4763 try updateFromSlice(MyStruct, &found, .{
4764 .gpa = gpa,
4765 .arena = arena,
4766 .source = ".{ .foo = .{ .bar = 100 } }",
4767 .diagnostics = &diagnostics,
4768 });
4769 expected.foo.bar = 100;
4770 try std.testing.expectEqualDeep(expected, found);
4771 }
4772
4773 // Same thing, but for const pointers
4774 {
4775 const MyStruct = struct {
4776 foo: *const struct { bar: u32 = 10, baz: u32 = 20, qux: u32 },
4777 };
4778 var expected: MyStruct = .{ .foo = &.{ .qux = 3 } };
4779 var found = expected;
4780 try updateFromSlice(MyStruct, &found, .{
4781 .gpa = gpa,
4782 .arena = arena,
4783 .source = ".{ .foo = .{ .bar = 100 } }",
4784 .diagnostics = &diagnostics,
4785 });
4786 expected.foo = &.{ .bar = 100, .baz = 20, .qux = 3 };
4787 try std.testing.expectEqualDeep(expected, found);
4788 }
4789}
4790
4791test "std.zon update unions" {
4792 const gpa = std.testing.allocator;
4793 var arena_allocator: ArenaAllocator = .init(gpa);
4794 defer arena_allocator.deinit();
4795 const arena = arena_allocator.allocator();
4796 var diagnostics: Diagnostics = undefined;
4797
4798 const MyUnion = union(enum) {
4799 none: void,
4800 foo: struct { bar: u32 = 10, baz: u32 = 20, qux: u32 },
4801 };
4802
4803 // Updating a union to a new field should fill in any default sub-fields we left off
4804 {
4805 var expected: MyUnion = .none;
4806 var found = expected;
4807 try updateFromSliceNoAlloc(MyUnion, &found, .{
4808 .gpa = gpa,
4809 .arena = arena,
4810 .source = ".{ .foo = .{ .qux = 3 } }",
4811 .diagnostics = &diagnostics,
4812 });
4813 expected = .{ .foo = .{ .qux = 3 } };
4814 try std.testing.expectEqual(expected, found);
4815 }
4816
4817 // Updating a union to a new field should error if we leave off required sub-fields
4818 {
4819 var found: MyUnion = .none;
4820 try std.testing.expectError(error.ParseZon, updateFromSliceNoAlloc(MyUnion, &found, .{
4821 .gpa = gpa,
4822 .arena = arena,
4823 .source = ".{ .foo = .{} }",
4824 .diagnostics = &diagnostics,
4825 }));
4826 try std.testing.expectFmt(
4827 \\input.zon:1:12: error: missing required field qux
4828 \\
4829 , "{f}", .{diagnostics.fmt("input.zon")});
4830 }
4831
4832 // Updating a union should preseve any sub-fields that we left off. It's also okay to leave off
4833 // required fields since they were already set.
4834 {
4835 var expected: MyUnion = .{
4836 .foo = .{ .bar = 10, .baz = 20, .qux = 30 },
4837 };
4838 var found = expected;
4839 try updateFromSliceNoAlloc(MyUnion, &found, .{
4840 .gpa = gpa,
4841 .arena = arena,
4842 .source = ".{ .foo = .{ .baz = 200 } }",
4843 .diagnostics = &diagnostics,
4844 });
4845 expected.foo.baz = 200;
4846 try std.testing.expectEqual(expected, found);
4847 }
4848}
4849
4850test "std.zon variants" {
4851 // Just a smoke test, we don't need to test each variant thoroughly because they all call into
4852 // the same code.
4853
4854 const gpa = std.testing.allocator;
4855 var arena_allocator: ArenaAllocator = .init(gpa);
4856 defer arena_allocator.deinit();
4857 const arena = arena_allocator.allocator();
4858 var diagnostics: Diagnostics = undefined;
4859
4860 const Struct = struct { a: u32, b: u32 };
4861 const start: Struct = .{ .a = 10, .b = 20 };
4862 const end: Struct = .{ .a = 100, .b = 20 };
4863
4864 // Update
4865 {
4866 var ast = try std.zig.Ast.parse(gpa, ".{ .a = 100 }", .{ .mode = .zon });
4867 defer ast.deinit(gpa);
4868 const zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false });
4869 defer zoir.deinit(gpa);
4870
4871 var curr = start;
4872 try updateFromSliceNoAlloc(Struct, &curr, .{
4873 .gpa = gpa,
4874 .arena = arena,
4875 .source = ".{ .a = 100 }",
4876 .diagnostics = &diagnostics,
4877 });
4878 try std.testing.expectEqual(end, curr);
4879
4880 curr = start;
4881 try updateFromSlice(Struct, &curr, .{
4882 .gpa = gpa,
4883 .arena = arena,
4884 .source = ".{ .a = 100 }",
4885 .diagnostics = &diagnostics,
4886 });
4887 try std.testing.expectEqual(end, curr);
4888
4889 curr = start;
4890 try updateFromZoirNoAlloc(Struct, &curr, .{
4891 .arena = arena,
4892 .ast = &ast,
4893 .zoir = &zoir,
4894 .diagnostics = &diagnostics,
4895 });
4896 try std.testing.expectEqual(end, curr);
4897
4898 curr = start;
4899 try updateFromZoir(Struct, &curr, .{
4900 .arena = arena,
4901 .ast = &ast,
4902 .zoir = &zoir,
4903 .diagnostics = &diagnostics,
4904 });
4905 try std.testing.expectEqual(end, curr);
4906 }
4907
4908 // From
4909 {
4910 var ast = try std.zig.Ast.parse(gpa, ".{ .a = 100, .b = 20 }", .{ .mode = .zon });
4911 defer ast.deinit(gpa);
4912 const zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false });
4913 defer zoir.deinit(gpa);
4914
4915 try std.testing.expectEqual(
4916 end,
4917 try fromSliceNoAlloc(Struct, .{
4918 .gpa = gpa,
4919 .arena = arena,
4920 .source = ".{ .a = 100, .b = 20 }",
4921 .diagnostics = &diagnostics,
4922 }),
4923 );
4924 try std.testing.expectEqual(
4925 end,
4926 try fromSlice(Struct, .{
4927 .gpa = gpa,
4928 .arena = arena,
4929 .source = ".{ .a = 100, .b = 20 }",
4930 .diagnostics = &diagnostics,
4931 }),
4932 );
4933 try std.testing.expectEqual(
4934 try fromZoirNoAlloc(Struct, .{
4935 .arena = arena,
4936 .ast = &ast,
4937 .zoir = &zoir,
4938 .diagnostics = &diagnostics,
4939 }),
4940 end,
4941 );
4942 try std.testing.expectEqual(
4943 try fromZoir(Struct, .{
4944 .arena = arena,
4945 .ast = &ast,
4946 .zoir = &zoir,
4947 .diagnostics = &diagnostics,
4948 }),
4949 end,
4950 );
4951 }
4952}
4953
4954test {
4955 _ = Diagnostics;
35704956}
src/Sema/LowerZon.zig+26-26
......@@ -69,7 +69,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
6969 const gpa = comp.gpa;
7070 const io = comp.io;
7171 const ip = &pt.zcu.intern_pool;
72 switch (node.get(self.zoir.*)) {
72 switch (node.get(self.zoir)) {
7373 .true => return .bool_true,
7474 .false => return .bool_false,
7575 .null => return .null_value,
......@@ -99,7 +99,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
9999 gpa,
100100 io,
101101 pt.tid,
102 val.get(self.zoir.*),
102 val.get(self.zoir),
103103 .no_embedded_nulls,
104104 ),
105105 }),
......@@ -172,7 +172,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
172172 gpa,
173173 io,
174174 pt.tid,
175 zoir_name.get(self.zoir.*),
175 zoir_name.get(self.zoir),
176176 .no_embedded_nulls,
177177 );
178178 field_ty.* = ip.typeOf(field_val);
......@@ -310,7 +310,7 @@ fn checkTypeInner(
310310fn nodeSrc(self: *LowerZon, node: Zoir.Node.Index) LazySrcLoc {
311311 return .{
312312 .baseline = .{ .inst = self.tracked_inst, .node = .main },
313 .offset = .{ .node_abs = node.getAstNode(self.zoir.*) },
313 .offset = .{ .node_abs = node.getAstNode(self.zoir) },
314314 };
315315}
316316
......@@ -363,7 +363,7 @@ fn lowerExprKnownResTyInner(
363363 .optional => return pt.intern(.{
364364 .opt = .{
365365 .ty = res_ty.toIntern(),
366 .val = if (node.get(self.zoir.*) == .null) b: {
366 .val = if (node.get(self.zoir) == .null) b: {
367367 break :b .none;
368368 } else b: {
369369 const child_type = res_ty.optionalChild(zcu);
......@@ -418,7 +418,7 @@ fn lowerExprKnownResTyInner(
418418}
419419
420420fn lowerBool(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
421 return switch (node.get(self.zoir.*)) {
421 return switch (node.get(self.zoir)) {
422422 .true => .bool_true,
423423 .false => .bool_false,
424424 else => return error.WrongType,
......@@ -431,7 +431,7 @@ fn lowerInt(
431431 res_ty: Type,
432432) !InternPool.Index {
433433 @setFloatMode(.strict);
434 return switch (node.get(self.zoir.*)) {
434 return switch (node.get(self.zoir)) {
435435 .int_literal => |int| switch (int) {
436436 .small => |val| {
437437 const rhs: i32 = val;
......@@ -555,7 +555,7 @@ fn lowerFloat(
555555 res_ty: Type,
556556) !InternPool.Index {
557557 @setFloatMode(.strict);
558 const value = switch (node.get(self.zoir.*)) {
558 const value = switch (node.get(self.zoir)) {
559559 .int_literal => |int| switch (int) {
560560 .small => |val| try self.sema.pt.floatValue(res_ty, @as(f128, @floatFromInt(val))),
561561 .big => |val| try self.sema.pt.floatValue(res_ty, val.toFloat(f128, .nearest_even)[0]),
......@@ -592,7 +592,7 @@ fn lowerFloat(
592592}
593593
594594fn lowerNull(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
595 switch (node.get(self.zoir.*)) {
595 switch (node.get(self.zoir)) {
596596 .null => return .null_value,
597597 else => return error.WrongType,
598598 }
......@@ -600,7 +600,7 @@ fn lowerNull(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
600600
601601fn lowerArray(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
602602 const array_info = res_ty.arrayInfo(self.sema.pt.zcu);
603 const nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir.*)) {
603 const nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) {
604604 .array_literal => |nodes| nodes,
605605 .empty_literal => .{ .start = node, .len = 0 },
606606 else => return error.WrongType,
......@@ -633,13 +633,13 @@ fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.I
633633 const io = comp.io;
634634 const ip = &pt.zcu.intern_pool;
635635 try self.sema.ensureLayoutResolved(res_ty, self.import_src, .init);
636 switch (node.get(self.zoir.*)) {
636 switch (node.get(self.zoir)) {
637637 .enum_literal => |field_name| {
638638 const field_name_interned = try ip.getOrPutString(
639639 gpa,
640640 io,
641641 self.sema.pt.tid,
642 field_name.get(self.zoir.*),
642 field_name.get(self.zoir),
643643 .no_embedded_nulls,
644644 );
645645 const field_index = res_ty.enumFieldIndex(field_name_interned, self.sema.pt.zcu) orelse {
......@@ -648,7 +648,7 @@ fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.I
648648 "enum {f} has no member named '{f}'",
649649 .{
650650 res_ty.fmt(self.sema.pt.zcu),
651 std.zig.fmtId(field_name.get(self.zoir.*)),
651 std.zig.fmtId(field_name.get(self.zoir)),
652652 },
653653 );
654654 };
......@@ -667,13 +667,13 @@ fn lowerEnumLiteral(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
667667 const gpa = comp.gpa;
668668 const io = comp.io;
669669 const ip = &pt.zcu.intern_pool;
670 switch (node.get(self.zoir.*)) {
670 switch (node.get(self.zoir)) {
671671 .enum_literal => |field_name| {
672672 const field_name_interned = try ip.getOrPutString(
673673 gpa,
674674 io,
675675 self.sema.pt.tid,
676 field_name.get(self.zoir.*),
676 field_name.get(self.zoir),
677677 .no_embedded_nulls,
678678 );
679679 return self.sema.pt.intern(.{ .enum_literal = field_name_interned });
......@@ -696,7 +696,7 @@ fn lowerTuple(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
696696
697697 const tuple_info = ip.indexToKey(res_ty.toIntern()).tuple_type;
698698
699 const elem_nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir.*)) {
699 const elem_nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) {
700700 .array_literal => |nodes| nodes,
701701 .empty_literal => .{ .start = node, .len = 0 },
702702 else => return error.WrongType,
......@@ -720,7 +720,7 @@ fn lowerTuple(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
720720 "index {} outside tuple of length {}",
721721 .{
722722 elems.len,
723 elem_nodes.at(@intCast(i)).getAstNode(self.zoir.*),
723 elem_nodes.at(@intCast(i)).getAstNode(self.zoir),
724724 },
725725 );
726726 }
......@@ -760,7 +760,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
760760 try self.sema.ensureStructDefaultsResolved(res_ty, self.import_src);
761761 const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?;
762762
763 const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.zoir.*)) {
763 const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.zoir)) {
764764 .struct_literal => |fields| fields,
765765 .empty_literal => .{ .names = &.{}, .vals = .{ .start = node, .len = 0 } },
766766 else => return error.WrongType,
......@@ -780,7 +780,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
780780 gpa,
781781 io,
782782 self.sema.pt.tid,
783 fields.names[i].get(self.zoir.*),
783 fields.names[i].get(self.zoir),
784784 .no_embedded_nulls,
785785 );
786786 const field_node = fields.vals.at(@intCast(i));
......@@ -844,7 +844,7 @@ fn lowerSlice(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
844844 const string_alignment = ptr_info.flags.alignment == .none or ptr_info.flags.alignment == .@"1";
845845 const string_sentinel = ptr_info.sentinel == .none or ptr_info.sentinel == .zero_u8;
846846 if (string_alignment and ptr_info.child == .u8_type and string_sentinel) {
847 switch (node.get(self.zoir.*)) {
847 switch (node.get(self.zoir)) {
848848 .string_literal => |val| {
849849 const ip_str = try ip.getOrPutString(gpa, io, self.sema.pt.tid, val, .maybe_embedded_nulls);
850850 const str_ref = try self.sema.addStrLit(ip_str, val.len);
......@@ -860,7 +860,7 @@ fn lowerSlice(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
860860 }
861861
862862 // Slice literals
863 const elem_nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir.*)) {
863 const elem_nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) {
864864 .array_literal => |nodes| nodes,
865865 .empty_literal => .{ .start = node, .len = 0 },
866866 else => return error.WrongType,
......@@ -927,19 +927,19 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
927927 const union_info = pt.zcu.typeToUnion(res_ty).?;
928928 const enum_tag_info = ip.loadEnumType(union_info.enum_tag_type);
929929
930 const field_name, const maybe_field_node = switch (node.get(self.zoir.*)) {
930 const field_name, const maybe_field_node = switch (node.get(self.zoir)) {
931931 .enum_literal => |name| b: {
932932 const field_name = try ip.getOrPutString(
933933 gpa,
934934 io,
935935 self.sema.pt.tid,
936 name.get(self.zoir.*),
936 name.get(self.zoir),
937937 .no_embedded_nulls,
938938 );
939939 break :b .{ field_name, null };
940940 },
941941 .struct_literal => b: {
942 const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.zoir.*)) {
942 const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.zoir)) {
943943 .struct_literal => |fields| fields,
944944 else => return self.fail(node, "expected type '{f}'", .{res_ty.fmt(self.sema.pt.zcu)}),
945945 };
......@@ -950,7 +950,7 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
950950 gpa,
951951 io,
952952 self.sema.pt.tid,
953 fields.names[0].get(self.zoir.*),
953 fields.names[0].get(self.zoir),
954954 .no_embedded_nulls,
955955 );
956956 break :b .{ field_name, fields.vals.at(0) };
......@@ -986,7 +986,7 @@ fn lowerVector(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
986986
987987 const vector_info = ip.indexToKey(res_ty.toIntern()).vector_type;
988988
989 const elem_nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir.*)) {
989 const elem_nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) {
990990 .array_literal => |nodes| nodes,
991991 .empty_literal => .{ .start = node, .len = 0 },
992992 else => return error.WrongType,
src/print_zoir.zig+1-1
......@@ -54,7 +54,7 @@ const PrintZon = struct {
5454 }
5555
5656 fn renderNode(pz: *PrintZon, node: Zoir.Node.Index) Error!void {
57 const zoir = pz.zoir;
57 const zoir = &pz.zoir;
5858 try pz.w.print("%{d} = ", .{@backingInt(node)});
5959 switch (node.get(zoir)) {
6060 .true => try pz.w.writeAll("true"),