package parser import ( "strconv" "github.com/vektah/gqlparser/ast" "github.com/vektah/gqlparser/gqlerror" "github.com/vektah/gqlparser/lexer" ) type parser struct { lexer lexer.Lexer err *gqlerror.Error peeked bool peekToken lexer.Token peekError *gqlerror.Error prev lexer.Token } func (p *parser) peekPos() *ast.Position { if p.err != nil { return nil } peek := p.peek() return &peek.Pos } func (p *parser) peek() lexer.Token { if p.err != nil { return p.prev } if !p.peeked { p.peekToken, p.peekError = p.lexer.ReadToken() p.peeked = true } return p.peekToken } func (p *parser) error(tok lexer.Token, format string, args ...interface{}) { if p.err != nil { return } p.err = gqlerror.ErrorLocf(tok.Pos.Src.Name, tok.Pos.Line, tok.Pos.Column, format, args...) } func (p *parser) next() lexer.Token { if p.err != nil { return p.prev } if p.peeked { p.peeked = false p.prev, p.err = p.peekToken, p.peekError } else { p.prev, p.err = p.lexer.ReadToken() } return p.prev } func (p *parser) expectKeyword(value string) lexer.Token { tok := p.peek() if tok.Kind == lexer.Name && tok.Value == value { return p.next() } p.error(tok, "Expected %s, found %s", strconv.Quote(value), tok.String()) return tok } func (p *parser) expect(kind lexer.Type) lexer.Token { tok := p.peek() if tok.Kind == kind { return p.next() } p.error(tok, "Expected %s, found %s", kind, tok.Kind.String()) return tok } func (p *parser) skip(kind lexer.Type) bool { if p.err != nil { return false } tok := p.peek() if tok.Kind != kind { return false } p.next() return true } func (p *parser) unexpectedError() { p.unexpectedToken(p.peek()) } func (p *parser) unexpectedToken(tok lexer.Token) { p.error(tok, "Unexpected %s", tok.String()) } func (p *parser) many(start lexer.Type, end lexer.Type, cb func()) { hasDef := p.skip(start) if !hasDef { return } for p.peek().Kind != end && p.err == nil { cb() } p.next() } func (p *parser) some(start lexer.Type, end lexer.Type, cb func()) { hasDef := p.skip(start) if !hasDef { return } called := false for p.peek().Kind != end && p.err == nil { called = true cb() } if !called { p.error(p.peek(), "expected at least one definition, found %s", p.peek().Kind.String()) return } p.next() }