#![cfg(all(feature = "compile", feature = "verify"))]
extern crate alloc;
use keleusma::Arena;
use keleusma::bytecode::Value;
use keleusma::compiler::compile;
use keleusma::lexer::tokenize;
use keleusma::parser::parse;
use keleusma::vm::{DEFAULT_ARENA_CAPACITY, Vm, VmState, required_persistent_capacity_for};
fn run_word(src: &str) -> i64 {
let m = compile(&parse(&tokenize(src).expect("lex")).expect("parse")).expect("compile");
let need = required_persistent_capacity_for(&m);
let mut arena = Arena::with_capacity(DEFAULT_ARENA_CAPACITY + need);
arena.resize_persistent(need).expect("resize_persistent");
let mut vm = Vm::new(m, &arena).expect("verify");
match vm.call(&[]).expect("call") {
VmState::Finished(Value::Int(n)) => n,
other => panic!("expected Int, got {:?}", other),
}
}
#[test]
fn private_struct_slot_write_then_read() {
let src = "struct Point { x: Word, y: Word }\n\
private data d { p: Point }\n\
fn main() -> Word { d.p = Point { x: 3, y: 4 }; d.p.x + d.p.y }";
assert_eq!(run_word(src), 7);
}
#[test]
fn private_tuple_slot_write_then_read() {
let src = "private data d { t: (Word, Word) }\n\
fn main() -> Word { d.t = (10, 20); d.t.0 + d.t.1 }";
assert_eq!(run_word(src), 30);
}
#[test]
fn d4_private_composite_write_bounded_by_slot_region() {
let src = "struct Point { x: Word, y: Word }\n\
private data d { a: Point, b: Point }\n\
fn main() -> Word { d.a = Point { x: 1, y: 2 }; 0 }";
let mut m = compile(&parse(&tokenize(src).expect("lex")).expect("parse")).expect("compile");
{
let dl = m.data_layout.as_mut().expect("data layout");
assert!(
dl.private_composite_layout.len() >= 2,
"expected two private composite slots"
);
dl.private_composite_layout[0].offset = 0;
dl.private_composite_layout[1].offset = 1;
}
let need = required_persistent_capacity_for(&m);
let mut arena = Arena::with_capacity(DEFAULT_ARENA_CAPACITY + need);
arena.resize_persistent(need).expect("resize_persistent");
let mut vm = Vm::new(m, &arena).expect("verify");
let err = vm
.call(&[])
.expect_err("the overrunning composite write must fault, not corrupt the neighbour");
let msg = alloc::format!("{err:?}");
assert!(
msg.contains("overruns its pool slot region"),
"expected a D4 pool-region fault, got: {msg}"
);
}
#[test]
fn private_nested_struct_slot_round_trips() {
let src = "struct Inner { a: Word, b: Word }\n\
struct Outer { inner: Inner, c: Word }\n\
private data d { o: Outer }\n\
fn main() -> Word { \
d.o = Outer { inner: Inner { a: 1, b: 2 }, c: 3 }; \
d.o.inner.a + d.o.inner.b + d.o.c }";
assert_eq!(run_word(src), 6);
}
#[test]
fn private_composite_survives_reset() {
let src = "struct Point { x: Word, y: Word }\n\
private data d { p: Point }\n\
loop main(seed: Word) -> Word { \
if seed == 0 { d.p = Point { x: 11, y: 22 }; }; \
let _ = yield d.p.x + d.p.y; \
0 \
}";
let m = compile(&parse(&tokenize(src).expect("lex")).expect("parse")).expect("compile");
let need = required_persistent_capacity_for(&m);
let mut arena = Arena::with_capacity(DEFAULT_ARENA_CAPACITY + need);
arena.resize_persistent(need).expect("resize_persistent");
let mut vm = Vm::new(m, &arena).expect("verify");
match vm.call(&[Value::Int(0)]).expect("call") {
VmState::Yielded(Value::Int(n)) => assert_eq!(n, 33),
other => panic!("iter 1 expected Yielded(33), got {:?}", other),
}
match vm.resume(Value::Int(1)).expect("resume") {
VmState::Reset => {}
other => panic!("expected Reset at loop body end, got {:?}", other),
}
match vm.resume(Value::Int(1)).expect("resume") {
VmState::Yielded(Value::Int(n)) => {
assert_eq!(n, 33, "private composite must survive RESET")
}
other => panic!("iter 2 expected Yielded(33), got {:?}", other),
}
}
#[test]
fn private_array_of_struct_write_then_read() {
let src = "struct Point { x: Word, y: Word }\n\
private data d { arr: [Point; 4] }\n\
fn main() -> Word { \
d.arr[0] = Point { x: 1, y: 2 }; \
d.arr[3] = Point { x: 30, y: 40 }; \
d.arr[0].x + d.arr[0].y + d.arr[3].x + d.arr[3].y }";
assert_eq!(run_word(src), 1 + 2 + 30 + 40);
}
#[test]
fn private_array_of_struct_survives_reset() {
let src = "struct Point { x: Word, y: Word }\n\
private data d { arr: [Point; 4] }\n\
loop main(seed: Word) -> Word { \
if seed == 0 { \
d.arr[1] = Point { x: 5, y: 6 }; \
d.arr[2] = Point { x: 7, y: 8 }; \
}; \
let _ = yield d.arr[1].x + d.arr[1].y + d.arr[2].x + d.arr[2].y; \
0 \
}";
let m = compile(&parse(&tokenize(src).expect("lex")).expect("parse")).expect("compile");
let need = required_persistent_capacity_for(&m);
let mut arena = Arena::with_capacity(DEFAULT_ARENA_CAPACITY + need);
arena.resize_persistent(need).expect("resize_persistent");
let mut vm = Vm::new(m, &arena).expect("verify");
let want = 5 + 6 + 7 + 8;
match vm.call(&[Value::Int(0)]).expect("call") {
VmState::Yielded(Value::Int(n)) => assert_eq!(n, want),
other => panic!("iter 1 expected Yielded({want}), got {:?}", other),
}
match vm.resume(Value::Int(1)).expect("resume") {
VmState::Reset => {}
other => panic!("expected Reset at loop body end, got {:?}", other),
}
match vm.resume(Value::Int(1)).expect("resume") {
VmState::Yielded(Value::Int(n)) => {
assert_eq!(n, want, "array-of-composite elements must survive RESET")
}
other => panic!("iter 2 expected Yielded({want}), got {:?}", other),
}
}