numberLiteral
Function parameters
Parameters
- gz:*GenZir
- node:Ast.Node.Index
- source_node:Ast.Node.Index
Functions in this namespace
Functions
Source
Implementation
fn numberLiteral(gz: *GenZir, ri: ResultInfo, node: Ast.Node.Index, source_node: Ast.Node.Index, sign: Sign) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
const tree = astgen.tree;
const num_token = tree.nodeMainToken(node);
const bytes = tree.tokenSlice(num_token);
const result: Zir.Inst.Ref = switch (std.zig.parseNumberLiteral(bytes)) {
.int => |num| switch (num) {
0 => if (sign == .positive) .zero else return astgen.failTokNotes(
num_token,
"integer literal '-0' is ambiguous",
.{},
&.{
try astgen.errNoteTok(num_token, "use '0' for an integer zero", .{}),
try astgen.errNoteTok(num_token, "use '-0.0' for a floating-point signed zero", .{}),
},
),
1 => {
// Handle the negation here!
const result: Zir.Inst.Ref = switch (sign) {
.positive => .one,
.negative => .negative_one,
};
return rvalue(gz, ri, result, source_node);
},
else => try gz.addInt(num),
},
.big_int => |base| big: {
const gpa = astgen.gpa;
var big_int = try std.math.big.int.Managed.init(gpa);
defer big_int.deinit();
const prefix_offset: usize = if (base == .decimal) 0 else 2;
big_int.setString(@intFromEnum(base), bytes[prefix_offset..]) catch |err| switch (err) {
error.InvalidCharacter => unreachable, // caught in `parseNumberLiteral`
error.InvalidBase => unreachable, // we only pass 16, 8, 2, see above
error.OutOfMemory => return error.OutOfMemory,
};
const limbs = big_int.limbs[0..big_int.len()];
assert(big_int.isPositive());
break :big try gz.addIntBig(limbs);
},
.float => {
const unsigned_float_number = std.fmt.parseFloat(f128, bytes) catch |err| switch (err) {
error.InvalidCharacter => unreachable, // validated by tokenizer
};
const float_number = switch (sign) {
.negative => -unsigned_float_number,
.positive => unsigned_float_number,
};
// If the value fits into a f64 without losing any precision, store it that way.
@setFloatMode(.strict);
const smaller_float: f64 = @floatCast(float_number);
const bigger_again: f128 = smaller_float;
if (bigger_again == float_number) {
const result = try gz.addFloat(smaller_float);
return rvalue(gz, ri, result, source_node);
}
// We need to use 128 bits. Break the float into 4 u32 values so we can
// put it into the `extra` array.
const int_bits: u128 = @bitCast(float_number);
const result = try gz.addPlNode(.float128, node, Zir.Inst.Float128{
.piece0 = @truncate(int_bits),
.piece1 = @truncate(int_bits >> 32),
.piece2 = @truncate(int_bits >> 64),
.piece3 = @truncate(int_bits >> 96),
});
return rvalue(gz, ri, result, source_node);
},
.failure => |err| return astgen.failWithNumberError(err, num_token, bytes),
};
if (sign == .positive) {
return rvalue(gz, ri, result, source_node);
} else {
const negated = try gz.addUnNode(.negate, result, source_node);
return rvalue(gz, ri, negated, source_node);
}
}