Skip to content

Commit 7bf8672

Browse files
committed
Add Rust-backed run command
1 parent bbcd886 commit 7bf8672

3 files changed

Lines changed: 82 additions & 3 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,11 +402,12 @@ rss review [--json] --diff <old.rss> <new.rss>
402402
rss review [--json] --map <file-or-directory>
403403
rss lower --rust <file.rss>
404404
rss lower --rust <file.rss> --out-dir <directory>
405+
rss run <file.rss>
405406
rss remap-rustc [--json] <rsscript-source-map.json> <rustc-json-lines>
406407
rss verify-rust [--json] <file.rss>
407408
```
408409

409-
If a lowered package contains `fn main() -> Unit`, `rss lower --rust --out-dir` also emits a Rust `src/main.rs` harness. That package can be checked or run with Cargo once the generated Rust and runtime crate are supported by the local toolchain.
410+
If a lowered package contains `fn main() -> Unit`, `rss lower --rust --out-dir` also emits a Rust `src/main.rs` harness. `rss run <file.rss>` uses the same lowering path, writes a temporary Rust package, and delegates execution to `cargo run`.
410411

411412
---
412413

RSScript_v0.5_Spec.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,8 @@ RSScript source
293293
-> executable / library
294294
```
295295

296+
`rss run <file.rss>` is a convenience command over this pipeline. It lowers the file to a temporary Rust package and invokes Cargo on that package. It is not an interpreter and must not bypass frontend diagnostics, source mapping, or the runtime crate target ABI.
297+
296298
The RSScript frontend is responsible for RSScript semantics.
297299

298300
rustc is responsible for:

src/main.rs

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::env;
22
use std::fs;
33
use std::path::{Path, PathBuf};
4-
use std::process::ExitCode;
4+
use std::process::{Command, ExitCode};
55
use std::time::{SystemTime, UNIX_EPOCH};
66

77
use rsscript::{
@@ -26,6 +26,7 @@ fn main() -> ExitCode {
2626
"fmt" => run_fmt(&args[2..]),
2727
"review" => run_review(&args[2..]),
2828
"lower" => run_lower(&args[2..]),
29+
"run" => run_generated_rust(&args[2..]),
2930
"remap-rustc" => run_remap_rustc(&args[2..]),
3031
"verify-rust" => run_verify_rust(&args[2..]),
3132
_ => {
@@ -290,6 +291,72 @@ fn run_verify_rust(args: &[String]) -> ExitCode {
290291
}
291292
}
292293

294+
fn run_generated_rust(args: &[String]) -> ExitCode {
295+
let (_, path) = parse_path_args(args);
296+
let Some(path) = path else {
297+
print_usage();
298+
return ExitCode::from(2);
299+
};
300+
let source = match fs::read_to_string(path) {
301+
Ok(source) => source,
302+
Err(error) => {
303+
eprintln!("failed to read {path}: {error}");
304+
return ExitCode::from(2);
305+
}
306+
};
307+
let runtime_path = match default_runtime_path() {
308+
Ok(path) => path,
309+
Err(error) => {
310+
eprintln!("{error}");
311+
return ExitCode::from(2);
312+
}
313+
};
314+
let package_name = generated_package_name(path);
315+
let package = match lower_source_to_rust_package(
316+
path,
317+
&source,
318+
&package_name,
319+
&runtime_path.display().to_string(),
320+
) {
321+
Ok(package) => package,
322+
Err(diagnostics) => {
323+
print_diagnostics(false, &diagnostics);
324+
return ExitCode::from(1);
325+
}
326+
};
327+
if package.main_rs.is_none() {
328+
eprintln!("rss run requires a zero-argument `fn main() -> Unit`.");
329+
return ExitCode::from(1);
330+
}
331+
332+
let temp_dir = run_temp_dir(&package.package_name);
333+
if let Err(error) = write_generated_rust_package(&temp_dir, &package) {
334+
eprintln!("{error}");
335+
cleanup_temp_dir(&temp_dir);
336+
return ExitCode::from(2);
337+
}
338+
let status = match Command::new("cargo")
339+
.arg("run")
340+
.arg("--quiet")
341+
.arg("--manifest-path")
342+
.arg(temp_dir.join("Cargo.toml"))
343+
.status()
344+
{
345+
Ok(status) => status,
346+
Err(error) => {
347+
eprintln!("failed to run cargo: {error}");
348+
cleanup_temp_dir(&temp_dir);
349+
return ExitCode::from(2);
350+
}
351+
};
352+
cleanup_temp_dir(&temp_dir);
353+
354+
status
355+
.code()
356+
.map(|code| ExitCode::from(code as u8))
357+
.unwrap_or_else(|| ExitCode::from(1))
358+
}
359+
293360
fn run_remap_rustc(args: &[String]) -> ExitCode {
294361
let (json, paths) = parse_multi_path_args(args);
295362
let [source_map_path, rustc_json_path] = paths.as_slice() else {
@@ -503,12 +570,20 @@ fn generated_package_name(path: &str) -> String {
503570
}
504571

505572
fn verify_temp_dir(package_name: &str) -> PathBuf {
573+
temp_package_dir("rsscript-verify", package_name)
574+
}
575+
576+
fn run_temp_dir(package_name: &str) -> PathBuf {
577+
temp_package_dir("rsscript-run", package_name)
578+
}
579+
580+
fn temp_package_dir(prefix: &str, package_name: &str) -> PathBuf {
506581
let now = SystemTime::now()
507582
.duration_since(UNIX_EPOCH)
508583
.map(|duration| duration.as_nanos())
509584
.unwrap_or(0);
510585
env::temp_dir().join(format!(
511-
"rsscript-verify-{package_name}-{}-{now}",
586+
"{prefix}-{package_name}-{}-{now}",
512587
std::process::id()
513588
))
514589
}
@@ -684,6 +759,7 @@ fn print_usage() {
684759
eprintln!(" rsscript fmt <file.rss>");
685760
eprintln!(" rsscript lower --rust <file.rss>");
686761
eprintln!(" rsscript lower --rust <file.rss> --out-dir <directory>");
762+
eprintln!(" rsscript run <file.rss>");
687763
eprintln!(" rsscript remap-rustc [--json] <rsscript-source-map.json> <rustc-json-lines>");
688764
eprintln!(" rsscript verify-rust [--json] <file.rss>");
689765
eprintln!(" rsscript review [--json] --diff <old.rss> <new.rss>");

0 commit comments

Comments
 (0)