Summary
Lua.Parser computes rich, structured error information internally but only exposes it as a pre-formatted display string. Tooling that wants to render parse errors in its own UI (editors, LSPs, web frontends, custom CLIs) currently has to scrape that display string back apart with regexes. It would be great to get the structured error directly.
Current state
Lua.parse_chunk/1 and Lua.Parser.parse/1 return {:error, [String.t()]} / {:error, String.t()} — an ANSI-formatted, human-facing string.
Lua.Parser.parse_raw/1 returns {:error, term()}, but that term is the raw internal tuple (e.g. {:unexpected_token, type, pos, message}) from before error conversion — not a stable, documented shape to match against.
Lua.Parser.Error is a well-formed struct (type, message, position: %{line, column}, suggestion, source_lines, related), and parse/1 already builds it via a private convert_error/2 — then immediately stringifies it with Error.format/2 and discards the struct. There's no public way to obtain it.
Lua.Parser.Error has constructors and format/2 / format_multiple/2, but no to_map/1.
Lua.VM.ErrorFormatter.to_map/3 exists, but it's oriented at VM/runtime errors: it takes (error_type, message, opts) and requires the caller to supply message/line/source themselves, so it isn't a parser-error consumer. It also hardcodes source_context.pointer_column to 1 even though the parser knows the real column via position.column.
The net effect: the structured data is computed and thrown away, and the only way to recover it is to parse the formatted string.
Proposal
-
A public way to obtain the structured error — either:
- a new
Lua.Parser.parse_structured/1 (and/or Lua.parse_chunk_structured/1) returning {:ok, Chunk.t()} | {:error, [%Lua.Parser.Error{}]}, or
- have
parse_raw/1 return the converted %Lua.Parser.Error{} rather than the raw internal tuple.
-
Lua.Parser.Error.to_map/1 (or /2 with the source) that emits a JSON-serializable map — ideally the same wire shape as Lua.VM.ErrorFormatter.to_map/3 (type, message, source, line, source_context: %{lines, pointer_column}, suggestion) so runtime and parse errors can share a single renderer. The struct already holds everything needed.
-
Bonus: populate source_context.pointer_column from position.column when available, so the ^ marker points at the real column instead of always column 1.
Why
Consumers that surface errors in a non-terminal UI want the structured fields (location, message, suggestion, source context) directly. Today the choice is "scrape the formatted string" (brittle — coupled to the display layout) or "match parse_raw/1's raw tuples" (coupled to internal parser representation). A documented struct + to_map would give a stable contract for both, and would let runtime and parse errors flow through one rendering path.
Happy to send a PR if this direction sounds good.
Summary
Lua.Parsercomputes rich, structured error information internally but only exposes it as a pre-formatted display string. Tooling that wants to render parse errors in its own UI (editors, LSPs, web frontends, custom CLIs) currently has to scrape that display string back apart with regexes. It would be great to get the structured error directly.Current state
Lua.parse_chunk/1andLua.Parser.parse/1return{:error, [String.t()]}/{:error, String.t()}— an ANSI-formatted, human-facing string.Lua.Parser.parse_raw/1returns{:error, term()}, but thattermis the raw internal tuple (e.g.{:unexpected_token, type, pos, message}) from before error conversion — not a stable, documented shape to match against.Lua.Parser.Erroris a well-formed struct (type,message,position: %{line, column},suggestion,source_lines,related), andparse/1already builds it via a privateconvert_error/2— then immediately stringifies it withError.format/2and discards the struct. There's no public way to obtain it.Lua.Parser.Errorhas constructors andformat/2/format_multiple/2, but noto_map/1.Lua.VM.ErrorFormatter.to_map/3exists, but it's oriented at VM/runtime errors: it takes(error_type, message, opts)and requires the caller to supplymessage/line/sourcethemselves, so it isn't a parser-error consumer. It also hardcodessource_context.pointer_columnto1even though the parser knows the real column viaposition.column.The net effect: the structured data is computed and thrown away, and the only way to recover it is to parse the formatted string.
Proposal
A public way to obtain the structured error — either:
Lua.Parser.parse_structured/1(and/orLua.parse_chunk_structured/1) returning{:ok, Chunk.t()} | {:error, [%Lua.Parser.Error{}]}, orparse_raw/1return the converted%Lua.Parser.Error{}rather than the raw internal tuple.Lua.Parser.Error.to_map/1(or/2with the source) that emits a JSON-serializable map — ideally the same wire shape asLua.VM.ErrorFormatter.to_map/3(type,message,source,line,source_context: %{lines, pointer_column},suggestion) so runtime and parse errors can share a single renderer. The struct already holds everything needed.Bonus: populate
source_context.pointer_columnfromposition.columnwhen available, so the^marker points at the real column instead of always column 1.Why
Consumers that surface errors in a non-terminal UI want the structured fields (location, message, suggestion, source context) directly. Today the choice is "scrape the formatted string" (brittle — coupled to the display layout) or "match
parse_raw/1's raw tuples" (coupled to internal parser representation). A documented struct +to_mapwould give a stable contract for both, and would let runtime and parse errors flow through one rendering path.Happy to send a PR if this direction sounds good.