From 91755e99493521062908a603349c11dd283a75dd Mon Sep 17 00:00:00 2001 From: Marko Lahma Date: Mon, 22 Jul 2024 22:57:58 +0300 Subject: [PATCH] Ensure Acornima ParseErrorException is exposed as JavasScriptException (#1924) --- Jint.Tests/Parser/JavascriptParserTests.cs | 7 +++- Jint.Tests/Runtime/ClassTests.cs | 30 +++++++++++++ Jint.Tests/Runtime/EngineTests.cs | 14 +++---- Jint/Engine.cs | 8 ++-- Jint/Extensions/AcornimaExtensions.cs | 42 +++++++++++++++++++ Jint/Native/Function/ClassDefinition.cs | 2 +- Jint/Native/Function/EvalFunction.cs | 16 +------ .../Function/FunctionInstance.Dynamic.cs | 2 +- Jint/Native/ShadowRealm/ShadowRealm.cs | 2 +- Jint/Runtime/Modules/ModuleFactory.cs | 16 +------ 10 files changed, 93 insertions(+), 46 deletions(-) create mode 100644 Jint/Extensions/AcornimaExtensions.cs diff --git a/Jint.Tests/Parser/JavascriptParserTests.cs b/Jint.Tests/Parser/JavascriptParserTests.cs index 0a2659895b..e224b61316 100644 --- a/Jint.Tests/Parser/JavascriptParserTests.cs +++ b/Jint.Tests/Parser/JavascriptParserTests.cs @@ -1,4 +1,6 @@ -namespace Jint.Tests.Parsing; +using Jint.Runtime; + +namespace Jint.Tests.Parsing; public class JavascriptParserTests { @@ -163,7 +165,8 @@ public void ShouldProvideLocationForMultiLinesStringLiterals() [Fact] public void ShouldThrowErrorForInvalidLeftHandOperation() { - Assert.Throws(() => new Engine().Execute("~ (WE0=1)--- l('1');")); + var ex = Assert.Throws(() => new Engine().Execute("~ (WE0=1)--- l('1');")); + Assert.Equal("Invalid left-hand side expression in postfix operation (:1:4)", ex.Message); } diff --git a/Jint.Tests/Runtime/ClassTests.cs b/Jint.Tests/Runtime/ClassTests.cs index b644451425..b3714f11cb 100644 --- a/Jint.Tests/Runtime/ClassTests.cs +++ b/Jint.Tests/Runtime/ClassTests.cs @@ -1,3 +1,5 @@ +using Jint.Runtime; + namespace Jint.Tests.Runtime; public class ClassTests @@ -45,4 +47,32 @@ get doubleWidth () { Assert.Equal(10, engine.Evaluate("board.width")); Assert.Equal(20, engine.Evaluate("board.doubleWidth ")); } + + [Fact] + public void PrivateMemberAccessOutsideOfClass() + { + var ex = Assert.Throws(() => new Engine().Evaluate + ( + """ + class A { } + new A().#nonexistent = 1; + """ + )); + + Assert.Equal("Private field '#nonexistent' must be declared in an enclosing class (:2:9)", ex.Message); + } + + [Fact] + public void PrivateMemberAccessAgainstUnknownMemberInConstructor() + { + var ex = Assert.Throws(() => new Engine().Evaluate + ( + """ + class A { constructor() { #nonexistent = 2; } } + new A(); + """ + )); + + Assert.Equal("Unexpected identifier '#nonexistent' (:1:27)", ex.Message); + } } diff --git a/Jint.Tests/Runtime/EngineTests.cs b/Jint.Tests/Runtime/EngineTests.cs index fcb75c010c..b403722d0c 100644 --- a/Jint.Tests/Runtime/EngineTests.cs +++ b/Jint.Tests/Runtime/EngineTests.cs @@ -1046,11 +1046,11 @@ public void ShouldGetParseErrorLocation() { engine.Evaluate("1.2+ new", "jQuery.js"); } - catch (SyntaxErrorException e) + catch (JavaScriptException e) { - Assert.Equal(1, e.LineNumber); - Assert.Equal(8, e.Column); - Assert.Equal("jQuery.js", e.SourceFile); + Assert.Equal(1, e.Location.Start.Line); + Assert.Equal(8, e.Location.Start.Column); + Assert.Equal("jQuery.js", e.Location.SourceFile); } } #region DateParsingAndStrings @@ -1314,7 +1314,7 @@ public void ShouldNotAllowDuplicateProtoProperty() { var code = "if({ __proto__: [], __proto__:[] } instanceof Array) {}"; - Exception ex = Assert.Throws(() => _engine.Execute(code, new ScriptParsingOptions { Tolerant = false })); + Exception ex = Assert.Throws(() => _engine.Execute(code, new ScriptParsingOptions { Tolerant = false })); Assert.Contains("Duplicate __proto__ fields are not allowed in object literals", ex.Message); ex = Assert.Throws(() => _engine.Execute($"eval('{code}')")); @@ -2865,8 +2865,8 @@ public void ShouldObeyScriptLevelStrictModeInFunctions() Assert.Equal("Cannot delete property 'prototype' of function Boolean() { [native code] }", ex.Message); const string source2 = "'use strict'; delete foobar;"; - var ex2 = Assert.Throws(() => engine.Evaluate(source2)); - Assert.Equal("Delete of an unqualified identifier in strict mode", ex2.Description); + ex = Assert.Throws(() => engine.Evaluate(source2)); + Assert.Equal("Delete of an unqualified identifier in strict mode (:1:22)", ex.Message); } [Fact] diff --git a/Jint/Engine.cs b/Jint/Engine.cs index 2ba6a12429..eae724f7b6 100644 --- a/Jint/Engine.cs +++ b/Jint/Engine.cs @@ -341,7 +341,7 @@ internal void ResetCallStack() /// public JsValue Evaluate(string code, string? source = null) { - var script = _defaultParser.ParseScript(code, source ?? "", _isStrict); + var script = _defaultParser.ParseScriptGuarded(Realm, code, source ?? "", _isStrict); return Evaluate(new Prepared