Update the generator to the google-internal version.
- a few changes to the plugin interface
- handle situation where an imported package is called "proto"
- use the file base name for the package name if a package is not specified

R=rsc
CC=dsymonds1
http://codereview.appspot.com/1641042
diff --git a/compiler/generator/generator.go b/compiler/generator/generator.go
index cbef5ed..f6fb238 100644
--- a/compiler/generator/generator.go
+++ b/compiler/generator/generator.go
@@ -33,10 +33,6 @@
 	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
 
@@ -57,12 +53,16 @@
 // 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)
+	Name() string
+	// Init is called once after data structures are built but before
+	// code generation begins.
+	Init(g *Generator)
+	// 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(file *FileDescriptor)
 	// GenerateImports produces the import declarations for this file.
-	GenerateImports(g *Generator, file *FileDescriptor)
+	// It is called after Generate.
+	GenerateImports(file *FileDescriptor)
 }
 
 var plugins []Plugin
@@ -72,13 +72,12 @@
 func RegisterPlugin(p Plugin) {
 	n := len(plugins)
 	if cap(plugins) == n {
-		nplugins := make([]Plugin, n, n+10)	// very unlikely to need more than this
+		nplugins := make([]Plugin, n, n+10) // very unlikely to need more than this
 		copy(nplugins, plugins)
 		plugins = nplugins
 	}
-	plugins = plugins[0:n+1]
+	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
@@ -180,7 +179,7 @@
 type ExtensionDescriptor struct {
 	common
 	*descriptor.FieldDescriptorProto
-	parent   *Descriptor // The containing message, if any.
+	parent *Descriptor // The containing message, if any.
 }
 
 // TypeName returns the elements of the dotted type name.
@@ -204,31 +203,24 @@
 // 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.
+	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.
+// If the file does not define a package, use the base of the file name.
 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
+	// Does the file have a package clause?
+	pkg := proto.GetString(d.Package)
+	if pkg != "" {
+		return pkg
 	}
-	for _, desc := range d.desc {
-		if len(desc.ext) > 0 || len(desc.ExtensionRange) > 0 {
-			return true
-		}
-	}
-	return false
+	// Use the file base name.
+	return BaseName(proto.GetString(d.Name))
 }
 
 // Object is an interface abstracting the abilities shared by enums and messages.
@@ -256,6 +248,12 @@
 	Request  *plugin.CodeGeneratorRequest  // The input.
 	Response *plugin.CodeGeneratorResponse // The output.
 
+	Param        map[string]string // Command-line parameters.
+	ImportPrefix string            // String to prefix to imported package file names.
+	ImportMap    map[string]string // Mapping from import name to generated name
+
+	ProtoPkg string // The name under which we import the library's package proto.
+
 	packageName      string            // What we're calling ourselves.
 	allFiles         []*FileDescriptor // All files in the tree
 	genFiles         []*FileDescriptor // Those files we will generate output for.
@@ -290,6 +288,29 @@
 	os.Exit(1)
 }
 
+// CommandLineParameters breaks the comma-separated list of key=value pairs
+// in the parameter (a member of the request protobuf) into a key/value map.
+// It then sets file name mappings defined by those entries.
+func (g *Generator) CommandLineParameters(parameter string) {
+	g.Param = make(map[string]string)
+	for _, p := range strings.Split(parameter, ",", 0) {
+		if i := strings.Index(p, "="); i < 0 {
+			g.Param[p] = ""
+		} else {
+			g.Param[p[0:i]] = p[i+1:]
+		}
+	}
+
+	g.ImportMap = make(map[string]string)
+	for k, v := range g.Param {
+		if k == "import_prefix" {
+			g.ImportPrefix = v
+		} else if len(k) > 0 && k[0] == 'M' {
+			g.ImportMap[k[1:]] = v
+		}
+	}
+}
+
 // 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.
@@ -303,17 +324,40 @@
 
 // For each input file, the unique package name to use, underscored.
 var uniquePackageName = make(map[*descriptor.FileDescriptorProto]string)
+// Package names already registered.  Key is the name from the .proto file;
+// value is the name that appears in the generated code.
+var pkgNamesInUse = make(map[string]bool)
 
-// SetPackageNames Sets the package name for this run.
+// Create and remember a guaranteed unique package name for this file descriptor.
+// Pkg is the candidate name.  If f is nil, it's a builtin package like "proto" and
+// has no file descriptor.
+func RegisterUniquePackageName(pkg string, f *FileDescriptor) string {
+	for pkgNamesInUse[pkg] {
+		// It's a duplicate; must rename.
+		pkg += "X"
+	}
+	// Install it.
+	pkgNamesInUse[pkg] = true
+	pkg = strings.Map(DotToUnderscore, pkg)
+	if f != nil {
+		uniquePackageName[f.FileDescriptorProto] = pkg
+	}
+	return pkg
+}
+
+// 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
+	// Register the name for this package.  It will be the first name
+	// registered so is guaranteed to be unmodified.
+	pkg := g.genFiles[0].originalPackageName()
+	g.packageName = RegisterUniquePackageName(pkg, g.genFiles[0])
+	// Register the proto package name.  It might collide with the
+	// name of a package we import.
+	g.ProtoPkg = RegisterUniquePackageName("proto", nil)
 	for _, f := range g.genFiles {
-		thisPkg := proto.GetString(f.Package)
+		thisPkg := f.originalPackageName()
 		if thisPkg != pkg {
 			g.Fail("inconsistent package names:", thisPkg, pkg)
 		}
@@ -327,20 +371,7 @@
 				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)
+		RegisterUniquePackageName(f.originalPackageName(), f)
 	}
 }
 
@@ -350,10 +381,6 @@
 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)
@@ -483,13 +510,19 @@
 	return sl
 }
 
-// BuildTypeNameMap builds the map from fully qualified type names to objects. 
+// 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() + "."
+		// The names in this loop are defined by the proto world, not us, so the
+		// package name may be empty.  If so, the dotted package name of X will
+		// be ".X"; otherwise it will be ".pkg.X".
+		dottedPkg := "." + proto.GetString(f.Package)
+		if dottedPkg != "." {
+			dottedPkg += "."
+		}
 		for _, enum := range f.enum {
 			name := dottedPkg + dottedSlice(enum.TypeName())
 			g.typeNameToObject[name] = enum
@@ -521,8 +554,16 @@
 			g.WriteString(s)
 		case *string:
 			g.WriteString(*s)
+		case bool:
+			g.WriteString(fmt.Sprintf("%t", s))
+		case *bool:
+			g.WriteString(fmt.Sprintf("%t", *s))
 		case *int32:
 			g.WriteString(fmt.Sprintf("%d", *s))
+		case float64:
+			g.WriteString(fmt.Sprintf("%g", s))
+		case *float64:
+			g.WriteString(fmt.Sprintf("%g", *s))
 		default:
 			g.Fail(fmt.Sprintf("unknown type in printer: %T", v))
 		}
@@ -542,10 +583,14 @@
 
 // GenerateAllFiles generates the output for all the files we're outputting.
 func (g *Generator) GenerateAllFiles() {
+	// Initialize the plugins
+	for _, p := range plugins {
+		p.Init(g)
+	}
+	// Generate the output.
 	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())
@@ -555,7 +600,7 @@
 // Run all the plugins associated with the file.
 func (g *Generator) runPlugins(file *FileDescriptor) {
 	for _, p := range plugins {
-		p.Generate(g, file)
+		p.Generate(file)
 	}
 }
 
@@ -588,6 +633,9 @@
 	}
 	g.generateInitFunction()
 
+	// Run the plugins before the imports so we know which imports are necessary.
+	g.runPlugins(file)
+
 	// Generate header and imports last, though they appear first in the output.
 	rem := g.Buffer
 	g.Buffer = new(bytes.Buffer)
@@ -607,16 +655,25 @@
 
 // Generate the header, including package definition and imports
 func (g *Generator) generateImports() {
-	if g.file.needProtoImport() {
-		g.P(`import "goprotobuf.googlecode.com/hg/proto"`)
-	}
+	// We almost always need a proto import.  Rather than computing when we
+	// do, which is tricky when there's a plugin, just import it and
+	// reference it later.
+	g.P("import " + g.ProtoPkg + " " + Quote(g.ImportPrefix+"net/proto2/go/proto"))
 	for _, s := range g.file.Dependency {
 		// Need to find the descriptor for this file
 		for _, fd := range g.allFiles {
+			// Do not import our own package.
+			if fd.PackageName() == g.packageName {
+				continue
+			}
 			if proto.GetString(fd.Name) == s {
 				filename := goFileName(s)
+				if substitution, ok := g.ImportMap[s]; ok {
+					filename = substitution
+				}
+				filename = g.ImportPrefix + filename
 				if strings.HasSuffix(filename, ".go") {
-					filename = filename[0:len(filename)-3]
+					filename = filename[0 : len(filename)-3]
 				}
 				if _, ok := g.usedPackages[fd.PackageName()]; ok {
 					g.P("import ", fd.PackageName(), " ", Quote(filename))
@@ -630,9 +687,12 @@
 	g.P()
 	// TODO: may need to worry about uniqueness across plugins
 	for _, p := range plugins {
-		p.GenerateImports(g, g.file)
+		p.GenerateImports(g.file)
 		g.P()
 	}
+	g.P("// Reference proto import to suppress error if it's not otherwise used.")
+	g.P("var _ = ", g.ProtoPkg, ".GetString")
+	g.P()
 }
 
 // Generate the enum definitions for this EnumDescriptor.
@@ -652,7 +712,7 @@
 	g.P(")")
 	g.P("var ", ccTypeName, "_name = map[int32] string {")
 	g.In()
-	generated := make(map[int32] bool)	// avoid duplicate values
+	generated := make(map[int32]bool) // avoid duplicate values
 	for _, e := range enum.Value {
 		duplicate := ""
 		if _, present := generated[*e.Number]; present {
@@ -871,15 +931,15 @@
 	// Extension support methods
 	if len(message.ExtensionRange) > 0 {
 		g.P()
-		g.P("var extRange_", ccTypeName, " = []proto.ExtensionRange{")
+		g.P("var extRange_", ccTypeName, " = []", g.ProtoPkg, ".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, "},")
+			end := fmt.Sprint(*r.End - 1) // make range inclusive on both ends
+			g.P(g.ProtoPkg+".ExtensionRange{", r.Start, ", ", end, "},")
 		}
 		g.Out()
 		g.P("}")
-		g.P("func (*", ccTypeName, ") ExtensionRangeArray() []proto.ExtensionRange {")
+		g.P("func (*", ccTypeName, ") ExtensionRangeArray() []", g.ProtoPkg, ".ExtensionRange {")
 		g.In()
 		g.P("return extRange_", ccTypeName)
 		g.Out()
@@ -949,7 +1009,7 @@
 	tag := g.goTag(field, wireType)
 	g.RecordTypeUse(*ext.Extendee)
 
-	g.P("var ", ccTypeName, " = &proto.ExtensionDesc{")
+	g.P("var ", ccTypeName, " = &", g.ProtoPkg, ".ExtensionDesc{")
 	g.In()
 	g.P("ExtendedType: (", extendedType, ")(nil),")
 	g.P("ExtensionType: (", fieldType, ")(nil),")
@@ -977,7 +1037,7 @@
 	typeName := enum.TypeName()
 	// The full type name, CamelCased.
 	ccTypeName := CamelCaseSlice(typeName)
-	g.P("proto.RegisterEnum(", Quote(pkg+ccTypeName), ", ", ccTypeName+"_name, ", ccTypeName+"_value)")
+	g.P(g.ProtoPkg+".RegisterEnum(", Quote(pkg+ccTypeName), ", ", ccTypeName+"_name, ", ccTypeName+"_value)")
 }
 
 // And now lots of helper functions.
@@ -1042,10 +1102,26 @@
 }
 
 // DotToUnderscore is the mapping function used to generate Go names from package names,
-// which can be dotted in the input .proto file.
+// which can be dotted in the input .proto file.  It maps dots to underscores.
+// Because we also get here from package names generated from file names, it also maps
+// minus signs to underscores.
 func DotToUnderscore(rune int) int {
-	if rune == '.' {
+	switch rune {
+	case '.', '-':
 		return '_'
 	}
 	return rune
 }
+
+// BaseName returns the last path element of the name, with the last dotted suffix removed.
+func BaseName(name string) string {
+	// First, find the last element
+	if i := strings.LastIndex(name, "/"); i >= 0 {
+		name = name[i+1:]
+	}
+	// Now drop the suffix
+	if i := strings.LastIndex(name, "."); i >= 0 {
+		name = name[0:i]
+	}
+	return name
+}