1 package parser
2
3 import (
4 "github.com/vektah/gqlparser/gqlerror"
5 "github.com/vektah/gqlparser/lexer"
6
7 . "github.com/vektah/gqlparser/ast"
8 )
9
10 func ParseQuery(source *Source) (*QueryDocument, *gqlerror.Error) {
11 p := parser{
12 lexer: lexer.New(source),
13 }
14 return p.parseQueryDocument(), p.err
15 }
16
17 func (p *parser) parseQueryDocument() *QueryDocument {
18 var doc QueryDocument
19 for p.peek().Kind != lexer.EOF {
20 if p.err != nil {
21 return &doc
22 }
23 doc.Position = p.peekPos()
24 switch p.peek().Kind {
25 case lexer.Name:
26 switch p.peek().Value {
27 case "query", "mutation", "subscription":
28 doc.Operations = append(doc.Operations, p.parseOperationDefinition())
29 case "fragment":
30 doc.Fragments = append(doc.Fragments, p.parseFragmentDefinition())
31 default:
32 p.unexpectedError()
33 }
34 case lexer.BraceL:
35 doc.Operations = append(doc.Operations, p.parseOperationDefinition())
36 default:
37 p.unexpectedError()
38 }
39 }
40
41 return &doc
42 }
43
44 func (p *parser) parseOperationDefinition() *OperationDefinition {
45 if p.peek().Kind == lexer.BraceL {
46 return &OperationDefinition{
47 Position: p.peekPos(),
48 Operation: Query,
49 SelectionSet: p.parseRequiredSelectionSet(),
50 }
51 }
52
53 var od OperationDefinition
54 od.Position = p.peekPos()
55 od.Operation = p.parseOperationType()
56
57 if p.peek().Kind == lexer.Name {
58 od.Name = p.next().Value
59 }
60
61 od.VariableDefinitions = p.parseVariableDefinitions()
62 od.Directives = p.parseDirectives(false)
63 od.SelectionSet = p.parseRequiredSelectionSet()
64
65 return &od
66 }
67
68 func (p *parser) parseOperationType() Operation {
69 tok := p.next()
70 switch tok.Value {
71 case "query":
72 return Query
73 case "mutation":
74 return Mutation
75 case "subscription":
76 return Subscription
77 }
78 p.unexpectedToken(tok)
79 return ""
80 }
81
82 func (p *parser) parseVariableDefinitions() VariableDefinitionList {
83 var defs []*VariableDefinition
84 p.many(lexer.ParenL, lexer.ParenR, func() {
85 defs = append(defs, p.parseVariableDefinition())
86 })
87
88 return defs
89 }
90
91 func (p *parser) parseVariableDefinition() *VariableDefinition {
92 var def VariableDefinition
93 def.Position = p.peekPos()
94 def.Variable = p.parseVariable()
95
96 p.expect(lexer.Colon)
97
98 def.Type = p.parseTypeReference()
99
100 if p.skip(lexer.Equals) {
101 def.DefaultValue = p.parseValueLiteral(true)
102 }
103
104 return &def
105 }
106
107 func (p *parser) parseVariable() string {
108 p.expect(lexer.Dollar)
109 return p.parseName()
110 }
111
112 func (p *parser) parseOptionalSelectionSet() SelectionSet {
113 var selections []Selection
114 p.some(lexer.BraceL, lexer.BraceR, func() {
115 selections = append(selections, p.parseSelection())
116 })
117
118 return SelectionSet(selections)
119 }
120
121 func (p *parser) parseRequiredSelectionSet() SelectionSet {
122 if p.peek().Kind != lexer.BraceL {
123 p.error(p.peek(), "Expected %s, found %s", lexer.BraceL, p.peek().Kind.String())
124 return nil
125 }
126
127 var selections []Selection
128 p.some(lexer.BraceL, lexer.BraceR, func() {
129 selections = append(selections, p.parseSelection())
130 })
131
132 return SelectionSet(selections)
133 }
134
135 func (p *parser) parseSelection() Selection {
136 if p.peek().Kind == lexer.Spread {
137 return p.parseFragment()
138 }
139 return p.parseField()
140 }
141
142 func (p *parser) parseField() *Field {
143 var field Field
144 field.Position = p.peekPos()
145 field.Alias = p.parseName()
146
147 if p.skip(lexer.Colon) {
148 field.Name = p.parseName()
149 } else {
150 field.Name = field.Alias
151 }
152
153 field.Arguments = p.parseArguments(false)
154 field.Directives = p.parseDirectives(false)
155 if p.peek().Kind == lexer.BraceL {
156 field.SelectionSet = p.parseOptionalSelectionSet()
157 }
158
159 return &field
160 }
161
162 func (p *parser) parseArguments(isConst bool) ArgumentList {
163 var arguments ArgumentList
164 p.many(lexer.ParenL, lexer.ParenR, func() {
165 arguments = append(arguments, p.parseArgument(isConst))
166 })
167
168 return arguments
169 }
170
171 func (p *parser) parseArgument(isConst bool) *Argument {
172 arg := Argument{}
173 arg.Position = p.peekPos()
174 arg.Name = p.parseName()
175 p.expect(lexer.Colon)
176
177 arg.Value = p.parseValueLiteral(isConst)
178 return &arg
179 }
180
181 func (p *parser) parseFragment() Selection {
182 p.expect(lexer.Spread)
183
184 if peek := p.peek(); peek.Kind == lexer.Name && peek.Value != "on" {
185 return &FragmentSpread{
186 Position: p.peekPos(),
187 Name: p.parseFragmentName(),
188 Directives: p.parseDirectives(false),
189 }
190 }
191
192 var def InlineFragment
193 def.Position = p.peekPos()
194 if p.peek().Value == "on" {
195 p.next()
196
197 def.TypeCondition = p.parseName()
198 }
199
200 def.Directives = p.parseDirectives(false)
201 def.SelectionSet = p.parseRequiredSelectionSet()
202 return &def
203 }
204
205 func (p *parser) parseFragmentDefinition() *FragmentDefinition {
206 var def FragmentDefinition
207 def.Position = p.peekPos()
208 p.expectKeyword("fragment")
209
210 def.Name = p.parseFragmentName()
211 def.VariableDefinition = p.parseVariableDefinitions()
212
213 p.expectKeyword("on")
214
215 def.TypeCondition = p.parseName()
216 def.Directives = p.parseDirectives(false)
217 def.SelectionSet = p.parseRequiredSelectionSet()
218 return &def
219 }
220
221 func (p *parser) parseFragmentName() string {
222 if p.peek().Value == "on" {
223 p.unexpectedError()
224 return ""
225 }
226
227 return p.parseName()
228 }
229
230 func (p *parser) parseValueLiteral(isConst bool) *Value {
231 token := p.peek()
232
233 var kind ValueKind
234 switch token.Kind {
235 case lexer.BracketL:
236 return p.parseList(isConst)
237 case lexer.BraceL:
238 return p.parseObject(isConst)
239 case lexer.Dollar:
240 if isConst {
241 p.unexpectedError()
242 return nil
243 }
244 return &Value{Position: &token.Pos, Raw: p.parseVariable(), Kind: Variable}
245 case lexer.Int:
246 kind = IntValue
247 case lexer.Float:
248 kind = FloatValue
249 case lexer.String:
250 kind = StringValue
251 case lexer.BlockString:
252 kind = BlockValue
253 case lexer.Name:
254 switch token.Value {
255 case "true", "false":
256 kind = BooleanValue
257 case "null":
258 kind = NullValue
259 default:
260 kind = EnumValue
261 }
262 default:
263 p.unexpectedError()
264 return nil
265 }
266
267 p.next()
268
269 return &Value{Position: &token.Pos, Raw: token.Value, Kind: kind}
270 }
271
272 func (p *parser) parseList(isConst bool) *Value {
273 var values ChildValueList
274 pos := p.peekPos()
275 p.many(lexer.BracketL, lexer.BracketR, func() {
276 values = append(values, &ChildValue{Value: p.parseValueLiteral(isConst)})
277 })
278
279 return &Value{Children: values, Kind: ListValue, Position: pos}
280 }
281
282 func (p *parser) parseObject(isConst bool) *Value {
283 var fields ChildValueList
284 pos := p.peekPos()
285 p.many(lexer.BraceL, lexer.BraceR, func() {
286 fields = append(fields, p.parseObjectField(isConst))
287 })
288
289 return &Value{Children: fields, Kind: ObjectValue, Position: pos}
290 }
291
292 func (p *parser) parseObjectField(isConst bool) *ChildValue {
293 field := ChildValue{}
294 field.Position = p.peekPos()
295 field.Name = p.parseName()
296
297 p.expect(lexer.Colon)
298
299 field.Value = p.parseValueLiteral(isConst)
300 return &field
301 }
302
303 func (p *parser) parseDirectives(isConst bool) []*Directive {
304 var directives []*Directive
305
306 for p.peek().Kind == lexer.At {
307 if p.err != nil {
308 break
309 }
310 directives = append(directives, p.parseDirective(isConst))
311 }
312 return directives
313 }
314
315 func (p *parser) parseDirective(isConst bool) *Directive {
316 p.expect(lexer.At)
317
318 return &Directive{
319 Position: p.peekPos(),
320 Name: p.parseName(),
321 Arguments: p.parseArguments(isConst),
322 }
323 }
324
325 func (p *parser) parseTypeReference() *Type {
326 var typ Type
327
328 if p.skip(lexer.BracketL) {
329 typ.Position = p.peekPos()
330 typ.Elem = p.parseTypeReference()
331 p.expect(lexer.BracketR)
332 } else {
333 typ.Position = p.peekPos()
334 typ.NamedType = p.parseName()
335 }
336
337 if p.skip(lexer.Bang) {
338 typ.Position = p.peekPos()
339 typ.NonNull = true
340 }
341 return &typ
342 }
343
344 func (p *parser) parseName() string {
345 token := p.expect(lexer.Name)
346
347 return token.Value
348 }
349
View as plain text