Browse Source

Implementing Object.constructor functions

Sebastien Ros 12 years ago
parent
commit
544dfae042
2 changed files with 234 additions and 12 deletions
  1. 206 12
      Jint/Native/Object/ObjectConstructor.cs
  2. 28 0
      Jint/Runtime/Descriptors/PropertyDescriptor.cs

+ 206 - 12
Jint/Native/Object/ObjectConstructor.cs

@@ -1,4 +1,6 @@
 using System;
 using System;
+using System.Collections.Generic;
+using System.Linq;
 using Jint.Native.Function;
 using Jint.Native.Function;
 using Jint.Runtime;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Descriptors;
@@ -101,22 +103,69 @@ namespace Jint.Native.Object
 
 
         public object GetPrototypeOf(object thisObject, object[] arguments)
         public object GetPrototypeOf(object thisObject, object[] arguments)
         {
         {
-            throw new NotImplementedException();
+            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            var o = thisObject as ObjectInstance;
+
+            return o.Prototype ?? Null.Instance;
         }
         }
 
 
         public object GetOwnPropertyDescriptor(object thisObject, object[] arguments)
         public object GetOwnPropertyDescriptor(object thisObject, object[] arguments)
         {
         {
-            throw new NotImplementedException();
+            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            var o = thisObject as ObjectInstance;
+
+            var p = arguments.Length > 0 ? arguments[0] : Undefined.Instance;
+            var name = TypeConverter.ToString(p);
+
+            var desc = o.GetOwnProperty(name);
+            return PropertyDescriptor.FromPropertyDescriptor(Engine, desc);
         }
         }
 
 
         public object GetOwnPropertyNames(object thisObject, object[] arguments)
         public object GetOwnPropertyNames(object thisObject, object[] arguments)
         {
         {
-            throw new NotImplementedException();
+            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            var o = thisObject as ObjectInstance;
+
+            var array = Engine.Array.Construct(Arguments.Empty);
+            var n = 0;
+            foreach (var p in o.Properties)
+            {
+                array.DefineOwnProperty(n.ToString(), new DataDescriptor(p.Key) { Writable = true, Enumerable = true, Configurable = true }, false);
+                n++;
+            }
+
+            return array;
         }
         }
 
 
         public object Create(object thisObject, object[] arguments)
         public object Create(object thisObject, object[] arguments)
         {
         {
-            throw new NotImplementedException();
+            if (TypeConverter.GetType(thisObject) != TypeCode.Object && thisObject != Null.Instance)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            var obj = Engine.Object.Construct(Arguments.Empty);
+            obj.Prototype = thisObject as ObjectInstance;
+
+            var properties = arguments.Length > 1 ? arguments[1] : Undefined.Instance;
+            if (properties != Undefined.Instance)
+            {
+                DefineProperties(obj, new [] {properties});
+            }
+
+            return obj;
         }
         }
 
 
         public object DefineProperty(object thisObject, object[] arguments)
         public object DefineProperty(object thisObject, object[] arguments)
@@ -143,42 +192,187 @@ namespace Jint.Native.Object
 
 
         public object DefineProperties(object thisObject, object[] arguments)
         public object DefineProperties(object thisObject, object[] arguments)
         {
         {
-            throw new NotImplementedException();
+            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            var o = thisObject as ObjectInstance;
+
+            var properties = arguments.Length > 1 ? arguments[1] : Undefined.Instance;
+            var props = TypeConverter.ToObject(Engine, properties);
+            var names = props.Properties.Keys;
+            var descriptors = new List<KeyValuePair<string, PropertyDescriptor>>();
+            foreach (var p in names)
+            {
+                var descObj = props.Get(p);
+                var desc = PropertyDescriptor.ToPropertyDescriptor(Engine, descObj);
+                descriptors.Add(new KeyValuePair<string, PropertyDescriptor>(p, desc));
+            }
+            foreach (var pair in descriptors)
+            {
+                o.DefineOwnProperty(pair.Key, pair.Value, true);
+            }
+
+            return o;
         }
         }
 
 
         public object Seal(object thisObject, object[] arguments)
         public object Seal(object thisObject, object[] arguments)
         {
         {
-            throw new NotImplementedException();
+            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            var o = thisObject as ObjectInstance;
+
+            foreach (var prop in o.Properties)
+            {
+                if (prop.Value.Configurable)
+                {
+                    prop.Value.Configurable = false;
+                }
+
+                o.DefineOwnProperty(prop.Key, prop.Value, true);
+            }
+
+            o.Extensible = false;
+
+            return o;
         }
         }
 
 
         public object Freeze(object thisObject, object[] arguments)
         public object Freeze(object thisObject, object[] arguments)
         {
         {
-            throw new NotImplementedException();
+            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            var o = thisObject as ObjectInstance;
+
+            foreach (var prop in o.Properties)
+            {
+                if (prop.Value.IsDataDescriptor())
+                {
+                    var datadesc = prop.Value.As<DataDescriptor>();
+                    if (datadesc.Writable)
+                    {
+                        datadesc.Writable = false;
+                    }
+                }
+                if (prop.Value.Configurable)
+                {
+                    prop.Value.Configurable = false;
+                }
+                o.DefineOwnProperty(prop.Key, prop.Value, true);
+            }
+            
+            o.Extensible = false;
+         
+            return o;
         }
         }
 
 
         public object PreventExtensions(object thisObject, object[] arguments)
         public object PreventExtensions(object thisObject, object[] arguments)
         {
         {
-            throw new NotImplementedException();
+            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            var o = thisObject as ObjectInstance;
+
+            o.Extensible = false;
+
+            return o;
         }
         }
 
 
         public object IsSealed(object thisObject, object[] arguments)
         public object IsSealed(object thisObject, object[] arguments)
         {
         {
-            throw new NotImplementedException();
+            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            var o = thisObject as ObjectInstance;
+
+            foreach (var prop in o.Properties)
+            {
+                if (prop.Value.Configurable)
+                {
+                    return false;
+                }
+            }
+
+            if (o.Extensible)
+            {
+                return true;
+            }
+
+            return false;
         }
         }
 
 
         public object IsFrozen(object thisObject, object[] arguments)
         public object IsFrozen(object thisObject, object[] arguments)
         {
         {
-            throw new NotImplementedException();
+            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            var o = thisObject as ObjectInstance;
+
+            foreach (var prop in o.Properties)
+            {
+                if (prop.Value.IsDataDescriptor())
+                {
+                    if (prop.Value.As<DataDescriptor>().Writable)
+                    {
+                        return false;
+                    }
+                }
+                if (prop.Value.Configurable)
+                {
+                    return false;
+                }
+            }
+
+            if (o.Extensible)
+            {
+                return true;
+            }
+
+            return false;
         }
         }
 
 
         public object IsExtensible(object thisObject, object[] arguments)
         public object IsExtensible(object thisObject, object[] arguments)
         {
         {
-            throw new NotImplementedException();
+            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            var o = thisObject as ObjectInstance;
+
+            return o.Extensible;
         }
         }
 
 
         public object Keys(object thisObject, object[] arguments)
         public object Keys(object thisObject, object[] arguments)
         {
         {
-            throw new NotImplementedException();
+            if (TypeConverter.GetType(thisObject) != TypeCode.Object)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            var o = thisObject as ObjectInstance;
+
+            var n = o.Properties.Values.Count(x => x.Enumerable);
+            var array = Engine.Array.Construct(new object[] {n});
+            var index = 0;
+            foreach (var prop in o.Properties.Where(x => x.Value.Enumerable))
+            {
+                array.DefineOwnProperty(index.ToString(), new DataDescriptor(prop.Key) { Writable = true, Enumerable = true, Configurable = true }, false);
+                index++;
+            }
+            return array;
         }
         }
     }
     }
 }
 }

+ 28 - 0
Jint/Runtime/Descriptors/PropertyDescriptor.cs

@@ -99,6 +99,34 @@ namespace Jint.Runtime.Descriptors
             }
             }
         }
         }
 
 
+        public static object FromPropertyDescriptor(Engine engine, PropertyDescriptor desc)
+        {
+            if (desc == PropertyDescriptor.Undefined)
+            {
+                return Native.Undefined.Instance;
+            }
+
+            var obj = engine.Object.Construct(Arguments.Empty);
+
+            if (desc.IsDataDescriptor())
+            {
+                var datadesc = desc.As<DataDescriptor>();
+                obj.DefineOwnProperty("value", new DataDescriptor(datadesc.Value) { Writable = true, Enumerable = true, Configurable = true }, false);
+                obj.DefineOwnProperty("writable", new DataDescriptor(datadesc.Writable) { Writable = true, Enumerable = true, Configurable = true }, false);
+            }
+            else
+            {
+                var accdesc = desc.As<AccessorDescriptor>();
+                obj.DefineOwnProperty("get", new DataDescriptor(accdesc.Get ?? Native.Undefined.Instance) { Writable = true, Enumerable = true, Configurable = true }, false);
+                obj.DefineOwnProperty("set", new DataDescriptor(accdesc.Set ?? Native.Undefined.Instance) { Writable = true, Enumerable = true, Configurable = true }, false);
+            }
+
+            obj.DefineOwnProperty("enumerable", new DataDescriptor(desc.Enumerable) { Writable = true, Enumerable = true, Configurable = true }, false);
+            obj.DefineOwnProperty("configurable", new DataDescriptor(desc.Configurable) { Writable = true, Enumerable = true, Configurable = true }, false);
+
+            return obj;
+        }
+
         /// <summary>
         /// <summary>
         /// Local implementation used to create a singleton representing 
         /// Local implementation used to create a singleton representing 
         /// an undefined result of a PropertyDescriptor. This prevents the rest
         /// an undefined result of a PropertyDescriptor. This prevents the rest