JintAssignmentExpression.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. using Esprima.Ast;
  2. using Jint.Native;
  3. using Jint.Native.Function;
  4. using Jint.Runtime.Environments;
  5. using Jint.Runtime.References;
  6. namespace Jint.Runtime.Interpreter.Expressions
  7. {
  8. internal sealed class JintAssignmentExpression : JintExpression
  9. {
  10. private readonly JintExpression _left;
  11. private readonly JintExpression _right;
  12. private readonly AssignmentOperator _operator;
  13. private JintAssignmentExpression(Engine engine, AssignmentExpression expression) : base(engine, expression)
  14. {
  15. _left = Build(engine, (Expression) expression.Left);
  16. _right = Build(engine, expression.Right);
  17. _operator = expression.Operator;
  18. }
  19. internal static JintExpression Build(Engine engine, AssignmentExpression expression)
  20. {
  21. if (expression.Operator == AssignmentOperator.Assign)
  22. {
  23. if (expression.Left is Expression)
  24. {
  25. return new SimpleAssignmentExpression(engine, expression);
  26. }
  27. if (expression.Left is BindingPattern)
  28. {
  29. return new BindingPatternAssignmentExpression(engine, expression);
  30. }
  31. }
  32. return new JintAssignmentExpression(engine, expression);
  33. }
  34. protected override object EvaluateInternal()
  35. {
  36. var lref = _left.Evaluate() as Reference ?? ExceptionHelper.ThrowReferenceError<Reference>(_engine);
  37. var rval = _right.GetValue();
  38. var lval = _engine.GetValue(lref, false);
  39. switch (_operator)
  40. {
  41. case AssignmentOperator.PlusAssign:
  42. if (AreIntegerOperands(lval, rval))
  43. {
  44. lval = (long) lval.AsInteger() + rval.AsInteger();
  45. }
  46. else
  47. {
  48. var lprim = TypeConverter.ToPrimitive(lval);
  49. var rprim = TypeConverter.ToPrimitive(rval);
  50. if (lprim.IsString() || rprim.IsString())
  51. {
  52. if (!(lprim is JsString jsString))
  53. {
  54. jsString = new JsString.ConcatenatedString(TypeConverter.ToString(lprim));
  55. }
  56. lval = jsString.Append(rprim);
  57. }
  58. else
  59. {
  60. lval = TypeConverter.ToNumber(lprim) + TypeConverter.ToNumber(rprim);
  61. }
  62. }
  63. break;
  64. case AssignmentOperator.MinusAssign:
  65. lval = AreIntegerOperands(lval, rval)
  66. ? JsNumber.Create(lval.AsInteger() - rval.AsInteger())
  67. : JsNumber.Create(TypeConverter.ToNumber(lval) - TypeConverter.ToNumber(rval));
  68. break;
  69. case AssignmentOperator.TimesAssign:
  70. if (AreIntegerOperands(lval, rval))
  71. {
  72. lval = (long) lval.AsInteger() * rval.AsInteger();
  73. }
  74. else if (lval.IsUndefined() || rval.IsUndefined())
  75. {
  76. lval = Undefined.Instance;
  77. }
  78. else
  79. {
  80. lval = TypeConverter.ToNumber(lval) * TypeConverter.ToNumber(rval);
  81. }
  82. break;
  83. case AssignmentOperator.DivideAssign:
  84. lval = Divide(lval, rval);
  85. break;
  86. case AssignmentOperator.ModuloAssign:
  87. if (lval.IsUndefined() || rval.IsUndefined())
  88. {
  89. lval = Undefined.Instance;
  90. }
  91. else
  92. {
  93. lval = TypeConverter.ToNumber(lval) % TypeConverter.ToNumber(rval);
  94. }
  95. break;
  96. case AssignmentOperator.BitwiseAndAssign:
  97. lval = TypeConverter.ToInt32(lval) & TypeConverter.ToInt32(rval);
  98. break;
  99. case AssignmentOperator.BitwiseOrAssign:
  100. lval = TypeConverter.ToInt32(lval) | TypeConverter.ToInt32(rval);
  101. break;
  102. case AssignmentOperator.BitwiseXOrAssign:
  103. lval = TypeConverter.ToInt32(lval) ^ TypeConverter.ToInt32(rval);
  104. break;
  105. case AssignmentOperator.LeftShiftAssign:
  106. lval = TypeConverter.ToInt32(lval) << (int) (TypeConverter.ToUint32(rval) & 0x1F);
  107. break;
  108. case AssignmentOperator.RightShiftAssign:
  109. lval = TypeConverter.ToInt32(lval) >> (int) (TypeConverter.ToUint32(rval) & 0x1F);
  110. break;
  111. case AssignmentOperator.UnsignedRightShiftAssign:
  112. lval = (uint) TypeConverter.ToInt32(lval) >> (int) (TypeConverter.ToUint32(rval) & 0x1F);
  113. break;
  114. default:
  115. return ExceptionHelper.ThrowNotImplementedException<object>();
  116. }
  117. _engine.PutValue(lref, lval);
  118. _engine._referencePool.Return(lref);
  119. return lval;
  120. }
  121. internal sealed class SimpleAssignmentExpression : JintExpression
  122. {
  123. private readonly JintExpression _left;
  124. private readonly JintExpression _right;
  125. private readonly JintIdentifierExpression _leftIdentifier;
  126. private readonly bool _evalOrArguments;
  127. private readonly ArrayPattern _arrayPattern;
  128. public SimpleAssignmentExpression(Engine engine, AssignmentExpression expression) : base(engine, expression)
  129. {
  130. if (expression.Left is ArrayPattern arrayPattern)
  131. {
  132. _arrayPattern = arrayPattern;
  133. }
  134. else
  135. {
  136. _left = Build(engine, (Expression) expression.Left);
  137. _leftIdentifier = _left as JintIdentifierExpression;
  138. _evalOrArguments = _leftIdentifier?.HasEvalOrArguments == true;
  139. }
  140. _right = Build(engine, expression.Right);
  141. }
  142. protected override object EvaluateInternal()
  143. {
  144. JsValue rval = null;
  145. if (_leftIdentifier != null)
  146. {
  147. rval = AssignToIdentifier(_engine, _leftIdentifier, _right, _evalOrArguments);
  148. }
  149. else if (_arrayPattern != null)
  150. {
  151. foreach (var element in _arrayPattern.Elements)
  152. {
  153. AssignToIdentifier(_engine, _leftIdentifier, _right, false);
  154. }
  155. }
  156. return rval ?? SetValue();
  157. }
  158. private JsValue SetValue()
  159. {
  160. // slower version
  161. var lref = _left.Evaluate() as Reference ?? ExceptionHelper.ThrowReferenceError<Reference>(_engine);
  162. lref.AssertValid(_engine);
  163. var rval = _right.GetValue();
  164. _engine.PutValue(lref, rval);
  165. _engine._referencePool.Return(lref);
  166. return rval;
  167. }
  168. internal static JsValue AssignToIdentifier(
  169. Engine engine,
  170. JintIdentifierExpression left,
  171. JintExpression right,
  172. bool hasEvalOrArguments)
  173. {
  174. var env = engine.ExecutionContext.LexicalEnvironment;
  175. var strict = StrictModeScope.IsStrictModeCode;
  176. if (LexicalEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
  177. env,
  178. left.ExpressionName,
  179. strict,
  180. out var environmentRecord,
  181. out _))
  182. {
  183. if (strict && hasEvalOrArguments)
  184. {
  185. ExceptionHelper.ThrowSyntaxError(engine);
  186. }
  187. var rval = right.GetValue().Clone();
  188. if (right._expression.IsFunctionWithName())
  189. {
  190. ((FunctionInstance) rval).SetFunctionName(left.ExpressionName);
  191. }
  192. environmentRecord.SetMutableBinding(left.ExpressionName, rval, strict);
  193. return rval;
  194. }
  195. return null;
  196. }
  197. }
  198. }
  199. }