1package parser
2
3import (
4 "github.com/vektah/gqlparser/gqlerror"
5 "github.com/vektah/gqlparser/lexer"
6
7 . "github.com/vektah/gqlparser/ast"
8)
9
10func ParseQuery(source *Source) (*QueryDocument, *gqlerror.Error) {
11 p := parser{
12 lexer: lexer.New(source),
13 }
14 return p.parseQueryDocument(), p.err
15}
16
17func (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
44func (p *parser) parseOperationDefinition() *OperationDefinition {
45 if p.peek().Kind == lexer.BraceL {
46 return &OperationDefinition{
47 Position: p.peekPos(),
48 Operation: Query,
49 SelectionSet: p.parseSelectionSet(),
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.parseSelectionSet()
64
65 return &od
66}
67
68func (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
82func (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
91func (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
107func (p *parser) parseVariable() string {
108 p.expect(lexer.Dollar)
109 return p.parseName()
110}
111
112func (p *parser) parseSelectionSet() SelectionSet {
113 var selections []Selection
114 p.many(lexer.BraceL, lexer.BraceR, func() {
115 selections = append(selections, p.parseSelection())
116 })
117
118 return SelectionSet(selections)
119}
120
121func (p *parser) parseSelection() Selection {
122 if p.peek().Kind == lexer.Spread {
123 return p.parseFragment()
124 }
125 return p.parseField()
126}
127
128func (p *parser) parseField() *Field {
129 var field Field
130 field.Position = p.peekPos()
131 field.Alias = p.parseName()
132
133 if p.skip(lexer.Colon) {
134 field.Name = p.parseName()
135 } else {
136 field.Name = field.Alias
137 }
138
139 field.Arguments = p.parseArguments(false)
140 field.Directives = p.parseDirectives(false)
141 if p.peek().Kind == lexer.BraceL {
142 field.SelectionSet = p.parseSelectionSet()
143 }
144
145 return &field
146}
147
148func (p *parser) parseArguments(isConst bool) ArgumentList {
149 var arguments ArgumentList
150 p.many(lexer.ParenL, lexer.ParenR, func() {
151 arguments = append(arguments, p.parseArgument(isConst))
152 })
153
154 return arguments
155}
156
157func (p *parser) parseArgument(isConst bool) *Argument {
158 arg := Argument{}
159 arg.Position = p.peekPos()
160 arg.Name = p.parseName()
161 p.expect(lexer.Colon)
162
163 arg.Value = p.parseValueLiteral(isConst)
164 return &arg
165}
166
167func (p *parser) parseFragment() Selection {
168 p.expect(lexer.Spread)
169
170 if peek := p.peek(); peek.Kind == lexer.Name && peek.Value != "on" {
171 return &FragmentSpread{
172 Position: p.peekPos(),
173 Name: p.parseFragmentName(),
174 Directives: p.parseDirectives(false),
175 }
176 }
177
178 var def InlineFragment
179 def.Position = p.peekPos()
180 if p.peek().Value == "on" {
181 p.next() // "on"
182
183 def.TypeCondition = p.parseName()
184 }
185
186 def.Directives = p.parseDirectives(false)
187 def.SelectionSet = p.parseSelectionSet()
188 return &def
189}
190
191func (p *parser) parseFragmentDefinition() *FragmentDefinition {
192 var def FragmentDefinition
193 def.Position = p.peekPos()
194 p.expectKeyword("fragment")
195
196 def.Name = p.parseFragmentName()
197 def.VariableDefinition = p.parseVariableDefinitions()
198
199 p.expectKeyword("on")
200
201 def.TypeCondition = p.parseName()
202 def.Directives = p.parseDirectives(false)
203 def.SelectionSet = p.parseSelectionSet()
204 return &def
205}
206
207func (p *parser) parseFragmentName() string {
208 if p.peek().Value == "on" {
209 p.unexpectedError()
210 return ""
211 }
212
213 return p.parseName()
214}
215
216func (p *parser) parseValueLiteral(isConst bool) *Value {
217 token := p.peek()
218
219 var kind ValueKind
220 switch token.Kind {
221 case lexer.BracketL:
222 return p.parseList(isConst)
223 case lexer.BraceL:
224 return p.parseObject(isConst)
225 case lexer.Dollar:
226 if isConst {
227 p.unexpectedError()
228 return nil
229 }
230 return &Value{Position: &token.Pos, Raw: p.parseVariable(), Kind: Variable}
231 case lexer.Int:
232 kind = IntValue
233 case lexer.Float:
234 kind = FloatValue
235 case lexer.String:
236 kind = StringValue
237 case lexer.BlockString:
238 kind = BlockValue
239 case lexer.Name:
240 switch token.Value {
241 case "true", "false":
242 kind = BooleanValue
243 case "null":
244 kind = NullValue
245 default:
246 kind = EnumValue
247 }
248 default:
249 p.unexpectedError()
250 return nil
251 }
252
253 p.next()
254
255 return &Value{Position: &token.Pos, Raw: token.Value, Kind: kind}
256}
257
258func (p *parser) parseList(isConst bool) *Value {
259 var values ChildValueList
260 pos := p.peekPos()
261 p.many(lexer.BracketL, lexer.BracketR, func() {
262 values = append(values, &ChildValue{Value: p.parseValueLiteral(isConst)})
263 })
264
265 return &Value{Children: values, Kind: ListValue, Position: pos}
266}
267
268func (p *parser) parseObject(isConst bool) *Value {
269 var fields ChildValueList
270 pos := p.peekPos()
271 p.many(lexer.BraceL, lexer.BraceR, func() {
272 fields = append(fields, p.parseObjectField(isConst))
273 })
274
275 return &Value{Children: fields, Kind: ObjectValue, Position: pos}
276}
277
278func (p *parser) parseObjectField(isConst bool) *ChildValue {
279 field := ChildValue{}
280 field.Position = p.peekPos()
281 field.Name = p.parseName()
282
283 p.expect(lexer.Colon)
284
285 field.Value = p.parseValueLiteral(isConst)
286 return &field
287}
288
289func (p *parser) parseDirectives(isConst bool) []*Directive {
290 var directives []*Directive
291
292 for p.peek().Kind == lexer.At {
293 if p.err != nil {
294 break
295 }
296 directives = append(directives, p.parseDirective(isConst))
297 }
298 return directives
299}
300
301func (p *parser) parseDirective(isConst bool) *Directive {
302 p.expect(lexer.At)
303
304 return &Directive{
305 Position: p.peekPos(),
306 Name: p.parseName(),
307 Arguments: p.parseArguments(isConst),
308 }
309}
310
311func (p *parser) parseTypeReference() *Type {
312 var typ Type
313
314 if p.skip(lexer.BracketL) {
315 typ.Position = p.peekPos()
316 typ.Elem = p.parseTypeReference()
317 p.expect(lexer.BracketR)
318 } else {
319 typ.Position = p.peekPos()
320 typ.NamedType = p.parseName()
321 }
322
323 if p.skip(lexer.Bang) {
324 typ.Position = p.peekPos()
325 typ.NonNull = true
326 }
327 return &typ
328}
329
330func (p *parser) parseName() string {
331 token := p.expect(lexer.Name)
332
333 return token.Value
334}