JintAssignmentExpression.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  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 lval = _engine.GetValue(lref, false);
  39. var handledByOverload = false;
  40. if (_engine.Options.Interop.OperatorOverloadingAllowed)
  41. {
  42. string operatorClrName = null;
  43. switch (_operator)
  44. {
  45. case AssignmentOperator.PlusAssign:
  46. operatorClrName = "op_Addition";
  47. break;
  48. case AssignmentOperator.MinusAssign:
  49. operatorClrName = "op_Subtraction";
  50. break;
  51. case AssignmentOperator.TimesAssign:
  52. operatorClrName = "op_Multiply";
  53. break;
  54. case AssignmentOperator.DivideAssign:
  55. operatorClrName = "op_Division";
  56. break;
  57. case AssignmentOperator.ModuloAssign:
  58. operatorClrName = "op_Modulus";
  59. break;
  60. case AssignmentOperator.BitwiseAndAssign:
  61. operatorClrName = "op_BitwiseAnd";
  62. break;
  63. case AssignmentOperator.BitwiseOrAssign:
  64. operatorClrName = "op_BitwiseOr";
  65. break;
  66. case AssignmentOperator.BitwiseXOrAssign:
  67. operatorClrName = "op_ExclusiveOr";
  68. break;
  69. case AssignmentOperator.LeftShiftAssign:
  70. operatorClrName = "op_LeftShift";
  71. break;
  72. case AssignmentOperator.RightShiftAssign:
  73. operatorClrName = "op_RightShift";
  74. break;
  75. case AssignmentOperator.UnsignedRightShiftAssign:
  76. operatorClrName = "op_UnsignedRightShift";
  77. break;
  78. case AssignmentOperator.ExponentiationAssign:
  79. case AssignmentOperator.Assign:
  80. default:
  81. break;
  82. }
  83. if (operatorClrName != null)
  84. {
  85. var rval = _right.GetValue();
  86. if (JintBinaryExpression.TryOperatorOverloading(_engine, lval, rval, operatorClrName, out var result))
  87. {
  88. lval = JsValue.FromObject(_engine, result);
  89. handledByOverload = true;
  90. }
  91. }
  92. }
  93. if (!handledByOverload)
  94. {
  95. switch (_operator)
  96. {
  97. case AssignmentOperator.PlusAssign:
  98. {
  99. var rval = _right.GetValue();
  100. if (AreIntegerOperands(lval, rval))
  101. {
  102. lval = (long) lval.AsInteger() + rval.AsInteger();
  103. }
  104. else
  105. {
  106. var lprim = TypeConverter.ToPrimitive(lval);
  107. var rprim = TypeConverter.ToPrimitive(rval);
  108. if (lprim.IsString() || rprim.IsString())
  109. {
  110. if (!(lprim is JsString jsString))
  111. {
  112. jsString = new JsString.ConcatenatedString(TypeConverter.ToString(lprim));
  113. }
  114. lval = jsString.Append(rprim);
  115. }
  116. else
  117. {
  118. lval = TypeConverter.ToNumber(lprim) + TypeConverter.ToNumber(rprim);
  119. }
  120. }
  121. break;
  122. }
  123. case AssignmentOperator.MinusAssign:
  124. {
  125. var rval = _right.GetValue();
  126. lval = AreIntegerOperands(lval, rval)
  127. ? JsNumber.Create(lval.AsInteger() - rval.AsInteger())
  128. : JsNumber.Create(TypeConverter.ToNumber(lval) - TypeConverter.ToNumber(rval));
  129. break;
  130. }
  131. case AssignmentOperator.TimesAssign:
  132. {
  133. var rval = _right.GetValue();
  134. if (AreIntegerOperands(lval, rval))
  135. {
  136. lval = (long) lval.AsInteger() * rval.AsInteger();
  137. }
  138. else if (lval.IsUndefined() || rval.IsUndefined())
  139. {
  140. lval = Undefined.Instance;
  141. }
  142. else
  143. {
  144. lval = TypeConverter.ToNumber(lval) * TypeConverter.ToNumber(rval);
  145. }
  146. break;
  147. }
  148. case AssignmentOperator.DivideAssign:
  149. {
  150. var rval = _right.GetValue();
  151. lval = Divide(lval, rval);
  152. break;
  153. }
  154. case AssignmentOperator.ModuloAssign:
  155. {
  156. var rval = _right.GetValue();
  157. if (lval.IsUndefined() || rval.IsUndefined())
  158. {
  159. lval = Undefined.Instance;
  160. }
  161. else
  162. {
  163. lval = TypeConverter.ToNumber(lval) % TypeConverter.ToNumber(rval);
  164. }
  165. break;
  166. }
  167. case AssignmentOperator.BitwiseAndAssign:
  168. {
  169. var rval = _right.GetValue();
  170. lval = TypeConverter.ToInt32(lval) & TypeConverter.ToInt32(rval);
  171. break;
  172. }
  173. case AssignmentOperator.BitwiseOrAssign:
  174. {
  175. var rval = _right.GetValue();
  176. lval = TypeConverter.ToInt32(lval) | TypeConverter.ToInt32(rval);
  177. break;
  178. }
  179. case AssignmentOperator.BitwiseXOrAssign:
  180. {
  181. var rval = _right.GetValue();
  182. lval = TypeConverter.ToInt32(lval) ^ TypeConverter.ToInt32(rval);
  183. break;
  184. }
  185. case AssignmentOperator.LeftShiftAssign:
  186. {
  187. var rval = _right.GetValue();
  188. lval = TypeConverter.ToInt32(lval) << (int) (TypeConverter.ToUint32(rval) & 0x1F);
  189. break;
  190. }
  191. case AssignmentOperator.RightShiftAssign:
  192. {
  193. var rval = _right.GetValue();
  194. lval = TypeConverter.ToInt32(lval) >> (int) (TypeConverter.ToUint32(rval) & 0x1F);
  195. break;
  196. }
  197. case AssignmentOperator.UnsignedRightShiftAssign:
  198. {
  199. var rval = _right.GetValue();
  200. lval = (uint) TypeConverter.ToInt32(lval) >> (int) (TypeConverter.ToUint32(rval) & 0x1F);
  201. break;
  202. }
  203. case AssignmentOperator.NullishAssign:
  204. {
  205. if (!lval.IsNullOrUndefined())
  206. {
  207. return lval;
  208. }
  209. var rval = NamedEvaluation(_right);
  210. lval = rval;
  211. break;
  212. }
  213. case AssignmentOperator.AndAssign:
  214. {
  215. if (!TypeConverter.ToBoolean(lval))
  216. {
  217. return lval;
  218. }
  219. var rval = NamedEvaluation(_right);
  220. lval = rval;
  221. break;
  222. }
  223. case AssignmentOperator.OrAssign:
  224. {
  225. if (TypeConverter.ToBoolean(lval))
  226. {
  227. return lval;
  228. }
  229. var rval = NamedEvaluation(_right);
  230. lval = rval;
  231. break;
  232. }
  233. default:
  234. ExceptionHelper.ThrowNotImplementedException();
  235. return null;
  236. }
  237. }
  238. _engine.PutValue(lref, lval);
  239. _engine._referencePool.Return(lref);
  240. return lval;
  241. }
  242. private JsValue NamedEvaluation(JintExpression expression)
  243. {
  244. var rval = expression.GetValue();
  245. if (expression._expression.IsAnonymousFunctionDefinition() && _left._expression.Type == Nodes.Identifier)
  246. {
  247. ((FunctionInstance) rval).SetFunctionName(((Identifier) _left._expression).Name);
  248. }
  249. return rval;
  250. }
  251. internal sealed class SimpleAssignmentExpression : JintExpression
  252. {
  253. private JintExpression _left;
  254. private JintExpression _right;
  255. private JintIdentifierExpression _leftIdentifier;
  256. private bool _evalOrArguments;
  257. public SimpleAssignmentExpression(Engine engine, AssignmentExpression expression) : base(engine, expression)
  258. {
  259. _initialized = false;
  260. }
  261. protected override void Initialize()
  262. {
  263. var assignmentExpression = ((AssignmentExpression) _expression);
  264. _left = Build(_engine, assignmentExpression.Left);
  265. _leftIdentifier = _left as JintIdentifierExpression;
  266. _evalOrArguments = _leftIdentifier?.HasEvalOrArguments == true;
  267. _right = Build(_engine, assignmentExpression.Right);
  268. }
  269. protected override object EvaluateInternal()
  270. {
  271. JsValue rval = null;
  272. if (_leftIdentifier != null)
  273. {
  274. rval = AssignToIdentifier(_engine, _leftIdentifier, _right, _evalOrArguments);
  275. }
  276. return rval ?? SetValue();
  277. }
  278. private JsValue SetValue()
  279. {
  280. // slower version
  281. var lref = _left.Evaluate() as Reference;
  282. if (lref is null)
  283. {
  284. ExceptionHelper.ThrowReferenceError(_engine.Realm, "not a valid reference");
  285. }
  286. lref.AssertValid(_engine);
  287. var rval = _right.GetValue();
  288. _engine.PutValue(lref, rval);
  289. _engine._referencePool.Return(lref);
  290. return rval;
  291. }
  292. internal static JsValue AssignToIdentifier(
  293. Engine engine,
  294. JintIdentifierExpression left,
  295. JintExpression right,
  296. bool hasEvalOrArguments)
  297. {
  298. var env = engine.ExecutionContext.LexicalEnvironment;
  299. var strict = StrictModeScope.IsStrictModeCode;
  300. if (JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
  301. engine,
  302. env,
  303. left._expressionName,
  304. strict,
  305. out var environmentRecord,
  306. out _))
  307. {
  308. if (strict && hasEvalOrArguments)
  309. {
  310. ExceptionHelper.ThrowSyntaxError(engine.Realm);
  311. }
  312. var rval = right.GetValue().Clone();
  313. if (right._expression.IsFunctionDefinition())
  314. {
  315. ((FunctionInstance) rval).SetFunctionName(left._expressionName.StringValue);
  316. }
  317. environmentRecord.SetMutableBinding(left._expressionName, rval, strict);
  318. return rval;
  319. }
  320. return null;
  321. }
  322. }
  323. }
  324. }