drive for loops with user-defined iterators (next protocol)#203
Merged
Conversation
a struct with a next() -> T? method is now iterable: for x in it calls
next() each iteration, binding x to the yielded value and stopping when
next() returns none.
struct Counter:
cur: Int
hi: Int
impl Counter:
fn next() -> Int?:
if self.cur >= self.hi:
return none
v := self.cur
self.cur = self.cur + 1
return v
for x in Counter(0, 5): # 0 1 2 3 4
break/continue and the optional value, index binding work; existing list,
string, map, set and range loops are unchanged. this is the consumption
half of the iterator protocol — lazy range/map/filter adapters build on it.
checker: iterator_element_type derives the loop variable's type from the
iterator's next() return. ir emitter: ir_emit_for_iterator_stmt drives the
loop via next(), reading the is_some flag and value out of the optional.
the iterator detection reads a module-global map; it's isolated in a small
helper because the same read inside the larger check_for_statement returned
stale results (a codegen sensitivity in the self-hosted compiler).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
summary
a struct with a
next() -> T?method is now iterable.for x in it:callsnext()each iteration, bindsxto the yielded value, and stops whennext()returns
none:break/continueand the optionalvalue, indexbinding work (the index isthe 0-based position). existing list / string / map / set / range loops are
unchanged.
this is the consumption half of the iterator protocol. it builds on struct
field assignment (#202) for the mutable cursor, and the lazy range / map /
filter adapters land on top of it next.
how
iterator_element_typederives the loop variable's type from thestruct's
next()return (the optional's inner type);check_for_statementfalls back to it for non-collection iterables.
ir_emit_for_iterator_stmtdrives the loop by callingnext(), branching on the optional'sis_someflag (field 0) and reading thevalue (field 8), reusing the existing break/continue label scaffolding.
what was tested
tests/cases/test_for_iterator.pith: Int iterator sum,break/continue,
value, indexbinding, and a String-element iterator(83 each), and bootstrap fixed point — all 0 failures
design note
the iterator detection reads a module-global map. The same read inlined into
the larger
check_for_statementreturned stale results — a codegen sensitivityin the self-hosted compiler with module-global access in big functions — so it
lives in a small dedicated helper, which compiles correctly.