JintUpdateExpression.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. using Jint.Native;
  2. using Jint.Runtime.Environments;
  3. namespace Jint.Runtime.Interpreter.Expressions
  4. {
  5. internal sealed class JintUpdateExpression : JintExpression
  6. {
  7. private JintExpression _argument = null!;
  8. private int _change;
  9. private bool _prefix;
  10. private JintIdentifierExpression? _leftIdentifier;
  11. private bool _evalOrArguments;
  12. private bool _initialized;
  13. public JintUpdateExpression(UpdateExpression expression) : base(expression)
  14. {
  15. }
  16. private void Initialize()
  17. {
  18. var expression = (UpdateExpression) _expression;
  19. _prefix = expression.Prefix;
  20. _argument = Build(expression.Argument);
  21. if (expression.Operator == UnaryOperator.Increment)
  22. {
  23. _change = 1;
  24. }
  25. else if (expression.Operator == UnaryOperator.Decrement)
  26. {
  27. _change = -1;
  28. }
  29. else
  30. {
  31. ExceptionHelper.ThrowArgumentException();
  32. }
  33. _leftIdentifier = _argument as JintIdentifierExpression;
  34. _evalOrArguments = _leftIdentifier?.HasEvalOrArguments == true;
  35. }
  36. protected override object EvaluateInternal(EvaluationContext context)
  37. {
  38. if (!_initialized)
  39. {
  40. Initialize();
  41. _initialized = true;
  42. }
  43. var fastResult = _leftIdentifier != null
  44. ? UpdateIdentifier(context)
  45. : null;
  46. return fastResult ?? UpdateNonIdentifier(context);
  47. }
  48. private JsValue UpdateNonIdentifier(EvaluationContext context)
  49. {
  50. var engine = context.Engine;
  51. var reference = _argument.Evaluate(context) as Reference;
  52. if (reference is null)
  53. {
  54. ExceptionHelper.ThrowTypeError(engine.Realm, "Invalid left-hand side expression");
  55. }
  56. reference.AssertValid(engine.Realm);
  57. var value = engine.GetValue(reference, false);
  58. var isInteger = value._type == InternalTypes.Integer;
  59. JsValue? newValue = null;
  60. var operatorOverloaded = false;
  61. if (context.OperatorOverloadingAllowed)
  62. {
  63. if (JintUnaryExpression.TryOperatorOverloading(context, _argument.GetValue(context), _change > 0 ? "op_Increment" : "op_Decrement", out var result))
  64. {
  65. operatorOverloaded = true;
  66. newValue = result;
  67. }
  68. }
  69. if (!operatorOverloaded)
  70. {
  71. if (isInteger)
  72. {
  73. newValue = JsNumber.Create(value.AsInteger() + _change);
  74. }
  75. else if (!value.IsBigInt())
  76. {
  77. newValue = JsNumber.Create(TypeConverter.ToNumber(value) + _change);
  78. }
  79. else
  80. {
  81. newValue = JsBigInt.Create(TypeConverter.ToBigInt(value) + _change);
  82. }
  83. }
  84. engine.PutValue(reference, newValue!);
  85. engine._referencePool.Return(reference);
  86. if (_prefix)
  87. {
  88. return newValue!;
  89. }
  90. else
  91. {
  92. if (isInteger || operatorOverloaded)
  93. {
  94. return value;
  95. }
  96. if (!value.IsBigInt())
  97. {
  98. return JsNumber.Create(TypeConverter.ToNumber(value));
  99. }
  100. return JsBigInt.Create(value);
  101. }
  102. }
  103. private JsValue? UpdateIdentifier(EvaluationContext context)
  104. {
  105. var strict = StrictModeScope.IsStrictModeCode;
  106. var name = _leftIdentifier!.Identifier;
  107. var engine = context.Engine;
  108. var env = engine.ExecutionContext.LexicalEnvironment;
  109. if (JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
  110. env,
  111. name,
  112. strict,
  113. out var environmentRecord,
  114. out var value))
  115. {
  116. if (strict && _evalOrArguments)
  117. {
  118. ExceptionHelper.ThrowSyntaxError(engine.Realm);
  119. }
  120. var isInteger = value._type == InternalTypes.Integer;
  121. JsValue? newValue = null;
  122. var operatorOverloaded = false;
  123. if (context.OperatorOverloadingAllowed)
  124. {
  125. if (JintUnaryExpression.TryOperatorOverloading(context, _argument.GetValue(context), _change > 0 ? "op_Increment" : "op_Decrement", out var result))
  126. {
  127. operatorOverloaded = true;
  128. newValue = result;
  129. }
  130. }
  131. if (!operatorOverloaded)
  132. {
  133. if (isInteger)
  134. {
  135. newValue = JsNumber.Create(value.AsInteger() + _change);
  136. }
  137. else if (value._type != InternalTypes.BigInt)
  138. {
  139. newValue = JsNumber.Create(TypeConverter.ToNumber(value) + _change);
  140. }
  141. else
  142. {
  143. newValue = JsBigInt.Create(TypeConverter.ToBigInt(value) + _change);
  144. }
  145. }
  146. environmentRecord.SetMutableBinding(name.Key.Name, newValue!, strict);
  147. if (_prefix)
  148. {
  149. return newValue;
  150. }
  151. if (!value.IsBigInt() && !value.IsNumber() && !operatorOverloaded)
  152. {
  153. return JsNumber.Create(TypeConverter.ToNumber(value));
  154. }
  155. return value;
  156. }
  157. return null;
  158. }
  159. }
  160. }