IteratorProtocol.cs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. using Jint.Native.Object;
  2. using Jint.Runtime;
  3. namespace Jint.Native.Iterator;
  4. /// <summary>
  5. /// Handles looping of iterator values, sub-classes can use to implement wanted actions.
  6. /// </summary>
  7. internal abstract class IteratorProtocol
  8. {
  9. private readonly Engine _engine;
  10. private readonly IteratorInstance _iterator;
  11. private readonly int _argCount;
  12. protected IteratorProtocol(
  13. Engine engine,
  14. IteratorInstance iterator,
  15. int argCount)
  16. {
  17. _engine = engine;
  18. _iterator = iterator;
  19. _argCount = argCount;
  20. }
  21. internal bool Execute()
  22. {
  23. var args = _engine._jsValueArrayPool.RentArray(_argCount);
  24. var done = false;
  25. try
  26. {
  27. while (ShouldContinue)
  28. {
  29. if (!_iterator.TryIteratorStep(out var item))
  30. {
  31. done = true;
  32. break;
  33. }
  34. var currentValue = item.Get(CommonProperties.Value);
  35. ProcessItem(args, currentValue);
  36. }
  37. }
  38. catch
  39. {
  40. IteratorClose(CompletionType.Throw);
  41. throw;
  42. }
  43. finally
  44. {
  45. _engine._jsValueArrayPool.ReturnArray(args);
  46. }
  47. IterationEnd();
  48. return done;
  49. }
  50. protected void IteratorClose(CompletionType completionType)
  51. {
  52. _iterator.Close(completionType);
  53. }
  54. protected virtual bool ShouldContinue => true;
  55. protected virtual void IterationEnd()
  56. {
  57. }
  58. protected abstract void ProcessItem(JsValue[] arguments, JsValue currentValue);
  59. internal static void AddEntriesFromIterable(ObjectInstance target, IteratorInstance iterable, object adder)
  60. {
  61. var callable = adder as ICallable;
  62. if (callable is null)
  63. {
  64. ExceptionHelper.ThrowTypeError(target.Engine.Realm, "adder must be callable");
  65. }
  66. var args = target.Engine._jsValueArrayPool.RentArray(2);
  67. var skipClose = true;
  68. try
  69. {
  70. do
  71. {
  72. if (!iterable.TryIteratorStep(out var nextItem))
  73. {
  74. return;
  75. }
  76. var temp = nextItem.Get(CommonProperties.Value);
  77. skipClose = false;
  78. var oi = temp as ObjectInstance;
  79. if (oi is null)
  80. {
  81. ExceptionHelper.ThrowTypeError(target.Engine.Realm, "iterator's value must be an object");
  82. }
  83. var k = oi.Get(JsString.NumberZeroString);
  84. var v = oi.Get(JsString.NumberOneString);
  85. args[0] = k;
  86. args[1] = v;
  87. callable.Call(target, args);
  88. } while (true);
  89. }
  90. catch
  91. {
  92. if (!skipClose)
  93. {
  94. iterable.Close(CompletionType.Throw);
  95. }
  96. throw;
  97. }
  98. finally
  99. {
  100. target.Engine._jsValueArrayPool.ReturnArray(args);
  101. }
  102. }
  103. }