Просмотр исходного кода

goprotobuf: make the generator a package, with the main
program a separate file. also introduce the hooks for a plugin
(really a plugin for this plugin) to enable add-on generators for
things like RPC.

R=rsc
CC=golang-dev
http://codereview.appspot.com/970046

Rob Pike 15 лет назад
Родитель
Сommit
af82b4e96e
6 измененных файлов с 1085 добавлено и 944 удалено
  1. 1 1
      compiler/Makefile
  2. 2 0
      compiler/descriptor/Makefile
  3. 40 0
      compiler/generator/Makefile
  4. 1030 0
      compiler/generator/generator.go
  5. 10 943
      compiler/main.go
  6. 2 0
      compiler/plugin/Makefile

+ 1 - 1
compiler/Makefile

@@ -36,7 +36,7 @@ TARG=protoc-gen-go
 GOFILES=\
 GOFILES=\
 	main.go\
 	main.go\
 
 
-DEPS=descriptor plugin
+DEPS=generator descriptor plugin
 
 
 include $(GOROOT)/src/Make.cmd
 include $(GOROOT)/src/Make.cmd
 
 

+ 2 - 0
compiler/descriptor/Makefile

@@ -35,6 +35,8 @@ TARG=goprotobuf.googlecode.com/hg/compiler/descriptor
 GOFILES=\
 GOFILES=\
 	descriptor.pb.go\
 	descriptor.pb.go\
 
 
+DEPS=../../proto
+
 include $(GOROOT)/src/Make.pkg
 include $(GOROOT)/src/Make.pkg
 
 
 # Not stored here, but descriptor.proto is in http://code.google.com/p/protobuf
 # Not stored here, but descriptor.proto is in http://code.google.com/p/protobuf

+ 40 - 0
compiler/generator/Makefile

@@ -0,0 +1,40 @@
+# Go support for Protocol Buffers - Google's data interchange format
+#
+# Copyright 2010 Google Inc.  All rights reserved.
+# http://code.google.com/p/goprotobuf/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(GOROOT)/src/Make.$(GOARCH)
+
+TARG=goprotobuf.googlecode.com/hg/compiler/generator
+GOFILES=\
+	generator.go\
+
+DEPS=../descriptor ../plugin ../../proto
+
+include $(GOROOT)/src/Make.pkg

+ 1030 - 0
compiler/generator/generator.go

@@ -0,0 +1,1030 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/*
+	The code generator for the plugin for the Google protocol buffer compiler.
+	It generates Go code from the protocol buffer description files read by the
+	main routine.
+
+	Not supported yet:
+		services
+		options
+*/
+package generator
+
+import (
+	"bytes"
+	"fmt"
+	"log"
+	"os"
+	"strings"
+	"unicode"
+
+	"goprotobuf.googlecode.com/hg/proto"
+	plugin "goprotobuf.googlecode.com/hg/compiler/plugin"
+	descriptor "goprotobuf.googlecode.com/hg/compiler/descriptor"
+)
+
+// A Plugin provides functionality to add to the output during Go code generation,
+// such as to produce RPC stubs.
+type Plugin interface {
+	// Name identifies the plugin.
+	Name()	string
+	// Generate produces the code generated by the plugin for this file, except for the imports,
+	// by calling the generator's methods P, In, and Out.
+	Generate(g *Generator, file *FileDescriptor)
+	// GenerateImports produces the import declarations for this file.
+	GenerateImports(g *Generator, file *FileDescriptor)
+}
+
+var plugins []Plugin
+
+// RegisterPlugin installs a (second-order) plugin to be run when the Go output is generated.
+// It is typically called during initialization.
+func RegisterPlugin(p Plugin) {
+	n := len(plugins)
+	if cap(plugins) == n {
+		nplugins := make([]Plugin, n, n+10)	// very unlikely to need more than this
+		copy(nplugins, plugins)
+		plugins = nplugins
+	}
+	plugins = plugins[0:n+1]
+	plugins[n] = p
+	log.Stderr("installed plugin:", p.Name())
+}
+
+// Each type we import as a protocol buffer (other than FileDescriptorProto) needs
+// a pointer to the FileDescriptorProto that represents it.  These types achieve that
+// wrapping by placing each Proto inside a struct with the pointer to its File. The
+// structs have the same names as their contents, with "Proto" removed.
+// FileDescriptor is used to store the things that it points to.
+
+// The file and package name method are common to messages and enums.
+type common struct {
+	File *descriptor.FileDescriptorProto // File this object comes from.
+}
+
+// PackageName is name in the package clause in the generated file.
+func (c *common) PackageName() string { return uniquePackageOf(c.File) }
+
+// Descriptor represents a protocol buffer message.
+type Descriptor struct {
+	common
+	*descriptor.DescriptorProto
+	parent   *Descriptor            // The containing message, if any.
+	nested   []*Descriptor          // Inner messages, if any.
+	ext      []*ExtensionDescriptor // Extensions, if any.
+	typename []string               // Cached typename vector.
+}
+
+// TypeName returns the elements of the dotted type name.
+// The package name is not part of this name.
+func (d *Descriptor) TypeName() []string {
+	if d.typename != nil {
+		return d.typename
+	}
+	n := 0
+	for parent := d; parent != nil; parent = parent.parent {
+		n++
+	}
+	s := make([]string, n, n)
+	for parent := d; parent != nil; parent = parent.parent {
+		n--
+		s[n] = proto.GetString(parent.Name)
+	}
+	d.typename = s
+	return s
+}
+
+// EnumDescriptor describes an enum. If it's at top level, its parent will be nil.
+// Otherwise it will be the descriptor of the message in which it is defined.
+type EnumDescriptor struct {
+	common
+	*descriptor.EnumDescriptorProto
+	parent   *Descriptor // The containing message, if any.
+	typename []string    // Cached typename vector.
+}
+
+// TypeName returns the elements of the dotted type name.
+// The package name is not part of this name.
+func (e *EnumDescriptor) TypeName() (s []string) {
+	if e.typename != nil {
+		return e.typename
+	}
+	name := proto.GetString(e.Name)
+	if e.parent == nil {
+		s = make([]string, 1)
+	} else {
+		pname := e.parent.TypeName()
+		s = make([]string, len(pname)+1)
+		copy(s, pname)
+	}
+	s[len(s)-1] = name
+	e.typename = s
+	return s
+}
+
+// Everything but the last element of the full type name, CamelCased.
+// The values of type Foo.Bar are call Foo_value1... not Foo_Bar_value1... .
+func (e *EnumDescriptor) prefix() string {
+	typeName := e.TypeName()
+	ccPrefix := CamelCaseSlice(typeName[0:len(typeName)-1]) + "_"
+	if e.parent == nil {
+		// If the enum is not part of a message, the prefix is just the type name.
+		ccPrefix = CamelCase(*e.Name) + "_"
+	}
+	return ccPrefix
+}
+
+// The integer value of the named constant in this enumerated type.
+func (e *EnumDescriptor) integerValueAsString(name string) string {
+	for _, c := range e.Value {
+		if proto.GetString(c.Name) == name {
+			return fmt.Sprint(proto.GetInt32(c.Number))
+		}
+	}
+	log.Exit("cannot find value for enum constant")
+	return ""
+}
+
+// ExtensionDescriptor desribes an extension. If it's at top level, its parent will be nil.
+// Otherwise it will be the descriptor of the message in which it is defined.
+type ExtensionDescriptor struct {
+	common
+	*descriptor.FieldDescriptorProto
+	parent   *Descriptor // The containing message, if any.
+}
+
+// TypeName returns the elements of the dotted type name.
+// The package name is not part of this name.
+func (e *ExtensionDescriptor) TypeName() (s []string) {
+	name := proto.GetString(e.Name)
+	if e.parent == nil {
+		// top-level extension
+		s = make([]string, 1)
+	} else {
+		pname := e.parent.TypeName()
+		s = make([]string, len(pname)+1)
+		copy(s, pname)
+	}
+	s[len(s)-1] = name
+	return s
+}
+
+// FileDescriptor describes an protocol buffer descriptor file (.proto).
+// It includes slices of all the messages and enums defined within it.
+// Those slices are constructed by WrapTypes.
+type FileDescriptor struct {
+	*descriptor.FileDescriptorProto
+	desc []*Descriptor           // All the messages defined in this file.
+	enum []*EnumDescriptor       // All the enums defined in this file.
+	ext  []*ExtensionDescriptor  // All the top-level extensions defined in this file.
+}
+
+// PackageName is the package name we'll use in the generated code to refer to this file.
+func (d *FileDescriptor) PackageName() string { return uniquePackageOf(d.FileDescriptorProto) }
+
+// The package named defined in the input for this file, possibly dotted.
+func (d *FileDescriptor) originalPackageName() string {
+	return proto.GetString(d.Package)
+}
+
+// Whether the proto library needs importing.
+// This will be true if there are any enums, extensions, or messages with extension ranges.
+func (d *FileDescriptor) needProtoImport() bool {
+	if len(d.enum) > 0 || len(d.ext) > 0 {
+		return true
+	}
+	for _, desc := range d.desc {
+		if len(desc.ext) > 0 || len(desc.ExtensionRange) > 0 {
+			return true
+		}
+	}
+	return false
+}
+
+// Object is an interface abstracting the abilities shared by enums and messages.
+type Object interface {
+	PackageName() string // The name we use in our output (a_b_c), possibly renamed for uniqueness.
+	TypeName() []string
+}
+
+// Each package name we generate must be unique. The package we're generating
+// gets its own name but every other package must have a unqiue name that does
+// not conflict in the code we generate.  These names are chosen globally (although
+// they don't have to be, it simplifies things to do them globally).
+func uniquePackageOf(fd *descriptor.FileDescriptorProto) string {
+	s, ok := uniquePackageName[fd]
+	if !ok {
+		log.Exit("internal error: no package name defined for", proto.GetString(fd.Name))
+	}
+	return s
+}
+
+// Generator is the type whose methods generate the output, stored in the associated response structure.
+type Generator struct {
+	bytes.Buffer
+
+	Request  *plugin.CodeGeneratorRequest  // The input.
+	Response *plugin.CodeGeneratorResponse // The output.
+
+	packageName      string            // What we're calling ourselves.
+	allFiles         []*FileDescriptor // All files in the tree
+	genFiles         []*FileDescriptor // Those files we will generate output for.
+	file             *FileDescriptor   // The file we are compiling now.
+	typeNameToObject map[string]Object // Key is a fully-qualified name in input syntax.
+	indent           string
+}
+
+// New creates a new generator and allocates the request and response protobufs.
+func New() *Generator {
+	g := new(Generator)
+	g.Request = plugin.NewCodeGeneratorRequest()
+	g.Response = plugin.NewCodeGeneratorResponse()
+	return g
+}
+
+// Error reports a problem, including an os.Error, and exits the program.
+func (g *Generator) Error(err os.Error, msgs ...string) {
+	s := strings.Join(msgs, " ") + ":" + err.String()
+	log.Stderr("protoc-gen-go: error: ", s)
+	g.Response.Error = proto.String(s)
+	os.Exit(1)
+}
+
+// Fail reports a problem and exits the program.
+func (g *Generator) Fail(msgs ...string) {
+	s := strings.Join(msgs, " ")
+	log.Stderr("protoc-gen-go: error: ", s)
+	g.Response.Error = proto.String(s)
+	os.Exit(1)
+}
+
+// DefaultPackageName returns the package name printed for the object.
+// If its file is in a different package, it returns the package name we're using for this file, plus ".".
+// Otherwise it returns the empty string.
+func (g *Generator) DefaultPackageName(obj Object) string {
+	pkg := obj.PackageName()
+	if pkg == g.packageName {
+		return ""
+	}
+	return pkg + "."
+}
+
+// For each input file, the unique package name to use, underscored.
+var uniquePackageName = make(map[*descriptor.FileDescriptorProto]string)
+
+// SetPackageNames Sets the package name for this run.
+// The package name must agree across all files being generated.
+// It also defines unique package names for all imported files.
+func (g *Generator) SetPackageNames() {
+	inUse := make(map[string]bool)
+	pkg := proto.GetString(g.genFiles[0].Package)
+	g.packageName = strings.Map(DotToUnderscore, pkg)
+	inUse[pkg] = true
+	for _, f := range g.genFiles {
+		thisPkg := proto.GetString(f.Package)
+		if thisPkg != pkg {
+			g.Fail("inconsistent package names:", thisPkg, pkg)
+		}
+	}
+AllFiles:
+	for _, f := range g.allFiles {
+		for _, genf := range g.genFiles {
+			if f == genf {
+				// In this package already.
+				uniquePackageName[f.FileDescriptorProto] = g.packageName
+				continue AllFiles
+			}
+		}
+		truePkg := proto.GetString(f.Package)
+		pkg := truePkg
+		for {
+			_, present := inUse[pkg]
+			if present {
+				// It's a duplicate; must rename.
+				pkg += "X"
+				continue
+			}
+			break
+		}
+		// Install it.
+		inUse[pkg] = true
+		uniquePackageName[f.FileDescriptorProto] = strings.Map(DotToUnderscore, pkg)
+	}
+}
+
+// WrapTypes walks the incoming data, wrapping DescriptorProtos, EnumDescriptorProtos
+// and FileDescriptorProtos into file-referenced objects within the Generator.
+// It also creates the list of files to generate and so should be called before GenerateAllFiles.
+func (g *Generator) WrapTypes() {
+	g.allFiles = make([]*FileDescriptor, len(g.Request.ProtoFile))
+	for i, f := range g.Request.ProtoFile {
+		pkg := proto.GetString(f.Package)
+		if pkg == "" {
+			g.Fail(proto.GetString(f.Name), "is missing a package declaration")
+		}
+		// We must wrap the descriptors before we wrap the enums
+		descs := wrapDescriptors(f)
+		g.buildNestedDescriptors(descs)
+		enums := wrapEnumDescriptors(f, descs)
+		exts := wrapExtensions(f)
+		g.allFiles[i] = &FileDescriptor{
+			FileDescriptorProto: f,
+			desc:                descs,
+			enum:                enums,
+			ext:                 exts,
+		}
+	}
+
+	g.genFiles = make([]*FileDescriptor, len(g.Request.FileToGenerate))
+FindFiles:
+	for i, fileName := range g.Request.FileToGenerate {
+		// Search the list.  This algorithm is n^2 but n is tiny.
+		for _, file := range g.allFiles {
+			if fileName == proto.GetString(file.Name) {
+				g.genFiles[i] = file
+				continue FindFiles
+			}
+		}
+		g.Fail("could not find file named", fileName)
+	}
+	g.Response.File = make([]*plugin.CodeGeneratorResponse_File, len(g.genFiles))
+}
+
+// Scan the descriptors in this file.  For each one, build the slice of nested descriptors
+func (g *Generator) buildNestedDescriptors(descs []*Descriptor) {
+	for _, desc := range descs {
+		if len(desc.NestedType) != 0 {
+			desc.nested = make([]*Descriptor, len(desc.NestedType))
+			n := 0
+			for _, nest := range descs {
+				if nest.parent == desc {
+					desc.nested[n] = nest
+					n++
+				}
+			}
+			if n != len(desc.NestedType) {
+				g.Fail("internal error: nesting failure for", proto.GetString(desc.Name))
+			}
+		}
+	}
+}
+
+// Construct the Descriptor and add it to the slice
+func addDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto) []*Descriptor {
+	d := &Descriptor{common{File: file}, desc, parent, nil, nil, nil}
+
+	d.ext = make([]*ExtensionDescriptor, len(desc.Extension))
+	for i, field := range desc.Extension {
+		d.ext[i] = &ExtensionDescriptor{common{File: file}, field, d}
+	}
+
+	if len(sl) == cap(sl) {
+		nsl := make([]*Descriptor, len(sl), 2*len(sl))
+		copy(nsl, sl)
+		sl = nsl
+	}
+	sl = sl[0 : len(sl)+1]
+	sl[len(sl)-1] = d
+	return sl
+}
+
+// Return a slice of all the Descriptors defined within this file
+func wrapDescriptors(file *descriptor.FileDescriptorProto) []*Descriptor {
+	sl := make([]*Descriptor, 0, len(file.MessageType)+10)
+	for _, desc := range file.MessageType {
+		sl = wrapThisDescriptor(sl, desc, nil, file)
+	}
+	return sl
+}
+
+// Wrap this Descriptor, recursively
+func wrapThisDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto) []*Descriptor {
+	sl = addDescriptor(sl, desc, parent, file)
+	me := sl[len(sl)-1]
+	for _, nested := range desc.NestedType {
+		sl = wrapThisDescriptor(sl, nested, me, file)
+	}
+	return sl
+}
+
+// Construct the EnumDescriptor and add it to the slice
+func addEnumDescriptor(sl []*EnumDescriptor, desc *descriptor.EnumDescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto) []*EnumDescriptor {
+	if len(sl) == cap(sl) {
+		nsl := make([]*EnumDescriptor, len(sl), 2*len(sl))
+		copy(nsl, sl)
+		sl = nsl
+	}
+	sl = sl[0 : len(sl)+1]
+	sl[len(sl)-1] = &EnumDescriptor{common{File: file}, desc, parent, nil}
+	return sl
+}
+
+// Return a slice of all the EnumDescriptors defined within this file
+func wrapEnumDescriptors(file *descriptor.FileDescriptorProto, descs []*Descriptor) []*EnumDescriptor {
+	sl := make([]*EnumDescriptor, 0, len(file.EnumType)+10)
+	for _, enum := range file.EnumType {
+		sl = addEnumDescriptor(sl, enum, nil, file)
+	}
+	for _, nested := range descs {
+		sl = wrapEnumDescriptorsInMessage(sl, nested, file)
+	}
+	return sl
+}
+
+// Wrap this EnumDescriptor, recursively
+func wrapEnumDescriptorsInMessage(sl []*EnumDescriptor, desc *Descriptor, file *descriptor.FileDescriptorProto) []*EnumDescriptor {
+	for _, enum := range desc.EnumType {
+		sl = addEnumDescriptor(sl, enum, desc, file)
+	}
+	for _, nested := range desc.nested {
+		sl = wrapEnumDescriptorsInMessage(sl, nested, file)
+	}
+	return sl
+}
+
+// Return a slice of all the top-level ExtensionDescriptors defined within this file.
+func wrapExtensions(file *descriptor.FileDescriptorProto) []*ExtensionDescriptor {
+	sl := make([]*ExtensionDescriptor, len(file.Extension))
+	for i, field := range file.Extension {
+		sl[i] = &ExtensionDescriptor{common{File: file}, field, nil}
+	}
+	return sl
+}
+
+// BuildTypeNameMap builds the map from fully qualified type names to objects. 
+// The key names for the map come from the input data, which puts a period at the beginning.
+// It should be called after SetPackageNames and before GenerateAllFiles.
+func (g *Generator) BuildTypeNameMap() {
+	g.typeNameToObject = make(map[string]Object)
+	for _, f := range g.allFiles {
+		dottedPkg := "." + f.originalPackageName() + "."
+		for _, enum := range f.enum {
+			name := dottedPkg + dottedSlice(enum.TypeName())
+			g.typeNameToObject[name] = enum
+		}
+		for _, desc := range f.desc {
+			name := dottedPkg + dottedSlice(desc.TypeName())
+			g.typeNameToObject[name] = desc
+		}
+	}
+}
+
+// ObjectNamed, given a fully-qualified input type name as it appears in the input data,
+// returns the descriptor for the message or enum with that name.
+func (g *Generator) ObjectNamed(typeName string) Object {
+	f, ok := g.typeNameToObject[typeName]
+	if !ok {
+		g.Fail("can't find object with type", typeName)
+	}
+	return f
+}
+
+// P prints the arguments to the generated output.  It handles strings and int32s, plus
+// handling indirections because they may be *string, etc.
+func (g *Generator) P(str ...interface{}) {
+	g.WriteString(g.indent)
+	for _, v := range str {
+		switch s := v.(type) {
+		case string:
+			g.WriteString(s)
+		case *string:
+			g.WriteString(*s)
+		case *int32:
+			g.WriteString(fmt.Sprintf("%d", *s))
+		default:
+			g.Fail(fmt.Sprintf("unknown type in printer: %T", v))
+		}
+	}
+	g.WriteByte('\n')
+}
+
+// In Indents the output one tab stop.
+func (g *Generator) In() { g.indent += "\t" }
+
+// Out unindents the output one tab stop.
+func (g *Generator) Out() {
+	if len(g.indent) > 0 {
+		g.indent = g.indent[1:]
+	}
+}
+
+// GenerateAllFiles generates the output for all the files we're outputting.
+func (g *Generator) GenerateAllFiles() {
+	for i, file := range g.genFiles {
+		g.Reset()
+		g.generate(file)
+		g.runPlugins(file)
+		g.Response.File[i] = plugin.NewCodeGeneratorResponse_File()
+		g.Response.File[i].Name = proto.String(goFileName(*file.Name))
+		g.Response.File[i].Content = proto.String(g.String())
+	}
+}
+
+// Run all the plugins associated with the file.
+func (g *Generator) runPlugins(file *FileDescriptor) {
+	for _, p := range plugins {
+		p.Generate(g, file)
+	}
+}
+
+
+// FileOf return the FileDescriptor for this FileDescriptorProto.
+func (g *Generator) FileOf(fd *descriptor.FileDescriptorProto) *FileDescriptor {
+	for _, file := range g.allFiles {
+		if file.FileDescriptorProto == fd {
+			return file
+		}
+	}
+	g.Fail("could not find file in table:", proto.GetString(fd.Name))
+	return nil
+}
+
+// Fill the response protocol buffer with the generated output for all the files we're
+// supposed to generate.
+func (g *Generator) generate(file *FileDescriptor) {
+	g.file = g.FileOf(file.FileDescriptorProto)
+	g.generateHeader()
+	g.generateImports()
+	for _, enum := range g.file.enum {
+		g.generateEnum(enum)
+	}
+	for _, desc := range g.file.desc {
+		g.generateMessage(desc)
+	}
+	for _, ext := range g.file.ext {
+		g.generateExtension(ext)
+	}
+	g.generateInitFunction()
+}
+
+// Generate the header, including package definition and imports
+func (g *Generator) generateHeader() {
+	g.P("// Code generated by protoc-gen-go from ", Quote(*g.file.Name))
+	g.P("// DO NOT EDIT!")
+	g.P()
+	g.P("package ", g.file.PackageName())
+	g.P()
+}
+
+// Generate the header, including package definition and imports
+func (g *Generator) generateImports() {
+	if g.file.needProtoImport() {
+		g.P(`import "goprotobuf.googlecode.com/hg/proto"`)
+	}
+	for _, s := range g.file.Dependency {
+		// Need to find the descriptor for this file
+		for _, fd := range g.allFiles {
+			if proto.GetString(fd.Name) == s {
+				filename := goFileName(s)
+				if strings.HasSuffix(filename, ".go") {
+					filename = filename[0:len(filename)-3]
+				}
+				g.P("import ", fd.PackageName(), " ", Quote(filename))
+				break
+			}
+		}
+	}
+	g.P()
+	// TODO: may need to worry about uniqueness across plugins
+	for _, p := range plugins {
+		p.GenerateImports(g, g.file)
+		g.P()
+	}
+}
+
+// Generate the enum definitions for this EnumDescriptor.
+func (g *Generator) generateEnum(enum *EnumDescriptor) {
+	// The full type name
+	typeName := enum.TypeName()
+	// The full type name, CamelCased.
+	ccTypeName := CamelCaseSlice(typeName)
+	ccPrefix := enum.prefix()
+	g.P("type ", ccTypeName, " int32")
+	g.P("const (")
+	g.In()
+	for _, e := range enum.Value {
+		g.P(ccPrefix+*e.Name, " = ", e.Number)
+	}
+	g.Out()
+	g.P(")")
+	g.P("var ", ccTypeName, "_name = map[int32] string {")
+	g.In()
+	generated := make(map[int32] bool)	// avoid duplicate values
+	for _, e := range enum.Value {
+		duplicate := ""
+		if _, present := generated[*e.Number]; present {
+			duplicate = "// Duplicate value: "
+		}
+		g.P(duplicate, e.Number, ": ", Quote(*e.Name), ",")
+		generated[*e.Number] = true
+	}
+	g.Out()
+	g.P("}")
+	g.P("var ", ccTypeName, "_value = map[string] int32 {")
+	g.In()
+	for _, e := range enum.Value {
+		g.P(Quote(*e.Name), ": ", e.Number, ",")
+	}
+	g.Out()
+	g.P("}")
+	g.P("func New", ccTypeName, "(x int32) *", ccTypeName, " {")
+	g.In()
+	g.P("e := ", ccTypeName, "(x)")
+	g.P("return &e")
+	g.Out()
+	g.P("}")
+	g.P()
+}
+
+// The tag is a string like "PB(varint,2,opt,name=fieldname,def=7)" that
+// identifies details of the field for the protocol buffer marshaling and unmarshaling
+// code.  The fields are:
+//	wire encoding
+//	protocol tag number
+//	opt,req,rep for optional, required, or repeated
+//	name= the original declared name
+//	enum= the name of the enum type if it is an enum-typed field.
+//	def= string representation of the default value, if any.
+// The default value must be in a representation that can be used at run-time
+// to generate the default value. Thus bools become 0 and 1, for instance.
+func (g *Generator) goTag(field *descriptor.FieldDescriptorProto, wiretype string) string {
+	optrepreq := ""
+	switch {
+	case isOptional(field):
+		optrepreq = "opt"
+	case isRequired(field):
+		optrepreq = "req"
+	case isRepeated(field):
+		optrepreq = "rep"
+	}
+	defaultValue := proto.GetString(field.DefaultValue)
+	if defaultValue != "" {
+		switch *field.Type {
+		case descriptor.FieldDescriptorProto_TYPE_BOOL:
+			if defaultValue == "true" {
+				defaultValue = "1"
+			} else {
+				defaultValue = "0"
+			}
+		case descriptor.FieldDescriptorProto_TYPE_STRING,
+			descriptor.FieldDescriptorProto_TYPE_BYTES:
+			// Protect frogs.
+			defaultValue = Quote(defaultValue)
+			// Don't need the quotes
+			defaultValue = defaultValue[1 : len(defaultValue)-1]
+		case descriptor.FieldDescriptorProto_TYPE_ENUM:
+			// For enums we need to provide the integer constant.
+			obj := g.ObjectNamed(proto.GetString(field.TypeName))
+			enum, ok := obj.(*EnumDescriptor)
+			if !ok {
+				g.Fail("enum type inconsistent for", CamelCaseSlice(obj.TypeName()))
+			}
+			defaultValue = enum.integerValueAsString(defaultValue)
+		}
+		defaultValue = ",def=" + defaultValue
+	}
+	enum := ""
+	if *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM {
+		obj := g.ObjectNamed(proto.GetString(field.TypeName))
+		enum = ",enum=" + obj.PackageName() + "." + CamelCaseSlice(obj.TypeName())
+	}
+	name := proto.GetString(field.Name)
+	if name == CamelCase(name) {
+		name = ""
+	} else {
+		name = ",name=" + name
+	}
+	return Quote(fmt.Sprintf("PB(%s,%d,%s%s%s%s)",
+		wiretype,
+		proto.GetInt32(field.Number),
+		optrepreq,
+		name,
+		enum,
+		defaultValue))
+}
+
+func needsStar(typ descriptor.FieldDescriptorProto_Type) bool {
+	switch typ {
+	case descriptor.FieldDescriptorProto_TYPE_GROUP:
+		return false
+	case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
+		return false
+	case descriptor.FieldDescriptorProto_TYPE_BYTES:
+		return false
+	}
+	return true
+}
+
+// TypeName is the printed name appropriate for an item. If the object is in the current file,
+// TypeName drops the package name and underscores the rest.
+// Otherwise the object is from another package; and the result is  the underscored
+// package name followed by the item name.
+// The result always has an initial capital.
+func (g *Generator) TypeName(obj Object) string {
+	return g.DefaultPackageName(obj) + CamelCaseSlice(obj.TypeName())
+}
+
+// TypeNameWithPackage is like TypeName, but always includes the package
+// name even if the object is in our own package.
+func (g *Generator) TypeNameWithPackage(obj Object) string {
+	return obj.PackageName() + CamelCaseSlice(obj.TypeName())
+}
+
+// GoType returns a string representing the type name, and the wire type
+func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto) (typ string, wire string) {
+	// TODO: Options.
+	switch *field.Type {
+	case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
+		typ, wire = "float64", "fixed64"
+	case descriptor.FieldDescriptorProto_TYPE_FLOAT:
+		typ, wire = "float32", "fixed32"
+	case descriptor.FieldDescriptorProto_TYPE_INT64:
+		typ, wire = "int64", "varint"
+	case descriptor.FieldDescriptorProto_TYPE_UINT64:
+		typ, wire = "uint64", "varint"
+	case descriptor.FieldDescriptorProto_TYPE_INT32:
+		typ, wire = "int32", "varint"
+	case descriptor.FieldDescriptorProto_TYPE_UINT32:
+		typ, wire = "uint32", "varint"
+	case descriptor.FieldDescriptorProto_TYPE_FIXED64:
+		typ, wire = "uint64", "fixed64"
+	case descriptor.FieldDescriptorProto_TYPE_FIXED32:
+		typ, wire = "uint32", "fixed32"
+	case descriptor.FieldDescriptorProto_TYPE_BOOL:
+		typ, wire = "bool", "varint"
+	case descriptor.FieldDescriptorProto_TYPE_STRING:
+		typ, wire = "string", "bytes"
+	case descriptor.FieldDescriptorProto_TYPE_GROUP:
+		desc := g.ObjectNamed(proto.GetString(field.TypeName))
+		typ, wire = "*"+g.TypeName(desc), "group"
+	case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
+		desc := g.ObjectNamed(proto.GetString(field.TypeName))
+		typ, wire = "*"+g.TypeName(desc), "bytes"
+	case descriptor.FieldDescriptorProto_TYPE_BYTES:
+		typ, wire = "[]byte", "bytes"
+	case descriptor.FieldDescriptorProto_TYPE_ENUM:
+		desc := g.ObjectNamed(proto.GetString(field.TypeName))
+		typ, wire = g.TypeName(desc), "varint"
+	case descriptor.FieldDescriptorProto_TYPE_SFIXED32:
+		typ, wire = "int32", "fixed32"
+	case descriptor.FieldDescriptorProto_TYPE_SFIXED64:
+		typ, wire = "int64", "fixed64"
+	case descriptor.FieldDescriptorProto_TYPE_SINT32:
+		typ, wire = "int32", "zigzag32"
+	case descriptor.FieldDescriptorProto_TYPE_SINT64:
+		typ, wire = "int64", "zigzag64"
+	default:
+		g.Fail("unknown type for", proto.GetString(field.Name))
+	}
+	if isRepeated(field) {
+		typ = "[]" + typ
+	} else if needsStar(*field.Type) {
+		typ = "*" + typ
+	}
+	return
+}
+
+// Generate the type and default constant definitions for this Descriptor.
+func (g *Generator) generateMessage(message *Descriptor) {
+	// The full type name
+	typeName := message.TypeName()
+	// The full type name, CamelCased.
+	ccTypeName := CamelCaseSlice(typeName)
+
+	g.P("type ", ccTypeName, " struct {")
+	g.In()
+	for _, field := range message.Field {
+		fieldname := CamelCase(*field.Name)
+		typename, wiretype := g.GoType(message, field)
+		tag := g.goTag(field, wiretype)
+		g.P(fieldname, "\t", typename, "\t", tag)
+	}
+	if len(message.ExtensionRange) > 0 {
+		g.P("XXX_extensions\t\tmap[int32][]byte")
+	}
+	g.P("XXX_unrecognized\t[]byte")
+	g.Out()
+	g.P("}")
+
+	// Reset and New functions
+	g.P("func (this *", ccTypeName, ") Reset() {")
+	g.In()
+	g.P("*this = ", ccTypeName, "{}")
+	g.Out()
+	g.P("}")
+	g.P("func New", ccTypeName, "() *", ccTypeName, " {")
+	g.In()
+	g.P("return new(", ccTypeName, ")")
+	g.Out()
+	g.P("}")
+
+	// Extension support methods
+	if len(message.ExtensionRange) > 0 {
+		g.P()
+		g.P("var extRange_", ccTypeName, " = []proto.ExtensionRange{")
+		g.In()
+		for _, r := range message.ExtensionRange {
+			end := fmt.Sprint(*r.End - 1)  // make range inclusive on both ends
+			g.P("proto.ExtensionRange{", r.Start, ", ", end, "},")
+		}
+		g.Out()
+		g.P("}")
+		g.P("func (*", ccTypeName, ") ExtensionRangeArray() []proto.ExtensionRange {")
+		g.In()
+		g.P("return extRange_", ccTypeName)
+		g.Out()
+		g.P("}")
+		g.P("func (this *", ccTypeName, ") ExtensionMap() map[int32][]byte {")
+		g.In()
+		g.P("if this.XXX_extensions == nil {")
+		g.In()
+		g.P("this.XXX_extensions = make(map[int32][]byte)")
+		g.Out()
+		g.P("}")
+		g.P("return this.XXX_extensions")
+		g.Out()
+		g.P("}")
+	}
+
+	// Default constants
+	for _, field := range message.Field {
+		def := proto.GetString(field.DefaultValue)
+		if def == "" {
+			continue
+		}
+		fieldname := "Default_" + ccTypeName + "_" + CamelCase(*field.Name)
+		typename, _ := g.GoType(message, field)
+		if typename[0] == '*' {
+			typename = typename[1:]
+		}
+		kind := "const "
+		switch {
+		case typename == "bool":
+		case typename == "string":
+			def = Quote(def)
+		case typename == "[]byte":
+			def = "[]byte(" + Quote(def) + ")"
+			kind = "var "
+		case *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM:
+			// Must be an enum.  Need to construct the prefixed name.
+			obj := g.ObjectNamed(proto.GetString(field.TypeName))
+			enum, ok := obj.(*EnumDescriptor)
+			if !ok {
+				log.Stderr("don't know how to generate constant for", fieldname)
+				continue
+			}
+			def = enum.prefix() + def
+		}
+		g.P(kind, fieldname, " ", typename, " = ", def)
+	}
+	g.P()
+
+	for _, ext := range message.ext {
+		g.generateExtension(ext)
+	}
+}
+
+func (g *Generator) generateExtension(ext *ExtensionDescriptor) {
+	// The full type name
+	typeName := ext.TypeName()
+	// Each scope of the extension is individually CamelCased, and all are joined with "_" with an "E_" prefix.
+	for i, s := range typeName {
+		typeName[i] = CamelCase(s)
+	}
+	ccTypeName := "E_" + strings.Join(typeName, "_")
+
+	extendedType := "*" + g.TypeName(g.ObjectNamed(*ext.Extendee))
+	field := ext.FieldDescriptorProto
+	fieldType, wireType := g.GoType(ext.parent, field)
+	tag := g.goTag(field, wireType)
+
+	g.P("var ", ccTypeName, " = &proto.ExtensionDesc{")
+	g.In()
+	g.P("ExtendedType: (", extendedType, ")(nil),")
+	g.P("ExtensionType: (", fieldType, ")(nil),")
+	g.P("Field: ", field.Number, ",")
+	g.P("Tag: ", tag, ",")
+
+	g.Out()
+	g.P("}")
+	g.P()
+}
+
+func (g *Generator) generateInitFunction() {
+	g.P("func init() {")
+	g.In()
+	for _, enum := range g.file.enum {
+		g.generateEnumRegistration(enum)
+	}
+	g.Out()
+	g.P("}")
+}
+
+func (g *Generator) generateEnumRegistration(enum *EnumDescriptor) {
+	pkg := g.packageName + "." // We always print the full package name here.
+	// The full type name
+	typeName := enum.TypeName()
+	// The full type name, CamelCased.
+	ccTypeName := CamelCaseSlice(typeName)
+	g.P("proto.RegisterEnum(", Quote(pkg+ccTypeName), ", ", ccTypeName+"_name, ", ccTypeName+"_value)")
+}
+
+// And now lots of helper functions.
+
+// CamelCase returns the CamelCased name.  Given foo_bar_Baz, the result is FooBar_Baz.
+func CamelCase(name string) string {
+	elems := strings.Split(name, "_", 0)
+	for i, e := range elems {
+		if e == "" {
+			elems[i] = "_"
+			continue
+		}
+		runes := []int(e)
+		if unicode.IsLower(runes[0]) {
+			runes[0] = unicode.ToUpper(runes[0])
+			elems[i] = string(runes)
+		} else {
+			if i > 0 {
+				elems[i] = "_" + e
+			}
+		}
+	}
+	s := strings.Join(elems, "")
+	// Name must not begin with an underscore.
+	if len(s) > 0 && s[0] == '_' {
+		s = "X" + s[1:]
+	}
+	return s
+}
+
+// CamelCaseSlice is like CamelCase, but the argument is a slice of strings to
+// be joined with "_".
+func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem, "_")) }
+
+// dottedSlice turns a sliced name into a dotted name.
+func dottedSlice(elem []string) string { return strings.Join(elem, ".") }
+
+// Quote returns a Go-source quoted string representation of s.
+func Quote(s string) string { return fmt.Sprintf("%q", s) }
+
+// Given a .proto file name, return the output name for the generated Go program.
+func goFileName(name string) string {
+	if strings.HasSuffix(name, ".proto") {
+		name = name[0 : len(name)-6]
+	}
+	return name + ".pb.go"
+}
+
+// Is this field optional?
+func isOptional(field *descriptor.FieldDescriptorProto) bool {
+	return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_OPTIONAL
+}
+
+// Is this field required?
+func isRequired(field *descriptor.FieldDescriptorProto) bool {
+	return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REQUIRED
+}
+
+// Is this field repeated?
+func isRepeated(field *descriptor.FieldDescriptorProto) bool {
+	return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED
+}
+
+// DotToUnderscore is the mapping function used to generate Go names from package names,
+// which can be dotted in the input .proto file.
+func DotToUnderscore(rune int) int {
+	if rune == '.' {
+		return '_'
+	}
+	return rune
+}

+ 10 - 943
compiler/main.go

@@ -35,44 +35,35 @@
 	This plugin takes no options and the protocol buffer file syntax does
 	This plugin takes no options and the protocol buffer file syntax does
 	not yet define any options for Go, so program does no option evaluation.
 	not yet define any options for Go, so program does no option evaluation.
 	That may change.
 	That may change.
-
-	Not supported yet:
-		Services
 */
 */
 
 
 package main
 package main
 
 
 import (
 import (
-	"bytes"
-	"fmt"
 	"io/ioutil"
 	"io/ioutil"
-	"log"
 	"os"
 	"os"
-	"strings"
-	"unicode"
 
 
 	"goprotobuf.googlecode.com/hg/proto"
 	"goprotobuf.googlecode.com/hg/proto"
-	plugin "goprotobuf.googlecode.com/hg/compiler/plugin"
-	descriptor "goprotobuf.googlecode.com/hg/compiler/descriptor"
+	"goprotobuf.googlecode.com/hg/compiler/generator"
 )
 )
 
 
 func main() {
 func main() {
 	// Begin by allocating a generator. The request and response structures are stored there
 	// Begin by allocating a generator. The request and response structures are stored there
 	// so we can do error handling easily - the response structure contains the field to
 	// so we can do error handling easily - the response structure contains the field to
 	// report failure.
 	// report failure.
-	g := NewGenerator()
+	g := generator.New()
 
 
 	data, err := ioutil.ReadAll(os.Stdin)
 	data, err := ioutil.ReadAll(os.Stdin)
 	if err != nil {
 	if err != nil {
-		g.error(err, "reading input")
+		g.Error(err, "reading input")
 	}
 	}
 
 
-	if err := proto.Unmarshal(data, g.request); err != nil {
-		g.error(err, "parsing input proto")
+	if err := proto.Unmarshal(data, g.Request); err != nil {
+		g.Error(err, "parsing input proto")
 	}
 	}
 
 
-	if len(g.request.FileToGenerate) == 0 {
-		g.fail("no files to generate")
+	if len(g.Request.FileToGenerate) == 0 {
+		g.Fail("no files to generate")
 	}
 	}
 
 
 	// Create a wrapped version of the Descriptors and EnumDescriptors that
 	// Create a wrapped version of the Descriptors and EnumDescriptors that
@@ -85,936 +76,12 @@ func main() {
 	g.GenerateAllFiles()
 	g.GenerateAllFiles()
 
 
 	// Send back the results.
 	// Send back the results.
-	data, err = proto.Marshal(g.response)
+	data, err = proto.Marshal(g.Response)
 	if err != nil {
 	if err != nil {
-		g.error(err, "failed to marshal output proto")
+		g.Error(err, "failed to marshal output proto")
 	}
 	}
 	_, err = os.Stdout.Write(data)
 	_, err = os.Stdout.Write(data)
 	if err != nil {
 	if err != nil {
-		g.error(err, "failed to write output proto")
-	}
-}
-
-// Each type we import as a protocol buffer (other than FileDescriptorProto) needs
-// a pointer to the FileDescriptorProto that represents it.  These types achieve that
-// wrapping by placing each Proto inside a struct with the pointer to its File. The
-// structs have the same names as their contents, with "Proto" removed.
-// FileDescriptor is used to store the things that it points to.
-
-// The file and package name method are common to messages and enums.
-type common struct {
-	file *descriptor.FileDescriptorProto // File this object comes from.
-}
-
-// The package name we will produce in our output.
-func (c *common) packageName() string { return uniquePackageOf(c.file) }
-
-// A message (struct).
-type Descriptor struct {
-	common
-	*descriptor.DescriptorProto
-	parent   *Descriptor            // The containing message, if any.
-	nested   []*Descriptor          // Inner messages, if any.
-	ext      []*ExtensionDescriptor // Extensions, if any.
-	typename []string               // Cached typename vector.
-}
-
-// Return the elements of the dotted type name.  The package name is not part
-// of this name.
-func (d *Descriptor) typeName() []string {
-	if d.typename != nil {
-		return d.typename
-	}
-	n := 0
-	for parent := d; parent != nil; parent = parent.parent {
-		n++
-	}
-	s := make([]string, n, n)
-	for parent := d; parent != nil; parent = parent.parent {
-		n--
-		s[n] = proto.GetString(parent.Name)
-	}
-	d.typename = s
-	return s
-}
-
-// An enum. If it's at top level, its parent will be nil. Otherwise it will be
-// the descriptor of the message in which it is defined.
-type EnumDescriptor struct {
-	common
-	*descriptor.EnumDescriptorProto
-	parent   *Descriptor // The containing message, if any.
-	typename []string    // Cached typename vector.
-}
-
-// Return the elements of the dotted type name.
-func (e *EnumDescriptor) typeName() (s []string) {
-	if e.typename != nil {
-		return e.typename
-	}
-	name := proto.GetString(e.Name)
-	if e.parent == nil {
-		s = make([]string, 1)
-	} else {
-		pname := e.parent.typeName()
-		s = make([]string, len(pname)+1)
-		copy(s, pname)
-	}
-	s[len(s)-1] = name
-	e.typename = s
-	return s
-}
-
-// Everything but the last element of the full type name, CamelCased.
-// The values of type Foo.Bar are call Foo_value1... not Foo_Bar_value1... .
-func (e *EnumDescriptor) prefix() string {
-	typeName := e.typeName()
-	ccPrefix := CamelCaseSlice(typeName[0:len(typeName)-1]) + "_"
-	if e.parent == nil {
-		// If the enum is not part of a message, the prefix is just the type name.
-		ccPrefix = CamelCase(*e.Name) + "_"
-	}
-	return ccPrefix
-}
-
-// The integer value of the named constant in this enumerated type.
-func (e *EnumDescriptor) integerValueAsString(name string) string {
-	for _, c := range e.Value {
-		if proto.GetString(c.Name) == name {
-			return fmt.Sprint(proto.GetInt32(c.Number))
-		}
-	}
-	log.Exit("cannot find value for enum constant")
-	return ""
-}
-
-// An extension. If it's at top level, its parent will be nil. Otherwise it will be
-// the descriptor of the message in which it is defined.
-type ExtensionDescriptor struct {
-	common
-	*descriptor.FieldDescriptorProto
-	parent   *Descriptor // The containing message, if any.
-}
-
-// Return the elements of the dotted type name.
-func (e *ExtensionDescriptor) typeName() (s []string) {
-	name := proto.GetString(e.Name)
-	if e.parent == nil {
-		// top-level extension
-		s = make([]string, 1)
-	} else {
-		pname := e.parent.typeName()
-		s = make([]string, len(pname)+1)
-		copy(s, pname)
-	}
-	s[len(s)-1] = name
-	return s
-}
-
-// A file. Includes slices of all the messages and enums defined within it.
-// Those slices are constructed by WrapTypes.
-type FileDescriptor struct {
-	*descriptor.FileDescriptorProto
-	desc []*Descriptor           // All the messages defined in this file.
-	enum []*EnumDescriptor       // All the enums defined in this file.
-	ext  []*ExtensionDescriptor  // All the top-level extensions defined in this file.
-}
-
-// The package name we'll use in the generated code to refer to this file.
-func (d *FileDescriptor) packageName() string { return uniquePackageOf(d.FileDescriptorProto) }
-
-// The package named defined in the input for this file, possibly dotted.
-func (d *FileDescriptor) originalPackageName() string {
-	return proto.GetString(d.Package)
-}
-
-// Whether the proto library needs importing.
-// This will be true if there are any enums or any extensions, or any messages with extension ranges.
-func (d *FileDescriptor) needProtoImport() bool {
-	if len(d.enum) > 0 || len(d.ext) > 0 {
-		return true
-	}
-	for _, desc := range d.desc {
-		if len(desc.ext) > 0 || len(desc.ExtensionRange) > 0 {
-			return true
-		}
-	}
-	return false
-}
-
-// Simplify some things by abstracting the abilities shared by enums and messages.
-type Object interface {
-	packageName() string // The name we use in our output (a_b_c), possibly renamed for uniqueness.
-	typeName() []string
-}
-
-// Each package name we generate must be unique. The package we're generating
-// gets its own name but every other package must have a unqiue name that does
-// not conflict in the code we generate.  These names are chosen globally (although
-// they don't have to be, it simplifies things to do them globally).
-func uniquePackageOf(fd *descriptor.FileDescriptorProto) string {
-	s, ok := uniquePackageName[fd]
-	if !ok {
-		log.Exit("internal error: no package name defined for", proto.GetString(fd.Name))
-	}
-	return s
-}
-
-// The type whose methods generate the output, stored in the associated response structure.
-type Generator struct {
-	bytes.Buffer
-
-	request  *plugin.CodeGeneratorRequest  // The input.
-	response *plugin.CodeGeneratorResponse // The output.
-
-	packageName      string            // What we're calling ourselves.
-	allFiles         []*FileDescriptor // All files in the tree
-	genFiles         []*FileDescriptor // Those files we will generate output for.
-	file             *FileDescriptor   // The file we are compiling now.
-	typeNameToObject map[string]Object // Key is a fully-qualified name in input syntax.
-	indent           string
-}
-
-// Create a new generator and allocate the request and response protobufs.
-func NewGenerator() *Generator {
-	g := new(Generator)
-	g.request = plugin.NewCodeGeneratorRequest()
-	g.response = plugin.NewCodeGeneratorResponse()
-	return g
-}
-
-// Report problem, including an os.Error, and fail.
-func (g *Generator) error(err os.Error, msgs ...string) {
-	s := strings.Join(msgs, " ") + ":" + err.String()
-	log.Stderr("protoc-gen-go: error: ", s)
-	g.response.Error = proto.String(s)
-	os.Exit(1)
-}
-
-// Report problem and fail.
-func (g *Generator) fail(msgs ...string) {
-	s := strings.Join(msgs, " ")
-	log.Stderr("protoc-gen-go: error: ", s)
-	g.response.Error = proto.String(s)
-	os.Exit(1)
-}
-
-// If this file is in a different package, return the package name we're using for this file, plus ".".
-// Otherwise return the empty string.
-func (g *Generator) DefaultPackageName(obj Object) string {
-	pkg := obj.packageName()
-	if pkg == g.packageName {
-		return ""
-	}
-	return pkg + "."
-}
-
-// For each input file, the unique package name to use, underscored.
-var uniquePackageName = make(map[*descriptor.FileDescriptorProto]string)
-
-// Set the package name for this run.  It must agree across all files being generated.
-// Also define unique package names for all imported files.
-func (g *Generator) SetPackageNames() {
-	inUse := make(map[string]bool)
-	pkg := proto.GetString(g.genFiles[0].Package)
-	g.packageName = strings.Map(DotToUnderscore, pkg)
-	inUse[pkg] = true
-	for _, f := range g.genFiles {
-		thisPkg := proto.GetString(f.Package)
-		if thisPkg != pkg {
-			g.fail("inconsistent package names:", thisPkg, pkg)
-		}
-	}
-AllFiles:
-	for _, f := range g.allFiles {
-		for _, genf := range g.genFiles {
-			if f == genf {
-				// In this package already.
-				uniquePackageName[f.FileDescriptorProto] = g.packageName
-				continue AllFiles
-			}
-		}
-		truePkg := proto.GetString(f.Package)
-		pkg := truePkg
-		for {
-			_, present := inUse[pkg]
-			if present {
-				// It's a duplicate; must rename.
-				pkg += "X"
-				continue
-			}
-			break
-		}
-		// Install it.
-		inUse[pkg] = true
-		uniquePackageName[f.FileDescriptorProto] = strings.Map(DotToUnderscore, pkg)
-	}
-}
-
-// Walk the incoming data, wrapping DescriptorProtos, EnumDescriptorProtos and FileDescriptorProtos
-// into file-referenced objects within the Generator.  Also create the list of files
-// to generate
-func (g *Generator) WrapTypes() {
-	g.allFiles = make([]*FileDescriptor, len(g.request.ProtoFile))
-	for i, f := range g.request.ProtoFile {
-		pkg := proto.GetString(f.Package)
-		if pkg == "" {
-			g.fail(proto.GetString(f.Name), "is missing a package declaration")
-		}
-		// We must wrap the descriptors before we wrap the enums
-		descs := WrapDescriptors(f)
-		g.BuildNestedDescriptors(descs)
-		enums := WrapEnumDescriptors(f, descs)
-		exts := WrapExtensions(f)
-		g.allFiles[i] = &FileDescriptor{
-			FileDescriptorProto: f,
-			desc:                descs,
-			enum:                enums,
-			ext:                 exts,
-		}
-	}
-
-	g.genFiles = make([]*FileDescriptor, len(g.request.FileToGenerate))
-FindFiles:
-	for i, fileName := range g.request.FileToGenerate {
-		// Search the list.  This algorithm is n^2 but n is tiny.
-		for _, file := range g.allFiles {
-			if fileName == proto.GetString(file.Name) {
-				g.genFiles[i] = file
-				continue FindFiles
-			}
-		}
-		g.fail("could not find file named", fileName)
-	}
-	g.response.File = make([]*plugin.CodeGeneratorResponse_File, len(g.genFiles))
-}
-
-// Scan the descriptors in this file.  For each one, build the slice of nested descriptors
-func (g *Generator) BuildNestedDescriptors(descs []*Descriptor) {
-	for _, desc := range descs {
-		if len(desc.NestedType) != 0 {
-			desc.nested = make([]*Descriptor, len(desc.NestedType))
-			n := 0
-			for _, nest := range descs {
-				if nest.parent == desc {
-					desc.nested[n] = nest
-					n++
-				}
-			}
-			if n != len(desc.NestedType) {
-				g.fail("internal error: nesting failure for", proto.GetString(desc.Name))
-			}
-		}
-	}
-}
-
-// Construct the Descriptor and add it to the slice
-func AddDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto) []*Descriptor {
-	d := &Descriptor{common{file: file}, desc, parent, nil, nil, nil}
-
-	d.ext = make([]*ExtensionDescriptor, len(desc.Extension))
-	for i, field := range desc.Extension {
-		d.ext[i] = &ExtensionDescriptor{common{file: file}, field, d}
-	}
-
-	if len(sl) == cap(sl) {
-		nsl := make([]*Descriptor, len(sl), 2*len(sl))
-		copy(nsl, sl)
-		sl = nsl
-	}
-	sl = sl[0 : len(sl)+1]
-	sl[len(sl)-1] = d
-	return sl
-}
-
-// Return a slice of all the Descriptors defined within this file
-func WrapDescriptors(file *descriptor.FileDescriptorProto) []*Descriptor {
-	sl := make([]*Descriptor, 0, len(file.MessageType)+10)
-	for _, desc := range file.MessageType {
-		sl = WrapThisDescriptor(sl, desc, nil, file)
-	}
-	return sl
-}
-
-// Wrap this Descriptor, recursively
-func WrapThisDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto) []*Descriptor {
-	sl = AddDescriptor(sl, desc, parent, file)
-	me := sl[len(sl)-1]
-	for _, nested := range desc.NestedType {
-		sl = WrapThisDescriptor(sl, nested, me, file)
-	}
-	return sl
-}
-
-// Construct the EnumDescriptor and add it to the slice
-func AddEnumDescriptor(sl []*EnumDescriptor, desc *descriptor.EnumDescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto) []*EnumDescriptor {
-	if len(sl) == cap(sl) {
-		nsl := make([]*EnumDescriptor, len(sl), 2*len(sl))
-		copy(nsl, sl)
-		sl = nsl
-	}
-	sl = sl[0 : len(sl)+1]
-	sl[len(sl)-1] = &EnumDescriptor{common{file: file}, desc, parent, nil}
-	return sl
-}
-
-// Return a slice of all the EnumDescriptors defined within this file
-func WrapEnumDescriptors(file *descriptor.FileDescriptorProto, descs []*Descriptor) []*EnumDescriptor {
-	sl := make([]*EnumDescriptor, 0, len(file.EnumType)+10)
-	for _, enum := range file.EnumType {
-		sl = AddEnumDescriptor(sl, enum, nil, file)
-	}
-	for _, nested := range descs {
-		sl = WrapEnumDescriptorsInMessage(sl, nested, file)
-	}
-	return sl
-}
-
-// Wrap this EnumDescriptor, recursively
-func WrapEnumDescriptorsInMessage(sl []*EnumDescriptor, desc *Descriptor, file *descriptor.FileDescriptorProto) []*EnumDescriptor {
-	for _, enum := range desc.EnumType {
-		sl = AddEnumDescriptor(sl, enum, desc, file)
-	}
-	for _, nested := range desc.nested {
-		sl = WrapEnumDescriptorsInMessage(sl, nested, file)
-	}
-	return sl
-}
-
-// Return a slice of all the top-level ExtensionDescriptors defined within this file.
-func WrapExtensions(file *descriptor.FileDescriptorProto) []*ExtensionDescriptor {
-	sl := make([]*ExtensionDescriptor, len(file.Extension))
-	for i, field := range file.Extension {
-		sl[i] = &ExtensionDescriptor{common{file: file}, field, nil}
-	}
-	return sl
-}
-
-// Build the map from fully qualified type names to objects.  The key for the map
-// comes from the input data, which puts a period at the beginning.
-func (g *Generator) BuildTypeNameMap() {
-	g.typeNameToObject = make(map[string]Object)
-	for _, f := range g.allFiles {
-		dottedPkg := "." + f.originalPackageName() + "."
-		for _, enum := range f.enum {
-			name := dottedPkg + DottedSlice(enum.typeName())
-			g.typeNameToObject[name] = enum
-		}
-		for _, desc := range f.desc {
-			name := dottedPkg + DottedSlice(desc.typeName())
-			g.typeNameToObject[name] = desc
-		}
-	}
-}
-
-// Given a fully-qualified input type name, return the descriptor for the message or enum with that type.
-func (g *Generator) objectNamed(typeName string) Object {
-	f, ok := g.typeNameToObject[typeName]
-	if !ok {
-		g.fail("can't find object with type", typeName)
-	}
-	return f
-}
-
-// Print the arguments, handling indirections because they may be *string, etc.
-func (g *Generator) p(str ...interface{}) {
-	g.WriteString(g.indent)
-	for _, v := range str {
-		switch s := v.(type) {
-		case string:
-			g.WriteString(s)
-		case *string:
-			g.WriteString(*s)
-		case *int32:
-			g.WriteString(fmt.Sprintf("%d", *s))
-		default:
-			g.fail(fmt.Sprintf("unknown type in printer: %T", v))
-		}
-	}
-	g.WriteByte('\n')
-}
-
-// Indent the output one tab stop.
-func (g *Generator) in() { g.indent += "\t" }
-
-// Unindent the output one tab stop.
-func (g *Generator) out() {
-	if len(g.indent) > 0 {
-		g.indent = g.indent[1:]
-	}
-}
-
-// Generate the output for all the files we're generating output for.
-func (g *Generator) GenerateAllFiles() {
-	for i, file := range g.genFiles {
-		g.Reset()
-		g.Generate(file)
-		g.response.File[i] = plugin.NewCodeGeneratorResponse_File()
-		g.response.File[i].Name = proto.String(GoName(*file.Name))
-		g.response.File[i].Content = proto.String(g.String())
-	}
-}
-
-// Return the FileDescriptor for this FileDescriptorProto
-func (g *Generator) FileOf(fd *descriptor.FileDescriptorProto) *FileDescriptor {
-	for _, file := range g.allFiles {
-		if file.FileDescriptorProto == fd {
-			return file
-		}
-	}
-	g.fail("could not find file in table:", proto.GetString(fd.Name))
-	return nil
-}
-
-// Fill the response protocol buffer with the generated output for all the files we're
-// supposed to generate.
-func (g *Generator) Generate(file *FileDescriptor) {
-	g.file = g.FileOf(file.FileDescriptorProto)
-	g.GenerateHeader()
-	g.GenerateImports()
-	for _, enum := range g.file.enum {
-		g.GenerateEnum(enum)
-	}
-	for _, desc := range g.file.desc {
-		g.GenerateMessage(desc)
-	}
-	for _, ext := range g.file.ext {
-		g.GenerateExtension(ext)
-	}
-	g.GenerateInitFunction()
-}
-
-// Generate the header, including package definition and imports
-func (g *Generator) GenerateHeader() {
-	g.p("// Code generated by protoc-gen-go from ", Quote(*g.file.Name))
-	g.p("// DO NOT EDIT!")
-	g.p()
-	g.p("package ", g.file.packageName())
-	g.p()
-}
-
-// Generate the header, including package definition and imports
-func (g *Generator) GenerateImports() {
-	if g.file.needProtoImport() {
-		g.p(`import "goprotobuf.googlecode.com/hg/proto"`)
-	}
-	for _, s := range g.file.Dependency {
-		// Need to find the descriptor for this file
-		for _, fd := range g.allFiles {
-			if proto.GetString(fd.Name) == s {
-				filename := GoName(s)
-				if strings.HasSuffix(filename, ".go") {
-					filename = filename[0:len(filename)-3]
-				}
-				g.p("import ", fd.packageName(), " ", Quote(filename))
-				break
-			}
-		}
-	}
-	g.p()
-}
-
-// Generate the enum definitions for this EnumDescriptor.
-func (g *Generator) GenerateEnum(enum *EnumDescriptor) {
-	// The full type name
-	typeName := enum.typeName()
-	// The full type name, CamelCased.
-	ccTypeName := CamelCaseSlice(typeName)
-	ccPrefix := enum.prefix()
-	g.p("type ", ccTypeName, " int32")
-	g.p("const (")
-	g.in()
-	for _, e := range enum.Value {
-		g.p(ccPrefix+*e.Name, " = ", e.Number)
-	}
-	g.out()
-	g.p(")")
-	g.p("var ", ccTypeName, "_name = map[int32] string {")
-	g.in()
-	generated := make(map[int32] bool)	// avoid duplicate values
-	for _, e := range enum.Value {
-		duplicate := ""
-		if _, present := generated[*e.Number]; present {
-			duplicate = "// Duplicate value: "
-		}
-		g.p(duplicate, e.Number, ": ", Quote(*e.Name), ",")
-		generated[*e.Number] = true
-	}
-	g.out()
-	g.p("}")
-	g.p("var ", ccTypeName, "_value = map[string] int32 {")
-	g.in()
-	for _, e := range enum.Value {
-		g.p(Quote(*e.Name), ": ", e.Number, ",")
-	}
-	g.out()
-	g.p("}")
-	g.p("func New", ccTypeName, "(x int32) *", ccTypeName, " {")
-	g.in()
-	g.p("e := ", ccTypeName, "(x)")
-	g.p("return &e")
-	g.out()
-	g.p("}")
-	g.p()
-}
-
-// The tag is a string like "PB(varint,2,opt,name=fieldname,def=7)" that
-// identifies details of the field for the protocol buffer marshaling and unmarshaling
-// code.  The fields are:
-//	wire encoding
-//	protocol tag number
-//	opt,req,rep for optional, required, or repeated
-//	name= the original declared name
-//	enum= the name of the enum type if it is an enum-typed field.
-//	def= string representation of the default value, if any.
-// The default value must be in a representation that can be used at run-time
-// to generate the default value. Thus bools become 0 and 1, for instance.
-func (g *Generator) GoTag(field *descriptor.FieldDescriptorProto, wiretype string) string {
-	optrepreq := ""
-	switch {
-	case IsOptional(field):
-		optrepreq = "opt"
-	case IsRequired(field):
-		optrepreq = "req"
-	case IsRepeated(field):
-		optrepreq = "rep"
-	}
-	defaultValue := proto.GetString(field.DefaultValue)
-	if defaultValue != "" {
-		switch *field.Type {
-		case descriptor.FieldDescriptorProto_TYPE_BOOL:
-			if defaultValue == "true" {
-				defaultValue = "1"
-			} else {
-				defaultValue = "0"
-			}
-		case descriptor.FieldDescriptorProto_TYPE_STRING,
-			descriptor.FieldDescriptorProto_TYPE_BYTES:
-			// Protect frogs.
-			defaultValue = Quote(defaultValue)
-			// Don't need the quotes
-			defaultValue = defaultValue[1 : len(defaultValue)-1]
-		case descriptor.FieldDescriptorProto_TYPE_ENUM:
-			// For enums we need to provide the integer constant.
-			obj := g.objectNamed(proto.GetString(field.TypeName))
-			enum, ok := obj.(*EnumDescriptor)
-			if !ok {
-				g.fail("enum type inconsistent for", CamelCaseSlice(obj.typeName()))
-			}
-			defaultValue = enum.integerValueAsString(defaultValue)
-		}
-		defaultValue = ",def=" + defaultValue
-	}
-	enum := ""
-	if *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM {
-		obj := g.objectNamed(proto.GetString(field.TypeName))
-		enum = ",enum=" + obj.packageName() + "." + CamelCaseSlice(obj.typeName())
-	}
-	name := proto.GetString(field.Name)
-	if name == CamelCase(name) {
-		name = ""
-	} else {
-		name = ",name=" + name
-	}
-	return Quote(fmt.Sprintf("PB(%s,%d,%s%s%s%s)",
-		wiretype,
-		proto.GetInt32(field.Number),
-		optrepreq,
-		name,
-		enum,
-		defaultValue))
-}
-
-func NeedsStar(typ descriptor.FieldDescriptorProto_Type) bool {
-	switch typ {
-	case descriptor.FieldDescriptorProto_TYPE_GROUP:
-		return false
-	case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
-		return false
-	case descriptor.FieldDescriptorProto_TYPE_BYTES:
-		return false
-	}
-	return true
-}
-
-// The type name appropriate for an item. If it's in the current file,
-// drop the package name and underscore the rest.
-// Otherwise it's from another package; use the underscored package name
-// followed by the field name.  The result has an initial capital.
-func (g *Generator) TypeName(obj Object) string {
-	return g.DefaultPackageName(obj) + CamelCaseSlice(obj.typeName())
-}
-
-// Like TypeName, but always includes the package name even if it's our own package.
-func (g *Generator) TypeNameWithPackage(obj Object) string {
-	return obj.packageName() + CamelCaseSlice(obj.typeName())
-}
-
-// Returns a string representing the type name, and the wire type
-func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto) (typ string, wire string) {
-	// TODO: Options.
-	switch *field.Type {
-	case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
-		typ, wire = "float64", "fixed64"
-	case descriptor.FieldDescriptorProto_TYPE_FLOAT:
-		typ, wire = "float32", "fixed32"
-	case descriptor.FieldDescriptorProto_TYPE_INT64:
-		typ, wire = "int64", "varint"
-	case descriptor.FieldDescriptorProto_TYPE_UINT64:
-		typ, wire = "uint64", "varint"
-	case descriptor.FieldDescriptorProto_TYPE_INT32:
-		typ, wire = "int32", "varint"
-	case descriptor.FieldDescriptorProto_TYPE_UINT32:
-		typ, wire = "uint32", "varint"
-	case descriptor.FieldDescriptorProto_TYPE_FIXED64:
-		typ, wire = "uint64", "fixed64"
-	case descriptor.FieldDescriptorProto_TYPE_FIXED32:
-		typ, wire = "uint32", "fixed32"
-	case descriptor.FieldDescriptorProto_TYPE_BOOL:
-		typ, wire = "bool", "varint"
-	case descriptor.FieldDescriptorProto_TYPE_STRING:
-		typ, wire = "string", "bytes"
-	case descriptor.FieldDescriptorProto_TYPE_GROUP:
-		desc := g.objectNamed(proto.GetString(field.TypeName))
-		typ, wire = "*"+g.TypeName(desc), "group"
-	case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
-		desc := g.objectNamed(proto.GetString(field.TypeName))
-		typ, wire = "*"+g.TypeName(desc), "bytes"
-	case descriptor.FieldDescriptorProto_TYPE_BYTES:
-		typ, wire = "[]byte", "bytes"
-	case descriptor.FieldDescriptorProto_TYPE_ENUM:
-		desc := g.objectNamed(proto.GetString(field.TypeName))
-		typ, wire = g.TypeName(desc), "varint"
-	case descriptor.FieldDescriptorProto_TYPE_SFIXED32:
-		typ, wire = "int32", "fixed32"
-	case descriptor.FieldDescriptorProto_TYPE_SFIXED64:
-		typ, wire = "int64", "fixed64"
-	case descriptor.FieldDescriptorProto_TYPE_SINT32:
-		typ, wire = "int32", "zigzag32"
-	case descriptor.FieldDescriptorProto_TYPE_SINT64:
-		typ, wire = "int64", "zigzag64"
-	default:
-		g.fail("unknown type for", proto.GetString(field.Name))
-	}
-	if IsRepeated(field) {
-		typ = "[]" + typ
-	} else if NeedsStar(*field.Type) {
-		typ = "*" + typ
-	}
-	return
-}
-
-// Generate the type and default constant definitions for this Descriptor.
-func (g *Generator) GenerateMessage(message *Descriptor) {
-	// The full type name
-	typeName := message.typeName()
-	// The full type name, CamelCased.
-	ccTypeName := CamelCaseSlice(typeName)
-
-	g.p("type ", ccTypeName, " struct {")
-	g.in()
-	for _, field := range message.Field {
-		fieldname := CamelCase(*field.Name)
-		typename, wiretype := g.GoType(message, field)
-		tag := g.GoTag(field, wiretype)
-		g.p(fieldname, "\t", typename, "\t", tag)
-	}
-	if len(message.ExtensionRange) > 0 {
-		g.p("XXX_extensions\t\tmap[int32][]byte")
-	}
-	g.p("XXX_unrecognized\t[]byte")
-	g.out()
-	g.p("}")
-
-	// Reset and New functions
-	g.p("func (this *", ccTypeName, ") Reset() {")
-	g.in()
-	g.p("*this = ", ccTypeName, "{}")
-	g.out()
-	g.p("}")
-	g.p("func New", ccTypeName, "() *", ccTypeName, " {")
-	g.in()
-	g.p("return new(", ccTypeName, ")")
-	g.out()
-	g.p("}")
-
-	// Extension support methods
-	if len(message.ExtensionRange) > 0 {
-		g.p()
-		g.p("var extRange_", ccTypeName, " = []proto.ExtensionRange{")
-		g.in()
-		for _, r := range message.ExtensionRange {
-			end := fmt.Sprint(*r.End - 1)  // make range inclusive on both ends
-			g.p("proto.ExtensionRange{", r.Start, ", ", end, "},")
-		}
-		g.out()
-		g.p("}")
-		g.p("func (*", ccTypeName, ") ExtensionRangeArray() []proto.ExtensionRange {")
-		g.in()
-		g.p("return extRange_", ccTypeName)
-		g.out()
-		g.p("}")
-		g.p("func (this *", ccTypeName, ") ExtensionMap() map[int32][]byte {")
-		g.in()
-		g.p("if this.XXX_extensions == nil {")
-		g.in()
-		g.p("this.XXX_extensions = make(map[int32][]byte)")
-		g.out()
-		g.p("}")
-		g.p("return this.XXX_extensions")
-		g.out()
-		g.p("}")
-	}
-
-	// Default constants
-	for _, field := range message.Field {
-		def := proto.GetString(field.DefaultValue)
-		if def == "" {
-			continue
-		}
-		fieldname := "Default_" + ccTypeName + "_" + CamelCase(*field.Name)
-		typename, _ := g.GoType(message, field)
-		if typename[0] == '*' {
-			typename = typename[1:]
-		}
-		kind := "const "
-		switch {
-		case typename == "bool":
-		case typename == "string":
-			def = Quote(def)
-		case typename == "[]byte":
-			def = "[]byte(" + Quote(def) + ")"
-			kind = "var "
-		case *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM:
-			// Must be an enum.  Need to construct the prefixed name.
-			obj := g.objectNamed(proto.GetString(field.TypeName))
-			enum, ok := obj.(*EnumDescriptor)
-			if !ok {
-				log.Stderr("don't know how to generate constant for", fieldname)
-				continue
-			}
-			def = enum.prefix() + def
-		}
-		g.p(kind, fieldname, " ", typename, " = ", def)
-	}
-	g.p()
-
-	for _, ext := range message.ext {
-		g.GenerateExtension(ext)
-	}
-}
-
-// Generate the extension descriptor for this ExtensionDescriptor.
-func (g *Generator) GenerateExtension(ext *ExtensionDescriptor) {
-	// The full type name
-	typeName := ext.typeName()
-	// Each scope of the extension is individually CamelCased, and all are joined with "_" with a "E_" prefix.
-	for i, s := range typeName {
-		typeName[i] = CamelCase(s)
-	}
-	ccTypeName := "E_" + strings.Join(typeName, "_")
-
-	extendedType := "*" + g.TypeName(g.objectNamed(*ext.Extendee))
-	field := ext.FieldDescriptorProto
-	fieldType, wireType := g.GoType(ext.parent, field)
-	tag := g.GoTag(field, wireType)
-
-	g.p("var ", ccTypeName, " = &proto.ExtensionDesc{")
-	g.in()
-	g.p("ExtendedType: (", extendedType, ")(nil),")
-	g.p("ExtensionType: (", fieldType, ")(nil),")
-	g.p("Field: ", field.Number, ",")
-	g.p("Tag: ", tag, ",")
-
-	g.out()
-	g.p("}")
-	g.p()
-}
-
-func (g *Generator) GenerateInitFunction() {
-	g.p("func init() {")
-	g.in()
-	for _, enum := range g.file.enum {
-		g.GenerateEnumRegistration(enum)
-	}
-	g.out()
-	g.p("}")
-}
-
-func (g *Generator) GenerateEnumRegistration(enum *EnumDescriptor) {
-	pkg := g.packageName + "." // We always print the full package name here.
-	// The full type name
-	typeName := enum.typeName()
-	// The full type name, CamelCased.
-	ccTypeName := CamelCaseSlice(typeName)
-	g.p("proto.RegisterEnum(", Quote(pkg+ccTypeName), ", ", ccTypeName+"_name, ", ccTypeName+"_value)")
-}
-
-// And now lots of helper functions.
-
-// Return change foo_bar_Baz to FooBar_Baz.
-func CamelCase(name string) string {
-	elems := strings.Split(name, "_", 0)
-	for i, e := range elems {
-		if e == "" {
-			elems[i] = "_"
-			continue
-		}
-		runes := []int(e)
-		if unicode.IsLower(runes[0]) {
-			runes[0] = unicode.ToUpper(runes[0])
-			elems[i] = string(runes)
-		} else {
-			if i > 0 {
-				elems[i] = "_" + e
-			}
-		}
-	}
-	s := strings.Join(elems, "")
-	// Name must not begin with an underscore.
-	if len(s) > 0 && s[0] == '_' {
-		s = "X" + s[1:]
-	}
-	return s
-}
-
-// Like CamelCase, but the argument is a slice of strings to
-// be concatenated with "_"
-func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem, "_")) }
-
-// Turn a sliced name into a dotted name
-func DottedSlice(elem []string) string { return strings.Join(elem, ".") }
-
-// Return a Go-source quoted string representation of s.
-func Quote(s string) string { return fmt.Sprintf("%q", s) }
-
-// Given a .proto file name, return the output name for the generated Go program.
-func GoName(name string) string {
-	if strings.HasSuffix(name, ".proto") {
-		name = name[0 : len(name)-6]
-	}
-	return name + ".pb.go"
-}
-
-// Is this field optional?
-func IsOptional(field *descriptor.FieldDescriptorProto) bool {
-	return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_OPTIONAL
-}
-
-// Is this field required?
-func IsRequired(field *descriptor.FieldDescriptorProto) bool {
-	return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REQUIRED
-}
-
-// Is this field repeated?
-func IsRepeated(field *descriptor.FieldDescriptorProto) bool {
-	return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED
-}
-
-// Mapping function used to generate Go names from package names, which can be dotted.
-func DotToUnderscore(rune int) int {
-	if rune == '.' {
-		return '_'
+		g.Error(err, "failed to write output proto")
 	}
 	}
-	return rune
 }
 }

+ 2 - 0
compiler/plugin/Makefile

@@ -35,6 +35,8 @@ TARG=goprotobuf.googlecode.com/hg/compiler/plugin
 GOFILES=\
 GOFILES=\
 	plugin.pb.go\
 	plugin.pb.go\
 
 
+DEPS=../../proto ../descriptor
+
 include $(GOROOT)/src/Make.pkg
 include $(GOROOT)/src/Make.pkg
 
 
 # Not stored here, but plugin.proto is in http://code.google.com/p/protobuf
 # Not stored here, but plugin.proto is in http://code.google.com/p/protobuf