diff --git a/Jint.Tests.Test262/Test262Harness.settings.json b/Jint.Tests.Test262/Test262Harness.settings.json
index 91af0acb29..75eed76e51 100644
--- a/Jint.Tests.Test262/Test262Harness.settings.json
+++ b/Jint.Tests.Test262/Test262Harness.settings.json
@@ -1,5 +1,5 @@
{
- "SuiteGitSha": "d62fa93c8f9ce5e687c0bbaa5d2b59670ab2ff60",
+ "SuiteGitSha": "b0f03cb22d8b9233347782d166e7793d4d4c757f",
//"SuiteDirectory": "//mnt/c/work/test262",
"TargetPath": "./Generated",
"Namespace": "Jint.Tests.Test262",
@@ -9,8 +9,12 @@
"async-iteration",
"Atomics",
"decorators",
+ "Error.isError",
"explicit-resource-management",
+ "import-defer",
"iterator-helpers",
+ "iterator-sequencing",
+ "json-parse-with-source",
"regexp-lookbehind",
"regexp-modifiers",
"regexp-unicode-property-escapes",
@@ -29,6 +33,14 @@
],
"ExcludedFiles": [
+ // requires rewrite of destructing towards spec
+ "language/destructuring/binding/keyed-destructuring-property-reference-target-evaluation-order-with-bindings.js",
+ "language/expressions/assignment/destructuring/keyed-destructuring-property-reference-target-evaluation-order-with-bindings.js",
+
+ // Acornima doesn't implement unicode 15/16 yet
+ "language/identifiers/*-unicode-15.*.js",
+ "language/identifiers/*-unicode-16.*.js",
+
// Currently quite impossible to detect if assignment target is CoverParenthesizedExpression
"language/expressions/assignment/fn-name-lhs-cover.js",
@@ -106,6 +118,7 @@
"built-ins/GeneratorPrototype/return/try-finally-nested-try-catch-within-outer-try-after-nested.js",
"built-ins/GeneratorPrototype/return/try-finally-nested-try-catch-within-outer-try-before-nested.js",
"built-ins/GeneratorPrototype/return/try-finally-nested-try-catch-within-outer-try-before-nested.js",
+ "built-ins/GeneratorPrototype/return/try-finally-set-property-within-try.js",
"built-ins/GeneratorPrototype/return/try-finally-within-finally.js",
"built-ins/GeneratorPrototype/return/try-finally-within-finally.js",
"built-ins/GeneratorPrototype/return/try-finally-within-try.js",
diff --git a/Jint.Tests.Test262/Test262Test.cs b/Jint.Tests.Test262/Test262Test.cs
index e0ae188798..565027b956 100644
--- a/Jint.Tests.Test262/Test262Test.cs
+++ b/Jint.Tests.Test262/Test262Test.cs
@@ -8,7 +8,7 @@ namespace Jint.Tests.Test262;
public abstract partial class Test262Test
{
- private Engine BuildTestExecutor(Test262File file)
+ private static Engine BuildTestExecutor(Test262File file)
{
var engine = new Engine(cfg =>
{
diff --git a/Jint/Engine.cs b/Jint/Engine.cs
index 40bf799dd6..932ed400ca 100644
--- a/Jint/Engine.cs
+++ b/Jint/Engine.cs
@@ -704,7 +704,7 @@ internal void PutValue(Reference reference, JsValue value)
var succeeded = baseObject.Set(reference.ReferencedName, value, reference.ThisValue);
if (!succeeded && reference.Strict)
{
- ExceptionHelper.ThrowTypeError(Realm, "Cannot assign to read only property '" + property + "' of " + baseObject);
+ ExceptionHelper.ThrowTypeError(Realm, $"Cannot assign to read only property '{property}' of {baseObject}");
}
}
else
@@ -906,18 +906,21 @@ internal Reference ResolveBinding(string name, Environment? env = null)
private static Reference GetIdentifierReference(Environment? env, string name, bool strict)
{
- if (env is null)
+ Key key = name;
+ while (true)
{
- return new Reference(JsValue.Undefined, name, strict);
- }
+ if (env is null)
+ {
+ return new Reference(JsValue.Undefined, name, strict);
+ }
- var envRec = env;
- if (envRec.HasBinding(name))
- {
- return new Reference(envRec, name, strict);
- }
+ if (env.HasBinding(key))
+ {
+ return new Reference(env, name, strict);
+ }
- return GetIdentifierReference(env._outerEnv, name, strict);
+ env = env._outerEnv;
+ }
}
///
diff --git a/Jint/Native/FinalizationRegistry/FinalizationRegistryPrototype.cs b/Jint/Native/FinalizationRegistry/FinalizationRegistryPrototype.cs
index 3ec8fb96e9..f032195d60 100644
--- a/Jint/Native/FinalizationRegistry/FinalizationRegistryPrototype.cs
+++ b/Jint/Native/FinalizationRegistry/FinalizationRegistryPrototype.cs
@@ -29,7 +29,9 @@ protected override void Initialize()
const PropertyFlag PropertyFlags = PropertyFlag.NonEnumerable;
var properties = new PropertyDictionary(4, checkExistingKeys: false)
{
- [KnownKeys.Constructor] = new(_constructor, PropertyFlag.NonEnumerable), ["register"] = new(new ClrFunction(Engine, "register", Register, 2, PropertyFlag.Configurable), PropertyFlags), ["unregister"] = new(new ClrFunction(Engine, "unregister", Unregister, 1, PropertyFlag.Configurable), PropertyFlags), ["cleanupSome"] = new(new ClrFunction(Engine, "cleanupSome", CleanupSome, 0, PropertyFlag.Configurable), PropertyFlags),
+ [KnownKeys.Constructor] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
+ ["register"] = new PropertyDescriptor(new ClrFunction(Engine, "register", Register, 2, PropertyFlag.Configurable), PropertyFlags),
+ ["unregister"] = new PropertyDescriptor(new ClrFunction(Engine, "unregister", Unregister, 1, PropertyFlag.Configurable), PropertyFlags),
};
SetProperties(properties);
@@ -88,21 +90,6 @@ private JsValue Unregister(JsValue thisObject, JsValue[] arguments)
return finalizationRegistry.Remove(unregisterToken);
}
- private JsValue CleanupSome(JsValue thisObject, JsValue[] arguments)
- {
- var finalizationRegistry = AssertFinalizationRegistryInstance(thisObject);
- var callback = arguments.At(0);
-
- if (!callback.IsUndefined() && callback is not ICallable)
- {
- ExceptionHelper.ThrowTypeError(_realm, callback + " must be callable");
- }
-
- FinalizationRegistryInstance.CleanupFinalizationRegistry(callback as ICallable);
-
- return Undefined;
- }
-
private FinalizationRegistryInstance AssertFinalizationRegistryInstance(JsValue thisObject)
{
if (thisObject is FinalizationRegistryInstance finalizationRegistryInstance)
diff --git a/Jint/Native/JsTypedArray.cs b/Jint/Native/JsTypedArray.cs
index 2df1b56d60..c9b8f0baa4 100644
--- a/Jint/Native/JsTypedArray.cs
+++ b/Jint/Native/JsTypedArray.cs
@@ -58,6 +58,38 @@ internal override uint GetLength()
return record.IsTypedArrayOutOfBounds ? 0 : record.TypedArrayLength;
}
+ public override bool PreventExtensions()
+ {
+ if (!IsTypedArrayFixedLength)
+ {
+ return false;
+ }
+
+ return base.PreventExtensions();
+ }
+
+ ///
+ /// https://tc39.es/ecma262/#sec-istypedarrayfixedlength
+ ///
+ private bool IsTypedArrayFixedLength
+ {
+ get
+ {
+ if (_arrayLength == LengthAuto)
+ {
+ return false;
+ }
+
+ var buffer = _viewedArrayBuffer;
+ if (!buffer.IsFixedLengthArrayBuffer && !buffer.IsSharedArrayBuffer)
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+
internal override bool IsArrayLike => true;
internal override bool IsIntegerIndexedArray => true;
diff --git a/Jint/Native/Object/ObjectConstructor.cs b/Jint/Native/Object/ObjectConstructor.cs
index e3724023e8..92e5a2c53b 100644
--- a/Jint/Native/Object/ObjectConstructor.cs
+++ b/Jint/Native/Object/ObjectConstructor.cs
@@ -109,7 +109,7 @@ private JsValue Entries(JsValue thisObject, JsValue[] arguments)
private JsValue FromEntries(JsValue thisObject, JsValue[] arguments)
{
var iterable = arguments.At(0);
- TypeConverter.CheckObjectCoercible(_engine, iterable);
+ TypeConverter.RequireObjectCoercible(_engine, iterable);
var obj = _realm.Intrinsics.Object.Construct(0);
@@ -206,7 +206,7 @@ public JsValue GetPrototypeOf(JsValue thisObject, JsValue[] arguments)
private JsValue SetPrototypeOf(JsValue thisObject, JsValue[] arguments)
{
var oArg = arguments.At(0);
- TypeConverter.CheckObjectCoercible(_engine, oArg);
+ TypeConverter.RequireObjectCoercible(_engine, oArg);
var prototype = arguments.At(1);
if (!prototype.IsObject() && !prototype.IsNull())
@@ -214,7 +214,7 @@ private JsValue SetPrototypeOf(JsValue thisObject, JsValue[] arguments)
ExceptionHelper.ThrowTypeError(_realm, $"Object prototype may only be an Object or null: {prototype}");
}
- if (!(oArg is ObjectInstance o))
+ if (oArg is not ObjectInstance o)
{
return oArg;
}
diff --git a/Jint/Native/Object/ObjectInstance.cs b/Jint/Native/Object/ObjectInstance.cs
index 2f6d6bf839..2afc454187 100644
--- a/Jint/Native/Object/ObjectInstance.cs
+++ b/Jint/Native/Object/ObjectInstance.cs
@@ -1217,6 +1217,9 @@ internal bool IsConcatSpreadable
internal virtual uint GetLength() => (uint) TypeConverter.ToLength(Get(CommonProperties.Length));
+ ///
+ /// https://tc39.es/ecma262/#sec-ordinarypreventextensions
+ ///
public virtual bool PreventExtensions()
{
Extensible = false;
diff --git a/Jint/Native/Object/ObjectPrototype.cs b/Jint/Native/Object/ObjectPrototype.cs
index df841e1a70..623005aed8 100644
--- a/Jint/Native/Object/ObjectPrototype.cs
+++ b/Jint/Native/Object/ObjectPrototype.cs
@@ -38,7 +38,7 @@ protected override void Initialize()
new ClrFunction(Engine, "get __proto__", (thisObject, _) => TypeConverter.ToObject(_realm, thisObject).GetPrototypeOf() ?? Null, 0, LengthFlags),
new ClrFunction(Engine, "set __proto__", (thisObject, arguments) =>
{
- TypeConverter.CheckObjectCoercible(_engine, thisObject);
+ TypeConverter.RequireObjectCoercible(_engine, thisObject);
var proto = arguments.At(0);
if (!proto.IsObject() && !proto.IsNull() || thisObject is not ObjectInstance objectInstance)
diff --git a/Jint/Native/String/StringPrototype.cs b/Jint/Native/String/StringPrototype.cs
index c1a13ec06c..91fb71574a 100644
--- a/Jint/Native/String/StringPrototype.cs
+++ b/Jint/Native/String/StringPrototype.cs
@@ -100,7 +100,7 @@ protected override void Initialize()
private ObjectInstance Iterator(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(_engine, thisObject);
+ TypeConverter.RequireObjectCoercible(_engine, thisObject);
var str = TypeConverter.ToString(thisObject);
return _realm.Intrinsics.StringIteratorPrototype.Construct(str);
}
@@ -195,7 +195,7 @@ internal static string TrimEx(string s)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private JsValue Trim(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var s = TypeConverter.ToJsString(thisObject);
if (s.Length == 0 || (!IsWhiteSpaceEx(s[0]) && !IsWhiteSpaceEx(s[s.Length - 1])))
{
@@ -209,7 +209,7 @@ private JsValue Trim(JsValue thisObject, JsValue[] arguments)
///
private JsValue TrimStart(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var s = TypeConverter.ToJsString(thisObject);
if (s.Length == 0 || !IsWhiteSpaceEx(s[0]))
{
@@ -223,7 +223,7 @@ private JsValue TrimStart(JsValue thisObject, JsValue[] arguments)
///
private JsValue TrimEnd(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var s = TypeConverter.ToJsString(thisObject);
if (s.Length == 0 || !IsWhiteSpaceEx(s[s.Length - 1]))
{
@@ -234,7 +234,7 @@ private JsValue TrimEnd(JsValue thisObject, JsValue[] arguments)
private JsValue ToLocaleUpperCase(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(_engine, thisObject);
+ TypeConverter.RequireObjectCoercible(_engine, thisObject);
var s = TypeConverter.ToString(thisObject);
var culture = CultureInfo.InvariantCulture;
if (arguments.Length > 0 && arguments[0].IsString())
@@ -266,21 +266,21 @@ private JsValue ToLocaleUpperCase(JsValue thisObject, JsValue[] arguments)
private JsValue ToUpperCase(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(_engine, thisObject);
+ TypeConverter.RequireObjectCoercible(_engine, thisObject);
var s = TypeConverter.ToString(thisObject);
return new JsString(s.ToUpperInvariant());
}
private JsValue ToLocaleLowerCase(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(_engine, thisObject);
+ TypeConverter.RequireObjectCoercible(_engine, thisObject);
var s = TypeConverter.ToString(thisObject);
return new JsString(s.ToLower(CultureInfo.InvariantCulture));
}
private JsValue ToLowerCase(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(_engine, thisObject);
+ TypeConverter.RequireObjectCoercible(_engine, thisObject);
var s = TypeConverter.ToString(thisObject);
return s.ToLowerInvariant();
}
@@ -308,7 +308,7 @@ private static int ToIntegerSupportInfinityUnlikely(JsValue numberVal)
private JsValue Substring(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var s = TypeConverter.ToString(thisObject);
var start = TypeConverter.ToNumber(arguments.At(0));
@@ -377,7 +377,7 @@ private static JsValue Substr(JsValue thisObject, JsValue[] arguments)
///
private JsValue Split(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var separator = arguments.At(0);
var limit = arguments.At(1);
@@ -470,7 +470,7 @@ internal static JsValue SplitWithStringSeparator(Realm realm, JsValue separator,
///
private JsValue At(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(_engine, thisObject);
+ TypeConverter.RequireObjectCoercible(_engine, thisObject);
var start = arguments.At(0);
var o = thisObject.ToString();
@@ -498,7 +498,7 @@ private JsValue At(JsValue thisObject, JsValue[] arguments)
private JsValue Slice(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var start = TypeConverter.ToNumber(arguments.At(0));
if (double.IsNegativeInfinity(start))
@@ -539,7 +539,7 @@ private JsValue Slice(JsValue thisObject, JsValue[] arguments)
private JsValue Search(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var regex = arguments.At(0);
if (regex is ObjectInstance oi)
@@ -561,7 +561,7 @@ private JsValue Search(JsValue thisObject, JsValue[] arguments)
///
private JsValue Replace(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var searchValue = arguments.At(0);
var replaceValue = arguments.At(1);
@@ -613,7 +613,7 @@ private JsValue Replace(JsValue thisObject, JsValue[] arguments)
///
private JsValue ReplaceAll(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var searchValue = arguments.At(0);
var replaceValue = arguments.At(1);
@@ -623,7 +623,7 @@ private JsValue ReplaceAll(JsValue thisObject, JsValue[] arguments)
if (searchValue.IsRegExp())
{
var flags = searchValue.Get(RegExpPrototype.PropertyFlags);
- TypeConverter.CheckObjectCoercible(_engine, flags);
+ TypeConverter.RequireObjectCoercible(_engine, flags);
if (!TypeConverter.ToString(flags).Contains('g'))
{
ExceptionHelper.ThrowTypeError(_realm, "String.prototype.replaceAll called with a non-global RegExp argument");
@@ -708,7 +708,7 @@ static int StringIndexOf(string s, string search, int fromIndex)
private JsValue Match(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var regex = arguments.At(0);
if (regex is ObjectInstance oi)
@@ -728,7 +728,7 @@ private JsValue Match(JsValue thisObject, JsValue[] arguments)
private JsValue MatchAll(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(_engine, thisObject);
+ TypeConverter.RequireObjectCoercible(_engine, thisObject);
var regex = arguments.At(0);
if (!regex.IsNullOrUndefined())
@@ -736,7 +736,7 @@ private JsValue MatchAll(JsValue thisObject, JsValue[] arguments)
if (regex.IsRegExp())
{
var flags = regex.Get(RegExpPrototype.PropertyFlags);
- TypeConverter.CheckObjectCoercible(_engine, flags);
+ TypeConverter.RequireObjectCoercible(_engine, flags);
if (!TypeConverter.ToString(flags).Contains('g'))
{
ExceptionHelper.ThrowTypeError(_realm);
@@ -757,7 +757,7 @@ private JsValue MatchAll(JsValue thisObject, JsValue[] arguments)
private JsValue LocaleCompare(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var s = TypeConverter.ToString(thisObject);
var that = TypeConverter.ToString(arguments.At(0));
@@ -777,7 +777,7 @@ private JsValue LocaleCompare(JsValue thisObject, JsValue[] arguments)
///
private JsValue LastIndexOf(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var jsString = TypeConverter.ToJsString(thisObject);
var searchStr = TypeConverter.ToString(arguments.At(0));
@@ -833,7 +833,7 @@ private JsValue LastIndexOf(JsValue thisObject, JsValue[] arguments)
///
private JsValue IndexOf(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var s = TypeConverter.ToJsString(thisObject);
var searchStr = TypeConverter.ToString(arguments.At(0));
@@ -858,7 +858,7 @@ private JsValue IndexOf(JsValue thisObject, JsValue[] arguments)
private JsValue Concat(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
if (thisObject is not JsString jsString)
{
@@ -879,7 +879,7 @@ private JsValue Concat(JsValue thisObject, JsValue[] arguments)
private JsValue CharCodeAt(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
JsValue pos = arguments.Length > 0 ? arguments[0] : 0;
var s = TypeConverter.ToJsString(thisObject);
@@ -896,7 +896,7 @@ private JsValue CharCodeAt(JsValue thisObject, JsValue[] arguments)
///
private JsValue CodePointAt(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
JsValue pos = arguments.Length > 0 ? arguments[0] : 0;
var s = TypeConverter.ToString(thisObject);
@@ -941,7 +941,7 @@ private static CodePointResult CodePointAt(string s, int position)
private JsValue CharAt(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var s = TypeConverter.ToJsString(thisObject);
var position = TypeConverter.ToInteger(arguments.At(0));
var size = s.Length;
@@ -989,7 +989,7 @@ private JsValue PadEnd(JsValue thisObject, JsValue[] arguments)
///
private JsValue StringPad(JsValue thisObject, JsValue[] arguments, bool padStart)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var s = TypeConverter.ToJsString(thisObject);
var targetLength = TypeConverter.ToInt32(arguments.At(0));
@@ -1020,7 +1020,7 @@ private JsValue StringPad(JsValue thisObject, JsValue[] arguments, bool padStart
///
private JsValue StartsWith(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var s = TypeConverter.ToJsString(thisObject);
@@ -1052,7 +1052,7 @@ private JsValue StartsWith(JsValue thisObject, JsValue[] arguments)
///
private JsValue EndsWith(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var s = TypeConverter.ToJsString(thisObject);
@@ -1083,7 +1083,7 @@ private JsValue EndsWith(JsValue thisObject, JsValue[] arguments)
///
private JsValue Includes(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var s = TypeConverter.ToJsString(thisObject);
var searchString = arguments.At(0);
@@ -1115,7 +1115,7 @@ private JsValue Includes(JsValue thisObject, JsValue[] arguments)
private JsValue Normalize(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var str = TypeConverter.ToString(thisObject);
var param = arguments.At(0);
@@ -1156,7 +1156,7 @@ private JsValue Normalize(JsValue thisObject, JsValue[] arguments)
///
private JsValue Repeat(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(Engine, thisObject);
+ TypeConverter.RequireObjectCoercible(Engine, thisObject);
var s = TypeConverter.ToString(thisObject);
var count = arguments.At(0);
@@ -1188,7 +1188,7 @@ private JsValue Repeat(JsValue thisObject, JsValue[] arguments)
private JsValue IsWellFormed(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(_engine, thisObject);
+ TypeConverter.RequireObjectCoercible(_engine, thisObject);
var s = TypeConverter.ToString(thisObject);
return IsStringWellFormedUnicode(s);
@@ -1196,7 +1196,7 @@ private JsValue IsWellFormed(JsValue thisObject, JsValue[] arguments)
private JsValue ToWellFormed(JsValue thisObject, JsValue[] arguments)
{
- TypeConverter.CheckObjectCoercible(_engine, thisObject);
+ TypeConverter.RequireObjectCoercible(_engine, thisObject);
var s = TypeConverter.ToString(thisObject);
var strLen = s.Length;
diff --git a/Jint/Runtime/Environments/ObjectEnvironment.cs b/Jint/Runtime/Environments/ObjectEnvironment.cs
index 731b20a848..695aadaa72 100644
--- a/Jint/Runtime/Environments/ObjectEnvironment.cs
+++ b/Jint/Runtime/Environments/ObjectEnvironment.cs
@@ -27,27 +27,13 @@ public ObjectEnvironment(
_withEnvironment = withEnvironment;
}
- internal override bool HasBinding(Key name)
- {
- var property = new JsString(name.Name);
- var foundBinding = _bindingObject.HasProperty(property);
+ internal override bool HasBinding(Key name) => HasBinding(JsString.Create(name.Name));
- if (!foundBinding)
- {
- return false;
- }
+ internal override bool HasBinding(BindingName name) => HasBinding(name.Value);
- if (!_withEnvironment)
- {
- return true;
- }
-
- return !IsBlocked(property);
- }
-
- internal override bool HasBinding(BindingName name)
+ private bool HasBinding(JsString nameValue)
{
- var foundBinding = _bindingObject.HasProperty(name.Value);
+ var foundBinding = _bindingObject.HasProperty(nameValue);
if (!foundBinding)
{
@@ -59,7 +45,7 @@ internal override bool HasBinding(BindingName name)
return true;
}
- return !IsBlocked(name.Value);
+ return !IsBlocked(nameValue);
}
internal override bool TryGetBinding(BindingName name, bool strict, [NotNullWhen(true)] out JsValue? value)
@@ -77,14 +63,17 @@ internal override bool TryGetBinding(BindingName name, bool strict, [NotNullWhen
return false;
}
- value = _bindingObject.Get(name.Value);
-
- if (strict && value.IsUndefined() && !_bindingObject.HasProperty(name.Value))
+ if (!_bindingObject.HasProperty(name.Value))
{
- // data was deleted during reading of unscopable information, of course...
- ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Key);
+ if (strict)
+ {
+ // data was deleted during reading of unscopable information, of course...
+ ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Key);
+ }
}
+ value = _bindingObject.Get(name.Value);
+
return true;
}
@@ -129,32 +118,41 @@ internal override void CreateImmutableBinding(Key name, bool strict = true)
internal override void SetMutableBinding(Key name, JsValue value, bool strict)
{
var jsString = new JsString(name);
- if (strict && !_bindingObject.HasProperty(jsString))
+ if (!_bindingObject.HasProperty(jsString))
{
- ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name);
+ if (strict)
+ {
+ ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name);
+ }
}
- _bindingObject.Set(jsString, value);
+ _bindingObject.Set(jsString, value, strict);
}
internal override void SetMutableBinding(BindingName name, JsValue value, bool strict)
{
- if (strict && !_bindingObject.HasProperty(name.Value))
+ if (!_bindingObject.HasProperty(name.Value))
{
- ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Key);
+ if (strict)
+ {
+ ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Key);
+ }
}
- _bindingObject.Set(name.Value, value);
+ _bindingObject.Set(name.Value, value, strict);
}
internal override JsValue GetBindingValue(Key name, bool strict)
{
- if (!_bindingObject.TryGetValue(name.Name, out var value) && strict)
+ if (!_bindingObject.HasProperty(name.Name))
{
- ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Name);
+ if (strict)
+ {
+ ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Name);
+ }
}
- return value;
+ return _bindingObject.Get(name.Name);
}
internal override bool DeleteBinding(Key name) => _bindingObject.Delete(name.Name);
diff --git a/Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs b/Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs
index cf71a3ca47..c3e04451f3 100644
--- a/Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs
+++ b/Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs
@@ -210,7 +210,7 @@ private JsValue EvaluateJsValue(EvaluationContext context)
{
if (r.IsSuperReference)
{
- ExceptionHelper.ThrowReferenceError(engine.Realm, r);
+ ExceptionHelper.ThrowReferenceError(engine.Realm, "Unsupported reference to 'super'");
}
var o = TypeConverter.ToObject(engine.Realm, r.Base);
@@ -315,4 +315,4 @@ internal static bool TryOperatorOverloading(EvaluationContext context, JsValue v
result = null;
return false;
}
-}
\ No newline at end of file
+}
diff --git a/Jint/Runtime/TypeConverter.cs b/Jint/Runtime/TypeConverter.cs
index bbca3b175f..568457e2cc 100644
--- a/Jint/Runtime/TypeConverter.cs
+++ b/Jint/Runtime/TypeConverter.cs
@@ -1032,11 +1032,17 @@ private static void ThrowMemberNullOrUndefinedError(
.SetJavaScriptCallstack(engine, sourceNode.Location, overwriteExisting: true);
}
- public static void CheckObjectCoercible(Engine engine, JsValue o)
+ [Obsolete("Use TypeConverter.RequireObjectCoercible")]
+ public static void CheckObjectCoercible(Engine engine, JsValue o) => RequireObjectCoercible(engine, o);
+
+ ///
+ /// https://tc39.es/ecma262/#sec-requireobjectcoercible
+ ///
+ public static void RequireObjectCoercible(Engine engine, JsValue o)
{
if (o._type < InternalTypes.Boolean)
{
- ExceptionHelper.ThrowTypeError(engine.Realm, "Cannot call method on " + o);
+ ExceptionHelper.ThrowTypeError(engine.Realm, $"Cannot call method on {o}");
}
}
}