initialise
[debian/goprotobuf.git] / compiler / generator / generator.go
1 // Go support for Protocol Buffers - Google's data interchange format
2 //
3 // Copyright 2010 Google Inc.  All rights reserved.
4 // http://code.google.com/p/goprotobuf/
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
8 // met:
9 //
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
15 // distribution.
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.
19 //
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.
31
32 /*
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
35         main routine.
36 */
37 package generator
38
39 import (
40         "bytes"
41         "fmt"
42         "go/parser"
43         "go/printer"
44         "go/token"
45         "log"
46         "os"
47         "path"
48         "strconv"
49         "strings"
50
51         "goprotobuf.googlecode.com/hg/proto"
52         plugin "goprotobuf.googlecode.com/hg/compiler/plugin"
53         descriptor "goprotobuf.googlecode.com/hg/compiler/descriptor"
54 )
55
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.
60         Name() string
61         // Init is called once after data structures are built but before
62         // code generation begins.
63         Init(g *Generator)
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)
70 }
71
72 var plugins []Plugin
73
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)
78 }
79
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.
85
86 // The file and package name method are common to messages and enums.
87 type common struct {
88         file *descriptor.FileDescriptorProto // File this object comes from.
89 }
90
91 // PackageName is name in the package clause in the generated file.
92 func (c *common) PackageName() string { return uniquePackageOf(c.file) }
93
94 func (c *common) File() *descriptor.FileDescriptorProto { return c.file }
95
96 // Descriptor represents a protocol buffer message.
97 type Descriptor struct {
98         common
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.
104 }
105
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 {
110                 return d.typename
111         }
112         n := 0
113         for parent := d; parent != nil; parent = parent.parent {
114                 n++
115         }
116         s := make([]string, n, n)
117         for parent := d; parent != nil; parent = parent.parent {
118                 n--
119                 s[n] = proto.GetString(parent.Name)
120         }
121         d.typename = s
122         return s
123 }
124
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 {
128         common
129         *descriptor.EnumDescriptorProto
130         parent   *Descriptor // The containing message, if any.
131         typename []string    // Cached typename vector.
132 }
133
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 {
138                 return e.typename
139         }
140         name := proto.GetString(e.Name)
141         if e.parent == nil {
142                 s = make([]string, 1)
143         } else {
144                 pname := e.parent.TypeName()
145                 s = make([]string, len(pname)+1)
146                 copy(s, pname)
147         }
148         s[len(s)-1] = name
149         e.typename = s
150         return s
151 }
152
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]) + "_"
158         if e.parent == nil {
159                 // If the enum is not part of a message, the prefix is just the type name.
160                 ccPrefix = CamelCase(*e.Name) + "_"
161         }
162         return ccPrefix
163 }
164
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))
170                 }
171         }
172         log.Fatal("cannot find value for enum constant")
173         return ""
174 }
175
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 {
179         common
180         *descriptor.FieldDescriptorProto
181         parent *Descriptor // The containing message, if any.
182 }
183
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)
188         if e.parent == nil {
189                 // top-level extension
190                 s = make([]string, 1)
191         } else {
192                 pname := e.parent.TypeName()
193                 s = make([]string, len(pname)+1)
194                 copy(s, pname)
195         }
196         s[len(s)-1] = name
197         return s
198 }
199
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)
207         }
208         return "E_" + strings.Join(typeName, "_")
209 }
210
211 // ImportedDescriptor describes a type that has been publicly imported from another file.
212 type ImportedDescriptor struct {
213         common
214         o Object
215 }
216
217 func (id *ImportedDescriptor) TypeName() []string { return id.o.TypeName() }
218
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.
228
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
233 }
234
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) }
237
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 != "" {
243                 return pkg
244         }
245         // Use the file base name.
246         return BaseName(proto.GetString(d.Name))
247 }
248
249 func (d *FileDescriptor) addExport(obj Object, symbol Symbol) {
250         d.exported[obj] = append(d.exported[obj], symbol)
251 }
252
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)
258 }
259
260 type messageSymbol struct {
261         sym                         string
262         hasExtensions, isMessageSet bool
263 }
264
265 func (ms messageSymbol) GenerateAlias(g *Generator, pkg string) {
266         remoteSym := pkg + "." + ms.sym
267
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() }")
276                 if ms.isMessageSet {
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) }")
281                 }
282         }
283 }
284
285 type enumSymbol string
286
287 func (es enumSymbol) GenerateAlias(g *Generator, pkg string) {
288         s := string(es)
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 }")
293 }
294
295 type constOrVarSymbol struct {
296         sym string
297         typ string // either "const" or "var"
298 }
299
300 func (cs constOrVarSymbol) GenerateAlias(g *Generator, pkg string) {
301         g.P(cs.typ, " ", cs.sym, " = ", pkg, ".", cs.sym)
302 }
303
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.
307         TypeName() []string
308         File() *descriptor.FileDescriptorProto
309 }
310
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]
317         if !ok {
318                 log.Fatal("internal error: no package name defined for", proto.GetString(fd.Name))
319         }
320         return s
321 }
322
323 // Generator is the type whose methods generate the output, stored in the associated response structure.
324 type Generator struct {
325         *bytes.Buffer
326
327         Request  *plugin.CodeGeneratorRequest  // The input.
328         Response *plugin.CodeGeneratorResponse // The output.
329
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
333
334         ProtoPkg string // The name under which we import the library's package proto.
335
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.
342         indent           string
343 }
344
345 // New creates a new generator and allocates the request and response protobufs.
346 func New() *Generator {
347         g := new(Generator)
348         g.Buffer = new(bytes.Buffer)
349         g.Request = new(plugin.CodeGeneratorRequest)
350         g.Response = new(plugin.CodeGeneratorResponse)
351         return g
352 }
353
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)
359         os.Exit(1)
360 }
361
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)
367         os.Exit(1)
368 }
369
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 {
377                         g.Param[p] = ""
378                 } else {
379                         g.Param[p[0:i]] = p[i+1:]
380                 }
381         }
382
383         g.ImportMap = make(map[string]string)
384         for k, v := range g.Param {
385                 if k == "import_prefix" {
386                         g.ImportPrefix = v
387                 } else if len(k) > 0 && k[0] == 'M' {
388                         g.ImportMap[k[1:]] = v
389                 }
390         }
391 }
392
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 {
399                 return ""
400         }
401         return pkg + "."
402 }
403
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)
409
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)
416
417         for i, orig := 1, pkg; pkgNamesInUse[pkg]; i++ {
418                 // It's a duplicate; must rename.
419                 pkg = orig + strconv.Itoa(i)
420         }
421         // Install it.
422         pkgNamesInUse[pkg] = true
423         if f != nil {
424                 uniquePackageName[f.FileDescriptorProto] = pkg
425         }
426         return pkg
427 }
428
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()
443                 if thisPkg != pkg {
444                         g.Fail("inconsistent package names:", thisPkg, pkg)
445                 }
446         }
447 AllFiles:
448         for _, f := range g.allFiles {
449                 for _, genf := range g.genFiles {
450                         if f == genf {
451                                 // In this package already.
452                                 uniquePackageName[f.FileDescriptorProto] = g.packageName
453                                 continue AllFiles
454                         }
455                 }
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)
459                 if pkg == "" {
460                         pkg = BaseName(*f.Name)
461                 }
462                 RegisterUniquePackageName(pkg, f)
463         }
464 }
465
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,
480                         desc:                descs,
481                         enum:                enums,
482                         ext:                 exts,
483                         imp:                 imps,
484                         exported:            make(map[Object][]Symbol),
485                 }
486         }
487
488         g.genFiles = make([]*FileDescriptor, len(g.Request.FileToGenerate))
489 FindFiles:
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) {
494                                 g.genFiles[i] = file
495                                 continue FindFiles
496                         }
497                 }
498                 g.Fail("could not find file named", fileName)
499         }
500         g.Response.File = make([]*plugin.CodeGeneratorResponse_File, len(g.genFiles))
501 }
502
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))
508                         n := 0
509                         for _, nest := range descs {
510                                 if nest.parent == desc {
511                                         desc.nested[n] = nest
512                                         n++
513                                 }
514                         }
515                         if n != len(desc.NestedType) {
516                                 g.Fail("internal error: nesting failure for", proto.GetString(desc.Name))
517                         }
518                 }
519         }
520 }
521
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}
525
526         d.ext = make([]*ExtensionDescriptor, len(desc.Extension))
527         for i, field := range desc.Extension {
528                 d.ext[i] = &ExtensionDescriptor{common{file}, field, d}
529         }
530
531         return append(sl, d)
532 }
533
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)
539         }
540         return sl
541 }
542
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)
546         me := sl[len(sl)-1]
547         for _, nested := range desc.NestedType {
548                 sl = wrapThisDescriptor(sl, nested, me, file)
549         }
550         return sl
551 }
552
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})
556 }
557
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)
561         // Top-level enums.
562         for _, enum := range file.EnumType {
563                 sl = addEnumDescriptor(sl, enum, nil, file)
564         }
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)
569                 }
570         }
571         return sl
572 }
573
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}
579         }
580         return sl
581 }
582
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})
589                 }
590                 for _, e := range df.enum {
591                         sl = append(sl, &ImportedDescriptor{common{file}, e})
592                 }
593                 for _, ext := range df.ext {
594                         sl = append(sl, &ImportedDescriptor{common{file}, ext})
595                 }
596         }
597         return
598 }
599
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 != "." {
611                         dottedPkg += "."
612                 }
613                 for _, enum := range f.enum {
614                         name := dottedPkg + dottedSlice(enum.TypeName())
615                         g.typeNameToObject[name] = enum
616                 }
617                 for _, desc := range f.desc {
618                         name := dottedPkg + dottedSlice(desc.TypeName())
619                         g.typeNameToObject[name] = desc
620                 }
621         }
622 }
623
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]
628         if !ok {
629                 g.Fail("can't find object with type", typeName)
630         }
631
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
637         if !direct {
638                 for _, dep := range g.file.Dependency {
639                         if *g.fileByName(dep).Name == *o.File().Name {
640                                 direct = true
641                                 break
642                         }
643                 }
644         }
645         if !direct {
646                 found := false
647         Loop:
648                 for _, dep := range g.file.Dependency {
649                         df := g.fileByName(*g.fileByName(dep).Name)
650                         for _, td := range df.imp {
651                                 if td.o == o {
652                                         // Found it!
653                                         o = td
654                                         found = true
655                                         break Loop
656                                 }
657                         }
658                 }
659                 if !found {
660                         log.Printf("protoc-gen-go: WARNING: failed finding publicly imported dependency for %v, used in %v", typeName, *g.file.Name)
661                 }
662         }
663
664         return o
665 }
666
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) {
673                 case string:
674                         g.WriteString(s)
675                 case *string:
676                         g.WriteString(*s)
677                 case bool:
678                         g.WriteString(fmt.Sprintf("%t", s))
679                 case *bool:
680                         g.WriteString(fmt.Sprintf("%t", *s))
681                 case *int32:
682                         g.WriteString(fmt.Sprintf("%d", *s))
683                 case float64:
684                         g.WriteString(fmt.Sprintf("%g", s))
685                 case *float64:
686                         g.WriteString(fmt.Sprintf("%g", *s))
687                 default:
688                         g.Fail(fmt.Sprintf("unknown type in printer: %T", v))
689                 }
690         }
691         g.WriteByte('\n')
692 }
693
694 // In Indents the output one tab stop.
695 func (g *Generator) In() { g.indent += "\t" }
696
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:]
701         }
702 }
703
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 {
708                 p.Init(g)
709         }
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
716         }
717         i := 0
718         for _, file := range g.allFiles {
719                 g.Reset()
720                 g.generate(file)
721                 if _, ok := genFileMap[file]; !ok {
722                         continue
723                 }
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())
727                 i++
728         }
729 }
730
731 // Run all the plugins associated with the file.
732 func (g *Generator) runPlugins(file *FileDescriptor) {
733         for _, p := range plugins {
734                 p.Generate(file)
735         }
736 }
737
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 {
742                         return file
743                 }
744         }
745         g.Fail("could not find file in table:", proto.GetString(fd.Name))
746         return nil
747 }
748
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)
754
755         for _, td := range g.file.imp {
756                 g.generateImported(td)
757         }
758         for _, enum := range g.file.enum {
759                 g.generateEnum(enum)
760         }
761         for _, desc := range g.file.desc {
762                 g.generateMessage(desc)
763         }
764         for _, ext := range g.file.ext {
765                 g.generateExtension(ext)
766         }
767         g.generateInitFunction()
768
769         // Run the plugins before the imports so we know which imports are necessary.
770         g.runPlugins(file)
771
772         // Generate header and imports last, though they appear first in the output.
773         rem := g.Buffer
774         g.Buffer = new(bytes.Buffer)
775         g.generateHeader()
776         g.generateImports()
777         g.Write(rem.Bytes())
778
779         // Reformat generated code.
780         fset := token.NewFileSet()
781         ast, err := parser.ParseFile(fset, "", g, parser.ParseComments)
782         if err != nil {
783                 g.Fail("bad Go source code was generated:", err.String())
784                 return
785         }
786         g.Reset()
787         _, err = (&printer.Config{printer.TabIndent | printer.UseSpaces, 8}).Fprint(g, fset, ast)
788         if err != nil {
789                 g.Fail("generated Go source code could not be reformatted:", err.String())
790         }
791 }
792
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!")
797         g.P()
798         g.P("package ", g.file.PackageName())
799         g.P()
800 }
801
802 func (g *Generator) fileByName(filename string) *FileDescriptor {
803         for _, fd := range g.allFiles {
804                 if proto.GetString(fd.Name) == filename {
805                         return fd
806                 }
807         }
808         return nil
809 }
810
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"))
817         g.P(`import "math"`)
818         g.P(`import "os"`)
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 {
823                         continue
824                 }
825                 filename := goFileName(s)
826                 if substitution, ok := g.ImportMap[s]; ok {
827                         filename = substitution
828                 }
829                 filename = g.ImportPrefix + filename
830                 if strings.HasSuffix(filename, ".go") {
831                         filename = filename[0 : len(filename)-3]
832                 }
833                 if _, ok := g.usedPackages[fd.PackageName()]; ok {
834                         g.P("import ", fd.PackageName(), " ", Quote(filename))
835                 } else {
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))
841                 }
842         }
843         g.P()
844         // TODO: may need to worry about uniqueness across plugins
845         for _, p := range plugins {
846                 p.GenerateImports(g.file)
847                 g.P()
848         }
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")
853         g.P()
854 }
855
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.
861         tn := id.TypeName()
862         sn := tn[len(tn)-1]
863         df := g.FileOf(id.o.File())
864         filename := *df.Name
865         for _, fd := range g.genFiles {
866                 if *fd.Name == filename {
867                         g.P("// Ignoring public import of ", sn, " from ", filename)
868                         g.P()
869                         return
870                 }
871         }
872         g.P("// ", sn, " from public import ", filename)
873         g.usedPackages[df.PackageName()] = true
874
875         for _, sym := range df.exported[id.o] {
876                 sym.GenerateAlias(g, df.PackageName())
877         }
878
879         g.P()
880 }
881
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))
891         g.P("const (")
892         g.In()
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"})
897         }
898         g.Out()
899         g.P(")")
900         g.P("var ", ccTypeName, "_name = map[int32]string{")
901         g.In()
902         generated := make(map[int32]bool) // avoid duplicate values
903         for _, e := range enum.Value {
904                 duplicate := ""
905                 if _, present := generated[*e.Number]; present {
906                         duplicate = "// Duplicate value: "
907                 }
908                 g.P(duplicate, e.Number, ": ", Quote(*e.Name), ",")
909                 generated[*e.Number] = true
910         }
911         g.Out()
912         g.P("}")
913         g.P("var ", ccTypeName, "_value = map[string]int32{")
914         g.In()
915         for _, e := range enum.Value {
916                 g.P(Quote(*e.Name), ": ", e.Number, ",")
917         }
918         g.Out()
919         g.P("}")
920
921         g.P("func New", ccTypeName, "(x ", ccTypeName, ") *", ccTypeName, " {")
922         g.In()
923         g.P("e := ", ccTypeName, "(x)")
924         g.P("return &e")
925         g.Out()
926         g.P("}")
927
928         g.P("func (x ", ccTypeName, ") String() string {")
929         g.In()
930         g.P("return ", g.ProtoPkg, ".EnumName(", ccTypeName, "_name, int32(x))")
931         g.Out()
932         g.P("}")
933
934         g.P()
935 }
936
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:
940 //      wire encoding
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 {
950         optrepreq := ""
951         switch {
952         case isOptional(field):
953                 optrepreq = "opt"
954         case isRequired(field):
955                 optrepreq = "req"
956         case isRepeated(field):
957                 optrepreq = "rep"
958         }
959         defaultValue := proto.GetString(field.DefaultValue)
960         if defaultValue != "" {
961                 switch *field.Type {
962                 case descriptor.FieldDescriptorProto_TYPE_BOOL:
963                         if defaultValue == "true" {
964                                 defaultValue = "1"
965                         } else {
966                                 defaultValue = "0"
967                         }
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)
975                         if !ok {
976                                 g.Fail("enum type inconsistent for", CamelCaseSlice(obj.TypeName()))
977                         }
978                         defaultValue = enum.integerValueAsString(defaultValue)
979                 }
980                 defaultValue = ",def=" + defaultValue
981         }
982         enum := ""
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))
987                 enum = ",enum="
988                 if pkg := proto.GetString(obj.File().Package); pkg != "" {
989                         enum += pkg + "."
990                 }
991                 enum += CamelCaseSlice(obj.TypeName())
992         }
993         packed := ""
994         if field.Options != nil && proto.GetBool(field.Options.Packed) {
995                 packed = ",packed"
996         }
997         fieldName := proto.GetString(field.Name)
998         name := fieldName
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 {
1006                         name = name[i+1:]
1007                 }
1008         }
1009         if name == CamelCase(fieldName) {
1010                 name = ""
1011         } else {
1012                 name = ",name=" + name
1013         }
1014         return Quote(fmt.Sprintf("%s,%d,%s%s%s%s%s",
1015                 wiretype,
1016                 proto.GetInt32(field.Number),
1017                 optrepreq,
1018                 packed,
1019                 name,
1020                 enum,
1021                 defaultValue))
1022 }
1023
1024 func needsStar(typ descriptor.FieldDescriptorProto_Type) bool {
1025         switch typ {
1026         case descriptor.FieldDescriptorProto_TYPE_GROUP:
1027                 return false
1028         case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
1029                 return false
1030         case descriptor.FieldDescriptorProto_TYPE_BYTES:
1031                 return false
1032         }
1033         return true
1034 }
1035
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())
1043 }
1044
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())
1049 }
1050
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) {
1053         // TODO: Options.
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"
1094         default:
1095                 g.Fail("unknown type for", proto.GetString(field.Name))
1096         }
1097         if isRepeated(field) {
1098                 typ = "[]" + typ
1099         } else if needsStar(*field.Type) {
1100                 typ = "*" + typ
1101         }
1102         return
1103 }
1104
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
1110         }
1111 }
1112
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)
1119
1120         g.P("type ", ccTypeName, " struct {")
1121         g.In()
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))
1129         }
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\"`")
1133         }
1134         g.P("XXX_unrecognized\t[]byte `json:\",omitempty\"`")
1135         g.Out()
1136         g.P("}")
1137
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) }")
1141
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) {
1148                         isMessageSet = true
1149                         g.P()
1150                         g.P("func (this *", ccTypeName, ") Marshal() ([]byte, os.Error) {")
1151                         g.In()
1152                         g.P("return ", g.ProtoPkg, ".MarshalMessageSet(this.ExtensionMap())")
1153                         g.Out()
1154                         g.P("}")
1155                         g.P("func (this *", ccTypeName, ") Unmarshal(buf []byte) os.Error {")
1156                         g.In()
1157                         g.P("return ", g.ProtoPkg, ".UnmarshalMessageSet(buf, this.ExtensionMap())")
1158                         g.Out()
1159                         g.P("}")
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)")
1163                 }
1164
1165                 g.P()
1166                 g.P("var extRange_", ccTypeName, " = []", g.ProtoPkg, ".ExtensionRange{")
1167                 g.In()
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, "},")
1171                 }
1172                 g.Out()
1173                 g.P("}")
1174                 g.P("func (*", ccTypeName, ") ExtensionRangeArray() []", g.ProtoPkg, ".ExtensionRange {")
1175                 g.In()
1176                 g.P("return extRange_", ccTypeName)
1177                 g.Out()
1178                 g.P("}")
1179                 g.P("func (this *", ccTypeName, ") ExtensionMap() map[int32]", g.ProtoPkg, ".Extension {")
1180                 g.In()
1181                 g.P("if this.XXX_extensions == nil {")
1182                 g.In()
1183                 g.P("this.XXX_extensions = make(map[int32]", g.ProtoPkg, ".Extension)")
1184                 g.Out()
1185                 g.P("}")
1186                 g.P("return this.XXX_extensions")
1187                 g.Out()
1188                 g.P("}")
1189         }
1190
1191         g.file.addExport(message, messageSymbol{ccTypeName, hasExtensions, isMessageSet})
1192
1193         // Default constants
1194         for _, field := range message.Field {
1195                 def := proto.GetString(field.DefaultValue)
1196                 if def == "" {
1197                         continue
1198                 }
1199                 fieldname := "Default_" + ccTypeName + "_" + CamelCase(*field.Name)
1200                 typename, _ := g.GoType(message, field)
1201                 if typename[0] == '*' {
1202                         typename = typename[1:]
1203                 }
1204                 kind := "const "
1205                 switch {
1206                 case typename == "bool":
1207                 case typename == "string":
1208                         def = Quote(def)
1209                 case typename == "[]byte":
1210                         def = "[]byte(" + Quote(def) + ")"
1211                         kind = "var "
1212                 case def == "inf", def == "-inf", def == "nan":
1213                         // These names are known to, and defined by, the protocol language.
1214                         switch def {
1215                         case "inf":
1216                                 def = "math.Inf(1)"
1217                         case "-inf":
1218                                 def = "math.Inf(-1)"
1219                         case "nan":
1220                                 def = "math.NaN()"
1221                         }
1222                         if *field.Type == descriptor.FieldDescriptorProto_TYPE_FLOAT {
1223                                 def = "float32(" + def + ")"
1224                         }
1225                         kind = "var "
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)
1230                         if !ok {
1231                                 log.Println("don't know how to generate constant for", fieldname)
1232                                 continue
1233                         }
1234                         def = g.DefaultPackageName(enum) + enum.prefix() + def
1235                 }
1236                 g.P(kind, fieldname, " ", typename, " = ", def)
1237                 g.file.addExport(message, constOrVarSymbol{fieldname, kind})
1238         }
1239         g.P()
1240
1241         for _, ext := range message.ext {
1242                 g.generateExtension(ext)
1243         }
1244 }
1245
1246 func (g *Generator) generateExtension(ext *ExtensionDescriptor) {
1247         ccTypeName := ext.DescName()
1248
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
1256                 g.RecordTypeUse(*n)
1257         }
1258
1259         g.P("var ", ccTypeName, " = &", g.ProtoPkg, ".ExtensionDesc{")
1260         g.In()
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, ",")
1266
1267         g.Out()
1268         g.P("}")
1269         g.P()
1270
1271         g.file.addExport(ext, constOrVarSymbol{ccTypeName, "var"})
1272 }
1273
1274 func (g *Generator) generateInitFunction() {
1275         g.P("func init() {")
1276         g.In()
1277         for _, enum := range g.file.enum {
1278                 g.generateEnumRegistration(enum)
1279         }
1280         for _, d := range g.file.desc {
1281                 for _, ext := range d.ext {
1282                         g.generateExtensionRegistration(ext)
1283                 }
1284         }
1285         for _, ext := range g.file.ext {
1286                 g.generateExtensionRegistration(ext)
1287         }
1288         g.Out()
1289         g.P("}")
1290 }
1291
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)
1295         if pkg != "" {
1296                 pkg += "."
1297         }
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)")
1303 }
1304
1305 func (g *Generator) generateExtensionRegistration(ext *ExtensionDescriptor) {
1306         g.P(g.ProtoPkg+".RegisterExtension(", ext.DescName(), ")")
1307 }
1308
1309 // And now lots of helper functions.
1310
1311 // Is c an ASCII lower-case letter?
1312 func isASCIILower(c byte) bool {
1313         return 'a' <= c && c <= 'z'
1314 }
1315
1316 // Is c an ASCII digit?
1317 func isASCIIDigit(c byte) bool {
1318         return '0' <= c && c <= '9'
1319 }
1320
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 {
1330         if s == "" {
1331                 return ""
1332         }
1333         t := make([]byte, 0, 32)
1334         i := 0
1335         if s[0] == '_' {
1336                 // Need a capital letter; drop the '_'.
1337                 t = append(t, 'X')
1338                 i++
1339         }
1340         // Invariant: if the next letter is lower case, it must be converted
1341         // to upper case.
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++ {
1345                 c := s[i]
1346                 if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) {
1347                         continue // Skip the underscore in s.
1348                 }
1349                 if isASCIIDigit(c) {
1350                         t = append(t, c)
1351                         continue
1352                 }
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.
1357                 }
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]) {
1361                         i++
1362                         t = append(t, s[i])
1363                 }
1364         }
1365         return string(t)
1366 }
1367
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, "_")) }
1371
1372 // dottedSlice turns a sliced name into a dotted name.
1373 func dottedSlice(elem []string) string { return strings.Join(elem, ".") }
1374
1375 // Quote returns a Go-source quoted string representation of s.
1376 func Quote(s string) string { return fmt.Sprintf("%q", s) }
1377
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)]
1383         }
1384         return name + ".pb.go"
1385 }
1386
1387 // Is this field optional?
1388 func isOptional(field *descriptor.FieldDescriptorProto) bool {
1389         return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_OPTIONAL
1390 }
1391
1392 // Is this field required?
1393 func isRequired(field *descriptor.FieldDescriptorProto) bool {
1394         return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REQUIRED
1395 }
1396
1397 // Is this field repeated?
1398 func isRepeated(field *descriptor.FieldDescriptorProto) bool {
1399         return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED
1400 }
1401
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 {
1407         switch rune {
1408         case '.', '-':
1409                 return '_'
1410         }
1411         return rune
1412 }
1413
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 {
1418                 name = name[i+1:]
1419         }
1420         // Now drop the suffix
1421         if i := strings.LastIndex(name, "."); i >= 0 {
1422                 name = name[0:i]
1423         }
1424         return name
1425 }