{"id":15399342,"url":"https://github.com/raviqqe/stak","last_synced_at":"2025-05-16T13:04:03.086Z","repository":{"id":178215203,"uuid":"661526011","full_name":"raviqqe/stak","owner":"raviqqe","description":"The miniature, embeddable R7RS Scheme implementation in Rust","archived":false,"fork":false,"pushed_at":"2025-05-12T23:25:33.000Z","size":7118,"stargazers_count":91,"open_issues_count":18,"forks_count":1,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-05-13T00:24:20.177Z","etag":null,"topics":["no-alloc","no-std","rust","scheme","script"],"latest_commit_sha":null,"homepage":"https://raviqqe.com/stak/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/raviqqe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-07-03T04:33:11.000Z","updated_at":"2025-05-12T07:02:17.000Z","dependencies_parsed_at":"2023-11-27T08:30:01.560Z","dependency_job_id":"db7dd3be-921c-4ff2-9492-8a4059a01c2e","html_url":"https://github.com/raviqqe/stak","commit_stats":{"total_commits":1510,"total_committers":2,"mean_commits":755.0,"dds":"0.37483443708609276","last_synced_commit":"d7af46dbae9195099689ece7770dd668eced0ebe"},"previous_names":["raviqqe/nil-scheme"],"tags_count":102,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raviqqe%2Fstak","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raviqqe%2Fstak/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raviqqe%2Fstak/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/raviqqe%2Fstak/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/raviqqe","download_url":"https://codeload.github.com/raviqqe/stak/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253851071,"owners_count":21973674,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["no-alloc","no-std","rust","scheme","script"],"created_at":"2024-10-01T15:48:14.977Z","updated_at":"2025-05-16T13:04:03.078Z","avatar_url":"https://github.com/raviqqe.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Stak Scheme\n\n[![GitHub Action](https://img.shields.io/github/actions/workflow/status/raviqqe/stak/test.yaml?branch=main\u0026style=flat-square)](https://github.com/raviqqe/stak/actions)\n[![Crate](https://img.shields.io/crates/v/stak.svg?style=flat-square)](https://crates.io/crates/stak)\n[![Codecov](https://img.shields.io/codecov/c/github/raviqqe/stak.svg?style=flat-square)](https://codecov.io/gh/raviqqe/stak)\n[![CodSpeed](https://img.shields.io/endpoint?url=https://codspeed.io/badge.json\u0026style=flat-square)](https://codspeed.io/raviqqe/stak)\n[![License](https://img.shields.io/github/license/raviqqe/stak.svg?style=flat-square)](https://github.com/raviqqe/stak/blob/main/LICENSE)\n\nThe miniature, embeddable R7RS Scheme implementation in Rust\n\nStak Scheme aims to be:\n\n- An embeddable Scheme interpreter for Rust with very small memory footprint and reasonable performance\n  - Its virtual machine (VM) is written in only 1.4 KLOC in Rust.\n- The minimal implementation of [the R7RS-small standard][r7rs-small]\n  - A subset of [Chibi Scheme](https://github.com/ashinn/chibi-scheme), [Gauche](https://github.com/shirok/Gauche), and [Guile](https://www.gnu.org/software/guile/)\n- A portable scripting environment that supports even no-`std` and no-`alloc` platforms\n\nFor more information and usage, visit [the full documentation](https://raviqqe.com/stak/install).\n\n## Install\n\n### Interpreter\n\nTo install the Scheme interpreter as a command, run:\n\n```sh\ncargo install stak\n```\n\n### Libraries\n\nTo install Stak Scheme as a library in your Rust project, run:\n\n```sh\ncargo add stak\ncargo add --build stak-build\ncargo install stak-compile\n```\n\nFor full examples, see [the `examples` directory](https://github.com/raviqqe/stak/tree/main/examples).\n\n## Examples\n\n### Dynamic scripting in Rust\n\nFirst, prepare a Scheme script named `src/fight.scm`:\n\n```scheme\n; Import a base library and the library named `(stak rust)` for Rust integration.\n(import (scheme base) (stak rust))\n\n; Make two people with a number of pies they have and their dodge rates.\n(define me (make-person 4 0.2))\n(define friend (make-person 2 0.6))\n\n; The fight begins. Let's throw pies to each other!\n(do ()\n  ((or\n      (person-wasted me)\n      (person-wasted friend)\n      (and\n        (zero? (person-pies me))\n        (zero? (person-pies friend)))))\n  (person-throw-pie me friend)\n  (person-throw-pie friend me))\n\n; Output the winner.\n(write-string\n  (cond\n    ((person-wasted friend)\n      \"You won!\")\n    ((person-wasted me)\n      \"You lost...\")\n    (else\n      \"Draw...\")))\n```\n\nThen, add a build script at `build.rs` to build the Scheme source file\ninto bytecodes.\n\n```rust no_run\nuse stak_build::{build_r7rs, BuildError};\n\nfn main() -\u003e Result\u003c(), BuildError\u003e {\n    build_r7rs()\n}\n```\n\nFinally, you can embed and run the Scheme script in a Rust program.\n\n```rust\nuse any_fn::{r#fn, Ref};\nuse core::error::Error;\nuse rand::random;\nuse stak::{\n    engine::{Engine, EngineError},\n    include_module,\n    module::UniversalModule,\n};\n\nconst HEAP_SIZE: usize = 1 \u003c\u003c 16;\n\n/// A person who holds pies to throw.\nstruct Person {\n    pies: usize,\n    dodge: f64,\n    wasted: bool,\n}\n\nimpl Person {\n    /// Creates a person.\n    pub fn new(pies: usize, dodge: f64) -\u003e Self {\n        Self {\n            pies,\n            dodge,\n            wasted: false,\n        }\n    }\n\n    /// Returns a number of pies the person has.\n    pub fn pies(\u0026self) -\u003e usize {\n        self.pies\n    }\n\n    /// Returns `true` if a person is wasted.\n    pub fn wasted(\u0026self) -\u003e bool {\n        self.wasted\n    }\n\n    /// Throws a pie to another person.\n    pub fn throw_pie(\u0026mut self, other: \u0026mut Person) {\n        if self.pies == 0 || self.wasted {\n            return;\n        }\n\n        self.pies -= 1;\n\n        if random::\u003cf64\u003e() \u003e other.dodge {\n            other.wasted = true;\n        }\n    }\n}\n\nfn main() -\u003e Result\u003c(), Box\u003cdyn Error\u003e\u003e {\n    // Include and run the Scheme module.\n    run_scheme(\u0026include_module!(\"fight.scm\"))?;\n\n    Ok(())\n}\n\nfn run_scheme(module: \u0026UniversalModule) -\u003e Result\u003c(), EngineError\u003e {\n    // Initialize a heap memory for a Scheme scripting engine.\n    let mut heap = [Default::default(); HEAP_SIZE];\n    // Define Rust functions to pass to the engine.\n    let mut functions = [\n        (\"make-person\", r#fn(Person::new)),\n        (\"person-pies\", r#fn::\u003c(Ref\u003c_\u003e,), _\u003e(Person::pies)),\n        (\"person-wasted\", r#fn::\u003c(Ref\u003c_\u003e,), _\u003e(Person::wasted)),\n        (\"person-throw-pie\", r#fn(Person::throw_pie)),\n    ];\n    // Initialize the engine.\n    let mut engine = Engine::new(\u0026mut heap, \u0026mut functions)?;\n\n    // Finally, run the module!\n    engine.run(module)\n}\n```\n\n## Performance\n\n### Computational benchmarks\n\nThe Stak Scheme interpreter runs 1.6 to 2.3 times slower than Python 3 at computationally heavy tasks depending on its configuration and benchmarks. For all the benchmark results, see [the GitHub Action](https://github.com/raviqqe/stak/actions/workflows/bench.yaml).\n\n- Baseline: Python 3.13\n- Environment: Ubuntu 24.04, x86-64\n\n| Benchmark        | Stak (minimal [^1]) | Stak (full [^2]) |\n| ---------------- | ------------------: | ---------------: |\n| Fibonacci number |        1.80x slower |     1.98x slower |\n| Integer sum      |        1.61x slower |     1.87x slower |\n| Tak function     |        2.10x slower |     2.27x slower |\n\n### Startup benchmarks\n\nAlthough Stak Scheme's minimality comes at the cost of speed, it is very fast at startup.\n\nThis means that Stak Scheme is suitable for embedding many small pieces of Scheme programs in Rust due to its tiny overhead on program initialization.\n\n- Environment: Ubuntu 24.04, x86-64\n\n| Benchmark     | Stak (full [^2]) | Lua 5.4 |\n| ------------- | ---------------: | ------: |\n| Empty program |         0.528 us | 50.9 us |\n\n[^1]: Minimal: Integer-only support + standard libraries based on libc\n\n[^2]: Full: 64-bit floating-point number support + standard libraries based on the `std` library in Rust\n\n## References\n\n- This project is based on [Ribbit Scheme][ribbit], the small and portable R4RS implementation.\n- [Scheme programming language][scheme]\n- [The R7RS-small standard][r7rs-small]\n\n## License\n\n[MIT](https://github.com/raviqqe/stak/blob/main/LICENSE)\n\n[scheme]: https://www.scheme.org/\n[r7rs-small]: https://small.r7rs.org/\n[ribbit]: https://github.com/udem-dlteam/ribbit\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fraviqqe%2Fstak","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fraviqqe%2Fstak","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fraviqqe%2Fstak/lists"}