Fix panic in parser when first token is invalid

newParser was calling p.next(), which could trigger a scanner error
that results in a panic.  Move the first p.next() into parse(p), which
correctly converts the paanic into a reportable error.

Bug: 254831383
Test: TestParserError
Change-Id: I2a427010379bb8dd5087550c7f159499cbb84066
This commit is contained in:
Colin Cross 2022-10-21 14:36:04 -07:00
parent c5e959b244
commit 31c10a12c8
2 changed files with 33 additions and 3 deletions

View file

@ -70,6 +70,7 @@ func parse(p *parser) (file *File, errs []error) {
} }
}() }()
p.next()
defs := p.parseDefinitions() defs := p.parseDefinitions()
p.accept(scanner.EOF) p.accept(scanner.EOF)
errs = p.errors errs = p.errors
@ -100,6 +101,7 @@ func Parse(filename string, r io.Reader, scope *Scope) (file *File, errs []error
func ParseExpression(r io.Reader) (value Expression, errs []error) { func ParseExpression(r io.Reader) (value Expression, errs []error) {
p := newParser(r, NewScope(nil)) p := newParser(r, NewScope(nil))
p.next()
value = p.parseExpression() value = p.parseExpression()
p.accept(scanner.EOF) p.accept(scanner.EOF)
errs = p.errors errs = p.errors
@ -124,7 +126,6 @@ func newParser(r io.Reader, scope *Scope) *parser {
} }
p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanStrings | p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanStrings |
scanner.ScanRawStrings | scanner.ScanComments scanner.ScanRawStrings | scanner.ScanComments
p.next()
return p return p
} }

View file

@ -1139,7 +1139,7 @@ var validParseTestCases = []struct {
Comments: []*Comment{ Comments: []*Comment{
&Comment{ &Comment{
Comment: []string{"/* comment3", " comment4 */"}, Comment: []string{"/* comment3", " comment4 */"},
Slash: mkpos(32, 5, 3), Slash: mkpos(32, 5, 3),
}, },
&Comment{ &Comment{
Comment: []string{"// comment5"}, Comment: []string{"// comment5"},
@ -1214,7 +1214,36 @@ func TestParseValidInput(t *testing.T) {
} }
} }
// TODO: Test error strings func TestParserError(t *testing.T) {
testcases := []struct {
name string
input string
err string
}{
{
name: "invalid first token",
input: "\x00",
err: "invalid character NUL",
},
// TODO: test more parser errors
}
for _, tt := range testcases {
t.Run(tt.name, func(t *testing.T) {
r := bytes.NewBufferString(tt.input)
_, errs := ParseAndEval("", r, NewScope(nil))
if len(errs) == 0 {
t.Fatalf("missing expected error")
}
if g, w := errs[0], tt.err; !strings.Contains(g.Error(), w) {
t.Errorf("expected error %q, got %q", w, g)
}
for _, err := range errs[1:] {
t.Errorf("got unexpected extra error %q", err)
}
})
}
}
func TestParserEndPos(t *testing.T) { func TestParserEndPos(t *testing.T) {
in := ` in := `