From 29e5123ef2e9a100b45e33e6c5f47c188fe376c0 Mon Sep 17 00:00:00 2001 From: Reuben Brooks Date: Thu, 27 Aug 2026 05:06:31 -0500 Subject: [PATCH 1/2] Add optional Nix development environment --- .envrc | 1 + README.md | 19 +++++++++++++++++ flake.lock | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 23 +++++++++++++------- 4 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 .envrc create mode 100644 flake.lock diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/README.md b/README.md index cedc185..c06c660 100644 --- a/README.md +++ b/README.md @@ -217,3 +217,22 @@ wrapper that skips gracefully if the tool isn't installed). [BSD-3-Clause](LICENSE) for the port code (© 2026 Reuben Brooks). The vendored Shen kernel under `kernel/` is © 2010–2022 Mark Tarver and retains its own BSD-3-Clause license (`kernel/LICENSE.txt`). +## Optional Nix environment + +Nix is optional; the normal shen-rust build and launcher commands continue to work +with tools installed by any method. For a pinned development toolchain: + +```sh +nix develop +``` + +The flake also exports `packages.toolchain` for composition by +[Bifrost](https://github.com/pyrex41/bifrost): + +```sh +nix shell .#toolchain +``` + +If direnv is installed, `direnv allow` opts this checkout into the same dev +shell automatically. Nothing activates until that explicit authorization, and +Nix is never required at runtime. diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..626f2ea --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1787631388, + "narHash": "sha256-vMiXptXarfSdJb1Gkc+FYVOAibuBRj7qxGa8z68q1Uw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ac6b2166e7a9375683b8e98f860f273222337b16", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix index 710077f..4874c5c 100644 --- a/flake.nix +++ b/flake.nix @@ -10,16 +10,23 @@ flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; + tools = [ + pkgs.rustc + pkgs.cargo + pkgs.rustfmt + pkgs.clippy + pkgs.rust-analyzer + pkgs.pkg-config + ]; in { + packages.toolchain = pkgs.buildEnv { + name = "shen-rust-toolchain"; + paths = tools; + }; + packages.default = self.packages.${system}.toolchain; + devShells.default = pkgs.mkShell { - buildInputs = [ - pkgs.rustc - pkgs.cargo - pkgs.rustfmt - pkgs.clippy - pkgs.rust-analyzer - pkgs.pkg-config - ]; + packages = tools; shellHook = '' echo "shen-rust dev shell" From 822bdea08bc6b9604af924b5572193b5dbf8fdd6 Mon Sep 17 00:00:00 2001 From: Reuben Brooks Date: Thu, 27 Aug 2026 05:23:52 -0500 Subject: [PATCH 2/2] Format Rust sources --- crates/shen-rust/src/primitives.rs | 11 +++++------ crates/shen-rust/tests/boot_kernel.rs | 14 +++++++++++--- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/crates/shen-rust/src/primitives.rs b/crates/shen-rust/src/primitives.rs index ff5d420..3ed887e 100644 --- a/crates/shen-rust/src/primitives.rs +++ b/crates/shen-rust/src/primitives.rs @@ -401,12 +401,11 @@ fn register_core(interp: &mut Interp) { ))), }); interp.register_native("string->n", 1, |_, args| match args[0].as_str() { - Some(s) => { - s.chars() - .next() - .map(|c| Value::int(c as i64)) - .ok_or_else(|| ShenError::new("string->n: empty string")) - } + Some(s) => s + .chars() + .next() + .map(|c| Value::int(c as i64)) + .ok_or_else(|| ShenError::new("string->n: empty string")), None => Err(ShenError::new(format!( "string->n: not a string: {:?}", args[0] diff --git a/crates/shen-rust/tests/boot_kernel.rs b/crates/shen-rust/tests/boot_kernel.rs index 942d693..4c236b8 100644 --- a/crates/shen-rust/tests/boot_kernel.rs +++ b/crates/shen-rust/tests/boot_kernel.rs @@ -93,7 +93,10 @@ fn shen_batteries_features_query_reports_sha_host() { let value = eval(&mut interp, "(shen.x.features.current)"); let pure = std::env::var("SHEN_X_SHA256").ok().as_deref() == Some("pure"); if pure { - assert!(value.is_nil(), "pure SHA mode must advertise no host feature: {value:?}"); + assert!( + value.is_nil(), + "pure SHA mode must advertise no host feature: {value:?}" + ); } else { let feature = value .head() @@ -108,8 +111,13 @@ fn shen_batteries_features_query_reports_sha_host() { let sym = interp.intern("shen.x.features.current"); let direct = interp.get_aot_direct(sym).expect("AOT feature query"); let direct_value = direct(&mut interp, &[]).expect("feature query succeeds"); - assert_eq!(direct_value.head().and_then(|v| v.as_sym()).map(|s| interp.resolve(s).to_string()), - Some("shen.x/sha256-host".to_string())); + assert_eq!( + direct_value + .head() + .and_then(|v| v.as_sym()) + .map(|s| interp.resolve(s).to_string()), + Some("shen.x/sha256-host".to_string()) + ); } }