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.

parseCNumLit

MacroTranslator.parseCNumLit
fn parseCNumLit(mt: *MacroTranslator) ParseError!ZigNode

File

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

Code

fn parseCNumLit(mt: *MacroTranslator) ParseError!ZigNode {
    const arena = mt.t.arena;
    const lit_bytes = mt.tokSlice();
    mt.i += 1;

    // +3 for prefix and +2 for suffix
    var bytes = try std.ArrayList(u8).initCapacity(arena, lit_bytes.len + 3 + 2);

    const prefix = aro.Tree.Token.NumberPrefix.fromString(lit_bytes);
    switch (prefix) {
        .binary => bytes.appendSliceAssumeCapacity("0b"),
        .octal => bytes.appendSliceAssumeCapacity("0o"),
        .hex => bytes.appendSliceAssumeCapacity("0x"),
        .decimal => {},
    }

    const after_prefix = lit_bytes[prefix.stringLen()..];
    const after_int = for (after_prefix, 0..) |c, i| switch (c) {
        '.' => {
            if (i == 0) {
                bytes.appendAssumeCapacity('0');
            }
            break after_prefix[i..];
        },
        'e', 'E' => {
            if (prefix != .hex) break after_prefix[i..];
            bytes.appendAssumeCapacity(c);
        },
        'p', 'P' => break after_prefix[i..],
        '0'...'9', 'a'...'d', 'A'...'D', 'f', 'F' => {
            if (!prefix.digitAllowed(c)) break after_prefix[i..];
            bytes.appendAssumeCapacity(c);
        },
        '\'' => {
            bytes.appendAssumeCapacity('_');
        },
        else => break after_prefix[i..],
    } else "";

    const after_frac = frac: {
        if (after_int.len == 0 or after_int[0] != '.') break :frac after_int;
        bytes.appendAssumeCapacity('.');
        for (after_int[1..], 1..) |c, i| {
            if (c == '\'') {
                bytes.appendAssumeCapacity('_');
                continue;
            }
            if (!prefix.digitAllowed(c)) break :frac after_int[i..];
            bytes.appendAssumeCapacity(c);
        }
        break :frac "";
    };

    const suffix_str = exponent: {
        if (after_frac.len == 0) break :exponent after_frac;
        switch (after_frac[0]) {
            'e', 'E' => {},
            'p', 'P' => if (prefix != .hex) break :exponent after_frac,
            else => break :exponent after_frac,
        }
        bytes.appendAssumeCapacity(after_frac[0]);
        for (after_frac[1..], 1..) |c, i| switch (c) {
            '+', '-', '0'...'9' => {
                bytes.appendAssumeCapacity(c);
            },
            '\'' => {
                bytes.appendAssumeCapacity('_');
            },
            else => break :exponent after_frac[i..],
        };
        break :exponent "";
    };

    const is_float = after_int.len != suffix_str.len;
    const suffix = aro.Tree.Token.NumberSuffix.fromString(suffix_str, if (is_float) .float else .int) orelse {
        try mt.fail("invalid number suffix: '{s}'", .{suffix_str});
        return error.ParseError;
    };
    if (suffix.isImaginary()) {
        try mt.fail("TODO: imaginary literals", .{});
        return error.ParseError;
    }
    if (suffix.isBitInt()) {
        try mt.fail("TODO: _BitInt literals", .{});
        return error.ParseError;
    }

    if (is_float) {
        const type_node = try ZigTag.type.create(arena, switch (suffix) {
            .F16 => "f16",
            .F, .F32 => "f32",
            .None, .F32x, .F64 => "f64",
            .L, .F64x => "c_longdouble",
            .W => "f80",
            .Q, .F128 => "f128",
            else => {
                try mt.fail("TODO: float literal suffix: '{s}'", .{suffix_str});
                return error.ParseError;
            },
        });
        if (bytes.getLast().? == '.') {
            bytes.appendAssumeCapacity('0');
        } else if (mem.findAny(u8, bytes.items, ".eEpP") == null) {
            bytes.appendSliceAssumeCapacity(".0");
        }
        const rhs = try ZigTag.float_literal.create(arena, bytes.items);
        return ZigTag.as.create(arena, .{ .lhs = type_node, .rhs = rhs });
    } else {
        const type_node = try ZigTag.type.create(arena, switch (suffix) {
            .None => "c_int",
            .U => "c_uint",
            .L => "c_long",
            .UL => "c_ulong",
            .LL => "c_longlong",
            .ULL => "c_ulonglong",
            else => unreachable,
        });
        const value = std.fmt.parseInt(i128, bytes.items, 0) catch math.maxInt(i128);

        // make the output less noisy by skipping promoteIntLiteral where
        // it's guaranteed to not be required because of C standard type constraints
        const guaranteed_to_fit = switch (suffix) {
            .None => math.cast(i16, value) != null,
            .U => math.cast(u16, value) != null,
            .L => math.cast(i32, value) != null,
            .UL => math.cast(u32, value) != null,
            .LL => math.cast(i64, value) != null,
            .ULL => math.cast(u64, value) != null,
            else => unreachable,
        };

        const literal_node = try ZigTag.integer_literal.create(arena, bytes.items);
        if (guaranteed_to_fit) {
            return ZigTag.as.create(arena, .{ .lhs = type_node, .rhs = literal_node });
        } else {
            return mt.t.createHelperCallNode(.promoteIntLiteral, &.{ type_node, literal_node, try ZigTag.enum_literal.create(arena, @tagName(prefix)) });
        }
    }
}