1use std::collections::HashMap;
2#[cfg(feature = "async-runtime")]
3use std::future::Future;
4use std::sync::Arc;
5
6use crate::error::IonError;
7use crate::host_types::{HostEnumDef, HostStructDef, IonType, IonTypeDef};
8use crate::interpreter::{Interpreter, Limits};
9use crate::lexer::Lexer;
10use crate::module::Module;
11use crate::parser::Parser;
12use crate::stdlib::OutputHandler;
13use crate::value::Value;
14
15pub struct Engine {
17 interpreter: Interpreter,
18 output: Arc<dyn OutputHandler>,
19 #[cfg(feature = "async-runtime")]
20 external_queue: crate::async_runtime::ExternalQueue,
21}
22
23impl Engine {
24 pub fn new() -> Self {
25 let output = crate::stdlib::missing_output_handler();
26 Self {
27 interpreter: Interpreter::with_output(Arc::clone(&output)),
28 output,
29 #[cfg(feature = "async-runtime")]
30 external_queue: crate::async_runtime::ExternalQueue::new(),
31 }
32 }
33
34 pub fn with_output<H>(output: H) -> Self
36 where
37 H: OutputHandler + 'static,
38 {
39 Self::with_output_handler(Arc::new(output))
40 }
41
42 pub fn with_output_handler(output: Arc<dyn OutputHandler>) -> Self {
44 Self {
45 interpreter: Interpreter::with_output(Arc::clone(&output)),
46 output,
47 #[cfg(feature = "async-runtime")]
48 external_queue: crate::async_runtime::ExternalQueue::new(),
49 }
50 }
51
52 pub fn eval(&mut self, source: &str) -> Result<Value, IonError> {
54 let mut lexer = Lexer::new(source);
55 let tokens = lexer.tokenize()?;
56 let mut parser = Parser::new(tokens);
57 let program = parser.parse_program()?;
58 self.interpreter.eval_program(&program)
59 }
60
61 #[cfg(feature = "async-runtime")]
67 pub fn eval_async<'a>(
68 &'a mut self,
69 source: &'a str,
70 ) -> crate::async_runtime::IonEvalFuture<'a> {
71 crate::async_runtime::IonEvalFuture::new(self, source)
72 }
73
74 #[cfg(feature = "async-runtime")]
77 pub fn handle(&self) -> crate::async_runtime::EngineHandle {
78 self.external_queue.handle()
79 }
80
81 #[cfg(feature = "async-runtime")]
82 #[allow(dead_code)]
83 pub(crate) fn external_queue(&self) -> crate::async_runtime::ExternalQueue {
84 self.external_queue.clone()
85 }
86
87 #[cfg(feature = "async-runtime")]
88 pub(crate) fn interpreter_mut(&mut self) -> &mut Interpreter {
89 &mut self.interpreter
90 }
91
92 #[cfg(feature = "async-runtime")]
93 pub(crate) fn interpreter(&self) -> &Interpreter {
94 &self.interpreter
95 }
96
97 #[cfg(feature = "async-runtime")]
98 pub(crate) fn output_handler(&self) -> Arc<dyn OutputHandler> {
99 Arc::clone(&self.output)
100 }
101
102 #[cfg(feature = "async-runtime")]
107 #[doc(hidden)]
108 pub fn drain_external_requests(&self) -> Vec<crate::async_runtime::ExternalRequest> {
109 self.external_queue.drain()
110 }
111
112 pub fn set(&mut self, name: &str, value: Value) {
114 self.interpreter.env.define(name.to_string(), value, false);
115 }
116
117 pub fn get(&self, name: &str) -> Option<Value> {
119 self.interpreter.env.get(name).cloned()
120 }
121
122 pub fn get_all(&self) -> HashMap<String, Value> {
124 self.interpreter.env.top_level()
125 }
126
127 pub fn set_limits(&mut self, limits: Limits) {
129 self.interpreter.limits = limits;
130 }
131
132 pub fn set_output<H>(&mut self, output: H)
135 where
136 H: OutputHandler + 'static,
137 {
138 self.set_output_handler(Arc::new(output));
139 }
140
141 pub fn set_output_handler(&mut self, output: Arc<dyn OutputHandler>) {
143 self.output = Arc::clone(&output);
144 let io = crate::stdlib::io_module_with_output(output);
145 self.interpreter
146 .env
147 .define(io.name.clone(), io.to_value(), false);
148 }
149
150 pub fn register_fn(&mut self, name: &str, func: fn(&[Value]) -> Result<Value, String>) {
152 self.interpreter.env.define(
153 name.to_string(),
154 Value::BuiltinFn(name.to_string(), func),
155 false,
156 );
157 }
158
159 pub fn register_closure<F>(&mut self, name: &str, func: F)
165 where
166 F: Fn(&[Value]) -> Result<Value, String> + Send + Sync + 'static,
167 {
168 self.interpreter.env.define(
169 name.to_string(),
170 Value::BuiltinClosure(name.to_string(), crate::value::BuiltinClosureFn::new(func)),
171 false,
172 );
173 }
174
175 #[cfg(feature = "async-runtime")]
178 pub fn register_async_fn<F, Fut>(&mut self, name: &str, func: F)
179 where
180 F: Fn(Vec<Value>) -> Fut + 'static,
181 Fut: Future<Output = Result<Value, IonError>> + 'static,
182 {
183 self.interpreter.env.define(
184 name.to_string(),
185 Value::AsyncBuiltinClosure(
186 name.to_string(),
187 crate::value::AsyncBuiltinClosureFn::new(func),
188 ),
189 false,
190 );
191 }
192
193 pub fn register_struct(&mut self, def: HostStructDef) {
195 self.interpreter.types.register_struct(def);
196 }
197
198 pub fn register_enum(&mut self, def: HostEnumDef) {
200 self.interpreter.types.register_enum(def);
201 }
202
203 pub fn register_module(&mut self, module: Module) {
205 let name = module.name.clone();
206 let value = module.to_value();
207 self.interpreter.env.define(name, value, false);
208 }
209
210 pub fn register_type<T: IonType>(&mut self) {
212 match T::ion_type_def() {
213 IonTypeDef::Struct(def) => self.interpreter.types.register_struct(def),
214 IonTypeDef::Enum(def) => self.interpreter.types.register_enum(def),
215 }
216 }
217
218 pub fn set_typed<T: IonType>(&mut self, name: &str, value: &T) {
220 self.interpreter
221 .env
222 .define(name.to_string(), value.to_ion(), false);
223 }
224
225 pub fn get_typed<T: IonType>(&self, name: &str) -> Result<T, String> {
227 let val = self.interpreter.env.get(name).ok_or_else(|| {
228 format!(
229 "{}{}{}",
230 ion_str!("variable '"),
231 name,
232 ion_str!("' not found")
233 )
234 })?;
235 T::from_ion(val)
236 }
237
238 #[cfg(feature = "vm")]
241 pub fn vm_eval(&mut self, source: &str) -> Result<Value, IonError> {
242 let mut lexer = Lexer::new(source);
243 let tokens = lexer.tokenize()?;
244 let mut parser = Parser::new(tokens);
245 let program = parser.parse_program()?;
246
247 let compiler = crate::compiler::Compiler::new();
249 match compiler.compile_program(&program) {
250 Ok((chunk, fn_chunks)) => {
251 let mut vm = crate::vm::Vm::with_env_and_output(
252 std::mem::take(&mut self.interpreter.env),
253 Arc::clone(&self.output),
254 );
255 vm.preload_fn_chunks(fn_chunks);
257 vm.set_types(self.interpreter.types.clone());
259 let result = vm.execute(&chunk);
260 self.interpreter.env = std::mem::take(vm.env_mut());
262 result
263 }
264 Err(_) => {
265 self.interpreter.eval_program(&program)
267 }
268 }
269 }
270}
271
272impl Default for Engine {
273 fn default() -> Self {
274 Self::new()
275 }
276}