Sources/TreeSitterScanners/lua/scanner.c
195 lines · 4559 bytes
1#include <stdio.h>
2#include "tree_sitter/alloc.h"
3#include "tree_sitter/parser.h"
4#include <wctype.h>
5
6enum TokenType {
7 BLOCK_COMMENT_START,
8 BLOCK_COMMENT_CONTENT,
9 BLOCK_COMMENT_END,
10
11 BLOCK_STRING_START,
12 BLOCK_STRING_CONTENT,
13 BLOCK_STRING_END,
14};
15
16static inline void consume(TSLexer *lexer) { lexer->advance(lexer, false); }
17
18static inline void skip(TSLexer *lexer) { lexer->advance(lexer, true); }
19
20static inline bool consume_char(char c, TSLexer *lexer) {
21 if (lexer->lookahead != c) {
22 return false;
23 }
24
25 consume(lexer);
26 return true;
27}
28
29static inline uint8_t consume_and_count_char(char c, TSLexer *lexer) {
30 uint8_t count = 0;
31 while (lexer->lookahead == c) {
32 ++count;
33 consume(lexer);
34 }
35 return count;
36}
37
38static inline void skip_whitespaces(TSLexer *lexer) {
39 while (iswspace(lexer->lookahead)) {
40 skip(lexer);
41 }
42}
43
44typedef struct {
45 char ending_char;
46 uint8_t level_count;
47} Scanner;
48
49static inline void reset_state(Scanner *scanner) {
50 scanner->ending_char = 0;
51 scanner->level_count = 0;
52}
53
54void *tree_sitter_lua_external_scanner_create() {
55 Scanner *scanner = ts_calloc(1, sizeof(Scanner));
56 return scanner;
57}
58
59void tree_sitter_lua_external_scanner_destroy(void *payload) {
60 Scanner *scanner = (Scanner *)payload;
61 ts_free(scanner);
62}
63
64unsigned tree_sitter_lua_external_scanner_serialize(void *payload, char *buffer) {
65 Scanner *scanner = (Scanner *)payload;
66 buffer[0] = scanner->ending_char;
67 buffer[1] = (char)scanner->level_count;
68 return 2;
69}
70
71void tree_sitter_lua_external_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
72 Scanner *scanner = (Scanner *)payload;
73 if (length == 0) return;
74 scanner->ending_char = buffer[0];
75 if (length == 1) return;
76 scanner->level_count = buffer[1];
77}
78
79static bool scan_block_start(Scanner *scanner, TSLexer *lexer) {
80 if (consume_char('[', lexer)) {
81 uint8_t level = consume_and_count_char('=', lexer);
82
83 if (consume_char('[', lexer)) {
84 scanner->level_count = level;
85 return true;
86 }
87 }
88
89 return false;
90}
91
92static bool scan_block_end(Scanner *scanner, TSLexer *lexer) {
93 if (consume_char(']', lexer)) {
94 uint8_t level = consume_and_count_char('=', lexer);
95
96 if (scanner->level_count == level && consume_char(']', lexer)) {
97 return true;
98 }
99 }
100
101 return false;
102}
103
104static bool scan_block_content(Scanner *scanner, TSLexer *lexer) {
105 while (lexer->lookahead != 0) {
106 if (lexer->lookahead == ']') {
107 lexer->mark_end(lexer);
108
109 if (scan_block_end(scanner, lexer)) {
110 return true;
111 }
112 } else {
113 consume(lexer);
114 }
115 }
116
117 return false;
118}
119
120static bool scan_comment_start(Scanner *scanner, TSLexer *lexer) {
121 if (consume_char('-', lexer) && consume_char('-', lexer)) {
122 lexer->mark_end(lexer);
123
124 if (scan_block_start(scanner, lexer)) {
125 lexer->mark_end(lexer);
126 lexer->result_symbol = BLOCK_COMMENT_START;
127 return true;
128 }
129 }
130
131 return false;
132}
133
134static bool scan_comment_content(Scanner *scanner, TSLexer *lexer) {
135 if (scanner->ending_char == 0) { // block comment
136 if (scan_block_content(scanner, lexer)) {
137 lexer->result_symbol = BLOCK_COMMENT_CONTENT;
138 return true;
139 }
140
141 return false;
142 }
143
144 while (lexer->lookahead != 0) {
145 if (lexer->lookahead == scanner->ending_char) {
146 reset_state(scanner);
147 lexer->result_symbol = BLOCK_COMMENT_CONTENT;
148 return true;
149 }
150
151 consume(lexer);
152 }
153
154 return false;
155}
156
157bool tree_sitter_lua_external_scanner_scan(void *payload, TSLexer *lexer, const bool *valid_symbols) {
158 Scanner *scanner = (Scanner *)payload;
159
160 if (valid_symbols[BLOCK_STRING_END] && scan_block_end(scanner, lexer)) {
161 reset_state(scanner);
162 lexer->result_symbol = BLOCK_STRING_END;
163 return true;
164 }
165
166 if (valid_symbols[BLOCK_STRING_CONTENT] && scan_block_content(scanner, lexer)) {
167 lexer->result_symbol = BLOCK_STRING_CONTENT;
168 return true;
169 }
170
171 if (valid_symbols[BLOCK_COMMENT_END] && scanner->ending_char == 0 && scan_block_end(scanner, lexer)) {
172 reset_state(scanner);
173 lexer->result_symbol = BLOCK_COMMENT_END;
174 return true;
175 }
176
177 if (valid_symbols[BLOCK_COMMENT_CONTENT] && scan_comment_content(scanner, lexer)) {
178 return true;
179 }
180
181 skip_whitespaces(lexer);
182
183 if (valid_symbols[BLOCK_STRING_START] && scan_block_start(scanner, lexer)) {
184 lexer->result_symbol = BLOCK_STRING_START;
185 return true;
186 }
187
188 if (valid_symbols[BLOCK_COMMENT_START]) {
189 if (scan_comment_start(scanner, lexer)) {
190 return true;
191 }
192 }
193
194 return false;
195}