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    pub fn with_options(options: CompilerOptions) -> Self {
43        install_native_builtin_contracts();
44        Self {
45            inner: harn_kernel::Compiler::with_options(options),
46        }
47    }
48
49    pub fn with_imported_enum_candidates(
50        self,
51        candidates: impl IntoIterator<Item = String>,
52    ) -> Self {
53        Self {
54            inner: self.inner.with_imported_enum_candidates(candidates),
55        }
56    }
57
58    pub fn compile(self, program: &[harn_parser::SNode]) -> Result<Chunk, CompileError> {
59        self.inner.compile(program).map(Chunk::from_portable)
60    }
61
62    pub fn compile_named(
63        self,
64        program: &[harn_parser::SNode],
65        name: &str,
66    ) -> Result<Chunk, CompileError> {
67        self.inner
68            .compile_named(program, name)
69            .map(Chunk::from_portable)
70    }
71
72    pub fn compile_named_pipeline_entry(
73        self,
74        program: &[harn_parser::SNode],
75        name: &str,
76        fixture: Option<&str>,
77    ) -> Result<CompiledCallableEntry, CompileError> {
78        self.inner
79            .compile_named_pipeline_entry(program, name, fixture)
80            .map(convert_entry)
81    }
82
83    /// Compile several named pipelines from one parsed file while sharing the
84    /// immutable top-level compilation work between their entry artifacts.
85    pub fn compile_named_pipeline_entries(
86        self,
87        program: &[harn_parser::SNode],
88        entries: &[(&str, Option<&str>)],
89    ) -> Result<Vec<Result<CompiledCallableEntry, CompileError>>, CompileError> {
90        self.inner
91            .compile_named_pipeline_entries(program, entries)
92            .map(|entries| {
93                entries
94                    .into_iter()
95                    .map(|entry| entry.map(convert_entry))
96                    .collect()
97            })
98    }
99
100    /// Compile pipeline and function entries through one immutable file
101    /// lowering while preserving a fresh runtime artifact for every request.
102    pub fn compile_named_callable_entries(
103        self,
104        program: &[harn_parser::SNode],
105        pipelines: &[(&str, Option<&str>)],
106        functions: &[&str],
107    ) -> Result<CompiledCallableBatch, CompileError> {
108        self.inner
109            .compile_named_callable_entries(program, pipelines, functions)
110            .map(|batch| CompiledCallableBatch {
111                pipelines: batch
112                    .pipelines
113                    .into_iter()
114                    .map(|entry| entry.map(convert_entry))
115                    .collect(),
116                functions: batch
117                    .functions
118                    .into_iter()
119                    .map(|entry| entry.map(convert_entry))
120                    .collect(),
121            })
122    }
123
124    pub fn compile_named_function_entry(
125        self,
126        program: &[harn_parser::SNode],
127        name: &str,
128    ) -> Result<CompiledCallableEntry, CompileError> {
129        self.inner
130            .compile_named_function_entry(program, name)
131            .map(convert_entry)
132    }
133
134    pub fn prepare_module_context(&mut self, program: &[harn_parser::SNode]) {
135        self.inner.prepare_module_context(program);
136    }
137
138    pub fn add_imported_enum_candidates(&mut self, candidates: impl IntoIterator<Item = String>) {
139        self.inner.add_imported_enum_candidates(candidates);
140    }
141
142    pub fn compile_module_init(
143        self,
144        context: &[harn_parser::SNode],
145        init_nodes: &[harn_parser::SNode],
146        imported_enums: &[String],
147    ) -> Result<Chunk, CompileError> {
148        self.inner
149            .compile_module_init(context, init_nodes, imported_enums)
150            .map(Chunk::from_portable)
151    }
152
153    pub fn compile_struct_constructor(
154        &self,
155        name: &str,
156        fields: &[harn_parser::StructField],
157    ) -> Result<CompiledFunction, CompileError> {
158        self.inner
159            .compile_struct_constructor(name, fields)
160            .map(CompiledFunction::from_portable)
161    }
162
163    pub fn compile_pipeline_callable(
164        &self,
165        program: &[harn_parser::SNode],
166        name: &str,
167        params: &[harn_parser::TypedParam],
168        body: &[harn_parser::SNode],
169        extends: Option<&str>,
170    ) -> Result<CompiledFunction, CompileError> {
171        self.inner
172            .compile_pipeline_callable(program, name, params, body, extends)
173            .map(CompiledFunction::from_portable)
174    }
175
176    pub fn compile_fn_body(
177        &mut self,
178        type_params: &[harn_parser::TypeParam],
179        params: &[harn_parser::TypedParam],
180        body: &[harn_parser::SNode],
181        source_file: Option<String>,
182    ) -> Result<CompiledFunction, CompileError> {
183        self.inner
184            .compile_fn_body(type_params, params, body, source_file)
185            .map(CompiledFunction::from_portable)
186    }
187
188    pub fn compile_public_type_schema_initializers(
189        program: &[harn_parser::SNode],
190        source_file: Option<String>,
191    ) -> Result<Vec<Chunk>, CompileError> {
192        harn_kernel::Compiler::compile_public_type_schema_initializers(program, source_file)
193            .map(|chunks| chunks.into_iter().map(Chunk::from_portable).collect())
194    }
195
196    pub fn compile_selected_public_type_schema_initializers(
197        program: &[harn_parser::SNode],
198        source_file: Option<String>,
199        selected_names: Option<&std::collections::BTreeSet<String>>,
200    ) -> Result<Vec<Chunk>, CompileError> {
201        harn_kernel::Compiler::compile_selected_public_type_schema_initializers(
202            program,
203            source_file,
204            selected_names,
205        )
206        .map(|chunks| chunks.into_iter().map(Chunk::from_portable).collect())
207    }
208
209    pub fn collect_type_aliases(&mut self, program: &[harn_parser::SNode]) {
210        self.inner.collect_type_aliases(program);
211    }
212
213    pub fn expand_alias(&self, ty: &harn_parser::TypeExpr) -> harn_parser::TypeExpr {
214        self.inner.expand_alias(ty)
215    }
216
217    pub fn type_expr_to_schema_value(type_expr: &harn_parser::TypeExpr) -> Option<crate::VmValue> {
218        harn_kernel::Compiler::type_expr_to_schema_value(type_expr).map(portable_value_to_vm)
219    }
220}
221
222fn install_native_builtin_contracts() {
223    harn_builtin_registry::install_builtin_manifest(crate::stdlib::all_builtin_manifest());
224}
225
226impl Default for Compiler {
227    fn default() -> Self {
228        Self::new()
229    }
230}
231
232fn convert_entry(entry: harn_kernel::CompiledCallableEntry) -> CompiledCallableEntry {
233    CompiledCallableEntry {
234        bootstrap: Chunk::from_portable(entry.bootstrap),
235        has_fixture: entry.has_fixture,
236        fixture_expects_harness: entry.fixture_expects_harness,
237        expects_harness: entry.expects_harness,
238    }
239}
240
241fn portable_value_to_vm(value: harn_kernel::value::VmValue) -> crate::VmValue {
242    match value {
243        harn_kernel::value::VmValue::Int(value) => crate::VmValue::Int(value),
244        harn_kernel::value::VmValue::Float(value) => crate::VmValue::Float(value),
245        harn_kernel::value::VmValue::String(value) => crate::VmValue::string(value),
246        harn_kernel::value::VmValue::Bool(value) => crate::VmValue::Bool(value),
247        harn_kernel::value::VmValue::Nil => crate::VmValue::Nil,
248        harn_kernel::value::VmValue::Duration(value) => crate::VmValue::Duration(value),
249        harn_kernel::value::VmValue::List(values) => crate::VmValue::List(std::sync::Arc::new(
250            values.iter().cloned().map(portable_value_to_vm).collect(),
251        )),
252        harn_kernel::value::VmValue::Dict(entries) => crate::VmValue::dict(
253            entries
254                .iter()
255                .map(|(key, value)| (key.clone(), portable_value_to_vm(value.clone()))),
256        ),
257    }
258}