1
use nomiscript::{
2
    Compiler, Expr, Fraction, Reader, Symbol, SymbolKind, SymbolTable, Value, WasmType,
3
    eval_program,
4
};
5

            
6
8
fn eval_to_value(symbols: &mut SymbolTable, code: &str) -> Value {
7
8
    let program = Reader::parse(code).unwrap();
8
8
    eval_program(symbols, &program).unwrap()
9
8
}
10

            
11
// --- Constant folding regression tests ---
12

            
13
#[test]
14
1
fn test_add_constant_fold() {
15
1
    let mut symbols = SymbolTable::with_builtins();
16
1
    let result = eval_to_value(&mut symbols, "(+ 1 2 3)");
17
1
    assert_eq!(result, Value::Number(Fraction::from_integer(6)));
18
1
}
19

            
20
#[test]
21
1
fn test_sub_constant_fold() {
22
1
    let mut symbols = SymbolTable::with_builtins();
23
1
    let result = eval_to_value(&mut symbols, "(- 10 3)");
24
1
    assert_eq!(result, Value::Number(Fraction::from_integer(7)));
25
1
}
26

            
27
#[test]
28
1
fn test_mul_constant_fold() {
29
1
    let mut symbols = SymbolTable::with_builtins();
30
1
    let result = eval_to_value(&mut symbols, "(* 3 4)");
31
1
    assert_eq!(result, Value::Number(Fraction::from_integer(12)));
32
1
}
33

            
34
#[test]
35
1
fn test_div_constant_fold() {
36
1
    let mut symbols = SymbolTable::with_builtins();
37
1
    let result = eval_to_value(&mut symbols, "(/ 10 3)");
38
1
    assert_eq!(result, Value::Number(Fraction::new(10, 3)));
39
1
}
40

            
41
#[test]
42
1
fn test_ratio_arithmetic() {
43
1
    let mut symbols = SymbolTable::with_builtins();
44
    // Reader doesn't support 1/3 literals; use (/ 1 3) instead
45
1
    let result = eval_to_value(&mut symbols, "(+ (/ 1 3) (/ 1 4))");
46
1
    assert_eq!(result, Value::Number(Fraction::new(7, 12)));
47
1
}
48

            
49
#[test]
50
1
fn test_comparison_constant_fold() {
51
1
    let mut symbols = SymbolTable::with_builtins();
52
1
    assert_eq!(eval_to_value(&mut symbols, "(= 1 1)"), Value::Bool(true));
53
1
    assert_eq!(eval_to_value(&mut symbols, "(< 1 2)"), Value::Bool(true));
54
1
    assert_eq!(eval_to_value(&mut symbols, "(> 3 2)"), Value::Bool(true));
55
1
}
56

            
57
// --- WASM compilation tests ---
58

            
59
#[test]
60
1
fn test_compile_constant_arithmetic_produces_valid_wasm() {
61
1
    let program = Reader::parse("(+ (/ 1 3) (/ 1 4))").unwrap();
62
1
    let mut compiler = Compiler::new();
63
1
    let wasm = compiler
64
1
        .compile(&program, &mut SymbolTable::with_builtins_for_wasm())
65
1
        .unwrap();
66
1
    assert_eq!(&wasm[0..4], b"\0asm");
67
1
}
68

            
69
#[test]
70
1
fn test_compile_comparison_produces_valid_wasm() {
71
1
    let program = Reader::parse("(= 1 2)").unwrap();
72
1
    let mut compiler = Compiler::new();
73
1
    let wasm = compiler
74
1
        .compile(&program, &mut SymbolTable::with_builtins_for_wasm())
75
1
        .unwrap();
76
1
    assert_eq!(&wasm[0..4], b"\0asm");
77
1
}
78

            
79
#[test]
80
1
fn test_compile_nested_arithmetic_produces_valid_wasm() {
81
1
    let program = Reader::parse("(* (+ 1 2) (- 5 3))").unwrap();
82
1
    let mut compiler = Compiler::new();
83
1
    let wasm = compiler
84
1
        .compile(&program, &mut SymbolTable::with_builtins_for_wasm())
85
1
        .unwrap();
86
1
    assert_eq!(&wasm[0..4], b"\0asm");
87
1
}
88

            
89
// --- WasmRuntime propagation tests (unit tests need internal access) ---
90
// These test the compile-time type tracking through the eval path.
91
// Since eval_value is crate-private, we test via WASM compilation
92
// with symbols pre-set to WasmRuntime values.
93

            
94
#[test]
95
1
fn test_arithmetic_rejects_i32_type() {
96
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
97
1
    symbols.define(
98
1
        Symbol::new("IDX", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::I32)),
99
    );
100
1
    let program = Reader::parse("(+ IDX 1)").unwrap();
101
1
    let mut compiler = Compiler::new();
102
1
    let result = compiler.compile(&program, &mut symbols);
103
1
    assert!(result.is_err(), "should reject I32 in arithmetic");
104
1
    let err = result.unwrap_err().to_string();
105
1
    assert!(
106
1
        err.contains("ratio") || err.contains("indices"),
107
        "error should mention type mismatch: {err}"
108
    );
109
1
}
110

            
111
#[test]
112
1
fn test_compile_runtime_addition_produces_valid_wasm() {
113
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
114
1
    symbols.define(
115
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
116
    );
117
1
    let program = Reader::parse("(+ X (/ 1 3))").unwrap();
118
1
    let mut compiler = Compiler::new();
119
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
120
1
    assert_eq!(&wasm[0..4], b"\0asm");
121
1
}
122

            
123
#[test]
124
1
fn test_compile_runtime_subtraction_produces_valid_wasm() {
125
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
126
1
    symbols.define(
127
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
128
    );
129
1
    let program = Reader::parse("(- X 1)").unwrap();
130
1
    let mut compiler = Compiler::new();
131
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
132
1
    assert_eq!(&wasm[0..4], b"\0asm");
133
1
}
134

            
135
#[test]
136
1
fn test_compile_runtime_multiplication_produces_valid_wasm() {
137
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
138
1
    symbols.define(
139
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
140
    );
141
1
    let program = Reader::parse("(* X 2)").unwrap();
142
1
    let mut compiler = Compiler::new();
143
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
144
1
    assert_eq!(&wasm[0..4], b"\0asm");
145
1
}
146

            
147
#[test]
148
1
fn test_compile_runtime_division_produces_valid_wasm() {
149
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
150
1
    symbols.define(
151
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
152
    );
153
1
    let program = Reader::parse("(/ X 3)").unwrap();
154
1
    let mut compiler = Compiler::new();
155
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
156
1
    assert_eq!(&wasm[0..4], b"\0asm");
157
1
}
158

            
159
#[test]
160
1
fn test_compile_runtime_nested_arithmetic_produces_valid_wasm() {
161
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
162
1
    symbols.define(
163
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
164
    );
165
1
    let program = Reader::parse("(+ (* X 2) (/ 1 3))").unwrap();
166
1
    let mut compiler = Compiler::new();
167
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
168
1
    assert_eq!(&wasm[0..4], b"\0asm");
169
1
}
170

            
171
#[test]
172
1
fn test_compile_runtime_comparison_produces_valid_wasm() {
173
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
174
1
    symbols.define(
175
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
176
    );
177
1
    let program = Reader::parse("(= X 0)").unwrap();
178
1
    let mut compiler = Compiler::new();
179
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
180
1
    assert_eq!(&wasm[0..4], b"\0asm");
181
1
}
182

            
183
// --- Runtime control flow tests ---
184

            
185
#[test]
186
1
fn test_compile_runtime_if_produces_valid_wasm() {
187
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
188
1
    symbols.define(
189
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
190
    );
191
1
    let program = Reader::parse("(if (= X 0) (+ X 1) (- X 1))").unwrap();
192
1
    let mut compiler = Compiler::new();
193
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
194
1
    assert_eq!(&wasm[0..4], b"\0asm");
195
1
}
196

            
197
#[test]
198
1
fn test_compile_runtime_if_no_else_produces_valid_wasm() {
199
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
200
1
    symbols.define(
201
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
202
    );
203
1
    let program = Reader::parse("(if (= X 0) (+ X 1))").unwrap();
204
1
    let mut compiler = Compiler::new();
205
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
206
1
    assert_eq!(&wasm[0..4], b"\0asm");
207
1
}
208

            
209
#[test]
210
1
fn test_compile_runtime_and_produces_valid_wasm() {
211
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
212
1
    symbols.define(
213
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
214
    );
215
1
    let program = Reader::parse("(and (= X 0) (> X 1))").unwrap();
216
1
    let mut compiler = Compiler::new();
217
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
218
1
    assert_eq!(&wasm[0..4], b"\0asm");
219
1
}
220

            
221
#[test]
222
1
fn test_compile_runtime_or_produces_valid_wasm() {
223
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
224
1
    symbols.define(
225
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
226
    );
227
1
    let program = Reader::parse("(or (= X 0) (< X 1))").unwrap();
228
1
    let mut compiler = Compiler::new();
229
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
230
1
    assert_eq!(&wasm[0..4], b"\0asm");
231
1
}
232

            
233
#[test]
234
1
fn test_compile_runtime_cond_produces_valid_wasm() {
235
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
236
1
    symbols.define(
237
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
238
    );
239
1
    let program = Reader::parse("(cond ((= X 0) (+ X 1)) ((> X 0) (- X 1)))").unwrap();
240
1
    let mut compiler = Compiler::new();
241
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
242
1
    assert_eq!(&wasm[0..4], b"\0asm");
243
1
}
244

            
245
// WHEN expands to (if test (begin body...) nil), UNLESS to (if test nil (begin body...))
246
// Test the equivalent IF forms since stdlib isn't loaded for WASM
247

            
248
#[test]
249
1
fn test_compile_runtime_when_equivalent_produces_valid_wasm() {
250
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
251
1
    symbols.define(
252
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
253
    );
254
1
    let program = Reader::parse("(if (= X 0) (begin (+ X 1)) nil)").unwrap();
255
1
    let mut compiler = Compiler::new();
256
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
257
1
    assert_eq!(&wasm[0..4], b"\0asm");
258
1
}
259

            
260
#[test]
261
1
fn test_compile_runtime_unless_equivalent_produces_valid_wasm() {
262
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
263
1
    symbols.define(
264
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
265
    );
266
1
    let program = Reader::parse("(if (= X 0) nil (begin (- X 1)))").unwrap();
267
1
    let mut compiler = Compiler::new();
268
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
269
1
    assert_eq!(&wasm[0..4], b"\0asm");
270
1
}
271

            
272
#[test]
273
1
fn test_compile_runtime_not_produces_valid_wasm() {
274
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
275
1
    symbols.define(
276
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
277
    );
278
1
    let program = Reader::parse("(not (= X 0))").unwrap();
279
1
    let mut compiler = Compiler::new();
280
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
281
1
    assert_eq!(&wasm[0..4], b"\0asm");
282
1
}
283

            
284
// --- LET/LET* with runtime bindings ---
285

            
286
#[test]
287
1
fn test_compile_let_star_runtime_binding_produces_valid_wasm() {
288
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
289
1
    symbols.define(
290
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
291
    );
292
    // LET* binds Y to a runtime value (X + 1), then uses Y in body
293
1
    let program = Reader::parse("(let* ((Y (+ X 1))) (+ Y 2))").unwrap();
294
1
    let mut compiler = Compiler::new();
295
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
296
1
    assert_eq!(&wasm[0..4], b"\0asm");
297
1
}
298

            
299
#[test]
300
1
fn test_compile_let_star_multiple_runtime_bindings_produces_valid_wasm() {
301
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
302
1
    symbols.define(
303
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
304
    );
305
1
    let program = Reader::parse("(let* ((Y (+ X 1)) (Z (* Y 2))) (- Z X))").unwrap();
306
1
    let mut compiler = Compiler::new();
307
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
308
1
    assert_eq!(&wasm[0..4], b"\0asm");
309
1
}
310

            
311
#[test]
312
1
fn test_compile_let_runtime_with_if_produces_valid_wasm() {
313
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
314
1
    symbols.define(
315
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
316
    );
317
1
    let program = Reader::parse("(let* ((Y (+ X 1))) (if (= Y 0) (+ Y 1) (- Y 1)))").unwrap();
318
1
    let mut compiler = Compiler::new();
319
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
320
1
    assert_eq!(&wasm[0..4], b"\0asm");
321
1
}
322

            
323
// --- DO / DO* with runtime bindings ---
324

            
325
#[test]
326
1
fn test_compile_runtime_do_simple_produces_valid_wasm() {
327
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
328
1
    symbols.define(
329
1
        Symbol::new("N", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
330
    );
331
1
    let program = Reader::parse("(do ((I 0 (+ I 1))) ((>= I N) I))").unwrap();
332
1
    let mut compiler = Compiler::new();
333
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
334
1
    assert_eq!(&wasm[0..4], b"\0asm");
335
1
}
336

            
337
#[test]
338
1
fn test_compile_runtime_do_with_body_produces_valid_wasm() {
339
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
340
1
    symbols.define(
341
1
        Symbol::new("N", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
342
    );
343
1
    let program =
344
1
        Reader::parse("(let* ((SUM 0)) (do ((I 0 (+ I 1))) ((>= I N) SUM) (setf SUM (+ SUM I))))")
345
1
            .unwrap();
346
1
    let mut compiler = Compiler::new();
347
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
348
1
    assert_eq!(&wasm[0..4], b"\0asm");
349
1
}
350

            
351
#[test]
352
1
fn test_compile_runtime_do_star_produces_valid_wasm() {
353
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
354
1
    symbols.define(
355
1
        Symbol::new("N", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
356
    );
357
1
    let program = Reader::parse("(do* ((I 0 (+ I 1))) ((>= I N) I))").unwrap();
358
1
    let mut compiler = Compiler::new();
359
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
360
1
    assert_eq!(&wasm[0..4], b"\0asm");
361
1
}
362

            
363
#[test]
364
1
fn test_compile_runtime_do_multiple_vars_produces_valid_wasm() {
365
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
366
1
    symbols.define(
367
1
        Symbol::new("N", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
368
    );
369
1
    let program = Reader::parse("(do ((I 0 (+ I 1)) (J N (- J 1))) ((>= I J) (+ I J)))").unwrap();
370
1
    let mut compiler = Compiler::new();
371
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
372
1
    assert_eq!(&wasm[0..4], b"\0asm");
373
1
}
374

            
375
#[test]
376
1
fn test_compile_runtime_do_no_result_produces_valid_wasm() {
377
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
378
1
    symbols.define(
379
1
        Symbol::new("N", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
380
    );
381
1
    let program = Reader::parse("(do ((I 0 (+ I 1))) ((>= I N)))").unwrap();
382
1
    let mut compiler = Compiler::new();
383
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
384
1
    assert_eq!(&wasm[0..4], b"\0asm");
385
1
}
386

            
387
// --- Entity accessors ---
388

            
389
#[test]
390
1
fn test_entity_count_produces_valid_wasm() {
391
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
392
1
    let program = Reader::parse("(entity-count)").unwrap();
393
1
    let mut compiler = Compiler::new();
394
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
395
1
    assert_eq!(&wasm[0..4], b"\0asm");
396
1
}
397

            
398
#[test]
399
1
fn test_context_type_produces_valid_wasm() {
400
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
401
1
    let program = Reader::parse("(context-type)").unwrap();
402
1
    let mut compiler = Compiler::new();
403
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
404
1
    assert_eq!(&wasm[0..4], b"\0asm");
405
1
}
406

            
407
#[test]
408
1
fn test_primary_entity_type_produces_valid_wasm() {
409
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
410
1
    let program = Reader::parse("(primary-entity-type)").unwrap();
411
1
    let mut compiler = Compiler::new();
412
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
413
1
    assert_eq!(&wasm[0..4], b"\0asm");
414
1
}
415

            
416
#[test]
417
1
fn test_primary_entity_idx_produces_valid_wasm() {
418
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
419
1
    let program = Reader::parse("(primary-entity-idx)").unwrap();
420
1
    let mut compiler = Compiler::new();
421
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
422
1
    assert_eq!(&wasm[0..4], b"\0asm");
423
1
}
424

            
425
#[test]
426
1
fn test_entity_count_in_comparison_produces_valid_wasm() {
427
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
428
1
    let program = Reader::parse("(if (= (entity-count) 0) \"empty\" \"has-entities\")").unwrap();
429
1
    let mut compiler = Compiler::new();
430
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
431
1
    assert_eq!(&wasm[0..4], b"\0asm");
432
1
}
433

            
434
#[test]
435
1
fn test_entity_count_in_do_loop_produces_valid_wasm() {
436
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
437
1
    let program = Reader::parse(
438
1
        "(let* ((n (entity-count)) (sum 0))
439
1
           (do ((i 0 (+ i 1))) ((>= i n) sum)
440
1
             (setf sum (+ sum 1))))",
441
    )
442
1
    .unwrap();
443
1
    let mut compiler = Compiler::new();
444
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
445
1
    assert_eq!(&wasm[0..4], b"\0asm");
446
1
}
447

            
448
#[test]
449
1
fn test_entity_type_with_idx_produces_valid_wasm() {
450
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
451
1
    symbols.define(
452
1
        Symbol::new("IDX", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::I32)),
453
    );
454
1
    let program = Reader::parse("(entity-type IDX)").unwrap();
455
1
    let mut compiler = Compiler::new();
456
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
457
1
    assert_eq!(&wasm[0..4], b"\0asm");
458
1
}
459

            
460
#[test]
461
1
fn test_entity_parent_idx_produces_valid_wasm() {
462
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
463
1
    symbols.define(
464
1
        Symbol::new("IDX", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::I32)),
465
    );
466
1
    let program = Reader::parse("(entity-parent-idx IDX)").unwrap();
467
1
    let mut compiler = Compiler::new();
468
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
469
1
    assert_eq!(&wasm[0..4], b"\0asm");
470
1
}
471

            
472
#[test]
473
1
fn test_entity_constants_defined() {
474
1
    let symbols = SymbolTable::with_builtins_for_wasm();
475
9
    for name in [
476
1
        "+ENTITY-TRANSACTION+",
477
1
        "+ENTITY-SPLIT+",
478
1
        "+ENTITY-TAG+",
479
1
        "+ENTITY-ACCOUNT+",
480
1
        "+ENTITY-COMMODITY+",
481
1
        "+CONTEXT-CREATE+",
482
1
        "+CONTEXT-UPDATE+",
483
1
        "+CONTEXT-DELETE+",
484
1
        "+CONTEXT-BATCH+",
485
1
    ] {
486
9
        assert!(symbols.lookup(name).is_some(), "missing constant: {name}");
487
    }
488
1
}
489

            
490
// --- SETF with WasmLocal ---
491

            
492
#[test]
493
1
fn test_compile_runtime_setf_wasm_local_produces_valid_wasm() {
494
1
    let mut symbols = SymbolTable::with_builtins_for_wasm();
495
1
    symbols.define(
496
1
        Symbol::new("X", SymbolKind::Variable).with_value(Expr::WasmRuntime(WasmType::Ratio)),
497
    );
498
1
    let program = Reader::parse("(let* ((Y (+ X 1))) (setf Y (+ Y 2)) Y)").unwrap();
499
1
    let mut compiler = Compiler::new();
500
1
    let wasm = compiler.compile(&program, &mut symbols).unwrap();
501
1
    assert_eq!(&wasm[0..4], b"\0asm");
502
1
}