use harn_parser::{Node, SNode};
use super::error::CompileError;
use super::{peel_node, Compiler};
impl Compiler {
pub(super) fn compile_with_pipeline_captures<'a, T>(
&mut self,
program: &'a [SNode],
body: &'a [SNode],
extends: Option<&str>,
compile: impl FnOnce(&mut Self) -> Result<T, CompileError>,
) -> Result<T, CompileError> {
let mut lineage = Vec::new();
Self::append_parent_pipeline_bodies(program, extends, &mut lineage);
lineage.push(body);
let match_patterns = self.lexical_match_pattern_catalog();
let captured =
harn_parser::lexical::captured_bindings_in_pipeline_lineage(&lineage, &match_patterns);
let saved = std::mem::replace(&mut self.captured_bindings, captured);
let result = compile(self);
self.captured_bindings = saved;
result
}
pub(super) fn compile_parent_pipeline(
&mut self,
program: &[SNode],
parent_name: &str,
) -> Result<(), CompileError> {
let parent = program.iter().find(
|node| matches!(peel_node(node), Node::Pipeline { name, .. } if name == parent_name),
);
let Some(parent) = parent else {
return Ok(());
};
let Node::Pipeline { body, extends, .. } = peel_node(parent) else {
return Ok(());
};
let saved_catalog = self.enum_catalog_snapshot();
let result: Result<(), CompileError> = (|| {
if let Some(grandparent) = extends {
self.compile_parent_pipeline(program, grandparent)?;
}
for statement in body {
self.compile_discarded_stmt(statement)?;
}
Ok(())
})();
self.restore_enum_catalog(saved_catalog);
result
}
fn append_parent_pipeline_bodies<'a>(
program: &'a [SNode],
parent_name: Option<&str>,
lineage: &mut Vec<&'a [SNode]>,
) {
let Some(parent_name) = parent_name else {
return;
};
let Some(parent) = program.iter().find(
|node| matches!(peel_node(node), Node::Pipeline { name, .. } if name == parent_name),
) else {
return;
};
let Node::Pipeline { body, extends, .. } = peel_node(parent) else {
return;
};
Self::append_parent_pipeline_bodies(program, extends.as_deref(), lineage);
lineage.push(body);
}
}