LibJS: Implement Error.isError

Implementing the stage 2.7 proposal:

https://github.com/tc39/proposal-is-error
This commit is contained in:
Shannon Booth 2024-11-10 05:59:08 +13:00 committed by Andrew Kaster
parent 4b93e27698
commit e4891af970
Notes: github-actions[bot] 2024-11-09 20:27:43 +00:00
6 changed files with 57 additions and 0 deletions

View file

@ -311,6 +311,7 @@ namespace JS {
P(is) \
P(isArray) \
P(isDisjointFrom) \
P(isError) \
P(isExtensible) \
P(isFinite) \
P(isFrozen) \

View file

@ -27,6 +27,9 @@ void ErrorConstructor::initialize(Realm& realm)
define_direct_property(vm.names.prototype, realm.intrinsics().error_prototype(), 0);
define_direct_property(vm.names.length, Value(1), Attribute::Configurable);
u8 attr = Attribute::Writable | Attribute::Configurable;
define_native_function(realm, vm.names.isError, is_error, 1, attr);
}
// 20.5.1.1 Error ( message [ , options ] ), https://tc39.es/ecma262/#sec-error-message
@ -120,4 +123,13 @@ ThrowCompletionOr<NonnullGCPtr<Object>> ErrorConstructor::construct(FunctionObje
JS_ENUMERATE_NATIVE_ERRORS
#undef __JS_ENUMERATE
// 20.5.2.1 Error.isError ( arg ), https://tc39.es/proposal-is-error/#sec-error.iserror
JS_DEFINE_NATIVE_FUNCTION(ErrorConstructor::is_error)
{
auto arg = vm.argument(0);
// 1. Return IsError(arg).
return Value(arg.is_error());
}
}

View file

@ -26,6 +26,8 @@ private:
explicit ErrorConstructor(Realm&);
virtual bool has_constructor() const override { return true; }
JS_DECLARE_NATIVE_FUNCTION(is_error);
};
#define DECLARE_NATIVE_ERROR_CONSTRUCTOR(ClassName, snake_name, PrototypeName, ConstructorName) \

View file

@ -257,6 +257,15 @@ Array& Value::as_array()
return static_cast<Array&>(as_object());
}
// 20.5.8.2 IsError ( argument ), https://tc39.es/proposal-is-error/#sec-iserror
bool Value::is_error() const
{
// 1. If argument is not an Object, return false.
// 2. If argument has an [[ErrorData]] internal slot, return true.
// 3. Return false.
return is_object() && is<Error>(as_object());
}
// 7.2.3 IsCallable ( argument ), https://tc39.es/ecma262/#sec-iscallable
bool Value::is_function() const
{

View file

@ -148,6 +148,7 @@ public:
ThrowCompletionOr<bool> is_array(VM&) const;
bool is_function() const;
bool is_constructor() const;
bool is_error() const;
ThrowCompletionOr<bool> is_regexp(VM&) const;
bool is_nan() const

View file

@ -0,0 +1,32 @@
test("Error.isError length is 1", () => {
expect(Error.isError).toHaveLength(1);
});
test("Error.isError arguments that evaluate to false", () => {
expect(Error.isError()).toBeFalse();
expect(Error.isError("1")).toBeFalse();
expect(Error.isError("foo")).toBeFalse();
expect(Error.isError(1)).toBeFalse();
expect(Error.isError(1, 2, 3)).toBeFalse();
expect(Error.isError(undefined)).toBeFalse();
expect(Error.isError(null)).toBeFalse();
expect(Error.isError(Infinity)).toBeFalse();
expect(Error.isError({})).toBeFalse();
});
test("Error.isError arguments that evaluate to true", () => {
expect(Error.isError(new Error())).toBeTrue();
expect(Error.isError(new EvalError())).toBeTrue();
expect(Error.isError(new RangeError())).toBeTrue();
expect(Error.isError(new ReferenceError())).toBeTrue();
expect(Error.isError(new SyntaxError())).toBeTrue();
expect(Error.isError(new TypeError())).toBeTrue();
expect(Error.isError(new URIError())).toBeTrue();
expect(Error.isError(new SuppressedError())).toBeTrue();
class MySuppressedError extends SuppressedError {}
expect(Error.isError(new MySuppressedError())).toBeTrue();
class MyTypeError extends TypeError {}
expect(Error.isError(new MyTypeError())).toBeTrue();
});