use std::path::Path;
use anyhow::{bail, Result};
use regex::Regex;
const TSG_SOURCE: &str = "src/stack-graphs.tsg";
const DIALECTS: [&str; 2] = ["typescript", "tsx"];
fn preprocess(
input: impl std::io::Read,
mut output: impl std::io::Write,
dialect: &str,
) -> Result<()> {
let directive_start = Regex::new(r";\s*#dialect\s+(\w+)").unwrap();
let directive_end = Regex::new(r";\s*#end").unwrap();
let no_code = Regex::new(r"^[\s;]+").unwrap();
let input = std::io::read_to_string(input)?;
let mut filter: Option<bool> = None;
for (mut line_no, line) in input.lines().enumerate() {
line_no += 1;
if let Some(captures) = directive_start.captures(line) {
if !no_code.is_match(line) {
bail!("Line {line_no}: unexpected code before directive");
}
if filter.is_some() {
bail!("Line {line_no}: dialect directive cannot be nested");
}
let directive = captures.get(1).unwrap().as_str();
if !DIALECTS.contains(&directive) {
bail!("Line {line_no}: unknown dialect: {directive}");
}
filter = Some(dialect == directive);
} else if directive_end.is_match(line) {
if !no_code.is_match(line) {
bail!("Line {line_no}: unexpected code before directive end");
}
if filter.is_none() {
bail!("Line {line_no}: unmatched directive end");
}
filter = None;
} else if filter.unwrap_or(true) {
output.write_all(line.as_bytes())?;
}
output.write(b"\n")?;
}
if filter.is_some() {
bail!("Unmatched directive end at the end of the file");
}
Ok(())
}
fn main() {
let out_dir = std::env::var_os("OUT_DIR").expect("OUT_DIR is not set");
for dialect in DIALECTS {
let input = std::fs::File::open(TSG_SOURCE).expect("Failed to open stack-graphs.tsg");
let out_filename = Path::new(&out_dir).join(format!("stack-graphs-{dialect}.tsg"));
let output = std::fs::File::create(out_filename).expect("Failed to create output file");
preprocess(input, output, dialect).expect("Failed to preprocess stack-graphs.tsg");
}
println!("cargo:rerun-if-changed={TSG_SOURCE}");
println!("cargo:rerun-if-changed=build.rs");
}