query.go

  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}