protected internal static JintExpression Build(Engine engine, Expression expression) { switch (expression.Type) { case Nodes.AssignmentExpression: return(JintAssignmentExpression.Build(engine, (AssignmentExpression)expression)); case Nodes.ArrayExpression: return(new JintArrayExpression(engine, (ArrayExpression)expression)); case Nodes.ArrowFunctionExpression: return(new JintArrowFunctionExpression(engine, (IFunction)expression)); case Nodes.BinaryExpression: return(JintBinaryExpression.Build(engine, (BinaryExpression)expression)); case Nodes.CallExpression: return(new JintCallExpression(engine, (CallExpression)expression)); case Nodes.ConditionalExpression: return(new JintConditionalExpression(engine, (ConditionalExpression)expression)); case Nodes.FunctionExpression: return(new JintFunctionExpression(engine, (IFunction)expression)); case Nodes.Identifier: return(new JintIdentifierExpression(engine, (Identifier)expression)); case Nodes.Literal: return(JintLiteralExpression.Build(engine, (Literal)expression)); case Nodes.LogicalExpression: switch (((BinaryExpression)expression).Operator) { case BinaryOperator.LogicalAnd: return(new JintLogicalAndExpression(engine, (BinaryExpression)expression)); case BinaryOperator.LogicalOr: return(new JintLogicalOrExpression(engine, (BinaryExpression)expression)); default: return(ExceptionHelper.ThrowArgumentOutOfRangeException <JintExpression>()); } case Nodes.MemberExpression: return(new JintMemberExpression(engine, (MemberExpression)expression)); case Nodes.NewExpression: return(new JintNewExpression(engine, (NewExpression)expression)); case Nodes.ObjectExpression: return(new JintObjectExpression(engine, (ObjectExpression)expression)); case Nodes.SequenceExpression: return(new JintSequenceExpression(engine, (SequenceExpression)expression)); case Nodes.ThisExpression: return(new JintThisExpression(engine, (ThisExpression)expression)); case Nodes.UpdateExpression: return(new JintUpdateExpression(engine, (UpdateExpression)expression)); case Nodes.UnaryExpression: return(JintUnaryExpression.Build(engine, (UnaryExpression)expression)); case Nodes.SpreadElement: return(new JintSpreadExpression(engine, (SpreadElement)expression)); case Nodes.TemplateLiteral: return(new JintTemplateLiteralExpression(engine, (TemplateLiteral)expression)); case Nodes.TaggedTemplateExpression: return(new JintTaggedTemplateExpression(engine, (TaggedTemplateExpression)expression)); default: return(ExceptionHelper.ThrowArgumentOutOfRangeException <JintExpression>(nameof(expression), $"unsupported expression type '{expression.Type}'")); } }
protected internal static JintExpression Build(Engine engine, Expression expression) { return(expression.Type switch { Nodes.AssignmentExpression => JintAssignmentExpression.Build(engine, (AssignmentExpression)expression), Nodes.ArrayExpression => new JintArrayExpression(engine, (ArrayExpression)expression), Nodes.ArrowFunctionExpression => new JintArrowFunctionExpression(engine, (IFunction)expression), Nodes.BinaryExpression => JintBinaryExpression.Build(engine, (BinaryExpression)expression), Nodes.CallExpression => new JintCallExpression(engine, (CallExpression)expression), Nodes.ConditionalExpression => new JintConditionalExpression(engine, (ConditionalExpression)expression), Nodes.FunctionExpression => new JintFunctionExpression(engine, (IFunction)expression), Nodes.Identifier => new JintIdentifierExpression(engine, (Identifier)expression), Nodes.Literal => JintLiteralExpression.Build(engine, (Literal)expression), Nodes.LogicalExpression => ((BinaryExpression)expression).Operator switch { BinaryOperator.LogicalAnd => new JintLogicalAndExpression(engine, (BinaryExpression)expression), BinaryOperator.LogicalOr => new JintLogicalOrExpression(engine, (BinaryExpression)expression), _ => ExceptionHelper.ThrowArgumentOutOfRangeException <JintExpression>() },
protected static bool Equal(JsValue x, JsValue y) { return(x.Type == y.Type ? JintBinaryExpression.StrictlyEqual(x, y) : EqualUnlikely(x, y)); }
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)); }