1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//! Module that defines the public evaluation API of [`Engine`].

use crate::eval::{Caches, GlobalRuntimeState};
use crate::func::native::locked_write;
use crate::parser::ParseState;
use crate::types::StringsInterner;
use crate::{Engine, RhaiResultOf, Scope, AST};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;

impl Engine {
    /// Evaluate a string as a script.
    ///
    /// # Example
    ///
    /// ```
    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
    /// use rhai::Engine;
    ///
    /// let engine = Engine::new();
    ///
    /// engine.run("print(40 + 2);")?;
    /// # Ok(())
    /// # }
    /// ```
    #[inline(always)]
    pub fn run(&self, script: &str) -> RhaiResultOf<()> {
        self.run_with_scope(&mut Scope::new(), script)
    }
    /// Evaluate a string as a script with own scope.
    ///
    /// ## Constants Propagation
    ///
    /// If not [`OptimizationLevel::None`][crate::OptimizationLevel::None], constants defined within
    /// the scope are propagated throughout the script _including_ functions.
    ///
    /// This allows functions to be optimized based on dynamic global constants.
    ///
    /// # Example
    ///
    /// ```
    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
    /// use rhai::{Engine, Scope};
    ///
    /// let engine = Engine::new();
    ///
    /// // Create initialized scope
    /// let mut scope = Scope::new();
    /// scope.push("x", 40_i64);
    ///
    /// engine.run_with_scope(&mut scope, "x += 2; print(x);")?;
    ///
    /// // The variable in the scope is modified
    /// assert_eq!(scope.get_value::<i64>("x").expect("variable x should exist"), 42);
    /// # Ok(())
    /// # }
    /// ```
    #[inline]
    pub fn run_with_scope(&self, scope: &mut Scope, script: &str) -> RhaiResultOf<()> {
        let scripts = [script];
        let ast = {
            let (stream, tc) = self.lex_raw(&scripts, self.token_mapper.as_deref());

            let mut interner;
            let mut guard;
            let interned_strings = if let Some(ref interner) = self.interned_strings {
                guard = locked_write(interner);
                &mut *guard
            } else {
                interner = StringsInterner::new();
                &mut interner
            };

            let state = &mut ParseState::new(Some(scope), interned_strings, tc);
            self.parse(stream.peekable(), state, self.optimization_level)?
        };
        self.run_ast_with_scope(scope, &ast)
    }
    /// Evaluate an [`AST`].
    ///
    /// # Example
    ///
    /// ```
    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
    /// use rhai::Engine;
    ///
    /// let engine = Engine::new();
    ///
    /// // Compile a script to an AST and store it for later evaluation
    /// let ast = engine.compile("print(40 + 2);")?;
    ///
    /// // Evaluate it
    /// engine.run_ast(&ast)?;
    /// # Ok(())
    /// # }
    /// ```
    #[inline(always)]
    pub fn run_ast(&self, ast: &AST) -> RhaiResultOf<()> {
        self.run_ast_with_scope(&mut Scope::new(), ast)
    }
    /// Evaluate an [`AST`] with own scope.
    ///
    /// # Example
    ///
    /// ```
    /// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
    /// use rhai::{Engine, Scope};
    ///
    /// let engine = Engine::new();
    ///
    /// // Create initialized scope
    /// let mut scope = Scope::new();
    /// scope.push("x", 40_i64);
    ///
    /// // Compile a script to an AST and store it for later evaluation
    /// let ast = engine.compile("x += 2; x")?;
    ///
    /// // Evaluate it
    /// engine.run_ast_with_scope(&mut scope, &ast)?;
    ///
    /// // The variable in the scope is modified
    /// assert_eq!(scope.get_value::<i64>("x").expect("variable x should exist"), 42);
    /// # Ok(())
    /// # }
    /// ```
    #[inline]
    pub fn run_ast_with_scope(&self, scope: &mut Scope, ast: &AST) -> RhaiResultOf<()> {
        let caches = &mut Caches::new();
        let global = &mut GlobalRuntimeState::new(self);
        global.source = ast.source_raw().cloned();

        #[cfg(not(feature = "no_function"))]
        global.lib.push(ast.shared_lib().clone());

        #[cfg(not(feature = "no_module"))]
        {
            global.embedded_module_resolver = ast.resolver().cloned();
        }

        let _ = self.eval_global_statements(global, caches, scope, ast.statements())?;

        #[cfg(feature = "debugging")]
        if self.is_debugger_registered() {
            global.debugger_mut().status = crate::eval::DebuggerStatus::Terminate;
            let node = &crate::ast::Stmt::Noop(crate::Position::NONE);
            self.run_debugger(global, caches, scope, None, node)?;
        }

        Ok(())
    }
}

/// Evaluate a string as a script.
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
/// rhai::run("print(40 + 2);")?;
/// # Ok(())
/// # }
/// ```
#[inline(always)]
pub fn run(script: &str) -> RhaiResultOf<()> {
    Engine::new().run(script)
}