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.

transCall

Translator.transCall
fn transCall(
    t: *Translator,
    scope: *Scope,
    call: Node.Call,
    used: ResultUsed,
) TransError!ZigNode

File

lib/compiler/translate-c/Translator.zig:3393

Code

fn transCall(
    t: *Translator,
    scope: *Scope,
    call: Node.Call,
    used: ResultUsed,
) TransError!ZigNode {
    const raw_fn_expr = try t.transExpr(scope, call.callee, .used);
    const fn_expr = blk: {
        loop: switch (call.callee.get(t.tree)) {
            .paren_expr => |paren_expr| {
                continue :loop paren_expr.operand.get(t.tree);
            },
            .decl_ref_expr => |decl_ref| {
                if (decl_ref.qt.is(t.comp, .func)) break :blk raw_fn_expr;
            },
            .cast => |cast| {
                if (cast.kind == .function_to_pointer) {
                    continue :loop cast.operand.get(t.tree);
                }
            },
            .deref_expr, .addr_of_expr => |un| {
                continue :loop un.operand.get(t.tree);
            },
            .generic_expr => |generic| {
                continue :loop generic.chosen.get(t.tree);
            },
            .generic_association_expr => |generic| {
                continue :loop generic.expr.get(t.tree);
            },
            .generic_default_expr => |generic| {
                continue :loop generic.expr.get(t.tree);
            },
            else => {},
        }
        break :blk try ZigTag.unwrap.create(t.arena, raw_fn_expr);
    };

    const callee_qt = call.callee.qt(t.tree);
    const maybe_ptr_ty = callee_qt.get(t.comp, .pointer);
    const func_qt = if (maybe_ptr_ty) |ptr| ptr.child else callee_qt;
    const func_ty = func_qt.get(t.comp, .func).?;

    const arg_nodes = try t.arena.alloc(ZigNode, call.args.len);
    for (call.args, arg_nodes, 0..) |c_arg, *zig_arg, i| {
        if (i < func_ty.params.len) {
            zig_arg.* = try t.transExprCoercing(scope, c_arg, .used);

            if (zig_arg.isBoolRes() and !func_ty.params[i].qt.is(t.comp, .bool)) {
                // In C the result type of a boolean expression is int. If this result is passed as
                // an argument to a function whose parameter is also int, there is no cast. Therefore
                // in Zig we'll need to cast it from bool to u1 (which will safely coerce to c_int).
                zig_arg.* = try ZigTag.int_from_bool.create(t.arena, zig_arg.*);
            }
        } else {
            zig_arg.* = try t.transExpr(scope, c_arg, .used);

            if (zig_arg.isBoolRes()) {
                // Same as above but now we don't have a result type.
                const u1_node = try ZigTag.int_from_bool.create(t.arena, zig_arg.*);
                const c_int_node = try ZigTag.type.create(t.arena, "c_int");
                zig_arg.* = try ZigTag.as.create(t.arena, .{ .lhs = c_int_node, .rhs = u1_node });
            }
        }
    }

    const res = try ZigTag.call.create(t.arena, .{
        .lhs = fn_expr,
        .args = arg_nodes,
    });
    if (call.qt.is(t.comp, .void)) return res;
    return t.maybeSuppressResult(used, res);
}