Skip to content

Parse errors carry line/column + context snippet - #3

Merged
conorbronsdon merged 2 commits into
mainfrom
error-positions
Jul 8, 2026
Merged

Parse errors carry line/column + context snippet#3
conorbronsdon merged 2 commits into
mainfrom
error-positions

Conversation

@conorbronsdon

Copy link
Copy Markdown
Owner

Adds position info to parse errors, replacing flat error strings. This establishes the error-reporting pattern for the sibling mojo-* parser libraries.

New module: src/xml/errors.mojo (exported from the package)

  • line_col(source: Span[UInt8, _], offset: Int) -> Tuple[Int, Int] — 1-based line and column from a byte offset. Column is the 1-based byte offset within the line (no UTF-8 decode: cheap and deterministic even on invalid input). Clamps out-of-range offsets; only LF terminates a line, so CRLF contributes no phantom column.
  • parse_error(msg: String, source: Span[UInt8, _], offset: Int) -> Error — message is exactly <msg> at line <L>, column <C>: '<snippet>', where the snippet is a ~30-byte whitespace-trimmed window of the offending line centered on the column, with ... where truncated, window edges nudged off UTF-8 continuation bytes, never multi-line.

Wiring

Every pull-parser raise site with a genuine byte offset now reports position + snippet: all strict-mode errors (previously a bare (line L, column C) suffix, no snippet) and the structural errors both modes raise (previously no position at all) — unterminated construct / start tag / attribute / attribute value, unquoted attribute value, malformed start/end tag, empty element name. Raise sites with no offset available (encoding sniff, entity-expansion guard, all DOM-level etree errors — events carry no offsets) are left untouched. Error mechanism unchanged: still raise Error(...), no new error types.

Verification

  • 23 new tests in test/test_errors.mojo: line_col edge cases (offset 0, at-newline, past-end, empty source, CRLF, consecutive newlines), exact parse_error message formats including truncation and UTF-8-boundary behavior, and 3 hand-verified malformed-XML integration positions.
  • Full suite green: 61 pull + 74 etree + 23 errors; CPython xml.etree anchor 14/14 matched; short fuzz run 0 crashes / 0 hangs; mojo format clean.

🤖 Generated with Claude Code

New src/xml/errors.mojo (exported from the package):

- line_col(source: Span[UInt8, _], offset: Int) -> Tuple[Int, Int] —
  1-based line and column from a byte offset; the column is the 1-based
  BYTE offset within the line (no UTF-8 decode, deterministic). Clamps
  out-of-range offsets; only LF terminates a line, so CRLF adds no
  phantom column.
- parse_error(msg, source, offset) -> Error — message is exactly
  "<msg> at line <L>, column <C>: <snippet>" with the snippet a ~30-byte
  whitespace-trimmed window of the offending line centered on the
  column, ... where truncated, nudged off UTF-8 continuation bytes,
  never multi-line.

Wired into every pull-parser raise site with a genuine byte offset:
strict errors (previously a bare parenthesized location, no snippet)
and the liberal-mode structural errors (previously no position):
unterminated construct/start tag/attribute/attribute value, unquoted
attribute value, malformed start/end tag, empty element name. Error
mechanism unchanged — still raise Error(...).

23 new tests (line_col edge cases, exact parse_error formats, 3
hand-verified malformed-XML integration positions); suite now
61 pull + 74 etree + 23 errors, anchor + short fuzz green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@conorbronsdon
conorbronsdon merged commit 9a014b3 into main Jul 8, 2026
1 check passed
@conorbronsdon
conorbronsdon deleted the error-positions branch July 8, 2026 04:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant