Skip to content
This repository has been archived by the owner on Jan 5, 2019. It is now read-only.

Commit

Permalink
adding proto2 group
Browse files Browse the repository at this point in the history
  • Loading branch information
Ernest Micklei authored and Ernest Micklei committed Feb 2, 2017
1 parent 01d521f commit 38c556f
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 69 deletions.
2 changes: 1 addition & 1 deletion field.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type Field struct {
Options []*Option
}

// NormalField
// NormalField represents a field in a Message.
type NormalField struct {
*Field
Repeated bool
Expand Down
5 changes: 5 additions & 0 deletions formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,8 @@ func (f *Formatter) VisitNormalField(f1 *NormalField) {
}
fmt.Fprintf(f.w, "%s %s = %d;\n", f1.Type, f1.Name, f1.Sequence)
}

// VisitGroup formats a proto2 Group.
func (f *Formatter) VisitGroup(g *Group) {
io.WriteString(f.w, "TODO group ")
}
42 changes: 42 additions & 0 deletions group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package proto

// Group represents a (proto2 only) group.
// https://developers.google.com/protocol-buffers/docs/reference/proto2-spec#group_field
type Group struct {
Name string
Sequence int
Elements []Visitee
}

// Accept dispatches the call to the visitor.
func (g *Group) Accept(v Visitor) {
v.VisitGroup(g)
}

// addElement is part of elementContainer
func (g *Group) addElement(v Visitee) {
g.Elements = append(g.Elements, v)
}

// parse expects:
// group = label "group" groupName "=" fieldNumber messageBody
func (g *Group) parse(p *Parser) error {
tok, lit := p.scanIgnoreWhitespace()
if tok != tIDENT {
if !isKeyword(tok) {
return p.unexpected(lit, "group name", g)
}
}
g.Name = lit
tok, lit = p.scanIgnoreWhitespace()
if tok != tEQUALS {
return p.unexpected(lit, "group =", g)
}
i, err := p.s.scanInteger()
if err != nil {
return p.unexpected(lit, "group sequence number", g)
}
g.Sequence = i
parseMessageBody(p, g)
return nil
}
39 changes: 30 additions & 9 deletions message.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ func (m *Message) Accept(v Visitor) {
v.VisitMessage(m)
}

// addElement is part of elementContainer
func (m *Message) addElement(v Visitee) {
m.Elements = append(m.Elements, v)
}

func (m *Message) parse(p *Parser) error {
tok, lit := p.scanIgnoreWhitespace()
if tok != tIDENT {
Expand All @@ -23,47 +28,63 @@ func (m *Message) parse(p *Parser) error {
if tok != tLEFTCURLY {
return p.unexpected(lit, "message opening {", m)
}
return parseMessageBody(p, m)
}

func parseMessageBody(p *Parser, c elementContainer) error {
var (
tok token
lit string
)
for {
tok, lit = p.scanIgnoreWhitespace()
switch tok {
case tCOMMENT:
m.Elements = append(m.Elements, p.newComment(lit))
c.addElement(p.newComment(lit))
case tENUM:
e := new(Enum)
if err := e.parse(p); err != nil {
return err
}
m.Elements = append(m.Elements, e)
c.addElement(e)
case tMESSAGE:
msg := new(Message)
if err := msg.parse(p); err != nil {
return err
}
m.Elements = append(m.Elements, msg)
c.addElement(msg)
case tOPTION:
o := new(Option)
if err := o.parse(p); err != nil {
return err
}
m.Elements = append(m.Elements, o)
c.addElement(o)
case tONEOF:
o := new(Oneof)
if err := o.parse(p); err != nil {
return err
}
m.Elements = append(m.Elements, o)
c.addElement(o)
case tMAP:
f := newMapField()
if err := f.parse(p); err != nil {
return err
}
m.Elements = append(m.Elements, f)
c.addElement(f)
case tRESERVED:
r := new(Reserved)
if err := r.parse(p); err != nil {
return err
}
m.Elements = append(m.Elements, r)
c.addElement(r)
// BEGIN proto2 only
case tGROUP:
g := new(Group)
if err := g.parse(p); err != nil {
return err
}
c.addElement(g)
// END proto2 only
case tRIGHTCURLY:
goto done
case tSEMICOLON:
Expand All @@ -75,12 +96,12 @@ func (m *Message) parse(p *Parser) error {
if err := f.parse(p); err != nil {
return err
}
m.Elements = append(m.Elements, f)
c.addElement(f)
}
}
done:
if tok != tRIGHTCURLY {
return p.unexpected(lit, "message closing }", m)
return p.unexpected(lit, "message|group closing }", c)
}
return nil
}
34 changes: 19 additions & 15 deletions proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,6 @@ type Proto struct {
Elements []Visitee
}

// Comment holds a message and line number.
type Comment struct {
Message string
}

// Accept dispatches the call to the visitor.
func (c *Comment) Accept(v Visitor) {
v.VisitComment(c)
}

// IsMultiline returns whether its message has one or more lineends.
func (c Comment) IsMultiline() bool {
return strings.Contains(c.Message, "\n")
}

// parse parsers a complete .proto definition source.
func (proto *Proto) parse(p *Parser) error {
for {
Expand Down Expand Up @@ -82,3 +67,22 @@ func (proto *Proto) parse(p *Parser) error {
done:
return nil
}

// Comment holds a message and line number.
type Comment struct {
Message string
}

// Accept dispatches the call to the visitor.
func (c *Comment) Accept(v Visitor) {
v.VisitComment(c)
}

// IsMultiline returns whether its message has one or more lineends.
func (c Comment) IsMultiline() bool {
return strings.Contains(c.Message, "\n")
}

type elementContainer interface {
addElement(v Visitee)
}
28 changes: 0 additions & 28 deletions proto_test.go

This file was deleted.

13 changes: 0 additions & 13 deletions scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,19 +96,6 @@ func (s *scanner) scanWhitespace() (tok token, lit string) {
return tWS, buf.String()
}

// skipWhitespace consumes all contiguous whitespace.
func (s *scanner) skipWhitespace() {
// Non-whitespace characters and EOF will cause the loop to exit.
for {
if ch := s.read(); ch == eof {
break
} else if !isWhitespace(ch) {
s.unread(ch)
break
}
}
}

func (s *scanner) scanInteger() (int, error) {
var i int
if _, err := fmt.Fscanf(s.r, "%d", &i); err != nil {
Expand Down
7 changes: 4 additions & 3 deletions token.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const (
tDOT // .

// Keywords
KeywordsStart
keywordsStart
tSYNTAX
tSERVICE
tRPC
Expand All @@ -52,9 +52,10 @@ const (
// proto2
tOPTIONAL
tGROUP
KeywordsEnd
keywordsEnd
)

// typeTokens exists for future validation
const typeTokens = "double float int32 int64 uint32 uint64 sint32 sint64 fixed32 sfixed32 sfixed64 bool string bytes"

// context dependent reserved words
Expand All @@ -64,5 +65,5 @@ const (

// isKeyword returns if tok is in the keywords range
func isKeyword(tok token) bool {
return KeywordsStart < tok && tok < KeywordsEnd
return keywordsStart < tok && tok < keywordsEnd
}
2 changes: 2 additions & 0 deletions visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type Visitor interface {
VisitReserved(r *Reserved)
VisitRPC(r *RPC)
VisitMapField(f *MapField)
VisitGroup(g *Group)
}

// Visitee is implemented by all Proto elements.
Expand Down Expand Up @@ -47,6 +48,7 @@ func (r *reflector) VisitOneofField(o *OneOfField) { r.name = "OneOfField" }
func (r *reflector) VisitReserved(rs *Reserved) { r.name = "Reserved" }
func (r *reflector) VisitRPC(rpc *RPC) { r.name = "RPC" }
func (r *reflector) VisitMapField(f *MapField) { r.name = "MapField" }
func (r *reflector) VisitGroup(g *Group) { r.name = "Group" }

// nameOfVisitee returns the short type name of a Visitee.
func nameOfVisitee(e Visitee) string {
Expand Down

0 comments on commit 38c556f

Please sign in to comment.