Browse Source

#451 don't translate flags to boolean?, separate *Set properties

Marko Lahma 7 years ago
parent
commit
8aef7b02e7

+ 2 - 2
Jint/Engine.cs

@@ -841,7 +841,7 @@ namespace Jint
                     {
                         var go = Global;
                         var existingProp = go.GetProperty(fn);
-                        if (existingProp.Configurable.Value)
+                        if (existingProp.Configurable)
                         {
                             go.DefineOwnProperty(fn,
                                 new PropertyDescriptor(
@@ -853,7 +853,7 @@ namespace Jint
                         }
                         else
                         {
-                            if (existingProp.IsAccessorDescriptor() || (!existingProp.Enumerable.Value))
+                            if (existingProp.IsAccessorDescriptor() || !existingProp.Enumerable)
                             {
                                 throw new JavaScriptException(TypeError);
                             }

+ 1 - 1
Jint/Native/Argument/ArgumentsInstance.cs

@@ -197,7 +197,7 @@ namespace Jint.Native.Argument
                             map.Put(propertyName, desc.Value, throwOnError);
                         }
 
-                        if (desc.Writable.HasValue && desc.Writable.Value == false)
+                        if (desc.WritableSet && !desc.Writable)
                         {
                             map.Delete(propertyName, false);
                         }

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

@@ -105,7 +105,7 @@ namespace Jint.Native.Array
                     return base.DefineOwnProperty("length", newLenDesc, throwOnError);
                 }
 
-                if (!oldLenDesc.Writable.Value)
+                if (!oldLenDesc.Writable)
                 {
                     if (throwOnError)
                     {
@@ -116,7 +116,7 @@ namespace Jint.Native.Array
                 }
 
                 bool newWritable;
-                if (!newLenDesc.Writable.HasValue || newLenDesc.Writable.Value)
+                if (!newLenDesc.WritableSet || newLenDesc.Writable)
                 {
                     newWritable = true;
                 }
@@ -239,7 +239,7 @@ namespace Jint.Native.Array
             }
             else if (IsArrayIndex(propertyName, out var index))
             {
-                if (index >= oldLen && !oldLenDesc.Writable.Value)
+                if (index >= oldLen && !oldLenDesc.Writable)
                 {
                     if (throwOnError)
                     {

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

@@ -317,7 +317,7 @@ namespace Jint.Native.Json
             _indent += _gap;
 
             var k = _propertyList ?? value.GetOwnProperties()
-                .Where(x => x.Value.Enumerable.HasValue && x.Value.Enumerable.Value == true)
+                .Where(x => x.Value.Enumerable)
                 .Select(x => x.Key)
                 .ToList();
 

+ 8 - 8
Jint/Native/Object/ObjectConstructor.cs

@@ -222,7 +222,7 @@ namespace Jint.Native.Object
             var descriptors = new List<KeyValuePair<string, PropertyDescriptor>>();
             foreach (var p in props.GetOwnProperties())
             {
-                if (!p.Value.Enumerable.HasValue || !p.Value.Enumerable.Value)
+                if (!p.Value.Enumerable)
                 {
                     continue;
                 }
@@ -252,7 +252,7 @@ namespace Jint.Native.Object
             foreach (var prop in properties)
             {
                 var propertyDescriptor = prop.Value;
-                if (propertyDescriptor.Configurable.HasValue && propertyDescriptor.Configurable.Value)
+                if (propertyDescriptor.Configurable)
                 {
                     var mutable = propertyDescriptor as PropertyDescriptor ?? new PropertyDescriptor(propertyDescriptor);
                     mutable.Configurable = false;
@@ -283,14 +283,14 @@ namespace Jint.Native.Object
                 var desc = o.GetOwnProperty(p.Key);
                 if (desc.IsDataDescriptor())
                 {
-                    if (desc.Writable.HasValue && desc.Writable.Value)
+                    if (desc.Writable)
                     {
                         var mutable = desc as PropertyDescriptor ?? new PropertyDescriptor(desc);
                         mutable.Writable = false;
                         desc = mutable;
                     }
                 }
-                if (desc.Configurable.HasValue && desc.Configurable.Value)
+                if (desc.Configurable)
                 {
                     var mutable = desc as PropertyDescriptor ?? new PropertyDescriptor(desc);
                     mutable.Configurable = false;
@@ -329,7 +329,7 @@ namespace Jint.Native.Object
 
             foreach (var prop in o.GetOwnProperties())
             {
-                if (prop.Value.Configurable.Value == true)
+                if (prop.Value.Configurable)
                 {
                     return false;
                 }
@@ -357,12 +357,12 @@ namespace Jint.Native.Object
                 var desc = pair.Value;
                 if (desc.IsDataDescriptor())
                 {
-                    if (desc.Writable.HasValue && desc.Writable.Value)
+                    if (desc.Writable)
                     {
                         return false;
                     }
                 }
-                if (desc.Configurable.HasValue && desc.Configurable.Value)
+                if (desc.Configurable)
                 {
                     return false;
                 }
@@ -398,7 +398,7 @@ namespace Jint.Native.Object
             }
 
             var enumerableProperties = o.GetOwnProperties()
-                .Where(x => x.Value.Enumerable.HasValue && x.Value.Enumerable.Value)
+                .Where(x => x.Value.Enumerable)
                 .ToArray();
             var n = enumerableProperties.Length;
 

+ 29 - 31
Jint/Native/Object/ObjectInstance.cs

@@ -331,7 +331,7 @@ namespace Jint.Native.Object
                     return true;
                 }
 
-                return desc.Writable.HasValue && desc.Writable.Value;
+                return desc.Writable;
             }
 
             if (Prototype == null)
@@ -360,10 +360,8 @@ namespace Jint.Native.Object
             {
                 return false;
             }
-            else
-            {
-                return inherited.Writable.HasValue && inherited.Writable.Value;
-            }
+
+            return inherited.Writable;
         }
 
         /// <summary>
@@ -396,7 +394,7 @@ namespace Jint.Native.Object
                 return true;
             }
 
-            if (desc.Configurable.HasValue && desc.Configurable.Value)
+            if (desc.Configurable)
             {
                 RemoveOwnProperty(propertyName);
                 return true;
@@ -509,11 +507,11 @@ namespace Jint.Native.Object
                     if (desc.IsGenericDescriptor() || desc.IsDataDescriptor())
                     {
                         IPropertyDescriptor propertyDescriptor;
-                        if (desc.Configurable.GetValueOrDefault() && desc.Enumerable.GetValueOrDefault() && desc.Writable.GetValueOrDefault())
+                        if (desc.Configurable && desc.Enumerable && desc.Writable)
                         {
                             propertyDescriptor = new ConfigurableEnumerableWritablePropertyDescriptor(desc.Value != null ? desc.Value : Undefined);
                         }
-                        else if (!desc.Configurable.GetValueOrDefault() && !desc.Enumerable.GetValueOrDefault() && !desc.Writable.GetValueOrDefault())
+                        else if (!desc.Configurable && !desc.Enumerable && !desc.Writable)
                         {
                             propertyDescriptor = new AllForbiddenPropertyDescriptor(desc.Value != null ? desc.Value : Undefined);
                         }
@@ -522,9 +520,9 @@ namespace Jint.Native.Object
                             propertyDescriptor = new PropertyDescriptor(desc)
                             {
                                 Value = desc.Value != null ? desc.Value : Undefined,
-                                Writable = desc.Writable.HasValue ? desc.Writable.Value : false,
-                                Enumerable = desc.Enumerable.HasValue ? desc.Enumerable.Value : false,
-                                Configurable = desc.Configurable.HasValue ? desc.Configurable.Value : false
+                                // TODO WritableSet = true,
+                                // TODO EnumerableSet = true,
+                                // TODO ConfigurableSet = true
                             };
                         }
 
@@ -534,8 +532,8 @@ namespace Jint.Native.Object
                     {
                         SetOwnProperty(propertyName, new GetSetPropertyDescriptor(desc)
                         {
-                            Enumerable = desc.Enumerable ?? false,
-                            Configurable = desc.Configurable ?? false,
+                            // TODO EnumerableSet = true,
+                            // TODO ConfigurableSet = true
                         });
                     }
                 }
@@ -544,9 +542,9 @@ namespace Jint.Native.Object
             }
 
             // Step 5
-            if (!current.Configurable.HasValue &&
-                !current.Enumerable.HasValue &&
-                !current.Writable.HasValue &&
+            if (!current.ConfigurableSet &&
+                !current.EnumerableSet &&
+                !current.WritableSet &&
                 current.Get == null &&
                 current.Set == null &&
                 current.Value == null)
@@ -556,9 +554,9 @@ namespace Jint.Native.Object
 
             // Step 6
             if (
-                current.Configurable == desc.Configurable &&
-                current.Writable == desc.Writable &&
-                current.Enumerable == desc.Enumerable &&
+                current.Configurable == desc.Configurable && current.ConfigurableSet == desc.ConfigurableSet &&
+                current.Writable == desc.Writable && current.WritableSet == desc.WritableSet &&
+                current.Enumerable == desc.Enumerable && current.EnumerableSet == desc.EnumerableSet &&
                 ((current.Get == null && desc.Get == null) || (current.Get != null && desc.Get != null && ExpressionInterpreter.SameValue(current.Get, desc.Get))) &&
                 ((current.Set == null && desc.Set == null) || (current.Set != null && desc.Set != null && ExpressionInterpreter.SameValue(current.Set, desc.Set))) &&
                 ((current.Value == null && desc.Value == null) || (current.Value != null && desc.Value != null && ExpressionInterpreter.StrictlyEqual(current.Value, desc.Value)))
@@ -567,9 +565,9 @@ namespace Jint.Native.Object
                 return true;
             }
 
-            if (!current.Configurable.HasValue || !current.Configurable.Value)
+            if (!current.Configurable)
             {
-                if (desc.Configurable.HasValue && desc.Configurable.Value)
+                if (desc.Configurable)
                 {
                     if (throwOnError)
                     {
@@ -579,7 +577,7 @@ namespace Jint.Native.Object
                     return false;
                 }
 
-                if (desc.Enumerable.HasValue && (!current.Enumerable.HasValue || desc.Enumerable.Value != current.Enumerable.Value))
+                if (desc.EnumerableSet && (desc.Enumerable != current.Enumerable))
                 {
                     if (throwOnError)
                     {
@@ -594,7 +592,7 @@ namespace Jint.Native.Object
             {
                 if (current.IsDataDescriptor() != desc.IsDataDescriptor())
                 {
-                    if (!current.Configurable.HasValue || !current.Configurable.Value)
+                    if (!current.Configurable)
                     {
                         if (throwOnError)
                         {
@@ -625,9 +623,9 @@ namespace Jint.Native.Object
                 }
                 else if (current.IsDataDescriptor() && desc.IsDataDescriptor())
                 {
-                    if (!current.Configurable.HasValue || current.Configurable.Value == false)
+                    if (!current.Configurable)
                     {
-                        if (!current.Writable.HasValue || !current.Writable.Value && desc.Writable.HasValue && desc.Writable.Value)
+                        if (!current.Writable && desc.Writable)
                         {
                             if (throwOnError)
                             {
@@ -637,7 +635,7 @@ namespace Jint.Native.Object
                             return false;
                         }
 
-                        if (!current.Writable.Value)
+                        if (!current.Writable)
                         {
                             if (desc.Value != null && !ExpressionInterpreter.SameValue(desc.Value, current.Value))
                             {
@@ -653,7 +651,7 @@ namespace Jint.Native.Object
                 }
                 else if (current.IsAccessorDescriptor() && desc.IsAccessorDescriptor())
                 {
-                    if (!current.Configurable.HasValue || !current.Configurable.Value)
+                    if (!current.Configurable)
                     {
                         if ((desc.Set != null && !ExpressionInterpreter.SameValue(desc.Set, current.Set != null ? current.Set : Undefined))
                             ||
@@ -676,19 +674,19 @@ namespace Jint.Native.Object
             }
 
             PropertyDescriptor mutable = null;
-            if (desc.Writable.HasValue)
+            if (desc.WritableSet)
             {
                 current = mutable = current as PropertyDescriptor ?? new PropertyDescriptor(current);
                 mutable.Writable = desc.Writable;
             }
 
-            if (desc.Enumerable.HasValue)
+            if (desc.EnumerableSet)
             {
                 current = mutable = current as PropertyDescriptor ?? new PropertyDescriptor(current);
                 mutable.Enumerable = desc.Enumerable;
             }
 
-            if (desc.Configurable.HasValue)
+            if (desc.ConfigurableSet)
             {
                 current = mutable = current as PropertyDescriptor ?? new PropertyDescriptor(current);
                 mutable.Configurable = desc.Configurable;
@@ -913,7 +911,7 @@ namespace Jint.Native.Object
 
                     foreach (var p in GetOwnProperties())
                     {
-                        if (!p.Value.Enumerable.HasValue || p.Value.Enumerable.Value == false)
+                        if (!p.Value.Enumerable)
                         {
                             continue;
                         }

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

@@ -38,7 +38,7 @@ namespace Jint.Native.Object
             {
                 return false;
             }
-            return desc.Enumerable.HasValue && desc.Enumerable.Value;
+            return desc.Enumerable;
         }
 
         private JsValue ValueOf(JsValue thisObject, JsValue[] arguments)

+ 8 - 3
Jint/Runtime/Descriptors/IPropertyDescriptor .cs

@@ -7,9 +7,14 @@ namespace Jint.Runtime.Descriptors
         JsValue Get { get; }
         JsValue Set { get; }
 
-        bool? Enumerable { get; }
-        bool? Writable { get; }
-        bool? Configurable { get; }
+        bool Enumerable { get; }
+        bool EnumerableSet { get; }
+        
+        bool Writable { get; }
+        bool WritableSet { get; }
+
+        bool Configurable { get; }
+        bool ConfigurableSet { get; }
 
         JsValue Value { get; set; }
     }

+ 121 - 44
Jint/Runtime/Descriptors/PropertyDescriptor.cs

@@ -30,72 +30,141 @@ namespace Jint.Runtime.Descriptors
         public PropertyDescriptor(JsValue value, bool? writable, bool? enumerable, bool? configurable)
         {
             Value = value;
-            Writable = writable;
-            Enumerable = enumerable;
-            Configurable = configurable;
+
+            Writable = writable.GetValueOrDefault();
+            WritableSet = writable != null;
+
+            Enumerable = enumerable.GetValueOrDefault();
+            EnumerableSet = enumerable != null;
+
+            Configurable = configurable.GetValueOrDefault();
+            ConfigurableSet = configurable != null;
         }
 
         public PropertyDescriptor(IPropertyDescriptor descriptor)
         {
             Value = descriptor.Value;
+
             Enumerable = descriptor.Enumerable;
+            EnumerableSet = descriptor.EnumerableSet;
+            
             Configurable = descriptor.Configurable;
+            ConfigurableSet = descriptor.ConfigurableSet;
+
             Writable = descriptor.Writable;
+            WritableSet = descriptor.WritableSet;
         }
 
         public virtual JsValue Get => null;
         public virtual JsValue Set => null;
 
-        public bool? Enumerable
+        public bool Enumerable
         {
             [MethodImpl(MethodImplOptions.AggressiveInlining)]
-            get => (_flags & PropertyFlag.EnumerableSet) != 0 ? (_flags & PropertyFlag.Enumerable) != 0 : (bool?) null;
+            get => (_flags & PropertyFlag.Enumerable) != 0;
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
             set
             {
-                _flags &= ~(PropertyFlag.EnumerableSet | PropertyFlag.Enumerable);
-                if (value != null)
+                _flags |= PropertyFlag.EnumerableSet;
+                if (value)
+                {
+                    _flags |= PropertyFlag.Enumerable;
+                }
+                else
+                {
+                    _flags &= ~(PropertyFlag.Enumerable);
+                }
+            }
+        }
+                
+        public bool EnumerableSet
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get => (_flags & (PropertyFlag.EnumerableSet | PropertyFlag.Enumerable)) != 0;
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            private set
+            {
+                if (value)
                 {
                     _flags |= PropertyFlag.EnumerableSet;
-                    if (value.Value)
-                    {
-                        _flags |= PropertyFlag.Enumerable;
-                    }
+                }
+                else
+                {
+                    _flags &= ~(PropertyFlag.EnumerableSet);
                 }
             }
         }
 
-        public bool? Writable
+        public bool Writable
         {
             [MethodImpl(MethodImplOptions.AggressiveInlining)]
-            get => (_flags & PropertyFlag.WritableSet) != 0 ? (_flags & PropertyFlag.Writable) != 0 : (bool?) null;
+            get => (_flags & PropertyFlag.Writable) != 0;
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
             set
             {
-                _flags &= ~(PropertyFlag.WritableSet | PropertyFlag.Writable);
-                if (value != null)
+                _flags |= PropertyFlag.WritableSet;
+                if (value)
+                {
+                    _flags |= PropertyFlag.Writable;
+                }
+                else
+                {
+                    _flags &= ~(PropertyFlag.Writable);
+                }
+            }
+        }
+
+        public bool WritableSet
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get => (_flags & (PropertyFlag.WritableSet | PropertyFlag.Writable)) != 0;
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            private set
+            {
+                if (value)
                 {
                     _flags |= PropertyFlag.WritableSet;
-                    if (value.Value)
-                    {
-                        _flags |= PropertyFlag.Writable;
-                    }
+                }
+                else
+                {
+                    _flags &= ~(PropertyFlag.WritableSet);
                 }
             }
         }
 
-        public bool? Configurable
+        public bool Configurable
         {
             [MethodImpl(MethodImplOptions.AggressiveInlining)]
-            get => (_flags & PropertyFlag.ConfigurableSet) != 0 ? (_flags & PropertyFlag.Configurable) != 0 : (bool?) null;
+            get => (_flags & PropertyFlag.Configurable) != 0;
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
             set
             {
-                _flags &= ~(PropertyFlag.ConfigurableSet | PropertyFlag.Configurable);
-                if (value != null)
+                _flags |= PropertyFlag.ConfigurableSet;
+                if (value)
+                {
+                    _flags |= PropertyFlag.Configurable;
+                }
+                else
+                {
+                    _flags &= ~(PropertyFlag.Configurable);
+                }
+            }
+        }
+        
+        public bool ConfigurableSet
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get => (_flags & (PropertyFlag.ConfigurableSet | PropertyFlag.Configurable)) != 0;
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            private set
+            {
+                if (value)
                 {
                     _flags |= PropertyFlag.ConfigurableSet;
-                    if (value.Value)
-                    {
-                        _flags |= PropertyFlag.Configurable;
-                    }
+                }
+                else
+                {
+                    _flags &= ~(PropertyFlag.ConfigurableSet);
                 }
             }
         }
@@ -110,8 +179,10 @@ namespace Jint.Runtime.Descriptors
                 throw new JavaScriptException(engine.TypeError);
             }
 
-            var hasGetProperty = obj.HasProperty("get");
-            var hasSetProperty = obj.HasProperty("set");
+            var getProperty = obj.GetProperty("get");
+            var hasGetProperty = getProperty != Undefined;
+            var setProperty = obj.GetProperty("set");
+            var hasSetProperty = setProperty != Undefined;
             
             if ((obj.HasProperty("value") || obj.HasProperty("writable")) &&
                 (hasGetProperty || hasSetProperty))
@@ -123,30 +194,36 @@ namespace Jint.Runtime.Descriptors
                 ? new GetSetPropertyDescriptor(null, null, null, null)
                 : new PropertyDescriptor();
 
-            if (obj.HasProperty("enumerable"))
+            var enumerableProperty = obj.GetProperty("enumerable");
+            if (enumerableProperty != Undefined)
             {
-                desc.Enumerable = TypeConverter.ToBoolean(obj.Get("enumerable"));
+                desc.Enumerable = TypeConverter.ToBoolean(obj.UnwrapJsValue(enumerableProperty));
+                desc.EnumerableSet = true;
             }
 
-            if (obj.HasProperty("configurable"))
+            var configurableProperty = obj.GetProperty("configurable");
+            if (configurableProperty != Undefined)
             {
-                desc.Configurable = TypeConverter.ToBoolean(obj.Get("configurable"));
+                desc.Configurable = TypeConverter.ToBoolean(obj.UnwrapJsValue(configurableProperty));
+                desc.ConfigurableSet = true;
             }
 
-            if (obj.HasProperty("value"))
+            var valueProperty = obj.GetProperty("value");
+            if (valueProperty != Undefined)
             {
-                var value = obj.Get("value");
-                desc.Value = value;
+                desc.Value = obj.UnwrapJsValue(valueProperty);
             }
 
-            if (obj.HasProperty("writable"))
+            var writableProperty = obj.GetProperty("writable");
+            if (writableProperty != Undefined)
             {
-                desc.Writable = TypeConverter.ToBoolean(obj.Get("writable"));
+                desc.Writable = TypeConverter.ToBoolean(obj.UnwrapJsValue(writableProperty));
+                desc.WritableSet = true;
             }
 
             if (hasGetProperty)
             {
-                var getter = obj.Get("get");
+                var getter = obj.UnwrapJsValue(getProperty);
                 if (getter != JsValue.Undefined && getter.TryCast<ICallable>() == null)
                 {
                     throw new JavaScriptException(engine.TypeError);
@@ -157,7 +234,7 @@ namespace Jint.Runtime.Descriptors
 
             if (hasSetProperty)
             {
-                var setter = obj.Get("set");
+                var setter = obj.UnwrapJsValue(setProperty);
                 if (setter != Native.Undefined.Instance && setter.TryCast<ICallable>() == null)
                 {
                     throw new JavaScriptException(engine.TypeError);
@@ -168,7 +245,7 @@ namespace Jint.Runtime.Descriptors
 
             if (desc.Get != null || desc.Get != null)
             {
-                if (desc.Value != null || desc.Writable.HasValue)
+                if (desc.Value != null || desc.WritableSet)
                 {
                     throw new JavaScriptException(engine.TypeError);
                 }
@@ -189,7 +266,7 @@ namespace Jint.Runtime.Descriptors
             if (desc.IsDataDescriptor())
             {
                 obj.SetOwnProperty("value", new ConfigurableEnumerableWritablePropertyDescriptor(desc.Value != null ? desc.Value : Native.Undefined.Instance));
-                obj.SetOwnProperty("writable", new ConfigurableEnumerableWritablePropertyDescriptor(desc.Writable.HasValue && desc.Writable.Value));
+                obj.SetOwnProperty("writable", new ConfigurableEnumerableWritablePropertyDescriptor(desc.Writable));
             }
             else
             {
@@ -197,8 +274,8 @@ namespace Jint.Runtime.Descriptors
                 obj.SetOwnProperty("set", new ConfigurableEnumerableWritablePropertyDescriptor(desc.Set ?? Native.Undefined.Instance));
             }
 
-            obj.SetOwnProperty("enumerable", new ConfigurableEnumerableWritablePropertyDescriptor(desc.Enumerable.HasValue && desc.Enumerable.Value));
-            obj.SetOwnProperty("configurable", new ConfigurableEnumerableWritablePropertyDescriptor(desc.Configurable.HasValue && desc.Configurable.Value));
+            obj.SetOwnProperty("enumerable", new ConfigurableEnumerableWritablePropertyDescriptor(desc.Enumerable));
+            obj.SetOwnProperty("configurable", new ConfigurableEnumerableWritablePropertyDescriptor(desc.Configurable));
 
             return obj;
         }

+ 1 - 1
Jint/Runtime/Descriptors/PropertyDescriptorExtensions.cs

@@ -15,7 +15,7 @@ namespace Jint.Runtime.Descriptors
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static bool IsDataDescriptor(this IPropertyDescriptor descriptor)
         {
-            return descriptor.Writable.HasValue || descriptor.Value != null;
+            return descriptor.WritableSet || descriptor.Value != null;
         }
 
         /// <summary>

+ 8 - 3
Jint/Runtime/Descriptors/Specialized/AllForbiddenPropertyDescriptor.cs

@@ -15,9 +15,14 @@ namespace Jint.Runtime.Descriptors.Specialized
         public JsValue Get => null;
         public JsValue Set => null;
 
-        public bool? Enumerable => false;
-        public bool? Writable => false;
-        public bool? Configurable => false;
+        public bool Enumerable => false;
+        public bool EnumerableSet => true;
+
+        public bool Writable => false;
+        public bool WritableSet => true;
+
+        public bool Configurable => false;
+        public bool ConfigurableSet => true;
 
         public JsValue Value { get; set; }
     }

+ 8 - 3
Jint/Runtime/Descriptors/Specialized/ConfigurableEnumerableWritablePropertyDescriptor.cs

@@ -15,9 +15,14 @@ namespace Jint.Runtime.Descriptors.Specialized
         public JsValue Get => null;
         public JsValue Set => null;
 
-        public bool? Enumerable => true;
-        public bool? Writable => true;
-        public bool? Configurable => true;
+        public bool Enumerable => true;
+        public bool EnumerableSet => true;
+        
+        public bool Writable => true;
+        public bool WritableSet => true;
+
+        public bool Configurable => true;
+        public bool ConfigurableSet => true;
 
         public JsValue Value { get; set; }
     }

+ 8 - 3
Jint/Runtime/Descriptors/Specialized/EnumerablePropertyDescriptor.cs

@@ -15,9 +15,14 @@ namespace Jint.Runtime.Descriptors.Specialized
         public JsValue Get => null;
         public JsValue Set => null;
 
-        public bool? Enumerable => true;
-        public bool? Writable => false;
-        public bool? Configurable => false;
+        public bool Enumerable => true;
+        public bool EnumerableSet => true;
+        
+        public bool Writable => false;
+        public bool WritableSet => true;
+
+        public bool Configurable => false;
+        public bool ConfigurableSet => true;
 
         public JsValue Value { get; set; }
     }

+ 1 - 2
Jint/Runtime/Descriptors/Specialized/GetSetPropertyDescriptor.cs

@@ -8,11 +8,10 @@ namespace Jint.Runtime.Descriptors.Specialized
         private JsValue _set;
 
         public GetSetPropertyDescriptor(JsValue get, JsValue set, bool? enumerable = null, bool? configurable = null)
+        : base(null, writable: null, enumerable: enumerable, configurable: configurable)
         {
             _get = get;
             _set = set;
-            Enumerable = enumerable;
-            Configurable = configurable;
         }
 
         public GetSetPropertyDescriptor(IPropertyDescriptor descriptor) : base(descriptor)

+ 0 - 1
Jint/Runtime/Descriptors/Specialized/IndexDescriptor.cs

@@ -49,7 +49,6 @@ namespace Jint.Runtime.Descriptors.Specialized
             Writable = true;
         }
 
-
         public IndexDescriptor(Engine engine, string key, object item)
             : this(engine, item.GetType(), key, item)
         {

+ 9 - 4
Jint/Runtime/Descriptors/Specialized/NonConfigurablePropertyDescriptor.cs

@@ -15,10 +15,15 @@ namespace Jint.Runtime.Descriptors.Specialized
         public JsValue Get => null;
         public JsValue Set => null;
 
-        public bool? Enumerable => true;
-        public bool? Writable => true;
-        public bool? Configurable => false;
-
+        public bool Enumerable => true;
+        public bool EnumerableSet => true;
+        
+        public bool Writable => true;
+        public bool WritableSet => true;
+        
+        public bool Configurable => false;
+        public bool ConfigurableSet => true;
+        
         public JsValue Value { get; set; }
     }
 }

+ 8 - 3
Jint/Runtime/Descriptors/Specialized/NonEnumerablePropertyDescriptor.cs

@@ -15,9 +15,14 @@ namespace Jint.Runtime.Descriptors.Specialized
         public JsValue Get => null;
         public JsValue Set => null;
 
-        public bool? Enumerable => false;
-        public bool? Writable => true;
-        public bool? Configurable => true;
+        public bool Enumerable => false;
+        public bool EnumerableSet => true;
+        
+        public bool Writable => true;
+        public bool WritableSet => true;
+        
+        public bool Configurable => true;
+        public bool ConfigurableSet => true;
 
         public JsValue Value { get; set; }
     }

+ 9 - 4
Jint/Runtime/Descriptors/Specialized/NullConfigurationPropertyDescriptor.cs

@@ -15,10 +15,15 @@ namespace Jint.Runtime.Descriptors.Specialized
         public JsValue Get => null;
         public JsValue Set => null;
 
-        public bool? Enumerable => null;
-        public bool? Writable => null;
-        public bool? Configurable => null;
-
+        public bool Enumerable => false;
+        public bool EnumerableSet => false;
+        
+        public bool Writable => false;
+        public bool WritableSet => false;
+        
+        public bool Configurable => false;
+        public bool ConfigurableSet => false;
+        
         public JsValue Value { get; set; }
     }
 }

+ 8 - 3
Jint/Runtime/Descriptors/Specialized/WritablePropertyDescriptor.cs

@@ -15,9 +15,14 @@ namespace Jint.Runtime.Descriptors.Specialized
         public JsValue Get => null;
         public JsValue Set => null;
 
-        public bool? Enumerable => false;
-        public bool? Writable => true;
-        public bool? Configurable => false;
+        public bool Enumerable => false;
+        public bool EnumerableSet => true;
+        
+        public bool Writable => true;
+        public bool WritableSet => true;
+        
+        public bool Configurable => false;
+        public bool ConfigurableSet => true;
 
         public JsValue Value { get; set; }
     }

+ 11 - 9
Jint/Runtime/ExpressionIntepreter.cs

@@ -815,14 +815,16 @@ namespace Jint.Runtime
         public JsValue EvaluateCallExpression(CallExpression callExpression)
         {
             var callee = EvaluateExpression(callExpression.Callee);
-
-            if (_engine.Options._IsDebugMode)
+            var options = _engine.Options;
+            var maxRecursionDepth = options._MaxRecursionDepth;
+            var debug = options._IsDebugMode;
+            
+            if (debug)
             {
                 _engine.DebugHandler.AddToDebugCallStack(callExpression);
             }
 
             JsValue thisObject;
-
             // todo: implement as in http://www.ecma-international.org/ecma-262/5.1/#sec-11.2.4
 
             var arguments = Array.Empty<JsValue>();
@@ -858,13 +860,13 @@ namespace Jint.Runtime
 
             var r = callee as Reference;
 
-            if (_engine.Options._MaxRecursionDepth >= 0)
+            if (maxRecursionDepth >= 0)
             {
                 var stackItem = new CallStackElement(callExpression, func, r != null ? r.GetReferencedName() : "anonymous function");
 
                 var recursionDepth = _engine.CallStack.Push(stackItem);
 
-                if (recursionDepth > _engine.Options._MaxRecursionDepth)
+                if (recursionDepth > maxRecursionDepth)
                 {
                     _engine.CallStack.Pop();
                     throw new RecursionDepthOverflowException(_engine.CallStack, stackItem.ToString());
@@ -879,8 +881,8 @@ namespace Jint.Runtime
             if (!func.IsObject())
             {
 
-                if (_engine.Options._ReferenceResolver == null ||
-                    !_engine.Options._ReferenceResolver.TryGetCallable(_engine, callee, out func))
+                if (options._ReferenceResolver == null ||
+                    !options._ReferenceResolver.TryGetCallable(_engine, callee, out func))
                 {
                     throw new JavaScriptException(_engine.TypeError,
                         r == null ? "" : string.Format("Property '{0}' of object is not a function", r.GetReferencedName()));
@@ -920,12 +922,12 @@ namespace Jint.Runtime
 
             var result = callable.Call(thisObject, arguments);
 
-            if (_engine.Options._IsDebugMode)
+            if (debug)
             {
                 _engine.DebugHandler.PopDebugCallStack();
             }
 
-            if (_engine.Options._MaxRecursionDepth >= 0)
+            if (maxRecursionDepth >= 0)
             {
                 _engine.CallStack.Pop();
             }

+ 1 - 1
Jint/Runtime/StatementInterpreter.cs

@@ -257,7 +257,7 @@ namespace Jint.Runtime
 
 
                     var value = cursor.GetOwnProperty(p);
-                    if (!value.Enumerable.HasValue || !value.Enumerable.Value)
+                    if (!value.Enumerable)
                     {
                         continue;
                     }