DoxigAlpha

renderMember

Function parameters

Parameters

#
r:*Render
decl:Ast.Node.Index

Type definitions in this namespace

Types

#

Functions in this namespace

Functions

#

Error sets in this namespace

Error Sets

#

Source

Implementation

#
fn renderMember(
    r: *Render,
    container: Container,
    decl: Ast.Node.Index,
    space: Space,
) Error!void {
    const tree = r.tree;
    const ais = r.ais;
    if (r.fixups.omit_nodes.contains(decl)) return;
    try renderDocComments(r, tree.firstToken(decl));
    switch (tree.nodeTag(decl)) {
        .fn_decl => {
            // Some examples:
            // pub extern "foo" fn ...
            // export fn ...
            const fn_proto, const body_node = tree.nodeData(decl).node_and_node;
            const fn_token = tree.nodeMainToken(fn_proto);
            // Go back to the first token we should render here.
            var i = fn_token;
            while (i > 0) {
                i -= 1;
                switch (tree.tokenTag(i)) {
                    .keyword_extern,
                    .keyword_export,
                    .keyword_pub,
                    .string_literal,
                    .keyword_inline,
                    .keyword_noinline,
                    => continue,

                    else => {
                        i += 1;
                        break;
                    },
                }
            }

            while (i < fn_token) : (i += 1) {
                try renderToken(r, i, .space);
            }
            switch (tree.nodeTag(fn_proto)) {
                .fn_proto_one, .fn_proto => {
                    var buf: [1]Ast.Node.Index = undefined;
                    const opt_callconv_expr = if (tree.nodeTag(fn_proto) == .fn_proto_one)
                        tree.fnProtoOne(&buf, fn_proto).ast.callconv_expr
                    else
                        tree.fnProto(fn_proto).ast.callconv_expr;

                    // Keep in sync with logic in `renderFnProto`. Search this file for the marker PROMOTE_CALLCONV_INLINE
                    if (opt_callconv_expr.unwrap()) |callconv_expr| {
                        if (tree.nodeTag(callconv_expr) == .enum_literal) {
                            if (mem.eql(u8, "@\"inline\"", tree.tokenSlice(tree.nodeMainToken(callconv_expr)))) {
                                try ais.underlying_writer.writeAll("inline ");
                            }
                        }
                    }
                },
                .fn_proto_simple, .fn_proto_multi => {},
                else => unreachable,
            }
            try renderExpression(r, fn_proto, .space);
            if (r.fixups.gut_functions.contains(decl)) {
                try ais.pushIndent(.normal);
                const lbrace = tree.nodeMainToken(body_node);
                try renderToken(r, lbrace, .newline);
                try discardAllParams(r, fn_proto);
                try ais.writeAll("@trap();");
                ais.popIndent();
                try ais.insertNewline();
                try renderToken(r, tree.lastToken(body_node), space); // rbrace
            } else if (r.fixups.unused_var_decls.count() != 0) {
                try ais.pushIndent(.normal);
                const lbrace = tree.nodeMainToken(body_node);
                try renderToken(r, lbrace, .newline);

                var fn_proto_buf: [1]Ast.Node.Index = undefined;
                const full_fn_proto = tree.fullFnProto(&fn_proto_buf, fn_proto).?;
                var it = full_fn_proto.iterate(&tree);
                while (it.next()) |param| {
                    const name_ident = param.name_token.?;
                    assert(tree.tokenTag(name_ident) == .identifier);
                    if (r.fixups.unused_var_decls.contains(name_ident)) {
                        try ais.writeAll("_ = ");
                        try ais.writeAll(tokenSliceForRender(r.tree, name_ident));
                        try ais.writeAll(";\n");
                    }
                }
                var statements_buf: [2]Ast.Node.Index = undefined;
                const statements = tree.blockStatements(&statements_buf, body_node).?;
                return finishRenderBlock(r, body_node, statements, space);
            } else {
                return renderExpression(r, body_node, space);
            }
        },
        .fn_proto_simple,
        .fn_proto_multi,
        .fn_proto_one,
        .fn_proto,
        => {
            // Extern function prototypes are parsed as these tags.
            // Go back to the first token we should render here.
            const fn_token = tree.nodeMainToken(decl);
            var i = fn_token;
            while (i > 0) {
                i -= 1;
                switch (tree.tokenTag(i)) {
                    .keyword_extern,
                    .keyword_export,
                    .keyword_pub,
                    .string_literal,
                    .keyword_inline,
                    .keyword_noinline,
                    => continue,

                    else => {
                        i += 1;
                        break;
                    },
                }
            }
            while (i < fn_token) : (i += 1) {
                try renderToken(r, i, .space);
            }
            try renderExpression(r, decl, .none);
            return renderToken(r, tree.lastToken(decl) + 1, space); // semicolon
        },

        .global_var_decl,
        .local_var_decl,
        .simple_var_decl,
        .aligned_var_decl,
        => {
            try ais.pushSpace(.semicolon);
            try renderVarDecl(r, tree.fullVarDecl(decl).?, false, .semicolon);
            ais.popSpace();
        },

        .test_decl => {
            const test_token = tree.nodeMainToken(decl);
            const opt_name_token, const block_node = tree.nodeData(decl).opt_token_and_node;
            try renderToken(r, test_token, .space);
            if (opt_name_token.unwrap()) |name_token| {
                switch (tree.tokenTag(name_token)) {
                    .string_literal => try renderToken(r, name_token, .space),
                    .identifier => try renderIdentifier(r, name_token, .space, .preserve_when_shadowing),
                    else => unreachable,
                }
            }
            try renderExpression(r, block_node, space);
        },

        .container_field_init,
        .container_field_align,
        .container_field,
        => return renderContainerField(r, container, tree.fullContainerField(decl).?, space),

        .@"comptime" => return renderExpression(r, decl, space),

        .root => unreachable,
        else => unreachable,
    }
}