harn_vm/compiler/
callable_entry.rs1use std::sync::Arc;
2
3use harn_parser::{Node, SNode};
4
5use super::{ensure_chunk_addressable, peel_node, CompileError, CompiledCallableEntry, Compiler};
6use crate::chunk::Op;
7
8impl Compiler {
9 pub fn compile_named_pipeline_entry(
11 mut self,
12 program: &[SNode],
13 pipeline_name: &str,
14 fixture_name: Option<&str>,
15 ) -> Result<CompiledCallableEntry, CompileError> {
16 self.prepare_module_context(program);
17 self.compile_entry_imports(program)?;
18 self.compile_top_level_declarations(program)?;
19
20 if let Some(fixture_name) = fixture_name {
21 let fixture = self.string_constant(fixture_name);
22 self.chunk.emit_u16(Op::GetVar, fixture, self.line);
23 }
24 let target = program.iter().find(
25 |node| matches!(peel_node(node), Node::Pipeline { name, .. } if name == pipeline_name),
26 );
27 let Some(target) = target else {
28 return Err(CompileError {
29 message: format!("Unknown pipeline: {pipeline_name}"),
30 line: self.line,
31 });
32 };
33 let Node::Pipeline {
34 name,
35 body,
36 extends,
37 params,
38 ..
39 } = peel_node(target)
40 else {
41 unreachable!("pipeline target was matched above");
42 };
43 let callable =
44 self.compile_pipeline_callable(program, name, params, body, extends.as_deref())?;
45 let function_index = self.chunk.functions.len();
46 self.chunk.functions.push(Arc::new(callable));
47 self.chunk
48 .emit_u16(Op::Closure, function_index as u16, self.line);
49 if fixture_name.is_some() {
50 self.chunk.emit_u16(Op::BuildList, 2, self.line);
51 }
52 self.chunk.emit(Op::Return, self.line);
53 ensure_chunk_addressable(&self.chunk, "the callable entry", self.line)?;
54 Ok(CompiledCallableEntry {
55 bootstrap: self.chunk,
56 has_fixture: fixture_name.is_some(),
57 })
58 }
59
60 pub fn compile_named_function_entry(
62 mut self,
63 program: &[SNode],
64 function_name: &str,
65 ) -> Result<CompiledCallableEntry, CompileError> {
66 self.prepare_module_context(program);
67 self.compile_entry_imports(program)?;
68 self.compile_top_level_declarations(program)?;
69 let target = program.iter().any(
70 |node| matches!(peel_node(node), Node::FnDecl { name, .. } if name == function_name),
71 );
72 if !target {
73 return Err(CompileError {
74 message: format!("Unknown function: {function_name}"),
75 line: self.line,
76 });
77 }
78 let function = self.string_constant(function_name);
79 self.chunk.emit_u16(Op::GetVar, function, self.line);
80 self.chunk.emit(Op::Return, self.line);
81 ensure_chunk_addressable(&self.chunk, "the callable entry", self.line)?;
82 Ok(CompiledCallableEntry {
83 bootstrap: self.chunk,
84 has_fixture: false,
85 })
86 }
87
88 fn compile_entry_imports(&mut self, program: &[SNode]) -> Result<(), CompileError> {
89 for node in program {
90 if matches!(
91 &node.node,
92 Node::ImportDecl { .. }
93 | Node::SelectiveImport { .. }
94 | Node::NamespaceImport { .. }
95 ) {
96 self.compile_node(node)?;
97 }
98 }
99 Ok(())
100 }
101}