Skip to main content

rexlang_engine/
evaluator.rs

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(&param_type) {
261            return Err(EngineError::AmbiguousOverload { name: name.clone() });
262        }
263
264        self.runtime
265            .typeclasses
266            .resolve(&info.class, name, &param_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}