JintAssignmentExpression.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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 == KnownKeys.Eval
  126. || _leftIdentifier?.ExpressionName == KnownKeys.Arguments;
  127. }
  128. _right = Build(engine, expression.Right);
  129. }
  130. protected override object EvaluateInternal()
  131. {
  132. JsValue rval = null;
  133. if (_leftIdentifier != null)
  134. {
  135. rval = AssignToIdentifier(_engine, _leftIdentifier, _right, _evalOrArguments);
  136. }
  137. else if (_arrayPattern != null)
  138. {
  139. foreach (var element in _arrayPattern.Elements)
  140. {
  141. AssignToIdentifier(_engine, _leftIdentifier, _right, false);
  142. }
  143. }
  144. return rval ?? SetValue();
  145. }
  146. private JsValue SetValue()
  147. {
  148. // slower version
  149. var lref = _left.Evaluate() as Reference ?? ExceptionHelper.ThrowReferenceError<Reference>(_engine);
  150. lref.AssertValid(_engine);
  151. var rval = _right.GetValue();
  152. if (_right._expression.IsFunctionWithName())
  153. {
  154. ((FunctionInstance) rval).SetFunctionName(lref.GetReferencedName());
  155. }
  156. _engine.PutValue(lref, rval);
  157. _engine._referencePool.Return(lref);
  158. return rval;
  159. }
  160. internal static JsValue AssignToIdentifier(
  161. Engine engine,
  162. JintIdentifierExpression left,
  163. JintExpression right,
  164. bool hasEvalOrArguments)
  165. {
  166. var env = engine.ExecutionContext.LexicalEnvironment;
  167. var strict = StrictModeScope.IsStrictModeCode;
  168. if (LexicalEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
  169. env,
  170. left.ExpressionName,
  171. strict,
  172. out var environmentRecord,
  173. out _))
  174. {
  175. if (strict && hasEvalOrArguments)
  176. {
  177. ExceptionHelper.ThrowSyntaxError(engine);
  178. }
  179. var rval = right.GetValue();
  180. if (right._expression.IsFunctionWithName())
  181. {
  182. ((FunctionInstance) rval).SetFunctionName(left.ExpressionName);
  183. }
  184. environmentRecord.SetMutableBinding(left.ExpressionName, rval, strict);
  185. return rval;
  186. }
  187. return null;
  188. }
  189. }
  190. }
  191. }