Ver Fonte

ES2022 Class fields and static blocks (#1546)

Marko Lahma há 2 anos atrás
pai
commit
d90b774ec2
41 ficheiros alterados com 1273 adições e 588 exclusões
  1. 3 8
      Jint.Tests.Test262/Test262Harness.settings.json
  2. 2 2
      Jint.Tests/Runtime/NullPropagation.cs
  3. 57 23
      Jint/Engine.cs
  4. 86 9
      Jint/EsprimaExtensions.cs
  5. 5 1
      Jint/Jint.csproj
  6. 4 0
      Jint/JsValueExtensions.cs
  7. 335 180
      Jint/Native/Function/ClassDefinition.cs
  8. 174 109
      Jint/Native/Function/EvalFunctionInstance.cs
  9. 4 4
      Jint/Native/Function/FunctionConstructor.cs
  10. 2 2
      Jint/Native/Function/FunctionInstance.Dynamic.cs
  11. 13 2
      Jint/Native/Function/FunctionInstance.cs
  12. 14 19
      Jint/Native/Function/ScriptFunctionInstance.cs
  13. 164 0
      Jint/Native/Object/ObjectInstance.Private.cs
  14. 28 1
      Jint/Native/Object/ObjectInstance.cs
  15. 74 0
      Jint/Native/PrivateName.cs
  16. 2 2
      Jint/Runtime/Environments/EnvironmentRecord.cs
  17. 2 2
      Jint/Runtime/Environments/GlobalEnvironmentRecord.cs
  18. 7 7
      Jint/Runtime/Environments/ObjectEnvironmentRecord.cs
  19. 24 25
      Jint/Runtime/Environments/PrivateEnvironmentRecord.cs
  20. 1 1
      Jint/Runtime/ExceptionHelper.cs
  21. 1 1
      Jint/Runtime/Interpreter/Expressions/BindingPatternAssignmentExpression.cs
  22. 24 24
      Jint/Runtime/Interpreter/Expressions/JintArrowFunctionExpression.cs
  23. 2 2
      Jint/Runtime/Interpreter/Expressions/JintAssignmentExpression.cs
  24. 7 0
      Jint/Runtime/Interpreter/Expressions/JintBinaryExpression.cs
  25. 14 8
      Jint/Runtime/Interpreter/Expressions/JintCallExpression.cs
  26. 2 1
      Jint/Runtime/Interpreter/Expressions/JintExpression.cs
  27. 2 2
      Jint/Runtime/Interpreter/Expressions/JintFunctionExpression.cs
  28. 52 53
      Jint/Runtime/Interpreter/Expressions/JintIdentifierExpression.cs
  29. 2 2
      Jint/Runtime/Interpreter/Expressions/JintImportExpression.cs
  30. 2 1
      Jint/Runtime/Interpreter/Expressions/JintLiteralExpression.cs
  31. 20 2
      Jint/Runtime/Interpreter/Expressions/JintMemberExpression.cs
  32. 4 3
      Jint/Runtime/Interpreter/Expressions/JintObjectExpression.cs
  33. 28 0
      Jint/Runtime/Interpreter/Expressions/JintPrivateIdentifierExpression.cs
  34. 2 2
      Jint/Runtime/Interpreter/Expressions/JintTaggedTemplateExpression.cs
  35. 11 11
      Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs
  36. 1 1
      Jint/Runtime/Interpreter/Statements/JintExportDefaultDeclaration.cs
  37. 2 2
      Jint/Runtime/Interpreter/Statements/JintVariableDeclaration.cs
  38. 1 1
      Jint/Runtime/Modules/SourceTextModuleRecord.cs
  39. 79 63
      Jint/Runtime/References/Reference.cs
  40. 13 9
      Jint/Runtime/TypeConverter.cs
  41. 3 3
      README.md

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

@@ -8,13 +8,6 @@
     "Array.fromAsync",
     "async-iteration",
     "Atomics",
-    "class-fields-private",
-    "class-fields-public",
-    "class-methods-private",
-    "class-static-block",
-    "class-static-fields-private",
-    "class-static-fields-public",
-    "class-static-methods-private",
     "decorators",
     "generators",
     "import-assertions",
@@ -76,9 +69,9 @@
     "built-ins/RegExp/unicode_restricted_identity_escape.js",
     "built-ins/RegExp/unicode_restricted_quantifiable_assertion.js",
 
-
     // requires investigation how to process complex function name evaluation for property
     "built-ins/Function/prototype/toString/method-computed-property-name.js",
+    "language/expressions/class/elements/class-name-static-initializer-anonymous.js",
 
     // http://www.ecma-international.org/ecma-262/#sec-block-level-function-declarations-web-legacy-compatibility-semantics not implemented (block level functions)
     "language/statements/let/block-local-closure-set-before-initialization.js",
@@ -118,6 +111,8 @@
     "language/expressions/object/accessor-name-computed.js",
     "built-ins/TypedArrayConstructors/ctors/object-arg/as-generator-iterable-returns.js",
     "language/expressions/object/method-definition/name-prop-name-yield-id.js",
+    "language/statements/class/elements/*-generator-method-*.js",
+    "language/expressions/class/elements/*-generator-method-*.js",
 
     // generators not implemented
     "built-ins/Object/prototype/toString/proxy-function.js",

+ 2 - 2
Jint.Tests/Runtime/NullPropagation.cs

@@ -11,7 +11,7 @@ namespace Jint.Tests.Runtime
         {
             public bool TryUnresolvableReference(Engine engine, Reference reference, out JsValue value)
             {
-                value = reference.GetBase();
+                value = reference.Base;
                 return true;
             }
 
@@ -24,7 +24,7 @@ namespace Jint.Tests.Runtime
             {
                 if (callee is Reference reference)
                 {
-                    var name = reference.GetReferencedName().AsString();
+                    var name = reference.ReferencedName.AsString();
                     if (name == "filter")
                     {
                         value = new ClrFunctionInstance(engine, "map", (thisObj, values) => engine.Realm.Intrinsics.Array.ArrayCreate(0));

+ 57 - 23
Jint/Engine.cs

@@ -26,7 +26,11 @@ namespace Jint
     /// </summary>
     public sealed partial class Engine : IDisposable
     {
-        private readonly JavaScriptParser _defaultParser = new(ParserOptions.Default);
+        private static readonly ParserOptions _defaultParserOptions = ParserOptions.Default with
+        {
+            AllowReturnOutsideFunction = true
+        };
+        private readonly JavaScriptParser _defaultParser = new(_defaultParserOptions);
 
         internal readonly ExecutionContextStack _executionContexts;
         private JsValue _completionValue = JsValue.Undefined;
@@ -286,13 +290,13 @@ namespace Jint
         /// Evaluates code and returns last return value.
         /// </summary>
         public JsValue Evaluate(string code)
-            => Evaluate(code, "<anonymous>", ParserOptions.Default);
+            => Evaluate(code, "<anonymous>", _defaultParserOptions);
 
         /// <summary>
         /// Evaluates code and returns last return value.
         /// </summary>
         public JsValue Evaluate(string code, string source)
-            => Evaluate(code, source, ParserOptions.Default);
+            => Evaluate(code, source, _defaultParserOptions);
 
         /// <summary>
         /// Evaluates code and returns last return value.
@@ -305,7 +309,7 @@ namespace Jint
         /// </summary>
         public JsValue Evaluate(string code, string source, ParserOptions parserOptions)
         {
-            var parser = ReferenceEquals(ParserOptions.Default, parserOptions)
+            var parser = ReferenceEquals(_defaultParserOptions, parserOptions)
                 ? _defaultParser
                 : new JavaScriptParser(parserOptions);
 
@@ -324,7 +328,7 @@ namespace Jint
         /// Executes code into engine and returns the engine instance (useful for chaining).
         /// </summary>
         public Engine Execute(string code, string? source = null)
-            => Execute(code, source ?? "<anonymous>", ParserOptions.Default);
+            => Execute(code, source ?? "<anonymous>", _defaultParserOptions);
 
         /// <summary>
         /// Executes code into engine and returns the engine instance (useful for chaining).
@@ -337,7 +341,7 @@ namespace Jint
         /// </summary>
         public Engine Execute(string code, string source, ParserOptions parserOptions)
         {
-            var parser = ReferenceEquals(ParserOptions.Default, parserOptions)
+            var parser = ReferenceEquals(_defaultParserOptions, parserOptions)
                 ? _defaultParser
                 : new JavaScriptParser(parserOptions);
 
@@ -506,7 +510,7 @@ namespace Jint
 
         internal JsValue GetValue(Reference reference, bool returnReferenceToPool)
         {
-            var baseValue = reference.GetBase();
+            var baseValue = reference.Base;
 
             if (baseValue.IsUndefined())
             {
@@ -524,9 +528,9 @@ namespace Jint
                 return baseValue;
             }
 
-            if (reference.IsPropertyReference())
+            if (reference.IsPropertyReference)
             {
-                var property = reference.GetReferencedName();
+                var property = reference.ReferencedName;
                 if (returnReferenceToPool)
                 {
                     _referencePool.Return(reference);
@@ -534,8 +538,14 @@ namespace Jint
 
                 if (baseValue.IsObject())
                 {
-                    var o = TypeConverter.ToObject(Realm, baseValue);
-                    var v = o.Get(property, reference.GetThisValue());
+                    var baseObj = TypeConverter.ToObject(Realm, baseValue);
+
+                    if (reference.IsPrivateReference)
+                    {
+                        return baseObj.PrivateGet((PrivateName) reference.ReferencedName);
+                    }
+
+                    var v = baseObj.Get(property, reference.ThisValue);
                     return v;
                 }
                 else
@@ -555,6 +565,11 @@ namespace Jint
                         o = TypeConverter.ToObject(Realm, baseValue);
                     }
 
+                    if (reference.IsPrivateReference)
+                    {
+                        return o.PrivateGet((PrivateName) reference.ReferencedName);
+                    }
+
                     var desc = o.GetProperty(property);
                     if (desc == PropertyDescriptor.Undefined)
                     {
@@ -583,7 +598,7 @@ namespace Jint
                 ExceptionHelper.ThrowArgumentException();
             }
 
-            var bindingValue = record.GetBindingValue(reference.GetReferencedName().ToString(), reference.IsStrictReference());
+            var bindingValue = record.GetBindingValue(reference.ReferencedName.ToString(), reference.Strict);
 
             if (returnReferenceToPool)
             {
@@ -632,32 +647,33 @@ namespace Jint
         /// </summary>
         internal void PutValue(Reference reference, JsValue value)
         {
-            var baseValue = reference.GetBase();
-            if (reference.IsUnresolvableReference())
+            if (reference.IsUnresolvableReference)
             {
-                if (reference.IsStrictReference() && reference.GetReferencedName() != CommonProperties.Arguments)
+                if (reference.Strict && reference.ReferencedName != CommonProperties.Arguments)
                 {
                     ExceptionHelper.ThrowReferenceError(Realm, reference);
                 }
 
-                Realm.GlobalObject.Set(reference.GetReferencedName(), value, throwOnError: false);
+                Realm.GlobalObject.Set(reference.ReferencedName, value, throwOnError: false);
             }
-            else if (reference.IsPropertyReference())
+            else if (reference.IsPropertyReference)
             {
-                if (reference.HasPrimitiveBase())
+                var baseObject = TypeConverter.ToObject(Realm, reference.Base);
+                if (reference.IsPrivateReference)
                 {
-                    baseValue = TypeConverter.ToObject(Realm, baseValue);
+                    baseObject.PrivateSet((PrivateName) reference.ReferencedName, value);
+                    return;
                 }
 
-                var succeeded = baseValue.Set(reference.GetReferencedName(), value, reference.GetThisValue());
-                if (!succeeded && reference.IsStrictReference())
+                var succeeded = baseObject.Set(reference.ReferencedName, value, reference.ThisValue);
+                if (!succeeded && reference.Strict)
                 {
-                    ExceptionHelper.ThrowTypeError(Realm, "Cannot assign to read only property '" + reference.GetReferencedName() + "' of " + baseValue);
+                    ExceptionHelper.ThrowTypeError(Realm, "Cannot assign to read only property '" + reference.ReferencedName + "' of " + baseObject);
                 }
             }
             else
             {
-                ((EnvironmentRecord) baseValue).SetMutableBinding(TypeConverter.ToString(reference.GetReferencedName()), value, reference.IsStrictReference());
+                ((EnvironmentRecord) reference.Base).SetMutableBinding(TypeConverter.ToString(reference.ReferencedName), value, reference.Strict);
             }
         }
 
@@ -1197,6 +1213,21 @@ namespace Jint
                 }
             }
 
+            HashSet<PrivateIdentifier>? privateIdentifiers = null;
+            var pointer = privateEnv;
+            while (pointer is not null)
+            {
+                foreach (var name in pointer.Names)
+                {
+                    privateIdentifiers??= new HashSet<PrivateIdentifier>(PrivateIdentifierNameComparer._instance);
+                    privateIdentifiers.Add(name.Key);
+                }
+
+                pointer = pointer.OuterPrivateEnvironment;
+            }
+
+            script.AllPrivateIdentifiersValid(realm, privateIdentifiers);
+
             var functionDeclarations = hoistingScope._functionDeclarations;
             var functionsToInitialize = new LinkedList<JintFunctionDefinition>();
             var declaredFunctionNames = new HashSet<string>();
@@ -1433,6 +1464,9 @@ namespace Jint
             return ((IConstructor) constructor).Construct(arguments, newTarget);
         }
 
+        internal JsValue Call(FunctionInstance functionInstance, JsValue thisObject)
+            => Call(functionInstance, thisObject, Arguments.Empty, null);
+
         internal JsValue Call(
             FunctionInstance functionInstance,
             JsValue thisObject,

+ 86 - 9
Jint/EsprimaExtensions.cs

@@ -1,6 +1,7 @@
 using System.Runtime.CompilerServices;
 using Esprima;
 using Esprima.Ast;
+using Esprima.Utils;
 using Jint.Native;
 using Jint.Native.Function;
 using Jint.Native.Object;
@@ -44,6 +45,10 @@ namespace Jint
             {
                 key = identifier.Name;
             }
+            else if (expression is PrivateIdentifier privateIdentifier)
+            {
+                key = engine.ExecutionContext.PrivateEnvironment!.Names[privateIdentifier];
+            }
             else if (resolveComputed)
             {
                 return TryGetComputedPropertyKey(expression, engine);
@@ -243,11 +248,37 @@ namespace Jint
                         target.Add(name);
                     }
                 }
-
                 break;
             }
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-static-semantics-privateboundidentifiers
+        /// </summary>
+        internal static void PrivateBoundIdentifiers(this Node parameter, HashSet<PrivateIdentifier> target)
+        {
+            if (parameter.Type == Nodes.PrivateIdentifier)
+            {
+                target.Add((PrivateIdentifier) parameter);
+            }
+            else if (parameter.Type is Nodes.AccessorProperty or Nodes.MethodDefinition or Nodes.PropertyDefinition)
+            {
+                if (((ClassProperty) parameter).Key is PrivateIdentifier privateKeyIdentifier)
+                {
+                    target.Add(privateKeyIdentifier);
+                }
+            }
+            else if (parameter.Type == Nodes.ClassBody)
+            {
+                ref readonly var elements = ref ((ClassBody) parameter).Body;
+                for (var i = 0; i < elements.Count; i++)
+                {
+                    var element = elements[i];
+                    PrivateBoundIdentifiers(element, target);
+                }
+            }
+        }
+
         internal static void BindingInitialization(
             this Node? expression,
             EvaluationContext context,
@@ -279,8 +310,8 @@ namespace Jint
             var intrinsics = engine.Realm.Intrinsics;
 
             var runningExecutionContext = engine.ExecutionContext;
-            var scope = runningExecutionContext.LexicalEnvironment;
-            var privateScope= runningExecutionContext.PrivateEnvironment;
+            var env = runningExecutionContext.LexicalEnvironment;
+            var privateEnv= runningExecutionContext.PrivateEnvironment;
 
             var prototype = functionPrototype ?? intrinsics.Function.PrototypeObject;
             var function = m.Value as IFunction;
@@ -290,7 +321,7 @@ namespace Jint
             }
 
             var definition = new JintFunctionDefinition(function);
-            var closure = intrinsics.Function.OrdinaryFunctionCreate(prototype, definition, definition.ThisMode, scope, privateScope);
+            var closure = intrinsics.Function.OrdinaryFunctionCreate(prototype, definition, definition.ThisMode, env, privateEnv);
             closure.MakeMethod(obj);
 
             return new Record(propKey, closure);
@@ -438,13 +469,59 @@ namespace Jint
         {
             return new MinimalSyntaxElement(location);
         }
-    }
 
-    internal sealed class MinimalSyntaxElement : SyntaxElement
-    {
-        public MinimalSyntaxElement(in Location location)
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-static-semantics-allprivateidentifiersvalid
+        /// </summary>
+        internal static void AllPrivateIdentifiersValid(this Script script, Realm realm, HashSet<PrivateIdentifier>? privateIdentifiers)
         {
-            Location = location;
+            var validator = new PrivateIdentifierValidator(realm, privateIdentifiers);
+            validator.Visit(script);
+        }
+
+        private sealed class MinimalSyntaxElement : SyntaxElement
+        {
+            public MinimalSyntaxElement(in Location location)
+            {
+                Location = location;
+            }
+        }
+
+        private sealed class PrivateIdentifierValidator : AstVisitor
+        {
+            private readonly Realm _realm;
+            private HashSet<PrivateIdentifier>? _privateNames;
+
+            public PrivateIdentifierValidator(Realm realm, HashSet<PrivateIdentifier>? privateNames)
+            {
+                _realm = realm;
+                _privateNames = privateNames;
+            }
+
+            protected override object VisitPrivateIdentifier(PrivateIdentifier privateIdentifier)
+            {
+                if (_privateNames is null || !_privateNames.Contains(privateIdentifier))
+                {
+                    Throw(_realm, privateIdentifier);
+                }
+                return privateIdentifier;
+            }
+
+            protected override object VisitClassBody(ClassBody classBody)
+            {
+                var oldList = _privateNames;
+                _privateNames = new HashSet<PrivateIdentifier>(PrivateIdentifierNameComparer._instance);
+                classBody.PrivateBoundIdentifiers(_privateNames);
+                base.VisitClassBody(classBody);
+                _privateNames = oldList;
+                return classBody;
+            }
+
+            [MethodImpl(MethodImplOptions.NoInlining)]
+            private static void Throw(Realm r, PrivateIdentifier id)
+            {
+                ExceptionHelper.ThrowSyntaxError(r, $"Private field '#{id.Name}' must be declared in an enclosing class");
+            }
         }
     }
 }

+ 5 - 1
Jint/Jint.csproj

@@ -12,9 +12,13 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Esprima" Version="3.0.0-rc-01" />
+    <PackageReference Include="Esprima" Version="3.0.0-rc-02" />
     <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="all" />
     <PackageReference Include="Nullable" Version="1.3.1" PrivateAssets="all" />
+    <PackageReference Include="PolySharp" Version="1.13.1">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
   </ItemGroup>
 
   <ItemGroup>

+ 4 - 0
Jint/JsValueExtensions.cs

@@ -50,6 +50,10 @@ namespace Jint
             return value is PromiseInstance;
         }
 
+        [Pure]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool IsPrivateName(this JsValue value) => value._type == InternalTypes.PrivateName;
+
         [Pure]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static bool IsRegExp(this JsValue value)

+ 335 - 180
Jint/Native/Function/ClassDefinition.cs

@@ -1,5 +1,6 @@
 using Esprima;
 using Esprima.Ast;
+using Esprima.Utils;
 using Jint.Native.Object;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
@@ -7,252 +8,406 @@ using Jint.Runtime.Environments;
 using Jint.Runtime.Interpreter;
 using Jint.Runtime.Interpreter.Expressions;
 
-namespace Jint.Native.Function
+namespace Jint.Native.Function;
+
+internal sealed class ClassDefinition
 {
-    internal sealed class ClassDefinition
-    {
-        private static readonly MethodDefinition _superConstructor;
-        internal static CallExpression _defaultSuperCall;
+    private static readonly MethodDefinition _superConstructor;
+    internal static CallExpression _defaultSuperCall;
 
-        internal static readonly MethodDefinition _emptyConstructor;
+    internal static readonly MethodDefinition _emptyConstructor;
 
-        internal readonly string? _className;
-        private readonly Expression? _superClass;
-        private readonly ClassBody _body;
+    internal readonly string? _className;
+    private readonly Expression? _superClass;
+    private readonly ClassBody _body;
 
-        static ClassDefinition()
+    static ClassDefinition()
+    {
+        // generate missing constructor AST only once
+        static MethodDefinition CreateConstructorMethodDefinition(string source)
         {
-            // generate missing constructor AST only once
-            static MethodDefinition CreateConstructorMethodDefinition(string source)
-            {
-                var script = new JavaScriptParser().ParseScript(source);
-                var classDeclaration = (ClassDeclaration) script.Body[0];
-                return (MethodDefinition) classDeclaration.Body.Body[0];
-            }
-
-            _superConstructor = CreateConstructorMethodDefinition("class temp { constructor(...args) { super(...args); } }");
-            _defaultSuperCall = (CallExpression) ((ExpressionStatement) _superConstructor.Value.Body.Body[0]).Expression;
-            _emptyConstructor = CreateConstructorMethodDefinition("class temp { constructor() {} }");
+            var script = new JavaScriptParser().ParseScript(source);
+            var classDeclaration = (ClassDeclaration) script.Body[0];
+            return (MethodDefinition) classDeclaration.Body.Body[0];
         }
 
-        public ClassDefinition(
-            string? className,
-            Expression? superClass,
-            ClassBody body)
+        _superConstructor = CreateConstructorMethodDefinition("class temp { constructor(...args) { super(...args); } }");
+        _defaultSuperCall = (CallExpression) ((ExpressionStatement) _superConstructor.Value.Body.Body[0]).Expression;
+        _emptyConstructor = CreateConstructorMethodDefinition("class temp { constructor() {} }");
+    }
+
+    public ClassDefinition(
+        string? className,
+        Expression? superClass,
+        ClassBody body)
+    {
+        _className = className;
+        _superClass = superClass;
+        _body = body;
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-runtime-semantics-classdefinitionevaluation
+    /// </summary>
+    public JsValue BuildConstructor(EvaluationContext context, EnvironmentRecord env)
+    {
+        // A class definition is always strict mode code.
+        using var _ = new StrictModeScope(true, true);
+
+        var engine = context.Engine;
+        var classEnv = JintEnvironment.NewDeclarativeEnvironment(engine, env);
+
+        if (_className is not null)
         {
-            _className = className;
-            _superClass = superClass;
-            _body = body;
+            classEnv.CreateImmutableBinding(_className, true);
         }
 
-        public void Initialize()
-        {
+        var outerPrivateEnvironment = engine.ExecutionContext.PrivateEnvironment;
+        var classPrivateEnvironment = JintEnvironment.NewPrivateEnvironment(engine, outerPrivateEnvironment);
 
+        ObjectInstance? protoParent = null;
+        ObjectInstance? constructorParent = null;
+        if (_superClass is null)
+        {
+            protoParent = engine.Realm.Intrinsics.Object.PrototypeObject;
+            constructorParent = engine.Realm.Intrinsics.Function.PrototypeObject;
         }
-
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-runtime-semantics-classdefinitionevaluation
-        /// </summary>
-        public JsValue BuildConstructor(
-            EvaluationContext context,
-            EnvironmentRecord env)
+        else
         {
-            // A class definition is always strict mode code.
-            using var _ = new StrictModeScope(true, true);
+            engine.UpdateLexicalEnvironment(classEnv);
+            var superclass = JintExpression.Build(_superClass).GetValue(context);
+            engine.UpdateLexicalEnvironment(env);
 
-            var engine = context.Engine;
-            var classScope = JintEnvironment.NewDeclarativeEnvironment(engine, env);
-
-            if (_className is not null)
+            if (superclass.IsNull())
             {
-                classScope.CreateImmutableBinding(_className, true);
+                protoParent = null;
+                constructorParent = engine.Realm.Intrinsics.Function.PrototypeObject;
             }
-
-            var outerPrivateEnvironment = engine.ExecutionContext.PrivateEnvironment;
-            var classPrivateEnvironment = JintEnvironment.NewPrivateEnvironment(engine, outerPrivateEnvironment);
-
-            /*
-                6. If ClassBodyopt is present, then
-                    a. For each String dn of the PrivateBoundIdentifiers of ClassBodyopt, do
-                    i. If classPrivateEnvironment.[[Names]] contains a Private Name whose [[Description]] is dn, then
-                    1. Assert: This is only possible for getter/setter pairs.
-                ii. Else,
-                    1. Let name be a new Private Name whose [[Description]] value is dn.
-                    2. Append name to classPrivateEnvironment.[[Names]].
-             */
-
-            ObjectInstance? protoParent = null;
-            ObjectInstance? constructorParent = null;
-            if (_superClass is null)
+            else if (!superclass.IsConstructor)
             {
-                protoParent = engine.Realm.Intrinsics.Object.PrototypeObject;
-                constructorParent = engine.Realm.Intrinsics.Function.PrototypeObject;
+                ExceptionHelper.ThrowTypeError(engine.Realm, "super class is not a constructor");
             }
             else
             {
-                engine.UpdateLexicalEnvironment(classScope);
-                var superclass = JintExpression.Build(_superClass).GetValue(context);
-                engine.UpdateLexicalEnvironment(env);
-
-                if (superclass.IsNull())
+                var temp = superclass.Get("prototype");
+                if (temp is ObjectInstance protoParentObject)
                 {
-                    protoParent = null;
-                    constructorParent = engine.Realm.Intrinsics.Function.PrototypeObject;
+                    protoParent = protoParentObject;
                 }
-                else if (!superclass.IsConstructor)
+                else if (temp.IsNull())
                 {
-                    ExceptionHelper.ThrowTypeError(engine.Realm, "super class is not a constructor");
+                    // OK
                 }
                 else
                 {
-                    var temp = superclass.Get("prototype");
-                    if (temp is ObjectInstance protoParentObject)
-                    {
-                        protoParent = protoParentObject;
-                    }
-                    else if (temp.IsNull())
-                    {
-                        // OK
-                    }
-                    else
-                    {
-                        ExceptionHelper.ThrowTypeError(engine.Realm, "cannot resolve super class prototype chain");
-                        return default;
-                    }
-
-                    constructorParent = (ObjectInstance) superclass;
+                    ExceptionHelper.ThrowTypeError(engine.Realm, "cannot resolve super class prototype chain");
+                    return default;
                 }
+
+                constructorParent = (ObjectInstance) superclass;
             }
+        }
+
+        ObjectInstance proto = new JsObject(engine) { _prototype = protoParent };
 
-            ObjectInstance proto = new JsObject(engine)
+        var privateBoundIdentifiers = new HashSet<PrivateIdentifier>(PrivateIdentifierNameComparer._instance);
+        MethodDefinition? constructor = null;
+        ref readonly var elements = ref _body.Body;
+        var classBody = elements;
+        for (var i = 0; i < classBody.Count; ++i)
+        {
+            var element = classBody[i];
+            if (element is MethodDefinition { Kind: PropertyKind.Constructor } c)
             {
-                _prototype = protoParent
-            };
+                constructor = c;
+            }
 
-            MethodDefinition? constructor = null;
-            var classBody = _body.Body;
-            for (var i = 0; i < classBody.Count; ++i)
+            privateBoundIdentifiers.Clear();
+            element.PrivateBoundIdentifiers(privateBoundIdentifiers);
+            foreach (var name in privateBoundIdentifiers)
             {
-                if (classBody[i] is MethodDefinition { Kind: PropertyKind.Constructor } c)
-                {
-                    constructor = c;
-                    break;
-                }
+                classPrivateEnvironment.Names.Add(name, new PrivateName(name));
             }
+        }
 
-            constructor ??= _superClass != null
-                ? _superConstructor
-                : _emptyConstructor;
+        constructor ??= _superClass != null
+            ? _superConstructor
+            : _emptyConstructor;
 
-            engine.UpdateLexicalEnvironment(classScope);
+        engine.UpdateLexicalEnvironment(classEnv);
+        engine.UpdatePrivateEnvironment(classPrivateEnvironment);
 
-            ScriptFunctionInstance F;
-            try
-            {
-                var constructorInfo = constructor.DefineMethod(proto, constructorParent);
-                F = constructorInfo.Closure;
+        ScriptFunctionInstance F;
+        try
+        {
+            var constructorInfo = constructor.DefineMethod(proto, constructorParent);
+            F = constructorInfo.Closure;
+
+            F.SetFunctionName(_className ?? "");
 
-                var name = env is ModuleEnvironmentRecord ? _className : _className ?? "";
-                if (name is not null)
+            F.MakeConstructor(writableProperty: false, proto);
+            F._constructorKind = _superClass is null ? ConstructorKind.Base : ConstructorKind.Derived;
+            F.MakeClassConstructor();
+            proto.CreateMethodProperty(CommonProperties.Constructor, F);
+
+            var instancePrivateMethods = new List<PrivateElement>();
+            var staticPrivateMethods = new List<PrivateElement>();
+            var instanceFields = new List<ClassFieldDefinition>();
+            var staticElements = new List<object>();
+
+            foreach (var e in elements)
+            {
+                if (e is MethodDefinition { Kind: PropertyKind.Constructor })
                 {
-                    F.SetFunctionName(name);
+                    continue;
                 }
 
-                F.MakeConstructor(writableProperty: false, proto);
-                F._constructorKind = _superClass is null ? ConstructorKind.Base : ConstructorKind.Derived;
-                F.MakeClassConstructor();
-                proto.CreateMethodProperty(CommonProperties.Constructor, F);
+                var isStatic = e is MethodDefinition { Static: true } or AccessorProperty { Static: true } or PropertyDefinition { Static: true } or StaticBlock;
 
-                foreach (var classProperty in _body.Body)
+                var target = !isStatic ? proto : F;
+                var element = ClassElementEvaluation(engine, target, e);
+                if (element is PrivateElement privateElement)
                 {
-                    if (classProperty is not MethodDefinition m || m.Kind == PropertyKind.Constructor)
+                    var container = !isStatic ? instancePrivateMethods : staticPrivateMethods;
+                    var index = container.FindIndex(x => x.Key.Description == privateElement.Key.Description);
+                    if (index != -1)
                     {
-                        continue;
-                    }
+                        var pe = container[index];
+                        var combined = privateElement.Get is null
+                            ? new PrivateElement { Key = pe.Key, Kind = PrivateElementKind.Accessor, Get = pe.Get, Set = privateElement.Set }
+                            : new PrivateElement { Key = pe.Key, Kind = PrivateElementKind.Accessor, Get = privateElement.Get, Set = pe.Set };
 
-                    var target = !m.Static ? proto : F;
-                    var value = MethodDefinitionEvaluation(engine, target, m);
-                    if (engine._activeEvaluationContext!.IsAbrupt())
+                        container[index] = combined;
+                    }
+                    else
                     {
-                        return value;
+                        container.Add(privateElement);
                     }
                 }
-            }
-            finally
-            {
-                engine.UpdateLexicalEnvironment(env);
-                engine.UpdatePrivateEnvironment(outerPrivateEnvironment);
+                else if (element is ClassFieldDefinition classFieldDefinition)
+                {
+                    if (!isStatic)
+                    {
+                        instanceFields.Add(classFieldDefinition);
+                    }
+                    else
+                    {
+                        staticElements.Add(element);
+                    }
+                }
+                else if (element is ClassStaticBlockDefinition)
+                {
+                    staticElements.Add(element);
+                }
             }
 
             if (_className is not null)
             {
-                classScope.InitializeBinding(_className, F);
+                classEnv.InitializeBinding(_className, F);
             }
 
-            /*
-            28. Set F.[[PrivateMethods]] to instancePrivateMethods.
-            29. Set F.[[Fields]] to instanceFields.
-            30. For each PrivateElement method of staticPrivateMethods, do
-                a. Perform ! PrivateMethodOrAccessorAdd(method, F).
-            31. For each element fieldRecord of staticFields, do
-                a. Let result be DefineField(F, fieldRecord).
-                b. If result is an abrupt completion, then
-            i. Set the running execution context's PrivateEnvironment to outerPrivateEnvironment.
-                ii. Return result.
-            */
-
-            engine.UpdatePrivateEnvironment(outerPrivateEnvironment);
-
-            return F;
-        }
+            F._privateMethods = instancePrivateMethods;
+            F._fields = instanceFields;
 
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-runtime-semantics-methoddefinitionevaluation
-        /// </summary>
-        private static JsValue MethodDefinitionEvaluation(
-            Engine engine,
-            ObjectInstance obj,
-            MethodDefinition method)
-        {
-            if (method.Kind != PropertyKind.Get && method.Kind != PropertyKind.Set)
+            for (var i = 0; i < staticPrivateMethods.Count; i++)
             {
-                var methodDef = method.DefineMethod(obj);
-                methodDef.Closure.SetFunctionName(methodDef.Key);
-                var desc = new PropertyDescriptor(methodDef.Closure, PropertyFlag.NonEnumerable);
-                obj.DefinePropertyOrThrow(methodDef.Key, desc);
+                F.PrivateMethodOrAccessorAdd(staticPrivateMethods[i]);
             }
-            else
+
+            for (var i = 0; i < staticElements.Count; i++)
             {
-                var value = method.TryGetKey(engine);
-                if (engine._activeEvaluationContext!.IsAbrupt())
+                var elementRecord = staticElements[i];
+                if (elementRecord is ClassFieldDefinition classFieldDefinition)
                 {
-                    return value;
+                    ObjectInstance.DefineField(F, classFieldDefinition);
                 }
-                var propKey = TypeConverter.ToPropertyKey(value);
-                var function = method.Value as IFunction;
-                if (function is null)
+                else
                 {
-                    ExceptionHelper.ThrowSyntaxError(obj.Engine.Realm);
+                    engine.Call(((ClassStaticBlockDefinition) elementRecord).BodyFunction, F);
                 }
+            }
+        }
+        finally
+        {
+            engine.UpdateLexicalEnvironment(env);
+            engine.UpdatePrivateEnvironment(outerPrivateEnvironment);
+        }
 
-                var closure = new ScriptFunctionInstance(
-                    obj.Engine,
-                    function,
-                    obj.Engine.ExecutionContext.LexicalEnvironment,
-                    true);
+        return F;
+    }
 
-                closure.SetFunctionName(propKey, method.Kind == PropertyKind.Get ? "get" : "set");
-                closure.MakeMethod(obj);
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-static-semantics-classelementevaluation
+    /// </summary>
+    private static object? ClassElementEvaluation(Engine engine, ObjectInstance target, ClassElement e)
+    {
+        return e switch
+        {
+            PropertyDefinition p => ClassFieldDefinitionEvaluation(engine, target, p),
+            MethodDefinition m => MethodDefinitionEvaluation(engine, target, m, enumerable: false),
+            StaticBlock s => ClassStaticBlockDefinitionEvaluation(engine, target, s),
+            _ => null
+        };
+    }
 
-                var propDesc = new GetSetPropertyDescriptor(
-                    method.Kind == PropertyKind.Get ? closure : null,
-                    method.Kind == PropertyKind.Set ? closure : null,
-                    PropertyFlag.Configurable);
+    /// <summary>
+    /// /https://tc39.es/ecma262/#sec-runtime-semantics-classfielddefinitionevaluation
+    /// </summary>
+    private static ClassFieldDefinition ClassFieldDefinitionEvaluation(Engine engine, ObjectInstance homeObject, PropertyDefinition fieldDefinition)
+    {
+        var name = fieldDefinition.GetKey(engine);
 
-                obj.DefinePropertyOrThrow(propKey, propDesc);
-            }
+        ScriptFunctionInstance? initializer = null;
+        if (fieldDefinition.Value is not null)
+        {
+            var intrinsics = engine.Realm.Intrinsics;
+            var env = engine.ExecutionContext.LexicalEnvironment;
+            var privateEnv = engine.ExecutionContext.PrivateEnvironment;
+
+            var definition = new JintFunctionDefinition(new ClassFieldFunction(fieldDefinition.Value));
+            initializer = intrinsics.Function.OrdinaryFunctionCreate(intrinsics.Function.PrototypeObject, definition, FunctionThisMode.Global, env, privateEnv);
+
+            initializer.MakeMethod(homeObject);
+            initializer._classFieldInitializerName = name;
+        }
+
+        return new ClassFieldDefinition { Name = name, Initializer = initializer };
+    }
+
+    private sealed class ClassFieldFunction : Node, IFunction
+    {
+        private readonly NodeList<Node> _nodeList = new();
+        private readonly BlockStatement _statement;
 
-            return obj;
+        public ClassFieldFunction(Expression expression) : base(Nodes.ExpressionStatement)
+        {
+            var nodeList = NodeList.Create<Statement>(new [] { new ReturnStatement(expression) });
+            _statement = new BlockStatement(nodeList);
         }
+
+        protected override object Accept(AstVisitor visitor) => throw new NotImplementedException();
+
+        public Identifier? Id => null;
+
+        public ref readonly NodeList<Node> Params => ref _nodeList;
+
+        public StatementListItem Body => _statement;
+        public bool Generator => false;
+        public bool Expression => false;
+        public bool Strict => true;
+        public bool Async => false;
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-runtime-semantics-classstaticblockdefinitionevaluation
+    /// </summary>
+    private static ClassStaticBlockDefinition ClassStaticBlockDefinitionEvaluation(Engine engine, ObjectInstance homeObject, StaticBlock o)
+    {
+        var intrinsics = engine.Realm.Intrinsics;
+
+        var definition = new JintFunctionDefinition(new ClassStaticBlockFunction(o));
+
+        var lex = engine.ExecutionContext.LexicalEnvironment;
+        var privateEnv = engine.ExecutionContext.PrivateEnvironment;
+
+        var bodyFunction = intrinsics.Function.OrdinaryFunctionCreate(intrinsics.Function.PrototypeObject, definition, FunctionThisMode.Global, lex, privateEnv);
+
+        bodyFunction.MakeMethod(homeObject);
+
+        return new ClassStaticBlockDefinition { BodyFunction = bodyFunction };
+    }
+
+    private sealed class ClassStaticBlockFunction : Node, IFunction
+    {
+        private readonly BlockStatement _statement;
+        private readonly NodeList<Node> _params;
+
+        public ClassStaticBlockFunction(StaticBlock staticBlock) : base(Nodes.StaticBlock)
+        {
+            _statement = new BlockStatement(staticBlock.Body);
+            _params = new NodeList<Node>();
+        }
+
+        protected override object Accept(AstVisitor visitor) => throw new NotImplementedException();
+
+        public Identifier? Id => null;
+        public ref readonly NodeList<Node> Params => ref _params;
+        public StatementListItem Body => _statement;
+        public bool Generator => false;
+        public bool Expression => false;
+        public bool Strict => false;
+        public bool Async => false;
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-runtime-semantics-methoddefinitionevaluation
+    /// </summary>
+    private static PrivateElement? MethodDefinitionEvaluation(
+        Engine engine,
+        ObjectInstance obj,
+        MethodDefinition method,
+        bool enumerable)
+    {
+        if (method.Kind != PropertyKind.Get && method.Kind != PropertyKind.Set)
+        {
+            var methodDef = method.DefineMethod(obj);
+            methodDef.Closure.SetFunctionName(methodDef.Key);
+            return DefineMethodProperty(obj, methodDef.Key, methodDef.Closure, enumerable);
+        }
+
+        var function = method.Value as IFunction;
+        if (function is null)
+        {
+            ExceptionHelper.ThrowSyntaxError(obj.Engine.Realm);
+        }
+
+        var getter = method.Kind == PropertyKind.Get;
+
+        var definition = new JintFunctionDefinition(function);
+        var intrinsics = engine.Realm.Intrinsics;
+
+        var value = method.TryGetKey(engine);
+        var propKey = TypeConverter.ToPropertyKey(value);
+        var env = engine.ExecutionContext.LexicalEnvironment;
+        var privateEnv = engine.ExecutionContext.PrivateEnvironment;
+
+        var closure = intrinsics.Function.OrdinaryFunctionCreate(intrinsics.Function.PrototypeObject, definition, definition.ThisMode, env, privateEnv);
+        closure.MakeMethod(obj);
+        closure.SetFunctionName(propKey, getter ? "get" : "set");
+
+        if (method.Key is PrivateIdentifier privateIdentifier)
+        {
+            return new PrivateElement
+            {
+                Key = privateEnv!.Names[privateIdentifier],
+                Kind = PrivateElementKind.Accessor,
+                Get = getter ? closure : null,
+                Set = !getter ? closure : null
+            };
+        }
+
+        var propDesc = new GetSetPropertyDescriptor(
+            getter ? closure : null,
+            !getter ? closure : null,
+            PropertyFlag.Configurable);
+
+        obj.DefinePropertyOrThrow(propKey, propDesc);
+
+        return null;
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-definemethodproperty
+    /// </summary>
+    private static PrivateElement? DefineMethodProperty(ObjectInstance homeObject, JsValue key, ScriptFunctionInstance closure, bool enumerable)
+    {
+        if (key.IsPrivateName())
+        {
+            return new PrivateElement { Key = (PrivateName) key, Kind = PrivateElementKind.Method, Value = closure };
+        }
+
+        var desc = new PropertyDescriptor(closure, enumerable ? PropertyFlag.Enumerable : PropertyFlag.NonEnumerable);
+        homeObject.DefinePropertyOrThrow(key, desc);
+        return null;
     }
 }

+ 174 - 109
Jint/Native/Function/EvalFunctionInstance.cs

@@ -1,161 +1,226 @@
 using Esprima;
 using Esprima.Ast;
+using Esprima.Utils;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Environments;
 using Jint.Runtime.Interpreter.Statements;
 
-namespace Jint.Native.Function
+namespace Jint.Native.Function;
+
+internal sealed class EvalFunctionInstance : FunctionInstance
 {
-    internal sealed class EvalFunctionInstance : FunctionInstance
+    private static readonly JsString _functionName = new("eval");
+
+    private static readonly ParserOptions _parserOptions = ParserOptions.Default with { Tolerant = true };
+    private readonly JavaScriptParser _parser = new(_parserOptions);
+
+    public EvalFunctionInstance(
+        Engine engine,
+        Realm realm,
+        FunctionPrototype functionPrototype)
+        : base(
+            engine,
+            realm,
+            _functionName,
+            StrictModeScope.IsStrictModeCode ? FunctionThisMode.Strict : FunctionThisMode.Global)
     {
-        private static readonly JsString _functionName = new("eval");
-
-        private readonly JavaScriptParser _parser = new(new ParserOptions { Tolerant = false });
-
-        public EvalFunctionInstance(
-            Engine engine,
-            Realm realm,
-            FunctionPrototype functionPrototype)
-            : base(
-                engine,
-                realm,
-                _functionName,
-                StrictModeScope.IsStrictModeCode ? FunctionThisMode.Strict : FunctionThisMode.Global)
+        _prototype = functionPrototype;
+        _length = new PropertyDescriptor(JsNumber.PositiveOne, PropertyFlag.Configurable);
+    }
+
+    protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
+    {
+        var callerRealm = _engine.ExecutionContext.Realm;
+        var x = arguments.At(0);
+        return PerformEval(x, callerRealm, false, false);
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-performeval
+    /// </summary>
+    public JsValue PerformEval(JsValue x, Realm callerRealm, bool strictCaller, bool direct)
+    {
+        if (!x.IsString())
         {
-            _prototype = functionPrototype;
-            _length = new PropertyDescriptor(JsNumber.PositiveOne, PropertyFlag.Configurable);
+            return x;
         }
 
-        protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
+        var evalRealm = _realm;
+        _engine._host.EnsureCanCompileStrings(callerRealm, evalRealm);
+
+        var inFunction = false;
+        var inMethod = false;
+        var inDerivedConstructor = false;
+        var inClassFieldInitializer = false;
+
+        if (direct)
         {
-            var callerRealm = _engine.ExecutionContext.Realm;
-            var x = arguments.At(0);
-            return PerformEval(x, callerRealm, false, false);
+            var thisEnvRec = _engine.ExecutionContext.GetThisEnvironment();
+            if (thisEnvRec is FunctionEnvironmentRecord functionEnvironmentRecord)
+            {
+                var F = functionEnvironmentRecord._functionObject;
+                inFunction = true;
+                inMethod = thisEnvRec.HasSuperBinding();
+
+                if (F._constructorKind == ConstructorKind.Derived)
+                {
+                    inDerivedConstructor = true;
+                }
+
+                var classFieldInitializerName = (F as ScriptFunctionInstance)?._classFieldInitializerName;
+                if (!string.IsNullOrEmpty(classFieldInitializerName?.ToString()))
+                {
+                    inClassFieldInitializer = true;
+                }
+            }
         }
 
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-performeval
-        /// </summary>
-        public JsValue PerformEval(JsValue x, Realm callerRealm, bool strictCaller, bool direct)
+        Script? script = null;
+        try
+        {
+            script = _parser.ParseScript(x.ToString(), strict: strictCaller);
+        }
+        catch (ParserException e)
         {
-            if (!x.IsString())
+            if (e.Description == Messages.InvalidLHSInAssignment)
             {
-                return x;
+                ExceptionHelper.ThrowReferenceError(callerRealm, (string?) null);
             }
+            else
+            {
+                ExceptionHelper.ThrowSyntaxError(callerRealm, e.Message);
+            }
+        }
 
-            var evalRealm = _realm;
-            _engine._host.EnsureCanCompileStrings(callerRealm, evalRealm);
-
-            var inFunction = false;
-            var inMethod = false;
-            var inDerivedConstructor = false;
+        var body = script.Body;
+        if (body.Count == 0)
+        {
+            return Undefined;
+        }
 
-            if (direct)
+        var analyzer = new EvalScriptAnalyzer();
+        analyzer.Visit(script);
+        if (!inFunction)
+        {
+            // if body Contains NewTarget, throw a SyntaxError exception.
+            if (analyzer._containsNewTarget)
             {
-                var thisEnvRec = _engine.ExecutionContext.GetThisEnvironment();
-                if (thisEnvRec is FunctionEnvironmentRecord functionEnvironmentRecord)
-                {
-                    var F = functionEnvironmentRecord._functionObject;
-                    inFunction = true;
-                    inMethod = thisEnvRec.HasSuperBinding();
-
-                    if (F._constructorKind == ConstructorKind.Derived)
-                    {
-                        inDerivedConstructor = true;
-                    }
-                }
+                ExceptionHelper.ThrowSyntaxError(evalRealm, "new.target expression is not allowed here");
             }
+        }
 
-            Script? script = null;
-            try
+        if (!inMethod)
+        {
+            // if body Contains SuperProperty, throw a SyntaxError exception.
+            if (analyzer._containsSuperProperty)
             {
-                script = _parser.ParseScript(x.ToString(), strict: strictCaller);
+                ExceptionHelper.ThrowSyntaxError(evalRealm, "'super' keyword unexpected here");
             }
-            catch (ParserException e)
+        }
+
+        if (!inDerivedConstructor)
+        {
+            // if body Contains SuperCall, throw a SyntaxError exception.
+            if (analyzer._containsSuperCall)
             {
-                if (e.Description == Messages.InvalidLHSInAssignment)
-                {
-                    ExceptionHelper.ThrowReferenceError(callerRealm, (string?) null);
-                }
-                else
-                {
-                    ExceptionHelper.ThrowSyntaxError(callerRealm, e.Message);
-                }
+                ExceptionHelper.ThrowSyntaxError(evalRealm, "'super' keyword unexpected here");
             }
+        }
 
-            var body = script.Body;
-            if (body.Count == 0)
+        if (inClassFieldInitializer)
+        {
+            // if ContainsArguments of body is true, throw a SyntaxError exception.
+            if (analyzer._containsArguments)
             {
-                return Undefined;
+                ExceptionHelper.ThrowSyntaxError(evalRealm, "'arguments' is not allowed in class field initializer or static initialization block");
             }
+        }
 
-            if (!inFunction)
+        var strictEval = script.Strict || _engine._isStrict;
+        var ctx = _engine.ExecutionContext;
+
+        using (new StrictModeScope(strictEval))
+        {
+            EnvironmentRecord lexEnv;
+            EnvironmentRecord varEnv;
+            PrivateEnvironmentRecord? privateEnv;
+            if (direct)
             {
-                // if body Contains NewTarget, throw a SyntaxError exception.
+                lexEnv = JintEnvironment.NewDeclarativeEnvironment(_engine, ctx.LexicalEnvironment);
+                varEnv = ctx.VariableEnvironment;
+                privateEnv = ctx.PrivateEnvironment;
             }
-            if (!inMethod)
+            else
             {
-                // if body Contains SuperProperty, throw a SyntaxError exception.
+                lexEnv = JintEnvironment.NewDeclarativeEnvironment(_engine, evalRealm.GlobalEnv);
+                varEnv = evalRealm.GlobalEnv;
+                privateEnv = null;
             }
-            if (!inDerivedConstructor)
+
+            if (strictEval)
             {
-                // if body Contains SuperCall, throw a SyntaxError exception.
+                varEnv = lexEnv;
             }
 
-            var strictEval = script.Strict || _engine._isStrict;
-            var ctx = _engine.ExecutionContext;
+            // If ctx is not already suspended, suspend ctx.
+
+            Engine.EnterExecutionContext(lexEnv, varEnv, evalRealm, privateEnv);
 
-            using (new StrictModeScope(strictEval))
+            try
             {
-                EnvironmentRecord lexEnv;
-                EnvironmentRecord varEnv;
-                PrivateEnvironmentRecord? privateEnv;
-                if (direct)
+                Engine.EvalDeclarationInstantiation(script, varEnv, lexEnv, privateEnv, strictEval);
+
+                var statement = new JintScript(script);
+                var result = statement.Execute(_engine._activeEvaluationContext!);
+                var value = result.GetValueOrDefault();
+
+                if (result.Type == CompletionType.Throw)
                 {
-                    lexEnv = JintEnvironment.NewDeclarativeEnvironment(_engine, ctx.LexicalEnvironment);
-                    varEnv = ctx.VariableEnvironment;
-                    privateEnv = ctx.PrivateEnvironment;
+                    ExceptionHelper.ThrowJavaScriptException(_engine, value, result);
+                    return null!;
                 }
                 else
                 {
-                    lexEnv = JintEnvironment.NewDeclarativeEnvironment(_engine, evalRealm.GlobalEnv);
-                    varEnv = evalRealm.GlobalEnv;
-                    privateEnv = null;
+                    return value;
                 }
+            }
+            finally
+            {
+                Engine.LeaveExecutionContext();
+            }
+        }
+    }
 
-                if (strictEval)
-                {
-                    varEnv = lexEnv;
-                }
+    private sealed class EvalScriptAnalyzer : AstVisitor
+    {
+        public bool _containsArguments;
+        public bool _containsNewTarget;
+        public bool _containsSuperCall;
+        public bool _containsSuperProperty;
 
-                // If ctx is not already suspended, suspend ctx.
+        protected override object VisitIdentifier(Identifier identifier)
+        {
+            _containsArguments |= identifier.Name == "arguments";
+            return identifier;
+        }
+
+        protected override object VisitMetaProperty(MetaProperty metaProperty)
+        {
+            _containsNewTarget |= metaProperty.Meta.Name == "new" && metaProperty.Property.Name == "target";
+            return metaProperty;
+        }
 
-                Engine.EnterExecutionContext(lexEnv, varEnv, evalRealm, privateEnv);
+        protected override object? VisitMemberExpression(MemberExpression memberExpression)
+        {
+            _containsSuperProperty |= memberExpression.Object.Type == Nodes.Super;
+            return base.VisitMemberExpression(memberExpression);
+        }
 
-                try
-                {
-                    Engine.EvalDeclarationInstantiation(script, varEnv, lexEnv, privateEnv, strictEval);
-
-                    var statement = new JintScript(script);
-                    var result = statement.Execute(_engine._activeEvaluationContext!);
-                    var value = result.GetValueOrDefault();
-
-                    if (result.Type == CompletionType.Throw)
-                    {
-                        ExceptionHelper.ThrowJavaScriptException(_engine, value, result);
-                        return null!;
-                    }
-                    else
-                    {
-                        return value;
-                    }
-                }
-                finally
-                {
-                    Engine.LeaveExecutionContext();
-                }
-            }
+        protected override object? VisitCallExpression(CallExpression callExpression)
+        {
+            _containsSuperCall |= callExpression.Callee.Type == Nodes.Super;
+            return base.VisitCallExpression(callExpression);
         }
     }
 }

+ 4 - 4
Jint/Native/Function/FunctionConstructor.cs

@@ -49,18 +49,18 @@ namespace Jint.Native.Function
         internal FunctionInstance InstantiateFunctionObject(
             JintFunctionDefinition functionDeclaration,
             EnvironmentRecord scope,
-            PrivateEnvironmentRecord? privateScope)
+            PrivateEnvironmentRecord? privateEnv)
         {
             var function = functionDeclaration.Function;
             if (!function.Generator)
             {
                 return function.Async
-                    ? InstantiateAsyncFunctionObject(functionDeclaration, scope, privateScope)
-                    : InstantiateOrdinaryFunctionObject(functionDeclaration, scope, privateScope);
+                    ? InstantiateAsyncFunctionObject(functionDeclaration, scope, privateEnv)
+                    : InstantiateOrdinaryFunctionObject(functionDeclaration, scope, privateEnv);
             }
             else
             {
-                return InstantiateGeneratorFunctionObject(functionDeclaration, scope, privateScope);
+                return InstantiateGeneratorFunctionObject(functionDeclaration, scope, privateEnv);
             }
         }
 

+ 2 - 2
Jint/Native/Function/FunctionInstance.Dynamic.cs

@@ -149,10 +149,10 @@ public partial class FunctionInstance
         var proto = GetPrototypeFromConstructor(newTarget, fallbackProto);
         var realmF = _realm;
         var scope = realmF.GlobalEnv;
-        PrivateEnvironmentRecord? privateScope = null;
+        PrivateEnvironmentRecord? privateEnv = null;
 
         var definition = new JintFunctionDefinition(function);
-        FunctionInstance F = OrdinaryFunctionCreate(proto, definition, function.Strict ? FunctionThisMode.Strict : FunctionThisMode.Global, scope, privateScope);
+        FunctionInstance F = OrdinaryFunctionCreate(proto, definition, function.Strict ? FunctionThisMode.Strict : FunctionThisMode.Global, scope, privateEnv);
         F.SetFunctionName(_functionNameAnonymous, force: true);
 
         if (kind == FunctionKind.Generator)

+ 13 - 2
Jint/Native/Function/FunctionInstance.cs

@@ -38,7 +38,7 @@ namespace Jint.Native.Function
             Engine engine,
             Realm realm,
             JintFunctionDefinition function,
-            EnvironmentRecord scope,
+            EnvironmentRecord env,
             FunctionThisMode thisMode)
             : this(
                 engine,
@@ -47,7 +47,7 @@ namespace Jint.Native.Function
                 thisMode)
         {
             _functionDefinition = function;
-            _environment = scope;
+            _environment = env;
         }
 
         internal FunctionInstance(
@@ -194,6 +194,11 @@ namespace Jint.Native.Function
                     ? JsString.Empty
                     : new JsString("[" + symbol._value + "]");
             }
+            else if (name is PrivateName privateName)
+            {
+                name = "#" + privateName.Description;
+            }
+
             if (!string.IsNullOrWhiteSpace(prefix))
             {
                 name = prefix + " " + name;
@@ -352,6 +357,9 @@ namespace Jint.Native.Function
             DefinePropertyOrThrow(CommonProperties.Length, new PropertyDescriptor(length, writable: false, enumerable: false, configurable: true));
         }
 
+        // native syntax doesn't expect to have private identifier indicator
+        private static readonly char[] _functionNameTrimStartChars = { '#' };
+
         public override string ToString()
         {
             // TODO no way to extract SourceText from Esprima at the moment, just returning native code
@@ -361,6 +369,9 @@ namespace Jint.Native.Function
             {
                 name = TypeConverter.ToString(nameValue);
             }
+
+            name = name.TrimStart(_functionNameTrimStartChars);
+
             return "function " + name + "() { [native code] }";
         }
 

+ 14 - 19
Jint/Native/Function/ScriptFunctionInstance.cs

@@ -11,6 +11,10 @@ namespace Jint.Native.Function
     public sealed class ScriptFunctionInstance : FunctionInstance, IConstructor
     {
         internal bool _isClassConstructor;
+        internal JsValue? _classFieldInitializerName;
+
+        internal List<PrivateElement>? _privateMethods;
+        internal List<ClassFieldDefinition>? _fields;
 
         /// <summary>
         /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
@@ -18,13 +22,13 @@ namespace Jint.Native.Function
         public ScriptFunctionInstance(
             Engine engine,
             IFunction functionDeclaration,
-            EnvironmentRecord scope,
+            EnvironmentRecord env,
             bool strict,
             ObjectInstance? proto = null)
             : this(
                 engine,
                 new JintFunctionDefinition(functionDeclaration),
-                scope,
+                env,
                 strict ? FunctionThisMode.Strict : FunctionThisMode.Global,
                 proto)
         {
@@ -33,10 +37,10 @@ namespace Jint.Native.Function
         internal ScriptFunctionInstance(
             Engine engine,
             JintFunctionDefinition function,
-            EnvironmentRecord scope,
+            EnvironmentRecord env,
             FunctionThisMode thisMode,
             ObjectInstance? proto = null)
-            : base(engine, engine.Realm, function, scope, thisMode)
+            : base(engine, engine.Realm, function, env, thisMode)
         {
             _prototype = proto ?? _engine.Realm.Intrinsics.Function.PrototypeObject;
             _length = new LazyPropertyDescriptor(null, _ => JsNumber.Create(function.Initialize().Length), PropertyFlag.Configurable);
@@ -140,13 +144,6 @@ namespace Jint.Native.Function
             }
 
             var calleeContext = PrepareForOrdinaryCall(newTarget);
-
-            if (kind == ConstructorKind.Base)
-            {
-                OrdinaryCallBindThis(calleeContext, thisArgument);
-                InitializeInstanceElements(thisArgument, this);
-            }
-
             var constructorEnv = (FunctionEnvironmentRecord) calleeContext.LexicalEnvironment;
 
             var strict = _thisMode == FunctionThisMode.Strict;
@@ -154,6 +151,12 @@ namespace Jint.Native.Function
             {
                 try
                 {
+                    if (kind == ConstructorKind.Base)
+                    {
+                        OrdinaryCallBindThis(calleeContext, thisArgument);
+                        ((ObjectInstance) thisArgument).InitializeInstanceElements(this);
+                    }
+
                     var context = _engine._activeEvaluationContext ?? new EvaluationContext(_engine);
 
                     var result = _functionDefinition.EvaluateBody(context, this, arguments);
@@ -204,14 +207,6 @@ namespace Jint.Native.Function
             return (ObjectInstance) constructorEnv.GetThisBinding();
         }
 
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-initializeinstanceelements
-        /// </summary>
-        private void InitializeInstanceElements(JsValue o, JsValue constructor)
-        {
-            // TODO private fields
-        }
-
         internal void MakeClassConstructor()
         {
             _isClassConstructor = true;

+ 164 - 0
Jint/Native/Object/ObjectInstance.Private.cs

@@ -0,0 +1,164 @@
+using System.Runtime.CompilerServices;
+using Jint.Native.Function;
+using Jint.Runtime;
+
+namespace Jint.Native.Object;
+
+public partial class ObjectInstance
+{
+    private Dictionary<PrivateName, PrivateElement>? _privateElements;
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-initializeinstanceelements
+    /// </summary>
+    internal void InitializeInstanceElements(ScriptFunctionInstance constructor)
+    {
+        var methods = constructor._privateMethods;
+        if (methods is not null)
+        {
+            for (var i = 0; i < methods.Count; i++)
+            {
+                PrivateMethodOrAccessorAdd(methods[i]);
+            }
+        }
+
+        var fields = constructor._fields;
+        if (fields is not null)
+        {
+            for (var i = 0; i < fields.Count; i++)
+            {
+                DefineField(this, fields[i]);
+            }
+        }
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-privatemethodoraccessoradd
+    /// </summary>
+    internal void PrivateMethodOrAccessorAdd(PrivateElement method)
+    {
+        // If the host is a web browser, then
+        // Perform ? HostEnsureCanAddPrivateElement(O).
+
+        var entry = PrivateElementFind(method.Key);
+        if (entry is not null)
+        {
+            ExceptionHelper.ThrowTypeError(_engine.Realm, "Already present");
+        }
+
+        _privateElements ??= new Dictionary<PrivateName, PrivateElement>();
+        _privateElements.Add(method.Key, method);
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-privatefieldadd
+    /// </summary>
+    private void PrivateFieldAdd(PrivateName property, JsValue value)
+    {
+        // If the host is a web browser, then
+        // Perform ? HostEnsureCanAddPrivateElement(O).
+
+        var entry = PrivateElementFind(property);
+        if (entry is not null)
+        {
+            ExceptionHelper.ThrowTypeError(_engine.Realm, "Already present");
+        }
+
+        _privateElements ??= new Dictionary<PrivateName, PrivateElement>();
+        _privateElements.Add(property, new PrivateElement { Key = property, Kind = PrivateElementKind.Field, Value = value });
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-privateget
+    /// </summary>
+    internal JsValue PrivateGet(PrivateName property)
+    {
+        var entry = PrivateElementFind(property);
+        if (entry is null)
+        {
+            ExceptionHelper.ThrowTypeError(_engine.Realm, $"Cannot read private member #{property} from an object whose class did not declare it");
+        }
+
+        if (entry.Kind is PrivateElementKind.Field or PrivateElementKind.Method)
+        {
+            return entry.Value ?? Undefined;
+        }
+
+        var getter = entry.Get;
+        if (getter is null)
+        {
+            ExceptionHelper.ThrowTypeError(_engine.Realm, $"'#{property}' was defined without a getter");
+        }
+
+        var functionInstance = (FunctionInstance) getter;
+        var privateGet = functionInstance._engine.Call(functionInstance, this);
+        return privateGet;
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-privateset
+    /// </summary>
+    internal void PrivateSet(PrivateName property, JsValue value)
+    {
+        var entry = PrivateElementFind(property);
+        if (entry is null)
+        {
+            ExceptionHelper.ThrowTypeError(_engine.Realm, "Not found");
+        }
+
+        if (entry.Kind == PrivateElementKind.Field)
+        {
+            entry.Value = value;
+        }
+        else if (entry.Kind == PrivateElementKind.Method)
+        {
+            ExceptionHelper.ThrowTypeError(_engine.Realm, "Cannot set method");
+        }
+        else
+        {
+            var setter = entry.Set;
+            if (setter is null)
+            {
+                ExceptionHelper.ThrowTypeError(_engine.Realm, $"'#{property}' was defined without a setter");
+            }
+
+            _engine.Call(setter, this, new[] { value });
+        }
+    }
+
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-privateelementfind
+    /// </summary>
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    internal PrivateElement? PrivateElementFind(PrivateName property)
+    {
+        return _privateElements?.TryGetValue(property, out var pe) == true ? pe : null;
+    }
+}
+
+internal sealed class ClassFieldDefinition
+{
+    public required JsValue Name { get; set; }
+    public ScriptFunctionInstance? Initializer { get; set; }
+}
+
+internal sealed class ClassStaticBlockDefinition
+{
+    public required FunctionInstance BodyFunction { get; set; }
+}
+
+internal sealed class PrivateElement
+{
+    public required PrivateName Key { get; set; }
+    public PrivateElementKind Kind { get; set; }
+    public JsValue? Value { get; set; }
+    public JsValue? Get { get; set; }
+    public JsValue? Set { get; set; }
+}
+
+internal enum PrivateElementKind
+{
+    Field,
+    Method,
+    Accessor
+}

+ 28 - 1
Jint/Native/Object/ObjectInstance.cs

@@ -412,7 +412,7 @@ namespace Jint.Native.Object
             }
 
             var functionInstance = (FunctionInstance) getter;
-            return functionInstance._engine.Call(functionInstance, thisObject, Arguments.Empty, expression: null);
+            return functionInstance._engine.Call(functionInstance, thisObject);
         }
 
         /// <summary>
@@ -1601,6 +1601,33 @@ namespace Jint.Native.Object
             return true;
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-definefield
+        /// </summary>
+        internal static void DefineField(ObjectInstance receiver, ClassFieldDefinition fieldRecord)
+        {
+            var fieldName = fieldRecord.Name;
+            var initializer = fieldRecord.Initializer;
+            var initValue = Undefined;
+            if (initializer is not null)
+            {
+                initValue = receiver._engine.Call(initializer, receiver);
+                if (initValue is FunctionInstance functionInstance)
+                {
+                    functionInstance.SetFunctionName(fieldName);
+                }
+            }
+
+            if (fieldName is PrivateName privateName)
+            {
+                receiver.PrivateFieldAdd(privateName, initValue);
+            }
+            else
+            {
+                receiver.CreateDataPropertyOrThrow(fieldName, initValue);
+            }
+        }
+
         internal enum IntegrityLevel
         {
             Sealed,

+ 74 - 0
Jint/Native/PrivateName.cs

@@ -0,0 +1,74 @@
+using Esprima.Ast;
+using Jint.Runtime;
+
+namespace Jint.Native;
+
+/// <summary>
+/// Private names are a bit like symbols, they follow reference equality so that each one is globally to object,
+/// only exception to the rule is get/set pair which should share same private name.
+/// </summary>
+internal sealed class PrivateName : JsValue, IEquatable<PrivateName>
+{
+    private readonly PrivateIdentifier _identifier;
+
+    public PrivateName(PrivateIdentifier identifier) : base(InternalTypes.PrivateName)
+    {
+        _identifier = identifier;
+        Description = identifier.Name;
+    }
+
+    public string Description { get; }
+
+    public override string ToString() => _identifier.Name;
+
+    public override object ToObject() => throw new NotImplementedException();
+
+    public override bool Equals(object? obj)
+    {
+        return Equals(obj as PrivateName);
+    }
+
+    public override bool Equals(JsValue? other)
+    {
+        return Equals(other as PrivateName);
+    }
+
+    public bool Equals(PrivateName? other)
+    {
+        if (ReferenceEquals(null, other))
+        {
+            return false;
+        }
+
+        if (ReferenceEquals(this, other))
+        {
+            return true;
+        }
+
+        return ReferenceEquals(this, other);
+    }
+
+    public override int GetHashCode()
+    {
+        return _identifier.Name.GetHashCode();
+    }
+}
+
+/// <summary>
+/// Compares private identifiers by their name instead of reference equality.
+/// </summary>
+internal sealed class PrivateIdentifierNameComparer : IEqualityComparer<PrivateIdentifier>
+{
+    internal static readonly PrivateIdentifierNameComparer _instance = new();
+
+    public bool Equals(PrivateIdentifier? x, PrivateIdentifier? y)
+    {
+        return x?.Name == y?.Name;
+    }
+
+    public int GetHashCode(PrivateIdentifier obj)
+    {
+        return obj.Name.GetHashCode();
+    }
+}
+

+ 2 - 2
Jint/Runtime/Environments/EnvironmentRecord.cs

@@ -116,7 +116,7 @@ namespace Jint.Runtime.Environments
         internal sealed class BindingName
         {
             public readonly Key Key;
-            public readonly JsString StringValue;
+            public readonly JsString Value;
             public readonly bool HasEvalOrArguments;
             public readonly JsValue? CalculatedValue;
 
@@ -124,7 +124,7 @@ namespace Jint.Runtime.Environments
             {
                 var key = (Key) value;
                 Key = key;
-                StringValue = JsString.Create(value);
+                Value = JsString.Create(value);
                 HasEvalOrArguments = key == KnownKeys.Eval || key == KnownKeys.Arguments;
                 if (key == KnownKeys.Undefined)
                 {

+ 2 - 2
Jint/Runtime/Environments/GlobalEnvironmentRecord.cs

@@ -57,7 +57,7 @@ namespace Jint.Runtime.Environments
                 return _globalObject.HasProperty(name.Key);
             }
 
-            return _global.HasProperty(name.StringValue);
+            return _global.HasProperty(name.Value);
         }
 
         internal override bool TryGetBinding(
@@ -99,7 +99,7 @@ namespace Jint.Runtime.Environments
             value = default;
 
             var parent = _global._prototype!;
-            var property = parent.GetOwnProperty(name.StringValue);
+            var property = parent.GetOwnProperty(name.Value);
 
             if (property == PropertyDescriptor.Undefined)
             {

+ 7 - 7
Jint/Runtime/Environments/ObjectEnvironmentRecord.cs

@@ -47,7 +47,7 @@ namespace Jint.Runtime.Environments
 
         internal override bool HasBinding(BindingName name)
         {
-            var foundBinding = HasProperty(name.StringValue);
+            var foundBinding = HasProperty(name.Value);
 
             if (!foundBinding)
             {
@@ -59,7 +59,7 @@ namespace Jint.Runtime.Environments
                 return true;
             }
 
-            return !IsBlocked(name.StringValue);
+            return !IsBlocked(name.Value);
         }
 
         private bool HasProperty(JsValue property)
@@ -76,19 +76,19 @@ namespace Jint.Runtime.Environments
             // we unwrap by name
             binding = default;
 
-            if (!HasProperty(name.StringValue))
+            if (!HasProperty(name.Value))
             {
                 value = default;
                 return false;
             }
 
-            if (_withEnvironment && IsBlocked(name.StringValue))
+            if (_withEnvironment && IsBlocked(name.Value))
             {
                 value = default;
                 return false;
             }
 
-            var desc = _bindingObject.GetProperty(name.StringValue);
+            var desc = _bindingObject.GetProperty(name.Value);
             value = ObjectInstance.UnwrapJsValue(desc, _bindingObject);
             return true;
         }
@@ -147,12 +147,12 @@ namespace Jint.Runtime.Environments
 
         internal override void SetMutableBinding(BindingName name, JsValue value, bool strict)
         {
-            if (strict && !_bindingObject.HasProperty(name.StringValue))
+            if (strict && !_bindingObject.HasProperty(name.Value))
             {
                 ExceptionHelper.ThrowReferenceNameError(_engine.Realm, name.Key);
             }
 
-            _bindingObject.Set(name.StringValue, value);
+            _bindingObject.Set(name.Value, value);
         }
 
         public override JsValue GetBindingValue(string name, bool strict)

+ 24 - 25
Jint/Runtime/Environments/PrivateEnvironmentRecord.cs

@@ -1,35 +1,34 @@
-namespace Jint.Runtime.Environments
+using Esprima.Ast;
+using Jint.Native;
+
+namespace Jint.Runtime.Environments;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-privateenvironment-records
+/// </summary>
+internal sealed class PrivateEnvironmentRecord
 {
-    /// <summary>
-    /// https://tc39.es/ecma262/#sec-privateenvironment-records
-    /// </summary>
-    internal sealed class PrivateEnvironmentRecord
+    public PrivateEnvironmentRecord(PrivateEnvironmentRecord? outerPrivEnv)
     {
-        private readonly PrivateEnvironmentRecord? _outerPrivateEnvironment;
-        private readonly List<PrivateName> _names = new();
+        OuterPrivateEnvironment = outerPrivEnv;
+    }
 
-        private readonly record struct PrivateName(string Name, string Description);
+    public PrivateEnvironmentRecord? OuterPrivateEnvironment { get; }
+    public Dictionary<PrivateIdentifier, PrivateName> Names { get; } = new();
 
-        public PrivateEnvironmentRecord(PrivateEnvironmentRecord? outerPrivEnv)
-        {
-            _outerPrivateEnvironment = outerPrivEnv;
-        }
-
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-resolve-private-identifier
-        /// </summary>
-        public string? ResolvePrivateIdentifier(string identifier)
+    /// <summary>
+    /// https://tc39.es/ecma262/#sec-resolve-private-identifier
+    /// </summary>
+    public PrivateName? ResolvePrivateIdentifier(string identifier)
+    {
+        foreach (var pn in Names)
         {
-            var names = _names;
-            foreach (var privateName in names)
+            if (pn.Value.Description == identifier)
             {
-                if (privateName.Description == identifier)
-                {
-                    return privateName.Name;
-                }
+                return pn.Value;
             }
-
-            return _outerPrivateEnvironment?.ResolvePrivateIdentifier(identifier);
         }
+
+        return OuterPrivateEnvironment?.ResolvePrivateIdentifier(identifier);
     }
 }

+ 1 - 1
Jint/Runtime/ExceptionHelper.cs

@@ -40,7 +40,7 @@ namespace Jint.Runtime
         [DoesNotReturn]
         public static void ThrowReferenceError(Realm realm, Reference reference)
         {
-            ThrowReferenceNameError(realm, reference?.GetReferencedName()?.ToString());
+            ThrowReferenceNameError(realm, reference?.ReferencedName?.ToString());
         }
 
         [DoesNotReturn]

+ 1 - 1
Jint/Runtime/Interpreter/Expressions/BindingPatternAssignmentExpression.cs

@@ -444,7 +444,7 @@ namespace Jint.Runtime.Interpreter.Expressions
             }
             else
             {
-                if (checkReference && lhs.IsUnresolvableReference() && StrictModeScope.IsStrictModeCode)
+                if (checkReference && lhs.IsUnresolvableReference && StrictModeScope.IsStrictModeCode)
                 {
                     ExceptionHelper.ThrowReferenceError(engine.Realm, lhs);
                 }

+ 24 - 24
Jint/Runtime/Interpreter/Expressions/JintArrowFunctionExpression.cs

@@ -2,35 +2,35 @@ using Esprima.Ast;
 using Jint.Native;
 using Jint.Native.Function;
 
-namespace Jint.Runtime.Interpreter.Expressions
-{
-    internal sealed class JintArrowFunctionExpression : JintExpression
-    {
-        private readonly JintFunctionDefinition _function;
+namespace Jint.Runtime.Interpreter.Expressions;
 
-        public JintArrowFunctionExpression(ArrowFunctionExpression function) : base(function)
-        {
-            _function = new JintFunctionDefinition(function);
-        }
+internal sealed class JintArrowFunctionExpression : JintExpression
+{
+    private readonly JintFunctionDefinition _function;
 
-        protected override object EvaluateInternal(EvaluationContext context)
-        {
-            var engine = context.Engine;
-            var scope = engine.ExecutionContext.LexicalEnvironment;
+    public JintArrowFunctionExpression(ArrowFunctionExpression function) : base(function)
+    {
+        _function = new JintFunctionDefinition(function);
+    }
 
-            var closure = new ScriptFunctionInstance(
-                engine,
-                _function,
-                scope,
-                FunctionThisMode.Lexical,
-                proto: engine.Realm.Intrinsics.Function.PrototypeObject);
+    protected override object EvaluateInternal(EvaluationContext context)
+    {
+        var engine = context.Engine;
+        var env = engine.ExecutionContext.LexicalEnvironment;
+        var privateEnv = engine.ExecutionContext.PrivateEnvironment;
 
-            if (_function.Name is null)
-            {
-                closure.SetFunctionName(JsString.Empty);
-            }
+        var closure = engine.Realm.Intrinsics.Function.OrdinaryFunctionCreate(
+            engine.Realm.Intrinsics.Function.PrototypeObject,
+            _function,
+            FunctionThisMode.Lexical,
+            env,
+            privateEnv);
 
-            return closure;
+        if (_function.Name is null)
+        {
+            closure.SetFunctionName(JsString.Empty);
         }
+
+        return closure;
     }
 }

+ 2 - 2
Jint/Runtime/Interpreter/Expressions/JintAssignmentExpression.cs

@@ -316,7 +316,7 @@ namespace Jint.Runtime.Interpreter.Expressions
             }
 
             // if we did string concatenation in-place, we don't need to update records, objects might have evil setters
-            if (!wasMutatedInPlace || lref.GetBase() is not EnvironmentRecord)
+            if (!wasMutatedInPlace || lref.Base is not EnvironmentRecord)
             {
                 engine.PutValue(lref, newLeftValue!);
             }
@@ -418,7 +418,7 @@ namespace Jint.Runtime.Interpreter.Expressions
 
                     if (right._expression.IsFunctionDefinition())
                     {
-                        ((FunctionInstance) rval).SetFunctionName(left.Identifier.StringValue);
+                        ((FunctionInstance) rval).SetFunctionName(left.Identifier.Value);
                     }
 
                     environmentRecord.SetMutableBinding(left.Identifier, rval, strict);

+ 7 - 0
Jint/Runtime/Interpreter/Expressions/JintBinaryExpression.cs

@@ -621,6 +621,13 @@ namespace Jint.Runtime.Interpreter.Expressions
                     ExceptionHelper.ThrowTypeError(context.Engine.Realm, "in can only be used with an object");
                 }
 
+                if (left.IsPrivateName())
+                {
+                    var privateEnv = context.Engine.ExecutionContext.PrivateEnvironment!;
+                    var privateName = privateEnv.ResolvePrivateIdentifier(((PrivateName) left).ToString());
+                    return privateName is not null && oi.PrivateElementFind(privateName) is not null ? JsBoolean.True : JsBoolean.False;
+                }
+
                 return oi.HasProperty(left) ? JsBoolean.True : JsBoolean.False;
             }
         }

+ 14 - 8
Jint/Runtime/Interpreter/Expressions/JintCallExpression.cs

@@ -103,8 +103,8 @@ namespace Jint.Runtime.Interpreter.Expressions
             var referenceRecord = reference as Reference;
             if (ReferenceEquals(func, engine.Realm.Intrinsics.Eval)
                 && referenceRecord != null
-                && !referenceRecord.IsPropertyReference()
-                && referenceRecord.GetReferencedName() == CommonProperties.Eval)
+                && !referenceRecord.IsPropertyReference
+                && referenceRecord.ReferencedName == CommonProperties.Eval)
             {
                 return HandleEval(context, func, engine, referenceRecord);
             }
@@ -117,13 +117,13 @@ namespace Jint.Runtime.Interpreter.Expressions
             JsValue thisObject;
             if (referenceRecord is not null)
             {
-                if (referenceRecord.IsPropertyReference())
+                if (referenceRecord.IsPropertyReference)
                 {
-                    thisObject = referenceRecord.GetThisValue();
+                    thisObject = referenceRecord.ThisValue;
                 }
                 else
                 {
-                    var baseValue = referenceRecord.GetBase();
+                    var baseValue = referenceRecord.Base;
 
                     // deviation from the spec to support null-propagation helper
                     if (baseValue.IsNullOrUndefined()
@@ -207,7 +207,7 @@ namespace Jint.Runtime.Interpreter.Expressions
         [MethodImpl(MethodImplOptions.NoInlining)]
         private static void ThrowReferenceNotFunction(Reference? referenceRecord1, object reference, Engine engine)
         {
-            var message = $"{referenceRecord1?.GetReferencedName() ?? reference} is not a function";
+            var message = $"{referenceRecord1?.ReferencedName ?? reference} is not a function";
             ExceptionHelper.ThrowTypeError(engine.Realm, message);
         }
 
@@ -217,7 +217,7 @@ namespace Jint.Runtime.Interpreter.Expressions
         {
             var message = referenceRecord1 == null
                 ? reference + " is not a function"
-                : $"Property '{referenceRecord1.GetReferencedName()}' of object is not a function";
+                : $"Property '{referenceRecord1.ReferencedName}' of object is not a function";
             ExceptionHelper.ThrowTypeError(engine.Realm, message);
         }
 
@@ -253,8 +253,14 @@ namespace Jint.Runtime.Interpreter.Expressions
             var defaultSuperCall = ReferenceEquals(_expression, ClassDefinition._defaultSuperCall);
             var argList = defaultSuperCall ? DefaultSuperCallArgumentListEvaluation(context) : ArgumentListEvaluation(context);
             var result = ((IConstructor) func).Construct(argList, newTarget);
+
             var thisER = (FunctionEnvironmentRecord) engine.ExecutionContext.GetThisEnvironment();
-            return thisER.BindThisValue(result);
+            thisER.BindThisValue(result);
+            var F = thisER._functionObject;
+
+            result.InitializeInstanceElements((ScriptFunctionInstance) F);
+
+            return result;
         }
 
         /// <summary>

+ 2 - 1
Jint/Runtime/Interpreter/Expressions/JintExpression.cs

@@ -124,6 +124,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 Nodes.ConditionalExpression => new JintConditionalExpression((ConditionalExpression) expression),
                 Nodes.FunctionExpression => new JintFunctionExpression((FunctionExpression) expression),
                 Nodes.Identifier => new JintIdentifierExpression((Identifier) expression),
+                Nodes.PrivateIdentifier => new JintPrivateIdentifierExpression((PrivateIdentifier) expression),
                 Nodes.Literal => JintLiteralExpression.Build((Literal) expression),
                 Nodes.LogicalExpression => ((BinaryExpression) expression).Operator switch
                 {
@@ -143,7 +144,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 Nodes.TemplateLiteral => new JintTemplateLiteralExpression((TemplateLiteral) expression),
                 Nodes.TaggedTemplateExpression => new JintTaggedTemplateExpression((TaggedTemplateExpression) expression),
                 Nodes.ClassExpression => new JintClassExpression((ClassExpression) expression),
-                Nodes.Import => new JintImportExpression((Import) expression),
+                Nodes.ImportExpression => new JintImportExpression((ImportExpression) expression),
                 Nodes.Super => new JintSuperExpression((Super) expression),
                 Nodes.MetaProperty => new JintMetaPropertyExpression((MetaProperty) expression),
                 Nodes.ChainExpression => ((ChainExpression) expression).Expression.Type == Nodes.CallExpression

+ 2 - 2
Jint/Runtime/Interpreter/Expressions/JintFunctionExpression.cs

@@ -53,7 +53,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 funcEnv.CreateImmutableBinding(name!, strict: false);
             }
 
-            var privateScope = runningExecutionContext.PrivateEnvironment;
+            var privateEnv = runningExecutionContext.PrivateEnvironment;
 
             var thisMode = _function.Strict
                 ? FunctionThisMode.Strict
@@ -65,7 +65,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 _function,
                 thisMode,
                 funcEnv ?? scope,
-                privateScope
+                privateEnv
             );
 
             if (name is not null)

+ 52 - 53
Jint/Runtime/Interpreter/Expressions/JintIdentifierExpression.cs

@@ -5,79 +5,78 @@ using Jint.Native;
 using Jint.Native.Argument;
 using Jint.Runtime.Environments;
 
-namespace Jint.Runtime.Interpreter.Expressions
+namespace Jint.Runtime.Interpreter.Expressions;
+
+internal sealed class JintIdentifierExpression : JintExpression
 {
-    internal sealed class JintIdentifierExpression : JintExpression
+    public JintIdentifierExpression(Identifier expression) : base(expression)
     {
-        public JintIdentifierExpression(Identifier expression) : base(expression)
-        {
-        }
+    }
 
-        internal EnvironmentRecord.BindingName Identifier
-        {
-            get => (EnvironmentRecord.BindingName) (_expression.AssociatedData ??= new EnvironmentRecord.BindingName(((Identifier) _expression).Name));
-        }
+    internal EnvironmentRecord.BindingName Identifier
+    {
+        get => (EnvironmentRecord.BindingName) (_expression.AssociatedData ??= new EnvironmentRecord.BindingName(((Identifier) _expression).Name));
+    }
 
-        public bool HasEvalOrArguments => Identifier.HasEvalOrArguments;
+    public bool HasEvalOrArguments => Identifier.HasEvalOrArguments;
 
-        protected override object EvaluateInternal(EvaluationContext context)
-        {
-            var engine = context.Engine;
-            var env = engine.ExecutionContext.LexicalEnvironment;
-            var strict = StrictModeScope.IsStrictModeCode;
-            var identifierEnvironment = JintEnvironment.TryGetIdentifierEnvironmentWithBinding(env, Identifier, out var temp)
-                ? temp
-                : JsValue.Undefined;
+    protected override object EvaluateInternal(EvaluationContext context)
+    {
+        var engine = context.Engine;
+        var env = engine.ExecutionContext.LexicalEnvironment;
+        var strict = StrictModeScope.IsStrictModeCode;
+        var identifierEnvironment = JintEnvironment.TryGetIdentifierEnvironmentWithBinding(env, Identifier, out var temp)
+            ? temp
+            : JsValue.Undefined;
 
-            return engine._referencePool.Rent(identifierEnvironment, Identifier.StringValue, strict, thisValue: null);
-        }
+        return engine._referencePool.Rent(identifierEnvironment, Identifier.Value, strict, thisValue: null);
+    }
 
-        public override JsValue GetValue(EvaluationContext context)
-        {
-            // need to notify correct node when taking shortcut
-            context.LastSyntaxElement = _expression;
+    public override JsValue GetValue(EvaluationContext context)
+    {
+        // need to notify correct node when taking shortcut
+        context.LastSyntaxElement = _expression;
 
-            if (Identifier.CalculatedValue is not null)
-            {
-                return Identifier.CalculatedValue;
-            }
+        if (Identifier.CalculatedValue is not null)
+        {
+            return Identifier.CalculatedValue;
+        }
 
-            var strict = StrictModeScope.IsStrictModeCode;
-            var engine = context.Engine;
-            var env = engine.ExecutionContext.LexicalEnvironment;
+        var strict = StrictModeScope.IsStrictModeCode;
+        var engine = context.Engine;
+        var env = engine.ExecutionContext.LexicalEnvironment;
 
-            if (JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
+        if (JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
                 env,
                 Identifier,
                 strict,
                 out _,
                 out var value))
+        {
+            if (value is null)
             {
-                if (value is null)
-                {
-                    ThrowNotInitialized(engine);
-                }
-            }
-            else
-            {
-                var reference = engine._referencePool.Rent(JsValue.Undefined, Identifier.StringValue, strict, thisValue: null);
-                value = engine.GetValue(reference, true);
-            }
-
-            // make sure arguments access freezes state
-            if (value is ArgumentsInstance argumentsInstance)
-            {
-                argumentsInstance.Materialize();
+                ThrowNotInitialized(engine);
             }
-
-            return value;
+        }
+        else
+        {
+            var reference = engine._referencePool.Rent(JsValue.Undefined, Identifier.Value, strict, thisValue: null);
+            value = engine.GetValue(reference, true);
         }
 
-        [DoesNotReturn]
-        [MethodImpl(MethodImplOptions.NoInlining)]
-        private void ThrowNotInitialized(Engine engine)
+        // make sure arguments access freezes state
+        if (value is ArgumentsInstance argumentsInstance)
         {
-            ExceptionHelper.ThrowReferenceError(engine.Realm, Identifier.Key.Name + " has not been initialized");
+            argumentsInstance.Materialize();
         }
+
+        return value;
+    }
+
+    [DoesNotReturn]
+    [MethodImpl(MethodImplOptions.NoInlining)]
+    private void ThrowNotInitialized(Engine engine)
+    {
+        ExceptionHelper.ThrowReferenceError(engine.Realm, Identifier.Key.Name + " has not been initialized");
     }
 }

+ 2 - 2
Jint/Runtime/Interpreter/Expressions/JintImportExpression.cs

@@ -8,7 +8,7 @@ internal sealed class JintImportExpression : JintExpression
 {
     private JintExpression _importExpression;
 
-    public JintImportExpression(Import expression) : base(expression)
+    public JintImportExpression(ImportExpression expression) : base(expression)
     {
         _initialized = false;
         _importExpression = null!;
@@ -16,7 +16,7 @@ internal sealed class JintImportExpression : JintExpression
 
     protected override void Initialize(EvaluationContext context)
     {
-        var expression = ((Import) _expression).Source;
+        var expression = ((ImportExpression) _expression).Source;
         _importExpression = Build(expression);
     }
 

+ 2 - 1
Jint/Runtime/Interpreter/Expressions/JintLiteralExpression.cs

@@ -75,7 +75,8 @@ namespace Jint.Runtime.Interpreter.Expressions
             var expression = (Literal) _expression;
             if (expression.TokenType == TokenType.RegularExpression)
             {
-                return context.Engine.Realm.Intrinsics.RegExp.Construct((System.Text.RegularExpressions.Regex) expression.Value!, expression.Regex!.Pattern, expression.Regex.Flags);
+                var regExpLiteral = (RegExpLiteral) _expression;
+                return context.Engine.Realm.Intrinsics.RegExp.Construct((System.Text.RegularExpressions.Regex) regExpLiteral.Value!, regExpLiteral.Regex.Pattern, regExpLiteral.Regex.Flags);
             }
 
             return JsValue.FromObject(context.Engine, expression.Value);

+ 20 - 2
Jint/Runtime/Interpreter/Expressions/JintMemberExpression.cs

@@ -27,7 +27,10 @@ namespace Jint.Runtime.Interpreter.Expressions
 
             if (!_memberExpression.Computed)
             {
-                _determinedProperty = ((Identifier) _memberExpression.Property).Name;
+                if (_memberExpression.Property is Identifier identifier)
+                {
+                    _determinedProperty = identifier.Name;
+                }
             }
             else if (_memberExpression.Property.Type == Nodes.Literal)
             {
@@ -81,7 +84,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 }
                 if (baseReference is Reference reference)
                 {
-                    baseReferenceName = reference.GetReferencedName().ToString();
+                    baseReferenceName = reference.ReferencedName.ToString();
                     baseValue = engine.GetValue(reference, false);
                     engine._referencePool.Return(reference);
                 }
@@ -107,6 +110,11 @@ namespace Jint.Runtime.Interpreter.Expressions
                 TypeConverter.CheckObjectCoercible(engine, baseValue, _memberExpression.Property, referenceName!);
             }
 
+            if (property.IsPrivateName())
+            {
+                return MakePrivateReference(engine, baseValue, property);
+            }
+
             // only convert if necessary
             var propertyKey = property.IsInteger() && baseValue.IsIntegerIndexedArray
                 ? property
@@ -114,5 +122,15 @@ namespace Jint.Runtime.Interpreter.Expressions
 
             return context.Engine._referencePool.Rent(baseValue, propertyKey, isStrictModeCode, thisValue: actualThis);
         }
+
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-makeprivatereference
+        /// </summary>
+        private object MakePrivateReference(Engine engine, JsValue baseValue, JsValue privateIdentifier)
+        {
+            var privEnv = engine.ExecutionContext.PrivateEnvironment;
+            var privateName = privEnv!.ResolvePrivateIdentifier(privateIdentifier.ToString());
+            return engine._referencePool.Rent(baseValue, privateName!, strict: true, thisValue: null);
+        }
     }
 }

+ 4 - 3
Jint/Runtime/Interpreter/Expressions/JintObjectExpression.cs

@@ -221,11 +221,12 @@ namespace Jint.Runtime.Interpreter.Expressions
                 else if (property.Kind == PropertyKind.Get || property.Kind == PropertyKind.Set)
                 {
                     var function = objectProperty.GetFunctionDefinition(engine);
-                    var closure = new ScriptFunctionInstance(
-                        engine,
+                    var closure = engine.Realm.Intrinsics.Function.OrdinaryFunctionCreate(
+                        engine.Realm.Intrinsics.Function.PrototypeObject,
                         function,
+                        function.ThisMode,
                         engine.ExecutionContext.LexicalEnvironment,
-                        function.ThisMode);
+                        engine.ExecutionContext.PrivateEnvironment);
 
                     closure.SetFunctionName(propName, property.Kind == PropertyKind.Get ? "get" : "set");
                     closure.MakeMethod(obj);

+ 28 - 0
Jint/Runtime/Interpreter/Expressions/JintPrivateIdentifierExpression.cs

@@ -0,0 +1,28 @@
+using Esprima.Ast;
+
+namespace Jint.Runtime.Interpreter.Expressions;
+
+internal sealed class JintPrivateIdentifierExpression : JintExpression
+{
+    private readonly string _privateIdentifierString;
+
+    public JintPrivateIdentifierExpression(PrivateIdentifier expression) : base(expression)
+    {
+        _privateIdentifierString = expression.Name;
+    }
+
+    protected override object EvaluateInternal(EvaluationContext context)
+    {
+        var engine = context.Engine;
+        var env = engine.ExecutionContext.PrivateEnvironment;
+
+        var privateIdentifier = env!.ResolvePrivateIdentifier(_privateIdentifierString);
+        if (privateIdentifier is not null)
+        {
+            return privateIdentifier;
+        }
+
+        ExceptionHelper.ThrowReferenceError(engine.Realm, "TODO Not found!!");
+        return null;
+    }
+}

+ 2 - 2
Jint/Runtime/Interpreter/Expressions/JintTaggedTemplateExpression.cs

@@ -49,8 +49,8 @@ internal sealed class JintTaggedTemplateExpression : JintExpression
             args[i + 1] = expressions[i].GetValue(context);
         }
 
-        var thisObject = identifier is Reference reference && reference.IsPropertyReference()
-            ? reference.GetBase()
+        var thisObject = identifier is Reference reference && reference.IsPropertyReference
+            ? reference.Base
             : JsValue.Undefined;
 
         var result = tagger.Call(thisObject, args);

+ 11 - 11
Jint/Runtime/Interpreter/Expressions/JintUnaryExpression.cs

@@ -89,7 +89,7 @@ namespace Jint.Runtime.Interpreter.Expressions
 
                 if (result is Reference rf)
                 {
-                    if (rf.IsUnresolvableReference())
+                    if (rf.IsUnresolvableReference)
                     {
                         engine._referencePool.Return(rf);
                         return JsString.UndefinedString;
@@ -210,9 +210,9 @@ namespace Jint.Runtime.Interpreter.Expressions
                         return JsBoolean.True;
                     }
 
-                    if (r.IsUnresolvableReference())
+                    if (r.IsUnresolvableReference)
                     {
-                        if (r.IsStrictReference())
+                        if (r.Strict)
                         {
                             ExceptionHelper.ThrowSyntaxError(engine.Realm, "Delete of an unqualified identifier in strict mode.");
                         }
@@ -221,24 +221,24 @@ namespace Jint.Runtime.Interpreter.Expressions
                         return JsBoolean.True;
                     }
 
-                    var referencedName = r.GetReferencedName();
-                    if (r.IsPropertyReference())
+                    var referencedName = r.ReferencedName;
+                    if (r.IsPropertyReference)
                     {
-                        if (r.IsSuperReference())
+                        if (r.IsSuperReference)
                         {
                             ExceptionHelper.ThrowReferenceError(engine.Realm, r);
                         }
 
-                        var o = TypeConverter.ToObject(engine.Realm, r.GetBase());
+                        var o = TypeConverter.ToObject(engine.Realm, r.Base);
                         var deleteStatus = o.Delete(referencedName);
                         if (!deleteStatus)
                         {
-                            if (r.IsStrictReference())
+                            if (r.Strict)
                             {
                                 ExceptionHelper.ThrowTypeError(engine.Realm, $"Cannot delete property '{referencedName}' of {o}");
                             }
 
-                            if (StrictModeScope.IsStrictModeCode && !r.GetBase().AsObject().GetProperty(referencedName).Configurable)
+                            if (StrictModeScope.IsStrictModeCode && !r.Base.AsObject().GetProperty(referencedName).Configurable)
                             {
                                 ExceptionHelper.ThrowTypeError(engine.Realm, $"Cannot delete property '{referencedName}' of {o}");
                             }
@@ -248,12 +248,12 @@ namespace Jint.Runtime.Interpreter.Expressions
                         return deleteStatus ? JsBoolean.True : JsBoolean.False;
                     }
 
-                    if (r.IsStrictReference())
+                    if (r.Strict)
                     {
                         ExceptionHelper.ThrowSyntaxError(engine.Realm);
                     }
 
-                    var bindings = (EnvironmentRecord) r.GetBase();
+                    var bindings = (EnvironmentRecord) r.Base;
                     var property = referencedName;
                     engine._referencePool.Return(r);
 

+ 1 - 1
Jint/Runtime/Interpreter/Statements/JintExportDefaultDeclaration.cs

@@ -21,7 +21,7 @@ internal sealed class JintExportDefaultDeclaration : JintStatement<ExportDefault
     {
         if (_statement.Declaration is ClassDeclaration classDeclaration)
         {
-            _classDefinition = new ClassDefinition(className: classDeclaration.Id?.Name, classDeclaration.SuperClass, classDeclaration.Body);
+            _classDefinition = new ClassDefinition(className: classDeclaration.Id?.Name ?? "default", classDeclaration.SuperClass, classDeclaration.Body);
         }
         else if (_statement.Declaration is FunctionDeclaration functionDeclaration)
         {

+ 2 - 2
Jint/Runtime/Interpreter/Statements/JintVariableDeclaration.cs

@@ -75,7 +75,7 @@ namespace Jint.Runtime.Interpreter.Statements
                         value = declaration.Init.GetValue(context).Clone();
                         if (declaration.Init._expression.IsFunctionDefinition())
                         {
-                            ((FunctionInstance) value).SetFunctionName(lhs.GetReferencedName());
+                            ((FunctionInstance) value).SetFunctionName(lhs.ReferencedName);
                         }
                     }
 
@@ -114,7 +114,7 @@ namespace Jint.Runtime.Interpreter.Statements
 
                         if (declaration.Init._expression.IsFunctionDefinition())
                         {
-                            ((FunctionInstance) value).SetFunctionName(lhs.GetReferencedName());
+                            ((FunctionInstance) value).SetFunctionName(lhs.ReferencedName);
                         }
 
                         engine.PutValue(lhs, value);

+ 1 - 1
Jint/Runtime/Modules/SourceTextModuleRecord.cs

@@ -319,7 +319,7 @@ internal class SourceTextModuleRecord : CyclicModuleRecord
                 var fd = new JintFunctionDefinition(d);
                 env.CreateMutableBinding(fn, true);
                 // TODO private scope
-                var fo = realm.Intrinsics.Function.InstantiateFunctionObject(fd, env, privateScope: null);
+                var fo = realm.Intrinsics.Function.InstantiateFunctionObject(fd, env, privateEnv: null);
                 if (fn == "*default*")
                 {
                     fo.SetFunctionName("default");

+ 79 - 63
Jint/Runtime/References/Reference.cs

@@ -3,92 +3,108 @@ using System.Runtime.CompilerServices;
 using Jint.Native;
 using Jint.Runtime.Environments;
 
-namespace Jint.Runtime.References
+namespace Jint.Runtime.References;
+
+/// <summary>
+/// https://tc39.es/ecma262/#sec-reference-record-specification-type
+/// </summary>
+public sealed class Reference
 {
+    private JsValue _base;
+    private JsValue _referencedName;
+    internal bool _strict;
+    private JsValue? _thisValue;
+
+    internal Reference(JsValue baseValue, JsValue referencedName, bool strict, JsValue? thisValue = null)
+    {
+        _base = baseValue;
+        _referencedName = referencedName;
+        _thisValue = thisValue;
+    }
+
     /// <summary>
-    /// Represents the Reference Specification Type
-    /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.7
+    /// The value or Environment Record which holds the binding. A [[Base]] of unresolvable indicates that the binding could not be resolved.
     /// </summary>
-    public sealed class Reference
+    public JsValue Base
     {
-        private JsValue _baseValue;
-        private JsValue _property;
-        internal bool _strict;
-        private JsValue? _thisValue;
-
-        public Reference(JsValue baseValue, JsValue property, bool strict, JsValue? thisValue = null)
-        {
-            _baseValue = baseValue;
-            _property = property;
-            _thisValue = thisValue;
-        }
-
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public JsValue GetBase() => _baseValue;
+        get => _base;
+    }
 
+    /// <summary>
+    /// The value or Environment Record which holds the binding. A [[Base]] of unresolvable indicates that the binding could not be resolved.
+    /// </summary>
+    public JsValue ReferencedName
+    {
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public JsValue GetReferencedName() => _property;
+        get => _referencedName;
+    }
 
+    /// <summary>
+    /// true if the Reference Record originated in strict mode code, false otherwise.
+    /// </summary>
+    public bool Strict
+    {
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public bool IsStrictReference() => _strict;
+        get => _strict;
+    }
 
+    public bool HasPrimitiveBase
+    {
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public bool HasPrimitiveBase()
-        {
-            return (_baseValue._type & InternalTypes.Primitive) != 0;
-        }
+        get => (_base._type & InternalTypes.Primitive) != 0;
+    }
 
+    public bool IsUnresolvableReference
+    {
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public bool IsUnresolvableReference()
-        {
-            return _baseValue._type == InternalTypes.Undefined;
-        }
+        get => _base._type == InternalTypes.Undefined;
+    }
 
-        public bool IsSuperReference()
-        {
-            return _thisValue is not null;
-        }
+    public bool IsSuperReference => _thisValue is not null;
+
+    // https://tc39.es/ecma262/#sec-ispropertyreference
 
+    public bool IsPropertyReference
+    {
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public bool IsPropertyReference()
-        {
-            // https://tc39.es/ecma262/#sec-ispropertyreference
-            return (_baseValue._type & (InternalTypes.Primitive | InternalTypes.Object)) != 0;
-        }
+        get => (_base._type & (InternalTypes.Primitive | InternalTypes.Object)) != 0;
+    }
 
-        public JsValue GetThisValue()
-        {
-            if (IsSuperReference())
-            {
-                return _thisValue!;
-            }
+    public JsValue ThisValue
+    {
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        get => IsSuperReference ? _thisValue! : Base;
+    }
 
-            return GetBase();
-        }
+    public bool IsPrivateReference
+    {
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        get => _referencedName._type == InternalTypes.PrivateName;
+    }
 
-        internal Reference Reassign(JsValue baseValue, JsValue name, bool strict, JsValue? thisValue)
-        {
-            _baseValue = baseValue;
-            _property = name;
-            _strict = strict;
-            _thisValue = thisValue;
+    internal Reference Reassign(JsValue baseValue, JsValue name, bool strict, JsValue? thisValue)
+    {
+        _base = baseValue;
+        _referencedName = name;
+        _strict = strict;
+        _thisValue = thisValue;
 
-            return this;
-        }
+        return this;
+    }
 
-        internal void AssertValid(Realm realm)
+    internal void AssertValid(Realm realm)
+    {
+        if (_strict
+            && (_base._type & InternalTypes.ObjectEnvironmentRecord) != 0
+            && (_referencedName == CommonProperties.Eval || _referencedName == CommonProperties.Arguments))
         {
-            if (_strict
-                && (_baseValue._type & InternalTypes.ObjectEnvironmentRecord) != 0
-                && (_property == CommonProperties.Eval || _property == CommonProperties.Arguments))
-            {
-                ExceptionHelper.ThrowSyntaxError(realm);
-            }
+            ExceptionHelper.ThrowSyntaxError(realm);
         }
+    }
 
-        internal void InitializeReferencedBinding(JsValue value)
-        {
-            ((EnvironmentRecord) _baseValue).InitializeBinding(TypeConverter.ToString(_property), value);
-        }
+    internal void InitializeReferencedBinding(JsValue value)
+    {
+        ((EnvironmentRecord) _base).InitializeBinding(TypeConverter.ToString(_referencedName), value);
     }
 }

+ 13 - 9
Jint/Runtime/TypeConverter.cs

@@ -49,15 +49,17 @@ namespace Jint.Runtime
         // primitive  types range end
         Object = 256,
 
+        PrivateName = 512,
+
         // internal usage
-        ObjectEnvironmentRecord = 512,
-        RequiresCloning = 1024,
-        Module = 2048,
+        ObjectEnvironmentRecord = 1024,
+        RequiresCloning = 2048,
+        Module = 4096,
 
         // the object doesn't override important GetOwnProperty etc which change behavior
-        PlainObject = 4096,
+        PlainObject = 8192,
         // our native array
-        Array = 8192,
+        Array = 16384,
 
         Primitive = Boolean | String | Number | Integer | BigInt | Symbol,
         InternalFlags = ObjectEnvironmentRecord | RequiresCloning | PlainObject | Array | Module
@@ -926,8 +928,8 @@ namespace Jint.Runtime
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static JsValue ToPropertyKey(JsValue o)
         {
-            const InternalTypes stringOrSymbol = InternalTypes.String | InternalTypes.Symbol;
-            return (o._type & stringOrSymbol) != 0
+            const InternalTypes PropertyKeys = InternalTypes.String | InternalTypes.Symbol | InternalTypes.PrivateName;
+            return (o._type & PropertyKeys) != 0
                 ? o
                 : ToPropertyKeyNonString(o);
         }
@@ -935,9 +937,9 @@ namespace Jint.Runtime
         [MethodImpl(MethodImplOptions.NoInlining)]
         private static JsValue ToPropertyKeyNonString(JsValue o)
         {
-            const InternalTypes stringOrSymbol = InternalTypes.String | InternalTypes.Symbol;
+            const InternalTypes PropertyKeys = InternalTypes.String | InternalTypes.Symbol | InternalTypes.PrivateName;
             var primitive = ToPrimitive(o, Types.String);
-            return (primitive._type & stringOrSymbol) != 0
+            return (primitive._type & PropertyKeys) != 0
                 ? primitive
                 : ToStringNonString(primitive);
         }
@@ -982,6 +984,8 @@ namespace Jint.Runtime
                     return "undefined";
                 case InternalTypes.Null:
                     return "null";
+                case InternalTypes.PrivateName:
+                    return o.ToString();
                 case InternalTypes.Object when o is IObjectWrapper p:
                     return p.Target?.ToString()!;
                 default:

+ 3 - 3
README.md

@@ -97,13 +97,13 @@ The entire execution engine was rebuild with performance in mind, in many cases
 
 #### ECMAScript 2022
 
--  Class Fields
+-  Class Fields
 - ✔ RegExp Match Indices
 - ❌ Top-level await
--  Ergonomic brand checks for Private Fields
+-  Ergonomic brand checks for Private Fields
 - ✔ `.at()`
 - ✔ Accessible `Object.prototype.hasOwnProperty` (`Object.hasOwn`)
--  Class Static Block
+-  Class Static Block
 - ✔ Error Cause
 
 #### ECMAScript Stage 3 (no version yet)