aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2012-01-12 16:04:48 -0800
committerRobert Griesemer <gri@golang.org>2012-01-12 16:04:48 -0800
commit74cb96322502ab686be92ce7bd07464a62afb011 (patch)
tree5f7ccc940caaa8adc6a5fc49eea7a2a0ce786366
parent06479f766c4ae16e918701839bec0776ed52ec67 (diff)
downloadgo-74cb96322502ab686be92ce7bd07464a62afb011.tar.gz
go-74cb96322502ab686be92ce7bd07464a62afb011.zip
go/parser: Remove unused Parse* functions. Simplified ParseExpr signature.
Only ParseFile, ParseDir, and ParseExpr are used in the tree. If partial parsing of code is required, it is fairly simple to wrap the relevant piece of code into a dummy package for parsing (see parser.ParseExpr). Also: minor cleanups. R=rsc CC=golang-dev https://golang.org/cl/5535055
-rw-r--r--src/cmd/cgo/gcc.go3
-rw-r--r--src/cmd/gofix/fix.go2
-rw-r--r--src/cmd/gofmt/rewrite.go2
-rw-r--r--src/pkg/go/parser/interface.go162
-rw-r--r--src/pkg/go/parser/parser.go46
-rw-r--r--src/pkg/go/parser/parser_test.go28
6 files changed, 88 insertions, 155 deletions
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 486090e90e..155eb0440f 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -344,8 +344,7 @@ func (p *Package) guessKinds(f *File) []*Name {
if _, err := strconv.Atoi(n.Define); err == nil {
ok = true
} else if n.Define[0] == '"' || n.Define[0] == '\'' {
- _, err := parser.ParseExpr(fset, "", n.Define)
- if err == nil {
+ if _, err := parser.ParseExpr(n.Define); err == nil {
ok = true
}
}
diff --git a/src/cmd/gofix/fix.go b/src/cmd/gofix/fix.go
index 5d70e9cf9c..d1a7bc8749 100644
--- a/src/cmd/gofix/fix.go
+++ b/src/cmd/gofix/fix.go
@@ -746,7 +746,7 @@ func usesImport(f *ast.File, path string) (used bool) {
}
func expr(s string) ast.Expr {
- x, err := parser.ParseExpr(fset, "", s)
+ x, err := parser.ParseExpr(s)
if err != nil {
panic("parsing " + s + ": " + err.Error())
}
diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go
index 60a4a7b49f..3c7861f0d1 100644
--- a/src/cmd/gofmt/rewrite.go
+++ b/src/cmd/gofmt/rewrite.go
@@ -36,7 +36,7 @@ func initRewrite() {
// but there are problems with preserving formatting and also
// with what a wildcard for a statement looks like.
func parseExpr(s string, what string) ast.Expr {
- x, err := parser.ParseExpr(fset, "input", s)
+ x, err := parser.ParseExpr(s)
if err != nil {
fmt.Fprintf(os.Stderr, "parsing %s %s: %s\n", what, s, err)
os.Exit(2)
diff --git a/src/pkg/go/parser/interface.go b/src/pkg/go/parser/interface.go
index be11f461c3..2ce3df8df7 100644
--- a/src/pkg/go/parser/interface.go
+++ b/src/pkg/go/parser/interface.go
@@ -10,7 +10,6 @@ import (
"bytes"
"errors"
"go/ast"
- "go/scanner"
"go/token"
"io"
"io/ioutil"
@@ -36,86 +35,28 @@ func readSource(filename string, src interface{}) ([]byte, error) {
}
case io.Reader:
var buf bytes.Buffer
- _, err := io.Copy(&buf, s)
- if err != nil {
+ if _, err := io.Copy(&buf, s); err != nil {
return nil, err
}
return buf.Bytes(), nil
- default:
- return nil, errors.New("invalid source")
}
+ return nil, errors.New("invalid source")
}
-
return ioutil.ReadFile(filename)
}
-func (p *parser) errors() error {
- mode := scanner.Sorted
- if p.mode&SpuriousErrors == 0 {
- mode = scanner.NoMultiples
- }
- return p.GetError(mode)
-}
-
-// ParseExpr parses a Go expression and returns the corresponding
-// AST node. The fset, filename, and src arguments have the same interpretation
-// as for ParseFile. If there is an error, the result expression
-// may be nil or contain a partial AST.
-//
-func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr, error) {
- data, err := readSource(filename, src)
- if err != nil {
- return nil, err
- }
-
- var p parser
- p.init(fset, filename, data, 0)
- x := p.parseRhs()
- if p.tok == token.SEMICOLON {
- p.next() // consume automatically inserted semicolon, if any
- }
- p.expect(token.EOF)
-
- return x, p.errors()
-}
-
-// ParseStmtList parses a list of Go statements and returns the list
-// of corresponding AST nodes. The fset, filename, and src arguments have the same
-// interpretation as for ParseFile. If there is an error, the node
-// list may be nil or contain partial ASTs.
+// The mode parameter to the Parse* functions is a set of flags (or 0).
+// They control the amount of source code parsed and other optional
+// parser functionality.
//
-func ParseStmtList(fset *token.FileSet, filename string, src interface{}) ([]ast.Stmt, error) {
- data, err := readSource(filename, src)
- if err != nil {
- return nil, err
- }
-
- var p parser
- p.init(fset, filename, data, 0)
- list := p.parseStmtList()
- p.expect(token.EOF)
-
- return list, p.errors()
-}
-
-// ParseDeclList parses a list of Go declarations and returns the list
-// of corresponding AST nodes. The fset, filename, and src arguments have the same
-// interpretation as for ParseFile. If there is an error, the node
-// list may be nil or contain partial ASTs.
-//
-func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast.Decl, error) {
- data, err := readSource(filename, src)
- if err != nil {
- return nil, err
- }
-
- var p parser
- p.init(fset, filename, data, 0)
- list := p.parseDeclList()
- p.expect(token.EOF)
-
- return list, p.errors()
-}
+const (
+ PackageClauseOnly uint = 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
+)
// ParseFile parses the source code of a single Go source file and returns
// the corresponding ast.File node. The source code may be provided via
@@ -124,7 +65,6 @@ func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast
// If src != nil, ParseFile parses the source from src and the filename is
// only used when recording position information. The type of the argument
// for the src parameter must be string, []byte, or io.Reader.
-//
// If src == nil, ParseFile parses the file specified by filename.
//
// The mode parameter controls the amount of source text parsed and other
@@ -133,49 +73,18 @@ func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast
//
// 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.BadX nodes
+// 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 file position.
//
func ParseFile(fset *token.FileSet, filename string, src interface{}, mode uint) (*ast.File, error) {
- data, err := readSource(filename, src)
+ text, err := readSource(filename, src)
if err != nil {
return nil, err
}
-
var p parser
- p.init(fset, filename, data, mode)
- file := p.parseFile() // parseFile reads to EOF
-
- return file, p.errors()
-}
-
-// ParseFiles calls ParseFile for each file in the filenames list and returns
-// a map of package name -> package AST with all the packages found. The mode
-// bits are passed to ParseFile unchanged. Position information is recorded
-// in the file set fset.
-//
-// Files with parse errors are ignored. In this case the map of packages may
-// be incomplete (missing packages and/or incomplete packages) and the first
-// error encountered is returned.
-//
-func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[string]*ast.Package, first error) {
- pkgs = make(map[string]*ast.Package)
- for _, filename := range filenames {
- if src, err := ParseFile(fset, filename, nil, mode); err == nil {
- name := src.Name.Name
- pkg, found := pkgs[name]
- if !found {
- // TODO(gri) Use NewPackage here; reconsider ParseFiles API.
- pkg = &ast.Package{name, nil, nil, make(map[string]*ast.File)}
- pkgs[name] = pkg
- }
- pkg.Files[filename] = src
- } else if first == nil {
- first = err
- }
- }
- return
+ p.init(fset, filename, text, mode)
+ return p.parseFile(), p.errors()
}
// ParseDir calls ParseFile for the files in the directory specified by path and
@@ -186,9 +95,9 @@ func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[st
//
// If the directory couldn't be read, a nil map and the respective error are
// returned. If a parse error occurred, a non-nil but incomplete map and the
-// error are returned.
+// first error encountered are returned.
//
-func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, mode uint) (map[string]*ast.Package, error) {
+func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, mode uint) (pkgs map[string]*ast.Package, first error) {
fd, err := os.Open(path)
if err != nil {
return nil, err
@@ -200,15 +109,36 @@ func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, m
return nil, err
}
- filenames := make([]string, len(list))
- n := 0
+ pkgs = make(map[string]*ast.Package)
for _, d := range list {
if filter == nil || filter(d) {
- filenames[n] = filepath.Join(path, d.Name())
- n++
+ filename := filepath.Join(path, d.Name())
+ if src, err := ParseFile(fset, filename, nil, mode); err == nil {
+ name := src.Name.Name
+ pkg, found := pkgs[name]
+ if !found {
+ pkg = &ast.Package{name, nil, nil, make(map[string]*ast.File)}
+ pkgs[name] = pkg
+ }
+ pkg.Files[filename] = src
+ } else if first == nil {
+ first = err
+ }
}
}
- filenames = filenames[0:n]
- return ParseFiles(fset, filenames, mode)
+ return
+}
+
+// ParseExpr is a convenience function for obtaining the AST of an expression x.
+// The position information recorded in the AST is undefined.
+//
+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
+ file, err := ParseFile(token.NewFileSet(), "", "package p;func _(){_=\n//line :1\n"+x+";}", 0)
+ if err != nil {
+ return nil, err
+ }
+ return file.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.AssignStmt).Rhs[0], nil
}
diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go
index 8467b0e4e4..d90f5775df 100644
--- a/src/pkg/go/parser/parser.go
+++ b/src/pkg/go/parser/parser.go
@@ -16,19 +16,6 @@ import (
"go/token"
)
-// The mode parameter to the Parse* functions is a set of flags (or 0).
-// They control the amount of source code parsed and other optional
-// parser functionality.
-//
-const (
- PackageClauseOnly uint = 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
-)
-
// The parser structure holds the parser's internal state.
type parser struct {
file *token.File
@@ -65,18 +52,13 @@ type parser struct {
targetStack [][]*ast.Ident // stack of unresolved labels
}
-// scannerMode returns the scanner mode bits given the parser's mode bits.
-func scannerMode(mode uint) uint {
+func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uint) {
+ p.file = fset.AddFile(filename, fset.Base(), len(src))
var m uint
if mode&ParseComments != 0 {
- m |= scanner.ScanComments
+ m = scanner.ScanComments
}
- return m
-}
-
-func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uint) {
- p.file = fset.AddFile(filename, fset.Base(), len(src))
- p.scanner.Init(p.file, src, p, scannerMode(mode))
+ p.scanner.Init(p.file, src, p, m)
p.mode = mode
p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently)
@@ -92,6 +74,14 @@ func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uin
p.openLabelScope()
}
+func (p *parser) errors() error {
+ m := scanner.Sorted
+ if p.mode&SpuriousErrors == 0 {
+ m = scanner.NoMultiples
+ }
+ return p.GetError(m)
+}
+
// ----------------------------------------------------------------------------
// Scoping support
@@ -2109,18 +2099,6 @@ func (p *parser) parseDecl() ast.Decl {
return p.parseGenDecl(p.tok, f)
}
-func (p *parser) parseDeclList() (list []ast.Decl) {
- if p.trace {
- defer un(trace(p, "DeclList"))
- }
-
- for p.tok != token.EOF {
- list = append(list, p.parseDecl())
- }
-
- return
-}
-
// ----------------------------------------------------------------------------
// Source files
diff --git a/src/pkg/go/parser/parser_test.go b/src/pkg/go/parser/parser_test.go
index f602db8896..a3ee8525de 100644
--- a/src/pkg/go/parser/parser_test.go
+++ b/src/pkg/go/parser/parser_test.go
@@ -54,7 +54,7 @@ func TestParseIllegalInputs(t *testing.T) {
}
}
-var validPrograms = []interface{}{
+var validPrograms = []string{
"package p\n",
`package p;`,
`package p; import "fmt"; func f() { fmt.Println("Hello, World!") };`,
@@ -136,6 +136,32 @@ func TestParse4(t *testing.T) {
}
}
+func TestParseExpr(t *testing.T) {
+ // just kicking the tires:
+ // a valid expression
+ src := "a + b"
+ x, err := ParseExpr(src)
+ if err != nil {
+ t.Errorf("ParseExpr(%s): %v", src, err)
+ }
+ // sanity check
+ if _, ok := x.(*ast.BinaryExpr); !ok {
+ t.Errorf("ParseExpr(%s): got %T, expected *ast.BinaryExpr", src, x)
+ }
+
+ // an invalid expression
+ src = "a + *"
+ _, err = ParseExpr(src)
+ if err == nil {
+ t.Errorf("ParseExpr(%s): %v", src, err)
+ }
+
+ // it must not crash
+ for _, src := range validPrograms {
+ ParseExpr(src)
+ }
+}
+
func TestColonEqualsScope(t *testing.T) {
f, err := ParseFile(fset, "", `package p; func f() { x, y, z := x, y, z }`, 0)
if err != nil {