HN Debrief

Parsers don't have to be complicated

  • Programming
  • Developer Tools
  • Standards
  • Security

The post is a practical case for hand-written parsers. It shows a small scanner abstraction in C++ and uses it to parse simple text formats, with the broader claim that you do not need parser generators or elaborate theory for a lot of day-to-day work. That landed with plenty of sympathy. People generally agreed that for small formats under your control, direct parsing code is often easier to read, easier to debug, and fast enough that asymptotic performance is rarely the thing that hurts you.

If you are parsing a narrow, controlled format, a hand-written scanner is often the fastest path to something understandable and maintainable. If the input is internet-facing, spec-heavy, or user-authored, budget early for hostile inputs, diagnostics, and compliance work because that is where parser complexity actually comes from.

Discussion mood

Mostly positive on hand-written parsers for small, controlled formats, with skepticism toward the post’s broader framing. The mood turned critical around URL parsing edge cases, parser ergonomics, and the idea that line tracking alone makes error handling nearly free.

Key insights

  1. 01

    URL parsing gets hard at host and port

    The easy part is splitting a URI into scheme, authority, path, query, and fragment. The hard part starts when you interpret the authority field, because IPv6 literals use colons too. That means a parser that grabs the first colon as a port separator will misread valid inputs, which is exactly the kind of bug that turns a neat scanner into an incomplete URL parser.

    Treat URL parsing as layered work, not one scan. If you only need to decompose a URI, say that explicitly. If you need host and port semantics, use exhaustive tests for IPv6 and bracketed authorities or lean on a battle-tested library.

      Attribution:
    • quuxplusone #1
    • meindnoch #1
  2. 02

    Good diagnostics require recovery, not just positions

    Line and column tracking helps, but it does not produce useful errors by itself. Useful diagnostics come from recovery strategies, alternate parses, tombstone nodes in the abstract syntax tree, and heuristics that stop one mistake from exploding into ten fake errors later. The Rust examples made the point sharply. A parser can accept the syntax, yet the compiler still needs extra machinery to explain that the user probably meant a turbofish instead of chained comparisons.

    If users will write this format by hand, spend design effort on recovery and suggestions before polishing parser internals. A parser that only reports offsets will feel broken long before it feels slow.

      Attribution:
    • estebank #1 #2
    • tgv #1
    • spockz #1
  3. 03

    Real inputs force you to accept awkward conventions

    Parser complexity often comes from compatibility baggage, not algorithmics. Numbers get serialized as JSON strings to avoid precision loss in ecosystems that coerce numbers to double-precision floating point. HTML’s optional closing behavior is intentional, not accidental sloppiness. Once a format has multiple widely used interpretations, your parser has to choose whether it is enforcing a spec or surviving contact with production data.

    Write down your acceptance policy early. Decide which invalid-but-common cases you will normalize, which you will reject, and which need a compatibility mode so the parser does not quietly become the product’s garbage collector.

      Attribution:
    • imoverclocked #1
    • craftkiller #1
    • trashb #1
  4. 04

    Parsing speed is rarely the real bottleneck

    For human-scale inputs, even theoretically ugly parsing is often fast enough in practice. The more serious risk is adversarial behavior and what the system does after parsing, like allocating huge object graphs from untrusted JSON. That reframes parser choice. Complexity analysis still matters, but mostly when inputs are attacker-controlled or the parser sits on a hot network edge.

    Optimize parser performance only after checking whether parsing is actually on the critical path. Put more attention on worst-case behavior, input caps, and downstream allocation patterns when the parser faces the public internet.

      Attribution:
    • simonask #1 #2
    • nly #1

Against the grain

  1. 01

    Parser combinators can be simpler than scanners

    The post’s scanner style did not read as especially simple to several experienced readers. Compared with parser combinators like nom or combinator-based code that mirrors the grammar directly, the example looked ad hoc and harder to reason about. That undercuts the article’s implicit equation of “hand-written” with “clearer.” Sometimes the more declarative tool is the simpler one.

    Do not default to hand-rolled parsing just because the format is small. Prototype the grammar in a combinator library too and keep whichever version makes the structure and failure cases easier to see.

      Attribution:
    • mrkeen #1
    • aappleby #1
    • speedgoose #1
  2. 02

    The scanner API reads awkwardly in use

    The example API drew criticism for making simple conditions harder to read than they need to be. Expressions like checking whether accept returned a non-empty view force the reader to mentally invert the logic, and they throw away the very matched text used to justify the return type. That is a library design problem, not a parsing problem, but it weakens the claim that this style improves clarity.

    Judge parser helpers by call-site readability, not implementation cleverness. If basic matches require double negatives or empty-value checks, redesign the API before building more parsers on top of it.

      Attribution:
    • derdi #1
    • roaringrocky #1
    • alexjurkiewicz #1

In plain english

HTML
HyperText Markup Language, the standard markup language used to structure web pages.
INI
A simple configuration file format made of sections and key-value pairs, often used for app settings.
IPv6
Internet Protocol version 6, a newer internet addressing format that uses hexadecimal numbers and colons.
JSON
JavaScript Object Notation, a widely used text format for structured data exchange.
nom
A Rust parser combinator library for building parsers by composing smaller parsing functions.
turbofish
Rust syntax that writes type parameters explicitly after double colons, like `::<T>`, to disambiguate parsing.
URI
Uniform Resource Identifier, the standard general term for a web-style identifier such as a URL.
URL
Uniform Resource Locator, a kind of URI that identifies where a resource is located and how to access it.
YAML
YAML Ain't Markup Language, a human-oriented configuration and data serialization format with flexible syntax.

Reference links

Standards and specifications

  • RFC 3986 Appendix B
    Cited to show the standard regular expression for splitting a URI reference into major components.

Parser theory and techniques

  • Packrat Parsing paper
    Linked as a reference for linear-time parsing with memoization, in contrast to naive recursive descent with backtracking.
  • nom
    Recommended as a parser combinator library that can make complex parsing feel structured and enjoyable.
  • bablr grammar example
    Shared as an example of grammar expressed through function calls without code generation.

Implementation references and bug examples

Compiler diagnostics examples

  • Rust PR 159689
    Referenced as a concrete example of improving Rust diagnostics for missing turbofish syntax without changing the parser itself.
  • Rust PR 160592
    Linked as another example of lexer-level diagnostic work in Rust.

Related languages and projects

  • Felix language
    Mentioned as an example of a system that generates C++ and includes unusual language features, including grammar modification.
  • Felix tutorial
    Shared as a starting point for learning Felix after a side discussion about its features.

Data format edge cases