|
1 | 1 | /*
|
2 |
| -* Copyright (c) 2024 Calvin Rose |
| 2 | +* Copyright (c) 2025 Calvin Rose |
3 | 3 | *
|
4 | 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
5 | 5 | * of this software and associated documentation files (the "Software"), to
|
@@ -549,36 +549,39 @@ static const uint8_t *peg_rule(
|
549 | 549 | const uint32_t *rule_separator = s->bytecode + rule[1];
|
550 | 550 | const uint32_t *rule_subpattern = s->bytecode + rule[2];
|
551 | 551 |
|
552 |
| - const uint8_t *separator_end = NULL; |
553 |
| - do { |
554 |
| - const uint8_t *text_start = text; |
| 552 | + const uint8_t *chunk_start = text; |
| 553 | + const uint8_t *chunk_end = NULL; |
| 554 | + |
| 555 | + while (text <= saved_end) { |
| 556 | + /* Find next split (or end of text) */ |
555 | 557 | CapState cs = cap_save(s);
|
556 | 558 | down1(s);
|
557 |
| - while (text <= s->text_end) { |
558 |
| - separator_end = peg_rule(s, rule_separator, text); |
| 559 | + while (text <= saved_end) { |
| 560 | + chunk_end = text; |
| 561 | + const uint8_t *check = peg_rule(s, rule_separator, text); |
559 | 562 | cap_load(s, cs);
|
560 |
| - if (separator_end) { |
| 563 | + if (check) { |
| 564 | + text = check; |
561 | 565 | break;
|
562 | 566 | }
|
563 | 567 | text++;
|
564 | 568 | }
|
565 | 569 | up1(s);
|
566 | 570 |
|
567 |
| - if (separator_end) { |
568 |
| - s->text_end = text; |
569 |
| - text = separator_end; |
570 |
| - } |
571 |
| - |
| 571 | + /* Match between splits */ |
| 572 | + s->text_end = chunk_end; |
572 | 573 | down1(s);
|
573 |
| - const uint8_t *subpattern_end = peg_rule(s, rule_subpattern, text_start); |
| 574 | + const uint8_t *subpattern_end = peg_rule(s, rule_subpattern, chunk_start); |
574 | 575 | up1(s);
|
575 | 576 | s->text_end = saved_end;
|
| 577 | + if (!subpattern_end) return NULL; /* Don't match anything */ |
576 | 578 |
|
577 |
| - if (!subpattern_end) { |
578 |
| - return NULL; |
579 |
| - } |
580 |
| - } while (separator_end); |
| 579 | + /* Ensure forward progress */ |
| 580 | + if (text == chunk_start) return NULL; |
| 581 | + chunk_start = text; |
| 582 | + } |
581 | 583 |
|
| 584 | + s->text_end = saved_end; |
582 | 585 | return s->text_end;
|
583 | 586 | }
|
584 | 587 |
|
|
0 commit comments