Summary
PR #579 added an FExecuting: Boolean re-entrancy guard to all 8 iterator helper classes (concat, map, filter, take, drop, flatMap, zip, zipKeyed) per ES2026 §27.1.2.1.1. The guard is currently duplicated across 8 field declarations and 16 AdvanceNext/DirectNext methods — identical check + set + try-finally in every one.
Problem
Adding a new iterator helper requires remembering to copy the pattern. Missing it produces a SIGSEGV on re-entrant .next() (the bug #514 demonstrated).
Proposed fix
Introduce TGocciaIteratorHelperValue as an intermediate class between TGocciaIteratorValue and all 8 helper classes:
TGocciaIteratorValue
└── TGocciaIteratorHelperValue (new: owns FExecuting, BeginExecuting/EndExecuting)
├── TGocciaConcatIteratorValue
├── TGocciaLazyMapIteratorValue
├── TGocciaLazyFilterIteratorValue
├── TGocciaLazyTakeIteratorValue
├── TGocciaLazyDropIteratorValue
├── TGocciaLazyFlatMapIteratorValue
├── TGocciaZipIteratorValue
└── TGocciaZipKeyedIteratorValue
The base class would own FExecuting and provide a protected BeginExecuting (check + set + throw) and EndExecuting (clear). Each subclass still needs the try-finally to call EndExecuting, but the field, the check, the throw, and the error message reference live in one place.
Non-helper iterators (array, string, map-entry, set-entry, generator, generic) are unaffected — they continue inheriting directly from TGocciaIteratorValue.
Scope
source/units/Goccia.Values.IteratorValue.pas — declare the new class
source/units/Goccia.Values.Iterator.Concat.pas
source/units/Goccia.Values.Iterator.Lazy.pas (5 classes)
source/units/Goccia.Values.Iterator.Zip.pas (2 classes)
No JS-visible behavior change. Existing re-entrancy tests in tests/built-ins/Iterator/iterator-helper-reentrant.js serve as the verification suite.
Related
Summary
PR #579 added an
FExecuting: Booleanre-entrancy guard to all 8 iterator helper classes (concat, map, filter, take, drop, flatMap, zip, zipKeyed) per ES2026 §27.1.2.1.1. The guard is currently duplicated across 8 field declarations and 16AdvanceNext/DirectNextmethods — identical check + set + try-finally in every one.Problem
Adding a new iterator helper requires remembering to copy the pattern. Missing it produces a SIGSEGV on re-entrant
.next()(the bug #514 demonstrated).Proposed fix
Introduce
TGocciaIteratorHelperValueas an intermediate class betweenTGocciaIteratorValueand all 8 helper classes:The base class would own
FExecutingand provide a protectedBeginExecuting(check + set + throw) andEndExecuting(clear). Each subclass still needs the try-finally to callEndExecuting, but the field, the check, the throw, and the error message reference live in one place.Non-helper iterators (array, string, map-entry, set-entry, generator, generic) are unaffected — they continue inheriting directly from
TGocciaIteratorValue.Scope
source/units/Goccia.Values.IteratorValue.pas— declare the new classsource/units/Goccia.Values.Iterator.Concat.passource/units/Goccia.Values.Iterator.Lazy.pas(5 classes)source/units/Goccia.Values.Iterator.Zip.pas(2 classes)No JS-visible behavior change. Existing re-entrancy tests in
tests/built-ins/Iterator/iterator-helper-reentrant.jsserve as the verification suite.Related