krz/orgstar

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

Sources/TreeSitterScanners/lua/scanner.c

abca8dc581329472f7fb8ccd3af147e5fb882f29
orgstar/Sources/TreeSitterScanners/lua/scanner.c history · blame · raw

195 lines · 4559 bytes

  1#include <stdio.h>
  2#include "tree_sitter/alloc.h"
  3#include "tree_sitter/parser.h"
  4#include <wctype.h>
  5
  6enum TokenType {
  7  BLOCK_COMMENT_START,
  8  BLOCK_COMMENT_CONTENT,
  9  BLOCK_COMMENT_END,
 10
 11  BLOCK_STRING_START,
 12  BLOCK_STRING_CONTENT,
 13  BLOCK_STRING_END,
 14};
 15
 16static inline void consume(TSLexer *lexer) { lexer->advance(lexer, false); }
 17
 18static inline void skip(TSLexer *lexer) { lexer->advance(lexer, true); }
 19
 20static inline bool consume_char(char c, TSLexer *lexer) {
 21  if (lexer->lookahead != c) {
 22    return false;
 23  }
 24
 25  consume(lexer);
 26  return true;
 27}
 28
 29static inline uint8_t consume_and_count_char(char c, TSLexer *lexer) {
 30  uint8_t count = 0;
 31  while (lexer->lookahead == c) {
 32    ++count;
 33    consume(lexer);
 34  }
 35  return count;
 36}
 37
 38static inline void skip_whitespaces(TSLexer *lexer) {
 39  while (iswspace(lexer->lookahead)) {
 40    skip(lexer);
 41  }
 42}
 43
 44typedef struct {
 45  char ending_char;
 46  uint8_t level_count;
 47} Scanner;
 48
 49static inline void reset_state(Scanner *scanner) {
 50  scanner->ending_char = 0;
 51  scanner->level_count = 0;
 52}
 53
 54void *tree_sitter_lua_external_scanner_create() {
 55  Scanner *scanner = ts_calloc(1, sizeof(Scanner));
 56  return scanner;
 57}
 58
 59void tree_sitter_lua_external_scanner_destroy(void *payload) {
 60  Scanner *scanner = (Scanner *)payload;
 61  ts_free(scanner);
 62}
 63
 64unsigned tree_sitter_lua_external_scanner_serialize(void *payload, char *buffer) {
 65  Scanner *scanner = (Scanner *)payload;
 66  buffer[0] = scanner->ending_char;
 67  buffer[1] = (char)scanner->level_count;
 68  return 2;
 69}
 70
 71void tree_sitter_lua_external_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
 72  Scanner *scanner = (Scanner *)payload;
 73  if (length == 0) return;
 74  scanner->ending_char = buffer[0];
 75  if (length == 1) return;
 76  scanner->level_count = buffer[1];
 77}
 78
 79static bool scan_block_start(Scanner *scanner, TSLexer *lexer) {
 80  if (consume_char('[', lexer)) {
 81    uint8_t level = consume_and_count_char('=', lexer);
 82
 83    if (consume_char('[', lexer)) {
 84      scanner->level_count = level;
 85      return true;
 86    }
 87  }
 88
 89  return false;
 90}
 91
 92static bool scan_block_end(Scanner *scanner, TSLexer *lexer) {
 93  if (consume_char(']', lexer)) {
 94    uint8_t level = consume_and_count_char('=', lexer);
 95
 96    if (scanner->level_count == level && consume_char(']', lexer)) {
 97      return true;
 98    }
 99  }
100
101  return false;
102}
103
104static bool scan_block_content(Scanner *scanner, TSLexer *lexer) {
105  while (lexer->lookahead != 0) {
106    if (lexer->lookahead == ']') {
107      lexer->mark_end(lexer);
108
109      if (scan_block_end(scanner, lexer)) {
110        return true;
111      }
112    } else {
113      consume(lexer);
114    }
115  }
116
117  return false;
118}
119
120static bool scan_comment_start(Scanner *scanner, TSLexer *lexer) {
121  if (consume_char('-', lexer) && consume_char('-', lexer)) {
122    lexer->mark_end(lexer);
123
124    if (scan_block_start(scanner, lexer)) {
125      lexer->mark_end(lexer);
126      lexer->result_symbol = BLOCK_COMMENT_START;
127      return true;
128    }
129  }
130
131  return false;
132}
133
134static bool scan_comment_content(Scanner *scanner, TSLexer *lexer) {
135  if (scanner->ending_char == 0) { // block comment
136    if (scan_block_content(scanner, lexer)) {
137      lexer->result_symbol = BLOCK_COMMENT_CONTENT;
138      return true;
139    }
140
141    return false;
142  }
143
144  while (lexer->lookahead != 0) {
145    if (lexer->lookahead == scanner->ending_char) {
146      reset_state(scanner);
147      lexer->result_symbol = BLOCK_COMMENT_CONTENT;
148      return true;
149    }
150
151    consume(lexer);
152  }
153
154  return false;
155}
156
157bool tree_sitter_lua_external_scanner_scan(void *payload, TSLexer *lexer, const bool *valid_symbols) {
158  Scanner *scanner = (Scanner *)payload;
159
160  if (valid_symbols[BLOCK_STRING_END] && scan_block_end(scanner, lexer)) {
161    reset_state(scanner);
162    lexer->result_symbol = BLOCK_STRING_END;
163    return true;
164  }
165
166  if (valid_symbols[BLOCK_STRING_CONTENT] && scan_block_content(scanner, lexer)) {
167    lexer->result_symbol = BLOCK_STRING_CONTENT;
168    return true;
169  }
170
171  if (valid_symbols[BLOCK_COMMENT_END] && scanner->ending_char == 0 && scan_block_end(scanner, lexer)) {
172    reset_state(scanner);
173    lexer->result_symbol = BLOCK_COMMENT_END;
174    return true;
175  }
176
177  if (valid_symbols[BLOCK_COMMENT_CONTENT] && scan_comment_content(scanner, lexer)) {
178    return true;
179  }
180
181  skip_whitespaces(lexer);
182
183  if (valid_symbols[BLOCK_STRING_START] && scan_block_start(scanner, lexer)) {
184    lexer->result_symbol = BLOCK_STRING_START;
185    return true;
186  }
187
188  if (valid_symbols[BLOCK_COMMENT_START]) {
189    if (scan_comment_start(scanner, lexer)) {
190      return true;
191    }
192  }
193
194  return false;
195}