DoxigAlpha

renderFnProto

Function parameters

Parameters

#
r:*Render
fn_proto:Ast.full.FnProto

Type definitions in this namespace

Types

#

Functions in this namespace

Functions

#

Error sets in this namespace

Error Sets

#

Source

Implementation

#
fn renderFnProto(r: *Render, fn_proto: Ast.full.FnProto, space: Space) Error!void {
    const tree = r.tree;
    const ais = r.ais;

    const after_fn_token = fn_proto.ast.fn_token + 1;
    const lparen = if (tree.tokenTag(after_fn_token) == .identifier) blk: {
        try renderToken(r, fn_proto.ast.fn_token, .space); // fn
        try renderIdentifier(r, after_fn_token, .none, .preserve_when_shadowing); // name
        break :blk after_fn_token + 1;
    } else blk: {
        try renderToken(r, fn_proto.ast.fn_token, .space); // fn
        break :blk fn_proto.ast.fn_token + 1;
    };
    assert(tree.tokenTag(lparen) == .l_paren);

    const return_type = fn_proto.ast.return_type.unwrap().?;
    const maybe_bang = tree.firstToken(return_type) - 1;
    const rparen = blk: {
        // These may appear in any order, so we have to check the token_starts array
        // to find out which is first.
        var rparen = if (tree.tokenTag(maybe_bang) == .bang) maybe_bang - 1 else maybe_bang;
        var smallest_start = tree.tokenStart(maybe_bang);
        if (fn_proto.ast.align_expr.unwrap()) |align_expr| {
            const tok = tree.firstToken(align_expr) - 3;
            const start = tree.tokenStart(tok);
            if (start < smallest_start) {
                rparen = tok;
                smallest_start = start;
            }
        }
        if (fn_proto.ast.addrspace_expr.unwrap()) |addrspace_expr| {
            const tok = tree.firstToken(addrspace_expr) - 3;
            const start = tree.tokenStart(tok);
            if (start < smallest_start) {
                rparen = tok;
                smallest_start = start;
            }
        }
        if (fn_proto.ast.section_expr.unwrap()) |section_expr| {
            const tok = tree.firstToken(section_expr) - 3;
            const start = tree.tokenStart(tok);
            if (start < smallest_start) {
                rparen = tok;
                smallest_start = start;
            }
        }
        if (fn_proto.ast.callconv_expr.unwrap()) |callconv_expr| {
            const tok = tree.firstToken(callconv_expr) - 3;
            const start = tree.tokenStart(tok);
            if (start < smallest_start) {
                rparen = tok;
                smallest_start = start;
            }
        }
        break :blk rparen;
    };
    assert(tree.tokenTag(rparen) == .r_paren);

    // The params list is a sparse set that does *not* include anytype or ... parameters.

    const trailing_comma = tree.tokenTag(rparen - 1) == .comma;
    if (!trailing_comma and !hasComment(tree, lparen, rparen)) {
        // Render all on one line, no trailing comma.
        try renderToken(r, lparen, .none); // (

        var param_i: usize = 0;
        var last_param_token = lparen;
        while (true) {
            last_param_token += 1;
            switch (tree.tokenTag(last_param_token)) {
                .doc_comment => {
                    try renderToken(r, last_param_token, .newline);
                    continue;
                },
                .ellipsis3 => {
                    try renderToken(r, last_param_token, .none); // ...
                    break;
                },
                .keyword_noalias, .keyword_comptime => {
                    try renderToken(r, last_param_token, .space);
                    last_param_token += 1;
                },
                .identifier => {},
                .keyword_anytype => {
                    try renderToken(r, last_param_token, .none); // anytype
                    continue;
                },
                .r_paren => break,
                .comma => {
                    try renderToken(r, last_param_token, .space); // ,
                    continue;
                },
                else => {}, // Parameter type without a name.
            }
            if (tree.tokenTag(last_param_token) == .identifier and
                tree.tokenTag(last_param_token + 1) == .colon)
            {
                try renderIdentifier(r, last_param_token, .none, .preserve_when_shadowing); // name
                last_param_token = last_param_token + 1;
                try renderToken(r, last_param_token, .space); // :
                last_param_token += 1;
            }
            if (tree.tokenTag(last_param_token) == .keyword_anytype) {
                try renderToken(r, last_param_token, .none); // anytype
                continue;
            }
            const param = fn_proto.ast.params[param_i];
            param_i += 1;
            try renderExpression(r, param, .none);
            last_param_token = tree.lastToken(param);
        }
    } else {
        // One param per line.
        try ais.pushIndent(.normal);
        try renderToken(r, lparen, .newline); // (

        var param_i: usize = 0;
        var last_param_token = lparen;
        while (true) {
            last_param_token += 1;
            switch (tree.tokenTag(last_param_token)) {
                .doc_comment => {
                    try renderToken(r, last_param_token, .newline);
                    continue;
                },
                .ellipsis3 => {
                    try renderToken(r, last_param_token, .comma); // ...
                    break;
                },
                .keyword_noalias, .keyword_comptime => {
                    try renderToken(r, last_param_token, .space);
                    last_param_token += 1;
                },
                .identifier => {},
                .keyword_anytype => {
                    try renderToken(r, last_param_token, .comma); // anytype
                    if (tree.tokenTag(last_param_token + 1) == .comma)
                        last_param_token += 1;
                    continue;
                },
                .r_paren => break,
                else => {}, // Parameter type without a name.
            }
            if (tree.tokenTag(last_param_token) == .identifier and
                tree.tokenTag(last_param_token + 1) == .colon)
            {
                try renderIdentifier(r, last_param_token, .none, .preserve_when_shadowing); // name
                last_param_token += 1;
                try renderToken(r, last_param_token, .space); // :
                last_param_token += 1;
            }
            if (tree.tokenTag(last_param_token) == .keyword_anytype) {
                try renderToken(r, last_param_token, .comma); // anytype
                if (tree.tokenTag(last_param_token + 1) == .comma)
                    last_param_token += 1;
                continue;
            }
            const param = fn_proto.ast.params[param_i];
            param_i += 1;
            try ais.pushSpace(.comma);
            try renderExpression(r, param, .comma);
            ais.popSpace();
            last_param_token = tree.lastToken(param);
            if (tree.tokenTag(last_param_token + 1) == .comma) last_param_token += 1;
        }
        ais.popIndent();
    }

    try renderToken(r, rparen, .space); // )

    if (fn_proto.ast.align_expr.unwrap()) |align_expr| {
        const align_lparen = tree.firstToken(align_expr) - 1;
        const align_rparen = tree.lastToken(align_expr) + 1;

        try renderToken(r, align_lparen - 1, .none); // align
        try renderToken(r, align_lparen, .none); // (
        try renderExpression(r, align_expr, .none);
        try renderToken(r, align_rparen, .space); // )
    }

    if (fn_proto.ast.addrspace_expr.unwrap()) |addrspace_expr| {
        const align_lparen = tree.firstToken(addrspace_expr) - 1;
        const align_rparen = tree.lastToken(addrspace_expr) + 1;

        try renderToken(r, align_lparen - 1, .none); // addrspace
        try renderToken(r, align_lparen, .none); // (
        try renderExpression(r, addrspace_expr, .none);
        try renderToken(r, align_rparen, .space); // )
    }

    if (fn_proto.ast.section_expr.unwrap()) |section_expr| {
        const section_lparen = tree.firstToken(section_expr) - 1;
        const section_rparen = tree.lastToken(section_expr) + 1;

        try renderToken(r, section_lparen - 1, .none); // section
        try renderToken(r, section_lparen, .none); // (
        try renderExpression(r, section_expr, .none);
        try renderToken(r, section_rparen, .space); // )
    }

    if (fn_proto.ast.callconv_expr.unwrap()) |callconv_expr| {
        // Keep in sync with logic in `renderMember`. Search this file for the marker PROMOTE_CALLCONV_INLINE
        const is_callconv_inline = mem.eql(u8, "@\"inline\"", tree.tokenSlice(tree.nodeMainToken(callconv_expr)));
        const is_declaration = fn_proto.name_token != null;
        if (!(is_declaration and is_callconv_inline)) {
            const callconv_lparen = tree.firstToken(callconv_expr) - 1;
            const callconv_rparen = tree.lastToken(callconv_expr) + 1;

            try renderToken(r, callconv_lparen - 1, .none); // callconv
            try renderToken(r, callconv_lparen, .none); // (
            try renderExpression(r, callconv_expr, .none);
            try renderToken(r, callconv_rparen, .space); // )
        }
    }

    if (tree.tokenTag(maybe_bang) == .bang) {
        try renderToken(r, maybe_bang, .none); // !
    }
    return renderExpression(r, return_type, space);
}