#ifndef TREE_SITTER_JAVASCRIPT_LITERAL_H_
#define TREE_SITTER_JAVASCRIPT_LITERAL_H_
#include "tree_sitter/parser.h"
static bool scan_character_reference(TSLexer *lexer);
static bool scan_template_escape_value(TSLexer *lexer);
static bool scan_fixed_hex_digits(TSLexer *lexer, unsigned length);
static bool scan_template_code_point(TSLexer *lexer);
static inline int hex_digit_value(int32_t c);
static inline bool is_ascii_letter(int32_t c);
static inline bool is_ascii_digit(int32_t c);
static inline bool reference_is_digit(int32_t c, bool hex);
static inline bool lexer_eof(const TSLexer *lexer);
static bool scan_template_chars(TSLexer *lexer, TSSymbol symbol) {
lexer->result_symbol = symbol;
for (bool has_content = false;; has_content = true) {
if (lexer_eof(lexer)) return false;
switch (lexer->lookahead) {
case '`':
case '\\':
if (has_content) lexer->mark_end(lexer);
return has_content;
case '$':
if (has_content) lexer->mark_end(lexer);
lexer->advance(lexer, false);
if (lexer->lookahead == '{') return has_content;
break;
default:
lexer->advance(lexer, false);
}
}
}
static bool scan_jsx_text(TSLexer *lexer, TSSymbol symbol) {
bool saw_text = false;
bool at_newline = false;
lexer->result_symbol = symbol;
while (!lexer_eof(lexer)) {
int32_t c = lexer->lookahead;
if (c == '<' || c == '>' || c == '{' || c == '}') break;
if (c == '&') {
lexer->mark_end(lexer);
if (scan_character_reference(lexer)) return saw_text;
saw_text = true;
at_newline = false;
continue;
}
bool is_space = (uint32_t)(c - '\t') <= '\r' - '\t' || c == ' ';
if (c == '\n' || c == '\r') {
at_newline = true;
} else {
at_newline &= is_space;
saw_text |= !at_newline;
}
lexer->advance(lexer, false);
}
if (saw_text) lexer->mark_end(lexer);
return saw_text;
}
static bool scan_character_reference(TSLexer *lexer) {
lexer->advance(lexer, false);
unsigned length = 0;
if (lexer->lookahead == '#') {
lexer->advance(lexer, false);
bool hex = lexer->lookahead == 'x' || lexer->lookahead == 'X';
if (hex) lexer->advance(lexer, false);
unsigned max_length = hex ? 6 : 5;
while (length < max_length && reference_is_digit(lexer->lookahead, hex)) {
lexer->advance(lexer, false);
length++;
}
} else {
while (length < 30 && is_ascii_letter(lexer->lookahead)) {
lexer->advance(lexer, false);
length++;
}
}
return length > 0 && lexer->lookahead == ';';
}
static bool scan_template_escape(TSLexer *lexer, TSSymbol symbol) {
lexer->advance(lexer, false);
if (lexer_eof(lexer) || !scan_template_escape_value(lexer)) return false;
lexer->mark_end(lexer);
lexer->result_symbol = symbol;
return true;
}
static bool scan_template_escape_value(TSLexer *lexer) {
int32_t c = lexer->lookahead;
lexer->advance(lexer, false);
switch (c) {
case '0':
return !is_ascii_digit(lexer->lookahead);
case 'x':
return scan_fixed_hex_digits(lexer, 2);
case 'u':
return lexer->lookahead == '{' ? scan_template_code_point(lexer) : scan_fixed_hex_digits(lexer, 4);
case '\r':
if (lexer->lookahead == '\n') lexer->advance(lexer, false);
return true;
default:
return !is_ascii_digit(c);
}
}
static bool scan_fixed_hex_digits(TSLexer *lexer, unsigned length) {
for (unsigned i = 0; i < length; i++) {
if (hex_digit_value(lexer->lookahead) < 0) return false;
lexer->advance(lexer, false);
}
return true;
}
static bool scan_template_code_point(TSLexer *lexer) {
lexer->advance(lexer, false);
uint32_t value = 0;
bool has_digit = false;
int digit;
while ((digit = hex_digit_value(lexer->lookahead)) >= 0) {
has_digit = true;
value = value * 16 + (unsigned)digit;
if (value > 0x10FFFF) return false;
lexer->advance(lexer, false);
}
if (!has_digit || lexer->lookahead != '}') return false;
lexer->advance(lexer, false);
return true;
}
static inline int hex_digit_value(int32_t c) {
if (is_ascii_digit(c)) return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
return -1;
}
static inline bool is_ascii_letter(int32_t c) {
return (uint32_t)((c | 0x20) - 'a') <= 'z' - 'a';
}
static inline bool reference_is_digit(int32_t c, bool hex) {
return hex ? hex_digit_value(c) >= 0 : is_ascii_digit(c);
}
static inline bool is_ascii_digit(int32_t c) {
return (uint32_t)(c - '0') <= 9;
}
static inline bool lexer_eof(const TSLexer *lexer) {
return lexer->lookahead == 0 && lexer->eof(lexer);
}
#endif