mirror of
https://github.com/golang/go
synced 2024-11-20 05:24:41 -07:00
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
This commit is contained in:
parent
06479f766c
commit
74cb963225
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
// 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 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.
|
||||
//
|
||||
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
|
||||
}
|
||||
|
@ -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 {
|
||||
var m uint
|
||||
if mode&ParseComments != 0 {
|
||||
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))
|
||||
var m uint
|
||||
if mode&ParseComments != 0 {
|
||||
m = scanner.ScanComments
|
||||
}
|
||||
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
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user