aboutsummaryrefslogtreecommitdiff
path: root/src/Lexer.zig
diff options
context:
space:
mode:
authorMathias Magnusson <mathias@magnusson.space>2025-06-01 01:09:37 +0200
committerMathias Magnusson <mathias@magnusson.space>2025-06-01 01:09:52 +0200
commit18cc7a9ff7e83f47e9289d2adbd15663833fefef (patch)
tree530ccbf750a55b131969db7b7caa3d75bfb18b27 /src/Lexer.zig
parenta86252879b27a4951e13aaa6a28ff7fce2505ff8 (diff)
downloadhuginn-18cc7a9ff7e83f47e9289d2adbd15663833fefef.tar.gz
capitalize Lexer.zig correctly
Diffstat (limited to 'src/Lexer.zig')
-rw-r--r--src/Lexer.zig99
1 files changed, 99 insertions, 0 deletions
diff --git a/src/Lexer.zig b/src/Lexer.zig
new file mode 100644
index 0000000..3621a1c
--- /dev/null
+++ b/src/Lexer.zig
@@ -0,0 +1,99 @@
+const std = @import("std");
+
+pub const Token = struct {
+ loc: Location,
+ type: Type,
+
+ pub const Type = enum {
+ left_paren,
+ right_paren,
+ integer_literal,
+ plus,
+ minus,
+ invalid,
+ eof,
+ };
+};
+
+pub const Location = struct {
+ start: usize,
+ end: usize,
+
+ pub fn combine(a: Location, b: Location) Location {
+ std.debug.assert(a.end <= b.start);
+ return .{ .start = @min(a.start, b.start), .end = @max(a.end, b.end) };
+ }
+
+ /// Assumes that the location comes directly from an `integer_literal` token.
+ pub fn getInt(self: Location, file_source: []const u8) u64 {
+ var value: u64 = 0;
+ for (file_source[self.start..self.end]) |c| {
+ std.debug.assert('0' <= c and c <= '9');
+ value = value * 10 + (c - '0');
+ }
+ return value;
+ }
+};
+
+source: []const u8,
+start: usize = 0,
+pos: usize = 0,
+
+pub fn next(self: *Self) ?Token {
+ self.start = self.pos;
+ return s: switch (self.eat() orelse return self.create(.eof)) {
+ '(' => self.create(.left_paren),
+ ')' => self.create(.right_paren),
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => self.integerLiteral(),
+ '+' => self.create(.plus),
+ '-' => self.create(.minus),
+ ' ' => {
+ self.start = self.pos;
+ continue :s (self.eat() orelse return self.create(.eof));
+ },
+ else => self.create(.invalid),
+ };
+}
+
+fn integerLiteral(self: *Self) Token {
+ var value: ?u64 = self.source[self.start] - '0';
+ while (digitValue(self.peek())) |v| {
+ var nxt: ?u64 = null;
+ if (value) |val|
+ if (std.math.mul(u64, val, 10) catch null) |p|
+ if (std.math.add(u64, p, v) catch null) |s| {
+ nxt = s;
+ };
+
+ value = nxt;
+ _ = self.eat();
+ }
+ return if (value != null)
+ self.create(.integer_literal)
+ else
+ self.create(.invalid);
+}
+
+fn create(self: *Self, tajp: Token.Type) Token {
+ const start = self.start;
+ return .{ .loc = .{ .start = start, .end = self.pos }, .type = tajp };
+}
+
+fn eat(self: *Self) ?u8 {
+ const token = self.peek();
+ if (token != null) self.pos += 1;
+ return token;
+}
+
+fn peek(self: *Self) ?u8 {
+ return if (self.pos < self.source.len) self.source[self.pos] else null;
+}
+
+const Self = @This();
+
+fn digitValue(c: ?u8) ?u8 {
+ return switch (c orelse return null) {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => c.? - '0',
+ else => null,
+ };
+}