tree-sitter/test/fixtures/test_grammars/external_tokens/scanner.c
Nia f09dc3cf46
fix(wasm): fix alias map size computation
This fixes a crash where parsing with certain languages can lead to a crash due to how the alias map was allocated and laid out in wasm memory
2025-09-18 18:34:27 -04:00

121 lines
2.9 KiB
C

#include "tree_sitter/alloc.h"
#include "tree_sitter/parser.h"
enum {
percent_string,
percent_string_start,
percent_string_end
};
typedef struct {
int32_t open_delimiter;
int32_t close_delimiter;
uint32_t depth;
} Scanner;
void *tree_sitter_external_tokens_external_scanner_create() {
Scanner *scanner = ts_malloc(sizeof(Scanner));
*scanner = (Scanner) {
.open_delimiter = 0,
.close_delimiter = 0,
.depth = 0
};
return scanner;
}
void tree_sitter_external_tokens_external_scanner_destroy(void *payload) {
ts_free(payload);
}
unsigned tree_sitter_external_tokens_external_scanner_serialize(
void *payload,
char *buffer
) { return 0; }
void tree_sitter_external_tokens_external_scanner_deserialize(
void *payload,
const char *buffer,
unsigned length
) {}
bool tree_sitter_external_tokens_external_scanner_scan(
void *payload, TSLexer *lexer, const bool *valid_symbols) {
Scanner *scanner = payload;
if (valid_symbols[percent_string]) {
while (lexer->lookahead == ' ' ||
lexer->lookahead == '\t' ||
lexer->lookahead == '\n' ||
lexer->lookahead == '\r') {
lexer->advance(lexer, true);
}
if (lexer->lookahead != '%') return false;
lexer->advance(lexer, false);
switch (lexer->lookahead) {
case '(':
scanner->open_delimiter = '(';
scanner->close_delimiter = ')';
scanner->depth = 1;
break;
case '[':
scanner->open_delimiter = '[';
scanner->close_delimiter = ']';
scanner->depth = 1;
break;
case '{':
scanner->open_delimiter = '{';
scanner->close_delimiter = '}';
scanner->depth = 1;
break;
default:
return false;
}
lexer->advance(lexer, false);
for (;;) {
if (scanner->depth == 0) {
lexer->log(lexer, "Found a percent string");
lexer->result_symbol = percent_string;
return true;
}
if (lexer->lookahead == scanner->open_delimiter) {
scanner->depth++;
} else if (lexer->lookahead == scanner->close_delimiter) {
scanner->depth--;
} else if (lexer->lookahead == '#') {
lexer->advance(lexer, false);
if (lexer->lookahead == '{') {
lexer->advance(lexer, false);
lexer->result_symbol = percent_string_start;
return true;
}
}
lexer->advance(lexer, false);
}
} else if (valid_symbols[percent_string_end]) {
if (lexer->lookahead != '}') return false;
lexer->advance(lexer, false);
for (;;) {
if (scanner->depth == 0) {
lexer->result_symbol = percent_string_end;
return true;
}
if (lexer->lookahead == scanner->open_delimiter) {
scanner->depth++;
} else if (lexer->lookahead == scanner->close_delimiter) {
scanner->depth--;
}
lexer->advance(lexer, false);
}
}
return false;
}