Skip to main content

Stage

Trait Stage 

Source
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

  • name returns a stable, static identifier, used to attribute a DriverError to the stage that produced it. It must not change between runs.
  • run consumes input, may read and write the Session (emitting diagnostics, reading configuration), and returns the output. A phase that cannot produce its output returns a DriverError — never a panic. Emitting an error diagnostic records a problem but does not by itself stop the pipeline; return Err, or call Session::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" warning

Required Associated Types§

Source

type Input

The artifact this stage consumes.

Source

type Output

The artifact this stage produces.

Required Methods§

Source

fn name(&self) -> &'static str

A stable, static name for this stage, used to attribute errors.

Source

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".

Implementors§

Source§

impl<C, A, B> Stage<C> for Then<A, B>
where A: Stage<C>, B: Stage<C, Input = A::Output>,

Source§

type Input = <A as Stage<C>>::Input

Source§

type Output = <B as Stage<C>>::Output