JintNewExpression.cs 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. using Jint.Native;
  2. namespace Jint.Runtime.Interpreter.Expressions;
  3. internal sealed class JintNewExpression : JintExpression
  4. {
  5. private JintExpression _calleeExpression = null!;
  6. private JintExpression[] _jintArguments = Array.Empty<JintExpression>();
  7. private bool _hasSpreads;
  8. private bool _initialized;
  9. public JintNewExpression(NewExpression expression) : base(expression)
  10. {
  11. }
  12. private void Initialize()
  13. {
  14. var expression = (NewExpression) _expression;
  15. _calleeExpression = Build(expression.Callee);
  16. if (expression.Arguments.Count <= 0)
  17. {
  18. return;
  19. }
  20. _jintArguments = new JintExpression[expression.Arguments.Count];
  21. for (var i = 0; i < _jintArguments.Length; i++)
  22. {
  23. var argument = expression.Arguments[i];
  24. _jintArguments[i] = Build(argument);
  25. _hasSpreads |= argument.Type == NodeType.SpreadElement;
  26. }
  27. }
  28. protected override object EvaluateInternal(EvaluationContext context)
  29. {
  30. if (!_initialized)
  31. {
  32. Initialize();
  33. _initialized = true;
  34. }
  35. var engine = context.Engine;
  36. // todo: optimize by defining a common abstract class or interface
  37. var jsValue = _calleeExpression.GetValue(context);
  38. JsValue[] arguments;
  39. if (_jintArguments.Length == 0)
  40. {
  41. arguments = Array.Empty<JsValue>();
  42. }
  43. else if (_hasSpreads)
  44. {
  45. arguments = BuildArgumentsWithSpreads(context, _jintArguments);
  46. }
  47. else
  48. {
  49. arguments = engine._jsValueArrayPool.RentArray(_jintArguments.Length);
  50. BuildArguments(context, _jintArguments, arguments);
  51. }
  52. // Reset the location to the "new" keyword so that if an Error object is
  53. // constructed below, the stack trace will capture the correct location.
  54. context.LastSyntaxElement = _expression;
  55. if (!jsValue.IsConstructor)
  56. {
  57. ExceptionHelper.ThrowTypeError(engine.Realm, _calleeExpression.SourceText + " is not a constructor");
  58. }
  59. // construct the new instance using the Function's constructor method
  60. var instance = engine.Construct(jsValue, arguments, jsValue, _calleeExpression);
  61. engine._jsValueArrayPool.ReturnArray(arguments);
  62. return instance;
  63. }
  64. }