pub struct ResolvedProgram { /* private fields */ }Expand description
A program with its imports spliced in, and the file each top-level form came from.
§Why file identity is per TOP-LEVEL FORM
resolve_uses splices whole files’ worth of top-level forms: a use is
replaced by every form of the package it names, in order. So a boundary
between two files is always a boundary between two top-level forms, and
every node beneath a top-level form came from exactly one file — the one
that form came from. A FileId per top-level form is therefore exactly as
precise as a FileId per node, at a fraction of the cost and with nothing
upstream to change.
That last part is the point. Span lives in tatara-lisp and carries no file
identity by a documented decision — “Spans are not portable across source
inputs — they are meaningful only relative to the string that produced them,
which the caller is responsible for holding onto.” blue is the caller. This
is blue holding onto them, beside the span rather than inside it.
§Why the fields are private
forms and owner are parallel, and files[i].id is FileId(i). Both
invariants are maintained by push and intern, the only places either
vector grows, and by retain, the only place either
shrinks. Public fields would make program.forms.retain(...) — the exact
call pipeline::run_in_surface makes to drop test blocks — shift every
form off its owner by one and report every subsequent diagnostic against the
wrong file, silently.
Implementations§
Source§impl ResolvedProgram
impl ResolvedProgram
Sourcepub fn sexps(&self) -> Vec<Sexp>
pub fn sexps(&self) -> Vec<Sexp>
The same forms with their spans projected away, for the stages that do not report positions — erasure, evaluation, the test harness.
Sourcepub fn files(&self) -> &[SourceFile]
pub fn files(&self) -> &[SourceFile]
Every file that contributed, entry first.
Sourcepub fn owner_of(&self, top_level: usize) -> Option<FileId>
pub fn owner_of(&self, top_level: usize) -> Option<FileId>
Which file the top_level-th form came from.
Sourcepub fn file(&self, id: FileId) -> Option<&SourceFile>
pub fn file(&self, id: FileId) -> Option<&SourceFile>
A file by its handle.
Sourcepub fn retain(&mut self, keep: impl Fn(&Spanned) -> bool)
pub fn retain(&mut self, keep: impl Fn(&Spanned) -> bool)
Drop the top-level forms keep rejects, taking their owners with them.
The lockstep is the whole reason this method exists rather than a public
forms field: Vec::retain on one of two parallel vectors is a silent
mis-attribution, not a compile error.
Sourcepub fn locate<'a>(
&'a self,
top_level: usize,
span: Span,
message: &'a str,
) -> Located<'a>
pub fn locate<'a>( &'a self, top_level: usize, span: Span, message: &'a str, ) -> Located<'a>
Resolve a diagnostic’s position against the file it actually came from.
top_level is blue_lang_check::Diagnostic::top_level — the join key.
An index with no owner (a diagnostic that escaped stamping) renders
without a position rather than borrowing the entry file’s: a missing
position costs the reader a search, a wrong one sends them to innocent
code and is believed.