Skip to content

Parsing Architecture & Tree-sitter Usage ​

HTTPX parses two fundamentally different kinds of input with two different engines. This page documents where each lives and why.

Tree-sitter usage ​

HTTPX uses Tree-sitter internally for structured-text edit vocabulary (points, ranges, text edits) shared by the document/template/watcher pipeline, so a future grammar can plug in without changing call sites.

Tree-sitter is intentionally hidden from the normal HTTPX API: user code only needs @import("httpx"). Each parsing module imports the treesitter dependency directly where Tree-sitter is the parsing foundation (no shared wrapper): src/parsing/html.zig (HTML grammar), src/parsing/xml.zig (XML grammar), src/parsing/feed.zig (JSON grammar), src/parsing/document.zig (incremental edits, queries), src/web/templates/parser.zig (template grammar), and src/web/watcher/reload.zig + src/web/watcher/backend.zig (incremental analysis and event intake).

Used by:

  • Templates — edit descriptors for development invalidation (Document.computeEdit, consumed by the dev watcher flow)
  • HTML/document parsing — source positions for incremental updates
  • Incremental development parsing — offsets/points shared with the watcher
  • JSON Feed — syntax layer: the bundled JSON grammar parses the document into a syntax tree (feed.zig maps it onto feed semantics; malformed input fails closed, escapes/surrogates decode per RFC 8259)

Not used for:

  • HTTP wire parsing
  • HTTP/2 frames
  • HTTP/3 frames
  • QUIC
  • TLS
  • DNS wire format
  • WebSocket frames
  • FTP wire protocol
  • compression
  • other binary/protocol parsing

Why native parsers remain ​

The installed treesitter-0.0.1 dependency ships exactly four grammars: arithmetic expressions, s-expressions, JSON, and an indentation outline demo, so HTTPX defines first-class HTML, XML, and template grammars on top of the Tree-sitter runtime: htmlLanguage in src/parsing/html.zig, xmlLanguage in src/parsing/xml.zig, and templateLanguage in src/web/templates/parser.zig. Syntax tokens and ranges come from the syntax tree, while tag matching, DOM building, and template nesting/AST semantics stay in HTTPX. JSON value decoding stays on std.json; structural consumers are JSON Feed and templates (syntax tree + positions from the grammar, field/AST mapping in HTTPX). Tiny line-oriented formats (robots.txt, sitemap) and small recursive-descent languages (GraphQL, route patterns, selectors) are objectively simpler, faster, and lower-allocation as specialized native parsers.

Grammar inventory ​

GrammarShips in depHTTPX consumerReason
Arithmetic expressionsYes (demo)NoneDemo grammar; template expressions are paths/filters, not arithmetic
S-expressionsYes (demo)NoneNo s-expression input in HTTPX
JSONYesFeed (JSON Feed syntax layer)Only shipped grammar with an HTTPX consumer; value decoding stays std.json
Outline (indent demo)Yes (demo)NoneDemo only
HTMLNo—Native parser retained
Templates ({{ }}, {% %}, {# #})HTTPX-defined (templateLanguage)Templates (syntax layer)Tree-sitter tokenizes; nesting/AST stays in HTTPX
CSS selectorsNo—Native parser retained
GraphQLNo—Native spec-driven parser retained
OpenAPI/YAMLNo—Generation from router metadata + std.json; retained

Parser decision matrix ​

ComponentCurrent parserTree-sitterDecisionReason
TemplatesTree-sitter syntax tokens + HTTPX AST (web/templates/parser.zig)YesIntegratedGrammar tokenizes text/expression/directive/comment; nesting stays native
HTMLnative tokenizer + DOM (parsing/html.zig, dom.zig)No grammarKeep nativeNo HTML grammar ships; streaming + arena DOM fits serving
DOMbuilt from native HTML parseNoKeep nativeSingle representation already; no second tree
Documentnative HTML + computeEdit vocabularyVocabulary onlyKeep nativeEdit descriptors shared with watcher; no grammar to parse with
Selectorsnative CSS-selector parser (parsing/selector.zig)NoKeep nativeTiny grammar; dedicated parser is faster/simpler
ExtractionDOM traversal (parsing/extract.zig)NoKeep nativeOperates on the single DOM; no reparse
JSONstd.json for valuesStructural for feedsValues decode via std; feed documents parse via the grammar
XMLnative streaming parser (parsing/xml.zig)NoKeep nativeStreaming fits feeds; no XML grammar ships
Feed (RSS/Atom)native over XML/DOMNoKeep nativeThin layer over retained parsers
Feed (JSON)Tree-sitter JSON syntax + HTTPX semanticsYesIntegratedGrammar fits; replaces a stub that ignored its input
Robots.txtnative line parser (parsing/robots.zig)NoKeep nativeLine-oriented; Tree-sitter is overkill
Sitemapnative XML-backed parser (parsing/sitemap.zig)NoKeep nativeSame as XML/feeds
GraphQLnative lexer + recursive descent (web/graphql/)NoKeep nativeSpec-driven with depth/complexity limits; no GraphQL grammar ships
OpenAPIbuilt from router metadata + std.jsonNoKeep nativeGeneration, not parsing; no grammar needed
Router patternsnative segment parser (web/router/pattern.zig)NoKeep nativeTrivial syntax ({param}, *wild); overhead unjustified
URI/URLnative (common/uri.zig)NoKeep nativeNot a Tree-sitter domain
HTTP/1.xnative wire parserNoKeep nativeBinary/protocol parsing
HTTP/2 (frames/HPACK)nativeNoKeep nativeBinary/protocol parsing
HTTP/3/QUICnativeNoKeep nativeBinary/protocol parsing
TLS/DNS/WS/FTPnativeNoKeep nativeBinary/protocol parsing
Multipartnative boundary parserNoKeep nativeWire format parsing
Compressionbrotli/zstd deps + stdNoKeep deps/stdCodec domain, not parsing

Released under the MIT License.