public JsValue EvaluateBinaryExpression(BinaryExpression expression) { var leftExpression = EvaluateExpression(expression.Left); JsValue left = _engine.GetValue(leftExpression); var rightExpression = EvaluateExpression(expression.Right); JsValue right = _engine.GetValue(rightExpression); JsValue value; switch (expression.Operator) { case BinaryOperator.Plus: var lprim = TypeConverter.ToPrimitive(left); var rprim = TypeConverter.ToPrimitive(right); if (lprim.IsString() || rprim.IsString()) { value = TypeConverter.ToString(lprim) + TypeConverter.ToString(rprim); } else { value = TypeConverter.ToNumber(lprim) + TypeConverter.ToNumber(rprim); } break; case BinaryOperator.Minus: value = TypeConverter.ToNumber(left) - TypeConverter.ToNumber(right); break; case BinaryOperator.Times: if (left == Undefined.Instance || right == Undefined.Instance) { value = Undefined.Instance; } else { value = TypeConverter.ToNumber(left) * TypeConverter.ToNumber(right); } break; case BinaryOperator.Divide: value = Divide(left, right); break; case BinaryOperator.Modulo: if (left == Undefined.Instance || right == Undefined.Instance) { value = Undefined.Instance; } else { value = TypeConverter.ToNumber(left) % TypeConverter.ToNumber(right); } break; case BinaryOperator.Equal: value = Equal(left, right); break; case BinaryOperator.NotEqual: value = !Equal(left, right); break; case BinaryOperator.Greater: value = Compare(right, left, false); if (value == Undefined.Instance) { value = false; } break; case BinaryOperator.GreaterOrEqual: value = Compare(left, right); if (value == Undefined.Instance || value.AsBoolean()) { value = false; } else { value = true; } break; case BinaryOperator.Less: value = Compare(left, right); if (value == Undefined.Instance) { value = false; } break; case BinaryOperator.LessOrEqual: value = Compare(right, left, false); if (value == Undefined.Instance || value.AsBoolean()) { value = false; } else { value = true; } break; case BinaryOperator.StrictlyEqual: return(StrictlyEqual(left, right)); case BinaryOperator.StricltyNotEqual: return(!StrictlyEqual(left, right)); case BinaryOperator.BitwiseAnd: return(TypeConverter.ToInt32(left) & TypeConverter.ToInt32(right)); case BinaryOperator.BitwiseOr: return(TypeConverter.ToInt32(left) | TypeConverter.ToInt32(right)); case BinaryOperator.BitwiseXOr: return(TypeConverter.ToInt32(left) ^ TypeConverter.ToInt32(right)); case BinaryOperator.LeftShift: return(TypeConverter.ToInt32(left) << (int)(TypeConverter.ToUint32(right) & 0x1F)); case BinaryOperator.RightShift: return(TypeConverter.ToInt32(left) >> (int)(TypeConverter.ToUint32(right) & 0x1F)); case BinaryOperator.UnsignedRightShift: return((uint)TypeConverter.ToInt32(left) >> (int)(TypeConverter.ToUint32(right) & 0x1F)); case BinaryOperator.InstanceOf: var f = right.TryCast <FunctionInstance>(); if (f == null) { throw new JavaScriptException(_engine.TypeError, "instanceof can only be used with a function object"); } value = f.HasInstance(left); break; case BinaryOperator.In: if (!right.IsObject()) { throw new JavaScriptException(_engine.TypeError, "in can only be used with an object"); } value = right.AsObject().HasProperty(TypeConverter.ToString(left)); break; default: throw new NotImplementedException(); } return(value); }
public JsValue EvaluateAssignmentExpression(AssignmentExpression assignmentExpression) { var lref = EvaluateExpression(assignmentExpression.Left) as Reference; JsValue rval = _engine.GetValue(EvaluateExpression(assignmentExpression.Right)); if (lref == null) { throw new JavaScriptException(_engine.ReferenceError); } if (assignmentExpression.Operator == AssignmentOperator.Assign) // "=" { if (lref.IsStrict() && lref.GetBase().TryCast <EnvironmentRecord>() != null && (lref.GetReferencedName() == "eval" || lref.GetReferencedName() == "arguments")) { throw new JavaScriptException(_engine.SyntaxError); } _engine.PutValue(lref, rval); return(rval); } JsValue lval = _engine.GetValue(lref); switch (assignmentExpression.Operator) { case AssignmentOperator.PlusAssign: var lprim = TypeConverter.ToPrimitive(lval); var rprim = TypeConverter.ToPrimitive(rval); if (lprim.IsString() || rprim.IsString()) { lval = TypeConverter.ToString(lprim) + TypeConverter.ToString(rprim); } else { lval = TypeConverter.ToNumber(lprim) + TypeConverter.ToNumber(rprim); } break; case AssignmentOperator.MinusAssign: lval = TypeConverter.ToNumber(lval) - TypeConverter.ToNumber(rval); break; case AssignmentOperator.TimesAssign: if (lval == Undefined.Instance || rval == Undefined.Instance) { lval = Undefined.Instance; } else { lval = TypeConverter.ToNumber(lval) * TypeConverter.ToNumber(rval); } break; case AssignmentOperator.DivideAssign: lval = Divide(lval, rval); break; case AssignmentOperator.ModuloAssign: if (lval == Undefined.Instance || rval == Undefined.Instance) { lval = Undefined.Instance; } else { lval = TypeConverter.ToNumber(lval) % TypeConverter.ToNumber(rval); } break; case AssignmentOperator.BitwiseAndAssign: lval = TypeConverter.ToInt32(lval) & TypeConverter.ToInt32(rval); break; case AssignmentOperator.BitwiseOrAssign: lval = TypeConverter.ToInt32(lval) | TypeConverter.ToInt32(rval); break; case AssignmentOperator.BitwiseXOrAssign: lval = TypeConverter.ToInt32(lval) ^ TypeConverter.ToInt32(rval); break; case AssignmentOperator.LeftShiftAssign: lval = TypeConverter.ToInt32(lval) << (int)(TypeConverter.ToUint32(rval) & 0x1F); break; case AssignmentOperator.RightShiftAssign: lval = TypeConverter.ToInt32(lval) >> (int)(TypeConverter.ToUint32(rval) & 0x1F); break; case AssignmentOperator.UnsignedRightShiftAssign: lval = (uint)TypeConverter.ToInt32(lval) >> (int)(TypeConverter.ToUint32(rval) & 0x1F); break; default: throw new NotImplementedException(); } _engine.PutValue(lref, lval); return(lval); }
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(); } }