From db344962ac1d37f652525d8bd6344e7abdf9afe4 Mon Sep 17 00:00:00 2001 From: zrr1999 <2742392377@qq.com> Date: Sat, 16 May 2026 22:04:23 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20refactor:=20update=20process=5Fr?= =?UTF-8?q?un=5Fstatus=20and=20exit=20signatures=20to=20use=20Option[U8]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Changed `process_run_status` to return `Option[U8]` instead of `I32`, allowing for better handling of exit codes. - Updated `exit` function to accept `U8` instead of `I32` for consistency with the new exit code handling. - Adjusted related documentation in README to reflect changes in runtime support for `basic-cli` applications. --- README.md | 4 ++-- host/src/lib.rs | 41 +++++++++++++++++++++++++---------------- src/basic_cli/cmd.sp | 4 ++-- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 179b512..ceb53b8 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ The current Platform contract MVP is intentionally split across two artifacts: - a hole-backed `main` function carries the authoritative startup signature - `main_for_host` is the Platform-owned adapter that receives the application startup function -Applications targeting `basic-cli` must implement the same startup function name/signature in their entry module. The current compiler already resolves the package's `[platform]` metadata and `src/platform_contract.sp` to validate that startup shape. Runtime support is currently specialized to package-backed `basic-cli`: imported `basic_cli.*` foreign functions route through the built-in basic-cli host profile, while generic handled-effects enforcement and startup `spec` stacking are still follow-up work. +Applications targeting `basic-cli` must implement the same startup function name/signature in their entry module. The current compiler already resolves the package's `[platform]` metadata and `src/platform_contract.sp` to validate that startup shape. Project-mode interpreter runtime support now goes through a generic package-backed host path: imported public `foreign fn` declarations bind by canonical operation name (`print`, `file_exists`, `exit`, etc.) instead of hard-coding the `basic-cli` package name. Startup `spec` stacking and native lowering for `foreign fn` platform projects are still follow-up work. `src/host.sp` remains as a compatibility copy of the adapter for older references; current manifest-backed projects use `src/platform_contract.sp`. @@ -152,7 +152,7 @@ Following Spore's [SEP-0003 (Effect System)](https://github.com/spore-lang/spore The canonical example is the **package-backed project-mode** `examples/hello-app/` application. It already validates and runs with `[project].platform = "basic-cli"`, an in-repo path dependency, and `import basic_cli.stdout`. -The pure standalone file example (`examples/hello.sp`) stays around for quick experiments. The main remaining platform gaps are generic handled-effects enforcement, startup `spec` stacking, native lowering for `foreign fn` platform projects, and lifting the runtime from its current explicit `basic-cli` host profile to a more general package-backed mechanism. +The pure standalone file example (`examples/hello.sp`) stays around for quick experiments. The main remaining platform gaps are startup `spec` stacking and native lowering for `foreign fn` platform projects. ## License diff --git a/host/src/lib.rs b/host/src/lib.rs index f44709e..ee71e3b 100644 --- a/host/src/lib.rs +++ b/host/src/lib.rs @@ -192,15 +192,20 @@ pub fn host_process_run_status(cmd: &str, args: &[String]) -> HostResult { kind: "ExecError".into(), message: format!("{cmd}: {e}"), })?; - Ok(HostValue::Int(status.code().unwrap_or(-1) as i64)) + let code = match status.code() { + Some(code) => { + let code = u8::try_from(code).map_err(|_| HostError { + kind: "ExecError".into(), + message: format!("{cmd}: exit code {code} is out of range for U8"), + })?; + Some(Box::new(HostValue::Int(i64::from(code)))) + } + None => None, + }; + Ok(HostValue::Option(code)) } -pub fn host_exit(code: i64) -> HostResult { - let code = u8::try_from(code).map_err(|_| HostError { - kind: "ExitError".into(), - message: format!("exit code {code} is out of range for 0..=255"), - })?; - +pub fn host_exit(code: u8) -> HostResult { #[cfg(test)] { Err(HostError { @@ -355,11 +360,22 @@ mod tests { fn process_run_status_echo() { let result = host_process_run_status("echo", &["hello".into()]).unwrap(); match result { - HostValue::Int(code) => assert_eq!(code, 0), - _ => panic!("expected Int"), + HostValue::Option(Some(code)) => match *code { + HostValue::Int(code) => assert_eq!(code, 0), + other => panic!("expected U8 code payload, got {other:?}"), + }, + other => panic!("expected Some(U8), got {other:?}"), } } + #[test] + #[cfg(unix)] + fn process_run_status_signal_returns_none() { + let result = host_process_run_status("sh", &["-c".into(), "kill -TERM $$".into()]) + .expect("signal termination should still report status"); + assert!(matches!(result, HostValue::Option(None))); + } + #[test] fn process_run_captures_stdout() { let result = @@ -385,13 +401,6 @@ mod tests { assert!(err.message.contains("17")); } - #[test] - fn exit_rejects_out_of_range_codes() { - let err = host_exit(256).unwrap_err(); - assert_eq!(err.kind, "ExitError"); - assert!(err.message.contains("0..=255")); - } - #[test] fn dispatch_table_has_all_functions() { let table = dispatch_table(); diff --git a/src/basic_cli/cmd.sp b/src/basic_cli/cmd.sp index ded96b4..ca7019b 100644 --- a/src/basic_cli/cmd.sp +++ b/src/basic_cli/cmd.sp @@ -7,7 +7,7 @@ pub foreign fn process_run(cmd: Str, args: List[Str]) -> Str ! ExecError uses [Spawn] /// Run a command and return its exit code. -pub foreign fn process_run_status(cmd: Str, args: List[Str]) -> I32 ! ExecError uses [Spawn] +pub foreign fn process_run_status(cmd: Str, args: List[Str]) -> Option[U8] ! ExecError uses [Spawn] /// Exit the current process with the provided status code. -pub foreign fn exit(code: I32) -> Never uses [Exit] +pub foreign fn exit(code: U8) -> Never uses [Exit]