aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.8/libgo/go/go/parser
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.8/libgo/go/go/parser')
-rw-r--r--gcc-4.8/libgo/go/go/parser/error_test.go5
-rw-r--r--gcc-4.8/libgo/go/go/parser/interface.go82
-rw-r--r--gcc-4.8/libgo/go/go/parser/parser.go85
-rw-r--r--gcc-4.8/libgo/go/go/parser/parser_test.go13
-rw-r--r--gcc-4.8/libgo/go/go/parser/short_test.go3
5 files changed, 131 insertions, 57 deletions
diff --git a/gcc-4.8/libgo/go/go/parser/error_test.go b/gcc-4.8/libgo/go/go/parser/error_test.go
index 8d06d1c84..d4d4f909d 100644
--- a/gcc-4.8/libgo/go/go/parser/error_test.go
+++ b/gcc-4.8/libgo/go/go/parser/error_test.go
@@ -89,8 +89,6 @@ func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]str
prev = pos
}
}
-
- panic("unreachable")
}
// compareErrors compares the map of expected error messages with the list
@@ -139,12 +137,13 @@ func checkErrors(t *testing.T, filename string, input interface{}) {
return
}
- _, err = ParseFile(fsetErrs, filename, src, DeclarationErrors)
+ _, err = ParseFile(fsetErrs, filename, src, DeclarationErrors|AllErrors)
found, ok := err.(scanner.ErrorList)
if err != nil && !ok {
t.Error(err)
return
}
+ found.RemoveMultiples()
// we are expecting the following errors
// (collect these after parsing a file so that it is found in the file set)
diff --git a/gcc-4.8/libgo/go/go/parser/interface.go b/gcc-4.8/libgo/go/go/parser/interface.go
index fac513e55..149257ca6 100644
--- a/gcc-4.8/libgo/go/go/parser/interface.go
+++ b/gcc-4.8/libgo/go/go/parser/interface.go
@@ -52,12 +52,13 @@ func readSource(filename string, src interface{}) ([]byte, error) {
type Mode uint
const (
- PackageClauseOnly Mode = 1 << iota // parsing stops after package clause
- ImportsOnly // parsing stops after import declarations
- ParseComments // parse comments and add them to AST
- Trace // print a trace of parsed productions
- DeclarationErrors // report declaration errors
- SpuriousErrors // report all (not just the first) errors per line
+ PackageClauseOnly Mode = 1 << iota // stop parsing after package clause
+ ImportsOnly // stop parsing after import declarations
+ ParseComments // parse comments and add them to AST
+ Trace // print a trace of parsed productions
+ DeclarationErrors // report declaration errors
+ SpuriousErrors // same as AllErrors, for backward-compatibility
+ AllErrors = SpuriousErrors // report all errors (not just the first 10 on different lines)
)
// ParseFile parses the source code of a single Go source file and returns
@@ -79,35 +80,39 @@ const (
// representing the fragments of erroneous source code). Multiple errors
// are returned via a scanner.ErrorList which is sorted by file position.
//
-func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) (*ast.File, error) {
+func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) (f *ast.File, err error) {
// get source
text, err := readSource(filename, src)
if err != nil {
return nil, err
}
- // parse source
var p parser
- p.init(fset, filename, text, mode)
- f := p.parseFile()
- if f == nil {
- // source is not a valid Go source file - satisfy
- // ParseFile API and return a valid (but) empty
- // *ast.File
- f = &ast.File{
- Name: new(ast.Ident),
- Scope: ast.NewScope(nil),
+ defer func() {
+ if e := recover(); e != nil {
+ _ = e.(bailout) // re-panics if it's not a bailout
+ }
+
+ // set result values
+ if f == nil {
+ // source is not a valid Go source file - satisfy
+ // ParseFile API and return a valid (but) empty
+ // *ast.File
+ f = &ast.File{
+ Name: new(ast.Ident),
+ Scope: ast.NewScope(nil),
+ }
}
- }
- // sort errors
- if p.mode&SpuriousErrors == 0 {
- p.errors.RemoveMultiples()
- } else {
p.errors.Sort()
- }
+ err = p.errors.Err()
+ }()
+
+ // parse source
+ p.init(fset, filename, text, mode)
+ f = p.parseFile()
- return f, p.errors.Err()
+ return
}
// ParseDir calls ParseFile for the files in the directory specified by path and
@@ -157,16 +162,27 @@ func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, m
}
// ParseExpr is a convenience function for obtaining the AST of an expression x.
-// The position information recorded in the AST is undefined.
+// The position information recorded in the AST is undefined. The filename used
+// in error messages is the empty string.
//
func ParseExpr(x string) (ast.Expr, error) {
- // parse x within the context of a complete package for correct scopes;
- // use //line directive for correct positions in error messages and put
- // x alone on a separate line (handles line comments), followed by a ';'
- // to force an error if the expression is incomplete
- file, err := ParseFile(token.NewFileSet(), "", "package p;func _(){_=\n//line :1\n"+x+"\n;}", 0)
- if err != nil {
- return nil, err
+ var p parser
+ p.init(token.NewFileSet(), "", []byte(x), 0)
+
+ // Set up pkg-level scopes to avoid nil-pointer errors.
+ // This is not needed for a correct expression x as the
+ // parser will be ok with a nil topScope, but be cautious
+ // in case of an erroneous x.
+ p.openScope()
+ p.pkgScope = p.topScope
+ e := p.parseRhsOrType()
+ p.closeScope()
+ assert(p.topScope == nil, "unbalanced scopes")
+
+ if p.errors.Len() > 0 {
+ p.errors.Sort()
+ return nil, p.errors.Err()
}
- return file.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.AssignStmt).Rhs[0], nil
+
+ return e, nil
}
diff --git a/gcc-4.8/libgo/go/go/parser/parser.go b/gcc-4.8/libgo/go/go/parser/parser.go
index 959af3872..f4a690a6f 100644
--- a/gcc-4.8/libgo/go/go/parser/parser.go
+++ b/gcc-4.8/libgo/go/go/parser/parser.go
@@ -48,7 +48,8 @@ type parser struct {
syncCnt int // number of calls to syncXXX without progress
// Non-syntactic parser control
- exprLev int // < 0: in control clause, >= 0: in expression
+ exprLev int // < 0: in control clause, >= 0: in expression
+ inRhs bool // if set, the parser is parsing a rhs expression
// Ordinary identifier scopes
pkgScope *ast.Scope // pkgScope.Outer == nil
@@ -340,8 +341,26 @@ func (p *parser) next() {
}
}
+// A bailout panic is raised to indicate early termination.
+type bailout struct{}
+
func (p *parser) error(pos token.Pos, msg string) {
- p.errors.Add(p.file.Position(pos), msg)
+ epos := p.file.Position(pos)
+
+ // If AllErrors is not set, discard errors reported on the same line
+ // as the last recorded error and stop parsing if there are more than
+ // 10 errors.
+ if p.mode&AllErrors == 0 {
+ n := len(p.errors)
+ if n > 0 && p.errors[n-1].Pos.Line == epos.Line {
+ return // discard - likely a spurious error
+ }
+ if n > 10 {
+ panic(bailout{})
+ }
+ }
+
+ p.errors.Add(epos, msg)
}
func (p *parser) errorExpected(pos token.Pos, msg string) {
@@ -521,6 +540,8 @@ func (p *parser) parseExprList(lhs bool) (list []ast.Expr) {
}
func (p *parser) parseLhsList() []ast.Expr {
+ old := p.inRhs
+ p.inRhs = false
list := p.parseExprList(true)
switch p.tok {
case token.DEFINE:
@@ -542,11 +563,16 @@ func (p *parser) parseLhsList() []ast.Expr {
p.resolve(x)
}
}
+ p.inRhs = old
return list
}
func (p *parser) parseRhsList() []ast.Expr {
- return p.parseExprList(false)
+ old := p.inRhs
+ p.inRhs = true
+ list := p.parseExprList(false)
+ p.inRhs = old
+ return list
}
// ----------------------------------------------------------------------------
@@ -1211,11 +1237,11 @@ func (p *parser) parseElement(keyOk bool) ast.Expr {
// In the former case we are done, and in the latter case we don't
// care because the type checker will do a separate field lookup.
//
- // If the key does not resolve, it must a) be defined at the top-
- // level in another file of the same package or be undeclared, or
- // b) it is a struct field. In the former case, the type checker
- // can do a top-level lookup, and in the latter case it will do a
- // separate field lookup.
+ // If the key does not resolve, it a) must be defined at the top
+ // level in another file of the same package, the universe scope, or be
+ // undeclared; or b) it is a struct field. In the former case, the type
+ // checker can do a top-level lookup, and in the latter case it will do
+ // a separate field lookup.
x := p.checkExpr(p.parseExpr(keyOk))
if keyOk {
if p.tok == token.COLON {
@@ -1487,6 +1513,14 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
return p.parsePrimaryExpr(lhs)
}
+func (p *parser) tokPrec() (token.Token, int) {
+ tok := p.tok
+ if p.inRhs && tok == token.ASSIGN {
+ tok = token.EQL
+ }
+ return tok, tok.Precedence()
+}
+
// If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
if p.trace {
@@ -1494,10 +1528,13 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
}
x := p.parseUnaryExpr(lhs)
- for prec := p.tok.Precedence(); prec >= prec1; prec-- {
- for p.tok.Precedence() == prec {
- pos, op := p.pos, p.tok
- p.next()
+ for _, prec := p.tokPrec(); prec >= prec1; prec-- {
+ for {
+ op, oprec := p.tokPrec()
+ if oprec != prec {
+ break
+ }
+ pos := p.expect(op)
if lhs {
p.resolve(x)
lhs = false
@@ -1523,11 +1560,19 @@ func (p *parser) parseExpr(lhs bool) ast.Expr {
}
func (p *parser) parseRhs() ast.Expr {
- return p.checkExpr(p.parseExpr(false))
+ old := p.inRhs
+ p.inRhs = true
+ x := p.checkExpr(p.parseExpr(false))
+ p.inRhs = old
+ return x
}
func (p *parser) parseRhsOrType() ast.Expr {
- return p.checkExprOrType(p.parseExpr(false))
+ old := p.inRhs
+ p.inRhs = true
+ x := p.checkExprOrType(p.parseExpr(false))
+ p.inRhs = old
+ return x
}
// ----------------------------------------------------------------------------
@@ -2073,7 +2118,7 @@ func (p *parser) parseStmt() (s ast.Stmt) {
// ----------------------------------------------------------------------------
// Declarations
-type parseSpecFunction func(p *parser, doc *ast.CommentGroup, keyword token.Token, iota int) ast.Spec
+type parseSpecFunction func(doc *ast.CommentGroup, keyword token.Token, iota int) ast.Spec
func isValidImport(lit string) bool {
const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
@@ -2192,12 +2237,12 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
lparen = p.pos
p.next()
for iota := 0; p.tok != token.RPAREN && p.tok != token.EOF; iota++ {
- list = append(list, f(p, p.leadComment, keyword, iota))
+ list = append(list, f(p.leadComment, keyword, iota))
}
rparen = p.expect(token.RPAREN)
p.expectSemi()
} else {
- list = append(list, f(p, nil, keyword, 0))
+ list = append(list, f(nil, keyword, 0))
}
return &ast.GenDecl{
@@ -2298,10 +2343,10 @@ func (p *parser) parseDecl(sync func(*parser)) ast.Decl {
var f parseSpecFunction
switch p.tok {
case token.CONST, token.VAR:
- f = (*parser).parseValueSpec
+ f = p.parseValueSpec
case token.TYPE:
- f = (*parser).parseTypeSpec
+ f = p.parseTypeSpec
case token.FUNC:
return p.parseFuncDecl()
@@ -2353,7 +2398,7 @@ func (p *parser) parseFile() *ast.File {
if p.mode&PackageClauseOnly == 0 {
// import decls
for p.tok == token.IMPORT {
- decls = append(decls, p.parseGenDecl(token.IMPORT, (*parser).parseImportSpec))
+ decls = append(decls, p.parseGenDecl(token.IMPORT, p.parseImportSpec))
}
if p.mode&ImportsOnly == 0 {
diff --git a/gcc-4.8/libgo/go/go/parser/parser_test.go b/gcc-4.8/libgo/go/go/parser/parser_test.go
index 1960377b0..48813d106 100644
--- a/gcc-4.8/libgo/go/go/parser/parser_test.go
+++ b/gcc-4.8/libgo/go/go/parser/parser_test.go
@@ -68,7 +68,7 @@ func TestParseDir(t *testing.T) {
func TestParseExpr(t *testing.T) {
// just kicking the tires:
- // a valid expression
+ // a valid arithmetic expression
src := "a + b"
x, err := ParseExpr(src)
if err != nil {
@@ -79,6 +79,17 @@ func TestParseExpr(t *testing.T) {
t.Errorf("ParseExpr(%s): got %T, expected *ast.BinaryExpr", src, x)
}
+ // a valid type expression
+ src = "struct{x *int}"
+ x, err = ParseExpr(src)
+ if err != nil {
+ t.Fatalf("ParseExpr(%s): %v", src, err)
+ }
+ // sanity check
+ if _, ok := x.(*ast.StructType); !ok {
+ t.Errorf("ParseExpr(%s): got %T, expected *ast.StructType", src, x)
+ }
+
// an invalid expression
src = "a + *"
_, err = ParseExpr(src)
diff --git a/gcc-4.8/libgo/go/go/parser/short_test.go b/gcc-4.8/libgo/go/go/parser/short_test.go
index c62f7e050..62277c0d2 100644
--- a/gcc-4.8/libgo/go/go/parser/short_test.go
+++ b/gcc-4.8/libgo/go/go/parser/short_test.go
@@ -71,6 +71,9 @@ var invalids = []string{
`package p; func f() { _ = (<-<- /* ERROR "expected 'chan'" */ chan int)(nil) };`,
`package p; func f() { _ = (<-chan<-chan<-chan<-chan<-chan<- /* ERROR "expected channel type" */ int)(nil) };`,
`package p; func f() { var t []int; t /* ERROR "expected identifier on left side of :=" */ [0] := 0 };`,
+ `package p; func f() { if x := g(); x = /* ERROR "expected '=='" */ 0 {}};`,
+ `package p; func f() { _ = x = /* ERROR "expected '=='" */ 0 {}};`,
+ `package p; func f() { _ = 1 == func()int { var x bool; x = x = /* ERROR "expected '=='" */ true; return x }() };`,
}
func TestInvalid(t *testing.T) {