feat: use comptime function to lex hex, octal and binary numbers
This commit is contained in:
parent
e7459ab441
commit
76c823cc54
@ -22,12 +22,11 @@ pub fn lex(input: []const u8, cap: usize, start: usize) LexError!?LexReturn {
|
||||
if (first_char == '0' and cap > start + 1) {
|
||||
const second_char = input[start + 1];
|
||||
switch (second_char) {
|
||||
'x', 'X' => return hex(input, cap, start),
|
||||
'o', 'O' => return octal(),
|
||||
'b', 'B' => return binary(),
|
||||
'x', 'X' => return prefixed('x', input, cap, start),
|
||||
'o', 'O' => return prefixed('o', input, cap, start),
|
||||
'b', 'B' => return prefixed('b', input, cap, start),
|
||||
else => {
|
||||
// Leading zero found. Throw an error.
|
||||
// TODO: throw an error :c
|
||||
return LexError.LeadingZero;
|
||||
},
|
||||
}
|
||||
@ -38,21 +37,28 @@ pub fn lex(input: []const u8, cap: usize, start: usize) LexError!?LexReturn {
|
||||
return integer(input, cap, start);
|
||||
}
|
||||
|
||||
/// Lexes a hexadecimal number.
|
||||
/// Allows 0-9a-fA-F
|
||||
/// Assumes that `start` is the position of the initial zero
|
||||
fn hex(input: []const u8, cap: usize, start: usize) LexError!?LexReturn {
|
||||
/// comptime function for lexing hex, octal and binary numbers.
|
||||
/// only allowed values for `prefix` are `x`, `o` & `b`.
|
||||
/// An adequate validator is choosen based on `prefix`,
|
||||
/// that validator will decide which characters to lex.
|
||||
fn prefixed(comptime prefix: u8, input: []const u8, cap: usize, start: usize) !?LexReturn {
|
||||
const validator = switch (prefix) {
|
||||
'x' => utils.is_hex_digit,
|
||||
'o' => utils.is_octal_digit,
|
||||
'b' => utils.is_binary_digit,
|
||||
else => @compileError("Invalid prefix passed to `prefixed` function."),
|
||||
};
|
||||
|
||||
var end_position = start + 2;
|
||||
|
||||
// There should be at least 1 hex digit
|
||||
if (end_position >= cap or !utils.is_hex_digit(input[end_position])) {
|
||||
if (end_position >= cap or !validator(input[end_position])) {
|
||||
return LexError.Incomplete;
|
||||
}
|
||||
|
||||
// loop through all chars
|
||||
end_position += 1;
|
||||
|
||||
while (end_position < cap and utils.is_hex_digit(input[end_position])) {
|
||||
while (end_position < cap and validator(input[end_position])) {
|
||||
end_position += 1;
|
||||
}
|
||||
|
||||
@ -62,10 +68,6 @@ fn hex(input: []const u8, cap: usize, start: usize) LexError!?LexReturn {
|
||||
};
|
||||
}
|
||||
|
||||
fn octal() !?LexReturn {
|
||||
return null;
|
||||
}
|
||||
|
||||
fn binary() !?LexReturn {
|
||||
return null;
|
||||
}
|
||||
@ -195,3 +197,73 @@ test "shouldnt parse incomplete hex number 2" {
|
||||
|
||||
try std.testing.expect(false);
|
||||
}
|
||||
|
||||
test "should lex octal number" {
|
||||
const input = "0o755";
|
||||
const result = try lex(input, input.len, 0);
|
||||
|
||||
if (result) |tuple| {
|
||||
const r = tuple[0];
|
||||
try std.testing.expectEqualDeep("0o755", r.value);
|
||||
} else {
|
||||
try std.testing.expect(false);
|
||||
}
|
||||
}
|
||||
|
||||
test "should lex octal number 2" {
|
||||
const input = " 0o755 ";
|
||||
const result = try lex(input, input.len, 2);
|
||||
|
||||
if (result) |tuple| {
|
||||
const r = tuple[0];
|
||||
try std.testing.expectEqualDeep("0o755", r.value);
|
||||
} else {
|
||||
try std.testing.expect(false);
|
||||
}
|
||||
}
|
||||
|
||||
test "shouldnt parse incomplete octal number" {
|
||||
const input = "0o8";
|
||||
const result = lex(input, input.len, 0) catch |err| {
|
||||
try std.testing.expect(err == token.LexError.Incomplete);
|
||||
return;
|
||||
};
|
||||
|
||||
if (result) |tuple| {
|
||||
const r = tuple[0];
|
||||
std.debug.print("{s}\n", .{r.value});
|
||||
} else {
|
||||
std.debug.print("nil returned", .{});
|
||||
}
|
||||
|
||||
try std.testing.expect(false);
|
||||
}
|
||||
|
||||
test "should lex binary number" {
|
||||
const input = "0b1011";
|
||||
const result = try lex(input, input.len, 0);
|
||||
|
||||
if (result) |tuple| {
|
||||
const r = tuple[0];
|
||||
try std.testing.expectEqualDeep("0b1011", r.value);
|
||||
} else {
|
||||
try std.testing.expect(false);
|
||||
}
|
||||
}
|
||||
|
||||
test "shouldnt parse incomplete binary number" {
|
||||
const input = "0b2";
|
||||
const result = lex(input, input.len, 0) catch |err| {
|
||||
try std.testing.expect(err == token.LexError.Incomplete);
|
||||
return;
|
||||
};
|
||||
|
||||
if (result) |tuple| {
|
||||
const r = tuple[0];
|
||||
std.debug.print("{s}\n", .{r.value});
|
||||
} else {
|
||||
std.debug.print("nil returned", .{});
|
||||
}
|
||||
|
||||
try std.testing.expect(false);
|
||||
}
|
||||
|
@ -2,6 +2,14 @@ pub fn is_decimal_digit(c: u8) bool {
|
||||
return '0' <= c and c <= '9';
|
||||
}
|
||||
|
||||
pub fn is_octal_digit(c: u8) bool {
|
||||
return '0' <= c and c <= '7';
|
||||
}
|
||||
|
||||
pub fn is_binary_digit(c: u8) bool {
|
||||
return c == '0' or c == '1';
|
||||
}
|
||||
|
||||
pub fn is_hex_digit(c: u8) bool {
|
||||
return ('0' <= c and c <= '9') or ('a' <= c and c <= 'f') or ('A' <= c and c <= 'F');
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user