go-common/app/admin/ep/melloi/service/proto/proto.go
2019-04-22 18:49:16 +08:00

171 lines
5.2 KiB
Go

// Copyright (c) 2017 Ernest Micklei
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package proto
// Proto represents a .proto definition
type Proto struct {
Filename string
Elements []Visitee
Imports []Import
Enums []Enum
Package []Package
Options []Option
Messages []Message
Services []Service
Extends []Extensions
}
// Accept dispatches the call to the visitor.
func (proto *Proto) Accept(v Visitor) {
// As Proto is not (yet) a Visitee, we enumerate its elements instead
//v.VisitProto(proto)
for _, each := range proto.Elements {
each.Accept(v)
}
}
// addElement is part of elementContainer
func (proto *Proto) addElement(v Visitee) {
v.parent(proto)
proto.Elements = append(proto.Elements, v)
}
// elements is part of elementContainer
func (proto *Proto) elements() []Visitee {
return proto.Elements
}
// takeLastComment is part of elementContainer
// removes and returns the last element of the list if it is a Comment.
func (proto *Proto) takeLastComment(expectedOnLine int) (last *Comment) {
last, proto.Elements = takeLastCommentIfEndsOnLine(proto.Elements, expectedOnLine)
return
}
// parse parsers a complete .proto definition source.
func (proto *Proto) parse(p *Parser) (*Proto, error) {
pro := new(Proto)
for {
pos, tok, lit := p.next()
switch {
case isComment(lit):
if com := mergeOrReturnComment(proto.Elements, lit, pos); com != nil { // not merged?
proto.Elements = append(proto.Elements, com)
}
case tOPTION == tok:
o := new(Option)
o.Position = pos
o.Comment, proto.Elements = takeLastCommentIfEndsOnLine(proto.Elements, pos.Line-1)
if err := o.parse(p); err != nil {
return pro, err
}
pro.Options = append(pro.Options, *o)
proto.addElement(o)
case tSYNTAX == tok:
s := new(Syntax)
s.Position = pos
s.Comment, proto.Elements = takeLastCommentIfEndsOnLine(proto.Elements, pos.Line-1)
if err := s.parse(p); err != nil {
return pro, err
}
proto.addElement(s)
case tIMPORT == tok:
im := new(Import)
im.Position = pos
im.Comment, proto.Elements = takeLastCommentIfEndsOnLine(proto.Elements, pos.Line-1)
if err := im.parse(p); err != nil {
return pro, err
}
pro.Imports = append(pro.Imports, *im)
proto.addElement(im)
case tENUM == tok:
enum := new(Enum)
enum.Position = pos
enum.Comment, proto.Elements = takeLastCommentIfEndsOnLine(proto.Elements, pos.Line-1)
if err := enum.parse(p); err != nil {
return pro, err
}
pro.Enums = append(pro.Enums, *enum)
proto.addElement(enum)
case tSERVICE == tok:
service := new(Service)
service.Position = pos
service.Comment, proto.Elements = takeLastCommentIfEndsOnLine(proto.Elements, pos.Line-1)
err := service.parse(p)
if err != nil {
return pro, err
}
pro.Services = append(pro.Services, *service)
proto.addElement(service)
case tPACKAGE == tok:
pkg := new(Package)
pkg.Position = pos
pkg.Comment, proto.Elements = takeLastCommentIfEndsOnLine(proto.Elements, pos.Line-1)
if err := pkg.parse(p); err != nil {
return pro, err
}
pro.Package = append(pro.Package, *pkg)
proto.addElement(pkg)
case tMESSAGE == tok:
msg := new(Message)
msg.Position = pos
msg.Comment, proto.Elements = takeLastCommentIfEndsOnLine(proto.Elements, pos.Line-1)
if err := msg.parse(p); err != nil {
return pro, err
}
pro.Messages = append(pro.Messages, *msg)
proto.addElement(msg)
// BEGIN proto2
case tEXTEND == tok:
msg := new(Message)
msg.Position = pos
msg.Comment, proto.Elements = takeLastCommentIfEndsOnLine(proto.Elements, pos.Line-1)
msg.IsExtend = true
if err := msg.parse(p); err != nil {
return pro, err
}
proto.addElement(msg)
// END proto2
case tSEMICOLON == tok:
maybeScanInlineComment(p, proto)
// continue
case tEOF == tok:
goto done
default:
return pro, p.unexpected(lit, ".proto element {comment|option|import|syntax|enum|service|package|message}", p)
}
}
done:
return pro, nil
}
func (proto *Proto) parent(v Visitee) {}
// elementContainer unifies types that have elements.
type elementContainer interface {
addElement(v Visitee)
elements() []Visitee
takeLastComment(expectedOnLine int) *Comment
}