Преглед на файлове

Adding undefined state for object attributes

aka Writable, Enumerable and Configurable are nullable
Sebastien Ros преди 12 години
родител
ревизия
1e30fd461f

+ 2 - 2
Jint/Engine.cs

@@ -500,7 +500,7 @@ namespace Jint
                     {
                         var go = Global;
                         var existingProp = go.GetProperty(fn);
-                        if (existingProp.Configurable)
+                        if (existingProp.ConfigurableIsSet)
                         {
                             go.DefineOwnProperty(fn,
                                                  new DataDescriptor(Undefined.Instance)
@@ -512,7 +512,7 @@ namespace Jint
                         }
                         else
                         {
-                            if (existingProp.IsAccessorDescriptor() || (!existingProp.Enumerable))
+                            if (existingProp.IsAccessorDescriptor() || (!existingProp.EnumerableIsSet))
                             {
                                 throw new JavaScriptException(TypeError);
                             }

+ 3 - 3
Jint/Native/Array/ArrayInstance.cs

@@ -44,7 +44,7 @@ namespace Jint.Native.Array
                 {
                     return base.DefineOwnProperty("length", newLenDesc, throwOnError);
                 }
-                if (!oldLenDesc.Writable)
+                if (!oldLenDesc.WritableIsSet)
                 {
                     if (throwOnError)
                     {
@@ -54,7 +54,7 @@ namespace Jint.Native.Array
                     return false;
                 }
                 var newWritable = true;
-                if (!newLenDesc.Writable)
+                if (!newLenDesc.WritableIsSet)
                 {
                     newWritable = false;
                     newLenDesc.Writable = true;
@@ -93,7 +93,7 @@ namespace Jint.Native.Array
             else if (IsArrayIndex(propertyName))
             {
                 var index = TypeConverter.ToUint32(propertyName);
-                if (index >= oldLen && !oldLenDesc.Writable)
+                if (index >= oldLen && !oldLenDesc.WritableIsSet)
                 {
                     if (throwOnError)
                     {

+ 1 - 1
Jint/Native/Json/JsonSerializer.cs

@@ -299,7 +299,7 @@ namespace Jint.Native.Json
             var k = _propertyList;
             if (k == null)
             {
-                k = value.Properties.Where(x => x.Value.Enumerable).Select(x => x.Key).ToList();
+                k = value.Properties.Where(x => x.Value.EnumerableIsSet).Select(x => x.Key).ToList();
             }
             var partial = new List<string>();
             foreach (var p in k)

+ 42 - 31
Jint/Native/Object/ObjectConstructor.cs

@@ -115,14 +115,15 @@ namespace Jint.Native.Object
 
         public object GetOwnPropertyDescriptor(object thisObject, object[] arguments)
         {
-            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            var oArg = arguments.Length > 0 ? arguments[0] : Undefined.Instance;
+            if (TypeConverter.GetType(oArg) != TypeCode.Object)
             {
                 throw new JavaScriptException(Engine.TypeError);
             }
 
-            var o = thisObject as ObjectInstance;
+            var o = oArg as ObjectInstance;
 
-            var p = arguments.Length > 0 ? arguments[0] : Undefined.Instance;
+            var p = arguments.Length > 1 ? arguments[1] : Undefined.Instance;
             var name = TypeConverter.ToString(p);
 
             var desc = o.GetOwnProperty(name);
@@ -131,12 +132,13 @@ namespace Jint.Native.Object
 
         public object GetOwnPropertyNames(object thisObject, object[] arguments)
         {
-            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            var oArg = arguments.Length > 0 ? arguments[0] : Undefined.Instance;
+            if (TypeConverter.GetType(oArg) != TypeCode.Object)
             {
                 throw new JavaScriptException(Engine.TypeError);
             }
 
-            var o = thisObject as ObjectInstance;
+            var o = oArg as ObjectInstance;
 
             var array = Engine.Array.Construct(Arguments.Empty);
             var n = 0;
@@ -151,7 +153,8 @@ namespace Jint.Native.Object
 
         public object Create(object thisObject, object[] arguments)
         {
-            if (TypeConverter.GetType(thisObject) != TypeCode.Object && thisObject != Null.Instance)
+            var oArg = arguments.Length > 0 ? arguments[0] : Undefined.Instance;
+            if (TypeConverter.GetType(oArg) != TypeCode.Object)
             {
                 throw new JavaScriptException(Engine.TypeError);
             }
@@ -162,7 +165,7 @@ namespace Jint.Native.Object
             var properties = arguments.Length > 1 ? arguments[1] : Undefined.Instance;
             if (properties != Undefined.Instance)
             {
-                DefineProperties(obj, new [] {properties});
+                DefineProperties(thisObject, new [] {obj, properties});
             }
 
             return obj;
@@ -192,12 +195,13 @@ namespace Jint.Native.Object
 
         public object DefineProperties(object thisObject, object[] arguments)
         {
-            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            var oArg = arguments.Length > 0 ? arguments[0] : Undefined.Instance;
+            if (TypeConverter.GetType(oArg) != TypeCode.Object)
             {
                 throw new JavaScriptException(Engine.TypeError);
             }
 
-            var o = thisObject as ObjectInstance;
+            var o = oArg as ObjectInstance;
 
             var properties = arguments.Length > 1 ? arguments[1] : Undefined.Instance;
             var props = TypeConverter.ToObject(Engine, properties);
@@ -219,16 +223,17 @@ namespace Jint.Native.Object
 
         public object Seal(object thisObject, object[] arguments)
         {
-            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            var oArg = arguments.Length > 0 ? arguments[0] : Undefined.Instance;
+            if (TypeConverter.GetType(oArg) != TypeCode.Object)
             {
                 throw new JavaScriptException(Engine.TypeError);
             }
 
-            var o = thisObject as ObjectInstance;
+            var o = oArg as ObjectInstance;
 
             foreach (var prop in o.Properties)
             {
-                if (prop.Value.Configurable)
+                if (prop.Value.ConfigurableIsSet)
                 {
                     prop.Value.Configurable = false;
                 }
@@ -243,24 +248,25 @@ namespace Jint.Native.Object
 
         public object Freeze(object thisObject, object[] arguments)
         {
-            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            var oArg = arguments.Length > 0 ? arguments[0] : Undefined.Instance;
+            if (TypeConverter.GetType(oArg) != TypeCode.Object)
             {
                 throw new JavaScriptException(Engine.TypeError);
             }
 
-            var o = thisObject as ObjectInstance;
+            var o = oArg as ObjectInstance;
 
             foreach (var prop in o.Properties)
             {
                 if (prop.Value.IsDataDescriptor())
                 {
                     var datadesc = prop.Value.As<DataDescriptor>();
-                    if (datadesc.Writable)
+                    if (datadesc.WritableIsSet)
                     {
                         datadesc.Writable = false;
                     }
                 }
-                if (prop.Value.Configurable)
+                if (prop.Value.ConfigurableIsSet)
                 {
                     prop.Value.Configurable = false;
                 }
@@ -274,12 +280,13 @@ namespace Jint.Native.Object
 
         public object PreventExtensions(object thisObject, object[] arguments)
         {
-            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            var oArg = arguments.Length > 0 ? arguments[0] : Undefined.Instance;
+            if (TypeConverter.GetType(oArg) != TypeCode.Object)
             {
                 throw new JavaScriptException(Engine.TypeError);
             }
 
-            var o = thisObject as ObjectInstance;
+            var o = oArg as ObjectInstance;
 
             o.Extensible = false;
 
@@ -288,16 +295,17 @@ namespace Jint.Native.Object
 
         public object IsSealed(object thisObject, object[] arguments)
         {
-            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            var oArg = arguments.Length > 0 ? arguments[0] : Undefined.Instance;
+            if (TypeConverter.GetType(oArg) != TypeCode.Object)
             {
                 throw new JavaScriptException(Engine.TypeError);
             }
 
-            var o = thisObject as ObjectInstance;
+            var o = oArg as ObjectInstance;
 
             foreach (var prop in o.Properties)
             {
-                if (prop.Value.Configurable)
+                if (prop.Value.ConfigurableIsSet)
                 {
                     return false;
                 }
@@ -313,23 +321,24 @@ namespace Jint.Native.Object
 
         public object IsFrozen(object thisObject, object[] arguments)
         {
-            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            var oArg = arguments.Length > 0 ? arguments[0] : Undefined.Instance;
+            if (TypeConverter.GetType(oArg) != TypeCode.Object)
             {
                 throw new JavaScriptException(Engine.TypeError);
             }
 
-            var o = thisObject as ObjectInstance;
+            var o = oArg as ObjectInstance;
 
             foreach (var prop in o.Properties)
             {
                 if (prop.Value.IsDataDescriptor())
                 {
-                    if (prop.Value.As<DataDescriptor>().Writable)
+                    if (prop.Value.As<DataDescriptor>().WritableIsSet)
                     {
                         return false;
                     }
                 }
-                if (prop.Value.Configurable)
+                if (prop.Value.ConfigurableIsSet)
                 {
                     return false;
                 }
@@ -345,29 +354,31 @@ namespace Jint.Native.Object
 
         public object IsExtensible(object thisObject, object[] arguments)
         {
-            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            var oArg = arguments.Length > 0 ? arguments[0] : Undefined.Instance;
+            if (TypeConverter.GetType(oArg) != TypeCode.Object)
             {
                 throw new JavaScriptException(Engine.TypeError);
             }
 
-            var o = thisObject as ObjectInstance;
+            var o = oArg as ObjectInstance;
 
             return o.Extensible;
         }
 
         public object Keys(object thisObject, object[] arguments)
         {
-            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            var oArg = arguments.Length > 0 ? arguments[0] : Undefined.Instance;
+            if (TypeConverter.GetType(oArg) != TypeCode.Object)
             {
                 throw new JavaScriptException(Engine.TypeError);
             }
 
-            var o = thisObject as ObjectInstance;
+            var o = oArg as ObjectInstance;
 
-            var n = o.Properties.Values.Count(x => x.Enumerable);
+            var n = o.Properties.Values.Count(x => x.EnumerableIsSet);
             var array = Engine.Array.Construct(new object[] {n});
             var index = 0;
-            foreach (var prop in o.Properties.Where(x => x.Value.Enumerable))
+            foreach (var prop in o.Properties.Where(x => x.Value.EnumerableIsSet))
             {
                 array.DefineOwnProperty(index.ToString(), new DataDescriptor(prop.Key) { Writable = true, Enumerable = true, Configurable = true }, false);
                 index++;

+ 26 - 11
Jint/Native/Object/ObjectInstance.cs

@@ -156,7 +156,7 @@ namespace Jint.Native.Object
 
             if (ownDesc.IsDataDescriptor())
             {
-                var valueDesc = new DataDescriptor(value) { Writable = true, Enumerable = true, Configurable = true };
+                var valueDesc = new DataDescriptor(value);
                 DefineOwnProperty(propertyName, valueDesc, throwOnError);
                 return;
             }
@@ -199,8 +199,8 @@ namespace Jint.Native.Object
 
                     return true;
                 }
-                
-                return desc.As<DataDescriptor>().Writable;
+
+                return desc.As<DataDescriptor>().WritableIsSet;
             }
 
             if (Prototype == null)
@@ -231,7 +231,7 @@ namespace Jint.Native.Object
             }
             else
             {
-                return inherited.As<DataDescriptor>().Writable;
+                return inherited.As<DataDescriptor>().WritableIsSet;
             }
         }
 
@@ -264,7 +264,7 @@ namespace Jint.Native.Object
                 return true;
             }
 
-            if (desc.Configurable)
+            if (desc.ConfigurableIsSet)
             {
                 Properties.Remove(propertyName);
                 return true;
@@ -386,9 +386,9 @@ namespace Jint.Native.Object
 
             // todo: if desc and current are the same, return true
 
-            if (!current.Configurable)
+            if (!current.ConfigurableIsSet)
             {
-                if (desc.Configurable)
+                if (desc.ConfigurableIsSet)
                 {
                     if (throwOnError)
                     {
@@ -416,7 +416,7 @@ namespace Jint.Native.Object
 
             if (current.IsDataDescriptor() != desc.IsDataDescriptor())
             {
-                if (!current.Configurable)
+                if (!current.ConfigurableIsSet)
                 {
                     if (throwOnError)
                     {
@@ -436,9 +436,9 @@ namespace Jint.Native.Object
                 var cd = current.As<DataDescriptor>();
                 var dd = current.As<DataDescriptor>();
 
-                if (!current.Configurable)
+                if (!current.ConfigurableIsSet)
                 {
-                    if (!cd.Writable && dd.Writable)
+                    if (!cd.WritableIsSet && dd.WritableIsSet)
                     {
                         if (throwOnError)
                         {
@@ -448,13 +448,18 @@ namespace Jint.Native.Object
                         return false;
                     }
                 }
+
+                if (!dd.Writable.HasValue && cd.Writable.HasValue)
+                {
+                    dd.Enumerable = cd.Enumerable;
+                }
             }
             else if (current.IsAccessorDescriptor() && desc.IsAccessorDescriptor())
             {
                 var ca = current.As<AccessorDescriptor>();
                 var da = desc.As<AccessorDescriptor>();
 
-                if (!current.Configurable)
+                if (!current.ConfigurableIsSet)
                 {
                     if ( (da.Set != null && da.Set != ca.Set)
                         || (da.Get != null && da.Get != ca.Get))
@@ -471,6 +476,16 @@ namespace Jint.Native.Object
 
             Properties[propertyName] = desc;
 
+            if (!desc.Configurable.HasValue && current.Configurable.HasValue)
+            {
+                desc.Configurable = current.Configurable;
+            }
+
+            if (!desc.Enumerable.HasValue && current.Enumerable.HasValue)
+            {
+                desc.Enumerable = current.Enumerable;
+            }
+
             return true;
         }
 

+ 1 - 1
Jint/Native/Object/ObjectPrototype.cs

@@ -39,7 +39,7 @@ namespace Jint.Native.Object
             {
                 return false;
             }
-            return desc.Enumerable;
+            return desc.EnumerableIsSet;
         }
 
         private object ValueOf(object thisObject, object[] arguments)

+ 6 - 1
Jint/Runtime/Descriptors/DataDescriptor.cs

@@ -21,7 +21,12 @@
         /// If false, attempts by ECMAScript code to change the 
         /// property‘s [[Value]] attribute using [[Put]] will not succeed.
         /// </summary>
-        public bool Writable { get; set; }
+        public bool? Writable { get; set; }
+
+        public bool WritableIsSet
+        {
+            get { return Writable.HasValue && Writable.Value; }
+        }
 
         public override bool IsAccessorDescriptor()
         {

+ 12 - 2
Jint/Runtime/Descriptors/PropertyDescriptor.cs

@@ -15,14 +15,24 @@ namespace Jint.Runtime.Descriptors
         /// enumeration (see 12.6.4). Otherwise, the property is said 
         /// to be non-enumerable.
         /// </summary>
-        public bool Enumerable { get; set; }
+        public bool? Enumerable { get; set; }
+
+        public bool EnumerableIsSet
+        {
+            get { return Enumerable.HasValue && Enumerable.Value; }
+        }
 
         /// <summary>
         /// If false, attempts to delete the property, change the 
         /// property to be a data property, or change its attributes will 
         /// fail.
         /// </summary>
-        public bool Configurable { get; set; }
+        public bool? Configurable { get; set; }
+
+        public bool ConfigurableIsSet
+        {
+            get { return Configurable.HasValue && Configurable.Value; }
+        }
 
         /// <summary>
         /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.10.1

+ 1 - 1
Jint/Runtime/StatementInterpreter.cs

@@ -212,7 +212,7 @@ namespace Jint.Runtime
             foreach (var p in keys)
             {
                 var value = obj.Properties[p];
-                if (!value.Enumerable)
+                if (!value.EnumerableIsSet)
                 {
                     continue;
                 }