瀏覽代碼

Adding more Array, Number, String, Boolean objects

Sebastien Ros 12 年之前
父節點
當前提交
f84eb02ef9

+ 1 - 1
Jint.Benchmark/Program.cs

@@ -27,7 +27,7 @@ namespace Jint.Benchmark
 
         static void Main(string[] args)
         {
-            const int iterations = 1000;
+            const int iterations = 100000;
             const bool reuseEngine = false;
 
             var watch = new Stopwatch();

+ 46 - 26
Jint.Tests/Runtime/EngineTests.cs

@@ -1,7 +1,6 @@
 using System;
 using System.IO;
 using System.Reflection;
-using Jint.Runtime;
 using Xunit;
 using Xunit.Extensions;
 
@@ -39,25 +38,24 @@ namespace Jint.Tests.Runtime
                     }
         }
 
-
         [Theory]
         [InlineData(42d, "42")]
         [InlineData("Hello", "'Hello'")]
         public void ShouldInterpretLiterals(object expected, string source)
         {
-            var interpreter = new Engine();
-            interpreter.Execute(source);
+            var engine = new Engine();
+            var result = engine.GetValue(engine.Execute(source));
             
-            Assert.Equal(expected, interpreter.Result);
+            Assert.Equal(expected, result);
         }
 
         [Fact]
         public void ShouldInterpretVariableDeclaration()
         {
-            var interpreter = new Engine();
-            interpreter.Execute("var foo = 'bar'; foo;");
+            var engine = new Engine();
+            var result = engine.GetValue(engine.Execute("var foo = 'bar'; foo;"));
 
-            Assert.Equal("bar", interpreter.Result);
+            Assert.Equal("bar", result);
         }
 
         [Theory]
@@ -67,16 +65,16 @@ namespace Jint.Tests.Runtime
         [InlineData(2d, "6 / 3")]
         public void ShouldInterpretBinaryExpression(double expected, string source)
         {
-            var interpreter = new Engine();
-            interpreter.Execute(source);
+            var engine = new Engine();
+            var result = engine.GetValue(engine.Execute(source));
 
-            Assert.Equal(expected, interpreter.Result);
+            Assert.Equal(expected, result);
         }
 
         [Fact]
         public void ShouldEvaluateHasOwnProperty()
         {
-            var engine = RunTest(@"
+            RunTest(@"
                 var x = {};
                 x.Bar = 42;
                 assert(x.hasOwnProperty('Bar'));
@@ -86,7 +84,7 @@ namespace Jint.Tests.Runtime
         [Fact]
         public void FunctionConstructorsShouldCreateNewObjects()
         {
-            var engine = RunTest(@"
+            RunTest(@"
                 var Vehicle = function () {};
                 var vehicle = new Vehicle();
                 assert(vehicle != undefined);
@@ -96,7 +94,7 @@ namespace Jint.Tests.Runtime
         [Fact]
         public void NewObjectsInheritFunctionConstructorProperties()
         {
-            var engine = RunTest(@"
+            RunTest(@"
                 var Vehicle = function () {};
                 var vehicle = new Vehicle();
                 Vehicle.prototype.wheelCount = 4;
@@ -108,7 +106,7 @@ namespace Jint.Tests.Runtime
         [Fact]
         public void NewObjectsShouldUsePrivateProperties()
         {
-            var engine = RunTest(@"
+            RunTest(@"
                 var Vehicle = function (color) {
                     this.color = color;
                 };
@@ -120,7 +118,7 @@ namespace Jint.Tests.Runtime
         [Fact]
         public void FunctionConstructorsShouldDefinePrototypeChain()
         {
-            var engine = RunTest(@"
+            RunTest(@"
                 function Vehicle() {};
                 var vehicle = new Vehicle();
                 assert(vehicle.hasOwnProperty('constructor') == false);
@@ -130,7 +128,7 @@ namespace Jint.Tests.Runtime
         [Fact]
         public void NewObjectsConstructorIsObject()
         {
-            var engine = RunTest(@"
+            RunTest(@"
                 var o = new Object();
                 assert(o instanceof Object);
                 assert(o.constructor == Object);
@@ -140,7 +138,7 @@ namespace Jint.Tests.Runtime
         [Fact]
         public void NewObjectsConstructorShouldBeConstructorObject()
         {
-            var engine = RunTest(@"
+            RunTest(@"
                 var Vehicle = function () {};
                 var vehicle = new Vehicle();
                 assert(vehicle.constructor == Vehicle);
@@ -150,7 +148,7 @@ namespace Jint.Tests.Runtime
         [Fact]
         public void NewObjectsIntanceOfConstructorObject()
         {
-            var engine = RunTest(@"
+            RunTest(@"
                 var Vehicle = function () {};
                 var vehicle = new Vehicle();
                 assert(vehicle instanceof Vehicle);
@@ -160,7 +158,7 @@ namespace Jint.Tests.Runtime
         [Fact]
         public void ShouldEvaluateForLoops()
         {
-            var engine = RunTest(@"
+            RunTest(@"
                 var foo = 0;
                 for (var i = 0; i < 5; i++) {
                     foo += i;
@@ -172,7 +170,7 @@ namespace Jint.Tests.Runtime
         [Fact]
         public void ShouldEvaluateRecursiveFunctions()
         {
-            var engine = RunTest(@"
+            RunTest(@"
                 function fib(n) {
                     if (n < 2) {
                         return n;
@@ -187,7 +185,7 @@ namespace Jint.Tests.Runtime
         [Fact]
         public void ShouldAccessObjectProperties()
         {
-            var engine = RunTest(@"
+            RunTest(@"
                 var o = {};
                 o.Foo = 'bar';
                 o.Baz = 42;
@@ -200,7 +198,7 @@ namespace Jint.Tests.Runtime
         [Fact]
         public void ShouldConstructArray()
         {
-            var engine = RunTest(@"
+            RunTest(@"
                 var o = [];
                 assert(o.length == 0);
             ");
@@ -209,27 +207,49 @@ namespace Jint.Tests.Runtime
         [Fact]
         public void ArrayPushShouldIncrementLength()
         {
-            var engine = RunTest(@"
+            RunTest(@"
                 var o = [];
                 o.push(1);
                 assert(o.length == 1);
             ");
         }
 
+        [Fact]
+        public void ArrayPopShouldDecrementLength()
+        {
+            RunTest(@"
+                var o = [42, 'foo'];
+                var pop = o.pop();
+                assert(o.length == 1);
+                assert(pop == 'foo');
+            ");
+        }
+
         [Fact]
         public void ArrayConstructor()
         {
-            var engine = RunTest(@"
+            RunTest(@"
                 var o = [];
                 assert(o.constructor == Array);
                 assert(o.hasOwnProperty('constructor') == false);
             ");
         }
+
+        [Fact]
+        public void Scratch()
+        {
+            RunTest(@"
+                var o = [42, 'foo'];
+                var a = o.pop();
+                var b = o.length;
+            ");
+        }
+        
         /*
                         [Fact]
                         public void ()
                         {
-                            var engine = RunTest(@"
+                            RunTest(@"
                             ");
                         }
                 */

+ 98 - 80
Jint/Engine.cs

@@ -1,10 +1,12 @@
 using System;
 using System.Collections.Generic;
-using Jint.Native;
 using Jint.Native.Array;
+using Jint.Native.Boolean;
 using Jint.Native.Errors;
 using Jint.Native.Function;
+using Jint.Native.Number;
 using Jint.Native.Object;
+using Jint.Native.String;
 using Jint.Parser;
 using Jint.Parser.Ast;
 using Jint.Runtime;
@@ -22,8 +24,6 @@ namespace Jint
         private readonly LexicalEnvironment _globalEnvironment;
         private readonly Stack<ExecutionContext> _executionContexts;
 
-        private object _result;
-
         public Engine() : this(null)
         {
         }
@@ -39,13 +39,16 @@ namespace Jint
             Global = new ObjectInstance(Object);
             Function = new FunctionConstructor(this);
             Array = new ArrayConstructor(this);
-
-            //Object.Prototype.DefineOwnProperty("hasOwnProperty", new DataDescriptor(new BuiltInPropertyWrapper((Func<ObjectInstance, string, bool>)ObjectConstructor.HasOwnProperty, rootObject)), false);
-            //Object.Prototype.DefineOwnProperty("toString", new DataDescriptor(new BuiltInPropertyWrapper((Func<ObjectInstance, string>)ObjectConstructor.ToString, rootObject)), false);
+            String = new StringConstructor(this);
+            Number = new NumberConstructor(this);
+            Boolean = new BooleanConstructor(this);
 
             Global.Set("Object", Object);
             Global.Set("Function", Function);
             Global.Set("Array", Array);
+            Global.Set("String", String);
+            Global.Set("Number", Number);
+            Global.Set("Boolean", Boolean);
 
             // create the global environment http://www.ecma-international.org/ecma-262/5.1/#sec-10.2.3
             _globalEnvironment = LexicalEnvironment.NewObjectEnvironment(Global, null);
@@ -79,10 +82,12 @@ namespace Jint
         public ObjectConstructor Object { get; private set; }
         public FunctionConstructor Function { get; private set; }
         public ArrayConstructor Array { get; private set; }
+        public StringConstructor String { get; private set; }
+        public BooleanConstructor Boolean { get; private set; }
+        public NumberConstructor Number { get; private set; }
 
         public ExecutionContext CurrentExecutionContext { get { return _executionContexts.Peek(); } }
 
-        public object Result { get { return GetValue(_result); } }
         public Options Options { get; private set; }
 
         public ExecutionContext EnterExecutionContext(LexicalEnvironment lexicalEnvironment, LexicalEnvironment variableEnvironment, object thisBinding)
@@ -103,136 +108,140 @@ namespace Jint
             _executionContexts.Pop();
         }
 
-        public void Execute(string source)
+        public object Execute(string source)
         {
             var parser = new JavascriptParser();
-            Execute(parser.Parse(source));
+            return Execute(parser.Parse(source));
         }
 
-        public void Execute(Program program)
+        public object Execute(Program program)
         {
-            ExecuteStatement(program);
+            return ExecuteStatement(program);
         }
 
-        public void ExecuteStatement(Statement statement)
+        public object ExecuteStatement(Statement statement)
         {
             switch (statement.Type)
             {
                 case SyntaxNodes.BlockStatement:
-                    _statements.ExecuteBlockStatement(statement.As<BlockStatement>());
-                    break;
+                    return _statements.ExecuteBlockStatement(statement.As<BlockStatement>());
+                    
                 case SyntaxNodes.BreakStatement:
-                    _statements.ExecuteBreakStatement(statement.As<BreakStatement>());
-                    break;
+                    return _statements.ExecuteBreakStatement(statement.As<BreakStatement>());
+                    
                 case SyntaxNodes.ContinueStatement:
-                    _statements.ExecuteContinueStatement(statement.As<ContinueStatement>());
-                    break;
+                    return _statements.ExecuteContinueStatement(statement.As<ContinueStatement>());
+                    
                 case SyntaxNodes.DoWhileStatement:
-                    _statements.ExecuteDoWhileStatement(statement.As<DoWhileStatement>());
-                    break;
+                    return _statements.ExecuteDoWhileStatement(statement.As<DoWhileStatement>());
+                    
                 case SyntaxNodes.DebuggerStatement:
-                    _statements.ExecuteDebuggerStatement(statement.As<DebuggerStatement>());
-                    break;
+                    return _statements.ExecuteDebuggerStatement(statement.As<DebuggerStatement>());
+                    
                 case SyntaxNodes.EmptyStatement:
-                    _statements.ExecuteEmptyStatement(statement.As<EmptyStatement>());
-                    break;
+                    return _statements.ExecuteEmptyStatement(statement.As<EmptyStatement>());
+                    
                 case SyntaxNodes.ExpressionStatement:
-                    _statements.ExecuteExpressionStatement(statement.As<ExpressionStatement>());
-                    break;
+                    return _statements.ExecuteExpressionStatement(statement.As<ExpressionStatement>());
+
                 case SyntaxNodes.ForStatement:
-                    _statements.ExecuteForStatement(statement.As<ForStatement>());
-                    break;
+                    return _statements.ExecuteForStatement(statement.As<ForStatement>());
+                    
                 case SyntaxNodes.ForInStatement:
-                    break;
+                    return null;
+
                 case SyntaxNodes.FunctionDeclaration:
-                    _statements.ExecuteFunctionDeclaration(statement.As<FunctionDeclaration>());
-                    break;
+                    return _statements.ExecuteFunctionDeclaration(statement.As<FunctionDeclaration>());
+                    
                 case SyntaxNodes.IfStatement:
-                    _statements.ExecuteIfStatement(statement.As<IfStatement>());
-                    break;
+                    return _statements.ExecuteIfStatement(statement.As<IfStatement>());
+                    
                 case SyntaxNodes.LabeledStatement:
-                    break;
+                    return null;
+
                 case SyntaxNodes.ReturnStatement:
-                    _statements.ExecuteReturnStatement(statement.As<ReturnStatement>());
-                    break;
+                    return _statements.ExecuteReturnStatement(statement.As<ReturnStatement>());
+                    
                 case SyntaxNodes.SwitchStatement:
-                    break;
+                    return null;
+
                 case SyntaxNodes.ThrowStatement:
-                    break;
+                    return null;
+
                 case SyntaxNodes.TryStatement:
-                    break;
+                    return null;
+
                 case SyntaxNodes.VariableDeclaration:
-                    _statements.ExecuteVariableDeclaration(statement.As<VariableDeclaration>());
-                    break;
+                    return _statements.ExecuteVariableDeclaration(statement.As<VariableDeclaration>());
+                    
                 case SyntaxNodes.WhileStatement:
-                    _statements.ExecuteWhileStatement(statement.As<WhileStatement>());
-                    break;
+                    return _statements.ExecuteWhileStatement(statement.As<WhileStatement>());
+                    
                 case SyntaxNodes.WithStatement:
-                    break;
-                case SyntaxNodes.Program:
-                    _statements.ExecuteProgram(statement.As<Program>());
-                    break;
+                    return null;
 
+                case SyntaxNodes.Program:
+                    return _statements.ExecuteProgram(statement.As<Program>());
+                    
                 default:
                     throw new ArgumentOutOfRangeException();
             }
+
+            return null;
         }
 
         public dynamic EvaluateExpression(Expression expression)
         {
-            _result = Undefined.Instance;
-
             switch (expression.Type)
             {
                 case SyntaxNodes.AssignmentExpression:
-                    _result = _expressions.EvaluateAssignmentExpression(expression.As<AssignmentExpression>());
-                    break;
+                    return _expressions.EvaluateAssignmentExpression(expression.As<AssignmentExpression>());
+
                 case SyntaxNodes.ArrayExpression:
-                    _result = _expressions.EvaluateArrayExpression(expression.As<ArrayExpression>());
-                    break;
+                    return _expressions.EvaluateArrayExpression(expression.As<ArrayExpression>());
+
                 case SyntaxNodes.BinaryExpression:
-                    _result = _expressions.EvaluateBinaryExpression(expression.As<BinaryExpression>());
-                    break;
+                    return _expressions.EvaluateBinaryExpression(expression.As<BinaryExpression>());
+
                 case SyntaxNodes.CallExpression:
-                    _result = _expressions.EvaluateCallExpression(expression.As<CallExpression>());
-                    break;
+                    return _expressions.EvaluateCallExpression(expression.As<CallExpression>());
+
                 case SyntaxNodes.ConditionalExpression:
-                    _result = _expressions.EvaluateConditionalExpression(expression.As<ConditionalExpression>());
-                    break;
+                    return _expressions.EvaluateConditionalExpression(expression.As<ConditionalExpression>());
+
                 case SyntaxNodes.FunctionExpression:
-                    _result = _expressions.EvaluateFunctionExpression(expression.As<FunctionExpression>());
-                    break;
+                    return _expressions.EvaluateFunctionExpression(expression.As<FunctionExpression>());
+
                 case SyntaxNodes.Identifier:
-                    _result = _expressions.EvaluateIdentifier(expression.As<Identifier>());
-                    break;
+                    return _expressions.EvaluateIdentifier(expression.As<Identifier>());
+
                 case SyntaxNodes.Literal:
-                    _result = _expressions.EvaluateLiteral(expression.As<Literal>());
-                    break;
+                    return _expressions.EvaluateLiteral(expression.As<Literal>());
+
                 case SyntaxNodes.LogicalExpression:
-                    break;
+                    return null;
+
                 case SyntaxNodes.MemberExpression:
-                    _result = _expressions.EvaluateMemberExpression(expression.As<MemberExpression>());
-                    break;
+                    return _expressions.EvaluateMemberExpression(expression.As<MemberExpression>());
+
                 case SyntaxNodes.NewExpression:
-                    _result = _expressions.EvaluateNewExpression(expression.As<NewExpression>());
-                    break;
+                    return _expressions.EvaluateNewExpression(expression.As<NewExpression>());
+
                 case SyntaxNodes.ObjectExpression:
-                    _result = _expressions.EvaluateObjectExpression(expression.As<ObjectExpression>());
-                    break;
+                    return _expressions.EvaluateObjectExpression(expression.As<ObjectExpression>());
+
                 case SyntaxNodes.SequenceExpression:
-                    _result = _expressions.EvaluateSequenceExpression(expression.As<SequenceExpression>());
-                    break;
+                    return _expressions.EvaluateSequenceExpression(expression.As<SequenceExpression>());
+
                 case SyntaxNodes.ThisExpression:
-                    _result = _expressions.EvaluateThisExpression(expression.As<ThisExpression>());
-                    break;
+                    return _expressions.EvaluateThisExpression(expression.As<ThisExpression>());
+
                 case SyntaxNodes.UpdateExpression:
-                    _result = _expressions.EvaluateUpdateExpression(expression.As<UpdateExpression>());
-                    break;
+                    return _expressions.EvaluateUpdateExpression(expression.As<UpdateExpression>());
+
                 default:
                     throw new ArgumentOutOfRangeException();
             }
-
-            return _result;
         }
 
         public dynamic GetValue(object value)
@@ -288,5 +297,14 @@ namespace Jint
             }
         }
 
+        public object GetGlobalValue(string propertyName)
+        {
+            if (System.String.IsNullOrEmpty(propertyName))
+            {
+                throw new ArgumentException("propertyName");
+            }
+
+            return GetValue(Global.Get(propertyName));
+        }
     }
 }

+ 7 - 0
Jint/Jint.csproj

@@ -46,6 +46,10 @@
   <ItemGroup>
     <Compile Include="Native\Array\ArrayConstructor.cs" />
     <Compile Include="Native\Array\ArrayInstance.cs" />
+    <Compile Include="Native\Boolean\BooleanConstructor.cs" />
+    <Compile Include="Native\Boolean\BooleanInstance.cs" />
+    <Compile Include="Native\String\StringConstructor.cs" />
+    <Compile Include="Native\String\StringInstance.cs" />
     <Compile Include="Native\Errors\TypeError.cs" />
     <Compile Include="Native\Errors\ReferenceError.cs" />
     <Compile Include="Native\Function\ScriptFunctionInstance.cs" />
@@ -53,6 +57,8 @@
     <Compile Include="Native\Null.cs" />
     <Compile Include="Native\Function\FunctionShim.cs" />
     <Compile Include="Native\Function\FunctionInstance.cs" />
+    <Compile Include="Native\Number\NumberConstructor.cs" />
+    <Compile Include="Native\Number\NumberInstance.cs" />
     <Compile Include="Native\Object\ObjectConstructor.cs" />
     <Compile Include="Native\Object\ObjectInstance.cs" />
     <Compile Include="Native\Undefined.cs" />
@@ -128,6 +134,7 @@
     <Compile Include="Runtime\Descriptors\PropertyDescriptor.cs" />
     <Compile Include="Runtime\References\Reference.cs" />
     <Compile Include="Runtime\StatementInterpreter.cs" />
+    <Compile Include="Runtime\TypeConverter.cs" />
   </ItemGroup>
   <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

+ 7 - 2
Jint/Native/Array/ArrayConstructor.cs

@@ -21,6 +21,7 @@ namespace Jint.Native.Array
 
             // Array method
             this.Prototype.DefineOwnProperty("push", new DataDescriptor(new BuiltInPropertyWrapper(engine, (Action<ArrayInstance, object>)Push, engine.RootFunction)), false);
+            this.Prototype.DefineOwnProperty("pop", new DataDescriptor(new BuiltInPropertyWrapper(engine, (Func<ArrayInstance, object>)Pop, engine.RootFunction)), false);
         }
 
         public override dynamic Call(object thisObject, dynamic[] arguments)
@@ -32,7 +33,7 @@ namespace Jint.Native.Array
         {
             var instance = new ArrayInstance(Prototype);
 
-            instance.DefineOwnProperty("length", new DataDescriptor((double)0), false);
+            instance.DefineOwnProperty("length", new AccessorDescriptor(() => instance.Length, x => { }), false);
 
             foreach (var arg in arguments)
             {
@@ -45,7 +46,11 @@ namespace Jint.Native.Array
         private static void Push(ArrayInstance thisObject, object o)
         {
             thisObject.Push(o);
-            thisObject.Set("length", (double)thisObject.Get("length") + 1);
+        }
+
+        private static object Pop(ArrayInstance thisObject)
+        {
+            return thisObject.Pop();
         }
     }
 }

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

@@ -9,7 +9,7 @@ namespace Jint.Native.Array
 {
     public class ArrayInstance : ObjectInstance
     {
-        private readonly List<object> _array = new List<object>();
+        private readonly Stack<object> _array = new Stack<object>();
  
         public ArrayInstance(ObjectInstance prototype) : base(prototype)
         {
@@ -23,11 +23,16 @@ namespace Jint.Native.Array
             }
         }
 
-        public int Length { get { return _array.Count; } }
+        public double Length { get { return _array.Count; } }
 
         public void Push(object o)
         {
-            _array.Add(o);
+            _array.Push(o);
+        }
+
+        public object Pop()
+        {
+            return _array.Pop();
         }
     }
 }

+ 45 - 0
Jint/Native/Boolean/BooleanConstructor.cs

@@ -0,0 +1,45 @@
+using Jint.Native.Function;
+using Jint.Native.Object;
+using Jint.Runtime;
+using Jint.Runtime.Descriptors;
+
+namespace Jint.Native.Boolean
+{
+    public class BooleanConstructor : FunctionInstance
+    {
+        private readonly Engine _engine;
+
+        public BooleanConstructor(Engine engine)
+            : base(engine, new ObjectInstance(engine.Object), null, null)
+        {
+            _engine = engine;
+
+            // the constructor is the function constructor of an object
+            this.Prototype.DefineOwnProperty("constructor", new DataDescriptor(this) { Writable = true, Enumerable = false, Configurable = false }, false);
+            this.Prototype.DefineOwnProperty("prototype", new DataDescriptor(Prototype) { Writable = true, Enumerable = false, Configurable = false }, false);
+
+        }
+
+        public override dynamic Call(object thisObject, dynamic[] arguments)
+        {
+            return Construct(arguments);
+        }
+
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.7.2.1
+        /// </summary>
+        /// <param name="arguments"></param>
+        /// <returns></returns>
+        public virtual ObjectInstance Construct(dynamic[] arguments)
+        {
+            return Construct(TypeConverter.ToBoolean(arguments[0]));
+        }
+
+        public BooleanInstance Construct(bool value)
+        {
+            var instance = new BooleanInstance(Prototype);
+            instance.PrimitiveValue = value;
+            return instance;
+        }
+    }
+}

+ 33 - 0
Jint/Native/Boolean/BooleanInstance.cs

@@ -0,0 +1,33 @@
+using System;
+using Jint.Native.Object;
+
+namespace Jint.Native.Boolean
+{
+    public class BooleanInstance : ObjectInstance, IPrimitiveType
+    {
+        public BooleanInstance(ObjectInstance prototype)
+            : base(prototype)
+        {
+        }
+
+        public override string Class
+        {
+            get
+            {
+                return "Boolean";
+            }
+        }
+
+        TypeCode IPrimitiveType.TypeCode
+        {
+            get { return TypeCode.Boolean; }
+        }
+
+        object IPrimitiveType.PrimitiveValue
+        {
+            get { return PrimitiveValue; }
+        }
+
+        public bool PrimitiveValue { get; set; }
+    }
+}

+ 5 - 1
Jint/Native/IPrimitiveType.cs

@@ -1,6 +1,10 @@
-namespace Jint.Native
+using System;
+
+namespace Jint.Native
 {
     public interface IPrimitiveType
     {
+        TypeCode TypeCode { get; } 
+        object PrimitiveValue { get; }
     }
 }

+ 13 - 1
Jint/Native/Null.cs

@@ -1,4 +1,6 @@
-namespace Jint.Native
+using System;
+
+namespace Jint.Native
 {
     public sealed class Null : IPrimitiveType
     {
@@ -12,5 +14,15 @@
         {
             return "null";
         }
+
+        public TypeCode TypeCode
+        {
+            get { return TypeCode.DBNull; }
+        }
+
+        public object PrimitiveValue
+        {
+            get { return Instance; }
+        }
     }
 }

+ 47 - 0
Jint/Native/Number/NumberConstructor.cs

@@ -0,0 +1,47 @@
+using Jint.Native.Function;
+using Jint.Native.Object;
+using Jint.Runtime;
+using Jint.Runtime.Descriptors;
+
+namespace Jint.Native.Number
+{
+    public class NumberConstructor : FunctionInstance
+    {
+        private readonly Engine _engine;
+
+        public NumberConstructor(Engine engine)
+            : base(engine, new ObjectInstance(engine.Object), null, null)
+        {
+            _engine = engine;
+
+            // the constructor is the function constructor of an object
+            this.Prototype.DefineOwnProperty("constructor", new DataDescriptor(this) { Writable = true, Enumerable = false, Configurable = false }, false);
+            this.Prototype.DefineOwnProperty("prototype", new DataDescriptor(Prototype) { Writable = true, Enumerable = false, Configurable = false }, false);
+
+        }
+
+        public override dynamic Call(object thisObject, dynamic[] arguments)
+        {
+            return Construct(arguments);
+        }
+
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.7.2.1
+        /// </summary>
+        /// <param name="arguments"></param>
+        /// <returns></returns>
+        public virtual ObjectInstance Construct(dynamic[] arguments)
+        {
+            return Construct(arguments.Length > 0 ? TypeConverter.ToNumber(arguments[0]) : 0);
+        }
+
+        public NumberInstance Construct(double value)
+        {
+            var instance = new NumberInstance(Prototype);
+            instance.PrimitiveValue = value;
+            return instance;
+        }
+
+
+    }
+}

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

@@ -0,0 +1,33 @@
+using System;
+using Jint.Native.Object;
+
+namespace Jint.Native.Number
+{
+    public class NumberInstance : ObjectInstance, IPrimitiveType
+    {
+        public NumberInstance(ObjectInstance prototype)
+            : base(prototype)
+        {
+        }
+
+        public override string Class
+        {
+            get
+            {
+                return "Number";
+            }
+        }
+
+        TypeCode IPrimitiveType.TypeCode
+        {
+            get { return TypeCode.Double; }
+        }
+
+        object IPrimitiveType.PrimitiveValue
+        {
+            get { return PrimitiveValue; }
+        }
+
+        public double PrimitiveValue { get; set; }
+    }
+}

+ 0 - 1
Jint/Native/Object/ObjectInstance.cs

@@ -328,6 +328,5 @@ namespace Jint.Native.Object
 
             return true;
         }
-
     }
 }

+ 45 - 0
Jint/Native/String/StringConstructor.cs

@@ -0,0 +1,45 @@
+using Jint.Native.Function;
+using Jint.Native.Object;
+using Jint.Runtime;
+using Jint.Runtime.Descriptors;
+
+namespace Jint.Native.String
+{
+    public class StringConstructor : FunctionInstance
+    {
+        private readonly Engine _engine;
+
+        public StringConstructor(Engine engine)
+            : base(engine, new ObjectInstance(engine.Object), null, null)
+        {
+            _engine = engine;
+
+            // the constructor is the function constructor of an object
+            this.Prototype.DefineOwnProperty("constructor", new DataDescriptor(this) { Writable = true, Enumerable = false, Configurable = false }, false);
+            this.Prototype.DefineOwnProperty("prototype", new DataDescriptor(Prototype) { Writable = true, Enumerable = false, Configurable = false }, false);
+
+        }
+
+        public override dynamic Call(object thisObject, dynamic[] arguments)
+        {
+            return Construct(arguments);
+        }
+
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.7.2.1
+        /// </summary>
+        /// <param name="arguments"></param>
+        /// <returns></returns>
+        public virtual ObjectInstance Construct(dynamic[] arguments)
+        {
+            return Construct(arguments.Length > 0 ? TypeConverter.ToString(arguments[0]) : "");
+        }
+
+        public StringInstance Construct(string value)
+        {
+            var instance = new StringInstance(Prototype);
+            instance.PrimitiveValue = value;
+            return instance;
+        }
+    }
+}

+ 33 - 0
Jint/Native/String/StringInstance.cs

@@ -0,0 +1,33 @@
+using System;
+using Jint.Native.Object;
+
+namespace Jint.Native.String
+{
+    public class StringInstance : ObjectInstance, IPrimitiveType
+    {
+        public StringInstance(ObjectInstance prototype)
+            : base(prototype)
+        {
+        }
+
+        public override string Class
+        {
+            get
+            {
+                return "String";
+            }
+        }
+
+        TypeCode IPrimitiveType.TypeCode
+        {
+            get { return TypeCode.Boolean; }
+        }
+
+        object IPrimitiveType.PrimitiveValue
+        {
+            get { return PrimitiveValue; }
+        }
+
+        public string PrimitiveValue { get; set; }
+    }
+}

+ 13 - 1
Jint/Native/Undefined.cs

@@ -1,4 +1,6 @@
-namespace Jint.Native
+using System;
+
+namespace Jint.Native
 {
     public class Undefined : IPrimitiveType
     {
@@ -12,5 +14,15 @@
         {
             return "undefined";
         }
+
+        public TypeCode TypeCode
+        {
+            get { return TypeCode.DBNull; }
+        }
+
+        public object PrimitiveValue
+        {
+            get { return Instance; }
+        }
     }
 }

+ 61 - 29
Jint/Runtime/StatementInterpreter.cs

@@ -14,21 +14,26 @@ namespace Jint.Runtime
             _engine = engine;
         }
 
-        private void ExecuteStatement(Statement statement)
+        private object ExecuteStatement(Statement statement)
         {
-            _engine.ExecuteStatement(statement);
+            return _engine.ExecuteStatement(statement);
         }
 
-        public void ExecuteProgram(Program program)
+        public object ExecuteProgram(Program program)
         {
+            object result = null;
+
             foreach (var statement in program.Body)
             {
-                ExecuteStatement(statement);
+                result = ExecuteStatement(statement);
             }
+
+            return result;
         }
 
-        public void ExecuteVariableDeclaration(VariableDeclaration statement)
+        public object ExecuteVariableDeclaration(VariableDeclaration statement)
         {
+            object result = null;
             var env = _engine.CurrentExecutionContext.VariableEnvironment.Record;
 
             foreach (var declaration in statement.Declarations)
@@ -37,7 +42,7 @@ namespace Jint.Runtime
 
                 if (declaration.Init != null)
                 {
-                    value = _engine.EvaluateExpression(declaration.Init);
+                    result = value = _engine.EvaluateExpression(declaration.Init);
                 }
 
                 var dn = declaration.Id.Name;
@@ -48,58 +53,72 @@ namespace Jint.Runtime
                     env.SetMutableBinding(declaration.Id.Name, value, false);
                 }
             }
+
+            return result;
         }
 
-        public void ExecuteDoWhileStatement(DoWhileStatement doWhileStatement)
+        public object ExecuteDoWhileStatement(DoWhileStatement doWhileStatement)
         {
+            object result = null;
+
             bool test;
             do
             {
-                ExecuteStatement(doWhileStatement.Body);
+                result = ExecuteStatement(doWhileStatement.Body);
                 test = _engine.EvaluateExpression(doWhileStatement.Test);
             } while (test);
+
+            return result;
         }
 
-        public void ExecuteContinueStatement(ContinueStatement continueStatement)
+        public object ExecuteContinueStatement(ContinueStatement continueStatement)
         {
             _engine.CurrentExecutionContext.Continue = continueStatement;
+            return null;
         }
 
-        public void ExecuteBreakStatement(BreakStatement breakStatement)
+        public object ExecuteBreakStatement(BreakStatement breakStatement)
         {
             _engine.CurrentExecutionContext.Break = breakStatement;
+            return null;
         }
 
-        public void ExecuteBlockStatement(BlockStatement blockStatement)
+        public object ExecuteBlockStatement(BlockStatement blockStatement)
         {
+            object result = null;
             foreach (var statement in blockStatement.Body)
             {
-                ExecuteStatement(statement);
+                result = ExecuteStatement(statement);
 
                 // return has been called, stop execution
                 if (!_engine.CurrentExecutionContext.Return.Equals(Undefined.Instance))
                 {
-                    return;
+                    return result;
                 }
             }
+
+            return result;
         }
 
-        public void ExecuteEmptyStatement(EmptyStatement emptyStatement)
+        public object ExecuteEmptyStatement(EmptyStatement emptyStatement)
         {
+            return null;
         }
 
-        public void ExecuteExpressionStatement(ExpressionStatement expressionStatement)
+        public object ExecuteExpressionStatement(ExpressionStatement expressionStatement)
         {
-            _engine.EvaluateExpression(expressionStatement.Expression);
+            return _engine.EvaluateExpression(expressionStatement.Expression);
         }
 
-        public void ExecuteReturnStatement(ReturnStatement statement)
+        public object ExecuteReturnStatement(ReturnStatement statement)
         {
-            _engine.CurrentExecutionContext.Return = _engine.EvaluateExpression(statement.Argument);
+            return _engine.CurrentExecutionContext.Return = _engine.EvaluateExpression(statement.Argument);
         }
 
-        public void ExecuteFunctionDeclaration(FunctionDeclaration functionDeclaration)
+        public object ExecuteFunctionDeclaration(FunctionDeclaration functionDeclaration)
         {
+            object result = null;
+
             // create function objects
             http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
 
@@ -108,7 +127,7 @@ namespace Jint.Runtime
             // todo: should be declared in the current context
             _engine.Global.Set(
                 identifier, 
-                new ScriptFunctionInstance(
+                result = new ScriptFunctionInstance(
                     _engine,
                     functionDeclaration.Body, 
                     identifier, 
@@ -118,47 +137,58 @@ namespace Jint.Runtime
                     LexicalEnvironment.NewDeclarativeEnvironment(_engine.CurrentExecutionContext.LexicalEnvironment)
                 )
             );
+
+            return result;
         }
 
-        public void ExecuteIfStatement(IfStatement ifStatement)
+        public object ExecuteIfStatement(IfStatement ifStatement)
         {
+            object result = null;
             var test = _engine.EvaluateExpression(ifStatement.Test);
 
             if (test)
             {
-                _engine.ExecuteStatement(ifStatement.Consequent);
+                result = _engine.ExecuteStatement(ifStatement.Consequent);
             }
             else if (ifStatement.Alternate != null)
             {
-                _engine.ExecuteStatement(ifStatement.Alternate);
+                result = _engine.ExecuteStatement(ifStatement.Alternate);
             }
+
+            return result;
         }
 
-        public void ExecuteWhileStatement(WhileStatement whileStatement)
+        public object ExecuteWhileStatement(WhileStatement whileStatement)
         {
+            object result = null;
+
             bool test = _engine.EvaluateExpression(whileStatement.Test);
 
             while(test)
             {
-                ExecuteStatement(whileStatement.Body);
+                result = ExecuteStatement(whileStatement.Body);
                 test = _engine.EvaluateExpression(whileStatement.Test);
             }
+
+            return result;
         }
 
-        public void ExecuteDebuggerStatement(DebuggerStatement debuggerStatement)
+        public object ExecuteDebuggerStatement(DebuggerStatement debuggerStatement)
         {
             throw new System.NotImplementedException();
         }
 
-        public void ExecuteForStatement(ForStatement forStatement)
+        public object ExecuteForStatement(ForStatement forStatement)
         {
+            object result = null;
+
             if (forStatement.Init.Type == SyntaxNodes.VariableDeclaration)
             {
-                _engine.ExecuteStatement(forStatement.Init.As<Statement>());
+                result = _engine.ExecuteStatement(forStatement.Init.As<Statement>());
             }
             else
             {
-                _engine.EvaluateExpression(forStatement.Init.As<Expression>());
+                result = _engine.EvaluateExpression(forStatement.Init.As<Expression>());
             }
 
             while (_engine.EvaluateExpression(forStatement.Test))
@@ -166,6 +196,8 @@ namespace Jint.Runtime
                 _engine.ExecuteStatement(forStatement.Body);
                 _engine.EvaluateExpression(forStatement.Update);
             }
+
+            return result;
         }
     }
 }

+ 163 - 0
Jint/Runtime/TypeConverter.cs

@@ -0,0 +1,163 @@
+using System;
+using Jint.Native;
+using Jint.Native.Errors;
+using Jint.Native.Object;
+
+namespace Jint.Runtime
+{
+    public class TypeConverter
+    {
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-9.1
+        /// </summary>
+        /// <param name="input"></param>
+        /// <param name="preferredType"></param>
+        /// <returns></returns>
+        public static object ToPrimitive(object input, TypeCode preferredType)
+        {
+            return Undefined.Instance;
+        }
+
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-9.2
+        /// </summary>
+        /// <param name="o"></param>
+        /// <returns></returns>
+        public static bool ToBoolean(object o)
+        {
+            return (bool) o;
+        }
+
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-9.3
+        /// </summary>
+        /// <param name="o"></param>
+        /// <returns></returns>
+        public static double ToNumber(object o)
+        {
+            if (o == Undefined.Instance)
+            {
+                return double.NaN;
+            }
+
+            if (o == Null.Instance)
+            {
+                return 0;
+            }
+
+            if (o is bool)
+            {
+                return (bool)o ? 1 : 0;
+            }
+
+            if (o is double)
+            {
+                return (double)o;
+            }
+
+            var s = o as string;
+            if (s != null)
+            {
+                return double.Parse(s);
+            }
+
+            return ToNumber(ToPrimitive(o, TypeCode.Double));
+        }
+
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-9.4
+        /// </summary>
+        /// <param name="o"></param>
+        /// <returns></returns>
+        public int ToInteger(object o)
+        {
+            return (int) o;
+        }
+
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-9.5
+        /// </summary>
+        /// <param name="o"></param>
+        /// <returns></returns>
+        public int ToInt32(object o)
+        {
+            return (int)o;
+        }
+
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-9.6
+        /// </summary>
+        /// <param name="o"></param>
+        /// <returns></returns>
+        public uint ToUint32(object o)
+        {
+            return (uint)o;
+        }
+
+
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-9.7
+        /// </summary>
+        /// <param name="o"></param>
+        /// <returns></returns>
+        public ushort ToUint16(object o)
+        {
+            return (ushort)o;
+        }
+
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-9.8
+        /// </summary>
+        /// <param name="o"></param>
+        /// <returns></returns>
+        public string ToString(object o)
+        {
+            return (string)o;
+        }
+
+        public ObjectInstance ToObject(Engine engine, object value)
+        {
+            var o = value as ObjectInstance;
+            if (o != null)
+            {
+                return o;
+            }
+
+            if (value == Undefined.Instance)
+            {
+                throw new TypeError();
+            }
+
+            if (value == Null.Instance)
+            {
+                throw new TypeError();
+            }
+
+            if (value is bool)
+            {
+                return engine.Boolean.Construct((bool) value);
+            }
+
+            if (value is int)
+            {
+                return engine.Number.Construct((int) value);
+            }
+
+            if (value is uint)
+            {
+                return engine.Number.Construct((uint) value);
+            }
+
+            if (value is double)
+            {
+                return engine.Number.Construct((double) value);
+            }
+            if (value is string)
+            {
+                return engine.String.Construct((string) value);
+            }
+
+            throw new TypeError();
+        }
+    }
+}