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

196 lines
5.6 KiB
C
Generated

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* This file is initially inspired by the one from
https://github.com/tree-sitter/tree-sitter-python/blob/1030ed7f0df3c7c0c80b23242f12d2f60e11c79a/src/scanner.c
*/
/* See
https://tree-sitter.github.io/tree-sitter/creating-parsers#external-scanners
for how the file works. */
#include "tree_sitter/array.h"
#include "tree_sitter/parser.h"
#include <stdint.h>
enum TokenType {
/* Triple Quoted String, as per https://www.erlang.org/eeps/eep-0064
*
* Start is three or more `"`, may only be followed by whitespace to end of
* line End is three or more `"`, may only be preceded by whitespace from
* start of line The starting and ending `"` count must be the same
*/
TQ_STRING,
/* A TQ_STRING preceded by /~[sSbB]?/ */
TQ_SIGIL_STRING,
/* Will only be in valid_symbols when in error recovery mode */
ERROR_SENTINEL
};
static inline void advance(TSLexer* lexer) {
lexer->advance(lexer, false);
/* fprintf(stderr, "Scanner advance:lookahead: '%c'.\n", lexer->lookahead); */
}
static inline void skip(TSLexer* lexer) {
lexer->advance(lexer, true);
/* fprintf(stderr, "Scanner skip:lookahead: '%c'.\n", lexer->lookahead); */
}
/* Note: writing to stderr will show up in tests, e.g. */
/* make gen && npm run test -- --filter "quoted binary explicit sigil in tq
* string, 5 quotes, with 3 inside" */
/* static inline void dump_la(TSLexer* lexer) { */
/* fprintf(stderr, "Scanner lookahead: '%c'.\n", lexer->lookahead); */
/* } */
static inline bool is_whitespace(TSLexer* lexer) {
return (
/* The test is based on the ?WHITE_SPACE/1 macro in
elp_scan.erl, and matches the one in grammar.js */
(lexer->lookahead >= 0x01 && lexer->lookahead <= 0x20) ||
(lexer->lookahead >= 0x80 && lexer->lookahead <= 0xA0));
}
bool tree_sitter_erlang_external_scanner_scan(
void* unused_payload,
TSLexer* lexer,
const bool* valid_symbols) {
(void)unused_payload;
if (valid_symbols[TQ_STRING] || valid_symbols[TQ_SIGIL_STRING]) {
/* Skip any leading whitespace */
while (is_whitespace(lexer)) {
skip(lexer);
}
bool is_sigil_string = false;
if (valid_symbols[TQ_SIGIL_STRING]) {
/* Look for /~[sSbB]?/ */
if (lexer->lookahead == '~') {
is_sigil_string = true;
advance(lexer);
switch (lexer->lookahead) {
case 's':
case 'S':
case 'b':
case 'B':
advance(lexer);
break;
case '"':
break;
default:
return false;
}
}
}
/* TODO: break into functions */
uint16_t delimiter_count = 0;
if (lexer->lookahead == '"') {
advance(lexer);
if (lexer->lookahead == '"') {
advance(lexer);
if (lexer->lookahead == '"') {
advance(lexer);
/* We may have seen the start of a tq string, look for the rest */
delimiter_count = 3;
while (lexer->lookahead == '"') {
delimiter_count++;
advance(lexer);
}
/* skip whitespace to end of line */
while (lexer->lookahead != '\n' && is_whitespace(lexer)) {
advance(lexer);
}
if (lexer->lookahead == '\n') {
advance(lexer);
} else {
return false;
}
for (;;) {
/* Look for end marker, skipping chars in the meantime */
/* newline, whitespace, same number of '"' at end */
if (lexer->lookahead == '\n') {
advance(lexer);
/* skip whitespace to first '"' */
while (lexer->lookahead != '\n' && is_whitespace(lexer)) {
advance(lexer);
}
/* match same number of final '"' */
uint16_t check = delimiter_count;
while (check > 0) {
if (lexer->lookahead != '"') {
break;
} else {
advance(lexer);
}
check--;
}
if (check <= 0) {
lexer->mark_end(lexer);
if (is_sigil_string) {
lexer->result_symbol = TQ_SIGIL_STRING;
} else {
lexer->result_symbol = TQ_STRING;
}
return true;
}
} else {
if (lexer->eof(lexer)) {
return false;
} else {
advance(lexer);
}
}
}
}
}
}
}
return false;
}
unsigned tree_sitter_erlang_external_scanner_serialize(
void* unused_payload,
char* unused_buffer) {
(void)unused_payload;
(void)unused_buffer;
return 0;
}
void tree_sitter_erlang_external_scanner_deserialize(
void* unused_payload,
const char* unused_buffer,
unsigned unused_length) {
(void)unused_payload;
(void)unused_buffer;
(void)unused_length;
}
void* tree_sitter_erlang_external_scanner_create() {
return 0;
}
void tree_sitter_erlang_external_scanner_destroy(void* unused_payload) {
(void)unused_payload;
}