// Func = Name FunctionType . func (p *parser) parseFunc(pkg *types.Package) *types.Func { name := p.parseName() if strings.ContainsRune(name, '$') { // This is a Type$equal or Type$hash function, which we don't want to parse, // except for the types. p.discardDirectiveWhileParsingTypes(pkg) return nil } return types.NewFunc(token.NoPos, pkg, name, p.parseFunctionType(pkg)) }
// InterfaceType = "interface" "{" [ MethodList ] "}" . // MethodList = Method { ";" Method } . // Method = Name Signature . // // The methods of embedded interfaces are always "inlined" // by the compiler and thus embedded interfaces are never // visible in the export data. // func (p *parser) parseInterfaceType() types.Type { var methods []*types.Func p.expectKeyword("interface") p.expect('{') for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ { if i > 0 { p.expect(';') } pkg, name := p.parseName(true) sig := p.parseSignature(nil) methods = append(methods, types.NewFunc(token.NoPos, pkg, name, sig)) } p.expect('}') return types.NewInterface(methods, nil) }
// MethodDecl = "func" Receiver Name Func . // Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" . // func (p *parser) parseMethodDecl() { // "func" already consumed p.expect('(') recv, _ := p.parseParameter() // receiver p.expect(')') // determine receiver base type object base := deref(recv.Type()).(*types.Named) // parse method name, signature, and possibly inlined body pkg, name := p.parseName(true) sig := p.parseFunc(recv) // add method to type unless type was imported before // and method exists already // TODO(gri) This leads to a quadratic algorithm - ok for now because method counts are small. base.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig)) }
// InterfaceType = "interface" "{" [ MethodList ] "}" . // MethodList = Method { ";" Method } . // Method = Name Signature . // // The methods of embedded interfaces are always "inlined" // by the compiler and thus embedded interfaces are never // visible in the export data. // func (p *parser) parseInterfaceType() types.Type { var methods []*types.Func p.expectKeyword("interface") p.expect('{') for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ { if i > 0 { p.expect(';') } pkg, name := p.parseName(true) sig := p.parseSignature(nil) methods = append(methods, types.NewFunc(token.NoPos, pkg, name, sig)) } p.expect('}') // Complete requires the type's embedded interfaces to be fully defined, // but we do not define any return types.NewInterface(methods, nil).Complete() }
func (p *importer) obj(pkg *types.Package) { var obj types.Object switch tag := p.int(); tag { case constTag: obj = types.NewConst(token.NoPos, pkg, p.string(), p.typ(), p.value()) case typeTag: // type object is added to scope via respective named type _ = p.typ().(*types.Named) return case varTag: obj = types.NewVar(token.NoPos, pkg, p.string(), p.typ()) case funcTag: obj = types.NewFunc(token.NoPos, pkg, p.string(), p.typ().(*types.Signature)) default: panic(fmt.Sprintf("unexpected object tag %d", tag)) } if alt := pkg.Scope().Insert(obj); alt != nil { panic(fmt.Sprintf("%s already declared", alt.Name())) } }
// NamedType = TypeName Type { Method } . // Method = "func" "(" Param ")" Name ParamList ResultList ";" . func (p *parser) parseNamedType(n int) types.Type { obj := p.parseTypeName() pkg := obj.Pkg() typ := obj.Type() p.typeMap[n] = typ nt, ok := typ.(*types.Named) if !ok { // This can happen for unsafe.Pointer, which is a TypeName holding a Basic type. pt := p.parseType(pkg) if pt != typ { p.error("unexpected underlying type for non-named TypeName") } return typ } underlying := p.parseType(pkg) if nt.Underlying() == nil { nt.SetUnderlying(underlying.Underlying()) } for p.tok == scanner.Ident { // collect associated methods p.expectKeyword("func") p.expect('(') receiver, _ := p.parseParam(pkg) p.expect(')') name := p.parseName() params, isVariadic := p.parseParamList(pkg) results := p.parseResultList(pkg) p.expect(';') sig := types.NewSignature(pkg.Scope(), receiver, params, results, isVariadic) nt.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig)) } return nt }
func (p *importer) typ() types.Type { // if the type was seen before, i is its index (>= 0) i := p.int() if i >= 0 { return p.typList[i] } // otherwise, i is the type tag (< 0) switch i { case arrayTag: t := new(types.Array) p.record(t) n := p.int64() *t = *types.NewArray(p.typ(), n) return t case sliceTag: t := new(types.Slice) p.record(t) *t = *types.NewSlice(p.typ()) return t case structTag: t := new(types.Struct) p.record(t) n := p.int() fields := make([]*types.Var, n) tags := make([]string, n) for i := range fields { fields[i] = p.field() tags[i] = p.string() } *t = *types.NewStruct(fields, tags) return t case pointerTag: t := new(types.Pointer) p.record(t) *t = *types.NewPointer(p.typ()) return t case signatureTag: t := new(types.Signature) p.record(t) *t = *p.signature() return t case interfaceTag: t := new(types.Interface) p.record(t) // read embedded interfaces embeddeds := make([]*types.Named, p.int()) for i := range embeddeds { embeddeds[i] = p.typ().(*types.Named) } // read methods methods := make([]*types.Func, p.int()) for i := range methods { pkg, name := p.qualifiedName() methods[i] = types.NewFunc(token.NoPos, pkg, name, p.typ().(*types.Signature)) } *t = *types.NewInterface(methods, embeddeds) return t case mapTag: t := new(types.Map) p.record(t) *t = *types.NewMap(p.typ(), p.typ()) return t case chanTag: t := new(types.Chan) p.record(t) *t = *types.NewChan(types.ChanDir(p.int()), p.typ()) return t case namedTag: // read type object name := p.string() pkg := p.pkg() scope := pkg.Scope() obj := scope.Lookup(name) // if the object doesn't exist yet, create and insert it if obj == nil { obj = types.NewTypeName(token.NoPos, pkg, name, nil) scope.Insert(obj) } // associate new named type with obj if it doesn't exist yet t0 := types.NewNamed(obj.(*types.TypeName), nil, nil) // but record the existing type, if any t := obj.Type().(*types.Named) p.record(t) // read underlying type t0.SetUnderlying(p.typ()) // read associated methods for i, n := 0, p.int(); i < n; i++ { t0.AddMethod(types.NewFunc(token.NoPos, pkg, p.string(), p.typ().(*types.Signature))) } return t default: panic(fmt.Sprintf("unexpected type tag %d", i)) } }
// FuncDecl = "func" ExportedName Func . // func (p *parser) parseFuncDecl() { // "func" already consumed pkg, name := p.parseExportedName() typ := p.parseFunc(nil) pkg.Scope().Insert(types.NewFunc(token.NoPos, pkg, name, typ)) }
func (cdd *CDD) Expr(w *bytes.Buffer, expr ast.Expr, nilT types.Type) { cdd.Complexity++ if t := cdd.gtc.ti.Types[expr]; t.Value != nil { // Constant expression cdd.Value(w, t.Value, t.Type) return } switch e := expr.(type) { case *ast.BinaryExpr: op := e.Op.String() ltyp := cdd.exprType(e.X) rtyp := cdd.exprType(e.Y) lhs := cdd.ExprStr(e.X, ltyp) rhs := cdd.ExprStr(e.Y, rtyp) if op == "==" || op == "!=" { eq(w, lhs, op, rhs, ltyp, rtyp) break } // BUG: strings if op == "&^" { op = "&~" } w.WriteString("(" + lhs + op + rhs + ")") case *ast.UnaryExpr: op := e.Op.String() if op == "<-" { t := cdd.exprType(e.X).(*types.Chan).Elem() if tup, ok := cdd.exprType(e).(*types.Tuple); ok { tn, _, _ := cdd.tupleName(tup) w.WriteString("RECVOK(" + tn + ", ") cdd.Expr(w, e.X, nil) w.WriteByte(')') } else { w.WriteString("RECV(") dim, _ := cdd.Type(w, t) w.WriteString(dimFuncPtr("", dim)) w.WriteString(", ") cdd.Expr(w, e.X, nil) w.WriteString(", ") zeroVal(w, t) w.WriteByte(')') } break } if op == "^" { op = "~" } w.WriteString(op) cdd.Expr(w, e.X, nil) case *ast.CallExpr: cdd.CallExpr(w, e) case *ast.Ident: if e.Name == "nil" { cdd.Nil(w, nilT) } else { cdd.Name(w, cdd.object(e), true) } case *ast.IndexExpr: cdd.indexExpr(w, cdd.exprType(e.X), cdd.ExprStr(e.X, nil), e.Index) case *ast.KeyValueExpr: kt := cdd.exprType(e.Key) if i, ok := e.Key.(*ast.Ident); ok && kt == nil { // e.Key is field name w.WriteByte('.') w.WriteString(i.Name) } else { w.WriteByte('[') cdd.Expr(w, e.Key, kt) w.WriteByte(']') } w.WriteString(" = ") cdd.Expr(w, e.Value, nilT) case *ast.ParenExpr: w.WriteByte('(') cdd.Expr(w, e.X, nilT) w.WriteByte(')') case *ast.SelectorExpr: s, fun, recv := cdd.SelectorExprStr(e) if recv == nil { w.WriteString(s) break } sig := fun.(*types.Signature) w.WriteString("({") res, params := cdd.signature(sig, false, numNames) w.WriteString(res.typ) w.WriteByte(' ') w.WriteString(dimFuncPtr("func"+params, res.dim)) w.WriteString(" { return " + s + "(") cdd.Expr(w, recv, nil) if p := sig.Params(); p != nil { for i := 1; i <= p.Len(); i++ { w.WriteString(", _" + strconv.Itoa(i)) } } w.WriteString("); } func;})") case *ast.SliceExpr: cdd.SliceExpr(w, e) case *ast.StarExpr: w.WriteByte('*') cdd.Expr(w, e.X, nil) case *ast.TypeAssertExpr: notImplemented(e) case *ast.CompositeLit: typ := cdd.exprType(e) switch t := underlying(typ).(type) { case *types.Array: w.WriteByte('{') nilT = t.Elem() case *types.Slice: w.WriteString("(slice){(") dim, _ := cdd.Type(w, t.Elem()) dim = append([]string{"[]"}, dim...) w.WriteString(dimFuncPtr("", dim)) w.WriteString("){") nilT = t.Elem() case *types.Struct: w.WriteByte('(') cdd.Type(w, typ) w.WriteString("){") nilT = nil default: notImplemented(e, t) } for i, el := range e.Elts { if i > 0 { w.WriteString(", ") } if nilT != nil { cdd.Expr(w, el, nilT) } else { cdd.Expr(w, el, underlying(typ).(*types.Struct).Field(i).Type()) } } switch underlying(typ).(type) { case *types.Slice: w.WriteByte('}') plen := ", " + strconv.Itoa(len(e.Elts)) w.WriteString(plen) w.WriteString(plen) w.WriteByte('}') default: w.WriteByte('}') } case *ast.FuncLit: fname := "func" fd := &ast.FuncDecl{ Name: &ast.Ident{NamePos: e.Type.Func, Name: fname}, Type: e.Type, Body: e.Body, } sig := cdd.exprType(e).(*types.Signature) cdd.gtc.ti.Defs[fd.Name] = types.NewFunc(e.Type.Func, cdd.gtc.pkg, fname, sig) w.WriteString("({\n") cdd.il++ cdds := cdd.gtc.FuncDecl(fd, cdd.il) for _, c := range cdds { for u, typPtr := range c.FuncBodyUses { cdd.FuncBodyUses[u] = typPtr } cdd.indent(w) w.Write(c.Def) } cdd.indent(w) w.WriteString(fname + "$;\n") cdd.il-- cdd.indent(w) w.WriteString("})") default: fmt.Fprintf(w, "!%v<%T>!", e, e) } }