/// <summary>
        /// http://www.ecma-international.org/ecma-262/5.1/#sec-12.6.4
        /// </summary>
        /// <param name="forInStatement"></param>
        /// <returns></returns>
        public Completion ExecuteForInStatement(ForInStatement forInStatement)
        {
            Identifier identifier = forInStatement.Left.Type == SyntaxNodes.VariableDeclaration
                                        ? forInStatement.Left.As <VariableDeclaration>().Declarations.First().Id
                                        : forInStatement.Left.As <Identifier>();

            var varRef     = _engine.EvaluateExpression(identifier) as Reference;
            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);
            JsValue v   = Null.Instance;

            // keys are constructed using the prototype chain
            var cursor        = obj;
            var processedKeys = new HashSet <string>();

            while (cursor != null)
            {
                var keys = _engine.Object.GetOwnPropertyNames(Undefined.Instance, Arguments.From(cursor)).AsArray();

                for (var i = 0; i < keys.GetLength(); i++)
                {
                    var p = keys.GetOwnProperty(i.ToString()).Value.AsString();

                    if (processedKeys.Contains(p))
                    {
                        continue;
                    }

                    processedKeys.Add(p);

                    // collection might be modified by inner statement
                    if (cursor.GetOwnProperty(p) == PropertyDescriptor.Undefined)
                    {
                        continue;
                    }


                    var value = cursor.GetOwnProperty(p);
                    if (!value.Enumerable.HasValue || !value.Enumerable.Value)
                    {
                        continue;
                    }

                    _engine.PutValue(varRef, p);

                    var stmt = ExecuteStatement(forInStatement.Body);
                    if (stmt.Value != null)
                    {
                        v = stmt.Value;
                    }
                    if (stmt.Type == Completion.Break)
                    {
                        return(new Completion(Completion.Normal, v, null));
                    }
                    if (stmt.Type != Completion.Continue)
                    {
                        if (stmt.Type != Completion.Normal)
                        {
                            return(stmt);
                        }
                    }
                }

                cursor = cursor.Prototype;
            }

            return(new Completion(Completion.Normal, v, null));
        }