protected override ExpressionResult EvaluateInternal(EvaluationContext context) { var left = _left.GetValue(context).Value; var right = _right.GetValue(context).Value; JsValue result; if (context.OperatorOverloadingAllowed && TryOperatorOverloading(context, left, right, "op_Multiply", out var opResult)) { result = JsValue.FromObject(context.Engine, opResult); } else if (AreIntegerOperands(left, right)) { result = JsNumber.Create((long)left.AsInteger() * right.AsInteger()); } else { var leftNumeric = TypeConverter.ToNumeric(left); var rightNumeric = TypeConverter.ToNumeric(right); if (leftNumeric.IsNumber() && rightNumeric.IsNumber()) { result = JsNumber.Create(leftNumeric.AsNumber() * rightNumeric.AsNumber()); } else { AssertValidBigIntArithmeticOperands(context, leftNumeric, rightNumeric); result = JsBigInt.Create(leftNumeric.AsBigInt() * rightNumeric.AsBigInt()); } } return(NormalCompletion(result)); }
internal static JsValue ConvertToJsValue(Literal literal) { if (literal.TokenType == TokenType.BooleanLiteral) { return(literal.NumericValue > 0.0 ? JsBoolean.True : JsBoolean.False); } if (literal.TokenType == TokenType.NullLiteral) { return(JsValue.Null); } if (literal.TokenType == TokenType.NumericLiteral) { var intValue = (int)literal.NumericValue; return(literal.NumericValue == intValue && (intValue != 0 || BitConverter.DoubleToInt64Bits(literal.NumericValue) != JsNumber.NegativeZeroBits) ? JsNumber.Create(intValue) : JsNumber.Create(literal.NumericValue)); } if (literal.TokenType == TokenType.StringLiteral) { return(JsString.Create((string)literal.Value)); } if (literal.TokenType == TokenType.BigIntLiteral) { return(JsBigInt.Create((BigInteger)literal.Value)); } return(null); }
protected override ExpressionResult EvaluateInternal(EvaluationContext context) { var left = _left.GetValue(context).Value; var right = _right.GetValue(context).Value; if (context.OperatorOverloadingAllowed && TryOperatorOverloading(context, left, right, "op_Subtraction", out var opResult)) { return(NormalCompletion(JsValue.FromObject(context.Engine, opResult))); } JsValue number; left = TypeConverter.ToNumeric(left); right = TypeConverter.ToNumeric(right); if (AreIntegerOperands(left, right)) { number = JsNumber.Create((long)left.AsInteger() - right.AsInteger()); } else if (AreNonBigIntOperands(left, right)) { number = JsNumber.Create(left.AsNumber() - right.AsNumber()); } else { number = JsBigInt.Create(TypeConverter.ToBigInt(left) - TypeConverter.ToBigInt(right)); } return(NormalCompletion(number)); }
protected override ExpressionResult EvaluateInternal(EvaluationContext context) { var left = _left.GetValue(context).Value; var right = _right.GetValue(context).Value; if (context.OperatorOverloadingAllowed && TryOperatorOverloading(context, left, right, "op_Addition", out var opResult)) { return(NormalCompletion(JsValue.FromObject(context.Engine, opResult))); } if (AreIntegerOperands(left, right)) { return(NormalCompletion(JsNumber.Create((long)left.AsInteger() + right.AsInteger()))); } var lprim = TypeConverter.ToPrimitive(left); var rprim = TypeConverter.ToPrimitive(right); JsValue result; if (lprim.IsString() || rprim.IsString()) { result = JsString.Create(TypeConverter.ToString(lprim) + TypeConverter.ToString(rprim)); } else if (AreNonBigIntOperands(left, right)) { result = JsNumber.Create(TypeConverter.ToNumber(lprim) + TypeConverter.ToNumber(rprim)); } else { AssertValidBigIntArithmeticOperands(context, lprim, rprim); result = JsBigInt.Create(TypeConverter.ToBigInt(lprim) + TypeConverter.ToBigInt(rprim)); } return(NormalCompletion(result)); }
private JsValue UpdateNonIdentifier(EvaluationContext context) { var engine = context.Engine; var reference = _argument.Evaluate(context).Value as Reference; if (reference is null) { ExceptionHelper.ThrowTypeError(engine.Realm, "Invalid left-hand side expression"); } reference.AssertValid(engine.Realm); var value = engine.GetValue(reference, false); var isInteger = value._type == InternalTypes.Integer; JsValue newValue = null; var operatorOverloaded = false; if (context.OperatorOverloadingAllowed) { if (JintUnaryExpression.TryOperatorOverloading(context, _argument.GetValue(context).Value, _change > 0 ? "op_Increment" : "op_Decrement", out var result)) { operatorOverloaded = true; newValue = result; } } if (!operatorOverloaded) { if (isInteger) { newValue = JsNumber.Create(value.AsInteger() + _change); } else if (!value.IsBigInt()) { newValue = JsNumber.Create(TypeConverter.ToNumber(value) + _change); } else { newValue = JsBigInt.Create(TypeConverter.ToBigInt(value) + _change); } } engine.PutValue(reference, newValue); engine._referencePool.Return(reference); if (_prefix) { return(newValue); } else { if (isInteger || operatorOverloaded) { return(value); } if (!value.IsBigInt()) { return(JsNumber.Create(TypeConverter.ToNumber(value))); } return(JsBigInt.Create(value)); } }
private JsValue UpdateIdentifier(EvaluationContext context) { var strict = StrictModeScope.IsStrictModeCode; var name = _leftIdentifier._expressionName; var engine = context.Engine; var env = engine.ExecutionContext.LexicalEnvironment; if (JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue( env, name, strict, out var environmentRecord, out var value)) { if (strict && _evalOrArguments) { ExceptionHelper.ThrowSyntaxError(engine.Realm); } var isInteger = value._type == InternalTypes.Integer; JsValue newValue = null; var operatorOverloaded = false; if (context.OperatorOverloadingAllowed) { if (JintUnaryExpression.TryOperatorOverloading(context, _argument.GetValue(context).Value, _change > 0 ? "op_Increment" : "op_Decrement", out var result)) { operatorOverloaded = true; newValue = result; } } if (!operatorOverloaded) { if (isInteger) { newValue = JsNumber.Create(value.AsInteger() + _change); } else if (value._type != InternalTypes.BigInt) { newValue = JsNumber.Create(TypeConverter.ToNumber(value) + _change); } else { newValue = JsBigInt.Create(TypeConverter.ToBigInt(value) + _change); } } environmentRecord.SetMutableBinding(name.Key.Name, newValue, strict); if (_prefix) { return(newValue); } if (!value.IsBigInt() && !value.IsNumber() && !operatorOverloaded) { return(JsNumber.Create(TypeConverter.ToNumber(value))); } return(value); } return(null); }
protected override ExpressionResult EvaluateInternal(EvaluationContext context) { var lref = _left.Evaluate(context).Value as Reference; if (lref is null) { ExceptionHelper.ThrowReferenceError(context.Engine.Realm, "not a valid reference"); } var engine = context.Engine; var lval = context.Engine.GetValue(lref, false); var handledByOverload = false; if (context.OperatorOverloadingAllowed) { string operatorClrName = null; switch (_operator) { case AssignmentOperator.PlusAssign: operatorClrName = "op_Addition"; break; case AssignmentOperator.MinusAssign: operatorClrName = "op_Subtraction"; break; case AssignmentOperator.TimesAssign: operatorClrName = "op_Multiply"; break; case AssignmentOperator.DivideAssign: operatorClrName = "op_Division"; break; case AssignmentOperator.ModuloAssign: operatorClrName = "op_Modulus"; break; case AssignmentOperator.BitwiseAndAssign: operatorClrName = "op_BitwiseAnd"; break; case AssignmentOperator.BitwiseOrAssign: operatorClrName = "op_BitwiseOr"; break; case AssignmentOperator.BitwiseXOrAssign: operatorClrName = "op_ExclusiveOr"; break; case AssignmentOperator.LeftShiftAssign: operatorClrName = "op_LeftShift"; break; case AssignmentOperator.RightShiftAssign: operatorClrName = "op_RightShift"; break; case AssignmentOperator.UnsignedRightShiftAssign: operatorClrName = "op_UnsignedRightShift"; break; case AssignmentOperator.ExponentiationAssign: case AssignmentOperator.Assign: default: break; } if (operatorClrName != null) { var rval = _right.GetValue(context).Value; if (JintBinaryExpression.TryOperatorOverloading(context, lval, rval, operatorClrName, out var result)) { lval = JsValue.FromObject(context.Engine, result); handledByOverload = true; } } } if (!handledByOverload) { switch (_operator) { case AssignmentOperator.PlusAssign: { var rval = _right.GetValue(context).Value; if (AreIntegerOperands(lval, rval)) { lval = (long)lval.AsInteger() + rval.AsInteger(); } else { var lprim = TypeConverter.ToPrimitive(lval); var rprim = TypeConverter.ToPrimitive(rval); if (lprim.IsString() || rprim.IsString()) { if (!(lprim is JsString jsString)) { jsString = new JsString.ConcatenatedString(TypeConverter.ToString(lprim)); } lval = jsString.Append(rprim); } else if (!AreIntegerOperands(lval, rval)) { lval = TypeConverter.ToNumber(lprim) + TypeConverter.ToNumber(rprim); } else { lval = TypeConverter.ToBigInt(lprim) + TypeConverter.ToBigInt(rprim); } } break; } case AssignmentOperator.MinusAssign: { var rval = _right.GetValue(context).Value; if (AreIntegerOperands(lval, rval)) { lval = JsNumber.Create(lval.AsInteger() - rval.AsInteger()); } else if (!AreIntegerOperands(lval, rval)) { lval = JsNumber.Create(TypeConverter.ToNumber(lval) - TypeConverter.ToNumber(rval)); } else { lval = JsNumber.Create(TypeConverter.ToBigInt(lval) - TypeConverter.ToBigInt(rval)); } break; } case AssignmentOperator.TimesAssign: { var rval = _right.GetValue(context).Value; if (AreIntegerOperands(lval, rval)) { lval = (long)lval.AsInteger() * rval.AsInteger(); } else if (lval.IsUndefined() || rval.IsUndefined()) { lval = Undefined.Instance; } else if (!AreIntegerOperands(lval, rval)) { lval = TypeConverter.ToNumber(lval) * TypeConverter.ToNumber(rval); } else { lval = TypeConverter.ToBigInt(lval) * TypeConverter.ToBigInt(rval); } break; } case AssignmentOperator.DivideAssign: { var rval = _right.GetValue(context).Value; lval = Divide(context, lval, rval); break; } case AssignmentOperator.ModuloAssign: { var rval = _right.GetValue(context).Value; if (lval.IsUndefined() || rval.IsUndefined()) { lval = Undefined.Instance; } else if (!AreIntegerOperands(lval, rval)) { lval = TypeConverter.ToNumber(lval) % TypeConverter.ToNumber(rval); } else { lval = TypeConverter.ToNumber(lval) % TypeConverter.ToNumber(rval); } break; } case AssignmentOperator.BitwiseAndAssign: { var rval = _right.GetValue(context).Value; lval = TypeConverter.ToInt32(lval) & TypeConverter.ToInt32(rval); break; } case AssignmentOperator.BitwiseOrAssign: { var rval = _right.GetValue(context).Value; lval = TypeConverter.ToInt32(lval) | TypeConverter.ToInt32(rval); break; } case AssignmentOperator.BitwiseXOrAssign: { var rval = _right.GetValue(context).Value; lval = TypeConverter.ToInt32(lval) ^ TypeConverter.ToInt32(rval); break; } case AssignmentOperator.LeftShiftAssign: { var rval = _right.GetValue(context).Value; lval = TypeConverter.ToInt32(lval) << (int)(TypeConverter.ToUint32(rval) & 0x1F); break; } case AssignmentOperator.RightShiftAssign: { var rval = _right.GetValue(context).Value; lval = TypeConverter.ToInt32(lval) >> (int)(TypeConverter.ToUint32(rval) & 0x1F); break; } case AssignmentOperator.UnsignedRightShiftAssign: { var rval = _right.GetValue(context).Value; lval = (uint)TypeConverter.ToInt32(lval) >> (int)(TypeConverter.ToUint32(rval) & 0x1F); break; } case AssignmentOperator.NullishAssign: { if (!lval.IsNullOrUndefined()) { return(NormalCompletion(lval)); } var rval = NamedEvaluation(context, _right); lval = rval; break; } case AssignmentOperator.AndAssign: { if (!TypeConverter.ToBoolean(lval)) { return(NormalCompletion(lval)); } var rval = NamedEvaluation(context, _right); lval = rval; break; } case AssignmentOperator.OrAssign: { if (TypeConverter.ToBoolean(lval)) { return(NormalCompletion(lval)); } var rval = NamedEvaluation(context, _right); lval = rval; break; } case AssignmentOperator.ExponentiationAssign: { var rval = _right.GetValue(context).Value; if (!lval.IsBigInt() && !rval.IsBigInt()) { lval = JsNumber.Create(System.Math.Pow(TypeConverter.ToNumber(lval), TypeConverter.ToNumber(rval))); } else { var exponent = TypeConverter.ToBigInt(rval); if (exponent > int.MaxValue || exponent < int.MinValue) { ExceptionHelper.ThrowTypeError(context.Engine.Realm, "Cannot do exponentation with exponent not fitting int32"); } lval = JsBigInt.Create(BigInteger.Pow(TypeConverter.ToBigInt(lval), (int)exponent)); } break; } default: ExceptionHelper.ThrowNotImplementedException(); return(default); } } engine.PutValue(lref, lval); engine._referencePool.Return(lref); return(NormalCompletion(lval)); }