feat: works
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
use icu_datetime::provider::{
|
||||
calendar::{DatePatternsV1Marker, DateSkeletonPatternsV1Marker, DateSymbolsV1Marker},
|
||||
week_data::WeekDataV1Marker,
|
||||
};
|
||||
use icu_locale_canonicalizer::{
|
||||
provider::{AliasesV1Marker, LikelySubtagsV1Marker},
|
||||
LocaleCanonicalizer,
|
||||
};
|
||||
use icu_plurals::provider::OrdinalV1Marker;
|
||||
use icu_provider::prelude::*;
|
||||
|
||||
/// Trait encompassing all the required implementations that define
|
||||
/// a valid icu data provider.
|
||||
pub trait BoaProvider:
|
||||
ResourceProvider<AliasesV1Marker>
|
||||
+ ResourceProvider<LikelySubtagsV1Marker>
|
||||
+ ResourceProvider<DateSymbolsV1Marker>
|
||||
+ ResourceProvider<DatePatternsV1Marker>
|
||||
+ ResourceProvider<DateSkeletonPatternsV1Marker>
|
||||
+ ResourceProvider<OrdinalV1Marker>
|
||||
+ ResourceProvider<WeekDataV1Marker>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T> BoaProvider for T where
|
||||
T: ResourceProvider<AliasesV1Marker>
|
||||
+ ResourceProvider<LikelySubtagsV1Marker>
|
||||
+ ResourceProvider<DateSymbolsV1Marker>
|
||||
+ ResourceProvider<DatePatternsV1Marker>
|
||||
+ ResourceProvider<DateSkeletonPatternsV1Marker>
|
||||
+ ResourceProvider<OrdinalV1Marker>
|
||||
+ ResourceProvider<WeekDataV1Marker>
|
||||
+ ?Sized
|
||||
{
|
||||
}
|
||||
|
||||
/// Collection of tools initialized from a [`BoaProvider`] that are used
|
||||
/// for the functionality of `Intl`.
|
||||
#[allow(unused)]
|
||||
pub(crate) struct Icu {
|
||||
provider: Box<dyn BoaProvider>,
|
||||
locale_canonicalizer: LocaleCanonicalizer,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Icu {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
#[derive(Debug)]
|
||||
struct Canonicalizer;
|
||||
f.debug_struct("Icu")
|
||||
.field("locale_canonicalizer", &Canonicalizer)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Icu {
|
||||
/// Create a new [`Icu`] from a valid [`BoaProvider`]
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This method will return an error if any of the tools
|
||||
/// required cannot be constructed.
|
||||
pub(crate) fn new(provider: Box<dyn BoaProvider>) -> Result<Self, DataError> {
|
||||
Ok(Self {
|
||||
locale_canonicalizer: LocaleCanonicalizer::new(&*provider)?,
|
||||
provider,
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the [`LocaleCanonicalizer`] tool.
|
||||
pub(crate) fn locale_canonicalizer(&self) -> &LocaleCanonicalizer {
|
||||
&self.locale_canonicalizer
|
||||
}
|
||||
|
||||
/// Get the inner icu data provider
|
||||
#[allow(unused)]
|
||||
pub(crate) fn provider(&self) -> &dyn BoaProvider {
|
||||
self.provider.as_ref()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,420 @@
|
||||
use crate::{
|
||||
builtins::{error::r#type::create_throw_type_error, iterable::IteratorPrototypes},
|
||||
object::{JsObject, ObjectData},
|
||||
property::PropertyDescriptorBuilder,
|
||||
Context,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Intrinsics {
|
||||
/// Cached standard constructors
|
||||
pub(super) constructors: StandardConstructors,
|
||||
/// Cached intrinsic objects
|
||||
pub(super) objects: IntrinsicObjects,
|
||||
}
|
||||
|
||||
impl Intrinsics {
|
||||
/// Return the cached intrinsic objects.
|
||||
#[inline]
|
||||
pub fn objects(&self) -> &IntrinsicObjects {
|
||||
&self.objects
|
||||
}
|
||||
|
||||
/// Return the cached standard constructors.
|
||||
#[inline]
|
||||
pub fn constructors(&self) -> &StandardConstructors {
|
||||
&self.constructors
|
||||
}
|
||||
}
|
||||
|
||||
/// Store a builtin constructor (such as `Object`) and its corresponding prototype.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StandardConstructor {
|
||||
pub(crate) constructor: JsObject,
|
||||
pub(crate) prototype: JsObject,
|
||||
}
|
||||
|
||||
impl Default for StandardConstructor {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
constructor: JsObject::empty(),
|
||||
prototype: JsObject::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StandardConstructor {
|
||||
/// Build a constructor with a defined prototype.
|
||||
fn with_prototype(prototype: JsObject) -> Self {
|
||||
Self {
|
||||
constructor: JsObject::empty(),
|
||||
prototype,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the constructor object.
|
||||
///
|
||||
/// This is the same as `Object`, `Array`, etc.
|
||||
#[inline]
|
||||
pub fn constructor(&self) -> JsObject {
|
||||
self.constructor.clone()
|
||||
}
|
||||
|
||||
/// Return the prototype of the constructor object.
|
||||
///
|
||||
/// This is the same as `Object.prototype`, `Array.prototype`, etc
|
||||
#[inline]
|
||||
pub fn prototype(&self) -> JsObject {
|
||||
self.prototype.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// Cached core standard constructors.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StandardConstructors {
|
||||
object: StandardConstructor,
|
||||
proxy: StandardConstructor,
|
||||
date: StandardConstructor,
|
||||
function: StandardConstructor,
|
||||
async_function: StandardConstructor,
|
||||
generator: StandardConstructor,
|
||||
generator_function: StandardConstructor,
|
||||
array: StandardConstructor,
|
||||
bigint: StandardConstructor,
|
||||
number: StandardConstructor,
|
||||
boolean: StandardConstructor,
|
||||
string: StandardConstructor,
|
||||
regexp: StandardConstructor,
|
||||
symbol: StandardConstructor,
|
||||
error: StandardConstructor,
|
||||
type_error: StandardConstructor,
|
||||
reference_error: StandardConstructor,
|
||||
range_error: StandardConstructor,
|
||||
syntax_error: StandardConstructor,
|
||||
eval_error: StandardConstructor,
|
||||
uri_error: StandardConstructor,
|
||||
aggregate_error: StandardConstructor,
|
||||
map: StandardConstructor,
|
||||
set: StandardConstructor,
|
||||
typed_array: StandardConstructor,
|
||||
typed_int8_array: StandardConstructor,
|
||||
typed_uint8_array: StandardConstructor,
|
||||
typed_uint8clamped_array: StandardConstructor,
|
||||
typed_int16_array: StandardConstructor,
|
||||
typed_uint16_array: StandardConstructor,
|
||||
typed_int32_array: StandardConstructor,
|
||||
typed_uint32_array: StandardConstructor,
|
||||
typed_bigint64_array: StandardConstructor,
|
||||
typed_biguint64_array: StandardConstructor,
|
||||
typed_float32_array: StandardConstructor,
|
||||
typed_float64_array: StandardConstructor,
|
||||
array_buffer: StandardConstructor,
|
||||
data_view: StandardConstructor,
|
||||
date_time_format: StandardConstructor,
|
||||
promise: StandardConstructor,
|
||||
}
|
||||
|
||||
impl Default for StandardConstructors {
|
||||
fn default() -> Self {
|
||||
let result = Self {
|
||||
object: StandardConstructor::default(),
|
||||
proxy: StandardConstructor::default(),
|
||||
date: StandardConstructor::default(),
|
||||
function: StandardConstructor::default(),
|
||||
async_function: StandardConstructor::default(),
|
||||
generator: StandardConstructor::default(),
|
||||
generator_function: StandardConstructor::default(),
|
||||
array: StandardConstructor::with_prototype(JsObject::from_proto_and_data(
|
||||
None,
|
||||
ObjectData::array(),
|
||||
)),
|
||||
bigint: StandardConstructor::default(),
|
||||
number: StandardConstructor::with_prototype(JsObject::from_proto_and_data(
|
||||
None,
|
||||
ObjectData::number(0.0),
|
||||
)),
|
||||
boolean: StandardConstructor::with_prototype(JsObject::from_proto_and_data(
|
||||
None,
|
||||
ObjectData::boolean(false),
|
||||
)),
|
||||
string: StandardConstructor::with_prototype(JsObject::from_proto_and_data(
|
||||
None,
|
||||
ObjectData::string("".into()),
|
||||
)),
|
||||
regexp: StandardConstructor::default(),
|
||||
symbol: StandardConstructor::default(),
|
||||
error: StandardConstructor::default(),
|
||||
type_error: StandardConstructor::default(),
|
||||
reference_error: StandardConstructor::default(),
|
||||
range_error: StandardConstructor::default(),
|
||||
syntax_error: StandardConstructor::default(),
|
||||
eval_error: StandardConstructor::default(),
|
||||
uri_error: StandardConstructor::default(),
|
||||
aggregate_error: StandardConstructor::default(),
|
||||
map: StandardConstructor::default(),
|
||||
set: StandardConstructor::default(),
|
||||
typed_array: StandardConstructor::default(),
|
||||
typed_int8_array: StandardConstructor::default(),
|
||||
typed_uint8_array: StandardConstructor::default(),
|
||||
typed_uint8clamped_array: StandardConstructor::default(),
|
||||
typed_int16_array: StandardConstructor::default(),
|
||||
typed_uint16_array: StandardConstructor::default(),
|
||||
typed_int32_array: StandardConstructor::default(),
|
||||
typed_uint32_array: StandardConstructor::default(),
|
||||
typed_bigint64_array: StandardConstructor::default(),
|
||||
typed_biguint64_array: StandardConstructor::default(),
|
||||
typed_float32_array: StandardConstructor::default(),
|
||||
typed_float64_array: StandardConstructor::default(),
|
||||
array_buffer: StandardConstructor::default(),
|
||||
data_view: StandardConstructor::default(),
|
||||
date_time_format: StandardConstructor::default(),
|
||||
promise: StandardConstructor::default(),
|
||||
};
|
||||
|
||||
// The value of `Array.prototype` is the Array prototype object.
|
||||
result.array.prototype.insert(
|
||||
"length",
|
||||
PropertyDescriptorBuilder::new()
|
||||
.value(0)
|
||||
.writable(true)
|
||||
.enumerable(false)
|
||||
.configurable(false)
|
||||
.build(),
|
||||
);
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl StandardConstructors {
|
||||
#[inline]
|
||||
pub fn object(&self) -> &StandardConstructor {
|
||||
&self.object
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn proxy(&self) -> &StandardConstructor {
|
||||
&self.proxy
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn date(&self) -> &StandardConstructor {
|
||||
&self.date
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn function(&self) -> &StandardConstructor {
|
||||
&self.function
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn async_function(&self) -> &StandardConstructor {
|
||||
&self.async_function
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn generator(&self) -> &StandardConstructor {
|
||||
&self.generator
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn generator_function(&self) -> &StandardConstructor {
|
||||
&self.generator_function
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn array(&self) -> &StandardConstructor {
|
||||
&self.array
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bigint_object(&self) -> &StandardConstructor {
|
||||
&self.bigint
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn number(&self) -> &StandardConstructor {
|
||||
&self.number
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn boolean(&self) -> &StandardConstructor {
|
||||
&self.boolean
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn string(&self) -> &StandardConstructor {
|
||||
&self.string
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn regexp(&self) -> &StandardConstructor {
|
||||
&self.regexp
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn symbol(&self) -> &StandardConstructor {
|
||||
&self.symbol
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn error(&self) -> &StandardConstructor {
|
||||
&self.error
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn reference_error(&self) -> &StandardConstructor {
|
||||
&self.reference_error
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn type_error(&self) -> &StandardConstructor {
|
||||
&self.type_error
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn range_error(&self) -> &StandardConstructor {
|
||||
&self.range_error
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn syntax_error(&self) -> &StandardConstructor {
|
||||
&self.syntax_error
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn eval_error(&self) -> &StandardConstructor {
|
||||
&self.eval_error
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn uri_error(&self) -> &StandardConstructor {
|
||||
&self.uri_error
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn aggregate_error(&self) -> &StandardConstructor {
|
||||
&self.aggregate_error
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn map(&self) -> &StandardConstructor {
|
||||
&self.map
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set(&self) -> &StandardConstructor {
|
||||
&self.set
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn typed_array(&self) -> &StandardConstructor {
|
||||
&self.typed_array
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn typed_int8_array(&self) -> &StandardConstructor {
|
||||
&self.typed_int8_array
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn typed_uint8_array(&self) -> &StandardConstructor {
|
||||
&self.typed_uint8_array
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn typed_uint8clamped_array(&self) -> &StandardConstructor {
|
||||
&self.typed_uint8clamped_array
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn typed_int16_array(&self) -> &StandardConstructor {
|
||||
&self.typed_int16_array
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn typed_uint16_array(&self) -> &StandardConstructor {
|
||||
&self.typed_uint16_array
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn typed_uint32_array(&self) -> &StandardConstructor {
|
||||
&self.typed_uint32_array
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn typed_int32_array(&self) -> &StandardConstructor {
|
||||
&self.typed_int32_array
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn typed_bigint64_array(&self) -> &StandardConstructor {
|
||||
&self.typed_bigint64_array
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn typed_biguint64_array(&self) -> &StandardConstructor {
|
||||
&self.typed_biguint64_array
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn typed_float32_array(&self) -> &StandardConstructor {
|
||||
&self.typed_float32_array
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn typed_float64_array(&self) -> &StandardConstructor {
|
||||
&self.typed_float64_array
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn array_buffer(&self) -> &StandardConstructor {
|
||||
&self.array_buffer
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn data_view(&self) -> &StandardConstructor {
|
||||
&self.data_view
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn date_time_format(&self) -> &StandardConstructor {
|
||||
&self.date_time_format
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn promise(&self) -> &StandardConstructor {
|
||||
&self.promise
|
||||
}
|
||||
}
|
||||
|
||||
/// Cached intrinsic objects
|
||||
#[derive(Debug, Default)]
|
||||
pub struct IntrinsicObjects {
|
||||
/// %ThrowTypeError% intrinsic object
|
||||
throw_type_error: JsObject,
|
||||
/// Cached iterator prototypes.
|
||||
iterator_prototypes: IteratorPrototypes,
|
||||
}
|
||||
|
||||
impl IntrinsicObjects {
|
||||
/// Initialize the intrinsic objects
|
||||
pub fn init(context: &mut Context) -> Self {
|
||||
Self {
|
||||
throw_type_error: create_throw_type_error(context),
|
||||
iterator_prototypes: IteratorPrototypes::init(context),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the `%ThrowTypeError%` intrinsic object
|
||||
#[inline]
|
||||
pub fn throw_type_error(&self) -> JsObject {
|
||||
self.throw_type_error.clone()
|
||||
}
|
||||
|
||||
/// Get the cached iterator prototypes.
|
||||
#[inline]
|
||||
pub fn iterator_prototypes(&self) -> &IteratorPrototypes {
|
||||
&self.iterator_prototypes
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,856 @@
|
||||
//! Javascript context.
|
||||
|
||||
pub mod intrinsics;
|
||||
|
||||
#[cfg(feature = "intl")]
|
||||
mod icu;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use intrinsics::{IntrinsicObjects, Intrinsics};
|
||||
|
||||
#[cfg(feature = "console")]
|
||||
use crate::builtins::console::Console;
|
||||
use crate::{
|
||||
builtins::{self, function::NativeFunctionSignature},
|
||||
bytecompiler::ByteCompiler,
|
||||
class::{Class, ClassBuilder},
|
||||
job::JobCallback,
|
||||
object::{FunctionBuilder, GlobalPropertyMap, JsObject, ObjectData},
|
||||
property::{Attribute, PropertyDescriptor, PropertyKey},
|
||||
realm::Realm,
|
||||
syntax::{ast::node::StatementList, parser::ParseError, Parser},
|
||||
vm::{CallFrame, CodeBlock, FinallyReturn, GeneratorResumeKind, Vm},
|
||||
JsResult, JsValue,
|
||||
};
|
||||
|
||||
use boa_gc::Gc;
|
||||
use boa_interner::{Interner, Sym};
|
||||
use boa_profiler::Profiler;
|
||||
|
||||
#[cfg(feature = "intl")]
|
||||
use icu_provider::DataError;
|
||||
|
||||
#[doc(inline)]
|
||||
#[cfg(all(feature = "intl", doc))]
|
||||
pub use icu::BoaProvider;
|
||||
|
||||
/// Javascript context. It is the primary way to interact with the runtime.
|
||||
///
|
||||
/// `Context`s constructed in a thread share the same runtime, therefore it
|
||||
/// is possible to share objects from one context to another context, but they
|
||||
/// have to be in the same thread.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ## Execute Function of Script File
|
||||
///
|
||||
/// ```rust
|
||||
/// use boa_engine::{
|
||||
/// Context,
|
||||
/// object::ObjectInitializer,
|
||||
/// property::{Attribute, PropertyDescriptor}
|
||||
/// };
|
||||
///
|
||||
/// let script = r#"
|
||||
/// function test(arg1) {
|
||||
/// if(arg1 != null) {
|
||||
/// return arg1.x;
|
||||
/// }
|
||||
/// return 112233;
|
||||
/// }
|
||||
/// "#;
|
||||
///
|
||||
/// let mut context = Context::default();
|
||||
///
|
||||
/// // Populate the script definition to the context.
|
||||
/// context.eval(script).unwrap();
|
||||
///
|
||||
/// // Create an object that can be used in eval calls.
|
||||
/// let arg = ObjectInitializer::new(&mut context)
|
||||
/// .property("x", 12, Attribute::READONLY)
|
||||
/// .build();
|
||||
/// context.register_global_property(
|
||||
/// "arg",
|
||||
/// arg,
|
||||
/// Attribute::all()
|
||||
/// );
|
||||
///
|
||||
/// let value = context.eval("test(arg)").unwrap();
|
||||
///
|
||||
/// assert_eq!(value.as_number(), Some(12.0))
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct Context {
|
||||
/// realm holds both the global object and the environment
|
||||
pub(crate) realm: Realm,
|
||||
|
||||
/// String interner in the context.
|
||||
interner: Interner,
|
||||
|
||||
/// console object state.
|
||||
#[cfg(feature = "console")]
|
||||
console: Console,
|
||||
|
||||
/// Intrinsic objects
|
||||
intrinsics: Intrinsics,
|
||||
|
||||
/// ICU related utilities
|
||||
#[cfg(feature = "intl")]
|
||||
icu: icu::Icu,
|
||||
|
||||
pub(crate) vm: Vm,
|
||||
|
||||
pub(crate) promise_job_queue: VecDeque<JobCallback>,
|
||||
}
|
||||
|
||||
impl Default for Context {
|
||||
fn default() -> Self {
|
||||
ContextBuilder::default().build()
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Create a new [`ContextBuilder`] to specify the [`Interner`] and/or
|
||||
/// the icu data provider.
|
||||
pub fn builder() -> ContextBuilder {
|
||||
ContextBuilder::default()
|
||||
}
|
||||
/// Gets the string interner.
|
||||
#[inline]
|
||||
pub fn interner(&self) -> &Interner {
|
||||
&self.interner
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the string interner.
|
||||
#[inline]
|
||||
pub fn interner_mut(&mut self) -> &mut Interner {
|
||||
&mut self.interner
|
||||
}
|
||||
|
||||
/// A helper function for getting an immutable reference to the `console` object.
|
||||
#[cfg(feature = "console")]
|
||||
pub(crate) fn console(&self) -> &Console {
|
||||
&self.console
|
||||
}
|
||||
|
||||
/// A helper function for getting a mutable reference to the `console` object.
|
||||
#[cfg(feature = "console")]
|
||||
#[inline]
|
||||
pub(crate) fn console_mut(&mut self) -> &mut Console {
|
||||
&mut self.console
|
||||
}
|
||||
|
||||
/// Sets up the default global objects within Global
|
||||
#[inline]
|
||||
fn create_intrinsics(&mut self) {
|
||||
let _timer = Profiler::global().start_event("create_intrinsics", "interpreter");
|
||||
// Create intrinsics, add global objects here
|
||||
builtins::init(self);
|
||||
}
|
||||
|
||||
/// Constructs an object with the `%Object.prototype%` prototype.
|
||||
#[inline]
|
||||
pub fn construct_object(&self) -> JsObject {
|
||||
JsObject::from_proto_and_data(
|
||||
self.intrinsics().constructors().object().prototype(),
|
||||
ObjectData::ordinary(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Parse the given source text.
|
||||
pub fn parse<S>(&mut self, src: S) -> Result<StatementList, ParseError>
|
||||
where
|
||||
S: AsRef<[u8]>,
|
||||
{
|
||||
let mut parser = Parser::new(src.as_ref());
|
||||
parser.parse_all(self)
|
||||
}
|
||||
|
||||
/// Parse the given source text with eval specific handling.
|
||||
pub(crate) fn parse_eval<S>(
|
||||
&mut self,
|
||||
src: S,
|
||||
direct: bool,
|
||||
strict: bool,
|
||||
) -> Result<StatementList, ParseError>
|
||||
where
|
||||
S: AsRef<[u8]>,
|
||||
{
|
||||
let mut parser = Parser::new(src.as_ref());
|
||||
if strict {
|
||||
parser.set_strict();
|
||||
}
|
||||
parser.parse_eval(direct, self)
|
||||
}
|
||||
|
||||
/// `Call ( F, V [ , argumentsList ] )`
|
||||
///
|
||||
/// The abstract operation `Call` takes arguments `F` (an ECMAScript language value) and `V`
|
||||
/// (an ECMAScript language value) and optional argument `argumentsList` (a `List` of
|
||||
/// ECMAScript language values) and returns either a normal completion containing an ECMAScript
|
||||
/// language value or a throw completion. It is used to call the `[[Call]]` internal method of
|
||||
/// a function object. `F` is the function object, `V` is an ECMAScript language value that is
|
||||
/// the `this` value of the `[[Call]]`, and `argumentsList` is the value passed to the
|
||||
/// corresponding argument of the internal method. If `argumentsList` is not present, a new
|
||||
/// empty `List` is used as its value.
|
||||
///
|
||||
/// More information:
|
||||
/// - [ECMA reference][spec]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#sec-call
|
||||
#[inline]
|
||||
pub(crate) fn call(
|
||||
&mut self,
|
||||
f: &JsValue,
|
||||
v: &JsValue,
|
||||
arguments_list: &[JsValue],
|
||||
) -> JsResult<JsValue> {
|
||||
// 1. If argumentsList is not present, set argumentsList to a new empty List.
|
||||
// 2. If IsCallable(F) is false, throw a TypeError exception.
|
||||
// 3. Return ? F.[[Call]](V, argumentsList).
|
||||
f.as_callable()
|
||||
.ok_or_else(|| self.construct_type_error("Value is not callable"))
|
||||
.and_then(|f| f.call(v, arguments_list, self))
|
||||
}
|
||||
|
||||
/// Return the global object.
|
||||
#[inline]
|
||||
pub fn global_object(&self) -> &JsObject {
|
||||
self.realm.global_object()
|
||||
}
|
||||
|
||||
/// Return a mutable reference to the global object string bindings.
|
||||
#[inline]
|
||||
pub(crate) fn global_bindings_mut(&mut self) -> &mut GlobalPropertyMap {
|
||||
self.realm.global_bindings_mut()
|
||||
}
|
||||
|
||||
/// Constructs a `Error` with the specified message.
|
||||
#[inline]
|
||||
pub fn construct_error<M>(&mut self, message: M) -> JsValue
|
||||
where
|
||||
M: Into<Box<str>>,
|
||||
{
|
||||
crate::builtins::error::Error::constructor(
|
||||
&self
|
||||
.intrinsics()
|
||||
.constructors()
|
||||
.error()
|
||||
.constructor()
|
||||
.into(),
|
||||
&[message.into().into()],
|
||||
self,
|
||||
)
|
||||
.expect("Into<String> used as message")
|
||||
}
|
||||
|
||||
/// Throws a `Error` with the specified message.
|
||||
#[inline]
|
||||
pub fn throw_error<M, R>(&mut self, message: M) -> JsResult<R>
|
||||
where
|
||||
M: Into<Box<str>>,
|
||||
{
|
||||
Err(self.construct_error(message))
|
||||
}
|
||||
|
||||
/// Constructs a `RangeError` with the specified message.
|
||||
#[inline]
|
||||
pub fn construct_range_error<M>(&mut self, message: M) -> JsValue
|
||||
where
|
||||
M: Into<Box<str>>,
|
||||
{
|
||||
crate::builtins::error::RangeError::constructor(
|
||||
&self
|
||||
.intrinsics()
|
||||
.constructors()
|
||||
.range_error()
|
||||
.constructor()
|
||||
.into(),
|
||||
&[message.into().into()],
|
||||
self,
|
||||
)
|
||||
.expect("Into<String> used as message")
|
||||
}
|
||||
|
||||
/// Throws a `RangeError` with the specified message.
|
||||
#[inline]
|
||||
pub fn throw_range_error<M, R>(&mut self, message: M) -> JsResult<R>
|
||||
where
|
||||
M: Into<Box<str>>,
|
||||
{
|
||||
Err(self.construct_range_error(message))
|
||||
}
|
||||
|
||||
/// Constructs a `TypeError` with the specified message.
|
||||
#[inline]
|
||||
pub fn construct_type_error<M>(&mut self, message: M) -> JsValue
|
||||
where
|
||||
M: Into<Box<str>>,
|
||||
{
|
||||
crate::builtins::error::TypeError::constructor(
|
||||
&self
|
||||
.intrinsics()
|
||||
.constructors()
|
||||
.type_error()
|
||||
.constructor()
|
||||
.into(),
|
||||
&[message.into().into()],
|
||||
self,
|
||||
)
|
||||
.expect("Into<String> used as message")
|
||||
}
|
||||
|
||||
/// Throws a `TypeError` with the specified message.
|
||||
#[inline]
|
||||
pub fn throw_type_error<M, R>(&mut self, message: M) -> JsResult<R>
|
||||
where
|
||||
M: Into<Box<str>>,
|
||||
{
|
||||
Err(self.construct_type_error(message))
|
||||
}
|
||||
|
||||
/// Constructs a `ReferenceError` with the specified message.
|
||||
#[inline]
|
||||
pub fn construct_reference_error<M>(&mut self, message: M) -> JsValue
|
||||
where
|
||||
M: Into<Box<str>>,
|
||||
{
|
||||
crate::builtins::error::ReferenceError::constructor(
|
||||
&self
|
||||
.intrinsics()
|
||||
.constructors()
|
||||
.reference_error()
|
||||
.constructor()
|
||||
.into(),
|
||||
&[message.into().into()],
|
||||
self,
|
||||
)
|
||||
.expect("Into<String> used as message")
|
||||
}
|
||||
|
||||
/// Throws a `ReferenceError` with the specified message.
|
||||
#[inline]
|
||||
pub fn throw_reference_error<M, R>(&mut self, message: M) -> JsResult<R>
|
||||
where
|
||||
M: Into<Box<str>>,
|
||||
{
|
||||
Err(self.construct_reference_error(message))
|
||||
}
|
||||
|
||||
/// Constructs a `SyntaxError` with the specified message.
|
||||
#[inline]
|
||||
pub fn construct_syntax_error<M>(&mut self, message: M) -> JsValue
|
||||
where
|
||||
M: Into<Box<str>>,
|
||||
{
|
||||
crate::builtins::error::SyntaxError::constructor(
|
||||
&self
|
||||
.intrinsics()
|
||||
.constructors()
|
||||
.syntax_error()
|
||||
.constructor()
|
||||
.into(),
|
||||
&[message.into().into()],
|
||||
self,
|
||||
)
|
||||
.expect("Into<String> used as message")
|
||||
}
|
||||
|
||||
/// Throws a `SyntaxError` with the specified message.
|
||||
#[inline]
|
||||
pub fn throw_syntax_error<M, R>(&mut self, message: M) -> JsResult<R>
|
||||
where
|
||||
M: Into<Box<str>>,
|
||||
{
|
||||
Err(self.construct_syntax_error(message))
|
||||
}
|
||||
|
||||
/// Constructs a `EvalError` with the specified message.
|
||||
pub fn construct_eval_error<M>(&mut self, message: M) -> JsValue
|
||||
where
|
||||
M: Into<Box<str>>,
|
||||
{
|
||||
crate::builtins::error::EvalError::constructor(
|
||||
&self
|
||||
.intrinsics()
|
||||
.constructors()
|
||||
.eval_error()
|
||||
.constructor()
|
||||
.into(),
|
||||
&[message.into().into()],
|
||||
self,
|
||||
)
|
||||
.expect("Into<String> used as message")
|
||||
}
|
||||
|
||||
/// Constructs a `URIError` with the specified message.
|
||||
pub fn construct_uri_error<M>(&mut self, message: M) -> JsValue
|
||||
where
|
||||
M: Into<Box<str>>,
|
||||
{
|
||||
crate::builtins::error::UriError::constructor(
|
||||
&self
|
||||
.intrinsics()
|
||||
.constructors()
|
||||
.uri_error()
|
||||
.constructor()
|
||||
.into(),
|
||||
&[message.into().into()],
|
||||
self,
|
||||
)
|
||||
.expect("Into<String> used as message")
|
||||
}
|
||||
|
||||
/// Throws a `EvalError` with the specified message.
|
||||
pub fn throw_eval_error<M, R>(&mut self, message: M) -> JsResult<R>
|
||||
where
|
||||
M: Into<Box<str>>,
|
||||
{
|
||||
Err(self.construct_eval_error(message))
|
||||
}
|
||||
|
||||
/// Throws a `URIError` with the specified message.
|
||||
pub fn throw_uri_error<M>(&mut self, message: M) -> JsResult<JsValue>
|
||||
where
|
||||
M: Into<Box<str>>,
|
||||
{
|
||||
Err(self.construct_uri_error(message))
|
||||
}
|
||||
|
||||
/// Register a global native function.
|
||||
///
|
||||
/// This is more efficient that creating a closure function, since this does not allocate,
|
||||
/// it is just a function pointer.
|
||||
///
|
||||
/// The function will be both `constructable` (call with `new`).
|
||||
///
|
||||
/// The function will be bound to the global object with `writable`, `non-enumerable`
|
||||
/// and `configurable` attributes. The same as when you create a function in JavaScript.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// If you want to make a function only `constructable`, or wish to bind it differently
|
||||
/// to the global object, you can create the function object with
|
||||
/// [`FunctionBuilder`](crate::object::FunctionBuilder::native). And bind it to the global
|
||||
/// object with [`Context::register_global_property`](Context::register_global_property)
|
||||
/// method.
|
||||
#[inline]
|
||||
pub fn register_global_function(
|
||||
&mut self,
|
||||
name: &str,
|
||||
length: usize,
|
||||
body: NativeFunctionSignature,
|
||||
) {
|
||||
let function = FunctionBuilder::native(self, body)
|
||||
.name(name)
|
||||
.length(length)
|
||||
.constructor(true)
|
||||
.build();
|
||||
|
||||
self.global_bindings_mut().insert(
|
||||
name.into(),
|
||||
PropertyDescriptor::builder()
|
||||
.value(function)
|
||||
.writable(true)
|
||||
.enumerable(false)
|
||||
.configurable(true)
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Register a global native function that is not a constructor.
|
||||
///
|
||||
/// This is more efficient that creating a closure function, since this does not allocate,
|
||||
/// it is just a function pointer.
|
||||
///
|
||||
/// The function will be bound to the global object with `writable`, `non-enumerable`
|
||||
/// and `configurable` attributes. The same as when you create a function in JavaScript.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The difference to [`Context::register_global_function`](Context::register_global_function) is,
|
||||
/// that the function will not be `constructable`.
|
||||
/// Usage of the function as a constructor will produce a `TypeError`.
|
||||
#[inline]
|
||||
pub fn register_global_builtin_function(
|
||||
&mut self,
|
||||
name: &str,
|
||||
length: usize,
|
||||
body: NativeFunctionSignature,
|
||||
) {
|
||||
let function = FunctionBuilder::native(self, body)
|
||||
.name(name)
|
||||
.length(length)
|
||||
.constructor(false)
|
||||
.build();
|
||||
|
||||
self.global_bindings_mut().insert(
|
||||
name.into(),
|
||||
PropertyDescriptor::builder()
|
||||
.value(function)
|
||||
.writable(true)
|
||||
.enumerable(false)
|
||||
.configurable(true)
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Register a global closure function.
|
||||
///
|
||||
/// The function will be both `constructable` (call with `new`).
|
||||
///
|
||||
/// The function will be bound to the global object with `writable`, `non-enumerable`
|
||||
/// and `configurable` attributes. The same as when you create a function in JavaScript.
|
||||
///
|
||||
/// # Note #1
|
||||
///
|
||||
/// If you want to make a function only `constructable`, or wish to bind it differently
|
||||
/// to the global object, you can create the function object with
|
||||
/// [`FunctionBuilder`](crate::object::FunctionBuilder::closure). And bind it to the global
|
||||
/// object with [`Context::register_global_property`](Context::register_global_property)
|
||||
/// method.
|
||||
///
|
||||
/// # Note #2
|
||||
///
|
||||
/// This function will only accept `Copy` closures, meaning you cannot
|
||||
/// move `Clone` types, just `Copy` types. If you need to move `Clone` types
|
||||
/// as captures, see [`FunctionBuilder::closure_with_captures`].
|
||||
///
|
||||
/// See <https://github.com/boa-dev/boa/issues/1515> for an explanation on
|
||||
/// why we need to restrict the set of accepted closures.
|
||||
#[inline]
|
||||
pub fn register_global_closure<F>(&mut self, name: &str, length: usize, body: F) -> JsResult<()>
|
||||
where
|
||||
F: Fn(&JsValue, &[JsValue], &mut Self) -> JsResult<JsValue> + Copy + 'static,
|
||||
{
|
||||
let function = FunctionBuilder::closure(self, body)
|
||||
.name(name)
|
||||
.length(length)
|
||||
.constructor(true)
|
||||
.build();
|
||||
|
||||
self.global_bindings_mut().insert(
|
||||
name.into(),
|
||||
PropertyDescriptor::builder()
|
||||
.value(function)
|
||||
.writable(true)
|
||||
.enumerable(false)
|
||||
.configurable(true)
|
||||
.build(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// <https://tc39.es/ecma262/#sec-hasproperty>
|
||||
#[inline]
|
||||
pub(crate) fn has_property(&mut self, obj: &JsValue, key: &PropertyKey) -> JsResult<bool> {
|
||||
if let Some(obj) = obj.as_object() {
|
||||
obj.__has_property__(key, self)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a global class of type `T`, where `T` implements `Class`.
|
||||
///
|
||||
/// # Example
|
||||
/// ```ignore
|
||||
/// #[derive(Debug, Trace, Finalize)]
|
||||
/// struct MyClass;
|
||||
///
|
||||
/// impl Class for MyClass {
|
||||
/// // ...
|
||||
/// }
|
||||
///
|
||||
/// context.register_global_class::<MyClass>();
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn register_global_class<T>(&mut self) -> JsResult<()>
|
||||
where
|
||||
T: Class,
|
||||
{
|
||||
let mut class_builder = ClassBuilder::new::<T>(self);
|
||||
T::init(&mut class_builder)?;
|
||||
|
||||
let class = class_builder.build();
|
||||
let property = PropertyDescriptor::builder()
|
||||
.value(class)
|
||||
.writable(T::ATTRIBUTES.writable())
|
||||
.enumerable(T::ATTRIBUTES.enumerable())
|
||||
.configurable(T::ATTRIBUTES.configurable())
|
||||
.build();
|
||||
|
||||
self.global_bindings_mut().insert(T::NAME.into(), property);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Register a global property.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use boa_engine::{
|
||||
/// Context,
|
||||
/// property::{Attribute, PropertyDescriptor},
|
||||
/// object::ObjectInitializer
|
||||
/// };
|
||||
///
|
||||
/// let mut context = Context::default();
|
||||
///
|
||||
/// context.register_global_property(
|
||||
/// "myPrimitiveProperty",
|
||||
/// 10,
|
||||
/// Attribute::all()
|
||||
/// );
|
||||
///
|
||||
/// let object = ObjectInitializer::new(&mut context)
|
||||
/// .property(
|
||||
/// "x",
|
||||
/// 0,
|
||||
/// Attribute::all()
|
||||
/// )
|
||||
/// .property(
|
||||
/// "y",
|
||||
/// 1,
|
||||
/// Attribute::all()
|
||||
/// )
|
||||
/// .build();
|
||||
/// context.register_global_property(
|
||||
/// "myObjectProperty",
|
||||
/// object,
|
||||
/// Attribute::all()
|
||||
/// );
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn register_global_property<K, V>(&mut self, key: K, value: V, attribute: Attribute)
|
||||
where
|
||||
K: Into<PropertyKey>,
|
||||
V: Into<JsValue>,
|
||||
{
|
||||
self.realm.global_property_map.insert(
|
||||
&key.into(),
|
||||
PropertyDescriptor::builder()
|
||||
.value(value)
|
||||
.writable(attribute.writable())
|
||||
.enumerable(attribute.enumerable())
|
||||
.configurable(attribute.configurable())
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Evaluates the given code by compiling down to bytecode, then interpreting the bytecode into a value
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
///# use boa_engine::Context;
|
||||
/// let mut context = Context::default();
|
||||
///
|
||||
/// let value = context.eval("1 + 3").unwrap();
|
||||
///
|
||||
/// assert!(value.is_number());
|
||||
/// assert_eq!(value.as_number().unwrap(), 4.0);
|
||||
/// ```
|
||||
#[allow(clippy::unit_arg, clippy::drop_copy)]
|
||||
pub fn eval<S>(&mut self, src: S) -> JsResult<JsValue>
|
||||
where
|
||||
S: AsRef<[u8]>,
|
||||
{
|
||||
let main_timer = Profiler::global().start_event("Evaluation", "Main");
|
||||
|
||||
let parsing_result = Parser::new(src.as_ref())
|
||||
.parse_all(self)
|
||||
.map_err(|e| e.to_string());
|
||||
|
||||
let statement_list = match parsing_result {
|
||||
Ok(statement_list) => statement_list,
|
||||
Err(e) => return self.throw_syntax_error(e),
|
||||
};
|
||||
|
||||
let code_block = self.compile(&statement_list)?;
|
||||
let result = self.execute(code_block);
|
||||
|
||||
// The main_timer needs to be dropped before the Profiler is.
|
||||
drop(main_timer);
|
||||
Profiler::global().drop();
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Compile the AST into a `CodeBlock` ready to be executed by the VM.
|
||||
#[inline]
|
||||
pub fn compile(&mut self, statement_list: &StatementList) -> JsResult<Gc<CodeBlock>> {
|
||||
let _timer = Profiler::global().start_event("Compilation", "Main");
|
||||
let mut compiler = ByteCompiler::new(Sym::MAIN, statement_list.strict(), self);
|
||||
compiler.create_declarations(statement_list.items())?;
|
||||
compiler.compile_statement_list(statement_list.items(), true)?;
|
||||
Ok(Gc::new(compiler.finish()))
|
||||
}
|
||||
|
||||
/// Compile the AST into a `CodeBlock` with an additional declarative environment.
|
||||
#[inline]
|
||||
pub(crate) fn compile_with_new_declarative(
|
||||
&mut self,
|
||||
statement_list: &StatementList,
|
||||
strict: bool,
|
||||
) -> JsResult<Gc<CodeBlock>> {
|
||||
let _timer = Profiler::global().start_event("Compilation", "Main");
|
||||
let mut compiler = ByteCompiler::new(Sym::MAIN, statement_list.strict(), self);
|
||||
compiler.compile_statement_list_with_new_declarative(
|
||||
statement_list.items(),
|
||||
true,
|
||||
strict || statement_list.strict(),
|
||||
)?;
|
||||
Ok(Gc::new(compiler.finish()))
|
||||
}
|
||||
|
||||
/// Call the VM with a `CodeBlock` and return the result.
|
||||
///
|
||||
/// Since this function receives a `Gc<CodeBlock>`, cloning the code is very cheap, since it's
|
||||
/// just a pointer copy. Therefore, if you'd like to execute the same `CodeBlock` multiple
|
||||
/// times, there is no need to re-compile it, and you can just call `clone()` on the
|
||||
/// `Gc<CodeBlock>` returned by the [`Self::compile()`] function.
|
||||
#[inline]
|
||||
pub fn execute(&mut self, code_block: Gc<CodeBlock>) -> JsResult<JsValue> {
|
||||
let _timer = Profiler::global().start_event("Execution", "Main");
|
||||
|
||||
self.vm.push_frame(CallFrame {
|
||||
code: code_block,
|
||||
pc: 0,
|
||||
catch: Vec::new(),
|
||||
finally_return: FinallyReturn::None,
|
||||
finally_jump: Vec::new(),
|
||||
pop_on_return: 0,
|
||||
loop_env_stack: Vec::from([0]),
|
||||
try_env_stack: Vec::from([crate::vm::TryStackEntry {
|
||||
num_env: 0,
|
||||
num_loop_stack_entries: 0,
|
||||
}]),
|
||||
param_count: 0,
|
||||
arg_count: 0,
|
||||
generator_resume_kind: GeneratorResumeKind::Normal,
|
||||
thrown: false,
|
||||
});
|
||||
|
||||
self.realm.set_global_binding_number();
|
||||
let result = self.run();
|
||||
self.vm.pop_frame();
|
||||
self.run_queued_jobs()?;
|
||||
let (result, _) = result?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Runs all the jobs in the job queue.
|
||||
fn run_queued_jobs(&mut self) -> JsResult<()> {
|
||||
while let Some(job) = self.promise_job_queue.pop_front() {
|
||||
job.call_job_callback(&JsValue::Undefined, &[], self)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Return the intrinsic constructors and objects.
|
||||
#[inline]
|
||||
pub fn intrinsics(&self) -> &Intrinsics {
|
||||
&self.intrinsics
|
||||
}
|
||||
|
||||
/// Set the value of trace on the context
|
||||
pub fn set_trace(&mut self, trace: bool) {
|
||||
self.vm.trace = trace;
|
||||
}
|
||||
|
||||
#[cfg(feature = "intl")]
|
||||
#[inline]
|
||||
/// Get the ICU related utilities
|
||||
pub(crate) fn icu(&self) -> &icu::Icu {
|
||||
&self.icu
|
||||
}
|
||||
|
||||
/// More information:
|
||||
/// - [ECMAScript reference][spec]
|
||||
///
|
||||
/// [spec]: https://tc39.es/ecma262/#sec-hostenqueuepromisejob
|
||||
pub fn host_enqueue_promise_job(&mut self, job: JobCallback /* , realm: Realm */) {
|
||||
// If realm is not null ...
|
||||
// TODO
|
||||
// Let scriptOrModule be ...
|
||||
// TODO
|
||||
self.promise_job_queue.push_back(job);
|
||||
}
|
||||
}
|
||||
/// Builder for the [`Context`] type.
|
||||
///
|
||||
/// This builder allows custom initialization of the [`Interner`] within
|
||||
/// the context.
|
||||
/// Additionally, if the `intl` feature is enabled, [`ContextBuilder`] becomes
|
||||
/// the only way to create a new [`Context`], since now it requires a
|
||||
/// valid data provider for the `Intl` functionality.
|
||||
///
|
||||
#[cfg_attr(
|
||||
feature = "intl",
|
||||
doc = "The required data in a valid provider is specified in [`BoaProvider`]"
|
||||
)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ContextBuilder {
|
||||
interner: Option<Interner>,
|
||||
#[cfg(feature = "intl")]
|
||||
icu: Option<icu::Icu>,
|
||||
}
|
||||
|
||||
impl ContextBuilder {
|
||||
/// Initializes the context [`Interner`] to the provided interner.
|
||||
///
|
||||
/// This is useful when you want to initialize an [`Interner`] with
|
||||
/// a collection of words before parsing.
|
||||
#[must_use]
|
||||
pub fn interner(mut self, interner: Interner) -> Self {
|
||||
self.interner = Some(interner);
|
||||
self
|
||||
}
|
||||
|
||||
/// Provides an icu data provider to the [`Context`].
|
||||
///
|
||||
/// This function is only available if the `intl` feature is enabled.
|
||||
#[cfg(any(feature = "intl", docs))]
|
||||
pub fn icu_provider(mut self, provider: Box<dyn icu::BoaProvider>) -> Result<Self, DataError> {
|
||||
self.icu = Some(icu::Icu::new(provider)?);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Creates a new [`ContextBuilder`] with a default empty [`Interner`]
|
||||
/// and a default [`BoaProvider`] if the `intl` feature is enabled.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Builds a new [`Context`] with the provided parameters, and defaults
|
||||
/// all missing parameters to their default values.
|
||||
pub fn build(self) -> Context {
|
||||
let mut context = Context {
|
||||
realm: Realm::create(),
|
||||
interner: self.interner.unwrap_or_default(),
|
||||
#[cfg(feature = "console")]
|
||||
console: Console::default(),
|
||||
intrinsics: Intrinsics::default(),
|
||||
vm: Vm {
|
||||
frames: Vec::with_capacity(16),
|
||||
stack: Vec::with_capacity(1024),
|
||||
trace: false,
|
||||
stack_size_limit: 1024,
|
||||
},
|
||||
#[cfg(feature = "intl")]
|
||||
icu: self.icu.unwrap_or_else(|| {
|
||||
// TODO: Replace with a more fitting default
|
||||
icu::Icu::new(Box::new(icu_testdata::get_provider()))
|
||||
.expect("Failed to initialize default icu data.")
|
||||
}),
|
||||
promise_job_queue: VecDeque::new(),
|
||||
};
|
||||
|
||||
// Add new builtIns to Context Realm
|
||||
// At a later date this can be removed from here and called explicitly,
|
||||
// but for now we almost always want these default builtins
|
||||
context.intrinsics.objects = IntrinsicObjects::init(&mut context);
|
||||
context.create_intrinsics();
|
||||
context
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user