mirror of
https://github.com/golang/go
synced 2024-11-25 04:47:57 -07:00
More steps towards tracking of identifier scopes.
- provide scope to parse functions; if non-nil, parser uses the scope to declare and lookup identifiers - resolve forward references where possible R=rsc CC=golang-dev https://golang.org/cl/194098
This commit is contained in:
parent
1c369bd55f
commit
f39dc9fff2
@ -60,7 +60,7 @@ type FuncType struct {
|
|||||||
|
|
||||||
func openProg(name string, p *Prog) {
|
func openProg(name string, p *Prog) {
|
||||||
var err os.Error
|
var err os.Error
|
||||||
p.AST, err = parser.ParseFile(name, nil, parser.ParseComments)
|
p.AST, err = parser.ParseFile(name, nil, nil, parser.ParseComments)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if list, ok := err.(scanner.ErrorList); ok {
|
if list, ok := err.(scanner.ErrorList); ok {
|
||||||
// If err is a scanner.ErrorList, its String will print just
|
// If err is a scanner.ErrorList, its String will print just
|
||||||
|
@ -62,7 +62,7 @@ func (p *Prog) loadDebugInfo() {
|
|||||||
for _, c := range p.Crefs {
|
for _, c := range p.Crefs {
|
||||||
// If we've already found this name as a define, it is not a Cref.
|
// If we've already found this name as a define, it is not a Cref.
|
||||||
if val, ok := defines[c.Name]; ok {
|
if val, ok := defines[c.Name]; ok {
|
||||||
_, err := parser.ParseExpr("", val)
|
_, err := parser.ParseExpr("", val, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "The value in C.%s does not parse as a Go expression; cannot use.\n", c.Name)
|
fmt.Fprintf(os.Stderr, "The value in C.%s does not parse as a Go expression; cannot use.\n", c.Name)
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
|
@ -122,7 +122,7 @@ func isPkgDir(dir *os.Dir) bool {
|
|||||||
|
|
||||||
|
|
||||||
func pkgName(filename string) string {
|
func pkgName(filename string) string {
|
||||||
file, err := parser.ParseFile(filename, nil, parser.PackageClauseOnly)
|
file, err := parser.ParseFile(filename, nil, nil, parser.PackageClauseOnly)
|
||||||
if err != nil || file == nil {
|
if err != nil || file == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@ -207,7 +207,7 @@ func newDirTree(path, name string, depth, maxDepth int) *Directory {
|
|||||||
nfiles++
|
nfiles++
|
||||||
if text == "" {
|
if text == "" {
|
||||||
// no package documentation yet; take the first found
|
// no package documentation yet; take the first found
|
||||||
file, err := parser.ParseFile(pathutil.Join(path, d.Name), nil,
|
file, err := parser.ParseFile(pathutil.Join(path, d.Name), nil, nil,
|
||||||
parser.ParseComments|parser.PackageClauseOnly)
|
parser.ParseComments|parser.PackageClauseOnly)
|
||||||
if err == nil &&
|
if err == nil &&
|
||||||
// Also accept fakePkgName, so we get synopses for commmands.
|
// Also accept fakePkgName, so we get synopses for commmands.
|
||||||
@ -845,7 +845,7 @@ func serveGoSource(c *http.Conn, r *http.Request, path string) {
|
|||||||
Error string
|
Error string
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := parser.ParseFile(path, nil, parser.ParseComments)
|
file, err := parser.ParseFile(path, nil, nil, parser.ParseComments)
|
||||||
info.Source = StyledNode{file, &Styler{linetags: true, highlight: r.FormValue("h")}}
|
info.Source = StyledNode{file, &Styler{linetags: true, highlight: r.FormValue("h")}}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
info.Error = err.String()
|
info.Error = err.String()
|
||||||
|
@ -600,7 +600,7 @@ func (x *Indexer) VisitFile(path string, d *os.Dir) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := parser.ParseFile(path, nil, parser.ParseComments)
|
file, err := parser.ParseFile(path, nil, nil, parser.ParseComments)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return // ignore files with (parse) errors
|
return // ignore files with (parse) errors
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,8 @@ var (
|
|||||||
rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')")
|
rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')")
|
||||||
|
|
||||||
// debugging support
|
// debugging support
|
||||||
checks = flag.Bool("checks", false, "do semantic checks")
|
|
||||||
comments = flag.Bool("comments", true, "print comments")
|
comments = flag.Bool("comments", true, "print comments")
|
||||||
|
debug = flag.Bool("debug", false, "print debugging information")
|
||||||
trace = flag.Bool("trace", false, "print parse trace")
|
trace = flag.Bool("trace", false, "print parse trace")
|
||||||
|
|
||||||
// layout control
|
// layout control
|
||||||
@ -64,9 +64,6 @@ func usage() {
|
|||||||
|
|
||||||
func initParserMode() {
|
func initParserMode() {
|
||||||
parserMode = uint(0)
|
parserMode = uint(0)
|
||||||
if *checks {
|
|
||||||
parserMode |= parser.CheckSemantics
|
|
||||||
}
|
|
||||||
if *comments {
|
if *comments {
|
||||||
parserMode |= parser.ParseComments
|
parserMode |= parser.ParseComments
|
||||||
}
|
}
|
||||||
@ -103,7 +100,11 @@ func processFile(f *os.File) os.Error {
|
|||||||
if *useOldParser {
|
if *useOldParser {
|
||||||
file, err = oldParser.ParseFile(f.Name(), src, parserMode)
|
file, err = oldParser.ParseFile(f.Name(), src, parserMode)
|
||||||
} else {
|
} else {
|
||||||
file, err = parser.ParseFile(f.Name(), src, parserMode)
|
var scope *ast.Scope
|
||||||
|
if *debug {
|
||||||
|
scope = ast.NewScope(nil)
|
||||||
|
}
|
||||||
|
file, err = parser.ParseFile(f.Name(), src, scope, parserMode)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -37,7 +37,7 @@ func initRewrite() {
|
|||||||
// but there are problems with preserving formatting and also
|
// but there are problems with preserving formatting and also
|
||||||
// with what a wildcard for a statement looks like.
|
// with what a wildcard for a statement looks like.
|
||||||
func parseExpr(s string, what string) ast.Expr {
|
func parseExpr(s string, what string) ast.Expr {
|
||||||
x, err := parser.ParseExpr("input", s)
|
x, err := parser.ParseExpr("input", s, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "parsing %s %s: %s\n", what, s, err)
|
fmt.Fprintf(os.Stderr, "parsing %s %s: %s\n", what, s, err)
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
|
@ -198,5 +198,5 @@ func ParsePackage(path string, filter func(*os.Dir) bool, mode uint) (*ast.Packa
|
|||||||
return nil, os.NewError(path + ": no package found")
|
return nil, os.NewError(path + ": no package found")
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ast.Package{name, path, files}, nil
|
return &ast.Package{name, path, nil, files}, nil
|
||||||
}
|
}
|
||||||
|
@ -722,5 +722,6 @@ type File struct {
|
|||||||
type Package struct {
|
type Package struct {
|
||||||
Name string // package name
|
Name string // package name
|
||||||
Path string // package path
|
Path string // package path
|
||||||
|
Scope *Scope // package scope
|
||||||
Files map[string]*File // path-relative filenames
|
Files map[string]*File // path-relative filenames
|
||||||
}
|
}
|
||||||
|
@ -26,12 +26,11 @@ type Object struct {
|
|||||||
Kind ObjKind
|
Kind ObjKind
|
||||||
Pos token.Position // declaration position
|
Pos token.Position // declaration position
|
||||||
Name string // declared name
|
Name string // declared name
|
||||||
Scope *Scope // scope in which the Object is declared
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func NewObj(kind ObjKind, pos token.Position, name string) *Object {
|
func NewObj(kind ObjKind, pos token.Position, name string) *Object {
|
||||||
return &Object{kind, pos, name, nil}
|
return &Object{kind, pos, name}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -55,16 +54,16 @@ func NewScope(outer *Scope) *Scope { return &Scope{outer, make(map[string]*Objec
|
|||||||
|
|
||||||
// Declare attempts to insert a named object into the scope s.
|
// Declare attempts to insert a named object into the scope s.
|
||||||
// If the scope does not contain an object with that name yet,
|
// If the scope does not contain an object with that name yet,
|
||||||
// Declare inserts the object, and the result is true. Otherwise,
|
// Declare inserts the object, and returns it. Otherwise, the
|
||||||
// the scope remains unchanged and the result is false.
|
// scope remains unchanged and Declare returns the object found
|
||||||
func (s *Scope) Declare(obj *Object) bool {
|
// in the scope instead.
|
||||||
if obj.Name != "_" {
|
func (s *Scope) Declare(obj *Object) *Object {
|
||||||
if _, found := s.Objects[obj.Name]; found {
|
decl, found := s.Objects[obj.Name]
|
||||||
return false
|
if !found {
|
||||||
}
|
|
||||||
s.Objects[obj.Name] = obj
|
s.Objects[obj.Name] = obj
|
||||||
|
decl = obj
|
||||||
}
|
}
|
||||||
return true
|
return decl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/scanner"
|
"go/scanner"
|
||||||
|
"go/token"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@ -50,62 +51,60 @@ func readSource(filename string, src interface{}) ([]byte, os.Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO(gri) Simplify parser interface by splitting these functions
|
func (p *parser) parseEOF() os.Error {
|
||||||
// into two parts: a single Init and a respective xParse
|
p.expect(token.EOF)
|
||||||
// function. The Init function can be shared.
|
return p.GetError(scanner.Sorted)
|
||||||
//
|
}
|
||||||
// - the Init function will take a scope
|
|
||||||
// - if a scope is provided, the parser tracks declarations, otherwise it won't
|
|
||||||
|
|
||||||
|
|
||||||
// ParseExpr parses a Go expression and returns the corresponding
|
// ParseExpr parses a Go expression and returns the corresponding
|
||||||
// AST node. The filename and src arguments have the same interpretation
|
// AST node. The filename, src, and scope arguments have the same interpretation
|
||||||
// as for ParseFile. If there is an error, the result expression
|
// as for ParseFile. If there is an error, the result expression
|
||||||
// may be nil or contain a partial AST.
|
// may be nil or contain a partial AST.
|
||||||
//
|
//
|
||||||
func ParseExpr(filename string, src interface{}) (ast.Expr, os.Error) {
|
func ParseExpr(filename string, src interface{}, scope *ast.Scope) (ast.Expr, os.Error) {
|
||||||
data, err := readSource(filename, src)
|
data, err := readSource(filename, src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var p parser
|
var p parser
|
||||||
p.init(filename, data, nil, 0)
|
p.init(filename, data, scope, 0)
|
||||||
return p.parseExpr(), p.GetError(scanner.Sorted)
|
return p.parseExpr(), p.parseEOF()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ParseStmtList parses a list of Go statements and returns the list
|
// ParseStmtList parses a list of Go statements and returns the list
|
||||||
// of corresponding AST nodes. The filename and src arguments have the same
|
// of corresponding AST nodes. The filename, src, and scope arguments have the same
|
||||||
// interpretation as for ParseFile. If there is an error, the node
|
// interpretation as for ParseFile. If there is an error, the node
|
||||||
// list may be nil or contain partial ASTs.
|
// list may be nil or contain partial ASTs.
|
||||||
//
|
//
|
||||||
func ParseStmtList(filename string, src interface{}) ([]ast.Stmt, os.Error) {
|
func ParseStmtList(filename string, src interface{}, scope *ast.Scope) ([]ast.Stmt, os.Error) {
|
||||||
data, err := readSource(filename, src)
|
data, err := readSource(filename, src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var p parser
|
var p parser
|
||||||
p.init(filename, data, nil, 0)
|
p.init(filename, data, scope, 0)
|
||||||
return p.parseStmtList(), p.GetError(scanner.Sorted)
|
return p.parseStmtList(), p.parseEOF()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ParseDeclList parses a list of Go declarations and returns the list
|
// ParseDeclList parses a list of Go declarations and returns the list
|
||||||
// of corresponding AST nodes. The filename and src arguments have the same
|
// of corresponding AST nodes. The filename, src, and scope arguments have the same
|
||||||
// interpretation as for ParseFile. If there is an error, the node
|
// interpretation as for ParseFile. If there is an error, the node
|
||||||
// list may be nil or contain partial ASTs.
|
// list may be nil or contain partial ASTs.
|
||||||
//
|
//
|
||||||
func ParseDeclList(filename string, src interface{}) ([]ast.Decl, os.Error) {
|
func ParseDeclList(filename string, src interface{}, scope *ast.Scope) ([]ast.Decl, os.Error) {
|
||||||
data, err := readSource(filename, src)
|
data, err := readSource(filename, src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var p parser
|
var p parser
|
||||||
p.init(filename, data, nil, 0)
|
p.init(filename, data, scope, 0)
|
||||||
return p.parseDeclList(), p.GetError(scanner.Sorted)
|
return p.parseDeclList(), p.parseEOF()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -118,6 +117,11 @@ func ParseDeclList(filename string, src interface{}) ([]ast.Decl, os.Error) {
|
|||||||
//
|
//
|
||||||
// If src == nil, ParseFile parses the file specified by filename.
|
// If src == nil, ParseFile parses the file specified by filename.
|
||||||
//
|
//
|
||||||
|
// If scope != nil, it is the immediately surrounding scope for the file
|
||||||
|
// (the package scope) and it is used to lookup and declare identifiers.
|
||||||
|
// When parsing multiple files belonging to a package, the same scope should
|
||||||
|
// be provided to all files.
|
||||||
|
//
|
||||||
// The mode parameter controls the amount of source text parsed and other
|
// The mode parameter controls the amount of source text parsed and other
|
||||||
// optional parser functionality.
|
// optional parser functionality.
|
||||||
//
|
//
|
||||||
@ -127,21 +131,15 @@ func ParseDeclList(filename string, src interface{}) ([]ast.Decl, os.Error) {
|
|||||||
// representing the fragments of erroneous source code). Multiple errors
|
// representing the fragments of erroneous source code). Multiple errors
|
||||||
// are returned via a scanner.ErrorList which is sorted by file position.
|
// are returned via a scanner.ErrorList which is sorted by file position.
|
||||||
//
|
//
|
||||||
func ParseFile(filename string, src interface{}, mode uint) (*ast.File, os.Error) {
|
func ParseFile(filename string, src interface{}, scope *ast.Scope, mode uint) (*ast.File, os.Error) {
|
||||||
data, err := readSource(filename, src)
|
data, err := readSource(filename, src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var p parser
|
var p parser
|
||||||
// TODO(gri) Remove CheckSemantics flag and code below once
|
|
||||||
// scope is provided via Init.
|
|
||||||
var scope *ast.Scope
|
|
||||||
if mode&CheckSemantics != 0 {
|
|
||||||
scope = ast.NewScope(nil)
|
|
||||||
}
|
|
||||||
p.init(filename, data, scope, mode)
|
p.init(filename, data, scope, mode)
|
||||||
return p.parseFile(), p.GetError(scanner.NoMultiples)
|
return p.parseFile(), p.GetError(scanner.NoMultiples) // parseFile() reads to EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -166,18 +164,19 @@ func ParseDir(path string, filter func(*os.Dir) bool, mode uint) (map[string]*as
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope := ast.NewScope(nil)
|
||||||
pkgs := make(map[string]*ast.Package)
|
pkgs := make(map[string]*ast.Package)
|
||||||
for i := 0; i < len(list); i++ {
|
for i := 0; i < len(list); i++ {
|
||||||
entry := &list[i]
|
entry := &list[i]
|
||||||
if filter == nil || filter(entry) {
|
if filter == nil || filter(entry) {
|
||||||
src, err := ParseFile(pathutil.Join(path, entry.Name), nil, mode)
|
src, err := ParseFile(pathutil.Join(path, entry.Name), nil, scope, mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return pkgs, err
|
return pkgs, err
|
||||||
}
|
}
|
||||||
name := src.Name.Name()
|
name := src.Name.Name()
|
||||||
pkg, found := pkgs[name]
|
pkg, found := pkgs[name]
|
||||||
if !found {
|
if !found {
|
||||||
pkg = &ast.Package{name, path, make(map[string]*ast.File)}
|
pkg = &ast.Package{name, path, scope, make(map[string]*ast.File)}
|
||||||
pkgs[name] = pkg
|
pkgs[name] = pkg
|
||||||
}
|
}
|
||||||
pkg.Files[entry.Name] = src
|
pkg.Files[entry.Name] = src
|
||||||
|
@ -30,7 +30,6 @@ const (
|
|||||||
PackageClauseOnly uint = 1 << iota // parsing stops after package clause
|
PackageClauseOnly uint = 1 << iota // parsing stops after package clause
|
||||||
ImportsOnly // parsing stops after import declarations
|
ImportsOnly // parsing stops after import declarations
|
||||||
ParseComments // parse comments and add them to AST
|
ParseComments // parse comments and add them to AST
|
||||||
CheckSemantics // do semantic checks (only declarations for now)
|
|
||||||
Trace // print a trace of parsed productions
|
Trace // print a trace of parsed productions
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -322,9 +321,15 @@ func (p *parser) parseIdentList(kind ast.ObjKind) []*ast.Ident {
|
|||||||
|
|
||||||
|
|
||||||
func (p *parser) declIdent(scope *ast.Scope, id *ast.Ident) {
|
func (p *parser) declIdent(scope *ast.Scope, id *ast.Ident) {
|
||||||
ok := scope.Declare(id.Obj)
|
decl := scope.Declare(id.Obj)
|
||||||
if p.checkDecl && !ok {
|
if p.checkDecl && decl != id.Obj {
|
||||||
p.Error(id.Pos(), "'"+id.Name()+"' declared already")
|
if decl.Kind == ast.Err {
|
||||||
|
// declared object is a forward declaration - update it
|
||||||
|
*decl = *id.Obj
|
||||||
|
id.Obj = decl
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.Error(id.Pos(), "'"+id.Name()+"' declared already at "+decl.Pos.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,9 +360,36 @@ func (p *parser) findIdent() *ast.Ident {
|
|||||||
p.expect(token.IDENT) // use expect() error handling
|
p.expect(token.IDENT) // use expect() error handling
|
||||||
}
|
}
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
// TODO(gri) These identifiers need to be tracked as
|
// No declaration found: either we are outside any function
|
||||||
// unresolved identifiers in the package
|
// (p.funcScope == nil) or the identifier is not declared
|
||||||
// scope so that they can be resolved later.
|
// in any function. Try the file and package scope.
|
||||||
|
obj = p.fileScope.Lookup(name) // file scope is nested in package scope
|
||||||
|
if obj == nil {
|
||||||
|
// No declaration found anywhere: track as
|
||||||
|
// unresolved identifier in the package scope.
|
||||||
|
obj = ast.NewObj(ast.Err, pos, name)
|
||||||
|
p.pkgScope.Declare(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &ast.Ident{pos, obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (p *parser) findIdentInScope(scope *ast.Scope) *ast.Ident {
|
||||||
|
pos := p.pos
|
||||||
|
name := "_"
|
||||||
|
var obj *ast.Object
|
||||||
|
if p.tok == token.IDENT {
|
||||||
|
name = string(p.lit)
|
||||||
|
obj = scope.Lookup(name)
|
||||||
|
p.next()
|
||||||
|
} else {
|
||||||
|
p.expect(token.IDENT) // use expect() error handling
|
||||||
|
}
|
||||||
|
if obj == nil {
|
||||||
|
// TODO(gri) At the moment we always arrive here because
|
||||||
|
// we don't track the lookup scope (and sometimes
|
||||||
|
// we can't). Just create a useable ident for now.
|
||||||
obj = ast.NewObj(ast.Err, pos, name)
|
obj = ast.NewObj(ast.Err, pos, name)
|
||||||
}
|
}
|
||||||
return &ast.Ident{pos, obj}
|
return &ast.Ident{pos, obj}
|
||||||
@ -421,7 +453,7 @@ func (p *parser) parseQualifiedIdent() ast.Expr {
|
|||||||
if p.tok == token.PERIOD {
|
if p.tok == token.PERIOD {
|
||||||
// first identifier is a package identifier
|
// first identifier is a package identifier
|
||||||
p.next()
|
p.next()
|
||||||
sel := p.findIdent()
|
sel := p.findIdentInScope(nil)
|
||||||
x = &ast.SelectorExpr{x, sel}
|
x = &ast.SelectorExpr{x, sel}
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
@ -970,7 +1002,7 @@ func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr {
|
|||||||
p.expect(token.PERIOD)
|
p.expect(token.PERIOD)
|
||||||
if p.tok == token.IDENT {
|
if p.tok == token.IDENT {
|
||||||
// selector
|
// selector
|
||||||
sel := p.findIdent()
|
sel := p.findIdentInScope(nil)
|
||||||
return &ast.SelectorExpr{x, sel}
|
return &ast.SelectorExpr{x, sel}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1403,7 +1435,7 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
|
|||||||
s := &ast.BranchStmt{p.pos, tok, nil}
|
s := &ast.BranchStmt{p.pos, tok, nil}
|
||||||
p.expect(tok)
|
p.expect(tok)
|
||||||
if tok != token.FALLTHROUGH && p.tok == token.IDENT {
|
if tok != token.FALLTHROUGH && p.tok == token.IDENT {
|
||||||
s.Label = p.findIdent()
|
s.Label = p.findIdentInScope(nil)
|
||||||
}
|
}
|
||||||
p.expectSemi()
|
p.expectSemi()
|
||||||
|
|
||||||
@ -1943,7 +1975,7 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.Field {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (p *parser) parseFunctionDecl() *ast.FuncDecl {
|
func (p *parser) parseFuncDecl() *ast.FuncDecl {
|
||||||
if p.trace {
|
if p.trace {
|
||||||
defer un(trace(p, "FunctionDecl"))
|
defer un(trace(p, "FunctionDecl"))
|
||||||
}
|
}
|
||||||
@ -1988,7 +2020,7 @@ func (p *parser) parseDecl() ast.Decl {
|
|||||||
f = parseVarSpec
|
f = parseVarSpec
|
||||||
|
|
||||||
case token.FUNC:
|
case token.FUNC:
|
||||||
return p.parseFunctionDecl()
|
return p.parseFuncDecl()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
pos := p.pos
|
pos := p.pos
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"go/ast"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@ -20,7 +21,7 @@ var illegalInputs = []interface{}{
|
|||||||
|
|
||||||
func TestParseIllegalInputs(t *testing.T) {
|
func TestParseIllegalInputs(t *testing.T) {
|
||||||
for _, src := range illegalInputs {
|
for _, src := range illegalInputs {
|
||||||
_, err := ParseFile("", src, 0)
|
_, err := ParseFile("", src, nil, 0)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("ParseFile(%v) should have failed", src)
|
t.Errorf("ParseFile(%v) should have failed", src)
|
||||||
}
|
}
|
||||||
@ -40,7 +41,7 @@ var validPrograms = []interface{}{
|
|||||||
|
|
||||||
func TestParseValidPrograms(t *testing.T) {
|
func TestParseValidPrograms(t *testing.T) {
|
||||||
for _, src := range validPrograms {
|
for _, src := range validPrograms {
|
||||||
_, err := ParseFile("", src, 0)
|
_, err := ParseFile("", src, ast.NewScope(nil), 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("ParseFile(%q): %v", src, err)
|
t.Errorf("ParseFile(%q): %v", src, err)
|
||||||
}
|
}
|
||||||
@ -56,7 +57,7 @@ var validFiles = []string{
|
|||||||
|
|
||||||
func TestParse3(t *testing.T) {
|
func TestParse3(t *testing.T) {
|
||||||
for _, filename := range validFiles {
|
for _, filename := range validFiles {
|
||||||
_, err := ParseFile(filename, nil, 0)
|
_, err := ParseFile(filename, nil, ast.NewScope(nil), 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("ParseFile(%s): %v", filename, err)
|
t.Errorf("ParseFile(%s): %v", filename, err)
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ func check(t *testing.T, source, golden string, mode checkMode) {
|
|||||||
if mode&oldSyntax != 0 {
|
if mode&oldSyntax != 0 {
|
||||||
prog, err = oldParser.ParseFile(source, nil, parser.ParseComments)
|
prog, err = oldParser.ParseFile(source, nil, parser.ParseComments)
|
||||||
} else {
|
} else {
|
||||||
prog, err = parser.ParseFile(source, nil, parser.ParseComments)
|
prog, err = parser.ParseFile(source, nil, nil, parser.ParseComments)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
Loading…
Reference in New Issue
Block a user