JintAssignmentExpression.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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.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 BindingPattern)
  24. {
  25. return new BindingPatternAssignmentExpression(engine, expression);
  26. }
  27. return new SimpleAssignmentExpression(engine, expression);
  28. }
  29. return new JintAssignmentExpression(engine, expression);
  30. }
  31. protected override object EvaluateInternal()
  32. {
  33. var lref = _left.Evaluate() as Reference;
  34. if (lref is null)
  35. {
  36. ExceptionHelper.ThrowReferenceError(_engine.Realm, "not a valid reference");
  37. }
  38. var rval = _right.GetValue();
  39. var lval = _engine.GetValue(lref, false);
  40. var handledByOverload = false;
  41. if (_engine.Options._IsOperatorOverloadingAllowed)
  42. {
  43. string operatorClrName = null;
  44. switch (_operator)
  45. {
  46. case AssignmentOperator.PlusAssign:
  47. operatorClrName = "op_Addition";
  48. break;
  49. case AssignmentOperator.MinusAssign:
  50. operatorClrName = "op_Subtraction";
  51. break;
  52. case AssignmentOperator.TimesAssign:
  53. operatorClrName = "op_Multiply";
  54. break;
  55. case AssignmentOperator.DivideAssign:
  56. operatorClrName = "op_Division";
  57. break;
  58. case AssignmentOperator.ModuloAssign:
  59. operatorClrName = "op_Modulus";
  60. break;
  61. case AssignmentOperator.BitwiseAndAssign:
  62. operatorClrName = "op_BitwiseAnd";
  63. break;
  64. case AssignmentOperator.BitwiseOrAssign:
  65. operatorClrName = "op_BitwiseOr";
  66. break;
  67. case AssignmentOperator.BitwiseXOrAssign:
  68. operatorClrName = "op_ExclusiveOr";
  69. break;
  70. case AssignmentOperator.LeftShiftAssign:
  71. operatorClrName = "op_LeftShift";
  72. break;
  73. case AssignmentOperator.RightShiftAssign:
  74. operatorClrName = "op_RightShift";
  75. break;
  76. case AssignmentOperator.UnsignedRightShiftAssign:
  77. operatorClrName = "op_UnsignedRightShift";
  78. break;
  79. case AssignmentOperator.ExponentiationAssign:
  80. case AssignmentOperator.Assign:
  81. default:
  82. break;
  83. }
  84. if (operatorClrName != null &&
  85. JintBinaryExpression.TryOperatorOverloading(_engine, lval, rval, operatorClrName, out var result))
  86. {
  87. lval = JsValue.FromObject(_engine, result);
  88. handledByOverload = true;
  89. }
  90. }
  91. if (!handledByOverload)
  92. {
  93. switch (_operator)
  94. {
  95. case AssignmentOperator.PlusAssign:
  96. if (AreIntegerOperands(lval, rval))
  97. {
  98. lval = (long) lval.AsInteger() + rval.AsInteger();
  99. }
  100. else
  101. {
  102. var lprim = TypeConverter.ToPrimitive(lval);
  103. var rprim = TypeConverter.ToPrimitive(rval);
  104. if (lprim.IsString() || rprim.IsString())
  105. {
  106. if (!(lprim is JsString jsString))
  107. {
  108. jsString = new JsString.ConcatenatedString(TypeConverter.ToString(lprim));
  109. }
  110. lval = jsString.Append(rprim);
  111. }
  112. else
  113. {
  114. lval = TypeConverter.ToNumber(lprim) + TypeConverter.ToNumber(rprim);
  115. }
  116. }
  117. break;
  118. case AssignmentOperator.MinusAssign:
  119. lval = AreIntegerOperands(lval, rval)
  120. ? JsNumber.Create(lval.AsInteger() - rval.AsInteger())
  121. : JsNumber.Create(TypeConverter.ToNumber(lval) - TypeConverter.ToNumber(rval));
  122. break;
  123. case AssignmentOperator.TimesAssign:
  124. if (AreIntegerOperands(lval, rval))
  125. {
  126. lval = (long) lval.AsInteger() * rval.AsInteger();
  127. }
  128. else if (lval.IsUndefined() || rval.IsUndefined())
  129. {
  130. lval = Undefined.Instance;
  131. }
  132. else
  133. {
  134. lval = TypeConverter.ToNumber(lval) * TypeConverter.ToNumber(rval);
  135. }
  136. break;
  137. case AssignmentOperator.DivideAssign:
  138. lval = Divide(lval, rval);
  139. break;
  140. case AssignmentOperator.ModuloAssign:
  141. if (lval.IsUndefined() || rval.IsUndefined())
  142. {
  143. lval = Undefined.Instance;
  144. }
  145. else
  146. {
  147. lval = TypeConverter.ToNumber(lval) % TypeConverter.ToNumber(rval);
  148. }
  149. break;
  150. case AssignmentOperator.BitwiseAndAssign:
  151. lval = TypeConverter.ToInt32(lval) & TypeConverter.ToInt32(rval);
  152. break;
  153. case AssignmentOperator.BitwiseOrAssign:
  154. lval = TypeConverter.ToInt32(lval) | TypeConverter.ToInt32(rval);
  155. break;
  156. case AssignmentOperator.BitwiseXOrAssign:
  157. lval = TypeConverter.ToInt32(lval) ^ TypeConverter.ToInt32(rval);
  158. break;
  159. case AssignmentOperator.LeftShiftAssign:
  160. lval = TypeConverter.ToInt32(lval) << (int) (TypeConverter.ToUint32(rval) & 0x1F);
  161. break;
  162. case AssignmentOperator.RightShiftAssign:
  163. lval = TypeConverter.ToInt32(lval) >> (int) (TypeConverter.ToUint32(rval) & 0x1F);
  164. break;
  165. case AssignmentOperator.UnsignedRightShiftAssign:
  166. lval = (uint) TypeConverter.ToInt32(lval) >> (int) (TypeConverter.ToUint32(rval) & 0x1F);
  167. break;
  168. default:
  169. ExceptionHelper.ThrowNotImplementedException();
  170. return null;
  171. }
  172. }
  173. _engine.PutValue(lref, lval);
  174. _engine._referencePool.Return(lref);
  175. return lval;
  176. }
  177. internal sealed class SimpleAssignmentExpression : JintExpression
  178. {
  179. private JintExpression _left;
  180. private JintExpression _right;
  181. private JintIdentifierExpression _leftIdentifier;
  182. private bool _evalOrArguments;
  183. public SimpleAssignmentExpression(Engine engine, AssignmentExpression expression) : base(engine, expression)
  184. {
  185. _initialized = false;
  186. }
  187. protected override void Initialize()
  188. {
  189. var assignmentExpression = ((AssignmentExpression) _expression);
  190. _left = Build(_engine, assignmentExpression.Left);
  191. _leftIdentifier = _left as JintIdentifierExpression;
  192. _evalOrArguments = _leftIdentifier?.HasEvalOrArguments == true;
  193. _right = Build(_engine, assignmentExpression.Right);
  194. }
  195. protected override object EvaluateInternal()
  196. {
  197. JsValue rval = null;
  198. if (_leftIdentifier != null)
  199. {
  200. rval = AssignToIdentifier(_engine, _leftIdentifier, _right, _evalOrArguments);
  201. }
  202. return rval ?? SetValue();
  203. }
  204. private JsValue SetValue()
  205. {
  206. // slower version
  207. var lref = _left.Evaluate() as Reference;
  208. if (lref is null)
  209. {
  210. ExceptionHelper.ThrowReferenceError(_engine.Realm, "not a valid reference");
  211. }
  212. lref.AssertValid(_engine);
  213. var rval = _right.GetValue();
  214. _engine.PutValue(lref, rval);
  215. _engine._referencePool.Return(lref);
  216. return rval;
  217. }
  218. internal static JsValue AssignToIdentifier(
  219. Engine engine,
  220. JintIdentifierExpression left,
  221. JintExpression right,
  222. bool hasEvalOrArguments)
  223. {
  224. var env = engine.ExecutionContext.LexicalEnvironment;
  225. var strict = StrictModeScope.IsStrictModeCode;
  226. if (JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
  227. engine,
  228. env,
  229. left._expressionName,
  230. strict,
  231. out var environmentRecord,
  232. out _))
  233. {
  234. if (strict && hasEvalOrArguments)
  235. {
  236. ExceptionHelper.ThrowSyntaxError(engine.Realm);
  237. }
  238. var rval = right.GetValue().Clone();
  239. if (right._expression.IsFunctionWithName())
  240. {
  241. ((FunctionInstance) rval).SetFunctionName(left._expressionName.StringValue);
  242. }
  243. environmentRecord.SetMutableBinding(left._expressionName, rval, strict);
  244. return rval;
  245. }
  246. return null;
  247. }
  248. }
  249. }
  250. }