tree-sitter-sed 0.7.0 → 0.8.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 +43 -0
- package/README.md +6 -4
- package/bindings/rust/build.rs +40 -0
- package/bindings/rust/lib.rs +70 -0
- package/common/grammar.js +213 -257
- package/common/regex.js +38 -92
- package/common/scanner.h +766 -1112
- package/package.json +7 -8
- package/queries/highlights.scm +2 -5
- package/sed_ere/queries/highlights.scm +2 -5
- package/sed_ere/src/grammar.json +724 -1282
- package/sed_ere/src/node-types.json +56 -58
- package/sed_ere/src/parser.c +28115 -37718
- package/src/grammar.json +655 -1101
- package/src/node-types.json +57 -49
- package/src/parser.c +31870 -41448
- package/tree-sitter.json +3 -3
- package/CMakeLists.txt +0 -121
- package/Makefile +0 -145
- package/bindings/c/tree-sitter-sed.pc.in +0 -10
- package/bindings/c/tree_sitter/tree-sitter-sed.h +0 -17
- package/test/binding.test.c +0 -9
package/common/scanner.h
CHANGED
|
@@ -110,6 +110,7 @@ enum TokenType {
|
|
|
110
110
|
INVALID_SUBSTITUTION_FLAG,
|
|
111
111
|
FLAG_AFTER_WRITE_MARKER,
|
|
112
112
|
TEXT_COMMAND_START,
|
|
113
|
+
TEXT_INCOMPLETE_INTRODUCER,
|
|
113
114
|
TEXT_LITERAL,
|
|
114
115
|
TEXT_BACKSLASH_ESCAPE,
|
|
115
116
|
TEXT_ESCAPED_NEWLINE,
|
|
@@ -121,7 +122,9 @@ enum TokenType {
|
|
|
121
122
|
FILE_ARGUMENT,
|
|
122
123
|
SUBSTITUTION_WFILE_ARGUMENT,
|
|
123
124
|
LINE_WORD,
|
|
125
|
+
ARGUMENT_SEPARATOR,
|
|
124
126
|
RIGHT_BRACE,
|
|
127
|
+
EMPTY_COMMAND_MARKER,
|
|
125
128
|
RESERVED_UNKNOWN_FUNCTION_TOKEN,
|
|
126
129
|
REGEX_INCOMPLETE_GROUP,
|
|
127
130
|
REGEX_INCOMPLETE_BRACKET_TERM,
|
|
@@ -193,14 +196,6 @@ enum TextState {
|
|
|
193
196
|
TEXT_AFTER_ESCAPED_NEWLINE,
|
|
194
197
|
};
|
|
195
198
|
|
|
196
|
-
enum RegexIntervalState {
|
|
197
|
-
REGEX_INTERVAL_NONE,
|
|
198
|
-
REGEX_INTERVAL_EXPECT_MINIMUM,
|
|
199
|
-
REGEX_INTERVAL_AFTER_MINIMUM,
|
|
200
|
-
REGEX_INTERVAL_EXPECT_MAXIMUM,
|
|
201
|
-
REGEX_INTERVAL_AFTER_MAXIMUM,
|
|
202
|
-
};
|
|
203
|
-
|
|
204
199
|
enum RegexDuplicationState {
|
|
205
200
|
REGEX_DUPLICATION_NONE,
|
|
206
201
|
REGEX_AFTER_DUPLICATION_SYMBOL,
|
|
@@ -231,7 +226,7 @@ typedef struct {
|
|
|
231
226
|
bool regex_after_alternation;
|
|
232
227
|
bool regex_after_anchor;
|
|
233
228
|
enum TextState text_state;
|
|
234
|
-
|
|
229
|
+
bool regex_in_interval;
|
|
235
230
|
enum RegexBracketTermState regex_bracket_term_state;
|
|
236
231
|
enum RegexBracketPendingElement regex_bracket_pending_element;
|
|
237
232
|
enum RegexBracketPendingElement regex_bracket_first_element;
|
|
@@ -242,7 +237,7 @@ typedef struct {
|
|
|
242
237
|
} ScannerState;
|
|
243
238
|
|
|
244
239
|
enum {
|
|
245
|
-
SCANNER_SERIALIZATION_VERSION =
|
|
240
|
+
SCANNER_SERIALIZATION_VERSION = 15,
|
|
246
241
|
SCANNER_SERIALIZED_STATE_SIZE = 17,
|
|
247
242
|
};
|
|
248
243
|
|
|
@@ -286,7 +281,7 @@ static void reset_mode_tracking(ScannerState *state) {
|
|
|
286
281
|
state->regex_after_alternation = false;
|
|
287
282
|
state->regex_after_anchor = false;
|
|
288
283
|
state->text_state = TEXT_EMPTY;
|
|
289
|
-
state->
|
|
284
|
+
state->regex_in_interval = false;
|
|
290
285
|
reset_bracket_tracking(state);
|
|
291
286
|
state->regex_group_depth = 0;
|
|
292
287
|
}
|
|
@@ -336,7 +331,7 @@ static unsigned sed_scanner_serialize(void *payload, char *buffer) {
|
|
|
336
331
|
buffer[6] = (char)((delimiter >> 16) & UINT32_C(0xff));
|
|
337
332
|
buffer[7] = (char)((delimiter >> 24) & UINT32_C(0xff));
|
|
338
333
|
serialize_uint16(buffer, 8, state->regex_group_depth);
|
|
339
|
-
buffer[10] =
|
|
334
|
+
buffer[10] = state->regex_in_interval ? 1 : 0;
|
|
340
335
|
buffer[11] = (char)state->regex_bracket_term_state;
|
|
341
336
|
buffer[12] = (char)state->regex_bracket_pending_element;
|
|
342
337
|
buffer[13] = (char)state->regex_bracket_first_element;
|
|
@@ -371,15 +366,18 @@ static bool regex_position_is_reset(const ScannerState *state) {
|
|
|
371
366
|
!state->regex_after_anchor;
|
|
372
367
|
}
|
|
373
368
|
|
|
374
|
-
|
|
375
|
-
|
|
369
|
+
// Reject NUL and decode errors before emission: they cannot survive delimiter
|
|
370
|
+
// serialization.
|
|
371
|
+
static bool delimiter_character_is_valid(int32_t character) {
|
|
372
|
+
const uint32_t code_point = (uint32_t)character;
|
|
373
|
+
return code_point !=
|
|
376
374
|
0 &&
|
|
377
|
-
|
|
375
|
+
code_point <=
|
|
378
376
|
UINT32_C(0x10ffff) &&
|
|
379
|
-
!(
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
377
|
+
!(code_point >= UINT32_C(0xd800) && code_point <= UINT32_C(0xdfff)) &&
|
|
378
|
+
character !=
|
|
379
|
+
'\\' &&
|
|
380
|
+
character != '\n';
|
|
383
381
|
}
|
|
384
382
|
|
|
385
383
|
static bool deserialized_state_is_valid(const ScannerState *candidate) {
|
|
@@ -395,12 +393,11 @@ static bool deserialized_state_is_valid(const ScannerState *candidate) {
|
|
|
395
393
|
regex_position_is_reset(candidate) &&
|
|
396
394
|
candidate->regex_group_depth ==
|
|
397
395
|
0 &&
|
|
398
|
-
candidate->
|
|
399
|
-
REGEX_INTERVAL_NONE &&
|
|
396
|
+
!candidate->regex_in_interval &&
|
|
400
397
|
bracket_tracking_is_reset(candidate);
|
|
401
398
|
}
|
|
402
399
|
|
|
403
|
-
if (!
|
|
400
|
+
if (!delimiter_character_is_valid(candidate->delimiter)) {
|
|
404
401
|
return false;
|
|
405
402
|
}
|
|
406
403
|
|
|
@@ -410,8 +407,7 @@ static bool deserialized_state_is_valid(const ScannerState *candidate) {
|
|
|
410
407
|
regex_position_is_reset(candidate) &&
|
|
411
408
|
candidate->text_state ==
|
|
412
409
|
TEXT_EMPTY &&
|
|
413
|
-
candidate->
|
|
414
|
-
REGEX_INTERVAL_NONE &&
|
|
410
|
+
!candidate->regex_in_interval &&
|
|
415
411
|
bracket_tracking_is_reset(candidate) &&
|
|
416
412
|
candidate->regex_group_depth == 0;
|
|
417
413
|
}
|
|
@@ -471,7 +467,7 @@ sed_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
|
|
|
471
467
|
.regex_after_anchor = (mode_flags & SERIALIZED_AFTER_ANCHOR_FLAG) != 0,
|
|
472
468
|
.text_state =
|
|
473
469
|
(enum TextState)((mode_flags >> SERIALIZED_TEXT_STATE_SHIFT) & 3U),
|
|
474
|
-
.
|
|
470
|
+
.regex_in_interval = buffer[10] != 0,
|
|
475
471
|
.regex_bracket_term_state =
|
|
476
472
|
(enum RegexBracketTermState)(unsigned char)buffer[11],
|
|
477
473
|
.regex_bracket_pending_element =
|
|
@@ -506,7 +502,7 @@ sed_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
|
|
|
506
502
|
}
|
|
507
503
|
#endif
|
|
508
504
|
|
|
509
|
-
if (
|
|
505
|
+
if ((unsigned char)buffer[10] > 1U) {
|
|
510
506
|
return;
|
|
511
507
|
}
|
|
512
508
|
if (candidate.regex_bracket_term_state > REGEX_BRACKET_TERM_EQUAL) {
|
|
@@ -558,6 +554,11 @@ static void advance(TSLexer *lexer) {
|
|
|
558
554
|
lexer->advance(lexer, false);
|
|
559
555
|
}
|
|
560
556
|
|
|
557
|
+
static void consume(TSLexer *lexer) {
|
|
558
|
+
advance(lexer);
|
|
559
|
+
lexer->mark_end(lexer);
|
|
560
|
+
}
|
|
561
|
+
|
|
561
562
|
static bool is_blank(int32_t character) {
|
|
562
563
|
return character == ' ' || character == '\t';
|
|
563
564
|
}
|
|
@@ -572,12 +573,6 @@ static void advance_past_blanks(TSLexer *lexer) {
|
|
|
572
573
|
}
|
|
573
574
|
}
|
|
574
575
|
|
|
575
|
-
static void advance_past_escaped_character(TSLexer *lexer) {
|
|
576
|
-
if (!lexer->eof(lexer) && lexer->lookahead != '\n') {
|
|
577
|
-
advance(lexer);
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
576
|
static void skip_blanks(TSLexer *lexer) {
|
|
582
577
|
while (is_blank(lexer->lookahead)) {
|
|
583
578
|
lexer->advance(lexer, true);
|
|
@@ -585,12 +580,7 @@ static void skip_blanks(TSLexer *lexer) {
|
|
|
585
580
|
}
|
|
586
581
|
|
|
587
582
|
static bool invalid_delimiter(TSLexer *lexer) {
|
|
588
|
-
return lexer->eof(lexer) ||
|
|
589
|
-
lexer->lookahead ==
|
|
590
|
-
0 ||
|
|
591
|
-
lexer->lookahead ==
|
|
592
|
-
'\\' ||
|
|
593
|
-
lexer->lookahead == '\n';
|
|
583
|
+
return lexer->eof(lexer) || !delimiter_character_is_valid(lexer->lookahead);
|
|
594
584
|
}
|
|
595
585
|
|
|
596
586
|
static bool delimiter_is_missing(TSLexer *lexer) {
|
|
@@ -609,32 +599,41 @@ static bool scan_simple_delimiter(
|
|
|
609
599
|
state->delimiter = lexer->lookahead;
|
|
610
600
|
state->mode = next_mode;
|
|
611
601
|
reset_mode_tracking(state);
|
|
612
|
-
state->regex_at_branch_start =
|
|
613
|
-
|
|
614
|
-
advance(lexer);
|
|
615
|
-
lexer->mark_end(lexer);
|
|
602
|
+
state->regex_at_branch_start = is_regex_mode(next_mode);
|
|
603
|
+
consume(lexer);
|
|
616
604
|
return true;
|
|
617
605
|
}
|
|
618
606
|
|
|
619
|
-
static bool
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
enum ScannerMode next_mode
|
|
623
|
-
) {
|
|
624
|
-
if (lexer->lookahead != state->delimiter) {
|
|
607
|
+
static bool
|
|
608
|
+
emit_symbol(const bool *valid_symbols, TSSymbol candidate, TSSymbol *symbol) {
|
|
609
|
+
if (!valid_symbols[candidate]) {
|
|
625
610
|
return false;
|
|
626
611
|
}
|
|
627
612
|
|
|
628
|
-
|
|
629
|
-
reset_mode_tracking(state);
|
|
630
|
-
if (next_mode == MODE_NONE) {
|
|
631
|
-
state->delimiter = 0;
|
|
632
|
-
}
|
|
633
|
-
advance(lexer);
|
|
634
|
-
lexer->mark_end(lexer);
|
|
613
|
+
*symbol = candidate;
|
|
635
614
|
return true;
|
|
636
615
|
}
|
|
637
616
|
|
|
617
|
+
static bool consume_as(
|
|
618
|
+
TSLexer *lexer,
|
|
619
|
+
const bool *valid_symbols,
|
|
620
|
+
TSSymbol candidate,
|
|
621
|
+
TSSymbol *symbol
|
|
622
|
+
) {
|
|
623
|
+
consume(lexer);
|
|
624
|
+
return emit_symbol(valid_symbols, candidate, symbol);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
static bool end_mode(
|
|
628
|
+
ScannerState *state,
|
|
629
|
+
const bool *valid_symbols,
|
|
630
|
+
TSSymbol candidate,
|
|
631
|
+
TSSymbol *symbol
|
|
632
|
+
) {
|
|
633
|
+
reset_state(state);
|
|
634
|
+
return emit_symbol(valid_symbols, candidate, symbol);
|
|
635
|
+
}
|
|
636
|
+
|
|
638
637
|
static bool scan_active_mode_delimiter(
|
|
639
638
|
TSLexer *lexer,
|
|
640
639
|
ScannerState *state,
|
|
@@ -670,26 +669,15 @@ static bool scan_active_mode_delimiter(
|
|
|
670
669
|
return false;
|
|
671
670
|
}
|
|
672
671
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
) {
|
|
676
|
-
|
|
672
|
+
state->mode = next_mode;
|
|
673
|
+
reset_mode_tracking(state);
|
|
674
|
+
if (next_mode == MODE_NONE) {
|
|
675
|
+
state->delimiter = 0;
|
|
677
676
|
}
|
|
678
|
-
|
|
679
|
-
*symbol = candidate;
|
|
680
|
-
return true;
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
static void consume(TSLexer *lexer) {
|
|
684
|
-
advance(lexer);
|
|
685
|
-
lexer->mark_end(lexer);
|
|
677
|
+
return consume_as(lexer, valid_symbols, candidate, symbol);
|
|
686
678
|
}
|
|
687
679
|
|
|
688
680
|
static bool scan_text_command_start(TSLexer *lexer, ScannerState *state) {
|
|
689
|
-
if (state->mode != MODE_NONE || lexer->lookahead != '\\') {
|
|
690
|
-
return false;
|
|
691
|
-
}
|
|
692
|
-
|
|
693
681
|
lexer->mark_end(lexer);
|
|
694
682
|
advance(lexer);
|
|
695
683
|
|
|
@@ -702,47 +690,23 @@ static bool scan_text_command_start(TSLexer *lexer, ScannerState *state) {
|
|
|
702
690
|
return true;
|
|
703
691
|
}
|
|
704
692
|
|
|
705
|
-
static bool
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
693
|
+
static bool scan_line_rest(TSLexer *lexer, bool ends_at_semicolon) {
|
|
694
|
+
bool consumed = false;
|
|
695
|
+
while (
|
|
696
|
+
!lexer->eof(lexer) &&
|
|
697
|
+
lexer->lookahead !=
|
|
698
|
+
'\n' &&
|
|
699
|
+
!(ends_at_semicolon && lexer->lookahead == ';')
|
|
700
|
+
) {
|
|
711
701
|
consume(lexer);
|
|
712
702
|
consumed = true;
|
|
713
703
|
}
|
|
714
|
-
|
|
715
704
|
return consumed;
|
|
716
705
|
}
|
|
717
706
|
|
|
718
|
-
static bool scan_file_argument(TSLexer *lexer) {
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
) {
|
|
722
|
-
return false;
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
consume(lexer);
|
|
726
|
-
return scan_to_physical_line_end(lexer, true);
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
static bool scan_substitution_wfile_argument(TSLexer *lexer) {
|
|
730
|
-
if (
|
|
731
|
-
lexer->eof(lexer) ||
|
|
732
|
-
is_blank(lexer->lookahead) ||
|
|
733
|
-
lexer->lookahead ==
|
|
734
|
-
'\n' ||
|
|
735
|
-
lexer->lookahead == ';'
|
|
736
|
-
) {
|
|
737
|
-
return false;
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
do {
|
|
741
|
-
consume(lexer);
|
|
742
|
-
} while (
|
|
743
|
-
!lexer->eof(lexer) && lexer->lookahead != '\n' && lexer->lookahead != ';'
|
|
744
|
-
);
|
|
745
|
-
return true;
|
|
707
|
+
static bool scan_file_argument(TSLexer *lexer, bool ends_at_semicolon) {
|
|
708
|
+
return !is_blank(lexer->lookahead) &&
|
|
709
|
+
scan_line_rest(lexer, ends_at_semicolon);
|
|
746
710
|
}
|
|
747
711
|
|
|
748
712
|
enum FlagAfterWriteScan {
|
|
@@ -781,55 +745,13 @@ static enum FlagAfterWriteScan scan_flag_after_write_marker(TSLexer *lexer) {
|
|
|
781
745
|
: FLAG_AFTER_WRITE_FALLBACK;
|
|
782
746
|
}
|
|
783
747
|
|
|
784
|
-
static bool scan_right_brace(TSLexer *lexer, ScannerState *state) {
|
|
785
|
-
if (state->mode != MODE_NONE) {
|
|
786
|
-
return false;
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
skip_blanks(lexer);
|
|
790
|
-
|
|
791
|
-
if (lexer->lookahead != '}') {
|
|
792
|
-
return false;
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
consume(lexer);
|
|
796
|
-
return true;
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
static bool scan_reserved_unknown_function(TSLexer *lexer) {
|
|
800
|
-
const int32_t character = lexer->lookahead;
|
|
801
|
-
if (
|
|
802
|
-
!is_digit(character) &&
|
|
803
|
-
character !=
|
|
804
|
-
'$' &&
|
|
805
|
-
character !=
|
|
806
|
-
'/' &&
|
|
807
|
-
character != '\\'
|
|
808
|
-
) {
|
|
809
|
-
return false;
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
consume(lexer);
|
|
813
|
-
return true;
|
|
814
|
-
}
|
|
815
|
-
|
|
816
748
|
enum LiteralScanResult {
|
|
817
749
|
LITERAL_SCAN_NONE,
|
|
818
750
|
LITERAL_SCAN_TOKEN,
|
|
819
751
|
LITERAL_SCAN_LINE_END,
|
|
820
752
|
};
|
|
821
753
|
|
|
822
|
-
static bool
|
|
823
|
-
emit_symbol(const bool *valid_symbols, TSSymbol candidate, TSSymbol *symbol) {
|
|
824
|
-
if (!valid_symbols[candidate]) {
|
|
825
|
-
return false;
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
*symbol = candidate;
|
|
829
|
-
return true;
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
static bool emit_missing_marker(
|
|
754
|
+
static bool emit_marker(
|
|
833
755
|
TSLexer *lexer,
|
|
834
756
|
const bool *valid_symbols,
|
|
835
757
|
TSSymbol candidate,
|
|
@@ -844,6 +766,15 @@ static bool emit_missing_marker(
|
|
|
844
766
|
return true;
|
|
845
767
|
}
|
|
846
768
|
|
|
769
|
+
static bool can_start_address(TSLexer *lexer) {
|
|
770
|
+
return is_digit(lexer->lookahead) ||
|
|
771
|
+
lexer->lookahead ==
|
|
772
|
+
'$' ||
|
|
773
|
+
lexer->lookahead ==
|
|
774
|
+
'/' ||
|
|
775
|
+
lexer->lookahead == '\\';
|
|
776
|
+
}
|
|
777
|
+
|
|
847
778
|
static bool at_command_boundary(TSLexer *lexer) {
|
|
848
779
|
return lexer->eof(lexer) ||
|
|
849
780
|
lexer->lookahead ==
|
|
@@ -853,13 +784,23 @@ static bool at_command_boundary(TSLexer *lexer) {
|
|
|
853
784
|
lexer->lookahead == '}';
|
|
854
785
|
}
|
|
855
786
|
|
|
856
|
-
static
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
787
|
+
static TSSymbol missing_command_separator_marker(
|
|
788
|
+
const TSLexer *lexer,
|
|
789
|
+
const bool *valid_symbols
|
|
790
|
+
) {
|
|
791
|
+
if (lexer->lookahead == '}') {
|
|
792
|
+
if (valid_symbols[MISSING_SEPARATOR_BEFORE_UNMATCHED_BRACE_MARKER]) {
|
|
793
|
+
return MISSING_SEPARATOR_BEFORE_UNMATCHED_BRACE_MARKER;
|
|
794
|
+
}
|
|
795
|
+
if (valid_symbols[MISSING_COMMAND_SEPARATOR_MARKER]) {
|
|
796
|
+
return MISSING_COMMAND_SEPARATOR_MARKER;
|
|
797
|
+
}
|
|
798
|
+
} else if (
|
|
799
|
+
lexer->eof(lexer) && valid_symbols[INCOMPLETE_COMMAND_SEPARATOR_MARKER]
|
|
800
|
+
) {
|
|
801
|
+
return INCOMPLETE_COMMAND_SEPARATOR_MARKER;
|
|
802
|
+
}
|
|
803
|
+
return ERROR_SENTINEL;
|
|
863
804
|
}
|
|
864
805
|
|
|
865
806
|
enum PostBlankRecoveryScan {
|
|
@@ -913,22 +854,10 @@ static enum PostBlankRecoveryScan scan_post_blank_recovery(
|
|
|
913
854
|
*symbol = MISSING_ADDRESS_SEPARATOR_MARKER;
|
|
914
855
|
return POST_BLANK_RECOVERY_TOKEN;
|
|
915
856
|
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
}
|
|
921
|
-
if (valid_symbols[MISSING_COMMAND_SEPARATOR_MARKER]) {
|
|
922
|
-
*symbol = MISSING_COMMAND_SEPARATOR_MARKER;
|
|
923
|
-
return POST_BLANK_RECOVERY_TOKEN;
|
|
924
|
-
}
|
|
925
|
-
return POST_BLANK_RECOVERY_FAILED;
|
|
926
|
-
}
|
|
927
|
-
if (lexer->eof(lexer) && valid_symbols[INCOMPLETE_COMMAND_SEPARATOR_MARKER]) {
|
|
928
|
-
*symbol = INCOMPLETE_COMMAND_SEPARATOR_MARKER;
|
|
929
|
-
return POST_BLANK_RECOVERY_TOKEN;
|
|
930
|
-
}
|
|
931
|
-
return POST_BLANK_RECOVERY_FAILED;
|
|
857
|
+
// The blanks precede the marker as padding of the brace or the source end.
|
|
858
|
+
*symbol = missing_command_separator_marker(lexer, valid_symbols);
|
|
859
|
+
return *symbol == ERROR_SENTINEL ? POST_BLANK_RECOVERY_FAILED
|
|
860
|
+
: POST_BLANK_RECOVERY_TOKEN;
|
|
932
861
|
}
|
|
933
862
|
|
|
934
863
|
static bool scan_text_token(
|
|
@@ -938,48 +867,25 @@ static bool scan_text_token(
|
|
|
938
867
|
TSSymbol *symbol
|
|
939
868
|
) {
|
|
940
869
|
if (lexer->eof(lexer)) {
|
|
941
|
-
if (state->text_state == TEXT_AFTER_ESCAPED_NEWLINE) {
|
|
942
|
-
if (!emit_missing_marker(
|
|
943
|
-
lexer,
|
|
944
|
-
valid_symbols,
|
|
945
|
-
MISSING_TEXT_MARKER,
|
|
946
|
-
symbol
|
|
947
|
-
)) {
|
|
948
|
-
return false;
|
|
949
|
-
}
|
|
950
|
-
state->text_state = TEXT_HAS_CONTENT;
|
|
951
|
-
return true;
|
|
952
|
-
}
|
|
953
870
|
if (
|
|
954
|
-
state->text_state
|
|
955
|
-
|
|
956
|
-
|
|
871
|
+
state->text_state !=
|
|
872
|
+
TEXT_HAS_CONTENT &&
|
|
873
|
+
emit_marker(lexer, valid_symbols, MISSING_TEXT_MARKER, symbol)
|
|
957
874
|
) {
|
|
958
875
|
state->text_state = TEXT_HAS_CONTENT;
|
|
959
876
|
return true;
|
|
960
877
|
}
|
|
961
|
-
if (!valid_symbols[TEXT_EOF]) {
|
|
962
|
-
return false;
|
|
963
|
-
}
|
|
964
878
|
lexer->mark_end(lexer);
|
|
965
|
-
|
|
966
|
-
*symbol = TEXT_EOF;
|
|
967
|
-
return true;
|
|
879
|
+
return end_mode(state, valid_symbols, TEXT_EOF, symbol);
|
|
968
880
|
}
|
|
969
881
|
|
|
970
882
|
if (lexer->lookahead == '\n') {
|
|
971
|
-
if (!valid_symbols[TEXT_LINE_END]) {
|
|
972
|
-
return false;
|
|
973
|
-
}
|
|
974
883
|
lexer->mark_end(lexer);
|
|
975
|
-
|
|
976
|
-
*symbol = TEXT_LINE_END;
|
|
977
|
-
return true;
|
|
884
|
+
return end_mode(state, valid_symbols, TEXT_LINE_END, symbol);
|
|
978
885
|
}
|
|
979
886
|
|
|
980
887
|
if (lexer->lookahead == '\\') {
|
|
981
|
-
|
|
982
|
-
lexer->mark_end(lexer);
|
|
888
|
+
consume(lexer);
|
|
983
889
|
|
|
984
890
|
if (lexer->eof(lexer)) {
|
|
985
891
|
state->text_state = TEXT_HAS_CONTENT;
|
|
@@ -1001,17 +907,13 @@ static bool scan_text_token(
|
|
|
1001
907
|
return emit_symbol(valid_symbols, TEXT_UNSPECIFIED_ESCAPE, symbol);
|
|
1002
908
|
}
|
|
1003
909
|
|
|
1004
|
-
if (!valid_symbols[TEXT_LITERAL]) {
|
|
1005
|
-
return false;
|
|
1006
|
-
}
|
|
1007
910
|
do {
|
|
1008
911
|
consume(lexer);
|
|
1009
912
|
} while (
|
|
1010
913
|
!lexer->eof(lexer) && lexer->lookahead != '\\' && lexer->lookahead != '\n'
|
|
1011
914
|
);
|
|
1012
915
|
state->text_state = TEXT_HAS_CONTENT;
|
|
1013
|
-
|
|
1014
|
-
return true;
|
|
916
|
+
return emit_symbol(valid_symbols, TEXT_LITERAL, symbol);
|
|
1015
917
|
}
|
|
1016
918
|
|
|
1017
919
|
static bool regex_is_inside_bracket(const ScannerState *state) {
|
|
@@ -1101,16 +1003,6 @@ static void finish_first_bracket_element(ScannerState *state) {
|
|
|
1101
1003
|
}
|
|
1102
1004
|
}
|
|
1103
1005
|
|
|
1104
|
-
static void
|
|
1105
|
-
update_bracket_state_after_literal(ScannerState *state, int32_t character) {
|
|
1106
|
-
if (state->regex_state == REGEX_BRACKET_FIRST) {
|
|
1107
|
-
state->regex_state =
|
|
1108
|
-
character == '^' ? REGEX_BRACKET_AFTER_CARET : REGEX_BRACKET_BODY;
|
|
1109
|
-
} else if (state->regex_state == REGEX_BRACKET_AFTER_CARET) {
|
|
1110
|
-
state->regex_state = REGEX_BRACKET_BODY;
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
1006
|
static bool
|
|
1115
1007
|
regex_literal_boundary(const ScannerState *state, int32_t character) {
|
|
1116
1008
|
if (state->regex_state == REGEX_OUTSIDE_BRACKET) {
|
|
@@ -1162,33 +1054,57 @@ scan_regex_literal(TSLexer *lexer, ScannerState *state) {
|
|
|
1162
1054
|
consume(lexer);
|
|
1163
1055
|
if (regex_is_inside_bracket(state)) {
|
|
1164
1056
|
begin_single_bracket_element(state, character);
|
|
1057
|
+
finish_first_bracket_element(state);
|
|
1165
1058
|
}
|
|
1166
|
-
update_bracket_state_after_literal(state, character);
|
|
1167
1059
|
return LITERAL_SCAN_TOKEN;
|
|
1168
1060
|
}
|
|
1169
1061
|
|
|
1170
1062
|
static TSSymbol
|
|
1171
|
-
|
|
1172
|
-
|
|
1063
|
+
unterminated_mode_symbol(enum ScannerMode mode, bool at_end_of_source) {
|
|
1064
|
+
switch (mode) {
|
|
1065
|
+
case MODE_REGEX_ADDRESS:
|
|
1173
1066
|
return at_end_of_source ? REGEX_UNTERMINATED_ADDRESS
|
|
1174
1067
|
: REGEX_LINE_UNTERMINATED_ADDRESS;
|
|
1068
|
+
case MODE_SUBSTITUTE_PATTERN:
|
|
1069
|
+
return at_end_of_source ? REGEX_UNTERMINATED_SUBSTITUTE
|
|
1070
|
+
: REGEX_LINE_UNTERMINATED_SUBSTITUTE;
|
|
1071
|
+
case MODE_SUBSTITUTE_REPLACEMENT:
|
|
1072
|
+
return at_end_of_source ? REPLACEMENT_UNTERMINATED
|
|
1073
|
+
: REPLACEMENT_LINE_UNTERMINATED;
|
|
1074
|
+
case MODE_TRANSLATE_SOURCE:
|
|
1075
|
+
return at_end_of_source ? TRANSLATE_UNTERMINATED_SOURCE
|
|
1076
|
+
: TRANSLATE_LINE_UNTERMINATED_SOURCE;
|
|
1077
|
+
case MODE_TRANSLATE_DESTINATION:
|
|
1078
|
+
return at_end_of_source ? TRANSLATE_UNTERMINATED_DESTINATION
|
|
1079
|
+
: TRANSLATE_LINE_UNTERMINATED_DESTINATION;
|
|
1080
|
+
case MODE_NONE:
|
|
1081
|
+
case MODE_TEXT:
|
|
1082
|
+
break;
|
|
1175
1083
|
}
|
|
1176
|
-
return
|
|
1177
|
-
: REGEX_LINE_UNTERMINATED_SUBSTITUTE;
|
|
1084
|
+
return ERROR_SENTINEL;
|
|
1178
1085
|
}
|
|
1179
1086
|
|
|
1180
|
-
static
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
TSSymbol
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1087
|
+
static const struct {
|
|
1088
|
+
int32_t marker;
|
|
1089
|
+
TSSymbol open_symbol;
|
|
1090
|
+
TSSymbol close_symbol;
|
|
1091
|
+
} bracket_terms[] = {
|
|
1092
|
+
[REGEX_BRACKET_TERM_COLON] = {':', REGEX_OPEN_COLON, REGEX_COLON_CLOSE},
|
|
1093
|
+
[REGEX_BRACKET_TERM_DOT] = {'.', REGEX_OPEN_DOT, REGEX_DOT_CLOSE},
|
|
1094
|
+
[REGEX_BRACKET_TERM_EQUAL] = {'=', REGEX_OPEN_EQUAL, REGEX_EQUAL_CLOSE},
|
|
1095
|
+
};
|
|
1189
1096
|
|
|
1190
|
-
|
|
1191
|
-
|
|
1097
|
+
static enum RegexBracketTermState bracket_term_for_marker(int32_t character) {
|
|
1098
|
+
for (
|
|
1099
|
+
enum RegexBracketTermState term_state = REGEX_BRACKET_TERM_COLON;
|
|
1100
|
+
term_state <= REGEX_BRACKET_TERM_EQUAL;
|
|
1101
|
+
term_state++
|
|
1102
|
+
) {
|
|
1103
|
+
if (bracket_terms[term_state].marker == character) {
|
|
1104
|
+
return term_state;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
return REGEX_BRACKET_TERM_NONE;
|
|
1192
1108
|
}
|
|
1193
1109
|
|
|
1194
1110
|
static bool scan_regex_bracket_opener(
|
|
@@ -1210,35 +1126,22 @@ static bool scan_regex_bracket_opener(
|
|
|
1210
1126
|
|
|
1211
1127
|
lexer->mark_end(lexer);
|
|
1212
1128
|
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
case ':':
|
|
1217
|
-
candidate = REGEX_OPEN_COLON;
|
|
1218
|
-
term_state = REGEX_BRACKET_TERM_COLON;
|
|
1219
|
-
break;
|
|
1220
|
-
case '.':
|
|
1221
|
-
candidate = REGEX_OPEN_DOT;
|
|
1222
|
-
term_state = REGEX_BRACKET_TERM_DOT;
|
|
1223
|
-
break;
|
|
1224
|
-
case '=':
|
|
1225
|
-
candidate = REGEX_OPEN_EQUAL;
|
|
1226
|
-
term_state = REGEX_BRACKET_TERM_EQUAL;
|
|
1227
|
-
break;
|
|
1228
|
-
default:
|
|
1129
|
+
const enum RegexBracketTermState term_state =
|
|
1130
|
+
bracket_term_for_marker(lexer->lookahead);
|
|
1131
|
+
if (term_state == REGEX_BRACKET_TERM_NONE) {
|
|
1229
1132
|
begin_single_bracket_element(state, '[');
|
|
1230
1133
|
finish_first_bracket_element(state);
|
|
1231
1134
|
return emit_symbol(valid_symbols, REGEX_BRACKET_LITERAL, symbol);
|
|
1232
1135
|
}
|
|
1233
1136
|
|
|
1234
|
-
if (!valid_symbols[candidate]) {
|
|
1235
|
-
return false;
|
|
1236
|
-
}
|
|
1237
1137
|
begin_compound_bracket_element(state);
|
|
1238
1138
|
finish_first_bracket_element(state);
|
|
1239
1139
|
state->regex_bracket_term_state = term_state;
|
|
1240
|
-
|
|
1241
|
-
|
|
1140
|
+
return emit_symbol(
|
|
1141
|
+
valid_symbols,
|
|
1142
|
+
bracket_terms[term_state].open_symbol,
|
|
1143
|
+
symbol
|
|
1144
|
+
);
|
|
1242
1145
|
}
|
|
1243
1146
|
|
|
1244
1147
|
static void record_bracket_term_character(
|
|
@@ -1255,19 +1158,7 @@ static void record_bracket_term_character(
|
|
|
1255
1158
|
}
|
|
1256
1159
|
|
|
1257
1160
|
static bool bracket_meta_character(int32_t character) {
|
|
1258
|
-
return character == '
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
static int32_t
|
|
1262
|
-
bracket_term_close_marker(enum RegexBracketTermState term_state) {
|
|
1263
|
-
switch (term_state) {
|
|
1264
|
-
case REGEX_BRACKET_TERM_COLON:
|
|
1265
|
-
return ':';
|
|
1266
|
-
case REGEX_BRACKET_TERM_DOT:
|
|
1267
|
-
return '.';
|
|
1268
|
-
default:
|
|
1269
|
-
return '=';
|
|
1270
|
-
}
|
|
1161
|
+
return character == '-' || character == ']';
|
|
1271
1162
|
}
|
|
1272
1163
|
|
|
1273
1164
|
static TSSymbol regex_bracket_term_content_symbol(
|
|
@@ -1281,45 +1172,45 @@ static TSSymbol regex_bracket_term_content_symbol(
|
|
|
1281
1172
|
if (character_count > 1U) {
|
|
1282
1173
|
return REGEX_COLL_ELEM_MULTI;
|
|
1283
1174
|
}
|
|
1284
|
-
if (
|
|
1285
|
-
|
|
1286
|
-
REGEX_BRACKET_TERM_DOT &&
|
|
1287
|
-
bracket_meta_character(single_character)
|
|
1288
|
-
) {
|
|
1289
|
-
return REGEX_META_CHAR;
|
|
1175
|
+
if (!bracket_meta_character(single_character)) {
|
|
1176
|
+
return REGEX_COLL_ELEM_SINGLE;
|
|
1290
1177
|
}
|
|
1291
|
-
return
|
|
1178
|
+
return state->regex_bracket_term_state == REGEX_BRACKET_TERM_DOT
|
|
1179
|
+
? REGEX_META_CHAR
|
|
1180
|
+
: REGEX_MALFORMED_BRACKET_TERM;
|
|
1292
1181
|
}
|
|
1293
1182
|
|
|
1294
1183
|
static bool scan_regex_bracket_term_content(
|
|
1295
1184
|
TSLexer *lexer,
|
|
1296
1185
|
ScannerState *state,
|
|
1297
|
-
int32_t close_marker,
|
|
1298
1186
|
const bool *valid_symbols,
|
|
1299
1187
|
TSSymbol *symbol
|
|
1300
1188
|
) {
|
|
1189
|
+
const int32_t close_marker =
|
|
1190
|
+
bracket_terms[state->regex_bracket_term_state].marker;
|
|
1301
1191
|
uint8_t character_count = 0;
|
|
1302
1192
|
int32_t single_character = 0;
|
|
1303
1193
|
bool stopped_at_close = false;
|
|
1194
|
+
bool leading_bracket_is_content =
|
|
1195
|
+
state->regex_bracket_term_state != REGEX_BRACKET_TERM_COLON;
|
|
1304
1196
|
lexer->mark_end(lexer);
|
|
1305
1197
|
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1198
|
+
for (;;) {
|
|
1199
|
+
if (
|
|
1200
|
+
lexer->eof(lexer) ||
|
|
1201
|
+
lexer->lookahead ==
|
|
1202
|
+
'\n' ||
|
|
1203
|
+
(lexer->lookahead == ']' && !leading_bracket_is_content)
|
|
1204
|
+
) {
|
|
1205
|
+
break;
|
|
1206
|
+
}
|
|
1207
|
+
leading_bracket_is_content = false;
|
|
1208
|
+
|
|
1314
1209
|
if (lexer->lookahead == close_marker) {
|
|
1315
1210
|
advance(lexer);
|
|
1316
1211
|
if (lexer->lookahead == ']') {
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
character_count,
|
|
1320
|
-
single_character
|
|
1321
|
-
);
|
|
1322
|
-
return emit_symbol(valid_symbols, candidate, symbol);
|
|
1212
|
+
stopped_at_close = true;
|
|
1213
|
+
break;
|
|
1323
1214
|
}
|
|
1324
1215
|
lexer->mark_end(lexer);
|
|
1325
1216
|
record_bracket_term_character(
|
|
@@ -1327,29 +1218,7 @@ static bool scan_regex_bracket_term_content(
|
|
|
1327
1218
|
&single_character,
|
|
1328
1219
|
close_marker
|
|
1329
1220
|
);
|
|
1330
|
-
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
for (;;) {
|
|
1334
|
-
if (
|
|
1335
|
-
lexer->eof(lexer) || lexer->lookahead == '\n' || lexer->lookahead == ']'
|
|
1336
|
-
) {
|
|
1337
|
-
break;
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
|
-
if (lexer->lookahead == close_marker) {
|
|
1341
|
-
advance(lexer);
|
|
1342
|
-
if (lexer->lookahead == ']') {
|
|
1343
|
-
stopped_at_close = true;
|
|
1344
|
-
break;
|
|
1345
|
-
}
|
|
1346
|
-
lexer->mark_end(lexer);
|
|
1347
|
-
record_bracket_term_character(
|
|
1348
|
-
&character_count,
|
|
1349
|
-
&single_character,
|
|
1350
|
-
close_marker
|
|
1351
|
-
);
|
|
1352
|
-
continue;
|
|
1221
|
+
continue;
|
|
1353
1222
|
}
|
|
1354
1223
|
|
|
1355
1224
|
const int32_t character = lexer->lookahead;
|
|
@@ -1376,154 +1245,112 @@ static bool scan_regex_bracket_term_content(
|
|
|
1376
1245
|
static bool scan_regex_bracket_term_close(
|
|
1377
1246
|
TSLexer *lexer,
|
|
1378
1247
|
ScannerState *state,
|
|
1379
|
-
int32_t marker,
|
|
1380
|
-
TSSymbol candidate,
|
|
1381
1248
|
const bool *valid_symbols,
|
|
1382
1249
|
TSSymbol *symbol
|
|
1383
1250
|
) {
|
|
1384
|
-
if (lexer->lookahead != marker) {
|
|
1385
|
-
return false;
|
|
1386
|
-
}
|
|
1387
|
-
|
|
1388
1251
|
consume(lexer);
|
|
1389
1252
|
if (lexer->lookahead != ']') {
|
|
1390
1253
|
return false;
|
|
1391
1254
|
}
|
|
1255
|
+
const TSSymbol candidate =
|
|
1256
|
+
bracket_terms[state->regex_bracket_term_state].close_symbol;
|
|
1392
1257
|
state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
|
|
1393
1258
|
finish_compound_bracket_element(state);
|
|
1394
1259
|
return emit_symbol(valid_symbols, candidate, symbol);
|
|
1395
1260
|
}
|
|
1396
1261
|
|
|
1397
|
-
|
|
1398
|
-
REGEX_INTERVAL_PART_END,
|
|
1399
|
-
REGEX_INTERVAL_PART_ESCAPED_CLOSE,
|
|
1400
|
-
REGEX_INTERVAL_PART_INVALID,
|
|
1401
|
-
};
|
|
1402
|
-
|
|
1403
|
-
static enum RegexIntervalPartResult scan_regex_interval_digits(
|
|
1404
|
-
TSLexer *lexer,
|
|
1405
|
-
const ScannerState *state,
|
|
1406
|
-
bool escaped_close,
|
|
1407
|
-
bool *has_digits
|
|
1408
|
-
) {
|
|
1409
|
-
for (;;) {
|
|
1410
|
-
if (is_digit(lexer->lookahead) && lexer->lookahead != state->delimiter) {
|
|
1411
|
-
advance(lexer);
|
|
1412
|
-
if (has_digits != NULL) {
|
|
1413
|
-
*has_digits = true;
|
|
1414
|
-
}
|
|
1415
|
-
continue;
|
|
1416
|
-
}
|
|
1417
|
-
|
|
1418
|
-
if (escaped_close && lexer->lookahead == '\\') {
|
|
1419
|
-
advance(lexer);
|
|
1420
|
-
if (lexer->lookahead == '}' && state->delimiter != '}') {
|
|
1421
|
-
return REGEX_INTERVAL_PART_ESCAPED_CLOSE;
|
|
1422
|
-
}
|
|
1423
|
-
advance_past_escaped_character(lexer);
|
|
1424
|
-
return REGEX_INTERVAL_PART_INVALID;
|
|
1425
|
-
}
|
|
1426
|
-
|
|
1427
|
-
return REGEX_INTERVAL_PART_END;
|
|
1428
|
-
}
|
|
1429
|
-
}
|
|
1430
|
-
|
|
1431
|
-
static bool
|
|
1432
|
-
scan_regex_interval_separator(TSLexer *lexer, const ScannerState *state) {
|
|
1433
|
-
if (lexer->lookahead != ',' || state->delimiter == ',') {
|
|
1434
|
-
return false;
|
|
1435
|
-
}
|
|
1436
|
-
|
|
1437
|
-
advance(lexer);
|
|
1438
|
-
return true;
|
|
1439
|
-
}
|
|
1440
|
-
|
|
1441
|
-
static bool scan_regex_interval_tail(
|
|
1262
|
+
static bool scan_regex_interval_open(
|
|
1442
1263
|
TSLexer *lexer,
|
|
1443
|
-
|
|
1444
|
-
bool
|
|
1264
|
+
ScannerState *state,
|
|
1265
|
+
const bool *valid_symbols,
|
|
1266
|
+
TSSymbol *symbol
|
|
1445
1267
|
) {
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
if (result == REGEX_INTERVAL_PART_INVALID) {
|
|
1450
|
-
return false;
|
|
1451
|
-
}
|
|
1452
|
-
if (result == REGEX_INTERVAL_PART_ESCAPED_CLOSE) {
|
|
1453
|
-
advance(lexer);
|
|
1454
|
-
return has_minimum;
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
const bool has_separator = scan_regex_interval_separator(lexer, state);
|
|
1458
|
-
if (!has_minimum) {
|
|
1459
|
-
return false;
|
|
1460
|
-
}
|
|
1461
|
-
|
|
1462
|
-
if (has_separator) {
|
|
1463
|
-
result = scan_regex_interval_digits(lexer, state, escaped_close, NULL);
|
|
1464
|
-
if (result == REGEX_INTERVAL_PART_INVALID) {
|
|
1465
|
-
return false;
|
|
1466
|
-
}
|
|
1467
|
-
if (result == REGEX_INTERVAL_PART_ESCAPED_CLOSE) {
|
|
1468
|
-
advance(lexer);
|
|
1469
|
-
return true;
|
|
1470
|
-
}
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
if (escaped_close) {
|
|
1474
|
-
if (lexer->lookahead != '\\') {
|
|
1475
|
-
return false;
|
|
1476
|
-
}
|
|
1477
|
-
advance(lexer);
|
|
1478
|
-
if (lexer->lookahead != '}' || state->delimiter == '}') {
|
|
1479
|
-
advance_past_escaped_character(lexer);
|
|
1480
|
-
return false;
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
if (lexer->lookahead != '}' || state->delimiter == '}') {
|
|
1485
|
-
return false;
|
|
1486
|
-
}
|
|
1487
|
-
|
|
1488
|
-
advance(lexer);
|
|
1489
|
-
return true;
|
|
1268
|
+
consume(lexer);
|
|
1269
|
+
state->regex_in_interval = true;
|
|
1270
|
+
return emit_symbol(valid_symbols, REGEX_INTERVAL_OPEN, symbol);
|
|
1490
1271
|
}
|
|
1491
1272
|
|
|
1492
|
-
static bool
|
|
1493
|
-
TSLexer *lexer,
|
|
1273
|
+
static bool end_interval(
|
|
1494
1274
|
ScannerState *state,
|
|
1495
1275
|
const bool *valid_symbols,
|
|
1276
|
+
TSSymbol candidate,
|
|
1496
1277
|
TSSymbol *symbol
|
|
1497
1278
|
) {
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
state->regex_interval_state = REGEX_INTERVAL_EXPECT_MINIMUM;
|
|
1501
|
-
return emit_symbol(valid_symbols, REGEX_INTERVAL_OPEN, symbol);
|
|
1279
|
+
state->regex_in_interval = false;
|
|
1280
|
+
return emit_symbol(valid_symbols, candidate, symbol);
|
|
1502
1281
|
}
|
|
1503
1282
|
|
|
1504
|
-
static bool
|
|
1283
|
+
static bool scan_regex_interval_close(
|
|
1505
1284
|
TSLexer *lexer,
|
|
1506
1285
|
ScannerState *state,
|
|
1507
|
-
|
|
1286
|
+
const bool *valid_symbols,
|
|
1508
1287
|
TSSymbol *symbol
|
|
1509
1288
|
) {
|
|
1510
|
-
|
|
1511
|
-
state
|
|
1512
|
-
*symbol = candidate;
|
|
1513
|
-
return true;
|
|
1289
|
+
consume(lexer);
|
|
1290
|
+
return end_interval(state, valid_symbols, REGEX_INTERVAL_CLOSE, symbol);
|
|
1514
1291
|
}
|
|
1515
1292
|
|
|
1293
|
+
#if !SED_REGEX_EXTENDED
|
|
1294
|
+
// A BRE escape that ends malformed interval content: the interval close and
|
|
1295
|
+
// the subexpression delimiters own source of their own, unless the escaped
|
|
1296
|
+
// character is the RE delimiter and the escape is that literal character.
|
|
1516
1297
|
static bool
|
|
1517
|
-
|
|
1298
|
+
interval_escape_ends_content(const ScannerState *state, int32_t escaped) {
|
|
1299
|
+
return (escaped == '}' || escaped == '(' || escaped == ')') &&
|
|
1300
|
+
escaped != state->delimiter;
|
|
1301
|
+
}
|
|
1302
|
+
#endif
|
|
1303
|
+
|
|
1304
|
+
static void finish_malformed_escape(TSLexer *lexer) {
|
|
1305
|
+
if (!lexer->eof(lexer) && lexer->lookahead != '\n') {
|
|
1306
|
+
advance(lexer);
|
|
1307
|
+
}
|
|
1308
|
+
lexer->mark_end(lexer);
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
// Leave independently parsed constructs outside the malformed interval token
|
|
1312
|
+
// so recovery preserves their source ownership.
|
|
1313
|
+
static void
|
|
1314
|
+
scan_malformed_interval_content(TSLexer *lexer, const ScannerState *state) {
|
|
1315
|
+
for (;;) {
|
|
1316
|
+
const int32_t character = lexer->lookahead;
|
|
1317
|
+
if (
|
|
1318
|
+
lexer->eof(lexer) ||
|
|
1319
|
+
character ==
|
|
1320
|
+
'\n' ||
|
|
1321
|
+
character ==
|
|
1322
|
+
state->delimiter ||
|
|
1323
|
+
character == '['
|
|
1324
|
+
) {
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
#if SED_REGEX_EXTENDED
|
|
1328
|
+
if (
|
|
1329
|
+
character ==
|
|
1330
|
+
'}' ||
|
|
1331
|
+
character ==
|
|
1332
|
+
'(' ||
|
|
1333
|
+
character ==
|
|
1334
|
+
')' ||
|
|
1335
|
+
character == '|'
|
|
1336
|
+
) {
|
|
1337
|
+
return;
|
|
1338
|
+
}
|
|
1339
|
+
#endif
|
|
1340
|
+
if (character != '\\') {
|
|
1341
|
+
consume(lexer);
|
|
1342
|
+
continue;
|
|
1343
|
+
}
|
|
1518
1344
|
|
|
1345
|
+
advance(lexer);
|
|
1519
1346
|
#if !SED_REGEX_EXTENDED
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
const bool *valid_symbols,
|
|
1524
|
-
TSSymbol *symbol
|
|
1525
|
-
);
|
|
1347
|
+
if (interval_escape_ends_content(state, lexer->lookahead)) {
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1526
1350
|
#endif
|
|
1351
|
+
finish_malformed_escape(lexer);
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1527
1354
|
|
|
1528
1355
|
static bool raw_duplication_symbol_follows(
|
|
1529
1356
|
const TSLexer *lexer,
|
|
@@ -1541,84 +1368,28 @@ static bool raw_duplication_symbol_follows(
|
|
|
1541
1368
|
#endif
|
|
1542
1369
|
}
|
|
1543
1370
|
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
DUPLICATION_CONTEXT_CONSUMED,
|
|
1548
|
-
};
|
|
1549
|
-
|
|
1550
|
-
static enum DuplicationContextScan scan_regex_duplication_context_marker(
|
|
1551
|
-
TSLexer *lexer,
|
|
1552
|
-
ScannerState *state,
|
|
1553
|
-
const bool *valid_symbols,
|
|
1554
|
-
TSSymbol *symbol
|
|
1371
|
+
static TSSymbol regex_duplication_context_marker(
|
|
1372
|
+
const TSLexer *lexer,
|
|
1373
|
+
const ScannerState *state
|
|
1555
1374
|
) {
|
|
1556
|
-
TSSymbol candidate;
|
|
1557
1375
|
if (state->regex_at_branch_start) {
|
|
1558
|
-
|
|
1559
|
-
} else if (state->regex_duplication_state != REGEX_DUPLICATION_NONE) {
|
|
1560
|
-
#if SED_REGEX_EXTENDED
|
|
1561
|
-
if (
|
|
1562
|
-
state->regex_duplication_state ==
|
|
1563
|
-
REGEX_AFTER_DUPLICATION_SYMBOL &&
|
|
1564
|
-
lexer->lookahead == '?'
|
|
1565
|
-
) {
|
|
1566
|
-
return DUPLICATION_CONTEXT_SKIPPED;
|
|
1567
|
-
}
|
|
1568
|
-
#endif
|
|
1569
|
-
candidate = REGEX_ADJACENT_DUPLICATION_MARKER;
|
|
1570
|
-
} else {
|
|
1571
|
-
return DUPLICATION_CONTEXT_SKIPPED;
|
|
1572
|
-
}
|
|
1573
|
-
|
|
1574
|
-
if (!valid_symbols[candidate]) {
|
|
1575
|
-
return DUPLICATION_CONTEXT_SKIPPED;
|
|
1376
|
+
return REGEX_LEADING_DUPLICATION_MARKER;
|
|
1576
1377
|
}
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
if (raw_duplication_symbol_follows(lexer, state)) {
|
|
1580
|
-
*symbol = candidate;
|
|
1581
|
-
return DUPLICATION_CONTEXT_TOKEN;
|
|
1378
|
+
if (state->regex_duplication_state == REGEX_DUPLICATION_NONE) {
|
|
1379
|
+
return ERROR_SENTINEL;
|
|
1582
1380
|
}
|
|
1583
|
-
|
|
1584
1381
|
#if SED_REGEX_EXTENDED
|
|
1585
|
-
if (
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
return DUPLICATION_CONTEXT_TOKEN;
|
|
1382
|
+
if (
|
|
1383
|
+
state->regex_duplication_state ==
|
|
1384
|
+
REGEX_AFTER_DUPLICATION_SYMBOL &&
|
|
1385
|
+
lexer->lookahead == '?'
|
|
1386
|
+
) {
|
|
1387
|
+
return ERROR_SENTINEL;
|
|
1592
1388
|
}
|
|
1593
1389
|
#else
|
|
1594
|
-
|
|
1595
|
-
return DUPLICATION_CONTEXT_SKIPPED;
|
|
1596
|
-
}
|
|
1597
|
-
advance(lexer);
|
|
1598
|
-
if (lexer->lookahead != '{' || state->delimiter == '{') {
|
|
1599
|
-
return scan_regex_after_backslash(lexer, state, valid_symbols, symbol)
|
|
1600
|
-
? DUPLICATION_CONTEXT_TOKEN
|
|
1601
|
-
: DUPLICATION_CONTEXT_CONSUMED;
|
|
1602
|
-
}
|
|
1603
|
-
advance(lexer);
|
|
1604
|
-
if (scan_regex_interval_tail(lexer, state, true)) {
|
|
1605
|
-
*symbol = candidate;
|
|
1606
|
-
return DUPLICATION_CONTEXT_TOKEN;
|
|
1607
|
-
}
|
|
1390
|
+
(void)lexer;
|
|
1608
1391
|
#endif
|
|
1609
|
-
|
|
1610
|
-
if (lexer->eof(lexer) && valid_symbols[REGEX_INCOMPLETE_INTERVAL]) {
|
|
1611
|
-
emit_interval_issue(lexer, state, REGEX_INCOMPLETE_INTERVAL, symbol);
|
|
1612
|
-
return DUPLICATION_CONTEXT_TOKEN;
|
|
1613
|
-
}
|
|
1614
|
-
|
|
1615
|
-
if (!valid_symbols[REGEX_INVALID_INTERVAL]) {
|
|
1616
|
-
*symbol = candidate;
|
|
1617
|
-
return DUPLICATION_CONTEXT_TOKEN;
|
|
1618
|
-
}
|
|
1619
|
-
scan_invalid_interval_remainder(lexer, state);
|
|
1620
|
-
emit_interval_issue(lexer, state, REGEX_INVALID_INTERVAL, symbol);
|
|
1621
|
-
return DUPLICATION_CONTEXT_TOKEN;
|
|
1392
|
+
return REGEX_ADJACENT_DUPLICATION_MARKER;
|
|
1622
1393
|
}
|
|
1623
1394
|
|
|
1624
1395
|
static bool raw_regex_operator_character(int32_t character) {
|
|
@@ -1646,10 +1417,9 @@ static bool scan_raw_regex_operator(
|
|
|
1646
1417
|
|
|
1647
1418
|
if (character == '{') {
|
|
1648
1419
|
#if SED_REGEX_EXTENDED
|
|
1649
|
-
return
|
|
1420
|
+
return scan_regex_interval_open(lexer, state, valid_symbols, symbol);
|
|
1650
1421
|
#else
|
|
1651
|
-
|
|
1652
|
-
return emit_symbol(valid_symbols, REGEX_LITERAL, symbol);
|
|
1422
|
+
return consume_as(lexer, valid_symbols, REGEX_LITERAL, symbol);
|
|
1653
1423
|
#endif
|
|
1654
1424
|
}
|
|
1655
1425
|
|
|
@@ -1724,10 +1494,17 @@ static bool regex_delimiter_is_special(int32_t character) {
|
|
|
1724
1494
|
}
|
|
1725
1495
|
}
|
|
1726
1496
|
|
|
1497
|
+
// The QUOTED_CHAR sequences of XBD 9.5.1 for the selected RE.
|
|
1727
1498
|
static bool escape_quotes_regex_syntax(int32_t character) {
|
|
1728
1499
|
switch (character) {
|
|
1729
1500
|
#if SED_REGEX_EXTENDED
|
|
1501
|
+
case '(':
|
|
1502
|
+
case ')':
|
|
1503
|
+
case '{':
|
|
1730
1504
|
case '}':
|
|
1505
|
+
case '+':
|
|
1506
|
+
case '?':
|
|
1507
|
+
case '|':
|
|
1731
1508
|
#endif
|
|
1732
1509
|
case '.':
|
|
1733
1510
|
case '*':
|
|
@@ -1747,11 +1524,12 @@ static bool scan_regex_escaped_delimiter(
|
|
|
1747
1524
|
const bool *valid_symbols,
|
|
1748
1525
|
TSSymbol *symbol
|
|
1749
1526
|
) {
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
return emit_symbol(
|
|
1527
|
+
return consume_as(
|
|
1528
|
+
lexer,
|
|
1753
1529
|
valid_symbols,
|
|
1754
|
-
|
|
1530
|
+
regex_delimiter_is_special(lexer->lookahead)
|
|
1531
|
+
? REGEX_SPECIAL_ESCAPED_DELIMITER
|
|
1532
|
+
: REGEX_ESCAPED_DELIMITER,
|
|
1755
1533
|
symbol
|
|
1756
1534
|
);
|
|
1757
1535
|
}
|
|
@@ -1777,103 +1555,89 @@ static bool scan_regex_escape_after_backslash(
|
|
|
1777
1555
|
#if !SED_REGEX_EXTENDED
|
|
1778
1556
|
if (lexer->lookahead == '}') {
|
|
1779
1557
|
if (valid_symbols[REGEX_INTERVAL_CLOSE]) {
|
|
1780
|
-
|
|
1781
|
-
state->regex_interval_state = REGEX_INTERVAL_NONE;
|
|
1782
|
-
return emit_symbol(valid_symbols, REGEX_INTERVAL_CLOSE, symbol);
|
|
1558
|
+
return scan_regex_interval_close(lexer, state, valid_symbols, symbol);
|
|
1783
1559
|
}
|
|
1784
1560
|
if (valid_symbols[REGEX_UNMATCHED_INTERVAL_CLOSE]) {
|
|
1785
|
-
|
|
1786
|
-
|
|
1561
|
+
return consume_as(
|
|
1562
|
+
lexer,
|
|
1563
|
+
valid_symbols,
|
|
1564
|
+
REGEX_UNMATCHED_INTERVAL_CLOSE,
|
|
1565
|
+
symbol
|
|
1566
|
+
);
|
|
1787
1567
|
}
|
|
1788
1568
|
}
|
|
1789
|
-
#endif
|
|
1790
1569
|
|
|
1791
|
-
if (lexer->lookahead == '('
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
state->regex_group_depth > 0 ? REGEX_GROUP_CLOSE
|
|
1804
|
-
: REGEX_UNMATCHED_GROUP_CLOSE,
|
|
1805
|
-
symbol
|
|
1806
|
-
);
|
|
1807
|
-
#endif
|
|
1570
|
+
if (lexer->lookahead == '(') {
|
|
1571
|
+
return consume_as(lexer, valid_symbols, REGEX_GROUP_OPEN, symbol);
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
if (lexer->lookahead == ')') {
|
|
1575
|
+
return consume_as(
|
|
1576
|
+
lexer,
|
|
1577
|
+
valid_symbols,
|
|
1578
|
+
state->regex_group_depth > 0 ? REGEX_GROUP_CLOSE
|
|
1579
|
+
: REGEX_UNMATCHED_GROUP_CLOSE,
|
|
1580
|
+
symbol
|
|
1581
|
+
);
|
|
1808
1582
|
}
|
|
1809
1583
|
|
|
1810
1584
|
if (lexer->lookahead >= '1' && lexer->lookahead <= '9') {
|
|
1811
|
-
|
|
1812
|
-
consume(lexer);
|
|
1813
|
-
return emit_symbol(valid_symbols, REGEX_NONPORTABLE_ESCAPE, symbol);
|
|
1814
|
-
#else
|
|
1815
|
-
consume(lexer);
|
|
1816
|
-
return emit_symbol(valid_symbols, REGEX_BACKREFERENCE, symbol);
|
|
1817
|
-
#endif
|
|
1585
|
+
return consume_as(lexer, valid_symbols, REGEX_BACKREFERENCE, symbol);
|
|
1818
1586
|
}
|
|
1819
1587
|
|
|
1820
1588
|
if (lexer->lookahead == '{') {
|
|
1821
|
-
|
|
1822
|
-
consume(lexer);
|
|
1823
|
-
return emit_symbol(valid_symbols, REGEX_QUOTED_ESCAPE, symbol);
|
|
1824
|
-
#else
|
|
1825
|
-
return scan_regex_interval(lexer, state, valid_symbols, symbol);
|
|
1826
|
-
#endif
|
|
1589
|
+
return scan_regex_interval_open(lexer, state, valid_symbols, symbol);
|
|
1827
1590
|
}
|
|
1828
1591
|
|
|
1829
|
-
if (
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
lexer->lookahead ==
|
|
1833
|
-
'?' ||
|
|
1834
|
-
lexer->lookahead == '|'
|
|
1835
|
-
) {
|
|
1836
|
-
#if SED_REGEX_EXTENDED
|
|
1837
|
-
consume(lexer);
|
|
1838
|
-
return emit_symbol(valid_symbols, REGEX_QUOTED_ESCAPE, symbol);
|
|
1839
|
-
#else
|
|
1840
|
-
const int32_t character = lexer->lookahead;
|
|
1841
|
-
consume(lexer);
|
|
1842
|
-
if (character == '|') {
|
|
1843
|
-
return emit_symbol(valid_symbols, REGEX_BRE_VERTICAL_LINE_ESCAPE, symbol);
|
|
1844
|
-
}
|
|
1845
|
-
return emit_symbol(
|
|
1592
|
+
if (lexer->lookahead == '|') {
|
|
1593
|
+
return consume_as(
|
|
1594
|
+
lexer,
|
|
1846
1595
|
valid_symbols,
|
|
1847
|
-
|
|
1596
|
+
REGEX_BRE_VERTICAL_LINE_ESCAPE,
|
|
1597
|
+
symbol
|
|
1598
|
+
);
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
if (lexer->lookahead == '?' || lexer->lookahead == '+') {
|
|
1602
|
+
return consume_as(
|
|
1603
|
+
lexer,
|
|
1604
|
+
valid_symbols,
|
|
1605
|
+
lexer->lookahead == '?' ? REGEX_BRE_QUESTION_MARK_ESCAPE
|
|
1606
|
+
: REGEX_BRE_PLUS_ESCAPE,
|
|
1848
1607
|
symbol
|
|
1849
1608
|
);
|
|
1850
|
-
#endif
|
|
1851
1609
|
}
|
|
1610
|
+
#endif
|
|
1852
1611
|
|
|
1853
1612
|
if (lexer->lookahead == 'n') {
|
|
1854
|
-
|
|
1855
|
-
return emit_symbol(valid_symbols, REGEX_NEWLINE_ESCAPE, symbol);
|
|
1613
|
+
return consume_as(lexer, valid_symbols, REGEX_NEWLINE_ESCAPE, symbol);
|
|
1856
1614
|
}
|
|
1857
1615
|
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1616
|
+
return consume_as(
|
|
1617
|
+
lexer,
|
|
1618
|
+
valid_symbols,
|
|
1619
|
+
escape_quotes_regex_syntax(lexer->lookahead) ? REGEX_QUOTED_ESCAPE
|
|
1620
|
+
: REGEX_NONPORTABLE_ESCAPE,
|
|
1621
|
+
symbol
|
|
1622
|
+
);
|
|
1863
1623
|
}
|
|
1864
1624
|
|
|
1865
1625
|
#if !SED_REGEX_EXTENDED
|
|
1626
|
+
// Scans the escape after a backslash whose token end is marked before it:
|
|
1627
|
+
// "\)" first closes an empty subexpression unless ')' is the delimiter.
|
|
1866
1628
|
static bool scan_regex_after_backslash(
|
|
1867
1629
|
TSLexer *lexer,
|
|
1868
1630
|
ScannerState *state,
|
|
1869
1631
|
const bool *valid_symbols,
|
|
1870
1632
|
TSSymbol *symbol
|
|
1871
1633
|
) {
|
|
1872
|
-
if (
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1634
|
+
if (
|
|
1635
|
+
lexer->lookahead ==
|
|
1636
|
+
')' &&
|
|
1637
|
+
state->delimiter !=
|
|
1638
|
+
')' &&
|
|
1639
|
+
valid_symbols[EMPTY_SUBEXPRESSION_MARKER]
|
|
1640
|
+
) {
|
|
1877
1641
|
*symbol = EMPTY_SUBEXPRESSION_MARKER;
|
|
1878
1642
|
return true;
|
|
1879
1643
|
}
|
|
@@ -1885,7 +1649,7 @@ static bool scan_regex_after_backslash(
|
|
|
1885
1649
|
|
|
1886
1650
|
static bool scan_regex_dup_count(
|
|
1887
1651
|
TSLexer *lexer,
|
|
1888
|
-
ScannerState *state,
|
|
1652
|
+
const ScannerState *state,
|
|
1889
1653
|
const bool *valid_symbols,
|
|
1890
1654
|
TSSymbol *symbol
|
|
1891
1655
|
) {
|
|
@@ -1893,45 +1657,9 @@ static bool scan_regex_dup_count(
|
|
|
1893
1657
|
consume(lexer);
|
|
1894
1658
|
} while (is_digit(lexer->lookahead) && lexer->lookahead != state->delimiter);
|
|
1895
1659
|
|
|
1896
|
-
if (state->regex_interval_state == REGEX_INTERVAL_EXPECT_MINIMUM) {
|
|
1897
|
-
state->regex_interval_state = REGEX_INTERVAL_AFTER_MINIMUM;
|
|
1898
|
-
} else if (state->regex_interval_state == REGEX_INTERVAL_EXPECT_MAXIMUM) {
|
|
1899
|
-
state->regex_interval_state = REGEX_INTERVAL_AFTER_MAXIMUM;
|
|
1900
|
-
}
|
|
1901
|
-
|
|
1902
1660
|
return emit_symbol(valid_symbols, REGEX_DUP_COUNT, symbol);
|
|
1903
1661
|
}
|
|
1904
1662
|
|
|
1905
|
-
static bool
|
|
1906
|
-
scan_invalid_interval_remainder(TSLexer *lexer, ScannerState *state) {
|
|
1907
|
-
bool consumed_character = false;
|
|
1908
|
-
while (
|
|
1909
|
-
!lexer->eof(lexer) &&
|
|
1910
|
-
lexer->lookahead !=
|
|
1911
|
-
'\n' &&
|
|
1912
|
-
lexer->lookahead != state->delimiter
|
|
1913
|
-
) {
|
|
1914
|
-
const int32_t character = lexer->lookahead;
|
|
1915
|
-
consume(lexer);
|
|
1916
|
-
consumed_character = true;
|
|
1917
|
-
if (character == '}') {
|
|
1918
|
-
break;
|
|
1919
|
-
}
|
|
1920
|
-
if (character != '\\' || lexer->eof(lexer) || lexer->lookahead == '\n') {
|
|
1921
|
-
continue;
|
|
1922
|
-
}
|
|
1923
|
-
const int32_t escaped = lexer->lookahead;
|
|
1924
|
-
consume(lexer);
|
|
1925
|
-
if (!SED_REGEX_EXTENDED && escaped == '}') {
|
|
1926
|
-
break;
|
|
1927
|
-
}
|
|
1928
|
-
}
|
|
1929
|
-
if (consumed_character) {
|
|
1930
|
-
state->regex_interval_state = REGEX_INTERVAL_NONE;
|
|
1931
|
-
}
|
|
1932
|
-
return consumed_character;
|
|
1933
|
-
}
|
|
1934
|
-
|
|
1935
1663
|
#if SED_REGEX_EXTENDED
|
|
1936
1664
|
static bool scan_empty_regex_construct(
|
|
1937
1665
|
TSLexer *lexer,
|
|
@@ -1946,7 +1674,7 @@ static bool scan_empty_regex_construct(
|
|
|
1946
1674
|
')' &&
|
|
1947
1675
|
valid_symbols[EMPTY_SUBEXPRESSION_MARKER]
|
|
1948
1676
|
) {
|
|
1949
|
-
return
|
|
1677
|
+
return emit_marker(
|
|
1950
1678
|
lexer,
|
|
1951
1679
|
valid_symbols,
|
|
1952
1680
|
EMPTY_SUBEXPRESSION_MARKER,
|
|
@@ -1959,365 +1687,343 @@ static bool scan_empty_regex_construct(
|
|
|
1959
1687
|
'|' ||
|
|
1960
1688
|
(state->regex_group_depth > 0 && lexer->lookahead == ')'))
|
|
1961
1689
|
) {
|
|
1962
|
-
return
|
|
1963
|
-
lexer,
|
|
1964
|
-
valid_symbols,
|
|
1965
|
-
EMPTY_ALTERNATIVE_MARKER,
|
|
1966
|
-
symbol
|
|
1967
|
-
);
|
|
1690
|
+
return emit_marker(lexer, valid_symbols, EMPTY_ALTERNATIVE_MARKER, symbol);
|
|
1968
1691
|
}
|
|
1969
1692
|
return false;
|
|
1970
1693
|
}
|
|
1971
1694
|
#endif
|
|
1972
1695
|
|
|
1973
|
-
static bool
|
|
1696
|
+
static bool scan_regex_special_token(
|
|
1974
1697
|
TSLexer *lexer,
|
|
1975
1698
|
ScannerState *state,
|
|
1976
1699
|
const bool *valid_symbols,
|
|
1977
1700
|
TSSymbol *symbol
|
|
1978
1701
|
) {
|
|
1979
|
-
|
|
1980
|
-
lexer
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
break;
|
|
1702
|
+
if (lexer->lookahead == '^') {
|
|
1703
|
+
consume(lexer);
|
|
1704
|
+
#if !SED_REGEX_EXTENDED
|
|
1705
|
+
if (!state->regex_at_branch_start || state->regex_after_anchor) {
|
|
1706
|
+
return emit_symbol(valid_symbols, REGEX_LITERAL, symbol);
|
|
1707
|
+
}
|
|
1708
|
+
if (state->regex_group_depth > 0) {
|
|
1709
|
+
return emit_symbol(valid_symbols, REGEX_BRE_SUBEXPRESSION_CARET, symbol);
|
|
1710
|
+
}
|
|
1711
|
+
#endif
|
|
1712
|
+
return emit_symbol(valid_symbols, REGEX_BEGINNING_ANCHOR, symbol);
|
|
1991
1713
|
}
|
|
1992
1714
|
|
|
1715
|
+
if (lexer->lookahead == '$') {
|
|
1716
|
+
consume(lexer);
|
|
1993
1717
|
#if !SED_REGEX_EXTENDED
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1718
|
+
if (lexer->lookahead == '\\') {
|
|
1719
|
+
// A dollar sign anchors a subexpression before "\)", unless ')'
|
|
1720
|
+
// delimits the RE and "\)" is the escaped delimiter.
|
|
1721
|
+
advance(lexer);
|
|
1722
|
+
const bool closes_subexpression = state->regex_group_depth >
|
|
1723
|
+
0 &&
|
|
1724
|
+
lexer->lookahead ==
|
|
1725
|
+
')' &&
|
|
1726
|
+
state->delimiter != ')';
|
|
1727
|
+
return emit_symbol(
|
|
1728
|
+
valid_symbols,
|
|
1729
|
+
closes_subexpression ? REGEX_BRE_SUBEXPRESSION_DOLLAR : REGEX_LITERAL,
|
|
1730
|
+
symbol
|
|
1731
|
+
);
|
|
1732
|
+
}
|
|
1733
|
+
const bool at_branch_end = lexer->eof(lexer) ||
|
|
1734
|
+
lexer->lookahead ==
|
|
1735
|
+
'\n' ||
|
|
1736
|
+
lexer->lookahead == state->delimiter;
|
|
1737
|
+
if (!at_branch_end) {
|
|
1738
|
+
return emit_symbol(valid_symbols, REGEX_LITERAL, symbol);
|
|
1739
|
+
}
|
|
1740
|
+
#endif
|
|
1741
|
+
return emit_symbol(valid_symbols, REGEX_END_ANCHOR, symbol);
|
|
1998
1742
|
}
|
|
1999
|
-
|
|
2000
|
-
if (
|
|
2001
|
-
return
|
|
1743
|
+
|
|
1744
|
+
if (lexer->lookahead == '.') {
|
|
1745
|
+
return consume_as(lexer, valid_symbols, REGEX_PERIOD, symbol);
|
|
2002
1746
|
}
|
|
2003
|
-
#endif
|
|
2004
1747
|
|
|
2005
|
-
if (
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
1748
|
+
if (lexer->lookahead == '\\') {
|
|
1749
|
+
consume(lexer);
|
|
1750
|
+
return scan_regex_escape_after_backslash(
|
|
1751
|
+
lexer,
|
|
1752
|
+
state,
|
|
1753
|
+
valid_symbols,
|
|
1754
|
+
symbol
|
|
1755
|
+
);
|
|
2011
1756
|
}
|
|
2012
1757
|
|
|
1758
|
+
if (raw_regex_operator_character(lexer->lookahead)) {
|
|
1759
|
+
return scan_raw_regex_operator(lexer, state, valid_symbols, symbol);
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
if (lexer->lookahead == '[') {
|
|
1763
|
+
consume(lexer);
|
|
1764
|
+
reset_bracket_tracking(state);
|
|
1765
|
+
state->regex_state = REGEX_BRACKET_FIRST;
|
|
1766
|
+
return emit_symbol(valid_symbols, REGEX_BRACKET_OPEN, symbol);
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
return false;
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
static bool scan_regex_bracket_close(
|
|
1773
|
+
TSLexer *lexer,
|
|
1774
|
+
ScannerState *state,
|
|
1775
|
+
const bool *valid_symbols,
|
|
1776
|
+
TSSymbol *symbol
|
|
1777
|
+
) {
|
|
1778
|
+
commit_pending_bracket_element(state);
|
|
2013
1779
|
if (
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
',' &&
|
|
2017
|
-
lexer->lookahead != state->delimiter
|
|
1780
|
+
bracket_expression_is_ambiguous(state) &&
|
|
1781
|
+
valid_symbols[AMBIGUOUS_BRACKET_EXPRESSION_MARKER]
|
|
2018
1782
|
) {
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
*symbol = REGEX_INTERVAL_SEPARATOR;
|
|
1783
|
+
lexer->mark_end(lexer);
|
|
1784
|
+
*symbol = AMBIGUOUS_BRACKET_EXPRESSION_MARKER;
|
|
2022
1785
|
return true;
|
|
2023
1786
|
}
|
|
2024
1787
|
|
|
2025
|
-
|
|
1788
|
+
consume(lexer);
|
|
1789
|
+
state->regex_state = REGEX_OUTSIDE_BRACKET;
|
|
1790
|
+
reset_bracket_tracking(state);
|
|
1791
|
+
return emit_symbol(valid_symbols, REGEX_BRACKET_CLOSE, symbol);
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
static bool scan_regex_bracket_hyphen(
|
|
1795
|
+
TSLexer *lexer,
|
|
1796
|
+
ScannerState *state,
|
|
1797
|
+
const bool *valid_symbols,
|
|
1798
|
+
TSSymbol *symbol
|
|
1799
|
+
) {
|
|
1800
|
+
lexer->mark_end(lexer);
|
|
1801
|
+
advance(lexer);
|
|
2026
1802
|
if (
|
|
2027
|
-
valid_symbols[
|
|
2028
|
-
lexer->
|
|
2029
|
-
|
|
2030
|
-
|
|
1803
|
+
valid_symbols[NONPORTABLE_RANGE_START_MARKER] &&
|
|
1804
|
+
!lexer->eof(lexer) &&
|
|
1805
|
+
lexer->lookahead !=
|
|
1806
|
+
'\n' &&
|
|
1807
|
+
lexer->lookahead != ']'
|
|
2031
1808
|
) {
|
|
2032
|
-
|
|
2033
|
-
state->regex_interval_state = REGEX_INTERVAL_NONE;
|
|
2034
|
-
*symbol = REGEX_INTERVAL_CLOSE;
|
|
1809
|
+
*symbol = NONPORTABLE_RANGE_START_MARKER;
|
|
2035
1810
|
return true;
|
|
2036
1811
|
}
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
1812
|
+
lexer->mark_end(lexer);
|
|
1813
|
+
|
|
1814
|
+
TSSymbol candidate;
|
|
1815
|
+
if (valid_symbols[REGEX_BRACKET_RANGE_END_HYPHEN]) {
|
|
1816
|
+
candidate = REGEX_BRACKET_RANGE_END_HYPHEN;
|
|
1817
|
+
} else if (
|
|
1818
|
+
lexer->eof(lexer) || lexer->lookahead == '\n' || lexer->lookahead == ']'
|
|
2042
1819
|
) {
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
state
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
if (lexer->eof(lexer) && valid_symbols[REGEX_INCOMPLETE_INTERVAL]) {
|
|
2056
|
-
return emit_interval_issue(
|
|
2057
|
-
lexer,
|
|
2058
|
-
state,
|
|
2059
|
-
REGEX_INCOMPLETE_INTERVAL,
|
|
2060
|
-
symbol
|
|
2061
|
-
);
|
|
2062
|
-
}
|
|
2063
|
-
if (!valid_symbols[REGEX_INVALID_INTERVAL]) {
|
|
2064
|
-
return false;
|
|
2065
|
-
}
|
|
2066
|
-
if (lexer->lookahead == '}') {
|
|
2067
|
-
advance(lexer);
|
|
1820
|
+
candidate = REGEX_BRACKET_TRAILING_HYPHEN;
|
|
1821
|
+
} else {
|
|
1822
|
+
candidate = REGEX_BRACKET_HYPHEN;
|
|
1823
|
+
}
|
|
1824
|
+
if (emit_symbol(valid_symbols, candidate, symbol)) {
|
|
1825
|
+
if (candidate == REGEX_BRACKET_RANGE_END_HYPHEN) {
|
|
1826
|
+
state->regex_bracket_pending_element = REGEX_BRACKET_PENDING_NONE;
|
|
1827
|
+
state->regex_bracket_range_pending = false;
|
|
1828
|
+
record_bracket_element(state, REGEX_BRACKET_PENDING_OTHER);
|
|
1829
|
+
} else if (candidate == REGEX_BRACKET_TRAILING_HYPHEN) {
|
|
1830
|
+
commit_pending_bracket_element(state);
|
|
1831
|
+
record_bracket_element(state, REGEX_BRACKET_PENDING_OTHER);
|
|
2068
1832
|
} else {
|
|
2069
|
-
|
|
2070
|
-
|
|
1833
|
+
state->regex_bracket_pending_element = REGEX_BRACKET_PENDING_NONE;
|
|
1834
|
+
state->regex_bracket_range_pending = true;
|
|
2071
1835
|
}
|
|
2072
|
-
return
|
|
1836
|
+
return true;
|
|
2073
1837
|
}
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
state->regex_interval_state !=
|
|
2078
|
-
REGEX_INTERVAL_NONE &&
|
|
2079
|
-
valid_symbols[REGEX_INVALID_INTERVAL] &&
|
|
2080
|
-
scan_invalid_interval_remainder(lexer, state)
|
|
2081
|
-
) {
|
|
2082
|
-
*symbol = REGEX_INVALID_INTERVAL;
|
|
1838
|
+
if (emit_symbol(valid_symbols, REGEX_SHARED_RANGE_ENDPOINT, symbol)) {
|
|
1839
|
+
commit_pending_bracket_element(state);
|
|
1840
|
+
state->regex_bracket_range_pending = false;
|
|
2083
1841
|
return true;
|
|
2084
1842
|
}
|
|
1843
|
+
return false;
|
|
1844
|
+
}
|
|
2085
1845
|
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
)
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
1846
|
+
static bool scan_regex_bracket_special_token(
|
|
1847
|
+
TSLexer *lexer,
|
|
1848
|
+
ScannerState *state,
|
|
1849
|
+
const bool *valid_symbols,
|
|
1850
|
+
TSSymbol *symbol
|
|
1851
|
+
) {
|
|
1852
|
+
if (state->regex_state == REGEX_BRACKET_FIRST && lexer->lookahead == '^') {
|
|
1853
|
+
consume(lexer);
|
|
1854
|
+
state->regex_state = REGEX_BRACKET_AFTER_CARET;
|
|
1855
|
+
return emit_symbol(valid_symbols, REGEX_BRACKET_NEGATION, symbol);
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
if (state->regex_state == REGEX_BRACKET_BODY && lexer->lookahead == ']') {
|
|
1859
|
+
return scan_regex_bracket_close(lexer, state, valid_symbols, symbol);
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
if (state->regex_state == REGEX_BRACKET_BODY && lexer->lookahead == '-') {
|
|
1863
|
+
return scan_regex_bracket_hyphen(lexer, state, valid_symbols, symbol);
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
if (lexer->lookahead == '[') {
|
|
1867
|
+
return scan_regex_bracket_opener(lexer, state, valid_symbols, symbol);
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
return false;
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
static bool scan_regex_token(
|
|
1874
|
+
TSLexer *lexer,
|
|
1875
|
+
ScannerState *state,
|
|
1876
|
+
const bool *valid_symbols,
|
|
1877
|
+
TSSymbol *symbol
|
|
1878
|
+
) {
|
|
1879
|
+
// The marker precedes the duplication symbol, whose interval is then
|
|
1880
|
+
// scanned like any other so that malformed content keeps its structure.
|
|
1881
|
+
const TSSymbol marker = regex_duplication_context_marker(lexer, state);
|
|
1882
|
+
if (marker != ERROR_SENTINEL && valid_symbols[marker]) {
|
|
1883
|
+
lexer->mark_end(lexer);
|
|
1884
|
+
#if SED_REGEX_EXTENDED
|
|
2102
1885
|
if (
|
|
2103
|
-
state->
|
|
2104
|
-
REGEX_BRACKET_TERM_NONE &&
|
|
2105
|
-
lexer->lookahead ==
|
|
2106
|
-
']' &&
|
|
2107
|
-
valid_symbols[REGEX_MALFORMED_BRACKET_TERM]
|
|
1886
|
+
raw_duplication_symbol_follows(lexer, state) || lexer->lookahead == '{'
|
|
2108
1887
|
) {
|
|
2109
|
-
|
|
2110
|
-
state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
|
|
2111
|
-
finish_compound_bracket_element(state);
|
|
2112
|
-
*symbol = REGEX_MALFORMED_BRACKET_TERM;
|
|
1888
|
+
*symbol = marker;
|
|
2113
1889
|
return true;
|
|
2114
1890
|
}
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
':',
|
|
2120
|
-
REGEX_COLON_CLOSE,
|
|
2121
|
-
valid_symbols,
|
|
2122
|
-
symbol
|
|
2123
|
-
);
|
|
2124
|
-
}
|
|
2125
|
-
if (valid_symbols[REGEX_DOT_CLOSE] && lexer->lookahead == '.') {
|
|
2126
|
-
return scan_regex_bracket_term_close(
|
|
2127
|
-
lexer,
|
|
2128
|
-
state,
|
|
2129
|
-
'.',
|
|
2130
|
-
REGEX_DOT_CLOSE,
|
|
2131
|
-
valid_symbols,
|
|
2132
|
-
symbol
|
|
2133
|
-
);
|
|
1891
|
+
#else
|
|
1892
|
+
if (raw_duplication_symbol_follows(lexer, state)) {
|
|
1893
|
+
*symbol = marker;
|
|
1894
|
+
return true;
|
|
2134
1895
|
}
|
|
2135
|
-
if (
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
symbol
|
|
2143
|
-
);
|
|
1896
|
+
if (lexer->lookahead == '\\') {
|
|
1897
|
+
advance(lexer);
|
|
1898
|
+
if (lexer->lookahead == '{' && state->delimiter != '{') {
|
|
1899
|
+
*symbol = marker;
|
|
1900
|
+
return true;
|
|
1901
|
+
}
|
|
1902
|
+
return scan_regex_after_backslash(lexer, state, valid_symbols, symbol);
|
|
2144
1903
|
}
|
|
1904
|
+
#endif
|
|
2145
1905
|
}
|
|
2146
1906
|
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
return emit_symbol(
|
|
2151
|
-
valid_symbols,
|
|
2152
|
-
inside_bracket ? REGEX_BRACKET_LITERAL : REGEX_LITERAL,
|
|
2153
|
-
symbol
|
|
2154
|
-
);
|
|
2155
|
-
}
|
|
2156
|
-
if (literal_result == LITERAL_SCAN_LINE_END) {
|
|
2157
|
-
return emit_unterminated(
|
|
2158
|
-
state,
|
|
2159
|
-
valid_symbols,
|
|
2160
|
-
regex_unterminated_symbol(state->mode, lexer->eof(lexer)),
|
|
2161
|
-
symbol
|
|
2162
|
-
);
|
|
1907
|
+
#if SED_REGEX_EXTENDED
|
|
1908
|
+
if (scan_empty_regex_construct(lexer, state, valid_symbols, symbol)) {
|
|
1909
|
+
return true;
|
|
2163
1910
|
}
|
|
2164
|
-
|
|
2165
|
-
if (state->regex_state == REGEX_OUTSIDE_BRACKET) {
|
|
2166
|
-
if (lexer->lookahead == '^') {
|
|
2167
|
-
consume(lexer);
|
|
2168
|
-
#if !SED_REGEX_EXTENDED
|
|
2169
|
-
if (
|
|
2170
|
-
state->regex_group_depth >
|
|
2171
|
-
0 &&
|
|
2172
|
-
state->regex_at_branch_start &&
|
|
2173
|
-
!state->regex_after_anchor
|
|
2174
|
-
) {
|
|
2175
|
-
return emit_symbol(
|
|
2176
|
-
valid_symbols,
|
|
2177
|
-
REGEX_BRE_SUBEXPRESSION_CARET,
|
|
2178
|
-
symbol
|
|
2179
|
-
);
|
|
2180
|
-
}
|
|
2181
1911
|
#endif
|
|
2182
|
-
const bool is_beginning_anchor = SED_REGEX_EXTENDED ||
|
|
2183
|
-
(state->regex_at_branch_start && !state->regex_after_anchor);
|
|
2184
|
-
const TSSymbol candidate =
|
|
2185
|
-
is_beginning_anchor ? REGEX_BEGINNING_ANCHOR : REGEX_LITERAL;
|
|
2186
|
-
return emit_symbol(valid_symbols, candidate, symbol);
|
|
2187
|
-
}
|
|
2188
1912
|
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
inspected_bre_escape = true;
|
|
2195
|
-
advance(lexer);
|
|
2196
|
-
if (state->regex_group_depth > 0 && lexer->lookahead == ')') {
|
|
2197
|
-
return emit_symbol(
|
|
2198
|
-
valid_symbols,
|
|
2199
|
-
REGEX_BRE_SUBEXPRESSION_DOLLAR,
|
|
2200
|
-
symbol
|
|
2201
|
-
);
|
|
2202
|
-
}
|
|
2203
|
-
}
|
|
2204
|
-
#endif
|
|
2205
|
-
const bool at_branch_end = SED_REGEX_EXTENDED ||
|
|
2206
|
-
(!inspected_bre_escape &&
|
|
2207
|
-
(lexer->eof(lexer) ||
|
|
2208
|
-
lexer->lookahead ==
|
|
2209
|
-
'\n' ||
|
|
2210
|
-
lexer->lookahead == state->delimiter));
|
|
2211
|
-
const TSSymbol candidate =
|
|
2212
|
-
at_branch_end ? REGEX_END_ANCHOR : REGEX_LITERAL;
|
|
2213
|
-
return emit_symbol(valid_symbols, candidate, symbol);
|
|
2214
|
-
}
|
|
1913
|
+
// The delimiter never reaches this point outside a bracket expression, so
|
|
1914
|
+
// the interval tokens compare only against their own characters.
|
|
1915
|
+
if (valid_symbols[REGEX_DUP_COUNT] && is_digit(lexer->lookahead)) {
|
|
1916
|
+
return scan_regex_dup_count(lexer, state, valid_symbols, symbol);
|
|
1917
|
+
}
|
|
2215
1918
|
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
1919
|
+
if (valid_symbols[REGEX_INTERVAL_SEPARATOR] && lexer->lookahead == ',') {
|
|
1920
|
+
consume(lexer);
|
|
1921
|
+
*symbol = REGEX_INTERVAL_SEPARATOR;
|
|
1922
|
+
return true;
|
|
1923
|
+
}
|
|
2220
1924
|
|
|
2221
|
-
|
|
2222
|
-
|
|
1925
|
+
#if SED_REGEX_EXTENDED
|
|
1926
|
+
if (valid_symbols[REGEX_INTERVAL_CLOSE] && lexer->lookahead == '}') {
|
|
1927
|
+
return scan_regex_interval_close(lexer, state, valid_symbols, symbol);
|
|
1928
|
+
}
|
|
1929
|
+
#else
|
|
1930
|
+
if (state->regex_in_interval && lexer->lookahead == '\\') {
|
|
1931
|
+
lexer->mark_end(lexer);
|
|
1932
|
+
advance(lexer);
|
|
1933
|
+
if (
|
|
1934
|
+
valid_symbols[REGEX_INTERVAL_CLOSE] &&
|
|
1935
|
+
lexer->lookahead ==
|
|
1936
|
+
'}' &&
|
|
1937
|
+
lexer->lookahead != state->delimiter
|
|
1938
|
+
) {
|
|
1939
|
+
return scan_regex_interval_close(lexer, state, valid_symbols, symbol);
|
|
1940
|
+
}
|
|
1941
|
+
if (lexer->eof(lexer) && valid_symbols[REGEX_INCOMPLETE_INTERVAL]) {
|
|
2223
1942
|
lexer->mark_end(lexer);
|
|
2224
|
-
return
|
|
2225
|
-
lexer,
|
|
1943
|
+
return end_interval(
|
|
2226
1944
|
state,
|
|
2227
1945
|
valid_symbols,
|
|
1946
|
+
REGEX_INCOMPLETE_INTERVAL,
|
|
2228
1947
|
symbol
|
|
2229
1948
|
);
|
|
2230
1949
|
}
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
if (lexer->lookahead == '[') {
|
|
2237
|
-
consume(lexer);
|
|
2238
|
-
reset_bracket_tracking(state);
|
|
2239
|
-
state->regex_state = REGEX_BRACKET_FIRST;
|
|
2240
|
-
return emit_symbol(valid_symbols, REGEX_BRACKET_OPEN, symbol);
|
|
1950
|
+
// The escape is the first unit of malformed content unless it ends the
|
|
1951
|
+
// content, in which case the issue is empty and the escape follows it.
|
|
1952
|
+
if (!interval_escape_ends_content(state, lexer->lookahead)) {
|
|
1953
|
+
finish_malformed_escape(lexer);
|
|
1954
|
+
scan_malformed_interval_content(lexer, state);
|
|
2241
1955
|
}
|
|
2242
|
-
|
|
2243
|
-
return false;
|
|
1956
|
+
return end_interval(state, valid_symbols, REGEX_INVALID_INTERVAL, symbol);
|
|
2244
1957
|
}
|
|
1958
|
+
#endif
|
|
2245
1959
|
|
|
2246
|
-
if (state->
|
|
2247
|
-
|
|
2248
|
-
state
|
|
2249
|
-
return
|
|
1960
|
+
if (state->regex_in_interval && valid_symbols[REGEX_INVALID_INTERVAL]) {
|
|
1961
|
+
lexer->mark_end(lexer);
|
|
1962
|
+
scan_malformed_interval_content(lexer, state);
|
|
1963
|
+
return end_interval(state, valid_symbols, REGEX_INVALID_INTERVAL, symbol);
|
|
2250
1964
|
}
|
|
2251
1965
|
|
|
2252
|
-
|
|
2253
|
-
|
|
1966
|
+
const bool inside_bracket = regex_is_inside_bracket(state);
|
|
1967
|
+
if (inside_bracket) {
|
|
2254
1968
|
if (
|
|
2255
|
-
|
|
2256
|
-
valid_symbols[
|
|
1969
|
+
valid_symbols[REGEX_CLASS_NAME] ||
|
|
1970
|
+
valid_symbols[REGEX_COLL_ELEM_SINGLE] ||
|
|
1971
|
+
valid_symbols[REGEX_COLL_ELEM_MULTI] ||
|
|
1972
|
+
valid_symbols[REGEX_META_CHAR]
|
|
2257
1973
|
) {
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
1974
|
+
return scan_regex_bracket_term_content(
|
|
1975
|
+
lexer,
|
|
1976
|
+
state,
|
|
1977
|
+
valid_symbols,
|
|
1978
|
+
symbol
|
|
1979
|
+
);
|
|
2261
1980
|
}
|
|
2262
|
-
|
|
2263
|
-
consume(lexer);
|
|
2264
|
-
state->regex_state = REGEX_OUTSIDE_BRACKET;
|
|
2265
|
-
reset_bracket_tracking(state);
|
|
2266
|
-
return emit_symbol(valid_symbols, REGEX_BRACKET_CLOSE, symbol);
|
|
2267
|
-
}
|
|
2268
|
-
|
|
2269
|
-
if (state->regex_state == REGEX_BRACKET_BODY && lexer->lookahead == '-') {
|
|
2270
|
-
lexer->mark_end(lexer);
|
|
2271
|
-
advance(lexer);
|
|
2272
1981
|
if (
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
lexer->lookahead
|
|
2276
|
-
'
|
|
2277
|
-
|
|
1982
|
+
state->regex_bracket_term_state !=
|
|
1983
|
+
REGEX_BRACKET_TERM_NONE &&
|
|
1984
|
+
lexer->lookahead ==
|
|
1985
|
+
']' &&
|
|
1986
|
+
valid_symbols[REGEX_MALFORMED_BRACKET_TERM]
|
|
2278
1987
|
) {
|
|
2279
|
-
|
|
1988
|
+
lexer->mark_end(lexer);
|
|
1989
|
+
state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
|
|
1990
|
+
finish_compound_bracket_element(state);
|
|
1991
|
+
*symbol = REGEX_MALFORMED_BRACKET_TERM;
|
|
2280
1992
|
return true;
|
|
2281
1993
|
}
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
lexer->eof(lexer) || lexer->lookahead == '\n' || lexer->lookahead == ']'
|
|
1994
|
+
if (
|
|
1995
|
+
state->regex_bracket_term_state !=
|
|
1996
|
+
REGEX_BRACKET_TERM_NONE &&
|
|
1997
|
+
valid_symbols[bracket_terms[state->regex_bracket_term_state]
|
|
1998
|
+
.close_symbol] &&
|
|
1999
|
+
lexer->lookahead == bracket_terms[state->regex_bracket_term_state].marker
|
|
2289
2000
|
) {
|
|
2290
|
-
|
|
2291
|
-
} else {
|
|
2292
|
-
candidate = REGEX_BRACKET_HYPHEN;
|
|
2293
|
-
}
|
|
2294
|
-
if (emit_symbol(valid_symbols, candidate, symbol)) {
|
|
2295
|
-
if (candidate == REGEX_BRACKET_RANGE_END_HYPHEN) {
|
|
2296
|
-
state->regex_bracket_pending_element = REGEX_BRACKET_PENDING_NONE;
|
|
2297
|
-
state->regex_bracket_range_pending = false;
|
|
2298
|
-
record_bracket_element(state, REGEX_BRACKET_PENDING_OTHER);
|
|
2299
|
-
} else if (candidate == REGEX_BRACKET_TRAILING_HYPHEN) {
|
|
2300
|
-
commit_pending_bracket_element(state);
|
|
2301
|
-
record_bracket_element(state, REGEX_BRACKET_PENDING_OTHER);
|
|
2302
|
-
} else {
|
|
2303
|
-
state->regex_bracket_pending_element = REGEX_BRACKET_PENDING_NONE;
|
|
2304
|
-
state->regex_bracket_range_pending = true;
|
|
2305
|
-
}
|
|
2306
|
-
return true;
|
|
2307
|
-
}
|
|
2308
|
-
if (emit_symbol(valid_symbols, REGEX_SHARED_RANGE_ENDPOINT, symbol)) {
|
|
2309
|
-
commit_pending_bracket_element(state);
|
|
2310
|
-
state->regex_bracket_range_pending = false;
|
|
2311
|
-
return true;
|
|
2001
|
+
return scan_regex_bracket_term_close(lexer, state, valid_symbols, symbol);
|
|
2312
2002
|
}
|
|
2313
|
-
return false;
|
|
2314
2003
|
}
|
|
2315
2004
|
|
|
2316
|
-
|
|
2317
|
-
|
|
2005
|
+
const enum LiteralScanResult literal_result =
|
|
2006
|
+
scan_regex_literal(lexer, state);
|
|
2007
|
+
if (literal_result == LITERAL_SCAN_TOKEN) {
|
|
2008
|
+
return emit_symbol(
|
|
2009
|
+
valid_symbols,
|
|
2010
|
+
inside_bracket ? REGEX_BRACKET_LITERAL : REGEX_LITERAL,
|
|
2011
|
+
symbol
|
|
2012
|
+
);
|
|
2013
|
+
}
|
|
2014
|
+
if (literal_result == LITERAL_SCAN_LINE_END) {
|
|
2015
|
+
return end_mode(
|
|
2016
|
+
state,
|
|
2017
|
+
valid_symbols,
|
|
2018
|
+
unterminated_mode_symbol(state->mode, lexer->eof(lexer)),
|
|
2019
|
+
symbol
|
|
2020
|
+
);
|
|
2318
2021
|
}
|
|
2319
2022
|
|
|
2320
|
-
|
|
2023
|
+
if (state->regex_state == REGEX_OUTSIDE_BRACKET) {
|
|
2024
|
+
return scan_regex_special_token(lexer, state, valid_symbols, symbol);
|
|
2025
|
+
}
|
|
2026
|
+
return scan_regex_bracket_special_token(lexer, state, valid_symbols, symbol);
|
|
2321
2027
|
}
|
|
2322
2028
|
|
|
2323
2029
|
static enum LiteralScanResult scan_operand_literal(
|
|
@@ -2354,16 +2060,19 @@ static bool scan_replacement_escape(
|
|
|
2354
2060
|
const bool *valid_symbols,
|
|
2355
2061
|
TSSymbol *symbol
|
|
2356
2062
|
) {
|
|
2357
|
-
|
|
2358
|
-
lexer->mark_end(lexer);
|
|
2063
|
+
consume(lexer);
|
|
2359
2064
|
|
|
2360
2065
|
if (lexer->eof(lexer)) {
|
|
2361
2066
|
return emit_symbol(valid_symbols, REPLACEMENT_INCOMPLETE_ESCAPE, symbol);
|
|
2362
2067
|
}
|
|
2363
2068
|
|
|
2364
2069
|
if (lexer->lookahead == '\n') {
|
|
2365
|
-
|
|
2366
|
-
|
|
2070
|
+
return consume_as(
|
|
2071
|
+
lexer,
|
|
2072
|
+
valid_symbols,
|
|
2073
|
+
REPLACEMENT_ESCAPED_NEWLINE,
|
|
2074
|
+
symbol
|
|
2075
|
+
);
|
|
2367
2076
|
}
|
|
2368
2077
|
|
|
2369
2078
|
TSSymbol candidate = REPLACEMENT_ESCAPE_SEQUENCE;
|
|
@@ -2376,8 +2085,12 @@ static bool scan_replacement_escape(
|
|
|
2376
2085
|
'\\' &&
|
|
2377
2086
|
!is_digit(lexer->lookahead)
|
|
2378
2087
|
) {
|
|
2379
|
-
|
|
2380
|
-
|
|
2088
|
+
return consume_as(
|
|
2089
|
+
lexer,
|
|
2090
|
+
valid_symbols,
|
|
2091
|
+
REPLACEMENT_NONPORTABLE_ESCAPE,
|
|
2092
|
+
symbol
|
|
2093
|
+
);
|
|
2381
2094
|
}
|
|
2382
2095
|
if (lexer->lookahead == state->delimiter) {
|
|
2383
2096
|
candidate = state->delimiter == '&'
|
|
@@ -2387,51 +2100,7 @@ static bool scan_replacement_escape(
|
|
|
2387
2100
|
candidate = REPLACEMENT_BACKREFERENCE;
|
|
2388
2101
|
}
|
|
2389
2102
|
|
|
2390
|
-
|
|
2391
|
-
return emit_symbol(valid_symbols, candidate, symbol);
|
|
2392
|
-
}
|
|
2393
|
-
|
|
2394
|
-
static bool scan_replacement_token(
|
|
2395
|
-
TSLexer *lexer,
|
|
2396
|
-
ScannerState *state,
|
|
2397
|
-
const bool *valid_symbols,
|
|
2398
|
-
TSSymbol *symbol
|
|
2399
|
-
) {
|
|
2400
|
-
const enum LiteralScanResult literal_result =
|
|
2401
|
-
scan_operand_literal(lexer, state, true);
|
|
2402
|
-
if (literal_result == LITERAL_SCAN_TOKEN) {
|
|
2403
|
-
return emit_symbol(valid_symbols, REPLACEMENT_LITERAL, symbol);
|
|
2404
|
-
}
|
|
2405
|
-
if (literal_result == LITERAL_SCAN_LINE_END) {
|
|
2406
|
-
return emit_unterminated(
|
|
2407
|
-
state,
|
|
2408
|
-
valid_symbols,
|
|
2409
|
-
lexer->eof(lexer) ? REPLACEMENT_UNTERMINATED
|
|
2410
|
-
: REPLACEMENT_LINE_UNTERMINATED,
|
|
2411
|
-
symbol
|
|
2412
|
-
);
|
|
2413
|
-
}
|
|
2414
|
-
|
|
2415
|
-
if (lexer->lookahead == '\\') {
|
|
2416
|
-
return scan_replacement_escape(lexer, state, valid_symbols, symbol);
|
|
2417
|
-
}
|
|
2418
|
-
|
|
2419
|
-
if (lexer->lookahead == '&') {
|
|
2420
|
-
consume(lexer);
|
|
2421
|
-
return emit_symbol(valid_symbols, REPLACEMENT_MATCH_REFERENCE, symbol);
|
|
2422
|
-
}
|
|
2423
|
-
|
|
2424
|
-
return false;
|
|
2425
|
-
}
|
|
2426
|
-
|
|
2427
|
-
static TSSymbol
|
|
2428
|
-
translate_unterminated_symbol(enum ScannerMode mode, bool at_end_of_source) {
|
|
2429
|
-
if (mode == MODE_TRANSLATE_SOURCE) {
|
|
2430
|
-
return at_end_of_source ? TRANSLATE_UNTERMINATED_SOURCE
|
|
2431
|
-
: TRANSLATE_LINE_UNTERMINATED_SOURCE;
|
|
2432
|
-
}
|
|
2433
|
-
return at_end_of_source ? TRANSLATE_UNTERMINATED_DESTINATION
|
|
2434
|
-
: TRANSLATE_LINE_UNTERMINATED_DESTINATION;
|
|
2103
|
+
return consume_as(lexer, valid_symbols, candidate, symbol);
|
|
2435
2104
|
}
|
|
2436
2105
|
|
|
2437
2106
|
static bool scan_translate_escape(
|
|
@@ -2440,8 +2109,7 @@ static bool scan_translate_escape(
|
|
|
2440
2109
|
const bool *valid_symbols,
|
|
2441
2110
|
TSSymbol *symbol
|
|
2442
2111
|
) {
|
|
2443
|
-
|
|
2444
|
-
lexer->mark_end(lexer);
|
|
2112
|
+
consume(lexer);
|
|
2445
2113
|
|
|
2446
2114
|
if (lexer->eof(lexer)) {
|
|
2447
2115
|
return emit_symbol(valid_symbols, TRANSLATE_INCOMPLETE_ESCAPE, symbol);
|
|
@@ -2451,45 +2119,56 @@ static bool scan_translate_escape(
|
|
|
2451
2119
|
return emit_symbol(valid_symbols, TRANSLATE_NONPORTABLE_ESCAPE, symbol);
|
|
2452
2120
|
}
|
|
2453
2121
|
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
return emit_symbol(valid_symbols, TRANSLATE_NONPORTABLE_ESCAPE, symbol);
|
|
2122
|
+
// "\n" is a newline even when 'n' is the delimiter.
|
|
2123
|
+
TSSymbol candidate;
|
|
2124
|
+
if (lexer->lookahead == 'n' || lexer->lookahead == '\\') {
|
|
2125
|
+
candidate = TRANSLATE_ESCAPE;
|
|
2126
|
+
} else if (lexer->lookahead == state->delimiter) {
|
|
2127
|
+
candidate = TRANSLATE_ESCAPED_DELIMITER;
|
|
2128
|
+
} else {
|
|
2129
|
+
candidate = TRANSLATE_NONPORTABLE_ESCAPE;
|
|
2463
2130
|
}
|
|
2464
|
-
|
|
2465
|
-
? TRANSLATE_ESCAPE
|
|
2466
|
-
: TRANSLATE_ESCAPED_DELIMITER;
|
|
2467
|
-
consume(lexer);
|
|
2468
|
-
return emit_symbol(valid_symbols, candidate, symbol);
|
|
2131
|
+
return consume_as(lexer, valid_symbols, candidate, symbol);
|
|
2469
2132
|
}
|
|
2470
2133
|
|
|
2471
|
-
static bool
|
|
2134
|
+
static bool scan_operand_token(
|
|
2472
2135
|
TSLexer *lexer,
|
|
2473
2136
|
ScannerState *state,
|
|
2474
2137
|
const bool *valid_symbols,
|
|
2475
2138
|
TSSymbol *symbol
|
|
2476
2139
|
) {
|
|
2140
|
+
const bool is_replacement = state->mode == MODE_SUBSTITUTE_REPLACEMENT;
|
|
2477
2141
|
const enum LiteralScanResult literal_result =
|
|
2478
|
-
scan_operand_literal(lexer, state,
|
|
2142
|
+
scan_operand_literal(lexer, state, is_replacement);
|
|
2479
2143
|
if (literal_result == LITERAL_SCAN_TOKEN) {
|
|
2480
|
-
return emit_symbol(
|
|
2144
|
+
return emit_symbol(
|
|
2145
|
+
valid_symbols,
|
|
2146
|
+
is_replacement ? REPLACEMENT_LITERAL : TRANSLATE_LITERAL,
|
|
2147
|
+
symbol
|
|
2148
|
+
);
|
|
2481
2149
|
}
|
|
2482
2150
|
if (literal_result == LITERAL_SCAN_LINE_END) {
|
|
2483
|
-
return
|
|
2151
|
+
return end_mode(
|
|
2484
2152
|
state,
|
|
2485
2153
|
valid_symbols,
|
|
2486
|
-
|
|
2154
|
+
unterminated_mode_symbol(state->mode, lexer->eof(lexer)),
|
|
2487
2155
|
symbol
|
|
2488
2156
|
);
|
|
2489
2157
|
}
|
|
2490
2158
|
|
|
2491
2159
|
if (lexer->lookahead == '\\') {
|
|
2492
|
-
return
|
|
2160
|
+
return is_replacement
|
|
2161
|
+
? scan_replacement_escape(lexer, state, valid_symbols, symbol)
|
|
2162
|
+
: scan_translate_escape(lexer, state, valid_symbols, symbol);
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
if (is_replacement && lexer->lookahead == '&') {
|
|
2166
|
+
return consume_as(
|
|
2167
|
+
lexer,
|
|
2168
|
+
valid_symbols,
|
|
2169
|
+
REPLACEMENT_MATCH_REFERENCE,
|
|
2170
|
+
symbol
|
|
2171
|
+
);
|
|
2493
2172
|
}
|
|
2494
2173
|
|
|
2495
2174
|
return false;
|
|
@@ -2503,19 +2182,19 @@ static bool scan_regex_recovery_marker(
|
|
|
2503
2182
|
) {
|
|
2504
2183
|
#if !SED_REGEX_EXTENDED
|
|
2505
2184
|
if (
|
|
2506
|
-
|
|
2185
|
+
emit_marker(
|
|
2507
2186
|
lexer,
|
|
2508
2187
|
valid_symbols,
|
|
2509
2188
|
BRE_VERTICAL_LINE_ESCAPE_MARKER,
|
|
2510
2189
|
symbol
|
|
2511
2190
|
) ||
|
|
2512
|
-
|
|
2191
|
+
emit_marker(
|
|
2513
2192
|
lexer,
|
|
2514
2193
|
valid_symbols,
|
|
2515
2194
|
BRE_QUESTION_MARK_ESCAPE_MARKER,
|
|
2516
2195
|
symbol
|
|
2517
2196
|
) ||
|
|
2518
|
-
|
|
2197
|
+
emit_marker(lexer, valid_symbols, BRE_PLUS_ESCAPE_MARKER, symbol)
|
|
2519
2198
|
) {
|
|
2520
2199
|
return true;
|
|
2521
2200
|
}
|
|
@@ -2532,7 +2211,7 @@ static bool scan_regex_recovery_marker(
|
|
|
2532
2211
|
0 &&
|
|
2533
2212
|
!state->regex_after_alternation &&
|
|
2534
2213
|
at_regex_end &&
|
|
2535
|
-
|
|
2214
|
+
emit_marker(
|
|
2536
2215
|
lexer,
|
|
2537
2216
|
valid_symbols,
|
|
2538
2217
|
lexer->eof(lexer) ? MISSING_SUBEXPRESSION_MARKER
|
|
@@ -2548,7 +2227,7 @@ static bool scan_regex_recovery_marker(
|
|
|
2548
2227
|
REGEX_BRACKET_FIRST ||
|
|
2549
2228
|
state->regex_state == REGEX_BRACKET_AFTER_CARET) &&
|
|
2550
2229
|
at_line_boundary &&
|
|
2551
|
-
|
|
2230
|
+
emit_marker(
|
|
2552
2231
|
lexer,
|
|
2553
2232
|
valid_symbols,
|
|
2554
2233
|
lexer->eof(lexer) ? INCOMPLETE_BRACKET_LIST_MARKER
|
|
@@ -2563,7 +2242,7 @@ static bool scan_regex_recovery_marker(
|
|
|
2563
2242
|
state->regex_bracket_term_state !=
|
|
2564
2243
|
REGEX_BRACKET_TERM_NONE &&
|
|
2565
2244
|
at_line_boundary &&
|
|
2566
|
-
|
|
2245
|
+
emit_marker(
|
|
2567
2246
|
lexer,
|
|
2568
2247
|
valid_symbols,
|
|
2569
2248
|
lexer->eof(lexer) ? REGEX_INCOMPLETE_BRACKET_TERM
|
|
@@ -2579,7 +2258,7 @@ static bool scan_regex_recovery_marker(
|
|
|
2579
2258
|
if (
|
|
2580
2259
|
regex_is_inside_bracket(state) &&
|
|
2581
2260
|
at_line_boundary &&
|
|
2582
|
-
|
|
2261
|
+
emit_marker(
|
|
2583
2262
|
lexer,
|
|
2584
2263
|
valid_symbols,
|
|
2585
2264
|
lexer->eof(lexer) ? INCOMPLETE_BRACKET_EXPRESSION_MARKER
|
|
@@ -2598,7 +2277,7 @@ static bool scan_regex_recovery_marker(
|
|
|
2598
2277
|
REGEX_OUTSIDE_BRACKET &&
|
|
2599
2278
|
state->regex_after_alternation &&
|
|
2600
2279
|
at_regex_end &&
|
|
2601
|
-
|
|
2280
|
+
emit_marker(
|
|
2602
2281
|
lexer,
|
|
2603
2282
|
valid_symbols,
|
|
2604
2283
|
lexer->eof(lexer) ? INCOMPLETE_ALTERNATIVE_MARKER
|
|
@@ -2612,21 +2291,16 @@ static bool scan_regex_recovery_marker(
|
|
|
2612
2291
|
#endif
|
|
2613
2292
|
|
|
2614
2293
|
if (
|
|
2615
|
-
state->
|
|
2616
|
-
|
|
2617
|
-
(
|
|
2618
|
-
#if !SED_REGEX_EXTENDED
|
|
2619
|
-
|| (state->delimiter == '}' && lexer->lookahead == '\\')
|
|
2620
|
-
#endif
|
|
2621
|
-
) &&
|
|
2622
|
-
emit_missing_marker(
|
|
2294
|
+
state->regex_in_interval &&
|
|
2295
|
+
at_regex_end &&
|
|
2296
|
+
emit_marker(
|
|
2623
2297
|
lexer,
|
|
2624
2298
|
valid_symbols,
|
|
2625
2299
|
lexer->eof(lexer) ? REGEX_INCOMPLETE_INTERVAL : REGEX_INVALID_INTERVAL,
|
|
2626
2300
|
symbol
|
|
2627
2301
|
)
|
|
2628
2302
|
) {
|
|
2629
|
-
state->
|
|
2303
|
+
state->regex_in_interval = false;
|
|
2630
2304
|
return true;
|
|
2631
2305
|
}
|
|
2632
2306
|
|
|
@@ -2636,7 +2310,7 @@ static bool scan_regex_recovery_marker(
|
|
|
2636
2310
|
state->regex_group_depth >
|
|
2637
2311
|
0 &&
|
|
2638
2312
|
at_line_boundary &&
|
|
2639
|
-
|
|
2313
|
+
emit_marker(
|
|
2640
2314
|
lexer,
|
|
2641
2315
|
valid_symbols,
|
|
2642
2316
|
lexer->eof(lexer) ? REGEX_INCOMPLETE_GROUP : REGEX_UNCLOSED_GROUP,
|
|
@@ -2655,60 +2329,86 @@ static TSSymbol missing_text_introducer_symbol(const TSLexer *lexer) {
|
|
|
2655
2329
|
: NONCONFORMING_MISSING_TEXT_INTRODUCER_MARKER;
|
|
2656
2330
|
}
|
|
2657
2331
|
|
|
2332
|
+
// Blanks before a closing brace are padding of the brace token, or of the
|
|
2333
|
+
// missing-brace marker when the source ends after them. Any other
|
|
2334
|
+
// continuation leaves the blank run to the internal lexer.
|
|
2335
|
+
static bool
|
|
2336
|
+
scan_right_brace(TSLexer *lexer, const bool *valid_symbols, TSSymbol *symbol) {
|
|
2337
|
+
skip_blanks(lexer);
|
|
2338
|
+
|
|
2339
|
+
if (lexer->lookahead == '}') {
|
|
2340
|
+
consume(lexer);
|
|
2341
|
+
*symbol = RIGHT_BRACE;
|
|
2342
|
+
return true;
|
|
2343
|
+
}
|
|
2344
|
+
if (lexer->eof(lexer)) {
|
|
2345
|
+
return emit_marker(
|
|
2346
|
+
lexer,
|
|
2347
|
+
valid_symbols,
|
|
2348
|
+
MISSING_CLOSING_BRACE_MARKER,
|
|
2349
|
+
symbol
|
|
2350
|
+
);
|
|
2351
|
+
}
|
|
2352
|
+
return false;
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2658
2355
|
static bool scan_command_token(
|
|
2659
2356
|
TSLexer *lexer,
|
|
2660
2357
|
ScannerState *state,
|
|
2661
2358
|
const bool *valid_symbols,
|
|
2662
2359
|
TSSymbol *symbol
|
|
2663
2360
|
) {
|
|
2664
|
-
if (
|
|
2361
|
+
if (
|
|
2362
|
+
valid_symbols[EMPTY_COMMAND_MARKER] &&
|
|
2363
|
+
(lexer->lookahead == ';' || lexer->lookahead == '\n')
|
|
2364
|
+
) {
|
|
2365
|
+
return emit_marker(lexer, valid_symbols, EMPTY_COMMAND_MARKER, symbol);
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
if (valid_symbols[LINE_WORD] && scan_line_rest(lexer, false)) {
|
|
2665
2369
|
*symbol = LINE_WORD;
|
|
2666
2370
|
return true;
|
|
2667
2371
|
}
|
|
2668
2372
|
|
|
2373
|
+
// The label separator of b and t is exactly one space. It is read before
|
|
2374
|
+
// the post-blank recovery markers, which would otherwise claim the blank in
|
|
2375
|
+
// front of a label that starts with a closing brace.
|
|
2376
|
+
if (valid_symbols[ARGUMENT_SEPARATOR] && lexer->lookahead == ' ') {
|
|
2377
|
+
consume(lexer);
|
|
2378
|
+
*symbol = ARGUMENT_SEPARATOR;
|
|
2379
|
+
return true;
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2669
2382
|
if (valid_symbols[FLAG_AFTER_WRITE_MARKER]) {
|
|
2670
|
-
|
|
2671
|
-
|
|
2383
|
+
switch (scan_flag_after_write_marker(lexer)) {
|
|
2384
|
+
case FLAG_AFTER_WRITE_MATCH:
|
|
2672
2385
|
*symbol = FLAG_AFTER_WRITE_MARKER;
|
|
2673
2386
|
return true;
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
valid_symbols[OMITTED_FILE_SEPARATOR_MARKER]
|
|
2679
|
-
) {
|
|
2680
|
-
*symbol = OMITTED_FILE_SEPARATOR_MARKER;
|
|
2681
|
-
return true;
|
|
2682
|
-
}
|
|
2683
|
-
if (scan == FLAG_AFTER_WRITE_FALLBACK) {
|
|
2684
|
-
return false;
|
|
2387
|
+
case FLAG_AFTER_WRITE_FALLBACK:
|
|
2388
|
+
return emit_symbol(valid_symbols, OMITTED_FILE_SEPARATOR_MARKER, symbol);
|
|
2389
|
+
case FLAG_AFTER_WRITE_NONE:
|
|
2390
|
+
break;
|
|
2685
2391
|
}
|
|
2686
2392
|
}
|
|
2687
2393
|
|
|
2688
2394
|
if (
|
|
2689
2395
|
valid_symbols[SUBSTITUTION_WFILE_ARGUMENT] &&
|
|
2690
|
-
|
|
2396
|
+
scan_file_argument(lexer, true)
|
|
2691
2397
|
) {
|
|
2692
2398
|
*symbol = SUBSTITUTION_WFILE_ARGUMENT;
|
|
2693
2399
|
return true;
|
|
2694
2400
|
}
|
|
2695
2401
|
|
|
2696
|
-
if (valid_symbols[FILE_ARGUMENT] && scan_file_argument(lexer)) {
|
|
2402
|
+
if (valid_symbols[FILE_ARGUMENT] && scan_file_argument(lexer, false)) {
|
|
2697
2403
|
*symbol = FILE_ARGUMENT;
|
|
2698
2404
|
return true;
|
|
2699
2405
|
}
|
|
2700
2406
|
|
|
2701
2407
|
if (
|
|
2702
2408
|
valid_symbols[INVALID_SUBSTITUTION_FLAG] &&
|
|
2409
|
+
!at_command_boundary(lexer) &&
|
|
2703
2410
|
!is_blank(lexer->lookahead) &&
|
|
2704
|
-
!is_substitution_flag_character(lexer->lookahead)
|
|
2705
|
-
lexer->lookahead !=
|
|
2706
|
-
';' &&
|
|
2707
|
-
lexer->lookahead !=
|
|
2708
|
-
'}' &&
|
|
2709
|
-
lexer->lookahead !=
|
|
2710
|
-
'\n' &&
|
|
2711
|
-
!lexer->eof(lexer)
|
|
2411
|
+
!is_substitution_flag_character(lexer->lookahead)
|
|
2712
2412
|
) {
|
|
2713
2413
|
consume(lexer);
|
|
2714
2414
|
*symbol = INVALID_SUBSTITUTION_FLAG;
|
|
@@ -2720,9 +2420,13 @@ static bool scan_command_token(
|
|
|
2720
2420
|
*symbol = TEXT_COMMAND_START;
|
|
2721
2421
|
return true;
|
|
2722
2422
|
}
|
|
2423
|
+
if (lexer->eof(lexer)) {
|
|
2424
|
+
lexer->mark_end(lexer);
|
|
2425
|
+
return emit_symbol(valid_symbols, TEXT_INCOMPLETE_INTRODUCER, symbol);
|
|
2426
|
+
}
|
|
2723
2427
|
return emit_symbol(
|
|
2724
2428
|
valid_symbols,
|
|
2725
|
-
|
|
2429
|
+
NONCONFORMING_MISSING_TEXT_INTRODUCER_MARKER,
|
|
2726
2430
|
symbol
|
|
2727
2431
|
);
|
|
2728
2432
|
}
|
|
@@ -2733,77 +2437,64 @@ static bool scan_command_token(
|
|
|
2733
2437
|
return true;
|
|
2734
2438
|
}
|
|
2735
2439
|
|
|
2736
|
-
if (valid_symbols[COMMENT_TEXT] &&
|
|
2440
|
+
if (valid_symbols[COMMENT_TEXT] && scan_line_rest(lexer, false)) {
|
|
2737
2441
|
*symbol = COMMENT_TEXT;
|
|
2738
2442
|
return true;
|
|
2739
2443
|
}
|
|
2740
2444
|
|
|
2741
2445
|
// Preserve an address interpretation before reserved-function recovery.
|
|
2742
2446
|
if (
|
|
2743
|
-
|
|
2447
|
+
can_start_address(lexer) &&
|
|
2448
|
+
emit_marker(lexer, valid_symbols, MISSING_ADDRESS_SEPARATOR_MARKER, symbol)
|
|
2744
2449
|
) {
|
|
2745
|
-
return
|
|
2746
|
-
lexer,
|
|
2747
|
-
valid_symbols,
|
|
2748
|
-
MISSING_ADDRESS_SEPARATOR_MARKER,
|
|
2749
|
-
symbol
|
|
2750
|
-
);
|
|
2450
|
+
return true;
|
|
2751
2451
|
}
|
|
2752
2452
|
|
|
2753
2453
|
if (
|
|
2754
|
-
valid_symbols[RESERVED_UNKNOWN_FUNCTION_TOKEN] &&
|
|
2755
|
-
scan_reserved_unknown_function(lexer)
|
|
2454
|
+
valid_symbols[RESERVED_UNKNOWN_FUNCTION_TOKEN] && can_start_address(lexer)
|
|
2756
2455
|
) {
|
|
2456
|
+
consume(lexer);
|
|
2757
2457
|
*symbol = RESERVED_UNKNOWN_FUNCTION_TOKEN;
|
|
2758
2458
|
return true;
|
|
2759
2459
|
}
|
|
2760
2460
|
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2461
|
+
static const struct {
|
|
2462
|
+
TSSymbol symbol;
|
|
2463
|
+
enum ScannerMode mode;
|
|
2464
|
+
int32_t required_delimiter;
|
|
2465
|
+
} delimited_openers[] = {
|
|
2466
|
+
{REGEX_ADDRESS_START, MODE_REGEX_ADDRESS, '/'},
|
|
2467
|
+
{ESCAPED_REGEX_ADDRESS_START, MODE_REGEX_ADDRESS, 0},
|
|
2468
|
+
{SUBSTITUTE_START, MODE_SUBSTITUTE_PATTERN, 0},
|
|
2469
|
+
{TRANSLATE_START, MODE_TRANSLATE_SOURCE, 0},
|
|
2470
|
+
};
|
|
2471
|
+
for (
|
|
2472
|
+
unsigned index = 0;
|
|
2473
|
+
index < sizeof(delimited_openers) / sizeof(delimited_openers[0]);
|
|
2474
|
+
index++
|
|
2766
2475
|
) {
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
*symbol =
|
|
2774
|
-
return true;
|
|
2775
|
-
}
|
|
2776
|
-
}
|
|
2777
|
-
|
|
2778
|
-
if (valid_symbols[SUBSTITUTE_START]) {
|
|
2779
|
-
if (scan_simple_delimiter(lexer, state, MODE_SUBSTITUTE_PATTERN)) {
|
|
2780
|
-
*symbol = SUBSTITUTE_START;
|
|
2781
|
-
return true;
|
|
2782
|
-
}
|
|
2783
|
-
}
|
|
2784
|
-
|
|
2785
|
-
if (valid_symbols[TRANSLATE_START]) {
|
|
2786
|
-
if (scan_simple_delimiter(lexer, state, MODE_TRANSLATE_SOURCE)) {
|
|
2787
|
-
*symbol = TRANSLATE_START;
|
|
2476
|
+
const int32_t required = delimited_openers[index].required_delimiter;
|
|
2477
|
+
if (
|
|
2478
|
+
valid_symbols[delimited_openers[index].symbol] &&
|
|
2479
|
+
(required == 0 || lexer->lookahead == required) &&
|
|
2480
|
+
scan_simple_delimiter(lexer, state, delimited_openers[index].mode)
|
|
2481
|
+
) {
|
|
2482
|
+
*symbol = delimited_openers[index].symbol;
|
|
2788
2483
|
return true;
|
|
2789
2484
|
}
|
|
2790
2485
|
}
|
|
2791
2486
|
|
|
2792
|
-
if (
|
|
2793
|
-
|
|
2794
|
-
|
|
2487
|
+
if (
|
|
2488
|
+
valid_symbols[RIGHT_BRACE] &&
|
|
2489
|
+
(is_blank(lexer->lookahead) || lexer->lookahead == '}')
|
|
2490
|
+
) {
|
|
2491
|
+
return scan_right_brace(lexer, valid_symbols, symbol);
|
|
2795
2492
|
}
|
|
2796
2493
|
|
|
2797
2494
|
if (
|
|
2798
|
-
valid_symbols[OMITTED_FIRST_ADDRESS_MARKER] &&
|
|
2799
2495
|
lexer->lookahead ==
|
|
2800
2496
|
',' &&
|
|
2801
|
-
|
|
2802
|
-
lexer,
|
|
2803
|
-
valid_symbols,
|
|
2804
|
-
OMITTED_FIRST_ADDRESS_MARKER,
|
|
2805
|
-
symbol
|
|
2806
|
-
)
|
|
2497
|
+
emit_marker(lexer, valid_symbols, OMITTED_FIRST_ADDRESS_MARKER, symbol)
|
|
2807
2498
|
) {
|
|
2808
2499
|
return true;
|
|
2809
2500
|
}
|
|
@@ -2814,7 +2505,7 @@ static bool scan_command_token(
|
|
|
2814
2505
|
!can_start_address(lexer) &&
|
|
2815
2506
|
!is_blank(lexer->lookahead)
|
|
2816
2507
|
) {
|
|
2817
|
-
return
|
|
2508
|
+
return emit_marker(
|
|
2818
2509
|
lexer,
|
|
2819
2510
|
valid_symbols,
|
|
2820
2511
|
lexer->eof(lexer) ? INCOMPLETE_OMITTED_ADDRESS_MARKER
|
|
@@ -2837,13 +2528,7 @@ static bool scan_command_token(
|
|
|
2837
2528
|
if (
|
|
2838
2529
|
!at_command_boundary(lexer) &&
|
|
2839
2530
|
!is_blank(lexer->lookahead) &&
|
|
2840
|
-
valid_symbols
|
|
2841
|
-
emit_missing_marker(
|
|
2842
|
-
lexer,
|
|
2843
|
-
valid_symbols,
|
|
2844
|
-
OMITTED_FILE_SEPARATOR_MARKER,
|
|
2845
|
-
symbol
|
|
2846
|
-
)
|
|
2531
|
+
emit_marker(lexer, valid_symbols, OMITTED_FILE_SEPARATOR_MARKER, symbol)
|
|
2847
2532
|
) {
|
|
2848
2533
|
return true;
|
|
2849
2534
|
}
|
|
@@ -2862,7 +2547,7 @@ static bool scan_command_token(
|
|
|
2862
2547
|
index++
|
|
2863
2548
|
) {
|
|
2864
2549
|
if (
|
|
2865
|
-
|
|
2550
|
+
emit_marker(
|
|
2866
2551
|
lexer,
|
|
2867
2552
|
valid_symbols,
|
|
2868
2553
|
boundary_markers[index][variant],
|
|
@@ -2875,7 +2560,7 @@ static bool scan_command_token(
|
|
|
2875
2560
|
}
|
|
2876
2561
|
|
|
2877
2562
|
if (
|
|
2878
|
-
|
|
2563
|
+
emit_marker(
|
|
2879
2564
|
lexer,
|
|
2880
2565
|
valid_symbols,
|
|
2881
2566
|
missing_text_introducer_symbol(lexer),
|
|
@@ -2885,19 +2570,17 @@ static bool scan_command_token(
|
|
|
2885
2570
|
return true;
|
|
2886
2571
|
}
|
|
2887
2572
|
|
|
2888
|
-
if (
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
symbol
|
|
2894
|
-
);
|
|
2573
|
+
if (
|
|
2574
|
+
lexer->eof(lexer) &&
|
|
2575
|
+
emit_marker(lexer, valid_symbols, MISSING_CLOSING_BRACE_MARKER, symbol)
|
|
2576
|
+
) {
|
|
2577
|
+
return true;
|
|
2895
2578
|
}
|
|
2896
2579
|
|
|
2897
2580
|
if (
|
|
2898
2581
|
!at_command_boundary(lexer) &&
|
|
2899
2582
|
!is_blank(lexer->lookahead) &&
|
|
2900
|
-
|
|
2583
|
+
emit_marker(
|
|
2901
2584
|
lexer,
|
|
2902
2585
|
valid_symbols,
|
|
2903
2586
|
MISSING_SEPARATOR_AFTER_UNMATCHED_BRACE_MARKER,
|
|
@@ -2907,38 +2590,10 @@ static bool scan_command_token(
|
|
|
2907
2590
|
return true;
|
|
2908
2591
|
}
|
|
2909
2592
|
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
valid_symbols,
|
|
2915
|
-
MISSING_SEPARATOR_BEFORE_UNMATCHED_BRACE_MARKER,
|
|
2916
|
-
symbol
|
|
2917
|
-
)
|
|
2918
|
-
) {
|
|
2919
|
-
return true;
|
|
2920
|
-
}
|
|
2921
|
-
if (
|
|
2922
|
-
emit_missing_marker(
|
|
2923
|
-
lexer,
|
|
2924
|
-
valid_symbols,
|
|
2925
|
-
MISSING_COMMAND_SEPARATOR_MARKER,
|
|
2926
|
-
symbol
|
|
2927
|
-
)
|
|
2928
|
-
) {
|
|
2929
|
-
return true;
|
|
2930
|
-
}
|
|
2931
|
-
} else if (lexer->eof(lexer)) {
|
|
2932
|
-
if (
|
|
2933
|
-
emit_missing_marker(
|
|
2934
|
-
lexer,
|
|
2935
|
-
valid_symbols,
|
|
2936
|
-
INCOMPLETE_COMMAND_SEPARATOR_MARKER,
|
|
2937
|
-
symbol
|
|
2938
|
-
)
|
|
2939
|
-
) {
|
|
2940
|
-
return true;
|
|
2941
|
-
}
|
|
2593
|
+
const TSSymbol separator_marker =
|
|
2594
|
+
missing_command_separator_marker(lexer, valid_symbols);
|
|
2595
|
+
if (separator_marker != ERROR_SENTINEL) {
|
|
2596
|
+
return emit_marker(lexer, valid_symbols, separator_marker, symbol);
|
|
2942
2597
|
}
|
|
2943
2598
|
|
|
2944
2599
|
const TSSymbol missing_opening_delimiter = lexer->eof(lexer)
|
|
@@ -2946,7 +2601,7 @@ static bool scan_command_token(
|
|
|
2946
2601
|
: NONCONFORMING_MISSING_OPENING_DELIMITER_MARKER;
|
|
2947
2602
|
if (
|
|
2948
2603
|
delimiter_is_missing(lexer) &&
|
|
2949
|
-
|
|
2604
|
+
emit_marker(lexer, valid_symbols, missing_opening_delimiter, symbol)
|
|
2950
2605
|
) {
|
|
2951
2606
|
return true;
|
|
2952
2607
|
}
|
|
@@ -2995,10 +2650,9 @@ static bool sed_scanner_scan_impl(
|
|
|
2995
2650
|
case MODE_SUBSTITUTE_PATTERN:
|
|
2996
2651
|
return scan_regex_token(lexer, state, valid_symbols, symbol);
|
|
2997
2652
|
case MODE_SUBSTITUTE_REPLACEMENT:
|
|
2998
|
-
return scan_replacement_token(lexer, state, valid_symbols, symbol);
|
|
2999
2653
|
case MODE_TRANSLATE_SOURCE:
|
|
3000
2654
|
case MODE_TRANSLATE_DESTINATION:
|
|
3001
|
-
return
|
|
2655
|
+
return scan_operand_token(lexer, state, valid_symbols, symbol);
|
|
3002
2656
|
case MODE_TEXT:
|
|
3003
2657
|
return false;
|
|
3004
2658
|
case MODE_NONE:
|