tree-sitter-sed 0.2.0 → 0.4.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
@@ -1,5 +1,5 @@
1
- #ifndef TREE_SITTER_POSIX_SED_COMMON_SCANNER_H_
2
- #define TREE_SITTER_POSIX_SED_COMMON_SCANNER_H_
1
+ #ifndef TREE_SITTER_SED_COMMON_SCANNER_H_
2
+ #define TREE_SITTER_SED_COMMON_SCANNER_H_
3
3
 
4
4
  #ifndef SED_REGEX_EXTENDED
5
5
  #error "SED_REGEX_EXTENDED must be defined before including scanner.h"
@@ -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,
@@ -248,6 +246,17 @@ enum {
248
246
  SCANNER_SERIALIZED_STATE_SIZE = 17,
249
247
  };
250
248
 
249
+ enum {
250
+ SERIALIZED_AT_BRANCH_START_FLAG = 1 << 0,
251
+ SERIALIZED_AFTER_ALTERNATION_FLAG = 1 << 1,
252
+ SERIALIZED_AFTER_ANCHOR_FLAG = 1 << 2,
253
+ SERIALIZED_TEXT_STATE_SHIFT = 3,
254
+ SERIALIZED_MODE_FLAGS_MAXIMUM = 31,
255
+ SERIALIZED_RANGE_PENDING_FLAG = 1 << 0,
256
+ SERIALIZED_DUPLICATION_STATE_SHIFT = 1,
257
+ SERIALIZED_BRACKET_FLAGS_MAXIMUM = 7,
258
+ };
259
+
251
260
  static void reset_bracket_tracking(ScannerState *state) {
252
261
  state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
253
262
  state->regex_bracket_pending_element = REGEX_BRACKET_PENDING_NONE;
@@ -306,6 +315,10 @@ static uint16_t deserialize_uint16(const char *buffer, unsigned offset) {
306
315
  ((uint16_t)(unsigned char)buffer[offset + 1] << 8));
307
316
  }
308
317
 
318
+ static bool is_regex_mode(enum ScannerMode mode) {
319
+ return mode == MODE_REGEX_ADDRESS || mode == MODE_SUBSTITUTE_PATTERN;
320
+ }
321
+
309
322
  static unsigned sed_scanner_serialize(void *payload, char *buffer) {
310
323
  const ScannerState *state = payload;
311
324
  const uint32_t delimiter = (uint32_t)state->delimiter;
@@ -313,10 +326,11 @@ static unsigned sed_scanner_serialize(void *payload, char *buffer) {
313
326
  buffer[0] = SCANNER_SERIALIZATION_VERSION;
314
327
  buffer[1] = (char)state->mode;
315
328
  buffer[2] = (char)state->regex_state;
316
- buffer[3] = (state->regex_at_branch_start ? 1 : 0) |
317
- (state->regex_after_alternation ? 2 : 0) |
318
- (state->regex_after_anchor ? 4 : 0) |
319
- ((unsigned char)state->text_state << 3);
329
+ buffer[3] =
330
+ (state->regex_at_branch_start ? SERIALIZED_AT_BRANCH_START_FLAG : 0) |
331
+ (state->regex_after_alternation ? SERIALIZED_AFTER_ALTERNATION_FLAG : 0) |
332
+ (state->regex_after_anchor ? SERIALIZED_AFTER_ANCHOR_FLAG : 0) |
333
+ ((unsigned char)state->text_state << SERIALIZED_TEXT_STATE_SHIFT);
320
334
  buffer[4] = (char)(delimiter & UINT32_C(0xff));
321
335
  buffer[5] = (char)((delimiter >> 8) & UINT32_C(0xff));
322
336
  buffer[6] = (char)((delimiter >> 16) & UINT32_C(0xff));
@@ -328,11 +342,103 @@ static unsigned sed_scanner_serialize(void *payload, char *buffer) {
328
342
  buffer[13] = (char)state->regex_bracket_first_element;
329
343
  buffer[14] = (char)state->regex_bracket_last_element;
330
344
  buffer[15] = (char)state->regex_bracket_element_count;
331
- buffer[16] = (state->regex_bracket_range_pending ? 1 : 0) |
332
- ((unsigned char)state->regex_duplication_state << 1);
345
+ buffer[16] =
346
+ (state->regex_bracket_range_pending ? SERIALIZED_RANGE_PENDING_FLAG : 0) |
347
+ ((unsigned char)state->regex_duplication_state
348
+ << SERIALIZED_DUPLICATION_STATE_SHIFT);
333
349
  return SCANNER_SERIALIZED_STATE_SIZE;
334
350
  }
335
351
 
352
+ static bool bracket_tracking_is_reset(const ScannerState *state) {
353
+ return state->regex_bracket_term_state ==
354
+ REGEX_BRACKET_TERM_NONE &&
355
+ state->regex_bracket_pending_element ==
356
+ REGEX_BRACKET_PENDING_NONE &&
357
+ state->regex_bracket_first_element ==
358
+ REGEX_BRACKET_PENDING_NONE &&
359
+ state->regex_bracket_last_element ==
360
+ REGEX_BRACKET_PENDING_NONE &&
361
+ state->regex_bracket_element_count ==
362
+ 0 &&
363
+ !state->regex_bracket_range_pending;
364
+ }
365
+
366
+ static bool regex_position_is_reset(const ScannerState *state) {
367
+ return !state->regex_at_branch_start &&
368
+ state->regex_duplication_state ==
369
+ REGEX_DUPLICATION_NONE &&
370
+ !state->regex_after_alternation &&
371
+ !state->regex_after_anchor;
372
+ }
373
+
374
+ static bool deserialized_delimiter_is_valid(uint32_t delimiter) {
375
+ return delimiter !=
376
+ 0 &&
377
+ delimiter <=
378
+ UINT32_C(0x10ffff) &&
379
+ !(delimiter >= UINT32_C(0xd800) && delimiter <= UINT32_C(0xdfff)) &&
380
+ delimiter !=
381
+ (uint32_t)'\\' &&
382
+ delimiter != (uint32_t)'\n';
383
+ }
384
+
385
+ static bool deserialized_state_is_valid(const ScannerState *candidate) {
386
+ if (candidate->mode == MODE_NONE) {
387
+ return false;
388
+ }
389
+
390
+ if (candidate->mode == MODE_TEXT) {
391
+ return candidate->delimiter ==
392
+ 0 &&
393
+ candidate->regex_state ==
394
+ REGEX_OUTSIDE_BRACKET &&
395
+ regex_position_is_reset(candidate) &&
396
+ candidate->regex_group_depth ==
397
+ 0 &&
398
+ candidate->regex_interval_state ==
399
+ REGEX_INTERVAL_NONE &&
400
+ bracket_tracking_is_reset(candidate);
401
+ }
402
+
403
+ if (!deserialized_delimiter_is_valid((uint32_t)candidate->delimiter)) {
404
+ return false;
405
+ }
406
+
407
+ if (!is_regex_mode(candidate->mode)) {
408
+ return candidate->regex_state ==
409
+ REGEX_OUTSIDE_BRACKET &&
410
+ regex_position_is_reset(candidate) &&
411
+ candidate->text_state ==
412
+ TEXT_EMPTY &&
413
+ candidate->regex_interval_state ==
414
+ REGEX_INTERVAL_NONE &&
415
+ bracket_tracking_is_reset(candidate) &&
416
+ candidate->regex_group_depth == 0;
417
+ }
418
+
419
+ if (candidate->text_state != TEXT_EMPTY) {
420
+ return false;
421
+ }
422
+
423
+ if (candidate->regex_state == REGEX_OUTSIDE_BRACKET) {
424
+ return bracket_tracking_is_reset(candidate);
425
+ }
426
+
427
+ if (!regex_position_is_reset(candidate)) {
428
+ return false;
429
+ }
430
+
431
+ if (
432
+ candidate->regex_state ==
433
+ REGEX_BRACKET_FIRST ||
434
+ candidate->regex_state == REGEX_BRACKET_AFTER_CARET
435
+ ) {
436
+ return bracket_tracking_is_reset(candidate);
437
+ }
438
+
439
+ return true;
440
+ }
441
+
336
442
  static void
337
443
  sed_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
338
444
  ScannerState *state = payload;
@@ -346,256 +452,106 @@ sed_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
346
452
  return;
347
453
  }
348
454
 
349
- const enum ScannerMode mode = (enum ScannerMode)(unsigned char)buffer[1];
350
- const enum RegexState regex_state = (enum RegexState)(unsigned char)buffer[2];
351
455
  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
456
  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) {
457
+ const ScannerState candidate = {
458
+ .delimiter = (int32_t)((uint32_t)(unsigned char)buffer[4] |
459
+ ((uint32_t)(unsigned char)buffer[5] << 8) |
460
+ ((uint32_t)(unsigned char)buffer[6] << 16) |
461
+ ((uint32_t)(unsigned char)buffer[7] << 24)),
462
+ .mode = (enum ScannerMode)(unsigned char)buffer[1],
463
+ .regex_state = (enum RegexState)(unsigned char)buffer[2],
464
+ .regex_at_branch_start =
465
+ (mode_flags & SERIALIZED_AT_BRANCH_START_FLAG) != 0,
466
+ .regex_duplication_state = (enum RegexDuplicationState)(
467
+ (regex_bracket_flags >> SERIALIZED_DUPLICATION_STATE_SHIFT) & 3U
468
+ ),
469
+ .regex_after_alternation =
470
+ (mode_flags & SERIALIZED_AFTER_ALTERNATION_FLAG) != 0,
471
+ .regex_after_anchor = (mode_flags & SERIALIZED_AFTER_ANCHOR_FLAG) != 0,
472
+ .text_state =
473
+ (enum TextState)((mode_flags >> SERIALIZED_TEXT_STATE_SHIFT) & 3U),
474
+ .regex_interval_state = (enum RegexIntervalState)(unsigned char)buffer[10],
475
+ .regex_bracket_term_state =
476
+ (enum RegexBracketTermState)(unsigned char)buffer[11],
477
+ .regex_bracket_pending_element =
478
+ (enum RegexBracketPendingElement)(unsigned char)buffer[12],
479
+ .regex_bracket_first_element =
480
+ (enum RegexBracketPendingElement)(unsigned char)buffer[13],
481
+ .regex_bracket_last_element =
482
+ (enum RegexBracketPendingElement)(unsigned char)buffer[14],
483
+ .regex_bracket_element_count = (uint8_t)(unsigned char)buffer[15],
484
+ .regex_bracket_range_pending =
485
+ (regex_bracket_flags & SERIALIZED_RANGE_PENDING_FLAG) != 0,
486
+ .regex_group_depth = deserialize_uint16(buffer, 8),
487
+ };
488
+
489
+ if (candidate.mode > MODE_TEXT) {
375
490
  return;
376
491
  }
377
492
 
378
- if (regex_state > REGEX_BRACKET_BODY) {
493
+ if (candidate.regex_state > REGEX_BRACKET_BODY) {
379
494
  return;
380
495
  }
381
496
 
382
- if ((mode_flags & (unsigned char)~31U) != 0) {
497
+ if ((mode_flags & (unsigned char)~SERIALIZED_MODE_FLAGS_MAXIMUM) != 0) {
383
498
  return;
384
499
  }
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) {
500
+ if (candidate.text_state > TEXT_AFTER_ESCAPED_NEWLINE) {
390
501
  return;
391
502
  }
392
503
  #if !SED_REGEX_EXTENDED
393
- if (regex_after_alternation) {
504
+ if (candidate.regex_after_alternation) {
394
505
  return;
395
506
  }
396
507
  #endif
397
508
 
398
- if (regex_interval_state > REGEX_INTERVAL_AFTER_MAXIMUM) {
509
+ if (candidate.regex_interval_state > REGEX_INTERVAL_AFTER_MAXIMUM) {
399
510
  return;
400
511
  }
401
- if (regex_bracket_term_state > REGEX_BRACKET_TERM_EQUAL) {
512
+ if (candidate.regex_bracket_term_state > REGEX_BRACKET_TERM_EQUAL) {
402
513
  return;
403
514
  }
404
515
  if (
405
- regex_bracket_pending_element >
516
+ candidate.regex_bracket_pending_element >
406
517
  REGEX_BRACKET_PENDING_COLON ||
407
- regex_bracket_first_element >
518
+ candidate.regex_bracket_first_element >
408
519
  REGEX_BRACKET_PENDING_COLON ||
409
- regex_bracket_last_element >
520
+ candidate.regex_bracket_last_element >
410
521
  REGEX_BRACKET_PENDING_COLON ||
411
- regex_bracket_element_count >
522
+ candidate.regex_bracket_element_count >
412
523
  3U ||
413
- (regex_bracket_flags & (unsigned char)~7U) !=
524
+ (regex_bracket_flags & (unsigned char)~SERIALIZED_BRACKET_FLAGS_MAXIMUM) !=
414
525
  0 ||
415
526
  #if SED_REGEX_EXTENDED
416
- regex_duplication_state > REGEX_AFTER_REPETITION_MODIFIER
527
+ candidate.regex_duplication_state > REGEX_AFTER_REPETITION_MODIFIER
417
528
  #else
418
- regex_duplication_state > REGEX_AFTER_DUPLICATION_SYMBOL
529
+ candidate.regex_duplication_state > REGEX_AFTER_DUPLICATION_SYMBOL
419
530
  #endif
420
531
  ) {
421
532
  return;
422
533
  }
423
534
  if (
424
- (regex_bracket_element_count ==
535
+ (candidate.regex_bracket_element_count ==
425
536
  0 &&
426
- (regex_bracket_first_element !=
537
+ (candidate.regex_bracket_first_element !=
427
538
  REGEX_BRACKET_PENDING_NONE ||
428
- regex_bracket_last_element != REGEX_BRACKET_PENDING_NONE)) ||
429
- (regex_bracket_element_count >
539
+ candidate.regex_bracket_last_element != REGEX_BRACKET_PENDING_NONE)) ||
540
+ (candidate.regex_bracket_element_count >
430
541
  0 &&
431
- (regex_bracket_first_element ==
542
+ (candidate.regex_bracket_first_element ==
432
543
  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 ==
463
- REGEX_BRACKET_PENDING_NONE &&
464
- regex_bracket_first_element ==
544
+ candidate.regex_bracket_last_element == REGEX_BRACKET_PENDING_NONE)) ||
545
+ (candidate.regex_bracket_pending_element !=
465
546
  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)
518
- ) {
519
- return;
520
- }
521
-
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;
532
- }
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
547
+ candidate.regex_bracket_range_pending)
570
548
  ) {
571
549
  return;
572
550
  }
573
551
 
574
- if (
575
- mode !=
576
- MODE_REGEX_ADDRESS &&
577
- mode !=
578
- MODE_SUBSTITUTE_PATTERN &&
579
- regex_group_depth != 0
580
- ) {
581
- return;
552
+ if (deserialized_state_is_valid(&candidate)) {
553
+ *state = candidate;
582
554
  }
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
555
  }
600
556
 
601
557
  static void advance(TSLexer *lexer) {
@@ -789,6 +745,42 @@ static bool scan_substitution_wfile_argument(TSLexer *lexer) {
789
745
  return true;
790
746
  }
791
747
 
748
+ enum FlagAfterWriteScan {
749
+ FLAG_AFTER_WRITE_NONE,
750
+ FLAG_AFTER_WRITE_MATCH,
751
+ FLAG_AFTER_WRITE_FALLBACK,
752
+ };
753
+
754
+ static bool is_substitution_flag_character(int32_t character) {
755
+ if (is_digit(character)) {
756
+ return true;
757
+ }
758
+
759
+ switch (character) {
760
+ case 'g':
761
+ case 'i':
762
+ case 'p':
763
+ case 'w':
764
+ return true;
765
+ default:
766
+ return false;
767
+ }
768
+ }
769
+
770
+ static enum FlagAfterWriteScan scan_flag_after_write_marker(TSLexer *lexer) {
771
+ if (!is_substitution_flag_character(lexer->lookahead)) {
772
+ return FLAG_AFTER_WRITE_NONE;
773
+ }
774
+
775
+ lexer->mark_end(lexer);
776
+ do {
777
+ advance(lexer);
778
+ } while (is_substitution_flag_character(lexer->lookahead));
779
+
780
+ return is_blank(lexer->lookahead) ? FLAG_AFTER_WRITE_MATCH
781
+ : FLAG_AFTER_WRITE_FALLBACK;
782
+ }
783
+
792
784
  static bool scan_right_brace(TSLexer *lexer, ScannerState *state) {
793
785
  if (state->mode != MODE_NONE) {
794
786
  return false;
@@ -883,8 +875,8 @@ static enum PostBlankRecoveryScan scan_post_blank_recovery(
883
875
  ) {
884
876
  if (
885
877
  !valid_symbols[OMITTED_ADDRESS_MARKER] &&
886
- !valid_symbols[ADDITIONAL_ADDRESS_MARKER] &&
887
- !valid_symbols[BLANKS_AROUND_ADDRESS_SEPARATOR_MARKER] &&
878
+ !valid_symbols[INCOMPLETE_OMITTED_ADDRESS_MARKER] &&
879
+ !valid_symbols[BLANKS_AROUND_ADDRESS_SEPARATOR] &&
888
880
  !valid_symbols[MISSING_ADDRESS_SEPARATOR_MARKER] &&
889
881
  !valid_symbols[MISSING_SEPARATOR_BEFORE_UNMATCHED_BRACE_MARKER] &&
890
882
  !valid_symbols[MISSING_COMMAND_SEPARATOR_MARKER] &&
@@ -896,22 +888,23 @@ static enum PostBlankRecoveryScan scan_post_blank_recovery(
896
888
  lexer->mark_end(lexer);
897
889
  advance_past_blanks(lexer);
898
890
 
899
- if (valid_symbols[OMITTED_ADDRESS_MARKER] && !can_start_address(lexer)) {
900
- *symbol = OMITTED_ADDRESS_MARKER;
901
- return POST_BLANK_RECOVERY_TOKEN;
902
- }
891
+ const bool after_separator = valid_symbols[OMITTED_ADDRESS_MARKER] ||
892
+ valid_symbols[INCOMPLETE_OMITTED_ADDRESS_MARKER];
893
+
903
894
  if (
904
- valid_symbols[ADDITIONAL_ADDRESS_MARKER] &&
905
- (lexer->lookahead == ',' || can_start_address(lexer))
895
+ valid_symbols[BLANKS_AROUND_ADDRESS_SEPARATOR] &&
896
+ (after_separator ? can_start_address(lexer) : lexer->lookahead == ',')
906
897
  ) {
907
- *symbol = ADDITIONAL_ADDRESS_MARKER;
898
+ lexer->mark_end(lexer);
899
+ *symbol = BLANKS_AROUND_ADDRESS_SEPARATOR;
908
900
  return POST_BLANK_RECOVERY_TOKEN;
909
901
  }
910
- if (
911
- valid_symbols[BLANKS_AROUND_ADDRESS_SEPARATOR_MARKER] &&
912
- lexer->lookahead == ','
913
- ) {
914
- *symbol = BLANKS_AROUND_ADDRESS_SEPARATOR_MARKER;
902
+ if (after_separator && !can_start_address(lexer)) {
903
+ *symbol = lexer->eof(lexer) ? INCOMPLETE_OMITTED_ADDRESS_MARKER
904
+ : OMITTED_ADDRESS_MARKER;
905
+ if (!valid_symbols[*symbol]) {
906
+ return POST_BLANK_RECOVERY_FAILED;
907
+ }
915
908
  return POST_BLANK_RECOVERY_TOKEN;
916
909
  }
917
910
  if (
@@ -1021,10 +1014,6 @@ static bool scan_text_token(
1021
1014
  return true;
1022
1015
  }
1023
1016
 
1024
- static bool is_regex_mode(enum ScannerMode mode) {
1025
- return mode == MODE_REGEX_ADDRESS || mode == MODE_SUBSTITUTE_PATTERN;
1026
- }
1027
-
1028
1017
  static bool regex_is_inside_bracket(const ScannerState *state) {
1029
1018
  return state->regex_state != REGEX_OUTSIDE_BRACKET;
1030
1019
  }
@@ -1125,44 +1114,36 @@ update_bracket_state_after_literal(ScannerState *state, int32_t character) {
1125
1114
  static bool
1126
1115
  regex_literal_boundary(const ScannerState *state, int32_t character) {
1127
1116
  if (state->regex_state == REGEX_OUTSIDE_BRACKET) {
1128
- return character ==
1129
- state->delimiter ||
1130
- character ==
1131
- '\\' ||
1132
- character ==
1133
- '(' ||
1134
- character ==
1135
- ')' ||
1136
- character ==
1137
- '[' ||
1138
- character ==
1139
- '*' ||
1140
- character ==
1141
- '+' ||
1142
- character ==
1143
- '?' ||
1144
- character ==
1145
- '|' ||
1146
- character ==
1147
- '{' ||
1148
- character ==
1149
- '.' ||
1150
- character ==
1151
- '^' ||
1152
- character == '$';
1117
+ switch (character) {
1118
+ case '\\':
1119
+ case '(':
1120
+ case ')':
1121
+ case '[':
1122
+ case '*':
1123
+ case '+':
1124
+ case '?':
1125
+ case '|':
1126
+ case '{':
1127
+ case '.':
1128
+ case '^':
1129
+ case '$':
1130
+ return true;
1131
+ default:
1132
+ return character == state->delimiter;
1133
+ }
1153
1134
  }
1154
1135
 
1155
- if (
1156
- character ==
1157
- '[' ||
1158
- (state->regex_state == REGEX_BRACKET_FIRST && character == '^') ||
1159
- (state->regex_state == REGEX_BRACKET_BODY && character == '-') ||
1160
- (state->regex_state == REGEX_BRACKET_BODY && character == ']')
1161
- ) {
1136
+ switch (character) {
1137
+ case '[':
1162
1138
  return true;
1139
+ case '^':
1140
+ return state->regex_state == REGEX_BRACKET_FIRST;
1141
+ case '-':
1142
+ case ']':
1143
+ return state->regex_state == REGEX_BRACKET_BODY;
1144
+ default:
1145
+ return false;
1163
1146
  }
1164
-
1165
- return false;
1166
1147
  }
1167
1148
 
1168
1149
  static enum LiteralScanResult
@@ -1230,15 +1211,19 @@ static bool scan_regex_bracket_opener(
1230
1211
  lexer->mark_end(lexer);
1231
1212
 
1232
1213
  TSSymbol candidate;
1214
+ enum RegexBracketTermState term_state;
1233
1215
  switch (lexer->lookahead) {
1234
1216
  case ':':
1235
1217
  candidate = REGEX_OPEN_COLON;
1218
+ term_state = REGEX_BRACKET_TERM_COLON;
1236
1219
  break;
1237
1220
  case '.':
1238
1221
  candidate = REGEX_OPEN_DOT;
1222
+ term_state = REGEX_BRACKET_TERM_DOT;
1239
1223
  break;
1240
1224
  case '=':
1241
1225
  candidate = REGEX_OPEN_EQUAL;
1226
+ term_state = REGEX_BRACKET_TERM_EQUAL;
1242
1227
  break;
1243
1228
  default:
1244
1229
  begin_single_bracket_element(state, '[');
@@ -1252,10 +1237,7 @@ static bool scan_regex_bracket_opener(
1252
1237
  consume(lexer);
1253
1238
  begin_compound_bracket_element(state);
1254
1239
  finish_first_bracket_element(state);
1255
- state->regex_bracket_term_state = candidate == REGEX_OPEN_COLON
1256
- ? REGEX_BRACKET_TERM_COLON
1257
- : candidate == REGEX_OPEN_DOT ? REGEX_BRACKET_TERM_DOT
1258
- : REGEX_BRACKET_TERM_EQUAL;
1240
+ state->regex_bracket_term_state = term_state;
1259
1241
  *symbol = candidate;
1260
1242
  return true;
1261
1243
  }
@@ -1277,6 +1259,18 @@ static bool bracket_meta_character(int32_t character) {
1277
1259
  return character == '^' || character == '-' || character == ']';
1278
1260
  }
1279
1261
 
1262
+ static int32_t
1263
+ bracket_term_close_marker(enum RegexBracketTermState term_state) {
1264
+ switch (term_state) {
1265
+ case REGEX_BRACKET_TERM_COLON:
1266
+ return ':';
1267
+ case REGEX_BRACKET_TERM_DOT:
1268
+ return '.';
1269
+ default:
1270
+ return '=';
1271
+ }
1272
+ }
1273
+
1280
1274
  static TSSymbol regex_bracket_term_content_symbol(
1281
1275
  const ScannerState *state,
1282
1276
  uint8_t character_count,
@@ -1509,6 +1503,18 @@ static bool scan_regex_interval(
1509
1503
  return emit_symbol(valid_symbols, REGEX_INTERVAL_OPEN, symbol);
1510
1504
  }
1511
1505
 
1506
+ static bool emit_interval_issue(
1507
+ TSLexer *lexer,
1508
+ ScannerState *state,
1509
+ TSSymbol candidate,
1510
+ TSSymbol *symbol
1511
+ ) {
1512
+ lexer->mark_end(lexer);
1513
+ state->regex_interval_state = REGEX_INTERVAL_NONE;
1514
+ *symbol = candidate;
1515
+ return true;
1516
+ }
1517
+
1512
1518
  static bool
1513
1519
  scan_invalid_interval_remainder(TSLexer *lexer, ScannerState *state);
1514
1520
 
@@ -1604,9 +1610,7 @@ static enum DuplicationContextScan scan_regex_duplication_context_marker(
1604
1610
  #endif
1605
1611
 
1606
1612
  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;
1613
+ emit_interval_issue(lexer, state, REGEX_INCOMPLETE_INTERVAL, symbol);
1610
1614
  return DUPLICATION_CONTEXT_TOKEN;
1611
1615
  }
1612
1616
 
@@ -1615,12 +1619,25 @@ static enum DuplicationContextScan scan_regex_duplication_context_marker(
1615
1619
  return DUPLICATION_CONTEXT_TOKEN;
1616
1620
  }
1617
1621
  scan_invalid_interval_remainder(lexer, state);
1618
- lexer->mark_end(lexer);
1619
- state->regex_interval_state = REGEX_INTERVAL_NONE;
1620
- *symbol = REGEX_INVALID_INTERVAL;
1622
+ emit_interval_issue(lexer, state, REGEX_INVALID_INTERVAL, symbol);
1621
1623
  return DUPLICATION_CONTEXT_TOKEN;
1622
1624
  }
1623
1625
 
1626
+ static bool raw_regex_operator_character(int32_t character) {
1627
+ switch (character) {
1628
+ case '(':
1629
+ case ')':
1630
+ case '*':
1631
+ case '+':
1632
+ case '?':
1633
+ case '|':
1634
+ case '{':
1635
+ return true;
1636
+ default:
1637
+ return false;
1638
+ }
1639
+ }
1640
+
1624
1641
  static bool scan_raw_regex_operator(
1625
1642
  TSLexer *lexer,
1626
1643
  ScannerState *state,
@@ -1689,39 +1706,42 @@ static bool scan_raw_regex_operator(
1689
1706
  }
1690
1707
 
1691
1708
  static bool regex_delimiter_is_special(int32_t character) {
1709
+ switch (character) {
1692
1710
  #if SED_REGEX_EXTENDED
1693
- return character ==
1694
- '.' ||
1695
- character ==
1696
- '[' ||
1697
- character ==
1698
- '(' ||
1699
- character ==
1700
- ')' ||
1701
- character ==
1702
- '*' ||
1703
- character ==
1704
- '+' ||
1705
- character ==
1706
- '?' ||
1707
- character ==
1708
- '{' ||
1709
- character ==
1710
- '|' ||
1711
- character ==
1712
- '^' ||
1713
- character == '$';
1714
- #else
1715
- return character ==
1716
- '.' ||
1717
- character ==
1718
- '[' ||
1719
- character ==
1720
- '*' ||
1721
- character ==
1722
- '^' ||
1723
- character == '$';
1711
+ case '(':
1712
+ case ')':
1713
+ case '+':
1714
+ case '?':
1715
+ case '{':
1716
+ case '|':
1717
+ #endif
1718
+ case '.':
1719
+ case '[':
1720
+ case '*':
1721
+ case '^':
1722
+ case '$':
1723
+ return true;
1724
+ default:
1725
+ return false;
1726
+ }
1727
+ }
1728
+
1729
+ static bool escape_quotes_regex_syntax(int32_t character) {
1730
+ switch (character) {
1731
+ #if SED_REGEX_EXTENDED
1732
+ case '}':
1724
1733
  #endif
1734
+ case '.':
1735
+ case '*':
1736
+ case '^':
1737
+ case '$':
1738
+ case '[':
1739
+ case '\\':
1740
+ case ']':
1741
+ return true;
1742
+ default:
1743
+ return false;
1744
+ }
1725
1745
  }
1726
1746
 
1727
1747
  static bool scan_regex_escaped_delimiter(
@@ -1837,29 +1857,11 @@ static bool scan_regex_escape_after_backslash(
1837
1857
  return emit_symbol(valid_symbols, REGEX_NEWLINE_ESCAPE, symbol);
1838
1858
  }
1839
1859
 
1840
- const int32_t character = lexer->lookahead;
1841
- const bool quotes_regex_syntax = character ==
1842
- '.' ||
1843
- character ==
1844
- '*' ||
1845
- character ==
1846
- '^' ||
1847
- character ==
1848
- '$' ||
1849
- character ==
1850
- '[' ||
1851
- character ==
1852
- '\\' ||
1853
- character ==
1854
- ']' ||
1855
- (SED_REGEX_EXTENDED && character == '}');
1856
- if (!quotes_regex_syntax) {
1857
- consume(lexer);
1858
- return emit_symbol(valid_symbols, REGEX_NONPORTABLE_ESCAPE, symbol);
1859
- }
1860
-
1860
+ const TSSymbol candidate = escape_quotes_regex_syntax(lexer->lookahead)
1861
+ ? REGEX_QUOTED_ESCAPE
1862
+ : REGEX_NONPORTABLE_ESCAPE;
1861
1863
  consume(lexer);
1862
- return emit_symbol(valid_symbols, REGEX_QUOTED_ESCAPE, symbol);
1864
+ return emit_symbol(valid_symbols, candidate, symbol);
1863
1865
  }
1864
1866
 
1865
1867
  #if !SED_REGEX_EXTENDED
@@ -2053,10 +2055,12 @@ static bool scan_regex_token(
2053
2055
  return true;
2054
2056
  }
2055
2057
  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;
2058
+ return emit_interval_issue(
2059
+ lexer,
2060
+ state,
2061
+ REGEX_INCOMPLETE_INTERVAL,
2062
+ symbol
2063
+ );
2060
2064
  }
2061
2065
  if (!valid_symbols[REGEX_INVALID_INTERVAL]) {
2062
2066
  return false;
@@ -2067,10 +2071,7 @@ static bool scan_regex_token(
2067
2071
  advance_past_escaped_character(lexer);
2068
2072
  scan_invalid_interval_remainder(lexer, state);
2069
2073
  }
2070
- lexer->mark_end(lexer);
2071
- state->regex_interval_state = REGEX_INTERVAL_NONE;
2072
- *symbol = REGEX_INVALID_INTERVAL;
2073
- return true;
2074
+ return emit_interval_issue(lexer, state, REGEX_INVALID_INTERVAL, symbol);
2074
2075
  }
2075
2076
  #endif
2076
2077
 
@@ -2092,14 +2093,10 @@ static bool scan_regex_token(
2092
2093
  valid_symbols[REGEX_COLL_ELEM_MULTI] ||
2093
2094
  valid_symbols[REGEX_META_CHAR]
2094
2095
  ) {
2095
- const int32_t close_marker =
2096
- state->regex_bracket_term_state == REGEX_BRACKET_TERM_COLON ? ':'
2097
- : state->regex_bracket_term_state == REGEX_BRACKET_TERM_DOT ? '.'
2098
- : '=';
2099
2096
  return scan_regex_bracket_term_content(
2100
2097
  lexer,
2101
2098
  state,
2102
- close_marker,
2099
+ bracket_term_close_marker(state->regex_bracket_term_state),
2103
2100
  valid_symbols,
2104
2101
  symbol
2105
2102
  );
@@ -2234,21 +2231,7 @@ static bool scan_regex_token(
2234
2231
  );
2235
2232
  }
2236
2233
 
2237
- if (
2238
- lexer->lookahead ==
2239
- '(' ||
2240
- lexer->lookahead ==
2241
- ')' ||
2242
- lexer->lookahead ==
2243
- '*' ||
2244
- lexer->lookahead ==
2245
- '+' ||
2246
- lexer->lookahead ==
2247
- '?' ||
2248
- lexer->lookahead ==
2249
- '|' ||
2250
- lexer->lookahead == '{'
2251
- ) {
2234
+ if (raw_regex_operator_character(lexer->lookahead)) {
2252
2235
  return scan_raw_regex_operator(lexer, state, valid_symbols, symbol);
2253
2236
  }
2254
2237
 
@@ -2514,226 +2497,196 @@ static bool scan_translate_token(
2514
2497
  return false;
2515
2498
  }
2516
2499
 
2517
- static bool sed_scanner_scan_impl(
2518
- ScannerState *state,
2500
+ static bool scan_regex_recovery_marker(
2519
2501
  TSLexer *lexer,
2502
+ ScannerState *state,
2520
2503
  const bool *valid_symbols,
2521
2504
  TSSymbol *symbol
2522
2505
  ) {
2523
- if (valid_symbols[ERROR_SENTINEL]) {
2524
- return false;
2506
+ #if !SED_REGEX_EXTENDED
2507
+ if (
2508
+ emit_missing_marker(
2509
+ lexer,
2510
+ valid_symbols,
2511
+ BRE_VERTICAL_LINE_ESCAPE_MARKER,
2512
+ symbol
2513
+ ) ||
2514
+ emit_missing_marker(
2515
+ lexer,
2516
+ valid_symbols,
2517
+ BRE_QUESTION_MARK_ESCAPE_MARKER,
2518
+ symbol
2519
+ ) ||
2520
+ emit_missing_marker(lexer, valid_symbols, BRE_PLUS_ESCAPE_MARKER, symbol)
2521
+ ) {
2522
+ return true;
2525
2523
  }
2524
+ #endif
2526
2525
 
2527
- if (state->mode == MODE_TEXT) {
2528
- return scan_text_token(lexer, state, valid_symbols, symbol);
2529
- }
2526
+ const bool at_line_boundary = lexer->eof(lexer) || lexer->lookahead == '\n';
2527
+ const bool at_regex_end =
2528
+ at_line_boundary || lexer->lookahead == state->delimiter;
2530
2529
 
2531
- #if !SED_REGEX_EXTENDED
2532
2530
  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
- ))
2558
- ) {
2559
- return true;
2560
- }
2561
- #endif
2562
-
2563
- if (
2564
- is_regex_mode(state->mode) &&
2565
2531
  state->regex_state ==
2566
2532
  REGEX_OUTSIDE_BRACKET &&
2567
2533
  state->regex_group_depth >
2568
2534
  0 &&
2569
2535
  !state->regex_after_alternation &&
2570
- (lexer->eof(lexer) ||
2571
- lexer->lookahead ==
2572
- '\n' ||
2573
- lexer->lookahead == state->delimiter)
2536
+ at_regex_end &&
2537
+ emit_missing_marker(
2538
+ lexer,
2539
+ valid_symbols,
2540
+ lexer->eof(lexer) ? MISSING_SUBEXPRESSION_MARKER
2541
+ : MISSING_SUBEXPRESSION_PLACEHOLDER_MARKER,
2542
+ symbol
2543
+ )
2574
2544
  ) {
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
- }
2545
+ return true;
2583
2546
  }
2584
2547
 
2585
2548
  if (
2586
- is_regex_mode(state->mode) &&
2587
2549
  (state->regex_state ==
2588
2550
  REGEX_BRACKET_FIRST ||
2589
2551
  state->regex_state == REGEX_BRACKET_AFTER_CARET) &&
2590
- (lexer->eof(lexer) || lexer->lookahead == '\n')
2552
+ at_line_boundary &&
2553
+ emit_missing_marker(
2554
+ lexer,
2555
+ valid_symbols,
2556
+ lexer->eof(lexer) ? INCOMPLETE_BRACKET_LIST_MARKER
2557
+ : MISSING_BRACKET_LIST_MARKER,
2558
+ symbol
2559
+ )
2591
2560
  ) {
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
- }
2561
+ return true;
2600
2562
  }
2601
2563
 
2602
2564
  if (
2603
- is_regex_mode(state->mode) &&
2604
2565
  state->regex_bracket_term_state !=
2605
2566
  REGEX_BRACKET_TERM_NONE &&
2606
- (lexer->eof(lexer) || lexer->lookahead == '\n')
2567
+ at_line_boundary &&
2568
+ emit_missing_marker(
2569
+ lexer,
2570
+ valid_symbols,
2571
+ lexer->eof(lexer) ? REGEX_INCOMPLETE_BRACKET_TERM
2572
+ : REGEX_MALFORMED_BRACKET_TERM,
2573
+ symbol
2574
+ )
2607
2575
  ) {
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
- }
2576
+ state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
2577
+ finish_compound_bracket_element(state);
2578
+ return true;
2617
2579
  }
2618
2580
 
2619
2581
  if (
2620
- is_regex_mode(state->mode) &&
2621
2582
  regex_is_inside_bracket(state) &&
2622
- (lexer->eof(lexer) || lexer->lookahead == '\n')
2583
+ at_line_boundary &&
2584
+ emit_missing_marker(
2585
+ lexer,
2586
+ valid_symbols,
2587
+ lexer->eof(lexer) ? INCOMPLETE_BRACKET_EXPRESSION_MARKER
2588
+ : UNCLOSED_BRACKET_EXPRESSION_MARKER,
2589
+ symbol
2590
+ )
2623
2591
  ) {
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
- }
2592
+ state->regex_state = REGEX_OUTSIDE_BRACKET;
2593
+ reset_bracket_tracking(state);
2594
+ return true;
2634
2595
  }
2635
2596
 
2636
2597
  #if SED_REGEX_EXTENDED
2637
2598
  if (
2638
- is_regex_mode(state->mode) &&
2639
2599
  state->regex_state ==
2640
2600
  REGEX_OUTSIDE_BRACKET &&
2641
2601
  state->regex_after_alternation &&
2642
- (lexer->lookahead ==
2643
- state->delimiter ||
2644
- lexer->lookahead ==
2645
- '\n' ||
2646
- lexer->eof(lexer))
2602
+ at_regex_end &&
2603
+ emit_missing_marker(
2604
+ lexer,
2605
+ valid_symbols,
2606
+ lexer->eof(lexer) ? INCOMPLETE_ALTERNATIVE_MARKER
2607
+ : EMPTY_ALTERNATIVE_MARKER,
2608
+ symbol
2609
+ )
2647
2610
  ) {
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
- }
2611
+ state->regex_after_alternation = false;
2612
+ return true;
2656
2613
  }
2657
2614
  #endif
2658
2615
 
2659
2616
  if (
2660
- is_regex_mode(state->mode) &&
2661
2617
  state->regex_interval_state !=
2662
2618
  REGEX_INTERVAL_NONE &&
2663
- (lexer->lookahead ==
2664
- state->delimiter ||
2665
- lexer->lookahead ==
2666
- '\n' ||
2619
+ (at_regex_end
2667
2620
  #if !SED_REGEX_EXTENDED
2668
- (state->delimiter == '}' && lexer->lookahead == '\\') ||
2621
+ || (state->delimiter == '}' && lexer->lookahead == '\\')
2669
2622
  #endif
2670
- lexer->eof(lexer))
2623
+ ) &&
2624
+ emit_missing_marker(
2625
+ lexer,
2626
+ valid_symbols,
2627
+ lexer->eof(lexer) ? REGEX_INCOMPLETE_INTERVAL : REGEX_INVALID_INTERVAL,
2628
+ symbol
2629
+ )
2671
2630
  ) {
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
- }
2631
+ state->regex_interval_state = REGEX_INTERVAL_NONE;
2632
+ return true;
2680
2633
  }
2681
2634
 
2682
2635
  if (
2683
- is_regex_mode(state->mode) &&
2684
2636
  state->regex_state ==
2685
2637
  REGEX_OUTSIDE_BRACKET &&
2686
- (lexer->lookahead == '\n' || lexer->eof(lexer))
2638
+ state->regex_group_depth >
2639
+ 0 &&
2640
+ at_line_boundary &&
2641
+ emit_missing_marker(
2642
+ lexer,
2643
+ valid_symbols,
2644
+ lexer->eof(lexer) ? REGEX_INCOMPLETE_GROUP : REGEX_UNCLOSED_GROUP,
2645
+ symbol
2646
+ )
2687
2647
  ) {
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
- }
2648
+ state->regex_group_depth--;
2649
+ return true;
2698
2650
  }
2699
2651
 
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);
2715
- }
2652
+ return false;
2653
+ }
2716
2654
 
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
- }
2655
+ static TSSymbol missing_text_introducer_symbol(const TSLexer *lexer) {
2656
+ return lexer->eof(lexer) ? MISSING_TEXT_INTRODUCER_MARKER
2657
+ : NONCONFORMING_MISSING_TEXT_INTRODUCER_MARKER;
2658
+ }
2731
2659
 
2660
+ static bool scan_command_token(
2661
+ TSLexer *lexer,
2662
+ ScannerState *state,
2663
+ const bool *valid_symbols,
2664
+ TSSymbol *symbol
2665
+ ) {
2732
2666
  if (valid_symbols[LINE_WORD] && scan_to_physical_line_end(lexer, false)) {
2733
2667
  *symbol = LINE_WORD;
2734
2668
  return true;
2735
2669
  }
2736
2670
 
2671
+ if (valid_symbols[FLAG_AFTER_WRITE_MARKER]) {
2672
+ const enum FlagAfterWriteScan scan = scan_flag_after_write_marker(lexer);
2673
+ if (scan == FLAG_AFTER_WRITE_MATCH) {
2674
+ *symbol = FLAG_AFTER_WRITE_MARKER;
2675
+ return true;
2676
+ }
2677
+ if (
2678
+ scan ==
2679
+ FLAG_AFTER_WRITE_FALLBACK &&
2680
+ valid_symbols[OMITTED_FILE_SEPARATOR_MARKER]
2681
+ ) {
2682
+ *symbol = OMITTED_FILE_SEPARATOR_MARKER;
2683
+ return true;
2684
+ }
2685
+ if (scan == FLAG_AFTER_WRITE_FALLBACK) {
2686
+ return false;
2687
+ }
2688
+ }
2689
+
2737
2690
  if (
2738
2691
  valid_symbols[SUBSTITUTION_WFILE_ARGUMENT] &&
2739
2692
  scan_substitution_wfile_argument(lexer)
@@ -2750,15 +2703,7 @@ static bool sed_scanner_scan_impl(
2750
2703
  if (
2751
2704
  valid_symbols[INVALID_SUBSTITUTION_FLAG] &&
2752
2705
  !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' &&
2706
+ !is_substitution_flag_character(lexer->lookahead) &&
2762
2707
  lexer->lookahead !=
2763
2708
  ';' &&
2764
2709
  lexer->lookahead !=
@@ -2777,10 +2722,11 @@ static bool sed_scanner_scan_impl(
2777
2722
  *symbol = TEXT_COMMAND_START;
2778
2723
  return true;
2779
2724
  }
2780
- const TSSymbol introducer_marker = lexer->eof(lexer)
2781
- ? MISSING_TEXT_INTRODUCER_MARKER
2782
- : NONCONFORMING_MISSING_TEXT_INTRODUCER_MARKER;
2783
- return emit_symbol(valid_symbols, introducer_marker, symbol);
2725
+ return emit_symbol(
2726
+ valid_symbols,
2727
+ missing_text_introducer_symbol(lexer),
2728
+ symbol
2729
+ );
2784
2730
  }
2785
2731
 
2786
2732
  if (valid_symbols[DEFAULT_OUTPUT_SUPPRESSION] && lexer->lookahead == 'n') {
@@ -2794,11 +2740,23 @@ static bool sed_scanner_scan_impl(
2794
2740
  return true;
2795
2741
  }
2796
2742
 
2743
+ // Preserve an address interpretation before reserved-function recovery.
2797
2744
  if (
2798
- valid_symbols[RESERVED_UNKNOWN_FUNCTION] &&
2745
+ valid_symbols[MISSING_ADDRESS_SEPARATOR_MARKER] && can_start_address(lexer)
2746
+ ) {
2747
+ return emit_missing_marker(
2748
+ lexer,
2749
+ valid_symbols,
2750
+ MISSING_ADDRESS_SEPARATOR_MARKER,
2751
+ symbol
2752
+ );
2753
+ }
2754
+
2755
+ if (
2756
+ valid_symbols[RESERVED_UNKNOWN_FUNCTION_TOKEN] &&
2799
2757
  scan_reserved_unknown_function(lexer)
2800
2758
  ) {
2801
- *symbol = RESERVED_UNKNOWN_FUNCTION;
2759
+ *symbol = RESERVED_UNKNOWN_FUNCTION_TOKEN;
2802
2760
  return true;
2803
2761
  }
2804
2762
 
@@ -2839,6 +2797,9 @@ static bool sed_scanner_scan_impl(
2839
2797
  }
2840
2798
 
2841
2799
  if (
2800
+ valid_symbols[OMITTED_FIRST_ADDRESS_MARKER] &&
2801
+ lexer->lookahead ==
2802
+ ',' &&
2842
2803
  emit_missing_marker(
2843
2804
  lexer,
2844
2805
  valid_symbols,
@@ -2850,54 +2811,20 @@ static bool sed_scanner_scan_impl(
2850
2811
  }
2851
2812
 
2852
2813
  if (
2853
- valid_symbols[OMITTED_ADDRESS_MARKER] &&
2814
+ (valid_symbols[OMITTED_ADDRESS_MARKER] ||
2815
+ valid_symbols[INCOMPLETE_OMITTED_ADDRESS_MARKER]) &&
2854
2816
  !can_start_address(lexer) &&
2855
2817
  !is_blank(lexer->lookahead)
2856
2818
  ) {
2857
2819
  return emit_missing_marker(
2858
2820
  lexer,
2859
2821
  valid_symbols,
2860
- OMITTED_ADDRESS_MARKER,
2822
+ lexer->eof(lexer) ? INCOMPLETE_OMITTED_ADDRESS_MARKER
2823
+ : OMITTED_ADDRESS_MARKER,
2861
2824
  symbol
2862
2825
  );
2863
2826
  }
2864
2827
 
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,
2873
- symbol
2874
- );
2875
- }
2876
-
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
2828
  if (is_blank(lexer->lookahead)) {
2902
2829
  switch (scan_post_blank_recovery(lexer, valid_symbols, symbol)) {
2903
2830
  case POST_BLANK_RECOVERY_TOKEN:
@@ -2909,18 +2836,6 @@ static bool sed_scanner_scan_impl(
2909
2836
  }
2910
2837
  }
2911
2838
 
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
2839
  if (
2925
2840
  !at_command_boundary(lexer) &&
2926
2841
  !is_blank(lexer->lookahead) &&
@@ -2951,11 +2866,13 @@ static bool sed_scanner_scan_impl(
2951
2866
  }
2952
2867
  }
2953
2868
 
2954
- const TSSymbol missing_text_introducer = lexer->eof(lexer)
2955
- ? MISSING_TEXT_INTRODUCER_MARKER
2956
- : NONCONFORMING_MISSING_TEXT_INTRODUCER_MARKER;
2957
2869
  if (
2958
- emit_missing_marker(lexer, valid_symbols, missing_text_introducer, symbol)
2870
+ emit_missing_marker(
2871
+ lexer,
2872
+ valid_symbols,
2873
+ missing_text_introducer_symbol(lexer),
2874
+ symbol
2875
+ )
2959
2876
  ) {
2960
2877
  return true;
2961
2878
  }
@@ -3029,6 +2946,60 @@ static bool sed_scanner_scan_impl(
3029
2946
  return false;
3030
2947
  }
3031
2948
 
2949
+ static bool sed_scanner_scan_impl(
2950
+ ScannerState *state,
2951
+ TSLexer *lexer,
2952
+ const bool *valid_symbols,
2953
+ TSSymbol *symbol
2954
+ ) {
2955
+ if (valid_symbols[ERROR_SENTINEL]) {
2956
+ return false;
2957
+ }
2958
+
2959
+ if (state->mode == MODE_TEXT) {
2960
+ return scan_text_token(lexer, state, valid_symbols, symbol);
2961
+ }
2962
+
2963
+ if (
2964
+ is_regex_mode(state->mode) &&
2965
+ scan_regex_recovery_marker(lexer, state, valid_symbols, symbol)
2966
+ ) {
2967
+ return true;
2968
+ }
2969
+
2970
+ const bool delimiter_is_active = state->mode !=
2971
+ MODE_NONE &&
2972
+ lexer->lookahead ==
2973
+ state->delimiter &&
2974
+ (!is_regex_mode(state->mode) ||
2975
+ state->regex_state == REGEX_OUTSIDE_BRACKET);
2976
+ if (delimiter_is_active) {
2977
+ if (state->regex_group_depth > 0 && valid_symbols[REGEX_UNCLOSED_GROUP]) {
2978
+ state->regex_group_depth--;
2979
+ *symbol = REGEX_UNCLOSED_GROUP;
2980
+ return true;
2981
+ }
2982
+ return scan_active_mode_delimiter(lexer, state, valid_symbols, symbol);
2983
+ }
2984
+
2985
+ switch (state->mode) {
2986
+ case MODE_REGEX_ADDRESS:
2987
+ case MODE_SUBSTITUTE_PATTERN:
2988
+ return scan_regex_token(lexer, state, valid_symbols, symbol);
2989
+ case MODE_SUBSTITUTE_REPLACEMENT:
2990
+ return scan_replacement_token(lexer, state, valid_symbols, symbol);
2991
+ case MODE_TRANSLATE_SOURCE:
2992
+ case MODE_TRANSLATE_DESTINATION:
2993
+ return scan_translate_token(lexer, state, valid_symbols, symbol);
2994
+ case MODE_TEXT:
2995
+ return false;
2996
+ case MODE_NONE:
2997
+ break;
2998
+ }
2999
+
3000
+ return scan_command_token(lexer, state, valid_symbols, symbol);
3001
+ }
3002
+
3032
3003
  static void
3033
3004
  update_regex_position_after_symbol(ScannerState *state, TSSymbol symbol) {
3034
3005
  #if !SED_REGEX_EXTENDED
@@ -3037,9 +3008,7 @@ update_regex_position_after_symbol(ScannerState *state, TSSymbol symbol) {
3037
3008
  BRE_VERTICAL_LINE_ESCAPE_MARKER ||
3038
3009
  symbol ==
3039
3010
  BRE_QUESTION_MARK_ESCAPE_MARKER ||
3040
- symbol ==
3041
- BRE_PLUS_ESCAPE_MARKER ||
3042
- symbol == UNMATCHED_INTERVAL_CLOSE_MARKER
3011
+ symbol == BRE_PLUS_ESCAPE_MARKER
3043
3012
  ) {
3044
3013
  return;
3045
3014
  }
@@ -3081,7 +3050,15 @@ update_regex_position_after_symbol(ScannerState *state, TSSymbol symbol) {
3081
3050
  }
3082
3051
  #endif
3083
3052
 
3084
- if (symbol == REGEX_BEGINNING_ANCHOR || symbol == REGEX_END_ANCHOR) {
3053
+ bool is_anchor =
3054
+ symbol == REGEX_BEGINNING_ANCHOR || symbol == REGEX_END_ANCHOR;
3055
+ #if !SED_REGEX_EXTENDED
3056
+ is_anchor = is_anchor ||
3057
+ symbol ==
3058
+ REGEX_BRE_SUBEXPRESSION_CARET ||
3059
+ symbol == REGEX_BRE_SUBEXPRESSION_DOLLAR;
3060
+ #endif
3061
+ if (is_anchor) {
3085
3062
  set_regex_position(state, true, REGEX_DUPLICATION_NONE, false, true);
3086
3063
  return;
3087
3064
  }