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
diff --git a/compiler/generator/Makefile b/compiler/generator/Makefile
new file mode 100644
index 0000000..2872c83
--- /dev/null
+++ b/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
diff --git a/compiler/generator/generator.go b/compiler/generator/generator.go
new file mode 100644
index 0000000..5cef6f5
--- /dev/null
+++ b/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
+}