Skip to main content

quickjs_oxide/engine/api/core/
ops.rs

1//! The operations `Context` and a host function's `Scope` share, written
2//! once on [`View`] and listed once in [`js_ops!`], which makes each an
3//! inherent method of both handles and a method of the [`Js`] trait.
4
5use std::any::Any;
6use std::rc::Rc;
7
8use oxide_core::heap::string::StringRepr;
9use oxide_core::{Intrinsic, NativeCx, RootMark};
10
11use super::RuntimeError;
12use super::buffer::{TypedArrayKind, TypedArrayView};
13use super::compile::{ScriptCompileError, compile_script, syntax_location};
14use super::context::{Context, EvalOptions, FunctionBytecodeRef, ModuleBytecodeRef, QjsHelpers};
15use super::function::{FunctionOptions, HostFunction, Raw, Scope, host_body};
16use super::promise::PromiseCapability;
17use super::property::{
18    AccessorValue, CompleteOrdinaryPropertyDescriptor, DescriptorField, Key,
19    OrdinaryPropertyDescriptor, PropertyKey, WellKnownSymbol,
20};
21use super::runtime::{Preloaded, PromiseSnapshot, PromiseState, Shared, slot};
22use super::value::{CallableRef, ObjectRef, Slot, SymbolRef, Value};
23use crate::engine::api::error::{Error, NativeErrorKind};
24use crate::engine::compiler::CompileOptions;
25use crate::engine::value::JsString;
26use crate::engine::value::bigint::JsBigInt;
27
28/// What every operation returns.
29pub type JsResult<T> = Result<T, RuntimeError>;
30
31/// The engine borrowed for operations: the core's view, the runtime it
32/// belongs to, and the root-stack mark its temporaries are cut back to when
33/// it drops.
34pub(crate) struct View<'a> {
35    pub(crate) core: NativeCx<'a>,
36    pub(crate) shared: &'a Rc<Shared>,
37    mark: RootMark,
38}
39
40impl Drop for View<'_> {
41    fn drop(&mut self) {
42        self.core.heap_mut().roots().truncate(self.mark);
43    }
44}
45
46impl<'a> View<'a> {
47    pub(crate) fn new(mut core: NativeCx<'a>, shared: &'a Rc<Shared>) -> Self {
48        let mark = core.heap_mut().roots().mark();
49        View { core, shared, mark }
50    }
51}
52
53impl View<'_> {
54    // ---- values ----
55
56    /// Copies a core value out: primitives as data, objects and symbols as
57    /// new handles. `value` must still be live (just returned or rooted).
58    pub(crate) fn lift(&mut self, value: oxide_core::Value) -> JsResult<Value> {
59        use oxide_core::value::Kind;
60        Ok(match value.kind() {
61            Kind::Undefined => Value::Undefined,
62            Kind::Null => Value::Null,
63            Kind::Bool => Value::Bool(value.as_bool().unwrap_or(false)),
64            Kind::Int32 => Value::Int(value.as_int32().unwrap_or(0)),
65            Kind::Number => Value::Float(value.as_f64().unwrap_or(f64::NAN)),
66            Kind::String => Value::String(match self.core.string_repr(value) {
67                Some(StringRepr::OneByte(units)) => JsString::try_from_latin1(units)?,
68                Some(StringRepr::TwoByte(units)) => JsString::try_from_utf16_slice(units)?,
69                None => JsString::from_static(""),
70            }),
71            Kind::BigInt => {
72                let decimal = self.core.bigint_decimal(value).unwrap_or_default();
73                Value::BigInt(
74                    JsBigInt::from_decimal_unchecked(&decimal)
75                        .ok_or(RuntimeError::Invariant("a BigInt's decimal text"))?,
76                )
77            }
78            Kind::Symbol => Value::Symbol(SymbolRef {
79                slot: slot(self.shared, self.core.hold(value), value),
80            }),
81            Kind::Object => Value::Object(ObjectRef {
82                slot: slot(self.shared, self.core.hold(value), value),
83            }),
84            _ => Value::Undefined,
85        })
86    }
87
88    pub(crate) fn lift_object(&mut self, object: oxide_core::ObjectId) -> ObjectRef {
89        let value = oxide_core::Value::object(object);
90        ObjectRef {
91            slot: slot(self.shared, self.core.hold(value), value),
92        }
93    }
94
95    /// The core value of `value`, rooted until the view drops.
96    pub(crate) fn lower(&mut self, value: &Value) -> JsResult<oxide_core::Value> {
97        let lowered = match value {
98            Value::Undefined => oxide_core::Value::UNDEFINED,
99            Value::Null => oxide_core::Value::NULL,
100            Value::Bool(value) => oxide_core::Value::bool(*value),
101            Value::Int(value) => oxide_core::Value::int32(*value),
102            Value::Float(value) => oxide_core::Value::number(*value),
103            Value::String(text) => {
104                let value = match (text.flat_latin1(), text.flat_utf16()) {
105                    (Some(units), _) => {
106                        self.core.new_string_repr(StringRepr::OneByte(units.into()))
107                    }
108                    (_, Some(units)) => self.core.new_string_units(units),
109                    _ => self
110                        .core
111                        .new_string_units(&text.utf16_units().collect::<Vec<_>>()),
112                }?;
113                self.temp(value);
114                value
115            }
116            Value::BigInt(big) => {
117                let decimal = big
118                    .to_string_radix(10)
119                    .map_err(|error| RuntimeError::Internal(format!("{error:?}")))?;
120                let value = self
121                    .core
122                    .new_bigint(&decimal)
123                    .ok_or(RuntimeError::Invariant("a BigInt's decimal text"))??;
124                self.temp(value);
125                value
126            }
127            Value::Symbol(symbol) => self.own(symbol.slot.as_ref())?,
128            Value::Object(object) => self.own(object.slot.as_ref())?,
129        };
130        Ok(lowered)
131    }
132
133    pub(crate) fn lower_all(&mut self, values: &[Value]) -> JsResult<Vec<oxide_core::Value>> {
134        values.iter().map(|value| self.lower(value)).collect()
135    }
136
137    /// The value a handle of this runtime holds.
138    pub(crate) fn own(&self, slot: &Slot) -> JsResult<oxide_core::Value> {
139        if slot.of(self.shared) {
140            Ok(slot.value)
141        } else if slot.shared.strong_count() == 0 {
142            Err(RuntimeError::Invariant("a value of a dropped runtime"))
143        } else {
144            Err(RuntimeError::Invariant("a value of another runtime"))
145        }
146    }
147
148    pub(crate) fn object(&self, object: &ObjectRef) -> JsResult<oxide_core::ObjectId> {
149        self.own(&object.slot)?
150            .as_object()
151            .ok_or(RuntimeError::Invariant("an object reference"))
152    }
153
154    fn function(&mut self, callable: &CallableRef) -> JsResult<oxide_core::Value> {
155        Ok(oxide_core::Value::object(
156            self.object(callable.as_object())?,
157        ))
158    }
159
160    fn temp(&mut self, value: oxide_core::Value) {
161        self.core.heap_mut().roots().push(value);
162    }
163
164    /// The core key of `key`, rooted until the view drops.
165    pub(crate) fn key(&mut self, key: &PropertyKey) -> JsResult<oxide_core::PropertyKey> {
166        let key = match &key.0 {
167            Key::Index(index) => oxide_core::PropertyKey::index(*index).map_or_else(
168                || {
169                    let units: Vec<u16> = index.to_string().encode_utf16().collect();
170                    self.core.key_from_units(&units)
171                },
172                Ok,
173            )?,
174            Key::String(text) => {
175                let units: Vec<u16> = text.utf16_units().collect();
176                self.core.key_from_units(&units)?
177            }
178            // The symbol's handle roots it.
179            Key::Symbol(symbol) => {
180                let value = self.own(&symbol.slot)?;
181                return self
182                    .core
183                    .key_from_symbol(value)
184                    .ok_or(RuntimeError::Invariant("a symbol reference"));
185            }
186        };
187        // An atom lives only while something names it.
188        if let Some(value) = key.heap_value() {
189            self.temp(value);
190        }
191        Ok(key)
192    }
193
194    /// The API key of a core key.
195    pub(crate) fn lift_key(&mut self, key: oxide_core::PropertyKey) -> JsResult<PropertyKey> {
196        Ok(match self.core.key_name(key) {
197            oxide_core::KeyName::Index(index) => PropertyKey(Key::Index(index)),
198            oxide_core::KeyName::String(units) => {
199                PropertyKey(Key::String(JsString::try_from_utf16(units)?))
200            }
201            oxide_core::KeyName::Symbol(symbol) => match self.lift(symbol)? {
202                Value::Symbol(symbol) => PropertyKey(Key::Symbol(symbol)),
203                _ => return Err(RuntimeError::Invariant("a symbol key")),
204            },
205        })
206    }
207
208    /// The error a throw returns: the thrown value, lifted. An interrupt is
209    /// `Interrupted`, and the outermost entry ends its unwinding.
210    pub(crate) fn thrown(&mut self, thrown: oxide_core::Throw) -> RuntimeError {
211        if self.core.is_interrupted() {
212            if self.core.owns_code() {
213                self.core.clear_interrupted();
214            }
215            return RuntimeError::Interrupted;
216        }
217        let out_of_memory = self.core.intrinsic(Intrinsic::OutOfMemoryError);
218        if thrown.0.as_object() == Some(out_of_memory) {
219            return RuntimeError::OutOfMemory;
220        }
221        match self.lift(thrown.0) {
222            Ok(value) => RuntimeError::Exception(value),
223            Err(error) => error,
224        }
225    }
226
227    /// Converts a core result, lifting a throw.
228    pub(crate) fn complete(
229        &mut self,
230        result: Result<oxide_core::Value, oxide_core::Throw>,
231    ) -> JsResult<Value> {
232        match result {
233            Ok(value) => self.lift(value),
234            Err(thrown) => Err(self.thrown(thrown)),
235        }
236    }
237
238    pub(crate) fn complete_with<T>(&mut self, result: Result<T, oxide_core::Throw>) -> JsResult<T> {
239        result.map_err(|thrown| self.thrown(thrown))
240    }
241
242    /// A descriptor in the core's form, its values rooted until the view
243    /// drops. Accessor fields that are not callable were rejected by the
244    /// type already.
245    fn lower_descriptor(
246        &mut self,
247        descriptor: &OrdinaryPropertyDescriptor,
248    ) -> JsResult<oxide_core::PropertyDescriptor> {
249        let accessor = |view: &mut Self, field: &DescriptorField<AccessorValue>| match field {
250            DescriptorField::Absent => Ok(None),
251            DescriptorField::Present(AccessorValue::Undefined) => {
252                Ok(Some(oxide_core::Value::UNDEFINED))
253            }
254            DescriptorField::Present(AccessorValue::Callable(function)) => {
255                view.own(&function.0.slot).map(Some)
256            }
257        };
258        Ok(oxide_core::PropertyDescriptor {
259            value: match &descriptor.value {
260                DescriptorField::Absent => None,
261                DescriptorField::Present(value) => Some(self.lower(value)?),
262            },
263            get: accessor(self, &descriptor.get)?,
264            set: accessor(self, &descriptor.set)?,
265            writable: descriptor.writable.into_option(),
266            enumerable: descriptor.enumerable.into_option(),
267            configurable: descriptor.configurable.into_option(),
268        })
269    }
270
271    fn lift_descriptor(
272        &mut self,
273        descriptor: oxide_core::PropertyDescriptor,
274    ) -> JsResult<CompleteOrdinaryPropertyDescriptor> {
275        if descriptor.is_accessor() {
276            let callable = |view: &mut Self, value: Option<oxide_core::Value>| {
277                Ok::<_, RuntimeError>(match value {
278                    Some(value) if !value.is_undefined() => match view.lift(value)? {
279                        Value::Object(object) => Some(CallableRef(object)),
280                        _ => None,
281                    },
282                    _ => None,
283                })
284            };
285            Ok(CompleteOrdinaryPropertyDescriptor::Accessor {
286                get: callable(self, descriptor.get)?,
287                set: callable(self, descriptor.set)?,
288                enumerable: descriptor.enumerable.unwrap_or(false),
289                configurable: descriptor.configurable.unwrap_or(false),
290            })
291        } else {
292            let value = descriptor.value.unwrap_or(oxide_core::Value::UNDEFINED);
293            Ok(CompleteOrdinaryPropertyDescriptor::Data {
294                value: self.lift(value)?,
295                writable: descriptor.writable.unwrap_or(false),
296                enumerable: descriptor.enumerable.unwrap_or(false),
297                configurable: descriptor.configurable.unwrap_or(false),
298            })
299        }
300    }
301
302    /// The error for an operation a host function cannot run, because the
303    /// running loop borrows what it needs.
304    fn modules_supported(&mut self) -> JsResult<()> {
305        if self.core.owns_code() {
306            Ok(())
307        } else {
308            Err(RuntimeError::Unsupported("modules inside a host function"))
309        }
310    }
311
312    // ---- scripts ----
313
314    pub(crate) fn eval(&mut self, source: &str) -> JsResult<Value> {
315        self.eval_bytes(source.as_bytes())
316    }
317
318    pub(crate) fn eval_bytes(&mut self, source: &[u8]) -> JsResult<Value> {
319        self.eval_bytes_with_filename(source, crate::engine::compiler::DEFAULT_EVAL_FILENAME)
320    }
321
322    pub(crate) fn eval_with_filename(&mut self, source: &str, filename: &str) -> JsResult<Value> {
323        self.eval_bytes_with_filename(source.as_bytes(), filename)
324    }
325
326    pub(crate) fn eval_with_options(
327        &mut self,
328        source: &str,
329        options: &EvalOptions,
330    ) -> JsResult<Value> {
331        self.eval_bytes_with_options(source.as_bytes(), options)
332    }
333
334    pub(crate) fn eval_bytes_with_options(
335        &mut self,
336        source: &[u8],
337        options: &EvalOptions,
338    ) -> JsResult<Value> {
339        let script = self.compile_script_bytes(source, &options.filename, options.transient)?;
340        self.execute(&script)
341    }
342
343    pub(crate) fn eval_bytes_with_filename(
344        &mut self,
345        source: &[u8],
346        filename: &str,
347    ) -> JsResult<Value> {
348        let script = self.compile_bytes_with_filename(source, filename)?;
349        self.execute(&script)
350    }
351
352    pub(crate) fn compile(&mut self, source: &str) -> JsResult<FunctionBytecodeRef> {
353        self.compile_bytes(source.as_bytes())
354    }
355
356    pub(crate) fn compile_bytes(&mut self, source: &[u8]) -> JsResult<FunctionBytecodeRef> {
357        self.compile_bytes_with_filename(source, crate::engine::compiler::DEFAULT_EVAL_FILENAME)
358    }
359
360    pub(crate) fn compile_with_filename(
361        &mut self,
362        source: &str,
363        filename: &str,
364    ) -> JsResult<FunctionBytecodeRef> {
365        self.compile_bytes_with_filename(source.as_bytes(), filename)
366    }
367
368    pub(crate) fn compile_with_options(
369        &mut self,
370        source: &str,
371        options: &CompileOptions,
372    ) -> JsResult<FunctionBytecodeRef> {
373        self.compile_bytes_with_options(source.as_bytes(), options)
374    }
375
376    pub(crate) fn compile_bytes_with_options(
377        &mut self,
378        source: &[u8],
379        options: &CompileOptions,
380    ) -> JsResult<FunctionBytecodeRef> {
381        self.compile_script_bytes(source, &options.filename, options.transient)
382    }
383
384    pub(crate) fn compile_bytes_with_filename(
385        &mut self,
386        source: &[u8],
387        filename: &str,
388    ) -> JsResult<FunctionBytecodeRef> {
389        self.compile_script_bytes(source, filename, false)
390    }
391
392    /// Compiles `source` as a script named `filename`; `transient` code goes
393    /// in the heap, which frees it once no function names it. Inside a host
394    /// function all code is transient.
395    fn compile_script_bytes(
396        &mut self,
397        source: &[u8],
398        filename: &str,
399        transient: bool,
400    ) -> JsResult<FunctionBytecodeRef> {
401        let debug_info = self.shared.debug_info.get();
402        let lowered = {
403            let mut compiler = self.core.compiler(transient);
404            compile_script(&mut compiler, source, filename, debug_info)
405        };
406        match lowered {
407            Ok(lowered) => Ok(FunctionBytecodeRef::new(
408                self.lift_object(lowered.function),
409                #[cfg(test)]
410                source,
411                #[cfg(test)]
412                filename,
413                #[cfg(test)]
414                debug_info,
415            )),
416            Err(ScriptCompileError::Front(error)) => {
417                Err(self.throw_compile_error(&error, source, filename))
418            }
419            Err(ScriptCompileError::Lower(error)) => match error {
420                crate::engine::compiler::register::LowerError::Syntax(message) => {
421                    let error = Error::new(crate::engine::api::error::ErrorKind::Syntax, message);
422                    Err(self.throw_compile_error(&error, source, filename))
423                }
424                other => Err(RuntimeError::Internal(other.to_string())),
425            },
426        }
427    }
428
429    /// A front-end error thrown as QuickJS's `JS_Eval` throws it: an error
430    /// object of its kind whose `stack` is its location.
431    fn throw_compile_error(
432        &mut self,
433        error: &Error,
434        source: &[u8],
435        filename: &str,
436    ) -> RuntimeError {
437        use crate::engine::api::error::ErrorKind;
438        let kind = match error.kind() {
439            ErrorKind::Syntax => oxide_core::ErrorKind::Syntax,
440            ErrorKind::Type => oxide_core::ErrorKind::Type,
441            ErrorKind::Reference => oxide_core::ErrorKind::Reference,
442            ErrorKind::Range => oxide_core::ErrorKind::Range,
443            ErrorKind::JsInternal => oxide_core::ErrorKind::Internal,
444            ErrorKind::Unsupported => {
445                return RuntimeError::Unsupported("constructs of this source");
446            }
447            ErrorKind::Internal | ErrorKind::Io => return RuntimeError::Compile(error.clone()),
448        };
449        let created = match syntax_location(error, source) {
450            Some((line, column)) => {
451                self.core
452                    .new_located_error(kind, error.message(), filename, line, column)
453            }
454            None => self.core.new_error(kind, error.message()),
455        };
456        match created {
457            Ok(thrown) => self.thrown(oxide_core::Throw(thrown)),
458            Err(error) => error.into(),
459        }
460    }
461
462    pub(crate) fn execute(&mut self, script: &FunctionBytecodeRef) -> JsResult<Value> {
463        let function = self.object(script.function())?;
464        let result = self.core.run_script(function);
465        self.complete(result)
466    }
467
468    // ---- modules ----
469
470    pub(crate) fn compile_module(&mut self, source: &str) -> JsResult<ModuleBytecodeRef> {
471        self.compile_module_bytes(source.as_bytes())
472    }
473
474    pub(crate) fn compile_module_bytes(&mut self, source: &[u8]) -> JsResult<ModuleBytecodeRef> {
475        self.compile_module_bytes_with_filename(
476            source,
477            crate::engine::compiler::DEFAULT_EVAL_FILENAME,
478        )
479    }
480
481    pub(crate) fn compile_module_with_filename(
482        &mut self,
483        source: &str,
484        filename: &str,
485    ) -> JsResult<ModuleBytecodeRef> {
486        self.compile_module_bytes_with_filename(source.as_bytes(), filename)
487    }
488
489    pub(crate) fn compile_module_bytes_with_options(
490        &mut self,
491        source: &[u8],
492        options: &CompileOptions,
493    ) -> JsResult<ModuleBytecodeRef> {
494        self.compile_module_bytes_with_filename(source, &options.filename)
495    }
496
497    pub(crate) fn compile_module_bytes_with_filename(
498        &mut self,
499        source: &[u8],
500        filename: &str,
501    ) -> JsResult<ModuleBytecodeRef> {
502        self.compile_module_bytes_with_import_meta(source, filename, Vec::new())
503    }
504
505    pub(crate) fn compile_module_bytes_with_import_meta(
506        &mut self,
507        source: &[u8],
508        filename: &str,
509        import_meta: Vec<(String, Value)>,
510    ) -> JsResult<ModuleBytecodeRef> {
511        self.modules_supported()?;
512        let debug_info = self.shared.debug_info.get();
513        let compiled = {
514            let mut compiler = self.core.compiler(false);
515            super::compile::compile_module(&mut compiler, filename, source, debug_info)
516        };
517        match compiled {
518            Ok((
519                oxide_core::vm::module::ModuleSource::Compiled {
520                    function, tables, ..
521                },
522                _,
523            )) => {
524                let function = self.lift_object(function);
525                // A second module of the same name replaces the first for
526                // later imports, as a fresh `JS_Eval` does.
527                self.core.forget_module(filename);
528                self.shared.modules.borrow_mut().insert(
529                    filename.to_owned(),
530                    Preloaded::Compiled {
531                        function,
532                        tables,
533                        import_meta,
534                    },
535                );
536                Ok(ModuleBytecodeRef::new(filename))
537            }
538            Ok(_) => Err(RuntimeError::Invariant("a compiled module")),
539            Err(super::compile::ModuleCompileError::Front(error)) => {
540                Err(self.throw_compile_error(&error, source, filename))
541            }
542            Err(super::compile::ModuleCompileError::Core(failure)) => {
543                let thrown = self.core.new_error(failure.kind, &failure.message)?;
544                Err(self.thrown(oxide_core::Throw(thrown)))
545            }
546        }
547    }
548
549    pub(crate) fn execute_module(&mut self, module: &ModuleBytecodeRef) -> JsResult<Value> {
550        self.modules_supported()?;
551        let result = self.core.run_module(module.name());
552        self.complete(result)
553    }
554
555    // ---- calls ----
556
557    pub(crate) fn call(
558        &mut self,
559        callable: &CallableRef,
560        this_value: Value,
561        arguments: &[Value],
562    ) -> JsResult<Value> {
563        let function = self.function(callable)?;
564        let this = self.lower(&this_value)?;
565        let args = self.lower_all(arguments)?;
566        let result = self.core.call(function, this, &args);
567        self.complete(result)
568    }
569
570    pub(crate) fn construct(
571        &mut self,
572        constructor: &CallableRef,
573        arguments: &[Value],
574    ) -> JsResult<Value> {
575        self.construct_with_new_target(constructor, constructor, arguments)
576    }
577
578    pub(crate) fn construct_with_new_target(
579        &mut self,
580        constructor: &CallableRef,
581        new_target: &CallableRef,
582        arguments: &[Value],
583    ) -> JsResult<Value> {
584        let function = self.function(constructor)?;
585        let target = self.function(new_target)?;
586        let args = self.lower_all(arguments)?;
587        if !self.core.is_constructor(function) {
588            let error = self
589                .core
590                .new_error(oxide_core::ErrorKind::Type, "not a constructor")?;
591            return Err(self.thrown(oxide_core::Throw(error)));
592        }
593        let result = self.core.construct(function, &args, target);
594        self.complete(result)
595    }
596
597    // ---- objects ----
598
599    pub(crate) fn new_object(&mut self) -> JsResult<ObjectRef> {
600        let object = self.core.new_object()?;
601        Ok(self.lift_object(object))
602    }
603
604    pub(crate) fn new_object_with_prototype(
605        &mut self,
606        prototype: Option<&ObjectRef>,
607    ) -> JsResult<ObjectRef> {
608        let prototype = prototype.map(|p| self.object(p)).transpose()?;
609        let object = self.core.new_object_with_prototype(prototype)?;
610        Ok(self.lift_object(object))
611    }
612
613    pub(crate) fn new_array(&mut self) -> JsResult<ObjectRef> {
614        self.new_array_from_values(Vec::new())
615    }
616
617    pub(crate) fn new_array_from_values(&mut self, values: Vec<Value>) -> JsResult<ObjectRef> {
618        let values = self.lower_all(&values)?;
619        let result = self.core.new_array_from(&values);
620        let array = self.complete_with(result)?;
621        Ok(self.lift_object(array))
622    }
623
624    pub(crate) fn get_own_property(
625        &mut self,
626        object: &ObjectRef,
627        key: &PropertyKey,
628    ) -> JsResult<Option<CompleteOrdinaryPropertyDescriptor>> {
629        let id = self.object(object)?;
630        let key = self.key(key)?;
631        let result = self.core.get_own_property(id, key);
632        match self.complete_with(result)? {
633            Some(descriptor) => self.lift_descriptor(descriptor).map(Some),
634            None => Ok(None),
635        }
636    }
637
638    pub(crate) fn define_own_property(
639        &mut self,
640        object: &ObjectRef,
641        key: &PropertyKey,
642        descriptor: &OrdinaryPropertyDescriptor,
643    ) -> JsResult<bool> {
644        let id = self.object(object)?;
645        let key = self.key(key)?;
646        let descriptor = self.lower_descriptor(descriptor)?;
647        let result = self.core.define_own_property(id, key, &descriptor);
648        self.complete_with(result)
649    }
650
651    pub(crate) fn get_property(
652        &mut self,
653        object: &ObjectRef,
654        key: &PropertyKey,
655    ) -> JsResult<Value> {
656        self.get_property_with_receiver(object, key, Value::Object(object.clone()))
657    }
658
659    pub(crate) fn get_property_with_receiver(
660        &mut self,
661        object: &ObjectRef,
662        key: &PropertyKey,
663        receiver: Value,
664    ) -> JsResult<Value> {
665        let id = self.object(object)?;
666        let key = self.key(key)?;
667        let receiver = self.lower(&receiver)?;
668        let result = self.core.get(id, key, receiver);
669        self.complete(result)
670    }
671
672    pub(crate) fn set_property(
673        &mut self,
674        object: &ObjectRef,
675        key: &PropertyKey,
676        value: Value,
677    ) -> JsResult<bool> {
678        self.set_property_with_receiver(object, key, value, Value::Object(object.clone()))
679    }
680
681    pub(crate) fn set_property_with_receiver(
682        &mut self,
683        object: &ObjectRef,
684        key: &PropertyKey,
685        value: Value,
686        receiver: Value,
687    ) -> JsResult<bool> {
688        let id = self.object(object)?;
689        let key = self.key(key)?;
690        let value = self.lower(&value)?;
691        let receiver = self.lower(&receiver)?;
692        let result = self.core.set(id, key, value, receiver);
693        self.complete_with(result)
694    }
695
696    pub(crate) fn delete_property(
697        &mut self,
698        object: &ObjectRef,
699        key: &PropertyKey,
700    ) -> JsResult<bool> {
701        let id = self.object(object)?;
702        let key = self.key(key)?;
703        let result = self.core.delete_property(id, key);
704        self.complete_with(result)
705    }
706
707    pub(crate) fn has_property(&mut self, object: &ObjectRef, key: &PropertyKey) -> JsResult<bool> {
708        let id = self.object(object)?;
709        let key = self.key(key)?;
710        let result = self.core.has_property(id, key);
711        self.complete_with(result)
712    }
713
714    pub(crate) fn has_own_property(
715        &mut self,
716        object: &ObjectRef,
717        key: &PropertyKey,
718    ) -> JsResult<bool> {
719        let id = self.object(object)?;
720        let key = self.key(key)?;
721        let result = self.core.has_own_property(id, key);
722        self.complete_with(result)
723    }
724
725    pub(crate) fn own_property_keys(&mut self, object: &ObjectRef) -> JsResult<Vec<PropertyKey>> {
726        let id = self.object(object)?;
727        let result = self.core.own_property_keys(id);
728        let keys = self.complete_with(result)?;
729        keys.into_iter().map(|key| self.lift_key(key)).collect()
730    }
731
732    pub(crate) fn get_prototype_of(&mut self, object: &ObjectRef) -> JsResult<Option<ObjectRef>> {
733        let id = self.object(object)?;
734        let result = self.core.get_prototype_of(id);
735        let prototype = self.complete_with(result)?;
736        Ok(prototype.map(|prototype| self.lift_object(prototype)))
737    }
738
739    pub(crate) fn set_prototype_of(
740        &mut self,
741        object: &ObjectRef,
742        prototype: Option<&ObjectRef>,
743    ) -> JsResult<bool> {
744        let id = self.object(object)?;
745        let prototype = prototype.map(|p| self.object(p)).transpose()?;
746        let result = self.core.set_prototype_of(id, prototype);
747        self.complete_with(result)
748    }
749
750    pub(crate) fn as_callable(&mut self, object: &ObjectRef) -> JsResult<Option<CallableRef>> {
751        let value = self.own(&object.slot)?;
752        Ok(self
753            .core
754            .is_callable(value)
755            .then(|| CallableRef(object.clone())))
756    }
757
758    pub(crate) fn is_constructor(&mut self, object: &ObjectRef) -> JsResult<bool> {
759        let value = self.own(&object.slot)?;
760        Ok(self.core.is_constructor(value))
761    }
762
763    pub(crate) fn is_array_object(&mut self, object: &ObjectRef) -> JsResult<bool> {
764        let value = self.own(&object.slot)?;
765        let result = self.core.is_array(value);
766        self.complete_with(result)
767    }
768
769    pub(crate) fn is_error_object(&mut self, object: &ObjectRef) -> JsResult<bool> {
770        let value = self.own(&object.slot)?;
771        Ok(self.core.is_error(value))
772    }
773
774    // ---- conversions and printing ----
775
776    #[allow(clippy::wrong_self_convention)]
777    pub(crate) fn to_js_string(&mut self, value: &Value) -> JsResult<JsString> {
778        let value = self.lower(value)?;
779        let result = self.core.to_string(value);
780        match self.complete(result)? {
781            Value::String(text) => Ok(text),
782            _ => Err(RuntimeError::Invariant("ToString returned a string")),
783        }
784    }
785
786    #[allow(clippy::wrong_self_convention)]
787    pub(crate) fn to_number(&mut self, value: &Value) -> JsResult<f64> {
788        let value = self.lower(value)?;
789        let result = self.core.to_number(value);
790        self.complete_with(result)
791    }
792
793    pub(crate) fn detach_array_buffer(&mut self, value: &Value) -> JsResult<()> {
794        let value = self.lower(value)?;
795        let result = self.core.detach_array_buffer(value);
796        self.complete_with(result)
797    }
798
799    pub(crate) fn type_of(&mut self, value: &Value) -> JsResult<String> {
800        let value = self.lower(value)?;
801        Ok(self.core.type_of(value))
802    }
803
804    pub(crate) fn print_value(&mut self, value: &Value) -> JsResult<String> {
805        let value = self.lower(value)?;
806        Ok(self.core.print_value(value))
807    }
808
809    pub(crate) fn qjs_print_value_bytes(&mut self, value: &Value) -> JsResult<Vec<u8>> {
810        let value = self.lower(value)?;
811        Ok(self.core.print_value_bytes(value))
812    }
813
814    // ---- symbols ----
815
816    pub(crate) fn new_symbol(&mut self, description: Option<JsString>) -> JsResult<SymbolRef> {
817        let units: Option<Vec<u16>> = description.map(|text| text.utf16_units().collect());
818        let symbol = self.core.new_symbol(units.as_deref())?;
819        match self.lift(symbol)? {
820            Value::Symbol(symbol) => Ok(symbol),
821            _ => Err(RuntimeError::Invariant("a new symbol")),
822        }
823    }
824
825    pub(crate) fn symbol_description(&mut self, symbol: &SymbolRef) -> JsResult<Option<JsString>> {
826        let value = self.own(&symbol.slot)?;
827        self.core
828            .symbol_description(value)
829            .map(JsString::try_from_utf16)
830            .transpose()
831            .map_err(RuntimeError::from)
832    }
833
834    pub(crate) fn well_known_symbol(&mut self, symbol: WellKnownSymbol) -> JsResult<SymbolRef> {
835        let value = self
836            .core
837            .well_known_symbol(symbol.name())
838            .ok_or(RuntimeError::Invariant("a well-known symbol"))?;
839        match self.lift(value)? {
840            Value::Symbol(symbol) => Ok(symbol),
841            _ => Err(RuntimeError::Invariant("a well-known symbol")),
842        }
843    }
844
845    // ---- promises ----
846
847    pub(crate) fn promise_snapshot(
848        &mut self,
849        promise: &ObjectRef,
850    ) -> JsResult<Option<PromiseSnapshot>> {
851        let value = oxide_core::Value::object(self.object(promise)?);
852        let Some((state, result)) = self.core.promise_state(value) else {
853            return Ok(None);
854        };
855        let state = match state {
856            1 => PromiseState::Fulfilled,
857            2 => PromiseState::Rejected,
858            _ => PromiseState::Pending,
859        };
860        let result = if state == PromiseState::Pending {
861            Value::Undefined
862        } else {
863            self.lift(result)?
864        };
865        Ok(Some(PromiseSnapshot::new(state, result)))
866    }
867
868    pub(crate) fn new_promise(&mut self) -> JsResult<PromiseCapability> {
869        let result = self.core.new_promise_capability();
870        let (promise, resolve, reject) = self.complete_with(result)?;
871        Ok(PromiseCapability {
872            promise: self.lift_object(promise),
873            resolve: CallableRef(self.lift_object(resolve)),
874            reject: CallableRef(self.lift_object(reject)),
875        })
876    }
877
878    pub(crate) fn promise_then(
879        &mut self,
880        promise: &ObjectRef,
881        on_fulfilled: impl HostFunction<Raw>,
882        on_rejected: impl HostFunction<Raw>,
883    ) -> JsResult<ObjectRef> {
884        let fulfilled = self.new_function(FunctionOptions::new("").length(1), on_fulfilled)?;
885        let rejected = self.new_function(FunctionOptions::new("").length(1), on_rejected)?;
886        let key = PropertyKey::from_js_string(JsString::from_static("then"));
887        let then = match self.get_property(promise, &key)? {
888            Value::Object(then) => self.as_callable(&then)?,
889            _ => None,
890        };
891        let Some(then) = then else {
892            return Err(self.throw_error(NativeErrorKind::Type, "not a function"));
893        };
894        let result = self.call(
895            &then,
896            Value::Object(promise.clone()),
897            &[Value::from(fulfilled), Value::from(rejected)],
898        )?;
899        match result {
900            Value::Object(promise) => Ok(promise),
901            _ => Err(RuntimeError::Invariant("then returned a promise")),
902        }
903    }
904
905    // ---- buffers ----
906
907    pub(crate) fn new_array_buffer(&mut self, bytes: &[u8]) -> JsResult<ObjectRef> {
908        let result = self.core.new_array_buffer(bytes.len());
909        let id = self.complete_with(result)?;
910        let buffer = self.lift_object(id);
911        let result = self.core.array_buffer_write(id, 0, bytes);
912        self.complete_with(result)?;
913        Ok(buffer)
914    }
915
916    pub(crate) fn array_buffer_len(&mut self, buffer: &ObjectRef) -> JsResult<Option<usize>> {
917        let id = self.object(buffer)?;
918        Ok(self.core.array_buffer_len(id))
919    }
920
921    pub(crate) fn array_buffer_to_vec(&mut self, buffer: &ObjectRef) -> JsResult<Vec<u8>> {
922        let id = self.object(buffer)?;
923        let mut bytes = vec![0; self.core.array_buffer_len(id).unwrap_or(0)];
924        let result = self.core.array_buffer_read(id, 0, &mut bytes);
925        self.complete_with(result)?;
926        Ok(bytes)
927    }
928
929    pub(crate) fn with_array_buffer_bytes<R>(
930        &mut self,
931        buffer: &ObjectRef,
932        f: impl FnOnce(&[u8]) -> R,
933    ) -> JsResult<R> {
934        let id = self.object(buffer)?;
935        if let Some(bytes) = self.core.array_buffer_bytes(id) {
936            return Ok(f(bytes));
937        }
938        // A shared buffer's bytes are atomics: they are copied first. A
939        // detached buffer or another object throws.
940        let bytes = self.array_buffer_to_vec(buffer)?;
941        Ok(f(&bytes))
942    }
943
944    pub(crate) fn write_array_buffer(
945        &mut self,
946        buffer: &ObjectRef,
947        offset: usize,
948        data: &[u8],
949    ) -> JsResult<()> {
950        let id = self.object(buffer)?;
951        let result = self.core.array_buffer_write(id, offset, data);
952        self.complete_with(result)
953    }
954
955    pub(crate) fn typed_array_view(
956        &mut self,
957        array: &ObjectRef,
958    ) -> JsResult<Option<TypedArrayView>> {
959        let id = self.object(array)?;
960        let Some((kind, buffer, byte_offset, length)) = self.core.typed_array_view(id) else {
961            return Ok(None);
962        };
963        Ok(Some(TypedArrayView {
964            kind,
965            buffer: self.lift_object(buffer),
966            byte_offset,
967            length,
968        }))
969    }
970
971    pub(crate) fn new_typed_array(
972        &mut self,
973        kind: TypedArrayKind,
974        buffer: &ObjectRef,
975        byte_offset: usize,
976        length: Option<usize>,
977    ) -> JsResult<ObjectRef> {
978        let constructor = CallableRef(self.intrinsic(typed_array_constructor(kind))?);
979        let mut arguments = vec![
980            Value::Object(buffer.clone()),
981            Value::number(byte_offset as f64),
982        ];
983        if let Some(length) = length {
984            arguments.push(Value::number(length as f64));
985        }
986        match self.construct(&constructor, &arguments)? {
987            Value::Object(array) => Ok(array),
988            _ => Err(RuntimeError::Invariant("a typed array")),
989        }
990    }
991
992    // ---- intrinsics ----
993
994    fn intrinsic(&mut self, intrinsic: Intrinsic) -> JsResult<ObjectRef> {
995        let object = self.core.intrinsic(intrinsic);
996        Ok(self.lift_object(object))
997    }
998
999    pub(crate) fn global_object(&mut self) -> JsResult<ObjectRef> {
1000        let object = self.core.global_object();
1001        Ok(self.lift_object(object))
1002    }
1003
1004    pub(crate) fn object_prototype(&mut self) -> JsResult<ObjectRef> {
1005        self.intrinsic(Intrinsic::ObjectPrototype)
1006    }
1007
1008    pub(crate) fn array_prototype(&mut self) -> JsResult<ObjectRef> {
1009        self.intrinsic(Intrinsic::ArrayPrototype)
1010    }
1011
1012    pub(crate) fn function_prototype(&mut self) -> JsResult<ObjectRef> {
1013        self.intrinsic(Intrinsic::FunctionPrototype)
1014    }
1015
1016    pub(crate) fn iterator_prototype(&mut self) -> JsResult<ObjectRef> {
1017        self.intrinsic(Intrinsic::IteratorPrototype)
1018    }
1019
1020    pub(crate) fn string_iterator_prototype(&mut self) -> JsResult<ObjectRef> {
1021        self.intrinsic(Intrinsic::StringIteratorPrototype)
1022    }
1023
1024    pub(crate) fn number_prototype(&mut self) -> JsResult<ObjectRef> {
1025        self.intrinsic(Intrinsic::NumberPrototype)
1026    }
1027
1028    pub(crate) fn boolean_prototype(&mut self) -> JsResult<ObjectRef> {
1029        self.intrinsic(Intrinsic::BooleanPrototype)
1030    }
1031
1032    pub(crate) fn string_prototype(&mut self) -> JsResult<ObjectRef> {
1033        self.intrinsic(Intrinsic::StringPrototype)
1034    }
1035
1036    pub(crate) fn symbol_prototype(&mut self) -> JsResult<ObjectRef> {
1037        self.intrinsic(Intrinsic::SymbolPrototype)
1038    }
1039
1040    pub(crate) fn bigint_prototype(&mut self) -> JsResult<ObjectRef> {
1041        self.intrinsic(Intrinsic::BigIntPrototype)
1042    }
1043
1044    pub(crate) fn function_constructor(&mut self) -> JsResult<CallableRef> {
1045        self.intrinsic(Intrinsic::Function).map(CallableRef)
1046    }
1047
1048    // ---- errors ----
1049
1050    pub(crate) fn new_native_error(
1051        &mut self,
1052        kind: NativeErrorKind,
1053        message: &str,
1054    ) -> JsResult<Value> {
1055        let error = self.core.new_error(native_kind(kind), message)?;
1056        self.lift(error)
1057    }
1058
1059    pub(crate) fn throw_error(&mut self, kind: NativeErrorKind, message: &str) -> RuntimeError {
1060        match self.new_native_error(kind, message) {
1061            Ok(error) => RuntimeError::Exception(error),
1062            Err(error) => error,
1063        }
1064    }
1065
1066    // ---- hosts ----
1067
1068    pub(crate) fn install_qjs_helpers(&mut self, helpers: &QjsHelpers) -> JsResult<()> {
1069        self.core
1070            .install_qjs_helpers(helpers.script_args.as_deref())?;
1071        if helpers.std {
1072            self.core.install_std()?;
1073        }
1074        Ok(())
1075    }
1076
1077    // ---- host functions and host objects ----
1078
1079    pub(crate) fn new_function<Args>(
1080        &mut self,
1081        options: FunctionOptions,
1082        function: impl HostFunction<Args>,
1083    ) -> JsResult<CallableRef> {
1084        let data = self.lower_all(&options.data)?;
1085        let body = host_body(self.shared, function);
1086        let object = self.core.new_host_function(
1087            &options.name,
1088            options.length,
1089            options.constructor,
1090            &data,
1091            body,
1092        )?;
1093        Ok(CallableRef(self.lift_object(object)))
1094    }
1095
1096    pub(crate) fn define_function<Args>(
1097        &mut self,
1098        target: &ObjectRef,
1099        name: &str,
1100        length: u32,
1101        function: impl HostFunction<Args>,
1102    ) -> JsResult<CallableRef> {
1103        let function = self.new_function(FunctionOptions::new(name).length(length), function)?;
1104        let key = PropertyKey::from_js_string(JsString::try_from_utf8(name)?);
1105        let descriptor = OrdinaryPropertyDescriptor::data(
1106            Value::Object(function.as_object().clone()),
1107            true,
1108            false,
1109            true,
1110        );
1111        if !self.define_own_property(target, &key, &descriptor)? {
1112            let error = self.throw_error(NativeErrorKind::Type, "property is not configurable");
1113            return Err(error);
1114        }
1115        Ok(function)
1116    }
1117
1118    pub(crate) fn new_host_object<T: 'static>(
1119        &mut self,
1120        value: T,
1121        prototype: Option<&ObjectRef>,
1122    ) -> JsResult<ObjectRef> {
1123        let prototype = prototype.map(|p| self.object(p)).transpose()?;
1124        let object = self.core.new_host_object(prototype, Rc::new(value))?;
1125        Ok(self.lift_object(object))
1126    }
1127
1128    pub(crate) fn host_data<T: 'static>(&mut self, object: &ObjectRef) -> JsResult<Option<Rc<T>>> {
1129        let id = self.object(object)?;
1130        Ok(self
1131            .core
1132            .host_data(id)
1133            .and_then(|data: Rc<dyn Any>| data.downcast::<T>().ok()))
1134    }
1135}
1136
1137fn typed_array_constructor(kind: TypedArrayKind) -> Intrinsic {
1138    match kind {
1139        TypedArrayKind::Int8 => Intrinsic::Int8Array,
1140        TypedArrayKind::Uint8 => Intrinsic::Uint8Array,
1141        TypedArrayKind::Uint8Clamped => Intrinsic::Uint8ClampedArray,
1142        TypedArrayKind::Int16 => Intrinsic::Int16Array,
1143        TypedArrayKind::Uint16 => Intrinsic::Uint16Array,
1144        TypedArrayKind::Int32 => Intrinsic::Int32Array,
1145        TypedArrayKind::Uint32 => Intrinsic::Uint32Array,
1146        TypedArrayKind::Float16 => Intrinsic::Float16Array,
1147        TypedArrayKind::Float32 => Intrinsic::Float32Array,
1148        TypedArrayKind::Float64 => Intrinsic::Float64Array,
1149        TypedArrayKind::BigInt64 => Intrinsic::BigInt64Array,
1150        TypedArrayKind::BigUint64 => Intrinsic::BigUint64Array,
1151    }
1152}
1153
1154pub(crate) fn native_kind(kind: NativeErrorKind) -> oxide_core::ErrorKind {
1155    match kind {
1156        NativeErrorKind::Eval => oxide_core::ErrorKind::Eval,
1157        NativeErrorKind::Range => oxide_core::ErrorKind::Range,
1158        NativeErrorKind::Reference => oxide_core::ErrorKind::Reference,
1159        NativeErrorKind::Syntax => oxide_core::ErrorKind::Syntax,
1160        NativeErrorKind::Type => oxide_core::ErrorKind::Type,
1161        NativeErrorKind::Uri => oxide_core::ErrorKind::Uri,
1162        NativeErrorKind::Internal => oxide_core::ErrorKind::Internal,
1163        NativeErrorKind::Aggregate => oxide_core::ErrorKind::Aggregate,
1164    }
1165}
1166
1167mod sealed {
1168    pub trait Sealed {}
1169    impl Sealed for super::Context {}
1170    impl Sealed for super::Scope<'_> {}
1171}
1172
1173/// Lists every shared operation once, with its documentation, and emits it
1174/// as an inherent method of `Context` (one entry each, `Reentered` inside a
1175/// host function), an inherent method of `Scope` (on the host function's
1176/// view) and a method of [`Js`]. `Context` takes `&self`: its state is the
1177/// runtime's, behind the `Rc`.
1178macro_rules! js_ops {
1179    ($(
1180        $(#[$doc:meta])*
1181        fn $name:ident $([$($generic:tt)*])? (&mut self $(, $arg:ident: $ty:ty)* $(,)?) -> $ret:ty;
1182    )*) => {
1183        impl Context {
1184            $(
1185                $(#[$doc])*
1186                pub fn $name $(<$($generic)*>)? (&self $(, $arg: $ty)*) -> $ret {
1187                    let mut entry = self.runtime.enter()?;
1188                    entry.view().$name($($arg),*)
1189                }
1190            )*
1191        }
1192
1193        impl Scope<'_> {
1194            $(
1195                $(#[$doc])*
1196                pub fn $name $(<$($generic)*>)? (&mut self $(, $arg: $ty)*) -> $ret {
1197                    self.view().$name($($arg),*)
1198                }
1199            )*
1200        }
1201
1202        /// The operations [`Context`] and a host function's [`Scope`]
1203        /// share, for code generic over where it runs. Sealed; both types
1204        /// also have each as an inherent method, so calling one needs no
1205        /// import.
1206        pub trait Js: sealed::Sealed {
1207            $(
1208                $(#[$doc])*
1209                fn $name $(<$($generic)*>)? (&mut self $(, $arg: $ty)*) -> $ret;
1210            )*
1211
1212            /// An error object of `kind` with `message` and a `stack` from
1213            /// the running frames, as the error to return:
1214            /// `return Err(js.throw_error(NativeErrorKind::Type, "x is required"))`.
1215            fn throw_error(&mut self, kind: NativeErrorKind, message: &str) -> RuntimeError;
1216        }
1217
1218        impl Js for Context {
1219            $(
1220                fn $name $(<$($generic)*>)? (&mut self $(, $arg: $ty)*) -> $ret {
1221                    Context::$name(self $(, $arg)*)
1222                }
1223            )*
1224
1225            fn throw_error(&mut self, kind: NativeErrorKind, message: &str) -> RuntimeError {
1226                Context::throw_error(self, kind, message)
1227            }
1228        }
1229
1230        impl Js for Scope<'_> {
1231            $(
1232                fn $name $(<$($generic)*>)? (&mut self $(, $arg: $ty)*) -> $ret {
1233                    Scope::$name(self $(, $arg)*)
1234                }
1235            )*
1236
1237            fn throw_error(&mut self, kind: NativeErrorKind, message: &str) -> RuntimeError {
1238                Scope::throw_error(self, kind, message)
1239            }
1240        }
1241    };
1242}
1243
1244impl Context {
1245    /// [`Js::throw_error`].
1246    pub fn throw_error(&self, kind: NativeErrorKind, message: &str) -> RuntimeError {
1247        match self.runtime.enter() {
1248            Ok(mut entry) => entry.view().throw_error(kind, message),
1249            Err(error) => error,
1250        }
1251    }
1252}
1253
1254impl Scope<'_> {
1255    /// [`Js::throw_error`].
1256    pub fn throw_error(&mut self, kind: NativeErrorKind, message: &str) -> RuntimeError {
1257        self.view().throw_error(kind, message)
1258    }
1259}
1260
1261js_ops! {
1262    // ---- scripts ----
1263
1264    /// Compiles and runs `source` as a script; the completion value.
1265    fn eval(&mut self, source: &str) -> JsResult<Value>;
1266    fn eval_bytes(&mut self, source: &[u8]) -> JsResult<Value>;
1267    fn eval_with_filename(&mut self, source: &str, filename: &str) -> JsResult<Value>;
1268    fn eval_with_options(&mut self, source: &str, options: &EvalOptions) -> JsResult<Value>;
1269    fn eval_bytes_with_options(&mut self, source: &[u8], options: &EvalOptions) -> JsResult<Value>;
1270    /// Compiles and runs `source` as a script named `filename`; the
1271    /// completion value. A syntax error is thrown (`RuntimeError::Exception`
1272    /// with a `SyntaxError`), as QuickJS's `JS_Eval` does.
1273    fn eval_bytes_with_filename(&mut self, source: &[u8], filename: &str) -> JsResult<Value>;
1274    fn compile(&mut self, source: &str) -> JsResult<FunctionBytecodeRef>;
1275    fn compile_bytes(&mut self, source: &[u8]) -> JsResult<FunctionBytecodeRef>;
1276    fn compile_with_filename(&mut self, source: &str, filename: &str) -> JsResult<FunctionBytecodeRef>;
1277    fn compile_with_options(&mut self, source: &str, options: &CompileOptions) -> JsResult<FunctionBytecodeRef>;
1278    fn compile_bytes_with_options(&mut self, source: &[u8], options: &CompileOptions) -> JsResult<FunctionBytecodeRef>;
1279    /// Compiles `source` as a script named `filename`. A syntax error is
1280    /// thrown (`RuntimeError::Exception` with a `SyntaxError`). Inside a
1281    /// host function the code is transient whatever the options say.
1282    fn compile_bytes_with_filename(&mut self, source: &[u8], filename: &str) -> JsResult<FunctionBytecodeRef>;
1283    /// Runs a compiled script with the global object as `this`.
1284    fn execute(&mut self, script: &FunctionBytecodeRef) -> JsResult<Value>;
1285
1286    // ---- modules (`Unsupported` inside a host function) ----
1287
1288    fn compile_module(&mut self, source: &str) -> JsResult<ModuleBytecodeRef>;
1289    fn compile_module_bytes(&mut self, source: &[u8]) -> JsResult<ModuleBytecodeRef>;
1290    fn compile_module_with_filename(&mut self, source: &str, filename: &str) -> JsResult<ModuleBytecodeRef>;
1291    fn compile_module_bytes_with_options(&mut self, source: &[u8], options: &CompileOptions) -> JsResult<ModuleBytecodeRef>;
1292    fn compile_module_bytes_with_filename(&mut self, source: &[u8], filename: &str) -> JsResult<ModuleBytecodeRef>;
1293    /// Compiles `source` as the module `filename`, whose `import.meta`
1294    /// starts with `import_meta` (qjs's `url` and `main`). A syntax error is
1295    /// thrown.
1296    fn compile_module_bytes_with_import_meta(&mut self, source: &[u8], filename: &str, import_meta: Vec<(String, Value)>) -> JsResult<ModuleBytecodeRef>;
1297    /// Links and evaluates a compiled module and what it imports; the
1298    /// promise of its evaluation.
1299    fn execute_module(&mut self, module: &ModuleBytecodeRef) -> JsResult<Value>;
1300
1301    // ---- calls ----
1302
1303    fn call(&mut self, callable: &CallableRef, this_value: Value, arguments: &[Value]) -> JsResult<Value>;
1304    fn construct(&mut self, constructor: &CallableRef, arguments: &[Value]) -> JsResult<Value>;
1305    fn construct_with_new_target(&mut self, constructor: &CallableRef, new_target: &CallableRef, arguments: &[Value]) -> JsResult<Value>;
1306
1307    // ---- objects ----
1308
1309    fn new_object(&mut self) -> JsResult<ObjectRef>;
1310    fn new_object_with_prototype(&mut self, prototype: Option<&ObjectRef>) -> JsResult<ObjectRef>;
1311    fn new_array(&mut self) -> JsResult<ObjectRef>;
1312    fn new_array_from_values(&mut self, values: Vec<Value>) -> JsResult<ObjectRef>;
1313    fn get_own_property(&mut self, object: &ObjectRef, key: &PropertyKey) -> JsResult<Option<CompleteOrdinaryPropertyDescriptor>>;
1314    fn define_own_property(&mut self, object: &ObjectRef, key: &PropertyKey, descriptor: &OrdinaryPropertyDescriptor) -> JsResult<bool>;
1315    fn get_property(&mut self, object: &ObjectRef, key: &PropertyKey) -> JsResult<Value>;
1316    fn get_property_with_receiver(&mut self, object: &ObjectRef, key: &PropertyKey, receiver: Value) -> JsResult<Value>;
1317    fn set_property(&mut self, object: &ObjectRef, key: &PropertyKey, value: Value) -> JsResult<bool>;
1318    fn set_property_with_receiver(&mut self, object: &ObjectRef, key: &PropertyKey, value: Value, receiver: Value) -> JsResult<bool>;
1319    fn delete_property(&mut self, object: &ObjectRef, key: &PropertyKey) -> JsResult<bool>;
1320    fn has_property(&mut self, object: &ObjectRef, key: &PropertyKey) -> JsResult<bool>;
1321    fn has_own_property(&mut self, object: &ObjectRef, key: &PropertyKey) -> JsResult<bool>;
1322    fn own_property_keys(&mut self, object: &ObjectRef) -> JsResult<Vec<PropertyKey>>;
1323    fn get_prototype_of(&mut self, object: &ObjectRef) -> JsResult<Option<ObjectRef>>;
1324    fn set_prototype_of(&mut self, object: &ObjectRef, prototype: Option<&ObjectRef>) -> JsResult<bool>;
1325    /// The object as a callable reference; `None` when it is not callable.
1326    fn as_callable(&mut self, object: &ObjectRef) -> JsResult<Option<CallableRef>>;
1327    fn is_constructor(&mut self, object: &ObjectRef) -> JsResult<bool>;
1328    /// `IsArray`.
1329    fn is_array_object(&mut self, object: &ObjectRef) -> JsResult<bool>;
1330    fn is_error_object(&mut self, object: &ObjectRef) -> JsResult<bool>;
1331
1332    // ---- conversions and printing ----
1333
1334    /// `ToString(value)`.
1335    fn to_js_string(&mut self, value: &Value) -> JsResult<JsString>;
1336    /// `ToNumber(value)`.
1337    fn to_number(&mut self, value: &Value) -> JsResult<f64>;
1338    /// QuickJS's `JS_DetachArrayBuffer`: detaches an ArrayBuffer; anything
1339    /// else is ignored.
1340    fn detach_array_buffer(&mut self, value: &Value) -> JsResult<()>;
1341    /// `typeof value`.
1342    fn type_of(&mut self, value: &Value) -> JsResult<String>;
1343    /// QuickJS's `JS_PrintValue`: what `print` and an uncaught-exception dump
1344    /// show. Runs no JavaScript (no accessor, trap or coercion).
1345    fn print_value(&mut self, value: &Value) -> JsResult<String>;
1346    /// `print_value` as the bytes QuickJS writes: a lone surrogate of a raw
1347    /// name, message or stack as its own three bytes (WTF-8) instead of
1348    /// U+FFFD.
1349    fn qjs_print_value_bytes(&mut self, value: &Value) -> JsResult<Vec<u8>>;
1350
1351    // ---- symbols ----
1352
1353    fn new_symbol(&mut self, description: Option<JsString>) -> JsResult<SymbolRef>;
1354    fn symbol_description(&mut self, symbol: &SymbolRef) -> JsResult<Option<JsString>>;
1355    fn well_known_symbol(&mut self, symbol: WellKnownSymbol) -> JsResult<SymbolRef>;
1356
1357    // ---- promises ----
1358
1359    /// A promise's state and result; `None` when `promise` is not one.
1360    fn promise_snapshot(&mut self, promise: &ObjectRef) -> JsResult<Option<PromiseSnapshot>>;
1361    /// `NewPromiseCapability(%Promise%)`: a pending promise and its
1362    /// resolving functions.
1363    fn new_promise(&mut self) -> JsResult<PromiseCapability>;
1364    /// `promise.then(on_fulfilled, on_rejected)` with host functions; the
1365    /// promise `then` returns.
1366    fn promise_then(&mut self, promise: &ObjectRef, on_fulfilled: impl HostFunction<Raw>, on_rejected: impl HostFunction<Raw>) -> JsResult<ObjectRef>;
1367
1368    // ---- buffers ----
1369
1370    /// A new `ArrayBuffer` holding a copy of `bytes`.
1371    fn new_array_buffer(&mut self, bytes: &[u8]) -> JsResult<ObjectRef>;
1372    /// A buffer's length in bytes; `None` for a detached buffer or another
1373    /// object.
1374    fn array_buffer_len(&mut self, buffer: &ObjectRef) -> JsResult<Option<usize>>;
1375    /// A copy of a buffer's bytes (`ArrayBuffer` or `SharedArrayBuffer`);
1376    /// a detached buffer or another object throws a `TypeError`.
1377    fn array_buffer_to_vec(&mut self, buffer: &ObjectRef) -> JsResult<Vec<u8>>;
1378    /// Calls `f` with a buffer's bytes, borrowed in place for an
1379    /// `ArrayBuffer` and copied first for a `SharedArrayBuffer`. `f` runs
1380    /// inside the engine's borrow, so it cannot call the engine.
1381    fn with_array_buffer_bytes[R](&mut self, buffer: &ObjectRef, f: impl FnOnce(&[u8]) -> R) -> JsResult<R>;
1382    /// Writes `data` into a buffer at `offset`: a `TypeError` for a
1383    /// detached buffer or another object, a `RangeError` past its end.
1384    fn write_array_buffer(&mut self, buffer: &ObjectRef, offset: usize, data: &[u8]) -> JsResult<()>;
1385    /// A typed array's kind, buffer, byte offset and current length; `None`
1386    /// for anything but a typed array (a `DataView` included).
1387    fn typed_array_view(&mut self, array: &ObjectRef) -> JsResult<Option<TypedArrayView>>;
1388    /// `new <Kind>Array(buffer, byte_offset, length)`; without `length` the
1389    /// view tracks a resizable buffer's length.
1390    fn new_typed_array(&mut self, kind: TypedArrayKind, buffer: &ObjectRef, byte_offset: usize, length: Option<usize>) -> JsResult<ObjectRef>;
1391
1392    // ---- intrinsics ----
1393
1394    fn global_object(&mut self) -> JsResult<ObjectRef>;
1395    fn object_prototype(&mut self) -> JsResult<ObjectRef>;
1396    fn array_prototype(&mut self) -> JsResult<ObjectRef>;
1397    fn function_prototype(&mut self) -> JsResult<ObjectRef>;
1398    fn iterator_prototype(&mut self) -> JsResult<ObjectRef>;
1399    fn string_iterator_prototype(&mut self) -> JsResult<ObjectRef>;
1400    fn number_prototype(&mut self) -> JsResult<ObjectRef>;
1401    fn boolean_prototype(&mut self) -> JsResult<ObjectRef>;
1402    fn string_prototype(&mut self) -> JsResult<ObjectRef>;
1403    fn symbol_prototype(&mut self) -> JsResult<ObjectRef>;
1404    fn bigint_prototype(&mut self) -> JsResult<ObjectRef>;
1405    fn function_constructor(&mut self) -> JsResult<CallableRef>;
1406
1407    // ---- errors ----
1408
1409    /// A new native error object (not thrown).
1410    fn new_native_error(&mut self, kind: NativeErrorKind, message: &str) -> JsResult<Value>;
1411
1412    // ---- hosts ----
1413
1414    /// qjs's `print` and `console.log`, `scriptArgs`, and under `std` its
1415    /// `load` and `read`.
1416    fn install_qjs_helpers(&mut self, helpers: &QjsHelpers) -> JsResult<()>;
1417
1418    // ---- host functions and host objects ----
1419
1420    /// A function whose body is `function`: a closure over a [`Scope`]
1421    /// (`|scope: &mut Scope<'_>| …`), named and shaped by `options`.
1422    fn new_function[Args](&mut self, options: FunctionOptions, function: impl HostFunction<Args>) -> JsResult<CallableRef>;
1423    /// [`Js::new_function`] defined on `target` as `name`, writable and
1424    /// configurable, not enumerable, as QuickJS's
1425    /// `JS_SetPropertyFunctionList` defines a method.
1426    fn define_function[Args](&mut self, target: &ObjectRef, name: &str, length: u32, function: impl HostFunction<Args>) -> JsResult<CallableRef>;
1427    /// An object inheriting from `prototype` (`None` for null) holding
1428    /// `value`, which drops when the object is collected.
1429    fn new_host_object[T: 'static](&mut self, value: T, prototype: Option<&ObjectRef>) -> JsResult<ObjectRef>;
1430    /// The value a host object holds; `None` for an ordinary object or a
1431    /// value of another type.
1432    fn host_data[T: 'static](&mut self, object: &ObjectRef) -> JsResult<Option<Rc<T>>>;
1433}