pub trait Stage<C> {
type Input;
type Output;
// Required methods
fn name(&self) -> &'static str;
fn run(
&mut self,
input: Self::Input,
session: &mut Session<C>,
) -> Result<Self::Output, DriverError>;
}Expand description
One phase of compilation: a transform from an input artifact to an output
artifact, run against a Session.
A stage is the unit a driver is assembled from. Each phase of a compiler — lex,
parse, resolve names, type-check, lower, emit — is a Stage that takes the
previous phase’s artifact as Input and produces the next one
as Output: a lexer is Stage<Input = Source, Output = Tokens>, a parser is Stage<Input = Tokens, Output = Ast>, and so on. Unlike
a pass (which rewrites one type in place), a stage changes the type as the
program moves down the pipeline — that type-threading is exactly what a driver
exists to manage.
A stage is generic over the session’s configuration type C, so every stage in
a pipeline reads and writes the same shared configuration and diagnostics. Wire
stages together with Pipeline, which enforces at compile
time that each stage’s Output is the next stage’s Input.
§Contract
namereturns a stable, static identifier, used to attribute aDriverErrorto the stage that produced it. It must not change between runs.runconsumesinput, may read and write theSession(emitting diagnostics, reading configuration), and returns the output. A phase that cannot produce its output returns aDriverError— never a panic. Emitting an error diagnostic records a problem but does not by itself stop the pipeline; returnErr, or callSession::abort_if_errors, to stop.
§Examples
A stage that parses whitespace-separated integers, warning on each token it cannot read and failing only if nothing parsed:
use driver_lang::{DriverError, Session, Stage};
struct Lex;
impl Stage<()> for Lex {
type Input = &'static str;
type Output = Vec<i64>;
fn name(&self) -> &'static str {
"lex"
}
fn run(&mut self, input: &'static str, session: &mut Session<()>)
-> Result<Vec<i64>, DriverError>
{
let mut out = Vec::new();
for word in input.split_whitespace() {
match word.parse::<i64>() {
Ok(n) => out.push(n),
Err(_) => { session.warn("skipping non-integer token"); }
}
}
if out.is_empty() {
return Err(DriverError::new("no integers in input"));
}
Ok(out)
}
}
let mut session = Session::new(());
let tokens = Lex.run("1 two 3", &mut session).unwrap();
assert_eq!(tokens, vec![1, 3]);
assert_eq!(session.diagnostics().len(), 1); // one "skipping" warningRequired Associated Types§
Required Methods§
Sourcefn run(
&mut self,
input: Self::Input,
session: &mut Session<C>,
) -> Result<Self::Output, DriverError>
fn run( &mut self, input: Self::Input, session: &mut Session<C>, ) -> Result<Self::Output, DriverError>
Run the stage: consume input, use the Session as needed, and produce
the output.
Return a DriverError — never a panic — if the phase cannot produce its
output; the Pipeline stops there and stamps this
stage’s name into the error.
§Errors
Returns whatever DriverError the phase produces when it cannot continue.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".