1use std::collections::hash_map::DefaultHasher;
2use std::hash::{Hash, Hasher};
3use std::ops::Deref;
4use std::path::Path;
5use std::sync::Arc;
6
7use rexlang_ast::expr::{Expr, Program, Symbol, sym};
8use rexlang_typesystem::{Subst, Type, TypeError, TypedExpr, Types, unify};
9use rexlang_util::{GasMeter, sha256_hex};
10
11use crate::engine::{
12 CompiledProgram, NativeImpl, OverloadedFn, RuntimeSnapshot, check_runtime_cancelled,
13 eval_typed_expr, impl_matches_type, is_function_type, type_head_is_var,
14};
15use crate::libraries::{LibraryId, ReplState, ResolvedLibrary};
16use crate::value::Value;
17use crate::{
18 CompileError, Compiler, EngineError, Env, EvalError, ExecutionError, Pointer, RuntimeEnv,
19};
20
21pub struct Evaluator<State = ()>
22where
23 State: Clone + Send + Sync + 'static,
24{
25 pub(crate) runtime: RuntimeEnv<State>,
26 pub(crate) compiler: Option<Compiler<State>>,
27}
28
29#[derive(Clone, Copy)]
30pub struct EvaluatorRef<'a, State = ()>
31where
32 State: Clone + Send + Sync + 'static,
33{
34 runtime: &'a RuntimeSnapshot<State>,
35}
36
37impl<State> Evaluator<State>
38where
39 State: Clone + Send + Sync + 'static,
40{
41 pub fn new(runtime: RuntimeEnv<State>) -> Self {
42 Self {
43 runtime,
44 compiler: None,
45 }
46 }
47
48 pub fn new_with_compiler(runtime: RuntimeEnv<State>, compiler: Compiler<State>) -> Self {
49 Self {
50 runtime,
51 compiler: Some(compiler),
52 }
53 }
54
55 pub(crate) fn sync_runtime_from_compiler(&mut self) {
56 if let Some(compiler) = &self.compiler {
57 self.runtime.sync_from_engine(&compiler.engine);
58 }
59 }
60
61 pub async fn run(
62 &mut self,
63 program: &CompiledProgram,
64 gas: &mut GasMeter,
65 ) -> Result<Pointer, EvalError> {
66 self.run_internal(program, gas)
67 .await
68 .map_err(EvalError::from)
69 }
70
71 pub(crate) async fn run_internal(
72 &mut self,
73 program: &CompiledProgram,
74 gas: &mut GasMeter,
75 ) -> Result<Pointer, EngineError> {
76 check_runtime_cancelled(&self.runtime.runtime)?;
77 self.runtime.validate_internal(program)?;
78 eval_typed_expr(
79 &self.runtime.runtime,
80 &program.env,
81 program.expr.as_ref(),
82 gas,
83 )
84 .await
85 }
86
87 pub async fn eval(
88 &mut self,
89 expr: &Expr,
90 gas: &mut GasMeter,
91 ) -> Result<(Pointer, Type), ExecutionError> {
92 self.prepare_and_run(gas, |compiler, _gas| compiler.compile_expr(expr))
93 .await
94 }
95
96 pub(crate) async fn run_prepared(
97 &mut self,
98 program: CompiledProgram,
99 gas: &mut GasMeter,
100 ) -> Result<(Pointer, Type), ExecutionError> {
101 self.sync_runtime_from_compiler();
102 let typ = program.result_type().clone();
103 let value = self.run(&program, gas).await?;
104 Ok((value, typ))
105 }
106
107 pub(crate) async fn prepare_and_run<F>(
108 &mut self,
109 gas: &mut GasMeter,
110 compile: F,
111 ) -> Result<(Pointer, Type), ExecutionError>
112 where
113 F: FnOnce(&mut Compiler<State>, &mut GasMeter) -> Result<CompiledProgram, CompileError>,
114 {
115 let compiler = self.compiler.as_mut().ok_or_else(|| {
116 CompileError::from(EngineError::Internal("evaluator has no compiler".into()))
117 })?;
118 let program = compile(compiler, gas)?;
119 self.run_prepared(program, gas).await
120 }
121
122 pub async fn eval_library_file(
123 &mut self,
124 path: impl AsRef<Path>,
125 gas: &mut GasMeter,
126 ) -> Result<(Pointer, Type), ExecutionError> {
127 let (id, bytes) = self
128 .runtime
129 .loader
130 .read_local_library_bytes(path.as_ref())
131 .map_err(CompileError::from)?;
132 let source_fingerprint = sha256_hex(&bytes);
133 if let Some(inst) = self
134 .runtime
135 .loader
136 .modules
137 .cached(&id)
138 .map_err(EvalError::from)?
139 {
140 if inst.source_fingerprint.as_deref() == Some(source_fingerprint.as_str()) {
141 return Ok((inst.init_value, inst.init_type));
142 }
143 self.runtime
144 .loader
145 .invalidate_library_caches(&id)
146 .map_err(EvalError::from)?;
147 }
148 let source = self
149 .runtime
150 .loader
151 .decode_local_library_source(&id, bytes)
152 .map_err(CompileError::from)?;
153 let inst = self
154 .runtime
155 .loader
156 .load_library_from_resolved(ResolvedLibrary { id, source }, gas)
157 .await
158 .map_err(CompileError::from)?;
159 Ok((inst.init_value, inst.init_type))
160 }
161
162 pub async fn eval_library_source(
163 &mut self,
164 source: &str,
165 gas: &mut GasMeter,
166 ) -> Result<(Pointer, Type), ExecutionError> {
167 let mut hasher = DefaultHasher::new();
168 source.hash(&mut hasher);
169 let id = LibraryId::Virtual(format!("<inline:{:016x}>", hasher.finish()));
170 if let Some(inst) = self
171 .runtime
172 .loader
173 .modules
174 .cached(&id)
175 .map_err(EvalError::from)?
176 {
177 return Ok((inst.init_value, inst.init_type));
178 }
179 let inst = self
180 .runtime
181 .loader
182 .load_library_from_resolved(
183 ResolvedLibrary {
184 id,
185 source: source.to_string(),
186 },
187 gas,
188 )
189 .await
190 .map_err(CompileError::from)?;
191 Ok((inst.init_value, inst.init_type))
192 }
193
194 pub async fn eval_snippet(
195 &mut self,
196 source: &str,
197 gas: &mut GasMeter,
198 ) -> Result<(Pointer, Type), ExecutionError> {
199 self.prepare_and_run(gas, |compiler, gas| compiler.compile_snippet(source, gas))
200 .await
201 }
202
203 pub async fn eval_repl_program(
204 &mut self,
205 program: &Program,
206 state: &mut ReplState,
207 gas: &mut GasMeter,
208 ) -> Result<(Pointer, Type), ExecutionError> {
209 let compiler = self.compiler.as_mut().ok_or_else(|| {
210 CompileError::from(EngineError::Internal("evaluator has no compiler".into()))
211 })?;
212 let compiled = compiler.compile_repl_program(program, state, gas).await?;
213 self.run_prepared(compiled, gas).await
214 }
215
216 pub async fn eval_snippet_at(
217 &mut self,
218 source: &str,
219 importer_path: impl AsRef<Path>,
220 gas: &mut GasMeter,
221 ) -> Result<(Pointer, Type), ExecutionError> {
222 let path = importer_path.as_ref().to_path_buf();
223 self.prepare_and_run(gas, |compiler, gas| {
224 compiler.compile_snippet_at(source, &path, gas)
225 })
226 .await
227 }
228}
229
230impl<'a, State> EvaluatorRef<'a, State>
231where
232 State: Clone + Send + Sync + 'static,
233{
234 pub(crate) fn new(runtime: &'a RuntimeSnapshot<State>) -> Self {
235 Self { runtime }
236 }
237
238 fn resolve_typeclass_method_impl(
239 &self,
240 name: &Symbol,
241 call_type: &Type,
242 ) -> Result<(Env, Arc<TypedExpr>, Subst), EngineError> {
243 let info = self
244 .runtime
245 .type_system
246 .class_methods
247 .get(name)
248 .ok_or_else(|| EngineError::UnknownVar(name.clone()))?;
249
250 let s_method = unify(&info.scheme.typ, call_type).map_err(EngineError::Type)?;
251 let class_pred = info
252 .scheme
253 .preds
254 .iter()
255 .find(|p| p.class == info.class)
256 .ok_or(EngineError::Type(TypeError::UnsupportedExpr(
257 "method scheme missing class predicate",
258 )))?;
259 let param_type = class_pred.typ.apply(&s_method);
260 if type_head_is_var(¶m_type) {
261 return Err(EngineError::AmbiguousOverload { name: name.clone() });
262 }
263
264 self.runtime
265 .typeclasses
266 .resolve(&info.class, name, ¶m_type)
267 }
268
269 fn cached_class_method(&self, name: &Symbol, typ: &Type) -> Option<Pointer> {
270 if !typ.ftv().is_empty() {
271 return None;
272 }
273 let cache = self.runtime.typeclass_cache.lock().ok()?;
274 cache.get(&(name.clone(), typ.clone())).cloned()
275 }
276
277 fn insert_cached_class_method(&self, name: &Symbol, typ: &Type, pointer: &Pointer) {
278 if typ.ftv().is_empty()
279 && let Ok(mut cache) = self.runtime.typeclass_cache.lock()
280 {
281 cache.insert((name.clone(), typ.clone()), *pointer);
282 }
283 }
284
285 fn resolve_class_method_plan(
286 &self,
287 name: &Symbol,
288 typ: &Type,
289 ) -> Result<Result<(Env, TypedExpr), Pointer>, EngineError> {
290 let (def_env, typed, s) = match self.resolve_typeclass_method_impl(name, typ) {
291 Ok(res) => res,
292 Err(EngineError::AmbiguousOverload { .. }) if is_function_type(typ) => {
293 let (name, typ, applied, applied_types) =
294 OverloadedFn::new(name.clone(), typ.clone()).into_parts();
295 let pointer =
296 self.runtime
297 .heap
298 .alloc_overloaded(name, typ, applied, applied_types)?;
299 return Ok(Err(pointer));
300 }
301 Err(err) => return Err(err),
302 };
303 let specialized = typed.as_ref().apply(&s);
304 Ok(Ok((def_env, specialized)))
305 }
306
307 pub(crate) async fn resolve_class_method(
308 &self,
309 name: &Symbol,
310 typ: &Type,
311 gas: &mut GasMeter,
312 ) -> Result<Pointer, EngineError> {
313 if let Some(pointer) = self.cached_class_method(name, typ) {
314 return Ok(pointer);
315 }
316
317 let pointer = match self.resolve_class_method_plan(name, typ)? {
318 Ok((def_env, specialized)) => {
319 eval_typed_expr(self.runtime, &def_env, &specialized, gas).await?
320 }
321 Err(pointer) => pointer,
322 };
323
324 if typ.ftv().is_empty() {
325 self.insert_cached_class_method(name, typ, &pointer);
326 }
327 Ok(pointer)
328 }
329
330 pub(crate) fn resolve_native_impl(
331 &self,
332 name: &str,
333 typ: &Type,
334 ) -> Result<NativeImpl<State>, EngineError> {
335 let sym_name = sym(name);
336 let impls = self
337 .runtime
338 .natives
339 .get(&sym_name)
340 .ok_or_else(|| EngineError::UnknownVar(sym_name.clone()))?;
341 let matches: Vec<NativeImpl<State>> = impls
342 .iter()
343 .filter(|imp| impl_matches_type(imp, typ))
344 .cloned()
345 .collect();
346 match matches.len() {
347 0 => Err(EngineError::MissingImpl {
348 name: sym_name.clone(),
349 typ: typ.to_string(),
350 }),
351 1 => Ok(matches[0].clone()),
352 _ => Err(EngineError::AmbiguousImpl {
353 name: sym_name,
354 typ: typ.to_string(),
355 }),
356 }
357 }
358
359 pub(crate) fn resolve_native(
360 &self,
361 name: &str,
362 typ: &Type,
363 _gas: &mut GasMeter,
364 ) -> Result<Pointer, EngineError> {
365 let sym_name = sym(name);
366 let impls = self
367 .runtime
368 .natives
369 .get(&sym_name)
370 .ok_or_else(|| EngineError::UnknownVar(sym_name.clone()))?;
371 let matches: Vec<NativeImpl<State>> = impls
372 .iter()
373 .filter(|imp| impl_matches_type(imp, typ))
374 .cloned()
375 .collect();
376 match matches.len() {
377 0 => Err(EngineError::MissingImpl {
378 name: sym_name.clone(),
379 typ: typ.to_string(),
380 }),
381 1 => {
382 let imp = matches[0].clone();
383 let (native_id, name, arity, typ, gas_cost, applied, applied_types) =
384 imp.to_native_fn(typ.clone()).into_parts();
385 self.runtime.heap.alloc_native(
386 native_id,
387 name,
388 arity,
389 typ,
390 gas_cost,
391 applied,
392 applied_types,
393 )
394 }
395 _ => {
396 if typ.ftv().is_empty() {
397 Err(EngineError::AmbiguousImpl {
398 name: sym_name.clone(),
399 typ: typ.to_string(),
400 })
401 } else if is_function_type(typ) {
402 let (name, typ, applied, applied_types) =
403 OverloadedFn::new(sym_name.clone(), typ.clone()).into_parts();
404 self.runtime
405 .heap
406 .alloc_overloaded(name, typ, applied, applied_types)
407 } else {
408 Err(EngineError::AmbiguousOverload { name: sym_name })
409 }
410 }
411 }
412 }
413
414 pub(crate) async fn resolve_global(
415 &self,
416 name: &Symbol,
417 typ: &Type,
418 ) -> Result<Pointer, EngineError> {
419 if let Some(ptr) = self.runtime.env.get(name) {
420 let value = self.runtime.heap.get(&ptr)?;
421 match value.as_ref() {
422 Value::Native(native) if native.is_zero_unapplied() => {
423 let mut gas = GasMeter::default();
424 native.call_zero(self.runtime, &mut gas).await
425 }
426 _ => Ok(ptr),
427 }
428 } else if self.runtime.type_system.class_methods.contains_key(name) {
429 let mut gas = GasMeter::default();
430 self.resolve_class_method(name, typ, &mut gas).await
431 } else {
432 let mut gas = GasMeter::default();
433 let pointer = self.resolve_native(name.as_ref(), typ, &mut gas)?;
434 let value = self.runtime.heap.get(&pointer)?;
435 match value.as_ref() {
436 Value::Native(native) if native.is_zero_unapplied() => {
437 let mut gas = GasMeter::default();
438 native.call_zero(self.runtime, &mut gas).await
439 }
440 _ => Ok(pointer),
441 }
442 }
443 }
444
445 pub(crate) async fn call_native_impl(
446 &self,
447 name: &str,
448 typ: &Type,
449 args: &[Pointer],
450 ) -> Result<Pointer, EngineError> {
451 let imp = self.resolve_native_impl(name, typ)?;
452 imp.func.call(self.runtime, typ.clone(), args).await
453 }
454}
455
456impl<'a, State> Deref for EvaluatorRef<'a, State>
457where
458 State: Clone + Send + Sync + 'static,
459{
460 type Target = RuntimeSnapshot<State>;
461
462 fn deref(&self) -> &Self::Target {
463 self.runtime
464 }
465}