瀏覽代碼

Implementing statement completion results

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

+ 19 - 12
Jint/Engine.cs

@@ -95,7 +95,7 @@ namespace Jint
         public DateConstructor Date { get; private set; }
         public DateConstructor Date { get; private set; }
         public MathInstance Math { get; private set; }
         public MathInstance Math { get; private set; }
 
 
-        public ExecutionContext CurrentExecutionContext { get { return _executionContexts.Peek(); } }
+        public ExecutionContext ExecutionContext { get { return _executionContexts.Peek(); } }
 
 
         public Options Options { get; private set; }
         public Options Options { get; private set; }
 
 
@@ -117,18 +117,18 @@ namespace Jint
             _executionContexts.Pop();
             _executionContexts.Pop();
         }
         }
 
 
-        public object Execute(string source)
+        public Completion Execute(string source)
         {
         {
             var parser = new JavascriptParser();
             var parser = new JavascriptParser();
             return Execute(parser.Parse(source));
             return Execute(parser.Parse(source));
         }
         }
 
 
-        public object Execute(Program program)
+        public Completion Execute(Program program)
         {
         {
             return ExecuteStatement(program);
             return ExecuteStatement(program);
         }
         }
 
 
-        public object ExecuteStatement(Statement statement)
+        public Completion ExecuteStatement(Statement statement)
         {
         {
             switch (statement.Type)
             switch (statement.Type)
             {
             {
@@ -157,7 +157,7 @@ namespace Jint
                     return _statements.ExecuteForStatement(statement.As<ForStatement>());
                     return _statements.ExecuteForStatement(statement.As<ForStatement>());
                     
                     
                 case SyntaxNodes.ForInStatement:
                 case SyntaxNodes.ForInStatement:
-                    return null;
+                    return _statements.ForInStatement(statement.As<ForInStatement>());
 
 
                 case SyntaxNodes.FunctionDeclaration:
                 case SyntaxNodes.FunctionDeclaration:
                     return _statements.ExecuteFunctionDeclaration(statement.As<FunctionDeclaration>());
                     return _statements.ExecuteFunctionDeclaration(statement.As<FunctionDeclaration>());
@@ -172,14 +172,14 @@ namespace Jint
                     return _statements.ExecuteReturnStatement(statement.As<ReturnStatement>());
                     return _statements.ExecuteReturnStatement(statement.As<ReturnStatement>());
                     
                     
                 case SyntaxNodes.SwitchStatement:
                 case SyntaxNodes.SwitchStatement:
-                    return null;
-
+                    return _statements.ExecuteSwitchStatement(statement.As<SwitchStatement>());
+                    
                 case SyntaxNodes.ThrowStatement:
                 case SyntaxNodes.ThrowStatement:
-                    return null;
+                    return _statements.ExecuteThrowStatement(statement.As<ThrowStatement>());
 
 
                 case SyntaxNodes.TryStatement:
                 case SyntaxNodes.TryStatement:
-                    return null;
-
+                    return _statements.ExecuteTryStatement(statement.As<TryStatement>());
+                    
                 case SyntaxNodes.VariableDeclaration:
                 case SyntaxNodes.VariableDeclaration:
                     return _statements.ExecuteVariableDeclaration(statement.As<VariableDeclaration>());
                     return _statements.ExecuteVariableDeclaration(statement.As<VariableDeclaration>());
                     
                     
@@ -187,7 +187,7 @@ namespace Jint
                     return _statements.ExecuteWhileStatement(statement.As<WhileStatement>());
                     return _statements.ExecuteWhileStatement(statement.As<WhileStatement>());
                     
                     
                 case SyntaxNodes.WithStatement:
                 case SyntaxNodes.WithStatement:
-                    return null;
+                    return _statements.ExecuteWithStatement(statement.As<WithStatement>());
 
 
                 case SyntaxNodes.Program:
                 case SyntaxNodes.Program:
                     return _statements.ExecuteProgram(statement.As<Program>());
                     return _statements.ExecuteProgram(statement.As<Program>());
@@ -264,9 +264,16 @@ namespace Jint
         public object GetValue(object value)
         public object GetValue(object value)
         {
         {
             var reference = value as Reference;
             var reference = value as Reference;
-            
+
             if (reference == null)
             if (reference == null)
             {
             {
+                var completion = value as Completion;
+
+                if (completion != null)
+                {
+                    return GetValue(completion.Value);
+                }
+
                 return value;
                 return value;
             }
             }
 
 

+ 2 - 0
Jint/Jint.csproj

@@ -43,6 +43,7 @@
     <Compile Include="Native\Boolean\BooleanInstance.cs" />
     <Compile Include="Native\Boolean\BooleanInstance.cs" />
     <Compile Include="Native\Date\DateConstructor.cs" />
     <Compile Include="Native\Date\DateConstructor.cs" />
     <Compile Include="Native\Date\DateInstance.cs" />
     <Compile Include="Native\Date\DateInstance.cs" />
+    <Compile Include="Native\Errors\Error.cs" />
     <Compile Include="Native\Errors\SyntaxError.cs" />
     <Compile Include="Native\Errors\SyntaxError.cs" />
     <Compile Include="Native\Errors\ReferenceError.cs" />
     <Compile Include="Native\Errors\ReferenceError.cs" />
     <Compile Include="Native\Errors\TypeError.cs" />
     <Compile Include="Native\Errors\TypeError.cs" />
@@ -120,6 +121,7 @@
     <Compile Include="Parser\Token.cs" />
     <Compile Include="Parser\Token.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Runtime\Arguments.cs" />
     <Compile Include="Runtime\Arguments.cs" />
+    <Compile Include="Runtime\Completion.cs" />
     <Compile Include="Runtime\Descriptors\AccessorDescriptor.cs" />
     <Compile Include="Runtime\Descriptors\AccessorDescriptor.cs" />
     <Compile Include="Runtime\Descriptors\DataDescriptor.cs" />
     <Compile Include="Runtime\Descriptors\DataDescriptor.cs" />
     <Compile Include="Runtime\Descriptors\PropertyDescriptor.cs" />
     <Compile Include="Runtime\Descriptors\PropertyDescriptor.cs" />

+ 8 - 0
Jint/Native/Errors/Error.cs

@@ -0,0 +1,8 @@
+using System;
+
+namespace Jint.Native.Errors
+{
+    public class Error : Exception
+    {
+    }
+}

+ 1 - 1
Jint/Native/Errors/ReferenceError.cs

@@ -2,7 +2,7 @@
 
 
 namespace Jint.Native.Errors
 namespace Jint.Native.Errors
 {
 {
-    public class ReferenceError : Exception
+    public class ReferenceError : Error
     {
     {
     }
     }
 }
 }

+ 1 - 1
Jint/Native/Errors/SyntaxError.cs

@@ -2,7 +2,7 @@
 
 
 namespace Jint.Native.Errors
 namespace Jint.Native.Errors
 {
 {
-    public class SyntaxError : Exception
+    public class SyntaxError : Error
     {
     {
     }
     }
 }
 }

+ 1 - 1
Jint/Native/Errors/TypeError.cs

@@ -2,7 +2,7 @@
 
 
 namespace Jint.Native.Errors
 namespace Jint.Native.Errors
 {
 {
-    public class TypeError : Exception
+    public class TypeError : Error
     {
     {
     }
     }
 }
 }

+ 3 - 4
Jint/Native/Function/ScriptFunctionInstance.cs

@@ -59,9 +59,8 @@ namespace Jint.Native.Function
                 env.SetMutableBinding(parameter.Name, i < arguments.Length ? arguments[i++] : Undefined.Instance, false);
                 env.SetMutableBinding(parameter.Name, i < arguments.Length ? arguments[i++] : Undefined.Instance, false);
             }
             }
 
 
-            _engine.ExecuteStatement(_body);
-            var result = _engine.CurrentExecutionContext.Return;
-
+            var result = _engine.ExecuteStatement(_body);
+            
             _engine.LeaveExecutionContext();
             _engine.LeaveExecutionContext();
 
 
             return result;
             return result;
@@ -71,7 +70,7 @@ namespace Jint.Native.Function
         {
         {
             // todo: http://www.ecma-international.org/ecma-262/5.1/#sec-13.2.2
             // todo: http://www.ecma-international.org/ecma-262/5.1/#sec-13.2.2
 
 
-            var instance = new FunctionShim(_engine, this.Prototype, null, null);
+            var instance = new FunctionShim(_engine, Prototype, null, null);
             return instance;
             return instance;
         }
         }
     }
     }

+ 1 - 1
Jint/Parser/Ast/CatchClause.cs

@@ -2,7 +2,7 @@ namespace Jint.Parser.Ast
 {
 {
     public class CatchClause : Statement
     public class CatchClause : Statement
     {
     {
-        public SyntaxNode Param;
+        public Identifier Param;
         public BlockStatement Body;
         public BlockStatement Body;
     }
     }
 }
 }

+ 1 - 1
Jint/Parser/Ast/ForInStatement.cs

@@ -3,7 +3,7 @@ namespace Jint.Parser.Ast
     public class ForInStatement : Statement
     public class ForInStatement : Statement
     {
     {
         public SyntaxNode Left;
         public SyntaxNode Left;
-        public SyntaxNode Right;
+        public Expression Right;
         public Statement Body;
         public Statement Body;
         public bool Each;
         public bool Each;
     }
     }

+ 1 - 1
Jint/Parser/Ast/Program.cs

@@ -8,7 +8,7 @@ namespace Jint.Parser.Ast
 
 
         public List<Comment> Comments;
         public List<Comment> Comments;
         public List<Token> Tokens;
         public List<Token> Tokens;
-        public List<Error> Errors;
+        public List<ParserError> Errors;
 
 
     }
     }
 }
 }

+ 1 - 1
Jint/Parser/Ast/SwitchStatement.cs

@@ -4,7 +4,7 @@ namespace Jint.Parser.Ast
 {
 {
     public class SwitchStatement : Statement
     public class SwitchStatement : Statement
     {
     {
-        public SyntaxNode Discriminant;
+        public Expression Discriminant;
         public IEnumerable<SwitchCase> Cases;
         public IEnumerable<SwitchCase> Cases;
     }
     }
 }
 }

+ 1 - 1
Jint/Parser/Ast/ThrowStatement.cs

@@ -2,6 +2,6 @@ namespace Jint.Parser.Ast
 {
 {
     public class ThrowStatement : Statement
     public class ThrowStatement : Statement
     {
     {
-        public SyntaxNode Argument;
+        public Expression Argument;
     }
     }
 }
 }

+ 1 - 1
Jint/Parser/Ast/TryStatement.cs

@@ -6,7 +6,7 @@ namespace Jint.Parser.Ast
     {
     {
         public Statement Block;
         public Statement Block;
         public IEnumerable<Statement> GuardedHandlers;
         public IEnumerable<Statement> GuardedHandlers;
-        public IEnumerable<Statement> Handlers;
+        public IEnumerable<CatchClause> Handlers;
         public Statement Finalizer;
         public Statement Finalizer;
     }
     }
 }
 }

+ 2 - 2
Jint/Parser/Ast/WithStatement.cs

@@ -4,7 +4,7 @@ namespace Jint
 {
 {
     public class WithStatement : Statement
     public class WithStatement : Statement
     {
     {
-        public object obj;
-        public Statement body;
+        public Expression Object;
+        public Statement Body;
     }
     }
 }
 }

+ 15 - 15
Jint/Parser/JavascriptParser.cs

@@ -1392,7 +1392,7 @@ namespace Jint.Parser
                 };
                 };
         }
         }
 
 
-        public CatchClause CreateCatchClause(SyntaxNode param, BlockStatement body)
+        public CatchClause CreateCatchClause(Identifier param, BlockStatement body)
         {
         {
             return new CatchClause
             return new CatchClause
                 {
                 {
@@ -1470,7 +1470,7 @@ namespace Jint.Parser
                 };
                 };
         }
         }
 
 
-        public ForInStatement CreateForInStatement(SyntaxNode left, SyntaxNode right, Statement body)
+        public ForInStatement CreateForInStatement(SyntaxNode left, Expression right, Statement body)
         {
         {
             return new ForInStatement
             return new ForInStatement
                 {
                 {
@@ -1643,7 +1643,7 @@ namespace Jint.Parser
                 };
                 };
         }
         }
 
 
-        public SwitchStatement CreateSwitchStatement(SyntaxNode discriminant, IEnumerable<SwitchCase> cases)
+        public SwitchStatement CreateSwitchStatement(Expression discriminant, IEnumerable<SwitchCase> cases)
         {
         {
             return new SwitchStatement
             return new SwitchStatement
                 {
                 {
@@ -1661,7 +1661,7 @@ namespace Jint.Parser
                 };
                 };
         }
         }
 
 
-        public ThrowStatement CreateThrowStatement(SyntaxNode argument)
+        public ThrowStatement CreateThrowStatement(Expression argument)
         {
         {
             return new ThrowStatement
             return new ThrowStatement
                 {
                 {
@@ -1671,7 +1671,7 @@ namespace Jint.Parser
         }
         }
 
 
         public TryStatement CreateTryStatement(Statement block, IEnumerable<Statement> guardedHandlers,
         public TryStatement CreateTryStatement(Statement block, IEnumerable<Statement> guardedHandlers,
-                                               IEnumerable<Statement> handlers, Statement finalizer)
+                                               IEnumerable<CatchClause> handlers, Statement finalizer)
         {
         {
             return new TryStatement
             return new TryStatement
                 {
                 {
@@ -1734,13 +1734,13 @@ namespace Jint.Parser
                 };
                 };
         }
         }
 
 
-        public WithStatement CreateWithStatement(object obj, Statement body)
+        public WithStatement CreateWithStatement(Expression obj, Statement body)
         {
         {
             return new WithStatement
             return new WithStatement
                 {
                 {
                     Type = SyntaxNodes.WithStatement,
                     Type = SyntaxNodes.WithStatement,
-                    obj = obj,
-                    body = body
+                    Object = obj,
+                    Body = body
                 };
                 };
         }
         }
 
 
@@ -1764,12 +1764,12 @@ namespace Jint.Parser
 
 
         private void ThrowError(Token token, string messageFormat, params object[] arguments)
         private void ThrowError(Token token, string messageFormat, params object[] arguments)
         {
         {
-            Error error;
+            ParserError error;
             string msg = String.Format(messageFormat, arguments);
             string msg = String.Format(messageFormat, arguments);
 
 
             if (token.LineNumber.HasValue)
             if (token.LineNumber.HasValue)
             {
             {
-                error = new Error("Line " + token.LineNumber + ": " + msg)
+                error = new ParserError("Line " + token.LineNumber + ": " + msg)
                     {
                     {
                         Index = token.Range[0],
                         Index = token.Range[0],
                         LineNumber = token.LineNumber.Value,
                         LineNumber = token.LineNumber.Value,
@@ -1778,7 +1778,7 @@ namespace Jint.Parser
             }
             }
             else
             else
             {
             {
-                error = new Error("Line " + _lineNumber + ": " + msg)
+                error = new ParserError("Line " + _lineNumber + ": " + msg)
                     {
                     {
                         Index = _index,
                         Index = _index,
                         LineNumber = _lineNumber,
                         LineNumber = _lineNumber,
@@ -1800,7 +1800,7 @@ namespace Jint.Parser
             {
             {
                 if (_extra.Errors != null)
                 if (_extra.Errors != null)
                 {
                 {
-                    _extra.Errors.Add(new Error(e.Message));
+                    _extra.Errors.Add(new ParserError(e.Message));
                 }
                 }
                 else
                 else
                 {
                 {
@@ -3284,7 +3284,7 @@ namespace Jint.Parser
 
 
         private TryStatement ParseTryStatement()
         private TryStatement ParseTryStatement()
         {
         {
-            var handlers = new List<Statement>();
+            var handlers = new List<CatchClause>();
             Statement finalizer = null;
             Statement finalizer = null;
 
 
             ExpectKeyword("try");
             ExpectKeyword("try");
@@ -3820,7 +3820,7 @@ namespace Jint.Parser
 
 
                 if (options.Tolerant)
                 if (options.Tolerant)
                 {
                 {
-                    _extra.Errors = new List<Error>();
+                    _extra.Errors = new List<ParserError>();
                 }
                 }
             }
             }
 
 
@@ -3859,7 +3859,7 @@ namespace Jint.Parser
 
 
             public List<Comment> Comments;
             public List<Comment> Comments;
             public List<Token> Tokens;
             public List<Token> Tokens;
-            public List<Error> Errors;
+            public List<ParserError> Errors;
         }
         }
 
 
         private class LocationMarker
         private class LocationMarker

+ 2 - 2
Jint/Parser/ParserException.cs

@@ -2,14 +2,14 @@
 
 
 namespace Jint.Parser
 namespace Jint.Parser
 {
 {
-    public class Error : Exception
+    public class ParserError : Exception
     {
     {
         public int Column;
         public int Column;
         public string Description;
         public string Description;
         public int Index;
         public int Index;
         public int LineNumber;
         public int LineNumber;
 
 
-        public Error(string message) : base(message)
+        public ParserError(string message) : base(message)
         {
         {
         }
         }
     }
     }

+ 27 - 0
Jint/Runtime/Completion.cs

@@ -0,0 +1,27 @@
+namespace Jint.Runtime
+{
+    /// <summary>
+    /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.9
+    /// </summary>
+    public class Completion
+    {
+        public static string Normal = "normal";
+        public static string Break = "break";
+        public static string Continue = "continue";
+        public static string Return = "return";
+        public static string Throw = "throw";
+
+        public Completion(string type, object value, string identifier)
+        {
+            Type = type;
+            Value = value;
+            Identifier = identifier;
+        }
+
+
+        public string Type { get; private set; }
+        public object Value { get; private set; }
+        public string Identifier { get; private set; }
+
+    }
+}

+ 1 - 24
Jint/Runtime/Environments/ExecutionContext.cs

@@ -1,33 +1,10 @@
-using Jint.Native;
-using Jint.Parser.Ast;
-
-namespace Jint.Runtime.Environments
+namespace Jint.Runtime.Environments
 {
 {
     public sealed class ExecutionContext
     public sealed class ExecutionContext
     {
     {
-        public ExecutionContext()
-        {
-            Return = Undefined.Instance;
-        }
-
         public LexicalEnvironment LexicalEnvironment { get; set; }
         public LexicalEnvironment LexicalEnvironment { get; set; }
         public LexicalEnvironment VariableEnvironment { get; set; }
         public LexicalEnvironment VariableEnvironment { get; set; }
         public object ThisBinding { get; set; }
         public object ThisBinding { get; set; }
 
 
-        /// <summary>
-        /// Set when a break statement has been processed 
-        /// </summary>
-        public BreakStatement Break { get; set; }
-
-        /// <summary>
-        /// Set when a continue statement has been processed
-        /// </summary>
-        public ContinueStatement Continue { get; set; }
-
-        /// <summary>
-        /// Set when a return statement has been processed
-        /// </summary>
-        public object Return { get; set; }
-
     }
     }
 }
 }

+ 5 - 5
Jint/Runtime/ExpressionIntepreter.cs

@@ -223,7 +223,7 @@ namespace Jint.Runtime
             return value;
             return value;
         }
         }
 
 
-        private bool StriclyEqual(object x, object y)
+        public static bool StriclyEqual(object x, object y)
         {
         {
             var typea = TypeConverter.GetType(x);
             var typea = TypeConverter.GetType(x);
             var typeb = TypeConverter.GetType(y);
             var typeb = TypeConverter.GetType(y);
@@ -264,7 +264,7 @@ namespace Jint.Runtime
 
 
         public object EvaluateIdentifier(Identifier identifier)
         public object EvaluateIdentifier(Identifier identifier)
         {
         {
-            return _engine.CurrentExecutionContext.LexicalEnvironment.GetIdentifierReference(identifier.Name, _engine.Options.IsStrict());
+            return _engine.ExecutionContext.LexicalEnvironment.GetIdentifierReference(identifier.Name, _engine.Options.IsStrict());
         }
         }
 
 
         public object EvaluateLiteral(Literal literal)
         public object EvaluateLiteral(Literal literal)
@@ -319,7 +319,7 @@ namespace Jint.Runtime
                 functionExpression.Parameters.ToArray(), 
                 functionExpression.Parameters.ToArray(), 
                 _engine.Function.Prototype,
                 _engine.Function.Prototype,
                 _engine.Object.Construct(Arguments.Empty),
                 _engine.Object.Construct(Arguments.Empty),
-                LexicalEnvironment.NewDeclarativeEnvironment(_engine.CurrentExecutionContext.LexicalEnvironment)
+                LexicalEnvironment.NewDeclarativeEnvironment(_engine.ExecutionContext.LexicalEnvironment)
                 );
                 );
         }
         }
 
 
@@ -340,7 +340,7 @@ namespace Jint.Runtime
             {
             {
                 // assert(...)
                 // assert(...)
                 var callee = (FunctionInstance)_engine.GetValue(result);
                 var callee = (FunctionInstance)_engine.GetValue(result);
-                return callee.Call(_engine.CurrentExecutionContext.ThisBinding, arguments);
+                return callee.Call(_engine.ExecutionContext.ThisBinding, arguments);
             }
             }
 
 
         }
         }
@@ -381,7 +381,7 @@ namespace Jint.Runtime
 
 
         public object EvaluateThisExpression(ThisExpression thisExpression)
         public object EvaluateThisExpression(ThisExpression thisExpression)
         {
         {
-            return _engine.CurrentExecutionContext.ThisBinding;
+            return _engine.ExecutionContext.ThisBinding;
         }
         }
 
 
         public object EvaluateNewExpression(NewExpression newExpression)
         public object EvaluateNewExpression(NewExpression newExpression)

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

@@ -21,10 +21,8 @@ namespace Jint.Runtime.Interop
 
 
         public override object Call(object thisObject, object[] arguments)
         public override object Call(object thisObject, object[] arguments)
         {
         {
-            // initialize Return flag
-            _engine.CurrentExecutionContext.Return = Undefined.Instance;
-
-            return _func((TObject) thisObject, arguments);
+            var result = _func((TObject) thisObject, arguments);
+            return new Completion(Completion.Normal, result, null);
         }
         }
     }
     }
 }
 }

+ 2 - 6
Jint/Runtime/Interop/DelegateWrapper.cs

@@ -21,12 +21,8 @@ namespace Jint.Runtime.Interop
 
 
         public override object Call(object thisObject, object[] arguments)
         public override object Call(object thisObject, object[] arguments)
         {
         {
-            // initialize Return flag
-            _engine.CurrentExecutionContext.Return = Undefined.Instance;
-
-            _d.DynamicInvoke(arguments);
-
-            return _engine.CurrentExecutionContext.Return;
+            var result = _d.DynamicInvoke(arguments);
+            return new Completion(Completion.Normal, result, null);
         }
         }
     }
     }
 }
 }

+ 417 - 104
Jint/Runtime/StatementInterpreter.cs

@@ -1,8 +1,11 @@
-using System.Linq;
+using System.Collections.Generic;
+using System.Linq;
 using Jint.Native;
 using Jint.Native;
+using Jint.Native.Errors;
 using Jint.Native.Function;
 using Jint.Native.Function;
 using Jint.Parser.Ast;
 using Jint.Parser.Ast;
 using Jint.Runtime.Environments;
 using Jint.Runtime.Environments;
+using Jint.Runtime.References;
 
 
 namespace Jint.Runtime
 namespace Jint.Runtime
 {
 {
@@ -15,190 +18,500 @@ namespace Jint.Runtime
             _engine = engine;
             _engine = engine;
         }
         }
 
 
-        private object ExecuteStatement(Statement statement)
+        private Completion ExecuteStatement(Statement statement)
         {
         {
             return _engine.ExecuteStatement(statement);
             return _engine.ExecuteStatement(statement);
         }
         }
 
 
-        public object ExecuteProgram(Program program)
+        public Completion ExecuteEmptyStatement(EmptyStatement emptyStatement)
         {
         {
-            object result = null;
+            return new Completion(Completion.Normal, null, null);
+        }
+
+        public Completion ExecuteExpressionStatement(ExpressionStatement expressionStatement)
+        {
+            var exprRef = _engine.EvaluateExpression(expressionStatement.Expression);
+            return new Completion(Completion.Normal, _engine.GetValue(exprRef), null);
+        }
+
+        public Completion ExecuteIfStatement(IfStatement ifStatement)
+        {
+            var exprRef = _engine.EvaluateExpression(ifStatement.Test);
+            Completion result;
 
 
-            foreach (var statement in program.Body)
+            if (TypeConverter.ToBoolean(_engine.GetValue(exprRef)))
+            {
+                result = ExecuteStatement(ifStatement.Consequent);
+            }
+            else if (ifStatement.Alternate != null)
+            {
+                result = ExecuteStatement(ifStatement.Alternate);
+            }
+            else
             {
             {
-                result = ExecuteStatement(statement);
+                return new Completion(Completion.Normal, null, null);
             }
             }
 
 
             return result;
             return result;
         }
         }
 
 
-        public object ExecuteVariableDeclaration(VariableDeclaration statement)
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.1
+        /// </summary>
+        /// <param name="doWhileStatement"></param>
+        /// <returns></returns>
+        public Completion ExecuteDoWhileStatement(DoWhileStatement doWhileStatement)
         {
         {
-            object result = null;
-            var env = _engine.CurrentExecutionContext.VariableEnvironment.Record;
+            object v = null;
+            bool iterating;
 
 
-            foreach (var declaration in statement.Declarations)
+            do
             {
             {
-                object value = Undefined.Instance;
-
-                if (declaration.Init != null)
+                var stmt = ExecuteStatement(doWhileStatement.Body);
+                if (stmt.Value != null)
                 {
                 {
-                    result = value = _engine.GetValue(_engine.EvaluateExpression(declaration.Init));
+                    v = stmt.Value;
                 }
                 }
-
-                var dn = declaration.Id.Name;
-                var varAlreadyDeclared = env.HasBinding(dn);
-                if (!varAlreadyDeclared)
+                if (stmt.Type != Completion.Continue /* todo: || stmt.Target*/)
                 {
                 {
-                    env.CreateMutableBinding(declaration.Id.Name, true);
+                    if (stmt.Type == Completion.Break /* todo: complete */)
+                    {
+                        return new Completion(Completion.Normal, v, null);
+                    }
+
+                    if (stmt.Type != Completion.Normal)
+                    {
+                        return stmt;
+                    }
                 }
                 }
-                env.SetMutableBinding(declaration.Id.Name, value, false);
-            }
+                var exprRef = _engine.EvaluateExpression(doWhileStatement.Test);
+                iterating = TypeConverter.ToBoolean(_engine.GetValue(exprRef));
 
 
-            return result;
+            } while (iterating);
+
+            return new Completion(Completion.Normal, v, null);
         }
         }
 
 
-        public object ExecuteDoWhileStatement(DoWhileStatement doWhileStatement)
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.2
+        /// </summary>
+        /// <param name="whileStatement"></param>
+        /// <returns></returns>
+        public Completion ExecuteWhileStatement(WhileStatement whileStatement)
         {
         {
-            object result = null;
-
-            bool test;
-            do
+            object v = null; 
+            while (true)
             {
             {
-                result = ExecuteStatement(doWhileStatement.Body);
-                test = TypeConverter.ToBoolean(_engine.EvaluateExpression(doWhileStatement.Test));
-            } while (test);
+                var exprRef = _engine.EvaluateExpression(whileStatement.Test);
 
 
-            return result;
-        }
+                if (!TypeConverter.ToBoolean(_engine.GetValue(exprRef)))
+                {
+                    return new Completion(Completion.Normal, v, null);
+                }
 
 
-        public object ExecuteContinueStatement(ContinueStatement continueStatement)
-        {
-            _engine.CurrentExecutionContext.Continue = continueStatement;
-            return null;
+                var stmt = ExecuteStatement(whileStatement.Body);
+
+                if (stmt.Value != null)
+                {
+                    v = stmt.Value;
+                }
+
+                if (stmt.Type != Completion.Continue /* todo: complete */)
+                {
+                    if (stmt.Type == Completion.Break /* todo: complete */)
+                    {
+                        return new Completion(Completion.Normal, v, null);
+                    }
+
+                    if (stmt.Type != Completion.Normal)
+                    {
+                        return stmt;
+                    }
+                }
+            }
         }
         }
 
 
-        public object ExecuteBreakStatement(BreakStatement breakStatement)
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.3
+        /// </summary>
+        /// <param name="forStatement"></param>
+        /// <returns></returns>
+        public Completion ExecuteForStatement(ForStatement forStatement)
         {
         {
-            _engine.CurrentExecutionContext.Break = breakStatement;
-            return null;
+            
+            if (forStatement.Init != null)
+            {
+                if (forStatement.Init.Type == SyntaxNodes.VariableDeclaration)
+                {
+                    ExecuteStatement(forStatement.Init.As<Statement>());
+                }
+                else
+                {
+                    _engine.GetValue(_engine.EvaluateExpression(forStatement.Init.As<Expression>()));
+                }
+            }
+
+            object v = null;
+            while (true)
+            {
+                if (forStatement.Test != null)
+                {
+                    var testExprRef = _engine.EvaluateExpression(forStatement.Test);
+                    if (!TypeConverter.ToBoolean(_engine.GetValue(testExprRef)))
+                    {
+                        return new Completion(Completion.Normal, v, null);
+                    }
+                }
+
+                var stmt = ExecuteStatement(forStatement.Body);
+                if (stmt.Value != null)
+                {
+                    v = stmt.Value;
+                }
+                if (stmt.Type == Completion.Break /* todo: complete */)
+                {
+                    return new Completion(Completion.Normal, v, null);
+                }
+                if (stmt.Type != Completion.Continue /* todo: complete */)
+                {
+                    if (stmt.Type != Completion.Normal)
+                    {
+                        return stmt;
+                    }
+                }
+                if (forStatement.Update != null)
+                {
+                    var incExprRef = _engine.EvaluateExpression(forStatement.Update);
+                    _engine.GetValue(incExprRef);
+                }
+            }
         }
         }
 
 
-        public object ExecuteBlockStatement(BlockStatement blockStatement)
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.4
+        /// </summary>
+        /// <param name="forInStatement"></param>
+        /// <returns></returns>
+        public Completion ForInStatement(ForInStatement forInStatement)
         {
         {
-            object result = null;
-            foreach (var statement in blockStatement.Body)
+            object varName = null;
+            if (forInStatement.Left.Type == SyntaxNodes.VariableDeclaration)
             {
             {
-                result = ExecuteStatement(statement);
+                varName = ExecuteStatement(forInStatement.Left.As<Statement>()).Value;
+            }
+            
+            var exprRef = _engine.EvaluateExpression(forInStatement.Right);
+            var experValue = _engine.GetValue(exprRef);
+            if (experValue == Undefined.Instance || experValue == Null.Instance)
+            {
+                return new Completion(Completion.Normal, null, null);
+            }
+            var obj = TypeConverter.ToObject(_engine, experValue);
+            object v = null;
+            foreach (var entry in obj.Properties)
+            {
+                if (!entry.Value.Enumerable)
+                {
+                    continue;
+                }
 
 
-                // return has been called, stop execution
-                if (!_engine.CurrentExecutionContext.Return.Equals(Undefined.Instance))
+                var p = entry.Key;
+
+                if (varName != null)
+                {
+                    var varRef = varName as Reference;
+                    _engine.SetValue(varRef, p);
+                }
+                else
+                {
+                    var lhsRef = _engine.EvaluateExpression(forInStatement.Left.As<Expression>()) as Reference;
+                    _engine.SetValue(lhsRef, p);
+                }
+                var stmt = ExecuteStatement(forInStatement.Body);
+                if (stmt.Value != null)
                 {
                 {
-                    return result;
+                    v = stmt.Value;
                 }
                 }
+                if (stmt.Type == Completion.Break /* todo: complete */)
+                {
+                    return new Completion(Completion.Normal, v, null);
+                }
+                if (stmt.Type != Completion.Continue /* todo: complete */)
+                {
+                    if (stmt.Type != Completion.Normal)
+                    {
+                        return stmt;
+                    }
+                }
+
             }
             }
 
 
-            return result;
+            return new Completion(Completion.Normal, v, null);
         }
         }
 
 
-        public object ExecuteEmptyStatement(EmptyStatement emptyStatement)
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.7
+        /// </summary>
+        /// <param name="continueStatement"></param>
+        /// <returns></returns>
+        public Completion ExecuteContinueStatement(ContinueStatement continueStatement)
         {
         {
-            return null;
+            return new Completion(Completion.Continue, null, continueStatement.Label != null ? continueStatement.Label.Name : null);
         }
         }
 
 
-        public object ExecuteExpressionStatement(ExpressionStatement expressionStatement)
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.8
+        /// </summary>
+        /// <param name="breakStatement"></param>
+        /// <returns></returns>
+        public Completion ExecuteBreakStatement(BreakStatement breakStatement)
         {
         {
-            return _engine.EvaluateExpression(expressionStatement.Expression);
+            return new Completion(Completion.Break, null, breakStatement.Label != null ? breakStatement.Label.Name : null);
         }
         }
 
 
-        public object ExecuteReturnStatement(ReturnStatement statement)
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.9
+        /// </summary>
+        /// <param name="statement"></param>
+        /// <returns></returns>
+        public Completion ExecuteReturnStatement(ReturnStatement statement)
         {
         {
-            return _engine.CurrentExecutionContext.Return = _engine.EvaluateExpression(statement.Argument);
+            if (statement.Argument == null)
+            {
+                return new Completion(Completion.Return, Undefined.Instance, null);
+            }
+            
+            var exprRef = _engine.EvaluateExpression(statement.Argument);    
+            return new Completion(Completion.Return, _engine.GetValue(exprRef), null);
         }
         }
 
 
-        public object ExecuteFunctionDeclaration(FunctionDeclaration functionDeclaration)
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.10
+        /// </summary>
+        /// <param name="withStatement"></param>
+        /// <returns></returns>
+        public Completion ExecuteWithStatement(WithStatement withStatement)
         {
         {
-            object result = null;
+            var val = _engine.EvaluateExpression(withStatement.Object);
+            var obj = TypeConverter.ToObject(_engine, _engine.GetValue(val));
+            var oldEnv = _engine.ExecutionContext.LexicalEnvironment;
+            var newEnv = LexicalEnvironment.NewObjectEnvironment(obj, oldEnv);
+            // todo: handle ProvideThis
+            // newEnv.ProvideThis = true;
+            _engine.ExecutionContext.LexicalEnvironment = newEnv;
+
+            Completion c;
+            try
+            {
+                c = ExecuteStatement(withStatement.Body);
+            }
+            catch (Error v)
+            {
+                c = new Completion(Completion.Throw, v, null);
+            }
+            finally
+            {
+                _engine.ExecutionContext.LexicalEnvironment = oldEnv;
+            }
 
 
-            // create function objects
-            // http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
+            return c;
+        }
 
 
-            var identifier = functionDeclaration.Id.Name;
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.11
+        /// </summary>
+        /// <param name="switchStatement"></param>
+        /// <returns></returns>
+        public Completion ExecuteSwitchStatement(SwitchStatement switchStatement)
+        {
+            var exprRef = _engine.EvaluateExpression(switchStatement.Discriminant);
+            var r = ExecuteSwitchBlock(switchStatement.Cases, _engine.GetValue(exprRef));
+            if (r.Type == Completion.Break /* too: complete */)
+            {
+                return new Completion(Completion.Normal, r.Value, null);
+            }
+            return r;
+        }
 
 
-            // todo: should be declared in the current context
-            _engine.Global.Set(
-                identifier, 
-                result = new ScriptFunctionInstance(
-                    _engine,
-                    functionDeclaration.Body, 
-                    identifier, 
-                    functionDeclaration.Parameters.ToArray(),
-                    _engine.Function.Prototype,
-                    _engine.Object.Construct(Arguments.Empty),
-                    LexicalEnvironment.NewDeclarativeEnvironment(_engine.CurrentExecutionContext.LexicalEnvironment)
-                )
-            );
+        public Completion ExecuteSwitchBlock(IEnumerable<SwitchCase> switchBlock, object input)
+        {
+            object v = null;
+            SwitchCase defaultCase = null;
+            foreach (var clause in switchBlock)
+            {
+                if (clause.Test == null)
+                {
+                    defaultCase = clause;
+                }
+                else
+                {
+                    var clauseSelector = _engine.GetValue(_engine.EvaluateExpression(clause.Test));
+                    if (ExpressionInterpreter.StriclyEqual(clauseSelector, input))
+                    {
+                        if (clause.Consequent != null)
+                        {
+                            var r = ExecuteStatementList(clause.Consequent);
+                            if (r.Type != Completion.Normal)
+                            {
+                                return r;
+                            }
+                            v = r.Value;
+                        }
+                    }
+                }
+            }
 
 
-            return result;
+            if (defaultCase != null)
+            {
+                var r = ExecuteStatementList(defaultCase.Consequent);
+                if (r.Type != Completion.Normal)
+                {
+                    return r;
+                }
+                v = r.Value;
+            }
+
+            return new Completion(Completion.Normal, v, null);
         }
         }
 
 
-        public object ExecuteIfStatement(IfStatement ifStatement)
+        public Completion ExecuteStatementList(IEnumerable<Statement> statementList)
         {
         {
-            object result = null;
-            var test = TypeConverter.ToBoolean(_engine.EvaluateExpression(ifStatement.Test));
-
-            if (test)
+            var c = new Completion(Completion.Normal, null, null);
+            
+            try
             {
             {
-                result = _engine.ExecuteStatement(ifStatement.Consequent);
+                foreach (var statement in statementList)
+                {
+                    c = ExecuteStatement(statement);
+                    if (c.Type != Completion.Normal)
+                    {
+                        return c;
+                    }
+                }
             }
             }
-            else if (ifStatement.Alternate != null)
+            catch(Error v)
             {
             {
-                result = _engine.ExecuteStatement(ifStatement.Alternate);
+                return new Completion(Completion.Throw, v, null);
             }
             }
 
 
-            return result;
+            return c;
         }
         }
 
 
-        public object ExecuteWhileStatement(WhileStatement whileStatement)
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.13
+        /// </summary>
+        /// <param name="throwStatement"></param>
+        /// <returns></returns>
+        public Completion ExecuteThrowStatement(ThrowStatement throwStatement)
         {
         {
-            object result = null;
+            var exprRef = _engine.EvaluateExpression(throwStatement.Argument);
+            return new Completion(Completion.Throw, _engine.GetValue(exprRef), null);
+        }
 
 
-            bool test = TypeConverter.ToBoolean(_engine.EvaluateExpression(whileStatement.Test));
+        /// <summary>
+        /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.14
+        /// </summary>
+        /// <param name="tryStatement"></param>
+        /// <returns></returns>
+        public Completion ExecuteTryStatement(TryStatement tryStatement)
+        {
+            var b = ExecuteStatement(tryStatement.Block);
+            if (b.Type == Completion.Throw)
+            {
+                // execute catch
+                if (tryStatement.Handlers.Any())
+                {
+                    foreach (var catchClaude in tryStatement.Handlers)
+                    {
+                        var c = b;
+                        var oldEnv = _engine.ExecutionContext.LexicalEnvironment;
+                        var catchEnv = LexicalEnvironment.NewDeclarativeEnvironment(oldEnv);
+                        catchEnv.Record.CreateMutableBinding(catchClaude.Param.Name);
+                        catchEnv.Record.SetMutableBinding(catchClaude.Param.Name, c, false);
+                        _engine.ExecutionContext.LexicalEnvironment = catchEnv;
+                        b = ExecuteStatement(catchClaude.Body);
+                        _engine.ExecutionContext.LexicalEnvironment = oldEnv;
+                    }
+                }
+            }
 
 
-            while(test)
+            if (tryStatement.Finalizer != null)
             {
             {
-                result = ExecuteStatement(whileStatement.Body);
-                test = TypeConverter.ToBoolean(_engine.EvaluateExpression(whileStatement.Test));
+                var f = ExecuteStatement(tryStatement.Finalizer);
+                if (f.Type == Completion.Normal)
+                {
+                    return b;
+                }
+            
+                return f;
             }
             }
 
 
-            return result;
+            return b;
         }
         }
 
 
-        public object ExecuteDebuggerStatement(DebuggerStatement debuggerStatement)
+        public Completion ExecuteProgram(Program program)
         {
         {
-            throw new System.NotImplementedException();
+            return ExecuteStatementList(program.Body);
         }
         }
 
 
-        public object ExecuteForStatement(ForStatement forStatement)
+        public Completion ExecuteVariableDeclaration(VariableDeclaration statement)
         {
         {
-            object result = null;
+            var env = _engine.ExecutionContext.VariableEnvironment.Record;
+            object value = Undefined.Instance;
 
 
-            if (forStatement.Init.Type == SyntaxNodes.VariableDeclaration)
-            {
-                result = _engine.ExecuteStatement(forStatement.Init.As<Statement>());
-            }
-            else
+            foreach (var declaration in statement.Declarations)
             {
             {
-                result = _engine.EvaluateExpression(forStatement.Init.As<Expression>());
-            }
 
 
-            while (TypeConverter.ToBoolean(_engine.EvaluateExpression(forStatement.Test)))
-            {
-                _engine.ExecuteStatement(forStatement.Body);
-                _engine.EvaluateExpression(forStatement.Update);
+                if (declaration.Init != null)
+                {
+                    value = _engine.GetValue(_engine.EvaluateExpression(declaration.Init));
+                }
+
+                var dn = declaration.Id.Name;
+                var varAlreadyDeclared = env.HasBinding(dn);
+                if (!varAlreadyDeclared)
+                {
+                    env.CreateMutableBinding(declaration.Id.Name, true);
+                }
+                env.SetMutableBinding(declaration.Id.Name, value, false);
             }
             }
 
 
-            return result;
+            return new Completion(Completion.Normal, value, null);
+        }
+
+        public Completion ExecuteBlockStatement(BlockStatement blockStatement)
+        {
+            return ExecuteStatementList(blockStatement.Body);
+        }
+
+        public Completion ExecuteFunctionDeclaration(FunctionDeclaration functionDeclaration)
+        {
+            // create function objects
+            // http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
+
+            var identifier = functionDeclaration.Id.Name;
+
+            // todo: should be declared in the current context
+            _engine.Global.Set(
+                identifier, 
+                new ScriptFunctionInstance(
+                    _engine,
+                    functionDeclaration.Body, 
+                    identifier, 
+                    functionDeclaration.Parameters.ToArray(),
+                    _engine.Function.Prototype,
+                    _engine.Object.Construct(Arguments.Empty),
+                    LexicalEnvironment.NewDeclarativeEnvironment(_engine.ExecutionContext.LexicalEnvironment)
+                )
+            );
+
+            return new Completion(Completion.Normal, null, null);
         }
         }
+
+        public Completion ExecuteDebuggerStatement(DebuggerStatement debuggerStatement)
+        {
+            throw new System.NotImplementedException();
+        }
+
     }
     }
 }
 }

+ 4 - 2
Jint/Runtime/TypeConverter.cs

@@ -278,9 +278,11 @@ namespace Jint.Runtime
             {
             {
                 return engine.Number.Construct((double) value);
                 return engine.Number.Construct((double) value);
             }
             }
-            if (value is string)
+
+            var s = value as string;
+            if (s != null)
             {
             {
-                return engine.String.Construct((string) value);
+                return engine.String.Construct(s);
             }
             }
 
 
             throw new TypeError();
             throw new TypeError();