Lines
92.19 %
Functions
56.67 %
Branches
100 %
use std::fs;
use std::path::Path;
use std::process::Command;
fn build_rust_wasm(manifest_path: &str, name: &str) {
let status = Command::new("cargo")
.args([
"build",
"--target",
"wasm32-unknown-unknown",
"--release",
"--manifest-path",
manifest_path,
])
.env_remove("RUSTFLAGS")
.env_remove("CARGO_ENCODED_RUSTFLAGS")
.status()
.unwrap_or_else(|_| panic!("Failed to build {name} WASM"));
assert!(status.success(), "{name} WASM build failed");
}
fn compile_nomiscript(nms_path: &Path, wasm_output_dir: &Path) {
let stem = nms_path.file_stem().unwrap().to_str().unwrap();
let wasm_name = stem.replace('-', "_");
let wasm_dest = wasm_output_dir.join(format!("{wasm_name}_nms.wasm"));
let source = fs::read_to_string(nms_path)
.unwrap_or_else(|_| panic!("Failed to read {}", nms_path.display()));
let program = nomiscript::Reader::parse(&source)
.unwrap_or_else(|e| panic!("Failed to parse {}: {e}", nms_path.display()));
let mut symbols = nomiscript::SymbolTable::with_builtins();
let mut compiler = nomiscript::Compiler::new();
let wasm = compiler
.compile(&program, &mut symbols)
.unwrap_or_else(|e| panic!("Failed to compile {}: {e}", nms_path.display()));
fs::write(&wasm_dest, &wasm)
.unwrap_or_else(|_| panic!("Failed to write {}", wasm_dest.display()));
println!("cargo:warning=Built and installed {wasm_name}_nms.wasm");
fn main() {
if std::env::var("MIRI_SYSROOT").is_ok() {
return;
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let scripts_dir = Path::new(manifest_dir)
.parent()
.unwrap()
.join("doc/scripts");
let wasm_output_dir = Path::new(manifest_dir)
.join("web/static/wasm");
if !scripts_dir.exists() {
fs::create_dir_all(&wasm_output_dir).ok();
println!("cargo:rerun-if-changed={}", scripts_dir.display());
let entries: Vec<_> = fs::read_dir(&scripts_dir)
.expect("Failed to read doc/scripts directory")
.filter_map(Result::ok)
.collect();
let org_files: Vec<_> = entries
.iter()
.filter(|e| e.path().extension().is_some_and(|ext| ext == "org"))
for entry in &org_files {
let org_path = entry.path();
println!("cargo:rerun-if-changed={}", org_path.display());
fs::create_dir_all(scripts_dir.join("src")).ok();
let status = Command::new("emacs")
"-q",
"--batch",
"--eval",
"(setq org-confirm-babel-evaluate nil)",
&format!(
"(progn (find-file \"{}\") (org-babel-tangle))",
org_path.display()
),
.current_dir(&scripts_dir)
.expect("Failed to run emacs org-babel-tangle");
assert!(
status.success(),
"org-babel-tangle failed for {}",
);
let cargo_toml = scripts_dir.join("Cargo.toml");
if !cargo_toml.exists() {
eprintln!(
"Warning: No Cargo.toml generated from {}",
continue;
let cargo_content =
fs::read_to_string(&cargo_toml).expect("Failed to read generated Cargo.toml");
let lib_name = cargo_content
.lines()
.find(|line| line.trim().starts_with("name = "))
.and_then(|line| {
let start = line.find('"')? + 1;
let end = line.rfind('"')?;
Some(&line[start..end])
});
let Some(lib_name) = lib_name else {
"Warning: Could not find lib name in Cargo.toml from {}",
};
let wasm_name = lib_name.replace('-', "_");
build_rust_wasm(cargo_toml.to_str().unwrap(), lib_name);
let wasm_source = scripts_dir
.join("target/wasm32-unknown-unknown/release")
.join(format!("{wasm_name}.wasm"));
if wasm_source.exists() {
let wasm_dest = wasm_output_dir.join(format!("{wasm_name}.wasm"));
fs::copy(&wasm_source, &wasm_dest).unwrap_or_else(|_| {
panic!(
"Failed to copy {} to {}",
wasm_source.display(),
wasm_dest.display()
)
println!("cargo:warning=Built and installed {wasm_name}.wasm");
} else {
panic!("WASM file not found: {}", wasm_source.display());
fs::remove_file(&cargo_toml).ok();
fs::remove_file(scripts_dir.join("Cargo.lock")).ok();
fs::remove_dir_all(scripts_dir.join("src")).ok();
fs::remove_dir_all(scripts_dir.join("target")).ok();
let nms_files: Vec<_> = entries
.filter(|e| e.path().extension().is_some_and(|ext| ext == "nms"))
for entry in &nms_files {
let nms_path = entry.path();
println!("cargo:rerun-if-changed={}", nms_path.display());
compile_nomiscript(&nms_path, &wasm_output_dir);