Browse Source

Implementing Arguments object

Sebastien Ros 12 years ago
parent
commit
ae2c00b4e0

+ 26 - 33
Jint.Benchmark/Program.cs

@@ -14,6 +14,8 @@ namespace Jint.Benchmark
             o.Baz = 42;
             o.Blah = o.Foo + o.Baz;
 
+            if(o.Blah != 'bar42') throw TypeError;
+
             function fib(n){
                 if(n<2) { 
                     return n; 
@@ -22,7 +24,7 @@ namespace Jint.Benchmark
                 return fib(n-1) + fib(n-2);  
             }
 
-            fib(3);
+            if(fib(3) != 8) throw TypeError;
         ";
 
         private static readonly string[] Sunspider = new string[]
@@ -32,11 +34,11 @@ namespace Jint.Benchmark
 
         static void Main(string[] args)
         {
-            bool runIronJs = true;
-            bool runJint = true;
-            bool runJurassic = true;
+            const bool runIronJs = true;
+            const bool runJint = true;
+            const bool runJurassic = true;
 
-            const int iterations = 1;
+            const int iterations = 1000;
             const bool reuseEngine = false;
 
             var watch = new Stopwatch();
@@ -45,30 +47,12 @@ namespace Jint.Benchmark
             {
                 var script = new WebClient().DownloadString(url);
 
-                // warming up engines
-                Jurassic.ScriptEngine jurassic;
-                if (runJurassic)
-                {
-                    jurassic = new Jurassic.ScriptEngine();
-                    jurassic.Execute(script);
-                }
-
-                Jint.Engine jint;
-                if (runJint)
-                {
-                    jint = new Jint.Engine();
-                    jint.Execute(script);
-                }
 
-                IronJS.Hosting.CSharp.Context ironjs;
                 if (runIronJs)
                 {
+                    IronJS.Hosting.CSharp.Context ironjs;
                     ironjs = new IronJS.Hosting.CSharp.Context();
                     ironjs.Execute(script);
-                }
-
-                if (runIronJs)
-                {
                     watch.Restart();
                     for (var i = 0; i < iterations; i++)
                     {
@@ -86,22 +70,31 @@ namespace Jint.Benchmark
 
                 if (runJint)
                 {
-                watch.Restart();
-                for (var i = 0; i < iterations; i++)
-                {
-                    if (!reuseEngine)
+                    Engine jint;
+                    jint = new Engine();
+                    jint.Execute(script);
+
+                    watch.Restart();
+                    for (var i = 0; i < iterations; i++)
                     {
-                        jint = new Jint.Engine();
-                    }
+                        if (!reuseEngine)
+                        {
+                            jint = new Jint.Engine();
+                        }
 
-                    jint.Execute(script);
-                }
+                        jint.Execute(script);
+                    }
 
-                Console.WriteLine("{2} | Jint: {0} iterations in {1} ms", iterations, watch.ElapsedMilliseconds, Path.GetFileName(url));
+                    Console.WriteLine("{2} | Jint: {0} iterations in {1} ms", iterations, watch.ElapsedMilliseconds,
+                                      Path.GetFileName(url));
                 }
 
                 if (runJurassic)
                 {
+                    Jurassic.ScriptEngine jurassic;
+                    jurassic = new Jurassic.ScriptEngine();
+                    jurassic.Execute(script);
+
                     watch.Restart();
                     for (var i = 0; i < iterations; i++)
                     {

+ 12 - 0
Jint.Tests/Runtime/EngineTests.cs

@@ -460,6 +460,18 @@ namespace Jint.Tests.Runtime
             ");
         }
 
+        [Fact]
+        public void FunctionArgumentsIsDefined()
+        {
+            RunTest(@"
+                function f() {
+                    assert(arguments.length > 0);
+                }
+
+                f(42);
+            ");
+        }
+
         [Fact]
         public void PrimitiveValueFunctions()
         {

+ 2 - 1
Jint/Jint.csproj

@@ -45,7 +45,8 @@
     <Compile Include="Native\Date\DateInstance.cs" />
     <Compile Include="Native\Error\ErrorConstructor.cs" />
     <Compile Include="Native\Error\ErrorInstance.cs" />
-    <Compile Include="Native\Function\ArgumentsObject.cs" />
+    <Compile Include="Native\Argument\ArgumentsObject.cs" />
+    <Compile Include="Native\Function\ThrowTypeError.cs" />
     <Compile Include="Native\Function\EvalFunctionInstance.cs" />
     <Compile Include="Native\Function\FunctionConstructor.cs" />
     <Compile Include="Native\Function\FunctionInstance.cs" />

+ 86 - 0
Jint/Native/Argument/ArgumentsObject.cs

@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using Jint.Native.Function;
+using Jint.Native.Object;
+using Jint.Runtime;
+using Jint.Runtime.Descriptors;
+using Jint.Runtime.Descriptors.Specialized;
+using Jint.Runtime.Environments;
+
+namespace Jint.Native.Argument
+{
+    /// <summary>
+    /// http://www.ecma-international.org/ecma-262/5.1/#sec-10.6
+    /// </summary>
+    public class ArgumentsInstance : ObjectInstance
+    {
+        public ArgumentsInstance(Engine engine, ObjectInstance prototype) : base(engine, prototype)
+        {
+            // todo: complete implementation
+        }
+
+        public static ArgumentsInstance CreateArgumentsObject(Engine engine, FunctionInstance func, string[] names, object[] args, EnvironmentRecord env, bool strict)
+        {
+            var len = args.Length;
+            var obj = new ArgumentsInstance(engine, engine.Object);
+            obj.DefineOwnProperty("length", new DataDescriptor(len) { Writable = true, Enumerable = false, Configurable = true }, false);
+            var map = engine.Object.Construct(Arguments.Empty);
+            var mappedNamed = new List<string>();
+            var indx = len - 1;
+            while (indx >= 0)
+            {
+                var indxStr = TypeConverter.ToString(indx);
+                var val = args[indx];
+                obj.DefineOwnProperty(indxStr, new DataDescriptor(val) { Writable = true, Enumerable = false, Configurable = true }, false);
+                if (indx < names.Length)
+                {
+                    var name = names[indx];
+                    if (!strict && !mappedNamed.Contains(name))
+                    {
+                        mappedNamed.Add(name);
+                        Func<string, object> g = n => env.GetBindingValue(name, false);
+                        var p = new Action<string, object>((n, o) => env.SetMutableBinding(name, o, true));
+
+                        map.DefineOwnProperty(indxStr, new ClrAccessDescriptor<string>(engine, g, p) { Configurable = true }, false);
+                    }
+                }
+                indx--;
+            }
+            if (mappedNamed.Count > 0)
+            {
+                obj.ParameterMap = map;
+            }
+            if (!strict)
+            {
+                obj.DefineOwnProperty("callee",
+                                      new DataDescriptor(func)
+                                      {
+                                          Writable = true,
+                                          Enumerable = false,
+                                          Configurable = false
+                                      }, false);
+            }
+            else
+            {
+                var thrower = engine.Function.ThrowTypeError;
+                obj.DefineOwnProperty("caller", new AccessorDescriptor(thrower, thrower) { Enumerable = false, Configurable = false }, false);
+                obj.DefineOwnProperty("callee", new AccessorDescriptor(thrower, thrower) { Enumerable = false, Configurable = false }, false);
+            }
+
+            return obj;
+        }
+
+        public ObjectInstance ParameterMap { get; set; }
+
+        public override string Class
+        {
+            get
+            {
+                return "Arguments";
+            }
+        }
+
+
+
+    }
+}

+ 0 - 15
Jint/Native/Function/ArgumentsObject.cs

@@ -1,15 +0,0 @@
-using Jint.Native.Object;
-
-namespace Jint.Native.Function
-{
-    /// <summary>
-    /// http://www.ecma-international.org/ecma-262/5.1/#sec-10.6
-    /// </summary>
-    public class ArgumentsInstance : ObjectInstance
-    {
-        public ArgumentsInstance(Engine engine, ObjectInstance prototype) : base(engine, prototype)
-        {
-            // todo: complete implementation
-        }
-    }
-}

+ 13 - 1
Jint/Native/Function/FunctionConstructor.cs

@@ -31,7 +31,7 @@ namespace Jint.Native.Function
 
         public ObjectInstance Construct(object[] arguments)
         {
-            var instance = new FunctionShim(_engine, Prototype, null, null);
+            var instance = new FunctionShim(_engine, Prototype, null, _engine.GlobalEnvironment);
             instance.DefineOwnProperty("constructor", new DataDescriptor(Prototype) { Writable = true, Enumerable = false, Configurable = false }, false);
 
             return instance;
@@ -55,5 +55,17 @@ namespace Jint.Native.Function
 
             return functionObject;
         }
+
+        private FunctionInstance _throwTypeError;
+        public FunctionInstance ThrowTypeError { get
+        {
+            if (_throwTypeError != null)
+            {
+                return _throwTypeError;
+            }
+
+            _throwTypeError = new ThrowTypeError(_engine);
+            return _throwTypeError;
+        }}
     }
 }

+ 9 - 2
Jint/Native/Function/ScriptFunctionInstance.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Linq;
+using Jint.Native.Argument;
 using Jint.Native.Object;
 using Jint.Parser;
 using Jint.Runtime;
@@ -30,6 +31,13 @@ namespace Jint.Native.Function
             DefineOwnProperty("name", new DataDescriptor(_functionDeclaration.Id), false);
             instancePrototype.DefineOwnProperty("constructor", new DataDescriptor(this) { Writable = true, Enumerable = true, Configurable = true }, false);
             DefineOwnProperty("prototype", new DataDescriptor(functionPrototype) { Writable = true, Enumerable = true, Configurable = true }, false);
+
+            if (strict)
+            {
+                var thrower = engine.Function.ThrowTypeError;
+                DefineOwnProperty("caller", new AccessorDescriptor(thrower) { Enumerable = false, Configurable = false }, false);
+                DefineOwnProperty("arguments", new AccessorDescriptor(thrower) { Enumerable = false, Configurable = false }, false);
+            }
         }
 
         /// <summary>
@@ -90,8 +98,7 @@ namespace Jint.Native.Function
 
             if (!argumentsAlreadyDeclared)
             {
-                // todo: ArgumentsInstance implementation
-                var argsObj = new ArgumentsInstance(_engine, null);
+                var argsObj = ArgumentsInstance.CreateArgumentsObject(_engine, this, _functionDeclaration.Parameters.Select(x => x.Name).ToArray(), arguments, env, Strict);
 
                 if (Strict)
                 {

+ 23 - 0
Jint/Native/Function/ThrowTypeError.cs

@@ -0,0 +1,23 @@
+using Jint.Parser.Ast;
+using Jint.Runtime;
+using Jint.Runtime.Descriptors;
+
+namespace Jint.Native.Function
+{
+    public sealed class ThrowTypeError : FunctionInstance
+    {
+        private readonly Engine _engine;
+
+        public ThrowTypeError(Engine engine): base(engine, engine.Function, new Identifier[0], engine.GlobalEnvironment, false)
+        {
+            _engine = engine;
+            DefineOwnProperty("length", new DataDescriptor(0) { Writable = false, Enumerable = false, Configurable = false }, false);
+            Extensible = false;
+        }
+
+        public override object Call(object thisObject, object[] arguments)
+        {
+            throw new JavaScriptException(_engine.TypeError);
+        }
+    }
+}