Skip to main content

harn_vm/
compiler.rs

1//! Native adapter over the portable canonical compiler.
2
3use crate::chunk::{Chunk, CompiledFunction};
4
5pub use harn_kernel::compiler::HARN_DISABLE_OPTIMIZATIONS_ENV;
6pub use harn_kernel::{CompileError, CompilerOptions};
7
8#[derive(Clone)]
9pub struct CompiledCallableEntry {
10    pub(crate) bootstrap: Chunk,
11    pub(crate) has_fixture: bool,
12    pub(crate) fixture_expects_harness: bool,
13    pub(crate) expects_harness: bool,
14}
15
16pub struct CompiledCallableBatch {
17    /// Results in the same order as requested pipeline entries.
18    pub pipelines: Vec<Result<CompiledCallableEntry, CompileError>>,
19    /// Results in the same order as requested function entries.
20    pub functions: Vec<Result<CompiledCallableEntry, CompileError>>,
21}
22
23pub struct Compiler {
24    inner: harn_kernel::Compiler,
25}
26
27impl Compiler {
28    pub fn new() -> Self {
29        install_native_builtin_contracts();
30        Self {
31            inner: harn_kernel::Compiler::new(),
32        }
33    }
34
35    pub fn new_trusted_host_dispatch() -> Self {
36        install_native_builtin_contracts();
37        Self {
38            inner: harn_kernel::Compiler::new_trusted_host_dispatch(),
39        }
40    }
41
42    #[doc(hidden)]
43    pub fn new_runtime_owned_source() -> Self {
44        install_native_builtin_contracts();
45        Self {
46            inner: harn_kernel::Compiler::new_runtime_owned_source(),
47        }
48    }
49
50    /// Compiler for Harn's immutable, embedder-owned stdlib sources.
51    #[doc(hidden)]
52    pub fn new_embedded_stdlib() -> Self {
53        install_native_builtin_contracts();
54        Self {
55            inner: harn_kernel::Compiler::new_embedded_stdlib(),
56        }
57    }
58
59    pub fn with_options(options: CompilerOptions) -> Self {
60        install_native_builtin_contracts();
61        Self {
62            inner: harn_kernel::Compiler::with_options(options),
63        }
64    }
65
66    pub fn with_imported_enum_candidates(
67        self,
68        candidates: impl IntoIterator<Item = String>,
69    ) -> Self {
70        Self {
71            inner: self.inner.with_imported_enum_candidates(candidates),
72        }
73    }
74
75    pub fn with_imported_source_callable_names(
76        self,
77        names: impl IntoIterator<Item = String>,
78    ) -> Self {
79        Self {
80            inner: self.inner.with_imported_source_callable_names(names),
81        }
82    }
83
84    pub fn compile(self, program: &[harn_parser::SNode]) -> Result<Chunk, CompileError> {
85        self.inner.compile(program).map(Chunk::from_portable)
86    }
87
88    pub fn compile_named(
89        self,
90        program: &[harn_parser::SNode],
91        name: &str,
92    ) -> Result<Chunk, CompileError> {
93        self.inner
94            .compile_named(program, name)
95            .map(Chunk::from_portable)
96    }
97
98    pub fn compile_named_pipeline_entry(
99        self,
100        program: &[harn_parser::SNode],
101        name: &str,
102        fixture: Option<&str>,
103    ) -> Result<CompiledCallableEntry, CompileError> {
104        self.inner
105            .compile_named_pipeline_entry(program, name, fixture)
106            .map(convert_entry)
107    }
108
109    /// Compile several named pipelines from one parsed file while sharing the
110    /// immutable top-level compilation work between their entry artifacts.
111    pub fn compile_named_pipeline_entries(
112        self,
113        program: &[harn_parser::SNode],
114        entries: &[(&str, Option<&str>)],
115    ) -> Result<Vec<Result<CompiledCallableEntry, CompileError>>, CompileError> {
116        self.inner
117            .compile_named_pipeline_entries(program, entries)
118            .map(|entries| {
119                entries
120                    .into_iter()
121                    .map(|entry| entry.map(convert_entry))
122                    .collect()
123            })
124    }
125
126    /// Compile pipeline and function entries through one immutable file
127    /// lowering while preserving a fresh runtime artifact for every request.
128    pub fn compile_named_callable_entries(
129        self,
130        program: &[harn_parser::SNode],
131        pipelines: &[(&str, Option<&str>)],
132        functions: &[&str],
133    ) -> Result<CompiledCallableBatch, CompileError> {
134        self.inner
135            .compile_named_callable_entries(program, pipelines, functions)
136            .map(|batch| CompiledCallableBatch {
137                pipelines: batch
138                    .pipelines
139                    .into_iter()
140                    .map(|entry| entry.map(convert_entry))
141                    .collect(),
142                functions: batch
143                    .functions
144                    .into_iter()
145                    .map(|entry| entry.map(convert_entry))
146                    .collect(),
147            })
148    }
149
150    pub fn compile_named_function_entry(
151        self,
152        program: &[harn_parser::SNode],
153        name: &str,
154    ) -> Result<CompiledCallableEntry, CompileError> {
155        self.inner
156            .compile_named_function_entry(program, name)
157            .map(convert_entry)
158    }
159
160    pub fn prepare_module_context(&mut self, program: &[harn_parser::SNode]) {
161        self.inner.prepare_module_context(program);
162    }
163
164    pub fn add_imported_enum_candidates(&mut self, candidates: impl IntoIterator<Item = String>) {
165        self.inner.add_imported_enum_candidates(candidates);
166    }
167
168    pub fn add_imported_source_callable_names(&mut self, names: impl IntoIterator<Item = String>) {
169        self.inner.add_imported_source_callable_names(names);
170    }
171
172    pub fn compile_module_init(
173        self,
174        context: &[harn_parser::SNode],
175        init_nodes: &[harn_parser::SNode],
176        imported_enums: &[String],
177        imported_source_callable_names: &[String],
178    ) -> Result<Chunk, CompileError> {
179        self.inner
180            .compile_module_init(
181                context,
182                init_nodes,
183                imported_enums,
184                imported_source_callable_names,
185            )
186            .map(Chunk::from_portable)
187    }
188
189    pub fn compile_struct_constructor(
190        &self,
191        name: &str,
192        fields: &[harn_parser::StructField],
193    ) -> Result<CompiledFunction, CompileError> {
194        self.inner
195            .compile_struct_constructor(name, fields)
196            .map(CompiledFunction::from_portable)
197    }
198
199    pub fn compile_pipeline_callable(
200        &self,
201        program: &[harn_parser::SNode],
202        name: &str,
203        params: &[harn_parser::TypedParam],
204        body: &[harn_parser::SNode],
205        extends: Option<&str>,
206    ) -> Result<CompiledFunction, CompileError> {
207        self.inner
208            .compile_pipeline_callable(program, name, params, body, extends)
209            .map(CompiledFunction::from_portable)
210    }
211
212    pub fn compile_fn_body(
213        &mut self,
214        type_params: &[harn_parser::TypeParam],
215        params: &[harn_parser::TypedParam],
216        body: &[harn_parser::SNode],
217        source_file: Option<String>,
218    ) -> Result<CompiledFunction, CompileError> {
219        self.inner
220            .compile_fn_body(type_params, params, body, source_file)
221            .map(CompiledFunction::from_portable)
222    }
223
224    pub fn compile_named_fn_body(
225        &mut self,
226        name: &str,
227        type_params: &[harn_parser::TypeParam],
228        params: &[harn_parser::TypedParam],
229        body: &[harn_parser::SNode],
230        source_file: Option<String>,
231    ) -> Result<CompiledFunction, CompileError> {
232        self.inner
233            .compile_named_fn_body(name, type_params, params, body, source_file)
234            .map(CompiledFunction::from_portable)
235    }
236
237    pub fn compile_public_type_schema_initializers(
238        program: &[harn_parser::SNode],
239        source_file: Option<String>,
240    ) -> Result<Vec<Chunk>, CompileError> {
241        harn_kernel::Compiler::compile_public_type_schema_initializers(program, source_file)
242            .map(|chunks| chunks.into_iter().map(Chunk::from_portable).collect())
243    }
244
245    pub fn compile_selected_public_type_schema_initializers(
246        program: &[harn_parser::SNode],
247        source_file: Option<String>,
248        selected_names: Option<&std::collections::BTreeSet<String>>,
249    ) -> Result<Vec<Chunk>, CompileError> {
250        harn_kernel::Compiler::compile_selected_public_type_schema_initializers(
251            program,
252            source_file,
253            selected_names,
254        )
255        .map(|chunks| chunks.into_iter().map(Chunk::from_portable).collect())
256    }
257
258    pub fn collect_type_aliases(&mut self, program: &[harn_parser::SNode]) {
259        self.inner.collect_type_aliases(program);
260    }
261
262    pub fn expand_alias(&self, ty: &harn_parser::TypeExpr) -> harn_parser::TypeExpr {
263        self.inner.expand_alias(ty)
264    }
265
266    pub fn type_expr_to_schema_value(type_expr: &harn_parser::TypeExpr) -> Option<crate::VmValue> {
267        harn_kernel::Compiler::type_expr_to_schema_value(type_expr).map(portable_value_to_vm)
268    }
269}
270
271fn install_native_builtin_contracts() {
272    harn_builtin_registry::install_builtin_manifest(crate::stdlib::all_builtin_manifest());
273}
274
275impl Default for Compiler {
276    fn default() -> Self {
277        Self::new()
278    }
279}
280
281fn convert_entry(entry: harn_kernel::CompiledCallableEntry) -> CompiledCallableEntry {
282    CompiledCallableEntry {
283        bootstrap: Chunk::from_portable(entry.bootstrap),
284        has_fixture: entry.has_fixture,
285        fixture_expects_harness: entry.fixture_expects_harness,
286        expects_harness: entry.expects_harness,
287    }
288}
289
290fn portable_value_to_vm(value: harn_kernel::value::VmValue) -> crate::VmValue {
291    match value {
292        harn_kernel::value::VmValue::Int(value) => crate::VmValue::Int(value),
293        harn_kernel::value::VmValue::Float(value) => crate::VmValue::Float(value),
294        harn_kernel::value::VmValue::String(value) => crate::VmValue::string(value),
295        harn_kernel::value::VmValue::Bool(value) => crate::VmValue::Bool(value),
296        harn_kernel::value::VmValue::Nil => crate::VmValue::Nil,
297        harn_kernel::value::VmValue::Duration(value) => crate::VmValue::Duration(value),
298        harn_kernel::value::VmValue::List(values) => crate::VmValue::List(std::sync::Arc::new(
299            values.iter().cloned().map(portable_value_to_vm).collect(),
300        )),
301        harn_kernel::value::VmValue::Dict(entries) => crate::VmValue::dict(
302            entries
303                .iter()
304                .map(|(key, value)| (key.clone(), portable_value_to_vm(value.clone()))),
305        ),
306    }
307}