diff --git a/experimental/incremental/task.go b/experimental/incremental/task.go index 41096197..43ef01fa 100644 --- a/experimental/incremental/task.go +++ b/experimental/incremental/task.go @@ -281,26 +281,29 @@ func (t *task) run(caller Task, q *AnyQuery) (output *result) { // Check for a potential cycle. var cycle *ErrCycle - caller.path.Walk()(func(node *path) bool { - if node.Query.Key() == q.Key() { - cycle = new(ErrCycle) - - // Re-walk the list to collect the cycle itself. - caller.path.Walk()(func(node2 *path) bool { - cycle.Cycle = append(cycle.Cycle, node2.Query) - return node2 != node - }) + for node := range caller.path.Walk() { + if node.Query.Key() != q.Key() { + continue + } - // Reverse the list so that dependency arrows point to the - // right (i.e., Cycle[n] depends on Cycle[n+1]). - slices.Reverse(cycle.Cycle) + cycle = new(ErrCycle) - // Insert a copy of the current query to complete the cycle. - cycle.Cycle = append(cycle.Cycle, AsAny(q)) - return false + // Re-walk the list to collect the cycle itself. + for node2 := range caller.path.Walk() { + cycle.Cycle = append(cycle.Cycle, node2.Query) + if node2 == node { + break + } } - return true - }) + + // Reverse the list so that dependency arrows point to the + // right (i.e., Cycle[n] depends on Cycle[n+1]). + slices.Reverse(cycle.Cycle) + + // Insert a copy of the current query to complete the cycle. + cycle.Cycle = append(cycle.Cycle, AsAny(q)) + break + } if cycle != nil { output.Fatal = cycle return output diff --git a/experimental/parser/legalize_decl.go b/experimental/parser/legalize_decl.go index 29e3c94b..d7f9a325 100644 --- a/experimental/parser/legalize_decl.go +++ b/experimental/parser/legalize_decl.go @@ -61,12 +61,11 @@ func legalizeDecl(p *parser, parent classified, decl ast.DeclAny) { ), ) - seq.Values(body.Decls())(func(decl ast.DeclAny) bool { + for decl := range seq.Values(body.Decls()) { // Treat bodies as being immediately inlined, hence we pass // parent here and not body as the parent. legalizeDecl(p, parent, decl) - return true - }) + } case ast.DeclKindDef: def := decl.AsDef() @@ -77,10 +76,9 @@ func legalizeDecl(p *parser, parent classified, decl ast.DeclAny) { what := classified{def, taxa.Classify(def)} legalizeDef(p, parent, def) - seq.Values(body.Decls())(func(decl ast.DeclAny) bool { + for decl := range seq.Values(body.Decls()) { legalizeDecl(p, what, decl) - return true - }) + } } } @@ -155,7 +153,7 @@ func legalizeRange(p *parser, parent classified, decl ast.DeclRange) { } var names, tags []ast.ExprAny - seq.Values(decl.Ranges())(func(expr ast.ExprAny) bool { + for expr := range seq.Values(decl.Ranges()) { switch expr.Kind() { case ast.ExprKindPath: path := expr.AsPath() @@ -260,9 +258,7 @@ func legalizeRange(p *parser, parent classified, decl ast.DeclRange) { want: want, }) } - - return true - }) + } if len(names) > 0 && len(tags) > 0 { parentWhat := "field" diff --git a/experimental/parser/legalize_file.go b/experimental/parser/legalize_file.go index 2b5a09c8..916d96c1 100644 --- a/experimental/parser/legalize_file.go +++ b/experimental/parser/legalize_file.go @@ -37,7 +37,7 @@ func legalizeFile(p *parser, file ast.File) { pkg ast.DeclPackage imports = make(map[string][]ast.DeclImport) ) - seq.All(file.Decls())(func(i int, decl ast.DeclAny) bool { + for i, decl := range seq.All(file.Decls()) { file := classified{file, taxa.TopLevel} switch decl.Kind() { case ast.DeclKindSyntax: @@ -49,9 +49,7 @@ func legalizeFile(p *parser, file ast.File) { default: legalizeDecl(p, file, decl) } - - return true - }) + } if pkg.IsZero() { p.Warnf("missing %s", taxa.Package).Apply( @@ -135,15 +133,15 @@ func legalizeSyntax(p *parser, parent classified, idx int, first *ast.DeclSyntax } permitted := func() report.DiagnosticOption { - values := iterx.Join(iterx.FilterMap(syntax.All(), func(s syntax.Syntax) (string, bool) { + values := iterx.FilterMap(syntax.All(), func(s syntax.Syntax) (string, bool) { if s.IsEdition() != (in == taxa.Edition) { return "", false } return fmt.Sprintf("%q", s), true - }), ", ") + }) - return report.Notef("permitted values: %s", values) + return report.Notef("permitted values: %s", iterx.Join(values, ", ")) } value := syntax.Lookup(name) @@ -251,13 +249,6 @@ func legalizePackage(p *parser, parent classified, idx int, first *ast.DeclPacka // imports is a map that classifies DeclImports by the contents of their import string. // This populates it and uses it to detect duplicates. func legalizeImport(p *parser, parent classified, decl ast.DeclImport, imports map[string][]ast.DeclImport) { - in := taxa.Import - if decl.IsPublic() { - in = taxa.PublicImport - } else if decl.IsWeak() { - in = taxa.WeakImport - } - if parent.what != taxa.TopLevel { p.Error(errBadNest{parent: parent, child: decl, validParents: taxa.TopLevel.AsSet()}) return @@ -267,6 +258,7 @@ func legalizeImport(p *parser, parent classified, decl ast.DeclImport, imports m p.Error(errHasOptions{decl}) } + in := taxa.Classify(decl) expr := decl.ImportPath() switch expr.Kind() { case ast.ExprKindLiteral: diff --git a/experimental/parser/legalize_option.go b/experimental/parser/legalize_option.go index 148228f8..f8de9b7f 100644 --- a/experimental/parser/legalize_option.go +++ b/experimental/parser/legalize_option.go @@ -41,10 +41,9 @@ func legalizeCompactOptions(p *parser, opts ast.CompactOptions) { return } - seq.Values(entries)(func(opt ast.Option) bool { + for opt := range seq.Values(entries) { legalizeOptionEntry(p, opt, opt.Span()) - return true - }) + } } // legalizeCompactOptions is the common path for legalizing options, either @@ -169,10 +168,9 @@ func legalizeOptionValue(p *parser, decl report.Span, parent ast.ExprAny, value ) default: - seq.Values(array)(func(e ast.ExprAny) bool { + for e := range seq.Values(array) { legalizeOptionValue(p, decl, value, e) - return true - }) + } if parent.Kind() == ast.ExprKindField && array.Len() == 0 { p.Warnf("empty %s has no effect", taxa.Array).Apply( @@ -212,7 +210,7 @@ func legalizeOptionValue(p *parser, decl report.Span, parent ast.ExprAny, value ) } - seq.Values(value.AsDict().Elements())(func(kv ast.ExprField) bool { + for kv := range seq.Values(dict.Elements()) { want := taxa.NewSet(taxa.FieldName, taxa.ExtensionName, taxa.TypeURL) switch kv.Key().Kind() { case ast.ExprKindLiteral: @@ -299,32 +297,30 @@ func legalizeOptionValue(p *parser, decl report.Span, parent ast.ExprAny, value // information. Namely, {a []} is not allowed if a is not of message // type. Arguably, because this syntax does nothing, it should // be disallowed... - seq.Values(kv.Value().AsArray().Elements())(func(e ast.ExprAny) bool { - if e.Kind() != ast.ExprKindDict { - p.Error(errUnexpected{ - what: e, - where: taxa.Array.In(), - want: taxa.Dict.AsSet(), - }).Apply( - report.Snippetf(kv.Key(), - "because this %s is missing a %s", - taxa.DictField, taxa.Colon), - report.Notef( - "the %s can be omitted in a %s, but only if the value is a %s or a %s of them", - taxa.Colon, taxa.DictField, - taxa.Dict, taxa.Array), - ) - - return false // Only diagnose the first one. + for e := range seq.Values(kv.Value().AsArray().Elements()) { + if e.Kind() == ast.ExprKindDict { + continue } + p.Error(errUnexpected{ + what: e, + where: taxa.Array.In(), + want: taxa.Dict.AsSet(), + }).Apply( + report.Snippetf(kv.Key(), + "because this %s is missing a %s", + taxa.DictField, taxa.Colon), + report.Notef( + "the %s can be omitted in a %s, but only if the value is a %s or a %s of them", + taxa.Colon, taxa.DictField, + taxa.Dict, taxa.Array), + ) - return true - }) + break // Only diagnose the first one. + } } legalizeOptionValue(p, decl, kv.AsAny(), kv.Value()) - return true - }) + } default: p.Error(errUnexpected{ what: value, diff --git a/experimental/parser/legalize_path.go b/experimental/parser/legalize_path.go index 3ddb1d05..6af40e09 100644 --- a/experimental/parser/legalize_path.go +++ b/experimental/parser/legalize_path.go @@ -47,7 +47,7 @@ func legalizePath(p *parser, where taxa.Place, path ast.Path, opts pathOptions) var bytes, components int var slash token.Token - iterx.Enumerate(path.Components)(func(i int, pc ast.PathComponent) bool { + for i, pc := range iterx.Enumerate(path.Components) { bytes += pc.Separator().Span().Len() // Just Len() here is technically incorrect, because it could be an // extension, but MaxBytes is never used with AllowExts. @@ -59,7 +59,7 @@ func legalizePath(p *parser, where taxa.Place, path ast.Path, opts pathOptions) report.Snippetf(path, "expected a path without a leading `%s`", pc.Separator().Text()), ) ok = false - return true + continue } if pc.Separator().Keyword() == keyword.Slash { @@ -68,14 +68,14 @@ func legalizePath(p *parser, where taxa.Place, path ast.Path, opts pathOptions) report.Snippetf(pc.Separator(), "help: replace this with a %s", taxa.Dot), ) ok = false - return true + continue } else if !slash.IsZero() { p.Errorf("type URL can only contain a single %s", taxa.Slash).Apply( report.Snippet(pc.Separator()), report.Snippetf(slash, "first one is here"), ) ok = false - return true + continue } slash = pc.Separator() } @@ -87,7 +87,7 @@ func legalizePath(p *parser, where taxa.Place, path ast.Path, opts pathOptions) AllowExts: false, }) if !ok { - return true + continue } } else { p.Errorf("unexpected nested extension path %s", where).Apply( @@ -95,12 +95,10 @@ func legalizePath(p *parser, where taxa.Place, path ast.Path, opts pathOptions) report.Snippet(pc.Name()), ) ok = false - return true + continue } } - - return true - }) + } if ok { if opts.MaxBytes > 0 && bytes > opts.MaxBytes { diff --git a/experimental/parser/lex.go b/experimental/parser/lex.go index 0469f00d..bcbb8491 100644 --- a/experimental/parser/lex.go +++ b/experimental/parser/lex.go @@ -16,6 +16,7 @@ package parser import ( "math" + "slices" "strings" "unicode" "unicode/utf8" @@ -224,15 +225,15 @@ func lexPrelude(l *lexer) bool { // Check that the text of the file is actually UTF-8. var idx int var count int - stringsx.Runes(l.Text())(func(n int, r rune) bool { - if r == -1 { - if count == 0 { - idx = n - } - count++ + for i, r := range stringsx.Runes(l.Text()) { + if r != -1 { + continue } - return true - }) + if count == 0 { + idx = i + } + count++ + } frac := float64(count) / float64(len(l.Text())) switch { case frac == 0: @@ -356,9 +357,9 @@ func fuseBraces(l *lexer) { // In backwards order, generate empty tokens to fuse with // the unclosed delimiters. - for i := len(opens) - 1; i >= 0; i-- { + for _, open := range slices.Backward(opens) { empty := l.Push(0, token.Unrecognized) - token.Fuse(opens[i].In(l.Context), empty) + token.Fuse(open.In(l.Context), empty) } } @@ -384,10 +385,9 @@ func fuseStrings(l *lexer) { } var start, end token.Token - l.All()(func(tok token.Token) bool { + for tok := range l.All() { switch tok.Kind() { case token.Space, token.Comment: - break case token.String: if start.IsZero() { @@ -400,9 +400,8 @@ func fuseStrings(l *lexer) { start = token.Zero end = token.Zero } + } - return true - }) concat(start, end) } diff --git a/experimental/parser/lex_test.go b/experimental/parser/lex_test.go index 74ce5e13..06092f1a 100644 --- a/experimental/parser/lex_test.go +++ b/experimental/parser/lex_test.go @@ -23,7 +23,6 @@ import ( "github.com/bufbuild/protocompile/experimental/ast" "github.com/bufbuild/protocompile/experimental/report" - "github.com/bufbuild/protocompile/experimental/token" "github.com/bufbuild/protocompile/internal/golden" ) @@ -57,7 +56,7 @@ func TestLexer(t *testing.T) { var tsv strings.Builder var count int tsv.WriteString("#\t\tkind\t\tkeyword\t\toffsets\t\tlinecol\t\ttext\n") - ctx.Stream().All()(func(tok token.Token) bool { + for tok := range ctx.Stream().All() { count++ sp := tok.Span() @@ -88,8 +87,7 @@ func TestLexer(t *testing.T) { } tsv.WriteByte('\n') - return true - }) + } if count > 0 { outputs[0] = tsv.String() } diff --git a/experimental/parser/parse_decl.go b/experimental/parser/parse_decl.go index 142461f0..9318c852 100644 --- a/experimental/parser/parse_decl.go +++ b/experimental/parser/parse_decl.go @@ -319,7 +319,7 @@ func parseRange(p *parser, c *token.Cursor) ast.DeclRange { // to parse this as an array, instead. if !canStartOptions(c.Peek()) { var last token.Token - delimited[ast.ExprAny]{ + d := delimited[ast.ExprAny]{ p: p, c: c, what: taxa.Expr, in: in, @@ -366,10 +366,11 @@ func parseRange(p *parser, c *token.Cursor) ast.DeclRange { return false }, - }.iter(func(expr ast.ExprAny, comma token.Token) bool { + } + + for expr, comma := range d.iter { exprs = append(exprs, exprComma{expr, comma}) - return true - }) + } } options := tryParseOptions(p, c, in) diff --git a/experimental/parser/parse_delimited.go b/experimental/parser/parse_delimited.go index ad0c78ba..52708eec 100644 --- a/experimental/parser/parse_delimited.go +++ b/experimental/parser/parse_delimited.go @@ -56,10 +56,9 @@ type delimited[T report.Spanner] struct { } func (d delimited[T]) appendTo(commas ast.Commas[T]) { - d.iter(func(v T, delim token.Token) bool { - commas.AppendComma(v, delim) - return true - }) + for v, d := range d.iter { + commas.AppendComma(v, d) + } } func (d delimited[T]) iter(yield func(value T, delim token.Token) bool) { diff --git a/experimental/parser/parse_expr.go b/experimental/parser/parse_expr.go index fee5fd79..af528d31 100644 --- a/experimental/parser/parse_expr.go +++ b/experimental/parser/parse_expr.go @@ -199,7 +199,7 @@ func parseExprSolo(p *parser, c *token.Cursor, where taxa.Place) ast.ExprAny { } dict := p.NewExprDict(body) - elems.iter(func(expr ast.ExprAny, comma token.Token) bool { + for expr, comma := range elems.iter { field := expr.AsField() if field.IsZero() { p.Error(errUnexpected{ @@ -211,9 +211,8 @@ func parseExprSolo(p *parser, c *token.Cursor, where taxa.Place) ast.ExprAny { field = p.NewExprField(ast.ExprFieldArgs{Value: expr}) } - dict.AppendComma(field, comma) - return true - }) + dict.Elements().AppendComma(field, comma) + } return dict.AsAny() default: