# Selector Parser Implementation Notes

These are implementation notes for the [selector](./selectors.md) parser. For the design document, see [selector parser design](./brain_storming_selector_parsing.md). For [specificity](./specificity.md) calculation, see the specificity documentation.

## Scope

The selector parser will parse CSS-inspired selectors for the Wasot [event stream](./architecture.md) into an [Abstract Syntax Tree (AST)](./ast.md). This AST will later be used to match and select events from the stream. The parser will be implemented using the pest parser generator.

### In Scope for Initial Implementation

1. **Basic Selectors**
   - Universal selector: `*`
   - Type selector: `type-name` (e.g., `paragraph`, `quote`, `#` for headings)
   - ID selector: `#id` (e.g., `#123`)

2. **Argument Selectors**
   - Has argument: `[argument]` (positional or keyword)
   - Has not argument: `[!argument]`
   - Key-value match: `[key="value"]`

3. **Child Selectors (Pseudo-classes)**
   - `:first-child`, `:first-block`, `:first-text`
   - `:last-child`, `:last-block`, `:last-text`
   - `:nth-child(n)`, `:nth-block(n)`, `:nth-text(n)`
   - `:not(selector)` - negation

4. **Combinators**
   - Descendant: ` ` (space)
   - Child: `>`
   - Adjacent sibling: `+`
   - General sibling: `~`

5. **Grouping**
   - Multiple selectors: `selector1, selector2`

### Out of Scope for Initial Implementation

- Class selectors (`.class`) - not implemented in Wasot yet
- Advanced argument selectors: `[key~="value"]`, `[key^="value"]`, `[key$="value"]`, `[key*="value"]`
- Regex matchers
- Callback matchers

## AST Design

The AST should be designed to:
1. Represent the hierarchical structure of selectors
2. Support efficient traversal during event matching
3. Be serializable for potential caching/storage

### Core AST Node Types

```rust
#[derive(Debug, Clone, PartialEq)]
pub enum Selector {
    /// A compound selector with optional combinators
    Compound(CompoundSelector),
    /// A group of selectors (comma-separated)
    Group(Vec<Selector>),
}

#[derive(Debug, Clone, PartialEq)]
pub struct CompoundSelector {
    /// The simple selector at this level
    pub simple: SimpleSelector,
    /// Optional combinator and next selector
    pub combinator: Option<(Combinator, Box<CompoundSelector>)>,
}

#[derive(Debug, Clone, PartialEq)]
pub enum SimpleSelector {
    /// Matches any element
    Universal,
    /// Matches elements by type name
    Type(String),
    /// Matches elements by ID
    Id(String),
    /// Combination of selectors that must all match
    Sequence(Vec<SimpleSelector>),
}

#[derive(Debug, Clone, PartialEq)]
pub enum Combinator {
    /// Descendant (space)
    Descendant,
    /// Direct child (>)
    Child,
    /// Adjacent sibling (+)
    AdjacentSibling,
    /// General sibling (~)
    GeneralSibling,
}

#[derive(Debug, Clone, PartialEq)]
pub enum PseudoClass {
    FirstChild,
    FirstBlock,
    FirstText,
    LastChild,
    LastBlock,
    LastText,
    NthChild(i32),
    NthBlock(i32),
    NthText(i32),
    Not(Box<Selector>),
}

#[derive(Debug, Clone, PartialEq)]
pub enum AttributeSelector {
    /// [attr] - has attribute (positional or keyword)
    Has(String),
    /// [!attr] - does not have attribute
    HasNot(String),
    /// [key="value"] - exact match
    Equals(String, String),
}
```

## Pest Grammar Design

The pest grammar should handle:
1. Whitespace flexibility
2. Quoted strings in attribute selectors
3. Proper precedence for combinators
4. Grouping with commas

### Grammar Structure (conceptual)

```pest
// Main entry point
selector_list = { SOI ~ selector ~ ("," ~ selector)* ~ EOI }

// Individual selector
selector = { compound_selector }

// Compound selector with combinators
compound_selector = {
    simple_selector ~ (combinator ~ simple_selector)*
}

// Simple selectors
simple_selector = {
    universal_selector |
    id_selector |
    type_selector |
    attribute_selector |
    pseudo_class_selector |
    selector_sequence
}

// Selector sequence (multiple simple selectors together)
selector_sequence = {
    (type_selector | universal_selector)? ~
    (id_selector | attribute_selector | pseudo_class_selector)*
}

// Basic selectors
universal_selector = { "*" }
type_selector = { identifier }
id_selector = { "#" ~ identifier }

// Attribute selectors
attribute_selector = {
    "[" ~ ("!" ~ identifier | identifier ~ ("=" ~ quoted_string)?) ~ "]"
}

// Pseudo-class selectors
pseudo_class_selector = {
    ":" ~ (
        "first-child" | "first-block" | "first-text" |
        "last-child" | "last-block" | "last-text" |
        nth_selector |
        not_selector
    )
}

nth_selector = {
    ("nth-child" | "nth-block" | "nth-text") ~ "(" ~ number ~ ")"
}

not_selector = {
    "not" ~ "(" ~ selector ~ ")"
}

// Combinators
combinator = {
    descendant_combinator |
    child_combinator |
    adjacent_sibling_combinator |
    general_sibling_combinator
}

descendant_combinator = { WHITESPACE+ }
child_combinator = { ">" }
adjacent_sibling_combinator = { "+" }
general_sibling_combinator = { "~" }

// Lexical elements
identifier = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "-" | "_")* }
number = @{ ASCII_DIGIT+ }
quoted_string = @{ "\"" ~ (!"\"" ~ ANY)* ~ "\"" }

// Whitespace handling
WHITESPACE = _{ " " | "\t" | "\n" | "\r" }
```

## Implementation Plan

### Phase 1: Setup and Basic Infrastructure
1. Add pest and pest_derive dependencies to Cargo.toml
2. Create `src/selectors/` module structure
3. Define the pest grammar file (`selectors.pest`)
4. Create AST types in `src/selectors/ast.rs`

### Phase 2: Parser Implementation
1. Implement pest parser rules
2. Create parser module that converts pest pairs to AST
3. Add comprehensive error handling
4. Write unit tests for each selector type

### Phase 3: Integration
1. Create a facade API for parsing selectors
2. Add serialization support for AST (serde)
3. Performance optimization (if needed)
4. Documentation and examples

## Event Matching Considerations

While the parser only creates the AST, we should design it with the event matching phase in mind:

1. **Context Tracking**: The matcher will need to track:
   - Current element path (for descendant/child selectors)
   - Sibling relationships
   - Child indices and counts

2. **Efficient Matching**: Consider adding helper methods to AST nodes for:
   - Quick type/ID lookups
   - Argument presence checks
   - Pseudo-class evaluation

3. **Stream Processing**: The event-based nature means:
   - Cannot look ahead (for `:last-child` etc.)
   - May need to buffer some events
   - Must handle partial matching states

## Testing Strategy

1. **Unit Tests**: Test each selector type individually
2. **Integration Tests**: Test complex selector combinations
3. **Error Cases**: Invalid syntax, edge cases
4. **Performance Tests**: Large selector strings, deeply nested selectors
5. **Compatibility Tests**: Ensure CSS-like behavior where applicable

## Future Extensions

The design should allow for easy addition of:
1. More pseudo-classes
2. Advanced attribute selectors
3. Custom selector types specific to Wasot
4. Performance optimizations (e.g., selector compilation)

## Incremental Implementation Order

Based on CSS usage patterns and implementation complexity, here's the recommended order for implementing selectors. Each group builds upon the previous ones and provides a useful subset of functionality.

### Group 1: Essential Core (MVP)
**These are the absolute basics - the 20% that covers 80% of use cases**
- `type-name` - Type selector (e.g., `paragraph`, `quote`, `#`)
- ` ` (space) - Descendant combinator (e.g., `paragraph quote`)

**Rationale**: These two alone enable selecting specific block types and nested structures, covering the vast majority of simple queries.

### Group 2: Basic Targeting
**Adds precise element selection**
- `#id` - ID selector (e.g., `#123`)
- `>` - Child combinator (e.g., `paragraph > quote`)
- `,` - Grouping (e.g., `paragraph, quote`)

**Rationale**: ID selection enables linking/referencing specific blocks. Child combinator allows distinguishing direct children from deep descendants. Grouping reduces repetition.

### Group 3: Universal and Arguments
**Enables content-aware selection**
- `*` - Universal selector
- `[argument]` - Has argument selector
- `[key="value"]` - Key-value match

**Rationale**: Universal selector is trivial to implement and useful for "select all". Argument selectors are crucial for Wasot's argument system.

### Group 4: Basic Position Pseudo-classes
**Common structural selectors**
- `:first-child` - First child element
- `:last-child` - Last child element
- `[!argument]` - Has not argument

**Rationale**: First/last child are commonly used in CSS. The "has not" selector complements the "has" selector from Group 3.

### Group 5: Type-specific Position
**More precise structural selection**
- `:first-block` - First block child (ignoring text)
- `:last-block` - Last block child
- `:first-text` - First text child
- `:last-text` - Last text child

**Rationale**: Wasot distinguishes between blocks and text, so type-specific selectors are valuable.

### Group 6: Nth Selectors
**Advanced positional selection**
- `:nth-child(n)` - Nth child element
- `:nth-block(n)` - Nth block child
- `:nth-text(n)` - Nth text child

**Rationale**: Less common but powerful for specific positional queries.

### Group 7: Advanced Combinators
**Sibling relationships**
- `+` - Adjacent sibling (e.g., `paragraph + quote`)
- `~` - General sibling (e.g., `paragraph ~ quote`)

**Rationale**: Sibling selectors are less common but useful for sequential content patterns.

### Group 8: Negation
**Complex logic**
- `:not(selector)` - Negation pseudo-class

**Rationale**: Most complex to implement as it requires recursive selector parsing, but enables powerful exclusion patterns.

### Implementation Notes

1. **Start with Group 1**: Get the parser infrastructure working with just type selectors and descendant combinators.
2. **Add groups incrementally**: Each group should have comprehensive tests before moving to the next.
3. **Parser complexity grows**: Groups 1-3 are relatively simple. Groups 4-6 require tracking element positions. Groups 7-8 are the most complex.
4. **Event matcher considerations**: Some selectors (like `:last-child`) require buffering in the event stream processor.

### Usage Frequency (based on CSS patterns)

**Very High Usage** (implement first):
- Type selectors: `paragraph`
- Descendant: `paragraph quote`
- Child: `paragraph > quote`

**High Usage**:
- ID selectors: `#123`
- First/last child: `:first-child`, `:last-child`
- Grouping: `paragraph, quote`

**Medium Usage**:
- Attribute selectors: `[author]`, `[author="John"]`
- Universal: `*`
- Nth-child: `:nth-child(2)`

**Low Usage** (implement last):
- Sibling combinators: `+`, `~`
- Negation: `:not()`
- Type-specific positions: `:first-block`, etc.

## Dependencies

- `pest = "2.7"` - Parser generator
- `pest_derive = "2.7"` - Derive macros for pest
- Existing dependencies: serde for serialization

## File Structure

```
src/
├── selectors/
│   ├── mod.rs           # Module exports
│   ├── ast.rs           # AST type definitions
│   ├── parser.rs        # Pest parser implementation
│   ├── selectors.pest   # Pest grammar file
│   └── tests.rs         # Unit tests
```

## Example Usage

```rust
use wasot_compiler::selectors::parse_selector;

let selector = parse_selector("paragraph > quote[author=\"John\"] :first-child")?;
// Returns AST representing:
// - Type selector "paragraph"
// - Child combinator
// - Type selector "quote"
// - Attribute selector [author="John"]
// - Pseudo-class :first-child
```