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