Module

parser

Recursive descent parser producing typed AST.

Consumes token stream from Lexer and builds typed AST nodes. Produces immutable (frozen) dataclass nodes for thread-safety.

Architecture:

The parser uses a mixin-based design for separation of concerns:

  • TokenNavigationMixin: Token stream traversal
  • InlineParsingMixin: Inline content (emphasis, links, code spans)
  • BlockParsingMixin: Block-level content (paragraphs, lists, tables)

Thread Safety:

  • Parser produces immutable AST (frozen dataclasses)
  • Configuration is read from ContextVar (thread-local)
  • Safe to share AST across threads

Classes

Parser 14 ▼
Recursive descent parser for Markdown. Consumes tokens from Lexer and builds typed AST. A…

Recursive descent parser for Markdown.

Consumes tokens from Lexer and builds typed AST.

Architecture:
    Uses mixin inheritance to separate concerns while maintaining
    a single entry point. Each mixin handles one aspect of the grammar:
  • TokenNavigationMixin: Token stream access, advance, peek

  • InlineParsingMixin: Emphasis, links, code spans, etc.

  • BlockParsingMixin: Lists, tables, code blocks, directives, etc.

    Usage:

    >> parser = Parser("# Hello

    World")

    >> ast = parser.parse() >> ast[0]

    Heading(level=1, children=(Text(content='Hello'),), ...)
    

    Thread Safety:

    Parser instances are single-use and not thread-safe. Create one per
    
    parse operation. Configuration is read from ContextVar (thread-local).
    
    The resulting AST is immutable and thread-safe.
    

    Configuration:

    Parser reads configuration from ContextVar instead of instance attributes.
    
    This provides:
    
  • 12 slots vs 18 before (config via ContextVar)

  • Faster instantiation (no config copying)

  • Automatic config inheritance for sub-parsers

  • Thread-safe by design

Methods

parse 0 Sequence[Block] ▼
Parse source into AST blocks. **Thread Safety:** Returns immutable AST (frozen…
def parse(self) -> Sequence[Block]

Parse source into AST blocks.

Thread Safety: Returns immutable AST (frozen dataclasses).

Returns
Sequence[Block] Sequence of Block nodes
Internal Methods 13 ▼
_config 0 ParseConfig ▼
Get current parse configuration (cached for parse duration).
property
def _config(self) -> ParseConfig
Returns
ParseConfig
_tables_enabled 0 bool ▼
Whether GFM table parsing is enabled.
property
def _tables_enabled(self) -> bool
Returns
bool
_strikethrough_enabled 0 bool ▼
Whether ~~strikethrough~~ syntax is enabled.
property
def _strikethrough_enabled(self) -> bool
Returns
bool
_task_lists_enabled 0 bool ▼
Whether - [ ] task list items are enabled.
property
def _task_lists_enabled(self) -> bool
Returns
bool
_footnotes_enabled 0 bool ▼
Whether [^ref] footnote references are enabled.
property
def _footnotes_enabled(self) -> bool
Returns
bool
_math_enabled 0 bool ▼
Whether $inline$ and $$block$$ math is enabled.
property
def _math_enabled(self) -> bool
Returns
bool
_autolinks_enabled 0 bool ▼
Whether automatic URL linking is enabled.
property
def _autolinks_enabled(self) -> bool
Returns
bool
_directive_registry 0 DirectiveRegistry | None ▼
Registry for directive handlers.
property
def _directive_registry(self) -> DirectiveRegistry | None
Returns
DirectiveRegistry | None
_strict_contracts 0 bool ▼
Whether to raise errors on directive contract violations.
property
def _strict_contracts(self) -> bool
Returns
bool
_text_transformer 0 Callable[[str], str] | N… ▼
Optional callback to transform plain text lines.
property
def _text_transformer(self) -> Callable[[str], str] | None
Returns
Callable[[str], str] | None
__init__ 2 ▼
Initialize parser with source text. Configuration is read from ContextVar, not…
def __init__(self, source: str, source_file: str | None = None) -> None

Initialize parser with source text.

Configuration is read from ContextVar, not passed as parameters. Use set_parse_config() or parse_config_context() before creating a Parser if you need non-default configuration.

Parameters
Name Type Description
source —

Markdown source text

source_file —

Optional source file path for error messages

Default:None
_reinit 2 ▼
Reinitialize parser for reuse (enables pooling). Resets all per-parse state wh…
def _reinit(self, source: str, source_file: str | None = None) -> None

Reinitialize parser for reuse (enables pooling).

Resets all per-parse state while keeping the instance allocated. This enables frameworks like Bengal to pool Parser instances and avoid allocation overhead for high-volume parsing.

Thread Safety: Parser instances are single-use per thread. Pooling is thread-local.

Parameters
Name Type Description
source —

New Markdown source text

source_file —

Optional source file path for error messages

Default:None
_parse_nested_content 3 tuple[Block, ...] ▼
Parse nested content as blocks (for block quotes, list items). Creates a sub-p…
def _parse_nested_content(self, content: str, location: SourceLocation, *, allow_setext_headings: bool = True) -> tuple[Block, ...]

Parse nested content as blocks (for block quotes, list items).

Creates a sub-parser to handle nested block-level content. Configuration is automatically inherited via ContextVar—no copying needed!

Thread Safety: Sub-parser reads config from the same ContextVar as parent, ensuring consistent configuration without manual copying.

Parameters
Name Type Description
content —

The markdown content to parse as blocks

location —

Source location for error reporting

allow_setext_headings —

If False, disable setext heading detection (used for blockquote content with lazy continuation lines)

Default:True
Returns
tuple[Block, ...] Tuple of Block nodes