Ver código fonte

Fix block-scoped function registrations (#859)

Marko Lahma 4 anos atrás
pai
commit
a44e845762

+ 0 - 4
Jint.Tests.Test262/Jint.Tests.Test262.csproj

@@ -16,8 +16,4 @@
     <PackageReference Include="xunit.runner.console" Version="2.4.1" />
     <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
   </ItemGroup>
-  <ItemGroup>
-    <None Remove="harness\**" />
-    <None Remove="test\**" />
-  </ItemGroup>
 </Project>

+ 1 - 6
Jint.Tests/Runtime/CallStackTests.cs

@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Xunit;
+using Xunit;
 
 namespace Jint.Tests.Runtime
 {

+ 0 - 5
Jint.Tests/Runtime/Debugger/DebugHandlerTests.cs

@@ -1,10 +1,5 @@
 using Jint.Native.Object;
 using Jint.Runtime.Debugger;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 using Xunit;
 
 namespace Jint.Tests.Runtime.Debugger

+ 27 - 0
Jint.Tests/Runtime/FunctionTests.cs

@@ -40,5 +40,32 @@ namespace Jint.Tests.Runtime
                     assert(a.foo === 'bar');
                 ");
         }
+        
+        [Fact]
+        public void BlockScopeFunctionShouldWork()
+        {
+            const string script = @"
+function execute(doc, args){
+    var i = doc;
+    {
+        function doSomething() {
+            return 'ayende';
+        }
+
+        i.Name = doSomething();
+    }
+}
+";
+
+            var engine = new Engine(options =>
+            {
+                options.Strict();
+            });
+            engine.Execute(script);
+
+            var obj = engine.Execute("var obj = {}; execute(obj); return obj;").GetCompletionValue().AsObject();
+
+            Assert.Equal("ayende", obj.Get("Name").AsString());
+        }
     }
 }

+ 3 - 3
Jint/Engine.cs

@@ -824,7 +824,7 @@ namespace Jint
                     ExceptionHelper.ThrowSyntaxError(this, $"Identifier '{fn}' has already been declared");
                 }
                 
-                var fo = Function.CreateFunctionObject(f, env);
+                var fo = Function.InstantiateFunctionObject(f, env);
                 envRec.CreateGlobalFunctionBinding(fn, fo, canBeDeleted: false);
             }
 
@@ -966,7 +966,7 @@ namespace Jint
             foreach (var f in functionsToInitialize)
             {
                 var fn = f.Id.Name;
-                var fo = Function.CreateFunctionObject(f, lexEnv);
+                var fo = Function.InstantiateFunctionObject(f, lexEnv);
                 varEnvRec.SetMutableBinding(fn, fo, strict: false);
             }
         }
@@ -1137,7 +1137,7 @@ namespace Jint
             foreach (var f in functionsToInitialize)
             {
                 var fn = f.Id.Name;
-                var fo = Function.CreateFunctionObject(f, lexEnv);
+                var fo = Function.InstantiateFunctionObject(f, lexEnv);
                 if (varEnvRec is GlobalEnvironmentRecord ger)
                 {
                     ger.CreateGlobalFunctionBinding(fn, fo, canBeDeleted: true);

+ 7 - 1
Jint/EsprimaExtensions.cs

@@ -100,6 +100,12 @@ namespace Jint
                 return;
             }
 
+            if (parameter is VariableDeclaration variableDeclaration)
+            {
+                variableDeclaration.GetBoundNames(target);
+                return;
+            }
+
             while (true)
             {
                 if (parameter is Identifier identifier)
@@ -107,7 +113,7 @@ namespace Jint
                     target.Add(identifier.Name!);
                     return;
                 }
-                
+
                 if (parameter is RestElement restElement)
                 {
                     parameter = restElement.Argument;

+ 9 - 10
Jint/HoistingScope.cs

@@ -58,34 +58,33 @@ namespace Jint
                 treeWalker._lexicalNames);
         }
 
-        public static List<VariableDeclaration> GetLexicalDeclarations(BlockStatement statement)
+        public static List<Declaration> GetLexicalDeclarations(BlockStatement statement)
         {
-            List<VariableDeclaration> lexicalDeclarations = null ;
+            List<Declaration> lexicalDeclarations = null ;
             ref readonly var statementListItems = ref statement.Body;
             for (var i = 0; i < statementListItems.Count; i++)
             {
                 var node = statementListItems[i];
-                if (node.Type != Nodes.VariableDeclaration)
+                if (node.Type != Nodes.VariableDeclaration && node.Type != Nodes.FunctionDeclaration)
                 {
                     continue;
                 }
 
-                var rootVariable = (VariableDeclaration) node;
-                if (rootVariable.Kind == VariableDeclarationKind.Var)
+                if (node is VariableDeclaration { Kind: VariableDeclarationKind.Var })
                 {
                     continue;
                 }
 
-                lexicalDeclarations ??= new List<VariableDeclaration>();
-                lexicalDeclarations.Add(rootVariable);
+                lexicalDeclarations ??= new List<Declaration>();
+                lexicalDeclarations.Add((Declaration) node);
             }
             
             return lexicalDeclarations;
         }
 
-        public static List<VariableDeclaration> GetLexicalDeclarations(SwitchCase statement)
+        public static List<Declaration> GetLexicalDeclarations(SwitchCase statement)
         {
-            List<VariableDeclaration> lexicalDeclarations = null ;
+            List<Declaration> lexicalDeclarations = null ;
             ref readonly var statementListItems = ref statement.Consequent;
             for (var i = 0; i < statementListItems.Count; i++)
             {
@@ -101,7 +100,7 @@ namespace Jint
                     continue;
                 }
 
-                lexicalDeclarations ??= new List<VariableDeclaration>();
+                lexicalDeclarations ??= new List<Declaration>();
                 lexicalDeclarations.Add(rootVariable);
             }
 

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

@@ -123,11 +123,9 @@ namespace Jint.Native.Function
         }
 
         /// <summary>
-        /// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
+        /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiatefunctionobject
         /// </summary>
-        /// <param name="functionDeclaration"></param>
-        /// <returns></returns>
-        public FunctionInstance CreateFunctionObject(FunctionDeclaration functionDeclaration, LexicalEnvironment env)
+        internal FunctionInstance InstantiateFunctionObject(FunctionDeclaration functionDeclaration, LexicalEnvironment env)
         {
             var functionObject = new ScriptFunctionInstance(
                 Engine,

+ 1 - 3
Jint/Runtime/Debugger/DebugScope.cs

@@ -1,6 +1,4 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
+using System.Collections.Generic;
 using Jint.Native;
 using Jint.Runtime.Environments;
 

+ 1 - 2
Jint/Runtime/Debugger/DebugScopes.cs

@@ -1,5 +1,4 @@
-using Jint.Native;
-using Jint.Runtime.Environments;
+using Jint.Runtime.Environments;
 using System.Collections;
 using System.Collections.Generic;
 

+ 1 - 1
Jint/Runtime/Environments/LexicalEnvironment.cs

@@ -12,7 +12,7 @@ namespace Jint.Runtime.Environments
     /// </summary>
     public sealed class LexicalEnvironment
     {
-        private readonly Engine _engine;
+        internal readonly Engine _engine;
         internal EnvironmentRecord _record;
         internal LexicalEnvironment _outer;
 

+ 11 - 10
Jint/Runtime/Interpreter/JintStatementList.cs

@@ -113,19 +113,19 @@ namespace Jint.Runtime.Interpreter
         /// </summary>
         internal static void BlockDeclarationInstantiation(
             LexicalEnvironment env,
-            List<VariableDeclaration> lexicalDeclarations)
+            List<Declaration> declarations)
         {
             var envRec = env._record;
             var boundNames = new List<string>();
-            for (var i = 0; i < lexicalDeclarations.Count; i++)
+            for (var i = 0; i < declarations.Count; i++)
             {
-                var variableDeclaration = lexicalDeclarations[i];
+                var d = declarations[i];
                 boundNames.Clear();
-                variableDeclaration.GetBoundNames(boundNames);
+                d.GetBoundNames(boundNames);
                 for (var j = 0; j < boundNames.Count; j++)
                 {
                     var dn = boundNames[j];
-                    if (variableDeclaration.Kind == VariableDeclarationKind.Const)
+                    if (d is VariableDeclaration { Kind: VariableDeclarationKind.Const })
                     {
                         envRec.CreateImmutableBinding(dn, strict: true);
                     }
@@ -135,11 +135,12 @@ namespace Jint.Runtime.Interpreter
                     }
                 }
 
-                /*  If d is a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration, then
-                 * Let fn be the sole element of the BoundNames of d.
-                 * Let fo be the result of performing InstantiateFunctionObject for d with argument env.
-                 * Perform envRec.InitializeBinding(fn, fo).
-                 */
+                if (d is FunctionDeclaration functionDeclaration)
+                {
+                    var fn = functionDeclaration.Id!.Name;
+                    var fo = env._engine.Function.InstantiateFunctionObject(functionDeclaration, env);
+                    envRec.InitializeBinding(fn, fo);
+                }
             }
         }
     }

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

@@ -7,7 +7,7 @@ namespace Jint.Runtime.Interpreter.Statements
     internal sealed class JintBlockStatement : JintStatement<BlockStatement>
     {
         private JintStatementList _statementList;
-        private List<VariableDeclaration> _lexicalDeclarations;
+        private List<Declaration> _lexicalDeclarations;
 
         public JintBlockStatement(Engine engine, BlockStatement blockStatement) : base(engine, blockStatement)
         {

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

@@ -121,7 +121,7 @@ namespace Jint.Runtime.Interpreter.Statements
         {
             internal readonly JintStatementList Consequent;
             internal readonly JintExpression Test;
-            internal readonly List<VariableDeclaration> LexicalDeclarations;
+            internal readonly List<Declaration> LexicalDeclarations;
 
             public JintSwitchCase(Engine engine, SwitchCase switchCase)
             {