message.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. package proto
  24. import (
  25. "text/scanner"
  26. )
  27. // Message consists of a message name and a message body.
  28. type Message struct {
  29. Position scanner.Position
  30. Comment *Comment
  31. Name string
  32. IsExtend bool
  33. Elements []Visitee
  34. Parent Visitee
  35. }
  36. func (m *Message) groupName() string {
  37. if m.IsExtend {
  38. return "extend"
  39. }
  40. return "message"
  41. }
  42. // parse expects ident { messageBody
  43. func (m *Message) parse(p *Parser) error {
  44. _, tok, lit := p.nextIdentifier()
  45. if tok != tIDENT {
  46. if !isKeyword(tok) {
  47. return p.unexpected(lit, m.groupName()+" identifier", m)
  48. }
  49. }
  50. m.Name = lit
  51. _, tok, lit = p.next()
  52. if tok != tLEFTCURLY {
  53. return p.unexpected(lit, m.groupName()+" opening {", m)
  54. }
  55. return parseMessageBody(p, m)
  56. }
  57. // parseMessageBody parses elements after {. It consumes the closing }
  58. func parseMessageBody(p *Parser, c elementContainer) error {
  59. var (
  60. pos scanner.Position
  61. tok token
  62. lit string
  63. )
  64. for {
  65. pos, tok, lit = p.next()
  66. switch {
  67. case isComment(lit):
  68. if com := mergeOrReturnComment(c.elements(), lit, pos); com != nil { // not merged?
  69. c.addElement(com)
  70. }
  71. case tENUM == tok:
  72. e := new(Enum)
  73. e.Position = pos
  74. e.Comment = c.takeLastComment(pos.Line - 1)
  75. if err := e.parse(p); err != nil {
  76. return err
  77. }
  78. c.addElement(e)
  79. case tMESSAGE == tok:
  80. msg := new(Message)
  81. msg.Position = pos
  82. msg.Comment = c.takeLastComment(pos.Line - 1)
  83. if err := msg.parse(p); err != nil {
  84. return err
  85. }
  86. c.addElement(msg)
  87. case tOPTION == tok:
  88. o := new(Option)
  89. o.Position = pos
  90. o.Comment = c.takeLastComment(pos.Line - 1)
  91. if err := o.parse(p); err != nil {
  92. return err
  93. }
  94. c.addElement(o)
  95. case tONEOF == tok:
  96. o := new(Oneof)
  97. o.Position = pos
  98. o.Comment = c.takeLastComment(pos.Line - 1)
  99. if err := o.parse(p); err != nil {
  100. return err
  101. }
  102. c.addElement(o)
  103. case tMAP == tok:
  104. f := newMapField()
  105. f.Position = pos
  106. f.Comment = c.takeLastComment(pos.Line - 1)
  107. if err := f.parse(p); err != nil {
  108. return err
  109. }
  110. c.addElement(f)
  111. case tRESERVED == tok:
  112. r := new(Reserved)
  113. r.Position = pos
  114. r.Comment = c.takeLastComment(pos.Line - 1)
  115. if err := r.parse(p); err != nil {
  116. return err
  117. }
  118. c.addElement(r)
  119. // BEGIN proto2
  120. case tOPTIONAL == tok || tREPEATED == tok || tREQUIRED == tok:
  121. // look ahead
  122. prevTok := tok
  123. pos, tok, lit = p.next()
  124. if tGROUP == tok {
  125. g := new(Group)
  126. g.Position = pos
  127. g.Comment = c.takeLastComment(pos.Line - 1)
  128. g.Optional = prevTok == tOPTIONAL
  129. g.Repeated = prevTok == tREPEATED
  130. g.Required = prevTok == tREQUIRED
  131. if err := g.parse(p); err != nil {
  132. return err
  133. }
  134. c.addElement(g)
  135. } else {
  136. // not a group, will be tFIELD
  137. p.nextPut(pos, tok, lit)
  138. f := newNormalField()
  139. f.Type = lit
  140. f.Position = pos
  141. f.Comment = c.takeLastComment(pos.Line - 1)
  142. f.Optional = prevTok == tOPTIONAL
  143. f.Repeated = prevTok == tREPEATED
  144. f.Required = prevTok == tREQUIRED
  145. if err := f.parse(p); err != nil {
  146. return err
  147. }
  148. c.addElement(f)
  149. }
  150. case tGROUP == tok:
  151. g := new(Group)
  152. g.Position = pos
  153. g.Comment = c.takeLastComment(pos.Line - 1)
  154. if err := g.parse(p); err != nil {
  155. return err
  156. }
  157. c.addElement(g)
  158. case tEXTENSIONS == tok:
  159. e := new(Extensions)
  160. e.Position = pos
  161. e.Comment = c.takeLastComment(pos.Line - 1)
  162. if err := e.parse(p); err != nil {
  163. return err
  164. }
  165. c.addElement(e)
  166. case tEXTEND == tok:
  167. e := new(Message)
  168. e.Position = pos
  169. e.Comment = c.takeLastComment(pos.Line - 1)
  170. e.IsExtend = true
  171. if err := e.parse(p); err != nil {
  172. return err
  173. }
  174. c.addElement(e)
  175. // END proto2 only
  176. case tRIGHTCURLY == tok || tEOF == tok:
  177. goto done
  178. case tSEMICOLON == tok:
  179. maybeScanInlineComment(p, c)
  180. // continue
  181. default:
  182. // tFIELD
  183. p.nextPut(pos, tok, lit)
  184. f := newNormalField()
  185. f.Position = pos
  186. f.Comment = c.takeLastComment(pos.Line - 1)
  187. if err := f.parse(p); err != nil {
  188. return err
  189. }
  190. c.addElement(f)
  191. }
  192. }
  193. done:
  194. if tok != tRIGHTCURLY {
  195. return p.unexpected(lit, "extend|message|group closing }", c)
  196. }
  197. return nil
  198. }
  199. // Accept dispatches the call to the visitor.
  200. func (m *Message) Accept(v Visitor) {
  201. v.VisitMessage(m)
  202. }
  203. // addElement is part of elementContainer
  204. func (m *Message) addElement(v Visitee) {
  205. v.parent(m)
  206. m.Elements = append(m.Elements, v)
  207. }
  208. // elements is part of elementContainer
  209. func (m *Message) elements() []Visitee {
  210. return m.Elements
  211. }
  212. func (m *Message) takeLastComment(expectedOnLine int) (last *Comment) {
  213. last, m.Elements = takeLastCommentIfEndsOnLine(m.Elements, expectedOnLine)
  214. return
  215. }
  216. // Doc is part of Documented
  217. func (m *Message) Doc() *Comment {
  218. return m.Comment
  219. }
  220. func (m *Message) parent(v Visitee) { m.Parent = v }