Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
b8bd4df
Re-emit branch_point captures on fail-retry
stefanobaghino Apr 20, 2026
1ee0e3c
Decrement Haskell syntest baseline after capture re-emit fix
stefanobaghino Apr 20, 2026
b8e4936
Fix MSRV rustfmt and docs broken intra-doc links
stefanobaghino Apr 20, 2026
c183165
Restore cleared scopes before Pop on pop: N + set: X
stefanobaghino Apr 20, 2026
d1200b3
Clip captures: N span to rule's match bounds
stefanobaghino Apr 21, 2026
cd23cc9
Suppress cur meta_scope on pop: N + embed: match text
stefanobaghino Apr 21, 2026
e9c022a
Drain orphan scope atoms on outer escape fire
stefanobaghino Apr 22, 2026
b185a2c
Order apply_prototype external prototype before target main
stefanobaghino Apr 22, 2026
69cd4b3
Cover apply_prototype external-prototype precedence
stefanobaghino Apr 23, 2026
347ea76
Drop HAML-Rails from syntest baselines
stefanobaghino Apr 23, 2026
17e46c4
Wrap past-EOL syntest assertions to next-line scopes
stefanobaghino Apr 23, 2026
b1b5438
Dedup flushed_ops across multi-fail parse_line calls
stefanobaghino Apr 23, 2026
78da6c4
Anchor replay-born branches to their replay line
stefanobaghino Apr 23, 2026
715a68e
Inherit outer prefix in replay-born branch_points
stefanobaghino Apr 25, 2026
7706736
Refresh post-replay shadow and stack_before snapshots
stefanobaghino Apr 25, 2026
d31dbe3
Subtract bp.pop_count in branch_point retain predicate
stefanobaghino Apr 26, 2026
d4a7e05
Route handle_fail cross-line re-emit through push_meta_ops
stefanobaghino Apr 26, 2026
82703dc
Save flushed_ops before cross-line replay loop and prefer inner corre…
stefanobaghino Apr 26, 2026
f3e497a
Fall through to parent on branch_point exhaustion
stefanobaghino Apr 27, 2026
ed949e4
Restore cleared scopes before deeper pops in pop:N
stefanobaghino Apr 27, 2026
0a2139a
Skip inner replay correction when nested deeper than outer BP
stefanobaghino Apr 27, 2026
d36dc01
Treat pop:N + push:X as Set with pop_count=N
stefanobaghino Apr 27, 2026
b31b727
Skip cur mcs Pop in Set when wrapper has embed_scope_replaces
stefanobaghino Apr 27, 2026
4bd9272
Defer target Clear in single-context Set when cur has meta_scope
stefanobaghino Apr 27, 2026
96ae959
Drop extra parent mcs on trigger of multi-set + target clear+ms
stefanobaghino Apr 27, 2026
aca11f5
Restore deeper frame clear_scopes on pop:N + set:
stefanobaghino Apr 27, 2026
61a796e
Drop python_strings.py from syntest baselines
stefanobaghino Apr 27, 2026
3b44840
Skip embed_scope_replaces for fragment embeds
stefanobaghino Apr 27, 2026
d4b6a5b
Drop python.py from syntest baselines
stefanobaghino Apr 27, 2026
72f5ac0
Prefer own over inherited in multi-extends parent merge
stefanobaghino Apr 28, 2026
172a697
Skip non-pure assertion lines in the syntest harness
stefanobaghino Apr 28, 2026
230faae
Bypass search cache on truncated searches at embed-escape boundary
stefanobaghino Apr 28, 2026
02ac40d
Apply non-topmost set target's clear_scopes at trigger position
stefanobaghino Apr 28, 2026
c432a0c
Defer LRD blank-line pop to next-line baseline
stefanobaghino Apr 28, 2026
6ca4ebd
Treat shebang header tail as testtoken_end in syntest harness
stefanobaghino Apr 28, 2026
1a83739
Un-ignore embed wrapper-mcs test; CI checks out the submodule
stefanobaghino Jul 11, 2026
79ae5fd
Merge branch '631-fragment-embed-skip-replaces' into 631-multi-extend…
stefanobaghino Jul 11, 2026
9b8b713
Merge branch '631-markdown-fence-embed-scope-token-drop' into 631-bas…
stefanobaghino Jul 11, 2026
f8f0501
Merge branch '631-bash-tilde-meta-scope-leak' into 631-php-multi-set-…
stefanobaghino Jul 11, 2026
11b84a2
Merge branch '631-php-multi-set-target-clear-extra-mcs-drop' into 631…
stefanobaghino Jul 11, 2026
1ce1d05
Merge branch '631-pop-n-set-deeper-clear-scopes-restore' into 631-fra…
stefanobaghino Jul 11, 2026
2048676
Un-ignore zsh-for-markdown shebang test; CI has the submodule
stefanobaghino Jul 11, 2026
ff67ac4
Merge branch '631-zsh-range-clear-parent-string-scope' into 631-markd…
stefanobaghino Jul 11, 2026
d8bd7d2
Merge branch '631-multi-extends-own-beats-inherited' into 631-syntest…
stefanobaghino Jul 11, 2026
f2a0dea
Merge branch '631-syntest-non-pure-assertion-gating' into 631-clip-lo…
stefanobaghino Jul 11, 2026
b872bfa
Merge branch '631-clip-lookahead-at-embed-escape' into 631-zsh-range-…
stefanobaghino Jul 11, 2026
39f3a17
Un-ignore LRD blank-line test; CI has the submodule
stefanobaghino Jul 11, 2026
78498a6
Merge branch '631-markdown-lrd-blank-line' into 631-syntest-shebang-t…
stefanobaghino Jul 11, 2026
02210d7
Un-ignore the 630-era submodule tests too; CI has the submodule
stefanobaghino Jul 11, 2026
6fa70b9
Merge branch '631-markdown-fence-embed-scope-token-drop' into 631-bas…
stefanobaghino Jul 11, 2026
d2efa94
Merge branch '631-bash-tilde-meta-scope-leak' into 631-php-multi-set-…
stefanobaghino Jul 11, 2026
eea01f4
Merge branch '631-php-multi-set-target-clear-extra-mcs-drop' into 631…
stefanobaghino Jul 11, 2026
5944f95
Merge branch '631-pop-n-set-deeper-clear-scopes-restore' into 631-fra…
stefanobaghino Jul 11, 2026
e298261
Merge branch '631-fragment-embed-skip-replaces' into 631-multi-extend…
stefanobaghino Jul 11, 2026
e96f99f
Merge branch '631-multi-extends-own-beats-inherited' into 631-syntest…
stefanobaghino Jul 11, 2026
f954cb1
Merge branch '631-syntest-non-pure-assertion-gating' into 631-clip-lo…
stefanobaghino Jul 11, 2026
bad01ab
Merge branch '631-clip-lookahead-at-embed-escape' into 631-zsh-range-…
stefanobaghino Jul 11, 2026
4426958
Merge branch '631-zsh-range-clear-parent-string-scope' into 631-markd…
stefanobaghino Jul 11, 2026
e72786d
Merge branch '631-markdown-lrd-blank-line' into 631-syntest-shebang-t…
stefanobaghino Jul 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified assets/default_newlines.packdump
Binary file not shown.
Binary file modified assets/default_nonewlines.packdump
Binary file not shown.
430 changes: 339 additions & 91 deletions examples/syntest.rs

Large diffs are not rendered by default.

3,255 changes: 3,072 additions & 183 deletions src/parsing/parser.rs

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions src/parsing/regex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,4 +345,27 @@ mod tests {
let back_to_str = serde_json::to_string(&pattern).unwrap();
assert_eq!(back_to_str, "\"just a string\"");
}

// The parser uses `end < text.len()` to clip a search at an embed-escape
// boundary. Negative lookaheads inside the embedded context's rules must
// treat the boundary as effective end-of-input — otherwise patterns like
// `done(?!cmd_char)` fail when `done` is immediately followed by the
// closing escape glyph (e.g. `` `for...done` `` in shell).
#[test]
fn search_clips_lookahead_at_end() {
let regex = Regex::new(String::from(r"done(?!X)"));
let mut region = Region::new();
let matched = regex.search("doneX", 0, 4, Some(&mut region), true);
assert!(matched, "lookahead must not see byte at index 4");
assert_eq!(region.pos(0), Some((0, 4)));
}

// Sanity check: when not clipped, the same lookahead correctly fails.
#[test]
fn search_lookahead_fails_when_unclipped() {
let regex = Regex::new(String::from(r"done(?!X)"));
let mut region = Region::new();
let matched = regex.search("doneX", 0, 5, Some(&mut region), true);
assert!(!matched, "lookahead must see the X when end == text.len()");
}
}
11 changes: 7 additions & 4 deletions src/parsing/syntax_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,17 +274,20 @@ impl<'a> Iterator for MatchIter<'a> {
_ => return self.next(),
};
let ctx_ptr = self.syntax_set.get_context(context_id).unwrap();
// Also include the external syntax's prototype if the context allows it
// Push target first, then external prototype on top so
// its patterns are iterated first: `MatchIter::next`
// reads the stack top, and ST's `apply_prototype` runs
// the prototype ahead of the included context — mirror
// of `ParseState::find_best_match`'s prototype chaining.
self.ctx_stack.push(ctx_ptr);
self.index_stack.push(0);
if ctx_ptr.meta_include_prototype.unwrap_or(true) {
if let Some(ref proto_id) = ctx_ptr.prototype {
let proto_ctx = self.syntax_set.get_context(proto_id).unwrap();
// Push prototype first (it will be iterated first)
self.ctx_stack.push(proto_ctx);
self.index_stack.push(0);
}
}
self.ctx_stack.push(ctx_ptr);
self.index_stack.push(0);
}
}
} else {
Expand Down
Loading