1 // Go support for Protocol Buffers - Google's data interchange format
3 // Copyright 2010 Google Inc. All rights reserved.
4 // http://code.google.com/p/goprotobuf/
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
10 // * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following disclaimer
14 // in the documentation and/or other materials provided with the
16 // * Neither the name of Google Inc. nor the names of its
17 // contributors may be used to endorse or promote products derived from
18 // this software without specific prior written permission.
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 The code generator for the plugin for the Google protocol buffer compiler.
34 It generates Go code from the protocol buffer description files read by the
51 "goprotobuf.googlecode.com/hg/proto"
52 plugin "goprotobuf.googlecode.com/hg/compiler/plugin"
53 descriptor "goprotobuf.googlecode.com/hg/compiler/descriptor"
56 // A Plugin provides functionality to add to the output during Go code generation,
57 // such as to produce RPC stubs.
58 type Plugin interface {
59 // Name identifies the plugin.
61 // Init is called once after data structures are built but before
62 // code generation begins.
64 // Generate produces the code generated by the plugin for this file,
65 // except for the imports, by calling the generator's methods P, In, and Out.
66 Generate(file *FileDescriptor)
67 // GenerateImports produces the import declarations for this file.
68 // It is called after Generate.
69 GenerateImports(file *FileDescriptor)
74 // RegisterPlugin installs a (second-order) plugin to be run when the Go output is generated.
75 // It is typically called during initialization.
76 func RegisterPlugin(p Plugin) {
77 plugins = append(plugins, p)
80 // Each type we import as a protocol buffer (other than FileDescriptorProto) needs
81 // a pointer to the FileDescriptorProto that represents it. These types achieve that
82 // wrapping by placing each Proto inside a struct with the pointer to its File. The
83 // structs have the same names as their contents, with "Proto" removed.
84 // FileDescriptor is used to store the things that it points to.
86 // The file and package name method are common to messages and enums.
88 file *descriptor.FileDescriptorProto // File this object comes from.
91 // PackageName is name in the package clause in the generated file.
92 func (c *common) PackageName() string { return uniquePackageOf(c.file) }
94 func (c *common) File() *descriptor.FileDescriptorProto { return c.file }
96 // Descriptor represents a protocol buffer message.
97 type Descriptor struct {
99 *descriptor.DescriptorProto
100 parent *Descriptor // The containing message, if any.
101 nested []*Descriptor // Inner messages, if any.
102 ext []*ExtensionDescriptor // Extensions, if any.
103 typename []string // Cached typename vector.
106 // TypeName returns the elements of the dotted type name.
107 // The package name is not part of this name.
108 func (d *Descriptor) TypeName() []string {
109 if d.typename != nil {
113 for parent := d; parent != nil; parent = parent.parent {
116 s := make([]string, n, n)
117 for parent := d; parent != nil; parent = parent.parent {
119 s[n] = proto.GetString(parent.Name)
125 // EnumDescriptor describes an enum. If it's at top level, its parent will be nil.
126 // Otherwise it will be the descriptor of the message in which it is defined.
127 type EnumDescriptor struct {
129 *descriptor.EnumDescriptorProto
130 parent *Descriptor // The containing message, if any.
131 typename []string // Cached typename vector.
134 // TypeName returns the elements of the dotted type name.
135 // The package name is not part of this name.
136 func (e *EnumDescriptor) TypeName() (s []string) {
137 if e.typename != nil {
140 name := proto.GetString(e.Name)
142 s = make([]string, 1)
144 pname := e.parent.TypeName()
145 s = make([]string, len(pname)+1)
153 // Everything but the last element of the full type name, CamelCased.
154 // The values of type Foo.Bar are call Foo_value1... not Foo_Bar_value1... .
155 func (e *EnumDescriptor) prefix() string {
156 typeName := e.TypeName()
157 ccPrefix := CamelCaseSlice(typeName[0:len(typeName)-1]) + "_"
159 // If the enum is not part of a message, the prefix is just the type name.
160 ccPrefix = CamelCase(*e.Name) + "_"
165 // The integer value of the named constant in this enumerated type.
166 func (e *EnumDescriptor) integerValueAsString(name string) string {
167 for _, c := range e.Value {
168 if proto.GetString(c.Name) == name {
169 return fmt.Sprint(proto.GetInt32(c.Number))
172 log.Fatal("cannot find value for enum constant")
176 // ExtensionDescriptor describes an extension. If it's at top level, its parent will be nil.
177 // Otherwise it will be the descriptor of the message in which it is defined.
178 type ExtensionDescriptor struct {
180 *descriptor.FieldDescriptorProto
181 parent *Descriptor // The containing message, if any.
184 // TypeName returns the elements of the dotted type name.
185 // The package name is not part of this name.
186 func (e *ExtensionDescriptor) TypeName() (s []string) {
187 name := proto.GetString(e.Name)
189 // top-level extension
190 s = make([]string, 1)
192 pname := e.parent.TypeName()
193 s = make([]string, len(pname)+1)
200 // DescName returns the variable name used for the generated descriptor.
201 func (e *ExtensionDescriptor) DescName() string {
202 // The full type name.
203 typeName := e.TypeName()
204 // Each scope of the extension is individually CamelCased, and all are joined with "_" with an "E_" prefix.
205 for i, s := range typeName {
206 typeName[i] = CamelCase(s)
208 return "E_" + strings.Join(typeName, "_")
211 // ImportedDescriptor describes a type that has been publicly imported from another file.
212 type ImportedDescriptor struct {
217 func (id *ImportedDescriptor) TypeName() []string { return id.o.TypeName() }
219 // FileDescriptor describes an protocol buffer descriptor file (.proto).
220 // It includes slices of all the messages and enums defined within it.
221 // Those slices are constructed by WrapTypes.
222 type FileDescriptor struct {
223 *descriptor.FileDescriptorProto
224 desc []*Descriptor // All the messages defined in this file.
225 enum []*EnumDescriptor // All the enums defined in this file.
226 ext []*ExtensionDescriptor // All the top-level extensions defined in this file.
227 imp []*ImportedDescriptor // All types defined in files publicly imported by this file.
229 // The full list of symbols that are exported,
230 // as a map from the exported object to its symbols.
231 // This is used for supporting public imports.
232 exported map[Object][]Symbol
235 // PackageName is the package name we'll use in the generated code to refer to this file.
236 func (d *FileDescriptor) PackageName() string { return uniquePackageOf(d.FileDescriptorProto) }
238 // The package named defined in the input for this file, possibly dotted.
239 // If the file does not define a package, use the base of the file name.
240 func (d *FileDescriptor) originalPackageName() string {
241 // Does the file have a package clause?
242 if pkg := proto.GetString(d.Package); pkg != "" {
245 // Use the file base name.
246 return BaseName(proto.GetString(d.Name))
249 func (d *FileDescriptor) addExport(obj Object, symbol Symbol) {
250 d.exported[obj] = append(d.exported[obj], symbol)
253 // Symbol is an interface representing an exported Go symbol.
254 type Symbol interface {
255 // GenerateAlias should generate an appropriate alias
256 // for the symbol from the named package.
257 GenerateAlias(g *Generator, pkg string)
260 type messageSymbol struct {
262 hasExtensions, isMessageSet bool
265 func (ms messageSymbol) GenerateAlias(g *Generator, pkg string) {
266 remoteSym := pkg + "." + ms.sym
268 g.P("type ", ms.sym, " ", remoteSym)
269 g.P("func (this *", ms.sym, ") Reset() { (*", remoteSym, ")(this).Reset() }")
270 g.P("func (this *", ms.sym, ") String() string { return (*", remoteSym, ")(this).String() }")
271 if ms.hasExtensions {
272 g.P("func (*", ms.sym, ") ExtensionRangeArray() []", g.ProtoPkg, ".ExtensionRange ",
273 "{ return (*", remoteSym, ")(nil).ExtensionRangeArray() }")
274 g.P("func (this *", ms.sym, ") ExtensionMap() map[int32]", g.ProtoPkg, ".Extension ",
275 "{ return (*", remoteSym, ")(this).ExtensionMap() }")
277 g.P("func (this *", ms.sym, ") Marshal() ([]byte, os.Error) ",
278 "{ return (*", remoteSym, ")(this).Marshal() }")
279 g.P("func (this *", ms.sym, ") Unmarshal(buf []byte) os.Error ",
280 "{ return (*", remoteSym, ")(this).Unmarshal(buf) }")
285 type enumSymbol string
287 func (es enumSymbol) GenerateAlias(g *Generator, pkg string) {
289 g.P("type ", s, " ", pkg, ".", s)
290 g.P("var ", s, "_name = ", pkg, ".", s, "_name")
291 g.P("var ", s, "_value = ", pkg, ".", s, "_value")
292 g.P("func New", s, "(x ", s, ") *", s, " { e := ", s, "(x); return &e }")
295 type constOrVarSymbol struct {
297 typ string // either "const" or "var"
300 func (cs constOrVarSymbol) GenerateAlias(g *Generator, pkg string) {
301 g.P(cs.typ, " ", cs.sym, " = ", pkg, ".", cs.sym)
304 // Object is an interface abstracting the abilities shared by enums, messages, extensions and imported objects.
305 type Object interface {
306 PackageName() string // The name we use in our output (a_b_c), possibly renamed for uniqueness.
308 File() *descriptor.FileDescriptorProto
311 // Each package name we generate must be unique. The package we're generating
312 // gets its own name but every other package must have a unique name that does
313 // not conflict in the code we generate. These names are chosen globally (although
314 // they don't have to be, it simplifies things to do them globally).
315 func uniquePackageOf(fd *descriptor.FileDescriptorProto) string {
316 s, ok := uniquePackageName[fd]
318 log.Fatal("internal error: no package name defined for", proto.GetString(fd.Name))
323 // Generator is the type whose methods generate the output, stored in the associated response structure.
324 type Generator struct {
327 Request *plugin.CodeGeneratorRequest // The input.
328 Response *plugin.CodeGeneratorResponse // The output.
330 Param map[string]string // Command-line parameters.
331 ImportPrefix string // String to prefix to imported package file names.
332 ImportMap map[string]string // Mapping from import name to generated name
334 ProtoPkg string // The name under which we import the library's package proto.
336 packageName string // What we're calling ourselves.
337 allFiles []*FileDescriptor // All files in the tree
338 genFiles []*FileDescriptor // Those files we will generate output for.
339 file *FileDescriptor // The file we are compiling now.
340 usedPackages map[string]bool // Names of packages used in current file.
341 typeNameToObject map[string]Object // Key is a fully-qualified name in input syntax.
345 // New creates a new generator and allocates the request and response protobufs.
346 func New() *Generator {
348 g.Buffer = new(bytes.Buffer)
349 g.Request = new(plugin.CodeGeneratorRequest)
350 g.Response = new(plugin.CodeGeneratorResponse)
354 // Error reports a problem, including an os.Error, and exits the program.
355 func (g *Generator) Error(err os.Error, msgs ...string) {
356 s := strings.Join(msgs, " ") + ":" + err.String()
357 log.Println("protoc-gen-go: error:", s)
358 g.Response.Error = proto.String(s)
362 // Fail reports a problem and exits the program.
363 func (g *Generator) Fail(msgs ...string) {
364 s := strings.Join(msgs, " ")
365 log.Println("protoc-gen-go: error:", s)
366 g.Response.Error = proto.String(s)
370 // CommandLineParameters breaks the comma-separated list of key=value pairs
371 // in the parameter (a member of the request protobuf) into a key/value map.
372 // It then sets file name mappings defined by those entries.
373 func (g *Generator) CommandLineParameters(parameter string) {
374 g.Param = make(map[string]string)
375 for _, p := range strings.Split(parameter, ",") {
376 if i := strings.Index(p, "="); i < 0 {
379 g.Param[p[0:i]] = p[i+1:]
383 g.ImportMap = make(map[string]string)
384 for k, v := range g.Param {
385 if k == "import_prefix" {
387 } else if len(k) > 0 && k[0] == 'M' {
388 g.ImportMap[k[1:]] = v
393 // DefaultPackageName returns the package name printed for the object.
394 // If its file is in a different package, it returns the package name we're using for this file, plus ".".
395 // Otherwise it returns the empty string.
396 func (g *Generator) DefaultPackageName(obj Object) string {
397 pkg := obj.PackageName()
398 if pkg == g.packageName {
404 // For each input file, the unique package name to use, underscored.
405 var uniquePackageName = make(map[*descriptor.FileDescriptorProto]string)
406 // Package names already registered. Key is the name from the .proto file;
407 // value is the name that appears in the generated code.
408 var pkgNamesInUse = make(map[string]bool)
410 // Create and remember a guaranteed unique package name for this file descriptor.
411 // Pkg is the candidate name. If f is nil, it's a builtin package like "proto" and
412 // has no file descriptor.
413 func RegisterUniquePackageName(pkg string, f *FileDescriptor) string {
414 // Convert dots to underscores before finding a unique alias.
415 pkg = strings.Map(DotToUnderscore, pkg)
417 for i, orig := 1, pkg; pkgNamesInUse[pkg]; i++ {
418 // It's a duplicate; must rename.
419 pkg = orig + strconv.Itoa(i)
422 pkgNamesInUse[pkg] = true
424 uniquePackageName[f.FileDescriptorProto] = pkg
429 // SetPackageNames sets the package name for this run.
430 // The package name must agree across all files being generated.
431 // It also defines unique package names for all imported files.
432 func (g *Generator) SetPackageNames() {
433 // Register the name for this package. It will be the first name
434 // registered so is guaranteed to be unmodified.
435 pkg := g.genFiles[0].originalPackageName()
436 g.packageName = RegisterUniquePackageName(pkg, g.genFiles[0])
437 // Register the proto package name. It might collide with the
438 // name of a package we import.
439 g.ProtoPkg = RegisterUniquePackageName("proto", nil)
440 // Verify that we are generating output for a single package.
441 for _, f := range g.genFiles {
442 thisPkg := f.originalPackageName()
444 g.Fail("inconsistent package names:", thisPkg, pkg)
448 for _, f := range g.allFiles {
449 for _, genf := range g.genFiles {
451 // In this package already.
452 uniquePackageName[f.FileDescriptorProto] = g.packageName
456 // The file is a dependency, so we want to ignore its go_package option
457 // because that is only relevant for its specific generated output.
458 pkg := proto.GetString(f.Package)
460 pkg = BaseName(*f.Name)
462 RegisterUniquePackageName(pkg, f)
466 // WrapTypes walks the incoming data, wrapping DescriptorProtos, EnumDescriptorProtos
467 // and FileDescriptorProtos into file-referenced objects within the Generator.
468 // It also creates the list of files to generate and so should be called before GenerateAllFiles.
469 func (g *Generator) WrapTypes() {
470 g.allFiles = make([]*FileDescriptor, len(g.Request.ProtoFile))
471 for i, f := range g.Request.ProtoFile {
472 // We must wrap the descriptors before we wrap the enums
473 descs := wrapDescriptors(f)
474 g.buildNestedDescriptors(descs)
475 enums := wrapEnumDescriptors(f, descs)
476 exts := wrapExtensions(f)
477 imps := wrapImported(f, g)
478 g.allFiles[i] = &FileDescriptor{
479 FileDescriptorProto: f,
484 exported: make(map[Object][]Symbol),
488 g.genFiles = make([]*FileDescriptor, len(g.Request.FileToGenerate))
490 for i, fileName := range g.Request.FileToGenerate {
491 // Search the list. This algorithm is n^2 but n is tiny.
492 for _, file := range g.allFiles {
493 if fileName == proto.GetString(file.Name) {
498 g.Fail("could not find file named", fileName)
500 g.Response.File = make([]*plugin.CodeGeneratorResponse_File, len(g.genFiles))
503 // Scan the descriptors in this file. For each one, build the slice of nested descriptors
504 func (g *Generator) buildNestedDescriptors(descs []*Descriptor) {
505 for _, desc := range descs {
506 if len(desc.NestedType) != 0 {
507 desc.nested = make([]*Descriptor, len(desc.NestedType))
509 for _, nest := range descs {
510 if nest.parent == desc {
511 desc.nested[n] = nest
515 if n != len(desc.NestedType) {
516 g.Fail("internal error: nesting failure for", proto.GetString(desc.Name))
522 // Construct the Descriptor and add it to the slice
523 func addDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto) []*Descriptor {
524 d := &Descriptor{common{file}, desc, parent, nil, nil, nil}
526 d.ext = make([]*ExtensionDescriptor, len(desc.Extension))
527 for i, field := range desc.Extension {
528 d.ext[i] = &ExtensionDescriptor{common{file}, field, d}
534 // Return a slice of all the Descriptors defined within this file
535 func wrapDescriptors(file *descriptor.FileDescriptorProto) []*Descriptor {
536 sl := make([]*Descriptor, 0, len(file.MessageType)+10)
537 for _, desc := range file.MessageType {
538 sl = wrapThisDescriptor(sl, desc, nil, file)
543 // Wrap this Descriptor, recursively
544 func wrapThisDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto) []*Descriptor {
545 sl = addDescriptor(sl, desc, parent, file)
547 for _, nested := range desc.NestedType {
548 sl = wrapThisDescriptor(sl, nested, me, file)
553 // Construct the EnumDescriptor and add it to the slice
554 func addEnumDescriptor(sl []*EnumDescriptor, desc *descriptor.EnumDescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto) []*EnumDescriptor {
555 return append(sl, &EnumDescriptor{common{file}, desc, parent, nil})
558 // Return a slice of all the EnumDescriptors defined within this file
559 func wrapEnumDescriptors(file *descriptor.FileDescriptorProto, descs []*Descriptor) []*EnumDescriptor {
560 sl := make([]*EnumDescriptor, 0, len(file.EnumType)+10)
562 for _, enum := range file.EnumType {
563 sl = addEnumDescriptor(sl, enum, nil, file)
565 // Enums within messages. Enums within embedded messages appear in the outer-most message.
566 for _, nested := range descs {
567 for _, enum := range nested.EnumType {
568 sl = addEnumDescriptor(sl, enum, nested, file)
574 // Return a slice of all the top-level ExtensionDescriptors defined within this file.
575 func wrapExtensions(file *descriptor.FileDescriptorProto) []*ExtensionDescriptor {
576 sl := make([]*ExtensionDescriptor, len(file.Extension))
577 for i, field := range file.Extension {
578 sl[i] = &ExtensionDescriptor{common{file}, field, nil}
583 // Return a slice of all the types that are publicly imported into this file.
584 func wrapImported(file *descriptor.FileDescriptorProto, g *Generator) (sl []*ImportedDescriptor) {
585 for _, index := range file.PublicDependency {
586 df := g.fileByName(file.Dependency[index])
587 for _, d := range df.desc {
588 sl = append(sl, &ImportedDescriptor{common{file}, d})
590 for _, e := range df.enum {
591 sl = append(sl, &ImportedDescriptor{common{file}, e})
593 for _, ext := range df.ext {
594 sl = append(sl, &ImportedDescriptor{common{file}, ext})
600 // BuildTypeNameMap builds the map from fully qualified type names to objects.
601 // The key names for the map come from the input data, which puts a period at the beginning.
602 // It should be called after SetPackageNames and before GenerateAllFiles.
603 func (g *Generator) BuildTypeNameMap() {
604 g.typeNameToObject = make(map[string]Object)
605 for _, f := range g.allFiles {
606 // The names in this loop are defined by the proto world, not us, so the
607 // package name may be empty. If so, the dotted package name of X will
608 // be ".X"; otherwise it will be ".pkg.X".
609 dottedPkg := "." + proto.GetString(f.Package)
610 if dottedPkg != "." {
613 for _, enum := range f.enum {
614 name := dottedPkg + dottedSlice(enum.TypeName())
615 g.typeNameToObject[name] = enum
617 for _, desc := range f.desc {
618 name := dottedPkg + dottedSlice(desc.TypeName())
619 g.typeNameToObject[name] = desc
624 // ObjectNamed, given a fully-qualified input type name as it appears in the input data,
625 // returns the descriptor for the message or enum with that name.
626 func (g *Generator) ObjectNamed(typeName string) Object {
627 o, ok := g.typeNameToObject[typeName]
629 g.Fail("can't find object with type", typeName)
632 // If the file of this object isn't a direct dependency of the current file,
633 // or in the current file, then this object has been publicly imported into
634 // a dependency of the current file.
635 // We should return the ImportedDescriptor object for it instead.
636 direct := *o.File().Name == *g.file.Name
638 for _, dep := range g.file.Dependency {
639 if *g.fileByName(dep).Name == *o.File().Name {
648 for _, dep := range g.file.Dependency {
649 df := g.fileByName(*g.fileByName(dep).Name)
650 for _, td := range df.imp {
660 log.Printf("protoc-gen-go: WARNING: failed finding publicly imported dependency for %v, used in %v", typeName, *g.file.Name)
667 // P prints the arguments to the generated output. It handles strings and int32s, plus
668 // handling indirections because they may be *string, etc.
669 func (g *Generator) P(str ...interface{}) {
670 g.WriteString(g.indent)
671 for _, v := range str {
672 switch s := v.(type) {
678 g.WriteString(fmt.Sprintf("%t", s))
680 g.WriteString(fmt.Sprintf("%t", *s))
682 g.WriteString(fmt.Sprintf("%d", *s))
684 g.WriteString(fmt.Sprintf("%g", s))
686 g.WriteString(fmt.Sprintf("%g", *s))
688 g.Fail(fmt.Sprintf("unknown type in printer: %T", v))
694 // In Indents the output one tab stop.
695 func (g *Generator) In() { g.indent += "\t" }
697 // Out unindents the output one tab stop.
698 func (g *Generator) Out() {
699 if len(g.indent) > 0 {
700 g.indent = g.indent[1:]
704 // GenerateAllFiles generates the output for all the files we're outputting.
705 func (g *Generator) GenerateAllFiles() {
706 // Initialize the plugins
707 for _, p := range plugins {
710 // Generate the output. The generator runs for every file, even the files
711 // that we don't generate output for, so that we can collate the full list
712 // of exported symbols to support public imports.
713 genFileMap := make(map[*FileDescriptor]bool, len(g.genFiles))
714 for _, file := range g.genFiles {
715 genFileMap[file] = true
718 for _, file := range g.allFiles {
721 if _, ok := genFileMap[file]; !ok {
724 g.Response.File[i] = new(plugin.CodeGeneratorResponse_File)
725 g.Response.File[i].Name = proto.String(goFileName(*file.Name))
726 g.Response.File[i].Content = proto.String(g.String())
731 // Run all the plugins associated with the file.
732 func (g *Generator) runPlugins(file *FileDescriptor) {
733 for _, p := range plugins {
738 // FileOf return the FileDescriptor for this FileDescriptorProto.
739 func (g *Generator) FileOf(fd *descriptor.FileDescriptorProto) *FileDescriptor {
740 for _, file := range g.allFiles {
741 if file.FileDescriptorProto == fd {
745 g.Fail("could not find file in table:", proto.GetString(fd.Name))
749 // Fill the response protocol buffer with the generated output for all the files we're
750 // supposed to generate.
751 func (g *Generator) generate(file *FileDescriptor) {
752 g.file = g.FileOf(file.FileDescriptorProto)
753 g.usedPackages = make(map[string]bool)
755 for _, td := range g.file.imp {
756 g.generateImported(td)
758 for _, enum := range g.file.enum {
761 for _, desc := range g.file.desc {
762 g.generateMessage(desc)
764 for _, ext := range g.file.ext {
765 g.generateExtension(ext)
767 g.generateInitFunction()
769 // Run the plugins before the imports so we know which imports are necessary.
772 // Generate header and imports last, though they appear first in the output.
774 g.Buffer = new(bytes.Buffer)
779 // Reformat generated code.
780 fset := token.NewFileSet()
781 ast, err := parser.ParseFile(fset, "", g, parser.ParseComments)
783 g.Fail("bad Go source code was generated:", err.String())
787 _, err = (&printer.Config{printer.TabIndent | printer.UseSpaces, 8}).Fprint(g, fset, ast)
789 g.Fail("generated Go source code could not be reformatted:", err.String())
793 // Generate the header, including package definition and imports
794 func (g *Generator) generateHeader() {
795 g.P("// Code generated by protoc-gen-go from ", Quote(*g.file.Name))
796 g.P("// DO NOT EDIT!")
798 g.P("package ", g.file.PackageName())
802 func (g *Generator) fileByName(filename string) *FileDescriptor {
803 for _, fd := range g.allFiles {
804 if proto.GetString(fd.Name) == filename {
811 // Generate the header, including package definition and imports
812 func (g *Generator) generateImports() {
813 // We almost always need a proto import. Rather than computing when we
814 // do, which is tricky when there's a plugin, just import it and
815 // reference it later. The same argument applies to the os package.
816 g.P("import " + g.ProtoPkg + " " + Quote(g.ImportPrefix+"goprotobuf.googlecode.com/hg/proto"))
819 for _, s := range g.file.Dependency {
820 fd := g.fileByName(s)
821 // Do not import our own package.
822 if fd.PackageName() == g.packageName {
825 filename := goFileName(s)
826 if substitution, ok := g.ImportMap[s]; ok {
827 filename = substitution
829 filename = g.ImportPrefix + filename
830 if strings.HasSuffix(filename, ".go") {
831 filename = filename[0 : len(filename)-3]
833 if _, ok := g.usedPackages[fd.PackageName()]; ok {
834 g.P("import ", fd.PackageName(), " ", Quote(filename))
836 // TODO: Re-enable this when we are more feature-complete.
837 // For instance, some protos use foreign field extensions, which we don't support.
838 // Until then, this is just annoying spam.
839 //log.Printf("protoc-gen-go: discarding unused import from %v: %v", *g.file.Name, s)
840 g.P("// discarding unused import ", fd.PackageName(), " ", Quote(filename))
844 // TODO: may need to worry about uniqueness across plugins
845 for _, p := range plugins {
846 p.GenerateImports(g.file)
849 g.P("// Reference proto, math & os imports to suppress error if they are not otherwise used.")
850 g.P("var _ = ", g.ProtoPkg, ".GetString")
851 g.P("var _ = math.Inf")
852 g.P("var _ os.Error")
856 func (g *Generator) generateImported(id *ImportedDescriptor) {
857 // Don't generate public import symbols for files that we are generating
858 // code for, since those symbols will already be in this package.
859 // We can't simply avoid creating the ImportedDescriptor objects,
860 // because g.genFiles isn't populated at that stage.
863 df := g.FileOf(id.o.File())
865 for _, fd := range g.genFiles {
866 if *fd.Name == filename {
867 g.P("// Ignoring public import of ", sn, " from ", filename)
872 g.P("// ", sn, " from public import ", filename)
873 g.usedPackages[df.PackageName()] = true
875 for _, sym := range df.exported[id.o] {
876 sym.GenerateAlias(g, df.PackageName())
882 // Generate the enum definitions for this EnumDescriptor.
883 func (g *Generator) generateEnum(enum *EnumDescriptor) {
884 // The full type name
885 typeName := enum.TypeName()
886 // The full type name, CamelCased.
887 ccTypeName := CamelCaseSlice(typeName)
888 ccPrefix := enum.prefix()
889 g.P("type ", ccTypeName, " int32")
890 g.file.addExport(enum, enumSymbol(ccTypeName))
893 for _, e := range enum.Value {
894 name := ccPrefix + *e.Name
895 g.P(name, " ", ccTypeName, " = ", e.Number)
896 g.file.addExport(enum, constOrVarSymbol{name, "const"})
900 g.P("var ", ccTypeName, "_name = map[int32]string{")
902 generated := make(map[int32]bool) // avoid duplicate values
903 for _, e := range enum.Value {
905 if _, present := generated[*e.Number]; present {
906 duplicate = "// Duplicate value: "
908 g.P(duplicate, e.Number, ": ", Quote(*e.Name), ",")
909 generated[*e.Number] = true
913 g.P("var ", ccTypeName, "_value = map[string]int32{")
915 for _, e := range enum.Value {
916 g.P(Quote(*e.Name), ": ", e.Number, ",")
921 g.P("func New", ccTypeName, "(x ", ccTypeName, ") *", ccTypeName, " {")
923 g.P("e := ", ccTypeName, "(x)")
928 g.P("func (x ", ccTypeName, ") String() string {")
930 g.P("return ", g.ProtoPkg, ".EnumName(", ccTypeName, "_name, int32(x))")
937 // The tag is a string like "varint,2,opt,name=fieldname,def=7" that
938 // identifies details of the field for the protocol buffer marshaling and unmarshaling
939 // code. The fields are:
941 // protocol tag number
942 // opt,req,rep for optional, required, or repeated
943 // packed whether the encoding is "packed" (optional; repeated primitives only)
944 // name= the original declared name
945 // enum= the name of the enum type if it is an enum-typed field.
946 // def= string representation of the default value, if any.
947 // The default value must be in a representation that can be used at run-time
948 // to generate the default value. Thus bools become 0 and 1, for instance.
949 func (g *Generator) goTag(field *descriptor.FieldDescriptorProto, wiretype string) string {
952 case isOptional(field):
954 case isRequired(field):
956 case isRepeated(field):
959 defaultValue := proto.GetString(field.DefaultValue)
960 if defaultValue != "" {
962 case descriptor.FieldDescriptorProto_TYPE_BOOL:
963 if defaultValue == "true" {
968 case descriptor.FieldDescriptorProto_TYPE_STRING,
969 descriptor.FieldDescriptorProto_TYPE_BYTES:
970 // Nothing to do. Quoting is done for the whole tag.
971 case descriptor.FieldDescriptorProto_TYPE_ENUM:
972 // For enums we need to provide the integer constant.
973 obj := g.ObjectNamed(proto.GetString(field.TypeName))
974 enum, ok := obj.(*EnumDescriptor)
976 g.Fail("enum type inconsistent for", CamelCaseSlice(obj.TypeName()))
978 defaultValue = enum.integerValueAsString(defaultValue)
980 defaultValue = ",def=" + defaultValue
983 if *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM {
984 // We avoid using obj.PackageName(), because we want to use the
985 // original (proto-world) package name.
986 obj := g.ObjectNamed(proto.GetString(field.TypeName))
988 if pkg := proto.GetString(obj.File().Package); pkg != "" {
991 enum += CamelCaseSlice(obj.TypeName())
994 if field.Options != nil && proto.GetBool(field.Options.Packed) {
997 fieldName := proto.GetString(field.Name)
999 if *field.Type == descriptor.FieldDescriptorProto_TYPE_GROUP {
1000 // We must use the type name for groups instead of
1001 // the field name to preserve capitalization.
1002 // type_name in FieldDescriptorProto is fully-qualified,
1003 // but we only want the local part.
1004 name = *field.TypeName
1005 if i := strings.LastIndex(name, "."); i >= 0 {
1009 if name == CamelCase(fieldName) {
1012 name = ",name=" + name
1014 return Quote(fmt.Sprintf("%s,%d,%s%s%s%s%s",
1016 proto.GetInt32(field.Number),
1024 func needsStar(typ descriptor.FieldDescriptorProto_Type) bool {
1026 case descriptor.FieldDescriptorProto_TYPE_GROUP:
1028 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
1030 case descriptor.FieldDescriptorProto_TYPE_BYTES:
1036 // TypeName is the printed name appropriate for an item. If the object is in the current file,
1037 // TypeName drops the package name and underscores the rest.
1038 // Otherwise the object is from another package; and the result is the underscored
1039 // package name followed by the item name.
1040 // The result always has an initial capital.
1041 func (g *Generator) TypeName(obj Object) string {
1042 return g.DefaultPackageName(obj) + CamelCaseSlice(obj.TypeName())
1045 // TypeNameWithPackage is like TypeName, but always includes the package
1046 // name even if the object is in our own package.
1047 func (g *Generator) TypeNameWithPackage(obj Object) string {
1048 return obj.PackageName() + CamelCaseSlice(obj.TypeName())
1051 // GoType returns a string representing the type name, and the wire type
1052 func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto) (typ string, wire string) {
1054 switch *field.Type {
1055 case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
1056 typ, wire = "float64", "fixed64"
1057 case descriptor.FieldDescriptorProto_TYPE_FLOAT:
1058 typ, wire = "float32", "fixed32"
1059 case descriptor.FieldDescriptorProto_TYPE_INT64:
1060 typ, wire = "int64", "varint"
1061 case descriptor.FieldDescriptorProto_TYPE_UINT64:
1062 typ, wire = "uint64", "varint"
1063 case descriptor.FieldDescriptorProto_TYPE_INT32:
1064 typ, wire = "int32", "varint"
1065 case descriptor.FieldDescriptorProto_TYPE_UINT32:
1066 typ, wire = "uint32", "varint"
1067 case descriptor.FieldDescriptorProto_TYPE_FIXED64:
1068 typ, wire = "uint64", "fixed64"
1069 case descriptor.FieldDescriptorProto_TYPE_FIXED32:
1070 typ, wire = "uint32", "fixed32"
1071 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1072 typ, wire = "bool", "varint"
1073 case descriptor.FieldDescriptorProto_TYPE_STRING:
1074 typ, wire = "string", "bytes"
1075 case descriptor.FieldDescriptorProto_TYPE_GROUP:
1076 desc := g.ObjectNamed(proto.GetString(field.TypeName))
1077 typ, wire = "*"+g.TypeName(desc), "group"
1078 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
1079 desc := g.ObjectNamed(proto.GetString(field.TypeName))
1080 typ, wire = "*"+g.TypeName(desc), "bytes"
1081 case descriptor.FieldDescriptorProto_TYPE_BYTES:
1082 typ, wire = "[]byte", "bytes"
1083 case descriptor.FieldDescriptorProto_TYPE_ENUM:
1084 desc := g.ObjectNamed(proto.GetString(field.TypeName))
1085 typ, wire = g.TypeName(desc), "varint"
1086 case descriptor.FieldDescriptorProto_TYPE_SFIXED32:
1087 typ, wire = "int32", "fixed32"
1088 case descriptor.FieldDescriptorProto_TYPE_SFIXED64:
1089 typ, wire = "int64", "fixed64"
1090 case descriptor.FieldDescriptorProto_TYPE_SINT32:
1091 typ, wire = "int32", "zigzag32"
1092 case descriptor.FieldDescriptorProto_TYPE_SINT64:
1093 typ, wire = "int64", "zigzag64"
1095 g.Fail("unknown type for", proto.GetString(field.Name))
1097 if isRepeated(field) {
1099 } else if needsStar(*field.Type) {
1105 func (g *Generator) RecordTypeUse(t string) {
1106 if obj, ok := g.typeNameToObject[t]; ok {
1107 // Call ObjectNamed to get the true object to record the use.
1108 obj = g.ObjectNamed(t)
1109 g.usedPackages[obj.PackageName()] = true
1113 // Generate the type and default constant definitions for this Descriptor.
1114 func (g *Generator) generateMessage(message *Descriptor) {
1115 // The full type name
1116 typeName := message.TypeName()
1117 // The full type name, CamelCased.
1118 ccTypeName := CamelCaseSlice(typeName)
1120 g.P("type ", ccTypeName, " struct {")
1122 for _, field := range message.Field {
1123 fieldname := CamelCase(*field.Name)
1124 typename, wiretype := g.GoType(message, field)
1125 jsonName := *field.Name
1126 tag := fmt.Sprintf("`protobuf:%s json:%q`", g.goTag(field, wiretype), jsonName+",omitempty")
1127 g.P(fieldname, "\t", typename, "\t", tag)
1128 g.RecordTypeUse(proto.GetString(field.TypeName))
1130 // TODO: Use `json:"-"` for these XXX_ fields when that makes it into a Go release.
1131 if len(message.ExtensionRange) > 0 {
1132 g.P("XXX_extensions\t\tmap[int32]", g.ProtoPkg, ".Extension `json:\",omitempty\"`")
1134 g.P("XXX_unrecognized\t[]byte `json:\",omitempty\"`")
1138 // Reset and String functions
1139 g.P("func (this *", ccTypeName, ") Reset() { *this = ", ccTypeName, "{} }")
1140 g.P("func (this *", ccTypeName, ") String() string { return ", g.ProtoPkg, ".CompactTextString(this) }")
1142 // Extension support methods
1143 var hasExtensions, isMessageSet bool
1144 if len(message.ExtensionRange) > 0 {
1145 hasExtensions = true
1146 // message_set_wire_format only makes sense when extensions are defined.
1147 if opts := message.Options; opts != nil && proto.GetBool(opts.MessageSetWireFormat) {
1150 g.P("func (this *", ccTypeName, ") Marshal() ([]byte, os.Error) {")
1152 g.P("return ", g.ProtoPkg, ".MarshalMessageSet(this.ExtensionMap())")
1155 g.P("func (this *", ccTypeName, ") Unmarshal(buf []byte) os.Error {")
1157 g.P("return ", g.ProtoPkg, ".UnmarshalMessageSet(buf, this.ExtensionMap())")
1160 g.P("// ensure ", ccTypeName, " satisfies proto.Marshaler and proto.Unmarshaler")
1161 g.P("var _ ", g.ProtoPkg, ".Marshaler = (*", ccTypeName, ")(nil)")
1162 g.P("var _ ", g.ProtoPkg, ".Unmarshaler = (*", ccTypeName, ")(nil)")
1166 g.P("var extRange_", ccTypeName, " = []", g.ProtoPkg, ".ExtensionRange{")
1168 for _, r := range message.ExtensionRange {
1169 end := fmt.Sprint(*r.End - 1) // make range inclusive on both ends
1170 g.P("{", r.Start, ", ", end, "},")
1174 g.P("func (*", ccTypeName, ") ExtensionRangeArray() []", g.ProtoPkg, ".ExtensionRange {")
1176 g.P("return extRange_", ccTypeName)
1179 g.P("func (this *", ccTypeName, ") ExtensionMap() map[int32]", g.ProtoPkg, ".Extension {")
1181 g.P("if this.XXX_extensions == nil {")
1183 g.P("this.XXX_extensions = make(map[int32]", g.ProtoPkg, ".Extension)")
1186 g.P("return this.XXX_extensions")
1191 g.file.addExport(message, messageSymbol{ccTypeName, hasExtensions, isMessageSet})
1193 // Default constants
1194 for _, field := range message.Field {
1195 def := proto.GetString(field.DefaultValue)
1199 fieldname := "Default_" + ccTypeName + "_" + CamelCase(*field.Name)
1200 typename, _ := g.GoType(message, field)
1201 if typename[0] == '*' {
1202 typename = typename[1:]
1206 case typename == "bool":
1207 case typename == "string":
1209 case typename == "[]byte":
1210 def = "[]byte(" + Quote(def) + ")"
1212 case def == "inf", def == "-inf", def == "nan":
1213 // These names are known to, and defined by, the protocol language.
1218 def = "math.Inf(-1)"
1222 if *field.Type == descriptor.FieldDescriptorProto_TYPE_FLOAT {
1223 def = "float32(" + def + ")"
1226 case *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM:
1227 // Must be an enum. Need to construct the prefixed name.
1228 obj := g.ObjectNamed(proto.GetString(field.TypeName))
1229 enum, ok := obj.(*EnumDescriptor)
1231 log.Println("don't know how to generate constant for", fieldname)
1234 def = g.DefaultPackageName(enum) + enum.prefix() + def
1236 g.P(kind, fieldname, " ", typename, " = ", def)
1237 g.file.addExport(message, constOrVarSymbol{fieldname, kind})
1241 for _, ext := range message.ext {
1242 g.generateExtension(ext)
1246 func (g *Generator) generateExtension(ext *ExtensionDescriptor) {
1247 ccTypeName := ext.DescName()
1249 extendedType := "*" + g.TypeName(g.ObjectNamed(*ext.Extendee))
1250 field := ext.FieldDescriptorProto
1251 fieldType, wireType := g.GoType(ext.parent, field)
1252 tag := g.goTag(field, wireType)
1253 g.RecordTypeUse(*ext.Extendee)
1254 if n := ext.FieldDescriptorProto.TypeName; n != nil {
1255 // foreign extension type
1259 g.P("var ", ccTypeName, " = &", g.ProtoPkg, ".ExtensionDesc{")
1261 g.P("ExtendedType: (", extendedType, ")(nil),")
1262 g.P("ExtensionType: (", fieldType, ")(nil),")
1263 g.P("Field: ", field.Number, ",")
1264 g.P(`Name: "`, g.packageName, ".", strings.Join(ext.TypeName(), "."), `",`)
1265 g.P("Tag: ", tag, ",")
1271 g.file.addExport(ext, constOrVarSymbol{ccTypeName, "var"})
1274 func (g *Generator) generateInitFunction() {
1275 g.P("func init() {")
1277 for _, enum := range g.file.enum {
1278 g.generateEnumRegistration(enum)
1280 for _, d := range g.file.desc {
1281 for _, ext := range d.ext {
1282 g.generateExtensionRegistration(ext)
1285 for _, ext := range g.file.ext {
1286 g.generateExtensionRegistration(ext)
1292 func (g *Generator) generateEnumRegistration(enum *EnumDescriptor) {
1293 // // We always print the full (proto-world) package name here.
1294 pkg := proto.GetString(enum.File().Package)
1298 // The full type name
1299 typeName := enum.TypeName()
1300 // The full type name, CamelCased.
1301 ccTypeName := CamelCaseSlice(typeName)
1302 g.P(g.ProtoPkg+".RegisterEnum(", Quote(pkg+ccTypeName), ", ", ccTypeName+"_name, ", ccTypeName+"_value)")
1305 func (g *Generator) generateExtensionRegistration(ext *ExtensionDescriptor) {
1306 g.P(g.ProtoPkg+".RegisterExtension(", ext.DescName(), ")")
1309 // And now lots of helper functions.
1311 // Is c an ASCII lower-case letter?
1312 func isASCIILower(c byte) bool {
1313 return 'a' <= c && c <= 'z'
1316 // Is c an ASCII digit?
1317 func isASCIIDigit(c byte) bool {
1318 return '0' <= c && c <= '9'
1321 // CamelCase returns the CamelCased name.
1322 // If there is an interior underscore followed by a lower case letter,
1323 // drop the underscore and convert the letter to upper case.
1324 // There is a remote possibility of this rewrite causing a name collision,
1325 // but it's so remote we're prepared to pretend it's nonexistent - since the
1326 // C++ generator lowercases names, it's extremely unlikely to have two fields
1327 // with different capitalizations.
1328 // In short, _my_field_name_2 becomes XMyFieldName2.
1329 func CamelCase(s string) string {
1333 t := make([]byte, 0, 32)
1336 // Need a capital letter; drop the '_'.
1340 // Invariant: if the next letter is lower case, it must be converted
1342 // That is, we process a word at a time, where words are marked by _ or
1343 // upper case letter. Digits are treated as words.
1344 for ; i < len(s); i++ {
1346 if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) {
1347 continue // Skip the underscore in s.
1349 if isASCIIDigit(c) {
1353 // Assume we have a letter now - if not, it's a bogus identifier.
1354 // The next word is a sequence of characters that must start upper case.
1355 if isASCIILower(c) {
1356 c ^= ' ' // Make it a capital letter.
1358 t = append(t, c) // Guaranteed not lower case.
1359 // Accept lower case sequence that follows.
1360 for i+1 < len(s) && isASCIILower(s[i+1]) {
1368 // CamelCaseSlice is like CamelCase, but the argument is a slice of strings to
1369 // be joined with "_".
1370 func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem, "_")) }
1372 // dottedSlice turns a sliced name into a dotted name.
1373 func dottedSlice(elem []string) string { return strings.Join(elem, ".") }
1375 // Quote returns a Go-source quoted string representation of s.
1376 func Quote(s string) string { return fmt.Sprintf("%q", s) }
1378 // Given a .proto file name, return the output name for the generated Go program.
1379 func goFileName(name string) string {
1380 ext := path.Ext(name)
1381 if ext == ".proto" || ext == ".protodevel" {
1382 name = name[0 : len(name)-len(ext)]
1384 return name + ".pb.go"
1387 // Is this field optional?
1388 func isOptional(field *descriptor.FieldDescriptorProto) bool {
1389 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_OPTIONAL
1392 // Is this field required?
1393 func isRequired(field *descriptor.FieldDescriptorProto) bool {
1394 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REQUIRED
1397 // Is this field repeated?
1398 func isRepeated(field *descriptor.FieldDescriptorProto) bool {
1399 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED
1402 // DotToUnderscore is the mapping function used to generate Go names from package names,
1403 // which can be dotted in the input .proto file. It maps dots to underscores.
1404 // Because we also get here from package names generated from file names, it also maps
1405 // minus signs to underscores.
1406 func DotToUnderscore(rune int) int {
1414 // BaseName returns the last path element of the name, with the last dotted suffix removed.
1415 func BaseName(name string) string {
1416 // First, find the last element
1417 if i := strings.LastIndex(name, "/"); i >= 0 {
1420 // Now drop the suffix
1421 if i := strings.LastIndex(name, "."); i >= 0 {