/// <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 = cursor.GetOwnProperties().Select(x => x.Key).ToArray(); foreach (var p in keys) { if (processedKeys.Contains(p)) { continue; } processedKeys.Add(p); // collection might be modified by inner statement if (!cursor.HasOwnProperty(p)) { 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); }
private void EmitForInStatement(ForInStatement s) { if (s.Each) { throw new NotImplementedException(); } else { Write("for ("); if (s.Left is VariableDeclaration) { var decl = s.Left as VariableDeclaration; Emit(decl.Declarations.First()); } else { Emit(s.Left); } Write(" in "); Emit(s.Right); Write(") "); } Emit(s.Body); }