master
   1//! The simplest way to parse ZON at runtime is to use `fromSlice`/`fromSliceAlloc`.
   2//!
   3//! Note that if you need to parse ZON at compile time, you may use `@import`.
   4//!
   5//! Parsing from individual Zoir nodes is also available:
   6//! * `fromZoir`/`fromZoirAlloc`
   7//! * `fromZoirNode`/`fromZoirNodeAlloc`
   8//!
   9//! For lower level control over parsing, see `std.zig.Zoir`.
  10
  11const std = @import("std");
  12const builtin = @import("builtin");
  13const Allocator = std.mem.Allocator;
  14const Ast = std.zig.Ast;
  15const Zoir = std.zig.Zoir;
  16const ZonGen = std.zig.ZonGen;
  17const TokenIndex = std.zig.Ast.TokenIndex;
  18const Base = std.zig.number_literal.Base;
  19const StrLitErr = std.zig.string_literal.Error;
  20const NumberLiteralError = std.zig.number_literal.Error;
  21const assert = std.debug.assert;
  22const ArrayList = std.ArrayList;
  23
  24/// Rename when adding or removing support for a type.
  25const valid_types = {};
  26
  27/// Configuration for the runtime parser.
  28pub const Options = struct {
  29    /// If true, unknown fields do not error.
  30    ignore_unknown_fields: bool = false,
  31    /// If true, the parser cleans up partially parsed values on error. This requires some extra
  32    /// bookkeeping, so you may want to turn it off if you don't need this feature (e.g. because
  33    /// you're using arena allocation.)
  34    free_on_error: bool = true,
  35};
  36
  37pub const Error = union(enum) {
  38    zoir: Zoir.CompileError,
  39    type_check: Error.TypeCheckFailure,
  40
  41    pub const Note = union(enum) {
  42        zoir: Zoir.CompileError.Note,
  43        type_check: TypeCheckFailure.Note,
  44
  45        pub const Iterator = struct {
  46            index: usize = 0,
  47            err: Error,
  48            diag: *const Diagnostics,
  49
  50            pub fn next(self: *@This()) ?Note {
  51                switch (self.err) {
  52                    .zoir => |err| {
  53                        if (self.index >= err.note_count) return null;
  54                        const note = err.getNotes(self.diag.zoir)[self.index];
  55                        self.index += 1;
  56                        return .{ .zoir = note };
  57                    },
  58                    .type_check => |err| {
  59                        if (self.index >= err.getNoteCount()) return null;
  60                        const note = err.getNote(self.index);
  61                        self.index += 1;
  62                        return .{ .type_check = note };
  63                    },
  64                }
  65            }
  66        };
  67
  68        fn formatMessage(self: []const u8, w: *std.Io.Writer) std.Io.Writer.Error!void {
  69            // Just writes the string for now, but we're keeping this behind a formatter so we have
  70            // the option to extend it in the future to print more advanced messages (like `Error`
  71            // does) without breaking the API.
  72            try w.writeAll(self);
  73        }
  74
  75        pub fn fmtMessage(self: Note, diag: *const Diagnostics) std.fmt.Alt([]const u8, Note.formatMessage) {
  76            return .{ .data = switch (self) {
  77                .zoir => |note| note.msg.get(diag.zoir),
  78                .type_check => |note| note.msg,
  79            } };
  80        }
  81
  82        pub fn getLocation(self: Note, diag: *const Diagnostics) Ast.Location {
  83            switch (self) {
  84                .zoir => |note| return zoirErrorLocation(diag.ast, note.token, note.node_or_offset),
  85                .type_check => |note| return diag.ast.tokenLocation(note.offset, note.token),
  86            }
  87        }
  88    };
  89
  90    pub const Iterator = struct {
  91        index: usize = 0,
  92        diag: *const Diagnostics,
  93
  94        pub fn next(self: *@This()) ?Error {
  95            if (self.index < self.diag.zoir.compile_errors.len) {
  96                const result: Error = .{ .zoir = self.diag.zoir.compile_errors[self.index] };
  97                self.index += 1;
  98                return result;
  99            }
 100
 101            if (self.diag.type_check) |err| {
 102                if (self.index == self.diag.zoir.compile_errors.len) {
 103                    const result: Error = .{ .type_check = err };
 104                    self.index += 1;
 105                    return result;
 106                }
 107            }
 108
 109            return null;
 110        }
 111    };
 112
 113    const TypeCheckFailure = struct {
 114        const Note = struct {
 115            token: Ast.TokenIndex,
 116            offset: u32,
 117            msg: []const u8,
 118            owned: bool,
 119
 120            fn deinit(self: @This(), gpa: Allocator) void {
 121                if (self.owned) gpa.free(self.msg);
 122            }
 123        };
 124
 125        message: []const u8,
 126        owned: bool,
 127        token: Ast.TokenIndex,
 128        offset: u32,
 129        note: ?@This().Note,
 130
 131        fn deinit(self: @This(), gpa: Allocator) void {
 132            if (self.note) |note| note.deinit(gpa);
 133            if (self.owned) gpa.free(self.message);
 134        }
 135
 136        fn getNoteCount(self: @This()) usize {
 137            return @intFromBool(self.note != null);
 138        }
 139
 140        fn getNote(self: @This(), index: usize) @This().Note {
 141            assert(index == 0);
 142            return self.note.?;
 143        }
 144    };
 145
 146    const FormatMessage = struct {
 147        err: Error,
 148        diag: *const Diagnostics,
 149    };
 150
 151    fn formatMessage(self: FormatMessage, w: *std.Io.Writer) std.Io.Writer.Error!void {
 152        switch (self.err) {
 153            .zoir => |err| try w.writeAll(err.msg.get(self.diag.zoir)),
 154            .type_check => |tc| try w.writeAll(tc.message),
 155        }
 156    }
 157
 158    pub fn fmtMessage(self: @This(), diag: *const Diagnostics) std.fmt.Alt(FormatMessage, formatMessage) {
 159        return .{ .data = .{
 160            .err = self,
 161            .diag = diag,
 162        } };
 163    }
 164
 165    pub fn getLocation(self: @This(), diag: *const Diagnostics) Ast.Location {
 166        return switch (self) {
 167            .zoir => |err| return zoirErrorLocation(
 168                diag.ast,
 169                err.token,
 170                err.node_or_offset,
 171            ),
 172            .type_check => |err| return diag.ast.tokenLocation(err.offset, err.token),
 173        };
 174    }
 175
 176    pub fn iterateNotes(self: @This(), diag: *const Diagnostics) Note.Iterator {
 177        return .{ .err = self, .diag = diag };
 178    }
 179
 180    fn zoirErrorLocation(ast: Ast, maybe_token: Ast.OptionalTokenIndex, node_or_offset: u32) Ast.Location {
 181        if (maybe_token.unwrap()) |token| {
 182            var location = ast.tokenLocation(0, token);
 183            location.column += node_or_offset;
 184            return location;
 185        } else {
 186            const ast_node: Ast.Node.Index = @enumFromInt(node_or_offset);
 187            const token = ast.nodeMainToken(ast_node);
 188            return ast.tokenLocation(0, token);
 189        }
 190    }
 191};
 192
 193/// Information about the success or failure of a parse.
 194pub const Diagnostics = struct {
 195    ast: Ast = .{
 196        .source = "",
 197        .tokens = .empty,
 198        .nodes = .empty,
 199        .extra_data = &.{},
 200        .mode = .zon,
 201        .errors = &.{},
 202    },
 203    zoir: Zoir = .{
 204        .nodes = .empty,
 205        .extra = &.{},
 206        .limbs = &.{},
 207        .string_bytes = &.{},
 208        .compile_errors = &.{},
 209        .error_notes = &.{},
 210    },
 211    type_check: ?Error.TypeCheckFailure = null,
 212
 213    fn assertEmpty(self: Diagnostics) void {
 214        assert(self.ast.tokens.len == 0);
 215        assert(self.zoir.nodes.len == 0);
 216        assert(self.type_check == null);
 217    }
 218
 219    pub fn deinit(self: *Diagnostics, gpa: Allocator) void {
 220        self.ast.deinit(gpa);
 221        self.zoir.deinit(gpa);
 222        if (self.type_check) |tc| tc.deinit(gpa);
 223        self.* = undefined;
 224    }
 225
 226    pub fn iterateErrors(self: *const Diagnostics) Error.Iterator {
 227        return .{ .diag = self };
 228    }
 229
 230    pub fn format(self: *const @This(), w: *std.Io.Writer) std.Io.Writer.Error!void {
 231        var errors = self.iterateErrors();
 232        while (errors.next()) |err| {
 233            const loc = err.getLocation(self);
 234            const msg = err.fmtMessage(self);
 235            try w.print("{d}:{d}: error: {f}\n", .{ loc.line + 1, loc.column + 1, msg });
 236
 237            var notes = err.iterateNotes(self);
 238            while (notes.next()) |note| {
 239                const note_loc = note.getLocation(self);
 240                const note_msg = note.fmtMessage(self);
 241                try w.print("{d}:{d}: note: {f}\n", .{
 242                    note_loc.line + 1,
 243                    note_loc.column + 1,
 244                    note_msg,
 245                });
 246            }
 247        }
 248    }
 249};
 250
 251/// Parses the given slice as ZON.
 252///
 253/// Returns `error.OutOfMemory` on allocation failure, or `error.ParseZon` error if the ZON is
 254/// invalid or can not be deserialized into type `T`.
 255///
 256/// When the parser returns `error.ParseZon`, it will also store a human readable explanation in
 257/// `diag` if non null. If diag is not null, it must be initialized to `.{}`.
 258///
 259/// Asserts at compile time that the result type doesn't contain pointers. As such, the result
 260/// doesn't need to be freed.
 261///
 262/// An allocator is still required for temporary allocations made during parsing.
 263pub fn fromSlice(
 264    T: type,
 265    gpa: Allocator,
 266    source: [:0]const u8,
 267    diag: ?*Diagnostics,
 268    options: Options,
 269) error{ OutOfMemory, ParseZon }!T {
 270    comptime assert(!requiresAllocator(T));
 271    return fromSliceAlloc(T, gpa, source, diag, options);
 272}
 273
 274/// Like `fromSlice`, but the result may contain pointers. To automatically free the result, see
 275/// `free`.
 276pub fn fromSliceAlloc(
 277    /// The type to deserialize into. May not be or contain any of the following types:
 278    /// * Any comptime-only type, except in a comptime field
 279    /// * `type`
 280    /// * `void`, except as a union payload
 281    /// * `noreturn`
 282    /// * An error set/error union
 283    /// * A many-pointer or C-pointer
 284    /// * An opaque type, including `anyopaque`
 285    /// * An async frame type, including `anyframe` and `anyframe->T`
 286    /// * A function
 287    ///
 288    /// All other types are valid. Unsupported types will fail at compile time.
 289    T: type,
 290    gpa: Allocator,
 291    source: [:0]const u8,
 292    diag: ?*Diagnostics,
 293    options: Options,
 294) error{ OutOfMemory, ParseZon }!T {
 295    if (diag) |s| s.assertEmpty();
 296
 297    var ast = try std.zig.Ast.parse(gpa, source, .zon);
 298    defer if (diag == null) ast.deinit(gpa);
 299    if (diag) |s| s.ast = ast;
 300
 301    // If there's no diagnostics, Zoir exists for the lifetime of this function. If there is a
 302    // diagnostics, ownership is transferred to diagnostics.
 303    var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false });
 304    defer if (diag == null) zoir.deinit(gpa);
 305
 306    if (diag) |s| s.* = .{};
 307    return fromZoirAlloc(T, gpa, ast, zoir, diag, options);
 308}
 309
 310/// Like `fromSlice`, but operates on `Zoir` instead of ZON source.
 311pub fn fromZoir(
 312    T: type,
 313    ast: Ast,
 314    zoir: Zoir,
 315    diag: ?*Diagnostics,
 316    options: Options,
 317) error{ParseZon}!T {
 318    comptime assert(!requiresAllocator(T));
 319    var buf: [0]u8 = .{};
 320    var failing_allocator = std.heap.FixedBufferAllocator.init(&buf);
 321    return fromZoirAlloc(
 322        T,
 323        failing_allocator.allocator(),
 324        ast,
 325        zoir,
 326        diag,
 327        options,
 328    ) catch |err| switch (err) {
 329        error.OutOfMemory => unreachable, // Checked by comptime assertion above
 330        else => |e| return e,
 331    };
 332}
 333
 334/// Like `fromSliceAlloc`, but operates on `Zoir` instead of ZON source.
 335pub fn fromZoirAlloc(
 336    T: type,
 337    gpa: Allocator,
 338    ast: Ast,
 339    zoir: Zoir,
 340    diag: ?*Diagnostics,
 341    options: Options,
 342) error{ OutOfMemory, ParseZon }!T {
 343    return fromZoirNodeAlloc(T, gpa, ast, zoir, .root, diag, options);
 344}
 345
 346/// Like `fromZoir`, but the parse starts at `node` instead of root.
 347pub fn fromZoirNode(
 348    T: type,
 349    ast: Ast,
 350    zoir: Zoir,
 351    node: Zoir.Node.Index,
 352    diag: ?*Diagnostics,
 353    options: Options,
 354) error{ParseZon}!T {
 355    comptime assert(!requiresAllocator(T));
 356    var buf: [0]u8 = .{};
 357    var failing_allocator = std.heap.FixedBufferAllocator.init(&buf);
 358    return fromZoirNodeAlloc(
 359        T,
 360        failing_allocator.allocator(),
 361        ast,
 362        zoir,
 363        node,
 364        diag,
 365        options,
 366    ) catch |err| switch (err) {
 367        error.OutOfMemory => unreachable, // Checked by comptime assertion above
 368        else => |e| return e,
 369    };
 370}
 371
 372/// Like `fromZoirAlloc`, but the parse starts at `node` instead of root.
 373pub fn fromZoirNodeAlloc(
 374    T: type,
 375    gpa: Allocator,
 376    ast: Ast,
 377    zoir: Zoir,
 378    node: Zoir.Node.Index,
 379    diag: ?*Diagnostics,
 380    options: Options,
 381) error{ OutOfMemory, ParseZon }!T {
 382    comptime assert(canParseType(T));
 383
 384    if (diag) |s| {
 385        s.assertEmpty();
 386        s.ast = ast;
 387        s.zoir = zoir;
 388    }
 389
 390    if (zoir.hasCompileErrors()) {
 391        return error.ParseZon;
 392    }
 393
 394    var parser: Parser = .{
 395        .gpa = gpa,
 396        .ast = ast,
 397        .zoir = zoir,
 398        .options = options,
 399        .diag = diag,
 400    };
 401
 402    return parser.parseExpr(T, node);
 403}
 404
 405/// Frees ZON values.
 406///
 407/// Provided for convenience, you may also free these values on your own using the same allocator
 408/// passed into the parser.
 409///
 410/// Asserts at comptime that sufficient information is available via the type system to free this
 411/// value. Untagged unions, for example, will fail this assert.
 412pub fn free(gpa: Allocator, value: anytype) void {
 413    const Value = @TypeOf(value);
 414
 415    _ = valid_types;
 416    switch (@typeInfo(Value)) {
 417        .bool, .int, .float, .@"enum" => {},
 418        .pointer => |pointer| {
 419            switch (pointer.size) {
 420                .one => {
 421                    free(gpa, value.*);
 422                    gpa.destroy(value);
 423                },
 424                .slice => {
 425                    for (value) |item| {
 426                        free(gpa, item);
 427                    }
 428                    gpa.free(value);
 429                },
 430                .many, .c => comptime unreachable,
 431            }
 432        },
 433        .array => {
 434            freeArray(gpa, @TypeOf(value), &value);
 435        },
 436        .vector => |vector| {
 437            const array: [vector.len]vector.child = value;
 438            freeArray(gpa, @TypeOf(array), &array);
 439        },
 440        .@"struct" => |@"struct"| inline for (@"struct".fields) |field| {
 441            free(gpa, @field(value, field.name));
 442        },
 443        .@"union" => |@"union"| if (@"union".tag_type == null) {
 444            if (comptime requiresAllocator(Value)) unreachable;
 445        } else switch (value) {
 446            inline else => |_, tag| {
 447                free(gpa, @field(value, @tagName(tag)));
 448            },
 449        },
 450        .optional => if (value) |some| {
 451            free(gpa, some);
 452        },
 453        .void => {},
 454        else => comptime unreachable,
 455    }
 456}
 457
 458fn freeArray(gpa: Allocator, comptime A: type, array: *const A) void {
 459    for (array) |elem| free(gpa, elem);
 460}
 461
 462fn requiresAllocator(T: type) bool {
 463    _ = valid_types;
 464    return switch (@typeInfo(T)) {
 465        .pointer => true,
 466        .array => |array| return array.len > 0 and requiresAllocator(array.child),
 467        .@"struct" => |@"struct"| inline for (@"struct".fields) |field| {
 468            if (requiresAllocator(field.type)) {
 469                break true;
 470            }
 471        } else false,
 472        .@"union" => |@"union"| inline for (@"union".fields) |field| {
 473            if (requiresAllocator(field.type)) {
 474                break true;
 475            }
 476        } else false,
 477        .optional => |optional| requiresAllocator(optional.child),
 478        .vector => |vector| return vector.len > 0 and requiresAllocator(vector.child),
 479        else => false,
 480    };
 481}
 482
 483const Parser = struct {
 484    gpa: Allocator,
 485    ast: Ast,
 486    zoir: Zoir,
 487    diag: ?*Diagnostics,
 488    options: Options,
 489
 490    const ParseExprError = error{ ParseZon, OutOfMemory };
 491
 492    fn parseExpr(self: *@This(), T: type, node: Zoir.Node.Index) ParseExprError!T {
 493        return self.parseExprInner(T, node) catch |err| switch (err) {
 494            error.WrongType => return self.failExpectedType(T, node),
 495            else => |e| return e,
 496        };
 497    }
 498
 499    const ParseExprInnerError = error{ ParseZon, OutOfMemory, WrongType };
 500
 501    fn parseExprInner(
 502        self: *@This(),
 503        T: type,
 504        node: Zoir.Node.Index,
 505    ) ParseExprInnerError!T {
 506        if (T == Zoir.Node.Index) {
 507            return node;
 508        }
 509
 510        switch (@typeInfo(T)) {
 511            .optional => |optional| if (node.get(self.zoir) == .null) {
 512                return null;
 513            } else {
 514                return try self.parseExprInner(optional.child, node);
 515            },
 516            .bool => return self.parseBool(node),
 517            .int => return self.parseInt(T, node),
 518            .float => return self.parseFloat(T, node),
 519            .@"enum" => return self.parseEnumLiteral(T, node),
 520            .pointer => |pointer| switch (pointer.size) {
 521                .one => {
 522                    const result = try self.gpa.create(pointer.child);
 523                    errdefer self.gpa.destroy(result);
 524                    result.* = try self.parseExprInner(pointer.child, node);
 525                    return result;
 526                },
 527                .slice => return self.parseSlicePointer(T, node),
 528                else => comptime unreachable,
 529            },
 530            .array => return self.parseArray(T, node),
 531            .vector => |vector| {
 532                const A = [vector.len]vector.child;
 533                return try self.parseArray(A, node);
 534            },
 535            .@"struct" => |@"struct"| if (@"struct".is_tuple)
 536                return self.parseTuple(T, node)
 537            else
 538                return self.parseStruct(T, node),
 539            .@"union" => return self.parseUnion(T, node),
 540
 541            else => comptime unreachable,
 542        }
 543    }
 544
 545    /// Prints a message of the form `expected T` where T is first converted to a ZON type. For
 546    /// example, `**?**u8` becomes `?u8`, and types that involve user specified type names are just
 547    /// referred to by the type of container.
 548    fn failExpectedType(
 549        self: @This(),
 550        T: type,
 551        node: Zoir.Node.Index,
 552    ) error{ ParseZon, OutOfMemory } {
 553        @branchHint(.cold);
 554        return self.failExpectedTypeInner(T, false, node);
 555    }
 556
 557    fn failExpectedTypeInner(
 558        self: @This(),
 559        T: type,
 560        opt: bool,
 561        node: Zoir.Node.Index,
 562    ) error{ ParseZon, OutOfMemory } {
 563        _ = valid_types;
 564        switch (@typeInfo(T)) {
 565            .@"struct" => |@"struct"| if (@"struct".is_tuple) {
 566                if (opt) {
 567                    return self.failNode(node, "expected optional tuple");
 568                } else {
 569                    return self.failNode(node, "expected tuple");
 570                }
 571            } else {
 572                if (opt) {
 573                    return self.failNode(node, "expected optional struct");
 574                } else {
 575                    return self.failNode(node, "expected struct");
 576                }
 577            },
 578            .@"union" => if (opt) {
 579                return self.failNode(node, "expected optional union");
 580            } else {
 581                return self.failNode(node, "expected union");
 582            },
 583            .array => if (opt) {
 584                return self.failNode(node, "expected optional array");
 585            } else {
 586                return self.failNode(node, "expected array");
 587            },
 588            .pointer => |pointer| switch (pointer.size) {
 589                .one => return self.failExpectedTypeInner(pointer.child, opt, node),
 590                .slice => {
 591                    if (pointer.child == u8 and
 592                        pointer.is_const and
 593                        (pointer.sentinel() == null or pointer.sentinel() == 0) and
 594                        pointer.alignment == 1)
 595                    {
 596                        if (opt) {
 597                            return self.failNode(node, "expected optional string");
 598                        } else {
 599                            return self.failNode(node, "expected string");
 600                        }
 601                    } else {
 602                        if (opt) {
 603                            return self.failNode(node, "expected optional array");
 604                        } else {
 605                            return self.failNode(node, "expected array");
 606                        }
 607                    }
 608                },
 609                else => comptime unreachable,
 610            },
 611            .vector, .bool, .int, .float => if (opt) {
 612                return self.failNodeFmt(node, "expected type '{s}'", .{@typeName(?T)});
 613            } else {
 614                return self.failNodeFmt(node, "expected type '{s}'", .{@typeName(T)});
 615            },
 616            .@"enum" => if (opt) {
 617                return self.failNode(node, "expected optional enum literal");
 618            } else {
 619                return self.failNode(node, "expected enum literal");
 620            },
 621            .optional => |optional| {
 622                return self.failExpectedTypeInner(optional.child, true, node);
 623            },
 624            else => comptime unreachable,
 625        }
 626    }
 627
 628    fn parseBool(self: @This(), node: Zoir.Node.Index) !bool {
 629        switch (node.get(self.zoir)) {
 630            .true => return true,
 631            .false => return false,
 632            else => return error.WrongType,
 633        }
 634    }
 635
 636    fn parseInt(self: @This(), T: type, node: Zoir.Node.Index) !T {
 637        switch (node.get(self.zoir)) {
 638            .int_literal => |int| switch (int) {
 639                .small => |val| return std.math.cast(T, val) orelse
 640                    self.failCannotRepresent(T, node),
 641                .big => |val| return val.toInt(T) catch
 642                    self.failCannotRepresent(T, node),
 643            },
 644            .float_literal => |val| return intFromFloatExact(T, val) orelse
 645                self.failCannotRepresent(T, node),
 646
 647            .char_literal => |val| return std.math.cast(T, val) orelse
 648                self.failCannotRepresent(T, node),
 649            else => return error.WrongType,
 650        }
 651    }
 652
 653    fn parseFloat(self: @This(), T: type, node: Zoir.Node.Index) !T {
 654        switch (node.get(self.zoir)) {
 655            .int_literal => |int| switch (int) {
 656                .small => |val| return @floatFromInt(val),
 657                .big => |val| return val.toFloat(T, .nearest_even)[0],
 658            },
 659            .float_literal => |val| return @floatCast(val),
 660            .pos_inf => return std.math.inf(T),
 661            .neg_inf => return -std.math.inf(T),
 662            .nan => return std.math.nan(T),
 663            .char_literal => |val| return @floatFromInt(val),
 664            else => return error.WrongType,
 665        }
 666    }
 667
 668    fn parseEnumLiteral(self: @This(), T: type, node: Zoir.Node.Index) !T {
 669        switch (node.get(self.zoir)) {
 670            .enum_literal => |field_name| {
 671                // Create a comptime string map for the enum fields
 672                const enum_fields = @typeInfo(T).@"enum".fields;
 673                comptime var kvs_list: [enum_fields.len]struct { []const u8, T } = undefined;
 674                inline for (enum_fields, 0..) |field, i| {
 675                    kvs_list[i] = .{ field.name, @enumFromInt(field.value) };
 676                }
 677                const enum_tags = std.StaticStringMap(T).initComptime(kvs_list);
 678
 679                // Get the tag if it exists
 680                const field_name_str = field_name.get(self.zoir);
 681                return enum_tags.get(field_name_str) orelse
 682                    self.failUnexpected(T, "enum literal", node, null, field_name_str);
 683            },
 684            else => return error.WrongType,
 685        }
 686    }
 687
 688    fn parseSlicePointer(self: *@This(), T: type, node: Zoir.Node.Index) ParseExprInnerError!T {
 689        switch (node.get(self.zoir)) {
 690            .string_literal => return self.parseString(T, node),
 691            .array_literal => |nodes| return self.parseSlice(T, nodes),
 692            .empty_literal => return self.parseSlice(T, .{ .start = node, .len = 0 }),
 693            else => return error.WrongType,
 694        }
 695    }
 696
 697    fn parseString(self: *@This(), T: type, node: Zoir.Node.Index) ParseExprInnerError!T {
 698        const ast_node = node.getAstNode(self.zoir);
 699        const pointer = @typeInfo(T).pointer;
 700        var size_hint = ZonGen.strLitSizeHint(self.ast, ast_node);
 701        if (pointer.sentinel() != null) size_hint += 1;
 702
 703        var aw: std.Io.Writer.Allocating = .init(self.gpa);
 704        try aw.ensureUnusedCapacity(size_hint);
 705        defer aw.deinit();
 706        const result = ZonGen.parseStrLit(self.ast, ast_node, &aw.writer) catch return error.OutOfMemory;
 707        switch (result) {
 708            .success => {},
 709            .failure => |err| {
 710                const token = self.ast.nodeMainToken(ast_node);
 711                const raw_string = self.ast.tokenSlice(token);
 712                return self.failTokenFmt(token, @intCast(err.offset()), "{f}", .{err.fmt(raw_string)});
 713            },
 714        }
 715
 716        if (pointer.child != u8 or
 717            pointer.size != .slice or
 718            !pointer.is_const or
 719            (pointer.sentinel() != null and pointer.sentinel() != 0) or
 720            pointer.alignment != 1)
 721        {
 722            return error.WrongType;
 723        }
 724
 725        if (pointer.sentinel() != null) {
 726            return aw.toOwnedSliceSentinel(0);
 727        } else {
 728            return aw.toOwnedSlice();
 729        }
 730    }
 731
 732    fn parseSlice(self: *@This(), T: type, nodes: Zoir.Node.Index.Range) !T {
 733        const pointer = @typeInfo(T).pointer;
 734
 735        // Make sure we're working with a slice
 736        switch (pointer.size) {
 737            .slice => {},
 738            .one, .many, .c => comptime unreachable,
 739        }
 740
 741        // Allocate the slice
 742        const slice = try self.gpa.allocWithOptions(
 743            pointer.child,
 744            nodes.len,
 745            .fromByteUnits(pointer.alignment),
 746            pointer.sentinel(),
 747        );
 748        errdefer self.gpa.free(slice);
 749
 750        // Parse the elements and return the slice
 751        for (slice, 0..) |*elem, i| {
 752            errdefer if (self.options.free_on_error) {
 753                for (slice[0..i]) |item| {
 754                    free(self.gpa, item);
 755                }
 756            };
 757            elem.* = try self.parseExpr(pointer.child, nodes.at(@intCast(i)));
 758        }
 759
 760        return slice;
 761    }
 762
 763    fn parseArray(self: *@This(), T: type, node: Zoir.Node.Index) !T {
 764        const nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) {
 765            .array_literal => |nodes| nodes,
 766            .empty_literal => .{ .start = node, .len = 0 },
 767            else => return error.WrongType,
 768        };
 769
 770        const array_info = @typeInfo(T).array;
 771
 772        // Check if the size matches
 773        if (nodes.len < array_info.len) {
 774            return self.failNodeFmt(
 775                node,
 776                "expected {} array elements; found {}",
 777                .{ array_info.len, nodes.len },
 778            );
 779        } else if (nodes.len > array_info.len) {
 780            return self.failNodeFmt(
 781                nodes.at(array_info.len),
 782                "index {} outside of array of length {}",
 783                .{ array_info.len, array_info.len },
 784            );
 785        }
 786
 787        // Parse the elements and return the array
 788        var result: T = undefined;
 789        for (&result, 0..) |*elem, i| {
 790            // If we fail to parse this field, free all fields before it
 791            errdefer if (self.options.free_on_error) {
 792                for (result[0..i]) |item| {
 793                    free(self.gpa, item);
 794                }
 795            };
 796
 797            elem.* = try self.parseExpr(array_info.child, nodes.at(@intCast(i)));
 798        }
 799        if (array_info.sentinel()) |s| result[result.len] = s;
 800        return result;
 801    }
 802
 803    fn parseStruct(self: *@This(), T: type, node: Zoir.Node.Index) !T {
 804        const repr = node.get(self.zoir);
 805        const fields: @FieldType(Zoir.Node, "struct_literal") = switch (repr) {
 806            .struct_literal => |nodes| nodes,
 807            .empty_literal => .{ .names = &.{}, .vals = .{ .start = node, .len = 0 } },
 808            else => return error.WrongType,
 809        };
 810
 811        const field_infos = @typeInfo(T).@"struct".fields;
 812
 813        // Build a map from field name to index.
 814        // The special value `comptime_field` indicates that this is actually a comptime field.
 815        const comptime_field = std.math.maxInt(usize);
 816        const field_indices: std.StaticStringMap(usize) = comptime b: {
 817            var kvs_list: [field_infos.len]struct { []const u8, usize } = undefined;
 818            for (&kvs_list, field_infos, 0..) |*kv, field, i| {
 819                kv.* = .{ field.name, if (field.is_comptime) comptime_field else i };
 820            }
 821            break :b .initComptime(kvs_list);
 822        };
 823
 824        // Parse the struct
 825        var result: T = undefined;
 826        var field_found: [field_infos.len]bool = @splat(false);
 827
 828        // If we fail partway through, free all already initialized fields
 829        var initialized: usize = 0;
 830        errdefer if (self.options.free_on_error and field_infos.len > 0) {
 831            for (fields.names[0..initialized]) |name_runtime| {
 832                switch (field_indices.get(name_runtime.get(self.zoir)) orelse continue) {
 833                    inline 0...(field_infos.len - 1) => |name_index| {
 834                        const name = field_infos[name_index].name;
 835                        free(self.gpa, @field(result, name));
 836                    },
 837                    else => unreachable, // Can't be out of bounds
 838                }
 839            }
 840        };
 841
 842        // Fill in the fields we found
 843        for (0..fields.names.len) |i| {
 844            const name = fields.names[i].get(self.zoir);
 845            const field_index = field_indices.get(name) orelse {
 846                if (self.options.ignore_unknown_fields) continue;
 847                return self.failUnexpected(T, "field", node, i, name);
 848            };
 849            if (field_index == comptime_field) {
 850                return self.failComptimeField(node, i);
 851            }
 852
 853            // Mark the field as found. Assert that the found array is not zero length to satisfy
 854            // the type checker (it can't be since we made it into an iteration of this loop.)
 855            if (field_found.len == 0) unreachable;
 856            field_found[field_index] = true;
 857
 858            switch (field_index) {
 859                inline 0...(field_infos.len - 1) => |j| {
 860                    if (field_infos[j].is_comptime) unreachable;
 861
 862                    @field(result, field_infos[j].name) = try self.parseExpr(
 863                        field_infos[j].type,
 864                        fields.vals.at(@intCast(i)),
 865                    );
 866                },
 867                else => unreachable, // Can't be out of bounds
 868            }
 869
 870            initialized += 1;
 871        }
 872
 873        // Fill in any missing default fields
 874        inline for (field_found, 0..) |found, i| {
 875            if (!found) {
 876                const field_info = field_infos[i];
 877                if (field_info.default_value_ptr) |default| {
 878                    const typed: *const field_info.type = @ptrCast(@alignCast(default));
 879                    @field(result, field_info.name) = typed.*;
 880                } else {
 881                    return self.failNodeFmt(
 882                        node,
 883                        "missing required field {s}",
 884                        .{field_infos[i].name},
 885                    );
 886                }
 887            }
 888        }
 889
 890        return result;
 891    }
 892
 893    fn parseTuple(self: *@This(), T: type, node: Zoir.Node.Index) !T {
 894        const nodes: Zoir.Node.Index.Range = switch (node.get(self.zoir)) {
 895            .array_literal => |nodes| nodes,
 896            .empty_literal => .{ .start = node, .len = 0 },
 897            else => return error.WrongType,
 898        };
 899
 900        var result: T = undefined;
 901        const field_infos = @typeInfo(T).@"struct".fields;
 902
 903        if (nodes.len > field_infos.len) {
 904            return self.failNodeFmt(
 905                nodes.at(field_infos.len),
 906                "index {} outside of tuple length {}",
 907                .{ field_infos.len, field_infos.len },
 908            );
 909        }
 910
 911        inline for (0..field_infos.len) |i| {
 912            // Check if we're out of bounds
 913            if (i >= nodes.len) {
 914                if (field_infos[i].default_value_ptr) |default| {
 915                    const typed: *const field_infos[i].type = @ptrCast(@alignCast(default));
 916                    @field(result, field_infos[i].name) = typed.*;
 917                } else {
 918                    return self.failNodeFmt(node, "missing tuple field with index {}", .{i});
 919                }
 920            } else {
 921                // If we fail to parse this field, free all fields before it
 922                errdefer if (self.options.free_on_error) {
 923                    inline for (0..i) |j| {
 924                        if (j >= i) break;
 925                        free(self.gpa, result[j]);
 926                    }
 927                };
 928
 929                if (field_infos[i].is_comptime) {
 930                    return self.failComptimeField(node, i);
 931                } else {
 932                    result[i] = try self.parseExpr(field_infos[i].type, nodes.at(i));
 933                }
 934            }
 935        }
 936
 937        return result;
 938    }
 939
 940    fn parseUnion(self: *@This(), T: type, node: Zoir.Node.Index) !T {
 941        const @"union" = @typeInfo(T).@"union";
 942        const field_infos = @"union".fields;
 943
 944        if (field_infos.len == 0) comptime unreachable;
 945
 946        // Gather info on the fields
 947        const field_indices = b: {
 948            comptime var kvs_list: [field_infos.len]struct { []const u8, usize } = undefined;
 949            inline for (field_infos, 0..) |field, i| {
 950                kvs_list[i] = .{ field.name, i };
 951            }
 952            break :b std.StaticStringMap(usize).initComptime(kvs_list);
 953        };
 954
 955        // Parse the union
 956        switch (node.get(self.zoir)) {
 957            .enum_literal => |field_name| {
 958                // The union must be tagged for an enum literal to coerce to it
 959                if (@"union".tag_type == null) {
 960                    return error.WrongType;
 961                }
 962
 963                // Get the index of the named field. We don't use `parseEnum` here as
 964                // the order of the enum and the order of the union might not match!
 965                const field_index = b: {
 966                    const field_name_str = field_name.get(self.zoir);
 967                    break :b field_indices.get(field_name_str) orelse
 968                        return self.failUnexpected(T, "field", node, null, field_name_str);
 969                };
 970
 971                // Initialize the union from the given field.
 972                switch (field_index) {
 973                    inline 0...field_infos.len - 1 => |i| {
 974                        // Fail if the field is not void
 975                        if (field_infos[i].type != void)
 976                            return self.failNode(node, "expected union");
 977
 978                        // Instantiate the union
 979                        return @unionInit(T, field_infos[i].name, {});
 980                    },
 981                    else => unreachable, // Can't be out of bounds
 982                }
 983            },
 984            .struct_literal => |struct_fields| {
 985                if (struct_fields.names.len != 1) {
 986                    return error.WrongType;
 987                }
 988
 989                // Fill in the field we found
 990                const field_name = struct_fields.names[0];
 991                const field_name_str = field_name.get(self.zoir);
 992                const field_val = struct_fields.vals.at(0);
 993                const field_index = field_indices.get(field_name_str) orelse
 994                    return self.failUnexpected(T, "field", node, 0, field_name_str);
 995
 996                switch (field_index) {
 997                    inline 0...field_infos.len - 1 => |i| {
 998                        if (field_infos[i].type == void) {
 999                            return self.failNode(field_val, "expected type 'void'");
1000                        } else {
1001                            const value = try self.parseExpr(field_infos[i].type, field_val);
1002                            return @unionInit(T, field_infos[i].name, value);
1003                        }
1004                    },
1005                    else => unreachable, // Can't be out of bounds
1006                }
1007            },
1008            else => return error.WrongType,
1009        }
1010    }
1011
1012    fn failTokenFmt(
1013        self: @This(),
1014        token: Ast.TokenIndex,
1015        offset: u32,
1016        comptime fmt: []const u8,
1017        args: anytype,
1018    ) error{ OutOfMemory, ParseZon } {
1019        @branchHint(.cold);
1020        return self.failTokenFmtNote(token, offset, fmt, args, null);
1021    }
1022
1023    fn failTokenFmtNote(
1024        self: @This(),
1025        token: Ast.TokenIndex,
1026        offset: u32,
1027        comptime fmt: []const u8,
1028        args: anytype,
1029        note: ?Error.TypeCheckFailure.Note,
1030    ) error{ OutOfMemory, ParseZon } {
1031        @branchHint(.cold);
1032        comptime assert(args.len > 0);
1033        if (self.diag) |s| s.type_check = .{
1034            .token = token,
1035            .offset = offset,
1036            .message = std.fmt.allocPrint(self.gpa, fmt, args) catch |err| {
1037                if (note) |n| n.deinit(self.gpa);
1038                return err;
1039            },
1040            .owned = true,
1041            .note = note,
1042        };
1043        return error.ParseZon;
1044    }
1045
1046    fn failNodeFmt(
1047        self: @This(),
1048        node: Zoir.Node.Index,
1049        comptime fmt: []const u8,
1050        args: anytype,
1051    ) error{ OutOfMemory, ParseZon } {
1052        @branchHint(.cold);
1053        const token = self.ast.nodeMainToken(node.getAstNode(self.zoir));
1054        return self.failTokenFmt(token, 0, fmt, args);
1055    }
1056
1057    fn failToken(
1058        self: @This(),
1059        failure: Error.TypeCheckFailure,
1060    ) error{ParseZon} {
1061        @branchHint(.cold);
1062        if (self.diag) |s| s.type_check = failure;
1063        return error.ParseZon;
1064    }
1065
1066    fn failNode(
1067        self: @This(),
1068        node: Zoir.Node.Index,
1069        message: []const u8,
1070    ) error{ParseZon} {
1071        @branchHint(.cold);
1072        const token = self.ast.nodeMainToken(node.getAstNode(self.zoir));
1073        return self.failToken(.{
1074            .token = token,
1075            .offset = 0,
1076            .message = message,
1077            .owned = false,
1078            .note = null,
1079        });
1080    }
1081
1082    fn failCannotRepresent(
1083        self: @This(),
1084        T: type,
1085        node: Zoir.Node.Index,
1086    ) error{ OutOfMemory, ParseZon } {
1087        @branchHint(.cold);
1088        return self.failNodeFmt(node, "type '{s}' cannot represent value", .{@typeName(T)});
1089    }
1090
1091    fn failUnexpected(
1092        self: @This(),
1093        T: type,
1094        item_kind: []const u8,
1095        node: Zoir.Node.Index,
1096        field: ?usize,
1097        name: []const u8,
1098    ) error{ OutOfMemory, ParseZon } {
1099        @branchHint(.cold);
1100        const gpa = self.gpa;
1101        const token = if (field) |f| b: {
1102            var buf: [2]Ast.Node.Index = undefined;
1103            const struct_init = self.ast.fullStructInit(&buf, node.getAstNode(self.zoir)).?;
1104            const field_node = struct_init.ast.fields[f];
1105            break :b self.ast.firstToken(field_node) - 2;
1106        } else self.ast.nodeMainToken(node.getAstNode(self.zoir));
1107        switch (@typeInfo(T)) {
1108            inline .@"struct", .@"union", .@"enum" => |info| {
1109                const note: Error.TypeCheckFailure.Note = if (info.fields.len == 0) b: {
1110                    break :b .{
1111                        .token = token,
1112                        .offset = 0,
1113                        .msg = "none expected",
1114                        .owned = false,
1115                    };
1116                } else b: {
1117                    const msg = "supported: ";
1118                    var buf: std.ArrayList(u8) = try .initCapacity(gpa, 64);
1119                    defer buf.deinit(gpa);
1120                    try buf.appendSlice(gpa, msg);
1121                    inline for (info.fields, 0..) |field_info, i| {
1122                        if (i != 0) try buf.appendSlice(gpa, ", ");
1123                        try buf.print(gpa, "'{f}'", .{std.zig.fmtIdFlags(field_info.name, .{
1124                            .allow_primitive = true,
1125                            .allow_underscore = true,
1126                        })});
1127                    }
1128                    break :b .{
1129                        .token = token,
1130                        .offset = 0,
1131                        .msg = try buf.toOwnedSlice(gpa),
1132                        .owned = true,
1133                    };
1134                };
1135                return self.failTokenFmtNote(
1136                    token,
1137                    0,
1138                    "unexpected {s} '{s}'",
1139                    .{ item_kind, name },
1140                    note,
1141                );
1142            },
1143            else => comptime unreachable,
1144        }
1145    }
1146
1147    // Technically we could do this if we were willing to do a deep equal to verify
1148    // the value matched, but doing so doesn't seem to support any real use cases
1149    // so isn't worth the complexity at the moment.
1150    fn failComptimeField(
1151        self: @This(),
1152        node: Zoir.Node.Index,
1153        field: usize,
1154    ) error{ OutOfMemory, ParseZon } {
1155        @branchHint(.cold);
1156        const ast_node = node.getAstNode(self.zoir);
1157        var buf: [2]Ast.Node.Index = undefined;
1158        const token = if (self.ast.fullStructInit(&buf, ast_node)) |struct_init| b: {
1159            const field_node = struct_init.ast.fields[field];
1160            break :b self.ast.firstToken(field_node);
1161        } else b: {
1162            const array_init = self.ast.fullArrayInit(&buf, ast_node).?;
1163            const value_node = array_init.ast.elements[field];
1164            break :b self.ast.firstToken(value_node);
1165        };
1166        return self.failToken(.{
1167            .token = token,
1168            .offset = 0,
1169            .message = "cannot initialize comptime field",
1170            .owned = false,
1171            .note = null,
1172        });
1173    }
1174};
1175
1176fn intFromFloatExact(T: type, value: anytype) ?T {
1177    if (value > std.math.maxInt(T) or value < std.math.minInt(T)) {
1178        return null;
1179    }
1180
1181    if (std.math.isNan(value) or std.math.trunc(value) != value) {
1182        return null;
1183    }
1184
1185    return @intFromFloat(value);
1186}
1187
1188fn canParseType(T: type) bool {
1189    comptime return canParseTypeInner(T, &.{}, false);
1190}
1191
1192fn canParseTypeInner(
1193    T: type,
1194    /// Visited structs and unions, to avoid infinite recursion.
1195    /// Tracking more types is unnecessary, and a little complex due to optional nesting.
1196    visited: []const type,
1197    parent_is_optional: bool,
1198) bool {
1199    return switch (@typeInfo(T)) {
1200        .bool,
1201        .int,
1202        .float,
1203        .null,
1204        .@"enum",
1205        => true,
1206
1207        .noreturn,
1208        .void,
1209        .type,
1210        .undefined,
1211        .error_union,
1212        .error_set,
1213        .@"fn",
1214        .frame,
1215        .@"anyframe",
1216        .@"opaque",
1217        .comptime_int,
1218        .comptime_float,
1219        .enum_literal,
1220        => false,
1221
1222        .pointer => |pointer| switch (pointer.size) {
1223            .one => canParseTypeInner(pointer.child, visited, parent_is_optional),
1224            .slice => canParseTypeInner(pointer.child, visited, false),
1225            .many, .c => false,
1226        },
1227
1228        .optional => |optional| if (parent_is_optional)
1229            false
1230        else
1231            canParseTypeInner(optional.child, visited, true),
1232
1233        .array => |array| canParseTypeInner(array.child, visited, false),
1234        .vector => |vector| canParseTypeInner(vector.child, visited, false),
1235
1236        .@"struct" => |@"struct"| {
1237            for (visited) |V| if (T == V) return true;
1238            const new_visited = visited ++ .{T};
1239            for (@"struct".fields) |field| {
1240                if (!field.is_comptime and !canParseTypeInner(field.type, new_visited, false)) {
1241                    return false;
1242                }
1243            }
1244            return true;
1245        },
1246        .@"union" => |@"union"| {
1247            for (visited) |V| if (T == V) return true;
1248            const new_visited = visited ++ .{T};
1249            for (@"union".fields) |field| {
1250                if (field.type != void and !canParseTypeInner(field.type, new_visited, false)) {
1251                    return false;
1252                }
1253            }
1254            return true;
1255        },
1256    };
1257}
1258
1259test "std.zon parse canParseType" {
1260    try std.testing.expect(!comptime canParseType(void));
1261    try std.testing.expect(!comptime canParseType(struct { f: [*]u8 }));
1262    try std.testing.expect(!comptime canParseType(struct { error{foo} }));
1263    try std.testing.expect(!comptime canParseType(union(enum) { a: void, b: [*c]u8 }));
1264    try std.testing.expect(!comptime canParseType(@Vector(0, [*c]u8)));
1265    try std.testing.expect(!comptime canParseType(*?[*c]u8));
1266    try std.testing.expect(comptime canParseType(enum(u8) { _ }));
1267    try std.testing.expect(comptime canParseType(union { foo: void }));
1268    try std.testing.expect(comptime canParseType(union(enum) { foo: void }));
1269    try std.testing.expect(!comptime canParseType(comptime_float));
1270    try std.testing.expect(!comptime canParseType(comptime_int));
1271    try std.testing.expect(comptime canParseType(struct { comptime foo: ??u8 = null }));
1272    try std.testing.expect(!comptime canParseType(@TypeOf(.foo)));
1273    try std.testing.expect(comptime canParseType(?u8));
1274    try std.testing.expect(comptime canParseType(*?*u8));
1275    try std.testing.expect(comptime canParseType(?struct {
1276        foo: ?struct {
1277            ?union(enum) {
1278                a: ?@Vector(0, ?*u8),
1279            },
1280            ?struct {
1281                f: ?[]?u8,
1282            },
1283        },
1284    }));
1285    try std.testing.expect(!comptime canParseType(??u8));
1286    try std.testing.expect(!comptime canParseType(?*?u8));
1287    try std.testing.expect(!comptime canParseType(*?*?*u8));
1288    try std.testing.expect(!comptime canParseType(struct { x: comptime_int = 2 }));
1289    try std.testing.expect(!comptime canParseType(struct { x: comptime_float = 2 }));
1290    try std.testing.expect(comptime canParseType(struct { comptime x: @TypeOf(.foo) = .foo }));
1291    try std.testing.expect(!comptime canParseType(struct { comptime_int }));
1292    const Recursive = struct { foo: ?*@This() };
1293    try std.testing.expect(comptime canParseType(Recursive));
1294
1295    // Make sure we validate nested optional before we early out due to already having seen
1296    // a type recursion!
1297    try std.testing.expect(!comptime canParseType(struct {
1298        add_to_visited: ?u8,
1299        retrieve_from_visited: ??u8,
1300    }));
1301}
1302
1303test "std.zon requiresAllocator" {
1304    try std.testing.expect(!requiresAllocator(u8));
1305    try std.testing.expect(!requiresAllocator(f32));
1306    try std.testing.expect(!requiresAllocator(enum { foo }));
1307    try std.testing.expect(!requiresAllocator(struct { f32 }));
1308    try std.testing.expect(!requiresAllocator(struct { x: f32 }));
1309    try std.testing.expect(!requiresAllocator([0][]const u8));
1310    try std.testing.expect(!requiresAllocator([2]u8));
1311    try std.testing.expect(!requiresAllocator(union { x: f32, y: f32 }));
1312    try std.testing.expect(!requiresAllocator(union(enum) { x: f32, y: f32 }));
1313    try std.testing.expect(!requiresAllocator(?f32));
1314    try std.testing.expect(!requiresAllocator(void));
1315    try std.testing.expect(!requiresAllocator(@TypeOf(null)));
1316    try std.testing.expect(!requiresAllocator(@Vector(3, u8)));
1317    try std.testing.expect(!requiresAllocator(@Vector(0, *const u8)));
1318
1319    try std.testing.expect(requiresAllocator([]u8));
1320    try std.testing.expect(requiresAllocator(*struct { u8, u8 }));
1321    try std.testing.expect(requiresAllocator([1][]const u8));
1322    try std.testing.expect(requiresAllocator(struct { x: i32, y: []u8 }));
1323    try std.testing.expect(requiresAllocator(union { x: i32, y: []u8 }));
1324    try std.testing.expect(requiresAllocator(union(enum) { x: i32, y: []u8 }));
1325    try std.testing.expect(requiresAllocator(?[]u8));
1326    try std.testing.expect(requiresAllocator(@Vector(3, *const u8)));
1327}
1328
1329test "std.zon ast errors" {
1330    const gpa = std.testing.allocator;
1331    var diag: Diagnostics = .{};
1332    defer diag.deinit(gpa);
1333    try std.testing.expectError(
1334        error.ParseZon,
1335        fromSlice(struct {}, gpa, ".{.x = 1 .y = 2}", &diag, .{}),
1336    );
1337    try std.testing.expectFmt("1:13: error: expected ',' after initializer\n", "{f}", .{diag});
1338}
1339
1340test "std.zon comments" {
1341    const gpa = std.testing.allocator;
1342
1343    try std.testing.expectEqual(@as(u8, 10), fromSlice(u8, gpa,
1344        \\// comment
1345        \\10 // comment
1346        \\// comment
1347    , null, .{}));
1348
1349    {
1350        var diag: Diagnostics = .{};
1351        defer diag.deinit(gpa);
1352        try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa,
1353            \\//! comment
1354            \\10 // comment
1355            \\// comment
1356        , &diag, .{}));
1357        try std.testing.expectFmt(
1358            "1:1: error: expected expression, found 'a document comment'\n",
1359            "{f}",
1360            .{diag},
1361        );
1362    }
1363}
1364
1365test "std.zon failure/oom formatting" {
1366    const gpa = std.testing.allocator;
1367    var failing_allocator = std.testing.FailingAllocator.init(gpa, .{
1368        .fail_index = 0,
1369        .resize_fail_index = 0,
1370    });
1371    var diag: Diagnostics = .{};
1372    defer diag.deinit(gpa);
1373    try std.testing.expectError(error.OutOfMemory, fromSliceAlloc(
1374        []const u8,
1375        failing_allocator.allocator(),
1376        "\"foo\"",
1377        &diag,
1378        .{},
1379    ));
1380    try std.testing.expectFmt("", "{f}", .{diag});
1381}
1382
1383test "std.zon fromSliceAlloc syntax error" {
1384    try std.testing.expectError(
1385        error.ParseZon,
1386        fromSlice(u8, std.testing.allocator, ".{", null, .{}),
1387    );
1388}
1389
1390test "std.zon optional" {
1391    const gpa = std.testing.allocator;
1392
1393    // Basic usage
1394    {
1395        const none = try fromSlice(?u32, gpa, "null", null, .{});
1396        try std.testing.expect(none == null);
1397        const some = try fromSlice(?u32, gpa, "1", null, .{});
1398        try std.testing.expect(some.? == 1);
1399    }
1400
1401    // Deep free
1402    {
1403        const none = try fromSliceAlloc(?[]const u8, gpa, "null", null, .{});
1404        try std.testing.expect(none == null);
1405        const some = try fromSliceAlloc(?[]const u8, gpa, "\"foo\"", null, .{});
1406        defer free(gpa, some);
1407        try std.testing.expectEqualStrings("foo", some.?);
1408    }
1409}
1410
1411test "std.zon unions" {
1412    const gpa = std.testing.allocator;
1413
1414    // Unions
1415    {
1416        const Tagged = union(enum) { x: f32, @"y y": bool, z, @"z z" };
1417        const Untagged = union { x: f32, @"y y": bool, z: void, @"z z": void };
1418
1419        const tagged_x = try fromSlice(Tagged, gpa, ".{.x = 1.5}", null, .{});
1420        try std.testing.expectEqual(Tagged{ .x = 1.5 }, tagged_x);
1421        const tagged_y = try fromSlice(Tagged, gpa, ".{.@\"y y\" = true}", null, .{});
1422        try std.testing.expectEqual(Tagged{ .@"y y" = true }, tagged_y);
1423        const tagged_z_shorthand = try fromSlice(Tagged, gpa, ".z", null, .{});
1424        try std.testing.expectEqual(@as(Tagged, .z), tagged_z_shorthand);
1425        const tagged_zz_shorthand = try fromSlice(Tagged, gpa, ".@\"z z\"", null, .{});
1426        try std.testing.expectEqual(@as(Tagged, .@"z z"), tagged_zz_shorthand);
1427
1428        const untagged_x = try fromSlice(Untagged, gpa, ".{.x = 1.5}", null, .{});
1429        try std.testing.expect(untagged_x.x == 1.5);
1430        const untagged_y = try fromSlice(Untagged, gpa, ".{.@\"y y\" = true}", null, .{});
1431        try std.testing.expect(untagged_y.@"y y");
1432    }
1433
1434    // Deep free
1435    {
1436        const Union = union(enum) { bar: []const u8, baz: bool };
1437
1438        const noalloc = try fromSliceAlloc(Union, gpa, ".{.baz = false}", null, .{});
1439        try std.testing.expectEqual(Union{ .baz = false }, noalloc);
1440
1441        const alloc = try fromSliceAlloc(Union, gpa, ".{.bar = \"qux\"}", null, .{});
1442        defer free(gpa, alloc);
1443        try std.testing.expectEqualDeep(Union{ .bar = "qux" }, alloc);
1444    }
1445
1446    // Unknown field
1447    {
1448        const Union = union { x: f32, y: f32 };
1449        var diag: Diagnostics = .{};
1450        defer diag.deinit(gpa);
1451        try std.testing.expectError(
1452            error.ParseZon,
1453            fromSliceAlloc(Union, gpa, ".{.z=2.5}", &diag, .{}),
1454        );
1455        try std.testing.expectFmt(
1456            \\1:4: error: unexpected field 'z'
1457            \\1:4: note: supported: 'x', 'y'
1458            \\
1459        ,
1460            "{f}",
1461            .{diag},
1462        );
1463    }
1464
1465    // Explicit void field
1466    {
1467        const Union = union(enum) { x: void };
1468        var diag: Diagnostics = .{};
1469        defer diag.deinit(gpa);
1470        try std.testing.expectError(
1471            error.ParseZon,
1472            fromSliceAlloc(Union, gpa, ".{.x=1}", &diag, .{}),
1473        );
1474        try std.testing.expectFmt("1:6: error: expected type 'void'\n", "{f}", .{diag});
1475    }
1476
1477    // Extra field
1478    {
1479        const Union = union { x: f32, y: bool };
1480        var diag: Diagnostics = .{};
1481        defer diag.deinit(gpa);
1482        try std.testing.expectError(
1483            error.ParseZon,
1484            fromSliceAlloc(Union, gpa, ".{.x = 1.5, .y = true}", &diag, .{}),
1485        );
1486        try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});
1487    }
1488
1489    // No fields
1490    {
1491        const Union = union { x: f32, y: bool };
1492        var diag: Diagnostics = .{};
1493        defer diag.deinit(gpa);
1494        try std.testing.expectError(
1495            error.ParseZon,
1496            fromSliceAlloc(Union, gpa, ".{}", &diag, .{}),
1497        );
1498        try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});
1499    }
1500
1501    // Enum literals cannot coerce into untagged unions
1502    {
1503        const Union = union { x: void };
1504        var diag: Diagnostics = .{};
1505        defer diag.deinit(gpa);
1506        try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".x", &diag, .{}));
1507        try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});
1508    }
1509
1510    // Unknown field for enum literal coercion
1511    {
1512        const Union = union(enum) { x: void };
1513        var diag: Diagnostics = .{};
1514        defer diag.deinit(gpa);
1515        try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".y", &diag, .{}));
1516        try std.testing.expectFmt(
1517            \\1:2: error: unexpected field 'y'
1518            \\1:2: note: supported: 'x'
1519            \\
1520        ,
1521            "{f}",
1522            .{diag},
1523        );
1524    }
1525
1526    // Non void field for enum literal coercion
1527    {
1528        const Union = union(enum) { x: f32 };
1529        var diag: Diagnostics = .{};
1530        defer diag.deinit(gpa);
1531        try std.testing.expectError(error.ParseZon, fromSliceAlloc(Union, gpa, ".x", &diag, .{}));
1532        try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});
1533    }
1534}
1535
1536test "std.zon structs" {
1537    const gpa = std.testing.allocator;
1538
1539    // Structs (various sizes tested since they're parsed differently)
1540    {
1541        const Vec0 = struct {};
1542        const Vec1 = struct { x: f32 };
1543        const Vec2 = struct { x: f32, y: f32 };
1544        const Vec3 = struct { x: f32, y: f32, z: f32 };
1545
1546        const zero = try fromSlice(Vec0, gpa, ".{}", null, .{});
1547        try std.testing.expectEqual(Vec0{}, zero);
1548
1549        const one = try fromSlice(Vec1, gpa, ".{.x = 1.2}", null, .{});
1550        try std.testing.expectEqual(Vec1{ .x = 1.2 }, one);
1551
1552        const two = try fromSlice(Vec2, gpa, ".{.x = 1.2, .y = 3.4}", null, .{});
1553        try std.testing.expectEqual(Vec2{ .x = 1.2, .y = 3.4 }, two);
1554
1555        const three = try fromSlice(Vec3, gpa, ".{.x = 1.2, .y = 3.4, .z = 5.6}", null, .{});
1556        try std.testing.expectEqual(Vec3{ .x = 1.2, .y = 3.4, .z = 5.6 }, three);
1557    }
1558
1559    // Deep free (structs and arrays)
1560    {
1561        const Foo = struct { bar: []const u8, baz: []const []const u8 };
1562
1563        const parsed = try fromSliceAlloc(
1564            Foo,
1565            gpa,
1566            ".{.bar = \"qux\", .baz = .{\"a\", \"b\"}}",
1567            null,
1568            .{},
1569        );
1570        defer free(gpa, parsed);
1571        try std.testing.expectEqualDeep(Foo{ .bar = "qux", .baz = &.{ "a", "b" } }, parsed);
1572    }
1573
1574    // Unknown field
1575    {
1576        const Vec2 = struct { x: f32, y: f32 };
1577        var diag: Diagnostics = .{};
1578        defer diag.deinit(gpa);
1579        try std.testing.expectError(
1580            error.ParseZon,
1581            fromSlice(Vec2, gpa, ".{.x=1.5, .z=2.5}", &diag, .{}),
1582        );
1583        try std.testing.expectFmt(
1584            \\1:12: error: unexpected field 'z'
1585            \\1:12: note: supported: 'x', 'y'
1586            \\
1587        ,
1588            "{f}",
1589            .{diag},
1590        );
1591    }
1592
1593    // Duplicate field
1594    {
1595        const Vec2 = struct { x: f32, y: f32 };
1596        var diag: Diagnostics = .{};
1597        defer diag.deinit(gpa);
1598        try std.testing.expectError(
1599            error.ParseZon,
1600            fromSlice(Vec2, gpa, ".{.x=1.5, .x=2.5, .x=3.5}", &diag, .{}),
1601        );
1602        try std.testing.expectFmt(
1603            \\1:4: error: duplicate struct field name
1604            \\1:12: note: duplicate name here
1605            \\
1606        , "{f}", .{diag});
1607    }
1608
1609    // Ignore unknown fields
1610    {
1611        const Vec2 = struct { x: f32, y: f32 = 2.0 };
1612        const parsed = try fromSlice(Vec2, gpa, ".{ .x = 1.0, .z = 3.0 }", null, .{
1613            .ignore_unknown_fields = true,
1614        });
1615        try std.testing.expectEqual(Vec2{ .x = 1.0, .y = 2.0 }, parsed);
1616    }
1617
1618    // Unknown field when struct has no fields (regression test)
1619    {
1620        const Vec2 = struct {};
1621        var diag: Diagnostics = .{};
1622        defer diag.deinit(gpa);
1623        try std.testing.expectError(
1624            error.ParseZon,
1625            fromSlice(Vec2, gpa, ".{.x=1.5, .z=2.5}", &diag, .{}),
1626        );
1627        try std.testing.expectFmt(
1628            \\1:4: error: unexpected field 'x'
1629            \\1:4: note: none expected
1630            \\
1631        , "{f}", .{diag});
1632    }
1633
1634    // Missing field
1635    {
1636        const Vec2 = struct { x: f32, y: f32 };
1637        var diag: Diagnostics = .{};
1638        defer diag.deinit(gpa);
1639        try std.testing.expectError(
1640            error.ParseZon,
1641            fromSlice(Vec2, gpa, ".{.x=1.5}", &diag, .{}),
1642        );
1643        try std.testing.expectFmt("1:2: error: missing required field y\n", "{f}", .{diag});
1644    }
1645
1646    // Default field
1647    {
1648        const Vec2 = struct { x: f32, y: f32 = 1.5 };
1649        const parsed = try fromSlice(Vec2, gpa, ".{.x = 1.2}", null, .{});
1650        try std.testing.expectEqual(Vec2{ .x = 1.2, .y = 1.5 }, parsed);
1651    }
1652
1653    // Comptime field
1654    {
1655        const Vec2 = struct { x: f32, comptime y: f32 = 1.5 };
1656        const parsed = try fromSlice(Vec2, gpa, ".{.x = 1.2}", null, .{});
1657        try std.testing.expectEqual(Vec2{ .x = 1.2, .y = 1.5 }, parsed);
1658    }
1659
1660    // Comptime field assignment
1661    {
1662        const Vec2 = struct { x: f32, comptime y: f32 = 1.5 };
1663        var diag: Diagnostics = .{};
1664        defer diag.deinit(gpa);
1665        const parsed = fromSlice(Vec2, gpa, ".{.x = 1.2, .y = 1.5}", &diag, .{});
1666        try std.testing.expectError(error.ParseZon, parsed);
1667        try std.testing.expectFmt(
1668            \\1:18: error: cannot initialize comptime field
1669            \\
1670        , "{f}", .{diag});
1671    }
1672
1673    // Enum field (regression test, we were previously getting the field name in an
1674    // incorrect way that broke for enum values)
1675    {
1676        const Vec0 = struct { x: enum { x } };
1677        const parsed = try fromSlice(Vec0, gpa, ".{ .x = .x }", null, .{});
1678        try std.testing.expectEqual(Vec0{ .x = .x }, parsed);
1679    }
1680
1681    // Enum field and struct field with @
1682    {
1683        const Vec0 = struct { @"x x": enum { @"x x" } };
1684        const parsed = try fromSlice(Vec0, gpa, ".{ .@\"x x\" = .@\"x x\" }", null, .{});
1685        try std.testing.expectEqual(Vec0{ .@"x x" = .@"x x" }, parsed);
1686    }
1687
1688    // Type expressions are not allowed
1689    {
1690        // Structs
1691        {
1692            var diag: Diagnostics = .{};
1693            defer diag.deinit(gpa);
1694            const parsed = fromSlice(struct {}, gpa, "Empty{}", &diag, .{});
1695            try std.testing.expectError(error.ParseZon, parsed);
1696            try std.testing.expectFmt(
1697                \\1:1: error: types are not available in ZON
1698                \\1:1: note: replace the type with '.'
1699                \\
1700            , "{f}", .{diag});
1701        }
1702
1703        // Arrays
1704        {
1705            var diag: Diagnostics = .{};
1706            defer diag.deinit(gpa);
1707            const parsed = fromSlice([3]u8, gpa, "[3]u8{1, 2, 3}", &diag, .{});
1708            try std.testing.expectError(error.ParseZon, parsed);
1709            try std.testing.expectFmt(
1710                \\1:1: error: types are not available in ZON
1711                \\1:1: note: replace the type with '.'
1712                \\
1713            , "{f}", .{diag});
1714        }
1715
1716        // Slices
1717        {
1718            var diag: Diagnostics = .{};
1719            defer diag.deinit(gpa);
1720            const parsed = fromSliceAlloc([]u8, gpa, "[]u8{1, 2, 3}", &diag, .{});
1721            try std.testing.expectError(error.ParseZon, parsed);
1722            try std.testing.expectFmt(
1723                \\1:1: error: types are not available in ZON
1724                \\1:1: note: replace the type with '.'
1725                \\
1726            , "{f}", .{diag});
1727        }
1728
1729        // Tuples
1730        {
1731            var diag: Diagnostics = .{};
1732            defer diag.deinit(gpa);
1733            const parsed = fromSlice(
1734                struct { u8, u8, u8 },
1735                gpa,
1736                "Tuple{1, 2, 3}",
1737                &diag,
1738                .{},
1739            );
1740            try std.testing.expectError(error.ParseZon, parsed);
1741            try std.testing.expectFmt(
1742                \\1:1: error: types are not available in ZON
1743                \\1:1: note: replace the type with '.'
1744                \\
1745            , "{f}", .{diag});
1746        }
1747
1748        // Nested
1749        {
1750            var diag: Diagnostics = .{};
1751            defer diag.deinit(gpa);
1752            const parsed = fromSlice(struct {}, gpa, ".{ .x = Tuple{1, 2, 3} }", &diag, .{});
1753            try std.testing.expectError(error.ParseZon, parsed);
1754            try std.testing.expectFmt(
1755                \\1:9: error: types are not available in ZON
1756                \\1:9: note: replace the type with '.'
1757                \\
1758            , "{f}", .{diag});
1759        }
1760    }
1761}
1762
1763test "std.zon tuples" {
1764    const gpa = std.testing.allocator;
1765
1766    // Structs (various sizes tested since they're parsed differently)
1767    {
1768        const Tuple0 = struct {};
1769        const Tuple1 = struct { f32 };
1770        const Tuple2 = struct { f32, bool };
1771        const Tuple3 = struct { f32, bool, u8 };
1772
1773        const zero = try fromSlice(Tuple0, gpa, ".{}", null, .{});
1774        try std.testing.expectEqual(Tuple0{}, zero);
1775
1776        const one = try fromSlice(Tuple1, gpa, ".{1.2}", null, .{});
1777        try std.testing.expectEqual(Tuple1{1.2}, one);
1778
1779        const two = try fromSlice(Tuple2, gpa, ".{1.2, true}", null, .{});
1780        try std.testing.expectEqual(Tuple2{ 1.2, true }, two);
1781
1782        const three = try fromSlice(Tuple3, gpa, ".{1.2, false, 3}", null, .{});
1783        try std.testing.expectEqual(Tuple3{ 1.2, false, 3 }, three);
1784    }
1785
1786    // Deep free
1787    {
1788        const Tuple = struct { []const u8, []const u8 };
1789        const parsed = try fromSliceAlloc(Tuple, gpa, ".{\"hello\", \"world\"}", null, .{});
1790        defer free(gpa, parsed);
1791        try std.testing.expectEqualDeep(Tuple{ "hello", "world" }, parsed);
1792    }
1793
1794    // Extra field
1795    {
1796        const Tuple = struct { f32, bool };
1797        var diag: Diagnostics = .{};
1798        defer diag.deinit(gpa);
1799        try std.testing.expectError(
1800            error.ParseZon,
1801            fromSlice(Tuple, gpa, ".{0.5, true, 123}", &diag, .{}),
1802        );
1803        try std.testing.expectFmt("1:14: error: index 2 outside of tuple length 2\n", "{f}", .{diag});
1804    }
1805
1806    // Extra field
1807    {
1808        const Tuple = struct { f32, bool };
1809        var diag: Diagnostics = .{};
1810        defer diag.deinit(gpa);
1811        try std.testing.expectError(
1812            error.ParseZon,
1813            fromSlice(Tuple, gpa, ".{0.5}", &diag, .{}),
1814        );
1815        try std.testing.expectFmt(
1816            "1:2: error: missing tuple field with index 1\n",
1817            "{f}",
1818            .{diag},
1819        );
1820    }
1821
1822    // Tuple with unexpected field names
1823    {
1824        const Tuple = struct { f32 };
1825        var diag: Diagnostics = .{};
1826        defer diag.deinit(gpa);
1827        try std.testing.expectError(
1828            error.ParseZon,
1829            fromSlice(Tuple, gpa, ".{.foo = 10.0}", &diag, .{}),
1830        );
1831        try std.testing.expectFmt("1:2: error: expected tuple\n", "{f}", .{diag});
1832    }
1833
1834    // Struct with missing field names
1835    {
1836        const Struct = struct { foo: f32 };
1837        var diag: Diagnostics = .{};
1838        defer diag.deinit(gpa);
1839        try std.testing.expectError(
1840            error.ParseZon,
1841            fromSlice(Struct, gpa, ".{10.0}", &diag, .{}),
1842        );
1843        try std.testing.expectFmt("1:2: error: expected struct\n", "{f}", .{diag});
1844    }
1845
1846    // Comptime field
1847    {
1848        const Vec2 = struct { f32, comptime f32 = 1.5 };
1849        const parsed = try fromSlice(Vec2, gpa, ".{ 1.2 }", null, .{});
1850        try std.testing.expectEqual(Vec2{ 1.2, 1.5 }, parsed);
1851    }
1852
1853    // Comptime field assignment
1854    {
1855        const Vec2 = struct { f32, comptime f32 = 1.5 };
1856        var diag: Diagnostics = .{};
1857        defer diag.deinit(gpa);
1858        const parsed = fromSlice(Vec2, gpa, ".{ 1.2, 1.5}", &diag, .{});
1859        try std.testing.expectError(error.ParseZon, parsed);
1860        try std.testing.expectFmt(
1861            \\1:9: error: cannot initialize comptime field
1862            \\
1863        , "{f}", .{diag});
1864    }
1865}
1866
1867// Test sizes 0 to 3 since small sizes get parsed differently
1868test "std.zon arrays and slices" {
1869    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/20881
1870
1871    const gpa = std.testing.allocator;
1872
1873    // Literals
1874    {
1875        // Arrays
1876        {
1877            const zero = try fromSlice([0]u8, gpa, ".{}", null, .{});
1878            try std.testing.expectEqualSlices(u8, &@as([0]u8, .{}), &zero);
1879
1880            const one = try fromSlice([1]u8, gpa, ".{'a'}", null, .{});
1881            try std.testing.expectEqualSlices(u8, &@as([1]u8, .{'a'}), &one);
1882
1883            const two = try fromSlice([2]u8, gpa, ".{'a', 'b'}", null, .{});
1884            try std.testing.expectEqualSlices(u8, &@as([2]u8, .{ 'a', 'b' }), &two);
1885
1886            const two_comma = try fromSlice([2]u8, gpa, ".{'a', 'b',}", null, .{});
1887            try std.testing.expectEqualSlices(u8, &@as([2]u8, .{ 'a', 'b' }), &two_comma);
1888
1889            const three = try fromSlice([3]u8, gpa, ".{'a', 'b', 'c'}", null, .{});
1890            try std.testing.expectEqualSlices(u8, &.{ 'a', 'b', 'c' }, &three);
1891
1892            const sentinel = try fromSlice([3:'z']u8, gpa, ".{'a', 'b', 'c'}", null, .{});
1893            const expected_sentinel: [3:'z']u8 = .{ 'a', 'b', 'c' };
1894            try std.testing.expectEqualSlices(u8, &expected_sentinel, &sentinel);
1895        }
1896
1897        // Slice literals
1898        {
1899            const zero = try fromSliceAlloc([]const u8, gpa, ".{}", null, .{});
1900            defer free(gpa, zero);
1901            try std.testing.expectEqualSlices(u8, @as([]const u8, &.{}), zero);
1902
1903            const one = try fromSliceAlloc([]u8, gpa, ".{'a'}", null, .{});
1904            defer free(gpa, one);
1905            try std.testing.expectEqualSlices(u8, &.{'a'}, one);
1906
1907            const two = try fromSliceAlloc([]const u8, gpa, ".{'a', 'b'}", null, .{});
1908            defer free(gpa, two);
1909            try std.testing.expectEqualSlices(u8, &.{ 'a', 'b' }, two);
1910
1911            const two_comma = try fromSliceAlloc([]const u8, gpa, ".{'a', 'b',}", null, .{});
1912            defer free(gpa, two_comma);
1913            try std.testing.expectEqualSlices(u8, &.{ 'a', 'b' }, two_comma);
1914
1915            const three = try fromSliceAlloc([]u8, gpa, ".{'a', 'b', 'c'}", null, .{});
1916            defer free(gpa, three);
1917            try std.testing.expectEqualSlices(u8, &.{ 'a', 'b', 'c' }, three);
1918
1919            const sentinel = try fromSliceAlloc([:'z']const u8, gpa, ".{'a', 'b', 'c'}", null, .{});
1920            defer free(gpa, sentinel);
1921            const expected_sentinel: [:'z']const u8 = &.{ 'a', 'b', 'c' };
1922            try std.testing.expectEqualSlices(u8, expected_sentinel, sentinel);
1923        }
1924    }
1925
1926    // Deep free
1927    {
1928        // Arrays
1929        {
1930            const parsed = try fromSliceAlloc([1][]const u8, gpa, ".{\"abc\"}", null, .{});
1931            defer free(gpa, parsed);
1932            const expected: [1][]const u8 = .{"abc"};
1933            try std.testing.expectEqualDeep(expected, parsed);
1934        }
1935
1936        // Slice literals
1937        {
1938            const parsed = try fromSliceAlloc([]const []const u8, gpa, ".{\"abc\"}", null, .{});
1939            defer free(gpa, parsed);
1940            const expected: []const []const u8 = &.{"abc"};
1941            try std.testing.expectEqualDeep(expected, parsed);
1942        }
1943    }
1944
1945    // Sentinels and alignment
1946    {
1947        // Arrays
1948        {
1949            const sentinel = try fromSlice([1:2]u8, gpa, ".{1}", null, .{});
1950            try std.testing.expectEqual(@as(usize, 1), sentinel.len);
1951            try std.testing.expectEqual(@as(u8, 1), sentinel[0]);
1952            try std.testing.expectEqual(@as(u8, 2), sentinel[1]);
1953        }
1954
1955        // Slice literals
1956        {
1957            const sentinel = try fromSliceAlloc([:2]align(4) u8, gpa, ".{1}", null, .{});
1958            defer free(gpa, sentinel);
1959            try std.testing.expectEqual(@as(usize, 1), sentinel.len);
1960            try std.testing.expectEqual(@as(u8, 1), sentinel[0]);
1961            try std.testing.expectEqual(@as(u8, 2), sentinel[1]);
1962        }
1963    }
1964
1965    // Expect 0 find 3
1966    {
1967        var diag: Diagnostics = .{};
1968        defer diag.deinit(gpa);
1969        try std.testing.expectError(
1970            error.ParseZon,
1971            fromSlice([0]u8, gpa, ".{'a', 'b', 'c'}", &diag, .{}),
1972        );
1973        try std.testing.expectFmt(
1974            "1:3: error: index 0 outside of array of length 0\n",
1975            "{f}",
1976            .{diag},
1977        );
1978    }
1979
1980    // Expect 1 find 2
1981    {
1982        var diag: Diagnostics = .{};
1983        defer diag.deinit(gpa);
1984        try std.testing.expectError(
1985            error.ParseZon,
1986            fromSlice([1]u8, gpa, ".{'a', 'b'}", &diag, .{}),
1987        );
1988        try std.testing.expectFmt(
1989            "1:8: error: index 1 outside of array of length 1\n",
1990            "{f}",
1991            .{diag},
1992        );
1993    }
1994
1995    // Expect 2 find 1
1996    {
1997        var diag: Diagnostics = .{};
1998        defer diag.deinit(gpa);
1999        try std.testing.expectError(
2000            error.ParseZon,
2001            fromSlice([2]u8, gpa, ".{'a'}", &diag, .{}),
2002        );
2003        try std.testing.expectFmt(
2004            "1:2: error: expected 2 array elements; found 1\n",
2005            "{f}",
2006            .{diag},
2007        );
2008    }
2009
2010    // Expect 3 find 0
2011    {
2012        var diag: Diagnostics = .{};
2013        defer diag.deinit(gpa);
2014        try std.testing.expectError(
2015            error.ParseZon,
2016            fromSlice([3]u8, gpa, ".{}", &diag, .{}),
2017        );
2018        try std.testing.expectFmt(
2019            "1:2: error: expected 3 array elements; found 0\n",
2020            "{f}",
2021            .{diag},
2022        );
2023    }
2024
2025    // Wrong inner type
2026    {
2027        // Array
2028        {
2029            var diag: Diagnostics = .{};
2030            defer diag.deinit(gpa);
2031            try std.testing.expectError(
2032                error.ParseZon,
2033                fromSlice([3]bool, gpa, ".{'a', 'b', 'c'}", &diag, .{}),
2034            );
2035            try std.testing.expectFmt("1:3: error: expected type 'bool'\n", "{f}", .{diag});
2036        }
2037
2038        // Slice
2039        {
2040            var diag: Diagnostics = .{};
2041            defer diag.deinit(gpa);
2042            try std.testing.expectError(
2043                error.ParseZon,
2044                fromSliceAlloc([]bool, gpa, ".{'a', 'b', 'c'}", &diag, .{}),
2045            );
2046            try std.testing.expectFmt("1:3: error: expected type 'bool'\n", "{f}", .{diag});
2047        }
2048    }
2049
2050    // Complete wrong type
2051    {
2052        // Array
2053        {
2054            var diag: Diagnostics = .{};
2055            defer diag.deinit(gpa);
2056            try std.testing.expectError(
2057                error.ParseZon,
2058                fromSlice([3]u8, gpa, "'a'", &diag, .{}),
2059            );
2060            try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2061        }
2062
2063        // Slice
2064        {
2065            var diag: Diagnostics = .{};
2066            defer diag.deinit(gpa);
2067            try std.testing.expectError(
2068                error.ParseZon,
2069                fromSliceAlloc([]u8, gpa, "'a'", &diag, .{}),
2070            );
2071            try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2072        }
2073    }
2074
2075    // Address of is not allowed (indirection for slices in ZON is implicit)
2076    {
2077        var diag: Diagnostics = .{};
2078        defer diag.deinit(gpa);
2079        try std.testing.expectError(
2080            error.ParseZon,
2081            fromSliceAlloc([]u8, gpa, "  &.{'a', 'b', 'c'}", &diag, .{}),
2082        );
2083        try std.testing.expectFmt(
2084            "1:3: error: pointers are not available in ZON\n",
2085            "{f}",
2086            .{diag},
2087        );
2088    }
2089}
2090
2091test "std.zon string literal" {
2092    const gpa = std.testing.allocator;
2093
2094    // Basic string literal
2095    {
2096        const parsed = try fromSliceAlloc([]const u8, gpa, "\"abc\"", null, .{});
2097        defer free(gpa, parsed);
2098        try std.testing.expectEqualStrings(@as([]const u8, "abc"), parsed);
2099    }
2100
2101    // String literal with escape characters
2102    {
2103        const parsed = try fromSliceAlloc([]const u8, gpa, "\"ab\\nc\"", null, .{});
2104        defer free(gpa, parsed);
2105        try std.testing.expectEqualStrings(@as([]const u8, "ab\nc"), parsed);
2106    }
2107
2108    // String literal with embedded null
2109    {
2110        const parsed = try fromSliceAlloc([]const u8, gpa, "\"ab\\x00c\"", null, .{});
2111        defer free(gpa, parsed);
2112        try std.testing.expectEqualStrings(@as([]const u8, "ab\x00c"), parsed);
2113    }
2114
2115    // Passing string literal to a mutable slice
2116    {
2117        {
2118            var diag: Diagnostics = .{};
2119            defer diag.deinit(gpa);
2120            try std.testing.expectError(
2121                error.ParseZon,
2122                fromSliceAlloc([]u8, gpa, "\"abcd\"", &diag, .{}),
2123            );
2124            try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2125        }
2126
2127        {
2128            var diag: Diagnostics = .{};
2129            defer diag.deinit(gpa);
2130            try std.testing.expectError(
2131                error.ParseZon,
2132                fromSliceAlloc([]u8, gpa, "\\\\abcd", &diag, .{}),
2133            );
2134            try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2135        }
2136    }
2137
2138    // Passing string literal to a array
2139    {
2140        {
2141            var ast = try std.zig.Ast.parse(gpa, "\"abcd\"", .zon);
2142            defer ast.deinit(gpa);
2143            var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false });
2144            defer zoir.deinit(gpa);
2145            var diag: Diagnostics = .{};
2146            defer diag.deinit(gpa);
2147            try std.testing.expectError(
2148                error.ParseZon,
2149                fromSlice([4:0]u8, gpa, "\"abcd\"", &diag, .{}),
2150            );
2151            try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2152        }
2153
2154        {
2155            var diag: Diagnostics = .{};
2156            defer diag.deinit(gpa);
2157            try std.testing.expectError(
2158                error.ParseZon,
2159                fromSlice([4:0]u8, gpa, "\\\\abcd", &diag, .{}),
2160            );
2161            try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2162        }
2163    }
2164
2165    // Zero terminated slices
2166    {
2167        {
2168            const parsed: [:0]const u8 = try fromSliceAlloc(
2169                [:0]const u8,
2170                gpa,
2171                "\"abc\"",
2172                null,
2173                .{},
2174            );
2175            defer free(gpa, parsed);
2176            try std.testing.expectEqualStrings("abc", parsed);
2177            try std.testing.expectEqual(@as(u8, 0), parsed[3]);
2178        }
2179
2180        {
2181            const parsed: [:0]const u8 = try fromSliceAlloc(
2182                [:0]const u8,
2183                gpa,
2184                "\\\\abc",
2185                null,
2186                .{},
2187            );
2188            defer free(gpa, parsed);
2189            try std.testing.expectEqualStrings("abc", parsed);
2190            try std.testing.expectEqual(@as(u8, 0), parsed[3]);
2191        }
2192    }
2193
2194    // Other value terminated slices
2195    {
2196        {
2197            var diag: Diagnostics = .{};
2198            defer diag.deinit(gpa);
2199            try std.testing.expectError(
2200                error.ParseZon,
2201                fromSliceAlloc([:1]const u8, gpa, "\"foo\"", &diag, .{}),
2202            );
2203            try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2204        }
2205
2206        {
2207            var diag: Diagnostics = .{};
2208            defer diag.deinit(gpa);
2209            try std.testing.expectError(
2210                error.ParseZon,
2211                fromSliceAlloc([:1]const u8, gpa, "\\\\foo", &diag, .{}),
2212            );
2213            try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2214        }
2215    }
2216
2217    // Expecting string literal, getting something else
2218    {
2219        var diag: Diagnostics = .{};
2220        defer diag.deinit(gpa);
2221        try std.testing.expectError(
2222            error.ParseZon,
2223            fromSliceAlloc([]const u8, gpa, "true", &diag, .{}),
2224        );
2225        try std.testing.expectFmt("1:1: error: expected string\n", "{f}", .{diag});
2226    }
2227
2228    // Expecting string literal, getting an incompatible tuple
2229    {
2230        var diag: Diagnostics = .{};
2231        defer diag.deinit(gpa);
2232        try std.testing.expectError(
2233            error.ParseZon,
2234            fromSliceAlloc([]const u8, gpa, ".{false}", &diag, .{}),
2235        );
2236        try std.testing.expectFmt("1:3: error: expected type 'u8'\n", "{f}", .{diag});
2237    }
2238
2239    // Invalid string literal
2240    {
2241        var diag: Diagnostics = .{};
2242        defer diag.deinit(gpa);
2243        try std.testing.expectError(
2244            error.ParseZon,
2245            fromSliceAlloc([]const i8, gpa, "\"\\a\"", &diag, .{}),
2246        );
2247        try std.testing.expectFmt("1:3: error: invalid escape character: 'a'\n", "{f}", .{diag});
2248    }
2249
2250    // Slice wrong child type
2251    {
2252        {
2253            var diag: Diagnostics = .{};
2254            defer diag.deinit(gpa);
2255            try std.testing.expectError(
2256                error.ParseZon,
2257                fromSliceAlloc([]const i8, gpa, "\"a\"", &diag, .{}),
2258            );
2259            try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2260        }
2261
2262        {
2263            var diag: Diagnostics = .{};
2264            defer diag.deinit(gpa);
2265            try std.testing.expectError(
2266                error.ParseZon,
2267                fromSliceAlloc([]const i8, gpa, "\\\\a", &diag, .{}),
2268            );
2269            try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2270        }
2271    }
2272
2273    // Bad alignment
2274    {
2275        {
2276            var diag: Diagnostics = .{};
2277            defer diag.deinit(gpa);
2278            try std.testing.expectError(
2279                error.ParseZon,
2280                fromSliceAlloc([]align(2) const u8, gpa, "\"abc\"", &diag, .{}),
2281            );
2282            try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2283        }
2284
2285        {
2286            var diag: Diagnostics = .{};
2287            defer diag.deinit(gpa);
2288            try std.testing.expectError(
2289                error.ParseZon,
2290                fromSliceAlloc([]align(2) const u8, gpa, "\\\\abc", &diag, .{}),
2291            );
2292            try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
2293        }
2294    }
2295
2296    // Multi line strings
2297    inline for (.{ []const u8, [:0]const u8 }) |String| {
2298        // Nested
2299        {
2300            const S = struct {
2301                message: String,
2302                message2: String,
2303                message3: String,
2304            };
2305            const parsed = try fromSliceAlloc(S, gpa,
2306                \\.{
2307                \\    .message =
2308                \\        \\hello, world!
2309                \\
2310                \\        \\this is a multiline string!
2311                \\        \\
2312                \\        \\...
2313                \\
2314                \\    ,
2315                \\    .message2 =
2316                \\        \\this too...sort of.
2317                \\    ,
2318                \\    .message3 =
2319                \\        \\
2320                \\        \\and this.
2321                \\}
2322            , null, .{});
2323            defer free(gpa, parsed);
2324            try std.testing.expectEqualStrings(
2325                "hello, world!\nthis is a multiline string!\n\n...",
2326                parsed.message,
2327            );
2328            try std.testing.expectEqualStrings("this too...sort of.", parsed.message2);
2329            try std.testing.expectEqualStrings("\nand this.", parsed.message3);
2330        }
2331    }
2332}
2333
2334test "std.zon enum literals" {
2335    const gpa = std.testing.allocator;
2336
2337    const Enum = enum {
2338        foo,
2339        bar,
2340        baz,
2341        @"ab\nc",
2342    };
2343
2344    // Tags that exist
2345    try std.testing.expectEqual(Enum.foo, try fromSlice(Enum, gpa, ".foo", null, .{}));
2346    try std.testing.expectEqual(Enum.bar, try fromSlice(Enum, gpa, ".bar", null, .{}));
2347    try std.testing.expectEqual(Enum.baz, try fromSlice(Enum, gpa, ".baz", null, .{}));
2348    try std.testing.expectEqual(
2349        Enum.@"ab\nc",
2350        try fromSlice(Enum, gpa, ".@\"ab\\nc\"", null, .{}),
2351    );
2352
2353    // Bad tag
2354    {
2355        var diag: Diagnostics = .{};
2356        defer diag.deinit(gpa);
2357        try std.testing.expectError(
2358            error.ParseZon,
2359            fromSlice(Enum, gpa, ".qux", &diag, .{}),
2360        );
2361        try std.testing.expectFmt(
2362            \\1:2: error: unexpected enum literal 'qux'
2363            \\1:2: note: supported: 'foo', 'bar', 'baz', '@"ab\nc"'
2364            \\
2365        ,
2366            "{f}",
2367            .{diag},
2368        );
2369    }
2370
2371    // Bad tag that's too long for parser
2372    {
2373        var diag: Diagnostics = .{};
2374        defer diag.deinit(gpa);
2375        try std.testing.expectError(
2376            error.ParseZon,
2377            fromSlice(Enum, gpa, ".@\"foobarbaz\"", &diag, .{}),
2378        );
2379        try std.testing.expectFmt(
2380            \\1:2: error: unexpected enum literal 'foobarbaz'
2381            \\1:2: note: supported: 'foo', 'bar', 'baz', '@"ab\nc"'
2382            \\
2383        ,
2384            "{f}",
2385            .{diag},
2386        );
2387    }
2388
2389    // Bad type
2390    {
2391        var diag: Diagnostics = .{};
2392        defer diag.deinit(gpa);
2393        try std.testing.expectError(
2394            error.ParseZon,
2395            fromSlice(Enum, gpa, "true", &diag, .{}),
2396        );
2397        try std.testing.expectFmt("1:1: error: expected enum literal\n", "{f}", .{diag});
2398    }
2399
2400    // Test embedded nulls in an identifier
2401    {
2402        var diag: Diagnostics = .{};
2403        defer diag.deinit(gpa);
2404        try std.testing.expectError(
2405            error.ParseZon,
2406            fromSlice(Enum, gpa, ".@\"\\x00\"", &diag, .{}),
2407        );
2408        try std.testing.expectFmt(
2409            "1:2: error: identifier cannot contain null bytes\n",
2410            "{f}",
2411            .{diag},
2412        );
2413    }
2414}
2415
2416test "std.zon parse bool" {
2417    const gpa = std.testing.allocator;
2418
2419    // Correct bools
2420    try std.testing.expectEqual(true, try fromSlice(bool, gpa, "true", null, .{}));
2421    try std.testing.expectEqual(false, try fromSlice(bool, gpa, "false", null, .{}));
2422
2423    // Errors
2424    {
2425        var diag: Diagnostics = .{};
2426        defer diag.deinit(gpa);
2427        try std.testing.expectError(
2428            error.ParseZon,
2429            fromSlice(bool, gpa, " foo", &diag, .{}),
2430        );
2431        try std.testing.expectFmt(
2432            \\1:2: error: invalid expression
2433            \\1:2: note: ZON allows identifiers 'true', 'false', 'null', 'inf', and 'nan'
2434            \\1:2: note: precede identifier with '.' for an enum literal
2435            \\
2436        , "{f}", .{diag});
2437    }
2438    {
2439        var diag: Diagnostics = .{};
2440        defer diag.deinit(gpa);
2441        try std.testing.expectError(error.ParseZon, fromSlice(bool, gpa, "123", &diag, .{}));
2442        try std.testing.expectFmt("1:1: error: expected type 'bool'\n", "{f}", .{diag});
2443    }
2444}
2445
2446test "std.zon intFromFloatExact" {
2447    // Valid conversions
2448    try std.testing.expectEqual(@as(u8, 10), intFromFloatExact(u8, @as(f32, 10.0)).?);
2449    try std.testing.expectEqual(@as(i8, -123), intFromFloatExact(i8, @as(f64, @as(f64, -123.0))).?);
2450    try std.testing.expectEqual(@as(i16, 45), intFromFloatExact(i16, @as(f128, @as(f128, 45.0))).?);
2451
2452    // Out of range
2453    try std.testing.expectEqual(@as(?u4, null), intFromFloatExact(u4, @as(f32, 16.0)));
2454    try std.testing.expectEqual(@as(?i4, null), intFromFloatExact(i4, @as(f64, -17.0)));
2455    try std.testing.expectEqual(@as(?u8, null), intFromFloatExact(u8, @as(f128, -2.0)));
2456
2457    // Not a whole number
2458    try std.testing.expectEqual(@as(?u8, null), intFromFloatExact(u8, @as(f32, 0.5)));
2459    try std.testing.expectEqual(@as(?i8, null), intFromFloatExact(i8, @as(f64, 0.01)));
2460
2461    // Infinity and NaN
2462    try std.testing.expectEqual(@as(?u8, null), intFromFloatExact(u8, std.math.inf(f32)));
2463    try std.testing.expectEqual(@as(?u8, null), intFromFloatExact(u8, -std.math.inf(f32)));
2464    try std.testing.expectEqual(@as(?u8, null), intFromFloatExact(u8, std.math.nan(f32)));
2465}
2466
2467test "std.zon parse int" {
2468    const gpa = std.testing.allocator;
2469
2470    // Test various numbers and types
2471    try std.testing.expectEqual(@as(u8, 10), try fromSlice(u8, gpa, "10", null, .{}));
2472    try std.testing.expectEqual(@as(i16, 24), try fromSlice(i16, gpa, "24", null, .{}));
2473    try std.testing.expectEqual(@as(i14, -4), try fromSlice(i14, gpa, "-4", null, .{}));
2474    try std.testing.expectEqual(@as(i32, -123), try fromSlice(i32, gpa, "-123", null, .{}));
2475
2476    // Test limits
2477    try std.testing.expectEqual(@as(i8, 127), try fromSlice(i8, gpa, "127", null, .{}));
2478    try std.testing.expectEqual(@as(i8, -128), try fromSlice(i8, gpa, "-128", null, .{}));
2479
2480    // Test characters
2481    try std.testing.expectEqual(@as(u8, 'a'), try fromSlice(u8, gpa, "'a'", null, .{}));
2482    try std.testing.expectEqual(@as(u8, 'z'), try fromSlice(u8, gpa, "'z'", null, .{}));
2483
2484    // Test big integers
2485    try std.testing.expectEqual(
2486        @as(u65, 36893488147419103231),
2487        try fromSlice(u65, gpa, "36893488147419103231", null, .{}),
2488    );
2489    try std.testing.expectEqual(
2490        @as(u65, 36893488147419103231),
2491        try fromSlice(u65, gpa, "368934_881_474191032_31", null, .{}),
2492    );
2493
2494    // Test big integer limits
2495    try std.testing.expectEqual(
2496        @as(i66, 36893488147419103231),
2497        try fromSlice(i66, gpa, "36893488147419103231", null, .{}),
2498    );
2499    try std.testing.expectEqual(
2500        @as(i66, -36893488147419103232),
2501        try fromSlice(i66, gpa, "-36893488147419103232", null, .{}),
2502    );
2503    {
2504        var diag: Diagnostics = .{};
2505        defer diag.deinit(gpa);
2506        try std.testing.expectError(error.ParseZon, fromSlice(
2507            i66,
2508            gpa,
2509            "36893488147419103232",
2510            &diag,
2511            .{},
2512        ));
2513        try std.testing.expectFmt(
2514            "1:1: error: type 'i66' cannot represent value\n",
2515            "{f}",
2516            .{diag},
2517        );
2518    }
2519    {
2520        var diag: Diagnostics = .{};
2521        defer diag.deinit(gpa);
2522        try std.testing.expectError(error.ParseZon, fromSlice(
2523            i66,
2524            gpa,
2525            "-36893488147419103233",
2526            &diag,
2527            .{},
2528        ));
2529        try std.testing.expectFmt(
2530            "1:1: error: type 'i66' cannot represent value\n",
2531            "{f}",
2532            .{diag},
2533        );
2534    }
2535
2536    // Test parsing whole number floats as integers
2537    try std.testing.expectEqual(@as(i8, -1), try fromSlice(i8, gpa, "-1.0", null, .{}));
2538    try std.testing.expectEqual(@as(i8, 123), try fromSlice(i8, gpa, "123.0", null, .{}));
2539
2540    // Test non-decimal integers
2541    try std.testing.expectEqual(@as(i16, 0xff), try fromSlice(i16, gpa, "0xff", null, .{}));
2542    try std.testing.expectEqual(@as(i16, -0xff), try fromSlice(i16, gpa, "-0xff", null, .{}));
2543    try std.testing.expectEqual(@as(i16, 0o77), try fromSlice(i16, gpa, "0o77", null, .{}));
2544    try std.testing.expectEqual(@as(i16, -0o77), try fromSlice(i16, gpa, "-0o77", null, .{}));
2545    try std.testing.expectEqual(@as(i16, 0b11), try fromSlice(i16, gpa, "0b11", null, .{}));
2546    try std.testing.expectEqual(@as(i16, -0b11), try fromSlice(i16, gpa, "-0b11", null, .{}));
2547
2548    // Test non-decimal big integers
2549    try std.testing.expectEqual(@as(u65, 0x1ffffffffffffffff), try fromSlice(
2550        u65,
2551        gpa,
2552        "0x1ffffffffffffffff",
2553        null,
2554        .{},
2555    ));
2556    try std.testing.expectEqual(@as(i66, 0x1ffffffffffffffff), try fromSlice(
2557        i66,
2558        gpa,
2559        "0x1ffffffffffffffff",
2560        null,
2561        .{},
2562    ));
2563    try std.testing.expectEqual(@as(i66, -0x1ffffffffffffffff), try fromSlice(
2564        i66,
2565        gpa,
2566        "-0x1ffffffffffffffff",
2567        null,
2568        .{},
2569    ));
2570    try std.testing.expectEqual(@as(u65, 0x1ffffffffffffffff), try fromSlice(
2571        u65,
2572        gpa,
2573        "0o3777777777777777777777",
2574        null,
2575        .{},
2576    ));
2577    try std.testing.expectEqual(@as(i66, 0x1ffffffffffffffff), try fromSlice(
2578        i66,
2579        gpa,
2580        "0o3777777777777777777777",
2581        null,
2582        .{},
2583    ));
2584    try std.testing.expectEqual(@as(i66, -0x1ffffffffffffffff), try fromSlice(
2585        i66,
2586        gpa,
2587        "-0o3777777777777777777777",
2588        null,
2589        .{},
2590    ));
2591    try std.testing.expectEqual(@as(u65, 0x1ffffffffffffffff), try fromSlice(
2592        u65,
2593        gpa,
2594        "0b11111111111111111111111111111111111111111111111111111111111111111",
2595        null,
2596        .{},
2597    ));
2598    try std.testing.expectEqual(@as(i66, 0x1ffffffffffffffff), try fromSlice(
2599        i66,
2600        gpa,
2601        "0b11111111111111111111111111111111111111111111111111111111111111111",
2602        null,
2603        .{},
2604    ));
2605    try std.testing.expectEqual(@as(i66, -0x1ffffffffffffffff), try fromSlice(
2606        i66,
2607        gpa,
2608        "-0b11111111111111111111111111111111111111111111111111111111111111111",
2609        null,
2610        .{},
2611    ));
2612
2613    // Number with invalid character in the middle
2614    {
2615        var diag: Diagnostics = .{};
2616        defer diag.deinit(gpa);
2617        try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "32a32", &diag, .{}));
2618        try std.testing.expectFmt(
2619            "1:3: error: invalid digit 'a' for decimal base\n",
2620            "{f}",
2621            .{diag},
2622        );
2623    }
2624
2625    // Failing to parse as int
2626    {
2627        var diag: Diagnostics = .{};
2628        defer diag.deinit(gpa);
2629        try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "true", &diag, .{}));
2630        try std.testing.expectFmt("1:1: error: expected type 'u8'\n", "{f}", .{diag});
2631    }
2632
2633    // Failing because an int is out of range
2634    {
2635        var diag: Diagnostics = .{};
2636        defer diag.deinit(gpa);
2637        try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "256", &diag, .{}));
2638        try std.testing.expectFmt(
2639            "1:1: error: type 'u8' cannot represent value\n",
2640            "{f}",
2641            .{diag},
2642        );
2643    }
2644
2645    // Failing because a negative int is out of range
2646    {
2647        var diag: Diagnostics = .{};
2648        defer diag.deinit(gpa);
2649        try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "-129", &diag, .{}));
2650        try std.testing.expectFmt(
2651            "1:1: error: type 'i8' cannot represent value\n",
2652            "{f}",
2653            .{diag},
2654        );
2655    }
2656
2657    // Failing because an unsigned int is negative
2658    {
2659        var diag: Diagnostics = .{};
2660        defer diag.deinit(gpa);
2661        try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "-1", &diag, .{}));
2662        try std.testing.expectFmt(
2663            "1:1: error: type 'u8' cannot represent value\n",
2664            "{f}",
2665            .{diag},
2666        );
2667    }
2668
2669    // Failing because a float is non-whole
2670    {
2671        var diag: Diagnostics = .{};
2672        defer diag.deinit(gpa);
2673        try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "1.5", &diag, .{}));
2674        try std.testing.expectFmt(
2675            "1:1: error: type 'u8' cannot represent value\n",
2676            "{f}",
2677            .{diag},
2678        );
2679    }
2680
2681    // Failing because a float is negative
2682    {
2683        var diag: Diagnostics = .{};
2684        defer diag.deinit(gpa);
2685        try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "-1.0", &diag, .{}));
2686        try std.testing.expectFmt(
2687            "1:1: error: type 'u8' cannot represent value\n",
2688            "{f}",
2689            .{diag},
2690        );
2691    }
2692
2693    // Negative integer zero
2694    {
2695        var diag: Diagnostics = .{};
2696        defer diag.deinit(gpa);
2697        try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "-0", &diag, .{}));
2698        try std.testing.expectFmt(
2699            \\1:2: error: integer literal '-0' is ambiguous
2700            \\1:2: note: use '0' for an integer zero
2701            \\1:2: note: use '-0.0' for a floating-point signed zero
2702            \\
2703        , "{f}", .{diag});
2704    }
2705
2706    // Negative integer zero casted to float
2707    {
2708        var diag: Diagnostics = .{};
2709        defer diag.deinit(gpa);
2710        try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-0", &diag, .{}));
2711        try std.testing.expectFmt(
2712            \\1:2: error: integer literal '-0' is ambiguous
2713            \\1:2: note: use '0' for an integer zero
2714            \\1:2: note: use '-0.0' for a floating-point signed zero
2715            \\
2716        , "{f}", .{diag});
2717    }
2718
2719    // Negative float 0 is allowed
2720    try std.testing.expect(
2721        std.math.isNegativeZero(try fromSlice(f32, gpa, "-0.0", null, .{})),
2722    );
2723    try std.testing.expect(std.math.isPositiveZero(try fromSlice(f32, gpa, "0.0", null, .{})));
2724
2725    // Double negation is not allowed
2726    {
2727        var diag: Diagnostics = .{};
2728        defer diag.deinit(gpa);
2729        try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "--2", &diag, .{}));
2730        try std.testing.expectFmt(
2731            "1:1: error: expected number or 'inf' after '-'\n",
2732            "{f}",
2733            .{diag},
2734        );
2735    }
2736
2737    {
2738        var diag: Diagnostics = .{};
2739        defer diag.deinit(gpa);
2740        try std.testing.expectError(
2741            error.ParseZon,
2742            fromSlice(f32, gpa, "--2.0", &diag, .{}),
2743        );
2744        try std.testing.expectFmt(
2745            "1:1: error: expected number or 'inf' after '-'\n",
2746            "{f}",
2747            .{diag},
2748        );
2749    }
2750
2751    // Invalid int literal
2752    {
2753        var diag: Diagnostics = .{};
2754        defer diag.deinit(gpa);
2755        try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "0xg", &diag, .{}));
2756        try std.testing.expectFmt("1:3: error: invalid digit 'g' for hex base\n", "{f}", .{diag});
2757    }
2758
2759    // Notes on invalid int literal
2760    {
2761        var diag: Diagnostics = .{};
2762        defer diag.deinit(gpa);
2763        try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "0123", &diag, .{}));
2764        try std.testing.expectFmt(
2765            \\1:1: error: number '0123' has leading zero
2766            \\1:1: note: use '0o' prefix for octal literals
2767            \\
2768        , "{f}", .{diag});
2769    }
2770}
2771
2772test "std.zon negative char" {
2773    const gpa = std.testing.allocator;
2774
2775    {
2776        var diag: Diagnostics = .{};
2777        defer diag.deinit(gpa);
2778        try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-'a'", &diag, .{}));
2779        try std.testing.expectFmt(
2780            "1:1: error: expected number or 'inf' after '-'\n",
2781            "{f}",
2782            .{diag},
2783        );
2784    }
2785    {
2786        var diag: Diagnostics = .{};
2787        defer diag.deinit(gpa);
2788        try std.testing.expectError(error.ParseZon, fromSlice(i16, gpa, "-'a'", &diag, .{}));
2789        try std.testing.expectFmt(
2790            "1:1: error: expected number or 'inf' after '-'\n",
2791            "{f}",
2792            .{diag},
2793        );
2794    }
2795}
2796
2797test "std.zon parse float" {
2798    if (builtin.cpu.arch == .x86 and builtin.abi == .musl and builtin.link_mode == .dynamic) return error.SkipZigTest;
2799
2800    const gpa = std.testing.allocator;
2801
2802    // Test decimals
2803    try std.testing.expectEqual(@as(f16, 0.5), try fromSlice(f16, gpa, "0.5", null, .{}));
2804    try std.testing.expectEqual(
2805        @as(f32, 123.456),
2806        try fromSlice(f32, gpa, "123.456", null, .{}),
2807    );
2808    try std.testing.expectEqual(
2809        @as(f64, -123.456),
2810        try fromSlice(f64, gpa, "-123.456", null, .{}),
2811    );
2812    try std.testing.expectEqual(@as(f128, 42.5), try fromSlice(f128, gpa, "42.5", null, .{}));
2813
2814    // Test whole numbers with and without decimals
2815    try std.testing.expectEqual(@as(f16, 5.0), try fromSlice(f16, gpa, "5.0", null, .{}));
2816    try std.testing.expectEqual(@as(f16, 5.0), try fromSlice(f16, gpa, "5", null, .{}));
2817    try std.testing.expectEqual(@as(f32, -102), try fromSlice(f32, gpa, "-102.0", null, .{}));
2818    try std.testing.expectEqual(@as(f32, -102), try fromSlice(f32, gpa, "-102", null, .{}));
2819
2820    // Test characters and negated characters
2821    try std.testing.expectEqual(@as(f32, 'a'), try fromSlice(f32, gpa, "'a'", null, .{}));
2822    try std.testing.expectEqual(@as(f32, 'z'), try fromSlice(f32, gpa, "'z'", null, .{}));
2823
2824    // Test big integers
2825    try std.testing.expectEqual(
2826        @as(f32, 36893488147419103231.0),
2827        try fromSlice(f32, gpa, "36893488147419103231", null, .{}),
2828    );
2829    try std.testing.expectEqual(
2830        @as(f32, -36893488147419103231.0),
2831        try fromSlice(f32, gpa, "-36893488147419103231", null, .{}),
2832    );
2833    try std.testing.expectEqual(@as(f128, 0x1ffffffffffffffff), try fromSlice(
2834        f128,
2835        gpa,
2836        "0x1ffffffffffffffff",
2837        null,
2838        .{},
2839    ));
2840    try std.testing.expectEqual(@as(f32, @floatFromInt(0x1ffffffffffffffff)), try fromSlice(
2841        f32,
2842        gpa,
2843        "0x1ffffffffffffffff",
2844        null,
2845        .{},
2846    ));
2847
2848    // Exponents, underscores
2849    try std.testing.expectEqual(
2850        @as(f32, 123.0E+77),
2851        try fromSlice(f32, gpa, "12_3.0E+77", null, .{}),
2852    );
2853
2854    // Hexadecimal
2855    try std.testing.expectEqual(
2856        @as(f32, 0x103.70p-5),
2857        try fromSlice(f32, gpa, "0x103.70p-5", null, .{}),
2858    );
2859    try std.testing.expectEqual(
2860        @as(f32, -0x103.70),
2861        try fromSlice(f32, gpa, "-0x103.70", null, .{}),
2862    );
2863    try std.testing.expectEqual(
2864        @as(f32, 0x1234_5678.9ABC_CDEFp-10),
2865        try fromSlice(f32, gpa, "0x1234_5678.9ABC_CDEFp-10", null, .{}),
2866    );
2867
2868    // inf, nan
2869    try std.testing.expect(std.math.isPositiveInf(try fromSlice(f32, gpa, "inf", null, .{})));
2870    try std.testing.expect(std.math.isNegativeInf(try fromSlice(f32, gpa, "-inf", null, .{})));
2871    try std.testing.expect(std.math.isNan(try fromSlice(f32, gpa, "nan", null, .{})));
2872
2873    // Negative nan not allowed
2874    {
2875        var diag: Diagnostics = .{};
2876        defer diag.deinit(gpa);
2877        try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-nan", &diag, .{}));
2878        try std.testing.expectFmt(
2879            "1:1: error: expected number or 'inf' after '-'\n",
2880            "{f}",
2881            .{diag},
2882        );
2883    }
2884
2885    // nan as int not allowed
2886    {
2887        var diag: Diagnostics = .{};
2888        defer diag.deinit(gpa);
2889        try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "nan", &diag, .{}));
2890        try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag});
2891    }
2892
2893    // nan as int not allowed
2894    {
2895        var diag: Diagnostics = .{};
2896        defer diag.deinit(gpa);
2897        try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "nan", &diag, .{}));
2898        try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag});
2899    }
2900
2901    // inf as int not allowed
2902    {
2903        var diag: Diagnostics = .{};
2904        defer diag.deinit(gpa);
2905        try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "inf", &diag, .{}));
2906        try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag});
2907    }
2908
2909    // -inf as int not allowed
2910    {
2911        var diag: Diagnostics = .{};
2912        defer diag.deinit(gpa);
2913        try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "-inf", &diag, .{}));
2914        try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag});
2915    }
2916
2917    // Bad identifier as float
2918    {
2919        var diag: Diagnostics = .{};
2920        defer diag.deinit(gpa);
2921        try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "foo", &diag, .{}));
2922        try std.testing.expectFmt(
2923            \\1:1: error: invalid expression
2924            \\1:1: note: ZON allows identifiers 'true', 'false', 'null', 'inf', and 'nan'
2925            \\1:1: note: precede identifier with '.' for an enum literal
2926            \\
2927        , "{f}", .{diag});
2928    }
2929
2930    {
2931        var diag: Diagnostics = .{};
2932        defer diag.deinit(gpa);
2933        try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-foo", &diag, .{}));
2934        try std.testing.expectFmt(
2935            "1:1: error: expected number or 'inf' after '-'\n",
2936            "{f}",
2937            .{diag},
2938        );
2939    }
2940
2941    // Non float as float
2942    {
2943        var diag: Diagnostics = .{};
2944        defer diag.deinit(gpa);
2945        try std.testing.expectError(
2946            error.ParseZon,
2947            fromSlice(f32, gpa, "\"foo\"", &diag, .{}),
2948        );
2949        try std.testing.expectFmt("1:1: error: expected type 'f32'\n", "{f}", .{diag});
2950    }
2951}
2952
2953test "std.zon free on error" {
2954    // Test freeing partially allocated structs
2955    {
2956        const Struct = struct {
2957            x: []const u8,
2958            y: []const u8,
2959            z: bool,
2960        };
2961        try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, std.testing.allocator,
2962            \\.{
2963            \\    .x = "hello",
2964            \\    .y = "world",
2965            \\    .z = "fail",
2966            \\}
2967        , null, .{}));
2968    }
2969
2970    // Test freeing partially allocated tuples
2971    {
2972        const Struct = struct {
2973            []const u8,
2974            []const u8,
2975            bool,
2976        };
2977        try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, std.testing.allocator,
2978            \\.{
2979            \\    "hello",
2980            \\    "world",
2981            \\    "fail",
2982            \\}
2983        , null, .{}));
2984    }
2985
2986    // Test freeing structs with missing fields
2987    {
2988        const Struct = struct {
2989            x: []const u8,
2990            y: bool,
2991        };
2992        try std.testing.expectError(error.ParseZon, fromSliceAlloc(Struct, std.testing.allocator,
2993            \\.{
2994            \\    .x = "hello",
2995            \\}
2996        , null, .{}));
2997    }
2998
2999    // Test freeing partially allocated arrays
3000    {
3001        try std.testing.expectError(error.ParseZon, fromSliceAlloc(
3002            [3][]const u8,
3003            std.testing.allocator,
3004            \\.{
3005            \\    "hello",
3006            \\    false,
3007            \\    false,
3008            \\}
3009        ,
3010            null,
3011            .{},
3012        ));
3013    }
3014
3015    // Test freeing partially allocated slices
3016    {
3017        try std.testing.expectError(error.ParseZon, fromSliceAlloc(
3018            [][]const u8,
3019            std.testing.allocator,
3020            \\.{
3021            \\    "hello",
3022            \\    "world",
3023            \\    false,
3024            \\}
3025        ,
3026            null,
3027            .{},
3028        ));
3029    }
3030
3031    // We can parse types that can't be freed, as long as they contain no allocations, e.g. untagged
3032    // unions.
3033    try std.testing.expectEqual(
3034        @as(f32, 1.5),
3035        (try fromSlice(union { x: f32 }, std.testing.allocator, ".{ .x = 1.5 }", null, .{})).x,
3036    );
3037
3038    // We can also parse types that can't be freed if it's impossible for an error to occur after
3039    // the allocation, as is the case here.
3040    {
3041        const result = try fromSliceAlloc(
3042            union { x: []const u8 },
3043            std.testing.allocator,
3044            ".{ .x = \"foo\" }",
3045            null,
3046            .{},
3047        );
3048        defer free(std.testing.allocator, result.x);
3049        try std.testing.expectEqualStrings("foo", result.x);
3050    }
3051
3052    // However, if it's possible we could get an error requiring we free the value, but the value
3053    // cannot be freed (e.g. untagged unions) then we need to turn off `free_on_error` for it to
3054    // compile.
3055    {
3056        const S = struct {
3057            union { x: []const u8 },
3058            bool,
3059        };
3060        const result = try fromSliceAlloc(
3061            S,
3062            std.testing.allocator,
3063            ".{ .{ .x = \"foo\" }, true }",
3064            null,
3065            .{ .free_on_error = false },
3066        );
3067        defer free(std.testing.allocator, result[0].x);
3068        try std.testing.expectEqualStrings("foo", result[0].x);
3069        try std.testing.expect(result[1]);
3070    }
3071
3072    // Again but for structs.
3073    {
3074        const S = struct {
3075            a: union { x: []const u8 },
3076            b: bool,
3077        };
3078        const result = try fromSliceAlloc(
3079            S,
3080            std.testing.allocator,
3081            ".{ .a = .{ .x = \"foo\" }, .b = true }",
3082            null,
3083            .{
3084                .free_on_error = false,
3085            },
3086        );
3087        defer free(std.testing.allocator, result.a.x);
3088        try std.testing.expectEqualStrings("foo", result.a.x);
3089        try std.testing.expect(result.b);
3090    }
3091
3092    // Again but for arrays.
3093    {
3094        const S = [2]union { x: []const u8 };
3095        const result = try fromSliceAlloc(
3096            S,
3097            std.testing.allocator,
3098            ".{ .{ .x = \"foo\" }, .{ .x = \"bar\" } }",
3099            null,
3100            .{
3101                .free_on_error = false,
3102            },
3103        );
3104        defer free(std.testing.allocator, result[0].x);
3105        defer free(std.testing.allocator, result[1].x);
3106        try std.testing.expectEqualStrings("foo", result[0].x);
3107        try std.testing.expectEqualStrings("bar", result[1].x);
3108    }
3109
3110    // Again but for slices.
3111    {
3112        const S = []union { x: []const u8 };
3113        const result = try fromSliceAlloc(
3114            S,
3115            std.testing.allocator,
3116            ".{ .{ .x = \"foo\" }, .{ .x = \"bar\" } }",
3117            null,
3118            .{
3119                .free_on_error = false,
3120            },
3121        );
3122        defer std.testing.allocator.free(result);
3123        defer free(std.testing.allocator, result[0].x);
3124        defer free(std.testing.allocator, result[1].x);
3125        try std.testing.expectEqualStrings("foo", result[0].x);
3126        try std.testing.expectEqualStrings("bar", result[1].x);
3127    }
3128}
3129
3130test "std.zon vector" {
3131    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/15330
3132    if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .s390x) return error.SkipZigTest; // github.com/ziglang/zig/issues/25957
3133
3134    const gpa = std.testing.allocator;
3135
3136    // Passing cases
3137    try std.testing.expectEqual(
3138        @Vector(0, bool){},
3139        try fromSlice(@Vector(0, bool), gpa, ".{}", null, .{}),
3140    );
3141    try std.testing.expectEqual(
3142        @Vector(3, bool){ true, false, true },
3143        try fromSlice(@Vector(3, bool), gpa, ".{true, false, true}", null, .{}),
3144    );
3145
3146    try std.testing.expectEqual(
3147        @Vector(0, f32){},
3148        try fromSlice(@Vector(0, f32), gpa, ".{}", null, .{}),
3149    );
3150    try std.testing.expectEqual(
3151        @Vector(3, f32){ 1.5, 2.5, 3.5 },
3152        try fromSlice(@Vector(3, f32), gpa, ".{1.5, 2.5, 3.5}", null, .{}),
3153    );
3154
3155    try std.testing.expectEqual(
3156        @Vector(0, u8){},
3157        try fromSlice(@Vector(0, u8), gpa, ".{}", null, .{}),
3158    );
3159    try std.testing.expectEqual(
3160        @Vector(3, u8){ 2, 4, 6 },
3161        try fromSlice(@Vector(3, u8), gpa, ".{2, 4, 6}", null, .{}),
3162    );
3163
3164    {
3165        try std.testing.expectEqual(
3166            @Vector(0, *const u8){},
3167            try fromSliceAlloc(@Vector(0, *const u8), gpa, ".{}", null, .{}),
3168        );
3169        const pointers = try fromSliceAlloc(@Vector(3, *const u8), gpa, ".{2, 4, 6}", null, .{});
3170        defer free(gpa, pointers);
3171        try std.testing.expectEqualDeep(@Vector(3, *const u8){ &2, &4, &6 }, pointers);
3172    }
3173
3174    {
3175        try std.testing.expectEqual(
3176            @Vector(0, ?*const u8){},
3177            try fromSliceAlloc(@Vector(0, ?*const u8), gpa, ".{}", null, .{}),
3178        );
3179        const pointers = try fromSliceAlloc(@Vector(3, ?*const u8), gpa, ".{2, null, 6}", null, .{});
3180        defer free(gpa, pointers);
3181        try std.testing.expectEqualDeep(@Vector(3, ?*const u8){ &2, null, &6 }, pointers);
3182    }
3183
3184    // Too few fields
3185    {
3186        var diag: Diagnostics = .{};
3187        defer diag.deinit(gpa);
3188        try std.testing.expectError(
3189            error.ParseZon,
3190            fromSlice(@Vector(2, f32), gpa, ".{0.5}", &diag, .{}),
3191        );
3192        try std.testing.expectFmt(
3193            "1:2: error: expected 2 array elements; found 1\n",
3194            "{f}",
3195            .{diag},
3196        );
3197    }
3198
3199    // Too many fields
3200    {
3201        var diag: Diagnostics = .{};
3202        defer diag.deinit(gpa);
3203        try std.testing.expectError(
3204            error.ParseZon,
3205            fromSlice(@Vector(2, f32), gpa, ".{0.5, 1.5, 2.5}", &diag, .{}),
3206        );
3207        try std.testing.expectFmt(
3208            "1:13: error: index 2 outside of array of length 2\n",
3209            "{f}",
3210            .{diag},
3211        );
3212    }
3213
3214    // Wrong type fields
3215    {
3216        var diag: Diagnostics = .{};
3217        defer diag.deinit(gpa);
3218        try std.testing.expectError(
3219            error.ParseZon,
3220            fromSlice(@Vector(3, f32), gpa, ".{0.5, true, 2.5}", &diag, .{}),
3221        );
3222        try std.testing.expectFmt(
3223            "1:8: error: expected type 'f32'\n",
3224            "{f}",
3225            .{diag},
3226        );
3227    }
3228
3229    // Wrong type
3230    {
3231        var diag: Diagnostics = .{};
3232        defer diag.deinit(gpa);
3233        try std.testing.expectError(
3234            error.ParseZon,
3235            fromSlice(@Vector(3, u8), gpa, "true", &diag, .{}),
3236        );
3237        try std.testing.expectFmt("1:1: error: expected type '@Vector(3, u8)'\n", "{f}", .{diag});
3238    }
3239
3240    // Elements should get freed on error
3241    {
3242        var diag: Diagnostics = .{};
3243        defer diag.deinit(gpa);
3244        try std.testing.expectError(
3245            error.ParseZon,
3246            fromSliceAlloc(@Vector(3, *u8), gpa, ".{1, true, 3}", &diag, .{}),
3247        );
3248        try std.testing.expectFmt("1:6: error: expected type 'u8'\n", "{f}", .{diag});
3249    }
3250}
3251
3252test "std.zon add pointers" {
3253    const gpa = std.testing.allocator;
3254
3255    // Primitive with varying levels of pointers
3256    {
3257        const result = try fromSliceAlloc(*u32, gpa, "10", null, .{});
3258        defer free(gpa, result);
3259        try std.testing.expectEqual(@as(u32, 10), result.*);
3260    }
3261
3262    {
3263        const result = try fromSliceAlloc(**u32, gpa, "10", null, .{});
3264        defer free(gpa, result);
3265        try std.testing.expectEqual(@as(u32, 10), result.*.*);
3266    }
3267
3268    {
3269        const result = try fromSliceAlloc(***u32, gpa, "10", null, .{});
3270        defer free(gpa, result);
3271        try std.testing.expectEqual(@as(u32, 10), result.*.*.*);
3272    }
3273
3274    // Primitive optional with varying levels of pointers
3275    {
3276        const some = try fromSliceAlloc(?*u32, gpa, "10", null, .{});
3277        defer free(gpa, some);
3278        try std.testing.expectEqual(@as(u32, 10), some.?.*);
3279
3280        const none = try fromSliceAlloc(?*u32, gpa, "null", null, .{});
3281        defer free(gpa, none);
3282        try std.testing.expectEqual(null, none);
3283    }
3284
3285    {
3286        const some = try fromSliceAlloc(*?u32, gpa, "10", null, .{});
3287        defer free(gpa, some);
3288        try std.testing.expectEqual(@as(u32, 10), some.*.?);
3289
3290        const none = try fromSliceAlloc(*?u32, gpa, "null", null, .{});
3291        defer free(gpa, none);
3292        try std.testing.expectEqual(null, none.*);
3293    }
3294
3295    {
3296        const some = try fromSliceAlloc(?**u32, gpa, "10", null, .{});
3297        defer free(gpa, some);
3298        try std.testing.expectEqual(@as(u32, 10), some.?.*.*);
3299
3300        const none = try fromSliceAlloc(?**u32, gpa, "null", null, .{});
3301        defer free(gpa, none);
3302        try std.testing.expectEqual(null, none);
3303    }
3304
3305    {
3306        const some = try fromSliceAlloc(*?*u32, gpa, "10", null, .{});
3307        defer free(gpa, some);
3308        try std.testing.expectEqual(@as(u32, 10), some.*.?.*);
3309
3310        const none = try fromSliceAlloc(*?*u32, gpa, "null", null, .{});
3311        defer free(gpa, none);
3312        try std.testing.expectEqual(null, none.*);
3313    }
3314
3315    {
3316        const some = try fromSliceAlloc(**?u32, gpa, "10", null, .{});
3317        defer free(gpa, some);
3318        try std.testing.expectEqual(@as(u32, 10), some.*.*.?);
3319
3320        const none = try fromSliceAlloc(**?u32, gpa, "null", null, .{});
3321        defer free(gpa, none);
3322        try std.testing.expectEqual(null, none.*.*);
3323    }
3324
3325    // Pointer to an array
3326    {
3327        const result = try fromSliceAlloc(*[3]u8, gpa, ".{ 1, 2, 3 }", null, .{});
3328        defer free(gpa, result);
3329        try std.testing.expectEqual([3]u8{ 1, 2, 3 }, result.*);
3330    }
3331
3332    // A complicated type with nested internal pointers and string allocations
3333    {
3334        const Inner = struct {
3335            f1: *const ?*const []const u8,
3336            f2: *const ?*const []const u8,
3337        };
3338        const Outer = struct {
3339            f1: *const ?*const Inner,
3340            f2: *const ?*const Inner,
3341        };
3342        const expected: Outer = .{
3343            .f1 = &&.{
3344                .f1 = &null,
3345                .f2 = &&"foo",
3346            },
3347            .f2 = &null,
3348        };
3349
3350        const found = try fromSliceAlloc(?*Outer, gpa,
3351            \\.{
3352            \\    .f1 = .{
3353            \\        .f1 = null,
3354            \\        .f2 = "foo",
3355            \\    },
3356            \\    .f2 = null,
3357            \\}
3358        , null, .{});
3359        defer free(gpa, found);
3360
3361        try std.testing.expectEqualDeep(expected, found.?.*);
3362    }
3363
3364    // Test that optional types are flattened correctly in errors
3365    {
3366        var diag: Diagnostics = .{};
3367        defer diag.deinit(gpa);
3368        try std.testing.expectError(
3369            error.ParseZon,
3370            fromSliceAlloc(*const ?*const u8, gpa, "true", &diag, .{}),
3371        );
3372        try std.testing.expectFmt("1:1: error: expected type '?u8'\n", "{f}", .{diag});
3373    }
3374
3375    {
3376        var diag: Diagnostics = .{};
3377        defer diag.deinit(gpa);
3378        try std.testing.expectError(
3379            error.ParseZon,
3380            fromSliceAlloc(*const ?*const f32, gpa, "true", &diag, .{}),
3381        );
3382        try std.testing.expectFmt("1:1: error: expected type '?f32'\n", "{f}", .{diag});
3383    }
3384
3385    {
3386        var diag: Diagnostics = .{};
3387        defer diag.deinit(gpa);
3388        try std.testing.expectError(
3389            error.ParseZon,
3390            fromSliceAlloc(*const ?*const @Vector(3, u8), gpa, "true", &diag, .{}),
3391        );
3392        try std.testing.expectFmt("1:1: error: expected type '?@Vector(3, u8)'\n", "{f}", .{diag});
3393    }
3394
3395    {
3396        var diag: Diagnostics = .{};
3397        defer diag.deinit(gpa);
3398        try std.testing.expectError(
3399            error.ParseZon,
3400            fromSliceAlloc(*const ?*const bool, gpa, "10", &diag, .{}),
3401        );
3402        try std.testing.expectFmt("1:1: error: expected type '?bool'\n", "{f}", .{diag});
3403    }
3404
3405    {
3406        var diag: Diagnostics = .{};
3407        defer diag.deinit(gpa);
3408        try std.testing.expectError(
3409            error.ParseZon,
3410            fromSliceAlloc(*const ?*const struct { a: i32 }, gpa, "true", &diag, .{}),
3411        );
3412        try std.testing.expectFmt("1:1: error: expected optional struct\n", "{f}", .{diag});
3413    }
3414
3415    {
3416        var diag: Diagnostics = .{};
3417        defer diag.deinit(gpa);
3418        try std.testing.expectError(
3419            error.ParseZon,
3420            fromSliceAlloc(*const ?*const struct { i32 }, gpa, "true", &diag, .{}),
3421        );
3422        try std.testing.expectFmt("1:1: error: expected optional tuple\n", "{f}", .{diag});
3423    }
3424
3425    {
3426        var diag: Diagnostics = .{};
3427        defer diag.deinit(gpa);
3428        try std.testing.expectError(
3429            error.ParseZon,
3430            fromSliceAlloc(*const ?*const union { x: void }, gpa, "true", &diag, .{}),
3431        );
3432        try std.testing.expectFmt("1:1: error: expected optional union\n", "{f}", .{diag});
3433    }
3434
3435    {
3436        var diag: Diagnostics = .{};
3437        defer diag.deinit(gpa);
3438        try std.testing.expectError(
3439            error.ParseZon,
3440            fromSliceAlloc(*const ?*const [3]u8, gpa, "true", &diag, .{}),
3441        );
3442        try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag});
3443    }
3444
3445    {
3446        var diag: Diagnostics = .{};
3447        defer diag.deinit(gpa);
3448        try std.testing.expectError(
3449            error.ParseZon,
3450            fromSliceAlloc(?[3]u8, gpa, "true", &diag, .{}),
3451        );
3452        try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag});
3453    }
3454
3455    {
3456        var diag: Diagnostics = .{};
3457        defer diag.deinit(gpa);
3458        try std.testing.expectError(
3459            error.ParseZon,
3460            fromSliceAlloc(*const ?*const []u8, gpa, "true", &diag, .{}),
3461        );
3462        try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag});
3463    }
3464
3465    {
3466        var diag: Diagnostics = .{};
3467        defer diag.deinit(gpa);
3468        try std.testing.expectError(
3469            error.ParseZon,
3470            fromSliceAlloc(?[]u8, gpa, "true", &diag, .{}),
3471        );
3472        try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag});
3473    }
3474
3475    {
3476        var diag: Diagnostics = .{};
3477        defer diag.deinit(gpa);
3478        try std.testing.expectError(
3479            error.ParseZon,
3480            fromSliceAlloc(*const ?*const []const u8, gpa, "true", &diag, .{}),
3481        );
3482        try std.testing.expectFmt("1:1: error: expected optional string\n", "{f}", .{diag});
3483    }
3484
3485    {
3486        var diag: Diagnostics = .{};
3487        defer diag.deinit(gpa);
3488        try std.testing.expectError(
3489            error.ParseZon,
3490            fromSliceAlloc(*const ?*const enum { foo }, gpa, "true", &diag, .{}),
3491        );
3492        try std.testing.expectFmt("1:1: error: expected optional enum literal\n", "{f}", .{diag});
3493    }
3494}
3495
3496test "std.zon stop on node" {
3497    const gpa = std.testing.allocator;
3498
3499    {
3500        const Vec2 = struct {
3501            x: Zoir.Node.Index,
3502            y: f32,
3503        };
3504
3505        var diag: Diagnostics = .{};
3506        defer diag.deinit(gpa);
3507        const result = try fromSlice(Vec2, gpa, ".{ .x = 1.5, .y = 2.5 }", &diag, .{});
3508        try std.testing.expectEqual(result.y, 2.5);
3509        try std.testing.expectEqual(Zoir.Node{ .float_literal = 1.5 }, result.x.get(diag.zoir));
3510    }
3511
3512    {
3513        var diag: Diagnostics = .{};
3514        defer diag.deinit(gpa);
3515        const result = try fromSlice(Zoir.Node.Index, gpa, "1.23", &diag, .{});
3516        try std.testing.expectEqual(Zoir.Node{ .float_literal = 1.23 }, result.get(diag.zoir));
3517    }
3518}
3519
3520test "std.zon no alloc" {
3521    const gpa = std.testing.allocator;
3522
3523    try std.testing.expectEqual(
3524        [3]u8{ 1, 2, 3 },
3525        try fromSlice([3]u8, gpa, ".{ 1, 2, 3 }", null, .{}),
3526    );
3527
3528    const Nested = struct { u8, u8, struct { u8, u8 } };
3529
3530    var ast = try std.zig.Ast.parse(gpa, ".{ 1, 2, .{ 3, 4 } }", .zon);
3531    defer ast.deinit(gpa);
3532
3533    var zoir = try ZonGen.generate(gpa, ast, .{ .parse_str_lits = false });
3534    defer zoir.deinit(gpa);
3535
3536    try std.testing.expectEqual(
3537        Nested{ 1, 2, .{ 3, 4 } },
3538        try fromZoir(Nested, ast, zoir, null, .{}),
3539    );
3540
3541    try std.testing.expectEqual(
3542        Nested{ 1, 2, .{ 3, 4 } },
3543        try fromZoirNode(Nested, ast, zoir, .root, null, .{}),
3544    );
3545}