Refactor Lookaround Assertions Using a Trait-Based Design #17

Closed
opened 2026-03-11 18:11:52 +03:00 by NiXTheDev · 0 comments
NiXTheDev commented 2026-03-11 18:11:52 +03:00 (Migrated from github.com)

Issue #16: Unify Lookaround Implementation with a Trait

Title: Refactor Lookaround Assertions Using a Trait-Based Design

Description:

**Goal**: Keep the matching logic modular and extensible when implementing lookahead/lookbehind.

The `ast.rs` already defines `Lookahead`, `NegativeLookahead`, etc. When implementing them in `engine.rs`, consider using a trait for assertions to avoid cluttering the main matching loop.

**Proposed Design**:
Define a trait `Assertion` that can evaluate whether the assertion holds at a given position, possibly consuming input or not. Then each assertion type (lookahead, lookbehind, word boundary) implements this trait.

**Example**:
```rust
trait Assertion {
    fn matches(&self, engine: &NfaSimulator, pos: usize) -> bool;
}

struct LookaheadAssertion {
    inner: Nfa,
    negated: bool,
}

impl Assertion for LookaheadAssertion {
    fn matches(&self, engine: &NfaSimulator, pos: usize) -> bool {
        // Run inner NFA from current position without consuming input
        let result = engine.run_internal_nfa(&self.inner, pos);
        if self.negated { !result } else { result }
    }
}

Then in the main NFA simulation, when encountering an assertion transition, call the assertion's matches method.

Benefits:

  • Clean separation of concerns.
  • Easier to add new assertion types (e.g., atomic groups, conditionals) later.
--- #### Issue #16: Unify Lookaround Implementation with a Trait **Title:** Refactor Lookaround Assertions Using a Trait-Based Design **Description:** ```md **Goal**: Keep the matching logic modular and extensible when implementing lookahead/lookbehind. The `ast.rs` already defines `Lookahead`, `NegativeLookahead`, etc. When implementing them in `engine.rs`, consider using a trait for assertions to avoid cluttering the main matching loop. **Proposed Design**: Define a trait `Assertion` that can evaluate whether the assertion holds at a given position, possibly consuming input or not. Then each assertion type (lookahead, lookbehind, word boundary) implements this trait. **Example**: ```rust trait Assertion { fn matches(&self, engine: &NfaSimulator, pos: usize) -> bool; } struct LookaheadAssertion { inner: Nfa, negated: bool, } impl Assertion for LookaheadAssertion { fn matches(&self, engine: &NfaSimulator, pos: usize) -> bool { // Run inner NFA from current position without consuming input let result = engine.run_internal_nfa(&self.inner, pos); if self.negated { !result } else { result } } } ``` Then in the main NFA simulation, when encountering an assertion transition, call the assertion's `matches` method. **Benefits**: - Clean separation of concerns. - Easier to add new assertion types (e.g., atomic groups, conditionals) later.
Sign in to join this conversation.
No description provided.