Ver código fonte

Adding Binding class to reflect the specs

Sebastien Ros 12 anos atrás
pai
commit
7694318c3a

+ 1 - 0
Jint/Jint.csproj

@@ -143,6 +143,7 @@
     <Compile Include="Runtime\Descriptors\PropertyDescriptor.cs" />
     <Compile Include="Runtime\Descriptors\Specialized\ClrDataDescriptor.cs" />
     <Compile Include="Runtime\Descriptors\Specialized\ClrAccessDescriptor.cs" />
+    <Compile Include="Runtime\Environments\Binding.cs" />
     <Compile Include="Runtime\Environments\DeclarativeEnvironmentRecord.cs" />
     <Compile Include="Runtime\Environments\EnvironmentRecord.cs" />
     <Compile Include="Runtime\Environments\ExecutionContext.cs" />

+ 1 - 0
Jint/Native/Function/FunctionPrototype.cs

@@ -29,6 +29,7 @@ namespace Jint.Native.Function
 
         public void Configure()
         {
+            FastAddProperty("constructor", Engine.Function, false, false, false);
             FastAddProperty("toString", new ClrFunctionInstance<object, object>(Engine, ToFunctionString), false, false, false);
             FastAddProperty("apply", new ClrFunctionInstance<object, object>(Engine, Apply), false, false, false);
             FastAddProperty("call", new ClrFunctionInstance<object, object>(Engine, Call), false, false, false);

+ 17 - 7
Jint/Native/Function/ScriptFunctionInstance.cs

@@ -27,13 +27,13 @@ namespace Jint.Native.Function
         public ScriptFunctionInstance(Engine engine, IFunctionDeclaration functionDeclaration, LexicalEnvironment scope, bool strict)
             : base(engine, functionDeclaration.Parameters.Select(x => x.Name).ToArray(), scope, strict)
         {
+            _functionDeclaration = functionDeclaration;
 
             Engine = engine;
-            _functionDeclaration = functionDeclaration;
             Extensible = true;
-            
-            var len = functionDeclaration.Parameters.Count();
-            DefineOwnProperty("length", new DataDescriptor(len) { Writable = false, Enumerable = false, Configurable = false }, false);
+            Prototype = engine.Function.PrototypeObject;
+
+            DefineOwnProperty("length", new DataDescriptor(FormalParameters.Length) { Writable = false, Enumerable = false, Configurable = false }, false);
 
             var proto = engine.Object.Construct(Arguments.Empty);
             proto.DefineOwnProperty("constructor", new DataDescriptor(this) { Writable = true, Enumerable = false, Configurable = true }, false);
@@ -85,11 +85,15 @@ namespace Jint.Native.Function
             var env = localEnv.Record;
             var configurableBindings = false;
 
+            //if (/* todo: if code is eval code */)
+            //{
+            //    configurableBindings = true;
+            //}
+
             var argCount = arguments.Length;
             var n = 0;
-            foreach (var parameter in _functionDeclaration.Parameters)
+            foreach (var argName in FormalParameters)
             {
-                var argName = parameter.Name;
                 n++;
                 var v = n > argCount ? Undefined.Instance : arguments[n-1];
                 var argAlreadyDeclared = env.HasBinding(argName);
@@ -107,11 +111,17 @@ namespace Jint.Native.Function
 
             if (!argumentsAlreadyDeclared)
             {
-                var argsObj = ArgumentsInstance.CreateArgumentsObject(Engine, this, _functionDeclaration.Parameters.Select(x => x.Name).ToArray(), arguments, env, Strict);
+                var argsObj = ArgumentsInstance.CreateArgumentsObject(Engine, this, FormalParameters, arguments, env, Strict);
 
                 if (Strict)
                 {
                     var declEnv = env as DeclarativeEnvironmentRecord;
+                    
+                    if (declEnv == null)
+                    {
+                        throw new ArgumentException();
+                    }
+
                     declEnv.CreateImmutableBinding("arguments");
                     declEnv.InitializeImmutableBinding("arguments", argsObj);
                 }

+ 9 - 0
Jint/Runtime/Environments/Binding.cs

@@ -0,0 +1,9 @@
+namespace Jint.Runtime.Environments
+{
+    public class Binding
+    {
+        public object Value;
+        public bool CanBeDeleted;
+        public bool Mutable;
+    }
+}

+ 59 - 7
Jint/Runtime/Environments/DeclarativeEnvironmentRecord.cs

@@ -9,31 +9,77 @@ namespace Jint.Runtime.Environments
     /// </summary>
     public sealed class DeclarativeEnvironmentRecord : EnvironmentRecord
     {
-        private readonly IDictionary<string, object> _bindings = new Dictionary<string, object>();
+        private readonly Engine _engine;
+        private readonly IDictionary<string, Binding> _bindings = new Dictionary<string, Binding>();
+
+        public DeclarativeEnvironmentRecord(Engine engine)
+        {
+            _engine = engine;
+        }
 
         public override bool HasBinding(string name)
         {
             return _bindings.ContainsKey(name);
         }
 
-        public override void CreateMutableBinding(string name, bool canBeDeleted = true)
+        public override void CreateMutableBinding(string name, bool canBeDeleted = false)
         {
-            _bindings.Add(name, Undefined.Instance);
+            _bindings.Add(name, new Binding
+                {
+                    Value = Undefined.Instance, 
+                    CanBeDeleted =  canBeDeleted,
+                    Mutable = true
+                });
         }
 
         public override void SetMutableBinding(string name, object value, bool strict)
         {
-            _bindings[name] = value;
+            var binding = _bindings[name];
+            if (binding.Mutable)
+            {
+                binding.Value = value;
+            }
+            else
+            {
+                if (strict)
+                {
+                    throw new JavaScriptException(_engine.TypeError, "Can't update the value of an immutable binding.");
+                }
+            }
         }
 
         public override object GetBindingValue(string name, bool strict)
         {
-            return _bindings[name];
+            var binding = _bindings[name];
+
+            if (!binding.Mutable && binding.Value == null)
+            {
+                if (strict)
+                {
+                    throw new JavaScriptException(_engine.ReferenceError, "Can't access anm uninitiazed immutable binding.");
+                }
+
+                return Undefined.Instance;
+            }
+
+            return binding.Value;
         }
 
         public override bool DeleteBinding(string name)
         {
+            Binding binding;
+            if (!_bindings.TryGetValue(name, out binding))
+            {
+                return true;
+            }
+
+            if (!binding.CanBeDeleted)
+            {
+                return false;
+            }
+
             _bindings.Remove(name);
+            
             return true;
         }
 
@@ -48,7 +94,12 @@ namespace Jint.Runtime.Environments
         /// <param name="name">The identifier of the binding.</param>
         public void CreateImmutableBinding(string name)
         {
-            CreateMutableBinding(name);
+            _bindings.Add(name, new Binding
+                {
+                    Value = null,
+                    Mutable = false,
+                    CanBeDeleted = false
+                });
         }
 
         /// <summary>
@@ -58,7 +109,8 @@ namespace Jint.Runtime.Environments
         /// <param name="value">The value of the binding.</param>
         public void InitializeImmutableBinding(string name, object value)
         {
-            SetMutableBinding(name, value, false);
+            var binding = _bindings[name];
+            binding.Value = value;
         }
     }
 }

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

@@ -47,7 +47,7 @@ namespace Jint.Runtime.Environments
 
         public static LexicalEnvironment NewDeclarativeEnvironment(Engine engine, LexicalEnvironment outer = null)
         {
-            return new LexicalEnvironment(new DeclarativeEnvironmentRecord(), outer);
+            return new LexicalEnvironment(new DeclarativeEnvironmentRecord(engine), outer);
         }
 
         public static LexicalEnvironment NewObjectEnvironment(Engine engine, ObjectInstance objectInstance, LexicalEnvironment outer, bool provideThis)