Page concepts parsers: Source version: Markbridge 0.4.2. These docs are built from the repository and may include unreleased changes. Source page: https://markbridge.dev/concepts/parsers/
# Parsers
> How the four parsers work and where they differ.
Each parser targets one input format but produces the same AST. They share philosophy (graceful degradation, bounded recursion) but not implementation.
## BBCode parser
**Path:** `Markbridge::Parsers::BBCode::Parser`
A hand-written, two-stage parser:
1. **Scanner** — streams the input and produces `TextToken`, `TagStartToken`, `TagEndToken`. Byte-offset based (`byteslice` / `byteindex` / `getbyte`, not character indices, which are O(n) on multibyte input), no regex except for character classes, minimal allocations.
2. **Parser** — consumes tokens through a `HandlerRegistry`. Each handler implements `on_open` / `on_close`. A `ParserState` tracks the node stack and enforces the max-depth limit (100).
**Unique to BBCode:** closing strategies. Real-world BBCode often has mismatched tags (`[b][i]text[/b][/i]`). A `ClosingStrategy` decides how to recover:
* `Strict` — auto-close only.
* `Reordering` (default) — reconciles sequences of up to 5 mismatched closing tags by peeking ahead.
**Handler API:** stateful. Handlers push/pop elements on the parser state stack via `on_open` / `on_close` callbacks.
## HTML parser
**Path:** `Markbridge::Parsers::HTML::Parser`
Thin wrapper over `Nokogiri::HTML.fragment` + a handler registry. Walks the DOM and dispatches each element to a handler.
**Handler API:** stateless — an object responding to `#process(element:, parent:)`. It adds an AST node to `parent` and returns either the node to descend into, or `nil` to skip children.
```ruby
class AsideHandler < Markbridge::Parsers::HTML::Handlers::BaseHandler
# Descend the children straight into the parent — no AST node for