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.

parseCPrimaryExpr

MacroTranslator.parseCPrimaryExpr
fn parseCPrimaryExpr(mt: *MacroTranslator, scope: *Scope) ParseError!ZigNode

File

lib/compiler/translate-c/MacroTranslator.zig:592

Code

fn parseCPrimaryExpr(mt: *MacroTranslator, scope: *Scope) ParseError!ZigNode {
    const arena = mt.t.arena;
    const gpa = mt.t.gpa;
    const tok = mt.peek();
    switch (tok) {
        .char_literal,
        .char_literal_utf_8,
        .char_literal_utf_16,
        .char_literal_utf_32,
        .char_literal_wide,
        => {
            const slice = mt.tokSlice();
            if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {
                return ZigTag.char_literal.create(arena, try mt.escapeUnprintables());
            } else {
                mt.i += 1;

                const str = try std.fmt.allocPrint(arena, "0x{x}", .{slice[1 .. slice.len - 1]});
                return ZigTag.integer_literal.create(arena, str);
            }
        },
        .string_literal,
        .string_literal_utf_16,
        .string_literal_utf_8,
        .string_literal_utf_32,
        .string_literal_wide,
        => return ZigTag.string_literal.create(arena, try mt.escapeUnprintables()),
        .pp_num => return mt.parseCNumLit(),
        .l_paren => {
            mt.i += 1;
            const inner_node = try mt.parseCExpr(scope);

            try mt.expect(.r_paren);
            return inner_node;
        },
        .macro_param, .macro_param_no_expand => {
            const param = mt.macro.params[mt.tokens[mt.i].end];
            mt.i += 1;

            const mangled_name = scope.getAlias(param) orelse param;
            return try ZigTag.identifier.create(arena, mangled_name);
        },
        .identifier, .extended_identifier => {
            const slice = mt.tokSlice();
            mt.i += 1;

            const mangled_name = scope.getAlias(slice) orelse slice;
            if (Translator.builtin_typedef_map.get(mangled_name)) |ty| {
                return ZigTag.type.create(arena, ty);
            }
            if (builtins.map.get(mangled_name)) |builtin| {
                const builtin_identifier = try ZigTag.identifier.create(arena, "__builtin");
                return ZigTag.field_access.create(arena, .{
                    .lhs = builtin_identifier,
                    .field_name = builtin.name,
                });
            }

            const identifier = try ZigTag.identifier.create(arena, mangled_name);
            scope.skipVariableDiscard(mangled_name);
            refs_var: {
                const ident_node = mt.t.global_scope.sym_table.get(slice) orelse break :refs_var;
                const var_decl_node = ident_node.castTag(.var_decl) orelse break :refs_var;
                if (!var_decl_node.data.is_const) mt.refs_var_decl = true;
            }
            return identifier;
        },
        .keyword_generic => {
            mt.i += 1;

            try mt.expect(.l_paren);
            const param = try mt.parseCCondExpr(scope);
            const typeof_param = try ZigTag.typeof.create(arena, param);
            try mt.expect(.comma);

            var cases: std.ArrayList(ZigNode) = .empty;
            defer cases.deinit(gpa);
            var has_default = false;
            while (true) {
                const case = if (mt.eat(.keyword_default)) blk: {
                    has_default = true;
                    try mt.expect(.colon);
                    const expr = try mt.parseCCondExpr(scope);
                    break :blk try ZigTag.switch_else.create(arena, expr);
                } else blk: {
                    const case_type = try mt.parseCTypeName(scope) orelse {
                        try mt.fail("unable to translate C expr: expected type instead got '{s}'", .{mt.peek().symbol()});
                        return error.ParseError;
                    };
                    try mt.expect(.colon);
                    const expr = try mt.parseCCondExpr(scope);
                    break :blk try ZigTag.switch_prong.create(arena, .{
                        .cases = try arena.dupe(ZigNode, &.{case_type}),
                        .cond = expr,
                    });
                };
                try cases.append(gpa, case);
                if (!mt.eat(.comma)) break;
            }
            try mt.expect(.r_paren);

            if (!has_default) try cases.append(gpa, try ZigTag.switch_else.create(
                arena,
                try ZigTag.@"comptime".create(arena, ZigTag.@"unreachable".init()),
            ));

            const sw = try ZigTag.@"switch".create(arena, .{
                .cond = typeof_param,
                .cases = try arena.dupe(ZigNode, cases.items),
            });
            return sw;
        },
        else => {},
    }

    // for handling type macros (EVIL)
    // TODO maybe detect and treat type macros as typedefs in parseCSpecifierQualifierList?
    if (try mt.parseCTypeName(scope)) |type_name| {
        return type_name;
    }

    try mt.fail("unable to translate C expr: unexpected token '{s}'", .{tok.symbol()});
    return error.ParseError;
}