ZON specification

I would like to start experimenting with ZON, but the documentation is not very useful.

As an example Zig Documentation and Zig Documentation are not consistent.

Is there any plan to add a ZON specification in https://ziglang.org/?

1 Like

Yeah, it would be nice to have a formal specification for zon. I also wrote a parser for it recently, and I’m sure there are edge cases that I don’t know about.

How exactly are they incosistent? To me they just seem to describe different things, one describes how the zon looks like in the file, and the other describes what Zig types the standard library can turn into zon.

2 Likes

The links you provided seem to be two sides of the same coin: std.zon tells you what’s supported, and std.zon.stringify tells you what’s not supported.

std.zon says what’s supported:

Supported Zig primitives:

    boolean literals
    number literals (including nan and inf)
    character literals
    enum literals
    null literals
    string literals
    multiline string literals

Supported Zig container types:

    anonymous struct literals
    anonymous tuple literals

std.zon.stringify says what’s not supported:

The following types and any types that contain them may not be serialized:

    type
    void, except as a union payload
    noreturn
    Error sets/error unions
    Untagged unions
    Many-pointers or C-pointers
    Opaque types, including anyopaque
    Async frame types, including anyframe and anyframe->T
    Functions

All other types are valid. Unsupported types will fail to serialize at compile time. Pointers are followed.

As far as a complete and exhaustive specification goes, I’m not aware that one currently exists. Documentation in Zig is scattered around in various places, and it’s not always obvious where to find it. There’s an open issue on Github: Documentation on ZON files · Issue #15552 · ziglang/zig · GitHub

In lieu of great documentation, you might snoop around on the issue tracker, particularly for issues and pull requests related to ZON. Additionally, looking at projects built by members of the community might give you a foothold. For example, @tensorush’s zq – specifically the tests.

3 Likes

IMHO, the inconsistency is that std.zon.stringify says:

  • void, except as a union payload

This means that tagged unions are supported, but std.zon don’t list it as supported.

Also, the documentation it is not clear if typed integers and float are supported.

The documentation is also not clear about pointers.

It is also not clear if comments are allowed.

Comments are allowed, which can be seen if you create the build.zig.zon with zig init.

As for void, I guess it’s just making use of the syntactic sugar that you can use enum tags to initialize void union fields. The following two are equivalent:

.voidTag
.{.voidTag = {}}

So you can serialize void tags without writing the {} void initializer.

The documentation is also not clear about pointers.

Well, zon does not support pointers, so it’s your choice if/how you want to serialize them. I wouldn’t say that’s a thing that belongs in the data format specification.
For slices/array pointers you would probably just turn them into zon tuples, not sure what to do with single item pointers though.
From the std source code, it seems like the current implementation just ignores the pointer and treats it directly as the element pointed to:


                .pointer => |pointer| {
                    // Try to serialize as a string
                    const item: ?type = switch (@typeInfo(pointer.child)) {
                        .array => |array| array.child,
                        else => if (pointer.size == .slice) pointer.child else null,
                    };
                    if (item == u8 and
                        (pointer.sentinel() == null or pointer.sentinel() == 0) and
                        !options.emit_strings_as_containers)
                    {
                        return try self.string(val);
                    }

                    // Serialize as either a tuple or as the child type
                    switch (pointer.size) {
                        .slice => try self.tupleImpl(val, options),
                        .one => try self.valueArbitraryDepth(val.*, options),
                        else => comptime unreachable,
                    }
                },
1 Like

thats because there isnt a tagged union literal, its the same as struct literals, or enum literals for void variants

std.zon states that number literals are allowed in zon
and std.zong.stringify states types not listed as disallowed are allowed, it doesnt disallow float or int types.

std.zon.stringify states [*] and [*c] are dissalowed and that other pointers are followed