Skip to main content

quickjs_oxide/engine/api/core/
context.rs

1//! The realm's handle and the types of its operations (`ops` defines the
2//! operations themselves).
3
4use super::RuntimeError;
5#[cfg(feature = "test262-host")]
6use super::property::PropertyKey;
7use super::runtime::Runtime;
8use super::value::ObjectRef;
9use super::value::Value;
10
11/// Options of `Context::eval_with_options`.
12#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct EvalOptions {
14    pub filename: String,
15    /// The code is freed once nothing names it (a REPL's line), instead of
16    /// living as long as the runtime.
17    pub transient: bool,
18}
19
20impl EvalOptions {
21    pub fn new(filename: impl Into<String>) -> Self {
22        EvalOptions {
23            filename: filename.into(),
24            transient: false,
25        }
26    }
27
28    /// These options with [`EvalOptions::transient`] set.
29    #[must_use]
30    pub fn transient(mut self) -> Self {
31        self.transient = true;
32        self
33    }
34}
35
36impl Default for EvalOptions {
37    fn default() -> Self {
38        Self::new(crate::engine::compiler::DEFAULT_EVAL_FILENAME)
39    }
40}
41
42/// A compiled script, run by `Context::execute`.
43#[derive(Clone, Debug, PartialEq)]
44pub struct FunctionBytecodeRef {
45    function: ObjectRef,
46    /// The front end's stack code, which the front end's tests inspect.
47    #[cfg(test)]
48    pub(crate) stack: StackCode,
49}
50
51/// A function of a compiled script's stack code: the script's unlinked tree
52/// and the child-constant path from its root.
53#[cfg(test)]
54#[derive(Clone)]
55pub(crate) struct StackCode {
56    pub(crate) root: std::rc::Rc<crate::engine::code::function::UnlinkedFunction>,
57    pub(crate) path: Vec<usize>,
58}
59
60#[cfg(test)]
61impl StackCode {
62    pub(crate) fn function(&self) -> &crate::engine::code::function::UnlinkedFunction {
63        self.path.iter().fold(&self.root, |function, index| {
64            function.constants()[*index]
65                .as_child()
66                .expect("a child-function constant")
67        })
68    }
69}
70
71#[cfg(test)]
72impl std::fmt::Debug for StackCode {
73    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74        f.debug_struct("StackCode")
75            .field("path", &self.path)
76            .finish()
77    }
78}
79
80#[cfg(test)]
81impl PartialEq for StackCode {
82    fn eq(&self, other: &Self) -> bool {
83        std::rc::Rc::ptr_eq(&self.root, &other.root) && self.path == other.path
84    }
85}
86
87/// A compiled module, run by `Context::execute_module`.
88#[derive(Clone, Debug, PartialEq, Eq)]
89pub struct ModuleBytecodeRef {
90    name: String,
91}
92
93impl ModuleBytecodeRef {
94    /// The module's name (its filename).
95    pub fn name(&self) -> &str {
96        &self.name
97    }
98}
99
100/// qjs's helpers (`Context::install_qjs_helpers`).
101#[derive(Clone, Debug, Default, PartialEq, Eq)]
102pub struct QjsHelpers {
103    /// `load` and `read` (`qjs --std`).
104    pub std: bool,
105    /// `scriptArgs`, when set.
106    pub script_args: Option<Vec<String>>,
107}
108
109/// The runtime's one realm.
110#[derive(Clone)]
111pub struct Context {
112    pub(crate) runtime: Runtime,
113}
114
115impl FunctionBytecodeRef {
116    pub(crate) fn new(
117        function: ObjectRef,
118        #[cfg(test)] source: &[u8],
119        #[cfg(test)] filename: &str,
120        #[cfg(test)] debug_info: crate::engine::code::debug::DebugInfoMode,
121    ) -> Self {
122        FunctionBytecodeRef {
123            function,
124            #[cfg(test)]
125            stack: StackCode {
126                root: std::rc::Rc::new(
127                    crate::engine::compiler::compile_unlinked_script_bytes_with_filename(
128                        source, filename, debug_info,
129                    )
130                    .expect("the script compiled once"),
131                ),
132                path: Vec::new(),
133            },
134        }
135    }
136
137    pub(crate) fn function(&self) -> &ObjectRef {
138        &self.function
139    }
140}
141
142impl ModuleBytecodeRef {
143    pub(crate) fn new(name: &str) -> Self {
144        ModuleBytecodeRef {
145            name: name.to_owned(),
146        }
147    }
148}
149
150/// The handle of the runtime's one realm. Its operations are listed with
151/// the [`Js`](super::Js) trait, which a host function's
152/// [`Scope`](super::Scope) shares; each is an inherent method and one
153/// engine entry.
154impl Context {
155    /// The runtime's realm (a second call returns the same one).
156    pub fn new(runtime: &Runtime) -> Self {
157        runtime.context()
158    }
159
160    pub fn try_clone(&self) -> Result<Self, RuntimeError> {
161        Ok(self.clone())
162    }
163
164    pub fn runtime(&self) -> &Runtime {
165        &self.runtime
166    }
167
168    /// Makes `exports` the module `name`: an `import` of the name sees each
169    /// value under its name (`default` is the default export), as the
170    /// module a [`ModuleLoader`](super::ModuleLoader) returns as
171    /// `ModuleSource::Synthetic`. A second definition of the name replaces
172    /// the first for later imports.
173    pub fn define_module(
174        &self,
175        name: &str,
176        exports: Vec<(String, Value)>,
177    ) -> Result<(), RuntimeError> {
178        let mut entry = self.runtime.enter()?;
179        {
180            let view = entry.view();
181            for (_, value) in &exports {
182                if let Value::Object(ObjectRef { slot })
183                | Value::Symbol(super::value::SymbolRef { slot }) = value
184                {
185                    view.own(slot)?;
186                }
187            }
188        }
189        entry.inner.core.forget_module(name);
190        self.runtime.shared.modules.borrow_mut().insert(
191            name.to_owned(),
192            super::runtime::Preloaded::Synthetic(exports),
193        );
194        Ok(())
195    }
196
197    /// Defines the Test262 host object `$262`; returns it.
198    #[cfg(feature = "test262-host")]
199    pub fn install_test262_host(&mut self) -> Result<ObjectRef, RuntimeError> {
200        {
201            let mut entry = self.runtime.enter()?;
202            entry.inner.core.install_test262_host()?;
203        }
204        let global = self.global_object()?;
205        let key = PropertyKey::from_js_string(crate::engine::value::JsString::from_static("$262"));
206        match self.get_property(&global, &key)? {
207            Value::Object(host) => Ok(host),
208            _ => Err(RuntimeError::Invariant("$262 is an object")),
209        }
210    }
211}