Add misses init command with binary and library scaffold modes
`misses init [--lib] [dir]` scaffolds a new proc-macro crate that uses misses as its build toolchain. Two modes are supported: Binary mode (default): The .mrs source files live in src/macros/ and are compiled to $OUT_DIR at build time via a generated build.rs. The generated Rust code is never committed — users must have misses installed to build from source. Library mode (--lib): The generated code is committed to generated/ so downstream users of the crate need no misses install at all. The .mrs source and build.rs are still present for the library author, who can regenerate via `cargo build --features misses-source`. The misses-source feature makes misses an optional build-dependency and gates the regeneration path in build.rs with #[cfg(feature)]. The command also teaches `main.rs` a proper subcommand dispatch so that `misses <file.mrs>` (compile) and `misses init` are cleanly separated. https://claude.ai/code/session_01D2g6zGJsBeUEzxBb7AvFDt
This commit is contained in:
+40
-12
@@ -1,17 +1,35 @@
|
||||
mod init;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
if args.len() < 2 {
|
||||
eprintln!("Usage: misses <input.mrs> [output.rs]");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
match args.get(1).map(String::as_str) {
|
||||
Some("init") => {
|
||||
let is_lib = args.iter().any(|a| a == "--lib");
|
||||
let dir = args
|
||||
.iter()
|
||||
.skip(2)
|
||||
.find(|a| !a.starts_with('-'))
|
||||
.map(String::as_str)
|
||||
.unwrap_or(".");
|
||||
init::run(dir, is_lib);
|
||||
}
|
||||
Some(_) => compile(&args),
|
||||
None => {
|
||||
print_usage();
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compile(args: &[String]) {
|
||||
let input_path = PathBuf::from(&args[1]);
|
||||
let src = match std::fs::read_to_string(&input_path) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
eprintln!("Error reading {:?}: {}", input_path, e);
|
||||
eprintln!("error reading {}: {}", input_path.display(), e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
@@ -19,7 +37,7 @@ fn main() {
|
||||
let ast = match misses::parse(&src) {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
eprintln!("Parse error: {}", e);
|
||||
eprintln!("parse error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
@@ -28,14 +46,24 @@ fn main() {
|
||||
|
||||
if args.len() >= 3 {
|
||||
let output_path = PathBuf::from(&args[2]);
|
||||
match std::fs::write(&output_path, &generated) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
eprintln!("Error writing {:?}: {}", output_path, e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
if let Err(e) = std::fs::write(&output_path, &generated) {
|
||||
eprintln!("error writing {}: {}", output_path.display(), e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
} else {
|
||||
print!("{}", generated);
|
||||
}
|
||||
}
|
||||
|
||||
fn print_usage() {
|
||||
eprintln!("Usage:");
|
||||
eprintln!(" misses <input.mrs> [output.rs] Compile a .mrs file to Rust");
|
||||
eprintln!(" misses init [--lib] [dir] Scaffold a new misses project");
|
||||
eprintln!();
|
||||
eprintln!("Modes for `misses init`:");
|
||||
eprintln!(" (default) Binary — .mrs sources are compiled at build time via build.rs;");
|
||||
eprintln!(" generated code lives in \\$OUT_DIR and is never committed.");
|
||||
eprintln!(" --lib Library — generated code is committed to generated/ so");
|
||||
eprintln!(" downstream users need no misses install. Rebuild with");
|
||||
eprintln!(" `cargo build --features misses-source`.");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user