| ... | ... | @@ -1,13 +1,11 @@ |
| 1 | 1 | //! The simplest way to parse ZON at runtime is to use `fromSlice`/`fromSliceAlloc`. |
| 2 | 2 | //! |
| 3 | | //! Note that if you need to parse ZON at compile time, you may use `@import`. |
| 4 | | //! |
| 5 | 3 | //! Parsing from individual Zoir nodes is also available: |
| 6 | 4 | //! * `fromZoir`/`fromZoirAlloc` |
| 7 | 5 | //! |
| 8 | | //! To update an existing values, see the `updateFrom*` variants. |
| 9 | | //! |
| 10 | | //! For lower level control over parsing, see `std.zig.Zoir`. |
| 6 | //! To update an existing values, see the `updateFrom*` variants. To get human readable errors, use |
| 7 | //! the `diag` option. For lower level control over parsing, see `std.zig.Zoir`. For importing ZON |
| 8 | //! at compile time, use `@import`. |
| 11 | 9 | |
| 12 | 10 | const std = @import("std"); |
| 13 | 11 | const Allocator = std.mem.Allocator; |
| ... | ... | @@ -20,235 +18,122 @@ const StrLitErr = std.zig.string_literal.Error; |
| 20 | 18 | const NumberLiteralError = std.zig.number_literal.Error; |
| 21 | 19 | const assert = std.debug.assert; |
| 22 | 20 | const ArrayList = std.ArrayList; |
| 21 | const ArenaAllocator = std.heap.ArenaAllocator; |
| 23 | 22 | |
| 24 | 23 | /// Rename when adding or removing support for a type. |
| 25 | 24 | const valid_types = {}; |
| 26 | 25 | |
| 27 | | pub const Error = union(enum) { |
| 28 | | zoir: Zoir.CompileError, |
| 29 | | type_check: Error.TypeCheckFailure, |
| 30 | | |
| 31 | | pub const Note = union(enum) { |
| 32 | | zoir: Zoir.CompileError.Note, |
| 33 | | type_check: TypeCheckFailure.Note, |
| 34 | | |
| 35 | | pub const Iterator = struct { |
| 36 | | index: usize = 0, |
| 37 | | err: Error, |
| 38 | | diag: *const Diagnostics, |
| 39 | | |
| 40 | | pub fn next(self: *@This()) ?Note { |
| 41 | | switch (self.err) { |
| 42 | | .zoir => |err| { |
| 43 | | if (self.index >= err.note_count) return null; |
| 44 | | const note = err.getNotes(self.diag.zoir)[self.index]; |
| 45 | | self.index += 1; |
| 46 | | return .{ .zoir = note }; |
| 47 | | }, |
| 48 | | .type_check => |err| { |
| 49 | | if (self.index >= err.getNoteCount()) return null; |
| 50 | | const note = err.getNote(self.index); |
| 51 | | self.index += 1; |
| 52 | | return .{ .type_check = note }; |
| 53 | | }, |
| 54 | | } |
| 55 | | } |
| 56 | | }; |
| 57 | | |
| 58 | | fn formatMessage(self: []const u8, w: *std.Io.Writer) std.Io.Writer.Error!void { |
| 59 | | // Just writes the string for now, but we're keeping this behind a formatter so we have |
| 60 | | // the option to extend it in the future to print more advanced messages (like `Error` |
| 61 | | // does) without breaking the API. |
| 62 | | try w.writeAll(self); |
| 63 | | } |
| 64 | | |
| 65 | | pub fn fmtMessage(self: Note, diag: *const Diagnostics) std.fmt.Alt([]const u8, Note.formatMessage) { |
| 66 | | return .{ .data = switch (self) { |
| 67 | | .zoir => |note| note.msg.get(diag.zoir), |
| 68 | | .type_check => |note| note.msg, |
| 69 | | } }; |
| 70 | | } |
| 71 | | |
| 72 | | pub fn getLocation(self: Note, diag: *const Diagnostics) Ast.Location { |
| 73 | | switch (self) { |
| 74 | | .zoir => |note| return zoirErrorLocation(diag.ast, note.token, note.node_or_offset), |
| 75 | | .type_check => |note| return diag.ast.tokenLocation(note.offset, note.token), |
| 76 | | } |
| 77 | | } |
| 26 | pub const Error = struct { |
| 27 | msg: []const u8, |
| 28 | loc: Ast.Location, |
| 29 | token: Ast.OptionalTokenIndex, |
| 30 | /// If `token == .none`, this is an `Ast.Node.Index`. |
| 31 | /// Otherwise, this is a byte offset into `token`. |
| 32 | node_or_offset: u32, |
| 33 | notes: []Note, |
| 34 | |
| 35 | const InitOptions = struct { |
| 36 | msg: []const u8, |
| 37 | token: Ast.OptionalTokenIndex, |
| 38 | node_or_offset: u32, |
| 39 | notes: []Note, |
| 78 | 40 | }; |
| 79 | 41 | |
| 80 | | pub const Iterator = struct { |
| 81 | | index: usize = 0, |
| 82 | | diag: *const Diagnostics, |
| 83 | | |
| 84 | | pub fn next(self: *@This()) ?Error { |
| 85 | | if (self.index < self.diag.zoir.compile_errors.len) { |
| 86 | | const result: Error = .{ .zoir = self.diag.zoir.compile_errors[self.index] }; |
| 87 | | self.index += 1; |
| 88 | | return result; |
| 89 | | } |
| 90 | | |
| 91 | | if (self.diag.type_check) |err| { |
| 92 | | if (self.index == self.diag.zoir.compile_errors.len) { |
| 93 | | const result: Error = .{ .type_check = err }; |
| 94 | | self.index += 1; |
| 95 | | return result; |
| 96 | | } |
| 97 | | } |
| 98 | | |
| 99 | | return null; |
| 100 | | } |
| 101 | | }; |
| 102 | | |
| 103 | | const TypeCheckFailure = struct { |
| 104 | | const Note = struct { |
| 105 | | token: Ast.TokenIndex, |
| 106 | | offset: u32, |
| 107 | | msg: []const u8, |
| 108 | | owned: bool, |
| 109 | | |
| 110 | | fn deinit(self: @This(), gpa: Allocator) void { |
| 111 | | if (self.owned) gpa.free(self.msg); |
| 112 | | } |
| 42 | fn init(ast: *const Ast, options: InitOptions) @This() { |
| 43 | return .{ |
| 44 | .msg = options.msg, |
| 45 | .loc = astLoc(ast, options.token, options.node_or_offset), |
| 46 | .token = options.token, |
| 47 | .node_or_offset = options.node_or_offset, |
| 48 | .notes = options.notes, |
| 113 | 49 | }; |
| 114 | | |
| 115 | | message: []const u8, |
| 116 | | owned: bool, |
| 117 | | token: Ast.TokenIndex, |
| 118 | | offset: u32, |
| 119 | | note: ?@This().Note, |
| 120 | | |
| 121 | | fn deinit(self: @This(), gpa: Allocator) void { |
| 122 | | if (self.note) |note| note.deinit(gpa); |
| 123 | | if (self.owned) gpa.free(self.message); |
| 124 | | } |
| 125 | | |
| 126 | | fn getNoteCount(self: @This()) usize { |
| 127 | | return @intFromBool(self.note != null); |
| 128 | | } |
| 129 | | |
| 130 | | fn getNote(self: @This(), index: usize) @This().Note { |
| 131 | | assert(index == 0); |
| 132 | | return self.note.?; |
| 133 | | } |
| 134 | | }; |
| 135 | | |
| 136 | | const FormatMessage = struct { |
| 137 | | err: Error, |
| 138 | | diag: *const Diagnostics, |
| 139 | | }; |
| 140 | | |
| 141 | | fn formatMessage(self: FormatMessage, w: *std.Io.Writer) std.Io.Writer.Error!void { |
| 142 | | switch (self.err) { |
| 143 | | .zoir => |err| try w.writeAll(err.msg.get(self.diag.zoir)), |
| 144 | | .type_check => |tc| try w.writeAll(tc.message), |
| 145 | | } |
| 146 | | } |
| 147 | | |
| 148 | | pub fn fmtMessage(self: @This(), diag: *const Diagnostics) std.fmt.Alt(FormatMessage, formatMessage) { |
| 149 | | return .{ .data = .{ |
| 150 | | .err = self, |
| 151 | | .diag = diag, |
| 152 | | } }; |
| 153 | | } |
| 154 | | |
| 155 | | pub fn getLocation(self: @This(), diag: *const Diagnostics) Ast.Location { |
| 156 | | return switch (self) { |
| 157 | | .zoir => |err| return zoirErrorLocation( |
| 158 | | diag.ast, |
| 159 | | err.token, |
| 160 | | err.node_or_offset, |
| 161 | | ), |
| 162 | | .type_check => |err| return diag.ast.tokenLocation(err.offset, err.token), |
| 163 | | }; |
| 164 | | } |
| 165 | | |
| 166 | | pub fn iterateNotes(self: @This(), diag: *const Diagnostics) Note.Iterator { |
| 167 | | return .{ .err = self, .diag = diag }; |
| 168 | 50 | } |
| 169 | 51 | |
| 170 | | fn zoirErrorLocation(ast: Ast, maybe_token: Ast.OptionalTokenIndex, node_or_offset: u32) Ast.Location { |
| 52 | fn astLoc( |
| 53 | ast: *const Ast, |
| 54 | maybe_token: Ast.OptionalTokenIndex, |
| 55 | node_or_offset: u32, |
| 56 | ) Ast.Location { |
| 171 | 57 | if (maybe_token.unwrap()) |token| { |
| 172 | | var location = ast.tokenLocation(0, token); |
| 173 | | location.column += node_or_offset; |
| 174 | | return location; |
| 58 | var loc = ast.tokenLocation(0, token); |
| 59 | loc.column += node_or_offset; |
| 60 | return loc; |
| 175 | 61 | } else { |
| 176 | 62 | const ast_node: Ast.Node.Index = @fromBackingInt(@intCast(node_or_offset)); |
| 177 | 63 | const token = ast.nodeMainToken(ast_node); |
| 178 | 64 | return ast.tokenLocation(0, token); |
| 179 | 65 | } |
| 180 | 66 | } |
| 67 | |
| 68 | pub const Note = struct { |
| 69 | msg: []const u8, |
| 70 | loc: Ast.Location, |
| 71 | token: Ast.OptionalTokenIndex, |
| 72 | /// If `token == .none`, this is an `Ast.Node.Index`. |
| 73 | /// Otherwise, this is a byte offset into `token`. |
| 74 | node_or_offset: u32, |
| 75 | |
| 76 | const InitOptions = struct { |
| 77 | msg: []const u8, |
| 78 | token: Ast.OptionalTokenIndex, |
| 79 | node_or_offset: u32, |
| 80 | }; |
| 81 | |
| 82 | fn init(ast: *const Ast, options: @This().InitOptions) @This() { |
| 83 | return .{ |
| 84 | .msg = options.msg, |
| 85 | .loc = astLoc(ast, options.token, options.node_or_offset), |
| 86 | .token = options.token, |
| 87 | .node_or_offset = options.node_or_offset, |
| 88 | }; |
| 89 | } |
| 90 | }; |
| 181 | 91 | }; |
| 182 | 92 | |
| 183 | | /// Information about the success or failure of a parse. |
| 93 | /// Human readable information about the success or failure of a parse. |
| 184 | 94 | pub const Diagnostics = struct { |
| 185 | | ast: Ast = .{ |
| 186 | | .source = "", |
| 187 | | .tokens = .empty, |
| 188 | | .nodes = .empty, |
| 189 | | .extra_data = &.{}, |
| 190 | | .mode = .zon, |
| 191 | | .errors = &.{}, |
| 192 | | }, |
| 193 | | zoir: Zoir = .{ |
| 194 | | .nodes = .empty, |
| 195 | | .extra = &.{}, |
| 196 | | .limbs = &.{}, |
| 197 | | .string_bytes = &.{}, |
| 198 | | .compile_errors = &.{}, |
| 199 | | .error_notes = &.{}, |
| 200 | | }, |
| 201 | | type_check: ?Error.TypeCheckFailure = null, |
| 202 | | |
| 203 | | fn assertEmpty(self: Diagnostics) void { |
| 204 | | assert(self.ast.tokens.len == 0); |
| 205 | | assert(self.zoir.nodes.len == 0); |
| 206 | | assert(self.type_check == null); |
| 207 | | } |
| 208 | | |
| 209 | | pub fn deinit(self: *Diagnostics, gpa: Allocator) void { |
| 210 | | self.ast.deinit(gpa); |
| 211 | | self.zoir.deinit(gpa); |
| 212 | | if (self.type_check) |tc| tc.deinit(gpa); |
| 213 | | self.* = undefined; |
| 214 | | } |
| 215 | | |
| 216 | | pub fn iterateErrors(self: *const Diagnostics) Error.Iterator { |
| 217 | | return .{ .diag = self }; |
| 95 | arena: Allocator, |
| 96 | compile_errors: std.ArrayList(Error), |
| 97 | |
| 98 | pub fn init(arena: Allocator) @This() { |
| 99 | return .{ |
| 100 | .arena = arena, |
| 101 | .compile_errors = .empty, |
| 102 | }; |
| 218 | 103 | } |
| 219 | 104 | |
| 220 | 105 | pub fn format(self: *const @This(), w: *std.Io.Writer) std.Io.Writer.Error!void { |
| 221 | | var errors = self.iterateErrors(); |
| 222 | | while (errors.next()) |err| { |
| 223 | | const loc = err.getLocation(self); |
| 224 | | const msg = err.fmtMessage(self); |
| 225 | | try w.print("{d}:{d}: error: {f}\n", .{ loc.line + 1, loc.column + 1, msg }); |
| 226 | | |
| 227 | | var notes = err.iterateNotes(self); |
| 228 | | while (notes.next()) |note| { |
| 229 | | const note_loc = note.getLocation(self); |
| 230 | | const note_msg = note.fmtMessage(self); |
| 231 | | try w.print("{d}:{d}: note: {f}\n", .{ |
| 232 | | note_loc.line + 1, |
| 233 | | note_loc.column + 1, |
| 234 | | note_msg, |
| 106 | for (self.compile_errors.items) |e| { |
| 107 | try w.print("{d}:{d}: error: {s}\n", .{ |
| 108 | e.loc.line + 1, |
| 109 | e.loc.column + 1, |
| 110 | e.msg, |
| 111 | }); |
| 112 | |
| 113 | for (e.notes) |note| { |
| 114 | try w.print("{d}:{d}: note: {s}\n", .{ |
| 115 | note.loc.line + 1, |
| 116 | note.loc.column + 1, |
| 117 | note.msg, |
| 235 | 118 | }); |
| 236 | 119 | } |
| 237 | 120 | } |
| 238 | 121 | } |
| 122 | |
| 123 | pub fn clear(self: *@This()) void { |
| 124 | self.compile_errors.clearRetainingCapacity(); |
| 125 | } |
| 239 | 126 | }; |
| 240 | 127 | |
| 241 | 128 | pub const FromSliceOptions = struct { |
| 129 | /// Used for scratch allocations. |
| 242 | 130 | gpa: Allocator, |
| 131 | /// The ZON source. |
| 243 | 132 | source: [:0]const u8, |
| 244 | 133 | /// Write human readable error messages here. |
| 245 | 134 | diag: ?*Diagnostics, |
| 246 | 135 | /// If true, unknown fields do not error. |
| 247 | 136 | ignore_unknown_fields: bool = false, |
| 248 | | /// If true, the parser cleans up partially parsed values on error. This requires some extra |
| 249 | | /// bookkeeping, so you may want to turn it off if you don't need this feature (e.g. because |
| 250 | | /// you're using arena allocation.) |
| 251 | | free_on_error: bool = true, |
| 252 | 137 | }; |
| 253 | 138 | |
| 254 | 139 | /// Parses the given slice as ZON. |
| ... | ... | @@ -257,7 +142,7 @@ pub const FromSliceOptions = struct { |
| 257 | 142 | /// invalid or can not be deserialized into type `T`. |
| 258 | 143 | /// |
| 259 | 144 | /// When the parser returns `error.ParseZon`, it will also store a human readable explanation in |
| 260 | | /// `diag` if non null. If diag is not null, it must be initialized to `.{}`. |
| 145 | /// `diag` if non null. |
| 261 | 146 | /// |
| 262 | 147 | /// Asserts at compile time that the result type doesn't contain pointers. As such, the result |
| 263 | 148 | /// doesn't need to be freed. |
| ... | ... | @@ -265,25 +150,13 @@ pub const FromSliceOptions = struct { |
| 265 | 150 | /// An allocator is still required for temporary allocations made during parsing. |
| 266 | 151 | pub fn fromSlice(T: type, options: FromSliceOptions) error{ OutOfMemory, ParseZon }!T { |
| 267 | 152 | comptime assert(!requiresAllocator(T)); |
| 268 | | return fromSliceAlloc(T, options); |
| 269 | | } |
| 270 | | |
| 271 | | pub fn UpdateFromSliceOptions(T: type) type { |
| 272 | | return struct { |
| 273 | | gpa: Allocator, |
| 274 | | /// The value to update. |
| 275 | | value: *T, |
| 276 | | /// The ZON source. |
| 277 | | source: [:0]const u8, |
| 278 | | /// Write human readable error messages here. |
| 279 | | diag: ?*Diagnostics, |
| 280 | | /// If true, unknown fields do not error. |
| 281 | | ignore_unknown_fields: bool = false, |
| 282 | | /// If true, the old values of overriden fields are freed. You may want to turn this off if you |
| 283 | | /// are updating a value that shouldn't be freed e.g. because it contains Zig string literals. |
| 284 | | /// In this case, you can use arena allocation. |
| 285 | | free_on_write: bool = true, |
| 286 | | }; |
| 153 | return fromSliceAlloc(T, .{ |
| 154 | .gpa = options.gpa, |
| 155 | .arena = .failing, |
| 156 | .source = options.source, |
| 157 | .diag = options.diag, |
| 158 | .ignore_unknown_fields = options.ignore_unknown_fields, |
| 159 | }); |
| 287 | 160 | } |
| 288 | 161 | |
| 289 | 162 | /// Similar to `fromSlice`, but updates an existing value `current`. Fields not specified by ZON are |
| ... | ... | @@ -291,141 +164,139 @@ pub fn UpdateFromSliceOptions(T: type) type { |
| 291 | 164 | /// failure, values that were updated prior to the failure are left updated. |
| 292 | 165 | pub fn updateFromSlice( |
| 293 | 166 | T: type, |
| 294 | | options: UpdateFromSliceOptions(T), |
| 167 | value: *T, |
| 168 | options: FromSliceOptions, |
| 295 | 169 | ) error{ OutOfMemory, ParseZon }!void { |
| 296 | 170 | comptime assert(!requiresAllocator(T)); |
| 297 | | try updateFromSliceAlloc(T, options); |
| 171 | try updateFromSliceAlloc(T, value, .{ |
| 172 | .gpa = options.gpa, |
| 173 | .arena = .failing, |
| 174 | .source = options.source, |
| 175 | .diag = options.diag, |
| 176 | .ignore_unknown_fields = options.ignore_unknown_fields, |
| 177 | }); |
| 298 | 178 | } |
| 299 | 179 | |
| 300 | | pub const FromSliceAllocOptions = FromSliceOptions; |
| 180 | pub const FromSliceAllocOptions = struct { |
| 181 | /// Used for scratch allocations. |
| 182 | gpa: Allocator, |
| 183 | /// Owns the result. |
| 184 | arena: Allocator, |
| 185 | /// The ZON source. |
| 186 | source: [:0]const u8, |
| 187 | /// Write human readable error messages here. |
| 188 | diag: ?*Diagnostics, |
| 189 | /// If true, unknown fields do not error. |
| 190 | ignore_unknown_fields: bool = false, |
| 191 | }; |
| 301 | 192 | |
| 302 | 193 | /// Like `fromSlice`, but the result may contain pointers. To automatically free the result, see |
| 303 | 194 | /// `free`. |
| 304 | | pub fn fromSliceAlloc(T: type, options: FromSliceOptions) error{ OutOfMemory, ParseZon }!T { |
| 305 | | var result: T = undefined; |
| 306 | | try parseSliceAlloc(T, &result, options.gpa, options.source, options.diag, .{ |
| 307 | | .ignore_unknown_fields = options.ignore_unknown_fields, |
| 308 | | .ignore_missing_fields = false, |
| 309 | | .free_on_error = options.free_on_error, |
| 310 | | .free_on_write = false, |
| 195 | pub fn fromSliceAlloc(T: type, options: FromSliceAllocOptions) error{ OutOfMemory, ParseZon }!T { |
| 196 | var value: T = undefined; |
| 197 | try parseSliceAlloc(T, &value, .{ |
| 198 | .gpa = options.gpa, |
| 199 | .arena = options.arena, |
| 200 | .source = options.source, |
| 201 | .diag = options.diag, |
| 202 | .parser_options = .{ |
| 203 | .ignore_unknown_fields = options.ignore_unknown_fields, |
| 204 | .ignore_missing_fields = false, |
| 205 | }, |
| 311 | 206 | }); |
| 312 | | return result; |
| 207 | return value; |
| 313 | 208 | } |
| 314 | 209 | |
| 315 | | pub const UpdateFromSliceAllocOptions = UpdateFromSliceOptions; |
| 316 | | |
| 317 | 210 | /// Like updateFromSlice`, but the result may contain pointers. |
| 318 | 211 | pub fn updateFromSliceAlloc( |
| 319 | 212 | T: type, |
| 320 | | options: UpdateFromSliceAllocOptions(T), |
| 213 | value: *T, |
| 214 | options: FromSliceAllocOptions, |
| 321 | 215 | ) error{ OutOfMemory, ParseZon }!void { |
| 322 | | try parseSliceAlloc( |
| 323 | | T, |
| 324 | | options.value, |
| 325 | | options.gpa, |
| 326 | | options.source, |
| 327 | | options.diag, |
| 328 | | .{ |
| 216 | try parseSliceAlloc(T, value, .{ |
| 217 | .gpa = options.gpa, |
| 218 | .arena = options.arena, |
| 219 | .source = options.source, |
| 220 | .diag = options.diag, |
| 221 | .parser_options = .{ |
| 329 | 222 | .ignore_unknown_fields = options.ignore_unknown_fields, |
| 330 | 223 | .ignore_missing_fields = true, |
| 331 | | .free_on_error = false, |
| 332 | | .free_on_write = options.free_on_write, |
| 333 | 224 | }, |
| 334 | | ); |
| 225 | }); |
| 335 | 226 | } |
| 336 | 227 | |
| 337 | | fn parseSliceAlloc( |
| 338 | | T: type, |
| 339 | | out: *T, |
| 228 | const ParseSliceAllocOptions = struct { |
| 340 | 229 | gpa: Allocator, |
| 230 | arena: Allocator, |
| 341 | 231 | source: [:0]const u8, |
| 342 | 232 | diag: ?*Diagnostics, |
| 343 | | options: Parser.Options, |
| 344 | | ) error{ OutOfMemory, ParseZon }!void { |
| 345 | | if (diag) |s| s.assertEmpty(); |
| 233 | parser_options: Parser.Options, |
| 234 | }; |
| 346 | 235 | |
| 347 | | var ast = try std.zig.Ast.parse(gpa, source, .{ .mode = .zon }); |
| 348 | | defer if (diag == null) ast.deinit(gpa); |
| 349 | | if (diag) |s| s.ast = ast; |
| 236 | fn parseSliceAlloc( |
| 237 | T: type, |
| 238 | value: *T, |
| 239 | options: ParseSliceAllocOptions, |
| 240 | ) error{ OutOfMemory, ParseZon }!void { |
| 241 | var ast = try std.zig.Ast.parse(options.gpa, options.source, .{ .mode = .zon }); |
| 242 | defer ast.deinit(options.gpa); |
| 350 | 243 | |
| 351 | | // If there's no diagnostics, Zoir exists for the lifetime of this function. If there is a |
| 352 | | // diagnostics, ownership is transferred to diagnostics. |
| 353 | | var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false }); |
| 354 | | defer if (diag == null) zoir.deinit(gpa); |
| 244 | var zoir = try ZonGen.generate(options.gpa, ast, .{ .parse_str_lits = false }); |
| 245 | defer zoir.deinit(options.gpa); |
| 355 | 246 | |
| 356 | | if (diag) |s| s.* = .{}; |
| 357 | | try parseZoirAlloc(T, out, gpa, ast, zoir, .root, diag, options); |
| 247 | try parseZoirAlloc(T, value, .{ |
| 248 | .arena = options.arena, |
| 249 | .ast = &ast, |
| 250 | .zoir = &zoir, |
| 251 | .node = .root, |
| 252 | .diag = options.diag, |
| 253 | .parser_options = options.parser_options, |
| 254 | }); |
| 358 | 255 | } |
| 359 | 256 | |
| 360 | 257 | pub const FromZoirOptions = struct { |
| 361 | 258 | /// The AST for this this ZON value. |
| 362 | | ast: Ast, |
| 259 | ast: *const Ast, |
| 363 | 260 | /// The zig object intermediate representation of this ZON value. |
| 364 | | zoir: Zoir, |
| 261 | zoir: *const Zoir, |
| 365 | 262 | /// The node to start parsing at. |
| 366 | 263 | node: Zoir.Node.Index = .root, |
| 367 | 264 | /// Write human readable error messages here. |
| 368 | 265 | diag: ?*Diagnostics, |
| 369 | 266 | /// If true, unknown fields do not error. |
| 370 | 267 | ignore_unknown_fields: bool = false, |
| 371 | | /// If true, the parser cleans up partially parsed values on error. This requires some extra |
| 372 | | /// bookkeeping, so you may want to turn it off if you don't need this feature (e.g. because |
| 373 | | /// you're using arena allocation.) |
| 374 | | free_on_error: bool = true, |
| 375 | 268 | }; |
| 376 | 269 | |
| 377 | 270 | /// Like `fromSlice`, but operates on `Zoir` instead of ZON source. |
| 378 | 271 | pub fn fromZoir(T: type, options: FromZoirOptions) error{ParseZon}!T { |
| 379 | 272 | comptime assert(!requiresAllocator(T)); |
| 380 | 273 | return fromZoirAlloc(T, .{ |
| 381 | | .gpa = .failing, |
| 274 | .arena = .failing, |
| 382 | 275 | .ast = options.ast, |
| 383 | 276 | .zoir = options.zoir, |
| 384 | 277 | .node = options.node, |
| 385 | 278 | .diag = options.diag, |
| 386 | 279 | .ignore_unknown_fields = options.ignore_unknown_fields, |
| 387 | | .free_on_error = options.free_on_error, |
| 388 | 280 | }) catch |err| switch (err) { |
| 389 | 281 | error.OutOfMemory => unreachable, // Checked by comptime assertion above |
| 390 | 282 | else => |e| return e, |
| 391 | 283 | }; |
| 392 | 284 | } |
| 393 | 285 | |
| 394 | | pub fn UpdateFromZoirOptions(T: type) type { |
| 395 | | return struct { |
| 396 | | value: *T, |
| 397 | | /// The AST for this ZON value. |
| 398 | | ast: Ast, |
| 399 | | /// The zig object intermediate representation of this ZON value. |
| 400 | | zoir: Zoir, |
| 401 | | /// The node to start parsing at. |
| 402 | | node: Zoir.Node.Index = .root, |
| 403 | | /// Write human readable error messages here. |
| 404 | | diag: ?*Diagnostics, |
| 405 | | /// If true, unknown fields do not error. |
| 406 | | ignore_unknown_fields: bool = false, |
| 407 | | /// If true, the old values of overriden fields are freed. You may want to turn this off if you |
| 408 | | /// are updating a value that shouldn't be freed e.g. because it contains Zig string literals. |
| 409 | | /// In this case, you can use arena allocation. |
| 410 | | free_on_write: bool = true, |
| 411 | | }; |
| 412 | | } |
| 413 | | |
| 414 | 286 | /// Like `updateSlice`, but operates on `Zoir` instead of ZON source. |
| 415 | 287 | pub fn updateFromZoir( |
| 416 | 288 | T: type, |
| 417 | | options: UpdateFromZoirOptions(T), |
| 289 | value: *T, |
| 290 | options: FromZoirOptions, |
| 418 | 291 | ) error{ParseZon}!void { |
| 419 | 292 | comptime assert(!requiresAllocator(T)); |
| 420 | | updateFromZoirAlloc(T, .{ |
| 421 | | .gpa = .failing, |
| 422 | | .value = options.value, |
| 293 | updateFromZoirAlloc(T, value, .{ |
| 294 | .arena = .failing, |
| 423 | 295 | .ast = options.ast, |
| 424 | 296 | .zoir = options.zoir, |
| 425 | 297 | .node = options.node, |
| 426 | 298 | .diag = options.diag, |
| 427 | 299 | .ignore_unknown_fields = options.ignore_unknown_fields, |
| 428 | | .free_on_write = options.free_on_write, |
| 429 | 300 | }) catch |err| switch (err) { |
| 430 | 301 | error.OutOfMemory => unreachable, // Checked by comptime assertion above |
| 431 | 302 | else => |e| return e, |
| ... | ... | @@ -433,172 +304,103 @@ pub fn updateFromZoir( |
| 433 | 304 | } |
| 434 | 305 | |
| 435 | 306 | pub const FromZoirAllocOptions = struct { |
| 436 | | gpa: Allocator, |
| 307 | /// Owns the result. |
| 308 | arena: Allocator, |
| 437 | 309 | /// The AST for this ZON value. |
| 438 | | ast: Ast, |
| 310 | ast: *const Ast, |
| 439 | 311 | /// The zig object intermediate representation of this ZON value. |
| 440 | | zoir: Zoir, |
| 312 | zoir: *const Zoir, |
| 441 | 313 | /// The node to start parsing at. |
| 442 | 314 | node: Zoir.Node.Index = .root, |
| 443 | 315 | /// Write human readable error messages here. |
| 444 | 316 | diag: ?*Diagnostics, |
| 445 | 317 | /// If true, unknown fields do not error. |
| 446 | 318 | ignore_unknown_fields: bool = false, |
| 447 | | /// If true, the parser cleans up partially parsed values on error. This requires some extra |
| 448 | | /// bookkeeping, so you may want to turn it off if you don't need this feature (e.g. because |
| 449 | | /// you're using arena allocation.) |
| 450 | | free_on_error: bool = true, |
| 451 | 319 | }; |
| 452 | 320 | |
| 453 | 321 | /// Like `fromSliceAlloc`, but operates on `Zoir` instead of ZON source. |
| 454 | 322 | pub fn fromZoirAlloc(T: type, options: FromZoirAllocOptions) error{ OutOfMemory, ParseZon }!T { |
| 455 | | var out: T = undefined; |
| 456 | | try parseZoirAlloc( |
| 457 | | T, |
| 458 | | &out, |
| 459 | | options.gpa, |
| 460 | | options.ast, |
| 461 | | options.zoir, |
| 462 | | options.node, |
| 463 | | options.diag, |
| 464 | | .{ |
| 323 | var value: T = undefined; |
| 324 | try parseZoirAlloc(T, &value, .{ |
| 325 | .arena = options.arena, |
| 326 | .ast = options.ast, |
| 327 | .zoir = options.zoir, |
| 328 | .node = options.node, |
| 329 | .diag = options.diag, |
| 330 | .parser_options = .{ |
| 465 | 331 | .ignore_unknown_fields = options.ignore_unknown_fields, |
| 466 | 332 | .ignore_missing_fields = false, |
| 467 | | .free_on_error = options.free_on_error, |
| 468 | | .free_on_write = false, |
| 469 | 333 | }, |
| 470 | | ); |
| 471 | | return out; |
| 472 | | } |
| 473 | | |
| 474 | | pub fn UpdateFromZoirAllocOptions(T: type) type { |
| 475 | | return struct { |
| 476 | | gpa: Allocator, |
| 477 | | value: *T, |
| 478 | | ast: Ast, |
| 479 | | zoir: Zoir, |
| 480 | | node: Zoir.Node.Index = .root, |
| 481 | | /// Write human readable error messages here. |
| 482 | | diag: ?*Diagnostics, |
| 483 | | /// If true, unknown fields do not error. |
| 484 | | ignore_unknown_fields: bool = false, |
| 485 | | /// If true, the old values of overriden fields are freed. You may want to turn this off if you |
| 486 | | /// are updating a value that shouldn't be freed e.g. because it contains Zig string literals. |
| 487 | | /// In this case, you can use arena allocation. |
| 488 | | free_on_write: bool = true, |
| 489 | | }; |
| 334 | }); |
| 335 | return value; |
| 490 | 336 | } |
| 491 | 337 | |
| 492 | 338 | /// Like updateSliceAlloc`, but operates on `Zoir` instead of ZON source. |
| 493 | 339 | pub fn updateFromZoirAlloc( |
| 494 | 340 | T: type, |
| 495 | | options: UpdateFromZoirAllocOptions(T), |
| 341 | value: *T, |
| 342 | options: FromZoirAllocOptions, |
| 496 | 343 | ) error{ OutOfMemory, ParseZon }!void { |
| 497 | | return parseZoirAlloc( |
| 498 | | T, |
| 499 | | options.value, |
| 500 | | options.gpa, |
| 501 | | options.ast, |
| 502 | | options.zoir, |
| 503 | | options.node, |
| 504 | | options.diag, |
| 505 | | .{ |
| 344 | return parseZoirAlloc(T, value, .{ |
| 345 | .arena = options.arena, |
| 346 | .ast = options.ast, |
| 347 | .zoir = options.zoir, |
| 348 | .node = options.node, |
| 349 | .diag = options.diag, |
| 350 | .parser_options = .{ |
| 506 | 351 | .ignore_unknown_fields = options.ignore_unknown_fields, |
| 507 | 352 | .ignore_missing_fields = true, |
| 508 | | .free_on_error = false, |
| 509 | | .free_on_write = options.free_on_write, |
| 510 | 353 | }, |
| 511 | | ); |
| 354 | }); |
| 512 | 355 | } |
| 513 | 356 | |
| 514 | | fn parseZoirAlloc( |
| 515 | | T: type, |
| 516 | | out: *T, |
| 517 | | gpa: Allocator, |
| 518 | | ast: Ast, |
| 519 | | zoir: Zoir, |
| 357 | const ParseZoirAllocOptions = struct { |
| 358 | arena: Allocator, |
| 359 | ast: *const Ast, |
| 360 | zoir: *const Zoir, |
| 520 | 361 | node: Zoir.Node.Index, |
| 521 | 362 | diag: ?*Diagnostics, |
| 522 | | options: Parser.Options, |
| 363 | parser_options: Parser.Options, |
| 364 | }; |
| 365 | |
| 366 | fn parseZoirAlloc( |
| 367 | T: type, |
| 368 | value: *T, |
| 369 | options: ParseZoirAllocOptions, |
| 523 | 370 | ) error{ OutOfMemory, ParseZon }!void { |
| 524 | 371 | comptime assert(canParseType(T)); |
| 525 | 372 | |
| 526 | | if (diag) |s| { |
| 527 | | s.assertEmpty(); |
| 528 | | s.ast = ast; |
| 529 | | s.zoir = zoir; |
| 530 | | } |
| 531 | | |
| 532 | | if (zoir.hasCompileErrors()) { |
| 373 | if (options.zoir.hasCompileErrors()) { |
| 374 | if (options.diag) |s| { |
| 375 | for (options.zoir.compile_errors) |e| { |
| 376 | var notes: std.ArrayList(Error.Note) = .empty; |
| 377 | for (e.getNotes(options.zoir)) |note| { |
| 378 | try notes.append(s.arena, .init(options.ast, .{ |
| 379 | .msg = try s.arena.dupe(u8, note.msg.get(options.zoir)), |
| 380 | .token = note.token, |
| 381 | .node_or_offset = note.node_or_offset, |
| 382 | })); |
| 383 | } |
| 384 | try s.compile_errors.append(s.arena, .init(options.ast, .{ |
| 385 | .msg = try s.arena.dupe(u8, e.msg.get(options.zoir)), |
| 386 | .token = e.token, |
| 387 | .node_or_offset = e.node_or_offset, |
| 388 | .notes = try notes.toOwnedSlice(s.arena), |
| 389 | })); |
| 390 | } |
| 391 | } |
| 533 | 392 | return error.ParseZon; |
| 534 | 393 | } |
| 535 | 394 | |
| 536 | 395 | var parser: Parser = .{ |
| 537 | | .gpa = gpa, |
| 538 | | .ast = ast, |
| 539 | | .zoir = zoir, |
| 540 | | .options = options, |
| 541 | | .diag = diag, |
| 396 | .arena = options.arena, |
| 397 | .ast = options.ast, |
| 398 | .zoir = options.zoir, |
| 399 | .options = options.parser_options, |
| 400 | .diag = options.diag, |
| 542 | 401 | }; |
| 543 | 402 | |
| 544 | | try parser.parseExprInto(node, out); |
| 545 | | } |
| 546 | | |
| 547 | | /// Frees ZON values. |
| 548 | | /// |
| 549 | | /// Provided for convenience, you may also free these values on your own using the same allocator |
| 550 | | /// passed into the parser. |
| 551 | | /// |
| 552 | | /// Asserts at comptime that sufficient information is available via the type system to free this |
| 553 | | /// value. Untagged unions, for example, will fail this assert. |
| 554 | | pub fn free(gpa: Allocator, value: anytype) void { |
| 555 | | const Value = @TypeOf(value); |
| 556 | | |
| 557 | | _ = valid_types; |
| 558 | | switch (@typeInfo(Value)) { |
| 559 | | .bool, .int, .float, .@"enum" => {}, |
| 560 | | .pointer => |pointer| { |
| 561 | | switch (pointer.size) { |
| 562 | | .one => { |
| 563 | | free(gpa, value.*); |
| 564 | | gpa.destroy(value); |
| 565 | | }, |
| 566 | | .slice => { |
| 567 | | for (value) |item| { |
| 568 | | free(gpa, item); |
| 569 | | } |
| 570 | | gpa.free(value); |
| 571 | | }, |
| 572 | | .many, .c => comptime unreachable, |
| 573 | | } |
| 574 | | }, |
| 575 | | .array => { |
| 576 | | freeArray(gpa, @TypeOf(value), &value); |
| 577 | | }, |
| 578 | | .vector => |vector| { |
| 579 | | const array: [vector.len]vector.child = value; |
| 580 | | freeArray(gpa, @TypeOf(array), &array); |
| 581 | | }, |
| 582 | | .@"struct" => |@"struct"| inline for (@"struct".field_names) |field_name| { |
| 583 | | free(gpa, @field(value, field_name)); |
| 584 | | }, |
| 585 | | .@"union" => |@"union"| if (@"union".tag_type == null) { |
| 586 | | if (comptime requiresAllocator(Value)) unreachable; |
| 587 | | } else switch (value) { |
| 588 | | inline else => |_, tag| { |
| 589 | | free(gpa, @field(value, @tagName(tag))); |
| 590 | | }, |
| 591 | | }, |
| 592 | | .optional => if (value) |some| { |
| 593 | | free(gpa, some); |
| 594 | | }, |
| 595 | | .void => {}, |
| 596 | | else => comptime unreachable, |
| 597 | | } |
| 598 | | } |
| 599 | | |
| 600 | | fn freeArray(gpa: Allocator, comptime A: type, array: *const A) void { |
| 601 | | for (array) |elem| free(gpa, elem); |
| 403 | try parser.parseExprInto(options.node, value); |
| 602 | 404 | } |
| 603 | 405 | |
| 604 | 406 | fn requiresAllocator(T: type) bool { |
| ... | ... | @@ -623,17 +425,15 @@ fn requiresAllocator(T: type) bool { |
| 623 | 425 | } |
| 624 | 426 | |
| 625 | 427 | const Parser = struct { |
| 626 | | gpa: Allocator, |
| 627 | | ast: Ast, |
| 628 | | zoir: Zoir, |
| 428 | arena: Allocator, |
| 429 | ast: *const Ast, |
| 430 | zoir: *const Zoir, |
| 629 | 431 | diag: ?*Diagnostics, |
| 630 | 432 | options: Parser.Options, |
| 631 | 433 | pointer_depth: usize = 0, |
| 632 | 434 | |
| 633 | 435 | pub const Options = struct { |
| 634 | 436 | ignore_unknown_fields: bool, |
| 635 | | free_on_error: bool, |
| 636 | | free_on_write: bool, |
| 637 | 437 | ignore_missing_fields: bool, |
| 638 | 438 | }; |
| 639 | 439 | |
| ... | ... | @@ -654,37 +454,36 @@ const Parser = struct { |
| 654 | 454 | out: anytype, |
| 655 | 455 | ) ParseExprInnerError!void { |
| 656 | 456 | if (@TypeOf(out.*) == Zoir.Node.Index) { |
| 657 | | self.write(out, node); |
| 457 | out.* = node; |
| 658 | 458 | return; |
| 659 | 459 | } |
| 660 | 460 | |
| 661 | 461 | switch (@typeInfo(@TypeOf(out.*))) { |
| 662 | 462 | .optional => |optional| if (node.get(self.zoir) == .null) { |
| 663 | | self.write(out, null); |
| 463 | out.* = null; |
| 664 | 464 | } else { |
| 665 | 465 | var new: optional.child = undefined; |
| 666 | 466 | try self.parseExprInnerInto(node, &new); |
| 667 | | self.write(out, new); |
| 467 | out.* = new; |
| 668 | 468 | }, |
| 669 | | .bool => self.write(out, try self.parseBool(node)), |
| 670 | | .int => self.write(out, try self.parseInt(@TypeOf(out.*), node)), |
| 671 | | .float => self.write(out, try self.parseFloat(@TypeOf(out.*), node)), |
| 672 | | .@"enum" => self.write(out, try self.parseEnumLiteral(@TypeOf(out.*), node)), |
| 469 | .bool => out.* = try self.parseBool(node), |
| 470 | .int => out.* = try self.parseInt(@TypeOf(out.*), node), |
| 471 | .float => out.* = try self.parseFloat(@TypeOf(out.*), node), |
| 472 | .@"enum" => out.* = try self.parseEnumLiteral(@TypeOf(out.*), node), |
| 673 | 473 | .pointer => |pointer| switch (pointer.size) { |
| 674 | 474 | .one => { |
| 675 | | const slice = try self.gpa.alignedAlloc( |
| 475 | const slice = try self.arena.alignedAlloc( |
| 676 | 476 | pointer.child, |
| 677 | 477 | if (pointer.attrs.@"align") |a| .fromByteUnits(a) else null, |
| 678 | 478 | 1, |
| 679 | 479 | ); |
| 680 | | errdefer self.gpa.free(slice); |
| 681 | 480 | const new = &slice[0]; |
| 682 | 481 | { |
| 683 | 482 | self.pointer_depth += 1; |
| 684 | 483 | defer self.pointer_depth -= 1; |
| 685 | 484 | try self.parseExprInnerInto(node, new); |
| 686 | 485 | } |
| 687 | | self.write(out, new); |
| 486 | out.* = new; |
| 688 | 487 | }, |
| 689 | 488 | .slice => { |
| 690 | 489 | const new = b: { |
| ... | ... | @@ -693,7 +492,7 @@ const Parser = struct { |
| 693 | 492 | const new = try self.parseSlicePointer(@TypeOf(out.*), node); |
| 694 | 493 | break :b new; |
| 695 | 494 | }; |
| 696 | | self.write(out, new); |
| 495 | out.* = new; |
| 697 | 496 | }, |
| 698 | 497 | else => comptime unreachable, |
| 699 | 498 | }, |
| ... | ... | @@ -867,7 +666,7 @@ const Parser = struct { |
| 867 | 666 | var size_hint = ZonGen.strLitSizeHint(self.ast, ast_node); |
| 868 | 667 | if (pointer.sentinel() != null) size_hint += 1; |
| 869 | 668 | |
| 870 | | var aw: std.Io.Writer.Allocating = .init(self.gpa); |
| 669 | var aw: std.Io.Writer.Allocating = .init(self.arena); |
| 871 | 670 | try aw.ensureUnusedCapacity(size_hint); |
| 872 | 671 | defer aw.deinit(); |
| 873 | 672 | const result = ZonGen.parseStrLit(self.ast, ast_node, &aw.writer) catch return error.OutOfMemory; |
| ... | ... | @@ -906,21 +705,15 @@ const Parser = struct { |
| 906 | 705 | } |
| 907 | 706 | |
| 908 | 707 | // Allocate the slice |
| 909 | | const slice = try self.gpa.allocWithOptions( |
| 708 | const slice = try self.arena.allocWithOptions( |
| 910 | 709 | pointer.child, |
| 911 | 710 | nodes.len, |
| 912 | 711 | .fromByteUnitsOptional(pointer.attrs.@"align"), |
| 913 | 712 | pointer.sentinel(), |
| 914 | 713 | ); |
| 915 | | errdefer self.gpa.free(slice); |
| 916 | 714 | |
| 917 | 715 | // Parse the elements and return the slice |
| 918 | 716 | for (slice, 0..) |*elem, i| { |
| 919 | | errdefer if (self.options.free_on_error) { |
| 920 | | for (slice[0..i]) |item| { |
| 921 | | free(self.gpa, item); |
| 922 | | } |
| 923 | | }; |
| 924 | 717 | try self.parseExprInto(nodes.at(@intCast(i)), elem); |
| 925 | 718 | } |
| 926 | 719 | |
| ... | ... | @@ -953,13 +746,6 @@ const Parser = struct { |
| 953 | 746 | |
| 954 | 747 | // Parse the elements and return the array |
| 955 | 748 | inline for (out, 0..) |*elem, i| { |
| 956 | | // If we fail to parse this field, free all fields before it |
| 957 | | errdefer if (self.options.free_on_error) { |
| 958 | | for (out[0..i]) |item| { |
| 959 | | free(self.gpa, item); |
| 960 | | } |
| 961 | | }; |
| 962 | | |
| 963 | 749 | try self.parseExprInto(nodes.at(@intCast(i)), elem); |
| 964 | 750 | } |
| 965 | 751 | |
| ... | ... | @@ -972,7 +758,7 @@ const Parser = struct { |
| 972 | 758 | const vector = @typeInfo(@TypeOf(out.*)).vector; |
| 973 | 759 | var array: [vector.len]vector.child = undefined; |
| 974 | 760 | try self.parseArrayInto(node, &array); |
| 975 | | self.write(out, array); |
| 761 | out.* = array; |
| 976 | 762 | } |
| 977 | 763 | |
| 978 | 764 | fn parseStructInto(self: *@This(), node: Zoir.Node.Index, out: anytype) !void { |
| ... | ... | @@ -998,22 +784,6 @@ const Parser = struct { |
| 998 | 784 | |
| 999 | 785 | // Parse the struct |
| 1000 | 786 | var field_found: [info.field_names.len]bool = @splat(false); |
| 1001 | | |
| 1002 | | // If we fail partway through, free all already initialized fields |
| 1003 | | var initialized: usize = 0; |
| 1004 | | errdefer if (self.options.free_on_error and info.field_names.len > 0) { |
| 1005 | | for (fields.names[0..initialized]) |name_runtime| { |
| 1006 | | switch (field_indices.get(name_runtime.get(self.zoir)) orelse continue) { |
| 1007 | | inline 0...(info.field_names.len - 1) => |name_index| { |
| 1008 | | const name = info.field_names[name_index]; |
| 1009 | | free(self.gpa, @field(out, name)); |
| 1010 | | }, |
| 1011 | | else => unreachable, // Can't be out of bounds |
| 1012 | | } |
| 1013 | | } |
| 1014 | | }; |
| 1015 | | |
| 1016 | | // Fill in the fields we found |
| 1017 | 787 | for (0..fields.names.len) |i| { |
| 1018 | 788 | const name = fields.names[i].get(self.zoir); |
| 1019 | 789 | const field_index = field_indices.get(name) orelse { |
| ... | ... | @@ -1040,8 +810,6 @@ const Parser = struct { |
| 1040 | 810 | }, |
| 1041 | 811 | else => unreachable, // Can't be out of bounds |
| 1042 | 812 | } |
| 1043 | | |
| 1044 | | initialized += 1; |
| 1045 | 813 | } |
| 1046 | 814 | |
| 1047 | 815 | // Fill in any missing default fields |
| ... | ... | @@ -1089,14 +857,6 @@ const Parser = struct { |
| 1089 | 857 | return self.failNodeFmt(node, "missing tuple field with index {}", .{i}); |
| 1090 | 858 | } |
| 1091 | 859 | } else { |
| 1092 | | // If we fail to parse this field, free all fields before it |
| 1093 | | errdefer if (self.options.free_on_error) { |
| 1094 | | inline for (0..i) |j| { |
| 1095 | | if (j >= i) break; |
| 1096 | | free(self.gpa, out[j]); |
| 1097 | | } |
| 1098 | | }; |
| 1099 | | |
| 1100 | 860 | if (info.field_attrs[i].@"comptime") { |
| 1101 | 861 | return self.failComptimeField(node, i); |
| 1102 | 862 | } else { |
| ... | ... | @@ -1144,7 +904,7 @@ const Parser = struct { |
| 1144 | 904 | return self.failNode(node, "expected union"); |
| 1145 | 905 | |
| 1146 | 906 | // Instantiate the union |
| 1147 | | self.write(out, @unionInit(@TypeOf(out.*), @"union".field_names[i], {})); |
| 907 | out.* = @unionInit(@TypeOf(out.*), @"union".field_names[i], {}); |
| 1148 | 908 | }, |
| 1149 | 909 | else => unreachable, // Can't be out of bounds |
| 1150 | 910 | } |
| ... | ... | @@ -1166,7 +926,7 @@ const Parser = struct { |
| 1166 | 926 | if (@"union".field_types[i] == void) { |
| 1167 | 927 | return self.failNode(field_val, "expected type 'void'"); |
| 1168 | 928 | } else { |
| 1169 | | self.write(out, @unionInit(@TypeOf(out.*), @"union".field_names[i], undefined)); |
| 929 | out.* = @unionInit(@TypeOf(out.*), @"union".field_names[i], undefined); |
| 1170 | 930 | try self.parseExprInto(field_val, &@field(out.*, @"union".field_names[i])); |
| 1171 | 931 | } |
| 1172 | 932 | }, |
| ... | ... | @@ -1185,7 +945,7 @@ const Parser = struct { |
| 1185 | 945 | args: anytype, |
| 1186 | 946 | ) error{ OutOfMemory, ParseZon } { |
| 1187 | 947 | @branchHint(.cold); |
| 1188 | | return self.failTokenFmtNote(token, offset, fmt, args, null); |
| 948 | return self.failTokenFmtNote(token, offset, fmt, args, &.{}); |
| 1189 | 949 | } |
| 1190 | 950 | |
| 1191 | 951 | fn failTokenFmtNote( |
| ... | ... | @@ -1194,20 +954,16 @@ const Parser = struct { |
| 1194 | 954 | offset: u32, |
| 1195 | 955 | comptime fmt: []const u8, |
| 1196 | 956 | args: anytype, |
| 1197 | | note: ?Error.TypeCheckFailure.Note, |
| 957 | notes: []Error.Note, |
| 1198 | 958 | ) error{ OutOfMemory, ParseZon } { |
| 1199 | 959 | @branchHint(.cold); |
| 1200 | 960 | comptime assert(args.len > 0); |
| 1201 | | if (self.diag) |s| s.type_check = .{ |
| 1202 | | .token = token, |
| 1203 | | .offset = offset, |
| 1204 | | .message = std.fmt.allocPrint(self.gpa, fmt, args) catch |err| { |
| 1205 | | if (note) |n| n.deinit(self.gpa); |
| 1206 | | return err; |
| 1207 | | }, |
| 1208 | | .owned = true, |
| 1209 | | .note = note, |
| 1210 | | }; |
| 961 | if (self.diag) |s| try s.compile_errors.append(s.arena, .init(self.ast, .{ |
| 962 | .token = .fromToken(token), |
| 963 | .node_or_offset = offset, |
| 964 | .msg = try std.fmt.allocPrint(s.arena, fmt, args), |
| 965 | .notes = notes, |
| 966 | })); |
| 1211 | 967 | return error.ParseZon; |
| 1212 | 968 | } |
| 1213 | 969 | |
| ... | ... | @@ -1224,27 +980,26 @@ const Parser = struct { |
| 1224 | 980 | |
| 1225 | 981 | fn failToken( |
| 1226 | 982 | self: @This(), |
| 1227 | | failure: Error.TypeCheckFailure, |
| 1228 | | ) error{ParseZon} { |
| 983 | failure: Error, |
| 984 | ) error{ OutOfMemory, ParseZon } { |
| 1229 | 985 | @branchHint(.cold); |
| 1230 | | if (self.diag) |s| s.type_check = failure; |
| 986 | if (self.diag) |s| try s.compile_errors.append(s.arena, failure); |
| 1231 | 987 | return error.ParseZon; |
| 1232 | 988 | } |
| 1233 | 989 | |
| 1234 | 990 | fn failNode( |
| 1235 | 991 | self: @This(), |
| 1236 | 992 | node: Zoir.Node.Index, |
| 1237 | | message: []const u8, |
| 1238 | | ) error{ParseZon} { |
| 993 | msg: []const u8, |
| 994 | ) error{ OutOfMemory, ParseZon } { |
| 1239 | 995 | @branchHint(.cold); |
| 1240 | 996 | const token = self.ast.nodeMainToken(node.getAstNode(self.zoir)); |
| 1241 | | return self.failToken(.{ |
| 1242 | | .token = token, |
| 1243 | | .offset = 0, |
| 1244 | | .message = message, |
| 1245 | | .owned = false, |
| 1246 | | .note = null, |
| 1247 | | }); |
| 997 | return self.failToken(.init(self.ast, .{ |
| 998 | .token = .fromToken(token), |
| 999 | .node_or_offset = 0, |
| 1000 | .msg = msg, |
| 1001 | .notes = &.{}, |
| 1002 | })); |
| 1248 | 1003 | } |
| 1249 | 1004 | |
| 1250 | 1005 | fn failCannotRepresent( |
| ... | ... | @@ -1265,8 +1020,7 @@ const Parser = struct { |
| 1265 | 1020 | name: []const u8, |
| 1266 | 1021 | ) error{ OutOfMemory, ParseZon } { |
| 1267 | 1022 | @branchHint(.cold); |
| 1268 | | if (self.diag == null) return error.ParseZon; |
| 1269 | | const gpa = self.gpa; |
| 1023 | const diag = self.diag orelse return error.ParseZon; |
| 1270 | 1024 | const token = if (field) |f| b: { |
| 1271 | 1025 | var buf: [2]Ast.Node.Index = undefined; |
| 1272 | 1026 | const struct_init = self.ast.fullStructInit(&buf, node.getAstNode(self.zoir)).?; |
| ... | ... | @@ -1275,38 +1029,35 @@ const Parser = struct { |
| 1275 | 1029 | } else self.ast.nodeMainToken(node.getAstNode(self.zoir)); |
| 1276 | 1030 | switch (@typeInfo(T)) { |
| 1277 | 1031 | inline .@"struct", .@"union", .@"enum" => |info| { |
| 1278 | | const note: Error.TypeCheckFailure.Note = if (info.field_names.len == 0) b: { |
| 1279 | | break :b .{ |
| 1280 | | .token = token, |
| 1281 | | .offset = 0, |
| 1032 | var notes: std.ArrayList(Error.Note) = .empty; |
| 1033 | if (info.field_names.len == 0) { |
| 1034 | try notes.append(diag.arena, .init(self.ast, .{ |
| 1035 | .token = .fromToken(token), |
| 1036 | .node_or_offset = 0, |
| 1282 | 1037 | .msg = "none expected", |
| 1283 | | .owned = false, |
| 1284 | | }; |
| 1285 | | } else b: { |
| 1286 | | const msg = "supported: "; |
| 1287 | | var buf: std.ArrayList(u8) = try .initCapacity(gpa, 64); |
| 1288 | | defer buf.deinit(gpa); |
| 1289 | | try buf.appendSlice(gpa, msg); |
| 1038 | })); |
| 1039 | } else { |
| 1040 | var aw: std.Io.Writer.Allocating = .init(diag.arena); |
| 1041 | aw.writer.writeAll("supported: ") catch return error.OutOfMemory; |
| 1290 | 1042 | inline for (info.field_names, 0..) |field_name, i| { |
| 1291 | | if (i != 0) try buf.appendSlice(gpa, ", "); |
| 1292 | | try buf.print(gpa, "'{f}'", .{std.zig.fmtIdFlags(field_name, .{ |
| 1043 | if (i != 0) aw.writer.writeAll(", ") catch return error.OutOfMemory; |
| 1044 | aw.writer.print("'{f}'", .{std.zig.fmtIdFlags(field_name, .{ |
| 1293 | 1045 | .allow_primitive = true, |
| 1294 | 1046 | .allow_underscore = true, |
| 1295 | | })}); |
| 1047 | })}) catch return error.OutOfMemory; |
| 1296 | 1048 | } |
| 1297 | | break :b .{ |
| 1298 | | .token = token, |
| 1299 | | .offset = 0, |
| 1300 | | .msg = try buf.toOwnedSlice(gpa), |
| 1301 | | .owned = true, |
| 1302 | | }; |
| 1303 | | }; |
| 1049 | try notes.append(diag.arena, .init(self.ast, .{ |
| 1050 | .token = .fromToken(token), |
| 1051 | .node_or_offset = 0, |
| 1052 | .msg = try aw.toOwnedSlice(), |
| 1053 | })); |
| 1054 | } |
| 1304 | 1055 | return self.failTokenFmtNote( |
| 1305 | 1056 | token, |
| 1306 | 1057 | 0, |
| 1307 | 1058 | "unexpected {s} '{s}'", |
| 1308 | 1059 | .{ item_kind, name }, |
| 1309 | | note, |
| 1060 | try notes.toOwnedSlice(diag.arena), |
| 1310 | 1061 | ); |
| 1311 | 1062 | }, |
| 1312 | 1063 | else => comptime unreachable, |
| ... | ... | @@ -1333,23 +1084,12 @@ const Parser = struct { |
| 1333 | 1084 | const value_node = array_init.ast.elements[field]; |
| 1334 | 1085 | break :b self.ast.firstToken(value_node); |
| 1335 | 1086 | }; |
| 1336 | | return self.failToken(.{ |
| 1337 | | .token = token, |
| 1338 | | .offset = 0, |
| 1339 | | .message = "cannot initialize comptime field", |
| 1340 | | .owned = false, |
| 1341 | | .note = null, |
| 1342 | | }); |
| 1343 | | } |
| 1344 | | |
| 1345 | | /// Write to out, freeing the old value first if necessary. |
| 1346 | | fn write(self: *@This(), out: anytype, new: @TypeOf(out.*)) void { |
| 1347 | | if (@typeInfo(@TypeOf(out)) == .pointer) { |
| 1348 | | if (self.options.free_on_write and self.pointer_depth == 0) { |
| 1349 | | free(self.gpa, out.*); |
| 1350 | | } |
| 1351 | | } |
| 1352 | | out.* = new; |
| 1087 | return self.failToken(.init(self.ast, .{ |
| 1088 | .token = .fromToken(token), |
| 1089 | .node_or_offset = 0, |
| 1090 | .msg = "cannot initialize comptime field", |
| 1091 | .notes = &.{}, |
| 1092 | })); |
| 1353 | 1093 | } |
| 1354 | 1094 | }; |
| 1355 | 1095 | |
| ... | ... | @@ -1511,17 +1251,26 @@ test "std.zon requiresAllocator" { |
| 1511 | 1251 | |
| 1512 | 1252 | test "std.zon ast errors" { |
| 1513 | 1253 | const gpa = std.testing.allocator; |
| 1514 | | var diag: Diagnostics = .{}; |
| 1515 | | defer diag.deinit(gpa); |
| 1254 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 1255 | defer arena_allocator.deinit(); |
| 1256 | const arena = arena_allocator.allocator(); |
| 1257 | var diag: Diagnostics = .init(arena); |
| 1516 | 1258 | try std.testing.expectError( |
| 1517 | 1259 | error.ParseZon, |
| 1518 | | fromSlice(struct {}, .{ .gpa = gpa, .source = ".{.x = 1 .y = 2}", .diag = &diag }), |
| 1260 | fromSlice(struct {}, .{ |
| 1261 | .gpa = gpa, |
| 1262 | .source = ".{.x = 1 .y = 2}", |
| 1263 | .diag = &diag, |
| 1264 | }), |
| 1519 | 1265 | ); |
| 1520 | 1266 | try std.testing.expectFmt("1:13: error: expected ',' after initializer\n", "{f}", .{diag}); |
| 1521 | 1267 | } |
| 1522 | 1268 | |
| 1523 | 1269 | test "std.zon comments" { |
| 1524 | 1270 | const gpa = std.testing.allocator; |
| 1271 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 1272 | defer arena_allocator.deinit(); |
| 1273 | const arena = arena_allocator.allocator(); |
| 1525 | 1274 | |
| 1526 | 1275 | try std.testing.expectEqual(@as(u8, 10), fromSlice(u8, .{ |
| 1527 | 1276 | .gpa = gpa, |
| ... | ... | @@ -1534,8 +1283,7 @@ test "std.zon comments" { |
| 1534 | 1283 | })); |
| 1535 | 1284 | |
| 1536 | 1285 | { |
| 1537 | | var diag: Diagnostics = .{}; |
| 1538 | | defer diag.deinit(gpa); |
| 1286 | var diag: Diagnostics = .init(arena); |
| 1539 | 1287 | try std.testing.expectError(error.ParseZon, fromSlice(u8, .{ |
| 1540 | 1288 | .gpa = gpa, |
| 1541 | 1289 | .source = |
| ... | ... | @@ -1555,10 +1303,13 @@ test "std.zon comments" { |
| 1555 | 1303 | |
| 1556 | 1304 | test "std.zon failure/oom formatting" { |
| 1557 | 1305 | const gpa = std.testing.allocator; |
| 1558 | | var diag: Diagnostics = .{}; |
| 1559 | | defer diag.deinit(gpa); |
| 1306 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 1307 | defer arena_allocator.deinit(); |
| 1308 | const arena = arena_allocator.allocator(); |
| 1309 | var diag: Diagnostics = .init(arena); |
| 1560 | 1310 | try std.testing.expectError(error.OutOfMemory, fromSliceAlloc([]const u8, .{ |
| 1561 | 1311 | .gpa = .failing, |
| 1312 | .arena = arena, |
| 1562 | 1313 | .source = "\"foo\"", |
| 1563 | 1314 | .diag = &diag, |
| 1564 | 1315 | })); |
| ... | ... | @@ -1566,10 +1317,11 @@ test "std.zon failure/oom formatting" { |
| 1566 | 1317 | } |
| 1567 | 1318 | |
| 1568 | 1319 | test "std.zon fromSliceAlloc syntax error" { |
| 1320 | const gpa = std.testing.allocator; |
| 1569 | 1321 | try std.testing.expectError( |
| 1570 | 1322 | error.ParseZon, |
| 1571 | 1323 | fromSlice(u8, .{ |
| 1572 | | .gpa = std.testing.allocator, |
| 1324 | .gpa = gpa, |
| 1573 | 1325 | .source = ".{", |
| 1574 | 1326 | .diag = null, |
| 1575 | 1327 | }), |
| ... | ... | @@ -1578,6 +1330,9 @@ test "std.zon fromSliceAlloc syntax error" { |
| 1578 | 1330 | |
| 1579 | 1331 | test "std.zon optional" { |
| 1580 | 1332 | const gpa = std.testing.allocator; |
| 1333 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 1334 | defer arena_allocator.deinit(); |
| 1335 | const arena = arena_allocator.allocator(); |
| 1581 | 1336 | |
| 1582 | 1337 | // Basic usage |
| 1583 | 1338 | { |
| ... | ... | @@ -1599,22 +1354,26 @@ test "std.zon optional" { |
| 1599 | 1354 | { |
| 1600 | 1355 | const none = try fromSliceAlloc(?[]const u8, .{ |
| 1601 | 1356 | .gpa = gpa, |
| 1357 | .arena = arena, |
| 1602 | 1358 | .source = "null", |
| 1603 | 1359 | .diag = null, |
| 1604 | 1360 | }); |
| 1605 | 1361 | try std.testing.expect(none == null); |
| 1606 | 1362 | const some = try fromSliceAlloc(?[]const u8, .{ |
| 1607 | 1363 | .gpa = gpa, |
| 1364 | .arena = arena, |
| 1608 | 1365 | .source = "\"foo\"", |
| 1609 | 1366 | .diag = null, |
| 1610 | 1367 | }); |
| 1611 | | defer free(gpa, some); |
| 1612 | 1368 | try std.testing.expectEqualStrings("foo", some.?); |
| 1613 | 1369 | } |
| 1614 | 1370 | } |
| 1615 | 1371 | |
| 1616 | 1372 | test "std.zon unions" { |
| 1617 | 1373 | const gpa = std.testing.allocator; |
| 1374 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 1375 | defer arena_allocator.deinit(); |
| 1376 | const arena = arena_allocator.allocator(); |
| 1618 | 1377 | |
| 1619 | 1378 | // Unions |
| 1620 | 1379 | { |
| ... | ... | @@ -1666,6 +1425,7 @@ test "std.zon unions" { |
| 1666 | 1425 | |
| 1667 | 1426 | const noalloc = try fromSliceAlloc(Union, .{ |
| 1668 | 1427 | .gpa = gpa, |
| 1428 | .arena = arena, |
| 1669 | 1429 | .source = ".{.baz = false}", |
| 1670 | 1430 | .diag = null, |
| 1671 | 1431 | }); |
| ... | ... | @@ -1673,21 +1433,25 @@ test "std.zon unions" { |
| 1673 | 1433 | |
| 1674 | 1434 | const alloc = try fromSliceAlloc(Union, .{ |
| 1675 | 1435 | .gpa = gpa, |
| 1436 | .arena = arena, |
| 1676 | 1437 | .source = ".{.bar = \"qux\"}", |
| 1677 | 1438 | .diag = null, |
| 1678 | 1439 | }); |
| 1679 | | defer free(gpa, alloc); |
| 1680 | 1440 | try std.testing.expectEqualDeep(Union{ .bar = "qux" }, alloc); |
| 1681 | 1441 | } |
| 1682 | 1442 | |
| 1683 | 1443 | // Unknown field |
| 1684 | 1444 | { |
| 1685 | 1445 | const Union = union { x: f32, y: f32 }; |
| 1686 | | var diag: Diagnostics = .{}; |
| 1687 | | defer diag.deinit(gpa); |
| 1446 | var diag: Diagnostics = .init(arena); |
| 1688 | 1447 | try std.testing.expectError( |
| 1689 | 1448 | error.ParseZon, |
| 1690 | | fromSliceAlloc(Union, .{ .gpa = gpa, .source = ".{.z=2.5}", .diag = &diag }), |
| 1449 | fromSliceAlloc(Union, .{ |
| 1450 | .gpa = gpa, |
| 1451 | .arena = arena, |
| 1452 | .source = ".{.z=2.5}", |
| 1453 | .diag = &diag, |
| 1454 | }), |
| 1691 | 1455 | ); |
| 1692 | 1456 | try std.testing.expectFmt( |
| 1693 | 1457 | \\1:4: error: unexpected field 'z' |
| ... | ... | @@ -1702,11 +1466,15 @@ test "std.zon unions" { |
| 1702 | 1466 | // Explicit void field |
| 1703 | 1467 | { |
| 1704 | 1468 | const Union = union(enum) { x: void }; |
| 1705 | | var diag: Diagnostics = .{}; |
| 1706 | | defer diag.deinit(gpa); |
| 1469 | var diag: Diagnostics = .init(arena); |
| 1707 | 1470 | try std.testing.expectError( |
| 1708 | 1471 | error.ParseZon, |
| 1709 | | fromSliceAlloc(Union, .{ .gpa = gpa, .source = ".{.x=1}", .diag = &diag }), |
| 1472 | fromSliceAlloc(Union, .{ |
| 1473 | .gpa = gpa, |
| 1474 | .arena = arena, |
| 1475 | .source = ".{.x=1}", |
| 1476 | .diag = &diag, |
| 1477 | }), |
| 1710 | 1478 | ); |
| 1711 | 1479 | try std.testing.expectFmt("1:6: error: expected type 'void'\n", "{f}", .{diag}); |
| 1712 | 1480 | } |
| ... | ... | @@ -1714,12 +1482,12 @@ test "std.zon unions" { |
| 1714 | 1482 | // Extra field |
| 1715 | 1483 | { |
| 1716 | 1484 | const Union = union { x: f32, y: bool }; |
| 1717 | | var diag: Diagnostics = .{}; |
| 1718 | | defer diag.deinit(gpa); |
| 1485 | var diag: Diagnostics = .init(arena); |
| 1719 | 1486 | try std.testing.expectError( |
| 1720 | 1487 | error.ParseZon, |
| 1721 | 1488 | fromSliceAlloc(Union, .{ |
| 1722 | 1489 | .gpa = gpa, |
| 1490 | .arena = arena, |
| 1723 | 1491 | .source = ".{.x = 1.5, .y = true}", |
| 1724 | 1492 | .diag = &diag, |
| 1725 | 1493 | }), |
| ... | ... | @@ -1730,11 +1498,15 @@ test "std.zon unions" { |
| 1730 | 1498 | // No fields |
| 1731 | 1499 | { |
| 1732 | 1500 | const Union = union { x: f32, y: bool }; |
| 1733 | | var diag: Diagnostics = .{}; |
| 1734 | | defer diag.deinit(gpa); |
| 1501 | var diag: Diagnostics = .init(arena); |
| 1735 | 1502 | try std.testing.expectError( |
| 1736 | 1503 | error.ParseZon, |
| 1737 | | fromSliceAlloc(Union, .{ .gpa = gpa, .source = ".{}", .diag = &diag }), |
| 1504 | fromSliceAlloc(Union, .{ |
| 1505 | .gpa = gpa, |
| 1506 | .arena = arena, |
| 1507 | .source = ".{}", |
| 1508 | .diag = &diag, |
| 1509 | }), |
| 1738 | 1510 | ); |
| 1739 | 1511 | try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag}); |
| 1740 | 1512 | } |
| ... | ... | @@ -1742,10 +1514,10 @@ test "std.zon unions" { |
| 1742 | 1514 | // Enum literals cannot coerce into untagged unions |
| 1743 | 1515 | { |
| 1744 | 1516 | const Union = union { x: void }; |
| 1745 | | var diag: Diagnostics = .{}; |
| 1746 | | defer diag.deinit(gpa); |
| 1517 | var diag: Diagnostics = .init(arena); |
| 1747 | 1518 | try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, .{ |
| 1748 | 1519 | .gpa = gpa, |
| 1520 | .arena = arena, |
| 1749 | 1521 | .source = ".x", |
| 1750 | 1522 | .diag = &diag, |
| 1751 | 1523 | })); |
| ... | ... | @@ -1755,10 +1527,10 @@ test "std.zon unions" { |
| 1755 | 1527 | // Unknown field for enum literal coercion |
| 1756 | 1528 | { |
| 1757 | 1529 | const Union = union(enum) { x: void }; |
| 1758 | | var diag: Diagnostics = .{}; |
| 1759 | | defer diag.deinit(gpa); |
| 1530 | var diag: Diagnostics = .init(arena); |
| 1760 | 1531 | try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, .{ |
| 1761 | 1532 | .gpa = gpa, |
| 1533 | .arena = arena, |
| 1762 | 1534 | .source = ".y", |
| 1763 | 1535 | .diag = &diag, |
| 1764 | 1536 | })); |
| ... | ... | @@ -1775,10 +1547,10 @@ test "std.zon unions" { |
| 1775 | 1547 | // Non void field for enum literal coercion |
| 1776 | 1548 | { |
| 1777 | 1549 | const Union = union(enum) { x: f32 }; |
| 1778 | | var diag: Diagnostics = .{}; |
| 1779 | | defer diag.deinit(gpa); |
| 1550 | var diag: Diagnostics = .init(arena); |
| 1780 | 1551 | try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, .{ |
| 1781 | 1552 | .gpa = gpa, |
| 1553 | .arena = arena, |
| 1782 | 1554 | .source = ".x", |
| 1783 | 1555 | .diag = &diag, |
| 1784 | 1556 | })); |
| ... | ... | @@ -1788,6 +1560,9 @@ test "std.zon unions" { |
| 1788 | 1560 | |
| 1789 | 1561 | test "std.zon structs" { |
| 1790 | 1562 | const gpa = std.testing.allocator; |
| 1563 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 1564 | defer arena_allocator.deinit(); |
| 1565 | const arena = arena_allocator.allocator(); |
| 1791 | 1566 | |
| 1792 | 1567 | // Structs (various sizes tested since they're parsed differently) |
| 1793 | 1568 | { |
| ... | ... | @@ -1831,21 +1606,24 @@ test "std.zon structs" { |
| 1831 | 1606 | |
| 1832 | 1607 | const parsed = try fromSliceAlloc(Foo, .{ |
| 1833 | 1608 | .gpa = gpa, |
| 1609 | .arena = arena, |
| 1834 | 1610 | .source = ".{.bar = \"qux\", .baz = .{\"a\", \"b\"}}", |
| 1835 | 1611 | .diag = null, |
| 1836 | 1612 | }); |
| 1837 | | defer free(gpa, parsed); |
| 1838 | 1613 | try std.testing.expectEqualDeep(Foo{ .bar = "qux", .baz = &.{ "a", "b" } }, parsed); |
| 1839 | 1614 | } |
| 1840 | 1615 | |
| 1841 | 1616 | // Unknown field |
| 1842 | 1617 | { |
| 1843 | 1618 | const Vec2 = struct { x: f32, y: f32 }; |
| 1844 | | var diag: Diagnostics = .{}; |
| 1845 | | defer diag.deinit(gpa); |
| 1619 | var diag: Diagnostics = .init(arena); |
| 1846 | 1620 | try std.testing.expectError( |
| 1847 | 1621 | error.ParseZon, |
| 1848 | | fromSlice(Vec2, .{ .gpa = gpa, .source = ".{.x=1.5, .z=2.5}", .diag = &diag }), |
| 1622 | fromSlice(Vec2, .{ |
| 1623 | .gpa = gpa, |
| 1624 | .source = ".{.x=1.5, .z=2.5}", |
| 1625 | .diag = &diag, |
| 1626 | }), |
| 1849 | 1627 | ); |
| 1850 | 1628 | try std.testing.expectFmt( |
| 1851 | 1629 | \\1:12: error: unexpected field 'z' |
| ... | ... | @@ -1860,11 +1638,14 @@ test "std.zon structs" { |
| 1860 | 1638 | // Duplicate field |
| 1861 | 1639 | { |
| 1862 | 1640 | const Vec2 = struct { x: f32, y: f32 }; |
| 1863 | | var diag: Diagnostics = .{}; |
| 1864 | | defer diag.deinit(gpa); |
| 1641 | var diag: Diagnostics = .init(arena); |
| 1865 | 1642 | try std.testing.expectError( |
| 1866 | 1643 | error.ParseZon, |
| 1867 | | fromSlice(Vec2, .{ .gpa = gpa, .source = ".{.x=1.5, .x=2.5, .x=3.5}", .diag = &diag }), |
| 1644 | fromSlice(Vec2, .{ |
| 1645 | .gpa = gpa, |
| 1646 | .source = ".{.x=1.5, .x=2.5, .x=3.5}", |
| 1647 | .diag = &diag, |
| 1648 | }), |
| 1868 | 1649 | ); |
| 1869 | 1650 | try std.testing.expectFmt( |
| 1870 | 1651 | \\1:4: error: duplicate struct field name |
| ... | ... | @@ -1888,11 +1669,14 @@ test "std.zon structs" { |
| 1888 | 1669 | // Unknown field when struct has no fields (regression test) |
| 1889 | 1670 | { |
| 1890 | 1671 | const Vec2 = struct {}; |
| 1891 | | var diag: Diagnostics = .{}; |
| 1892 | | defer diag.deinit(gpa); |
| 1672 | var diag: Diagnostics = .init(arena); |
| 1893 | 1673 | try std.testing.expectError( |
| 1894 | 1674 | error.ParseZon, |
| 1895 | | fromSlice(Vec2, .{ .gpa = gpa, .source = ".{.x=1.5, .z=2.5}", .diag = &diag }), |
| 1675 | fromSlice(Vec2, .{ |
| 1676 | .gpa = gpa, |
| 1677 | .source = ".{.x=1.5, .z=2.5}", |
| 1678 | .diag = &diag, |
| 1679 | }), |
| 1896 | 1680 | ); |
| 1897 | 1681 | try std.testing.expectFmt( |
| 1898 | 1682 | \\1:4: error: unexpected field 'x' |
| ... | ... | @@ -1904,11 +1688,14 @@ test "std.zon structs" { |
| 1904 | 1688 | // Missing field |
| 1905 | 1689 | { |
| 1906 | 1690 | const Vec2 = struct { x: f32, y: f32 }; |
| 1907 | | var diag: Diagnostics = .{}; |
| 1908 | | defer diag.deinit(gpa); |
| 1691 | var diag: Diagnostics = .init(arena); |
| 1909 | 1692 | try std.testing.expectError( |
| 1910 | 1693 | error.ParseZon, |
| 1911 | | fromSlice(Vec2, .{ .gpa = gpa, .source = ".{.x=1.5}", .diag = &diag }), |
| 1694 | fromSlice(Vec2, .{ |
| 1695 | .gpa = gpa, |
| 1696 | .source = ".{.x=1.5}", |
| 1697 | .diag = &diag, |
| 1698 | }), |
| 1912 | 1699 | ); |
| 1913 | 1700 | try std.testing.expectFmt("1:2: error: missing required field y\n", "{f}", .{diag}); |
| 1914 | 1701 | } |
| ... | ... | @@ -1916,22 +1703,29 @@ test "std.zon structs" { |
| 1916 | 1703 | // Default field |
| 1917 | 1704 | { |
| 1918 | 1705 | const Vec2 = struct { x: f32, y: f32 = 1.5 }; |
| 1919 | | const parsed = try fromSlice(Vec2, .{ .gpa = gpa, .source = ".{.x = 1.2}", .diag = null }); |
| 1706 | const parsed = try fromSlice(Vec2, .{ |
| 1707 | .gpa = gpa, |
| 1708 | .source = ".{.x = 1.2}", |
| 1709 | .diag = null, |
| 1710 | }); |
| 1920 | 1711 | try std.testing.expectEqual(Vec2{ .x = 1.2, .y = 1.5 }, parsed); |
| 1921 | 1712 | } |
| 1922 | 1713 | |
| 1923 | 1714 | // Comptime field |
| 1924 | 1715 | { |
| 1925 | 1716 | const Vec2 = struct { x: f32, comptime y: f32 = 1.5 }; |
| 1926 | | const parsed = try fromSlice(Vec2, .{ .gpa = gpa, .source = ".{.x = 1.2}", .diag = null }); |
| 1717 | const parsed = try fromSlice(Vec2, .{ |
| 1718 | .gpa = gpa, |
| 1719 | .source = ".{.x = 1.2}", |
| 1720 | .diag = null, |
| 1721 | }); |
| 1927 | 1722 | try std.testing.expectEqual(Vec2{ .x = 1.2, .y = 1.5 }, parsed); |
| 1928 | 1723 | } |
| 1929 | 1724 | |
| 1930 | 1725 | // Comptime field assignment |
| 1931 | 1726 | { |
| 1932 | 1727 | const Vec2 = struct { x: f32, comptime y: f32 = 1.5 }; |
| 1933 | | var diag: Diagnostics = .{}; |
| 1934 | | defer diag.deinit(gpa); |
| 1728 | var diag: Diagnostics = .init(arena); |
| 1935 | 1729 | const parsed = fromSlice(Vec2, .{ |
| 1936 | 1730 | .gpa = gpa, |
| 1937 | 1731 | .source = ".{.x = 1.2, .y = 1.5}", |
| ... | ... | @@ -1971,8 +1765,7 @@ test "std.zon structs" { |
| 1971 | 1765 | { |
| 1972 | 1766 | // Structs |
| 1973 | 1767 | { |
| 1974 | | var diag: Diagnostics = .{}; |
| 1975 | | defer diag.deinit(gpa); |
| 1768 | var diag: Diagnostics = .init(arena); |
| 1976 | 1769 | const parsed = fromSlice(struct {}, .{ |
| 1977 | 1770 | .gpa = gpa, |
| 1978 | 1771 | .source = "Empty{}", |
| ... | ... | @@ -1988,8 +1781,7 @@ test "std.zon structs" { |
| 1988 | 1781 | |
| 1989 | 1782 | // Arrays |
| 1990 | 1783 | { |
| 1991 | | var diag: Diagnostics = .{}; |
| 1992 | | defer diag.deinit(gpa); |
| 1784 | var diag: Diagnostics = .init(arena); |
| 1993 | 1785 | const parsed = fromSlice([3]u8, .{ |
| 1994 | 1786 | .gpa = gpa, |
| 1995 | 1787 | .source = "[3]u8{1, 2, 3}", |
| ... | ... | @@ -2005,10 +1797,10 @@ test "std.zon structs" { |
| 2005 | 1797 | |
| 2006 | 1798 | // Slices |
| 2007 | 1799 | { |
| 2008 | | var diag: Diagnostics = .{}; |
| 2009 | | defer diag.deinit(gpa); |
| 1800 | var diag: Diagnostics = .init(arena); |
| 2010 | 1801 | const parsed = fromSliceAlloc([]u8, .{ |
| 2011 | 1802 | .gpa = gpa, |
| 1803 | .arena = arena, |
| 2012 | 1804 | .source = "[]u8{1, 2, 3}", |
| 2013 | 1805 | .diag = &diag, |
| 2014 | 1806 | }); |
| ... | ... | @@ -2022,8 +1814,7 @@ test "std.zon structs" { |
| 2022 | 1814 | |
| 2023 | 1815 | // Tuples |
| 2024 | 1816 | { |
| 2025 | | var diag: Diagnostics = .{}; |
| 2026 | | defer diag.deinit(gpa); |
| 1817 | var diag: Diagnostics = .init(arena); |
| 2027 | 1818 | const parsed = fromSlice(struct { u8, u8, u8 }, .{ |
| 2028 | 1819 | .gpa = gpa, |
| 2029 | 1820 | .source = "Tuple{1, 2, 3}", |
| ... | ... | @@ -2039,8 +1830,7 @@ test "std.zon structs" { |
| 2039 | 1830 | |
| 2040 | 1831 | // Nested |
| 2041 | 1832 | { |
| 2042 | | var diag: Diagnostics = .{}; |
| 2043 | | defer diag.deinit(gpa); |
| 1833 | var diag: Diagnostics = .init(arena); |
| 2044 | 1834 | const parsed = fromSlice(struct {}, .{ |
| 2045 | 1835 | .gpa = gpa, |
| 2046 | 1836 | .source = ".{ .x = Tuple{1, 2, 3} }", |
| ... | ... | @@ -2058,6 +1848,9 @@ test "std.zon structs" { |
| 2058 | 1848 | |
| 2059 | 1849 | test "std.zon tuples" { |
| 2060 | 1850 | const gpa = std.testing.allocator; |
| 1851 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 1852 | defer arena_allocator.deinit(); |
| 1853 | const arena = arena_allocator.allocator(); |
| 2061 | 1854 | |
| 2062 | 1855 | // Structs (various sizes tested since they're parsed differently) |
| 2063 | 1856 | { |
| ... | ... | @@ -2100,21 +1893,24 @@ test "std.zon tuples" { |
| 2100 | 1893 | const Tuple = struct { []const u8, []const u8 }; |
| 2101 | 1894 | const parsed = try fromSliceAlloc(Tuple, .{ |
| 2102 | 1895 | .gpa = gpa, |
| 1896 | .arena = arena, |
| 2103 | 1897 | .source = ".{\"hello\", \"world\"}", |
| 2104 | 1898 | .diag = null, |
| 2105 | 1899 | }); |
| 2106 | | defer free(gpa, parsed); |
| 2107 | 1900 | try std.testing.expectEqualDeep(Tuple{ "hello", "world" }, parsed); |
| 2108 | 1901 | } |
| 2109 | 1902 | |
| 2110 | 1903 | // Extra field |
| 2111 | 1904 | { |
| 2112 | 1905 | const Tuple = struct { f32, bool }; |
| 2113 | | var diag: Diagnostics = .{}; |
| 2114 | | defer diag.deinit(gpa); |
| 1906 | var diag: Diagnostics = .init(arena); |
| 2115 | 1907 | try std.testing.expectError( |
| 2116 | 1908 | error.ParseZon, |
| 2117 | | fromSlice(Tuple, .{ .gpa = gpa, .source = ".{0.5, true, 123}", .diag = &diag }), |
| 1909 | fromSlice(Tuple, .{ |
| 1910 | .gpa = gpa, |
| 1911 | .source = ".{0.5, true, 123}", |
| 1912 | .diag = &diag, |
| 1913 | }), |
| 2118 | 1914 | ); |
| 2119 | 1915 | try std.testing.expectFmt("1:14: error: index 2 outside of tuple length 2\n", "{f}", .{diag}); |
| 2120 | 1916 | } |
| ... | ... | @@ -2122,11 +1918,14 @@ test "std.zon tuples" { |
| 2122 | 1918 | // Extra field |
| 2123 | 1919 | { |
| 2124 | 1920 | const Tuple = struct { f32, bool }; |
| 2125 | | var diag: Diagnostics = .{}; |
| 2126 | | defer diag.deinit(gpa); |
| 1921 | var diag: Diagnostics = .init(arena); |
| 2127 | 1922 | try std.testing.expectError( |
| 2128 | 1923 | error.ParseZon, |
| 2129 | | fromSlice(Tuple, .{ .gpa = gpa, .source = ".{0.5}", .diag = &diag }), |
| 1924 | fromSlice(Tuple, .{ |
| 1925 | .gpa = gpa, |
| 1926 | .source = ".{0.5}", |
| 1927 | .diag = &diag, |
| 1928 | }), |
| 2130 | 1929 | ); |
| 2131 | 1930 | try std.testing.expectFmt( |
| 2132 | 1931 | "1:2: error: missing tuple field with index 1\n", |
| ... | ... | @@ -2138,11 +1937,14 @@ test "std.zon tuples" { |
| 2138 | 1937 | // Tuple with unexpected field names |
| 2139 | 1938 | { |
| 2140 | 1939 | const Tuple = struct { f32 }; |
| 2141 | | var diag: Diagnostics = .{}; |
| 2142 | | defer diag.deinit(gpa); |
| 1940 | var diag: Diagnostics = .init(arena); |
| 2143 | 1941 | try std.testing.expectError( |
| 2144 | 1942 | error.ParseZon, |
| 2145 | | fromSlice(Tuple, .{ .gpa = gpa, .source = ".{.foo = 10.0}", .diag = &diag }), |
| 1943 | fromSlice(Tuple, .{ |
| 1944 | .gpa = gpa, |
| 1945 | .source = ".{.foo = 10.0}", |
| 1946 | .diag = &diag, |
| 1947 | }), |
| 2146 | 1948 | ); |
| 2147 | 1949 | try std.testing.expectFmt("1:2: error: expected tuple\n", "{f}", .{diag}); |
| 2148 | 1950 | } |
| ... | ... | @@ -2150,11 +1952,14 @@ test "std.zon tuples" { |
| 2150 | 1952 | // Struct with missing field names |
| 2151 | 1953 | { |
| 2152 | 1954 | const Struct = struct { foo: f32 }; |
| 2153 | | var diag: Diagnostics = .{}; |
| 2154 | | defer diag.deinit(gpa); |
| 1955 | var diag: Diagnostics = .init(arena); |
| 2155 | 1956 | try std.testing.expectError( |
| 2156 | 1957 | error.ParseZon, |
| 2157 | | fromSlice(Struct, .{ .gpa = gpa, .source = ".{10.0}", .diag = &diag }), |
| 1958 | fromSlice(Struct, .{ |
| 1959 | .gpa = gpa, |
| 1960 | .source = ".{10.0}", |
| 1961 | .diag = &diag, |
| 1962 | }), |
| 2158 | 1963 | ); |
| 2159 | 1964 | try std.testing.expectFmt("1:2: error: expected struct\n", "{f}", .{diag}); |
| 2160 | 1965 | } |
| ... | ... | @@ -2162,16 +1967,23 @@ test "std.zon tuples" { |
| 2162 | 1967 | // Comptime field |
| 2163 | 1968 | { |
| 2164 | 1969 | const Vec2 = struct { f32, comptime f32 = 1.5 }; |
| 2165 | | const parsed = try fromSlice(Vec2, .{ .gpa = gpa, .source = ".{ 1.2 }", .diag = null }); |
| 1970 | const parsed = try fromSlice(Vec2, .{ |
| 1971 | .gpa = gpa, |
| 1972 | .source = ".{ 1.2 }", |
| 1973 | .diag = null, |
| 1974 | }); |
| 2166 | 1975 | try std.testing.expectEqual(Vec2{ 1.2, 1.5 }, parsed); |
| 2167 | 1976 | } |
| 2168 | 1977 | |
| 2169 | 1978 | // Comptime field assignment |
| 2170 | 1979 | { |
| 2171 | 1980 | const Vec2 = struct { f32, comptime f32 = 1.5 }; |
| 2172 | | var diag: Diagnostics = .{}; |
| 2173 | | defer diag.deinit(gpa); |
| 2174 | | const parsed = fromSlice(Vec2, .{ .gpa = gpa, .source = ".{ 1.2, 1.5}", .diag = &diag }); |
| 1981 | var diag: Diagnostics = .init(arena); |
| 1982 | const parsed = fromSlice(Vec2, .{ |
| 1983 | .gpa = gpa, |
| 1984 | .source = ".{ 1.2, 1.5}", |
| 1985 | .diag = &diag, |
| 1986 | }); |
| 2175 | 1987 | try std.testing.expectError(error.ParseZon, parsed); |
| 2176 | 1988 | try std.testing.expectFmt( |
| 2177 | 1989 | \\1:9: error: cannot initialize comptime field |
| ... | ... | @@ -2183,6 +1995,9 @@ test "std.zon tuples" { |
| 2183 | 1995 | // Test sizes 0 to 3 since small sizes get parsed differently |
| 2184 | 1996 | test "std.zon arrays and slices" { |
| 2185 | 1997 | const gpa = std.testing.allocator; |
| 1998 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 1999 | defer arena_allocator.deinit(); |
| 2000 | const arena = arena_allocator.allocator(); |
| 2186 | 2001 | |
| 2187 | 2002 | // Literals |
| 2188 | 2003 | { |
| ... | ... | @@ -2236,50 +2051,50 @@ test "std.zon arrays and slices" { |
| 2236 | 2051 | { |
| 2237 | 2052 | const zero = try fromSliceAlloc([]const u8, .{ |
| 2238 | 2053 | .gpa = gpa, |
| 2054 | .arena = arena, |
| 2239 | 2055 | .source = ".{}", |
| 2240 | 2056 | .diag = null, |
| 2241 | 2057 | }); |
| 2242 | | defer free(gpa, zero); |
| 2243 | 2058 | try std.testing.expectEqualSlices(u8, @as([]const u8, &.{}), zero); |
| 2244 | 2059 | |
| 2245 | 2060 | const one = try fromSliceAlloc([]u8, .{ |
| 2246 | 2061 | .gpa = gpa, |
| 2062 | .arena = arena, |
| 2247 | 2063 | .source = ".{'a'}", |
| 2248 | 2064 | .diag = null, |
| 2249 | 2065 | }); |
| 2250 | | defer free(gpa, one); |
| 2251 | 2066 | try std.testing.expectEqualSlices(u8, &.{'a'}, one); |
| 2252 | 2067 | |
| 2253 | 2068 | const two = try fromSliceAlloc([]const u8, .{ |
| 2254 | 2069 | .gpa = gpa, |
| 2070 | .arena = arena, |
| 2255 | 2071 | .source = ".{'a', 'b'}", |
| 2256 | 2072 | .diag = null, |
| 2257 | 2073 | }); |
| 2258 | | defer free(gpa, two); |
| 2259 | 2074 | try std.testing.expectEqualSlices(u8, &.{ 'a', 'b' }, two); |
| 2260 | 2075 | |
| 2261 | 2076 | const two_comma = try fromSliceAlloc([]const u8, .{ |
| 2262 | 2077 | .gpa = gpa, |
| 2078 | .arena = arena, |
| 2263 | 2079 | .source = ".{'a', 'b',}", |
| 2264 | 2080 | .diag = null, |
| 2265 | 2081 | }); |
| 2266 | | defer free(gpa, two_comma); |
| 2267 | 2082 | try std.testing.expectEqualSlices(u8, &.{ 'a', 'b' }, two_comma); |
| 2268 | 2083 | |
| 2269 | 2084 | const three = try fromSliceAlloc([]u8, .{ |
| 2270 | 2085 | .gpa = gpa, |
| 2086 | .arena = arena, |
| 2271 | 2087 | .source = ".{'a', 'b', 'c'}", |
| 2272 | 2088 | .diag = null, |
| 2273 | 2089 | }); |
| 2274 | | defer free(gpa, three); |
| 2275 | 2090 | try std.testing.expectEqualSlices(u8, &.{ 'a', 'b', 'c' }, three); |
| 2276 | 2091 | |
| 2277 | 2092 | const sentinel = try fromSliceAlloc([:'z']const u8, .{ |
| 2278 | 2093 | .gpa = gpa, |
| 2094 | .arena = arena, |
| 2279 | 2095 | .source = ".{'a', 'b', 'c'}", |
| 2280 | 2096 | .diag = null, |
| 2281 | 2097 | }); |
| 2282 | | defer free(gpa, sentinel); |
| 2283 | 2098 | const expected_sentinel: [:'z']const u8 = &.{ 'a', 'b', 'c' }; |
| 2284 | 2099 | try std.testing.expectEqualSlices(u8, expected_sentinel, sentinel); |
| 2285 | 2100 | } |
| ... | ... | @@ -2291,10 +2106,10 @@ test "std.zon arrays and slices" { |
| 2291 | 2106 | { |
| 2292 | 2107 | const parsed = try fromSliceAlloc([1][]const u8, .{ |
| 2293 | 2108 | .gpa = gpa, |
| 2109 | .arena = arena, |
| 2294 | 2110 | .source = ".{\"abc\"}", |
| 2295 | 2111 | .diag = null, |
| 2296 | 2112 | }); |
| 2297 | | defer free(gpa, parsed); |
| 2298 | 2113 | const expected: [1][]const u8 = .{"abc"}; |
| 2299 | 2114 | try std.testing.expectEqualDeep(expected, parsed); |
| 2300 | 2115 | } |
| ... | ... | @@ -2303,10 +2118,10 @@ test "std.zon arrays and slices" { |
| 2303 | 2118 | { |
| 2304 | 2119 | const parsed = try fromSliceAlloc([]const []const u8, .{ |
| 2305 | 2120 | .gpa = gpa, |
| 2121 | .arena = arena, |
| 2306 | 2122 | .source = ".{\"abc\"}", |
| 2307 | 2123 | .diag = null, |
| 2308 | 2124 | }); |
| 2309 | | defer free(gpa, parsed); |
| 2310 | 2125 | const expected: []const []const u8 = &.{"abc"}; |
| 2311 | 2126 | try std.testing.expectEqualDeep(expected, parsed); |
| 2312 | 2127 | } |
| ... | ... | @@ -2330,10 +2145,10 @@ test "std.zon arrays and slices" { |
| 2330 | 2145 | { |
| 2331 | 2146 | const sentinel = try fromSliceAlloc([:2]align(4) u8, .{ |
| 2332 | 2147 | .gpa = gpa, |
| 2148 | .arena = arena, |
| 2333 | 2149 | .source = ".{1}", |
| 2334 | 2150 | .diag = null, |
| 2335 | 2151 | }); |
| 2336 | | defer free(gpa, sentinel); |
| 2337 | 2152 | try std.testing.expectEqual(@as(usize, 1), sentinel.len); |
| 2338 | 2153 | try std.testing.expectEqual(@as(u8, 1), sentinel[0]); |
| 2339 | 2154 | try std.testing.expectEqual(@as(u8, 2), sentinel[1]); |
| ... | ... | @@ -2342,11 +2157,14 @@ test "std.zon arrays and slices" { |
| 2342 | 2157 | |
| 2343 | 2158 | // Expect 0 find 3 |
| 2344 | 2159 | { |
| 2345 | | var diag: Diagnostics = .{}; |
| 2346 | | defer diag.deinit(gpa); |
| 2160 | var diag: Diagnostics = .init(arena); |
| 2347 | 2161 | try std.testing.expectError( |
| 2348 | 2162 | error.ParseZon, |
| 2349 | | fromSlice([0]u8, .{ .gpa = gpa, .source = ".{'a', 'b', 'c'}", .diag = &diag }), |
| 2163 | fromSlice([0]u8, .{ |
| 2164 | .gpa = gpa, |
| 2165 | .source = ".{'a', 'b', 'c'}", |
| 2166 | .diag = &diag, |
| 2167 | }), |
| 2350 | 2168 | ); |
| 2351 | 2169 | try std.testing.expectFmt( |
| 2352 | 2170 | "1:3: error: index 0 outside of array of length 0\n", |
| ... | ... | @@ -2357,11 +2175,14 @@ test "std.zon arrays and slices" { |
| 2357 | 2175 | |
| 2358 | 2176 | // Expect 1 find 2 |
| 2359 | 2177 | { |
| 2360 | | var diag: Diagnostics = .{}; |
| 2361 | | defer diag.deinit(gpa); |
| 2178 | var diag: Diagnostics = .init(arena); |
| 2362 | 2179 | try std.testing.expectError( |
| 2363 | 2180 | error.ParseZon, |
| 2364 | | fromSlice([1]u8, .{ .gpa = gpa, .source = ".{'a', 'b'}", .diag = &diag }), |
| 2181 | fromSlice([1]u8, .{ |
| 2182 | .gpa = gpa, |
| 2183 | .source = ".{'a', 'b'}", |
| 2184 | .diag = &diag, |
| 2185 | }), |
| 2365 | 2186 | ); |
| 2366 | 2187 | try std.testing.expectFmt( |
| 2367 | 2188 | "1:8: error: index 1 outside of array of length 1\n", |
| ... | ... | @@ -2372,11 +2193,14 @@ test "std.zon arrays and slices" { |
| 2372 | 2193 | |
| 2373 | 2194 | // Expect 2 find 1 |
| 2374 | 2195 | { |
| 2375 | | var diag: Diagnostics = .{}; |
| 2376 | | defer diag.deinit(gpa); |
| 2196 | var diag: Diagnostics = .init(arena); |
| 2377 | 2197 | try std.testing.expectError( |
| 2378 | 2198 | error.ParseZon, |
| 2379 | | fromSlice([2]u8, .{ .gpa = gpa, .source = ".{'a'}", .diag = &diag }), |
| 2199 | fromSlice([2]u8, .{ |
| 2200 | .gpa = gpa, |
| 2201 | .source = ".{'a'}", |
| 2202 | .diag = &diag, |
| 2203 | }), |
| 2380 | 2204 | ); |
| 2381 | 2205 | try std.testing.expectFmt( |
| 2382 | 2206 | "1:2: error: expected 2 array elements; found 1\n", |
| ... | ... | @@ -2387,11 +2211,14 @@ test "std.zon arrays and slices" { |
| 2387 | 2211 | |
| 2388 | 2212 | // Expect 3 find 0 |
| 2389 | 2213 | { |
| 2390 | | var diag: Diagnostics = .{}; |
| 2391 | | defer diag.deinit(gpa); |
| 2214 | var diag: Diagnostics = .init(arena); |
| 2392 | 2215 | try std.testing.expectError( |
| 2393 | 2216 | error.ParseZon, |
| 2394 | | fromSlice([3]u8, .{ .gpa = gpa, .source = ".{}", .diag = &diag }), |
| 2217 | fromSlice([3]u8, .{ |
| 2218 | .gpa = gpa, |
| 2219 | .source = ".{}", |
| 2220 | .diag = &diag, |
| 2221 | }), |
| 2395 | 2222 | ); |
| 2396 | 2223 | try std.testing.expectFmt( |
| 2397 | 2224 | "1:2: error: expected 3 array elements; found 0\n", |
| ... | ... | @@ -2404,23 +2231,26 @@ test "std.zon arrays and slices" { |
| 2404 | 2231 | { |
| 2405 | 2232 | // Array |
| 2406 | 2233 | { |
| 2407 | | var diag: Diagnostics = .{}; |
| 2408 | | defer diag.deinit(gpa); |
| 2234 | var diag: Diagnostics = .init(arena); |
| 2409 | 2235 | try std.testing.expectError( |
| 2410 | 2236 | error.ParseZon, |
| 2411 | | fromSlice([3]bool, .{ .gpa = gpa, .source = ".{'a', 'b', 'c'}", .diag = &diag }), |
| 2237 | fromSlice([3]bool, .{ |
| 2238 | .gpa = gpa, |
| 2239 | .source = ".{'a', 'b', 'c'}", |
| 2240 | .diag = &diag, |
| 2241 | }), |
| 2412 | 2242 | ); |
| 2413 | 2243 | try std.testing.expectFmt("1:3: error: expected type 'bool'\n", "{f}", .{diag}); |
| 2414 | 2244 | } |
| 2415 | 2245 | |
| 2416 | 2246 | // Slice |
| 2417 | 2247 | { |
| 2418 | | var diag: Diagnostics = .{}; |
| 2419 | | defer diag.deinit(gpa); |
| 2248 | var diag: Diagnostics = .init(arena); |
| 2420 | 2249 | try std.testing.expectError( |
| 2421 | 2250 | error.ParseZon, |
| 2422 | 2251 | fromSliceAlloc([]bool, .{ |
| 2423 | 2252 | .gpa = gpa, |
| 2253 | .arena = arena, |
| 2424 | 2254 | .source = ".{'a', 'b', 'c'}", |
| 2425 | 2255 | .diag = &diag, |
| 2426 | 2256 | }), |
| ... | ... | @@ -2433,22 +2263,24 @@ test "std.zon arrays and slices" { |
| 2433 | 2263 | { |
| 2434 | 2264 | // Array |
| 2435 | 2265 | { |
| 2436 | | var diag: Diagnostics = .{}; |
| 2437 | | defer diag.deinit(gpa); |
| 2266 | var diag: Diagnostics = .init(arena); |
| 2438 | 2267 | try std.testing.expectError( |
| 2439 | 2268 | error.ParseZon, |
| 2440 | | fromSlice([3]u8, .{ .gpa = gpa, .source = "'a'", .diag = &diag }), |
| 2269 | fromSlice([3]u8, .{ |
| 2270 | .gpa = gpa, |
| 2271 | .source = "'a'", |
| 2272 | .diag = &diag, |
| 2273 | }), |
| 2441 | 2274 | ); |
| 2442 | 2275 | try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); |
| 2443 | 2276 | } |
| 2444 | 2277 | |
| 2445 | 2278 | // Slice |
| 2446 | 2279 | { |
| 2447 | | var diag: Diagnostics = .{}; |
| 2448 | | defer diag.deinit(gpa); |
| 2280 | var diag: Diagnostics = .init(arena); |
| 2449 | 2281 | try std.testing.expectError( |
| 2450 | 2282 | error.ParseZon, |
| 2451 | | fromSliceAlloc([]u8, .{ .gpa = gpa, .source = "'a'", .diag = &diag }), |
| 2283 | fromSliceAlloc([]u8, .{ .gpa = gpa, .arena = arena, .source = "'a'", .diag = &diag }), |
| 2452 | 2284 | ); |
| 2453 | 2285 | try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); |
| 2454 | 2286 | } |
| ... | ... | @@ -2456,11 +2288,10 @@ test "std.zon arrays and slices" { |
| 2456 | 2288 | |
| 2457 | 2289 | // Address of is not allowed (indirection for slices in ZON is implicit) |
| 2458 | 2290 | { |
| 2459 | | var diag: Diagnostics = .{}; |
| 2460 | | defer diag.deinit(gpa); |
| 2291 | var diag: Diagnostics = .init(arena); |
| 2461 | 2292 | try std.testing.expectError( |
| 2462 | 2293 | error.ParseZon, |
| 2463 | | fromSliceAlloc([]u8, .{ .gpa = gpa, .source = " &.{'a', 'b', 'c'}", .diag = &diag }), |
| 2294 | fromSliceAlloc([]u8, .{ .gpa = gpa, .arena = arena, .source = " &.{'a', 'b', 'c'}", .diag = &diag }), |
| 2464 | 2295 | ); |
| 2465 | 2296 | try std.testing.expectFmt( |
| 2466 | 2297 | "1:3: error: pointers are not available in ZON\n", |
| ... | ... | @@ -2472,15 +2303,18 @@ test "std.zon arrays and slices" { |
| 2472 | 2303 | |
| 2473 | 2304 | test "std.zon string literal" { |
| 2474 | 2305 | const gpa = std.testing.allocator; |
| 2306 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 2307 | defer arena_allocator.deinit(); |
| 2308 | const arena = arena_allocator.allocator(); |
| 2475 | 2309 | |
| 2476 | 2310 | // Basic string literal |
| 2477 | 2311 | { |
| 2478 | 2312 | const parsed = try fromSliceAlloc([]const u8, .{ |
| 2479 | 2313 | .gpa = gpa, |
| 2314 | .arena = arena, |
| 2480 | 2315 | .source = "\"abc\"", |
| 2481 | 2316 | .diag = null, |
| 2482 | 2317 | }); |
| 2483 | | defer free(gpa, parsed); |
| 2484 | 2318 | try std.testing.expectEqualStrings(@as([]const u8, "abc"), parsed); |
| 2485 | 2319 | } |
| 2486 | 2320 | |
| ... | ... | @@ -2488,10 +2322,10 @@ test "std.zon string literal" { |
| 2488 | 2322 | { |
| 2489 | 2323 | const parsed = try fromSliceAlloc([]const u8, .{ |
| 2490 | 2324 | .gpa = gpa, |
| 2325 | .arena = arena, |
| 2491 | 2326 | .source = "\"ab\\nc\"", |
| 2492 | 2327 | .diag = null, |
| 2493 | 2328 | }); |
| 2494 | | defer free(gpa, parsed); |
| 2495 | 2329 | try std.testing.expectEqualStrings(@as([]const u8, "ab\nc"), parsed); |
| 2496 | 2330 | } |
| 2497 | 2331 | |
| ... | ... | @@ -2499,31 +2333,29 @@ test "std.zon string literal" { |
| 2499 | 2333 | { |
| 2500 | 2334 | const parsed = try fromSliceAlloc([]const u8, .{ |
| 2501 | 2335 | .gpa = gpa, |
| 2336 | .arena = arena, |
| 2502 | 2337 | .source = "\"ab\\x00c\"", |
| 2503 | 2338 | .diag = null, |
| 2504 | 2339 | }); |
| 2505 | | defer free(gpa, parsed); |
| 2506 | 2340 | try std.testing.expectEqualStrings(@as([]const u8, "ab\x00c"), parsed); |
| 2507 | 2341 | } |
| 2508 | 2342 | |
| 2509 | 2343 | // Passing string literal to a mutable slice |
| 2510 | 2344 | { |
| 2511 | 2345 | { |
| 2512 | | var diag: Diagnostics = .{}; |
| 2513 | | defer diag.deinit(gpa); |
| 2346 | var diag: Diagnostics = .init(arena); |
| 2514 | 2347 | try std.testing.expectError( |
| 2515 | 2348 | error.ParseZon, |
| 2516 | | fromSliceAlloc([]u8, .{ .gpa = gpa, .source = "\"abcd\"", .diag = &diag }), |
| 2349 | fromSliceAlloc([]u8, .{ .gpa = gpa, .arena = arena, .source = "\"abcd\"", .diag = &diag }), |
| 2517 | 2350 | ); |
| 2518 | 2351 | try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); |
| 2519 | 2352 | } |
| 2520 | 2353 | |
| 2521 | 2354 | { |
| 2522 | | var diag: Diagnostics = .{}; |
| 2523 | | defer diag.deinit(gpa); |
| 2355 | var diag: Diagnostics = .init(arena); |
| 2524 | 2356 | try std.testing.expectError( |
| 2525 | 2357 | error.ParseZon, |
| 2526 | | fromSliceAlloc([]u8, .{ .gpa = gpa, .source = "\\\\abcd", .diag = &diag }), |
| 2358 | fromSliceAlloc([]u8, .{ .gpa = gpa, .arena = arena, .source = "\\\\abcd", .diag = &diag }), |
| 2527 | 2359 | ); |
| 2528 | 2360 | try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); |
| 2529 | 2361 | } |
| ... | ... | @@ -2536,21 +2368,27 @@ test "std.zon string literal" { |
| 2536 | 2368 | defer ast.deinit(gpa); |
| 2537 | 2369 | var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false }); |
| 2538 | 2370 | defer zoir.deinit(gpa); |
| 2539 | | var diag: Diagnostics = .{}; |
| 2540 | | defer diag.deinit(gpa); |
| 2371 | var diag: Diagnostics = .init(arena); |
| 2541 | 2372 | try std.testing.expectError( |
| 2542 | 2373 | error.ParseZon, |
| 2543 | | fromSlice([4:0]u8, .{ .gpa = gpa, .source = "\"abcd\"", .diag = &diag }), |
| 2374 | fromSlice([4:0]u8, .{ |
| 2375 | .gpa = gpa, |
| 2376 | .source = "\"abcd\"", |
| 2377 | .diag = &diag, |
| 2378 | }), |
| 2544 | 2379 | ); |
| 2545 | 2380 | try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); |
| 2546 | 2381 | } |
| 2547 | 2382 | |
| 2548 | 2383 | { |
| 2549 | | var diag: Diagnostics = .{}; |
| 2550 | | defer diag.deinit(gpa); |
| 2384 | var diag: Diagnostics = .init(arena); |
| 2551 | 2385 | try std.testing.expectError( |
| 2552 | 2386 | error.ParseZon, |
| 2553 | | fromSlice([4:0]u8, .{ .gpa = gpa, .source = "\\\\abcd", .diag = &diag }), |
| 2387 | fromSlice([4:0]u8, .{ |
| 2388 | .gpa = gpa, |
| 2389 | .source = "\\\\abcd", |
| 2390 | .diag = &diag, |
| 2391 | }), |
| 2554 | 2392 | ); |
| 2555 | 2393 | try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); |
| 2556 | 2394 | } |
| ... | ... | @@ -2561,10 +2399,10 @@ test "std.zon string literal" { |
| 2561 | 2399 | { |
| 2562 | 2400 | const parsed: [:0]const u8 = try fromSliceAlloc([:0]const u8, .{ |
| 2563 | 2401 | .gpa = gpa, |
| 2402 | .arena = arena, |
| 2564 | 2403 | .source = "\"abc\"", |
| 2565 | 2404 | .diag = null, |
| 2566 | 2405 | }); |
| 2567 | | defer free(gpa, parsed); |
| 2568 | 2406 | try std.testing.expectEqualStrings("abc", parsed); |
| 2569 | 2407 | try std.testing.expectEqual(@as(u8, 0), parsed[3]); |
| 2570 | 2408 | } |
| ... | ... | @@ -2572,10 +2410,10 @@ test "std.zon string literal" { |
| 2572 | 2410 | { |
| 2573 | 2411 | const parsed: [:0]const u8 = try fromSliceAlloc([:0]const u8, .{ |
| 2574 | 2412 | .gpa = gpa, |
| 2413 | .arena = arena, |
| 2575 | 2414 | .source = "\\\\abc", |
| 2576 | 2415 | .diag = null, |
| 2577 | 2416 | }); |
| 2578 | | defer free(gpa, parsed); |
| 2579 | 2417 | try std.testing.expectEqualStrings("abc", parsed); |
| 2580 | 2418 | try std.testing.expectEqual(@as(u8, 0), parsed[3]); |
| 2581 | 2419 | } |
| ... | ... | @@ -2584,21 +2422,19 @@ test "std.zon string literal" { |
| 2584 | 2422 | // Other value terminated slices |
| 2585 | 2423 | { |
| 2586 | 2424 | { |
| 2587 | | var diag: Diagnostics = .{}; |
| 2588 | | defer diag.deinit(gpa); |
| 2425 | var diag: Diagnostics = .init(arena); |
| 2589 | 2426 | try std.testing.expectError( |
| 2590 | 2427 | error.ParseZon, |
| 2591 | | fromSliceAlloc([:1]const u8, .{ .gpa = gpa, .source = "\"foo\"", .diag = &diag }), |
| 2428 | fromSliceAlloc([:1]const u8, .{ .gpa = gpa, .arena = arena, .source = "\"foo\"", .diag = &diag }), |
| 2592 | 2429 | ); |
| 2593 | 2430 | try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); |
| 2594 | 2431 | } |
| 2595 | 2432 | |
| 2596 | 2433 | { |
| 2597 | | var diag: Diagnostics = .{}; |
| 2598 | | defer diag.deinit(gpa); |
| 2434 | var diag: Diagnostics = .init(arena); |
| 2599 | 2435 | try std.testing.expectError( |
| 2600 | 2436 | error.ParseZon, |
| 2601 | | fromSliceAlloc([:1]const u8, .{ .gpa = gpa, .source = "\\\\foo", .diag = &diag }), |
| 2437 | fromSliceAlloc([:1]const u8, .{ .gpa = gpa, .arena = arena, .source = "\\\\foo", .diag = &diag }), |
| 2602 | 2438 | ); |
| 2603 | 2439 | try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); |
| 2604 | 2440 | } |
| ... | ... | @@ -2606,33 +2442,30 @@ test "std.zon string literal" { |
| 2606 | 2442 | |
| 2607 | 2443 | // Expecting string literal, getting something else |
| 2608 | 2444 | { |
| 2609 | | var diag: Diagnostics = .{}; |
| 2610 | | defer diag.deinit(gpa); |
| 2445 | var diag: Diagnostics = .init(arena); |
| 2611 | 2446 | try std.testing.expectError( |
| 2612 | 2447 | error.ParseZon, |
| 2613 | | fromSliceAlloc([]const u8, .{ .gpa = gpa, .source = "true", .diag = &diag }), |
| 2448 | fromSliceAlloc([]const u8, .{ .gpa = gpa, .arena = arena, .source = "true", .diag = &diag }), |
| 2614 | 2449 | ); |
| 2615 | 2450 | try std.testing.expectFmt("1:1: error: expected string\n", "{f}", .{diag}); |
| 2616 | 2451 | } |
| 2617 | 2452 | |
| 2618 | 2453 | // Expecting string literal, getting an incompatible tuple |
| 2619 | 2454 | { |
| 2620 | | var diag: Diagnostics = .{}; |
| 2621 | | defer diag.deinit(gpa); |
| 2455 | var diag: Diagnostics = .init(arena); |
| 2622 | 2456 | try std.testing.expectError( |
| 2623 | 2457 | error.ParseZon, |
| 2624 | | fromSliceAlloc([]const u8, .{ .gpa = gpa, .source = ".{false}", .diag = &diag }), |
| 2458 | fromSliceAlloc([]const u8, .{ .gpa = gpa, .arena = arena, .source = ".{false}", .diag = &diag }), |
| 2625 | 2459 | ); |
| 2626 | 2460 | try std.testing.expectFmt("1:3: error: expected type 'u8'\n", "{f}", .{diag}); |
| 2627 | 2461 | } |
| 2628 | 2462 | |
| 2629 | 2463 | // Invalid string literal |
| 2630 | 2464 | { |
| 2631 | | var diag: Diagnostics = .{}; |
| 2632 | | defer diag.deinit(gpa); |
| 2465 | var diag: Diagnostics = .init(arena); |
| 2633 | 2466 | try std.testing.expectError( |
| 2634 | 2467 | error.ParseZon, |
| 2635 | | fromSliceAlloc([]const i8, .{ .gpa = gpa, .source = "\"\\a\"", .diag = &diag }), |
| 2468 | fromSliceAlloc([]const i8, .{ .gpa = gpa, .arena = arena, .source = "\"\\a\"", .diag = &diag }), |
| 2636 | 2469 | ); |
| 2637 | 2470 | try std.testing.expectFmt("1:3: error: invalid escape character: 'a'\n", "{f}", .{diag}); |
| 2638 | 2471 | } |
| ... | ... | @@ -2640,21 +2473,19 @@ test "std.zon string literal" { |
| 2640 | 2473 | // Slice wrong child type |
| 2641 | 2474 | { |
| 2642 | 2475 | { |
| 2643 | | var diag: Diagnostics = .{}; |
| 2644 | | defer diag.deinit(gpa); |
| 2476 | var diag: Diagnostics = .init(arena); |
| 2645 | 2477 | try std.testing.expectError( |
| 2646 | 2478 | error.ParseZon, |
| 2647 | | fromSliceAlloc([]const i8, .{ .gpa = gpa, .source = "\"a\"", .diag = &diag }), |
| 2479 | fromSliceAlloc([]const i8, .{ .gpa = gpa, .arena = arena, .source = "\"a\"", .diag = &diag }), |
| 2648 | 2480 | ); |
| 2649 | 2481 | try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); |
| 2650 | 2482 | } |
| 2651 | 2483 | |
| 2652 | 2484 | { |
| 2653 | | var diag: Diagnostics = .{}; |
| 2654 | | defer diag.deinit(gpa); |
| 2485 | var diag: Diagnostics = .init(arena); |
| 2655 | 2486 | try std.testing.expectError( |
| 2656 | 2487 | error.ParseZon, |
| 2657 | | fromSliceAlloc([]const i8, .{ .gpa = gpa, .source = "\\\\a", .diag = &diag }), |
| 2488 | fromSliceAlloc([]const i8, .{ .gpa = gpa, .arena = arena, .source = "\\\\a", .diag = &diag }), |
| 2658 | 2489 | ); |
| 2659 | 2490 | try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); |
| 2660 | 2491 | } |
| ... | ... | @@ -2663,12 +2494,12 @@ test "std.zon string literal" { |
| 2663 | 2494 | // Bad alignment |
| 2664 | 2495 | { |
| 2665 | 2496 | { |
| 2666 | | var diag: Diagnostics = .{}; |
| 2667 | | defer diag.deinit(gpa); |
| 2497 | var diag: Diagnostics = .init(arena); |
| 2668 | 2498 | try std.testing.expectError( |
| 2669 | 2499 | error.ParseZon, |
| 2670 | 2500 | fromSliceAlloc([]align(2) const u8, .{ |
| 2671 | 2501 | .gpa = gpa, |
| 2502 | .arena = arena, |
| 2672 | 2503 | .source = "\"abc\"", |
| 2673 | 2504 | .diag = &diag, |
| 2674 | 2505 | }), |
| ... | ... | @@ -2677,12 +2508,12 @@ test "std.zon string literal" { |
| 2677 | 2508 | } |
| 2678 | 2509 | |
| 2679 | 2510 | { |
| 2680 | | var diag: Diagnostics = .{}; |
| 2681 | | defer diag.deinit(gpa); |
| 2511 | var diag: Diagnostics = .init(arena); |
| 2682 | 2512 | try std.testing.expectError( |
| 2683 | 2513 | error.ParseZon, |
| 2684 | 2514 | fromSliceAlloc([]align(2) const u8, .{ |
| 2685 | 2515 | .gpa = gpa, |
| 2516 | .arena = arena, |
| 2686 | 2517 | .source = "\\\\abc", |
| 2687 | 2518 | .diag = &diag, |
| 2688 | 2519 | }), |
| ... | ... | @@ -2702,6 +2533,7 @@ test "std.zon string literal" { |
| 2702 | 2533 | }; |
| 2703 | 2534 | const parsed = try fromSliceAlloc(S, .{ |
| 2704 | 2535 | .gpa = gpa, |
| 2536 | .arena = arena, |
| 2705 | 2537 | .source = |
| 2706 | 2538 | \\.{ |
| 2707 | 2539 | \\ .message = |
| ... | ... | @@ -2722,7 +2554,6 @@ test "std.zon string literal" { |
| 2722 | 2554 | , |
| 2723 | 2555 | .diag = null, |
| 2724 | 2556 | }); |
| 2725 | | defer free(gpa, parsed); |
| 2726 | 2557 | try std.testing.expectEqualStrings( |
| 2727 | 2558 | "hello, world!\nthis is a multiline string!\n\n...", |
| 2728 | 2559 | parsed.message, |
| ... | ... | @@ -2735,6 +2566,9 @@ test "std.zon string literal" { |
| 2735 | 2566 | |
| 2736 | 2567 | test "std.zon enum literals" { |
| 2737 | 2568 | const gpa = std.testing.allocator; |
| 2569 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 2570 | defer arena_allocator.deinit(); |
| 2571 | const arena = arena_allocator.allocator(); |
| 2738 | 2572 | |
| 2739 | 2573 | const Enum = enum { |
| 2740 | 2574 | foo, |
| ... | ... | @@ -2761,16 +2595,23 @@ test "std.zon enum literals" { |
| 2761 | 2595 | })); |
| 2762 | 2596 | try std.testing.expectEqual( |
| 2763 | 2597 | Enum.@"ab\nc", |
| 2764 | | try fromSlice(Enum, .{ .gpa = gpa, .source = ".@\"ab\\nc\"", .diag = null }), |
| 2598 | try fromSlice(Enum, .{ |
| 2599 | .gpa = gpa, |
| 2600 | .source = ".@\"ab\\nc\"", |
| 2601 | .diag = null, |
| 2602 | }), |
| 2765 | 2603 | ); |
| 2766 | 2604 | |
| 2767 | 2605 | // Bad tag |
| 2768 | 2606 | { |
| 2769 | | var diag: Diagnostics = .{}; |
| 2770 | | defer diag.deinit(gpa); |
| 2607 | var diag: Diagnostics = .init(arena); |
| 2771 | 2608 | try std.testing.expectError( |
| 2772 | 2609 | error.ParseZon, |
| 2773 | | fromSlice(Enum, .{ .gpa = gpa, .source = ".qux", .diag = &diag }), |
| 2610 | fromSlice(Enum, .{ |
| 2611 | .gpa = gpa, |
| 2612 | .source = ".qux", |
| 2613 | .diag = &diag, |
| 2614 | }), |
| 2774 | 2615 | ); |
| 2775 | 2616 | try std.testing.expectFmt( |
| 2776 | 2617 | \\1:2: error: unexpected enum literal 'qux' |
| ... | ... | @@ -2784,11 +2625,14 @@ test "std.zon enum literals" { |
| 2784 | 2625 | |
| 2785 | 2626 | // Bad tag that's too long for parser |
| 2786 | 2627 | { |
| 2787 | | var diag: Diagnostics = .{}; |
| 2788 | | defer diag.deinit(gpa); |
| 2628 | var diag: Diagnostics = .init(arena); |
| 2789 | 2629 | try std.testing.expectError( |
| 2790 | 2630 | error.ParseZon, |
| 2791 | | fromSlice(Enum, .{ .gpa = gpa, .source = ".@\"foobarbaz\"", .diag = &diag }), |
| 2631 | fromSlice(Enum, .{ |
| 2632 | .gpa = gpa, |
| 2633 | .source = ".@\"foobarbaz\"", |
| 2634 | .diag = &diag, |
| 2635 | }), |
| 2792 | 2636 | ); |
| 2793 | 2637 | try std.testing.expectFmt( |
| 2794 | 2638 | \\1:2: error: unexpected enum literal 'foobarbaz' |
| ... | ... | @@ -2802,22 +2646,28 @@ test "std.zon enum literals" { |
| 2802 | 2646 | |
| 2803 | 2647 | // Bad type |
| 2804 | 2648 | { |
| 2805 | | var diag: Diagnostics = .{}; |
| 2806 | | defer diag.deinit(gpa); |
| 2649 | var diag: Diagnostics = .init(arena); |
| 2807 | 2650 | try std.testing.expectError( |
| 2808 | 2651 | error.ParseZon, |
| 2809 | | fromSlice(Enum, .{ .gpa = gpa, .source = "true", .diag = &diag }), |
| 2652 | fromSlice(Enum, .{ |
| 2653 | .gpa = gpa, |
| 2654 | .source = "true", |
| 2655 | .diag = &diag, |
| 2656 | }), |
| 2810 | 2657 | ); |
| 2811 | 2658 | try std.testing.expectFmt("1:1: error: expected enum literal\n", "{f}", .{diag}); |
| 2812 | 2659 | } |
| 2813 | 2660 | |
| 2814 | 2661 | // Test embedded nulls in an identifier |
| 2815 | 2662 | { |
| 2816 | | var diag: Diagnostics = .{}; |
| 2817 | | defer diag.deinit(gpa); |
| 2663 | var diag: Diagnostics = .init(arena); |
| 2818 | 2664 | try std.testing.expectError( |
| 2819 | 2665 | error.ParseZon, |
| 2820 | | fromSlice(Enum, .{ .gpa = gpa, .source = ".@\"\\x00\"", .diag = &diag }), |
| 2666 | fromSlice(Enum, .{ |
| 2667 | .gpa = gpa, |
| 2668 | .source = ".@\"\\x00\"", |
| 2669 | .diag = &diag, |
| 2670 | }), |
| 2821 | 2671 | ); |
| 2822 | 2672 | try std.testing.expectFmt( |
| 2823 | 2673 | "1:2: error: identifier cannot contain null bytes\n", |
| ... | ... | @@ -2829,6 +2679,9 @@ test "std.zon enum literals" { |
| 2829 | 2679 | |
| 2830 | 2680 | test "std.zon parse bool" { |
| 2831 | 2681 | const gpa = std.testing.allocator; |
| 2682 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 2683 | defer arena_allocator.deinit(); |
| 2684 | const arena = arena_allocator.allocator(); |
| 2832 | 2685 | |
| 2833 | 2686 | // Correct bools |
| 2834 | 2687 | try std.testing.expectEqual(true, try fromSlice(bool, .{ |
| ... | ... | @@ -2844,11 +2697,14 @@ test "std.zon parse bool" { |
| 2844 | 2697 | |
| 2845 | 2698 | // Errors |
| 2846 | 2699 | { |
| 2847 | | var diag: Diagnostics = .{}; |
| 2848 | | defer diag.deinit(gpa); |
| 2700 | var diag: Diagnostics = .init(arena); |
| 2849 | 2701 | try std.testing.expectError( |
| 2850 | 2702 | error.ParseZon, |
| 2851 | | fromSlice(bool, .{ .gpa = gpa, .source = " foo", .diag = &diag }), |
| 2703 | fromSlice(bool, .{ |
| 2704 | .gpa = gpa, |
| 2705 | .source = " foo", |
| 2706 | .diag = &diag, |
| 2707 | }), |
| 2852 | 2708 | ); |
| 2853 | 2709 | try std.testing.expectFmt( |
| 2854 | 2710 | \\1:2: error: invalid expression |
| ... | ... | @@ -2858,8 +2714,7 @@ test "std.zon parse bool" { |
| 2858 | 2714 | , "{f}", .{diag}); |
| 2859 | 2715 | } |
| 2860 | 2716 | { |
| 2861 | | var diag: Diagnostics = .{}; |
| 2862 | | defer diag.deinit(gpa); |
| 2717 | var diag: Diagnostics = .init(arena); |
| 2863 | 2718 | try std.testing.expectError(error.ParseZon, fromSlice(bool, .{ |
| 2864 | 2719 | .gpa = gpa, |
| 2865 | 2720 | .source = "123", |
| ... | ... | @@ -2893,6 +2748,9 @@ test "std.zon intFromFloatExact" { |
| 2893 | 2748 | |
| 2894 | 2749 | test "std.zon parse int" { |
| 2895 | 2750 | const gpa = std.testing.allocator; |
| 2751 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 2752 | defer arena_allocator.deinit(); |
| 2753 | const arena = arena_allocator.allocator(); |
| 2896 | 2754 | |
| 2897 | 2755 | // Test various numbers and types |
| 2898 | 2756 | try std.testing.expectEqual(@as(u8, 10), try fromSlice(u8, .{ |
| ... | ... | @@ -2984,8 +2842,7 @@ test "std.zon parse int" { |
| 2984 | 2842 | }), |
| 2985 | 2843 | ); |
| 2986 | 2844 | { |
| 2987 | | var diag: Diagnostics = .{}; |
| 2988 | | defer diag.deinit(gpa); |
| 2845 | var diag: Diagnostics = .init(arena); |
| 2989 | 2846 | try std.testing.expectError(error.ParseZon, fromSlice(i66, .{ |
| 2990 | 2847 | .gpa = gpa, |
| 2991 | 2848 | .source = "36893488147419103232", |
| ... | ... | @@ -2998,8 +2855,7 @@ test "std.zon parse int" { |
| 2998 | 2855 | ); |
| 2999 | 2856 | } |
| 3000 | 2857 | { |
| 3001 | | var diag: Diagnostics = .{}; |
| 3002 | | defer diag.deinit(gpa); |
| 2858 | var diag: Diagnostics = .init(arena); |
| 3003 | 2859 | try std.testing.expectError(error.ParseZon, fromSlice(i66, .{ |
| 3004 | 2860 | .gpa = gpa, |
| 3005 | 2861 | .source = "-36893488147419103233", |
| ... | ... | @@ -3105,8 +2961,7 @@ test "std.zon parse int" { |
| 3105 | 2961 | |
| 3106 | 2962 | // Number with invalid character in the middle |
| 3107 | 2963 | { |
| 3108 | | var diag: Diagnostics = .{}; |
| 3109 | | defer diag.deinit(gpa); |
| 2964 | var diag: Diagnostics = .init(arena); |
| 3110 | 2965 | try std.testing.expectError(error.ParseZon, fromSlice(u8, .{ |
| 3111 | 2966 | .gpa = gpa, |
| 3112 | 2967 | .source = "32a32", |
| ... | ... | @@ -3121,8 +2976,7 @@ test "std.zon parse int" { |
| 3121 | 2976 | |
| 3122 | 2977 | // Failing to parse as int |
| 3123 | 2978 | { |
| 3124 | | var diag: Diagnostics = .{}; |
| 3125 | | defer diag.deinit(gpa); |
| 2979 | var diag: Diagnostics = .init(arena); |
| 3126 | 2980 | try std.testing.expectError(error.ParseZon, fromSlice(u8, .{ |
| 3127 | 2981 | .gpa = gpa, |
| 3128 | 2982 | .source = "true", |
| ... | ... | @@ -3133,8 +2987,7 @@ test "std.zon parse int" { |
| 3133 | 2987 | |
| 3134 | 2988 | // Failing because an int is out of range |
| 3135 | 2989 | { |
| 3136 | | var diag: Diagnostics = .{}; |
| 3137 | | defer diag.deinit(gpa); |
| 2990 | var diag: Diagnostics = .init(arena); |
| 3138 | 2991 | try std.testing.expectError(error.ParseZon, fromSlice(u8, .{ |
| 3139 | 2992 | .gpa = gpa, |
| 3140 | 2993 | .source = "256", |
| ... | ... | @@ -3149,8 +3002,7 @@ test "std.zon parse int" { |
| 3149 | 3002 | |
| 3150 | 3003 | // Failing because a negative int is out of range |
| 3151 | 3004 | { |
| 3152 | | var diag: Diagnostics = .{}; |
| 3153 | | defer diag.deinit(gpa); |
| 3005 | var diag: Diagnostics = .init(arena); |
| 3154 | 3006 | try std.testing.expectError(error.ParseZon, fromSlice(i8, .{ |
| 3155 | 3007 | .gpa = gpa, |
| 3156 | 3008 | .source = "-129", |
| ... | ... | @@ -3165,8 +3017,7 @@ test "std.zon parse int" { |
| 3165 | 3017 | |
| 3166 | 3018 | // Failing because an unsigned int is negative |
| 3167 | 3019 | { |
| 3168 | | var diag: Diagnostics = .{}; |
| 3169 | | defer diag.deinit(gpa); |
| 3020 | var diag: Diagnostics = .init(arena); |
| 3170 | 3021 | try std.testing.expectError(error.ParseZon, fromSlice(u8, .{ |
| 3171 | 3022 | .gpa = gpa, |
| 3172 | 3023 | .source = "-1", |
| ... | ... | @@ -3181,8 +3032,7 @@ test "std.zon parse int" { |
| 3181 | 3032 | |
| 3182 | 3033 | // Failing because a float is non-whole |
| 3183 | 3034 | { |
| 3184 | | var diag: Diagnostics = .{}; |
| 3185 | | defer diag.deinit(gpa); |
| 3035 | var diag: Diagnostics = .init(arena); |
| 3186 | 3036 | try std.testing.expectError(error.ParseZon, fromSlice(u8, .{ |
| 3187 | 3037 | .gpa = gpa, |
| 3188 | 3038 | .source = "1.5", |
| ... | ... | @@ -3197,8 +3047,7 @@ test "std.zon parse int" { |
| 3197 | 3047 | |
| 3198 | 3048 | // Failing because a float is negative |
| 3199 | 3049 | { |
| 3200 | | var diag: Diagnostics = .{}; |
| 3201 | | defer diag.deinit(gpa); |
| 3050 | var diag: Diagnostics = .init(arena); |
| 3202 | 3051 | try std.testing.expectError(error.ParseZon, fromSlice(u8, .{ |
| 3203 | 3052 | .gpa = gpa, |
| 3204 | 3053 | .source = "-1.0", |
| ... | ... | @@ -3213,8 +3062,7 @@ test "std.zon parse int" { |
| 3213 | 3062 | |
| 3214 | 3063 | // Negative integer zero |
| 3215 | 3064 | { |
| 3216 | | var diag: Diagnostics = .{}; |
| 3217 | | defer diag.deinit(gpa); |
| 3065 | var diag: Diagnostics = .init(arena); |
| 3218 | 3066 | try std.testing.expectError(error.ParseZon, fromSlice(i8, .{ |
| 3219 | 3067 | .gpa = gpa, |
| 3220 | 3068 | .source = "-0", |
| ... | ... | @@ -3230,8 +3078,7 @@ test "std.zon parse int" { |
| 3230 | 3078 | |
| 3231 | 3079 | // Negative integer zero casted to float |
| 3232 | 3080 | { |
| 3233 | | var diag: Diagnostics = .{}; |
| 3234 | | defer diag.deinit(gpa); |
| 3081 | var diag: Diagnostics = .init(arena); |
| 3235 | 3082 | try std.testing.expectError(error.ParseZon, fromSlice(f32, .{ |
| 3236 | 3083 | .gpa = gpa, |
| 3237 | 3084 | .source = "-0", |
| ... | ... | @@ -3261,8 +3108,7 @@ test "std.zon parse int" { |
| 3261 | 3108 | |
| 3262 | 3109 | // Double negation is not allowed |
| 3263 | 3110 | { |
| 3264 | | var diag: Diagnostics = .{}; |
| 3265 | | defer diag.deinit(gpa); |
| 3111 | var diag: Diagnostics = .init(arena); |
| 3266 | 3112 | try std.testing.expectError(error.ParseZon, fromSlice(i8, .{ |
| 3267 | 3113 | .gpa = gpa, |
| 3268 | 3114 | .source = "--2", |
| ... | ... | @@ -3276,11 +3122,14 @@ test "std.zon parse int" { |
| 3276 | 3122 | } |
| 3277 | 3123 | |
| 3278 | 3124 | { |
| 3279 | | var diag: Diagnostics = .{}; |
| 3280 | | defer diag.deinit(gpa); |
| 3125 | var diag: Diagnostics = .init(arena); |
| 3281 | 3126 | try std.testing.expectError( |
| 3282 | 3127 | error.ParseZon, |
| 3283 | | fromSlice(f32, .{ .gpa = gpa, .source = "--2.0", .diag = &diag }), |
| 3128 | fromSlice(f32, .{ |
| 3129 | .gpa = gpa, |
| 3130 | .source = "--2.0", |
| 3131 | .diag = &diag, |
| 3132 | }), |
| 3284 | 3133 | ); |
| 3285 | 3134 | try std.testing.expectFmt( |
| 3286 | 3135 | "1:1: error: expected number or 'inf' after '-'\n", |
| ... | ... | @@ -3291,8 +3140,7 @@ test "std.zon parse int" { |
| 3291 | 3140 | |
| 3292 | 3141 | // Invalid int literal |
| 3293 | 3142 | { |
| 3294 | | var diag: Diagnostics = .{}; |
| 3295 | | defer diag.deinit(gpa); |
| 3143 | var diag: Diagnostics = .init(arena); |
| 3296 | 3144 | try std.testing.expectError(error.ParseZon, fromSlice(u8, .{ |
| 3297 | 3145 | .gpa = gpa, |
| 3298 | 3146 | .source = "0xg", |
| ... | ... | @@ -3303,8 +3151,7 @@ test "std.zon parse int" { |
| 3303 | 3151 | |
| 3304 | 3152 | // Notes on invalid int literal |
| 3305 | 3153 | { |
| 3306 | | var diag: Diagnostics = .{}; |
| 3307 | | defer diag.deinit(gpa); |
| 3154 | var diag: Diagnostics = .init(arena); |
| 3308 | 3155 | try std.testing.expectError(error.ParseZon, fromSlice(u8, .{ |
| 3309 | 3156 | .gpa = gpa, |
| 3310 | 3157 | .source = "0123", |
| ... | ... | @@ -3320,10 +3167,12 @@ test "std.zon parse int" { |
| 3320 | 3167 | |
| 3321 | 3168 | test "std.zon negative char" { |
| 3322 | 3169 | const gpa = std.testing.allocator; |
| 3170 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 3171 | defer arena_allocator.deinit(); |
| 3172 | const arena = arena_allocator.allocator(); |
| 3323 | 3173 | |
| 3324 | 3174 | { |
| 3325 | | var diag: Diagnostics = .{}; |
| 3326 | | defer diag.deinit(gpa); |
| 3175 | var diag: Diagnostics = .init(arena); |
| 3327 | 3176 | try std.testing.expectError(error.ParseZon, fromSlice(f32, .{ |
| 3328 | 3177 | .gpa = gpa, |
| 3329 | 3178 | .source = "-'a'", |
| ... | ... | @@ -3336,8 +3185,7 @@ test "std.zon negative char" { |
| 3336 | 3185 | ); |
| 3337 | 3186 | } |
| 3338 | 3187 | { |
| 3339 | | var diag: Diagnostics = .{}; |
| 3340 | | defer diag.deinit(gpa); |
| 3188 | var diag: Diagnostics = .init(arena); |
| 3341 | 3189 | try std.testing.expectError(error.ParseZon, fromSlice(i16, .{ |
| 3342 | 3190 | .gpa = gpa, |
| 3343 | 3191 | .source = "-'a'", |
| ... | ... | @@ -3353,6 +3201,9 @@ test "std.zon negative char" { |
| 3353 | 3201 | |
| 3354 | 3202 | test "std.zon parse float" { |
| 3355 | 3203 | const gpa = std.testing.allocator; |
| 3204 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 3205 | defer arena_allocator.deinit(); |
| 3206 | const arena = arena_allocator.allocator(); |
| 3356 | 3207 | |
| 3357 | 3208 | // Test decimals |
| 3358 | 3209 | try std.testing.expectEqual(@as(f16, 0.5), try fromSlice(f16, .{ |
| ... | ... | @@ -3362,11 +3213,19 @@ test "std.zon parse float" { |
| 3362 | 3213 | })); |
| 3363 | 3214 | try std.testing.expectEqual( |
| 3364 | 3215 | @as(f32, 123.456), |
| 3365 | | try fromSlice(f32, .{ .gpa = gpa, .source = "123.456", .diag = null }), |
| 3216 | try fromSlice(f32, .{ |
| 3217 | .gpa = gpa, |
| 3218 | .source = "123.456", |
| 3219 | .diag = null, |
| 3220 | }), |
| 3366 | 3221 | ); |
| 3367 | 3222 | try std.testing.expectEqual( |
| 3368 | 3223 | @as(f64, -123.456), |
| 3369 | | try fromSlice(f64, .{ .gpa = gpa, .source = "-123.456", .diag = null }), |
| 3224 | try fromSlice(f64, .{ |
| 3225 | .gpa = gpa, |
| 3226 | .source = "-123.456", |
| 3227 | .diag = null, |
| 3228 | }), |
| 3370 | 3229 | ); |
| 3371 | 3230 | try std.testing.expectEqual(@as(f128, 42.5), try fromSlice(f128, .{ |
| 3372 | 3231 | .gpa = gpa, |
| ... | ... | @@ -3491,8 +3350,7 @@ test "std.zon parse float" { |
| 3491 | 3350 | |
| 3492 | 3351 | // Negative nan not allowed |
| 3493 | 3352 | { |
| 3494 | | var diag: Diagnostics = .{}; |
| 3495 | | defer diag.deinit(gpa); |
| 3353 | var diag: Diagnostics = .init(arena); |
| 3496 | 3354 | try std.testing.expectError(error.ParseZon, fromSlice(f32, .{ |
| 3497 | 3355 | .gpa = gpa, |
| 3498 | 3356 | .source = "-nan", |
| ... | ... | @@ -3507,8 +3365,7 @@ test "std.zon parse float" { |
| 3507 | 3365 | |
| 3508 | 3366 | // nan as int not allowed |
| 3509 | 3367 | { |
| 3510 | | var diag: Diagnostics = .{}; |
| 3511 | | defer diag.deinit(gpa); |
| 3368 | var diag: Diagnostics = .init(arena); |
| 3512 | 3369 | try std.testing.expectError(error.ParseZon, fromSlice(i8, .{ |
| 3513 | 3370 | .gpa = gpa, |
| 3514 | 3371 | .source = "nan", |
| ... | ... | @@ -3519,8 +3376,7 @@ test "std.zon parse float" { |
| 3519 | 3376 | |
| 3520 | 3377 | // nan as int not allowed |
| 3521 | 3378 | { |
| 3522 | | var diag: Diagnostics = .{}; |
| 3523 | | defer diag.deinit(gpa); |
| 3379 | var diag: Diagnostics = .init(arena); |
| 3524 | 3380 | try std.testing.expectError(error.ParseZon, fromSlice(i8, .{ |
| 3525 | 3381 | .gpa = gpa, |
| 3526 | 3382 | .source = "nan", |
| ... | ... | @@ -3531,8 +3387,7 @@ test "std.zon parse float" { |
| 3531 | 3387 | |
| 3532 | 3388 | // inf as int not allowed |
| 3533 | 3389 | { |
| 3534 | | var diag: Diagnostics = .{}; |
| 3535 | | defer diag.deinit(gpa); |
| 3390 | var diag: Diagnostics = .init(arena); |
| 3536 | 3391 | try std.testing.expectError(error.ParseZon, fromSlice(i8, .{ |
| 3537 | 3392 | .gpa = gpa, |
| 3538 | 3393 | .source = "inf", |
| ... | ... | @@ -3543,8 +3398,7 @@ test "std.zon parse float" { |
| 3543 | 3398 | |
| 3544 | 3399 | // -inf as int not allowed |
| 3545 | 3400 | { |
| 3546 | | var diag: Diagnostics = .{}; |
| 3547 | | defer diag.deinit(gpa); |
| 3401 | var diag: Diagnostics = .init(arena); |
| 3548 | 3402 | try std.testing.expectError(error.ParseZon, fromSlice(i8, .{ |
| 3549 | 3403 | .gpa = gpa, |
| 3550 | 3404 | .source = "-inf", |
| ... | ... | @@ -3555,8 +3409,7 @@ test "std.zon parse float" { |
| 3555 | 3409 | |
| 3556 | 3410 | // Bad identifier as float |
| 3557 | 3411 | { |
| 3558 | | var diag: Diagnostics = .{}; |
| 3559 | | defer diag.deinit(gpa); |
| 3412 | var diag: Diagnostics = .init(arena); |
| 3560 | 3413 | try std.testing.expectError(error.ParseZon, fromSlice(f32, .{ |
| 3561 | 3414 | .gpa = gpa, |
| 3562 | 3415 | .source = "foo", |
| ... | ... | @@ -3571,8 +3424,7 @@ test "std.zon parse float" { |
| 3571 | 3424 | } |
| 3572 | 3425 | |
| 3573 | 3426 | { |
| 3574 | | var diag: Diagnostics = .{}; |
| 3575 | | defer diag.deinit(gpa); |
| 3427 | var diag: Diagnostics = .init(arena); |
| 3576 | 3428 | try std.testing.expectError(error.ParseZon, fromSlice(f32, .{ |
| 3577 | 3429 | .gpa = gpa, |
| 3578 | 3430 | .source = "-foo", |
| ... | ... | @@ -3587,17 +3439,25 @@ test "std.zon parse float" { |
| 3587 | 3439 | |
| 3588 | 3440 | // Non float as float |
| 3589 | 3441 | { |
| 3590 | | var diag: Diagnostics = .{}; |
| 3591 | | defer diag.deinit(gpa); |
| 3442 | var diag: Diagnostics = .init(arena); |
| 3592 | 3443 | try std.testing.expectError( |
| 3593 | 3444 | error.ParseZon, |
| 3594 | | fromSlice(f32, .{ .gpa = gpa, .source = "\"foo\"", .diag = &diag }), |
| 3445 | fromSlice(f32, .{ |
| 3446 | .gpa = gpa, |
| 3447 | .source = "\"foo\"", |
| 3448 | .diag = &diag, |
| 3449 | }), |
| 3595 | 3450 | ); |
| 3596 | 3451 | try std.testing.expectFmt("1:1: error: expected type 'f32'\n", "{f}", .{diag}); |
| 3597 | 3452 | } |
| 3598 | 3453 | } |
| 3599 | 3454 | |
| 3600 | 3455 | test "std.zon free on error" { |
| 3456 | const gpa = std.testing.allocator; |
| 3457 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 3458 | defer arena_allocator.deinit(); |
| 3459 | const arena = arena_allocator.allocator(); |
| 3460 | |
| 3601 | 3461 | // Test freeing partially allocated structs |
| 3602 | 3462 | { |
| 3603 | 3463 | const Struct = struct { |
| ... | ... | @@ -3606,7 +3466,8 @@ test "std.zon free on error" { |
| 3606 | 3466 | z: bool, |
| 3607 | 3467 | }; |
| 3608 | 3468 | try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, .{ |
| 3609 | | .gpa = std.testing.allocator, |
| 3469 | .gpa = gpa, |
| 3470 | .arena = arena, |
| 3610 | 3471 | .source = |
| 3611 | 3472 | \\.{ |
| 3612 | 3473 | \\ .x = "hello", |
| ... | ... | @@ -3626,7 +3487,8 @@ test "std.zon free on error" { |
| 3626 | 3487 | bool, |
| 3627 | 3488 | }; |
| 3628 | 3489 | try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, .{ |
| 3629 | | .gpa = std.testing.allocator, |
| 3490 | .gpa = gpa, |
| 3491 | .arena = arena, |
| 3630 | 3492 | .source = |
| 3631 | 3493 | \\.{ |
| 3632 | 3494 | \\ "hello", |
| ... | ... | @@ -3639,58 +3501,55 @@ test "std.zon free on error" { |
| 3639 | 3501 | } |
| 3640 | 3502 | |
| 3641 | 3503 | // Test freeing structs with missing fields |
| 3642 | | { |
| 3643 | | const Struct = struct { |
| 3644 | | x: []const u8, |
| 3645 | | y: bool, |
| 3646 | | }; |
| 3647 | | try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, .{ |
| 3648 | | .gpa = std.testing.allocator, |
| 3649 | | .source = |
| 3650 | | \\.{ |
| 3651 | | \\ .x = "hello", |
| 3652 | | \\} |
| 3653 | | , |
| 3654 | | .diag = null, |
| 3655 | | })); |
| 3656 | | } |
| 3504 | const Struct = struct { |
| 3505 | x: []const u8, |
| 3506 | y: bool, |
| 3507 | }; |
| 3508 | try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, .{ |
| 3509 | .gpa = gpa, |
| 3510 | .arena = arena, |
| 3511 | .source = |
| 3512 | \\.{ |
| 3513 | \\ .x = "hello", |
| 3514 | \\} |
| 3515 | , |
| 3516 | .diag = null, |
| 3517 | })); |
| 3657 | 3518 | |
| 3658 | 3519 | // Test freeing partially allocated arrays |
| 3659 | | { |
| 3660 | | try std.testing.expectError(error.ParseZon, fromSliceAlloc([3][]const u8, .{ |
| 3661 | | .gpa = std.testing.allocator, |
| 3662 | | .source = |
| 3663 | | \\.{ |
| 3664 | | \\ "hello", |
| 3665 | | \\ false, |
| 3666 | | \\ false, |
| 3667 | | \\} |
| 3668 | | , |
| 3669 | | .diag = null, |
| 3670 | | })); |
| 3671 | | } |
| 3520 | try std.testing.expectError(error.ParseZon, fromSliceAlloc([3][]const u8, .{ |
| 3521 | .gpa = gpa, |
| 3522 | .arena = arena, |
| 3523 | .source = |
| 3524 | \\.{ |
| 3525 | \\ "hello", |
| 3526 | \\ false, |
| 3527 | \\ false, |
| 3528 | \\} |
| 3529 | , |
| 3530 | .diag = null, |
| 3531 | })); |
| 3672 | 3532 | |
| 3673 | 3533 | // Test freeing partially allocated slices |
| 3674 | | { |
| 3675 | | try std.testing.expectError(error.ParseZon, fromSliceAlloc([][]const u8, .{ |
| 3676 | | .gpa = std.testing.allocator, |
| 3677 | | .source = |
| 3678 | | \\.{ |
| 3679 | | \\ "hello", |
| 3680 | | \\ "world", |
| 3681 | | \\ false, |
| 3682 | | \\} |
| 3683 | | , |
| 3684 | | .diag = null, |
| 3685 | | })); |
| 3686 | | } |
| 3534 | try std.testing.expectError(error.ParseZon, fromSliceAlloc([][]const u8, .{ |
| 3535 | .gpa = gpa, |
| 3536 | .arena = arena, |
| 3537 | .source = |
| 3538 | \\.{ |
| 3539 | \\ "hello", |
| 3540 | \\ "world", |
| 3541 | \\ false, |
| 3542 | \\} |
| 3543 | , |
| 3544 | .diag = null, |
| 3545 | })); |
| 3687 | 3546 | |
| 3688 | 3547 | // We can parse types that can't be freed, as long as they contain no allocations, e.g. untagged |
| 3689 | 3548 | // unions. |
| 3690 | 3549 | try std.testing.expectEqual( |
| 3691 | 3550 | @as(f32, 1.5), |
| 3692 | 3551 | (try fromSlice(union { x: f32 }, .{ |
| 3693 | | .gpa = std.testing.allocator, |
| 3552 | .gpa = gpa, |
| 3694 | 3553 | .source = ".{ .x = 1.5 }", |
| 3695 | 3554 | .diag = null, |
| 3696 | 3555 | })).x, |
| ... | ... | @@ -3700,80 +3559,13 @@ test "std.zon free on error" { |
| 3700 | 3559 | // the allocation, as is the case here. |
| 3701 | 3560 | { |
| 3702 | 3561 | const result = try fromSliceAlloc(union { x: []const u8 }, .{ |
| 3703 | | .gpa = std.testing.allocator, |
| 3562 | .gpa = gpa, |
| 3563 | .arena = arena, |
| 3704 | 3564 | .source = ".{ .x = \"foo\" }", |
| 3705 | 3565 | .diag = null, |
| 3706 | 3566 | }); |
| 3707 | | defer free(std.testing.allocator, result.x); |
| 3708 | 3567 | try std.testing.expectEqualStrings("foo", result.x); |
| 3709 | 3568 | } |
| 3710 | | |
| 3711 | | // However, if it's possible we could get an error requiring we free the value, but the value |
| 3712 | | // cannot be freed (e.g. untagged unions) then we need to turn off `free_on_error` for it to |
| 3713 | | // compile. |
| 3714 | | { |
| 3715 | | const S = struct { |
| 3716 | | union { x: []const u8 }, |
| 3717 | | bool, |
| 3718 | | }; |
| 3719 | | const result = try fromSliceAlloc(S, .{ |
| 3720 | | .gpa = std.testing.allocator, |
| 3721 | | .source = ".{ .{ .x = \"foo\" }, true }", |
| 3722 | | .free_on_error = false, |
| 3723 | | .diag = null, |
| 3724 | | }); |
| 3725 | | defer free(std.testing.allocator, result[0].x); |
| 3726 | | try std.testing.expectEqualStrings("foo", result[0].x); |
| 3727 | | try std.testing.expect(result[1]); |
| 3728 | | } |
| 3729 | | |
| 3730 | | // Again but for structs. |
| 3731 | | { |
| 3732 | | const S = struct { |
| 3733 | | a: union { x: []const u8 }, |
| 3734 | | b: bool, |
| 3735 | | }; |
| 3736 | | const result = try fromSliceAlloc(S, .{ |
| 3737 | | .gpa = std.testing.allocator, |
| 3738 | | .source = ".{ .a = .{ .x = \"foo\" }, .b = true }", |
| 3739 | | .free_on_error = false, |
| 3740 | | .diag = null, |
| 3741 | | }); |
| 3742 | | defer free(std.testing.allocator, result.a.x); |
| 3743 | | try std.testing.expectEqualStrings("foo", result.a.x); |
| 3744 | | try std.testing.expect(result.b); |
| 3745 | | } |
| 3746 | | |
| 3747 | | // Again but for arrays. |
| 3748 | | { |
| 3749 | | const S = [2]union { x: []const u8 }; |
| 3750 | | const result = try fromSliceAlloc(S, .{ |
| 3751 | | .gpa = std.testing.allocator, |
| 3752 | | .source = ".{ .{ .x = \"foo\" }, .{ .x = \"bar\" } }", |
| 3753 | | .free_on_error = false, |
| 3754 | | .diag = null, |
| 3755 | | }); |
| 3756 | | defer free(std.testing.allocator, result[0].x); |
| 3757 | | defer free(std.testing.allocator, result[1].x); |
| 3758 | | try std.testing.expectEqualStrings("foo", result[0].x); |
| 3759 | | try std.testing.expectEqualStrings("bar", result[1].x); |
| 3760 | | } |
| 3761 | | |
| 3762 | | // Again but for slices. |
| 3763 | | { |
| 3764 | | const S = []union { x: []const u8 }; |
| 3765 | | const result = try fromSliceAlloc(S, .{ |
| 3766 | | .gpa = std.testing.allocator, |
| 3767 | | .source = ".{ .{ .x = \"foo\" }, .{ .x = \"bar\" } }", |
| 3768 | | .free_on_error = false, |
| 3769 | | .diag = null, |
| 3770 | | }); |
| 3771 | | defer std.testing.allocator.free(result); |
| 3772 | | defer free(std.testing.allocator, result[0].x); |
| 3773 | | defer free(std.testing.allocator, result[1].x); |
| 3774 | | try std.testing.expectEqualStrings("foo", result[0].x); |
| 3775 | | try std.testing.expectEqualStrings("bar", result[1].x); |
| 3776 | | } |
| 3777 | 3569 | } |
| 3778 | 3570 | |
| 3779 | 3571 | test "std.zon vector" { |
| ... | ... | @@ -3781,11 +3573,18 @@ test "std.zon vector" { |
| 3781 | 3573 | if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .s390x) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/25957 |
| 3782 | 3574 | |
| 3783 | 3575 | const gpa = std.testing.allocator; |
| 3576 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 3577 | defer arena_allocator.deinit(); |
| 3578 | const arena = arena_allocator.allocator(); |
| 3784 | 3579 | |
| 3785 | 3580 | // Passing cases |
| 3786 | 3581 | try std.testing.expectEqual( |
| 3787 | 3582 | @Vector(0, bool){}, |
| 3788 | | try fromSlice(@Vector(0, bool), .{ .gpa = gpa, .source = ".{}", .diag = null }), |
| 3583 | try fromSlice(@Vector(0, bool), .{ |
| 3584 | .gpa = gpa, |
| 3585 | .source = ".{}", |
| 3586 | .diag = null, |
| 3587 | }), |
| 3789 | 3588 | ); |
| 3790 | 3589 | try std.testing.expectEqual( |
| 3791 | 3590 | @Vector(3, bool){ true, false, true }, |
| ... | ... | @@ -3798,7 +3597,11 @@ test "std.zon vector" { |
| 3798 | 3597 | |
| 3799 | 3598 | try std.testing.expectEqual( |
| 3800 | 3599 | @Vector(0, f32){}, |
| 3801 | | try fromSlice(@Vector(0, f32), .{ .gpa = gpa, .source = ".{}", .diag = null }), |
| 3600 | try fromSlice(@Vector(0, f32), .{ |
| 3601 | .gpa = gpa, |
| 3602 | .source = ".{}", |
| 3603 | .diag = null, |
| 3604 | }), |
| 3802 | 3605 | ); |
| 3803 | 3606 | try std.testing.expectEqual( |
| 3804 | 3607 | @Vector(3, f32){ 1.5, 2.5, 3.5 }, |
| ... | ... | @@ -3811,11 +3614,19 @@ test "std.zon vector" { |
| 3811 | 3614 | |
| 3812 | 3615 | try std.testing.expectEqual( |
| 3813 | 3616 | @Vector(0, u8){}, |
| 3814 | | try fromSlice(@Vector(0, u8), .{ .gpa = gpa, .source = ".{}", .diag = null }), |
| 3617 | try fromSlice(@Vector(0, u8), .{ |
| 3618 | .gpa = gpa, |
| 3619 | .source = ".{}", |
| 3620 | .diag = null, |
| 3621 | }), |
| 3815 | 3622 | ); |
| 3816 | 3623 | try std.testing.expectEqual( |
| 3817 | 3624 | @Vector(3, u8){ 2, 4, 6 }, |
| 3818 | | try fromSlice(@Vector(3, u8), .{ .gpa = gpa, .source = ".{2, 4, 6}", .diag = null }), |
| 3625 | try fromSlice(@Vector(3, u8), .{ |
| 3626 | .gpa = gpa, |
| 3627 | .source = ".{2, 4, 6}", |
| 3628 | .diag = null, |
| 3629 | }), |
| 3819 | 3630 | ); |
| 3820 | 3631 | |
| 3821 | 3632 | { |
| ... | ... | @@ -3823,16 +3634,17 @@ test "std.zon vector" { |
| 3823 | 3634 | @Vector(0, *const u8){}, |
| 3824 | 3635 | try fromSliceAlloc(@Vector(0, *const u8), .{ |
| 3825 | 3636 | .gpa = gpa, |
| 3637 | .arena = arena, |
| 3826 | 3638 | .source = ".{}", |
| 3827 | 3639 | .diag = null, |
| 3828 | 3640 | }), |
| 3829 | 3641 | ); |
| 3830 | 3642 | const pointers = try fromSliceAlloc(@Vector(3, *const u8), .{ |
| 3831 | 3643 | .gpa = gpa, |
| 3644 | .arena = arena, |
| 3832 | 3645 | .source = ".{2, 4, 6}", |
| 3833 | 3646 | .diag = null, |
| 3834 | 3647 | }); |
| 3835 | | defer free(gpa, pointers); |
| 3836 | 3648 | try std.testing.expectEqualDeep(@Vector(3, *const u8){ &2, &4, &6 }, pointers); |
| 3837 | 3649 | } |
| 3838 | 3650 | |
| ... | ... | @@ -3841,23 +3653,23 @@ test "std.zon vector" { |
| 3841 | 3653 | @Vector(0, ?*const u8){}, |
| 3842 | 3654 | try fromSliceAlloc(@Vector(0, ?*const u8), .{ |
| 3843 | 3655 | .gpa = gpa, |
| 3656 | .arena = arena, |
| 3844 | 3657 | .source = ".{}", |
| 3845 | 3658 | .diag = null, |
| 3846 | 3659 | }), |
| 3847 | 3660 | ); |
| 3848 | 3661 | const pointers = try fromSliceAlloc(@Vector(3, ?*const u8), .{ |
| 3849 | 3662 | .gpa = gpa, |
| 3663 | .arena = arena, |
| 3850 | 3664 | .source = ".{2, null, 6}", |
| 3851 | 3665 | .diag = null, |
| 3852 | 3666 | }); |
| 3853 | | defer free(gpa, pointers); |
| 3854 | 3667 | try std.testing.expectEqualDeep(@Vector(3, ?*const u8){ &2, null, &6 }, pointers); |
| 3855 | 3668 | } |
| 3856 | 3669 | |
| 3857 | 3670 | // Too few fields |
| 3858 | 3671 | { |
| 3859 | | var diag: Diagnostics = .{}; |
| 3860 | | defer diag.deinit(gpa); |
| 3672 | var diag: Diagnostics = .init(arena); |
| 3861 | 3673 | try std.testing.expectError( |
| 3862 | 3674 | error.ParseZon, |
| 3863 | 3675 | fromSlice(@Vector(2, f32), .{ |
| ... | ... | @@ -3875,8 +3687,7 @@ test "std.zon vector" { |
| 3875 | 3687 | |
| 3876 | 3688 | // Too many fields |
| 3877 | 3689 | { |
| 3878 | | var diag: Diagnostics = .{}; |
| 3879 | | defer diag.deinit(gpa); |
| 3690 | var diag: Diagnostics = .init(arena); |
| 3880 | 3691 | try std.testing.expectError( |
| 3881 | 3692 | error.ParseZon, |
| 3882 | 3693 | fromSlice(@Vector(2, f32), .{ |
| ... | ... | @@ -3894,8 +3705,7 @@ test "std.zon vector" { |
| 3894 | 3705 | |
| 3895 | 3706 | // Wrong type fields |
| 3896 | 3707 | { |
| 3897 | | var diag: Diagnostics = .{}; |
| 3898 | | defer diag.deinit(gpa); |
| 3708 | var diag: Diagnostics = .init(arena); |
| 3899 | 3709 | try std.testing.expectError( |
| 3900 | 3710 | error.ParseZon, |
| 3901 | 3711 | fromSlice(@Vector(3, f32), .{ |
| ... | ... | @@ -3913,23 +3723,26 @@ test "std.zon vector" { |
| 3913 | 3723 | |
| 3914 | 3724 | // Wrong type |
| 3915 | 3725 | { |
| 3916 | | var diag: Diagnostics = .{}; |
| 3917 | | defer diag.deinit(gpa); |
| 3726 | var diag: Diagnostics = .init(arena); |
| 3918 | 3727 | try std.testing.expectError( |
| 3919 | 3728 | error.ParseZon, |
| 3920 | | fromSlice(@Vector(3, u8), .{ .gpa = gpa, .source = "true", .diag = &diag }), |
| 3729 | fromSlice(@Vector(3, u8), .{ |
| 3730 | .gpa = gpa, |
| 3731 | .source = "true", |
| 3732 | .diag = &diag, |
| 3733 | }), |
| 3921 | 3734 | ); |
| 3922 | 3735 | try std.testing.expectFmt("1:1: error: expected type '@Vector(3, u8)'\n", "{f}", .{diag}); |
| 3923 | 3736 | } |
| 3924 | 3737 | |
| 3925 | 3738 | // Elements should get freed on error |
| 3926 | 3739 | { |
| 3927 | | var diag: Diagnostics = .{}; |
| 3928 | | defer diag.deinit(gpa); |
| 3740 | var diag: Diagnostics = .init(arena); |
| 3929 | 3741 | try std.testing.expectError( |
| 3930 | 3742 | error.ParseZon, |
| 3931 | 3743 | fromSliceAlloc(@Vector(3, *u8), .{ |
| 3932 | 3744 | .gpa = gpa, |
| 3745 | .arena = arena, |
| 3933 | 3746 | .source = ".{1, true, 3}", |
| 3934 | 3747 | .diag = &diag, |
| 3935 | 3748 | }), |
| ... | ... | @@ -3940,35 +3753,38 @@ test "std.zon vector" { |
| 3940 | 3753 | |
| 3941 | 3754 | test "std.zon add pointers" { |
| 3942 | 3755 | const gpa = std.testing.allocator; |
| 3756 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 3757 | defer arena_allocator.deinit(); |
| 3758 | const arena = arena_allocator.allocator(); |
| 3943 | 3759 | |
| 3944 | 3760 | // Primitive with varying levels of pointers |
| 3945 | 3761 | { |
| 3946 | 3762 | const result = try fromSliceAlloc(*u32, .{ |
| 3947 | 3763 | .gpa = gpa, |
| 3764 | .arena = arena, |
| 3948 | 3765 | .source = "10", |
| 3949 | 3766 | .diag = null, |
| 3950 | 3767 | }); |
| 3951 | | defer free(gpa, result); |
| 3952 | 3768 | try std.testing.expectEqual(@as(u32, 10), result.*); |
| 3953 | 3769 | } |
| 3954 | 3770 | |
| 3955 | 3771 | { |
| 3956 | 3772 | const result = try fromSliceAlloc(**u32, .{ |
| 3957 | 3773 | .gpa = gpa, |
| 3774 | .arena = arena, |
| 3958 | 3775 | .source = "10", |
| 3959 | 3776 | .diag = null, |
| 3960 | 3777 | }); |
| 3961 | | defer free(gpa, result); |
| 3962 | 3778 | try std.testing.expectEqual(@as(u32, 10), result.*.*); |
| 3963 | 3779 | } |
| 3964 | 3780 | |
| 3965 | 3781 | { |
| 3966 | 3782 | const result = try fromSliceAlloc(***u32, .{ |
| 3967 | 3783 | .gpa = gpa, |
| 3784 | .arena = arena, |
| 3968 | 3785 | .source = "10", |
| 3969 | 3786 | .diag = null, |
| 3970 | 3787 | }); |
| 3971 | | defer free(gpa, result); |
| 3972 | 3788 | try std.testing.expectEqual(@as(u32, 10), result.*.*.*); |
| 3973 | 3789 | } |
| 3974 | 3790 | |
| ... | ... | @@ -3976,90 +3792,90 @@ test "std.zon add pointers" { |
| 3976 | 3792 | { |
| 3977 | 3793 | const some = try fromSliceAlloc(?*u32, .{ |
| 3978 | 3794 | .gpa = gpa, |
| 3795 | .arena = arena, |
| 3979 | 3796 | .source = "10", |
| 3980 | 3797 | .diag = null, |
| 3981 | 3798 | }); |
| 3982 | | defer free(gpa, some); |
| 3983 | 3799 | try std.testing.expectEqual(@as(u32, 10), some.?.*); |
| 3984 | 3800 | |
| 3985 | 3801 | const none = try fromSliceAlloc(?*u32, .{ |
| 3986 | 3802 | .gpa = gpa, |
| 3803 | .arena = arena, |
| 3987 | 3804 | .source = "null", |
| 3988 | 3805 | .diag = null, |
| 3989 | 3806 | }); |
| 3990 | | defer free(gpa, none); |
| 3991 | 3807 | try std.testing.expectEqual(null, none); |
| 3992 | 3808 | } |
| 3993 | 3809 | |
| 3994 | 3810 | { |
| 3995 | 3811 | const some = try fromSliceAlloc(*?u32, .{ |
| 3996 | 3812 | .gpa = gpa, |
| 3813 | .arena = arena, |
| 3997 | 3814 | .source = "10", |
| 3998 | 3815 | .diag = null, |
| 3999 | 3816 | }); |
| 4000 | | defer free(gpa, some); |
| 4001 | 3817 | try std.testing.expectEqual(@as(u32, 10), some.*.?); |
| 4002 | 3818 | |
| 4003 | 3819 | const none = try fromSliceAlloc(*?u32, .{ |
| 4004 | 3820 | .gpa = gpa, |
| 3821 | .arena = arena, |
| 4005 | 3822 | .source = "null", |
| 4006 | 3823 | .diag = null, |
| 4007 | 3824 | }); |
| 4008 | | defer free(gpa, none); |
| 4009 | 3825 | try std.testing.expectEqual(null, none.*); |
| 4010 | 3826 | } |
| 4011 | 3827 | |
| 4012 | 3828 | { |
| 4013 | 3829 | const some = try fromSliceAlloc(?**u32, .{ |
| 4014 | 3830 | .gpa = gpa, |
| 3831 | .arena = arena, |
| 4015 | 3832 | .source = "10", |
| 4016 | 3833 | .diag = null, |
| 4017 | 3834 | }); |
| 4018 | | defer free(gpa, some); |
| 4019 | 3835 | try std.testing.expectEqual(@as(u32, 10), some.?.*.*); |
| 4020 | 3836 | |
| 4021 | 3837 | const none = try fromSliceAlloc(?**u32, .{ |
| 4022 | 3838 | .gpa = gpa, |
| 3839 | .arena = arena, |
| 4023 | 3840 | .source = "null", |
| 4024 | 3841 | .diag = null, |
| 4025 | 3842 | }); |
| 4026 | | defer free(gpa, none); |
| 4027 | 3843 | try std.testing.expectEqual(null, none); |
| 4028 | 3844 | } |
| 4029 | 3845 | |
| 4030 | 3846 | { |
| 4031 | 3847 | const some = try fromSliceAlloc(*?*u32, .{ |
| 4032 | 3848 | .gpa = gpa, |
| 3849 | .arena = arena, |
| 4033 | 3850 | .source = "10", |
| 4034 | 3851 | .diag = null, |
| 4035 | 3852 | }); |
| 4036 | | defer free(gpa, some); |
| 4037 | 3853 | try std.testing.expectEqual(@as(u32, 10), some.*.?.*); |
| 4038 | 3854 | |
| 4039 | 3855 | const none = try fromSliceAlloc(*?*u32, .{ |
| 4040 | 3856 | .gpa = gpa, |
| 3857 | .arena = arena, |
| 4041 | 3858 | .source = "null", |
| 4042 | 3859 | .diag = null, |
| 4043 | 3860 | }); |
| 4044 | | defer free(gpa, none); |
| 4045 | 3861 | try std.testing.expectEqual(null, none.*); |
| 4046 | 3862 | } |
| 4047 | 3863 | |
| 4048 | 3864 | { |
| 4049 | 3865 | const some = try fromSliceAlloc(**?u32, .{ |
| 4050 | 3866 | .gpa = gpa, |
| 3867 | .arena = arena, |
| 4051 | 3868 | .source = "10", |
| 4052 | 3869 | .diag = null, |
| 4053 | 3870 | }); |
| 4054 | | defer free(gpa, some); |
| 4055 | 3871 | try std.testing.expectEqual(@as(u32, 10), some.*.*.?); |
| 4056 | 3872 | |
| 4057 | 3873 | const none = try fromSliceAlloc(**?u32, .{ |
| 4058 | 3874 | .gpa = gpa, |
| 3875 | .arena = arena, |
| 4059 | 3876 | .source = "null", |
| 4060 | 3877 | .diag = null, |
| 4061 | 3878 | }); |
| 4062 | | defer free(gpa, none); |
| 4063 | 3879 | try std.testing.expectEqual(null, none.*.*); |
| 4064 | 3880 | } |
| 4065 | 3881 | |
| ... | ... | @@ -4067,10 +3883,10 @@ test "std.zon add pointers" { |
| 4067 | 3883 | { |
| 4068 | 3884 | const result = try fromSliceAlloc(*[3]u8, .{ |
| 4069 | 3885 | .gpa = gpa, |
| 3886 | .arena = arena, |
| 4070 | 3887 | .source = ".{ 1, 2, 3 }", |
| 4071 | 3888 | .diag = null, |
| 4072 | 3889 | }); |
| 4073 | | defer free(gpa, result); |
| 4074 | 3890 | try std.testing.expectEqual([3]u8{ 1, 2, 3 }, result.*); |
| 4075 | 3891 | } |
| 4076 | 3892 | |
| ... | ... | @@ -4094,6 +3910,7 @@ test "std.zon add pointers" { |
| 4094 | 3910 | |
| 4095 | 3911 | const found = try fromSliceAlloc(?*Outer, .{ |
| 4096 | 3912 | .gpa = gpa, |
| 3913 | .arena = arena, |
| 4097 | 3914 | .source = |
| 4098 | 3915 | \\.{ |
| 4099 | 3916 | \\ .f1 = .{ |
| ... | ... | @@ -4105,39 +3922,46 @@ test "std.zon add pointers" { |
| 4105 | 3922 | , |
| 4106 | 3923 | .diag = null, |
| 4107 | 3924 | }); |
| 4108 | | defer free(gpa, found); |
| 4109 | 3925 | |
| 4110 | 3926 | try std.testing.expectEqualDeep(expected, found.?.*); |
| 4111 | 3927 | } |
| 4112 | 3928 | |
| 4113 | 3929 | // Test that optional types are flattened correctly in errors |
| 4114 | 3930 | { |
| 4115 | | var diag: Diagnostics = .{}; |
| 4116 | | defer diag.deinit(gpa); |
| 3931 | var diag: Diagnostics = .init(arena); |
| 4117 | 3932 | try std.testing.expectError( |
| 4118 | 3933 | error.ParseZon, |
| 4119 | | fromSliceAlloc(*const ?*const u8, .{ .gpa = gpa, .source = "true", .diag = &diag }), |
| 3934 | fromSliceAlloc(*const ?*const u8, .{ |
| 3935 | .gpa = gpa, |
| 3936 | .arena = arena, |
| 3937 | .source = "true", |
| 3938 | .diag = &diag, |
| 3939 | }), |
| 4120 | 3940 | ); |
| 4121 | 3941 | try std.testing.expectFmt("1:1: error: expected type '?u8'\n", "{f}", .{diag}); |
| 4122 | 3942 | } |
| 4123 | 3943 | |
| 4124 | 3944 | { |
| 4125 | | var diag: Diagnostics = .{}; |
| 4126 | | defer diag.deinit(gpa); |
| 3945 | var diag: Diagnostics = .init(arena); |
| 4127 | 3946 | try std.testing.expectError( |
| 4128 | 3947 | error.ParseZon, |
| 4129 | | fromSliceAlloc(*const ?*const f32, .{ .gpa = gpa, .source = "true", .diag = &diag }), |
| 3948 | fromSliceAlloc(*const ?*const f32, .{ |
| 3949 | .gpa = gpa, |
| 3950 | .arena = arena, |
| 3951 | .source = "true", |
| 3952 | .diag = &diag, |
| 3953 | }), |
| 4130 | 3954 | ); |
| 4131 | 3955 | try std.testing.expectFmt("1:1: error: expected type '?f32'\n", "{f}", .{diag}); |
| 4132 | 3956 | } |
| 4133 | 3957 | |
| 4134 | 3958 | { |
| 4135 | | var diag: Diagnostics = .{}; |
| 4136 | | defer diag.deinit(gpa); |
| 3959 | var diag: Diagnostics = .init(arena); |
| 4137 | 3960 | try std.testing.expectError( |
| 4138 | 3961 | error.ParseZon, |
| 4139 | 3962 | fromSliceAlloc(*const ?*const @Vector(3, u8), .{ |
| 4140 | 3963 | .gpa = gpa, |
| 3964 | .arena = arena, |
| 4141 | 3965 | .source = "true", |
| 4142 | 3966 | .diag = &diag, |
| 4143 | 3967 | }), |
| ... | ... | @@ -4146,101 +3970,141 @@ test "std.zon add pointers" { |
| 4146 | 3970 | } |
| 4147 | 3971 | |
| 4148 | 3972 | { |
| 4149 | | var diag: Diagnostics = .{}; |
| 4150 | | defer diag.deinit(gpa); |
| 3973 | var diag: Diagnostics = .init(arena); |
| 4151 | 3974 | try std.testing.expectError( |
| 4152 | 3975 | error.ParseZon, |
| 4153 | | fromSliceAlloc(*const ?*const bool, .{ .gpa = gpa, .source = "10", .diag = &diag }), |
| 3976 | fromSliceAlloc(*const ?*const bool, .{ |
| 3977 | .gpa = gpa, |
| 3978 | .arena = arena, |
| 3979 | .source = "10", |
| 3980 | .diag = &diag, |
| 3981 | }), |
| 4154 | 3982 | ); |
| 4155 | 3983 | try std.testing.expectFmt("1:1: error: expected type '?bool'\n", "{f}", .{diag}); |
| 4156 | 3984 | } |
| 4157 | 3985 | |
| 4158 | 3986 | { |
| 4159 | | var diag: Diagnostics = .{}; |
| 4160 | | defer diag.deinit(gpa); |
| 3987 | var diag: Diagnostics = .init(arena); |
| 4161 | 3988 | try std.testing.expectError( |
| 4162 | 3989 | error.ParseZon, |
| 4163 | | fromSliceAlloc(*const ?*const struct { a: i32 }, .{ .gpa = gpa, .source = "true", .diag = &diag }), |
| 3990 | fromSliceAlloc(*const ?*const struct { a: i32 }, .{ |
| 3991 | .gpa = gpa, |
| 3992 | .arena = arena, |
| 3993 | .source = "true", |
| 3994 | .diag = &diag, |
| 3995 | }), |
| 4164 | 3996 | ); |
| 4165 | 3997 | try std.testing.expectFmt("1:1: error: expected optional struct\n", "{f}", .{diag}); |
| 4166 | 3998 | } |
| 4167 | 3999 | |
| 4168 | 4000 | { |
| 4169 | | var diag: Diagnostics = .{}; |
| 4170 | | defer diag.deinit(gpa); |
| 4001 | var diag: Diagnostics = .init(arena); |
| 4171 | 4002 | try std.testing.expectError( |
| 4172 | 4003 | error.ParseZon, |
| 4173 | | fromSliceAlloc(*const ?*const struct { i32 }, .{ .gpa = gpa, .source = "true", .diag = &diag }), |
| 4004 | fromSliceAlloc(*const ?*const struct { i32 }, .{ |
| 4005 | .gpa = gpa, |
| 4006 | .arena = arena, |
| 4007 | .source = "true", |
| 4008 | .diag = &diag, |
| 4009 | }), |
| 4174 | 4010 | ); |
| 4175 | 4011 | try std.testing.expectFmt("1:1: error: expected optional tuple\n", "{f}", .{diag}); |
| 4176 | 4012 | } |
| 4177 | 4013 | |
| 4178 | 4014 | { |
| 4179 | | var diag: Diagnostics = .{}; |
| 4180 | | defer diag.deinit(gpa); |
| 4015 | var diag: Diagnostics = .init(arena); |
| 4181 | 4016 | try std.testing.expectError( |
| 4182 | 4017 | error.ParseZon, |
| 4183 | | fromSliceAlloc(*const ?*const union { x: void }, .{ .gpa = gpa, .source = "true", .diag = &diag }), |
| 4018 | fromSliceAlloc(*const ?*const union { x: void }, .{ |
| 4019 | .gpa = gpa, |
| 4020 | .arena = arena, |
| 4021 | .source = "true", |
| 4022 | .diag = &diag, |
| 4023 | }), |
| 4184 | 4024 | ); |
| 4185 | 4025 | try std.testing.expectFmt("1:1: error: expected optional union\n", "{f}", .{diag}); |
| 4186 | 4026 | } |
| 4187 | 4027 | |
| 4188 | 4028 | { |
| 4189 | | var diag: Diagnostics = .{}; |
| 4190 | | defer diag.deinit(gpa); |
| 4029 | var diag: Diagnostics = .init(arena); |
| 4191 | 4030 | try std.testing.expectError( |
| 4192 | 4031 | error.ParseZon, |
| 4193 | | fromSliceAlloc(*const ?*const [3]u8, .{ .gpa = gpa, .source = "true", .diag = &diag }), |
| 4032 | fromSliceAlloc(*const ?*const [3]u8, .{ |
| 4033 | .gpa = gpa, |
| 4034 | .arena = arena, |
| 4035 | .source = "true", |
| 4036 | .diag = &diag, |
| 4037 | }), |
| 4194 | 4038 | ); |
| 4195 | 4039 | try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag}); |
| 4196 | 4040 | } |
| 4197 | 4041 | |
| 4198 | 4042 | { |
| 4199 | | var diag: Diagnostics = .{}; |
| 4200 | | defer diag.deinit(gpa); |
| 4043 | var diag: Diagnostics = .init(arena); |
| 4201 | 4044 | try std.testing.expectError( |
| 4202 | 4045 | error.ParseZon, |
| 4203 | | fromSliceAlloc(?[3]u8, .{ .gpa = gpa, .source = "true", .diag = &diag }), |
| 4046 | fromSliceAlloc(?[3]u8, .{ |
| 4047 | .gpa = gpa, |
| 4048 | .arena = arena, |
| 4049 | .source = "true", |
| 4050 | .diag = &diag, |
| 4051 | }), |
| 4204 | 4052 | ); |
| 4205 | 4053 | try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag}); |
| 4206 | 4054 | } |
| 4207 | 4055 | |
| 4208 | 4056 | { |
| 4209 | | var diag: Diagnostics = .{}; |
| 4210 | | defer diag.deinit(gpa); |
| 4057 | var diag: Diagnostics = .init(arena); |
| 4211 | 4058 | try std.testing.expectError( |
| 4212 | 4059 | error.ParseZon, |
| 4213 | | fromSliceAlloc(*const ?*const []u8, .{ .gpa = gpa, .source = "true", .diag = &diag }), |
| 4060 | fromSliceAlloc(*const ?*const []u8, .{ |
| 4061 | .gpa = gpa, |
| 4062 | .arena = arena, |
| 4063 | .source = "true", |
| 4064 | .diag = &diag, |
| 4065 | }), |
| 4214 | 4066 | ); |
| 4215 | 4067 | try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag}); |
| 4216 | 4068 | } |
| 4217 | 4069 | |
| 4218 | 4070 | { |
| 4219 | | var diag: Diagnostics = .{}; |
| 4220 | | defer diag.deinit(gpa); |
| 4071 | var diag: Diagnostics = .init(arena); |
| 4221 | 4072 | try std.testing.expectError( |
| 4222 | 4073 | error.ParseZon, |
| 4223 | | fromSliceAlloc(?[]u8, .{ .gpa = gpa, .source = "true", .diag = &diag }), |
| 4074 | fromSliceAlloc(?[]u8, .{ |
| 4075 | .gpa = gpa, |
| 4076 | .arena = arena, |
| 4077 | .source = "true", |
| 4078 | .diag = &diag, |
| 4079 | }), |
| 4224 | 4080 | ); |
| 4225 | 4081 | try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag}); |
| 4226 | 4082 | } |
| 4227 | 4083 | |
| 4228 | 4084 | { |
| 4229 | | var diag: Diagnostics = .{}; |
| 4230 | | defer diag.deinit(gpa); |
| 4085 | var diag: Diagnostics = .init(arena); |
| 4231 | 4086 | try std.testing.expectError( |
| 4232 | 4087 | error.ParseZon, |
| 4233 | | fromSliceAlloc(*const ?*const []const u8, .{ .gpa = gpa, .source = "true", .diag = &diag }), |
| 4088 | fromSliceAlloc(*const ?*const []const u8, .{ |
| 4089 | .gpa = gpa, |
| 4090 | .arena = arena, |
| 4091 | .source = "true", |
| 4092 | .diag = &diag, |
| 4093 | }), |
| 4234 | 4094 | ); |
| 4235 | 4095 | try std.testing.expectFmt("1:1: error: expected optional string\n", "{f}", .{diag}); |
| 4236 | 4096 | } |
| 4237 | 4097 | |
| 4238 | 4098 | { |
| 4239 | | var diag: Diagnostics = .{}; |
| 4240 | | defer diag.deinit(gpa); |
| 4099 | var diag: Diagnostics = .init(arena); |
| 4241 | 4100 | try std.testing.expectError( |
| 4242 | 4101 | error.ParseZon, |
| 4243 | | fromSliceAlloc(*const ?*const enum { foo }, .{ .gpa = gpa, .source = "true", .diag = &diag }), |
| 4102 | fromSliceAlloc(*const ?*const enum { foo }, .{ |
| 4103 | .gpa = gpa, |
| 4104 | .arena = arena, |
| 4105 | .source = "true", |
| 4106 | .diag = &diag, |
| 4107 | }), |
| 4244 | 4108 | ); |
| 4245 | 4109 | try std.testing.expectFmt("1:1: error: expected optional enum literal\n", "{f}", .{diag}); |
| 4246 | 4110 | } |
| ... | ... | @@ -4255,26 +4119,35 @@ test "std.zon stop on node" { |
| 4255 | 4119 | y: f32, |
| 4256 | 4120 | }; |
| 4257 | 4121 | |
| 4258 | | var diag: Diagnostics = .{}; |
| 4259 | | defer diag.deinit(gpa); |
| 4260 | | const result = try fromSlice(Vec2, .{ |
| 4261 | | .gpa = gpa, |
| 4262 | | .source = ".{ .x = 1.5, .y = 2.5 }", |
| 4263 | | .diag = &diag, |
| 4122 | var ast = try std.zig.Ast.parse(gpa, ".{ .x = 1.5, .y = 2.5 }", .{ .mode = .zon }); |
| 4123 | defer ast.deinit(gpa); |
| 4124 | |
| 4125 | var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false }); |
| 4126 | defer zoir.deinit(gpa); |
| 4127 | |
| 4128 | const result = try fromZoir(Vec2, .{ |
| 4129 | .ast = &ast, |
| 4130 | .zoir = &zoir, |
| 4131 | .diag = null, |
| 4264 | 4132 | }); |
| 4133 | |
| 4265 | 4134 | try std.testing.expectEqual(result.y, 2.5); |
| 4266 | | try std.testing.expectEqual(Zoir.Node{ .float_literal = 1.5 }, result.x.get(diag.zoir)); |
| 4135 | try std.testing.expectEqual(Zoir.Node{ .float_literal = 1.5 }, result.x.get(&zoir)); |
| 4267 | 4136 | } |
| 4268 | 4137 | |
| 4269 | 4138 | { |
| 4270 | | var diag: Diagnostics = .{}; |
| 4271 | | defer diag.deinit(gpa); |
| 4272 | | const result = try fromSlice(Zoir.Node.Index, .{ |
| 4273 | | .gpa = gpa, |
| 4274 | | .source = "1.23", |
| 4275 | | .diag = &diag, |
| 4139 | var ast = try std.zig.Ast.parse(gpa, "1.23", .{ .mode = .zon }); |
| 4140 | defer ast.deinit(gpa); |
| 4141 | |
| 4142 | var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false }); |
| 4143 | defer zoir.deinit(gpa); |
| 4144 | |
| 4145 | const result = try fromZoir(Zoir.Node.Index, .{ |
| 4146 | .ast = &ast, |
| 4147 | .zoir = &zoir, |
| 4148 | .diag = null, |
| 4276 | 4149 | }); |
| 4277 | | try std.testing.expectEqual(Zoir.Node{ .float_literal = 1.23 }, result.get(diag.zoir)); |
| 4150 | try std.testing.expectEqual(Zoir.Node{ .float_literal = 1.23 }, result.get(&zoir)); |
| 4278 | 4151 | } |
| 4279 | 4152 | } |
| 4280 | 4153 | |
| ... | ... | @@ -4300,12 +4173,19 @@ test "std.zon no alloc" { |
| 4300 | 4173 | |
| 4301 | 4174 | try std.testing.expectEqual( |
| 4302 | 4175 | Nested{ 1, 2, .{ 3, 4 } }, |
| 4303 | | try fromZoir(Nested, .{ .ast = ast, .zoir = zoir, .diag = null }), |
| 4176 | try fromZoir(Nested, .{ |
| 4177 | .ast = &ast, |
| 4178 | .zoir = &zoir, |
| 4179 | .diag = null, |
| 4180 | }), |
| 4304 | 4181 | ); |
| 4305 | 4182 | } |
| 4306 | 4183 | |
| 4307 | 4184 | test "std.zon errors without diagnostics" { |
| 4308 | 4185 | const gpa = std.testing.allocator; |
| 4186 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 4187 | defer arena_allocator.deinit(); |
| 4188 | const arena = arena_allocator.allocator(); |
| 4309 | 4189 | |
| 4310 | 4190 | const Enum = enum { |
| 4311 | 4191 | foo, |
| ... | ... | @@ -4314,6 +4194,7 @@ test "std.zon errors without diagnostics" { |
| 4314 | 4194 | }; |
| 4315 | 4195 | try std.testing.expectError(error.ParseZon, fromSliceAlloc(Enum, .{ |
| 4316 | 4196 | .gpa = gpa, |
| 4197 | .arena = arena, |
| 4317 | 4198 | .source = ".nothing", |
| 4318 | 4199 | .diag = null, |
| 4319 | 4200 | })); |
| ... | ... | @@ -4323,6 +4204,7 @@ test "std.zon errors without diagnostics" { |
| 4323 | 4204 | }; |
| 4324 | 4205 | try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, .{ |
| 4325 | 4206 | .gpa = gpa, |
| 4207 | .arena = arena, |
| 4326 | 4208 | .source = ".{ .name = \"Alice\", .age = 25 }", |
| 4327 | 4209 | .diag = null, |
| 4328 | 4210 | })); |
| ... | ... | @@ -4333,11 +4215,13 @@ test "std.zon errors without diagnostics" { |
| 4333 | 4215 | }; |
| 4334 | 4216 | try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, .{ |
| 4335 | 4217 | .gpa = gpa, |
| 4218 | .arena = arena, |
| 4336 | 4219 | .source = ".a", |
| 4337 | 4220 | .diag = null, |
| 4338 | 4221 | })); |
| 4339 | 4222 | try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, .{ |
| 4340 | 4223 | .gpa = gpa, |
| 4224 | .arena = arena, |
| 4341 | 4225 | .source = ".{ .b = 8 }", |
| 4342 | 4226 | .diag = null, |
| 4343 | 4227 | })); |
| ... | ... | @@ -4345,6 +4229,9 @@ test "std.zon errors without diagnostics" { |
| 4345 | 4229 | |
| 4346 | 4230 | test "std.zon aligned pointers" { |
| 4347 | 4231 | const gpa = std.testing.allocator; |
| 4232 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 4233 | defer arena_allocator.deinit(); |
| 4234 | const arena = arena_allocator.allocator(); |
| 4348 | 4235 | |
| 4349 | 4236 | const n: u8 align(8) = 10; |
| 4350 | 4237 | const Foo = struct { |
| ... | ... | @@ -4356,15 +4243,18 @@ test "std.zon aligned pointers" { |
| 4356 | 4243 | }; |
| 4357 | 4244 | const found = try fromSliceAlloc(Foo, .{ |
| 4358 | 4245 | .gpa = gpa, |
| 4246 | .arena = arena, |
| 4359 | 4247 | .source = ".{ .inner = 10 }", |
| 4360 | 4248 | .diag = null, |
| 4361 | 4249 | }); |
| 4362 | | defer free(gpa, found); |
| 4363 | 4250 | try std.testing.expectEqualDeep(expected.inner, found.inner); |
| 4364 | 4251 | } |
| 4365 | 4252 | |
| 4366 | 4253 | test "std.zon update" { |
| 4367 | 4254 | const gpa = std.testing.allocator; |
| 4255 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 4256 | defer arena_allocator.deinit(); |
| 4257 | const arena = arena_allocator.allocator(); |
| 4368 | 4258 | |
| 4369 | 4259 | const Vector = struct { x: f32, y: f32, z: f32 }; |
| 4370 | 4260 | const MyStruct = struct { |
| ... | ... | @@ -4379,51 +4269,43 @@ test "std.zon update" { |
| 4379 | 4269 | str: []const u8, |
| 4380 | 4270 | }; |
| 4381 | 4271 | |
| 4272 | var v1: Vector = .{ .x = 1, .y = 2, .z = 3 }; |
| 4382 | 4273 | var expected: MyStruct = .{ |
| 4383 | 4274 | .foo = 10, |
| 4384 | 4275 | .bar = true, |
| 4385 | 4276 | .baz = .{ .a = .{ 1, 2 }, .b = .c }, |
| 4386 | | .ptr = b: { |
| 4387 | | const v = gpa.create(Vector) catch @panic("oom"); |
| 4388 | | v.* = .{ .x = 1, .y = 2, .z = 3 }; |
| 4389 | | break :b v; |
| 4390 | | }, |
| 4391 | | .str = gpa.dupe(u8, "hello, world") catch @panic("oom"), |
| 4277 | .ptr = &v1, |
| 4278 | .str = "hello, world", |
| 4392 | 4279 | }; |
| 4393 | | defer free(gpa, expected); |
| 4280 | var v2: Vector = .{ .x = 1, .y = 2, .z = 3 }; |
| 4394 | 4281 | var found: MyStruct = .{ |
| 4395 | 4282 | .foo = 10, |
| 4396 | 4283 | .bar = true, |
| 4397 | 4284 | .baz = .{ .a = .{ 1, 2 }, .b = .c }, |
| 4398 | | .ptr = b: { |
| 4399 | | const v = gpa.create(Vector) catch @panic("oom"); |
| 4400 | | v.* = .{ .x = 1, .y = 2, .z = 3 }; |
| 4401 | | break :b v; |
| 4402 | | }, |
| 4403 | | .str = gpa.dupe(u8, "hello, world") catch @panic("oom"), |
| 4285 | .ptr = &v2, |
| 4286 | .str = "hello, world", |
| 4404 | 4287 | }; |
| 4405 | | defer free(gpa, found); |
| 4406 | 4288 | |
| 4407 | | try updateFromSliceAlloc(MyStruct, .{ |
| 4289 | try updateFromSliceAlloc(MyStruct, &found, .{ |
| 4408 | 4290 | .gpa = gpa, |
| 4409 | | .value = &found, |
| 4291 | .arena = arena, |
| 4410 | 4292 | .source = ".{}", |
| 4411 | 4293 | .diag = null, |
| 4412 | 4294 | }); |
| 4413 | 4295 | try std.testing.expectEqualDeep(expected, found); |
| 4414 | 4296 | |
| 4415 | | try updateFromSliceAlloc(MyStruct, .{ |
| 4297 | try updateFromSliceAlloc(MyStruct, &found, .{ |
| 4416 | 4298 | .gpa = gpa, |
| 4417 | | .value = &found, |
| 4299 | .arena = arena, |
| 4418 | 4300 | .source = ".{ .bar = false }", |
| 4419 | 4301 | .diag = null, |
| 4420 | 4302 | }); |
| 4421 | 4303 | expected.bar = false; |
| 4422 | 4304 | try std.testing.expectEqualDeep(expected, found); |
| 4423 | 4305 | |
| 4424 | | try updateFromSliceAlloc(MyStruct, .{ |
| 4306 | try updateFromSliceAlloc(MyStruct, &found, .{ |
| 4425 | 4307 | .gpa = gpa, |
| 4426 | | .value = &found, |
| 4308 | .arena = arena, |
| 4427 | 4309 | .source = ".{ .baz = .{ .a = .{ 2, 4 } } }", |
| 4428 | 4310 | .diag = null, |
| 4429 | 4311 | }); |
| ... | ... | @@ -4431,9 +4313,9 @@ test "std.zon update" { |
| 4431 | 4313 | expected.baz.a[1] = 4; |
| 4432 | 4314 | try std.testing.expectEqualDeep(expected, found); |
| 4433 | 4315 | |
| 4434 | | try updateFromSliceAlloc(MyStruct, .{ |
| 4316 | try updateFromSliceAlloc(MyStruct, &found, .{ |
| 4435 | 4317 | .gpa = gpa, |
| 4436 | | .value = &found, |
| 4318 | .arena = arena, |
| 4437 | 4319 | .source = ".{ .foo = 11, .baz = .{ .b = .d } }", |
| 4438 | 4320 | .diag = null, |
| 4439 | 4321 | }); |
| ... | ... | @@ -4441,27 +4323,27 @@ test "std.zon update" { |
| 4441 | 4323 | expected.baz.b = .d; |
| 4442 | 4324 | try std.testing.expectEqualDeep(expected, found); |
| 4443 | 4325 | |
| 4444 | | try updateFromSliceAlloc(MyStruct, .{ |
| 4326 | try updateFromSliceAlloc(MyStruct, &found, .{ |
| 4445 | 4327 | .gpa = gpa, |
| 4446 | | .value = &found, |
| 4328 | .arena = arena, |
| 4447 | 4329 | .source = ".{ .optional = 10 }", |
| 4448 | 4330 | .diag = null, |
| 4449 | 4331 | }); |
| 4450 | 4332 | expected.optional = 10; |
| 4451 | 4333 | try std.testing.expectEqualDeep(expected, found); |
| 4452 | 4334 | |
| 4453 | | try updateFromSliceAlloc(MyStruct, .{ |
| 4335 | try updateFromSliceAlloc(MyStruct, &found, .{ |
| 4454 | 4336 | .gpa = gpa, |
| 4455 | | .value = &found, |
| 4337 | .arena = arena, |
| 4456 | 4338 | .source = ".{ .optional = null }", |
| 4457 | 4339 | .diag = null, |
| 4458 | 4340 | }); |
| 4459 | 4341 | expected.optional = null; |
| 4460 | 4342 | try std.testing.expectEqualDeep(expected, found); |
| 4461 | 4343 | |
| 4462 | | try updateFromSliceAlloc(MyStruct, .{ |
| 4344 | try updateFromSliceAlloc(MyStruct, &found, .{ |
| 4463 | 4345 | .gpa = gpa, |
| 4464 | | .value = &found, |
| 4346 | .arena = arena, |
| 4465 | 4347 | .source = ".{ .ptr = .{ .x = 10, .y = 20, .z = 30 } }", |
| 4466 | 4348 | .diag = null, |
| 4467 | 4349 | }); |
| ... | ... | @@ -4470,14 +4352,13 @@ test "std.zon update" { |
| 4470 | 4352 | expected.ptr.z = 30; |
| 4471 | 4353 | try std.testing.expectEqualDeep(expected, found); |
| 4472 | 4354 | |
| 4473 | | try updateFromSliceAlloc(MyStruct, .{ |
| 4355 | try updateFromSliceAlloc(MyStruct, &found, .{ |
| 4474 | 4356 | .gpa = gpa, |
| 4475 | | .value = &found, |
| 4357 | .arena = arena, |
| 4476 | 4358 | .source = ".{ .str = \"foo\" }", |
| 4477 | 4359 | .diag = null, |
| 4478 | 4360 | }); |
| 4479 | | gpa.free(expected.str); |
| 4480 | | expected.str = gpa.dupe(u8, "foo") catch @panic("oom"); |
| 4361 | expected.str = "foo"; |
| 4481 | 4362 | try std.testing.expectEqualDeep(expected, found); |
| 4482 | 4363 | } |
| 4483 | 4364 | |
| ... | ... | @@ -4486,6 +4367,9 @@ test "std.zon variants" { |
| 4486 | 4367 | // the same code. |
| 4487 | 4368 | |
| 4488 | 4369 | const gpa = std.testing.allocator; |
| 4370 | var arena_allocator: ArenaAllocator = .init(gpa); |
| 4371 | defer arena_allocator.deinit(); |
| 4372 | const arena = arena_allocator.allocator(); |
| 4489 | 4373 | |
| 4490 | 4374 | const Struct = struct { a: u32, b: u32 }; |
| 4491 | 4375 | const start: Struct = .{ .a = 10, .b = 20 }; |
| ... | ... | @@ -4499,38 +4383,35 @@ test "std.zon variants" { |
| 4499 | 4383 | defer zoir.deinit(gpa); |
| 4500 | 4384 | |
| 4501 | 4385 | var curr = start; |
| 4502 | | try updateFromSlice(Struct, .{ |
| 4386 | try updateFromSlice(Struct, &curr, .{ |
| 4503 | 4387 | .gpa = gpa, |
| 4504 | | .value = &curr, |
| 4505 | 4388 | .source = ".{ .a = 100 }", |
| 4506 | 4389 | .diag = null, |
| 4507 | 4390 | }); |
| 4508 | 4391 | try std.testing.expectEqual(end, curr); |
| 4509 | 4392 | |
| 4510 | 4393 | curr = start; |
| 4511 | | try updateFromSliceAlloc(Struct, .{ |
| 4394 | try updateFromSliceAlloc(Struct, &curr, .{ |
| 4512 | 4395 | .gpa = gpa, |
| 4513 | | .value = &curr, |
| 4396 | .arena = arena, |
| 4514 | 4397 | .source = ".{ .a = 100 }", |
| 4515 | 4398 | .diag = null, |
| 4516 | 4399 | }); |
| 4517 | 4400 | try std.testing.expectEqual(end, curr); |
| 4518 | 4401 | |
| 4519 | 4402 | curr = start; |
| 4520 | | try updateFromZoir(Struct, .{ |
| 4521 | | .ast = ast, |
| 4522 | | .value = &curr, |
| 4523 | | .zoir = zoir, |
| 4403 | try updateFromZoir(Struct, &curr, .{ |
| 4404 | .ast = &ast, |
| 4405 | .zoir = &zoir, |
| 4524 | 4406 | .diag = null, |
| 4525 | 4407 | }); |
| 4526 | 4408 | try std.testing.expectEqual(end, curr); |
| 4527 | 4409 | |
| 4528 | 4410 | curr = start; |
| 4529 | | try updateFromZoirAlloc(Struct, .{ |
| 4530 | | .gpa = gpa, |
| 4531 | | .value = &curr, |
| 4532 | | .ast = ast, |
| 4533 | | .zoir = zoir, |
| 4411 | try updateFromZoirAlloc(Struct, &curr, .{ |
| 4412 | .arena = arena, |
| 4413 | .ast = &ast, |
| 4414 | .zoir = &zoir, |
| 4534 | 4415 | .diag = null, |
| 4535 | 4416 | }); |
| 4536 | 4417 | try std.testing.expectEqual(end, curr); |
| ... | ... | @@ -4555,23 +4436,24 @@ test "std.zon variants" { |
| 4555 | 4436 | end, |
| 4556 | 4437 | try fromSliceAlloc(Struct, .{ |
| 4557 | 4438 | .gpa = gpa, |
| 4439 | .arena = arena, |
| 4558 | 4440 | .source = ".{ .a = 100, .b = 20 }", |
| 4559 | 4441 | .diag = null, |
| 4560 | 4442 | }), |
| 4561 | 4443 | ); |
| 4562 | 4444 | try std.testing.expectEqual( |
| 4563 | 4445 | try fromZoir(Struct, .{ |
| 4564 | | .ast = ast, |
| 4565 | | .zoir = zoir, |
| 4446 | .ast = &ast, |
| 4447 | .zoir = &zoir, |
| 4566 | 4448 | .diag = null, |
| 4567 | 4449 | }), |
| 4568 | 4450 | end, |
| 4569 | 4451 | ); |
| 4570 | 4452 | try std.testing.expectEqual( |
| 4571 | 4453 | try fromZoirAlloc(Struct, .{ |
| 4572 | | .gpa = gpa, |
| 4573 | | .ast = ast, |
| 4574 | | .zoir = zoir, |
| 4454 | .arena = arena, |
| 4455 | .ast = &ast, |
| 4456 | .zoir = &zoir, |
| 4575 | 4457 | .diag = null, |
| 4576 | 4458 | }), |
| 4577 | 4459 | end, |