tiny.zen.math.token
Defined in math.
API (4)
Actions
Public operations.
Types and contracts
Public types and contracts.
Source
Source: lib/zen/src/math/root.zig:6
zig
pub const token = @import("token.zig");Source: lib/zen/src/math/token.zig
zig
const std = @import("std");pub const Error = error{InvalidEquation};pub const Token = union(enum) { char: u21, command: []const u8, open, close, caret, underscore, prime, end,};pub const Tokenizer = struct { source: []const u8, index: usize = 0, start: usize = 0, reason: []const u8 = "", pub fn next(self: *Tokenizer) Error!Token { while (self.index < self.source.len and isSpace(self.source[self.index])) self.index += 1; self.start = self.index; if (self.index >= self.source.len) return .end; const byte = self.source[self.index]; switch (byte) { '{' => { self.index += 1; return .open; }, '}' => { self.index += 1; return .close; }, '^' => { self.index += 1; return .caret; }, '_' => { self.index += 1; return .underscore; }, '\'' => { self.index += 1; return .prime; }, '\\' => { self.index += 1; if (self.index >= self.source.len) return self.fail("incomplete command"); if (!std.ascii.isAlphabetic(self.source[self.index])) { self.index += 1; return .{ .command = self.source[self.index - 1 .. self.index] }; } const start = self.index; while (self.index < self.source.len and std.ascii.isAlphabetic(self.source[self.index])) self.index += 1; return .{ .command = self.source[start..self.index] }; }, else => { if (byte < 0x80) { self.index += 1; return .{ .char = byte }; } const len = std.unicode.utf8ByteSequenceLength(byte) catch return self.fail("invalid utf-8"); if (self.index + len > self.source.len) return self.fail("invalid utf-8"); const decoded = std.unicode.utf8Decode(self.source[self.index .. self.index + len]) catch return self.fail("invalid utf-8"); self.index += len; return .{ .char = decoded }; }, } } fn fail(self: *Tokenizer, reason: []const u8) Error { self.reason = reason; return error.InvalidEquation; } fn isSpace(byte: u8) bool { return byte == ' ' or byte == '\t' or byte == '\n' or byte == '\r'; }};test "tokenizer splits commands scripts and characters" { var tokens = Tokenizer{ .source = "\\frac{a}{2} ^ x_\\pi \\, ω'" }; try std.testing.expectEqualStrings("frac", (try tokens.next()).command); try std.testing.expect((try tokens.next()) == .open); try std.testing.expectEqual(@as(u21, 'a'), (try tokens.next()).char); try std.testing.expect((try tokens.next()) == .close); try std.testing.expect((try tokens.next()) == .open); try std.testing.expectEqual(@as(u21, '2'), (try tokens.next()).char); try std.testing.expect((try tokens.next()) == .close); try std.testing.expect((try tokens.next()) == .caret); try std.testing.expectEqual(@as(u21, 'x'), (try tokens.next()).char); try std.testing.expect((try tokens.next()) == .underscore); try std.testing.expectEqualStrings("pi", (try tokens.next()).command); try std.testing.expectEqualStrings(",", (try tokens.next()).command); try std.testing.expectEqual(@as(u21, 'ω'), (try tokens.next()).char); try std.testing.expect((try tokens.next()) == .prime); try std.testing.expect((try tokens.next()) == .end);}test "tokenizer records token starts" { var tokens = Tokenizer{ .source = " x \\pi" }; _ = try tokens.next(); try std.testing.expectEqual(@as(usize, 2), tokens.start); _ = try tokens.next(); try std.testing.expectEqual(@as(usize, 4), tokens.start); _ = try tokens.next(); try std.testing.expectEqual(@as(usize, 7), tokens.start);}test "tokenizer rejects trailing backslash and bad utf8" { var trailing = Tokenizer{ .source = "x\\" }; _ = try trailing.next(); try std.testing.expectError(error.InvalidEquation, trailing.next()); try std.testing.expectEqualStrings("incomplete command", trailing.reason); try std.testing.expectEqual(@as(usize, 1), trailing.start); var bad = Tokenizer{ .source = &.{ 0xFF, 0x20 } }; try std.testing.expectError(error.InvalidEquation, bad.next()); try std.testing.expectEqualStrings("invalid utf-8", bad.reason); try std.testing.expectEqual(@as(usize, 0), bad.start);}Audit
| Definitions | 5 |
|---|---|
| Public names | 5 |
| Members | 13 |
| Version | 26.7.0 |
| Revision | daab053ee433 |