diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go index f6142d135df..2cc771e16f5 100644 --- a/src/cmd/cgo/ast.go +++ b/src/cmd/cgo/ast.go @@ -90,14 +90,14 @@ func openProg(name string, p *Prog) { ws := 0 for _, spec := range d.Specs { s, ok := spec.(*ast.ImportSpec) - if !ok || len(s.Path) != 1 || string(s.Path[0].Value) != `"C"` { + if !ok || string(s.Path.Value) != `"C"` { d.Specs[ws] = spec ws++ continue } sawC = true if s.Name != nil { - error(s.Path[0].Pos(), `cannot rename import "C"`) + error(s.Path.Pos(), `cannot rename import "C"`) } if s.Doc != nil { p.Preamble += doc.CommentText(s.Doc) + "\n" @@ -168,7 +168,6 @@ func walk(x interface{}, p *Prog, context string) { case *ast.Ident: case *ast.Ellipsis: case *ast.BasicLit: - case *ast.StringList: case *ast.FuncLit: walk(n.Type, p, "type") walk(n.Body, p, "stmt") diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go index 14aacfec68c..dcad67a95a1 100644 --- a/src/cmd/godoc/index.go +++ b/src/cmd/godoc/index.go @@ -479,9 +479,7 @@ func (x *Indexer) visitSpec(spec ast.Spec, isVarDecl bool) { case *ast.ImportSpec: x.visitComment(n.Doc) x.visitIdent(ImportDecl, n.Name) - for _, s := range n.Path { - ast.Walk(x, s) - } + ast.Walk(x, n.Path) x.visitComment(n.Comment) case *ast.ValueSpec: @@ -524,9 +522,7 @@ func (x *Indexer) Visit(node interface{}) ast.Visitor { x.visitIdent(VarDecl, m) } ast.Walk(x, n.Type) - for _, s := range n.Tag { - ast.Walk(x, s) - } + ast.Walk(x, n.Tag) x.visitComment(n.Comment) case *ast.DeclStmt: diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go index e9b1d6c47f3..4b4adba030b 100644 --- a/src/cmd/gofmt/doc.go +++ b/src/cmd/gofmt/doc.go @@ -29,14 +29,6 @@ The flags are: -tabwidth=8 tab width in spaces. -Flags to aid the transition to the new semicolon-free syntax (these flags will be -removed eventually): - - -oldparser=true - parse old syntax (required semicolons). - -oldprinter=true - print old syntax (required semicolons). - Debugging flags: -trace diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index 6997bf3e210..abd30edc89b 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -6,7 +6,6 @@ package main import ( "bytes" - oldParser "exp/parser" "flag" "fmt" "go/ast" @@ -35,9 +34,6 @@ var ( tabWidth = flag.Int("tabwidth", 8, "tab width") tabIndent = flag.Bool("tabindent", true, "indent with tabs independent of -spaces") useSpaces = flag.Bool("spaces", true, "align with spaces instead of tabs") - - // semicolon transition - useOldParser = flag.Bool("oldparser", false, "parse old syntax (required semicolons)") ) @@ -96,16 +92,12 @@ func processFile(f *os.File) os.Error { return err } - var file *ast.File - if *useOldParser { - file, err = oldParser.ParseFile(f.Name(), src, parserMode) - } else { - var scope *ast.Scope - if *debug { - scope = ast.NewScope(nil) - } - file, err = parser.ParseFile(f.Name(), src, scope, parserMode) + var scope *ast.Scope + if *debug { + scope = ast.NewScope(nil) } + file, err := parser.ParseFile(f.Name(), src, scope, parserMode) + if err != nil { return err } diff --git a/src/pkg/Makefile b/src/pkg/Makefile index 2a65d376986..7fb0240a542 100644 --- a/src/pkg/Makefile +++ b/src/pkg/Makefile @@ -64,7 +64,6 @@ DIRS=\ exp/eval\ exp/exception\ exp/iterable\ - exp/parser\ expvar\ flag\ fmt\ diff --git a/src/pkg/exp/eval/eval_test.go b/src/pkg/exp/eval/eval_test.go index 93a643b5aaa..911c7e4a52e 100644 --- a/src/pkg/exp/eval/eval_test.go +++ b/src/pkg/exp/eval/eval_test.go @@ -43,7 +43,7 @@ func runTests(t *testing.T, baseName string, tests []test) { func (a test) run(t *testing.T, name string) { w := newTestWorld() for _, j := range a { - src := j.code + src := j.code + ";" // trailing semicolon to finish statement if noisy { println("code:", src) } diff --git a/src/pkg/exp/eval/expr.go b/src/pkg/exp/eval/expr.go index ed32c0a3c6d..94714943c69 100644 --- a/src/pkg/exp/eval/expr.go +++ b/src/pkg/exp/eval/expr.go @@ -627,20 +627,6 @@ func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr { } return ei.compileStarExpr(v) - case *ast.StringList: - strings := make([]*expr, len(x.Strings)) - bad := false - for i, s := range x.Strings { - strings[i] = a.compile(s, false) - if strings[i] == nil { - bad = true - } - } - if bad { - return nil - } - return ei.compileStringList(strings) - case *ast.StructType: goto notimpl diff --git a/src/pkg/exp/eval/expr_test.go b/src/pkg/exp/eval/expr_test.go index 5cfbc823270..10c7f6be528 100644 --- a/src/pkg/exp/eval/expr_test.go +++ b/src/pkg/exp/eval/expr_test.go @@ -51,9 +51,6 @@ var exprTests = []test{ CErr("\"\\z\"", illegalEscape), CErr("\"abc", "string not terminated"), - Val("\"abc\" \"def\"", "abcdef"), - CErr("\"abc\" \"\\z\"", illegalEscape), - Val("(i)", 1), Val("ai[0]", 1), diff --git a/src/pkg/exp/eval/stmt_test.go b/src/pkg/exp/eval/stmt_test.go index 1600a750781..a14a288d936 100644 --- a/src/pkg/exp/eval/stmt_test.go +++ b/src/pkg/exp/eval/stmt_test.go @@ -202,8 +202,8 @@ var stmtTests = []test{ Run("fn1 := func() int { L: goto L; i = 2 }"), Run("fn1 := func() int { return 1; L: goto L }"), // Scope checking - Run("fn1 := func() { { L: x:=1 } goto L }"), - CErr("fn1 := func() { { x:=1; L: } goto L }", "into scope"), + Run("fn1 := func() { { L: x:=1 }; goto L }"), + CErr("fn1 := func() { { x:=1; L: }; goto L }", "into scope"), CErr("fn1 := func() { goto L; x:=1; L: }", "into scope"), Run("fn1 := func() { goto L; { L: x:=1 } }"), CErr("fn1 := func() { goto L; { x:=1; L: } }", "into scope"), @@ -279,10 +279,10 @@ var stmtTests = []test{ // Scoping Val2("for i := 2; true; { i2 = i; i := 3; break }", "i", 1, "i2", 2), // Labeled break/continue - Val1("L1: for { L2: for { i+=2; break L1; i+=4 } i+=8 }", "i", 1+2), - Val1("L1: for { L2: for { i+=2; break L2; i+=4 } i+=8; break; i+=16 }", "i", 1+2+8), + Val1("L1: for { L2: for { i+=2; break L1; i+=4 }; i+=8 }", "i", 1+2), + Val1("L1: for { L2: for { i+=2; break L2; i+=4 }; i+=8; break; i+=16 }", "i", 1+2+8), CErr("L1: { for { break L1 } }", "break.*not defined"), - CErr("L1: for {} for { break L1 }", "break.*not defined"), + CErr("L1: for {}; for { break L1 }", "break.*not defined"), CErr("L1:; for { break L1 }", "break.*not defined"), Val2("L1: for i = 0; i < 2; i++ { L2: for { i2++; continue L1; i2++ } }", "i", 2, "i2", 4), CErr("L1: { for { continue L1 } }", "continue.*not defined"), @@ -294,7 +294,7 @@ var stmtTests = []test{ CErr("fn1 := func() int{ for {break} }", "return"), Run("fn1 := func() int{ for { for {break} } }"), CErr("fn1 := func() int{ L1: for { for {break L1} } }", "return"), - Run("fn1 := func() int{ for true {} return 1 }"), + Run("fn1 := func() int{ for true {}; return 1 }"), // Selectors Val1("var x struct { a int; b int }; x.a = 42; i = x.a", "i", 42), @@ -305,7 +305,7 @@ var stmtTests = []test{ CErr("type T struct { x int }; type U struct { x int }; var y struct { T; U }; y.x = 42", "ambiguous.*\tT\\.x\n\tU\\.x"), CErr("type T struct { *T }; var x T; x.foo", "no field"), - Val1("fib := func(int) int{return 0;}; fib = func(v int) int { if v < 2 { return 1 } return fib(v-1)+fib(v-2) }; i = fib(20)", "i", 10946), + Val1("fib := func(int) int{return 0;}; fib = func(v int) int { if v < 2 { return 1 }; return fib(v-1)+fib(v-2) }; i = fib(20)", "i", 10946), // Make slice Val2("x := make([]int, 2); x[0] = 42; i, i2 = x[0], x[1]", "i", 42, "i2", 0), @@ -335,7 +335,7 @@ var stmtTests = []test{ RErr("x := make(map[int] int); i = x[1]", "key '1' not found"), // Functions - Val2("func fib(n int) int { if n <= 2 { return n } return fib(n-1) + fib(n-2) }", "fib(4)", 5, "fib(10)", 89), + Val2("func fib(n int) int { if n <= 2 { return n }; return fib(n-1) + fib(n-2) }", "fib(4)", 5, "fib(10)", 89), Run("func f1(){}"), Run2("func f1(){}", "f1()"), } diff --git a/src/pkg/exp/eval/world.go b/src/pkg/exp/eval/world.go index c36081b263f..1d19b50b627 100644 --- a/src/pkg/exp/eval/world.go +++ b/src/pkg/exp/eval/world.go @@ -9,7 +9,7 @@ package eval import ( "go/ast" - parser "exp/parser" + "go/parser" "go/scanner" "go/token" "os" @@ -136,13 +136,13 @@ func (e *exprCode) Run() (Value, os.Error) { } func (w *World) Compile(text string) (Code, os.Error) { - stmts, err := parser.ParseStmtList("input", text) + stmts, err := parser.ParseStmtList("input", text, nil) if err == nil { return w.CompileStmtList(stmts) } // Otherwise try as DeclList. - decls, err1 := parser.ParseDeclList("input", text) + decls, err1 := parser.ParseDeclList("input", text, nil) if err1 == nil { return w.CompileDeclList(decls) } diff --git a/src/pkg/exp/parser/Makefile b/src/pkg/exp/parser/Makefile deleted file mode 100644 index da359175857..00000000000 --- a/src/pkg/exp/parser/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ../../../Make.$(GOARCH) - -TARG=exp/parser -GOFILES=\ - interface.go\ - parser.go\ - -include ../../../Make.pkg diff --git a/src/pkg/exp/parser/interface.go b/src/pkg/exp/parser/interface.go deleted file mode 100644 index e04ff188871..00000000000 --- a/src/pkg/exp/parser/interface.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file contains the exported entry points for invoking the parser. - -package oldParser - -import ( - "bytes" - "fmt" - "go/ast" - "go/scanner" - "io" - "io/ioutil" - "os" - pathutil "path" - "strings" -) - - -// If src != nil, readSource converts src to a []byte if possible; -// otherwise it returns an error. If src == nil, readSource returns -// the result of reading the file specified by filename. -// -func readSource(filename string, src interface{}) ([]byte, os.Error) { - if src != nil { - switch s := src.(type) { - case string: - return strings.Bytes(s), nil - case []byte: - return s, nil - case *bytes.Buffer: - // is io.Reader, but src is already available in []byte form - if s != nil { - return s.Bytes(), nil - } - case io.Reader: - var buf bytes.Buffer - _, err := io.Copy(&buf, s) - if err != nil { - return nil, err - } - return buf.Bytes(), nil - default: - return nil, os.ErrorString("invalid source") - } - } - - return ioutil.ReadFile(filename) -} - - -// ParseExpr parses a Go expression and returns the corresponding -// AST node. The 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(filename string, src interface{}) (ast.Expr, os.Error) { - data, err := readSource(filename, src) - if err != nil { - return nil, err - } - - var p parser - p.init(filename, data, 0) - return p.parseExpr(), p.GetError(scanner.Sorted) -} - - -// ParseStmtList parses a list of Go statements and returns the list -// of corresponding AST nodes. The 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(filename string, src interface{}) ([]ast.Stmt, os.Error) { - data, err := readSource(filename, src) - if err != nil { - return nil, err - } - - var p parser - p.init(filename, data, 0) - return p.parseStmtList(), p.GetError(scanner.Sorted) -} - - -// ParseDeclList parses a list of Go declarations and returns the list -// of corresponding AST nodes. The 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(filename string, src interface{}) ([]ast.Decl, os.Error) { - data, err := readSource(filename, src) - if err != nil { - return nil, err - } - - var p parser - p.init(filename, data, 0) - return p.parseDeclList(), p.GetError(scanner.Sorted) -} - - -// ParseFile parses a Go source file and returns a File node. -// -// If src != nil, ParseFile parses the file source from src. src may -// be provided in a variety of formats. At the moment the following types -// are supported: string, []byte, and io.Reader. In this case, filename is -// only used for source position information and error messages. -// -// If src == nil, ParseFile parses the file specified by filename. -// -// The mode parameter controls the amount of source text parsed and other -// optional parser functionality. -// -// 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 -// representing the fragments of erroneous source code). Multiple errors -// are returned via a scanner.ErrorList which is sorted by file position. -// -func ParseFile(filename string, src interface{}, mode uint) (*ast.File, os.Error) { - data, err := readSource(filename, src) - if err != nil { - return nil, err - } - - var p parser - p.init(filename, data, mode) - return p.parseFile(), p.GetError(scanner.NoMultiples) -} - - -// ParsePkgFile parses the file specified by filename and returns the -// corresponding AST. If the file cannot be read, has syntax errors, or -// does not belong to the package (i.e., pkgname != "" and the package -// name in the file doesn't match pkkname), an error is returned. -// -func ParsePkgFile(pkgname, filename string, mode uint) (*ast.File, os.Error) { - src, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - - if pkgname != "" { - prog, err := ParseFile(filename, src, PackageClauseOnly) - if err != nil { - return nil, err - } - if prog.Name.Name() != pkgname { - return nil, os.NewError(fmt.Sprintf("multiple packages found: %s, %s", prog.Name.Name(), pkgname)) - } - if mode == PackageClauseOnly { - return prog, nil - } - } - - return ParseFile(filename, src, mode) -} - - -// ParsePackage parses all files in the directory specified by path and -// returns an AST representing the package found. The set of files may be -// restricted by providing a non-nil filter function; only the files with -// os.Dir entries passing through the filter are considered. -// If ParsePackage does not find exactly one package, it returns an error. -// -func ParsePackage(path string, filter func(*os.Dir) bool, mode uint) (*ast.Package, os.Error) { - fd, err := os.Open(path, os.O_RDONLY, 0) - if err != nil { - return nil, err - } - defer fd.Close() - - list, err := fd.Readdir(-1) - if err != nil { - return nil, err - } - - name := "" - files := make(map[string]*ast.File) - for i := 0; i < len(list); i++ { - entry := &list[i] - if filter == nil || filter(entry) { - filename := pathutil.Join(path, entry.Name) - src, err := ParsePkgFile(name, filename, mode) - if err != nil { - return nil, err - } - files[filename] = src - if name == "" { - name = src.Name.Name() - } - } - } - - if len(files) == 0 { - return nil, os.NewError(path + ": no package found") - } - - return &ast.Package{name, nil, files}, nil -} diff --git a/src/pkg/exp/parser/parser.go b/src/pkg/exp/parser/parser.go deleted file mode 100644 index 6114c88953c..00000000000 --- a/src/pkg/exp/parser/parser.go +++ /dev/null @@ -1,1972 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// A parser for "old" Go source files using the old semicolon syntax. -// Input may be provided in a variety of forms (see the various Parse* -// functions); the output is an abstract syntax tree (AST) representing -// the Go source. The oldParser is invoked through one of the Parse* -// functions. -// -// NOTE: This package is deprecated and will be removed once all Go code -// has been converted to using the new syntax and after a reasonable -// grace period. -// -package oldParser - -import ( - "container/vector" - "fmt" - "go/ast" - "go/scanner" - "go/token" -) - - -// noPos is used when there is no corresponding source position for a token. -var noPos token.Position - - -// 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 -) - - -// The parser structure holds the parser's internal state. -type parser struct { - scanner.ErrorVector - scanner scanner.Scanner - - // Tracing/debugging - mode uint // parsing mode - trace bool // == (mode & Trace != 0) - indent uint // indentation used for tracing output - - // Comments - comments *ast.CommentGroup // list of collected comments - lastComment *ast.CommentGroup // last comment in the comments list - leadComment *ast.CommentGroup // the last lead comment - lineComment *ast.CommentGroup // the last line comment - - // Next token - pos token.Position // token position - tok token.Token // one token look-ahead - lit []byte // token literal - - // Non-syntactic parser control - optSemi bool // true if semicolon separator is optional in statement list - exprLev int // < 0: in control clause, >= 0: in expression - - // Scopes - pkgScope *ast.Scope - fileScope *ast.Scope - topScope *ast.Scope -} - - -// scannerMode returns the scanner mode bits given the parser's mode bits. -func scannerMode(mode uint) uint { - if mode&ParseComments != 0 { - return scanner.ScanComments - } - return 0 -} - - -func (p *parser) init(filename string, src []byte, mode uint) { - p.scanner.Init(filename, src, p, scannerMode(mode)) - p.mode = mode - p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently) - p.next() -} - - -// ---------------------------------------------------------------------------- -// Parsing support - -func (p *parser) printTrace(a ...interface{}) { - const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " + - ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " - const n = uint(len(dots)) - fmt.Printf("%5d:%3d: ", p.pos.Line, p.pos.Column) - i := 2 * p.indent - for ; i > n; i -= n { - fmt.Print(dots) - } - fmt.Print(dots[0:i]) - fmt.Println(a) -} - - -func trace(p *parser, msg string) *parser { - p.printTrace(msg, "(") - p.indent++ - return p -} - - -// Usage pattern: defer un(trace(p, "...")); -func un(p *parser) { - p.indent-- - p.printTrace(")") -} - - -// Advance to the next token. -func (p *parser) next0() { - // Because of one-token look-ahead, print the previous token - // when tracing as it provides a more readable output. The - // very first token (p.pos.Line == 0) is not initialized (it - // is token.ILLEGAL), so don't print it . - if p.trace && p.pos.Line > 0 { - s := p.tok.String() - switch { - case p.tok.IsLiteral(): - p.printTrace(s, string(p.lit)) - case p.tok.IsOperator(), p.tok.IsKeyword(): - p.printTrace("\"" + s + "\"") - default: - p.printTrace(s) - } - } - - p.pos, p.tok, p.lit = p.scanner.Scan() - p.optSemi = false -} - - -// Consume a comment and return it and the line on which it ends. -func (p *parser) consumeComment() (comment *ast.Comment, endline int) { - // /*-style comments may end on a different line than where they start. - // Scan the comment for '\n' chars and adjust endline accordingly. - endline = p.pos.Line - if p.lit[1] == '*' { - for _, b := range p.lit { - if b == '\n' { - endline++ - } - } - } - - comment = &ast.Comment{p.pos, p.lit} - p.next0() - - return -} - - -// Consume a group of adjacent comments, add it to the parser's -// comments list, and return the line of which the last comment -// in the group ends. An empty line or non-comment token terminates -// a comment group. -// -func (p *parser) consumeCommentGroup() int { - list := new(vector.Vector) - endline := p.pos.Line - for p.tok == token.COMMENT && endline+1 >= p.pos.Line { - var comment *ast.Comment - comment, endline = p.consumeComment() - list.Push(comment) - } - - // convert list - group := make([]*ast.Comment, list.Len()) - for i := 0; i < list.Len(); i++ { - group[i] = list.At(i).(*ast.Comment) - } - - // add comment group to the comments list - g := &ast.CommentGroup{group, nil} - if p.lastComment != nil { - p.lastComment.Next = g - } else { - p.comments = g - } - p.lastComment = g - - return endline -} - - -// Advance to the next non-comment token. In the process, collect -// any comment groups encountered, and remember the last lead and -// and line comments. -// -// A lead comment is a comment group that starts and ends in a -// line without any other tokens and that is followed by a non-comment -// token on the line immediately after the comment group. -// -// A line comment is a comment group that follows a non-comment -// token on the same line, and that has no tokens after it on the line -// where it ends. -// -// Lead and line comments may be considered documentation that is -// stored in the AST. -// -func (p *parser) next() { - p.leadComment = nil - p.lineComment = nil - line := p.pos.Line // current line - p.next0() - - if p.tok == token.COMMENT { - if p.pos.Line == line { - // The comment is on same line as previous token; it - // cannot be a lead comment but may be a line comment. - endline := p.consumeCommentGroup() - if p.pos.Line != endline { - // The next token is on a different line, thus - // the last comment group is a line comment. - p.lineComment = p.lastComment - } - } - - // consume successor comments, if any - endline := -1 - for p.tok == token.COMMENT { - endline = p.consumeCommentGroup() - } - - if endline >= 0 && endline+1 == p.pos.Line { - // The next token is following on the line immediately after the - // comment group, thus the last comment group is a lead comment. - p.leadComment = p.lastComment - } - } -} - - -func (p *parser) errorExpected(pos token.Position, msg string) { - msg = "expected " + msg - if pos.Offset == p.pos.Offset { - // the error happened at the current position; - // make the error message more specific - msg += ", found '" + p.tok.String() + "'" - if p.tok.IsLiteral() { - msg += " " + string(p.lit) - } - } - p.Error(pos, msg) -} - - -func (p *parser) expect(tok token.Token) token.Position { - pos := p.pos - if p.tok != tok { - p.errorExpected(pos, "'"+tok.String()+"'") - } - p.next() // make progress in any case - return pos -} - - -// ---------------------------------------------------------------------------- -// Common productions - -func (p *parser) parseIdent() *ast.Ident { - obj := ast.NewObj(ast.Err, p.pos, "") - if p.tok == token.IDENT { - obj.Name = string(p.lit) - p.next() - } else { - p.expect(token.IDENT) // use expect() error handling - } - return &ast.Ident{obj.Pos, obj} -} - - -func (p *parser) parseIdentList() []*ast.Ident { - if p.trace { - defer un(trace(p, "IdentList")) - } - - list := new(vector.Vector) - list.Push(p.parseIdent()) - for p.tok == token.COMMA { - p.next() - list.Push(p.parseIdent()) - } - - // convert vector - idents := make([]*ast.Ident, list.Len()) - for i := 0; i < list.Len(); i++ { - idents[i] = list.At(i).(*ast.Ident) - } - - return idents -} - - -func (p *parser) parseExprList() []ast.Expr { - if p.trace { - defer un(trace(p, "ExpressionList")) - } - - list := new(vector.Vector) - list.Push(p.parseExpr()) - for p.tok == token.COMMA { - p.next() - list.Push(p.parseExpr()) - } - - // convert list - exprs := make([]ast.Expr, list.Len()) - for i := 0; i < list.Len(); i++ { - exprs[i] = list.At(i).(ast.Expr) - } - - return exprs -} - - -// ---------------------------------------------------------------------------- -// Types - -func (p *parser) parseType() ast.Expr { - if p.trace { - defer un(trace(p, "Type")) - } - - typ := p.tryType() - - if typ == nil { - p.errorExpected(p.pos, "type") - p.next() // make progress - return &ast.BadExpr{p.pos} - } - - return typ -} - - -func (p *parser) parseQualifiedIdent() ast.Expr { - if p.trace { - defer un(trace(p, "QualifiedIdent")) - } - - var x ast.Expr = p.parseIdent() - if p.tok == token.PERIOD { - // first identifier is a package identifier - p.next() - sel := p.parseIdent() - x = &ast.SelectorExpr{x, sel} - } - return x -} - - -func (p *parser) parseTypeName() ast.Expr { - if p.trace { - defer un(trace(p, "TypeName")) - } - - return p.parseQualifiedIdent() -} - - -func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr { - if p.trace { - defer un(trace(p, "ArrayType")) - } - - lbrack := p.expect(token.LBRACK) - var len ast.Expr - if ellipsisOk && p.tok == token.ELLIPSIS { - len = &ast.Ellipsis{p.pos, nil} - p.next() - } else if p.tok != token.RBRACK { - len = p.parseExpr() - } - p.expect(token.RBRACK) - elt := p.parseType() - - return &ast.ArrayType{lbrack, len, elt} -} - - -func (p *parser) makeIdentList(list *vector.Vector) []*ast.Ident { - idents := make([]*ast.Ident, list.Len()) - for i := 0; i < list.Len(); i++ { - ident, isIdent := list.At(i).(*ast.Ident) - if !isIdent { - pos := list.At(i).(ast.Expr).Pos() - p.errorExpected(pos, "identifier") - idents[i] = &ast.Ident{pos, ast.NewObj(ast.Err, pos, "")} - } - idents[i] = ident - } - return idents -} - - -func (p *parser) parseFieldDecl() *ast.Field { - if p.trace { - defer un(trace(p, "FieldDecl")) - } - - doc := p.leadComment - - // a list of identifiers looks like a list of type names - list := new(vector.Vector) - for { - // TODO(gri): do not allow ()'s here - list.Push(p.parseType()) - if p.tok == token.COMMA { - p.next() - } else { - break - } - } - - // if we had a list of identifiers, it must be followed by a type - typ := p.tryType() - - // optional tag - var tag []*ast.BasicLit - if p.tok == token.STRING { - tag = p.parseStringList(nil) - } - - // analyze case - var idents []*ast.Ident - if typ != nil { - // IdentifierList Type - idents = p.makeIdentList(list) - } else { - // Type (anonymous field) - if list.Len() == 1 { - // TODO(gri): check that this looks like a type - typ = list.At(0).(ast.Expr) - } else { - p.errorExpected(p.pos, "anonymous field") - typ = &ast.BadExpr{p.pos} - } - } - - return &ast.Field{doc, idents, typ, tag, nil} -} - - -func (p *parser) parseStructType() *ast.StructType { - if p.trace { - defer un(trace(p, "StructType")) - } - - pos := p.expect(token.STRUCT) - lbrace := p.expect(token.LBRACE) - list := new(vector.Vector) - for p.tok == token.IDENT || p.tok == token.MUL { - f := p.parseFieldDecl() - if p.tok != token.RBRACE { - p.expect(token.SEMICOLON) - } - f.Comment = p.lineComment - list.Push(f) - } - rbrace := p.expect(token.RBRACE) - p.optSemi = true - - // convert vector - fields := make([]*ast.Field, list.Len()) - for i := list.Len() - 1; i >= 0; i-- { - fields[i] = list.At(i).(*ast.Field) - } - - return &ast.StructType{pos, lbrace, fields, rbrace, false} -} - - -func (p *parser) parsePointerType() *ast.StarExpr { - if p.trace { - defer un(trace(p, "PointerType")) - } - - star := p.expect(token.MUL) - base := p.parseType() - - return &ast.StarExpr{star, base} -} - - -func (p *parser) tryParameterType(ellipsisOk bool) ast.Expr { - if ellipsisOk && p.tok == token.ELLIPSIS { - pos := p.pos - p.next() - typ := p.tryType() - if p.tok != token.RPAREN { - p.Error(pos, "can use '...' for last parameter only") - } - return &ast.Ellipsis{pos, typ} - } - return p.tryType() -} - - -func (p *parser) parseParameterType(ellipsisOk bool) ast.Expr { - typ := p.tryParameterType(ellipsisOk) - if typ == nil { - p.errorExpected(p.pos, "type") - p.next() // make progress - typ = &ast.BadExpr{p.pos} - } - return typ -} - - -func (p *parser) parseParameterDecl(ellipsisOk bool) (*vector.Vector, ast.Expr) { - if p.trace { - defer un(trace(p, "ParameterDecl")) - } - - // a list of identifiers looks like a list of type names - list := new(vector.Vector) - for { - // TODO(gri): do not allow ()'s here - list.Push(p.parseParameterType(ellipsisOk)) - if p.tok == token.COMMA { - p.next() - } else { - break - } - } - - // if we had a list of identifiers, it must be followed by a type - typ := p.tryParameterType(ellipsisOk) - - return list, typ -} - - -func (p *parser) parseParameterList(ellipsisOk bool) []*ast.Field { - if p.trace { - defer un(trace(p, "ParameterList")) - } - - list, typ := p.parseParameterDecl(ellipsisOk) - if typ != nil { - // IdentifierList Type - idents := p.makeIdentList(list) - list.Resize(0, 0) - list.Push(&ast.Field{nil, idents, typ, nil, nil}) - - for p.tok == token.COMMA { - p.next() - idents := p.parseIdentList() - typ := p.parseParameterType(ellipsisOk) - list.Push(&ast.Field{nil, idents, typ, nil, nil}) - } - - } else { - // Type { "," Type } (anonymous parameters) - // convert list of types into list of *Param - for i := 0; i < list.Len(); i++ { - list.Set(i, &ast.Field{Type: list.At(i).(ast.Expr)}) - } - } - - // convert list - params := make([]*ast.Field, list.Len()) - for i := 0; i < list.Len(); i++ { - params[i] = list.At(i).(*ast.Field) - } - - return params -} - - -func (p *parser) parseParameters(ellipsisOk bool) []*ast.Field { - if p.trace { - defer un(trace(p, "Parameters")) - } - - var params []*ast.Field - p.expect(token.LPAREN) - if p.tok != token.RPAREN { - params = p.parseParameterList(ellipsisOk) - } - p.expect(token.RPAREN) - - return params -} - - -func (p *parser) parseResult() []*ast.Field { - if p.trace { - defer un(trace(p, "Result")) - } - - var results []*ast.Field - if p.tok == token.LPAREN { - results = p.parseParameters(false) - } else if p.tok != token.FUNC { - typ := p.tryType() - if typ != nil { - results = make([]*ast.Field, 1) - results[0] = &ast.Field{Type: typ} - } - } - - return results -} - - -func (p *parser) parseSignature() (params []*ast.Field, results []*ast.Field) { - if p.trace { - defer un(trace(p, "Signature")) - } - - params = p.parseParameters(true) - results = p.parseResult() - - return -} - - -func (p *parser) parseFuncType() *ast.FuncType { - if p.trace { - defer un(trace(p, "FuncType")) - } - - pos := p.expect(token.FUNC) - params, results := p.parseSignature() - - return &ast.FuncType{pos, params, results} -} - - -func (p *parser) parseMethodSpec() *ast.Field { - if p.trace { - defer un(trace(p, "MethodSpec")) - } - - doc := p.leadComment - var idents []*ast.Ident - var typ ast.Expr - x := p.parseQualifiedIdent() - if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN { - // method - idents = []*ast.Ident{ident} - params, results := p.parseSignature() - typ = &ast.FuncType{noPos, params, results} - } else { - // embedded interface - typ = x - } - - return &ast.Field{doc, idents, typ, nil, nil} -} - - -func (p *parser) parseInterfaceType() *ast.InterfaceType { - if p.trace { - defer un(trace(p, "InterfaceType")) - } - - pos := p.expect(token.INTERFACE) - lbrace := p.expect(token.LBRACE) - list := new(vector.Vector) - for p.tok == token.IDENT { - m := p.parseMethodSpec() - if p.tok != token.RBRACE { - p.expect(token.SEMICOLON) - } - m.Comment = p.lineComment - list.Push(m) - } - rbrace := p.expect(token.RBRACE) - p.optSemi = true - - // convert vector - methods := make([]*ast.Field, list.Len()) - for i := list.Len() - 1; i >= 0; i-- { - methods[i] = list.At(i).(*ast.Field) - } - - return &ast.InterfaceType{pos, lbrace, methods, rbrace, false} -} - - -func (p *parser) parseMapType() *ast.MapType { - if p.trace { - defer un(trace(p, "MapType")) - } - - pos := p.expect(token.MAP) - p.expect(token.LBRACK) - key := p.parseType() - p.expect(token.RBRACK) - value := p.parseType() - - return &ast.MapType{pos, key, value} -} - - -func (p *parser) parseChanType() *ast.ChanType { - if p.trace { - defer un(trace(p, "ChanType")) - } - - pos := p.pos - dir := ast.SEND | ast.RECV - if p.tok == token.CHAN { - p.next() - if p.tok == token.ARROW { - p.next() - dir = ast.SEND - } - } else { - p.expect(token.ARROW) - p.expect(token.CHAN) - dir = ast.RECV - } - value := p.parseType() - - return &ast.ChanType{pos, dir, value} -} - - -func (p *parser) tryRawType(ellipsisOk bool) ast.Expr { - switch p.tok { - case token.IDENT: - return p.parseTypeName() - case token.LBRACK: - return p.parseArrayType(ellipsisOk) - case token.STRUCT: - return p.parseStructType() - case token.MUL: - return p.parsePointerType() - case token.FUNC: - return p.parseFuncType() - case token.INTERFACE: - return p.parseInterfaceType() - case token.MAP: - return p.parseMapType() - case token.CHAN, token.ARROW: - return p.parseChanType() - case token.LPAREN: - lparen := p.pos - p.next() - typ := p.parseType() - rparen := p.expect(token.RPAREN) - return &ast.ParenExpr{lparen, typ, rparen} - } - - // no type found - return nil -} - - -func (p *parser) tryType() ast.Expr { return p.tryRawType(false) } - - -// ---------------------------------------------------------------------------- -// Blocks - -func makeStmtList(list *vector.Vector) []ast.Stmt { - stats := make([]ast.Stmt, list.Len()) - for i := 0; i < list.Len(); i++ { - stats[i] = list.At(i).(ast.Stmt) - } - return stats -} - - -func (p *parser) parseStmtList() []ast.Stmt { - if p.trace { - defer un(trace(p, "StatementList")) - } - - list := new(vector.Vector) - expectSemi := false - for p.tok != token.CASE && p.tok != token.DEFAULT && p.tok != token.RBRACE && p.tok != token.EOF { - if expectSemi { - p.expect(token.SEMICOLON) - expectSemi = false - } - list.Push(p.parseStmt()) - if p.tok == token.SEMICOLON { - p.next() - } else if p.optSemi { - p.optSemi = false // "consume" optional semicolon - } else { - expectSemi = true - } - } - - return makeStmtList(list) -} - - -func (p *parser) parseBlockStmt(idents []*ast.Ident) *ast.BlockStmt { - if p.trace { - defer un(trace(p, "BlockStmt")) - } - - lbrace := p.expect(token.LBRACE) - list := p.parseStmtList() - rbrace := p.expect(token.RBRACE) - p.optSemi = true - - return &ast.BlockStmt{lbrace, list, rbrace} -} - - -// ---------------------------------------------------------------------------- -// Expressions - -func (p *parser) parseStringList(x *ast.BasicLit) []*ast.BasicLit { - if p.trace { - defer un(trace(p, "StringList")) - } - - list := new(vector.Vector) - if x != nil { - list.Push(x) - } - - for p.tok == token.STRING { - list.Push(&ast.BasicLit{p.pos, token.STRING, p.lit}) - p.next() - } - - // convert list - strings := make([]*ast.BasicLit, list.Len()) - for i := 0; i < list.Len(); i++ { - strings[i] = list.At(i).(*ast.BasicLit) - } - - return strings -} - - -func (p *parser) parseFuncTypeOrLit() ast.Expr { - if p.trace { - defer un(trace(p, "FuncTypeOrLit")) - } - - typ := p.parseFuncType() - if p.tok != token.LBRACE { - // function type only - return typ - } - - p.exprLev++ - body := p.parseBlockStmt(nil) - p.optSemi = false // function body requires separating ";" - p.exprLev-- - - return &ast.FuncLit{typ, body} -} - - -// parseOperand may return an expression or a raw type (incl. array -// types of the form [...]T. Callers must verify the result. -// -func (p *parser) parseOperand() ast.Expr { - if p.trace { - defer un(trace(p, "Operand")) - } - - switch p.tok { - case token.IDENT: - return p.parseIdent() - - case token.INT, token.FLOAT, token.CHAR, token.STRING: - x := &ast.BasicLit{p.pos, p.tok, p.lit} - p.next() - if p.tok == token.STRING && p.tok == token.STRING { - return &ast.StringList{p.parseStringList(x)} - } - return x - - case token.LPAREN: - lparen := p.pos - p.next() - p.exprLev++ - x := p.parseExpr() - p.exprLev-- - rparen := p.expect(token.RPAREN) - return &ast.ParenExpr{lparen, x, rparen} - - case token.FUNC: - return p.parseFuncTypeOrLit() - - default: - t := p.tryRawType(true) // could be type for composite literal or conversion - if t != nil { - return t - } - } - - p.errorExpected(p.pos, "operand") - p.next() // make progress - return &ast.BadExpr{p.pos} -} - - -func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr { - if p.trace { - defer un(trace(p, "SelectorOrTypeAssertion")) - } - - p.expect(token.PERIOD) - if p.tok == token.IDENT { - // selector - sel := p.parseIdent() - return &ast.SelectorExpr{x, sel} - } - - // type assertion - p.expect(token.LPAREN) - var typ ast.Expr - if p.tok == token.TYPE { - // type switch: typ == nil - p.next() - } else { - typ = p.parseType() - } - p.expect(token.RPAREN) - - return &ast.TypeAssertExpr{x, typ} -} - - -func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr { - if p.trace { - defer un(trace(p, "IndexOrSlice")) - } - - p.expect(token.LBRACK) - p.exprLev++ - index := p.parseExpr() - if p.tok == token.COLON { - p.next() - var end ast.Expr - if p.tok != token.RBRACK { - end = p.parseExpr() - } - x = &ast.SliceExpr{x, index, end} - } else { - x = &ast.IndexExpr{x, index} - } - p.exprLev-- - p.expect(token.RBRACK) - - return x -} - - -func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr { - if p.trace { - defer un(trace(p, "CallOrConversion")) - } - - lparen := p.expect(token.LPAREN) - p.exprLev++ - var args []ast.Expr - if p.tok != token.RPAREN { - args = p.parseExprList() - } - p.exprLev-- - rparen := p.expect(token.RPAREN) - - return &ast.CallExpr{fun, lparen, args, rparen} -} - - -func (p *parser) parseElement() ast.Expr { - if p.trace { - defer un(trace(p, "Element")) - } - - x := p.parseExpr() - if p.tok == token.COLON { - colon := p.pos - p.next() - x = &ast.KeyValueExpr{x, colon, p.parseExpr()} - } - - return x -} - - -func (p *parser) parseElementList() []ast.Expr { - if p.trace { - defer un(trace(p, "ElementList")) - } - - list := new(vector.Vector) - for p.tok != token.RBRACE && p.tok != token.EOF { - list.Push(p.parseElement()) - if p.tok == token.COMMA { - p.next() - } else { - break - } - } - - // convert list - elts := make([]ast.Expr, list.Len()) - for i := 0; i < list.Len(); i++ { - elts[i] = list.At(i).(ast.Expr) - } - - return elts -} - - -func (p *parser) parseCompositeLit(typ ast.Expr) ast.Expr { - if p.trace { - defer un(trace(p, "CompositeLit")) - } - - lbrace := p.expect(token.LBRACE) - var elts []ast.Expr - if p.tok != token.RBRACE { - elts = p.parseElementList() - } - rbrace := p.expect(token.RBRACE) - return &ast.CompositeLit{typ, lbrace, elts, rbrace} -} - - -// TODO(gri): Consider different approach to checking syntax after parsing: -// Provide a arguments (set of flags) to parsing functions -// restricting what they are supposed to accept depending -// on context. - -// checkExpr checks that x is an expression (and not a type). -func (p *parser) checkExpr(x ast.Expr) ast.Expr { - // TODO(gri): should provide predicate in AST nodes - switch t := x.(type) { - case *ast.BadExpr: - case *ast.Ident: - case *ast.BasicLit: - case *ast.StringList: - case *ast.FuncLit: - case *ast.CompositeLit: - case *ast.ParenExpr: - case *ast.SelectorExpr: - case *ast.IndexExpr: - case *ast.SliceExpr: - case *ast.TypeAssertExpr: - if t.Type == nil { - // the form X.(type) is only allowed in type switch expressions - p.errorExpected(x.Pos(), "expression") - x = &ast.BadExpr{x.Pos()} - } - case *ast.CallExpr: - case *ast.StarExpr: - case *ast.UnaryExpr: - if t.Op == token.RANGE { - // the range operator is only allowed at the top of a for statement - p.errorExpected(x.Pos(), "expression") - x = &ast.BadExpr{x.Pos()} - } - case *ast.BinaryExpr: - default: - // all other nodes are not proper expressions - p.errorExpected(x.Pos(), "expression") - x = &ast.BadExpr{x.Pos()} - } - return x -} - - -// isTypeName returns true iff x is type name. -func isTypeName(x ast.Expr) bool { - // TODO(gri): should provide predicate in AST nodes - switch t := x.(type) { - case *ast.BadExpr: - case *ast.Ident: - case *ast.ParenExpr: - return isTypeName(t.X) // TODO(gri): should (TypeName) be illegal? - case *ast.SelectorExpr: - return isTypeName(t.X) - default: - return false // all other nodes are not type names - } - return true -} - - -// isCompositeLitType returns true iff x is a legal composite literal type. -func isCompositeLitType(x ast.Expr) bool { - // TODO(gri): should provide predicate in AST nodes - switch t := x.(type) { - case *ast.BadExpr: - case *ast.Ident: - case *ast.ParenExpr: - return isCompositeLitType(t.X) - case *ast.SelectorExpr: - return isTypeName(t.X) - case *ast.ArrayType: - case *ast.StructType: - case *ast.MapType: - default: - return false // all other nodes are not legal composite literal types - } - return true -} - - -// checkExprOrType checks that x is an expression or a type -// (and not a raw type such as [...]T). -// -func (p *parser) checkExprOrType(x ast.Expr) ast.Expr { - // TODO(gri): should provide predicate in AST nodes - switch t := x.(type) { - case *ast.UnaryExpr: - if t.Op == token.RANGE { - // the range operator is only allowed at the top of a for statement - p.errorExpected(x.Pos(), "expression") - x = &ast.BadExpr{x.Pos()} - } - case *ast.ArrayType: - if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis { - p.Error(len.Pos(), "expected array length, found '...'") - x = &ast.BadExpr{x.Pos()} - } - } - - // all other nodes are expressions or types - return x -} - - -func (p *parser) parsePrimaryExpr() ast.Expr { - if p.trace { - defer un(trace(p, "PrimaryExpr")) - } - - x := p.parseOperand() -L: for { - switch p.tok { - case token.PERIOD: - x = p.parseSelectorOrTypeAssertion(p.checkExpr(x)) - case token.LBRACK: - x = p.parseIndexOrSlice(p.checkExpr(x)) - case token.LPAREN: - x = p.parseCallOrConversion(p.checkExprOrType(x)) - case token.LBRACE: - if isCompositeLitType(x) && (p.exprLev >= 0 || !isTypeName(x)) { - x = p.parseCompositeLit(x) - } else { - break L - } - default: - break L - } - } - - return x -} - - -func (p *parser) parseUnaryExpr() ast.Expr { - if p.trace { - defer un(trace(p, "UnaryExpr")) - } - - switch p.tok { - case token.ADD, token.SUB, token.NOT, token.XOR, token.ARROW, token.AND, token.RANGE: - pos, op := p.pos, p.tok - p.next() - x := p.parseUnaryExpr() - return &ast.UnaryExpr{pos, op, p.checkExpr(x)} - - case token.MUL: - // unary "*" expression or pointer type - pos := p.pos - p.next() - x := p.parseUnaryExpr() - return &ast.StarExpr{pos, p.checkExprOrType(x)} - } - - return p.parsePrimaryExpr() -} - - -func (p *parser) parseBinaryExpr(prec1 int) ast.Expr { - if p.trace { - defer un(trace(p, "BinaryExpr")) - } - - x := p.parseUnaryExpr() - for prec := p.tok.Precedence(); prec >= prec1; prec-- { - for p.tok.Precedence() == prec { - pos, op := p.pos, p.tok - p.next() - y := p.parseBinaryExpr(prec + 1) - x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)} - } - } - - return x -} - - -// TODO(gri): parseExpr may return a type or even a raw type ([..]int) - -// should reject when a type/raw type is obviously not allowed -func (p *parser) parseExpr() ast.Expr { - if p.trace { - defer un(trace(p, "Expression")) - } - - return p.parseBinaryExpr(token.LowestPrec + 1) -} - - -// ---------------------------------------------------------------------------- -// Statements - - -func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt { - if p.trace { - defer un(trace(p, "SimpleStmt")) - } - - x := p.parseExprList() - - switch p.tok { - case token.COLON: - // labeled statement - p.next() - if labelOk && len(x) == 1 { - if label, isIdent := x[0].(*ast.Ident); isIdent { - return &ast.LabeledStmt{label, p.parseStmt()} - } - } - p.Error(x[0].Pos(), "illegal label declaration") - return &ast.BadStmt{x[0].Pos()} - - case - token.DEFINE, token.ASSIGN, token.ADD_ASSIGN, - token.SUB_ASSIGN, token.MUL_ASSIGN, token.QUO_ASSIGN, - token.REM_ASSIGN, token.AND_ASSIGN, token.OR_ASSIGN, - token.XOR_ASSIGN, token.SHL_ASSIGN, token.SHR_ASSIGN, token.AND_NOT_ASSIGN: - // assignment statement - pos, tok := p.pos, p.tok - p.next() - y := p.parseExprList() - return &ast.AssignStmt{x, pos, tok, y} - } - - if len(x) > 1 { - p.Error(x[0].Pos(), "only one expression allowed") - // continue with first expression - } - - if p.tok == token.INC || p.tok == token.DEC { - // increment or decrement - s := &ast.IncDecStmt{x[0], p.tok} - p.next() // consume "++" or "--" - return s - } - - // expression - return &ast.ExprStmt{x[0]} -} - - -func (p *parser) parseCallExpr() *ast.CallExpr { - x := p.parseExpr() - if call, isCall := x.(*ast.CallExpr); isCall { - return call - } - p.errorExpected(x.Pos(), "function/method call") - return nil -} - - -func (p *parser) parseGoStmt() ast.Stmt { - if p.trace { - defer un(trace(p, "GoStmt")) - } - - pos := p.expect(token.GO) - call := p.parseCallExpr() - if call != nil { - return &ast.GoStmt{pos, call} - } - return &ast.BadStmt{pos} -} - - -func (p *parser) parseDeferStmt() ast.Stmt { - if p.trace { - defer un(trace(p, "DeferStmt")) - } - - pos := p.expect(token.DEFER) - call := p.parseCallExpr() - if call != nil { - return &ast.DeferStmt{pos, call} - } - return &ast.BadStmt{pos} -} - - -func (p *parser) parseReturnStmt() *ast.ReturnStmt { - if p.trace { - defer un(trace(p, "ReturnStmt")) - } - - pos := p.pos - p.expect(token.RETURN) - var x []ast.Expr - if p.tok != token.SEMICOLON && p.tok != token.CASE && p.tok != token.DEFAULT && p.tok != token.RBRACE { - x = p.parseExprList() - } - - return &ast.ReturnStmt{pos, x} -} - - -func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt { - if p.trace { - defer un(trace(p, "BranchStmt")) - } - - s := &ast.BranchStmt{p.pos, tok, nil} - p.expect(tok) - if tok != token.FALLTHROUGH && p.tok == token.IDENT { - s.Label = p.parseIdent() - } - - return s -} - - -func (p *parser) makeExpr(s ast.Stmt) ast.Expr { - if s == nil { - return nil - } - if es, isExpr := s.(*ast.ExprStmt); isExpr { - return p.checkExpr(es.X) - } - p.Error(s.Pos(), "expected condition, found simple statement") - return &ast.BadExpr{s.Pos()} -} - - -func (p *parser) parseControlClause(isForStmt bool) (s1, s2, s3 ast.Stmt) { - if p.tok != token.LBRACE { - prevLev := p.exprLev - p.exprLev = -1 - - if p.tok != token.SEMICOLON { - s1 = p.parseSimpleStmt(false) - } - if p.tok == token.SEMICOLON { - p.next() - if p.tok != token.LBRACE && p.tok != token.SEMICOLON { - s2 = p.parseSimpleStmt(false) - } - if isForStmt { - // for statements have a 3rd section - p.expect(token.SEMICOLON) - if p.tok != token.LBRACE { - s3 = p.parseSimpleStmt(false) - } - } - } else { - s1, s2 = nil, s1 - } - - p.exprLev = prevLev - } - - return s1, s2, s3 -} - - -func (p *parser) parseIfStmt() *ast.IfStmt { - if p.trace { - defer un(trace(p, "IfStmt")) - } - - pos := p.expect(token.IF) - s1, s2, _ := p.parseControlClause(false) - body := p.parseBlockStmt(nil) - var else_ ast.Stmt - if p.tok == token.ELSE { - p.next() - else_ = p.parseStmt() - } - - return &ast.IfStmt{pos, s1, p.makeExpr(s2), body, else_} -} - - -func (p *parser) parseCaseClause() *ast.CaseClause { - if p.trace { - defer un(trace(p, "CaseClause")) - } - - // SwitchCase - pos := p.pos - var x []ast.Expr - if p.tok == token.CASE { - p.next() - x = p.parseExprList() - } else { - p.expect(token.DEFAULT) - } - - colon := p.expect(token.COLON) - body := p.parseStmtList() - - return &ast.CaseClause{pos, x, colon, body} -} - - -func (p *parser) parseTypeList() []ast.Expr { - if p.trace { - defer un(trace(p, "TypeList")) - } - - list := new(vector.Vector) - list.Push(p.parseType()) - for p.tok == token.COMMA { - p.next() - list.Push(p.parseType()) - } - - // convert list - exprs := make([]ast.Expr, list.Len()) - for i := 0; i < list.Len(); i++ { - exprs[i] = list.At(i).(ast.Expr) - } - - return exprs -} - - -func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause { - if p.trace { - defer un(trace(p, "TypeCaseClause")) - } - - // TypeSwitchCase - pos := p.pos - var types []ast.Expr - if p.tok == token.CASE { - p.next() - types = p.parseTypeList() - } else { - p.expect(token.DEFAULT) - } - - colon := p.expect(token.COLON) - body := p.parseStmtList() - - return &ast.TypeCaseClause{pos, types, colon, body} -} - - -func isExprSwitch(s ast.Stmt) bool { - if s == nil { - return true - } - if e, ok := s.(*ast.ExprStmt); ok { - if a, ok := e.X.(*ast.TypeAssertExpr); ok { - return a.Type != nil // regular type assertion - } - return true - } - return false -} - - -func (p *parser) parseSwitchStmt() ast.Stmt { - if p.trace { - defer un(trace(p, "SwitchStmt")) - } - - pos := p.expect(token.SWITCH) - s1, s2, _ := p.parseControlClause(false) - - if isExprSwitch(s2) { - lbrace := p.expect(token.LBRACE) - cases := new(vector.Vector) - for p.tok == token.CASE || p.tok == token.DEFAULT { - cases.Push(p.parseCaseClause()) - } - rbrace := p.expect(token.RBRACE) - p.optSemi = true - body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace} - return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body} - } - - // type switch - // TODO(gri): do all the checks! - lbrace := p.expect(token.LBRACE) - cases := new(vector.Vector) - for p.tok == token.CASE || p.tok == token.DEFAULT { - cases.Push(p.parseTypeCaseClause()) - } - rbrace := p.expect(token.RBRACE) - p.optSemi = true - body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace} - return &ast.TypeSwitchStmt{pos, s1, s2, body} -} - - -func (p *parser) parseCommClause() *ast.CommClause { - if p.trace { - defer un(trace(p, "CommClause")) - } - - // CommCase - pos := p.pos - var tok token.Token - var lhs, rhs ast.Expr - if p.tok == token.CASE { - p.next() - if p.tok == token.ARROW { - // RecvExpr without assignment - rhs = p.parseExpr() - } else { - // SendExpr or RecvExpr - rhs = p.parseExpr() - if p.tok == token.ASSIGN || p.tok == token.DEFINE { - // RecvExpr with assignment - tok = p.tok - p.next() - lhs = rhs - if p.tok == token.ARROW { - rhs = p.parseExpr() - } else { - p.expect(token.ARROW) // use expect() error handling - } - } - // else SendExpr - } - } else { - p.expect(token.DEFAULT) - } - - colon := p.expect(token.COLON) - body := p.parseStmtList() - - return &ast.CommClause{pos, tok, lhs, rhs, colon, body} -} - - -func (p *parser) parseSelectStmt() *ast.SelectStmt { - if p.trace { - defer un(trace(p, "SelectStmt")) - } - - pos := p.expect(token.SELECT) - lbrace := p.expect(token.LBRACE) - cases := new(vector.Vector) - for p.tok == token.CASE || p.tok == token.DEFAULT { - cases.Push(p.parseCommClause()) - } - rbrace := p.expect(token.RBRACE) - p.optSemi = true - body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace} - - return &ast.SelectStmt{pos, body} -} - - -func (p *parser) parseForStmt() ast.Stmt { - if p.trace { - defer un(trace(p, "ForStmt")) - } - - pos := p.expect(token.FOR) - s1, s2, s3 := p.parseControlClause(true) - body := p.parseBlockStmt(nil) - - if as, isAssign := s2.(*ast.AssignStmt); isAssign { - // possibly a for statement with a range clause; check assignment operator - if as.Tok != token.ASSIGN && as.Tok != token.DEFINE { - p.errorExpected(as.TokPos, "'=' or ':='") - return &ast.BadStmt{pos} - } - // check lhs - var key, value ast.Expr - switch len(as.Lhs) { - case 2: - value = as.Lhs[1] - fallthrough - case 1: - key = as.Lhs[0] - default: - p.errorExpected(as.Lhs[0].Pos(), "1 or 2 expressions") - return &ast.BadStmt{pos} - } - // check rhs - if len(as.Rhs) != 1 { - p.errorExpected(as.Rhs[0].Pos(), "1 expressions") - return &ast.BadStmt{pos} - } - if rhs, isUnary := as.Rhs[0].(*ast.UnaryExpr); isUnary && rhs.Op == token.RANGE { - // rhs is range expression; check lhs - return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body} - } else { - p.errorExpected(s2.Pos(), "range clause") - return &ast.BadStmt{pos} - } - } else { - // regular for statement - return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body} - } - - panic() // unreachable - return nil -} - - -func (p *parser) parseStmt() ast.Stmt { - if p.trace { - defer un(trace(p, "Statement")) - } - - switch p.tok { - case token.CONST, token.TYPE, token.VAR: - decl, _ := p.parseDecl(false) // do not consume trailing semicolon - return &ast.DeclStmt{decl} - case - // tokens that may start a top-level expression - token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operand - token.LBRACK, token.STRUCT, // composite type - token.MUL, token.AND, token.ARROW, token.ADD, token.SUB, token.XOR: // unary operators - return p.parseSimpleStmt(true) - case token.GO: - return p.parseGoStmt() - case token.DEFER: - return p.parseDeferStmt() - case token.RETURN: - return p.parseReturnStmt() - case token.BREAK, token.CONTINUE, token.GOTO, token.FALLTHROUGH: - return p.parseBranchStmt(p.tok) - case token.LBRACE: - return p.parseBlockStmt(nil) - case token.IF: - return p.parseIfStmt() - case token.SWITCH: - return p.parseSwitchStmt() - case token.SELECT: - return p.parseSelectStmt() - case token.FOR: - return p.parseForStmt() - case token.SEMICOLON, token.RBRACE: - // don't consume the ";", it is the separator following the empty statement - return &ast.EmptyStmt{p.pos} - } - - // no statement found - p.errorExpected(p.pos, "statement") - p.next() // make progress - return &ast.BadStmt{p.pos} -} - - -// ---------------------------------------------------------------------------- -// Declarations - -type parseSpecFunction func(p *parser, doc *ast.CommentGroup, getSemi bool) (spec ast.Spec, gotSemi bool) - - -// Consume semicolon if there is one and getSemi is set, and get any line comment. -// Return the comment if any and indicate if a semicolon was consumed. -// -func (p *parser) parseComment(getSemi bool) (comment *ast.CommentGroup, gotSemi bool) { - if getSemi && p.tok == token.SEMICOLON { - p.next() - gotSemi = true - } - return p.lineComment, gotSemi -} - - -func parseImportSpec(p *parser, doc *ast.CommentGroup, getSemi bool) (spec ast.Spec, gotSemi bool) { - if p.trace { - defer un(trace(p, "ImportSpec")) - } - - var ident *ast.Ident - if p.tok == token.PERIOD { - ident = &ast.Ident{p.pos, ast.NewObj(ast.Err, p.pos, ".")} - p.next() - } else if p.tok == token.IDENT { - ident = p.parseIdent() - } - - var path []*ast.BasicLit - if p.tok == token.STRING { - path = p.parseStringList(nil) - } else { - p.expect(token.STRING) // use expect() error handling - } - - comment, gotSemi := p.parseComment(getSemi) - - return &ast.ImportSpec{doc, ident, path, comment}, gotSemi -} - - -func parseConstSpec(p *parser, doc *ast.CommentGroup, getSemi bool) (spec ast.Spec, gotSemi bool) { - if p.trace { - defer un(trace(p, "ConstSpec")) - } - - idents := p.parseIdentList() - typ := p.tryType() - var values []ast.Expr - if typ != nil || p.tok == token.ASSIGN { - p.expect(token.ASSIGN) - values = p.parseExprList() - } - comment, gotSemi := p.parseComment(getSemi) - - return &ast.ValueSpec{doc, idents, typ, values, comment}, gotSemi -} - - -func parseTypeSpec(p *parser, doc *ast.CommentGroup, getSemi bool) (spec ast.Spec, gotSemi bool) { - if p.trace { - defer un(trace(p, "TypeSpec")) - } - - ident := p.parseIdent() - typ := p.parseType() - comment, gotSemi := p.parseComment(getSemi) - - return &ast.TypeSpec{doc, ident, typ, comment}, gotSemi -} - - -func parseVarSpec(p *parser, doc *ast.CommentGroup, getSemi bool) (spec ast.Spec, gotSemi bool) { - if p.trace { - defer un(trace(p, "VarSpec")) - } - - idents := p.parseIdentList() - typ := p.tryType() - var values []ast.Expr - if typ == nil || p.tok == token.ASSIGN { - p.expect(token.ASSIGN) - values = p.parseExprList() - } - comment, gotSemi := p.parseComment(getSemi) - - return &ast.ValueSpec{doc, idents, typ, values, comment}, gotSemi -} - - -func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction, getSemi bool) (decl *ast.GenDecl, gotSemi bool) { - if p.trace { - defer un(trace(p, keyword.String()+"Decl")) - } - - doc := p.leadComment - pos := p.expect(keyword) - var lparen, rparen token.Position - list := new(vector.Vector) - if p.tok == token.LPAREN { - lparen = p.pos - p.next() - for p.tok != token.RPAREN && p.tok != token.EOF { - doc := p.leadComment - spec, semi := f(p, doc, true) // consume semicolon if any - list.Push(spec) - if !semi { - break - } - } - rparen = p.expect(token.RPAREN) - - if getSemi && p.tok == token.SEMICOLON { - p.next() - gotSemi = true - } else { - p.optSemi = true - } - } else { - spec, semi := f(p, nil, getSemi) - list.Push(spec) - gotSemi = semi - } - - // convert vector - specs := make([]ast.Spec, list.Len()) - for i := 0; i < list.Len(); i++ { - specs[i] = list.At(i).(ast.Spec) - } - - return &ast.GenDecl{doc, pos, keyword, lparen, specs, rparen}, gotSemi -} - - -func (p *parser) parseReceiver() *ast.Field { - if p.trace { - defer un(trace(p, "Receiver")) - } - - pos := p.pos - par := p.parseParameters(false) - - // must have exactly one receiver - if len(par) != 1 || len(par) == 1 && len(par[0].Names) > 1 { - p.errorExpected(pos, "exactly one receiver") - return &ast.Field{Type: &ast.BadExpr{noPos}} - } - - recv := par[0] - - // recv type must be TypeName or *TypeName - base := recv.Type - if ptr, isPtr := base.(*ast.StarExpr); isPtr { - base = ptr.X - } - if !isTypeName(base) { - p.errorExpected(base.Pos(), "type name") - } - - return recv -} - - -func (p *parser) parseFunctionDecl() *ast.FuncDecl { - if p.trace { - defer un(trace(p, "FunctionDecl")) - } - - doc := p.leadComment - pos := p.expect(token.FUNC) - - var recv *ast.Field - if p.tok == token.LPAREN { - recv = p.parseReceiver() - } - - ident := p.parseIdent() - params, results := p.parseSignature() - - var body *ast.BlockStmt - if p.tok == token.LBRACE { - body = p.parseBlockStmt(nil) - } - - return &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body} -} - - -func (p *parser) parseDecl(getSemi bool) (decl ast.Decl, gotSemi bool) { - if p.trace { - defer un(trace(p, "Declaration")) - } - - var f parseSpecFunction - switch p.tok { - case token.CONST: - f = parseConstSpec - - case token.TYPE: - f = parseTypeSpec - - case token.VAR: - f = parseVarSpec - - case token.FUNC: - decl = p.parseFunctionDecl() - _, gotSemi := p.parseComment(getSemi) - return decl, gotSemi - - default: - pos := p.pos - p.errorExpected(pos, "declaration") - decl = &ast.BadDecl{pos} - gotSemi = getSemi && p.tok == token.SEMICOLON - p.next() // make progress in any case - return decl, gotSemi - } - - return p.parseGenDecl(p.tok, f, getSemi) -} - - -func (p *parser) parseDeclList() []ast.Decl { - if p.trace { - defer un(trace(p, "DeclList")) - } - - list := new(vector.Vector) - for p.tok != token.EOF { - decl, _ := p.parseDecl(true) // consume optional semicolon - list.Push(decl) - } - - // convert vector - decls := make([]ast.Decl, list.Len()) - for i := 0; i < list.Len(); i++ { - decls[i] = list.At(i).(ast.Decl) - } - - return decls -} - - -// ---------------------------------------------------------------------------- -// Source files - -func (p *parser) parseFile() *ast.File { - if p.trace { - defer un(trace(p, "File")) - } - - // package clause - doc := p.leadComment - pos := p.expect(token.PACKAGE) - ident := p.parseIdent() - - // Common error: semicolon after package clause. - // Accept and report it for better error synchronization. - if p.tok == token.SEMICOLON { - p.Error(p.pos, "expected declaration, found ';'") - p.next() - } - - var decls []ast.Decl - - // Don't bother parsing the rest if we had errors already. - // Likely not a Go source file at all. - - if p.ErrorCount() == 0 && p.mode&PackageClauseOnly == 0 { - // import decls - list := new(vector.Vector) - for p.tok == token.IMPORT { - decl, _ := p.parseGenDecl(token.IMPORT, parseImportSpec, true) // consume optional semicolon - list.Push(decl) - } - - if p.mode&ImportsOnly == 0 { - // rest of package body - for p.tok != token.EOF { - decl, _ := p.parseDecl(true) // consume optional semicolon - list.Push(decl) - } - } - - // convert declaration list - decls = make([]ast.Decl, list.Len()) - for i := 0; i < list.Len(); i++ { - decls[i] = list.At(i).(ast.Decl) - } - } - - return &ast.File{doc, pos, ident, decls, p.comments} -} diff --git a/src/pkg/exp/parser/parser_test.go b/src/pkg/exp/parser/parser_test.go deleted file mode 100644 index 2aefaa1cfff..00000000000 --- a/src/pkg/exp/parser/parser_test.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package oldParser - -import ( - "os" - "testing" -) - - -var illegalInputs = []interface{}{ - nil, - 3.14, - []byte(nil), - "foo!", -} - - -func TestParseIllegalInputs(t *testing.T) { - for _, src := range illegalInputs { - _, err := ParseFile("", src, 0) - if err == nil { - t.Errorf("ParseFile(%v) should have failed", src) - } - } -} - - -var validPrograms = []interface{}{ - `package main`, - `package main import "fmt" func main() { fmt.Println("Hello, World!") }`, - `package main func main() { if f(T{}) {} }`, -} - - -func TestParseValidPrograms(t *testing.T) { - for _, src := range validPrograms { - _, err := ParseFile("", src, 0) - if err != nil { - t.Errorf("ParseFile(%q): %v", src, err) - } - } -} - - -var validFiles = []string{ - "parser.go", - "parser_test.go", -} - - -func TestParse3(t *testing.T) { - return // disabled since the parser only accepts old syntax - for _, filename := range validFiles { - _, err := ParseFile(filename, nil, 0) - if err != nil { - t.Errorf("ParseFile(%s): %v", filename, err) - } - } -} - - -func nameFilter(filename string) bool { - switch filename { - case "parser.go": - case "interface.go": - case "parser_test.go": - default: - return false - } - return true -} - - -func dirFilter(d *os.Dir) bool { return nameFilter(d.Name) } - - -func TestParse4(t *testing.T) { - return // disabled since the parser only accepts old syntax - path := "." - pkg, err := ParsePackage(path, dirFilter, 0) - if err != nil { - t.Fatalf("ParsePackage(%s): %v", path, err) - } - if pkg.Name != "oldParser" { - t.Errorf("incorrect package name: %s", pkg.Name) - } - for filename, _ := range pkg.Files { - if !nameFilter(filename) { - t.Errorf("unexpected package file: %s", filename) - } - } -} diff --git a/src/pkg/go/ast/ast.go b/src/pkg/go/ast/ast.go index 95700cb14dc..0976a5ec785 100644 --- a/src/pkg/go/ast/ast.go +++ b/src/pkg/go/ast/ast.go @@ -90,7 +90,7 @@ type Field struct { Doc *CommentGroup // associated documentation; or nil Names []*Ident // field/method/parameter names; or nil if anonymous field Type Expr // field/method/parameter type - Tag []*BasicLit // field tag; or nil + Tag *BasicLit // field tag; or nil Comment *CommentGroup // line comments; or nil } @@ -136,17 +136,6 @@ type ( Value []byte // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 'a', '\x7f', "foo" or `\m\n\o` } - // A StringList node represents a sequence of adjacent string literals. - // A single string literal (common case) is represented by a BasicLit - // node; StringList nodes are used only if there are two or more string - // literals in a sequence. - // TODO(gri) Deprecated. StringLists are only created by exp/parser; - // Remove when exp/parser is removed. - // - StringList struct { - Strings []*BasicLit // list of strings, len(Strings) > 1 - } - // A FuncLit node represents a function literal. FuncLit struct { Type *FuncType // function type @@ -309,7 +298,6 @@ type ( // Pos() implementations for expression/type where the position // corresponds to the position of a sub-node. // -func (x *StringList) Pos() token.Position { return x.Strings[0].Pos() } func (x *FuncLit) Pos() token.Position { return x.Type.Pos() } func (x *CompositeLit) Pos() token.Position { return x.Type.Pos() } func (x *SelectorExpr) Pos() token.Position { return x.X.Pos() } @@ -327,7 +315,6 @@ func (x *BadExpr) exprNode() {} func (x *Ident) exprNode() {} func (x *Ellipsis) exprNode() {} func (x *BasicLit) exprNode() {} -func (x *StringList) exprNode() {} func (x *FuncLit) exprNode() {} func (x *CompositeLit) exprNode() {} func (x *ParenExpr) exprNode() {} @@ -604,7 +591,7 @@ type ( ImportSpec struct { Doc *CommentGroup // associated documentation; or nil Name *Ident // local package name (including "."); or nil - Path []*BasicLit // package path + Path *BasicLit // package path Comment *CommentGroup // line comments; or nil } @@ -634,7 +621,7 @@ func (s *ImportSpec) Pos() token.Position { if s.Name != nil { return s.Name.Pos() } - return s.Path[0].Pos() + return s.Path.Pos() } func (s *ValueSpec) Pos() token.Position { return s.Names[0].Pos() } diff --git a/src/pkg/go/ast/walk.go b/src/pkg/go/ast/walk.go index 33a2d32940d..ee2c89cbe11 100644 --- a/src/pkg/go/ast/walk.go +++ b/src/pkg/go/ast/walk.go @@ -74,20 +74,13 @@ func Walk(v Visitor, node interface{}) { walkCommentGroup(v, n.Doc) Walk(v, n.Names) Walk(v, n.Type) - for _, x := range n.Tag { - Walk(v, x) - } + Walk(v, n.Tag) walkCommentGroup(v, n.Comment) // Expressions case *BadExpr, *Ident, *Ellipsis, *BasicLit: // nothing to do - case *StringList: - for _, x := range n.Strings { - Walk(v, x) - } - case *FuncLit: if n != nil { Walk(v, n.Type) @@ -249,9 +242,7 @@ func Walk(v Visitor, node interface{}) { case *ImportSpec: walkCommentGroup(v, n.Doc) walkIdent(v, n.Name) - for _, x := range n.Path { - Walk(v, x) - } + Walk(v, n.Path) walkCommentGroup(v, n.Comment) case *ValueSpec: diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go index d848d2392b7..15bb2d61251 100644 --- a/src/pkg/go/parser/parser.go +++ b/src/pkg/go/parser/parser.go @@ -526,11 +526,10 @@ func (p *parser) parseFieldDecl() *ast.Field { typ := p.tryType() // optional tag - var tag []*ast.BasicLit + var tag *ast.BasicLit if p.tok == token.STRING { - x := &ast.BasicLit{p.pos, p.tok, p.lit} + tag = &ast.BasicLit{p.pos, p.tok, p.lit} p.next() - tag = []*ast.BasicLit{x} } // analyze case @@ -1129,7 +1128,6 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr { case *ast.BadExpr: case *ast.Ident: case *ast.BasicLit: - case *ast.StringList: case *ast.FuncLit: case *ast.CompositeLit: case *ast.ParenExpr: @@ -1827,11 +1825,10 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup) ast.Spec { p.declIdent(p.fileScope, ident) } - var path []*ast.BasicLit + var path *ast.BasicLit if p.tok == token.STRING { - x := &ast.BasicLit{p.pos, p.tok, p.lit} + path = &ast.BasicLit{p.pos, p.tok, p.lit} p.next() - path = []*ast.BasicLit{x} } else { p.expect(token.STRING) // use expect() error handling } diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go index 218ad765d8d..9a7519ba35b 100644 --- a/src/pkg/go/printer/nodes.go +++ b/src/pkg/go/printer/nodes.go @@ -396,7 +396,7 @@ func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace tok p.print(sep) } p.print(sep) - p.expr(&ast.StringList{f.Tag}, &ml) + p.expr(f.Tag, &ml) extraTabs = 0 } if f.Comment != nil { @@ -680,9 +680,6 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi case *ast.BasicLit: p.print(x) - case *ast.StringList: - p.stringList(x.Strings, multiLine) - case *ast.FuncLit: p.expr(x.Type, multiLine) p.funcBody(x.Body, distance(x.Type.Pos(), p.pos), true, multiLine) @@ -1117,9 +1114,9 @@ func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *boo if s.Name != nil { p.expr(s.Name, multiLine) p.print(blank) - p.moveCommentsAfter(s.Path[0].Pos()) + p.moveCommentsAfter(s.Path.Pos()) } - p.expr(&ast.StringList{s.Path}, multiLine) + p.expr(s.Path, multiLine) comment = s.Comment case *ast.ValueSpec: