Browse Source

Implementing Array.prototype.concat

Sebastien Ros 12 years ago
parent
commit
b95ee27b63

+ 36 - 3
Jint/Native/Array/ArrayPrototype.cs

@@ -1,6 +1,9 @@
 using System;
+using System.Collections.Generic;
+using System.Dynamic;
 using Jint.Native.Object;
 using Jint.Runtime;
+using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.Array
@@ -190,7 +193,7 @@ namespace Jint.Native.Array
                 }
                 else
                 {
-                    var elementObj = TypeConverter.ToObject(Engine, firstElement);
+                    var elementObj = TypeConverter.ToObject(Engine, nextElement);
                     var func = elementObj.Get("toLocaleString") as ICallable;
                     if (func == null)
                     {
@@ -207,7 +210,37 @@ namespace Jint.Native.Array
 
         private object Concat(object thisObj, object[] arguments)
         {
-            throw new NotImplementedException();
+            var o = TypeConverter.ToObject(Engine, thisObj);
+            var a = Engine.Array.Construct(Arguments.Empty);
+            var n = 0;
+            var items = new List<object>() {o};
+            items.AddRange(arguments);
+
+            foreach (var e in items)
+            {
+                var eArray = e as ArrayInstance;
+                if (eArray != null)
+                {
+                    var len =  TypeConverter.ToUint32(eArray.Get("length"));
+                    for (var k = 0; k < len; k++)
+                    {
+                        var p = k.ToString();
+                        var exists = eArray.HasProperty(p);
+                        if (exists)
+                        {
+                            var subElement = eArray.Get(p);
+                            a.DefineOwnProperty(TypeConverter.ToString(n), new DataDescriptor(subElement) { Writable = true, Enumerable = true, Configurable = true}, false);
+                        }
+                        n++;
+                    }
+                }
+                else
+                {
+                    a.DefineOwnProperty(TypeConverter.ToString(n), new DataDescriptor(e) { Writable = true, Enumerable = true, Configurable = true }, false);
+                    n++;
+                }
+            }
+            return a;
         }
 
         private object ToString(object thisObj, object[] arguments)
@@ -239,7 +272,7 @@ namespace Jint.Native.Array
             uint n = TypeConverter.ToUint32(lenVal);
             foreach (object e in arguments)
             {
-                o.Put(TypeConverter.ToString(n), e, true);
+                o.DefineOwnProperty(TypeConverter.ToString(n), new DataDescriptor(e){Configurable = true, Enumerable = true, Writable = true}, true);
                 n++;
             }
             o.Put("length", n, true);

+ 1 - 1
Jint/Native/Function/ScriptFunctionInstance.cs

@@ -144,7 +144,7 @@ namespace Jint.Native.Function
                 throw new JavaScriptException(result.Value);
             }
 
-            return result;
+            return result.Value;
         }
 
         /// <summary>

+ 19 - 1
Jint/Native/Object/ObjectConstructor.cs

@@ -1,6 +1,7 @@
 using System;
 using Jint.Native.Function;
 using Jint.Runtime;
+using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.Object
@@ -120,7 +121,24 @@ namespace Jint.Native.Object
 
         public object DefineProperty(object thisObject, object[] arguments)
         {
-            throw new NotImplementedException();
+            var o = arguments[0] as ObjectInstance;
+            var p = arguments[1];
+            var attributes = arguments[2] as ObjectInstance;
+            
+            if (o == null)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            if (attributes == null)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            var name = TypeConverter.ToString(p);
+            var desc = PropertyDescriptor.ToPropertyDescriptor(Engine, attributes);
+            o.DefineOwnProperty(name, desc, true);
+            return o;
         }
 
         public object DefineProperties(object thisObject, object[] arguments)

+ 2 - 2
Jint/Native/Object/ObjectInstance.cs

@@ -310,7 +310,7 @@ namespace Jint.Native.Object
                 if (callable != null)
                 {
                     var str = callable.Call(this, Arguments.Empty);
-                    if (str is IPrimitiveType)
+                    if (TypeConverter.IsPrimitiveValue(str))
                     {
                         return str;
                     }
@@ -321,7 +321,7 @@ namespace Jint.Native.Object
                 if (callable != null)
                 {
                     var val = callable.Call(this, Arguments.Empty);
-                    if (val is IPrimitiveType)
+                    if (TypeConverter.IsPrimitiveValue(val))
                     {
                         return val;
                     }

+ 5 - 4
Jint/Runtime/Descriptors/AccessorDescriptor.cs

@@ -1,10 +1,11 @@
-using Jint.Native.Function;
+using Jint.Native;
+using Jint.Native.Function;
 
 namespace Jint.Runtime.Descriptors
 {
     public class AccessorDescriptor : PropertyDescriptor
     {
-        public AccessorDescriptor(FunctionInstance get, FunctionInstance set = null)
+        public AccessorDescriptor(ICallable get, ICallable set = null)
         {
             Get = get;
             Set = set;
@@ -22,13 +23,13 @@ namespace Jint.Runtime.Descriptors
         /// The getter function
         /// </summary>
         /// <returns></returns>
-        public virtual FunctionInstance Get { get; set; }
+        public virtual ICallable Get { get; set; }
 
         /// <summary>
         /// The setter function
         /// </summary>
         /// <returns></returns>
-        public virtual FunctionInstance Set { get; set; }
+        public virtual ICallable Set { get; set; }
 
         public override bool IsAccessorDescriptor()
         {

+ 53 - 1
Jint/Runtime/Descriptors/PropertyDescriptor.cs

@@ -1,4 +1,7 @@
-namespace Jint.Runtime.Descriptors
+using Jint.Native;
+using Jint.Native.Object;
+
+namespace Jint.Runtime.Descriptors
 {
     /// <summary>
     /// An element of a javascript object
@@ -47,6 +50,55 @@
             return (T)this;
         }
 
+        public static PropertyDescriptor ToPropertyDescriptor(Engine engine, object o)
+        {
+            var obj = o as ObjectInstance;
+
+            if (obj == null)
+            {
+                throw new JavaScriptException(engine.TypeError);
+            }
+
+            if ((obj.HasProperty("value") || obj.HasProperty("writable")) &&
+                (obj.HasProperty("get") || obj.HasProperty("set")))
+            {
+                throw new JavaScriptException(engine.TypeError);
+            }
+            
+            bool writable = TypeConverter.ToBoolean(obj.Get("writable"));
+            bool enumerable = TypeConverter.ToBoolean(obj.Get("enumerable"));
+            bool configurable = TypeConverter.ToBoolean(obj.Get("configurable"));
+
+            if (obj.HasProperty("value"))
+            {
+                var value = TypeConverter.ToBoolean(obj.Get("value"));
+                return new DataDescriptor(value) { Configurable = configurable, Enumerable = enumerable, Writable = writable};
+            }
+            else
+            {
+                object getter = null, setter = null;
+                if (obj.HasProperty("get"))
+                {
+                    getter = obj.Get("get");
+                    if (getter != Native.Undefined.Instance && !(getter is ICallable))
+                    {
+                        throw new JavaScriptException(engine.TypeError);
+                    }
+                }
+
+                if (obj.HasProperty("set"))
+                {
+                    setter = obj.Get("set");
+                    if (setter != Native.Undefined.Instance && !(setter is ICallable))
+                    {
+                        throw new JavaScriptException(engine.TypeError);
+                    }
+                }
+
+                return new AccessorDescriptor(getter as ICallable, setter as ICallable);
+            }
+        }
+
         /// <summary>
         /// Local implementation used to create a singleton representing 
         /// an undefined result of a PropertyDescriptor. This prevents the rest

+ 9 - 7
Jint/Runtime/ExpressionIntepreter.cs

@@ -693,14 +693,16 @@ namespace Jint.Runtime
 
         public object EvaluateArrayExpression(ArrayExpression arrayExpression)
         {
-            var arguments = arrayExpression.Elements.Select(EvaluateExpression).Select(_engine.GetValue).ToArray();
-
-            // construct the new instance using the Function's constructor method
-            var instance = _engine.Array.Construct(Arguments.Empty) as ArrayInstance;
-
-            _engine.Array.PrototypeObject.Push(instance, arguments);
+            var a = _engine.Array.Construct(Arguments.Empty);
+            var n = 0;
+            foreach (var expr in arrayExpression.Elements)
+            {
+                var value = expr == null ? Null.Instance : _engine.GetValue(EvaluateExpression(expr));
+                a.DefineOwnProperty(n.ToString(), new DataDescriptor(value) { Writable = true, Enumerable = true, Configurable = true }, false);
+                n++;
+            }
             
-            return instance;
+            return a;
         }
 
         public object EvaluateUnaryExpression(UnaryExpression unaryExpression)

+ 4 - 4
Jint/Runtime/Interop/ClrFunctionInstance.cs

@@ -10,17 +10,17 @@ namespace Jint.Runtime.Interop
     {
         private readonly Func<TObject, object[], TResult> _func;
 
-        public ClrFunctionInstance(Engine engine, Func<TObject, object[], TResult> func)
+        public ClrFunctionInstance(Engine engine, Func<TObject, object[], TResult> func, int length)
             : base(engine, null, null, false)
         {
             _func = func;
             Prototype = engine.Function.PrototypeObject;
+            FastAddProperty("length", length, false, false, false);
         }
 
-        public ClrFunctionInstance(Engine engine, Func<TObject, object[], TResult> func, int length)
-            : this(engine, func)
+        public ClrFunctionInstance(Engine engine, Func<TObject, object[], TResult> func)
+            : this(engine, func, 0)
         {
-            FastAddProperty("length", length, false, false, false);
         }
 
         public override object Call(object thisObject, object[] arguments)

+ 1 - 1
Jint/Runtime/TypeConverter.cs

@@ -293,7 +293,7 @@ namespace Jint.Runtime
 
                 if (double.IsInfinity(n))
                 {
-                    return "infinity";
+                    return "Infinity";
                 }
 
                 return n.ToString();