refactor: simplify iterator.Try and remove unnecessary backtracking

Simplify Try to save/restore the index directly instead of
copying and syncing the entire iterator. Remove the now-unused
Copy and Sync methods.

Rewrite ScanRune and ParseRawToken as peek-then-advance so they
no longer need Try at all. Remove redundant Try wrappers from
parse functions that are already disambiguated by their callers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-11 20:04:07 -05:00
parent da3da70855
commit b1fef85d60
5 changed files with 114 additions and 136 deletions

View File

@@ -8,17 +8,18 @@ import (
// ParseRawToken consumes the next token from the iterator if its type matches
// the expected type.
// Uses [iterator.Try] for automatic backtracking on failure.
// Returns an error if the iterator is exhausted or the token type does not
// match.
func ParseRawToken[T Type](i *iterator.Iterator[Token[T]], expected T) (*Token[T], error) {
return iterator.Try(i, func(i *iterator.Iterator[Token[T]]) (*Token[T], error) {
if tok, err := i.Next(); err != nil {
return nil, err
} else if tok.Type != expected {
return nil, fmt.Errorf("expected token %v, got %v'", expected.Name(), tok.Value)
} else {
return &tok, nil
}
})
tok, err := i.Get()
if err != nil {
return nil, err
}
if tok.Type != expected {
return nil, fmt.Errorf("expected token %v, got %v'", expected.Name(), tok.Value)
}
i.Forward()
return &tok, nil
}
// ParseList repeatedly applies a parse function, collecting results into a

View File

@@ -17,15 +17,15 @@ func IsVariable(r rune) bool {
// predicate.
// Returns an error if the iterator is exhausted or the rune does not match.
func ScanRune(i *iterator.Iterator[rune], expected func(rune) bool) (rune, error) {
return iterator.Try(i, func(i *iterator.Iterator[rune]) (rune, error) {
if r, err := i.Next(); err != nil {
return r, err
} else if !expected(r) {
return r, fmt.Errorf("got unexpected rune %v'", r)
} else {
return r, nil
}
})
r, err := i.Get()
if err != nil {
return r, err
}
if !expected(r) {
return r, fmt.Errorf("got unexpected rune %v'", r)
}
i.Forward()
return r, nil
}
// ScanCharacter consumes the next rune from the iterator if it matches the