lib/chant/src/lexer/literal.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const chant = @import("../root.zig");
2 const cursor = @import("cursor.zig");
3
4 const Token = chant.token.Token;
5 const Error = @import("error.zig").Error;
6
7 pub fn lex(self: anytype, start: usize, column: u32) Error!?Token {
8 if (self.source.len >= self.index + 3 and self.source[self.index] == 'u' and self.source[self.index + 1] == '8') {
9 return switch (self.source[self.index + 2]) {
10 '"' => try string(self, start, column, 2),
11 '\'' => try character(self, start, column, 2),
12 else => null,
13 };
14 }
15 return switch (self.source[self.index]) {
16 '"' => try string(self, start, column, 0),
17 '\'' => try character(self, start, column, 0),
18 else => null,
19 };
20 }
21
22 fn string(self: anytype, start: usize, column: u32, prefix_len: usize) Error!Token {
23 self.index += prefix_len + 1;
24 while (true) {
25 if (self.index >= self.source.len) return error.UnterminatedString;
26 const c = self.source[self.index];
27 if (c == '\n') return error.UnterminatedString;
28 if (c == '\\') {
29 if (!takeEscape(self)) return error.UnterminatedString;
30 continue;
31 }
32 self.index += 1;
33 if (c == '"') break;
34 }
35 return cursor.make(self, .string, start, column);
36 }
37
38 fn character(self: anytype, start: usize, column: u32, prefix_len: usize) Error!Token {
39 self.index += prefix_len + 1;
40 while (true) {
41 if (self.index >= self.source.len) return error.UnterminatedCharacter;
42 const c = self.source[self.index];
43 if (c == '\n') return error.UnterminatedCharacter;
44 if (c == '\\') {
45 if (!takeEscape(self)) return error.UnterminatedCharacter;
46 continue;
47 }
48 self.index += 1;
49 if (c == '\'') break;
50 }
51 return cursor.make(self, .character, start, column);
52 }
53
54 fn takeEscape(self: anytype) bool {
55 self.index += 1;
56 if (self.index >= self.source.len) return false;
57 self.index += 1;
58 return true;
59 }