@raviqqe/stak 0.3.23 → 0.3.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,6 +19,14 @@ For more information and usage, visit [the full documentation](https://raviqqe.g
19
19
 
20
20
  ## Install
21
21
 
22
+ ### Interpreter
23
+
24
+ To install the Scheme interpreter as a command, run:
25
+
26
+ ```sh
27
+ cargo install stak
28
+ ```
29
+
22
30
  ### Libraries
23
31
 
24
32
  To install Stak Scheme as a library in your Rust project, run:
@@ -31,27 +39,53 @@ cargo install stak-compile
31
39
 
32
40
  For full examples, see [the `examples` directory](https://github.com/raviqqe/stak/tree/main/examples).
33
41
 
34
- ### Command line tools
35
-
36
- To install the Scheme interpreter as a command, run:
37
-
38
- ```sh
39
- cargo install stak
40
- ```
41
-
42
42
  ## Examples
43
43
 
44
- ### Embedding Scheme scripts in Rust
44
+ ### Dynamic scripting in Rust
45
45
 
46
- First, prepare a Scheme script at `src/hello.scm`.
46
+ First, prepare a Scheme script named `src/fight.scm`:
47
47
 
48
48
  ```scheme
49
- (import (scheme base))
50
-
51
- (write-string "Hello, world!\n")
49
+ ; Import a base library and the library named `(stak rust)` for Rust integration.
50
+ (import (scheme base) (stak rust))
51
+
52
+ ; Use the `define-rust` procedure to import native functions written in Rust.
53
+ ; The order of the functions should match the ones passed into the `Engine::new()`
54
+ ; function in Rust.
55
+ (define-rust
56
+ make-person
57
+ person-pies
58
+ person-wasted
59
+ person-throw-pie)
60
+
61
+ ; Make two people with a number of pies they have and their dodge rates.
62
+ (define me (make-person 4 0.2))
63
+ (define friend (make-person 2 0.6))
64
+
65
+ ; The fight begins. Let's throw pies to each other!
66
+ (do ()
67
+ ((or
68
+ (person-wasted me)
69
+ (person-wasted friend)
70
+ (and
71
+ (zero? (person-pies me))
72
+ (zero? (person-pies friend)))))
73
+ (person-throw-pie me friend)
74
+ (person-throw-pie friend me))
75
+
76
+ ; Output the winner.
77
+ (write-string
78
+ (cond
79
+ ((person-wasted friend)
80
+ "You won!")
81
+ ((person-wasted me)
82
+ "You lost...")
83
+ (else
84
+ "Draw...")))
52
85
  ```
53
86
 
54
- Then, add a build script at `build.rs` to build the Scheme source file into bytecodes.
87
+ Then, add a build script at `build.rs` to build the Scheme source file
88
+ into bytecodes.
55
89
 
56
90
  ```rust no_run
57
91
  use stak_build::{build_r7rs, BuildError};
@@ -61,115 +95,86 @@ fn main() -> Result<(), BuildError> {
61
95
  }
62
96
  ```
63
97
 
64
- Now, you can include the Scheme script into a program in Rust using [the `stak::include_module` macro](https://docs.rs/stak/latest/stak/macro.include_module.html).
98
+ Finally, you can embed and run the Scheme script in a Rust program.
65
99
 
66
100
  ```rust
101
+ use any_fn::{r#fn, Ref};
67
102
  use core::error::Error;
103
+ use rand::random;
68
104
  use stak::{
69
- device::StdioDevice,
70
- file::VoidFileSystem,
105
+ engine::{Engine, EngineError},
71
106
  include_module,
72
- process_context::VoidProcessContext,
73
- module::{Module, UniversalModule},
74
- r7rs::{SmallError, SmallPrimitiveSet},
75
- time::VoidClock,
76
- vm::Vm,
107
+ module::UniversalModule,
77
108
  };
78
109
 
79
110
  const HEAP_SIZE: usize = 1 << 16;
80
111
 
81
- // Include a Scheme script in the bytecode format built by the build script above.
82
- static MODULE: UniversalModule = include_module!("hello.scm");
83
-
84
- fn main() -> Result<(), Box<dyn Error>> {
85
- run(&MODULE.bytecode())?;
86
-
87
- Ok(())
112
+ /// A person who holds pies to throw.
113
+ struct Person {
114
+ pies: usize,
115
+ dodge: f64,
116
+ wasted: bool,
88
117
  }
89
118
 
90
- fn run(bytecodes: &[u8]) -> Result<(), SmallError> {
91
- // Prepare a heap memory of a virtual machine.
92
- let mut heap = [Default::default(); HEAP_SIZE];
93
- // Create a virtual machine with its heap memory primitive procedures.
94
- let mut vm = Vm::new(
95
- &mut heap,
96
- SmallPrimitiveSet::new(
97
- // Attach standard input, output, and error of this process to a virtual machine.
98
- StdioDevice::new(),
99
- // Use void system interfaces for security because we don't need them for this example.
100
- VoidFileSystem::new(),
101
- VoidProcessContext::new(),
102
- VoidClock::new(),
103
- ),
104
- )?;
105
-
106
- // Initialize a virtual machine with bytecodes.
107
- vm.initialize(bytecodes.iter().copied())?;
108
- // Run bytecodes on a virtual machine.
109
- vm.run()
110
- }
111
- ```
119
+ impl Person {
120
+ /// Creates a person.
121
+ pub fn new(pies: usize, dodge: f64) -> Self {
122
+ Self {
123
+ pies,
124
+ dodge,
125
+ wasted: false,
126
+ }
127
+ }
112
128
 
113
- ### Communication between Scheme and Rust
129
+ /// Returns a number of pies the person has.
130
+ pub fn pies(&self) -> usize {
131
+ self.pies
132
+ }
114
133
 
115
- Currently, in-memory standard input (`stdin`) and output (`stdout`) to Scheme scripts are the only way to communicate information between Rust programs and Scheme scripts.
134
+ /// Returns `true` if a person is wasted.
135
+ pub fn wasted(&self) -> bool {
136
+ self.wasted
137
+ }
116
138
 
117
- ```rust
118
- use core::{error::Error, str::{self, FromStr}};
119
- use stak::{
120
- device::ReadWriteDevice,
121
- file::VoidFileSystem,
122
- include_module,
123
- process_context::VoidProcessContext,
124
- module::{Module, UniversalModule},
125
- r7rs::{SmallError, SmallPrimitiveSet},
126
- time::VoidClock,
127
- vm::Vm,
128
- };
139
+ /// Throws a pie to another person.
140
+ pub fn throw_pie(&mut self, other: &mut Person) {
141
+ if self.pies == 0 || self.wasted {
142
+ return;
143
+ }
129
144
 
130
- const BUFFER_SIZE: usize = 1 << 8;
131
- const HEAP_SIZE: usize = 1 << 16;
145
+ self.pies -= 1;
132
146
 
133
- static MODULE: UniversalModule = include_module!("fibonacci.scm");
147
+ if random::<f64>() > other.dodge {
148
+ other.wasted = true;
149
+ }
150
+ }
151
+ }
134
152
 
135
153
  fn main() -> Result<(), Box<dyn Error>> {
136
- let input = 15;
137
- let mut output = vec![];
138
- let mut error = vec![];
139
-
140
- run(&MODULE.bytecode(), input.to_string().as_bytes(), &mut output, &mut error)?;
141
-
142
- // If stderr is not empty, we assume that some error has occurred.
143
- if !error.is_empty() {
144
- return Err(str::from_utf8(&error)?.into());
145
- }
154
+ // Import a Scheme module of the script.
155
+ static MODULE: UniversalModule = include_module!("fight.scm");
146
156
 
147
- // Decode and test the output.
148
- assert_eq!(isize::from_str(&str::from_utf8(&output)?)?, 610);
157
+ // Run the Scheme module.
158
+ run_scheme(&MODULE)?;
149
159
 
150
160
  Ok(())
151
161
  }
152
162
 
153
- fn run(
154
- bytecodes: &[u8],
155
- input: &[u8],
156
- output: &mut Vec<u8>,
157
- error: &mut Vec<u8>,
158
- ) -> Result<(), SmallError> {
163
+ fn run_scheme(module: &'static UniversalModule) -> Result<(), EngineError> {
164
+ // Initialize a heap memory for a Scheme scripting engine.
159
165
  let mut heap = [Default::default(); HEAP_SIZE];
160
- let mut vm = Vm::new(
161
- &mut heap,
162
- SmallPrimitiveSet::new(
163
- // Create and attach an in-memory I/O device.
164
- ReadWriteDevice::new(input, output, error),
165
- VoidFileSystem::new(),
166
- VoidProcessContext::new(),
167
- VoidClock::new(),
168
- ),
169
- )?;
170
-
171
- vm.initialize(bytecodes.iter().copied())?;
172
- vm.run()
166
+ // Define Rust functions to pass to the engine.
167
+ let mut functions = [
168
+ r#fn(Person::new),
169
+ r#fn::<(Ref<_>,), _>(Person::pies),
170
+ r#fn::<(Ref<_>,), _>(Person::wasted),
171
+ r#fn(Person::throw_pie),
172
+ ];
173
+ // Initialize the engine.
174
+ let mut engine = Engine::new(&mut heap, &mut functions)?;
175
+
176
+ // Finally, run the module!
177
+ engine.run(module)
173
178
  }
174
179
  ```
175
180
 
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@raviqqe/stak",
3
3
  "type": "module",
4
4
  "description": "Stak Scheme in WebAssembly",
5
- "version": "0.3.23",
5
+ "version": "0.3.25",
6
6
  "license": "SEE LICENSE IN ../LICENSE",
7
7
  "repository": {
8
8
  "type": "git",
package/stak_wasm_bg.wasm CHANGED
Binary file