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) {
|
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);
|
||||||
|
}
|
||||||
|
@ -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');
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user