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 }