forge_codegen/
compiler.rs1use std::fs;
5use std::path::{Path, PathBuf};
6
7use walkdir::WalkDir;
8
9use crate::lower::{lower, lower_with_target, LowerTarget};
10use crate::parser::tokenize;
11
12pub fn compile_source(source: &str) -> String {
13 let tokens = tokenize(source);
14 lower(&tokens)
15}
16
17pub fn compile_source_runtime(source: &str) -> String {
22 let tokens = tokenize(source);
23 lower_with_target(&tokens, LowerTarget::MiniJinja)
24}
25
26pub fn compile_file(input: &Path, output: &Path) -> std::io::Result<()> {
27 let raw = fs::read_to_string(input)?;
28 let lowered = compile_source(&raw);
29 if let Some(parent) = output.parent() {
30 fs::create_dir_all(parent)?;
31 }
32 fs::write(output, lowered)?;
33 Ok(())
34}
35
36pub fn compile_dir(input_dir: &Path, output_dir: &Path) -> std::io::Result<Vec<PathBuf>> {
39 let mut written = Vec::new();
40 if !input_dir.exists() {
41 return Ok(written);
42 }
43 for entry in WalkDir::new(input_dir).into_iter().filter_map(|e| e.ok()) {
44 if !entry.file_type().is_file() {
45 continue;
46 }
47 let path = entry.path();
48 let Some(file_name) = path.file_name().and_then(|n| n.to_str()) else {
49 continue;
50 };
51 if !file_name.ends_with(".forge.html") && !file_name.ends_with(".forge") {
52 continue;
53 }
54 let rel = path.strip_prefix(input_dir).unwrap_or(path);
55 let out_name = file_name
56 .replace(".forge.html", ".html")
57 .replace(".forge", ".html");
58 let mut out_path = output_dir.to_path_buf();
59 if let Some(parent) = rel.parent() {
60 out_path.push(parent);
61 }
62 out_path.push(out_name);
63 compile_file(path, &out_path)?;
64 written.push(out_path);
65 }
66 Ok(written)
67}