Skip to content

Commit

Permalink
avoid returning errors when one-or-more groups have no matches (#390)
Browse files Browse the repository at this point in the history
  • Loading branch information
gordallott committed Feb 29, 2024
1 parent 79c6085 commit e31fb00
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 1 deletion.
27 changes: 27 additions & 0 deletions error_test.go
Expand Up @@ -45,6 +45,33 @@ func TestErrorReporting(t *testing.T) {
require.EqualError(t, err, `1:20: unexpected token ")" (expected <ident>)`)
}

func TestMoreThanOneErrors(t *testing.T) {
type unionMatchAtLeastOnce struct {
Ident string `( @Ident `
String string `| @String+ `
Float float64 `| @Float )`
}
type union struct {
Ident string `( @Ident `
String string `| @String `
Float float64 `| @Float )`
}

pAtLeastOnce := mustTestParser[unionMatchAtLeastOnce](t, participle.Unquote("String"))
p := mustTestParser[union](t, participle.Unquote("String"))

ast, err := pAtLeastOnce.ParseString("", `"a string" "two strings"`)
require.NoError(t, err)
require.Equal(t, &unionMatchAtLeastOnce{String: "a stringtwo strings"}, ast)

_, err = p.ParseString("", `102`)
require.EqualError(t, err, `1:1: unexpected token "102"`)

_, err = pAtLeastOnce.ParseString("", `102`)
// ensure we don't get a "+1:1: sub-expression <string>+ must match at least once" error
require.EqualError(t, err, `1:1: unexpected token "102"`)
}

func TestErrorWrap(t *testing.T) {
expected := errors.New("badbad")
err := participle.Wrapf(lexer.Position{Line: 1, Column: 1}, expected, "bad: %s", "thing")
Expand Down
3 changes: 2 additions & 1 deletion nodes.go
Expand Up @@ -282,7 +282,8 @@ func (g *group) Parse(ctx *parseContext, parent reflect.Value) (out []reflect.Va
if matches >= MaxIterations {
return nil, Errorf(t.Pos, "too many iterations of %s (> %d)", g, MaxIterations)
}
if matches < min {
// avoid returning errors in parent nodes if the group is optional
if matches > 0 && matches < min {
return out, Errorf(t.Pos, "sub-expression %s must match at least once", g)
}
// The idea here is that something like "a"? is a successful match and that parsing should proceed.
Expand Down

0 comments on commit e31fb00

Please sign in to comment.