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