Repository: jhump/protoreflect
Pull request #284 (2019-10-08 23:15:21)

Support compiled file descriptors as imports in protoparse.
I have taken a stab at implementing what is needed for #279.

I essentially added a `FileDescriptors` map that takes filenames and descriptors, and a small helper method (`GetRegisteredDescriptors`) to allow the user to easily get these by providing filenames after the compiled proto has been registered (imported in Go).


Patch:
diff --git a/desc/protoparse/ast.go b/desc/protoparse/ast.go
index e1eb4df..f3fafb3 100644
--- a/desc/protoparse/ast.go
+++ b/desc/protoparse/ast.go
@@ -526,6 +526,7 @@ type groupNode struct {
 	name         *identNode
 	tag          *intLiteralNode
 	decls        []*messageElement
+	options      *compactOptionsNode
 
 	// This field is populated after parsing, to allow lookup of extendee source
 	// locations when field extendees cannot be linked. (Otherwise, this is just
diff --git a/desc/protoparse/parser.go b/desc/protoparse/parser.go
index bdc55d4..25c4672 100644
--- a/desc/protoparse/parser.go
+++ b/desc/protoparse/parser.go
@@ -104,6 +104,20 @@ type Parser struct {
 	// with import statements all being relative to the root of this tree).
 	InferImportPaths bool
 
+	// LookupImport is a function that accepts a filename and
+	// returns a file descriptor, which will be consulted when resolving imports.
+	// This allows a compiled Go proto in another Go module to be referenced
+	// in the proto(s) being parsed.
+	//
+	// In the event of a filename collision, Accessor is consulted first,
+	// then LookupImport is consulted, and finally the well-known protos
+	// are used.
+	//
+	// For example, in order to automatically look up compiled Go protos that
+	// have been imported and be able to use them as imports, set this to
+	// desc.LoadFileDescriptor.
+	LookupImport func(string) (*desc.FileDescriptor, error)
+
 	// Used to create a reader for a given filename, when loading proto source
 	// file contents. If unset, os.Open is used. If ImportPaths is also empty
 	// then relative paths are will be relative to the process's current working
@@ -187,7 +201,7 @@ func (p Parser) ParseFiles(filenames ...string) ([]*desc.FileDescriptor, error)
 	protos := map[string]*parseResult{}
 	results := &parseResults{resultsByFilename: protos}
 	errs := newErrorHandler(p.ErrorReporter)
-	parseProtoFiles(accessor, filenames, errs, true, true, results)
+	parseProtoFiles(accessor, filenames, errs, true, true, results, p.LookupImport)
 	if err := errs.getError(); err != nil {
 		return nil, err
 	}
@@ -255,7 +269,7 @@ func (p Parser) ParseFilesButDoNotLink(filenames ...string) ([]*dpb.FileDescript
 
 	protos := map[string]*parseResult{}
 	errs := newErrorHandler(p.ErrorReporter)
-	parseProtoFiles(accessor, filenames, errs, false, p.ValidateUnlinkedFiles, &parseResults{resultsByFilename: protos})
+	parseProtoFiles(accessor, filenames, errs, false, p.ValidateUnlinkedFiles, &parseResults{resultsByFilename: protos}, p.LookupImport)
 	if err := errs.getError(); err != nil {
 		return nil, err
 	}
@@ -387,19 +401,24 @@ func fixupFilenames(protos map[string]*parseResult) map[string]*parseResult {
 	return revisedProtos
 }
 
-func parseProtoFiles(acc FileAccessor, filenames []string, errs *errorHandler, recursive, validate bool, parsed *parseResults) {
+func parseProtoFiles(acc FileAccessor, filenames []string, errs *errorHandler, recursive, validate bool, parsed *parseResults, lookupImport func(string) (*desc.FileDescriptor, error)) {
 	for _, name := range filenames {
-		parseProtoFile(acc, name, nil, errs, recursive, validate, parsed)
+		parseProtoFile(acc, name, nil, errs, recursive, validate, parsed, lookupImport)
 		if errs.err != nil {
 			return
 		}
 	}
 }
 
-func parseProtoFile(acc FileAccessor, filename string, importLoc *SourcePos, errs *errorHandler, recursive, validate bool, parsed *parseResults) {
+func parseProtoFile(acc FileAccessor, filename string, importLoc *SourcePos, errs *errorHandler, recursive, validate bool, parsed *parseResults, lookupImport func(string) (*desc.FileDescriptor, error)) {
 	if parsed.has(filename) {
 		return
 	}
+	if lookupImport == nil {
+		lookupImport = func(string) (*desc.FileDescriptor, error) {
+			return nil, errors.New("no import lookup function")
+		}
+	}
 	in, err := acc(filename)
 	var result *parseResult
 	if err == nil {
@@ -412,6 +431,10 @@ func parseProtoFile(acc FileAccessor, filename string, importLoc *SourcePos, err
 			}()
 			result = parseProto(filename, in, errs, validate)
 		}()
+	} else if d, lookupErr := lookupImport(filename); lookupErr == nil {
+		// This is a user-provided descriptor, which is acting similarly to a
+		// well-known import.
+		result = &parseResult{fd: proto.Clone(d.AsFileDescriptorProto()).(*dpb.FileDescriptorProto)}
 	} else if d, ok := standardImports[filename]; ok {
 		// it's a well-known import
 		// (we clone it to make sure we're not sharing state with other
@@ -447,7 +470,7 @@ func parseProtoFile(acc FileAccessor, filename string, importLoc *SourcePos, err
 		if !ok {
 			// no AST for this file? use imports in descriptor
 			for _, dep := range fd.Dependency {
-				parseProtoFile(acc, dep, decl.start(), errs, true, validate, parsed)
+				parseProtoFile(acc, dep, decl.start(), errs, true, validate, parsed, lookupImport)
 				if errs.getError() != nil {
 					return // abort
 				}
@@ -456,7 +479,7 @@ func parseProtoFile(acc FileAccessor, filename string, importLoc *SourcePos, err
 		}
 		// we have an AST; use it so we can report import location in errors
 		for _, dep := range fnode.imports {
-			parseProtoFile(acc, dep.name.val, dep.name.start(), errs, true, validate, parsed)
+			parseProtoFile(acc, dep.name.val, dep.name.start(), errs, true, validate, parsed, lookupImport)
 			if errs.getError() != nil {
 				return // abort
 			}
@@ -848,6 +871,9 @@ func (r *parseResult) asGroupDescriptors(group *groupNode, isProto3 bool) (*dpb.
 		TypeName: proto.String(group.name.val),
 	}
 	r.putFieldNode(fd, group)
+	if opts := group.options.Elements(); len(opts) > 0 {
+		fd.Options = &dpb.FieldOptions{UninterpretedOption: r.asUninterpretedOptions(opts)}
+	}
 	md := &dpb.DescriptorProto{Name: proto.String(group.name.val)}
 	r.putMessageNode(md, group)
 	r.addMessageDecls(md, group.decls, isProto3)
diff --git a/desc/protoparse/proto.y b/desc/protoparse/proto.y
index 4619998..d021e0b 100644
--- a/desc/protoparse/proto.y
+++ b/desc/protoparse/proto.y
@@ -560,6 +560,33 @@ group : _REQUIRED _GROUP name '=' _INT_LIT '{' messageBody '}' {
 		$$ = &groupNode{groupKeyword: $2, label: lbl, name: $3, tag: $5, decls: $7}
 		$$.setRange($1, $8)
 	}
+	| _REQUIRED _GROUP name '=' _INT_LIT compactOptions '{' messageBody '}' {
+		checkTag(protolex, $5.start(), $5.val)
+		if !unicode.IsUpper(rune($3.val[0])) {
+			lexError(protolex, $3.start(), fmt.Sprintf("group %s should have a name that starts with a capital letter", $3.val))
+		}
+		lbl := fieldLabel{identNode: $1, required: true}
+		$$ = &groupNode{groupKeyword: $2, label: lbl, name: $3, tag: $5, options: $6, decls: $8}
+		$$.setRange($1, $9)
+	}
+	| _OPTIONAL _GROUP name '=' _INT_LIT compactOptions '{' messageBody '}' {
+		checkTag(protolex, $5.start(), $5.val)
+		if !unicode.IsUpper(rune($3.val[0])) {
+			lexError(protolex, $3.start(), fmt.Sprintf("group %s should have a name that starts with a capital letter", $3.val))
+		}
+		lbl := fieldLabel{identNode: $1}
+		$$ = &groupNode{groupKeyword: $2, label: lbl, name: $3, tag: $5, options: $6, decls: $8}
+		$$.setRange($1, $9)
+	}
+	| _REPEATED _GROUP name '=' _INT_LIT compactOptions '{' messageBody '}' {
+		checkTag(protolex, $5.start(), $5.val)
+		if !unicode.IsUpper(rune($3.val[0])) {
+			lexError(protolex, $3.start(), fmt.Sprintf("group %s should have a name that starts with a capital letter", $3.val))
+		}
+		lbl := fieldLabel{identNode: $1, repeated: true}
+		$$ = &groupNode{groupKeyword: $2, label: lbl, name: $3, tag: $5, options: $6, decls: $8}
+		$$.setRange($1, $9)
+	}
 
 oneof : _ONEOF name '{' oneofBody '}' {
 		c := 0
diff --git a/desc/protoparse/proto.y.go b/desc/protoparse/proto.y.go
index dbd72c0..61f4edc 100644
--- a/desc/protoparse/proto.y.go
+++ b/desc/protoparse/proto.y.go
@@ -198,7 +198,7 @@ const protoEofCode = 1
 const protoErrCode = 2
 const protoInitialStackSize = 16
 
-//line proto.y:996
+//line proto.y:1023
 
 //line yacctab:1
 var protoExca = [...]int{
@@ -218,16 +218,16 @@ var protoExca = [...]int{
 	1, 3,
 	-2, 0,
 	-1, 93,
-	55, 162,
+	55, 165,
 	-2, 0,
 	-1, 94,
-	55, 150,
+	55, 153,
 	-2, 0,
 	-1, 95,
-	55, 179,
+	55, 182,
 	-2, 0,
 	-1, 97,
-	55, 188,
+	55, 191,
 	-2, 0,
 	-1, 110,
 	55, 54,
@@ -236,7 +236,7 @@ var protoExca = [...]int{
 	61, 54,
 	-2, 0,
 	-1, 246,
-	55, 103,
+	55, 106,
 	-2, 0,
 	-1, 272,
 	61, 54,
@@ -245,353 +245,384 @@ var protoExca = [...]int{
 	61, 54,
 	-2, 0,
 	-1, 354,
-	55, 162,
+	55, 165,
 	-2, 0,
-	-1, 357,
-	55, 162,
+	-1, 358,
+	55, 165,
 	-2, 0,
-	-1, 360,
-	55, 162,
+	-1, 362,
+	55, 165,
 	-2, 0,
-	-1, 370,
+	-1, 373,
 	61, 54,
 	-2, 0,
-	-1, 372,
+	-1, 375,
 	61, 54,
 	-2, 0,
-	-1, 393,
-	55, 162,
+	-1, 380,
+	55, 165,
 	-2, 0,
-	-1, 404,
-	55, 200,
+	-1, 383,
+	55, 165,
+	-2, 0,
+	-1, 386,
+	55, 165,
+	-2, 0,
+	-1, 402,
+	55, 165,
+	-2, 0,
+	-1, 416,
+	55, 203,
 	-2, 0,
 }
 
 const protoPrivate = 57344
 
-const protoLast = 2634
+const protoLast = 2850
 
 var protoAct = [...]int{
 
-	31, 124, 8, 406, 8, 8, 116, 117, 169, 75,
-	309, 288, 293, 209, 196, 107, 210, 103, 181, 78,
-	79, 161, 83, 104, 8, 168, 123, 81, 133, 118,
-	155, 195, 102, 142, 105, 145, 391, 358, 346, 331,
-	241, 355, 352, 242, 30, 76, 345, 330, 243, 80,
-	26, 244, 244, 338, 344, 244, 244, 244, 328, 84,
-	347, 304, 87, 88, 276, 275, 401, 212, 244, 342,
-	321, 29, 212, 244, 115, 383, 244, 268, 212, 227,
-	110, 226, 203, 367, 303, 226, 90, 412, 229, 225,
-	398, 101, 109, 225, 396, 151, 146, 266, 393, 162,
-	226, 360, 399, 308, 226, 265, 92, 226, 225, 374,
-	96, 173, 225, 351, 357, 225, 320, 403, 354, 404,
-	89, 249, 157, 379, 186, 156, 213, 90, 153, 250,
-	248, 213, 377, 246, 194, 79, 78, 213, 243, 226,
-	198, 199, 224, 97, 183, 151, 146, 225, 95, 94,
-	223, 93, 165, 375, 366, 361, 86, 341, 335, 188,
-	190, 192, 162, 17, 14, 80, 76, 220, 211, 173,
-	4, 15, 165, 200, 16, 17, 202, 222, 153, 86,
-	205, 157, 218, 17, 156, 215, 86, 202, 409, 234,
-	235, 236, 237, 238, 239, 86, 228, 166, 285, 17,
-	219, 232, 164, 230, 100, 19, 18, 20, 21, 409,
-	216, 183, 96, 206, 13, 187, 167, 166, 25, 365,
-	17, 368, 164, 211, 264, 217, 14, 99, 109, 364,
-	173, 332, 283, 15, 98, 282, 16, 17, 408, 281,
-	280, 410, 290, 85, 279, 269, 278, 247, 294, 240,
-	207, 271, 91, 24, 289, 273, 267, 245, 286, 408,
-	29, 197, 277, 382, 381, 327, 326, 19, 18, 20,
-	21, 109, 76, 173, 173, 299, 13, 325, 291, 306,
-	324, 211, 222, 211, 307, 302, 121, 11, 323, 11,
-	11, 322, 119, 10, 294, 10, 10, 311, 317, 301,
-	336, 337, 5, 315, 197, 334, 23, 284, 305, 11,
-	178, 178, 179, 175, 176, 10, 86, 173, 173, 29,
-	163, 299, 180, 29, 177, 23, 222, 160, 329, 27,
-	28, 3, 340, 109, 22, 12, 154, 147, 144, 343,
-	122, 289, 348, 362, 208, 339, 109, 109, 148, 173,
-	127, 120, 9, 201, 9, 9, 292, 222, 140, 76,
-	126, 376, 296, 125, 378, 363, 353, 380, 356, 295,
-	359, 173, 170, 173, 9, 313, 172, 251, 369, 371,
-	108, 106, 182, 405, 186, 173, 186, 173, 186, 287,
-	7, 6, 2, 222, 394, 222, 384, 1, 386, 0,
-	400, 0, 0, 0, 0, 0, 407, 407, 186, 411,
-	0, 0, 311, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 314, 392, 29, 111, 114, 32,
-	33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
-	43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
-	53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
-	63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
-	73, 74, 0, 0, 0, 0, 110, 0, 0, 0,
-	0, 0, 0, 0, 316, 112, 113, 0, 0, 0,
-	312, 29, 111, 114, 32, 33, 34, 35, 36, 37,
-	38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-	48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
-	58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
-	68, 69, 70, 71, 72, 73, 74, 0, 0, 0,
-	0, 110, 0, 0, 0, 0, 0, 0, 0, 272,
-	112, 113, 0, 0, 270, 29, 111, 114, 32, 33,
-	34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
-	44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
-	54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-	64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
-	74, 0, 0, 0, 0, 110, 0, 0, 0, 0,
-	0, 0, 0, 372, 112, 113, 29, 111, 114, 32,
-	33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
-	43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
-	53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
-	63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
-	73, 74, 0, 0, 0, 0, 110, 0, 0, 0,
-	0, 0, 171, 0, 370, 112, 113, 32, 33, 34,
+	31, 124, 8, 117, 8, 8, 418, 169, 196, 210,
+	293, 168, 309, 209, 104, 102, 103, 242, 75, 78,
+	79, 288, 83, 133, 8, 116, 181, 107, 123, 105,
+	118, 81, 142, 155, 161, 346, 145, 195, 331, 362,
+	358, 400, 347, 345, 80, 26, 330, 241, 30, 76,
+	360, 344, 244, 244, 84, 243, 244, 87, 88, 356,
+	354, 352, 244, 338, 328, 244, 304, 276, 275, 413,
+	342, 321, 212, 244, 244, 389, 244, 370, 244, 244,
+	268, 244, 29, 212, 115, 212, 203, 303, 227, 110,
+	90, 101, 109, 89, 226, 151, 146, 229, 226, 162,
+	90, 92, 225, 407, 226, 402, 225, 405, 308, 226,
+	386, 173, 225, 377, 96, 266, 383, 225, 351, 380,
+	186, 226, 246, 265, 157, 249, 156, 153, 97, 225,
+	320, 213, 368, 250, 194, 79, 78, 95, 94, 183,
+	198, 199, 213, 248, 213, 151, 146, 93, 424, 226,
+	224, 243, 165, 86, 188, 190, 192, 225, 223, 411,
+	80, 421, 162, 17, 415, 86, 416, 220, 384, 173,
+	76, 202, 17, 86, 381, 165, 222, 153, 86, 200,
+	211, 205, 202, 157, 378, 156, 17, 228, 215, 234,
+	235, 236, 237, 238, 239, 218, 421, 166, 230, 369,
+	364, 100, 164, 341, 335, 217, 183, 17, 285, 232,
+	219, 420, 14, 99, 422, 216, 96, 264, 4, 15,
+	166, 98, 16, 17, 206, 164, 85, 187, 109, 167,
+	173, 25, 367, 332, 283, 211, 282, 281, 280, 279,
+	278, 273, 271, 247, 269, 267, 420, 240, 294, 207,
+	91, 24, 286, 19, 18, 20, 21, 277, 371, 245,
+	290, 388, 13, 289, 121, 11, 387, 11, 11, 327,
+	299, 109, 326, 173, 173, 325, 76, 307, 324, 306,
+	302, 222, 305, 323, 317, 322, 315, 11, 178, 179,
+	301, 29, 311, 211, 294, 211, 291, 27, 28, 180,
+	336, 337, 329, 334, 252, 253, 254, 255, 256, 257,
+	258, 259, 260, 261, 262, 263, 299, 173, 173, 339,
+	175, 176, 29, 197, 197, 222, 284, 340, 348, 178,
+	86, 177, 29, 109, 343, 119, 10, 163, 10, 10,
+	353, 355, 357, 359, 361, 363, 109, 109, 366, 173,
+	289, 3, 160, 365, 22, 5, 222, 12, 10, 23,
+	154, 372, 374, 76, 147, 144, 122, 120, 9, 208,
+	9, 9, 148, 127, 173, 201, 173, 292, 23, 140,
+	379, 126, 296, 186, 382, 390, 186, 392, 385, 186,
+	9, 173, 125, 173, 295, 170, 313, 172, 222, 186,
+	222, 186, 403, 186, 251, 401, 395, 108, 106, 397,
+	182, 417, 399, 311, 287, 7, 186, 6, 419, 419,
+	2, 1, 0, 0, 423, 0, 0, 314, 412, 29,
+	111, 114, 32, 33, 34, 35, 36, 37, 38, 39,
+	40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+	50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+	60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+	70, 71, 72, 73, 74, 0, 0, 0, 0, 110,
+	0, 0, 0, 0, 0, 0, 0, 316, 112, 113,
+	0, 0, 0, 312, 29, 111, 114, 32, 33, 34,
 	35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
 	45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
 	55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
 	65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 397, 0, 171, 0, 0, 0, 174, 32, 33,
-	34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
-	44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
-	54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-	64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
-	74, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 395, 0, 171, 0, 0, 0, 174, 32,
-	33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
-	43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
-	53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
-	63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
-	73, 74, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 373, 0, 0, 0, 0, 0, 174,
-	29, 111, 114, 32, 33, 34, 35, 36, 37, 38,
-	39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
-	49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
-	59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
-	69, 70, 71, 72, 73, 74, 0, 0, 0, 0,
-	110, 0, 0, 0, 0, 0, 171, 0, 0, 112,
-	113, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+	0, 0, 0, 0, 110, 0, 0, 0, 0, 0,
+	0, 0, 272, 112, 113, 0, 0, 270, 29, 111,
+	114, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+	41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+	51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+	61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+	71, 72, 73, 74, 0, 0, 0, 0, 110, 0,
+	0, 0, 0, 0, 0, 0, 375, 112, 113, 29,
+	111, 114, 32, 33, 34, 35, 36, 37, 38, 39,
+	40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+	50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+	60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+	70, 71, 72, 73, 74, 0, 0, 0, 0, 110,
+	0, 0, 0, 0, 0, 171, 0, 373, 112, 113,
+	32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+	42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+	52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+	62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+	72, 73, 74, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 406, 0, 171, 0, 0, 0,
+	174, 32, 33, 34, 35, 36, 37, 38, 39, 40,
 	41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
 	51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
 	61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
 	71, 72, 73, 74, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 350, 0, 171, 0, 0,
+	0, 0, 0, 0, 0, 404, 0, 171, 0, 0,
 	0, 174, 32, 33, 34, 35, 36, 37, 38, 39,
 	40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
 	50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
 	60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
 	70, 71, 72, 73, 74, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 319, 0, 171, 0,
-	0, 0, 174, 32, 33, 34, 35, 36, 37, 38,
-	39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
-	49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
-	59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
-	69, 70, 71, 72, 73, 74, 0, 0, 0, 0,
-	0, 221, 0, 0, 0, 0, 0, 0, 0, 387,
-	0, 0, 0, 174, 32, 33, 34, 35, 36, 37,
+	0, 0, 0, 0, 0, 0, 376, 0, 0, 0,
+	0, 0, 174, 29, 111, 114, 32, 33, 34, 35,
+	36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+	46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+	56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+	66, 67, 68, 69, 70, 71, 72, 73, 74, 0,
+	0, 0, 0, 110, 0, 0, 0, 0, 0, 171,
+	0, 0, 112, 113, 32, 33, 34, 35, 36, 37,
 	38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
 	48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
 	58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
-	68, 69, 70, 71, 72, 73, 74, 252, 253, 254,
-	255, 256, 257, 258, 259, 260, 261, 262, 263, 0,
-	385, 0, 0, 0, 174, 32, 33, 34, 35, 36,
+	68, 69, 70, 71, 72, 73, 74, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 350, 0,
+	171, 0, 0, 0, 174, 32, 33, 34, 35, 36,
 	37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
 	47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
 	57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
 	67, 68, 69, 70, 71, 72, 73, 74, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 349, 0, 0, 0, 174, 32, 33, 34, 35,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 319,
+	0, 171, 0, 0, 0, 174, 32, 33, 34, 35,
 	36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
 	46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
 	56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
 	66, 67, 68, 69, 70, 71, 72, 73, 74, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 318, 0, 0, 0, 174, 32, 33, 34,
+	0, 0, 0, 0, 221, 0, 0, 0, 0, 0,
+	0, 0, 393, 0, 0, 0, 174, 32, 33, 34,
 	35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
 	45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
 	55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
 	65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 274, 0, 0, 0, 174, 32, 33,
+	0, 0, 0, 391, 0, 0, 0, 174, 32, 33,
 	34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
 	44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
 	54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
 	64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
 	74, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 171, 0, 0, 0, 174, 32,
+	0, 0, 0, 0, 349, 0, 0, 0, 174, 32,
 	33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
 	43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
 	53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
 	63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
 	73, 74, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 174,
+	0, 0, 0, 0, 0, 318, 0, 0, 0, 174,
 	32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
 	42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
 	52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
 	62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
 	72, 73, 74, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 77, 32,
-	33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
-	43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
-	53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
-	63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
-	73, 74, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 129, 0, 0, 0, 233, 32, 33,
-	34, 35, 36, 37, 138, 39, 40, 41, 42, 132,
-	131, 130, 46, 47, 48, 49, 50, 51, 52, 53,
-	54, 55, 56, 57, 58, 59, 60, 61, 139, 143,
-	137, 65, 66, 141, 134, 135, 136, 71, 72, 73,
-	74, 0, 0, 128, 0, 0, 402, 129, 0, 0,
-	82, 0, 32, 33, 34, 35, 36, 37, 138, 39,
-	40, 41, 42, 132, 131, 130, 46, 47, 48, 49,
+	0, 0, 0, 0, 0, 0, 274, 0, 0, 0,
+	174, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+	41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+	51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+	61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+	71, 72, 73, 74, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 171, 0, 0,
+	0, 174, 32, 33, 34, 35, 36, 37, 38, 39,
+	40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
 	50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
-	60, 61, 139, 143, 137, 65, 66, 141, 134, 135,
-	136, 71, 72, 73, 74, 0, 0, 128, 0, 0,
-	390, 129, 0, 0, 82, 0, 32, 33, 34, 35,
-	36, 37, 138, 39, 40, 41, 42, 132, 131, 130,
-	46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
-	56, 57, 58, 59, 60, 61, 139, 143, 137, 65,
-	66, 141, 134, 135, 136, 71, 72, 73, 74, 0,
-	0, 128, 0, 0, 389, 129, 0, 0, 82, 0,
-	32, 33, 34, 35, 36, 37, 138, 39, 40, 41,
-	42, 132, 131, 130, 46, 47, 48, 49, 50, 51,
-	52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
-	139, 143, 137, 65, 66, 141, 134, 135, 136, 71,
-	72, 73, 74, 0, 0, 128, 0, 0, 388, 298,
-	0, 0, 82, 0, 32, 33, 34, 35, 36, 37,
-	138, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-	48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
-	58, 59, 60, 300, 62, 63, 64, 65, 66, 67,
-	68, 69, 70, 71, 72, 73, 74, 0, 0, 297,
-	0, 0, 333, 159, 0, 0, 82, 0, 32, 33,
-	34, 35, 36, 37, 38, 39, 40, 41, 42, 132,
-	131, 130, 46, 47, 48, 49, 50, 51, 52, 53,
-	54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-	64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
-	74, 0, 0, 158, 0, 0, 214, 129, 0, 0,
-	82, 0, 32, 33, 34, 35, 36, 37, 138, 39,
-	40, 41, 42, 132, 131, 130, 46, 47, 48, 49,
+	60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+	70, 71, 72, 73, 74, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 174, 32, 33, 34, 35, 36, 37, 38,
+	39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+	49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+	59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+	69, 70, 71, 72, 73, 74, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 77, 32, 33, 34, 35, 36, 37, 38, 39,
+	40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
 	50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
-	60, 61, 139, 143, 137, 65, 66, 141, 134, 135,
-	136, 71, 72, 73, 74, 0, 0, 128, 0, 0,
-	185, 129, 0, 0, 82, 0, 32, 33, 34, 35,
-	36, 37, 138, 39, 40, 41, 42, 132, 131, 130,
-	46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
-	56, 57, 58, 59, 60, 61, 139, 143, 137, 65,
-	66, 141, 134, 135, 136, 71, 72, 73, 74, 0,
-	0, 128, 0, 0, 298, 0, 0, 0, 82, 32,
+	60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+	70, 71, 72, 73, 74, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 129, 0, 0, 0,
+	233, 32, 33, 34, 35, 36, 37, 138, 39, 40,
+	41, 42, 132, 131, 130, 46, 47, 48, 49, 50,
+	51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+	61, 139, 143, 137, 65, 66, 141, 134, 135, 136,
+	71, 72, 73, 74, 0, 0, 128, 0, 0, 414,
+	129, 0, 0, 82, 0, 32, 33, 34, 35, 36,
+	37, 138, 39, 40, 41, 42, 132, 131, 130, 46,
+	47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+	57, 58, 59, 60, 61, 139, 143, 137, 65, 66,
+	141, 134, 135, 136, 71, 72, 73, 74, 0, 0,
+	128, 0, 0, 410, 129, 0, 0, 82, 0, 32,
+	33, 34, 35, 36, 37, 138, 39, 40, 41, 42,
+	132, 131, 130, 46, 47, 48, 49, 50, 51, 52,
+	53, 54, 55, 56, 57, 58, 59, 60, 61, 139,
+	143, 137, 65, 66, 141, 134, 135, 136, 71, 72,
+	73, 74, 0, 0, 128, 0, 0, 409, 129, 0,
+	0, 82, 0, 32, 33, 34, 35, 36, 37, 138,
+	39, 40, 41, 42, 132, 131, 130, 46, 47, 48,
+	49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+	59, 60, 61, 139, 143, 137, 65, 66, 141, 134,
+	135, 136, 71, 72, 73, 74, 0, 0, 128, 0,
+	0, 408, 129, 0, 0, 82, 0, 32, 33, 34,
+	35, 36, 37, 138, 39, 40, 41, 42, 132, 131,
+	130, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+	55, 56, 57, 58, 59, 60, 61, 139, 143, 137,
+	65, 66, 141, 134, 135, 136, 71, 72, 73, 74,
+	0, 0, 128, 0, 0, 398, 129, 0, 0, 82,
+	0, 32, 33, 34, 35, 36, 37, 138, 39, 40,
+	41, 42, 132, 131, 130, 46, 47, 48, 49, 50,
+	51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+	61, 139, 143, 137, 65, 66, 141, 134, 135, 136,
+	71, 72, 73, 74, 0, 0, 128, 0, 0, 396,
+	129, 0, 0, 82, 0, 32, 33, 34, 35, 36,
+	37, 138, 39, 40, 41, 42, 132, 131, 130, 46,
+	47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+	57, 58, 59, 60, 61, 139, 143, 137, 65, 66,
+	141, 134, 135, 136, 71, 72, 73, 74, 0, 0,
+	128, 0, 0, 394, 298, 0, 0, 82, 0, 32,
 	33, 34, 35, 36, 37, 138, 39, 40, 41, 42,
 	43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
 	53, 54, 55, 56, 57, 58, 59, 60, 300, 62,
 	63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
-	73, 74, 0, 0, 297, 0, 0, 159, 0, 0,
-	0, 82, 32, 33, 34, 35, 36, 37, 38, 39,
-	40, 41, 42, 132, 131, 130, 46, 47, 48, 49,
-	50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
-	60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
-	70, 71, 72, 73, 74, 0, 0, 158, 0, 0,
-	231, 0, 0, 0, 82, 32, 33, 34, 35, 36,
-	37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
-	47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
-	57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
-	67, 68, 69, 70, 71, 72, 73, 74, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 82, 32, 33,
-	34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
-	44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
-	54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-	64, 65, 66, 67, 68, 69, 70, 71, 72, 310,
-	74, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	82, 32, 33, 34, 35, 36, 37, 38, 39, 40,
-	41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+	73, 74, 0, 0, 297, 0, 0, 333, 159, 0,
+	0, 82, 0, 32, 33, 34, 35, 36, 37, 38,
+	39, 40, 41, 42, 132, 131, 130, 46, 47, 48,
+	49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+	59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+	69, 70, 71, 72, 73, 74, 0, 0, 158, 0,
+	0, 214, 129, 0, 0, 82, 0, 32, 33, 34,
+	35, 36, 37, 138, 39, 40, 41, 42, 132, 131,
+	130, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+	55, 56, 57, 58, 59, 60, 61, 139, 143, 137,
+	65, 66, 141, 134, 135, 136, 71, 72, 73, 74,
+	0, 0, 128, 0, 0, 185, 129, 0, 0, 82,
+	0, 32, 33, 34, 35, 36, 37, 138, 39, 40,
+	41, 42, 132, 131, 130, 46, 47, 48, 49, 50,
 	51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
-	61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
-	71, 72, 73, 74, 0, 0, 0, 0, 0, 0,
+	61, 139, 143, 137, 65, 66, 141, 134, 135, 136,
+	71, 72, 73, 74, 0, 0, 128, 0, 0, 298,
 	0, 0, 0, 82, 32, 33, 34, 35, 36, 37,
-	38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+	138, 39, 40, 41, 42, 43, 44, 45, 46, 47,
 	48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
-	58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
-	68, 69, 70, 71, 72, 73, 74, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 184, 32, 33, 34,
-	35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
-	45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
-	55, 56, 57, 58, 59, 60, 193, 62, 63, 64,
+	58, 59, 60, 300, 62, 63, 64, 65, 66, 67,
+	68, 69, 70, 71, 72, 73, 74, 0, 0, 297,
+	0, 0, 159, 0, 0, 0, 82, 32, 33, 34,
+	35, 36, 37, 38, 39, 40, 41, 42, 132, 131,
+	130, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+	55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
 	65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 82,
+	0, 0, 158, 0, 0, 231, 0, 0, 0, 82,
 	32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
 	42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
-	52, 53, 54, 55, 56, 57, 58, 59, 60, 191,
+	52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
 	62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
 	72, 73, 74, 0, 0, 0, 0, 0, 0, 0,
 	0, 0, 82, 32, 33, 34, 35, 36, 37, 38,
 	39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
 	49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
-	59, 60, 189, 62, 63, 64, 65, 66, 67, 68,
-	69, 70, 71, 72, 73, 74, 0, 0, 0, 0,
-	0, 150, 0, 0, 0, 82, 32, 33, 34, 35,
-	36, 37, 138, 39, 40, 41, 42, 43, 44, 45,
+	59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+	69, 70, 71, 72, 310, 74, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 82, 32, 33, 34, 35,
+	36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
 	46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
 	56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
-	66, 152, 68, 69, 70, 71, 72, 73, 74, 0,
-	150, 149, 0, 0, 204, 32, 33, 34, 35, 36,
-	37, 138, 39, 40, 41, 42, 43, 44, 45, 46,
+	66, 67, 68, 69, 70, 71, 72, 73, 74, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 82, 32,
+	33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
+	43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+	53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
+	63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
+	73, 74, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 184, 32, 33, 34, 35, 36, 37, 38, 39,
+	40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+	50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+	60, 193, 62, 63, 64, 65, 66, 67, 68, 69,
+	70, 71, 72, 73, 74, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 82, 32, 33, 34, 35, 36,
+	37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
 	47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
-	57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
-	152, 68, 69, 70, 71, 72, 73, 74, 0, 0,
-	149, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+	57, 58, 59, 60, 191, 62, 63, 64, 65, 66,
+	67, 68, 69, 70, 71, 72, 73, 74, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 82, 32, 33,
+	34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+	44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+	54, 55, 56, 57, 58, 59, 60, 189, 62, 63,
+	64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+	74, 0, 0, 0, 0, 0, 150, 0, 0, 0,
+	82, 32, 33, 34, 35, 36, 37, 138, 39, 40,
 	41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
 	51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
-	61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
-	71, 72, 73, 74,
+	61, 62, 63, 64, 65, 66, 152, 68, 69, 70,
+	71, 72, 73, 74, 0, 150, 149, 0, 0, 204,
+	32, 33, 34, 35, 36, 37, 138, 39, 40, 41,
+	42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+	52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+	62, 63, 64, 65, 66, 152, 68, 69, 70, 71,
+	72, 73, 74, 0, 0, 149, 32, 33, 34, 35,
+	36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+	46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+	56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+	66, 67, 68, 69, 70, 71, 72, 73, 74, 14,
+	0, 0, 0, 0, 0, 0, 15, 0, 0, 16,
+	17, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	19, 18, 20, 21, 0, 0, 0, 0, 0, 13,
 }
 var protoPact = [...]int{
 
-	162, -1000, 224, 224, 202, -1000, -1000, -1000, -1000, -1000,
-	-1000, -1000, -1000, -1000, 166, 319, 2584, 1463, 2584, 2584,
-	2224, 2584, 224, -1000, 315, -1000, 191, 315, 315, -1000,
-	68, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
+	210, -1000, 2797, 2797, 200, -1000, -1000, -1000, -1000, -1000,
+	-1000, -1000, -1000, -1000, 179, 287, 2749, 1466, 2749, 2749,
+	2389, 2749, 2797, -1000, 328, -1000, 174, 328, 328, -1000,
+	41, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
 	-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
 	-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
 	-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-	-1000, -1000, -1000, -1000, -1000, 201, 27, 2224, 97, 95,
-	94, 27, 2584, 89, 182, -1000, -1000, 175, 152, -1000,
-	2584, 856, 8, 1959, 2538, 2065, 27, 150, -1000, -1000,
-	-1000, -1000, 164, -1000, -1000, 312, -1000, -1000, -1000, -1000,
-	1402, -1000, 308, 306, -1000, 2277, 1905, -1000, -1000, -1000,
-	-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 163,
-	2436, 2383, 2330, 2584, 2584, 2584, 2224, 299, 1463, 2584,
-	2584, 256, -1000, 20, 2489, -1000, -1000, -1000, -1000, -1000,
-	161, 199, 67, -1000, 1851, -1000, -1000, -1000, -1000, 158,
-	170, -1000, -1000, -1000, -1000, 148, 2584, -1000, 1036, -1000,
-	90, 87, 26, -1000, 2118, -1000, -1000, -1000, -1000, -1000,
-	-1000, -1000, 2277, -1000, 1522, -1000, -1000, -1000, 2584, 2584,
-	2584, 2584, 2584, 2584, 198, -12, -1000, 217, 79, 196,
-	78, 69, 312, 1124, -1000, -1000, -1000, 73, 45, -1000,
-	216, -1000, -1000, 305, -1000, -1000, -1000, -1000, -1000, -1000,
-	12, -1000, -1000, -1000, -1000, -1000, -1000, 487, -1000, 1341,
-	-3, -4, -1000, 2224, 195, 193, 189, 188, 184, 181,
-	302, -1000, 146, 299, 1463, 237, 2012, 294, -1000, -1000,
-	315, 24, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-	-1000, -1000, -1000, -1000, 9, 73, -1000, 62, 2171, -1000,
-	422, -1000, 1280, 975, 55, -1000, -1000, 4, 286, 283,
-	275, 272, 261, 260, 6, -1000, -1000, -21, -1000, 180,
-	-1000, -1000, 1797, -1000, -1000, -1000, -1000, -1000, 106, 2584,
-	2584, 1, 312, 2224, -1000, 105, -1000, -1000, -1000, 3,
-	2224, -1000, -1000, -14, -8, -1000, 1219, 914, 52, -1000,
-	-1000, -1000, -10, 64, -11, 60, -15, 47, -1000, 103,
-	-1000, 1463, 856, -1000, -1000, -1000, 178, 168, -1000, 102,
-	22, -1000, 172, -1000, -1000, 612, 551, -1000, 792, 48,
-	-1000, -1000, -1000, 101, 1959, -1000, 80, 1959, -1000, 71,
-	1959, -1000, -1000, -1000, 259, 258, -1000, -1000, 10, -1000,
-	1158, -1000, 1097, -1000, -1000, -1000, 1743, -1000, 1689, -1000,
-	1635, -16, 44, 2171, 731, 33, 670, 29, -1000, -1000,
-	-1000, -1000, 50, 1959, 0, -1000, -1000, -1000, -1000, -1000,
-	1581, 65, -1000, -1000, 207, 186, -1000, -1000, -1000, 35,
-	-1000, -1000, -1000,
+	-1000, -1000, -1000, -1000, -1000, 199, 31, 2389, 93, 84,
+	83, 31, 2749, 74, 169, -1000, -1000, 161, 149, -1000,
+	2749, 859, 18, 2124, 2703, 2230, 31, 173, -1000, -1000,
+	-1000, -1000, 177, -1000, -1000, 326, -1000, -1000, -1000, -1000,
+	1405, -1000, 315, 283, -1000, 2442, 2070, -1000, -1000, -1000,
+	-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 175,
+	2601, 2548, 2495, 2749, 2749, 2749, 2389, 319, 1466, 2749,
+	2749, 318, -1000, 24, 2654, -1000, -1000, -1000, -1000, -1000,
+	172, 198, 78, -1000, 2016, -1000, -1000, -1000, -1000, 163,
+	150, -1000, -1000, -1000, -1000, 158, 2749, -1000, 1039, -1000,
+	98, 97, 35, -1000, 2283, -1000, -1000, -1000, -1000, -1000,
+	-1000, -1000, 2442, -1000, 1525, -1000, -1000, -1000, 2749, 2749,
+	2749, 2749, 2749, 2749, 196, -5, -1000, 219, 68, 192,
+	91, 73, 326, 281, -1000, -1000, -1000, 80, 63, -1000,
+	205, -1000, -1000, 324, -1000, -1000, -1000, -1000, -1000, -1000,
+	15, -1000, -1000, -1000, -1000, -1000, -1000, 490, -1000, 1344,
+	0, -1, -1000, 2389, 189, 188, 187, 186, 185, 183,
+	321, -1000, 156, 319, 1466, 255, 2177, 285, -1000, -1000,
+	328, 27, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
+	-1000, -1000, -1000, -1000, 14, 80, -1000, 67, 2336, -1000,
+	425, -1000, 1283, 978, 69, -1000, -1000, 5, 280, 278,
+	273, 270, 267, 264, 12, -1000, -1000, -22, -1000, 182,
+	-1000, -1000, 1962, -1000, -1000, -1000, -1000, -1000, 152, 2749,
+	2749, 11, 326, 2389, -1000, 151, -1000, -1000, -1000, 4,
+	2389, -1000, -1000, -17, -26, -1000, 1222, 917, 57, -1000,
+	-1000, -1000, 9, 6, 7, -14, -2, -15, -1000, 148,
+	-1000, 1466, 859, -1000, -1000, -1000, 181, 81, -1000, 147,
+	16, -1000, 209, -1000, -1000, 615, 554, -1000, 795, 52,
+	-1000, -1000, -1000, 132, 2124, 65, -1000, 122, 2124, 62,
+	-1000, 116, 2124, 56, -1000, -1000, -1000, 261, 256, -1000,
+	-1000, 10, -1000, 1161, -1000, 1100, -1000, -1000, -1000, 1908,
+	2124, -1000, 1854, 2124, -1000, 1800, 2124, -11, 51, 2336,
+	734, 46, 673, 42, -1000, 1746, -1000, 1692, -1000, 1638,
+	-1000, 107, 2124, 3, -1000, -1000, -1000, -1000, -1000, -1000,
+	-1000, -1000, 1584, 112, -1000, -1000, 194, 159, -1000, -1000,
+	-1000, 96, -1000, -1000, -1000,
 }
 var protoPgo = [...]int{
 
-	0, 397, 392, 302, 331, 391, 390, 1, 11, 389,
-	3, 383, 9, 18, 382, 43, 32, 17, 23, 381,
-	380, 16, 15, 0, 377, 27, 28, 376, 375, 25,
-	8, 372, 29, 369, 363, 26, 362, 360, 358, 351,
-	7, 6, 12, 356, 353, 350, 348, 33, 14, 31,
-	13, 344, 340, 292, 35, 338, 337, 286, 30, 336,
-	34, 335, 21, 327, 320, 10,
+	0, 421, 420, 355, 351, 417, 415, 1, 21, 414,
+	6, 411, 18, 26, 410, 17, 15, 16, 14, 408,
+	407, 9, 27, 0, 404, 31, 23, 397, 396, 11,
+	7, 395, 30, 394, 392, 28, 382, 381, 379, 367,
+	3, 25, 10, 377, 375, 373, 372, 32, 8, 37,
+	13, 369, 366, 335, 36, 365, 364, 264, 33, 360,
+	29, 357, 34, 352, 337, 12,
 }
 var protoR1 = [...]int{
 
@@ -605,21 +636,22 @@ var protoR1 = [...]int{
 	31, 27, 27, 27, 28, 28, 28, 28, 28, 28,
 	28, 28, 28, 26, 26, 32, 32, 32, 32, 32,
 	32, 32, 32, 15, 9, 9, 8, 35, 35, 35,
-	34, 43, 43, 43, 42, 42, 42, 42, 42, 42,
-	33, 33, 36, 37, 37, 38, 24, 24, 24, 24,
-	24, 24, 24, 24, 24, 24, 24, 24, 52, 52,
-	49, 49, 48, 48, 48, 51, 51, 50, 50, 50,
-	45, 45, 46, 46, 47, 44, 44, 53, 55, 55,
-	55, 54, 54, 54, 54, 54, 54, 56, 56, 39,
-	41, 41, 41, 40, 40, 40, 40, 40, 40, 40,
-	40, 40, 40, 40, 40, 40, 57, 59, 59, 59,
-	58, 58, 58, 58, 58, 61, 63, 63, 63, 62,
-	62, 62, 62, 62, 64, 64, 65, 65, 11, 11,
-	11, 10, 10, 10, 10, 23, 23, 23, 23, 23,
+	35, 35, 35, 34, 43, 43, 43, 42, 42, 42,
+	42, 42, 42, 33, 33, 36, 37, 37, 38, 24,
+	24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+	24, 52, 52, 49, 49, 48, 48, 48, 51, 51,
+	50, 50, 50, 45, 45, 46, 46, 47, 44, 44,
+	53, 55, 55, 55, 54, 54, 54, 54, 54, 54,
+	56, 56, 39, 41, 41, 41, 40, 40, 40, 40,
+	40, 40, 40, 40, 40, 40, 40, 40, 40, 57,
+	59, 59, 59, 58, 58, 58, 58, 58, 61, 63,
+	63, 63, 62, 62, 62, 62, 62, 64, 64, 65,
+	65, 11, 11, 11, 10, 10, 10, 10, 23, 23,
+	23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
 	23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
 	23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
 	23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
-	23, 23, 23, 23, 23, 23, 23, 23,
+	23,
 }
 var protoR2 = [...]int{
 
@@ -633,21 +665,22 @@ var protoR2 = [...]int{
 	4, 1, 3, 3, 1, 3, 3, 3, 5, 5,
 	3, 5, 5, 1, 2, 6, 6, 6, 5, 7,
 	7, 7, 6, 3, 3, 1, 3, 8, 8, 8,
+	9, 9, 9, 5, 2, 1, 0, 1, 1, 1,
+	1, 2, 1, 5, 6, 7, 5, 6, 6, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 3, 4, 3, 1, 1, 3, 3, 3, 1,
+	1, 3, 3, 3, 1, 3, 1, 3, 3, 1,
 	5, 2, 1, 0, 1, 1, 1, 1, 2, 1,
-	5, 6, 7, 5, 6, 6, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1, 3, 4,
-	3, 1, 1, 3, 3, 3, 1, 1, 3, 3,
-	3, 1, 3, 1, 3, 3, 1, 5, 2, 1,
-	0, 1, 1, 1, 1, 2, 1, 4, 5, 5,
-	2, 1, 0, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 2, 1, 5, 2, 1, 0,
-	1, 1, 1, 2, 1, 5, 2, 1, 0, 1,
-	1, 1, 2, 1, 10, 12, 2, 1, 2, 1,
-	0, 1, 1, 2, 1, 1, 1, 1, 1, 1,
+	4, 5, 5, 2, 1, 0, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 2, 1, 5,
+	2, 1, 0, 1, 1, 1, 2, 1, 5, 2,
+	1, 0, 1, 1, 1, 2, 1, 10, 12, 2,
+	1, 2, 1, 0, 1, 1, 2, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
+	1,
 }
 var protoChk = [...]int{
 
@@ -686,58 +719,60 @@ var protoChk = [...]int{
 	61, 66, 5, 5, 5, 5, 5, 5, 52, -15,
 	68, 60, 51, 55, -42, 52, -23, -23, 52, -15,
 	-26, 52, 66, -26, 68, 60, 52, 68, -29, 2,
-	61, 61, 52, -15, 54, 52, -15, 54, 52, -15,
-	54, 52, -8, -16, 51, 51, 52, 61, 49, -16,
-	62, -16, 62, 61, 61, 52, -41, 52, -41, 52,
-	-41, 5, 5, 65, -29, 2, -29, 2, 55, 55,
-	55, 52, -15, 54, -65, 61, 61, 61, 61, 52,
-	-41, 66, 55, 52, 54, -11, -10, -7, 52, 2,
-	55, -10, 52,
+	61, 61, 52, -15, 54, -15, 52, -15, 54, -15,
+	52, -15, 54, -15, 52, -8, -16, 51, 51, 52,
+	61, 49, -16, 62, -16, 62, 61, 61, 52, -41,
+	54, 52, -41, 54, 52, -41, 54, 5, 5, 65,
+	-29, 2, -29, 2, 55, -41, 55, -41, 55, -41,
+	52, -15, 54, -65, 61, 61, 61, 61, 55, 55,
+	55, 52, -41, 66, 55, 52, 54, -11, -10, -7,
+	52, 2, 55, -10, 52,
 }
 var protoDef = [...]int{
 
 	-2, -2, -2, -2, 0, 6, 7, 8, 9, 10,
 	11, 12, 13, 14, 16, 0, 0, 0, 0, 0,
 	0, 0, -2, 5, 0, 15, 0, 0, 0, 49,
-	0, 22, 205, 206, 207, 208, 209, 210, 211, 212,
-	213, 214, 215, 216, 217, 218, 219, 220, 221, 222,
-	223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
-	233, 234, 235, 236, 237, 238, 239, 240, 241, 242,
-	243, 244, 245, 246, 247, 0, 25, 0, 0, 0,
+	0, 22, 208, 209, 210, 211, 212, 213, 214, 215,
+	216, 217, 218, 219, 220, 221, 222, 223, 224, 225,
+	226, 227, 228, 229, 230, 231, 232, 233, 234, 235,
+	236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
+	246, 247, 248, 249, 250, 0, 25, 0, 0, 0,
 	0, 83, 0, 0, 0, 18, 50, 0, 0, 21,
 	0, 0, 0, -2, -2, -2, 84, -2, 17, 19,
 	20, 23, 0, 32, 33, 34, 35, 36, 37, 38,
-	-2, 39, 0, 0, 44, 26, 0, 161, 163, 164,
-	165, 166, 167, 168, 169, 170, 171, 172, 173, 175,
-	0, 0, 0, 0, 241, 242, 0, 237, 211, 235,
-	0, 240, 141, 236, 0, 149, 151, 152, 153, 154,
-	156, 0, 240, 143, 0, 178, 180, 181, 182, 184,
-	0, 187, 189, 190, 191, 193, 0, 24, 0, 52,
+	-2, 39, 0, 0, 44, 26, 0, 164, 166, 167,
+	168, 169, 170, 171, 172, 173, 174, 175, 176, 178,
+	0, 0, 0, 0, 244, 245, 0, 240, 214, 238,
+	0, 243, 144, 239, 0, 152, 154, 155, 156, 157,
+	159, 0, 243, 146, 0, 181, 183, 184, 185, 187,
+	0, 190, 192, 193, 194, 196, 0, 24, 0, 52,
 	55, 60, 0, 71, 0, 40, 46, 47, 41, 45,
-	48, 27, 28, 30, 0, 159, 160, 174, 0, 234,
-	0, 234, 0, 234, 0, 0, 131, 132, 0, 0,
-	0, 0, 146, 0, 147, 148, 155, 0, 0, 136,
-	137, 42, 43, 0, 176, 177, 183, 185, 186, 192,
+	48, 27, 28, 30, 0, 162, 163, 177, 0, 237,
+	0, 237, 0, 237, 0, 0, 134, 135, 0, 0,
+	0, 0, 149, 0, 150, 151, 158, 0, 0, 139,
+	140, 42, 43, 0, 179, 180, 186, 188, 189, 195,
 	0, 51, 53, 56, 57, 58, 59, 0, 66, -2,
 	0, 0, 29, 0, 0, 0, 0, 0, 0, 0,
-	0, 128, 0, 0, 0, 0, -2, 0, 140, 144,
-	0, 0, 116, 117, 118, 119, 120, 121, 122, 123,
-	124, 125, 126, 127, 0, 0, 142, 0, 0, 61,
+	0, 131, 0, 0, 0, 0, -2, 0, 143, 147,
+	0, 0, 119, 120, 121, 122, 123, 124, 125, 126,
+	127, 128, 129, 130, 0, 0, 145, 0, 0, 61,
 	0, 65, -2, 0, 60, 72, 73, 0, 0, 0,
-	0, 0, 0, 0, 0, 129, 130, 0, 95, 0,
-	133, 134, 0, 102, 104, 105, 106, 107, 109, 0,
-	234, 0, 145, 0, 157, 0, 135, 138, 139, 0,
-	246, 197, 62, 0, 0, 74, -2, 0, 60, 68,
+	0, 0, 0, 0, 0, 132, 133, 0, 95, 0,
+	136, 137, 0, 105, 107, 108, 109, 110, 112, 0,
+	237, 0, 148, 0, 160, 0, 138, 141, 142, 0,
+	249, 200, 62, 0, 0, 74, -2, 0, 60, 68,
 	70, 31, 0, 0, 0, 0, 0, 0, 88, 0,
-	93, 0, 0, 100, 101, 108, 0, 0, 113, 0,
-	0, 158, 0, 196, 63, 0, 0, 64, 0, 60,
-	67, 69, 85, 0, -2, 86, 0, -2, 87, 0,
-	-2, 92, 94, 96, 0, 0, 114, 115, 0, 75,
-	-2, 76, -2, 77, 80, 89, 0, 90, 0, 91,
-	0, 0, 0, 0, 0, 60, 0, 60, 97, 98,
-	99, 110, 0, -2, 0, 78, 81, 79, 82, 111,
-	0, 0, 112, 194, -2, 0, 199, 201, 202, 204,
-	195, 198, 203,
+	93, 0, 0, 103, 104, 111, 0, 0, 116, 0,
+	0, 161, 0, 199, 63, 0, 0, 64, 0, 60,
+	67, 69, 85, 0, -2, 0, 86, 0, -2, 0,
+	87, 0, -2, 0, 92, 94, 96, 0, 0, 117,
+	118, 0, 75, -2, 76, -2, 77, 80, 89, 0,
+	-2, 90, 0, -2, 91, 0, -2, 0, 0, 0,
+	0, 60, 0, 60, 97, 0, 98, 0, 99, 0,
+	113, 0, -2, 0, 78, 81, 79, 82, 100, 101,
+	102, 114, 0, 0, 115, 197, -2, 0, 202, 204,
+	205, 207, 198, 201, 206,
 }
 var protoTok1 = [...]int{
 
@@ -1773,8 +1808,44 @@ protodefault:
 			protoVAL.grp.setRange(protoDollar[1].id, protoDollar[8].b)
 		}
 	case 100:
+		protoDollar = protoS[protopt-9 : protopt+1]
+//line proto.y:563
+		{
+			checkTag(protolex, protoDollar[5].i.start(), protoDollar[5].i.val)
+			if !unicode.IsUpper(rune(protoDollar[3].id.val[0])) {
+				lexError(protolex, protoDollar[3].id.start(), fmt.Sprintf("group %s should have a name that starts with a capital letter", protoDollar[3].id.val))
+			}
+			lbl := fieldLabel{identNode: protoDollar[1].id, required: true}
+			protoVAL.grp = &groupNode{groupKeyword: protoDollar[2].id, label: lbl, name: protoDollar[3].id, tag: protoDollar[5].i, options: protoDollar[6].cmpctOpts, decls: protoDollar[8].msgDecls}
+			protoVAL.grp.setRange(protoDollar[1].id, protoDollar[9].b)
+		}
+	case 101:
+		protoDollar = protoS[protopt-9 : protopt+1]
+//line proto.y:572
+		{
+			checkTag(protolex, protoDollar[5].i.start(), protoDollar[5].i.val)
+			if !unicode.IsUpper(rune(protoDollar[3].id.val[0])) {
+				lexError(protolex, protoDollar[3].id.start(), fmt.Sprintf("group %s should have a name that starts with a capital letter", protoDollar[3].id.val))
+			}
+			lbl := fieldLabel{identNode: protoDollar[1].id}
+			protoVAL.grp = &groupNode{groupKeyword: protoDollar[2].id, label: lbl, name: protoDollar[3].id, tag: protoDollar[5].i, options: protoDollar[6].cmpctOpts, decls: protoDollar[8].msgDecls}
+			protoVAL.grp.setRange(protoDollar[1].id, protoDollar[9].b)
+		}
+	case 102:
+		protoDollar = protoS[protopt-9 : protopt+1]
+//line proto.y:581
+		{
+			checkTag(protolex, protoDollar[5].i.start(), protoDollar[5].i.val)
+			if !unicode.IsUpper(rune(protoDollar[3].id.val[0])) {
+				lexError(protolex, protoDollar[3].id.start(), fmt.Sprintf("group %s should have a name that starts with a capital letter", protoDollar[3].id.val))
+			}
+			lbl := fieldLabel{identNode: protoDollar[1].id, repeated: true}
+			protoVAL.grp = &groupNode{groupKeyword: protoDollar[2].id, label: lbl, name: protoDollar[3].id, tag: protoDollar[5].i, options: protoDollar[6].cmpctOpts, decls: protoDollar[8].msgDecls}
+			protoVAL.grp.setRange(protoDollar[1].id, protoDollar[9].b)
+		}
+	case 103:
 		protoDollar = protoS[protopt-5 : protopt+1]
-//line proto.y:564
+//line proto.y:591
 		{
 			c := 0
 			for _, el := range protoDollar[4].ooDecls {
@@ -1788,71 +1859,71 @@ protodefault:
 			protoVAL.oo = &oneOfNode{name: protoDollar[2].id, decls: protoDollar[4].ooDecls}
 			protoVAL.oo.setRange(protoDollar[1].id, protoDollar[5].b)
 		}
-	case 101:
+	case 104:
 		protoDollar = protoS[protopt-2 : protopt+1]
-//line proto.y:578
+//line proto.y:605
 		{
 			protoVAL.ooDecls = append(protoDollar[1].ooDecls, protoDollar[2].ooDecls...)
 		}
-	case 103:
+	case 106:
 		protoDollar = protoS[protopt-0 : protopt+1]
-//line proto.y:582
+//line proto.y:609
 		{
 			protoVAL.ooDecls = nil
 		}
-	case 104:
+	case 107:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:586
+//line proto.y:613
 		{
 			protoVAL.ooDecls = []*oneOfElement{{option: protoDollar[1].opts[0]}}
 		}
-	case 105:
+	case 108:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:589
+//line proto.y:616
 		{
 			protoVAL.ooDecls = []*oneOfElement{{field: protoDollar[1].fld}}
 		}
-	case 106:
+	case 109:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:592
+//line proto.y:619
 		{
 			protoVAL.ooDecls = []*oneOfElement{{group: protoDollar[1].grp}}
 		}
-	case 107:
+	case 110:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:595
+//line proto.y:622
 		{
 			protoVAL.ooDecls = []*oneOfElement{{empty: protoDollar[1].b}}
 		}
-	case 108:
+	case 111:
 		protoDollar = protoS[protopt-2 : protopt+1]
-//line proto.y:598
+//line proto.y:625
 		{
 		}
-	case 109:
+	case 112:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:600
+//line proto.y:627
 		{
 		}
-	case 110:
+	case 113:
 		protoDollar = protoS[protopt-5 : protopt+1]
-//line proto.y:603
+//line proto.y:630
 		{
 			checkTag(protolex, protoDollar[4].i.start(), protoDollar[4].i.val)
 			protoVAL.fld = &fieldNode{fldType: protoDollar[1].cid, name: protoDollar[2].id, tag: protoDollar[4].i}
 			protoVAL.fld.setRange(protoDollar[1].cid, protoDollar[5].b)
 		}
-	case 111:
+	case 114:
 		protoDollar = protoS[protopt-6 : protopt+1]
-//line proto.y:608
+//line proto.y:635
 		{
 			checkTag(protolex, protoDollar[4].i.start(), protoDollar[4].i.val)
 			protoVAL.fld = &fieldNode{fldType: protoDollar[1].cid, name: protoDollar[2].id, tag: protoDollar[4].i, options: protoDollar[5].cmpctOpts}
 			protoVAL.fld.setRange(protoDollar[1].cid, protoDollar[6].b)
 		}
-	case 112:
+	case 115:
 		protoDollar = protoS[protopt-7 : protopt+1]
-//line proto.y:614
+//line proto.y:641
 		{
 			checkTag(protolex, protoDollar[4].i.start(), protoDollar[4].i.val)
 			if !unicode.IsUpper(rune(protoDollar[2].id.val[0])) {
@@ -1861,52 +1932,52 @@ protodefault:
 			protoVAL.grp = &groupNode{groupKeyword: protoDollar[1].id, name: protoDollar[2].id, tag: protoDollar[4].i, decls: protoDollar[6].msgDecls}
 			protoVAL.grp.setRange(protoDollar[1].id, protoDollar[7].b)
 		}
-	case 113:
+	case 116:
 		protoDollar = protoS[protopt-5 : protopt+1]
-//line proto.y:623
+//line proto.y:650
 		{
 			checkTag(protolex, protoDollar[4].i.start(), protoDollar[4].i.val)
 			protoVAL.mapFld = &mapFieldNode{mapType: protoDollar[1].mapType, name: protoDollar[2].id, tag: protoDollar[4].i}
 			protoVAL.mapFld.setRange(protoDollar[1].mapType, protoDollar[5].b)
 		}
-	case 114:
+	case 117:
 		protoDollar = protoS[protopt-6 : protopt+1]
-//line proto.y:628
+//line proto.y:655
 		{
 			checkTag(protolex, protoDollar[4].i.start(), protoDollar[4].i.val)
 			protoVAL.mapFld = &mapFieldNode{mapType: protoDollar[1].mapType, name: protoDollar[2].id, tag: protoDollar[4].i, options: protoDollar[5].cmpctOpts}
 			protoVAL.mapFld.setRange(protoDollar[1].mapType, protoDollar[6].b)
 		}
-	case 115:
+	case 118:
 		protoDollar = protoS[protopt-6 : protopt+1]
-//line proto.y:634
+//line proto.y:661
 		{
 			protoVAL.mapType = &mapTypeNode{mapKeyword: protoDollar[1].id, keyType: protoDollar[3].id, valueType: protoDollar[5].cid}
 			protoVAL.mapType.setRange(protoDollar[1].id, protoDollar[6].b)
 		}
-	case 128:
+	case 131:
 		protoDollar = protoS[protopt-3 : protopt+1]
-//line proto.y:652
+//line proto.y:679
 		{
 			protoVAL.ext = &extensionRangeNode{ranges: protoDollar[2].rngs}
 			protoVAL.ext.setRange(protoDollar[1].id, protoDollar[3].b)
 		}
-	case 129:
+	case 132:
 		protoDollar = protoS[protopt-4 : protopt+1]
-//line proto.y:656
+//line proto.y:683
 		{
 			protoVAL.ext = &extensionRangeNode{ranges: protoDollar[2].rngs, options: protoDollar[3].cmpctOpts}
 			protoVAL.ext.setRange(protoDollar[1].id, protoDollar[4].b)
 		}
-	case 130:
+	case 133:
 		protoDollar = protoS[protopt-3 : protopt+1]
-//line proto.y:661
+//line proto.y:688
 		{
 			protoVAL.rngs = append(protoDollar[1].rngs, protoDollar[3].rngs...)
 		}
-	case 132:
+	case 135:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:666
+//line proto.y:693
 		{
 			if protoDollar[1].i.val > internal.MaxTag {
 				lexError(protolex, protoDollar[1].i.start(), fmt.Sprintf("range includes out-of-range tag: %d (should be between 0 and %d)", protoDollar[1].i.val, internal.MaxTag))
@@ -1915,9 +1986,9 @@ protodefault:
 			r.setRange(protoDollar[1].i, protoDollar[1].i)
 			protoVAL.rngs = []*rangeNode{r}
 		}
-	case 133:
+	case 136:
 		protoDollar = protoS[protopt-3 : protopt+1]
-//line proto.y:674
+//line proto.y:701
 		{
 			if protoDollar[1].i.val > internal.MaxTag {
 				lexError(protolex, protoDollar[1].i.start(), fmt.Sprintf("range start is out-of-range tag: %d (should be between 0 and %d)", protoDollar[1].i.val, internal.MaxTag))
@@ -1932,9 +2003,9 @@ protodefault:
 			r.setRange(protoDollar[1].i, protoDollar[3].i)
 			protoVAL.rngs = []*rangeNode{r}
 		}
-	case 134:
+	case 137:
 		protoDollar = protoS[protopt-3 : protopt+1]
-//line proto.y:688
+//line proto.y:715
 		{
 			if protoDollar[1].i.val > internal.MaxTag {
 				lexError(protolex, protoDollar[1].i.start(), fmt.Sprintf("range start is out-of-range tag: %d (should be between 0 and %d)", protoDollar[1].i.val, internal.MaxTag))
@@ -1943,24 +2014,24 @@ protodefault:
 			r.setRange(protoDollar[1].i, protoDollar[3].id)
 			protoVAL.rngs = []*rangeNode{r}
 		}
-	case 135:
+	case 138:
 		protoDollar = protoS[protopt-3 : protopt+1]
-//line proto.y:697
+//line proto.y:724
 		{
 			protoVAL.rngs = append(protoDollar[1].rngs, protoDollar[3].rngs...)
 		}
-	case 137:
+	case 140:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:702
+//line proto.y:729
 		{
 			checkInt64InInt32Range(protolex, protoDollar[1].il.start(), protoDollar[1].il.val)
 			r := &rangeNode{stNode: protoDollar[1].il, enNode: protoDollar[1].il, st: int32(protoDollar[1].il.val), en: int32(protoDollar[1].il.val)}
 			r.setRange(protoDollar[1].il, protoDollar[1].il)
 			protoVAL.rngs = []*rangeNode{r}
 		}
-	case 138:
+	case 141:
 		protoDollar = protoS[protopt-3 : protopt+1]
-//line proto.y:708
+//line proto.y:735
 		{
 			checkInt64InInt32Range(protolex, protoDollar[1].il.start(), protoDollar[1].il.val)
 			checkInt64InInt32Range(protolex, protoDollar[3].il.start(), protoDollar[3].il.val)
@@ -1971,32 +2042,32 @@ protodefault:
 			r.setRange(protoDollar[1].il, protoDollar[3].il)
 			protoVAL.rngs = []*rangeNode{r}
 		}
-	case 139:
+	case 142:
 		protoDollar = protoS[protopt-3 : protopt+1]
-//line proto.y:718
+//line proto.y:745
 		{
 			checkInt64InInt32Range(protolex, protoDollar[1].il.start(), protoDollar[1].il.val)
 			r := &rangeNode{stNode: protoDollar[1].il, enNode: protoDollar[3].id, st: int32(protoDollar[1].il.val), en: math.MaxInt32}
 			r.setRange(protoDollar[1].il, protoDollar[3].id)
 			protoVAL.rngs = []*rangeNode{r}
 		}
-	case 140:
+	case 143:
 		protoDollar = protoS[protopt-3 : protopt+1]
-//line proto.y:725
+//line proto.y:752
 		{
 			protoVAL.resvd = &reservedNode{ranges: protoDollar[2].rngs}
 			protoVAL.resvd.setRange(protoDollar[1].id, protoDollar[3].b)
 		}
-	case 142:
+	case 145:
 		protoDollar = protoS[protopt-3 : protopt+1]
-//line proto.y:731
+//line proto.y:758
 		{
 			protoVAL.resvd = &reservedNode{ranges: protoDollar[2].rngs}
 			protoVAL.resvd.setRange(protoDollar[1].id, protoDollar[3].b)
 		}
-	case 144:
+	case 147:
 		protoDollar = protoS[protopt-3 : protopt+1]
-//line proto.y:737
+//line proto.y:764
 		{
 			rsvd := map[string]struct{}{}
 			for _, n := range protoDollar[2].names {
@@ -2009,185 +2080,185 @@ protodefault:
 			protoVAL.resvd = &reservedNode{names: protoDollar[2].names}
 			protoVAL.resvd.setRange(protoDollar[1].id, protoDollar[3].b)
 		}
-	case 145:
+	case 148:
 		protoDollar = protoS[protopt-3 : protopt+1]
-//line proto.y:750
+//line proto.y:777
 		{
 			protoVAL.names = append(protoDollar[1].names, protoDollar[3].str)
 		}
-	case 146:
+	case 149:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:753
+//line proto.y:780
 		{
 			protoVAL.names = []*compoundStringNode{protoDollar[1].str}
 		}
-	case 147:
+	case 150:
 		protoDollar = protoS[protopt-5 : protopt+1]
-//line proto.y:757
+//line proto.y:784
 		{
 			protoVAL.en = &enumNode{name: protoDollar[2].id, decls: protoDollar[4].enDecls}
 			protoVAL.en.setRange(protoDollar[1].id, protoDollar[5].b)
 		}
-	case 148:
+	case 151:
 		protoDollar = protoS[protopt-2 : protopt+1]
-//line proto.y:762
+//line proto.y:789
 		{
 			protoVAL.enDecls = append(protoDollar[1].enDecls, protoDollar[2].enDecls...)
 		}
-	case 150:
+	case 153:
 		protoDollar = protoS[protopt-0 : protopt+1]
-//line proto.y:766
+//line proto.y:793
 		{
 			protoVAL.enDecls = nil
 		}
-	case 151:
+	case 154:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:770
+//line proto.y:797
 		{
 			protoVAL.enDecls = []*enumElement{{option: protoDollar[1].opts[0]}}
 		}
-	case 152:
+	case 155:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:773
+//line proto.y:800
 		{
 			protoVAL.enDecls = []*enumElement{{value: protoDollar[1].env}}
 		}
-	case 153:
+	case 156:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:776
+//line proto.y:803
 		{
 			protoVAL.enDecls = []*enumElement{{reserved: protoDollar[1].resvd}}
 		}
-	case 154:
+	case 157:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:779
+//line proto.y:806
 		{
 			protoVAL.enDecls = []*enumElement{{empty: protoDollar[1].b}}
 		}
-	case 155:
+	case 158:
 		protoDollar = protoS[protopt-2 : protopt+1]
-//line proto.y:782
+//line proto.y:809
 		{
 		}
-	case 156:
+	case 159:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:784
+//line proto.y:811
 		{
 		}
-	case 157:
+	case 160:
 		protoDollar = protoS[protopt-4 : protopt+1]
-//line proto.y:787
+//line proto.y:814
 		{
 			checkInt64InInt32Range(protolex, protoDollar[3].il.start(), protoDollar[3].il.val)
 			protoVAL.env = &enumValueNode{name: protoDollar[1].id, number: protoDollar[3].il}
 			protoVAL.env.setRange(protoDollar[1].id, protoDollar[4].b)
 		}
-	case 158:
+	case 161:
 		protoDollar = protoS[protopt-5 : protopt+1]
-//line proto.y:792
+//line proto.y:819
 		{
 			checkInt64InInt32Range(protolex, protoDollar[3].il.start(), protoDollar[3].il.val)
 			protoVAL.env = &enumValueNode{name: protoDollar[1].id, number: protoDollar[3].il, options: protoDollar[4].cmpctOpts}
 			protoVAL.env.setRange(protoDollar[1].id, protoDollar[5].b)
 		}
-	case 159:
+	case 162:
 		protoDollar = protoS[protopt-5 : protopt+1]
-//line proto.y:798
+//line proto.y:825
 		{
 			protoVAL.msg = &messageNode{name: protoDollar[2].id, decls: protoDollar[4].msgDecls}
 			protoVAL.msg.setRange(protoDollar[1].id, protoDollar[5].b)
 		}
-	case 160:
+	case 163:
 		protoDollar = protoS[protopt-2 : protopt+1]
-//line proto.y:803
+//line proto.y:830
 		{
 			protoVAL.msgDecls = append(protoDollar[1].msgDecls, protoDollar[2].msgDecls...)
 		}
-	case 162:
+	case 165:
 		protoDollar = protoS[protopt-0 : protopt+1]
-//line proto.y:807
+//line proto.y:834
 		{
 			protoVAL.msgDecls = nil
 		}
-	case 163:
+	case 166:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:811
+//line proto.y:838
 		{
 			protoVAL.msgDecls = []*messageElement{{field: protoDollar[1].fld}}
 		}
-	case 164:
+	case 167:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:814
+//line proto.y:841
 		{
 			protoVAL.msgDecls = []*messageElement{{enum: protoDollar[1].en}}
 		}
-	case 165:
+	case 168:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:817
+//line proto.y:844
 		{
 			protoVAL.msgDecls = []*messageElement{{nested: protoDollar[1].msg}}
 		}
-	case 166:
+	case 169:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:820
+//line proto.y:847
 		{
 			protoVAL.msgDecls = []*messageElement{{extend: protoDollar[1].extend}}
 		}
-	case 167:
+	case 170:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:823
+//line proto.y:850
 		{
 			protoVAL.msgDecls = []*messageElement{{extensionRange: protoDollar[1].ext}}
 		}
-	case 168:
+	case 171:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:826
+//line proto.y:853
 		{
 			protoVAL.msgDecls = []*messageElement{{group: protoDollar[1].grp}}
 		}
-	case 169:
+	case 172:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:829
+//line proto.y:856
 		{
 			protoVAL.msgDecls = []*messageElement{{option: protoDollar[1].opts[0]}}
 		}
-	case 170:
+	case 173:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:832
+//line proto.y:859
 		{
 			protoVAL.msgDecls = []*messageElement{{oneOf: protoDollar[1].oo}}
 		}
-	case 171:
+	case 174:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:835
+//line proto.y:862
 		{
 			protoVAL.msgDecls = []*messageElement{{mapField: protoDollar[1].mapFld}}
 		}
-	case 172:
+	case 175:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:838
+//line proto.y:865
 		{
 			protoVAL.msgDecls = []*messageElement{{reserved: protoDollar[1].resvd}}
 		}
-	case 173:
+	case 176:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:841
+//line proto.y:868
 		{
 			protoVAL.msgDecls = []*messageElement{{empty: protoDollar[1].b}}
 		}
-	case 174:
+	case 177:
 		protoDollar = protoS[protopt-2 : protopt+1]
-//line proto.y:844
+//line proto.y:871
 		{
 		}
-	case 175:
+	case 178:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:846
+//line proto.y:873
 		{
 		}
-	case 176:
+	case 179:
 		protoDollar = protoS[protopt-5 : protopt+1]
-//line proto.y:849
+//line proto.y:876
 		{
 			c := 0
 			for _, el := range protoDollar[4].extDecls {
@@ -2201,153 +2272,153 @@ protodefault:
 			protoVAL.extend = &extendNode{extendee: protoDollar[2].cid, decls: protoDollar[4].extDecls}
 			protoVAL.extend.setRange(protoDollar[1].id, protoDollar[5].b)
 		}
-	case 177:
+	case 180:
 		protoDollar = protoS[protopt-2 : protopt+1]
-//line proto.y:863
+//line proto.y:890
 		{
 			protoVAL.extDecls = append(protoDollar[1].extDecls, protoDollar[2].extDecls...)
 		}
-	case 179:
+	case 182:
 		protoDollar = protoS[protopt-0 : protopt+1]
-//line proto.y:867
+//line proto.y:894
 		{
 			protoVAL.extDecls = nil
 		}
-	case 180:
+	case 183:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:871
+//line proto.y:898
 		{
 			protoVAL.extDecls = []*extendElement{{field: protoDollar[1].fld}}
 		}
-	case 181:
+	case 184:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:874
+//line proto.y:901
 		{
 			protoVAL.extDecls = []*extendElement{{group: protoDollar[1].grp}}
 		}
-	case 182:
+	case 185:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:877
+//line proto.y:904
 		{
 			protoVAL.extDecls = []*extendElement{{empty: protoDollar[1].b}}
 		}
-	case 183:
+	case 186:
 		protoDollar = protoS[protopt-2 : protopt+1]
-//line proto.y:880
+//line proto.y:907
 		{
 		}
-	case 184:
+	case 187:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:882
+//line proto.y:909
 		{
 		}
-	case 185:
+	case 188:
 		protoDollar = protoS[protopt-5 : protopt+1]
-//line proto.y:885
+//line proto.y:912
 		{
 			protoVAL.svc = &serviceNode{name: protoDollar[2].id, decls: protoDollar[4].svcDecls}
 			protoVAL.svc.setRange(protoDollar[1].id, protoDollar[5].b)
 		}
-	case 186:
+	case 189:
 		protoDollar = protoS[protopt-2 : protopt+1]
-//line proto.y:890
+//line proto.y:917
 		{
 			protoVAL.svcDecls = append(protoDollar[1].svcDecls, protoDollar[2].svcDecls...)
 		}
-	case 188:
+	case 191:
 		protoDollar = protoS[protopt-0 : protopt+1]
-//line proto.y:894
+//line proto.y:921
 		{
 			protoVAL.svcDecls = nil
 		}
-	case 189:
+	case 192:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:901
+//line proto.y:928
 		{
 			protoVAL.svcDecls = []*serviceElement{{option: protoDollar[1].opts[0]}}
 		}
-	case 190:
+	case 193:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:904
+//line proto.y:931
 		{
 			protoVAL.svcDecls = []*serviceElement{{rpc: protoDollar[1].mtd}}
 		}
-	case 191:
+	case 194:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:907
+//line proto.y:934
 		{
 			protoVAL.svcDecls = []*serviceElement{{empty: protoDollar[1].b}}
 		}
-	case 192:
+	case 195:
 		protoDollar = protoS[protopt-2 : protopt+1]
-//line proto.y:910
+//line proto.y:937
 		{
 		}
-	case 193:
+	case 196:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:912
+//line proto.y:939
 		{
 		}
-	case 194:
+	case 197:
 		protoDollar = protoS[protopt-10 : protopt+1]
-//line proto.y:915
+//line proto.y:942
 		{
 			protoVAL.mtd = &methodNode{name: protoDollar[2].id, input: protoDollar[4].rpcType, output: protoDollar[8].rpcType}
 			protoVAL.mtd.setRange(protoDollar[1].id, protoDollar[10].b)
 		}
-	case 195:
+	case 198:
 		protoDollar = protoS[protopt-12 : protopt+1]
-//line proto.y:919
+//line proto.y:946
 		{
 			protoVAL.mtd = &methodNode{name: protoDollar[2].id, input: protoDollar[4].rpcType, output: protoDollar[8].rpcType, options: protoDollar[11].opts}
 			protoVAL.mtd.setRange(protoDollar[1].id, protoDollar[12].b)
 		}
-	case 196:
+	case 199:
 		protoDollar = protoS[protopt-2 : protopt+1]
-//line proto.y:924
+//line proto.y:951
 		{
 			protoVAL.rpcType = &rpcTypeNode{msgType: protoDollar[2].cid, streamKeyword: protoDollar[1].id}
 			protoVAL.rpcType.setRange(protoDollar[1].id, protoDollar[2].cid)
 		}
-	case 197:
+	case 200:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:928
+//line proto.y:955
 		{
 			protoVAL.rpcType = &rpcTypeNode{msgType: protoDollar[1].cid}
 			protoVAL.rpcType.setRange(protoDollar[1].cid, protoDollar[1].cid)
 		}
-	case 198:
+	case 201:
 		protoDollar = protoS[protopt-2 : protopt+1]
-//line proto.y:933
+//line proto.y:960
 		{
 			protoVAL.opts = append(protoDollar[1].opts, protoDollar[2].opts...)
 		}
-	case 200:
+	case 203:
 		protoDollar = protoS[protopt-0 : protopt+1]
-//line proto.y:937
+//line proto.y:964
 		{
 			protoVAL.opts = []*optionNode{}
 		}
-	case 201:
+	case 204:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:941
+//line proto.y:968
 		{
 			protoVAL.opts = protoDollar[1].opts
 		}
-	case 202:
+	case 205:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:944
+//line proto.y:971
 		{
 			protoVAL.opts = []*optionNode{}
 		}
-	case 203:
+	case 206:
 		protoDollar = protoS[protopt-2 : protopt+1]
-//line proto.y:947
+//line proto.y:974
 		{
 		}
-	case 204:
+	case 207:
 		protoDollar = protoS[protopt-1 : protopt+1]
-//line proto.y:949
+//line proto.y:976
 		{
 		}
 	}
diff --git a/desc/protoprint/print.go b/desc/protoprint/print.go
index 0363cf0..eb8c35c 100644
--- a/desc/protoprint/print.go
+++ b/desc/protoprint/print.go
@@ -877,7 +877,10 @@ func asDynamicIfPossible(msg proto.Message, mf *dynamic.MessageFactory) proto.Me
 func (p *Printer) printField(fld *desc.FieldDescriptor, mf *dynamic.MessageFactory, w *writer, sourceInfo internal.SourceInfoMap, path []int32, scope string, indent int) {
 	var groupPath []int32
 	var si *descriptor.SourceCodeInfo_Location
-	if isGroup(fld) {
+
+	group := isGroup(fld)
+
+	if group {
 		// compute path to group message type
 		groupPath = make([]int32, len(path)-2)
 		copy(groupPath, path)
@@ -918,61 +921,59 @@ func (p *Printer) printField(fld *desc.FieldDescriptor, mf *dynamic.MessageFacto
 			p.printElementString(locSi, w, indent, labelString(fld.GetLabel()))
 		}
 
-		if isGroup(fld) {
+		if group {
 			fmt.Fprint(w, "group ")
+		}
 
-			typeSi := sourceInfo.Get(append(path, internal.Field_typeTag))
-			p.printElementString(typeSi, w, indent, p.typeString(fld, scope))
-			fmt.Fprint(w, "= ")
-
-			numSi := sourceInfo.Get(append(path, internal.Field_numberTag))
-			p.printElementString(numSi, w, indent, fmt.Sprintf("%d", fld.GetNumber()))
-
-			fmt.Fprintln(w, "{")
-			p.printMessageBody(fld.GetMessageType(), mf, w, sourceInfo, groupPath, indent+1)
-
-			p.indent(w, indent)
-			fmt.Fprintln(w, "}")
-		} else {
-			typeSi := sourceInfo.Get(append(path, internal.Field_typeTag))
-			p.printElementString(typeSi, w, indent, p.typeString(fld, scope))
+		typeSi := sourceInfo.Get(append(path, internal.Field_typeTag))
+		p.printElementString(typeSi, w, indent, p.typeString(fld, scope))
 
+		if !group {
 			nameSi := sourceInfo.Get(append(path, internal.Field_nameTag))
 			p.printElementString(nameSi, w, indent, fld.GetName())
-			fmt.Fprint(w, "= ")
+		}
 
-			numSi := sourceInfo.Get(append(path, internal.Field_numberTag))
-			p.printElementString(numSi, w, indent, fmt.Sprintf("%d", fld.GetNumber()))
+		fmt.Fprint(w, "= ")
+		numSi := sourceInfo.Get(append(path, internal.Field_numberTag))
+		p.printElementString(numSi, w, indent, fmt.Sprintf("%d", fld.GetNumber()))
 
-			opts, err := p.extractOptions(fld, fld.GetOptions(), mf)
-			if err != nil {
-				if w.err == nil {
-					w.err = err
-				}
-				return
+		opts, err := p.extractOptions(fld, fld.GetOptions(), mf)
+		if err != nil {
+			if w.err == nil {
+				w.err = err
 			}
+			return
+		}
 
-			// we use negative values for "extras" keys so they can't collide
-			// with legit option tags
+		// we use negative values for "extras" keys so they can't collide
+		// with legit option tags
 
-			if !fld.GetFile().IsProto3() && fld.AsFieldDescriptorProto().DefaultValue != nil {
-				defVal := fld.GetDefaultValue()
-				if fld.GetEnumType() != nil {
-					defVal = fld.GetEnumType().FindValueByNumber(defVal.(int32))
-				}
-				opts[-internal.Field_defaultTag] = []option{{name: "default", val: defVal}}
+		if !fld.GetFile().IsProto3() && fld.AsFieldDescriptorProto().DefaultValue != nil {
+			defVal := fld.GetDefaultValue()
+			if fld.GetEnumType() != nil {
+				defVal = fld.GetEnumType().FindValueByNumber(defVal.(int32))
 			}
+			opts[-internal.Field_defaultTag] = []option{{name: "default", val: defVal}}
+		}
 
-			jsn := fld.AsFieldDescriptorProto().GetJsonName()
-			if jsn != "" && jsn != internal.JsonName(fld.GetName()) {
-				opts[-internal.Field_jsonNameTag] = []option{{name: "json_name", val: jsn}}
-			}
+		jsn := fld.AsFieldDescriptorProto().GetJsonName()
+		if jsn != "" && jsn != internal.JsonName(fld.GetName()) {
+			opts[-internal.Field_jsonNameTag] = []option{{name: "json_name", val: jsn}}
+		}
 
-			elements := elementAddrs{dsc: fld, opts: opts}
-			elements.addrs = optionsAsElementAddrs(internal.Field_optionsTag, 0, opts)
-			p.sort(elements, sourceInfo, path)
-			p.printOptionElementsShort(elements, w, sourceInfo, path, indent)
+		elements := elementAddrs{dsc: fld, opts: opts}
+		elements.addrs = optionsAsElementAddrs(internal.Field_optionsTag, 0, opts)
+		p.sort(elements, sourceInfo, path)
+		p.printOptionElementsShort(elements, w, sourceInfo, path, indent)
+
+		if group {
+			fmt.Fprintln(w, "{")
+			p.printMessageBody(fld.GetMessageType(), mf, w, sourceInfo, groupPath, indent+1)
 
+			p.indent(w, indent)
+			fmt.Fprintln(w, "}")
+
+		} else {
 			fmt.Fprint(w, ";")
 		}
 	})
@@ -1463,7 +1464,7 @@ func (p *Printer) printOptionElementsShort(addrs elementAddrs, w *writer, source
 				fmt.Fprint(w, " ") // trailing space
 			})
 	}
-	fmt.Fprint(w, "]")
+	fmt.Fprint(w, "] ")
 }
 
 func (p *Printer) printOptions(opts []option, w *writer, indent int, siFetch func(i int32) *descriptor.SourceCodeInfo_Location, fn func(w *writer, indent int, opt option)) {
@@ -2069,7 +2070,6 @@ func (a elementSrcOrder) Less(i, j int) bool {
 		// i will be unknown and j will be known
 		swapped := false
 		if si != nil {
-			si, sj = sj, si
 			ti, tj = tj, ti
 			swapped = true
 		}


Test patch:
diff --git a/desc/descriptor_test.go b/desc/descriptor_test.go
index 44a9e44..ccd5caf 100644
--- a/desc/descriptor_test.go
+++ b/desc/descriptor_test.go
@@ -290,6 +290,14 @@ func TestFileDescriptorObjectGraph(t *testing.T) {
 									"one of":       {(*FieldDescriptor).GetOneOf, refs("testprotos.AnotherTestMessage.atmoo")},
 								},
 							},
+							{
+								name: "testprotos.AnotherTestMessage.withoptions",
+								references: map[string]childCases{
+									"message type": {(*FieldDescriptor).GetMessageType, refs("testprotos.AnotherTestMessage.WithOptions")},
+									"enum type":    {(*FieldDescriptor).GetEnumType, nil},
+									"one of":       {(*FieldDescriptor).GetOneOf, nil},
+								},
+							},
 						}},
 						"one ofs": {(*MessageDescriptor).GetOneOfs, []descCase{
 							{
@@ -447,6 +455,16 @@ func TestFileDescriptorObjectGraph(t *testing.T) {
 									"one ofs":           {(*MessageDescriptor).GetOneOfs, nil},
 								},
 							},
+							{
+								name: "testprotos.AnotherTestMessage.WithOptions",
+								references: map[string]childCases{
+									"fields":            {(*MessageDescriptor).GetFields, nil},
+									"nested messages":   {(*MessageDescriptor).GetNestedMessageTypes, nil},
+									"nested enums":      {(*MessageDescriptor).GetNestedEnumTypes, nil},
+									"nested extensions": {(*MessageDescriptor).GetNestedExtensions, nil},
+									"one ofs":           {(*MessageDescriptor).GetOneOfs, nil},
+								},
+							},
 						}},
 						"nested enums":      {(*MessageDescriptor).GetNestedEnumTypes, nil},
 						"nested extensions": {(*MessageDescriptor).GetNestedExtensions, nil},
diff --git a/desc/protoparse/parser_test.go b/desc/protoparse/parser_test.go
index f6b9ded..8334924 100644
--- a/desc/protoparse/parser_test.go
+++ b/desc/protoparse/parser_test.go
@@ -2,6 +2,7 @@ package protoparse
 
 import (
 	"bytes"
+	"errors"
 	"io"
 	"io/ioutil"
 	"os"
@@ -11,6 +12,7 @@ import (
 
 	dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
 
+	"github.com/jhump/protoreflect/desc"
 	"github.com/jhump/protoreflect/internal/testutil"
 )
 
@@ -473,3 +475,65 @@ func TestParseFilesWithImportsNoImportPath(t *testing.T) {
 	testutil.Ok(t, err)
 	testutil.Eq(t, len(relFilePaths), len(protos))
 }
+
+func TestParseFilesWithDependencies(t *testing.T) {
+	// Create some file contents that import a non-well-known proto.
+	// (One of the protos in internal/testprotos is fine.)
+	contents := map[string]string{
+		"test.proto": `
+			syntax = "proto3";
+			import "desc_test_wellknowntypes.proto";
+
+			message TestImportedType {
+				testprotos.TestWellKnownTypes imported_field = 1;
+			}
+		`,
+	}
+
+	// Establish that we *can* parse the source file with a parser that
+	// registers the dependency.
+	t.Run("DependencyIncluded", func(t *testing.T) {
+		// Create a dependency-aware parser.
+		parser := Parser{
+			Accessor: FileContentsFromMap(contents),
+			LookupImport: func(imp string) (*desc.FileDescriptor, error) {
+				if imp == "desc_test_wellknowntypes.proto" {
+					return desc.LoadFileDescriptor(imp)
+				}
+				return nil, errors.New("unexpected filename")
+			},
+		}
+		if _, err := parser.ParseFiles("test.proto"); err != nil {
+			t.Errorf("Could not parse with a non-well-known import: %v", err)
+		}
+	})
+
+	// Establish that we *can not* parse the source file with a parser that
+	// did not register the dependency.
+	t.Run("DependencyExcluded", func(t *testing.T) {
+		// Create a dependency-aware parser.
+		parser := Parser{
+			Accessor: FileContentsFromMap(contents),
+		}
+		if _, err := parser.ParseFiles("test.proto"); err == nil {
+			t.Errorf("Expected parse to fail due to lack of an import.")
+		}
+	})
+
+	// Establish that the accessor has precedence over LookupImport.
+	t.Run("AccessorWins", func(t *testing.T) {
+		// Create a dependency-aware parser that should never be called.
+		parser := Parser{
+			Accessor: FileContentsFromMap(map[string]string{
+				"test.proto": `syntax = "proto3";`,
+			}),
+			LookupImport: func(imp string) (*desc.FileDescriptor, error) {
+				t.Errorf("LookupImport was called on a filename available to the Accessor.")
+				return nil, errors.New("unimportant")
+			},
+		}
+		if _, err := parser.ParseFiles("test.proto"); err != nil {
+			t.Error(err)
+		}
+	})
+}
diff --git a/desc/protoprint/testfiles/desc_test1-compact.proto b/desc/protoprint/testfiles/desc_test1-compact.proto
index 0219ff8..9751850 100644
--- a/desc/protoprint/testfiles/desc_test1-compact.proto
+++ b/desc/protoprint/testfiles/desc_test1-compact.proto
@@ -88,6 +88,9 @@ message AnotherTestMessage {
     // Comment for int
     int64 int = 8;
   }
+  // Comment for WithOptions
+  optional group WithOptions = 9 [deprecated = true] {
+  }
   extensions 100 to 200;
 }
 // Comment for AnotherTestMessage extensions (2)
diff --git a/desc/protoprint/testfiles/desc_test1-default.proto b/desc/protoprint/testfiles/desc_test1-default.proto
index e569076..08476be 100644
--- a/desc/protoprint/testfiles/desc_test1-default.proto
+++ b/desc/protoprint/testfiles/desc_test1-default.proto
@@ -120,6 +120,10 @@ message AnotherTestMessage {
     int64 int = 8;
   }
 
+  // Comment for WithOptions
+  optional group WithOptions = 9 [deprecated = true] {
+  }
+
   extensions 100 to 200;
 }
 
diff --git a/desc/protoprint/testfiles/desc_test1-multiline-style-comments.proto b/desc/protoprint/testfiles/desc_test1-multiline-style-comments.proto
index 9f130bb..e9dc609 100644
--- a/desc/protoprint/testfiles/desc_test1-multiline-style-comments.proto
+++ b/desc/protoprint/testfiles/desc_test1-multiline-style-comments.proto
@@ -120,6 +120,10 @@ message AnotherTestMessage {
 		int64 int = 8;
 	}
 
+	/* Comment for WithOptions */
+	optional group WithOptions = 9 [deprecated = true] {
+	}
+
 	extensions 100 to 200;
 }
 
diff --git a/desc/protoprint/testfiles/desc_test1-no-trailing-comments.proto b/desc/protoprint/testfiles/desc_test1-no-trailing-comments.proto
index e569076..08476be 100644
--- a/desc/protoprint/testfiles/desc_test1-no-trailing-comments.proto
+++ b/desc/protoprint/testfiles/desc_test1-no-trailing-comments.proto
@@ -120,6 +120,10 @@ message AnotherTestMessage {
     int64 int = 8;
   }
 
+  // Comment for WithOptions
+  optional group WithOptions = 9 [deprecated = true] {
+  }
+
   extensions 100 to 200;
 }
 
diff --git a/desc/protoprint/testfiles/desc_test1-only-doc-comments.proto b/desc/protoprint/testfiles/desc_test1-only-doc-comments.proto
index e569076..08476be 100644
--- a/desc/protoprint/testfiles/desc_test1-only-doc-comments.proto
+++ b/desc/protoprint/testfiles/desc_test1-only-doc-comments.proto
@@ -120,6 +120,10 @@ message AnotherTestMessage {
     int64 int = 8;
   }
 
+  // Comment for WithOptions
+  optional group WithOptions = 9 [deprecated = true] {
+  }
+
   extensions 100 to 200;
 }
 
diff --git a/desc/protoprint/testfiles/desc_test1-sorted-AND-multiline-style-comments.proto b/desc/protoprint/testfiles/desc_test1-sorted-AND-multiline-style-comments.proto
index 8a4043a..7cbae79 100644
--- a/desc/protoprint/testfiles/desc_test1-sorted-AND-multiline-style-comments.proto
+++ b/desc/protoprint/testfiles/desc_test1-sorted-AND-multiline-style-comments.proto
@@ -42,6 +42,10 @@ message AnotherTestMessage {
     int64 int = 8;
   }
 
+  /* Comment for WithOptions */
+  optional group WithOptions = 9 [deprecated = true] {
+  }
+
   extensions 100 to 200;
 }
 
diff --git a/desc/protoprint/testfiles/desc_test1-sorted.proto b/desc/protoprint/testfiles/desc_test1-sorted.proto
index 7cc324b..04a4b35 100644
--- a/desc/protoprint/testfiles/desc_test1-sorted.proto
+++ b/desc/protoprint/testfiles/desc_test1-sorted.proto
@@ -42,6 +42,10 @@ message AnotherTestMessage {
       int64 int = 8;
    }
 
+   // Comment for WithOptions
+   optional group WithOptions = 9 [deprecated = true] {
+   }
+
    extensions 100 to 200;
 }
 
diff --git a/desc/protoprint/testfiles/desc_test1-trailing-on-next-line.proto b/desc/protoprint/testfiles/desc_test1-trailing-on-next-line.proto
index e569076..08476be 100644
--- a/desc/protoprint/testfiles/desc_test1-trailing-on-next-line.proto
+++ b/desc/protoprint/testfiles/desc_test1-trailing-on-next-line.proto
@@ -120,6 +120,10 @@ message AnotherTestMessage {
     int64 int = 8;
   }
 
+  // Comment for WithOptions
+  optional group WithOptions = 9 [deprecated = true] {
+  }
+
   extensions 100 to 200;
 }
 
diff --git a/dynamic/msgregistry/message_registry_test.go b/dynamic/msgregistry/message_registry_test.go
index 9ae3f3e..5304faa 100644
--- a/dynamic/msgregistry/message_registry_test.go
+++ b/dynamic/msgregistry/message_registry_test.go
@@ -107,7 +107,7 @@ func TestMessageRegistry_LookupTypes(t *testing.T) {
 		testutil.Eq(t, exp, mr.ComputeURL(ed))
 	}
 	// sanity check
-	testutil.Eq(t, 10, msgCount)
+	testutil.Eq(t, 11, msgCount)
 	testutil.Eq(t, 2, enumCount)
 }
 
diff --git a/internal/testprotos/desc_test1.pb.go b/internal/testprotos/desc_test1.pb.go
index e498cb6..77b042c 100644
--- a/internal/testprotos/desc_test1.pb.go
+++ b/internal/testprotos/desc_test1.pb.go
@@ -395,8 +395,9 @@ type AnotherTestMessage struct {
 	// Types that are valid to be assigned to Atmoo:
 	//	*AnotherTestMessage_Str
 	//	*AnotherTestMessage_Int
-	Atmoo                        isAnotherTestMessage_Atmoo `protobuf_oneof:"atmoo"`
-	XXX_NoUnkeyedLiteral         struct{}                   `json:"-"`
+	Atmoo                        isAnotherTestMessage_Atmoo      `protobuf_oneof:"atmoo"`
+	Withoptions                  *AnotherTestMessage_WithOptions `protobuf:"group,9,opt,name=WithOptions,json=withoptions" json:"withoptions,omitempty"` // Deprecated: Do not use.
+	XXX_NoUnkeyedLiteral         struct{}                        `json:"-"`
 	proto.XXX_InternalExtensions `json:"-"`
 	XXX_unrecognized             []byte `json:"-"`
 	XXX_sizecache                int32  `json:"-"`
@@ -514,6 +515,14 @@ func (m *AnotherTestMessage) GetInt() int64 {
 	return 0
 }
 
+// Deprecated: Do not use.
+func (m *AnotherTestMessage) GetWithoptions() *AnotherTestMessage_WithOptions {
+	if m != nil {
+		return m.Withoptions
+	}
+	return nil
+}
+
 // XXX_OneofWrappers is for the internal use of the proto package.
 func (*AnotherTestMessage) XXX_OneofWrappers() []interface{} {
 	return []interface{}{
@@ -581,6 +590,38 @@ func (m *AnotherTestMessage_RockNRoll) GetDoors() string {
 	return ""
 }
 
+// Comment for WithOptions
+type AnotherTestMessage_WithOptions struct {
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *AnotherTestMessage_WithOptions) Reset()         { *m = AnotherTestMessage_WithOptions{} }
+func (m *AnotherTestMessage_WithOptions) String() string { return proto.CompactTextString(m) }
+func (*AnotherTestMessage_WithOptions) ProtoMessage()    {}
+func (*AnotherTestMessage_WithOptions) Descriptor() ([]byte, []int) {
+	return fileDescriptor_550618e6d7083528, []int{1, 5}
+}
+
+func (m *AnotherTestMessage_WithOptions) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_AnotherTestMessage_WithOptions.Unmarshal(m, b)
+}
+func (m *AnotherTestMessage_WithOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_AnotherTestMessage_WithOptions.Marshal(b, m, deterministic)
+}
+func (m *AnotherTestMessage_WithOptions) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_AnotherTestMessage_WithOptions.Merge(m, src)
+}
+func (m *AnotherTestMessage_WithOptions) XXX_Size() int {
+	return xxx_messageInfo_AnotherTestMessage_WithOptions.Size(m)
+}
+func (m *AnotherTestMessage_WithOptions) XXX_DiscardUnknown() {
+	xxx_messageInfo_AnotherTestMessage_WithOptions.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_AnotherTestMessage_WithOptions proto.InternalMessageInfo
+
 var E_Xtm = &proto.ExtensionDesc{
 	ExtendedType:  (*AnotherTestMessage)(nil),
 	ExtensionType: (*TestMessage)(nil),
@@ -631,6 +672,7 @@ func init() {
 	proto.RegisterMapType((map[uint32]bool)(nil), "testprotos.AnotherTestMessage.MapField3Entry")
 	proto.RegisterMapType((map[string]*AnotherTestMessage)(nil), "testprotos.AnotherTestMessage.MapField4Entry")
 	proto.RegisterType((*AnotherTestMessage_RockNRoll)(nil), "testprotos.AnotherTestMessage.RockNRoll")
+	proto.RegisterType((*AnotherTestMessage_WithOptions)(nil), "testprotos.AnotherTestMessage.WithOptions")
 	proto.RegisterExtension(E_Xtm)
 	proto.RegisterExtension(E_Xs)
 	proto.RegisterExtension(E_Xi)
@@ -640,49 +682,51 @@ func init() {
 func init() { proto.RegisterFile("desc_test1.proto", fileDescriptor_550618e6d7083528) }
 
 var fileDescriptor_550618e6d7083528 = []byte{
-	// 696 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x94, 0xcd, 0x6a, 0xdb, 0x4a,
-	0x14, 0xc7, 0xaf, 0x46, 0x96, 0x6d, 0x9d, 0xdc, 0x04, 0x31, 0x84, 0x1b, 0x91, 0xc5, 0xc5, 0x98,
-	0x7b, 0xa9, 0x09, 0x54, 0xae, 0x65, 0x17, 0x5a, 0xd3, 0x4d, 0x42, 0x13, 0x5a, 0x48, 0xb2, 0x98,
-	0x7e, 0x40, 0x4b, 0x21, 0x28, 0xd6, 0xd8, 0x51, 0x23, 0xcd, 0x18, 0xcd, 0xb8, 0xd8, 0x79, 0x9a,
-	0x2e, 0xfa, 0x00, 0x7d, 0x8c, 0xf6, 0x1d, 0xfa, 0x26, 0xdd, 0x94, 0x19, 0xdb, 0xb1, 0xfc, 0x91,
-	0x28, 0x29, 0x49, 0x77, 0x73, 0x46, 0xe7, 0xff, 0x9b, 0xf3, 0xa5, 0x03, 0x4e, 0x48, 0x45, 0xe7,
-	0x44, 0x52, 0x21, 0x1b, 0x5e, 0x3f, 0xe5, 0x92, 0x63, 0x50, 0x86, 0x3e, 0x8a, 0xea, 0xcf, 0x32,
-	0xac, 0xbd, 0xa6, 0x42, 0x1e, 0x51, 0x21, 0x82, 0x1e, 0xc5, 0x8f, 0x01, 0xb1, 0xc4, 0x35, 0x2a,
-	0x46, 0x6d, 0xcd, 0xff, 0xdf, 0x9b, 0x39, 0x7a, 0x19, 0x27, 0xef, 0x98, 0x0a, 0x49, 0xc3, 0x89,
-	0x45, 0x10, 0x4b, 0xf0, 0x21, 0x98, 0x01, 0x4b, 0x5c, 0xa4, 0x75, 0xed, 0x1b, 0xe9, 0xbc, 0x5d,
-	0xc6, 0xe5, 0x19, 0x4d, 0xe7, 0x61, 0x0a, 0x83, 0xbb, 0x50, 0x18, 0x29, 0x9c, 0xa9, 0x71, 0xe4,
-	0xf7, 0x71, 0xde, 0x3b, 0x2a, 0x57, 0x3e, 0xa3, 0xf9, 0xd8, 0x07, 0xc4, 0xa8, 0x5b, 0xa8, 0x98,
-	0xb5, 0x0d, 0xbf, 0x7a, 0xfd, 0x2b, 0xfb, 0x6c, 0x90, 0x10, 0xc4, 0xe8, 0xf6, 0x97, 0x22, 0xac,
-	0xcf, 0xb1, 0xa6, 0xb9, 0x1b, 0x77, 0x9b, 0x3b, 0xba, 0xdf, 0xdc, 0xb7, 0x7f, 0x14, 0x60, 0x73,
-	0xd5, 0xe7, 0xcb, 0x00, 0x8c, 0x8a, 0x79, 0xaf, 0x01, 0x7c, 0x36, 0x61, 0xeb, 0x0a, 0x0f, 0xec,
-	0x80, 0xd9, 0xe5, 0x5c, 0x97, 0xd4, 0x26, 0xea, 0xa8, 0x6e, 0x4e, 0x83, 0x54, 0x57, 0xc5, 0x22,
-	0xea, 0x38, 0xbe, 0xb9, 0xd0, 0x33, 0xf2, 0xb7, 0xba, 0xb9, 0xc0, 0x03, 0x30, 0x43, 0xdd, 0x4f,
-	0xa3, 0xb6, 0xe1, 0x77, 0xee, 0x3e, 0x70, 0xef, 0x39, 0xa5, 0xfd, 0x78, 0x94, 0x19, 0x08, 0xf5,
-	0xde, 0xb4, 0xff, 0xd6, 0xdd, 0xf4, 0x7f, 0xfc, 0x03, 0x16, 0x6f, 0xfb, 0x03, 0x3e, 0x00, 0x24,
-	0x13, 0xb7, 0xa4, 0x65, 0x5b, 0x57, 0xc8, 0x08, 0x92, 0x49, 0x75, 0x07, 0x9c, 0xc5, 0x34, 0x30,
-	0x40, 0xf1, 0xed, 0xee, 0xe1, 0x9b, 0xfd, 0x86, 0x63, 0x5c, 0x9e, 0x7d, 0x07, 0xf9, 0x4f, 0xc1,
-	0xea, 0xc6, 0x41, 0x4f, 0xe0, 0x7f, 0xb3, 0xc4, 0x49, 0xec, 0x19, 0xb0, 0xfb, 0x4d, 0x0d, 0x4b,
-	0x79, 0x0f, 0x39, 0x06, 0x19, 0x2b, 0xaa, 0xff, 0x01, 0xe4, 0x3f, 0x50, 0xfd, 0x5a, 0x02, 0xbc,
-	0x8c, 0x9b, 0x36, 0xd2, 0xf8, 0xe3, 0x8d, 0x84, 0x24, 0xe8, 0x9f, 0x74, 0x23, 0x1a, 0x87, 0x0d,
-	0x17, 0xe9, 0xf9, 0x7f, 0x78, 0x7d, 0xe6, 0xde, 0x51, 0xd0, 0x3f, 0xd0, 0xfe, 0xfb, 0x4c, 0xa6,
-	0x23, 0x62, 0x27, 0x53, 0x7b, 0x8e, 0xe6, 0xbb, 0xe6, 0xad, 0x68, 0xfe, 0x02, 0xcd, 0x9f, 0xa3,
-	0x35, 0xf5, 0xca, 0xba, 0x39, 0xad, 0xb9, 0x40, 0x6b, 0xce, 0xd1, 0x5a, 0xae, 0x75, 0x2b, 0x5a,
-	0x6b, 0x81, 0xd6, 0xc2, 0x07, 0x60, 0xa7, 0xbc, 0x73, 0xce, 0x52, 0x1e, 0xc7, 0x7a, 0x72, 0xc1,
-	0xaf, 0xe5, 0xc0, 0x08, 0xef, 0x9c, 0x1f, 0x13, 0x1e, 0xc7, 0x64, 0x26, 0xc5, 0x18, 0x4c, 0x21,
-	0x53, 0x3d, 0xc4, 0xf6, 0x8b, 0xbf, 0x88, 0x32, 0xd4, 0x5d, 0xc4, 0xa4, 0x5b, 0xae, 0x18, 0x35,
-	0x53, 0xdd, 0x45, 0x4c, 0x6e, 0x3f, 0x83, 0x8d, 0xf9, 0xb2, 0xab, 0x5d, 0x70, 0x4e, 0x47, 0x7a,
-	0x60, 0x2c, 0xa2, 0x8e, 0x78, 0x13, 0xac, 0x4f, 0x41, 0x3c, 0xa0, 0x7a, 0x63, 0xd8, 0x64, 0x6c,
-	0xb4, 0xd1, 0x13, 0x23, 0xab, 0xf6, 0x97, 0xd4, 0xe6, 0x0a, 0x35, 0xba, 0x42, 0xdd, 0x5c, 0x52,
-	0xaf, 0xaf, 0x50, 0x97, 0xb3, 0xea, 0x0f, 0x33, 0x75, 0x6b, 0x49, 0x6d, 0x8f, 0xd5, 0xad, 0xac,
-	0x7a, 0xcd, 0xcf, 0xf9, 0xf5, 0xb2, 0xf4, 0x57, 0x60, 0x5f, 0xd6, 0x15, 0xbb, 0x50, 0x3a, 0xa5,
-	0x81, 0x8c, 0xa9, 0x98, 0xc0, 0xa7, 0x26, 0xfe, 0x07, 0x8a, 0x42, 0x72, 0x46, 0xc5, 0xa4, 0x36,
-	0x13, 0x4b, 0x85, 0x1d, 0x72, 0x9e, 0x0a, 0xbd, 0x52, 0x6d, 0x32, 0x36, 0x76, 0xac, 0x72, 0xe8,
-	0x7c, 0x37, 0xf6, 0x4a, 0x60, 0x05, 0x32, 0xe1, 0xbc, 0xfd, 0x12, 0xcc, 0xa1, 0x4c, 0x72, 0x37,
-	0x42, 0x78, 0xfd, 0x26, 0x52, 0x8c, 0xb6, 0x07, 0x68, 0x98, 0xbf, 0x5b, 0xa8, 0x8e, 0x06, 0x0d,
-	0x85, 0xf6, 0x8f, 0x72, 0xfd, 0xbb, 0x7a, 0x08, 0xd0, 0x30, 0x6a, 0x3f, 0x02, 0x73, 0x38, 0xc8,
-	0x17, 0xf4, 0x2a, 0x46, 0xad, 0x40, 0x94, 0xeb, 0x5e, 0xf3, 0x7d, 0xa3, 0x17, 0xc9, 0xb3, 0xc1,
-	0xa9, 0xd7, 0xe1, 0x49, 0xfd, 0xe3, 0xd9, 0x20, 0xe9, 0xd7, 0xb5, 0x30, 0xa5, 0xdd, 0x98, 0x76,
-	0x64, 0x3d, 0x62, 0x92, 0xa6, 0x2c, 0x88, 0xeb, 0x33, 0xe4, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff,
-	0x9b, 0x1d, 0x1b, 0x3b, 0x61, 0x09, 0x00, 0x00,
+	// 733 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x94, 0xdd, 0x6e, 0xda, 0x48,
+	0x14, 0xc7, 0xd7, 0x63, 0x4c, 0xf0, 0x61, 0x13, 0xa1, 0x51, 0xb4, 0xb1, 0xb8, 0x58, 0x21, 0xb4,
+	0xab, 0x45, 0x91, 0xd6, 0x2c, 0x86, 0x95, 0x5a, 0xd4, 0x9b, 0xa0, 0x26, 0x6a, 0xa5, 0x24, 0xad,
+	0xa6, 0x5f, 0x6a, 0x55, 0x29, 0x72, 0x60, 0x00, 0x37, 0xf6, 0x0c, 0xf2, 0x0c, 0x2d, 0xe4, 0x2d,
+	0xfa, 0x06, 0xbd, 0xe8, 0xc3, 0xb4, 0xef, 0xd0, 0x37, 0xe9, 0x4d, 0x35, 0x03, 0x04, 0xf3, 0x91,
+	0x38, 0xa9, 0x92, 0xde, 0xcd, 0x19, 0x9f, 0xff, 0xef, 0x9c, 0xe3, 0x73, 0xe6, 0x40, 0xa1, 0x43,
+	0x45, 0xfb, 0x44, 0x52, 0x21, 0x6b, 0xee, 0x20, 0xe6, 0x92, 0x63, 0x50, 0x86, 0x3e, 0x8a, 0xf2,
+	0xf7, 0x1c, 0xe4, 0x9f, 0x53, 0x21, 0x8f, 0xa8, 0x10, 0x7e, 0x8f, 0xe2, 0xff, 0x01, 0xb1, 0xc8,
+	0x31, 0x4a, 0x46, 0x25, 0xef, 0xfd, 0xed, 0xce, 0x1d, 0xdd, 0x84, 0x93, 0x7b, 0x4c, 0x85, 0xa4,
+	0x9d, 0xa9, 0x45, 0x10, 0x8b, 0xf0, 0x21, 0x98, 0x3e, 0x8b, 0x1c, 0xa4, 0x75, 0xcd, 0x6b, 0xe9,
+	0xdc, 0x3d, 0xc6, 0x65, 0x9f, 0xc6, 0x8b, 0x30, 0x85, 0xc1, 0x5d, 0xc8, 0x8c, 0x15, 0xce, 0xd4,
+	0x38, 0xf2, 0xf3, 0x38, 0xf7, 0x35, 0x95, 0x6b, 0xc3, 0x68, 0x3e, 0xf6, 0x00, 0x31, 0xea, 0x64,
+	0x4a, 0x66, 0x65, 0xcb, 0x2b, 0x5f, 0x1d, 0x65, 0x9f, 0x0d, 0x23, 0x82, 0x18, 0x2d, 0x7e, 0xce,
+	0xc2, 0xe6, 0x02, 0x6b, 0x56, 0xbb, 0x71, 0xbb, 0xb5, 0xa3, 0xbb, 0xad, 0xbd, 0xf8, 0x2d, 0x03,
+	0xdb, 0xeb, 0x3e, 0x5f, 0x24, 0x60, 0x94, 0xcc, 0x3b, 0x4d, 0xe0, 0x93, 0x09, 0x3b, 0x97, 0x78,
+	0xe0, 0x02, 0x98, 0x5d, 0xce, 0xf5, 0x2f, 0xb5, 0x89, 0x3a, 0xaa, 0x9b, 0x53, 0x3f, 0xd6, 0x7f,
+	0xc5, 0x22, 0xea, 0x38, 0xb9, 0x39, 0xd7, 0x33, 0xf2, 0xbb, 0xba, 0x39, 0xc7, 0x43, 0x30, 0x3b,
+	0xba, 0x9f, 0x46, 0x65, 0xcb, 0x6b, 0xdf, 0x7e, 0xe2, 0xee, 0x43, 0x4a, 0x07, 0xe1, 0x38, 0x31,
+	0x10, 0x2a, 0xde, 0xac, 0xff, 0xd6, 0xed, 0xf4, 0x7f, 0xf2, 0x00, 0xb3, 0x37, 0x7d, 0x80, 0xff,
+	0x00, 0x92, 0x91, 0xb3, 0xa1, 0x65, 0x3b, 0x97, 0xc8, 0x08, 0x92, 0x51, 0x79, 0x17, 0x0a, 0xcb,
+	0x65, 0x60, 0x80, 0xec, 0xcb, 0xbd, 0xc3, 0x17, 0xfb, 0xb5, 0x82, 0x71, 0x71, 0xf6, 0x0a, 0xc8,
+	0xbb, 0x0f, 0x56, 0x37, 0xf4, 0x7b, 0x02, 0xff, 0x99, 0x24, 0x4e, 0x73, 0x4f, 0x80, 0x9d, 0x2f,
+	0x6a, 0x58, 0x72, 0x2d, 0x54, 0x30, 0xc8, 0x44, 0x51, 0xfe, 0x0b, 0x20, 0x3d, 0x40, 0xf9, 0x63,
+	0x0e, 0xf0, 0x2a, 0x6e, 0xd6, 0x48, 0xe3, 0x97, 0x37, 0x12, 0x22, 0x7f, 0x70, 0xd2, 0x0d, 0x68,
+	0xd8, 0xa9, 0x39, 0x48, 0xcf, 0xff, 0xbf, 0x57, 0x57, 0xee, 0x1e, 0xf9, 0x83, 0x03, 0xed, 0xbf,
+	0xcf, 0x64, 0x3c, 0x26, 0x76, 0x34, 0xb3, 0x17, 0x68, 0x9e, 0x63, 0xde, 0x88, 0xe6, 0x2d, 0xd1,
+	0xbc, 0x05, 0x5a, 0x5d, 0xaf, 0xac, 0xeb, 0xd3, 0xea, 0x4b, 0xb4, 0xfa, 0x02, 0xad, 0xe1, 0x58,
+	0x37, 0xa2, 0x35, 0x96, 0x68, 0x0d, 0x7c, 0x00, 0x76, 0xcc, 0xdb, 0x67, 0x2c, 0xe6, 0x61, 0xa8,
+	0x27, 0x17, 0xbc, 0x4a, 0x0a, 0x8c, 0xf0, 0xf6, 0xd9, 0x31, 0xe1, 0x61, 0x48, 0xe6, 0x52, 0x8c,
+	0xc1, 0x14, 0x32, 0xd6, 0x43, 0x6c, 0x3f, 0xfa, 0x8d, 0x28, 0x43, 0xdd, 0x05, 0x4c, 0x3a, 0xb9,
+	0x92, 0x51, 0x31, 0xd5, 0x5d, 0xc0, 0x24, 0x7e, 0x0a, 0xf9, 0x0f, 0x81, 0xec, 0xf3, 0x81, 0x0c,
+	0x38, 0x13, 0x8e, 0xad, 0x23, 0xee, 0xa6, 0x44, 0x7c, 0x15, 0xc8, 0xfe, 0x93, 0x89, 0xa2, 0x85,
+	0x1c, 0x83, 0x24, 0x11, 0xc5, 0x07, 0xb0, 0xb5, 0xd8, 0x48, 0xb5, 0x5d, 0xce, 0xe8, 0x58, 0x8f,
+	0xa0, 0x45, 0xd4, 0x11, 0x6f, 0x83, 0xf5, 0xde, 0x0f, 0x87, 0x54, 0xef, 0x20, 0x9b, 0x4c, 0x8c,
+	0x26, 0xba, 0x67, 0x24, 0xd5, 0xde, 0x8a, 0xda, 0x5c, 0xa3, 0x46, 0x97, 0xa8, 0xeb, 0x2b, 0xea,
+	0xcd, 0x35, 0xea, 0x5c, 0x52, 0xfd, 0x76, 0xae, 0x6e, 0xac, 0xa8, 0xed, 0x89, 0xba, 0x91, 0x54,
+	0xe7, 0xbd, 0x94, 0xc7, 0x9c, 0xa4, 0x3f, 0x03, 0xfb, 0xa2, 0x53, 0xd8, 0x81, 0x8d, 0x53, 0xea,
+	0xcb, 0x90, 0x8a, 0x29, 0x7c, 0x66, 0xe2, 0x3f, 0x20, 0x2b, 0x24, 0x67, 0x54, 0x4c, 0xff, 0xcd,
+	0xd4, 0x52, 0x69, 0x77, 0x38, 0x8f, 0x85, 0x5e, 0xd2, 0x36, 0x99, 0x18, 0xc5, 0x4d, 0xc8, 0x27,
+	0x9a, 0xb1, 0x6b, 0xe5, 0x3a, 0x85, 0xaf, 0x46, 0x6b, 0x03, 0x2c, 0x5f, 0x46, 0x9c, 0x37, 0x1f,
+	0x83, 0x39, 0x92, 0x51, 0xea, 0xca, 0xe9, 0x5c, 0xbd, 0xea, 0x14, 0xa3, 0xe9, 0x02, 0x1a, 0xa5,
+	0x2f, 0x2f, 0xaa, 0x93, 0x43, 0x23, 0xa1, 0xfd, 0x83, 0x54, 0xff, 0xae, 0x9e, 0x09, 0x34, 0x0a,
+	0x9a, 0xff, 0x81, 0x39, 0x1a, 0xa6, 0x0b, 0x7a, 0x25, 0xa3, 0x92, 0x21, 0xca, 0xb5, 0x55, 0x7f,
+	0x53, 0xeb, 0x05, 0xb2, 0x3f, 0x3c, 0x75, 0xdb, 0x3c, 0xaa, 0xbe, 0xeb, 0x0f, 0xa3, 0x41, 0x55,
+	0x0b, 0x63, 0xda, 0x0d, 0x69, 0x5b, 0x56, 0x03, 0x26, 0x69, 0xcc, 0xfc, 0xb0, 0x3a, 0x47, 0xfe,
+	0x08, 0x00, 0x00, 0xff, 0xff, 0x55, 0x22, 0xd4, 0xab, 0xc2, 0x09, 0x00, 0x00,
 }
diff --git a/internal/testprotos/desc_test1.proto b/internal/testprotos/desc_test1.proto
index cf59776..6b7d56b 100644
--- a/internal/testprotos/desc_test1.proto
+++ b/internal/testprotos/desc_test1.proto
@@ -95,6 +95,9 @@ message AnotherTestMessage {
 		// Comment for int
 		int64 int = 8;
 	}
+	// Comment for WithOptions
+	optional group WithOptions = 9 [deprecated = true] {
+	}
 
 	extensions 100 to 200;
 }