use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("template.rs");
let template_content =
fs::read_to_string("src/lexer.rs").expect("Failed to read src/lexer.rs template file");
let escaped_content = template_content.replace("\\", "\\\\").replace("\"", "\\\"");
let template_code = format!(
r#"// This file is auto-generated by build.rs
// Do not edit manually
pub const LEXER_TEMPLATE: &str = "{}";
"#,
escaped_content
);
fs::write(&dest_path, template_code).expect("Failed to write template.rs");
println!("cargo:rerun-if-changed=src/lexer.rs");
println!("cargo:rerun-if-changed=src/parser.rs");
println!("cargo:rerun-if-changed=src/generator.rs");
println!("cargo:rerun-if-changed=src/token.rs");
register_klex_files();
generate_test_lexers();
}
fn register_klex_files() {
let tests_dir = Path::new("tests");
if !tests_dir.exists() {
return;
}
if let Ok(entries) = fs::read_dir(tests_dir) {
for entry in entries.filter_map(|e| e.ok()) {
let path = entry.path();
if path.extension().map_or(false, |ext| ext == "klex") {
println!("cargo:rerun-if-changed={}", path.display());
}
}
}
}
fn generate_test_lexers() {
let tests_dir = Path::new("tests");
if !tests_dir.exists() {
return;
}
let klex_files: Vec<PathBuf> = match fs::read_dir(tests_dir) {
Ok(entries) => entries
.filter_map(|entry| entry.ok())
.map(|entry| entry.path())
.filter(|path| path.extension().map_or(false, |ext| ext == "klex"))
.collect(),
Err(_) => return,
};
if klex_files.is_empty() {
return;
}
let klex_bin = Path::new("target/debug/klex");
if !klex_bin.exists() {
let klex_bin_release = Path::new("target/release/klex");
if !klex_bin_release.exists() {
println!("cargo:warning=klex binary not found. Run 'make generate-lexers' after build to generate test lexers.");
return;
}
}
for klex_file in klex_files {
let file_stem = klex_file.file_stem().unwrap().to_str().unwrap();
let output_file = tests_dir.join(format!("{}_lexer.rs", file_stem));
let needs_regeneration = if output_file.exists() {
let klex_modified = fs::metadata(&klex_file)
.and_then(|m| m.modified())
.ok();
let output_modified = fs::metadata(&output_file)
.and_then(|m| m.modified())
.ok();
match (klex_modified, output_modified) {
(Some(klex_time), Some(output_time)) => klex_time > output_time,
_ => true,
}
} else {
true
};
if needs_regeneration {
let klex_bin = if Path::new("target/debug/klex").exists() {
"target/debug/klex"
} else {
"target/release/klex"
};
let status = Command::new(klex_bin)
.arg(klex_file.to_str().unwrap())
.arg(output_file.to_str().unwrap())
.status();
match status {
Ok(status) if status.success() => {
}
_ => {
println!("cargo:warning=Failed to generate {}. Run 'make generate-lexers' manually.", output_file.display());
}
}
}
}
}