mirror of https://github.com/pulumi/pulumi.git
548 lines
19 KiB
Go
548 lines
19 KiB
Go
// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
|
|
|
|
package lumidl
|
|
|
|
import (
|
|
"fmt"
|
|
"go/types"
|
|
"path/filepath"
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/pulumi/pulumi/pkg/tokens"
|
|
"github.com/pulumi/pulumi/pkg/tools"
|
|
"github.com/pulumi/pulumi/pkg/util/contract"
|
|
)
|
|
|
|
type RPCGenerator struct {
|
|
IDLRoot string // the root where IDL is loaded from.
|
|
IDLPkgBase string // the IDL's base package path.
|
|
RPCPkgBase string // the RPC's base package path.
|
|
Out string // where RPC stub outputs will be saved.
|
|
CurrPkg *Package // the package currently being visited.
|
|
CurrFile string // the file currently being visited.
|
|
FileHadRes bool // true if the file had at least one resource.
|
|
FileImports map[string]string // a map of foreign packages used in a file.
|
|
}
|
|
|
|
func NewRPCGenerator(root, idlPkgBase, rpcPkgBase, out string) *RPCGenerator {
|
|
return &RPCGenerator{
|
|
IDLRoot: root,
|
|
IDLPkgBase: idlPkgBase,
|
|
RPCPkgBase: rpcPkgBase,
|
|
Out: out,
|
|
}
|
|
}
|
|
|
|
func (g *RPCGenerator) Generate(pkg *Package) error {
|
|
// Ensure the directory structure exists in the target.
|
|
if err := mirrorDirLayout(pkg, g.Out); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Install context about the current entity being visited.
|
|
oldpkg, oldfile := g.CurrPkg, g.CurrFile
|
|
g.CurrPkg = pkg
|
|
defer (func() {
|
|
g.CurrPkg = oldpkg
|
|
g.CurrFile = oldfile
|
|
})()
|
|
|
|
// Now walk through the package, file by file, and generate the contents.
|
|
for relpath, file := range pkg.Files {
|
|
g.CurrFile = relpath
|
|
var members []Member
|
|
for _, nm := range file.MemberNames {
|
|
members = append(members, file.Members[nm])
|
|
}
|
|
path := filepath.Join(g.Out, relpath)
|
|
if err := g.EmitFile(path, pkg, members); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (g *RPCGenerator) EmitFile(file string, pkg *Package, members []Member) error {
|
|
oldHadRes, oldImports := g.FileHadRes, g.FileImports
|
|
g.FileHadRes, g.FileImports = false, make(map[string]string)
|
|
defer (func() {
|
|
g.FileHadRes = oldHadRes
|
|
g.FileImports = oldImports
|
|
})()
|
|
|
|
// First, generate the body. This is required first so we know which imports to emit.
|
|
body := g.genFileBody(file, pkg, members)
|
|
|
|
// Open up a writer that overwrites whatever file contents already exist.
|
|
w, err := tools.NewGenWriter(lumidl, file)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer contract.IgnoreClose(w)
|
|
|
|
// Emit a header into the file.
|
|
w.EmitHeaderWarning()
|
|
|
|
// Now emit the package name at the top-level.
|
|
w.Writefmtln("package %v", pkg.Pkginfo.Pkg.Name())
|
|
w.Writefmtln("")
|
|
|
|
// And all of the imports that we're going to need.
|
|
if g.FileHadRes || len(g.FileImports) > 0 {
|
|
w.Writefmtln("import (")
|
|
|
|
if g.FileHadRes {
|
|
w.Writefmtln(` pbempty "github.com/golang/protobuf/ptypes/empty"`)
|
|
w.Writefmtln(` pbstruct "github.com/golang/protobuf/ptypes/struct"`)
|
|
w.Writefmtln(` "golang.org/x/net/context"`)
|
|
w.Writefmtln("")
|
|
w.Writefmtln(` "github.com/pulumi/pulumi/pkg/resource"`)
|
|
w.Writefmtln(` "github.com/pulumi/pulumi/pkg/resource/plugin"`)
|
|
w.Writefmtln(` "github.com/pulumi/pulumi/pkg/tokens"`)
|
|
w.Writefmtln(` "github.com/pulumi/pulumi/pkg/util/contract"`)
|
|
w.Writefmtln(` "github.com/pulumi/pulumi/pkg/util/mapper"`)
|
|
w.Writefmtln(` lumirpc "github.com/pulumi/pulumi/sdk/proto/go"`)
|
|
}
|
|
|
|
if len(g.FileImports) > 0 {
|
|
if g.FileHadRes {
|
|
w.Writefmtln("")
|
|
}
|
|
// Sort the imports so they are in a correct, deterministic order.
|
|
var imports []string
|
|
for imp := range g.FileImports {
|
|
imports = append(imports, imp)
|
|
}
|
|
sort.Strings(imports)
|
|
|
|
// Now just emit a list of imports with their given names.
|
|
for _, imp := range imports {
|
|
name := g.FileImports[imp]
|
|
|
|
// If the import referenced one of the IDL packages, we must rewrite it to an RPC package.
|
|
contract.Assertf(strings.HasPrefix(imp, g.IDLPkgBase),
|
|
"Inter-IDL package references not yet supported (%v is not part of %v)", imp, g.IDLPkgBase)
|
|
var imppath string
|
|
if imp == g.IDLPkgBase {
|
|
imppath = g.RPCPkgBase
|
|
} else {
|
|
relimp := imp[len(g.IDLPkgBase)+1:]
|
|
imppath = g.RPCPkgBase + "/" + relimp
|
|
}
|
|
|
|
w.Writefmtln(` %v "%v"`, name, imppath)
|
|
}
|
|
}
|
|
|
|
w.Writefmtln(")")
|
|
w.Writefmtln("")
|
|
}
|
|
|
|
// Now finally emit the actual body and close out the file.
|
|
w.Writefmtln("%v", body)
|
|
return w.Flush()
|
|
}
|
|
|
|
func (g *RPCGenerator) genFileBody(file string, pkg *Package, members []Member) string {
|
|
w, err := tools.NewGenWriter(lumidl, "")
|
|
contract.IgnoreError(err)
|
|
|
|
// First, for each RPC struct/resource member, emit its appropriate generated code.
|
|
var typedefs []Typedef
|
|
var consts []*Const
|
|
module := g.getFileModule(file)
|
|
for _, m := range members {
|
|
switch t := m.(type) {
|
|
case *Alias:
|
|
typedefs = append(typedefs, t)
|
|
case *Const:
|
|
consts = append(consts, t)
|
|
case *Enum:
|
|
typedefs = append(typedefs, t)
|
|
case *Resource:
|
|
g.EmitResource(w, module, pkg, t)
|
|
g.EmitStructType(w, module, pkg, t)
|
|
case *Struct:
|
|
g.EmitStructType(w, module, pkg, t)
|
|
default:
|
|
contract.Failf("Unrecognized package member type: %v", reflect.TypeOf(t))
|
|
}
|
|
}
|
|
|
|
// Next emit all supporting types. First, aliases and enum types.
|
|
if len(typedefs) > 0 {
|
|
g.EmitTypedefs(w, typedefs)
|
|
}
|
|
|
|
// Finally, emit any consts at the very end.
|
|
if len(consts) > 0 {
|
|
g.EmitConstants(w, consts)
|
|
}
|
|
|
|
err = w.Flush()
|
|
contract.IgnoreError(err)
|
|
return w.Buffer()
|
|
}
|
|
|
|
// getFileModule generates a module name from a filename. To do so, we simply find the path part after the root and
|
|
// remove any file extensions, to get the underlying package's module token.
|
|
func (g *RPCGenerator) getFileModule(file string) tokens.Module {
|
|
module, _ := filepath.Rel(g.Out, file)
|
|
if ext := filepath.Ext(module); ext != "" {
|
|
extix := strings.LastIndex(module, ext)
|
|
module = module[:extix]
|
|
}
|
|
return tokens.Module(module)
|
|
}
|
|
|
|
func (g *RPCGenerator) EmitResource(w *tools.GenWriter, module tokens.Module, pkg *Package, res *Resource) {
|
|
name := res.Name()
|
|
w.Writefmtln("/* RPC stubs for %v resource provider */", name)
|
|
w.Writefmtln("")
|
|
|
|
// Remember when we encounter resources so we can import the right packages.
|
|
g.FileHadRes = true
|
|
|
|
propopts := res.PropertyOptions()
|
|
var hasinputs bool
|
|
for _, propopt := range propopts {
|
|
if !propopt.Out {
|
|
hasinputs = true
|
|
break
|
|
}
|
|
}
|
|
|
|
// Emit a type token.
|
|
token := fmt.Sprintf("%v:%v:%v", pkg.Name, module, name)
|
|
w.Writefmtln("// %[1]vToken is the type token corresponding to the %[1]v package type.", name)
|
|
w.Writefmtln(`const %vToken = tokens.Type("%v")`, name, token)
|
|
w.Writefmtln("")
|
|
|
|
// Now, generate an ops interface that the real provider will implement.
|
|
w.Writefmtln("// %[1]vProviderOps is a pluggable interface for %[1]v-related management functionality.", name)
|
|
w.Writefmtln("type %vProviderOps interface {", name)
|
|
w.Writefmtln(" Configure(ctx context.Context, vars map[tokens.ModuleMember]string) error")
|
|
w.Writefmtln(" Check(ctx context.Context, obj *%v, property string) error", name)
|
|
w.Writefmtln(" Diff(ctx context.Context, id resource.ID,")
|
|
w.Writefmtln(" old *%[1]v, new *%[1]v, diff *resource.ObjectDiff) ([]string, error)", name)
|
|
w.Writefmtln(" Create(ctx context.Context, obj *%v) (resource.ID, error)", name)
|
|
w.Writefmtln(" Update(ctx context.Context, id resource.ID,")
|
|
w.Writefmtln(" old *%[1]v, new *%[1]v, diff *resource.ObjectDiff) error", name)
|
|
w.Writefmtln(" Delete(ctx context.Context, id resource.ID, obj %v) error", name)
|
|
w.Writefmtln("}")
|
|
w.Writefmtln("")
|
|
|
|
// Next generate all the RPC scaffolding goo
|
|
w.Writefmtln("// %[1]vProvider is a dynamic gRPC-based plugin for managing %[1]v resources.", name)
|
|
w.Writefmtln("type %vProvider struct {", name)
|
|
w.Writefmtln(" ops %vProviderOps", name)
|
|
w.Writefmtln("}")
|
|
w.Writefmtln("")
|
|
w.Writefmtln("// New%vProvider allocates a resource provider that delegates to a ops instance.", name)
|
|
w.Writefmtln("func New%[1]vProvider(ops %[1]vProviderOps) lumirpc.ResourceProviderServer {", name)
|
|
w.Writefmtln(" contract.Assert(ops != nil)")
|
|
w.Writefmtln(" return &%vProvider{ops: ops}", name)
|
|
w.Writefmtln("}")
|
|
w.Writefmtln("")
|
|
w.Writefmtln("func (p *%vProvider) Configure(", name)
|
|
w.Writefmtln(" ctx context.Context, req *lumirpc.ConfigureRequest) (*pbempty.Empty, error) {")
|
|
w.Writefmtln(" vars := make(map[tokens.ModuleMember]string)")
|
|
w.Writefmtln(" for k, v := range req.GetVariables() {")
|
|
w.Writefmtln(" vars[tokens.ModuleMember(k)] = v")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" if err := p.ops.Configure(ctx, vars); err != nil {")
|
|
w.Writefmtln(" return nil, err")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" return &pbempty.Empty{}, nil")
|
|
w.Writefmtln("}")
|
|
w.Writefmtln("")
|
|
w.Writefmtln("func (p *%vProvider) Check(", name)
|
|
w.Writefmtln(" ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {")
|
|
w.Writefmtln(" contract.Assert(resource.URN(req.GetUrn()).Type() == %vToken)", name)
|
|
w.Writefmtln(" obj, _, err := p.Unmarshal(req.GetProperties(), true)")
|
|
w.Writefmtln(" if obj == nil || err != nil {")
|
|
w.Writefmtln(" return plugin.NewCheckResponse(err), nil")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" var failures []error")
|
|
// check global properties:
|
|
w.Writefmtln(" if failure := p.ops.Check(ctx, obj, \"\"); failure != nil {")
|
|
w.Writefmtln(" failures = append(failures, failure)")
|
|
w.Writefmtln(" }")
|
|
// check each input property:
|
|
if hasinputs {
|
|
for _, opts := range propopts {
|
|
if !opts.Out {
|
|
w.Writefmtln(" if failure := p.ops.Check(ctx, obj, \"%v\"); failure != nil {", opts.Name)
|
|
w.Writefmtln(" failures = append(failures,")
|
|
w.Writefmtln(" resource.NewPropertyError(\"%v\", \"%v\", failure))", name, opts.Name)
|
|
w.Writefmtln(" }")
|
|
}
|
|
}
|
|
w.Writefmtln(" if len(failures) > 0 {")
|
|
w.Writefmtln(" return plugin.NewCheckResponse(resource.NewErrors(failures)), nil")
|
|
w.Writefmtln(" }")
|
|
}
|
|
w.Writefmtln(" return plugin.NewCheckResponse(nil), nil")
|
|
w.Writefmtln("}")
|
|
w.Writefmtln("")
|
|
w.Writefmtln("func (p *%vProvider) Create(", name)
|
|
w.Writefmtln(" ctx context.Context, req *lumirpc.CreateRequest) (*lumirpc.CreateResponse, error) {")
|
|
w.Writefmtln(" contract.Assert(resource.URN(req.GetUrn()).Type() == %vToken)", name)
|
|
w.Writefmtln(" obj, _, err := p.Unmarshal(req.GetProperties(), false)")
|
|
w.Writefmtln(" if err != nil {")
|
|
w.Writefmtln(" return nil, err")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" id, err := p.ops.Create(ctx, obj)")
|
|
w.Writefmtln(" if err != nil {")
|
|
w.Writefmtln(" return nil, err")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" props, err := plugin.MarshalProperties(")
|
|
w.Writefmtln(" resource.NewPropertyMap(obj), plugin.MarshalOptions{})")
|
|
w.Writefmtln(" if err != nil {")
|
|
w.Writefmtln(" return nil, err")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" return &lumirpc.CreateResponse{Id: string(id), Properties: props}, nil")
|
|
w.Writefmtln("}")
|
|
w.Writefmtln("")
|
|
w.Writefmtln("func (p *%vProvider) Diff(", name)
|
|
w.Writefmtln(" ctx context.Context, req *lumirpc.DiffRequest) (*lumirpc.DiffResponse, error) {")
|
|
w.Writefmtln(" contract.Assert(resource.URN(req.GetUrn()).Type() == %vToken)", name)
|
|
w.Writefmtln(" id := resource.ID(req.GetId())")
|
|
w.Writefmtln(" old, oldprops, err := p.Unmarshal(req.GetOlds(), false)")
|
|
w.Writefmtln(" if err != nil {")
|
|
w.Writefmtln(" return nil, err")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" new, newprops, err := p.Unmarshal(req.GetNews(), true)")
|
|
w.Writefmtln(" if new == nil || err != nil {")
|
|
w.Writefmtln(" return nil, err")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" var replaces []string")
|
|
w.Writefmtln(" diff := oldprops.Diff(newprops)")
|
|
w.Writefmtln(" if diff != nil {")
|
|
for _, opts := range propopts {
|
|
if opts.Replaces {
|
|
w.Writefmtln(" if diff.Changed(\"%v\") {", opts.Name)
|
|
w.Writefmtln(" replaces = append(replaces, \"%v\")", opts.Name)
|
|
w.Writefmtln(" }")
|
|
}
|
|
}
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" more, err := p.ops.Diff(ctx, id, old, new, diff)")
|
|
w.Writefmtln(" if err != nil {")
|
|
w.Writefmtln(" return nil, err")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" return &lumirpc.DiffResponse{")
|
|
w.Writefmtln(" Replaces: append(replaces, more...),")
|
|
w.Writefmtln(" }, err")
|
|
w.Writefmtln("}")
|
|
w.Writefmtln("")
|
|
w.Writefmtln("func (p *%vProvider) Update(", name)
|
|
w.Writefmtln(" ctx context.Context, req *lumirpc.UpdateRequest) (*lumirpc.UpdateResponse, error) {")
|
|
w.Writefmtln(" contract.Assert(resource.URN(req.GetUrn()).Type() == %vToken)", name)
|
|
w.Writefmtln(" id := resource.ID(req.GetId())")
|
|
w.Writefmtln(" old, oldprops, err := p.Unmarshal(req.GetOlds(), false)")
|
|
w.Writefmtln(" if err != nil {")
|
|
w.Writefmtln(" return nil, err")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" new, newprops, err := p.Unmarshal(req.GetNews(), false)")
|
|
w.Writefmtln(" if err != nil {")
|
|
w.Writefmtln(" return nil, err")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" diff := oldprops.Diff(newprops)")
|
|
w.Writefmtln(" if err := p.ops.Update(ctx, id, old, new, diff); err != nil {")
|
|
w.Writefmtln(" return nil, err")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" props, err := plugin.MarshalProperties(")
|
|
w.Writefmtln(" resource.NewPropertyMap(new), plugin.MarshalOptions{})")
|
|
w.Writefmtln(" if err != nil {")
|
|
w.Writefmtln(" return nil, err")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" return &lumirpc.UpdateResponse{Properties: props}, nil")
|
|
w.Writefmtln("}")
|
|
w.Writefmtln("")
|
|
w.Writefmtln("func (p *%vProvider) Delete(", name)
|
|
w.Writefmtln(" ctx context.Context, req *lumirpc.DeleteRequest) (*pbempty.Empty, error) {")
|
|
w.Writefmtln(" contract.Assert(resource.URN(req.GetUrn()).Type() == %vToken)", name)
|
|
w.Writefmtln(" id := resource.ID(req.GetId())")
|
|
w.Writefmtln(" obj, _, err := p.Unmarshal(req.GetProperties(), false)")
|
|
w.Writefmtln(" if err != nil {")
|
|
w.Writefmtln(" return nil, err")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" if err := p.ops.Delete(ctx, id, *obj); err != nil {")
|
|
w.Writefmtln(" return nil, err")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" return &pbempty.Empty{}, nil")
|
|
w.Writefmtln("}")
|
|
w.Writefmtln("")
|
|
w.Writefmtln("func (p *%vProvider) Unmarshal(", name)
|
|
w.Writefmtln(" v *pbstruct.Struct, allowUnknowns bool) (*%v, resource.PropertyMap, error) {", name)
|
|
w.Writefmtln(" opts := plugin.MarshalOptions{AllowUnknowns: allowUnknowns}")
|
|
w.Writefmtln(" props, err := plugin.UnmarshalProperties(v, opts)")
|
|
w.Writefmtln(" if err != nil {")
|
|
w.Writefmtln(" return nil, nil, err")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" if allowUnknowns && props.ContainsUnknowns() {")
|
|
w.Writefmtln(" return nil, props, nil")
|
|
w.Writefmtln(" }")
|
|
w.Writefmtln(" var obj %v", name)
|
|
w.Writefmtln(" return &obj, props, mapper.MapIU(props.Mappable(), &obj)")
|
|
w.Writefmtln("}")
|
|
w.Writefmtln("")
|
|
}
|
|
|
|
func (g *RPCGenerator) EmitStructType(w *tools.GenWriter, module tokens.Module, pkg *Package, t TypeMember) {
|
|
name := t.Name()
|
|
w.Writefmtln("/* Marshalable %v structure(s) */", name)
|
|
w.Writefmtln("")
|
|
|
|
props := t.Properties()
|
|
propopts := t.PropertyOptions()
|
|
w.Writefmtln("// %v is a marshalable representation of its corresponding IDL type.", name)
|
|
w.Writefmtln("type %v struct {", name)
|
|
for i, prop := range props {
|
|
opts := propopts[i]
|
|
// Make a JSON tag for this so we can serialize; note that outputs are always optional in this position.
|
|
jsontag := makeLumiTag(opts)
|
|
w.Writefmtln(" %v %v %v",
|
|
prop.Name(), g.GenTypeName(prop.Type(), opts.Optional || opts.In || opts.Out), jsontag)
|
|
}
|
|
w.Writefmtln("}")
|
|
w.Writefmtln("")
|
|
|
|
if len(props) > 0 {
|
|
w.Writefmtln("// %v's properties have constants to make dealing with diffs and property bags easier.", name)
|
|
w.Writefmtln("const (")
|
|
for i, prop := range props {
|
|
opts := propopts[i]
|
|
w.Writefmtln(" %v_%v = \"%v\"", name, prop.Name(), opts.Name)
|
|
}
|
|
w.Writefmtln(")")
|
|
w.Writefmtln("")
|
|
}
|
|
}
|
|
|
|
// makeLumiTag turns a set of property options into a serializable JSON tag.
|
|
func makeLumiTag(opts PropertyOptions) string {
|
|
var flags string
|
|
if opts.Optional || opts.In || opts.Out {
|
|
flags = ",optional"
|
|
}
|
|
return fmt.Sprintf("`pulumi:\"%v%v\"`", opts.Name, flags)
|
|
}
|
|
|
|
func (g *RPCGenerator) GenTypeName(t types.Type, opt bool) string {
|
|
switch u := t.(type) {
|
|
case *types.Basic:
|
|
switch k := u.Kind(); k {
|
|
case types.Bool:
|
|
return "bool"
|
|
case types.String:
|
|
return "string"
|
|
case types.Float64:
|
|
return "float64"
|
|
default:
|
|
contract.Failf("Unrecognized GenTypeName basic type: %v", k)
|
|
}
|
|
case *types.Interface:
|
|
return "interface{}"
|
|
case *types.Named:
|
|
obj := u.Obj()
|
|
// For resource types, simply emit an ID, since that is what will have been serialized.
|
|
if IsResource(obj, u) {
|
|
return "resource.ID"
|
|
}
|
|
|
|
// For references to the special predefined types, use the runtime provider representation.
|
|
if spec, kind := IsSpecial(obj); spec {
|
|
switch kind {
|
|
case SpecialArchiveType:
|
|
return "resource.Archive"
|
|
case SpecialAssetType:
|
|
return "resource.Asset"
|
|
default:
|
|
contract.Failf("Unexpected special kind: %v", kind)
|
|
}
|
|
}
|
|
|
|
// Otherwise, see how to reference the type, based on imports.
|
|
pkg := obj.Pkg()
|
|
name := obj.Name()
|
|
|
|
// If this came from the same package, Go can access it without qualification.
|
|
if pkg == g.CurrPkg.Pkginfo.Pkg {
|
|
return name
|
|
}
|
|
|
|
// Otherwise, we will need to refer to a qualified import name.
|
|
impname := g.registerImport(pkg)
|
|
return fmt.Sprintf("%v.%v", impname, name)
|
|
case *types.Map:
|
|
return fmt.Sprintf("map[%v]%v", g.GenTypeName(u.Key(), false), g.GenTypeName(u.Elem(), false))
|
|
case *types.Pointer:
|
|
// If this isn't an optional property, and the underlying type is a resource or special type, unpointerize it.
|
|
elem := u.Elem()
|
|
unptr := false
|
|
if !opt {
|
|
if elnm, iselnm := elem.(*types.Named); iselnm {
|
|
if IsResource(elnm.Obj(), elnm) {
|
|
unptr = true
|
|
} else if spec, _ := IsSpecial(elnm.Obj()); spec {
|
|
unptr = true
|
|
}
|
|
}
|
|
}
|
|
if unptr {
|
|
return g.GenTypeName(elem, false)
|
|
}
|
|
return fmt.Sprintf("*%v", g.GenTypeName(u.Elem(), false))
|
|
case *types.Slice:
|
|
return fmt.Sprintf("[]%v", g.GenTypeName(u.Elem(), false)) // postfix syntax for arrays.
|
|
default:
|
|
contract.Failf("Unrecognized GenTypeName type: %v", reflect.TypeOf(u))
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// registerImport registers that we have seen a foreign package and requests that the imports be emitted for it.
|
|
func (g *RPCGenerator) registerImport(pkg *types.Package) string {
|
|
path := pkg.Path()
|
|
if impname, has := g.FileImports[path]; has {
|
|
return impname
|
|
}
|
|
|
|
// If we haven't seen this yet, allocate an import name for it. For now, we just use the package name with two
|
|
// leading underscores, to avoid accidental collisions with other names in the file.
|
|
name := "__" + pkg.Name()
|
|
g.FileImports[path] = name
|
|
return name
|
|
}
|
|
|
|
func (g *RPCGenerator) EmitTypedefs(w *tools.GenWriter, typedefs []Typedef) {
|
|
w.Writefmtln("/* Typedefs */")
|
|
w.Writefmtln("")
|
|
|
|
w.Writefmtln("type (")
|
|
for _, td := range typedefs {
|
|
w.Writefmtln(" %v %v", td.Name(), td.Target())
|
|
}
|
|
w.Writefmtln(")")
|
|
|
|
w.Writefmtln("")
|
|
}
|
|
|
|
func (g *RPCGenerator) EmitConstants(w *tools.GenWriter, consts []*Const) {
|
|
w.Writefmtln("/* Constants */")
|
|
w.Writefmtln("")
|
|
|
|
w.Writefmtln("const (")
|
|
for _, konst := range consts {
|
|
w.Writefmtln(" %v %v = %v", konst.Name(), g.GenTypeName(konst.Type, false), konst.Value)
|
|
}
|
|
w.Writefmtln(")")
|
|
|
|
w.Writefmtln("")
|
|
}
|