Add extensions to the generator.

R=r
CC=golang-dev
http://codereview.appspot.com/774041
diff --git a/compiler/testdata/Makefile b/compiler/testdata/Makefile
index 0cc9ad1..3eb2efb 100644
--- a/compiler/testdata/Makefile
+++ b/compiler/testdata/Makefile
@@ -37,9 +37,10 @@
 include $(GOROOT)/src/Make.common
 include $(GOROOT)/src/pkg/goprotobuf.googlecode.com/hg/Make.protobuf
 
-CLEANFILES+=*.pb.go
+CLEANFILES+=*.pb.go extension_test
 
-test:	golden testbuild
+test:	golden testbuild extension_test
+	./extension_test
 	@echo PASS
 
 golden:
@@ -51,6 +52,9 @@
 testbuild:	main.$O
 	$(LD) -L. main.$O
 
+extension_test:	extension_test.$O
+	$(LD) -L. -o $@ $< 
+
 multi.a: multi3.pb.$O multi2.pb.$O multi1.pb.$O
 	rm -f multi.a
 	$(QUOTED_GOBIN)/gopack grc $@ $<
@@ -61,3 +65,4 @@
 test.pb.go:	imp.pb.go
 multi1.pb.go:	multi2.pb.go multi3.pb.go
 main.$O: imp.pb.$O test.pb.$O multi.a
+extension_test.$O: extension_base.pb.$O extension_user.pb.$O
diff --git a/compiler/testdata/extension_base.proto b/compiler/testdata/extension_base.proto
new file mode 100644
index 0000000..5f91628
--- /dev/null
+++ b/compiler/testdata/extension_base.proto
@@ -0,0 +1,38 @@
+// 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.
+
+package extension_base;
+
+message BaseMessage {
+  optional int32 height = 1;
+  extensions 4 to 9;
+  extensions 16 to max;
+}
diff --git a/compiler/testdata/extension_test.go b/compiler/testdata/extension_test.go
new file mode 100644
index 0000000..1ddb229
--- /dev/null
+++ b/compiler/testdata/extension_test.go
@@ -0,0 +1,159 @@
+// 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.
+
+// Test that we can use protocol buffers that use extensions.
+
+package main
+
+import (
+	"testing"
+
+	"goprotobuf.googlecode.com/hg/proto"
+	base "extension_base.pb"
+	user "extension_user.pb"
+)
+
+func TestSingleFieldExtension(t *testing.T) {
+	bm := base.NewBaseMessage()
+	bm.Height = proto.Int32(178)
+
+	// Use extension within scope of another type.
+	vol := proto.Uint32(11)
+	t.Logf("bm: %T, user.LoudMessage_Volume: %T", bm, user.LoudMessage_Volume)
+	err := proto.SetExtension(bm, user.LoudMessage_Volume, vol)
+	if err != nil {
+		t.Fatal("Failed setting extension:", err)
+	}
+	buf, err := proto.Marshal(bm)
+	if err != nil {
+		t.Fatal("Failed encoding message with extension:", err)
+	}
+	bm_new := base.NewBaseMessage()
+	if err := proto.Unmarshal(buf, bm_new); err != nil {
+		t.Fatal("Failed decoding message with extension:", err)
+	}
+	if !proto.HasExtension(bm_new, user.LoudMessage_Volume) {
+		t.Fatal("Decoded message didn't contain extension.")
+	}
+	vol_out, err := proto.GetExtension(bm_new, user.LoudMessage_Volume)
+	if err != nil {
+		t.Fatal("Failed getting extension:", err)
+	}
+	if v := vol_out.(*uint32); *v != *vol {
+		t.Errorf("vol_out = %v, expected %v", *v, *vol)
+	}
+	proto.ClearExtension(bm_new, user.LoudMessage_Volume)
+	if proto.HasExtension(bm_new, user.LoudMessage_Volume) {
+		t.Fatal("Failed clearing extension.")
+	}
+}
+
+func TestMessageExtension(t *testing.T) {
+	bm := base.NewBaseMessage()
+	bm.Height = proto.Int32(179)
+
+	// Use extension that is itself a message.
+	um := &user.UserMessage{
+		Name: proto.String("Dave"),
+		Rank: proto.String("Major"),
+	}
+	err := proto.SetExtension(bm, user.LoginMessage_UserMessage, um)
+	if err != nil {
+		t.Fatal("Failed setting extension:", err)
+	}
+	buf, err := proto.Marshal(bm)
+	if err != nil {
+		t.Fatal("Failed encoding message with extension:", err)
+	}
+	bm_new := base.NewBaseMessage()
+	if err := proto.Unmarshal(buf, bm_new); err != nil {
+		t.Fatal("Failed decoding message with extension:", err)
+	}
+	if !proto.HasExtension(bm_new, user.LoginMessage_UserMessage) {
+		t.Fatal("Decoded message didn't contain extension.")
+	}
+	um_out, err := proto.GetExtension(bm_new, user.LoginMessage_UserMessage)
+	if err != nil {
+		t.Fatal("Failed getting extension:", err)
+	}
+	if n := um_out.(*user.UserMessage).Name; *n != *um.Name {
+		t.Errorf("um_out.Name = %q, expected %q", *n, *um.Name)
+	}
+	if r := um_out.(*user.UserMessage).Rank; *r != *um.Rank {
+		t.Errorf("um_out.Rank = %q, expected %q", *r, *um.Rank)
+	}
+	proto.ClearExtension(bm_new, user.LoginMessage_UserMessage)
+	if proto.HasExtension(bm_new, user.LoginMessage_UserMessage) {
+		t.Fatal("Failed clearing extension.")
+	}
+}
+
+func TestTopLevelExtension(t *testing.T) {
+	bm := base.NewBaseMessage()
+	bm.Height = proto.Int32(179)
+
+	width := proto.Int32(17)
+	err := proto.SetExtension(bm, user.E_Width, width)
+	if err != nil {
+		t.Fatal("Failed setting extension:", err)
+	}
+	buf, err := proto.Marshal(bm)
+	if err != nil {
+		t.Fatal("Failed encoding message with extension:", err)
+	}
+	bm_new := base.NewBaseMessage()
+	if err := proto.Unmarshal(buf, bm_new); err != nil {
+		t.Fatal("Failed decoding message with extension:", err)
+	}
+	if !proto.HasExtension(bm_new, user.E_Width) {
+		t.Fatal("Decoded message didn't contain extension.")
+	}
+	width_out, err := proto.GetExtension(bm_new, user.E_Width)
+	if err != nil {
+		t.Fatal("Failed getting extension:", err)
+	}
+	if w := width_out.(*int32); *w != *width {
+		t.Errorf("width_out = %v, expected %v", *w, *width)
+	}
+	proto.ClearExtension(bm_new, user.E_Width)
+	if proto.HasExtension(bm_new, user.E_Width) {
+		t.Fatal("Failed clearing extension.")
+	}
+}
+
+func main() {
+	// simpler than rigging up gotest
+	testing.Main([]testing.Test{
+		testing.Test{"TestSingleFieldExtension", TestSingleFieldExtension},
+		testing.Test{"TestMessageExtension", TestMessageExtension},
+		testing.Test{"TestTopLevelExtension", TestTopLevelExtension},
+	})
+}
diff --git a/compiler/testdata/extension_user.proto b/compiler/testdata/extension_user.proto
new file mode 100644
index 0000000..6fb3d72
--- /dev/null
+++ b/compiler/testdata/extension_user.proto
@@ -0,0 +1,73 @@
+// 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.
+
+import "extension_base.proto";
+
+package extension_user;
+
+message UserMessage {
+  optional string name = 1;
+  optional string rank = 2;
+}
+
+// Extend with a message
+extend extension_base.BaseMessage {
+  optional UserMessage user_message = 5;
+}
+
+// Extend with some primitive types
+extend extension_base.BaseMessage {
+  optional int32 width = 6;
+  optional int64 area = 7;
+}
+
+// Extend inside the scope of another type
+message LoudMessage {
+  extend extension_base.BaseMessage {
+    optional uint32 volume = 8;
+  }
+  extensions 100 to max;
+}
+
+// Extend inside the scope of another type, using a message.
+message LoginMessage {
+  extend extension_base.BaseMessage {
+    required UserMessage user_message = 16;
+  }
+}
+
+// An extension of an extension
+message Announcement {
+  optional string words = 1;
+  extend LoudMessage {
+    optional Announcement loud_ext = 100;
+  }
+}
diff --git a/compiler/testdata/test.pb.go.golden b/compiler/testdata/test.pb.go.golden
index 0d7a7cb..6807d20 100644
--- a/compiler/testdata/test.pb.go.golden
+++ b/compiler/testdata/test.pb.go.golden
@@ -84,6 +84,7 @@
 
 type Reply struct {
 	Found	[]*Reply_Entry	"PB(bytes,1,rep,name=found)"
+	XXX_extensions		map[int32][]byte
 	XXX_unrecognized	[]byte
 }
 func (this *Reply) Reset() {
@@ -93,6 +94,19 @@
 	return new(Reply)
 }
 
+var extRange_Reply = []proto.ExtensionRange{
+	proto.ExtensionRange{100, 536870911},
+}
+func (*Reply) ExtensionRangeArray() []proto.ExtensionRange {
+	return extRange_Reply
+}
+func (this *Reply) ExtensionMap() map[int32][]byte {
+	if this.XXX_extensions == nil {
+		this.XXX_extensions = make(map[int32][]byte)
+	}
+	return this.XXX_extensions
+}
+
 type Reply_Entry struct {
 	KeyThatNeeds_1234camel_CasIng	*int64	"PB(varint,1,req,name=key_that_needs_1234camel_CasIng)"
 	Value	*int64	"PB(varint,2,opt,name=value,def=7)"
@@ -117,6 +131,20 @@
 	return new(ReplyExtensions)
 }
 
+var ReplyExtensions_Time = &proto.ExtensionDesc{
+	ExtendedType: (*Reply)(nil),
+	ExtensionType: (*float64)(nil),
+	Field: 101,
+	Tag: "PB(fixed64,101,opt,name=time)",
+}
+
+var E_Tag = &proto.ExtensionDesc{
+	ExtendedType: (*Reply)(nil),
+	ExtensionType: (*string)(nil),
+	Field: 103,
+	Tag: "PB(bytes,103,opt,name=tag)",
+}
+
 func init() {
 	proto.RegisterEnum("my_test.HatType", HatType_name, HatType_value)
 	proto.RegisterEnum("my_test.Days", Days_name, Days_value)
diff --git a/compiler/testdata/test.proto b/compiler/testdata/test.proto
index f7e7a3d..ef91b03 100644
--- a/compiler/testdata/test.proto
+++ b/compiler/testdata/test.proto
@@ -73,3 +73,8 @@
     optional double time = 101;
   }
 }
+
+// top-level extension
+extend Reply {
+  optional string tag = 103;
+}