Commit 99aa56a4 authored by Robert Griesemer's avatar Robert Griesemer

go/parser: return partial result from ParseExpr in case of error

Remove redundant code and improve documentation in the process.

Fixes #34211.

Change-Id: I9a6d1467f1a2c98a163f41f9df147fc6500c6fad
Reviewed-on: https://go-review.googlesource.com/c/go/+/196077Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent d55cf5b8
...@@ -75,7 +75,7 @@ const ( ...@@ -75,7 +75,7 @@ const (
// indicates the specific failure. If the source was read but syntax // indicates the specific failure. If the source was read but syntax
// errors were found, the result is a partial AST (with ast.Bad* nodes // errors were found, the result is a partial AST (with ast.Bad* nodes
// representing the fragments of erroneous source code). Multiple errors // representing the fragments of erroneous source code). Multiple errors
// are returned via a scanner.ErrorList which is sorted by file position. // are returned via a scanner.ErrorList which is sorted by source position.
// //
func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) (f *ast.File, err error) { func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) (f *ast.File, err error) {
if fset == nil { if fset == nil {
...@@ -173,6 +173,12 @@ func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, m ...@@ -173,6 +173,12 @@ func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, m
// be a valid Go (type or value) expression. Specifically, fset must not // be a valid Go (type or value) expression. Specifically, fset must not
// be nil. // be nil.
// //
// If the source couldn't be read, the returned AST is nil and the error
// indicates the specific failure. If the source was read but syntax
// errors were found, the result is a partial AST (with ast.Bad* nodes
// representing the fragments of erroneous source code). Multiple errors
// are returned via a scanner.ErrorList which is sorted by source position.
//
func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode Mode) (expr ast.Expr, err error) { func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode Mode) (expr ast.Expr, err error) {
if fset == nil { if fset == nil {
panic("parser.ParseExprFrom: no token.FileSet provided (fset == nil)") panic("parser.ParseExprFrom: no token.FileSet provided (fset == nil)")
...@@ -204,7 +210,7 @@ func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode M ...@@ -204,7 +210,7 @@ func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode M
// in case of an erroneous x. // in case of an erroneous x.
p.openScope() p.openScope()
p.pkgScope = p.topScope p.pkgScope = p.topScope
e := p.parseRhsOrType() expr = p.parseRhsOrType()
p.closeScope() p.closeScope()
assert(p.topScope == nil, "unbalanced scopes") assert(p.topScope == nil, "unbalanced scopes")
...@@ -215,18 +221,17 @@ func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode M ...@@ -215,18 +221,17 @@ func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode M
} }
p.expect(token.EOF) p.expect(token.EOF)
if p.errors.Len() > 0 { return
p.errors.Sort()
return nil, p.errors.Err()
}
return e, nil
} }
// ParseExpr is a convenience function for obtaining the AST of an expression x. // ParseExpr is a convenience function for obtaining the AST of an expression x.
// The position information recorded in the AST is undefined. The filename used // The position information recorded in the AST is undefined. The filename used
// in error messages is the empty string. // in error messages is the empty string.
// //
// If syntax errors were found, the result is a partial AST (with ast.Bad* nodes
// representing the fragments of erroneous source code). Multiple errors are
// returned via a scanner.ErrorList which is sorted by source position.
//
func ParseExpr(x string) (ast.Expr, error) { func ParseExpr(x string) (ast.Expr, error) {
return ParseExprFrom(token.NewFileSet(), "", []byte(x), 0) return ParseExprFrom(token.NewFileSet(), "", []byte(x), 0)
} }
...@@ -108,9 +108,16 @@ func TestParseExpr(t *testing.T) { ...@@ -108,9 +108,16 @@ func TestParseExpr(t *testing.T) {
// an invalid expression // an invalid expression
src = "a + *" src = "a + *"
if _, err := ParseExpr(src); err == nil { x, err = ParseExpr(src)
if err == nil {
t.Errorf("ParseExpr(%q): got no error", src) t.Errorf("ParseExpr(%q): got no error", src)
} }
if x == nil {
t.Errorf("ParseExpr(%q): got no (partial) result", src)
}
if _, ok := x.(*ast.BinaryExpr); !ok {
t.Errorf("ParseExpr(%q): got %T, want *ast.BinaryExpr", src, x)
}
// a valid expression followed by extra tokens is invalid // a valid expression followed by extra tokens is invalid
src = "a[i] := x" src = "a[i] := x"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment