]> Cypherpunks repositories - gostls13.git/commitdiff
- removed exp/parser (support for old semicolon syntax)
authorRobert Griesemer <gri@golang.org>
Sat, 20 Feb 2010 00:01:31 +0000 (16:01 -0800)
committerRobert Griesemer <gri@golang.org>
Sat, 20 Feb 2010 00:01:31 +0000 (16:01 -0800)
- go/ast: removed StringList (not needed anymore)
- go/ast: changed import path and field list tag to a single string
- updated all dependencies

R=rsc
CC=golang-dev
https://golang.org/cl/217056

18 files changed:
src/cmd/cgo/ast.go
src/cmd/godoc/index.go
src/cmd/gofmt/doc.go
src/cmd/gofmt/gofmt.go
src/pkg/Makefile
src/pkg/exp/eval/eval_test.go
src/pkg/exp/eval/expr.go
src/pkg/exp/eval/expr_test.go
src/pkg/exp/eval/stmt_test.go
src/pkg/exp/eval/world.go
src/pkg/exp/parser/Makefile [deleted file]
src/pkg/exp/parser/interface.go [deleted file]
src/pkg/exp/parser/parser.go [deleted file]
src/pkg/exp/parser/parser_test.go [deleted file]
src/pkg/go/ast/ast.go
src/pkg/go/ast/walk.go
src/pkg/go/parser/parser.go
src/pkg/go/printer/nodes.go

index f6142d135dfc96919d6e5f4a9cc3c3cb8d180888..2cc771e16f5a0053ce6ef55fab6a5d10f9a8b653 100644 (file)
@@ -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")
index 14aacfec68cf4dd3516bb929c8627609cad9eeab..dcad67a95a1f3b92b662388ad324799e7f65957a 100644 (file)
@@ -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:
index e9b1d6c47f3342e2257059e0d15f0ce4b1e76357..4b4adba030bb7ff7ddbcac0fced59eb889f2b40c 100644 (file)
@@ -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
index 6997bf3e210b9a159ea9517cd198d2ea0a28eb09..abd30edc89b6c9f6635813e43e2beebcb599395f 100644 (file)
@@ -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
        }
index 2a65d376986af36e3df00a23a14ec11a4fec2f54..7fb0240a542cc2ed39c6c6ac0e5faaec664ccb95 100644 (file)
@@ -64,7 +64,6 @@ DIRS=\
        exp/eval\
        exp/exception\
        exp/iterable\
-       exp/parser\
        expvar\
        flag\
        fmt\
index 93a643b5aaa437626507d773fe9be9e1f0c89dfc..911c7e4a52ec3d23cb304daab55c4eae0950bbf4 100644 (file)
@@ -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)
                }
index ed32c0a3c6d65bf58373b43ed197dba211d9344d..94714943c692a54aae403ded70b5c51b25b7871f 100644 (file)
@@ -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
 
index 5cfbc823270185935a41c432fa1f77773d1c53e7..10c7f6be5281bed6965d323b414d86d05f26221e 100644 (file)
@@ -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),
index 1600a750781c25185eec5c4f497121da3e32e0eb..a14a288d936bf4e2c787aee0b8357f03a931497a 100644 (file)
@@ -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()"),
 }
index c36081b263fddc34d2abdd487852ce741b243652..1d19b50b627a437796c501b0cbc50808dc2fad07 100644 (file)
@@ -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 (file)
index da35917..0000000
+++ /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 (file)
index e04ff18..0000000
+++ /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 (file)
index 6114c88..0000000
+++ /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 (file)
index 2aefaa1..0000000
+++ /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)
-               }
-       }
-}
index 95700cb14dcdce1a30d0631d3bbf084bac181d09..0976a5ec7856098c1d1408db46624a6e34befac1 100644 (file)
@@ -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() }
index 33a2d32940da8bd778a3cc13d5db87c939970fc5..ee2c89cbe111b928a868d5e86d8192bc83f87e3d 100644 (file)
@@ -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:
index d848d2392b7473329d5b80ff3e6a22e3459baec2..15bb2d61251b484d8b2645934d9fd00ed41df8fe 100644 (file)
@@ -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
        }
index 218ad765d8d03d21da5394cee6e04d921e4c9790..9a7519ba35b678921e68295068786e2a6f4ba34e 100644 (file)
@@ -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: