Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,15 @@
use crate::{
ecmascript::{
Agent, ArgumentsList, BUILTIN_STRING_MEMORY, Behaviour, Builtin,
BuiltinIntrinsicConstructor, Error, ExceptionType, Function, JsResult, Object,
PropertyDescriptor, PropertyKey, ProtoIntrinsics, Realm, String, Value,
builders::BuiltinFunctionBuilder, create_array_from_scoped_list, define_property_or_throw,
get_iterator, iterator_to_list, ordinary_create_from_constructor, throw_not_callable,
to_string,
BuiltinIntrinsicConstructor, ErrorConstructor, ExceptionType, InternalMethods, JsResult,
Object, PropertyDescriptor, Realm, String, Value, builders::BuiltinFunctionBuilder,
create_array_from_scoped_list, get_iterator, iterator_to_list, throw_not_callable,
unwrap_try,
},
engine::{Bindable, GcScope, Scopable},
heap::{ArenaAccessMut, IntrinsicConstructorIndexes},
heap::IntrinsicConstructorIndexes,
};

use super::error_constructor::get_error_cause;

pub(crate) struct AggregateErrorConstructor;
impl Builtin for AggregateErrorConstructor {
const NAME: String<'static> = BUILTIN_STRING_MEMORY.AggregateError;
Expand All @@ -38,45 +35,17 @@ impl AggregateErrorConstructor {
mut gc: GcScope<'gc, '_>,
) -> JsResult<'gc, Value<'gc>> {
let errors = arguments.get(0).scope(agent, gc.nogc());
let message = arguments.get(1).scope(agent, gc.nogc());
let options = arguments.get(2);
// 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
let new_target = new_target.map_or_else(
|| agent.running_execution_context().function.unwrap(),
|new_target| Function::try_from(new_target).unwrap(),
);
// 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%AggregateError.prototype%", « [[ErrorData]] »).
let o = ordinary_create_from_constructor(
let message = arguments.get(1).bind(gc.nogc());
let options = arguments.get(2).bind(gc.nogc());
let o = ErrorConstructor::base_constructor(
agent,
new_target.unbind(),
ProtoIntrinsics::AggregateError,
ExceptionType::AggregateError,
ArgumentsList::from_mut_slice(&mut [message.unbind(), options.unbind()]),
new_target,
gc.reborrow(),
)
.unbind()?
.bind(gc.nogc());
let o = Error::try_from(o.unbind()).unwrap();
// 3. If message is not undefined, then
let message = message.get(agent).bind(gc.nogc());
let message = if !message.is_undefined() {
// a. Let msg be ? ToString(message).
Some(
to_string(agent, message.unbind(), gc.reborrow())
.unbind()?
.scope(agent, gc.nogc()),
)
} else {
None
};
// 4. Perform ? InstallErrorCause(O, options).
let cause = get_error_cause(agent, options, gc.reborrow())
.unbind()?
.bind(gc.nogc());
// b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg).
let message = message.map(|message| message.get(agent).bind(gc.nogc()));
let heap_data = o.get_mut(agent);
heap_data.kind = ExceptionType::AggregateError;
heap_data.message = message.unbind();
heap_data.cause = cause.unbind();
.scope(agent, gc.nogc());
// 5. Let errorsList be ? IteratorToList(? GetIterator(errors, sync)).
let Some(iterator_record) = get_iterator(agent, errors.get(agent), false, gc.reborrow())
.unbind()?
Expand All @@ -85,33 +54,25 @@ impl AggregateErrorConstructor {
else {
return Err(throw_not_callable(agent, gc.into_nogc()));
};
let errors_list = iterator_to_list(agent, iterator_record.unbind(), gc.reborrow())
.unbind()?
.bind(gc.nogc());
let errors_list =
iterator_to_list(agent, iterator_record.unbind(), gc.reborrow()).unbind()?;
let gc = gc.into_nogc();
let o = unsafe { o.take(agent) }.bind(gc);
// 6. Perform ! DefinePropertyOrThrow(O, "errors", PropertyDescriptor {
let property_descriptor = PropertyDescriptor {
// [[Configurable]]: true,
configurable: Some(true),
// [[Enumerable]]: false,
enumerable: Some(false),
// [[Writable]]: true,
writable: Some(true),
// [[Value]]: CreateArrayFromList(errorsList)
value: Some(
create_array_from_scoped_list(agent, errors_list, gc.nogc())
.unbind()
.into(),
),
..Default::default()
};
define_property_or_throw(
// [[Configurable]]: true,
// [[Enumerable]]: false,
// [[Writable]]: true,
// [[Value]]: CreateArrayFromList(errorsList)
let property_descriptor = PropertyDescriptor::non_enumerable_data_descriptor(
create_array_from_scoped_list(agent, errors_list, gc),
);
unwrap_try(o.try_define_own_property(
agent,
o.unbind(),
PropertyKey::from(BUILTIN_STRING_MEMORY.errors),
BUILTIN_STRING_MEMORY.errors.into(),
property_descriptor,
gc.reborrow(),
)
.unbind()?;
None,
gc,
));
// }).
// 7. Return O.
Ok(o.into())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ use crate::engine::NoGcScope;
use crate::{
ecmascript::{
Agent, ArgumentsList, BUILTIN_STRING_MEMORY, Behaviour, Builtin,
BuiltinIntrinsicConstructor, Error, ExceptionType, Function, JsResult, Object, PropertyKey,
ProtoIntrinsics, Realm, String, Value, builders::BuiltinFunctionBuilder, get, has_property,
ordinary_create_from_constructor, to_string,
BuiltinIntrinsicConstructor, Error, ErrorHeapData, ExceptionType, Function,
InternalMethods, JsResult, Object, PropertyDescriptor, PropertyKey, ProtoIntrinsics, Realm,
String, Value, builders::BuiltinFunctionBuilder, get, has_property,
ordinary_populate_from_constructor, to_string, unwrap_try,
},
engine::{Bindable, GcScope, Scopable},
heap::{ArenaAccessMut, IntrinsicConstructorIndexes},
heap::{CreateHeapData, IntrinsicConstructorIndexes},
};

pub(crate) struct ErrorConstructor;
Expand All @@ -39,74 +40,126 @@ impl Builtin for ErrorIsError {
}

impl ErrorConstructor {
/// ### [20.5.1.1 Error ( message \[ , options \] )](https://tc39.es/ecma262/#sec-error-message)
fn constructor<'gc>(
/// ### [20.5.6.1.1 NativeError ( message \[ , options \] )](https://tc39.es/ecma262/#sec-nativeerror)
pub(crate) fn base_constructor<'gc>(
agent: &mut Agent,
_this_value: Value,
error_kind: ExceptionType,
arguments: ArgumentsList,
new_target: Option<Object>,
mut gc: GcScope<'gc, '_>,
) -> JsResult<'gc, Value<'gc>> {
let message = arguments.get(0).bind(gc.nogc());
let mut options = arguments.get(1).bind(gc.nogc());
let mut new_target = new_target.bind(gc.nogc());
) -> JsResult<'gc, Error<'gc>> {
let nogc = gc.nogc();
let scoped_message = arguments.get(0).scope(agent, nogc);
let options = arguments.get(1).scope(agent, nogc);
let new_target = new_target.bind(nogc);

let intrinsic = match error_kind {
ExceptionType::Error => ProtoIntrinsics::Error,
ExceptionType::AggregateError => ProtoIntrinsics::AggregateError,
ExceptionType::EvalError => ProtoIntrinsics::EvalError,
ExceptionType::RangeError => ProtoIntrinsics::RangeError,
ExceptionType::ReferenceError => ProtoIntrinsics::ReferenceError,
ExceptionType::SyntaxError => ProtoIntrinsics::SyntaxError,
ExceptionType::TypeError => ProtoIntrinsics::TypeError,
ExceptionType::UriError => ProtoIntrinsics::URIError,
};

// 1. If NewTarget is undefined, let newTarget be the active function
// object; else let newTarget be NewTarget.
let new_target = new_target.map_or_else(
|| agent.running_execution_context().function.unwrap(),
|new_target| Function::try_from(new_target).unwrap(),
);
// 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%NativeError.prototype%", « [[ErrorData]] »).
let o = agent
.heap
// b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg).
.create(ErrorHeapData::new(error_kind, None, None))
.bind(gc.nogc());
let o = ordinary_populate_from_constructor(
agent,
o.unbind().into(),
new_target.unbind(),
intrinsic,
gc.reborrow(),
)
.unbind()?
.bind(gc.nogc());
let mut o = Error::try_from(o).unwrap();

// SAFETY: not shared.
let message = unsafe { scoped_message.take(agent) }.bind(gc.nogc());

// 3. If message is not undefined, then
let message = if let Ok(message) = String::try_from(message) {
Some(message.scope(agent, gc.nogc()))
let msg = if let Ok(msg) = String::try_from(message) {
Some(msg)
} else if !message.is_undefined() {
let scoped_o = o.scope(agent, gc.nogc());
// a. Let msg be ? ToString(message).
let scoped_options = options.scope(agent, gc.nogc());
let scoped_new_target = new_target.map(|n| n.scope(agent, gc.nogc()));
let message = to_string(agent, message.unbind(), gc.reborrow())
let ms = to_string(agent, message.unbind(), gc.reborrow())
.unbind()?
.scope(agent, gc.nogc());
// SAFETY: Never shared.
unsafe {
new_target = scoped_new_target.map(|n| n.take(agent)).bind(gc.nogc());
options = scoped_options.take(agent).bind(gc.nogc());
}
Some(message)
.bind(gc.nogc());
// SAFETY: not shared.
o = unsafe { scoped_o.take(agent) }.bind(gc.nogc());
Some(ms)
} else {
None
};

// 3. If message is not undefined, then
if let Some(msg) = msg {
// b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg).
unwrap_try(o.try_define_own_property(
agent,
BUILTIN_STRING_MEMORY.message.into(),
PropertyDescriptor::non_enumerable_data_descriptor(msg),
None,
gc.nogc(),
));
}

// SAFETY: not shared.
let options = unsafe { options.take(agent) }.bind(gc.nogc());

// 4. Perform ? InstallErrorCause(O, options).
let cause = if !options.is_object() {
None
} else {
let scoped_new_target = new_target.map(|n| n.scope(agent, gc.nogc()));
let scoped_o = o.scope(agent, gc.nogc());
let cause = get_error_cause(agent, options.unbind(), gc.reborrow())
.unbind()?
.bind(gc.nogc());
// SAFETY: Never shared.
new_target = unsafe { scoped_new_target.map(|n| n.take(agent)).bind(gc.nogc()) };
cause.map(|c| c.scope(agent, gc.nogc()))
// SAFETY: not shared.
o = unsafe { scoped_o.take(agent) }.bind(gc.nogc());
cause
};
// 1. If options is an Object and ? HasProperty(options, "cause") is
// true, then
if let Some(cause) = cause {
// b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "cause", cause).
unwrap_try(o.try_define_own_property(
agent,
BUILTIN_STRING_MEMORY.cause.into(),
PropertyDescriptor::non_enumerable_data_descriptor(cause),
None,
gc.nogc(),
));
}

// 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
let new_target = new_target.map_or_else(
|| agent.running_execution_context().function.unwrap(),
|new_target| Function::try_from(new_target).unwrap(),
);
// 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%Error.prototype%", « [[ErrorData]] »).
let o = ordinary_create_from_constructor(
agent,
new_target.unbind(),
ProtoIntrinsics::Error,
gc.reborrow(),
)
.unbind()?
.bind(gc.into_nogc());
let o = Error::try_from(o).unwrap();
// b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg).
let message = message.map(|message| message.get(agent));
let cause = cause.map(|c| c.get(agent));
let heap_data = o.get_mut(agent);
heap_data.kind = ExceptionType::Error;
heap_data.message = message;
heap_data.cause = cause;
// 5. Return O.
Ok(o.into())
Ok(o.unbind())
}

/// ### [20.5.1.1 Error ( message \[ , options \] )](https://tc39.es/ecma262/#sec-error-message)
fn constructor<'gc>(
agent: &mut Agent,
_this_value: Value,
arguments: ArgumentsList,
new_target: Option<Object>,
gc: GcScope<'gc, '_>,
) -> JsResult<'gc, Value<'gc>> {
Self::base_constructor(agent, ExceptionType::Error, arguments, new_target, gc)
.map(Value::from)
}

#[cfg(feature = "proposal-is-error")]
Expand Down
Loading