Commit fa497796 authored by Robert Griesemer's avatar Robert Griesemer

go/parser: report illegal label declarations at ':' rather than guessing the start

Also:
- Add parser.SpuriousError flag. If set, the parser reports all (including
  spurious) errors rather then at most one error per line.
- Add -e flag to gofmt and gotype: If set, gofmt and gotype report all
  (including spurious) errors rather than at most one error per line.
- Updated the respective documentation.

Fixes #2088.

R=rsc
CC=golang-dev
https://golang.org/cl/4803047
parent 3d552700
...@@ -14,11 +14,12 @@ Usage: ...@@ -14,11 +14,12 @@ Usage:
gofmt [flags] [path ...] gofmt [flags] [path ...]
The flags are: The flags are:
-d -d
Do not print reformatted sources to standard output. Do not print reformatted sources to standard output.
If a file's formatting is different than gofmt's, print diffs If a file's formatting is different than gofmt's, print diffs
to standard output. to standard output.
-e
Print all (including spurious) errors.
-l -l
Do not print reformatted sources to standard output. Do not print reformatted sources to standard output.
If a file's formatting is different from gofmt's, print its name If a file's formatting is different from gofmt's, print its name
...@@ -31,6 +32,8 @@ The flags are: ...@@ -31,6 +32,8 @@ The flags are:
Do not print reformatted sources to standard output. Do not print reformatted sources to standard output.
If a file's formatting is different from gofmt's, overwrite it If a file's formatting is different from gofmt's, overwrite it
with gofmt's version. with gofmt's version.
Formatting control flags:
-comments=true -comments=true
Print comments; if false, all comments are elided from the output. Print comments; if false, all comments are elided from the output.
-spaces -spaces
...@@ -40,6 +43,7 @@ The flags are: ...@@ -40,6 +43,7 @@ The flags are:
-tabwidth=8 -tabwidth=8
Tab width in spaces. Tab width in spaces.
The rewrite rule specified with the -r flag must be a string of the form: The rewrite rule specified with the -r flag must be a string of the form:
pattern -> replacement pattern -> replacement
......
...@@ -29,6 +29,7 @@ var ( ...@@ -29,6 +29,7 @@ var (
rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')") rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')")
simplifyAST = flag.Bool("s", false, "simplify code") simplifyAST = flag.Bool("s", false, "simplify code")
doDiff = flag.Bool("d", false, "display diffs instead of rewriting files") doDiff = flag.Bool("d", false, "display diffs instead of rewriting files")
allErrors = flag.Bool("e", false, "print all (including spurious) errors")
// layout control // layout control
comments = flag.Bool("comments", true, "print comments") comments = flag.Bool("comments", true, "print comments")
...@@ -64,6 +65,9 @@ func initParserMode() { ...@@ -64,6 +65,9 @@ func initParserMode() {
if *comments { if *comments {
parserMode |= parser.ParseComments parserMode |= parser.ParseComments
} }
if *allErrors {
parserMode |= parser.SpuriousErrors
}
} }
func initPrinterMode() { func initPrinterMode() {
......
...@@ -24,18 +24,20 @@ Usage: ...@@ -24,18 +24,20 @@ Usage:
gotype [flags] [path ...] gotype [flags] [path ...]
The flags are: The flags are:
-e
Print all (including spurious) errors.
-p pkgName -p pkgName
process only those files in package pkgName. Process only those files in package pkgName.
-r -r
recursively process subdirectories. Recursively process subdirectories.
-v -v
verbose mode. Verbose mode.
Debugging flags: Debugging flags:
-trace
print parse trace (disables concurrent parsing).
-ast -ast
print AST (disables concurrent parsing). Print AST (disables concurrent parsing).
-trace
Print parse trace (disables concurrent parsing).
Examples Examples
......
...@@ -23,6 +23,7 @@ var ( ...@@ -23,6 +23,7 @@ var (
pkgName = flag.String("p", "", "process only those files in package pkgName") pkgName = flag.String("p", "", "process only those files in package pkgName")
recursive = flag.Bool("r", false, "recursively process subdirectories") recursive = flag.Bool("r", false, "recursively process subdirectories")
verbose = flag.Bool("v", false, "verbose mode") verbose = flag.Bool("v", false, "verbose mode")
allErrors = flag.Bool("e", false, "print all (including spurious) errors")
// debugging support // debugging support
printTrace = flag.Bool("trace", false, "print parse trace") printTrace = flag.Bool("trace", false, "print parse trace")
...@@ -68,6 +69,9 @@ func parse(fset *token.FileSet, filename string, src []byte) *ast.File { ...@@ -68,6 +69,9 @@ func parse(fset *token.FileSet, filename string, src []byte) *ast.File {
// parse entire file // parse entire file
mode := parser.DeclarationErrors mode := parser.DeclarationErrors
if *allErrors {
mode |= parser.SpuriousErrors
}
if *printTrace { if *printTrace {
mode |= parser.Trace mode |= parser.Trace
} }
......
...@@ -48,9 +48,12 @@ func readSource(filename string, src interface{}) ([]byte, os.Error) { ...@@ -48,9 +48,12 @@ func readSource(filename string, src interface{}) ([]byte, os.Error) {
return ioutil.ReadFile(filename) return ioutil.ReadFile(filename)
} }
func (p *parser) parseEOF() os.Error { func (p *parser) errors() os.Error {
p.expect(token.EOF) mode := scanner.Sorted
return p.GetError(scanner.Sorted) if p.mode&SpuriousErrors == 0 {
mode = scanner.NoMultiples
}
return p.GetError(mode)
} }
// ParseExpr parses a Go expression and returns the corresponding // ParseExpr parses a Go expression and returns the corresponding
...@@ -70,7 +73,9 @@ func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr, ...@@ -70,7 +73,9 @@ func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr,
if p.tok == token.SEMICOLON { if p.tok == token.SEMICOLON {
p.next() // consume automatically inserted semicolon, if any p.next() // consume automatically inserted semicolon, if any
} }
return x, p.parseEOF() p.expect(token.EOF)
return x, p.errors()
} }
// ParseStmtList parses a list of Go statements and returns the list // ParseStmtList parses a list of Go statements and returns the list
...@@ -86,7 +91,10 @@ func ParseStmtList(fset *token.FileSet, filename string, src interface{}) ([]ast ...@@ -86,7 +91,10 @@ func ParseStmtList(fset *token.FileSet, filename string, src interface{}) ([]ast
var p parser var p parser
p.init(fset, filename, data, 0) p.init(fset, filename, data, 0)
return p.parseStmtList(), p.parseEOF() list := p.parseStmtList()
p.expect(token.EOF)
return list, p.errors()
} }
// ParseDeclList parses a list of Go declarations and returns the list // ParseDeclList parses a list of Go declarations and returns the list
...@@ -102,7 +110,10 @@ func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast ...@@ -102,7 +110,10 @@ func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast
var p parser var p parser
p.init(fset, filename, data, 0) p.init(fset, filename, data, 0)
return p.parseDeclList(), p.parseEOF() list := p.parseDeclList()
p.expect(token.EOF)
return list, p.errors()
} }
// ParseFile parses the source code of a single Go source file and returns // ParseFile parses the source code of a single Go source file and returns
...@@ -133,7 +144,9 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode uint) ...@@ -133,7 +144,9 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode uint)
var p parser var p parser
p.init(fset, filename, data, mode) p.init(fset, filename, data, mode)
return p.parseFile(), p.GetError(scanner.NoMultiples) // parseFile() reads to EOF file := p.parseFile() // parseFile reads to EOF
return file, p.errors()
} }
// ParseFiles calls ParseFile for each file in the filenames list and returns // ParseFiles calls ParseFile for each file in the filenames list and returns
......
...@@ -26,6 +26,7 @@ const ( ...@@ -26,6 +26,7 @@ const (
ParseComments // parse comments and add them to AST ParseComments // parse comments and add them to AST
Trace // print a trace of parsed productions Trace // print a trace of parsed productions
DeclarationErrors // report declaration errors DeclarationErrors // report declaration errors
SpuriousErrors // report all (not just the first) errors per line
) )
// The parser structure holds the parser's internal state. // The parser structure holds the parser's internal state.
...@@ -1408,7 +1409,13 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt { ...@@ -1408,7 +1409,13 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
p.declare(stmt, nil, p.labelScope, ast.Lbl, label) p.declare(stmt, nil, p.labelScope, ast.Lbl, label)
return stmt return stmt
} }
p.error(x[0].Pos(), "illegal label declaration") // The label declaration typically starts at x[0].Pos(), but the label
// declaration may be erroneous due to a token after that position (and
// before the ':'). If SpuriousErrors is not set, the (only) error re-
// ported for the line is the illegal label error instead of the token
// before the ':' that caused the problem. Thus, use the (latest) colon
// position for error reporting.
p.error(colon, "illegal label declaration")
return &ast.BadStmt{x[0].Pos(), colon + 1} return &ast.BadStmt{x[0].Pos(), colon + 1}
case token.ARROW: case token.ARROW:
......
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