1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package proto
25
26 import (
27 "text/scanner"
28 )
29
30
31 type Service struct {
32 Position scanner.Position
33 Comment *Comment
34 Name string
35 Elements []Visitee
36 Parent Visitee
37 }
38
39
40 func (s *Service) Accept(v Visitor) {
41 v.VisitService(s)
42 }
43
44
45 func (s *Service) Doc() *Comment {
46 return s.Comment
47 }
48
49
50 func (s *Service) addElement(v Visitee) {
51 v.parent(s)
52 s.Elements = append(s.Elements, v)
53 }
54
55
56 func (s *Service) elements() []Visitee {
57 return s.Elements
58 }
59
60
61
62 func (s *Service) takeLastComment(expectedOnLine int) (last *Comment) {
63 last, s.Elements = takeLastCommentIfEndsOnLine(s.Elements, expectedOnLine)
64 return
65 }
66
67
68 func (s *Service) parse(p *Parser) error {
69 pos, tok, lit := p.nextIdentifier()
70 if tok != tIDENT {
71 if !isKeyword(tok) {
72 return p.unexpected(lit, "service identifier", s)
73 }
74 }
75 s.Name = lit
76 consumeCommentFor(p, s)
77 pos, tok, lit = p.next()
78 if tok != tLEFTCURLY {
79 return p.unexpected(lit, "service opening {", s)
80 }
81 for {
82 pos, tok, lit = p.next()
83 switch tok {
84 case tCOMMENT:
85 if com := mergeOrReturnComment(s.Elements, lit, pos); com != nil {
86 s.addElement(com)
87 }
88 case tOPTION:
89 opt := new(Option)
90 opt.Position = pos
91 opt.Comment, s.Elements = takeLastCommentIfEndsOnLine(s.elements(), pos.Line-1)
92 if err := opt.parse(p); err != nil {
93 return err
94 }
95 s.addElement(opt)
96 case tRPC:
97 rpc := new(RPC)
98 rpc.Position = pos
99 rpc.Comment, s.Elements = takeLastCommentIfEndsOnLine(s.Elements, pos.Line-1)
100 err := rpc.parse(p)
101 if err != nil {
102 return err
103 }
104 s.addElement(rpc)
105 maybeScanInlineComment(p, s)
106 case tSEMICOLON:
107 maybeScanInlineComment(p, s)
108 case tRIGHTCURLY:
109 goto done
110 default:
111 return p.unexpected(lit, "service comment|rpc", s)
112 }
113 }
114 done:
115 return nil
116 }
117
118 func (s *Service) parent(v Visitee) { s.Parent = v }
119
120
121 type RPC struct {
122 Position scanner.Position
123 Comment *Comment
124 Name string
125 RequestType string
126 StreamsRequest bool
127 ReturnsType string
128 StreamsReturns bool
129 Elements []Visitee
130 InlineComment *Comment
131 Parent Visitee
132
133
134 Options []*Option
135 }
136
137
138 func (r *RPC) Accept(v Visitor) {
139 v.VisitRPC(r)
140 }
141
142
143 func (r *RPC) Doc() *Comment {
144 return r.Comment
145 }
146
147
148 func (r *RPC) inlineComment(c *Comment) {
149 r.InlineComment = c
150 }
151
152
153 func (r *RPC) parse(p *Parser) error {
154 pos, tok, lit := p.next()
155 if tok != tIDENT {
156 return p.unexpected(lit, "rpc method", r)
157 }
158 r.Name = lit
159 pos, tok, lit = p.next()
160 if tok != tLEFTPAREN {
161 return p.unexpected(lit, "rpc type opening (", r)
162 }
163 pos, tok, lit = p.nextTypeName()
164 if tSTREAM == tok {
165 r.StreamsRequest = true
166 pos, tok, lit = p.nextTypeName()
167 }
168 if tok != tIDENT {
169 return p.unexpected(lit, "rpc stream | request type", r)
170 }
171 r.RequestType = lit
172 pos, tok, lit = p.next()
173 if tok != tRIGHTPAREN {
174 return p.unexpected(lit, "rpc type closing )", r)
175 }
176 pos, tok, lit = p.next()
177 if tok != tRETURNS {
178 return p.unexpected(lit, "rpc returns", r)
179 }
180 pos, tok, lit = p.next()
181 if tok != tLEFTPAREN {
182 return p.unexpected(lit, "rpc type opening (", r)
183 }
184 pos, tok, lit = p.nextTypeName()
185 if tSTREAM == tok {
186 r.StreamsReturns = true
187 pos, tok, lit = p.nextTypeName()
188 }
189 if tok != tIDENT {
190 return p.unexpected(lit, "rpc stream | returns type", r)
191 }
192 r.ReturnsType = lit
193 pos, tok, lit = p.next()
194 if tok != tRIGHTPAREN {
195 return p.unexpected(lit, "rpc type closing )", r)
196 }
197 pos, tok, lit = p.next()
198 if tSEMICOLON == tok {
199 p.nextPut(pos, tok, lit)
200 return nil
201 }
202 if tLEFTCURLY == tok {
203
204 for {
205 pos, tok, lit = p.next()
206 if tRIGHTCURLY == tok {
207 break
208 }
209 if isComment(lit) {
210 if com := mergeOrReturnComment(r.elements(), lit, pos); com != nil {
211 r.addElement(com)
212 continue
213 }
214 }
215 if tSEMICOLON == tok {
216 maybeScanInlineComment(p, r)
217 continue
218 }
219 if tOPTION == tok {
220 o := new(Option)
221 o.Position = pos
222 if err := o.parse(p); err != nil {
223 return err
224 }
225 r.addElement(o)
226 }
227 }
228 }
229 return nil
230 }
231
232
233 func (r *RPC) addElement(v Visitee) {
234 v.parent(r)
235 r.Elements = append(r.Elements, v)
236
237 if option, ok := v.(*Option); ok {
238 r.Options = append(r.Options, option)
239 }
240 }
241
242
243 func (r *RPC) elements() []Visitee {
244 return r.Elements
245 }
246
247 func (r *RPC) takeLastComment(expectedOnLine int) (last *Comment) {
248 last, r.Elements = takeLastCommentIfEndsOnLine(r.Elements, expectedOnLine)
249 return
250 }
251
252 func (r *RPC) parent(v Visitee) { r.Parent = v }
253
View as plain text