public JsValue EvaluateUnaryExpression(UnaryExpression unaryExpression) { var value = _engine.EvaluateExpression(unaryExpression.Argument); Reference r; switch (unaryExpression.Operator) { case UnaryOperator.Plus: return(TypeConverter.ToNumber(_engine.GetValue(value))); case UnaryOperator.Minus: var n = TypeConverter.ToNumber(_engine.GetValue(value)); return(double.IsNaN(n) ? double.NaN : n *-1); case UnaryOperator.BitwiseNot: return(~TypeConverter.ToInt32(_engine.GetValue(value))); case UnaryOperator.LogicalNot: return(!TypeConverter.ToBoolean(_engine.GetValue(value))); case UnaryOperator.Delete: r = value as Reference; if (r == null) { return(true); } if (r.IsUnresolvableReference()) { if (r.IsStrict()) { throw new JavaScriptException(_engine.SyntaxError); } return(true); } if (r.IsPropertyReference()) { var o = TypeConverter.ToObject(_engine, r.GetBase()); return(o.Delete(r.GetReferencedName(), r.IsStrict())); } if (r.IsStrict()) { throw new JavaScriptException(_engine.SyntaxError); } var bindings = r.GetBase().TryCast <EnvironmentRecord>(); return(bindings.DeleteBinding(r.GetReferencedName())); case UnaryOperator.Void: _engine.GetValue(value); return(Undefined.Instance); case UnaryOperator.TypeOf: r = value as Reference; if (r != null) { if (r.IsUnresolvableReference()) { return("undefined"); } } var v = _engine.GetValue(value); if (v == Undefined.Instance) { return("undefined"); } if (v == Null.Instance) { return("object"); } switch (v.Type) { case Types.Boolean: return("boolean"); case Types.Number: return("number"); case Types.String: return("string"); } if (v.TryCast <ICallable>() != null) { return("function"); } return("object"); default: throw new ArgumentException(); } }
/// <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)); }