diff --git a/Jint.Tests.Test262/Language/ArgumentsObjectTests.cs b/Jint.Tests.Test262/Language/ArgumentsObjectTests.cs new file mode 100644 index 0000000000..de4e66aca4 --- /dev/null +++ b/Jint.Tests.Test262/Language/ArgumentsObjectTests.cs @@ -0,0 +1,15 @@ +using Xunit; + +namespace Jint.Tests.Test262.Language +{ + public class ArgumentsObjectTests : Test262Test + { + [Theory(DisplayName = "language\\arguments-object")] + [MemberData(nameof(SourceFiles), "language\\arguments-object", false)] + [MemberData(nameof(SourceFiles), "language\\arguments-object", true, Skip = "Skipped")] + protected void ArgumentsObject(SourceFile sourceFile) + { + RunTestInternal(sourceFile); + } + } +} \ No newline at end of file diff --git a/Jint.Tests.Test262/Language/ComputedPropertyNamesTests.cs b/Jint.Tests.Test262/Language/ComputedPropertyNamesTests.cs new file mode 100644 index 0000000000..68bbb916cc --- /dev/null +++ b/Jint.Tests.Test262/Language/ComputedPropertyNamesTests.cs @@ -0,0 +1,15 @@ +using Xunit; + +namespace Jint.Tests.Test262.Language +{ + public class ComputedPropertyNamesTests : Test262Test + { + [Theory(DisplayName = "language\\computed-property-names")] + [MemberData(nameof(SourceFiles), "language\\computed-property-names", false)] + [MemberData(nameof(SourceFiles), "language\\computed-property-names", true, Skip = "Skipped")] + protected void ComputedPropertyNames(SourceFile sourceFile) + { + RunTestInternal(sourceFile); + } + } +} \ No newline at end of file diff --git a/Jint.Tests.Test262/Language/Expressions/SuperTests.cs b/Jint.Tests.Test262/Language/Expressions/SuperTests.cs new file mode 100644 index 0000000000..457968299f --- /dev/null +++ b/Jint.Tests.Test262/Language/Expressions/SuperTests.cs @@ -0,0 +1,15 @@ +using Xunit; + +namespace Jint.Tests.Test262.Language.Expressions +{ + public class SuperTests : Test262Test + { + [Theory(DisplayName = "language\\expressions\\super")] + [MemberData(nameof(SourceFiles), "language\\expressions\\super", false)] + [MemberData(nameof(SourceFiles), "language\\expressions\\super", true, Skip = "Skipped")] + protected void Super(SourceFile sourceFile) + { + RunTestInternal(sourceFile); + } + } +} \ No newline at end of file diff --git a/Jint.Tests.Test262/test/skipped.json b/Jint.Tests.Test262/test/skipped.json index 46a6a8ac08..6ba0ee6eb5 100644 --- a/Jint.Tests.Test262/test/skipped.json +++ b/Jint.Tests.Test262/test/skipped.json @@ -268,6 +268,28 @@ "reason": "generators not implemented" }, + // Eval problems + + { + "source": "language/expressions/super/prop-dot-cls-val-from-eval.js", + "reason": "JavaScriptParser cannot handle direct 'super.property' script code" + }, + + { + "source": "language/expressions/super/prop-dot-obj-val-from-eval.js", + "reason": "JavaScriptParser cannot handle direct 'super.property' script code" + }, + + { + "source": "language/expressions/super/prop-expr-cls-val-from-eval.js", + "reason": "JavaScriptParser cannot handle direct 'super.property' script code" + }, + + { + "source": "language/expressions/super/prop-expr-obj-val-from-eval.js", + "reason": "JavaScriptParser cannot handle direct 'super.property' script code" + }, + // Esprima problems { diff --git a/Jint/EsprimaExtensions.cs b/Jint/EsprimaExtensions.cs index 7a8636f492..ec90c12818 100644 --- a/Jint/EsprimaExtensions.cs +++ b/Jint/EsprimaExtensions.cs @@ -42,11 +42,12 @@ public static JsValue GetKey(this Expression expression, Engine engine, bool res private static bool TryGetComputedPropertyKey(T expression, Engine engine, out JsValue propertyKey) where T : Expression { - if (expression.Type == Nodes.Identifier - || expression.Type == Nodes.CallExpression - || expression.Type == Nodes.BinaryExpression - || expression.Type == Nodes.UpdateExpression - || expression.Type == Nodes.AssignmentExpression + if (expression.Type is Nodes.Identifier + or Nodes.CallExpression + or Nodes.BinaryExpression + or Nodes.UpdateExpression + or Nodes.AssignmentExpression + or Nodes.UnaryExpression || expression is StaticMemberExpression) { propertyKey = TypeConverter.ToPropertyKey(JintExpression.Build(engine, expression).GetValue()); diff --git a/Jint/Jint.csproj b/Jint/Jint.csproj index e16df4d834..2b79227a79 100644 --- a/Jint/Jint.csproj +++ b/Jint/Jint.csproj @@ -8,7 +8,7 @@ true - + diff --git a/Jint/Native/Array/ArrayInstance.cs b/Jint/Native/Array/ArrayInstance.cs index 6f838dac4b..35fb03c5b4 100644 --- a/Jint/Native/Array/ArrayInstance.cs +++ b/Jint/Native/Array/ArrayInstance.cs @@ -258,7 +258,7 @@ protected override bool TryGetProperty(JsValue property, out PropertyDescriptor return base.TryGetProperty(property, out descriptor); } - public override List GetOwnPropertyKeys(Types types) + public override List GetOwnPropertyKeys(Types types = Types.None | Types.String | Types.Symbol) { var properties = new List(_dense?.Length ?? 0 + 1); if (_dense != null) diff --git a/Jint/Native/Function/EvalFunctionInstance.cs b/Jint/Native/Function/EvalFunctionInstance.cs index 054f71a30d..ad5b0c3063 100644 --- a/Jint/Native/Function/EvalFunctionInstance.cs +++ b/Jint/Native/Function/EvalFunctionInstance.cs @@ -80,7 +80,7 @@ public JsValue PerformEval(JsValue x, Realm callerRealm, bool strictCaller, bool } else { - ExceptionHelper.ThrowSyntaxError(callerRealm); + ExceptionHelper.ThrowSyntaxError(callerRealm, e.Message); } } diff --git a/Jint/Native/Function/FunctionInstance.cs b/Jint/Native/Function/FunctionInstance.cs index 5fe1c29b38..4ba7b72b33 100644 --- a/Jint/Native/Function/FunctionInstance.cs +++ b/Jint/Native/Function/FunctionInstance.cs @@ -105,23 +105,36 @@ public override IEnumerable> GetOwnPro public override List GetOwnPropertyKeys(Types types) { - var keys = new List(); - if (_prototypeDescriptor != null) + var keys = base.GetOwnPropertyKeys(types); + + // works around a problem where we don't use property for function names and classes should report it last + // as it's the last operation when creating a class constructor + if ((types & Types.String) != 0 && _nameDescriptor != null && this is ScriptFunctionInstance { _isClassConstructor: true }) { - keys.Add(CommonProperties.Prototype); + keys.Add(CommonProperties.Name); } + + return keys; + } + + internal override IEnumerable GetInitialOwnStringPropertyKeys() + { if (_length != null) { - keys.Add(CommonProperties.Length); + yield return CommonProperties.Length; } - if (_nameDescriptor != null) + + // works around a problem where we don't use property for function names and classes should report it last + // as it's the last operation when creating a class constructor + if (_nameDescriptor != null && this is not ScriptFunctionInstance { _isClassConstructor: true }) { - keys.Add(CommonProperties.Name); + yield return CommonProperties.Name; } - keys.AddRange(base.GetOwnPropertyKeys(types)); - - return keys; + if (_prototypeDescriptor != null) + { + yield return CommonProperties.Prototype; + } } public override PropertyDescriptor GetOwnProperty(JsValue property) diff --git a/Jint/Native/Function/ScriptFunctionInstance.cs b/Jint/Native/Function/ScriptFunctionInstance.cs index 788b7c8e28..f5123acb4a 100644 --- a/Jint/Native/Function/ScriptFunctionInstance.cs +++ b/Jint/Native/Function/ScriptFunctionInstance.cs @@ -11,7 +11,7 @@ namespace Jint.Native.Function { public sealed class ScriptFunctionInstance : FunctionInstance, IConstructor { - private bool _isClassConstructor; + internal bool _isClassConstructor; /// /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2 diff --git a/Jint/Native/Object/ObjectInstance.cs b/Jint/Native/Object/ObjectInstance.cs index 2dd289a5fb..6a050adfa0 100644 --- a/Jint/Native/Object/ObjectInstance.cs +++ b/Jint/Native/Object/ObjectInstance.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Dynamic; +using System.Linq; using System.Runtime.CompilerServices; using Jint.Collections; using Jint.Native.Array; @@ -217,8 +218,13 @@ public virtual List GetOwnPropertyKeys(Types types = Types.String | Typ { EnsureInitialized(); - var keys = new List(_properties?.Count ?? 0 + _symbols?.Count ?? 0); var propertyKeys = new List(); + if ((types & Types.String) != 0) + { + propertyKeys.AddRange(GetInitialOwnStringPropertyKeys()); + } + + var keys = new List(_properties?.Count ?? 0 + _symbols?.Count ?? 0 + propertyKeys.Count); List symbolKeys = null; if ((types & Types.String) != 0 && _properties != null) @@ -257,6 +263,8 @@ public virtual List GetOwnPropertyKeys(Types types = Types.String | Typ return keys; } + internal virtual IEnumerable GetInitialOwnStringPropertyKeys() => Enumerable.Empty(); + protected virtual void AddProperty(JsValue property, PropertyDescriptor descriptor) { SetProperty(property, descriptor); diff --git a/Jint/Native/Proxy/ProxyInstance.cs b/Jint/Native/Proxy/ProxyInstance.cs index bf1200b3e7..62a4f0b722 100644 --- a/Jint/Native/Proxy/ProxyInstance.cs +++ b/Jint/Native/Proxy/ProxyInstance.cs @@ -115,7 +115,7 @@ public override JsValue Get(JsValue property, JsValue receiver) return result; } - public override List GetOwnPropertyKeys(Types types) + public override List GetOwnPropertyKeys(Types types = Types.None | Types.String | Types.Symbol) { if (!TryCallHandler(TrapOwnKeys, new JsValue[] {_target }, out var result)) { diff --git a/Jint/Runtime/Environments/FunctionEnvironmentRecord.cs b/Jint/Runtime/Environments/FunctionEnvironmentRecord.cs index 0db9902cfd..7410e0e7a3 100644 --- a/Jint/Runtime/Environments/FunctionEnvironmentRecord.cs +++ b/Jint/Runtime/Environments/FunctionEnvironmentRecord.cs @@ -76,7 +76,7 @@ public JsValue GetSuperBase() var home = _functionObject._homeObject; return home.IsUndefined() ? Undefined - : ((ObjectInstance) home).GetPrototypeOf(); + : ((ObjectInstance) home).GetPrototypeOf() ?? Null; } // optimization to have logic near record internal structures. diff --git a/Jint/Runtime/Interpreter/Expressions/JintObjectExpression.cs b/Jint/Runtime/Interpreter/Expressions/JintObjectExpression.cs index 15b93fad0f..6395139ad1 100644 --- a/Jint/Runtime/Interpreter/Expressions/JintObjectExpression.cs +++ b/Jint/Runtime/Interpreter/Expressions/JintObjectExpression.cs @@ -190,6 +190,7 @@ private object BuildObjectNormal() isStrictModeCode); closure.SetFunctionName(propName, property.Kind == PropertyKind.Get ? "get" : "set"); + closure.MakeMethod(obj); var propDesc = new GetSetPropertyDescriptor( get: property.Kind == PropertyKind.Get ? closure : null,