瀏覽代碼

Use latest test262 suite and fix/implement accordingly (#1497)

Marko Lahma 2 年之前
父節點
當前提交
fbaad9f476

+ 2 - 1
Jint.Tests.Test262/Test262Harness.settings.json

@@ -1,10 +1,11 @@
 {
-  "SuiteGitSha": "83a46bfe0e79aed8274a1b9f4beb0a2efa0b3533",
+  "SuiteGitSha": "9704d7f22f6342d6c4753ab9a8d62d6725de8c4e",
   //"SuiteDirectory": "//mnt/c/work/test262",
   "TargetPath": "./Generated",
   "Namespace": "Jint.Tests.Test262",
   "Parallel": true,
   "ExcludedFeatures": [
+    "Array.fromAsync",
     "async-iteration",
     "Atomics",
     "class-fields-private",

+ 1 - 1
Jint/Native/Array/ArrayInstance.cs

@@ -1187,7 +1187,7 @@ namespace Jint.Native.Array
         /// <inheritdoc />
         internal sealed override bool FindWithCallback(
             JsValue[] arguments,
-            out uint index,
+            out ulong index,
             out JsValue value,
             bool visitUnassigned,
             bool fromEnd = false)

+ 18 - 1
Jint/Native/ArrayBuffer/ArrayBufferPrototype.cs

@@ -26,10 +26,11 @@ namespace Jint.Native.ArrayBuffer
         protected override void Initialize()
         {
             const PropertyFlag lengthFlags = PropertyFlag.Configurable;
-            var properties = new PropertyDictionary(3, checkExistingKeys: false)
+            var properties = new PropertyDictionary(4, checkExistingKeys: false)
             {
                 ["byteLength"] = new GetSetPropertyDescriptor(new ClrFunctionInstance(_engine, "get byteLength", ByteLength, 0, lengthFlags), Undefined, PropertyFlag.Configurable),
                 ["constructor"] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
+                ["detached"] = new GetSetPropertyDescriptor(new ClrFunctionInstance(_engine, "get detached", Detached, 0, lengthFlags), Undefined, PropertyFlag.Configurable),
                 ["slice"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "slice", Slice, 2, lengthFlags), PropertyFlag.Configurable | PropertyFlag.Writable)
             };
             SetProperties(properties);
@@ -41,6 +42,22 @@ namespace Jint.Native.ArrayBuffer
             SetSymbols(symbols);
         }
 
+        private JsValue Detached(JsValue thisObj, JsValue[] arguments)
+        {
+            var o = thisObj as ArrayBufferInstance;
+            if (o is null)
+            {
+                ExceptionHelper.ThrowTypeError(_realm, "Method ArrayBuffer.prototype.detached called on incompatible receiver " + thisObj);
+            }
+
+            if (o.IsSharedArrayBuffer)
+            {
+                ExceptionHelper.ThrowTypeError(_realm);
+            }
+
+            return o.IsDetachedBuffer;
+        }
+
         /// <summary>
         /// https://tc39.es/ecma262/#sec-get-arraybuffer.prototype.bytelength
         /// </summary>

+ 36 - 13
Jint/Native/Object/ObjectInstance.cs

@@ -1046,22 +1046,22 @@ namespace Jint.Native.Object
         /// </summary>
         internal virtual bool FindWithCallback(
             JsValue[] arguments,
-            out uint index,
+            out ulong index,
             out JsValue value,
             bool visitUnassigned,
             bool fromEnd = false)
         {
-            long GetLength()
+            ulong GetLength()
             {
                 var descValue = Get(CommonProperties.Length);
                 var len = TypeConverter.ToNumber(descValue);
 
-                return (long) System.Math.Max(
+                return (ulong) System.Math.Max(
                     0,
                     System.Math.Min(len, ArrayOperations.MaxArrayLikeLength));
             }
 
-            bool TryGetValue(uint idx, out JsValue jsValue)
+            bool TryGetValue(ulong idx, out JsValue jsValue)
             {
                 var property = JsString.Create(idx);
                 var kPresent = HasProperty(property);
@@ -1083,18 +1083,41 @@ namespace Jint.Native.Object
 
             var args = _engine._jsValueArrayPool.RentArray(3);
             args[2] = this;
-            for (uint k = 0; k < length; k++)
+
+            if (!fromEnd)
             {
-                if (TryGetValue(k, out var kvalue) || visitUnassigned)
+                for (ulong k = 0; k < length; k++)
                 {
-                    args[0] = kvalue;
-                    args[1] = k;
-                    var testResult = callable.Call(thisArg, args);
-                    if (TypeConverter.ToBoolean(testResult))
+                    if (TryGetValue(k, out var kvalue) || visitUnassigned)
                     {
-                        index = k;
-                        value = kvalue;
-                        return true;
+                        args[0] = kvalue;
+                        args[1] = k;
+                        var testResult = callable.Call(thisArg, args);
+                        if (TypeConverter.ToBoolean(testResult))
+                        {
+                            index = k;
+                            value = kvalue;
+                            return true;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                for (ulong k = length - 1; k >= 0; k--)
+                {
+                    if (TryGetValue(k, out var kvalue) || visitUnassigned)
+                    {
+                        kvalue ??= Undefined;
+                        args[0] = kvalue;
+                        args[1] = k;
+                        var testResult = callable.Call(thisArg, args);
+                        if (TypeConverter.ToBoolean(testResult))
+                        {
+                            index = k;
+                            value = kvalue;
+                            return true;
+                        }
                     }
                 }
             }

+ 95 - 9
Jint/Native/String/StringPrototype.cs

@@ -1,6 +1,7 @@
 using System.Runtime.CompilerServices;
 using System.Text;
 using Jint.Collections;
+using Jint.Native.Json;
 using Jint.Native.Object;
 using Jint.Native.RegExp;
 using Jint.Native.Symbol;
@@ -39,7 +40,7 @@ namespace Jint.Native.String
 
             var trimStart = new PropertyDescriptor(new ClrFunctionInstance(Engine, "trimStart", TrimStart, 0, lengthFlags), propertyFlags);
             var trimEnd = new PropertyDescriptor(new ClrFunctionInstance(Engine, "trimEnd", TrimEnd, 0, lengthFlags), propertyFlags);
-            var properties = new PropertyDictionary(35, checkExistingKeys: false)
+            var properties = new PropertyDictionary(37, checkExistingKeys: false)
             {
                 ["constructor"] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
                 ["toString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toString", ToStringString, 0, lengthFlags), propertyFlags),
@@ -77,6 +78,8 @@ namespace Jint.Native.String
                 ["normalize"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "normalize", Normalize, 0, lengthFlags), propertyFlags),
                 ["repeat"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "repeat", Repeat, 1, lengthFlags), propertyFlags),
                 ["at"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "at", At, 1, lengthFlags), propertyFlags),
+                ["isWellFormed"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "isWellFormed", IsWellFormed, 0, lengthFlags), propertyFlags),
+                ["toWellFormed"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toWellFormed", ToWellFormed, 0, lengthFlags), propertyFlags),
             };
             SetProperties(properties);
 
@@ -862,16 +865,36 @@ namespace Jint.Native.String
                 return Undefined;
             }
 
-            var first = (long) s[position];
-            if (first >= 0xD800 && first <= 0xDBFF && s.Length > position + 1)
+            return CodePointAt(s, position).CodePoint;
+        }
+
+        private readonly record struct CodePointResult(int CodePoint, int CodeUnitCount, bool IsUnpairedSurrogate);
+
+        private static CodePointResult CodePointAt(string s, int position)
+        {
+            var size = s.Length;
+            var first = s.CharCodeAt(position);
+            var cp = s.CharCodeAt(position);
+
+            var firstIsLeading = char.IsHighSurrogate(first);
+            var firstIsTrailing = char.IsLowSurrogate(first);
+            if (!firstIsLeading && !firstIsTrailing)
             {
-                long second = s[position + 1];
-                if (second >= 0xDC00 && second <= 0xDFFF)
-                {
-                    return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
-                }
+                return new CodePointResult(cp, 1, false);
+            }
+
+            if (firstIsTrailing || position + 1 == size)
+            {
+                return new CodePointResult(cp, 1, true);
+            }
+
+            var second = s.CharCodeAt(position + 1);
+            if (!char.IsLowSurrogate(second))
+            {
+                return new CodePointResult(cp, 1, true);
             }
-            return first;
+
+            return new CodePointResult(char.ConvertToUtf32(first, second), 2, false);
         }
 
         private JsValue CharAt(JsValue thisObj, JsValue[] arguments)
@@ -1121,5 +1144,68 @@ namespace Jint.Native.String
 
             return sb.ToString();
         }
+
+        private JsValue IsWellFormed(JsValue thisObj, JsValue[] arguments)
+        {
+            TypeConverter.CheckObjectCoercible(_engine, thisObj);
+            var s = TypeConverter.ToString(thisObj);
+
+            return IsStringWellFormedUnicode(s);
+        }
+
+        private JsValue ToWellFormed(JsValue thisObj, JsValue[] arguments)
+        {
+            TypeConverter.CheckObjectCoercible(_engine, thisObj);
+            var s = TypeConverter.ToString(thisObj);
+
+            var strLen = s.Length;
+            var k = 0;
+
+            using var builder = StringBuilderPool.Rent();
+            var result = builder.Builder;
+            while (k < strLen)
+            {
+                var cp = CodePointAt(s, k);
+                if (cp.IsUnpairedSurrogate)
+                {
+                    result.Append("\uFFFD");
+                }
+                else
+                {
+                    result.Append(s, k, cp.CodeUnitCount);
+                }
+                k += cp.CodeUnitCount;
+            }
+
+            return result.ToString();
+        }
+
+        private static bool IsStringWellFormedUnicode(string s)
+        {
+            for (var i = 0; i < s.Length; ++i)
+            {
+                var isSurrogate = (s.CharCodeAt(i) & 0xF800) == 0xD800;
+                if (!isSurrogate)
+                {
+                    continue;
+                }
+
+                var isLeadingSurrogate = s.CharCodeAt(i) < 0xDC00;
+                if (!isLeadingSurrogate)
+                {
+                    return false; // unpaired trailing surrogate
+                }
+
+                var isFollowedByTrailingSurrogate = i + 1 < s.Length && (s.CharCodeAt(i + 1) & 0xFC00) == 0xDC00;
+                if (!isFollowedByTrailingSurrogate)
+                {
+                    return false; // unpaired leading surrogate
+                }
+
+                ++i;
+            }
+
+            return true;
+        }
     }
 }