Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

Node

ast.Node
pub const Node = extern union

File

Code

pub const Node = extern union {
    /// If the tag value is less than Tag.no_payload_count, then no pointer
    /// dereference is needed.
    tag_if_small_enough: usize,
    ptr_otherwise: *Payload,

    pub const Tag = enum {
        /// Declarations add themselves to the correct scopes and should not be emitted as this tag.
        declaration,
        null_literal,
        undefined_literal,
        /// opaque {}
        opaque_literal,
        true_literal,
        false_literal,
        empty_block,
        return_void,
        zero_literal,
        one_literal,
        @"unreachable",
        void_type,
        noreturn_type,
        @"anytype",
        @"continue",
        @"break",
        // After this, the tag requires a payload.

        integer_literal,
        float_literal,
        string_literal,
        char_literal,
        enum_literal,
        /// "string"[0..end]
        string_slice,
        identifier,
        @"if",
        /// if (!operand) break;
        if_not_break,
        @"while",
        /// while (true) operand
        while_true,
        @"switch",
        /// else => operand,
        switch_else,
        /// items => body,
        switch_prong,
        break_val,
        @"return",
        field_access,
        field_builtin,
        array_access,
        call,
        var_decl,
        /// const name = struct { init }
        wrapped_local,
        /// var name = init.*
        mut_str,
        func,
        warning,
        @"struct",
        @"union",
        @"opaque",
        @"comptime",
        @"defer",
        array_init,
        tuple,
        container_init,
        container_init_dot,
        /// _ = operand;
        discard,

        // a + b
        add,
        // a = b
        add_assign,
        // c = (a = b)
        add_wrap,
        add_wrap_assign,
        sub,
        sub_assign,
        sub_wrap,
        sub_wrap_assign,
        mul,
        mul_assign,
        mul_wrap,
        mul_wrap_assign,
        div,
        div_assign,
        shl,
        shl_assign,
        shr,
        shr_assign,
        mod,
        mod_assign,
        @"and",
        @"or",
        less_than,
        less_than_equal,
        greater_than,
        greater_than_equal,
        equal,
        not_equal,
        bit_and,
        bit_and_assign,
        bit_or,
        bit_or_assign,
        bit_xor,
        bit_xor_assign,
        array_cat,
        ellipsis3,
        assign,

        /// @intCast(operand)
        int_cast,
        /// @constCast(operand)
        const_cast,
        /// @volatileCast(operand)
        volatile_cast,
        /// @divTrunc(lhs, rhs)
        div_trunc,
        /// @intFromBool(operand)
        int_from_bool,
        /// @as(lhs, rhs)
        as,
        /// @truncate(operand)
        truncate,
        /// @bitCast(operand)
        bit_cast,
        /// @floatCast(operand)
        float_cast,
        /// @intFromFloat(operand)
        int_from_float,
        /// @floatFromInt(operand)
        float_from_int,
        /// @ptrFromInt(operand)
        ptr_from_int,
        /// @intFromPtr(operand)
        int_from_ptr,
        /// @alignCast(operand)
        align_cast,
        /// @ptrCast(operand)
        ptr_cast,
        /// @divExact(lhs, rhs)
        div_exact,
        /// @offsetOf(lhs, rhs)
        offset_of,
        /// @splat(operand)
        vector_zero_init,
        /// @shuffle(type, a, b, mask)
        shuffle,
        /// @extern(ty, .{ .name = n })
        builtin_extern,

        /// @byteSwap(operand)
        byte_swap,
        /// @ceil(operand)
        ceil,
        /// @cos(operand)
        cos,
        /// @sin(operand)
        sin,
        /// @exp(operand)
        exp,
        /// @exp2(operand)
        exp2,
        /// @exp10(operand)
        exp10,
        /// @abs(operand)
        abs,
        /// @log(operand)
        log,
        /// @log2(operand)
        log2,
        /// @log10(operand)
        log10,
        /// @round(operand)
        round,
        /// @sqrt(operand)
        sqrt,
        /// @trunc(operand)
        trunc,
        /// @floor(operand)
        floor,

        /// __helpers.<name>(argshelper_call)
        helper_call,
        /// __helpers.<name>
        helper_ref,

        asm_simple,

        negate,
        negate_wrap,
        bit_not,
        not,
        address_of,
        /// .?
        unwrap,
        /// .*
        deref,

        block,
        /// { operand }
        block_single,

        sizeof,
        alignof,
        typeof,
        typeinfo,
        type,

        optional_type,
        c_pointer,
        single_pointer,
        array_type,
        null_sentinel_array_type,

        /// @Vector(lhs, rhs)
        vector,
        /// @import("std").mem.zeroes(operand)
        std_mem_zeroes,
        /// @import("std").mem.zeroInit(lhs, rhs)
        std_mem_zeroinit,
        // pub const name = @compileError(msg);
        fail_decl,
        // var actual = mangled;
        arg_redecl,
        /// pub const alias = actual;
        alias,
        /// const name = init;
        var_simple,
        /// pub const name = init;
        pub_var_simple,
        /// pub? const name (: type)? = value
        enum_constant,

        /// pub inline fn name(params) return_type body
        pub_inline_fn,

        /// array_type{}
        empty_array,
        /// @as([count]type, @splat(val))
        array_filler,

        /// comptime { if (!(lhs)) @compileError(rhs); }
        static_assert,

        /// __root.<name>
        root_ref,

        pub const last_no_payload_tag = Tag.@"break";
        pub const no_payload_count = @backingInt(last_no_payload_tag) + 1;

        pub fn Type(comptime t: Tag) type {
            return switch (t) {
                .declaration,
                .null_literal,
                .undefined_literal,
                .opaque_literal,
                .true_literal,
                .false_literal,
                .empty_block,
                .return_void,
                .zero_literal,
                .one_literal,
                .void_type,
                .noreturn_type,
                .@"anytype",
                .@"continue",
                .@"break",
                .@"unreachable",
                => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),

                .std_mem_zeroes,
                .@"return",
                .@"comptime",
                .@"defer",
                .asm_simple,
                .negate,
                .negate_wrap,
                .bit_not,
                .not,
                .optional_type,
                .address_of,
                .unwrap,
                .deref,
                .int_from_ptr,
                .empty_array,
                .while_true,
                .if_not_break,
                .switch_else,
                .block_single,
                .int_from_bool,
                .sizeof,
                .alignof,
                .typeof,
                .typeinfo,
                .align_cast,
                .truncate,
                .bit_cast,
                .float_cast,
                .int_from_float,
                .float_from_int,
                .ptr_from_int,
                .ptr_cast,
                .int_cast,
                .const_cast,
                .volatile_cast,
                .vector_zero_init,
                .byte_swap,
                .ceil,
                .cos,
                .sin,
                .exp,
                .exp2,
                .exp10,
                .abs,
                .log,
                .log2,
                .log10,
                .round,
                .sqrt,
                .trunc,
                .floor,
                => Payload.UnOp,

                .add,
                .add_assign,
                .add_wrap,
                .add_wrap_assign,
                .sub,
                .sub_assign,
                .sub_wrap,
                .sub_wrap_assign,
                .mul,
                .mul_assign,
                .mul_wrap,
                .mul_wrap_assign,
                .div,
                .div_assign,
                .shl,
                .shl_assign,
                .shr,
                .shr_assign,
                .mod,
                .mod_assign,
                .@"and",
                .@"or",
                .less_than,
                .less_than_equal,
                .greater_than,
                .greater_than_equal,
                .equal,
                .not_equal,
                .bit_and,
                .bit_and_assign,
                .bit_or,
                .bit_or_assign,
                .bit_xor,
                .bit_xor_assign,
                .div_trunc,
                .as,
                .array_cat,
                .ellipsis3,
                .assign,
                .array_access,
                .std_mem_zeroinit,
                .vector,
                .div_exact,
                .offset_of,
                .static_assert,
                .field_builtin,
                => Payload.BinOp,

                .integer_literal,
                .float_literal,
                .string_literal,
                .char_literal,
                .enum_literal,
                .identifier,
                .warning,
                .type,
                => Payload.Value,
                .discard => Payload.Discard,
                .@"if" => Payload.If,
                .@"while" => Payload.While,
                .@"switch", .array_init, .switch_prong => Payload.Switch,
                .break_val => Payload.BreakVal,
                .call => Payload.Call,
                .var_decl => Payload.VarDecl,
                .func => Payload.Func,
                .@"struct", .@"union", .@"opaque" => Payload.Container,
                .tuple => Payload.TupleInit,
                .container_init => Payload.ContainerInit,
                .container_init_dot => Payload.ContainerInitDot,
                .block => Payload.Block,
                .c_pointer, .single_pointer => Payload.Pointer,
                .array_type, .null_sentinel_array_type => Payload.Array,
                .arg_redecl, .alias => Payload.ArgRedecl,
                .fail_decl => Payload.FailDecl,
                .var_simple, .pub_var_simple, .wrapped_local, .mut_str => Payload.SimpleVarDecl,
                .enum_constant => Payload.EnumConstant,
                .array_filler => Payload.ArrayFiller,
                .pub_inline_fn => Payload.PubInlineFn,
                .field_access => Payload.FieldAccess,
                .string_slice => Payload.StringSlice,
                .shuffle => Payload.Shuffle,
                .builtin_extern => Payload.Extern,
                .helper_call => Payload.HelperCall,
                .helper_ref => Payload.HelperRef,
                .root_ref => Payload.RootRef,
            };
        }

        pub fn init(comptime t: Tag) Node {
            comptime std.debug.assert(@backingInt(t) < Tag.no_payload_count);
            return .{ .tag_if_small_enough = @backingInt(t) };
        }

        pub fn create(comptime t: Tag, ally: Allocator, data: Data(t)) error{OutOfMemory}!Node {
            const ptr = try ally.create(t.Type());
            ptr.* = .{
                .base = .{ .tag = t },
                .data = data,
            };
            return Node{ .ptr_otherwise = &ptr.base };
        }

        pub fn Data(comptime t: Tag) type {
            return std.meta.fieldInfo(t.Type(), .data).type;
        }
    };

    pub fn tag(self: Node) Tag {
        if (self.tag_if_small_enough < Tag.no_payload_count) {
            return @fromBackingInt(@intCast(@as(std.meta.Tag(Tag), @intCast(self.tag_if_small_enough))));
        } else {
            return self.ptr_otherwise.tag;
        }
    }

    pub fn castTag(self: Node, comptime t: Tag) ?*t.Type() {
        if (self.tag_if_small_enough < Tag.no_payload_count)
            return null;

        if (self.ptr_otherwise.tag == t)
            return @alignCast(@fieldParentPtr("base", self.ptr_otherwise));

        return null;
    }

    pub fn initPayload(payload: *Payload) Node {
        std.debug.assert(@backingInt(payload.tag) >= Tag.no_payload_count);
        return .{ .ptr_otherwise = payload };
    }

    pub fn isNoreturn(node: Node) bool {
        return switch (node.tag()) {
            .block => {
                const block_node = node.castTag(.block).?;
                if (block_node.data.stmts.len == 0) return false;

                const last = block_node.data.stmts[block_node.data.stmts.len - 1];
                return last.isNoreturn();
            },
            .@"switch" => {
                const switch_node = node.castTag(.@"switch").?;

                for (switch_node.data.cases) |case| {
                    const body = if (case.castTag(.switch_else)) |some|
                        some.data
                    else if (case.castTag(.switch_prong)) |some|
                        some.data.cond
                    else
                        unreachable;

                    if (!body.isNoreturn()) return false;
                }
                return true;
            },
            .@"return", .return_void => true,
            .@"break" => true,
            .@"continue" => true,
            .@"unreachable" => true,
            else => false,
        };
    }

    pub fn isBoolRes(res: Node) bool {
        switch (res.tag()) {
            .@"or",
            .@"and",
            .equal,
            .not_equal,
            .less_than,
            .less_than_equal,
            .greater_than,
            .greater_than_equal,
            .not,
            .false_literal,
            .true_literal,
            => return true,
            else => return false,
        }
    }
}