@konomanoasa/tree-sitter-yaml 0.1.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 ADDED
@@ -0,0 +1,2655 @@
1
+ #include "tree_sitter/alloc.h"
2
+ #include "tree_sitter/parser.h"
3
+ #include <stdint.h>
4
+ #include <string.h>
5
+
6
+ enum Token {
7
+ LINE_BREAK,
8
+ END_OF_FILE,
9
+ DOCUMENT_OPEN,
10
+ DOCUMENT_CLOSE,
11
+ DOCUMENT_START,
12
+ DOCUMENT_END,
13
+ BYTE_ORDER_MARK,
14
+ INDENT,
15
+ DEDENT,
16
+ OUTDENT,
17
+ RESTORE_INDENT,
18
+ MAPPING_START,
19
+ MAPPING_END,
20
+ PAIR_START,
21
+ SEQUENCE_START,
22
+ SEQUENCE_END,
23
+ ENTRY_START,
24
+ VALUE_START,
25
+ SEQUENCE_VALUE_START,
26
+ EMPTY_BLOCK_NODE,
27
+ EXPLICIT_VALUE_START,
28
+ INVALID_COMPACT_START,
29
+ SEQUENCE_INDICATOR,
30
+ VALUE_INDICATOR,
31
+ KEY_INDICATOR,
32
+ SINGLE_START,
33
+ DOUBLE_START,
34
+ FLOW_SEQUENCE_START,
35
+ FLOW_MAPPING_START,
36
+ FLOW_MAP_PAIR_START,
37
+ FLOW_SEQ_PAIR_START,
38
+ IMPLICIT_KEY_START,
39
+ KEY_END,
40
+ INVALID_KEY_END,
41
+ FLOW_NODE_END,
42
+ PLAIN_START,
43
+ PLAIN_END,
44
+ PLAIN_CONTINUE,
45
+ SCALAR_TEXT,
46
+ SINGLE_OPEN,
47
+ DOUBLE_OPEN,
48
+ QUOTE_CLOSE,
49
+ QUOTED_ESCAPE,
50
+ ESCAPED_QUOTE,
51
+ SCALAR_LINE_BREAK,
52
+ SCALAR_LINE_PREFIX,
53
+ SCALAR_LINE_SUFFIX,
54
+ ESCAPE_INDICATOR,
55
+ FLOW_SEQUENCE_OPEN,
56
+ FLOW_SEQUENCE_CLOSE,
57
+ FLOW_MAPPING_OPEN,
58
+ FLOW_MAPPING_CLOSE,
59
+ FLOW_SEPARATOR,
60
+ COMMENT_START,
61
+ COMMENT_MARKER,
62
+ COMMENT_TEXT,
63
+ COMMENT_END,
64
+ LINE_PREFIX_START,
65
+ LINE_PREFIX_END,
66
+ INDENTATION,
67
+ SEPARATION,
68
+ LINE_CONTEXT,
69
+ LITERAL_START,
70
+ FOLDED_START,
71
+ LITERAL_INDICATOR,
72
+ FOLDED_INDICATOR,
73
+ INDENTATION_INDICATOR,
74
+ CHOMPING_INDICATOR,
75
+ BLOCK_HEADER_BREAK,
76
+ BLOCK_HEADER_END,
77
+ BLOCK_BODY_START,
78
+ BLOCK_SCALAR_END,
79
+ BLOCK_TEXT_LINE_START,
80
+ BLOCK_SPACED_LINE_START,
81
+ BLOCK_EMPTY_LINE_START,
82
+ BLOCK_LINE_END,
83
+ BOUNDARY_CHECK,
84
+ DOCUMENT_CONTENT_END,
85
+ DOCUMENT_COMPACT_START,
86
+ UNEXPECTED_CONTENT_START,
87
+ PROPERTIES_START,
88
+ PROPERTIES_END,
89
+ PROPERTY_CONTENT_START,
90
+ BLOCK_PROPERTY_CONTENT_START,
91
+ BLOCK_KEY_CONTENT_START,
92
+ DUPLICATE_ANCHOR_START,
93
+ DUPLICATE_TAG_START,
94
+ PROPERTY_ALIAS_START,
95
+ PROPERTY_COMPACT_START,
96
+ ANCHOR_INDICATOR,
97
+ ALIAS_START,
98
+ ALIAS_INDICATOR,
99
+ ANCHOR_NAME,
100
+ ALIAS_NAME,
101
+ NAME_END,
102
+ VERBATIM_TAG_START,
103
+ VERBATIM_TAG_OPEN,
104
+ VERBATIM_TAG_CLOSE,
105
+ SHORTHAND_TAG_START,
106
+ NON_SPECIFIC_TAG,
107
+ TAG_HANDLE_START,
108
+ PRIMARY_TAG_HANDLE,
109
+ SECONDARY_TAG_HANDLE,
110
+ TAG_HANDLE_OPEN,
111
+ TAG_HANDLE_NAME,
112
+ TAG_HANDLE_CLOSE,
113
+ TAG_SUFFIX_START,
114
+ TAG_END,
115
+ TAG_URI_START,
116
+ TAG_URI_END,
117
+ URI_TEXT,
118
+ TAG_SUFFIX_TEXT,
119
+ URI_ESCAPE,
120
+ YAML_DIRECTIVE_START,
121
+ TAG_DIRECTIVE_START,
122
+ RESERVED_DIRECTIVE_START,
123
+ DIRECTIVE_INDICATOR,
124
+ DIRECTIVE_NAME,
125
+ DIRECTIVE_NAME_END,
126
+ DIRECTIVE_END,
127
+ YAML_VERSION,
128
+ TAG_PREFIX_START,
129
+ TAG_PREFIX_END,
130
+ DIRECTIVE_PARAMETER,
131
+ INVALID_ENCODING,
132
+ INVALID_CHARACTER,
133
+ INVALID_ESCAPE,
134
+ INCOMPLETE_ESCAPE,
135
+ INVALID_LINE_CONTINUATION,
136
+ INVALID_SCALAR_START,
137
+ MISSING_FLOW_SEPARATOR,
138
+ UNEXPECTED_FLOW_SEPARATOR,
139
+ INVALID_INDENTATION,
140
+ MISSING_INDENTATION,
141
+ MISSING_SEPARATION,
142
+ INVALID_BLOCK_HEADER,
143
+ INVALID_TAG_HANDLE,
144
+ INVALID_TAG_CHARACTER,
145
+ INVALID_URI_ESCAPE,
146
+ INCOMPLETE_URI_ESCAPE,
147
+ INVALID_YAML_VERSION,
148
+ UNFINISHED_YAML_VERSION,
149
+ UNEXPECTED_DIRECTIVE_PARAMETER,
150
+ UNEXPECTED_DOCUMENT_END_CONTENT,
151
+ INVALID_HEADER_INDENTATION,
152
+ INVALID_HEADER_CHOMPING,
153
+ MISSING_DOCUMENT_END,
154
+ MISSING_QUOTE_CLOSE,
155
+ INCOMPLETE_QUOTE_CLOSE,
156
+ MISSING_FLOW_SEQUENCE_CLOSE,
157
+ INCOMPLETE_FLOW_SEQUENCE_CLOSE,
158
+ MISSING_FLOW_MAPPING_CLOSE,
159
+ INCOMPLETE_FLOW_MAPPING_CLOSE,
160
+ MISSING_VALUE_INDICATOR,
161
+ INCOMPLETE_VALUE_INDICATOR,
162
+ MISSING_ANCHOR_NAME,
163
+ INCOMPLETE_ANCHOR_NAME,
164
+ MISSING_ALIAS_NAME,
165
+ INCOMPLETE_ALIAS_NAME,
166
+ MISSING_TAG_URI,
167
+ INCOMPLETE_TAG_URI,
168
+ MISSING_TAG_SUFFIX,
169
+ INCOMPLETE_TAG_SUFFIX,
170
+ MISSING_VERBATIM_TAG_CLOSE,
171
+ INCOMPLETE_VERBATIM_TAG_CLOSE,
172
+ MISSING_DIRECTIVE_NAME,
173
+ INCOMPLETE_DIRECTIVE_NAME,
174
+ MISSING_YAML_VERSION,
175
+ INCOMPLETE_YAML_VERSION,
176
+ MISSING_TAG_HANDLE,
177
+ INCOMPLETE_TAG_HANDLE,
178
+ MISSING_TAG_HANDLE_CLOSE,
179
+ INCOMPLETE_TAG_HANDLE_CLOSE,
180
+ MISSING_TAG_PREFIX,
181
+ INCOMPLETE_TAG_PREFIX,
182
+ MISSING_DOCUMENT_START,
183
+ INCOMPLETE_DOCUMENT_START,
184
+ ERROR_SENTINEL
185
+ };
186
+
187
+ enum Mode {
188
+ NORMAL,
189
+ PLAIN,
190
+ SINGLE,
191
+ DOUBLE,
192
+ COMMENT,
193
+ PREFIX,
194
+ COMPACT_PREFIX,
195
+ COMMENT_BEGIN,
196
+ BLOCK_HEADER,
197
+ BLOCK_HEADER_DONE,
198
+ BLOCK_DETECT,
199
+ BLOCK_BODY,
200
+ BLOCK_LINE,
201
+ BLOCK_LINE_DONE,
202
+ ANCHOR_BODY,
203
+ ALIAS_BODY,
204
+ HANDLE_SELECT,
205
+ HANDLE_BODY,
206
+ SUFFIX_BEGIN,
207
+ SUFFIX_BODY,
208
+ URI_BEGIN,
209
+ URI_BODY,
210
+ VERBATIM_CLOSE,
211
+ PREFIX_BODY,
212
+ DIRECTIVE_NAME_BODY,
213
+ DIRECTIVE_VERSION,
214
+ DIRECTIVE_HANDLE,
215
+ DIRECTIVE_PREFIX,
216
+ DIRECTIVE_PARAMETERS
217
+ };
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
+ enum HandleForm { PRIMARY_HANDLE = 1, SECONDARY_HANDLE, NAMED_HANDLE };
229
+ enum DirectiveKind { YAML_DIRECTIVE = 1, TAG_DIRECTIVE, RESERVED_DIRECTIVE };
230
+ /* Line starts that end the open constructs of a document. */
231
+ enum Boundary {
232
+ NO_BOUNDARY,
233
+ DOCUMENT_START_LINE,
234
+ DOCUMENT_END_LINE,
235
+ DIRECTIVE_LINE,
236
+ STREAM_BOM
237
+ };
238
+ #define SCANNER_FIELDS(F) \
239
+ F(int64_t, indent, 8, 1) \
240
+ F(uint32_t, flow, 4, 0) \
241
+ F(uint8_t, mode, 1, 0) \
242
+ F(bool, line, 1, 0) \
243
+ F(bool, document, 1, 0) \
244
+ F(uint32_t, column, 4, 0) \
245
+ F(bool, prefix, 1, 0) \
246
+ F(bool, first, 1, 0) \
247
+ F(bool, json, 1, 0) \
248
+ F(bool, continuation, 1, 0) \
249
+ F(bool, quote_line_empty, 1, 0) \
250
+ F(uint32_t, line_indent, 4, 0) \
251
+ F(bool, tab_invalid, 1, 0) \
252
+ F(bool, prefix_tab, 1, 0) \
253
+ F(bool, indent_checked, 1, 0) \
254
+ F(bool, line_prefixed, 1, 0) \
255
+ F(bool, scalar_indent, 1, 0) \
256
+ F(int32_t, line_head, 4, 0) \
257
+ F(bool, line_context, 1, 0) \
258
+ F(bool, layout_only, 1, 0) \
259
+ F(bool, line_mapping_key, 1, 0) \
260
+ F(bool, prefix_invalid, 1, 0) \
261
+ F(bool, separated, 1, 0) \
262
+ F(bool, key_done, 1, 0) \
263
+ F(int64_t, block_indent, 8, 1) \
264
+ F(uint8_t, header_flags, 1, 0) \
265
+ F(uint8_t, return_mode, 1, 0) \
266
+ F(bool, block_leading, 1, 0) \
267
+ F(bool, block_empty, 1, 0) \
268
+ F(bool, block_prefix, 1, 0) \
269
+ F(uint8_t, boundary, 1, 0) \
270
+ F(bool, boundary_checked, 1, 0) \
271
+ F(bool, document_started, 1, 0) \
272
+ F(bool, document_content, 1, 0) \
273
+ F(bool, after_document_end, 1, 0) \
274
+ F(bool, block_out, 1, 0) \
275
+ F(uint8_t, property_flags, 1, 0) \
276
+ F(uint8_t, handle_form, 1, 0) \
277
+ F(bool, properties_ready, 1, 0) \
278
+ F(bool, duplicate_pending, 1, 0) \
279
+ F(bool, property_separation_notified, 1, 0) \
280
+ F(uint8_t, directive_kind, 1, 0) \
281
+ F(bool, directive_handle, 1, 0) \
282
+ F(bool, value_separation, 1, 0) \
283
+ F(uint32_t, scalar_spaces, 4, 0) \
284
+ F(bool, scalar_tab, 1, 0) \
285
+ F(bool, explicit_document_required, 1, 0) \
286
+ F(uint8_t, block_kind, 1, 0)
287
+
288
+ #define FIELD_BYTES(type, name, width, bias) +width
289
+ enum {
290
+ IMPLICIT_KEY_LIMIT = 1024,
291
+ IMPLICIT_KEY_WORDS = IMPLICIT_KEY_LIMIT / 64 + 1,
292
+ SCANNER_STATE_BYTES = 0 SCANNER_FIELDS(FIELD_BYTES),
293
+ SCANNER_KEY_BYTES = IMPLICIT_KEY_LIMIT / 8 + 1
294
+ };
295
+ #undef FIELD_BYTES
296
+
297
+ #define DECLARE_FIELD(type, name, width, bias) type name;
298
+ typedef struct {
299
+ SCANNER_FIELDS(DECLARE_FIELD)
300
+ uint64_t implicit_keys[IMPLICIT_KEY_WORDS];
301
+ } Scanner;
302
+ #undef DECLARE_FIELD
303
+
304
+ typedef struct {
305
+ TSLexer lexer;
306
+ TSLexer *source;
307
+ uint32_t column, marked_column;
308
+ uint64_t characters;
309
+ uint64_t marked_characters;
310
+ bool broken, marked_broken;
311
+ bool separated, marked_separation;
312
+ } Cursor;
313
+
314
+ static bool blank(int32_t c) {
315
+ return c == ' ' || c == '\t';
316
+ }
317
+ static bool newline(int32_t c) {
318
+ return c == '\n' || c == '\r';
319
+ }
320
+ static bool space(int32_t c) {
321
+ return blank(c) || newline(c);
322
+ }
323
+ static bool flow_indicator(int32_t c) {
324
+ return c == ',' || c == '[' || c == ']' || c == '{' || c == '}';
325
+ }
326
+ static bool flow_entry_end(int32_t c) {
327
+ return c == ',' || c == ']' || c == '}';
328
+ }
329
+ static bool colon_boundary(TSLexer *l, bool flow) {
330
+ return l->eof(l) ||
331
+ space(l->lookahead) ||
332
+ (flow && flow_indicator(l->lookahead));
333
+ }
334
+ static bool invalid_encoding(int32_t c) {
335
+ return c < 0 || c > 0x10ffff || (c >= 0xd800 && c <= 0xdfff);
336
+ }
337
+ static bool invalid_quoted(int32_t c) {
338
+ return invalid_encoding(c) ||
339
+ (c < 0x20 && c != '\t' && c != '\n' && c != '\r');
340
+ }
341
+ static bool invalid_unquoted(int32_t c) {
342
+ return invalid_quoted(c) ||
343
+ (c >= 0x7f && c <= 0x9f && c != 0x85) ||
344
+ c ==
345
+ 0xfeff ||
346
+ c ==
347
+ 0xfffe ||
348
+ c == 0xffff;
349
+ }
350
+
351
+ static bool
352
+ block_value_follows(const Scanner *s, const TSLexer *l, const bool *valid) {
353
+ if (l->eof(l))
354
+ return false;
355
+ if (
356
+ valid[EXPLICIT_VALUE_START] &&
357
+ s->line &&
358
+ s->line_indent ==
359
+ s->indent &&
360
+ s->line_head == ':'
361
+ )
362
+ return true;
363
+ return (valid[VALUE_START] || valid[SEQUENCE_VALUE_START]) &&
364
+ (!s->line ||
365
+ s->line_indent >
366
+ s->indent ||
367
+ (valid[VALUE_START] &&
368
+ s->line_indent ==
369
+ s->indent &&
370
+ s->line_head == '-'));
371
+ }
372
+
373
+ static bool property_line_follows(const Scanner *s) {
374
+ return s->flow ||
375
+ !s->line ||
376
+ s->line_indent >
377
+ s->indent ||
378
+ (s->block_out && s->line_indent == s->indent && s->line_head == '-');
379
+ }
380
+
381
+ static void cursor_advance(TSLexer *lexer, bool skip) {
382
+ Cursor *cursor = (Cursor *)lexer;
383
+ cursor->characters++;
384
+ cursor->separated = space(lexer->lookahead);
385
+ cursor->broken |= newline(lexer->lookahead);
386
+ cursor->column = newline(lexer->lookahead) ? 0 : cursor->column + 1;
387
+ cursor->source->advance(cursor->source, skip);
388
+ lexer->lookahead = cursor->source->lookahead;
389
+ }
390
+ static void cursor_mark(TSLexer *lexer) {
391
+ Cursor *cursor = (Cursor *)lexer;
392
+ cursor->marked_column = cursor->column;
393
+ cursor->marked_characters = cursor->characters;
394
+ cursor->marked_broken = cursor->broken;
395
+ cursor->marked_separation = cursor->separated;
396
+ cursor->source->mark_end(cursor->source);
397
+ }
398
+ static uint32_t cursor_column(TSLexer *lexer) {
399
+ return ((Cursor *)lexer)->column;
400
+ }
401
+ static bool cursor_eof(const TSLexer *lexer) {
402
+ const Cursor *cursor = (const Cursor *)lexer;
403
+ return cursor->source->eof(cursor->source);
404
+ }
405
+ static uint64_t cursor_characters(const TSLexer *lexer) {
406
+ return ((const Cursor *)lexer)->characters;
407
+ }
408
+ static bool cursor_broken(const TSLexer *lexer) {
409
+ return ((const Cursor *)lexer)->broken;
410
+ }
411
+ static void cursor_start_line(TSLexer *lexer) {
412
+ ((Cursor *)lexer)->column = 0;
413
+ }
414
+
415
+ static bool emit(TSLexer *l, const bool *valid, enum Token token) {
416
+ if (!valid[token])
417
+ return false;
418
+ l->result_symbol = token;
419
+ return true;
420
+ }
421
+ static void step(TSLexer *l) {
422
+ l->advance(l, false);
423
+ }
424
+ static bool finish(TSLexer *l, const bool *valid, enum Token token) {
425
+ l->mark_end(l);
426
+ return emit(l, valid, token);
427
+ }
428
+ static uint32_t count_spaces(TSLexer *l) {
429
+ uint32_t spaces = 0;
430
+ while (l->lookahead == ' ') {
431
+ step(l);
432
+ spaces++;
433
+ }
434
+ return spaces;
435
+ }
436
+ static void skip_blanks(TSLexer *l) {
437
+ while (blank(l->lookahead))
438
+ step(l);
439
+ }
440
+ static bool take(TSLexer *l, const bool *valid, enum Token token) {
441
+ if (!valid[token])
442
+ return false;
443
+ step(l);
444
+ return finish(l, valid, token);
445
+ }
446
+ static bool emit_missing(
447
+ TSLexer *l,
448
+ const bool *valid,
449
+ enum Token missing,
450
+ enum Token incomplete
451
+ ) {
452
+ return emit(l, valid, l->eof(l) ? incomplete : missing);
453
+ }
454
+ static bool scan_separation(TSLexer *l, const bool *valid) {
455
+ step(l);
456
+ skip_blanks(l);
457
+ return finish(l, valid, SEPARATION);
458
+ }
459
+ static bool
460
+ close_flow(Scanner *s, TSLexer *l, const bool *valid, enum Token token) {
461
+ bool closed = token == FLOW_SEQUENCE_CLOSE || token == FLOW_MAPPING_CLOSE
462
+ ? take(l, valid, token)
463
+ : emit(l, valid, token);
464
+ if (closed) {
465
+ s->flow--;
466
+ s->json = true;
467
+ /* A mismatched closer ends the collection mid-line without consuming
468
+ * source, so the rest of the line is content rather than layout. */
469
+ s->line = false;
470
+ }
471
+ return closed;
472
+ }
473
+ static bool emit_closing(
474
+ Scanner *s,
475
+ TSLexer *l,
476
+ const bool *valid,
477
+ const enum Token *closings,
478
+ size_t count
479
+ ) {
480
+ for (size_t i = 0; i < count; i++) {
481
+ enum Token token = closings[i];
482
+ if (!valid[token])
483
+ continue;
484
+ switch (token) {
485
+ case MISSING_FLOW_SEQUENCE_CLOSE:
486
+ case MISSING_FLOW_MAPPING_CLOSE:
487
+ case INCOMPLETE_FLOW_SEQUENCE_CLOSE:
488
+ case INCOMPLETE_FLOW_MAPPING_CLOSE:
489
+ return close_flow(s, l, valid, token);
490
+ case DEDENT:
491
+ case OUTDENT:
492
+ s->indent--;
493
+ break;
494
+ case RESTORE_INDENT:
495
+ case INDENT:
496
+ s->indent++;
497
+ break;
498
+ default:
499
+ break;
500
+ }
501
+ return emit(l, valid, token);
502
+ }
503
+ return false;
504
+ }
505
+ static bool start_plain(Scanner *s, TSLexer *l, const bool *valid) {
506
+ if (!valid[PLAIN_START])
507
+ return false;
508
+ s->mode = PLAIN;
509
+ s->first = true;
510
+ s->json = false;
511
+ return emit(l, valid, PLAIN_START);
512
+ }
513
+ static bool scan_invalid_character(TSLexer *l, const bool *valid) {
514
+ if (l->eof(l) || !invalid_unquoted(l->lookahead))
515
+ return false;
516
+ return take(
517
+ l,
518
+ valid,
519
+ invalid_encoding(l->lookahead) ? INVALID_ENCODING : INVALID_CHARACTER
520
+ );
521
+ }
522
+
523
+ static bool scan_line_text(TSLexer *l, const bool *valid, enum Token token) {
524
+ if (scan_invalid_character(l, valid))
525
+ return true;
526
+ do {
527
+ step(l);
528
+ } while (
529
+ !l->eof(l) && !newline(l->lookahead) && !invalid_unquoted(l->lookahead)
530
+ );
531
+ return finish(l, valid, token);
532
+ }
533
+
534
+ static enum Boundary document_marker(TSLexer *l) {
535
+ if (l->get_column(l) != 0 || (l->lookahead != '-' && l->lookahead != '.'))
536
+ return NO_BOUNDARY;
537
+ int32_t marker = l->lookahead;
538
+ for (unsigned i = 0; i < 3; i++) {
539
+ if (l->lookahead != marker)
540
+ return NO_BOUNDARY;
541
+ step(l);
542
+ }
543
+ if (!space(l->lookahead) && !l->eof(l))
544
+ return NO_BOUNDARY;
545
+ return marker == '-' ? DOCUMENT_START_LINE : DOCUMENT_END_LINE;
546
+ }
547
+ /* Outside flow collections and scalars, a directive indicator or a BOM at
548
+ * the start of a line also ends the open constructs of the document. */
549
+ static enum Boundary line_boundary(const Scanner *s, TSLexer *l) {
550
+ if (l->lookahead == '-' || l->lookahead == '.')
551
+ return document_marker(l);
552
+ if (s->flow || (s->mode != NORMAL && s->mode != BLOCK_BODY))
553
+ return NO_BOUNDARY;
554
+ if (l->lookahead == '%')
555
+ return s->mode == NORMAL ? DIRECTIVE_LINE : NO_BOUNDARY;
556
+ return l->lookahead == 0xfeff ? STREAM_BOM : NO_BOUNDARY;
557
+ }
558
+
559
+ static enum Token node_start(int32_t c) {
560
+ switch (c) {
561
+ case '[':
562
+ return FLOW_SEQUENCE_START;
563
+ case '{':
564
+ return FLOW_MAPPING_START;
565
+ case '\'':
566
+ return SINGLE_START;
567
+ case '"':
568
+ return DOUBLE_START;
569
+ case '&':
570
+ case '!':
571
+ return PROPERTIES_START;
572
+ case '*':
573
+ return ALIAS_START;
574
+ default:
575
+ return PLAIN_START;
576
+ }
577
+ }
578
+ static bool name_boundary(TSLexer *l) {
579
+ return l->eof(l) || space(l->lookahead) || flow_indicator(l->lookahead);
580
+ }
581
+ static bool block_collection(enum Token kind) {
582
+ return kind == MAPPING_START || kind == SEQUENCE_START;
583
+ }
584
+
585
+ /* Only starts within the same line's last 1024 characters can remain valid. */
586
+ static void advance_keys(Scanner *s, uint64_t characters, bool broken) {
587
+ if (broken || characters > IMPLICIT_KEY_LIMIT) {
588
+ memset(s->implicit_keys, 0, sizeof(s->implicit_keys));
589
+ return;
590
+ }
591
+ unsigned words = (unsigned)(characters / 64);
592
+ unsigned bits = (unsigned)(characters % 64);
593
+ for (unsigned i = IMPLICIT_KEY_WORDS; i-- > 0;) {
594
+ uint64_t value = i >= words ? s->implicit_keys[i - words] << bits : 0;
595
+ if (bits && i > words)
596
+ value |= s->implicit_keys[i - words - 1] >> (64 - bits);
597
+ s->implicit_keys[i] = value;
598
+ }
599
+ s->implicit_keys[IMPLICIT_KEY_WORDS - 1] &= 1;
600
+ }
601
+ static unsigned end_key(Scanner *s) {
602
+ for (unsigned i = 0; i < IMPLICIT_KEY_WORDS; i++) {
603
+ uint64_t word = s->implicit_keys[i];
604
+ if (word) {
605
+ s->implicit_keys[i] &= word - 1;
606
+ unsigned age = i * 64;
607
+ while (!(word & 1)) {
608
+ word >>= 1;
609
+ age++;
610
+ }
611
+ return age;
612
+ }
613
+ }
614
+ return IMPLICIT_KEY_LIMIT + 1;
615
+ }
616
+
617
+ /* Flow entries and values are optional, so the parser reduces a flow node only
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
+ */
622
+ static void skip_layout(TSLexer *l) {
623
+ for (;;) {
624
+ while (space(l->lookahead))
625
+ step(l);
626
+ if (l->lookahead != '#')
627
+ return;
628
+ while (!l->eof(l) && !newline(l->lookahead))
629
+ step(l);
630
+ }
631
+ }
632
+ static bool scan_key_end(Scanner *s, TSLexer *l, const bool *valid) {
633
+ if (!s->line && blank(l->lookahead))
634
+ return scan_separation(l, valid);
635
+ unsigned age = end_key(s);
636
+ if (s->flow)
637
+ skip_layout(l);
638
+ bool key_invalid =
639
+ cursor_broken(l) || age + cursor_characters(l) > IMPLICIT_KEY_LIMIT;
640
+ if (valid[FLOW_NODE_END]) {
641
+ bool colon = l->lookahead == ':';
642
+ if (colon) {
643
+ step(l);
644
+ colon = s->json || colon_boundary(l, true);
645
+ }
646
+ if (!colon)
647
+ return emit(l, valid, FLOW_NODE_END);
648
+ }
649
+ s->key_done = true;
650
+ return emit(l, valid, key_invalid ? INVALID_KEY_END : KEY_END);
651
+ }
652
+
653
+ static void skip_property_or_alias(TSLexer *l) {
654
+ bool tag = l->lookahead == '!';
655
+ step(l);
656
+ if (tag && l->lookahead == '<') {
657
+ step(l);
658
+ while (!l->eof(l) && !space(l->lookahead) && l->lookahead != '>')
659
+ step(l);
660
+ if (l->lookahead == '>')
661
+ step(l);
662
+ } else {
663
+ while (!name_boundary(l))
664
+ step(l);
665
+ }
666
+ }
667
+
668
+ static enum Token classify_block_node(TSLexer *l) {
669
+ bool properties = l->lookahead == '&' || l->lookahead == '!';
670
+ while (l->lookahead == '&' || l->lookahead == '!') {
671
+ skip_property_or_alias(l);
672
+ skip_blanks(l);
673
+ if (l->eof(l) || newline(l->lookahead) || l->lookahead == '#')
674
+ return PROPERTIES_START;
675
+ }
676
+ int32_t first = l->lookahead;
677
+ if (first == '|' || first == '>')
678
+ return properties ? PROPERTIES_START
679
+ : first == '|' ? LITERAL_START
680
+ : FOLDED_START;
681
+ enum Token content = node_start(first);
682
+ enum Token fallback = properties ? PROPERTIES_START : content;
683
+ bool structured = content ==
684
+ SINGLE_START ||
685
+ content ==
686
+ DOUBLE_START ||
687
+ content ==
688
+ FLOW_SEQUENCE_START ||
689
+ content == FLOW_MAPPING_START;
690
+ if (first == '*') {
691
+ skip_property_or_alias(l);
692
+ }
693
+ if (first == '-' || first == '?') {
694
+ step(l);
695
+ if (space(l->lookahead) || l->eof(l))
696
+ return properties ? PROPERTIES_START
697
+ : first == '-' ? SEQUENCE_START
698
+ : MAPPING_START;
699
+ }
700
+ int32_t quote = 0;
701
+ char initial_closings[32];
702
+ char *closings = initial_closings;
703
+ size_t flow = 0, capacity = sizeof(initial_closings);
704
+ bool separated = false;
705
+ bool complete = content == ALIAS_START;
706
+ bool plain = content == PLAIN_START;
707
+ bool adjacent = false;
708
+ while (!l->eof(l)) {
709
+ if (
710
+ l->get_column(l) ==
711
+ 0 &&
712
+ cursor_characters(l) &&
713
+ (l->lookahead == '-' || l->lookahead == '.')
714
+ ) {
715
+ if (document_marker(l) || l->eof(l))
716
+ break;
717
+ if (!quote)
718
+ plain = true;
719
+ }
720
+ int32_t c = l->lookahead;
721
+ if (!quote && !flow) {
722
+ if (complete && !space(c) && c != ':')
723
+ break;
724
+ if (newline(c) || (c == '#' && separated))
725
+ break;
726
+ }
727
+ if (quote) {
728
+ if (c == '\\' && quote == '"') {
729
+ step(l);
730
+ if (l->eof(l))
731
+ break;
732
+ } else if (c == quote) {
733
+ if (quote == '\'') {
734
+ step(l);
735
+ if (l->lookahead == '\'') {
736
+ step(l);
737
+ continue;
738
+ }
739
+ }
740
+ quote = 0;
741
+ adjacent = true;
742
+ if (!flow)
743
+ complete = true;
744
+ separated = false;
745
+ if (c == '\'')
746
+ continue;
747
+ }
748
+ } else if (structured && !plain && (c == '\'' || c == '"'))
749
+ quote = c;
750
+ else if (flow && !plain && (c == '&' || c == '*' || c == '!')) {
751
+ skip_property_or_alias(l);
752
+ adjacent = false;
753
+ separated = false;
754
+ continue;
755
+ } else if (flow && c == '#' && (separated || !plain)) {
756
+ while (!l->eof(l) && !newline(l->lookahead))
757
+ step(l);
758
+ plain = false;
759
+ separated = true;
760
+ continue;
761
+ } else if (structured && (c == '[' || c == '{')) {
762
+ if (flow == capacity) {
763
+ capacity *= 2;
764
+ char *expanded = ts_calloc(capacity, sizeof(*expanded));
765
+ memcpy(expanded, closings, flow);
766
+ if (closings != initial_closings)
767
+ ts_free(closings);
768
+ closings = expanded;
769
+ }
770
+ closings[flow++] = c == '[' ? ']' : '}';
771
+ plain = false;
772
+ adjacent = false;
773
+ } else if ((c == ']' || c == '}') && flow) {
774
+ while (flow && closings[flow - 1] != c)
775
+ flow--;
776
+ if (!flow)
777
+ break;
778
+ flow--;
779
+ plain = false;
780
+ adjacent = true;
781
+ if (!flow)
782
+ complete = true;
783
+ } else if (flow && c == ',') {
784
+ plain = false;
785
+ adjacent = false;
786
+ } else if (c == ':') {
787
+ step(l);
788
+ bool indicator = colon_boundary(l, flow);
789
+ if (!flow && indicator) {
790
+ fallback = MAPPING_START;
791
+ break;
792
+ }
793
+ if (!flow && complete)
794
+ break;
795
+ plain = !indicator && !adjacent;
796
+ adjacent = false;
797
+ separated = false;
798
+ continue;
799
+ } else if (flow && !plain && c == '?') {
800
+ step(l);
801
+ plain = !space(l->lookahead) && !l->eof(l);
802
+ adjacent = false;
803
+ separated = false;
804
+ continue;
805
+ } else if (!space(c)) {
806
+ plain = true;
807
+ adjacent = false;
808
+ }
809
+ separated = space(c);
810
+ step(l);
811
+ }
812
+ if (closings != initial_closings)
813
+ ts_free(closings);
814
+ return fallback;
815
+ }
816
+
817
+ static enum Token classify_block_start(Scanner *s, TSLexer *l) {
818
+ if (!s->block_kind)
819
+ s->block_kind = (uint8_t)(classify_block_node(l) + 1);
820
+ return (enum Token)(s->block_kind - 1);
821
+ }
822
+
823
+ static enum Token
824
+ property_content_start(Scanner *s, TSLexer *l, const bool *valid) {
825
+ if (l->lookahead == '*' && !(s->line && s->line_mapping_key))
826
+ return PROPERTY_ALIAS_START;
827
+ if (!s->flow) {
828
+ enum Token kind = classify_block_start(s, l);
829
+ if (
830
+ s->line &&
831
+ valid[BLOCK_KEY_CONTENT_START] &&
832
+ (block_collection(kind) || kind == LITERAL_START || kind == FOLDED_START)
833
+ )
834
+ return BLOCK_KEY_CONTENT_START;
835
+ if (
836
+ !s->line &&
837
+ valid[PROPERTY_COMPACT_START] &&
838
+ (kind ==
839
+ SEQUENCE_START ||
840
+ (kind == MAPPING_START && valid[BLOCK_PROPERTY_CONTENT_START]))
841
+ )
842
+ return PROPERTY_COMPACT_START;
843
+ }
844
+ return valid[BLOCK_PROPERTY_CONTENT_START] ? BLOCK_PROPERTY_CONTENT_START
845
+ : PROPERTY_CONTENT_START;
846
+ }
847
+
848
+ static bool
849
+ emit_indicator(Scanner *s, TSLexer *l, const bool *valid, enum Token token) {
850
+ l->mark_end(l);
851
+ if (!s->flow && blank(l->lookahead)) {
852
+ skip_blanks(l);
853
+ if (!l->eof(l) && !newline(l->lookahead) && l->lookahead != '#') {
854
+ enum Token kind = classify_block_node(l);
855
+ if (block_collection(kind))
856
+ s->mode = COMPACT_PREFIX;
857
+ }
858
+ }
859
+ return emit(l, valid, token);
860
+ }
861
+
862
+ static void skip_line_break(TSLexer *l) {
863
+ int32_t first = l->lookahead;
864
+ step(l);
865
+ if (first == '\r' && l->lookahead == '\n')
866
+ step(l);
867
+ }
868
+ static bool line_break(TSLexer *l, const bool *valid, enum Token token) {
869
+ skip_line_break(l);
870
+ return finish(l, valid, token);
871
+ }
872
+ static unsigned hex_value(int32_t c) {
873
+ if (c >= '0' && c <= '9')
874
+ return (unsigned)(c - '0');
875
+ if (c >= 'a' && c <= 'f')
876
+ return (unsigned)(c - 'a' + 10);
877
+ if (c >= 'A' && c <= 'F')
878
+ return (unsigned)(c - 'A' + 10);
879
+ return 16;
880
+ }
881
+ static unsigned hex_digits(TSLexer *l, unsigned remaining, uint32_t *value) {
882
+ *value = 0;
883
+ while (remaining && !l->eof(l)) {
884
+ unsigned digit = hex_value(l->lookahead);
885
+ if (digit == 16)
886
+ break;
887
+ *value = (*value << 4) | digit;
888
+ step(l);
889
+ l->mark_end(l);
890
+ remaining--;
891
+ }
892
+ return remaining;
893
+ }
894
+
895
+ static bool word_char(int32_t c) {
896
+ return (c >= 'a' && c <= 'z') ||
897
+ (c >= 'A' && c <= 'Z') ||
898
+ (c >= '0' && c <= '9') ||
899
+ c == '-';
900
+ }
901
+ static bool uri_char(int32_t c, bool suffix) {
902
+ return word_char(c) ||
903
+ (c >
904
+ 0 &&
905
+ c <
906
+ 128 &&
907
+ strchr("#;/?:@&=+$,_.!~*'()[]", (int)c) &&
908
+ (!suffix || (c != '!' && !flow_indicator(c))));
909
+ }
910
+ static void finish_tag(Scanner *s) {
911
+ s->mode = NORMAL;
912
+ s->property_flags |= PROPERTY_TAG;
913
+ }
914
+ static bool scan_name(Scanner *s, TSLexer *l, const bool *valid) {
915
+ bool anchor = s->mode == ANCHOR_BODY;
916
+ if (name_boundary(l)) {
917
+ if (s->first) {
918
+ s->first = false;
919
+ return anchor
920
+ ? emit_missing(l, valid, MISSING_ANCHOR_NAME, INCOMPLETE_ANCHOR_NAME)
921
+ : emit_missing(l, valid, MISSING_ALIAS_NAME, INCOMPLETE_ALIAS_NAME);
922
+ }
923
+ s->mode = NORMAL;
924
+ if (anchor)
925
+ s->property_flags |= PROPERTY_ANCHOR;
926
+ return emit(l, valid, NAME_END);
927
+ }
928
+ s->first = false;
929
+ if (scan_invalid_character(l, valid))
930
+ return true;
931
+ do {
932
+ step(l);
933
+ } while (!name_boundary(l) && !invalid_unquoted(l->lookahead));
934
+ return finish(l, valid, anchor ? ANCHOR_NAME : ALIAS_NAME);
935
+ }
936
+
937
+ /* The starting lookahead has already selected the tag handle form. */
938
+ static bool scan_handle(Scanner *s, TSLexer *l, const bool *valid) {
939
+ if (s->mode == HANDLE_SELECT) {
940
+ step(l);
941
+ enum Token token = s->handle_form == PRIMARY_HANDLE ? PRIMARY_TAG_HANDLE
942
+ : s->handle_form == SECONDARY_HANDLE ? SECONDARY_TAG_HANDLE
943
+ : TAG_HANDLE_OPEN;
944
+ if (s->handle_form == SECONDARY_HANDLE)
945
+ step(l);
946
+ l->mark_end(l);
947
+ s->mode = s->handle_form == NAMED_HANDLE ? HANDLE_BODY
948
+ : s->directive_handle ? DIRECTIVE_PREFIX
949
+ : SUFFIX_BEGIN;
950
+ return emit(l, valid, token);
951
+ }
952
+ if (s->directive_handle && (l->eof(l) || space(l->lookahead))) {
953
+ s->mode = DIRECTIVE_PREFIX;
954
+ return emit_missing(
955
+ l,
956
+ valid,
957
+ MISSING_TAG_HANDLE_CLOSE,
958
+ INCOMPLETE_TAG_HANDLE_CLOSE
959
+ );
960
+ }
961
+ if (l->lookahead == '!') {
962
+ s->mode = s->directive_handle ? DIRECTIVE_PREFIX : SUFFIX_BEGIN;
963
+ return take(l, valid, TAG_HANDLE_CLOSE);
964
+ }
965
+ if (scan_invalid_character(l, valid))
966
+ return true;
967
+ if (!word_char(l->lookahead))
968
+ return take(l, valid, INVALID_TAG_HANDLE);
969
+ do {
970
+ step(l);
971
+ } while (word_char(l->lookahead));
972
+ return finish(l, valid, TAG_HANDLE_NAME);
973
+ }
974
+
975
+ /* The zero-width boundaries around a verbatim URI or a tag suffix. */
976
+ static bool scan_tag_boundary(Scanner *s, TSLexer *l, const bool *valid) {
977
+ if (s->mode == URI_BEGIN) {
978
+ s->mode = URI_BODY;
979
+ if (l->eof(l) || space(l->lookahead) || l->lookahead == '>') {
980
+ s->mode = VERBATIM_CLOSE;
981
+ return emit_missing(l, valid, MISSING_TAG_URI, INCOMPLETE_TAG_URI);
982
+ }
983
+ return emit(l, valid, TAG_URI_START);
984
+ }
985
+ if (s->mode == VERBATIM_CLOSE) {
986
+ finish_tag(s);
987
+ if (l->lookahead == '>')
988
+ return take(l, valid, VERBATIM_TAG_CLOSE);
989
+ return emit_missing(
990
+ l,
991
+ valid,
992
+ MISSING_VERBATIM_TAG_CLOSE,
993
+ INCOMPLETE_VERBATIM_TAG_CLOSE
994
+ );
995
+ }
996
+ s->mode = SUFFIX_BODY;
997
+ if (name_boundary(l))
998
+ return emit_missing(l, valid, MISSING_TAG_SUFFIX, INCOMPLETE_TAG_SUFFIX);
999
+ return emit(l, valid, TAG_SUFFIX_START);
1000
+ }
1001
+
1002
+ static bool scan_uri(Scanner *s, TSLexer *l, const bool *valid) {
1003
+ bool prefix = s->mode == PREFIX_BODY;
1004
+ 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
+ ) {
1010
+ if (prefix) {
1011
+ s->mode = DIRECTIVE_PARAMETERS;
1012
+ return emit(l, valid, TAG_PREFIX_END);
1013
+ }
1014
+ if (suffix) {
1015
+ finish_tag(s);
1016
+ return emit(l, valid, TAG_END);
1017
+ }
1018
+ s->mode = VERBATIM_CLOSE;
1019
+ return emit(l, valid, TAG_URI_END);
1020
+ }
1021
+ if (scan_invalid_character(l, valid))
1022
+ return true;
1023
+ if (prefix && s->first) {
1024
+ s->first = false;
1025
+ if (flow_indicator(l->lookahead))
1026
+ return take(l, valid, INVALID_TAG_CHARACTER);
1027
+ }
1028
+ if (l->lookahead == '%') {
1029
+ step(l);
1030
+ l->mark_end(l);
1031
+ uint32_t value;
1032
+ unsigned remaining = hex_digits(l, 2, &value);
1033
+ return emit(
1034
+ l,
1035
+ valid,
1036
+ !remaining ? URI_ESCAPE
1037
+ : l->eof(l) ? INCOMPLETE_URI_ESCAPE
1038
+ : INVALID_URI_ESCAPE
1039
+ );
1040
+ }
1041
+ if (!uri_char(l->lookahead, suffix))
1042
+ return take(l, valid, INVALID_TAG_CHARACTER);
1043
+ do {
1044
+ step(l);
1045
+ } while (uri_char(l->lookahead, suffix));
1046
+ return finish(l, valid, suffix ? TAG_SUFFIX_TEXT : URI_TEXT);
1047
+ }
1048
+
1049
+ static bool directive_boundary(TSLexer *l) {
1050
+ return l->eof(l) || space(l->lookahead) || invalid_unquoted(l->lookahead);
1051
+ }
1052
+ static bool
1053
+ scan_directive_word(TSLexer *l, const bool *valid, enum Token token) {
1054
+ do {
1055
+ step(l);
1056
+ } while (!directive_boundary(l));
1057
+ return finish(l, valid, token);
1058
+ }
1059
+ /* The zero-width start token reads to the end of the line so that any edit
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. */
1063
+ static bool start_comment(
1064
+ Scanner *s,
1065
+ TSLexer *l,
1066
+ const bool *valid,
1067
+ enum Mode return_mode,
1068
+ bool missing_separation
1069
+ ) {
1070
+ if (!valid[COMMENT_START])
1071
+ return false;
1072
+ while (!l->eof(l) && !newline(l->lookahead))
1073
+ step(l);
1074
+ s->mode = COMMENT_BEGIN;
1075
+ s->return_mode = (uint8_t)return_mode;
1076
+ s->first = missing_separation;
1077
+ return emit(l, valid, COMMENT_START);
1078
+ }
1079
+ static bool scan_directive_name(Scanner *s, TSLexer *l, const bool *valid) {
1080
+ if (l->eof(l) || space(l->lookahead)) {
1081
+ if (s->first) {
1082
+ s->first = false;
1083
+ return emit_missing(
1084
+ l,
1085
+ valid,
1086
+ MISSING_DIRECTIVE_NAME,
1087
+ INCOMPLETE_DIRECTIVE_NAME
1088
+ );
1089
+ }
1090
+ s->mode = s->directive_kind == YAML_DIRECTIVE ? DIRECTIVE_VERSION
1091
+ : s->directive_kind == TAG_DIRECTIVE ? DIRECTIVE_HANDLE
1092
+ : DIRECTIVE_PARAMETERS;
1093
+ return emit(l, valid, DIRECTIVE_NAME_END);
1094
+ }
1095
+ s->first = false;
1096
+ if (scan_invalid_character(l, valid))
1097
+ return true;
1098
+ return scan_directive_word(l, valid, DIRECTIVE_NAME);
1099
+ }
1100
+ static bool
1101
+ scan_yaml_version(Scanner *s, TSLexer *l, const bool *valid, bool end) {
1102
+ if (scan_invalid_character(l, valid))
1103
+ return true;
1104
+ s->mode = DIRECTIVE_PARAMETERS;
1105
+ if (end)
1106
+ return emit_missing(
1107
+ l,
1108
+ valid,
1109
+ MISSING_YAML_VERSION,
1110
+ INCOMPLETE_YAML_VERSION
1111
+ );
1112
+ unsigned part = 0;
1113
+ bool correct = true;
1114
+ do {
1115
+ int32_t c = l->lookahead;
1116
+ if (c >= '0' && c <= '9') {
1117
+ if (part == 0 || part == 2)
1118
+ part++;
1119
+ } else if (c == '.' && part == 1)
1120
+ part = 2;
1121
+ else
1122
+ correct = false;
1123
+ step(l);
1124
+ } while (!directive_boundary(l));
1125
+ return finish(
1126
+ l,
1127
+ valid,
1128
+ correct && part == 3 ? YAML_VERSION
1129
+ : correct && l->eof(l) ? UNFINISHED_YAML_VERSION
1130
+ : INVALID_YAML_VERSION
1131
+ );
1132
+ }
1133
+ static bool
1134
+ scan_directive_handle(Scanner *s, TSLexer *l, const bool *valid, bool end) {
1135
+ if (scan_invalid_character(l, valid))
1136
+ return true;
1137
+ s->mode = DIRECTIVE_PREFIX;
1138
+ s->property_separation_notified = false;
1139
+ if (end)
1140
+ return emit_missing(l, valid, MISSING_TAG_HANDLE, INCOMPLETE_TAG_HANDLE);
1141
+ if (l->lookahead == '!') {
1142
+ step(l);
1143
+ s->handle_form = l->lookahead == '!' ? SECONDARY_HANDLE
1144
+ : directive_boundary(l) ? PRIMARY_HANDLE
1145
+ : NAMED_HANDLE;
1146
+ s->directive_handle = true;
1147
+ s->mode = HANDLE_SELECT;
1148
+ return emit(l, valid, TAG_HANDLE_START);
1149
+ }
1150
+ return scan_directive_word(l, valid, INVALID_TAG_HANDLE);
1151
+ }
1152
+ static bool
1153
+ scan_directive_prefix(Scanner *s, TSLexer *l, const bool *valid, bool end) {
1154
+ if (end) {
1155
+ s->mode = DIRECTIVE_PARAMETERS;
1156
+ return emit_missing(l, valid, MISSING_TAG_PREFIX, INCOMPLETE_TAG_PREFIX);
1157
+ }
1158
+ if (!s->separated && !s->property_separation_notified) {
1159
+ s->property_separation_notified = true;
1160
+ return emit(l, valid, MISSING_SEPARATION);
1161
+ }
1162
+ s->mode = PREFIX_BODY;
1163
+ s->first = true;
1164
+ return emit(l, valid, TAG_PREFIX_START);
1165
+ }
1166
+ static bool scan_directive(Scanner *s, TSLexer *l, const bool *valid) {
1167
+ if (s->mode == DIRECTIVE_NAME_BODY)
1168
+ return scan_directive_name(s, l, valid);
1169
+ if (blank(l->lookahead))
1170
+ return scan_separation(l, valid);
1171
+ bool end =
1172
+ l->eof(l) || newline(l->lookahead) || (l->lookahead == '#' && s->separated);
1173
+ switch ((enum Mode)s->mode) {
1174
+ case DIRECTIVE_VERSION:
1175
+ return scan_yaml_version(s, l, valid, end);
1176
+ case DIRECTIVE_HANDLE:
1177
+ return scan_directive_handle(s, l, valid, end);
1178
+ case DIRECTIVE_PREFIX:
1179
+ return scan_directive_prefix(s, l, valid, end);
1180
+ default:
1181
+ break;
1182
+ }
1183
+ if (l->lookahead == '#' && s->separated)
1184
+ return start_comment(s, l, valid, DIRECTIVE_PARAMETERS, false);
1185
+ if (end) {
1186
+ s->mode = NORMAL;
1187
+ return emit(l, valid, DIRECTIVE_END);
1188
+ }
1189
+ if (scan_invalid_character(l, valid))
1190
+ return true;
1191
+ return scan_directive_word(
1192
+ l,
1193
+ valid,
1194
+ s->directive_kind == RESERVED_DIRECTIVE ? DIRECTIVE_PARAMETER
1195
+ : UNEXPECTED_DIRECTIVE_PARAMETER
1196
+ );
1197
+ }
1198
+
1199
+ static bool scalar_break(Scanner *s, TSLexer *l, const bool *valid) {
1200
+ s->prefix = true;
1201
+ s->continuation = false;
1202
+ s->quote_line_empty = s->mode == DOUBLE;
1203
+ s->scalar_indent = true;
1204
+ s->scalar_spaces = 0;
1205
+ s->scalar_tab = false;
1206
+ return line_break(l, valid, SCALAR_LINE_BREAK);
1207
+ }
1208
+ /* Content resumes after the prefix of a continuation line; its first token
1209
+ * must be indented past the enclosing block indentation. */
1210
+ static bool resume_scalar_line(Scanner *s) {
1211
+ s->prefix = false;
1212
+ s->continuation = false;
1213
+ if (!s->scalar_indent)
1214
+ return true;
1215
+ s->scalar_indent = false;
1216
+ return s->scalar_spaces > s->indent;
1217
+ }
1218
+ static bool scalar_prefix(Scanner *s, TSLexer *l, const bool *valid) {
1219
+ if (l->lookahead == '\t' && s->scalar_spaces <= s->indent) {
1220
+ s->scalar_tab = true;
1221
+ return take(l, valid, INVALID_INDENTATION);
1222
+ }
1223
+ do {
1224
+ if (l->lookahead == '\t')
1225
+ s->scalar_tab = true;
1226
+ else if (!s->scalar_tab)
1227
+ s->scalar_spaces++;
1228
+ step(l);
1229
+ } while (
1230
+ blank(l->lookahead) &&
1231
+ !(l->lookahead == '\t' && s->scalar_spaces <= s->indent)
1232
+ );
1233
+ return finish(l, valid, SCALAR_LINE_PREFIX);
1234
+ }
1235
+ static bool scan_quote(Scanner *s, TSLexer *l, const bool *valid) {
1236
+ int32_t quote = s->mode == SINGLE ? '\'' : '"';
1237
+ if (l->eof(l)) {
1238
+ if (!emit(l, valid, INCOMPLETE_QUOTE_CLOSE))
1239
+ return false;
1240
+ s->mode = NORMAL;
1241
+ s->prefix = false;
1242
+ s->json = true;
1243
+ return true;
1244
+ }
1245
+ if (newline(l->lookahead))
1246
+ return scalar_break(s, l, valid);
1247
+ if (s->prefix && blank(l->lookahead))
1248
+ return scalar_prefix(s, l, valid);
1249
+ if (!resume_scalar_line(s))
1250
+ return emit(l, valid, MISSING_INDENTATION);
1251
+ if (invalid_quoted(l->lookahead) && scan_invalid_character(l, valid))
1252
+ return true;
1253
+ if (l->lookahead == quote) {
1254
+ step(l);
1255
+ l->mark_end(l);
1256
+ if (quote == '\'' && l->lookahead == '\'') {
1257
+ step(l);
1258
+ return finish(l, valid, ESCAPED_QUOTE);
1259
+ }
1260
+ if (!emit(l, valid, QUOTE_CLOSE))
1261
+ return false;
1262
+ s->mode = NORMAL;
1263
+ s->json = true;
1264
+ return true;
1265
+ }
1266
+ if (s->mode == DOUBLE && l->lookahead == '\\') {
1267
+ step(l);
1268
+ l->mark_end(l);
1269
+ if (newline(l->lookahead))
1270
+ return emit(
1271
+ l,
1272
+ valid,
1273
+ s->quote_line_empty ? INVALID_LINE_CONTINUATION : ESCAPE_INDICATOR
1274
+ );
1275
+ if (l->eof(l))
1276
+ return emit(l, valid, INCOMPLETE_ESCAPE);
1277
+ if (invalid_quoted(l->lookahead)) {
1278
+ /* The prefix belongs to the scalar; decoding failure owns its own bytes.
1279
+ */
1280
+ return emit(l, valid, INVALID_ESCAPE);
1281
+ }
1282
+ int32_t c = l->lookahead;
1283
+ const char *simple = "0abtnvfre \t\"/\\N_LP";
1284
+ bool ok = c > 0 && c < 128 && strchr(simple, (int)c);
1285
+ unsigned digits = c == 'x' ? 2 : c == 'u' ? 4 : c == 'U' ? 8 : 0;
1286
+ step(l);
1287
+ l->mark_end(l);
1288
+ if (digits) {
1289
+ uint32_t value;
1290
+ unsigned remaining = hex_digits(l, digits, &value);
1291
+ uint64_t lower = (uint64_t)value << (remaining * 4);
1292
+ uint64_t upper = lower | ((UINT64_C(1) << (remaining * 4)) - 1);
1293
+ ok = lower <= 0x10ffff && (lower < 0xd800 || upper > 0xdfff);
1294
+ if (remaining)
1295
+ return emit(
1296
+ l,
1297
+ valid,
1298
+ l->eof(l) && ok ? INCOMPLETE_ESCAPE : INVALID_ESCAPE
1299
+ );
1300
+ }
1301
+ if (ok)
1302
+ s->quote_line_empty = false;
1303
+ return emit(l, valid, ok ? QUOTED_ESCAPE : INVALID_ESCAPE);
1304
+ }
1305
+ bool text = false;
1306
+ while (
1307
+ !l->eof(l) &&
1308
+ l->lookahead !=
1309
+ quote &&
1310
+ !newline(l->lookahead) &&
1311
+ !invalid_quoted(l->lookahead) &&
1312
+ !(s->mode == DOUBLE && l->lookahead == '\\')
1313
+ ) {
1314
+ if (blank(l->lookahead)) {
1315
+ step(l);
1316
+ skip_blanks(l);
1317
+ if (newline(l->lookahead)) {
1318
+ if (text)
1319
+ return emit(l, valid, SCALAR_TEXT);
1320
+ return finish(l, valid, SCALAR_LINE_SUFFIX);
1321
+ }
1322
+ text = true;
1323
+ l->mark_end(l);
1324
+ continue;
1325
+ }
1326
+ step(l);
1327
+ s->quote_line_empty = false;
1328
+ text = true;
1329
+ l->mark_end(l);
1330
+ }
1331
+ return text && emit(l, valid, SCALAR_TEXT);
1332
+ }
1333
+
1334
+ static bool scan_plain(Scanner *s, TSLexer *l, const bool *valid) {
1335
+ bool text = false;
1336
+ if (s->first) {
1337
+ s->first = false;
1338
+ if (
1339
+ l->lookahead >
1340
+ 0 &&
1341
+ l->lookahead <
1342
+ 128 &&
1343
+ strchr(",]}@`%&*!|>", (int)l->lookahead)
1344
+ )
1345
+ return take(l, valid, INVALID_SCALAR_START);
1346
+ if (l->lookahead == '-' || l->lookahead == '?' || l->lookahead == ':') {
1347
+ step(l);
1348
+ if (
1349
+ space(l->lookahead) ||
1350
+ l->eof(l) ||
1351
+ (s->flow && flow_indicator(l->lookahead))
1352
+ ) {
1353
+ return finish(l, valid, INVALID_SCALAR_START);
1354
+ }
1355
+ text = true;
1356
+ }
1357
+ }
1358
+ if (s->continuation || s->prefix) {
1359
+ if (newline(l->lookahead))
1360
+ return scalar_break(s, l, valid);
1361
+ if (blank(l->lookahead)) {
1362
+ if (s->prefix)
1363
+ return scalar_prefix(s, l, valid);
1364
+ step(l);
1365
+ skip_blanks(l);
1366
+ return finish(l, valid, SCALAR_LINE_SUFFIX);
1367
+ }
1368
+ if (!resume_scalar_line(s))
1369
+ return emit(l, valid, MISSING_INDENTATION);
1370
+ } else if (space(l->lookahead)) {
1371
+ bool broken = false;
1372
+ uint32_t indentation = 0;
1373
+ bool tab = false;
1374
+ while (space(l->lookahead)) {
1375
+ broken |= newline(l->lookahead);
1376
+ if (newline(l->lookahead)) {
1377
+ indentation = 0;
1378
+ tab = false;
1379
+ } else if (l->lookahead == '\t')
1380
+ tab = true;
1381
+ else if (!tab)
1382
+ indentation++;
1383
+ step(l);
1384
+ }
1385
+ bool more = !l->eof(l) &&
1386
+ l->lookahead !=
1387
+ '#' &&
1388
+ (!s->flow || !flow_indicator(l->lookahead)) &&
1389
+ (!broken || s->flow || indentation > s->indent);
1390
+ if (more && l->lookahead == ':') {
1391
+ step(l);
1392
+ more = !colon_boundary(l, s->flow);
1393
+ }
1394
+ if (
1395
+ more &&
1396
+ l->get_column(l) ==
1397
+ 0 &&
1398
+ (l->lookahead == 0xfeff || document_marker(l))
1399
+ )
1400
+ more = false;
1401
+ if (more && !broken) {
1402
+ text = true;
1403
+ } else {
1404
+ if (more && emit(l, valid, PLAIN_CONTINUE)) {
1405
+ s->continuation = true;
1406
+ return true;
1407
+ }
1408
+ if (!emit(l, valid, PLAIN_END))
1409
+ return false;
1410
+ s->mode = NORMAL;
1411
+ return true;
1412
+ }
1413
+ }
1414
+ if (!text && scan_invalid_character(l, valid))
1415
+ return true;
1416
+ l->mark_end(l);
1417
+ while (!l->eof(l)) {
1418
+ int32_t c = l->lookahead;
1419
+ if (newline(c) || invalid_unquoted(c) || (s->flow && flow_indicator(c)))
1420
+ break;
1421
+ if (c == ':') {
1422
+ step(l);
1423
+ if (colon_boundary(l, s->flow))
1424
+ break;
1425
+ text = true;
1426
+ l->mark_end(l);
1427
+ continue;
1428
+ }
1429
+ if (blank(c)) {
1430
+ step(l);
1431
+ skip_blanks(l);
1432
+ if (l->eof(l) || newline(l->lookahead) || l->lookahead == '#')
1433
+ break;
1434
+ if (invalid_unquoted(l->lookahead)) {
1435
+ text = true;
1436
+ l->mark_end(l);
1437
+ break;
1438
+ }
1439
+ continue;
1440
+ }
1441
+ step(l);
1442
+ text = true;
1443
+ l->mark_end(l);
1444
+ }
1445
+ if (text)
1446
+ return emit(l, valid, SCALAR_TEXT);
1447
+ if (!emit(l, valid, PLAIN_END))
1448
+ return false;
1449
+ s->mode = NORMAL;
1450
+ return true;
1451
+ }
1452
+
1453
+ static bool scan_block_header(Scanner *s, TSLexer *l, const bool *valid) {
1454
+ if (s->mode == BLOCK_HEADER_DONE || l->eof(l)) {
1455
+ s->mode = BLOCK_DETECT;
1456
+ return emit(l, valid, BLOCK_HEADER_END);
1457
+ }
1458
+ if (scan_invalid_character(l, valid))
1459
+ return true;
1460
+ if (newline(l->lookahead)) {
1461
+ s->mode = BLOCK_HEADER_DONE;
1462
+ return line_break(l, valid, BLOCK_HEADER_BREAK);
1463
+ }
1464
+ if (blank(l->lookahead)) {
1465
+ s->header_flags |= HEADER_SEPARATION;
1466
+ return scan_separation(l, valid);
1467
+ }
1468
+ if (l->lookahead == '#' && valid[COMMENT_START])
1469
+ return start_comment(s, l, valid, BLOCK_HEADER, !s->separated);
1470
+ if (
1471
+ l->lookahead >=
1472
+ '1' &&
1473
+ l->lookahead <=
1474
+ '9' &&
1475
+ !(s->header_flags & (HEADER_INDENTATION | HEADER_SEPARATION))
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')
1489
+ return take(l, valid, INVALID_HEADER_INDENTATION);
1490
+ if (l->lookahead == '+' || l->lookahead == '-')
1491
+ return take(l, valid, INVALID_HEADER_CHOMPING);
1492
+ step(l);
1493
+ while (
1494
+ !l->eof(l) &&
1495
+ !space(l->lookahead) &&
1496
+ l->lookahead !=
1497
+ '#' &&
1498
+ !invalid_unquoted(l->lookahead) &&
1499
+ !(l->lookahead >= '0' && l->lookahead <= '9') &&
1500
+ l->lookahead !=
1501
+ '+' &&
1502
+ l->lookahead != '-'
1503
+ )
1504
+ step(l);
1505
+ return finish(l, valid, INVALID_BLOCK_HEADER);
1506
+ }
1507
+
1508
+ static void reset_line(Scanner *s) {
1509
+ s->line = true;
1510
+ s->line_context = false;
1511
+ s->line_prefixed = false;
1512
+ s->line_indent = 0;
1513
+ s->line_mapping_key = false;
1514
+ s->prefix_invalid = false;
1515
+ s->after_document_end = false;
1516
+ }
1517
+
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
+ static void close_document(Scanner *s) {
1521
+ s->document = false;
1522
+ s->document_content = false;
1523
+ s->explicit_document_required = true;
1524
+ }
1525
+ static void open_document(Scanner *s, bool started) {
1526
+ s->document = true;
1527
+ s->document_started = started;
1528
+ s->document_content = false;
1529
+ s->flow = 0;
1530
+ s->indent = -1;
1531
+ s->block_out = false;
1532
+ }
1533
+
1534
+ /* Close open constructs before a document marker; directives and stream BOMs
1535
+ * are left for normal scanning. */
1536
+ static bool scan_boundary(Scanner *s, TSLexer *l, const bool *valid) {
1537
+ if (s->mode == SINGLE || s->mode == DOUBLE) {
1538
+ s->mode = NORMAL;
1539
+ s->prefix = false;
1540
+ s->scalar_indent = false;
1541
+ return emit(l, valid, MISSING_QUOTE_CLOSE);
1542
+ }
1543
+ if (s->mode == PLAIN) {
1544
+ s->mode = NORMAL;
1545
+ return emit(l, valid, PLAIN_END);
1546
+ }
1547
+ if (s->mode == BLOCK_BODY) {
1548
+ s->mode = NORMAL;
1549
+ reset_line(s);
1550
+ return emit(l, valid, BLOCK_SCALAR_END);
1551
+ }
1552
+ static const enum Token closings[] = {
1553
+ EMPTY_BLOCK_NODE,
1554
+ MISSING_FLOW_SEQUENCE_CLOSE,
1555
+ MISSING_FLOW_MAPPING_CLOSE,
1556
+ MAPPING_END,
1557
+ SEQUENCE_END,
1558
+ DEDENT,
1559
+ RESTORE_INDENT
1560
+ };
1561
+ if (emit_closing(s, l, valid, closings, sizeof(closings) / sizeof(*closings)))
1562
+ return true;
1563
+ if (valid[DOCUMENT_CLOSE] && s->document && s->document_started) {
1564
+ close_document(s);
1565
+ return emit(l, valid, DOCUMENT_CLOSE);
1566
+ }
1567
+ enum Boundary boundary = (enum Boundary)s->boundary;
1568
+ bool opens = boundary == DOCUMENT_START_LINE || boundary == DIRECTIVE_LINE;
1569
+ if (opens && valid[DOCUMENT_OPEN] && !s->document) {
1570
+ open_document(s, false);
1571
+ return emit(l, valid, DOCUMENT_OPEN);
1572
+ }
1573
+ if (boundary == DIRECTIVE_LINE || boundary == STREAM_BOM) {
1574
+ if (
1575
+ boundary ==
1576
+ DIRECTIVE_LINE &&
1577
+ s->explicit_document_required &&
1578
+ valid[MISSING_DOCUMENT_END]
1579
+ ) {
1580
+ s->explicit_document_required = false;
1581
+ return emit(l, valid, MISSING_DOCUMENT_END);
1582
+ }
1583
+ return false;
1584
+ }
1585
+ enum Token token =
1586
+ boundary == DOCUMENT_START_LINE ? DOCUMENT_START : DOCUMENT_END;
1587
+ if (!valid[token])
1588
+ return false;
1589
+ for (unsigned i = 0; i < 3; i++)
1590
+ step(l);
1591
+ l->mark_end(l);
1592
+ s->document_started = token == DOCUMENT_START;
1593
+ s->after_document_end = token == DOCUMENT_END;
1594
+ s->explicit_document_required = false;
1595
+ return emit(l, valid, token);
1596
+ }
1597
+
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
+ static bool detect_block_indent(Scanner *s, TSLexer *l, const bool *valid) {
1601
+ if (s->block_indent < 0) {
1602
+ uint32_t longest = 0;
1603
+ for (;;) {
1604
+ uint32_t spaces = count_spaces(l);
1605
+ if (newline(l->lookahead)) {
1606
+ if (spaces > longest)
1607
+ longest = spaces;
1608
+ skip_line_break(l);
1609
+ } else {
1610
+ bool content = !l->eof(l) && spaces > s->indent;
1611
+ if (
1612
+ content && !spaces && (l->lookahead == 0xfeff || document_marker(l))
1613
+ )
1614
+ content = false;
1615
+ s->block_indent =
1616
+ content ? spaces : (spaces > longest ? spaces : longest);
1617
+ break;
1618
+ }
1619
+ }
1620
+ }
1621
+ s->block_leading = true;
1622
+ s->mode = BLOCK_BODY;
1623
+ return emit(l, valid, BLOCK_BODY_START);
1624
+ }
1625
+ static bool scan_block_body(Scanner *s, TSLexer *l, const bool *valid) {
1626
+ if (l->eof(l)) {
1627
+ s->mode = NORMAL;
1628
+ reset_line(s);
1629
+ return emit(l, valid, BLOCK_SCALAR_END);
1630
+ }
1631
+ uint32_t spaces = count_spaces(l);
1632
+ bool empty = newline(l->lookahead) || l->eof(l);
1633
+ bool spaced = spaces > s->block_indent || l->lookahead == '\t';
1634
+ /* A less indented line that holds only blanks and a comment is a
1635
+ * separation line of the enclosing construct, not scalar content. */
1636
+ bool separation = false;
1637
+ if (!empty && spaces < s->block_indent && l->lookahead == '\t') {
1638
+ skip_blanks(l);
1639
+ separation = l->eof(l) || newline(l->lookahead) || l->lookahead == '#';
1640
+ }
1641
+ if (
1642
+ !empty &&
1643
+ (spaces <=
1644
+ s->indent ||
1645
+ separation ||
1646
+ (spaces < s->block_indent && l->lookahead == '#'))
1647
+ ) {
1648
+ s->mode = NORMAL;
1649
+ reset_line(s);
1650
+ return emit(l, valid, BLOCK_SCALAR_END);
1651
+ }
1652
+ s->block_empty = empty &&
1653
+ (spaces <=
1654
+ s->block_indent ||
1655
+ (s->block_leading && !(s->header_flags & HEADER_INDENTATION)));
1656
+ if (!s->block_empty)
1657
+ s->block_leading = false;
1658
+ s->block_prefix = true;
1659
+ s->scalar_indent = true;
1660
+ s->mode = BLOCK_LINE;
1661
+ return emit(
1662
+ l,
1663
+ valid,
1664
+ s->block_empty ? BLOCK_EMPTY_LINE_START
1665
+ : spaced ? BLOCK_SPACED_LINE_START
1666
+ : BLOCK_TEXT_LINE_START
1667
+ );
1668
+ }
1669
+ static bool scan_block_line(Scanner *s, TSLexer *l, const bool *valid) {
1670
+ if (s->mode == BLOCK_LINE_DONE || l->eof(l)) {
1671
+ s->mode = BLOCK_BODY;
1672
+ return emit(l, valid, BLOCK_LINE_END);
1673
+ }
1674
+ if (s->block_prefix) {
1675
+ s->block_prefix = false;
1676
+ bool consumed = false;
1677
+ while (l->lookahead == ' ' && l->get_column(l) < s->block_indent) {
1678
+ step(l);
1679
+ consumed = true;
1680
+ }
1681
+ if (consumed) {
1682
+ return finish(l, valid, SCALAR_LINE_PREFIX);
1683
+ }
1684
+ }
1685
+ if (s->scalar_indent) {
1686
+ s->scalar_indent = false;
1687
+ if (s->block_empty && s->block_leading && l->lookahead == ' ') {
1688
+ count_spaces(l);
1689
+ return finish(l, valid, INVALID_INDENTATION);
1690
+ }
1691
+ if (!s->block_empty && l->get_column(l) < s->block_indent)
1692
+ return emit(l, valid, MISSING_INDENTATION);
1693
+ }
1694
+ if (newline(l->lookahead)) {
1695
+ s->mode = BLOCK_LINE_DONE;
1696
+ reset_line(s);
1697
+ return line_break(l, valid, SCALAR_LINE_BREAK);
1698
+ }
1699
+ return scan_line_text(l, valid, SCALAR_TEXT);
1700
+ }
1701
+
1702
+ static bool scan_comment(Scanner *s, TSLexer *l, const bool *valid) {
1703
+ if (s->mode == COMMENT_BEGIN) {
1704
+ if (s->first) {
1705
+ s->first = false;
1706
+ return emit(l, valid, MISSING_SEPARATION);
1707
+ }
1708
+ s->mode = COMMENT;
1709
+ return take(l, valid, COMMENT_MARKER);
1710
+ }
1711
+ if (l->eof(l) || newline(l->lookahead)) {
1712
+ if (!emit(l, valid, COMMENT_END))
1713
+ return false;
1714
+ s->mode = s->return_mode;
1715
+ s->return_mode = NORMAL;
1716
+ return true;
1717
+ }
1718
+ return scan_line_text(l, valid, COMMENT_TEXT);
1719
+ }
1720
+
1721
+ static bool start_line_prefix(
1722
+ Scanner *s,
1723
+ TSLexer *l,
1724
+ const bool *valid,
1725
+ bool prefix_invalid,
1726
+ bool tab_invalid,
1727
+ bool indent_checked
1728
+ ) {
1729
+ s->prefix_invalid = prefix_invalid;
1730
+ s->tab_invalid = tab_invalid;
1731
+ s->indent_checked = indent_checked;
1732
+ s->prefix_tab = false;
1733
+ s->mode = PREFIX;
1734
+ return emit(l, valid, LINE_PREFIX_START);
1735
+ }
1736
+ static bool scan_prefix(Scanner *s, TSLexer *l, const bool *valid) {
1737
+ if (s->mode == COMPACT_PREFIX)
1738
+ return start_line_prefix(s, l, valid, false, true, true);
1739
+ if (l->lookahead == ' ' && !s->prefix_tab) {
1740
+ bool excess = s->prefix_invalid && l->get_column(l) >= s->indent;
1741
+ do {
1742
+ step(l);
1743
+ } while (
1744
+ l->lookahead ==
1745
+ ' ' &&
1746
+ (excess || !s->prefix_invalid || l->get_column(l) < s->indent)
1747
+ );
1748
+ return finish(l, valid, excess ? INVALID_INDENTATION : INDENTATION);
1749
+ }
1750
+ if (blank(l->lookahead)) {
1751
+ s->prefix_tab = true;
1752
+ if (s->tab_invalid && l->lookahead == '\t')
1753
+ return take(l, valid, INVALID_INDENTATION);
1754
+ do {
1755
+ step(l);
1756
+ } while (blank(l->lookahead) && !(s->tab_invalid && l->lookahead == '\t'));
1757
+ return finish(l, valid, SEPARATION);
1758
+ }
1759
+ if (
1760
+ !s->indent_checked &&
1761
+ s->flow &&
1762
+ !newline(l->lookahead) &&
1763
+ !l->eof(l) &&
1764
+ l->lookahead !=
1765
+ '#' &&
1766
+ s->line_indent <= s->indent
1767
+ ) {
1768
+ s->indent_checked = true;
1769
+ return emit(l, valid, MISSING_INDENTATION);
1770
+ }
1771
+ s->mode = NORMAL;
1772
+ return emit(l, valid, LINE_PREFIX_END);
1773
+ }
1774
+
1775
+ static bool
1776
+ scan_node_start(Scanner *s, TSLexer *l, const bool *valid, int64_t column) {
1777
+ int32_t first = l->lookahead;
1778
+ enum Token kind = s->flow ? node_start(first) : classify_block_start(s, l);
1779
+ if (!s->line && valid[DOCUMENT_COMPACT_START] && block_collection(kind))
1780
+ return emit(l, valid, DOCUMENT_COMPACT_START);
1781
+ if (
1782
+ !s->flow &&
1783
+ s->line &&
1784
+ column ==
1785
+ s->indent &&
1786
+ kind !=
1787
+ SEQUENCE_START &&
1788
+ valid[SEQUENCE_END]
1789
+ )
1790
+ return emit(l, valid, SEQUENCE_END);
1791
+ if (
1792
+ !s->flow &&
1793
+ s->line &&
1794
+ (column == s->indent || s->prefix_invalid) &&
1795
+ kind ==
1796
+ SEQUENCE_START &&
1797
+ valid[MAPPING_END]
1798
+ )
1799
+ return emit(l, valid, MAPPING_END);
1800
+ if (
1801
+ !s->flow &&
1802
+ s->line &&
1803
+ (column == s->indent || s->prefix_invalid) &&
1804
+ valid[PAIR_START] &&
1805
+ kind != SEQUENCE_START
1806
+ ) {
1807
+ s->key_done = false;
1808
+ return emit(l, valid, PAIR_START);
1809
+ }
1810
+ if (
1811
+ kind ==
1812
+ MAPPING_START &&
1813
+ !valid[MAPPING_START] &&
1814
+ !valid[INDENT] &&
1815
+ !valid[PAIR_START]
1816
+ )
1817
+ kind = node_start(first);
1818
+ if ((kind == LITERAL_START || kind == FOLDED_START) && !valid[kind])
1819
+ kind = PLAIN_START;
1820
+ if (!s->flow && block_collection(kind)) {
1821
+ enum Token shift = column < s->indent ? OUTDENT : INDENT;
1822
+ if (column != s->indent && emit_closing(s, l, valid, &shift, 1))
1823
+ return true;
1824
+ if (column == s->indent || (s->line && s->prefix_invalid)) {
1825
+ enum Token token = kind == MAPPING_START && valid[PAIR_START] ? PAIR_START
1826
+ : kind == SEQUENCE_START && valid[ENTRY_START] ? ENTRY_START
1827
+ : kind;
1828
+ if (valid[token]) {
1829
+ if (token == PAIR_START)
1830
+ s->key_done = false;
1831
+ return emit(l, valid, token);
1832
+ }
1833
+ }
1834
+ }
1835
+ if (kind == PLAIN_START || (kind == MAPPING_START && valid[PLAIN_START]))
1836
+ return start_plain(s, l, valid);
1837
+ if (kind == PROPERTIES_START) {
1838
+ s->json = false;
1839
+ s->property_flags = 0;
1840
+ s->properties_ready = false;
1841
+ s->duplicate_pending = false;
1842
+ s->property_separation_notified = false;
1843
+ }
1844
+ return !block_collection(kind) && emit(l, valid, kind);
1845
+ }
1846
+
1847
+ static bool scan_node_open(Scanner *s, TSLexer *l, const bool *valid) {
1848
+ if (
1849
+ (l->lookahead == '\'' && valid[SINGLE_OPEN]) ||
1850
+ (l->lookahead == '"' && valid[DOUBLE_OPEN])
1851
+ ) {
1852
+ bool single = l->lookahead == '\'';
1853
+ s->mode = single ? SINGLE : DOUBLE;
1854
+ s->quote_line_empty = false;
1855
+ return take(l, valid, single ? SINGLE_OPEN : DOUBLE_OPEN);
1856
+ }
1857
+ if (
1858
+ (l->lookahead == '[' && valid[FLOW_SEQUENCE_OPEN]) ||
1859
+ (l->lookahead == '{' && valid[FLOW_MAPPING_OPEN])
1860
+ ) {
1861
+ bool sequence = l->lookahead == '[';
1862
+ s->flow++;
1863
+ return take(l, valid, sequence ? FLOW_SEQUENCE_OPEN : FLOW_MAPPING_OPEN);
1864
+ }
1865
+ if (
1866
+ (l->lookahead == '|' && valid[LITERAL_INDICATOR]) ||
1867
+ (l->lookahead == '>' && valid[FOLDED_INDICATOR])
1868
+ ) {
1869
+ bool literal = l->lookahead == '|';
1870
+ s->mode = BLOCK_HEADER;
1871
+ s->block_indent = -1;
1872
+ s->header_flags = 0;
1873
+ return take(l, valid, literal ? LITERAL_INDICATOR : FOLDED_INDICATOR);
1874
+ }
1875
+ return false;
1876
+ }
1877
+
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
+ static bool scan_line_context(Scanner *s, TSLexer *l, const bool *valid) {
1891
+ s->line_indent = count_spaces(l);
1892
+ skip_blanks(l);
1893
+ s->line_head = l->lookahead;
1894
+ s->layout_only = l->eof(l) || newline(l->lookahead) || l->lookahead == '#';
1895
+ if (s->line_head == '-' || s->line_head == ':') {
1896
+ step(l);
1897
+ if (!space(l->lookahead) && !l->eof(l))
1898
+ s->line_head = 0;
1899
+ } else if (
1900
+ !s->flow &&
1901
+ (s->line_head == '&' || s->line_head == '!' || s->line_head == '*')
1902
+ ) {
1903
+ s->line_mapping_key = classify_block_start(s, l) == MAPPING_START;
1904
+ }
1905
+ s->line_context = true;
1906
+ return emit(l, valid, LINE_CONTEXT);
1907
+ }
1908
+ static bool begin_line_prefix(Scanner *s, TSLexer *l, const bool *valid) {
1909
+ uint32_t spaces = count_spaces(l);
1910
+ skip_blanks(l);
1911
+ bool prefix_invalid = !s->layout_only &&
1912
+ !s->flow &&
1913
+ spaces >
1914
+ s->indent &&
1915
+ !valid[VALUE_START] &&
1916
+ !valid[SEQUENCE_VALUE_START] &&
1917
+ !valid[INDENT] &&
1918
+ (valid[PAIR_START] || valid[ENTRY_START]);
1919
+ bool tab_invalid = !s->layout_only && spaces <= s->indent;
1920
+ if (!s->layout_only && !s->flow)
1921
+ tab_invalid |= block_collection(classify_block_node(l));
1922
+ s->line_prefixed = true;
1923
+ return start_line_prefix(s, l, valid, prefix_invalid, tab_invalid, false);
1924
+ }
1925
+
1926
+ static bool
1927
+ scan_normal(Scanner *s, TSLexer *l, const bool *valid, bool property_pending) {
1928
+ if (
1929
+ !property_pending &&
1930
+ (valid[KEY_END] || valid[INVALID_KEY_END] || valid[FLOW_NODE_END])
1931
+ )
1932
+ return scan_key_end(s, l, valid);
1933
+ if (
1934
+ s->key_done &&
1935
+ (valid[MISSING_VALUE_INDICATOR] || valid[INCOMPLETE_VALUE_INDICATOR])
1936
+ ) {
1937
+ s->key_done = false;
1938
+ if (l->lookahead == ':') {
1939
+ step(l);
1940
+ if (colon_boundary(l, false))
1941
+ return emit_indicator(s, l, valid, VALUE_INDICATOR);
1942
+ }
1943
+ return emit_missing(
1944
+ l,
1945
+ valid,
1946
+ MISSING_VALUE_INDICATOR,
1947
+ INCOMPLETE_VALUE_INDICATOR
1948
+ );
1949
+ }
1950
+ if (s->line && !s->line_context && valid[LINE_CONTEXT])
1951
+ return scan_line_context(s, l, valid);
1952
+ if (s->line_context && !s->layout_only && !property_line_follows(s)) {
1953
+ s->properties_ready = false;
1954
+ property_pending = false;
1955
+ if (valid[PROPERTIES_END])
1956
+ return emit(l, valid, PROPERTIES_END);
1957
+ }
1958
+ static const enum Token restorations[] = {DEDENT, RESTORE_INDENT};
1959
+ if (
1960
+ !property_pending &&
1961
+ emit_closing(
1962
+ s,
1963
+ l,
1964
+ valid,
1965
+ restorations,
1966
+ sizeof(restorations) / sizeof(*restorations)
1967
+ )
1968
+ )
1969
+ return true;
1970
+ if (
1971
+ !property_pending &&
1972
+ s->line &&
1973
+ s->line_context &&
1974
+ !s->layout_only &&
1975
+ !s->flow
1976
+ ) {
1977
+ if (valid[EMPTY_BLOCK_NODE] && !block_value_follows(s, l, valid))
1978
+ return emit(l, valid, EMPTY_BLOCK_NODE);
1979
+ if (
1980
+ valid[MAPPING_END] &&
1981
+ (s->line_indent <
1982
+ s->indent ||
1983
+ (s->line_indent ==
1984
+ s->indent &&
1985
+ s->line_head ==
1986
+ '-' &&
1987
+ !valid[VALUE_START]))
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);
1994
+ }
1995
+ if (
1996
+ s->line &&
1997
+ !s->line_prefixed &&
1998
+ valid[LINE_PREFIX_START] &&
1999
+ (blank(l->lookahead) ||
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]) {
2009
+ reset_line(s);
2010
+ return line_break(l, valid, LINE_BREAK);
2011
+ }
2012
+ if (blank(l->lookahead) && valid[SEPARATION])
2013
+ return scan_separation(l, valid);
2014
+ if (l->lookahead == '#' && valid[COMMENT_START])
2015
+ return start_comment(
2016
+ s,
2017
+ l,
2018
+ valid,
2019
+ NORMAL,
2020
+ !s->separated && l->get_column(l) != 0
2021
+ );
2022
+ if (valid[DIRECTIVE_INDICATOR]) {
2023
+ s->mode = DIRECTIVE_NAME_BODY;
2024
+ s->first = true;
2025
+ return take(l, valid, DIRECTIVE_INDICATOR);
2026
+ }
2027
+ if (
2028
+ l->lookahead ==
2029
+ '%' &&
2030
+ l->get_column(l) ==
2031
+ 0 &&
2032
+ valid[RESERVED_DIRECTIVE_START]
2033
+ ) {
2034
+ char name[5] = {0};
2035
+ unsigned length = 0;
2036
+ step(l);
2037
+ while (!directive_boundary(l)) {
2038
+ if (length < 4 && l->lookahead < 128)
2039
+ name[length] = (char)l->lookahead;
2040
+ if (length < 5)
2041
+ length++;
2042
+ step(l);
2043
+ }
2044
+ s->directive_kind = length == 4 && !strcmp(name, "YAML") ? YAML_DIRECTIVE
2045
+ : length == 3 && !strcmp(name, "TAG") ? TAG_DIRECTIVE
2046
+ : RESERVED_DIRECTIVE;
2047
+ return emit(
2048
+ l,
2049
+ valid,
2050
+ s->directive_kind == YAML_DIRECTIVE ? YAML_DIRECTIVE_START
2051
+ : s->directive_kind == TAG_DIRECTIVE ? TAG_DIRECTIVE_START
2052
+ : RESERVED_DIRECTIVE_START
2053
+ );
2054
+ }
2055
+ if (
2056
+ !s->document_started &&
2057
+ (valid[MISSING_DOCUMENT_START] || valid[INCOMPLETE_DOCUMENT_START])
2058
+ ) {
2059
+ s->document_started = true;
2060
+ s->explicit_document_required = false;
2061
+ return emit_missing(
2062
+ l,
2063
+ valid,
2064
+ MISSING_DOCUMENT_START,
2065
+ INCOMPLETE_DOCUMENT_START
2066
+ );
2067
+ }
2068
+ return scan_properties(s, l, valid, property_pending);
2069
+ }
2070
+
2071
+ static void begin_property(Scanner *s) {
2072
+ s->duplicate_pending = false;
2073
+ s->property_separation_notified = false;
2074
+ }
2075
+ static bool scan_properties(
2076
+ Scanner *s,
2077
+ TSLexer *l,
2078
+ const bool *valid,
2079
+ bool property_pending
2080
+ ) {
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
+ if (property_pending) {
2103
+ bool content = !l->eof(l) && !(s->flow && flow_entry_end(l->lookahead));
2104
+ if (
2105
+ l->lookahead ==
2106
+ ':' &&
2107
+ !(s->property_flags & PROPERTY_COLON_CONTENT) &&
2108
+ !(s->line && !s->flow && valid[BLOCK_PROPERTY_CONTENT_START])
2109
+ )
2110
+ content = false;
2111
+ if (!property_line_follows(s))
2112
+ content = false;
2113
+ if (!content) {
2114
+ s->properties_ready = false;
2115
+ return scan(s, l, valid);
2116
+ }
2117
+ if (
2118
+ !s->separated &&
2119
+ !s->property_separation_notified &&
2120
+ valid[MISSING_SEPARATION]
2121
+ ) {
2122
+ s->property_separation_notified = true;
2123
+ return emit(l, valid, MISSING_SEPARATION);
2124
+ }
2125
+ s->properties_ready = false;
2126
+ return emit(l, valid, property_content_start(s, l, valid));
2127
+ }
2128
+ if (
2129
+ s->property_flags &&
2130
+ !s->separated &&
2131
+ !s->property_separation_notified &&
2132
+ valid[MISSING_SEPARATION] &&
2133
+ ((l->lookahead == '&' && valid[ANCHOR_INDICATOR]) ||
2134
+ (l->lookahead == '!' && valid[SHORTHAND_TAG_START]))
2135
+ ) {
2136
+ s->property_separation_notified = true;
2137
+ return emit(l, valid, MISSING_SEPARATION);
2138
+ }
2139
+ if (
2140
+ (l->lookahead == '&' && valid[ANCHOR_INDICATOR]) ||
2141
+ (l->lookahead == '*' && valid[ALIAS_INDICATOR])
2142
+ ) {
2143
+ bool anchor = l->lookahead == '&';
2144
+ if (
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);
2154
+ s->mode = anchor ? ANCHOR_BODY : ALIAS_BODY;
2155
+ s->first = true;
2156
+ s->json = false;
2157
+ return take(l, valid, anchor ? ANCHOR_INDICATOR : ALIAS_INDICATOR);
2158
+ }
2159
+ if (
2160
+ l->lookahead ==
2161
+ '!' &&
2162
+ (valid[VERBATIM_TAG_START] ||
2163
+ valid[SHORTHAND_TAG_START] ||
2164
+ valid[NON_SPECIFIC_TAG])
2165
+ ) {
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
+ step(l);
2175
+ if (l->lookahead == '<')
2176
+ return emit(l, valid, VERBATIM_TAG_START);
2177
+ if (!name_boundary(l))
2178
+ return emit(l, valid, SHORTHAND_TAG_START);
2179
+ l->mark_end(l);
2180
+ begin_property(s);
2181
+ s->property_flags |= PROPERTY_TAG;
2182
+ return emit(l, valid, NON_SPECIFIC_TAG);
2183
+ }
2184
+ if (valid[VERBATIM_TAG_OPEN]) {
2185
+ step(l);
2186
+ step(l);
2187
+ l->mark_end(l);
2188
+ begin_property(s);
2189
+ s->mode = URI_BEGIN;
2190
+ return emit(l, valid, VERBATIM_TAG_OPEN);
2191
+ }
2192
+ if (valid[TAG_HANDLE_START]) {
2193
+ s->directive_handle = false;
2194
+ step(l);
2195
+ s->handle_form = PRIMARY_HANDLE;
2196
+ if (l->lookahead == '!')
2197
+ s->handle_form = SECONDARY_HANDLE;
2198
+ else {
2199
+ while (!name_boundary(l)) {
2200
+ if (l->lookahead == '!') {
2201
+ s->handle_form = NAMED_HANDLE;
2202
+ break;
2203
+ }
2204
+ step(l);
2205
+ }
2206
+ }
2207
+ s->mode = HANDLE_SELECT;
2208
+ begin_property(s);
2209
+ return emit(l, valid, TAG_HANDLE_START);
2210
+ }
2211
+ return scan_content(s, l, valid);
2212
+ }
2213
+
2214
+ static bool scan_content(Scanner *s, TSLexer *l, const bool *valid) {
2215
+ if (
2216
+ l->lookahead == 0xfeff && l->get_column(l) == 0 && valid[BYTE_ORDER_MARK]
2217
+ ) {
2218
+ step(l);
2219
+ /* The line starts after the BOM; its layout is measured from there. */
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 {
2229
+ step(l);
2230
+ } while (
2231
+ !l->eof(l) && !space(l->lookahead) && !invalid_unquoted(l->lookahead)
2232
+ );
2233
+ return finish(l, valid, UNEXPECTED_DOCUMENT_END_CONTENT);
2234
+ }
2235
+ int64_t column = s->line ? s->line_indent : l->get_column(l);
2236
+ if (
2237
+ valid[EXPLICIT_VALUE_START] &&
2238
+ l->lookahead ==
2239
+ ':' &&
2240
+ s->line_head ==
2241
+ ':' &&
2242
+ s->line &&
2243
+ column == s->indent
2244
+ )
2245
+ return emit(l, valid, EXPLICIT_VALUE_START);
2246
+ if (
2247
+ valid[VALUE_START] || valid[SEQUENCE_VALUE_START] || valid[EMPTY_BLOCK_NODE]
2248
+ ) {
2249
+ if (block_value_follows(s, l, valid)) {
2250
+ if (!s->line && valid[INVALID_COMPACT_START]) {
2251
+ enum Token kind = classify_block_node(l);
2252
+ if (block_collection(kind))
2253
+ return emit(l, valid, INVALID_COMPACT_START);
2254
+ }
2255
+ s->block_out = valid[VALUE_START];
2256
+ return emit(l, valid, s->block_out ? VALUE_START : SEQUENCE_VALUE_START);
2257
+ }
2258
+ return emit(l, valid, EMPTY_BLOCK_NODE);
2259
+ }
2260
+ if (valid[DOCUMENT_CLOSE] && end) {
2261
+ close_document(s);
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);
2271
+ }
2272
+ if (
2273
+ !s->flow && !s->line && !valid[VALUE_START] && !valid[SEQUENCE_VALUE_START]
2274
+ ) {
2275
+ if (valid[MAPPING_END])
2276
+ return emit(l, valid, MAPPING_END);
2277
+ if (valid[SEQUENCE_END])
2278
+ return emit(l, valid, SEQUENCE_END);
2279
+ }
2280
+ if (end) {
2281
+ static const enum Token endings[] = {
2282
+ MAPPING_END,
2283
+ SEQUENCE_END,
2284
+ INCOMPLETE_FLOW_SEQUENCE_CLOSE,
2285
+ INCOMPLETE_FLOW_MAPPING_CLOSE,
2286
+ END_OF_FILE
2287
+ };
2288
+ return emit_closing(
2289
+ s,
2290
+ l,
2291
+ valid,
2292
+ endings,
2293
+ sizeof(endings) / sizeof(*endings)
2294
+ );
2295
+ }
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
+ if (
2309
+ l->lookahead ==
2310
+ ',' &&
2311
+ !valid[FLOW_SEPARATOR] &&
2312
+ valid[UNEXPECTED_FLOW_SEPARATOR]
2313
+ )
2314
+ return take(l, valid, UNEXPECTED_FLOW_SEPARATOR);
2315
+ if (valid[FLOW_MAP_PAIR_START] && !flow_entry_end(l->lookahead)) {
2316
+ s->json = false;
2317
+ return emit(l, valid, FLOW_MAP_PAIR_START);
2318
+ }
2319
+ if (valid[IMPLICIT_KEY_START] && !(s->flow && flow_entry_end(l->lookahead))) {
2320
+ int32_t first = l->lookahead;
2321
+ bool indicator = false;
2322
+ if (l->lookahead == '?' || l->lookahead == ':') {
2323
+ 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
+ }
2338
+ s->implicit_keys[0] |= 1;
2339
+ s->block_out = false;
2340
+ return emit(l, valid, IMPLICIT_KEY_START);
2341
+ }
2342
+ if (l->lookahead == '?' && valid[KEY_INDICATOR]) {
2343
+ step(l);
2344
+ if (space(l->lookahead) || l->eof(l)) {
2345
+ return emit_indicator(s, l, valid, KEY_INDICATOR);
2346
+ }
2347
+ return start_plain(s, l, valid);
2348
+ }
2349
+ if (l->lookahead == ':' && valid[VALUE_INDICATOR]) {
2350
+ bool adjacent = s->flow && s->json;
2351
+ step(l);
2352
+ if (adjacent || colon_boundary(l, s->flow)) {
2353
+ s->value_separation =
2354
+ s->flow && !adjacent && (l->lookahead == '[' || l->lookahead == '{');
2355
+ s->json = false;
2356
+ return emit_indicator(s, l, valid, VALUE_INDICATOR);
2357
+ }
2358
+ return start_plain(s, l, valid) || emit(l, valid, MISSING_FLOW_SEPARATOR);
2359
+ }
2360
+ if (l->lookahead == '-' && valid[SEQUENCE_INDICATOR]) {
2361
+ step(l);
2362
+ return emit_indicator(s, l, valid, SEQUENCE_INDICATOR);
2363
+ }
2364
+ if (s->value_separation && valid[MISSING_SEPARATION]) {
2365
+ s->value_separation = false;
2366
+ return emit(l, valid, MISSING_SEPARATION);
2367
+ }
2368
+ if (l->lookahead == ',' && valid[FLOW_SEPARATOR])
2369
+ return take(l, valid, FLOW_SEPARATOR);
2370
+ if (l->lookahead == ']' && valid[FLOW_SEQUENCE_CLOSE])
2371
+ return close_flow(s, l, valid, FLOW_SEQUENCE_CLOSE);
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);
2388
+ if (
2389
+ valid[PAIR_START] ||
2390
+ valid[ENTRY_START] ||
2391
+ valid[MAPPING_START] ||
2392
+ valid[SEQUENCE_START] ||
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]
2404
+ ) {
2405
+ return scan_node_start(s, l, valid, column);
2406
+ }
2407
+ return scan_node_open(s, l, valid);
2408
+ }
2409
+
2410
+ static bool scan(Scanner *s, TSLexer *l, const bool *valid) {
2411
+ if (valid[ERROR_SENTINEL])
2412
+ return false;
2413
+ l->mark_end(l);
2414
+ bool boundary_mode = s->mode ==
2415
+ NORMAL ||
2416
+ s->mode ==
2417
+ PLAIN ||
2418
+ s->mode ==
2419
+ SINGLE ||
2420
+ s->mode ==
2421
+ DOUBLE ||
2422
+ s->mode == BLOCK_BODY;
2423
+ if (
2424
+ boundary_mode &&
2425
+ !s->boundary_checked &&
2426
+ l->get_column(l) ==
2427
+ 0 &&
2428
+ valid[BOUNDARY_CHECK]
2429
+ ) {
2430
+ int32_t first = l->lookahead;
2431
+ enum Boundary boundary = line_boundary(s, l);
2432
+ if (boundary || first == '-' || first == '.') {
2433
+ s->boundary = (uint8_t)boundary;
2434
+ s->boundary_checked = true;
2435
+ return emit(l, valid, BOUNDARY_CHECK);
2436
+ }
2437
+ }
2438
+ if (s->mode == NORMAL && s->boundary && valid[PROPERTIES_END]) {
2439
+ s->properties_ready = true;
2440
+ return emit(l, valid, PROPERTIES_END);
2441
+ }
2442
+ if (s->boundary)
2443
+ s->properties_ready = false;
2444
+ bool property_pending = s->properties_ready &&
2445
+ (valid[PROPERTY_CONTENT_START] || valid[BLOCK_PROPERTY_CONTENT_START]);
2446
+ if (
2447
+ s->mode ==
2448
+ NORMAL &&
2449
+ s->boundary ==
2450
+ DOCUMENT_END_LINE &&
2451
+ valid[MISSING_DOCUMENT_START]
2452
+ ) {
2453
+ s->document_started = true;
2454
+ return emit(l, valid, MISSING_DOCUMENT_START);
2455
+ }
2456
+ if (s->mode == NORMAL && !property_pending && valid[DOCUMENT_CONTENT_END]) {
2457
+ s->document_content = true;
2458
+ return emit(l, valid, DOCUMENT_CONTENT_END);
2459
+ }
2460
+ if (
2461
+ boundary_mode &&
2462
+ s->boundary &&
2463
+ !(s->mode ==
2464
+ NORMAL &&
2465
+ (valid[KEY_END] ||
2466
+ valid[INVALID_KEY_END] ||
2467
+ valid[FLOW_NODE_END] ||
2468
+ (s->key_done && valid[MISSING_VALUE_INDICATOR])))
2469
+ ) {
2470
+ if (scan_boundary(s, l, valid))
2471
+ return true;
2472
+ if (s->boundary != DIRECTIVE_LINE && s->boundary != STREAM_BOM)
2473
+ return false;
2474
+ }
2475
+ switch ((enum Mode)s->mode) {
2476
+ case NORMAL:
2477
+ break;
2478
+ case PLAIN:
2479
+ return scan_plain(s, l, valid);
2480
+ case SINGLE:
2481
+ case DOUBLE:
2482
+ return scan_quote(s, l, valid);
2483
+ case COMMENT_BEGIN:
2484
+ case COMMENT:
2485
+ return scan_comment(s, l, valid);
2486
+ case COMPACT_PREFIX:
2487
+ case PREFIX:
2488
+ return scan_prefix(s, l, valid);
2489
+ case BLOCK_HEADER:
2490
+ case BLOCK_HEADER_DONE:
2491
+ return scan_block_header(s, l, valid);
2492
+ case BLOCK_DETECT:
2493
+ return detect_block_indent(s, l, valid);
2494
+ case BLOCK_BODY:
2495
+ return scan_block_body(s, l, valid);
2496
+ case BLOCK_LINE:
2497
+ case BLOCK_LINE_DONE:
2498
+ return scan_block_line(s, l, valid);
2499
+ case ANCHOR_BODY:
2500
+ case ALIAS_BODY:
2501
+ return scan_name(s, l, valid);
2502
+ case HANDLE_SELECT:
2503
+ case HANDLE_BODY:
2504
+ return scan_handle(s, l, valid);
2505
+ case URI_BEGIN:
2506
+ case VERBATIM_CLOSE:
2507
+ case SUFFIX_BEGIN:
2508
+ return scan_tag_boundary(s, l, valid);
2509
+ case URI_BODY:
2510
+ case SUFFIX_BODY:
2511
+ case PREFIX_BODY:
2512
+ return scan_uri(s, l, valid);
2513
+ case DIRECTIVE_NAME_BODY:
2514
+ case DIRECTIVE_VERSION:
2515
+ case DIRECTIVE_HANDLE:
2516
+ case DIRECTIVE_PREFIX:
2517
+ case DIRECTIVE_PARAMETERS:
2518
+ return scan_directive(s, l, valid);
2519
+ default:
2520
+ return false;
2521
+ }
2522
+ return scan_normal(s, l, valid, property_pending);
2523
+ }
2524
+
2525
+ static bool layout_token(TSSymbol token) {
2526
+ switch (token) {
2527
+ case LINE_BREAK:
2528
+ case SEPARATION:
2529
+ case COMMENT_START:
2530
+ case COMMENT_MARKER:
2531
+ case COMMENT_TEXT:
2532
+ case COMMENT_END:
2533
+ case LINE_PREFIX_START:
2534
+ case LINE_PREFIX_END:
2535
+ case INDENTATION:
2536
+ case INVALID_INDENTATION:
2537
+ case BYTE_ORDER_MARK:
2538
+ case LINE_CONTEXT:
2539
+ case BOUNDARY_CHECK:
2540
+ return true;
2541
+ default:
2542
+ return false;
2543
+ }
2544
+ }
2545
+ static void reset_scanner(Scanner *s) {
2546
+ *s = (Scanner){
2547
+ .indent = -1,
2548
+ .block_indent = -1,
2549
+ .line = true,
2550
+ .separated = true
2551
+ };
2552
+ }
2553
+ static void write_integer(char **cursor, uint64_t value, unsigned width) {
2554
+ for (unsigned i = 0; i < width; i++) {
2555
+ *(*cursor)++ = (char)value;
2556
+ value >>= 8;
2557
+ }
2558
+ }
2559
+ static uint64_t read_integer(const char **cursor, unsigned width) {
2560
+ uint64_t value = 0;
2561
+ for (unsigned i = 0; i < width; i++)
2562
+ value |= (uint64_t)(uint8_t)*(*cursor)++ << (i * 8);
2563
+ return value;
2564
+ }
2565
+
2566
+ void *tree_sitter_yaml_external_scanner_create(void) {
2567
+ Scanner *s = ts_calloc(1, sizeof(Scanner));
2568
+ reset_scanner(s);
2569
+ return s;
2570
+ }
2571
+ void tree_sitter_yaml_external_scanner_destroy(void *payload) {
2572
+ ts_free(payload);
2573
+ }
2574
+ unsigned
2575
+ tree_sitter_yaml_external_scanner_serialize(void *payload, char *buffer) {
2576
+ const Scanner *s = payload;
2577
+ char *cursor = buffer;
2578
+ #define WRITE_FIELD(type, name, width, bias) \
2579
+ write_integer(&cursor, (uint64_t)(s->name + bias), width);
2580
+ SCANNER_FIELDS(WRITE_FIELD)
2581
+ #undef WRITE_FIELD
2582
+ unsigned key_bytes = SCANNER_KEY_BYTES;
2583
+ while (
2584
+ key_bytes &&
2585
+ !(uint8_t)(s->implicit_keys[(key_bytes - 1) / 8] >>
2586
+ (((key_bytes - 1) % 8) * 8))
2587
+ )
2588
+ key_bytes--;
2589
+ for (unsigned i = 0; i < key_bytes; i++)
2590
+ *cursor++ = (char)(s->implicit_keys[i / 8] >> ((i % 8) * 8));
2591
+ return (unsigned)(cursor - buffer);
2592
+ }
2593
+ void tree_sitter_yaml_external_scanner_deserialize(
2594
+ void *payload,
2595
+ const char *buffer,
2596
+ unsigned length
2597
+ ) {
2598
+ Scanner *s = payload;
2599
+ reset_scanner(s);
2600
+ if (
2601
+ length <
2602
+ SCANNER_STATE_BYTES ||
2603
+ length >
2604
+ SCANNER_STATE_BYTES +
2605
+ SCANNER_KEY_BYTES
2606
+ )
2607
+ return;
2608
+ const char *cursor = buffer;
2609
+ #define READ_FIELD(type, name, width, bias) \
2610
+ s->name = (type)read_integer(&cursor, width) - bias;
2611
+ SCANNER_FIELDS(READ_FIELD)
2612
+ #undef READ_FIELD
2613
+ for (unsigned i = 0; i < length - SCANNER_STATE_BYTES; i++)
2614
+ s->implicit_keys[i / 8] |= (uint64_t)(uint8_t)*cursor++ << ((i % 8) * 8);
2615
+ }
2616
+ #undef SCANNER_FIELDS
2617
+
2618
+ bool tree_sitter_yaml_external_scanner_scan(
2619
+ void *payload,
2620
+ TSLexer *lexer,
2621
+ const bool *valid
2622
+ ) {
2623
+ Scanner next = *(Scanner *)payload;
2624
+ Cursor cursor = {0};
2625
+ cursor.source = lexer;
2626
+ cursor.column = next.column;
2627
+ cursor.marked_column = next.column;
2628
+ cursor.separated = next.separated;
2629
+ cursor.marked_separation = next.separated;
2630
+ cursor.lexer.lookahead = lexer->lookahead;
2631
+ cursor.lexer.advance = cursor_advance;
2632
+ cursor.lexer.mark_end = cursor_mark;
2633
+ cursor.lexer.get_column = cursor_column;
2634
+ cursor.lexer.eof = cursor_eof;
2635
+ if (!scan(&next, &cursor.lexer, valid))
2636
+ return false;
2637
+ /* Edits inside the final lookahead codepoint must invalidate this token. */
2638
+ if (!cursor.lexer.eof(&cursor.lexer))
2639
+ step(&cursor.lexer);
2640
+ if (next.flow && !layout_token(cursor.lexer.result_symbol))
2641
+ skip_layout(&cursor.lexer);
2642
+ next.column = cursor.marked_column;
2643
+ next.separated = cursor.marked_separation;
2644
+ if (cursor.marked_characters) {
2645
+ next.block_kind = 0;
2646
+ advance_keys(&next, cursor.marked_characters, cursor.marked_broken);
2647
+ next.boundary = 0;
2648
+ next.boundary_checked = false;
2649
+ if (!layout_token(cursor.lexer.result_symbol))
2650
+ next.line = false;
2651
+ }
2652
+ lexer->result_symbol = cursor.lexer.result_symbol;
2653
+ *(Scanner *)payload = next;
2654
+ return true;
2655
+ }