rukalang/driver/
passes.rs

1//! Concrete pass wrappers used by the driver pipeline.
2
3use std::convert::Infallible;
4use std::path::Path;
5
6use crate::check::{self, CheckedProgram};
7use crate::codegen;
8use crate::elab;
9use crate::hir::{self, HirProgram};
10use crate::meta;
11use crate::mir::{self, MirProgram};
12use crate::pass::{Pass, PassContext, PassTiming};
13use crate::source_index::build_function_line_map;
14use crate::syntax::ast::Program;
15
16/// Expand frontend modules by evaluating meta constructs.
17///
18/// This is the first executable compiler pass after module resolution.
19/// It resolves `meta` expressions and template expansion so later passes
20/// consume one concrete runtime-facing AST shape.
21///
22/// Input: parsed frontend [`Program`].
23/// Output: expanded frontend [`Program`].
24/// Pass name: `meta.expand_program`.
25pub(super) struct ExpandProgramPass<'a> {
26    /// Parsed program to expand.
27    pub(super) program: &'a Program,
28}
29
30impl<'a> Pass for ExpandProgramPass<'a> {
31    type In = ();
32    type Out = Program;
33    type Error = meta::MetaEvalError;
34
35    const NAME: &'static str = "meta.expand_program";
36
37    fn run(&mut self, _input: Self::In, _cx: &mut PassContext) -> Result<Self::Out, Self::Error> {
38        meta::expand_program(self.program)
39    }
40}
41
42/// Elaborate runtime-facing AST types and template specializations.
43///
44/// This pass delegates into `elab` and aggregates internal elaboration
45/// subpass timings so they can be surfaced by the top-level driver.
46///
47/// Input: expanded frontend [`Program`].
48/// Output: elaborated frontend [`Program`].
49/// Pass name: `elab.elaborate_program`.
50pub(super) struct ElaborateProgramPass<'a> {
51    /// Expanded program to elaborate.
52    pub(super) program: &'a Program,
53    /// Elaboration subpass timings recorded during run.
54    pub(super) subpass_timings: Vec<PassTiming>,
55}
56
57impl<'a> Pass for ElaborateProgramPass<'a> {
58    type In = ();
59    type Out = Program;
60    type Error = elab::ElabError;
61
62    const NAME: &'static str = "elab.elaborate_program";
63
64    fn run(&mut self, _input: Self::In, _cx: &mut PassContext) -> Result<Self::Out, Self::Error> {
65        let (program, timings) = elab::elaborate_program_with_timings(self.program)?;
66        self.subpass_timings = timings;
67        Ok(program)
68    }
69}
70
71impl<'a> ElaborateProgramPass<'a> {
72    /// Drain recorded elaboration subpass timings after one run.
73    pub(super) fn take_subpass_timings(&mut self) -> Vec<PassTiming> {
74        std::mem::take(&mut self.subpass_timings)
75    }
76}
77
78/// Lower elaborated frontend AST into HIR.
79///
80/// This pass materializes HIR entities and side tables used by semantic
81/// checking and downstream lowering.
82///
83/// Input: elaborated frontend [`Program`].
84/// Output: [`HirProgram`].
85/// Pass name: `hir.lower_program`.
86pub(super) struct LowerHirPass<'a> {
87    /// Elaborated program to lower.
88    pub(super) program: &'a Program,
89}
90
91impl<'a> Pass for LowerHirPass<'a> {
92    type In = ();
93    type Out = HirProgram;
94    type Error = Infallible;
95
96    const NAME: &'static str = "hir.lower_program";
97
98    fn run(&mut self, _input: Self::In, _cx: &mut PassContext) -> Result<Self::Out, Self::Error> {
99        Ok(hir::lower::lower_program(self.program))
100    }
101}
102
103/// Run semantic/type checks on HIR.
104///
105/// This pass computes function signatures, local symbol tables, and typed
106/// expression facts consumed by MIR lowering and diagnostics.
107///
108/// Input: [`HirProgram`].
109/// Output: [`CheckedProgram`].
110/// Pass name: `check.check_program`.
111pub(super) struct CheckProgramPass<'a> {
112    /// HIR program to check.
113    pub(super) program: &'a HirProgram,
114}
115
116impl<'a> Pass for CheckProgramPass<'a> {
117    type In = ();
118    type Out = CheckedProgram;
119    type Error = check::CheckError;
120
121    const NAME: &'static str = "check.check_program";
122
123    fn run(&mut self, _input: Self::In, _cx: &mut PassContext) -> Result<Self::Out, Self::Error> {
124        check::check_program(self.program)
125    }
126}
127
128/// Lower HIR + checker facts into MIR.
129///
130/// This pass builds control-flow blocks, locals, and low-level instructions
131/// for both Rust and WASM code generation.
132///
133/// Input: [`HirProgram`] plus [`CheckedProgram`].
134/// Output: [`MirProgram`].
135/// Pass name: `mir.lower_program`.
136pub(super) struct LowerMirPass<'a> {
137    /// HIR input program.
138    pub(super) hir: &'a HirProgram,
139    /// Semantic annotations from checker.
140    pub(super) checked: &'a CheckedProgram,
141}
142
143impl<'a> Pass for LowerMirPass<'a> {
144    type In = ();
145    type Out = MirProgram;
146    type Error = mir::lower::LowerError;
147
148    const NAME: &'static str = "mir.lower_program";
149
150    fn run(&mut self, _input: Self::In, _cx: &mut PassContext) -> Result<Self::Out, Self::Error> {
151        mir::lower::lower_program(self.hir, self.checked)
152    }
153}
154
155/// Emit Rust source from MIR.
156///
157/// This pass computes a function-line map from source text and emits Rust
158/// code with best-effort source correspondence metadata.
159///
160/// Input: [`MirProgram`], source path, and source text.
161/// Output: generated Rust source text.
162/// Pass name: `codegen.rust.emit_program`.
163pub(super) struct EmitRustPass<'a> {
164    /// MIR program to emit.
165    pub(super) mir: &'a MirProgram,
166    /// Source file path used for line mapping comments.
167    pub(super) source_file: &'a Path,
168    /// Source text used to derive function line map.
169    pub(super) source_text: &'a str,
170}
171
172impl<'a> Pass for EmitRustPass<'a> {
173    type In = ();
174    type Out = String;
175    type Error = codegen::rust::CodegenError;
176
177    const NAME: &'static str = "codegen.rust.emit_program";
178
179    fn run(&mut self, _input: Self::In, _cx: &mut PassContext) -> Result<Self::Out, Self::Error> {
180        let function_lines = build_function_line_map(self.source_text);
181        codegen::rust::emit_program_with_function_lines(self.mir, self.source_file, &function_lines)
182    }
183}
184
185/// Emit WASM/WAT artifacts from MIR.
186///
187/// This pass computes a function-line map from source text and emits browser
188/// artifacts, including WAT, optional WASM bytes, and diagnostics.
189///
190/// Input: [`MirProgram`] and source text.
191/// Output: [`codegen::wasm::WasmArtifacts`].
192/// Pass name: `codegen.wasm.emit_program`.
193pub(super) struct EmitWasmPass<'a> {
194    /// MIR program to emit.
195    pub(super) mir: &'a MirProgram,
196    /// Source text used to derive function line map.
197    pub(super) source_text: &'a str,
198}
199
200impl<'a> Pass for EmitWasmPass<'a> {
201    type In = ();
202    type Out = codegen::wasm::WasmArtifacts;
203    type Error = Infallible;
204
205    const NAME: &'static str = "codegen.wasm.emit_program";
206
207    fn run(&mut self, _input: Self::In, _cx: &mut PassContext) -> Result<Self::Out, Self::Error> {
208        let function_lines = build_function_line_map(self.source_text);
209        Ok(codegen::wasm::emit_program_best_effort_with_options(
210            self.mir,
211            codegen::wasm::EmitOptions {
212                assert_no_leaks_at_run_main: true,
213                function_lines,
214            },
215        ))
216    }
217}