Compare commits

...

3 Commits

Author SHA1 Message Date
26f5fed321 chore: small changes 2024-11-17 08:08:57 -05:00
8dccf94ad5 feat: lex floating point numbers with scientific notation 2024-11-17 07:56:29 -05:00
b0aec04235 feat: lex scientific number 2024-11-17 07:54:12 -05:00
4 changed files with 104 additions and 6 deletions

View File

@ -24,7 +24,8 @@ Now in Zig!
## v0.0.1
- [ ]
- [x] Lex integers & floating point numbers
- [ ]

View File

@ -10,12 +10,12 @@
// This is a [Semantic Version](https://semver.org/).
// In a future version of Zig it will be used for package deduplication.
.version = "0.0.0",
.version = "0.0.1",
// This field is optional.
// This is currently advisory only; Zig does not yet do anything
// with this value.
//.minimum_zig_version = "0.11.0",
.minimum_zig_version = "0.13.0",
// This field is optional.
// Each dependency must either provide a `url` and `hash`, or a `path`.

View File

@ -110,7 +110,7 @@ fn integer(input: []const u8, cap: usize, start: usize) LexError!?LexReturn {
},
// if an `e` (exponential notiation) is found, lex that
'e' => {
return null;
return scientific(input, cap, start, last_pos);
},
// otherwise return the current integer
else => {
@ -131,8 +131,8 @@ fn integer(input: []const u8, cap: usize, start: usize) LexError!?LexReturn {
///
/// token_start: the position the current token started at
/// decimal_point: the position of the decimal point `.`
fn floating_point(input: []const u8, cap: usize, token_start: usize, decimal_point: usize) LexError!?LexReturn {
var current_pos = decimal_point + 1;
fn floating_point(input: []const u8, cap: usize, token_start: usize, period_pos: usize) LexError!?LexReturn {
var current_pos = period_pos + 1;
// there should be at least 1 digit after the period
if (current_pos >= cap or !utils.is_decimal_digit(input[current_pos])) {
@ -146,6 +146,12 @@ fn floating_point(input: []const u8, cap: usize, token_start: usize, decimal_poi
current_pos += 1;
}
// check if the current character is a `e`,
// if so lex a scientific number
if (current_pos < cap and input[current_pos] == 'e') {
return scientific(input, cap, token_start, current_pos);
}
// return the matched fp number
return .{
Token.init(input[token_start..current_pos], TokenType.Float, token_start),
@ -153,6 +159,38 @@ fn floating_point(input: []const u8, cap: usize, token_start: usize, decimal_poi
};
}
/// exp_pos is the position at the `e` character
fn scientific(input: []const u8, cap: usize, token_start: usize, exp_pos: usize) LexError!?LexReturn {
var current_pos = exp_pos + 1;
// expect `+` or `-`
if (current_pos >= cap) {
return LexError.IncompleteScientificNumber;
}
const sign_char = input[current_pos];
if (sign_char != '+' and sign_char != '-') {
return LexError.IncompleteScientificNumber;
}
current_pos += 1;
const digits_start = current_pos;
// lex at least 1 digit
while (current_pos < cap and utils.is_decimal_digit(input[current_pos])) {
current_pos += 1;
}
// if there is no difference, no extra digits were lexed.
if (digits_start == current_pos) {
return LexError.IncompleteScientificNumber;
}
// return the scientific number
return .{
Token.init(input[token_start..current_pos], TokenType.Float, token_start),
current_pos,
};
}
test "int lexer 1" {
const input = "322 ";
const result = try integer(input, input.len, 0);
@ -393,3 +431,61 @@ test "should fail on incomplete fp number" {
try std.testing.expect(false);
}
test "should lex scientific number" {
const input = "42e+3";
const result = try lex(input, input.len, 0);
if (result) |tuple| {
const r = tuple[0];
try std.testing.expectEqualDeep("42e+3", r.value);
} else {
try std.testing.expect(false);
}
}
test "should fail on incomplete scientific number" {
const input = "123e";
const result = lex(input, input.len, 0) catch |err| {
try std.testing.expect(err == token.LexError.IncompleteScientificNumber);
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 fail on incomplete scientific number 2" {
const input = "123e+";
const result = lex(input, input.len, 0) catch |err| {
try std.testing.expect(err == token.LexError.IncompleteScientificNumber);
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 floating scientific number" {
const input = "0.58e+3";
const result = try lex(input, input.len, 0);
if (result) |tuple| {
const r = tuple[0];
try std.testing.expectEqualDeep("0.58e+3", r.value);
} else {
try std.testing.expect(false);
}
}

View File

@ -21,4 +21,5 @@ pub const LexError = error{
LeadingZero,
Incomplete,
IncompleteFloatingNumber,
IncompleteScientificNumber,
};