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 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 EvaluateBinaryExpression(BinaryExpression expression) { JsValue left = _engine.GetValue(EvaluateExpression(expression.Left)); JsValue right = _engine.GetValue(EvaluateExpression(expression.Right)); JsValue value; switch (expression.Operator) { case "+": 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 "-": value = TypeConverter.ToNumber(left) - TypeConverter.ToNumber(right); break; case "*": if (left == Undefined.Instance || right == Undefined.Instance) { value = Undefined.Instance; } else { value = TypeConverter.ToNumber(left) * TypeConverter.ToNumber(right); } break; case "/": value = Divide(left, right); break; case "%": if (left == Undefined.Instance || right == Undefined.Instance) { value = Undefined.Instance; } else { value = TypeConverter.ToNumber(left) % TypeConverter.ToNumber(right); } break; case "==": value = Equal(left, right); break; case "!=": value = !Equal(left, right); break; case ">": value = Compare(right, left, false); if (value == Undefined.Instance) { value = false; } break; case ">=": value = Compare(left, right); if (value == Undefined.Instance || value.AsBoolean()) { value = false; } else { value = true; } break; case "<": value = Compare(left, right); if (value == Undefined.Instance) { value = false; } break; case "<=": value = Compare(right, left, false); if (value == Undefined.Instance || value.AsBoolean()) { value = false; } else { value = true; } break; case "===": return(StrictlyEqual(left, right)); case "!==": return(!StrictlyEqual(left, right)); case "&": return(TypeConverter.ToInt32(left) & TypeConverter.ToInt32(right)); case "|": return(TypeConverter.ToInt32(left) | TypeConverter.ToInt32(right)); case "^": return(TypeConverter.ToInt32(left) ^ TypeConverter.ToInt32(right)); case "<<": return(TypeConverter.ToInt32(left) << (int)(TypeConverter.ToUint32(right) & 0x1F)); case ">>": return(TypeConverter.ToInt32(left) >> (int)(TypeConverter.ToUint32(right) & 0x1F)); case ">>>": return((uint)TypeConverter.ToInt32(left) >> (int)(TypeConverter.ToUint32(right) & 0x1F)); case "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 "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) { JsValue rval = _engine.GetValue(EvaluateExpression(assignmentExpression.Right)); var lref = EvaluateExpression(assignmentExpression.Left) as Reference; if (lref == null) { throw new JavaScriptException(_engine.ReferenceError); } if (assignmentExpression.Operator == "=") { 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 "+=": 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 "-=": lval = TypeConverter.ToNumber(lval) - TypeConverter.ToNumber(rval); break; case "*=": if (lval == Undefined.Instance || rval == Undefined.Instance) { lval = Undefined.Instance; } else { lval = TypeConverter.ToNumber(lval) * TypeConverter.ToNumber(rval); } break; case "/=": lval = Divide(lval, rval); break; case "%=": if (lval == Undefined.Instance || rval == Undefined.Instance) { lval = Undefined.Instance; } else { lval = TypeConverter.ToNumber(lval) % TypeConverter.ToNumber(rval); } break; case "&=": lval = TypeConverter.ToInt32(lval) & TypeConverter.ToInt32(rval); break; case "|=": lval = TypeConverter.ToInt32(lval) | TypeConverter.ToInt32(rval); break; case "^=": lval = TypeConverter.ToInt32(lval) ^ TypeConverter.ToInt32(rval); break; case "<<=": lval = TypeConverter.ToInt32(lval) << (int)(TypeConverter.ToUint32(rval) & 0x1F); break; case ">>=": lval = TypeConverter.ToInt32(lval) >> (int)(TypeConverter.ToUint32(rval) & 0x1F); break; case ">>>=": lval = (uint)TypeConverter.ToInt32(lval) >> (int)(TypeConverter.ToUint32(rval) & 0x1F); break; default: throw new NotImplementedException(); } _engine.PutValue(lref, lval); return(lval); }
public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError) { var oldLenDesc = _length; var oldLen = (uint)TypeConverter.ToNumber(oldLenDesc.Value); uint index; if (propertyName.Length == 6 && propertyName == "length") { var value = desc.Value; if (ReferenceEquals(value, null)) { return(base.DefineOwnProperty("length", desc, throwOnError)); } var newLenDesc = new PropertyDescriptor(desc); uint newLen = TypeConverter.ToUint32(value); if (newLen != TypeConverter.ToNumber(value)) { ExceptionHelper.ThrowRangeError(_engine); } newLenDesc.Value = newLen; if (newLen >= oldLen) { return(base.DefineOwnProperty("length", newLenDesc, throwOnError)); } if (!oldLenDesc.Writable) { if (throwOnError) { ExceptionHelper.ThrowTypeError(_engine); } return(false); } bool newWritable; if (!newLenDesc.WritableSet || newLenDesc.Writable) { newWritable = true; } else { newWritable = false; newLenDesc.Writable = true; } var succeeded = base.DefineOwnProperty("length", newLenDesc, throwOnError); if (!succeeded) { return(false); } var count = _dense?.Length ?? _sparse.Count; if (count < oldLen - newLen) { if (_dense != null) { for (uint keyIndex = 0; keyIndex < _dense.Length; ++keyIndex) { if (_dense[keyIndex] == null) { continue; } // is it the index of the array if (keyIndex >= newLen && keyIndex < oldLen) { var deleteSucceeded = DeleteAt(keyIndex); if (!deleteSucceeded) { newLenDesc.Value = keyIndex + 1; if (!newWritable) { newLenDesc.Writable = false; } base.DefineOwnProperty("length", newLenDesc, false); if (throwOnError) { ExceptionHelper.ThrowTypeError(_engine); } return(false); } } } } else { // in the case of sparse arrays, treat each concrete element instead of // iterating over all indexes var keys = new List <uint>(_sparse.Keys); var keysCount = keys.Count; for (var i = 0; i < keysCount; i++) { var keyIndex = keys[i]; // is it the index of the array if (keyIndex >= newLen && keyIndex < oldLen) { var deleteSucceeded = Delete(TypeConverter.ToString(keyIndex), false); if (!deleteSucceeded) { newLenDesc.Value = JsNumber.Create(keyIndex + 1); if (!newWritable) { newLenDesc.Writable = false; } base.DefineOwnProperty("length", newLenDesc, false); if (throwOnError) { ExceptionHelper.ThrowTypeError(_engine); } return(false); } } } } } else { while (newLen < oldLen) { // algorithm as per the spec oldLen--; var deleteSucceeded = Delete(TypeConverter.ToString(oldLen), false); if (!deleteSucceeded) { newLenDesc.Value = oldLen + 1; if (!newWritable) { newLenDesc.Writable = false; } base.DefineOwnProperty("length", newLenDesc, false); if (throwOnError) { ExceptionHelper.ThrowTypeError(_engine); } return(false); } } } if (!newWritable) { DefineOwnProperty("length", new PropertyDescriptor(value: null, flags: PropertyFlag.WritableSet), false); } return(true); } else if (IsArrayIndex(propertyName, out index)) { if (index >= oldLen && !oldLenDesc.Writable) { if (throwOnError) { ExceptionHelper.ThrowTypeError(_engine); } return(false); } var succeeded = base.DefineOwnProperty(propertyName, desc, false); if (!succeeded) { if (throwOnError) { ExceptionHelper.ThrowTypeError(_engine); } return(false); } if (index >= oldLen) { oldLenDesc.Value = index + 1; base.DefineOwnProperty("length", oldLenDesc, false); } return(true); } return(base.DefineOwnProperty(propertyName, desc, throwOnError)); }