#include "tree_sitter/parser.h"
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <wctype.h>
#ifdef NDEBUG
#error "expected assertions to be enabled"
#endif
#ifndef __FILE_NAME__
#define __FILE_NAME__ __FILE__
#endif
#ifdef __GNUC__
#define unused_attr __attribute__((unused))
#else
#define unused_attr
#endif
#ifdef __wasm__
#define assertf(...) (void)0;
#else
#ifndef fprintf_s
#define fprintf_s fprintf
#endif
#ifdef DEBUG_PRINT
#define dbg_print(...) \
do { \
fprintf_s(stderr, " \033[96;1mparse: \033[0m"); \
fprintf_s(stderr, __VA_ARGS__); \
} while (0)
#else
#define dbg_print(...)
#endif
#define panic(...) \
do { \
fprintf_s(stderr, "panic at %s:%d: ", __FILE_NAME__, __LINE__); \
fprintf_s(stderr, __VA_ARGS__); \
fprintf_s(stderr, "\n"); \
exit(1); \
} while (0);
#define assertf(condition, ...) \
do { \
if (__builtin_expect(!(condition), 0)) { \
panic(__VA_ARGS__); \
} \
} while (0);
#ifndef __GNUC__
#define __builtin_expect(a, b) a
#endif
#endif
#define SBYTES sizeof(Scanner)
enum TokenType {
INDENT,
DEDENT,
NEWLINE,
TEXT,
ERROR_RECOVERY,
TOKEN_TYPE_END,
};
unused_attr static inline void assert_valid_token(const TSSymbol sym) {
assertf(sym >= INDENT && sym < TOKEN_TYPE_END, "invalid symbol %d", sym);
}
typedef struct Scanner {
uint32_t prev_indent;
uint16_t advance_brace_count;
bool has_seen_eof;
} Scanner;
void *tree_sitter_just_external_scanner_create(void) {
Scanner *ptr = (Scanner *)calloc(SBYTES, 1);
assertf(ptr, "tree_sitter_just_external_scanner_create: out of memory");
return ptr;
}
void tree_sitter_just_external_scanner_destroy(void *payload) {
assertf(payload, "got null payload at destroy");
free(payload);
}
unsigned tree_sitter_just_external_scanner_serialize(void *payload,
char *buffer) {
assertf(SBYTES < TREE_SITTER_SERIALIZATION_BUFFER_SIZE,
"invalid scanner size");
memcpy(buffer, payload, SBYTES);
return SBYTES;
}
void tree_sitter_just_external_scanner_deserialize(void *payload,
const char *buffer,
unsigned length) {
Scanner *ptr = (Scanner *)payload;
if (length == 0) {
ptr->prev_indent = 0;
ptr->has_seen_eof = false;
return;
}
memcpy(ptr, buffer, SBYTES);
}
static inline void advance(TSLexer *lexer) { lexer->advance(lexer, false); }
static inline void skip(TSLexer *lexer) { lexer->advance(lexer, true); }
static bool handle_eof(TSLexer *lexer, Scanner *state,
const bool *valid_symbols) {
assertf(lexer->eof(lexer), "expected EOF");
lexer->mark_end(lexer);
if (valid_symbols[DEDENT]) {
lexer->result_symbol = DEDENT;
return true;
}
if (valid_symbols[NEWLINE]) {
if (state->has_seen_eof) {
return false;
}
lexer->result_symbol = NEWLINE;
state->has_seen_eof = true;
return true;
}
return false;
}
bool tree_sitter_just_external_scanner_scan(void *payload, TSLexer *lexer,
const bool *valid_symbols) {
Scanner *scanner = (Scanner *)(payload);
if (lexer->eof(lexer)) {
return handle_eof(lexer, scanner, valid_symbols);
}
if (valid_symbols[NEWLINE]) {
bool escape = false;
if (lexer->lookahead == '\\') {
escape = true;
skip(lexer);
}
bool eol_found = false;
while (iswspace(lexer->lookahead)) {
if (lexer->lookahead == '\n') {
skip(lexer);
eol_found = true;
break;
}
skip(lexer);
}
if (eol_found && !escape) {
lexer->result_symbol = NEWLINE;
return true;
}
}
if (valid_symbols[INDENT] || valid_symbols[DEDENT]) {
while (!lexer->eof(lexer) && isspace(lexer->lookahead)) {
switch (lexer->lookahead) {
case '\n':
if (valid_symbols[INDENT]) {
return false;
}
case '\t':
case ' ':
skip(lexer);
break;
default:
return false;
}
}
if (lexer->eof(lexer)) {
return handle_eof(lexer, scanner, valid_symbols);
}
uint32_t indent = lexer->get_column(lexer);
if (indent > scanner->prev_indent && valid_symbols[INDENT] &&
scanner->prev_indent == 0) {
lexer->result_symbol = INDENT;
scanner->prev_indent = indent;
return true;
}
if (indent < scanner->prev_indent && valid_symbols[DEDENT] && indent == 0) {
lexer->result_symbol = DEDENT;
scanner->prev_indent = indent;
return true;
}
}
if (valid_symbols[TEXT]) {
if (lexer->get_column(lexer) == scanner->prev_indent &&
(lexer->lookahead == '\n' || lexer->lookahead == '@' ||
lexer->lookahead == '-')) {
return false;
}
bool advanced_once = false;
while (lexer->lookahead == '{' && scanner->advance_brace_count > 0 &&
!lexer->eof(lexer)) {
scanner->advance_brace_count--;
advance(lexer);
advanced_once = true;
}
while (1) {
if (lexer->eof(lexer)) {
return handle_eof(lexer, scanner, valid_symbols);
}
while (!lexer->eof(lexer) && lexer->lookahead != '\n' &&
lexer->lookahead != '{') {
if (lexer->lookahead == '#' && !advanced_once) {
advance(lexer);
if (lexer->lookahead == '!') {
return false;
}
}
advance(lexer);
advanced_once = true;
}
if (lexer->lookahead == '\n' || lexer->eof(lexer)) {
lexer->mark_end(lexer);
lexer->result_symbol = TEXT;
if (advanced_once) {
return true;
}
if (lexer->eof(lexer)) {
return handle_eof(lexer, scanner, valid_symbols);
}
advance(lexer);
} else if (lexer->lookahead == '{') {
lexer->mark_end(lexer);
advance(lexer);
if (lexer->eof(lexer) ||
lexer->lookahead == '\n') { lexer->mark_end(lexer);
lexer->result_symbol = TEXT;
return advanced_once;
}
if (lexer->lookahead == '{') {
advance(lexer);
while (lexer->lookahead == '{') { scanner->advance_brace_count++;
advance(lexer);
}
while (!lexer->eof(lexer) && lexer->lookahead != '\n') {
advance(lexer);
if (lexer->lookahead == '}') {
advance(lexer);
if (lexer->lookahead == '}') {
lexer->result_symbol = TEXT;
return advanced_once;
}
}
}
if (!advanced_once) {
return false;
}
}
}
}
}
return false;
}