Assumes that number literals normally rejected by RC's preprocessor are similarly rejected before being parsed.
Relevant RC preprocessor errors: RC2021: expected exponent value, not '<digit>' example that is rejected: 1e1 example that is accepted: 1ea (this function will parse the two examples above the same)
pub fn parseNumberLiteral(bytes: SourceBytes) Number
pub fn parseNumberLiteral(bytes: SourceBytes) Number {
std.debug.assert(bytes.slice.len > 0);
var result = Number{ .value = 0, .is_long = false };
var radix: u8 = 10;
var buf = bytes.slice;
const Prefix = enum { none, minus, complement };
var prefix: Prefix = .none;
switch (buf[0]) {
'-' => {
prefix = .minus;
buf = buf[1..];
},
'~' => {
prefix = .complement;
buf = buf[1..];
},
else => {},
}
if (buf.len > 2 and buf[0] == '0') {
switch (buf[1]) {
'o' => { // octal radix prefix is case-sensitive
radix = 8;
buf = buf[2..];
},
'x', 'X' => {
radix = 16;
buf = buf[2..];
},
else => {},
}
}
var i: usize = 0;
while (bytes.code_page.codepointAt(i, buf)) |codepoint| : (i += codepoint.byte_len) {
const c = codepoint.value;
if (c == 'L' or c == 'l') {
result.is_long = true;
break;
}
const digit = switch (c) {
// On invalid digit for the radix, just stop parsing but don't fail
0x00...0x7F => std.fmt.charToDigit(@intCast(c), radix) catch break,
else => break,
};
if (result.value != 0) {
result.value *%= radix;
}
result.value +%= digit;
}
switch (prefix) {
.none => {},
.minus => result.value = 0 -% result.value,
.complement => result.value = ~result.value,
}
return result;
}