mirror of https://github.com/Wilfred/difftastic/
converting scanner.cc to scanner.c
parent
7305b7b4c0
commit
222053dfd8
File diff suppressed because it is too large
Load Diff
@ -1,785 +0,0 @@
|
||||
#include <tree_sitter/parser.h>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <queue>
|
||||
#include <regex>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using std::vector;
|
||||
using std::memcpy;
|
||||
using std::regex;
|
||||
|
||||
enum TokenType {
|
||||
START_DELIMITER,
|
||||
END_DELIMITER,
|
||||
STRING_CONTENT,
|
||||
STRING_SINGLE_QUOTED_CONTENT,
|
||||
STRING_QQ_QUOTED_CONTENT,
|
||||
STRING_DOUBLE_QUOTED_CONTENT,
|
||||
START_DELIMITER_QW,
|
||||
ELEMENT_IN_QW,
|
||||
END_DELIMITER_QW,
|
||||
START_DELIMITER_REGEX,
|
||||
REGEX_PATTERN,
|
||||
END_DELIMITER_REGEX,
|
||||
START_DELIMITER_SEARCH_REPLACE,
|
||||
SEARCH_REPLACE_CONTENT,
|
||||
SEPARATOR_DELIMITER_SEARCH_REPLACE,
|
||||
END_DELIMITER_SEARCH_REPLACE,
|
||||
START_DELIMITER_TRANSLITERATION,
|
||||
TRANSLITERATION_CONTENT,
|
||||
SEPARATOR_DELIMITER_TRANSLITERATION,
|
||||
END_DELIMITER_TRANSLITERATION,
|
||||
IMAGINARY_HEREDOC_START,
|
||||
HEREDOC_START_IDENTIFIER,
|
||||
HEREDOC_CONTENT,
|
||||
HEREDOC_END_IDENTIFIER,
|
||||
POD_CONTENT,
|
||||
};
|
||||
|
||||
struct Delimiter {
|
||||
|
||||
int32_t get_end_delimiter() {
|
||||
return end_delimiter;
|
||||
}
|
||||
|
||||
int32_t end_delimiter;
|
||||
};
|
||||
|
||||
struct Scanner {
|
||||
Scanner() {
|
||||
// assert(sizeof(Delimiter) == sizeof(char));
|
||||
deserialize(NULL, 0);
|
||||
}
|
||||
|
||||
unsigned serialize(char *buffer) {
|
||||
size_t no_of_bytes = 0;
|
||||
|
||||
// size_t delimiter_count = delimiter_stack.size();
|
||||
// if (delimiter_count > UINT8_MAX) delimiter_count = UINT8_MAX;
|
||||
// buffer[no_of_bytes++] = delimiter_count;
|
||||
|
||||
// if (delimiter_count > 0) {
|
||||
// memcpy(&buffer[no_of_bytes], delimiter_stack.data(), delimiter_count);
|
||||
// }
|
||||
// no_of_bytes += delimiter_count;
|
||||
|
||||
return no_of_bytes;
|
||||
}
|
||||
|
||||
void deserialize(const char *buffer, unsigned length) {
|
||||
// delimiter_stack.clear();
|
||||
|
||||
// if (length > 0) {
|
||||
// size_t no_of_bytes = 0;
|
||||
|
||||
// size_t delimiter_count = (uint8_t)buffer[no_of_bytes++];
|
||||
// delimiter_stack.resize(delimiter_count);
|
||||
// if (delimiter_count > 0) {
|
||||
// memcpy(delimiter_stack.data(), &buffer[no_of_bytes], delimiter_count);
|
||||
// }
|
||||
// no_of_bytes += delimiter_count;
|
||||
// }
|
||||
}
|
||||
|
||||
bool scan(TSLexer *lexer, const bool *valid_symbols) {
|
||||
// on ERROR, external scanner is called with all valid_symbols to be true.
|
||||
// so for our usecase we need this logic.
|
||||
// ref - https://github.com/tree-sitter/tree-sitter/issues/1128
|
||||
if (
|
||||
valid_symbols[START_DELIMITER]
|
||||
&& valid_symbols[END_DELIMITER]
|
||||
&& valid_symbols[STRING_CONTENT]
|
||||
&& valid_symbols[STRING_SINGLE_QUOTED_CONTENT]
|
||||
&& valid_symbols[STRING_QQ_QUOTED_CONTENT]
|
||||
&& valid_symbols[STRING_DOUBLE_QUOTED_CONTENT]
|
||||
&& valid_symbols[START_DELIMITER_QW]
|
||||
&& valid_symbols[END_DELIMITER_QW]
|
||||
&& valid_symbols[START_DELIMITER_REGEX]
|
||||
&& valid_symbols[REGEX_PATTERN]
|
||||
&& valid_symbols[END_DELIMITER_REGEX]
|
||||
&& valid_symbols[START_DELIMITER_SEARCH_REPLACE]
|
||||
&& valid_symbols[SEARCH_REPLACE_CONTENT]
|
||||
&& valid_symbols[SEPARATOR_DELIMITER_SEARCH_REPLACE]
|
||||
&& valid_symbols[END_DELIMITER_SEARCH_REPLACE]
|
||||
&& valid_symbols[START_DELIMITER_TRANSLITERATION]
|
||||
&& valid_symbols[TRANSLITERATION_CONTENT]
|
||||
&& valid_symbols[SEPARATOR_DELIMITER_TRANSLITERATION]
|
||||
&& valid_symbols[END_DELIMITER_TRANSLITERATION]
|
||||
&& valid_symbols[IMAGINARY_HEREDOC_START]
|
||||
&& valid_symbols[HEREDOC_START_IDENTIFIER]
|
||||
&& valid_symbols[HEREDOC_CONTENT]
|
||||
&& valid_symbols[HEREDOC_END_IDENTIFIER]
|
||||
&& valid_symbols[POD_CONTENT]
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (valid_symbols[STRING_SINGLE_QUOTED_CONTENT]) {
|
||||
|
||||
// end when you reach the final single quote '
|
||||
if (lexer->lookahead == '\'') {
|
||||
lexer->mark_end(lexer);
|
||||
advance(lexer);
|
||||
return false;
|
||||
}
|
||||
// check for escaped single quote \'
|
||||
else if (lexer->lookahead == '\\') {
|
||||
lexer->result_symbol = STRING_SINGLE_QUOTED_CONTENT;
|
||||
advance(lexer);
|
||||
|
||||
if (lexer->lookahead == '\'') {
|
||||
advance(lexer);
|
||||
}
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
|
||||
// some exit conditions
|
||||
if (!lexer->lookahead) {
|
||||
lexer->mark_end(lexer);
|
||||
return false;
|
||||
}
|
||||
|
||||
lexer->result_symbol = STRING_SINGLE_QUOTED_CONTENT;
|
||||
advance(lexer);
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: handle qqqSTRINGq; - this should throw error
|
||||
if (valid_symbols[START_DELIMITER]) {
|
||||
return parse_start_delimiter(lexer, START_DELIMITER);
|
||||
}
|
||||
|
||||
if (valid_symbols[STRING_QQ_QUOTED_CONTENT]) {
|
||||
return parse_delimited_and_interpolated_content(lexer, STRING_QQ_QUOTED_CONTENT, END_DELIMITER);
|
||||
}
|
||||
|
||||
if (valid_symbols[STRING_DOUBLE_QUOTED_CONTENT]) {
|
||||
if (lexer->lookahead == '"') {
|
||||
lexer->mark_end(lexer);
|
||||
advance(lexer);
|
||||
return false;
|
||||
}
|
||||
|
||||
// oh boy! the interpolation
|
||||
if (lexer->lookahead == '$') {
|
||||
return handle_interpolation(lexer, STRING_DOUBLE_QUOTED_CONTENT);
|
||||
}
|
||||
// escape sequences, only basic support as of now
|
||||
if (lexer->lookahead == '\\') {
|
||||
return handle_escape_sequence(lexer, STRING_DOUBLE_QUOTED_CONTENT);
|
||||
}
|
||||
|
||||
// some exit conditions
|
||||
if (!lexer->lookahead) {
|
||||
lexer->mark_end(lexer);
|
||||
return false;
|
||||
}
|
||||
|
||||
lexer->result_symbol = STRING_DOUBLE_QUOTED_CONTENT;
|
||||
advance(lexer);
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (valid_symbols[START_DELIMITER_QW]) {
|
||||
return parse_start_delimiter(lexer, START_DELIMITER_QW);
|
||||
}
|
||||
|
||||
if (valid_symbols[ELEMENT_IN_QW]) {
|
||||
run_over_spaces(lexer);
|
||||
|
||||
if (lexer->lookahead == get_end_delimiter()) {
|
||||
lexer->result_symbol = END_DELIMITER_QW;
|
||||
advance(lexer);
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
|
||||
// exit condition
|
||||
if (!lexer->lookahead) {
|
||||
lexer->mark_end(lexer);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (
|
||||
lexer->lookahead // exit condition
|
||||
&& lexer->lookahead != ' '
|
||||
&& lexer->lookahead != '\t'
|
||||
&& lexer->lookahead != '\r'
|
||||
&& lexer->lookahead != '\n'
|
||||
&& lexer->lookahead != get_end_delimiter()
|
||||
) {
|
||||
lexer->result_symbol = ELEMENT_IN_QW;
|
||||
advance(lexer);
|
||||
}
|
||||
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (valid_symbols[START_DELIMITER_REGEX]) {
|
||||
return parse_start_delimiter(lexer, START_DELIMITER_REGEX);
|
||||
}
|
||||
if (valid_symbols[REGEX_PATTERN]) {
|
||||
return parse_delimited_and_interpolated_content(lexer, REGEX_PATTERN, END_DELIMITER_REGEX);
|
||||
}
|
||||
|
||||
if (valid_symbols[START_DELIMITER_SEARCH_REPLACE]) {
|
||||
return parse_start_delimiter(lexer, START_DELIMITER_SEARCH_REPLACE);
|
||||
}
|
||||
|
||||
if (valid_symbols[SEARCH_REPLACE_CONTENT]) {
|
||||
if (lexer->lookahead == get_end_delimiter()) {
|
||||
return process_separator_delimiter(lexer, SEPARATOR_DELIMITER_SEARCH_REPLACE, END_DELIMITER_SEARCH_REPLACE);
|
||||
}
|
||||
else {
|
||||
// oh boy! the interpolation
|
||||
if (lexer->lookahead == '$') {
|
||||
return handle_interpolation(lexer, SEARCH_REPLACE_CONTENT);
|
||||
}
|
||||
// escape sequences, only basic support as of now
|
||||
if (lexer->lookahead == '\\') {
|
||||
return handle_escape_sequence(lexer, SEARCH_REPLACE_CONTENT);
|
||||
}
|
||||
|
||||
// some exit conditions
|
||||
if (!lexer->lookahead) {
|
||||
lexer->mark_end(lexer);
|
||||
return false;
|
||||
}
|
||||
|
||||
// handling nested delimiters qq { hello { from { the}}};
|
||||
if (lexer->lookahead == start_delimiter_char) {
|
||||
lexer->result_symbol = SEARCH_REPLACE_CONTENT;
|
||||
advance(lexer);
|
||||
return scan_nested_delimiters(lexer, SEARCH_REPLACE_CONTENT);
|
||||
}
|
||||
|
||||
lexer->result_symbol = SEARCH_REPLACE_CONTENT;
|
||||
advance(lexer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_symbols[START_DELIMITER_TRANSLITERATION]) {
|
||||
return parse_start_delimiter(lexer, START_DELIMITER_TRANSLITERATION);
|
||||
}
|
||||
if (valid_symbols[TRANSLITERATION_CONTENT]) {
|
||||
if (lexer->lookahead == get_end_delimiter()) {
|
||||
return process_separator_delimiter(lexer, SEPARATOR_DELIMITER_TRANSLITERATION, END_DELIMITER_TRANSLITERATION);
|
||||
}
|
||||
|
||||
// exit condition
|
||||
if (!lexer->lookahead) {
|
||||
lexer->mark_end(lexer);
|
||||
return false;
|
||||
}
|
||||
|
||||
// escape sequence
|
||||
if (lexer->lookahead == '\\') {
|
||||
lexer->result_symbol = TRANSLITERATION_CONTENT;
|
||||
advance(lexer);
|
||||
// self end delimiter
|
||||
if (lexer->lookahead == get_end_delimiter()) {
|
||||
advance(lexer);
|
||||
}
|
||||
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
|
||||
// handling nested delimiters qq { hello { from { the}}};
|
||||
if (lexer->lookahead == start_delimiter_char) {
|
||||
lexer->result_symbol = TRANSLITERATION_CONTENT;
|
||||
advance(lexer);
|
||||
return scan_nested_delimiters(lexer, TRANSLITERATION_CONTENT);
|
||||
}
|
||||
|
||||
lexer->result_symbol = TRANSLITERATION_CONTENT;
|
||||
advance(lexer);
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (valid_symbols[HEREDOC_START_IDENTIFIER]) {
|
||||
lexer->result_symbol = HEREDOC_START_IDENTIFIER;
|
||||
|
||||
std::string delimiter;
|
||||
bool allows_interpolation;
|
||||
bool found_delimiter = advance_word(lexer, delimiter, allows_interpolation);
|
||||
if (found_delimiter) {
|
||||
heredoc_identifier_queue.push(delimiter);
|
||||
heredoc_allows_interpolation.push(allows_interpolation);
|
||||
|
||||
started_heredoc = true;
|
||||
}
|
||||
|
||||
return found_delimiter;
|
||||
}
|
||||
|
||||
if (
|
||||
(valid_symbols[HEREDOC_CONTENT] || valid_symbols[IMAGINARY_HEREDOC_START])
|
||||
&& !heredoc_identifier_queue.empty()
|
||||
) {
|
||||
// another exit condition
|
||||
if (!lexer->lookahead && !started_heredoc_body) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lexer->lookahead == '\n' && !started_heredoc_body) {
|
||||
started_heredoc_body = true;
|
||||
|
||||
lexer->result_symbol = IMAGINARY_HEREDOC_START;
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (started_heredoc_body) {
|
||||
switch (lexer->lookahead) {
|
||||
case '\\': {
|
||||
if (heredoc_allows_interpolation.front()) {
|
||||
return handle_escape_sequence(lexer, HEREDOC_CONTENT);
|
||||
}
|
||||
}
|
||||
|
||||
case '$': {
|
||||
if (heredoc_allows_interpolation.front()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
case '\n': {
|
||||
skip(lexer);
|
||||
lexer->mark_end(lexer);
|
||||
// TODO: validate all possible intended heredocs properly
|
||||
if (heredoc_allows_indent.front()) {
|
||||
while (iswspace(lexer->lookahead)) {
|
||||
advance(lexer);
|
||||
}
|
||||
}
|
||||
return exit_if_heredoc_end_delimiter(lexer);
|
||||
}
|
||||
|
||||
default: {
|
||||
// exit condition
|
||||
if (!lexer->lookahead) {
|
||||
started_heredoc_body = false;
|
||||
lexer->mark_end(lexer);
|
||||
return false;
|
||||
}
|
||||
lexer->result_symbol = HEREDOC_CONTENT;
|
||||
advance(lexer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_symbols[POD_CONTENT]) {
|
||||
|
||||
while (lexer->lookahead) {
|
||||
lexer->result_symbol = POD_CONTENT;
|
||||
|
||||
// if it is =cut that marks the end of pod content
|
||||
if (lexer->lookahead == '=') {
|
||||
lexer->advance(lexer, false);
|
||||
if (lexer->lookahead == 'c') {
|
||||
lexer->advance(lexer, false);
|
||||
if (lexer->lookahead == 'u') {
|
||||
lexer->advance(lexer, false);
|
||||
if (lexer->lookahead == 't') {
|
||||
lexer->advance(lexer, false);
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
lexer->advance(lexer, false);
|
||||
}
|
||||
}
|
||||
|
||||
// or if it end of the file also, mark the end of pod content
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parse_delimited_and_interpolated_content(TSLexer *lexer, TokenType token_type, TokenType ending_delimiter) {
|
||||
if (lexer->lookahead == get_end_delimiter()) {
|
||||
lexer->result_symbol = ending_delimiter;
|
||||
advance(lexer);
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// oh boy! the interpolation
|
||||
if (lexer->lookahead == '$') {
|
||||
return handle_interpolation(lexer, token_type);
|
||||
}
|
||||
// escape sequences, only basic support as of now
|
||||
if (lexer->lookahead == '\\') {
|
||||
return handle_escape_sequence(lexer, token_type);
|
||||
}
|
||||
|
||||
if (!lexer->lookahead) {
|
||||
lexer->mark_end(lexer);
|
||||
return false;
|
||||
}
|
||||
|
||||
// handling nested delimiters qq { hello { from { the}}};
|
||||
if (lexer->lookahead == start_delimiter_char) {
|
||||
lexer->result_symbol = token_type;
|
||||
advance(lexer);
|
||||
return scan_nested_delimiters(lexer, token_type);
|
||||
}
|
||||
|
||||
lexer->result_symbol = token_type;
|
||||
advance(lexer);
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
|
||||
// shouldn't reach here
|
||||
return false;
|
||||
}
|
||||
|
||||
bool scan_nested_delimiters(TSLexer *lexer, TokenType token_type) {
|
||||
while(lexer->lookahead) {
|
||||
if (lexer->lookahead == get_end_delimiter()) {
|
||||
lexer->result_symbol = token_type;
|
||||
advance(lexer);
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
else if (lexer->lookahead == start_delimiter_char) {
|
||||
lexer->result_symbol = token_type;
|
||||
advance(lexer);
|
||||
scan_nested_delimiters(lexer, token_type);
|
||||
}
|
||||
else if (lexer->lookahead == '\\') {
|
||||
advance(lexer);
|
||||
advance(lexer);
|
||||
}
|
||||
else {
|
||||
advance(lexer);
|
||||
}
|
||||
}
|
||||
lexer->mark_end(lexer);
|
||||
return false;
|
||||
}
|
||||
|
||||
void advance(TSLexer *lexer) {
|
||||
lexer->advance(lexer, false);
|
||||
}
|
||||
|
||||
void skip(TSLexer *lexer) {
|
||||
lexer->advance(lexer, true);
|
||||
}
|
||||
|
||||
void set_end_delimiter(int32_t start_delimiter) {
|
||||
// round, angle, square, curly
|
||||
is_delimiter_enclosing = true;
|
||||
if (start_delimiter == '(') {
|
||||
end_delimiter_char = ')';
|
||||
}
|
||||
else if (start_delimiter == '<') {
|
||||
end_delimiter_char = '>';
|
||||
}
|
||||
else if (start_delimiter == '[') {
|
||||
end_delimiter_char = ']';
|
||||
}
|
||||
else if (start_delimiter == '{') {
|
||||
end_delimiter_char = '}';
|
||||
}
|
||||
else {
|
||||
is_delimiter_enclosing = false;
|
||||
end_delimiter_char = start_delimiter;
|
||||
}
|
||||
}
|
||||
|
||||
bool process_separator_delimiter(TSLexer *lexer, TokenType separator_token, TokenType end_token) {
|
||||
if (is_separator_delimiter_parsed) {
|
||||
lexer->result_symbol = end_token;
|
||||
advance(lexer);
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
lexer->result_symbol = separator_token;
|
||||
advance(lexer);
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
// if delimiter is {}, (), <>, []
|
||||
if (is_delimiter_enclosing) {
|
||||
run_over_spaces(lexer);
|
||||
|
||||
if (lexer->lookahead == start_delimiter_char) {
|
||||
lexer->result_symbol = separator_token;
|
||||
advance(lexer);
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
is_separator_delimiter_parsed = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
is_separator_delimiter_parsed = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t get_end_delimiter() {
|
||||
return end_delimiter_char;
|
||||
}
|
||||
|
||||
// Give a token type, parses the start delimiter,
|
||||
// and keeps track of it in memory.
|
||||
bool parse_start_delimiter(TSLexer *lexer, TokenType token_type) {
|
||||
run_over_spaces(lexer);
|
||||
|
||||
start_delimiter_char = lexer->lookahead;
|
||||
set_end_delimiter(start_delimiter_char);
|
||||
|
||||
// for substitute and tr/y usecase
|
||||
is_separator_delimiter_parsed = false;
|
||||
|
||||
lexer->result_symbol = token_type;
|
||||
advance(lexer);
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// runs over spaces like a champ
|
||||
void run_over_spaces(TSLexer *lexer) {
|
||||
while (iswspace(lexer->lookahead)) skip(lexer);
|
||||
}
|
||||
|
||||
// runs with the spaces using advance
|
||||
void run_with_spaces(TSLexer *lexer) {
|
||||
while (iswspace(lexer->lookahead)) advance(lexer);
|
||||
}
|
||||
|
||||
bool handle_interpolation(TSLexer *lexer, TokenType surrounding_token) {
|
||||
if (lexer->lookahead == '$') {
|
||||
|
||||
// allow $ to be last character in a regex
|
||||
if (surrounding_token == SEARCH_REPLACE_CONTENT || surrounding_token == REGEX_PATTERN) {
|
||||
advance(lexer);
|
||||
run_with_spaces(lexer);
|
||||
if (lexer->lookahead == get_end_delimiter()) {
|
||||
lexer->result_symbol = surrounding_token;
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool handle_escape_sequence(TSLexer *lexer, TokenType surrounding_token) {
|
||||
// escape sequences, only basic support as of now
|
||||
if (lexer->lookahead == '\\') {
|
||||
advance(lexer);
|
||||
// also, self end delimiter will be treated as string
|
||||
if (
|
||||
lexer->lookahead == 't' || lexer->lookahead == 'n' || lexer->lookahead == 'r' || lexer->lookahead == 'f' || lexer->lookahead == 'b' || lexer->lookahead == 'a' || lexer->lookahead == 'e'
|
||||
) {
|
||||
// advance(lexer);
|
||||
lexer->mark_end(lexer);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
lexer->result_symbol = surrounding_token;
|
||||
advance(lexer);
|
||||
lexer->mark_end(lexer);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool handle_nested_delimiters() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume a "word" in POSIX parlance, and returns it unquoted.
|
||||
*
|
||||
* This is an approximate implementation that doesn't deal with any
|
||||
* POSIX-mandated substitution, and assumes the default value for
|
||||
* IFS.
|
||||
*/
|
||||
bool advance_word(TSLexer *lexer, std::string& unquoted_word, bool& allows_interpolation) {
|
||||
bool empty = true;
|
||||
bool has_space_before = false;
|
||||
allows_interpolation = true;
|
||||
|
||||
// <<~EOF
|
||||
if (lexer->lookahead == '~') {
|
||||
heredoc_allows_indent.push(true);
|
||||
advance(lexer);
|
||||
}
|
||||
else {
|
||||
heredoc_allows_indent.push(false);
|
||||
}
|
||||
|
||||
// <<\EOF, <<~\EOF
|
||||
if (lexer->lookahead == '\\') {
|
||||
allows_interpolation = false;
|
||||
advance(lexer);
|
||||
}
|
||||
|
||||
|
||||
// run over the spaces
|
||||
if (iswspace(lexer->lookahead)) {
|
||||
run_over_spaces(lexer);
|
||||
has_space_before = true;
|
||||
}
|
||||
|
||||
int32_t quote = 0;
|
||||
if (
|
||||
lexer->lookahead == '\''
|
||||
|| lexer->lookahead == '"'
|
||||
|| lexer->lookahead == '`'
|
||||
) {
|
||||
allows_interpolation = (lexer->lookahead == '\'') ? false : true;
|
||||
quote = lexer->lookahead;
|
||||
advance(lexer);
|
||||
}
|
||||
else if (has_space_before) {
|
||||
return false;
|
||||
}
|
||||
|
||||
regex identifier_regex("[a-zA-Z0-9]");
|
||||
while (
|
||||
lexer->lookahead
|
||||
&& std::regex_match(std::string(1, static_cast<char>(lexer->lookahead)), identifier_regex)
|
||||
&& ! (quote ? lexer->lookahead == quote : iswspace(lexer->lookahead))
|
||||
) {
|
||||
// TODO: check this below condition
|
||||
if (lexer->lookahead == '\\') {
|
||||
advance(lexer);
|
||||
if (! lexer->lookahead) return false;
|
||||
}
|
||||
empty = false;
|
||||
unquoted_word += lexer->lookahead;
|
||||
advance(lexer);
|
||||
}
|
||||
|
||||
if (quote && lexer->lookahead == quote) {
|
||||
advance(lexer);
|
||||
}
|
||||
|
||||
return ! empty;
|
||||
}
|
||||
|
||||
bool exit_if_heredoc_end_delimiter(TSLexer *lexer) {
|
||||
std::string word;
|
||||
// lexer->result_symbol = HEREDOC_END_IDENTIFIER;
|
||||
while (!iswspace(lexer->lookahead)) {
|
||||
// printf("string here - %c", lexer->lookahead);
|
||||
word += lexer->lookahead;
|
||||
advance(lexer);
|
||||
|
||||
if (!lexer->lookahead) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (word == heredoc_identifier_queue.front()) {
|
||||
// if (1) {
|
||||
lexer->result_symbol = HEREDOC_END_IDENTIFIER;
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
// unset stuffs
|
||||
started_heredoc = false;
|
||||
started_heredoc_body = false;
|
||||
heredoc_identifier_queue.pop();
|
||||
heredoc_allows_interpolation.pop();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
lexer->result_symbol = HEREDOC_CONTENT;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t start_delimiter_char;
|
||||
int32_t end_delimiter_char;
|
||||
bool is_separator_delimiter_parsed;
|
||||
bool is_delimiter_enclosing; // is the delimiter {}, <> and same character not //, !!
|
||||
int delimiter_cout = 0;
|
||||
bool reached;
|
||||
|
||||
// heredoc
|
||||
bool started_heredoc = false;
|
||||
bool started_heredoc_body = false;
|
||||
std::queue<std::string> heredoc_identifier_queue;
|
||||
std::queue<bool> heredoc_allows_interpolation;
|
||||
std::queue<bool> heredoc_allows_indent;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
void * tree_sitter_perl_external_scanner_create() {
|
||||
return new Scanner();
|
||||
}
|
||||
|
||||
void tree_sitter_perl_external_scanner_destroy(void *payload) {
|
||||
Scanner *scanner = static_cast<Scanner *>(payload);
|
||||
delete scanner;
|
||||
}
|
||||
|
||||
unsigned tree_sitter_perl_external_scanner_serialize(
|
||||
void *payload,
|
||||
char *buffer
|
||||
) {
|
||||
Scanner *scanner = static_cast<Scanner *>(payload);
|
||||
return scanner->serialize(buffer);
|
||||
}
|
||||
|
||||
void tree_sitter_perl_external_scanner_deserialize(
|
||||
void *payload,
|
||||
const char *buffer,
|
||||
unsigned length
|
||||
) {
|
||||
Scanner *scanner = static_cast<Scanner *>(payload);
|
||||
scanner->deserialize(buffer, length);
|
||||
}
|
||||
|
||||
bool tree_sitter_perl_external_scanner_scan(
|
||||
void *payload,
|
||||
TSLexer *lexer,
|
||||
const bool *valid_symbols
|
||||
) {
|
||||
|
||||
Scanner *scanner = static_cast<Scanner *>(payload);
|
||||
return scanner->scan(lexer, valid_symbols);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue