@rhost/testkit 1.5.0 → 1.5.2
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/node_modules/@ursamu/mushcode/.github/workflows/publish.yml +36 -0
- package/node_modules/@ursamu/mushcode/LICENSE +21 -0
- package/node_modules/@ursamu/mushcode/README.md +110 -0
- package/node_modules/@ursamu/mushcode/_dist/mod.d.ts +36 -0
- package/node_modules/@ursamu/mushcode/_dist/mod.d.ts.map +1 -0
- package/node_modules/@ursamu/mushcode/_dist/parser/mod.d.ts +41 -0
- package/node_modules/@ursamu/mushcode/_dist/parser/mod.d.ts.map +1 -0
- package/node_modules/@ursamu/mushcode/_dist/src/analyze/commands.d.ts +15 -0
- package/node_modules/@ursamu/mushcode/_dist/src/analyze/commands.d.ts.map +1 -0
- package/node_modules/@ursamu/mushcode/_dist/src/analyze/deps.d.ts +18 -0
- package/node_modules/@ursamu/mushcode/_dist/src/analyze/deps.d.ts.map +1 -0
- package/node_modules/@ursamu/mushcode/_dist/src/analyze/mod.d.ts +20 -0
- package/node_modules/@ursamu/mushcode/_dist/src/analyze/mod.d.ts.map +1 -0
- package/node_modules/@ursamu/mushcode/_dist/src/analyze/tags.d.ts +6 -0
- package/node_modules/@ursamu/mushcode/_dist/src/analyze/tags.d.ts.map +1 -0
- package/node_modules/@ursamu/mushcode/_dist/src/eval/context.d.ts +85 -0
- package/node_modules/@ursamu/mushcode/_dist/src/eval/context.d.ts.map +1 -0
- package/node_modules/@ursamu/mushcode/_dist/src/eval/engine.d.ts +48 -0
- package/node_modules/@ursamu/mushcode/_dist/src/eval/engine.d.ts.map +1 -0
- package/node_modules/@ursamu/mushcode/_dist/src/eval/mod.d.ts +26 -0
- package/node_modules/@ursamu/mushcode/_dist/src/eval/mod.d.ts.map +1 -0
- package/node_modules/@ursamu/mushcode/_dist/src/eval/stdlib/mod.d.ts +3 -0
- package/node_modules/@ursamu/mushcode/_dist/src/eval/stdlib/mod.d.ts.map +1 -0
- package/node_modules/@ursamu/mushcode/_dist/src/lint/mod.d.ts +38 -0
- package/node_modules/@ursamu/mushcode/_dist/src/lint/mod.d.ts.map +1 -0
- package/node_modules/@ursamu/mushcode/_dist/src/print/mod.d.ts +18 -0
- package/node_modules/@ursamu/mushcode/_dist/src/print/mod.d.ts.map +1 -0
- package/node_modules/@ursamu/mushcode/_dist/src/print/printer.d.ts +15 -0
- package/node_modules/@ursamu/mushcode/_dist/src/print/printer.d.ts.map +1 -0
- package/node_modules/@ursamu/mushcode/_dist/src/traverse/mod.d.ts +19 -0
- package/node_modules/@ursamu/mushcode/_dist/src/traverse/mod.d.ts.map +1 -0
- package/node_modules/@ursamu/mushcode/_dist/src/traverse/transform.d.ts +27 -0
- package/node_modules/@ursamu/mushcode/_dist/src/traverse/transform.d.ts.map +1 -0
- package/node_modules/@ursamu/mushcode/_dist/src/traverse/walk.d.ts +27 -0
- package/node_modules/@ursamu/mushcode/_dist/src/traverse/walk.d.ts.map +1 -0
- package/node_modules/@ursamu/mushcode/deno.json +26 -0
- package/node_modules/@ursamu/mushcode/deno.lock +42 -0
- package/node_modules/@ursamu/mushcode/docs/analyze.md +145 -0
- package/node_modules/@ursamu/mushcode/docs/eval.md +312 -0
- package/node_modules/@ursamu/mushcode/docs/lint.md +152 -0
- package/node_modules/@ursamu/mushcode/docs/parser.md +196 -0
- package/node_modules/@ursamu/mushcode/docs/print.md +84 -0
- package/node_modules/@ursamu/mushcode/docs/stdlib.md +418 -0
- package/node_modules/@ursamu/mushcode/docs/traverse.md +167 -0
- package/node_modules/@ursamu/mushcode/grammar/mux-softcode.pegjs +781 -0
- package/node_modules/@ursamu/mushcode/mod.js +44 -0
- package/node_modules/@ursamu/mushcode/mod.js.map +1 -0
- package/node_modules/@ursamu/mushcode/mod.ts +63 -0
- package/node_modules/@ursamu/mushcode/package.json +38 -0
- package/node_modules/@ursamu/mushcode/parser/mod.js +47 -0
- package/node_modules/@ursamu/mushcode/parser/mod.js.map +1 -0
- package/node_modules/@ursamu/mushcode/parser/mod.ts +99 -0
- package/node_modules/@ursamu/mushcode/parser/mux-softcode.js +3833 -0
- package/node_modules/@ursamu/mushcode/parser/mux-softcode.mjs +3837 -0
- package/node_modules/@ursamu/mushcode/src/analyze/commands.js +29 -0
- package/node_modules/@ursamu/mushcode/src/analyze/commands.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/analyze/commands.ts +46 -0
- package/node_modules/@ursamu/mushcode/src/analyze/deps.js +45 -0
- package/node_modules/@ursamu/mushcode/src/analyze/deps.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/analyze/deps.ts +51 -0
- package/node_modules/@ursamu/mushcode/src/analyze/mod.js +18 -0
- package/node_modules/@ursamu/mushcode/src/analyze/mod.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/analyze/mod.ts +20 -0
- package/node_modules/@ursamu/mushcode/src/analyze/tags.js +11 -0
- package/node_modules/@ursamu/mushcode/src/analyze/tags.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/analyze/tags.ts +11 -0
- package/node_modules/@ursamu/mushcode/src/eval/context.js +22 -0
- package/node_modules/@ursamu/mushcode/src/eval/context.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/eval/context.ts +177 -0
- package/node_modules/@ursamu/mushcode/src/eval/engine.js +238 -0
- package/node_modules/@ursamu/mushcode/src/eval/engine.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/eval/engine.ts +276 -0
- package/node_modules/@ursamu/mushcode/src/eval/mod.js +25 -0
- package/node_modules/@ursamu/mushcode/src/eval/mod.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/eval/mod.ts +31 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/compare.js +56 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/compare.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/compare.ts +16 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/db.js +91 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/db.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/db.ts +104 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/iter.js +91 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/iter.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/iter.ts +98 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/logic.js +79 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/logic.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/logic.ts +84 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/math.js +120 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/math.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/math.ts +115 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/mod.js +17 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/mod.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/mod.ts +19 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/register.js +28 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/register.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/register.ts +31 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/string.js +153 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/string.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/eval/stdlib/string.ts +154 -0
- package/node_modules/@ursamu/mushcode/src/lint/builtin_arities.js +212 -0
- package/node_modules/@ursamu/mushcode/src/lint/builtin_arities.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/lint/builtin_arities.ts +68 -0
- package/node_modules/@ursamu/mushcode/src/lint/mod.js +60 -0
- package/node_modules/@ursamu/mushcode/src/lint/mod.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/lint/mod.ts +96 -0
- package/node_modules/@ursamu/mushcode/src/lint/rules/arg_count.js +37 -0
- package/node_modules/@ursamu/mushcode/src/lint/rules/arg_count.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/lint/rules/arg_count.ts +44 -0
- package/node_modules/@ursamu/mushcode/src/lint/rules/iter_var_outside_iter.js +55 -0
- package/node_modules/@ursamu/mushcode/src/lint/rules/iter_var_outside_iter.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/lint/rules/iter_var_outside_iter.ts +60 -0
- package/node_modules/@ursamu/mushcode/src/lint/rules/missing_wildcard.js +31 -0
- package/node_modules/@ursamu/mushcode/src/lint/rules/missing_wildcard.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/lint/rules/missing_wildcard.ts +40 -0
- package/node_modules/@ursamu/mushcode/src/lint/rules/register_before_set.js +59 -0
- package/node_modules/@ursamu/mushcode/src/lint/rules/register_before_set.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/lint/rules/register_before_set.ts +64 -0
- package/node_modules/@ursamu/mushcode/src/print/lock_printer.js +43 -0
- package/node_modules/@ursamu/mushcode/src/print/lock_printer.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/print/lock_printer.ts +41 -0
- package/node_modules/@ursamu/mushcode/src/print/mod.js +17 -0
- package/node_modules/@ursamu/mushcode/src/print/mod.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/print/mod.ts +18 -0
- package/node_modules/@ursamu/mushcode/src/print/printer.js +91 -0
- package/node_modules/@ursamu/mushcode/src/print/printer.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/print/printer.ts +132 -0
- package/node_modules/@ursamu/mushcode/src/traverse/child_slots.js +129 -0
- package/node_modules/@ursamu/mushcode/src/traverse/child_slots.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/traverse/child_slots.ts +51 -0
- package/node_modules/@ursamu/mushcode/src/traverse/mod.js +17 -0
- package/node_modules/@ursamu/mushcode/src/traverse/mod.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/traverse/mod.ts +19 -0
- package/node_modules/@ursamu/mushcode/src/traverse/transform.js +70 -0
- package/node_modules/@ursamu/mushcode/src/traverse/transform.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/traverse/transform.ts +84 -0
- package/node_modules/@ursamu/mushcode/src/traverse/walk.js +55 -0
- package/node_modules/@ursamu/mushcode/src/traverse/walk.js.map +1 -0
- package/node_modules/@ursamu/mushcode/src/traverse/walk.ts +82 -0
- package/node_modules/@ursamu/mushcode/tests/01-literals.test.ts +105 -0
- package/node_modules/@ursamu/mushcode/tests/02-substitutions.test.ts +145 -0
- package/node_modules/@ursamu/mushcode/tests/03-function-calls.test.ts +184 -0
- package/node_modules/@ursamu/mushcode/tests/04-eval-blocks.test.ts +110 -0
- package/node_modules/@ursamu/mushcode/tests/05-braced-strings.test.ts +119 -0
- package/node_modules/@ursamu/mushcode/tests/06-commands.test.ts +222 -0
- package/node_modules/@ursamu/mushcode/tests/07-dollar-patterns.test.ts +156 -0
- package/node_modules/@ursamu/mushcode/tests/08-lock-expressions.test.ts +159 -0
- package/node_modules/@ursamu/mushcode/tests/09-edge-cases.test.ts +162 -0
- package/node_modules/@ursamu/mushcode/tests/10-regression.test.ts +211 -0
- package/node_modules/@ursamu/mushcode/tests/11-tags.test.ts +357 -0
- package/node_modules/@ursamu/mushcode/tests/12-locations.test.ts +162 -0
- package/node_modules/@ursamu/mushcode/tests/13-eval.test.ts +389 -0
- package/node_modules/@ursamu/mushcode/tests/analyze.test.ts +194 -0
- package/node_modules/@ursamu/mushcode/tests/helpers.ts +69 -0
- package/node_modules/@ursamu/mushcode/tests/lint.test.ts +232 -0
- package/node_modules/@ursamu/mushcode/tests/print.test.ts +204 -0
- package/node_modules/@ursamu/mushcode/tests/traverse.test.ts +211 -0
- package/package.json +4 -1
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
# Stdlib
|
|
2
|
+
|
|
3
|
+
All functions listed here are registered by `registerStdlib(engine)`.
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { EvalEngine, registerStdlib, makeContext } from "jsr:@ursamu/mushcode/eval";
|
|
7
|
+
|
|
8
|
+
const engine = new EvalEngine(accessor);
|
|
9
|
+
registerStdlib(engine);
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Errors return `#-1 MESSAGE` strings, matching MUX server conventions.
|
|
13
|
+
Integer inputs and outputs use integer arithmetic; mixed or float inputs return
|
|
14
|
+
up to 6 significant digits.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Math
|
|
19
|
+
|
|
20
|
+
### `add(n, n, …)`
|
|
21
|
+
|
|
22
|
+
Sum of two or more numbers.
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// [add(1,2,3)] → "6"
|
|
26
|
+
// [add(1.5,2.5)] → "4"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### `sub(a, b)`
|
|
30
|
+
|
|
31
|
+
Subtraction.
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
// [sub(10,3)] → "7"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### `mul(n, n, …)`
|
|
38
|
+
|
|
39
|
+
Product of two or more numbers.
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
// [mul(2,3,4)] → "24"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### `div(a, b)`
|
|
46
|
+
|
|
47
|
+
Division. Integer operands use integer (truncating) division. Returns `#-1
|
|
48
|
+
DIVIDE BY ZERO` if `b` is 0.
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// [div(10,3)] → "3" (integer truncation)
|
|
52
|
+
// [div(10.0,3)] → "3.33333"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### `mod(a, b)`
|
|
56
|
+
|
|
57
|
+
Remainder. Returns `#-1 DIVIDE BY ZERO` if `b` is 0.
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
// [mod(10,3)] → "1"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### `abs(n)`
|
|
64
|
+
|
|
65
|
+
Absolute value.
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// [abs(-5)] → "5"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### `round(n, places)`
|
|
72
|
+
|
|
73
|
+
Round `n` to `places` decimal places.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// [round(3.14159,2)] → "3.14"
|
|
77
|
+
// [round(3.5,0)] → "4"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### `floor(n)`
|
|
81
|
+
|
|
82
|
+
Floor (round down to nearest integer).
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
// [floor(3.9)] → "3"
|
|
86
|
+
// [floor(-1.1)] → "-2"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### `ceil(n)`
|
|
90
|
+
|
|
91
|
+
Ceiling (round up to nearest integer).
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// [ceil(3.1)] → "4"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### `max(n, n, …)` / `min(n, n, …)`
|
|
98
|
+
|
|
99
|
+
Maximum or minimum of two or more values.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
// [max(1,5,3)] → "5"
|
|
103
|
+
// [min(1,5,3)] → "1"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### `power(base, exp)`
|
|
107
|
+
|
|
108
|
+
Exponentiation.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
// [power(2,8)] → "256"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### `sqrt(n)`
|
|
115
|
+
|
|
116
|
+
Square root. Returns `#-1 ARGUMENT OUT OF RANGE` for negative input.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
// [sqrt(9)] → "3"
|
|
120
|
+
// [sqrt(2)] → "1.41421"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## String
|
|
126
|
+
|
|
127
|
+
### `strlen(str)`
|
|
128
|
+
|
|
129
|
+
Length of a string.
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
// [strlen(Hello)] → "5"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### `mid(str, start, len)`
|
|
136
|
+
|
|
137
|
+
Substring. `start` is 0-based.
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// [mid(Hello,1,3)] → "ell"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### `left(str, n)` / `right(str, n)`
|
|
144
|
+
|
|
145
|
+
First or last `n` characters.
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// [left(Hello,3)] → "Hel"
|
|
149
|
+
// [right(Hello,3)] → "llo"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### `trim(str)`
|
|
153
|
+
|
|
154
|
+
Strip leading and trailing whitespace.
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// [trim( hi )] → "hi"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### `ljust(str, width[, fill])` / `rjust(str, width[, fill])` / `center(str, width[, fill])`
|
|
161
|
+
|
|
162
|
+
Pad a string to `width` characters. Default fill character is space.
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// [ljust(hi,6)] → "hi "
|
|
166
|
+
// [rjust(hi,6)] → " hi"
|
|
167
|
+
// [center(hi,6)] → " hi "
|
|
168
|
+
// [ljust(hi,6,-)] → "hi----"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### `ucstr(str)` / `lcstr(str)` / `capstr(str)`
|
|
172
|
+
|
|
173
|
+
Uppercase, lowercase, or capitalise first letter.
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
// [ucstr(hello)] → "HELLO"
|
|
177
|
+
// [lcstr(HELLO)] → "hello"
|
|
178
|
+
// [capstr(hello world)] → "Hello world"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### `cat(str, …)`
|
|
182
|
+
|
|
183
|
+
Concatenate arguments with a single space between each.
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
// [cat(hello,world)] → "hello world"
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### `space(n)`
|
|
190
|
+
|
|
191
|
+
A string of `n` spaces.
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
// [space(3)] → " "
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### `repeat(str, n)`
|
|
198
|
+
|
|
199
|
+
Repeat `str` exactly `n` times.
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
// [repeat(-,5)] → "-----"
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Compare
|
|
208
|
+
|
|
209
|
+
All compare functions return `"1"` (true) or `"0"` (false).
|
|
210
|
+
|
|
211
|
+
### `eq(a, b)` / `neq(a, b)`
|
|
212
|
+
|
|
213
|
+
Numeric equality / inequality.
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
// [eq(3,3)] → "1"
|
|
217
|
+
// [neq(3,4)] → "1"
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### `gt(a, b)` / `gte(a, b)` / `lt(a, b)` / `lte(a, b)`
|
|
221
|
+
|
|
222
|
+
Numeric greater-than, greater-or-equal, less-than, less-or-equal.
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
// [gt(5,3)] → "1"
|
|
226
|
+
// [lte(3,3)] → "1"
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Logic
|
|
232
|
+
|
|
233
|
+
`if`, `ifelse`, `switch`, `and`, and `or` are **lazy** — they only evaluate the
|
|
234
|
+
branches they need.
|
|
235
|
+
|
|
236
|
+
### `if(cond, then)`
|
|
237
|
+
|
|
238
|
+
If `cond` is truthy (non-zero, non-empty), return `then`. Otherwise return `""`.
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
// [if(1,yes)] → "yes"
|
|
242
|
+
// [if(0,yes)] → ""
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### `ifelse(cond, then, else)`
|
|
246
|
+
|
|
247
|
+
If `cond` is truthy, return `then`; otherwise return `else`.
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// [ifelse([gt(%0,10)],big,small)] → "big" or "small"
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### `switch(value, match1, result1, match2, result2, …[, default])`
|
|
254
|
+
|
|
255
|
+
Exact-match switch. Compares `value` against each `match` string in order.
|
|
256
|
+
Returns the corresponding `result` for the first match, or `default` (or `""`)
|
|
257
|
+
if nothing matches.
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
// [switch(%0,1,one,2,two,other)] → "one" if %0 is "1"
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### `and(a, b, …)` / `or(a, b, …)`
|
|
264
|
+
|
|
265
|
+
Short-circuit logical AND / OR. Return `"1"` or `"0"`.
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
// [and(1,1,0)] → "0"
|
|
269
|
+
// [or(0,0,1)] → "1"
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### `not(a)`
|
|
273
|
+
|
|
274
|
+
Logical NOT.
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
// [not(0)] → "1"
|
|
278
|
+
// [not(1)] → "0"
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### `t(a)`
|
|
282
|
+
|
|
283
|
+
Truthiness test — returns `"1"` if `a` is non-empty and non-`"0"`, else `"0"`.
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
// [t(hello)] → "1"
|
|
287
|
+
// [t(0)] → "0"
|
|
288
|
+
// [t()] → "0"
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## Registers
|
|
294
|
+
|
|
295
|
+
### `setq(reg, val)` / `setr(reg, val)`
|
|
296
|
+
|
|
297
|
+
Store `val` in register `reg`. Both forms are equivalent. Returns `""` and
|
|
298
|
+
mutates `ctx.registers`.
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
// [setq(0,hello)][r(0)] → "hello"
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### `r(reg)`
|
|
305
|
+
|
|
306
|
+
Read register `reg`. Returns `""` if not set.
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
// [setq(name,Alice)][r(name)] → "Alice"
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## Iter / List
|
|
315
|
+
|
|
316
|
+
### `iter(list, body[, idelim[, odelim]])`
|
|
317
|
+
|
|
318
|
+
Evaluate `body` for each item in `list`. Inside `body`, `##` holds the current
|
|
319
|
+
item and `#@` holds its 1-based position. Default delimiter is space (which
|
|
320
|
+
also collapses consecutive whitespace, MUX-style).
|
|
321
|
+
|
|
322
|
+
`iter` is **lazy** — `body` is evaluated once per item.
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
// [iter(a b c,## is #@)] → "a is 1 b is 2 c is 3"
|
|
326
|
+
// [iter(a|b|c,##,|,;)] → "a;b;c"
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### `words(str[, delim])`
|
|
330
|
+
|
|
331
|
+
Count of items in a space- (or delim-) separated list.
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
// [words(a b c)] → "3"
|
|
335
|
+
// [words(a|b,|)] → "2"
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### `word(str, n[, delim])`
|
|
339
|
+
|
|
340
|
+
The nth word (1-based).
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
// [word(a b c,2)] → "b"
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### `first(str[, delim])` / `last(str[, delim])`
|
|
347
|
+
|
|
348
|
+
First or last word.
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
// [first(a b c)] → "a"
|
|
352
|
+
// [last(a b c)] → "c"
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### `rest(str[, delim])`
|
|
356
|
+
|
|
357
|
+
All words after the first.
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
// [rest(a b c)] → "b c"
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## DB
|
|
366
|
+
|
|
367
|
+
These functions call through to `ObjectAccessor` methods.
|
|
368
|
+
|
|
369
|
+
### `get(obj/attr)`
|
|
370
|
+
|
|
371
|
+
Read the named attribute from `obj`. Returns `""` if the attribute is unset.
|
|
372
|
+
Returns `#-1 NO MATCH` if `obj` cannot be resolved, or `#-1 BAD ARGUMENT
|
|
373
|
+
FORMAT` if the argument has no `/`.
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
// [get(me/DESC)] — reads DESC from the enactor
|
|
377
|
+
// [get(#room/NAME)] — reads NAME from a TagRef-resolved object
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### `name(obj)`
|
|
381
|
+
|
|
382
|
+
Display name of `obj`.
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
// [name(me)] → "Alice"
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### `hasattr(obj, attr)`
|
|
389
|
+
|
|
390
|
+
`"1"` if the attribute exists on `obj`, `"0"` otherwise.
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
// [hasattr(me,DESC)] → "1" or "0"
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### `hasflag(obj, flag)`
|
|
397
|
+
|
|
398
|
+
`"1"` if `obj` has `flag`, `"0"` otherwise.
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
// [hasflag(me,WIZARD)] → "1" or "0"
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### `u(obj/attr[, arg0, arg1, …])`
|
|
405
|
+
|
|
406
|
+
Evaluate the named attribute as a function call. Creates a child `EvalContext`
|
|
407
|
+
where:
|
|
408
|
+
- `%0`–`%9` are the extra arguments passed to `u()`
|
|
409
|
+
- `%!` is the object that owns the attribute (new executor)
|
|
410
|
+
- `%@` is the previous executor (caller)
|
|
411
|
+
- `%#` is unchanged (original enactor)
|
|
412
|
+
- `depth` is incremented; returns `#-1 EVALUATION DEPTH EXCEEDED` at `maxDepth`
|
|
413
|
+
|
|
414
|
+
```typescript
|
|
415
|
+
// [u(me/FN_DOUBLE,21)] → evaluates the FN_DOUBLE attr with %0="21"
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
If `obj/` is omitted (bare attribute name), the executor is used as the target.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Traverse
|
|
2
|
+
|
|
3
|
+
```typescript
|
|
4
|
+
import { walk, transform, findAll, findFirst, findFirstOrNull } from "jsr:@ursamu/mushcode/traverse";
|
|
5
|
+
import type { Visitor, Transformer } from "jsr:@ursamu/mushcode/traverse";
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
## `walk(root, visitor)`
|
|
9
|
+
|
|
10
|
+
Depth-first walk over an AST. The visitor's `enter` hook is called before a
|
|
11
|
+
node's children are visited; `leave` is called after.
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
function walk(root: ASTNode, visitor: Visitor): void
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
interface Visitor {
|
|
19
|
+
enter?: (node: ASTNode) => false | void;
|
|
20
|
+
leave?: (node: ASTNode) => void;
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Returning `false` from `enter` skips the node's children and suppresses the
|
|
25
|
+
`leave` call for that node.
|
|
26
|
+
|
|
27
|
+
Nodes are visited in place — you may mutate `node` fields inside a visitor, but
|
|
28
|
+
prefer `transform` when you need a new tree.
|
|
29
|
+
|
|
30
|
+
### Example: collect all function names
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { parse } from "jsr:@ursamu/mushcode/parse";
|
|
34
|
+
import { walk } from "jsr:@ursamu/mushcode/traverse";
|
|
35
|
+
|
|
36
|
+
const ast = parse("[add(1,[mul(2,3)])]");
|
|
37
|
+
const names: string[] = [];
|
|
38
|
+
|
|
39
|
+
walk(ast, {
|
|
40
|
+
enter(node) {
|
|
41
|
+
if (node.type === "FunctionCall") names.push(node.name as string);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
console.log(names); // ["add", "mul"]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Example: skip subtrees
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
walk(ast, {
|
|
52
|
+
enter(node) {
|
|
53
|
+
// Do not descend into braced strings
|
|
54
|
+
if (node.type === "BracedString") return false;
|
|
55
|
+
if (node.type === "Literal") process(node);
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## `transform(root, fn)`
|
|
61
|
+
|
|
62
|
+
Produce a new tree by applying `fn` to every node top-down. The original tree
|
|
63
|
+
is never mutated.
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
function transform(root: ASTNode, fn: Transformer): ASTNode
|
|
67
|
+
|
|
68
|
+
type Transformer = (node: ASTNode) => ASTNode | null | undefined;
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Return values from the transformer:
|
|
72
|
+
|
|
73
|
+
| Return value | Effect |
|
|
74
|
+
|--------------|-------------------------------------------------------------------------|
|
|
75
|
+
| `undefined` | Keep the node as-is and recurse into its children |
|
|
76
|
+
| `ASTNode` | Replace the node with the returned value, then recurse into its children |
|
|
77
|
+
| `null` | Remove the node (from an array slot) or set the field to `null` |
|
|
78
|
+
|
|
79
|
+
### Example: replace TagRefs with Literal placeholders
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { parse } from "jsr:@ursamu/mushcode/parse";
|
|
83
|
+
import { transform } from "jsr:@ursamu/mushcode/traverse";
|
|
84
|
+
|
|
85
|
+
const ast = parse("@pemit %#=[get(#room/DESC)]");
|
|
86
|
+
|
|
87
|
+
const out = transform(ast, (node) => {
|
|
88
|
+
if (node.type === "TagRef") {
|
|
89
|
+
return { type: "Literal", value: `<tag:${node.name}>` };
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// out contains a new tree with TagRef replaced by Literal
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Example: strip all EvalBlocks (flatten to their content)
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
const stripped = transform(ast, (node) => {
|
|
100
|
+
if (node.type === "EvalBlock") {
|
|
101
|
+
// Replace EvalBlock with a Literal that holds its printed content
|
|
102
|
+
// (or return null to remove it entirely)
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## `findAll(root, type)`
|
|
109
|
+
|
|
110
|
+
Collect every node of the given type anywhere in the tree.
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
function findAll(root: ASTNode, type: string): ASTNode[]
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { parse } from "jsr:@ursamu/mushcode/parse";
|
|
118
|
+
import { findAll } from "jsr:@ursamu/mushcode/traverse";
|
|
119
|
+
|
|
120
|
+
const ast = parse("$+finger *:@pemit %#=[u(me/FN,%0,#room)]");
|
|
121
|
+
const refs = findAll(ast, "TagRef");
|
|
122
|
+
console.log(refs.map(n => n.name)); // ["room"]
|
|
123
|
+
|
|
124
|
+
const subs = findAll(ast, "Substitution");
|
|
125
|
+
console.log(subs.map(n => n.code)); // ["#", "0"]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Returns an empty array when no nodes of that type exist.
|
|
129
|
+
|
|
130
|
+
## `findFirst(root, type)`
|
|
131
|
+
|
|
132
|
+
Return the first node of the given type. Throws `Error` if none is found.
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
function findFirst(root: ASTNode, type: string): ASTNode
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
import { parse } from "jsr:@ursamu/mushcode/parse";
|
|
140
|
+
import { findFirst } from "jsr:@ursamu/mushcode/traverse";
|
|
141
|
+
|
|
142
|
+
const ast = parse("$do *:@pemit %#=[u(me/FN,%0)]");
|
|
143
|
+
const call = findFirst(ast, "FunctionCall");
|
|
144
|
+
console.log(call.name); // "u"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## `findFirstOrNull(root, type)`
|
|
148
|
+
|
|
149
|
+
Return the first node of the given type, or `null` if none exists. Prefer this
|
|
150
|
+
over `findFirst` when the node might not be present.
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
function findFirstOrNull(root: ASTNode, type: string): ASTNode | null
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { parse } from "jsr:@ursamu/mushcode/parse";
|
|
158
|
+
import { findFirstOrNull } from "jsr:@ursamu/mushcode/traverse";
|
|
159
|
+
|
|
160
|
+
const ast = parse("@pemit %#=Hello");
|
|
161
|
+
const call = findFirstOrNull(ast, "FunctionCall");
|
|
162
|
+
if (call) {
|
|
163
|
+
console.log(call.name);
|
|
164
|
+
} else {
|
|
165
|
+
console.log("no function call found");
|
|
166
|
+
}
|
|
167
|
+
```
|