Files
wehub-resource-sync 41cb1c0170
OpenSSF Scorecard / scorecard (push) Failing after 0s
DCO / dco (push) Failing after 0s
CodeQL SAST / analyze (push) Failing after 1s
Deploy Pages / deploy (push) Failing after 1s
chore: import upstream snapshot with attribution
2026-07-13 12:28:05 +08:00

155 lines
4.1 KiB
C
Generated

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "tree_sitter/parser.h"
enum TokenType {
HERE_STRING_BODY,
};
// a hand written string implmentation
// data[0], data[1], ..., data[len-1] is the content of string
// data[len] is `\0` for typical string `char*` compatibility
// So 0 <= len < cap
typedef struct {
size_t len;
size_t cap;
char *data;
} String;
static void check_alloc(void *ptr) {
if (ptr == NULL) {
#ifndef __wasm32__
fprintf(stderr, "Scanner: Failed to allocate memory\n");
#endif
abort();
}
}
static String string_new(void) {
size_t init_len = 16;
// (init_len + 1) for null terminator
size_t cap = init_len + 1;
void *tmp = calloc(1, sizeof(char) * cap);
check_alloc(tmp);
return (String){.cap = cap, .len = 0, .data = tmp};
}
static void string_resize(String *str, size_t new_cap) {
void *block = realloc(str->data, new_cap * sizeof(char));
check_alloc(block);
str->data = block;
str->cap = new_cap;
memset(str->data + str->len, 0, (new_cap - str->len) * sizeof(char));
}
static void string_push(String *str, int32_t elem) {
if (str->len + sizeof(elem) >= str->cap) {
// str->cap * 2 + 1 > str->len + sizeof(elem) always holds
// as str->cap > 16
string_resize(str, str->cap * 2 + 1);
}
// NOTE: we don't consider little-endian/big-endian here
// the character in string is only for compare.
// They only need to be store in consistent way
memcpy(str->data + str->len, &elem, sizeof(elem));
str->len += sizeof(elem);
}
static void string_free(String *str) {
if (str->data != NULL) {
free(str->data);
str->data = NULL;
str->len = 0;
str->cap = 0;
}
}
static void string_clear(String *str) {
memset(str->data, 0, str->len * sizeof(char));
str->len = 0;
}
static void advance(TSLexer *lexer) {
lexer->advance(lexer, false);
}
static void skip(TSLexer *lexer) {
lexer->advance(lexer, true);
}
// NOTE: only "\n" is allowed as newline here,
// It implies that "\r" can also be terminator.
static bool isnewline(int32_t chr) {
return chr == '\n';
}
// `read_line` read strings until a newline or EOF
static void read_line(String *str, TSLexer *lexer) {
while (!isnewline(lexer->lookahead) && !lexer->eof(lexer)) {
string_push(str, lexer->lookahead);
advance(lexer);
}
}
// Suppose terminator is `T`, newline (\n) is `$`,
// It should accept "#<<T$T" or "#<<T$...$T", where `...`
// is the string content.
static bool scan(TSLexer *lexer, const bool *valid_symbols) {
if (!valid_symbols[HERE_STRING_BODY]) {
return false;
}
String terminator = string_new();
read_line(&terminator, lexer);
if (lexer->eof(lexer)) {
string_free(&terminator);
return false;
}
// skip `\n`
skip(lexer);
String current_line = string_new();
while (true) {
read_line(&current_line, lexer);
if (strcmp(terminator.data, current_line.data) == 0) {
lexer->result_symbol = HERE_STRING_BODY;
string_free(&terminator);
string_free(&current_line);
return true;
}
if (lexer->eof(lexer)) {
string_free(&terminator);
string_free(&current_line);
return false;
}
string_clear(&current_line);
// skip `\n`
skip(lexer);
}
}
void *tree_sitter_racket_external_scanner_create() {
return NULL;
}
unsigned tree_sitter_racket_external_scanner_serialize(void *payload,
char *buffer) {
return 0;
}
void tree_sitter_racket_external_scanner_deserialize(void *payload,
const char *buffer,
unsigned length) {
}
bool tree_sitter_racket_external_scanner_scan(void *payload,
TSLexer *lexer,
const bool *valid_symbols) {
return scan(lexer, valid_symbols);
}
void tree_sitter_racket_external_scanner_destroy(void *payload) {
}