tree-sitter-sed 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/common/scanner.h CHANGED
@@ -42,7 +42,6 @@ enum TokenType {
42
42
  BRE_QUESTION_MARK_ESCAPE_MARKER,
43
43
  BRE_PLUS_ESCAPE_MARKER,
44
44
  REGEX_UNMATCHED_INTERVAL_CLOSE,
45
- UNMATCHED_INTERVAL_CLOSE_MARKER,
46
45
  #endif
47
46
  #if SED_REGEX_EXTENDED
48
47
  REGEX_ALTERNATION_OPERATOR,
@@ -109,6 +108,7 @@ enum TokenType {
109
108
  TRANSLATE_UNTERMINATED_SOURCE,
110
109
  TRANSLATE_UNTERMINATED_DESTINATION,
111
110
  INVALID_SUBSTITUTION_FLAG,
111
+ FLAG_AFTER_WRITE_MARKER,
112
112
  TEXT_COMMAND_START,
113
113
  TEXT_LITERAL,
114
114
  TEXT_BACKSLASH_ESCAPE,
@@ -122,7 +122,7 @@ enum TokenType {
122
122
  SUBSTITUTION_WFILE_ARGUMENT,
123
123
  LINE_WORD,
124
124
  RIGHT_BRACE,
125
- RESERVED_UNKNOWN_FUNCTION,
125
+ RESERVED_UNKNOWN_FUNCTION_TOKEN,
126
126
  REGEX_INCOMPLETE_GROUP,
127
127
  REGEX_INCOMPLETE_BRACKET_TERM,
128
128
  REGEX_INCOMPLETE_INTERVAL,
@@ -132,15 +132,15 @@ enum TokenType {
132
132
  REPLACEMENT_LINE_UNTERMINATED,
133
133
  TRANSLATE_LINE_UNTERMINATED_SOURCE,
134
134
  TRANSLATE_LINE_UNTERMINATED_DESTINATION,
135
+ BLANKS_AROUND_ADDRESS_SEPARATOR,
135
136
  OMITTED_ADDRESS_MARKER,
137
+ INCOMPLETE_OMITTED_ADDRESS_MARKER,
136
138
  OMITTED_FIRST_ADDRESS_MARKER,
137
139
  EMPTY_SUBEXPRESSION_MARKER,
138
140
  MISSING_SUBEXPRESSION_MARKER,
139
141
  #if SED_REGEX_EXTENDED
140
142
  EMPTY_ALTERNATIVE_MARKER,
141
143
  #endif
142
- EXCESS_ADDRESSES_MARKER,
143
- ADDITIONAL_ADDRESS_MARKER,
144
144
  MISSING_FUNCTION_MARKER,
145
145
  MISSING_LABEL_MARKER,
146
146
  MISSING_RFILE_MARKER,
@@ -149,9 +149,7 @@ enum TokenType {
149
149
  MISSING_TEXT_INTRODUCER_MARKER,
150
150
  MISSING_TEXT_MARKER,
151
151
  MISSING_COMMAND_SEPARATOR_MARKER,
152
- BLANKS_AROUND_ADDRESS_SEPARATOR_MARKER,
153
152
  MISSING_ADDRESS_SEPARATOR_MARKER,
154
- DUPLICATE_NEGATION_MARKER,
155
153
  MISSING_CLOSING_BRACE_MARKER,
156
154
  MISSING_OPENING_DELIMITER_MARKER,
157
155
  MISSING_SEPARATOR_BEFORE_UNMATCHED_BRACE_MARKER,
@@ -306,6 +304,10 @@ static uint16_t deserialize_uint16(const char *buffer, unsigned offset) {
306
304
  ((uint16_t)(unsigned char)buffer[offset + 1] << 8));
307
305
  }
308
306
 
307
+ static bool is_regex_mode(enum ScannerMode mode) {
308
+ return mode == MODE_REGEX_ADDRESS || mode == MODE_SUBSTITUTE_PATTERN;
309
+ }
310
+
309
311
  static unsigned sed_scanner_serialize(void *payload, char *buffer) {
310
312
  const ScannerState *state = payload;
311
313
  const uint32_t delimiter = (uint32_t)state->delimiter;
@@ -333,6 +335,96 @@ static unsigned sed_scanner_serialize(void *payload, char *buffer) {
333
335
  return SCANNER_SERIALIZED_STATE_SIZE;
334
336
  }
335
337
 
338
+ static bool bracket_tracking_is_reset(const ScannerState *state) {
339
+ return state->regex_bracket_term_state ==
340
+ REGEX_BRACKET_TERM_NONE &&
341
+ state->regex_bracket_pending_element ==
342
+ REGEX_BRACKET_PENDING_NONE &&
343
+ state->regex_bracket_first_element ==
344
+ REGEX_BRACKET_PENDING_NONE &&
345
+ state->regex_bracket_last_element ==
346
+ REGEX_BRACKET_PENDING_NONE &&
347
+ state->regex_bracket_element_count ==
348
+ 0 &&
349
+ !state->regex_bracket_range_pending;
350
+ }
351
+
352
+ static bool regex_position_is_reset(const ScannerState *state) {
353
+ return !state->regex_at_branch_start &&
354
+ state->regex_duplication_state ==
355
+ REGEX_DUPLICATION_NONE &&
356
+ !state->regex_after_alternation &&
357
+ !state->regex_after_anchor;
358
+ }
359
+
360
+ static bool deserialized_delimiter_is_valid(uint32_t delimiter) {
361
+ return delimiter !=
362
+ 0 &&
363
+ delimiter <=
364
+ UINT32_C(0x10ffff) &&
365
+ !(delimiter >= UINT32_C(0xd800) && delimiter <= UINT32_C(0xdfff)) &&
366
+ delimiter !=
367
+ (uint32_t)'\\' &&
368
+ delimiter != (uint32_t)'\n';
369
+ }
370
+
371
+ static bool deserialized_state_is_valid(const ScannerState *candidate) {
372
+ if (candidate->mode == MODE_NONE) {
373
+ return false;
374
+ }
375
+
376
+ if (candidate->mode == MODE_TEXT) {
377
+ return candidate->delimiter ==
378
+ 0 &&
379
+ candidate->regex_state ==
380
+ REGEX_OUTSIDE_BRACKET &&
381
+ regex_position_is_reset(candidate) &&
382
+ candidate->regex_group_depth ==
383
+ 0 &&
384
+ candidate->regex_interval_state ==
385
+ REGEX_INTERVAL_NONE &&
386
+ bracket_tracking_is_reset(candidate);
387
+ }
388
+
389
+ if (!deserialized_delimiter_is_valid((uint32_t)candidate->delimiter)) {
390
+ return false;
391
+ }
392
+
393
+ if (!is_regex_mode(candidate->mode)) {
394
+ return candidate->regex_state ==
395
+ REGEX_OUTSIDE_BRACKET &&
396
+ regex_position_is_reset(candidate) &&
397
+ candidate->text_state ==
398
+ TEXT_EMPTY &&
399
+ candidate->regex_interval_state ==
400
+ REGEX_INTERVAL_NONE &&
401
+ bracket_tracking_is_reset(candidate) &&
402
+ candidate->regex_group_depth == 0;
403
+ }
404
+
405
+ if (candidate->text_state != TEXT_EMPTY) {
406
+ return false;
407
+ }
408
+
409
+ if (candidate->regex_state == REGEX_OUTSIDE_BRACKET) {
410
+ return bracket_tracking_is_reset(candidate);
411
+ }
412
+
413
+ if (!regex_position_is_reset(candidate)) {
414
+ return false;
415
+ }
416
+
417
+ if (
418
+ candidate->regex_state ==
419
+ REGEX_BRACKET_FIRST ||
420
+ candidate->regex_state == REGEX_BRACKET_AFTER_CARET
421
+ ) {
422
+ return bracket_tracking_is_reset(candidate);
423
+ }
424
+
425
+ return true;
426
+ }
427
+
336
428
  static void
337
429
  sed_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
338
430
  ScannerState *state = payload;
@@ -346,256 +438,101 @@ sed_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
346
438
  return;
347
439
  }
348
440
 
349
- const enum ScannerMode mode = (enum ScannerMode)(unsigned char)buffer[1];
350
- const enum RegexState regex_state = (enum RegexState)(unsigned char)buffer[2];
351
441
  const unsigned char mode_flags = (unsigned char)buffer[3];
352
- const uint32_t delimiter = (uint32_t)(unsigned char)buffer[4] |
353
- ((uint32_t)(unsigned char)buffer[5] << 8) |
354
- ((uint32_t)(unsigned char)buffer[6] << 16) |
355
- ((uint32_t)(unsigned char)buffer[7] << 24);
356
- const uint16_t regex_group_depth = deserialize_uint16(buffer, 8);
357
- const enum RegexIntervalState regex_interval_state =
358
- (enum RegexIntervalState)(unsigned char)buffer[10];
359
- const enum RegexBracketTermState regex_bracket_term_state =
360
- (enum RegexBracketTermState)(unsigned char)buffer[11];
361
- const enum RegexBracketPendingElement regex_bracket_pending_element =
362
- (enum RegexBracketPendingElement)(unsigned char)buffer[12];
363
- const enum RegexBracketPendingElement regex_bracket_first_element =
364
- (enum RegexBracketPendingElement)(unsigned char)buffer[13];
365
- const enum RegexBracketPendingElement regex_bracket_last_element =
366
- (enum RegexBracketPendingElement)(unsigned char)buffer[14];
367
- const uint8_t regex_bracket_element_count =
368
- (uint8_t)(unsigned char)buffer[15];
369
442
  const unsigned char regex_bracket_flags = (unsigned char)buffer[16];
370
- const bool regex_bracket_range_pending = (regex_bracket_flags & 1U) != 0;
371
- const enum RegexDuplicationState regex_duplication_state =
372
- (enum RegexDuplicationState)((regex_bracket_flags >> 1) & 3U);
373
-
374
- if (mode > MODE_TEXT) {
443
+ const ScannerState candidate = {
444
+ .delimiter = (int32_t)((uint32_t)(unsigned char)buffer[4] |
445
+ ((uint32_t)(unsigned char)buffer[5] << 8) |
446
+ ((uint32_t)(unsigned char)buffer[6] << 16) |
447
+ ((uint32_t)(unsigned char)buffer[7] << 24)),
448
+ .mode = (enum ScannerMode)(unsigned char)buffer[1],
449
+ .regex_state = (enum RegexState)(unsigned char)buffer[2],
450
+ .regex_at_branch_start = (mode_flags & 1U) != 0,
451
+ .regex_duplication_state =
452
+ (enum RegexDuplicationState)((regex_bracket_flags >> 1) & 3U),
453
+ .regex_after_alternation = (mode_flags & 2U) != 0,
454
+ .regex_after_anchor = (mode_flags & 4U) != 0,
455
+ .text_state = (enum TextState)((mode_flags >> 3) & 3U),
456
+ .regex_interval_state = (enum RegexIntervalState)(unsigned char)buffer[10],
457
+ .regex_bracket_term_state =
458
+ (enum RegexBracketTermState)(unsigned char)buffer[11],
459
+ .regex_bracket_pending_element =
460
+ (enum RegexBracketPendingElement)(unsigned char)buffer[12],
461
+ .regex_bracket_first_element =
462
+ (enum RegexBracketPendingElement)(unsigned char)buffer[13],
463
+ .regex_bracket_last_element =
464
+ (enum RegexBracketPendingElement)(unsigned char)buffer[14],
465
+ .regex_bracket_element_count = (uint8_t)(unsigned char)buffer[15],
466
+ .regex_bracket_range_pending = (regex_bracket_flags & 1U) != 0,
467
+ .regex_group_depth = deserialize_uint16(buffer, 8),
468
+ };
469
+
470
+ if (candidate.mode > MODE_TEXT) {
375
471
  return;
376
472
  }
377
473
 
378
- if (regex_state > REGEX_BRACKET_BODY) {
474
+ if (candidate.regex_state > REGEX_BRACKET_BODY) {
379
475
  return;
380
476
  }
381
477
 
382
478
  if ((mode_flags & (unsigned char)~31U) != 0) {
383
479
  return;
384
480
  }
385
- const bool regex_at_branch_start = (mode_flags & 1U) != 0;
386
- const bool regex_after_alternation = (mode_flags & 2U) != 0;
387
- const bool regex_after_anchor = (mode_flags & 4U) != 0;
388
- const enum TextState text_state = (enum TextState)((mode_flags >> 3) & 3U);
389
- if (text_state > TEXT_AFTER_ESCAPED_NEWLINE) {
481
+ if (candidate.text_state > TEXT_AFTER_ESCAPED_NEWLINE) {
390
482
  return;
391
483
  }
392
484
  #if !SED_REGEX_EXTENDED
393
- if (regex_after_alternation) {
485
+ if (candidate.regex_after_alternation) {
394
486
  return;
395
487
  }
396
488
  #endif
397
489
 
398
- if (regex_interval_state > REGEX_INTERVAL_AFTER_MAXIMUM) {
490
+ if (candidate.regex_interval_state > REGEX_INTERVAL_AFTER_MAXIMUM) {
399
491
  return;
400
492
  }
401
- if (regex_bracket_term_state > REGEX_BRACKET_TERM_EQUAL) {
493
+ if (candidate.regex_bracket_term_state > REGEX_BRACKET_TERM_EQUAL) {
402
494
  return;
403
495
  }
404
496
  if (
405
- regex_bracket_pending_element >
497
+ candidate.regex_bracket_pending_element >
406
498
  REGEX_BRACKET_PENDING_COLON ||
407
- regex_bracket_first_element >
499
+ candidate.regex_bracket_first_element >
408
500
  REGEX_BRACKET_PENDING_COLON ||
409
- regex_bracket_last_element >
501
+ candidate.regex_bracket_last_element >
410
502
  REGEX_BRACKET_PENDING_COLON ||
411
- regex_bracket_element_count >
503
+ candidate.regex_bracket_element_count >
412
504
  3U ||
413
505
  (regex_bracket_flags & (unsigned char)~7U) !=
414
506
  0 ||
415
507
  #if SED_REGEX_EXTENDED
416
- regex_duplication_state > REGEX_AFTER_REPETITION_MODIFIER
508
+ candidate.regex_duplication_state > REGEX_AFTER_REPETITION_MODIFIER
417
509
  #else
418
- regex_duplication_state > REGEX_AFTER_DUPLICATION_SYMBOL
510
+ candidate.regex_duplication_state > REGEX_AFTER_DUPLICATION_SYMBOL
419
511
  #endif
420
512
  ) {
421
513
  return;
422
514
  }
423
515
  if (
424
- (regex_bracket_element_count ==
516
+ (candidate.regex_bracket_element_count ==
425
517
  0 &&
426
- (regex_bracket_first_element !=
518
+ (candidate.regex_bracket_first_element !=
427
519
  REGEX_BRACKET_PENDING_NONE ||
428
- regex_bracket_last_element != REGEX_BRACKET_PENDING_NONE)) ||
429
- (regex_bracket_element_count >
520
+ candidate.regex_bracket_last_element != REGEX_BRACKET_PENDING_NONE)) ||
521
+ (candidate.regex_bracket_element_count >
430
522
  0 &&
431
- (regex_bracket_first_element ==
523
+ (candidate.regex_bracket_first_element ==
432
524
  REGEX_BRACKET_PENDING_NONE ||
433
- regex_bracket_last_element == REGEX_BRACKET_PENDING_NONE)) ||
434
- (regex_bracket_pending_element !=
435
- REGEX_BRACKET_PENDING_NONE &&
436
- regex_bracket_range_pending)
437
- ) {
438
- return;
439
- }
440
-
441
- if (mode == MODE_NONE) {
442
- return;
443
- }
444
-
445
- if (mode == MODE_TEXT) {
446
- if (
447
- delimiter ==
448
- 0 &&
449
- regex_state ==
450
- REGEX_OUTSIDE_BRACKET &&
451
- !regex_at_branch_start &&
452
- regex_duplication_state ==
453
- REGEX_DUPLICATION_NONE &&
454
- regex_group_depth ==
455
- 0 &&
456
- !regex_after_anchor &&
457
- regex_interval_state ==
458
- REGEX_INTERVAL_NONE &&
459
- !regex_after_alternation &&
460
- regex_bracket_term_state ==
461
- REGEX_BRACKET_TERM_NONE &&
462
- regex_bracket_pending_element ==
525
+ candidate.regex_bracket_last_element == REGEX_BRACKET_PENDING_NONE)) ||
526
+ (candidate.regex_bracket_pending_element !=
463
527
  REGEX_BRACKET_PENDING_NONE &&
464
- regex_bracket_first_element ==
465
- REGEX_BRACKET_PENDING_NONE &&
466
- regex_bracket_last_element ==
467
- REGEX_BRACKET_PENDING_NONE &&
468
- regex_bracket_element_count ==
469
- 0 &&
470
- !regex_bracket_range_pending
471
- ) {
472
- state->mode = mode;
473
- state->text_state = text_state;
474
- }
475
- return;
476
- }
477
-
478
- if (
479
- delimiter ==
480
- 0 ||
481
- delimiter >
482
- UINT32_C(0x10ffff) ||
483
- (delimiter >= UINT32_C(0xd800) && delimiter <= UINT32_C(0xdfff)) ||
484
- delimiter ==
485
- (uint32_t)'\\' ||
486
- delimiter == (uint32_t)'\n'
487
- ) {
488
- return;
489
- }
490
-
491
- if (
492
- mode !=
493
- MODE_REGEX_ADDRESS &&
494
- mode !=
495
- MODE_SUBSTITUTE_PATTERN &&
496
- (regex_state !=
497
- REGEX_OUTSIDE_BRACKET ||
498
- regex_at_branch_start ||
499
- regex_duplication_state !=
500
- REGEX_DUPLICATION_NONE ||
501
- regex_after_alternation ||
502
- regex_after_anchor ||
503
- text_state !=
504
- TEXT_EMPTY ||
505
- regex_interval_state !=
506
- REGEX_INTERVAL_NONE ||
507
- regex_bracket_term_state !=
508
- REGEX_BRACKET_TERM_NONE ||
509
- regex_bracket_pending_element !=
510
- REGEX_BRACKET_PENDING_NONE ||
511
- regex_bracket_first_element !=
512
- REGEX_BRACKET_PENDING_NONE ||
513
- regex_bracket_last_element !=
514
- REGEX_BRACKET_PENDING_NONE ||
515
- regex_bracket_element_count !=
516
- 0 ||
517
- regex_bracket_range_pending)
528
+ candidate.regex_bracket_range_pending)
518
529
  ) {
519
530
  return;
520
531
  }
521
532
 
522
- if (
523
- regex_state !=
524
- REGEX_OUTSIDE_BRACKET &&
525
- (regex_at_branch_start ||
526
- regex_duplication_state !=
527
- REGEX_DUPLICATION_NONE ||
528
- regex_after_alternation ||
529
- regex_after_anchor)
530
- ) {
531
- return;
533
+ if (deserialized_state_is_valid(&candidate)) {
534
+ *state = candidate;
532
535
  }
533
-
534
- if (
535
- regex_state ==
536
- REGEX_OUTSIDE_BRACKET &&
537
- (regex_bracket_term_state !=
538
- REGEX_BRACKET_TERM_NONE ||
539
- regex_bracket_pending_element !=
540
- REGEX_BRACKET_PENDING_NONE ||
541
- regex_bracket_first_element !=
542
- REGEX_BRACKET_PENDING_NONE ||
543
- regex_bracket_last_element !=
544
- REGEX_BRACKET_PENDING_NONE ||
545
- regex_bracket_element_count !=
546
- 0 ||
547
- regex_bracket_range_pending)
548
- ) {
549
- return;
550
- }
551
-
552
- if (
553
- (regex_state ==
554
- REGEX_BRACKET_FIRST ||
555
- regex_state == REGEX_BRACKET_AFTER_CARET) &&
556
- (regex_bracket_term_state !=
557
- REGEX_BRACKET_TERM_NONE ||
558
- regex_bracket_pending_element !=
559
- REGEX_BRACKET_PENDING_NONE ||
560
- regex_bracket_element_count !=
561
- 0 ||
562
- regex_bracket_range_pending)
563
- ) {
564
- return;
565
- }
566
-
567
- if (
568
- (mode == MODE_REGEX_ADDRESS || mode == MODE_SUBSTITUTE_PATTERN) &&
569
- text_state != TEXT_EMPTY
570
- ) {
571
- return;
572
- }
573
-
574
- if (
575
- mode !=
576
- MODE_REGEX_ADDRESS &&
577
- mode !=
578
- MODE_SUBSTITUTE_PATTERN &&
579
- regex_group_depth != 0
580
- ) {
581
- return;
582
- }
583
-
584
- state->mode = mode;
585
- state->delimiter = (int32_t)delimiter;
586
- state->regex_state = regex_state;
587
- state->regex_at_branch_start = regex_at_branch_start;
588
- state->regex_duplication_state = regex_duplication_state;
589
- state->regex_after_alternation = regex_after_alternation;
590
- state->regex_after_anchor = regex_after_anchor;
591
- state->regex_interval_state = regex_interval_state;
592
- state->regex_bracket_term_state = regex_bracket_term_state;
593
- state->regex_bracket_pending_element = regex_bracket_pending_element;
594
- state->regex_bracket_first_element = regex_bracket_first_element;
595
- state->regex_bracket_last_element = regex_bracket_last_element;
596
- state->regex_bracket_element_count = regex_bracket_element_count;
597
- state->regex_bracket_range_pending = regex_bracket_range_pending;
598
- state->regex_group_depth = regex_group_depth;
599
536
  }
600
537
 
601
538
  static void advance(TSLexer *lexer) {
@@ -789,6 +726,42 @@ static bool scan_substitution_wfile_argument(TSLexer *lexer) {
789
726
  return true;
790
727
  }
791
728
 
729
+ enum FlagAfterWriteScan {
730
+ FLAG_AFTER_WRITE_NONE,
731
+ FLAG_AFTER_WRITE_MATCH,
732
+ FLAG_AFTER_WRITE_FALLBACK,
733
+ };
734
+
735
+ static bool is_substitution_flag_character(int32_t character) {
736
+ if (is_digit(character)) {
737
+ return true;
738
+ }
739
+
740
+ switch (character) {
741
+ case 'g':
742
+ case 'i':
743
+ case 'p':
744
+ case 'w':
745
+ return true;
746
+ default:
747
+ return false;
748
+ }
749
+ }
750
+
751
+ static enum FlagAfterWriteScan scan_flag_after_write_marker(TSLexer *lexer) {
752
+ if (!is_substitution_flag_character(lexer->lookahead)) {
753
+ return FLAG_AFTER_WRITE_NONE;
754
+ }
755
+
756
+ lexer->mark_end(lexer);
757
+ do {
758
+ advance(lexer);
759
+ } while (is_substitution_flag_character(lexer->lookahead));
760
+
761
+ return is_blank(lexer->lookahead) ? FLAG_AFTER_WRITE_MATCH
762
+ : FLAG_AFTER_WRITE_FALLBACK;
763
+ }
764
+
792
765
  static bool scan_right_brace(TSLexer *lexer, ScannerState *state) {
793
766
  if (state->mode != MODE_NONE) {
794
767
  return false;
@@ -883,8 +856,8 @@ static enum PostBlankRecoveryScan scan_post_blank_recovery(
883
856
  ) {
884
857
  if (
885
858
  !valid_symbols[OMITTED_ADDRESS_MARKER] &&
886
- !valid_symbols[ADDITIONAL_ADDRESS_MARKER] &&
887
- !valid_symbols[BLANKS_AROUND_ADDRESS_SEPARATOR_MARKER] &&
859
+ !valid_symbols[INCOMPLETE_OMITTED_ADDRESS_MARKER] &&
860
+ !valid_symbols[BLANKS_AROUND_ADDRESS_SEPARATOR] &&
888
861
  !valid_symbols[MISSING_ADDRESS_SEPARATOR_MARKER] &&
889
862
  !valid_symbols[MISSING_SEPARATOR_BEFORE_UNMATCHED_BRACE_MARKER] &&
890
863
  !valid_symbols[MISSING_COMMAND_SEPARATOR_MARKER] &&
@@ -896,22 +869,23 @@ static enum PostBlankRecoveryScan scan_post_blank_recovery(
896
869
  lexer->mark_end(lexer);
897
870
  advance_past_blanks(lexer);
898
871
 
899
- if (valid_symbols[OMITTED_ADDRESS_MARKER] && !can_start_address(lexer)) {
900
- *symbol = OMITTED_ADDRESS_MARKER;
901
- return POST_BLANK_RECOVERY_TOKEN;
902
- }
872
+ const bool after_separator = valid_symbols[OMITTED_ADDRESS_MARKER] ||
873
+ valid_symbols[INCOMPLETE_OMITTED_ADDRESS_MARKER];
874
+
903
875
  if (
904
- valid_symbols[ADDITIONAL_ADDRESS_MARKER] &&
905
- (lexer->lookahead == ',' || can_start_address(lexer))
876
+ valid_symbols[BLANKS_AROUND_ADDRESS_SEPARATOR] &&
877
+ (after_separator ? can_start_address(lexer) : lexer->lookahead == ',')
906
878
  ) {
907
- *symbol = ADDITIONAL_ADDRESS_MARKER;
879
+ lexer->mark_end(lexer);
880
+ *symbol = BLANKS_AROUND_ADDRESS_SEPARATOR;
908
881
  return POST_BLANK_RECOVERY_TOKEN;
909
882
  }
910
- if (
911
- valid_symbols[BLANKS_AROUND_ADDRESS_SEPARATOR_MARKER] &&
912
- lexer->lookahead == ','
913
- ) {
914
- *symbol = BLANKS_AROUND_ADDRESS_SEPARATOR_MARKER;
883
+ if (after_separator && !can_start_address(lexer)) {
884
+ *symbol = lexer->eof(lexer) ? INCOMPLETE_OMITTED_ADDRESS_MARKER
885
+ : OMITTED_ADDRESS_MARKER;
886
+ if (!valid_symbols[*symbol]) {
887
+ return POST_BLANK_RECOVERY_FAILED;
888
+ }
915
889
  return POST_BLANK_RECOVERY_TOKEN;
916
890
  }
917
891
  if (
@@ -1021,10 +995,6 @@ static bool scan_text_token(
1021
995
  return true;
1022
996
  }
1023
997
 
1024
- static bool is_regex_mode(enum ScannerMode mode) {
1025
- return mode == MODE_REGEX_ADDRESS || mode == MODE_SUBSTITUTE_PATTERN;
1026
- }
1027
-
1028
998
  static bool regex_is_inside_bracket(const ScannerState *state) {
1029
999
  return state->regex_state != REGEX_OUTSIDE_BRACKET;
1030
1000
  }
@@ -1509,6 +1479,18 @@ static bool scan_regex_interval(
1509
1479
  return emit_symbol(valid_symbols, REGEX_INTERVAL_OPEN, symbol);
1510
1480
  }
1511
1481
 
1482
+ static bool emit_interval_issue(
1483
+ TSLexer *lexer,
1484
+ ScannerState *state,
1485
+ TSSymbol candidate,
1486
+ TSSymbol *symbol
1487
+ ) {
1488
+ lexer->mark_end(lexer);
1489
+ state->regex_interval_state = REGEX_INTERVAL_NONE;
1490
+ *symbol = candidate;
1491
+ return true;
1492
+ }
1493
+
1512
1494
  static bool
1513
1495
  scan_invalid_interval_remainder(TSLexer *lexer, ScannerState *state);
1514
1496
 
@@ -1604,9 +1586,7 @@ static enum DuplicationContextScan scan_regex_duplication_context_marker(
1604
1586
  #endif
1605
1587
 
1606
1588
  if (lexer->eof(lexer) && valid_symbols[REGEX_INCOMPLETE_INTERVAL]) {
1607
- lexer->mark_end(lexer);
1608
- state->regex_interval_state = REGEX_INTERVAL_NONE;
1609
- *symbol = REGEX_INCOMPLETE_INTERVAL;
1589
+ emit_interval_issue(lexer, state, REGEX_INCOMPLETE_INTERVAL, symbol);
1610
1590
  return DUPLICATION_CONTEXT_TOKEN;
1611
1591
  }
1612
1592
 
@@ -1615,9 +1595,7 @@ static enum DuplicationContextScan scan_regex_duplication_context_marker(
1615
1595
  return DUPLICATION_CONTEXT_TOKEN;
1616
1596
  }
1617
1597
  scan_invalid_interval_remainder(lexer, state);
1618
- lexer->mark_end(lexer);
1619
- state->regex_interval_state = REGEX_INTERVAL_NONE;
1620
- *symbol = REGEX_INVALID_INTERVAL;
1598
+ emit_interval_issue(lexer, state, REGEX_INVALID_INTERVAL, symbol);
1621
1599
  return DUPLICATION_CONTEXT_TOKEN;
1622
1600
  }
1623
1601
 
@@ -2053,10 +2031,12 @@ static bool scan_regex_token(
2053
2031
  return true;
2054
2032
  }
2055
2033
  if (lexer->eof(lexer) && valid_symbols[REGEX_INCOMPLETE_INTERVAL]) {
2056
- lexer->mark_end(lexer);
2057
- state->regex_interval_state = REGEX_INTERVAL_NONE;
2058
- *symbol = REGEX_INCOMPLETE_INTERVAL;
2059
- return true;
2034
+ return emit_interval_issue(
2035
+ lexer,
2036
+ state,
2037
+ REGEX_INCOMPLETE_INTERVAL,
2038
+ symbol
2039
+ );
2060
2040
  }
2061
2041
  if (!valid_symbols[REGEX_INVALID_INTERVAL]) {
2062
2042
  return false;
@@ -2067,10 +2047,7 @@ static bool scan_regex_token(
2067
2047
  advance_past_escaped_character(lexer);
2068
2048
  scan_invalid_interval_remainder(lexer, state);
2069
2049
  }
2070
- lexer->mark_end(lexer);
2071
- state->regex_interval_state = REGEX_INTERVAL_NONE;
2072
- *symbol = REGEX_INVALID_INTERVAL;
2073
- return true;
2050
+ return emit_interval_issue(lexer, state, REGEX_INVALID_INTERVAL, symbol);
2074
2051
  }
2075
2052
  #endif
2076
2053
 
@@ -2514,226 +2491,191 @@ static bool scan_translate_token(
2514
2491
  return false;
2515
2492
  }
2516
2493
 
2517
- static bool sed_scanner_scan_impl(
2518
- ScannerState *state,
2494
+ static bool scan_regex_recovery_marker(
2519
2495
  TSLexer *lexer,
2496
+ ScannerState *state,
2520
2497
  const bool *valid_symbols,
2521
2498
  TSSymbol *symbol
2522
2499
  ) {
2523
- if (valid_symbols[ERROR_SENTINEL]) {
2524
- return false;
2525
- }
2526
-
2527
- if (state->mode == MODE_TEXT) {
2528
- return scan_text_token(lexer, state, valid_symbols, symbol);
2529
- }
2530
-
2531
2500
  #if !SED_REGEX_EXTENDED
2532
2501
  if (
2533
- is_regex_mode(state->mode) &&
2534
- (emit_missing_marker(
2535
- lexer,
2536
- valid_symbols,
2537
- BRE_VERTICAL_LINE_ESCAPE_MARKER,
2538
- symbol
2539
- ) ||
2540
- emit_missing_marker(
2541
- lexer,
2542
- valid_symbols,
2543
- BRE_QUESTION_MARK_ESCAPE_MARKER,
2544
- symbol
2545
- ) ||
2546
- emit_missing_marker(
2547
- lexer,
2548
- valid_symbols,
2549
- BRE_PLUS_ESCAPE_MARKER,
2550
- symbol
2551
- ) ||
2552
- emit_missing_marker(
2553
- lexer,
2554
- valid_symbols,
2555
- UNMATCHED_INTERVAL_CLOSE_MARKER,
2556
- symbol
2557
- ))
2502
+ emit_missing_marker(
2503
+ lexer,
2504
+ valid_symbols,
2505
+ BRE_VERTICAL_LINE_ESCAPE_MARKER,
2506
+ symbol
2507
+ ) ||
2508
+ emit_missing_marker(
2509
+ lexer,
2510
+ valid_symbols,
2511
+ BRE_QUESTION_MARK_ESCAPE_MARKER,
2512
+ symbol
2513
+ ) ||
2514
+ emit_missing_marker(lexer, valid_symbols, BRE_PLUS_ESCAPE_MARKER, symbol)
2558
2515
  ) {
2559
2516
  return true;
2560
2517
  }
2561
2518
  #endif
2562
2519
 
2520
+ const bool at_line_boundary = lexer->eof(lexer) || lexer->lookahead == '\n';
2521
+ const bool at_regex_end =
2522
+ at_line_boundary || lexer->lookahead == state->delimiter;
2523
+
2563
2524
  if (
2564
- is_regex_mode(state->mode) &&
2565
2525
  state->regex_state ==
2566
2526
  REGEX_OUTSIDE_BRACKET &&
2567
2527
  state->regex_group_depth >
2568
2528
  0 &&
2569
2529
  !state->regex_after_alternation &&
2570
- (lexer->eof(lexer) ||
2571
- lexer->lookahead ==
2572
- '\n' ||
2573
- lexer->lookahead == state->delimiter)
2530
+ at_regex_end &&
2531
+ emit_missing_marker(
2532
+ lexer,
2533
+ valid_symbols,
2534
+ lexer->eof(lexer) ? MISSING_SUBEXPRESSION_MARKER
2535
+ : MISSING_SUBEXPRESSION_PLACEHOLDER_MARKER,
2536
+ symbol
2537
+ )
2574
2538
  ) {
2575
- const TSSymbol candidate = lexer->eof(lexer)
2576
- ? MISSING_SUBEXPRESSION_MARKER
2577
- : MISSING_SUBEXPRESSION_PLACEHOLDER_MARKER;
2578
- if (valid_symbols[candidate]) {
2579
- lexer->mark_end(lexer);
2580
- *symbol = candidate;
2581
- return true;
2582
- }
2539
+ return true;
2583
2540
  }
2584
2541
 
2585
2542
  if (
2586
- is_regex_mode(state->mode) &&
2587
2543
  (state->regex_state ==
2588
2544
  REGEX_BRACKET_FIRST ||
2589
2545
  state->regex_state == REGEX_BRACKET_AFTER_CARET) &&
2590
- (lexer->eof(lexer) || lexer->lookahead == '\n')
2546
+ at_line_boundary &&
2547
+ emit_missing_marker(
2548
+ lexer,
2549
+ valid_symbols,
2550
+ lexer->eof(lexer) ? INCOMPLETE_BRACKET_LIST_MARKER
2551
+ : MISSING_BRACKET_LIST_MARKER,
2552
+ symbol
2553
+ )
2591
2554
  ) {
2592
- const TSSymbol candidate = lexer->eof(lexer)
2593
- ? INCOMPLETE_BRACKET_LIST_MARKER
2594
- : MISSING_BRACKET_LIST_MARKER;
2595
- if (valid_symbols[candidate]) {
2596
- lexer->mark_end(lexer);
2597
- *symbol = candidate;
2598
- return true;
2599
- }
2555
+ return true;
2600
2556
  }
2601
2557
 
2602
2558
  if (
2603
- is_regex_mode(state->mode) &&
2604
2559
  state->regex_bracket_term_state !=
2605
2560
  REGEX_BRACKET_TERM_NONE &&
2606
- (lexer->eof(lexer) || lexer->lookahead == '\n')
2561
+ at_line_boundary &&
2562
+ emit_missing_marker(
2563
+ lexer,
2564
+ valid_symbols,
2565
+ lexer->eof(lexer) ? REGEX_INCOMPLETE_BRACKET_TERM
2566
+ : REGEX_MALFORMED_BRACKET_TERM,
2567
+ symbol
2568
+ )
2607
2569
  ) {
2608
- const TSSymbol candidate = lexer->eof(lexer) ? REGEX_INCOMPLETE_BRACKET_TERM
2609
- : REGEX_MALFORMED_BRACKET_TERM;
2610
- if (valid_symbols[candidate]) {
2611
- lexer->mark_end(lexer);
2612
- state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
2613
- finish_compound_bracket_element(state);
2614
- *symbol = candidate;
2615
- return true;
2616
- }
2570
+ state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
2571
+ finish_compound_bracket_element(state);
2572
+ return true;
2617
2573
  }
2618
2574
 
2619
2575
  if (
2620
- is_regex_mode(state->mode) &&
2621
2576
  regex_is_inside_bracket(state) &&
2622
- (lexer->eof(lexer) || lexer->lookahead == '\n')
2577
+ at_line_boundary &&
2578
+ emit_missing_marker(
2579
+ lexer,
2580
+ valid_symbols,
2581
+ lexer->eof(lexer) ? INCOMPLETE_BRACKET_EXPRESSION_MARKER
2582
+ : UNCLOSED_BRACKET_EXPRESSION_MARKER,
2583
+ symbol
2584
+ )
2623
2585
  ) {
2624
- const TSSymbol candidate = lexer->eof(lexer)
2625
- ? INCOMPLETE_BRACKET_EXPRESSION_MARKER
2626
- : UNCLOSED_BRACKET_EXPRESSION_MARKER;
2627
- if (valid_symbols[candidate]) {
2628
- lexer->mark_end(lexer);
2629
- state->regex_state = REGEX_OUTSIDE_BRACKET;
2630
- reset_bracket_tracking(state);
2631
- *symbol = candidate;
2632
- return true;
2633
- }
2586
+ state->regex_state = REGEX_OUTSIDE_BRACKET;
2587
+ reset_bracket_tracking(state);
2588
+ return true;
2634
2589
  }
2635
2590
 
2636
2591
  #if SED_REGEX_EXTENDED
2637
2592
  if (
2638
- is_regex_mode(state->mode) &&
2639
2593
  state->regex_state ==
2640
2594
  REGEX_OUTSIDE_BRACKET &&
2641
2595
  state->regex_after_alternation &&
2642
- (lexer->lookahead ==
2643
- state->delimiter ||
2644
- lexer->lookahead ==
2645
- '\n' ||
2646
- lexer->eof(lexer))
2596
+ at_regex_end &&
2597
+ emit_missing_marker(
2598
+ lexer,
2599
+ valid_symbols,
2600
+ lexer->eof(lexer) ? INCOMPLETE_ALTERNATIVE_MARKER
2601
+ : EMPTY_ALTERNATIVE_MARKER,
2602
+ symbol
2603
+ )
2647
2604
  ) {
2648
- const TSSymbol candidate = lexer->eof(lexer) ? INCOMPLETE_ALTERNATIVE_MARKER
2649
- : EMPTY_ALTERNATIVE_MARKER;
2650
- if (valid_symbols[candidate]) {
2651
- lexer->mark_end(lexer);
2652
- state->regex_after_alternation = false;
2653
- *symbol = candidate;
2654
- return true;
2655
- }
2605
+ state->regex_after_alternation = false;
2606
+ return true;
2656
2607
  }
2657
2608
  #endif
2658
2609
 
2659
2610
  if (
2660
- is_regex_mode(state->mode) &&
2661
2611
  state->regex_interval_state !=
2662
2612
  REGEX_INTERVAL_NONE &&
2663
- (lexer->lookahead ==
2664
- state->delimiter ||
2665
- lexer->lookahead ==
2666
- '\n' ||
2613
+ (at_regex_end
2667
2614
  #if !SED_REGEX_EXTENDED
2668
- (state->delimiter == '}' && lexer->lookahead == '\\') ||
2615
+ || (state->delimiter == '}' && lexer->lookahead == '\\')
2669
2616
  #endif
2670
- lexer->eof(lexer))
2617
+ ) &&
2618
+ emit_missing_marker(
2619
+ lexer,
2620
+ valid_symbols,
2621
+ lexer->eof(lexer) ? REGEX_INCOMPLETE_INTERVAL : REGEX_INVALID_INTERVAL,
2622
+ symbol
2623
+ )
2671
2624
  ) {
2672
- const TSSymbol candidate =
2673
- lexer->eof(lexer) ? REGEX_INCOMPLETE_INTERVAL : REGEX_INVALID_INTERVAL;
2674
- if (valid_symbols[candidate]) {
2675
- lexer->mark_end(lexer);
2676
- state->regex_interval_state = REGEX_INTERVAL_NONE;
2677
- *symbol = candidate;
2678
- return true;
2679
- }
2625
+ state->regex_interval_state = REGEX_INTERVAL_NONE;
2626
+ return true;
2680
2627
  }
2681
2628
 
2682
2629
  if (
2683
- is_regex_mode(state->mode) &&
2684
2630
  state->regex_state ==
2685
2631
  REGEX_OUTSIDE_BRACKET &&
2686
- (lexer->lookahead == '\n' || lexer->eof(lexer))
2632
+ state->regex_group_depth >
2633
+ 0 &&
2634
+ at_line_boundary &&
2635
+ emit_missing_marker(
2636
+ lexer,
2637
+ valid_symbols,
2638
+ lexer->eof(lexer) ? REGEX_INCOMPLETE_GROUP : REGEX_UNCLOSED_GROUP,
2639
+ symbol
2640
+ )
2687
2641
  ) {
2688
- if (state->regex_group_depth > 0) {
2689
- const TSSymbol candidate =
2690
- lexer->eof(lexer) ? REGEX_INCOMPLETE_GROUP : REGEX_UNCLOSED_GROUP;
2691
- if (valid_symbols[candidate]) {
2692
- lexer->mark_end(lexer);
2693
- state->regex_group_depth--;
2694
- *symbol = candidate;
2695
- return true;
2696
- }
2697
- }
2698
- }
2699
-
2700
- const bool delimiter_is_active = state->mode !=
2701
- MODE_NONE &&
2702
- state->mode !=
2703
- MODE_TEXT &&
2704
- lexer->lookahead ==
2705
- state->delimiter &&
2706
- (!is_regex_mode(state->mode) ||
2707
- state->regex_state == REGEX_OUTSIDE_BRACKET);
2708
- if (delimiter_is_active) {
2709
- if (state->regex_group_depth > 0 && valid_symbols[REGEX_UNCLOSED_GROUP]) {
2710
- state->regex_group_depth--;
2711
- *symbol = REGEX_UNCLOSED_GROUP;
2712
- return true;
2713
- }
2714
- return scan_active_mode_delimiter(lexer, state, valid_symbols, symbol);
2642
+ state->regex_group_depth--;
2643
+ return true;
2715
2644
  }
2716
2645
 
2717
- switch (state->mode) {
2718
- case MODE_REGEX_ADDRESS:
2719
- case MODE_SUBSTITUTE_PATTERN:
2720
- return scan_regex_token(lexer, state, valid_symbols, symbol);
2721
- case MODE_SUBSTITUTE_REPLACEMENT:
2722
- return scan_replacement_token(lexer, state, valid_symbols, symbol);
2723
- case MODE_TRANSLATE_SOURCE:
2724
- case MODE_TRANSLATE_DESTINATION:
2725
- return scan_translate_token(lexer, state, valid_symbols, symbol);
2726
- case MODE_TEXT:
2727
- return false;
2728
- case MODE_NONE:
2729
- break;
2730
- }
2646
+ return false;
2647
+ }
2731
2648
 
2649
+ static bool scan_command_token(
2650
+ TSLexer *lexer,
2651
+ ScannerState *state,
2652
+ const bool *valid_symbols,
2653
+ TSSymbol *symbol
2654
+ ) {
2732
2655
  if (valid_symbols[LINE_WORD] && scan_to_physical_line_end(lexer, false)) {
2733
2656
  *symbol = LINE_WORD;
2734
2657
  return true;
2735
2658
  }
2736
2659
 
2660
+ if (valid_symbols[FLAG_AFTER_WRITE_MARKER]) {
2661
+ const enum FlagAfterWriteScan scan = scan_flag_after_write_marker(lexer);
2662
+ if (scan == FLAG_AFTER_WRITE_MATCH) {
2663
+ *symbol = FLAG_AFTER_WRITE_MARKER;
2664
+ return true;
2665
+ }
2666
+ if (
2667
+ scan ==
2668
+ FLAG_AFTER_WRITE_FALLBACK &&
2669
+ valid_symbols[OMITTED_FILE_SEPARATOR_MARKER]
2670
+ ) {
2671
+ *symbol = OMITTED_FILE_SEPARATOR_MARKER;
2672
+ return true;
2673
+ }
2674
+ if (scan == FLAG_AFTER_WRITE_FALLBACK) {
2675
+ return false;
2676
+ }
2677
+ }
2678
+
2737
2679
  if (
2738
2680
  valid_symbols[SUBSTITUTION_WFILE_ARGUMENT] &&
2739
2681
  scan_substitution_wfile_argument(lexer)
@@ -2750,15 +2692,7 @@ static bool sed_scanner_scan_impl(
2750
2692
  if (
2751
2693
  valid_symbols[INVALID_SUBSTITUTION_FLAG] &&
2752
2694
  !is_blank(lexer->lookahead) &&
2753
- !is_digit(lexer->lookahead) &&
2754
- lexer->lookahead !=
2755
- 'g' &&
2756
- lexer->lookahead !=
2757
- 'i' &&
2758
- lexer->lookahead !=
2759
- 'p' &&
2760
- lexer->lookahead !=
2761
- 'w' &&
2695
+ !is_substitution_flag_character(lexer->lookahead) &&
2762
2696
  lexer->lookahead !=
2763
2697
  ';' &&
2764
2698
  lexer->lookahead !=
@@ -2794,11 +2728,23 @@ static bool sed_scanner_scan_impl(
2794
2728
  return true;
2795
2729
  }
2796
2730
 
2731
+ // Preserve an address interpretation before reserved-function recovery.
2732
+ if (
2733
+ valid_symbols[MISSING_ADDRESS_SEPARATOR_MARKER] && can_start_address(lexer)
2734
+ ) {
2735
+ return emit_missing_marker(
2736
+ lexer,
2737
+ valid_symbols,
2738
+ MISSING_ADDRESS_SEPARATOR_MARKER,
2739
+ symbol
2740
+ );
2741
+ }
2742
+
2797
2743
  if (
2798
- valid_symbols[RESERVED_UNKNOWN_FUNCTION] &&
2744
+ valid_symbols[RESERVED_UNKNOWN_FUNCTION_TOKEN] &&
2799
2745
  scan_reserved_unknown_function(lexer)
2800
2746
  ) {
2801
- *symbol = RESERVED_UNKNOWN_FUNCTION;
2747
+ *symbol = RESERVED_UNKNOWN_FUNCTION_TOKEN;
2802
2748
  return true;
2803
2749
  }
2804
2750
 
@@ -2839,6 +2785,9 @@ static bool sed_scanner_scan_impl(
2839
2785
  }
2840
2786
 
2841
2787
  if (
2788
+ valid_symbols[OMITTED_FIRST_ADDRESS_MARKER] &&
2789
+ lexer->lookahead ==
2790
+ ',' &&
2842
2791
  emit_missing_marker(
2843
2792
  lexer,
2844
2793
  valid_symbols,
@@ -2850,54 +2799,20 @@ static bool sed_scanner_scan_impl(
2850
2799
  }
2851
2800
 
2852
2801
  if (
2853
- valid_symbols[OMITTED_ADDRESS_MARKER] &&
2802
+ (valid_symbols[OMITTED_ADDRESS_MARKER] ||
2803
+ valid_symbols[INCOMPLETE_OMITTED_ADDRESS_MARKER]) &&
2854
2804
  !can_start_address(lexer) &&
2855
2805
  !is_blank(lexer->lookahead)
2856
2806
  ) {
2857
2807
  return emit_missing_marker(
2858
2808
  lexer,
2859
2809
  valid_symbols,
2860
- OMITTED_ADDRESS_MARKER,
2861
- symbol
2862
- );
2863
- }
2864
-
2865
- if (
2866
- valid_symbols[ADDITIONAL_ADDRESS_MARKER] &&
2867
- (lexer->lookahead == ',' || can_start_address(lexer))
2868
- ) {
2869
- return emit_missing_marker(
2870
- lexer,
2871
- valid_symbols,
2872
- ADDITIONAL_ADDRESS_MARKER,
2810
+ lexer->eof(lexer) ? INCOMPLETE_OMITTED_ADDRESS_MARKER
2811
+ : OMITTED_ADDRESS_MARKER,
2873
2812
  symbol
2874
2813
  );
2875
2814
  }
2876
2815
 
2877
- if (
2878
- valid_symbols[MISSING_ADDRESS_SEPARATOR_MARKER] && can_start_address(lexer)
2879
- ) {
2880
- return emit_missing_marker(
2881
- lexer,
2882
- valid_symbols,
2883
- MISSING_ADDRESS_SEPARATOR_MARKER,
2884
- symbol
2885
- );
2886
- }
2887
-
2888
- if (
2889
- valid_symbols[BLANKS_AROUND_ADDRESS_SEPARATOR_MARKER] &&
2890
- lexer->lookahead == ','
2891
- ) {
2892
- lexer->mark_end(lexer);
2893
- advance(lexer);
2894
- if (is_blank(lexer->lookahead)) {
2895
- *symbol = BLANKS_AROUND_ADDRESS_SEPARATOR_MARKER;
2896
- return true;
2897
- }
2898
- return false;
2899
- }
2900
-
2901
2816
  if (is_blank(lexer->lookahead)) {
2902
2817
  switch (scan_post_blank_recovery(lexer, valid_symbols, symbol)) {
2903
2818
  case POST_BLANK_RECOVERY_TOKEN:
@@ -2909,18 +2824,6 @@ static bool sed_scanner_scan_impl(
2909
2824
  }
2910
2825
  }
2911
2826
 
2912
- if (
2913
- emit_missing_marker(lexer, valid_symbols, DUPLICATE_NEGATION_MARKER, symbol)
2914
- ) {
2915
- return true;
2916
- }
2917
-
2918
- if (
2919
- emit_missing_marker(lexer, valid_symbols, EXCESS_ADDRESSES_MARKER, symbol)
2920
- ) {
2921
- return true;
2922
- }
2923
-
2924
2827
  if (
2925
2828
  !at_command_boundary(lexer) &&
2926
2829
  !is_blank(lexer->lookahead) &&
@@ -3029,6 +2932,60 @@ static bool sed_scanner_scan_impl(
3029
2932
  return false;
3030
2933
  }
3031
2934
 
2935
+ static bool sed_scanner_scan_impl(
2936
+ ScannerState *state,
2937
+ TSLexer *lexer,
2938
+ const bool *valid_symbols,
2939
+ TSSymbol *symbol
2940
+ ) {
2941
+ if (valid_symbols[ERROR_SENTINEL]) {
2942
+ return false;
2943
+ }
2944
+
2945
+ if (state->mode == MODE_TEXT) {
2946
+ return scan_text_token(lexer, state, valid_symbols, symbol);
2947
+ }
2948
+
2949
+ if (
2950
+ is_regex_mode(state->mode) &&
2951
+ scan_regex_recovery_marker(lexer, state, valid_symbols, symbol)
2952
+ ) {
2953
+ return true;
2954
+ }
2955
+
2956
+ const bool delimiter_is_active = state->mode !=
2957
+ MODE_NONE &&
2958
+ lexer->lookahead ==
2959
+ state->delimiter &&
2960
+ (!is_regex_mode(state->mode) ||
2961
+ state->regex_state == REGEX_OUTSIDE_BRACKET);
2962
+ if (delimiter_is_active) {
2963
+ if (state->regex_group_depth > 0 && valid_symbols[REGEX_UNCLOSED_GROUP]) {
2964
+ state->regex_group_depth--;
2965
+ *symbol = REGEX_UNCLOSED_GROUP;
2966
+ return true;
2967
+ }
2968
+ return scan_active_mode_delimiter(lexer, state, valid_symbols, symbol);
2969
+ }
2970
+
2971
+ switch (state->mode) {
2972
+ case MODE_REGEX_ADDRESS:
2973
+ case MODE_SUBSTITUTE_PATTERN:
2974
+ return scan_regex_token(lexer, state, valid_symbols, symbol);
2975
+ case MODE_SUBSTITUTE_REPLACEMENT:
2976
+ return scan_replacement_token(lexer, state, valid_symbols, symbol);
2977
+ case MODE_TRANSLATE_SOURCE:
2978
+ case MODE_TRANSLATE_DESTINATION:
2979
+ return scan_translate_token(lexer, state, valid_symbols, symbol);
2980
+ case MODE_TEXT:
2981
+ return false;
2982
+ case MODE_NONE:
2983
+ break;
2984
+ }
2985
+
2986
+ return scan_command_token(lexer, state, valid_symbols, symbol);
2987
+ }
2988
+
3032
2989
  static void
3033
2990
  update_regex_position_after_symbol(ScannerState *state, TSSymbol symbol) {
3034
2991
  #if !SED_REGEX_EXTENDED
@@ -3037,9 +2994,7 @@ update_regex_position_after_symbol(ScannerState *state, TSSymbol symbol) {
3037
2994
  BRE_VERTICAL_LINE_ESCAPE_MARKER ||
3038
2995
  symbol ==
3039
2996
  BRE_QUESTION_MARK_ESCAPE_MARKER ||
3040
- symbol ==
3041
- BRE_PLUS_ESCAPE_MARKER ||
3042
- symbol == UNMATCHED_INTERVAL_CLOSE_MARKER
2997
+ symbol == BRE_PLUS_ESCAPE_MARKER
3043
2998
  ) {
3044
2999
  return;
3045
3000
  }
@@ -3081,7 +3036,15 @@ update_regex_position_after_symbol(ScannerState *state, TSSymbol symbol) {
3081
3036
  }
3082
3037
  #endif
3083
3038
 
3084
- if (symbol == REGEX_BEGINNING_ANCHOR || symbol == REGEX_END_ANCHOR) {
3039
+ bool is_anchor =
3040
+ symbol == REGEX_BEGINNING_ANCHOR || symbol == REGEX_END_ANCHOR;
3041
+ #if !SED_REGEX_EXTENDED
3042
+ is_anchor = is_anchor ||
3043
+ symbol ==
3044
+ REGEX_BRE_SUBEXPRESSION_CARET ||
3045
+ symbol == REGEX_BRE_SUBEXPRESSION_DOLLAR;
3046
+ #endif
3047
+ if (is_anchor) {
3085
3048
  set_regex_position(state, true, REGEX_DUPLICATION_NONE, false, true);
3086
3049
  return;
3087
3050
  }