1// Copyright (c) 2017 Ernest Micklei 2// 3// MIT License 4// 5// Permission is hereby granted, free of charge, to any person obtaining 6// a copy of this software and associated documentation files (the 7// "Software"), to deal in the Software without restriction, including 8// without limitation the rights to use, copy, modify, merge, publish, 9// distribute, sublicense, and/or sell copies of the Software, and to 10// permit persons to whom the Software is furnished to do so, subject to 11// the following conditions: 12// 13// The above copyright notice and this permission notice shall be 14// included in all copies or substantial portions of the Software. 15// 16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24package proto 25 26// Proto represents a .proto definition 27type Proto struct { 28 Elements []Visitee 29} 30 31// addElement is part of elementContainer 32func (proto *Proto) addElement(v Visitee) { 33 proto.Elements = append(proto.Elements, v) 34} 35 36// elements is part of elementContainer 37func (proto *Proto) elements() []Visitee { 38 return proto.Elements 39} 40 41// takeLastComment is part of elementContainer 42// removes and returns the last element of the list if it is a Comment. 43func (proto *Proto) takeLastComment() (last *Comment) { 44 last, proto.Elements = takeLastComment(proto.Elements) 45 return 46} 47 48// parse parsers a complete .proto definition source. 49func (proto *Proto) parse(p *Parser) error { 50 for { 51 pos, tok, lit := p.next() 52 switch { 53 case isComment(lit): 54 if com := mergeOrReturnComment(proto.Elements, lit, pos); com != nil { // not merged? 55 proto.Elements = append(proto.Elements, com) 56 } 57 case tOPTION == tok: 58 o := new(Option) 59 o.Position = pos 60 o.Comment, proto.Elements = takeLastComment(proto.Elements) 61 if err := o.parse(p); err != nil { 62 return err 63 } 64 proto.Elements = append(proto.Elements, o) 65 case tSYNTAX == tok: 66 s := new(Syntax) 67 s.Position = pos 68 s.Comment, proto.Elements = takeLastComment(proto.Elements) 69 if err := s.parse(p); err != nil { 70 return err 71 } 72 proto.Elements = append(proto.Elements, s) 73 case tIMPORT == tok: 74 im := new(Import) 75 im.Position = pos 76 im.Comment, proto.Elements = takeLastComment(proto.Elements) 77 if err := im.parse(p); err != nil { 78 return err 79 } 80 proto.Elements = append(proto.Elements, im) 81 case tENUM == tok: 82 enum := new(Enum) 83 enum.Position = pos 84 enum.Comment, proto.Elements = takeLastComment(proto.Elements) 85 if err := enum.parse(p); err != nil { 86 return err 87 } 88 proto.Elements = append(proto.Elements, enum) 89 case tSERVICE == tok: 90 service := new(Service) 91 service.Position = pos 92 service.Comment, proto.Elements = takeLastComment(proto.Elements) 93 err := service.parse(p) 94 if err != nil { 95 return err 96 } 97 proto.Elements = append(proto.Elements, service) 98 case tPACKAGE == tok: 99 pkg := new(Package) 100 pkg.Position = pos 101 pkg.Comment, proto.Elements = takeLastComment(proto.Elements) 102 if err := pkg.parse(p); err != nil { 103 return err 104 } 105 proto.Elements = append(proto.Elements, pkg) 106 case tMESSAGE == tok: 107 msg := new(Message) 108 msg.Position = pos 109 msg.Comment, proto.Elements = takeLastComment(proto.Elements) 110 if err := msg.parse(p); err != nil { 111 return err 112 } 113 proto.Elements = append(proto.Elements, msg) 114 // BEGIN proto2 115 case tEXTEND == tok: 116 msg := new(Message) 117 msg.Position = pos 118 msg.Comment, proto.Elements = takeLastComment(proto.Elements) 119 msg.IsExtend = true 120 if err := msg.parse(p); err != nil { 121 return err 122 } 123 proto.Elements = append(proto.Elements, msg) 124 // END proto2 125 case tSEMICOLON == tok: 126 maybeScanInlineComment(p, proto) 127 // continue 128 case tEOF == tok: 129 goto done 130 default: 131 return p.unexpected(lit, ".proto element {comment|option|import|syntax|enum|service|package|message}", p) 132 } 133 } 134done: 135 return nil 136} 137 138// elementContainer unifies types that have elements. 139type elementContainer interface { 140 addElement(v Visitee) 141 elements() []Visitee 142 takeLastComment() *Comment 143} 144