JintNewExpression.cs 2.6 KB

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