extern crate parity_wasm; extern crate tempfile; extern crate wasm_bindgen_wasm_interpreter; use std::fs; use std::process::Command; use wasm_bindgen_wasm_interpreter::Interpreter; fn interpret(wat: &str, name: &str, result: Option<&[u32]>) { let input = tempfile::NamedTempFile::new().unwrap(); let output = tempfile::NamedTempFile::new().unwrap(); fs::write(input.path(), wat).unwrap(); let status = Command::new("wat2wasm") .arg(input.path()) .arg("-o").arg(output.path()) .status() .unwrap(); println!("status: {}", status); assert!(status.success()); let module = parity_wasm::deserialize_file(output.path()).unwrap(); let mut i = Interpreter::new(&module); assert_eq!(i.interpret(name, &module), result); } #[test] fn smoke() { let wat = r#" (module (export "foo" (func $foo)) (func $foo) ) "#; interpret(wat, "foo", Some(&[])); interpret(wat, "bar", None); let wat = r#" (module (import "__wbindgen_placeholder__" "__wbindgen_describe" (func $__wbindgen_describe (param i32))) (func $foo i32.const 1 call $__wbindgen_describe ) (export "foo" (func $foo)) ) "#; interpret(wat, "foo", Some(&[1])); } #[test] fn locals() { let wat = r#" (module (import "__wbindgen_placeholder__" "__wbindgen_describe" (func $__wbindgen_describe (param i32))) (func $foo (local i32) i32.const 2 set_local 0 get_local 0 call $__wbindgen_describe ) (export "foo" (func $foo)) ) "#; interpret(wat, "foo", Some(&[2])); } #[test] fn globals() { let wat = r#" (module (import "__wbindgen_placeholder__" "__wbindgen_describe" (func $__wbindgen_describe (param i32))) (global i32 (i32.const 0)) (func $foo (local i32) get_global 0 set_local 0 get_local 0 call $__wbindgen_describe get_local 0 set_global 0 ) (export "foo" (func $foo)) ) "#; interpret(wat, "foo", Some(&[256])); } #[test] fn arithmetic() { let wat = r#" (module (import "__wbindgen_placeholder__" "__wbindgen_describe" (func $__wbindgen_describe (param i32))) (func $foo i32.const 1 i32.const 2 i32.add call $__wbindgen_describe i32.const 2 i32.const 1 i32.sub call $__wbindgen_describe ) (export "foo" (func $foo)) ) "#; interpret(wat, "foo", Some(&[3, 1])); } #[test] fn return_early() { let wat = r#" (module (import "__wbindgen_placeholder__" "__wbindgen_describe" (func $__wbindgen_describe (param i32))) (func $foo i32.const 1 i32.const 2 call $__wbindgen_describe return ) (export "foo" (func $foo)) ) "#; interpret(wat, "foo", Some(&[2])); } #[test] fn loads_and_stores() { let wat = r#" (module (import "__wbindgen_placeholder__" "__wbindgen_describe" (func $__wbindgen_describe (param i32))) (global i32 (i32.const 0)) (memory 1) (func $foo (local i32) ;; decrement the stack pointer, setting our local to the ;; lowest address of our stack get_global 0 i32.const 16 i32.sub set_local 0 get_local 0 set_global 0 ;; store 1 at fp+0 get_local 0 i32.const 1 i32.store offset=0 ;; store 2 at fp+4 get_local 0 i32.const 2 i32.store offset=4 ;; store 3 at fp+8 get_local 0 i32.const 3 i32.store offset=8 ;; load fp+0 and call get_local 0 i32.load offset=0 call $__wbindgen_describe ;; load fp+4 and call get_local 0 i32.load offset=4 call $__wbindgen_describe ;; load fp+8 and call get_local 0 i32.load offset=8 call $__wbindgen_describe ;; increment our stack pointer get_local 0 i32.const 16 i32.add set_global 0 ) (export "foo" (func $foo)) ) "#; interpret(wat, "foo", Some(&[1, 2, 3])); } #[test] fn calling_functions() { let wat = r#" (module (import "__wbindgen_placeholder__" "__wbindgen_describe" (func $__wbindgen_describe (param i32))) (global i32 (i32.const 0)) (memory 1) (func $foo call $bar ) (func $bar i32.const 0 call $__wbindgen_describe ) (export "foo" (func $foo)) ) "#; interpret(wat, "foo", Some(&[0])); }