Jelajahi Sumber

Add import.meta support (#1173)

Marko Lahma 3 tahun lalu
induk
melakukan
05ddb01022

+ 6 - 3
Jint.Tests.Test262/Test262Harness.settings.json

@@ -22,7 +22,6 @@
     "generators",
     "hashbang",
     "import-assertions",
-    "import.meta",
     "numeric-separator-literal",
     "Promise.allSettled",
     "Promise.any",
@@ -69,11 +68,15 @@
     "built-ins/RegExp/unicode_restricted_identity_escape_alpha.js",
     "built-ins/RegExp/unicode_restricted_identity_escape_c.js",
     "built-ins/RegExp/unicode_restricted_identity_escape_u.js",
+    "built-ins/RegExp/unicode_identity_escape.js",
+    "built-ins/RegExp/unicode_character_class_backspace_escape.js",
+    "built-ins/RegExp/unicode_restricted_identity_escape_x.js",
+    "language/literals/regexp/u-astral-char-class-invert.js",
 
     // Issue with \r in source string
     "built-ins/RegExp/dotall/without-dotall.js",
     "built-ins/RegExp/dotall/without-dotall-unicode.js",
-    
+
     // regex named groups
     "built-ins/String/prototype/replaceAll/searchValue-replacer-RegExp-call.js",
 
@@ -218,7 +221,7 @@
 
     // negative years, c'mon...
     "built-ins/Date/prototype/*/negative-year.js",
-    
+
     // failing tests in new test suite (due to updating to latest and using whole set)
     "language/arguments-object/mapped/nonconfigurable-descriptors-define-failure.js",
     "language/destructuring/binding/syntax/destructuring-array-parameters-function-arguments-length.js",

+ 4 - 5
Jint.Tests.Test262/Test262Test.cs

@@ -23,12 +23,11 @@ public abstract partial class Test262Test
         engine.Execute(State.Sources["assert.js"]);
         engine.Execute(State.Sources["sta.js"]);
 
-        engine.SetValue("print",
-            new ClrFunctionInstance(engine, "print", (thisObj, args) => TypeConverter.ToString(args.At(0))));
+        engine.SetValue("print", new ClrFunctionInstance(engine, "print", (_, args) => TypeConverter.ToString(args.At(0))));
 
         var o = engine.Realm.Intrinsics.Object.Construct(Arguments.Empty);
         o.FastSetProperty("evalScript", new PropertyDescriptor(new ClrFunctionInstance(engine, "evalScript",
-            (thisObj, args) =>
+            (_, args) =>
             {
                 if (args.Length > 1)
                 {
@@ -43,7 +42,7 @@ public abstract partial class Test262Test
             }), true, true, true));
 
         o.FastSetProperty("createRealm", new PropertyDescriptor(new ClrFunctionInstance(engine, "createRealm",
-            (thisObj, args) =>
+            (_, args) =>
             {
                 var realm = engine._host.CreateRealm();
                 realm.GlobalObject.Set("global", realm.GlobalObject);
@@ -51,7 +50,7 @@ public abstract partial class Test262Test
             }), true, true, true));
 
         o.FastSetProperty("detachArrayBuffer", new PropertyDescriptor(new ClrFunctionInstance(engine, "detachArrayBuffer",
-            (thisObj, args) =>
+            (_, args) =>
             {
                 var buffer = (ArrayBufferInstance) args.At(0);
                 buffer.DetachArrayBuffer();

+ 1 - 1
Jint/Jint.csproj

@@ -8,7 +8,7 @@
     <IsPackable>true</IsPackable>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="Esprima" Version="2.1.2" />
+    <PackageReference Include="Esprima" Version="3.0.0-beta-1" />
     <PackageReference Include="IsExternalInit" Version="1.0.2" PrivateAssets="all" />
     <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="all" />
     <PackageReference Include="Nullable" Version="1.3.0" PrivateAssets="all" />

+ 2 - 2
Jint/Native/Function/ClassDefinition.cs

@@ -132,9 +132,9 @@ namespace Jint.Native.Function
             var classBody = _body.Body;
             for (var i = 0; i < classBody.Count; ++i)
             {
-                if (classBody[i].Kind == PropertyKind.Constructor)
+                if (classBody[i] is MethodDefinition { Kind: PropertyKind.Constructor } c)
                 {
-                    constructor = (MethodDefinition) classBody[i];
+                    constructor = c;
                     break;
                 }
             }

+ 12 - 17
Jint/Native/Json/JsonSerializer.cs

@@ -159,21 +159,14 @@ namespace Jint.Native.Json
 
             if (value.IsObject())
             {
-                switch (value)
+                value = value switch
                 {
-                    case NumberInstance:
-                        value = TypeConverter.ToNumber(value);
-                        break;
-                    case StringInstance:
-                        value = TypeConverter.ToString(value);
-                        break;
-                    case BooleanInstance booleanInstance:
-                        value = booleanInstance.BooleanData;
-                        break;
-                    case BigIntInstance bigIntInstance:
-                        value = bigIntInstance.BigIntData;
-                        break;
-                }
+                    NumberInstance => TypeConverter.ToNumber(value),
+                    StringInstance => TypeConverter.ToString(value),
+                    BooleanInstance booleanInstance => booleanInstance.BooleanData,
+                    BigIntInstance bigIntInstance => bigIntInstance.BigIntData,
+                    _ => value
+                };
             }
 
             if (ReferenceEquals(value, Null.Instance))
@@ -244,7 +237,7 @@ namespace Jint.Native.Json
         {
             using var stringBuilder = StringBuilderPool.Rent();
             var sb = stringBuilder.Builder;
-            sb.Append("\"");
+            sb.Append('"');
 
             foreach (var c in value)
             {
@@ -272,18 +265,20 @@ namespace Jint.Native.Json
                         sb.Append("\\t");
                         break;
                     default:
-                        if (c < 0x20)
+                        if (c < 0x20 || (c - 0x10000 >> 10) + 0xD800 == (c - 0x10000) % 0x400 + 0xDC00)
                         {
                             sb.Append("\\u");
                             sb.Append(((int) c).ToString("x4"));
                         }
                         else
+                        {
                             sb.Append(c);
+                        }
                         break;
                 }
             }
 
-            sb.Append("\"");
+            sb.Append('"');
             return sb.ToString();
         }
 

+ 3 - 2
Jint/Native/RegExp/RegExpConstructor.cs

@@ -105,10 +105,11 @@ namespace Jint.Native.RegExp
 
             try
             {
-                var scanner = new Scanner("/" + p + "/" + flags, new ParserOptions { AdaptRegexp = true });
+                var parserOptions = new ParserOptions { AdaptRegexp = true };
+                var scanner = new Scanner("/" + p + "/" + flags, parserOptions);
 
                 // seems valid
-                r.Value = scanner.ParseRegex(p, f);
+                r.Value = scanner.ParseRegex(p, f, parserOptions.RegexTimeout);
 
                 var timeout = _engine.Options.Constraints.RegexTimeout;
                 if (timeout.Ticks > 0)

+ 17 - 0
Jint/Runtime/Host.cs

@@ -1,5 +1,7 @@
 #nullable enable
 
+using System.Collections;
+using System.Collections.Generic;
 using Jint.Native;
 using Jint.Native.Global;
 using Jint.Native.Object;
@@ -170,5 +172,20 @@ namespace Jint.Runtime
 
             PromiseOperations.PerformPromiseThen(Engine, innerPromise, onFulfilled, onRejected, promiseCapability);
         }
+
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-hostgetimportmetaproperties
+        /// </summary>
+        public virtual List<KeyValuePair<JsValue, JsValue>> GetImportMetaProperties(ModuleRecord moduleRecord)
+        {
+            return new List<KeyValuePair<JsValue, JsValue>>();
+        }
+
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-hostfinalizeimportmeta
+        /// </summary>
+        public virtual void FinalizeImportMeta(ObjectInstance importMeta, ModuleRecord moduleRecord)
+        {
+        }
     }
 }

+ 28 - 5
Jint/Runtime/Interpreter/Expressions/JintMetaPropertyExpression.cs

@@ -1,25 +1,48 @@
 using Esprima.Ast;
+using Jint.Native;
+using Jint.Runtime.Modules;
 
 namespace Jint.Runtime.Interpreter.Expressions
 {
     internal sealed class JintMetaPropertyExpression : JintExpression
     {
-        private readonly bool _newTarget;
-
         public JintMetaPropertyExpression(MetaProperty expression) : base(expression)
         {
-            _newTarget = expression.Meta.Name == "new" && expression.Property.Name == "target";
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-meta-properties
+        /// </summary>
         protected override ExpressionResult EvaluateInternal(EvaluationContext context)
         {
-            if (_newTarget)
+            var expression = (MetaProperty) _expression;
+            if (expression.Meta.Name == "new" && expression.Property.Name == "target")
             {
                 return NormalCompletion(context.Engine.GetNewTarget());
             }
 
+            if (expression.Meta.Name == "import" && expression.Property.Name == "meta")
+            {
+                var module = (SourceTextModuleRecord) context.Engine.ExecutionContext.ScriptOrModule!;
+                var importMeta = module.ImportMeta;
+                if (importMeta is null)
+                {
+                    importMeta = context.Engine.Realm.Intrinsics.Object.Construct(0);
+                    var importMetaValues = context.Engine._host.GetImportMetaProperties(module);
+                    foreach (var p in importMetaValues)
+                    {
+                        importMeta.CreateDataPropertyOrThrow(p.Key, p.Value);
+                    }
+
+                    context.Engine._host.FinalizeImportMeta(importMeta, module);
+                    module.ImportMeta = importMeta;
+                }
+
+                return NormalCompletion(importMeta);
+            }
+
             ExceptionHelper.ThrowNotImplementedException();
             return default;
         }
     }
-}
+}

+ 5 - 5
Jint/Runtime/Interpreter/Statements/JintTryStatement.cs

@@ -10,9 +10,9 @@ namespace Jint.Runtime.Interpreter.Statements
     /// </summary>
     internal sealed class JintTryStatement : JintStatement<TryStatement>
     {
-        private JintStatement _block;
+        private JintBlockStatement _block;
         private JintStatement _catch;
-        private JintStatement _finalizer;
+        private JintBlockStatement _finalizer;
 
         public JintTryStatement(TryStatement statement) : base(statement)
         {
@@ -21,10 +21,10 @@ namespace Jint.Runtime.Interpreter.Statements
 
         protected override void Initialize(EvaluationContext context)
         {
-            _block = Build(_statement.Block);
+            _block = new JintBlockStatement(_statement.Block);
             if (_statement.Finalizer != null)
             {
-                _finalizer = Build(_statement.Finalizer);
+                _finalizer = new JintBlockStatement(_statement.Finalizer);
             }
         }
 
@@ -97,4 +97,4 @@ namespace Jint.Runtime.Interpreter.Statements
             return b.UpdateEmpty(Undefined.Instance);
         }
     }
-}
+}

+ 15 - 4
Jint/Runtime/Modules/SourceTextModuleRecord.cs

@@ -2,7 +2,6 @@
 using Esprima.Ast;
 using Jint.Native.Object;
 using Jint.Native.Promise;
-using Jint.Runtime.Descriptors;
 using Jint.Runtime.Environments;
 using Jint.Runtime.Interpreter;
 
@@ -34,7 +33,7 @@ internal class SourceTextModuleRecord : CyclicModuleRecord
 {
     private readonly Module _source;
     private ExecutionContext _context;
-    private readonly ObjectInstance _importMeta;
+    private ObjectInstance _importMeta;
     private readonly List<ImportEntry> _importEntries;
     internal readonly List<ExportEntry> _localExportEntries;
     private readonly List<ExportEntry> _indirectExportEntries;
@@ -46,8 +45,6 @@ internal class SourceTextModuleRecord : CyclicModuleRecord
         _source = source;
 
         // https://tc39.es/ecma262/#sec-parsemodule
-        _importMeta = _realm.Intrinsics.Object.Construct(1);
-        _importMeta.DefineOwnProperty("url", new PropertyDescriptor(location, PropertyFlag.ConfigurableEnumerableWritable));
 
         HoistingScope.GetImportsAndExports(
             _source,
@@ -60,6 +57,20 @@ internal class SourceTextModuleRecord : CyclicModuleRecord
         //ToDo async modules
     }
 
+    internal ObjectInstance ImportMeta
+    {
+        get
+        {
+            if (_importMeta is null)
+            {
+                _importMeta = _realm.Intrinsics.Object.Construct(1);
+                _importMeta.CreateDataProperty("url", Location);
+            }
+            return _importMeta;
+        }
+        set => _importMeta = value;
+    }
+
     /// <summary>
     /// https://tc39.es/ecma262/#sec-getexportednames
     /// </summary>

+ 1 - 1
README.md

@@ -78,7 +78,7 @@ The entire execution engine was rebuild with performance in mind, in many cases
 - ✔ `for-in` enhancements
 - ✔ `globalThis` object
 - ✔ `import`
--  `import.meta`
+-  `import.meta`
 - ✔ Nullish coalescing operator (`??`)
 - ✔ Optional chaining
 - ❌ `Promise.allSettled`