JintAssignmentExpression.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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. ExceptionHelper.ThrowNotImplementedException();
  116. return null;
  117. }
  118. _engine.PutValue(lref, lval);
  119. _engine._referencePool.Return(lref);
  120. return lval;
  121. }
  122. internal sealed class SimpleAssignmentExpression : JintExpression
  123. {
  124. private readonly JintExpression _left;
  125. private readonly JintExpression _right;
  126. private readonly JintIdentifierExpression _leftIdentifier;
  127. private readonly bool _evalOrArguments;
  128. private readonly ArrayPattern _arrayPattern;
  129. public SimpleAssignmentExpression(Engine engine, AssignmentExpression expression) : base(engine, expression)
  130. {
  131. if (expression.Left is ArrayPattern arrayPattern)
  132. {
  133. _arrayPattern = arrayPattern;
  134. }
  135. else
  136. {
  137. _left = Build(engine, (Expression) expression.Left);
  138. _leftIdentifier = _left as JintIdentifierExpression;
  139. _evalOrArguments = _leftIdentifier?.ExpressionName == KnownKeys.Eval
  140. || _leftIdentifier?.ExpressionName == KnownKeys.Arguments;
  141. }
  142. _right = Build(engine, expression.Right);
  143. }
  144. protected override object EvaluateInternal()
  145. {
  146. JsValue rval = null;
  147. if (_leftIdentifier != null)
  148. {
  149. rval = AssignToIdentifier(_engine, _leftIdentifier, _right, _evalOrArguments);
  150. }
  151. else if (_arrayPattern != null)
  152. {
  153. foreach (var element in _arrayPattern.Elements)
  154. {
  155. AssignToIdentifier(_engine, _leftIdentifier, _right, false);
  156. }
  157. }
  158. return rval ?? SetValue();
  159. }
  160. private JsValue SetValue()
  161. {
  162. // slower version
  163. var lref = _left.Evaluate() as Reference ?? ExceptionHelper.ThrowReferenceError<Reference>(_engine);
  164. lref.AssertValid(_engine);
  165. var rval = _right.GetValue();
  166. if (_right._expression.IsFunctionWithName())
  167. {
  168. ((FunctionInstance) rval).SetFunctionName(lref.GetReferencedName());
  169. }
  170. _engine.PutValue(lref, rval);
  171. _engine._referencePool.Return(lref);
  172. return rval;
  173. }
  174. internal static JsValue AssignToIdentifier(
  175. Engine engine,
  176. JintIdentifierExpression left,
  177. JintExpression right,
  178. bool hasEvalOrArguments)
  179. {
  180. var env = engine.ExecutionContext.LexicalEnvironment;
  181. var strict = StrictModeScope.IsStrictModeCode;
  182. if (LexicalEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
  183. env,
  184. left.ExpressionName,
  185. strict,
  186. out var environmentRecord,
  187. out _))
  188. {
  189. if (strict && hasEvalOrArguments)
  190. {
  191. ExceptionHelper.ThrowSyntaxError(engine);
  192. }
  193. var rval = right.GetValue().Clone();
  194. if (right._expression.IsFunctionWithName())
  195. {
  196. ((FunctionInstance) rval).SetFunctionName(left.ExpressionName);
  197. }
  198. environmentRecord.SetMutableBinding(left.ExpressionName, rval, strict);
  199. return rval;
  200. }
  201. return null;
  202. }
  203. }
  204. }
  205. }