pub const Token = struct { start: usize, end: usize, type: Type, pub const Type = union(enum) { LeftParen, RightParen, IntegerLiteral: usize, Plus, Invalid, Eof, }; }; source: []const u8, last_end: usize = 0, pos: usize = 0, pub fn next(self: *Self) ?Token { return s: switch (self.eat() orelse return self.create(.Eof)) { '(' => self.create(.LeftParen), ')' => self.create(.RightParen), '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => |d| self.integerLiteral(d), '+' => self.create(.Plus), ' ' => { self.last_end = self.pos; continue :s (self.eat() orelse return self.create(.Eof)); }, else => self.create(.Invalid), }; } fn integerLiteral(self: *Self, first: u8) Token { var value: usize = @intCast(digitValue(first).?); while (digitValue(self.peek())) |d| { _ = self.eat(); value = value *| 10 +| d; } return self.create(.{ .IntegerLiteral = value }); } fn create(self: *Self, tajp: Token.Type) Token { const start = self.last_end; self.last_end = self.pos; return .{ .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, }; }