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