summaryrefslogtreecommitdiffstats
path: root/libgo/go/go
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2011-09-16 15:47:21 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2011-09-16 15:47:21 +0000
commit49b4e44b7d540fa846d353b10237848a67789cbf (patch)
treeea2b52e3c258d6b6d9356977c683c7f72a4a5fd5 /libgo/go/go
parent82ceb8f6a88a0193971f53e0571e017f2764f7d7 (diff)
downloadppe42-gcc-49b4e44b7d540fa846d353b10237848a67789cbf.tar.gz
ppe42-gcc-49b4e44b7d540fa846d353b10237848a67789cbf.zip
Update Go library to r60.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@178910 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/go')
-rw-r--r--libgo/go/go/ast/ast.go66
-rw-r--r--libgo/go/go/ast/filter.go130
-rw-r--r--libgo/go/go/ast/print.go9
-rw-r--r--libgo/go/go/ast/print_test.go5
-rw-r--r--libgo/go/go/ast/resolve.go90
-rw-r--r--libgo/go/go/ast/scope.go22
-rw-r--r--libgo/go/go/ast/walk.go7
-rw-r--r--libgo/go/go/build/build.go444
-rw-r--r--libgo/go/go/build/build_test.go61
-rw-r--r--libgo/go/go/build/cgotest/cgotest.go19
-rw-r--r--libgo/go/go/build/cmdtest/main.go12
-rw-r--r--libgo/go/go/build/dir.go172
-rw-r--r--libgo/go/go/build/path.go182
-rw-r--r--libgo/go/go/build/pkgtest/pkgtest.go9
-rw-r--r--libgo/go/go/build/syslist_test.go62
-rw-r--r--libgo/go/go/doc/comment.go16
-rw-r--r--libgo/go/go/doc/doc.go55
-rw-r--r--libgo/go/go/parser/interface.go37
-rw-r--r--libgo/go/go/parser/parser.go283
-rw-r--r--libgo/go/go/parser/parser_test.go28
-rw-r--r--libgo/go/go/printer/nodes.go240
-rw-r--r--libgo/go/go/printer/performance_test.go4
-rw-r--r--libgo/go/go/printer/printer.go57
-rw-r--r--libgo/go/go/printer/printer_test.go10
-rw-r--r--libgo/go/go/printer/testdata/comments.golden20
-rw-r--r--libgo/go/go/printer/testdata/comments.input2
-rw-r--r--libgo/go/go/printer/testdata/comments.x11
-rw-r--r--libgo/go/go/printer/testdata/declarations.golden61
-rw-r--r--libgo/go/go/printer/testdata/declarations.input29
-rw-r--r--libgo/go/go/printer/testdata/expressions.golden25
-rw-r--r--libgo/go/go/printer/testdata/expressions.raw25
-rw-r--r--libgo/go/go/printer/testdata/parser.go99
-rw-r--r--libgo/go/go/printer/testdata/statements.golden31
-rw-r--r--libgo/go/go/printer/testdata/statements.input13
-rw-r--r--libgo/go/go/scanner/errors.go34
-rw-r--r--libgo/go/go/scanner/scanner.go59
-rw-r--r--libgo/go/go/scanner/scanner_test.go44
-rw-r--r--libgo/go/go/token/position.go35
-rw-r--r--libgo/go/go/token/position_test.go9
-rw-r--r--libgo/go/go/token/token.go8
-rw-r--r--libgo/go/go/typechecker/scope.go6
-rw-r--r--libgo/go/go/typechecker/type.go7
-rw-r--r--libgo/go/go/typechecker/typechecker.go20
-rw-r--r--libgo/go/go/typechecker/typechecker_test.go5
-rw-r--r--libgo/go/go/typechecker/universe.go2
-rw-r--r--libgo/go/go/types/check.go226
-rw-r--r--libgo/go/go/types/check_test.go215
-rw-r--r--libgo/go/go/types/const.go15
-rw-r--r--libgo/go/go/types/exportdata.go11
-rw-r--r--libgo/go/go/types/gcimporter.go273
-rw-r--r--libgo/go/go/types/gcimporter_test.go28
-rw-r--r--libgo/go/go/types/testdata/exports.go23
-rw-r--r--libgo/go/go/types/types.go177
-rw-r--r--libgo/go/go/types/universe.go23
54 files changed, 2318 insertions, 1238 deletions
diff --git a/libgo/go/go/ast/ast.go b/libgo/go/go/ast/ast.go
index 2fc1a60323d..22bd5ee2266 100644
--- a/libgo/go/go/ast/ast.go
+++ b/libgo/go/go/ast/ast.go
@@ -13,7 +13,6 @@ import (
"utf8"
)
-
// ----------------------------------------------------------------------------
// Interfaces
//
@@ -31,35 +30,30 @@ import (
// That position information is needed to properly position comments
// when printing the construct.
-
// All node types implement the Node interface.
type Node interface {
Pos() token.Pos // position of first character belonging to the node
End() token.Pos // position of first character immediately after the node
}
-
// All expression nodes implement the Expr interface.
type Expr interface {
Node
exprNode()
}
-
// All statement nodes implement the Stmt interface.
type Stmt interface {
Node
stmtNode()
}
-
// All declaration nodes implement the Decl interface.
type Decl interface {
Node
declNode()
}
-
// ----------------------------------------------------------------------------
// Comments
@@ -69,11 +63,9 @@ type Comment struct {
Text string // comment text (excluding '\n' for //-style comments)
}
-
func (c *Comment) Pos() token.Pos { return c.Slash }
func (c *Comment) End() token.Pos { return token.Pos(int(c.Slash) + len(c.Text)) }
-
// A CommentGroup represents a sequence of comments
// with no other tokens and no empty lines between.
//
@@ -81,11 +73,9 @@ type CommentGroup struct {
List []*Comment // len(List) > 0
}
-
func (g *CommentGroup) Pos() token.Pos { return g.List[0].Pos() }
func (g *CommentGroup) End() token.Pos { return g.List[len(g.List)-1].End() }
-
// ----------------------------------------------------------------------------
// Expressions and types
@@ -101,7 +91,6 @@ type Field struct {
Comment *CommentGroup // line comments; or nil
}
-
func (f *Field) Pos() token.Pos {
if len(f.Names) > 0 {
return f.Names[0].Pos()
@@ -109,7 +98,6 @@ func (f *Field) Pos() token.Pos {
return f.Type.Pos()
}
-
func (f *Field) End() token.Pos {
if f.Tag != nil {
return f.Tag.End()
@@ -117,15 +105,13 @@ func (f *Field) End() token.Pos {
return f.Type.End()
}
-
// A FieldList represents a list of Fields, enclosed by parentheses or braces.
type FieldList struct {
Opening token.Pos // position of opening parenthesis/brace, if any
- List []*Field // field list
+ List []*Field // field list; or nil
Closing token.Pos // position of closing parenthesis/brace, if any
}
-
func (f *FieldList) Pos() token.Pos {
if f.Opening.IsValid() {
return f.Opening
@@ -138,7 +124,6 @@ func (f *FieldList) Pos() token.Pos {
return token.NoPos
}
-
func (f *FieldList) End() token.Pos {
if f.Closing.IsValid() {
return f.Closing + 1
@@ -151,7 +136,6 @@ func (f *FieldList) End() token.Pos {
return token.NoPos
}
-
// NumFields returns the number of (named and anonymous fields) in a FieldList.
func (f *FieldList) NumFields() int {
n := 0
@@ -167,7 +151,6 @@ func (f *FieldList) NumFields() int {
return n
}
-
// An expression is represented by a tree consisting of one
// or more of the following concrete expression nodes.
//
@@ -298,7 +281,6 @@ type (
}
)
-
// The direction of a channel type is indicated by one
// of the following constants.
//
@@ -309,7 +291,6 @@ const (
RECV
)
-
// A type is represented by a tree consisting of one
// or more of the following type-specific expression
// nodes.
@@ -334,7 +315,7 @@ type (
// A FuncType node represents a function type.
FuncType struct {
Func token.Pos // position of "func" keyword
- Params *FieldList // (incoming) parameters
+ Params *FieldList // (incoming) parameters; or nil
Results *FieldList // (outgoing) results; or nil
}
@@ -360,7 +341,6 @@ type (
}
)
-
// Pos and End implementations for expression/type nodes.
//
func (x *BadExpr) Pos() token.Pos { return x.From }
@@ -391,7 +371,6 @@ func (x *InterfaceType) Pos() token.Pos { return x.Interface }
func (x *MapType) Pos() token.Pos { return x.Map }
func (x *ChanType) Pos() token.Pos { return x.Begin }
-
func (x *BadExpr) End() token.Pos { return x.To }
func (x *Ident) End() token.Pos { return token.Pos(int(x.NamePos) + len(x.Name)) }
func (x *Ellipsis) End() token.Pos {
@@ -430,7 +409,6 @@ func (x *InterfaceType) End() token.Pos { return x.Methods.End() }
func (x *MapType) End() token.Pos { return x.Value.End() }
func (x *ChanType) End() token.Pos { return x.Value.End() }
-
// exprNode() ensures that only expression/type nodes can be
// assigned to an ExprNode.
//
@@ -458,7 +436,6 @@ func (x *InterfaceType) exprNode() {}
func (x *MapType) exprNode() {}
func (x *ChanType) exprNode() {}
-
// ----------------------------------------------------------------------------
// Convenience functions for Idents
@@ -469,7 +446,6 @@ var noPos token.Pos
//
func NewIdent(name string) *Ident { return &Ident{noPos, name, nil} }
-
// IsExported returns whether name is an exported Go symbol
// (i.e., whether it begins with an uppercase letter).
//
@@ -478,13 +454,11 @@ func IsExported(name string) bool {
return unicode.IsUpper(ch)
}
-
// IsExported returns whether id is an exported Go symbol
// (i.e., whether it begins with an uppercase letter).
//
func (id *Ident) IsExported() bool { return IsExported(id.Name) }
-
func (id *Ident) String() string {
if id != nil {
return id.Name
@@ -492,7 +466,6 @@ func (id *Ident) String() string {
return "<nil>"
}
-
// ----------------------------------------------------------------------------
// Statements
@@ -515,10 +488,10 @@ type (
// An EmptyStmt node represents an empty statement.
// The "position" of the empty statement is the position
- // of the immediately preceeding semicolon.
+ // of the immediately preceding semicolon.
//
EmptyStmt struct {
- Semicolon token.Pos // position of preceeding ";"
+ Semicolon token.Pos // position of preceding ";"
}
// A LabeledStmt node represents a labeled statement.
@@ -596,7 +569,7 @@ type (
// An IfStmt node represents an if statement.
IfStmt struct {
If token.Pos // position of "if" keyword
- Init Stmt // initalization statement; or nil
+ Init Stmt // initialization statement; or nil
Cond Expr // condition
Body *BlockStmt
Else Stmt // else branch; or nil
@@ -613,7 +586,7 @@ type (
// A SwitchStmt node represents an expression switch statement.
SwitchStmt struct {
Switch token.Pos // position of "switch" keyword
- Init Stmt // initalization statement; or nil
+ Init Stmt // initialization statement; or nil
Tag Expr // tag expression; or nil
Body *BlockStmt // CaseClauses only
}
@@ -621,7 +594,7 @@ type (
// An TypeSwitchStmt node represents a type switch statement.
TypeSwitchStmt struct {
Switch token.Pos // position of "switch" keyword
- Init Stmt // initalization statement; or nil
+ Init Stmt // initialization statement; or nil
Assign Stmt // x := y.(type) or y.(type)
Body *BlockStmt // CaseClauses only
}
@@ -643,7 +616,7 @@ type (
// A ForStmt represents a for statement.
ForStmt struct {
For token.Pos // position of "for" keyword
- Init Stmt // initalization statement; or nil
+ Init Stmt // initialization statement; or nil
Cond Expr // condition; or nil
Post Stmt // post iteration statement; or nil
Body *BlockStmt
@@ -660,7 +633,6 @@ type (
}
)
-
// Pos and End implementations for statement nodes.
//
func (s *BadStmt) Pos() token.Pos { return s.From }
@@ -685,7 +657,6 @@ func (s *SelectStmt) Pos() token.Pos { return s.Select }
func (s *ForStmt) Pos() token.Pos { return s.For }
func (s *RangeStmt) Pos() token.Pos { return s.For }
-
func (s *BadStmt) End() token.Pos { return s.To }
func (s *DeclStmt) End() token.Pos { return s.Decl.End() }
func (s *EmptyStmt) End() token.Pos {
@@ -737,7 +708,6 @@ func (s *SelectStmt) End() token.Pos { return s.Body.End() }
func (s *ForStmt) End() token.Pos { return s.Body.End() }
func (s *RangeStmt) End() token.Pos { return s.Body.End() }
-
// stmtNode() ensures that only statement nodes can be
// assigned to a StmtNode.
//
@@ -763,7 +733,6 @@ func (s *SelectStmt) stmtNode() {}
func (s *ForStmt) stmtNode() {}
func (s *RangeStmt) stmtNode() {}
-
// ----------------------------------------------------------------------------
// Declarations
@@ -805,7 +774,6 @@ type (
}
)
-
// Pos and End implementations for spec nodes.
//
func (s *ImportSpec) Pos() token.Pos {
@@ -817,7 +785,6 @@ func (s *ImportSpec) Pos() token.Pos {
func (s *ValueSpec) Pos() token.Pos { return s.Names[0].Pos() }
func (s *TypeSpec) Pos() token.Pos { return s.Name.Pos() }
-
func (s *ImportSpec) End() token.Pos { return s.Path.End() }
func (s *ValueSpec) End() token.Pos {
if n := len(s.Values); n > 0 {
@@ -830,7 +797,6 @@ func (s *ValueSpec) End() token.Pos {
}
func (s *TypeSpec) End() token.Pos { return s.Type.End() }
-
// specNode() ensures that only spec nodes can be
// assigned to a Spec.
//
@@ -838,7 +804,6 @@ func (s *ImportSpec) specNode() {}
func (s *ValueSpec) specNode() {}
func (s *TypeSpec) specNode() {}
-
// A declaration is represented by one of the following declaration nodes.
//
type (
@@ -880,14 +845,12 @@ type (
}
)
-
// Pos and End implementations for declaration nodes.
//
func (d *BadDecl) Pos() token.Pos { return d.From }
func (d *GenDecl) Pos() token.Pos { return d.TokPos }
func (d *FuncDecl) Pos() token.Pos { return d.Type.Pos() }
-
func (d *BadDecl) End() token.Pos { return d.To }
func (d *GenDecl) End() token.Pos {
if d.Rparen.IsValid() {
@@ -902,7 +865,6 @@ func (d *FuncDecl) End() token.Pos {
return d.Type.End()
}
-
// declNode() ensures that only declaration nodes can be
// assigned to a DeclNode.
//
@@ -910,7 +872,6 @@ func (d *BadDecl) declNode() {}
func (d *GenDecl) declNode() {}
func (d *FuncDecl) declNode() {}
-
// ----------------------------------------------------------------------------
// Files and packages
@@ -931,7 +892,6 @@ type File struct {
Comments []*CommentGroup // list of all comments in the source file
}
-
func (f *File) Pos() token.Pos { return f.Package }
func (f *File) End() token.Pos {
if n := len(f.Decls); n > 0 {
@@ -940,17 +900,15 @@ func (f *File) End() token.Pos {
return f.Name.End()
}
-
// A Package node represents a set of source files
// collectively building a Go package.
//
type Package struct {
- Name string // package name
- Scope *Scope // package scope
- Imports map[string]*Scope // map of import path -> package scope across all files
- Files map[string]*File // Go source files by filename
+ Name string // package name
+ Scope *Scope // package scope across all files
+ Imports map[string]*Object // map of package id -> package object
+ Files map[string]*File // Go source files by filename
}
-
func (p *Package) Pos() token.Pos { return token.NoPos }
func (p *Package) End() token.Pos { return token.NoPos }
diff --git a/libgo/go/go/ast/filter.go b/libgo/go/go/ast/filter.go
index 090d08d34c7..26733430d64 100644
--- a/libgo/go/go/ast/filter.go
+++ b/libgo/go/go/ast/filter.go
@@ -20,25 +20,25 @@ func identListExports(list []*Ident) []*Ident {
return list[0:j]
}
-
-// isExportedType assumes that typ is a correct type.
-func isExportedType(typ Expr) bool {
- switch t := typ.(type) {
+// fieldName assumes that x is the type of an anonymous field and
+// returns the corresponding field name. If x is not an acceptable
+// anonymous field, the result is nil.
+//
+func fieldName(x Expr) *Ident {
+ switch t := x.(type) {
case *Ident:
- return t.IsExported()
- case *ParenExpr:
- return isExportedType(t.X)
+ return t
case *SelectorExpr:
- // assume t.X is a typename
- return t.Sel.IsExported()
+ if _, ok := t.X.(*Ident); ok {
+ return t.Sel
+ }
case *StarExpr:
- return isExportedType(t.X)
+ return fieldName(t.X)
}
- return false
+ return nil
}
-
-func fieldListExports(fields *FieldList, incomplete *bool) {
+func fieldListExports(fields *FieldList) (removedFields bool) {
if fields == nil {
return
}
@@ -53,12 +53,13 @@ func fieldListExports(fields *FieldList, incomplete *bool) {
// fields, so this is not absolutely correct.
// However, this cannot be done w/o complete
// type information.)
- exported = isExportedType(f.Type)
+ name := fieldName(f.Type)
+ exported = name != nil && name.IsExported()
} else {
n := len(f.Names)
f.Names = identListExports(f.Names)
if len(f.Names) < n {
- *incomplete = true
+ removedFields = true
}
exported = len(f.Names) > 0
}
@@ -69,12 +70,12 @@ func fieldListExports(fields *FieldList, incomplete *bool) {
}
}
if j < len(list) {
- *incomplete = true
+ removedFields = true
}
fields.List = list[0:j]
+ return
}
-
func paramListExports(fields *FieldList) {
if fields == nil {
return
@@ -84,18 +85,21 @@ func paramListExports(fields *FieldList) {
}
}
-
func typeExports(typ Expr) {
switch t := typ.(type) {
case *ArrayType:
typeExports(t.Elt)
case *StructType:
- fieldListExports(t.Fields, &t.Incomplete)
+ if fieldListExports(t.Fields) {
+ t.Incomplete = true
+ }
case *FuncType:
paramListExports(t.Params)
paramListExports(t.Results)
case *InterfaceType:
- fieldListExports(t.Methods, &t.Incomplete)
+ if fieldListExports(t.Methods) {
+ t.Incomplete = true
+ }
case *MapType:
typeExports(t.Key)
typeExports(t.Value)
@@ -104,7 +108,6 @@ func typeExports(typ Expr) {
}
}
-
func specExports(spec Spec) bool {
switch s := spec.(type) {
case *ValueSpec:
@@ -122,7 +125,6 @@ func specExports(spec Spec) bool {
return false
}
-
func specListExports(list []Spec) []Spec {
j := 0
for _, s := range list {
@@ -134,7 +136,6 @@ func specListExports(list []Spec) []Spec {
return list[0:j]
}
-
func declExports(decl Decl) bool {
switch d := decl.(type) {
case *GenDecl:
@@ -147,7 +148,6 @@ func declExports(decl Decl) bool {
return false
}
-
// FileExports trims the AST for a Go source file in place such that only
// exported nodes remain: all top-level identifiers which are not exported
// and their associated information (such as type, initial value, or function
@@ -170,7 +170,6 @@ func FileExports(src *File) bool {
return j > 0
}
-
// PackageExports trims the AST for a Go package in place such that only
// exported nodes remain. The pkg.Files list is not changed, so that file
// names and top-level package comments don't get lost.
@@ -188,7 +187,6 @@ func PackageExports(pkg *Package) bool {
return hasExports
}
-
// ----------------------------------------------------------------------------
// General filtering
@@ -205,6 +203,37 @@ func filterIdentList(list []*Ident, f Filter) []*Ident {
return list[0:j]
}
+func filterFieldList(fields *FieldList, filter Filter) (removedFields bool) {
+ if fields == nil {
+ return false
+ }
+ list := fields.List
+ j := 0
+ for _, f := range list {
+ keepField := false
+ if len(f.Names) == 0 {
+ // anonymous field
+ name := fieldName(f.Type)
+ keepField = name != nil && filter(name.Name)
+ } else {
+ n := len(f.Names)
+ f.Names = filterIdentList(f.Names, filter)
+ if len(f.Names) < n {
+ removedFields = true
+ }
+ keepField = len(f.Names) > 0
+ }
+ if keepField {
+ list[j] = f
+ j++
+ }
+ }
+ if j < len(list) {
+ removedFields = true
+ }
+ fields.List = list[0:j]
+ return
+}
func filterSpec(spec Spec, f Filter) bool {
switch s := spec.(type) {
@@ -212,12 +241,25 @@ func filterSpec(spec Spec, f Filter) bool {
s.Names = filterIdentList(s.Names, f)
return len(s.Names) > 0
case *TypeSpec:
- return f(s.Name.Name)
+ if f(s.Name.Name) {
+ return true
+ }
+ switch t := s.Type.(type) {
+ case *StructType:
+ if filterFieldList(t.Fields, f) {
+ t.Incomplete = true
+ }
+ return len(t.Fields.List) > 0
+ case *InterfaceType:
+ if filterFieldList(t.Methods, f) {
+ t.Incomplete = true
+ }
+ return len(t.Methods.List) > 0
+ }
}
return false
}
-
func filterSpecList(list []Spec, f Filter) []Spec {
j := 0
for _, s := range list {
@@ -229,8 +271,14 @@ func filterSpecList(list []Spec, f Filter) []Spec {
return list[0:j]
}
-
-func filterDecl(decl Decl, f Filter) bool {
+// FilterDecl trims the AST for a Go declaration in place by removing
+// all names (including struct field and interface method names, but
+// not from parameter lists) that don't pass through the filter f.
+//
+// FilterDecl returns true if there are any declared names left after
+// filtering; it returns false otherwise.
+//
+func FilterDecl(decl Decl, f Filter) bool {
switch d := decl.(type) {
case *GenDecl:
d.Specs = filterSpecList(d.Specs, f)
@@ -241,12 +289,11 @@ func filterDecl(decl Decl, f Filter) bool {
return false
}
-
// FilterFile trims the AST for a Go file in place by removing all
-// names from top-level declarations (but not from parameter lists
-// or inside types) that don't pass through the filter f. If the
-// declaration is empty afterwards, the declaration is removed from
-// the AST.
+// names from top-level declarations (including struct field and
+// interface method names, but not from parameter lists) that don't
+// pass through the filter f. If the declaration is empty afterwards,
+// the declaration is removed from the AST.
// The File.comments list is not changed.
//
// FilterFile returns true if there are any top-level declarations
@@ -255,7 +302,7 @@ func filterDecl(decl Decl, f Filter) bool {
func FilterFile(src *File, f Filter) bool {
j := 0
for _, d := range src.Decls {
- if filterDecl(d, f) {
+ if FilterDecl(d, f) {
src.Decls[j] = d
j++
}
@@ -264,12 +311,11 @@ func FilterFile(src *File, f Filter) bool {
return j > 0
}
-
// FilterPackage trims the AST for a Go package in place by removing all
-// names from top-level declarations (but not from parameter lists
-// or inside types) that don't pass through the filter f. If the
-// declaration is empty afterwards, the declaration is removed from
-// the AST.
+// names from top-level declarations (including struct field and
+// interface method names, but not from parameter lists) that don't
+// pass through the filter f. If the declaration is empty afterwards,
+// the declaration is removed from the AST.
// The pkg.Files list is not changed, so that file names and top-level
// package comments don't get lost.
//
@@ -286,7 +332,6 @@ func FilterPackage(pkg *Package, f Filter) bool {
return hasDecls
}
-
// ----------------------------------------------------------------------------
// Merging of package files
@@ -306,7 +351,6 @@ const (
//
var separator = &Comment{noPos, "//"}
-
// MergePackageFiles creates a file AST by merging the ASTs of the
// files belonging to a package. The mode flags control merging behavior.
//
diff --git a/libgo/go/go/ast/print.go b/libgo/go/go/ast/print.go
index 81e1da1d0aa..62a30481d5c 100644
--- a/libgo/go/go/ast/print.go
+++ b/libgo/go/go/ast/print.go
@@ -14,11 +14,9 @@ import (
"reflect"
)
-
// A FieldFilter may be provided to Fprint to control the output.
type FieldFilter func(name string, value reflect.Value) bool
-
// NotNilFilter returns true for field values that are not nil;
// it returns false otherwise.
func NotNilFilter(_ string, v reflect.Value) bool {
@@ -29,7 +27,6 @@ func NotNilFilter(_ string, v reflect.Value) bool {
return true
}
-
// Fprint prints the (sub-)tree starting at AST node x to w.
// If fset != nil, position information is interpreted relative
// to that file set. Otherwise positions are printed as integer
@@ -68,14 +65,12 @@ func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n i
return
}
-
// Print prints x to standard output, skipping nil fields.
// Print(fset, x) is the same as Fprint(os.Stdout, fset, x, NotNilFilter).
func Print(fset *token.FileSet, x interface{}) (int, os.Error) {
return Fprint(os.Stdout, fset, x, NotNilFilter)
}
-
type printer struct {
output io.Writer
fset *token.FileSet
@@ -87,7 +82,6 @@ type printer struct {
line int // current line number
}
-
var indent = []byte(". ")
func (p *printer) Write(data []byte) (n int, err os.Error) {
@@ -120,14 +114,12 @@ func (p *printer) Write(data []byte) (n int, err os.Error) {
return
}
-
// localError wraps locally caught os.Errors so we can distinguish
// them from genuine panics which we don't want to return as errors.
type localError struct {
err os.Error
}
-
// printf is a convenience wrapper that takes care of print errors.
func (p *printer) printf(format string, args ...interface{}) {
n, err := fmt.Fprintf(p, format, args...)
@@ -137,7 +129,6 @@ func (p *printer) printf(format string, args ...interface{}) {
}
}
-
// Implementation note: Print is written for AST nodes but could be
// used to print arbitrary data structures; such a version should
// probably be in a different package.
diff --git a/libgo/go/go/ast/print_test.go b/libgo/go/go/ast/print_test.go
index 0820dcfcef2..f4e8f7a78f7 100644
--- a/libgo/go/go/ast/print_test.go
+++ b/libgo/go/go/ast/print_test.go
@@ -10,7 +10,6 @@ import (
"testing"
)
-
var tests = []struct {
x interface{} // x is printed as s
s string
@@ -49,11 +48,10 @@ var tests = []struct {
3 }`},
}
-
// Split s into lines, trim whitespace from all lines, and return
// the concatenated non-empty lines.
func trim(s string) string {
- lines := strings.Split(s, "\n", -1)
+ lines := strings.Split(s, "\n")
i := 0
for _, line := range lines {
line = strings.TrimSpace(line)
@@ -65,7 +63,6 @@ func trim(s string) string {
return strings.Join(lines[0:i], "\n")
}
-
func TestPrint(t *testing.T) {
var buf bytes.Buffer
for _, test := range tests {
diff --git a/libgo/go/go/ast/resolve.go b/libgo/go/go/ast/resolve.go
index fddc3baab86..3927a799e0a 100644
--- a/libgo/go/go/ast/resolve.go
+++ b/libgo/go/go/ast/resolve.go
@@ -11,25 +11,22 @@ import (
"go/scanner"
"go/token"
"os"
+ "strconv"
)
-
type pkgBuilder struct {
scanner.ErrorVector
fset *token.FileSet
}
-
func (p *pkgBuilder) error(pos token.Pos, msg string) {
p.Error(p.fset.Position(pos), msg)
}
-
func (p *pkgBuilder) errorf(pos token.Pos, format string, args ...interface{}) {
p.error(pos, fmt.Sprintf(format, args...))
}
-
func (p *pkgBuilder) declare(scope, altScope *Scope, obj *Object) {
alt := scope.Insert(obj)
if alt == nil && altScope != nil {
@@ -45,7 +42,6 @@ func (p *pkgBuilder) declare(scope, altScope *Scope, obj *Object) {
}
}
-
func resolve(scope *Scope, ident *Ident) bool {
for ; scope != nil; scope = scope.Outer {
if obj := scope.Lookup(ident.Name); obj != nil {
@@ -56,13 +52,16 @@ func resolve(scope *Scope, ident *Ident) bool {
return false
}
-
-// NewPackage uses an Importer to resolve imports. Given an importPath,
-// an importer returns the imported package's name, its scope of exported
-// objects, and an error, if any.
-//
-type Importer func(path string) (name string, scope *Scope, err os.Error)
-
+// An Importer resolves import paths to package Objects.
+// The imports map records the packages already imported,
+// indexed by package id (canonical import path).
+// An Importer must determine the canonical import path and
+// check the map to see if it is already present in the imports map.
+// If so, the Importer can return the map entry. Otherwise, the
+// Importer should load the package data for the given path into
+// a new *Object (pkg), record pkg in the imports map, and then
+// return pkg.
+type Importer func(imports map[string]*Object, path string) (pkg *Object, err os.Error)
// NewPackage creates a new Package node from a set of File nodes. It resolves
// unresolved identifiers across files and updates each file's Unresolved list
@@ -70,7 +69,7 @@ type Importer func(path string) (name string, scope *Scope, err os.Error)
// used to resolve identifiers not declared in any of the package files. Any
// remaining unresolved identifiers are reported as undeclared. If the files
// belong to different packages, one package name is selected and files with
-// different package name are reported and then ignored.
+// different package names are reported and then ignored.
// The result is a package node and a scanner.ErrorList if there were errors.
//
func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, universe *Scope) (*Package, os.Error) {
@@ -96,14 +95,8 @@ func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer,
}
}
- // imports maps import paths to package names and scopes
- // TODO(gri): Eventually we like to get to the import scope from
- // a package object. Then we can have a map path -> Obj.
- type importedPkg struct {
- name string
- scope *Scope
- }
- imports := make(map[string]*importedPkg)
+ // package global mapping of imported package ids to package objects
+ imports := make(map[string]*Object)
// complete file scopes with imports and resolve identifiers
for _, file := range files {
@@ -117,42 +110,41 @@ func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer,
importErrors := false
fileScope := NewScope(pkgScope)
for _, spec := range file.Imports {
- // add import to global map of imports
- path := string(spec.Path.Value)
- path = path[1 : len(path)-1] // strip ""'s
- pkg := imports[path]
- if pkg == nil {
- if importer == nil {
- importErrors = true
- continue
- }
- name, scope, err := importer(path)
- if err != nil {
- p.errorf(spec.Path.Pos(), "could not import %s (%s)", path, err)
- importErrors = true
- continue
- }
- pkg = &importedPkg{name, scope}
- imports[path] = pkg
- // TODO(gri) If a local package name != "." is provided,
- // global identifier resolution could proceed even if the
- // import failed. Consider adjusting the logic here a bit.
+ if importer == nil {
+ importErrors = true
+ continue
+ }
+ path, _ := strconv.Unquote(string(spec.Path.Value))
+ pkg, err := importer(imports, path)
+ if err != nil {
+ p.errorf(spec.Path.Pos(), "could not import %s (%s)", path, err)
+ importErrors = true
+ continue
}
+ // TODO(gri) If a local package name != "." is provided,
+ // global identifier resolution could proceed even if the
+ // import failed. Consider adjusting the logic here a bit.
+
// local name overrides imported package name
- name := pkg.name
+ name := pkg.Name
if spec.Name != nil {
name = spec.Name.Name
}
+
// add import to file scope
if name == "." {
// merge imported scope with file scope
- for _, obj := range pkg.scope.Objects {
+ for _, obj := range pkg.Data.(*Scope).Objects {
p.declare(fileScope, pkgScope, obj)
}
} else {
// declare imported package object in file scope
+ // (do not re-use pkg in the file scope but create
+ // a new object instead; the Decl field is different
+ // for different files)
obj := NewObj(Pkg, name)
obj.Decl = spec
+ obj.Data = pkg.Data
p.declare(fileScope, pkgScope, obj)
}
}
@@ -161,8 +153,8 @@ func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer,
if importErrors {
// don't use the universe scope without correct imports
// (objects in the universe may be shadowed by imports;
- // with missing imports identifiers might get resolved
- // wrongly)
+ // with missing imports, identifiers might get resolved
+ // incorrectly to universe objects)
pkgScope.Outer = nil
}
i := 0
@@ -178,11 +170,5 @@ func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer,
pkgScope.Outer = universe // reset universe scope
}
- // collect all import paths and respective package scopes
- importedScopes := make(map[string]*Scope)
- for path, pkg := range imports {
- importedScopes[path] = pkg.scope
- }
-
- return &Package{pkgName, pkgScope, importedScopes, files}, p.GetError(scanner.Sorted)
+ return &Package{pkgName, pkgScope, imports, files}, p.GetError(scanner.Sorted)
}
diff --git a/libgo/go/go/ast/scope.go b/libgo/go/go/ast/scope.go
index 830d88aef4a..92e36698081 100644
--- a/libgo/go/go/ast/scope.go
+++ b/libgo/go/go/ast/scope.go
@@ -12,7 +12,6 @@ import (
"go/token"
)
-
// A Scope maintains the set of named language entities declared
// in the scope and a link to the immediately surrounding (outer)
// scope.
@@ -22,14 +21,12 @@ type Scope struct {
Objects map[string]*Object
}
-
// NewScope creates a new scope nested in the outer scope.
func NewScope(outer *Scope) *Scope {
const n = 4 // initial scope capacity
return &Scope{outer, make(map[string]*Object, n)}
}
-
// Lookup returns the object with the given name if it is
// found in scope s, otherwise it returns nil. Outer scopes
// are ignored.
@@ -38,7 +35,6 @@ func (s *Scope) Lookup(name string) *Object {
return s.Objects[name]
}
-
// Insert attempts to insert a named object obj into the scope s.
// If the scope already contains an object alt with the same name,
// Insert leaves the scope unchanged and returns alt. Otherwise
@@ -51,7 +47,6 @@ func (s *Scope) Insert(obj *Object) (alt *Object) {
return
}
-
// Debugging support
func (s *Scope) String() string {
var buf bytes.Buffer
@@ -66,27 +61,35 @@ func (s *Scope) String() string {
return buf.String()
}
-
// ----------------------------------------------------------------------------
// Objects
+// TODO(gri) Consider replacing the Object struct with an interface
+// and a corresponding set of object implementations.
+
// An Object describes a named language entity such as a package,
// constant, type, variable, function (incl. methods), or label.
//
+// The Data fields contains object-specific data:
+//
+// Kind Data type Data value
+// Pkg *Scope package scope
+// Con int iota for the respective declaration
+// Con != nil constant value
+//
type Object struct {
Kind ObjKind
Name string // declared name
Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil
+ Data interface{} // object-specific data; or nil
Type interface{} // place holder for type information; may be nil
}
-
// NewObj creates a new object of a given kind and name.
func NewObj(kind ObjKind, name string) *Object {
return &Object{Kind: kind, Name: name}
}
-
// Pos computes the source position of the declaration of an object name.
// The result may be an invalid position if it cannot be computed
// (obj.Decl may be nil or not correct).
@@ -126,7 +129,6 @@ func (obj *Object) Pos() token.Pos {
return token.NoPos
}
-
// ObKind describes what an object represents.
type ObjKind int
@@ -141,7 +143,6 @@ const (
Lbl // label
)
-
var objKindStrings = [...]string{
Bad: "bad",
Pkg: "package",
@@ -152,5 +153,4 @@ var objKindStrings = [...]string{
Lbl: "label",
}
-
func (kind ObjKind) String() string { return objKindStrings[kind] }
diff --git a/libgo/go/go/ast/walk.go b/libgo/go/go/ast/walk.go
index 95c4b3a3564..181cfd1491a 100644
--- a/libgo/go/go/ast/walk.go
+++ b/libgo/go/go/ast/walk.go
@@ -13,7 +13,6 @@ type Visitor interface {
Visit(node Node) (w Visitor)
}
-
// Helper functions for common node lists. They may be empty.
func walkIdentList(v Visitor, list []*Ident) {
@@ -22,28 +21,24 @@ func walkIdentList(v Visitor, list []*Ident) {
}
}
-
func walkExprList(v Visitor, list []Expr) {
for _, x := range list {
Walk(v, x)
}
}
-
func walkStmtList(v Visitor, list []Stmt) {
for _, x := range list {
Walk(v, x)
}
}
-
func walkDeclList(v Visitor, list []Decl) {
for _, x := range list {
Walk(v, x)
}
}
-
// TODO(gri): Investigate if providing a closure to Walk leads to
// simpler use (and may help eliminate Inspect in turn).
@@ -369,7 +364,6 @@ func Walk(v Visitor, node Node) {
v.Visit(nil)
}
-
type inspector func(Node) bool
func (f inspector) Visit(node Node) Visitor {
@@ -379,7 +373,6 @@ func (f inspector) Visit(node Node) Visitor {
return nil
}
-
// Inspect traverses an AST in depth-first order: It starts by calling
// f(node); node must not be nil. If f returns true, Inspect invokes f
// for all the non-nil children of node, recursively.
diff --git a/libgo/go/go/build/build.go b/libgo/go/go/build/build.go
new file mode 100644
index 00000000000..97f92bfb6e7
--- /dev/null
+++ b/libgo/go/go/build/build.go
@@ -0,0 +1,444 @@
+// Copyright 2011 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 build provides tools for building Go packages.
+package build
+
+import (
+ "bytes"
+ "exec"
+ "fmt"
+ "os"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strings"
+)
+
+// Build produces a build Script for the given package.
+func Build(tree *Tree, pkg string, info *DirInfo) (*Script, os.Error) {
+ s := &Script{}
+ b := &build{
+ script: s,
+ path: filepath.Join(tree.SrcDir(), pkg),
+ }
+ b.obj = b.abs("_obj") + string(filepath.Separator)
+
+ b.goarch = runtime.GOARCH
+ if g := os.Getenv("GOARCH"); g != "" {
+ b.goarch = g
+ }
+ var err os.Error
+ b.arch, err = ArchChar(b.goarch)
+ if err != nil {
+ return nil, err
+ }
+
+ // add import object files to list of Inputs
+ for _, pkg := range info.Imports {
+ t, p, err := FindTree(pkg)
+ if err != nil && err != ErrNotFound {
+ // FindTree should always be able to suggest an import
+ // path and tree. The path must be malformed
+ // (for example, an absolute or relative path).
+ return nil, os.NewError("build: invalid import: " + pkg)
+ }
+ s.addInput(filepath.Join(t.PkgDir(), p+".a"))
+ }
+
+ // .go files to be built with gc
+ gofiles := b.abss(info.GoFiles...)
+ s.addInput(gofiles...)
+
+ var ofiles []string // object files to be linked or packed
+
+ // make build directory
+ b.mkdir(b.obj)
+ s.addIntermediate(b.obj)
+
+ // cgo
+ if len(info.CgoFiles) > 0 {
+ cgoFiles := b.abss(info.CgoFiles...)
+ s.addInput(cgoFiles...)
+ cgoCFiles := b.abss(info.CFiles...)
+ s.addInput(cgoCFiles...)
+ outGo, outObj := b.cgo(cgoFiles, cgoCFiles)
+ gofiles = append(gofiles, outGo...)
+ ofiles = append(ofiles, outObj...)
+ s.addIntermediate(outGo...)
+ s.addIntermediate(outObj...)
+ }
+
+ // compile
+ if len(gofiles) > 0 {
+ ofile := b.obj + "_go_." + b.arch
+ b.gc(ofile, gofiles...)
+ ofiles = append(ofiles, ofile)
+ s.addIntermediate(ofile)
+ }
+
+ // assemble
+ for _, sfile := range info.SFiles {
+ ofile := b.obj + sfile[:len(sfile)-1] + b.arch
+ sfile = b.abs(sfile)
+ s.addInput(sfile)
+ b.asm(ofile, sfile)
+ ofiles = append(ofiles, ofile)
+ s.addIntermediate(ofile)
+ }
+
+ if len(ofiles) == 0 {
+ return nil, os.NewError("make: no object files to build")
+ }
+
+ // choose target file
+ var targ string
+ if info.IsCommand() {
+ // use the last part of the import path as binary name
+ _, bin := filepath.Split(pkg)
+ if runtime.GOOS == "windows" {
+ bin += ".exe"
+ }
+ targ = filepath.Join(tree.BinDir(), bin)
+ } else {
+ targ = filepath.Join(tree.PkgDir(), pkg+".a")
+ }
+
+ // make target directory
+ targDir, _ := filepath.Split(targ)
+ b.mkdir(targDir)
+
+ // link binary or pack object
+ if info.IsCommand() {
+ b.ld(targ, ofiles...)
+ } else {
+ b.gopack(targ, ofiles...)
+ }
+ s.Output = append(s.Output, targ)
+
+ return b.script, nil
+}
+
+// A Script describes the build process for a Go package.
+// The Input, Intermediate, and Output fields are lists of absolute paths.
+type Script struct {
+ Cmd []*Cmd
+ Input []string
+ Intermediate []string
+ Output []string
+}
+
+func (s *Script) addInput(file ...string) {
+ s.Input = append(s.Input, file...)
+}
+
+func (s *Script) addIntermediate(file ...string) {
+ s.Intermediate = append(s.Intermediate, file...)
+}
+
+// Run runs the Script's Cmds in order.
+func (s *Script) Run() os.Error {
+ for _, c := range s.Cmd {
+ if err := c.Run(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Stale returns true if the build's inputs are newer than its outputs.
+func (s *Script) Stale() bool {
+ var latest int64
+ // get latest mtime of outputs
+ for _, file := range s.Output {
+ fi, err := os.Stat(file)
+ if err != nil {
+ // any error reading output files means stale
+ return true
+ }
+ if m := fi.Mtime_ns; m > latest {
+ latest = m
+ }
+ }
+ for _, file := range s.Input {
+ fi, err := os.Stat(file)
+ if err != nil || fi.Mtime_ns > latest {
+ // any error reading input files means stale
+ // (attempt to rebuild to figure out why)
+ return true
+ }
+ }
+ return false
+}
+
+// Clean removes the Script's Intermediate files.
+// It tries to remove every file and returns the first error it encounters.
+func (s *Script) Clean() (err os.Error) {
+ // Reverse order so that directories get removed after the files they contain.
+ for i := len(s.Intermediate) - 1; i >= 0; i-- {
+ if e := os.Remove(s.Intermediate[i]); err == nil {
+ err = e
+ }
+ }
+ return
+}
+
+// Nuke removes the Script's Intermediate and Output files.
+// It tries to remove every file and returns the first error it encounters.
+func (s *Script) Nuke() (err os.Error) {
+ // Reverse order so that directories get removed after the files they contain.
+ for i := len(s.Output) - 1; i >= 0; i-- {
+ if e := os.Remove(s.Output[i]); err == nil {
+ err = e
+ }
+ }
+ if e := s.Clean(); err == nil {
+ err = e
+ }
+ return
+}
+
+// A Cmd describes an individual build command.
+type Cmd struct {
+ Args []string // command-line
+ Stdout string // write standard output to this file, "" is passthrough
+ Dir string // working directory
+ Env []string // environment
+ Input []string // file paths (dependencies)
+ Output []string // file paths
+}
+
+func (c *Cmd) String() string {
+ return strings.Join(c.Args, " ")
+}
+
+// Run executes the Cmd.
+func (c *Cmd) Run() os.Error {
+ if c.Args[0] == "mkdir" {
+ for _, p := range c.Output {
+ if err := os.MkdirAll(p, 0777); err != nil {
+ return fmt.Errorf("command %q: %v", c, err)
+ }
+ }
+ return nil
+ }
+ out := new(bytes.Buffer)
+ cmd := exec.Command(c.Args[0], c.Args[1:]...)
+ cmd.Dir = c.Dir
+ cmd.Env = c.Env
+ cmd.Stdout = out
+ cmd.Stderr = out
+ if c.Stdout != "" {
+ f, err := os.Create(c.Stdout)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ cmd.Stdout = f
+ }
+ if err := cmd.Run(); err != nil {
+ return fmt.Errorf("command %q: %v\n%v", c, err, out)
+ }
+ return nil
+}
+
+// ArchChar returns the architecture character for the given goarch.
+// For example, ArchChar("amd64") returns "6".
+func ArchChar(goarch string) (string, os.Error) {
+ switch goarch {
+ case "386":
+ return "8", nil
+ case "amd64":
+ return "6", nil
+ case "arm":
+ return "5", nil
+ }
+ return "", os.NewError("unsupported GOARCH " + goarch)
+}
+
+type build struct {
+ script *Script
+ path string
+ obj string
+ goarch string
+ arch string
+}
+
+func (b *build) abs(file string) string {
+ if filepath.IsAbs(file) {
+ return file
+ }
+ return filepath.Join(b.path, file)
+}
+
+func (b *build) abss(file ...string) []string {
+ s := make([]string, len(file))
+ for i, f := range file {
+ s[i] = b.abs(f)
+ }
+ return s
+}
+
+func (b *build) add(c Cmd) {
+ b.script.Cmd = append(b.script.Cmd, &c)
+}
+
+func (b *build) mkdir(name string) {
+ b.add(Cmd{
+ Args: []string{"mkdir", "-p", name},
+ Output: []string{name},
+ })
+}
+
+func (b *build) gc(ofile string, gofiles ...string) {
+ gc := b.arch + "g"
+ args := append([]string{gc, "-o", ofile}, gcImportArgs...)
+ args = append(args, gofiles...)
+ b.add(Cmd{
+ Args: args,
+ Input: gofiles,
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) asm(ofile string, sfile string) {
+ asm := b.arch + "a"
+ b.add(Cmd{
+ Args: []string{asm, "-o", ofile, sfile},
+ Input: []string{sfile},
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) ld(targ string, ofiles ...string) {
+ ld := b.arch + "l"
+ args := append([]string{ld, "-o", targ}, ldImportArgs...)
+ args = append(args, ofiles...)
+ b.add(Cmd{
+ Args: args,
+ Input: ofiles,
+ Output: []string{targ},
+ })
+}
+
+func (b *build) gopack(targ string, ofiles ...string) {
+ b.add(Cmd{
+ Args: append([]string{"gopack", "grc", targ}, ofiles...),
+ Input: ofiles,
+ Output: []string{targ},
+ })
+}
+
+func (b *build) cc(ofile string, cfiles ...string) {
+ cc := b.arch + "c"
+ dir := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH)
+ inc := filepath.Join(runtime.GOROOT(), "pkg", dir)
+ args := []string{cc, "-FVw", "-I", inc, "-o", ofile}
+ b.add(Cmd{
+ Args: append(args, cfiles...),
+ Input: cfiles,
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) gccCompile(ofile, cfile string) {
+ b.add(Cmd{
+ Args: b.gccArgs("-o", ofile, "-c", cfile),
+ Input: []string{cfile},
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) gccLink(ofile string, ofiles ...string) {
+ b.add(Cmd{
+ Args: append(b.gccArgs("-o", ofile), ofiles...),
+ Input: ofiles,
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) gccArgs(args ...string) []string {
+ // TODO(adg): HOST_CC
+ a := []string{"gcc", "-I", b.path, "-g", "-fPIC", "-O2"}
+ switch b.arch {
+ case "8":
+ a = append(a, "-m32")
+ case "6":
+ a = append(a, "-m64")
+ }
+ return append(a, args...)
+}
+
+var cgoRe = regexp.MustCompile(`[/\\:]`)
+
+func (b *build) cgo(cgofiles, cgocfiles []string) (outGo, outObj []string) {
+ // cgo
+ // TODO(adg): CGOPKGPATH
+ // TODO(adg): CGO_FLAGS
+ gofiles := []string{b.obj + "_cgo_gotypes.go"}
+ cfiles := []string{b.obj + "_cgo_main.c", b.obj + "_cgo_export.c"}
+ for _, fn := range cgofiles {
+ f := b.obj + cgoRe.ReplaceAllString(fn[:len(fn)-2], "_")
+ gofiles = append(gofiles, f+"cgo1.go")
+ cfiles = append(cfiles, f+"cgo2.c")
+ }
+ defunC := b.obj + "_cgo_defun.c"
+ output := append([]string{defunC}, cfiles...)
+ output = append(output, gofiles...)
+ b.add(Cmd{
+ Args: append([]string{"cgo", "--"}, cgofiles...),
+ Dir: b.path,
+ Env: append(os.Environ(), "GOARCH="+b.goarch),
+ Input: cgofiles,
+ Output: output,
+ })
+ outGo = append(outGo, gofiles...)
+ exportH := filepath.Join(b.path, "_cgo_export.h")
+ b.script.addIntermediate(defunC, exportH, b.obj+"_cgo_flags")
+ b.script.addIntermediate(cfiles...)
+
+ // cc _cgo_defun.c
+ defunObj := b.obj + "_cgo_defun." + b.arch
+ b.cc(defunObj, defunC)
+ outObj = append(outObj, defunObj)
+
+ // gcc
+ linkobj := make([]string, 0, len(cfiles))
+ for _, cfile := range cfiles {
+ ofile := cfile[:len(cfile)-1] + "o"
+ b.gccCompile(ofile, cfile)
+ linkobj = append(linkobj, ofile)
+ if !strings.HasSuffix(ofile, "_cgo_main.o") {
+ outObj = append(outObj, ofile)
+ } else {
+ b.script.addIntermediate(ofile)
+ }
+ }
+ for _, cfile := range cgocfiles {
+ ofile := b.obj + cgoRe.ReplaceAllString(cfile[:len(cfile)-1], "_") + "o"
+ b.gccCompile(ofile, cfile)
+ linkobj = append(linkobj, ofile)
+ outObj = append(outObj, ofile)
+ }
+ dynObj := b.obj + "_cgo_.o"
+ b.gccLink(dynObj, linkobj...)
+ b.script.addIntermediate(dynObj)
+
+ // cgo -dynimport
+ importC := b.obj + "_cgo_import.c"
+ b.add(Cmd{
+ Args: []string{"cgo", "-dynimport", dynObj},
+ Stdout: importC,
+ Input: []string{dynObj},
+ Output: []string{importC},
+ })
+ b.script.addIntermediate(importC)
+
+ // cc _cgo_import.ARCH
+ importObj := b.obj + "_cgo_import." + b.arch
+ b.cc(importObj, importC)
+ outObj = append(outObj, importObj)
+
+ return
+}
diff --git a/libgo/go/go/build/build_test.go b/libgo/go/go/build/build_test.go
new file mode 100644
index 00000000000..e59d87672ca
--- /dev/null
+++ b/libgo/go/go/build/build_test.go
@@ -0,0 +1,61 @@
+// Copyright 2011 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 build
+
+import (
+ "exec"
+ "path/filepath"
+ "testing"
+)
+
+var buildPkgs = []string{
+ "go/build/pkgtest",
+ "go/build/cmdtest",
+ "go/build/cgotest",
+}
+
+const cmdtestOutput = "3"
+
+func TestBuild(t *testing.T) {
+ for _, pkg := range buildPkgs {
+ tree := Path[0] // Goroot
+ dir := filepath.Join(tree.SrcDir(), pkg)
+
+ info, err := ScanDir(dir, true)
+ if err != nil {
+ t.Error("ScanDir:", err)
+ continue
+ }
+
+ s, err := Build(tree, pkg, info)
+ if err != nil {
+ t.Error("Build:", err)
+ continue
+ }
+
+ if err := s.Run(); err != nil {
+ t.Error("Run:", err)
+ continue
+ }
+
+ if pkg == "go/build/cmdtest" {
+ bin := s.Output[0]
+ b, err := exec.Command(bin).CombinedOutput()
+ if err != nil {
+ t.Errorf("exec: %s: %v", bin, err)
+ continue
+ }
+ if string(b) != cmdtestOutput {
+ t.Errorf("cmdtest output: %s want: %s", b, cmdtestOutput)
+ }
+ }
+
+ defer func(s *Script) {
+ if err := s.Nuke(); err != nil {
+ t.Errorf("nuking: %v", err)
+ }
+ }(s)
+ }
+}
diff --git a/libgo/go/go/build/cgotest/cgotest.go b/libgo/go/go/build/cgotest/cgotest.go
new file mode 100644
index 00000000000..93bbf06883f
--- /dev/null
+++ b/libgo/go/go/build/cgotest/cgotest.go
@@ -0,0 +1,19 @@
+// Copyright 2011 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 cgotest
+
+/*
+char* greeting = "hello, world";
+*/
+// #include "cgotest.h"
+import "C"
+import "unsafe"
+
+var Greeting = C.GoString(C.greeting)
+
+func DoAdd(x, y int) (sum int) {
+ C.Add(C.int(x), C.int(y), (*C.int)(unsafe.Pointer(&sum)))
+ return
+}
diff --git a/libgo/go/go/build/cmdtest/main.go b/libgo/go/go/build/cmdtest/main.go
new file mode 100644
index 00000000000..bed4f485a0a
--- /dev/null
+++ b/libgo/go/go/build/cmdtest/main.go
@@ -0,0 +1,12 @@
+// Copyright 2011 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 main
+
+import "go/build/pkgtest"
+
+func main() {
+ pkgtest.Foo()
+ print(int(pkgtest.Sqrt(9)))
+}
diff --git a/libgo/go/go/build/dir.go b/libgo/go/go/build/dir.go
new file mode 100644
index 00000000000..e0000b53446
--- /dev/null
+++ b/libgo/go/go/build/dir.go
@@ -0,0 +1,172 @@
+// Copyright 2011 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 build
+
+import (
+ "go/parser"
+ "go/token"
+ "log"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "runtime"
+)
+
+type DirInfo struct {
+ GoFiles []string // .go files in dir (excluding CgoFiles)
+ CgoFiles []string // .go files that import "C"
+ CFiles []string // .c files in dir
+ SFiles []string // .s files in dir
+ Imports []string // All packages imported by goFiles
+ PkgName string // Name of package in dir
+}
+
+func (d *DirInfo) IsCommand() bool {
+ return d.PkgName == "main"
+}
+
+// ScanDir returns a structure with details about the Go content found
+// in the given directory. The file lists exclude:
+//
+// - files in package main (unless allowMain is true)
+// - files in package documentation
+// - files ending in _test.go
+// - files starting with _ or .
+//
+// Only files that satisfy the goodOSArch function are included.
+func ScanDir(dir string, allowMain bool) (info *DirInfo, err os.Error) {
+ f, err := os.Open(dir)
+ if err != nil {
+ return nil, err
+ }
+ dirs, err := f.Readdir(-1)
+ f.Close()
+ if err != nil {
+ return nil, err
+ }
+
+ var di DirInfo
+ imported := make(map[string]bool)
+ fset := token.NewFileSet()
+ for i := range dirs {
+ d := &dirs[i]
+ if strings.HasPrefix(d.Name, "_") ||
+ strings.HasPrefix(d.Name, ".") {
+ continue
+ }
+ if !goodOSArch(d.Name) {
+ continue
+ }
+
+ switch filepath.Ext(d.Name) {
+ case ".go":
+ if strings.HasSuffix(d.Name, "_test.go") {
+ continue
+ }
+ case ".c":
+ di.CFiles = append(di.CFiles, d.Name)
+ continue
+ case ".s":
+ di.SFiles = append(di.SFiles, d.Name)
+ continue
+ default:
+ continue
+ }
+
+ filename := filepath.Join(dir, d.Name)
+ pf, err := parser.ParseFile(fset, filename, nil, parser.ImportsOnly)
+ if err != nil {
+ return nil, err
+ }
+ s := string(pf.Name.Name)
+ if s == "main" && !allowMain {
+ continue
+ }
+ if s == "documentation" {
+ continue
+ }
+ if di.PkgName == "" {
+ di.PkgName = s
+ } else if di.PkgName != s {
+ // Only if all files in the directory are in package main
+ // do we return PkgName=="main".
+ // A mix of main and another package reverts
+ // to the original (allowMain=false) behaviour.
+ if s == "main" || di.PkgName == "main" {
+ return ScanDir(dir, false)
+ }
+ return nil, os.NewError("multiple package names in " + dir)
+ }
+ isCgo := false
+ for _, spec := range pf.Imports {
+ quoted := string(spec.Path.Value)
+ path, err := strconv.Unquote(quoted)
+ if err != nil {
+ log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
+ }
+ imported[path] = true
+ if path == "C" {
+ isCgo = true
+ }
+ }
+ if isCgo {
+ di.CgoFiles = append(di.CgoFiles, d.Name)
+ } else {
+ di.GoFiles = append(di.GoFiles, d.Name)
+ }
+ }
+ di.Imports = make([]string, len(imported))
+ i := 0
+ for p := range imported {
+ di.Imports[i] = p
+ i++
+ }
+ return &di, nil
+}
+
+// goodOSArch returns false if the filename contains a $GOOS or $GOARCH
+// suffix which does not match the current system.
+// The recognized filename formats are:
+//
+// name_$(GOOS).*
+// name_$(GOARCH).*
+// name_$(GOOS)_$(GOARCH).*
+//
+func goodOSArch(filename string) bool {
+ if dot := strings.Index(filename, "."); dot != -1 {
+ filename = filename[:dot]
+ }
+ l := strings.Split(filename, "_")
+ n := len(l)
+ if n == 0 {
+ return true
+ }
+ if good, known := goodOS[l[n-1]]; known {
+ return good
+ }
+ if good, known := goodArch[l[n-1]]; known {
+ if !good || n < 2 {
+ return false
+ }
+ good, known = goodOS[l[n-2]]
+ return good || !known
+ }
+ return true
+}
+
+var goodOS = make(map[string]bool)
+var goodArch = make(map[string]bool)
+
+func init() {
+ goodOS = make(map[string]bool)
+ goodArch = make(map[string]bool)
+ for _, v := range strings.Fields(goosList) {
+ goodOS[v] = v == runtime.GOOS
+ }
+ for _, v := range strings.Fields(goarchList) {
+ goodArch[v] = v == runtime.GOARCH
+ }
+}
diff --git a/libgo/go/go/build/path.go b/libgo/go/go/build/path.go
new file mode 100644
index 00000000000..e39b5f8fa57
--- /dev/null
+++ b/libgo/go/go/build/path.go
@@ -0,0 +1,182 @@
+// Copyright 2011 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 build
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+ "runtime"
+)
+
+// Path is a validated list of Trees derived from $GOROOT and $GOPATH at init.
+var Path []*Tree
+
+// Tree describes a Go source tree, either $GOROOT or one from $GOPATH.
+type Tree struct {
+ Path string
+ Goroot bool
+}
+
+func newTree(p string) (*Tree, os.Error) {
+ if !filepath.IsAbs(p) {
+ return nil, os.NewError("must be absolute")
+ }
+ ep, err := filepath.EvalSymlinks(p)
+ if err != nil {
+ return nil, err
+ }
+ return &Tree{Path: ep}, nil
+}
+
+// SrcDir returns the tree's package source directory.
+func (t *Tree) SrcDir() string {
+ if t.Goroot {
+ return filepath.Join(t.Path, "src", "pkg")
+ }
+ return filepath.Join(t.Path, "src")
+}
+
+// PkgDir returns the tree's package object directory.
+func (t *Tree) PkgDir() string {
+ goos, goarch := runtime.GOOS, runtime.GOARCH
+ if e := os.Getenv("GOOS"); e != "" {
+ goos = e
+ }
+ if e := os.Getenv("GOARCH"); e != "" {
+ goarch = e
+ }
+ return filepath.Join(t.Path, "pkg", goos+"_"+goarch)
+}
+
+// BinDir returns the tree's binary executable directory.
+func (t *Tree) BinDir() string {
+ if t.Goroot {
+ if gobin := os.Getenv("GOBIN"); gobin != "" {
+ return gobin
+ }
+ }
+ return filepath.Join(t.Path, "bin")
+}
+
+// HasSrc returns whether the given package's
+// source can be found inside this Tree.
+func (t *Tree) HasSrc(pkg string) bool {
+ fi, err := os.Stat(filepath.Join(t.SrcDir(), pkg))
+ if err != nil {
+ return false
+ }
+ return fi.IsDirectory()
+}
+
+// HasPkg returns whether the given package's
+// object file can be found inside this Tree.
+func (t *Tree) HasPkg(pkg string) bool {
+ fi, err := os.Stat(filepath.Join(t.PkgDir(), pkg+".a"))
+ if err != nil {
+ return false
+ }
+ return fi.IsRegular()
+ // TODO(adg): check object version is consistent
+}
+
+var (
+ ErrNotFound = os.NewError("go/build: package could not be found locally")
+ ErrTreeNotFound = os.NewError("go/build: no valid GOROOT or GOPATH could be found")
+)
+
+// FindTree takes an import or filesystem path and returns the
+// tree where the package source should be and the package import path.
+func FindTree(path string) (tree *Tree, pkg string, err os.Error) {
+ if isLocalPath(path) {
+ if path, err = filepath.Abs(path); err != nil {
+ return
+ }
+ if path, err = filepath.EvalSymlinks(path); err != nil {
+ return
+ }
+ for _, t := range Path {
+ tpath := t.SrcDir() + string(filepath.Separator)
+ if !filepath.HasPrefix(path, tpath) {
+ continue
+ }
+ tree = t
+ pkg = path[len(tpath):]
+ return
+ }
+ err = fmt.Errorf("path %q not inside a GOPATH", path)
+ return
+ }
+ tree = defaultTree
+ pkg = path
+ for _, t := range Path {
+ if t.HasSrc(pkg) {
+ tree = t
+ return
+ }
+ }
+ if tree == nil {
+ err = ErrTreeNotFound
+ } else {
+ err = ErrNotFound
+ }
+ return
+}
+
+// isLocalPath returns whether the given path is local (/foo ./foo ../foo . ..)
+// Windows paths that starts with drive letter (c:\foo c:foo) are considered local.
+func isLocalPath(s string) bool {
+ const sep = string(filepath.Separator)
+ return s == "." || s == ".." ||
+ filepath.HasPrefix(s, sep) ||
+ filepath.HasPrefix(s, "."+sep) || filepath.HasPrefix(s, ".."+sep) ||
+ filepath.VolumeName(s) != ""
+}
+
+var (
+ // argument lists used by the build's gc and ld methods
+ gcImportArgs []string
+ ldImportArgs []string
+
+ // default tree for remote packages
+ defaultTree *Tree
+)
+
+// set up Path: parse and validate GOROOT and GOPATH variables
+func init() {
+ root := runtime.GOROOT()
+ t, err := newTree(root)
+ if err != nil {
+ log.Printf("go/build: invalid GOROOT %q: %v", root, err)
+ } else {
+ t.Goroot = true
+ Path = []*Tree{t}
+ }
+
+ for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
+ if p == "" {
+ continue
+ }
+ t, err := newTree(p)
+ if err != nil {
+ log.Printf("go/build: invalid GOPATH %q: %v", p, err)
+ continue
+ }
+ Path = append(Path, t)
+ gcImportArgs = append(gcImportArgs, "-I", t.PkgDir())
+ ldImportArgs = append(ldImportArgs, "-L", t.PkgDir())
+
+ // select first GOPATH entry as default
+ if defaultTree == nil {
+ defaultTree = t
+ }
+ }
+
+ // use GOROOT if no valid GOPATH specified
+ if defaultTree == nil && len(Path) > 0 {
+ defaultTree = Path[0]
+ }
+}
diff --git a/libgo/go/go/build/pkgtest/pkgtest.go b/libgo/go/go/build/pkgtest/pkgtest.go
new file mode 100644
index 00000000000..9322f5ebd71
--- /dev/null
+++ b/libgo/go/go/build/pkgtest/pkgtest.go
@@ -0,0 +1,9 @@
+// Copyright 2011 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 pkgtest
+
+func Foo() {}
+
+func Sqrt(x float64) float64
diff --git a/libgo/go/go/build/syslist_test.go b/libgo/go/go/build/syslist_test.go
new file mode 100644
index 00000000000..eb0e5dcb6b2
--- /dev/null
+++ b/libgo/go/go/build/syslist_test.go
@@ -0,0 +1,62 @@
+// Copyright 2011 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 build
+
+import (
+ "runtime"
+ "testing"
+)
+
+var (
+ thisOS = runtime.GOOS
+ thisArch = runtime.GOARCH
+ otherOS = anotherOS()
+ otherArch = anotherArch()
+)
+
+func anotherOS() string {
+ if thisOS != "darwin" {
+ return "darwin"
+ }
+ return "linux"
+}
+
+func anotherArch() string {
+ if thisArch != "amd64" {
+ return "amd64"
+ }
+ return "386"
+}
+
+type GoodFileTest struct {
+ name string
+ result bool
+}
+
+var tests = []GoodFileTest{
+ {"file.go", true},
+ {"file.c", true},
+ {"file_foo.go", true},
+ {"file_" + thisArch + ".go", true},
+ {"file_" + otherArch + ".go", false},
+ {"file_" + thisOS + ".go", true},
+ {"file_" + otherOS + ".go", false},
+ {"file_" + thisOS + "_" + thisArch + ".go", true},
+ {"file_" + otherOS + "_" + thisArch + ".go", false},
+ {"file_" + thisOS + "_" + otherArch + ".go", false},
+ {"file_" + otherOS + "_" + otherArch + ".go", false},
+ {"file_foo_" + thisArch + ".go", true},
+ {"file_foo_" + otherArch + ".go", false},
+ {"file_" + thisOS + ".c", true},
+ {"file_" + otherOS + ".c", false},
+}
+
+func TestGoodOSArch(t *testing.T) {
+ for _, test := range tests {
+ if goodOSArch(test.name) != test.result {
+ t.Fatalf("goodOSArch(%q) != %v", test.name, test.result)
+ }
+ }
+}
diff --git a/libgo/go/go/doc/comment.go b/libgo/go/go/doc/comment.go
index f1ebfa97b9f..e1989226b68 100644
--- a/libgo/go/go/doc/comment.go
+++ b/libgo/go/go/doc/comment.go
@@ -11,13 +11,11 @@ import (
"io"
"regexp"
"strings"
- "template" // for htmlEscape
+ "template" // for HTMLEscape
)
-
func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' }
-
func stripTrailingWhitespace(s string) string {
i := len(s)
for i > 0 && isWhitespace(s[i-1]) {
@@ -26,7 +24,6 @@ func stripTrailingWhitespace(s string) string {
return s[0:i]
}
-
// CommentText returns the text of comment,
// with the comment markers - //, /*, and */ - removed.
func CommentText(comment *ast.CommentGroup) string {
@@ -58,7 +55,7 @@ func CommentText(comment *ast.CommentGroup) string {
}
// Split on newlines.
- cl := strings.Split(c, "\n", -1)
+ cl := strings.Split(c, "\n")
// Walk lines, stripping trailing white space and adding to list.
for _, l := range cl {
@@ -85,7 +82,6 @@ func CommentText(comment *ast.CommentGroup) string {
return strings.Join(lines, "\n")
}
-
// Split bytes into lines.
func split(text []byte) [][]byte {
// count lines
@@ -119,7 +115,6 @@ func split(text []byte) [][]byte {
return out
}
-
var (
ldquo = []byte("&ldquo;")
rdquo = []byte("&rdquo;")
@@ -148,7 +143,6 @@ func commentEscape(w io.Writer, s []byte, nice bool) {
template.HTMLEscape(w, s[last:])
}
-
const (
// Regexp for Go identifiers
identRx = `[a-zA-Z_][a-zA-Z_0-9]*` // TODO(gri) ASCII only for now - fix this
@@ -176,7 +170,6 @@ var (
html_endpre = []byte("</pre>\n")
)
-
// Emphasize and escape a line of text for HTML. URLs are converted into links;
// if the URL also appears in the words map, the link is taken from the map (if
// the corresponding map value is the empty string, the URL is not converted
@@ -235,7 +228,6 @@ func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) {
commentEscape(w, line, nice)
}
-
func indentLen(s []byte) int {
i := 0
for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
@@ -244,10 +236,8 @@ func indentLen(s []byte) int {
return i
}
-
func isBlank(s []byte) bool { return len(s) == 0 || (len(s) == 1 && s[0] == '\n') }
-
func commonPrefix(a, b []byte) []byte {
i := 0
for i < len(a) && i < len(b) && a[i] == b[i] {
@@ -256,7 +246,6 @@ func commonPrefix(a, b []byte) []byte {
return a[0:i]
}
-
func unindent(block [][]byte) {
if len(block) == 0 {
return
@@ -279,7 +268,6 @@ func unindent(block [][]byte) {
}
}
-
// Convert comment text to formatted HTML.
// The comment was prepared by DocReader,
// so it is known not to have leading, trailing blank lines
diff --git a/libgo/go/go/doc/doc.go b/libgo/go/go/doc/doc.go
index 29d205d391c..c7fed97841c 100644
--- a/libgo/go/go/doc/doc.go
+++ b/libgo/go/go/doc/doc.go
@@ -12,7 +12,6 @@ import (
"sort"
)
-
// ----------------------------------------------------------------------------
type typeDoc struct {
@@ -25,7 +24,6 @@ type typeDoc struct {
methods map[string]*ast.FuncDecl
}
-
// docReader accumulates documentation for a single package.
// It modifies the AST: Comments (declaration documentation)
// that have been collected by the DocReader are set to nil
@@ -42,14 +40,12 @@ type docReader struct {
bugs []*ast.CommentGroup
}
-
func (doc *docReader) init(pkgName string) {
doc.pkgName = pkgName
doc.types = make(map[string]*typeDoc)
doc.funcs = make(map[string]*ast.FuncDecl)
}
-
func (doc *docReader) addDoc(comments *ast.CommentGroup) {
if doc.doc == nil {
// common case: just one package comment
@@ -71,7 +67,6 @@ func (doc *docReader) addDoc(comments *ast.CommentGroup) {
doc.doc = &ast.CommentGroup{list}
}
-
func (doc *docReader) addType(decl *ast.GenDecl) {
spec := decl.Specs[0].(*ast.TypeSpec)
typ := doc.lookupTypeDoc(spec.Name.Name)
@@ -84,7 +79,6 @@ func (doc *docReader) addType(decl *ast.GenDecl) {
}
}
-
func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
if name == "" {
return nil // no type docs for anonymous types
@@ -98,7 +92,6 @@ func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
return tdoc
}
-
func baseTypeName(typ ast.Expr) string {
switch t := typ.(type) {
case *ast.Ident:
@@ -113,7 +106,6 @@ func baseTypeName(typ ast.Expr) string {
return ""
}
-
func (doc *docReader) addValue(decl *ast.GenDecl) {
// determine if decl should be associated with a type
// Heuristic: For each typed entry, determine the type name, if any.
@@ -165,7 +157,6 @@ func (doc *docReader) addValue(decl *ast.GenDecl) {
*values = append(*values, decl)
}
-
// Helper function to set the table entry for function f. Makes sure that
// at least one f with associated documentation is stored in table, if there
// are multiple f's with the same name.
@@ -183,7 +174,6 @@ func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) {
table[name] = f
}
-
func (doc *docReader) addFunc(fun *ast.FuncDecl) {
name := fun.Name.Name
@@ -238,7 +228,6 @@ func (doc *docReader) addFunc(fun *ast.FuncDecl) {
setFunc(doc.funcs, fun)
}
-
func (doc *docReader) addDecl(decl ast.Decl) {
switch d := decl.(type) {
case *ast.GenDecl:
@@ -271,7 +260,6 @@ func (doc *docReader) addDecl(decl ast.Decl) {
}
}
-
func copyCommentList(list []*ast.Comment) []*ast.Comment {
return append([]*ast.Comment(nil), list...)
}
@@ -281,7 +269,6 @@ var (
bug_content = regexp.MustCompile("[^ \n\r\t]+") // at least one non-whitespace char
)
-
// addFile adds the AST for a source file to the docReader.
// Adding the same AST multiple times is a no-op.
//
@@ -313,7 +300,6 @@ func (doc *docReader) addFile(src *ast.File) {
src.Comments = nil // consumed unassociated comments - remove from ast.File node
}
-
func NewFileDoc(file *ast.File) *PackageDoc {
var r docReader
r.init(file.Name.Name)
@@ -321,7 +307,6 @@ func NewFileDoc(file *ast.File) *PackageDoc {
return r.newDoc("", nil)
}
-
func NewPackageDoc(pkg *ast.Package, importpath string) *PackageDoc {
var r docReader
r.init(pkg.Name)
@@ -335,7 +320,6 @@ func NewPackageDoc(pkg *ast.Package, importpath string) *PackageDoc {
return r.newDoc(importpath, filenames)
}
-
// ----------------------------------------------------------------------------
// Conversion to external representation
@@ -353,7 +337,6 @@ type sortValueDoc []*ValueDoc
func (p sortValueDoc) Len() int { return len(p) }
func (p sortValueDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
-
func declName(d *ast.GenDecl) string {
if len(d.Specs) != 1 {
return ""
@@ -369,7 +352,6 @@ func declName(d *ast.GenDecl) string {
return ""
}
-
func (p sortValueDoc) Less(i, j int) bool {
// sort by name
// pull blocks (name = "") up to top
@@ -380,7 +362,6 @@ func (p sortValueDoc) Less(i, j int) bool {
return p[i].order < p[j].order
}
-
func makeValueDocs(list []*ast.GenDecl, tok token.Token) []*ValueDoc {
d := make([]*ValueDoc, len(list)) // big enough in any case
n := 0
@@ -396,7 +377,6 @@ func makeValueDocs(list []*ast.GenDecl, tok token.Token) []*ValueDoc {
return d
}
-
// FuncDoc is the documentation for a func declaration,
// either a top-level function or a method function.
//
@@ -413,7 +393,6 @@ func (p sortFuncDoc) Len() int { return len(p) }
func (p sortFuncDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p sortFuncDoc) Less(i, j int) bool { return p[i].Name < p[j].Name }
-
func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {
d := make([]*FuncDoc, len(m))
i := 0
@@ -433,7 +412,6 @@ func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {
return d
}
-
// TypeDoc is the documentation for a declared type.
// Consts and Vars are sorted lists of constants and variables of (mostly) that type.
// Factories is a sorted list of factory functions that return that type.
@@ -463,7 +441,6 @@ func (p sortTypeDoc) Less(i, j int) bool {
return p[i].order < p[j].order
}
-
// NOTE(rsc): This would appear not to be correct for type ( )
// blocks, but the doc extractor above has split them into
// individual declarations.
@@ -520,7 +497,6 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
return d
}
-
func makeBugDocs(list []*ast.CommentGroup) []string {
d := make([]string, len(list))
for i, g := range list {
@@ -529,7 +505,6 @@ func makeBugDocs(list []*ast.CommentGroup) []string {
return d
}
-
// PackageDoc is the documentation for an entire package.
//
type PackageDoc struct {
@@ -544,14 +519,13 @@ type PackageDoc struct {
Bugs []string
}
-
// newDoc returns the accumulated documentation for the package.
//
func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc {
p := new(PackageDoc)
p.PackageName = doc.pkgName
p.ImportPath = importpath
- sort.SortStrings(filenames)
+ sort.Strings(filenames)
p.Filenames = filenames
p.Doc = CommentText(doc.doc)
// makeTypeDocs may extend the list of doc.values and
@@ -565,12 +539,23 @@ func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc
return p
}
-
// ----------------------------------------------------------------------------
// Filtering by name
type Filter func(string) bool
+func matchFields(fields *ast.FieldList, f Filter) bool {
+ if fields != nil {
+ for _, field := range fields.List {
+ for _, name := range field.Names {
+ if f(name.Name) {
+ return true
+ }
+ }
+ }
+ }
+ return false
+}
func matchDecl(d *ast.GenDecl, f Filter) bool {
for _, d := range d.Specs {
@@ -585,12 +570,21 @@ func matchDecl(d *ast.GenDecl, f Filter) bool {
if f(v.Name.Name) {
return true
}
+ switch t := v.Type.(type) {
+ case *ast.StructType:
+ if matchFields(t.Fields, f) {
+ return true
+ }
+ case *ast.InterfaceType:
+ if matchFields(t.Methods, f) {
+ return true
+ }
+ }
}
}
return false
}
-
func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
w := 0
for _, vd := range a {
@@ -602,7 +596,6 @@ func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
return a[0:w]
}
-
func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
w := 0
for _, fd := range a {
@@ -614,7 +607,6 @@ func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
return a[0:w]
}
-
func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
w := 0
for _, td := range a {
@@ -637,7 +629,6 @@ func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
return a[0:w]
}
-
// Filter eliminates documentation for names that don't pass through the filter f.
// TODO: Recognize "Type.Method" as a name.
//
diff --git a/libgo/go/go/parser/interface.go b/libgo/go/go/parser/interface.go
index b4780e05784..4f980fc6539 100644
--- a/libgo/go/go/parser/interface.go
+++ b/libgo/go/go/parser/interface.go
@@ -17,7 +17,6 @@ import (
"path/filepath"
)
-
// 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.
@@ -42,20 +41,21 @@ func readSource(filename string, src interface{}) ([]byte, os.Error) {
}
return buf.Bytes(), nil
default:
- return nil, os.ErrorString("invalid source")
+ return nil, os.NewError("invalid source")
}
}
return ioutil.ReadFile(filename)
}
-
-func (p *parser) parseEOF() os.Error {
- p.expect(token.EOF)
- return p.GetError(scanner.Sorted)
+func (p *parser) errors() os.Error {
+ mode := scanner.Sorted
+ if p.mode&SpuriousErrors == 0 {
+ mode = scanner.NoMultiples
+ }
+ return p.GetError(mode)
}
-
// ParseExpr parses a Go expression and returns the corresponding
// AST node. The fset, filename, and src arguments have the same interpretation
// as for ParseFile. If there is an error, the result expression
@@ -73,9 +73,10 @@ func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr,
if p.tok == token.SEMICOLON {
p.next() // consume automatically inserted semicolon, if any
}
- return x, p.parseEOF()
-}
+ p.expect(token.EOF)
+ return x, p.errors()
+}
// ParseStmtList parses a list of Go statements and returns the list
// of corresponding AST nodes. The fset, filename, and src arguments have the same
@@ -90,9 +91,11 @@ func ParseStmtList(fset *token.FileSet, filename string, src interface{}) ([]ast
var p parser
p.init(fset, filename, data, 0)
- return p.parseStmtList(), p.parseEOF()
-}
+ list := p.parseStmtList()
+ p.expect(token.EOF)
+ return list, p.errors()
+}
// ParseDeclList parses a list of Go declarations and returns the list
// of corresponding AST nodes. The fset, filename, and src arguments have the same
@@ -107,9 +110,11 @@ func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast
var p parser
p.init(fset, filename, data, 0)
- return p.parseDeclList(), p.parseEOF()
-}
+ list := p.parseDeclList()
+ p.expect(token.EOF)
+ return list, p.errors()
+}
// ParseFile parses the source code of a single Go source file and returns
// the corresponding ast.File node. The source code may be provided via
@@ -139,9 +144,10 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode uint)
var p parser
p.init(fset, filename, data, mode)
- return p.parseFile(), p.GetError(scanner.NoMultiples) // parseFile() reads to EOF
-}
+ file := p.parseFile() // parseFile reads to EOF
+ return file, p.errors()
+}
// ParseFiles calls ParseFile for each file in the filenames list and returns
// a map of package name -> package AST with all the packages found. The mode
@@ -171,7 +177,6 @@ func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[st
return
}
-
// ParseDir calls ParseFile for the files in the directory specified by path and
// returns a map of package name -> package AST with all the packages found. If
// filter != nil, only the files with os.FileInfo entries passing through the filter
diff --git a/libgo/go/go/parser/parser.go b/libgo/go/go/parser/parser.go
index afa9ae517b6..9c14d166732 100644
--- a/libgo/go/go/parser/parser.go
+++ b/libgo/go/go/parser/parser.go
@@ -16,7 +16,6 @@ import (
"go/token"
)
-
// The mode parameter to the Parse* functions is a set of flags (or 0).
// They control the amount of source code parsed and other optional
// parser functionality.
@@ -27,9 +26,9 @@ const (
ParseComments // parse comments and add them to AST
Trace // print a trace of parsed productions
DeclarationErrors // report declaration errors
+ SpuriousErrors // report all (not just the first) errors per line
)
-
// The parser structure holds the parser's internal state.
type parser struct {
file *token.File
@@ -54,7 +53,7 @@ type parser struct {
// Non-syntactic parser control
exprLev int // < 0: in control clause, >= 0: in expression
- // Ordinary identifer scopes
+ // Ordinary identifier scopes
pkgScope *ast.Scope // pkgScope.Outer == nil
topScope *ast.Scope // top-most scope; may be pkgScope
unresolved []*ast.Ident // unresolved identifiers
@@ -66,7 +65,6 @@ type parser struct {
targetStack [][]*ast.Ident // stack of unresolved labels
}
-
// scannerMode returns the scanner mode bits given the parser's mode bits.
func scannerMode(mode uint) uint {
var m uint = scanner.InsertSemis
@@ -76,7 +74,6 @@ func scannerMode(mode uint) uint {
return m
}
-
func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uint) {
p.file = fset.AddFile(filename, fset.Base(), len(src))
p.scanner.Init(p.file, src, p, scannerMode(mode))
@@ -95,7 +92,6 @@ func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uin
p.openLabelScope()
}
-
// ----------------------------------------------------------------------------
// Scoping support
@@ -103,18 +99,15 @@ func (p *parser) openScope() {
p.topScope = ast.NewScope(p.topScope)
}
-
func (p *parser) closeScope() {
p.topScope = p.topScope.Outer
}
-
func (p *parser) openLabelScope() {
p.labelScope = ast.NewScope(p.labelScope)
p.targetStack = append(p.targetStack, nil)
}
-
func (p *parser) closeLabelScope() {
// resolve labels
n := len(p.targetStack) - 1
@@ -130,15 +123,16 @@ func (p *parser) closeLabelScope() {
p.labelScope = p.labelScope.Outer
}
-
-func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
+func (p *parser) declare(decl, data interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
for _, ident := range idents {
assert(ident.Obj == nil, "identifier already declared or resolved")
+ obj := ast.NewObj(kind, ident.Name)
+ // remember the corresponding declaration for redeclaration
+ // errors and global variable resolution/typechecking phase
+ obj.Decl = decl
+ obj.Data = data
+ ident.Obj = obj
if ident.Name != "_" {
- obj := ast.NewObj(kind, ident.Name)
- // remember the corresponding declaration for redeclaration
- // errors and global variable resolution/typechecking phase
- obj.Decl = decl
if alt := scope.Insert(obj); alt != nil && p.mode&DeclarationErrors != 0 {
prevDecl := ""
if pos := alt.Pos(); pos.IsValid() {
@@ -146,12 +140,10 @@ func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, i
}
p.error(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl))
}
- ident.Obj = obj
}
}
}
-
func (p *parser) shortVarDecl(idents []*ast.Ident) {
// Go spec: A short variable declaration may redeclare variables
// provided they were originally declared in the same block with
@@ -159,17 +151,17 @@ func (p *parser) shortVarDecl(idents []*ast.Ident) {
n := 0 // number of new variables
for _, ident := range idents {
assert(ident.Obj == nil, "identifier already declared or resolved")
+ obj := ast.NewObj(ast.Var, ident.Name)
+ // short var declarations cannot have redeclaration errors
+ // and are not global => no need to remember the respective
+ // declaration
+ ident.Obj = obj
if ident.Name != "_" {
- obj := ast.NewObj(ast.Var, ident.Name)
- // short var declarations cannot have redeclaration errors
- // and are not global => no need to remember the respective
- // declaration
- alt := p.topScope.Insert(obj)
- if alt == nil {
+ if alt := p.topScope.Insert(obj); alt != nil {
+ ident.Obj = alt // redeclaration
+ } else {
n++ // new declaration
- alt = obj
}
- ident.Obj = alt
}
}
if n == 0 && p.mode&DeclarationErrors != 0 {
@@ -177,13 +169,11 @@ func (p *parser) shortVarDecl(idents []*ast.Ident) {
}
}
-
// The unresolved object is a sentinel to mark identifiers that have been added
// to the list of unresolved identifiers. The sentinel is only used for verifying
// internal consistency.
var unresolved = new(ast.Object)
-
func (p *parser) resolve(x ast.Expr) {
// nothing to do if x is not an identifier or the blank identifier
ident, _ := x.(*ast.Ident)
@@ -209,7 +199,6 @@ func (p *parser) resolve(x ast.Expr) {
p.unresolved = append(p.unresolved, ident)
}
-
// ----------------------------------------------------------------------------
// Parsing support
@@ -227,21 +216,18 @@ func (p *parser) printTrace(a ...interface{}) {
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
@@ -283,7 +269,6 @@ func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
return
}
-
// Consume a group of adjacent comments, add it to the parser's
// comments list, and return it together with the line at which
// the last comment in the group ends. An empty line or non-comment
@@ -305,7 +290,6 @@ func (p *parser) consumeCommentGroup() (comments *ast.CommentGroup, endline int)
return
}
-
// Advance to the next non-comment token. In the process, collect
// any comment groups encountered, and remember the last lead and
// and line comments.
@@ -356,12 +340,10 @@ func (p *parser) next() {
}
}
-
func (p *parser) error(pos token.Pos, msg string) {
p.Error(p.file.Position(pos), msg)
}
-
func (p *parser) errorExpected(pos token.Pos, msg string) {
msg = "expected " + msg
if pos == p.pos {
@@ -379,7 +361,6 @@ func (p *parser) errorExpected(pos token.Pos, msg string) {
p.error(pos, msg)
}
-
func (p *parser) expect(tok token.Token) token.Pos {
pos := p.pos
if p.tok != tok {
@@ -389,21 +370,18 @@ func (p *parser) expect(tok token.Token) token.Pos {
return pos
}
-
func (p *parser) expectSemi() {
if p.tok != token.RPAREN && p.tok != token.RBRACE {
p.expect(token.SEMICOLON)
}
}
-
func assert(cond bool, msg string) {
if !cond {
panic("go/parser internal error: " + msg)
}
}
-
// ----------------------------------------------------------------------------
// Identifiers
@@ -419,7 +397,6 @@ func (p *parser) parseIdent() *ast.Ident {
return &ast.Ident{pos, name, nil}
}
-
func (p *parser) parseIdentList() (list []*ast.Ident) {
if p.trace {
defer un(trace(p, "IdentList"))
@@ -434,7 +411,6 @@ func (p *parser) parseIdentList() (list []*ast.Ident) {
return
}
-
// ----------------------------------------------------------------------------
// Common productions
@@ -444,16 +420,15 @@ func (p *parser) parseExprList(lhs bool) (list []ast.Expr) {
defer un(trace(p, "ExpressionList"))
}
- list = append(list, p.parseExpr(lhs))
+ list = append(list, p.checkExpr(p.parseExpr(lhs)))
for p.tok == token.COMMA {
p.next()
- list = append(list, p.parseExpr(lhs))
+ list = append(list, p.checkExpr(p.parseExpr(lhs)))
}
return
}
-
func (p *parser) parseLhsList() []ast.Expr {
list := p.parseExprList(true)
switch p.tok {
@@ -477,12 +452,10 @@ func (p *parser) parseLhsList() []ast.Expr {
return list
}
-
func (p *parser) parseRhsList() []ast.Expr {
return p.parseExprList(false)
}
-
// ----------------------------------------------------------------------------
// Types
@@ -503,7 +476,6 @@ func (p *parser) parseType() ast.Expr {
return typ
}
-
// If the result is an identifier, it is not resolved.
func (p *parser) parseTypeName() ast.Expr {
if p.trace {
@@ -524,7 +496,6 @@ func (p *parser) parseTypeName() ast.Expr {
return ident
}
-
func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
if p.trace {
defer un(trace(p, "ArrayType"))
@@ -544,7 +515,6 @@ func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
return &ast.ArrayType{lbrack, len, elt}
}
-
func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
idents := make([]*ast.Ident, len(list))
for i, x := range list {
@@ -559,7 +529,6 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
return idents
}
-
func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
if p.trace {
defer un(trace(p, "FieldDecl"))
@@ -596,12 +565,11 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
p.expectSemi() // call before accessing p.linecomment
field := &ast.Field{doc, idents, typ, tag, p.lineComment}
- p.declare(field, scope, ast.Var, idents...)
+ p.declare(field, nil, scope, ast.Var, idents...)
return field
}
-
func (p *parser) parseStructType() *ast.StructType {
if p.trace {
defer un(trace(p, "StructType"))
@@ -623,7 +591,6 @@ func (p *parser) parseStructType() *ast.StructType {
return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
}
-
func (p *parser) parsePointerType() *ast.StarExpr {
if p.trace {
defer un(trace(p, "PointerType"))
@@ -635,7 +602,6 @@ func (p *parser) parsePointerType() *ast.StarExpr {
return &ast.StarExpr{star, base}
}
-
func (p *parser) tryVarType(isParam bool) ast.Expr {
if isParam && p.tok == token.ELLIPSIS {
pos := p.pos
@@ -653,7 +619,6 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
return p.tryIdentOrType(false)
}
-
func (p *parser) parseVarType(isParam bool) ast.Expr {
typ := p.tryVarType(isParam)
if typ == nil {
@@ -665,7 +630,6 @@ func (p *parser) parseVarType(isParam bool) ast.Expr {
return typ
}
-
func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
if p.trace {
defer un(trace(p, "VarList"))
@@ -693,7 +657,6 @@ func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
return
}
-
func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) {
if p.trace {
defer un(trace(p, "ParameterList"))
@@ -707,7 +670,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
params = append(params, field)
// Go spec: The scope of an identifier denoting a function
// parameter or result variable is the function body.
- p.declare(field, scope, ast.Var, idents...)
+ p.declare(field, nil, scope, ast.Var, idents...)
if p.tok == token.COMMA {
p.next()
}
@@ -719,7 +682,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
params = append(params, field)
// Go spec: The scope of an identifier denoting a function
// parameter or result variable is the function body.
- p.declare(field, scope, ast.Var, idents...)
+ p.declare(field, nil, scope, ast.Var, idents...)
if p.tok != token.COMMA {
break
}
@@ -738,7 +701,6 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
return
}
-
func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldList {
if p.trace {
defer un(trace(p, "Parameters"))
@@ -754,7 +716,6 @@ func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldLi
return &ast.FieldList{lparen, params, rparen}
}
-
func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
if p.trace {
defer un(trace(p, "Result"))
@@ -774,7 +735,6 @@ func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
return nil
}
-
func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldList) {
if p.trace {
defer un(trace(p, "Signature"))
@@ -786,7 +746,6 @@ func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldLis
return
}
-
func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
if p.trace {
defer un(trace(p, "FuncType"))
@@ -799,7 +758,6 @@ func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
return &ast.FuncType{pos, params, results}, scope
}
-
func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
if p.trace {
defer un(trace(p, "MethodSpec"))
@@ -818,16 +776,16 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
} else {
// embedded interface
typ = x
+ p.resolve(typ)
}
p.expectSemi() // call before accessing p.linecomment
spec := &ast.Field{doc, idents, typ, nil, p.lineComment}
- p.declare(spec, scope, ast.Fun, idents...)
+ p.declare(spec, nil, scope, ast.Fun, idents...)
return spec
}
-
func (p *parser) parseInterfaceType() *ast.InterfaceType {
if p.trace {
defer un(trace(p, "InterfaceType"))
@@ -846,7 +804,6 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
}
-
func (p *parser) parseMapType() *ast.MapType {
if p.trace {
defer un(trace(p, "MapType"))
@@ -861,7 +818,6 @@ func (p *parser) parseMapType() *ast.MapType {
return &ast.MapType{pos, key, value}
}
-
func (p *parser) parseChanType() *ast.ChanType {
if p.trace {
defer un(trace(p, "ChanType"))
@@ -885,7 +841,6 @@ func (p *parser) parseChanType() *ast.ChanType {
return &ast.ChanType{pos, dir, value}
}
-
// If the result is an identifier, it is not resolved.
func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
switch p.tok {
@@ -918,7 +873,6 @@ func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
return nil
}
-
func (p *parser) tryType() ast.Expr {
typ := p.tryIdentOrType(false)
if typ != nil {
@@ -927,7 +881,6 @@ func (p *parser) tryType() ast.Expr {
return typ
}
-
// ----------------------------------------------------------------------------
// Blocks
@@ -943,7 +896,6 @@ func (p *parser) parseStmtList() (list []ast.Stmt) {
return
}
-
func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
if p.trace {
defer un(trace(p, "Body"))
@@ -960,7 +912,6 @@ func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
return &ast.BlockStmt{lbrace, list, rbrace}
}
-
func (p *parser) parseBlockStmt() *ast.BlockStmt {
if p.trace {
defer un(trace(p, "BlockStmt"))
@@ -975,7 +926,6 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt {
return &ast.BlockStmt{lbrace, list, rbrace}
}
-
// ----------------------------------------------------------------------------
// Expressions
@@ -997,7 +947,6 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
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.
// If lhs is set and the result is an identifier, it is not resolved.
@@ -1024,7 +973,7 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
lparen := p.pos
p.next()
p.exprLev++
- x := p.parseRhs()
+ x := p.parseRhsOrType() // types may be parenthesized: (some type)
p.exprLev--
rparen := p.expect(token.RPAREN)
return &ast.ParenExpr{lparen, x, rparen}
@@ -1047,7 +996,6 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
return &ast.BadExpr{pos, p.pos}
}
-
func (p *parser) parseSelector(x ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "Selector"))
@@ -1058,7 +1006,6 @@ func (p *parser) parseSelector(x ast.Expr) ast.Expr {
return &ast.SelectorExpr{x, sel}
}
-
func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "TypeAssertion"))
@@ -1077,7 +1024,6 @@ func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
return &ast.TypeAssertExpr{x, typ}
}
-
func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "IndexOrSlice"))
@@ -1106,7 +1052,6 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
return &ast.IndexExpr{x, lbrack, low, rbrack}
}
-
func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
if p.trace {
defer un(trace(p, "CallOrConversion"))
@@ -1117,7 +1062,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
var list []ast.Expr
var ellipsis token.Pos
for p.tok != token.RPAREN && p.tok != token.EOF && !ellipsis.IsValid() {
- list = append(list, p.parseRhs())
+ list = append(list, p.parseRhsOrType()) // builtins may expect a type: make(some type, ...)
if p.tok == token.ELLIPSIS {
ellipsis = p.pos
p.next()
@@ -1133,7 +1078,6 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
return &ast.CallExpr{fun, lparen, list, ellipsis, rparen}
}
-
func (p *parser) parseElement(keyOk bool) ast.Expr {
if p.trace {
defer un(trace(p, "Element"))
@@ -1143,7 +1087,7 @@ func (p *parser) parseElement(keyOk bool) ast.Expr {
return p.parseLiteralValue(nil)
}
- x := p.parseExpr(keyOk) // don't resolve if map key
+ x := p.checkExpr(p.parseExpr(keyOk)) // don't resolve if map key
if keyOk {
if p.tok == token.COLON {
colon := p.pos
@@ -1156,7 +1100,6 @@ func (p *parser) parseElement(keyOk bool) ast.Expr {
return x
}
-
func (p *parser) parseElementList() (list []ast.Expr) {
if p.trace {
defer un(trace(p, "ElementList"))
@@ -1173,7 +1116,6 @@ func (p *parser) parseElementList() (list []ast.Expr) {
return
}
-
func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "LiteralValue"))
@@ -1190,7 +1132,6 @@ func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
return &ast.CompositeLit{typ, lbrace, elts, rbrace}
}
-
// checkExpr checks that x is an expression (and not a type).
func (p *parser) checkExpr(x ast.Expr) ast.Expr {
switch t := unparen(x).(type) {
@@ -1205,19 +1146,14 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
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(), x.End()}
- }
+ // If t.Type == nil we have a type assertion of the form
+ // y.(type), which is only allowed in type switch expressions.
+ // It's hard to exclude those but for the case where we are in
+ // a type switch. Instead be lenient and test this in the type
+ // checker.
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(), x.End()}
- }
case *ast.BinaryExpr:
default:
// all other nodes are not proper expressions
@@ -1227,7 +1163,6 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
return x
}
-
// isTypeName returns true iff x is a (qualified) TypeName.
func isTypeName(x ast.Expr) bool {
switch t := x.(type) {
@@ -1242,7 +1177,6 @@ func isTypeName(x ast.Expr) bool {
return true
}
-
// isLiteralType returns true iff x is a legal composite literal type.
func isLiteralType(x ast.Expr) bool {
switch t := x.(type) {
@@ -1260,7 +1194,6 @@ func isLiteralType(x ast.Expr) bool {
return true
}
-
// If x is of the form *T, deref returns T, otherwise it returns x.
func deref(x ast.Expr) ast.Expr {
if p, isPtr := x.(*ast.StarExpr); isPtr {
@@ -1269,7 +1202,6 @@ func deref(x ast.Expr) ast.Expr {
return x
}
-
// If x is of the form (T), unparen returns unparen(T), otherwise it returns x.
func unparen(x ast.Expr) ast.Expr {
if p, isParen := x.(*ast.ParenExpr); isParen {
@@ -1278,7 +1210,6 @@ func unparen(x ast.Expr) ast.Expr {
return x
}
-
// checkExprOrType checks that x is an expression or a type
// (and not a raw type such as [...]T).
//
@@ -1287,11 +1218,6 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
case *ast.ParenExpr:
panic("unreachable")
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(), x.End()}
- }
case *ast.ArrayType:
if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis {
p.error(len.Pos(), "expected array length, found '...'")
@@ -1303,7 +1229,6 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
return x
}
-
// If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parsePrimaryExpr(lhs bool) ast.Expr {
if p.trace {
@@ -1358,7 +1283,6 @@ L:
return x
}
-
// If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
if p.trace {
@@ -1366,7 +1290,7 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
}
switch p.tok {
- case token.ADD, token.SUB, token.NOT, token.XOR, token.AND, token.RANGE:
+ case token.ADD, token.SUB, token.NOT, token.XOR, token.AND:
pos, op := p.pos, p.tok
p.next()
x := p.parseUnaryExpr(false)
@@ -1396,7 +1320,6 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
return p.parsePrimaryExpr(lhs)
}
-
// If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
if p.trace {
@@ -1420,10 +1343,10 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
return x
}
-
// If lhs is set and the result is an identifier, it is not resolved.
-// TODO(gri): parseExpr may return a type or even a raw type ([..]int) -
-// should reject when a type/raw type is obviously not allowed
+// The result may be a type or even a raw type ([...]int). Callers must
+// check the result (using checkExpr or checkExprOrType), depending on
+// context.
func (p *parser) parseExpr(lhs bool) ast.Expr {
if p.trace {
defer un(trace(p, "Expression"))
@@ -1432,16 +1355,29 @@ func (p *parser) parseExpr(lhs bool) ast.Expr {
return p.parseBinaryExpr(lhs, token.LowestPrec+1)
}
-
func (p *parser) parseRhs() ast.Expr {
- return p.parseExpr(false)
+ return p.checkExpr(p.parseExpr(false))
}
+func (p *parser) parseRhsOrType() ast.Expr {
+ return p.checkExprOrType(p.parseExpr(false))
+}
// ----------------------------------------------------------------------------
// Statements
-func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
+// Parsing modes for parseSimpleStmt.
+const (
+ basic = iota
+ labelOk
+ rangeOk
+)
+
+// parseSimpleStmt returns true as 2nd result if it parsed the assignment
+// of a range clause (with mode == rangeOk). The returned statement is an
+// assignment with a right-hand side that is a single unary expression of
+// the form "range x". No guarantees are given for the left-hand side.
+func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
if p.trace {
defer un(trace(p, "SimpleStmt"))
}
@@ -1454,11 +1390,20 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
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
+ // assignment statement, possibly part of a range clause
pos, tok := p.pos, p.tok
p.next()
- y := p.parseRhsList()
- return &ast.AssignStmt{x, pos, tok, y}
+ var y []ast.Expr
+ isRange := false
+ if mode == rangeOk && p.tok == token.RANGE && (tok == token.DEFINE || tok == token.ASSIGN) {
+ pos := p.pos
+ p.next()
+ y = []ast.Expr{&ast.UnaryExpr{pos, token.RANGE, p.parseRhs()}}
+ isRange = true
+ } else {
+ y = p.parseRhsList()
+ }
+ return &ast.AssignStmt{x, pos, tok, y}, isRange
}
if len(x) > 1 {
@@ -1471,38 +1416,43 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
// labeled statement
colon := p.pos
p.next()
- if label, isIdent := x[0].(*ast.Ident); labelOk && isIdent {
+ if label, isIdent := x[0].(*ast.Ident); mode == labelOk && isIdent {
// Go spec: The scope of a label is the body of the function
// in which it is declared and excludes the body of any nested
// function.
stmt := &ast.LabeledStmt{label, colon, p.parseStmt()}
- p.declare(stmt, p.labelScope, ast.Lbl, label)
- return stmt
+ p.declare(stmt, nil, p.labelScope, ast.Lbl, label)
+ return stmt, false
}
- p.error(x[0].Pos(), "illegal label declaration")
- return &ast.BadStmt{x[0].Pos(), colon + 1}
+ // The label declaration typically starts at x[0].Pos(), but the label
+ // declaration may be erroneous due to a token after that position (and
+ // before the ':'). If SpuriousErrors is not set, the (only) error re-
+ // ported for the line is the illegal label error instead of the token
+ // before the ':' that caused the problem. Thus, use the (latest) colon
+ // position for error reporting.
+ p.error(colon, "illegal label declaration")
+ return &ast.BadStmt{x[0].Pos(), colon + 1}, false
case token.ARROW:
// send statement
arrow := p.pos
p.next() // consume "<-"
y := p.parseRhs()
- return &ast.SendStmt{x[0], arrow, y}
+ return &ast.SendStmt{x[0], arrow, y}, false
case token.INC, token.DEC:
// increment or decrement
s := &ast.IncDecStmt{x[0], p.pos, p.tok}
p.next() // consume "++" or "--"
- return s
+ return s, false
}
// expression
- return &ast.ExprStmt{x[0]}
+ return &ast.ExprStmt{x[0]}, false
}
-
func (p *parser) parseCallExpr() *ast.CallExpr {
- x := p.parseRhs()
+ x := p.parseRhsOrType() // could be a conversion: (some type)(x)
if call, isCall := x.(*ast.CallExpr); isCall {
return call
}
@@ -1510,7 +1460,6 @@ func (p *parser) parseCallExpr() *ast.CallExpr {
return nil
}
-
func (p *parser) parseGoStmt() ast.Stmt {
if p.trace {
defer un(trace(p, "GoStmt"))
@@ -1526,7 +1475,6 @@ func (p *parser) parseGoStmt() ast.Stmt {
return &ast.GoStmt{pos, call}
}
-
func (p *parser) parseDeferStmt() ast.Stmt {
if p.trace {
defer un(trace(p, "DeferStmt"))
@@ -1542,7 +1490,6 @@ func (p *parser) parseDeferStmt() ast.Stmt {
return &ast.DeferStmt{pos, call}
}
-
func (p *parser) parseReturnStmt() *ast.ReturnStmt {
if p.trace {
defer un(trace(p, "ReturnStmt"))
@@ -1559,7 +1506,6 @@ func (p *parser) parseReturnStmt() *ast.ReturnStmt {
return &ast.ReturnStmt{pos, x}
}
-
func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
if p.trace {
defer un(trace(p, "BranchStmt"))
@@ -1578,7 +1524,6 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
return &ast.BranchStmt{pos, tok, label}
}
-
func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
if s == nil {
return nil
@@ -1590,7 +1535,6 @@ func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
return &ast.BadExpr{s.Pos(), s.End()}
}
-
func (p *parser) parseIfStmt() *ast.IfStmt {
if p.trace {
defer un(trace(p, "IfStmt"))
@@ -1609,7 +1553,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
p.next()
x = p.parseRhs()
} else {
- s = p.parseSimpleStmt(false)
+ s, _ = p.parseSimpleStmt(basic)
if p.tok == token.SEMICOLON {
p.next()
x = p.parseRhs()
@@ -1633,7 +1577,6 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
return &ast.IfStmt{pos, s, x, body, else_}
}
-
func (p *parser) parseTypeList() (list []ast.Expr) {
if p.trace {
defer un(trace(p, "TypeList"))
@@ -1648,7 +1591,6 @@ func (p *parser) parseTypeList() (list []ast.Expr) {
return
}
-
func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
if p.trace {
defer un(trace(p, "CaseClause"))
@@ -1675,7 +1617,6 @@ func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
return &ast.CaseClause{pos, list, colon, body}
}
-
func isExprSwitch(s ast.Stmt) bool {
if s == nil {
return true
@@ -1689,7 +1630,6 @@ func isExprSwitch(s ast.Stmt) bool {
return false
}
-
func (p *parser) parseSwitchStmt() ast.Stmt {
if p.trace {
defer un(trace(p, "SwitchStmt"))
@@ -1704,14 +1644,14 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
prevLev := p.exprLev
p.exprLev = -1
if p.tok != token.SEMICOLON {
- s2 = p.parseSimpleStmt(false)
+ s2, _ = p.parseSimpleStmt(basic)
}
if p.tok == token.SEMICOLON {
p.next()
s1 = s2
s2 = nil
if p.tok != token.LBRACE {
- s2 = p.parseSimpleStmt(false)
+ s2, _ = p.parseSimpleStmt(basic)
}
}
p.exprLev = prevLev
@@ -1735,7 +1675,6 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
return &ast.TypeSwitchStmt{pos, s1, s2, body}
}
-
func (p *parser) parseCommClause() *ast.CommClause {
if p.trace {
defer un(trace(p, "CommClause"))
@@ -1797,7 +1736,6 @@ func (p *parser) parseCommClause() *ast.CommClause {
return &ast.CommClause{pos, comm, colon, body}
}
-
func (p *parser) parseSelectStmt() *ast.SelectStmt {
if p.trace {
defer un(trace(p, "SelectStmt"))
@@ -1816,7 +1754,6 @@ func (p *parser) parseSelectStmt() *ast.SelectStmt {
return &ast.SelectStmt{pos, body}
}
-
func (p *parser) parseForStmt() ast.Stmt {
if p.trace {
defer un(trace(p, "ForStmt"))
@@ -1827,22 +1764,23 @@ func (p *parser) parseForStmt() ast.Stmt {
defer p.closeScope()
var s1, s2, s3 ast.Stmt
+ var isRange bool
if p.tok != token.LBRACE {
prevLev := p.exprLev
p.exprLev = -1
if p.tok != token.SEMICOLON {
- s2 = p.parseSimpleStmt(false)
+ s2, isRange = p.parseSimpleStmt(rangeOk)
}
- if p.tok == token.SEMICOLON {
+ if !isRange && p.tok == token.SEMICOLON {
p.next()
s1 = s2
s2 = nil
if p.tok != token.SEMICOLON {
- s2 = p.parseSimpleStmt(false)
+ s2, _ = p.parseSimpleStmt(basic)
}
p.expectSemi()
if p.tok != token.LBRACE {
- s3 = p.parseSimpleStmt(false)
+ s3, _ = p.parseSimpleStmt(basic)
}
}
p.exprLev = prevLev
@@ -1851,12 +1789,8 @@ func (p *parser) parseForStmt() ast.Stmt {
body := p.parseBlockStmt()
p.expectSemi()
- 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, body.End()}
- }
+ if isRange {
+ as := s2.(*ast.AssignStmt)
// check lhs
var key, value ast.Expr
switch len(as.Lhs) {
@@ -1868,25 +1802,16 @@ func (p *parser) parseForStmt() ast.Stmt {
p.errorExpected(as.Lhs[0].Pos(), "1 or 2 expressions")
return &ast.BadStmt{pos, body.End()}
}
- // check rhs
- if len(as.Rhs) != 1 {
- p.errorExpected(as.Rhs[0].Pos(), "1 expression")
- return &ast.BadStmt{pos, body.End()}
- }
- if rhs, isUnary := as.Rhs[0].(*ast.UnaryExpr); isUnary && rhs.Op == token.RANGE {
- // rhs is range expression
- // (any short variable declaration was handled by parseSimpleStat above)
- return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body}
- }
- p.errorExpected(s2.Pos(), "range clause")
- return &ast.BadStmt{pos, body.End()}
+ // parseSimpleStmt returned a right-hand side that
+ // is a single unary expression of the form "range x"
+ x := as.Rhs[0].(*ast.UnaryExpr).X
+ return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, x, body}
}
// regular for statement
return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}
}
-
func (p *parser) parseStmt() (s ast.Stmt) {
if p.trace {
defer un(trace(p, "Statement"))
@@ -1900,7 +1825,7 @@ func (p *parser) parseStmt() (s ast.Stmt) {
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
- s = p.parseSimpleStmt(true)
+ s, _ = p.parseSimpleStmt(labelOk)
// because of the required look-ahead, labeled statements are
// parsed by parseSimpleStmt - don't expect a semicolon after
// them
@@ -1943,13 +1868,11 @@ func (p *parser) parseStmt() (s ast.Stmt) {
return
}
-
// ----------------------------------------------------------------------------
// Declarations
type parseSpecFunction func(p *parser, doc *ast.CommentGroup, iota int) ast.Spec
-
func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
if p.trace {
defer un(trace(p, "ImportSpec"))
@@ -1980,7 +1903,6 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
return spec
}
-
func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
if p.trace {
defer un(trace(p, "ConstSpec"))
@@ -2000,12 +1922,11 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
// the end of the innermost containing block.
// (Global identifiers are resolved in a separate phase after parsing.)
spec := &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
- p.declare(spec, p.topScope, ast.Con, idents...)
+ p.declare(spec, iota, p.topScope, ast.Con, idents...)
return spec
}
-
func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
if p.trace {
defer un(trace(p, "TypeSpec"))
@@ -2018,7 +1939,7 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
// containing block.
// (Global identifiers are resolved in a separate phase after parsing.)
spec := &ast.TypeSpec{doc, ident, nil, nil}
- p.declare(spec, p.topScope, ast.Typ, ident)
+ p.declare(spec, nil, p.topScope, ast.Typ, ident)
spec.Type = p.parseType()
p.expectSemi() // call before accessing p.linecomment
@@ -2027,7 +1948,6 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
return spec
}
-
func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
if p.trace {
defer un(trace(p, "VarSpec"))
@@ -2047,12 +1967,11 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
// the end of the innermost containing block.
// (Global identifiers are resolved in a separate phase after parsing.)
spec := &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
- p.declare(spec, p.topScope, ast.Var, idents...)
+ p.declare(spec, nil, p.topScope, ast.Var, idents...)
return spec
}
-
func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
if p.trace {
defer un(trace(p, "GenDecl("+keyword.String()+")"))
@@ -2077,7 +1996,6 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
return &ast.GenDecl{doc, pos, keyword, lparen, list, rparen}
}
-
func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
if p.trace {
defer un(trace(p, "Receiver"))
@@ -2105,7 +2023,6 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
return par
}
-
func (p *parser) parseFuncDecl() *ast.FuncDecl {
if p.trace {
defer un(trace(p, "FunctionDecl"))
@@ -2139,14 +2056,13 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
// init() functions cannot be referred to and there may
// be more than one - don't put them in the pkgScope
if ident.Name != "init" {
- p.declare(decl, p.pkgScope, ast.Fun, ident)
+ p.declare(decl, nil, p.pkgScope, ast.Fun, ident)
}
}
return decl
}
-
func (p *parser) parseDecl() ast.Decl {
if p.trace {
defer un(trace(p, "Declaration"))
@@ -2177,7 +2093,6 @@ func (p *parser) parseDecl() ast.Decl {
return p.parseGenDecl(p.tok, f)
}
-
func (p *parser) parseDeclList() (list []ast.Decl) {
if p.trace {
defer un(trace(p, "DeclList"))
@@ -2190,7 +2105,6 @@ func (p *parser) parseDeclList() (list []ast.Decl) {
return
}
-
// ----------------------------------------------------------------------------
// Source files
@@ -2243,6 +2157,5 @@ func (p *parser) parseFile() *ast.File {
}
}
- // TODO(gri): store p.imports in AST
return &ast.File{doc, pos, ident, decls, p.pkgScope, p.imports, p.unresolved[0:i], p.comments}
}
diff --git a/libgo/go/go/parser/parser_test.go b/libgo/go/go/parser/parser_test.go
index 5b52f51d4a5..39a78e5156e 100644
--- a/libgo/go/go/parser/parser_test.go
+++ b/libgo/go/go/parser/parser_test.go
@@ -10,7 +10,6 @@ import (
"testing"
)
-
var fset = token.NewFileSet()
var illegalInputs = []interface{}{
@@ -22,9 +21,26 @@ var illegalInputs = []interface{}{
`package p; func f() { if ; /* should have condition */ {} };`,
`package p; func f() { if f(); /* should have condition */ {} };`,
`package p; const c; /* should have constant value */`,
+ `package p; func f() { if _ = range x; true {} };`,
+ `package p; func f() { switch _ = range x; true {} };`,
+ `package p; func f() { for _ = range x ; ; {} };`,
+ `package p; func f() { for ; ; _ = range x {} };`,
+ `package p; func f() { for ; _ = range x ; {} };`,
+ `package p; var a = [1]int; /* illegal expression */`,
+ `package p; var a = [...]int; /* illegal expression */`,
+ `package p; var a = struct{} /* illegal expression */`,
+ `package p; var a = func(); /* illegal expression */`,
+ `package p; var a = interface{} /* illegal expression */`,
+ `package p; var a = []int /* illegal expression */`,
+ `package p; var a = map[int]int /* illegal expression */`,
+ `package p; var a = chan int; /* illegal expression */`,
+ `package p; var a = []int{[]int}; /* illegal expression */`,
+ `package p; var a = ([]int); /* illegal expression */`,
+ `package p; var a = a[[]int:[]int]; /* illegal expression */`,
+ `package p; var a = <- chan int; /* illegal expression */`,
+ `package p; func f() { select { case _ <- chan int: } };`,
}
-
func TestParseIllegalInputs(t *testing.T) {
for _, src := range illegalInputs {
_, err := ParseFile(fset, "", src, 0)
@@ -34,7 +50,6 @@ func TestParseIllegalInputs(t *testing.T) {
}
}
-
var validPrograms = []interface{}{
"package p\n",
`package p;`,
@@ -54,9 +69,9 @@ var validPrograms = []interface{}{
`package p; func f() { select { case x := (<-c): } };`,
`package p; func f() { if ; true {} };`,
`package p; func f() { switch ; {} };`,
+ `package p; func f() { for _ = range "foo" + "bar" {} };`,
}
-
func TestParseValidPrograms(t *testing.T) {
for _, src := range validPrograms {
_, err := ParseFile(fset, "", src, 0)
@@ -66,13 +81,11 @@ func TestParseValidPrograms(t *testing.T) {
}
}
-
var validFiles = []string{
"parser.go",
"parser_test.go",
}
-
func TestParse3(t *testing.T) {
for _, filename := range validFiles {
_, err := ParseFile(fset, filename, nil, DeclarationErrors)
@@ -82,7 +95,6 @@ func TestParse3(t *testing.T) {
}
}
-
func nameFilter(filename string) bool {
switch filename {
case "parser.go":
@@ -94,10 +106,8 @@ func nameFilter(filename string) bool {
return true
}
-
func dirFilter(f *os.FileInfo) bool { return nameFilter(f.Name) }
-
func TestParse4(t *testing.T) {
path := "."
pkgs, err := ParseDir(fset, path, dirFilter, 0)
diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go
index 86c32793062..9cd975ec1be 100644
--- a/libgo/go/go/printer/nodes.go
+++ b/libgo/go/go/printer/nodes.go
@@ -14,7 +14,6 @@ import (
"go/token"
)
-
// Other formatting issues:
// - better comment formatting for /*-style comments at the end of a line (e.g. a declaration)
// when the comment spans multiple lines; if such a comment is just two lines, formatting is
@@ -23,7 +22,6 @@ import (
// - should use blank instead of tab to separate one-line function bodies from
// the function header unless there is a group of consecutive one-liners
-
// ----------------------------------------------------------------------------
// Common AST nodes.
@@ -33,7 +31,7 @@ import (
// line break was printed; returns false otherwise.
//
// TODO(gri): linebreak may add too many lines if the next statement at "line"
-// is preceeded by comments because the computation of n assumes
+// is preceded by comments because the computation of n assumes
// the current position before the comment and the target position
// after the comment. Thus, after interspersing such comments, the
// space taken up by them is not considered to reduce the number of
@@ -56,7 +54,6 @@ func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (prin
return
}
-
// setComment sets g as the next comment if g != nil and if node comments
// are enabled - this mode is used when printing source code fragments such
// as exports only. It assumes that there are no other pending comments to
@@ -78,7 +75,6 @@ func (p *printer) setComment(g *ast.CommentGroup) {
p.cindex = 0
}
-
type exprListMode uint
const (
@@ -90,7 +86,6 @@ const (
periodSep // elements are separated by periods
)
-
// Sets multiLine to true if the identifier list spans multiple lines.
// If indent is set, a multi-line identifier list is indented after the
// first linebreak encountered.
@@ -107,7 +102,6 @@ func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos)
}
-
// Print a list of expressions. If the list spans multiple
// source lines, the original line breaks are respected between
// expressions. Sets multiLine to true if the list spans multiple
@@ -215,12 +209,13 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
}
if i > 0 {
- if mode&commaSep != 0 {
+ switch {
+ case mode&commaSep != 0:
p.print(token.COMMA)
- }
- if mode&periodSep != 0 {
+ case mode&periodSep != 0:
p.print(token.PERIOD)
}
+ needsBlank := mode&periodSep == 0 // period-separated list elements don't need a blank
if prevLine < line && prevLine > 0 && line > 0 {
// lines are broken using newlines so comments remain aligned
// unless forceFF is set or there are multiple expressions on
@@ -229,11 +224,12 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
ws = ignore
*multiLine = true
prevBreak = i
+ needsBlank = false // we got a line break instead
}
- } else if mode&periodSep == 0 {
+ }
+ if needsBlank {
p.print(blank)
}
- // period-separated list elements don't need a blank
}
if isPair && size > 0 && len(list) > 1 {
@@ -269,7 +265,6 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
}
}
-
// Sets multiLine to true if the the parameter list spans multiple lines.
func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
p.print(fields.Opening, token.LPAREN)
@@ -300,7 +295,6 @@ func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
p.print(fields.Closing, token.RPAREN)
}
-
// Sets multiLine to true if the signature spans multiple lines.
func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) {
p.parameters(params, multiLine)
@@ -316,7 +310,6 @@ func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) {
}
}
-
func identListSize(list []*ast.Ident, maxSize int) (size int) {
for i, x := range list {
if i > 0 {
@@ -330,7 +323,6 @@ func identListSize(list []*ast.Ident, maxSize int) (size int) {
return
}
-
func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
if len(list) != 1 {
return false // allow only one field
@@ -349,18 +341,11 @@ func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
return namesSize+typeSize <= maxSize
}
-
func (p *printer) setLineComment(text string) {
p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos, text}}})
}
-
func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
- p.nesting++
- defer func() {
- p.nesting--
- }()
-
lbrace := fields.Opening
list := fields.List
rbrace := fields.Closing
@@ -438,8 +423,8 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
if len(list) > 0 {
p.print(formfeed)
}
- p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't loose the last line comment
- p.setLineComment("// contains unexported fields")
+ p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't lose the last line comment
+ p.setLineComment("// contains filtered or unexported fields")
}
} else { // interface
@@ -465,15 +450,14 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
if len(list) > 0 {
p.print(formfeed)
}
- p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't loose the last line comment
- p.setLineComment("// contains unexported methods")
+ p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't lose the last line comment
+ p.setLineComment("// contains filtered or unexported methods")
}
}
p.print(unindent, formfeed, rbrace, token.RBRACE)
}
-
// ----------------------------------------------------------------------------
// Expressions
@@ -532,7 +516,6 @@ func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) {
return
}
-
func cutoff(e *ast.BinaryExpr, depth int) int {
has4, has5, maxProblem := walkBinary(e)
if maxProblem > 0 {
@@ -550,7 +533,6 @@ func cutoff(e *ast.BinaryExpr, depth int) int {
return 4
}
-
func diffPrec(expr ast.Expr, prec int) int {
x, ok := expr.(*ast.BinaryExpr)
if !ok || prec != x.Op.Precedence() {
@@ -559,7 +541,6 @@ func diffPrec(expr ast.Expr, prec int) int {
return 0
}
-
func reduceDepth(depth int) int {
depth--
if depth < 1 {
@@ -568,7 +549,6 @@ func reduceDepth(depth int) int {
return depth
}
-
// Format the binary expression: decide the cutoff and then format.
// Let's call depth == 1 Normal mode, and depth > 1 Compact mode.
// (Algorithm suggestion by Russ Cox.)
@@ -646,13 +626,11 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL
}
}
-
func isBinary(expr ast.Expr) bool {
_, ok := expr.(*ast.BinaryExpr)
return ok
}
-
// If the expression contains one or more selector expressions, splits it into
// two expressions at the rightmost period. Writes entire expr to suffix when
// selector isn't found. Rewrites AST nodes for calls, index expressions and
@@ -692,7 +670,6 @@ func splitSelector(expr ast.Expr) (body, suffix ast.Expr) {
return
}
-
// Convert an expression into an expression list split at the periods of
// selector expressions.
func selectorExprList(expr ast.Expr) (list []ast.Expr) {
@@ -711,7 +688,6 @@ func selectorExprList(expr ast.Expr) (list []ast.Expr) {
return
}
-
// Sets multiLine to true if the expression spans multiple lines.
func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
p.print(expr.Pos())
@@ -898,19 +874,16 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
return
}
-
func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) {
p.expr1(x, token.LowestPrec, depth, multiLine)
}
-
// Sets multiLine to true if the expression spans multiple lines.
func (p *printer) expr(x ast.Expr, multiLine *bool) {
const depth = 1
p.expr1(x, token.LowestPrec, depth, multiLine)
}
-
// ----------------------------------------------------------------------------
// Statements
@@ -935,7 +908,6 @@ func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
}
}
-
// block prints an *ast.BlockStmt; it always spans at least two lines.
func (p *printer) block(s *ast.BlockStmt, indent int) {
p.print(s.Pos(), token.LBRACE)
@@ -944,7 +916,6 @@ func (p *printer) block(s *ast.BlockStmt, indent int) {
p.print(s.Rbrace, token.RBRACE)
}
-
func isTypeName(x ast.Expr) bool {
switch t := x.(type) {
case *ast.Ident:
@@ -955,7 +926,6 @@ func isTypeName(x ast.Expr) bool {
return false
}
-
func stripParens(x ast.Expr) ast.Expr {
if px, strip := x.(*ast.ParenExpr); strip {
// parentheses must not be stripped if there are any
@@ -982,7 +952,6 @@ func stripParens(x ast.Expr) ast.Expr {
return x
}
-
func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, post ast.Stmt) {
p.print(blank)
needsBlank := false
@@ -1017,7 +986,6 @@ func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po
}
}
-
// Sets multiLine to true if the statements spans multiple lines.
func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
p.print(stmt.Pos())
@@ -1156,8 +1124,14 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
case *ast.SelectStmt:
p.print(token.SELECT, blank)
- p.block(s.Body, 0)
- *multiLine = true
+ body := s.Body
+ if len(body.List) == 0 && !p.commentBefore(p.fset.Position(body.Rbrace)) {
+ // print empty select statement w/o comments on one line
+ p.print(body.Lbrace, token.LBRACE, body.Rbrace, token.RBRACE)
+ } else {
+ p.block(body, 0)
+ *multiLine = true
+ }
case *ast.ForStmt:
p.print(token.FOR)
@@ -1185,10 +1159,98 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
return
}
-
// ----------------------------------------------------------------------------
// Declarations
+// The keepTypeColumn function determines if the type column of a series of
+// consecutive const or var declarations must be kept, or if initialization
+// values (V) can be placed in the type column (T) instead. The i'th entry
+// in the result slice is true if the type column in spec[i] must be kept.
+//
+// For example, the declaration:
+//
+// const (
+// foobar int = 42 // comment
+// x = 7 // comment
+// foo
+// bar = 991
+// )
+//
+// leads to the type/values matrix below. A run of value columns (V) can
+// be moved into the type column if there is no type for any of the values
+// in that column (we only move entire columns so that they align properly).
+//
+// matrix formatted result
+// matrix
+// T V -> T V -> true there is a T and so the type
+// - V - V true column must be kept
+// - - - - false
+// - V V - false V is moved into T column
+//
+func keepTypeColumn(specs []ast.Spec) []bool {
+ m := make([]bool, len(specs))
+
+ populate := func(i, j int, keepType bool) {
+ if keepType {
+ for ; i < j; i++ {
+ m[i] = true
+ }
+ }
+ }
+
+ i0 := -1 // if i0 >= 0 we are in a run and i0 is the start of the run
+ var keepType bool
+ for i, s := range specs {
+ t := s.(*ast.ValueSpec)
+ if t.Values != nil {
+ if i0 < 0 {
+ // start of a run of ValueSpecs with non-nil Values
+ i0 = i
+ keepType = false
+ }
+ } else {
+ if i0 >= 0 {
+ // end of a run
+ populate(i0, i, keepType)
+ i0 = -1
+ }
+ }
+ if t.Type != nil {
+ keepType = true
+ }
+ }
+ if i0 >= 0 {
+ // end of a run
+ populate(i0, len(specs), keepType)
+ }
+
+ return m
+}
+
+func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine *bool) {
+ p.setComment(s.Doc)
+ p.identList(s.Names, doIndent, multiLine) // always present
+ extraTabs := 3
+ if s.Type != nil || keepType {
+ p.print(vtab)
+ extraTabs--
+ }
+ if s.Type != nil {
+ p.expr(s.Type, multiLine)
+ }
+ if s.Values != nil {
+ p.print(vtab, token.ASSIGN)
+ p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
+ extraTabs--
+ }
+ if s.Comment != nil {
+ for ; extraTabs > 0; extraTabs-- {
+ p.print(vtab)
+ }
+ p.setComment(s.Comment)
+ }
+}
+
// The parameter n is the number of specs in the group. If doIndent is set,
// multi-line identifier lists in the spec are indented when the first
// linebreak is encountered.
@@ -1206,38 +1268,20 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
p.setComment(s.Comment)
case *ast.ValueSpec:
+ if n != 1 {
+ p.internalError("expected n = 1; got", n)
+ }
p.setComment(s.Doc)
p.identList(s.Names, doIndent, multiLine) // always present
- if n == 1 {
- if s.Type != nil {
- p.print(blank)
- p.expr(s.Type, multiLine)
- }
- if s.Values != nil {
- p.print(blank, token.ASSIGN)
- p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
- }
- p.setComment(s.Comment)
-
- } else {
- extraTabs := 3
- if s.Type != nil {
- p.print(vtab)
- p.expr(s.Type, multiLine)
- extraTabs--
- }
- if s.Values != nil {
- p.print(vtab, token.ASSIGN)
- p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
- extraTabs--
- }
- if s.Comment != nil {
- for ; extraTabs > 0; extraTabs-- {
- p.print(vtab)
- }
- p.setComment(s.Comment)
- }
+ if s.Type != nil {
+ p.print(blank)
+ p.expr(s.Type, multiLine)
}
+ if s.Values != nil {
+ p.print(blank, token.ASSIGN)
+ p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
+ }
+ p.setComment(s.Comment)
case *ast.TypeSpec:
p.setComment(s.Doc)
@@ -1255,7 +1299,6 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
}
}
-
// Sets multiLine to true if the declaration spans multiple lines.
func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
p.setComment(d.Doc)
@@ -1264,15 +1307,29 @@ func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
if d.Lparen.IsValid() {
// group of parenthesized declarations
p.print(d.Lparen, token.LPAREN)
- if len(d.Specs) > 0 {
+ if n := len(d.Specs); n > 0 {
p.print(indent, formfeed)
- var ml bool
- for i, s := range d.Specs {
- if i > 0 {
- p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml)
+ if n > 1 && (d.Tok == token.CONST || d.Tok == token.VAR) {
+ // two or more grouped const/var declarations:
+ // determine if the type column must be kept
+ keepType := keepTypeColumn(d.Specs)
+ var ml bool
+ for i, s := range d.Specs {
+ if i > 0 {
+ p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml)
+ }
+ ml = false
+ p.valueSpec(s.(*ast.ValueSpec), keepType[i], false, &ml)
+ }
+ } else {
+ var ml bool
+ for i, s := range d.Specs {
+ if i > 0 {
+ p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml)
+ }
+ ml = false
+ p.spec(s, n, false, &ml)
}
- ml = false
- p.spec(s, len(d.Specs), false, &ml)
}
p.print(unindent, formfeed)
*multiLine = true
@@ -1285,7 +1342,6 @@ func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
}
}
-
// nodeSize determines the size of n in chars after formatting.
// The result is <= maxSize if the node fits on one line with at
// most maxSize chars and the formatted output doesn't contain
@@ -1303,7 +1359,7 @@ func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
size = maxSize + 1 // assume n doesn't fit
p.nodeSizes[n] = size
- // nodeSize computation must be indendent of particular
+ // nodeSize computation must be independent of particular
// style so that we always get the same decision; print
// in RawFormat
cfg := Config{Mode: RawFormat}
@@ -1323,7 +1379,6 @@ func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
return
}
-
func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
pos1 := b.Pos()
pos2 := b.Rbrace
@@ -1347,18 +1402,12 @@ func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
return headerSize+bodySize <= maxSize
}
-
// Sets multiLine to true if the function body spans multiple lines.
func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLine *bool) {
if b == nil {
return
}
- p.nesting++
- defer func() {
- p.nesting--
- }()
-
if p.isOneLineFunc(b, headerSize) {
sep := vtab
if isLit {
@@ -1384,7 +1433,6 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
*multiLine = true
}
-
// distance returns the column difference between from and to if both
// are on the same line; if they are on different lines (or unknown)
// the result is infinity.
@@ -1396,7 +1444,6 @@ func (p *printer) distance(from0 token.Pos, to token.Position) int {
return infinity
}
-
// Sets multiLine to true if the declaration spans multiple lines.
func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
p.setComment(d.Doc)
@@ -1410,7 +1457,6 @@ func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false, multiLine)
}
-
// Sets multiLine to true if the declaration spans multiple lines.
func (p *printer) decl(decl ast.Decl, multiLine *bool) {
switch d := decl.(type) {
@@ -1425,7 +1471,6 @@ func (p *printer) decl(decl ast.Decl, multiLine *bool) {
}
}
-
// ----------------------------------------------------------------------------
// Files
@@ -1440,7 +1485,6 @@ func declToken(decl ast.Decl) (tok token.Token) {
return
}
-
func (p *printer) file(src *ast.File) {
p.setComment(src.Doc)
p.print(src.Pos(), token.PACKAGE, blank)
diff --git a/libgo/go/go/printer/performance_test.go b/libgo/go/go/printer/performance_test.go
index 31de0b7ad40..84fb2808eba 100644
--- a/libgo/go/go/printer/performance_test.go
+++ b/libgo/go/go/printer/performance_test.go
@@ -17,17 +17,14 @@ import (
"testing"
)
-
var testfile *ast.File
-
func testprint(out io.Writer, file *ast.File) {
if _, err := (&Config{TabIndent | UseSpaces, 8}).Fprint(out, fset, file); err != nil {
log.Fatalf("print error: %s", err)
}
}
-
// cannot initialize in init because (printer) Fprint launches goroutines.
func initialize() {
const filename = "testdata/parser.go"
@@ -51,7 +48,6 @@ func initialize() {
testfile = file
}
-
func BenchmarkPrint(b *testing.B) {
if testfile == nil {
initialize()
diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go
index 01ebf783c41..871fefa0c8f 100644
--- a/libgo/go/go/printer/printer.go
+++ b/libgo/go/go/printer/printer.go
@@ -17,7 +17,6 @@ import (
"tabwriter"
)
-
const debug = false // enable for debugging
@@ -33,7 +32,6 @@ const (
unindent = whiteSpace('<')
)
-
var (
esc = []byte{tabwriter.Escape}
htab = []byte{'\t'}
@@ -42,16 +40,13 @@ var (
formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than the max determined by nlines
)
-
// Special positions
var noPos token.Position // use noPos when a position is needed but not known
var infinity = 1 << 30
-
// Use ignoreMultiLine if the multiLine information is not important.
var ignoreMultiLine = new(bool)
-
// A pmode value represents the current printer mode.
type pmode int
@@ -60,7 +55,6 @@ const (
noExtraLinebreak
)
-
type printer struct {
// Configuration (does not change after initialization)
output io.Writer
@@ -69,7 +63,6 @@ type printer struct {
errors chan os.Error
// Current state
- nesting int // nesting level (0: top-level (package scope), >0: functions/decls.)
written int // number of bytes written
indent int // current indentation
mode pmode // current printer mode
@@ -98,7 +91,6 @@ type printer struct {
nodeSizes map[ast.Node]int
}
-
func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node]int) {
p.output = output
p.Config = *cfg
@@ -108,7 +100,6 @@ func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet, nodeS
p.nodeSizes = nodeSizes
}
-
func (p *printer) internalError(msg ...interface{}) {
if debug {
fmt.Print(p.pos.String() + ": ")
@@ -117,7 +108,6 @@ func (p *printer) internalError(msg ...interface{}) {
}
}
-
// escape escapes string s by bracketing it with tabwriter.Escape.
// Escaped strings pass through tabwriter unchanged. (Note that
// valid Go programs cannot contain tabwriter.Escape bytes since
@@ -131,26 +121,20 @@ func (p *printer) escape(s string) string {
return p.litbuf.String()
}
-
// nlines returns the adjusted number of linebreaks given the desired number
-// of breaks n such that min <= result <= max where max depends on the current
-// nesting level.
+// of breaks n such that min <= result <= max.
//
func (p *printer) nlines(n, min int) int {
- if n < min {
+ const max = 2 // max. number of newlines
+ switch {
+ case n < min:
return min
- }
- max := 3 // max. number of newlines at the top level (p.nesting == 0)
- if p.nesting > 0 {
- max = 2 // max. number of newlines everywhere else
- }
- if n > max {
+ case n > max:
return max
}
return n
}
-
// write0 writes raw (uninterpreted) data to p.output and handles errors.
// write0 does not indent after newlines, and does not HTML-escape or update p.pos.
//
@@ -165,7 +149,6 @@ func (p *printer) write0(data []byte) {
}
}
-
// write interprets data and writes it to p.output. It inserts indentation
// after a line break unless in a tabwriter escape sequence.
// It updates p.pos as a side-effect.
@@ -220,7 +203,6 @@ func (p *printer) write(data []byte) {
p.pos.Column += d
}
-
func (p *printer) writeNewlines(n int, useFF bool) {
if n > 0 {
n = p.nlines(n, 0)
@@ -232,7 +214,6 @@ func (p *printer) writeNewlines(n int, useFF bool) {
}
}
-
// writeItem writes data at position pos. data is the text corresponding to
// a single lexical token, but may also be comment text. pos is the actual
// (or at least very accurately estimated) position of the data in the original
@@ -261,7 +242,6 @@ func (p *printer) writeItem(pos token.Position, data string) {
p.last = p.pos
}
-
// writeCommentPrefix writes the whitespace before a comment.
// If there is any pending whitespace, it consumes as much of
// it as is likely to help position the comment nicely.
@@ -368,7 +348,6 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment
}
}
-
// TODO(gri): It should be possible to convert the code below from using
// []byte to string and in the process eliminate some conversions.
@@ -398,7 +377,6 @@ func split(text []byte) [][]byte {
return lines
}
-
func isBlank(s []byte) bool {
for _, b := range s {
if b > ' ' {
@@ -408,7 +386,6 @@ func isBlank(s []byte) bool {
return true
}
-
func commonPrefix(a, b []byte) []byte {
i := 0
for i < len(a) && i < len(b) && a[i] == b[i] && (a[i] <= ' ' || a[i] == '*') {
@@ -417,7 +394,6 @@ func commonPrefix(a, b []byte) []byte {
return a[0:i]
}
-
func stripCommonPrefix(lines [][]byte) {
if len(lines) < 2 {
return // at most one line - nothing to do
@@ -545,7 +521,6 @@ func stripCommonPrefix(lines [][]byte) {
}
}
-
func (p *printer) writeComment(comment *ast.Comment) {
text := comment.Text
@@ -575,7 +550,6 @@ func (p *printer) writeComment(comment *ast.Comment) {
}
}
-
// writeCommentSuffix writes a line break after a comment if indicated
// and processes any leftover indentation information. If a line break
// is needed, the kind of break (newline vs formfeed) depends on the
@@ -589,7 +563,7 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
// ignore trailing whitespace
p.wsbuf[i] = ignore
case indent, unindent:
- // don't loose indentation information
+ // don't lose indentation information
case newline, formfeed:
// if we need a line break, keep exactly one
// but remember if we dropped any formfeeds
@@ -613,7 +587,6 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
return
}
-
// intersperseComments consumes all comments that appear before the next token
// tok and prints it together with the buffered whitespace (i.e., the whitespace
// that needs to be written before the next token). A heuristic is used to mix
@@ -651,7 +624,6 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro
return false
}
-
// whiteWhitespace writes the first n whitespace entries.
func (p *printer) writeWhitespace(n int) {
// write entries
@@ -701,7 +673,6 @@ func (p *printer) writeWhitespace(n int) {
p.wsbuf = p.wsbuf[0:i]
}
-
// ----------------------------------------------------------------------------
// Printing interface
@@ -724,7 +695,6 @@ func mayCombine(prev token.Token, next byte) (b bool) {
return
}
-
// print prints a list of "items" (roughly corresponding to syntactic
// tokens, but also including whitespace and formatting information).
// It is the only print function that should be called directly from
@@ -812,7 +782,6 @@ func (p *printer) print(args ...interface{}) {
}
}
-
// commentBefore returns true iff the current comment occurs
// before the next position in the source code.
//
@@ -820,7 +789,6 @@ func (p *printer) commentBefore(next token.Position) bool {
return p.cindex < len(p.comments) && p.fset.Position(p.comments[p.cindex].List[0].Pos()).Offset < next.Offset
}
-
// Flush prints any pending comments and whitespace occurring
// textually before the position of the next token tok. Flush
// returns true if a pending formfeed character was dropped
@@ -838,7 +806,6 @@ func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
return
}
-
// ----------------------------------------------------------------------------
// Trimmer
@@ -854,7 +821,6 @@ type trimmer struct {
space bytes.Buffer
}
-
// trimmer is implemented as a state machine.
// It can be in one of the following states:
const (
@@ -863,7 +829,6 @@ const (
inText // inside text
)
-
// Design note: It is tempting to eliminate extra blanks occurring in
// whitespace in this function as it could simplify some
// of the blanks logic in the node printing functions.
@@ -941,7 +906,6 @@ func (p *trimmer) Write(data []byte) (n int, err os.Error) {
return
}
-
// ----------------------------------------------------------------------------
// Public interface
@@ -952,14 +916,12 @@ const (
UseSpaces // use spaces instead of tabs for alignment
)
-
// A Config node controls the output of Fprint.
type Config struct {
Mode uint // default: 0
Tabwidth int // default: 8
}
-
// fprint implements Fprint and takes a nodesSizes map for setting up the printer state.
func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{}, nodeSizes map[ast.Node]int) (int, os.Error) {
// redirect output through a trimmer to eliminate trailing whitespace
@@ -994,11 +956,9 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{
go func() {
switch n := node.(type) {
case ast.Expr:
- p.nesting = 1
p.useNodeComments = true
p.expr(n, ignoreMultiLine)
case ast.Stmt:
- p.nesting = 1
p.useNodeComments = true
// A labeled statement will un-indent to position the
// label. Set indent to 1 so we don't get indent "underflow".
@@ -1007,15 +967,12 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{
}
p.stmt(n, false, ignoreMultiLine)
case ast.Decl:
- p.nesting = 1
p.useNodeComments = true
p.decl(n, ignoreMultiLine)
case ast.Spec:
- p.nesting = 1
p.useNodeComments = true
p.spec(n, 1, false, ignoreMultiLine)
case *ast.File:
- p.nesting = 0
p.comments = n.Comments
p.useNodeComments = n.Comments == nil
p.file(n)
@@ -1036,7 +993,6 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{
return p.written, err
}
-
// Fprint "pretty-prints" an AST node to output and returns the number
// of bytes written and an error (if any) for a given configuration cfg.
// Position information is interpreted relative to the file set fset.
@@ -1047,7 +1003,6 @@ func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{
return cfg.fprint(output, fset, node, make(map[ast.Node]int))
}
-
// Fprint "pretty-prints" an AST node to output.
// It calls Config.Fprint with default settings.
//
diff --git a/libgo/go/go/printer/printer_test.go b/libgo/go/go/printer/printer_test.go
index 090f92af181..ff2d906b560 100644
--- a/libgo/go/go/printer/printer_test.go
+++ b/libgo/go/go/printer/printer_test.go
@@ -16,19 +16,15 @@ import (
"time"
)
-
const (
dataDir = "testdata"
tabwidth = 8
)
-
var update = flag.Bool("update", false, "update golden files")
-
var fset = token.NewFileSet()
-
func lineString(text []byte, i int) string {
i0 := i
for i < len(text) && text[i] != '\n' {
@@ -37,7 +33,6 @@ func lineString(text []byte, i int) string {
return string(text[i0:i])
}
-
type checkMode uint
const (
@@ -45,7 +40,6 @@ const (
rawFormat
)
-
func runcheck(t *testing.T, source, golden string, mode checkMode) {
// parse source
prog, err := parser.ParseFile(fset, source, nil, parser.ParseComments)
@@ -109,7 +103,6 @@ func runcheck(t *testing.T, source, golden string, mode checkMode) {
}
}
-
func check(t *testing.T, source, golden string, mode checkMode) {
// start a timer to produce a time-out signal
tc := make(chan int)
@@ -135,7 +128,6 @@ func check(t *testing.T, source, golden string, mode checkMode) {
}
}
-
type entry struct {
source, golden string
mode checkMode
@@ -154,7 +146,6 @@ var data = []entry{
{"slow.input", "slow.golden", 0},
}
-
func TestFiles(t *testing.T) {
for i, e := range data {
source := filepath.Join(dataDir, e.source)
@@ -168,7 +159,6 @@ func TestFiles(t *testing.T) {
}
}
-
// TestLineComments, using a simple test case, checks that consequtive line
// comments are properly terminated with a newline even if the AST position
// information is incorrect.
diff --git a/libgo/go/go/printer/testdata/comments.golden b/libgo/go/go/printer/testdata/comments.golden
index a86d6617432..7b332252c4e 100644
--- a/libgo/go/go/printer/testdata/comments.golden
+++ b/libgo/go/go/printer/testdata/comments.golden
@@ -22,7 +22,7 @@ const (
_ = iota + 10
_ // comments
- _ = 10 // comment
+ _ = 10 // comment
_ T = 20 // comment
)
@@ -38,9 +38,9 @@ const (
_ // comment
_ // comment
_ = iota + 10
- _ // comment
- _ = 10
- _ = 20 // comment
+ _ // comment
+ _ = 10
+ _ = 20 // comment
_ T = 0 // comment
)
@@ -106,7 +106,6 @@ type S3 struct {
var x int // x
var ()
-
// This comment SHOULD be associated with the next declaration.
func f0() {
const pi = 3.14 // pi
@@ -128,12 +127,10 @@ func f1() {
f0()
}
-
func _() {
// this comment should be properly indented
}
-
func _(x int) int {
if x < 0 { // the tab printed before this comment's // must not affect the remaining lines
return -x // this statement should be properly indented
@@ -144,7 +141,6 @@ func _(x int) int {
return x
}
-
func typeswitch(x interface{}) {
switch v := x.(type) {
case bool, int, float:
@@ -211,7 +207,6 @@ func _() {
aligned line */
}
-
func _() {
/*
freestanding comment
@@ -292,7 +287,6 @@ func _() {
aligned line */
}
-
func _() {
/*
freestanding comment
@@ -409,7 +403,6 @@ func _() {
*/
}
-
// Some interesting interspersed comments
func _( /* this */ x /* is */ /* an */ int) {
}
@@ -434,9 +427,8 @@ func _() {
_ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */ }
}
-
// Comments immediately adjacent to punctuation (for which the go/printer
-// may obly have estimated position information) must remain after the punctuation.
+// may only have estimated position information) must remain after the punctuation.
func _() {
_ = T{
1, // comment after comma
@@ -466,7 +458,6 @@ func _() {
}
}
-
// Line comments with tabs
func _() {
var finput *bufio.Reader // input file
@@ -479,5 +470,4 @@ func _() {
var lflag bool // -l - disable line directives
}
-
/* This comment is the last entry in this file. It must be printed and should be followed by a newline */
diff --git a/libgo/go/go/printer/testdata/comments.input b/libgo/go/go/printer/testdata/comments.input
index 14cd4cf7a12..2a9a86b6815 100644
--- a/libgo/go/go/printer/testdata/comments.input
+++ b/libgo/go/go/printer/testdata/comments.input
@@ -434,7 +434,7 @@ func _() {
// Comments immediately adjacent to punctuation (for which the go/printer
-// may obly have estimated position information) must remain after the punctuation.
+// may only have estimated position information) must remain after the punctuation.
func _() {
_ = T{
1, // comment after comma
diff --git a/libgo/go/go/printer/testdata/comments.x b/libgo/go/go/printer/testdata/comments.x
index 4d7a928ae09..ae7729286e5 100644
--- a/libgo/go/go/printer/testdata/comments.x
+++ b/libgo/go/go/printer/testdata/comments.x
@@ -2,13 +2,12 @@
//
package main
-
// The SZ struct; it is empty.
type SZ struct{}
// The S0 struct; no field is exported.
type S0 struct {
- // contains unexported fields
+ // contains filtered or unexported fields
}
// The S1 struct; some fields are not exported.
@@ -16,7 +15,7 @@ type S1 struct {
S0
A, B, C float // 3 exported fields
D int // 2 unexported fields
- // contains unexported fields
+ // contains filtered or unexported fields
}
// The S2 struct; all fields are exported.
@@ -30,14 +29,14 @@ type SZ interface{}
// The I0 interface; no method is exported.
type I0 interface {
- // contains unexported methods
+ // contains filtered or unexported methods
}
// The I1 interface; some methods are not exported.
type I1 interface {
I0
F(x float) float // exported methods
- // contains unexported methods
+ // contains filtered or unexported methods
}
// The I2 interface; all methods are exported.
@@ -53,5 +52,5 @@ type S3 struct {
F1 int // line comment for F1
// lead comment for F2
F2 int // line comment for F2
- // contains unexported fields
+ // contains filtered or unexported fields
}
diff --git a/libgo/go/go/printer/testdata/declarations.golden b/libgo/go/go/printer/testdata/declarations.golden
index c1b255842c1..970533e8cfb 100644
--- a/libgo/go/go/printer/testdata/declarations.golden
+++ b/libgo/go/go/printer/testdata/declarations.golden
@@ -44,7 +44,6 @@ import _ "os"
import _ "os"
import _ "os"
-
import _ "fmt"
import _ "fmt"
import _ "fmt"
@@ -116,7 +115,6 @@ import _ "io"
var _ int
-
// printing of constant literals
const (
_ = "foobar"
@@ -158,9 +156,7 @@ const (
bar`
)
-
func _() {
- // the following decls need a semicolon at the end
type _ int
type _ *int
type _ []int
@@ -175,7 +171,6 @@ func _() {
var _ chan int
var _ func() int
- // the following decls don't need a semicolon at the end
type _ struct{}
type _ *struct{}
type _ []struct{}
@@ -205,7 +200,6 @@ func _() {
var _ func() interface{}
}
-
// don't lose blank lines in grouped declarations
const (
_ int = 0
@@ -222,7 +216,6 @@ const (
_
)
-
type (
_ int
_ struct{}
@@ -233,7 +226,6 @@ type (
_ map[string]int
)
-
var (
_ int = 0
_ float = 1
@@ -246,7 +238,6 @@ var (
_ bool
)
-
// don't lose blank lines in this struct
type _ struct {
String struct {
@@ -295,7 +286,6 @@ type _ struct {
}
}
-
// no tabs for single or ungrouped decls
func _() {
const xxxxxx = 0
@@ -331,11 +321,11 @@ func _() {
)
// some entries have a type
const (
- xxxxxx = 1
- x = 2
- xxx = 3
+ xxxxxx = 1
+ x = 2
+ xxx = 3
yyyyyyyy float = iota
- yyyy = "bar"
+ yyyy = "bar"
yyy
yy = 2
)
@@ -365,7 +355,7 @@ func _() {
xxx string
yyyyyyyy int = 1234
y float = 3.14
- yyyy = "bar"
+ yyyy = "bar"
yyy string = "foo"
)
// mixed entries - all comments should be aligned
@@ -373,7 +363,7 @@ func _() {
a, b, c int
x = 10
d int // comment
- y = 20 // comment
+ y = 20 // comment
f, ff, fff, ffff int = 0, 1, 2, 3 // comment
)
// respect original line breaks
@@ -401,6 +391,32 @@ func _() {
)
}
+// alignment of "=" in consecutive lines (extended example from issue 1414)
+const (
+ umax uint = ^uint(0) // maximum value for a uint
+ bpu = 1 << (5 + umax>>63) // bits per uint
+ foo
+ bar = -1
+)
+
+// typical enum
+const (
+ a MyType = iota
+ abcd
+ b
+ c
+ def
+)
+
+// excerpt from godoc.go
+var (
+ goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
+ testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)")
+ pkgPath = flag.String("path", "", "additional package directories (colon-separated)")
+ filter = flag.String("filter", "", "filter file containing permitted package directory paths")
+ filterMin = flag.Int("filter_minutes", 0, "filter file update interval in minutes; disabled if <= 0")
+ filterDelay delayTime // actual filter update interval in minutes; usually filterDelay == filterMin, but filterDelay may back off exponentially
+)
// formatting of structs
type _ struct{}
@@ -469,14 +485,12 @@ type _ struct {
r, s float // this line should be indented
}
-
// difficult cases
type _ struct {
bool // comment
text []byte // comment
}
-
// formatting of interfaces
type EI interface{}
@@ -502,7 +516,6 @@ type _ interface { // this comment must not change indentation
gggggggggggg(x, y, z int) // hurray
}
-
// formatting of variable declarations
func _() {
type day struct {
@@ -520,7 +533,6 @@ func _() {
)
}
-
// formatting of multi-line variable declarations
var a1, b1, c1 int // all on one line
@@ -533,7 +545,6 @@ var (
a4, b4, c4 int // this line should be indented
)
-
func _() {
var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
Headers: map[string]string{},
@@ -545,7 +556,6 @@ func _() {
}
}
-
func _() {
var Universe = Scope{
Names: map[string]*Ident{
@@ -589,7 +599,6 @@ func _() {
}
}
-
// alignment of map composite entries
var _ = map[int]int{
// small key sizes: always align even if size ratios are large
@@ -613,21 +622,18 @@ var _ = map[int]int{
abcde: a, // align with previous line
}
-
func _() {
var _ = T{
a, // must introduce trailing comma
}
}
-
// formatting of function results
func _() func() {}
func _() func(int) { return nil }
func _() func(int) int { return nil }
func _() func(int) func(int) func() { return nil }
-
// formatting of consecutive single-line functions
func _() {}
func _() {}
@@ -655,7 +661,6 @@ func _() int {
return x
}
-
// making function declarations safe for new semicolon rules
func _() { /* multi-line func because of comment */
}
@@ -664,7 +669,6 @@ func _() {
/* multi-line func because block is on multiple lines */
}
-
// ellipsis parameters
func _(...int)
func _(...*int)
@@ -686,7 +690,6 @@ func _(x ...func(...int))
func _(x ...map[string]int)
func _(x ...chan int)
-
// these parameter lists must remain multi-line since they are multi-line in the source
func _(bool,
int) {
diff --git a/libgo/go/go/printer/testdata/declarations.input b/libgo/go/go/printer/testdata/declarations.input
index c8b37e12ba4..c6134096bf1 100644
--- a/libgo/go/go/printer/testdata/declarations.input
+++ b/libgo/go/go/printer/testdata/declarations.input
@@ -159,7 +159,6 @@ bar`
func _() {
- // the following decls need a semicolon at the end
type _ int
type _ *int
type _ []int
@@ -174,7 +173,6 @@ func _() {
var _ chan int
var _ func() int
- // the following decls don't need a semicolon at the end
type _ struct{}
type _ *struct{}
type _ []struct{}
@@ -400,6 +398,33 @@ func _() {
)
}
+// alignment of "=" in consecutive lines (extended example from issue 1414)
+const (
+ umax uint = ^uint(0) // maximum value for a uint
+ bpu = 1 << (5 + umax>>63) // bits per uint
+ foo
+ bar = -1
+)
+
+// typical enum
+const (
+ a MyType = iota
+ abcd
+ b
+ c
+ def
+)
+
+// excerpt from godoc.go
+var (
+ goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
+ testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)")
+ pkgPath = flag.String("path", "", "additional package directories (colon-separated)")
+ filter = flag.String("filter", "", "filter file containing permitted package directory paths")
+ filterMin = flag.Int("filter_minutes", 0, "filter file update interval in minutes; disabled if <= 0")
+ filterDelay delayTime // actual filter update interval in minutes; usually filterDelay == filterMin, but filterDelay may back off exponentially
+)
+
// formatting of structs
type _ struct{}
diff --git a/libgo/go/go/printer/testdata/expressions.golden b/libgo/go/go/printer/testdata/expressions.golden
index 3d0f144e10f..d0cf24ad6f6 100644
--- a/libgo/go/go/printer/testdata/expressions.golden
+++ b/libgo/go/go/printer/testdata/expressions.golden
@@ -17,7 +17,6 @@ var (
p *int
)
-
func _() {
// no spaces around simple or parenthesized expressions
_ = (a + 0)
@@ -115,7 +114,6 @@ func _() {
x < y || z > 42
}
-
func _() {
_ = a + b
_ = a + b + c
@@ -187,7 +185,6 @@ func _() {
_ = token(matchType + xlength<<lengthShift + xoffset)
}
-
func f(x int, args ...int) {
f(0, args...)
f(1, args)
@@ -226,7 +223,6 @@ func f(x int, args ...int) {
_ = f(x / *y, x < -1, x < <-1, x + +1, x - -1, x & &x, x & ^x)
}
-
func _() {
_ = T{}
_ = struct{}{}
@@ -236,7 +232,6 @@ func _() {
_ = map[int]T{}
}
-
// one-line structs/interfaces in composite literals (up to a threshold)
func _() {
_ = struct{}{}
@@ -246,7 +241,6 @@ func _() {
_ = struct{ s struct{ int } }{struct{ int }{0}}
}
-
func _() {
// do not modify literals
_ = "tab1 tab2 tab3 end" // string contains 3 tabs
@@ -261,7 +255,6 @@ func _() {
they must not be removed`
}
-
func _() {
// smart handling of indentation for multi-line raw strings
var _ = ``
@@ -332,7 +325,6 @@ bar`
}
}
-
func _() {
// one-line function literals (body is on a single line)
_ = func() {}
@@ -361,7 +353,6 @@ func _() {
})
}
-
func _() {
_ = [][]int{
[]int{1},
@@ -381,7 +372,6 @@ func _() {
_ = [][]int{{1}, {1, 2}, {1, 2, 3}}
}
-
// various multi-line expressions
func _() {
// do not add extra indentation to multi-line string lists
@@ -397,25 +387,21 @@ func _() {
}
}
-
const _ = F1 +
`string = "%s";` +
`ptr = *;` +
`datafmt.T2 = s ["-" p "-"];`
-
const _ = `datafmt "datafmt";` +
`default = "%v";` +
`array = *;` +
`datafmt.T3 = s {" " a a / ","};`
-
const _ = `datafmt "datafmt";` +
`default = "%v";` +
`array = *;` +
`datafmt.T3 = s {" " a a / ","};`
-
func _() {
_ = F1 +
`string = "%s";` +
@@ -434,7 +420,6 @@ func _() {
`datafmt.T3 = s {" " a a / ","};`
}
-
func _() {
// respect source lines in multi-line expressions
_ = a +
@@ -448,7 +433,6 @@ func _() {
_ = "170141183460469231731687303715884105727" // prime
}
-
// Alignment after overlong lines
const (
_ = "991"
@@ -459,7 +443,6 @@ const (
_ = "170141183460469231731687303715884105727" // prime
)
-
// Correct placement of operators and comments in multi-line expressions
func _() {
_ = a + // comment
@@ -471,7 +454,6 @@ func _() {
_ = "ba0408" + "7265717569726564" // field 71, encoding 2, string "required"
}
-
// Correct placement of terminating comma/closing parentheses in multi-line calls.
func _() {
f(1,
@@ -497,7 +479,6 @@ func _() {
)
}
-
// Align comments in multi-line lists of single-line expressions.
var txpix = [NCOL]draw.Color{
draw.Yellow, // yellow
@@ -512,7 +493,6 @@ var txpix = [NCOL]draw.Color{
draw.Color(0xBB005DFF), /* maroon */
}
-
func same(t, u *Time) bool {
// respect source lines in multi-line expressions
return t.Year == u.Year &&
@@ -526,7 +506,6 @@ func same(t, u *Time) bool {
t.Zone == u.Zone
}
-
func (p *parser) charClass() {
// respect source lines in multi-line expressions
if cc.negate && len(cc.ranges) == 2 &&
@@ -536,7 +515,6 @@ func (p *parser) charClass() {
}
}
-
func addState(s []state, inst instr, match []int) {
// handle comments correctly in multi-line expressions
for i := 0; i < l; i++ {
@@ -639,12 +617,11 @@ func _() {
c
}
-
// Don't introduce extra newlines in strangely formatted expression lists.
func f() {
// os.Open parameters should remain on two lines
if writer, err = os.Open(outfile, s.O_WRONLY|os.O_CREATE|
- os.O_TRUNC,0666); err != nil {
+ os.O_TRUNC, 0666); err != nil {
log.Fatal(err)
}
}
diff --git a/libgo/go/go/printer/testdata/expressions.raw b/libgo/go/go/printer/testdata/expressions.raw
index 72ab850fab4..d7819a3baad 100644
--- a/libgo/go/go/printer/testdata/expressions.raw
+++ b/libgo/go/go/printer/testdata/expressions.raw
@@ -17,7 +17,6 @@ var (
p *int
)
-
func _() {
// no spaces around simple or parenthesized expressions
_ = (a + 0)
@@ -115,7 +114,6 @@ func _() {
x < y || z > 42
}
-
func _() {
_ = a + b
_ = a + b + c
@@ -187,7 +185,6 @@ func _() {
_ = token(matchType + xlength<<lengthShift + xoffset)
}
-
func f(x int, args ...int) {
f(0, args...)
f(1, args)
@@ -226,7 +223,6 @@ func f(x int, args ...int) {
_ = f(x / *y, x < -1, x < <-1, x + +1, x - -1, x & &x, x & ^x)
}
-
func _() {
_ = T{}
_ = struct{}{}
@@ -236,7 +232,6 @@ func _() {
_ = map[int]T{}
}
-
// one-line structs/interfaces in composite literals (up to a threshold)
func _() {
_ = struct{}{}
@@ -246,7 +241,6 @@ func _() {
_ = struct{ s struct{ int } }{struct{ int }{0}}
}
-
func _() {
// do not modify literals
_ = "tab1 tab2 tab3 end" // string contains 3 tabs
@@ -261,7 +255,6 @@ func _() {
they must not be removed`
}
-
func _() {
// smart handling of indentation for multi-line raw strings
var _ = ``
@@ -332,7 +325,6 @@ bar`
}
}
-
func _() {
// one-line function literals (body is on a single line)
_ = func() {}
@@ -361,7 +353,6 @@ func _() {
})
}
-
func _() {
_ = [][]int{
[]int{1},
@@ -381,7 +372,6 @@ func _() {
_ = [][]int{{1}, {1, 2}, {1, 2, 3}}
}
-
// various multi-line expressions
func _() {
// do not add extra indentation to multi-line string lists
@@ -397,25 +387,21 @@ func _() {
}
}
-
const _ = F1 +
`string = "%s";` +
`ptr = *;` +
`datafmt.T2 = s ["-" p "-"];`
-
const _ = `datafmt "datafmt";` +
`default = "%v";` +
`array = *;` +
`datafmt.T3 = s {" " a a / ","};`
-
const _ = `datafmt "datafmt";` +
`default = "%v";` +
`array = *;` +
`datafmt.T3 = s {" " a a / ","};`
-
func _() {
_ = F1 +
`string = "%s";` +
@@ -434,7 +420,6 @@ func _() {
`datafmt.T3 = s {" " a a / ","};`
}
-
func _() {
// respect source lines in multi-line expressions
_ = a +
@@ -448,7 +433,6 @@ func _() {
_ = "170141183460469231731687303715884105727" // prime
}
-
// Alignment after overlong lines
const (
_ = "991"
@@ -459,7 +443,6 @@ const (
_ = "170141183460469231731687303715884105727" // prime
)
-
// Correct placement of operators and comments in multi-line expressions
func _() {
_ = a + // comment
@@ -471,7 +454,6 @@ func _() {
_ = "ba0408" + "7265717569726564" // field 71, encoding 2, string "required"
}
-
// Correct placement of terminating comma/closing parentheses in multi-line calls.
func _() {
f(1,
@@ -497,7 +479,6 @@ func _() {
)
}
-
// Align comments in multi-line lists of single-line expressions.
var txpix = [NCOL]draw.Color{
draw.Yellow, // yellow
@@ -512,7 +493,6 @@ var txpix = [NCOL]draw.Color{
draw.Color(0xBB005DFF), /* maroon */
}
-
func same(t, u *Time) bool {
// respect source lines in multi-line expressions
return t.Year == u.Year &&
@@ -526,7 +506,6 @@ func same(t, u *Time) bool {
t.Zone == u.Zone
}
-
func (p *parser) charClass() {
// respect source lines in multi-line expressions
if cc.negate && len(cc.ranges) == 2 &&
@@ -536,7 +515,6 @@ func (p *parser) charClass() {
}
}
-
func addState(s []state, inst instr, match []int) {
// handle comments correctly in multi-line expressions
for i := 0; i < l; i++ {
@@ -639,12 +617,11 @@ func _() {
c
}
-
// Don't introduce extra newlines in strangely formatted expression lists.
func f() {
// os.Open parameters should remain on two lines
if writer, err = os.Open(outfile, s.O_WRONLY|os.O_CREATE|
- os.O_TRUNC,0666); err != nil {
+ os.O_TRUNC, 0666); err != nil {
log.Fatal(err)
}
}
diff --git a/libgo/go/go/printer/testdata/parser.go b/libgo/go/go/printer/testdata/parser.go
index 5c57e41d130..2d27af49920 100644
--- a/libgo/go/go/printer/testdata/parser.go
+++ b/libgo/go/go/printer/testdata/parser.go
@@ -16,7 +16,6 @@ import (
"go/token"
)
-
// The mode parameter to the Parse* functions is a set of flags (or 0).
// They control the amount of source code parsed and other optional
// parser functionality.
@@ -29,7 +28,6 @@ const (
DeclarationErrors // report declaration errors
)
-
// The parser structure holds the parser's internal state.
type parser struct {
file *token.File
@@ -66,7 +64,6 @@ type parser struct {
targetStack [][]*ast.Ident // stack of unresolved labels
}
-
// scannerMode returns the scanner mode bits given the parser's mode bits.
func scannerMode(mode uint) uint {
var m uint = scanner.InsertSemis
@@ -76,7 +73,6 @@ func scannerMode(mode uint) uint {
return m
}
-
func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uint) {
p.file = fset.AddFile(filename, fset.Base(), len(src))
p.scanner.Init(p.file, src, p, scannerMode(mode))
@@ -95,7 +91,6 @@ func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uin
p.openLabelScope()
}
-
// ----------------------------------------------------------------------------
// Scoping support
@@ -103,18 +98,15 @@ func (p *parser) openScope() {
p.topScope = ast.NewScope(p.topScope)
}
-
func (p *parser) closeScope() {
p.topScope = p.topScope.Outer
}
-
func (p *parser) openLabelScope() {
p.labelScope = ast.NewScope(p.labelScope)
p.targetStack = append(p.targetStack, nil)
}
-
func (p *parser) closeLabelScope() {
// resolve labels
n := len(p.targetStack) - 1
@@ -130,7 +122,6 @@ func (p *parser) closeLabelScope() {
p.labelScope = p.labelScope.Outer
}
-
func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
for _, ident := range idents {
assert(ident.Obj == nil, "identifier already declared or resolved")
@@ -151,7 +142,6 @@ func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, i
}
}
-
func (p *parser) shortVarDecl(idents []*ast.Ident) {
// Go spec: A short variable declaration may redeclare variables
// provided they were originally declared in the same block with
@@ -177,13 +167,11 @@ func (p *parser) shortVarDecl(idents []*ast.Ident) {
}
}
-
// The unresolved object is a sentinel to mark identifiers that have been added
// to the list of unresolved identifiers. The sentinel is only used for verifying
// internal consistency.
var unresolved = new(ast.Object)
-
func (p *parser) resolve(x ast.Expr) {
// nothing to do if x is not an identifier or the blank identifier
ident, _ := x.(*ast.Ident)
@@ -209,7 +197,6 @@ func (p *parser) resolve(x ast.Expr) {
p.unresolved = append(p.unresolved, ident)
}
-
// ----------------------------------------------------------------------------
// Parsing support
@@ -227,21 +214,18 @@ func (p *parser) printTrace(a ...interface{}) {
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
@@ -283,7 +267,6 @@ func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
return
}
-
// Consume a group of adjacent comments, add it to the parser's
// comments list, and return it together with the line at which
// the last comment in the group ends. An empty line or non-comment
@@ -305,7 +288,6 @@ func (p *parser) consumeCommentGroup() (comments *ast.CommentGroup, endline int)
return
}
-
// Advance to the next non-comment token. In the process, collect
// any comment groups encountered, and remember the last lead and
// and line comments.
@@ -356,12 +338,10 @@ func (p *parser) next() {
}
}
-
func (p *parser) error(pos token.Pos, msg string) {
p.Error(p.file.Position(pos), msg)
}
-
func (p *parser) errorExpected(pos token.Pos, msg string) {
msg = "expected " + msg
if pos == p.pos {
@@ -379,7 +359,6 @@ func (p *parser) errorExpected(pos token.Pos, msg string) {
p.error(pos, msg)
}
-
func (p *parser) expect(tok token.Token) token.Pos {
pos := p.pos
if p.tok != tok {
@@ -389,21 +368,18 @@ func (p *parser) expect(tok token.Token) token.Pos {
return pos
}
-
func (p *parser) expectSemi() {
if p.tok != token.RPAREN && p.tok != token.RBRACE {
p.expect(token.SEMICOLON)
}
}
-
func assert(cond bool, msg string) {
if !cond {
panic("go/parser internal error: " + msg)
}
}
-
// ----------------------------------------------------------------------------
// Identifiers
@@ -419,7 +395,6 @@ func (p *parser) parseIdent() *ast.Ident {
return &ast.Ident{pos, name, nil}
}
-
func (p *parser) parseIdentList() (list []*ast.Ident) {
if p.trace {
defer un(trace(p, "IdentList"))
@@ -434,7 +409,6 @@ func (p *parser) parseIdentList() (list []*ast.Ident) {
return
}
-
// ----------------------------------------------------------------------------
// Common productions
@@ -453,7 +427,6 @@ func (p *parser) parseExprList(lhs bool) (list []ast.Expr) {
return
}
-
func (p *parser) parseLhsList() []ast.Expr {
list := p.parseExprList(true)
switch p.tok {
@@ -477,12 +450,10 @@ func (p *parser) parseLhsList() []ast.Expr {
return list
}
-
func (p *parser) parseRhsList() []ast.Expr {
return p.parseExprList(false)
}
-
// ----------------------------------------------------------------------------
// Types
@@ -503,7 +474,6 @@ func (p *parser) parseType() ast.Expr {
return typ
}
-
// If the result is an identifier, it is not resolved.
func (p *parser) parseTypeName() ast.Expr {
if p.trace {
@@ -524,7 +494,6 @@ func (p *parser) parseTypeName() ast.Expr {
return ident
}
-
func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
if p.trace {
defer un(trace(p, "ArrayType"))
@@ -544,7 +513,6 @@ func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
return &ast.ArrayType{lbrack, len, elt}
}
-
func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
idents := make([]*ast.Ident, len(list))
for i, x := range list {
@@ -559,7 +527,6 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
return idents
}
-
func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
if p.trace {
defer un(trace(p, "FieldDecl"))
@@ -601,7 +568,6 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
return field
}
-
func (p *parser) parseStructType() *ast.StructType {
if p.trace {
defer un(trace(p, "StructType"))
@@ -623,7 +589,6 @@ func (p *parser) parseStructType() *ast.StructType {
return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
}
-
func (p *parser) parsePointerType() *ast.StarExpr {
if p.trace {
defer un(trace(p, "PointerType"))
@@ -635,7 +600,6 @@ func (p *parser) parsePointerType() *ast.StarExpr {
return &ast.StarExpr{star, base}
}
-
func (p *parser) tryVarType(isParam bool) ast.Expr {
if isParam && p.tok == token.ELLIPSIS {
pos := p.pos
@@ -653,7 +617,6 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
return p.tryIdentOrType(false)
}
-
func (p *parser) parseVarType(isParam bool) ast.Expr {
typ := p.tryVarType(isParam)
if typ == nil {
@@ -665,7 +628,6 @@ func (p *parser) parseVarType(isParam bool) ast.Expr {
return typ
}
-
func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
if p.trace {
defer un(trace(p, "VarList"))
@@ -693,7 +655,6 @@ func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
return
}
-
func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) {
if p.trace {
defer un(trace(p, "ParameterList"))
@@ -738,7 +699,6 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
return
}
-
func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldList {
if p.trace {
defer un(trace(p, "Parameters"))
@@ -754,7 +714,6 @@ func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldLi
return &ast.FieldList{lparen, params, rparen}
}
-
func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
if p.trace {
defer un(trace(p, "Result"))
@@ -774,7 +733,6 @@ func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
return nil
}
-
func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldList) {
if p.trace {
defer un(trace(p, "Signature"))
@@ -786,7 +744,6 @@ func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldLis
return
}
-
func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
if p.trace {
defer un(trace(p, "FuncType"))
@@ -799,7 +756,6 @@ func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
return &ast.FuncType{pos, params, results}, scope
}
-
func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
if p.trace {
defer un(trace(p, "MethodSpec"))
@@ -827,7 +783,6 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
return spec
}
-
func (p *parser) parseInterfaceType() *ast.InterfaceType {
if p.trace {
defer un(trace(p, "InterfaceType"))
@@ -846,7 +801,6 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
}
-
func (p *parser) parseMapType() *ast.MapType {
if p.trace {
defer un(trace(p, "MapType"))
@@ -861,7 +815,6 @@ func (p *parser) parseMapType() *ast.MapType {
return &ast.MapType{pos, key, value}
}
-
func (p *parser) parseChanType() *ast.ChanType {
if p.trace {
defer un(trace(p, "ChanType"))
@@ -885,7 +838,6 @@ func (p *parser) parseChanType() *ast.ChanType {
return &ast.ChanType{pos, dir, value}
}
-
// If the result is an identifier, it is not resolved.
func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
switch p.tok {
@@ -918,7 +870,6 @@ func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
return nil
}
-
func (p *parser) tryType() ast.Expr {
typ := p.tryIdentOrType(false)
if typ != nil {
@@ -927,7 +878,6 @@ func (p *parser) tryType() ast.Expr {
return typ
}
-
// ----------------------------------------------------------------------------
// Blocks
@@ -943,7 +893,6 @@ func (p *parser) parseStmtList() (list []ast.Stmt) {
return
}
-
func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
if p.trace {
defer un(trace(p, "Body"))
@@ -960,7 +909,6 @@ func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
return &ast.BlockStmt{lbrace, list, rbrace}
}
-
func (p *parser) parseBlockStmt() *ast.BlockStmt {
if p.trace {
defer un(trace(p, "BlockStmt"))
@@ -975,7 +923,6 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt {
return &ast.BlockStmt{lbrace, list, rbrace}
}
-
// ----------------------------------------------------------------------------
// Expressions
@@ -997,7 +944,6 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
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.
// If lhs is set and the result is an identifier, it is not resolved.
@@ -1047,7 +993,6 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
return &ast.BadExpr{pos, p.pos}
}
-
func (p *parser) parseSelector(x ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "Selector"))
@@ -1058,7 +1003,6 @@ func (p *parser) parseSelector(x ast.Expr) ast.Expr {
return &ast.SelectorExpr{x, sel}
}
-
func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "TypeAssertion"))
@@ -1077,7 +1021,6 @@ func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
return &ast.TypeAssertExpr{x, typ}
}
-
func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "IndexOrSlice"))
@@ -1106,7 +1049,6 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
return &ast.IndexExpr{x, lbrack, low, rbrack}
}
-
func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
if p.trace {
defer un(trace(p, "CallOrConversion"))
@@ -1133,7 +1075,6 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
return &ast.CallExpr{fun, lparen, list, ellipsis, rparen}
}
-
func (p *parser) parseElement(keyOk bool) ast.Expr {
if p.trace {
defer un(trace(p, "Element"))
@@ -1156,7 +1097,6 @@ func (p *parser) parseElement(keyOk bool) ast.Expr {
return x
}
-
func (p *parser) parseElementList() (list []ast.Expr) {
if p.trace {
defer un(trace(p, "ElementList"))
@@ -1173,7 +1113,6 @@ func (p *parser) parseElementList() (list []ast.Expr) {
return
}
-
func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "LiteralValue"))
@@ -1190,7 +1129,6 @@ func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
return &ast.CompositeLit{typ, lbrace, elts, rbrace}
}
-
// checkExpr checks that x is an expression (and not a type).
func (p *parser) checkExpr(x ast.Expr) ast.Expr {
switch t := unparen(x).(type) {
@@ -1227,7 +1165,6 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
return x
}
-
// isTypeName returns true iff x is a (qualified) TypeName.
func isTypeName(x ast.Expr) bool {
switch t := x.(type) {
@@ -1242,7 +1179,6 @@ func isTypeName(x ast.Expr) bool {
return true
}
-
// isLiteralType returns true iff x is a legal composite literal type.
func isLiteralType(x ast.Expr) bool {
switch t := x.(type) {
@@ -1260,7 +1196,6 @@ func isLiteralType(x ast.Expr) bool {
return true
}
-
// If x is of the form *T, deref returns T, otherwise it returns x.
func deref(x ast.Expr) ast.Expr {
if p, isPtr := x.(*ast.StarExpr); isPtr {
@@ -1269,7 +1204,6 @@ func deref(x ast.Expr) ast.Expr {
return x
}
-
// If x is of the form (T), unparen returns unparen(T), otherwise it returns x.
func unparen(x ast.Expr) ast.Expr {
if p, isParen := x.(*ast.ParenExpr); isParen {
@@ -1278,7 +1212,6 @@ func unparen(x ast.Expr) ast.Expr {
return x
}
-
// checkExprOrType checks that x is an expression or a type
// (and not a raw type such as [...]T).
//
@@ -1303,7 +1236,6 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
return x
}
-
// If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parsePrimaryExpr(lhs bool) ast.Expr {
if p.trace {
@@ -1358,7 +1290,6 @@ L:
return x
}
-
// If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
if p.trace {
@@ -1396,7 +1327,6 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
return p.parsePrimaryExpr(lhs)
}
-
// If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
if p.trace {
@@ -1420,7 +1350,6 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
return x
}
-
// If lhs is set and the result is an identifier, it is not resolved.
// TODO(gri): parseExpr may return a type or even a raw type ([..]int) -
// should reject when a type/raw type is obviously not allowed
@@ -1432,12 +1361,10 @@ func (p *parser) parseExpr(lhs bool) ast.Expr {
return p.parseBinaryExpr(lhs, token.LowestPrec+1)
}
-
func (p *parser) parseRhs() ast.Expr {
return p.parseExpr(false)
}
-
// ----------------------------------------------------------------------------
// Statements
@@ -1500,7 +1427,6 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
return &ast.ExprStmt{x[0]}
}
-
func (p *parser) parseCallExpr() *ast.CallExpr {
x := p.parseRhs()
if call, isCall := x.(*ast.CallExpr); isCall {
@@ -1510,7 +1436,6 @@ func (p *parser) parseCallExpr() *ast.CallExpr {
return nil
}
-
func (p *parser) parseGoStmt() ast.Stmt {
if p.trace {
defer un(trace(p, "GoStmt"))
@@ -1526,7 +1451,6 @@ func (p *parser) parseGoStmt() ast.Stmt {
return &ast.GoStmt{pos, call}
}
-
func (p *parser) parseDeferStmt() ast.Stmt {
if p.trace {
defer un(trace(p, "DeferStmt"))
@@ -1542,7 +1466,6 @@ func (p *parser) parseDeferStmt() ast.Stmt {
return &ast.DeferStmt{pos, call}
}
-
func (p *parser) parseReturnStmt() *ast.ReturnStmt {
if p.trace {
defer un(trace(p, "ReturnStmt"))
@@ -1559,7 +1482,6 @@ func (p *parser) parseReturnStmt() *ast.ReturnStmt {
return &ast.ReturnStmt{pos, x}
}
-
func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
if p.trace {
defer un(trace(p, "BranchStmt"))
@@ -1578,7 +1500,6 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
return &ast.BranchStmt{pos, tok, label}
}
-
func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
if s == nil {
return nil
@@ -1590,7 +1511,6 @@ func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
return &ast.BadExpr{s.Pos(), s.End()}
}
-
func (p *parser) parseIfStmt() *ast.IfStmt {
if p.trace {
defer un(trace(p, "IfStmt"))
@@ -1633,7 +1553,6 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
return &ast.IfStmt{pos, s, x, body, else_}
}
-
func (p *parser) parseTypeList() (list []ast.Expr) {
if p.trace {
defer un(trace(p, "TypeList"))
@@ -1648,7 +1567,6 @@ func (p *parser) parseTypeList() (list []ast.Expr) {
return
}
-
func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
if p.trace {
defer un(trace(p, "CaseClause"))
@@ -1675,7 +1593,6 @@ func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
return &ast.CaseClause{pos, list, colon, body}
}
-
func isExprSwitch(s ast.Stmt) bool {
if s == nil {
return true
@@ -1689,7 +1606,6 @@ func isExprSwitch(s ast.Stmt) bool {
return false
}
-
func (p *parser) parseSwitchStmt() ast.Stmt {
if p.trace {
defer un(trace(p, "SwitchStmt"))
@@ -1735,7 +1651,6 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
return &ast.TypeSwitchStmt{pos, s1, s2, body}
}
-
func (p *parser) parseCommClause() *ast.CommClause {
if p.trace {
defer un(trace(p, "CommClause"))
@@ -1801,7 +1716,6 @@ func (p *parser) parseCommClause() *ast.CommClause {
return &ast.CommClause{pos, comm, colon, body}
}
-
func (p *parser) parseSelectStmt() *ast.SelectStmt {
if p.trace {
defer un(trace(p, "SelectStmt"))
@@ -1820,7 +1734,6 @@ func (p *parser) parseSelectStmt() *ast.SelectStmt {
return &ast.SelectStmt{pos, body}
}
-
func (p *parser) parseForStmt() ast.Stmt {
if p.trace {
defer un(trace(p, "ForStmt"))
@@ -1890,7 +1803,6 @@ func (p *parser) parseForStmt() ast.Stmt {
return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}
}
-
func (p *parser) parseStmt() (s ast.Stmt) {
if p.trace {
defer un(trace(p, "Statement"))
@@ -1947,13 +1859,11 @@ func (p *parser) parseStmt() (s ast.Stmt) {
return
}
-
// ----------------------------------------------------------------------------
// Declarations
type parseSpecFunction func(p *parser, doc *ast.CommentGroup, iota int) ast.Spec
-
func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
if p.trace {
defer un(trace(p, "ImportSpec"))
@@ -1984,7 +1894,6 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
return spec
}
-
func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
if p.trace {
defer un(trace(p, "ConstSpec"))
@@ -2009,7 +1918,6 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
return spec
}
-
func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
if p.trace {
defer un(trace(p, "TypeSpec"))
@@ -2031,7 +1939,6 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
return spec
}
-
func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
if p.trace {
defer un(trace(p, "VarSpec"))
@@ -2056,7 +1963,6 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
return spec
}
-
func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
if p.trace {
defer un(trace(p, "GenDecl("+keyword.String()+")"))
@@ -2081,7 +1987,6 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
return &ast.GenDecl{doc, pos, keyword, lparen, list, rparen}
}
-
func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
if p.trace {
defer un(trace(p, "Receiver"))
@@ -2109,7 +2014,6 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
return par
}
-
func (p *parser) parseFuncDecl() *ast.FuncDecl {
if p.trace {
defer un(trace(p, "FunctionDecl"))
@@ -2150,7 +2054,6 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
return decl
}
-
func (p *parser) parseDecl() ast.Decl {
if p.trace {
defer un(trace(p, "Declaration"))
@@ -2181,7 +2084,6 @@ func (p *parser) parseDecl() ast.Decl {
return p.parseGenDecl(p.tok, f)
}
-
func (p *parser) parseDeclList() (list []ast.Decl) {
if p.trace {
defer un(trace(p, "DeclList"))
@@ -2194,7 +2096,6 @@ func (p *parser) parseDeclList() (list []ast.Decl) {
return
}
-
// ----------------------------------------------------------------------------
// Source files
diff --git a/libgo/go/go/printer/testdata/statements.golden b/libgo/go/go/printer/testdata/statements.golden
index 2900602699f..a6d85107f0b 100644
--- a/libgo/go/go/printer/testdata/statements.golden
+++ b/libgo/go/go/printer/testdata/statements.golden
@@ -30,7 +30,6 @@ func _() {
}
}
-
// Formatting of switch-statement headers.
func _() {
switch {
@@ -56,7 +55,6 @@ func _() {
}
}
-
// Formatting of switch statement bodies.
func _() {
switch {
@@ -110,6 +108,19 @@ func _() {
}
}
+// Formatting of selected select statements.
+func _() {
+ select {}
+ select { /* this comment should not be tab-aligned because the closing } is on the same line */
+ }
+ select { /* this comment should be tab-aligned */
+ }
+ select { // this comment should be tab-aligned
+ }
+ select {
+ case <-c:
+ }
+}
// Formatting of for-statement headers.
func _() {
@@ -149,7 +160,6 @@ func _() {
} // no parens printed
}
-
// Don't remove mandatory parentheses around composite literals in control clauses.
func _() {
// strip parentheses - no composite literals or composite literals don't start with a type name
@@ -243,7 +253,6 @@ func _() {
}
}
-
// Extra empty lines inside functions. Do respect source code line
// breaks between statement boundaries but print at most one empty
// line at a time.
@@ -276,19 +285,16 @@ func _() {
}
}
-
// Formatting around labels.
func _() {
L:
}
-
func _() {
// this comment should be indented
L: // no semicolon needed
}
-
func _() {
switch 0 {
case 0:
@@ -302,7 +308,6 @@ func _() {
}
}
-
func _() {
f()
L1:
@@ -312,26 +317,22 @@ L2:
L3:
}
-
func _() {
// this comment should be indented
L:
}
-
func _() {
L:
_ = 0
}
-
func _() {
// this comment should be indented
L:
_ = 0
}
-
func _() {
for {
L1:
@@ -341,7 +342,6 @@ func _() {
}
}
-
func _() {
// this comment should be indented
for {
@@ -352,7 +352,6 @@ func _() {
}
}
-
func _() {
if true {
_ = 0
@@ -370,7 +369,6 @@ L:
_ = 0
}
-
func _() {
for {
goto L
@@ -380,7 +378,6 @@ L:
MoreCode()
}
-
func _() {
for {
goto L
@@ -393,7 +390,6 @@ L: // A comment on the same line as the label, followed by a single empty line.
MoreCode()
}
-
func _() {
for {
goto L
@@ -404,7 +400,6 @@ L:
MoreCode()
}
-
func _() {
for {
goto AVeryLongLabelThatShouldNotAffectFormatting
diff --git a/libgo/go/go/printer/testdata/statements.input b/libgo/go/go/printer/testdata/statements.input
index 21e61efc4f8..86a753c5ad9 100644
--- a/libgo/go/go/printer/testdata/statements.input
+++ b/libgo/go/go/printer/testdata/statements.input
@@ -91,6 +91,19 @@ func _() {
}
+// Formatting of selected select statements.
+func _() {
+ select {
+ }
+ select { /* this comment should not be tab-aligned because the closing } is on the same line */ }
+ select { /* this comment should be tab-aligned */
+ }
+ select { // this comment should be tab-aligned
+ }
+ select { case <-c: }
+}
+
+
// Formatting of for-statement headers.
func _() {
for{}
diff --git a/libgo/go/go/scanner/errors.go b/libgo/go/go/scanner/errors.go
index 47e35a7107d..a0927e4167f 100644
--- a/libgo/go/go/scanner/errors.go
+++ b/libgo/go/go/scanner/errors.go
@@ -5,7 +5,6 @@
package scanner
import (
- "container/vector"
"fmt"
"go/token"
"io"
@@ -13,7 +12,6 @@ import (
"sort"
)
-
// An implementation of an ErrorHandler may be provided to the Scanner.
// If a syntax error is encountered and a handler was installed, Error
// is called with a position and an error message. The position points
@@ -23,7 +21,6 @@ type ErrorHandler interface {
Error(pos token.Position, msg string)
}
-
// ErrorVector implements the ErrorHandler interface. It maintains a list
// of errors which can be retrieved with GetErrorList and GetError. The
// zero value for an ErrorVector is an empty ErrorVector ready to use.
@@ -34,17 +31,14 @@ type ErrorHandler interface {
// error handling is obtained.
//
type ErrorVector struct {
- errors vector.Vector
+ errors []*Error
}
-
// Reset resets an ErrorVector to no errors.
-func (h *ErrorVector) Reset() { h.errors.Resize(0, 0) }
-
+func (h *ErrorVector) Reset() { h.errors = h.errors[:0] }
// ErrorCount returns the number of errors collected.
-func (h *ErrorVector) ErrorCount() int { return h.errors.Len() }
-
+func (h *ErrorVector) ErrorCount() int { return len(h.errors) }
// Within ErrorVector, an error is represented by an Error node. The
// position Pos, if valid, points to the beginning of the offending
@@ -55,7 +49,6 @@ type Error struct {
Msg string
}
-
func (e *Error) String() string {
if e.Pos.Filename != "" || e.Pos.IsValid() {
// don't print "<unknown position>"
@@ -65,16 +58,13 @@ func (e *Error) String() string {
return e.Msg
}
-
// An ErrorList is a (possibly sorted) list of Errors.
type ErrorList []*Error
-
// ErrorList implements the sort Interface.
func (p ErrorList) Len() int { return len(p) }
func (p ErrorList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
-
func (p ErrorList) Less(i, j int) bool {
e := &p[i].Pos
f := &p[j].Pos
@@ -95,7 +85,6 @@ func (p ErrorList) Less(i, j int) bool {
return false
}
-
func (p ErrorList) String() string {
switch len(p) {
case 0:
@@ -106,7 +95,6 @@ func (p ErrorList) String() string {
return fmt.Sprintf("%s (and %d more errors)", p[0].String(), len(p)-1)
}
-
// These constants control the construction of the ErrorList
// returned by GetErrors.
//
@@ -116,20 +104,17 @@ const (
NoMultiples // sort error list and leave only the first error per line
)
-
// GetErrorList returns the list of errors collected by an ErrorVector.
// The construction of the ErrorList returned is controlled by the mode
// parameter. If there are no errors, the result is nil.
//
func (h *ErrorVector) GetErrorList(mode int) ErrorList {
- if h.errors.Len() == 0 {
+ if len(h.errors) == 0 {
return nil
}
- list := make(ErrorList, h.errors.Len())
- for i := 0; i < h.errors.Len(); i++ {
- list[i] = h.errors.At(i).(*Error)
- }
+ list := make(ErrorList, len(h.errors))
+ copy(list, h.errors)
if mode >= Sorted {
sort.Sort(list)
@@ -151,26 +136,23 @@ func (h *ErrorVector) GetErrorList(mode int) ErrorList {
return list
}
-
// GetError is like GetErrorList, but it returns an os.Error instead
// so that a nil result can be assigned to an os.Error variable and
// remains nil.
//
func (h *ErrorVector) GetError(mode int) os.Error {
- if h.errors.Len() == 0 {
+ if len(h.errors) == 0 {
return nil
}
return h.GetErrorList(mode)
}
-
// ErrorVector implements the ErrorHandler interface.
func (h *ErrorVector) Error(pos token.Position, msg string) {
- h.errors.Push(&Error{pos, msg})
+ h.errors = append(h.errors, &Error{pos, msg})
}
-
// PrintError is a utility function that prints a list of errors to w,
// one error per line, if the err parameter is an ErrorList. Otherwise
// it prints the err string.
diff --git a/libgo/go/go/scanner/scanner.go b/libgo/go/go/scanner/scanner.go
index 07b7454c87d..7f3dd237328 100644
--- a/libgo/go/go/scanner/scanner.go
+++ b/libgo/go/go/scanner/scanner.go
@@ -22,6 +22,7 @@ package scanner
import (
"bytes"
+ "fmt"
"go/token"
"path/filepath"
"strconv"
@@ -29,7 +30,6 @@ import (
"utf8"
)
-
// A Scanner holds the scanner's internal state while processing
// a given text. It can be allocated as part of another data
// structure but must be initialized via Init before use.
@@ -53,7 +53,6 @@ type Scanner struct {
ErrorCount int // number of errors encountered
}
-
// Read the next Unicode char into S.ch.
// S.ch < 0 means end-of-file.
//
@@ -87,7 +86,6 @@ func (S *Scanner) next() {
}
}
-
// The mode parameter to the Init function is a set of flags (or 0).
// They control scanner behavior.
//
@@ -133,37 +131,6 @@ func (S *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode uint
S.next()
}
-
-func charString(ch int) string {
- var s string
- switch ch {
- case -1:
- return `EOF`
- case '\a':
- s = `\a`
- case '\b':
- s = `\b`
- case '\f':
- s = `\f`
- case '\n':
- s = `\n`
- case '\r':
- s = `\r`
- case '\t':
- s = `\t`
- case '\v':
- s = `\v`
- case '\\':
- s = `\\`
- case '\'':
- s = `\'`
- default:
- s = string(ch)
- }
- return "'" + s + "' (U+" + strconv.Itob(ch, 16) + ")"
-}
-
-
func (S *Scanner) error(offs int, msg string) {
if S.err != nil {
S.err.Error(S.file.Position(S.file.Pos(offs)), msg)
@@ -171,7 +138,6 @@ func (S *Scanner) error(offs int, msg string) {
S.ErrorCount++
}
-
var prefix = []byte("//line ")
func (S *Scanner) interpretLineComment(text []byte) {
@@ -192,7 +158,6 @@ func (S *Scanner) interpretLineComment(text []byte) {
}
}
-
func (S *Scanner) scanComment() {
// initial '/' already consumed; S.ch == '/' || S.ch == '*'
offs := S.offset - 1 // position of initial '/'
@@ -224,7 +189,6 @@ func (S *Scanner) scanComment() {
S.error(offs, "comment not terminated")
}
-
func (S *Scanner) findLineEnd() bool {
// initial '/' already consumed
@@ -269,17 +233,14 @@ func (S *Scanner) findLineEnd() bool {
return false
}
-
func isLetter(ch int) bool {
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
}
-
func isDigit(ch int) bool {
return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
}
-
func (S *Scanner) scanIdentifier() token.Token {
offs := S.offset
for isLetter(S.ch) || isDigit(S.ch) {
@@ -288,7 +249,6 @@ func (S *Scanner) scanIdentifier() token.Token {
return token.Lookup(S.src[offs:S.offset])
}
-
func digitVal(ch int) int {
switch {
case '0' <= ch && ch <= '9':
@@ -301,14 +261,12 @@ func digitVal(ch int) int {
return 16 // larger than any legal digit val
}
-
func (S *Scanner) scanMantissa(base int) {
for digitVal(S.ch) < base {
S.next()
}
}
-
func (S *Scanner) scanNumber(seenDecimalPoint bool) token.Token {
// digitVal(S.ch) < 10
tok := token.INT
@@ -327,6 +285,10 @@ func (S *Scanner) scanNumber(seenDecimalPoint bool) token.Token {
// hexadecimal int
S.next()
S.scanMantissa(16)
+ if S.offset-offs <= 2 {
+ // only scanned "0x" or "0X"
+ S.error(offs, "illegal hexadecimal number")
+ }
} else {
// octal int or float
seenDecimalDigit := false
@@ -376,7 +338,6 @@ exit:
return tok
}
-
func (S *Scanner) scanEscape(quote int) {
offs := S.offset
@@ -421,7 +382,6 @@ func (S *Scanner) scanEscape(quote int) {
}
}
-
func (S *Scanner) scanChar() {
// '\'' opening already consumed
offs := S.offset - 1
@@ -448,7 +408,6 @@ func (S *Scanner) scanChar() {
}
}
-
func (S *Scanner) scanString() {
// '"' opening already consumed
offs := S.offset - 1
@@ -468,7 +427,6 @@ func (S *Scanner) scanString() {
S.next()
}
-
func (S *Scanner) scanRawString() {
// '`' opening already consumed
offs := S.offset - 1
@@ -485,14 +443,12 @@ func (S *Scanner) scanRawString() {
S.next()
}
-
func (S *Scanner) skipWhitespace() {
for S.ch == ' ' || S.ch == '\t' || S.ch == '\n' && !S.insertSemi || S.ch == '\r' {
S.next()
}
}
-
// Helper functions for scanning multi-byte tokens such as >> += >>= .
// Different routines recognize different length tok_i based on matches
// of ch_i. If a token ends in '=', the result is tok1 or tok3
@@ -507,7 +463,6 @@ func (S *Scanner) switch2(tok0, tok1 token.Token) token.Token {
return tok0
}
-
func (S *Scanner) switch3(tok0, tok1 token.Token, ch2 int, tok2 token.Token) token.Token {
if S.ch == '=' {
S.next()
@@ -520,7 +475,6 @@ func (S *Scanner) switch3(tok0, tok1 token.Token, ch2 int, tok2 token.Token) tok
return tok0
}
-
func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Token) token.Token {
if S.ch == '=' {
S.next()
@@ -537,7 +491,6 @@ func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Toke
return tok0
}
-
// Scan scans the next token and returns the token position,
// the token, and the literal string corresponding to the
// token. The source end is indicated by token.EOF.
@@ -700,7 +653,7 @@ scanAgain:
tok = S.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR)
default:
if S.mode&AllowIllegalChars == 0 {
- S.error(offs, "illegal character "+charString(ch))
+ S.error(offs, fmt.Sprintf("illegal character %#U", ch))
}
insertSemi = S.insertSemi // preserve insertSemi info
}
diff --git a/libgo/go/go/scanner/scanner_test.go b/libgo/go/go/scanner/scanner_test.go
index 8afb00ee5bc..eb9e1cb818a 100644
--- a/libgo/go/go/scanner/scanner_test.go
+++ b/libgo/go/go/scanner/scanner_test.go
@@ -12,10 +12,8 @@ import (
"testing"
)
-
var fset = token.NewFileSet()
-
const /* class */ (
special = iota
literal
@@ -23,7 +21,6 @@ const /* class */ (
keyword
)
-
func tokenclass(tok token.Token) int {
switch {
case tok.IsLiteral():
@@ -36,14 +33,12 @@ func tokenclass(tok token.Token) int {
return special
}
-
type elt struct {
tok token.Token
lit string
class int
}
-
var tokens = [...]elt{
// Special tokens
{token.COMMENT, "/* a comment */", special},
@@ -89,7 +84,7 @@ var tokens = [...]elt{
literal,
},
- // Operators and delimitors
+ // Operators and delimiters
{token.ADD, "+", operator},
{token.SUB, "-", operator},
{token.MUL, "*", operator},
@@ -178,7 +173,6 @@ var tokens = [...]elt{
{token.VAR, "var", keyword},
}
-
const whitespace = " \t \n\n\n" // to separate tokens
type testErrorHandler struct {
@@ -189,7 +183,6 @@ func (h *testErrorHandler) Error(pos token.Position, msg string) {
h.t.Errorf("Error() called (msg = %s)", msg)
}
-
func newlineCount(s string) int {
n := 0
for i := 0; i < len(s); i++ {
@@ -200,7 +193,6 @@ func newlineCount(s string) int {
return n
}
-
func checkPos(t *testing.T, lit string, p token.Pos, expected token.Position) {
pos := fset.Position(p)
if pos.Filename != expected.Filename {
@@ -217,7 +209,6 @@ func checkPos(t *testing.T, lit string, p token.Pos, expected token.Position) {
}
}
-
// Verify that calling Scan() provides the correct results.
func TestScan(t *testing.T) {
// make source
@@ -271,7 +262,6 @@ func TestScan(t *testing.T) {
}
}
-
func checkSemi(t *testing.T, line string, mode uint) {
var S Scanner
file := fset.AddFile("TestSemis", fset.Base(), len(line))
@@ -305,7 +295,6 @@ func checkSemi(t *testing.T, line string, mode uint) {
}
}
-
var lines = []string{
// # indicates a semicolon present in the source
// $ indicates an automatically inserted semicolon
@@ -429,7 +418,6 @@ var lines = []string{
"package main$",
}
-
func TestSemis(t *testing.T) {
for _, line := range lines {
checkSemi(t, line, AllowIllegalChars|InsertSemis)
@@ -463,25 +451,31 @@ var segments = []segment{
{"\n //line foo:42\n line44", filepath.Join("dir", "foo"), 44}, // bad line comment, ignored
{"\n//line foo 42\n line46", filepath.Join("dir", "foo"), 46}, // bad line comment, ignored
{"\n//line foo:42 extra text\n line48", filepath.Join("dir", "foo"), 48}, // bad line comment, ignored
- {"\n//line /bar:42\n line42", string(filepath.Separator) + "bar", 42},
{"\n//line ./foo:42\n line42", filepath.Join("dir", "foo"), 42},
{"\n//line a/b/c/File1.go:100\n line100", filepath.Join("dir", "a", "b", "c", "File1.go"), 100},
}
+var unixsegments = []segment{
+ {"\n//line /bar:42\n line42", "/bar", 42},
+}
+
var winsegments = []segment{
+ {"\n//line c:\\bar:42\n line42", "c:\\bar", 42},
{"\n//line c:\\dir\\File1.go:100\n line100", "c:\\dir\\File1.go", 100},
}
-
// Verify that comments of the form "//line filename:line" are interpreted correctly.
func TestLineComments(t *testing.T) {
+ segs := segments
if runtime.GOOS == "windows" {
- segments = append(segments, winsegments...)
+ segs = append(segs, winsegments...)
+ } else {
+ segs = append(segs, unixsegments...)
}
// make source
var src string
- for _, e := range segments {
+ for _, e := range segs {
src += e.srcline
}
@@ -489,7 +483,7 @@ func TestLineComments(t *testing.T) {
var S Scanner
file := fset.AddFile(filepath.Join("dir", "TestLineComments"), fset.Base(), len(src))
S.Init(file, []byte(src), nil, 0)
- for _, s := range segments {
+ for _, s := range segs {
p, _, lit := S.Scan()
pos := file.Position(p)
checkPos(t, lit, p, token.Position{s.filename, pos.Offset, s.line, pos.Column})
@@ -500,7 +494,6 @@ func TestLineComments(t *testing.T) {
}
}
-
// Verify that initializing the same scanner more then once works correctly.
func TestInit(t *testing.T) {
var s Scanner
@@ -536,7 +529,6 @@ func TestInit(t *testing.T) {
}
}
-
func TestIllegalChars(t *testing.T) {
var s Scanner
@@ -558,7 +550,6 @@ func TestIllegalChars(t *testing.T) {
}
}
-
func TestStdErrorHander(t *testing.T) {
const src = "@\n" + // illegal character, cause an error
"@ @\n" + // two errors on the same line
@@ -601,21 +592,18 @@ func TestStdErrorHander(t *testing.T) {
}
}
-
type errorCollector struct {
cnt int // number of errors encountered
msg string // last error message encountered
pos token.Position // last error position encountered
}
-
func (h *errorCollector) Error(pos token.Position, msg string) {
h.cnt++
h.msg = msg
h.pos = pos
}
-
func checkError(t *testing.T, src string, tok token.Token, pos int, err string) {
var s Scanner
var h errorCollector
@@ -643,14 +631,15 @@ func checkError(t *testing.T, src string, tok token.Token, pos int, err string)
}
}
-
var errors = []struct {
src string
tok token.Token
pos int
err string
}{
- {`#`, token.ILLEGAL, 0, "illegal character '#' (U+23)"},
+ {"\a", token.ILLEGAL, 0, "illegal character U+0007"},
+ {`#`, token.ILLEGAL, 0, "illegal character U+0023 '#'"},
+ {`…`, token.ILLEGAL, 0, "illegal character U+2026 '…'"},
{`' '`, token.CHAR, 0, ""},
{`''`, token.CHAR, 0, "illegal character literal"},
{`'\8'`, token.CHAR, 2, "unknown escape sequence"},
@@ -670,11 +659,12 @@ var errors = []struct {
{"078e0", token.FLOAT, 0, ""},
{"078", token.INT, 0, "illegal octal number"},
{"07800000009", token.INT, 0, "illegal octal number"},
+ {"0x", token.INT, 0, "illegal hexadecimal number"},
+ {"0X", token.INT, 0, "illegal hexadecimal number"},
{"\"abc\x00def\"", token.STRING, 4, "illegal character NUL"},
{"\"abc\x80def\"", token.STRING, 4, "illegal UTF-8 encoding"},
}
-
func TestScanErrors(t *testing.T) {
for _, e := range errors {
checkError(t, e.src, e.tok, e.pos, e.err)
diff --git a/libgo/go/go/token/position.go b/libgo/go/go/token/position.go
index 8c35eeb52f7..c559e19f886 100644
--- a/libgo/go/go/token/position.go
+++ b/libgo/go/go/token/position.go
@@ -12,7 +12,6 @@ import (
"sync"
)
-
// Position describes an arbitrary source position
// including the file, line, and column location.
// A Position is valid if the line number is > 0.
@@ -24,11 +23,9 @@ type Position struct {
Column int // column number, starting at 1 (character count)
}
-
// IsValid returns true if the position is valid.
func (pos *Position) IsValid() bool { return pos.Line > 0 }
-
// String returns a string in one of several forms:
//
// file:line:column valid position with file name
@@ -50,7 +47,6 @@ func (pos Position) String() string {
return s
}
-
// Pos is a compact encoding of a source position within a file set.
// It can be converted into a Position for a more convenient, but much
// larger, representation.
@@ -73,7 +69,6 @@ func (pos Position) String() string {
//
type Pos int
-
// The zero value for Pos is NoPos; there is no file and line information
// associated with it, and NoPos().IsValid() is false. NoPos is always
// smaller than any other Pos value. The corresponding Position value
@@ -81,18 +76,15 @@ type Pos int
//
const NoPos Pos = 0
-
// IsValid returns true if the position is valid.
func (p Pos) IsValid() bool {
return p != NoPos
}
-
func searchFiles(a []*File, x int) int {
return sort.Search(len(a), func(i int) bool { return a[i].base > x }) - 1
}
-
func (s *FileSet) file(p Pos) *File {
if f := s.last; f != nil && f.base <= int(p) && int(p) <= f.base+f.size {
return f
@@ -108,7 +100,6 @@ func (s *FileSet) file(p Pos) *File {
return nil
}
-
// File returns the file which contains the position p.
// If no such file is found (for instance for p == NoPos),
// the result is nil.
@@ -122,7 +113,6 @@ func (s *FileSet) File(p Pos) (f *File) {
return
}
-
func (f *File) position(p Pos) (pos Position) {
offset := int(p) - f.base
pos.Offset = offset
@@ -130,12 +120,11 @@ func (f *File) position(p Pos) (pos Position) {
return
}
-
// Position converts a Pos in the fileset into a general Position.
func (s *FileSet) Position(p Pos) (pos Position) {
if p != NoPos {
// TODO(gri) consider optimizing the case where p
- // is in the last file addded, or perhaps
+ // is in the last file added, or perhaps
// looked at - will eliminate one level
// of search
s.mutex.RLock()
@@ -147,14 +136,12 @@ func (s *FileSet) Position(p Pos) (pos Position) {
return
}
-
type lineInfo struct {
offset int
filename string
line int
}
-
// AddLineInfo adds alternative file and line number information for
// a given file offset. The offset must be larger than the offset for
// the previously added alternative line info and smaller than the
@@ -171,7 +158,6 @@ func (f *File) AddLineInfo(offset int, filename string, line int) {
f.set.mutex.Unlock()
}
-
// A File is a handle for a file belonging to a FileSet.
// A File has a name, size, and line offset table.
//
@@ -186,25 +172,21 @@ type File struct {
infos []lineInfo
}
-
// Name returns the file name of file f as registered with AddFile.
func (f *File) Name() string {
return f.name
}
-
// Base returns the base offset of file f as registered with AddFile.
func (f *File) Base() int {
return f.base
}
-
// Size returns the size of file f as registered with AddFile.
func (f *File) Size() int {
return f.size
}
-
// LineCount returns the number of lines in file f.
func (f *File) LineCount() int {
f.set.mutex.RLock()
@@ -213,7 +195,6 @@ func (f *File) LineCount() int {
return n
}
-
// AddLine adds the line offset for a new line.
// The line offset must be larger than the offset for the previous line
// and smaller than the file size; otherwise the line offset is ignored.
@@ -226,7 +207,6 @@ func (f *File) AddLine(offset int) {
f.set.mutex.Unlock()
}
-
// SetLines sets the line offsets for a file and returns true if successful.
// The line offsets are the offsets of the first character of each line;
// for instance for the content "ab\nc\n" the line offsets are {0, 3}.
@@ -251,7 +231,6 @@ func (f *File) SetLines(lines []int) bool {
return true
}
-
// SetLinesForContent sets the line offsets for the given file content.
func (f *File) SetLinesForContent(content []byte) {
var lines []int
@@ -272,7 +251,6 @@ func (f *File) SetLinesForContent(content []byte) {
f.set.mutex.Unlock()
}
-
// Pos returns the Pos value for the given file offset;
// the offset must be <= f.Size().
// f.Pos(f.Offset(p)) == p.
@@ -284,7 +262,6 @@ func (f *File) Pos(offset int) Pos {
return Pos(f.base + offset)
}
-
// Offset returns the offset for the given file position p;
// p must be a valid Pos value in that file.
// f.Offset(f.Pos(offset)) == offset.
@@ -296,7 +273,6 @@ func (f *File) Offset(p Pos) int {
return int(p) - f.base
}
-
// Line returns the line number for the given file position p;
// p must be a Pos value in that file or NoPos.
//
@@ -305,7 +281,6 @@ func (f *File) Line(p Pos) int {
return f.Position(p).Line
}
-
// Position returns the Position value for the given file position p;
// p must be a Pos value in that file or NoPos.
//
@@ -319,7 +294,6 @@ func (f *File) Position(p Pos) (pos Position) {
return
}
-
func searchInts(a []int, x int) int {
// This function body is a manually inlined version of:
//
@@ -342,12 +316,10 @@ func searchInts(a []int, x int) int {
return i - 1
}
-
func searchLineInfos(a []lineInfo, x int) int {
return sort.Search(len(a), func(i int) bool { return a[i].offset > x }) - 1
}
-
// info returns the file name, line, and column number for a file offset.
func (f *File) info(offset int) (filename string, line, column int) {
filename = f.name
@@ -367,7 +339,6 @@ func (f *File) info(offset int) (filename string, line, column int) {
return
}
-
// A FileSet represents a set of source files.
// Methods of file sets are synchronized; multiple goroutines
// may invoke them concurrently.
@@ -379,7 +350,6 @@ type FileSet struct {
last *File // cache of last file looked up
}
-
// NewFileSet creates a new file set.
func NewFileSet() *FileSet {
s := new(FileSet)
@@ -387,7 +357,6 @@ func NewFileSet() *FileSet {
return s
}
-
// Base returns the minimum base offset that must be provided to
// AddFile when adding the next file.
//
@@ -399,7 +368,6 @@ func (s *FileSet) Base() int {
}
-
// AddFile adds a new file with a given filename, base offset, and file size
// to the file set s and returns the file. Multiple files may have the same
// name. The base offset must not be smaller than the FileSet's Base(), and
@@ -434,7 +402,6 @@ func (s *FileSet) AddFile(filename string, base, size int) *File {
return f
}
-
// Files returns the files added to the file set.
func (s *FileSet) Files() <-chan *File {
ch := make(chan *File)
diff --git a/libgo/go/go/token/position_test.go b/libgo/go/go/token/position_test.go
index 979c9b1e8e7..30bec59913a 100644
--- a/libgo/go/go/token/position_test.go
+++ b/libgo/go/go/token/position_test.go
@@ -9,7 +9,6 @@ import (
"testing"
)
-
func checkPos(t *testing.T, msg string, p, q Position) {
if p.Filename != q.Filename {
t.Errorf("%s: expected filename = %q; got %q", msg, q.Filename, p.Filename)
@@ -25,7 +24,6 @@ func checkPos(t *testing.T, msg string, p, q Position) {
}
}
-
func TestNoPos(t *testing.T) {
if NoPos.IsValid() {
t.Errorf("NoPos should not be valid")
@@ -36,7 +34,6 @@ func TestNoPos(t *testing.T) {
checkPos(t, "fset NoPos", fset.Position(NoPos), Position{})
}
-
var tests = []struct {
filename string
source []byte // may be nil
@@ -53,7 +50,6 @@ var tests = []struct {
{"h", []byte("package p\n\nimport \"fmt\"\n "), 25, []int{0, 10, 11, 24}},
}
-
func linecol(lines []int, offs int) (int, int) {
prevLineOffs := 0
for line, lineOffs := range lines {
@@ -65,7 +61,6 @@ func linecol(lines []int, offs int) (int, int) {
return len(lines), offs - prevLineOffs + 1
}
-
func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) {
for offs := 0; offs < f.Size(); offs++ {
p := f.Pos(offs)
@@ -80,7 +75,6 @@ func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) {
}
}
-
func makeTestSource(size int, lines []int) []byte {
src := make([]byte, size)
for _, offs := range lines {
@@ -91,7 +85,6 @@ func makeTestSource(size int, lines []int) []byte {
return src
}
-
func TestPositions(t *testing.T) {
const delta = 7 // a non-zero base offset increment
fset := NewFileSet()
@@ -150,7 +143,6 @@ func TestPositions(t *testing.T) {
}
}
-
func TestLineInfo(t *testing.T) {
fset := NewFileSet()
f := fset.AddFile("foo", fset.Base(), 500)
@@ -170,7 +162,6 @@ func TestLineInfo(t *testing.T) {
}
}
-
func TestFiles(t *testing.T) {
fset := NewFileSet()
for i, test := range tests {
diff --git a/libgo/go/go/token/token.go b/libgo/go/go/token/token.go
index c2ec80ae140..557374052c9 100644
--- a/libgo/go/go/token/token.go
+++ b/libgo/go/go/token/token.go
@@ -9,7 +9,6 @@ package token
import "strconv"
-
// Token is the set of lexical tokens of the Go programming language.
type Token int
@@ -124,7 +123,6 @@ const (
keyword_end
)
-
var tokens = [...]string{
ILLEGAL: "ILLEGAL",
@@ -225,7 +223,6 @@ var tokens = [...]string{
VAR: "var",
}
-
// String returns the string corresponding to the token tok.
// For operators, delimiters, and keywords the string is the actual
// token character sequence (e.g., for the token ADD, the string is
@@ -243,7 +240,6 @@ func (tok Token) String() string {
return s
}
-
// A set of constants for precedence-based expression parsing.
// Non-operators have lowest precedence, followed by operators
// starting with precedence 1 up to unary operators. The highest
@@ -256,7 +252,6 @@ const (
HighestPrec = 7
)
-
// Precedence returns the operator precedence of the binary
// operator op. If op is not a binary operator, the result
// is LowestPrecedence.
@@ -277,7 +272,6 @@ func (op Token) Precedence() int {
return LowestPrec
}
-
var keywords map[string]Token
func init() {
@@ -287,7 +281,6 @@ func init() {
}
}
-
// Lookup maps an identifier to its keyword token or IDENT (if not a keyword).
//
func Lookup(ident []byte) Token {
@@ -299,7 +292,6 @@ func Lookup(ident []byte) Token {
return IDENT
}
-
// Predicates
// IsLiteral returns true for tokens corresponding to identifiers
diff --git a/libgo/go/go/typechecker/scope.go b/libgo/go/go/typechecker/scope.go
index a4bee6e6962..d73d1a45048 100644
--- a/libgo/go/go/typechecker/scope.go
+++ b/libgo/go/go/typechecker/scope.go
@@ -12,18 +12,15 @@ package typechecker
import "go/ast"
-
func (tc *typechecker) openScope() *ast.Scope {
tc.topScope = ast.NewScope(tc.topScope)
return tc.topScope
}
-
func (tc *typechecker) closeScope() {
tc.topScope = tc.topScope.Outer
}
-
// declInScope declares an object of a given kind and name in scope and sets the object's Decl and N fields.
// It returns the newly allocated object. If an object with the same name already exists in scope, an error
// is reported and the object is not inserted.
@@ -40,13 +37,11 @@ func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.ObjKind, name *ast
return obj
}
-
// decl is the same as declInScope(tc.topScope, ...)
func (tc *typechecker) decl(kind ast.ObjKind, name *ast.Ident, decl interface{}, n int) *ast.Object {
return tc.declInScope(tc.topScope, kind, name, decl, n)
}
-
// find returns the object with the given name if visible in the current scope hierarchy.
// If no such object is found, an error is reported and a bad object is returned instead.
func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) {
@@ -61,7 +56,6 @@ func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) {
return
}
-
// findField returns the object with the given name if visible in the type's scope.
// If no such object is found, an error is reported and a bad object is returned instead.
func (tc *typechecker) findField(typ *Type, name *ast.Ident) (obj *ast.Object) {
diff --git a/libgo/go/go/typechecker/type.go b/libgo/go/go/typechecker/type.go
index 62b4e9d3e4a..1b88eb54b85 100644
--- a/libgo/go/go/typechecker/type.go
+++ b/libgo/go/go/typechecker/type.go
@@ -6,7 +6,6 @@ package typechecker
import "go/ast"
-
// A Type represents a Go type.
type Type struct {
Form Form
@@ -18,13 +17,11 @@ type Type struct {
Expr ast.Expr // corresponding AST expression
}
-
// NewType creates a new type of a given form.
func NewType(form Form) *Type {
return &Type{Form: form, Scope: ast.NewScope(nil)}
}
-
// Form describes the form of a type.
type Form int
@@ -45,7 +42,6 @@ const (
Tuple
)
-
var formStrings = [...]string{
BadType: "badType",
Unresolved: "unresolved",
@@ -62,10 +58,8 @@ var formStrings = [...]string{
Tuple: "tuple",
}
-
func (form Form) String() string { return formStrings[form] }
-
// The list of basic type id's.
const (
Bool = iota
@@ -96,7 +90,6 @@ const (
// TODO(gri) ideal types are missing
)
-
var BasicTypes = map[uint]string{
Bool: "bool",
Byte: "byte",
diff --git a/libgo/go/go/typechecker/typechecker.go b/libgo/go/go/typechecker/typechecker.go
index b151f5834da..24480165bde 100644
--- a/libgo/go/go/typechecker/typechecker.go
+++ b/libgo/go/go/typechecker/typechecker.go
@@ -17,19 +17,16 @@ import (
"os"
)
-
// TODO(gri) don't report errors for objects/types that are marked as bad.
const debug = true // set for debugging output
-
// An importer takes an import path and returns the data describing the
// respective package's exported interface. The data format is TBD.
//
type Importer func(path string) ([]byte, os.Error)
-
// CheckPackage typechecks a package and augments the AST by setting
// *ast.Object, *ast.Type, and *ast.Scope fields accordingly. If an
// importer is provided, it is used to handle imports, otherwise they
@@ -46,7 +43,6 @@ func CheckPackage(fset *token.FileSet, pkg *ast.Package, importer Importer) os.E
return tc.GetError(scanner.Sorted)
}
-
// CheckFile typechecks a single file, but otherwise behaves like
// CheckPackage. If the complete package consists of more than just
// one file, the file may not typecheck without errors.
@@ -57,7 +53,6 @@ func CheckFile(fset *token.FileSet, file *ast.File, importer Importer) os.Error
return CheckPackage(fset, pkg, importer)
}
-
// ----------------------------------------------------------------------------
// Typechecker state
@@ -71,19 +66,16 @@ type typechecker struct {
iota int // current value of iota
}
-
func (tc *typechecker) Errorf(pos token.Pos, format string, args ...interface{}) {
tc.Error(tc.fset.Position(pos), fmt.Sprintf(format, args...))
}
-
func assert(pred bool) {
if !pred {
panic("internal error")
}
}
-
/*
Typechecking is done in several phases:
@@ -158,7 +150,6 @@ func (tc *typechecker) checkPackage(pkg *ast.Package) {
pkg.Scope = tc.topScope
}
-
func (tc *typechecker) declGlobal(global ast.Decl) {
switch d := global.(type) {
case *ast.BadDecl:
@@ -218,7 +209,6 @@ func (tc *typechecker) declGlobal(global ast.Decl) {
}
}
-
// If x is of the form *T, deref returns T, otherwise it returns x.
func deref(x ast.Expr) ast.Expr {
if p, isPtr := x.(*ast.StarExpr); isPtr {
@@ -227,7 +217,6 @@ func deref(x ast.Expr) ast.Expr {
return x
}
-
func (tc *typechecker) bindMethod(method *ast.FuncDecl) {
// a method is declared in the receiver base type's scope
var scope *ast.Scope
@@ -259,7 +248,6 @@ func (tc *typechecker) bindMethod(method *ast.FuncDecl) {
tc.declInScope(scope, ast.Fun, method.Name, method, 0)
}
-
func (tc *typechecker) resolve(obj *ast.Object) {
// check for declaration cycles
if tc.cyclemap[obj] {
@@ -318,7 +306,6 @@ func (tc *typechecker) resolve(obj *ast.Object) {
}
}
-
func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *Type) {
tc.openScope()
defer tc.closeScope()
@@ -338,7 +325,6 @@ func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *Type) {
}
}
-
// ----------------------------------------------------------------------------
// Types
@@ -350,7 +336,6 @@ func unparen(x ast.Expr) ast.Expr {
return x
}
-
func (tc *typechecker) declFields(scope *ast.Scope, fields *ast.FieldList, ref bool) (n uint) {
if fields != nil {
for _, f := range fields.List {
@@ -365,7 +350,6 @@ func (tc *typechecker) declFields(scope *ast.Scope, fields *ast.FieldList, ref b
return n
}
-
func (tc *typechecker) declSignature(typ *Type, recv, params, results *ast.FieldList) {
assert((typ.Form == Method) == (recv != nil))
typ.Params = ast.NewScope(nil)
@@ -374,7 +358,6 @@ func (tc *typechecker) declSignature(typ *Type, recv, params, results *ast.Field
typ.N = tc.declFields(typ.Params, results, true)
}
-
func (tc *typechecker) typeFor(def *Type, x ast.Expr, ref bool) (typ *Type) {
x = unparen(x)
@@ -472,17 +455,14 @@ func (tc *typechecker) typeFor(def *Type, x ast.Expr, ref bool) (typ *Type) {
return
}
-
// ----------------------------------------------------------------------------
// TODO(gri) implement these place holders
func (tc *typechecker) declConst(*ast.Object) {
}
-
func (tc *typechecker) declVar(*ast.Object) {
}
-
func (tc *typechecker) checkStmt(ast.Stmt) {
}
diff --git a/libgo/go/go/typechecker/typechecker_test.go b/libgo/go/go/typechecker/typechecker_test.go
index d16e0692180..4bad4499a47 100644
--- a/libgo/go/go/typechecker/typechecker_test.go
+++ b/libgo/go/go/typechecker/typechecker_test.go
@@ -41,7 +41,6 @@ import (
"testing"
)
-
const testDir = "./testdata" // location of test packages
var fset = token.NewFileSet()
@@ -51,7 +50,6 @@ var (
trace = flag.Bool("trace", false, "print package names")
)
-
// ERROR comments must be of the form /* ERROR "rx" */ and rx is
// a regular expression that matches the expected error message.
var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`)
@@ -91,12 +89,10 @@ func expectedErrors(t *testing.T, pkg *ast.Package) (list scanner.ErrorList) {
return
}
-
func testFilter(f *os.FileInfo) bool {
return strings.HasSuffix(f.Name, ".src") && f.Name[0] != '.'
}
-
func checkError(t *testing.T, expected, found *scanner.Error) {
rx, err := regexp.Compile(expected.Msg)
if err != nil {
@@ -120,7 +116,6 @@ func checkError(t *testing.T, expected, found *scanner.Error) {
}
}
-
func TestTypeCheck(t *testing.T) {
flag.Parse()
pkgRx, err := regexp.Compile(*pkgPat)
diff --git a/libgo/go/go/typechecker/universe.go b/libgo/go/go/typechecker/universe.go
index abc8bbbd49c..81c14a05e57 100644
--- a/libgo/go/go/typechecker/universe.go
+++ b/libgo/go/go/typechecker/universe.go
@@ -11,7 +11,6 @@ import "go/ast"
// The Universe scope contains all predeclared identifiers.
var Universe *ast.Scope
-
func def(obj *ast.Object) {
alt := Universe.Insert(obj)
if alt != nil {
@@ -19,7 +18,6 @@ func def(obj *ast.Object) {
}
}
-
func init() {
Universe = ast.NewScope(nil)
diff --git a/libgo/go/go/types/check.go b/libgo/go/go/types/check.go
new file mode 100644
index 00000000000..87e3e93da73
--- /dev/null
+++ b/libgo/go/go/types/check.go
@@ -0,0 +1,226 @@
+// Copyright 2011 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 implements the Check function, which typechecks a package.
+
+package types
+
+import (
+ "fmt"
+ "go/ast"
+ "go/scanner"
+ "go/token"
+ "os"
+ "strconv"
+)
+
+const debug = false
+
+type checker struct {
+ fset *token.FileSet
+ scanner.ErrorVector
+ types map[ast.Expr]Type
+}
+
+func (c *checker) errorf(pos token.Pos, format string, args ...interface{}) string {
+ msg := fmt.Sprintf(format, args...)
+ c.Error(c.fset.Position(pos), msg)
+ return msg
+}
+
+// collectFields collects struct fields tok = token.STRUCT), interface methods
+// (tok = token.INTERFACE), and function arguments/results (tok = token.FUNC).
+func (c *checker) collectFields(tok token.Token, list *ast.FieldList, cycleOk bool) (fields ObjList, tags []string, isVariadic bool) {
+ if list != nil {
+ for _, field := range list.List {
+ ftype := field.Type
+ if t, ok := ftype.(*ast.Ellipsis); ok {
+ ftype = t.Elt
+ isVariadic = true
+ }
+ typ := c.makeType(ftype, cycleOk)
+ tag := ""
+ if field.Tag != nil {
+ assert(field.Tag.Kind == token.STRING)
+ tag, _ = strconv.Unquote(field.Tag.Value)
+ }
+ if len(field.Names) > 0 {
+ // named fields
+ for _, name := range field.Names {
+ obj := name.Obj
+ obj.Type = typ
+ fields = append(fields, obj)
+ if tok == token.STRUCT {
+ tags = append(tags, tag)
+ }
+ }
+ } else {
+ // anonymous field
+ switch tok {
+ case token.STRUCT:
+ tags = append(tags, tag)
+ fallthrough
+ case token.FUNC:
+ obj := ast.NewObj(ast.Var, "")
+ obj.Type = typ
+ fields = append(fields, obj)
+ case token.INTERFACE:
+ utyp := Underlying(typ)
+ if typ, ok := utyp.(*Interface); ok {
+ // TODO(gri) This is not good enough. Check for double declarations!
+ fields = append(fields, typ.Methods...)
+ } else if _, ok := utyp.(*Bad); !ok {
+ // if utyp is Bad, don't complain (the root cause was reported before)
+ c.errorf(ftype.Pos(), "interface contains embedded non-interface type")
+ }
+ default:
+ panic("unreachable")
+ }
+ }
+ }
+ }
+ return
+}
+
+// makeType makes a new type for an AST type specification x or returns
+// the type referred to by a type name x. If cycleOk is set, a type may
+// refer to itself directly or indirectly; otherwise cycles are errors.
+//
+func (c *checker) makeType(x ast.Expr, cycleOk bool) (typ Type) {
+ if debug {
+ fmt.Printf("makeType (cycleOk = %v)\n", cycleOk)
+ ast.Print(c.fset, x)
+ defer func() {
+ fmt.Printf("-> %T %v\n\n", typ, typ)
+ }()
+ }
+
+ switch t := x.(type) {
+ case *ast.BadExpr:
+ return &Bad{}
+
+ case *ast.Ident:
+ // type name
+ obj := t.Obj
+ if obj == nil {
+ // unresolved identifier (error has been reported before)
+ return &Bad{Msg: "unresolved identifier"}
+ }
+ if obj.Kind != ast.Typ {
+ msg := c.errorf(t.Pos(), "%s is not a type", t.Name)
+ return &Bad{Msg: msg}
+ }
+ c.checkObj(obj, cycleOk)
+ if !cycleOk && obj.Type.(*Name).Underlying == nil {
+ // TODO(gri) Enable this message again once its position
+ // is independent of the underlying map implementation.
+ // msg := c.errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name)
+ msg := "illegal cycle"
+ return &Bad{Msg: msg}
+ }
+ return obj.Type.(Type)
+
+ case *ast.ParenExpr:
+ return c.makeType(t.X, cycleOk)
+
+ case *ast.SelectorExpr:
+ // qualified identifier
+ // TODO (gri) eventually, this code belongs to expression
+ // type checking - here for the time being
+ if ident, ok := t.X.(*ast.Ident); ok {
+ if obj := ident.Obj; obj != nil {
+ if obj.Kind != ast.Pkg {
+ msg := c.errorf(ident.Pos(), "%s is not a package", obj.Name)
+ return &Bad{Msg: msg}
+ }
+ // TODO(gri) we have a package name but don't
+ // have the mapping from package name to package
+ // scope anymore (created in ast.NewPackage).
+ return &Bad{} // for now
+ }
+ }
+ // TODO(gri) can this really happen (the parser should have excluded this)?
+ msg := c.errorf(t.Pos(), "expected qualified identifier")
+ return &Bad{Msg: msg}
+
+ case *ast.StarExpr:
+ return &Pointer{Base: c.makeType(t.X, true)}
+
+ case *ast.ArrayType:
+ if t.Len != nil {
+ // TODO(gri) compute length
+ return &Array{Elt: c.makeType(t.Elt, cycleOk)}
+ }
+ return &Slice{Elt: c.makeType(t.Elt, true)}
+
+ case *ast.StructType:
+ fields, tags, _ := c.collectFields(token.STRUCT, t.Fields, cycleOk)
+ return &Struct{Fields: fields, Tags: tags}
+
+ case *ast.FuncType:
+ params, _, _ := c.collectFields(token.FUNC, t.Params, true)
+ results, _, isVariadic := c.collectFields(token.FUNC, t.Results, true)
+ return &Func{Recv: nil, Params: params, Results: results, IsVariadic: isVariadic}
+
+ case *ast.InterfaceType:
+ methods, _, _ := c.collectFields(token.INTERFACE, t.Methods, cycleOk)
+ methods.Sort()
+ return &Interface{Methods: methods}
+
+ case *ast.MapType:
+ return &Map{Key: c.makeType(t.Key, true), Elt: c.makeType(t.Key, true)}
+
+ case *ast.ChanType:
+ return &Chan{Dir: t.Dir, Elt: c.makeType(t.Value, true)}
+ }
+
+ panic(fmt.Sprintf("unreachable (%T)", x))
+}
+
+// checkObj type checks an object.
+func (c *checker) checkObj(obj *ast.Object, ref bool) {
+ if obj.Type != nil {
+ // object has already been type checked
+ return
+ }
+
+ switch obj.Kind {
+ case ast.Bad:
+ // ignore
+
+ case ast.Con:
+ // TODO(gri) complete this
+
+ case ast.Typ:
+ typ := &Name{Obj: obj}
+ obj.Type = typ // "mark" object so recursion terminates
+ typ.Underlying = Underlying(c.makeType(obj.Decl.(*ast.TypeSpec).Type, ref))
+
+ case ast.Var:
+ // TODO(gri) complete this
+
+ case ast.Fun:
+ // TODO(gri) complete this
+
+ default:
+ panic("unreachable")
+ }
+}
+
+// Check typechecks a package.
+// It augments the AST by assigning types to all ast.Objects and returns a map
+// of types for all expression nodes in statements, and a scanner.ErrorList if
+// there are errors.
+//
+func Check(fset *token.FileSet, pkg *ast.Package) (types map[ast.Expr]Type, err os.Error) {
+ var c checker
+ c.fset = fset
+ c.types = make(map[ast.Expr]Type)
+
+ for _, obj := range pkg.Scope.Objects {
+ c.checkObj(obj, false)
+ }
+
+ return c.types, c.GetError(scanner.NoMultiples)
+}
diff --git a/libgo/go/go/types/check_test.go b/libgo/go/go/types/check_test.go
new file mode 100644
index 00000000000..8be653fcb66
--- /dev/null
+++ b/libgo/go/go/types/check_test.go
@@ -0,0 +1,215 @@
+// Copyright 2011 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 implements a typechecker test harness. The packages specified
+// in tests are typechecked. Error messages reported by the typechecker are
+// compared against the error messages expected in the test files.
+//
+// Expected errors are indicated in the test files by putting a comment
+// of the form /* ERROR "rx" */ immediately following an offending token.
+// The harness will verify that an error matching the regular expression
+// rx is reported at that source position. Consecutive comments may be
+// used to indicate multiple errors for the same token position.
+//
+// For instance, the following test file indicates that a "not declared"
+// error should be reported for the undeclared variable x:
+//
+// package p
+// func f() {
+// _ = x /* ERROR "not declared" */ + 1
+// }
+
+package types
+
+import (
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/scanner"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "regexp"
+ "testing"
+)
+
+// The test filenames do not end in .go so that they are invisible
+// to gofmt since they contain comments that must not change their
+// positions relative to surrounding tokens.
+
+var tests = []struct {
+ name string
+ files []string
+}{
+ {"test0", []string{"testdata/test0.src"}},
+}
+
+var fset = token.NewFileSet()
+
+// TODO(gri) This functionality should be in token.Fileset.
+func getFile(filename string) *token.File {
+ for f := range fset.Files() {
+ if f.Name() == filename {
+ return f
+ }
+ }
+ return nil
+}
+
+// TODO(gri) This functionality should be in token.Fileset.
+func getPos(filename string, offset int) token.Pos {
+ if f := getFile(filename); f != nil {
+ return f.Pos(offset)
+ }
+ return token.NoPos
+}
+
+// TODO(gri) Need to revisit parser interface. We should be able to use parser.ParseFiles
+// or a similar function instead.
+func parseFiles(t *testing.T, testname string, filenames []string) (map[string]*ast.File, os.Error) {
+ files := make(map[string]*ast.File)
+ var errors scanner.ErrorList
+ for _, filename := range filenames {
+ if _, exists := files[filename]; exists {
+ t.Fatalf("%s: duplicate file %s", testname, filename)
+ }
+ file, err := parser.ParseFile(fset, filename, nil, parser.DeclarationErrors)
+ if file == nil {
+ t.Fatalf("%s: could not parse file %s", testname, filename)
+ }
+ files[filename] = file
+ if err != nil {
+ // if the parser returns a non-scanner.ErrorList error
+ // the file couldn't be read in the first place and
+ // file == nil; in that case we shouldn't reach here
+ errors = append(errors, err.(scanner.ErrorList)...)
+ }
+
+ }
+ return files, errors
+}
+
+// ERROR comments must be of the form /* ERROR "rx" */ and rx is
+// a regular expression that matches the expected error message.
+//
+var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`)
+
+// expectedErrors collects the regular expressions of ERROR comments found
+// in files and returns them as a map of error positions to error messages.
+//
+func expectedErrors(t *testing.T, testname string, files map[string]*ast.File) map[token.Pos]string {
+ errors := make(map[token.Pos]string)
+ for filename := range files {
+ src, err := ioutil.ReadFile(filename)
+ if err != nil {
+ t.Fatalf("%s: could not read %s", testname, filename)
+ }
+
+ var s scanner.Scanner
+ // file was parsed already - do not add it again to the file
+ // set otherwise the position information returned here will
+ // not match the position information collected by the parser
+ s.Init(getFile(filename), src, nil, scanner.ScanComments)
+ var prev token.Pos // position of last non-comment token
+
+ scanFile:
+ for {
+ pos, tok, lit := s.Scan()
+ switch tok {
+ case token.EOF:
+ break scanFile
+ case token.COMMENT:
+ s := errRx.FindStringSubmatch(lit)
+ if len(s) == 2 {
+ errors[prev] = string(s[1])
+ }
+ default:
+ prev = pos
+ }
+ }
+ }
+ return errors
+}
+
+func eliminate(t *testing.T, expected map[token.Pos]string, errors os.Error) {
+ if errors == nil {
+ return
+ }
+ for _, error := range errors.(scanner.ErrorList) {
+ // error.Pos is a token.Position, but we want
+ // a token.Pos so we can do a map lookup
+ // TODO(gri) Need to move scanner.Errors over
+ // to use token.Pos and file set info.
+ pos := getPos(error.Pos.Filename, error.Pos.Offset)
+ if msg, found := expected[pos]; found {
+ // we expect a message at pos; check if it matches
+ rx, err := regexp.Compile(msg)
+ if err != nil {
+ t.Errorf("%s: %v", error.Pos, err)
+ continue
+ }
+ if match := rx.MatchString(error.Msg); !match {
+ t.Errorf("%s: %q does not match %q", error.Pos, error.Msg, msg)
+ continue
+ }
+ // we have a match - eliminate this error
+ expected[pos] = "", false
+ } else {
+ // To keep in mind when analyzing failed test output:
+ // If the same error position occurs multiple times in errors,
+ // this message will be triggered (because the first error at
+ // the position removes this position from the expected errors).
+ t.Errorf("%s: no (multiple?) error expected, but found: %s", error.Pos, error.Msg)
+ }
+ }
+}
+
+func check(t *testing.T, testname string, testfiles []string) {
+ // TODO(gri) Eventually all these different phases should be
+ // subsumed into a single function call that takes
+ // a set of files and creates a fully resolved and
+ // type-checked AST.
+
+ files, err := parseFiles(t, testname, testfiles)
+
+ // we are expecting the following errors
+ // (collect these after parsing the files so that
+ // they are found in the file set)
+ errors := expectedErrors(t, testname, files)
+
+ // verify errors returned by the parser
+ eliminate(t, errors, err)
+
+ // verify errors returned after resolving identifiers
+ pkg, err := ast.NewPackage(fset, files, GcImporter, Universe)
+ eliminate(t, errors, err)
+
+ // verify errors returned by the typechecker
+ _, err = Check(fset, pkg)
+ eliminate(t, errors, err)
+
+ // there should be no expected errors left
+ if len(errors) > 0 {
+ t.Errorf("%s: %d errors not reported:", testname, len(errors))
+ for pos, msg := range errors {
+ t.Errorf("%s: %s\n", fset.Position(pos), msg)
+ }
+ }
+}
+
+func TestCheck(t *testing.T) {
+ // For easy debugging w/o changing the testing code,
+ // if there is a local test file, only test that file.
+ const testfile = "test.go"
+ if fi, err := os.Stat(testfile); err == nil && fi.IsRegular() {
+ fmt.Printf("WARNING: Testing only %s (remove it to run all tests)\n", testfile)
+ check(t, testfile, []string{testfile})
+ return
+ }
+
+ // Otherwise, run all the tests.
+ for _, test := range tests {
+ check(t, test.name, test.files)
+ }
+}
diff --git a/libgo/go/go/types/const.go b/libgo/go/go/types/const.go
index 6fdc22f6b34..1ef95d9f952 100644
--- a/libgo/go/go/types/const.go
+++ b/libgo/go/go/types/const.go
@@ -12,7 +12,6 @@ import (
"strconv"
)
-
// TODO(gri) Consider changing the API so Const is an interface
// and operations on consts don't have to type switch.
@@ -28,20 +27,17 @@ type Const struct {
val interface{}
}
-
// Representation of complex values.
type cmplx struct {
re, im *big.Rat
}
-
func assert(cond bool) {
if !cond {
panic("go/types internal error: assertion failed")
}
}
-
// MakeConst makes an ideal constant from a literal
// token and the corresponding literal string.
func MakeConst(tok token.Token, lit string) Const {
@@ -75,14 +71,12 @@ func MakeConst(tok token.Token, lit string) Const {
panic("unreachable")
}
-
// MakeZero returns the zero constant for the given type.
func MakeZero(typ *Type) Const {
// TODO(gri) fix this
return Const{0}
}
-
// Match attempts to match the internal constant representations of x and y.
// If the attempt is successful, the result is the values of x and y,
// if necessary converted to have the same internal representation; otherwise
@@ -132,7 +126,6 @@ func (x Const) Match(y Const) (u, v Const) {
return
}
-
// Convert attempts to convert the constant x to a given type.
// If the attempt is successful, the result is the new constant;
// otherwise the result is invalid.
@@ -148,7 +141,6 @@ func (x Const) Convert(typ *Type) Const {
return x
}
-
func (x Const) String() string {
switch x := x.val.(type) {
case bool:
@@ -169,12 +161,10 @@ func (x Const) String() string {
panic("unreachable")
}
-
func (x Const) UnaryOp(op token.Token) Const {
panic("unimplemented")
}
-
func (x Const) BinaryOp(op token.Token, y Const) Const {
var z interface{}
switch x := x.val.(type) {
@@ -194,7 +184,6 @@ func (x Const) BinaryOp(op token.Token, y Const) Const {
return Const{z}
}
-
func binaryBoolOp(x bool, op token.Token, y bool) interface{} {
switch op {
case token.EQL:
@@ -205,7 +194,6 @@ func binaryBoolOp(x bool, op token.Token, y bool) interface{} {
panic("unreachable")
}
-
func binaryIntOp(x *big.Int, op token.Token, y *big.Int) interface{} {
var z big.Int
switch op {
@@ -247,7 +235,6 @@ func binaryIntOp(x *big.Int, op token.Token, y *big.Int) interface{} {
panic("unreachable")
}
-
func binaryFloatOp(x *big.Rat, op token.Token, y *big.Rat) interface{} {
var z big.Rat
switch op {
@@ -275,7 +262,6 @@ func binaryFloatOp(x *big.Rat, op token.Token, y *big.Rat) interface{} {
panic("unreachable")
}
-
func binaryCmplxOp(x cmplx, op token.Token, y cmplx) interface{} {
a, b := x.re, x.im
c, d := y.re, y.im
@@ -325,7 +311,6 @@ func binaryCmplxOp(x cmplx, op token.Token, y cmplx) interface{} {
panic("unreachable")
}
-
func binaryStringOp(x string, op token.Token, y string) interface{} {
switch op {
case token.ADD:
diff --git a/libgo/go/go/types/exportdata.go b/libgo/go/go/types/exportdata.go
index cb08ffe18a2..383520320f4 100644
--- a/libgo/go/go/types/exportdata.go
+++ b/libgo/go/go/types/exportdata.go
@@ -15,7 +15,6 @@ import (
"strings"
)
-
func readGopackHeader(buf *bufio.Reader) (name string, size int, err os.Error) {
// See $GOROOT/include/ar.h.
hdr := make([]byte, 64+12+6+6+8+10+2)
@@ -29,20 +28,18 @@ func readGopackHeader(buf *bufio.Reader) (name string, size int, err os.Error) {
s := strings.TrimSpace(string(hdr[64+12+6+6+8:][:10]))
size, err = strconv.Atoi(s)
if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
- err = os.ErrorString("invalid archive header")
+ err = os.NewError("invalid archive header")
return
}
name = strings.TrimSpace(string(hdr[:64]))
return
}
-
type dataReader struct {
*bufio.Reader
io.Closer
}
-
// ExportData returns a readCloser positioned at the beginning of the
// export data section of the given object/archive file, or an error.
// It is the caller's responsibility to close the readCloser.
@@ -80,7 +77,7 @@ func ExportData(filename string) (rc io.ReadCloser, err os.Error) {
return
}
if name != "__.SYMDEF" {
- err = os.ErrorString("go archive does not begin with __.SYMDEF")
+ err = os.NewError("go archive does not begin with __.SYMDEF")
return
}
const block = 4096
@@ -102,7 +99,7 @@ func ExportData(filename string) (rc io.ReadCloser, err os.Error) {
return
}
if name != "__.PKGDEF" {
- err = os.ErrorString("go archive is missing __.PKGDEF")
+ err = os.NewError("go archive is missing __.PKGDEF")
return
}
@@ -117,7 +114,7 @@ func ExportData(filename string) (rc io.ReadCloser, err os.Error) {
// Now at __.PKGDEF in archive or still at beginning of file.
// Either way, line should begin with "go object ".
if !strings.HasPrefix(string(line), "go object ") {
- err = os.ErrorString("not a go object file")
+ err = os.NewError("not a go object file")
return
}
diff --git a/libgo/go/go/types/gcimporter.go b/libgo/go/go/types/gcimporter.go
index 30adc04e729..6ab1806b643 100644
--- a/libgo/go/go/types/gcimporter.go
+++ b/libgo/go/go/types/gcimporter.go
@@ -20,7 +20,6 @@ import (
"strconv"
)
-
const trace = false // set to true for debugging
var (
@@ -28,7 +27,6 @@ var (
pkgExts = [...]string{".a", ".5", ".6", ".8"}
)
-
// findPkg returns the filename and package id for an import path.
// If no file was found, an empty filename is returned.
func findPkg(path string) (filename, id string) {
@@ -69,20 +67,17 @@ func findPkg(path string) (filename, id string) {
return
}
-
// gcParser parses the exports inside a gc compiler-produced
// object/archive file and populates its scope with the results.
type gcParser struct {
scanner scanner.Scanner
- tok int // current token
- lit string // literal string; only valid for Ident, Int, String tokens
- id string // package id of imported package
- scope *ast.Scope // scope of imported package; alias for deps[id]
- deps map[string]*ast.Scope // package id -> package scope
+ tok int // current token
+ lit string // literal string; only valid for Ident, Int, String tokens
+ id string // package id of imported package
+ imports map[string]*ast.Object // package id -> package object
}
-
-func (p *gcParser) init(filename, id string, src io.Reader) {
+func (p *gcParser) init(filename, id string, src io.Reader, imports map[string]*ast.Object) {
p.scanner.Init(src)
p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
@@ -90,11 +85,9 @@ func (p *gcParser) init(filename, id string, src io.Reader) {
p.scanner.Filename = filename // for good error messages
p.next()
p.id = id
- p.scope = ast.NewScope(nil)
- p.deps = map[string]*ast.Scope{"unsafe": Unsafe, id: p.scope}
+ p.imports = imports
}
-
func (p *gcParser) next() {
p.tok = p.scanner.Scan()
switch p.tok {
@@ -108,11 +101,10 @@ func (p *gcParser) next() {
}
}
-
// GcImporter implements the ast.Importer signature.
-func GcImporter(path string) (name string, scope *ast.Scope, err os.Error) {
+func GcImporter(imports map[string]*ast.Object, path string) (pkg *ast.Object, err os.Error) {
if path == "unsafe" {
- return path, Unsafe, nil
+ return Unsafe, nil
}
defer func() {
@@ -126,10 +118,14 @@ func GcImporter(path string) (name string, scope *ast.Scope, err os.Error) {
filename, id := findPkg(path)
if filename == "" {
- err = os.ErrorString("can't find import: " + id)
+ err = os.NewError("can't find import: " + id)
return
}
+ if pkg = imports[id]; pkg != nil {
+ return // package was imported before
+ }
+
buf, err := ExportData(filename)
if err != nil {
return
@@ -137,17 +133,15 @@ func GcImporter(path string) (name string, scope *ast.Scope, err os.Error) {
defer buf.Close()
if trace {
- fmt.Printf("importing %s\n", filename)
+ fmt.Printf("importing %s (%s)\n", id, filename)
}
var p gcParser
- p.init(filename, id, buf)
- name, scope = p.parseExport()
-
+ p.init(filename, id, buf, imports)
+ pkg = p.parseExport()
return
}
-
// ----------------------------------------------------------------------------
// Error handling
@@ -157,26 +151,22 @@ type importError struct {
err os.Error
}
-
func (e importError) String() string {
return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err)
}
-
func (p *gcParser) error(err interface{}) {
if s, ok := err.(string); ok {
- err = os.ErrorString(s)
+ err = os.NewError(s)
}
// panic with a runtime.Error if err is not an os.Error
panic(importError{p.scanner.Pos(), err.(os.Error)})
}
-
func (p *gcParser) errorf(format string, args ...interface{}) {
p.error(fmt.Sprintf(format, args...))
}
-
func (p *gcParser) expect(tok int) string {
lit := p.lit
if p.tok != tok {
@@ -186,7 +176,6 @@ func (p *gcParser) expect(tok int) string {
return lit
}
-
func (p *gcParser) expectSpecial(tok string) {
sep := 'x' // not white space
i := 0
@@ -200,7 +189,6 @@ func (p *gcParser) expectSpecial(tok string) {
}
}
-
func (p *gcParser) expectKeyword(keyword string) {
lit := p.expect(scanner.Ident)
if lit != keyword {
@@ -208,29 +196,37 @@ func (p *gcParser) expectKeyword(keyword string) {
}
}
-
// ----------------------------------------------------------------------------
// Import declarations
// ImportPath = string_lit .
//
-func (p *gcParser) parsePkgId() *ast.Scope {
+func (p *gcParser) parsePkgId() *ast.Object {
id, err := strconv.Unquote(p.expect(scanner.String))
if err != nil {
p.error(err)
}
- scope := p.scope // id == "" stands for the imported package id
- if id != "" {
- if scope = p.deps[id]; scope == nil {
- scope = ast.NewScope(nil)
- p.deps[id] = scope
- }
+ switch id {
+ case "":
+ // id == "" stands for the imported package id
+ // (only known at time of package installation)
+ id = p.id
+ case "unsafe":
+ // package unsafe is not in the imports map - handle explicitly
+ return Unsafe
}
- return scope
-}
+ pkg := p.imports[id]
+ if pkg == nil {
+ scope = ast.NewScope(nil)
+ pkg = ast.NewObj(ast.Pkg, "")
+ pkg.Data = scope
+ p.imports[id] = pkg
+ }
+ return pkg
+}
// dotIdentifier = ( ident | '·' ) { ident | int | '·' } .
func (p *gcParser) parseDotIdent() string {
@@ -249,17 +245,17 @@ func (p *gcParser) parseDotIdent() string {
return ident
}
-
// ExportedName = ImportPath "." dotIdentifier .
//
func (p *gcParser) parseExportedName(kind ast.ObjKind) *ast.Object {
- scope := p.parsePkgId()
+ pkg := p.parsePkgId()
p.expect('.')
name := p.parseDotIdent()
// a type may have been declared before - if it exists
// already in the respective package scope, return that
// type
+ scope := pkg.Data.(*ast.Scope)
if kind == ast.Typ {
if obj := scope.Lookup(name); obj != nil {
assert(obj.Kind == ast.Typ)
@@ -283,7 +279,6 @@ func (p *gcParser) parseExportedName(kind ast.ObjKind) *ast.Object {
return obj
}
-
// ----------------------------------------------------------------------------
// Types
@@ -297,7 +292,6 @@ func (p *gcParser) parseBasicType() Type {
return obj.Type.(Type)
}
-
// ArrayType = "[" int_lit "]" Type .
//
func (p *gcParser) parseArrayType() Type {
@@ -312,7 +306,6 @@ func (p *gcParser) parseArrayType() Type {
return &Array{Len: n, Elt: elt}
}
-
// MapType = "map" "[" Type "]" Type .
//
func (p *gcParser) parseMapType() Type {
@@ -324,7 +317,6 @@ func (p *gcParser) parseMapType() Type {
return &Map{Key: key, Elt: elt}
}
-
// Name = identifier | "?" .
//
func (p *gcParser) parseName() (name string) {
@@ -341,156 +333,171 @@ func (p *gcParser) parseName() (name string) {
return
}
-
// Field = Name Type [ ":" string_lit ] .
//
-func (p *gcParser) parseField(scope *ast.Scope) {
- // TODO(gri) The code below is not correct for anonymous fields:
- // The name is the type name; it should not be empty.
+func (p *gcParser) parseField() (fld *ast.Object, tag string) {
name := p.parseName()
ftyp := p.parseType()
if name == "" {
// anonymous field - ftyp must be T or *T and T must be a type name
- ftyp = Deref(ftyp)
- if ftyp, ok := ftyp.(*Name); ok {
- name = ftyp.Obj.Name
- } else {
+ if _, ok := Deref(ftyp).(*Name); !ok {
p.errorf("anonymous field expected")
}
}
if p.tok == ':' {
p.next()
- tag := p.expect(scanner.String)
- _ = tag // TODO(gri) store tag somewhere
+ tag = p.expect(scanner.String)
}
- fld := ast.NewObj(ast.Var, name)
+ fld = ast.NewObj(ast.Var, name)
fld.Type = ftyp
- scope.Insert(fld)
+ return
}
-
// StructType = "struct" "{" [ FieldList ] "}" .
// FieldList = Field { ";" Field } .
//
func (p *gcParser) parseStructType() Type {
+ var fields []*ast.Object
+ var tags []string
+
+ parseField := func() {
+ fld, tag := p.parseField()
+ fields = append(fields, fld)
+ tags = append(tags, tag)
+ }
+
p.expectKeyword("struct")
p.expect('{')
- scope := ast.NewScope(nil)
if p.tok != '}' {
- p.parseField(scope)
+ parseField()
for p.tok == ';' {
p.next()
- p.parseField(scope)
+ parseField()
}
}
p.expect('}')
- return &Struct{}
-}
+ return &Struct{Fields: fields, Tags: tags}
+}
-// Parameter = ( identifier | "?" ) [ "..." ] Type .
+// Parameter = ( identifier | "?" ) [ "..." ] Type [ ":" string_lit ] .
//
-func (p *gcParser) parseParameter(scope *ast.Scope, isVariadic *bool) {
+func (p *gcParser) parseParameter() (par *ast.Object, isVariadic bool) {
name := p.parseName()
if name == "" {
name = "_" // cannot access unnamed identifiers
}
- if isVariadic != nil {
- if *isVariadic {
- p.error("... not on final argument")
- }
- if p.tok == '.' {
- p.expectSpecial("...")
- *isVariadic = true
- }
+ if p.tok == '.' {
+ p.expectSpecial("...")
+ isVariadic = true
}
ptyp := p.parseType()
- par := ast.NewObj(ast.Var, name)
+ // ignore argument tag
+ if p.tok == ':' {
+ p.next()
+ p.expect(scanner.String)
+ }
+ par = ast.NewObj(ast.Var, name)
par.Type = ptyp
- scope.Insert(par)
+ return
}
-
// Parameters = "(" [ ParameterList ] ")" .
// ParameterList = { Parameter "," } Parameter .
//
-func (p *gcParser) parseParameters(scope *ast.Scope, isVariadic *bool) {
+func (p *gcParser) parseParameters() (list []*ast.Object, isVariadic bool) {
+ parseParameter := func() {
+ par, variadic := p.parseParameter()
+ list = append(list, par)
+ if variadic {
+ if isVariadic {
+ p.error("... not on final argument")
+ }
+ isVariadic = true
+ }
+ }
+
p.expect('(')
if p.tok != ')' {
- p.parseParameter(scope, isVariadic)
+ parseParameter()
for p.tok == ',' {
p.next()
- p.parseParameter(scope, isVariadic)
+ parseParameter()
}
}
p.expect(')')
-}
+ return
+}
// Signature = Parameters [ Result ] .
// Result = Type | Parameters .
//
-func (p *gcParser) parseSignature(scope *ast.Scope, isVariadic *bool) {
- p.parseParameters(scope, isVariadic)
+func (p *gcParser) parseSignature() *Func {
+ params, isVariadic := p.parseParameters()
// optional result type
+ var results []*ast.Object
switch p.tok {
case scanner.Ident, scanner.String, '[', '*', '<':
// single, unnamed result
result := ast.NewObj(ast.Var, "_")
result.Type = p.parseType()
- scope.Insert(result)
+ results = []*ast.Object{result}
case '(':
// named or multiple result(s)
- p.parseParameters(scope, nil)
+ var variadic bool
+ results, variadic = p.parseParameters()
+ if variadic {
+ p.error("... not permitted on result type")
+ }
}
-}
-
-// FuncType = "func" Signature .
-//
-func (p *gcParser) parseFuncType() Type {
- // "func" already consumed
- scope := ast.NewScope(nil)
- isVariadic := false
- p.parseSignature(scope, &isVariadic)
- return &Func{IsVariadic: isVariadic}
+ return &Func{Params: params, Results: results, IsVariadic: isVariadic}
}
-
// MethodSpec = identifier Signature .
//
-func (p *gcParser) parseMethodSpec(scope *ast.Scope) {
+func (p *gcParser) parseMethodSpec() *ast.Object {
if p.tok == scanner.Ident {
p.expect(scanner.Ident)
} else {
+ // TODO(gri) should this be parseExportedName here?
p.parsePkgId()
p.expect('.')
p.parseDotIdent()
}
- isVariadic := false
- p.parseSignature(scope, &isVariadic)
-}
+ p.parseSignature()
+ // TODO(gri) compute method object
+ return ast.NewObj(ast.Fun, "_")
+}
// InterfaceType = "interface" "{" [ MethodList ] "}" .
// MethodList = MethodSpec { ";" MethodSpec } .
//
func (p *gcParser) parseInterfaceType() Type {
+ var methods ObjList
+
+ parseMethod := func() {
+ meth := p.parseMethodSpec()
+ methods = append(methods, meth)
+ }
+
p.expectKeyword("interface")
p.expect('{')
- scope := ast.NewScope(nil)
if p.tok != '}' {
- p.parseMethodSpec(scope)
+ parseMethod()
for p.tok == ';' {
p.next()
- p.parseMethodSpec(scope)
+ parseMethod()
}
}
p.expect('}')
- return &Interface{}
-}
+ methods.Sort()
+ return &Interface{Methods: methods}
+}
// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
//
@@ -511,7 +518,6 @@ func (p *gcParser) parseChanType() Type {
return &Chan{Dir: dir, Elt: elt}
}
-
// Type =
// BasicType | TypeName | ArrayType | SliceType | StructType |
// PointerType | FuncType | InterfaceType | MapType | ChanType |
@@ -520,6 +526,7 @@ func (p *gcParser) parseChanType() Type {
// TypeName = ExportedName .
// SliceType = "[" "]" Type .
// PointerType = "*" Type .
+// FuncType = "func" Signature .
//
func (p *gcParser) parseType() Type {
switch p.tok {
@@ -530,8 +537,9 @@ func (p *gcParser) parseType() Type {
case "struct":
return p.parseStructType()
case "func":
- p.next() // parseFuncType assumes "func" is already consumed
- return p.parseFuncType()
+ // FuncType
+ p.next()
+ return p.parseSignature()
case "interface":
return p.parseInterfaceType()
case "map":
@@ -567,7 +575,6 @@ func (p *gcParser) parseType() Type {
return nil
}
-
// ----------------------------------------------------------------------------
// Declarations
@@ -578,12 +585,12 @@ func (p *gcParser) parseImportDecl() {
// The identifier has no semantic meaning in the import data.
// It exists so that error messages can print the real package
// name: binary.ByteOrder instead of "encoding/binary".ByteOrder.
- // TODO(gri): Save package id -> package name mapping.
- p.expect(scanner.Ident)
- p.parsePkgId()
+ name := p.expect(scanner.Ident)
+ pkg := p.parsePkgId()
+ assert(pkg.Name == "" || pkg.Name == name)
+ pkg.Name = name
}
-
// int_lit = [ "+" | "-" ] { "0" ... "9" } .
//
func (p *gcParser) parseInt() (sign, val string) {
@@ -598,7 +605,6 @@ func (p *gcParser) parseInt() (sign, val string) {
return
}
-
// number = int_lit [ "p" int_lit ] .
//
func (p *gcParser) parseNumber() Const {
@@ -629,7 +635,6 @@ func (p *gcParser) parseNumber() Const {
return Const{mant}
}
-
// ConstDecl = "const" ExportedName [ Type ] "=" Literal .
// Literal = bool_lit | int_lit | float_lit | complex_lit | string_lit .
// bool_lit = "true" | "false" .
@@ -681,24 +686,28 @@ func (p *gcParser) parseConstDecl() {
if obj.Type == nil {
obj.Type = typ
}
- _ = x // TODO(gri) store x somewhere
+ obj.Data = x
}
-
// TypeDecl = "type" ExportedName Type .
//
func (p *gcParser) parseTypeDecl() {
p.expectKeyword("type")
obj := p.parseExportedName(ast.Typ)
+
+ // The type object may have been imported before and thus already
+ // have a type associated with it. We still need to parse the type
+ // structure, but throw it away if the object already has a type.
+ // This ensures that all imports refer to the same type object for
+ // a given type declaration.
typ := p.parseType()
- name := obj.Type.(*Name)
- assert(name.Underlying == nil)
- assert(Underlying(typ) == typ)
- name.Underlying = typ
+ if name := obj.Type.(*Name); name.Underlying == nil {
+ assert(Underlying(typ) == typ)
+ name.Underlying = typ
+ }
}
-
// VarDecl = "var" ExportedName Type .
//
func (p *gcParser) parseVarDecl() {
@@ -707,32 +716,26 @@ func (p *gcParser) parseVarDecl() {
obj.Type = p.parseType()
}
-
// FuncDecl = "func" ExportedName Signature .
//
func (p *gcParser) parseFuncDecl() {
// "func" already consumed
obj := p.parseExportedName(ast.Fun)
- obj.Type = p.parseFuncType()
+ obj.Type = p.parseSignature()
}
-
// MethodDecl = "func" Receiver identifier Signature .
// Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" .
//
func (p *gcParser) parseMethodDecl() {
// "func" already consumed
- scope := ast.NewScope(nil) // method scope
p.expect('(')
- p.parseParameter(scope, nil) // receiver
+ p.parseParameter() // receiver
p.expect(')')
p.expect(scanner.Ident)
- isVariadic := false
- p.parseSignature(scope, &isVariadic)
-
+ p.parseSignature()
}
-
// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
//
func (p *gcParser) parseDecl() {
@@ -756,14 +759,13 @@ func (p *gcParser) parseDecl() {
p.expect('\n')
}
-
// ----------------------------------------------------------------------------
// Export
// Export = "PackageClause { Decl } "$$" .
// PackageClause = "package" identifier [ "safe" ] "\n" .
//
-func (p *gcParser) parseExport() (string, *ast.Scope) {
+func (p *gcParser) parseExport() *ast.Object {
p.expectKeyword("package")
name := p.expect(scanner.Ident)
if p.tok != '\n' {
@@ -774,6 +776,11 @@ func (p *gcParser) parseExport() (string, *ast.Scope) {
}
p.expect('\n')
+ assert(p.imports[p.id] == nil)
+ pkg := ast.NewObj(ast.Pkg, name)
+ pkg.Data = ast.NewScope(nil)
+ p.imports[p.id] = pkg
+
for p.tok != '$' && p.tok != scanner.EOF {
p.parseDecl()
}
@@ -788,5 +795,5 @@ func (p *gcParser) parseExport() (string, *ast.Scope) {
p.errorf("expected no scanner errors, got %d", n)
}
- return name, p.scope
+ return pkg
}
diff --git a/libgo/go/go/types/gcimporter_test.go b/libgo/go/go/types/gcimporter_test.go
index 556e761df2d..ec87f5d514b 100644
--- a/libgo/go/go/types/gcimporter_test.go
+++ b/libgo/go/go/types/gcimporter_test.go
@@ -6,6 +6,7 @@ package types
import (
"exec"
+ "go/ast"
"io/ioutil"
"path/filepath"
"runtime"
@@ -14,7 +15,6 @@ import (
"time"
)
-
var gcName, gcPath string // compiler name and path
func init() {
@@ -34,31 +34,23 @@ func init() {
gcPath, _ = exec.LookPath(gcName)
}
-
func compile(t *testing.T, dirname, filename string) {
- cmd, err := exec.Run(gcPath, []string{gcPath, filename}, nil, dirname, exec.DevNull, exec.Pipe, exec.MergeWithStdout)
+ cmd := exec.Command(gcPath, filename)
+ cmd.Dir = dirname
+ out, err := cmd.CombinedOutput()
if err != nil {
t.Errorf("%s %s failed: %s", gcName, filename, err)
return
}
- defer cmd.Close()
-
- msg, err := cmd.Wait(0)
- if err != nil {
- t.Errorf("%s %s failed: %s", gcName, filename, err)
- return
- }
-
- if !msg.Exited() || msg.ExitStatus() != 0 {
- t.Errorf("%s %s failed: exit status = %d", gcName, filename, msg.ExitStatus())
- output, _ := ioutil.ReadAll(cmd.Stdout)
- t.Log(string(output))
- }
+ t.Logf("%s", string(out))
}
+// Use the same global imports map for all tests. The effect is
+// as if all tested packages were imported into a single package.
+var imports = make(map[string]*ast.Object)
func testPath(t *testing.T, path string) bool {
- _, _, err := GcImporter(path)
+ _, err := GcImporter(imports, path)
if err != nil {
t.Errorf("testPath(%s): %s", path, err)
return false
@@ -66,7 +58,6 @@ func testPath(t *testing.T, path string) bool {
return true
}
-
const maxTime = 3e9 // maximum allotted testing time in ns
func testDir(t *testing.T, dir string, endTime int64) (nimports int) {
@@ -98,7 +89,6 @@ func testDir(t *testing.T, dir string, endTime int64) (nimports int) {
return
}
-
func TestGcImport(t *testing.T) {
compile(t, "testdata", "exports.go")
diff --git a/libgo/go/go/types/testdata/exports.go b/libgo/go/go/types/testdata/exports.go
index 13efe012a0b..ed63bf9adec 100644
--- a/libgo/go/go/types/testdata/exports.go
+++ b/libgo/go/go/types/testdata/exports.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// This file is used to generate a .6 object file which
+// This file is used to generate an object file which
// serves as test file for gcimporter_test.go.
package exports
@@ -11,19 +11,17 @@ import (
"go/ast"
)
-
const (
C0 int = 0
- C1 = 3.14159265
- C2 = 2.718281828i
- C3 = -123.456e-789
- C4 = +123.456E+789
- C5 = 1234i
- C6 = "foo\n"
- C7 = `bar\n`
+ C1 = 3.14159265
+ C2 = 2.718281828i
+ C3 = -123.456e-789
+ C4 = +123.456E+789
+ C5 = 1234i
+ C6 = "foo\n"
+ C7 = `bar\n`
)
-
type (
T1 int
T2 [10]int
@@ -38,7 +36,7 @@ type (
T9 struct {
a int
b, c float32
- d []string "tag"
+ d []string `go:"tag"`
}
T10 struct {
T8
@@ -72,18 +70,15 @@ type (
T28 func(T28) T28
)
-
var (
V0 int
V1 = -991.0
)
-
func F1() {}
func F2(x int) {}
func F3() int { return 0 }
func F4() float32 { return 0 }
func F5(a, b, c int, u, v, w struct{ x, y T1 }, more ...interface{}) (p, q, r chan<- T10)
-
func (p *T1) M1()
diff --git a/libgo/go/go/types/types.go b/libgo/go/go/types/types.go
index 2ee645d989b..3aa896892e3 100644
--- a/libgo/go/go/types/types.go
+++ b/libgo/go/go/types/types.go
@@ -7,21 +7,27 @@
//
package types
-import "go/ast"
-
+import (
+ "go/ast"
+ "sort"
+)
// All types implement the Type interface.
type Type interface {
isType()
}
-
// All concrete types embed ImplementsType which
// ensures that all types implement the Type interface.
type ImplementsType struct{}
func (t *ImplementsType) isType() {}
+// A Bad type is a non-nil placeholder type when we don't know a type.
+type Bad struct {
+ ImplementsType
+ Msg string // for better error reporting/debugging
+}
// A Basic represents a (unnamed) basic type.
type Basic struct {
@@ -29,7 +35,6 @@ type Basic struct {
// TODO(gri) need a field specifying the exact basic type
}
-
// An Array represents an array type [Len]Elt.
type Array struct {
ImplementsType
@@ -37,50 +42,52 @@ type Array struct {
Elt Type
}
-
// A Slice represents a slice type []Elt.
type Slice struct {
ImplementsType
Elt Type
}
-
// A Struct represents a struct type struct{...}.
+// Anonymous fields are represented by objects with empty names.
type Struct struct {
ImplementsType
- // TODO(gri) need to remember fields.
+ Fields ObjList // struct fields; or nil
+ Tags []string // corresponding tags; or nil
+ // TODO(gri) This type needs some rethinking:
+ // - at the moment anonymous fields are marked with "" object names,
+ // and their names have to be reconstructed
+ // - there is no scope for fast lookup (but the parser creates one)
}
-
// A Pointer represents a pointer type *Base.
type Pointer struct {
ImplementsType
Base Type
}
-
// A Func represents a function type func(...) (...).
+// Unnamed parameters are represented by objects with empty names.
type Func struct {
ImplementsType
- IsVariadic bool
- // TODO(gri) need to remember parameters.
+ Recv *ast.Object // nil if not a method
+ Params ObjList // (incoming) parameters from left to right; or nil
+ Results ObjList // (outgoing) results from left to right; or nil
+ IsVariadic bool // true if the last parameter's type is of the form ...T
}
-
// An Interface represents an interface type interface{...}.
type Interface struct {
ImplementsType
- // TODO(gri) need to remember methods.
+ Methods ObjList // interface methods sorted by name; or nil
}
-
// A Map represents a map type map[Key]Elt.
type Map struct {
ImplementsType
Key, Elt Type
}
-
// A Chan represents a channel type chan Elt, <-chan Elt, or chan<-Elt.
type Chan struct {
ImplementsType
@@ -88,7 +95,6 @@ type Chan struct {
Elt Type
}
-
// A Name represents a named type as declared in a type declaration.
type Name struct {
ImplementsType
@@ -97,7 +103,6 @@ type Name struct {
// TODO(gri) need to remember fields and methods.
}
-
// If typ is a pointer type, Deref returns the pointer's base type;
// otherwise it returns typ.
func Deref(typ Type) Type {
@@ -107,16 +112,144 @@ func Deref(typ Type) Type {
return typ
}
-
// Underlying returns the underlying type of a type.
func Underlying(typ Type) Type {
if typ, ok := typ.(*Name); ok {
utyp := typ.Underlying
- if _, ok := utyp.(*Basic); ok {
- return typ
+ if _, ok := utyp.(*Basic); !ok {
+ return utyp
}
- return utyp
-
+ // the underlying type of a type name referring
+ // to an (untyped) basic type is the basic type
+ // name
}
return typ
}
+
+// An ObjList represents an ordered (in some fashion) list of objects.
+type ObjList []*ast.Object
+
+// ObjList implements sort.Interface.
+func (list ObjList) Len() int { return len(list) }
+func (list ObjList) Less(i, j int) bool { return list[i].Name < list[j].Name }
+func (list ObjList) Swap(i, j int) { list[i], list[j] = list[j], list[i] }
+
+// Sort sorts an object list by object name.
+func (list ObjList) Sort() { sort.Sort(list) }
+
+// identicalTypes returns true if both lists a and b have the
+// same length and corresponding objects have identical types.
+func identicalTypes(a, b ObjList) bool {
+ if len(a) == len(b) {
+ for i, x := range a {
+ y := b[i]
+ if !Identical(x.Type.(Type), y.Type.(Type)) {
+ return false
+ }
+ }
+ return true
+ }
+ return false
+}
+
+// Identical returns true if two types are identical.
+func Identical(x, y Type) bool {
+ if x == y {
+ return true
+ }
+
+ switch x := x.(type) {
+ case *Bad:
+ // A Bad type is always identical to any other type
+ // (to avoid spurious follow-up errors).
+ return true
+
+ case *Basic:
+ if y, ok := y.(*Basic); ok {
+ panic("unimplemented")
+ _ = y
+ }
+
+ case *Array:
+ // Two array types are identical if they have identical element types
+ // and the same array length.
+ if y, ok := y.(*Array); ok {
+ return x.Len == y.Len && Identical(x.Elt, y.Elt)
+ }
+
+ case *Slice:
+ // Two slice types are identical if they have identical element types.
+ if y, ok := y.(*Slice); ok {
+ return Identical(x.Elt, y.Elt)
+ }
+
+ case *Struct:
+ // Two struct types are identical if they have the same sequence of fields,
+ // and if corresponding fields have the same names, and identical types,
+ // and identical tags. Two anonymous fields are considered to have the same
+ // name. Lower-case field names from different packages are always different.
+ if y, ok := y.(*Struct); ok {
+ // TODO(gri) handle structs from different packages
+ if identicalTypes(x.Fields, y.Fields) {
+ for i, f := range x.Fields {
+ g := y.Fields[i]
+ if f.Name != g.Name || x.Tags[i] != y.Tags[i] {
+ return false
+ }
+ }
+ return true
+ }
+ }
+
+ case *Pointer:
+ // Two pointer types are identical if they have identical base types.
+ if y, ok := y.(*Pointer); ok {
+ return Identical(x.Base, y.Base)
+ }
+
+ case *Func:
+ // Two function types are identical if they have the same number of parameters
+ // and result values, corresponding parameter and result types are identical,
+ // and either both functions are variadic or neither is. Parameter and result
+ // names are not required to match.
+ if y, ok := y.(*Func); ok {
+ return identicalTypes(x.Params, y.Params) &&
+ identicalTypes(x.Results, y.Results) &&
+ x.IsVariadic == y.IsVariadic
+ }
+
+ case *Interface:
+ // Two interface types are identical if they have the same set of methods with
+ // the same names and identical function types. Lower-case method names from
+ // different packages are always different. The order of the methods is irrelevant.
+ if y, ok := y.(*Interface); ok {
+ return identicalTypes(x.Methods, y.Methods) // methods are sorted
+ }
+
+ case *Map:
+ // Two map types are identical if they have identical key and value types.
+ if y, ok := y.(*Map); ok {
+ return Identical(x.Key, y.Key) && Identical(x.Elt, y.Elt)
+ }
+
+ case *Chan:
+ // Two channel types are identical if they have identical value types
+ // and the same direction.
+ if y, ok := y.(*Chan); ok {
+ return x.Dir == y.Dir && Identical(x.Elt, y.Elt)
+ }
+
+ case *Name:
+ // Two named types are identical if their type names originate
+ // in the same type declaration.
+ if y, ok := y.(*Name); ok {
+ return x.Obj == y.Obj ||
+ // permit bad objects to be equal to avoid
+ // follow up errors
+ x.Obj != nil && x.Obj.Kind == ast.Bad ||
+ y.Obj != nil && y.Obj.Kind == ast.Bad
+ }
+ }
+
+ return false
+}
diff --git a/libgo/go/go/types/universe.go b/libgo/go/go/types/universe.go
index 2a54a8ac12c..6ae88e5f9c2 100644
--- a/libgo/go/go/types/universe.go
+++ b/libgo/go/go/types/universe.go
@@ -9,14 +9,12 @@ package types
import "go/ast"
-
var (
- scope, // current scope to use for initialization
- Universe,
- Unsafe *ast.Scope
+ scope *ast.Scope // current scope to use for initialization
+ Universe *ast.Scope
+ Unsafe *ast.Object // package unsafe
)
-
func define(kind ast.ObjKind, name string) *ast.Object {
obj := ast.NewObj(kind, name)
if scope.Insert(obj) != nil {
@@ -25,7 +23,6 @@ func define(kind ast.ObjKind, name string) *ast.Object {
return obj
}
-
func defType(name string) *Name {
obj := define(ast.Typ, name)
typ := &Name{Underlying: &Basic{}, Obj: obj}
@@ -33,19 +30,16 @@ func defType(name string) *Name {
return typ
}
-
func defConst(name string) {
obj := define(ast.Con, name)
_ = obj // TODO(gri) fill in other properties
}
-
func defFun(name string) {
obj := define(ast.Fun, name)
_ = obj // TODO(gri) fill in other properties
}
-
var (
Bool,
Int,
@@ -54,10 +48,9 @@ var (
String *Name
)
-
func init() {
- Universe = ast.NewScope(nil)
- scope = Universe
+ scope = ast.NewScope(nil)
+ Universe = scope
Bool = defType("bool")
defType("byte") // TODO(gri) should be an alias for uint8
@@ -98,8 +91,10 @@ func init() {
defFun("real")
defFun("recover")
- Unsafe = ast.NewScope(nil)
- scope = Unsafe
+ scope = ast.NewScope(nil)
+ Unsafe = ast.NewObj(ast.Pkg, "unsafe")
+ Unsafe.Data = scope
+
defType("Pointer")
defFun("Alignof")
OpenPOWER on IntegriCloud