use super::{create_module, get_slot_checked, VMConfig};
struct Point {
x: f64,
}
impl Point {
fn x(&self, vm: &super::VM) {
vm.ensure_slots(1);
vm.set_slot_double(0, self.x);
}
fn set_x(&mut self, vm: &super::VM) {
self.x = get_slot_checked!(vm => num 1);
}
}
impl super::Class for Point {
fn initialize(vm: &super::VM) -> Point {
let x = get_slot_checked!(vm => num 1);
Point { x }
}
}
struct Math;
impl super::Class for Math {
fn initialize(_: &super::VM) -> Math {
Math
}
}
impl Math {
fn add5(vm: &super::VM) {
vm.ensure_slots(2);
let i = get_slot_checked!(vm => num 1);
vm.set_slot_double(0, i + 5.0);
}
fn pointy(vm: &super::VM) {
vm.ensure_slots(2);
let send = vm.set_slot_new_foreign("main", "RawPoint", Point { x: 345.7 }, 0);
if send.is_err() {
panic!("Could not send RawPoint object");
}
}
fn opposite_points(vm: &super::VM) {
vm.ensure_slots(3);
vm.set_slot_new_list(0);
let send = vm.set_slot_new_foreign_scratch("main", "RawPoint", Point { x: 1.0 }, 1, 2);
if send.is_err() {
panic!("Could not send RawPoint object");
}
vm.insert_in_list(0, 0, 1);
let send = vm.set_slot_new_foreign_scratch("main", "RawPoint", Point { x: -1.0 }, 1, 2);
if send.is_err() {
panic!("Could not send RawPoint object");
}
vm.insert_in_list(0, 1, 1);
}
}
create_module! {
class("RawPoint") crate::tests::Point => point {
instance(fn "x", 0) x,
instance(fn "set_x", 1) set_x
}
class("Math") crate::tests::Math => math {
static(fn "add5", 1) add5,
static(fn "pointy", 0) pointy,
static(fn "opposite_points", 0) opposite_points
}
module => main
}
#[test]
fn init_vm() {
let _ = VMConfig::new().build();
}
#[test]
fn test_small_wren_program() {
let vm = VMConfig::new().build();
let interp = vm.interpret("main", "System.print(\"I am running in a VM!\")");
println!("{:?}", interp);
assert!(interp.is_ok());
}
#[test]
fn test_small_wren_program_call() {
let vm = VMConfig::new().build();
let source = vm.interpret(
"main",
r"
class GameEngine {
static update(elapsedTime) {
System.print(elapsedTime)
return 16.45
}
}
",
);
assert!(source.is_ok());
vm.execute(|vm| {
vm.ensure_slots(2);
vm.get_variable("main", "GameEngine", 0);
vm.set_slot_double(1, 32.2);
});
let interp = vm.call(super::FunctionSignature::new_function("update", 1));
assert!(interp.is_ok());
vm.execute(|vm| {
assert_eq!(vm.get_slot_type(0), super::SlotType::Num);
assert_eq!(vm.get_slot_double(0), Some(16.45));
});
}
#[test]
fn test_external_module() {
let mut lib = super::ModuleLibrary::new();
main::publish_module(&mut lib);
let vm = VMConfig::new().library(&lib).build();
let source = vm.interpret(
"main",
"
class Math {
foreign static add5(a)
}
foreign class RawPoint {
construct new(x) {}
foreign x()
foreign set_x(val)
}
class Point {
construct new(x) {
_rp = RawPoint.new(x)
}
x { _rp.x() }
x=(val) { _rp.set_x(val) }
}
class GameEngine {
static update(elapsedTime) {
System.print(elapsedTime)
var p = Point.new(3)
System.print(p.x)
p.x = 10
System.print(p.x)
return Math.add5(16.45)
}
}
",
);
println!("{:?}", source);
assert!(source.is_ok());
vm.execute(|vm| {
vm.ensure_slots(2);
vm.get_variable("main", "GameEngine", 0);
vm.set_slot_double(1, 32.2);
});
let _ = vm.get_slot_handle(0);
let interp = vm.call(super::FunctionSignature::new_function("update", 1));
if let Err(e) = interp.clone() {
eprintln!("{}", e);
}
assert!(interp.is_ok());
vm.execute(|vm| {
assert_eq!(vm.get_slot_type(0), super::SlotType::Num);
assert_eq!(vm.get_slot_double(0), Some(21.45));
})
}
#[test]
fn test_script_module() {
struct TestLoader;
impl super::ModuleScriptLoader for TestLoader {
fn load_script(&mut self, name: String) -> Option<String> {
if name == "math" {
Some(
"
class Math {
static add5(val) {
return val + 5
}
}
"
.into(),
)
} else {
None
}
}
}
let vm = VMConfig::new().script_loader(TestLoader).build();
let source = vm.interpret(
"main",
"
import \"math\" for Math
class GameEngine {
static update(elapsedTime) {
System.print(elapsedTime)
return Math.add5(16.45)
}
}
",
);
assert!(source.is_ok());
vm.execute(|vm| {
vm.ensure_slots(2);
vm.get_variable("main", "GameEngine", 0);
vm.set_slot_double(1, 32.2);
});
let _ = vm.get_slot_handle(0);
let interp = vm.call(super::FunctionSignature::new_function("update", 1));
assert!(interp.is_ok());
vm.execute(|vm| {
assert_eq!(vm.get_slot_type(0), super::SlotType::Num);
assert_eq!(vm.get_slot_double(0), Some(21.45));
});
}
#[test]
fn foreign_instance() {
let mut lib = super::ModuleLibrary::new();
main::publish_module(&mut lib);
let vm = VMConfig::new().library(&lib).build();
let source = vm.interpret(
"main",
"
class Math {
foreign static add5(a)
foreign static pointy()
foreign static opposite_points()
}
foreign class RawPoint {
construct new(x) {}
foreign x()
foreign set_x(val)
}
class GameEngine {
static update(elapsedTime) {
System.print(elapsedTime)
var p = Math.pointy()
System.print(p.x())
var p_list = Math.opposite_points()
//should be zero
var list_sum = p_list.map{|a| a.x()}.reduce{|a, b| a + b}
return Math.add5(16.45 + list_sum)
}
}
",
);
println!("{:?}", source);
assert!(source.is_ok());
vm.execute(|vm| {
vm.ensure_slots(2);
vm.get_variable("main", "GameEngine", 0);
vm.set_slot_double(1, 32.2);
});
let interp = vm.call(super::FunctionSignature::new_function("update", 1));
let _ = vm.get_slot_handle(0);
if let Err(e) = interp.clone() {
eprintln!("{}", e);
}
assert!(interp.is_ok());
vm.execute(|vm| {
assert_eq!(vm.get_slot_type(0), super::SlotType::Num);
assert_eq!(vm.get_slot_double(0), Some(21.45));
});
}