@konomanoasa/tree-sitter-yaml 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/scanner.c CHANGED
@@ -1,8 +1,11 @@
1
1
  #include "tree_sitter/alloc.h"
2
2
  #include "tree_sitter/parser.h"
3
+ #include <stddef.h>
3
4
  #include <stdint.h>
4
5
  #include <string.h>
5
6
 
7
+ #define COUNT(array) (sizeof(array) / sizeof(*(array)))
8
+
6
9
  enum Token {
7
10
  LINE_BREAK,
8
11
  END_OF_FILE,
@@ -17,12 +20,18 @@ enum Token {
17
20
  RESTORE_INDENT,
18
21
  MAPPING_START,
19
22
  MAPPING_END,
23
+ MAPPING_IN_MAPPING_END,
24
+ MAPPING_IN_SEQUENCE_END,
25
+ MAPPING_IN_SHARED_END,
20
26
  PAIR_START,
21
27
  SEQUENCE_START,
22
28
  SEQUENCE_END,
29
+ SEQUENCE_IN_MAPPING_END,
30
+ SEQUENCE_IN_SEQUENCE_END,
31
+ SEQUENCE_IN_SHARED_END,
23
32
  ENTRY_START,
24
- VALUE_START,
25
- SEQUENCE_VALUE_START,
33
+ BLOCK_OUT_VALUE_START,
34
+ BLOCK_IN_VALUE_START,
26
35
  EMPTY_BLOCK_NODE,
27
36
  EXPLICIT_VALUE_START,
28
37
  INVALID_COMPACT_START,
@@ -84,7 +93,9 @@ enum Token {
84
93
  BOUNDARY_CHECK,
85
94
  DOCUMENT_CONTENT_END,
86
95
  DOCUMENT_COMPACT_START,
87
- UNEXPECTED_CONTENT_START,
96
+ UNEXPECTED_DOCUMENT_CONTENT_START,
97
+ UNEXPECTED_COLLECTION_CONTENT_START,
98
+ COLLECTION_CONTENT_END,
88
99
  PROPERTIES_START,
89
100
  PROPERTIES_END,
90
101
  BLOCK_PROPERTIES_END,
@@ -133,6 +144,7 @@ enum Token {
133
144
  TAG_PREFIX_END,
134
145
  DIRECTIVE_PARAMETER,
135
146
  UNFINISHED_UNEXPECTED_DOCUMENT_CONTENT_START,
147
+ UNFINISHED_UNEXPECTED_COLLECTION_CONTENT_START,
136
148
  UNFINISHED_INVALID_DOCUMENT_COLLECTION_START,
137
149
  UNFINISHED_DUPLICATE_ANCHOR_START,
138
150
  UNFINISHED_DUPLICATE_TAG_START,
@@ -235,8 +247,9 @@ enum Mode {
235
247
  DIRECTIVE_PARAMETERS
236
248
  };
237
249
  enum HandleForm { PRIMARY_HANDLE = 1, SECONDARY_HANDLE, NAMED_HANDLE };
238
- /* Appending ":" can move these continued properties into an implicit key. */
239
250
  enum PropertyKey { ANCHOR_KEY = 1, TAG_KEY = 2 };
251
+ enum KeyState { KEY_NONE, KEY_ENDED, BLOCK_KEY_ENDED };
252
+ enum PrefixIssue { PREFIX_INDENTATION = 1, PREFIX_TAB = 2 };
240
253
  enum DirectiveKind { YAML_DIRECTIVE = 1, TAG_DIRECTIVE, RESERVED_DIRECTIVE };
241
254
  enum Boundary {
242
255
  NO_BOUNDARY,
@@ -247,10 +260,11 @@ enum Boundary {
247
260
  };
248
261
  #define SCANNER_FIELDS(F) \
249
262
  F(int64_t, indent, 8, 1) \
263
+ F(uint16_t, outdent_count, 2, 0) \
264
+ F(bool, outdenting, 1, 0) \
250
265
  F(uint32_t, flow, 4, 0) \
251
266
  F(uint8_t, mode, 1, 0) \
252
267
  F(bool, line, 1, 0) \
253
- F(bool, document, 1, 0) \
254
268
  F(uint32_t, column, 4, 0) \
255
269
  F(bool, prefix, 1, 0) \
256
270
  F(bool, first, 1, 0) \
@@ -269,7 +283,9 @@ enum Boundary {
269
283
  F(bool, line_mapping_key, 1, 0) \
270
284
  F(bool, prefix_invalid, 1, 0) \
271
285
  F(bool, separated, 1, 0) \
272
- F(bool, key_done, 1, 0) \
286
+ F(uint8_t, key_state, 1, 0) \
287
+ F(bool, colon_line_only, 1, 0) \
288
+ F(bool, first_pair, 1, 0) \
273
289
  F(int64_t, block_indent, 8, 1) \
274
290
  F(bool, block_explicit_indent, 1, 0) \
275
291
  F(bool, header_separated, 1, 0) \
@@ -278,14 +294,15 @@ enum Boundary {
278
294
  F(bool, block_empty, 1, 0) \
279
295
  F(bool, block_prefix, 1, 0) \
280
296
  F(uint32_t, block_layout_lines, 4, 0) \
297
+ F(bool, block_marker_eof, 1, 0) \
281
298
  F(uint8_t, boundary, 1, 0) \
282
299
  F(bool, boundary_checked, 1, 0) \
283
300
  F(uint8_t, boundary_pending, 1, 0) \
284
301
  F(bool, document_started, 1, 0) \
302
+ F(bool, document_start_line, 1, 0) \
285
303
  F(bool, document_content, 1, 0) \
286
304
  F(bool, after_document_end, 1, 0) \
287
305
  F(bool, block_out, 1, 0) \
288
- F(bool, property_colon_content, 1, 0) \
289
306
  F(uint8_t, handle_form, 1, 0) \
290
307
  F(bool, properties_ready, 1, 0) \
291
308
  F(bool, property_separation_notified, 1, 0) \
@@ -298,7 +315,7 @@ enum Boundary {
298
315
  F(bool, explicit_document_required, 1, 0) \
299
316
  F(bool, eof_continuation, 1, 0) \
300
317
  F(bool, block_eof, 1, 0) \
301
- F(bool, prefix_eof, 1, 0) \
318
+ F(uint8_t, prefix_eof, 1, 0) \
302
319
  F(int64_t, provisional_indent, 8, 2) \
303
320
  F(uint8_t, block_kind, 1, 0)
304
321
 
@@ -307,7 +324,12 @@ enum {
307
324
  IMPLICIT_KEY_LIMIT = 1024,
308
325
  IMPLICIT_KEY_WORDS = IMPLICIT_KEY_LIMIT / 64 + 1,
309
326
  SCANNER_STATE_BYTES = 0 SCANNER_FIELDS(FIELD_BYTES),
310
- SCANNER_KEY_BYTES = IMPLICIT_KEY_LIMIT / 8 + 1
327
+ SCANNER_KEY_BYTES = IMPLICIT_KEY_LIMIT / 8 + 1,
328
+ OUTDENT_LIMIT =
329
+ (TREE_SITTER_SERIALIZATION_BUFFER_SIZE -
330
+ SCANNER_STATE_BYTES -
331
+ SCANNER_KEY_BYTES) /
332
+ 4
311
333
  };
312
334
  #undef FIELD_BYTES
313
335
 
@@ -315,6 +337,7 @@ enum {
315
337
  typedef struct {
316
338
  SCANNER_FIELDS(DECLARE_FIELD)
317
339
  uint64_t implicit_keys[IMPLICIT_KEY_WORDS];
340
+ uint32_t outdent_origins[OUTDENT_LIMIT];
318
341
  } Scanner;
319
342
  #undef DECLARE_FIELD
320
343
 
@@ -326,6 +349,7 @@ typedef struct {
326
349
  uint64_t marked_characters;
327
350
  bool broken, marked_broken;
328
351
  bool separated, marked_separation;
352
+ bool allocation_failed;
329
353
  } Cursor;
330
354
 
331
355
  static bool blank(int32_t c) {
@@ -343,11 +367,6 @@ static bool flow_indicator(int32_t c) {
343
367
  static bool flow_entry_end(int32_t c) {
344
368
  return c == ',' || c == ']' || c == '}';
345
369
  }
346
- static bool colon_boundary(TSLexer *l, bool flow) {
347
- return l->eof(l) ||
348
- space(l->lookahead) ||
349
- (flow && flow_indicator(l->lookahead));
350
- }
351
370
  static bool invalid_encoding(int32_t c) {
352
371
  return c < 0 || c > 0x10ffff || (c >= 0xd800 && c <= 0xdfff);
353
372
  }
@@ -358,41 +377,56 @@ static bool invalid_quoted(int32_t c) {
358
377
  static bool invalid_unquoted(int32_t c) {
359
378
  return invalid_quoted(c) ||
360
379
  (c >= 0x7f && c <= 0x9f && c != 0x85) ||
361
- c ==
362
- 0xfeff ||
363
- c ==
364
- 0xfffe ||
380
+ c == 0xfeff ||
381
+ c == 0xfffe ||
365
382
  c == 0xffff;
366
383
  }
367
384
 
368
- static bool
369
- block_value_follows(const Scanner *s, const TSLexer *l, const bool *valid) {
370
- if (l->eof(l))
371
- return false;
372
- if (
373
- valid[EXPLICIT_VALUE_START] &&
374
- s->line &&
375
- s->line_indent ==
376
- s->indent &&
377
- s->line_head == ':'
378
- )
379
- return true;
380
- return (valid[VALUE_START] || valid[SEQUENCE_VALUE_START]) &&
381
- (!s->line ||
382
- s->line_indent >
383
- s->indent ||
384
- (valid[VALUE_START] &&
385
- s->line_indent ==
386
- s->indent &&
387
- s->line_head == '-'));
388
- }
389
-
390
- static bool property_line_follows(const Scanner *s) {
385
+ static int64_t outdent_boundary(const Scanner *s) {
386
+ int64_t boundary = -1;
387
+ for (unsigned i = 0; i < s->outdent_count; i++)
388
+ if (s->outdent_origins[i] > boundary) boundary = s->outdent_origins[i];
389
+ return boundary;
390
+ }
391
+ static int64_t content_indent(const Scanner *s) {
392
+ int64_t boundary = outdent_boundary(s);
393
+ return s->indent > boundary ? s->indent : boundary;
394
+ }
395
+ static bool indicator_line(const Scanner *s, int32_t indicator) {
396
+ return s->line &&
397
+ s->line_indent == s->indent &&
398
+ s->line_indent > outdent_boundary(s) &&
399
+ s->line_head == indicator;
400
+ }
401
+ static bool eof_pending(const Scanner *s) {
402
+ return s->eof_continuation || s->boundary_pending;
403
+ }
404
+ static bool block_value_follows(
405
+ const Scanner *s,
406
+ const bool *valid,
407
+ bool line,
408
+ uint32_t line_indent,
409
+ int32_t line_head
410
+ ) {
411
+ if (line && line_indent <= outdent_boundary(s)) return false;
412
+ bool indicator = line && line_indent == s->indent;
413
+ if (valid[EXPLICIT_VALUE_START] && indicator && line_head == ':') return true;
414
+ return (valid[BLOCK_OUT_VALUE_START] || valid[BLOCK_IN_VALUE_START]) &&
415
+ (!line ||
416
+ line_indent > s->indent ||
417
+ (valid[BLOCK_OUT_VALUE_START] && indicator && line_head == '-'));
418
+ }
419
+ static bool property_line_follows(
420
+ const Scanner *s,
421
+ bool line,
422
+ uint32_t line_indent,
423
+ int32_t line_head
424
+ ) {
391
425
  return s->flow ||
392
- !s->line ||
393
- s->line_indent >
394
- s->indent ||
395
- (s->block_out && s->line_indent == s->indent && s->line_head == '-');
426
+ !line ||
427
+ (line_indent > outdent_boundary(s) &&
428
+ (line_indent > s->indent ||
429
+ (s->block_out && line_indent == s->indent && line_head == '-')));
396
430
  }
397
431
 
398
432
  static void cursor_advance(TSLexer *lexer, bool skip) {
@@ -430,14 +464,19 @@ static void cursor_start_line(TSLexer *lexer) {
430
464
  }
431
465
 
432
466
  static bool emit(TSLexer *l, const bool *valid, enum Token token) {
433
- if (!valid[token])
434
- return false;
467
+ if (!valid[token]) return false;
435
468
  l->result_symbol = token;
436
469
  return true;
437
470
  }
438
471
  static void step(TSLexer *l) {
439
472
  l->advance(l, false);
440
473
  }
474
+ static bool step_boundary(TSLexer *l, bool flow) {
475
+ step(l);
476
+ return l->eof(l) ||
477
+ space(l->lookahead) ||
478
+ (flow && flow_indicator(l->lookahead));
479
+ }
441
480
  static bool finish(TSLexer *l, const bool *valid, enum Token token) {
442
481
  l->mark_end(l);
443
482
  return emit(l, valid, token);
@@ -451,12 +490,16 @@ static uint32_t count_spaces(TSLexer *l) {
451
490
  return spaces;
452
491
  }
453
492
  static void skip_blanks(TSLexer *l) {
454
- while (blank(l->lookahead))
455
- step(l);
493
+ while (blank(l->lookahead)) step(l);
494
+ }
495
+ static void skip_line(TSLexer *l) {
496
+ while (!l->eof(l) && !newline(l->lookahead)) step(l);
497
+ }
498
+ static bool layout_follows(TSLexer *l) {
499
+ return l->eof(l) || newline(l->lookahead) || l->lookahead == '#';
456
500
  }
457
501
  static bool take(TSLexer *l, const bool *valid, enum Token token) {
458
- if (!valid[token])
459
- return false;
502
+ if (!valid[token]) return false;
460
503
  step(l);
461
504
  return finish(l, valid, token);
462
505
  }
@@ -473,31 +516,55 @@ static bool scan_separation(TSLexer *l, const bool *valid) {
473
516
  skip_blanks(l);
474
517
  return finish(l, valid, SEPARATION);
475
518
  }
519
+ static bool separation_missing(const Scanner *s) {
520
+ return !s->separated && !s->property_separation_notified;
521
+ }
522
+ static bool emit_missing_separation(Scanner *s, TSLexer *l, const bool *valid) {
523
+ s->property_separation_notified = true;
524
+ return emit(l, valid, MISSING_SEPARATION);
525
+ }
526
+ static void skip_line_break(TSLexer *l) {
527
+ int32_t first = l->lookahead;
528
+ step(l);
529
+ if (first == '\r' && l->lookahead == '\n') step(l);
530
+ }
531
+ static bool skip_layout_lines(TSLexer *l, bool line, uint32_t *line_indent) {
532
+ for (;;) {
533
+ if (line) *line_indent = count_spaces(l);
534
+ skip_blanks(l);
535
+ if (l->lookahead == '#') skip_line(l);
536
+ if (!newline(l->lookahead)) return line;
537
+ skip_line_break(l);
538
+ line = true;
539
+ }
540
+ }
541
+ static bool line_break(TSLexer *l, const bool *valid, enum Token token) {
542
+ skip_line_break(l);
543
+ return finish(l, valid, token);
544
+ }
545
+ static void reset_line(Scanner *s) {
546
+ s->line = true;
547
+ s->document_start_line = false;
548
+ s->line_context = false;
549
+ s->line_prefixed = false;
550
+ s->line_indent = 0;
551
+ s->line_mapping_key = false;
552
+ s->prefix_invalid = false;
553
+ s->after_document_end = false;
554
+ if (!s->flow) s->colon_line_only = true;
555
+ }
476
556
  static bool
477
557
  close_flow(Scanner *s, TSLexer *l, const bool *valid, enum Token token) {
478
- bool closed = token == FLOW_SEQUENCE_CLOSE || token == FLOW_MAPPING_CLOSE
558
+ s->flow--;
559
+ s->json = s->flow > 0;
560
+ s->line = false;
561
+ return token == FLOW_SEQUENCE_CLOSE || token == FLOW_MAPPING_CLOSE
479
562
  ? take(l, valid, token)
480
563
  : emit(l, valid, token);
481
- if (closed) {
482
- s->flow--;
483
- s->json = true;
484
- /* Missing closers must also mark the rest of this line as content. */
485
- s->line = false;
486
- }
487
- return closed;
488
564
  }
489
- static bool emit_closing(
490
- Scanner *s,
491
- TSLexer *l,
492
- const bool *valid,
493
- const enum Token *closings,
494
- size_t count
495
- ) {
496
- for (size_t i = 0; i < count; i++) {
497
- enum Token token = closings[i];
498
- if (!valid[token])
499
- continue;
500
- switch (token) {
565
+ static bool
566
+ emit_structure(Scanner *s, TSLexer *l, const bool *valid, enum Token token) {
567
+ switch (token) {
501
568
  case MISSING_FLOW_SEQUENCE_CLOSE:
502
569
  case MISSING_FLOW_MAPPING_CLOSE:
503
570
  case INCOMPLETE_FLOW_SEQUENCE_CLOSE:
@@ -505,25 +572,88 @@ static bool emit_closing(
505
572
  return close_flow(s, l, valid, token);
506
573
  case DEDENT:
507
574
  case OUTDENT:
575
+ if (token == OUTDENT && !s->outdenting) {
576
+ if (s->outdent_count == OUTDENT_LIMIT) return false;
577
+ s->outdent_origins[s->outdent_count++] = (uint32_t)s->indent;
578
+ s->outdenting = true;
579
+ }
508
580
  s->indent--;
509
- if (s->indent <= s->provisional_indent)
510
- s->provisional_indent = -2;
581
+ if (s->indent <= s->provisional_indent) s->provisional_indent = -2;
511
582
  break;
512
583
  case RESTORE_INDENT:
584
+ s->indent++;
585
+ if (
586
+ s->outdent_count &&
587
+ s->indent == s->outdent_origins[s->outdent_count - 1]
588
+ )
589
+ s->outdent_count--;
590
+ break;
513
591
  case INDENT:
514
592
  s->indent++;
515
593
  break;
594
+ case MAPPING_START:
595
+ case SEQUENCE_START:
596
+ s->outdenting = false;
597
+ break;
598
+ case MAPPING_END:
599
+ case MAPPING_IN_MAPPING_END:
600
+ case MAPPING_IN_SEQUENCE_END:
601
+ case MAPPING_IN_SHARED_END:
602
+ s->first_pair = false;
603
+ s->colon_line_only = true;
604
+ break;
605
+ case SEQUENCE_END:
606
+ case SEQUENCE_IN_MAPPING_END:
607
+ case SEQUENCE_IN_SEQUENCE_END:
608
+ case SEQUENCE_IN_SHARED_END:
609
+ s->colon_line_only = true;
610
+ break;
516
611
  default:
517
612
  break;
518
- }
519
- return emit(l, valid, token);
520
613
  }
614
+ return emit(l, valid, token);
615
+ }
616
+ static bool emit_first(
617
+ Scanner *s,
618
+ TSLexer *l,
619
+ const bool *valid,
620
+ const enum Token *tokens,
621
+ size_t count
622
+ ) {
623
+ for (size_t i = 0; i < count; i++)
624
+ if (valid[tokens[i]]) return emit_structure(s, l, valid, tokens[i]);
625
+ return false;
626
+ }
627
+ static const enum Token mapping_endings[] = {
628
+ MAPPING_END,
629
+ MAPPING_IN_MAPPING_END,
630
+ MAPPING_IN_SEQUENCE_END,
631
+ MAPPING_IN_SHARED_END
632
+ };
633
+ static const enum Token sequence_endings[] = {
634
+ SEQUENCE_END,
635
+ SEQUENCE_IN_MAPPING_END,
636
+ SEQUENCE_IN_SEQUENCE_END,
637
+ SEQUENCE_IN_SHARED_END
638
+ };
639
+ static bool end_collection(Scanner *s, TSLexer *l, const bool *valid) {
640
+ return emit_first(s, l, valid, mapping_endings, COUNT(mapping_endings)) ||
641
+ emit_first(s, l, valid, sequence_endings, COUNT(sequence_endings));
642
+ }
643
+ static bool restore_indent(Scanner *s, TSLexer *l, const bool *valid) {
644
+ static const enum Token restorations[] = {DEDENT, RESTORE_INDENT};
645
+ return emit_first(s, l, valid, restorations, COUNT(restorations));
646
+ }
647
+ static bool
648
+ any_valid(const bool *valid, const enum Token *tokens, size_t count) {
649
+ for (size_t i = 0; i < count; i++)
650
+ if (valid[tokens[i]]) return true;
521
651
  return false;
522
652
  }
523
653
  static bool start_plain(Scanner *s, TSLexer *l, const bool *valid) {
524
- if (!valid[PLAIN_START])
525
- return false;
654
+ if (!valid[PLAIN_START]) return false;
526
655
  s->eof_continuation = false;
656
+ if (!s->flow) s->colon_line_only = false;
527
657
  s->mode = PLAIN;
528
658
  s->first = true;
529
659
  s->json = false;
@@ -531,12 +661,10 @@ static bool start_plain(Scanner *s, TSLexer *l, const bool *valid) {
531
661
  }
532
662
  static bool scan_invalid_character(TSLexer *l, const bool *valid, bool quoted) {
533
663
  bool (*invalid)(int32_t) = quoted ? invalid_quoted : invalid_unquoted;
534
- if (l->eof(l) || !invalid(l->lookahead))
535
- return false;
664
+ if (l->eof(l) || !invalid(l->lookahead)) return false;
536
665
  bool undecodable = invalid_encoding(l->lookahead);
537
666
  enum Token token = undecodable ? INVALID_ENCODING : INVALID_CHARACTER;
538
- if (!valid[token])
539
- return false;
667
+ if (!valid[token]) return false;
540
668
  do {
541
669
  step(l);
542
670
  } while (
@@ -548,8 +676,7 @@ static bool scan_invalid_character(TSLexer *l, const bool *valid, bool quoted) {
548
676
  }
549
677
 
550
678
  static bool scan_line_text(TSLexer *l, const bool *valid, enum Token token) {
551
- if (scan_invalid_character(l, valid, false))
552
- return true;
679
+ if (scan_invalid_character(l, valid, false)) return true;
553
680
  do {
554
681
  step(l);
555
682
  } while (
@@ -560,12 +687,10 @@ static bool scan_line_text(TSLexer *l, const bool *valid, enum Token token) {
560
687
 
561
688
  static enum Boundary document_marker_tail(TSLexer *l, int32_t marker) {
562
689
  for (unsigned i = 0; i < 2; i++) {
563
- if (l->lookahead != marker)
564
- return NO_BOUNDARY;
690
+ if (l->lookahead != marker) return NO_BOUNDARY;
565
691
  step(l);
566
692
  }
567
- if (!space(l->lookahead) && !l->eof(l))
568
- return NO_BOUNDARY;
693
+ if (!space(l->lookahead) && !l->eof(l)) return NO_BOUNDARY;
569
694
  return marker == '-' ? DOCUMENT_START_LINE : DOCUMENT_END_LINE;
570
695
  }
571
696
  static enum Boundary document_marker(TSLexer *l) {
@@ -575,33 +700,64 @@ static enum Boundary document_marker(TSLexer *l) {
575
700
  step(l);
576
701
  return document_marker_tail(l, marker);
577
702
  }
703
+ /* Requires document_marker() lookahead. */
704
+ static bool partial_marker(const TSLexer *l, int32_t first) {
705
+ return (first == '-' || first == '.') && l->eof(l);
706
+ }
578
707
  static enum Boundary line_boundary(const Scanner *s, TSLexer *l) {
579
- if (l->lookahead == '-' || l->lookahead == '.')
580
- return document_marker(l);
708
+ if (l->lookahead == '-' || l->lookahead == '.') return document_marker(l);
581
709
  if (s->flow || (s->mode != NORMAL && s->mode != BLOCK_BODY))
582
710
  return NO_BOUNDARY;
583
711
  if (l->lookahead == '%')
584
712
  return s->mode == NORMAL ? DIRECTIVE_LINE : NO_BOUNDARY;
585
713
  return l->lookahead == 0xfeff ? STREAM_BOM : NO_BOUNDARY;
586
714
  }
715
+ static bool line_head_boundary(
716
+ const Scanner *s,
717
+ TSLexer *l,
718
+ bool line,
719
+ int32_t *line_head
720
+ ) {
721
+ int32_t first = *line_head = l->lookahead;
722
+ if (first == '-' && line && !s->flow) {
723
+ bool column_zero = l->get_column(l) == 0;
724
+ if (!step_boundary(l, false)) *line_head = 0;
725
+ return column_zero && document_marker_tail(l, first) != NO_BOUNDARY;
726
+ }
727
+ return l->get_column(l) == 0 && line_boundary(s, l) != NO_BOUNDARY;
728
+ }
729
+ /* Comment edits must invalidate preceding node reductions. */
730
+ static bool start_comment(
731
+ Scanner *s,
732
+ TSLexer *l,
733
+ const bool *valid,
734
+ enum Mode return_mode,
735
+ bool missing_separation
736
+ ) {
737
+ skip_line(l);
738
+ s->mode = COMMENT_BEGIN;
739
+ s->return_mode = (uint8_t)return_mode;
740
+ s->first = missing_separation;
741
+ return emit(l, valid, COMMENT_START);
742
+ }
587
743
 
588
744
  static enum Token node_start(int32_t c) {
589
745
  switch (c) {
590
- case '[':
591
- return FLOW_SEQUENCE_START;
592
- case '{':
593
- return FLOW_MAPPING_START;
594
- case '\'':
595
- return SINGLE_START;
596
- case '"':
597
- return DOUBLE_START;
598
- case '&':
599
- case '!':
600
- return PROPERTIES_START;
601
- case '*':
602
- return ALIAS_START;
603
- default:
604
- return PLAIN_START;
746
+ case '[':
747
+ return FLOW_SEQUENCE_START;
748
+ case '{':
749
+ return FLOW_MAPPING_START;
750
+ case '\'':
751
+ return SINGLE_START;
752
+ case '"':
753
+ return DOUBLE_START;
754
+ case '&':
755
+ case '!':
756
+ return PROPERTIES_START;
757
+ case '*':
758
+ return ALIAS_START;
759
+ default:
760
+ return PLAIN_START;
605
761
  }
606
762
  }
607
763
  static bool name_boundary(TSLexer *l) {
@@ -645,37 +801,40 @@ static unsigned end_key(Scanner *s) {
645
801
  /* Layout edits must invalidate preceding node reductions. */
646
802
  static void skip_layout(TSLexer *l) {
647
803
  for (;;) {
648
- while (space(l->lookahead))
649
- step(l);
650
- if (l->lookahead != '#')
651
- return;
652
- while (!l->eof(l) && !newline(l->lookahead))
653
- step(l);
804
+ while (space(l->lookahead)) step(l);
805
+ if (l->lookahead != '#') return;
806
+ skip_line(l);
654
807
  }
655
808
  }
809
+ static bool block_key_colon(const Scanner *s, TSLexer *l) {
810
+ return l->lookahead == ':' &&
811
+ (!s->line ||
812
+ (l->get_column(l) == s->indent && s->indent > outdent_boundary(s)));
813
+ }
656
814
  static bool scan_key_end(Scanner *s, TSLexer *l, const bool *valid) {
657
- if (!s->line && blank(l->lookahead))
658
- return scan_separation(l, valid);
815
+ if (!s->line && blank(l->lookahead)) return scan_separation(l, valid);
659
816
  unsigned age = end_key(s);
660
- if (s->flow)
661
- skip_layout(l);
817
+ if (s->flow) skip_layout(l);
662
818
  bool key_invalid =
663
819
  cursor_broken(l) || age + cursor_characters(l) > IMPLICIT_KEY_LIMIT;
820
+ bool colon_eof = false;
664
821
  if (valid[FLOW_NODE_END]) {
665
822
  bool colon = l->lookahead == ':';
666
823
  if (colon) {
667
- step(l);
668
- colon = s->json || colon_boundary(l, true);
824
+ colon = step_boundary(l, true) || s->json;
825
+ colon_eof = !s->json && l->eof(l);
669
826
  }
670
- if (!colon)
671
- return emit(l, valid, FLOW_NODE_END);
672
- }
673
- s->key_done = true;
674
- if (key_invalid && !s->flow && l->lookahead == ':') {
827
+ if (!colon) return emit(l, valid, FLOW_NODE_END);
828
+ } else if (key_invalid && !s->flow && block_key_colon(s, l)) {
675
829
  step(l);
676
- if (l->eof(l))
677
- return emit(l, valid, UNFINISHED_INVALID_KEY_END);
830
+ colon_eof = s->first_pair && l->eof(l);
831
+ }
832
+ if (!s->flow) {
833
+ s->key_state = s->line ? BLOCK_KEY_ENDED : KEY_ENDED;
834
+ s->first_pair = false;
678
835
  }
836
+ if (key_invalid && colon_eof)
837
+ return emit(l, valid, UNFINISHED_INVALID_KEY_END);
679
838
  return emit(l, valid, key_invalid ? INVALID_KEY_END : KEY_END);
680
839
  }
681
840
 
@@ -684,87 +843,89 @@ static void skip_property_or_alias(TSLexer *l) {
684
843
  step(l);
685
844
  if (tag && l->lookahead == '<') {
686
845
  step(l);
687
- while (!l->eof(l) && !space(l->lookahead) && l->lookahead != '>')
688
- step(l);
689
- if (l->lookahead == '>')
690
- step(l);
846
+ while (!l->eof(l) && !space(l->lookahead) && l->lookahead != '>') step(l);
847
+ if (l->lookahead == '>') step(l);
691
848
  } else {
692
- while (!name_boundary(l))
693
- step(l);
849
+ while (!name_boundary(l)) step(l);
694
850
  }
695
851
  }
696
852
 
697
- static enum Token classify_block_node(TSLexer *l, bool *unfinished) {
698
- if (unfinished)
699
- *unfinished = false;
700
- bool properties = l->lookahead == '&' || l->lookahead == '!';
701
- bool attached = false;
702
- while (l->lookahead == '&' || l->lookahead == '!') {
703
- skip_property_or_alias(l);
704
- attached = !blank(l->lookahead);
705
- skip_blanks(l);
706
- if (l->eof(l) || newline(l->lookahead) || l->lookahead == '#')
707
- return PROPERTIES_START;
708
- }
709
- int32_t first = l->lookahead;
710
- if (first == '|' || first == '>')
711
- return properties ? PROPERTIES_START
712
- : first == '|' ? LITERAL_START
713
- : FOLDED_START;
714
- enum Token content = node_start(first);
715
- enum Token fallback = properties ? PROPERTIES_START : content;
716
- bool structured = content ==
717
- SINGLE_START ||
718
- content ==
719
- DOUBLE_START ||
720
- content ==
721
- FLOW_SEQUENCE_START ||
853
+ typedef struct {
854
+ char initial[32];
855
+ char *closings;
856
+ size_t depth, capacity;
857
+ } FlowStack;
858
+ /* This bit is unused by ']' and '}'. */
859
+ enum { VALUE_CLOSING = 0x02 };
860
+ enum FlowPosition { AT_ENTRY, AT_KEY, AT_VALUE, AT_VALUE_PROPERTIES };
861
+ static bool flow_value(enum FlowPosition position) {
862
+ return position == AT_VALUE || position == AT_VALUE_PROPERTIES;
863
+ }
864
+
865
+ static bool push_flow(FlowStack *flows, int32_t opening) {
866
+ if (flows->depth == flows->capacity) {
867
+ if (flows->capacity > SIZE_MAX / 2) return false;
868
+ size_t capacity = flows->capacity * 2;
869
+ char *expanded = ts_calloc(capacity, sizeof(*expanded));
870
+ if (!expanded) return false;
871
+ memcpy(expanded, flows->closings, flows->depth);
872
+ if (flows->closings != flows->initial) ts_free(flows->closings);
873
+ flows->closings = expanded;
874
+ flows->capacity = capacity;
875
+ }
876
+ flows->closings[flows->depth++] = opening == '[' ? ']' : '}';
877
+ return true;
878
+ }
879
+ static char pop_flow(FlowStack *flows, int32_t closing) {
880
+ while (
881
+ flows->depth &&
882
+ (flows->closings[flows->depth - 1] & ~VALUE_CLOSING) != closing
883
+ )
884
+ flows->depth--;
885
+ return flows->depth ? flows->closings[--flows->depth] : 0;
886
+ }
887
+
888
+ static bool key_colon_follows(
889
+ TSLexer *l,
890
+ enum Token content,
891
+ bool adjacent,
892
+ bool *unfinished
893
+ ) {
894
+ FlowStack flows = {.capacity = sizeof(flows.initial)};
895
+ flows.closings = flows.initial;
896
+ bool structured = content == SINGLE_START ||
897
+ content == DOUBLE_START ||
898
+ content == FLOW_SEQUENCE_START ||
722
899
  content == FLOW_MAPPING_START;
723
- if (first == '*') {
724
- skip_property_or_alias(l);
725
- }
726
- if (first == '-' || first == '?') {
727
- step(l);
728
- if (space(l->lookahead) || l->eof(l)) {
729
- if (unfinished)
730
- *unfinished = l->eof(l);
731
- return properties ? PROPERTIES_START
732
- : first == '-' ? SEQUENCE_START
733
- : MAPPING_START;
734
- }
735
- }
736
- int32_t quote = 0;
737
- char initial_closings[32];
738
- char *closings = initial_closings;
739
- size_t flow = 0, capacity = sizeof(initial_closings);
740
- bool separated = false;
741
900
  bool complete = content == ALIAS_START;
742
901
  bool plain = content == PLAIN_START;
743
- bool adjacent = attached;
902
+ bool separated = false;
903
+ bool colon = false;
904
+ int32_t quote = 0;
905
+ enum FlowPosition position = AT_ENTRY;
744
906
  while (!l->eof(l)) {
745
907
  if (
746
- l->get_column(l) ==
747
- 0 &&
908
+ l->get_column(l) == 0 &&
748
909
  cursor_characters(l) &&
749
910
  (l->lookahead == '-' || l->lookahead == '.')
750
911
  ) {
751
- if (document_marker(l) || l->eof(l))
752
- break;
753
- if (!quote)
912
+ if (document_marker(l) || l->eof(l)) break;
913
+ if (!quote) {
754
914
  plain = true;
915
+ adjacent = false;
916
+ position = AT_ENTRY;
917
+ }
918
+ separated = false;
755
919
  }
756
920
  int32_t c = l->lookahead;
757
- if (!quote && !flow) {
758
- if (complete && !space(c) && c != ':')
759
- break;
760
- if (newline(c) || (c == '#' && separated))
761
- break;
921
+ if (!quote && !flows.depth) {
922
+ if (complete && !space(c) && c != ':') break;
923
+ if (newline(c) || (c == '#' && separated)) break;
762
924
  }
763
925
  if (quote) {
764
926
  if (c == '\\' && quote == '"') {
765
927
  step(l);
766
- if (l->eof(l))
767
- break;
928
+ if (l->eof(l)) break;
768
929
  } else if (c == quote) {
769
930
  if (quote == '\'') {
770
931
  step(l);
@@ -774,82 +935,103 @@ static enum Token classify_block_node(TSLexer *l, bool *unfinished) {
774
935
  }
775
936
  }
776
937
  quote = 0;
777
- adjacent = true;
778
- if (!flow)
779
- complete = true;
938
+ adjacent = !flow_value(position);
939
+ position = AT_ENTRY;
940
+ if (!flows.depth) complete = true;
780
941
  separated = false;
781
- if (c == '\'')
782
- continue;
942
+ if (c == '\'') continue;
783
943
  }
784
- } else if (structured && !plain && (c == '\'' || c == '"'))
785
- quote = c;
786
- else if (flow && !plain && (c == '&' || c == '*' || c == '!')) {
944
+ } else if (structured && !plain && (c == '\'' || c == '"')) quote = c;
945
+ else if (flows.depth && !plain && (c == '&' || c == '*' || c == '!')) {
946
+ position = c == '*' ? AT_ENTRY
947
+ : flow_value(position) ? AT_VALUE_PROPERTIES
948
+ : AT_KEY;
787
949
  skip_property_or_alias(l);
788
950
  adjacent = false;
789
951
  separated = false;
790
952
  continue;
791
- } else if (flow && c == '#' && (separated || !plain)) {
792
- while (!l->eof(l) && !newline(l->lookahead))
793
- step(l);
953
+ } else if (flows.depth && c == '#' && (separated || !plain)) {
954
+ skip_line(l);
794
955
  plain = false;
795
956
  separated = true;
796
957
  continue;
797
958
  } else if (structured && (c == '[' || c == '{')) {
798
- if (flow == capacity) {
799
- capacity *= 2;
800
- char *expanded = ts_calloc(capacity, sizeof(*expanded));
801
- memcpy(expanded, closings, flow);
802
- if (closings != initial_closings)
803
- ts_free(closings);
804
- closings = expanded;
959
+ if (!push_flow(&flows, c)) {
960
+ ((Cursor *)l)->allocation_failed = true;
961
+ break;
805
962
  }
806
- closings[flow++] = c == '[' ? ']' : '}';
963
+ if (flow_value(position))
964
+ flows.closings[flows.depth - 1] |= VALUE_CLOSING;
807
965
  plain = false;
808
966
  adjacent = false;
809
- } else if ((c == ']' || c == '}') && flow) {
810
- while (flow && closings[flow - 1] != c)
811
- flow--;
812
- if (!flow)
813
- break;
814
- flow--;
967
+ position = AT_ENTRY;
968
+ } else if ((c == ']' || c == '}') && flows.depth) {
969
+ char closing = pop_flow(&flows, c);
970
+ if (!closing) break;
815
971
  plain = false;
816
- adjacent = true;
817
- if (!flow)
818
- complete = true;
819
- } else if (flow && c == ',') {
972
+ adjacent = !(closing & VALUE_CLOSING);
973
+ position = AT_ENTRY;
974
+ if (!flows.depth) complete = true;
975
+ } else if (flows.depth && c == ',') {
820
976
  plain = false;
821
977
  adjacent = false;
978
+ position = AT_ENTRY;
822
979
  } else if (c == ':') {
823
- step(l);
824
- bool indicator = colon_boundary(l, flow);
825
- if (!flow && indicator) {
826
- fallback = MAPPING_START;
827
- if (unfinished)
828
- *unfinished = l->eof(l);
980
+ bool indicator = step_boundary(l, flows.depth > 0);
981
+ if (!flows.depth && indicator) {
982
+ colon = true;
983
+ if (unfinished) *unfinished = l->eof(l);
829
984
  break;
830
985
  }
831
- if (!flow && complete)
832
- break;
833
- plain = !indicator && !adjacent;
986
+ if (!flows.depth && complete) break;
987
+ plain = indicator ? position == AT_VALUE : !adjacent;
988
+ position = plain ? AT_ENTRY : AT_VALUE;
834
989
  adjacent = false;
835
990
  separated = false;
836
991
  continue;
837
- } else if (flow && !plain && c == '?') {
838
- step(l);
839
- plain = !space(l->lookahead) && !l->eof(l);
992
+ } else if (flows.depth && !plain && c == '?') {
993
+ plain = !step_boundary(l, false) || position != AT_ENTRY;
994
+ position = plain ? AT_ENTRY : AT_KEY;
840
995
  adjacent = false;
841
996
  separated = false;
842
997
  continue;
843
998
  } else if (!space(c)) {
844
999
  plain = true;
845
1000
  adjacent = false;
1001
+ position = AT_ENTRY;
846
1002
  }
847
1003
  separated = space(c);
848
1004
  step(l);
849
1005
  }
850
- if (closings != initial_closings)
851
- ts_free(closings);
852
- return fallback;
1006
+ if (flows.closings != flows.initial) ts_free(flows.closings);
1007
+ return colon;
1008
+ }
1009
+
1010
+ static enum Token classify_block_node(TSLexer *l, bool *unfinished) {
1011
+ if (unfinished) *unfinished = false;
1012
+ bool properties = l->lookahead == '&' || l->lookahead == '!';
1013
+ bool attached = false;
1014
+ while (l->lookahead == '&' || l->lookahead == '!') {
1015
+ skip_property_or_alias(l);
1016
+ attached = !blank(l->lookahead);
1017
+ skip_blanks(l);
1018
+ if (layout_follows(l)) return PROPERTIES_START;
1019
+ }
1020
+ int32_t first = l->lookahead;
1021
+ if (first == '|' || first == '>')
1022
+ return properties ? PROPERTIES_START
1023
+ : first == '|' ? LITERAL_START
1024
+ : FOLDED_START;
1025
+ enum Token content = node_start(first);
1026
+ if (first == '*') skip_property_or_alias(l);
1027
+ if ((first == '-' || first == '?') && step_boundary(l, false)) {
1028
+ if (unfinished) *unfinished = l->eof(l);
1029
+ return properties ? PROPERTIES_START
1030
+ : first == '-' ? SEQUENCE_START
1031
+ : MAPPING_START;
1032
+ }
1033
+ if (key_colon_follows(l, content, attached, unfinished)) return MAPPING_START;
1034
+ return properties ? PROPERTIES_START : content;
853
1035
  }
854
1036
 
855
1037
  static enum Token classify_block_start(Scanner *s, TSLexer *l) {
@@ -864,8 +1046,7 @@ property_content_start(Scanner *s, TSLexer *l, const bool *valid) {
864
1046
  if (s->line && !s->flow) {
865
1047
  skip_property_or_alias(l);
866
1048
  skip_blanks(l);
867
- if (l->eof(l))
868
- return UNFINISHED_PROPERTIES_ON_ALIAS_START;
1049
+ if (l->eof(l)) return UNFINISHED_PROPERTIES_ON_ALIAS_START;
869
1050
  }
870
1051
  return PROPERTY_ALIAS_START;
871
1052
  }
@@ -880,8 +1061,7 @@ property_content_start(Scanner *s, TSLexer *l, const bool *valid) {
880
1061
  if (
881
1062
  !s->line &&
882
1063
  valid[PROPERTY_COMPACT_START] &&
883
- (kind ==
884
- SEQUENCE_START ||
1064
+ (kind == SEQUENCE_START ||
885
1065
  (kind == MAPPING_START && valid[BLOCK_PROPERTY_CONTENT_START]))
886
1066
  )
887
1067
  return s->block_eof ? UNFINISHED_INVALID_PROPERTY_COLLECTION_START
@@ -896,11 +1076,11 @@ emit_indicator(Scanner *s, TSLexer *l, const bool *valid, enum Token token) {
896
1076
  l->mark_end(l);
897
1077
  if (!s->flow && blank(l->lookahead)) {
898
1078
  skip_blanks(l);
899
- if (!l->eof(l) && !newline(l->lookahead) && l->lookahead != '#') {
1079
+ if (!layout_follows(l)) {
900
1080
  bool unfinished;
901
1081
  enum Token kind = classify_block_node(l, &unfinished);
902
1082
  if (block_collection(kind)) {
903
- s->prefix_eof = unfinished;
1083
+ s->prefix_eof = unfinished ? PREFIX_TAB : 0;
904
1084
  s->mode = COMPACT_PREFIX;
905
1085
  }
906
1086
  }
@@ -908,31 +1088,17 @@ emit_indicator(Scanner *s, TSLexer *l, const bool *valid, enum Token token) {
908
1088
  return emit(l, valid, token);
909
1089
  }
910
1090
 
911
- static void skip_line_break(TSLexer *l) {
912
- int32_t first = l->lookahead;
913
- step(l);
914
- if (first == '\r' && l->lookahead == '\n')
915
- step(l);
916
- }
917
- static bool line_break(TSLexer *l, const bool *valid, enum Token token) {
918
- skip_line_break(l);
919
- return finish(l, valid, token);
920
- }
921
1091
  static unsigned hex_value(int32_t c) {
922
- if (c >= '0' && c <= '9')
923
- return (unsigned)(c - '0');
924
- if (c >= 'a' && c <= 'f')
925
- return (unsigned)(c - 'a' + 10);
926
- if (c >= 'A' && c <= 'F')
927
- return (unsigned)(c - 'A' + 10);
1092
+ if (c >= '0' && c <= '9') return (unsigned)(c - '0');
1093
+ if (c >= 'a' && c <= 'f') return (unsigned)(c - 'a' + 10);
1094
+ if (c >= 'A' && c <= 'F') return (unsigned)(c - 'A' + 10);
928
1095
  return 16;
929
1096
  }
930
1097
  static unsigned hex_digits(TSLexer *l, unsigned remaining, uint32_t *value) {
931
1098
  *value = 0;
932
1099
  while (remaining && !l->eof(l)) {
933
1100
  unsigned digit = hex_value(l->lookahead);
934
- if (digit == 16)
935
- break;
1101
+ if (digit == 16) break;
936
1102
  *value = (*value << 4) | digit;
937
1103
  step(l);
938
1104
  l->mark_end(l);
@@ -949,10 +1115,8 @@ static bool word_char(int32_t c) {
949
1115
  }
950
1116
  static bool uri_char(int32_t c, bool suffix) {
951
1117
  return word_char(c) ||
952
- (c >
953
- 0 &&
954
- c <
955
- 128 &&
1118
+ (c > 0 &&
1119
+ c < 128 &&
956
1120
  strchr("#;/?:@&=+$,_.!~*'()[]", (int)c) &&
957
1121
  (!suffix || (c != '!' && !flow_indicator(c))));
958
1122
  }
@@ -969,30 +1133,32 @@ static bool scan_name(Scanner *s, TSLexer *l, const bool *valid) {
969
1133
  return emit(l, valid, NAME_END);
970
1134
  }
971
1135
  s->first = false;
972
- if (scan_invalid_character(l, valid, false))
973
- return true;
1136
+ if (scan_invalid_character(l, valid, false)) return true;
974
1137
  do {
975
1138
  step(l);
976
1139
  } while (!name_boundary(l) && !invalid_unquoted(l->lookahead));
977
1140
  return finish(l, valid, anchor ? ANCHOR_NAME : ALIAS_NAME);
978
1141
  }
979
1142
 
1143
+ static void end_handle(Scanner *s) {
1144
+ s->mode = s->directive_handle ? DIRECTIVE_PREFIX : SUFFIX_BEGIN;
1145
+ s->directive_handle = false;
1146
+ }
980
1147
  static bool scan_handle(Scanner *s, TSLexer *l, const bool *valid) {
981
1148
  if (s->mode == HANDLE_SELECT) {
982
1149
  step(l);
983
1150
  enum Token token = s->handle_form == PRIMARY_HANDLE ? PRIMARY_TAG_HANDLE
984
1151
  : s->handle_form == SECONDARY_HANDLE ? SECONDARY_TAG_HANDLE
985
1152
  : TAG_HANDLE_OPEN;
986
- if (s->handle_form == SECONDARY_HANDLE)
987
- step(l);
1153
+ if (s->handle_form == SECONDARY_HANDLE) step(l);
988
1154
  l->mark_end(l);
989
- s->mode = s->handle_form == NAMED_HANDLE ? HANDLE_BODY
990
- : s->directive_handle ? DIRECTIVE_PREFIX
991
- : SUFFIX_BEGIN;
1155
+ if (s->handle_form == NAMED_HANDLE) s->mode = HANDLE_BODY;
1156
+ else end_handle(s);
1157
+ s->handle_form = 0;
992
1158
  return emit(l, valid, token);
993
1159
  }
994
1160
  if (s->directive_handle && (l->eof(l) || space(l->lookahead))) {
995
- s->mode = DIRECTIVE_PREFIX;
1161
+ end_handle(s);
996
1162
  return emit_missing(
997
1163
  l,
998
1164
  valid,
@@ -1001,19 +1167,17 @@ static bool scan_handle(Scanner *s, TSLexer *l, const bool *valid) {
1001
1167
  );
1002
1168
  }
1003
1169
  if (l->lookahead == '!') {
1004
- s->mode = s->directive_handle ? DIRECTIVE_PREFIX : SUFFIX_BEGIN;
1170
+ end_handle(s);
1005
1171
  return take(l, valid, TAG_HANDLE_CLOSE);
1006
1172
  }
1007
- if (scan_invalid_character(l, valid, false))
1008
- return true;
1173
+ if (scan_invalid_character(l, valid, false)) return true;
1009
1174
  if (!word_char(l->lookahead)) {
1010
1175
  do {
1011
1176
  step(l);
1012
1177
  } while (
1013
1178
  !l->eof(l) &&
1014
1179
  !space(l->lookahead) &&
1015
- l->lookahead !=
1016
- '!' &&
1180
+ l->lookahead != '!' &&
1017
1181
  !invalid_unquoted(l->lookahead) &&
1018
1182
  !word_char(l->lookahead)
1019
1183
  );
@@ -1036,8 +1200,7 @@ static bool scan_tag_boundary(Scanner *s, TSLexer *l, const bool *valid) {
1036
1200
  }
1037
1201
  if (s->mode == VERBATIM_CLOSE) {
1038
1202
  s->mode = NORMAL;
1039
- if (l->lookahead == '>')
1040
- return take(l, valid, VERBATIM_TAG_CLOSE);
1203
+ if (l->lookahead == '>') return take(l, valid, VERBATIM_TAG_CLOSE);
1041
1204
  return emit_missing(
1042
1205
  l,
1043
1206
  valid,
@@ -1072,8 +1235,7 @@ static bool scan_uri(Scanner *s, TSLexer *l, const bool *valid) {
1072
1235
  s->mode = VERBATIM_CLOSE;
1073
1236
  return emit(l, valid, TAG_URI_END);
1074
1237
  }
1075
- if (scan_invalid_character(l, valid, false))
1076
- return true;
1238
+ if (scan_invalid_character(l, valid, false)) return true;
1077
1239
  if (prefix && s->first) {
1078
1240
  s->first = false;
1079
1241
  if (flow_indicator(l->lookahead) && uri_char(l->lookahead, false))
@@ -1100,8 +1262,7 @@ static bool scan_uri(Scanner *s, TSLexer *l, const bool *valid) {
1100
1262
  } while (
1101
1263
  !uri_boundary(l, prefix, suffix) &&
1102
1264
  !invalid_unquoted(l->lookahead) &&
1103
- l->lookahead !=
1104
- '%' &&
1265
+ l->lookahead != '%' &&
1105
1266
  !uri_char(l->lookahead, suffix)
1106
1267
  );
1107
1268
  return finish(l, valid, INVALID_TAG_CHARACTER);
@@ -1122,22 +1283,25 @@ scan_directive_word(TSLexer *l, const bool *valid, enum Token token) {
1122
1283
  } while (!directive_boundary(l));
1123
1284
  return finish(l, valid, token);
1124
1285
  }
1125
- /* Comment edits must also invalidate preceding node reductions. */
1126
- static bool start_comment(
1127
- Scanner *s,
1128
- TSLexer *l,
1129
- const bool *valid,
1130
- enum Mode return_mode,
1131
- bool missing_separation
1132
- ) {
1133
- if (!valid[COMMENT_START])
1134
- return false;
1135
- while (!l->eof(l) && !newline(l->lookahead))
1286
+ static bool start_directive(Scanner *s, TSLexer *l, const bool *valid) {
1287
+ char name[5] = {0};
1288
+ unsigned length = 0;
1289
+ step(l);
1290
+ while (!directive_boundary(l)) {
1291
+ if (length < 4 && l->lookahead < 128) name[length] = (char)l->lookahead;
1292
+ if (length < 5) length++;
1136
1293
  step(l);
1137
- s->mode = COMMENT_BEGIN;
1138
- s->return_mode = (uint8_t)return_mode;
1139
- s->first = missing_separation;
1140
- return emit(l, valid, COMMENT_START);
1294
+ }
1295
+ s->directive_kind = length == 4 && !strcmp(name, "YAML") ? YAML_DIRECTIVE
1296
+ : length == 3 && !strcmp(name, "TAG") ? TAG_DIRECTIVE
1297
+ : RESERVED_DIRECTIVE;
1298
+ return emit(
1299
+ l,
1300
+ valid,
1301
+ s->directive_kind == YAML_DIRECTIVE ? YAML_DIRECTIVE_START
1302
+ : s->directive_kind == TAG_DIRECTIVE ? TAG_DIRECTIVE_START
1303
+ : RESERVED_DIRECTIVE_START
1304
+ );
1141
1305
  }
1142
1306
  static bool scan_directive_name(Scanner *s, TSLexer *l, const bool *valid) {
1143
1307
  if (l->eof(l) || space(l->lookahead)) {
@@ -1156,14 +1320,12 @@ static bool scan_directive_name(Scanner *s, TSLexer *l, const bool *valid) {
1156
1320
  return emit(l, valid, DIRECTIVE_NAME_END);
1157
1321
  }
1158
1322
  s->first = false;
1159
- if (scan_invalid_character(l, valid, false))
1160
- return true;
1323
+ if (scan_invalid_character(l, valid, false)) return true;
1161
1324
  return scan_directive_word(l, valid, DIRECTIVE_NAME);
1162
1325
  }
1163
1326
  static bool
1164
1327
  scan_yaml_version(Scanner *s, TSLexer *l, const bool *valid, bool end) {
1165
- if (scan_invalid_character(l, valid, false))
1166
- return true;
1328
+ if (scan_invalid_character(l, valid, false)) return true;
1167
1329
  s->mode = DIRECTIVE_PARAMETERS;
1168
1330
  if (end)
1169
1331
  return emit_missing(
@@ -1177,12 +1339,9 @@ scan_yaml_version(Scanner *s, TSLexer *l, const bool *valid, bool end) {
1177
1339
  do {
1178
1340
  int32_t c = l->lookahead;
1179
1341
  if (c >= '0' && c <= '9') {
1180
- if (part == 0 || part == 2)
1181
- part++;
1182
- } else if (c == '.' && part == 1)
1183
- part = 2;
1184
- else
1185
- correct = false;
1342
+ if (part == 0 || part == 2) part++;
1343
+ } else if (c == '.' && part == 1) part = 2;
1344
+ else correct = false;
1186
1345
  step(l);
1187
1346
  } while (!directive_boundary(l));
1188
1347
  return finish(
@@ -1195,8 +1354,7 @@ scan_yaml_version(Scanner *s, TSLexer *l, const bool *valid, bool end) {
1195
1354
  }
1196
1355
  static bool
1197
1356
  scan_directive_handle(Scanner *s, TSLexer *l, const bool *valid, bool end) {
1198
- if (scan_invalid_character(l, valid, false))
1199
- return true;
1357
+ if (scan_invalid_character(l, valid, false)) return true;
1200
1358
  s->mode = DIRECTIVE_PREFIX;
1201
1359
  s->property_separation_notified = false;
1202
1360
  if (end)
@@ -1218,30 +1376,26 @@ scan_directive_prefix(Scanner *s, TSLexer *l, const bool *valid, bool end) {
1218
1376
  s->mode = DIRECTIVE_PARAMETERS;
1219
1377
  return emit_missing(l, valid, MISSING_TAG_PREFIX, INCOMPLETE_TAG_PREFIX);
1220
1378
  }
1221
- if (!s->separated && !s->property_separation_notified) {
1222
- s->property_separation_notified = true;
1223
- return emit(l, valid, MISSING_SEPARATION);
1224
- }
1379
+ if (separation_missing(s)) return emit_missing_separation(s, l, valid);
1225
1380
  s->mode = PREFIX_BODY;
1226
1381
  s->first = true;
1382
+ s->property_separation_notified = false;
1227
1383
  return emit(l, valid, TAG_PREFIX_START);
1228
1384
  }
1229
1385
  static bool scan_directive(Scanner *s, TSLexer *l, const bool *valid) {
1230
- if (s->mode == DIRECTIVE_NAME_BODY)
1231
- return scan_directive_name(s, l, valid);
1232
- if (blank(l->lookahead))
1233
- return scan_separation(l, valid);
1386
+ if (s->mode == DIRECTIVE_NAME_BODY) return scan_directive_name(s, l, valid);
1387
+ if (blank(l->lookahead)) return scan_separation(l, valid);
1234
1388
  bool end =
1235
1389
  l->eof(l) || newline(l->lookahead) || (l->lookahead == '#' && s->separated);
1236
1390
  switch ((enum Mode)s->mode) {
1237
- case DIRECTIVE_VERSION:
1238
- return scan_yaml_version(s, l, valid, end);
1239
- case DIRECTIVE_HANDLE:
1240
- return scan_directive_handle(s, l, valid, end);
1241
- case DIRECTIVE_PREFIX:
1242
- return scan_directive_prefix(s, l, valid, end);
1243
- default:
1244
- break;
1391
+ case DIRECTIVE_VERSION:
1392
+ return scan_yaml_version(s, l, valid, end);
1393
+ case DIRECTIVE_HANDLE:
1394
+ return scan_directive_handle(s, l, valid, end);
1395
+ case DIRECTIVE_PREFIX:
1396
+ return scan_directive_prefix(s, l, valid, end);
1397
+ default:
1398
+ break;
1245
1399
  }
1246
1400
  if (l->lookahead == '#' && s->separated)
1247
1401
  return start_comment(s, l, valid, DIRECTIVE_PARAMETERS, false);
@@ -1249,8 +1403,7 @@ static bool scan_directive(Scanner *s, TSLexer *l, const bool *valid) {
1249
1403
  s->mode = NORMAL;
1250
1404
  return emit(l, valid, DIRECTIVE_END);
1251
1405
  }
1252
- if (scan_invalid_character(l, valid, false))
1253
- return true;
1406
+ if (scan_invalid_character(l, valid, false)) return true;
1254
1407
  return scan_directive_word(
1255
1408
  l,
1256
1409
  valid,
@@ -1259,6 +1412,25 @@ static bool scan_directive(Scanner *s, TSLexer *l, const bool *valid) {
1259
1412
  );
1260
1413
  }
1261
1414
 
1415
+ static void end_scalar(Scanner *s) {
1416
+ s->mode = NORMAL;
1417
+ s->first = false;
1418
+ s->prefix = false;
1419
+ s->continuation = false;
1420
+ s->quote_line_empty = false;
1421
+ s->scalar_indent = false;
1422
+ s->scalar_spaces = 0;
1423
+ s->scalar_tab = false;
1424
+ s->block_indent = -1;
1425
+ s->block_explicit_indent = false;
1426
+ s->header_separated = false;
1427
+ s->block_leading = false;
1428
+ s->block_empty = false;
1429
+ s->block_prefix = false;
1430
+ s->block_layout_lines = 0;
1431
+ s->block_marker_eof = false;
1432
+ }
1433
+
1262
1434
  static bool scalar_break(Scanner *s, TSLexer *l, const bool *valid) {
1263
1435
  s->prefix = true;
1264
1436
  s->continuation = false;
@@ -1271,8 +1443,7 @@ static bool scalar_break(Scanner *s, TSLexer *l, const bool *valid) {
1271
1443
  static bool resume_scalar_line(Scanner *s) {
1272
1444
  s->prefix = false;
1273
1445
  s->continuation = false;
1274
- if (!s->scalar_indent)
1275
- return true;
1446
+ if (!s->scalar_indent) return true;
1276
1447
  s->scalar_indent = false;
1277
1448
  return s->scalar_spaces > s->indent;
1278
1449
  }
@@ -1280,6 +1451,10 @@ static bool provisional_indentation(const Scanner *s, uint32_t spaces) {
1280
1451
  return s->boundary_pending ||
1281
1452
  (s->provisional_indent >= -1 && spaces > s->provisional_indent);
1282
1453
  }
1454
+ static enum Token missing_indentation(const Scanner *s, uint32_t spaces) {
1455
+ return provisional_indentation(s, spaces) ? UNFINISHED_MISSING_INDENTATION
1456
+ : MISSING_INDENTATION;
1457
+ }
1283
1458
  static bool scalar_prefix(Scanner *s, TSLexer *l, const bool *valid) {
1284
1459
  if (l->lookahead == '\t' && s->scalar_spaces <= s->indent) {
1285
1460
  s->scalar_tab = true;
@@ -1289,16 +1464,14 @@ static bool scalar_prefix(Scanner *s, TSLexer *l, const bool *valid) {
1289
1464
  return finish(
1290
1465
  l,
1291
1466
  valid,
1292
- provisional_indentation(s, s->scalar_spaces)
1467
+ provisional_indentation(s, s->scalar_spaces) || s->block_marker_eof
1293
1468
  ? UNFINISHED_TAB_IN_INDENTATION
1294
1469
  : TAB_IN_INDENTATION
1295
1470
  );
1296
1471
  }
1297
1472
  do {
1298
- if (l->lookahead == '\t')
1299
- s->scalar_tab = true;
1300
- else if (!s->scalar_tab)
1301
- s->scalar_spaces++;
1473
+ if (l->lookahead == '\t') s->scalar_tab = true;
1474
+ else if (!s->scalar_tab) s->scalar_spaces++;
1302
1475
  step(l);
1303
1476
  } while (
1304
1477
  blank(l->lookahead) &&
@@ -1306,92 +1479,75 @@ static bool scalar_prefix(Scanner *s, TSLexer *l, const bool *valid) {
1306
1479
  );
1307
1480
  return finish(l, valid, SCALAR_LINE_PREFIX);
1308
1481
  }
1309
- static bool scan_quote(Scanner *s, TSLexer *l, const bool *valid) {
1310
- int32_t quote = s->mode == SINGLE ? '\'' : '"';
1311
- if (l->eof(l)) {
1312
- if (!emit(l, valid, INCOMPLETE_QUOTE_CLOSE))
1313
- return false;
1314
- s->mode = NORMAL;
1315
- s->prefix = false;
1316
- s->json = true;
1317
- return true;
1318
- }
1482
+ static bool
1483
+ close_quote(Scanner *s, TSLexer *l, const bool *valid, enum Token token) {
1484
+ end_scalar(s);
1485
+ s->json = s->flow > 0;
1486
+ return emit(l, valid, token);
1487
+ }
1488
+ static bool scan_escape(Scanner *s, TSLexer *l, const bool *valid) {
1489
+ step(l);
1490
+ l->mark_end(l);
1319
1491
  if (newline(l->lookahead))
1320
- return scalar_break(s, l, valid);
1321
- if (s->prefix && blank(l->lookahead))
1322
- return scalar_prefix(s, l, valid);
1323
- if (!resume_scalar_line(s))
1324
1492
  return emit(
1325
1493
  l,
1326
1494
  valid,
1327
- provisional_indentation(s, s->scalar_spaces)
1328
- ? UNFINISHED_MISSING_INDENTATION
1329
- : MISSING_INDENTATION
1495
+ s->quote_line_empty ? INVALID_LINE_CONTINUATION : ESCAPE_INDICATOR
1330
1496
  );
1331
- if (scan_invalid_character(l, valid, true))
1332
- return true;
1333
- if (l->lookahead == quote) {
1334
- step(l);
1335
- l->mark_end(l);
1336
- if (quote == '\'' && l->lookahead == '\'') {
1337
- step(l);
1338
- return finish(l, valid, ESCAPED_QUOTE);
1339
- }
1340
- if (!emit(l, valid, QUOTE_CLOSE))
1341
- return false;
1342
- s->mode = NORMAL;
1343
- s->json = true;
1344
- return true;
1345
- }
1346
- if (s->mode == DOUBLE && l->lookahead == '\\') {
1347
- step(l);
1348
- l->mark_end(l);
1349
- if (newline(l->lookahead))
1350
- return emit(
1351
- l,
1352
- valid,
1353
- s->quote_line_empty ? INVALID_LINE_CONTINUATION : ESCAPE_INDICATOR
1354
- );
1355
- if (l->eof(l))
1356
- return emit(l, valid, INCOMPLETE_ESCAPE);
1357
- if (invalid_quoted(l->lookahead)) {
1497
+ if (l->eof(l)) return emit(l, valid, INCOMPLETE_ESCAPE);
1498
+ if (invalid_quoted(l->lookahead))
1499
+ return emit(
1500
+ l,
1501
+ valid,
1502
+ invalid_encoding(l->lookahead) ? UNDECODABLE_ESCAPE_PREFIX
1503
+ : INVALID_ESCAPE
1504
+ );
1505
+ int32_t c = l->lookahead;
1506
+ bool ok = c > 0 && c < 128 && strchr("0abtnvfre \t\"/\\N_LP", (int)c);
1507
+ unsigned digits = c == 'x' ? 2 : c == 'u' ? 4 : c == 'U' ? 8 : 0;
1508
+ step(l);
1509
+ l->mark_end(l);
1510
+ if (digits) {
1511
+ uint32_t value;
1512
+ unsigned remaining = hex_digits(l, digits, &value);
1513
+ uint64_t lower = (uint64_t)value << (remaining * 4);
1514
+ uint64_t upper = lower | ((UINT64_C(1) << (remaining * 4)) - 1);
1515
+ ok = lower <= 0x10ffff && (lower < 0xd800 || upper > 0xdfff);
1516
+ if (remaining && ok && invalid_encoding(l->lookahead))
1517
+ return emit(l, valid, UNDECODABLE_ESCAPE_PREFIX);
1518
+ if (remaining)
1358
1519
  return emit(
1359
1520
  l,
1360
1521
  valid,
1361
- invalid_encoding(l->lookahead) ? UNDECODABLE_ESCAPE_PREFIX
1362
- : INVALID_ESCAPE
1522
+ l->eof(l) && ok ? INCOMPLETE_ESCAPE : INVALID_ESCAPE
1363
1523
  );
1364
- }
1365
- int32_t c = l->lookahead;
1366
- const char *simple = "0abtnvfre \t\"/\\N_LP";
1367
- bool ok = c > 0 && c < 128 && strchr(simple, (int)c);
1368
- unsigned digits = c == 'x' ? 2 : c == 'u' ? 4 : c == 'U' ? 8 : 0;
1524
+ }
1525
+ if (ok) s->quote_line_empty = false;
1526
+ return emit(l, valid, ok ? QUOTED_ESCAPE : INVALID_ESCAPE);
1527
+ }
1528
+ static bool scan_quote(Scanner *s, TSLexer *l, const bool *valid) {
1529
+ int32_t quote = s->mode == SINGLE ? '\'' : '"';
1530
+ if (l->eof(l)) return close_quote(s, l, valid, INCOMPLETE_QUOTE_CLOSE);
1531
+ if (newline(l->lookahead)) return scalar_break(s, l, valid);
1532
+ if (s->prefix && blank(l->lookahead)) return scalar_prefix(s, l, valid);
1533
+ if (!resume_scalar_line(s))
1534
+ return emit(l, valid, missing_indentation(s, s->scalar_spaces));
1535
+ if (scan_invalid_character(l, valid, true)) return true;
1536
+ if (l->lookahead == quote) {
1369
1537
  step(l);
1370
1538
  l->mark_end(l);
1371
- if (digits) {
1372
- uint32_t value;
1373
- unsigned remaining = hex_digits(l, digits, &value);
1374
- uint64_t lower = (uint64_t)value << (remaining * 4);
1375
- uint64_t upper = lower | ((UINT64_C(1) << (remaining * 4)) - 1);
1376
- ok = lower <= 0x10ffff && (lower < 0xd800 || upper > 0xdfff);
1377
- if (remaining && ok && invalid_encoding(l->lookahead))
1378
- return emit(l, valid, UNDECODABLE_ESCAPE_PREFIX);
1379
- if (remaining)
1380
- return emit(
1381
- l,
1382
- valid,
1383
- l->eof(l) && ok ? INCOMPLETE_ESCAPE : INVALID_ESCAPE
1384
- );
1539
+ if (quote == '\'' && l->lookahead == '\'') {
1540
+ step(l);
1541
+ return finish(l, valid, ESCAPED_QUOTE);
1385
1542
  }
1386
- if (ok)
1387
- s->quote_line_empty = false;
1388
- return emit(l, valid, ok ? QUOTED_ESCAPE : INVALID_ESCAPE);
1543
+ return close_quote(s, l, valid, QUOTE_CLOSE);
1389
1544
  }
1545
+ if (s->mode == DOUBLE && l->lookahead == '\\')
1546
+ return scan_escape(s, l, valid);
1390
1547
  bool text = false;
1391
1548
  while (
1392
1549
  !l->eof(l) &&
1393
- l->lookahead !=
1394
- quote &&
1550
+ l->lookahead != quote &&
1395
1551
  !newline(l->lookahead) &&
1396
1552
  !invalid_quoted(l->lookahead) &&
1397
1553
  !(s->mode == DOUBLE && l->lookahead == '\\')
@@ -1400,8 +1556,7 @@ static bool scan_quote(Scanner *s, TSLexer *l, const bool *valid) {
1400
1556
  step(l);
1401
1557
  skip_blanks(l);
1402
1558
  if (newline(l->lookahead)) {
1403
- if (text)
1404
- return emit(l, valid, SCALAR_TEXT);
1559
+ if (text) return emit(l, valid, SCALAR_TEXT);
1405
1560
  return finish(l, valid, SCALAR_LINE_SUFFIX);
1406
1561
  }
1407
1562
  text = true;
@@ -1416,21 +1571,51 @@ static bool scan_quote(Scanner *s, TSLexer *l, const bool *valid) {
1416
1571
  return text && emit(l, valid, SCALAR_TEXT);
1417
1572
  }
1418
1573
 
1574
+ enum PlainSpace { PLAIN_STOPS, PLAIN_SAME_LINE, PLAIN_NEXT_LINE };
1575
+ static enum PlainSpace plain_space(Scanner *s, TSLexer *l) {
1576
+ bool broken = false;
1577
+ uint32_t indentation = 0;
1578
+ bool tab = false;
1579
+ while (space(l->lookahead)) {
1580
+ broken |= newline(l->lookahead);
1581
+ if (newline(l->lookahead)) {
1582
+ indentation = 0;
1583
+ tab = false;
1584
+ } else if (l->lookahead == '\t') tab = true;
1585
+ else if (!tab) indentation++;
1586
+ step(l);
1587
+ }
1588
+ bool more = !l->eof(l) &&
1589
+ l->lookahead != '#' &&
1590
+ (!s->flow || !flow_indicator(l->lookahead)) &&
1591
+ (!broken || s->flow || indentation > content_indent(s));
1592
+ if (more && l->lookahead == ':') {
1593
+ more = !step_boundary(l, s->flow);
1594
+ s->eof_continuation = l->eof(l);
1595
+ }
1596
+ if (more && l->get_column(l) == 0) {
1597
+ int32_t first = l->lookahead;
1598
+ if (first == 0xfeff || document_marker(l)) more = false;
1599
+ else s->block_marker_eof = partial_marker(l, first);
1600
+ }
1601
+ return !more ? PLAIN_STOPS : broken ? PLAIN_NEXT_LINE : PLAIN_SAME_LINE;
1602
+ }
1603
+ static bool end_plain(Scanner *s, TSLexer *l, const bool *valid) {
1604
+ end_scalar(s);
1605
+ return emit(l, valid, PLAIN_END);
1606
+ }
1419
1607
  static bool scan_plain(Scanner *s, TSLexer *l, const bool *valid) {
1420
1608
  bool text = false;
1421
1609
  if (s->first) {
1422
1610
  s->first = false;
1423
1611
  if (
1424
- l->lookahead >
1425
- 0 &&
1426
- l->lookahead <
1427
- 128 &&
1612
+ l->lookahead > 0 &&
1613
+ l->lookahead < 128 &&
1428
1614
  strchr(",]}@`%&*!|>", (int)l->lookahead)
1429
1615
  )
1430
1616
  return take(l, valid, INVALID_SCALAR_START);
1431
1617
  if (l->lookahead == '-' || l->lookahead == '?' || l->lookahead == ':') {
1432
- step(l);
1433
- if (colon_boundary(l, s->flow)) {
1618
+ if (step_boundary(l, s->flow)) {
1434
1619
  return finish(
1435
1620
  l,
1436
1621
  valid,
@@ -1441,78 +1626,35 @@ static bool scan_plain(Scanner *s, TSLexer *l, const bool *valid) {
1441
1626
  }
1442
1627
  }
1443
1628
  if (s->continuation || s->prefix) {
1444
- if (newline(l->lookahead))
1445
- return scalar_break(s, l, valid);
1629
+ if (newline(l->lookahead)) return scalar_break(s, l, valid);
1446
1630
  if (blank(l->lookahead)) {
1447
- if (s->prefix)
1448
- return scalar_prefix(s, l, valid);
1631
+ if (s->prefix) return scalar_prefix(s, l, valid);
1449
1632
  step(l);
1450
1633
  skip_blanks(l);
1451
1634
  return finish(l, valid, SCALAR_LINE_SUFFIX);
1452
1635
  }
1453
1636
  if (!resume_scalar_line(s))
1454
- return emit(
1455
- l,
1456
- valid,
1457
- provisional_indentation(s, s->scalar_spaces)
1458
- ? UNFINISHED_MISSING_INDENTATION
1459
- : MISSING_INDENTATION
1460
- );
1637
+ return emit(l, valid, missing_indentation(s, s->scalar_spaces));
1461
1638
  } else if (space(l->lookahead)) {
1462
- bool broken = false;
1463
- uint32_t indentation = 0;
1464
- bool tab = false;
1465
- while (space(l->lookahead)) {
1466
- broken |= newline(l->lookahead);
1467
- if (newline(l->lookahead)) {
1468
- indentation = 0;
1469
- tab = false;
1470
- } else if (l->lookahead == '\t')
1471
- tab = true;
1472
- else if (!tab)
1473
- indentation++;
1474
- step(l);
1475
- }
1476
- bool more = !l->eof(l) &&
1477
- l->lookahead !=
1478
- '#' &&
1479
- (!s->flow || !flow_indicator(l->lookahead)) &&
1480
- (!broken || s->flow || indentation > s->indent);
1481
- if (more && l->lookahead == ':') {
1482
- step(l);
1483
- s->eof_continuation = l->eof(l);
1484
- more = !colon_boundary(l, s->flow);
1485
- }
1486
- if (
1487
- more &&
1488
- l->get_column(l) ==
1489
- 0 &&
1490
- (l->lookahead == 0xfeff || document_marker(l))
1491
- )
1492
- more = false;
1493
- if (more && !broken) {
1639
+ enum PlainSpace next = plain_space(s, l);
1640
+ if (next == PLAIN_SAME_LINE) {
1494
1641
  text = true;
1642
+ } else if (next == PLAIN_NEXT_LINE && valid[PLAIN_CONTINUE]) {
1643
+ s->continuation = true;
1644
+ return emit(l, valid, PLAIN_CONTINUE);
1495
1645
  } else {
1496
- if (more && emit(l, valid, PLAIN_CONTINUE)) {
1497
- s->continuation = true;
1498
- return true;
1499
- }
1500
- if (!emit(l, valid, PLAIN_END))
1501
- return false;
1502
- s->mode = NORMAL;
1503
- return true;
1646
+ s->eof_continuation |= l->eof(l);
1647
+ return end_plain(s, l, valid);
1504
1648
  }
1505
1649
  }
1506
- if (!text && scan_invalid_character(l, valid, false))
1507
- return true;
1650
+ if (!text && scan_invalid_character(l, valid, false)) return true;
1508
1651
  l->mark_end(l);
1509
1652
  while (!l->eof(l)) {
1510
1653
  int32_t c = l->lookahead;
1511
1654
  if (newline(c) || invalid_unquoted(c) || (s->flow && flow_indicator(c)))
1512
1655
  break;
1513
1656
  if (c == ':') {
1514
- step(l);
1515
- if (colon_boundary(l, s->flow)) {
1657
+ if (step_boundary(l, s->flow)) {
1516
1658
  s->eof_continuation = l->eof(l);
1517
1659
  break;
1518
1660
  }
@@ -1523,8 +1665,7 @@ static bool scan_plain(Scanner *s, TSLexer *l, const bool *valid) {
1523
1665
  if (blank(c)) {
1524
1666
  step(l);
1525
1667
  skip_blanks(l);
1526
- if (l->eof(l) || newline(l->lookahead) || l->lookahead == '#')
1527
- break;
1668
+ if (layout_follows(l)) break;
1528
1669
  if (invalid_unquoted(l->lookahead)) {
1529
1670
  text = true;
1530
1671
  l->mark_end(l);
@@ -1536,12 +1677,14 @@ static bool scan_plain(Scanner *s, TSLexer *l, const bool *valid) {
1536
1677
  text = true;
1537
1678
  l->mark_end(l);
1538
1679
  }
1539
- if (text)
1540
- return emit(l, valid, SCALAR_TEXT);
1541
- if (!emit(l, valid, PLAIN_END))
1542
- return false;
1543
- s->mode = NORMAL;
1544
- return true;
1680
+ if (text) return emit(l, valid, SCALAR_TEXT);
1681
+ return end_plain(s, l, valid);
1682
+ }
1683
+
1684
+ static bool end_block_scalar(Scanner *s, TSLexer *l, const bool *valid) {
1685
+ end_scalar(s);
1686
+ reset_line(s);
1687
+ return emit(l, valid, BLOCK_SCALAR_END);
1545
1688
  }
1546
1689
 
1547
1690
  static bool scan_block_header(Scanner *s, TSLexer *l, const bool *valid) {
@@ -1549,8 +1692,7 @@ static bool scan_block_header(Scanner *s, TSLexer *l, const bool *valid) {
1549
1692
  s->mode = BLOCK_DETECT;
1550
1693
  return emit(l, valid, BLOCK_HEADER_END);
1551
1694
  }
1552
- if (scan_invalid_character(l, valid, false))
1553
- return true;
1695
+ if (scan_invalid_character(l, valid, false)) return true;
1554
1696
  if (newline(l->lookahead)) {
1555
1697
  s->mode = BLOCK_HEADER_DONE;
1556
1698
  return line_break(l, valid, BLOCK_HEADER_BREAK);
@@ -1559,7 +1701,7 @@ static bool scan_block_header(Scanner *s, TSLexer *l, const bool *valid) {
1559
1701
  s->header_separated = true;
1560
1702
  return scan_separation(l, valid);
1561
1703
  }
1562
- if (l->lookahead == '#' && valid[COMMENT_START])
1704
+ if (l->lookahead == '#')
1563
1705
  return start_comment(s, l, valid, BLOCK_HEADER, !s->separated);
1564
1706
  if (l->lookahead >= '1' && l->lookahead <= '9') {
1565
1707
  if (valid[INDENTATION_INDICATOR] && !s->header_separated) {
@@ -1581,127 +1723,30 @@ static bool scan_block_header(Scanner *s, TSLexer *l, const bool *valid) {
1581
1723
  while (
1582
1724
  !l->eof(l) &&
1583
1725
  !space(l->lookahead) &&
1584
- l->lookahead !=
1585
- '#' &&
1726
+ l->lookahead != '#' &&
1586
1727
  !invalid_unquoted(l->lookahead) &&
1587
1728
  !(l->lookahead >= '1' && l->lookahead <= '9') &&
1588
- l->lookahead !=
1589
- '+' &&
1729
+ l->lookahead != '+' &&
1590
1730
  l->lookahead != '-'
1591
1731
  )
1592
1732
  step(l);
1593
1733
  return finish(l, valid, INVALID_BLOCK_HEADER);
1594
1734
  }
1595
1735
 
1596
- static void reset_line(Scanner *s) {
1597
- s->line = true;
1598
- s->line_context = false;
1599
- s->line_prefixed = false;
1600
- s->line_indent = 0;
1601
- s->line_mapping_key = false;
1602
- s->prefix_invalid = false;
1603
- s->after_document_end = false;
1604
- }
1605
-
1606
- static void close_document(Scanner *s) {
1607
- s->document = false;
1608
- s->document_content = false;
1609
- s->explicit_document_required = true;
1610
- }
1611
- static void open_document(Scanner *s, bool started) {
1612
- s->document = true;
1613
- s->document_started = started;
1614
- s->document_content = false;
1615
- s->eof_continuation = false;
1616
- s->flow = 0;
1617
- s->indent = -1;
1618
- s->provisional_indent = -2;
1619
- s->block_out = false;
1620
- }
1621
-
1622
- static bool scan_boundary(Scanner *s, TSLexer *l, const bool *valid) {
1623
- if (s->mode == SINGLE || s->mode == DOUBLE) {
1624
- s->mode = NORMAL;
1625
- s->prefix = false;
1626
- s->scalar_indent = false;
1627
- return emit(
1628
- l,
1629
- valid,
1630
- s->boundary_pending ? INCOMPLETE_QUOTE_CLOSE : MISSING_QUOTE_CLOSE
1631
- );
1632
- }
1633
- if (s->mode == PLAIN) {
1634
- s->mode = NORMAL;
1635
- return emit(l, valid, PLAIN_END);
1636
- }
1637
- if (s->mode == BLOCK_BODY) {
1638
- s->mode = NORMAL;
1639
- reset_line(s);
1640
- return emit(l, valid, BLOCK_SCALAR_END);
1641
- }
1642
- const enum Token closings[] = {
1643
- EMPTY_BLOCK_NODE,
1644
- s->boundary_pending ? INCOMPLETE_FLOW_SEQUENCE_CLOSE
1645
- : MISSING_FLOW_SEQUENCE_CLOSE,
1646
- s->boundary_pending ? INCOMPLETE_FLOW_MAPPING_CLOSE
1647
- : MISSING_FLOW_MAPPING_CLOSE,
1648
- MAPPING_END,
1649
- SEQUENCE_END,
1650
- DEDENT,
1651
- RESTORE_INDENT
1652
- };
1653
- if (emit_closing(s, l, valid, closings, sizeof(closings) / sizeof(*closings)))
1654
- return true;
1655
- if (valid[DOCUMENT_CLOSE] && s->document && s->document_started) {
1656
- close_document(s);
1657
- return emit(l, valid, DOCUMENT_CLOSE);
1658
- }
1659
- enum Boundary boundary = (enum Boundary)s->boundary;
1660
- bool opens = boundary == DOCUMENT_START_LINE || boundary == DIRECTIVE_LINE;
1661
- if (opens && valid[DOCUMENT_OPEN] && !s->document) {
1662
- open_document(s, false);
1663
- return emit(l, valid, DOCUMENT_OPEN);
1664
- }
1665
- if (boundary == DIRECTIVE_LINE || boundary == STREAM_BOM) {
1666
- if (
1667
- boundary ==
1668
- DIRECTIVE_LINE &&
1669
- s->explicit_document_required &&
1670
- valid[MISSING_DOCUMENT_END]
1671
- ) {
1672
- s->explicit_document_required = false;
1673
- return emit(l, valid, MISSING_DOCUMENT_END);
1674
- }
1675
- return false;
1676
- }
1677
- enum Token token =
1678
- boundary == DOCUMENT_START_LINE ? DOCUMENT_START : DOCUMENT_END;
1679
- if (!valid[token])
1680
- return false;
1681
- for (unsigned i = 0; i < 3; i++)
1682
- step(l);
1683
- l->mark_end(l);
1684
- s->document_started = token == DOCUMENT_START;
1685
- s->after_document_end = token == DOCUMENT_END;
1686
- s->explicit_document_required = false;
1687
- return emit(l, valid, token);
1688
- }
1689
-
1690
1736
  static bool detect_block_indent(Scanner *s, TSLexer *l, const bool *valid) {
1691
1737
  if (s->block_indent < 0) {
1692
1738
  uint32_t longest = 0;
1693
1739
  for (;;) {
1694
1740
  uint32_t spaces = count_spaces(l);
1695
1741
  if (newline(l->lookahead)) {
1696
- if (spaces > longest)
1697
- longest = spaces;
1742
+ if (spaces > longest) longest = spaces;
1698
1743
  skip_line_break(l);
1699
1744
  } else {
1700
- bool content = !l->eof(l) && spaces > s->indent;
1701
- if (
1702
- content && !spaces && (l->lookahead == 0xfeff || document_marker(l))
1703
- )
1745
+ int32_t first = l->lookahead;
1746
+ bool content = !l->eof(l) && spaces > content_indent(s);
1747
+ if (content && !spaces && (first == 0xfeff || document_marker(l)))
1704
1748
  content = false;
1749
+ s->block_marker_eof = content && !spaces && partial_marker(l, first);
1705
1750
  s->block_indent = content ? spaces
1706
1751
  : longest > s->indent ? longest
1707
1752
  : s->indent + 1;
@@ -1713,35 +1758,33 @@ static bool detect_block_indent(Scanner *s, TSLexer *l, const bool *valid) {
1713
1758
  s->mode = BLOCK_BODY;
1714
1759
  return emit(l, valid, BLOCK_BODY_START);
1715
1760
  }
1716
- /* Cache the layout run to avoid repeated lookahead on shallow tab lines. */
1717
1761
  static bool block_stream_layout_follows(Scanner *s, TSLexer *l) {
1718
1762
  uint32_t lines = 1;
1763
+ bool shallow_comment = false;
1764
+ s->block_marker_eof = false;
1719
1765
  for (;;) {
1720
1766
  skip_blanks(l);
1721
- if (l->lookahead == '#') {
1722
- do {
1723
- step(l);
1724
- } while (!l->eof(l) && !newline(l->lookahead));
1725
- }
1726
- if (l->eof(l))
1767
+ if (l->lookahead == '#') skip_line(l);
1768
+ if (l->eof(l)) {
1769
+ if (!shallow_comment) s->eof_continuation = true;
1727
1770
  return true;
1771
+ }
1728
1772
  if (!newline(l->lookahead)) {
1729
1773
  s->block_layout_lines = lines;
1730
- return l->get_column(l) ==
1731
- 0 &&
1732
- (l->lookahead == 0xfeff || l->lookahead == '%' || document_marker(l));
1774
+ if (l->get_column(l) != 0) return false;
1775
+ int32_t first = l->lookahead;
1776
+ if (first == 0xfeff || first == '%' || document_marker(l)) return true;
1777
+ s->block_marker_eof = partial_marker(l, first);
1778
+ return false;
1733
1779
  }
1734
1780
  skip_line_break(l);
1735
1781
  lines++;
1782
+ if (count_spaces(l) < s->block_indent && l->lookahead == '#')
1783
+ shallow_comment = true;
1736
1784
  }
1737
1785
  }
1738
1786
  static bool scan_block_body(Scanner *s, TSLexer *l, const bool *valid) {
1739
- if (l->eof(l)) {
1740
- s->mode = NORMAL;
1741
- s->block_layout_lines = 0;
1742
- reset_line(s);
1743
- return emit(l, valid, BLOCK_SCALAR_END);
1744
- }
1787
+ if (l->eof(l)) return end_block_scalar(s, l, valid);
1745
1788
  uint32_t spaces = count_spaces(l);
1746
1789
  int32_t first = l->lookahead;
1747
1790
  bool empty = newline(first);
@@ -1749,24 +1792,20 @@ static bool scan_block_body(Scanner *s, TSLexer *l, const bool *valid) {
1749
1792
  bool shallow_tab = spaces < s->block_indent && first == '\t';
1750
1793
  bool leading = s->block_leading && !s->block_explicit_indent;
1751
1794
  bool end = l->eof(l) && (spaces <= s->block_indent || leading);
1795
+ if (end) s->eof_continuation = true;
1752
1796
  if (shallow_tab && !s->block_layout_lines)
1753
1797
  end = block_stream_layout_follows(s, l);
1754
1798
  if (
1755
1799
  end ||
1756
1800
  (!empty &&
1757
1801
  ((spaces <= s->indent && !shallow_tab) ||
1802
+ spaces <= outdent_boundary(s) ||
1758
1803
  (spaces < s->block_indent && first == '#')))
1759
- ) {
1760
- s->mode = NORMAL;
1761
- s->block_layout_lines = 0;
1762
- reset_line(s);
1763
- return emit(l, valid, BLOCK_SCALAR_END);
1764
- }
1765
- if (s->block_layout_lines)
1766
- s->block_layout_lines--;
1804
+ )
1805
+ return end_block_scalar(s, l, valid);
1806
+ if (s->block_layout_lines) s->block_layout_lines--;
1767
1807
  s->block_empty = empty && (spaces <= s->block_indent || leading);
1768
- if (!s->block_empty)
1769
- s->block_leading = false;
1808
+ if (!s->block_empty) s->block_leading = false;
1770
1809
  s->block_prefix = true;
1771
1810
  s->scalar_indent = true;
1772
1811
  s->mode = BLOCK_LINE;
@@ -1790,22 +1829,26 @@ static bool scan_block_line(Scanner *s, TSLexer *l, const bool *valid) {
1790
1829
  step(l);
1791
1830
  consumed = true;
1792
1831
  }
1793
- if (consumed) {
1794
- return finish(l, valid, SCALAR_LINE_PREFIX);
1795
- }
1832
+ if (consumed) return finish(l, valid, SCALAR_LINE_PREFIX);
1796
1833
  }
1797
1834
  if (s->scalar_indent) {
1798
1835
  s->scalar_indent = false;
1799
1836
  if (s->block_empty && s->block_leading && l->lookahead == ' ') {
1800
1837
  count_spaces(l);
1801
- return finish(l, valid, INVALID_INDENTATION);
1838
+ return finish(
1839
+ l,
1840
+ valid,
1841
+ s->block_marker_eof ? UNFINISHED_INVALID_INDENTATION
1842
+ : INVALID_INDENTATION
1843
+ );
1802
1844
  }
1803
1845
  if (!s->block_empty && l->get_column(l) < s->block_indent)
1804
1846
  return emit(
1805
1847
  l,
1806
1848
  valid,
1807
- s->boundary_pending ? UNFINISHED_MISSING_INDENTATION
1808
- : MISSING_INDENTATION
1849
+ s->boundary_pending || (s->block_marker_eof && s->block_layout_lines)
1850
+ ? UNFINISHED_MISSING_INDENTATION
1851
+ : MISSING_INDENTATION
1809
1852
  );
1810
1853
  }
1811
1854
  if (newline(l->lookahead)) {
@@ -1816,6 +1859,92 @@ static bool scan_block_line(Scanner *s, TSLexer *l, const bool *valid) {
1816
1859
  return scan_line_text(l, valid, SCALAR_TEXT);
1817
1860
  }
1818
1861
 
1862
+ static void close_document(Scanner *s) {
1863
+ s->document_content = false;
1864
+ s->explicit_document_required = true;
1865
+ }
1866
+ static void open_document(Scanner *s, bool started) {
1867
+ s->document_started = started;
1868
+ s->document_start_line = false;
1869
+ s->document_content = false;
1870
+ s->eof_continuation = false;
1871
+ s->directive_kind = 0;
1872
+ s->flow = 0;
1873
+ s->indent = -1;
1874
+ s->outdent_count = 0;
1875
+ s->outdenting = false;
1876
+ s->provisional_indent = -2;
1877
+ s->block_out = false;
1878
+ }
1879
+
1880
+ static bool check_boundary(Scanner *s, TSLexer *l, const bool *valid) {
1881
+ int32_t first = l->lookahead;
1882
+ enum Boundary boundary = line_boundary(s, l);
1883
+ if (!boundary && first != '-' && first != '.') return false;
1884
+ s->boundary = (uint8_t)boundary;
1885
+ s->boundary_pending = l->eof(l)
1886
+ ? first == '-' ? DOCUMENT_START_LINE : DOCUMENT_END_LINE
1887
+ : NO_BOUNDARY;
1888
+ s->boundary_checked = true;
1889
+ return emit(l, valid, BOUNDARY_CHECK);
1890
+ }
1891
+ static bool scan_boundary(Scanner *s, TSLexer *l, const bool *valid) {
1892
+ if (s->mode == SINGLE || s->mode == DOUBLE) {
1893
+ end_scalar(s);
1894
+ return emit(
1895
+ l,
1896
+ valid,
1897
+ s->boundary_pending ? INCOMPLETE_QUOTE_CLOSE : MISSING_QUOTE_CLOSE
1898
+ );
1899
+ }
1900
+ if (s->mode == BLOCK_BODY) return end_block_scalar(s, l, valid);
1901
+ const enum Token closings[] = {
1902
+ EMPTY_BLOCK_NODE,
1903
+ s->boundary_pending ? INCOMPLETE_FLOW_SEQUENCE_CLOSE
1904
+ : MISSING_FLOW_SEQUENCE_CLOSE,
1905
+ s->boundary_pending ? INCOMPLETE_FLOW_MAPPING_CLOSE
1906
+ : MISSING_FLOW_MAPPING_CLOSE,
1907
+ };
1908
+ if (
1909
+ emit_first(s, l, valid, closings, COUNT(closings)) ||
1910
+ end_collection(s, l, valid)
1911
+ )
1912
+ return true;
1913
+ if (restore_indent(s, l, valid)) return true;
1914
+ if (valid[DOCUMENT_CLOSE] && s->document_started) {
1915
+ close_document(s);
1916
+ return emit(l, valid, DOCUMENT_CLOSE);
1917
+ }
1918
+ enum Boundary boundary = (enum Boundary)s->boundary;
1919
+ bool opens = boundary == DOCUMENT_START_LINE || boundary == DIRECTIVE_LINE;
1920
+ if (opens && valid[DOCUMENT_OPEN]) {
1921
+ open_document(s, false);
1922
+ return emit(l, valid, DOCUMENT_OPEN);
1923
+ }
1924
+ if (boundary == DIRECTIVE_LINE || boundary == STREAM_BOM) {
1925
+ if (
1926
+ boundary == DIRECTIVE_LINE &&
1927
+ s->explicit_document_required &&
1928
+ valid[MISSING_DOCUMENT_END]
1929
+ ) {
1930
+ s->explicit_document_required = false;
1931
+ return emit(l, valid, MISSING_DOCUMENT_END);
1932
+ }
1933
+ return false;
1934
+ }
1935
+ enum Token token =
1936
+ boundary == DOCUMENT_START_LINE ? DOCUMENT_START : DOCUMENT_END;
1937
+ if (!valid[token]) return false;
1938
+ for (unsigned i = 0; i < 3; i++) step(l);
1939
+ l->mark_end(l);
1940
+ s->document_started = token == DOCUMENT_START;
1941
+ s->document_start_line = token == DOCUMENT_START;
1942
+ s->after_document_end = token == DOCUMENT_END;
1943
+ s->explicit_document_required = false;
1944
+ s->directive_kind = 0;
1945
+ return emit(l, valid, token);
1946
+ }
1947
+
1819
1948
  static bool scan_comment(Scanner *s, TSLexer *l, const bool *valid) {
1820
1949
  if (s->mode == COMMENT_BEGIN) {
1821
1950
  if (s->first) {
@@ -1826,11 +1955,9 @@ static bool scan_comment(Scanner *s, TSLexer *l, const bool *valid) {
1826
1955
  return take(l, valid, COMMENT_MARKER);
1827
1956
  }
1828
1957
  if (l->eof(l) || newline(l->lookahead)) {
1829
- if (!emit(l, valid, COMMENT_END))
1830
- return false;
1831
1958
  s->mode = s->return_mode;
1832
1959
  s->return_mode = NORMAL;
1833
- return true;
1960
+ return emit(l, valid, COMMENT_END);
1834
1961
  }
1835
1962
  return scan_line_text(l, valid, COMMENT_TEXT);
1836
1963
  }
@@ -1858,16 +1985,15 @@ static bool scan_prefix(Scanner *s, TSLexer *l, const bool *valid) {
1858
1985
  do {
1859
1986
  step(l);
1860
1987
  } while (
1861
- l->lookahead ==
1862
- ' ' &&
1988
+ l->lookahead == ' ' &&
1863
1989
  (excess || !s->prefix_invalid || l->get_column(l) < s->indent)
1864
1990
  );
1991
+ if (!excess) return finish(l, valid, INDENTATION);
1865
1992
  return finish(
1866
1993
  l,
1867
1994
  valid,
1868
- excess
1869
- ? s->prefix_eof ? UNFINISHED_INVALID_INDENTATION : INVALID_INDENTATION
1870
- : INDENTATION
1995
+ s->prefix_eof & PREFIX_INDENTATION ? UNFINISHED_INVALID_INDENTATION
1996
+ : INVALID_INDENTATION
1871
1997
  );
1872
1998
  }
1873
1999
  if (blank(l->lookahead)) {
@@ -1879,7 +2005,7 @@ static bool scan_prefix(Scanner *s, TSLexer *l, const bool *valid) {
1879
2005
  return finish(
1880
2006
  l,
1881
2007
  valid,
1882
- s->prefix_eof || provisional_indentation(s, s->line_indent)
2008
+ s->prefix_eof & PREFIX_TAB || provisional_indentation(s, s->line_indent)
1883
2009
  ? UNFINISHED_TAB_IN_INDENTATION
1884
2010
  : TAB_IN_INDENTATION
1885
2011
  );
@@ -1894,68 +2020,57 @@ static bool scan_prefix(Scanner *s, TSLexer *l, const bool *valid) {
1894
2020
  s->flow &&
1895
2021
  !newline(l->lookahead) &&
1896
2022
  !l->eof(l) &&
1897
- l->lookahead !=
1898
- '#' &&
2023
+ l->lookahead != '#' &&
1899
2024
  s->line_indent <= s->indent
1900
2025
  ) {
1901
2026
  s->indent_checked = true;
1902
- return emit(
1903
- l,
1904
- valid,
1905
- provisional_indentation(s, s->line_indent)
1906
- ? UNFINISHED_MISSING_INDENTATION
1907
- : MISSING_INDENTATION
1908
- );
2027
+ return emit(l, valid, missing_indentation(s, s->line_indent));
1909
2028
  }
1910
2029
  s->mode = NORMAL;
2030
+ s->tab_invalid = false;
2031
+ s->prefix_tab = false;
2032
+ s->indent_checked = false;
2033
+ s->prefix_eof = 0;
1911
2034
  return emit(l, valid, LINE_PREFIX_END);
1912
2035
  }
1913
2036
 
2037
+ static bool start_pair(Scanner *s, TSLexer *l, const bool *valid) {
2038
+ s->key_state = KEY_NONE;
2039
+ s->first_pair = !any_valid(valid, mapping_endings, COUNT(mapping_endings));
2040
+ return emit(l, valid, PAIR_START);
2041
+ }
1914
2042
  static bool
1915
2043
  scan_node_start(Scanner *s, TSLexer *l, const bool *valid, int64_t column) {
1916
2044
  int32_t first = l->lookahead;
1917
2045
  enum Token kind = s->flow ? node_start(first) : classify_block_start(s, l);
1918
- if (!s->line && valid[DOCUMENT_COMPACT_START] && block_collection(kind))
2046
+ if (!s->line && valid[INVALID_COMPACT_START] && block_collection(kind))
1919
2047
  return emit(
1920
2048
  l,
1921
2049
  valid,
1922
- s->block_eof ? UNFINISHED_INVALID_DOCUMENT_COLLECTION_START
1923
- : DOCUMENT_COMPACT_START
2050
+ s->block_eof ? UNFINISHED_INVALID_COMPACT_COLLECTION_START
2051
+ : INVALID_COMPACT_START
1924
2052
  );
1925
2053
  if (
1926
- !s->flow &&
1927
- s->line &&
1928
- column ==
1929
- s->indent &&
1930
- kind !=
1931
- SEQUENCE_START &&
1932
- valid[SEQUENCE_END]
2054
+ s->document_start_line &&
2055
+ valid[DOCUMENT_COMPACT_START] &&
2056
+ block_collection(kind)
1933
2057
  )
1934
- return emit(l, valid, SEQUENCE_END);
1935
- if (
1936
- !s->flow &&
1937
- s->line &&
1938
- (column == s->indent || s->prefix_invalid) &&
1939
- kind ==
1940
- SEQUENCE_START &&
1941
- valid[MAPPING_END]
1942
- ) {
1943
- s->eof_continuation = s->block_eof;
1944
- return emit(l, valid, MAPPING_END);
1945
- }
2058
+ return emit(
2059
+ l,
2060
+ valid,
2061
+ s->block_eof ? UNFINISHED_INVALID_DOCUMENT_COLLECTION_START
2062
+ : DOCUMENT_COMPACT_START
2063
+ );
1946
2064
  if (
1947
2065
  !s->flow &&
1948
2066
  s->line &&
1949
2067
  (column == s->indent || s->prefix_invalid) &&
1950
2068
  valid[PAIR_START] &&
1951
2069
  kind != SEQUENCE_START
1952
- ) {
1953
- s->key_done = false;
1954
- return emit(l, valid, PAIR_START);
1955
- }
2070
+ )
2071
+ return start_pair(s, l, valid);
1956
2072
  if (
1957
- kind ==
1958
- MAPPING_START &&
2073
+ kind == MAPPING_START &&
1959
2074
  !valid[MAPPING_START] &&
1960
2075
  !valid[INDENT] &&
1961
2076
  !valid[PAIR_START]
@@ -1967,24 +2082,19 @@ scan_node_start(Scanner *s, TSLexer *l, const bool *valid, int64_t column) {
1967
2082
  if (s->block_eof && s->provisional_indent == -2 && column > s->indent)
1968
2083
  s->provisional_indent = s->indent;
1969
2084
  enum Token shift = column < s->indent ? OUTDENT : INDENT;
1970
- if (column != s->indent && emit_closing(s, l, valid, &shift, 1))
1971
- return true;
2085
+ if (column != s->indent && valid[shift])
2086
+ return emit_structure(s, l, valid, shift);
1972
2087
  if (column == s->indent || (s->line && s->prefix_invalid)) {
1973
- enum Token token = kind == MAPPING_START && valid[PAIR_START] ? PAIR_START
1974
- : kind == SEQUENCE_START && valid[ENTRY_START] ? ENTRY_START
1975
- : kind;
1976
- if (valid[token]) {
1977
- if (token == PAIR_START)
1978
- s->key_done = false;
1979
- return emit(l, valid, token);
1980
- }
2088
+ if (kind == MAPPING_START && valid[PAIR_START])
2089
+ return start_pair(s, l, valid);
2090
+ if (kind == SEQUENCE_START && valid[ENTRY_START])
2091
+ return emit(l, valid, ENTRY_START);
2092
+ if (valid[kind]) return emit_structure(s, l, valid, kind);
1981
2093
  }
1982
2094
  }
1983
- if (kind == PLAIN_START || (kind == MAPPING_START && valid[PLAIN_START]))
1984
- return start_plain(s, l, valid);
2095
+ if (kind == PLAIN_START) return start_plain(s, l, valid);
1985
2096
  if (kind == PROPERTIES_START) {
1986
2097
  s->json = false;
1987
- s->property_colon_content = false;
1988
2098
  s->properties_ready = false;
1989
2099
  s->property_separation_notified = false;
1990
2100
  s->property_keys = 0;
@@ -1993,50 +2103,50 @@ scan_node_start(Scanner *s, TSLexer *l, const bool *valid, int64_t column) {
1993
2103
  }
1994
2104
 
1995
2105
  static bool scan_node_open(Scanner *s, TSLexer *l, const bool *valid) {
1996
- if (
1997
- (l->lookahead == '\'' && valid[SINGLE_OPEN]) ||
1998
- (l->lookahead == '"' && valid[DOUBLE_OPEN])
1999
- ) {
2000
- bool single = l->lookahead == '\'';
2001
- s->mode = single ? SINGLE : DOUBLE;
2002
- s->quote_line_empty = false;
2003
- return take(l, valid, single ? SINGLE_OPEN : DOUBLE_OPEN);
2004
- }
2005
- if (
2006
- (l->lookahead == '[' && valid[FLOW_SEQUENCE_OPEN]) ||
2007
- (l->lookahead == '{' && valid[FLOW_MAPPING_OPEN])
2008
- ) {
2009
- bool sequence = l->lookahead == '[';
2010
- s->flow++;
2011
- return take(l, valid, sequence ? FLOW_SEQUENCE_OPEN : FLOW_MAPPING_OPEN);
2012
- }
2013
- if (
2014
- (l->lookahead == '|' && valid[LITERAL_INDICATOR]) ||
2015
- (l->lookahead == '>' && valid[FOLDED_INDICATOR])
2016
- ) {
2017
- bool literal = l->lookahead == '|';
2018
- s->mode = BLOCK_HEADER;
2019
- s->block_indent = -1;
2020
- s->block_layout_lines = 0;
2021
- s->block_explicit_indent = false;
2022
- s->header_separated = false;
2023
- return take(l, valid, literal ? LITERAL_INDICATOR : FOLDED_INDICATOR);
2106
+ switch (l->lookahead) {
2107
+ case '\'':
2108
+ case '"':
2109
+ s->mode = l->lookahead == '\'' ? SINGLE : DOUBLE;
2110
+ s->quote_line_empty = false;
2111
+ return take(l, valid, s->mode == SINGLE ? SINGLE_OPEN : DOUBLE_OPEN);
2112
+ case '[':
2113
+ case '{':
2114
+ s->flow++;
2115
+ return take(
2116
+ l,
2117
+ valid,
2118
+ l->lookahead == '[' ? FLOW_SEQUENCE_OPEN : FLOW_MAPPING_OPEN
2119
+ );
2120
+ case '|':
2121
+ case '>':
2122
+ s->mode = BLOCK_HEADER;
2123
+ s->block_indent = -1;
2124
+ s->block_layout_lines = 0;
2125
+ s->block_marker_eof = false;
2126
+ s->block_explicit_indent = false;
2127
+ s->header_separated = false;
2128
+ return take(
2129
+ l,
2130
+ valid,
2131
+ l->lookahead == '|' ? LITERAL_INDICATOR : FOLDED_INDICATOR
2132
+ );
2133
+ default:
2134
+ return false;
2024
2135
  }
2025
- return false;
2026
2136
  }
2027
2137
 
2028
2138
  static bool scan_line_context(Scanner *s, TSLexer *l, const bool *valid) {
2029
- s->line_indent = count_spaces(l);
2139
+ uint32_t line_indent = count_spaces(l);
2030
2140
  skip_blanks(l);
2031
- s->line_head = l->lookahead;
2032
- s->layout_only = l->eof(l) || newline(l->lookahead) || l->lookahead == '#';
2033
- if (s->line_head == '-' || s->line_head == ':') {
2034
- step(l);
2035
- if (!space(l->lookahead) && !l->eof(l))
2036
- s->line_head = 0;
2141
+ int32_t line_head = l->lookahead;
2142
+ bool layout_only = layout_follows(l);
2143
+ s->line_indent = line_indent;
2144
+ s->line_head = line_head;
2145
+ s->layout_only = layout_only;
2146
+ if (line_head == '-' || line_head == ':') {
2147
+ if (!step_boundary(l, false)) s->line_head = 0;
2037
2148
  } else if (
2038
- !s->flow &&
2039
- (s->line_head == '&' || s->line_head == '!' || s->line_head == '*')
2149
+ !s->flow && (line_head == '&' || line_head == '!' || line_head == '*')
2040
2150
  ) {
2041
2151
  s->line_mapping_key = classify_block_start(s, l) == MAPPING_START;
2042
2152
  }
@@ -2048,29 +2158,51 @@ static bool begin_line_prefix(Scanner *s, TSLexer *l, const bool *valid) {
2048
2158
  skip_blanks(l);
2049
2159
  bool prefix_invalid = !s->layout_only &&
2050
2160
  !s->flow &&
2051
- spaces >
2052
- s->indent &&
2053
- !valid[VALUE_START] &&
2054
- !valid[SEQUENCE_VALUE_START] &&
2161
+ spaces > s->indent &&
2162
+ !valid[BLOCK_OUT_VALUE_START] &&
2163
+ !valid[BLOCK_IN_VALUE_START] &&
2055
2164
  !valid[INDENT] &&
2056
2165
  (valid[PAIR_START] || valid[ENTRY_START]);
2057
2166
  bool tab_invalid = !s->layout_only && spaces <= s->indent;
2058
- s->prefix_eof = prefix_invalid && s->eof_continuation;
2167
+ s->prefix_eof =
2168
+ prefix_invalid && s->eof_continuation ? PREFIX_INDENTATION | PREFIX_TAB : 0;
2059
2169
  if (!s->layout_only && !s->flow) {
2060
2170
  bool unfinished;
2061
2171
  bool collection = block_collection(classify_block_node(l, &unfinished));
2062
- s->prefix_eof |= !tab_invalid && collection && unfinished;
2172
+ if (collection && unfinished && !tab_invalid) s->prefix_eof |= PREFIX_TAB;
2063
2173
  tab_invalid |= collection;
2064
2174
  }
2065
2175
  s->line_prefixed = true;
2066
2176
  return start_line_prefix(s, l, valid, prefix_invalid, tab_invalid, false);
2067
2177
  }
2068
2178
 
2179
+ static bool start_implicit_key(Scanner *s, TSLexer *l, const bool *valid) {
2180
+ int32_t first = l->lookahead;
2181
+ if (
2182
+ (first == '?' || first == ':') && step_boundary(l, first == ':' && s->flow)
2183
+ ) {
2184
+ if (valid[FLOW_SEQ_PAIR_START]) {
2185
+ s->json = false;
2186
+ return emit(l, valid, FLOW_SEQ_PAIR_START);
2187
+ }
2188
+ return emit_indicator(
2189
+ s,
2190
+ l,
2191
+ valid,
2192
+ first == '?' ? KEY_INDICATOR : VALUE_INDICATOR
2193
+ );
2194
+ }
2195
+ s->implicit_keys[0] |= 1;
2196
+ if (!s->flow) {
2197
+ s->block_out = false;
2198
+ s->colon_line_only = false;
2199
+ }
2200
+ return emit(l, valid, IMPLICIT_KEY_START);
2201
+ }
2069
2202
  static bool
2070
2203
  scan_entry(Scanner *s, TSLexer *l, const bool *valid, int64_t column) {
2071
2204
  if (
2072
- l->lookahead ==
2073
- ',' &&
2205
+ l->lookahead == ',' &&
2074
2206
  !valid[FLOW_SEPARATOR] &&
2075
2207
  valid[UNEXPECTED_FLOW_SEPARATOR]
2076
2208
  )
@@ -2079,52 +2211,22 @@ scan_entry(Scanner *s, TSLexer *l, const bool *valid, int64_t column) {
2079
2211
  s->json = false;
2080
2212
  return emit(l, valid, FLOW_MAP_PAIR_START);
2081
2213
  }
2082
- if (valid[IMPLICIT_KEY_START] && !(s->flow && flow_entry_end(l->lookahead))) {
2083
- int32_t first = l->lookahead;
2084
- bool indicator = false;
2085
- if (l->lookahead == '?' || l->lookahead == ':') {
2086
- step(l);
2087
- indicator = colon_boundary(l, first == ':' && s->flow);
2088
- }
2089
- if (indicator) {
2090
- if (valid[FLOW_SEQ_PAIR_START]) {
2091
- s->json = false;
2092
- return emit(l, valid, FLOW_SEQ_PAIR_START);
2093
- }
2094
- return emit_indicator(
2095
- s,
2096
- l,
2097
- valid,
2098
- first == '?' ? KEY_INDICATOR : VALUE_INDICATOR
2099
- );
2100
- }
2101
- s->implicit_keys[0] |= 1;
2102
- s->block_out = false;
2103
- return emit(l, valid, IMPLICIT_KEY_START);
2104
- }
2214
+ if (valid[IMPLICIT_KEY_START] && !(s->flow && flow_entry_end(l->lookahead)))
2215
+ return start_implicit_key(s, l, valid);
2105
2216
  if (l->lookahead == '?' && valid[KEY_INDICATOR]) {
2106
- step(l);
2107
- if (space(l->lookahead) || l->eof(l)) {
2217
+ if (step_boundary(l, false))
2108
2218
  return emit_indicator(s, l, valid, KEY_INDICATOR);
2109
- }
2110
2219
  return start_plain(s, l, valid);
2111
2220
  }
2112
2221
  if (l->lookahead == ':' && valid[VALUE_INDICATOR]) {
2113
2222
  bool adjacent = s->flow && s->json;
2114
- step(l);
2115
- if (adjacent || colon_boundary(l, s->flow)) {
2223
+ if (step_boundary(l, s->flow) || adjacent) {
2116
2224
  s->value_separation =
2117
2225
  s->flow && !adjacent && (l->lookahead == '[' || l->lookahead == '{');
2118
2226
  s->json = false;
2119
2227
  return emit_indicator(s, l, valid, VALUE_INDICATOR);
2120
2228
  }
2121
- bool unfinished = s->eof_continuation;
2122
- return start_plain(s, l, valid) ||
2123
- emit(
2124
- l,
2125
- valid,
2126
- unfinished ? UNFINISHED_MISSING_FLOW_SEPARATOR : MISSING_FLOW_SEPARATOR
2127
- );
2229
+ return start_plain(s, l, valid) || emit(l, valid, MISSING_FLOW_SEPARATOR);
2128
2230
  }
2129
2231
  if (l->lookahead == '-' && valid[SEQUENCE_INDICATOR]) {
2130
2232
  step(l);
@@ -2144,43 +2246,64 @@ scan_entry(Scanner *s, TSLexer *l, const bool *valid, int64_t column) {
2144
2246
  return close_flow(s, l, valid, MISSING_FLOW_MAPPING_CLOSE);
2145
2247
  if (l->lookahead == '}' && valid[MISSING_FLOW_SEQUENCE_CLOSE])
2146
2248
  return close_flow(s, l, valid, MISSING_FLOW_SEQUENCE_CLOSE);
2249
+ static const enum Token flow_starts[] = {
2250
+ PLAIN_START,
2251
+ SINGLE_START,
2252
+ DOUBLE_START,
2253
+ FLOW_SEQUENCE_START,
2254
+ FLOW_MAPPING_START
2255
+ };
2147
2256
  if (
2148
2257
  valid[MISSING_FLOW_SEPARATOR] &&
2149
- !valid[PLAIN_START] &&
2150
- !valid[SINGLE_START] &&
2151
- !valid[DOUBLE_START] &&
2152
- !valid[FLOW_SEQUENCE_START] &&
2153
- !valid[FLOW_MAPPING_START] &&
2258
+ !any_valid(valid, flow_starts, COUNT(flow_starts)) &&
2154
2259
  !flow_entry_end(l->lookahead)
2155
2260
  )
2156
2261
  return emit(
2157
2262
  l,
2158
2263
  valid,
2159
- s->eof_continuation ? UNFINISHED_MISSING_FLOW_SEPARATOR
2160
- : MISSING_FLOW_SEPARATOR
2264
+ eof_pending(s) ? UNFINISHED_MISSING_FLOW_SEPARATOR
2265
+ : MISSING_FLOW_SEPARATOR
2161
2266
  );
2162
- if (
2163
- valid[PAIR_START] ||
2164
- valid[ENTRY_START] ||
2165
- valid[MAPPING_START] ||
2166
- valid[SEQUENCE_START] ||
2167
- valid[PLAIN_START] ||
2168
- valid[INDENT] ||
2169
- valid[OUTDENT] ||
2170
- valid[SINGLE_START] ||
2171
- valid[DOUBLE_START] ||
2172
- valid[FLOW_SEQUENCE_START] ||
2173
- valid[FLOW_MAPPING_START] ||
2174
- valid[LITERAL_START] ||
2175
- valid[FOLDED_START] ||
2176
- valid[PROPERTIES_START] ||
2177
- valid[ALIAS_START]
2178
- ) {
2267
+ static const enum Token node_starts[] = {
2268
+ PAIR_START,
2269
+ ENTRY_START,
2270
+ MAPPING_START,
2271
+ SEQUENCE_START,
2272
+ PLAIN_START,
2273
+ INDENT,
2274
+ OUTDENT,
2275
+ SINGLE_START,
2276
+ DOUBLE_START,
2277
+ FLOW_SEQUENCE_START,
2278
+ FLOW_MAPPING_START,
2279
+ LITERAL_START,
2280
+ FOLDED_START,
2281
+ PROPERTIES_START,
2282
+ ALIAS_START
2283
+ };
2284
+ if (any_valid(valid, node_starts, COUNT(node_starts)))
2179
2285
  return scan_node_start(s, l, valid, column);
2180
- }
2181
2286
  return scan_node_open(s, l, valid);
2182
2287
  }
2183
2288
 
2289
+ static bool start_block_value(Scanner *s, TSLexer *l, const bool *valid) {
2290
+ uint32_t line_indent = s->line_indent;
2291
+ bool line = skip_layout_lines(l, s->line, &line_indent);
2292
+ int32_t line_head;
2293
+ if (l->eof(l) || line_head_boundary(s, l, line, &line_head))
2294
+ return emit(l, valid, EMPTY_BLOCK_NODE);
2295
+ if (line_head == ':' && !step_boundary(l, false)) line_head = 0;
2296
+ if (!block_value_follows(s, valid, line, line_indent, line_head))
2297
+ return emit(l, valid, EMPTY_BLOCK_NODE);
2298
+ if (valid[EXPLICIT_VALUE_START] && line_head == ':')
2299
+ return emit(l, valid, EXPLICIT_VALUE_START);
2300
+ s->block_out = valid[BLOCK_OUT_VALUE_START];
2301
+ return emit(
2302
+ l,
2303
+ valid,
2304
+ s->block_out ? BLOCK_OUT_VALUE_START : BLOCK_IN_VALUE_START
2305
+ );
2306
+ }
2184
2307
  static bool scan_content(Scanner *s, TSLexer *l, const bool *valid) {
2185
2308
  if (
2186
2309
  l->lookahead == 0xfeff && l->get_column(l) == 0 && valid[BYTE_ORDER_MARK]
@@ -2190,8 +2313,7 @@ static bool scan_content(Scanner *s, TSLexer *l, const bool *valid) {
2190
2313
  reset_line(s);
2191
2314
  return finish(l, valid, BYTE_ORDER_MARK);
2192
2315
  }
2193
- if (scan_invalid_character(l, valid, false))
2194
- return true;
2316
+ if (scan_invalid_character(l, valid, false)) return true;
2195
2317
  bool end = l->eof(l);
2196
2318
  if (s->after_document_end && !end) {
2197
2319
  do {
@@ -2202,92 +2324,78 @@ static bool scan_content(Scanner *s, TSLexer *l, const bool *valid) {
2202
2324
  return finish(l, valid, UNEXPECTED_DOCUMENT_END_CONTENT);
2203
2325
  }
2204
2326
  int64_t column = s->line ? s->line_indent : l->get_column(l);
2205
- if (
2206
- valid[EXPLICIT_VALUE_START] &&
2207
- l->lookahead ==
2208
- ':' &&
2209
- s->line_head ==
2210
- ':' &&
2211
- s->line &&
2212
- column == s->indent
2213
- )
2214
- return emit(l, valid, EXPLICIT_VALUE_START);
2215
- if (
2216
- valid[VALUE_START] || valid[SEQUENCE_VALUE_START] || valid[EMPTY_BLOCK_NODE]
2217
- ) {
2218
- if (block_value_follows(s, l, valid)) {
2219
- if (!s->line && valid[INVALID_COMPACT_START]) {
2220
- bool unfinished;
2221
- enum Token kind = classify_block_node(l, &unfinished);
2222
- if (block_collection(kind))
2223
- return emit(
2224
- l,
2225
- valid,
2226
- unfinished ? UNFINISHED_INVALID_COMPACT_COLLECTION_START
2227
- : INVALID_COMPACT_START
2228
- );
2229
- }
2230
- s->block_out = valid[VALUE_START];
2231
- return emit(l, valid, s->block_out ? VALUE_START : SEQUENCE_VALUE_START);
2232
- }
2233
- return emit(l, valid, EMPTY_BLOCK_NODE);
2234
- }
2235
2327
  if (valid[DOCUMENT_CLOSE] && end) {
2236
2328
  close_document(s);
2237
2329
  return emit(l, valid, DOCUMENT_CLOSE);
2238
2330
  }
2239
- if (valid[DOCUMENT_OPEN] && !end && !s->document) {
2331
+ if (valid[DOCUMENT_OPEN] && !end) {
2240
2332
  open_document(s, !s->explicit_document_required);
2241
2333
  return emit(l, valid, DOCUMENT_OPEN);
2242
2334
  }
2243
- if (valid[UNEXPECTED_CONTENT_START] && s->document_content && !end) {
2335
+ if (valid[UNEXPECTED_DOCUMENT_CONTENT_START] && s->document_content && !end) {
2244
2336
  s->document_content = false;
2245
2337
  return emit(
2246
2338
  l,
2247
2339
  valid,
2248
- s->eof_continuation || s->boundary_pending
2249
- ? UNFINISHED_UNEXPECTED_DOCUMENT_CONTENT_START
2250
- : UNEXPECTED_CONTENT_START
2340
+ eof_pending(s) ? UNFINISHED_UNEXPECTED_DOCUMENT_CONTENT_START
2341
+ : UNEXPECTED_DOCUMENT_CONTENT_START
2251
2342
  );
2252
2343
  }
2253
- if (!s->flow && !s->line) {
2254
- if (valid[MAPPING_END])
2255
- return emit(l, valid, MAPPING_END);
2256
- if (valid[SEQUENCE_END])
2257
- return emit(l, valid, SEQUENCE_END);
2344
+ if (
2345
+ !end &&
2346
+ valid[UNEXPECTED_COLLECTION_CONTENT_START] &&
2347
+ (!s->line ||
2348
+ (valid[PAIR_START] && s->line_head == '-') ||
2349
+ (valid[ENTRY_START] && s->line_head != '-'))
2350
+ ) {
2351
+ s->block_out = false;
2352
+ bool unfinished = eof_pending(s);
2353
+ if (s->line && valid[PAIR_START]) {
2354
+ classify_block_start(s, l);
2355
+ unfinished |= s->block_eof;
2356
+ }
2357
+ return emit(
2358
+ l,
2359
+ valid,
2360
+ unfinished ? UNFINISHED_UNEXPECTED_COLLECTION_CONTENT_START
2361
+ : UNEXPECTED_COLLECTION_CONTENT_START
2362
+ );
2258
2363
  }
2364
+ if ((end || (!s->flow && !s->line)) && end_collection(s, l, valid))
2365
+ return true;
2259
2366
  if (end) {
2260
2367
  static const enum Token endings[] = {
2261
- MAPPING_END,
2262
- SEQUENCE_END,
2263
2368
  INCOMPLETE_FLOW_SEQUENCE_CLOSE,
2264
2369
  INCOMPLETE_FLOW_MAPPING_CLOSE,
2265
2370
  END_OF_FILE
2266
2371
  };
2267
- return emit_closing(
2268
- s,
2269
- l,
2270
- valid,
2271
- endings,
2272
- sizeof(endings) / sizeof(*endings)
2273
- );
2372
+ return emit_first(s, l, valid, endings, COUNT(endings));
2274
2373
  }
2275
- if (valid[MAPPING_END] && column < s->indent)
2276
- return emit(l, valid, MAPPING_END);
2277
- if (
2278
- valid[SEQUENCE_END] &&
2279
- (column < s->indent || (s->line && l->lookahead != '-'))
2280
- )
2281
- return emit(l, valid, SEQUENCE_END);
2282
2374
  return scan_entry(s, l, valid, column);
2283
2375
  }
2284
2376
 
2285
- static bool scan(Scanner *s, TSLexer *l, const bool *valid);
2286
-
2287
2377
  static void begin_property(Scanner *s, unsigned key) {
2288
2378
  s->property_separation_notified = false;
2289
2379
  s->property_keys &= (uint8_t)~key;
2290
2380
  }
2381
+ static bool start_tag_handle(Scanner *s, TSLexer *l, const bool *valid) {
2382
+ s->directive_handle = false;
2383
+ step(l);
2384
+ s->handle_form = PRIMARY_HANDLE;
2385
+ if (l->lookahead == '!') s->handle_form = SECONDARY_HANDLE;
2386
+ else {
2387
+ while (!name_boundary(l)) {
2388
+ if (l->lookahead == '!') {
2389
+ s->handle_form = NAMED_HANDLE;
2390
+ break;
2391
+ }
2392
+ step(l);
2393
+ }
2394
+ }
2395
+ s->mode = HANDLE_SELECT;
2396
+ begin_property(s, TAG_KEY);
2397
+ return emit(l, valid, TAG_HANDLE_START);
2398
+ }
2291
2399
  static bool scan_properties(
2292
2400
  Scanner *s,
2293
2401
  TSLexer *l,
@@ -2295,50 +2403,25 @@ static bool scan_properties(
2295
2403
  bool property_pending
2296
2404
  ) {
2297
2405
  if (property_pending) {
2298
- bool content = !l->eof(l) && !(s->flow && flow_entry_end(l->lookahead));
2299
- if (
2300
- l->lookahead ==
2301
- ':' &&
2302
- !s->property_colon_content &&
2303
- !(s->line && !s->flow && valid[BLOCK_PROPERTY_CONTENT_START])
2304
- )
2305
- content = false;
2306
- if (!property_line_follows(s))
2307
- content = false;
2308
- if (!content) {
2309
- s->properties_ready = false;
2310
- return scan(s, l, valid);
2311
- }
2312
- if (
2313
- !s->separated &&
2314
- !s->property_separation_notified &&
2315
- valid[MISSING_SEPARATION]
2316
- ) {
2317
- s->property_separation_notified = true;
2318
- return emit(l, valid, MISSING_SEPARATION);
2319
- }
2406
+ if (separation_missing(s) && valid[MISSING_SEPARATION])
2407
+ return emit_missing_separation(s, l, valid);
2320
2408
  s->properties_ready = false;
2409
+ s->property_separation_notified = false;
2321
2410
  return emit(l, valid, property_content_start(s, l, valid));
2322
2411
  }
2412
+ bool anchor = l->lookahead == '&';
2413
+ bool tag = l->lookahead == '!';
2323
2414
  if (
2324
- !s->separated &&
2325
- !s->property_separation_notified &&
2415
+ separation_missing(s) &&
2326
2416
  valid[MISSING_SEPARATION] &&
2327
- ((l->lookahead ==
2328
- '&' &&
2329
- (valid[ANCHOR_INDICATOR] || valid[DUPLICATE_ANCHOR_START])) ||
2330
- (l->lookahead ==
2331
- '!' &&
2332
- (valid[SHORTHAND_TAG_START] || valid[DUPLICATE_TAG_START])))
2333
- ) {
2334
- s->property_separation_notified = true;
2335
- return emit(l, valid, MISSING_SEPARATION);
2336
- }
2417
+ ((anchor && (valid[ANCHOR_INDICATOR] || valid[DUPLICATE_ANCHOR_START])) ||
2418
+ (tag && (valid[SHORTHAND_TAG_START] || valid[DUPLICATE_TAG_START])))
2419
+ )
2420
+ return emit_missing_separation(s, l, valid);
2337
2421
  if (
2338
- (l->lookahead == '&' && valid[DUPLICATE_ANCHOR_START]) ||
2339
- (l->lookahead == '!' && valid[DUPLICATE_TAG_START])
2422
+ (anchor && valid[DUPLICATE_ANCHOR_START]) ||
2423
+ (tag && valid[DUPLICATE_TAG_START])
2340
2424
  ) {
2341
- bool anchor = l->lookahead == '&';
2342
2425
  bool unfinished = s->property_keys & (anchor ? ANCHOR_KEY : TAG_KEY);
2343
2426
  return emit(
2344
2427
  l,
@@ -2350,10 +2433,9 @@ static bool scan_properties(
2350
2433
  );
2351
2434
  }
2352
2435
  if (
2353
- (l->lookahead == '&' && valid[ANCHOR_INDICATOR]) ||
2436
+ (anchor && valid[ANCHOR_INDICATOR]) ||
2354
2437
  (l->lookahead == '*' && valid[ALIAS_INDICATOR])
2355
2438
  ) {
2356
- bool anchor = l->lookahead == '&';
2357
2439
  begin_property(s, anchor ? ANCHOR_KEY : 0);
2358
2440
  s->mode = anchor ? ANCHOR_BODY : ALIAS_BODY;
2359
2441
  s->first = true;
@@ -2361,17 +2443,14 @@ static bool scan_properties(
2361
2443
  return take(l, valid, anchor ? ANCHOR_INDICATOR : ALIAS_INDICATOR);
2362
2444
  }
2363
2445
  if (
2364
- l->lookahead ==
2365
- '!' &&
2446
+ tag &&
2366
2447
  (valid[VERBATIM_TAG_START] ||
2367
2448
  valid[SHORTHAND_TAG_START] ||
2368
2449
  valid[NON_SPECIFIC_TAG])
2369
2450
  ) {
2370
2451
  step(l);
2371
- if (l->lookahead == '<')
2372
- return emit(l, valid, VERBATIM_TAG_START);
2373
- if (!name_boundary(l))
2374
- return emit(l, valid, SHORTHAND_TAG_START);
2452
+ if (l->lookahead == '<') return emit(l, valid, VERBATIM_TAG_START);
2453
+ if (!name_boundary(l)) return emit(l, valid, SHORTHAND_TAG_START);
2375
2454
  l->mark_end(l);
2376
2455
  begin_property(s, TAG_KEY);
2377
2456
  return emit(l, valid, NON_SPECIFIC_TAG);
@@ -2384,121 +2463,28 @@ static bool scan_properties(
2384
2463
  s->mode = URI_BEGIN;
2385
2464
  return emit(l, valid, VERBATIM_TAG_OPEN);
2386
2465
  }
2387
- if (valid[TAG_HANDLE_START]) {
2388
- s->directive_handle = false;
2389
- step(l);
2390
- s->handle_form = PRIMARY_HANDLE;
2391
- if (l->lookahead == '!')
2392
- s->handle_form = SECONDARY_HANDLE;
2393
- else {
2394
- while (!name_boundary(l)) {
2395
- if (l->lookahead == '!') {
2396
- s->handle_form = NAMED_HANDLE;
2397
- break;
2398
- }
2399
- step(l);
2400
- }
2401
- }
2402
- s->mode = HANDLE_SELECT;
2403
- begin_property(s, TAG_KEY);
2404
- return emit(l, valid, TAG_HANDLE_START);
2405
- }
2466
+ if (valid[TAG_HANDLE_START]) return start_tag_handle(s, l, valid);
2406
2467
  return scan_content(s, l, valid);
2407
2468
  }
2408
2469
 
2409
- static bool
2410
- scan_normal(Scanner *s, TSLexer *l, const bool *valid, bool property_pending) {
2411
- if (
2412
- !property_pending &&
2413
- (valid[KEY_END] || valid[INVALID_KEY_END] || valid[FLOW_NODE_END])
2414
- )
2415
- return scan_key_end(s, l, valid);
2416
- if (
2417
- s->key_done &&
2418
- (valid[MISSING_VALUE_INDICATOR] || valid[INCOMPLETE_VALUE_INDICATOR])
2419
- ) {
2420
- s->key_done = false;
2421
- if (l->lookahead == ':') {
2422
- step(l);
2423
- if (colon_boundary(l, false))
2424
- return emit_indicator(s, l, valid, VALUE_INDICATOR);
2425
- }
2426
- return emit_missing(
2427
- l,
2428
- valid,
2429
- MISSING_VALUE_INDICATOR,
2430
- INCOMPLETE_VALUE_INDICATOR
2431
- );
2432
- }
2433
- if (s->line && !s->line_context && valid[LINE_CONTEXT])
2434
- return scan_line_context(s, l, valid);
2435
- if (s->line_context && !s->layout_only && !property_line_follows(s)) {
2436
- s->properties_ready = false;
2437
- property_pending = false;
2438
- }
2439
- static const enum Token restorations[] = {DEDENT, RESTORE_INDENT};
2440
- if (
2441
- !property_pending &&
2442
- emit_closing(
2443
- s,
2444
- l,
2445
- valid,
2446
- restorations,
2447
- sizeof(restorations) / sizeof(*restorations)
2448
- )
2449
- )
2450
- return true;
2451
- if (
2452
- !property_pending &&
2453
- s->line &&
2454
- s->line_context &&
2455
- !s->layout_only &&
2456
- !s->flow
2457
- ) {
2458
- if (valid[EMPTY_BLOCK_NODE] && !block_value_follows(s, l, valid))
2459
- return emit(l, valid, EMPTY_BLOCK_NODE);
2460
- if (
2461
- valid[MAPPING_END] &&
2462
- (s->line_indent <
2463
- s->indent ||
2464
- (s->line_indent ==
2465
- s->indent &&
2466
- s->line_head ==
2467
- '-' &&
2468
- !valid[VALUE_START]))
2469
- ) {
2470
- if (s->line_indent == s->indent) {
2471
- skip_blanks(l);
2472
- step(l);
2473
- s->eof_continuation = l->eof(l);
2474
- }
2475
- return emit(l, valid, MAPPING_END);
2476
- }
2477
- if (
2478
- valid[SEQUENCE_END] && (s->line_indent < s->indent || s->line_head != '-')
2479
- )
2480
- return emit(l, valid, SEQUENCE_END);
2481
- }
2470
+ static bool scan_layout(Scanner *s, TSLexer *l, const bool *valid) {
2482
2471
  if (
2483
2472
  s->line &&
2484
2473
  !s->line_prefixed &&
2485
- valid[LINE_PREFIX_START] &&
2486
2474
  (blank(l->lookahead) ||
2487
2475
  (s->flow &&
2488
- s->indent >=
2489
- 0 &&
2476
+ s->indent >= 0 &&
2490
2477
  !newline(l->lookahead) &&
2491
2478
  !l->eof(l) &&
2492
2479
  l->lookahead != '#'))
2493
2480
  )
2494
2481
  return begin_line_prefix(s, l, valid);
2495
- if (newline(l->lookahead) && valid[LINE_BREAK]) {
2482
+ if (newline(l->lookahead)) {
2496
2483
  reset_line(s);
2497
2484
  return line_break(l, valid, LINE_BREAK);
2498
2485
  }
2499
- if (blank(l->lookahead) && valid[SEPARATION])
2500
- return scan_separation(l, valid);
2501
- if (l->lookahead == '#' && valid[COMMENT_START])
2486
+ if (blank(l->lookahead)) return scan_separation(l, valid);
2487
+ if (l->lookahead == '#')
2502
2488
  return start_comment(
2503
2489
  s,
2504
2490
  l,
@@ -2506,110 +2492,151 @@ scan_normal(Scanner *s, TSLexer *l, const bool *valid, bool property_pending) {
2506
2492
  NORMAL,
2507
2493
  !s->separated && l->get_column(l) != 0
2508
2494
  );
2495
+ return false;
2496
+ }
2497
+
2498
+ static bool scan_key_colon(Scanner *s, TSLexer *l, const bool *valid) {
2499
+ if (
2500
+ s->key_state == BLOCK_KEY_ENDED &&
2501
+ (!s->line || s->layout_only) &&
2502
+ scan_layout(s, l, valid)
2503
+ )
2504
+ return true;
2505
+ bool line_colon = indicator_line(s, ':');
2506
+ if (line_colon && !s->line_prefixed && blank(l->lookahead))
2507
+ return begin_line_prefix(s, l, valid);
2508
+ bool completable = s->indent > outdent_boundary(s) ||
2509
+ (s->key_state == KEY_ENDED && !s->colon_line_only);
2510
+ s->key_state = KEY_NONE;
2511
+ if (
2512
+ l->lookahead == ':' && (!s->line || line_colon) && step_boundary(l, false)
2513
+ )
2514
+ return emit_indicator(s, l, valid, VALUE_INDICATOR);
2515
+ return emit(
2516
+ l,
2517
+ valid,
2518
+ completable &&
2519
+ (l->eof(l) || s->eof_continuation || (!s->line && s->boundary_pending))
2520
+ ? INCOMPLETE_VALUE_INDICATOR
2521
+ : MISSING_VALUE_INDICATOR
2522
+ );
2523
+ }
2524
+ static bool close_by_line(Scanner *s, TSLexer *l, const bool *valid) {
2525
+ if (s->line_indent < s->indent || s->line_indent <= outdent_boundary(s))
2526
+ return end_collection(s, l, valid);
2527
+ if (s->line_indent != s->indent) return false;
2528
+ static const enum Token in_shared[] = {
2529
+ MAPPING_IN_SHARED_END,
2530
+ SEQUENCE_IN_SHARED_END
2531
+ };
2532
+ static const enum Token in_sequence[] = {
2533
+ MAPPING_IN_SEQUENCE_END,
2534
+ SEQUENCE_IN_SEQUENCE_END
2535
+ };
2536
+ static const enum Token in_mapping[] = {
2537
+ MAPPING_IN_MAPPING_END,
2538
+ SEQUENCE_IN_MAPPING_END
2539
+ };
2540
+ if (emit_first(s, l, valid, in_shared, COUNT(in_shared))) return true;
2541
+ return s->line_head == '-'
2542
+ ? emit_first(s, l, valid, in_sequence, COUNT(in_sequence))
2543
+ : emit_first(s, l, valid, in_mapping, COUNT(in_mapping));
2544
+ }
2545
+ static bool
2546
+ emit_missing_document_start(Scanner *s, TSLexer *l, const bool *valid) {
2547
+ bool directives = s->directive_kind;
2548
+ s->document_started = true;
2549
+ s->explicit_document_required = false;
2550
+ s->directive_kind = 0;
2551
+ if (
2552
+ s->boundary_pending == DOCUMENT_START_LINE ||
2553
+ (s->boundary_pending == DOCUMENT_END_LINE && !directives)
2554
+ )
2555
+ return emit(l, valid, INCOMPLETE_DOCUMENT_START);
2556
+ return emit_missing(
2557
+ l,
2558
+ valid,
2559
+ MISSING_DOCUMENT_START,
2560
+ INCOMPLETE_DOCUMENT_START
2561
+ );
2562
+ }
2563
+ static bool key_end_valid(const bool *valid) {
2564
+ return valid[KEY_END] || valid[INVALID_KEY_END] || valid[FLOW_NODE_END];
2565
+ }
2566
+ static bool key_colon_pending(const Scanner *s, const bool *valid) {
2567
+ return s->key_state != KEY_NONE &&
2568
+ (valid[MISSING_VALUE_INDICATOR] || valid[INCOMPLETE_VALUE_INDICATOR]);
2569
+ }
2570
+ static bool
2571
+ scan_normal(Scanner *s, TSLexer *l, const bool *valid, bool property_pending) {
2572
+ if (!property_pending && key_end_valid(valid))
2573
+ return scan_key_end(s, l, valid);
2574
+ if (valid[EMPTY_BLOCK_NODE]) return start_block_value(s, l, valid);
2575
+ if (s->line && !s->line_context) return scan_line_context(s, l, valid);
2576
+ if (key_colon_pending(s, valid)) return scan_key_colon(s, l, valid);
2577
+ if (
2578
+ s->line_context &&
2579
+ !s->layout_only &&
2580
+ !property_line_follows(s, s->line, s->line_indent, s->line_head)
2581
+ ) {
2582
+ s->properties_ready = false;
2583
+ property_pending = false;
2584
+ }
2585
+ if (!property_pending && restore_indent(s, l, valid)) return true;
2586
+ if (
2587
+ !property_pending &&
2588
+ s->line &&
2589
+ s->line_context &&
2590
+ !s->layout_only &&
2591
+ !s->flow &&
2592
+ close_by_line(s, l, valid)
2593
+ )
2594
+ return true;
2595
+ if (scan_layout(s, l, valid)) return true;
2509
2596
  if (valid[DIRECTIVE_INDICATOR]) {
2510
2597
  s->mode = DIRECTIVE_NAME_BODY;
2511
2598
  s->first = true;
2512
2599
  return take(l, valid, DIRECTIVE_INDICATOR);
2513
2600
  }
2514
2601
  if (
2515
- l->lookahead ==
2516
- '%' &&
2517
- l->get_column(l) ==
2518
- 0 &&
2602
+ l->lookahead == '%' &&
2603
+ l->get_column(l) == 0 &&
2519
2604
  valid[RESERVED_DIRECTIVE_START]
2520
- ) {
2521
- char name[5] = {0};
2522
- unsigned length = 0;
2523
- step(l);
2524
- while (!directive_boundary(l)) {
2525
- if (length < 4 && l->lookahead < 128)
2526
- name[length] = (char)l->lookahead;
2527
- if (length < 5)
2528
- length++;
2529
- step(l);
2530
- }
2531
- s->directive_kind = length == 4 && !strcmp(name, "YAML") ? YAML_DIRECTIVE
2532
- : length == 3 && !strcmp(name, "TAG") ? TAG_DIRECTIVE
2533
- : RESERVED_DIRECTIVE;
2534
- return emit(
2535
- l,
2536
- valid,
2537
- s->directive_kind == YAML_DIRECTIVE ? YAML_DIRECTIVE_START
2538
- : s->directive_kind == TAG_DIRECTIVE ? TAG_DIRECTIVE_START
2539
- : RESERVED_DIRECTIVE_START
2540
- );
2541
- }
2605
+ )
2606
+ return start_directive(s, l, valid);
2542
2607
  if (
2543
2608
  !s->document_started &&
2544
2609
  (valid[MISSING_DOCUMENT_START] || valid[INCOMPLETE_DOCUMENT_START])
2545
- ) {
2546
- s->document_started = true;
2547
- s->explicit_document_required = false;
2548
- if (s->boundary_pending == DOCUMENT_START_LINE)
2549
- return emit(l, valid, INCOMPLETE_DOCUMENT_START);
2550
- return emit_missing(
2551
- l,
2552
- valid,
2553
- MISSING_DOCUMENT_START,
2554
- INCOMPLETE_DOCUMENT_START
2555
- );
2556
- }
2610
+ )
2611
+ return emit_missing_document_start(s, l, valid);
2557
2612
  return scan_properties(s, l, valid, property_pending);
2558
2613
  }
2559
2614
 
2560
2615
  static bool scan_property_tail(Scanner *s, TSLexer *l, const bool *valid) {
2561
- Scanner context = *s;
2562
- for (;;) {
2563
- if (context.line) {
2564
- context.line_indent = count_spaces(l);
2565
- }
2566
- skip_blanks(l);
2567
- if (l->lookahead == '#') {
2568
- while (!l->eof(l) && !newline(l->lookahead))
2569
- step(l);
2570
- }
2571
- if (!newline(l->lookahead))
2572
- break;
2573
- skip_line_break(l);
2574
- context.line = true;
2575
- }
2616
+ uint32_t line_indent = s->line_indent;
2617
+ bool line = skip_layout_lines(l, s->line, &line_indent);
2576
2618
  bool end = l->eof(l);
2577
- int32_t first = l->lookahead;
2578
- context.line_head = first;
2579
- bool boundary = false;
2580
- if (first == '-' && context.line && !s->flow) {
2581
- bool column_zero = l->get_column(l) == 0;
2582
- step(l);
2583
- if (!space(l->lookahead) && !l->eof(l))
2584
- context.line_head = 0;
2585
- if (column_zero)
2586
- boundary = document_marker_tail(l, first) != NO_BOUNDARY;
2587
- } else if (l->get_column(l) == 0) {
2588
- boundary = line_boundary(&context, l) != NO_BOUNDARY;
2589
- }
2619
+ s->eof_continuation |= end;
2620
+ int32_t line_head;
2621
+ bool boundary = line_head_boundary(s, l, line, &line_head);
2590
2622
  enum Token content_end =
2591
2623
  valid[BLOCK_PROPERTIES_END] ? BLOCK_PROPERTIES_END : PROPERTIES_END;
2592
2624
  enum Token token = content_end;
2593
2625
  if (
2594
2626
  boundary ||
2595
2627
  end ||
2596
- (s->flow && flow_entry_end(first)) ||
2597
- !property_line_follows(&context)
2628
+ (s->flow && flow_entry_end(line_head)) ||
2629
+ !property_line_follows(s, line, line_indent, line_head)
2598
2630
  ) {
2599
2631
  token = EMPTY_PROPERTIES_END;
2600
- } else if (first == ':') {
2601
- step(l);
2602
- if (colon_boundary(l, s->flow)) {
2603
- if (s->flow || !context.line || !valid[BLOCK_PROPERTIES_END])
2604
- token = EMPTY_PROPERTIES_END;
2605
- } else {
2606
- s->property_colon_content = true;
2607
- }
2608
- } else if (first == '&' || first == '!') {
2632
+ } else if (line_head == ':' && step_boundary(l, s->flow)) {
2633
+ if (s->flow || !line || !valid[BLOCK_PROPERTIES_END])
2634
+ token = EMPTY_PROPERTIES_END;
2635
+ s->eof_continuation = l->eof(l);
2636
+ } else if (line_head == '&' || line_head == '!') {
2609
2637
  token = PROPERTY_CONTINUE;
2610
- if (context.line && !s->flow) {
2611
- if (classify_block_node(l, NULL) == MAPPING_START)
2612
- token = content_end;
2638
+ if (line && !s->flow) {
2639
+ if (classify_block_node(l, NULL) == MAPPING_START) token = content_end;
2613
2640
  s->property_keys = l->eof(l) ? ANCHOR_KEY | TAG_KEY : 0;
2614
2641
  }
2615
2642
  }
@@ -2619,152 +2646,133 @@ static bool scan_property_tail(Scanner *s, TSLexer *l, const bool *valid) {
2619
2646
  }
2620
2647
 
2621
2648
  static bool scan(Scanner *s, TSLexer *l, const bool *valid) {
2622
- if (valid[ERROR_SENTINEL])
2623
- return false;
2649
+ if (valid[ERROR_SENTINEL]) return false;
2624
2650
  l->mark_end(l);
2625
2651
  if (s->mode == NORMAL && valid[EMPTY_PROPERTIES_END])
2626
2652
  return scan_property_tail(s, l, valid);
2627
- bool boundary_mode = s->mode ==
2628
- NORMAL ||
2629
- s->mode ==
2630
- PLAIN ||
2631
- s->mode ==
2632
- SINGLE ||
2633
- s->mode ==
2634
- DOUBLE ||
2653
+ bool boundary_mode = s->mode == NORMAL ||
2654
+ s->mode == PLAIN ||
2655
+ s->mode == SINGLE ||
2656
+ s->mode == DOUBLE ||
2635
2657
  s->mode == BLOCK_BODY;
2636
2658
  if (
2637
2659
  boundary_mode &&
2638
2660
  !s->boundary_checked &&
2639
- l->get_column(l) ==
2640
- 0 &&
2641
- valid[BOUNDARY_CHECK]
2642
- ) {
2643
- int32_t first = l->lookahead;
2644
- enum Boundary boundary = line_boundary(s, l);
2645
- if (boundary || first == '-' || first == '.') {
2646
- s->boundary = (uint8_t)boundary;
2647
- s->boundary_pending = l->eof(l)
2648
- ? first == '-' ? DOCUMENT_START_LINE : DOCUMENT_END_LINE
2649
- : NO_BOUNDARY;
2650
- s->boundary_checked = true;
2651
- return emit(l, valid, BOUNDARY_CHECK);
2652
- }
2653
- }
2654
- if (s->boundary)
2655
- s->properties_ready = false;
2661
+ l->get_column(l) == 0 &&
2662
+ check_boundary(s, l, valid)
2663
+ )
2664
+ return true;
2665
+ if (s->boundary) s->properties_ready = false;
2656
2666
  bool property_pending = s->properties_ready &&
2657
2667
  (valid[PROPERTY_CONTENT_START] || valid[BLOCK_PROPERTY_CONTENT_START]);
2658
- if (
2659
- s->mode ==
2660
- NORMAL &&
2661
- s->boundary ==
2662
- DOCUMENT_END_LINE &&
2663
- valid[MISSING_DOCUMENT_START]
2664
- ) {
2665
- s->document_started = true;
2666
- return emit(l, valid, MISSING_DOCUMENT_START);
2667
- }
2668
- if (s->mode == NORMAL && !property_pending && valid[DOCUMENT_CONTENT_END]) {
2669
- s->document_content = true;
2670
- return emit(l, valid, DOCUMENT_CONTENT_END);
2668
+ if (s->mode == NORMAL) {
2669
+ if (s->boundary == DOCUMENT_END_LINE && valid[MISSING_DOCUMENT_START]) {
2670
+ s->document_started = true;
2671
+ s->directive_kind = 0;
2672
+ return emit(l, valid, MISSING_DOCUMENT_START);
2673
+ }
2674
+ if (!property_pending && valid[DOCUMENT_CONTENT_END]) {
2675
+ s->document_content = true;
2676
+ return emit(l, valid, DOCUMENT_CONTENT_END);
2677
+ }
2678
+ if (!property_pending && valid[COLLECTION_CONTENT_END])
2679
+ return emit(l, valid, COLLECTION_CONTENT_END);
2671
2680
  }
2672
2681
  if (
2673
2682
  boundary_mode &&
2674
2683
  s->boundary &&
2675
- !(s->mode ==
2676
- NORMAL &&
2677
- (valid[KEY_END] ||
2678
- valid[INVALID_KEY_END] ||
2679
- valid[FLOW_NODE_END] ||
2680
- (s->key_done && valid[MISSING_VALUE_INDICATOR])))
2684
+ !(s->mode == NORMAL &&
2685
+ (key_end_valid(valid) || key_colon_pending(s, valid)))
2681
2686
  ) {
2682
- if (scan_boundary(s, l, valid))
2683
- return true;
2687
+ if (scan_boundary(s, l, valid)) return true;
2684
2688
  if (s->boundary != DIRECTIVE_LINE && s->boundary != STREAM_BOM)
2685
2689
  return false;
2686
2690
  }
2687
2691
  switch ((enum Mode)s->mode) {
2688
- case NORMAL:
2689
- break;
2690
- case PLAIN:
2691
- return scan_plain(s, l, valid);
2692
- case SINGLE:
2693
- case DOUBLE:
2694
- return scan_quote(s, l, valid);
2695
- case COMMENT_BEGIN:
2696
- case COMMENT:
2697
- return scan_comment(s, l, valid);
2698
- case COMPACT_PREFIX:
2699
- case PREFIX:
2700
- return scan_prefix(s, l, valid);
2701
- case BLOCK_HEADER:
2702
- case BLOCK_HEADER_DONE:
2703
- return scan_block_header(s, l, valid);
2704
- case BLOCK_DETECT:
2705
- return detect_block_indent(s, l, valid);
2706
- case BLOCK_BODY:
2707
- return scan_block_body(s, l, valid);
2708
- case BLOCK_LINE:
2709
- case BLOCK_LINE_DONE:
2710
- return scan_block_line(s, l, valid);
2711
- case ANCHOR_BODY:
2712
- case ALIAS_BODY:
2713
- return scan_name(s, l, valid);
2714
- case HANDLE_SELECT:
2715
- case HANDLE_BODY:
2716
- return scan_handle(s, l, valid);
2717
- case URI_BEGIN:
2718
- case VERBATIM_CLOSE:
2719
- case SUFFIX_BEGIN:
2720
- return scan_tag_boundary(s, l, valid);
2721
- case URI_BODY:
2722
- case SUFFIX_BODY:
2723
- case PREFIX_BODY:
2724
- return scan_uri(s, l, valid);
2725
- case DIRECTIVE_NAME_BODY:
2726
- case DIRECTIVE_VERSION:
2727
- case DIRECTIVE_HANDLE:
2728
- case DIRECTIVE_PREFIX:
2729
- case DIRECTIVE_PARAMETERS:
2730
- return scan_directive(s, l, valid);
2731
- default:
2732
- return false;
2692
+ case NORMAL:
2693
+ break;
2694
+ case PLAIN:
2695
+ return scan_plain(s, l, valid);
2696
+ case SINGLE:
2697
+ case DOUBLE:
2698
+ return scan_quote(s, l, valid);
2699
+ case COMMENT_BEGIN:
2700
+ case COMMENT:
2701
+ return scan_comment(s, l, valid);
2702
+ case COMPACT_PREFIX:
2703
+ case PREFIX:
2704
+ return scan_prefix(s, l, valid);
2705
+ case BLOCK_HEADER:
2706
+ case BLOCK_HEADER_DONE:
2707
+ return scan_block_header(s, l, valid);
2708
+ case BLOCK_DETECT:
2709
+ return detect_block_indent(s, l, valid);
2710
+ case BLOCK_BODY:
2711
+ return scan_block_body(s, l, valid);
2712
+ case BLOCK_LINE:
2713
+ case BLOCK_LINE_DONE:
2714
+ return scan_block_line(s, l, valid);
2715
+ case ANCHOR_BODY:
2716
+ case ALIAS_BODY:
2717
+ return scan_name(s, l, valid);
2718
+ case HANDLE_SELECT:
2719
+ case HANDLE_BODY:
2720
+ return scan_handle(s, l, valid);
2721
+ case URI_BEGIN:
2722
+ case VERBATIM_CLOSE:
2723
+ case SUFFIX_BEGIN:
2724
+ return scan_tag_boundary(s, l, valid);
2725
+ case URI_BODY:
2726
+ case SUFFIX_BODY:
2727
+ case PREFIX_BODY:
2728
+ return scan_uri(s, l, valid);
2729
+ case DIRECTIVE_NAME_BODY:
2730
+ case DIRECTIVE_VERSION:
2731
+ case DIRECTIVE_HANDLE:
2732
+ case DIRECTIVE_PREFIX:
2733
+ case DIRECTIVE_PARAMETERS:
2734
+ return scan_directive(s, l, valid);
2735
+ default:
2736
+ return false;
2733
2737
  }
2734
2738
  return scan_normal(s, l, valid, property_pending);
2735
2739
  }
2736
2740
 
2737
2741
  static bool layout_token(TSSymbol token) {
2738
2742
  switch (token) {
2739
- case LINE_BREAK:
2740
- case SEPARATION:
2741
- case COMMENT_START:
2742
- case COMMENT_MARKER:
2743
- case COMMENT_TEXT:
2744
- case COMMENT_END:
2745
- case LINE_PREFIX_START:
2746
- case LINE_PREFIX_END:
2747
- case INDENTATION:
2748
- case INVALID_INDENTATION:
2749
- case TAB_IN_INDENTATION:
2750
- case UNFINISHED_INVALID_INDENTATION:
2751
- case UNFINISHED_TAB_IN_INDENTATION:
2752
- case BYTE_ORDER_MARK:
2753
- case LINE_CONTEXT:
2754
- case BOUNDARY_CHECK:
2755
- return true;
2756
- default:
2757
- return false;
2743
+ case LINE_BREAK:
2744
+ case SEPARATION:
2745
+ case COMMENT_START:
2746
+ case COMMENT_MARKER:
2747
+ case COMMENT_TEXT:
2748
+ case COMMENT_END:
2749
+ case LINE_PREFIX_START:
2750
+ case LINE_PREFIX_END:
2751
+ case INDENTATION:
2752
+ case INVALID_INDENTATION:
2753
+ case TAB_IN_INDENTATION:
2754
+ case UNFINISHED_INVALID_INDENTATION:
2755
+ case UNFINISHED_TAB_IN_INDENTATION:
2756
+ case BYTE_ORDER_MARK:
2757
+ case LINE_CONTEXT:
2758
+ case BOUNDARY_CHECK:
2759
+ return true;
2760
+ default:
2761
+ return false;
2758
2762
  }
2759
2763
  }
2764
+ /* Origins past outdent_count may be uninitialized. */
2765
+ static size_t state_size(const Scanner *s) {
2766
+ return offsetof(Scanner, outdent_origins) +
2767
+ s->outdent_count * sizeof(*s->outdent_origins);
2768
+ }
2760
2769
  static void reset_scanner(Scanner *s) {
2761
- *s = (Scanner){
2762
- .indent = -1,
2763
- .provisional_indent = -2,
2764
- .block_indent = -1,
2765
- .line = true,
2766
- .separated = true
2767
- };
2770
+ memset(s, 0, offsetof(Scanner, outdent_origins));
2771
+ s->indent = -1;
2772
+ s->provisional_indent = -2;
2773
+ s->block_indent = -1;
2774
+ s->line = true;
2775
+ s->separated = true;
2768
2776
  }
2769
2777
  static void write_integer(char **cursor, uint64_t value, unsigned width) {
2770
2778
  for (unsigned i = 0; i < width; i++) {
@@ -2781,7 +2789,7 @@ static uint64_t read_integer(const char **cursor, unsigned width) {
2781
2789
 
2782
2790
  void *tree_sitter_yaml_external_scanner_create(void) {
2783
2791
  Scanner *s = ts_calloc(1, sizeof(Scanner));
2784
- reset_scanner(s);
2792
+ if (s) reset_scanner(s);
2785
2793
  return s;
2786
2794
  }
2787
2795
  void tree_sitter_yaml_external_scanner_destroy(void *payload) {
@@ -2789,13 +2797,19 @@ void tree_sitter_yaml_external_scanner_destroy(void *payload) {
2789
2797
  }
2790
2798
  unsigned
2791
2799
  tree_sitter_yaml_external_scanner_serialize(void *payload, char *buffer) {
2800
+ if (!payload) return 0;
2792
2801
  const Scanner *s = payload;
2793
2802
  char *cursor = buffer;
2794
2803
  #define WRITE_FIELD(type, name, width, bias) \
2795
2804
  write_integer(&cursor, (uint64_t)(s->name + bias), width);
2796
2805
  SCANNER_FIELDS(WRITE_FIELD)
2797
2806
  #undef WRITE_FIELD
2798
- unsigned key_bytes = SCANNER_KEY_BYTES;
2807
+ for (unsigned i = 0; i < s->outdent_count; i++)
2808
+ write_integer(&cursor, s->outdent_origins[i], 4);
2809
+ unsigned words = IMPLICIT_KEY_WORDS;
2810
+ while (words && !s->implicit_keys[words - 1]) words--;
2811
+ unsigned key_bytes =
2812
+ words * 8 < SCANNER_KEY_BYTES ? words * 8 : SCANNER_KEY_BYTES;
2799
2813
  while (
2800
2814
  key_bytes &&
2801
2815
  !(uint8_t)(s->implicit_keys[(key_bytes - 1) / 8] >>
@@ -2811,14 +2825,12 @@ void tree_sitter_yaml_external_scanner_deserialize(
2811
2825
  const char *buffer,
2812
2826
  unsigned length
2813
2827
  ) {
2828
+ if (!payload) return;
2814
2829
  Scanner *s = payload;
2815
2830
  reset_scanner(s);
2816
2831
  if (
2817
- length <
2818
- SCANNER_STATE_BYTES ||
2819
- length >
2820
- SCANNER_STATE_BYTES +
2821
- SCANNER_KEY_BYTES
2832
+ length < SCANNER_STATE_BYTES ||
2833
+ length > TREE_SITTER_SERIALIZATION_BUFFER_SIZE
2822
2834
  )
2823
2835
  return;
2824
2836
  const char *cursor = buffer;
@@ -2826,7 +2838,18 @@ void tree_sitter_yaml_external_scanner_deserialize(
2826
2838
  s->name = (type)read_integer(&cursor, width) - bias;
2827
2839
  SCANNER_FIELDS(READ_FIELD)
2828
2840
  #undef READ_FIELD
2829
- for (unsigned i = 0; i < length - SCANNER_STATE_BYTES; i++)
2841
+ unsigned state_bytes = SCANNER_STATE_BYTES + s->outdent_count * 4;
2842
+ if (
2843
+ s->outdent_count > OUTDENT_LIMIT ||
2844
+ length < state_bytes ||
2845
+ length > state_bytes + SCANNER_KEY_BYTES
2846
+ ) {
2847
+ reset_scanner(s);
2848
+ return;
2849
+ }
2850
+ for (unsigned i = 0; i < s->outdent_count; i++)
2851
+ s->outdent_origins[i] = (uint32_t)read_integer(&cursor, 4);
2852
+ for (unsigned i = 0; i < length - state_bytes; i++)
2830
2853
  s->implicit_keys[i / 8] |= (uint64_t)(uint8_t)*cursor++ << ((i % 8) * 8);
2831
2854
  }
2832
2855
  #undef SCANNER_FIELDS
@@ -2836,23 +2859,26 @@ bool tree_sitter_yaml_external_scanner_scan(
2836
2859
  TSLexer *lexer,
2837
2860
  const bool *valid
2838
2861
  ) {
2839
- Scanner next = *(Scanner *)payload;
2840
- Cursor cursor = {0};
2841
- cursor.source = lexer;
2842
- cursor.column = next.column;
2843
- cursor.marked_column = next.column;
2844
- cursor.separated = next.separated;
2845
- cursor.marked_separation = next.separated;
2846
- cursor.lexer.lookahead = lexer->lookahead;
2847
- cursor.lexer.advance = cursor_advance;
2848
- cursor.lexer.mark_end = cursor_mark;
2849
- cursor.lexer.get_column = cursor_column;
2850
- cursor.lexer.eof = cursor_eof;
2851
- if (!scan(&next, &cursor.lexer, valid))
2862
+ if (!payload) return false;
2863
+ Scanner next;
2864
+ memcpy(&next, payload, state_size(payload));
2865
+ Cursor cursor = {
2866
+ .lexer =
2867
+ {.lookahead = lexer->lookahead,
2868
+ .advance = cursor_advance,
2869
+ .mark_end = cursor_mark,
2870
+ .get_column = cursor_column,
2871
+ .eof = cursor_eof},
2872
+ .source = lexer,
2873
+ .column = next.column,
2874
+ .marked_column = next.column,
2875
+ .separated = next.separated,
2876
+ .marked_separation = next.separated
2877
+ };
2878
+ if (!scan(&next, &cursor.lexer, valid) || cursor.allocation_failed)
2852
2879
  return false;
2853
- /* Edits inside the final lookahead codepoint must invalidate this token. */
2854
- if (!cursor.lexer.eof(&cursor.lexer))
2855
- step(&cursor.lexer);
2880
+ /* Include the final lookahead codepoint in edit invalidation. */
2881
+ if (!cursor.lexer.eof(&cursor.lexer)) step(&cursor.lexer);
2856
2882
  if (next.flow && !layout_token(cursor.lexer.result_symbol))
2857
2883
  skip_layout(&cursor.lexer);
2858
2884
  next.column = cursor.marked_column;
@@ -2863,10 +2889,12 @@ bool tree_sitter_yaml_external_scanner_scan(
2863
2889
  next.boundary = 0;
2864
2890
  next.boundary_checked = false;
2865
2891
  next.boundary_pending = 0;
2866
- if (!layout_token(cursor.lexer.result_symbol))
2892
+ if (!layout_token(cursor.lexer.result_symbol)) {
2867
2893
  next.line = false;
2894
+ next.layout_only = false;
2895
+ }
2868
2896
  }
2869
2897
  lexer->result_symbol = cursor.lexer.result_symbol;
2870
- *(Scanner *)payload = next;
2898
+ memcpy(payload, &next, state_size(&next));
2871
2899
  return true;
2872
2900
  }