@konomanoasa/tree-sitter-yaml 0.1.0 → 0.3.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/Cargo.toml +1 -1
- package/README.md +6 -8
- package/grammar.js +229 -162
- package/package.json +6 -5
- package/src/grammar.json +2917 -715
- package/src/node-types.json +105 -45
- package/src/parser.c +158375 -65635
- package/src/scanner.c +716 -499
- package/tree-sitter.json +1 -1
package/src/scanner.c
CHANGED
|
@@ -38,6 +38,7 @@ enum Token {
|
|
|
38
38
|
IMPLICIT_KEY_START,
|
|
39
39
|
KEY_END,
|
|
40
40
|
INVALID_KEY_END,
|
|
41
|
+
UNFINISHED_INVALID_KEY_END,
|
|
41
42
|
FLOW_NODE_END,
|
|
42
43
|
PLAIN_START,
|
|
43
44
|
PLAIN_END,
|
|
@@ -86,6 +87,9 @@ enum Token {
|
|
|
86
87
|
UNEXPECTED_CONTENT_START,
|
|
87
88
|
PROPERTIES_START,
|
|
88
89
|
PROPERTIES_END,
|
|
90
|
+
BLOCK_PROPERTIES_END,
|
|
91
|
+
EMPTY_PROPERTIES_END,
|
|
92
|
+
PROPERTY_CONTINUE,
|
|
89
93
|
PROPERTY_CONTENT_START,
|
|
90
94
|
BLOCK_PROPERTY_CONTENT_START,
|
|
91
95
|
BLOCK_KEY_CONTENT_START,
|
|
@@ -128,20 +132,30 @@ enum Token {
|
|
|
128
132
|
TAG_PREFIX_START,
|
|
129
133
|
TAG_PREFIX_END,
|
|
130
134
|
DIRECTIVE_PARAMETER,
|
|
135
|
+
UNFINISHED_UNEXPECTED_DOCUMENT_CONTENT_START,
|
|
136
|
+
UNFINISHED_INVALID_DOCUMENT_COLLECTION_START,
|
|
137
|
+
UNFINISHED_DUPLICATE_ANCHOR_START,
|
|
138
|
+
UNFINISHED_DUPLICATE_TAG_START,
|
|
139
|
+
UNFINISHED_PROPERTIES_ON_ALIAS_START,
|
|
140
|
+
UNFINISHED_INVALID_PROPERTY_COLLECTION_START,
|
|
141
|
+
UNFINISHED_INVALID_COMPACT_COLLECTION_START,
|
|
131
142
|
INVALID_ENCODING,
|
|
132
143
|
INVALID_CHARACTER,
|
|
133
144
|
INVALID_ESCAPE,
|
|
134
145
|
INCOMPLETE_ESCAPE,
|
|
135
146
|
INVALID_LINE_CONTINUATION,
|
|
136
147
|
INVALID_SCALAR_START,
|
|
148
|
+
INCOMPLETE_SCALAR_START,
|
|
137
149
|
MISSING_FLOW_SEPARATOR,
|
|
138
150
|
UNEXPECTED_FLOW_SEPARATOR,
|
|
139
151
|
INVALID_INDENTATION,
|
|
152
|
+
TAB_IN_INDENTATION,
|
|
140
153
|
MISSING_INDENTATION,
|
|
141
154
|
MISSING_SEPARATION,
|
|
142
155
|
INVALID_BLOCK_HEADER,
|
|
143
156
|
INVALID_TAG_HANDLE,
|
|
144
157
|
INVALID_TAG_CHARACTER,
|
|
158
|
+
INVALID_TAG_PREFIX_START,
|
|
145
159
|
INVALID_URI_ESCAPE,
|
|
146
160
|
INCOMPLETE_URI_ESCAPE,
|
|
147
161
|
INVALID_YAML_VERSION,
|
|
@@ -181,6 +195,11 @@ enum Token {
|
|
|
181
195
|
INCOMPLETE_TAG_PREFIX,
|
|
182
196
|
MISSING_DOCUMENT_START,
|
|
183
197
|
INCOMPLETE_DOCUMENT_START,
|
|
198
|
+
UNFINISHED_INVALID_INDENTATION,
|
|
199
|
+
UNFINISHED_TAB_IN_INDENTATION,
|
|
200
|
+
UNFINISHED_MISSING_INDENTATION,
|
|
201
|
+
UNFINISHED_MISSING_FLOW_SEPARATOR,
|
|
202
|
+
UNDECODABLE_ESCAPE_PREFIX,
|
|
184
203
|
ERROR_SENTINEL
|
|
185
204
|
};
|
|
186
205
|
|
|
@@ -215,19 +234,10 @@ enum Mode {
|
|
|
215
234
|
DIRECTIVE_PREFIX,
|
|
216
235
|
DIRECTIVE_PARAMETERS
|
|
217
236
|
};
|
|
218
|
-
enum HeaderFlag {
|
|
219
|
-
HEADER_INDENTATION = 1,
|
|
220
|
-
HEADER_CHOMPING = 2,
|
|
221
|
-
HEADER_SEPARATION = 4
|
|
222
|
-
};
|
|
223
|
-
enum PropertyFlag {
|
|
224
|
-
PROPERTY_ANCHOR = 1,
|
|
225
|
-
PROPERTY_TAG = 2,
|
|
226
|
-
PROPERTY_COLON_CONTENT = 4
|
|
227
|
-
};
|
|
228
237
|
enum HandleForm { PRIMARY_HANDLE = 1, SECONDARY_HANDLE, NAMED_HANDLE };
|
|
238
|
+
/* Appending ":" can move these continued properties into an implicit key. */
|
|
239
|
+
enum PropertyKey { ANCHOR_KEY = 1, TAG_KEY = 2 };
|
|
229
240
|
enum DirectiveKind { YAML_DIRECTIVE = 1, TAG_DIRECTIVE, RESERVED_DIRECTIVE };
|
|
230
|
-
/* Line starts that end the open constructs of a document. */
|
|
231
241
|
enum Boundary {
|
|
232
242
|
NO_BOUNDARY,
|
|
233
243
|
DOCUMENT_START_LINE,
|
|
@@ -261,28 +271,35 @@ enum Boundary {
|
|
|
261
271
|
F(bool, separated, 1, 0) \
|
|
262
272
|
F(bool, key_done, 1, 0) \
|
|
263
273
|
F(int64_t, block_indent, 8, 1) \
|
|
264
|
-
F(
|
|
274
|
+
F(bool, block_explicit_indent, 1, 0) \
|
|
275
|
+
F(bool, header_separated, 1, 0) \
|
|
265
276
|
F(uint8_t, return_mode, 1, 0) \
|
|
266
277
|
F(bool, block_leading, 1, 0) \
|
|
267
278
|
F(bool, block_empty, 1, 0) \
|
|
268
279
|
F(bool, block_prefix, 1, 0) \
|
|
280
|
+
F(uint32_t, block_layout_lines, 4, 0) \
|
|
269
281
|
F(uint8_t, boundary, 1, 0) \
|
|
270
282
|
F(bool, boundary_checked, 1, 0) \
|
|
283
|
+
F(uint8_t, boundary_pending, 1, 0) \
|
|
271
284
|
F(bool, document_started, 1, 0) \
|
|
272
285
|
F(bool, document_content, 1, 0) \
|
|
273
286
|
F(bool, after_document_end, 1, 0) \
|
|
274
287
|
F(bool, block_out, 1, 0) \
|
|
275
|
-
F(
|
|
288
|
+
F(bool, property_colon_content, 1, 0) \
|
|
276
289
|
F(uint8_t, handle_form, 1, 0) \
|
|
277
290
|
F(bool, properties_ready, 1, 0) \
|
|
278
|
-
F(bool, duplicate_pending, 1, 0) \
|
|
279
291
|
F(bool, property_separation_notified, 1, 0) \
|
|
292
|
+
F(uint8_t, property_keys, 1, 0) \
|
|
280
293
|
F(uint8_t, directive_kind, 1, 0) \
|
|
281
294
|
F(bool, directive_handle, 1, 0) \
|
|
282
295
|
F(bool, value_separation, 1, 0) \
|
|
283
296
|
F(uint32_t, scalar_spaces, 4, 0) \
|
|
284
297
|
F(bool, scalar_tab, 1, 0) \
|
|
285
298
|
F(bool, explicit_document_required, 1, 0) \
|
|
299
|
+
F(bool, eof_continuation, 1, 0) \
|
|
300
|
+
F(bool, block_eof, 1, 0) \
|
|
301
|
+
F(bool, prefix_eof, 1, 0) \
|
|
302
|
+
F(int64_t, provisional_indent, 8, 2) \
|
|
286
303
|
F(uint8_t, block_kind, 1, 0)
|
|
287
304
|
|
|
288
305
|
#define FIELD_BYTES(type, name, width, bias) +width
|
|
@@ -464,8 +481,7 @@ close_flow(Scanner *s, TSLexer *l, const bool *valid, enum Token token) {
|
|
|
464
481
|
if (closed) {
|
|
465
482
|
s->flow--;
|
|
466
483
|
s->json = true;
|
|
467
|
-
/*
|
|
468
|
-
* source, so the rest of the line is content rather than layout. */
|
|
484
|
+
/* Missing closers must also mark the rest of this line as content. */
|
|
469
485
|
s->line = false;
|
|
470
486
|
}
|
|
471
487
|
return closed;
|
|
@@ -490,6 +506,8 @@ static bool emit_closing(
|
|
|
490
506
|
case DEDENT:
|
|
491
507
|
case OUTDENT:
|
|
492
508
|
s->indent--;
|
|
509
|
+
if (s->indent <= s->provisional_indent)
|
|
510
|
+
s->provisional_indent = -2;
|
|
493
511
|
break;
|
|
494
512
|
case RESTORE_INDENT:
|
|
495
513
|
case INDENT:
|
|
@@ -505,23 +523,32 @@ static bool emit_closing(
|
|
|
505
523
|
static bool start_plain(Scanner *s, TSLexer *l, const bool *valid) {
|
|
506
524
|
if (!valid[PLAIN_START])
|
|
507
525
|
return false;
|
|
526
|
+
s->eof_continuation = false;
|
|
508
527
|
s->mode = PLAIN;
|
|
509
528
|
s->first = true;
|
|
510
529
|
s->json = false;
|
|
511
530
|
return emit(l, valid, PLAIN_START);
|
|
512
531
|
}
|
|
513
|
-
static bool scan_invalid_character(TSLexer *l, const bool *valid) {
|
|
514
|
-
|
|
532
|
+
static bool scan_invalid_character(TSLexer *l, const bool *valid, bool quoted) {
|
|
533
|
+
bool (*invalid)(int32_t) = quoted ? invalid_quoted : invalid_unquoted;
|
|
534
|
+
if (l->eof(l) || !invalid(l->lookahead))
|
|
515
535
|
return false;
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
536
|
+
bool undecodable = invalid_encoding(l->lookahead);
|
|
537
|
+
enum Token token = undecodable ? INVALID_ENCODING : INVALID_CHARACTER;
|
|
538
|
+
if (!valid[token])
|
|
539
|
+
return false;
|
|
540
|
+
do {
|
|
541
|
+
step(l);
|
|
542
|
+
} while (
|
|
543
|
+
!l->eof(l) &&
|
|
544
|
+
invalid(l->lookahead) &&
|
|
545
|
+
invalid_encoding(l->lookahead) == undecodable
|
|
520
546
|
);
|
|
547
|
+
return finish(l, valid, token);
|
|
521
548
|
}
|
|
522
549
|
|
|
523
550
|
static bool scan_line_text(TSLexer *l, const bool *valid, enum Token token) {
|
|
524
|
-
if (scan_invalid_character(l, valid))
|
|
551
|
+
if (scan_invalid_character(l, valid, false))
|
|
525
552
|
return true;
|
|
526
553
|
do {
|
|
527
554
|
step(l);
|
|
@@ -531,11 +558,8 @@ static bool scan_line_text(TSLexer *l, const bool *valid, enum Token token) {
|
|
|
531
558
|
return finish(l, valid, token);
|
|
532
559
|
}
|
|
533
560
|
|
|
534
|
-
static enum Boundary
|
|
535
|
-
|
|
536
|
-
return NO_BOUNDARY;
|
|
537
|
-
int32_t marker = l->lookahead;
|
|
538
|
-
for (unsigned i = 0; i < 3; i++) {
|
|
561
|
+
static enum Boundary document_marker_tail(TSLexer *l, int32_t marker) {
|
|
562
|
+
for (unsigned i = 0; i < 2; i++) {
|
|
539
563
|
if (l->lookahead != marker)
|
|
540
564
|
return NO_BOUNDARY;
|
|
541
565
|
step(l);
|
|
@@ -544,8 +568,13 @@ static enum Boundary document_marker(TSLexer *l) {
|
|
|
544
568
|
return NO_BOUNDARY;
|
|
545
569
|
return marker == '-' ? DOCUMENT_START_LINE : DOCUMENT_END_LINE;
|
|
546
570
|
}
|
|
547
|
-
|
|
548
|
-
|
|
571
|
+
static enum Boundary document_marker(TSLexer *l) {
|
|
572
|
+
if (l->get_column(l) != 0 || (l->lookahead != '-' && l->lookahead != '.'))
|
|
573
|
+
return NO_BOUNDARY;
|
|
574
|
+
int32_t marker = l->lookahead;
|
|
575
|
+
step(l);
|
|
576
|
+
return document_marker_tail(l, marker);
|
|
577
|
+
}
|
|
549
578
|
static enum Boundary line_boundary(const Scanner *s, TSLexer *l) {
|
|
550
579
|
if (l->lookahead == '-' || l->lookahead == '.')
|
|
551
580
|
return document_marker(l);
|
|
@@ -582,7 +611,6 @@ static bool block_collection(enum Token kind) {
|
|
|
582
611
|
return kind == MAPPING_START || kind == SEQUENCE_START;
|
|
583
612
|
}
|
|
584
613
|
|
|
585
|
-
/* Only starts within the same line's last 1024 characters can remain valid. */
|
|
586
614
|
static void advance_keys(Scanner *s, uint64_t characters, bool broken) {
|
|
587
615
|
if (broken || characters > IMPLICIT_KEY_LIMIT) {
|
|
588
616
|
memset(s->implicit_keys, 0, sizeof(s->implicit_keys));
|
|
@@ -614,11 +642,7 @@ static unsigned end_key(Scanner *s) {
|
|
|
614
642
|
return IMPLICIT_KEY_LIMIT + 1;
|
|
615
643
|
}
|
|
616
644
|
|
|
617
|
-
/*
|
|
618
|
-
* at the token that follows the layout after it. Reading that layout keeps an
|
|
619
|
-
* edit inside it from leaving a reused node's reduction unrevised. The key
|
|
620
|
-
* lookahead reads the same layout because the colon may follow comment lines.
|
|
621
|
-
*/
|
|
645
|
+
/* Layout edits must invalidate preceding node reductions. */
|
|
622
646
|
static void skip_layout(TSLexer *l) {
|
|
623
647
|
for (;;) {
|
|
624
648
|
while (space(l->lookahead))
|
|
@@ -647,6 +671,11 @@ static bool scan_key_end(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
647
671
|
return emit(l, valid, FLOW_NODE_END);
|
|
648
672
|
}
|
|
649
673
|
s->key_done = true;
|
|
674
|
+
if (key_invalid && !s->flow && l->lookahead == ':') {
|
|
675
|
+
step(l);
|
|
676
|
+
if (l->eof(l))
|
|
677
|
+
return emit(l, valid, UNFINISHED_INVALID_KEY_END);
|
|
678
|
+
}
|
|
650
679
|
return emit(l, valid, key_invalid ? INVALID_KEY_END : KEY_END);
|
|
651
680
|
}
|
|
652
681
|
|
|
@@ -665,10 +694,14 @@ static void skip_property_or_alias(TSLexer *l) {
|
|
|
665
694
|
}
|
|
666
695
|
}
|
|
667
696
|
|
|
668
|
-
static enum Token classify_block_node(TSLexer *l) {
|
|
697
|
+
static enum Token classify_block_node(TSLexer *l, bool *unfinished) {
|
|
698
|
+
if (unfinished)
|
|
699
|
+
*unfinished = false;
|
|
669
700
|
bool properties = l->lookahead == '&' || l->lookahead == '!';
|
|
701
|
+
bool attached = false;
|
|
670
702
|
while (l->lookahead == '&' || l->lookahead == '!') {
|
|
671
703
|
skip_property_or_alias(l);
|
|
704
|
+
attached = !blank(l->lookahead);
|
|
672
705
|
skip_blanks(l);
|
|
673
706
|
if (l->eof(l) || newline(l->lookahead) || l->lookahead == '#')
|
|
674
707
|
return PROPERTIES_START;
|
|
@@ -692,10 +725,13 @@ static enum Token classify_block_node(TSLexer *l) {
|
|
|
692
725
|
}
|
|
693
726
|
if (first == '-' || first == '?') {
|
|
694
727
|
step(l);
|
|
695
|
-
if (space(l->lookahead) || l->eof(l))
|
|
728
|
+
if (space(l->lookahead) || l->eof(l)) {
|
|
729
|
+
if (unfinished)
|
|
730
|
+
*unfinished = l->eof(l);
|
|
696
731
|
return properties ? PROPERTIES_START
|
|
697
732
|
: first == '-' ? SEQUENCE_START
|
|
698
733
|
: MAPPING_START;
|
|
734
|
+
}
|
|
699
735
|
}
|
|
700
736
|
int32_t quote = 0;
|
|
701
737
|
char initial_closings[32];
|
|
@@ -704,7 +740,7 @@ static enum Token classify_block_node(TSLexer *l) {
|
|
|
704
740
|
bool separated = false;
|
|
705
741
|
bool complete = content == ALIAS_START;
|
|
706
742
|
bool plain = content == PLAIN_START;
|
|
707
|
-
bool adjacent =
|
|
743
|
+
bool adjacent = attached;
|
|
708
744
|
while (!l->eof(l)) {
|
|
709
745
|
if (
|
|
710
746
|
l->get_column(l) ==
|
|
@@ -788,6 +824,8 @@ static enum Token classify_block_node(TSLexer *l) {
|
|
|
788
824
|
bool indicator = colon_boundary(l, flow);
|
|
789
825
|
if (!flow && indicator) {
|
|
790
826
|
fallback = MAPPING_START;
|
|
827
|
+
if (unfinished)
|
|
828
|
+
*unfinished = l->eof(l);
|
|
791
829
|
break;
|
|
792
830
|
}
|
|
793
831
|
if (!flow && complete)
|
|
@@ -816,14 +854,21 @@ static enum Token classify_block_node(TSLexer *l) {
|
|
|
816
854
|
|
|
817
855
|
static enum Token classify_block_start(Scanner *s, TSLexer *l) {
|
|
818
856
|
if (!s->block_kind)
|
|
819
|
-
s->block_kind = (uint8_t)(classify_block_node(l) + 1);
|
|
857
|
+
s->block_kind = (uint8_t)(classify_block_node(l, &s->block_eof) + 1);
|
|
820
858
|
return (enum Token)(s->block_kind - 1);
|
|
821
859
|
}
|
|
822
860
|
|
|
823
861
|
static enum Token
|
|
824
862
|
property_content_start(Scanner *s, TSLexer *l, const bool *valid) {
|
|
825
|
-
if (l->lookahead == '*' && !(s->line && s->line_mapping_key))
|
|
863
|
+
if (l->lookahead == '*' && !(s->line && s->line_mapping_key)) {
|
|
864
|
+
if (s->line && !s->flow) {
|
|
865
|
+
skip_property_or_alias(l);
|
|
866
|
+
skip_blanks(l);
|
|
867
|
+
if (l->eof(l))
|
|
868
|
+
return UNFINISHED_PROPERTIES_ON_ALIAS_START;
|
|
869
|
+
}
|
|
826
870
|
return PROPERTY_ALIAS_START;
|
|
871
|
+
}
|
|
827
872
|
if (!s->flow) {
|
|
828
873
|
enum Token kind = classify_block_start(s, l);
|
|
829
874
|
if (
|
|
@@ -839,7 +884,8 @@ property_content_start(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
839
884
|
SEQUENCE_START ||
|
|
840
885
|
(kind == MAPPING_START && valid[BLOCK_PROPERTY_CONTENT_START]))
|
|
841
886
|
)
|
|
842
|
-
return
|
|
887
|
+
return s->block_eof ? UNFINISHED_INVALID_PROPERTY_COLLECTION_START
|
|
888
|
+
: PROPERTY_COMPACT_START;
|
|
843
889
|
}
|
|
844
890
|
return valid[BLOCK_PROPERTY_CONTENT_START] ? BLOCK_PROPERTY_CONTENT_START
|
|
845
891
|
: PROPERTY_CONTENT_START;
|
|
@@ -851,9 +897,12 @@ emit_indicator(Scanner *s, TSLexer *l, const bool *valid, enum Token token) {
|
|
|
851
897
|
if (!s->flow && blank(l->lookahead)) {
|
|
852
898
|
skip_blanks(l);
|
|
853
899
|
if (!l->eof(l) && !newline(l->lookahead) && l->lookahead != '#') {
|
|
854
|
-
|
|
855
|
-
|
|
900
|
+
bool unfinished;
|
|
901
|
+
enum Token kind = classify_block_node(l, &unfinished);
|
|
902
|
+
if (block_collection(kind)) {
|
|
903
|
+
s->prefix_eof = unfinished;
|
|
856
904
|
s->mode = COMPACT_PREFIX;
|
|
905
|
+
}
|
|
857
906
|
}
|
|
858
907
|
}
|
|
859
908
|
return emit(l, valid, token);
|
|
@@ -907,10 +956,6 @@ static bool uri_char(int32_t c, bool suffix) {
|
|
|
907
956
|
strchr("#;/?:@&=+$,_.!~*'()[]", (int)c) &&
|
|
908
957
|
(!suffix || (c != '!' && !flow_indicator(c))));
|
|
909
958
|
}
|
|
910
|
-
static void finish_tag(Scanner *s) {
|
|
911
|
-
s->mode = NORMAL;
|
|
912
|
-
s->property_flags |= PROPERTY_TAG;
|
|
913
|
-
}
|
|
914
959
|
static bool scan_name(Scanner *s, TSLexer *l, const bool *valid) {
|
|
915
960
|
bool anchor = s->mode == ANCHOR_BODY;
|
|
916
961
|
if (name_boundary(l)) {
|
|
@@ -921,12 +966,10 @@ static bool scan_name(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
921
966
|
: emit_missing(l, valid, MISSING_ALIAS_NAME, INCOMPLETE_ALIAS_NAME);
|
|
922
967
|
}
|
|
923
968
|
s->mode = NORMAL;
|
|
924
|
-
if (anchor)
|
|
925
|
-
s->property_flags |= PROPERTY_ANCHOR;
|
|
926
969
|
return emit(l, valid, NAME_END);
|
|
927
970
|
}
|
|
928
971
|
s->first = false;
|
|
929
|
-
if (scan_invalid_character(l, valid))
|
|
972
|
+
if (scan_invalid_character(l, valid, false))
|
|
930
973
|
return true;
|
|
931
974
|
do {
|
|
932
975
|
step(l);
|
|
@@ -934,7 +977,6 @@ static bool scan_name(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
934
977
|
return finish(l, valid, anchor ? ANCHOR_NAME : ALIAS_NAME);
|
|
935
978
|
}
|
|
936
979
|
|
|
937
|
-
/* The starting lookahead has already selected the tag handle form. */
|
|
938
980
|
static bool scan_handle(Scanner *s, TSLexer *l, const bool *valid) {
|
|
939
981
|
if (s->mode == HANDLE_SELECT) {
|
|
940
982
|
step(l);
|
|
@@ -962,17 +1004,27 @@ static bool scan_handle(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
962
1004
|
s->mode = s->directive_handle ? DIRECTIVE_PREFIX : SUFFIX_BEGIN;
|
|
963
1005
|
return take(l, valid, TAG_HANDLE_CLOSE);
|
|
964
1006
|
}
|
|
965
|
-
if (scan_invalid_character(l, valid))
|
|
1007
|
+
if (scan_invalid_character(l, valid, false))
|
|
966
1008
|
return true;
|
|
967
|
-
if (!word_char(l->lookahead))
|
|
968
|
-
|
|
1009
|
+
if (!word_char(l->lookahead)) {
|
|
1010
|
+
do {
|
|
1011
|
+
step(l);
|
|
1012
|
+
} while (
|
|
1013
|
+
!l->eof(l) &&
|
|
1014
|
+
!space(l->lookahead) &&
|
|
1015
|
+
l->lookahead !=
|
|
1016
|
+
'!' &&
|
|
1017
|
+
!invalid_unquoted(l->lookahead) &&
|
|
1018
|
+
!word_char(l->lookahead)
|
|
1019
|
+
);
|
|
1020
|
+
return finish(l, valid, INVALID_TAG_HANDLE);
|
|
1021
|
+
}
|
|
969
1022
|
do {
|
|
970
1023
|
step(l);
|
|
971
1024
|
} while (word_char(l->lookahead));
|
|
972
1025
|
return finish(l, valid, TAG_HANDLE_NAME);
|
|
973
1026
|
}
|
|
974
1027
|
|
|
975
|
-
/* The zero-width boundaries around a verbatim URI or a tag suffix. */
|
|
976
1028
|
static bool scan_tag_boundary(Scanner *s, TSLexer *l, const bool *valid) {
|
|
977
1029
|
if (s->mode == URI_BEGIN) {
|
|
978
1030
|
s->mode = URI_BODY;
|
|
@@ -983,7 +1035,7 @@ static bool scan_tag_boundary(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
983
1035
|
return emit(l, valid, TAG_URI_START);
|
|
984
1036
|
}
|
|
985
1037
|
if (s->mode == VERBATIM_CLOSE) {
|
|
986
|
-
|
|
1038
|
+
s->mode = NORMAL;
|
|
987
1039
|
if (l->lookahead == '>')
|
|
988
1040
|
return take(l, valid, VERBATIM_TAG_CLOSE);
|
|
989
1041
|
return emit_missing(
|
|
@@ -999,37 +1051,41 @@ static bool scan_tag_boundary(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
999
1051
|
return emit(l, valid, TAG_SUFFIX_START);
|
|
1000
1052
|
}
|
|
1001
1053
|
|
|
1054
|
+
static bool uri_boundary(TSLexer *l, bool prefix, bool suffix) {
|
|
1055
|
+
return l->eof(l) ||
|
|
1056
|
+
space(l->lookahead) ||
|
|
1057
|
+
(suffix ? flow_indicator(l->lookahead) : !prefix && l->lookahead == '>');
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1002
1060
|
static bool scan_uri(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1003
1061
|
bool prefix = s->mode == PREFIX_BODY;
|
|
1004
1062
|
bool suffix = s->mode == SUFFIX_BODY;
|
|
1005
|
-
if (
|
|
1006
|
-
l->eof(l) ||
|
|
1007
|
-
space(l->lookahead) ||
|
|
1008
|
-
(suffix ? flow_indicator(l->lookahead) : !prefix && l->lookahead == '>')
|
|
1009
|
-
) {
|
|
1063
|
+
if (uri_boundary(l, prefix, suffix)) {
|
|
1010
1064
|
if (prefix) {
|
|
1011
1065
|
s->mode = DIRECTIVE_PARAMETERS;
|
|
1012
1066
|
return emit(l, valid, TAG_PREFIX_END);
|
|
1013
1067
|
}
|
|
1014
1068
|
if (suffix) {
|
|
1015
|
-
|
|
1069
|
+
s->mode = NORMAL;
|
|
1016
1070
|
return emit(l, valid, TAG_END);
|
|
1017
1071
|
}
|
|
1018
1072
|
s->mode = VERBATIM_CLOSE;
|
|
1019
1073
|
return emit(l, valid, TAG_URI_END);
|
|
1020
1074
|
}
|
|
1021
|
-
if (scan_invalid_character(l, valid))
|
|
1075
|
+
if (scan_invalid_character(l, valid, false))
|
|
1022
1076
|
return true;
|
|
1023
1077
|
if (prefix && s->first) {
|
|
1024
1078
|
s->first = false;
|
|
1025
|
-
if (flow_indicator(l->lookahead))
|
|
1026
|
-
return take(l, valid,
|
|
1079
|
+
if (flow_indicator(l->lookahead) && uri_char(l->lookahead, false))
|
|
1080
|
+
return take(l, valid, INVALID_TAG_PREFIX_START);
|
|
1027
1081
|
}
|
|
1028
1082
|
if (l->lookahead == '%') {
|
|
1029
1083
|
step(l);
|
|
1030
1084
|
l->mark_end(l);
|
|
1031
1085
|
uint32_t value;
|
|
1032
1086
|
unsigned remaining = hex_digits(l, 2, &value);
|
|
1087
|
+
if (remaining && invalid_encoding(l->lookahead))
|
|
1088
|
+
return emit(l, valid, UNDECODABLE_ESCAPE_PREFIX);
|
|
1033
1089
|
return emit(
|
|
1034
1090
|
l,
|
|
1035
1091
|
valid,
|
|
@@ -1038,8 +1094,18 @@ static bool scan_uri(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1038
1094
|
: INVALID_URI_ESCAPE
|
|
1039
1095
|
);
|
|
1040
1096
|
}
|
|
1041
|
-
if (!uri_char(l->lookahead, suffix))
|
|
1042
|
-
|
|
1097
|
+
if (!uri_char(l->lookahead, suffix)) {
|
|
1098
|
+
do {
|
|
1099
|
+
step(l);
|
|
1100
|
+
} while (
|
|
1101
|
+
!uri_boundary(l, prefix, suffix) &&
|
|
1102
|
+
!invalid_unquoted(l->lookahead) &&
|
|
1103
|
+
l->lookahead !=
|
|
1104
|
+
'%' &&
|
|
1105
|
+
!uri_char(l->lookahead, suffix)
|
|
1106
|
+
);
|
|
1107
|
+
return finish(l, valid, INVALID_TAG_CHARACTER);
|
|
1108
|
+
}
|
|
1043
1109
|
do {
|
|
1044
1110
|
step(l);
|
|
1045
1111
|
} while (uri_char(l->lookahead, suffix));
|
|
@@ -1056,10 +1122,7 @@ scan_directive_word(TSLexer *l, const bool *valid, enum Token token) {
|
|
|
1056
1122
|
} while (!directive_boundary(l));
|
|
1057
1123
|
return finish(l, valid, token);
|
|
1058
1124
|
}
|
|
1059
|
-
/*
|
|
1060
|
-
* inside the comment invalidates the comment's first leaf. Tree-sitter then
|
|
1061
|
-
* breaks down the reused node before it, whose reduction may have depended on
|
|
1062
|
-
* the content that follows the comment. */
|
|
1125
|
+
/* Comment edits must also invalidate preceding node reductions. */
|
|
1063
1126
|
static bool start_comment(
|
|
1064
1127
|
Scanner *s,
|
|
1065
1128
|
TSLexer *l,
|
|
@@ -1093,13 +1156,13 @@ static bool scan_directive_name(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1093
1156
|
return emit(l, valid, DIRECTIVE_NAME_END);
|
|
1094
1157
|
}
|
|
1095
1158
|
s->first = false;
|
|
1096
|
-
if (scan_invalid_character(l, valid))
|
|
1159
|
+
if (scan_invalid_character(l, valid, false))
|
|
1097
1160
|
return true;
|
|
1098
1161
|
return scan_directive_word(l, valid, DIRECTIVE_NAME);
|
|
1099
1162
|
}
|
|
1100
1163
|
static bool
|
|
1101
1164
|
scan_yaml_version(Scanner *s, TSLexer *l, const bool *valid, bool end) {
|
|
1102
|
-
if (scan_invalid_character(l, valid))
|
|
1165
|
+
if (scan_invalid_character(l, valid, false))
|
|
1103
1166
|
return true;
|
|
1104
1167
|
s->mode = DIRECTIVE_PARAMETERS;
|
|
1105
1168
|
if (end)
|
|
@@ -1132,7 +1195,7 @@ scan_yaml_version(Scanner *s, TSLexer *l, const bool *valid, bool end) {
|
|
|
1132
1195
|
}
|
|
1133
1196
|
static bool
|
|
1134
1197
|
scan_directive_handle(Scanner *s, TSLexer *l, const bool *valid, bool end) {
|
|
1135
|
-
if (scan_invalid_character(l, valid))
|
|
1198
|
+
if (scan_invalid_character(l, valid, false))
|
|
1136
1199
|
return true;
|
|
1137
1200
|
s->mode = DIRECTIVE_PREFIX;
|
|
1138
1201
|
s->property_separation_notified = false;
|
|
@@ -1186,7 +1249,7 @@ static bool scan_directive(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1186
1249
|
s->mode = NORMAL;
|
|
1187
1250
|
return emit(l, valid, DIRECTIVE_END);
|
|
1188
1251
|
}
|
|
1189
|
-
if (scan_invalid_character(l, valid))
|
|
1252
|
+
if (scan_invalid_character(l, valid, false))
|
|
1190
1253
|
return true;
|
|
1191
1254
|
return scan_directive_word(
|
|
1192
1255
|
l,
|
|
@@ -1205,8 +1268,6 @@ static bool scalar_break(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1205
1268
|
s->scalar_tab = false;
|
|
1206
1269
|
return line_break(l, valid, SCALAR_LINE_BREAK);
|
|
1207
1270
|
}
|
|
1208
|
-
/* Content resumes after the prefix of a continuation line; its first token
|
|
1209
|
-
* must be indented past the enclosing block indentation. */
|
|
1210
1271
|
static bool resume_scalar_line(Scanner *s) {
|
|
1211
1272
|
s->prefix = false;
|
|
1212
1273
|
s->continuation = false;
|
|
@@ -1215,10 +1276,23 @@ static bool resume_scalar_line(Scanner *s) {
|
|
|
1215
1276
|
s->scalar_indent = false;
|
|
1216
1277
|
return s->scalar_spaces > s->indent;
|
|
1217
1278
|
}
|
|
1279
|
+
static bool provisional_indentation(const Scanner *s, uint32_t spaces) {
|
|
1280
|
+
return s->boundary_pending ||
|
|
1281
|
+
(s->provisional_indent >= -1 && spaces > s->provisional_indent);
|
|
1282
|
+
}
|
|
1218
1283
|
static bool scalar_prefix(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1219
1284
|
if (l->lookahead == '\t' && s->scalar_spaces <= s->indent) {
|
|
1220
1285
|
s->scalar_tab = true;
|
|
1221
|
-
|
|
1286
|
+
do {
|
|
1287
|
+
step(l);
|
|
1288
|
+
} while (l->lookahead == '\t');
|
|
1289
|
+
return finish(
|
|
1290
|
+
l,
|
|
1291
|
+
valid,
|
|
1292
|
+
provisional_indentation(s, s->scalar_spaces)
|
|
1293
|
+
? UNFINISHED_TAB_IN_INDENTATION
|
|
1294
|
+
: TAB_IN_INDENTATION
|
|
1295
|
+
);
|
|
1222
1296
|
}
|
|
1223
1297
|
do {
|
|
1224
1298
|
if (l->lookahead == '\t')
|
|
@@ -1247,8 +1321,14 @@ static bool scan_quote(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1247
1321
|
if (s->prefix && blank(l->lookahead))
|
|
1248
1322
|
return scalar_prefix(s, l, valid);
|
|
1249
1323
|
if (!resume_scalar_line(s))
|
|
1250
|
-
return emit(
|
|
1251
|
-
|
|
1324
|
+
return emit(
|
|
1325
|
+
l,
|
|
1326
|
+
valid,
|
|
1327
|
+
provisional_indentation(s, s->scalar_spaces)
|
|
1328
|
+
? UNFINISHED_MISSING_INDENTATION
|
|
1329
|
+
: MISSING_INDENTATION
|
|
1330
|
+
);
|
|
1331
|
+
if (scan_invalid_character(l, valid, true))
|
|
1252
1332
|
return true;
|
|
1253
1333
|
if (l->lookahead == quote) {
|
|
1254
1334
|
step(l);
|
|
@@ -1275,9 +1355,12 @@ static bool scan_quote(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1275
1355
|
if (l->eof(l))
|
|
1276
1356
|
return emit(l, valid, INCOMPLETE_ESCAPE);
|
|
1277
1357
|
if (invalid_quoted(l->lookahead)) {
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1358
|
+
return emit(
|
|
1359
|
+
l,
|
|
1360
|
+
valid,
|
|
1361
|
+
invalid_encoding(l->lookahead) ? UNDECODABLE_ESCAPE_PREFIX
|
|
1362
|
+
: INVALID_ESCAPE
|
|
1363
|
+
);
|
|
1281
1364
|
}
|
|
1282
1365
|
int32_t c = l->lookahead;
|
|
1283
1366
|
const char *simple = "0abtnvfre \t\"/\\N_LP";
|
|
@@ -1291,6 +1374,8 @@ static bool scan_quote(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1291
1374
|
uint64_t lower = (uint64_t)value << (remaining * 4);
|
|
1292
1375
|
uint64_t upper = lower | ((UINT64_C(1) << (remaining * 4)) - 1);
|
|
1293
1376
|
ok = lower <= 0x10ffff && (lower < 0xd800 || upper > 0xdfff);
|
|
1377
|
+
if (remaining && ok && invalid_encoding(l->lookahead))
|
|
1378
|
+
return emit(l, valid, UNDECODABLE_ESCAPE_PREFIX);
|
|
1294
1379
|
if (remaining)
|
|
1295
1380
|
return emit(
|
|
1296
1381
|
l,
|
|
@@ -1345,12 +1430,12 @@ static bool scan_plain(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1345
1430
|
return take(l, valid, INVALID_SCALAR_START);
|
|
1346
1431
|
if (l->lookahead == '-' || l->lookahead == '?' || l->lookahead == ':') {
|
|
1347
1432
|
step(l);
|
|
1348
|
-
if (
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1433
|
+
if (colon_boundary(l, s->flow)) {
|
|
1434
|
+
return finish(
|
|
1435
|
+
l,
|
|
1436
|
+
valid,
|
|
1437
|
+
l->eof(l) ? INCOMPLETE_SCALAR_START : INVALID_SCALAR_START
|
|
1438
|
+
);
|
|
1354
1439
|
}
|
|
1355
1440
|
text = true;
|
|
1356
1441
|
}
|
|
@@ -1366,7 +1451,13 @@ static bool scan_plain(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1366
1451
|
return finish(l, valid, SCALAR_LINE_SUFFIX);
|
|
1367
1452
|
}
|
|
1368
1453
|
if (!resume_scalar_line(s))
|
|
1369
|
-
return emit(
|
|
1454
|
+
return emit(
|
|
1455
|
+
l,
|
|
1456
|
+
valid,
|
|
1457
|
+
provisional_indentation(s, s->scalar_spaces)
|
|
1458
|
+
? UNFINISHED_MISSING_INDENTATION
|
|
1459
|
+
: MISSING_INDENTATION
|
|
1460
|
+
);
|
|
1370
1461
|
} else if (space(l->lookahead)) {
|
|
1371
1462
|
bool broken = false;
|
|
1372
1463
|
uint32_t indentation = 0;
|
|
@@ -1389,6 +1480,7 @@ static bool scan_plain(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1389
1480
|
(!broken || s->flow || indentation > s->indent);
|
|
1390
1481
|
if (more && l->lookahead == ':') {
|
|
1391
1482
|
step(l);
|
|
1483
|
+
s->eof_continuation = l->eof(l);
|
|
1392
1484
|
more = !colon_boundary(l, s->flow);
|
|
1393
1485
|
}
|
|
1394
1486
|
if (
|
|
@@ -1411,7 +1503,7 @@ static bool scan_plain(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1411
1503
|
return true;
|
|
1412
1504
|
}
|
|
1413
1505
|
}
|
|
1414
|
-
if (!text && scan_invalid_character(l, valid))
|
|
1506
|
+
if (!text && scan_invalid_character(l, valid, false))
|
|
1415
1507
|
return true;
|
|
1416
1508
|
l->mark_end(l);
|
|
1417
1509
|
while (!l->eof(l)) {
|
|
@@ -1420,8 +1512,10 @@ static bool scan_plain(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1420
1512
|
break;
|
|
1421
1513
|
if (c == ':') {
|
|
1422
1514
|
step(l);
|
|
1423
|
-
if (colon_boundary(l, s->flow))
|
|
1515
|
+
if (colon_boundary(l, s->flow)) {
|
|
1516
|
+
s->eof_continuation = l->eof(l);
|
|
1424
1517
|
break;
|
|
1518
|
+
}
|
|
1425
1519
|
text = true;
|
|
1426
1520
|
l->mark_end(l);
|
|
1427
1521
|
continue;
|
|
@@ -1455,40 +1549,34 @@ static bool scan_block_header(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1455
1549
|
s->mode = BLOCK_DETECT;
|
|
1456
1550
|
return emit(l, valid, BLOCK_HEADER_END);
|
|
1457
1551
|
}
|
|
1458
|
-
if (scan_invalid_character(l, valid))
|
|
1552
|
+
if (scan_invalid_character(l, valid, false))
|
|
1459
1553
|
return true;
|
|
1460
1554
|
if (newline(l->lookahead)) {
|
|
1461
1555
|
s->mode = BLOCK_HEADER_DONE;
|
|
1462
1556
|
return line_break(l, valid, BLOCK_HEADER_BREAK);
|
|
1463
1557
|
}
|
|
1464
1558
|
if (blank(l->lookahead)) {
|
|
1465
|
-
s->
|
|
1559
|
+
s->header_separated = true;
|
|
1466
1560
|
return scan_separation(l, valid);
|
|
1467
1561
|
}
|
|
1468
1562
|
if (l->lookahead == '#' && valid[COMMENT_START])
|
|
1469
1563
|
return start_comment(s, l, valid, BLOCK_HEADER, !s->separated);
|
|
1470
|
-
if (
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
) {
|
|
1477
|
-
s->block_indent = s->indent + l->lookahead - '0';
|
|
1478
|
-
s->header_flags |= HEADER_INDENTATION;
|
|
1479
|
-
return take(l, valid, INDENTATION_INDICATOR);
|
|
1480
|
-
}
|
|
1481
|
-
if (
|
|
1482
|
-
(l->lookahead == '+' || l->lookahead == '-') &&
|
|
1483
|
-
!(s->header_flags & (HEADER_CHOMPING | HEADER_SEPARATION))
|
|
1484
|
-
) {
|
|
1485
|
-
s->header_flags |= HEADER_CHOMPING;
|
|
1486
|
-
return take(l, valid, CHOMPING_INDICATOR);
|
|
1487
|
-
}
|
|
1488
|
-
if (l->lookahead >= '1' && l->lookahead <= '9')
|
|
1564
|
+
if (l->lookahead >= '1' && l->lookahead <= '9') {
|
|
1565
|
+
if (valid[INDENTATION_INDICATOR] && !s->header_separated) {
|
|
1566
|
+
s->block_indent = s->indent + l->lookahead - '0';
|
|
1567
|
+
s->block_explicit_indent = true;
|
|
1568
|
+
return take(l, valid, INDENTATION_INDICATOR);
|
|
1569
|
+
}
|
|
1489
1570
|
return take(l, valid, INVALID_HEADER_INDENTATION);
|
|
1571
|
+
}
|
|
1490
1572
|
if (l->lookahead == '+' || l->lookahead == '-')
|
|
1491
|
-
return take(
|
|
1573
|
+
return take(
|
|
1574
|
+
l,
|
|
1575
|
+
valid,
|
|
1576
|
+
valid[CHOMPING_INDICATOR] && !s->header_separated
|
|
1577
|
+
? CHOMPING_INDICATOR
|
|
1578
|
+
: INVALID_HEADER_CHOMPING
|
|
1579
|
+
);
|
|
1492
1580
|
step(l);
|
|
1493
1581
|
while (
|
|
1494
1582
|
!l->eof(l) &&
|
|
@@ -1496,7 +1584,7 @@ static bool scan_block_header(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1496
1584
|
l->lookahead !=
|
|
1497
1585
|
'#' &&
|
|
1498
1586
|
!invalid_unquoted(l->lookahead) &&
|
|
1499
|
-
!(l->lookahead >= '
|
|
1587
|
+
!(l->lookahead >= '1' && l->lookahead <= '9') &&
|
|
1500
1588
|
l->lookahead !=
|
|
1501
1589
|
'+' &&
|
|
1502
1590
|
l->lookahead != '-'
|
|
@@ -1515,8 +1603,6 @@ static void reset_line(Scanner *s) {
|
|
|
1515
1603
|
s->after_document_end = false;
|
|
1516
1604
|
}
|
|
1517
1605
|
|
|
1518
|
-
/* A document that ends without "..." must be followed by an explicit
|
|
1519
|
-
* document; a directive document then also lacks its document end marker. */
|
|
1520
1606
|
static void close_document(Scanner *s) {
|
|
1521
1607
|
s->document = false;
|
|
1522
1608
|
s->document_content = false;
|
|
@@ -1526,19 +1612,23 @@ static void open_document(Scanner *s, bool started) {
|
|
|
1526
1612
|
s->document = true;
|
|
1527
1613
|
s->document_started = started;
|
|
1528
1614
|
s->document_content = false;
|
|
1615
|
+
s->eof_continuation = false;
|
|
1529
1616
|
s->flow = 0;
|
|
1530
1617
|
s->indent = -1;
|
|
1618
|
+
s->provisional_indent = -2;
|
|
1531
1619
|
s->block_out = false;
|
|
1532
1620
|
}
|
|
1533
1621
|
|
|
1534
|
-
/* Close open constructs before a document marker; directives and stream BOMs
|
|
1535
|
-
* are left for normal scanning. */
|
|
1536
1622
|
static bool scan_boundary(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1537
1623
|
if (s->mode == SINGLE || s->mode == DOUBLE) {
|
|
1538
1624
|
s->mode = NORMAL;
|
|
1539
1625
|
s->prefix = false;
|
|
1540
1626
|
s->scalar_indent = false;
|
|
1541
|
-
return emit(
|
|
1627
|
+
return emit(
|
|
1628
|
+
l,
|
|
1629
|
+
valid,
|
|
1630
|
+
s->boundary_pending ? INCOMPLETE_QUOTE_CLOSE : MISSING_QUOTE_CLOSE
|
|
1631
|
+
);
|
|
1542
1632
|
}
|
|
1543
1633
|
if (s->mode == PLAIN) {
|
|
1544
1634
|
s->mode = NORMAL;
|
|
@@ -1549,10 +1639,12 @@ static bool scan_boundary(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1549
1639
|
reset_line(s);
|
|
1550
1640
|
return emit(l, valid, BLOCK_SCALAR_END);
|
|
1551
1641
|
}
|
|
1552
|
-
|
|
1642
|
+
const enum Token closings[] = {
|
|
1553
1643
|
EMPTY_BLOCK_NODE,
|
|
1554
|
-
|
|
1555
|
-
|
|
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,
|
|
1556
1648
|
MAPPING_END,
|
|
1557
1649
|
SEQUENCE_END,
|
|
1558
1650
|
DEDENT,
|
|
@@ -1595,8 +1687,6 @@ static bool scan_boundary(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1595
1687
|
return emit(l, valid, token);
|
|
1596
1688
|
}
|
|
1597
1689
|
|
|
1598
|
-
/* Auto-detects the content indentation from the first non-empty body line,
|
|
1599
|
-
* or from the longest leading empty line when no content follows. */
|
|
1600
1690
|
static bool detect_block_indent(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1601
1691
|
if (s->block_indent < 0) {
|
|
1602
1692
|
uint32_t longest = 0;
|
|
@@ -1612,8 +1702,9 @@ static bool detect_block_indent(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1612
1702
|
content && !spaces && (l->lookahead == 0xfeff || document_marker(l))
|
|
1613
1703
|
)
|
|
1614
1704
|
content = false;
|
|
1615
|
-
s->block_indent =
|
|
1616
|
-
|
|
1705
|
+
s->block_indent = content ? spaces
|
|
1706
|
+
: longest > s->indent ? longest
|
|
1707
|
+
: s->indent + 1;
|
|
1617
1708
|
break;
|
|
1618
1709
|
}
|
|
1619
1710
|
}
|
|
@@ -1622,37 +1713,58 @@ static bool detect_block_indent(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1622
1713
|
s->mode = BLOCK_BODY;
|
|
1623
1714
|
return emit(l, valid, BLOCK_BODY_START);
|
|
1624
1715
|
}
|
|
1716
|
+
/* Cache the layout run to avoid repeated lookahead on shallow tab lines. */
|
|
1717
|
+
static bool block_stream_layout_follows(Scanner *s, TSLexer *l) {
|
|
1718
|
+
uint32_t lines = 1;
|
|
1719
|
+
for (;;) {
|
|
1720
|
+
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))
|
|
1727
|
+
return true;
|
|
1728
|
+
if (!newline(l->lookahead)) {
|
|
1729
|
+
s->block_layout_lines = lines;
|
|
1730
|
+
return l->get_column(l) ==
|
|
1731
|
+
0 &&
|
|
1732
|
+
(l->lookahead == 0xfeff || l->lookahead == '%' || document_marker(l));
|
|
1733
|
+
}
|
|
1734
|
+
skip_line_break(l);
|
|
1735
|
+
lines++;
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1625
1738
|
static bool scan_block_body(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1626
1739
|
if (l->eof(l)) {
|
|
1627
1740
|
s->mode = NORMAL;
|
|
1741
|
+
s->block_layout_lines = 0;
|
|
1628
1742
|
reset_line(s);
|
|
1629
1743
|
return emit(l, valid, BLOCK_SCALAR_END);
|
|
1630
1744
|
}
|
|
1631
1745
|
uint32_t spaces = count_spaces(l);
|
|
1632
|
-
|
|
1633
|
-
bool
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
bool
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
}
|
|
1746
|
+
int32_t first = l->lookahead;
|
|
1747
|
+
bool empty = newline(first);
|
|
1748
|
+
bool spaced = spaces > s->block_indent || first == '\t';
|
|
1749
|
+
bool shallow_tab = spaces < s->block_indent && first == '\t';
|
|
1750
|
+
bool leading = s->block_leading && !s->block_explicit_indent;
|
|
1751
|
+
bool end = l->eof(l) && (spaces <= s->block_indent || leading);
|
|
1752
|
+
if (shallow_tab && !s->block_layout_lines)
|
|
1753
|
+
end = block_stream_layout_follows(s, l);
|
|
1641
1754
|
if (
|
|
1642
|
-
|
|
1643
|
-
(
|
|
1644
|
-
s->indent ||
|
|
1645
|
-
|
|
1646
|
-
(spaces < s->block_indent && l->lookahead == '#'))
|
|
1755
|
+
end ||
|
|
1756
|
+
(!empty &&
|
|
1757
|
+
((spaces <= s->indent && !shallow_tab) ||
|
|
1758
|
+
(spaces < s->block_indent && first == '#')))
|
|
1647
1759
|
) {
|
|
1648
1760
|
s->mode = NORMAL;
|
|
1761
|
+
s->block_layout_lines = 0;
|
|
1649
1762
|
reset_line(s);
|
|
1650
1763
|
return emit(l, valid, BLOCK_SCALAR_END);
|
|
1651
1764
|
}
|
|
1652
|
-
s->
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
(s->block_leading && !(s->header_flags & HEADER_INDENTATION)));
|
|
1765
|
+
if (s->block_layout_lines)
|
|
1766
|
+
s->block_layout_lines--;
|
|
1767
|
+
s->block_empty = empty && (spaces <= s->block_indent || leading);
|
|
1656
1768
|
if (!s->block_empty)
|
|
1657
1769
|
s->block_leading = false;
|
|
1658
1770
|
s->block_prefix = true;
|
|
@@ -1689,7 +1801,12 @@ static bool scan_block_line(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1689
1801
|
return finish(l, valid, INVALID_INDENTATION);
|
|
1690
1802
|
}
|
|
1691
1803
|
if (!s->block_empty && l->get_column(l) < s->block_indent)
|
|
1692
|
-
return emit(
|
|
1804
|
+
return emit(
|
|
1805
|
+
l,
|
|
1806
|
+
valid,
|
|
1807
|
+
s->boundary_pending ? UNFINISHED_MISSING_INDENTATION
|
|
1808
|
+
: MISSING_INDENTATION
|
|
1809
|
+
);
|
|
1693
1810
|
}
|
|
1694
1811
|
if (newline(l->lookahead)) {
|
|
1695
1812
|
s->mode = BLOCK_LINE_DONE;
|
|
@@ -1745,12 +1862,28 @@ static bool scan_prefix(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1745
1862
|
' ' &&
|
|
1746
1863
|
(excess || !s->prefix_invalid || l->get_column(l) < s->indent)
|
|
1747
1864
|
);
|
|
1748
|
-
return finish(
|
|
1865
|
+
return finish(
|
|
1866
|
+
l,
|
|
1867
|
+
valid,
|
|
1868
|
+
excess
|
|
1869
|
+
? s->prefix_eof ? UNFINISHED_INVALID_INDENTATION : INVALID_INDENTATION
|
|
1870
|
+
: INDENTATION
|
|
1871
|
+
);
|
|
1749
1872
|
}
|
|
1750
1873
|
if (blank(l->lookahead)) {
|
|
1751
1874
|
s->prefix_tab = true;
|
|
1752
|
-
if (s->tab_invalid && l->lookahead == '\t')
|
|
1753
|
-
|
|
1875
|
+
if (s->tab_invalid && l->lookahead == '\t') {
|
|
1876
|
+
do {
|
|
1877
|
+
step(l);
|
|
1878
|
+
} while (l->lookahead == '\t');
|
|
1879
|
+
return finish(
|
|
1880
|
+
l,
|
|
1881
|
+
valid,
|
|
1882
|
+
s->prefix_eof || provisional_indentation(s, s->line_indent)
|
|
1883
|
+
? UNFINISHED_TAB_IN_INDENTATION
|
|
1884
|
+
: TAB_IN_INDENTATION
|
|
1885
|
+
);
|
|
1886
|
+
}
|
|
1754
1887
|
do {
|
|
1755
1888
|
step(l);
|
|
1756
1889
|
} while (blank(l->lookahead) && !(s->tab_invalid && l->lookahead == '\t'));
|
|
@@ -1766,7 +1899,13 @@ static bool scan_prefix(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1766
1899
|
s->line_indent <= s->indent
|
|
1767
1900
|
) {
|
|
1768
1901
|
s->indent_checked = true;
|
|
1769
|
-
return emit(
|
|
1902
|
+
return emit(
|
|
1903
|
+
l,
|
|
1904
|
+
valid,
|
|
1905
|
+
provisional_indentation(s, s->line_indent)
|
|
1906
|
+
? UNFINISHED_MISSING_INDENTATION
|
|
1907
|
+
: MISSING_INDENTATION
|
|
1908
|
+
);
|
|
1770
1909
|
}
|
|
1771
1910
|
s->mode = NORMAL;
|
|
1772
1911
|
return emit(l, valid, LINE_PREFIX_END);
|
|
@@ -1777,7 +1916,12 @@ scan_node_start(Scanner *s, TSLexer *l, const bool *valid, int64_t column) {
|
|
|
1777
1916
|
int32_t first = l->lookahead;
|
|
1778
1917
|
enum Token kind = s->flow ? node_start(first) : classify_block_start(s, l);
|
|
1779
1918
|
if (!s->line && valid[DOCUMENT_COMPACT_START] && block_collection(kind))
|
|
1780
|
-
return emit(
|
|
1919
|
+
return emit(
|
|
1920
|
+
l,
|
|
1921
|
+
valid,
|
|
1922
|
+
s->block_eof ? UNFINISHED_INVALID_DOCUMENT_COLLECTION_START
|
|
1923
|
+
: DOCUMENT_COMPACT_START
|
|
1924
|
+
);
|
|
1781
1925
|
if (
|
|
1782
1926
|
!s->flow &&
|
|
1783
1927
|
s->line &&
|
|
@@ -1795,8 +1939,10 @@ scan_node_start(Scanner *s, TSLexer *l, const bool *valid, int64_t column) {
|
|
|
1795
1939
|
kind ==
|
|
1796
1940
|
SEQUENCE_START &&
|
|
1797
1941
|
valid[MAPPING_END]
|
|
1798
|
-
)
|
|
1942
|
+
) {
|
|
1943
|
+
s->eof_continuation = s->block_eof;
|
|
1799
1944
|
return emit(l, valid, MAPPING_END);
|
|
1945
|
+
}
|
|
1800
1946
|
if (
|
|
1801
1947
|
!s->flow &&
|
|
1802
1948
|
s->line &&
|
|
@@ -1818,6 +1964,8 @@ scan_node_start(Scanner *s, TSLexer *l, const bool *valid, int64_t column) {
|
|
|
1818
1964
|
if ((kind == LITERAL_START || kind == FOLDED_START) && !valid[kind])
|
|
1819
1965
|
kind = PLAIN_START;
|
|
1820
1966
|
if (!s->flow && block_collection(kind)) {
|
|
1967
|
+
if (s->block_eof && s->provisional_indent == -2 && column > s->indent)
|
|
1968
|
+
s->provisional_indent = s->indent;
|
|
1821
1969
|
enum Token shift = column < s->indent ? OUTDENT : INDENT;
|
|
1822
1970
|
if (column != s->indent && emit_closing(s, l, valid, &shift, 1))
|
|
1823
1971
|
return true;
|
|
@@ -1836,10 +1984,10 @@ scan_node_start(Scanner *s, TSLexer *l, const bool *valid, int64_t column) {
|
|
|
1836
1984
|
return start_plain(s, l, valid);
|
|
1837
1985
|
if (kind == PROPERTIES_START) {
|
|
1838
1986
|
s->json = false;
|
|
1839
|
-
s->
|
|
1987
|
+
s->property_colon_content = false;
|
|
1840
1988
|
s->properties_ready = false;
|
|
1841
|
-
s->duplicate_pending = false;
|
|
1842
1989
|
s->property_separation_notified = false;
|
|
1990
|
+
s->property_keys = 0;
|
|
1843
1991
|
}
|
|
1844
1992
|
return !block_collection(kind) && emit(l, valid, kind);
|
|
1845
1993
|
}
|
|
@@ -1869,24 +2017,14 @@ static bool scan_node_open(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1869
2017
|
bool literal = l->lookahead == '|';
|
|
1870
2018
|
s->mode = BLOCK_HEADER;
|
|
1871
2019
|
s->block_indent = -1;
|
|
1872
|
-
s->
|
|
2020
|
+
s->block_layout_lines = 0;
|
|
2021
|
+
s->block_explicit_indent = false;
|
|
2022
|
+
s->header_separated = false;
|
|
1873
2023
|
return take(l, valid, literal ? LITERAL_INDICATOR : FOLDED_INDICATOR);
|
|
1874
2024
|
}
|
|
1875
2025
|
return false;
|
|
1876
2026
|
}
|
|
1877
2027
|
|
|
1878
|
-
static bool scan(Scanner *s, TSLexer *l, const bool *valid);
|
|
1879
|
-
|
|
1880
|
-
static bool scan_content(Scanner *s, TSLexer *l, const bool *valid);
|
|
1881
|
-
static bool
|
|
1882
|
-
scan_entry(Scanner *s, TSLexer *l, const bool *valid, int64_t column);
|
|
1883
|
-
static bool scan_properties(
|
|
1884
|
-
Scanner *s,
|
|
1885
|
-
TSLexer *l,
|
|
1886
|
-
const bool *valid,
|
|
1887
|
-
bool property_pending
|
|
1888
|
-
);
|
|
1889
|
-
|
|
1890
2028
|
static bool scan_line_context(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1891
2029
|
s->line_indent = count_spaces(l);
|
|
1892
2030
|
skip_blanks(l);
|
|
@@ -1917,160 +2055,238 @@ static bool begin_line_prefix(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
1917
2055
|
!valid[INDENT] &&
|
|
1918
2056
|
(valid[PAIR_START] || valid[ENTRY_START]);
|
|
1919
2057
|
bool tab_invalid = !s->layout_only && spaces <= s->indent;
|
|
1920
|
-
|
|
1921
|
-
|
|
2058
|
+
s->prefix_eof = prefix_invalid && s->eof_continuation;
|
|
2059
|
+
if (!s->layout_only && !s->flow) {
|
|
2060
|
+
bool unfinished;
|
|
2061
|
+
bool collection = block_collection(classify_block_node(l, &unfinished));
|
|
2062
|
+
s->prefix_eof |= !tab_invalid && collection && unfinished;
|
|
2063
|
+
tab_invalid |= collection;
|
|
2064
|
+
}
|
|
1922
2065
|
s->line_prefixed = true;
|
|
1923
2066
|
return start_line_prefix(s, l, valid, prefix_invalid, tab_invalid, false);
|
|
1924
2067
|
}
|
|
1925
2068
|
|
|
1926
2069
|
static bool
|
|
1927
|
-
|
|
2070
|
+
scan_entry(Scanner *s, TSLexer *l, const bool *valid, int64_t column) {
|
|
1928
2071
|
if (
|
|
1929
|
-
|
|
1930
|
-
|
|
2072
|
+
l->lookahead ==
|
|
2073
|
+
',' &&
|
|
2074
|
+
!valid[FLOW_SEPARATOR] &&
|
|
2075
|
+
valid[UNEXPECTED_FLOW_SEPARATOR]
|
|
1931
2076
|
)
|
|
1932
|
-
return
|
|
1933
|
-
if (
|
|
1934
|
-
s->
|
|
1935
|
-
(valid
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
2077
|
+
return take(l, valid, UNEXPECTED_FLOW_SEPARATOR);
|
|
2078
|
+
if (valid[FLOW_MAP_PAIR_START] && !flow_entry_end(l->lookahead)) {
|
|
2079
|
+
s->json = false;
|
|
2080
|
+
return emit(l, valid, FLOW_MAP_PAIR_START);
|
|
2081
|
+
}
|
|
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 == ':') {
|
|
1939
2086
|
step(l);
|
|
1940
|
-
|
|
1941
|
-
return emit_indicator(s, l, valid, VALUE_INDICATOR);
|
|
2087
|
+
indicator = colon_boundary(l, first == ':' && s->flow);
|
|
1942
2088
|
}
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
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);
|
|
1949
2104
|
}
|
|
1950
|
-
if (
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
return emit(l, valid, PROPERTIES_END);
|
|
2105
|
+
if (l->lookahead == '?' && valid[KEY_INDICATOR]) {
|
|
2106
|
+
step(l);
|
|
2107
|
+
if (space(l->lookahead) || l->eof(l)) {
|
|
2108
|
+
return emit_indicator(s, l, valid, KEY_INDICATOR);
|
|
2109
|
+
}
|
|
2110
|
+
return start_plain(s, l, valid);
|
|
1957
2111
|
}
|
|
1958
|
-
|
|
2112
|
+
if (l->lookahead == ':' && valid[VALUE_INDICATOR]) {
|
|
2113
|
+
bool adjacent = s->flow && s->json;
|
|
2114
|
+
step(l);
|
|
2115
|
+
if (adjacent || colon_boundary(l, s->flow)) {
|
|
2116
|
+
s->value_separation =
|
|
2117
|
+
s->flow && !adjacent && (l->lookahead == '[' || l->lookahead == '{');
|
|
2118
|
+
s->json = false;
|
|
2119
|
+
return emit_indicator(s, l, valid, VALUE_INDICATOR);
|
|
2120
|
+
}
|
|
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
|
+
);
|
|
2128
|
+
}
|
|
2129
|
+
if (l->lookahead == '-' && valid[SEQUENCE_INDICATOR]) {
|
|
2130
|
+
step(l);
|
|
2131
|
+
return emit_indicator(s, l, valid, SEQUENCE_INDICATOR);
|
|
2132
|
+
}
|
|
2133
|
+
if (s->value_separation && valid[MISSING_SEPARATION]) {
|
|
2134
|
+
s->value_separation = false;
|
|
2135
|
+
return emit(l, valid, MISSING_SEPARATION);
|
|
2136
|
+
}
|
|
2137
|
+
if (l->lookahead == ',' && valid[FLOW_SEPARATOR])
|
|
2138
|
+
return take(l, valid, FLOW_SEPARATOR);
|
|
2139
|
+
if (l->lookahead == ']' && valid[FLOW_SEQUENCE_CLOSE])
|
|
2140
|
+
return close_flow(s, l, valid, FLOW_SEQUENCE_CLOSE);
|
|
2141
|
+
if (l->lookahead == '}' && valid[FLOW_MAPPING_CLOSE])
|
|
2142
|
+
return close_flow(s, l, valid, FLOW_MAPPING_CLOSE);
|
|
2143
|
+
if (l->lookahead == ']' && valid[MISSING_FLOW_MAPPING_CLOSE])
|
|
2144
|
+
return close_flow(s, l, valid, MISSING_FLOW_MAPPING_CLOSE);
|
|
2145
|
+
if (l->lookahead == '}' && valid[MISSING_FLOW_SEQUENCE_CLOSE])
|
|
2146
|
+
return close_flow(s, l, valid, MISSING_FLOW_SEQUENCE_CLOSE);
|
|
1959
2147
|
if (
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
2148
|
+
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] &&
|
|
2154
|
+
!flow_entry_end(l->lookahead)
|
|
2155
|
+
)
|
|
2156
|
+
return emit(
|
|
1963
2157
|
l,
|
|
1964
2158
|
valid,
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
)
|
|
1968
|
-
)
|
|
1969
|
-
return true;
|
|
2159
|
+
s->eof_continuation ? UNFINISHED_MISSING_FLOW_SEPARATOR
|
|
2160
|
+
: MISSING_FLOW_SEPARATOR
|
|
2161
|
+
);
|
|
1970
2162
|
if (
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
)
|
|
1989
|
-
return emit(l, valid, MAPPING_END);
|
|
1990
|
-
if (
|
|
1991
|
-
valid[SEQUENCE_END] && (s->line_indent < s->indent || s->line_head != '-')
|
|
1992
|
-
)
|
|
1993
|
-
return emit(l, valid, SEQUENCE_END);
|
|
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
|
+
) {
|
|
2179
|
+
return scan_node_start(s, l, valid, column);
|
|
1994
2180
|
}
|
|
2181
|
+
return scan_node_open(s, l, valid);
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2184
|
+
static bool scan_content(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1995
2185
|
if (
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
(
|
|
2000
|
-
(s->flow &&
|
|
2001
|
-
s->indent >=
|
|
2002
|
-
0 &&
|
|
2003
|
-
!newline(l->lookahead) &&
|
|
2004
|
-
!l->eof(l) &&
|
|
2005
|
-
l->lookahead != '#'))
|
|
2006
|
-
)
|
|
2007
|
-
return begin_line_prefix(s, l, valid);
|
|
2008
|
-
if (newline(l->lookahead) && valid[LINE_BREAK]) {
|
|
2186
|
+
l->lookahead == 0xfeff && l->get_column(l) == 0 && valid[BYTE_ORDER_MARK]
|
|
2187
|
+
) {
|
|
2188
|
+
step(l);
|
|
2189
|
+
cursor_start_line(l);
|
|
2009
2190
|
reset_line(s);
|
|
2010
|
-
return
|
|
2191
|
+
return finish(l, valid, BYTE_ORDER_MARK);
|
|
2011
2192
|
}
|
|
2012
|
-
if (
|
|
2013
|
-
return
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
l
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
!s->separated && l->get_column(l) != 0
|
|
2193
|
+
if (scan_invalid_character(l, valid, false))
|
|
2194
|
+
return true;
|
|
2195
|
+
bool end = l->eof(l);
|
|
2196
|
+
if (s->after_document_end && !end) {
|
|
2197
|
+
do {
|
|
2198
|
+
step(l);
|
|
2199
|
+
} while (
|
|
2200
|
+
!l->eof(l) && !space(l->lookahead) && !invalid_unquoted(l->lookahead)
|
|
2021
2201
|
);
|
|
2022
|
-
|
|
2023
|
-
s->mode = DIRECTIVE_NAME_BODY;
|
|
2024
|
-
s->first = true;
|
|
2025
|
-
return take(l, valid, DIRECTIVE_INDICATOR);
|
|
2202
|
+
return finish(l, valid, UNEXPECTED_DOCUMENT_END_CONTENT);
|
|
2026
2203
|
}
|
|
2204
|
+
int64_t column = s->line ? s->line_indent : l->get_column(l);
|
|
2027
2205
|
if (
|
|
2206
|
+
valid[EXPLICIT_VALUE_START] &&
|
|
2028
2207
|
l->lookahead ==
|
|
2029
|
-
'
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
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]
|
|
2033
2217
|
) {
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
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);
|
|
2043
2232
|
}
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2233
|
+
return emit(l, valid, EMPTY_BLOCK_NODE);
|
|
2234
|
+
}
|
|
2235
|
+
if (valid[DOCUMENT_CLOSE] && end) {
|
|
2236
|
+
close_document(s);
|
|
2237
|
+
return emit(l, valid, DOCUMENT_CLOSE);
|
|
2238
|
+
}
|
|
2239
|
+
if (valid[DOCUMENT_OPEN] && !end && !s->document) {
|
|
2240
|
+
open_document(s, !s->explicit_document_required);
|
|
2241
|
+
return emit(l, valid, DOCUMENT_OPEN);
|
|
2242
|
+
}
|
|
2243
|
+
if (valid[UNEXPECTED_CONTENT_START] && s->document_content && !end) {
|
|
2244
|
+
s->document_content = false;
|
|
2047
2245
|
return emit(
|
|
2048
2246
|
l,
|
|
2049
2247
|
valid,
|
|
2050
|
-
s->
|
|
2051
|
-
|
|
2052
|
-
|
|
2248
|
+
s->eof_continuation || s->boundary_pending
|
|
2249
|
+
? UNFINISHED_UNEXPECTED_DOCUMENT_CONTENT_START
|
|
2250
|
+
: UNEXPECTED_CONTENT_START
|
|
2053
2251
|
);
|
|
2054
2252
|
}
|
|
2055
|
-
if (
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
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);
|
|
2258
|
+
}
|
|
2259
|
+
if (end) {
|
|
2260
|
+
static const enum Token endings[] = {
|
|
2261
|
+
MAPPING_END,
|
|
2262
|
+
SEQUENCE_END,
|
|
2263
|
+
INCOMPLETE_FLOW_SEQUENCE_CLOSE,
|
|
2264
|
+
INCOMPLETE_FLOW_MAPPING_CLOSE,
|
|
2265
|
+
END_OF_FILE
|
|
2266
|
+
};
|
|
2267
|
+
return emit_closing(
|
|
2268
|
+
s,
|
|
2062
2269
|
l,
|
|
2063
2270
|
valid,
|
|
2064
|
-
|
|
2065
|
-
|
|
2271
|
+
endings,
|
|
2272
|
+
sizeof(endings) / sizeof(*endings)
|
|
2066
2273
|
);
|
|
2067
2274
|
}
|
|
2068
|
-
|
|
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
|
+
return scan_entry(s, l, valid, column);
|
|
2069
2283
|
}
|
|
2070
2284
|
|
|
2071
|
-
static
|
|
2072
|
-
|
|
2285
|
+
static bool scan(Scanner *s, TSLexer *l, const bool *valid);
|
|
2286
|
+
|
|
2287
|
+
static void begin_property(Scanner *s, unsigned key) {
|
|
2073
2288
|
s->property_separation_notified = false;
|
|
2289
|
+
s->property_keys &= (uint8_t)~key;
|
|
2074
2290
|
}
|
|
2075
2291
|
static bool scan_properties(
|
|
2076
2292
|
Scanner *s,
|
|
@@ -2078,33 +2294,12 @@ static bool scan_properties(
|
|
|
2078
2294
|
const bool *valid,
|
|
2079
2295
|
bool property_pending
|
|
2080
2296
|
) {
|
|
2081
|
-
/* Properties at the start of a line end the node's own properties when
|
|
2082
|
-
* they belong to the first key of a block mapping that is its content.
|
|
2083
|
-
* The line context records whether the leading property or alias of the
|
|
2084
|
-
* line is such a key. */
|
|
2085
|
-
if (
|
|
2086
|
-
valid[PROPERTIES_END] &&
|
|
2087
|
-
((l->lookahead != '&' && l->lookahead != '!') ||
|
|
2088
|
-
(s->property_flags &&
|
|
2089
|
-
!s->flow &&
|
|
2090
|
-
s->line &&
|
|
2091
|
-
(s->line_indent <= s->indent || s->line_mapping_key)))
|
|
2092
|
-
) {
|
|
2093
|
-
s->properties_ready = true;
|
|
2094
|
-
s->property_separation_notified = false;
|
|
2095
|
-
if (l->lookahead == ':') {
|
|
2096
|
-
step(l);
|
|
2097
|
-
if (!colon_boundary(l, s->flow))
|
|
2098
|
-
s->property_flags |= PROPERTY_COLON_CONTENT;
|
|
2099
|
-
}
|
|
2100
|
-
return emit(l, valid, PROPERTIES_END);
|
|
2101
|
-
}
|
|
2102
2297
|
if (property_pending) {
|
|
2103
2298
|
bool content = !l->eof(l) && !(s->flow && flow_entry_end(l->lookahead));
|
|
2104
2299
|
if (
|
|
2105
2300
|
l->lookahead ==
|
|
2106
2301
|
':' &&
|
|
2107
|
-
!
|
|
2302
|
+
!s->property_colon_content &&
|
|
2108
2303
|
!(s->line && !s->flow && valid[BLOCK_PROPERTY_CONTENT_START])
|
|
2109
2304
|
)
|
|
2110
2305
|
content = false;
|
|
@@ -2126,31 +2321,40 @@ static bool scan_properties(
|
|
|
2126
2321
|
return emit(l, valid, property_content_start(s, l, valid));
|
|
2127
2322
|
}
|
|
2128
2323
|
if (
|
|
2129
|
-
s->property_flags &&
|
|
2130
2324
|
!s->separated &&
|
|
2131
2325
|
!s->property_separation_notified &&
|
|
2132
2326
|
valid[MISSING_SEPARATION] &&
|
|
2133
|
-
((l->lookahead ==
|
|
2134
|
-
|
|
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])))
|
|
2135
2333
|
) {
|
|
2136
2334
|
s->property_separation_notified = true;
|
|
2137
2335
|
return emit(l, valid, MISSING_SEPARATION);
|
|
2138
2336
|
}
|
|
2337
|
+
if (
|
|
2338
|
+
(l->lookahead == '&' && valid[DUPLICATE_ANCHOR_START]) ||
|
|
2339
|
+
(l->lookahead == '!' && valid[DUPLICATE_TAG_START])
|
|
2340
|
+
) {
|
|
2341
|
+
bool anchor = l->lookahead == '&';
|
|
2342
|
+
bool unfinished = s->property_keys & (anchor ? ANCHOR_KEY : TAG_KEY);
|
|
2343
|
+
return emit(
|
|
2344
|
+
l,
|
|
2345
|
+
valid,
|
|
2346
|
+
anchor
|
|
2347
|
+
? (unfinished ? UNFINISHED_DUPLICATE_ANCHOR_START
|
|
2348
|
+
: DUPLICATE_ANCHOR_START)
|
|
2349
|
+
: (unfinished ? UNFINISHED_DUPLICATE_TAG_START : DUPLICATE_TAG_START)
|
|
2350
|
+
);
|
|
2351
|
+
}
|
|
2139
2352
|
if (
|
|
2140
2353
|
(l->lookahead == '&' && valid[ANCHOR_INDICATOR]) ||
|
|
2141
2354
|
(l->lookahead == '*' && valid[ALIAS_INDICATOR])
|
|
2142
2355
|
) {
|
|
2143
2356
|
bool anchor = l->lookahead == '&';
|
|
2144
|
-
|
|
2145
|
-
anchor &&
|
|
2146
|
-
(s->property_flags & PROPERTY_ANCHOR) &&
|
|
2147
|
-
!s->duplicate_pending &&
|
|
2148
|
-
valid[DUPLICATE_ANCHOR_START]
|
|
2149
|
-
) {
|
|
2150
|
-
s->duplicate_pending = true;
|
|
2151
|
-
return emit(l, valid, DUPLICATE_ANCHOR_START);
|
|
2152
|
-
}
|
|
2153
|
-
begin_property(s);
|
|
2357
|
+
begin_property(s, anchor ? ANCHOR_KEY : 0);
|
|
2154
2358
|
s->mode = anchor ? ANCHOR_BODY : ALIAS_BODY;
|
|
2155
2359
|
s->first = true;
|
|
2156
2360
|
s->json = false;
|
|
@@ -2163,29 +2367,20 @@ static bool scan_properties(
|
|
|
2163
2367
|
valid[SHORTHAND_TAG_START] ||
|
|
2164
2368
|
valid[NON_SPECIFIC_TAG])
|
|
2165
2369
|
) {
|
|
2166
|
-
if (
|
|
2167
|
-
(s->property_flags & PROPERTY_TAG) &&
|
|
2168
|
-
!s->duplicate_pending &&
|
|
2169
|
-
valid[DUPLICATE_TAG_START]
|
|
2170
|
-
) {
|
|
2171
|
-
s->duplicate_pending = true;
|
|
2172
|
-
return emit(l, valid, DUPLICATE_TAG_START);
|
|
2173
|
-
}
|
|
2174
2370
|
step(l);
|
|
2175
2371
|
if (l->lookahead == '<')
|
|
2176
2372
|
return emit(l, valid, VERBATIM_TAG_START);
|
|
2177
2373
|
if (!name_boundary(l))
|
|
2178
2374
|
return emit(l, valid, SHORTHAND_TAG_START);
|
|
2179
2375
|
l->mark_end(l);
|
|
2180
|
-
begin_property(s);
|
|
2181
|
-
s->property_flags |= PROPERTY_TAG;
|
|
2376
|
+
begin_property(s, TAG_KEY);
|
|
2182
2377
|
return emit(l, valid, NON_SPECIFIC_TAG);
|
|
2183
2378
|
}
|
|
2184
2379
|
if (valid[VERBATIM_TAG_OPEN]) {
|
|
2185
2380
|
step(l);
|
|
2186
2381
|
step(l);
|
|
2187
2382
|
l->mark_end(l);
|
|
2188
|
-
begin_property(s);
|
|
2383
|
+
begin_property(s, TAG_KEY);
|
|
2189
2384
|
s->mode = URI_BEGIN;
|
|
2190
2385
|
return emit(l, valid, VERBATIM_TAG_OPEN);
|
|
2191
2386
|
}
|
|
@@ -2205,212 +2400,230 @@ static bool scan_properties(
|
|
|
2205
2400
|
}
|
|
2206
2401
|
}
|
|
2207
2402
|
s->mode = HANDLE_SELECT;
|
|
2208
|
-
begin_property(s);
|
|
2403
|
+
begin_property(s, TAG_KEY);
|
|
2209
2404
|
return emit(l, valid, TAG_HANDLE_START);
|
|
2210
2405
|
}
|
|
2211
2406
|
return scan_content(s, l, valid);
|
|
2212
2407
|
}
|
|
2213
2408
|
|
|
2214
|
-
static bool
|
|
2409
|
+
static bool
|
|
2410
|
+
scan_normal(Scanner *s, TSLexer *l, const bool *valid, bool property_pending) {
|
|
2215
2411
|
if (
|
|
2216
|
-
|
|
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])
|
|
2217
2419
|
) {
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
cursor_start_line(l);
|
|
2221
|
-
reset_line(s);
|
|
2222
|
-
return finish(l, valid, BYTE_ORDER_MARK);
|
|
2223
|
-
}
|
|
2224
|
-
if (scan_invalid_character(l, valid))
|
|
2225
|
-
return true;
|
|
2226
|
-
bool end = l->eof(l);
|
|
2227
|
-
if (s->after_document_end && !end) {
|
|
2228
|
-
do {
|
|
2420
|
+
s->key_done = false;
|
|
2421
|
+
if (l->lookahead == ':') {
|
|
2229
2422
|
step(l);
|
|
2230
|
-
|
|
2231
|
-
|
|
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
|
|
2232
2431
|
);
|
|
2233
|
-
return finish(l, valid, UNEXPECTED_DOCUMENT_END_CONTENT);
|
|
2234
2432
|
}
|
|
2235
|
-
|
|
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};
|
|
2236
2440
|
if (
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2441
|
+
!property_pending &&
|
|
2442
|
+
emit_closing(
|
|
2443
|
+
s,
|
|
2444
|
+
l,
|
|
2445
|
+
valid,
|
|
2446
|
+
restorations,
|
|
2447
|
+
sizeof(restorations) / sizeof(*restorations)
|
|
2448
|
+
)
|
|
2244
2449
|
)
|
|
2245
|
-
return
|
|
2450
|
+
return true;
|
|
2246
2451
|
if (
|
|
2247
|
-
|
|
2452
|
+
!property_pending &&
|
|
2453
|
+
s->line &&
|
|
2454
|
+
s->line_context &&
|
|
2455
|
+
!s->layout_only &&
|
|
2456
|
+
!s->flow
|
|
2248
2457
|
) {
|
|
2249
|
-
if (block_value_follows(s, l, valid))
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
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);
|
|
2254
2474
|
}
|
|
2255
|
-
|
|
2256
|
-
return emit(l, valid, s->block_out ? VALUE_START : SEQUENCE_VALUE_START);
|
|
2475
|
+
return emit(l, valid, MAPPING_END);
|
|
2257
2476
|
}
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
return emit(l, valid, DOCUMENT_CLOSE);
|
|
2263
|
-
}
|
|
2264
|
-
if (valid[DOCUMENT_OPEN] && !end && !s->document) {
|
|
2265
|
-
open_document(s, !s->explicit_document_required);
|
|
2266
|
-
return emit(l, valid, DOCUMENT_OPEN);
|
|
2267
|
-
}
|
|
2268
|
-
if (valid[UNEXPECTED_CONTENT_START] && s->document_content && !end) {
|
|
2269
|
-
s->document_content = false;
|
|
2270
|
-
return emit(l, valid, UNEXPECTED_CONTENT_START);
|
|
2477
|
+
if (
|
|
2478
|
+
valid[SEQUENCE_END] && (s->line_indent < s->indent || s->line_head != '-')
|
|
2479
|
+
)
|
|
2480
|
+
return emit(l, valid, SEQUENCE_END);
|
|
2271
2481
|
}
|
|
2272
2482
|
if (
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2483
|
+
s->line &&
|
|
2484
|
+
!s->line_prefixed &&
|
|
2485
|
+
valid[LINE_PREFIX_START] &&
|
|
2486
|
+
(blank(l->lookahead) ||
|
|
2487
|
+
(s->flow &&
|
|
2488
|
+
s->indent >=
|
|
2489
|
+
0 &&
|
|
2490
|
+
!newline(l->lookahead) &&
|
|
2491
|
+
!l->eof(l) &&
|
|
2492
|
+
l->lookahead != '#'))
|
|
2493
|
+
)
|
|
2494
|
+
return begin_line_prefix(s, l, valid);
|
|
2495
|
+
if (newline(l->lookahead) && valid[LINE_BREAK]) {
|
|
2496
|
+
reset_line(s);
|
|
2497
|
+
return line_break(l, valid, LINE_BREAK);
|
|
2279
2498
|
}
|
|
2280
|
-
if (
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
INCOMPLETE_FLOW_SEQUENCE_CLOSE,
|
|
2285
|
-
INCOMPLETE_FLOW_MAPPING_CLOSE,
|
|
2286
|
-
END_OF_FILE
|
|
2287
|
-
};
|
|
2288
|
-
return emit_closing(
|
|
2499
|
+
if (blank(l->lookahead) && valid[SEPARATION])
|
|
2500
|
+
return scan_separation(l, valid);
|
|
2501
|
+
if (l->lookahead == '#' && valid[COMMENT_START])
|
|
2502
|
+
return start_comment(
|
|
2289
2503
|
s,
|
|
2290
2504
|
l,
|
|
2291
2505
|
valid,
|
|
2292
|
-
|
|
2293
|
-
|
|
2506
|
+
NORMAL,
|
|
2507
|
+
!s->separated && l->get_column(l) != 0
|
|
2294
2508
|
);
|
|
2509
|
+
if (valid[DIRECTIVE_INDICATOR]) {
|
|
2510
|
+
s->mode = DIRECTIVE_NAME_BODY;
|
|
2511
|
+
s->first = true;
|
|
2512
|
+
return take(l, valid, DIRECTIVE_INDICATOR);
|
|
2295
2513
|
}
|
|
2296
|
-
if (valid[MAPPING_END] && column < s->indent)
|
|
2297
|
-
return emit(l, valid, MAPPING_END);
|
|
2298
|
-
if (
|
|
2299
|
-
valid[SEQUENCE_END] &&
|
|
2300
|
-
(column < s->indent || (s->line && l->lookahead != '-'))
|
|
2301
|
-
)
|
|
2302
|
-
return emit(l, valid, SEQUENCE_END);
|
|
2303
|
-
return scan_entry(s, l, valid, column);
|
|
2304
|
-
}
|
|
2305
|
-
|
|
2306
|
-
static bool
|
|
2307
|
-
scan_entry(Scanner *s, TSLexer *l, const bool *valid, int64_t column) {
|
|
2308
2514
|
if (
|
|
2309
2515
|
l->lookahead ==
|
|
2310
|
-
'
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2516
|
+
'%' &&
|
|
2517
|
+
l->get_column(l) ==
|
|
2518
|
+
0 &&
|
|
2519
|
+
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++;
|
|
2323
2529
|
step(l);
|
|
2324
|
-
indicator = colon_boundary(l, first == ':' && s->flow);
|
|
2325
|
-
}
|
|
2326
|
-
if (indicator) {
|
|
2327
|
-
if (valid[FLOW_SEQ_PAIR_START]) {
|
|
2328
|
-
s->json = false;
|
|
2329
|
-
return emit(l, valid, FLOW_SEQ_PAIR_START);
|
|
2330
|
-
}
|
|
2331
|
-
return emit_indicator(
|
|
2332
|
-
s,
|
|
2333
|
-
l,
|
|
2334
|
-
valid,
|
|
2335
|
-
first == '?' ? KEY_INDICATOR : VALUE_INDICATOR
|
|
2336
|
-
);
|
|
2337
2530
|
}
|
|
2338
|
-
s->
|
|
2339
|
-
|
|
2340
|
-
|
|
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
|
+
);
|
|
2341
2541
|
}
|
|
2342
|
-
if (
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2542
|
+
if (
|
|
2543
|
+
!s->document_started &&
|
|
2544
|
+
(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
|
+
);
|
|
2348
2556
|
}
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2557
|
+
return scan_properties(s, l, valid, property_pending);
|
|
2558
|
+
}
|
|
2559
|
+
|
|
2560
|
+
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);
|
|
2357
2570
|
}
|
|
2358
|
-
|
|
2571
|
+
if (!newline(l->lookahead))
|
|
2572
|
+
break;
|
|
2573
|
+
skip_line_break(l);
|
|
2574
|
+
context.line = true;
|
|
2359
2575
|
}
|
|
2360
|
-
|
|
2576
|
+
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;
|
|
2361
2582
|
step(l);
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
if (l->lookahead == '}' && valid[FLOW_MAPPING_CLOSE])
|
|
2373
|
-
return close_flow(s, l, valid, FLOW_MAPPING_CLOSE);
|
|
2374
|
-
if (l->lookahead == ']' && valid[MISSING_FLOW_MAPPING_CLOSE])
|
|
2375
|
-
return close_flow(s, l, valid, MISSING_FLOW_MAPPING_CLOSE);
|
|
2376
|
-
if (l->lookahead == '}' && valid[MISSING_FLOW_SEQUENCE_CLOSE])
|
|
2377
|
-
return close_flow(s, l, valid, MISSING_FLOW_SEQUENCE_CLOSE);
|
|
2378
|
-
if (
|
|
2379
|
-
valid[MISSING_FLOW_SEPARATOR] &&
|
|
2380
|
-
!valid[PLAIN_START] &&
|
|
2381
|
-
!valid[SINGLE_START] &&
|
|
2382
|
-
!valid[DOUBLE_START] &&
|
|
2383
|
-
!valid[FLOW_SEQUENCE_START] &&
|
|
2384
|
-
!valid[FLOW_MAPPING_START] &&
|
|
2385
|
-
!flow_entry_end(l->lookahead)
|
|
2386
|
-
)
|
|
2387
|
-
return emit(l, valid, MISSING_FLOW_SEPARATOR);
|
|
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
|
+
}
|
|
2590
|
+
enum Token content_end =
|
|
2591
|
+
valid[BLOCK_PROPERTIES_END] ? BLOCK_PROPERTIES_END : PROPERTIES_END;
|
|
2592
|
+
enum Token token = content_end;
|
|
2388
2593
|
if (
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
valid[PLAIN_START] ||
|
|
2394
|
-
valid[INDENT] ||
|
|
2395
|
-
valid[OUTDENT] ||
|
|
2396
|
-
valid[SINGLE_START] ||
|
|
2397
|
-
valid[DOUBLE_START] ||
|
|
2398
|
-
valid[FLOW_SEQUENCE_START] ||
|
|
2399
|
-
valid[FLOW_MAPPING_START] ||
|
|
2400
|
-
valid[LITERAL_START] ||
|
|
2401
|
-
valid[FOLDED_START] ||
|
|
2402
|
-
valid[PROPERTIES_START] ||
|
|
2403
|
-
valid[ALIAS_START]
|
|
2594
|
+
boundary ||
|
|
2595
|
+
end ||
|
|
2596
|
+
(s->flow && flow_entry_end(first)) ||
|
|
2597
|
+
!property_line_follows(&context)
|
|
2404
2598
|
) {
|
|
2405
|
-
|
|
2599
|
+
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 == '!') {
|
|
2609
|
+
token = PROPERTY_CONTINUE;
|
|
2610
|
+
if (context.line && !s->flow) {
|
|
2611
|
+
if (classify_block_node(l, NULL) == MAPPING_START)
|
|
2612
|
+
token = content_end;
|
|
2613
|
+
s->property_keys = l->eof(l) ? ANCHOR_KEY | TAG_KEY : 0;
|
|
2614
|
+
}
|
|
2406
2615
|
}
|
|
2407
|
-
|
|
2616
|
+
s->properties_ready = token == content_end;
|
|
2617
|
+
s->property_separation_notified = false;
|
|
2618
|
+
return emit(l, valid, token);
|
|
2408
2619
|
}
|
|
2409
2620
|
|
|
2410
2621
|
static bool scan(Scanner *s, TSLexer *l, const bool *valid) {
|
|
2411
2622
|
if (valid[ERROR_SENTINEL])
|
|
2412
2623
|
return false;
|
|
2413
2624
|
l->mark_end(l);
|
|
2625
|
+
if (s->mode == NORMAL && valid[EMPTY_PROPERTIES_END])
|
|
2626
|
+
return scan_property_tail(s, l, valid);
|
|
2414
2627
|
bool boundary_mode = s->mode ==
|
|
2415
2628
|
NORMAL ||
|
|
2416
2629
|
s->mode ==
|
|
@@ -2431,14 +2644,13 @@ static bool scan(Scanner *s, TSLexer *l, const bool *valid) {
|
|
|
2431
2644
|
enum Boundary boundary = line_boundary(s, l);
|
|
2432
2645
|
if (boundary || first == '-' || first == '.') {
|
|
2433
2646
|
s->boundary = (uint8_t)boundary;
|
|
2647
|
+
s->boundary_pending = l->eof(l)
|
|
2648
|
+
? first == '-' ? DOCUMENT_START_LINE : DOCUMENT_END_LINE
|
|
2649
|
+
: NO_BOUNDARY;
|
|
2434
2650
|
s->boundary_checked = true;
|
|
2435
2651
|
return emit(l, valid, BOUNDARY_CHECK);
|
|
2436
2652
|
}
|
|
2437
2653
|
}
|
|
2438
|
-
if (s->mode == NORMAL && s->boundary && valid[PROPERTIES_END]) {
|
|
2439
|
-
s->properties_ready = true;
|
|
2440
|
-
return emit(l, valid, PROPERTIES_END);
|
|
2441
|
-
}
|
|
2442
2654
|
if (s->boundary)
|
|
2443
2655
|
s->properties_ready = false;
|
|
2444
2656
|
bool property_pending = s->properties_ready &&
|
|
@@ -2534,6 +2746,9 @@ static bool layout_token(TSSymbol token) {
|
|
|
2534
2746
|
case LINE_PREFIX_END:
|
|
2535
2747
|
case INDENTATION:
|
|
2536
2748
|
case INVALID_INDENTATION:
|
|
2749
|
+
case TAB_IN_INDENTATION:
|
|
2750
|
+
case UNFINISHED_INVALID_INDENTATION:
|
|
2751
|
+
case UNFINISHED_TAB_IN_INDENTATION:
|
|
2537
2752
|
case BYTE_ORDER_MARK:
|
|
2538
2753
|
case LINE_CONTEXT:
|
|
2539
2754
|
case BOUNDARY_CHECK:
|
|
@@ -2545,6 +2760,7 @@ static bool layout_token(TSSymbol token) {
|
|
|
2545
2760
|
static void reset_scanner(Scanner *s) {
|
|
2546
2761
|
*s = (Scanner){
|
|
2547
2762
|
.indent = -1,
|
|
2763
|
+
.provisional_indent = -2,
|
|
2548
2764
|
.block_indent = -1,
|
|
2549
2765
|
.line = true,
|
|
2550
2766
|
.separated = true
|
|
@@ -2646,6 +2862,7 @@ bool tree_sitter_yaml_external_scanner_scan(
|
|
|
2646
2862
|
advance_keys(&next, cursor.marked_characters, cursor.marked_broken);
|
|
2647
2863
|
next.boundary = 0;
|
|
2648
2864
|
next.boundary_checked = false;
|
|
2865
|
+
next.boundary_pending = 0;
|
|
2649
2866
|
if (!layout_token(cursor.lexer.result_symbol))
|
|
2650
2867
|
next.line = false;
|
|
2651
2868
|
}
|