import (
"bytes"
+ "fmt"
"go/ast"
)
switch x := x.(type) {
default:
- buf.WriteString("(bad expr)") // nil, ast.BadExpr, ast.KeyValueExpr
+ buf.WriteString(fmt.Sprintf("(ast: %T)", x)) // nil, ast.BadExpr, ast.KeyValueExpr
case *ast.Ident:
buf.WriteString(x.Name)
case *ast.CallExpr:
WriteExpr(buf, x.Fun)
- buf.WriteByte('(')
- for i, arg := range x.Args {
- if i > 0 {
- buf.WriteString(", ")
- }
- WriteExpr(buf, arg)
+ var l, r byte = '(', ')'
+ if x.Brackets {
+ l, r = '[', ']'
}
+ buf.WriteByte(l)
+ writeExprList(buf, x.Args)
if x.Ellipsis.IsValid() {
buf.WriteString("...")
}
- buf.WriteByte(')')
+ buf.WriteByte(r)
case *ast.StarExpr:
buf.WriteByte('*')
case *ast.StructType:
buf.WriteString("struct{")
- writeFieldList(buf, x.Fields, "; ", false)
+ writeFieldList(buf, x.Fields.List, "; ", false)
buf.WriteByte('}')
case *ast.FuncType:
writeSigExpr(buf, x)
case *ast.InterfaceType:
+ // separate type list types from method list
+ // TODO(gri) we can get rid of this extra code if writeExprList does the separation
+ var types []ast.Expr
+ var methods []*ast.Field
+ for _, f := range x.Methods.List {
+ if len(f.Names) > 1 && f.Names[0].Name == "type" {
+ // type list type
+ types = append(types, f.Type)
+ } else {
+ // method or embedded interface
+ methods = append(methods, f)
+ }
+ }
+
buf.WriteString("interface{")
- writeFieldList(buf, x.Methods, "; ", true)
+ writeFieldList(buf, methods, "; ", true)
+ if len(types) > 0 {
+ if len(methods) > 0 {
+ buf.WriteString("; ")
+ }
+ buf.WriteString("type ")
+ writeExprList(buf, types)
+ }
buf.WriteByte('}')
case *ast.MapType:
func writeSigExpr(buf *bytes.Buffer, sig *ast.FuncType) {
buf.WriteByte('(')
- writeFieldList(buf, sig.Params, ", ", false)
+ writeFieldList(buf, sig.Params.List, ", ", false)
buf.WriteByte(')')
res := sig.Results
// multiple or named result(s)
buf.WriteByte('(')
- writeFieldList(buf, res, ", ", false)
+ writeFieldList(buf, res.List, ", ", false)
buf.WriteByte(')')
}
-func writeFieldList(buf *bytes.Buffer, fields *ast.FieldList, sep string, iface bool) {
- for i, f := range fields.List {
+func writeFieldList(buf *bytes.Buffer, list []*ast.Field, sep string, iface bool) {
+ for i, f := range list {
if i > 0 {
buf.WriteString(sep)
}
// field list names
- for i, name := range f.Names {
- if i > 0 {
- buf.WriteString(", ")
- }
- buf.WriteString(name.Name)
- }
+ writeIdentList(buf, f.Names)
// types of interface methods consist of signatures only
if sig, _ := f.Type.(*ast.FuncType); sig != nil && iface {
// ignore tag
}
}
+
+func writeIdentList(buf *bytes.Buffer, list []*ast.Ident) {
+ for i, x := range list {
+ if i > 0 {
+ buf.WriteString(", ")
+ }
+ buf.WriteString(x.Name)
+ }
+}
+
+func writeExprList(buf *bytes.Buffer, list []ast.Expr) {
+ for i, x := range list {
+ if i > 0 {
+ buf.WriteString(", ")
+ }
+ WriteExpr(buf, x)
+ }
+}
return nil
}
+// Squash merges s with its parent scope p by adding all
+// objects of s to p, adding all children of s to the
+// children of p, and removing s from p's children.
+// The function f is called for each object obj in s which
+// has an object alt in p. s should be discarded after
+// having been squashed.
+func (s *Scope) Squash(err func(obj, alt Object)) {
+ p := s.parent
+ assert(p != nil)
+ for _, obj := range s.elems {
+ obj.setParent(nil)
+ if alt := p.Insert(obj); alt != nil {
+ err(obj, alt)
+ }
+ }
+
+ j := -1 // index of s in p.children
+ for i, ch := range p.children {
+ if ch == s {
+ j = i
+ break
+ }
+ }
+ assert(j >= 0)
+ k := len(p.children) - 1
+ p.children[j] = p.children[k]
+ p.children = p.children[:k]
+
+ p.children = append(p.children, s.children...)
+
+ s.children = nil
+ s.elems = nil
+}
+
// Pos and End describe the scope's source code extent [pos, end).
// The results are guaranteed to be valid only if the type-checked
// AST has complete position information. The extent is undefined
func (s *StdSizes) Alignof(T Type) int64 {
// For arrays and structs, alignment is defined in terms
// of alignment of the elements and fields, respectively.
- switch t := T.Underlying().(type) {
+ switch t := optype(T).(type) {
case *Array:
// spec: "For a variable x of array type: unsafe.Alignof(x)
// is the same as unsafe.Alignof(x[0]), but at least 1."
}
func (s *StdSizes) Sizeof(T Type) int64 {
- switch t := T.Underlying().(type) {
+ switch t := optype(T).(type) {
case *Basic:
assert(isTyped(T))
k := t.kind
}
offsets := s.Offsetsof(t.fields)
return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
+ case *Sum:
+ panic("Sizeof unimplemented for type sum")
case *Interface:
return s.WordSize * 2
}
func (conf *Config) offsetof(typ Type, index []int) int64 {
var o int64
for _, i := range index {
- s := typ.Underlying().(*Struct)
+ s := asStruct(typ)
o += conf.offsetsof(s)[i]
typ = s.fields[i].typ
}