lib/chant/src/lexer/punctuator.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const chant = @import("../root.zig");
2 const cursor = @import("cursor.zig");
3
4 const Kind = chant.token.Kind;
5 const Token = chant.token.Token;
6 const Error = @import("error.zig").Error;
7
8 pub fn lex(self: anytype, start: usize, column: u32) Error!Token {
9 const kind = kindAt(self) orelse return error.UnexpectedCharacter;
10 return cursor.make(self, kind, start, column);
11 }
12
13 fn kindAt(self: anytype) ?Kind {
14 const source = self.source;
15 const c = source[self.index];
16 const one = self.index + 1;
17 const two = self.index + 2;
18 const next_c: u8 = if (one < source.len) source[one] else 0;
19 const next_next: u8 = if (two < source.len) source[two] else 0;
20
21 switch (c) {
22 '(' => return cursor.take(self, .lparen, 1),
23 ')' => return cursor.take(self, .rparen, 1),
24 '{' => return cursor.take(self, .lbrace, 1),
25 '}' => return cursor.take(self, .rbrace, 1),
26 '[' => return cursor.take(self, .lbracket, 1),
27 ']' => return cursor.take(self, .rbracket, 1),
28 ';' => return cursor.take(self, .semicolon, 1),
29 ',' => return cursor.take(self, .comma, 1),
30 '?' => return cursor.take(self, .question, 1),
31 '~' => return cursor.take(self, .tilde, 1),
32 ':' => return cursor.take(self, .colon, 1),
33 '+' => return plus(self, next_c),
34 '-' => return minus(self, next_c),
35 '*' => return assignable(self, next_c, .star, .star_assign),
36 '/' => return assignable(self, next_c, .slash, .slash_assign),
37 '%' => return assignable(self, next_c, .percent, .percent_assign),
38 '&' => return ampersand(self, next_c),
39 '|' => return pipe(self, next_c),
40 '^' => return assignable(self, next_c, .caret, .caret_assign),
41 '!' => return assignable(self, next_c, .bang, .ne),
42 '=' => return assignable(self, next_c, .assign, .eq),
43 '<' => return leftAngle(self, next_c, next_next),
44 '>' => return rightAngle(self, next_c, next_next),
45 '.' => return dot(self, next_c, next_next),
46 else => return null,
47 }
48 }
49
50 fn plus(self: anytype, next_c: u8) Kind {
51 if (next_c == '+') return cursor.take(self, .plus_plus, 2);
52 if (next_c == '=') return cursor.take(self, .plus_assign, 2);
53 return cursor.take(self, .plus, 1);
54 }
55
56 fn minus(self: anytype, next_c: u8) Kind {
57 if (next_c == '-') return cursor.take(self, .minus_minus, 2);
58 if (next_c == '=') return cursor.take(self, .minus_assign, 2);
59 if (next_c == '>') return cursor.take(self, .arrow, 2);
60 return cursor.take(self, .minus, 1);
61 }
62
63 fn ampersand(self: anytype, next_c: u8) Kind {
64 if (next_c == '&') return cursor.take(self, .amp_amp, 2);
65 if (next_c == '=') return cursor.take(self, .amp_assign, 2);
66 return cursor.take(self, .amp, 1);
67 }
68
69 fn pipe(self: anytype, next_c: u8) Kind {
70 if (next_c == '|') return cursor.take(self, .pipe_pipe, 2);
71 if (next_c == '=') return cursor.take(self, .pipe_assign, 2);
72 return cursor.take(self, .pipe, 1);
73 }
74
75 fn assignable(self: anytype, next_c: u8, plain: Kind, assigned: Kind) Kind {
76 if (next_c == '=') return cursor.take(self, assigned, 2);
77 return cursor.take(self, plain, 1);
78 }
79
80 fn leftAngle(self: anytype, next_c: u8, next_next: u8) Kind {
81 if (next_c == '<' and next_next == '=') return cursor.take(self, .shl_assign, 3);
82 if (next_c == '<') return cursor.take(self, .shl, 2);
83 if (next_c == '=') return cursor.take(self, .le, 2);
84 return cursor.take(self, .lt, 1);
85 }
86
87 fn rightAngle(self: anytype, next_c: u8, next_next: u8) Kind {
88 if (next_c == '>' and next_next == '=') return cursor.take(self, .shr_assign, 3);
89 if (next_c == '>') return cursor.take(self, .shr, 2);
90 if (next_c == '=') return cursor.take(self, .ge, 2);
91 return cursor.take(self, .gt, 1);
92 }
93
94 fn dot(self: anytype, next_c: u8, next_next: u8) Kind {
95 if (next_c == '.' and next_next == '.') return cursor.take(self, .ellipsis, 3);
96 return cursor.take(self, .dot, 1);
97 }