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...@@ -168,11 +168,31 @@ pub inline fn rawFree(a: Allocator, memory: []u8, alignment: Alignment, ret_addr
168/// Returns a pointer to undefined memory.168/// Returns a pointer to undefined memory.
169/// Call `destroy` with the result to free the memory.169/// Call `destroy` with the result to free the memory.
170pub fn create(a: Allocator, comptime T: type) Error!*T {170pub 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 {
171 if (@sizeOf(T) == 0) {190 if (@sizeOf(T) == 0) {
172 const ptr = comptime std.mem.alignBackward(usize, math.maxInt(usize), @alignOf(T));191 const ptr = comptime std.mem.alignBackward(usize, math.maxInt(usize), @alignOf(T));
173 return @ptrFromInt(ptr);192 return @ptrFromInt(ptr);
174 }193 }
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));
176 return ptr;196 return ptr;
177}197}
178198
lib/std/zig/ErrorBundle.zig+2-2
...@@ -634,7 +634,7 @@ pub const Wip = struct {...@@ -634,7 +634,7 @@ pub const Wip = struct {
634 const err_loc = std.zig.findLineColumn(source, err_span.main);634 const err_loc = std.zig.findLineColumn(source, err_span.main);
635635
636 try eb.addRootErrorMessage(.{636 try eb.addRootErrorMessage(.{
637 .msg = try eb.addString(err.msg.get(zoir)),637 .msg = try eb.addString(err.msg.get(&zoir)),
638 .src_loc = try eb.addSourceLocation(.{638 .src_loc = try eb.addSourceLocation(.{
639 .src_path = try eb.addString(src_path),639 .src_path = try eb.addString(src_path),
640 .span_start = err_span.start,640 .span_start = err_span.start,
...@@ -664,7 +664,7 @@ pub const Wip = struct {...@@ -664,7 +664,7 @@ pub const Wip = struct {
664664
665 // This line can cause `wip.extra.items` to be resized.665 // This line can cause `wip.extra.items` to be resized.
666 const note_index = @backingInt(try eb.addErrorMessage(.{666 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)),
668 .src_loc = try eb.addSourceLocation(.{668 .src_loc = try eb.addSourceLocation(.{
669 .src_path = try eb.addString(src_path),669 .src_path = try eb.addString(src_path),
670 .span_start = note_span.start,670 .span_start = note_span.start,
lib/std/zig/Zoir.zig+6-6
...@@ -42,7 +42,7 @@ pub const Header = extern struct {...@@ -42,7 +42,7 @@ pub const Header = extern struct {
42 }42 }
43};43};
4444
45pub fn hasCompileErrors(zoir: Zoir) bool {45pub fn hasCompileErrors(zoir: *const Zoir) bool {
46 if (zoir.compile_errors.len > 0) {46 if (zoir.compile_errors.len > 0) {
47 assert(zoir.nodes.len == 0);47 assert(zoir.nodes.len == 0);
48 assert(zoir.extra.len == 0);48 assert(zoir.extra.len == 0);
...@@ -54,7 +54,7 @@ pub fn hasCompileErrors(zoir: Zoir) bool {...@@ -54,7 +54,7 @@ pub fn hasCompileErrors(zoir: Zoir) bool {
54 }54 }
55}55}
5656
57pub fn deinit(zoir: Zoir, gpa: Allocator) void {57pub fn deinit(zoir: *const Zoir, gpa: Allocator) void {
58 var nodes = zoir.nodes;58 var nodes = zoir.nodes;
59 nodes.deinit(gpa);59 nodes.deinit(gpa);
6060
...@@ -105,7 +105,7 @@ pub const Node = union(enum) {...@@ -105,7 +105,7 @@ pub const Node = union(enum) {
105 root = 0,105 root = 0,
106 _,106 _,
107107
108 pub fn get(idx: Index, zoir: Zoir) Node {108 pub fn get(idx: Index, zoir: *const Zoir) Node {
109 const repr = zoir.nodes.get(@backingInt(idx));109 const repr = zoir.nodes.get(@backingInt(idx));
110 return switch (repr.tag) {110 return switch (repr.tag) {
111 .true => .true,111 .true => .true,
...@@ -151,7 +151,7 @@ pub const Node = union(enum) {...@@ -151,7 +151,7 @@ pub const Node = union(enum) {
151 };151 };
152 }152 }
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 {
155 return zoir.nodes.items(.ast_node)[@backingInt(idx)];155 return zoir.nodes.items(.ast_node)[@backingInt(idx)];
156 }156 }
157157
...@@ -227,7 +227,7 @@ pub const Node = union(enum) {...@@ -227,7 +227,7 @@ pub const Node = union(enum) {
227227
228pub const NullTerminatedString = enum(u32) {228pub const NullTerminatedString = enum(u32) {
229 _,229 _,
230 pub fn get(nts: NullTerminatedString, zoir: Zoir) [:0]const u8 {230 pub fn get(nts: NullTerminatedString, zoir: *const Zoir) [:0]const u8 {
231 const idx = std.mem.findScalar(u8, zoir.string_bytes[@backingInt(nts)..], 0).?;231 const idx = std.mem.findScalar(u8, zoir.string_bytes[@backingInt(nts)..], 0).?;
232 return zoir.string_bytes[@backingInt(nts)..][0..idx :0];232 return zoir.string_bytes[@backingInt(nts)..][0..idx :0];
233 }233 }
...@@ -244,7 +244,7 @@ pub const CompileError = extern struct {...@@ -244,7 +244,7 @@ pub const CompileError = extern struct {
244 first_note: u32,244 first_note: u32,
245 note_count: u32,245 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 {
248 return zoir.error_notes[err.first_note..][0..err.note_count];248 return zoir.error_notes[err.first_note..][0..err.note_count];
249 }249 }
250250
lib/std/zig/ZonGen.zig+4-4
...@@ -490,7 +490,7 @@ fn appendIdentStr(zg: *ZonGen, ident_token: Ast.TokenIndex) error{ OutOfMemory,...@@ -490,7 +490,7 @@ fn appendIdentStr(zg: *ZonGen, ident_token: Ast.TokenIndex) error{ OutOfMemory,
490}490}
491491
492/// Estimates the size of a string node without parsing it.492/// 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 {
494 switch (tree.nodeTag(node)) {494 switch (tree.nodeTag(node)) {
495 // Parsed string literals are typically around the size of the raw strings.495 // Parsed string literals are typically around the size of the raw strings.
496 .string_literal => {496 .string_literal => {
...@@ -515,7 +515,7 @@ pub fn strLitSizeHint(tree: Ast, node: Ast.Node.Index) usize {...@@ -515,7 +515,7 @@ pub fn strLitSizeHint(tree: Ast, node: Ast.Node.Index) usize {
515515
516/// Parses the given node as a string literal.516/// Parses the given node as a string literal.
517pub fn parseStrLit(517pub fn parseStrLit(
518 tree: Ast,518 tree: *const Ast,
519 node: Ast.Node.Index,519 node: Ast.Node.Index,
520 writer: *Writer,520 writer: *Writer,
521) Writer.Error!std.zig.string_literal.Result {521) Writer.Error!std.zig.string_literal.Result {
...@@ -559,12 +559,12 @@ fn strLitAsString(zg: *ZonGen, str_node: Ast.Node.Index) error{ OutOfMemory, Bad...@@ -559,12 +559,12 @@ fn strLitAsString(zg: *ZonGen, str_node: Ast.Node.Index) error{ OutOfMemory, Bad
559 const gpa = zg.gpa;559 const gpa = zg.gpa;
560 const string_bytes = &zg.string_bytes;560 const string_bytes = &zg.string_bytes;
561 const str_index: u32 = @intCast(zg.string_bytes.items.len);561 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);
563 try string_bytes.ensureUnusedCapacity(gpa, size_hint);563 try string_bytes.ensureUnusedCapacity(gpa, size_hint);
564 const result = r: {564 const result = r: {
565 var aw: Writer.Allocating = .fromArrayList(gpa, &zg.string_bytes);565 var aw: Writer.Allocating = .fromArrayList(gpa, &zg.string_bytes);
566 defer zg.string_bytes = aw.toArrayList();566 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) {
568 error.WriteFailed => return error.OutOfMemory,568 error.WriteFailed => return error.OutOfMemory,
569 };569 };
570 };570 };
lib/std/zon/parse.zig+2921-1535
...@@ -1,14 +1,13 @@...@@ -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.
2//!3//!
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`.
4//!5//!
5//! Parsing from individual Zoir nodes is also available:6//! To parse into an existing value, see the `updateFrom*` variants. For lower level control over
6//! * `fromZoir`/`fromZoirAlloc`7//! parsing, see `std.zig.ZonGen`. For importing ZON at compile time, use `@import`.
7//! * `fromZoirNode`/`fromZoirNodeAlloc`
8//!
9//! For lower level control over parsing, see `std.zig.Zoir`.
108
11const std = @import("std");9const std = @import("std");
10const builtin = @import("builtin");
12const Allocator = std.mem.Allocator;11const Allocator = std.mem.Allocator;
13const Ast = std.zig.Ast;12const Ast = std.zig.Ast;
14const Zoir = std.zig.Zoir;13const Zoir = std.zig.Zoir;
...@@ -19,443 +18,474 @@ const StrLitErr = std.zig.string_literal.Error;...@@ -19,443 +18,474 @@ const StrLitErr = std.zig.string_literal.Error;
19const NumberLiteralError = std.zig.number_literal.Error;18const NumberLiteralError = std.zig.number_literal.Error;
20const assert = std.debug.assert;19const assert = std.debug.assert;
21const ArrayList = std.ArrayList;20const ArrayList = std.ArrayList;
21const ArenaAllocator = std.heap.ArenaAllocator;
2222
23/// Rename when adding or removing support for a type.23/// Rename when adding or removing support for a type.
24const valid_types = {};24const valid_types = {};
2525
26/// Configuration for the runtime parser.26/// Errors encountered while parsing ZON. See `log` and `fatal` for reporting errors to the user.
27pub const Options = struct {27pub const Diagnostics = struct {
28 /// If true, unknown fields do not error.28 errors: []const 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};
3529
36pub const Error = union(enum) {30 /// Log the failure with `std.log.err`.
37 zoir: Zoir.CompileError,31 pub fn log(self: *const Diagnostics, path: []const u8) void {
38 type_check: Error.TypeCheckFailure,32 std.log.err("{f}", .{self.fmt(path)});
3933 }
40 pub const Note = union(enum) {34
41 zoir: Zoir.CompileError.Note,35 test log {
42 type_check: TypeCheckFailure.Note,36 const gpa = std.testing.allocator;
4337 var arena_allocator: ArenaAllocator = .init(gpa);
44 pub const Iterator = struct {38 defer arena_allocator.deinit();
45 index: usize = 0,39 const arena = arena_allocator.allocator();
46 err: Error,40 var diagnostics: Diagnostics = undefined;
47 diag: *const Diagnostics,41
4842 const MyType = struct {
49 pub fn next(self: *@This()) ?Note {43 foo: u32,
50 switch (self.err) {44 bar: u32,
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 }
65 };45 };
6646
67 fn formatMessage(self: []const u8, w: *std.Io.Writer) std.Io.Writer.Error!void {47 const parsed: MyType = fromSliceNoAlloc(MyType, .{
68 // Just writes the string for now, but we're keeping this behind a formatter so we have48 .gpa = gpa,
69 // the option to extend it in the future to print more advanced messages (like `Error`49 .arena = arena,
70 // does) without breaking the API.50 .source = ".{ .foo = 1, .bar = 2 }",
71 try w.writeAll(self);51 .diagnostics = &diagnostics,
72 }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) {62 /// Log the failure with `std.log.err`, and then terminate the process with exit code 1.
75 return .{ .data = switch (self) {63 pub fn fatal(self: *const Diagnostics, path: []const u8) noreturn {
76 .zoir => |note| note.msg.get(diag.zoir),64 std.process.fatal("{f}", .{self.fmt(path)});
77 .type_check => |note| note.msg,65 }
78 } };
79 }
8066
81 pub fn getLocation(self: Note, diag: *const Diagnostics) Ast.Location {67 test fatal {
82 switch (self) {68 const gpa = std.testing.allocator;
83 .zoir => |note| return zoirErrorLocation(diag.ast, note.token, note.node_or_offset),69 var arena_allocator: ArenaAllocator = .init(gpa);
84 .type_check => |note| return diag.ast.tokenLocation(note.offset, note.token),70 defer arena_allocator.deinit();
85 }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);
86 }112 }
87 };113 }
88114
89 pub const Iterator = struct {115 pub const Formatter = struct {
90 index: usize = 0,116 path: []const u8,
91 diag: *const Diagnostics,117 errors: []const Error,
92118
93 pub fn next(self: *@This()) ?Error {119 pub fn format(self: *const @This(), w: *std.Io.Writer) std.Io.Writer.Error!void {
94 if (self.index < self.diag.zoir.compile_errors.len) {120 for (self.errors) |e| {
95 const result: Error = .{ .zoir = self.diag.zoir.compile_errors[self.index] };121 try w.print("{s}:", .{self.path});
96 self.index += 1;122 try w.print("{d}:{d}: error: {s}\n", .{
97 return result;123 e.loc.line + 1,
98 }124 e.loc.column + 1,
125 e.msg,
126 });
99127
100 if (self.diag.type_check) |err| {128 for (e.notes) |note| {
101 if (self.index == self.diag.zoir.compile_errors.len) {129 try w.print("{s}:", .{self.path});
102 const result: Error = .{ .type_check = err };130 try w.print("{d}:{d}: note: {s}\n", .{
103 self.index += 1;131 note.loc.line + 1,
104 return result;132 note.loc.column + 1,
133 note.msg,
134 });
105 }135 }
106 }136 }
107
108 return null;
109 }137 }
110 };138 };
111139
112 const TypeCheckFailure = struct {140 pub const Error = struct {
113 const Note = struct {141 msg: []const u8,
114 token: Ast.TokenIndex,142 loc: Ast.Location,
115 offset: u32,143 token: Ast.OptionalTokenIndex,
116 msg: []const u8,144 /// If `token == .none`, this is an `Ast.Node.Index`.
117 owned: bool,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 {149 const Options = struct {
120 if (self.owned) gpa.free(self.msg);150 msg: []const u8,
121 }151 token: Ast.OptionalTokenIndex,
152 node_or_offset: u32,
153 notes: []Note,
122 };154 };
123155
124 message: []const u8,156 fn init(ast: *const Ast, options: Error.Options) Error {
125 owned: bool,157 return .{
126 token: Ast.TokenIndex,158 .msg = options.msg,
127 offset: u32,159 .loc = astLoc(ast, options.token, options.node_or_offset),
128 note: ?@This().Note,160 .token = options.token,
129161 .node_or_offset = options.node_or_offset,
130 fn deinit(self: @This(), gpa: Allocator) void {162 .notes = options.notes,
131 if (self.note) |note| note.deinit(gpa);163 };
132 if (self.owned) gpa.free(self.message);
133 }164 }
165 };
134166
135 fn getNoteCount(self: @This()) usize {167 pub const Note = struct {
136 return @intFromBool(self.note != null);168 msg: []const u8,
137 }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 {175 const Options = struct {
140 assert(index == 0);176 msg: []const u8,
141 return self.note.?;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 };
142 }188 }
143 };189 };
190};
144191
145 const FormatMessage = struct {192pub const Options = struct {
146 err: Error,193 /// Used for scratch allocations.
147 diag: *const Diagnostics,194 gpa: Allocator,
148 };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 {206/// Parses the given slice as ZON, writing any errors to `options.diagnostics`.
151 switch (self.err) {207pub fn fromSlice(T: type, options: Options) error{ OutOfMemory, ParseZon }!T {
152 .zoir => |err| try w.writeAll(err.msg.get(self.diag.zoir)),208 var value: T = undefined;
153 .type_check => |tc| try w.writeAll(tc.message),209 try fromSliceInner(T, &value, false, options);
154 }210 return value;
155 }211}
156212
157 pub fn fmtMessage(self: @This(), diag: *const Diagnostics) std.fmt.Alt(FormatMessage, formatMessage) {213test fromSlice {
158 return .{ .data = .{214 const gpa = std.testing.allocator;
159 .err = self,215 var arena_allocator: ArenaAllocator = .init(gpa);
160 .diag = diag,216 defer arena_allocator.deinit();
161 } };217 const arena = arena_allocator.allocator();
162 }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 {226 const source =
165 return switch (self) {227 \\.{
166 .zoir => |err| return zoirErrorLocation(228 \\ .address_mode = .{ .u = .clamp },
167 diag.ast,229 \\ .mipmaps = false,
168 err.token,230 \\}
169 err.node_or_offset,231 ;
170 ),
171 .type_check => |err| return diag.ast.tokenLocation(err.offset, err.token),
172 };
173 }
174232
175 pub fn iterateNotes(self: @This(), diag: *const Diagnostics) Note.Iterator {233 var diagnostics: Diagnostics = undefined;
176 return .{ .err = self, .diag = diag };234 const options = fromSlice(TextureOptions, .{
177 }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 {247 try std.testing.expectEqualDeep(TextureOptions{
180 if (maybe_token.unwrap()) |token| {248 .address_mode = .{ .u = .clamp, .v = .wrap },
181 var location = ast.tokenLocation(0, token);249 .mipmaps = false,
182 location.column += node_or_offset;250 .premultiply = true,
183 return location;251 }, options);
184 } else {252}
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};
191253
192/// Information about the success or failure of a parse.254/// Like `fromSlice` but the result type may not contain pointers, allowing it to outlive
193pub const Diagnostics = struct {255/// `options.arena`.
194 ast: Ast = .{256pub fn fromSliceNoAlloc(T: type, options: Options) error{ OutOfMemory, ParseZon }!T {
195 .source = "",257 comptime assert(!requiresAllocator(T));
196 .tokens = .empty,258 return fromSlice(T, options);
197 .nodes = .empty,259}
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};
249260
250/// Parses the given slice as ZON.261/// Similar to `fromSlice`, but updates the existing contents of `value` in place. Fields
251///262/// unspecified by ZON are left unchanged.
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.
260///263///
261/// An allocator is still required for temporary allocations made during parsing.264/// Assumes that `value` points to a fully initialized value prior to this call. Slices and untagged
262pub fn fromSlice(265/// unions are replaced in their entirey when specified. On error, `value` remains valid, but may be
266/// partially updated.
267pub fn updateFromSlice(
263 T: type,268 T: type,
264 gpa: Allocator,269 value: *T,
265 source: [:0]const u8,
266 diag: ?*Diagnostics,
267 options: Options,270 options: Options,
268) error{ OutOfMemory, ParseZon }!T {271) error{ OutOfMemory, ParseZon }!void {
269 comptime assert(!requiresAllocator(T));272 try fromSliceInner(T, value, true, options);
270 return fromSliceAlloc(T, gpa, source, diag, options);
271}273}
272274
273/// Like `fromSlice`, but the result may contain pointers. To automatically free the result, see275test updateFromSlice {
274/// `free`.276 const gpa = std.testing.allocator;
275pub fn fromSliceAlloc(277 var arena_allocator: ArenaAllocator = .init(gpa);
276 /// The type to deserialize into. May not be or contain any of the following types:278 defer arena_allocator.deinit();
277 /// * Any comptime-only type, except in a comptime field279 const arena = arena_allocator.allocator();
278 /// * `type`280
279 /// * `void`, except as a union payload281 const MyTextEditorConfig = struct {
280 /// * `noreturn`282 indentation: enum { spaces, tabs },
281 /// * An error set/error union283 columns: []const u16,
282 /// * A many-pointer or C-pointer284 dark_mode: enum { auto, dark, light },
283 /// * An opaque type, including `anyopaque`285 theme: []const u8,
284 /// * An async frame type, including `anyframe` and `anyframe->T`286 };
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();
295287
296 var ast = try std.zig.Ast.parse(gpa, source, .{ .mode = .zon });288 const global_config =
297 defer if (diag == null) ast.deinit(gpa);289 \\.{
298 if (diag) |s| s.ast = ast;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 a308 var diagnostics: Diagnostics = undefined;
301 // diagnostics, ownership is transferred to diagnostics.309 updateFromSlice(MyTextEditorConfig, &config, .{
302 var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false });310 .gpa = gpa,
303 defer if (diag == null) zoir.deinit(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.* = .{};334 try std.testing.expectEqualDeep(MyTextEditorConfig{
306 return fromZoirAlloc(T, gpa, ast, zoir, diag, options);335 .indentation = .tabs,
336 .columns = &.{100},
337 .dark_mode = .dark,
338 .theme = "default",
339 }, config);
307}340}
308341
309/// Like `fromSlice`, but operates on `Zoir` instead of ZON source.342/// Like `updateFromSlice` but the `T` may not contain pointers, allowing `value` to outlive
310pub fn fromZoir(343/// `options.arena`.
344pub fn updateFromSliceNoAlloc(
311 T: type,345 T: type,
312 ast: Ast,346 value: *T,
313 zoir: Zoir,
314 diag: ?*Diagnostics,
315 options: Options,347 options: Options,
316) error{ParseZon}!T {348) error{ OutOfMemory, ParseZon }!void {
317 comptime assert(!requiresAllocator(T));349 comptime assert(!requiresAllocator(T));
318 var buf: [0]u8 = .{};350 try fromSliceInner(T, value, true, options);
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 };
331}351}
332352
333/// Like `fromSliceAlloc`, but operates on `Zoir` instead of ZON source.353fn fromSliceInner(
334pub fn fromZoirAlloc(
335 T: type,354 T: type,
336 gpa: Allocator,355 value: *T,
337 ast: Ast,356 initialized: bool,
338 zoir: Zoir,
339 diag: ?*Diagnostics,
340 options: Options,357 options: Options,
341) error{ OutOfMemory, ParseZon }!T {358) error{ OutOfMemory, ParseZon }!void {
342 return fromZoirNodeAlloc(T, gpa, ast, zoir, .root, diag, options);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;
343}399}
344400
345/// Like `fromZoir`, but the parse starts at `node` instead of root.401/// Like `fromSliceNoAlloc`, but operates on `Zoir` instead of ZON source.
346pub fn fromZoirNode(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(
347 T: type,409 T: type,
348 ast: Ast,410 value: *T,
349 zoir: Zoir,411 options: FromZoirOptions,
350 node: Zoir.Node.Index,412) error{ OutOfMemory, ParseZon }!void {
351 diag: ?*Diagnostics,413 return fromZoirInner(T, value, true, options);
352 options: Options,414}
353) error{ParseZon}!T {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 {
354 comptime assert(!requiresAllocator(T));422 comptime assert(!requiresAllocator(T));
355 var buf: [0]u8 = .{};423 return updateFromZoir(T, value, options);
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 };
369}424}
370425
371/// Like `fromZoirAlloc`, but the parse starts at `node` instead of root.426fn fromZoirInner(
372pub fn fromZoirNodeAlloc(
373 T: type,427 T: type,
374 gpa: Allocator,428 value: *T,
375 ast: Ast,429 initialized: bool,
376 zoir: Zoir,430 options: FromZoirOptions,
377 node: Zoir.Node.Index,431) error{ OutOfMemory, ParseZon }!void {
378 diag: ?*Diagnostics,432 var errors: std.ArrayList(Diagnostics.Error) = .empty;
379 options: Options,433 defer options.diagnostics.* = .{ .errors = errors.items };
380) error{ OutOfMemory, ParseZon }!T {434 return inner(T, value, initialized, .{
381 comptime assert(canParseType(T));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| {443const InnerOptions = struct {
384 s.assertEmpty();444 arena: Allocator,
385 s.ast = ast;445 ast: *const Ast,
386 s.zoir = zoir;446 zoir: *const Zoir,
387 }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 }
390 return error.ParseZon;477 return error.ParseZon;
391 }478 }
392479
393 var parser: Parser = .{480 var parser: Parser = .{
394 .gpa = gpa,481 .arena = options.arena,
395 .ast = ast,482 .ast = options.ast,
396 .zoir = zoir,483 .zoir = options.zoir,
397 .options = options,484 .ignore_unknown_fields = options.ignore_unknown_fields,
398 .diag = diag,485 .errors = options.errors,
399 };486 };
400487
401 return parser.parseExpr(T, node);488 try parser.parseExprInto(options.node, value, initialized);
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);
459}489}
460490
461fn requiresAllocator(T: type) bool {491fn requiresAllocator(T: type) bool {
...@@ -480,62 +510,93 @@ fn requiresAllocator(T: type) bool {...@@ -480,62 +510,93 @@ fn requiresAllocator(T: type) bool {
480}510}
481511
482const Parser = struct {512const Parser = struct {
483 gpa: Allocator,513 arena: Allocator,
484 ast: Ast,514 ast: *const Ast,
485 zoir: Zoir,515 zoir: *const Zoir,
486 diag: ?*Diagnostics,516 errors: *std.ArrayList(Diagnostics.Error),
487 options: Options,517 ignore_unknown_fields: bool,
488518
489 const ParseExprError = error{ ParseZon, OutOfMemory };519 const ParseExprError = error{ ParseZon, OutOfMemory };
490520
491 fn parseExpr(self: *@This(), T: type, node: Zoir.Node.Index) ParseExprError!T {521 fn parseExprInto(
492 return self.parseExprInner(T, node) catch |err| switch (err) {522 self: *Parser,
493 error.WrongType => return self.failExpectedType(T, node),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),
494 else => |e| return e,529 else => |e| return e,
495 };530 };
496 }531 }
497532
498 const ParseExprInnerError = error{ ParseZon, OutOfMemory, WrongType };533 const ParseExprInnerError = error{ ParseZon, OutOfMemory, WrongType };
499534
500 fn parseExprInner(535 fn parseExprIntoInner(
501 self: *@This(),536 self: *@This(),
502 T: type,
503 node: Zoir.Node.Index,537 node: Zoir.Node.Index,
504 ) ParseExprInnerError!T {538 out: anytype,
505 if (T == Zoir.Node.Index) {539 initialized: bool,
506 return node;540 ) ParseExprInnerError!void {
541 if (@TypeOf(out.*) == Zoir.Node.Index) {
542 out.* = node;
543 return;
507 }544 }
508545
509 switch (@typeInfo(T)) {546 switch (@typeInfo(@TypeOf(out.*))) {
510 .optional => |optional| if (node.get(self.zoir) == .null) {547 .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);
512 } else {551 } 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;
514 },555 },
515 .bool => return self.parseBool(node),556 .bool => out.* = try self.parseBool(node),
516 .int => return self.parseInt(T, node),557 .int => out.* = try self.parseInt(@TypeOf(out.*), node),
517 .float => return self.parseFloat(T, node),558 .float => out.* = try self.parseFloat(@TypeOf(out.*), node),
518 .@"enum" => return self.parseEnumLiteral(T, node),559 .@"enum" => out.* = try self.parseEnumLiteral(@TypeOf(out.*), node),
519 .pointer => |pointer| switch (pointer.size) {560 .pointer => |pointer| switch (pointer.size) {
520 .one => {561 .one => {
521 const result = try self.gpa.create(pointer.child);562 // Get a pointer to update
522 errdefer self.gpa.destroy(result);563 const new = b: {
523 result.* = try self.parseExprInner(pointer.child, node);564 // If the existing value is initialized and non const, use it
524 return result;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;
525 },590 },
526 .slice => return self.parseSlicePointer(T, node),
527 else => comptime unreachable,591 else => comptime unreachable,
528 },592 },
529 .array => return self.parseArray(T, node),593 .array => try self.parseArrayInto(node, out),
530 .vector => |vector| {594 .vector => try self.parseVectorInto(node, out),
531 const A = [vector.len]vector.child;
532 return try self.parseArray(A, node);
533 },
534 .@"struct" => |@"struct"| if (@"struct".is_tuple)595 .@"struct" => |@"struct"| if (@"struct".is_tuple)
535 return self.parseTuple(T, node)596 try self.parseTupleInto(node, out)
536 else597 else
537 return self.parseStruct(T, node),598 try self.parseStructInto(node, out, initialized),
538 .@"union" => return self.parseUnion(T, node),599 .@"union" => try self.parseUnionInto(node, out, initialized),
539600
540 else => comptime unreachable,601 else => comptime unreachable,
541 }602 }
...@@ -545,7 +606,7 @@ const Parser = struct {...@@ -545,7 +606,7 @@ const Parser = struct {
545 /// example, `**?**u8` becomes `?u8`, and types that involve user specified type names are just606 /// example, `**?**u8` becomes `?u8`, and types that involve user specified type names are just
546 /// referred to by the type of container.607 /// referred to by the type of container.
547 fn failExpectedType(608 fn failExpectedType(
548 self: @This(),609 self: Parser,
549 T: type,610 T: type,
550 node: Zoir.Node.Index,611 node: Zoir.Node.Index,
551 ) error{ ParseZon, OutOfMemory } {612 ) error{ ParseZon, OutOfMemory } {
...@@ -554,7 +615,7 @@ const Parser = struct {...@@ -554,7 +615,7 @@ const Parser = struct {
554 }615 }
555616
556 fn failExpectedTypeInner(617 fn failExpectedTypeInner(
557 self: @This(),618 self: Parser,
558 T: type,619 T: type,
559 opt: bool,620 opt: bool,
560 node: Zoir.Node.Index,621 node: Zoir.Node.Index,
...@@ -624,7 +685,7 @@ const Parser = struct {...@@ -624,7 +685,7 @@ const Parser = struct {
624 }685 }
625 }686 }
626687
627 fn parseBool(self: @This(), node: Zoir.Node.Index) !bool {688 fn parseBool(self: Parser, node: Zoir.Node.Index) !bool {
628 switch (node.get(self.zoir)) {689 switch (node.get(self.zoir)) {
629 .true => return true,690 .true => return true,
630 .false => return false,691 .false => return false,
...@@ -632,7 +693,7 @@ const Parser = struct {...@@ -632,7 +693,7 @@ const Parser = struct {
632 }693 }
633 }694 }
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 {
636 switch (node.get(self.zoir)) {697 switch (node.get(self.zoir)) {
637 .int_literal => |int| switch (int) {698 .int_literal => |int| switch (int) {
638 .small => |val| return std.math.cast(T, val) orelse699 .small => |val| return std.math.cast(T, val) orelse
...@@ -649,7 +710,7 @@ const Parser = struct {...@@ -649,7 +710,7 @@ const Parser = struct {
649 }710 }
650 }711 }
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 {
653 switch (node.get(self.zoir)) {714 switch (node.get(self.zoir)) {
654 .int_literal => |int| switch (int) {715 .int_literal => |int| switch (int) {
655 .small => |val| return @floatFromInt(val),716 .small => |val| return @floatFromInt(val),
...@@ -664,7 +725,7 @@ const Parser = struct {...@@ -664,7 +725,7 @@ const Parser = struct {
664 }725 }
665 }726 }
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 {
668 switch (node.get(self.zoir)) {729 switch (node.get(self.zoir)) {
669 .enum_literal => |field_name| {730 .enum_literal => |field_name| {
670 // Create a comptime string map for the enum fields731 // Create a comptime string map for the enum fields
...@@ -684,7 +745,7 @@ const Parser = struct {...@@ -684,7 +745,7 @@ const Parser = struct {
684 }745 }
685 }746 }
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 {
688 switch (node.get(self.zoir)) {749 switch (node.get(self.zoir)) {
689 .string_literal => return self.parseString(T, node),750 .string_literal => return self.parseString(T, node),
690 .array_literal => |nodes| return self.parseSlice(T, nodes),751 .array_literal => |nodes| return self.parseSlice(T, nodes),
...@@ -693,13 +754,13 @@ const Parser = struct {...@@ -693,13 +754,13 @@ const Parser = struct {
693 }754 }
694 }755 }
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 {
697 const ast_node = node.getAstNode(self.zoir);758 const ast_node = node.getAstNode(self.zoir);
698 const pointer = @typeInfo(T).pointer;759 const pointer = @typeInfo(T).pointer;
699 var size_hint = ZonGen.strLitSizeHint(self.ast, ast_node);760 var size_hint = ZonGen.strLitSizeHint(self.ast, ast_node);
700 if (pointer.sentinel() != null) size_hint += 1;761 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);
703 try aw.ensureUnusedCapacity(size_hint);764 try aw.ensureUnusedCapacity(size_hint);
704 defer aw.deinit();765 defer aw.deinit();
705 const result = ZonGen.parseStrLit(self.ast, ast_node, &aw.writer) catch return error.OutOfMemory;766 const result = ZonGen.parseStrLit(self.ast, ast_node, &aw.writer) catch return error.OutOfMemory;
...@@ -728,7 +789,7 @@ const Parser = struct {...@@ -728,7 +789,7 @@ const Parser = struct {
728 }789 }
729 }790 }
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 {
732 const pointer = @typeInfo(T).pointer;793 const pointer = @typeInfo(T).pointer;
733794
734 // Make sure we're working with a slice795 // Make sure we're working with a slice
...@@ -738,68 +799,68 @@ const Parser = struct {...@@ -738,68 +799,68 @@ const Parser = struct {
738 }799 }
739800
740 // Allocate the slice801 // Allocate the slice
741 const slice = try self.gpa.allocWithOptions(802 const slice = try self.arena.allocWithOptions(
742 pointer.child,803 pointer.child,
743 nodes.len,804 nodes.len,
744 .fromByteUnitsOptional(pointer.attrs.@"align"),805 .fromByteUnitsOptional(pointer.attrs.@"align"),
745 pointer.sentinel(),806 pointer.sentinel(),
746 );807 );
747 errdefer self.gpa.free(slice);
748808
749 // Parse the elements and return the slice809 // Parse the elements and return the slice
750 for (slice, 0..) |*elem, i| {810 for (slice, 0..) |*elem, i| {
751 errdefer if (self.options.free_on_error) {811 try self.parseExprInto(nodes.at(@intCast(i)), elem, false);
752 for (slice[0..i]) |item| {
753 free(self.gpa, item);
754 }
755 };
756 elem.* = try self.parseExpr(pointer.child, nodes.at(@intCast(i)));
757 }812 }
758813
759 return slice;814 return slice;
760 }815 }
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 {
763 const nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) {818 const nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) {
764 .array_literal => |nodes| nodes,819 .array_literal => |nodes| nodes,
765 .empty_literal => .{ .start = node, .len = 0 },820 .empty_literal => .{ .start = node, .len = 0 },
766 else => return error.WrongType,821 else => return error.WrongType,
767 };822 };
768823
769 const array_info = @typeInfo(T).array;824 const array = @typeInfo(@TypeOf(out.*)).array;
770825
771 // Check if the size matches826 // Check if the size matches
772 if (nodes.len < array_info.len) {827 if (nodes.len < array.len) {
773 return self.failNodeFmt(828 return self.failNodeFmt(
774 node,829 node,
775 "expected {} array elements; found {}",830 "expected {} array elements; found {}",
776 .{ array_info.len, nodes.len },831 .{ array.len, nodes.len },
777 );832 );
778 } else if (nodes.len > array_info.len) {833 } else if (nodes.len > array.len) {
779 return self.failNodeFmt(834 return self.failNodeFmt(
780 nodes.at(array_info.len),835 nodes.at(array.len),
781 "index {} outside of array of length {}",836 "index {} outside of array of length {}",
782 .{ array_info.len, array_info.len },837 .{ array.len, array.len },
783 );838 );
784 }839 }
785840
786 // Parse the elements and return the array841 // Parse the elements and return the array
787 var result: T = undefined;842 for (out, 0..) |*elem, i| {
788 for (&result, 0..) |*elem, i| {843 try self.parseExprInto(nodes.at(@intCast(i)), elem, false);
789 // If we fail to parse this field, free all fields before it844 }
790 errdefer if (self.options.free_on_error) {
791 for (result[0..i]) |item| {
792 free(self.gpa, item);
793 }
794 };
795845
796 elem.* = try self.parseExpr(array_info.child, nodes.at(@intCast(i)));846 if (array.sentinel()) |s| {
847 out[array.len] = s;
797 }848 }
798 if (array_info.sentinel()) |s| result[result.len] = s;
799 return result;
800 }849 }
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 {
803 const repr = node.get(self.zoir);864 const repr = node.get(self.zoir);
804 const fields: @FieldType(Zoir.Node, "struct_literal") = switch (repr) {865 const fields: @FieldType(Zoir.Node, "struct_literal") = switch (repr) {
805 .struct_literal => |nodes| nodes,866 .struct_literal => |nodes| nodes,
...@@ -807,7 +868,7 @@ const Parser = struct {...@@ -807,7 +868,7 @@ const Parser = struct {
807 else => return error.WrongType,868 else => return error.WrongType,
808 };869 };
809870
810 const info = @typeInfo(T).@"struct";871 const info = @typeInfo(@TypeOf(out.*)).@"struct";
811872
812 // Build a map from field name to index.873 // Build a map from field name to index.
813 // The special value `comptime_field` indicates that this is actually a comptime field.874 // The special value `comptime_field` indicates that this is actually a comptime field.
...@@ -821,29 +882,12 @@ const Parser = struct {...@@ -821,29 +882,12 @@ const Parser = struct {
821 };882 };
822883
823 // Parse the struct884 // Parse the struct
824 var result: T = undefined;
825 var field_found: [info.field_names.len]bool = @splat(false);885 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
842 for (0..fields.names.len) |i| {886 for (0..fields.names.len) |i| {
843 const name = fields.names[i].get(self.zoir);887 const name = fields.names[i].get(self.zoir);
844 const field_index = field_indices.get(name) orelse {888 const field_index = field_indices.get(name) orelse {
845 if (self.options.ignore_unknown_fields) continue;889 if (self.ignore_unknown_fields) continue;
846 return self.failUnexpected(T, "field", node, i, name);890 return self.failUnexpected(@TypeOf(out.*), "field", node, i, name);
847 };891 };
848 if (field_index == comptime_field) {892 if (field_index == comptime_field) {
849 return self.failComptimeField(node, i);893 return self.failComptimeField(node, i);
...@@ -857,46 +901,43 @@ const Parser = struct {...@@ -857,46 +901,43 @@ const Parser = struct {
857 switch (field_index) {901 switch (field_index) {
858 inline 0...(info.field_names.len - 1) => |j| {902 inline 0...(info.field_names.len - 1) => |j| {
859 if (info.field_attrs[j].@"comptime") unreachable;903 if (info.field_attrs[j].@"comptime") unreachable;
860904 try self.parseExprInto(
861 @field(result, info.field_names[j]) = try self.parseExpr(
862 info.field_types[j],
863 fields.vals.at(@intCast(i)),905 fields.vals.at(@intCast(i)),
906 &@field(out, info.field_names[j]),
907 initialized,
864 );908 );
865 },909 },
866 else => unreachable, // Can't be out of bounds910 else => unreachable, // Can't be out of bounds
867 }911 }
868
869 initialized += 1;
870 }912 }
871913
872 // Fill in any missing default fields914 // Fill in any missing default fields
873 inline for (field_found, 0..) |found, i| {915 if (!initialized) {
874 if (!found) {916 inline for (field_found, 0..) |found, i| {
875 const field_attrs = info.field_attrs[i];917 if (!found) {
876 if (field_attrs.defaultValue(info.field_types[i])) |default| {918 const field_attrs = info.field_attrs[i];
877 @field(result, info.field_names[i]) = default;919 if (field_attrs.defaultValue(info.field_types[i])) |default| {
878 } else {920 @field(out, info.field_names[i]) = default;
879 return self.failNodeFmt(921 } else {
880 node,922 return self.failNodeFmt(
881 "missing required field {s}",923 node,
882 .{info.field_names[i]},924 "missing required field {s}",
883 );925 .{info.field_names[i]},
926 );
927 }
884 }928 }
885 }929 }
886 }930 }
887
888 return result;
889 }931 }
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 {
892 const nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) {934 const nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) {
893 .array_literal => |nodes| nodes,935 .array_literal => |nodes| nodes,
894 .empty_literal => .{ .start = node, .len = 0 },936 .empty_literal => .{ .start = node, .len = 0 },
895 else => return error.WrongType,937 else => return error.WrongType,
896 };938 };
897939
898 var result: T = undefined;940 const info = @typeInfo(@TypeOf(out.*)).@"struct";
899 const info = @typeInfo(T).@"struct";
900941
901 if (nodes.len > info.field_names.len) {942 if (nodes.len > info.field_names.len) {
902 return self.failNodeFmt(943 return self.failNodeFmt(
...@@ -910,38 +951,36 @@ const Parser = struct {...@@ -910,38 +951,36 @@ const Parser = struct {
910 // Check if we're out of bounds951 // Check if we're out of bounds
911 if (i >= nodes.len) {952 if (i >= nodes.len) {
912 if (info.field_attrs[i].defaultValue(info.field_types[i])) |default| {953 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;
914 } else {955 } else {
915 return self.failNodeFmt(node, "missing tuple field with index {}", .{i});956 return self.failNodeFmt(node, "missing tuple field with index {}", .{i});
916 }957 }
917 } else {958 } 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
926 if (info.field_attrs[i].@"comptime") {959 if (info.field_attrs[i].@"comptime") {
927 return self.failComptimeField(node, i);960 return self.failComptimeField(node, i);
928 } else {961 } else {
929 result[i] = try self.parseExpr(info.field_types[i], nodes.at(i));962 try self.parseExprInto(nodes.at(i), &out[i], false);
930 }963 }
931 }964 }
932 }965 }
933
934 return result;
935 }966 }
936967
937 fn parseUnion(self: *@This(), T: type, node: Zoir.Node.Index) !T {968 fn parseUnionInto(
938 const @"union" = @typeInfo(T).@"union";969 self: *Parser,
970 node: Zoir.Node.Index,
971 out: anytype,
972 initialized: bool,
973 ) !void {
974 const @"union" = @typeInfo(@TypeOf(out.*)).@"union";
939975
940 if (@"union".field_names.len == 0) comptime unreachable;976 if (@"union".field_names.len == 0) comptime unreachable;
941977
942 // Gather info on the fields978 // Gather info on the fields
943 const field_indices = b: {979 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;
945 inline for (@"union".field_names, 0..) |field_name, i| {984 inline for (@"union".field_names, 0..) |field_name, i| {
946 kvs_list[i] = .{ field_name, i };985 kvs_list[i] = .{ field_name, i };
947 }986 }
...@@ -961,7 +1000,13 @@ const Parser = struct {...@@ -961,7 +1000,13 @@ const Parser = struct {
961 const field_index = b: {1000 const field_index = b: {
962 const field_name_str = field_name.get(self.zoir);1001 const field_name_str = field_name.get(self.zoir);
963 break :b field_indices.get(field_name_str) orelse1002 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 );
965 };1010 };
9661011
967 // Initialize the union from the given field.1012 // Initialize the union from the given field.
...@@ -972,7 +1017,7 @@ const Parser = struct {...@@ -972,7 +1017,7 @@ const Parser = struct {
972 return self.failNode(node, "expected union");1017 return self.failNode(node, "expected union");
9731018
974 // Instantiate the union1019 // Instantiate the union
975 return @unionInit(T, @"union".field_names[i], {});1020 out.* = @unionInit(@TypeOf(out.*), @"union".field_names[i], {});
976 },1021 },
977 else => unreachable, // Can't be out of bounds1022 else => unreachable, // Can't be out of bounds
978 }1023 }
...@@ -987,15 +1032,32 @@ const Parser = struct {...@@ -987,15 +1032,32 @@ const Parser = struct {
987 const field_name_str = field_name.get(self.zoir);1032 const field_name_str = field_name.get(self.zoir);
988 const field_val = struct_fields.vals.at(0);1033 const field_val = struct_fields.vals.at(0);
989 const field_index = field_indices.get(field_name_str) orelse1034 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
992 switch (field_index) {1037 switch (field_index) {
993 inline 0...@"union".field_names.len - 1 => |i| {1038 inline 0...@"union".field_names.len - 1 => |i| {
994 if (@"union".field_types[i] == void) {1039 if (@"union".field_types[i] == void) {
995 return self.failNode(field_val, "expected type 'void'");1040 return self.failNode(field_val, "expected type 'void'");
996 } else {1041 } else {
997 const value = try self.parseExpr(@"union".field_types[i], field_val);1042 const field_initialized = b: {
998 return @unionInit(T, @"union".field_names[i], value);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 );
999 }1061 }
1000 },1062 },
1001 else => unreachable, // Can't be out of bounds1063 else => unreachable, // Can't be out of bounds
...@@ -1006,41 +1068,37 @@ const Parser = struct {...@@ -1006,41 +1068,37 @@ const Parser = struct {
1006 }1068 }
10071069
1008 fn failTokenFmt(1070 fn failTokenFmt(
1009 self: @This(),1071 self: Parser,
1010 token: Ast.TokenIndex,1072 token: Ast.TokenIndex,
1011 offset: u32,1073 offset: u32,
1012 comptime fmt: []const u8,1074 comptime fmt: []const u8,
1013 args: anytype,1075 args: anytype,
1014 ) error{ OutOfMemory, ParseZon } {1076 ) error{ OutOfMemory, ParseZon } {
1015 @branchHint(.cold);1077 @branchHint(.cold);
1016 return self.failTokenFmtNote(token, offset, fmt, args, null);1078 return self.failTokenFmtNote(token, offset, fmt, args, &.{});
1017 }1079 }
10181080
1019 fn failTokenFmtNote(1081 fn failTokenFmtNote(
1020 self: @This(),1082 self: Parser,
1021 token: Ast.TokenIndex,1083 token: Ast.TokenIndex,
1022 offset: u32,1084 offset: u32,
1023 comptime fmt: []const u8,1085 comptime fmt: []const u8,
1024 args: anytype,1086 args: anytype,
1025 note: ?Error.TypeCheckFailure.Note,1087 notes: []Diagnostics.Note,
1026 ) error{ OutOfMemory, ParseZon } {1088 ) error{ OutOfMemory, ParseZon } {
1027 @branchHint(.cold);1089 @branchHint(.cold);
1028 comptime assert(args.len > 0);1090 comptime assert(args.len > 0);
1029 if (self.diag) |s| s.type_check = .{1091 try self.errors.append(self.arena, .init(self.ast, .{
1030 .token = token,1092 .token = .fromToken(token),
1031 .offset = offset,1093 .node_or_offset = offset,
1032 .message = std.fmt.allocPrint(self.gpa, fmt, args) catch |err| {1094 .msg = try std.fmt.allocPrint(self.arena, fmt, args),
1033 if (note) |n| n.deinit(self.gpa);1095 .notes = notes,
1034 return err;1096 }));
1035 },
1036 .owned = true,
1037 .note = note,
1038 };
1039 return error.ParseZon;1097 return error.ParseZon;
1040 }1098 }
10411099
1042 fn failNodeFmt(1100 fn failNodeFmt(
1043 self: @This(),1101 self: Parser,
1044 node: Zoir.Node.Index,1102 node: Zoir.Node.Index,
1045 comptime fmt: []const u8,1103 comptime fmt: []const u8,
1046 args: anytype,1104 args: anytype,
...@@ -1051,32 +1109,31 @@ const Parser = struct {...@@ -1051,32 +1109,31 @@ const Parser = struct {
1051 }1109 }
10521110
1053 fn failToken(1111 fn failToken(
1054 self: @This(),1112 self: Parser,
1055 failure: Error.TypeCheckFailure,1113 failure: Diagnostics.Error,
1056 ) error{ParseZon} {1114 ) error{ OutOfMemory, ParseZon } {
1057 @branchHint(.cold);1115 @branchHint(.cold);
1058 if (self.diag) |s| s.type_check = failure;1116 try self.errors.append(self.arena, failure);
1059 return error.ParseZon;1117 return error.ParseZon;
1060 }1118 }
10611119
1062 fn failNode(1120 fn failNode(
1063 self: @This(),1121 self: Parser,
1064 node: Zoir.Node.Index,1122 node: Zoir.Node.Index,
1065 message: []const u8,1123 msg: []const u8,
1066 ) error{ParseZon} {1124 ) error{ OutOfMemory, ParseZon } {
1067 @branchHint(.cold);1125 @branchHint(.cold);
1068 const token = self.ast.nodeMainToken(node.getAstNode(self.zoir));1126 const token = self.ast.nodeMainToken(node.getAstNode(self.zoir));
1069 return self.failToken(.{1127 return self.failToken(.init(self.ast, .{
1070 .token = token,1128 .token = .fromToken(token),
1071 .offset = 0,1129 .node_or_offset = 0,
1072 .message = message,1130 .msg = msg,
1073 .owned = false,1131 .notes = &.{},
1074 .note = null,1132 }));
1075 });
1076 }1133 }
10771134
1078 fn failCannotRepresent(1135 fn failCannotRepresent(
1079 self: @This(),1136 self: Parser,
1080 T: type,1137 T: type,
1081 node: Zoir.Node.Index,1138 node: Zoir.Node.Index,
1082 ) error{ OutOfMemory, ParseZon } {1139 ) error{ OutOfMemory, ParseZon } {
...@@ -1085,7 +1142,7 @@ const Parser = struct {...@@ -1085,7 +1142,7 @@ const Parser = struct {
1085 }1142 }
10861143
1087 fn failUnexpected(1144 fn failUnexpected(
1088 self: @This(),1145 self: Parser,
1089 T: type,1146 T: type,
1090 item_kind: []const u8,1147 item_kind: []const u8,
1091 node: Zoir.Node.Index,1148 node: Zoir.Node.Index,
...@@ -1093,8 +1150,6 @@ const Parser = struct {...@@ -1093,8 +1150,6 @@ const Parser = struct {
1093 name: []const u8,1150 name: []const u8,
1094 ) error{ OutOfMemory, ParseZon } {1151 ) error{ OutOfMemory, ParseZon } {
1095 @branchHint(.cold);1152 @branchHint(.cold);
1096 if (self.diag == null) return error.ParseZon;
1097 const gpa = self.gpa;
1098 const token = if (field) |f| b: {1153 const token = if (field) |f| b: {
1099 var buf: [2]Ast.Node.Index = undefined;1154 var buf: [2]Ast.Node.Index = undefined;
1100 const struct_init = self.ast.fullStructInit(&buf, node.getAstNode(self.zoir)).?;1155 const struct_init = self.ast.fullStructInit(&buf, node.getAstNode(self.zoir)).?;
...@@ -1103,38 +1158,35 @@ const Parser = struct {...@@ -1103,38 +1158,35 @@ const Parser = struct {
1103 } else self.ast.nodeMainToken(node.getAstNode(self.zoir));1158 } else self.ast.nodeMainToken(node.getAstNode(self.zoir));
1104 switch (@typeInfo(T)) {1159 switch (@typeInfo(T)) {
1105 inline .@"struct", .@"union", .@"enum" => |info| {1160 inline .@"struct", .@"union", .@"enum" => |info| {
1106 const note: Error.TypeCheckFailure.Note = if (info.field_names.len == 0) b: {1161 var notes: std.ArrayList(Diagnostics.Note) = .empty;
1107 break :b .{1162 if (info.field_names.len == 0) {
1108 .token = token,1163 try notes.append(self.arena, .init(self.ast, .{
1109 .offset = 0,1164 .token = .fromToken(token),
1165 .node_or_offset = 0,
1110 .msg = "none expected",1166 .msg = "none expected",
1111 .owned = false,1167 }));
1112 };1168 } else {
1113 } else b: {1169 var aw: std.Io.Writer.Allocating = .init(self.arena);
1114 const msg = "supported: ";1170 aw.writer.writeAll("supported: ") catch return error.OutOfMemory;
1115 var buf: std.ArrayList(u8) = try .initCapacity(gpa, 64);
1116 defer buf.deinit(gpa);
1117 try buf.appendSlice(gpa, msg);
1118 inline for (info.field_names, 0..) |field_name, i| {1171 inline for (info.field_names, 0..) |field_name, i| {
1119 if (i != 0) try buf.appendSlice(gpa, ", ");1172 if (i != 0) aw.writer.writeAll(", ") catch return error.OutOfMemory;
1120 try buf.print(gpa, "'{f}'", .{std.zig.fmtIdFlags(field_name, .{1173 aw.writer.print("'{f}'", .{std.zig.fmtIdFlags(field_name, .{
1121 .allow_primitive = true,1174 .allow_primitive = true,
1122 .allow_underscore = true,1175 .allow_underscore = true,
1123 })});1176 })}) catch return error.OutOfMemory;
1124 }1177 }
1125 break :b .{1178 try notes.append(self.arena, .init(self.ast, .{
1126 .token = token,1179 .token = .fromToken(token),
1127 .offset = 0,1180 .node_or_offset = 0,
1128 .msg = try buf.toOwnedSlice(gpa),1181 .msg = try aw.toOwnedSlice(),
1129 .owned = true,1182 }));
1130 };1183 }
1131 };
1132 return self.failTokenFmtNote(1184 return self.failTokenFmtNote(
1133 token,1185 token,
1134 0,1186 0,
1135 "unexpected {s} '{s}'",1187 "unexpected {s} '{s}'",
1136 .{ item_kind, name },1188 .{ item_kind, name },
1137 note,1189 notes.items,
1138 );1190 );
1139 },1191 },
1140 else => comptime unreachable,1192 else => comptime unreachable,
...@@ -1145,12 +1197,11 @@ const Parser = struct {...@@ -1145,12 +1197,11 @@ const Parser = struct {
1145 // the value matched, but doing so doesn't seem to support any real use cases1197 // the value matched, but doing so doesn't seem to support any real use cases
1146 // so isn't worth the complexity at the moment.1198 // so isn't worth the complexity at the moment.
1147 fn failComptimeField(1199 fn failComptimeField(
1148 self: @This(),1200 self: Parser,
1149 node: Zoir.Node.Index,1201 node: Zoir.Node.Index,
1150 field: usize,1202 field: usize,
1151 ) error{ OutOfMemory, ParseZon } {1203 ) error{ OutOfMemory, ParseZon } {
1152 @branchHint(.cold);1204 @branchHint(.cold);
1153 if (self.diag == null) return error.ParseZon;
1154 const ast_node = node.getAstNode(self.zoir);1205 const ast_node = node.getAstNode(self.zoir);
1155 var buf: [2]Ast.Node.Index = undefined;1206 var buf: [2]Ast.Node.Index = undefined;
1156 const token = if (self.ast.fullStructInit(&buf, ast_node)) |struct_init| b: {1207 const token = if (self.ast.fullStructInit(&buf, ast_node)) |struct_init| b: {
...@@ -1161,13 +1212,12 @@ const Parser = struct {...@@ -1161,13 +1212,12 @@ const Parser = struct {
1161 const value_node = array_init.ast.elements[field];1212 const value_node = array_init.ast.elements[field];
1162 break :b self.ast.firstToken(value_node);1213 break :b self.ast.firstToken(value_node);
1163 };1214 };
1164 return self.failToken(.{1215 return self.failToken(.init(self.ast, .{
1165 .token = token,1216 .token = .fromToken(token),
1166 .offset = 0,1217 .node_or_offset = 0,
1167 .message = "cannot initialize comptime field",1218 .msg = "cannot initialize comptime field",
1168 .owned = false,1219 .notes = &.{},
1169 .note = null,1220 }));
1170 });
1171 }1221 }
1172};1222};
11731223
...@@ -1329,106 +1379,198 @@ test "std.zon requiresAllocator" {...@@ -1329,106 +1379,198 @@ test "std.zon requiresAllocator" {
13291379
1330test "std.zon ast errors" {1380test "std.zon ast errors" {
1331 const gpa = std.testing.allocator;1381 const gpa = std.testing.allocator;
1332 var diag: Diagnostics = .{};1382 var arena_allocator: ArenaAllocator = .init(gpa);
1333 defer diag.deinit(gpa);1383 defer arena_allocator.deinit();
1384 const arena = arena_allocator.allocator();
1385 var diagnostics: Diagnostics = undefined;
1334 try std.testing.expectError(1386 try std.testing.expectError(
1335 error.ParseZon,1387 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 }),
1337 );1394 );
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")});
1339}1399}
13401400
1341test "std.zon comments" {1401test "std.zon comments" {
1342 const gpa = std.testing.allocator;1402 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 =
1345 \\// comment1412 \\// comment
1346 \\10 // comment1413 \\10 // comment
1347 \\// comment1414 \\// comment
1348 , null, .{}));1415 ,
1416 .diagnostics = &diagnostics,
1417 }));
13491418
1350 {1419 {
1351 var diag: Diagnostics = .{};1420 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
1352 defer diag.deinit(gpa);1421 .gpa = gpa,
1353 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa,1422 .arena = arena,
1423 .source =
1354 \\//! comment1424 \\//! comment
1355 \\10 // comment1425 \\10 // comment
1356 \\// comment1426 \\// comment
1357 , &diag, .{}));1427 ,
1428 .diagnostics = &diagnostics,
1429 }));
1358 try std.testing.expectFmt(1430 try std.testing.expectFmt(
1359 "1:1: error: expected expression, found 'a document comment'\n",1431 \\input.zon:1:1: error: expected expression, found 'a document comment'
1360 "{f}",1432 \\
1361 .{diag},1433 , "{f}", .{diagnostics.fmt("input.zon")});
1362 );
1363 }1434 }
1364}1435}
13651436
1366test "std.zon failure/oom formatting" {1437test "std.zon failure/oom formatting" {
1367 const gpa = std.testing.allocator;1438 const gpa = std.testing.allocator;
1368 var failing_allocator = std.testing.FailingAllocator.init(gpa, .{1439 var arena_allocator: ArenaAllocator = .init(gpa);
1369 .fail_index = 0,1440 defer arena_allocator.deinit();
1370 .resize_fail_index = 0,1441 const arena = arena_allocator.allocator();
1371 });1442 var diagnostics: Diagnostics = undefined;
1372 var diag: Diagnostics = .{};1443
1373 defer diag.deinit(gpa);1444 try std.testing.expectError(error.OutOfMemory, fromSlice([]const u8, .{
1374 try std.testing.expectError(error.OutOfMemory, fromSliceAlloc(1445 .gpa = .failing,
1375 []const u8,1446 .arena = arena,
1376 failing_allocator.allocator(),1447 .source = "\"foo\"",
1377 "\"foo\"",1448 .diagnostics = &diagnostics,
1378 &diag,1449 }));
1379 .{},1450 try std.testing.expectFmt(
1380 ));1451 \\
1381 try std.testing.expectFmt("", "{f}", .{diag});1452 , "{f}", .{diagnostics.fmt("input.zon")});
1382}1453}
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;
1385 try std.testing.expectError(1461 try std.testing.expectError(
1386 error.ParseZon,1462 error.ParseZon,
1387 fromSlice(u8, std.testing.allocator, ".{", null, .{}),1463 fromSliceNoAlloc(u8, .{
1464 .gpa = gpa,
1465 .arena = arena,
1466 .source = ".{",
1467 .diagnostics = &diagnostics,
1468 }),
1388 );1469 );
1470 try std.testing.expectFmt(
1471 \\input.zon:1:3: error: expected expression, found 'EOF'
1472 \\
1473 , "{f}", .{diagnostics.fmt("input.zon")});
1389}1474}
13901475
1391test "std.zon optional" {1476test "std.zon optional" {
1392 const gpa = std.testing.allocator;1477 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
1394 // Basic usage1483 // Basic usage
1395 {1484 {
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 });
1397 try std.testing.expect(none == null);1491 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 });
1399 try std.testing.expect(some.? == 1);1498 try std.testing.expect(some.? == 1);
1400 }1499 }
14011500
1402 // Deep free1501 // Deep free
1403 {1502 {
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 });
1405 try std.testing.expect(none == null);1509 try std.testing.expect(none == null);
1406 const some = try fromSliceAlloc(?[]const u8, gpa, "\"foo\"", null, .{});1510 const some = try fromSlice(?[]const u8, .{
1407 defer free(gpa, some);1511 .gpa = gpa,
1512 .arena = arena,
1513 .source = "\"foo\"",
1514 .diagnostics = &diagnostics,
1515 });
1408 try std.testing.expectEqualStrings("foo", some.?);1516 try std.testing.expectEqualStrings("foo", some.?);
1409 }1517 }
1410}1518}
14111519
1412test "std.zon unions" {1520test "std.zon unions" {
1413 const gpa = std.testing.allocator;1521 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
1415 // Unions1527 // Unions
1416 {1528 {
1417 const Tagged = union(enum) { x: f32, @"y y": bool, z, @"z z" };1529 const Tagged = union(enum) { x: f32, @"y y": bool, z, @"z z" };
1418 const Untagged = union { x: f32, @"y y": bool, z: void, @"z z": void };1530 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 });
1421 try std.testing.expectEqual(Tagged{ .x = 1.5 }, tagged_x);1538 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 });
1423 try std.testing.expectEqual(Tagged{ .@"y y" = true }, tagged_y);1545 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 });
1425 try std.testing.expectEqual(@as(Tagged, .z), tagged_z_shorthand);1552 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 });
1427 try std.testing.expectEqual(@as(Tagged, .@"z z"), tagged_zz_shorthand);1559 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 });
1430 try std.testing.expect(untagged_x.x == 1.5);1567 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 });
1432 try std.testing.expect(untagged_y.@"y y");1574 try std.testing.expect(untagged_y.@"y y");
1433 }1575 }
14341576
...@@ -1436,106 +1578,149 @@ test "std.zon unions" {...@@ -1436,106 +1578,149 @@ test "std.zon unions" {
1436 {1578 {
1437 const Union = union(enum) { bar: []const u8, baz: bool };1579 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 });
1440 try std.testing.expectEqual(Union{ .baz = false }, noalloc);1587 try std.testing.expectEqual(Union{ .baz = false }, noalloc);
14411588
1442 const alloc = try fromSliceAlloc(Union, gpa, ".{.bar = \"qux\"}", null, .{});1589 const alloc = try fromSlice(Union, .{
1443 defer free(gpa, alloc);1590 .gpa = gpa,
1591 .arena = arena,
1592 .source = ".{.bar = \"qux\"}",
1593 .diagnostics = &diagnostics,
1594 });
1444 try std.testing.expectEqualDeep(Union{ .bar = "qux" }, alloc);1595 try std.testing.expectEqualDeep(Union{ .bar = "qux" }, alloc);
1445 }1596 }
14461597
1447 // Unknown field1598 // Unknown field
1448 {1599 {
1449 const Union = union { x: f32, y: f32 };1600 const Union = union { x: f32, y: f32 };
1450 var diag: Diagnostics = .{};
1451 defer diag.deinit(gpa);
1452 try std.testing.expectError(1601 try std.testing.expectError(
1453 error.ParseZon,1602 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 }),
1455 );1609 );
1456 try std.testing.expectFmt(1610 try std.testing.expectFmt(
1457 \\1:4: error: unexpected field 'z'1611 \\input.zon:1:4: error: unexpected field 'z'
1458 \\1:4: note: supported: 'x', 'y'1612 \\input.zon:1:4: note: supported: 'x', 'y'
1459 \\1613 \\
1460 ,1614 , "{f}", .{diagnostics.fmt("input.zon")});
1461 "{f}",
1462 .{diag},
1463 );
1464 }1615 }
14651616
1466 // Explicit void field1617 // Explicit void field
1467 {1618 {
1468 const Union = union(enum) { x: void };1619 const Union = union(enum) { x: void };
1469 var diag: Diagnostics = .{};
1470 defer diag.deinit(gpa);
1471 try std.testing.expectError(1620 try std.testing.expectError(
1472 error.ParseZon,1621 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 }),
1474 );1628 );
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")});
1476 }1633 }
14771634
1478 // Extra field1635 // Extra field
1479 {1636 {
1480 const Union = union { x: f32, y: bool };1637 const Union = union { x: f32, y: bool };
1481 var diag: Diagnostics = .{};
1482 defer diag.deinit(gpa);
1483 try std.testing.expectError(1638 try std.testing.expectError(
1484 error.ParseZon,1639 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 }),
1486 );1646 );
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")});
1488 }1651 }
14891652
1490 // No fields1653 // No fields
1491 {1654 {
1492 const Union = union { x: f32, y: bool };1655 const Union = union { x: f32, y: bool };
1493 var diag: Diagnostics = .{};
1494 defer diag.deinit(gpa);
1495 try std.testing.expectError(1656 try std.testing.expectError(
1496 error.ParseZon,1657 error.ParseZon,
1497 fromSliceAlloc(Union, gpa, ".{}", &diag, .{}),1658 fromSlice(Union, .{
1659 .gpa = gpa,
1660 .arena = arena,
1661 .source = ".{}",
1662 .diagnostics = &diagnostics,
1663 }),
1498 );1664 );
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")});
1500 }1669 }
15011670
1502 // Enum literals cannot coerce into untagged unions1671 // Enum literals cannot coerce into untagged unions
1503 {1672 {
1504 const Union = union { x: void };1673 const Union = union { x: void };
1505 var diag: Diagnostics = .{};1674 try std.testing.expectError(error.ParseZon, fromSlice(Union, .{
1506 defer diag.deinit(gpa);1675 .gpa = gpa,
1507 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".x", &diag, .{}));1676 .arena = arena,
1508 try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});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")});
1509 }1684 }
15101685
1511 // Unknown field for enum literal coercion1686 // Unknown field for enum literal coercion
1512 {1687 {
1513 const Union = union(enum) { x: void };1688 const Union = union(enum) { x: void };
1514 var diag: Diagnostics = .{};1689 try std.testing.expectError(error.ParseZon, fromSlice(Union, .{
1515 defer diag.deinit(gpa);1690 .gpa = gpa,
1516 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".y", &diag, .{}));1691 .arena = arena,
1692 .source = ".y",
1693 .diagnostics = &diagnostics,
1694 }));
1517 try std.testing.expectFmt(1695 try std.testing.expectFmt(
1518 \\1:2: error: unexpected field 'y'1696 \\input.zon:1:2: error: unexpected field 'y'
1519 \\1:2: note: supported: 'x'1697 \\input.zon:1:2: note: supported: 'x'
1520 \\1698 \\
1521 ,1699 , "{f}", .{diagnostics.fmt("input.zon")});
1522 "{f}",
1523 .{diag},
1524 );
1525 }1700 }
15261701
1527 // Non void field for enum literal coercion1702 // Non void field for enum literal coercion
1528 {1703 {
1529 const Union = union(enum) { x: f32 };1704 const Union = union(enum) { x: f32 };
1530 var diag: Diagnostics = .{};1705 try std.testing.expectError(error.ParseZon, fromSlice(Union, .{
1531 defer diag.deinit(gpa);1706 .gpa = gpa,
1532 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".x", &diag, .{}));1707 .arena = arena,
1533 try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});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")});
1534 }1715 }
1535}1716}
15361717
1537test "std.zon structs" {1718test "std.zon structs" {
1538 const gpa = std.testing.allocator;1719 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
1540 // Structs (various sizes tested since they're parsed differently)1725 // Structs (various sizes tested since they're parsed differently)
1541 {1726 {
...@@ -1544,16 +1729,36 @@ test "std.zon structs" {...@@ -1544,16 +1729,36 @@ test "std.zon structs" {
1544 const Vec2 = struct { x: f32, y: f32 };1729 const Vec2 = struct { x: f32, y: f32 };
1545 const Vec3 = struct { x: f32, y: f32, z: f32 };1730 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 });
1548 try std.testing.expectEqual(Vec0{}, zero);1738 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 });
1551 try std.testing.expectEqual(Vec1{ .x = 1.2 }, one);1746 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 });
1554 try std.testing.expectEqual(Vec2{ .x = 1.2, .y = 3.4 }, two);1754 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 });
1557 try std.testing.expectEqual(Vec3{ .x = 1.2, .y = 3.4, .z = 5.6 }, three);1762 try std.testing.expectEqual(Vec3{ .x = 1.2, .y = 3.4, .z = 5.6 }, three);
1558 }1763 }
15591764
...@@ -1561,57 +1766,62 @@ test "std.zon structs" {...@@ -1561,57 +1766,62 @@ test "std.zon structs" {
1561 {1766 {
1562 const Foo = struct { bar: []const u8, baz: []const []const u8 };1767 const Foo = struct { bar: []const u8, baz: []const []const u8 };
15631768
1564 const parsed = try fromSliceAlloc(1769 const parsed = try fromSlice(Foo, .{
1565 Foo,1770 .gpa = gpa,
1566 gpa,1771 .arena = arena,
1567 ".{.bar = \"qux\", .baz = .{\"a\", \"b\"}}",1772 .source = ".{.bar = \"qux\", .baz = .{\"a\", \"b\"}}",
1568 null,1773 .diagnostics = &diagnostics,
1569 .{},1774 });
1570 );
1571 defer free(gpa, parsed);
1572 try std.testing.expectEqualDeep(Foo{ .bar = "qux", .baz = &.{ "a", "b" } }, parsed);1775 try std.testing.expectEqualDeep(Foo{ .bar = "qux", .baz = &.{ "a", "b" } }, parsed);
1573 }1776 }
15741777
1575 // Unknown field1778 // Unknown field
1576 {1779 {
1577 const Vec2 = struct { x: f32, y: f32 };1780 const Vec2 = struct { x: f32, y: f32 };
1578 var diag: Diagnostics = .{};
1579 defer diag.deinit(gpa);
1580 try std.testing.expectError(1781 try std.testing.expectError(
1581 error.ParseZon,1782 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 }),
1583 );1789 );
1584 try std.testing.expectFmt(1790 try std.testing.expectFmt(
1585 \\1:12: error: unexpected field 'z'1791 \\input.zon:1:12: error: unexpected field 'z'
1586 \\1:12: note: supported: 'x', 'y'1792 \\input.zon:1:12: note: supported: 'x', 'y'
1587 \\1793 \\
1588 ,1794 , "{f}", .{diagnostics.fmt("input.zon")});
1589 "{f}",
1590 .{diag},
1591 );
1592 }1795 }
15931796
1594 // Duplicate field1797 // Duplicate field
1595 {1798 {
1596 const Vec2 = struct { x: f32, y: f32 };1799 const Vec2 = struct { x: f32, y: f32 };
1597 var diag: Diagnostics = .{};
1598 defer diag.deinit(gpa);
1599 try std.testing.expectError(1800 try std.testing.expectError(
1600 error.ParseZon,1801 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 }),
1602 );1808 );
1603 try std.testing.expectFmt(1809 try std.testing.expectFmt(
1604 \\1:4: error: duplicate struct field name1810 \\input.zon:1:4: error: duplicate struct field name
1605 \\1:12: note: duplicate name here1811 \\input.zon:1:12: note: duplicate name here
1606 \\1812 \\
1607 , "{f}", .{diag});1813 , "{f}", .{diagnostics.fmt("input.zon")});
1608 }1814 }
16091815
1610 // Ignore unknown fields1816 // Ignore unknown fields
1611 {1817 {
1612 const Vec2 = struct { x: f32, y: f32 = 2.0 };1818 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 }",
1614 .ignore_unknown_fields = true,1823 .ignore_unknown_fields = true,
1824 .diagnostics = &diagnostics,
1615 });1825 });
1616 try std.testing.expectEqual(Vec2{ .x = 1.0, .y = 2.0 }, parsed);1826 try std.testing.expectEqual(Vec2{ .x = 1.0, .y = 2.0 }, parsed);
1617 }1827 }
...@@ -1619,70 +1829,102 @@ test "std.zon structs" {...@@ -1619,70 +1829,102 @@ test "std.zon structs" {
1619 // Unknown field when struct has no fields (regression test)1829 // Unknown field when struct has no fields (regression test)
1620 {1830 {
1621 const Vec2 = struct {};1831 const Vec2 = struct {};
1622 var diag: Diagnostics = .{};
1623 defer diag.deinit(gpa);
1624 try std.testing.expectError(1832 try std.testing.expectError(
1625 error.ParseZon,1833 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 }),
1627 );1840 );
1628 try std.testing.expectFmt(1841 try std.testing.expectFmt(
1629 \\1:4: error: unexpected field 'x'1842 \\input.zon:1:4: error: unexpected field 'x'
1630 \\1:4: note: none expected1843 \\input.zon:1:4: note: none expected
1631 \\1844 \\
1632 , "{f}", .{diag});1845 , "{f}", .{diagnostics.fmt("input.zon")});
1633 }1846 }
16341847
1635 // Missing field1848 // Missing field
1636 {1849 {
1637 const Vec2 = struct { x: f32, y: f32 };1850 const Vec2 = struct { x: f32, y: f32 };
1638 var diag: Diagnostics = .{};
1639 defer diag.deinit(gpa);
1640 try std.testing.expectError(1851 try std.testing.expectError(
1641 error.ParseZon,1852 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 }),
1643 );1859 );
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")});
1645 }1864 }
16461865
1647 // Default field1866 // Default field
1648 {1867 {
1649 const Vec2 = struct { x: f32, y: f32 = 1.5 };1868 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 });
1651 try std.testing.expectEqual(Vec2{ .x = 1.2, .y = 1.5 }, parsed);1875 try std.testing.expectEqual(Vec2{ .x = 1.2, .y = 1.5 }, parsed);
1652 }1876 }
16531877
1654 // Comptime field1878 // Comptime field
1655 {1879 {
1656 const Vec2 = struct { x: f32, comptime y: f32 = 1.5 };1880 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 });
1658 try std.testing.expectEqual(Vec2{ .x = 1.2, .y = 1.5 }, parsed);1887 try std.testing.expectEqual(Vec2{ .x = 1.2, .y = 1.5 }, parsed);
1659 }1888 }
16601889
1661 // Comptime field assignment1890 // Comptime field assignment
1662 {1891 {
1663 const Vec2 = struct { x: f32, comptime y: f32 = 1.5 };1892 const Vec2 = struct { x: f32, comptime y: f32 = 1.5 };
1664 var diag: Diagnostics = .{};1893 const parsed = fromSliceNoAlloc(Vec2, .{
1665 defer diag.deinit(gpa);1894 .gpa = gpa,
1666 const parsed = fromSlice(Vec2, gpa, ".{.x = 1.2, .y = 1.5}", &diag, .{});1895 .arena = arena,
1896 .source = ".{.x = 1.2, .y = 1.5}",
1897 .diagnostics = &diagnostics,
1898 });
1667 try std.testing.expectError(error.ParseZon, parsed);1899 try std.testing.expectError(error.ParseZon, parsed);
1668 try std.testing.expectFmt(1900 try std.testing.expectFmt(
1669 \\1:18: error: cannot initialize comptime field1901 \\input.zon:1:18: error: cannot initialize comptime field
1670 \\1902 \\
1671 , "{f}", .{diag});1903 , "{f}", .{diagnostics.fmt("input.zon")});
1672 }1904 }
16731905
1674 // Enum field (regression test, we were previously getting the field name in an1906 // Enum field (regression test, we were previously getting the field name in an
1675 // incorrect way that broke for enum values)1907 // incorrect way that broke for enum values)
1676 {1908 {
1677 const Vec0 = struct { x: enum { x } };1909 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 });
1679 try std.testing.expectEqual(Vec0{ .x = .x }, parsed);1916 try std.testing.expectEqual(Vec0{ .x = .x }, parsed);
1680 }1917 }
16811918
1682 // Enum field and struct field with @1919 // Enum field and struct field with @
1683 {1920 {
1684 const Vec0 = struct { @"x x": enum { @"x x" } };1921 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 });
1686 try std.testing.expectEqual(Vec0{ .@"x x" = .@"x x" }, parsed);1928 try std.testing.expectEqual(Vec0{ .@"x x" = .@"x x" }, parsed);
1687 }1929 }
16881930
...@@ -1690,79 +1932,92 @@ test "std.zon structs" {...@@ -1690,79 +1932,92 @@ test "std.zon structs" {
1690 {1932 {
1691 // Structs1933 // Structs
1692 {1934 {
1693 var diag: Diagnostics = .{};1935 const parsed = fromSliceNoAlloc(struct {}, .{
1694 defer diag.deinit(gpa);1936 .gpa = gpa,
1695 const parsed = fromSlice(struct {}, gpa, "Empty{}", &diag, .{});1937 .arena = arena,
1938 .source = "Empty{}",
1939 .diagnostics = &diagnostics,
1940 });
1696 try std.testing.expectError(error.ParseZon, parsed);1941 try std.testing.expectError(error.ParseZon, parsed);
1697 try std.testing.expectFmt(1942 try std.testing.expectFmt(
1698 \\1:1: error: types are not available in ZON1943 \\input.zon:1:1: error: types are not available in ZON
1699 \\1:1: note: replace the type with '.'1944 \\input.zon:1:1: note: replace the type with '.'
1700 \\1945 \\
1701 , "{f}", .{diag});1946 , "{f}", .{diagnostics.fmt("input.zon")});
1702 }1947 }
17031948
1704 // Arrays1949 // Arrays
1705 {1950 {
1706 var diag: Diagnostics = .{};1951 const parsed = fromSliceNoAlloc([3]u8, .{
1707 defer diag.deinit(gpa);1952 .gpa = gpa,
1708 const parsed = fromSlice([3]u8, gpa, "[3]u8{1, 2, 3}", &diag, .{});1953 .arena = arena,
1954 .source = "[3]u8{1, 2, 3}",
1955 .diagnostics = &diagnostics,
1956 });
1709 try std.testing.expectError(error.ParseZon, parsed);1957 try std.testing.expectError(error.ParseZon, parsed);
1710 try std.testing.expectFmt(1958 try std.testing.expectFmt(
1711 \\1:1: error: types are not available in ZON1959 \\input.zon:1:1: error: types are not available in ZON
1712 \\1:1: note: replace the type with '.'1960 \\input.zon:1:1: note: replace the type with '.'
1713 \\1961 \\
1714 , "{f}", .{diag});1962 , "{f}", .{diagnostics.fmt("input.zon")});
1715 }1963 }
17161964
1717 // Slices1965 // Slices
1718 {1966 {
1719 var diag: Diagnostics = .{};1967 const parsed = fromSlice([]u8, .{
1720 defer diag.deinit(gpa);1968 .gpa = gpa,
1721 const parsed = fromSliceAlloc([]u8, gpa, "[]u8{1, 2, 3}", &diag, .{});1969 .arena = arena,
1970 .source = "[]u8{1, 2, 3}",
1971 .diagnostics = &diagnostics,
1972 });
1722 try std.testing.expectError(error.ParseZon, parsed);1973 try std.testing.expectError(error.ParseZon, parsed);
1723 try std.testing.expectFmt(1974 try std.testing.expectFmt(
1724 \\1:1: error: types are not available in ZON1975 \\input.zon:1:1: error: types are not available in ZON
1725 \\1:1: note: replace the type with '.'1976 \\input.zon:1:1: note: replace the type with '.'
1726 \\1977 \\
1727 , "{f}", .{diag});1978 , "{f}", .{diagnostics.fmt("input.zon")});
1728 }1979 }
17291980
1730 // Tuples1981 // Tuples
1731 {1982 {
1732 var diag: Diagnostics = .{};1983 const parsed = fromSliceNoAlloc(struct { u8, u8, u8 }, .{
1733 defer diag.deinit(gpa);1984 .gpa = gpa,
1734 const parsed = fromSlice(1985 .arena = arena,
1735 struct { u8, u8, u8 },1986 .source = "Tuple{1, 2, 3}",
1736 gpa,1987 .diagnostics = &diagnostics,
1737 "Tuple{1, 2, 3}",1988 });
1738 &diag,
1739 .{},
1740 );
1741 try std.testing.expectError(error.ParseZon, parsed);1989 try std.testing.expectError(error.ParseZon, parsed);
1742 try std.testing.expectFmt(1990 try std.testing.expectFmt(
1743 \\1:1: error: types are not available in ZON1991 \\input.zon:1:1: error: types are not available in ZON
1744 \\1:1: note: replace the type with '.'1992 \\input.zon:1:1: note: replace the type with '.'
1745 \\1993 \\
1746 , "{f}", .{diag});1994 , "{f}", .{diagnostics.fmt("input.zon")});
1747 }1995 }
17481996
1749 // Nested1997 // Nested
1750 {1998 {
1751 var diag: Diagnostics = .{};1999 const parsed = fromSliceNoAlloc(struct {}, .{
1752 defer diag.deinit(gpa);2000 .gpa = gpa,
1753 const parsed = fromSlice(struct {}, gpa, ".{ .x = Tuple{1, 2, 3} }", &diag, .{});2001 .arena = arena,
2002 .source = ".{ .x = Tuple{1, 2, 3} }",
2003 .diagnostics = &diagnostics,
2004 });
1754 try std.testing.expectError(error.ParseZon, parsed);2005 try std.testing.expectError(error.ParseZon, parsed);
1755 try std.testing.expectFmt(2006 try std.testing.expectFmt(
1756 \\1:9: error: types are not available in ZON2007 \\input.zon:1:9: error: types are not available in ZON
1757 \\1:9: note: replace the type with '.'2008 \\input.zon:1:9: note: replace the type with '.'
1758 \\2009 \\
1759 , "{f}", .{diag});2010 , "{f}", .{diagnostics.fmt("input.zon")});
1760 }2011 }
1761 }2012 }
1762}2013}
17632014
1764test "std.zon tuples" {2015test "std.zon tuples" {
1765 const gpa = std.testing.allocator;2016 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
1767 // Structs (various sizes tested since they're parsed differently)2022 // Structs (various sizes tested since they're parsed differently)
1768 {2023 {
...@@ -1771,152 +2026,262 @@ test "std.zon tuples" {...@@ -1771,152 +2026,262 @@ test "std.zon tuples" {
1771 const Tuple2 = struct { f32, bool };2026 const Tuple2 = struct { f32, bool };
1772 const Tuple3 = struct { f32, bool, u8 };2027 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 });
1775 try std.testing.expectEqual(Tuple0{}, zero);2035 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 });
1778 try std.testing.expectEqual(Tuple1{1.2}, one);2043 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 });
1781 try std.testing.expectEqual(Tuple2{ 1.2, true }, two);2051 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 });
1784 try std.testing.expectEqual(Tuple3{ 1.2, false, 3 }, three);2059 try std.testing.expectEqual(Tuple3{ 1.2, false, 3 }, three);
1785 }2060 }
17862061
1787 // Deep free2062 // Deep free
1788 {2063 {
1789 const Tuple = struct { []const u8, []const u8 };2064 const Tuple = struct { []const u8, []const u8 };
1790 const parsed = try fromSliceAlloc(Tuple, gpa, ".{\"hello\", \"world\"}", null, .{});2065 const parsed = try fromSlice(Tuple, .{
1791 defer free(gpa, parsed);2066 .gpa = gpa,
2067 .arena = arena,
2068 .source = ".{\"hello\", \"world\"}",
2069 .diagnostics = &diagnostics,
2070 });
1792 try std.testing.expectEqualDeep(Tuple{ "hello", "world" }, parsed);2071 try std.testing.expectEqualDeep(Tuple{ "hello", "world" }, parsed);
1793 }2072 }
17942073
1795 // Extra field2074 // Extra field
1796 {2075 {
1797 const Tuple = struct { f32, bool };2076 const Tuple = struct { f32, bool };
1798 var diag: Diagnostics = .{};
1799 defer diag.deinit(gpa);
1800 try std.testing.expectError(2077 try std.testing.expectError(
1801 error.ParseZon,2078 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 }),
1803 );2085 );
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")});
1805 }2090 }
18062091
1807 // Extra field2092 // Extra field
1808 {2093 {
1809 const Tuple = struct { f32, bool };2094 const Tuple = struct { f32, bool };
1810 var diag: Diagnostics = .{};
1811 defer diag.deinit(gpa);
1812 try std.testing.expectError(2095 try std.testing.expectError(
1813 error.ParseZon,2096 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 }),
1815 );2103 );
1816 try std.testing.expectFmt(2104 try std.testing.expectFmt(
1817 "1:2: error: missing tuple field with index 1\n",2105 \\input.zon:1:2: error: missing tuple field with index 1
1818 "{f}",2106 \\
1819 .{diag},2107 , "{f}", .{diagnostics.fmt("input.zon")});
1820 );
1821 }2108 }
18222109
1823 // Tuple with unexpected field names2110 // Tuple with unexpected field names
1824 {2111 {
1825 const Tuple = struct { f32 };2112 const Tuple = struct { f32 };
1826 var diag: Diagnostics = .{};
1827 defer diag.deinit(gpa);
1828 try std.testing.expectError(2113 try std.testing.expectError(
1829 error.ParseZon,2114 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 }),
1831 );2121 );
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")});
1833 }2126 }
18342127
1835 // Struct with missing field names2128 // Struct with missing field names
1836 {2129 {
1837 const Struct = struct { foo: f32 };2130 const Struct = struct { foo: f32 };
1838 var diag: Diagnostics = .{};
1839 defer diag.deinit(gpa);
1840 try std.testing.expectError(2131 try std.testing.expectError(
1841 error.ParseZon,2132 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 }),
1843 );2139 );
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")});
1845 }2144 }
18462145
1847 // Comptime field2146 // Comptime field
1848 {2147 {
1849 const Vec2 = struct { f32, comptime f32 = 1.5 };2148 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 });
1851 try std.testing.expectEqual(Vec2{ 1.2, 1.5 }, parsed);2155 try std.testing.expectEqual(Vec2{ 1.2, 1.5 }, parsed);
1852 }2156 }
18532157
1854 // Comptime field assignment2158 // Comptime field assignment
1855 {2159 {
1856 const Vec2 = struct { f32, comptime f32 = 1.5 };2160 const Vec2 = struct { f32, comptime f32 = 1.5 };
1857 var diag: Diagnostics = .{};2161 const parsed = fromSliceNoAlloc(Vec2, .{
1858 defer diag.deinit(gpa);2162 .gpa = gpa,
1859 const parsed = fromSlice(Vec2, gpa, ".{ 1.2, 1.5}", &diag, .{});2163 .arena = arena,
2164 .source = ".{ 1.2, 1.5}",
2165 .diagnostics = &diagnostics,
2166 });
1860 try std.testing.expectError(error.ParseZon, parsed);2167 try std.testing.expectError(error.ParseZon, parsed);
1861 try std.testing.expectFmt(2168 try std.testing.expectFmt(
1862 \\1:9: error: cannot initialize comptime field2169 \\input.zon:1:9: error: cannot initialize comptime field
1863 \\2170 \\
1864 , "{f}", .{diag});2171 , "{f}", .{diagnostics.fmt("input.zon")});
1865 }2172 }
1866}2173}
18672174
1868// Test sizes 0 to 3 since small sizes get parsed differently2175// Test sizes 0 to 3 since small sizes get parsed differently
1869test "std.zon arrays and slices" {2176test "std.zon arrays and slices" {
1870 const gpa = std.testing.allocator;2177 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
1872 // Literals2183 // Literals
1873 {2184 {
1874 // Arrays2185 // Arrays
1875 {2186 {
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 });
1877 try std.testing.expectEqualSlices(u8, &@as([0]u8, .{}), &zero);2193 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 });
1880 try std.testing.expectEqualSlices(u8, &@as([1]u8, .{'a'}), &one);2201 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 });
1883 try std.testing.expectEqualSlices(u8, &@as([2]u8, .{ 'a', 'b' }), &two);2209 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 });
1886 try std.testing.expectEqualSlices(u8, &@as([2]u8, .{ 'a', 'b' }), &two_comma);2217 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 });
1889 try std.testing.expectEqualSlices(u8, &.{ 'a', 'b', 'c' }, &three);2225 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 });
1892 const expected_sentinel: [3:'z']u8 = .{ 'a', 'b', 'c' };2233 const expected_sentinel: [3:'z']u8 = .{ 'a', 'b', 'c' };
1893 try std.testing.expectEqualSlices(u8, &expected_sentinel, &sentinel);2234 try std.testing.expectEqualSlices(u8, &expected_sentinel, &sentinel);
1894 }2235 }
18952236
1896 // Slice literals2237 // Slice literals
1897 {2238 {
1898 const zero = try fromSliceAlloc([]const u8, gpa, ".{}", null, .{});2239 const zero = try fromSlice([]const u8, .{
1899 defer free(gpa, zero);2240 .gpa = gpa,
2241 .arena = arena,
2242 .source = ".{}",
2243 .diagnostics = &diagnostics,
2244 });
1900 try std.testing.expectEqualSlices(u8, @as([]const u8, &.{}), zero);2245 try std.testing.expectEqualSlices(u8, @as([]const u8, &.{}), zero);
19012246
1902 const one = try fromSliceAlloc([]u8, gpa, ".{'a'}", null, .{});2247 const one = try fromSlice([]u8, .{
1903 defer free(gpa, one);2248 .gpa = gpa,
2249 .arena = arena,
2250 .source = ".{'a'}",
2251 .diagnostics = &diagnostics,
2252 });
1904 try std.testing.expectEqualSlices(u8, &.{'a'}, one);2253 try std.testing.expectEqualSlices(u8, &.{'a'}, one);
19052254
1906 const two = try fromSliceAlloc([]const u8, gpa, ".{'a', 'b'}", null, .{});2255 const two = try fromSlice([]const u8, .{
1907 defer free(gpa, two);2256 .gpa = gpa,
2257 .arena = arena,
2258 .source = ".{'a', 'b'}",
2259 .diagnostics = &diagnostics,
2260 });
1908 try std.testing.expectEqualSlices(u8, &.{ 'a', 'b' }, two);2261 try std.testing.expectEqualSlices(u8, &.{ 'a', 'b' }, two);
19092262
1910 const two_comma = try fromSliceAlloc([]const u8, gpa, ".{'a', 'b',}", null, .{});2263 const two_comma = try fromSlice([]const u8, .{
1911 defer free(gpa, two_comma);2264 .gpa = gpa,
2265 .arena = arena,
2266 .source = ".{'a', 'b',}",
2267 .diagnostics = &diagnostics,
2268 });
1912 try std.testing.expectEqualSlices(u8, &.{ 'a', 'b' }, two_comma);2269 try std.testing.expectEqualSlices(u8, &.{ 'a', 'b' }, two_comma);
19132270
1914 const three = try fromSliceAlloc([]u8, gpa, ".{'a', 'b', 'c'}", null, .{});2271 const three = try fromSlice([]u8, .{
1915 defer free(gpa, three);2272 .gpa = gpa,
2273 .arena = arena,
2274 .source = ".{'a', 'b', 'c'}",
2275 .diagnostics = &diagnostics,
2276 });
1916 try std.testing.expectEqualSlices(u8, &.{ 'a', 'b', 'c' }, three);2277 try std.testing.expectEqualSlices(u8, &.{ 'a', 'b', 'c' }, three);
19172278
1918 const sentinel = try fromSliceAlloc([:'z']const u8, gpa, ".{'a', 'b', 'c'}", null, .{});2279 const sentinel = try fromSlice([:'z']const u8, .{
1919 defer free(gpa, sentinel);2280 .gpa = gpa,
2281 .arena = arena,
2282 .source = ".{'a', 'b', 'c'}",
2283 .diagnostics = &diagnostics,
2284 });
1920 const expected_sentinel: [:'z']const u8 = &.{ 'a', 'b', 'c' };2285 const expected_sentinel: [:'z']const u8 = &.{ 'a', 'b', 'c' };
1921 try std.testing.expectEqualSlices(u8, expected_sentinel, sentinel);2286 try std.testing.expectEqualSlices(u8, expected_sentinel, sentinel);
1922 }2287 }
...@@ -1926,16 +2291,24 @@ test "std.zon arrays and slices" {...@@ -1926,16 +2291,24 @@ test "std.zon arrays and slices" {
1926 {2291 {
1927 // Arrays2292 // Arrays
1928 {2293 {
1929 const parsed = try fromSliceAlloc([1][]const u8, gpa, ".{\"abc\"}", null, .{});2294 const parsed = try fromSlice([1][]const u8, .{
1930 defer free(gpa, parsed);2295 .gpa = gpa,
2296 .arena = arena,
2297 .source = ".{\"abc\"}",
2298 .diagnostics = &diagnostics,
2299 });
1931 const expected: [1][]const u8 = .{"abc"};2300 const expected: [1][]const u8 = .{"abc"};
1932 try std.testing.expectEqualDeep(expected, parsed);2301 try std.testing.expectEqualDeep(expected, parsed);
1933 }2302 }
19342303
1935 // Slice literals2304 // Slice literals
1936 {2305 {
1937 const parsed = try fromSliceAlloc([]const []const u8, gpa, ".{\"abc\"}", null, .{});2306 const parsed = try fromSlice([]const []const u8, .{
1938 defer free(gpa, parsed);2307 .gpa = gpa,
2308 .arena = arena,
2309 .source = ".{\"abc\"}",
2310 .diagnostics = &diagnostics,
2311 });
1939 const expected: []const []const u8 = &.{"abc"};2312 const expected: []const []const u8 = &.{"abc"};
1940 try std.testing.expectEqualDeep(expected, parsed);2313 try std.testing.expectEqualDeep(expected, parsed);
1941 }2314 }
...@@ -1945,7 +2318,12 @@ test "std.zon arrays and slices" {...@@ -1945,7 +2318,12 @@ test "std.zon arrays and slices" {
1945 {2318 {
1946 // Arrays2319 // Arrays
1947 {2320 {
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 });
1949 try std.testing.expectEqual(@as(usize, 1), sentinel.len);2327 try std.testing.expectEqual(@as(usize, 1), sentinel.len);
1950 try std.testing.expectEqual(@as(u8, 1), sentinel[0]);2328 try std.testing.expectEqual(@as(u8, 1), sentinel[0]);
1951 try std.testing.expectEqual(@as(u8, 2), sentinel[1]);2329 try std.testing.expectEqual(@as(u8, 2), sentinel[1]);
...@@ -1953,8 +2331,12 @@ test "std.zon arrays and slices" {...@@ -1953,8 +2331,12 @@ test "std.zon arrays and slices" {
19532331
1954 // Slice literals2332 // Slice literals
1955 {2333 {
1956 const sentinel = try fromSliceAlloc([:2]align(4) u8, gpa, ".{1}", null, .{});2334 const sentinel = try fromSlice([:2]align(4) u8, .{
1957 defer free(gpa, sentinel);2335 .gpa = gpa,
2336 .arena = arena,
2337 .source = ".{1}",
2338 .diagnostics = &diagnostics,
2339 });
1958 try std.testing.expectEqual(@as(usize, 1), sentinel.len);2340 try std.testing.expectEqual(@as(usize, 1), sentinel.len);
1959 try std.testing.expectEqual(@as(u8, 1), sentinel[0]);2341 try std.testing.expectEqual(@as(u8, 1), sentinel[0]);
1960 try std.testing.expectEqual(@as(u8, 2), sentinel[1]);2342 try std.testing.expectEqual(@as(u8, 2), sentinel[1]);
...@@ -1963,86 +2345,106 @@ test "std.zon arrays and slices" {...@@ -1963,86 +2345,106 @@ test "std.zon arrays and slices" {
19632345
1964 // Expect 0 find 32346 // Expect 0 find 3
1965 {2347 {
1966 var diag: Diagnostics = .{};
1967 defer diag.deinit(gpa);
1968 try std.testing.expectError(2348 try std.testing.expectError(
1969 error.ParseZon,2349 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 }),
1971 );2356 );
1972 try std.testing.expectFmt(2357 try std.testing.expectFmt(
1973 "1:3: error: index 0 outside of array of length 0\n",2358 \\input.zon:1:3: error: index 0 outside of array of length 0
1974 "{f}",2359 \\
1975 .{diag},2360 , "{f}", .{diagnostics.fmt("input.zon")});
1976 );
1977 }2361 }
19782362
1979 // Expect 1 find 22363 // Expect 1 find 2
1980 {2364 {
1981 var diag: Diagnostics = .{};
1982 defer diag.deinit(gpa);
1983 try std.testing.expectError(2365 try std.testing.expectError(
1984 error.ParseZon,2366 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 }),
1986 );2373 );
1987 try std.testing.expectFmt(2374 try std.testing.expectFmt(
1988 "1:8: error: index 1 outside of array of length 1\n",2375 \\input.zon:1:8: error: index 1 outside of array of length 1
1989 "{f}",2376 \\
1990 .{diag},2377 , "{f}", .{diagnostics.fmt("input.zon")});
1991 );
1992 }2378 }
19932379
1994 // Expect 2 find 12380 // Expect 2 find 1
1995 {2381 {
1996 var diag: Diagnostics = .{};
1997 defer diag.deinit(gpa);
1998 try std.testing.expectError(2382 try std.testing.expectError(
1999 error.ParseZon,2383 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 }),
2001 );2390 );
2002 try std.testing.expectFmt(2391 try std.testing.expectFmt(
2003 "1:2: error: expected 2 array elements; found 1\n",2392 \\input.zon:1:2: error: expected 2 array elements; found 1
2004 "{f}",2393 \\
2005 .{diag},2394 , "{f}", .{diagnostics.fmt("input.zon")});
2006 );
2007 }2395 }
20082396
2009 // Expect 3 find 02397 // Expect 3 find 0
2010 {2398 {
2011 var diag: Diagnostics = .{};
2012 defer diag.deinit(gpa);
2013 try std.testing.expectError(2399 try std.testing.expectError(
2014 error.ParseZon,2400 error.ParseZon,
2015 fromSlice([3]u8, gpa, ".{}", &diag, .{}),2401 fromSliceNoAlloc([3]u8, .{
2402 .gpa = gpa,
2403 .arena = arena,
2404 .source = ".{}",
2405 .diagnostics = &diagnostics,
2406 }),
2016 );2407 );
2017 try std.testing.expectFmt(2408 try std.testing.expectFmt(
2018 "1:2: error: expected 3 array elements; found 0\n",2409 \\input.zon:1:2: error: expected 3 array elements; found 0
2019 "{f}",2410 \\
2020 .{diag},2411 , "{f}", .{diagnostics.fmt("input.zon")});
2021 );
2022 }2412 }
20232413
2024 // Wrong inner type2414 // Wrong inner type
2025 {2415 {
2026 // Array2416 // Array
2027 {2417 {
2028 var diag: Diagnostics = .{};
2029 defer diag.deinit(gpa);
2030 try std.testing.expectError(2418 try std.testing.expectError(
2031 error.ParseZon,2419 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 }),
2033 );2426 );
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")});
2035 }2431 }
20362432
2037 // Slice2433 // Slice
2038 {2434 {
2039 var diag: Diagnostics = .{};
2040 defer diag.deinit(gpa);
2041 try std.testing.expectError(2435 try std.testing.expectError(
2042 error.ParseZon,2436 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 }),
2044 );2443 );
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")});
2046 }2448 }
2047 }2449 }
20482450
...@@ -2050,87 +2452,109 @@ test "std.zon arrays and slices" {...@@ -2050,87 +2452,109 @@ test "std.zon arrays and slices" {
2050 {2452 {
2051 // Array2453 // Array
2052 {2454 {
2053 var diag: Diagnostics = .{};
2054 defer diag.deinit(gpa);
2055 try std.testing.expectError(2455 try std.testing.expectError(
2056 error.ParseZon,2456 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 }),
2058 );2463 );
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")});
2060 }2468 }
20612469
2062 // Slice2470 // Slice
2063 {2471 {
2064 var diag: Diagnostics = .{};
2065 defer diag.deinit(gpa);
2066 try std.testing.expectError(2472 try std.testing.expectError(
2067 error.ParseZon,2473 error.ParseZon,
2068 fromSliceAlloc([]u8, gpa, "'a'", &diag, .{}),2474 fromSlice([]u8, .{ .gpa = gpa, .arena = arena, .source = "'a'", .diagnostics = &diagnostics }),
2069 );2475 );
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")});
2071 }2480 }
2072 }2481 }
20732482
2074 // Address of is not allowed (indirection for slices in ZON is implicit)2483 // Address of is not allowed (indirection for slices in ZON is implicit)
2075 {2484 {
2076 var diag: Diagnostics = .{};
2077 defer diag.deinit(gpa);
2078 try std.testing.expectError(2485 try std.testing.expectError(
2079 error.ParseZon,2486 error.ParseZon,
2080 fromSliceAlloc([]u8, gpa, " &.{'a', 'b', 'c'}", &diag, .{}),2487 fromSlice([]u8, .{ .gpa = gpa, .arena = arena, .source = " &.{'a', 'b', 'c'}", .diagnostics = &diagnostics }),
2081 );2488 );
2082 try std.testing.expectFmt(2489 try std.testing.expectFmt(
2083 "1:3: error: pointers are not available in ZON\n",2490 \\input.zon:1:3: error: pointers are not available in ZON
2084 "{f}",2491 \\
2085 .{diag},2492 , "{f}", .{diagnostics.fmt("input.zon")});
2086 );
2087 }2493 }
2088}2494}
20892495
2090test "std.zon string literal" {2496test "std.zon string literal" {
2091 const gpa = std.testing.allocator;2497 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
2093 // Basic string literal2503 // Basic string literal
2094 {2504 {
2095 const parsed = try fromSliceAlloc([]const u8, gpa, "\"abc\"", null, .{});2505 const parsed = try fromSlice([]const u8, .{
2096 defer free(gpa, parsed);2506 .gpa = gpa,
2507 .arena = arena,
2508 .source = "\"abc\"",
2509 .diagnostics = &diagnostics,
2510 });
2097 try std.testing.expectEqualStrings(@as([]const u8, "abc"), parsed);2511 try std.testing.expectEqualStrings(@as([]const u8, "abc"), parsed);
2098 }2512 }
20992513
2100 // String literal with escape characters2514 // String literal with escape characters
2101 {2515 {
2102 const parsed = try fromSliceAlloc([]const u8, gpa, "\"ab\\nc\"", null, .{});2516 const parsed = try fromSlice([]const u8, .{
2103 defer free(gpa, parsed);2517 .gpa = gpa,
2518 .arena = arena,
2519 .source = "\"ab\\nc\"",
2520 .diagnostics = &diagnostics,
2521 });
2104 try std.testing.expectEqualStrings(@as([]const u8, "ab\nc"), parsed);2522 try std.testing.expectEqualStrings(@as([]const u8, "ab\nc"), parsed);
2105 }2523 }
21062524
2107 // String literal with embedded null2525 // String literal with embedded null
2108 {2526 {
2109 const parsed = try fromSliceAlloc([]const u8, gpa, "\"ab\\x00c\"", null, .{});2527 const parsed = try fromSlice([]const u8, .{
2110 defer free(gpa, parsed);2528 .gpa = gpa,
2529 .arena = arena,
2530 .source = "\"ab\\x00c\"",
2531 .diagnostics = &diagnostics,
2532 });
2111 try std.testing.expectEqualStrings(@as([]const u8, "ab\x00c"), parsed);2533 try std.testing.expectEqualStrings(@as([]const u8, "ab\x00c"), parsed);
2112 }2534 }
21132535
2114 // Passing string literal to a mutable slice2536 // Passing string literal to a mutable slice
2115 {2537 {
2116 {2538 {
2117 var diag: Diagnostics = .{};
2118 defer diag.deinit(gpa);
2119 try std.testing.expectError(2539 try std.testing.expectError(
2120 error.ParseZon,2540 error.ParseZon,
2121 fromSliceAlloc([]u8, gpa, "\"abcd\"", &diag, .{}),2541 fromSlice([]u8, .{ .gpa = gpa, .arena = arena, .source = "\"abcd\"", .diagnostics = &diagnostics }),
2122 );2542 );
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")});
2124 }2547 }
21252548
2126 {2549 {
2127 var diag: Diagnostics = .{};
2128 defer diag.deinit(gpa);
2129 try std.testing.expectError(2550 try std.testing.expectError(
2130 error.ParseZon,2551 error.ParseZon,
2131 fromSliceAlloc([]u8, gpa, "\\\\abcd", &diag, .{}),2552 fromSlice([]u8, .{ .gpa = gpa, .arena = arena, .source = "\\\\abcd", .diagnostics = &diagnostics }),
2132 );2553 );
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")});
2134 }2558 }
2135 }2559 }
21362560
...@@ -2141,50 +2565,58 @@ test "std.zon string literal" {...@@ -2141,50 +2565,58 @@ test "std.zon string literal" {
2141 defer ast.deinit(gpa);2565 defer ast.deinit(gpa);
2142 var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false });2566 var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false });
2143 defer zoir.deinit(gpa);2567 defer zoir.deinit(gpa);
2144 var diag: Diagnostics = .{};
2145 defer diag.deinit(gpa);
2146 try std.testing.expectError(2568 try std.testing.expectError(
2147 error.ParseZon,2569 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 }),
2149 );2576 );
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")});
2151 }2581 }
21522582
2153 {2583 {
2154 var diag: Diagnostics = .{};
2155 defer diag.deinit(gpa);
2156 try std.testing.expectError(2584 try std.testing.expectError(
2157 error.ParseZon,2585 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 }),
2159 );2592 );
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")});
2161 }2597 }
2162 }2598 }
21632599
2164 // Zero terminated slices2600 // Zero terminated slices
2165 {2601 {
2166 {2602 {
2167 const parsed: [:0]const u8 = try fromSliceAlloc(2603 const parsed: [:0]const u8 = try fromSlice([:0]const u8, .{
2168 [:0]const u8,2604 .gpa = gpa,
2169 gpa,2605 .arena = arena,
2170 "\"abc\"",2606 .source = "\"abc\"",
2171 null,2607 .diagnostics = &diagnostics,
2172 .{},2608 });
2173 );
2174 defer free(gpa, parsed);
2175 try std.testing.expectEqualStrings("abc", parsed);2609 try std.testing.expectEqualStrings("abc", parsed);
2176 try std.testing.expectEqual(@as(u8, 0), parsed[3]);2610 try std.testing.expectEqual(@as(u8, 0), parsed[3]);
2177 }2611 }
21782612
2179 {2613 {
2180 const parsed: [:0]const u8 = try fromSliceAlloc(2614 const parsed: [:0]const u8 = try fromSlice([:0]const u8, .{
2181 [:0]const u8,2615 .gpa = gpa,
2182 gpa,2616 .arena = arena,
2183 "\\\\abc",2617 .source = "\\\\abc",
2184 null,2618 .diagnostics = &diagnostics,
2185 .{},2619 });
2186 );
2187 defer free(gpa, parsed);
2188 try std.testing.expectEqualStrings("abc", parsed);2620 try std.testing.expectEqualStrings("abc", parsed);
2189 try std.testing.expectEqual(@as(u8, 0), parsed[3]);2621 try std.testing.expectEqual(@as(u8, 0), parsed[3]);
2190 }2622 }
...@@ -2193,102 +2625,121 @@ test "std.zon string literal" {...@@ -2193,102 +2625,121 @@ test "std.zon string literal" {
2193 // Other value terminated slices2625 // Other value terminated slices
2194 {2626 {
2195 {2627 {
2196 var diag: Diagnostics = .{};
2197 defer diag.deinit(gpa);
2198 try std.testing.expectError(2628 try std.testing.expectError(
2199 error.ParseZon,2629 error.ParseZon,
2200 fromSliceAlloc([:1]const u8, gpa, "\"foo\"", &diag, .{}),2630 fromSlice([:1]const u8, .{ .gpa = gpa, .arena = arena, .source = "\"foo\"", .diagnostics = &diagnostics }),
2201 );2631 );
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")});
2203 }2636 }
22042637
2205 {2638 {
2206 var diag: Diagnostics = .{};
2207 defer diag.deinit(gpa);
2208 try std.testing.expectError(2639 try std.testing.expectError(
2209 error.ParseZon,2640 error.ParseZon,
2210 fromSliceAlloc([:1]const u8, gpa, "\\\\foo", &diag, .{}),2641 fromSlice([:1]const u8, .{ .gpa = gpa, .arena = arena, .source = "\\\\foo", .diagnostics = &diagnostics }),
2211 );2642 );
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")});
2213 }2647 }
2214 }2648 }
22152649
2216 // Expecting string literal, getting something else2650 // Expecting string literal, getting something else
2217 {2651 {
2218 var diag: Diagnostics = .{};
2219 defer diag.deinit(gpa);
2220 try std.testing.expectError(2652 try std.testing.expectError(
2221 error.ParseZon,2653 error.ParseZon,
2222 fromSliceAlloc([]const u8, gpa, "true", &diag, .{}),2654 fromSlice([]const u8, .{ .gpa = gpa, .arena = arena, .source = "true", .diagnostics = &diagnostics }),
2223 );2655 );
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")});
2225 }2660 }
22262661
2227 // Expecting string literal, getting an incompatible tuple2662 // Expecting string literal, getting an incompatible tuple
2228 {2663 {
2229 var diag: Diagnostics = .{};
2230 defer diag.deinit(gpa);
2231 try std.testing.expectError(2664 try std.testing.expectError(
2232 error.ParseZon,2665 error.ParseZon,
2233 fromSliceAlloc([]const u8, gpa, ".{false}", &diag, .{}),2666 fromSlice([]const u8, .{ .gpa = gpa, .arena = arena, .source = ".{false}", .diagnostics = &diagnostics }),
2234 );2667 );
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")});
2236 }2672 }
22372673
2238 // Invalid string literal2674 // Invalid string literal
2239 {2675 {
2240 var diag: Diagnostics = .{};
2241 defer diag.deinit(gpa);
2242 try std.testing.expectError(2676 try std.testing.expectError(
2243 error.ParseZon,2677 error.ParseZon,
2244 fromSliceAlloc([]const i8, gpa, "\"\\a\"", &diag, .{}),2678 fromSlice([]const i8, .{ .gpa = gpa, .arena = arena, .source = "\"\\a\"", .diagnostics = &diagnostics }),
2245 );2679 );
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")});
2247 }2684 }
22482685
2249 // Slice wrong child type2686 // Slice wrong child type
2250 {2687 {
2251 {2688 {
2252 var diag: Diagnostics = .{};
2253 defer diag.deinit(gpa);
2254 try std.testing.expectError(2689 try std.testing.expectError(
2255 error.ParseZon,2690 error.ParseZon,
2256 fromSliceAlloc([]const i8, gpa, "\"a\"", &diag, .{}),2691 fromSlice([]const i8, .{ .gpa = gpa, .arena = arena, .source = "\"a\"", .diagnostics = &diagnostics }),
2257 );2692 );
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")});
2259 }2697 }
22602698
2261 {2699 {
2262 var diag: Diagnostics = .{};
2263 defer diag.deinit(gpa);
2264 try std.testing.expectError(2700 try std.testing.expectError(
2265 error.ParseZon,2701 error.ParseZon,
2266 fromSliceAlloc([]const i8, gpa, "\\\\a", &diag, .{}),2702 fromSlice([]const i8, .{ .gpa = gpa, .arena = arena, .source = "\\\\a", .diagnostics = &diagnostics }),
2267 );2703 );
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")});
2269 }2708 }
2270 }2709 }
22712710
2272 // Bad alignment2711 // Bad alignment
2273 {2712 {
2274 {2713 {
2275 var diag: Diagnostics = .{};
2276 defer diag.deinit(gpa);
2277 try std.testing.expectError(2714 try std.testing.expectError(
2278 error.ParseZon,2715 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 }),
2280 );2722 );
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")});
2282 }2727 }
22832728
2284 {2729 {
2285 var diag: Diagnostics = .{};
2286 defer diag.deinit(gpa);
2287 try std.testing.expectError(2730 try std.testing.expectError(
2288 error.ParseZon,2731 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 }),
2290 );2738 );
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")});
2292 }2743 }
2293 }2744 }
22942745
...@@ -2301,7 +2752,10 @@ test "std.zon string literal" {...@@ -2301,7 +2752,10 @@ test "std.zon string literal" {
2301 message2: String,2752 message2: String,
2302 message3: String,2753 message3: String,
2303 };2754 };
2304 const parsed = try fromSliceAlloc(S, gpa,2755 const parsed = try fromSlice(S, .{
2756 .gpa = gpa,
2757 .arena = arena,
2758 .source =
2305 \\.{2759 \\.{
2306 \\ .message =2760 \\ .message =
2307 \\ \\hello, world!2761 \\ \\hello, world!
...@@ -2318,8 +2772,9 @@ test "std.zon string literal" {...@@ -2318,8 +2772,9 @@ test "std.zon string literal" {
2318 \\ \\2772 \\ \\
2319 \\ \\and this.2773 \\ \\and this.
2320 \\}2774 \\}
2321 , null, .{});2775 ,
2322 defer free(gpa, parsed);2776 .diagnostics = &diagnostics,
2777 });
2323 try std.testing.expectEqualStrings(2778 try std.testing.expectEqualStrings(
2324 "hello, world!\nthis is a multiline string!\n\n...",2779 "hello, world!\nthis is a multiline string!\n\n...",
2325 parsed.message,2780 parsed.message,
...@@ -2332,6 +2787,10 @@ test "std.zon string literal" {...@@ -2332,6 +2787,10 @@ test "std.zon string literal" {
23322787
2333test "std.zon enum literals" {2788test "std.zon enum literals" {
2334 const gpa = std.testing.allocator;2789 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
2336 const Enum = enum {2795 const Enum = enum {
2337 foo,2796 foo,
...@@ -2341,104 +2800,155 @@ test "std.zon enum literals" {...@@ -2341,104 +2800,155 @@ test "std.zon enum literals" {
2341 };2800 };
23422801
2343 // Tags that exist2802 // Tags that exist
2344 try std.testing.expectEqual(Enum.foo, try fromSlice(Enum, gpa, ".foo", null, .{}));2803 try std.testing.expectEqual(Enum.foo, try fromSliceNoAlloc(Enum, .{
2345 try std.testing.expectEqual(Enum.bar, try fromSlice(Enum, gpa, ".bar", null, .{}));2804 .gpa = gpa,
2346 try std.testing.expectEqual(Enum.baz, try fromSlice(Enum, gpa, ".baz", null, .{}));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 }));
2347 try std.testing.expectEqual(2821 try std.testing.expectEqual(
2348 Enum.@"ab\nc",2822 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 }),
2350 );2829 );
23512830
2352 // Bad tag2831 // Bad tag
2353 {2832 {
2354 var diag: Diagnostics = .{};
2355 defer diag.deinit(gpa);
2356 try std.testing.expectError(2833 try std.testing.expectError(
2357 error.ParseZon,2834 error.ParseZon,
2358 fromSlice(Enum, gpa, ".qux", &diag, .{}),2835 fromSliceNoAlloc(Enum, .{
2836 .gpa = gpa,
2837 .arena = arena,
2838 .source = ".qux",
2839 .diagnostics = &diagnostics,
2840 }),
2359 );2841 );
2360 try std.testing.expectFmt(2842 try std.testing.expectFmt(
2361 \\1:2: error: unexpected enum literal 'qux'2843 \\input.zon:1:2: error: unexpected enum literal 'qux'
2362 \\1:2: note: supported: 'foo', 'bar', 'baz', '@"ab\nc"'2844 \\input.zon:1:2: note: supported: 'foo', 'bar', 'baz', '@"ab\nc"'
2363 \\2845 \\
2364 ,2846 , "{f}", .{diagnostics.fmt("input.zon")});
2365 "{f}",
2366 .{diag},
2367 );
2368 }2847 }
23692848
2370 // Bad tag that's too long for parser2849 // Bad tag that's too long for parser
2371 {2850 {
2372 var diag: Diagnostics = .{};
2373 defer diag.deinit(gpa);
2374 try std.testing.expectError(2851 try std.testing.expectError(
2375 error.ParseZon,2852 error.ParseZon,
2376 fromSlice(Enum, gpa, ".@\"foobarbaz\"", &diag, .{}),2853 fromSliceNoAlloc(Enum, .{
2854 .gpa = gpa,
2855 .arena = arena,
2856 .source = ".@\"foobarbaz\"",
2857 .diagnostics = &diagnostics,
2858 }),
2377 );2859 );
2378 try std.testing.expectFmt(2860 try std.testing.expectFmt(
2379 \\1:2: error: unexpected enum literal 'foobarbaz'2861 \\input.zon:1:2: error: unexpected enum literal 'foobarbaz'
2380 \\1:2: note: supported: 'foo', 'bar', 'baz', '@"ab\nc"'2862 \\input.zon:1:2: note: supported: 'foo', 'bar', 'baz', '@"ab\nc"'
2381 \\2863 \\
2382 ,2864 , "{f}", .{diagnostics.fmt("input.zon")});
2383 "{f}",
2384 .{diag},
2385 );
2386 }2865 }
23872866
2388 // Bad type2867 // Bad type
2389 {2868 {
2390 var diag: Diagnostics = .{};
2391 defer diag.deinit(gpa);
2392 try std.testing.expectError(2869 try std.testing.expectError(
2393 error.ParseZon,2870 error.ParseZon,
2394 fromSlice(Enum, gpa, "true", &diag, .{}),2871 fromSliceNoAlloc(Enum, .{
2872 .gpa = gpa,
2873 .arena = arena,
2874 .source = "true",
2875 .diagnostics = &diagnostics,
2876 }),
2395 );2877 );
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")});
2397 }2882 }
23982883
2399 // Test embedded nulls in an identifier2884 // Test embedded nulls in an identifier
2400 {2885 {
2401 var diag: Diagnostics = .{};
2402 defer diag.deinit(gpa);
2403 try std.testing.expectError(2886 try std.testing.expectError(
2404 error.ParseZon,2887 error.ParseZon,
2405 fromSlice(Enum, gpa, ".@\"\\x00\"", &diag, .{}),2888 fromSliceNoAlloc(Enum, .{
2889 .gpa = gpa,
2890 .arena = arena,
2891 .source = ".@\"\\x00\"",
2892 .diagnostics = &diagnostics,
2893 }),
2406 );2894 );
2407 try std.testing.expectFmt(2895 try std.testing.expectFmt(
2408 "1:2: error: identifier cannot contain null bytes\n",2896 \\input.zon:1:2: error: identifier cannot contain null bytes
2409 "{f}",2897 \\
2410 .{diag},2898 , "{f}", .{diagnostics.fmt("input.zon")});
2411 );
2412 }2899 }
2413}2900}
24142901
2415test "std.zon parse bool" {2902test "std.zon parse bool" {
2416 const gpa = std.testing.allocator;2903 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
2418 // Correct bools2909 // Correct bools
2419 try std.testing.expectEqual(true, try fromSlice(bool, gpa, "true", null, .{}));2910 try std.testing.expectEqual(true, try fromSliceNoAlloc(bool, .{
2420 try std.testing.expectEqual(false, try fromSlice(bool, gpa, "false", null, .{}));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
2422 // Errors2923 // Errors
2423 {2924 {
2424 var diag: Diagnostics = .{};
2425 defer diag.deinit(gpa);
2426 try std.testing.expectError(2925 try std.testing.expectError(
2427 error.ParseZon,2926 error.ParseZon,
2428 fromSlice(bool, gpa, " foo", &diag, .{}),2927 fromSliceNoAlloc(bool, .{
2928 .gpa = gpa,
2929 .arena = arena,
2930 .source = " foo",
2931 .diagnostics = &diagnostics,
2932 }),
2429 );2933 );
2430 try std.testing.expectFmt(2934 try std.testing.expectFmt(
2431 \\1:2: error: invalid expression2935 \\input.zon:1:2: error: invalid expression
2432 \\1:2: note: ZON allows identifiers 'true', 'false', 'null', 'inf', and 'nan'2936 \\input.zon:1:2: note: ZON allows identifiers 'true', 'false', 'null', 'inf', and 'nan'
2433 \\1:2: note: precede identifier with '.' for an enum literal2937 \\input.zon:1:2: note: precede identifier with '.' for an enum literal
2434 \\2938 \\
2435 , "{f}", .{diag});2939 , "{f}", .{diagnostics.fmt("input.zon")});
2436 }2940 }
2437 {2941 {
2438 var diag: Diagnostics = .{};2942 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(bool, .{
2439 defer diag.deinit(gpa);2943 .gpa = gpa,
2440 try std.testing.expectError(error.ParseZon, fromSlice(bool, gpa, "123", &diag, .{}));2944 .arena = arena,
2441 try std.testing.expectFmt("1:1: error: expected type 'bool'\n", "{f}", .{diag});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")});
2442 }2952 }
2443}2953}
24442954
...@@ -2466,493 +2976,782 @@ test "std.zon intFromFloatExact" {...@@ -2466,493 +2976,782 @@ test "std.zon intFromFloatExact" {
24662976
2467test "std.zon parse int" {2977test "std.zon parse int" {
2468 const gpa = std.testing.allocator;2978 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
2470 // Test various numbers and types2984 // Test various numbers and types
2471 try std.testing.expectEqual(@as(u8, 10), try fromSlice(u8, gpa, "10", null, .{}));2985 try std.testing.expectEqual(@as(u8, 10), try fromSliceNoAlloc(u8, .{
2472 try std.testing.expectEqual(@as(i16, 24), try fromSlice(i16, gpa, "24", null, .{}));2986 .gpa = gpa,
2473 try std.testing.expectEqual(@as(i14, -4), try fromSlice(i14, gpa, "-4", null, .{}));2987 .arena = arena,
2474 try std.testing.expectEqual(@as(i32, -123), try fromSlice(i32, gpa, "-123", null, .{}));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
2476 // Test limits3010 // Test limits
2477 try std.testing.expectEqual(@as(i8, 127), try fromSlice(i8, gpa, "127", null, .{}));3011 try std.testing.expectEqual(@as(i8, 127), try fromSliceNoAlloc(i8, .{
2478 try std.testing.expectEqual(@as(i8, -128), try fromSlice(i8, gpa, "-128", null, .{}));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
2480 // Test characters3024 // Test characters
2481 try std.testing.expectEqual(@as(u8, 'a'), try fromSlice(u8, gpa, "'a'", null, .{}));3025 try std.testing.expectEqual(@as(u8, 'a'), try fromSliceNoAlloc(u8, .{
2482 try std.testing.expectEqual(@as(u8, 'z'), try fromSlice(u8, gpa, "'z'", null, .{}));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
2484 // Test big integers3038 // Test big integers
2485 try std.testing.expectEqual(3039 try std.testing.expectEqual(
2486 @as(u65, 36893488147419103231),3040 @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 }),
2488 );3047 );
2489 try std.testing.expectEqual(3048 try std.testing.expectEqual(
2490 @as(u65, 36893488147419103231),3049 @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 }),
2492 );3056 );
2493 try std.testing.expectEqual(3057 try std.testing.expectEqual(
2494 @as(u128, 340282366920938463463374607431768211455),3058 @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 }),
2496 );3065 );
24973066
2498 // Test big integer limits3067 // Test big integer limits
2499 try std.testing.expectEqual(3068 try std.testing.expectEqual(
2500 @as(i66, 36893488147419103231),3069 @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 }),
2502 );3076 );
2503 try std.testing.expectEqual(3077 try std.testing.expectEqual(
2504 @as(i66, -36893488147419103232),3078 @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 }),
2506 );3085 );
2507 {3086 {
2508 var diag: Diagnostics = .{};3087 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i66, .{
2509 defer diag.deinit(gpa);3088 .gpa = gpa,
2510 try std.testing.expectError(error.ParseZon, fromSlice(3089 .arena = arena,
2511 i66,3090 .source = "36893488147419103232",
2512 gpa,3091 .diagnostics = &diagnostics,
2513 "36893488147419103232",3092 }));
2514 &diag,3093 try std.testing.expectFmt(
2515 .{},3094 \\input.zon:1:1: error: type 'i66' cannot represent value
2516 ));3095 \\
2517 try std.testing.expectFmt(3096 , "{f}", .{diagnostics.fmt("input.zon")});
2518 "1:1: error: type 'i66' cannot represent value\n",
2519 "{f}",
2520 .{diag},
2521 );
2522 }3097 }
2523 {3098 {
2524 var diag: Diagnostics = .{};3099 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i66, .{
2525 defer diag.deinit(gpa);3100 .gpa = gpa,
2526 try std.testing.expectError(error.ParseZon, fromSlice(3101 .arena = arena,
2527 i66,3102 .source = "-36893488147419103233",
2528 gpa,3103 .diagnostics = &diagnostics,
2529 "-36893488147419103233",3104 }));
2530 &diag,
2531 .{},
2532 ));
2533 try std.testing.expectFmt(3105 try std.testing.expectFmt(
2534 "1:1: error: type 'i66' cannot represent value\n",3106 \\input.zon:1:1: error: type 'i66' cannot represent value
2535 "{f}",3107 \\
2536 .{diag},3108 , "{f}", .{diagnostics.fmt("input.zon")});
2537 );
2538 }3109 }
25393110
2540 // Test parsing whole number floats as integers3111 // Test parsing whole number floats as integers
2541 try std.testing.expectEqual(@as(i8, -1), try fromSlice(i8, gpa, "-1.0", null, .{}));3112 try std.testing.expectEqual(@as(i8, -1), try fromSliceNoAlloc(i8, .{
2542 try std.testing.expectEqual(@as(i8, 123), try fromSlice(i8, gpa, "123.0", null, .{}));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
2544 // Test non-decimal integers3125 // Test non-decimal integers
2545 try std.testing.expectEqual(@as(i16, 0xff), try fromSlice(i16, gpa, "0xff", null, .{}));3126 try std.testing.expectEqual(@as(i16, 0xff), try fromSliceNoAlloc(i16, .{
2546 try std.testing.expectEqual(@as(i16, -0xff), try fromSlice(i16, gpa, "-0xff", null, .{}));3127 .gpa = gpa,
2547 try std.testing.expectEqual(@as(i16, 0o77), try fromSlice(i16, gpa, "0o77", null, .{}));3128 .arena = arena,
2548 try std.testing.expectEqual(@as(i16, -0o77), try fromSlice(i16, gpa, "-0o77", null, .{}));3129 .source = "0xff",
2549 try std.testing.expectEqual(@as(i16, 0b11), try fromSlice(i16, gpa, "0b11", null, .{}));3130 .diagnostics = &diagnostics,
2550 try std.testing.expectEqual(@as(i16, -0b11), try fromSlice(i16, gpa, "-0b11", null, .{}));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
2552 // Test non-decimal big integers3163 // Test non-decimal big integers
2553 try std.testing.expectEqual(@as(u65, 0x1ffffffffffffffff), try fromSlice(3164 try std.testing.expectEqual(@as(u65, 0x1ffffffffffffffff), try fromSliceNoAlloc(u65, .{
2554 u65,3165 .gpa = gpa,
2555 gpa,3166 .arena = arena,
2556 "0x1ffffffffffffffff",3167 .source = "0x1ffffffffffffffff",
2557 null,3168 .diagnostics = &diagnostics,
2558 .{},3169 }));
2559 ));3170 try std.testing.expectEqual(@as(i66, 0x1ffffffffffffffff), try fromSliceNoAlloc(i66, .{
2560 try std.testing.expectEqual(@as(i66, 0x1ffffffffffffffff), try fromSlice(3171 .gpa = gpa,
2561 i66,3172 .arena = arena,
2562 gpa,3173 .source = "0x1ffffffffffffffff",
2563 "0x1ffffffffffffffff",3174 .diagnostics = &diagnostics,
2564 null,3175 }));
2565 .{},3176 try std.testing.expectEqual(@as(i66, -0x1ffffffffffffffff), try fromSliceNoAlloc(i66, .{
2566 ));3177 .gpa = gpa,
2567 try std.testing.expectEqual(@as(i66, -0x1ffffffffffffffff), try fromSlice(3178 .arena = arena,
2568 i66,3179 .source = "-0x1ffffffffffffffff",
2569 gpa,3180 .diagnostics = &diagnostics,
2570 "-0x1ffffffffffffffff",3181 }));
2571 null,3182 try std.testing.expectEqual(@as(u65, 0x1ffffffffffffffff), try fromSliceNoAlloc(u65, .{
2572 .{},3183 .gpa = gpa,
2573 ));3184 .arena = arena,
2574 try std.testing.expectEqual(@as(u65, 0x1ffffffffffffffff), try fromSlice(3185 .source = "0o3777777777777777777777",
2575 u65,3186 .diagnostics = &diagnostics,
2576 gpa,3187 }));
2577 "0o3777777777777777777777",3188 try std.testing.expectEqual(@as(i66, 0x1ffffffffffffffff), try fromSliceNoAlloc(i66, .{
2578 null,3189 .gpa = gpa,
2579 .{},3190 .arena = arena,
2580 ));3191 .source = "0o3777777777777777777777",
2581 try std.testing.expectEqual(@as(i66, 0x1ffffffffffffffff), try fromSlice(3192 .diagnostics = &diagnostics,
2582 i66,3193 }));
2583 gpa,3194 try std.testing.expectEqual(@as(i66, -0x1ffffffffffffffff), try fromSliceNoAlloc(i66, .{
2584 "0o3777777777777777777777",3195 .gpa = gpa,
2585 null,3196 .arena = arena,
2586 .{},3197 .source = "-0o3777777777777777777777",
2587 ));3198 .diagnostics = &diagnostics,
2588 try std.testing.expectEqual(@as(i66, -0x1ffffffffffffffff), try fromSlice(3199 }));
2589 i66,3200 try std.testing.expectEqual(@as(u65, 0x1ffffffffffffffff), try fromSliceNoAlloc(u65, .{
2590 gpa,3201 .gpa = gpa,
2591 "-0o3777777777777777777777",3202 .arena = arena,
2592 null,3203 .source = "0b11111111111111111111111111111111111111111111111111111111111111111",
2593 .{},3204 .diagnostics = &diagnostics,
2594 ));3205 }));
2595 try std.testing.expectEqual(@as(u65, 0x1ffffffffffffffff), try fromSlice(3206 try std.testing.expectEqual(@as(i66, 0x1ffffffffffffffff), try fromSliceNoAlloc(i66, .{
2596 u65,3207 .gpa = gpa,
2597 gpa,3208 .arena = arena,
2598 "0b11111111111111111111111111111111111111111111111111111111111111111",3209 .source = "0b11111111111111111111111111111111111111111111111111111111111111111",
2599 null,3210 .diagnostics = &diagnostics,
2600 .{},3211 }));
2601 ));3212 try std.testing.expectEqual(@as(i66, -0x1ffffffffffffffff), try fromSliceNoAlloc(i66, .{
2602 try std.testing.expectEqual(@as(i66, 0x1ffffffffffffffff), try fromSlice(3213 .gpa = gpa,
2603 i66,3214 .arena = arena,
2604 gpa,3215 .source = "-0b11111111111111111111111111111111111111111111111111111111111111111",
2605 "0b11111111111111111111111111111111111111111111111111111111111111111",3216 .diagnostics = &diagnostics,
2606 null,3217 }));
2607 .{},
2608 ));
2609 try std.testing.expectEqual(@as(i66, -0x1ffffffffffffffff), try fromSlice(
2610 i66,
2611 gpa,
2612 "-0b11111111111111111111111111111111111111111111111111111111111111111",
2613 null,
2614 .{},
2615 ));
26163218
2617 // Number with invalid character in the middle3219 // Number with invalid character in the middle
2618 {3220 {
2619 var diag: Diagnostics = .{};3221 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
2620 defer diag.deinit(gpa);3222 .gpa = gpa,
2621 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "32a32", &diag, .{}));3223 .arena = arena,
3224 .source = "32a32",
3225 .diagnostics = &diagnostics,
3226 }));
2622 try std.testing.expectFmt(3227 try std.testing.expectFmt(
2623 "1:3: error: invalid digit 'a' for decimal base\n",3228 \\input.zon:1:3: error: invalid digit 'a' for decimal base
2624 "{f}",3229 \\
2625 .{diag},3230 , "{f}", .{diagnostics.fmt("input.zon")});
2626 );
2627 }3231 }
26283232
2629 // Failing to parse as int3233 // Failing to parse as int
2630 {3234 {
2631 var diag: Diagnostics = .{};3235 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
2632 defer diag.deinit(gpa);3236 .gpa = gpa,
2633 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "true", &diag, .{}));3237 .arena = arena,
2634 try std.testing.expectFmt("1:1: error: expected type 'u8'\n", "{f}", .{diag});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")});
2635 }3245 }
26363246
2637 // Failing because an int is out of range3247 // Failing because an int is out of range
2638 {3248 {
2639 var diag: Diagnostics = .{};3249 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
2640 defer diag.deinit(gpa);3250 .gpa = gpa,
2641 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "256", &diag, .{}));3251 .arena = arena,
3252 .source = "256",
3253 .diagnostics = &diagnostics,
3254 }));
2642 try std.testing.expectFmt(3255 try std.testing.expectFmt(
2643 "1:1: error: type 'u8' cannot represent value\n",3256 \\input.zon:1:1: error: type 'u8' cannot represent value
2644 "{f}",3257 \\
2645 .{diag},3258 , "{f}", .{diagnostics.fmt("input.zon")});
2646 );
2647 }3259 }
26483260
2649 // Failing because a negative int is out of range3261 // Failing because a negative int is out of range
2650 {3262 {
2651 var diag: Diagnostics = .{};3263 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i8, .{
2652 defer diag.deinit(gpa);3264 .gpa = gpa,
2653 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "-129", &diag, .{}));3265 .arena = arena,
3266 .source = "-129",
3267 .diagnostics = &diagnostics,
3268 }));
2654 try std.testing.expectFmt(3269 try std.testing.expectFmt(
2655 "1:1: error: type 'i8' cannot represent value\n",3270 \\input.zon:1:1: error: type 'i8' cannot represent value
2656 "{f}",3271 \\
2657 .{diag},3272 , "{f}", .{diagnostics.fmt("input.zon")});
2658 );
2659 }3273 }
26603274
2661 // Failing because an unsigned int is negative3275 // Failing because an unsigned int is negative
2662 {3276 {
2663 var diag: Diagnostics = .{};3277 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
2664 defer diag.deinit(gpa);3278 .gpa = gpa,
2665 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "-1", &diag, .{}));3279 .arena = arena,
3280 .source = "-1",
3281 .diagnostics = &diagnostics,
3282 }));
2666 try std.testing.expectFmt(3283 try std.testing.expectFmt(
2667 "1:1: error: type 'u8' cannot represent value\n",3284 \\input.zon:1:1: error: type 'u8' cannot represent value
2668 "{f}",3285 \\
2669 .{diag},3286 , "{f}", .{diagnostics.fmt("input.zon")});
2670 );
2671 }3287 }
26723288
2673 // Failing because a float is non-whole3289 // Failing because a float is non-whole
2674 {3290 {
2675 var diag: Diagnostics = .{};3291 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
2676 defer diag.deinit(gpa);3292 .gpa = gpa,
2677 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "1.5", &diag, .{}));3293 .arena = arena,
3294 .source = "1.5",
3295 .diagnostics = &diagnostics,
3296 }));
2678 try std.testing.expectFmt(3297 try std.testing.expectFmt(
2679 "1:1: error: type 'u8' cannot represent value\n",3298 \\input.zon:1:1: error: type 'u8' cannot represent value
2680 "{f}",3299 \\
2681 .{diag},3300 , "{f}", .{diagnostics.fmt("input.zon")});
2682 );
2683 }3301 }
26843302
2685 // Failing because a float is negative3303 // Failing because a float is negative
2686 {3304 {
2687 var diag: Diagnostics = .{};3305 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
2688 defer diag.deinit(gpa);3306 .gpa = gpa,
2689 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "-1.0", &diag, .{}));3307 .arena = arena,
3308 .source = "-1.0",
3309 .diagnostics = &diagnostics,
3310 }));
2690 try std.testing.expectFmt(3311 try std.testing.expectFmt(
2691 "1:1: error: type 'u8' cannot represent value\n",3312 \\input.zon:1:1: error: type 'u8' cannot represent value
2692 "{f}",3313 \\
2693 .{diag},3314 , "{f}", .{diagnostics.fmt("input.zon")});
2694 );
2695 }3315 }
26963316
2697 // Negative integer zero3317 // Negative integer zero
2698 {3318 {
2699 var diag: Diagnostics = .{};3319 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i8, .{
2700 defer diag.deinit(gpa);3320 .gpa = gpa,
2701 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "-0", &diag, .{}));3321 .arena = arena,
3322 .source = "-0",
3323 .diagnostics = &diagnostics,
3324 }));
2702 try std.testing.expectFmt(3325 try std.testing.expectFmt(
2703 \\1:2: error: integer literal '-0' is ambiguous3326 \\input.zon:1:2: error: integer literal '-0' is ambiguous
2704 \\1:2: note: use '0' for an integer zero3327 \\input.zon:1:2: note: use '0' for an integer zero
2705 \\1:2: note: use '-0.0' for a floating-point signed zero3328 \\input.zon:1:2: note: use '-0.0' for a floating-point signed zero
2706 \\3329 \\
2707 , "{f}", .{diag});3330 , "{f}", .{diagnostics.fmt("input.zon")});
2708 }3331 }
27093332
2710 // Negative integer zero casted to float3333 // Negative integer zero casted to float
2711 {3334 {
2712 var diag: Diagnostics = .{};3335 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(f32, .{
2713 defer diag.deinit(gpa);3336 .gpa = gpa,
2714 try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-0", &diag, .{}));3337 .arena = arena,
3338 .source = "-0",
3339 .diagnostics = &diagnostics,
3340 }));
2715 try std.testing.expectFmt(3341 try std.testing.expectFmt(
2716 \\1:2: error: integer literal '-0' is ambiguous3342 \\input.zon:1:2: error: integer literal '-0' is ambiguous
2717 \\1:2: note: use '0' for an integer zero3343 \\input.zon:1:2: note: use '0' for an integer zero
2718 \\1:2: note: use '-0.0' for a floating-point signed zero3344 \\input.zon:1:2: note: use '-0.0' for a floating-point signed zero
2719 \\3345 \\
2720 , "{f}", .{diag});3346 , "{f}", .{diagnostics.fmt("input.zon")});
2721 }3347 }
27223348
2723 // Negative float 0 is allowed3349 // Negative float 0 is allowed
2724 try std.testing.expect(3350 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 })),
2726 );3357 );
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
2729 // Double negation is not allowed3365 // Double negation is not allowed
2730 {3366 {
2731 var diag: Diagnostics = .{};3367 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i8, .{
2732 defer diag.deinit(gpa);3368 .gpa = gpa,
2733 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "--2", &diag, .{}));3369 .arena = arena,
3370 .source = "--2",
3371 .diagnostics = &diagnostics,
3372 }));
2734 try std.testing.expectFmt(3373 try std.testing.expectFmt(
2735 "1:1: error: expected number or 'inf' after '-'\n",3374 \\input.zon:1:1: error: expected number or 'inf' after '-'
2736 "{f}",3375 \\
2737 .{diag},3376 , "{f}", .{diagnostics.fmt("input.zon")});
2738 );
2739 }3377 }
27403378
2741 {3379 {
2742 var diag: Diagnostics = .{};
2743 defer diag.deinit(gpa);
2744 try std.testing.expectError(3380 try std.testing.expectError(
2745 error.ParseZon,3381 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 }),
2747 );3388 );
2748 try std.testing.expectFmt(3389 try std.testing.expectFmt(
2749 "1:1: error: expected number or 'inf' after '-'\n",3390 \\input.zon:1:1: error: expected number or 'inf' after '-'
2750 "{f}",3391 \\
2751 .{diag},3392 , "{f}", .{diagnostics.fmt("input.zon")});
2752 );
2753 }3393 }
27543394
2755 // Invalid int literal3395 // Invalid int literal
2756 {3396 {
2757 var diag: Diagnostics = .{};3397 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
2758 defer diag.deinit(gpa);3398 .gpa = gpa,
2759 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "0xg", &diag, .{}));3399 .arena = arena,
2760 try std.testing.expectFmt("1:3: error: invalid digit 'g' for hex base\n", "{f}", .{diag});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")});
2761 }3407 }
27623408
2763 // Notes on invalid int literal3409 // Notes on invalid int literal
2764 {3410 {
2765 var diag: Diagnostics = .{};3411 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(u8, .{
2766 defer diag.deinit(gpa);3412 .gpa = gpa,
2767 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "0123", &diag, .{}));3413 .arena = arena,
3414 .source = "0123",
3415 .diagnostics = &diagnostics,
3416 }));
2768 try std.testing.expectFmt(3417 try std.testing.expectFmt(
2769 \\1:1: error: number '0123' has leading zero3418 \\input.zon:1:1: error: number '0123' has leading zero
2770 \\1:1: note: use '0o' prefix for octal literals3419 \\input.zon:1:1: note: use '0o' prefix for octal literals
2771 \\3420 \\
2772 , "{f}", .{diag});3421 , "{f}", .{diagnostics.fmt("input.zon")});
2773 }3422 }
2774}3423}
27753424
2776test "std.zon negative char" {3425test "std.zon negative char" {
2777 const gpa = std.testing.allocator;3426 const gpa = std.testing.allocator;
27783427 var arena_allocator: ArenaAllocator = .init(gpa);
2779 {3428 defer arena_allocator.deinit();
2780 var diag: Diagnostics = .{};3429 const arena = arena_allocator.allocator();
2781 defer diag.deinit(gpa);3430 var diagnostics: Diagnostics = undefined;
2782 try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-'a'", &diag, .{}));3431
3432 {
3433 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(f32, .{
3434 .gpa = gpa,
3435 .arena = arena,
3436 .source = "-'a'",
3437 .diagnostics = &diagnostics,
3438 }));
2783 try std.testing.expectFmt(3439 try std.testing.expectFmt(
2784 "1:1: error: expected number or 'inf' after '-'\n",3440 \\input.zon:1:1: error: expected number or 'inf' after '-'
2785 "{f}",3441 \\
2786 .{diag},3442 , "{f}", .{diagnostics.fmt("input.zon")});
2787 );
2788 }3443 }
2789 {3444 {
2790 var diag: Diagnostics = .{};3445 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i16, .{
2791 defer diag.deinit(gpa);3446 .gpa = gpa,
2792 try std.testing.expectError(error.ParseZon, fromSlice(i16, gpa, "-'a'", &diag, .{}));3447 .arena = arena,
3448 .source = "-'a'",
3449 .diagnostics = &diagnostics,
3450 }));
2793 try std.testing.expectFmt(3451 try std.testing.expectFmt(
2794 "1:1: error: expected number or 'inf' after '-'\n",3452 \\input.zon:1:1: error: expected number or 'inf' after '-'
2795 "{f}",3453 \\
2796 .{diag},3454 , "{f}", .{diagnostics.fmt("input.zon")});
2797 );
2798 }3455 }
2799}3456}
28003457
2801test "std.zon parse float" {3458test "std.zon parse float" {
3459 if (builtin.cpu.arch == .x86) return error.SkipZigTest;
3460
2802 const gpa = std.testing.allocator;3461 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
2804 // Test decimals3467 // 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 }));
2806 try std.testing.expectEqual(3474 try std.testing.expectEqual(
2807 @as(f32, 123.456),3475 @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 }),
2809 );3482 );
2810 try std.testing.expectEqual(3483 try std.testing.expectEqual(
2811 @as(f64, -123.456),3484 @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 }),
2813 );3491 );
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
2816 // Test whole numbers with and without decimals3499 // Test whole numbers with and without decimals
2817 try std.testing.expectEqual(@as(f16, 5.0), try fromSlice(f16, gpa, "5.0", null, .{}));3500 try std.testing.expectEqual(@as(f16, 5.0), try fromSliceNoAlloc(f16, .{
2818 try std.testing.expectEqual(@as(f16, 5.0), try fromSlice(f16, gpa, "5", null, .{}));3501 .gpa = gpa,
2819 try std.testing.expectEqual(@as(f32, -102), try fromSlice(f32, gpa, "-102.0", null, .{}));3502 .arena = arena,
2820 try std.testing.expectEqual(@as(f32, -102), try fromSlice(f32, gpa, "-102", null, .{}));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
2822 // Test characters and negated characters3525 // Test characters and negated characters
2823 try std.testing.expectEqual(@as(f32, 'a'), try fromSlice(f32, gpa, "'a'", null, .{}));3526 try std.testing.expectEqual(@as(f32, 'a'), try fromSliceNoAlloc(f32, .{
2824 try std.testing.expectEqual(@as(f32, 'z'), try fromSlice(f32, gpa, "'z'", null, .{}));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
2826 // Test big integers3539 // Test big integers
2827 try std.testing.expectEqual(3540 try std.testing.expectEqual(
2828 @as(f32, 36893488147419103231.0),3541 @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 }),
2830 );3548 );
2831 try std.testing.expectEqual(3549 try std.testing.expectEqual(
2832 @as(f32, -36893488147419103231.0),3550 @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 }),
2834 );3557 );
2835 try std.testing.expectEqual(@as(f128, 0x1ffffffffffffffff), try fromSlice(3558 try std.testing.expectEqual(@as(f128, 0x1ffffffffffffffff), try fromSliceNoAlloc(f128, .{
2836 f128,3559 .gpa = gpa,
2837 gpa,3560 .arena = arena,
2838 "0x1ffffffffffffffff",3561 .source = "0x1ffffffffffffffff",
2839 null,3562 .diagnostics = &diagnostics,
2840 .{},3563 }));
2841 ));3564 try std.testing.expectEqual(@as(f32, @floatFromInt(0x1ffffffffffffffff)), try fromSliceNoAlloc(f32, .{
2842 try std.testing.expectEqual(@as(f32, @floatFromInt(0x1ffffffffffffffff)), try fromSlice(3565 .gpa = gpa,
2843 f32,3566 .arena = arena,
2844 gpa,3567 .source = "0x1ffffffffffffffff",
2845 "0x1ffffffffffffffff",3568 .diagnostics = &diagnostics,
2846 null,3569 }));
2847 .{},
2848 ));
28493570
2850 // Exponents, underscores3571 // Exponents, underscores
2851 try std.testing.expectEqual(3572 try std.testing.expectEqual(
2852 @as(f32, 123.0E+77),3573 @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 }),
2854 );3580 );
28553581
2856 // Hexadecimal3582 // Hexadecimal
2857 try std.testing.expectEqual(3583 try std.testing.expectEqual(
2858 @as(f32, 0x103.70p-5),3584 @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 }),
2860 );3591 );
2861 try std.testing.expectEqual(3592 try std.testing.expectEqual(
2862 @as(f32, -0x103.70),3593 @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 }),
2864 );3600 );
2865 try std.testing.expectEqual(3601 try std.testing.expectEqual(
2866 @as(f32, 0x1234_5678.9ABC_CDEFp-10),3602 @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 }),
2868 );3609 );
28693610
2870 // inf, nan3611 // inf, nan
2871 try std.testing.expect(std.math.isPositiveInf(try fromSlice(f32, gpa, "inf", null, .{})));3612 try std.testing.expect(std.math.isPositiveInf(try fromSliceNoAlloc(f32, .{
2872 try std.testing.expect(std.math.isNegativeInf(try fromSlice(f32, gpa, "-inf", null, .{})));3613 .gpa = gpa,
2873 try std.testing.expect(std.math.isNan(try fromSlice(f32, gpa, "nan", null, .{})));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
2875 // Negative nan not allowed3631 // Negative nan not allowed
2876 {3632 {
2877 var diag: Diagnostics = .{};3633 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(f32, .{
2878 defer diag.deinit(gpa);3634 .gpa = gpa,
2879 try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-nan", &diag, .{}));3635 .arena = arena,
3636 .source = "-nan",
3637 .diagnostics = &diagnostics,
3638 }));
2880 try std.testing.expectFmt(3639 try std.testing.expectFmt(
2881 "1:1: error: expected number or 'inf' after '-'\n",3640 \\input.zon:1:1: error: expected number or 'inf' after '-'
2882 "{f}",3641 \\
2883 .{diag},3642 , "{f}", .{diagnostics.fmt("input.zon")});
2884 );
2885 }3643 }
28863644
2887 // nan as int not allowed3645 // nan as int not allowed
2888 {3646 {
2889 var diag: Diagnostics = .{};3647 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i8, .{
2890 defer diag.deinit(gpa);3648 .gpa = gpa,
2891 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "nan", &diag, .{}));3649 .arena = arena,
2892 try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag});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")});
2893 }3657 }
28943658
2895 // nan as int not allowed3659 // nan as int not allowed
2896 {3660 {
2897 var diag: Diagnostics = .{};3661 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i8, .{
2898 defer diag.deinit(gpa);3662 .gpa = gpa,
2899 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "nan", &diag, .{}));3663 .arena = arena,
2900 try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag});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")});
2901 }3671 }
29023672
2903 // inf as int not allowed3673 // inf as int not allowed
2904 {3674 {
2905 var diag: Diagnostics = .{};3675 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i8, .{
2906 defer diag.deinit(gpa);3676 .gpa = gpa,
2907 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "inf", &diag, .{}));3677 .arena = arena,
2908 try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag});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")});
2909 }3685 }
29103686
2911 // -inf as int not allowed3687 // -inf as int not allowed
2912 {3688 {
2913 var diag: Diagnostics = .{};3689 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(i8, .{
2914 defer diag.deinit(gpa);3690 .gpa = gpa,
2915 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "-inf", &diag, .{}));3691 .arena = arena,
2916 try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag});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")});
2917 }3699 }
29183700
2919 // Bad identifier as float3701 // Bad identifier as float
2920 {3702 {
2921 var diag: Diagnostics = .{};3703 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(f32, .{
2922 defer diag.deinit(gpa);3704 .gpa = gpa,
2923 try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "foo", &diag, .{}));3705 .arena = arena,
3706 .source = "foo",
3707 .diagnostics = &diagnostics,
3708 }));
2924 try std.testing.expectFmt(3709 try std.testing.expectFmt(
2925 \\1:1: error: invalid expression3710 \\input.zon:1:1: error: invalid expression
2926 \\1:1: note: ZON allows identifiers 'true', 'false', 'null', 'inf', and 'nan'3711 \\input.zon:1:1: note: ZON allows identifiers 'true', 'false', 'null', 'inf', and 'nan'
2927 \\1:1: note: precede identifier with '.' for an enum literal3712 \\input.zon:1:1: note: precede identifier with '.' for an enum literal
2928 \\3713 \\
2929 , "{f}", .{diag});3714 , "{f}", .{diagnostics.fmt("input.zon")});
2930 }3715 }
29313716
2932 {3717 {
2933 var diag: Diagnostics = .{};3718 try std.testing.expectError(error.ParseZon, fromSliceNoAlloc(f32, .{
2934 defer diag.deinit(gpa);3719 .gpa = gpa,
2935 try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-foo", &diag, .{}));3720 .arena = arena,
3721 .source = "-foo",
3722 .diagnostics = &diagnostics,
3723 }));
2936 try std.testing.expectFmt(3724 try std.testing.expectFmt(
2937 "1:1: error: expected number or 'inf' after '-'\n",3725 \\input.zon:1:1: error: expected number or 'inf' after '-'
2938 "{f}",3726 \\
2939 .{diag},3727 , "{f}", .{diagnostics.fmt("input.zon")});
2940 );
2941 }3728 }
29423729
2943 // Non float as float3730 // Non float as float
2944 {3731 {
2945 var diag: Diagnostics = .{};
2946 defer diag.deinit(gpa);
2947 try std.testing.expectError(3732 try std.testing.expectError(
2948 error.ParseZon,3733 error.ParseZon,
2949 fromSlice(f32, gpa, "\"foo\"", &diag, .{}),3734 fromSliceNoAlloc(f32, .{
3735 .gpa = gpa,
3736 .arena = arena,
3737 .source = "\"foo\"",
3738 .diagnostics = &diagnostics,
3739 }),
2950 );3740 );
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")});
2952 }3745 }
2953}3746}
29543747
2955test "std.zon free on error" {3748test "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
2956 // Test freeing partially allocated structs3755 // Test freeing partially allocated structs
2957 {3756 {
2958 const Struct = struct {3757 const Struct = struct {
...@@ -2960,13 +3759,18 @@ test "std.zon free on error" {...@@ -2960,13 +3759,18 @@ test "std.zon free on error" {
2960 y: []const u8,3759 y: []const u8,
2961 z: bool,3760 z: bool,
2962 };3761 };
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 =
2964 \\.{3766 \\.{
2965 \\ .x = "hello",3767 \\ .x = "hello",
2966 \\ .y = "world",3768 \\ .y = "world",
2967 \\ .z = "fail",3769 \\ .z = "fail",
2968 \\}3770 \\}
2969 , null, .{}));3771 ,
3772 .diagnostics = &diagnostics,
3773 }));
2970 }3774 }
29713775
2972 // Test freeing partially allocated tuples3776 // Test freeing partially allocated tuples
...@@ -2976,358 +3780,418 @@ test "std.zon free on error" {...@@ -2976,358 +3780,418 @@ test "std.zon free on error" {
2976 []const u8,3780 []const u8,
2977 bool,3781 bool,
2978 };3782 };
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 =
2980 \\.{3787 \\.{
2981 \\ "hello",3788 \\ "hello",
2982 \\ "world",3789 \\ "world",
2983 \\ "fail",3790 \\ "fail",
2984 \\}3791 \\}
2985 , null, .{}));3792 ,
3793 .diagnostics = &diagnostics,
3794 }));
2986 }3795 }
29873796
2988 // Test freeing structs with missing fields3797 // Test freeing structs with missing fields
2989 {3798 const Struct = struct {
2990 const Struct = struct {3799 x: []const u8,
2991 x: []const u8,3800 y: bool,
2992 y: bool,3801 };
2993 };3802 try std.testing.expectError(error.ParseZon, fromSlice(Struct, .{
2994 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, std.testing.allocator,3803 .gpa = gpa,
2995 \\.{3804 .arena = arena,
2996 \\ .x = "hello",3805 .source =
2997 \\}3806 \\.{
2998 , null, .{}));3807 \\ .x = "hello",
2999 }3808 \\}
3809 ,
3810 .diagnostics = &diagnostics,
3811 }));
30003812
3001 // Test freeing partially allocated arrays3813 // Test freeing partially allocated arrays
3002 {3814 try std.testing.expectError(error.ParseZon, fromSlice([3][]const u8, .{
3003 try std.testing.expectError(error.ParseZon, fromSliceAlloc(3815 .gpa = gpa,
3004 [3][]const u8,3816 .arena = arena,
3005 std.testing.allocator,3817 .source =
3006 \\.{3818 \\.{
3007 \\ "hello",3819 \\ "hello",
3008 \\ false,3820 \\ false,
3009 \\ false,3821 \\ false,
3010 \\}3822 \\}
3011 ,3823 ,
3012 null,3824 .diagnostics = &diagnostics,
3013 .{},3825 }));
3014 ));
3015 }
30163826
3017 // Test freeing partially allocated slices3827 // Test freeing partially allocated slices
3018 {3828 try std.testing.expectError(error.ParseZon, fromSlice([][]const u8, .{
3019 try std.testing.expectError(error.ParseZon, fromSliceAlloc(3829 .gpa = gpa,
3020 [][]const u8,3830 .arena = arena,
3021 std.testing.allocator,3831 .source =
3022 \\.{3832 \\.{
3023 \\ "hello",3833 \\ "hello",
3024 \\ "world",3834 \\ "world",
3025 \\ false,3835 \\ false,
3026 \\}3836 \\}
3027 ,3837 ,
3028 null,3838 .diagnostics = &diagnostics,
3029 .{},3839 }));
3030 ));
3031 }
30323840
3033 // We can parse types that can't be freed, as long as they contain no allocations, e.g. untagged3841 // We can parse types that can't be freed, as long as they contain no allocations, e.g. untagged
3034 // unions.3842 // unions.
3035 try std.testing.expectEqual(3843 try std.testing.expectEqual(
3036 @as(f32, 1.5),3844 @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,
3038 );3851 );
30393852
3040 // We can also parse types that can't be freed if it's impossible for an error to occur after3853 // We can also parse types that can't be freed if it's impossible for an error to occur after
3041 // the allocation, as is the case here.3854 // the allocation, as is the case here.
3042 {3855 {
3043 const result = try fromSliceAlloc(3856 const result = try fromSlice(union { x: []const u8 }, .{
3044 union { x: []const u8 },3857 .gpa = gpa,
3045 std.testing.allocator,3858 .arena = arena,
3046 ".{ .x = \"foo\" }",3859 .source = ".{ .x = \"foo\" }",
3047 null,3860 .diagnostics = &diagnostics,
3048 .{},3861 });
3049 );
3050 defer free(std.testing.allocator, result.x);
3051 try std.testing.expectEqualStrings("foo", result.x);3862 try std.testing.expectEqualStrings("foo", result.x);
3052 }3863 }
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 }
3130}3864}
31313865
3132test "std.zon vector" {3866test "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
3134 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .s390x) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/259573868 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .s390x) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/25957
31353869
3136 const gpa = std.testing.allocator;3870 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
3138 // Passing cases3876 // Passing cases
3139 try std.testing.expectEqual(3877 try std.testing.expectEqual(
3140 @Vector(0, bool){},3878 @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 }),
3142 );3885 );
3143 try std.testing.expectEqual(3886 try std.testing.expectEqual(
3144 @Vector(3, bool){ true, false, true },3887 @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 }),
3146 );3894 );
31473895
3148 try std.testing.expectEqual(3896 try std.testing.expectEqual(
3149 @Vector(0, f32){},3897 @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 }),
3151 );3904 );
3152 try std.testing.expectEqual(3905 try std.testing.expectEqual(
3153 @Vector(3, f32){ 1.5, 2.5, 3.5 },3906 @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 }),
3155 );3913 );
31563914
3157 try std.testing.expectEqual(3915 try std.testing.expectEqual(
3158 @Vector(0, u8){},3916 @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 }),
3160 );3923 );
3161 try std.testing.expectEqual(3924 try std.testing.expectEqual(
3162 @Vector(3, u8){ 2, 4, 6 },3925 @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 }),
3164 );3932 );
31653933
3166 {3934 {
3167 try std.testing.expectEqual(3935 try std.testing.expectEqual(
3168 @Vector(0, *const u8){},3936 @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 }),
3170 );3943 );
3171 const pointers = try fromSliceAlloc(@Vector(3, *const u8), gpa, ".{2, 4, 6}", null, .{});3944 const pointers = try fromSlice(@Vector(3, *const u8), .{
3172 defer free(gpa, pointers);3945 .gpa = gpa,
3946 .arena = arena,
3947 .source = ".{2, 4, 6}",
3948 .diagnostics = &diagnostics,
3949 });
3173 try std.testing.expectEqualDeep(@Vector(3, *const u8){ &2, &4, &6 }, pointers);3950 try std.testing.expectEqualDeep(@Vector(3, *const u8){ &2, &4, &6 }, pointers);
3174 }3951 }
31753952
3176 {3953 {
3177 try std.testing.expectEqual(3954 try std.testing.expectEqual(
3178 @Vector(0, ?*const u8){},3955 @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 }),
3180 );3962 );
3181 const pointers = try fromSliceAlloc(@Vector(3, ?*const u8), gpa, ".{2, null, 6}", null, .{});3963 const pointers = try fromSlice(@Vector(3, ?*const u8), .{
3182 defer free(gpa, pointers);3964 .gpa = gpa,
3965 .arena = arena,
3966 .source = ".{2, null, 6}",
3967 .diagnostics = &diagnostics,
3968 });
3183 try std.testing.expectEqualDeep(@Vector(3, ?*const u8){ &2, null, &6 }, pointers);3969 try std.testing.expectEqualDeep(@Vector(3, ?*const u8){ &2, null, &6 }, pointers);
3184 }3970 }
31853971
3186 // Too few fields3972 // Too few fields
3187 {3973 {
3188 var diag: Diagnostics = .{};
3189 defer diag.deinit(gpa);
3190 try std.testing.expectError(3974 try std.testing.expectError(
3191 error.ParseZon,3975 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 }),
3193 );3982 );
3194 try std.testing.expectFmt(3983 try std.testing.expectFmt(
3195 "1:2: error: expected 2 array elements; found 1\n",3984 \\input.zon:1:2: error: expected 2 array elements; found 1
3196 "{f}",3985 \\
3197 .{diag},3986 , "{f}", .{diagnostics.fmt("input.zon")});
3198 );
3199 }3987 }
32003988
3201 // Too many fields3989 // Too many fields
3202 {3990 {
3203 var diag: Diagnostics = .{};
3204 defer diag.deinit(gpa);
3205 try std.testing.expectError(3991 try std.testing.expectError(
3206 error.ParseZon,3992 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 }),
3208 );3999 );
3209 try std.testing.expectFmt(4000 try std.testing.expectFmt(
3210 "1:13: error: index 2 outside of array of length 2\n",4001 \\input.zon:1:13: error: index 2 outside of array of length 2
3211 "{f}",4002 \\
3212 .{diag},4003 , "{f}", .{diagnostics.fmt("input.zon")});
3213 );
3214 }4004 }
32154005
3216 // Wrong type fields4006 // Wrong type fields
3217 {4007 {
3218 var diag: Diagnostics = .{};
3219 defer diag.deinit(gpa);
3220 try std.testing.expectError(4008 try std.testing.expectError(
3221 error.ParseZon,4009 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 }),
3223 );4016 );
3224 try std.testing.expectFmt(4017 try std.testing.expectFmt(
3225 "1:8: error: expected type 'f32'\n",4018 \\input.zon:1:8: error: expected type 'f32'
3226 "{f}",4019 \\
3227 .{diag},4020 , "{f}", .{diagnostics.fmt("input.zon")});
3228 );
3229 }4021 }
32304022
3231 // Wrong type4023 // Wrong type
3232 {4024 {
3233 var diag: Diagnostics = .{};
3234 defer diag.deinit(gpa);
3235 try std.testing.expectError(4025 try std.testing.expectError(
3236 error.ParseZon,4026 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 }),
3238 );4033 );
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")});
3240 }4038 }
32414039
3242 // Elements should get freed on error4040 // Elements should get freed on error
3243 {4041 {
3244 var diag: Diagnostics = .{};
3245 defer diag.deinit(gpa);
3246 try std.testing.expectError(4042 try std.testing.expectError(
3247 error.ParseZon,4043 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 }),
3249 );4050 );
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")});
3251 }4055 }
3252}4056}
32534057
3254test "std.zon add pointers" {4058test "std.zon add pointers" {
3255 const gpa = std.testing.allocator;4059 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
3257 // Primitive with varying levels of pointers4065 // Primitive with varying levels of pointers
3258 {4066 {
3259 const result = try fromSliceAlloc(*u32, gpa, "10", null, .{});4067 const result = try fromSlice(*u32, .{
3260 defer free(gpa, result);4068 .gpa = gpa,
4069 .arena = arena,
4070 .source = "10",
4071 .diagnostics = &diagnostics,
4072 });
3261 try std.testing.expectEqual(@as(u32, 10), result.*);4073 try std.testing.expectEqual(@as(u32, 10), result.*);
3262 }4074 }
32634075
3264 {4076 {
3265 const result = try fromSliceAlloc(**u32, gpa, "10", null, .{});4077 const result = try fromSlice(**u32, .{
3266 defer free(gpa, result);4078 .gpa = gpa,
4079 .arena = arena,
4080 .source = "10",
4081 .diagnostics = &diagnostics,
4082 });
3267 try std.testing.expectEqual(@as(u32, 10), result.*.*);4083 try std.testing.expectEqual(@as(u32, 10), result.*.*);
3268 }4084 }
32694085
3270 {4086 {
3271 const result = try fromSliceAlloc(***u32, gpa, "10", null, .{});4087 const result = try fromSlice(***u32, .{
3272 defer free(gpa, result);4088 .gpa = gpa,
4089 .arena = arena,
4090 .source = "10",
4091 .diagnostics = &diagnostics,
4092 });
3273 try std.testing.expectEqual(@as(u32, 10), result.*.*.*);4093 try std.testing.expectEqual(@as(u32, 10), result.*.*.*);
3274 }4094 }
32754095
3276 // Primitive optional with varying levels of pointers4096 // Primitive optional with varying levels of pointers
3277 {4097 {
3278 const some = try fromSliceAlloc(?*u32, gpa, "10", null, .{});4098 const some = try fromSlice(?*u32, .{
3279 defer free(gpa, some);4099 .gpa = gpa,
4100 .arena = arena,
4101 .source = "10",
4102 .diagnostics = &diagnostics,
4103 });
3280 try std.testing.expectEqual(@as(u32, 10), some.?.*);4104 try std.testing.expectEqual(@as(u32, 10), some.?.*);
32814105
3282 const none = try fromSliceAlloc(?*u32, gpa, "null", null, .{});4106 const none = try fromSlice(?*u32, .{
3283 defer free(gpa, none);4107 .gpa = gpa,
4108 .arena = arena,
4109 .source = "null",
4110 .diagnostics = &diagnostics,
4111 });
3284 try std.testing.expectEqual(null, none);4112 try std.testing.expectEqual(null, none);
3285 }4113 }
32864114
3287 {4115 {
3288 const some = try fromSliceAlloc(*?u32, gpa, "10", null, .{});4116 const some = try fromSlice(*?u32, .{
3289 defer free(gpa, some);4117 .gpa = gpa,
4118 .arena = arena,
4119 .source = "10",
4120 .diagnostics = &diagnostics,
4121 });
3290 try std.testing.expectEqual(@as(u32, 10), some.*.?);4122 try std.testing.expectEqual(@as(u32, 10), some.*.?);
32914123
3292 const none = try fromSliceAlloc(*?u32, gpa, "null", null, .{});4124 const none = try fromSlice(*?u32, .{
3293 defer free(gpa, none);4125 .gpa = gpa,
4126 .arena = arena,
4127 .source = "null",
4128 .diagnostics = &diagnostics,
4129 });
3294 try std.testing.expectEqual(null, none.*);4130 try std.testing.expectEqual(null, none.*);
3295 }4131 }
32964132
3297 {4133 {
3298 const some = try fromSliceAlloc(?**u32, gpa, "10", null, .{});4134 const some = try fromSlice(?**u32, .{
3299 defer free(gpa, some);4135 .gpa = gpa,
4136 .arena = arena,
4137 .source = "10",
4138 .diagnostics = &diagnostics,
4139 });
3300 try std.testing.expectEqual(@as(u32, 10), some.?.*.*);4140 try std.testing.expectEqual(@as(u32, 10), some.?.*.*);
33014141
3302 const none = try fromSliceAlloc(?**u32, gpa, "null", null, .{});4142 const none = try fromSlice(?**u32, .{
3303 defer free(gpa, none);4143 .gpa = gpa,
4144 .arena = arena,
4145 .source = "null",
4146 .diagnostics = &diagnostics,
4147 });
3304 try std.testing.expectEqual(null, none);4148 try std.testing.expectEqual(null, none);
3305 }4149 }
33064150
3307 {4151 {
3308 const some = try fromSliceAlloc(*?*u32, gpa, "10", null, .{});4152 const some = try fromSlice(*?*u32, .{
3309 defer free(gpa, some);4153 .gpa = gpa,
4154 .arena = arena,
4155 .source = "10",
4156 .diagnostics = &diagnostics,
4157 });
3310 try std.testing.expectEqual(@as(u32, 10), some.*.?.*);4158 try std.testing.expectEqual(@as(u32, 10), some.*.?.*);
33114159
3312 const none = try fromSliceAlloc(*?*u32, gpa, "null", null, .{});4160 const none = try fromSlice(*?*u32, .{
3313 defer free(gpa, none);4161 .gpa = gpa,
4162 .arena = arena,
4163 .source = "null",
4164 .diagnostics = &diagnostics,
4165 });
3314 try std.testing.expectEqual(null, none.*);4166 try std.testing.expectEqual(null, none.*);
3315 }4167 }
33164168
3317 {4169 {
3318 const some = try fromSliceAlloc(**?u32, gpa, "10", null, .{});4170 const some = try fromSlice(**?u32, .{
3319 defer free(gpa, some);4171 .gpa = gpa,
4172 .arena = arena,
4173 .source = "10",
4174 .diagnostics = &diagnostics,
4175 });
3320 try std.testing.expectEqual(@as(u32, 10), some.*.*.?);4176 try std.testing.expectEqual(@as(u32, 10), some.*.*.?);
33214177
3322 const none = try fromSliceAlloc(**?u32, gpa, "null", null, .{});4178 const none = try fromSlice(**?u32, .{
3323 defer free(gpa, none);4179 .gpa = gpa,
4180 .arena = arena,
4181 .source = "null",
4182 .diagnostics = &diagnostics,
4183 });
3324 try std.testing.expectEqual(null, none.*.*);4184 try std.testing.expectEqual(null, none.*.*);
3325 }4185 }
33264186
3327 // Pointer to an array4187 // Pointer to an array
3328 {4188 {
3329 const result = try fromSliceAlloc(*[3]u8, gpa, ".{ 1, 2, 3 }", null, .{});4189 const result = try fromSlice(*[3]u8, .{
3330 defer free(gpa, result);4190 .gpa = gpa,
4191 .arena = arena,
4192 .source = ".{ 1, 2, 3 }",
4193 .diagnostics = &diagnostics,
4194 });
3331 try std.testing.expectEqual([3]u8{ 1, 2, 3 }, result.*);4195 try std.testing.expectEqual([3]u8{ 1, 2, 3 }, result.*);
3332 }4196 }
33334197
...@@ -3349,7 +4213,10 @@ test "std.zon add pointers" {...@@ -3349,7 +4213,10 @@ test "std.zon add pointers" {
3349 .f2 = &null,4213 .f2 = &null,
3350 };4214 };
33514215
3352 const found = try fromSliceAlloc(?*Outer, gpa,4216 const found = try fromSlice(?*Outer, .{
4217 .gpa = gpa,
4218 .arena = arena,
4219 .source =
3353 \\.{4220 \\.{
3354 \\ .f1 = .{4221 \\ .f1 = .{
3355 \\ .f1 = null,4222 \\ .f1 = null,
...@@ -3357,146 +4224,229 @@ test "std.zon add pointers" {...@@ -3357,146 +4224,229 @@ test "std.zon add pointers" {
3357 \\ },4224 \\ },
3358 \\ .f2 = null,4225 \\ .f2 = null,
3359 \\}4226 \\}
3360 , null, .{});4227 ,
3361 defer free(gpa, found);4228 .diagnostics = &diagnostics,
4229 });
33624230
3363 try std.testing.expectEqualDeep(expected, found.?.*);4231 try std.testing.expectEqualDeep(expected, found.?.*);
3364 }4232 }
33654233
3366 // Test that optional types are flattened correctly in errors4234 // Test that optional types are flattened correctly in errors
3367 {4235 {
3368 var diag: Diagnostics = .{};
3369 defer diag.deinit(gpa);
3370 try std.testing.expectError(4236 try std.testing.expectError(
3371 error.ParseZon,4237 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 }),
3373 );4244 );
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")});
3375 }4249 }
33764250
3377 {4251 {
3378 var diag: Diagnostics = .{};
3379 defer diag.deinit(gpa);
3380 try std.testing.expectError(4252 try std.testing.expectError(
3381 error.ParseZon,4253 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 }),
3383 );4260 );
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")});
3385 }4265 }
33864266
3387 {4267 {
3388 var diag: Diagnostics = .{};
3389 defer diag.deinit(gpa);
3390 try std.testing.expectError(4268 try std.testing.expectError(
3391 error.ParseZon,4269 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 }),
3393 );4276 );
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")});
3395 }4281 }
33964282
3397 {4283 {
3398 var diag: Diagnostics = .{};
3399 defer diag.deinit(gpa);
3400 try std.testing.expectError(4284 try std.testing.expectError(
3401 error.ParseZon,4285 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 }),
3403 );4292 );
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")});
3405 }4297 }
34064298
3407 {4299 {
3408 var diag: Diagnostics = .{};
3409 defer diag.deinit(gpa);
3410 try std.testing.expectError(4300 try std.testing.expectError(
3411 error.ParseZon,4301 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 }),
3413 );4308 );
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")});
3415 }4313 }
34164314
3417 {4315 {
3418 var diag: Diagnostics = .{};
3419 defer diag.deinit(gpa);
3420 try std.testing.expectError(4316 try std.testing.expectError(
3421 error.ParseZon,4317 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 }),
3423 );4324 );
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")});
3425 }4329 }
34264330
3427 {4331 {
3428 var diag: Diagnostics = .{};
3429 defer diag.deinit(gpa);
3430 try std.testing.expectError(4332 try std.testing.expectError(
3431 error.ParseZon,4333 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 }),
3433 );4340 );
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")});
3435 }4345 }
34364346
3437 {4347 {
3438 var diag: Diagnostics = .{};
3439 defer diag.deinit(gpa);
3440 try std.testing.expectError(4348 try std.testing.expectError(
3441 error.ParseZon,4349 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 }),
3443 );4356 );
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")});
3445 }4361 }
34464362
3447 {4363 {
3448 var diag: Diagnostics = .{};
3449 defer diag.deinit(gpa);
3450 try std.testing.expectError(4364 try std.testing.expectError(
3451 error.ParseZon,4365 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 }),
3453 );4372 );
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")});
3455 }4377 }
34564378
3457 {4379 {
3458 var diag: Diagnostics = .{};
3459 defer diag.deinit(gpa);
3460 try std.testing.expectError(4380 try std.testing.expectError(
3461 error.ParseZon,4381 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 }),
3463 );4388 );
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")});
3465 }4393 }
34664394
3467 {4395 {
3468 var diag: Diagnostics = .{};
3469 defer diag.deinit(gpa);
3470 try std.testing.expectError(4396 try std.testing.expectError(
3471 error.ParseZon,4397 error.ParseZon,
3472 fromSliceAlloc(?[]u8, gpa, "true", &diag, .{}),4398 fromSlice(?[]u8, .{
4399 .gpa = gpa,
4400 .arena = arena,
4401 .source = "true",
4402 .diagnostics = &diagnostics,
4403 }),
3473 );4404 );
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")});
3475 }4409 }
34764410
3477 {4411 {
3478 var diag: Diagnostics = .{};
3479 defer diag.deinit(gpa);
3480 try std.testing.expectError(4412 try std.testing.expectError(
3481 error.ParseZon,4413 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 }),
3483 );4420 );
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")});
3485 }4425 }
34864426
3487 {4427 {
3488 var diag: Diagnostics = .{};
3489 defer diag.deinit(gpa);
3490 try std.testing.expectError(4428 try std.testing.expectError(
3491 error.ParseZon,4429 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 }),
3493 );4436 );
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")});
3495 }4441 }
3496}4442}
34974443
3498test "std.zon stop on node" {4444test "std.zon stop on node" {
3499 const gpa = std.testing.allocator;4445 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
3501 {4451 {
3502 const Vec2 = struct {4452 const Vec2 = struct {
...@@ -3504,27 +4454,55 @@ test "std.zon stop on node" {...@@ -3504,27 +4454,55 @@ test "std.zon stop on node" {
3504 y: f32,4454 y: f32,
3505 };4455 };
35064456
3507 var diag: Diagnostics = .{};4457 var ast = try std.zig.Ast.parse(gpa, ".{ .x = 1.5, .y = 2.5 }", .{ .mode = .zon });
3508 defer diag.deinit(gpa);4458 defer ast.deinit(gpa);
3509 const result = try fromSlice(Vec2, gpa, ".{ .x = 1.5, .y = 2.5 }", &diag, .{});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
3510 try std.testing.expectEqual(result.y, 2.5);4470 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));
3512 }4472 }
35134473
3514 {4474 {
3515 var diag: Diagnostics = .{};4475 var ast = try std.zig.Ast.parse(gpa, "1.23", .{ .mode = .zon });
3516 defer diag.deinit(gpa);4476 defer ast.deinit(gpa);
3517 const result = try fromSlice(Zoir.Node.Index, gpa, "1.23", &diag, .{});4477
3518 try std.testing.expectEqual(Zoir.Node{ .float_literal = 1.23 }, result.get(diag.zoir));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));
3519 }4488 }
3520}4489}
35214490
3522test "std.zon no alloc" {4491test "std.zon no alloc" {
3523 const gpa = std.testing.allocator;4492 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
3525 try std.testing.expectEqual(4498 try std.testing.expectEqual(
3526 [3]u8{ 1, 2, 3 },4499 [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 }),
3528 );4506 );
35294507
3530 const Nested = struct { u8, u8, struct { u8, u8 } };4508 const Nested = struct { u8, u8, struct { u8, u8 } };
...@@ -3537,34 +4515,442 @@ test "std.zon no alloc" {...@@ -3537,34 +4515,442 @@ test "std.zon no alloc" {
35374515
3538 try std.testing.expectEqual(4516 try std.testing.expectEqual(
3539 Nested{ 1, 2, .{ 3, 4 } },4517 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 }),
3541 );4524 );
4525}
35424526
3543 try std.testing.expectEqual(4527test "std.zon aligned pointers" {
3544 Nested{ 1, 2, .{ 3, 4 } },4528 const gpa = std.testing.allocator;
3545 try fromZoirNode(Nested, ast, zoir, .root, null, .{}),4529 var arena_allocator: ArenaAllocator = .init(gpa);
3546 );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);
3547}4549}
35484550
3549test "std.zon errors without diagnostics" {4551test "std.zon update basic" {
3550 const gpa = std.testing.allocator;4552 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 {4571 var v1: Vector = .{ .x = 1, .y = 2, .z = 3 };
3553 foo,4572 var expected: MyStruct = .{
3554 bar,4573 .foo = 10,
3555 baz,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",
3556 };4586 };
3557 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Enum, gpa, ".nothing", null, .{}));
35584587
3559 const Struct = struct {4588 try updateFromSlice(MyStruct, &found, .{
3560 name: []const u8,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 },
3561 };4673 };
3562 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, gpa, ".{ .name = \"Alice\", .age = 25 }", null, .{}));
35634674
3564 const Union = union(enum) {4675 // Updating an optional that starts out null should fill in any default fields we left off
3565 x,4676 {
3566 y: u32,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 },
3567 };4731 };
3568 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".a", null, .{}));4732
3569 try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".{ .b = 8 }", null, .{}));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;
3570}4956}
src/Sema/LowerZon.zig+26-26
...@@ -69,7 +69,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter...@@ -69,7 +69,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
69 const gpa = comp.gpa;69 const gpa = comp.gpa;
70 const io = comp.io;70 const io = comp.io;
71 const ip = &pt.zcu.intern_pool;71 const ip = &pt.zcu.intern_pool;
72 switch (node.get(self.zoir.*)) {72 switch (node.get(self.zoir)) {
73 .true => return .bool_true,73 .true => return .bool_true,
74 .false => return .bool_false,74 .false => return .bool_false,
75 .null => return .null_value,75 .null => return .null_value,
...@@ -99,7 +99,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter...@@ -99,7 +99,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
99 gpa,99 gpa,
100 io,100 io,
101 pt.tid,101 pt.tid,
102 val.get(self.zoir.*),102 val.get(self.zoir),
103 .no_embedded_nulls,103 .no_embedded_nulls,
104 ),104 ),
105 }),105 }),
...@@ -172,7 +172,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter...@@ -172,7 +172,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
172 gpa,172 gpa,
173 io,173 io,
174 pt.tid,174 pt.tid,
175 zoir_name.get(self.zoir.*),175 zoir_name.get(self.zoir),
176 .no_embedded_nulls,176 .no_embedded_nulls,
177 );177 );
178 field_ty.* = ip.typeOf(field_val);178 field_ty.* = ip.typeOf(field_val);
...@@ -310,7 +310,7 @@ fn checkTypeInner(...@@ -310,7 +310,7 @@ fn checkTypeInner(
310fn nodeSrc(self: *LowerZon, node: Zoir.Node.Index) LazySrcLoc {310fn nodeSrc(self: *LowerZon, node: Zoir.Node.Index) LazySrcLoc {
311 return .{311 return .{
312 .baseline = .{ .inst = self.tracked_inst, .node = .main },312 .baseline = .{ .inst = self.tracked_inst, .node = .main },
313 .offset = .{ .node_abs = node.getAstNode(self.zoir.*) },313 .offset = .{ .node_abs = node.getAstNode(self.zoir) },
314 };314 };
315}315}
316316
...@@ -363,7 +363,7 @@ fn lowerExprKnownResTyInner(...@@ -363,7 +363,7 @@ fn lowerExprKnownResTyInner(
363 .optional => return pt.intern(.{363 .optional => return pt.intern(.{
364 .opt = .{364 .opt = .{
365 .ty = res_ty.toIntern(),365 .ty = res_ty.toIntern(),
366 .val = if (node.get(self.zoir.*) == .null) b: {366 .val = if (node.get(self.zoir) == .null) b: {
367 break :b .none;367 break :b .none;
368 } else b: {368 } else b: {
369 const child_type = res_ty.optionalChild(zcu);369 const child_type = res_ty.optionalChild(zcu);
...@@ -418,7 +418,7 @@ fn lowerExprKnownResTyInner(...@@ -418,7 +418,7 @@ fn lowerExprKnownResTyInner(
418}418}
419419
420fn lowerBool(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {420fn lowerBool(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
421 return switch (node.get(self.zoir.*)) {421 return switch (node.get(self.zoir)) {
422 .true => .bool_true,422 .true => .bool_true,
423 .false => .bool_false,423 .false => .bool_false,
424 else => return error.WrongType,424 else => return error.WrongType,
...@@ -431,7 +431,7 @@ fn lowerInt(...@@ -431,7 +431,7 @@ fn lowerInt(
431 res_ty: Type,431 res_ty: Type,
432) !InternPool.Index {432) !InternPool.Index {
433 @setFloatMode(.strict);433 @setFloatMode(.strict);
434 return switch (node.get(self.zoir.*)) {434 return switch (node.get(self.zoir)) {
435 .int_literal => |int| switch (int) {435 .int_literal => |int| switch (int) {
436 .small => |val| {436 .small => |val| {
437 const rhs: i32 = val;437 const rhs: i32 = val;
...@@ -555,7 +555,7 @@ fn lowerFloat(...@@ -555,7 +555,7 @@ fn lowerFloat(
555 res_ty: Type,555 res_ty: Type,
556) !InternPool.Index {556) !InternPool.Index {
557 @setFloatMode(.strict);557 @setFloatMode(.strict);
558 const value = switch (node.get(self.zoir.*)) {558 const value = switch (node.get(self.zoir)) {
559 .int_literal => |int| switch (int) {559 .int_literal => |int| switch (int) {
560 .small => |val| try self.sema.pt.floatValue(res_ty, @as(f128, @floatFromInt(val))),560 .small => |val| try self.sema.pt.floatValue(res_ty, @as(f128, @floatFromInt(val))),
561 .big => |val| try self.sema.pt.floatValue(res_ty, val.toFloat(f128, .nearest_even)[0]),561 .big => |val| try self.sema.pt.floatValue(res_ty, val.toFloat(f128, .nearest_even)[0]),
...@@ -592,7 +592,7 @@ fn lowerFloat(...@@ -592,7 +592,7 @@ fn lowerFloat(
592}592}
593593
594fn lowerNull(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {594fn lowerNull(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
595 switch (node.get(self.zoir.*)) {595 switch (node.get(self.zoir)) {
596 .null => return .null_value,596 .null => return .null_value,
597 else => return error.WrongType,597 else => return error.WrongType,
598 }598 }
...@@ -600,7 +600,7 @@ fn lowerNull(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {...@@ -600,7 +600,7 @@ fn lowerNull(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
600600
601fn lowerArray(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {601fn lowerArray(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
602 const array_info = res_ty.arrayInfo(self.sema.pt.zcu);602 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)) {
604 .array_literal => |nodes| nodes,604 .array_literal => |nodes| nodes,
605 .empty_literal => .{ .start = node, .len = 0 },605 .empty_literal => .{ .start = node, .len = 0 },
606 else => return error.WrongType,606 else => return error.WrongType,
...@@ -633,13 +633,13 @@ fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.I...@@ -633,13 +633,13 @@ fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.I
633 const io = comp.io;633 const io = comp.io;
634 const ip = &pt.zcu.intern_pool;634 const ip = &pt.zcu.intern_pool;
635 try self.sema.ensureLayoutResolved(res_ty, self.import_src, .init);635 try self.sema.ensureLayoutResolved(res_ty, self.import_src, .init);
636 switch (node.get(self.zoir.*)) {636 switch (node.get(self.zoir)) {
637 .enum_literal => |field_name| {637 .enum_literal => |field_name| {
638 const field_name_interned = try ip.getOrPutString(638 const field_name_interned = try ip.getOrPutString(
639 gpa,639 gpa,
640 io,640 io,
641 self.sema.pt.tid,641 self.sema.pt.tid,
642 field_name.get(self.zoir.*),642 field_name.get(self.zoir),
643 .no_embedded_nulls,643 .no_embedded_nulls,
644 );644 );
645 const field_index = res_ty.enumFieldIndex(field_name_interned, self.sema.pt.zcu) orelse {645 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...@@ -648,7 +648,7 @@ fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.I
648 "enum {f} has no member named '{f}'",648 "enum {f} has no member named '{f}'",
649 .{649 .{
650 res_ty.fmt(self.sema.pt.zcu),650 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)),
652 },652 },
653 );653 );
654 };654 };
...@@ -667,13 +667,13 @@ fn lowerEnumLiteral(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {...@@ -667,13 +667,13 @@ fn lowerEnumLiteral(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
667 const gpa = comp.gpa;667 const gpa = comp.gpa;
668 const io = comp.io;668 const io = comp.io;
669 const ip = &pt.zcu.intern_pool;669 const ip = &pt.zcu.intern_pool;
670 switch (node.get(self.zoir.*)) {670 switch (node.get(self.zoir)) {
671 .enum_literal => |field_name| {671 .enum_literal => |field_name| {
672 const field_name_interned = try ip.getOrPutString(672 const field_name_interned = try ip.getOrPutString(
673 gpa,673 gpa,
674 io,674 io,
675 self.sema.pt.tid,675 self.sema.pt.tid,
676 field_name.get(self.zoir.*),676 field_name.get(self.zoir),
677 .no_embedded_nulls,677 .no_embedded_nulls,
678 );678 );
679 return self.sema.pt.intern(.{ .enum_literal = field_name_interned });679 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....@@ -696,7 +696,7 @@ fn lowerTuple(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
696696
697 const tuple_info = ip.indexToKey(res_ty.toIntern()).tuple_type;697 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)) {
700 .array_literal => |nodes| nodes,700 .array_literal => |nodes| nodes,
701 .empty_literal => .{ .start = node, .len = 0 },701 .empty_literal => .{ .start = node, .len = 0 },
702 else => return error.WrongType,702 else => return error.WrongType,
...@@ -720,7 +720,7 @@ fn lowerTuple(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool....@@ -720,7 +720,7 @@ fn lowerTuple(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
720 "index {} outside tuple of length {}",720 "index {} outside tuple of length {}",
721 .{721 .{
722 elems.len,722 elems.len,
723 elem_nodes.at(@intCast(i)).getAstNode(self.zoir.*),723 elem_nodes.at(@intCast(i)).getAstNode(self.zoir),
724 },724 },
725 );725 );
726 }726 }
...@@ -760,7 +760,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool...@@ -760,7 +760,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
760 try self.sema.ensureStructDefaultsResolved(res_ty, self.import_src);760 try self.sema.ensureStructDefaultsResolved(res_ty, self.import_src);
761 const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?;761 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)) {
764 .struct_literal => |fields| fields,764 .struct_literal => |fields| fields,
765 .empty_literal => .{ .names = &.{}, .vals = .{ .start = node, .len = 0 } },765 .empty_literal => .{ .names = &.{}, .vals = .{ .start = node, .len = 0 } },
766 else => return error.WrongType,766 else => return error.WrongType,
...@@ -780,7 +780,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool...@@ -780,7 +780,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
780 gpa,780 gpa,
781 io,781 io,
782 self.sema.pt.tid,782 self.sema.pt.tid,
783 fields.names[i].get(self.zoir.*),783 fields.names[i].get(self.zoir),
784 .no_embedded_nulls,784 .no_embedded_nulls,
785 );785 );
786 const field_node = fields.vals.at(@intCast(i));786 const field_node = fields.vals.at(@intCast(i));
...@@ -844,7 +844,7 @@ fn lowerSlice(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool....@@ -844,7 +844,7 @@ fn lowerSlice(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
844 const string_alignment = ptr_info.flags.alignment == .none or ptr_info.flags.alignment == .@"1";844 const string_alignment = ptr_info.flags.alignment == .none or ptr_info.flags.alignment == .@"1";
845 const string_sentinel = ptr_info.sentinel == .none or ptr_info.sentinel == .zero_u8;845 const string_sentinel = ptr_info.sentinel == .none or ptr_info.sentinel == .zero_u8;
846 if (string_alignment and ptr_info.child == .u8_type and string_sentinel) {846 if (string_alignment and ptr_info.child == .u8_type and string_sentinel) {
847 switch (node.get(self.zoir.*)) {847 switch (node.get(self.zoir)) {
848 .string_literal => |val| {848 .string_literal => |val| {
849 const ip_str = try ip.getOrPutString(gpa, io, self.sema.pt.tid, val, .maybe_embedded_nulls);849 const ip_str = try ip.getOrPutString(gpa, io, self.sema.pt.tid, val, .maybe_embedded_nulls);
850 const str_ref = try self.sema.addStrLit(ip_str, val.len);850 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....@@ -860,7 +860,7 @@ fn lowerSlice(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
860 }860 }
861861
862 // Slice literals862 // 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)) {
864 .array_literal => |nodes| nodes,864 .array_literal => |nodes| nodes,
865 .empty_literal => .{ .start = node, .len = 0 },865 .empty_literal => .{ .start = node, .len = 0 },
866 else => return error.WrongType,866 else => return error.WrongType,
...@@ -927,19 +927,19 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool....@@ -927,19 +927,19 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
927 const union_info = pt.zcu.typeToUnion(res_ty).?;927 const union_info = pt.zcu.typeToUnion(res_ty).?;
928 const enum_tag_info = ip.loadEnumType(union_info.enum_tag_type);928 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)) {
931 .enum_literal => |name| b: {931 .enum_literal => |name| b: {
932 const field_name = try ip.getOrPutString(932 const field_name = try ip.getOrPutString(
933 gpa,933 gpa,
934 io,934 io,
935 self.sema.pt.tid,935 self.sema.pt.tid,
936 name.get(self.zoir.*),936 name.get(self.zoir),
937 .no_embedded_nulls,937 .no_embedded_nulls,
938 );938 );
939 break :b .{ field_name, null };939 break :b .{ field_name, null };
940 },940 },
941 .struct_literal => b: {941 .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)) {
943 .struct_literal => |fields| fields,943 .struct_literal => |fields| fields,
944 else => return self.fail(node, "expected type '{f}'", .{res_ty.fmt(self.sema.pt.zcu)}),944 else => return self.fail(node, "expected type '{f}'", .{res_ty.fmt(self.sema.pt.zcu)}),
945 };945 };
...@@ -950,7 +950,7 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool....@@ -950,7 +950,7 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
950 gpa,950 gpa,
951 io,951 io,
952 self.sema.pt.tid,952 self.sema.pt.tid,
953 fields.names[0].get(self.zoir.*),953 fields.names[0].get(self.zoir),
954 .no_embedded_nulls,954 .no_embedded_nulls,
955 );955 );
956 break :b .{ field_name, fields.vals.at(0) };956 break :b .{ field_name, fields.vals.at(0) };
...@@ -986,7 +986,7 @@ fn lowerVector(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool...@@ -986,7 +986,7 @@ fn lowerVector(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
986986
987 const vector_info = ip.indexToKey(res_ty.toIntern()).vector_type;987 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)) {
990 .array_literal => |nodes| nodes,990 .array_literal => |nodes| nodes,
991 .empty_literal => .{ .start = node, .len = 0 },991 .empty_literal => .{ .start = node, .len = 0 },
992 else => return error.WrongType,992 else => return error.WrongType,
src/print_zoir.zig+1-1
...@@ -54,7 +54,7 @@ const PrintZon = struct {...@@ -54,7 +54,7 @@ const PrintZon = struct {
54 }54 }
5555
56 fn renderNode(pz: *PrintZon, node: Zoir.Node.Index) Error!void {56 fn renderNode(pz: *PrintZon, node: Zoir.Node.Index) Error!void {
57 const zoir = pz.zoir;57 const zoir = &pz.zoir;
58 try pz.w.print("%{d} = ", .{@backingInt(node)});58 try pz.w.print("%{d} = ", .{@backingInt(node)});
59 switch (node.get(zoir)) {59 switch (node.get(zoir)) {
60 .true => try pz.w.writeAll("true"),60 .true => try pz.w.writeAll("true"),