JintAssignmentExpression.cs 8.2 KB

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