@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 +104 -99
- package/package.json +1 -1
- package/stak_wasm_bg.wasm +0 -0
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
|
-
###
|
|
44
|
+
### Dynamic scripting in Rust
|
|
45
45
|
|
|
46
|
-
First, prepare a Scheme script
|
|
46
|
+
First, prepare a Scheme script named `src/fight.scm`:
|
|
47
47
|
|
|
48
48
|
```scheme
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
70
|
-
file::VoidFileSystem,
|
|
105
|
+
engine::{Engine, EngineError},
|
|
71
106
|
include_module,
|
|
72
|
-
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
129
|
+
/// Returns a number of pies the person has.
|
|
130
|
+
pub fn pies(&self) -> usize {
|
|
131
|
+
self.pies
|
|
132
|
+
}
|
|
114
133
|
|
|
115
|
-
|
|
134
|
+
/// Returns `true` if a person is wasted.
|
|
135
|
+
pub fn wasted(&self) -> bool {
|
|
136
|
+
self.wasted
|
|
137
|
+
}
|
|
116
138
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
131
|
-
const HEAP_SIZE: usize = 1 << 16;
|
|
145
|
+
self.pies -= 1;
|
|
132
146
|
|
|
133
|
-
|
|
147
|
+
if random::<f64>() > other.dodge {
|
|
148
|
+
other.wasted = true;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
134
152
|
|
|
135
153
|
fn main() -> Result<(), Box<dyn Error>> {
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
//
|
|
148
|
-
|
|
157
|
+
// Run the Scheme module.
|
|
158
|
+
run_scheme(&MODULE)?;
|
|
149
159
|
|
|
150
160
|
Ok(())
|
|
151
161
|
}
|
|
152
162
|
|
|
153
|
-
fn
|
|
154
|
-
|
|
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
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
package/stak_wasm_bg.wasm
CHANGED
|
Binary file
|