Преглед изворни кода

Implementing all standard conversions

Sebastien Ros пре 12 година
родитељ
комит
241205132a

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

@@ -41,7 +41,7 @@ namespace Jint.Native.Array
             FastAddProperty("push", new ClrFunctionInstance<object, object>(Engine, Push, 1), true, false, true);
             FastAddProperty("reverse", new ClrFunctionInstance<object, object>(Engine, Reverse), true, false, true);
             FastAddProperty("shift", new ClrFunctionInstance<object, object>(Engine, Shift), true, false, true);
-            FastAddProperty("slice", new ClrFunctionInstance<ArrayInstance, object>(Engine, Slice, 2), true, false, true);
+            FastAddProperty("slice", new ClrFunctionInstance<object, object>(Engine, Slice, 2), true, false, true);
             FastAddProperty("sort", new ClrFunctionInstance<ArrayInstance, object>(Engine, Sort), true, false, true);
             FastAddProperty("splice", new ClrFunctionInstance<ArrayInstance, object>(Engine, Splice, 2), true, false, true);
             FastAddProperty("unshift", new ClrFunctionInstance<ArrayInstance, object>(Engine, Unshift), true, false, true);
@@ -111,9 +111,65 @@ namespace Jint.Native.Array
             throw new NotImplementedException();
         }
 
-        private object Slice(ArrayInstance arg1, object[] arg2)
+        private object Slice(object thisObj, object[] arguments)
         {
-            throw new NotImplementedException();
+            var start = arguments.Length > 0 ? arguments[0] : Undefined.Instance;
+            var end = arguments.Length > 1 ? arguments[1] : Undefined.Instance;
+
+            var o = TypeConverter.ToObject(Engine, thisObj);
+            var a = Engine.Array.Construct(Arguments.Empty);
+            var lenVal = o.Get("length");
+            var len = TypeConverter.ToUint32(lenVal);
+
+            var relativeStart = TypeConverter.ToInteger(start);
+            int k;
+            if (relativeStart < 0)
+            {
+                k = (int) System.Math.Max(len + relativeStart, 0);
+            }
+            else
+            {
+                k = (int)System.Math.Min(relativeStart, len);
+            }
+
+            double relativeEnd;
+            if (end == Undefined.Instance)
+            {
+                relativeEnd = (int)len;
+            }
+            else
+            {
+                relativeEnd = TypeConverter.ToInteger(end);
+            }
+            int final;
+            if (relativeEnd < 0)
+            {
+                final = (int) System.Math.Max(len + relativeEnd, 0);
+            }
+            else
+            {
+                final = (int) System.Math.Min(relativeEnd, len);
+            }
+            var n = 0;
+            for (; k < final; k++)
+            {
+                var pk = TypeConverter.ToString(k);
+                var kPresent = o.HasProperty(pk);
+                if (kPresent)
+                {
+                    var kValue = o.Get(pk);
+                    a.DefineOwnProperty(TypeConverter.ToString(n),
+                                        new DataDescriptor(kValue)
+                                            {
+                                                Writable = true,
+                                                Enumerable = true,
+                                                Configurable = true
+                                            }, false);
+                }
+                n++;
+            }
+
+            return a;
         }
 
         private object Shift(object thisObj, object[] arg2)

+ 1 - 1
Jint/Native/Boolean/BooleanConstructor.cs

@@ -51,7 +51,7 @@ namespace Jint.Native.Boolean
         /// <returns></returns>
         public ObjectInstance Construct(object[] arguments)
         {
-            return Construct(TypeConverter.ToBoolean(arguments[0]));
+            return Construct(TypeConverter.ToBoolean(arguments.Length > 0 ? arguments[0] : Undefined.Instance));
         }
 
         public BooleanPrototype PrototypeObject { get; private set; }

+ 24 - 3
Jint/Native/Boolean/BooleanPrototype.cs

@@ -1,4 +1,6 @@
 using System;
+using Jint.Native.Object;
+using Jint.Runtime;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.Boolean
@@ -25,16 +27,35 @@ namespace Jint.Native.Boolean
 
         public void Configure()
         {
-            FastAddProperty("toString", new ClrFunctionInstance<object, object>(Engine, ToBooleanString), true, false, true);
+            FastAddProperty("toString", new ClrFunctionInstance<object, bool>(Engine, ToBooleanString), true, false, true);
             FastAddProperty("valueOf", new ClrFunctionInstance<object, object>(Engine, ValueOf), true, false, true);
         }
 
         private object ValueOf(object thisObj, object[] arguments)
         {
-            throw new NotImplementedException();
+            var B = thisObj;
+            object b;
+            if (TypeConverter.GetType(B) == TypeCode.Boolean)
+            {
+                b = B;
+            }
+            else
+            {
+                var o = B as BooleanInstance;
+                if (o != null)
+                {
+                    return o.PrimitiveValue;
+                }
+                else
+                {
+                    throw new JavaScriptException(Engine.TypeError);
+                }
+            }
+
+            return b;
         }
 
-        private object ToBooleanString(object thisObj, object[] arguments)
+        private bool ToBooleanString(object thisObj, object[] arguments)
         {
             throw new NotImplementedException();
         }

+ 60 - 16
Jint/Native/Date/DateConstructor.cs

@@ -2,11 +2,14 @@
 using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Runtime;
+using Jint.Runtime.Interop;
 
 namespace Jint.Native.Date
 {
     public sealed class DateConstructor : FunctionInstance, IConstructor
     {
+        private static readonly DateTime Origin = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+
         public DateConstructor(Engine engine) : base(engine, null, null, false)
         {
         }
@@ -20,7 +23,7 @@ namespace Jint.Native.Date
             obj.Prototype = engine.Function.PrototypeObject;
             obj.PrototypeObject = DatePrototype.CreatePrototypeObject(engine, obj);
 
-            obj.FastAddProperty("length", 1, false, false, false);
+            obj.FastAddProperty("length", 7, false, false, false);
 
             // The initial value of Date.prototype is the Date prototype object
             obj.FastAddProperty("prototype", obj.PrototypeObject, false, false, false);
@@ -30,7 +33,24 @@ namespace Jint.Native.Date
 
         public void Configure()
         {
+            FastAddProperty("parse", new ClrFunctionInstance<object, object>(Engine, Parse, 0), true, false, true);
+            FastAddProperty("UTC", new ClrFunctionInstance<object, object>(Engine, Utc, 0), true, false, true);
+            FastAddProperty("now", new ClrFunctionInstance<object, object>(Engine, Now, 0), true, false, true);
+        }
+
+        private object Parse(object thisObj, object[] arguments)
+        {
+            throw new NotImplementedException();
+        }
+
+        private object Utc(object thisObj, object[] arguments)
+        {
+            throw new NotImplementedException();
+        }
 
+        private object Now(object thisObj, object[] arguments)
+        {
+            throw new NotImplementedException();
         }
 
         public override object Call(object thisObject, object[] arguments)
@@ -47,7 +67,7 @@ namespace Jint.Native.Date
         {
             if (arguments.Length == 0)
             {
-                return Construct(DateTime.UtcNow);
+                return Construct(DateTime.Now);
             }
             else if (arguments.Length == 1)
             {
@@ -58,20 +78,17 @@ namespace Jint.Native.Date
                     return Construct(d);
                 }
 
-                v = TypeConverter.ToNumber(v);
-
-                // todo: implement TimeClip
-                return Construct(new DateTime(TypeConverter.ToUint32(v)));
+                return Construct(TypeConverter.ToNumber(v));
             }
             else
             {
                 var y = TypeConverter.ToNumber(arguments[0]);
-                var m = TypeConverter.ToInteger(arguments[0]);
-                var date = arguments.Length > 2 ? TypeConverter.ToInteger(arguments[2]) : 1;
-                var hours = arguments.Length > 3 ? TypeConverter.ToInteger(arguments[3]) : 0;
-                var minutes = arguments.Length > 4 ? TypeConverter.ToInteger(arguments[4]) : 0;
-                var seconds = arguments.Length > 5 ? TypeConverter.ToInteger(arguments[5]) : 0;
-                var ms = arguments.Length > 6 ? TypeConverter.ToInteger(arguments[6]) : 0;
+                var m = (int) TypeConverter.ToInteger(arguments[0]);
+                var date = arguments.Length > 2 ? (int)TypeConverter.ToInteger(arguments[2]) : 1;
+                var hours = arguments.Length > 3 ? (int)TypeConverter.ToInteger(arguments[3]) : 0;
+                var minutes = arguments.Length > 4 ? (int)TypeConverter.ToInteger(arguments[4]) : 0;
+                var seconds = arguments.Length > 5 ? (int)TypeConverter.ToInteger(arguments[5]) : 0;
+                var ms = arguments.Length > 6 ? (int)TypeConverter.ToInteger(arguments[6]) : 0;
 
                 if ((!double.IsNaN(y)) && (0 <= TypeConverter.ToInteger(y)) && (TypeConverter.ToInteger(y) <= 99))
                 {
@@ -86,14 +103,41 @@ namespace Jint.Native.Date
 
         public DateInstance Construct(DateTime value)
         {
-            var instance = new DateInstance(Engine);
-            instance.Prototype = PrototypeObject;
-            instance.PrimitiveValue = value;
-            instance.Extensible = true;
+            var instance = new DateInstance(Engine)
+                {
+                    Prototype = PrototypeObject,
+                    PrimitiveValue = (value - Origin).TotalMilliseconds,
+                    Extensible = true
+                };
+
+            return instance;
+        }
+
+        public DateInstance Construct(double time)
+        {
+            var instance = new DateInstance(Engine)
+                {
+                    Prototype = PrototypeObject,
+                    PrimitiveValue = TimeClip(time),
+                    Extensible = true
+                };
 
             return instance;
         }
 
+        public double TimeClip(double time)
+        {
+            if (double.IsInfinity(time) || double.IsNaN(time))
+            {
+                return double.NaN;
+            }
+
+            if (System.Math.Abs(time) > 8640000000000000)
+            {
+                return double.NaN;
+            }
 
+            return TypeConverter.ToInteger(time);
+        }
     }
 }

+ 19 - 1
Jint/Native/Date/DateInstance.cs

@@ -5,6 +5,12 @@ namespace Jint.Native.Date
 {
     public class DateInstance : ObjectInstance, IPrimitiveType
     {
+        // Maximum allowed value to prevent DateTime overflow
+        private static readonly double Max = (DateTime.MaxValue - new DateTime(170, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
+
+        // Minimum allowed value to prevent DateTime overflow
+        private static readonly double Min = -(new DateTime(170, 1, 1, 0, 0, 0, DateTimeKind.Utc) - DateTime.MinValue).TotalMilliseconds;
+
         public DateInstance(Engine engine)
             : base(engine)
         {
@@ -28,6 +34,18 @@ namespace Jint.Native.Date
             get { return PrimitiveValue; }
         }
 
-        public DateTime PrimitiveValue { get; set; }
+        public DateTime ToDateTime()
+        {
+            if (double.IsNaN(PrimitiveValue) || PrimitiveValue > Max || PrimitiveValue < Min)
+            {
+                return DateTime.MinValue;
+            }
+            else
+            {
+                return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(PrimitiveValue);
+            }
+        }
+
+        public double PrimitiveValue { get; set; }
     }
 }

+ 55 - 2
Jint/Native/Date/DatePrototype.cs

@@ -1,4 +1,6 @@
-namespace Jint.Native.Date
+using Jint.Runtime.Interop;
+
+namespace Jint.Native.Date
 {
     /// <summary>
     /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.5
@@ -22,7 +24,58 @@
 
         public void Configure()
         {
-            
+            FastAddProperty("toString", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("toDateString", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("toTimeString", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("toLocaleString", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("toLocaleDateString", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("toLocaleTimeString", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("valueOf", new ClrFunctionInstance<DateInstance, double>(Engine, ValueOf, 0), true, false, true);
+            FastAddProperty("getTime", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getFullYear", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getUTCFullYear", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getMonth", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getUTCMonth", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getDate", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getUTCDate", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getDay", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getUTCDay", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getHours", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getUTCHours", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getMinutes", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getUTCMinutes", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getSeconds", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getUTCSeconds", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getMilliseconds", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getUTCMilliseconds", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("getTimezoneOffset", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("setTime", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("setMilliseconds", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("setSeconds", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("setUTCSeconds", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("setMinutes", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("setUTCMinutes", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("setHours", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("setUTCHours", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("setDate", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("setUTCDate", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("setMonth", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("setUTCMonth", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("setFullYear", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("setUTCFullYear", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("toUTCString", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("toISOString", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+            FastAddProperty("toJSON", new ClrFunctionInstance<object, object>(Engine, ToString, 0), true, false, true);
+        }
+
+        private double ValueOf(DateInstance thisObj, object[] arguments)
+        {
+            return thisObj.PrimitiveValue;
+        }
+
+        private object ToString(object arg1, object[] arg2)
+        {
+            throw new System.NotImplementedException();
         }
     }
 }

+ 7 - 0
Jint/Native/Number/NumberInstance.cs

@@ -5,6 +5,8 @@ namespace Jint.Native.Number
 {
     public class NumberInstance : ObjectInstance, IPrimitiveType
     {
+        private static readonly long NegativeZeroBits = BitConverter.DoubleToInt64Bits(-0.0);
+
         public NumberInstance(Engine engine)
             : base(engine)
         {
@@ -29,5 +31,10 @@ namespace Jint.Native.Number
         }
 
         public double PrimitiveValue { get; set; }
+
+        public static bool IsNegativeZero(double x)
+        {
+            return BitConverter.DoubleToInt64Bits(x) == NegativeZeroBits;
+        }
     }
 }

+ 7 - 1
Jint/Native/Number/NumberPrototype.cs

@@ -41,7 +41,13 @@ namespace Jint.Native.Number
 
         private object ValueOf(object thisObj, object[] arguments)
         {
-            throw new System.NotImplementedException();
+            var number = thisObj as NumberInstance;
+            if (number == null)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            return number.PrimitiveValue;
         }
 
         private object ToFixed(object thisObj, object[] arguments)

+ 9 - 3
Jint/Native/String/StringConstructor.cs

@@ -31,12 +31,18 @@ namespace Jint.Native.String
 
         public void Configure()
         {
-            FastAddProperty("fromCharCode", new ClrFunctionInstance<object, object>(Engine, FromCharCode), false, false, false);
+            FastAddProperty("fromCharCode", new ClrFunctionInstance<object, string>(Engine, FromCharCode), false, false, false);
         }
 
-        private object FromCharCode(object thisObj, object[] arguments)
+        private static string FromCharCode(object thisObj, object[] arguments)
         {
-            throw new System.NotImplementedException();
+            var chars = new char[arguments.Length];
+            for (var i = 0; i < chars.Length; i++ )
+            {
+                chars[i] = (char)TypeConverter.ToUint16(arguments[i]);
+            }
+            
+            return new System.String(chars);
         }
 
         public override object Call(object thisObject, object[] arguments)

+ 27 - 5
Jint/Native/String/StringPrototype.cs

@@ -1,4 +1,5 @@
 using System;
+using Jint.Runtime;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.String
@@ -27,7 +28,7 @@ namespace Jint.Native.String
         public void Configure()
         {
             FastAddProperty("toString", new ClrFunctionInstance<object, object>(Engine, ToStringString), false, false, false);
-            FastAddProperty("valueOf", new ClrFunctionInstance<object, object>(Engine, ValueOf), false, false, false);
+            FastAddProperty("valueOf", new ClrFunctionInstance<StringInstance, string>(Engine, ValueOf), false, false, false);
             FastAddProperty("charAt", new ClrFunctionInstance<object, object>(Engine, CharAt), false, false, false);
             FastAddProperty("charCodeAt", new ClrFunctionInstance<object, object>(Engine, CharCodeAt), false, false, false);
             FastAddProperty("concat", new ClrFunctionInstance<object, object>(Engine, Concat), false, false, false);
@@ -108,16 +109,37 @@ namespace Jint.Native.String
         }
         private object CharCodeAt(object thisObj, object[] arguments)
         {
-            throw new NotImplementedException();
+            TypeConverter.CheckObjectCoercible(Engine, thisObj);
+
+            object pos = arguments.Length > 0 ? arguments[0] : 0;
+            var s = TypeConverter.ToString(thisObj);
+            var position = (int)TypeConverter.ToInteger(pos);
+            if (position < 0 || position >= s.Length)
+            {
+                return double.NaN;
+            }
+            return (uint)s[position];
         }
+
         private object CharAt(object thisObj, object[] arguments)
         {
-            throw new NotImplementedException();
+            TypeConverter.CheckObjectCoercible(Engine, thisObj);
+            var s = TypeConverter.ToString(thisObj);
+            var position = TypeConverter.ToInteger(arguments.Length > 0 ? arguments[0] : Undefined.Instance);
+            var size = s.Length;
+            if (position > size || position < 0)
+            {
+                return "";
+            }
+            return s[(int) position].ToString();
+
         }
-        private object ValueOf(object thisObj, object[] arguments)
+
+        private static string ValueOf(StringInstance thisObj, object[] arguments)
         {
-            throw new NotImplementedException();
+            return thisObj.PrimitiveValue;
         }
+
         private object ToStringString(object thisObj, object[] arguments)
         {
             throw new NotImplementedException();

+ 15 - 1
Jint/Parser/JavascriptParser.cs

@@ -817,10 +817,24 @@ namespace Jint.Parser
                 throw new Exception(Messages.UnexpectedToken);
             }
 
+            double n;
+            try
+            {
+                n = Double.Parse(number, NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent);
+            }
+            catch (OverflowException)
+            {
+                n = number.Trim().StartsWith("-") ? double.NegativeInfinity : double.PositiveInfinity;
+            }
+            catch (Exception)
+            {
+                n = double.NaN;
+            }
+
             return new Token
                 {
                     Type = Tokens.NumericLiteral,
-                    Value = Double.Parse(number, NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent),
+                    Value = n,
                     LineNumber = _lineNumber,
                     LineStart = _lineStart,
                     Range = new[] {start, _index}

+ 61 - 16
Jint/Runtime/ExpressionIntepreter.cs

@@ -2,6 +2,7 @@
 using System.Linq;
 using Jint.Native;
 using Jint.Native.Function;
+using Jint.Native.Number;
 using Jint.Native.Object;
 using Jint.Parser.Ast;
 using Jint.Runtime.Descriptors;
@@ -83,14 +84,7 @@ namespace Jint.Runtime
                     break;
 
                 case "/=":
-                    if (lval == Undefined.Instance || rval == Undefined.Instance)
-                    {
-                        lval = Undefined.Instance;
-                    }
-                    else
-                    {
-                        lval = TypeConverter.ToNumber(lval) / TypeConverter.ToNumber(rval);
-                    }
+                    lval = Divide(lval, rval);
                     break;
 
                 case "%=":
@@ -138,6 +132,56 @@ namespace Jint.Runtime
             return lval;
         }
 
+        private object Divide(object lval, object rval)
+        {
+            if (lval == Undefined.Instance || rval == Undefined.Instance)
+            {
+                return Undefined.Instance;
+            }
+            else
+            {
+                var rN = TypeConverter.ToNumber(rval);
+                var lN = TypeConverter.ToNumber(lval);
+
+                if (double.IsNaN(rN) || double.IsNaN(lN))
+                {
+                    return double.NaN;
+                }
+
+                if (double.IsInfinity(lN) && double.IsInfinity(rN))
+                {
+                    return double.NaN;
+                }
+
+                if (double.IsInfinity(lN) && rN == 0)
+                {
+                    if (NumberInstance.IsNegativeZero(rN))
+                    {
+                        return -lN;
+                    }
+
+                    return lN;
+                }
+
+                if (lN == 0 && rN == 0)
+                {
+                    return double.NaN;
+                }
+
+                if (rN == 0)
+                {
+                    if (NumberInstance.IsNegativeZero(rN))
+                    {
+                        return lN > 0 ? -double.PositiveInfinity : -double.NegativeInfinity;
+                    }
+
+                    return lN > 0 ? double.PositiveInfinity : double.NegativeInfinity;
+                }
+
+                return lN/rN;
+            }
+        }
+
         public object EvaluateBinaryExpression(BinaryExpression expression)
         {
             object left = _engine.GetValue(EvaluateExpression(expression.Left));
@@ -175,14 +219,7 @@ namespace Jint.Runtime
                     break;
                 
                 case "/":
-                    if (left == Undefined.Instance || right == Undefined.Instance)
-                    {
-                        value = Undefined.Instance;
-                    }
-                    else
-                    {
-                        value = TypeConverter.ToNumber(left) / TypeConverter.ToNumber(right);
-                    }
+                    value = Divide(left, right);
                     break;
 
                 case "%":
@@ -409,10 +446,18 @@ namespace Jint.Runtime
                 {
                     return false;
                 }
+
                 if (nx == ny)
                 {
+                    if (nx == 0)
+                    {
+                        // +0 !== -0
+                        return NumberInstance.IsNegativeZero(nx) == NumberInstance.IsNegativeZero(ny);
+                    }
+
                     return true;
                 }
+
                 return false;
             }
             if (typea == TypeCode.String)

+ 80 - 44
Jint/Runtime/TypeConverter.cs

@@ -62,10 +62,11 @@ namespace Jint.Runtime
                 return false;
             }
 
+
             var p = o as IPrimitiveType;
             if (p != null)
             {
-                o = p.PrimitiveValue;
+                o = ToBoolean(p.PrimitiveValue);
             }
 
             if (o is double)
@@ -153,9 +154,51 @@ namespace Jint.Runtime
             if (s != null)
             {
                 double n;
-                if (double.TryParse(s, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out n))
+                s = s.Trim();
+
+                if (String.IsNullOrEmpty(s))
                 {
-                    return n;
+                    return 0;
+                }
+
+                if ("+Infinity".Equals(s) || "Infinity".Equals(s))
+                {
+                    return double.PositiveInfinity;
+                }
+
+                if ("-Infinity".Equals(s))
+                {
+                    return double.NegativeInfinity;
+                }
+
+                // todo: use a common implementation with JavascriptParser
+                try
+                {
+                    if (!s.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
+                    {
+                        n = Double.Parse(s,
+                                         NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign |
+                                         NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite |
+                                         NumberStyles.AllowExponent, CultureInfo.InvariantCulture);
+                        if (s.StartsWith("-") && n == 0)
+                        {
+                            return -0.0;
+                        }
+
+                        return n;
+                    }
+
+                    int i = int.Parse(s.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
+                 
+                    return i;
+                }
+                catch (OverflowException)
+                {
+                    return s.StartsWith("-") ? double.NegativeInfinity : double.PositiveInfinity;
+                }
+                catch
+                {
+                    return double.NaN;
                 }
 
                 return double.NaN;
@@ -169,25 +212,21 @@ namespace Jint.Runtime
         /// </summary>
         /// <param name="o"></param>
         /// <returns></returns>
-        public static int ToInteger(object o)
+        public static double ToInteger(object o)
         {
-            if (o is int)
-            {
-                return (int) o;
-            }
-
-            if (o is uint)
-            {
-                return (int) (uint) o;
-            }
-
             var number = ToNumber(o);
+
             if (double.IsNaN(number))
             {
                 return 0;
             }
             
-            return (int) number;
+            if (number == 0 || number == double.NegativeInfinity || number == double.PositiveInfinity)
+            {
+                return number;
+            }
+
+            return Math.Sign(number)*Math.Floor(Math.Abs(number));
         }
 
         /// <summary>
@@ -201,19 +240,8 @@ namespace Jint.Runtime
             {
                 return (int)o;
             }
-
-            if (o is uint)
-            {
-                return (int) (uint) o;
-            }
-
-            var n = ToNumber(o);
-            if (double.IsNaN(n) || double.IsInfinity(n) || n == 0)
-            {
-                return 0;
-            }
-
-            return Convert.ToInt32(n);
+                
+            return (int)(uint)ToNumber(o);
         }
 
         /// <summary>
@@ -223,14 +251,12 @@ namespace Jint.Runtime
         /// <returns></returns>
         public static uint ToUint32(object o)
         {
-            var number = ToNumber(o);
-            if (double.IsNaN(number) || double.IsInfinity(number) || number == 0)
+            if (o is uint)
             {
-                return 0;
+                return (uint)o;
             }
-
-            var posInt = (long) number;
-            return (uint)(posInt % 4294967296);
+                
+            return (uint)ToNumber(o);
         }
 
         /// <summary>
@@ -240,13 +266,7 @@ namespace Jint.Runtime
         /// <returns></returns>
         public static ushort ToUint16(object o)
         {
-            var n = ToNumber(o);
-            if (double.IsNaN(n) || double.IsInfinity(n) || n == 0)
-            {
-                return 0;
-            }
-
-            return Convert.ToUInt16(n);
+            return (ushort)(uint)ToNumber(o);
         }
 
         /// <summary>
@@ -289,14 +309,24 @@ namespace Jint.Runtime
                 if (double.IsNaN(n))
                 {
                     return "NaN";
-                }    
+                }
 
-                if (double.IsInfinity(n))
+                if (n == double.PositiveInfinity)
                 {
                     return "Infinity";
                 }
 
-                return n.ToString();
+                if (n == double.NegativeInfinity)
+                {
+                    return "-Infinity";
+                }
+
+                // todo: fix unit tests in 9.8.1
+                // var d = -Math.Log10((double)SignificantFraction((decimal)n));
+                // var i = Math.Log10(Math.Floor(n));
+
+
+                return n.ToString(CultureInfo.InvariantCulture);
             }
 
             if (o is int)
@@ -401,5 +431,11 @@ namespace Jint.Runtime
                 throw new JavaScriptException(engine.TypeError);
             }
         }
+
+        public static Decimal SignificantFraction(Decimal d)
+        {
+            var b = decimal.GetBits(d);
+            return new decimal(1, 0, 0, false, (byte)((b[3] >> 16) & 0x7fff));
+        }
     }
 }