1use super::{Caches, GlobalRuntimeState};
4use crate::ast::FnCallHashes;
5use crate::tokenizer::{is_valid_function_name, Token};
6use crate::types::dynamic::Variant;
7use crate::{
8 calc_fn_hash, expose_under_internals, Dynamic, Engine, FnArgsVec, FuncArgs, ImmutableString,
9 Position, RhaiResult, RhaiResultOf, Scope, StaticVec, ERR,
10};
11#[cfg(feature = "no_std")]
12use std::prelude::v1::*;
13use std::{
14 any::type_name,
15 mem,
16 ops::{Deref, DerefMut},
17};
18
19#[allow(dead_code)]
21pub struct EvalContext<'a, 's, 'ps, 'g, 'c, 't> {
22 engine: &'a Engine,
24 global: &'g mut GlobalRuntimeState,
26 caches: &'c mut Caches,
28 scope: &'s mut Scope<'ps>,
30 this_ptr: Option<&'t mut Dynamic>,
32}
33
34impl<'a, 's, 'ps, 'g, 'c, 't> EvalContext<'a, 's, 'ps, 'g, 'c, 't> {
35 #[expose_under_internals]
37 #[inline(always)]
38 #[must_use]
39 fn new(
40 engine: &'a Engine,
41 global: &'g mut GlobalRuntimeState,
42 caches: &'c mut Caches,
43 scope: &'s mut Scope<'ps>,
44 this_ptr: Option<&'t mut Dynamic>,
45 ) -> Self {
46 Self {
47 engine,
48 global,
49 caches,
50 scope,
51 this_ptr,
52 }
53 }
54 #[inline(always)]
56 #[must_use]
57 pub const fn engine(&self) -> &'a Engine {
58 self.engine
59 }
60 #[inline(always)]
62 #[must_use]
63 pub fn source(&self) -> Option<&str> {
64 self.global.source()
65 }
66 #[inline(always)]
68 #[must_use]
69 pub fn source_mut(&mut self) -> &mut Option<ImmutableString> {
70 &mut self.global.source
71 }
72
73 #[inline(always)]
75 #[must_use]
76 pub const fn scope(&self) -> &Scope<'ps> {
77 self.scope
78 }
79 #[inline(always)]
81 #[must_use]
82 pub fn scope_mut(&mut self) -> &mut Scope<'ps> {
83 self.scope
84 }
85 #[cfg(not(feature = "no_module"))]
88 #[inline(always)]
89 pub fn iter_imports(&self) -> impl Iterator<Item = (&str, &crate::Module)> {
90 self.global.iter_imports()
91 }
92 #[inline(always)]
94 pub const fn tag(&self) -> &Dynamic {
95 &self.global.tag
96 }
97 #[inline(always)]
99 pub fn tag_mut(&mut self) -> &mut Dynamic {
100 &mut self.global.tag
101 }
102 #[cfg(feature = "internals")]
105 #[inline(always)]
106 #[must_use]
107 pub const fn global_runtime_state(&self) -> &GlobalRuntimeState {
108 self.global
109 }
110 #[cfg(feature = "internals")]
113 #[inline(always)]
114 #[must_use]
115 pub fn global_runtime_state_mut(&mut self) -> &mut GlobalRuntimeState {
116 self.global
117 }
118 #[cfg(not(feature = "no_function"))]
122 #[inline]
123 pub fn iter_namespaces(&self) -> impl Iterator<Item = &crate::Module> {
124 self.global.lib.iter().map(<_>::as_ref)
125 }
126 #[cfg(not(feature = "no_function"))]
131 #[cfg(feature = "internals")]
132 #[inline(always)]
133 #[must_use]
134 pub fn namespaces(&self) -> &[crate::SharedModule] {
135 &self.global.lib
136 }
137 #[cfg(not(feature = "no_function"))]
142 #[cfg(feature = "internals")]
143 #[inline(always)]
144 #[must_use]
145 pub fn namespaces_mut(&mut self) -> &mut [crate::SharedModule] {
146 self.global.lib.as_mut()
147 }
148 #[inline(always)]
150 #[must_use]
151 pub fn this_ptr(&self) -> Option<&Dynamic> {
152 self.this_ptr.as_deref()
153 }
154 #[inline(always)]
156 #[must_use]
157 pub fn this_ptr_mut(&mut self) -> Option<&mut Dynamic> {
158 self.this_ptr.as_deref_mut()
159 }
160 #[inline(always)]
162 #[must_use]
163 pub const fn call_level(&self) -> usize {
164 self.global.level
165 }
166 #[cfg(feature = "debugging")]
169 #[cfg(feature = "internals")]
170 #[inline(always)]
171 #[must_use]
172 pub fn debugger(&self) -> Option<&crate::debugger::Debugger> {
173 self.global.debugger.as_deref()
174 }
175 #[cfg(feature = "debugging")]
178 #[cfg(feature = "internals")]
179 #[inline(always)]
180 #[must_use]
181 pub fn debugger_mut(&mut self) -> Option<&mut crate::debugger::Debugger> {
182 self.global.debugger.as_deref_mut()
183 }
184
185 #[cfg(not(feature = "no_custom_syntax"))]
191 #[inline(always)]
192 pub fn eval_expression_tree(&mut self, expr: &crate::Expression) -> crate::RhaiResult {
193 #[allow(deprecated)]
194 self.eval_expression_tree_raw(expr, true)
195 }
196 #[cfg(not(feature = "no_custom_syntax"))]
210 #[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."]
211 #[inline]
212 pub fn eval_expression_tree_raw(
213 &mut self,
214 expr: &crate::Expression,
215 rewind_scope: bool,
216 ) -> crate::RhaiResult {
217 let expr: &crate::ast::Expr = expr;
218 let this_ptr = self.this_ptr.as_deref_mut();
219
220 match expr {
221 crate::ast::Expr::Stmt(stmts) => self.engine.eval_stmt_block(
222 self.global,
223 self.caches,
224 self.scope,
225 this_ptr,
226 stmts.statements(),
227 rewind_scope,
228 ),
229 _ => self
230 .engine
231 .eval_expr(self.global, self.caches, self.scope, this_ptr, expr),
232 }
233 }
234
235 pub fn call_fn<T: Variant + Clone>(
237 &mut self,
238 fn_name: impl AsRef<str>,
239 args: impl FuncArgs,
240 ) -> RhaiResultOf<T> {
241 let engine = self.engine();
242
243 let mut arg_values = StaticVec::new_const();
244 args.parse(&mut arg_values);
245
246 let args = &mut arg_values.iter_mut().collect::<FnArgsVec<_>>();
247
248 let is_ref_mut = if let Some(this_ptr) = self.this_ptr.as_deref_mut() {
249 args.insert(0, this_ptr);
250 true
251 } else {
252 false
253 };
254
255 _call_fn_raw(
256 engine,
257 self.global,
258 self.caches,
259 self.scope,
260 fn_name,
261 args,
262 false,
263 is_ref_mut,
264 false,
265 )
266 .and_then(|result| {
267 result.try_cast_result().map_err(|r| {
268 let result_type = engine.map_type_name(r.type_name());
269 let cast_type = match type_name::<T>() {
270 typ if typ.contains("::") => engine.map_type_name(typ),
271 typ => typ,
272 };
273 ERR::ErrorMismatchOutputType(cast_type.into(), result_type.into(), Position::NONE)
274 .into()
275 })
276 })
277 }
278 pub fn call_native_fn<T: Variant + Clone>(
285 &mut self,
286 fn_name: impl AsRef<str>,
287 args: impl FuncArgs,
288 ) -> RhaiResultOf<T> {
289 let engine = self.engine();
290
291 let mut arg_values = StaticVec::new_const();
292 args.parse(&mut arg_values);
293
294 let args = &mut arg_values.iter_mut().collect::<FnArgsVec<_>>();
295
296 let is_ref_mut = self.this_ptr.as_deref_mut().map_or(false, |this_ptr| {
297 args.insert(0, this_ptr);
298 true
299 });
300
301 _call_fn_raw(
302 engine,
303 self.global,
304 self.caches,
305 self.scope,
306 fn_name,
307 args,
308 true,
309 is_ref_mut,
310 false,
311 )
312 .and_then(|result| {
313 result.try_cast_result().map_err(|r| {
314 let result_type = engine.map_type_name(r.type_name());
315 let cast_type = match type_name::<T>() {
316 typ if typ.contains("::") => engine.map_type_name(typ),
317 typ => typ,
318 };
319 ERR::ErrorMismatchOutputType(cast_type.into(), result_type.into(), Position::NONE)
320 .into()
321 })
322 })
323 }
324 #[inline(always)]
344 pub fn call_fn_raw(
345 &mut self,
346 fn_name: impl AsRef<str>,
347 is_ref_mut: bool,
348 is_method_call: bool,
349 args: &mut [&mut Dynamic],
350 ) -> RhaiResult {
351 let name = fn_name.as_ref();
352 let native_only = !is_valid_function_name(name);
353 #[cfg(not(feature = "no_function"))]
354 let native_only = native_only && !crate::parser::is_anonymous_fn(name);
355
356 _call_fn_raw(
357 self.engine(),
358 self.global,
359 self.caches,
360 self.scope,
361 fn_name,
362 args,
363 native_only,
364 is_ref_mut,
365 is_method_call,
366 )
367 }
368 #[inline(always)]
389 pub fn call_native_fn_raw(
390 &mut self,
391 fn_name: impl AsRef<str>,
392 is_ref_mut: bool,
393 args: &mut [&mut Dynamic],
394 ) -> RhaiResult {
395 _call_fn_raw(
396 self.engine(),
397 self.global,
398 self.caches,
399 self.scope,
400 fn_name,
401 args,
402 true,
403 is_ref_mut,
404 false,
405 )
406 }
407
408 pub fn new_frame<'f>(&'f mut self) -> EvalContextFrameGuard<'f, 'a, 's, 'ps, 'g, 'c, 't> {
453 EvalContextFrameGuard {
454 #[cfg(feature = "internals")]
455 #[cfg(not(feature = "no_module"))]
456 imports_len: None,
457 #[cfg(feature = "internals")]
458 #[cfg(not(feature = "no_function"))]
459 lib_len: None,
460 caches_len: None,
461 scope_len: None,
462 source: None,
463 #[cfg(feature = "internals")]
464 level: None,
465 tag: None,
466
467 context: self,
468 }
469 }
470}
471
472fn _call_fn_raw(
474 engine: &Engine,
475 global: &mut GlobalRuntimeState,
476 caches: &mut Caches,
477 scope: &mut Scope,
478 fn_name: impl AsRef<str>,
479 args: &mut [&mut Dynamic],
480 native_only: bool,
481 is_ref_mut: bool,
482 is_method_call: bool,
483) -> RhaiResult {
484 defer! { let orig_level = global.level; global.level += 1 }
485
486 let fn_name = fn_name.as_ref();
487 let op_token = Token::lookup_symbol_from_syntax(fn_name);
488 let op_token = op_token.as_ref();
489 let args_len = args.len();
490
491 if native_only {
492 let hash = calc_fn_hash(None, fn_name, args_len);
493
494 return engine
495 .exec_native_fn_call(
496 global,
497 caches,
498 fn_name,
499 op_token,
500 hash,
501 args,
502 is_ref_mut,
503 false,
504 Position::NONE,
505 )
506 .map(|(r, ..)| r);
507 }
508
509 let hash = match is_method_call {
512 #[cfg(not(feature = "no_function"))]
513 true => FnCallHashes::from_script_and_native(
514 calc_fn_hash(None, fn_name, args_len - 1),
515 calc_fn_hash(None, fn_name, args_len),
516 ),
517 #[cfg(feature = "no_function")]
518 true => FnCallHashes::from_native_only(calc_fn_hash(None, fn_name, args_len)),
519 _ => FnCallHashes::from_hash(calc_fn_hash(None, fn_name, args_len)),
520 };
521
522 engine
523 .exec_fn_call(
524 global,
525 caches,
526 Some(scope),
527 fn_name,
528 op_token,
529 hash,
530 args,
531 is_ref_mut,
532 is_method_call,
533 Position::NONE,
534 )
535 .map(|(r, ..)| r)
536}
537
538pub struct EvalContextFrameGuard<'f, 'a, 's, 'ps, 'g, 'c, 't> {
540 context: &'f mut EvalContext<'a, 's, 'ps, 'g, 'c, 't>,
541
542 caches_len: Option<usize>,
543 scope_len: Option<usize>,
544 #[cfg(feature = "internals")]
545 #[cfg(not(feature = "no_module"))]
546 imports_len: Option<usize>,
547 #[cfg(feature = "internals")]
548 #[cfg(not(feature = "no_function"))]
549 lib_len: Option<usize>,
550 source: Option<Option<ImmutableString>>,
551 #[cfg(feature = "internals")]
552 level: Option<usize>,
553 tag: Option<Dynamic>,
554}
555
556impl Drop for EvalContextFrameGuard<'_, '_, '_, '_, '_, '_, '_> {
557 #[inline(always)]
558 fn drop(&mut self) {
559 if let Some(caches_len) = self.caches_len {
560 self.context.caches.rewind_fn_resolution_caches(caches_len);
561 }
562 if let Some(scope_len) = self.scope_len {
563 self.context.scope.rewind(scope_len);
564 }
565 #[cfg(feature = "internals")]
566 #[cfg(not(feature = "no_module"))]
567 if let Some(imports_len) = self.imports_len {
568 self.context.global.truncate_imports(imports_len);
569 }
570 #[cfg(feature = "internals")]
571 #[cfg(not(feature = "no_function"))]
572 if let Some(lib_len) = self.lib_len {
573 self.context.global.lib.truncate(lib_len);
574 }
575 if let Some(source) = self.source.take() {
576 *self.context.source_mut() = source;
577 }
578 #[cfg(feature = "internals")]
579 if let Some(level) = self.level {
580 self.context.global.level = level;
581 }
582 if let Some(tag) = self.tag.take() {
583 *self.context.tag_mut() = tag;
584 }
585 }
586}
587
588impl<'a, 's, 'ps, 'g, 'c, 't> Deref for EvalContextFrameGuard<'_, 'a, 's, 'ps, 'g, 'c, 't> {
589 type Target = EvalContext<'a, 's, 'ps, 'g, 'c, 't>;
590
591 #[inline(always)]
592 fn deref(&self) -> &Self::Target {
593 self.context
594 }
595}
596
597impl<'a, 's, 'ps, 'g, 'c, 't> DerefMut for EvalContextFrameGuard<'_, 'a, 's, 'ps, 'g, 'c, 't> {
598 #[inline(always)]
599 fn deref_mut(&mut self) -> &mut Self::Target {
600 self.context
601 }
602}
603
604impl<'t> EvalContextFrameGuard<'_, '_, '_, '_, '_, '_, 't> {
605 pub fn with_new_caching_layer(mut self) -> Self {
607 self.caches_len = Some(self.context.caches.fn_resolution_caches_len());
608 self.context.caches.push_fn_resolution_cache();
609 self
610 }
611 #[inline(always)]
613 pub fn rewind_scope(mut self, enable: bool) -> Self {
614 self.scope_len = if enable {
615 Some(self.context.scope().len())
616 } else {
617 None
618 };
619 self
620 }
621 #[inline(always)]
623 pub fn with_source(mut self, source: impl Into<ImmutableString>) -> Self {
624 self.source = Some(Some(source.into()));
625 mem::swap(self.context.source_mut(), self.source.as_mut().unwrap());
626 self
627 }
628 #[inline(always)]
630 pub fn clear_source(mut self) -> Self {
631 self.source = Some(None);
632 mem::swap(self.context.source_mut(), self.source.as_mut().unwrap());
633 self
634 }
635 #[inline(always)]
637 pub fn with_tag(mut self, tag: Dynamic) -> Self {
638 self.tag = Some(tag);
639 mem::swap(self.context.tag_mut(), self.tag.as_mut().unwrap());
640 self
641 }
642 #[inline(always)]
644 pub fn clear_tag(mut self) -> Self {
645 self.tag = Some(Dynamic::UNIT);
646 mem::swap(self.context.tag_mut(), self.tag.as_mut().unwrap());
647 self
648 }
649 #[cfg(feature = "internals")]
654 #[cfg(not(feature = "no_module"))]
655 pub fn with_import(
656 mut self,
657 name: impl Into<ImmutableString>,
658 module: impl Into<crate::SharedModule>,
659 ) -> Self {
660 self.imports_len = Some(self.context.global.num_imports());
661 self.context.global.push_import(name.into(), module.into());
662 self
663 }
664 #[cfg(feature = "internals")]
669 #[cfg(not(feature = "no_function"))]
670 #[inline(always)]
671 #[must_use]
672 pub fn with_namespace(mut self, module: impl Into<crate::SharedModule>) -> Self {
673 self.lib_len = Some(self.context.global.lib.len());
674 self.context.global.lib.push(module.into());
675 self
676 }
677 #[cfg(feature = "internals")]
680 #[inline(always)]
681 pub fn up_call_level(mut self) -> Self {
682 self.level = Some(self.context.global.level);
683 self.context.global.level += 1;
684 self
685 }
686}