krz/orgstar

A native macOS editor for org-mode files. editor org-mode swift

Sources/TreeSitterScanners/yaml/scanner.c

176fc78498d9ba962fa963bbeca0dd433d9e0bab
orgstar/Sources/TreeSitterScanners/yaml/scanner.c history · blame · raw

1415 lines · 51495 bytes

   1#include "tree_sitter/array.h"
   2#include "tree_sitter/parser.h"
   3
   4#define _str(x) #x
   5#define _file(x) _str(schema.x.c)
   6
   7#ifndef YAML_SCHEMA
   8#define YAML_SCHEMA core
   9#endif
  10
  11#include _file(YAML_SCHEMA)
  12
  13// clang-format off
  14
  15typedef enum {
  16    END_OF_FILE,
  17
  18    S_DIR_YML_BGN,  R_DIR_YML_VER,
  19    S_DIR_TAG_BGN,  R_DIR_TAG_HDL,  R_DIR_TAG_PFX,
  20    S_DIR_RSV_BGN,  R_DIR_RSV_PRM,
  21    S_DRS_END,
  22    S_DOC_END,
  23    R_BLK_SEQ_BGN,  BR_BLK_SEQ_BGN, B_BLK_SEQ_BGN,
  24    R_BLK_KEY_BGN,  BR_BLK_KEY_BGN, B_BLK_KEY_BGN,
  25    R_BLK_VAL_BGN,  BR_BLK_VAL_BGN, B_BLK_VAL_BGN,
  26    R_BLK_IMP_BGN,
  27    R_BLK_LIT_BGN,  BR_BLK_LIT_BGN,
  28    R_BLK_FLD_BGN,  BR_BLK_FLD_BGN,
  29    BR_BLK_STR_CTN,
  30    R_FLW_SEQ_BGN,  BR_FLW_SEQ_BGN, B_FLW_SEQ_BGN,
  31    R_FLW_SEQ_END,  BR_FLW_SEQ_END, B_FLW_SEQ_END,
  32    R_FLW_MAP_BGN,  BR_FLW_MAP_BGN, B_FLW_MAP_BGN,
  33    R_FLW_MAP_END,  BR_FLW_MAP_END, B_FLW_MAP_END,
  34    R_FLW_SEP_BGN,  BR_FLW_SEP_BGN,
  35    R_FLW_KEY_BGN,  BR_FLW_KEY_BGN,
  36    R_FLW_JSV_BGN,  BR_FLW_JSV_BGN,
  37    R_FLW_NJV_BGN,  BR_FLW_NJV_BGN,
  38    R_DQT_STR_BGN,  BR_DQT_STR_BGN, B_DQT_STR_BGN,
  39    R_DQT_STR_CTN,  BR_DQT_STR_CTN,
  40    R_DQT_ESC_NWL,  BR_DQT_ESC_NWL,
  41    R_DQT_ESC_SEQ,  BR_DQT_ESC_SEQ,
  42    R_DQT_STR_END,  BR_DQT_STR_END,
  43    R_SQT_STR_BGN,  BR_SQT_STR_BGN, B_SQT_STR_BGN,
  44    R_SQT_STR_CTN,  BR_SQT_STR_CTN,
  45    R_SQT_ESC_SQT,  BR_SQT_ESC_SQT,
  46    R_SQT_STR_END,  BR_SQT_STR_END,
  47
  48    R_SGL_PLN_NUL_BLK, BR_SGL_PLN_NUL_BLK, B_SGL_PLN_NUL_BLK, R_SGL_PLN_NUL_FLW, BR_SGL_PLN_NUL_FLW,
  49    R_SGL_PLN_BOL_BLK, BR_SGL_PLN_BOL_BLK, B_SGL_PLN_BOL_BLK, R_SGL_PLN_BOL_FLW, BR_SGL_PLN_BOL_FLW,
  50    R_SGL_PLN_INT_BLK, BR_SGL_PLN_INT_BLK, B_SGL_PLN_INT_BLK, R_SGL_PLN_INT_FLW, BR_SGL_PLN_INT_FLW,
  51    R_SGL_PLN_FLT_BLK, BR_SGL_PLN_FLT_BLK, B_SGL_PLN_FLT_BLK, R_SGL_PLN_FLT_FLW, BR_SGL_PLN_FLT_FLW,
  52    R_SGL_PLN_TMS_BLK, BR_SGL_PLN_TMS_BLK, B_SGL_PLN_TMS_BLK, R_SGL_PLN_TMS_FLW, BR_SGL_PLN_TMS_FLW,
  53    R_SGL_PLN_STR_BLK, BR_SGL_PLN_STR_BLK, B_SGL_PLN_STR_BLK, R_SGL_PLN_STR_FLW, BR_SGL_PLN_STR_FLW,
  54
  55    R_MTL_PLN_STR_BLK,  BR_MTL_PLN_STR_BLK,
  56    R_MTL_PLN_STR_FLW,  BR_MTL_PLN_STR_FLW,
  57
  58    R_TAG,     BR_TAG,     B_TAG,
  59    R_ACR_BGN, BR_ACR_BGN, B_ACR_BGN, R_ACR_CTN,
  60    R_ALS_BGN, BR_ALS_BGN, B_ALS_BGN, R_ALS_CTN,
  61
  62    BL,
  63    COMMENT,
  64
  65    ERR_REC,
  66} TokenType;
  67
  68// clang-format on
  69
  70#define SCN_SUCC 1
  71#define SCN_STOP 0
  72#define SCN_FAIL (-1)
  73
  74#define IND_ROT 'r'
  75#define IND_MAP 'm'
  76#define IND_SEQ 'q'
  77#define IND_STR 's'
  78
  79#define RET_SYM(RESULT_SYMBOL)                                                                                         \
  80    {                                                                                                                  \
  81        flush(scanner);                                                                                                \
  82        lexer->result_symbol = RESULT_SYMBOL;                                                                          \
  83        return true;                                                                                                   \
  84    }
  85
  86#define POP_IND()                                                                                                      \
  87    {                                                                                                                  \
  88        /* incorrect status caused by error recovering */                                                              \
  89        if (scanner->ind_typ_stk.size == 1) {                                                                          \
  90            return false;                                                                                              \
  91        }                                                                                                              \
  92        pop_ind(scanner);                                                                                              \
  93    }
  94
  95#define PUSH_IND(TYP, LEN) push_ind(scanner, TYP, LEN)
  96
  97#define PUSH_BGN_IND(TYP)                                                                                              \
  98    {                                                                                                                  \
  99        if (has_tab_ind)                                                                                               \
 100            return false;                                                                                              \
 101        push_ind(scanner, TYP, bgn_col);                                                                               \
 102    }
 103
 104#define MAY_PUSH_IMP_IND(TYP)                                                                                          \
 105    {                                                                                                                  \
 106        if (cur_ind != scanner->blk_imp_col) {                                                                         \
 107            if (scanner->blk_imp_tab)                                                                                  \
 108                return false;                                                                                          \
 109            push_ind(scanner, IND_MAP, scanner->blk_imp_col);                                                          \
 110        }                                                                                                              \
 111    }
 112
 113#define MAY_PUSH_SPC_SEQ_IND()                                                                                         \
 114    {                                                                                                                  \
 115        if (cur_ind_typ == IND_MAP) {                                                                                  \
 116            push_ind(scanner, IND_SEQ, bgn_col);                                                                       \
 117        }                                                                                                              \
 118    }
 119
 120#define MAY_UPD_IMP_COL()                                                                                              \
 121    {                                                                                                                  \
 122        if (scanner->blk_imp_row != bgn_row) {                                                                         \
 123            scanner->blk_imp_row = bgn_row;                                                                            \
 124            scanner->blk_imp_col = bgn_col;                                                                            \
 125            scanner->blk_imp_tab = has_tab_ind;                                                                        \
 126        }                                                                                                              \
 127    }
 128
 129#if HAS_TIMESTAMP
 130#define SGL_PLN_SYM(POS, CTX)                                                                                          \
 131    (scanner->rlt_sch == RS_NULL        ? POS##_SGL_PLN_NUL_##CTX                                                      \
 132     : scanner->rlt_sch == RS_BOOL      ? POS##_SGL_PLN_BOL_##CTX                                                      \
 133     : scanner->rlt_sch == RS_INT       ? POS##_SGL_PLN_INT_##CTX                                                      \
 134     : scanner->rlt_sch == RS_FLOAT     ? POS##_SGL_PLN_FLT_##CTX                                                      \
 135     : scanner->rlt_sch == RS_TIMESTAMP ? POS##_SGL_PLN_TMS_##CTX                                                      \
 136                                        : POS##_SGL_PLN_STR_##CTX)
 137#else
 138#define SGL_PLN_SYM(POS, CTX)                                                                                          \
 139    (scanner->rlt_sch == RS_NULL        ? POS##_SGL_PLN_NUL_##CTX                                                      \
 140     : scanner->rlt_sch == RS_BOOL      ? POS##_SGL_PLN_BOL_##CTX                                                      \
 141     : scanner->rlt_sch == RS_INT       ? POS##_SGL_PLN_INT_##CTX                                                      \
 142     : scanner->rlt_sch == RS_FLOAT     ? POS##_SGL_PLN_FLT_##CTX                                                      \
 143                                        : POS##_SGL_PLN_STR_##CTX)
 144#endif
 145
 146typedef struct {
 147    int16_t row;
 148    int16_t col;
 149    int16_t blk_imp_row;
 150    int16_t blk_imp_col;
 151    int16_t blk_imp_tab;
 152    Array(int16_t) ind_typ_stk;
 153    Array(int16_t) ind_len_stk;
 154
 155    // temp
 156    int16_t end_row;
 157    int16_t end_col;
 158    int16_t cur_row;
 159    int16_t cur_col;
 160    int32_t cur_chr;
 161    int8_t sch_stt;
 162    ResultSchema rlt_sch;
 163} Scanner;
 164
 165static unsigned serialize(Scanner *scanner, char *buffer) {
 166    size_t size = 0;
 167    *(int16_t *)&buffer[size] = scanner->row;
 168    size += sizeof(int16_t);
 169    *(int16_t *)&buffer[size] = scanner->col;
 170    size += sizeof(int16_t);
 171    *(int16_t *)&buffer[size] = scanner->blk_imp_row;
 172    size += sizeof(int16_t);
 173    *(int16_t *)&buffer[size] = scanner->blk_imp_col;
 174    size += sizeof(int16_t);
 175    *(int16_t *)&buffer[size] = scanner->blk_imp_tab;
 176    size += sizeof(int16_t);
 177    int16_t *typ_itr = scanner->ind_typ_stk.contents + 1;
 178    int16_t *typ_end = scanner->ind_typ_stk.contents + scanner->ind_typ_stk.size;
 179    int16_t *len_itr = scanner->ind_len_stk.contents + 1;
 180    for (; typ_itr != typ_end && size < TREE_SITTER_SERIALIZATION_BUFFER_SIZE; ++typ_itr, ++len_itr) {
 181        *(int16_t *)&buffer[size] = *typ_itr;
 182        size += sizeof(int16_t);
 183        *(int16_t *)&buffer[size] = *len_itr;
 184        size += sizeof(int16_t);
 185    }
 186    return size;
 187}
 188
 189static void deserialize(Scanner *scanner, const char *buffer, unsigned length) {
 190    scanner->row = 0;
 191    scanner->col = 0;
 192    scanner->blk_imp_row = -1;
 193    scanner->blk_imp_col = -1;
 194    scanner->blk_imp_tab = 0;
 195    array_delete(&scanner->ind_typ_stk);
 196    array_push(&scanner->ind_typ_stk, IND_ROT);
 197    array_delete(&scanner->ind_len_stk);
 198    array_push(&scanner->ind_len_stk, -1);
 199    if (length > 0) {
 200        size_t size = 0;
 201        scanner->row = *(int16_t *)&buffer[size];
 202        size += sizeof(int16_t);
 203        scanner->col = *(int16_t *)&buffer[size];
 204        size += sizeof(int16_t);
 205        scanner->blk_imp_row = *(int16_t *)&buffer[size];
 206        size += sizeof(int16_t);
 207        scanner->blk_imp_col = *(int16_t *)&buffer[size];
 208        size += sizeof(int16_t);
 209        scanner->blk_imp_tab = *(int16_t *)&buffer[size];
 210        size += sizeof(int16_t);
 211        while (size < length) {
 212            array_push(&scanner->ind_typ_stk, *(int16_t *)&buffer[size]);
 213            size += sizeof(int16_t);
 214            array_push(&scanner->ind_len_stk, *(int16_t *)&buffer[size]);
 215            size += sizeof(int16_t);
 216        }
 217        assert(size == length);
 218    }
 219}
 220
 221static inline void adv(Scanner *scanner, TSLexer *lexer) {
 222    scanner->cur_col++;
 223    scanner->cur_chr = lexer->lookahead;
 224    lexer->advance(lexer, false);
 225}
 226
 227static inline void adv_nwl(Scanner *scanner, TSLexer *lexer) {
 228    scanner->cur_row++;
 229    scanner->cur_col = 0;
 230    scanner->cur_chr = lexer->lookahead;
 231    lexer->advance(lexer, false);
 232}
 233
 234static inline void skp(Scanner *scanner, TSLexer *lexer) {
 235    scanner->cur_col++;
 236    scanner->cur_chr = lexer->lookahead;
 237    lexer->advance(lexer, true);
 238}
 239
 240static inline void skp_nwl(Scanner *scanner, TSLexer *lexer) {
 241    scanner->cur_row++;
 242    scanner->cur_col = 0;
 243    scanner->cur_chr = lexer->lookahead;
 244    lexer->advance(lexer, true);
 245}
 246
 247static inline void mrk_end(Scanner *scanner, TSLexer *lexer) {
 248    scanner->end_row = scanner->cur_row;
 249    scanner->end_col = scanner->cur_col;
 250    lexer->mark_end(lexer);
 251}
 252
 253static inline void init(Scanner *scanner) {
 254    scanner->cur_row = scanner->row;
 255    scanner->cur_col = scanner->col;
 256    scanner->cur_chr = 0;
 257    scanner->sch_stt = 0;
 258    scanner->rlt_sch = RS_STR;
 259}
 260
 261static inline void flush(Scanner *scanner) {
 262    scanner->row = scanner->end_row;
 263    scanner->col = scanner->end_col;
 264}
 265
 266static inline void pop_ind(Scanner *scanner) {
 267    array_pop(&scanner->ind_len_stk);
 268    array_pop(&scanner->ind_typ_stk);
 269}
 270
 271static inline void push_ind(Scanner *scanner, int16_t typ, int16_t len) {
 272    array_push(&scanner->ind_len_stk, len);
 273    array_push(&scanner->ind_typ_stk, typ);
 274}
 275
 276static inline bool is_wsp(int32_t c) { return c == ' ' || c == '\t'; }
 277
 278static inline bool is_nwl(int32_t c) { return c == '\r' || c == '\n'; }
 279
 280static inline bool is_wht(int32_t c) { return is_wsp(c) || is_nwl(c) || c == 0; }
 281
 282static inline bool is_ns_dec_digit(int32_t c) { return c >= '0' && c <= '9'; }
 283
 284static inline bool is_ns_hex_digit(int32_t c) {
 285    return is_ns_dec_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
 286}
 287
 288static inline bool is_ns_word_char(int32_t c) {
 289    return c == '-' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
 290}
 291
 292static inline bool is_nb_json(int32_t c) { return c == 0x09 || (c >= 0x20 && c <= 0x10ffff); }
 293
 294static inline bool is_nb_double_char(int32_t c) { return is_nb_json(c) && c != '\\' && c != '"'; }
 295
 296static inline bool is_nb_single_char(int32_t c) { return is_nb_json(c) && c != '\''; }
 297
 298static inline bool is_ns_char(int32_t c) {
 299    return (c >= 0x21 && c <= 0x7e) || c == 0x85 || (c >= 0xa0 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfefe) ||
 300           (c >= 0xff00 && c <= 0xfffd) || (c >= 0x10000 && c <= 0x10ffff);
 301}
 302
 303static inline bool is_c_indicator(int32_t c) {
 304    return c == '-' || c == '?' || c == ':' || c == ',' || c == '[' || c == ']' || c == '{' || c == '}' || c == '#' ||
 305           c == '&' || c == '*' || c == '!' || c == '|' || c == '>' || c == '\'' || c == '"' || c == '%' || c == '@' ||
 306           c == '`';
 307}
 308
 309static inline bool is_c_flow_indicator(int32_t c) { return c == ',' || c == '[' || c == ']' || c == '{' || c == '}'; }
 310
 311static inline bool is_plain_safe_in_block(int32_t c) { return is_ns_char(c); }
 312
 313static inline bool is_plain_safe_in_flow(int32_t c) { return is_ns_char(c) && !is_c_flow_indicator(c); }
 314
 315static inline bool is_ns_uri_char(int32_t c) {
 316    return is_ns_word_char(c) || c == '#' || c == ';' || c == '/' || c == '?' || c == ':' || c == '@' || c == '&' ||
 317           c == '=' || c == '+' || c == '$' || c == ',' || c == '_' || c == '.' || c == '!' || c == '~' || c == '*' ||
 318           c == '\'' || c == '(' || c == ')' || c == '[' || c == ']';
 319}
 320
 321static inline bool is_ns_tag_char(int32_t c) {
 322    return is_ns_word_char(c) || c == '#' || c == ';' || c == '/' || c == '?' || c == ':' || c == '@' || c == '&' ||
 323           c == '=' || c == '+' || c == '$' || c == '_' || c == '.' || c == '~' || c == '*' || c == '\'' || c == '(' ||
 324           c == ')';
 325}
 326
 327static inline bool is_ns_anchor_char(int32_t c) { return is_ns_char(c) && !is_c_flow_indicator(c); }
 328
 329static char scn_uri_esc(Scanner *scanner, TSLexer *lexer) {
 330    if (lexer->lookahead != '%') {
 331        return SCN_STOP;
 332    }
 333    mrk_end(scanner, lexer);
 334    adv(scanner, lexer);
 335    if (!is_ns_hex_digit(lexer->lookahead)) {
 336        return SCN_FAIL;
 337    }
 338    adv(scanner, lexer);
 339    if (!is_ns_hex_digit(lexer->lookahead)) {
 340        return SCN_FAIL;
 341    }
 342    adv(scanner, lexer);
 343    return SCN_SUCC;
 344}
 345
 346static char scn_ns_uri_char(Scanner *scanner, TSLexer *lexer) {
 347    if (is_ns_uri_char(lexer->lookahead)) {
 348        adv(scanner, lexer);
 349        return SCN_SUCC;
 350    }
 351    return scn_uri_esc(scanner, lexer);
 352}
 353
 354static char scn_ns_tag_char(Scanner *scanner, TSLexer *lexer) {
 355    if (is_ns_tag_char(lexer->lookahead)) {
 356        adv(scanner, lexer);
 357        return SCN_SUCC;
 358    }
 359    return scn_uri_esc(scanner, lexer);
 360}
 361
 362static bool scn_dir_bgn(Scanner *scanner, TSLexer *lexer) {
 363    adv(scanner, lexer);
 364    if (lexer->lookahead == 'Y') {
 365        adv(scanner, lexer);
 366        if (lexer->lookahead == 'A') {
 367            adv(scanner, lexer);
 368            if (lexer->lookahead == 'M') {
 369                adv(scanner, lexer);
 370                if (lexer->lookahead == 'L') {
 371                    adv(scanner, lexer);
 372                    if (is_wht(lexer->lookahead)) {
 373                        mrk_end(scanner, lexer);
 374                        RET_SYM(S_DIR_YML_BGN);
 375                    }
 376                }
 377            }
 378        }
 379    } else if (lexer->lookahead == 'T') {
 380        adv(scanner, lexer);
 381        if (lexer->lookahead == 'A') {
 382            adv(scanner, lexer);
 383            if (lexer->lookahead == 'G') {
 384                adv(scanner, lexer);
 385                if (is_wht(lexer->lookahead)) {
 386                    mrk_end(scanner, lexer);
 387                    RET_SYM(S_DIR_TAG_BGN);
 388                }
 389            }
 390        }
 391    }
 392    for (;;) {
 393        if (!is_ns_char(lexer->lookahead)) {
 394            break;
 395        }
 396        adv(scanner, lexer);
 397    }
 398    if (scanner->cur_col > 1 && is_wht(lexer->lookahead)) {
 399        mrk_end(scanner, lexer);
 400        RET_SYM(S_DIR_RSV_BGN);
 401    }
 402    return false;
 403}
 404
 405static bool scn_dir_yml_ver(Scanner *scanner, TSLexer *lexer, TSSymbol result_symbol) {
 406    uint16_t n1 = 0;
 407    uint16_t n2 = 0;
 408    while (is_ns_dec_digit(lexer->lookahead)) {
 409        adv(scanner, lexer);
 410        n1++;
 411    }
 412    if (lexer->lookahead != '.') {
 413        return false;
 414    }
 415    adv(scanner, lexer);
 416    while (is_ns_dec_digit(lexer->lookahead)) {
 417        adv(scanner, lexer);
 418        n2++;
 419    }
 420    if (n1 == 0 || n2 == 0) {
 421        return false;
 422    }
 423    mrk_end(scanner, lexer);
 424    RET_SYM(result_symbol);
 425}
 426
 427static bool scn_tag_hdl_tal(Scanner *scanner, TSLexer *lexer) {
 428    if (lexer->lookahead == '!') {
 429        adv(scanner, lexer);
 430        return true;
 431    }
 432    uint16_t n = 0;
 433    while (is_ns_word_char(lexer->lookahead)) {
 434        adv(scanner, lexer);
 435        n++;
 436    }
 437    if (n == 0) {
 438        return true;
 439    }
 440    if (lexer->lookahead == '!') {
 441        adv(scanner, lexer);
 442        return true;
 443    }
 444    return false;
 445}
 446
 447static bool scn_dir_tag_hdl(Scanner *scanner, TSLexer *lexer, TSSymbol result_symbol) {
 448    if (lexer->lookahead == '!') {
 449        adv(scanner, lexer);
 450        if (scn_tag_hdl_tal(scanner, lexer)) {
 451            mrk_end(scanner, lexer);
 452            RET_SYM(result_symbol);
 453        }
 454    }
 455    return false;
 456}
 457
 458static bool scn_dir_tag_pfx(Scanner *scanner, TSLexer *lexer, TSSymbol result_symbol) {
 459    if (lexer->lookahead == '!') {
 460        adv(scanner, lexer);
 461    } else if (scn_ns_tag_char(scanner, lexer) == SCN_SUCC) {
 462        ;
 463    } else {
 464        return false;
 465    }
 466    for (;;) {
 467        switch (scn_ns_uri_char(scanner, lexer)) {
 468            case SCN_STOP:
 469                mrk_end(scanner, lexer);
 470            case SCN_FAIL:
 471                RET_SYM(result_symbol);
 472            default:
 473                break;
 474        }
 475    }
 476}
 477
 478static bool scn_dir_rsv_prm(Scanner *scanner, TSLexer *lexer, TSSymbol result_symbol) {
 479    if (!is_ns_char(lexer->lookahead)) {
 480        return false;
 481    }
 482    adv(scanner, lexer);
 483    while (is_ns_char(lexer->lookahead)) {
 484        adv(scanner, lexer);
 485    }
 486    mrk_end(scanner, lexer);
 487    RET_SYM(result_symbol);
 488}
 489
 490static bool scn_tag(Scanner *scanner, TSLexer *lexer, TSSymbol result_symbol) {
 491    if (lexer->lookahead != '!') {
 492        return false;
 493    }
 494    adv(scanner, lexer);
 495    if (is_wht(lexer->lookahead)) {
 496        mrk_end(scanner, lexer);
 497        RET_SYM(result_symbol);
 498    }
 499    if (lexer->lookahead == '<') {
 500        adv(scanner, lexer);
 501        if (scn_ns_uri_char(scanner, lexer) != SCN_SUCC) {
 502            return false;
 503        }
 504        for (;;) {
 505            switch (scn_ns_uri_char(scanner, lexer)) {
 506                case SCN_STOP:
 507                    if (lexer->lookahead == '>') {
 508                        adv(scanner, lexer);
 509                        mrk_end(scanner, lexer);
 510                        RET_SYM(result_symbol);
 511                    }
 512                case SCN_FAIL:
 513                    return false;
 514                default:
 515                    break;
 516            }
 517        }
 518    } else {
 519        if (scn_tag_hdl_tal(scanner, lexer) && scn_ns_tag_char(scanner, lexer) != SCN_SUCC) {
 520            return false;
 521        }
 522        for (;;) {
 523            switch (scn_ns_tag_char(scanner, lexer)) {
 524                case SCN_STOP:
 525                    mrk_end(scanner, lexer);
 526                case SCN_FAIL:
 527                    RET_SYM(result_symbol);
 528                default:
 529                    break;
 530            }
 531        }
 532    }
 533    return false;
 534}
 535
 536static bool scn_acr_bgn(Scanner *scanner, TSLexer *lexer, TSSymbol result_symbol) {
 537    if (lexer->lookahead != '&') {
 538        return false;
 539    }
 540    adv(scanner, lexer);
 541    if (!is_ns_anchor_char(lexer->lookahead)) {
 542        return false;
 543    }
 544    mrk_end(scanner, lexer);
 545    RET_SYM(result_symbol);
 546}
 547
 548static bool scn_acr_ctn(Scanner *scanner, TSLexer *lexer, TSSymbol result_symbol) {
 549    while (is_ns_anchor_char(lexer->lookahead)) {
 550        adv(scanner, lexer);
 551    }
 552    mrk_end(scanner, lexer);
 553    RET_SYM(result_symbol);
 554}
 555
 556static bool scn_als_bgn(Scanner *scanner, TSLexer *lexer, TSSymbol result_symbol) {
 557    if (lexer->lookahead != '*') {
 558        return false;
 559    }
 560    adv(scanner, lexer);
 561    if (!is_ns_anchor_char(lexer->lookahead)) {
 562        return false;
 563    }
 564    mrk_end(scanner, lexer);
 565    RET_SYM(result_symbol);
 566}
 567
 568static bool scn_als_ctn(Scanner *scanner, TSLexer *lexer, TSSymbol result_symbol) {
 569    while (is_ns_anchor_char(lexer->lookahead)) {
 570        adv(scanner, lexer);
 571    }
 572    mrk_end(scanner, lexer);
 573    RET_SYM(result_symbol);
 574}
 575
 576static bool scn_dqt_esc_seq(Scanner *scanner, TSLexer *lexer, TSSymbol result_symbol) {
 577    uint16_t i;
 578    switch (lexer->lookahead) {
 579        case '0':
 580        case 'a':
 581        case 'b':
 582        case 't':
 583        case '\t':
 584        case 'n':
 585        case 'v':
 586        case 'r':
 587        case 'e':
 588        case 'f':
 589        case ' ':
 590        case '"':
 591        case '/':
 592        case '\\':
 593        case 'N':
 594        case '_':
 595        case 'L':
 596        case 'P':
 597            adv(scanner, lexer);
 598            break;
 599        case 'U':
 600            adv(scanner, lexer);
 601            for (i = 0; i < 8; i++) {
 602                if (is_ns_hex_digit(lexer->lookahead)) {
 603                    adv(scanner, lexer);
 604                } else {
 605                    return false;
 606                }
 607            }
 608            break;
 609        case 'u':
 610            adv(scanner, lexer);
 611            for (i = 0; i < 4; i++) {
 612                if (is_ns_hex_digit(lexer->lookahead)) {
 613                    adv(scanner, lexer);
 614                } else {
 615                    return false;
 616                }
 617            }
 618            break;
 619        case 'x':
 620            adv(scanner, lexer);
 621            for (i = 0; i < 2; i++) {
 622                if (is_ns_hex_digit(lexer->lookahead)) {
 623                    adv(scanner, lexer);
 624                } else {
 625                    return false;
 626                }
 627            }
 628            break;
 629        default:
 630            return false;
 631    }
 632    mrk_end(scanner, lexer);
 633    RET_SYM(result_symbol);
 634}
 635
 636static bool scn_drs_doc_end(Scanner *scanner, TSLexer *lexer) {
 637    if (lexer->lookahead != '-' && lexer->lookahead != '.') {
 638        return false;
 639    }
 640    int32_t delimeter = lexer->lookahead;
 641    adv(scanner, lexer);
 642    if (lexer->lookahead == delimeter) {
 643        adv(scanner, lexer);
 644        if (lexer->lookahead == delimeter) {
 645            adv(scanner, lexer);
 646            if (is_wht(lexer->lookahead)) {
 647                return true;
 648            }
 649        }
 650    }
 651    mrk_end(scanner, lexer);
 652    return false;
 653}
 654
 655static bool scn_dqt_str_cnt(Scanner *scanner, TSLexer *lexer, TSSymbol result_symbol) {
 656    if (!is_nb_double_char(lexer->lookahead)) {
 657        return false;
 658    }
 659    if (scanner->cur_col == 0 && scn_drs_doc_end(scanner, lexer)) {
 660        mrk_end(scanner, lexer);
 661        RET_SYM(scanner->cur_chr == '-' ? S_DRS_END : S_DOC_END);
 662    } else {
 663        adv(scanner, lexer);
 664    }
 665    while (is_nb_double_char(lexer->lookahead)) {
 666        adv(scanner, lexer);
 667    }
 668    mrk_end(scanner, lexer);
 669    RET_SYM(result_symbol);
 670}
 671
 672static bool scn_sqt_str_cnt(Scanner *scanner, TSLexer *lexer, TSSymbol result_symbol) {
 673    if (!is_nb_single_char(lexer->lookahead)) {
 674        return false;
 675    }
 676    if (scanner->cur_col == 0 && scn_drs_doc_end(scanner, lexer)) {
 677        mrk_end(scanner, lexer);
 678        RET_SYM(scanner->cur_chr == '-' ? S_DRS_END : S_DOC_END);
 679    } else {
 680        adv(scanner, lexer);
 681    }
 682    while (is_nb_single_char(lexer->lookahead)) {
 683        adv(scanner, lexer);
 684    }
 685    mrk_end(scanner, lexer);
 686    RET_SYM(result_symbol);
 687}
 688
 689static bool scn_blk_str_bgn(Scanner *scanner, TSLexer *lexer, TSSymbol result_symbol) {
 690    if (lexer->lookahead != '|' && lexer->lookahead != '>') {
 691        return false;
 692    }
 693    adv(scanner, lexer);
 694    int16_t cur_ind = *array_back(&scanner->ind_len_stk);
 695    int16_t ind = -1;
 696    if (lexer->lookahead >= '1' && lexer->lookahead <= '9') {
 697        ind = lexer->lookahead - '1';
 698        adv(scanner, lexer);
 699        if (lexer->lookahead == '+' || lexer->lookahead == '-') {
 700            adv(scanner, lexer);
 701        }
 702    } else if (lexer->lookahead == '+' || lexer->lookahead == '-') {
 703        adv(scanner, lexer);
 704        if (lexer->lookahead >= '1' && lexer->lookahead <= '9') {
 705            ind = lexer->lookahead - '1';
 706            adv(scanner, lexer);
 707        }
 708    }
 709    if (!is_wht(lexer->lookahead)) {
 710        return false;
 711    }
 712    mrk_end(scanner, lexer);
 713    if (ind != -1) {
 714        ind += cur_ind;
 715    } else {
 716        ind = cur_ind;
 717        while (is_wsp(lexer->lookahead)) {
 718            adv(scanner, lexer);
 719        }
 720        if (lexer->lookahead == '#') {
 721            adv(scanner, lexer);
 722            while (!is_nwl(lexer->lookahead) && lexer->lookahead != 0) {
 723                adv(scanner, lexer);
 724            }
 725        }
 726        if (is_nwl(lexer->lookahead)) {
 727            adv_nwl(scanner, lexer);
 728        }
 729        while (lexer->lookahead != 0) {
 730            if (lexer->lookahead == ' ') {
 731                adv(scanner, lexer);
 732            } else if (is_nwl(lexer->lookahead)) {
 733                if (scanner->cur_col - 1 < ind) {
 734                    break;
 735                }
 736                ind = scanner->cur_col - 1;
 737                adv_nwl(scanner, lexer);
 738            } else {
 739                if (scanner->cur_col - 1 > ind) {
 740                    ind = scanner->cur_col - 1;
 741                }
 742                break;
 743            }
 744        }
 745    }
 746    PUSH_IND(IND_STR, ind);
 747    RET_SYM(result_symbol);
 748}
 749
 750static bool scn_blk_str_cnt(Scanner *scanner, TSLexer *lexer, TSSymbol result_symbol) {
 751    if (!is_ns_char(lexer->lookahead)) {
 752        return false;
 753    }
 754    if (scanner->cur_col == 0 && scn_drs_doc_end(scanner, lexer)) {
 755        POP_IND();
 756        RET_SYM(BL);
 757    } else {
 758        adv(scanner, lexer);
 759    }
 760    mrk_end(scanner, lexer);
 761    for (;;) {
 762        if (is_ns_char(lexer->lookahead)) {
 763            adv(scanner, lexer);
 764            while (is_ns_char(lexer->lookahead)) {
 765                adv(scanner, lexer);
 766            }
 767            mrk_end(scanner, lexer);
 768        }
 769        if (is_wsp(lexer->lookahead)) {
 770            adv(scanner, lexer);
 771            while (is_wsp(lexer->lookahead)) {
 772                adv(scanner, lexer);
 773            }
 774        } else {
 775            break;
 776        }
 777    }
 778    RET_SYM(result_symbol);
 779}
 780
 781static char scn_pln_cnt(Scanner *scanner, TSLexer *lexer, bool (*is_plain_safe)(int32_t)) {
 782    bool is_cur_wsp = is_wsp(scanner->cur_chr);
 783    bool is_cur_saf = is_plain_safe(scanner->cur_chr);
 784    bool is_lka_wsp = is_wsp(lexer->lookahead);
 785    bool is_lka_saf = is_plain_safe(lexer->lookahead);
 786    if (is_lka_saf || is_lka_wsp) {
 787        for (;;) {
 788            if (is_lka_saf && lexer->lookahead != '#' && lexer->lookahead != ':') {
 789                adv(scanner, lexer);
 790                mrk_end(scanner, lexer);
 791                scanner->sch_stt = adv_sch_stt(scanner->sch_stt, scanner->cur_chr, &scanner->rlt_sch);
 792            } else if (is_cur_saf && lexer->lookahead == '#') {
 793                adv(scanner, lexer);
 794                mrk_end(scanner, lexer);
 795                scanner->sch_stt = adv_sch_stt(scanner->sch_stt, scanner->cur_chr, &scanner->rlt_sch);
 796            } else if (is_lka_wsp) {
 797                adv(scanner, lexer);
 798                scanner->sch_stt = adv_sch_stt(scanner->sch_stt, scanner->cur_chr, &scanner->rlt_sch);
 799            } else if (lexer->lookahead == ':') {
 800                adv(scanner, lexer); // check later
 801            } else {
 802                break;
 803            }
 804
 805            is_cur_wsp = is_lka_wsp;
 806            is_cur_saf = is_lka_saf;
 807            is_lka_wsp = is_wsp(lexer->lookahead);
 808            is_lka_saf = is_plain_safe(lexer->lookahead);
 809
 810            if (scanner->cur_chr == ':') {
 811                if (is_lka_saf) {
 812                    mrk_end(scanner, lexer);
 813                    scanner->sch_stt = adv_sch_stt(scanner->sch_stt, scanner->cur_chr, &scanner->rlt_sch);
 814                } else {
 815                    return SCN_FAIL;
 816                }
 817            }
 818        }
 819    } else {
 820        return SCN_STOP;
 821    }
 822    return SCN_SUCC;
 823}
 824
 825static bool scan(Scanner *scanner, TSLexer *lexer, const bool *valid_symbols) {
 826    init(scanner);
 827    mrk_end(scanner, lexer);
 828
 829    bool allow_comment = !(valid_symbols[R_DQT_STR_CTN] || valid_symbols[BR_DQT_STR_CTN] ||
 830                           valid_symbols[R_SQT_STR_CTN] || valid_symbols[BR_SQT_STR_CTN]);
 831    int16_t *ind_ptr = scanner->ind_len_stk.contents + scanner->ind_len_stk.size - 1;
 832    int16_t *ind_end = scanner->ind_len_stk.contents - 1;
 833    int16_t cur_ind = *ind_ptr--;
 834    int16_t prt_ind = ind_ptr == ind_end ? -1 : *ind_ptr;
 835    int16_t cur_ind_typ = *array_back(&scanner->ind_typ_stk);
 836
 837    bool has_tab_ind = false;
 838    int16_t leading_spaces = 0;
 839
 840    for (;;) {
 841        if (lexer->lookahead == ' ') {
 842            if (!has_tab_ind) {
 843                leading_spaces++;
 844            }
 845            skp(scanner, lexer);
 846        } else if (lexer->lookahead == '\t') {
 847            has_tab_ind = true;
 848            skp(scanner, lexer);
 849        } else if (is_nwl(lexer->lookahead)) {
 850            has_tab_ind = false;
 851            leading_spaces = 0;
 852            skp_nwl(scanner, lexer);
 853        } else if (allow_comment && lexer->lookahead == '#') {
 854            if (valid_symbols[BR_BLK_STR_CTN] && valid_symbols[BL] && scanner->cur_col <= cur_ind) {
 855                POP_IND();
 856                RET_SYM(BL);
 857            }
 858            if (valid_symbols[BR_BLK_STR_CTN]
 859                    ? scanner->cur_row == scanner->row
 860                    : scanner->cur_col == 0 || scanner->cur_row != scanner->row || scanner->cur_col > scanner->col) {
 861                adv(scanner, lexer);
 862                while (!is_nwl(lexer->lookahead) && lexer->lookahead != 0) {
 863                    adv(scanner, lexer);
 864                }
 865                mrk_end(scanner, lexer);
 866                RET_SYM(COMMENT);
 867            } else {
 868                break;
 869            }
 870        } else {
 871            break;
 872        }
 873    }
 874
 875    if (lexer->lookahead == 0) {
 876        if (valid_symbols[BL]) {
 877            mrk_end(scanner, lexer);
 878            POP_IND();
 879            RET_SYM(BL)
 880        }
 881        if (valid_symbols[END_OF_FILE]) {
 882            mrk_end(scanner, lexer);
 883            RET_SYM(END_OF_FILE)
 884        }
 885        return false;
 886    }
 887
 888    int16_t bgn_row = scanner->cur_row;
 889    int16_t bgn_col = scanner->cur_col;
 890    int32_t bgn_chr = lexer->lookahead;
 891
 892    if (valid_symbols[BL] && bgn_col <= cur_ind && !has_tab_ind) {
 893        if (cur_ind == prt_ind && cur_ind_typ == IND_SEQ ? bgn_col < cur_ind || lexer->lookahead != '-'
 894                                                         : bgn_col <= prt_ind || cur_ind_typ == IND_STR) {
 895            POP_IND();
 896            RET_SYM(BL);
 897        }
 898    }
 899
 900    bool has_nwl = scanner->cur_row > scanner->row;
 901    bool is_r = !has_nwl;
 902    bool is_br = has_nwl && leading_spaces > cur_ind;
 903    bool is_b = has_nwl && leading_spaces == cur_ind && !has_tab_ind;
 904    bool is_s = bgn_col == 0;
 905
 906    if (valid_symbols[R_DIR_YML_VER] && is_r) {
 907        return scn_dir_yml_ver(scanner, lexer, R_DIR_YML_VER);
 908    }
 909    if (valid_symbols[R_DIR_TAG_HDL] && is_r) {
 910        return scn_dir_tag_hdl(scanner, lexer, R_DIR_TAG_HDL);
 911    }
 912    if (valid_symbols[R_DIR_TAG_PFX] && is_r) {
 913        return scn_dir_tag_pfx(scanner, lexer, R_DIR_TAG_PFX);
 914    }
 915    if (valid_symbols[R_DIR_RSV_PRM] && is_r) {
 916        return scn_dir_rsv_prm(scanner, lexer, R_DIR_RSV_PRM);
 917    }
 918    if (valid_symbols[BR_BLK_STR_CTN] && is_br && scn_blk_str_cnt(scanner, lexer, BR_BLK_STR_CTN)) {
 919        return true;
 920    }
 921
 922    if ((valid_symbols[R_DQT_STR_CTN] && is_r && scn_dqt_str_cnt(scanner, lexer, R_DQT_STR_CTN)) ||
 923        (valid_symbols[BR_DQT_STR_CTN] && is_br && scn_dqt_str_cnt(scanner, lexer, BR_DQT_STR_CTN))) {
 924        return true;
 925    }
 926
 927    if ((valid_symbols[R_SQT_STR_CTN] && is_r && scn_sqt_str_cnt(scanner, lexer, R_SQT_STR_CTN)) ||
 928        (valid_symbols[BR_SQT_STR_CTN] && is_br && scn_sqt_str_cnt(scanner, lexer, BR_SQT_STR_CTN))) {
 929        return true;
 930    }
 931
 932    if (valid_symbols[R_ACR_CTN] && is_r) {
 933        return scn_acr_ctn(scanner, lexer, R_ACR_CTN);
 934    }
 935    if (valid_symbols[R_ALS_CTN] && is_r) {
 936        return scn_als_ctn(scanner, lexer, R_ALS_CTN);
 937    }
 938
 939    if (lexer->lookahead == '%') {
 940        if (valid_symbols[S_DIR_YML_BGN] && is_s) {
 941            return scn_dir_bgn(scanner, lexer);
 942        }
 943    } else if (lexer->lookahead == '*') {
 944        if (valid_symbols[R_ALS_BGN] && is_r) {
 945            MAY_UPD_IMP_COL();
 946            return scn_als_bgn(scanner, lexer, R_ALS_BGN);
 947        }
 948        if (valid_symbols[BR_ALS_BGN] && is_br) {
 949            MAY_UPD_IMP_COL();
 950            return scn_als_bgn(scanner, lexer, BR_ALS_BGN);
 951        }
 952        if (valid_symbols[B_ALS_BGN] && is_b) {
 953            MAY_UPD_IMP_COL();
 954            return scn_als_bgn(scanner, lexer, B_ALS_BGN);
 955        }
 956    } else if (lexer->lookahead == '&') {
 957        if (valid_symbols[R_ACR_BGN] && is_r) {
 958            MAY_UPD_IMP_COL();
 959            return scn_acr_bgn(scanner, lexer, R_ACR_BGN);
 960        }
 961        if (valid_symbols[BR_ACR_BGN] && is_br) {
 962            MAY_UPD_IMP_COL();
 963            return scn_acr_bgn(scanner, lexer, BR_ACR_BGN);
 964        }
 965        if (valid_symbols[B_ACR_BGN] && is_b) {
 966            MAY_UPD_IMP_COL();
 967            return scn_acr_bgn(scanner, lexer, B_ACR_BGN);
 968        }
 969    } else if (lexer->lookahead == '!') {
 970        if (valid_symbols[R_TAG] && is_r) {
 971            MAY_UPD_IMP_COL();
 972            return scn_tag(scanner, lexer, R_TAG);
 973        }
 974        if (valid_symbols[BR_TAG] && is_br) {
 975            MAY_UPD_IMP_COL();
 976            return scn_tag(scanner, lexer, BR_TAG);
 977        }
 978        if (valid_symbols[B_TAG] && is_b) {
 979            MAY_UPD_IMP_COL();
 980            return scn_tag(scanner, lexer, B_TAG);
 981        }
 982    } else if (lexer->lookahead == '[') {
 983        if (valid_symbols[R_FLW_SEQ_BGN] && is_r) {
 984            MAY_UPD_IMP_COL();
 985            adv(scanner, lexer);
 986            mrk_end(scanner, lexer);
 987            RET_SYM(R_FLW_SEQ_BGN)
 988        }
 989        if (valid_symbols[BR_FLW_SEQ_BGN] && is_br) {
 990            MAY_UPD_IMP_COL();
 991            adv(scanner, lexer);
 992            mrk_end(scanner, lexer);
 993            RET_SYM(BR_FLW_SEQ_BGN)
 994        }
 995        if (valid_symbols[B_FLW_SEQ_BGN] && is_b) {
 996            MAY_UPD_IMP_COL();
 997            adv(scanner, lexer);
 998            mrk_end(scanner, lexer);
 999            RET_SYM(B_FLW_SEQ_BGN)
1000        }
1001    } else if (lexer->lookahead == ']') {
1002        if (valid_symbols[R_FLW_SEQ_END] && is_r) {
1003            adv(scanner, lexer);
1004            mrk_end(scanner, lexer);
1005            RET_SYM(R_FLW_SEQ_END)
1006        }
1007        if (valid_symbols[BR_FLW_SEQ_END] && is_br) {
1008            adv(scanner, lexer);
1009            mrk_end(scanner, lexer);
1010            RET_SYM(BR_FLW_SEQ_END)
1011        }
1012        if (valid_symbols[B_FLW_SEQ_END] && is_b) {
1013            adv(scanner, lexer);
1014            mrk_end(scanner, lexer);
1015            RET_SYM(BR_FLW_SEQ_END)
1016        }
1017    } else if (lexer->lookahead == '{') {
1018        if (valid_symbols[R_FLW_MAP_BGN] && is_r) {
1019            MAY_UPD_IMP_COL();
1020            adv(scanner, lexer);
1021            mrk_end(scanner, lexer);
1022            RET_SYM(R_FLW_MAP_BGN)
1023        }
1024        if (valid_symbols[BR_FLW_MAP_BGN] && is_br) {
1025            MAY_UPD_IMP_COL();
1026            adv(scanner, lexer);
1027            mrk_end(scanner, lexer);
1028            RET_SYM(BR_FLW_MAP_BGN)
1029        }
1030        if (valid_symbols[B_FLW_MAP_BGN] && is_b) {
1031            MAY_UPD_IMP_COL();
1032            adv(scanner, lexer);
1033            mrk_end(scanner, lexer);
1034            RET_SYM(B_FLW_MAP_BGN)
1035        }
1036    } else if (lexer->lookahead == '}') {
1037        if (valid_symbols[R_FLW_MAP_END] && is_r) {
1038            adv(scanner, lexer);
1039            mrk_end(scanner, lexer);
1040            RET_SYM(R_FLW_MAP_END)
1041        }
1042        if (valid_symbols[BR_FLW_MAP_END] && is_br) {
1043            adv(scanner, lexer);
1044            mrk_end(scanner, lexer);
1045            RET_SYM(BR_FLW_MAP_END)
1046        }
1047        if (valid_symbols[B_FLW_MAP_END] && is_b) {
1048            adv(scanner, lexer);
1049            mrk_end(scanner, lexer);
1050            RET_SYM(BR_FLW_MAP_END)
1051        }
1052    } else if (lexer->lookahead == ',') {
1053        if (valid_symbols[R_FLW_SEP_BGN] && is_r) {
1054            adv(scanner, lexer);
1055            mrk_end(scanner, lexer);
1056            RET_SYM(R_FLW_SEP_BGN)
1057        }
1058        if (valid_symbols[BR_FLW_SEP_BGN] && is_br) {
1059            adv(scanner, lexer);
1060            mrk_end(scanner, lexer);
1061            RET_SYM(BR_FLW_SEP_BGN)
1062        }
1063    } else if (lexer->lookahead == '"') {
1064        if (valid_symbols[R_DQT_STR_BGN] && is_r) {
1065            MAY_UPD_IMP_COL();
1066            adv(scanner, lexer);
1067            mrk_end(scanner, lexer);
1068            RET_SYM(R_DQT_STR_BGN)
1069        }
1070        if (valid_symbols[BR_DQT_STR_BGN] && is_br) {
1071            MAY_UPD_IMP_COL();
1072            adv(scanner, lexer);
1073            mrk_end(scanner, lexer);
1074            RET_SYM(BR_DQT_STR_BGN)
1075        }
1076        if (valid_symbols[B_DQT_STR_BGN] && is_b) {
1077            MAY_UPD_IMP_COL();
1078            adv(scanner, lexer);
1079            mrk_end(scanner, lexer);
1080            RET_SYM(B_DQT_STR_BGN)
1081        }
1082        if (valid_symbols[R_DQT_STR_END] && is_r) {
1083            adv(scanner, lexer);
1084            mrk_end(scanner, lexer);
1085            RET_SYM(R_DQT_STR_END)
1086        }
1087        if (valid_symbols[BR_DQT_STR_END] && is_br) {
1088            adv(scanner, lexer);
1089            mrk_end(scanner, lexer);
1090            RET_SYM(BR_DQT_STR_END)
1091        }
1092    } else if (lexer->lookahead == '\'') {
1093        if (valid_symbols[R_SQT_STR_BGN] && is_r) {
1094            MAY_UPD_IMP_COL();
1095            adv(scanner, lexer);
1096            mrk_end(scanner, lexer);
1097            RET_SYM(R_SQT_STR_BGN)
1098        }
1099        if (valid_symbols[BR_SQT_STR_BGN] && is_br) {
1100            MAY_UPD_IMP_COL();
1101            adv(scanner, lexer);
1102            mrk_end(scanner, lexer);
1103            RET_SYM(BR_SQT_STR_BGN)
1104        }
1105        if (valid_symbols[B_SQT_STR_BGN] && is_b) {
1106            MAY_UPD_IMP_COL();
1107            adv(scanner, lexer);
1108            mrk_end(scanner, lexer);
1109            RET_SYM(B_SQT_STR_BGN)
1110        }
1111        if (valid_symbols[R_SQT_STR_END] && is_r) {
1112            adv(scanner, lexer);
1113            if (lexer->lookahead == '\'') {
1114                adv(scanner, lexer);
1115                mrk_end(scanner, lexer);
1116                RET_SYM(R_SQT_ESC_SQT)
1117            } else {
1118                mrk_end(scanner, lexer);
1119                RET_SYM(R_SQT_STR_END)
1120            }
1121        }
1122        if (valid_symbols[BR_SQT_STR_END] && is_br) {
1123            adv(scanner, lexer);
1124            if (lexer->lookahead == '\'') {
1125                adv(scanner, lexer);
1126                mrk_end(scanner, lexer);
1127                RET_SYM(BR_SQT_ESC_SQT)
1128            } else {
1129                mrk_end(scanner, lexer);
1130                RET_SYM(BR_SQT_STR_END)
1131            }
1132        }
1133    } else if (lexer->lookahead == '?') {
1134        bool is_r_blk_key_bgn = valid_symbols[R_BLK_KEY_BGN] && is_r;
1135        bool is_br_blk_key_bgn = valid_symbols[BR_BLK_KEY_BGN] && is_br;
1136        bool is_b_blk_key_bgn = valid_symbols[B_BLK_KEY_BGN] && is_b;
1137        bool is_r_flw_key_bgn = valid_symbols[R_FLW_KEY_BGN] && is_r;
1138        bool is_br_flw_key_bgn = valid_symbols[BR_FLW_KEY_BGN] && is_br;
1139        if (is_r_blk_key_bgn || is_br_blk_key_bgn || is_b_blk_key_bgn || is_r_flw_key_bgn || is_br_flw_key_bgn) {
1140            adv(scanner, lexer);
1141            if (is_wht(lexer->lookahead)) {
1142                mrk_end(scanner, lexer);
1143                if (is_r_blk_key_bgn) {
1144                    PUSH_BGN_IND(IND_MAP);
1145                    RET_SYM(R_BLK_KEY_BGN);
1146                }
1147                if (is_br_blk_key_bgn) {
1148                    PUSH_BGN_IND(IND_MAP);
1149                    RET_SYM(BR_BLK_KEY_BGN);
1150                }
1151                if (is_b_blk_key_bgn)
1152                    RET_SYM(B_BLK_KEY_BGN);
1153                if (is_r_flw_key_bgn)
1154                    RET_SYM(R_FLW_KEY_BGN);
1155                if (is_br_flw_key_bgn)
1156                    RET_SYM(BR_FLW_KEY_BGN);
1157            }
1158        }
1159    } else if (lexer->lookahead == ':') {
1160        if (valid_symbols[R_FLW_JSV_BGN] && is_r) {
1161            adv(scanner, lexer);
1162            mrk_end(scanner, lexer);
1163            RET_SYM(R_FLW_JSV_BGN);
1164        }
1165        if (valid_symbols[BR_FLW_JSV_BGN] && is_br) {
1166            adv(scanner, lexer);
1167            mrk_end(scanner, lexer);
1168            RET_SYM(BR_FLW_JSV_BGN);
1169        }
1170        bool is_r_blk_val_bgn = valid_symbols[R_BLK_VAL_BGN] && is_r;
1171        bool is_br_blk_val_bgn = valid_symbols[BR_BLK_VAL_BGN] && is_br;
1172        bool is_b_blk_val_bgn = valid_symbols[B_BLK_VAL_BGN] && is_b;
1173        bool is_r_blk_imp_bgn = valid_symbols[R_BLK_IMP_BGN] && is_r;
1174        bool is_r_flw_njv_bgn = valid_symbols[R_FLW_NJV_BGN] && is_r;
1175        bool is_br_flw_njv_bgn = valid_symbols[BR_FLW_NJV_BGN] && is_br;
1176        if (is_r_blk_val_bgn || is_br_blk_val_bgn || is_b_blk_val_bgn || is_r_blk_imp_bgn || is_r_flw_njv_bgn ||
1177            is_br_flw_njv_bgn) {
1178            adv(scanner, lexer);
1179            bool is_lka_wht = is_wht(lexer->lookahead);
1180            if (is_lka_wht) {
1181                if (is_r_blk_val_bgn) {
1182                    PUSH_BGN_IND(IND_MAP);
1183                    mrk_end(scanner, lexer);
1184                    RET_SYM(R_BLK_VAL_BGN);
1185                }
1186                if (is_br_blk_val_bgn) {
1187                    PUSH_BGN_IND(IND_MAP);
1188                    mrk_end(scanner, lexer);
1189                    RET_SYM(BR_BLK_VAL_BGN);
1190                }
1191                if (is_b_blk_val_bgn) {
1192                    mrk_end(scanner, lexer);
1193                    RET_SYM(B_BLK_VAL_BGN);
1194                }
1195                if (is_r_blk_imp_bgn) {
1196                    MAY_PUSH_IMP_IND();
1197                    mrk_end(scanner, lexer);
1198                    RET_SYM(R_BLK_IMP_BGN);
1199                }
1200            }
1201            if (is_lka_wht || lexer->lookahead == ',' || lexer->lookahead == ']' || lexer->lookahead == '}') {
1202                if (is_r_flw_njv_bgn) {
1203                    mrk_end(scanner, lexer);
1204                    RET_SYM(R_FLW_NJV_BGN);
1205                }
1206                if (is_br_flw_njv_bgn) {
1207                    mrk_end(scanner, lexer);
1208                    RET_SYM(BR_FLW_NJV_BGN);
1209                }
1210            }
1211        }
1212    } else if (lexer->lookahead == '-') {
1213        bool is_r_blk_seq_bgn = valid_symbols[R_BLK_SEQ_BGN] && is_r;
1214        bool is_br_blk_seq_bgn = valid_symbols[BR_BLK_SEQ_BGN] && is_br;
1215        bool is_b_blk_seq_bgn = valid_symbols[B_BLK_SEQ_BGN] && is_b;
1216        bool is_s_drs_end = is_s;
1217        if (is_r_blk_seq_bgn || is_br_blk_seq_bgn || is_b_blk_seq_bgn || is_s_drs_end) {
1218            adv(scanner, lexer);
1219            if (is_wht(lexer->lookahead)) {
1220                if (is_r_blk_seq_bgn) {
1221                    PUSH_BGN_IND(IND_SEQ);
1222                    mrk_end(scanner, lexer);
1223                    RET_SYM(R_BLK_SEQ_BGN)
1224                }
1225                if (is_br_blk_seq_bgn) {
1226                    PUSH_BGN_IND(IND_SEQ);
1227                    mrk_end(scanner, lexer);
1228                    RET_SYM(BR_BLK_SEQ_BGN)
1229                }
1230                if (is_b_blk_seq_bgn) {
1231                    MAY_PUSH_SPC_SEQ_IND();
1232                    mrk_end(scanner, lexer);
1233                    RET_SYM(B_BLK_SEQ_BGN)
1234                }
1235            } else if (lexer->lookahead == '-' && is_s_drs_end) {
1236                adv(scanner, lexer);
1237                if (lexer->lookahead == '-') {
1238                    adv(scanner, lexer);
1239                    if (is_wht(lexer->lookahead)) {
1240                        if (valid_symbols[BL]) {
1241                            POP_IND();
1242                            RET_SYM(BL);
1243                        }
1244                        mrk_end(scanner, lexer);
1245                        RET_SYM(S_DRS_END);
1246                    }
1247                }
1248            }
1249        }
1250    } else if (lexer->lookahead == '.') {
1251        if (is_s) {
1252            adv(scanner, lexer);
1253            if (lexer->lookahead == '.') {
1254                adv(scanner, lexer);
1255                if (lexer->lookahead == '.') {
1256                    adv(scanner, lexer);
1257                    if (is_wht(lexer->lookahead)) {
1258                        if (valid_symbols[BL]) {
1259                            POP_IND();
1260                            RET_SYM(BL);
1261                        }
1262                        mrk_end(scanner, lexer);
1263                        RET_SYM(S_DOC_END);
1264                    }
1265                }
1266            }
1267        }
1268    } else if (lexer->lookahead == '\\') {
1269        bool is_r_dqt_esc_nwl = valid_symbols[R_DQT_ESC_NWL] && is_r;
1270        bool is_br_dqt_esc_nwl = valid_symbols[BR_DQT_ESC_NWL] && is_br;
1271        bool is_r_dqt_esc_seq = valid_symbols[R_DQT_ESC_SEQ] && is_r;
1272        bool is_br_dqt_esc_seq = valid_symbols[BR_DQT_ESC_SEQ] && is_br;
1273        if (is_r_dqt_esc_nwl || is_br_dqt_esc_nwl || is_r_dqt_esc_seq || is_br_dqt_esc_seq) {
1274            adv(scanner, lexer);
1275            if (is_nwl(lexer->lookahead)) {
1276                if (is_r_dqt_esc_nwl) {
1277                    mrk_end(scanner, lexer);
1278                    RET_SYM(R_DQT_ESC_NWL)
1279                }
1280                if (is_br_dqt_esc_nwl) {
1281                    mrk_end(scanner, lexer);
1282                    RET_SYM(BR_DQT_ESC_NWL)
1283                }
1284            }
1285            if (is_r_dqt_esc_seq) {
1286                return scn_dqt_esc_seq(scanner, lexer, R_DQT_ESC_SEQ);
1287            }
1288            if (is_br_dqt_esc_seq) {
1289                return scn_dqt_esc_seq(scanner, lexer, BR_DQT_ESC_SEQ);
1290            }
1291            return false;
1292        }
1293    } else if (lexer->lookahead == '|') {
1294        if (valid_symbols[R_BLK_LIT_BGN] && is_r) {
1295            return scn_blk_str_bgn(scanner, lexer, R_BLK_LIT_BGN);
1296        }
1297        if (valid_symbols[BR_BLK_LIT_BGN] && is_br) {
1298            return scn_blk_str_bgn(scanner, lexer, BR_BLK_LIT_BGN);
1299        }
1300    } else if (lexer->lookahead == '>') {
1301        if (valid_symbols[R_BLK_FLD_BGN] && is_r) {
1302            return scn_blk_str_bgn(scanner, lexer, R_BLK_FLD_BGN);
1303        }
1304        if (valid_symbols[BR_BLK_FLD_BGN] && is_br) {
1305            return scn_blk_str_bgn(scanner, lexer, BR_BLK_FLD_BGN);
1306        }
1307    }
1308
1309    bool maybe_sgl_pln_blk = (valid_symbols[R_SGL_PLN_STR_BLK] && is_r) ||
1310                             (valid_symbols[BR_SGL_PLN_STR_BLK] && is_br) || (valid_symbols[B_SGL_PLN_STR_BLK] && is_b);
1311    bool maybe_sgl_pln_flw = (valid_symbols[R_SGL_PLN_STR_FLW] && is_r) || (valid_symbols[BR_SGL_PLN_STR_FLW] && is_br);
1312    bool maybe_mtl_pln_blk = (valid_symbols[R_MTL_PLN_STR_BLK] && is_r) || (valid_symbols[BR_MTL_PLN_STR_BLK] && is_br);
1313    bool maybe_mtl_pln_flw = (valid_symbols[R_MTL_PLN_STR_FLW] && is_r) || (valid_symbols[BR_MTL_PLN_STR_FLW] && is_br);
1314
1315    if (maybe_sgl_pln_blk || maybe_sgl_pln_flw || maybe_mtl_pln_blk || maybe_mtl_pln_flw) {
1316        bool is_in_blk = maybe_sgl_pln_blk || maybe_mtl_pln_blk;
1317        bool (*is_plain_safe)(int32_t) = is_in_blk ? is_plain_safe_in_block : is_plain_safe_in_flow;
1318        if (scanner->cur_col - bgn_col == 0) {
1319            adv(scanner, lexer);
1320        }
1321        if (scanner->cur_col - bgn_col == 1) {
1322            bool is_plain_first =
1323                (is_ns_char(bgn_chr) && !is_c_indicator(bgn_chr)) ||
1324                ((bgn_chr == '-' || bgn_chr == '?' || bgn_chr == ':') && is_plain_safe(lexer->lookahead));
1325            if (!is_plain_first) {
1326                return false;
1327            }
1328            scanner->sch_stt = adv_sch_stt(scanner->sch_stt, scanner->cur_chr, &scanner->rlt_sch);
1329        } else {
1330            // no need to check the following cases:
1331            // ..X
1332            // ...X
1333            // --X
1334            // ---X
1335            // X: lookahead
1336            scanner->sch_stt = SCH_STT_FRZ; // must be RS_STR
1337        }
1338
1339        mrk_end(scanner, lexer);
1340
1341        for (;;) {
1342            if (!is_nwl(lexer->lookahead)) {
1343                if (scn_pln_cnt(scanner, lexer, is_plain_safe) != SCN_SUCC) {
1344                    break;
1345                }
1346            }
1347            if (lexer->lookahead == 0 || !is_nwl(lexer->lookahead)) {
1348                break;
1349            }
1350            for (;;) {
1351                if (is_nwl(lexer->lookahead)) {
1352                    adv_nwl(scanner, lexer);
1353                } else if (is_wsp(lexer->lookahead)) {
1354                    adv(scanner, lexer);
1355                } else {
1356                    break;
1357                }
1358            }
1359            if (lexer->lookahead == 0 || scanner->cur_col <= cur_ind) {
1360                break;
1361            }
1362            if (scanner->cur_col == 0 && scn_drs_doc_end(scanner, lexer)) {
1363                break;
1364            }
1365        }
1366
1367        if (scanner->end_row == bgn_row) {
1368            if (maybe_sgl_pln_blk) {
1369                MAY_UPD_IMP_COL();
1370                RET_SYM(is_r ? SGL_PLN_SYM(R, BLK) : is_br ? SGL_PLN_SYM(BR, BLK) : SGL_PLN_SYM(B, BLK));
1371            }
1372            if (maybe_sgl_pln_flw)
1373                RET_SYM(is_r ? SGL_PLN_SYM(R, FLW) : SGL_PLN_SYM(BR, FLW));
1374        } else {
1375            if (maybe_mtl_pln_blk) {
1376                MAY_UPD_IMP_COL();
1377                RET_SYM(is_r ? R_MTL_PLN_STR_BLK : BR_MTL_PLN_STR_BLK);
1378            }
1379            if (maybe_mtl_pln_flw)
1380                RET_SYM(is_r ? R_MTL_PLN_STR_FLW : BR_MTL_PLN_STR_FLW);
1381        }
1382
1383        return false;
1384    }
1385
1386    return !valid_symbols[ERR_REC];
1387}
1388
1389void *tree_sitter_yaml_external_scanner_create() {
1390    Scanner *scanner = ts_calloc(1, sizeof(Scanner));
1391    deserialize(scanner, NULL, 0);
1392    return scanner;
1393}
1394
1395void tree_sitter_yaml_external_scanner_destroy(void *payload) {
1396    Scanner *scanner = (Scanner *)payload;
1397    array_delete(&scanner->ind_len_stk);
1398    array_delete(&scanner->ind_typ_stk);
1399    ts_free(scanner);
1400}
1401
1402unsigned tree_sitter_yaml_external_scanner_serialize(void *payload, char *buffer) {
1403    Scanner *scanner = (Scanner *)payload;
1404    return serialize(scanner, buffer);
1405}
1406
1407void tree_sitter_yaml_external_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
1408    Scanner *scanner = (Scanner *)payload;
1409    deserialize(scanner, buffer, length);
1410}
1411
1412bool tree_sitter_yaml_external_scanner_scan(void *payload, TSLexer *lexer, const bool *valid_symbols) {
1413    Scanner *scanner = (Scanner *)payload;
1414    return scan(scanner, lexer, valid_symbols);
1415}