feat: parse hex numbers
This commit is contained in:
parent
758f551db0
commit
e7459ab441
@ -4,6 +4,7 @@ const utils = @import("./utils.zig");
|
|||||||
|
|
||||||
const Token = token.Token;
|
const Token = token.Token;
|
||||||
const TokenType = token.TokenType;
|
const TokenType = token.TokenType;
|
||||||
|
const LexError = token.LexError;
|
||||||
|
|
||||||
const is_decimal_digit = utils.is_decimal_digit;
|
const is_decimal_digit = utils.is_decimal_digit;
|
||||||
|
|
||||||
@ -14,20 +15,22 @@ const LexReturn = struct { Token, usize };
|
|||||||
/// A number is either an Int or a Float.
|
/// A number is either an Int or a Float.
|
||||||
/// No number can have a leading zero. That is an error to
|
/// No number can have a leading zero. That is an error to
|
||||||
/// avoid confussion with PHP literal octals.
|
/// avoid confussion with PHP literal octals.
|
||||||
fn lex(input: []const u8, cap: usize, start: usize) !?LexReturn {
|
pub fn lex(input: []const u8, cap: usize, start: usize) LexError!?LexReturn {
|
||||||
const first_char = input[start];
|
const first_char = input[start];
|
||||||
|
|
||||||
// Attempt to lex a hex, octal or binary number
|
// Attempt to lex a hex, octal or binary number
|
||||||
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(),
|
'x', 'X' => return hex(input, cap, start),
|
||||||
'o', 'O' => return octal(),
|
'o', 'O' => return octal(),
|
||||||
'b', 'B' => return binary(),
|
'b', 'B' => return binary(),
|
||||||
|
else => {
|
||||||
|
// Leading zero found. Throw an error.
|
||||||
|
// TODO: throw an error :c
|
||||||
|
return LexError.LeadingZero;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Leading zero found. Throw an error.
|
|
||||||
// TODO: throw an error :c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to lex an integer.
|
// Attempt to lex an integer.
|
||||||
@ -35,8 +38,28 @@ fn lex(input: []const u8, cap: usize, start: usize) !?LexReturn {
|
|||||||
return integer(input, cap, start);
|
return integer(input, cap, start);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hex() !?LexReturn {
|
/// Lexes a hexadecimal number.
|
||||||
return null;
|
/// 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 {
|
||||||
|
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])) {
|
||||||
|
return LexError.Incomplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop through all chars
|
||||||
|
end_position += 1;
|
||||||
|
|
||||||
|
while (end_position < cap and utils.is_hex_digit(input[end_position])) {
|
||||||
|
end_position += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{
|
||||||
|
Token.init(input[start..end_position], TokenType.Int, start),
|
||||||
|
end_position,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn octal() !?LexReturn {
|
fn octal() !?LexReturn {
|
||||||
@ -114,3 +137,61 @@ test "should return null if not an integer" {
|
|||||||
|
|
||||||
try std.testing.expect(result == null);
|
try std.testing.expect(result == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "should lex hex number" {
|
||||||
|
const input = "0xa";
|
||||||
|
const result = try lex(input, input.len, 0);
|
||||||
|
|
||||||
|
if (result) |tuple| {
|
||||||
|
const r = tuple[0];
|
||||||
|
try std.testing.expectEqualDeep("0xa", r.value);
|
||||||
|
} else {
|
||||||
|
try std.testing.expect(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "should lex hex number 2" {
|
||||||
|
const input = " 0Xff00AA ";
|
||||||
|
const result = try lex(input, input.len, 2);
|
||||||
|
|
||||||
|
if (result) |tuple| {
|
||||||
|
const r = tuple[0];
|
||||||
|
try std.testing.expectEqualDeep("0Xff00AA", r.value);
|
||||||
|
} else {
|
||||||
|
try std.testing.expect(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "shouldnt parse incomplete hex number" {
|
||||||
|
const input = "0xZZ";
|
||||||
|
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 "shouldnt parse incomplete hex number 2" {
|
||||||
|
const input = "0x";
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
@ -7,8 +7,13 @@ const Token = token.Token;
|
|||||||
|
|
||||||
pub fn tokenize(input: []const u8) !void {
|
pub fn tokenize(input: []const u8) !void {
|
||||||
const input_len = input.len;
|
const input_len = input.len;
|
||||||
const next_token = try number(input, input_len, 0);
|
const next_token = try number.lex(input, input_len, 0);
|
||||||
_ = next_token;
|
|
||||||
|
|
||||||
std.debug.print("tokenize :D {s}\n", .{input});
|
if (next_token) |tuple| {
|
||||||
|
const t = tuple[0];
|
||||||
|
|
||||||
|
std.debug.print("{s}\n", .{t.value});
|
||||||
|
} else {
|
||||||
|
std.debug.print("no token found :c", .{});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,3 +16,8 @@ pub const Token = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const LexError = error{
|
||||||
|
LeadingZero,
|
||||||
|
Incomplete,
|
||||||
|
};
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
pub fn is_decimal_digit(c: u8) bool {
|
pub fn is_decimal_digit(c: u8) bool {
|
||||||
return '0' <= c and c <= '9';
|
return '0' <= c and c <= '9';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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