1use crate::ffi::Ffi;
6#[cfg(feature = "go_std")]
7use crate::std::os;
8#[cfg(feature = "serde_borsh")]
9use borsh::BorshSerialize;
10use std::path::Path;
11use std::rc::Rc;
12
13#[cfg(feature = "codegen")]
14pub use {cg::SourceRead, types::ImportKey};
15#[cfg(feature = "codegen")]
16extern crate go_codegen as cg;
17#[cfg(feature = "codegen")]
18extern crate go_parser as parser;
19#[cfg(feature = "codegen")]
20extern crate go_types as types;
21extern crate go_vm as vm;
22
23#[derive(Default)]
24pub struct Config {
25 pub trace_parser: bool,
27 pub trace_checker: bool,
29 pub std_in: Option<Box<dyn std::io::Read + Sync + Send>>,
31 pub std_out: Option<Box<dyn std::io::Write + Sync + Send>>,
33 pub std_err: Option<Box<dyn std::io::Write + Sync + Send>>,
35}
36
37pub struct Engine {
38 ffi: vm::FfiFactory,
39}
40
41impl Engine {
42 pub fn new() -> Engine {
43 #[cfg(not(feature = "go_std"))]
44 {
45 Engine {
46 ffi: vm::FfiFactory::new(),
47 }
48 }
49
50 #[cfg(feature = "go_std")]
51 {
52 let mut e = Engine {
53 ffi: vm::FfiFactory::new(),
54 };
55 crate::std::register(&mut e.ffi);
56 e
57 }
58 }
59
60 pub fn with_user_data(data: usize) -> Engine {
61 #[cfg(not(feature = "go_std"))]
62 {
63 Engine {
64 ffi: vm::FfiFactory::with_user_data(data),
65 }
66 }
67
68 #[cfg(feature = "go_std")]
69 {
70 let mut e = Engine {
71 ffi: vm::FfiFactory::with_user_data(data),
72 };
73 crate::std::register(&mut e.ffi);
74 e
75 }
76 }
77
78 #[cfg(feature = "go_std")]
79 pub fn set_std_io(
80 &self,
81 std_in: Option<Box<dyn std::io::Read + Sync + Send>>,
82 std_out: Option<Box<dyn std::io::Write + Sync + Send>>,
83 std_err: Option<Box<dyn std::io::Write + Sync + Send>>,
84 ) {
85 os::set_std_io(std_in, std_out, std_err);
86 }
87
88 pub fn register_extension(&mut self, name: &'static str, proto: Rc<dyn Ffi>) {
89 self.ffi.register(name, proto);
90 }
91
92 #[cfg(feature = "codegen")]
93 pub fn compile<S: SourceRead>(
94 &self,
95 reader: &S,
96 path: &Path,
97 debug_info: bool,
98 trace_parser: bool,
99 trace_checker: bool,
100 ) -> Result<vm::Bytecode, parser::ErrorList> {
101 let cfg = types::TraceConfig {
102 trace_parser,
103 trace_checker,
104 };
105 cg::parse_check_gen(path, &cfg, reader, debug_info)
106 }
107
108 #[cfg(all(feature = "codegen", feature = "serde_borsh"))]
109 pub fn compile_serialize<S: SourceRead>(
110 &self,
111 reader: &S,
112 path: &Path,
113 debug_info: bool,
114 trace_parser: bool,
115 trace_checker: bool,
116 ) -> Result<Vec<u8>, parser::ErrorList> {
117 self.compile(reader, path, debug_info, trace_parser, trace_checker)
118 .map(|code| code.try_to_vec().unwrap())
119 }
120
121 pub fn run_bytecode(&self, bc: &vm::Bytecode) -> Option<vm::PanicData> {
122 vm::run(bc, &self.ffi)
123 }
124
125 #[cfg(feature = "codegen")]
126 pub fn run_source<S: SourceRead>(
127 &self,
128 trace_parser: bool,
129 trace_checker: bool,
130 reader: &S,
131 path: &Path,
132 panic_handler: Option<Rc<dyn Fn(String, String)>>,
133 ) -> Result<(), parser::ErrorList> {
134 self.compile(reader, path, true, trace_parser, trace_checker)
135 .map(|code| {
136 let pdata = vm::run(&code, &self.ffi);
147 if let Some(pdata) = pdata {
148 let call_stack = vm::CallStackDisplay::new(&pdata, &code);
149 if let Some(handler) = panic_handler {
150 handler(format!("{}", pdata.msg), format!("{}", call_stack));
151 } else {
152 eprintln!("{}\n", pdata.msg);
153 eprintln!("{}\n", call_stack);
154 }
155 }
156 })
157 }
158}