goprotobuf: Support extensions in text parser.

R=r
TBR=r
CC=golang-dev
http://codereview.appspot.com/5462043
diff --git a/proto/text_parser.go b/proto/text_parser.go
index 31efc05..0e76e13 100644
--- a/proto/text_parser.go
+++ b/proto/text_parser.go
@@ -32,7 +32,7 @@
 package proto
 
 // Functions for parsing the Text protocol buffer format.
-// TODO: message sets, extensions.
+// TODO: message sets.
 
 import (
 	"fmt"
@@ -151,7 +151,7 @@
 	p.cur.offset, p.cur.line = p.offset, p.line
 	p.cur.unquoted = ""
 	switch p.s[0] {
-	case '<', '>', '{', '}', ':':
+	case '<', '>', '{', '}', ':', '[', ']':
 		// Single symbol
 		p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)]
 	case '"':
@@ -252,11 +252,50 @@
 	return -1, nil, false
 }
 
+// Consume a ':' from the input stream (if the next token is a colon),
+// returning an error if a colon is needed but not present.
+func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError {
+	tok := p.next()
+	if tok.err != nil {
+		return tok.err
+	}
+	if tok.value != ":" {
+		// Colon is optional when the field is a group or message.
+		needColon := true
+		switch props.Wire {
+		case "group":
+			needColon = false
+		case "bytes":
+			// A "bytes" field is either a message, a string, or a repeated field;
+			// those three become *T, *string and []T respectively, so we can check for
+			// this field being a pointer to a non-string.
+			if typ.Kind() == reflect.Ptr {
+				// *T or *string
+				if typ.Elem().Kind() == reflect.String {
+					break
+				}
+			} else if typ.Kind() == reflect.Slice {
+				// []T or []*T
+				if typ.Elem().Kind() != reflect.Ptr {
+					break
+				}
+			}
+			needColon = false
+		}
+		if needColon {
+			return p.errorf("expected ':', found %q", tok.value)
+		}
+		p.back()
+	}
+	return nil
+}
+
 func (p *textParser) readStruct(sv reflect.Value, terminator string) *ParseError {
 	st := sv.Type()
 	reqCount := GetProperties(st).reqCount
 	// A struct is a sequence of "name: value", terminated by one of
-	// '>' or '}', or the end of the input.
+	// '>' or '}', or the end of the input.  A name may also be
+	// "[extension]".
 	for {
 		tok := p.next()
 		if tok.err != nil {
@@ -265,58 +304,76 @@
 		if tok.value == terminator {
 			break
 		}
-
-		fi, props, ok := structFieldByName(st, tok.value)
-		if !ok {
-			return p.errorf("unknown field name %q in %v", tok.value, st)
-		}
-
-		// Check that it's not already set if it's not a repeated field.
-		if !props.Repeated && !isNil(sv.Field(fi)) {
-			return p.errorf("non-repeated field %q was repeated", tok.value)
-		}
-
-		tok = p.next()
-		if tok.err != nil {
-			return tok.err
-		}
-		if tok.value != ":" {
-			// Colon is optional when the field is a group or message.
-			needColon := true
-			switch props.Wire {
-			case "group":
-				needColon = false
-			case "bytes":
-				// A "bytes" field is either a message, a string, or a repeated field;
-				// those three become *T, *string and []T respectively, so we can check for
-				// this field being a pointer to a non-string.
-				typ := st.Field(fi).Type
-				if typ.Kind() == reflect.Ptr {
-					// *T or *string
-					if typ.Elem().Kind() == reflect.String {
-						break
-					}
-				} else if typ.Kind() == reflect.Slice {
-					// []T or []*T
-					if typ.Elem().Kind() != reflect.Ptr {
-						break
-					}
+		if tok.value == "[" {
+			// Looks like an extension.
+			//
+			// TODO: Check whether we need to handle
+			// namespace rooted names (e.g. ".something.Foo").
+			tok = p.next()
+			if tok.err != nil {
+				return tok.err
+			}
+			var desc *ExtensionDesc
+			// This could be faster, but it's functional.
+			// TODO: Do something smarter than a linear scan.
+			for _, d := range RegisteredExtensions(reflect.New(st).Interface()) {
+				if d.Name == tok.value {
+					desc = d
+					break
 				}
-				needColon = false
 			}
-			if needColon {
-				return p.errorf("expected ':', found %q", tok.value)
+			if desc == nil {
+				return p.errorf("unrecognized extension %q", tok.value)
 			}
-			p.back()
-		}
+			// Check the extension terminator.
+			tok = p.next()
+			if tok.err != nil {
+				return tok.err
+			}
+			if tok.value != "]" {
+				return p.errorf("unrecognized extension terminator %q", tok.value)
+			}
 
-		// Parse into the field.
-		if err := p.readAny(sv.Field(fi), props); err != nil {
-			return err
-		}
+			props := &Properties{}
+			props.Parse(desc.Tag)
 
-		if props.Required {
-			reqCount--
+			typ := reflect.TypeOf(desc.ExtensionType)
+			if err := p.checkForColon(props, typ); err != nil {
+				return err
+			}
+
+			// Read the extension structure, and set it in
+			// the value we're constructing.
+			ext := reflect.New(typ).Elem()
+			if err := p.readAny(ext, props); err != nil {
+				return err
+			}
+			SetExtension(sv.Addr().Interface().(extendableProto),
+				desc, ext.Interface())
+		} else {
+			// This is a normal, non-extension field.
+			fi, props, ok := structFieldByName(st, tok.value)
+			if !ok {
+				return p.errorf("unknown field name %q in %v", tok.value, st)
+			}
+
+			// Check that it's not already set if it's not a repeated field.
+			if !props.Repeated && !isNil(sv.Field(fi)) {
+				return p.errorf("non-repeated field %q was repeated", tok.value)
+			}
+
+			if err := p.checkForColon(props, st.Field(fi).Type); err != nil {
+				return err
+			}
+
+			// Parse into the field.
+			if err := p.readAny(sv.Field(fi), props); err != nil {
+				return err
+			}
+
+			if props.Required {
+				reqCount--
+			}
 		}
 	}