Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use range-for loops in parser #465

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 20 additions & 17 deletions experimental/incremental/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 6 additions & 10 deletions experimental/parser/legalize_decl.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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
})
}
}
}

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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"
Expand Down
20 changes: 6 additions & 14 deletions experimental/parser/legalize_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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(
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down
52 changes: 24 additions & 28 deletions experimental/parser/legalize_option.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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,
Expand Down
16 changes: 7 additions & 9 deletions experimental/parser/legalize_path.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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 {
Expand All @@ -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()
}
Expand All @@ -87,20 +87,18 @@ 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(
// Use Name() here so we get the outer parens of the extension.
report.Snippet(pc.Name()),
)
ok = false
return true
continue
}
}

return true
})
}

if ok {
if opts.MaxBytes > 0 && bytes > opts.MaxBytes {
Expand Down
27 changes: 13 additions & 14 deletions experimental/parser/lex.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package parser

import (
"math"
"slices"
"strings"
"unicode"
"unicode/utf8"
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)
}
}

Expand All @@ -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() {
Expand All @@ -400,9 +400,8 @@ func fuseStrings(l *lexer) {
start = token.Zero
end = token.Zero
}
}

return true
})
concat(start, end)
}

Expand Down
6 changes: 2 additions & 4 deletions experimental/parser/lex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -88,8 +87,7 @@ func TestLexer(t *testing.T) {
}

tsv.WriteByte('\n')
return true
})
}
if count > 0 {
outputs[0] = tsv.String()
}
Expand Down
Loading
Loading