diff --git a/formatter.go b/formatter.go index 0b46833..5772086 100644 --- a/formatter.go +++ b/formatter.go @@ -116,9 +116,9 @@ func (f *Formatter) VisitOption(o *Option) { if o.AggregatedConstants != nil { fmt.Fprintf(f.w, "{\n") f.indentLevel++ - for k, v := range o.AggregatedConstants { + for _, each := range o.AggregatedConstants { f.indent(0) - fmt.Fprintf(f.w, "%s: %s\n", k, v.String()) + fmt.Fprintf(f.w, "%s: %s\n", each.Name, each.Literal.String()) } f.indent(-1) fmt.Fprintf(f.w, "}") diff --git a/option.go b/option.go index 4999047..4df23dd 100644 --- a/option.go +++ b/option.go @@ -24,6 +24,7 @@ package proto import "fmt" +import "bytes" // Option is a protoc compiler option type Option struct { @@ -31,7 +32,7 @@ type Option struct { Constant Literal IsEmbedded bool Comment *Comment - AggregatedConstants map[string]*Literal + AggregatedConstants []*NamedLiteral } // inlineComment is part of commentInliner. @@ -130,25 +131,46 @@ func (o *Option) parse(p *Parser) error { type Literal struct { Source string IsString bool + Comment string } // String returns the source (if quoted then use double quote). func (l Literal) String() string { + var buf bytes.Buffer if l.IsString { - return "\"" + l.Source + "\"" + buf.WriteRune('"') } - return l.Source + buf.WriteString(l.Source) + if l.IsString { + buf.WriteRune('"') + } + if len(l.Comment) > 0 { + buf.WriteString(" //") + buf.WriteString(l.Comment) + } + return buf.String() } // parse expects to read a literal constant after =. func (l *Literal) parse(p *Parser) error { l.Source, l.IsString = p.s.scanLiteral() + p.s.skipWhitespace() + if p.s.peek('/') { + p.s.read() // consume first slash + l.Comment = p.s.scanComment() + } return nil } +// NamedLiteral associates a name with a Literal +type NamedLiteral struct { + *Literal + Name string +} + // parseAggregate reads options written using aggregate syntax func (o *Option) parseAggregate(p *Parser) error { - o.AggregatedConstants = map[string]*Literal{} + o.AggregatedConstants = []*NamedLiteral{} for { tok, lit := p.scanIgnoreWhitespace() if tRIGHTCURLY == tok { @@ -166,7 +188,7 @@ func (o *Option) parseAggregate(p *Parser) error { if err := l.parse(p); err != nil { return err } - o.AggregatedConstants[key] = l + o.AggregatedConstants = append(o.AggregatedConstants, &NamedLiteral{Name: key, Literal: l}) } tok, lit := p.scanIgnoreWhitespace() if tSEMICOLON != tok { diff --git a/service_test.go b/service_test.go index 6dd4b27..e18bf14 100644 --- a/service_test.go +++ b/service_test.go @@ -53,8 +53,8 @@ func TestRPCWithOptionAggregateSyntax(t *testing.T) { proto := `service AccountService { rpc CreateAccount (CreateAccount) returns (ServiceFault){ option (test_ident) = { - test: "test" - test2:"test2" + test: "test" // test + test2:"test2" // test2 }; } }` @@ -77,10 +77,16 @@ func TestRPCWithOptionAggregateSyntax(t *testing.T) { if got, want := len(opt.AggregatedConstants), 2; got != want { t.Fatalf("got [%v] want [%v]", got, want) } - if got, want := opt.AggregatedConstants["test"].Source, "test"; got != want { + if got, want := opt.AggregatedConstants[0].Source, "test"; got != want { t.Errorf("got [%v] want [%v]", got, want) } - if got, want := opt.AggregatedConstants["test2"].Source, "test2"; got != want { + if got, want := opt.AggregatedConstants[0].Comment, " test"; got != want { + t.Errorf("got [%v] want [%v]", got, want) + } + if got, want := opt.AggregatedConstants[1].Source, "test2"; got != want { + t.Errorf("got [%v] want [%v]", got, want) + } + if got, want := opt.AggregatedConstants[1].Comment, " test2"; got != want { t.Errorf("got [%v] want [%v]", got, want) } }