f8d9fa9e80
This upgrades all of libgo other than the runtime package to the Go 1.4 release. In Go 1.4 much of the runtime was rewritten into Go. Merging that code will take more time and will not change the API, so I'm putting it off for now. There are a few runtime changes anyhow, to accomodate other packages that rely on minor modifications to the runtime support. The compiler changes slightly to add a one-bit flag to each type descriptor kind that is stored directly in an interface, which for gccgo is currently only pointer types. Another one-bit flag (gcprog) is reserved because it is used by the gc compiler, but gccgo does not currently use it. There is another error check in the compiler since I ran across it during testing. gotools/: * Makefile.am (go_cmd_go_files): Sort entries. Add generate.go. * Makefile.in: Rebuild. From-SVN: r219627
162 lines
4.4 KiB
Go
162 lines
4.4 KiB
Go
// Copyright 2010 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/ast"
|
|
"go/token"
|
|
"reflect"
|
|
)
|
|
|
|
type simplifier struct {
|
|
hasDotImport bool // package file contains: import . "some/import/path"
|
|
}
|
|
|
|
func (s *simplifier) Visit(node ast.Node) ast.Visitor {
|
|
switch n := node.(type) {
|
|
case *ast.CompositeLit:
|
|
// array, slice, and map composite literals may be simplified
|
|
outer := n
|
|
var eltType ast.Expr
|
|
switch typ := outer.Type.(type) {
|
|
case *ast.ArrayType:
|
|
eltType = typ.Elt
|
|
case *ast.MapType:
|
|
eltType = typ.Value
|
|
}
|
|
|
|
if eltType != nil {
|
|
typ := reflect.ValueOf(eltType)
|
|
for i, x := range outer.Elts {
|
|
px := &outer.Elts[i]
|
|
// look at value of indexed/named elements
|
|
if t, ok := x.(*ast.KeyValueExpr); ok {
|
|
x = t.Value
|
|
px = &t.Value
|
|
}
|
|
ast.Walk(s, x) // simplify x
|
|
// if the element is a composite literal and its literal type
|
|
// matches the outer literal's element type exactly, the inner
|
|
// literal type may be omitted
|
|
if inner, ok := x.(*ast.CompositeLit); ok {
|
|
if match(nil, typ, reflect.ValueOf(inner.Type)) {
|
|
inner.Type = nil
|
|
}
|
|
}
|
|
// if the outer literal's element type is a pointer type *T
|
|
// and the element is & of a composite literal of type T,
|
|
// the inner &T may be omitted.
|
|
if ptr, ok := eltType.(*ast.StarExpr); ok {
|
|
if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND {
|
|
if inner, ok := addr.X.(*ast.CompositeLit); ok {
|
|
if match(nil, reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) {
|
|
inner.Type = nil // drop T
|
|
*px = inner // drop &
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// node was simplified - stop walk (there are no subnodes to simplify)
|
|
return nil
|
|
}
|
|
|
|
case *ast.SliceExpr:
|
|
// a slice expression of the form: s[a:len(s)]
|
|
// can be simplified to: s[a:]
|
|
// if s is "simple enough" (for now we only accept identifiers)
|
|
if n.Max != nil || s.hasDotImport {
|
|
// - 3-index slices always require the 2nd and 3rd index
|
|
// - if dot imports are present, we cannot be certain that an
|
|
// unresolved "len" identifier refers to the predefined len()
|
|
break
|
|
}
|
|
if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil {
|
|
// the array/slice object is a single, resolved identifier
|
|
if call, _ := n.High.(*ast.CallExpr); call != nil && len(call.Args) == 1 && !call.Ellipsis.IsValid() {
|
|
// the high expression is a function call with a single argument
|
|
if fun, _ := call.Fun.(*ast.Ident); fun != nil && fun.Name == "len" && fun.Obj == nil {
|
|
// the function called is "len" and it is not locally defined; and
|
|
// because we don't have dot imports, it must be the predefined len()
|
|
if arg, _ := call.Args[0].(*ast.Ident); arg != nil && arg.Obj == s.Obj {
|
|
// the len argument is the array/slice object
|
|
n.High = nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Note: We could also simplify slice expressions of the form s[0:b] to s[:b]
|
|
// but we leave them as is since sometimes we want to be very explicit
|
|
// about the lower bound.
|
|
// An example where the 0 helps:
|
|
// x, y, z := b[0:2], b[2:4], b[4:6]
|
|
// An example where it does not:
|
|
// x, y := b[:n], b[n:]
|
|
|
|
case *ast.RangeStmt:
|
|
// - a range of the form: for x, _ = range v {...}
|
|
// can be simplified to: for x = range v {...}
|
|
// - a range of the form: for _ = range v {...}
|
|
// can be simplified to: for range v {...}
|
|
if isBlank(n.Value) {
|
|
n.Value = nil
|
|
}
|
|
if isBlank(n.Key) && n.Value == nil {
|
|
n.Key = nil
|
|
}
|
|
}
|
|
|
|
return s
|
|
}
|
|
|
|
func isBlank(x ast.Expr) bool {
|
|
ident, ok := x.(*ast.Ident)
|
|
return ok && ident.Name == "_"
|
|
}
|
|
|
|
func simplify(f *ast.File) {
|
|
var s simplifier
|
|
|
|
// determine if f contains dot imports
|
|
for _, imp := range f.Imports {
|
|
if imp.Name != nil && imp.Name.Name == "." {
|
|
s.hasDotImport = true
|
|
break
|
|
}
|
|
}
|
|
|
|
// remove empty declarations such as "const ()", etc
|
|
removeEmptyDeclGroups(f)
|
|
|
|
ast.Walk(&s, f)
|
|
}
|
|
|
|
func removeEmptyDeclGroups(f *ast.File) {
|
|
i := 0
|
|
for _, d := range f.Decls {
|
|
if g, ok := d.(*ast.GenDecl); !ok || !isEmpty(f, g) {
|
|
f.Decls[i] = d
|
|
i++
|
|
}
|
|
}
|
|
f.Decls = f.Decls[:i]
|
|
}
|
|
|
|
func isEmpty(f *ast.File, g *ast.GenDecl) bool {
|
|
if g.Doc != nil || g.Specs != nil {
|
|
return false
|
|
}
|
|
|
|
for _, c := range f.Comments {
|
|
// if there is a comment in the declaration, it is not considered empty
|
|
if g.Pos() <= c.Pos() && c.End() <= g.End() {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|