Syntax.Report
Caret rendering for Syntax.Diagnostic: the plain-text report the compiler prints for a refused source.
It is rebuilt in Prism from the diagnostic and the source text alone. The target is exact bytes, not a lookalike, so the layout below is an executable specification of the compiler’s renderer: the header line, the location line, the gutter, the source line with tabs expanded to four-column stops, the underline row, the arrow row carrying the label, and the closing rule. Syntax.Diagnostic supplies the data; this module is the only thing in Prism that can draw it.
The shape reproduced is one primary span drawn as a caret under one source line, which is every diagnostic the syntax boundary raises: a lexical fault is a zero-width caret at its offset, and a parse fault is the offending token’s span or a caret at end of input. rp_exact is the predicate for that shape and rp_report answers None outside it rather than guessing. Three things fall outside.
A span crossing a line boundary, reachable through a multi-line string literal, draws the compiler’s multi-line form instead: an arrow down the margin from the opening line to the closing one. That form is not implemented.
Several labels on one report, and the help and note trailers, belong to the structured type-error path rather than the syntax boundary. related is a reserved surface on Diagnostic and nothing populates it yet, so a second label has no source here to draw from.
A non-ASCII byte at or before the end of the diagnostic’s own line changes the answer, and there the compiler’s output is the right one: it draws one cell per character, while every column here is counted in bytes, so a two-byte character before the caret pulls this module’s caret one cell further right. Counting characters would mean carrying a decoder the rest of the module has no use for, so the predicate below declines those lines instead.
Functions and Values
rp_kind
rp_kind : (Syntax.Diagnostic.DiagPhase) -> String
The report-kind label the compiler stamps in the header for a phase.
rp_kind(DPLex)
Lexical Error
rp_label
rp_label : (Syntax.Diagnostic.Diagnostic) -> String
The text on the caret’s label. The end-of-input parse fault asks for more input; every other diagnostic points here.
rp_message
rp_message : (String, Syntax.Diagnostic.Diagnostic) -> String
The message on the header line. A parse fault’s message already carries its own position; a lexical fault’s is followed by the line and column of its caret.
rp_exact
rp_exact : (String, Syntax.Diagnostic.Diagnostic) -> Bool
Whether the compiler draws this diagnostic as one caret under one source line, the shape this module reproduces byte for byte. False for a span that crosses a line boundary, a span running past the end of the text, and a source carrying a non-ASCII byte at or before the end of the caret’s line.
rp_report
rp_report : (String, String, Syntax.Diagnostic.Diagnostic) -> Option(String)
The compiler’s plain-text report for one diagnostic, or None when the diagnostic falls outside the shape this module draws (see rp_exact). name is the source name in the location line; the compiler passes <source> when reporting on a single file. The result ends with a newline.
let d = Diagnostic {
code = "E7100",
phase = DPParse,
span = Span { lo = 12, hi = 13 },
message = "unexpected ')'",
expected = Nil,
related = Nil
}
print(unwrap_or("", rp_report("<source>", "fn main() = )\n", d)))
[E7100] Parse Error: unexpected ')'
╭─[ <source>:1:13 ]
│
1 │ fn main() = )
│ ┬
│ ╰── here
───╯
rp_report_doc
rp_report_doc : (String, Syntax.Diagnostic.DiagnosticsDoc) -> Option(String)
Every diagnostic in a document rendered in order and concatenated, or None when any one of them falls outside the shape this module draws. The compiler stops at its first refusal, so a document carrying more than one diagnostic has no single compiler report to compare against.