diff options
Diffstat (limited to 'gcc-4.8/libgo/go/go/parser')
-rw-r--r-- | gcc-4.8/libgo/go/go/parser/error_test.go | 5 | ||||
-rw-r--r-- | gcc-4.8/libgo/go/go/parser/interface.go | 82 | ||||
-rw-r--r-- | gcc-4.8/libgo/go/go/parser/parser.go | 85 | ||||
-rw-r--r-- | gcc-4.8/libgo/go/go/parser/parser_test.go | 13 | ||||
-rw-r--r-- | gcc-4.8/libgo/go/go/parser/short_test.go | 3 |
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) { |