tree-sitter-sed 0.7.0 → 0.9.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
@@ -21,10 +21,13 @@ enum TokenType {
21
21
  TRANSLATE_MIDDLE,
22
22
  TRANSLATE_END,
23
23
  REGEX_LITERAL,
24
+ INVALID_CHARACTER,
25
+ NUL_CHARACTER,
24
26
  REGEX_BEGINNING_ANCHOR,
25
27
  REGEX_END_ANCHOR,
26
28
  REGEX_PERIOD,
27
29
  REGEX_QUOTED_ESCAPE,
30
+ ESCAPE_PREFIX,
28
31
  REGEX_NEWLINE_ESCAPE,
29
32
  REGEX_ESCAPED_DELIMITER,
30
33
  REGEX_SPECIAL_ESCAPED_DELIMITER,
@@ -38,9 +41,6 @@ enum TokenType {
38
41
  REGEX_BRE_PLUS_ESCAPE,
39
42
  REGEX_BRE_SUBEXPRESSION_CARET,
40
43
  REGEX_BRE_SUBEXPRESSION_DOLLAR,
41
- BRE_VERTICAL_LINE_ESCAPE_MARKER,
42
- BRE_QUESTION_MARK_ESCAPE_MARKER,
43
- BRE_PLUS_ESCAPE_MARKER,
44
44
  REGEX_UNMATCHED_INTERVAL_CLOSE,
45
45
  #endif
46
46
  #if SED_REGEX_EXTENDED
@@ -73,6 +73,7 @@ enum TokenType {
73
73
  REGEX_BRACKET_TRAILING_HYPHEN,
74
74
  REGEX_OPEN_COLON,
75
75
  REGEX_CLASS_NAME,
76
+ REGEX_INVALID_CLASS_NAME,
76
77
  REGEX_COLON_CLOSE,
77
78
  REGEX_OPEN_DOT,
78
79
  REGEX_COLL_ELEM_SINGLE,
@@ -110,6 +111,7 @@ enum TokenType {
110
111
  INVALID_SUBSTITUTION_FLAG,
111
112
  FLAG_AFTER_WRITE_MARKER,
112
113
  TEXT_COMMAND_START,
114
+ TEXT_INCOMPLETE_INTRODUCER,
113
115
  TEXT_LITERAL,
114
116
  TEXT_BACKSLASH_ESCAPE,
115
117
  TEXT_ESCAPED_NEWLINE,
@@ -120,8 +122,11 @@ enum TokenType {
120
122
  COMMENT_TEXT,
121
123
  FILE_ARGUMENT,
122
124
  SUBSTITUTION_WFILE_ARGUMENT,
125
+ SUBSTITUTION_WFILE_CONTINUATION,
123
126
  LINE_WORD,
127
+ ARGUMENT_SEPARATOR,
124
128
  RIGHT_BRACE,
129
+ EMPTY_COMMAND_MARKER,
125
130
  RESERVED_UNKNOWN_FUNCTION_TOKEN,
126
131
  REGEX_INCOMPLETE_GROUP,
127
132
  REGEX_INCOMPLETE_BRACKET_TERM,
@@ -187,24 +192,18 @@ enum RegexState {
187
192
  REGEX_BRACKET_BODY,
188
193
  };
189
194
 
190
- enum TextState {
191
- TEXT_EMPTY,
192
- TEXT_HAS_CONTENT,
193
- TEXT_AFTER_ESCAPED_NEWLINE,
194
- };
195
-
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
- enum RegexDuplicationState {
205
- REGEX_DUPLICATION_NONE,
195
+ enum RegexPosition {
196
+ REGEX_AFTER_ATOM,
197
+ REGEX_AT_BRANCH_START,
198
+ #if SED_REGEX_EXTENDED
199
+ REGEX_AFTER_ALTERNATION,
200
+ #else
201
+ REGEX_AFTER_ANCHOR,
202
+ #endif
206
203
  REGEX_AFTER_DUPLICATION_SYMBOL,
204
+ #if SED_REGEX_EXTENDED
207
205
  REGEX_AFTER_REPETITION_MODIFIER,
206
+ #endif
208
207
  };
209
208
 
210
209
  enum RegexBracketTermState {
@@ -226,39 +225,31 @@ typedef struct {
226
225
  int32_t delimiter;
227
226
  enum ScannerMode mode;
228
227
  enum RegexState regex_state;
229
- bool regex_at_branch_start;
230
- enum RegexDuplicationState regex_duplication_state;
231
- bool regex_after_alternation;
232
- bool regex_after_anchor;
233
- enum TextState text_state;
234
- enum RegexIntervalState regex_interval_state;
228
+ enum RegexPosition regex_position;
229
+ bool text_line_has_content;
230
+ bool regex_in_interval;
235
231
  enum RegexBracketTermState regex_bracket_term_state;
232
+ bool regex_bracket_term_has_content;
236
233
  enum RegexBracketPendingElement regex_bracket_pending_element;
237
234
  enum RegexBracketPendingElement regex_bracket_first_element;
238
235
  enum RegexBracketPendingElement regex_bracket_last_element;
239
236
  uint8_t regex_bracket_element_count;
240
237
  bool regex_bracket_range_pending;
241
- uint16_t regex_group_depth;
238
+ uint32_t regex_group_depth;
242
239
  } ScannerState;
243
240
 
244
- enum {
245
- SCANNER_SERIALIZATION_VERSION = 14,
246
- SCANNER_SERIALIZED_STATE_SIZE = 17,
247
- };
241
+ enum { SCANNER_SERIALIZED_STATE_SIZE = 17 };
248
242
 
249
243
  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,
244
+ SERIALIZED_TEXT_HAS_CONTENT_FLAG = 1 << 0,
245
+ SERIALIZED_IN_INTERVAL_FLAG = 1 << 1,
246
+ SERIALIZED_BRACKET_TERM_HAS_CONTENT_FLAG = 1 << 2,
247
+ SERIALIZED_RANGE_PENDING_FLAG = 1 << 3,
258
248
  };
259
249
 
260
250
  static void reset_bracket_tracking(ScannerState *state) {
261
251
  state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
252
+ state->regex_bracket_term_has_content = false;
262
253
  state->regex_bracket_pending_element = REGEX_BRACKET_PENDING_NONE;
263
254
  state->regex_bracket_first_element = REGEX_BRACKET_PENDING_NONE;
264
255
  state->regex_bracket_last_element = REGEX_BRACKET_PENDING_NONE;
@@ -266,27 +257,21 @@ static void reset_bracket_tracking(ScannerState *state) {
266
257
  state->regex_bracket_range_pending = false;
267
258
  }
268
259
 
269
- static void set_regex_position(
270
- ScannerState *state,
271
- bool at_branch_start,
272
- enum RegexDuplicationState duplication_state,
273
- bool after_alternation,
274
- bool after_anchor
275
- ) {
276
- state->regex_at_branch_start = at_branch_start;
277
- state->regex_duplication_state = duplication_state;
278
- state->regex_after_alternation = after_alternation;
279
- state->regex_after_anchor = after_anchor;
260
+ static bool regex_at_branch_start(const ScannerState *state) {
261
+ return state->regex_position ==
262
+ REGEX_AT_BRANCH_START ||
263
+ #if SED_REGEX_EXTENDED
264
+ state->regex_position == REGEX_AFTER_ALTERNATION;
265
+ #else
266
+ state->regex_position == REGEX_AFTER_ANCHOR;
267
+ #endif
280
268
  }
281
269
 
282
270
  static void reset_mode_tracking(ScannerState *state) {
283
271
  state->regex_state = REGEX_OUTSIDE_BRACKET;
284
- state->regex_at_branch_start = false;
285
- state->regex_duplication_state = REGEX_DUPLICATION_NONE;
286
- state->regex_after_alternation = false;
287
- state->regex_after_anchor = false;
288
- state->text_state = TEXT_EMPTY;
289
- state->regex_interval_state = REGEX_INTERVAL_NONE;
272
+ state->regex_position = REGEX_AFTER_ATOM;
273
+ state->text_line_has_content = false;
274
+ state->regex_in_interval = false;
290
275
  reset_bracket_tracking(state);
291
276
  state->regex_group_depth = 0;
292
277
  }
@@ -305,14 +290,18 @@ static void sed_scanner_destroy(void *payload) {
305
290
  ts_free(payload);
306
291
  }
307
292
 
308
- static void serialize_uint16(char *buffer, unsigned offset, uint16_t value) {
309
- buffer[offset] = (char)(value & UINT16_C(0xff));
310
- buffer[offset + 1] = (char)((value >> 8) & UINT16_C(0xff));
293
+ static void serialize_uint32(char *buffer, unsigned offset, uint32_t value) {
294
+ buffer[offset] = (char)(value & UINT32_C(0xff));
295
+ buffer[offset + 1] = (char)((value >> 8) & UINT32_C(0xff));
296
+ buffer[offset + 2] = (char)((value >> 16) & UINT32_C(0xff));
297
+ buffer[offset + 3] = (char)((value >> 24) & UINT32_C(0xff));
311
298
  }
312
299
 
313
- static uint16_t deserialize_uint16(const char *buffer, unsigned offset) {
314
- return (uint16_t)((uint16_t)(unsigned char)buffer[offset] |
315
- ((uint16_t)(unsigned char)buffer[offset + 1] << 8));
300
+ static uint32_t deserialize_uint32(const char *buffer, unsigned offset) {
301
+ return (uint32_t)(unsigned char)buffer[offset] |
302
+ ((uint32_t)(unsigned char)buffer[offset + 1] << 8) |
303
+ ((uint32_t)(unsigned char)buffer[offset + 2] << 16) |
304
+ ((uint32_t)(unsigned char)buffer[offset + 3] << 24);
316
305
  }
317
306
 
318
307
  static bool is_regex_mode(enum ScannerMode mode) {
@@ -321,243 +310,84 @@ static bool is_regex_mode(enum ScannerMode mode) {
321
310
 
322
311
  static unsigned sed_scanner_serialize(void *payload, char *buffer) {
323
312
  const ScannerState *state = payload;
324
- const uint32_t delimiter = (uint32_t)state->delimiter;
325
313
 
326
- buffer[0] = SCANNER_SERIALIZATION_VERSION;
327
- buffer[1] = (char)state->mode;
328
- buffer[2] = (char)state->regex_state;
314
+ buffer[0] = (char)state->mode;
315
+ buffer[1] = (char)state->regex_state;
316
+ buffer[2] = (char)state->regex_position;
329
317
  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);
334
- buffer[4] = (char)(delimiter & UINT32_C(0xff));
335
- buffer[5] = (char)((delimiter >> 8) & UINT32_C(0xff));
336
- buffer[6] = (char)((delimiter >> 16) & UINT32_C(0xff));
337
- buffer[7] = (char)((delimiter >> 24) & UINT32_C(0xff));
338
- serialize_uint16(buffer, 8, state->regex_group_depth);
339
- buffer[10] = (char)state->regex_interval_state;
340
- buffer[11] = (char)state->regex_bracket_term_state;
341
- buffer[12] = (char)state->regex_bracket_pending_element;
342
- buffer[13] = (char)state->regex_bracket_first_element;
343
- buffer[14] = (char)state->regex_bracket_last_element;
344
- buffer[15] = (char)state->regex_bracket_element_count;
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);
318
+ (state->text_line_has_content ? SERIALIZED_TEXT_HAS_CONTENT_FLAG : 0) |
319
+ (state->regex_in_interval ? SERIALIZED_IN_INTERVAL_FLAG : 0) |
320
+ (state->regex_bracket_term_has_content
321
+ ? SERIALIZED_BRACKET_TERM_HAS_CONTENT_FLAG
322
+ : 0) |
323
+ (state->regex_bracket_range_pending ? SERIALIZED_RANGE_PENDING_FLAG : 0);
324
+ serialize_uint32(buffer, 4, (uint32_t)state->delimiter);
325
+ serialize_uint32(buffer, 8, state->regex_group_depth);
326
+ buffer[12] = (char)state->regex_bracket_term_state;
327
+ buffer[13] = (char)state->regex_bracket_pending_element;
328
+ buffer[14] = (char)state->regex_bracket_first_element;
329
+ buffer[15] = (char)state->regex_bracket_last_element;
330
+ buffer[16] = (char)state->regex_bracket_element_count;
349
331
  return SCANNER_SERIALIZED_STATE_SIZE;
350
332
  }
351
333
 
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 !=
334
+ static bool source_character_is_valid(int32_t character) {
335
+ const uint32_t code_point = (uint32_t)character;
336
+ return code_point !=
376
337
  0 &&
377
- delimiter <=
338
+ code_point <=
378
339
  UINT32_C(0x10ffff) &&
379
- !(delimiter >= UINT32_C(0xd800) && delimiter <= UINT32_C(0xdfff)) &&
380
- delimiter !=
381
- (uint32_t)'\\' &&
382
- delimiter != (uint32_t)'\n';
340
+ !(code_point >= UINT32_C(0xd800) && code_point <= UINT32_C(0xdfff));
383
341
  }
384
342
 
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;
343
+ static bool delimiter_character_is_valid(int32_t character) {
344
+ return source_character_is_valid(character) &&
345
+ character !=
346
+ '\\' &&
347
+ character != '\n';
440
348
  }
441
349
 
442
350
  static void
443
351
  sed_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
444
352
  ScannerState *state = payload;
445
- reset_state(state);
446
-
447
- if (
448
- length !=
449
- SCANNER_SERIALIZED_STATE_SIZE ||
450
- (unsigned char)buffer[0] != SCANNER_SERIALIZATION_VERSION
451
- ) {
353
+ if (length == 0) {
354
+ reset_state(state);
452
355
  return;
453
356
  }
454
357
 
455
- const unsigned char mode_flags = (unsigned char)buffer[3];
456
- const unsigned char regex_bracket_flags = (unsigned char)buffer[16];
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],
358
+ const unsigned char flags = (unsigned char)buffer[3];
359
+ *state = (ScannerState){
360
+ .mode = (enum ScannerMode)(unsigned char)buffer[0],
361
+ .regex_state = (enum RegexState)(unsigned char)buffer[1],
362
+ .regex_position = (enum RegexPosition)(unsigned char)buffer[2],
363
+ .text_line_has_content = (flags & SERIALIZED_TEXT_HAS_CONTENT_FLAG) != 0,
364
+ .regex_in_interval = (flags & SERIALIZED_IN_INTERVAL_FLAG) != 0,
365
+ .regex_bracket_term_has_content =
366
+ (flags & SERIALIZED_BRACKET_TERM_HAS_CONTENT_FLAG) != 0,
367
+ .regex_bracket_range_pending = (flags & SERIALIZED_RANGE_PENDING_FLAG) != 0,
368
+ .delimiter = (int32_t)deserialize_uint32(buffer, 4),
369
+ .regex_group_depth = deserialize_uint32(buffer, 8),
475
370
  .regex_bracket_term_state =
476
- (enum RegexBracketTermState)(unsigned char)buffer[11],
371
+ (enum RegexBracketTermState)(unsigned char)buffer[12],
477
372
  .regex_bracket_pending_element =
478
- (enum RegexBracketPendingElement)(unsigned char)buffer[12],
479
- .regex_bracket_first_element =
480
373
  (enum RegexBracketPendingElement)(unsigned char)buffer[13],
481
- .regex_bracket_last_element =
374
+ .regex_bracket_first_element =
482
375
  (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),
376
+ .regex_bracket_last_element =
377
+ (enum RegexBracketPendingElement)(unsigned char)buffer[15],
378
+ .regex_bracket_element_count = (uint8_t)(unsigned char)buffer[16],
487
379
  };
488
-
489
- if (candidate.mode > MODE_TEXT) {
490
- return;
491
- }
492
-
493
- if (candidate.regex_state > REGEX_BRACKET_BODY) {
494
- return;
495
- }
496
-
497
- if ((mode_flags & (unsigned char)~SERIALIZED_MODE_FLAGS_MAXIMUM) != 0) {
498
- return;
499
- }
500
- if (candidate.text_state > TEXT_AFTER_ESCAPED_NEWLINE) {
501
- return;
502
- }
503
- #if !SED_REGEX_EXTENDED
504
- if (candidate.regex_after_alternation) {
505
- return;
506
- }
507
- #endif
508
-
509
- if (candidate.regex_interval_state > REGEX_INTERVAL_AFTER_MAXIMUM) {
510
- return;
511
- }
512
- if (candidate.regex_bracket_term_state > REGEX_BRACKET_TERM_EQUAL) {
513
- return;
514
- }
515
- if (
516
- candidate.regex_bracket_pending_element >
517
- REGEX_BRACKET_PENDING_COLON ||
518
- candidate.regex_bracket_first_element >
519
- REGEX_BRACKET_PENDING_COLON ||
520
- candidate.regex_bracket_last_element >
521
- REGEX_BRACKET_PENDING_COLON ||
522
- candidate.regex_bracket_element_count >
523
- 3U ||
524
- (regex_bracket_flags & (unsigned char)~SERIALIZED_BRACKET_FLAGS_MAXIMUM) !=
525
- 0 ||
526
- #if SED_REGEX_EXTENDED
527
- candidate.regex_duplication_state > REGEX_AFTER_REPETITION_MODIFIER
528
- #else
529
- candidate.regex_duplication_state > REGEX_AFTER_DUPLICATION_SYMBOL
530
- #endif
531
- ) {
532
- return;
533
- }
534
- if (
535
- (candidate.regex_bracket_element_count ==
536
- 0 &&
537
- (candidate.regex_bracket_first_element !=
538
- REGEX_BRACKET_PENDING_NONE ||
539
- candidate.regex_bracket_last_element != REGEX_BRACKET_PENDING_NONE)) ||
540
- (candidate.regex_bracket_element_count >
541
- 0 &&
542
- (candidate.regex_bracket_first_element ==
543
- REGEX_BRACKET_PENDING_NONE ||
544
- candidate.regex_bracket_last_element == REGEX_BRACKET_PENDING_NONE)) ||
545
- (candidate.regex_bracket_pending_element !=
546
- REGEX_BRACKET_PENDING_NONE &&
547
- candidate.regex_bracket_range_pending)
548
- ) {
549
- return;
550
- }
551
-
552
- if (deserialized_state_is_valid(&candidate)) {
553
- *state = candidate;
554
- }
555
380
  }
556
381
 
557
382
  static void advance(TSLexer *lexer) {
558
383
  lexer->advance(lexer, false);
559
384
  }
560
385
 
386
+ static void consume(TSLexer *lexer) {
387
+ advance(lexer);
388
+ lexer->mark_end(lexer);
389
+ }
390
+
561
391
  static bool is_blank(int32_t character) {
562
392
  return character == ' ' || character == '\t';
563
393
  }
@@ -566,14 +396,13 @@ static bool is_digit(int32_t character) {
566
396
  return character >= '0' && character <= '9';
567
397
  }
568
398
 
569
- static void advance_past_blanks(TSLexer *lexer) {
570
- while (is_blank(lexer->lookahead)) {
571
- advance(lexer);
572
- }
399
+ static bool is_letter(int32_t character) {
400
+ return (character >= 'a' && character <= 'z') ||
401
+ (character >= 'A' && character <= 'Z');
573
402
  }
574
403
 
575
- static void advance_past_escaped_character(TSLexer *lexer) {
576
- if (!lexer->eof(lexer) && lexer->lookahead != '\n') {
404
+ static void advance_past_blanks(TSLexer *lexer) {
405
+ while (is_blank(lexer->lookahead)) {
577
406
  advance(lexer);
578
407
  }
579
408
  }
@@ -585,12 +414,7 @@ static void skip_blanks(TSLexer *lexer) {
585
414
  }
586
415
 
587
416
  static bool invalid_delimiter(TSLexer *lexer) {
588
- return lexer->eof(lexer) ||
589
- lexer->lookahead ==
590
- 0 ||
591
- lexer->lookahead ==
592
- '\\' ||
593
- lexer->lookahead == '\n';
417
+ return lexer->eof(lexer) || !delimiter_character_is_valid(lexer->lookahead);
594
418
  }
595
419
 
596
420
  static bool delimiter_is_missing(TSLexer *lexer) {
@@ -609,32 +433,42 @@ static bool scan_simple_delimiter(
609
433
  state->delimiter = lexer->lookahead;
610
434
  state->mode = next_mode;
611
435
  reset_mode_tracking(state);
612
- state->regex_at_branch_start =
613
- next_mode == MODE_REGEX_ADDRESS || next_mode == MODE_SUBSTITUTE_PATTERN;
614
- advance(lexer);
615
- lexer->mark_end(lexer);
436
+ state->regex_position =
437
+ is_regex_mode(next_mode) ? REGEX_AT_BRANCH_START : REGEX_AFTER_ATOM;
438
+ consume(lexer);
616
439
  return true;
617
440
  }
618
441
 
619
- static bool scan_mode_delimiter(
620
- TSLexer *lexer,
621
- ScannerState *state,
622
- enum ScannerMode next_mode
623
- ) {
624
- if (lexer->lookahead != state->delimiter) {
442
+ static bool
443
+ emit_symbol(const bool *valid_symbols, TSSymbol candidate, TSSymbol *symbol) {
444
+ if (!valid_symbols[candidate]) {
625
445
  return false;
626
446
  }
627
447
 
628
- state->mode = next_mode;
629
- reset_mode_tracking(state);
630
- if (next_mode == MODE_NONE) {
631
- state->delimiter = 0;
632
- }
633
- advance(lexer);
634
- lexer->mark_end(lexer);
448
+ *symbol = candidate;
635
449
  return true;
636
450
  }
637
451
 
452
+ static bool consume_as(
453
+ TSLexer *lexer,
454
+ const bool *valid_symbols,
455
+ TSSymbol candidate,
456
+ TSSymbol *symbol
457
+ ) {
458
+ consume(lexer);
459
+ return emit_symbol(valid_symbols, candidate, symbol);
460
+ }
461
+
462
+ static bool end_mode(
463
+ ScannerState *state,
464
+ const bool *valid_symbols,
465
+ TSSymbol candidate,
466
+ TSSymbol *symbol
467
+ ) {
468
+ reset_state(state);
469
+ return emit_symbol(valid_symbols, candidate, symbol);
470
+ }
471
+
638
472
  static bool scan_active_mode_delimiter(
639
473
  TSLexer *lexer,
640
474
  ScannerState *state,
@@ -670,26 +504,15 @@ static bool scan_active_mode_delimiter(
670
504
  return false;
671
505
  }
672
506
 
673
- if (
674
- !valid_symbols[candidate] || !scan_mode_delimiter(lexer, state, next_mode)
675
- ) {
676
- return false;
507
+ state->mode = next_mode;
508
+ reset_mode_tracking(state);
509
+ if (next_mode == MODE_NONE) {
510
+ state->delimiter = 0;
677
511
  }
678
-
679
- *symbol = candidate;
680
- return true;
681
- }
682
-
683
- static void consume(TSLexer *lexer) {
684
- advance(lexer);
685
- lexer->mark_end(lexer);
512
+ return consume_as(lexer, valid_symbols, candidate, symbol);
686
513
  }
687
514
 
688
515
  static bool scan_text_command_start(TSLexer *lexer, ScannerState *state) {
689
- if (state->mode != MODE_NONE || lexer->lookahead != '\\') {
690
- return false;
691
- }
692
-
693
516
  lexer->mark_end(lexer);
694
517
  advance(lexer);
695
518
 
@@ -702,47 +525,25 @@ static bool scan_text_command_start(TSLexer *lexer, ScannerState *state) {
702
525
  return true;
703
526
  }
704
527
 
705
- static bool scan_to_physical_line_end(TSLexer *lexer, bool consumed) {
706
- while (!lexer->eof(lexer)) {
707
- if (lexer->lookahead == '\n') {
708
- return consumed;
709
- }
710
-
528
+ static bool scan_line_rest(TSLexer *lexer, bool ends_at_semicolon) {
529
+ bool consumed = false;
530
+ while (
531
+ !lexer->eof(lexer) &&
532
+ lexer->lookahead !=
533
+ 0 &&
534
+ lexer->lookahead !=
535
+ '\n' &&
536
+ !(ends_at_semicolon && lexer->lookahead == ';')
537
+ ) {
711
538
  consume(lexer);
712
539
  consumed = true;
713
540
  }
714
-
715
541
  return consumed;
716
542
  }
717
543
 
718
- static bool scan_file_argument(TSLexer *lexer) {
719
- if (
720
- lexer->eof(lexer) || is_blank(lexer->lookahead) || lexer->lookahead == '\n'
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;
544
+ static bool scan_file_argument(TSLexer *lexer, bool ends_at_semicolon) {
545
+ return !is_blank(lexer->lookahead) &&
546
+ scan_line_rest(lexer, ends_at_semicolon);
746
547
  }
747
548
 
748
549
  enum FlagAfterWriteScan {
@@ -781,55 +582,14 @@ static enum FlagAfterWriteScan scan_flag_after_write_marker(TSLexer *lexer) {
781
582
  : FLAG_AFTER_WRITE_FALLBACK;
782
583
  }
783
584
 
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
585
  enum LiteralScanResult {
817
586
  LITERAL_SCAN_NONE,
818
587
  LITERAL_SCAN_TOKEN,
588
+ LITERAL_SCAN_INVALID_CHARACTER,
819
589
  LITERAL_SCAN_LINE_END,
820
590
  };
821
591
 
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(
592
+ static bool emit_marker(
833
593
  TSLexer *lexer,
834
594
  const bool *valid_symbols,
835
595
  TSSymbol candidate,
@@ -840,10 +600,23 @@ static bool emit_missing_marker(
840
600
  }
841
601
 
842
602
  lexer->mark_end(lexer);
603
+ // Keep the marker empty while recording its full lookahead character.
604
+ if (!lexer->eof(lexer)) {
605
+ advance(lexer);
606
+ }
843
607
  *symbol = candidate;
844
608
  return true;
845
609
  }
846
610
 
611
+ static bool can_start_address(TSLexer *lexer) {
612
+ return is_digit(lexer->lookahead) ||
613
+ lexer->lookahead ==
614
+ '$' ||
615
+ lexer->lookahead ==
616
+ '/' ||
617
+ lexer->lookahead == '\\';
618
+ }
619
+
847
620
  static bool at_command_boundary(TSLexer *lexer) {
848
621
  return lexer->eof(lexer) ||
849
622
  lexer->lookahead ==
@@ -853,13 +626,23 @@ static bool at_command_boundary(TSLexer *lexer) {
853
626
  lexer->lookahead == '}';
854
627
  }
855
628
 
856
- static bool can_start_address(TSLexer *lexer) {
857
- return is_digit(lexer->lookahead) ||
858
- lexer->lookahead ==
859
- '$' ||
860
- lexer->lookahead ==
861
- '/' ||
862
- lexer->lookahead == '\\';
629
+ static TSSymbol missing_command_separator_marker(
630
+ const TSLexer *lexer,
631
+ const bool *valid_symbols
632
+ ) {
633
+ if (lexer->lookahead == '}') {
634
+ if (valid_symbols[MISSING_SEPARATOR_BEFORE_UNMATCHED_BRACE_MARKER]) {
635
+ return MISSING_SEPARATOR_BEFORE_UNMATCHED_BRACE_MARKER;
636
+ }
637
+ if (valid_symbols[MISSING_COMMAND_SEPARATOR_MARKER]) {
638
+ return MISSING_COMMAND_SEPARATOR_MARKER;
639
+ }
640
+ } else if (
641
+ lexer->eof(lexer) && valid_symbols[INCOMPLETE_COMMAND_SEPARATOR_MARKER]
642
+ ) {
643
+ return INCOMPLETE_COMMAND_SEPARATOR_MARKER;
644
+ }
645
+ return ERROR_SENTINEL;
863
646
  }
864
647
 
865
648
  enum PostBlankRecoveryScan {
@@ -913,22 +696,10 @@ static enum PostBlankRecoveryScan scan_post_blank_recovery(
913
696
  *symbol = MISSING_ADDRESS_SEPARATOR_MARKER;
914
697
  return POST_BLANK_RECOVERY_TOKEN;
915
698
  }
916
- if (lexer->lookahead == '}') {
917
- if (valid_symbols[MISSING_SEPARATOR_BEFORE_UNMATCHED_BRACE_MARKER]) {
918
- *symbol = MISSING_SEPARATOR_BEFORE_UNMATCHED_BRACE_MARKER;
919
- return POST_BLANK_RECOVERY_TOKEN;
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;
699
+ // The blanks precede the marker as padding of the brace or the source end.
700
+ *symbol = missing_command_separator_marker(lexer, valid_symbols);
701
+ return *symbol == ERROR_SENTINEL ? POST_BLANK_RECOVERY_FAILED
702
+ : POST_BLANK_RECOVERY_TOKEN;
932
703
  }
933
704
 
934
705
  static bool scan_text_token(
@@ -938,80 +709,66 @@ static bool scan_text_token(
938
709
  TSSymbol *symbol
939
710
  ) {
940
711
  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
712
  if (
954
- state->text_state ==
955
- TEXT_EMPTY &&
956
- emit_missing_marker(lexer, valid_symbols, MISSING_TEXT_MARKER, symbol)
713
+ !state->text_line_has_content &&
714
+ emit_marker(lexer, valid_symbols, MISSING_TEXT_MARKER, symbol)
957
715
  ) {
958
- state->text_state = TEXT_HAS_CONTENT;
716
+ state->text_line_has_content = true;
959
717
  return true;
960
718
  }
961
- if (!valid_symbols[TEXT_EOF]) {
962
- return false;
963
- }
964
719
  lexer->mark_end(lexer);
965
- reset_state(state);
966
- *symbol = TEXT_EOF;
967
- return true;
720
+ return end_mode(state, valid_symbols, TEXT_EOF, symbol);
968
721
  }
969
722
 
970
723
  if (lexer->lookahead == '\n') {
971
- if (!valid_symbols[TEXT_LINE_END]) {
972
- return false;
973
- }
974
724
  lexer->mark_end(lexer);
975
- reset_state(state);
976
- *symbol = TEXT_LINE_END;
977
- return true;
725
+ return end_mode(state, valid_symbols, TEXT_LINE_END, symbol);
726
+ }
727
+
728
+ if (lexer->lookahead == 0) {
729
+ state->text_line_has_content = true;
730
+ return consume_as(lexer, valid_symbols, NUL_CHARACTER, symbol);
978
731
  }
979
732
 
980
733
  if (lexer->lookahead == '\\') {
981
- advance(lexer);
982
- lexer->mark_end(lexer);
734
+ consume(lexer);
983
735
 
984
736
  if (lexer->eof(lexer)) {
985
- state->text_state = TEXT_HAS_CONTENT;
737
+ state->text_line_has_content = true;
986
738
  return emit_symbol(valid_symbols, TEXT_UNSPECIFIED_ESCAPE, symbol);
987
739
  }
740
+ if (lexer->lookahead == 0) {
741
+ state->text_line_has_content = true;
742
+ return emit_symbol(valid_symbols, ESCAPE_PREFIX, symbol);
743
+ }
988
744
  if (lexer->lookahead == '\\') {
989
745
  consume(lexer);
990
- state->text_state = TEXT_HAS_CONTENT;
746
+ state->text_line_has_content = true;
991
747
  return emit_symbol(valid_symbols, TEXT_BACKSLASH_ESCAPE, symbol);
992
748
  }
993
749
  if (lexer->lookahead == '\n') {
994
750
  consume(lexer);
995
- state->text_state = TEXT_AFTER_ESCAPED_NEWLINE;
751
+ state->text_line_has_content = false;
996
752
  return emit_symbol(valid_symbols, TEXT_ESCAPED_NEWLINE, symbol);
997
753
  }
998
754
 
999
755
  consume(lexer);
1000
- state->text_state = TEXT_HAS_CONTENT;
756
+ state->text_line_has_content = true;
1001
757
  return emit_symbol(valid_symbols, TEXT_UNSPECIFIED_ESCAPE, symbol);
1002
758
  }
1003
759
 
1004
- if (!valid_symbols[TEXT_LITERAL]) {
1005
- return false;
1006
- }
1007
760
  do {
1008
761
  consume(lexer);
1009
762
  } while (
1010
- !lexer->eof(lexer) && lexer->lookahead != '\\' && lexer->lookahead != '\n'
763
+ !lexer->eof(lexer) &&
764
+ lexer->lookahead !=
765
+ 0 &&
766
+ lexer->lookahead !=
767
+ '\\' &&
768
+ lexer->lookahead != '\n'
1011
769
  );
1012
- state->text_state = TEXT_HAS_CONTENT;
1013
- *symbol = TEXT_LITERAL;
1014
- return true;
770
+ state->text_line_has_content = true;
771
+ return emit_symbol(valid_symbols, TEXT_LITERAL, symbol);
1015
772
  }
1016
773
 
1017
774
  static bool regex_is_inside_bracket(const ScannerState *state) {
@@ -1068,12 +825,14 @@ begin_single_bracket_element(ScannerState *state, int32_t character) {
1068
825
  }
1069
826
 
1070
827
  static void begin_compound_bracket_element(ScannerState *state) {
828
+ state->regex_bracket_term_has_content = false;
1071
829
  if (!state->regex_bracket_range_pending) {
1072
830
  commit_pending_bracket_element(state);
1073
831
  }
1074
832
  }
1075
833
 
1076
834
  static void finish_compound_bracket_element(ScannerState *state) {
835
+ state->regex_bracket_term_has_content = false;
1077
836
  if (state->regex_bracket_range_pending) {
1078
837
  record_bracket_element(state, REGEX_BRACKET_PENDING_OTHER);
1079
838
  state->regex_bracket_range_pending = false;
@@ -1101,16 +860,6 @@ static void finish_first_bracket_element(ScannerState *state) {
1101
860
  }
1102
861
  }
1103
862
 
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
863
  static bool
1115
864
  regex_literal_boundary(const ScannerState *state, int32_t character) {
1116
865
  if (state->regex_state == REGEX_OUTSIDE_BRACKET) {
@@ -1162,33 +911,58 @@ scan_regex_literal(TSLexer *lexer, ScannerState *state) {
1162
911
  consume(lexer);
1163
912
  if (regex_is_inside_bracket(state)) {
1164
913
  begin_single_bracket_element(state, character);
914
+ finish_first_bracket_element(state);
1165
915
  }
1166
- update_bracket_state_after_literal(state, character);
1167
- return LITERAL_SCAN_TOKEN;
916
+ return source_character_is_valid(character) ? LITERAL_SCAN_TOKEN
917
+ : LITERAL_SCAN_INVALID_CHARACTER;
1168
918
  }
1169
919
 
1170
920
  static TSSymbol
1171
- regex_unterminated_symbol(enum ScannerMode mode, bool at_end_of_source) {
1172
- if (mode == MODE_REGEX_ADDRESS) {
921
+ unterminated_mode_symbol(enum ScannerMode mode, bool at_end_of_source) {
922
+ switch (mode) {
923
+ case MODE_REGEX_ADDRESS:
1173
924
  return at_end_of_source ? REGEX_UNTERMINATED_ADDRESS
1174
925
  : REGEX_LINE_UNTERMINATED_ADDRESS;
926
+ case MODE_SUBSTITUTE_PATTERN:
927
+ return at_end_of_source ? REGEX_UNTERMINATED_SUBSTITUTE
928
+ : REGEX_LINE_UNTERMINATED_SUBSTITUTE;
929
+ case MODE_SUBSTITUTE_REPLACEMENT:
930
+ return at_end_of_source ? REPLACEMENT_UNTERMINATED
931
+ : REPLACEMENT_LINE_UNTERMINATED;
932
+ case MODE_TRANSLATE_SOURCE:
933
+ return at_end_of_source ? TRANSLATE_UNTERMINATED_SOURCE
934
+ : TRANSLATE_LINE_UNTERMINATED_SOURCE;
935
+ case MODE_TRANSLATE_DESTINATION:
936
+ return at_end_of_source ? TRANSLATE_UNTERMINATED_DESTINATION
937
+ : TRANSLATE_LINE_UNTERMINATED_DESTINATION;
938
+ case MODE_NONE:
939
+ case MODE_TEXT:
940
+ break;
1175
941
  }
1176
- return at_end_of_source ? REGEX_UNTERMINATED_SUBSTITUTE
1177
- : REGEX_LINE_UNTERMINATED_SUBSTITUTE;
942
+ return ERROR_SENTINEL;
1178
943
  }
1179
944
 
1180
- static bool emit_unterminated(
1181
- ScannerState *state,
1182
- const bool *valid_symbols,
1183
- TSSymbol candidate,
1184
- TSSymbol *symbol
1185
- ) {
1186
- if (!emit_symbol(valid_symbols, candidate, symbol)) {
1187
- return false;
1188
- }
945
+ static const struct {
946
+ int32_t marker;
947
+ TSSymbol open_symbol;
948
+ TSSymbol close_symbol;
949
+ } bracket_terms[] = {
950
+ [REGEX_BRACKET_TERM_COLON] = {':', REGEX_OPEN_COLON, REGEX_COLON_CLOSE},
951
+ [REGEX_BRACKET_TERM_DOT] = {'.', REGEX_OPEN_DOT, REGEX_DOT_CLOSE},
952
+ [REGEX_BRACKET_TERM_EQUAL] = {'=', REGEX_OPEN_EQUAL, REGEX_EQUAL_CLOSE},
953
+ };
1189
954
 
1190
- reset_state(state);
1191
- return true;
955
+ static enum RegexBracketTermState bracket_term_for_marker(int32_t character) {
956
+ for (
957
+ enum RegexBracketTermState term_state = REGEX_BRACKET_TERM_COLON;
958
+ term_state <= REGEX_BRACKET_TERM_EQUAL;
959
+ term_state++
960
+ ) {
961
+ if (bracket_terms[term_state].marker == character) {
962
+ return term_state;
963
+ }
964
+ }
965
+ return REGEX_BRACKET_TERM_NONE;
1192
966
  }
1193
967
 
1194
968
  static bool scan_regex_bracket_opener(
@@ -1210,35 +984,22 @@ static bool scan_regex_bracket_opener(
1210
984
 
1211
985
  lexer->mark_end(lexer);
1212
986
 
1213
- TSSymbol candidate;
1214
- enum RegexBracketTermState term_state;
1215
- switch (lexer->lookahead) {
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:
987
+ const enum RegexBracketTermState term_state =
988
+ bracket_term_for_marker(lexer->lookahead);
989
+ if (term_state == REGEX_BRACKET_TERM_NONE) {
1229
990
  begin_single_bracket_element(state, '[');
1230
991
  finish_first_bracket_element(state);
1231
992
  return emit_symbol(valid_symbols, REGEX_BRACKET_LITERAL, symbol);
1232
993
  }
1233
994
 
1234
- if (!valid_symbols[candidate]) {
1235
- return false;
1236
- }
1237
995
  begin_compound_bracket_element(state);
1238
996
  finish_first_bracket_element(state);
1239
997
  state->regex_bracket_term_state = term_state;
1240
- *symbol = candidate;
1241
- return true;
998
+ return emit_symbol(
999
+ valid_symbols,
1000
+ bracket_terms[term_state].open_symbol,
1001
+ symbol
1002
+ );
1242
1003
  }
1243
1004
 
1244
1005
  static void record_bracket_term_character(
@@ -1255,19 +1016,7 @@ static void record_bracket_term_character(
1255
1016
  }
1256
1017
 
1257
1018
  static bool bracket_meta_character(int32_t character) {
1258
- return character == '^' || character == '-' || 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
- }
1019
+ return character == '-' || character == ']';
1271
1020
  }
1272
1021
 
1273
1022
  static TSSymbol regex_bracket_term_content_symbol(
@@ -1281,61 +1030,46 @@ static TSSymbol regex_bracket_term_content_symbol(
1281
1030
  if (character_count > 1U) {
1282
1031
  return REGEX_COLL_ELEM_MULTI;
1283
1032
  }
1284
- if (
1285
- state->regex_bracket_term_state ==
1286
- REGEX_BRACKET_TERM_DOT &&
1287
- bracket_meta_character(single_character)
1288
- ) {
1289
- return REGEX_META_CHAR;
1033
+ if (!bracket_meta_character(single_character)) {
1034
+ return REGEX_COLL_ELEM_SINGLE;
1290
1035
  }
1291
- return REGEX_COLL_ELEM_SINGLE;
1036
+ return state->regex_bracket_term_state == REGEX_BRACKET_TERM_DOT
1037
+ ? REGEX_META_CHAR
1038
+ : REGEX_MALFORMED_BRACKET_TERM;
1292
1039
  }
1293
1040
 
1294
1041
  static bool scan_regex_bracket_term_content(
1295
1042
  TSLexer *lexer,
1296
1043
  ScannerState *state,
1297
- int32_t close_marker,
1298
1044
  const bool *valid_symbols,
1299
1045
  TSSymbol *symbol
1300
1046
  ) {
1047
+ const int32_t close_marker =
1048
+ bracket_terms[state->regex_bracket_term_state].marker;
1301
1049
  uint8_t character_count = 0;
1302
1050
  int32_t single_character = 0;
1303
1051
  bool stopped_at_close = false;
1052
+ bool valid_class_name = true;
1053
+ bool leading_bracket_is_content = !state->regex_bracket_term_has_content &&
1054
+ state->regex_bracket_term_state != REGEX_BRACKET_TERM_COLON;
1304
1055
  lexer->mark_end(lexer);
1305
1056
 
1306
- if (
1307
- lexer->lookahead ==
1308
- ']' &&
1309
- state->regex_bracket_term_state != REGEX_BRACKET_TERM_COLON
1310
- ) {
1311
- advance(lexer);
1312
- lexer->mark_end(lexer);
1313
- record_bracket_term_character(&character_count, &single_character, ']');
1314
- if (lexer->lookahead == close_marker) {
1315
- advance(lexer);
1316
- if (lexer->lookahead == ']') {
1317
- const TSSymbol candidate = regex_bracket_term_content_symbol(
1318
- state,
1319
- character_count,
1320
- single_character
1321
- );
1322
- return emit_symbol(valid_symbols, candidate, symbol);
1323
- }
1324
- lexer->mark_end(lexer);
1325
- record_bracket_term_character(
1326
- &character_count,
1327
- &single_character,
1328
- close_marker
1329
- );
1330
- }
1057
+ if (!lexer->eof(lexer) && !source_character_is_valid(lexer->lookahead)) {
1058
+ state->regex_bracket_term_has_content = true;
1059
+ return consume_as(lexer, valid_symbols, INVALID_CHARACTER, symbol);
1331
1060
  }
1332
1061
 
1333
1062
  for (;;) {
1334
1063
  if (
1335
- lexer->eof(lexer) || lexer->lookahead == '\n' || lexer->lookahead == ']'
1064
+ lexer->eof(lexer) ||
1065
+ lexer->lookahead ==
1066
+ '\n' ||
1067
+ !source_character_is_valid(lexer->lookahead) ||
1068
+ (lexer->lookahead == ']' && !leading_bracket_is_content)
1336
1069
  ) {
1337
1070
  break;
1338
1071
  }
1072
+ leading_bracket_is_content = false;
1339
1073
 
1340
1074
  if (lexer->lookahead == close_marker) {
1341
1075
  advance(lexer);
@@ -1344,6 +1078,7 @@ static bool scan_regex_bracket_term_content(
1344
1078
  break;
1345
1079
  }
1346
1080
  lexer->mark_end(lexer);
1081
+ valid_class_name = false;
1347
1082
  record_bracket_term_character(
1348
1083
  &character_count,
1349
1084
  &single_character,
@@ -1353,6 +1088,10 @@ static bool scan_regex_bracket_term_content(
1353
1088
  }
1354
1089
 
1355
1090
  const int32_t character = lexer->lookahead;
1091
+ valid_class_name = valid_class_name &&
1092
+ (is_letter(character) ||
1093
+ (is_digit(character) &&
1094
+ (state->regex_bracket_term_has_content || character_count > 0)));
1356
1095
  consume(lexer);
1357
1096
  record_bracket_term_character(
1358
1097
  &character_count,
@@ -1362,169 +1101,155 @@ static bool scan_regex_bracket_term_content(
1362
1101
  }
1363
1102
 
1364
1103
  if (character_count == 0) {
1104
+ const TSSymbol closing =
1105
+ bracket_terms[state->regex_bracket_term_state].close_symbol;
1106
+ if (stopped_at_close && valid_symbols[closing]) {
1107
+ lexer->mark_end(lexer);
1108
+ state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
1109
+ finish_compound_bracket_element(state);
1110
+ return emit_symbol(valid_symbols, closing, symbol);
1111
+ }
1365
1112
  if (!stopped_at_close) {
1366
1113
  state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
1367
1114
  finish_compound_bracket_element(state);
1368
1115
  }
1369
1116
  return emit_symbol(valid_symbols, REGEX_MALFORMED_BRACKET_TERM, symbol);
1370
1117
  }
1371
- const TSSymbol candidate =
1372
- regex_bracket_term_content_symbol(state, character_count, single_character);
1118
+ state->regex_bracket_term_has_content = true;
1119
+ const TSSymbol candidate = state->regex_bracket_term_state ==
1120
+ REGEX_BRACKET_TERM_COLON &&
1121
+ !valid_class_name
1122
+ ? REGEX_INVALID_CLASS_NAME
1123
+ : regex_bracket_term_content_symbol(
1124
+ state,
1125
+ character_count,
1126
+ single_character
1127
+ );
1373
1128
  return emit_symbol(valid_symbols, candidate, symbol);
1374
1129
  }
1375
1130
 
1376
1131
  static bool scan_regex_bracket_term_close(
1377
1132
  TSLexer *lexer,
1378
1133
  ScannerState *state,
1379
- int32_t marker,
1380
- TSSymbol candidate,
1381
1134
  const bool *valid_symbols,
1382
1135
  TSSymbol *symbol
1383
1136
  ) {
1384
- if (lexer->lookahead != marker) {
1385
- return false;
1386
- }
1387
-
1388
1137
  consume(lexer);
1389
1138
  if (lexer->lookahead != ']') {
1390
1139
  return false;
1391
1140
  }
1141
+ const TSSymbol candidate =
1142
+ bracket_terms[state->regex_bracket_term_state].close_symbol;
1392
1143
  state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
1393
1144
  finish_compound_bracket_element(state);
1394
1145
  return emit_symbol(valid_symbols, candidate, symbol);
1395
1146
  }
1396
1147
 
1397
- enum RegexIntervalPartResult {
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(
1148
+ static bool scan_regex_interval_open(
1404
1149
  TSLexer *lexer,
1405
- const ScannerState *state,
1406
- bool escaped_close,
1407
- bool *has_digits
1150
+ ScannerState *state,
1151
+ const bool *valid_symbols,
1152
+ TSSymbol *symbol
1408
1153
  ) {
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
- }
1154
+ consume(lexer);
1155
+ state->regex_in_interval = true;
1156
+ return emit_symbol(valid_symbols, REGEX_INTERVAL_OPEN, symbol);
1157
+ }
1417
1158
 
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
- }
1159
+ static bool end_interval(
1160
+ ScannerState *state,
1161
+ const bool *valid_symbols,
1162
+ TSSymbol candidate,
1163
+ TSSymbol *symbol
1164
+ ) {
1165
+ state->regex_in_interval = false;
1166
+ return emit_symbol(valid_symbols, candidate, symbol);
1167
+ }
1426
1168
 
1427
- return REGEX_INTERVAL_PART_END;
1428
- }
1169
+ static bool scan_regex_interval_close(
1170
+ TSLexer *lexer,
1171
+ ScannerState *state,
1172
+ const bool *valid_symbols,
1173
+ TSSymbol *symbol
1174
+ ) {
1175
+ consume(lexer);
1176
+ return end_interval(state, valid_symbols, REGEX_INTERVAL_CLOSE, symbol);
1429
1177
  }
1430
1178
 
1179
+ #if !SED_REGEX_EXTENDED
1431
1180
  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;
1181
+ interval_escape_ends_content(const ScannerState *state, int32_t escaped) {
1182
+ return (escaped == '}' || escaped == '(' || escaped == ')') &&
1183
+ escaped != state->delimiter;
1439
1184
  }
1185
+ #endif
1440
1186
 
1441
- static bool scan_regex_interval_tail(
1442
- TSLexer *lexer,
1443
- const ScannerState *state,
1444
- bool escaped_close
1445
- ) {
1446
- bool has_minimum = false;
1447
- enum RegexIntervalPartResult result =
1448
- scan_regex_interval_digits(lexer, state, escaped_close, &has_minimum);
1449
- if (result == REGEX_INTERVAL_PART_INVALID) {
1450
- return false;
1451
- }
1452
- if (result == REGEX_INTERVAL_PART_ESCAPED_CLOSE) {
1187
+ static void finish_malformed_escape(TSLexer *lexer) {
1188
+ if (
1189
+ !lexer->eof(lexer) &&
1190
+ lexer->lookahead !=
1191
+ '\n' &&
1192
+ source_character_is_valid(lexer->lookahead)
1193
+ ) {
1453
1194
  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
1195
  }
1196
+ lexer->mark_end(lexer);
1197
+ }
1461
1198
 
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;
1199
+ static void
1200
+ scan_malformed_interval_content(TSLexer *lexer, const ScannerState *state) {
1201
+ for (;;) {
1202
+ const int32_t character = lexer->lookahead;
1203
+ if (
1204
+ lexer->eof(lexer) ||
1205
+ !source_character_is_valid(character) ||
1206
+ character ==
1207
+ '\n' ||
1208
+ character ==
1209
+ state->delimiter ||
1210
+ character == '['
1211
+ ) {
1212
+ return;
1466
1213
  }
1467
- if (result == REGEX_INTERVAL_PART_ESCAPED_CLOSE) {
1468
- advance(lexer);
1469
- return true;
1214
+ #if SED_REGEX_EXTENDED
1215
+ if (
1216
+ character ==
1217
+ '}' ||
1218
+ character ==
1219
+ '(' ||
1220
+ character ==
1221
+ ')' ||
1222
+ character == '|'
1223
+ ) {
1224
+ return;
1470
1225
  }
1471
- }
1472
-
1473
- if (escaped_close) {
1474
- if (lexer->lookahead != '\\') {
1475
- return false;
1226
+ #endif
1227
+ if (character != '\\') {
1228
+ consume(lexer);
1229
+ continue;
1476
1230
  }
1231
+
1477
1232
  advance(lexer);
1478
- if (lexer->lookahead != '}' || state->delimiter == '}') {
1479
- advance_past_escaped_character(lexer);
1480
- return false;
1233
+ #if !SED_REGEX_EXTENDED
1234
+ if (interval_escape_ends_content(state, lexer->lookahead)) {
1235
+ return;
1481
1236
  }
1237
+ #endif
1238
+ finish_malformed_escape(lexer);
1482
1239
  }
1483
-
1484
- if (lexer->lookahead != '}' || state->delimiter == '}') {
1485
- return false;
1486
- }
1487
-
1488
- advance(lexer);
1489
- return true;
1490
1240
  }
1491
1241
 
1492
- static bool scan_regex_interval(
1242
+ static bool emit_malformed_interval(
1493
1243
  TSLexer *lexer,
1494
1244
  ScannerState *state,
1495
1245
  const bool *valid_symbols,
1496
1246
  TSSymbol *symbol
1497
1247
  ) {
1498
- advance(lexer);
1499
- lexer->mark_end(lexer);
1500
- state->regex_interval_state = REGEX_INTERVAL_EXPECT_MINIMUM;
1501
- return emit_symbol(valid_symbols, REGEX_INTERVAL_OPEN, symbol);
1502
- }
1503
-
1504
- static bool emit_interval_issue(
1505
- TSLexer *lexer,
1506
- ScannerState *state,
1507
- TSSymbol candidate,
1508
- TSSymbol *symbol
1509
- ) {
1510
- lexer->mark_end(lexer);
1511
- state->regex_interval_state = REGEX_INTERVAL_NONE;
1512
- *symbol = candidate;
1513
- return true;
1248
+ state->regex_in_interval =
1249
+ !lexer->eof(lexer) && !source_character_is_valid(lexer->lookahead);
1250
+ return emit_symbol(valid_symbols, REGEX_INVALID_INTERVAL, symbol);
1514
1251
  }
1515
1252
 
1516
- static bool
1517
- scan_invalid_interval_remainder(TSLexer *lexer, ScannerState *state);
1518
-
1519
- #if !SED_REGEX_EXTENDED
1520
- static bool scan_regex_after_backslash(
1521
- TSLexer *lexer,
1522
- ScannerState *state,
1523
- const bool *valid_symbols,
1524
- TSSymbol *symbol
1525
- );
1526
- #endif
1527
-
1528
1253
  static bool raw_duplication_symbol_follows(
1529
1254
  const TSLexer *lexer,
1530
1255
  const ScannerState *state
@@ -1537,88 +1262,38 @@ static bool raw_duplication_symbol_follows(
1537
1262
  '+' ||
1538
1263
  lexer->lookahead == '?';
1539
1264
  #else
1540
- return lexer->lookahead == '*' && !state->regex_at_branch_start;
1265
+ return lexer->lookahead == '*' && !regex_at_branch_start(state);
1541
1266
  #endif
1542
1267
  }
1543
1268
 
1544
- enum DuplicationContextScan {
1545
- DUPLICATION_CONTEXT_SKIPPED,
1546
- DUPLICATION_CONTEXT_TOKEN,
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
1269
+ static TSSymbol regex_duplication_context_marker(
1270
+ const TSLexer *lexer,
1271
+ const ScannerState *state
1555
1272
  ) {
1556
- TSSymbol candidate;
1557
- if (state->regex_at_branch_start) {
1558
- candidate = REGEX_LEADING_DUPLICATION_MARKER;
1559
- } else if (state->regex_duplication_state != REGEX_DUPLICATION_NONE) {
1273
+ if (regex_at_branch_start(state)) {
1274
+ return REGEX_LEADING_DUPLICATION_MARKER;
1275
+ }
1276
+ if (
1277
+ state->regex_position !=
1278
+ REGEX_AFTER_DUPLICATION_SYMBOL
1560
1279
  #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
- }
1280
+ && state->regex_position != REGEX_AFTER_REPETITION_MODIFIER
1568
1281
  #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;
1576
- }
1577
-
1578
- lexer->mark_end(lexer);
1579
- if (raw_duplication_symbol_follows(lexer, state)) {
1580
- *symbol = candidate;
1581
- return DUPLICATION_CONTEXT_TOKEN;
1282
+ ) {
1283
+ return ERROR_SENTINEL;
1582
1284
  }
1583
-
1584
1285
  #if SED_REGEX_EXTENDED
1585
- if (lexer->lookahead != '{' || state->delimiter == '{') {
1586
- return DUPLICATION_CONTEXT_SKIPPED;
1587
- }
1588
- advance(lexer);
1589
- if (scan_regex_interval_tail(lexer, state, false)) {
1590
- *symbol = candidate;
1591
- return DUPLICATION_CONTEXT_TOKEN;
1286
+ if (
1287
+ state->regex_position ==
1288
+ REGEX_AFTER_DUPLICATION_SYMBOL &&
1289
+ lexer->lookahead == '?'
1290
+ ) {
1291
+ return ERROR_SENTINEL;
1592
1292
  }
1593
1293
  #else
1594
- if (lexer->lookahead != '\\') {
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
- }
1294
+ (void)lexer;
1608
1295
  #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;
1296
+ return REGEX_ADJACENT_DUPLICATION_MARKER;
1622
1297
  }
1623
1298
 
1624
1299
  static bool raw_regex_operator_character(int32_t character) {
@@ -1646,10 +1321,9 @@ static bool scan_raw_regex_operator(
1646
1321
 
1647
1322
  if (character == '{') {
1648
1323
  #if SED_REGEX_EXTENDED
1649
- return scan_regex_interval(lexer, state, valid_symbols, symbol);
1324
+ return scan_regex_interval_open(lexer, state, valid_symbols, symbol);
1650
1325
  #else
1651
- consume(lexer);
1652
- return emit_symbol(valid_symbols, REGEX_LITERAL, symbol);
1326
+ return consume_as(lexer, valid_symbols, REGEX_LITERAL, symbol);
1653
1327
  #endif
1654
1328
  }
1655
1329
 
@@ -1661,7 +1335,7 @@ static bool scan_raw_regex_operator(
1661
1335
  #else
1662
1336
  return emit_symbol(
1663
1337
  valid_symbols,
1664
- state->regex_at_branch_start ? REGEX_LITERAL : REGEX_ZERO_OR_MORE,
1338
+ regex_at_branch_start(state) ? REGEX_LITERAL : REGEX_ZERO_OR_MORE,
1665
1339
  symbol
1666
1340
  );
1667
1341
  #endif
@@ -1690,7 +1364,7 @@ static bool scan_raw_regex_operator(
1690
1364
 
1691
1365
  if (character == '?') {
1692
1366
  if (
1693
- state->regex_duplication_state ==
1367
+ state->regex_position ==
1694
1368
  REGEX_AFTER_DUPLICATION_SYMBOL &&
1695
1369
  valid_symbols[REGEX_REPETITION_MODIFIER]
1696
1370
  ) {
@@ -1724,10 +1398,17 @@ static bool regex_delimiter_is_special(int32_t character) {
1724
1398
  }
1725
1399
  }
1726
1400
 
1401
+ // The QUOTED_CHAR sequences of XBD 9.5.1 for the selected RE.
1727
1402
  static bool escape_quotes_regex_syntax(int32_t character) {
1728
1403
  switch (character) {
1729
1404
  #if SED_REGEX_EXTENDED
1730
- case '}':
1405
+ case '(':
1406
+ case ')':
1407
+ case '{':
1408
+ case '}':
1409
+ case '+':
1410
+ case '?':
1411
+ case '|':
1731
1412
  #endif
1732
1413
  case '.':
1733
1414
  case '*':
@@ -1747,11 +1428,12 @@ static bool scan_regex_escaped_delimiter(
1747
1428
  const bool *valid_symbols,
1748
1429
  TSSymbol *symbol
1749
1430
  ) {
1750
- const bool special = regex_delimiter_is_special(lexer->lookahead);
1751
- consume(lexer);
1752
- return emit_symbol(
1431
+ return consume_as(
1432
+ lexer,
1753
1433
  valid_symbols,
1754
- special ? REGEX_SPECIAL_ESCAPED_DELIMITER : REGEX_ESCAPED_DELIMITER,
1434
+ regex_delimiter_is_special(lexer->lookahead)
1435
+ ? REGEX_SPECIAL_ESCAPED_DELIMITER
1436
+ : REGEX_ESCAPED_DELIMITER,
1755
1437
  symbol
1756
1438
  );
1757
1439
  }
@@ -1770,6 +1452,10 @@ static bool scan_regex_escape_after_backslash(
1770
1452
  return emit_symbol(valid_symbols, REGEX_FORBIDDEN_NEWLINE_ESCAPE, symbol);
1771
1453
  }
1772
1454
 
1455
+ if (!source_character_is_valid(lexer->lookahead)) {
1456
+ return emit_symbol(valid_symbols, ESCAPE_PREFIX, symbol);
1457
+ }
1458
+
1773
1459
  if (lexer->lookahead == state->delimiter) {
1774
1460
  return scan_regex_escaped_delimiter(lexer, valid_symbols, symbol);
1775
1461
  }
@@ -1777,103 +1463,89 @@ static bool scan_regex_escape_after_backslash(
1777
1463
  #if !SED_REGEX_EXTENDED
1778
1464
  if (lexer->lookahead == '}') {
1779
1465
  if (valid_symbols[REGEX_INTERVAL_CLOSE]) {
1780
- consume(lexer);
1781
- state->regex_interval_state = REGEX_INTERVAL_NONE;
1782
- return emit_symbol(valid_symbols, REGEX_INTERVAL_CLOSE, symbol);
1466
+ return scan_regex_interval_close(lexer, state, valid_symbols, symbol);
1783
1467
  }
1784
1468
  if (valid_symbols[REGEX_UNMATCHED_INTERVAL_CLOSE]) {
1785
- consume(lexer);
1786
- return emit_symbol(valid_symbols, REGEX_UNMATCHED_INTERVAL_CLOSE, symbol);
1469
+ return consume_as(
1470
+ lexer,
1471
+ valid_symbols,
1472
+ REGEX_UNMATCHED_INTERVAL_CLOSE,
1473
+ symbol
1474
+ );
1787
1475
  }
1788
1476
  }
1789
- #endif
1790
1477
 
1791
- if (lexer->lookahead == '(' || lexer->lookahead == ')') {
1792
- #if !SED_REGEX_EXTENDED
1793
- const int32_t character = lexer->lookahead;
1794
- #endif
1795
- consume(lexer);
1796
- #if SED_REGEX_EXTENDED
1797
- return emit_symbol(valid_symbols, REGEX_QUOTED_ESCAPE, symbol);
1798
- #else
1799
- return character == '('
1800
- ? emit_symbol(valid_symbols, REGEX_GROUP_OPEN, symbol)
1801
- : emit_symbol(
1802
- valid_symbols,
1803
- state->regex_group_depth > 0 ? REGEX_GROUP_CLOSE
1804
- : REGEX_UNMATCHED_GROUP_CLOSE,
1805
- symbol
1806
- );
1807
- #endif
1478
+ if (lexer->lookahead == '(') {
1479
+ return consume_as(lexer, valid_symbols, REGEX_GROUP_OPEN, symbol);
1480
+ }
1481
+
1482
+ if (lexer->lookahead == ')') {
1483
+ return consume_as(
1484
+ lexer,
1485
+ valid_symbols,
1486
+ state->regex_group_depth > 0 ? REGEX_GROUP_CLOSE
1487
+ : REGEX_UNMATCHED_GROUP_CLOSE,
1488
+ symbol
1489
+ );
1808
1490
  }
1809
1491
 
1810
1492
  if (lexer->lookahead >= '1' && lexer->lookahead <= '9') {
1811
- #if SED_REGEX_EXTENDED
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
1493
+ return consume_as(lexer, valid_symbols, REGEX_BACKREFERENCE, symbol);
1818
1494
  }
1819
1495
 
1820
1496
  if (lexer->lookahead == '{') {
1821
- #if SED_REGEX_EXTENDED
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
1497
+ return scan_regex_interval_open(lexer, state, valid_symbols, symbol);
1827
1498
  }
1828
1499
 
1829
- if (
1830
- lexer->lookahead ==
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(
1500
+ if (lexer->lookahead == '|') {
1501
+ return consume_as(
1502
+ lexer,
1846
1503
  valid_symbols,
1847
- character == '?' ? REGEX_BRE_QUESTION_MARK_ESCAPE : REGEX_BRE_PLUS_ESCAPE,
1504
+ REGEX_BRE_VERTICAL_LINE_ESCAPE,
1848
1505
  symbol
1849
1506
  );
1850
- #endif
1851
1507
  }
1852
1508
 
1509
+ if (lexer->lookahead == '?' || lexer->lookahead == '+') {
1510
+ return consume_as(
1511
+ lexer,
1512
+ valid_symbols,
1513
+ lexer->lookahead == '?' ? REGEX_BRE_QUESTION_MARK_ESCAPE
1514
+ : REGEX_BRE_PLUS_ESCAPE,
1515
+ symbol
1516
+ );
1517
+ }
1518
+ #endif
1519
+
1853
1520
  if (lexer->lookahead == 'n') {
1854
- consume(lexer);
1855
- return emit_symbol(valid_symbols, REGEX_NEWLINE_ESCAPE, symbol);
1521
+ return consume_as(lexer, valid_symbols, REGEX_NEWLINE_ESCAPE, symbol);
1856
1522
  }
1857
1523
 
1858
- const TSSymbol candidate = escape_quotes_regex_syntax(lexer->lookahead)
1859
- ? REGEX_QUOTED_ESCAPE
1860
- : REGEX_NONPORTABLE_ESCAPE;
1861
- consume(lexer);
1862
- return emit_symbol(valid_symbols, candidate, symbol);
1524
+ return consume_as(
1525
+ lexer,
1526
+ valid_symbols,
1527
+ escape_quotes_regex_syntax(lexer->lookahead) ? REGEX_QUOTED_ESCAPE
1528
+ : REGEX_NONPORTABLE_ESCAPE,
1529
+ symbol
1530
+ );
1863
1531
  }
1864
1532
 
1865
1533
  #if !SED_REGEX_EXTENDED
1534
+ // Scans the escape after a backslash whose token end is marked before it:
1535
+ // "\)" first closes an empty subexpression unless ')' is the delimiter.
1866
1536
  static bool scan_regex_after_backslash(
1867
1537
  TSLexer *lexer,
1868
1538
  ScannerState *state,
1869
1539
  const bool *valid_symbols,
1870
1540
  TSSymbol *symbol
1871
1541
  ) {
1872
- if (lexer->lookahead == state->delimiter) {
1873
- return scan_regex_escaped_delimiter(lexer, valid_symbols, symbol);
1874
- }
1875
-
1876
- if (lexer->lookahead == ')' && valid_symbols[EMPTY_SUBEXPRESSION_MARKER]) {
1542
+ if (
1543
+ lexer->lookahead ==
1544
+ ')' &&
1545
+ state->delimiter !=
1546
+ ')' &&
1547
+ valid_symbols[EMPTY_SUBEXPRESSION_MARKER]
1548
+ ) {
1877
1549
  *symbol = EMPTY_SUBEXPRESSION_MARKER;
1878
1550
  return true;
1879
1551
  }
@@ -1885,7 +1557,7 @@ static bool scan_regex_after_backslash(
1885
1557
 
1886
1558
  static bool scan_regex_dup_count(
1887
1559
  TSLexer *lexer,
1888
- ScannerState *state,
1560
+ const ScannerState *state,
1889
1561
  const bool *valid_symbols,
1890
1562
  TSSymbol *symbol
1891
1563
  ) {
@@ -1893,45 +1565,9 @@ static bool scan_regex_dup_count(
1893
1565
  consume(lexer);
1894
1566
  } while (is_digit(lexer->lookahead) && lexer->lookahead != state->delimiter);
1895
1567
 
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
1568
  return emit_symbol(valid_symbols, REGEX_DUP_COUNT, symbol);
1903
1569
  }
1904
1570
 
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
1571
  #if SED_REGEX_EXTENDED
1936
1572
  static bool scan_empty_regex_construct(
1937
1573
  TSLexer *lexer,
@@ -1946,7 +1582,7 @@ static bool scan_empty_regex_construct(
1946
1582
  ')' &&
1947
1583
  valid_symbols[EMPTY_SUBEXPRESSION_MARKER]
1948
1584
  ) {
1949
- return emit_missing_marker(
1585
+ return emit_marker(
1950
1586
  lexer,
1951
1587
  valid_symbols,
1952
1588
  EMPTY_SUBEXPRESSION_MARKER,
@@ -1959,87 +1595,257 @@ static bool scan_empty_regex_construct(
1959
1595
  '|' ||
1960
1596
  (state->regex_group_depth > 0 && lexer->lookahead == ')'))
1961
1597
  ) {
1962
- return emit_missing_marker(
1598
+ return emit_marker(lexer, valid_symbols, EMPTY_ALTERNATIVE_MARKER, symbol);
1599
+ }
1600
+ return false;
1601
+ }
1602
+ #endif
1603
+
1604
+ static bool scan_regex_special_token(
1605
+ TSLexer *lexer,
1606
+ ScannerState *state,
1607
+ const bool *valid_symbols,
1608
+ TSSymbol *symbol
1609
+ ) {
1610
+ if (lexer->lookahead == '^') {
1611
+ consume(lexer);
1612
+ #if !SED_REGEX_EXTENDED
1613
+ if (
1614
+ !regex_at_branch_start(state) ||
1615
+ state->regex_position == REGEX_AFTER_ANCHOR
1616
+ ) {
1617
+ return emit_symbol(valid_symbols, REGEX_LITERAL, symbol);
1618
+ }
1619
+ if (state->regex_group_depth > 0) {
1620
+ return emit_symbol(valid_symbols, REGEX_BRE_SUBEXPRESSION_CARET, symbol);
1621
+ }
1622
+ #endif
1623
+ return emit_symbol(valid_symbols, REGEX_BEGINNING_ANCHOR, symbol);
1624
+ }
1625
+
1626
+ if (lexer->lookahead == '$') {
1627
+ consume(lexer);
1628
+ #if !SED_REGEX_EXTENDED
1629
+ if (lexer->lookahead == '\\') {
1630
+ advance(lexer);
1631
+ const bool closes_subexpression = state->regex_group_depth >
1632
+ 0 &&
1633
+ lexer->lookahead ==
1634
+ ')' &&
1635
+ state->delimiter != ')';
1636
+ return emit_symbol(
1637
+ valid_symbols,
1638
+ closes_subexpression ? REGEX_BRE_SUBEXPRESSION_DOLLAR : REGEX_LITERAL,
1639
+ symbol
1640
+ );
1641
+ }
1642
+ const bool at_branch_end = lexer->eof(lexer) ||
1643
+ lexer->lookahead ==
1644
+ '\n' ||
1645
+ lexer->lookahead == state->delimiter;
1646
+ if (!at_branch_end) {
1647
+ return emit_symbol(valid_symbols, REGEX_LITERAL, symbol);
1648
+ }
1649
+ #endif
1650
+ return emit_symbol(valid_symbols, REGEX_END_ANCHOR, symbol);
1651
+ }
1652
+
1653
+ if (lexer->lookahead == '.') {
1654
+ return consume_as(lexer, valid_symbols, REGEX_PERIOD, symbol);
1655
+ }
1656
+
1657
+ if (lexer->lookahead == '\\') {
1658
+ consume(lexer);
1659
+ return scan_regex_escape_after_backslash(
1963
1660
  lexer,
1661
+ state,
1964
1662
  valid_symbols,
1965
- EMPTY_ALTERNATIVE_MARKER,
1966
1663
  symbol
1967
1664
  );
1968
1665
  }
1666
+
1667
+ if (raw_regex_operator_character(lexer->lookahead)) {
1668
+ return scan_raw_regex_operator(lexer, state, valid_symbols, symbol);
1669
+ }
1670
+
1671
+ if (lexer->lookahead == '[') {
1672
+ consume(lexer);
1673
+ reset_bracket_tracking(state);
1674
+ state->regex_state = REGEX_BRACKET_FIRST;
1675
+ return emit_symbol(valid_symbols, REGEX_BRACKET_OPEN, symbol);
1676
+ }
1677
+
1969
1678
  return false;
1970
1679
  }
1971
- #endif
1972
1680
 
1973
- static bool scan_regex_token(
1681
+ static bool scan_regex_bracket_close(
1974
1682
  TSLexer *lexer,
1975
1683
  ScannerState *state,
1976
1684
  const bool *valid_symbols,
1977
1685
  TSSymbol *symbol
1978
1686
  ) {
1979
- switch (scan_regex_duplication_context_marker(
1980
- lexer,
1981
- state,
1982
- valid_symbols,
1983
- symbol
1984
- )) {
1985
- case DUPLICATION_CONTEXT_TOKEN:
1687
+ commit_pending_bracket_element(state);
1688
+ if (
1689
+ bracket_expression_is_ambiguous(state) &&
1690
+ valid_symbols[AMBIGUOUS_BRACKET_EXPRESSION_MARKER]
1691
+ ) {
1692
+ lexer->mark_end(lexer);
1693
+ *symbol = AMBIGUOUS_BRACKET_EXPRESSION_MARKER;
1986
1694
  return true;
1987
- case DUPLICATION_CONTEXT_CONSUMED:
1988
- return false;
1989
- case DUPLICATION_CONTEXT_SKIPPED:
1990
- break;
1991
1695
  }
1992
1696
 
1993
- #if !SED_REGEX_EXTENDED
1994
- if (lexer->lookahead == '\\' && valid_symbols[EMPTY_SUBEXPRESSION_MARKER]) {
1995
- lexer->mark_end(lexer);
1996
- advance(lexer);
1997
- return scan_regex_after_backslash(lexer, state, valid_symbols, symbol);
1697
+ consume(lexer);
1698
+ state->regex_state = REGEX_OUTSIDE_BRACKET;
1699
+ reset_bracket_tracking(state);
1700
+ return emit_symbol(valid_symbols, REGEX_BRACKET_CLOSE, symbol);
1701
+ }
1702
+
1703
+ static bool scan_regex_bracket_hyphen(
1704
+ TSLexer *lexer,
1705
+ ScannerState *state,
1706
+ const bool *valid_symbols,
1707
+ TSSymbol *symbol
1708
+ ) {
1709
+ lexer->mark_end(lexer);
1710
+ advance(lexer);
1711
+ if (
1712
+ valid_symbols[NONPORTABLE_RANGE_START_MARKER] &&
1713
+ !lexer->eof(lexer) &&
1714
+ lexer->lookahead !=
1715
+ '\n' &&
1716
+ lexer->lookahead != ']'
1717
+ ) {
1718
+ *symbol = NONPORTABLE_RANGE_START_MARKER;
1719
+ return true;
1720
+ }
1721
+ lexer->mark_end(lexer);
1722
+
1723
+ TSSymbol candidate;
1724
+ if (valid_symbols[REGEX_BRACKET_RANGE_END_HYPHEN]) {
1725
+ candidate = REGEX_BRACKET_RANGE_END_HYPHEN;
1726
+ } else if (
1727
+ lexer->eof(lexer) || lexer->lookahead == '\n' || lexer->lookahead == ']'
1728
+ ) {
1729
+ candidate = REGEX_BRACKET_TRAILING_HYPHEN;
1730
+ } else {
1731
+ candidate = REGEX_BRACKET_HYPHEN;
1732
+ }
1733
+ if (emit_symbol(valid_symbols, candidate, symbol)) {
1734
+ if (candidate == REGEX_BRACKET_RANGE_END_HYPHEN) {
1735
+ state->regex_bracket_pending_element = REGEX_BRACKET_PENDING_NONE;
1736
+ state->regex_bracket_range_pending = false;
1737
+ record_bracket_element(state, REGEX_BRACKET_PENDING_OTHER);
1738
+ } else if (candidate == REGEX_BRACKET_TRAILING_HYPHEN) {
1739
+ commit_pending_bracket_element(state);
1740
+ record_bracket_element(state, REGEX_BRACKET_PENDING_OTHER);
1741
+ } else {
1742
+ state->regex_bracket_pending_element = REGEX_BRACKET_PENDING_NONE;
1743
+ state->regex_bracket_range_pending = true;
1744
+ }
1745
+ return true;
1998
1746
  }
1747
+ if (emit_symbol(valid_symbols, REGEX_SHARED_RANGE_ENDPOINT, symbol)) {
1748
+ commit_pending_bracket_element(state);
1749
+ state->regex_bracket_range_pending = false;
1750
+ return true;
1751
+ }
1752
+ return false;
1753
+ }
1754
+
1755
+ static bool scan_regex_bracket_special_token(
1756
+ TSLexer *lexer,
1757
+ ScannerState *state,
1758
+ const bool *valid_symbols,
1759
+ TSSymbol *symbol
1760
+ ) {
1761
+ if (state->regex_state == REGEX_BRACKET_FIRST && lexer->lookahead == '^') {
1762
+ consume(lexer);
1763
+ state->regex_state = REGEX_BRACKET_AFTER_CARET;
1764
+ return emit_symbol(valid_symbols, REGEX_BRACKET_NEGATION, symbol);
1765
+ }
1766
+
1767
+ if (state->regex_state == REGEX_BRACKET_BODY && lexer->lookahead == ']') {
1768
+ return scan_regex_bracket_close(lexer, state, valid_symbols, symbol);
1769
+ }
1770
+
1771
+ if (state->regex_state == REGEX_BRACKET_BODY && lexer->lookahead == '-') {
1772
+ return scan_regex_bracket_hyphen(lexer, state, valid_symbols, symbol);
1773
+ }
1774
+
1775
+ if (lexer->lookahead == '[') {
1776
+ return scan_regex_bracket_opener(lexer, state, valid_symbols, symbol);
1777
+ }
1778
+
1779
+ return false;
1780
+ }
1781
+
1782
+ static bool scan_regex_token(
1783
+ TSLexer *lexer,
1784
+ ScannerState *state,
1785
+ const bool *valid_symbols,
1786
+ TSSymbol *symbol
1787
+ ) {
1788
+ // The marker precedes the duplication symbol, whose interval is then
1789
+ // scanned like any other so that malformed content keeps its structure.
1790
+ const TSSymbol marker = regex_duplication_context_marker(lexer, state);
1791
+ if (marker != ERROR_SENTINEL && valid_symbols[marker]) {
1792
+ lexer->mark_end(lexer);
1793
+ #if SED_REGEX_EXTENDED
1794
+ if (
1795
+ raw_duplication_symbol_follows(lexer, state) || lexer->lookahead == '{'
1796
+ ) {
1797
+ *symbol = marker;
1798
+ return true;
1799
+ }
1999
1800
  #else
1801
+ if (raw_duplication_symbol_follows(lexer, state)) {
1802
+ *symbol = marker;
1803
+ return true;
1804
+ }
1805
+ if (lexer->lookahead == '\\') {
1806
+ advance(lexer);
1807
+ if (lexer->lookahead == '{' && state->delimiter != '{') {
1808
+ *symbol = marker;
1809
+ return true;
1810
+ }
1811
+ return scan_regex_after_backslash(lexer, state, valid_symbols, symbol);
1812
+ }
1813
+ #endif
1814
+ }
1815
+
1816
+ #if SED_REGEX_EXTENDED
2000
1817
  if (scan_empty_regex_construct(lexer, state, valid_symbols, symbol)) {
2001
1818
  return true;
2002
1819
  }
2003
1820
  #endif
2004
1821
 
1822
+ // The delimiter never reaches this point outside a bracket expression, so
1823
+ // the interval tokens compare only against their own characters.
2005
1824
  if (
2006
- valid_symbols[REGEX_DUP_COUNT] &&
2007
- is_digit(lexer->lookahead) &&
2008
- lexer->lookahead != state->delimiter
1825
+ state->regex_in_interval &&
1826
+ !lexer->eof(lexer) &&
1827
+ !source_character_is_valid(lexer->lookahead)
2009
1828
  ) {
1829
+ return consume_as(lexer, valid_symbols, INVALID_CHARACTER, symbol);
1830
+ }
1831
+
1832
+ if (valid_symbols[REGEX_DUP_COUNT] && is_digit(lexer->lookahead)) {
2010
1833
  return scan_regex_dup_count(lexer, state, valid_symbols, symbol);
2011
1834
  }
2012
1835
 
2013
- if (
2014
- valid_symbols[REGEX_INTERVAL_SEPARATOR] &&
2015
- lexer->lookahead ==
2016
- ',' &&
2017
- lexer->lookahead != state->delimiter
2018
- ) {
1836
+ if (valid_symbols[REGEX_INTERVAL_SEPARATOR] && lexer->lookahead == ',') {
2019
1837
  consume(lexer);
2020
- state->regex_interval_state = REGEX_INTERVAL_EXPECT_MAXIMUM;
2021
1838
  *symbol = REGEX_INTERVAL_SEPARATOR;
2022
1839
  return true;
2023
1840
  }
2024
1841
 
2025
1842
  #if SED_REGEX_EXTENDED
2026
- if (
2027
- valid_symbols[REGEX_INTERVAL_CLOSE] &&
2028
- lexer->lookahead ==
2029
- '}' &&
2030
- lexer->lookahead != state->delimiter
2031
- ) {
2032
- consume(lexer);
2033
- state->regex_interval_state = REGEX_INTERVAL_NONE;
2034
- *symbol = REGEX_INTERVAL_CLOSE;
2035
- return true;
1843
+ if (valid_symbols[REGEX_INTERVAL_CLOSE] && lexer->lookahead == '}') {
1844
+ return scan_regex_interval_close(lexer, state, valid_symbols, symbol);
2036
1845
  }
2037
1846
  #else
2038
- if (
2039
- state->regex_interval_state !=
2040
- REGEX_INTERVAL_NONE &&
2041
- lexer->lookahead == '\\'
2042
- ) {
1847
+ if (state->regex_in_interval && lexer->lookahead == '\\') {
1848
+ lexer->mark_end(lexer);
2043
1849
  advance(lexer);
2044
1850
  if (
2045
1851
  valid_symbols[REGEX_INTERVAL_CLOSE] &&
@@ -2047,46 +1853,38 @@ static bool scan_regex_token(
2047
1853
  '}' &&
2048
1854
  lexer->lookahead != state->delimiter
2049
1855
  ) {
2050
- consume(lexer);
2051
- state->regex_interval_state = REGEX_INTERVAL_NONE;
2052
- *symbol = REGEX_INTERVAL_CLOSE;
2053
- return true;
1856
+ return scan_regex_interval_close(lexer, state, valid_symbols, symbol);
2054
1857
  }
2055
1858
  if (lexer->eof(lexer) && valid_symbols[REGEX_INCOMPLETE_INTERVAL]) {
2056
- return emit_interval_issue(
2057
- lexer,
1859
+ lexer->mark_end(lexer);
1860
+ return end_interval(
2058
1861
  state,
1862
+ valid_symbols,
2059
1863
  REGEX_INCOMPLETE_INTERVAL,
2060
1864
  symbol
2061
1865
  );
2062
1866
  }
2063
- if (!valid_symbols[REGEX_INVALID_INTERVAL]) {
2064
- return false;
2065
- }
2066
- if (lexer->lookahead == '}') {
2067
- advance(lexer);
2068
- } else {
2069
- advance_past_escaped_character(lexer);
2070
- scan_invalid_interval_remainder(lexer, state);
1867
+ // The escape is the first unit of malformed content unless it ends the
1868
+ // content, in which case the issue is empty and the escape follows it.
1869
+ if (!interval_escape_ends_content(state, lexer->lookahead)) {
1870
+ finish_malformed_escape(lexer);
1871
+ scan_malformed_interval_content(lexer, state);
2071
1872
  }
2072
- return emit_interval_issue(lexer, state, REGEX_INVALID_INTERVAL, symbol);
1873
+ return emit_malformed_interval(lexer, state, valid_symbols, symbol);
2073
1874
  }
2074
1875
  #endif
2075
1876
 
2076
- if (
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;
2083
- return true;
1877
+ if (state->regex_in_interval && valid_symbols[REGEX_INVALID_INTERVAL]) {
1878
+ lexer->mark_end(lexer);
1879
+ scan_malformed_interval_content(lexer, state);
1880
+ return emit_malformed_interval(lexer, state, valid_symbols, symbol);
2084
1881
  }
2085
1882
 
2086
1883
  const bool inside_bracket = regex_is_inside_bracket(state);
2087
1884
  if (inside_bracket) {
2088
1885
  if (
2089
1886
  valid_symbols[REGEX_CLASS_NAME] ||
1887
+ valid_symbols[REGEX_INVALID_CLASS_NAME] ||
2090
1888
  valid_symbols[REGEX_COLL_ELEM_SINGLE] ||
2091
1889
  valid_symbols[REGEX_COLL_ELEM_MULTI] ||
2092
1890
  valid_symbols[REGEX_META_CHAR]
@@ -2094,7 +1892,6 @@ static bool scan_regex_token(
2094
1892
  return scan_regex_bracket_term_content(
2095
1893
  lexer,
2096
1894
  state,
2097
- bracket_term_close_marker(state->regex_bracket_term_state),
2098
1895
  valid_symbols,
2099
1896
  symbol
2100
1897
  );
@@ -2112,212 +1909,42 @@ static bool scan_regex_token(
2112
1909
  *symbol = REGEX_MALFORMED_BRACKET_TERM;
2113
1910
  return true;
2114
1911
  }
2115
- if (valid_symbols[REGEX_COLON_CLOSE] && lexer->lookahead == ':') {
2116
- return scan_regex_bracket_term_close(
2117
- lexer,
2118
- state,
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
- );
2134
- }
2135
- if (valid_symbols[REGEX_EQUAL_CLOSE] && lexer->lookahead == '=') {
2136
- return scan_regex_bracket_term_close(
2137
- lexer,
2138
- state,
2139
- '=',
2140
- REGEX_EQUAL_CLOSE,
2141
- valid_symbols,
2142
- symbol
2143
- );
2144
- }
2145
- }
2146
-
2147
- const enum LiteralScanResult literal_result =
2148
- scan_regex_literal(lexer, state);
2149
- if (literal_result == LITERAL_SCAN_TOKEN) {
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
- );
2163
- }
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
- #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
-
2189
- if (lexer->lookahead == '$') {
2190
- bool inspected_bre_escape = false;
2191
- consume(lexer);
2192
- #if !SED_REGEX_EXTENDED
2193
- if (lexer->lookahead == '\\') {
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
- }
2215
-
2216
- if (lexer->lookahead == '.') {
2217
- consume(lexer);
2218
- return emit_symbol(valid_symbols, REGEX_PERIOD, symbol);
2219
- }
2220
-
2221
- if (lexer->lookahead == '\\') {
2222
- advance(lexer);
2223
- lexer->mark_end(lexer);
2224
- return scan_regex_escape_after_backslash(
2225
- lexer,
2226
- state,
2227
- valid_symbols,
2228
- symbol
2229
- );
2230
- }
2231
-
2232
- if (raw_regex_operator_character(lexer->lookahead)) {
2233
- return scan_raw_regex_operator(lexer, state, valid_symbols, symbol);
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);
2241
- }
2242
-
2243
- return false;
2244
- }
2245
-
2246
- if (state->regex_state == REGEX_BRACKET_FIRST && lexer->lookahead == '^') {
2247
- consume(lexer);
2248
- state->regex_state = REGEX_BRACKET_AFTER_CARET;
2249
- return emit_symbol(valid_symbols, REGEX_BRACKET_NEGATION, symbol);
2250
- }
2251
-
2252
- if (state->regex_state == REGEX_BRACKET_BODY && lexer->lookahead == ']') {
2253
- commit_pending_bracket_element(state);
2254
- if (
2255
- bracket_expression_is_ambiguous(state) &&
2256
- valid_symbols[AMBIGUOUS_BRACKET_EXPRESSION_MARKER]
2257
- ) {
2258
- lexer->mark_end(lexer);
2259
- *symbol = AMBIGUOUS_BRACKET_EXPRESSION_MARKER;
2260
- return true;
2261
- }
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
1912
  if (
2273
- valid_symbols[NONPORTABLE_RANGE_START_MARKER] &&
2274
- !lexer->eof(lexer) &&
2275
- lexer->lookahead !=
2276
- '\n' &&
2277
- lexer->lookahead != ']'
2278
- ) {
2279
- *symbol = NONPORTABLE_RANGE_START_MARKER;
2280
- return true;
2281
- }
2282
- lexer->mark_end(lexer);
2283
-
2284
- TSSymbol candidate;
2285
- if (valid_symbols[REGEX_BRACKET_RANGE_END_HYPHEN]) {
2286
- candidate = REGEX_BRACKET_RANGE_END_HYPHEN;
2287
- } else if (
2288
- lexer->eof(lexer) || lexer->lookahead == '\n' || lexer->lookahead == ']'
1913
+ state->regex_bracket_term_state !=
1914
+ REGEX_BRACKET_TERM_NONE &&
1915
+ valid_symbols[bracket_terms[state->regex_bracket_term_state]
1916
+ .close_symbol] &&
1917
+ lexer->lookahead == bracket_terms[state->regex_bracket_term_state].marker
2289
1918
  ) {
2290
- candidate = REGEX_BRACKET_TRAILING_HYPHEN;
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;
1919
+ return scan_regex_bracket_term_close(lexer, state, valid_symbols, symbol);
2312
1920
  }
2313
- return false;
2314
1921
  }
2315
1922
 
2316
- if (lexer->lookahead == '[') {
2317
- return scan_regex_bracket_opener(lexer, state, valid_symbols, symbol);
1923
+ const enum LiteralScanResult literal_result =
1924
+ scan_regex_literal(lexer, state);
1925
+ if (literal_result == LITERAL_SCAN_INVALID_CHARACTER) {
1926
+ return emit_symbol(valid_symbols, INVALID_CHARACTER, symbol);
1927
+ }
1928
+ if (literal_result == LITERAL_SCAN_TOKEN) {
1929
+ return emit_symbol(
1930
+ valid_symbols,
1931
+ inside_bracket ? REGEX_BRACKET_LITERAL : REGEX_LITERAL,
1932
+ symbol
1933
+ );
1934
+ }
1935
+ if (literal_result == LITERAL_SCAN_LINE_END) {
1936
+ return end_mode(
1937
+ state,
1938
+ valid_symbols,
1939
+ unterminated_mode_symbol(state->mode, lexer->eof(lexer)),
1940
+ symbol
1941
+ );
2318
1942
  }
2319
1943
 
2320
- return false;
1944
+ if (state->regex_state == REGEX_OUTSIDE_BRACKET) {
1945
+ return scan_regex_special_token(lexer, state, valid_symbols, symbol);
1946
+ }
1947
+ return scan_regex_bracket_special_token(lexer, state, valid_symbols, symbol);
2321
1948
  }
2322
1949
 
2323
1950
  static enum LiteralScanResult scan_operand_literal(
@@ -2333,6 +1960,10 @@ static enum LiteralScanResult scan_operand_literal(
2333
1960
  return consumed ? LITERAL_SCAN_TOKEN : LITERAL_SCAN_LINE_END;
2334
1961
  }
2335
1962
 
1963
+ if (lexer->lookahead == 0) {
1964
+ return consumed ? LITERAL_SCAN_TOKEN : LITERAL_SCAN_INVALID_CHARACTER;
1965
+ }
1966
+
2336
1967
  if (
2337
1968
  lexer->lookahead ==
2338
1969
  state->delimiter ||
@@ -2340,6 +1971,10 @@ static enum LiteralScanResult scan_operand_literal(
2340
1971
  '\\' ||
2341
1972
  (ampersand_is_special && lexer->lookahead == '&')
2342
1973
  ) {
1974
+ if (consumed && lexer->lookahead == state->delimiter) {
1975
+ // Track every byte of the delimiter as lookahead, outside the literal.
1976
+ advance(lexer);
1977
+ }
2343
1978
  return consumed ? LITERAL_SCAN_TOKEN : LITERAL_SCAN_NONE;
2344
1979
  }
2345
1980
 
@@ -2354,16 +1989,23 @@ static bool scan_replacement_escape(
2354
1989
  const bool *valid_symbols,
2355
1990
  TSSymbol *symbol
2356
1991
  ) {
2357
- advance(lexer);
2358
- lexer->mark_end(lexer);
1992
+ consume(lexer);
2359
1993
 
2360
1994
  if (lexer->eof(lexer)) {
2361
1995
  return emit_symbol(valid_symbols, REPLACEMENT_INCOMPLETE_ESCAPE, symbol);
2362
1996
  }
2363
1997
 
1998
+ if (lexer->lookahead == 0) {
1999
+ return emit_symbol(valid_symbols, ESCAPE_PREFIX, symbol);
2000
+ }
2001
+
2364
2002
  if (lexer->lookahead == '\n') {
2365
- consume(lexer);
2366
- return emit_symbol(valid_symbols, REPLACEMENT_ESCAPED_NEWLINE, symbol);
2003
+ return consume_as(
2004
+ lexer,
2005
+ valid_symbols,
2006
+ REPLACEMENT_ESCAPED_NEWLINE,
2007
+ symbol
2008
+ );
2367
2009
  }
2368
2010
 
2369
2011
  TSSymbol candidate = REPLACEMENT_ESCAPE_SEQUENCE;
@@ -2376,8 +2018,12 @@ static bool scan_replacement_escape(
2376
2018
  '\\' &&
2377
2019
  !is_digit(lexer->lookahead)
2378
2020
  ) {
2379
- consume(lexer);
2380
- return emit_symbol(valid_symbols, REPLACEMENT_NONPORTABLE_ESCAPE, symbol);
2021
+ return consume_as(
2022
+ lexer,
2023
+ valid_symbols,
2024
+ REPLACEMENT_NONPORTABLE_ESCAPE,
2025
+ symbol
2026
+ );
2381
2027
  }
2382
2028
  if (lexer->lookahead == state->delimiter) {
2383
2029
  candidate = state->delimiter == '&'
@@ -2387,51 +2033,7 @@ static bool scan_replacement_escape(
2387
2033
  candidate = REPLACEMENT_BACKREFERENCE;
2388
2034
  }
2389
2035
 
2390
- consume(lexer);
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;
2036
+ return consume_as(lexer, valid_symbols, candidate, symbol);
2435
2037
  }
2436
2038
 
2437
2039
  static bool scan_translate_escape(
@@ -2440,56 +2042,73 @@ static bool scan_translate_escape(
2440
2042
  const bool *valid_symbols,
2441
2043
  TSSymbol *symbol
2442
2044
  ) {
2443
- advance(lexer);
2444
- lexer->mark_end(lexer);
2045
+ consume(lexer);
2445
2046
 
2446
2047
  if (lexer->eof(lexer)) {
2447
2048
  return emit_symbol(valid_symbols, TRANSLATE_INCOMPLETE_ESCAPE, symbol);
2448
2049
  }
2449
2050
 
2051
+ if (lexer->lookahead == 0) {
2052
+ return emit_symbol(valid_symbols, ESCAPE_PREFIX, symbol);
2053
+ }
2054
+
2450
2055
  if (lexer->lookahead == '\n') {
2451
2056
  return emit_symbol(valid_symbols, TRANSLATE_NONPORTABLE_ESCAPE, symbol);
2452
2057
  }
2453
2058
 
2454
- if (
2455
- lexer->lookahead !=
2456
- 'n' &&
2457
- lexer->lookahead !=
2458
- '\\' &&
2459
- (lexer->lookahead != state->delimiter || state->delimiter == 'n')
2460
- ) {
2461
- consume(lexer);
2462
- return emit_symbol(valid_symbols, TRANSLATE_NONPORTABLE_ESCAPE, symbol);
2059
+ // "\n" is a newline even when 'n' is the delimiter.
2060
+ TSSymbol candidate;
2061
+ if (lexer->lookahead == 'n' || lexer->lookahead == '\\') {
2062
+ candidate = TRANSLATE_ESCAPE;
2063
+ } else if (lexer->lookahead == state->delimiter) {
2064
+ candidate = TRANSLATE_ESCAPED_DELIMITER;
2065
+ } else {
2066
+ candidate = TRANSLATE_NONPORTABLE_ESCAPE;
2463
2067
  }
2464
- const TSSymbol candidate = lexer->lookahead == 'n' || lexer->lookahead == '\\'
2465
- ? TRANSLATE_ESCAPE
2466
- : TRANSLATE_ESCAPED_DELIMITER;
2467
- consume(lexer);
2468
- return emit_symbol(valid_symbols, candidate, symbol);
2068
+ return consume_as(lexer, valid_symbols, candidate, symbol);
2469
2069
  }
2470
2070
 
2471
- static bool scan_translate_token(
2071
+ static bool scan_operand_token(
2472
2072
  TSLexer *lexer,
2473
2073
  ScannerState *state,
2474
2074
  const bool *valid_symbols,
2475
2075
  TSSymbol *symbol
2476
2076
  ) {
2077
+ const bool is_replacement = state->mode == MODE_SUBSTITUTE_REPLACEMENT;
2477
2078
  const enum LiteralScanResult literal_result =
2478
- scan_operand_literal(lexer, state, false);
2079
+ scan_operand_literal(lexer, state, is_replacement);
2479
2080
  if (literal_result == LITERAL_SCAN_TOKEN) {
2480
- return emit_symbol(valid_symbols, TRANSLATE_LITERAL, symbol);
2081
+ return emit_symbol(
2082
+ valid_symbols,
2083
+ is_replacement ? REPLACEMENT_LITERAL : TRANSLATE_LITERAL,
2084
+ symbol
2085
+ );
2086
+ }
2087
+ if (literal_result == LITERAL_SCAN_INVALID_CHARACTER) {
2088
+ return consume_as(lexer, valid_symbols, NUL_CHARACTER, symbol);
2481
2089
  }
2482
2090
  if (literal_result == LITERAL_SCAN_LINE_END) {
2483
- return emit_unterminated(
2091
+ return end_mode(
2484
2092
  state,
2485
2093
  valid_symbols,
2486
- translate_unterminated_symbol(state->mode, lexer->eof(lexer)),
2094
+ unterminated_mode_symbol(state->mode, lexer->eof(lexer)),
2487
2095
  symbol
2488
2096
  );
2489
2097
  }
2490
2098
 
2491
2099
  if (lexer->lookahead == '\\') {
2492
- return scan_translate_escape(lexer, state, valid_symbols, symbol);
2100
+ return is_replacement
2101
+ ? scan_replacement_escape(lexer, state, valid_symbols, symbol)
2102
+ : scan_translate_escape(lexer, state, valid_symbols, symbol);
2103
+ }
2104
+
2105
+ if (is_replacement && lexer->lookahead == '&') {
2106
+ return consume_as(
2107
+ lexer,
2108
+ valid_symbols,
2109
+ REPLACEMENT_MATCH_REFERENCE,
2110
+ symbol
2111
+ );
2493
2112
  }
2494
2113
 
2495
2114
  return false;
@@ -2501,26 +2120,6 @@ static bool scan_regex_recovery_marker(
2501
2120
  const bool *valid_symbols,
2502
2121
  TSSymbol *symbol
2503
2122
  ) {
2504
- #if !SED_REGEX_EXTENDED
2505
- if (
2506
- emit_missing_marker(
2507
- lexer,
2508
- valid_symbols,
2509
- BRE_VERTICAL_LINE_ESCAPE_MARKER,
2510
- symbol
2511
- ) ||
2512
- emit_missing_marker(
2513
- lexer,
2514
- valid_symbols,
2515
- BRE_QUESTION_MARK_ESCAPE_MARKER,
2516
- symbol
2517
- ) ||
2518
- emit_missing_marker(lexer, valid_symbols, BRE_PLUS_ESCAPE_MARKER, symbol)
2519
- ) {
2520
- return true;
2521
- }
2522
- #endif
2523
-
2524
2123
  const bool at_line_boundary = lexer->eof(lexer) || lexer->lookahead == '\n';
2525
2124
  const bool at_regex_end =
2526
2125
  at_line_boundary || lexer->lookahead == state->delimiter;
@@ -2530,9 +2129,12 @@ static bool scan_regex_recovery_marker(
2530
2129
  REGEX_OUTSIDE_BRACKET &&
2531
2130
  state->regex_group_depth >
2532
2131
  0 &&
2533
- !state->regex_after_alternation &&
2132
+ #if SED_REGEX_EXTENDED
2133
+ state->regex_position !=
2134
+ REGEX_AFTER_ALTERNATION &&
2135
+ #endif
2534
2136
  at_regex_end &&
2535
- emit_missing_marker(
2137
+ emit_marker(
2536
2138
  lexer,
2537
2139
  valid_symbols,
2538
2140
  lexer->eof(lexer) ? MISSING_SUBEXPRESSION_MARKER
@@ -2548,7 +2150,7 @@ static bool scan_regex_recovery_marker(
2548
2150
  REGEX_BRACKET_FIRST ||
2549
2151
  state->regex_state == REGEX_BRACKET_AFTER_CARET) &&
2550
2152
  at_line_boundary &&
2551
- emit_missing_marker(
2153
+ emit_marker(
2552
2154
  lexer,
2553
2155
  valid_symbols,
2554
2156
  lexer->eof(lexer) ? INCOMPLETE_BRACKET_LIST_MARKER
@@ -2563,7 +2165,7 @@ static bool scan_regex_recovery_marker(
2563
2165
  state->regex_bracket_term_state !=
2564
2166
  REGEX_BRACKET_TERM_NONE &&
2565
2167
  at_line_boundary &&
2566
- emit_missing_marker(
2168
+ emit_marker(
2567
2169
  lexer,
2568
2170
  valid_symbols,
2569
2171
  lexer->eof(lexer) ? REGEX_INCOMPLETE_BRACKET_TERM
@@ -2579,7 +2181,7 @@ static bool scan_regex_recovery_marker(
2579
2181
  if (
2580
2182
  regex_is_inside_bracket(state) &&
2581
2183
  at_line_boundary &&
2582
- emit_missing_marker(
2184
+ emit_marker(
2583
2185
  lexer,
2584
2186
  valid_symbols,
2585
2187
  lexer->eof(lexer) ? INCOMPLETE_BRACKET_EXPRESSION_MARKER
@@ -2596,9 +2198,10 @@ static bool scan_regex_recovery_marker(
2596
2198
  if (
2597
2199
  state->regex_state ==
2598
2200
  REGEX_OUTSIDE_BRACKET &&
2599
- state->regex_after_alternation &&
2201
+ state->regex_position ==
2202
+ REGEX_AFTER_ALTERNATION &&
2600
2203
  at_regex_end &&
2601
- emit_missing_marker(
2204
+ emit_marker(
2602
2205
  lexer,
2603
2206
  valid_symbols,
2604
2207
  lexer->eof(lexer) ? INCOMPLETE_ALTERNATIVE_MARKER
@@ -2606,27 +2209,22 @@ static bool scan_regex_recovery_marker(
2606
2209
  symbol
2607
2210
  )
2608
2211
  ) {
2609
- state->regex_after_alternation = false;
2212
+ state->regex_position = REGEX_AT_BRANCH_START;
2610
2213
  return true;
2611
2214
  }
2612
2215
  #endif
2613
2216
 
2614
2217
  if (
2615
- state->regex_interval_state !=
2616
- REGEX_INTERVAL_NONE &&
2617
- (at_regex_end
2618
- #if !SED_REGEX_EXTENDED
2619
- || (state->delimiter == '}' && lexer->lookahead == '\\')
2620
- #endif
2621
- ) &&
2622
- emit_missing_marker(
2218
+ state->regex_in_interval &&
2219
+ at_regex_end &&
2220
+ emit_marker(
2623
2221
  lexer,
2624
2222
  valid_symbols,
2625
2223
  lexer->eof(lexer) ? REGEX_INCOMPLETE_INTERVAL : REGEX_INVALID_INTERVAL,
2626
2224
  symbol
2627
2225
  )
2628
2226
  ) {
2629
- state->regex_interval_state = REGEX_INTERVAL_NONE;
2227
+ state->regex_in_interval = false;
2630
2228
  return true;
2631
2229
  }
2632
2230
 
@@ -2636,7 +2234,7 @@ static bool scan_regex_recovery_marker(
2636
2234
  state->regex_group_depth >
2637
2235
  0 &&
2638
2236
  at_line_boundary &&
2639
- emit_missing_marker(
2237
+ emit_marker(
2640
2238
  lexer,
2641
2239
  valid_symbols,
2642
2240
  lexer->eof(lexer) ? REGEX_INCOMPLETE_GROUP : REGEX_UNCLOSED_GROUP,
@@ -2655,60 +2253,97 @@ static TSSymbol missing_text_introducer_symbol(const TSLexer *lexer) {
2655
2253
  : NONCONFORMING_MISSING_TEXT_INTRODUCER_MARKER;
2656
2254
  }
2657
2255
 
2256
+ static bool
2257
+ scan_right_brace(TSLexer *lexer, const bool *valid_symbols, TSSymbol *symbol) {
2258
+ skip_blanks(lexer);
2259
+
2260
+ if (lexer->lookahead == '}') {
2261
+ consume(lexer);
2262
+ *symbol = RIGHT_BRACE;
2263
+ return true;
2264
+ }
2265
+ if (lexer->eof(lexer)) {
2266
+ return emit_marker(
2267
+ lexer,
2268
+ valid_symbols,
2269
+ MISSING_CLOSING_BRACE_MARKER,
2270
+ symbol
2271
+ );
2272
+ }
2273
+ return false;
2274
+ }
2275
+
2658
2276
  static bool scan_command_token(
2659
2277
  TSLexer *lexer,
2660
2278
  ScannerState *state,
2661
2279
  const bool *valid_symbols,
2662
2280
  TSSymbol *symbol
2663
2281
  ) {
2664
- if (valid_symbols[LINE_WORD] && scan_to_physical_line_end(lexer, false)) {
2282
+ if (
2283
+ valid_symbols[EMPTY_COMMAND_MARKER] &&
2284
+ (lexer->lookahead == ';' || lexer->lookahead == '\n')
2285
+ ) {
2286
+ return emit_marker(lexer, valid_symbols, EMPTY_COMMAND_MARKER, symbol);
2287
+ }
2288
+
2289
+ if (
2290
+ valid_symbols[NUL_CHARACTER] && !lexer->eof(lexer) && lexer->lookahead == 0
2291
+ ) {
2292
+ return consume_as(lexer, valid_symbols, NUL_CHARACTER, symbol);
2293
+ }
2294
+
2295
+ if (
2296
+ valid_symbols[SUBSTITUTION_WFILE_CONTINUATION] &&
2297
+ scan_line_rest(lexer, true)
2298
+ ) {
2299
+ *symbol = SUBSTITUTION_WFILE_CONTINUATION;
2300
+ return true;
2301
+ }
2302
+
2303
+ if (valid_symbols[LINE_WORD] && scan_line_rest(lexer, false)) {
2665
2304
  *symbol = LINE_WORD;
2666
2305
  return true;
2667
2306
  }
2668
2307
 
2308
+ // The label separator of b and t is exactly one space. It is read before
2309
+ // the post-blank recovery markers, which would otherwise claim the blank in
2310
+ // front of a label that starts with a closing brace.
2311
+ if (valid_symbols[ARGUMENT_SEPARATOR] && lexer->lookahead == ' ') {
2312
+ consume(lexer);
2313
+ *symbol = ARGUMENT_SEPARATOR;
2314
+ return true;
2315
+ }
2316
+
2669
2317
  if (valid_symbols[FLAG_AFTER_WRITE_MARKER]) {
2670
- const enum FlagAfterWriteScan scan = scan_flag_after_write_marker(lexer);
2671
- if (scan == FLAG_AFTER_WRITE_MATCH) {
2318
+ switch (scan_flag_after_write_marker(lexer)) {
2319
+ case FLAG_AFTER_WRITE_MATCH:
2672
2320
  *symbol = FLAG_AFTER_WRITE_MARKER;
2673
2321
  return true;
2674
- }
2675
- if (
2676
- scan ==
2677
- FLAG_AFTER_WRITE_FALLBACK &&
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;
2322
+ case FLAG_AFTER_WRITE_FALLBACK:
2323
+ return emit_symbol(valid_symbols, OMITTED_FILE_SEPARATOR_MARKER, symbol);
2324
+ case FLAG_AFTER_WRITE_NONE:
2325
+ break;
2685
2326
  }
2686
2327
  }
2687
2328
 
2688
2329
  if (
2689
2330
  valid_symbols[SUBSTITUTION_WFILE_ARGUMENT] &&
2690
- scan_substitution_wfile_argument(lexer)
2331
+ scan_file_argument(lexer, true)
2691
2332
  ) {
2692
2333
  *symbol = SUBSTITUTION_WFILE_ARGUMENT;
2693
2334
  return true;
2694
2335
  }
2695
2336
 
2696
- if (valid_symbols[FILE_ARGUMENT] && scan_file_argument(lexer)) {
2337
+ if (valid_symbols[FILE_ARGUMENT] && scan_file_argument(lexer, false)) {
2697
2338
  *symbol = FILE_ARGUMENT;
2698
2339
  return true;
2699
2340
  }
2700
2341
 
2701
2342
  if (
2702
2343
  valid_symbols[INVALID_SUBSTITUTION_FLAG] &&
2344
+ !at_command_boundary(lexer) &&
2703
2345
  !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)
2346
+ !is_substitution_flag_character(lexer->lookahead)
2712
2347
  ) {
2713
2348
  consume(lexer);
2714
2349
  *symbol = INVALID_SUBSTITUTION_FLAG;
@@ -2720,9 +2355,13 @@ static bool scan_command_token(
2720
2355
  *symbol = TEXT_COMMAND_START;
2721
2356
  return true;
2722
2357
  }
2358
+ if (lexer->eof(lexer)) {
2359
+ lexer->mark_end(lexer);
2360
+ return emit_symbol(valid_symbols, TEXT_INCOMPLETE_INTRODUCER, symbol);
2361
+ }
2723
2362
  return emit_symbol(
2724
2363
  valid_symbols,
2725
- missing_text_introducer_symbol(lexer),
2364
+ NONCONFORMING_MISSING_TEXT_INTRODUCER_MARKER,
2726
2365
  symbol
2727
2366
  );
2728
2367
  }
@@ -2733,77 +2372,72 @@ static bool scan_command_token(
2733
2372
  return true;
2734
2373
  }
2735
2374
 
2736
- if (valid_symbols[COMMENT_TEXT] && scan_to_physical_line_end(lexer, false)) {
2375
+ if (valid_symbols[COMMENT_TEXT] && scan_line_rest(lexer, false)) {
2737
2376
  *symbol = COMMENT_TEXT;
2738
2377
  return true;
2739
2378
  }
2740
2379
 
2741
- // Preserve an address interpretation before reserved-function recovery.
2742
2380
  if (
2743
- valid_symbols[MISSING_ADDRESS_SEPARATOR_MARKER] && can_start_address(lexer)
2381
+ valid_symbols[INVALID_CHARACTER] &&
2382
+ !lexer->eof(lexer) &&
2383
+ !source_character_is_valid(lexer->lookahead)
2744
2384
  ) {
2745
- return emit_missing_marker(
2746
- lexer,
2747
- valid_symbols,
2748
- MISSING_ADDRESS_SEPARATOR_MARKER,
2749
- symbol
2750
- );
2385
+ return consume_as(lexer, valid_symbols, INVALID_CHARACTER, symbol);
2751
2386
  }
2752
2387
 
2388
+ // Preserve an address interpretation before reserved-function recovery.
2753
2389
  if (
2754
- valid_symbols[RESERVED_UNKNOWN_FUNCTION_TOKEN] &&
2755
- scan_reserved_unknown_function(lexer)
2390
+ can_start_address(lexer) &&
2391
+ emit_marker(lexer, valid_symbols, MISSING_ADDRESS_SEPARATOR_MARKER, symbol)
2756
2392
  ) {
2757
- *symbol = RESERVED_UNKNOWN_FUNCTION_TOKEN;
2758
2393
  return true;
2759
2394
  }
2760
2395
 
2761
2396
  if (
2762
- valid_symbols[REGEX_ADDRESS_START] &&
2763
- lexer->lookahead ==
2764
- '/' &&
2765
- scan_simple_delimiter(lexer, state, MODE_REGEX_ADDRESS)
2397
+ valid_symbols[RESERVED_UNKNOWN_FUNCTION_TOKEN] && can_start_address(lexer)
2766
2398
  ) {
2767
- *symbol = REGEX_ADDRESS_START;
2399
+ consume(lexer);
2400
+ *symbol = RESERVED_UNKNOWN_FUNCTION_TOKEN;
2768
2401
  return true;
2769
2402
  }
2770
2403
 
2771
- if (valid_symbols[ESCAPED_REGEX_ADDRESS_START]) {
2772
- if (scan_simple_delimiter(lexer, state, MODE_REGEX_ADDRESS)) {
2773
- *symbol = ESCAPED_REGEX_ADDRESS_START;
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;
2404
+ static const struct {
2405
+ TSSymbol symbol;
2406
+ enum ScannerMode mode;
2407
+ int32_t required_delimiter;
2408
+ } delimited_openers[] = {
2409
+ {REGEX_ADDRESS_START, MODE_REGEX_ADDRESS, '/'},
2410
+ {ESCAPED_REGEX_ADDRESS_START, MODE_REGEX_ADDRESS, 0},
2411
+ {SUBSTITUTE_START, MODE_SUBSTITUTE_PATTERN, 0},
2412
+ {TRANSLATE_START, MODE_TRANSLATE_SOURCE, 0},
2413
+ };
2414
+ for (
2415
+ unsigned index = 0;
2416
+ index < sizeof(delimited_openers) / sizeof(delimited_openers[0]);
2417
+ index++
2418
+ ) {
2419
+ const int32_t required = delimited_openers[index].required_delimiter;
2420
+ if (
2421
+ valid_symbols[delimited_openers[index].symbol] &&
2422
+ (required == 0 || lexer->lookahead == required) &&
2423
+ scan_simple_delimiter(lexer, state, delimited_openers[index].mode)
2424
+ ) {
2425
+ *symbol = delimited_openers[index].symbol;
2788
2426
  return true;
2789
2427
  }
2790
2428
  }
2791
2429
 
2792
- if (valid_symbols[RIGHT_BRACE] && scan_right_brace(lexer, state)) {
2793
- *symbol = RIGHT_BRACE;
2794
- return true;
2430
+ if (
2431
+ valid_symbols[RIGHT_BRACE] &&
2432
+ (is_blank(lexer->lookahead) || lexer->lookahead == '}')
2433
+ ) {
2434
+ return scan_right_brace(lexer, valid_symbols, symbol);
2795
2435
  }
2796
2436
 
2797
2437
  if (
2798
- valid_symbols[OMITTED_FIRST_ADDRESS_MARKER] &&
2799
2438
  lexer->lookahead ==
2800
2439
  ',' &&
2801
- emit_missing_marker(
2802
- lexer,
2803
- valid_symbols,
2804
- OMITTED_FIRST_ADDRESS_MARKER,
2805
- symbol
2806
- )
2440
+ emit_marker(lexer, valid_symbols, OMITTED_FIRST_ADDRESS_MARKER, symbol)
2807
2441
  ) {
2808
2442
  return true;
2809
2443
  }
@@ -2814,7 +2448,7 @@ static bool scan_command_token(
2814
2448
  !can_start_address(lexer) &&
2815
2449
  !is_blank(lexer->lookahead)
2816
2450
  ) {
2817
- return emit_missing_marker(
2451
+ return emit_marker(
2818
2452
  lexer,
2819
2453
  valid_symbols,
2820
2454
  lexer->eof(lexer) ? INCOMPLETE_OMITTED_ADDRESS_MARKER
@@ -2837,13 +2471,7 @@ static bool scan_command_token(
2837
2471
  if (
2838
2472
  !at_command_boundary(lexer) &&
2839
2473
  !is_blank(lexer->lookahead) &&
2840
- valid_symbols[OMITTED_FILE_SEPARATOR_MARKER] &&
2841
- emit_missing_marker(
2842
- lexer,
2843
- valid_symbols,
2844
- OMITTED_FILE_SEPARATOR_MARKER,
2845
- symbol
2846
- )
2474
+ emit_marker(lexer, valid_symbols, OMITTED_FILE_SEPARATOR_MARKER, symbol)
2847
2475
  ) {
2848
2476
  return true;
2849
2477
  }
@@ -2862,7 +2490,7 @@ static bool scan_command_token(
2862
2490
  index++
2863
2491
  ) {
2864
2492
  if (
2865
- emit_missing_marker(
2493
+ emit_marker(
2866
2494
  lexer,
2867
2495
  valid_symbols,
2868
2496
  boundary_markers[index][variant],
@@ -2875,7 +2503,7 @@ static bool scan_command_token(
2875
2503
  }
2876
2504
 
2877
2505
  if (
2878
- emit_missing_marker(
2506
+ emit_marker(
2879
2507
  lexer,
2880
2508
  valid_symbols,
2881
2509
  missing_text_introducer_symbol(lexer),
@@ -2885,19 +2513,17 @@ static bool scan_command_token(
2885
2513
  return true;
2886
2514
  }
2887
2515
 
2888
- if (valid_symbols[MISSING_CLOSING_BRACE_MARKER] && lexer->eof(lexer)) {
2889
- return emit_missing_marker(
2890
- lexer,
2891
- valid_symbols,
2892
- MISSING_CLOSING_BRACE_MARKER,
2893
- symbol
2894
- );
2516
+ if (
2517
+ lexer->eof(lexer) &&
2518
+ emit_marker(lexer, valid_symbols, MISSING_CLOSING_BRACE_MARKER, symbol)
2519
+ ) {
2520
+ return true;
2895
2521
  }
2896
2522
 
2897
2523
  if (
2898
2524
  !at_command_boundary(lexer) &&
2899
2525
  !is_blank(lexer->lookahead) &&
2900
- emit_missing_marker(
2526
+ emit_marker(
2901
2527
  lexer,
2902
2528
  valid_symbols,
2903
2529
  MISSING_SEPARATOR_AFTER_UNMATCHED_BRACE_MARKER,
@@ -2907,38 +2533,10 @@ static bool scan_command_token(
2907
2533
  return true;
2908
2534
  }
2909
2535
 
2910
- if (lexer->lookahead == '}') {
2911
- if (
2912
- emit_missing_marker(
2913
- lexer,
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
- }
2536
+ const TSSymbol separator_marker =
2537
+ missing_command_separator_marker(lexer, valid_symbols);
2538
+ if (separator_marker != ERROR_SENTINEL) {
2539
+ return emit_marker(lexer, valid_symbols, separator_marker, symbol);
2942
2540
  }
2943
2541
 
2944
2542
  const TSSymbol missing_opening_delimiter = lexer->eof(lexer)
@@ -2946,7 +2544,7 @@ static bool scan_command_token(
2946
2544
  : NONCONFORMING_MISSING_OPENING_DELIMITER_MARKER;
2947
2545
  if (
2948
2546
  delimiter_is_missing(lexer) &&
2949
- emit_missing_marker(lexer, valid_symbols, missing_opening_delimiter, symbol)
2547
+ emit_marker(lexer, valid_symbols, missing_opening_delimiter, symbol)
2950
2548
  ) {
2951
2549
  return true;
2952
2550
  }
@@ -2982,9 +2580,12 @@ static bool sed_scanner_scan_impl(
2982
2580
  (!is_regex_mode(state->mode) ||
2983
2581
  state->regex_state == REGEX_OUTSIDE_BRACKET);
2984
2582
  if (delimiter_is_active) {
2985
- if (state->regex_group_depth > 0 && valid_symbols[REGEX_UNCLOSED_GROUP]) {
2583
+ if (
2584
+ state->regex_group_depth >
2585
+ 0 &&
2586
+ emit_marker(lexer, valid_symbols, REGEX_UNCLOSED_GROUP, symbol)
2587
+ ) {
2986
2588
  state->regex_group_depth--;
2987
- *symbol = REGEX_UNCLOSED_GROUP;
2988
2589
  return true;
2989
2590
  }
2990
2591
  return scan_active_mode_delimiter(lexer, state, valid_symbols, symbol);
@@ -2995,10 +2596,9 @@ static bool sed_scanner_scan_impl(
2995
2596
  case MODE_SUBSTITUTE_PATTERN:
2996
2597
  return scan_regex_token(lexer, state, valid_symbols, symbol);
2997
2598
  case MODE_SUBSTITUTE_REPLACEMENT:
2998
- return scan_replacement_token(lexer, state, valid_symbols, symbol);
2999
2599
  case MODE_TRANSLATE_SOURCE:
3000
2600
  case MODE_TRANSLATE_DESTINATION:
3001
- return scan_translate_token(lexer, state, valid_symbols, symbol);
2601
+ return scan_operand_token(lexer, state, valid_symbols, symbol);
3002
2602
  case MODE_TEXT:
3003
2603
  return false;
3004
2604
  case MODE_NONE:
@@ -3010,17 +2610,10 @@ static bool sed_scanner_scan_impl(
3010
2610
 
3011
2611
  static void
3012
2612
  update_regex_position_after_symbol(ScannerState *state, TSSymbol symbol) {
3013
- #if !SED_REGEX_EXTENDED
3014
- if (
3015
- symbol ==
3016
- BRE_VERTICAL_LINE_ESCAPE_MARKER ||
3017
- symbol ==
3018
- BRE_QUESTION_MARK_ESCAPE_MARKER ||
3019
- symbol == BRE_PLUS_ESCAPE_MARKER
3020
- ) {
2613
+ if (!is_regex_mode(state->mode)) {
3021
2614
  return;
3022
2615
  }
3023
- #endif
2616
+
3024
2617
  if (
3025
2618
  symbol ==
3026
2619
  REGEX_LEADING_DUPLICATION_MARKER ||
@@ -3036,24 +2629,20 @@ update_regex_position_after_symbol(ScannerState *state, TSSymbol symbol) {
3036
2629
  }
3037
2630
 
3038
2631
  if (symbol == REGEX_GROUP_OPEN) {
3039
- if (state->regex_group_depth < UINT16_MAX) {
3040
- state->regex_group_depth++;
3041
- }
3042
- set_regex_position(state, true, REGEX_DUPLICATION_NONE, false, false);
2632
+ state->regex_group_depth++;
2633
+ state->regex_position = REGEX_AT_BRANCH_START;
3043
2634
  return;
3044
2635
  }
3045
2636
 
3046
2637
  if (symbol == REGEX_GROUP_CLOSE) {
3047
- if (state->regex_group_depth > 0) {
3048
- state->regex_group_depth--;
3049
- }
3050
- set_regex_position(state, false, REGEX_DUPLICATION_NONE, false, false);
2638
+ state->regex_group_depth--;
2639
+ state->regex_position = REGEX_AFTER_ATOM;
3051
2640
  return;
3052
2641
  }
3053
2642
 
3054
2643
  #if SED_REGEX_EXTENDED
3055
2644
  if (symbol == REGEX_ALTERNATION_OPERATOR) {
3056
- set_regex_position(state, true, REGEX_DUPLICATION_NONE, true, false);
2645
+ state->regex_position = REGEX_AFTER_ALTERNATION;
3057
2646
  return;
3058
2647
  }
3059
2648
  #endif
@@ -3067,7 +2656,11 @@ update_regex_position_after_symbol(ScannerState *state, TSSymbol symbol) {
3067
2656
  symbol == REGEX_BRE_SUBEXPRESSION_DOLLAR;
3068
2657
  #endif
3069
2658
  if (is_anchor) {
3070
- set_regex_position(state, true, REGEX_DUPLICATION_NONE, false, true);
2659
+ #if SED_REGEX_EXTENDED
2660
+ state->regex_position = REGEX_AT_BRANCH_START;
2661
+ #else
2662
+ state->regex_position = REGEX_AFTER_ANCHOR;
2663
+ #endif
3071
2664
  return;
3072
2665
  }
3073
2666
 
@@ -3083,30 +2676,18 @@ update_regex_position_after_symbol(ScannerState *state, TSSymbol symbol) {
3083
2676
  symbol == REGEX_ZERO_OR_ONE;
3084
2677
  #endif
3085
2678
  if (is_duplication) {
3086
- set_regex_position(
3087
- state,
3088
- false,
3089
- REGEX_AFTER_DUPLICATION_SYMBOL,
3090
- false,
3091
- false
3092
- );
2679
+ state->regex_position = REGEX_AFTER_DUPLICATION_SYMBOL;
3093
2680
  return;
3094
2681
  }
3095
2682
 
3096
2683
  #if SED_REGEX_EXTENDED
3097
2684
  if (symbol == REGEX_REPETITION_MODIFIER) {
3098
- set_regex_position(
3099
- state,
3100
- false,
3101
- REGEX_AFTER_REPETITION_MODIFIER,
3102
- false,
3103
- false
3104
- );
2685
+ state->regex_position = REGEX_AFTER_REPETITION_MODIFIER;
3105
2686
  return;
3106
2687
  }
3107
2688
  #endif
3108
2689
 
3109
- set_regex_position(state, false, REGEX_DUPLICATION_NONE, false, false);
2690
+ state->regex_position = REGEX_AFTER_ATOM;
3110
2691
  }
3111
2692
 
3112
2693
  static bool