feat: use comptime function to lex hex, octal and binary numbers

This commit is contained in:
Araozu 2024-11-16 18:56:12 -05:00
parent e7459ab441
commit 76c823cc54
2 changed files with 95 additions and 15 deletions

View File

@ -22,12 +22,11 @@ pub fn lex(input: []const u8, cap: usize, start: usize) LexError!?LexReturn {
if (first_char == '0' and cap > start + 1) { if (first_char == '0' and cap > start + 1) {
const second_char = input[start + 1]; const second_char = input[start + 1];
switch (second_char) { switch (second_char) {
'x', 'X' => return hex(input, cap, start), 'x', 'X' => return prefixed('x', input, cap, start),
'o', 'O' => return octal(), 'o', 'O' => return prefixed('o', input, cap, start),
'b', 'B' => return binary(), 'b', 'B' => return prefixed('b', input, cap, start),
else => { else => {
// Leading zero found. Throw an error. // Leading zero found. Throw an error.
// TODO: throw an error :c
return LexError.LeadingZero; return LexError.LeadingZero;
}, },
} }
@ -38,21 +37,28 @@ pub fn lex(input: []const u8, cap: usize, start: usize) LexError!?LexReturn {
return integer(input, cap, start); return integer(input, cap, start);
} }
/// Lexes a hexadecimal number. /// comptime function for lexing hex, octal and binary numbers.
/// Allows 0-9a-fA-F /// only allowed values for `prefix` are `x`, `o` & `b`.
/// Assumes that `start` is the position of the initial zero /// An adequate validator is choosen based on `prefix`,
fn hex(input: []const u8, cap: usize, start: usize) LexError!?LexReturn { /// 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; var end_position = start + 2;
// There should be at least 1 hex digit // 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; return LexError.Incomplete;
} }
// loop through all chars // loop through all chars
end_position += 1; end_position += 1;
while (end_position < cap and validator(input[end_position])) {
while (end_position < cap and utils.is_hex_digit(input[end_position])) {
end_position += 1; 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 { fn binary() !?LexReturn {
return null; return null;
} }
@ -195,3 +197,73 @@ test "shouldnt parse incomplete hex number 2" {
try std.testing.expect(false); 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);
}

View File

@ -2,6 +2,14 @@ pub fn is_decimal_digit(c: u8) bool {
return '0' <= c and c <= '9'; 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 { 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'); return ('0' <= c and c <= '9') or ('a' <= c and c <= 'f') or ('A' <= c and c <= 'F');
} }