1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! The compilation-phase trait — the seam a driver is built from.
use crateDriverError;
use crateSession;
/// 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`](Self::Input) and produces the next one
/// as [`Output`](Self::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`](crate::Pipeline), which enforces at compile
/// time that each stage's `Output` is the next stage's `Input`.
///
/// # Contract
///
/// - [`name`](Self::name) returns a stable, static identifier, used to attribute a
/// [`DriverError`] to the stage that produced it. It must not change between
/// runs.
/// - [`run`](Self::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`](crate::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
/// ```