#![cfg(all(feature = "compile", feature = "verify"))]
extern crate alloc;
use alloc::string::String;
use alloc::vec;
use keleusma::bytecode::EnumBody;
use keleusma::compiler::compile;
use keleusma::lexer::tokenize;
use keleusma::parser::parse;
use keleusma::vm::{DEFAULT_ARENA_CAPACITY, Vm, VmState};
use keleusma::{Arena, KeleusmaType, Value};
#[derive(KeleusmaType, Debug, Clone, PartialEq)]
enum Msg {
Note(i64, i64),
Code(i64),
}
#[test]
fn native_struct_with_text_field_flattens_and_reads() {
let src = "use sensor() -> Sensor\n\
use tlen(Text) -> Word\n\
struct Sensor { name: Text, id: Word }\n\
fn main() -> Word { let s = sensor(); s.id + tlen(s.name) }";
let module = compile(&parse(&tokenize(src).expect("lex")).expect("parse")).expect("compile");
let arena = Arena::with_capacity(DEFAULT_ARENA_CAPACITY);
let mut vm = Vm::new(module, &arena).expect("verify");
vm.register_native("sensor", |_| {
Ok(Value::struct_value(
String::from("Sensor"),
vec![
(String::from("name"), Value::StaticStr(String::from("abcd"))),
(String::from("id"), Value::Int(10)),
],
))
});
vm.register_fn("tlen", |s: String| -> i64 { s.len() as i64 });
match vm.call(&[]).expect("call") {
VmState::Finished(v) => assert_eq!(v, Value::Int(14)),
other => panic!("expected finished, got {:?}", other),
}
}
#[test]
fn native_array_of_text_flattens_and_indexes() {
let src = "use lines() -> [Text; 2]\n\
use tlen(Text) -> Word\n\
fn main() -> Word { let a = lines(); tlen(a[0]) + tlen(a[1]) }";
let module = compile(&parse(&tokenize(src).expect("lex")).expect("parse")).expect("compile");
let arena = Arena::with_capacity(DEFAULT_ARENA_CAPACITY);
let mut vm = Vm::new(module, &arena).expect("verify");
vm.register_native("lines", |_| {
Ok(Value::array(vec![
Value::StaticStr(String::from("ab")),
Value::StaticStr(String::from("cde")),
]))
});
vm.register_fn("tlen", |s: String| -> i64 { s.len() as i64 });
match vm.call(&[]).expect("call") {
VmState::Finished(v) => assert_eq!(v, Value::Int(5)),
other => panic!("expected finished, got {:?}", other),
}
}
#[test]
fn native_enum_largest_text_variant_flattens_and_matches() {
let src = "use note() -> Msg\n\
use tlen(Text) -> Word\n\
enum Msg { Note(Text), Code(Word) }\n\
fn main() -> Word { let m = note(); match m { Msg::Note(s) => tlen(s), Msg::Code(n) => n } }";
let module = compile(&parse(&tokenize(src).expect("lex")).expect("parse")).expect("compile");
let arena = Arena::with_capacity(DEFAULT_ARENA_CAPACITY);
let mut vm = Vm::new(module, &arena).expect("verify");
vm.register_native("note", |_| {
Ok(Value::Enum(EnumBody::boxed(
String::from("Msg"),
String::from("Note"),
vec![Value::StaticStr(String::from("hey"))],
)))
});
vm.register_fn("tlen", |s: String| -> i64 { s.len() as i64 });
match vm.call(&[]).expect("call") {
VmState::Finished(v) => assert_eq!(v, Value::Int(3)),
other => panic!("expected finished, got {:?}", other),
}
}
#[test]
fn native_enum_smaller_later_variant_reads_correctly() {
let src = "use code() -> Msg\n\
enum Msg { Note(Text), Code(Word) }\n\
fn main() -> Word { let m = code(); match m { Msg::Note(_) => 0, Msg::Code(n) => n } }";
let module = compile(&parse(&tokenize(src).expect("lex")).expect("parse")).expect("compile");
let arena = Arena::with_capacity(DEFAULT_ARENA_CAPACITY);
let mut vm = Vm::new(module, &arena).expect("verify");
vm.register_native("code", |_| {
Ok(Value::Enum(EnumBody::boxed(
String::from("Msg"),
String::from("Code"),
vec![Value::Int(7)],
)))
});
match vm.call(&[]).expect("call") {
VmState::Finished(v) => assert_eq!(v, Value::Int(7)),
other => panic!("expected finished, got {:?}", other),
}
}
#[test]
fn signatured_native_returns_smaller_enum_variant_correctly() {
let src = "use code() -> Msg\n\
enum Msg { Note(Word, Word), Code(Word) }\n\
fn main() -> Word { let m = code(); match m { Msg::Note(a, b) => a + b, Msg::Code(n) => n } }";
let module = compile(&parse(&tokenize(src).expect("lex")).expect("parse")).expect("compile");
let arena = Arena::with_capacity(DEFAULT_ARENA_CAPACITY);
let mut vm = Vm::new(module, &arena).expect("verify");
vm.register_fn("code", || -> Msg { Msg::Code(7) });
match vm.call(&[]).expect("call") {
VmState::Finished(v) => assert_eq!(v, Value::Int(7)),
other => panic!("expected finished, got {:?}", other),
}
}
#[test]
fn native_option_text_return_matches() {
let src = "use getopt() -> Option<Text>\n\
use tlen(Text) -> Word\n\
fn main() -> Word { match getopt() { Option::Some(s) => tlen(s), Option::None => 0 } }";
let module = compile(&parse(&tokenize(src).expect("lex")).expect("parse")).expect("compile");
let arena = Arena::with_capacity(DEFAULT_ARENA_CAPACITY);
let mut vm = Vm::new(module, &arena).expect("verify");
vm.register_native("getopt", |_| {
Ok(Value::Enum(EnumBody::boxed(
String::from("Option"),
String::from("Some"),
vec![Value::StaticStr(String::from("hello"))],
)))
});
vm.register_fn("tlen", |s: String| -> i64 { s.len() as i64 });
match vm.call(&[]).expect("call") {
VmState::Finished(v) => assert_eq!(v, Value::Int(5)),
other => panic!("expected finished, got {:?}", other),
}
}