diff --git a/src/builder/module.rs b/src/builder/module.rs index 39cc198..36a5707 100644 --- a/src/builder/module.rs +++ b/src/builder/module.rs @@ -299,6 +299,12 @@ impl ModuleBuilder where F: Invoke { import::ImportBuilder::with_callback(self) } + /// With global variable + pub fn with_global(mut self, global: elements::GlobalEntry) -> Self { + self.module.global.entries_mut().push(global); + self + } + /// Build module (final step) pub fn build(self) -> F::Result { self.callback.invoke(self.module.into()) diff --git a/src/elements/global_entry.rs b/src/elements/global_entry.rs index 9fb23bb..3e3201f 100644 --- a/src/elements/global_entry.rs +++ b/src/elements/global_entry.rs @@ -8,6 +8,13 @@ pub struct GlobalEntry { } impl GlobalEntry { + /// Create new global. + pub fn new(global_type: GlobalType, init_expr: InitExpr) -> Self { + GlobalEntry { + global_type: global_type, + init_expr: init_expr, + } + } /// Global type. pub fn global_type(&self) -> &GlobalType { &self.global_type } /// Initialization expression (opcodes) for global. diff --git a/src/elements/section.rs b/src/elements/section.rs index 08ff143..4761d0c 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -409,6 +409,11 @@ impl GlobalSection { pub fn entries(&self) -> &[GlobalEntry] { &self.0 } + + /// Mutable list of all global entries in the section + pub fn entries_mut(&mut self) -> &mut Vec { + &mut self.0 + } } impl Deserialize for GlobalSection { diff --git a/src/interpreter/tests/basics.rs b/src/interpreter/tests/basics.rs new file mode 100644 index 0000000..ba877b1 --- /dev/null +++ b/src/interpreter/tests/basics.rs @@ -0,0 +1,87 @@ +///! Basic tests for instructions/constructions, missing in wabt tests + +use builder::module; +use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, GlobalType, + InitExpr, ValueType, Opcodes, Opcode}; +use interpreter::Error; +use interpreter::program::ProgramInstance; +use interpreter::value::RuntimeValue; + +#[test] +fn import_function() { + let module1 = module() + .with_export(ExportEntry::new("external_func".into(), Internal::Function(0))) + .function() + .signature().return_type().i32().build() + .body().with_opcodes(Opcodes::new(vec![ + Opcode::I32Const(3), + Opcode::End, + ])).build() + .build() + .build(); + + let module2 = module() + .with_import(ImportEntry::new("external_module".into(), "external_func".into(), External::Function(0))) + .function() + .signature().return_type().i32().build() + .body().with_opcodes(Opcodes::new(vec![ + Opcode::Call(0), + Opcode::I32Const(7), + Opcode::I32Add, + Opcode::End, + ])).build() + .build() + .build(); + + let program = ProgramInstance::new(); + let external_module = program.add_module("external_module", module1).unwrap(); + let main_module = program.add_module("main", module2).unwrap(); + + assert_eq!(external_module.execute(0, vec![]).unwrap().unwrap(), RuntimeValue::I32(3)); + assert_eq!(main_module.execute(1, vec![]).unwrap().unwrap(), RuntimeValue::I32(10)); +} + +#[test] +fn global_get_set() { + let module = module() + .with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, true), InitExpr::new(vec![Opcode::I32Const(42)]))) + .with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Opcode::I32Const(777)]))) + .function() + .signature().return_type().i32().build() + .body().with_opcodes(Opcodes::new(vec![ + Opcode::GetGlobal(0), + Opcode::I32Const(8), + Opcode::I32Add, + Opcode::SetGlobal(0), + Opcode::GetGlobal(0), + Opcode::End, + ])).build() + .build() + .function() + .signature().return_type().i32().build() + .body().with_opcodes(Opcodes::new(vec![ + Opcode::GetGlobal(1), + Opcode::I32Const(8), + Opcode::I32Add, + Opcode::SetGlobal(1), + Opcode::GetGlobal(1), + Opcode::End, + ])).build() + .build() + .function() + .signature().return_type().i32().build() + .body().with_opcodes(Opcodes::new(vec![ + Opcode::I64Const(8), + Opcode::SetGlobal(0), + Opcode::GetGlobal(0), + Opcode::End, + ])).build() + .build() + .build(); + + let program = ProgramInstance::new(); + let module = program.add_module("main", module).unwrap(); + assert_eq!(module.execute(0, vec![]).unwrap().unwrap(), RuntimeValue::I32(50)); + assert_eq!(module.execute(1, vec![]).unwrap_err(), Error::Variable("trying to update immutable variable".into())); + assert_eq!(module.execute(2, vec![]).unwrap_err(), Error::Variable("trying to update variable of type I32 with value of type Some(I64)".into())); +} diff --git a/src/interpreter/tests/import.rs b/src/interpreter/tests/import.rs deleted file mode 100644 index 070d3b7..0000000 --- a/src/interpreter/tests/import.rs +++ /dev/null @@ -1,38 +0,0 @@ -use builder::module; -use elements::{ExportEntry, Internal, ImportEntry, External, Opcodes, Opcode}; -use interpreter::program::ProgramInstance; -use interpreter::value::RuntimeValue; - -#[test] -fn import_function() { - let module1 = module() - .with_export(ExportEntry::new("external_func".into(), Internal::Function(0))) - .function() - .signature().return_type().i32().build() - .body().with_opcodes(Opcodes::new(vec![ - Opcode::I32Const(3), - Opcode::End, - ])).build() - .build() - .build(); - - let module2 = module() - .with_import(ImportEntry::new("external_module".into(), "external_func".into(), External::Function(0))) - .function() - .signature().return_type().i32().build() - .body().with_opcodes(Opcodes::new(vec![ - Opcode::Call(0), - Opcode::I32Const(7), - Opcode::I32Add, - Opcode::End, - ])).build() - .build() - .build(); - - let program = ProgramInstance::new(); - let external_module = program.add_module("external_module", module1).unwrap(); - let main_module = program.add_module("main", module2).unwrap(); - - assert_eq!(external_module.execute(0, vec![]).unwrap().unwrap(), RuntimeValue::I32(3)); - assert_eq!(main_module.execute(1, vec![]).unwrap().unwrap(), RuntimeValue::I32(10)); -} diff --git a/src/interpreter/tests/mod.rs b/src/interpreter/tests/mod.rs index fd2c28a..349e08d 100644 --- a/src/interpreter/tests/mod.rs +++ b/src/interpreter/tests/mod.rs @@ -1,2 +1,2 @@ -mod import; -mod wabt; \ No newline at end of file +mod basics; +mod wabt;