pub(crate) fn prepare_eval_temp_file(
code: &str,
) -> Result<(String, tempfile::NamedTempFile), String> {
Ok((eval_source_for_code(code), create_eval_temp_file()?))
}
pub(super) fn eval_source_for_code(code: &str) -> String {
if eval_code_parses_as_program(code) {
return code.to_string();
}
let (header, body) = split_eval_header(code);
if header.is_empty() {
format!("pipeline main(task) {{\n{body}\n}}")
} else {
format!("{header}\npipeline main(task) {{\n{body}\n}}")
}
}
fn eval_code_parses_as_program(code: &str) -> bool {
harn_parser::parse_source(code)
.map(|program| {
program.iter().any(|node| {
let (_, inner) = harn_parser::peel_attributes(node);
matches!(&inner.node, harn_parser::Node::Pipeline { .. })
})
})
.unwrap_or(false)
}
pub(super) fn create_eval_temp_file() -> Result<tempfile::NamedTempFile, String> {
if let Some(dir) = std::env::current_dir().ok().as_deref() {
match tempfile::Builder::new()
.prefix(".harn-eval-")
.suffix(".harn")
.tempfile_in(dir)
{
Ok(tmp) => return Ok(tmp),
Err(error) => eprintln!(
"warning: harn run -e: could not create temp file in {}: {error}; \
relative imports will not resolve",
dir.display()
),
}
}
tempfile::Builder::new()
.prefix("harn-eval-")
.suffix(".harn")
.tempfile()
.map_err(|error| format!("failed to create temp file for -e: {error}"))
}
pub(super) fn split_eval_header(code: &str) -> (String, String) {
let mut header_end = 0usize;
let mut last_kept = 0usize;
for (idx, line) in code.lines().enumerate() {
let trimmed = line.trim_start();
if trimmed.is_empty() || trimmed.starts_with("//") {
header_end = idx + 1;
continue;
}
let is_import = trimmed.starts_with("import ")
|| trimmed.starts_with("import\t")
|| trimmed.starts_with("import\"")
|| trimmed.starts_with("pub import ")
|| trimmed.starts_with("pub import\t");
if is_import {
header_end = idx + 1;
last_kept = idx + 1;
} else {
break;
}
}
if last_kept == 0 {
return (String::new(), code.to_string());
}
let mut header_lines = Vec::new();
let mut body_lines = Vec::new();
for (idx, line) in code.lines().enumerate() {
if idx < header_end {
header_lines.push(line);
} else {
body_lines.push(line);
}
}
(header_lines.join("\n"), body_lines.join("\n"))
}