I think, the single tokens' token kind value being their ASCII character value idea, could've been salvaged by using a lookup table.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 | enum TokenClass {
TOKEN_CLASS_CMP = 1 << 0,
TOKEN_CLASS_ADD = 1 << 1,
TOKEN_CLASS_MUL = 1 << 2,
TOKEN_CLASS_ASSIGN = 1 << 3,
TOKEN_CLASS_UNARY = 1 << 4,
};
const int token_class_bits[256] = {
[TOKEN_EQ] = TOKEN_CLASS_CMP,
[TOKEN_NOTEQ] = TOKEN_CLASS_CMP,
['<'] = TOKEN_CLASS_CMP,
['>'] = TOKEN_CLASS_CMP,
[TOKEN_LTEQ] = TOKEN_CLASS_CMP,
[TOKEN_GTEQ] = TOKEN_CLASS_CMP,
['+'] = TOKEN_CLASS_ADD | TOKEN_CLASS_UNARY,
['-'] = TOKEN_CLASS_ADD | TOKEN_CLASS_UNARY,
['^'] = TOKEN_CLASS_ADD,
['|'] = TOKEN_CLASS_ADD,
['*'] = TOKEN_CLASS_MUL | TOKEN_CLASS_UNARY,
['/'] = TOKEN_CLASS_MUL,
['%'] = TOKEN_CLASS_MUL,
['&'] = TOKEN_CLASS_MUL | TOKEN_CLASS_UNARY,
[TOKEN_LSHIFT] = TOKEN_CLASS_MUL,
[TOKEN_RSHIFT] = TOKEN_CLASS_MUL,
['='] = TOKEN_CLASS_ASSIGN,
[TOKEN_ADD_ASSIGN] = TOKEN_CLASS_ASSIGN,
[TOKEN_SUB_ASSIGN] = TOKEN_CLASS_ASSIGN,
[TOKEN_OR_ASSIGN] = TOKEN_CLASS_ASSIGN,
[TOKEN_AND_ASSIGN] = TOKEN_CLASS_ASSIGN,
// ...
};
bool is_cmp_op() {
return (token_class_bits[token.kind] & TOKEN_CLASS_CMP) != 0;
}
bool is_add_op() {
return (token_class_bits[token.kind] & TOKEN_CLASS_ADD) != 0;
}
bool is_mul_op() {
return (token_class_bits[token.kind] & TOKEN_CLASS_MUL) != 0;
}
bool is_assign_op() {
return (token_class_bits[token.kind] & TOKEN_CLASS_ASSIGN) != 0;
}
bool is_unary_op() {
return (token_class_bits[token.kind] & TOKEN_CLASS_UNARY) != 0;
}
|
This is pretty much the same as LuaJIT's way of implementing isdigit, isxdigit, etc:
https://github.com/LuaJIT/LuaJIT/blob/master/src/lj_char.h
Somewhere at the end of Day 6's video pervognsen was talking about error handling in the context of "push oriented" APIs, the idea sounded familiar to me, then I remembered that Rob Pike had a post about it:
https://blog.golang.org/errors-are-values