forked from roc-lang/roc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.rs
119 lines (96 loc) · 3.67 KB
/
main.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use bumpalo::{collections::Vec, Bump};
use clap::ArgAction;
use clap::{Arg, Command};
use std::fs;
use std::io;
use std::iter::once;
use std::process;
use roc_wasm_interp::{DefaultImportDispatcher, Instance};
use roc_wasm_module::WasmModule;
pub const FLAG_FUNCTION: &str = "function";
pub const FLAG_DEBUG: &str = "debug";
pub const FLAG_HEX: &str = "hex";
pub const WASM_FILE: &str = "WASM_FILE";
pub const ARGS_FOR_APP: &str = "ARGS_FOR_APP";
fn main() -> io::Result<()> {
let arena = Bump::new();
// Define the command line arguments
let flag_function = Arg::new(FLAG_FUNCTION)
.long(FLAG_FUNCTION)
.help("Call a specific function exported from the WebAssembly module")
.default_value("_start")
.required(false);
let flag_debug = Arg::new(FLAG_DEBUG)
.long(FLAG_DEBUG)
.help("Print a log of every instruction executed, for debugging purposes.")
.action(ArgAction::SetTrue)
.required(false);
let flag_hex = Arg::new(FLAG_HEX)
.long(FLAG_HEX)
.help("If the called function returns a value, print it in hexadecimal format.")
.action(ArgAction::SetTrue)
.required(false);
let wasm_file_to_run = Arg::new(WASM_FILE)
.help("The .wasm file to run")
.required(true);
let args_for_app = Arg::new(ARGS_FOR_APP)
.help("Arguments to pass into the WebAssembly app\ne.g. `roc_wasm_interp app.wasm 123 123.45`")
.num_args(0..);
let app = Command::new("roc_wasm_interp")
.about("Run the given .wasm file")
.arg(flag_function)
.arg(flag_debug)
.arg(flag_hex)
.arg(wasm_file_to_run)
.arg(args_for_app);
// Parse the command line arguments
let matches = app.get_matches();
let start_fn_name = matches.get_one::<String>(FLAG_FUNCTION).unwrap();
let is_debug_mode = matches.get_flag(FLAG_DEBUG);
let is_hex_format = matches.get_flag(FLAG_HEX);
let start_arg_strings = matches.get_many::<String>(ARGS_FOR_APP).unwrap_or_default();
let wasm_path = matches.get_one::<String>(WASM_FILE).unwrap();
// WASI expects the .wasm file to be argv[0]
let wasi_argv_iter = once(wasm_path)
.chain(start_arg_strings)
.map(|s| s.as_bytes());
let wasi_argv = Vec::from_iter_in(wasi_argv_iter, &arena);
// Load the WebAssembly binary file
let module_bytes = fs::read(wasm_path)?;
// Parse the binary data
let require_relocatable = false;
let module = match WasmModule::preload(&arena, &module_bytes, require_relocatable) {
Ok(m) => m,
Err(e) => {
eprintln!("I couldn't parse this WebAssembly module! There's something wrong at byte offset {:#x}.", e.offset);
eprintln!("{}", e.message);
eprintln!("If you think this could be a code generation problem in the Roc compiler, see crates/compiler/gen_wasm/README.md for debugging tips.");
process::exit(1);
}
};
// Create an execution instance
let dispatcher = DefaultImportDispatcher::new(&wasi_argv);
let mut inst =
Instance::for_module(&arena, &module, dispatcher, is_debug_mode).unwrap_or_else(|e| {
eprintln!("{}", e);
process::exit(2);
});
// Run
let result = inst.call_export_from_cli(&module, start_fn_name, &wasi_argv);
// Print out return value, if any
match result {
Ok(Some(val)) => {
if is_hex_format {
println!("{:#x?}", val)
} else {
println!("{:?}", val)
}
}
Ok(None) => {}
Err(e) => {
eprintln!("{}", e);
process::exit(3);
}
}
Ok(())
}