scanner.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. #include "tree_sitter/alloc.h"
  2. #include "tree_sitter/array.h"
  3. #include "tree_sitter/parser.h"
  4. #include <wctype.h>
  5. // #define DEBUG
  6. #ifdef DEBUG
  7. #define LOG(...) fprintf(stderr, __VA_ARGS__)
  8. #else
  9. #define LOG(...)
  10. #endif
  11. enum TokenType {
  12. AUTOMATIC_SEMICOLON,
  13. INDENT,
  14. OUTDENT,
  15. COMMA_OUTDENT,
  16. SIMPLE_STRING_START,
  17. SIMPLE_STRING_MIDDLE,
  18. SIMPLE_MULTILINE_STRING_START,
  19. INTERPOLATED_STRING_MIDDLE,
  20. INTERPOLATED_MULTILINE_STRING_MIDDLE,
  21. RAW_STRING_START,
  22. RAW_STRING_MIDDLE,
  23. RAW_STRING_MULTILINE_MIDDLE,
  24. SINGLE_LINE_STRING_END,
  25. MULTILINE_STRING_END,
  26. ELSE,
  27. CATCH,
  28. FINALLY,
  29. EXTENDS,
  30. DERIVES,
  31. WITH,
  32. ERROR_SENTINEL
  33. };
  34. const char* token_name[] = {
  35. "AUTOMATIC_SEMICOLON",
  36. "INDENT",
  37. "OUTDENT",
  38. "COMMA_OUTDENT",
  39. "SIMPLE_STRING_START",
  40. "SIMPLE_STRING_MIDDLE",
  41. "SIMPLE_MULTILINE_STRING_START",
  42. "INTERPOLATED_STRING_MIDDLE",
  43. "INTERPOLATED_MULTILINE_STRING_MIDDLE",
  44. "RAW_STRING_MIDDLE",
  45. "RAW_STRING_MULTILINE_MIDDLE",
  46. "SINGLE_LINE_STRING_END",
  47. "MULTILINE_STRING_END",
  48. "ELSE",
  49. "CATCH",
  50. "FINALLY",
  51. "EXTENDS",
  52. "DERIVES",
  53. "WITH",
  54. "ERROR_SENTINEL"
  55. };
  56. typedef struct {
  57. Array(int16_t) indents;
  58. int16_t last_indentation_size;
  59. int16_t last_newline_count;
  60. int16_t last_column;
  61. } Scanner;
  62. void *tree_sitter_scala_external_scanner_create() {
  63. Scanner *scanner = ts_calloc(1, sizeof(Scanner));
  64. array_init(&scanner->indents);
  65. scanner->last_indentation_size = -1;
  66. scanner->last_column = -1;
  67. return scanner;
  68. }
  69. void tree_sitter_scala_external_scanner_destroy(void *payload) {
  70. Scanner *scanner = payload;
  71. array_delete(&scanner->indents);
  72. ts_free(scanner);
  73. }
  74. unsigned tree_sitter_scala_external_scanner_serialize(void *payload, char *buffer) {
  75. Scanner *scanner = (Scanner*)payload;
  76. if ((scanner->indents.size + 3) * sizeof(int16_t) > TREE_SITTER_SERIALIZATION_BUFFER_SIZE) {
  77. return 0;
  78. }
  79. size_t size = 0;
  80. memcpy(buffer + size, &scanner->last_indentation_size, sizeof(int16_t));
  81. size += sizeof(int16_t);
  82. memcpy(buffer + size, &scanner->last_newline_count, sizeof(int16_t));
  83. size += sizeof(int16_t);
  84. memcpy(buffer + size, &scanner->last_column, sizeof(int16_t));
  85. size += sizeof(int16_t);
  86. for (unsigned i = 0; i < scanner->indents.size; i++) {
  87. memcpy(buffer + size, &scanner->indents.contents[i], sizeof(int16_t));
  88. size += sizeof(int16_t);
  89. }
  90. return size;
  91. }
  92. void tree_sitter_scala_external_scanner_deserialize(void *payload, const char *buffer,
  93. unsigned length) {
  94. Scanner *scanner = (Scanner*)payload;
  95. array_clear(&scanner->indents);
  96. scanner->last_indentation_size = -1;
  97. scanner->last_column = -1;
  98. scanner->last_newline_count = 0;
  99. if (length == 0) {
  100. return;
  101. }
  102. size_t size = 0;
  103. scanner->last_indentation_size = *(int16_t *)&buffer[size];
  104. size += sizeof(int16_t);
  105. scanner->last_newline_count = *(int16_t *)&buffer[size];
  106. size += sizeof(int16_t);
  107. scanner->last_column = *(int16_t *)&buffer[size];
  108. size += sizeof(int16_t);
  109. while (size < length) {
  110. array_push(&scanner->indents, *(int16_t *)&buffer[size]);
  111. size += sizeof(int16_t);
  112. }
  113. assert(size == length);
  114. }
  115. static inline void advance(TSLexer *lexer) { lexer->advance(lexer, false); }
  116. static inline void skip(TSLexer *lexer) { lexer->advance(lexer, true); }
  117. // Used to detect leading infix operators on continuation lines.
  118. // See: https://www.scala-lang.org/api/3.x/docs/changed-features/operators.html
  119. static bool is_op_char(int32_t c) {
  120. switch (c) {
  121. case '!': case '#': case '%': case '&':
  122. case '*': case '+': case '-': case '<':
  123. case '=': case '>': case '?': case '@':
  124. case '\\': case '^': case '|': case '~':
  125. case ':':
  126. return true;
  127. default:
  128. return false;
  129. }
  130. }
  131. // We enumerate 3 types of strings that we need to handle differently:
  132. // 1. Simple strings, `"..."` or `"""..."""`
  133. // 2. Interpolated strings, `s"..."` or `f"..."` or `foo"..."` or foo"""...""".
  134. // 3. Raw strings, `raw"..."`
  135. typedef enum {
  136. STRING_MODE_SIMPLE,
  137. STRING_MODE_INTERPOLATED,
  138. STRING_MODE_RAW
  139. } StringMode;
  140. static bool scan_string_content(TSLexer *lexer, bool is_multiline, StringMode string_mode) {
  141. LOG("scan_string_content(%d, %d, %c)\n", is_multiline, string_mode, lexer->lookahead);
  142. unsigned closing_quote_count = 0;
  143. for (;;) {
  144. if (lexer->lookahead == '"') {
  145. advance(lexer);
  146. closing_quote_count++;
  147. if (!is_multiline) {
  148. lexer->result_symbol = SINGLE_LINE_STRING_END;
  149. lexer->mark_end(lexer);
  150. return true;
  151. }
  152. if (closing_quote_count >= 3 && lexer->lookahead != '"') {
  153. lexer->result_symbol = MULTILINE_STRING_END;
  154. lexer->mark_end(lexer);
  155. return true;
  156. }
  157. } else if (lexer->lookahead == '$' && string_mode != STRING_MODE_SIMPLE) {
  158. switch (string_mode) {
  159. case STRING_MODE_INTERPOLATED:
  160. lexer->result_symbol = is_multiline ? INTERPOLATED_MULTILINE_STRING_MIDDLE : INTERPOLATED_STRING_MIDDLE;
  161. break;
  162. case STRING_MODE_RAW:
  163. lexer->result_symbol = is_multiline ? RAW_STRING_MULTILINE_MIDDLE : RAW_STRING_MIDDLE;
  164. break;
  165. default:
  166. assert(false);
  167. }
  168. lexer->mark_end(lexer);
  169. return true;
  170. } else {
  171. closing_quote_count = 0;
  172. if (lexer->lookahead == '\\') {
  173. // Multiline strings ignore escape sequences
  174. if (is_multiline || string_mode == STRING_MODE_RAW) {
  175. // FIXME: In raw string mode, we have to jump over escaped quotes.
  176. advance(lexer);
  177. // In single-line raw strings, `\"` is not translated to `"`, but it also does
  178. // not close the string. Likewise, `\\` is not translated to `\`, but it does
  179. // stop the second `\` from stopping a double-quote from closing the string.
  180. if (!is_multiline && string_mode == STRING_MODE_RAW &&
  181. (lexer->lookahead == '"' || lexer->lookahead == '\\')) {
  182. advance(lexer);
  183. }
  184. } else {
  185. lexer->result_symbol = string_mode == STRING_MODE_SIMPLE ? SIMPLE_STRING_MIDDLE : INTERPOLATED_STRING_MIDDLE;
  186. lexer->mark_end(lexer);
  187. return true;
  188. }
  189. // During error recovery and dynamic precedence resolution, the external
  190. // scanner will be invoked with all valid_symbols set to true, which means
  191. // we will be asked to scan a string token when we are not actually in a
  192. // string context. Here we detect these cases and return false.
  193. } else if (lexer->lookahead == '\n' && !is_multiline) {
  194. return false;
  195. } else if (lexer->eof(lexer)) {
  196. return false;
  197. } else {
  198. advance(lexer);
  199. }
  200. }
  201. }
  202. }
  203. static bool detect_comment_start(TSLexer *lexer) {
  204. lexer->mark_end(lexer);
  205. // Comments should not affect indentation
  206. if (lexer->lookahead == '/') {
  207. advance(lexer);
  208. if (lexer->lookahead == '/' || lexer -> lookahead == '*') {
  209. return true;
  210. }
  211. }
  212. return false;
  213. }
  214. static bool scan_word(TSLexer *lexer, const char* const word) {
  215. for (uint8_t i = 0; word[i] != '\0'; i++) {
  216. if (lexer->lookahead != word[i]) {
  217. return false;
  218. }
  219. advance(lexer);
  220. }
  221. return !iswalnum(lexer->lookahead);
  222. }
  223. // Returns true if the lookahead starts a leading infix operator — a symbolic
  224. // operator or back-ticked identifier followed by whitespace and then a
  225. // non-whitespace operand on the same line. Such a line is a continuation of
  226. // the previous expression, so neither AUTOMATIC_SEMICOLON nor OUTDENT should
  227. // fire ahead of it. Advances the lexer; the caller must not rely on position.
  228. static bool is_leading_infix_continuation(TSLexer *lexer) {
  229. if (is_op_char(lexer->lookahead)) {
  230. advance(lexer);
  231. while (is_op_char(lexer->lookahead)) {
  232. advance(lexer);
  233. }
  234. bool found_space = false;
  235. while (lexer->lookahead == ' ' || lexer->lookahead == '\t') {
  236. advance(lexer);
  237. found_space = true;
  238. }
  239. return found_space && !iswspace(lexer->lookahead) && !lexer->eof(lexer);
  240. }
  241. if (lexer->lookahead == '`') {
  242. advance(lexer);
  243. while (lexer->lookahead != '`' && !lexer->eof(lexer)) {
  244. advance(lexer);
  245. }
  246. if (lexer->lookahead != '`') {
  247. return false;
  248. }
  249. advance(lexer);
  250. bool found_space = false;
  251. while (lexer->lookahead == ' ' || lexer->lookahead == '\t') {
  252. advance(lexer);
  253. found_space = true;
  254. }
  255. return found_space && !iswspace(lexer->lookahead) && !lexer->eof(lexer);
  256. }
  257. return false;
  258. }
  259. static inline void debug_indents(Scanner *scanner) {
  260. LOG(" indents(%d): ", scanner->indents.size);
  261. for (unsigned i = 0; i < scanner->indents.size; i++) {
  262. LOG("%d ", scanner->indents.contents[i]);
  263. }
  264. LOG("\n");
  265. }
  266. bool tree_sitter_scala_external_scanner_scan(void *payload, TSLexer *lexer,
  267. const bool *valid_symbols) {
  268. #ifdef DEBUG
  269. {
  270. if (valid_symbols[ERROR_SENTINEL]) {
  271. LOG("entering tree_sitter_scala_external_scanner_scan. ERROR_SENTINEL is valid\n");
  272. } else {
  273. char debug_str[1024] = "entering tree_sitter_scala_external_scanner_scan valid symbols: ";
  274. for (unsigned i = 0; i < ERROR_SENTINEL; i++) {
  275. if (valid_symbols[i]) {
  276. strcat(debug_str, token_name[i]);
  277. strcat(debug_str, ", ");
  278. }
  279. }
  280. strcat(debug_str, "\n");
  281. LOG("%s", debug_str);
  282. }
  283. }
  284. #endif
  285. Scanner *scanner = (Scanner *)payload;
  286. int16_t prev = scanner->indents.size > 0 ? *array_back(&scanner->indents) : -1;
  287. int16_t newline_count = 0;
  288. int16_t indentation_size = 0;
  289. while (iswspace(lexer->lookahead)) {
  290. if (lexer->lookahead == '\n') {
  291. newline_count++;
  292. indentation_size = 0;
  293. }
  294. else {
  295. indentation_size++;
  296. }
  297. skip(lexer);
  298. }
  299. // Separate from OUTDENT because the scanner cannot distinguish a comma that
  300. // terminates an indented block (e.g. `map: x => f(x),`) from one that is
  301. // internal to it (e.g. `case EnumCase1, EnumCase2`). By using a distinct
  302. // token, tree-sitter only makes it valid in grammar contexts where comma
  303. // termination is expected (colon_argument, _indentable_expression).
  304. if (valid_symbols[COMMA_OUTDENT] && lexer->lookahead == ',' && prev != -1) {
  305. if (scanner->indents.size > 0) {
  306. array_pop(&scanner->indents);
  307. }
  308. lexer->mark_end(lexer);
  309. lexer->result_symbol = COMMA_OUTDENT;
  310. return true;
  311. }
  312. // Before advancing the lexer, check if we can double outdent
  313. if (
  314. valid_symbols[OUTDENT] &&
  315. (
  316. lexer->lookahead == 0 ||
  317. (
  318. prev != -1 &&
  319. (
  320. lexer->lookahead == ')' ||
  321. lexer->lookahead == ']' ||
  322. lexer->lookahead == '}'
  323. )
  324. ) ||
  325. (
  326. scanner->last_indentation_size != -1 &&
  327. prev != -1 &&
  328. scanner->last_indentation_size < prev
  329. )
  330. )
  331. ) {
  332. if (scanner->indents.size > 0) {
  333. array_pop(&scanner->indents);
  334. }
  335. LOG(" pop\n");
  336. LOG(" OUTDENT\n");
  337. lexer->result_symbol = OUTDENT;
  338. return true;
  339. }
  340. scanner->last_indentation_size = -1;
  341. if (
  342. valid_symbols[INDENT] &&
  343. newline_count > 0 &&
  344. (
  345. scanner->indents.size == 0 ||
  346. indentation_size > *array_back(&scanner->indents)
  347. )
  348. ) {
  349. if (detect_comment_start(lexer)) {
  350. return false;
  351. }
  352. array_push(&scanner->indents, indentation_size);
  353. lexer->result_symbol = INDENT;
  354. LOG(" INDENT\n");
  355. return true;
  356. }
  357. // This saves the indentation_size and newline_count so it can be used
  358. // in subsequent calls for multiple outdent or auto-semicolon.
  359. if (valid_symbols[OUTDENT] &&
  360. (lexer->lookahead == 0 ||
  361. (
  362. newline_count > 0 &&
  363. prev != -1 &&
  364. indentation_size < prev
  365. )
  366. )
  367. ) {
  368. lexer->mark_end(lexer);
  369. if (detect_comment_start(lexer)) {
  370. return false;
  371. }
  372. scanner->last_indentation_size = indentation_size;
  373. scanner->last_newline_count = newline_count;
  374. if (lexer->eof(lexer)) {
  375. scanner->last_column = -1;
  376. } else {
  377. scanner->last_column = (int16_t)lexer->get_column(lexer);
  378. }
  379. // Don't close the indented block when the next line starts with a leading
  380. // infix operator: that operator continues the previous expression.
  381. if (lexer->lookahead != 0 && is_leading_infix_continuation(lexer)) {
  382. return false;
  383. }
  384. if (scanner->indents.size > 0) {
  385. array_pop(&scanner->indents);
  386. }
  387. LOG(" pop\n");
  388. LOG(" OUTDENT\n");
  389. lexer->result_symbol = OUTDENT;
  390. return true;
  391. }
  392. // Recover newline_count from the outdent reset
  393. bool is_eof = lexer->eof(lexer);
  394. if (
  395. (
  396. scanner->last_newline_count > 0 &&
  397. (is_eof && scanner->last_column == -1)
  398. ) ||
  399. (!is_eof && lexer->get_column(lexer) == (uint32_t)scanner->last_column)
  400. ) {
  401. newline_count += scanner->last_newline_count;
  402. }
  403. scanner->last_newline_count = 0;
  404. if (valid_symbols[AUTOMATIC_SEMICOLON] && newline_count > 0) {
  405. // AUTOMATIC_SEMICOLON should not be issued in the middle of expressions
  406. // Thus, we exit this branch when encountering comments, else/catch clauses, etc.
  407. lexer->mark_end(lexer);
  408. lexer->result_symbol = AUTOMATIC_SEMICOLON;
  409. // Probably, a multi-line field expression, e.g.
  410. // a
  411. // .b
  412. // .c
  413. if (lexer->lookahead == '.') {
  414. return false;
  415. }
  416. // Single-line and multi-line comments
  417. if (lexer->lookahead == '/') {
  418. advance(lexer);
  419. if (lexer->lookahead == '/') {
  420. return false;
  421. }
  422. if (lexer->lookahead == '*') {
  423. advance(lexer);
  424. while (!lexer->eof(lexer)) {
  425. if (lexer->lookahead == '*') {
  426. advance(lexer);
  427. if (lexer->lookahead == '/') {
  428. advance(lexer);
  429. break;
  430. }
  431. } else {
  432. advance(lexer);
  433. }
  434. }
  435. while (iswspace(lexer->lookahead)) {
  436. if (lexer->lookahead == '\n' || lexer->lookahead == '\r') {
  437. return false;
  438. }
  439. skip(lexer);
  440. }
  441. // If some code is present at the same line after comment end,
  442. // we should still produce AUTOMATIC_SEMICOLON, e.g. in
  443. // val a = 1
  444. // /* comment */ val b = 2
  445. return true;
  446. }
  447. }
  448. if (valid_symbols[ELSE]) {
  449. return !scan_word(lexer, "else");
  450. }
  451. if (valid_symbols[CATCH]) {
  452. if (scan_word(lexer, "catch")) {
  453. return false;
  454. }
  455. }
  456. if (valid_symbols[FINALLY]) {
  457. if (scan_word(lexer, "finally")) {
  458. return false;
  459. }
  460. }
  461. if (valid_symbols[EXTENDS]) {
  462. if (scan_word(lexer, "extends")) {
  463. return false;
  464. }
  465. }
  466. if (valid_symbols[WITH]) {
  467. if (scan_word(lexer, "with")) {
  468. return false;
  469. }
  470. }
  471. if (valid_symbols[DERIVES]) {
  472. if (scan_word(lexer, "derives")) {
  473. return false;
  474. }
  475. }
  476. if (newline_count > 1) {
  477. return true;
  478. }
  479. // Don't insert automatic semicolon before leading infix operators:
  480. // - symbolic, e.g. || or &&
  481. // - back-ticked, e.g. `in`
  482. // Only suppress if the operator is followed by horizontal whitespace
  483. // and then non-newline content on the same line, meaning it has an operand.
  484. if (is_leading_infix_continuation(lexer)) {
  485. return false;
  486. }
  487. return true;
  488. }
  489. while (iswspace(lexer->lookahead)) {
  490. if (lexer->lookahead == '\n') {
  491. newline_count++;
  492. }
  493. skip(lexer);
  494. }
  495. if (valid_symbols[SIMPLE_STRING_START] && lexer->lookahead == '"') {
  496. advance(lexer);
  497. lexer->mark_end(lexer);
  498. if (lexer->lookahead == '"') {
  499. advance(lexer);
  500. if (lexer->lookahead == '"') {
  501. advance(lexer);
  502. lexer->result_symbol = SIMPLE_MULTILINE_STRING_START;
  503. lexer->mark_end(lexer);
  504. return true;
  505. }
  506. }
  507. lexer->result_symbol = SIMPLE_STRING_START;
  508. return true;
  509. }
  510. // We need two tokens of lookahead to determine if we are parsing a raw string,
  511. // the `raw` and the `"`, which is why we need to do it in the external scanner.
  512. if (valid_symbols[RAW_STRING_START] && lexer->lookahead == 'r') {
  513. advance(lexer);
  514. if (lexer->lookahead == 'a') {
  515. advance(lexer);
  516. if (lexer->lookahead == 'w') {
  517. advance(lexer);
  518. if (lexer->lookahead == '"') {
  519. lexer->mark_end(lexer);
  520. lexer->result_symbol = RAW_STRING_START;
  521. return true;
  522. }
  523. }
  524. }
  525. }
  526. if (valid_symbols[SIMPLE_STRING_MIDDLE]) {
  527. return scan_string_content(lexer, false, STRING_MODE_SIMPLE);
  528. }
  529. if (valid_symbols[INTERPOLATED_STRING_MIDDLE]) {
  530. return scan_string_content(lexer, false, STRING_MODE_INTERPOLATED);
  531. }
  532. if (valid_symbols[RAW_STRING_MIDDLE]) {
  533. return scan_string_content(lexer, false, STRING_MODE_RAW);
  534. }
  535. if (valid_symbols[RAW_STRING_MULTILINE_MIDDLE]) {
  536. return scan_string_content(lexer, true, STRING_MODE_RAW);
  537. }
  538. if (valid_symbols[INTERPOLATED_MULTILINE_STRING_MIDDLE]) {
  539. return scan_string_content(lexer, true, STRING_MODE_INTERPOLATED);
  540. }
  541. // We still need to handle the simple multiline string case, but there is
  542. // no `MULTILINE_STRING_MIDDLE` token, and `MULTILINE_STRING_END` is used
  543. // by all three of simple raw, and interpolated multiline strings. So this
  544. // check needs to come after the `INTERPOLATED_MULTILINE_STRING_MIDDLE` and
  545. // `RAW_STRING_MULTILINE_MIDDLE` check, so that we can be sure we are in a
  546. // simple multiline string context.
  547. if (valid_symbols[MULTILINE_STRING_END]) {
  548. return scan_string_content(lexer, true, STRING_MODE_SIMPLE);
  549. }
  550. return false;
  551. }
  552. //