aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/vektah/gqlparser/lexer
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/vektah/gqlparser/lexer')
-rw-r--r--vendor/github.com/vektah/gqlparser/lexer/blockstring.go58
-rw-r--r--vendor/github.com/vektah/gqlparser/lexer/lexer.go510
-rw-r--r--vendor/github.com/vektah/gqlparser/lexer/lexer_test.yml672
-rw-r--r--vendor/github.com/vektah/gqlparser/lexer/token.go148
4 files changed, 1388 insertions, 0 deletions
diff --git a/vendor/github.com/vektah/gqlparser/lexer/blockstring.go b/vendor/github.com/vektah/gqlparser/lexer/blockstring.go
new file mode 100644
index 00000000..4065a610
--- /dev/null
+++ b/vendor/github.com/vektah/gqlparser/lexer/blockstring.go
@@ -0,0 +1,58 @@
+package lexer
+
+import (
+ "math"
+ "strings"
+)
+
+// blockStringValue produces the value of a block string from its parsed raw value, similar to
+// Coffeescript's block string, Python's docstring trim or Ruby's strip_heredoc.
+//
+// This implements the GraphQL spec's BlockStringValue() static algorithm.
+func blockStringValue(raw string) string {
+ lines := strings.Split(raw, "\n")
+
+ commonIndent := math.MaxInt32
+ for _, line := range lines {
+ indent := leadingWhitespace(line)
+ if indent < len(line) && indent < commonIndent {
+ commonIndent = indent
+ if commonIndent == 0 {
+ break
+ }
+ }
+ }
+
+ if commonIndent != math.MaxInt32 && len(lines) > 0 {
+ for i := 1; i < len(lines); i++ {
+ if len(lines[i]) < commonIndent {
+ lines[i] = ""
+ } else {
+ lines[i] = lines[i][commonIndent:]
+ }
+ }
+ }
+
+ start := 0
+ end := len(lines)
+
+ for start < end && leadingWhitespace(lines[start]) == math.MaxInt32 {
+ start++
+ }
+
+ for start < end && leadingWhitespace(lines[end-1]) == math.MaxInt32 {
+ end--
+ }
+
+ return strings.Join(lines[start:end], "\n")
+}
+
+func leadingWhitespace(str string) int {
+ for i, r := range str {
+ if r != ' ' && r != '\t' {
+ return i
+ }
+ }
+ // this line is made up entirely of whitespace, its leading whitespace doesnt count.
+ return math.MaxInt32
+}
diff --git a/vendor/github.com/vektah/gqlparser/lexer/lexer.go b/vendor/github.com/vektah/gqlparser/lexer/lexer.go
new file mode 100644
index 00000000..3aaa7102
--- /dev/null
+++ b/vendor/github.com/vektah/gqlparser/lexer/lexer.go
@@ -0,0 +1,510 @@
+package lexer
+
+import (
+ "bytes"
+ "unicode/utf8"
+
+ "github.com/vektah/gqlparser/ast"
+ "github.com/vektah/gqlparser/gqlerror"
+)
+
+// Lexer turns graphql request and schema strings into tokens
+type Lexer struct {
+ *ast.Source
+ // An offset into the string in bytes
+ start int
+ // An offset into the string in runes
+ startRunes int
+ // An offset into the string in bytes
+ end int
+ // An offset into the string in runes
+ endRunes int
+ // the current line number
+ line int
+ // An offset into the string in rune
+ lineStartRunes int
+}
+
+func New(src *ast.Source) Lexer {
+ return Lexer{
+ Source: src,
+ line: 1,
+ }
+}
+
+// take one rune from input and advance end
+func (s *Lexer) peek() (rune, int) {
+ return utf8.DecodeRuneInString(s.Input[s.end:])
+}
+
+func (s *Lexer) makeToken(kind Type) (Token, *gqlerror.Error) {
+ return s.makeValueToken(kind, s.Input[s.start:s.end])
+}
+
+func (s *Lexer) makeValueToken(kind Type, value string) (Token, *gqlerror.Error) {
+ return Token{
+ Kind: kind,
+ Value: value,
+ Pos: ast.Position{
+ Start: s.startRunes,
+ End: s.endRunes,
+ Line: s.line,
+ Column: s.startRunes - s.lineStartRunes + 1,
+ Src: s.Source,
+ },
+ }, nil
+}
+
+func (s *Lexer) makeError(format string, args ...interface{}) (Token, *gqlerror.Error) {
+ column := s.endRunes - s.lineStartRunes + 1
+ return Token{
+ Kind: Invalid,
+ Pos: ast.Position{
+ Start: s.startRunes,
+ End: s.endRunes,
+ Line: s.line,
+ Column: column,
+ Src: s.Source,
+ },
+ }, gqlerror.ErrorLocf(s.Source.Name, s.line, column, format, args...)
+}
+
+// ReadToken gets the next token from the source starting at the given position.
+//
+// This skips over whitespace and comments until it finds the next lexable
+// token, then lexes punctuators immediately or calls the appropriate helper
+// function for more complicated tokens.
+func (s *Lexer) ReadToken() (token Token, err *gqlerror.Error) {
+
+ s.ws()
+ s.start = s.end
+ s.startRunes = s.endRunes
+
+ if s.end >= len(s.Input) {
+ return s.makeToken(EOF)
+ }
+ r := s.Input[s.start]
+ s.end++
+ s.endRunes++
+ switch r {
+ case '!':
+ return s.makeValueToken(Bang, "")
+
+ case '$':
+ return s.makeValueToken(Dollar, "")
+ case '&':
+ return s.makeValueToken(Amp, "")
+ case '(':
+ return s.makeValueToken(ParenL, "")
+ case ')':
+ return s.makeValueToken(ParenR, "")
+ case '.':
+ if len(s.Input) > s.start+2 && s.Input[s.start:s.start+3] == "..." {
+ s.end += 2
+ s.endRunes += 2
+ return s.makeValueToken(Spread, "")
+ }
+ case ':':
+ return s.makeValueToken(Colon, "")
+ case '=':
+ return s.makeValueToken(Equals, "")
+ case '@':
+ return s.makeValueToken(At, "")
+ case '[':
+ return s.makeValueToken(BracketL, "")
+ case ']':
+ return s.makeValueToken(BracketR, "")
+ case '{':
+ return s.makeValueToken(BraceL, "")
+ case '}':
+ return s.makeValueToken(BraceR, "")
+ case '|':
+ return s.makeValueToken(Pipe, "")
+ case '#':
+ s.readComment()
+ return s.ReadToken()
+
+ case '_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z':
+ return s.readName()
+
+ case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ return s.readNumber()
+
+ case '"':
+ if len(s.Input) > s.start+2 && s.Input[s.start:s.start+3] == `"""` {
+ return s.readBlockString()
+ }
+
+ return s.readString()
+ }
+
+ s.end--
+ s.endRunes--
+
+ if r < 0x0020 && r != 0x0009 && r != 0x000a && r != 0x000d {
+ return s.makeError(`Cannot contain the invalid character "\u%04d"`, r)
+ }
+
+ if r == '\'' {
+ return s.makeError(`Unexpected single quote character ('), did you mean to use a double quote (")?`)
+ }
+
+ return s.makeError(`Cannot parse the unexpected character "%s".`, string(r))
+}
+
+// ws reads from body starting at startPosition until it finds a non-whitespace
+// or commented character, and updates the token end to include all whitespace
+func (s *Lexer) ws() {
+ for s.end < len(s.Input) {
+ switch s.Input[s.end] {
+ case '\t', ' ', ',':
+ s.end++
+ s.endRunes++
+ case '\n':
+ s.end++
+ s.endRunes++
+ s.line++
+ s.lineStartRunes = s.endRunes
+ case '\r':
+ s.end++
+ s.endRunes++
+ s.line++
+ s.lineStartRunes = s.endRunes
+ // skip the following newline if its there
+ if s.end < len(s.Input) && s.Input[s.end] == '\n' {
+ s.end++
+ s.endRunes++
+ }
+ // byte order mark, given ws is hot path we aren't relying on the unicode package here.
+ case 0xef:
+ if s.end+2 < len(s.Input) && s.Input[s.end+1] == 0xBB && s.Input[s.end+2] == 0xBF {
+ s.end += 3
+ s.endRunes++
+ } else {
+ return
+ }
+ default:
+ return
+ }
+ }
+}
+
+// readComment from the input
+//
+// #[\u0009\u0020-\uFFFF]*
+func (s *Lexer) readComment() (Token, *gqlerror.Error) {
+ for s.end < len(s.Input) {
+ r, w := s.peek()
+
+ // SourceCharacter but not LineTerminator
+ if r > 0x001f || r == '\t' {
+ s.end += w
+ s.endRunes++
+ } else {
+ break
+ }
+ }
+
+ return s.makeToken(Comment)
+}
+
+// readNumber from the input, either a float
+// or an int depending on whether a decimal point appears.
+//
+// Int: -?(0|[1-9][0-9]*)
+// Float: -?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)?
+func (s *Lexer) readNumber() (Token, *gqlerror.Error) {
+ float := false
+
+ // backup to the first digit
+ s.end--
+ s.endRunes--
+
+ s.acceptByte('-')
+
+ if s.acceptByte('0') {
+ if consumed := s.acceptDigits(); consumed != 0 {
+ s.end -= consumed
+ s.endRunes -= consumed
+ return s.makeError("Invalid number, unexpected digit after 0: %s.", s.describeNext())
+ }
+ } else {
+ if consumed := s.acceptDigits(); consumed == 0 {
+ return s.makeError("Invalid number, expected digit but got: %s.", s.describeNext())
+ }
+ }
+
+ if s.acceptByte('.') {
+ float = true
+
+ if consumed := s.acceptDigits(); consumed == 0 {
+ return s.makeError("Invalid number, expected digit but got: %s.", s.describeNext())
+ }
+ }
+
+ if s.acceptByte('e', 'E') {
+ float = true
+
+ s.acceptByte('-', '+')
+
+ if consumed := s.acceptDigits(); consumed == 0 {
+ return s.makeError("Invalid number, expected digit but got: %s.", s.describeNext())
+ }
+ }
+
+ if float {
+ return s.makeToken(Float)
+ } else {
+ return s.makeToken(Int)
+ }
+}
+
+// acceptByte if it matches any of given bytes, returning true if it found anything
+func (s *Lexer) acceptByte(bytes ...uint8) bool {
+ if s.end >= len(s.Input) {
+ return false
+ }
+
+ for _, accepted := range bytes {
+ if s.Input[s.end] == accepted {
+ s.end++
+ s.endRunes++
+ return true
+ }
+ }
+ return false
+}
+
+// acceptDigits from the input, returning the number of digits it found
+func (s *Lexer) acceptDigits() int {
+ consumed := 0
+ for s.end < len(s.Input) && s.Input[s.end] >= '0' && s.Input[s.end] <= '9' {
+ s.end++
+ s.endRunes++
+ consumed++
+ }
+
+ return consumed
+}
+
+// describeNext peeks at the input and returns a human readable string. This should will alloc
+// and should only be used in errors
+func (s *Lexer) describeNext() string {
+ if s.end < len(s.Input) {
+ return `"` + string(s.Input[s.end]) + `"`
+ }
+ return "<EOF>"
+}
+
+// readString from the input
+//
+// "([^"\\\u000A\u000D]|(\\(u[0-9a-fA-F]{4}|["\\/bfnrt])))*"
+func (s *Lexer) readString() (Token, *gqlerror.Error) {
+ inputLen := len(s.Input)
+
+ // this buffer is lazily created only if there are escape characters.
+ var buf *bytes.Buffer
+
+ // skip the opening quote
+ s.start++
+ s.startRunes++
+
+ for s.end < inputLen {
+ r := s.Input[s.end]
+ if r == '\n' || r == '\r' {
+ break
+ }
+ if r < 0x0020 && r != '\t' {
+ return s.makeError(`Invalid character within String: "\u%04d".`, r)
+ }
+ switch r {
+ default:
+ var char = rune(r)
+ var w = 1
+
+ // skip unicode overhead if we are in the ascii range
+ if r >= 127 {
+ char, w = utf8.DecodeRuneInString(s.Input[s.end:])
+ }
+ s.end += w
+ s.endRunes++
+
+ if buf != nil {
+ buf.WriteRune(char)
+ }
+
+ case '"':
+ t, err := s.makeToken(String)
+ // the token should not include the quotes in its value, but should cover them in its position
+ t.Pos.Start--
+ t.Pos.End++
+
+ if buf != nil {
+ t.Value = buf.String()
+ }
+
+ // skip the close quote
+ s.end++
+ s.endRunes++
+
+ return t, err
+
+ case '\\':
+ if s.end+1 >= inputLen {
+ s.end++
+ s.endRunes++
+ return s.makeError(`Invalid character escape sequence.`)
+ }
+
+ if buf == nil {
+ buf = bytes.NewBufferString(s.Input[s.start:s.end])
+ }
+
+ escape := s.Input[s.end+1]
+
+ if escape == 'u' {
+ if s.end+6 >= inputLen {
+ s.end++
+ s.endRunes++
+ return s.makeError("Invalid character escape sequence: \\%s.", s.Input[s.end:])
+ }
+
+ r, ok := unhex(s.Input[s.end+2 : s.end+6])
+ if !ok {
+ s.end++
+ s.endRunes++
+ return s.makeError("Invalid character escape sequence: \\%s.", s.Input[s.end:s.end+5])
+ }
+ buf.WriteRune(r)
+ s.end += 6
+ s.endRunes += 6
+ } else {
+ switch escape {
+ case '"', '/', '\\':
+ buf.WriteByte(escape)
+ case 'b':
+ buf.WriteByte('\b')
+ case 'f':
+ buf.WriteByte('\f')
+ case 'n':
+ buf.WriteByte('\n')
+ case 'r':
+ buf.WriteByte('\r')
+ case 't':
+ buf.WriteByte('\t')
+ default:
+ s.end += 1
+ s.endRunes += 1
+ return s.makeError("Invalid character escape sequence: \\%s.", string(escape))
+ }
+ s.end += 2
+ s.endRunes += 2
+ }
+ }
+ }
+
+ return s.makeError("Unterminated string.")
+}
+
+// readBlockString from the input
+//
+// """("?"?(\\"""|\\(?!=""")|[^"\\]))*"""
+func (s *Lexer) readBlockString() (Token, *gqlerror.Error) {
+ inputLen := len(s.Input)
+
+ var buf bytes.Buffer
+
+ // skip the opening quote
+ s.start += 3
+ s.startRunes += 3
+ s.end += 2
+ s.endRunes += 2
+
+ for s.end < inputLen {
+ r := s.Input[s.end]
+
+ // Closing triple quote (""")
+ if r == '"' && s.end+3 <= inputLen && s.Input[s.end:s.end+3] == `"""` {
+ t, err := s.makeValueToken(BlockString, blockStringValue(buf.String()))
+
+ // the token should not include the quotes in its value, but should cover them in its position
+ t.Pos.Start -= 3
+ t.Pos.End += 3
+
+ // skip the close quote
+ s.end += 3
+ s.endRunes += 3
+
+ return t, err
+ }
+
+ // SourceCharacter
+ if r < 0x0020 && r != '\t' && r != '\n' && r != '\r' {
+ return s.makeError(`Invalid character within String: "\u%04d".`, r)
+ }
+
+ if r == '\\' && s.end+4 <= inputLen && s.Input[s.end:s.end+4] == `\"""` {
+ buf.WriteString(`"""`)
+ s.end += 4
+ s.endRunes += 4
+ } else if r == '\r' {
+ if s.end+1 <= inputLen && s.Input[s.end+1] == '\n' {
+ s.end++
+ s.endRunes++
+ }
+
+ buf.WriteByte('\n')
+ s.end++
+ s.endRunes++
+ } else {
+ var char = rune(r)
+ var w = 1
+
+ // skip unicode overhead if we are in the ascii range
+ if r >= 127 {
+ char, w = utf8.DecodeRuneInString(s.Input[s.end:])
+ }
+ s.end += w
+ s.endRunes++
+ buf.WriteRune(char)
+ }
+ }
+
+ return s.makeError("Unterminated string.")
+}
+
+func unhex(b string) (v rune, ok bool) {
+ for _, c := range b {
+ v <<= 4
+ switch {
+ case '0' <= c && c <= '9':
+ v |= c - '0'
+ case 'a' <= c && c <= 'f':
+ v |= c - 'a' + 10
+ case 'A' <= c && c <= 'F':
+ v |= c - 'A' + 10
+ default:
+ return 0, false
+ }
+ }
+
+ return v, true
+}
+
+// readName from the input
+//
+// [_A-Za-z][_0-9A-Za-z]*
+func (s *Lexer) readName() (Token, *gqlerror.Error) {
+ for s.end < len(s.Input) {
+ r, w := s.peek()
+
+ if (r >= '0' && r <= '9') || (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') || r == '_' {
+ s.end += w
+ s.endRunes++
+ } else {
+ break
+ }
+ }
+
+ return s.makeToken(Name)
+}
diff --git a/vendor/github.com/vektah/gqlparser/lexer/lexer_test.yml b/vendor/github.com/vektah/gqlparser/lexer/lexer_test.yml
new file mode 100644
index 00000000..e2c26696
--- /dev/null
+++ b/vendor/github.com/vektah/gqlparser/lexer/lexer_test.yml
@@ -0,0 +1,672 @@
+encoding:
+ - name: disallows uncommon control characters
+ input: "\u0007"
+ error:
+ message: 'Cannot contain the invalid character "\u0007"'
+ locations: [{line: 1, column: 1}]
+
+ - name: accepts BOM header
+ input: "\uFEFF foo"
+ tokens:
+ -
+ kind: NAME
+ start: 2
+ end: 5
+ value: 'foo'
+
+simple tokens:
+ - name: records line and column
+ input: "\n \r\n \r foo\n"
+ tokens:
+ -
+ kind: NAME
+ start: 8
+ end: 11
+ line: 4
+ column: 3
+ value: 'foo'
+
+ - name: skips whitespace
+ input: "\n\n foo\n\n\n"
+ tokens:
+ -
+ kind: NAME
+ start: 6
+ end: 9
+ value: 'foo'
+
+ - name: skips comments
+ input: "\n #comment\n foo#comment\n"
+ tokens:
+ -
+ kind: NAME
+ start: 18
+ end: 21
+ value: 'foo'
+
+ - name: skips commas
+ input: ",,,foo,,,"
+ tokens:
+ -
+ kind: NAME
+ start: 3
+ end: 6
+ value: 'foo'
+
+ - name: errors respect whitespace
+ input: "\n\n ?\n\n\n"
+ error:
+ message: 'Cannot parse the unexpected character "?".'
+ locations: [{line: 3, column: 5}]
+ string: |
+ Syntax Error: Cannot parse the unexpected character "?".
+ GraphQL request (3:5)
+ 2:
+ 3: ?
+ ^
+ 4:
+
+ - name: lex reports useful information for dashes in names
+ input: "a-b"
+ error:
+ message: 'Invalid number, expected digit but got: "b".'
+ locations: [{ line: 1, column: 3 }]
+ tokens:
+ -
+ kind: Name
+ start: 0
+ end: 1
+ value: a
+
+lexes strings:
+ - name: basic
+ input: '"simple"'
+ tokens:
+ -
+ kind: STRING
+ start: 0
+ end: 8
+ value: 'simple'
+
+ - name: whitespace
+ input: '" white space "'
+ tokens:
+ -
+ kind: STRING
+ start: 0
+ end: 15
+ value: ' white space '
+
+ - name: quote
+ input: '"quote \""'
+ tokens:
+ -
+ kind: STRING
+ start: 0
+ end: 10
+ value: 'quote "'
+
+ - name: escaped
+ input: '"escaped \n\r\b\t\f"'
+ tokens:
+ -
+ kind: STRING
+ start: 0
+ end: 20
+ value: "escaped \n\r\b\t\f"
+
+ - name: slashes
+ input: '"slashes \\ \/"'
+ tokens:
+ -
+ kind: STRING
+ start: 0
+ end: 15
+ value: 'slashes \ /'
+
+ - name: unicode
+ input: '"unicode \u1234\u5678\u90AB\uCDEF"'
+ tokens:
+ -
+ kind: STRING
+ start: 0
+ end: 34
+ value: "unicode \u1234\u5678\u90AB\uCDEF"
+
+lex reports useful string errors:
+ - name: unterminated
+ input: '"'
+ error:
+ message: "Unterminated string."
+ locations: [{ line: 1, column: 2 }]
+
+ - name: no end quote
+ input: '"no end quote'
+ error:
+ message: 'Unterminated string.'
+ locations: [{ line: 1, column: 14 }]
+
+ - name: single quotes
+ input: "'single quotes'"
+ error:
+ message: "Unexpected single quote character ('), did you mean to use a double quote (\")?"
+ locations: [{ line: 1, column: 1 }]
+
+ - name: control characters
+ input: "\"contains unescaped \u0007 control char\""
+ error:
+ message: 'Invalid character within String: "\u0007".'
+ locations: [{ line: 1, column: 21 }]
+
+ - name: null byte
+ input: "\"null-byte is not \u0000 end of file\""
+ error:
+ message: 'Invalid character within String: "\u0000".'
+ locations: [{ line: 1, column: 19 }]
+
+ - name: unterminated newline
+ input: "\"multi\nline\""
+ error:
+ message: 'Unterminated string.'
+ locations: [{line: 1, column: 7 }]
+
+ - name: unterminated carriage return
+ input: "\"multi\rline\""
+ error:
+ message: 'Unterminated string.'
+ locations: [{ line: 1, column: 7 }]
+
+ - name: bad escape character
+ input: '"bad \z esc"'
+ error:
+ message: 'Invalid character escape sequence: \z.'
+ locations: [{ line: 1, column: 7 }]
+
+ - name: hex escape sequence
+ input: '"bad \x esc"'
+ error:
+ message: 'Invalid character escape sequence: \x.'
+ locations: [{ line: 1, column: 7 }]
+
+ - name: short escape sequence
+ input: '"bad \u1 esc"'
+ error:
+ message: 'Invalid character escape sequence: \u1 es.'
+ locations: [{ line: 1, column: 7 }]
+
+ - name: invalid escape sequence 1
+ input: '"bad \u0XX1 esc"'
+ error:
+ message: 'Invalid character escape sequence: \u0XX1.'
+ locations: [{ line: 1, column: 7 }]
+
+ - name: invalid escape sequence 2
+ input: '"bad \uXXXX esc"'
+ error:
+ message: 'Invalid character escape sequence: \uXXXX.'
+ locations: [{ line: 1, column: 7 }]
+
+ - name: invalid escape sequence 3
+ input: '"bad \uFXXX esc"'
+ error:
+ message: 'Invalid character escape sequence: \uFXXX.'
+ locations: [{ line: 1, column: 7 }]
+
+ - name: invalid character escape sequence
+ input: '"bad \uXXXF esc"'
+ error:
+ message: 'Invalid character escape sequence: \uXXXF.'
+ locations: [{ line: 1, column: 7 }]
+
+lexes block strings:
+ - name: simple
+ input: '"""simple"""'
+ tokens:
+ -
+ kind: BLOCK_STRING
+ start: 0
+ end: 12
+ value: 'simple'
+
+ - name: white space
+ input: '""" white space """'
+ tokens:
+ -
+ kind: BLOCK_STRING
+ start: 0
+ end: 19
+ value: ' white space '
+
+ - name: contains quote
+ input: '"""contains " quote"""'
+ tokens:
+ -
+ kind: BLOCK_STRING
+ start: 0
+ end: 22
+ value: 'contains " quote'
+
+ - name: contains triplequote
+ input: "\"\"\"contains \\\"\"\" triplequote\"\"\""
+ tokens:
+ -
+ kind: BLOCK_STRING
+ start: 0
+ end: 31
+ value: 'contains """ triplequote'
+
+ - name: multi line
+ input: "\"\"\"multi\nline\"\"\""
+ tokens:
+ -
+ kind: BLOCK_STRING
+ start: 0
+ end: 16
+ value: "multi\nline"
+
+ - name: multi line normalized
+ input: "\"\"\"multi\rline\r\nnormalized\"\"\""
+ tokens:
+ -
+ kind: BLOCK_STRING
+ start: 0
+ end: 28
+ value: "multi\nline\nnormalized"
+
+ - name: unescaped
+ input: '"""unescaped \n\r\b\t\f\u1234"""'
+ tokens:
+ -
+ kind: BLOCK_STRING
+ start: 0
+ end: 32
+ value: 'unescaped \n\r\b\t\f\u1234'
+
+ - name: slashes
+ input: '"""slashes \\ \/"""'
+ tokens:
+ -
+ kind: BLOCK_STRING
+ start: 0
+ end: 19
+ value: 'slashes \\ \/'
+
+ - name: multiple lines
+ input: |
+ """
+
+ spans
+ multiple
+ lines
+
+ """
+ tokens:
+ -
+ kind: BLOCK_STRING
+ start: 0
+ end: 36
+ value: "spans\n multiple\n lines"
+
+lex reports useful block string errors:
+ - name: unterminated string
+ input: '"""'
+ error:
+ message: "Unterminated string."
+ locations: [{ line: 1, column: 4 }]
+
+ - name: unescaped control characters
+ input: "\"\"\"contains unescaped \u0007 control char\"\"\""
+ error:
+ message: 'Invalid character within String: "\u0007".'
+ locations: [{ line: 1, column: 23 }]
+
+ - name: null byte
+ input: "\"\"\"null-byte is not \u0000 end of file\"\"\""
+ error:
+ message: 'Invalid character within String: "\u0000".'
+ locations: [{ line: 1, column: 21 }]
+
+lexes numbers:
+ - name: integer
+ input: "4"
+ tokens:
+ -
+ kind: INT
+ start: 0
+ end: 1
+ value: '4'
+
+ - name: float
+ input: "4.123"
+ tokens:
+ -
+ kind: FLOAT
+ start: 0
+ end: 5
+ value: '4.123'
+
+ - name: negative
+ input: "-4"
+ tokens:
+ -
+ kind: INT
+ start: 0
+ end: 2
+ value: '-4'
+
+ - name: nine
+ input: "9"
+ tokens:
+ -
+ kind: INT
+ start: 0
+ end: 1
+ value: '9'
+
+ - name: zero
+ input: "0"
+ tokens:
+ -
+ kind: INT
+ start: 0
+ end: 1
+ value: '0'
+
+ - name: negative float
+ input: "-4.123"
+ tokens:
+ -
+ kind: FLOAT
+ start: 0
+ end: 6
+ value: '-4.123'
+
+ - name: float leading zero
+ input: "0.123"
+ tokens:
+ -
+ kind: FLOAT
+ start: 0
+ end: 5
+ value: '0.123'
+
+ - name: exponent whole
+ input: "123e4"
+ tokens:
+ -
+ kind: FLOAT
+ start: 0
+ end: 5
+ value: '123e4'
+
+ - name: exponent uppercase
+ input: "123E4"
+ tokens:
+ -
+ kind: FLOAT
+ start: 0
+ end: 5
+ value: '123E4'
+
+ - name: exponent negative power
+ input: "123e-4"
+ tokens:
+ -
+ kind: FLOAT
+ start: 0
+ end: 6
+ value: '123e-4'
+
+ - name: exponent positive power
+ input: "123e+4"
+ tokens:
+ -
+ kind: FLOAT
+ start: 0
+ end: 6
+ value: '123e+4'
+
+ - name: exponent negative base
+ input: "-1.123e4"
+ tokens:
+ -
+ kind: FLOAT
+ start: 0
+ end: 8
+ value: '-1.123e4'
+
+ - name: exponent negative base upper
+ input: "-1.123E4"
+ tokens:
+ -
+ kind: FLOAT
+ start: 0
+ end: 8
+ value: '-1.123E4'
+
+ - name: exponent negative base negative power
+ input: "-1.123e-4"
+ tokens:
+ -
+ kind: FLOAT
+ start: 0
+ end: 9
+ value: '-1.123e-4'
+
+ - name: exponent negative base positive power
+ input: "-1.123e+4"
+ tokens:
+ -
+ kind: FLOAT
+ start: 0
+ end: 9
+ value: '-1.123e+4'
+
+ - name: exponent negative base large power
+ input: "-1.123e4567"
+ tokens:
+ -
+ kind: FLOAT
+ start: 0
+ end: 11
+ value: '-1.123e4567'
+
+lex reports useful number errors:
+ - name: zero
+ input: "00"
+ error:
+ message: 'Invalid number, unexpected digit after 0: "0".'
+ locations: [{ line: 1, column: 2 }]
+
+ - name: positive
+ input: "+1"
+ error:
+ message: 'Cannot parse the unexpected character "+".'
+ locations: [{ line: 1, column: 1 }]
+
+ - name: trailing dot
+ input: "1."
+ error:
+ message: 'Invalid number, expected digit but got: <EOF>.'
+ locations: [{ line: 1, column: 3 }]
+
+ - name: traililng dot exponent
+ input: "1.e1"
+ error:
+ message: 'Invalid number, expected digit but got: "e".'
+ locations: [{ line: 1, column: 3 }]
+
+ - name: missing leading zero
+ input: ".123"
+ error:
+ message: 'Cannot parse the unexpected character ".".'
+ locations: [{ line: 1, column: 1 }]
+
+ - name: characters
+ input: "1.A"
+ error:
+ message: 'Invalid number, expected digit but got: "A".'
+ locations: [{ line: 1, column: 3 }]
+
+ - name: negative characters
+ input: "-A"
+ error:
+ message: 'Invalid number, expected digit but got: "A".'
+ locations: [{ line: 1, column: 2 }]
+
+ - name: missing exponent
+ input: '1.0e'
+ error:
+ message: 'Invalid number, expected digit but got: <EOF>.'
+ locations: [{ line: 1, column: 5 }]
+
+ - name: character exponent
+ input: "1.0eA"
+ error:
+ message: 'Invalid number, expected digit but got: "A".'
+ locations: [{ line: 1, column: 5 }]
+
+lexes punctuation:
+ - name: bang
+ input: "!"
+ tokens:
+ -
+ kind: BANG
+ start: 0
+ end: 1
+ value: undefined
+
+ - name: dollar
+ input: "$"
+ tokens:
+ -
+ kind: DOLLAR
+ start: 0
+ end: 1
+ value: undefined
+
+ - name: open paren
+ input: "("
+ tokens:
+ -
+ kind: PAREN_L
+ start: 0
+ end: 1
+ value: undefined
+
+ - name: close paren
+ input: ")"
+ tokens:
+ -
+ kind: PAREN_R
+ start: 0
+ end: 1
+ value: undefined
+
+ - name: spread
+ input: "..."
+ tokens:
+ -
+ kind: SPREAD
+ start: 0
+ end: 3
+ value: undefined
+
+ - name: colon
+ input: ":"
+ tokens:
+ -
+ kind: COLON
+ start: 0
+ end: 1
+ value: undefined
+
+ - name: equals
+ input: "="
+ tokens:
+ -
+ kind: EQUALS
+ start: 0
+ end: 1
+ value: undefined
+
+ - name: at
+ input: "@"
+ tokens:
+ -
+ kind: AT
+ start: 0
+ end: 1
+ value: undefined
+
+ - name: open bracket
+ input: "["
+ tokens:
+ -
+ kind: BRACKET_L
+ start: 0
+ end: 1
+ value: undefined
+
+ - name: close bracket
+ input: "]"
+ tokens:
+ -
+ kind: BRACKET_R
+ start: 0
+ end: 1
+ value: undefined
+
+ - name: open brace
+ input: "{"
+ tokens:
+ -
+ kind: BRACE_L
+ start: 0
+ end: 1
+ value: undefined
+
+ - name: close brace
+ input: "}"
+ tokens:
+ -
+ kind: BRACE_R
+ start: 0
+ end: 1
+ value: undefined
+
+ - name: pipe
+ input: "|"
+ tokens:
+ -
+ kind: PIPE
+ start: 0
+ end: 1
+ value: undefined
+
+lex reports useful unknown character error:
+ - name: not a spread
+ input: ".."
+ error:
+ message: 'Cannot parse the unexpected character ".".'
+ locations: [{ line: 1, column: 1 }]
+
+ - name: question mark
+ input: "?"
+ error:
+ message: 'Cannot parse the unexpected character "?".'
+ message: 'Cannot parse the unexpected character "?".'
+ locations: [{ line: 1, column: 1 }]
+
+ - name: unicode 203
+ input: "\u203B"
+ error:
+ message: 'Cannot parse the unexpected character "â".'
+ locations: [{ line: 1, column: 1 }]
+
+ - name: unicode 200
+ input: "\u200b"
+ error:
+ message: 'Cannot parse the unexpected character "â".'
+ locations: [{ line: 1, column: 1 }]
+
diff --git a/vendor/github.com/vektah/gqlparser/lexer/token.go b/vendor/github.com/vektah/gqlparser/lexer/token.go
new file mode 100644
index 00000000..aef8b729
--- /dev/null
+++ b/vendor/github.com/vektah/gqlparser/lexer/token.go
@@ -0,0 +1,148 @@
+package lexer
+
+import (
+ "strconv"
+
+ "github.com/vektah/gqlparser/ast"
+)
+
+const (
+ Invalid Type = iota
+ EOF
+ Bang
+ Dollar
+ Amp
+ ParenL
+ ParenR
+ Spread
+ Colon
+ Equals
+ At
+ BracketL
+ BracketR
+ BraceL
+ BraceR
+ Pipe
+ Name
+ Int
+ Float
+ String
+ BlockString
+ Comment
+)
+
+func (t Type) Name() string {
+ switch t {
+ case Invalid:
+ return "Invalid"
+ case EOF:
+ return "EOF"
+ case Bang:
+ return "Bang"
+ case Dollar:
+ return "Dollar"
+ case Amp:
+ return "Amp"
+ case ParenL:
+ return "ParenL"
+ case ParenR:
+ return "ParenR"
+ case Spread:
+ return "Spread"
+ case Colon:
+ return "Colon"
+ case Equals:
+ return "Equals"
+ case At:
+ return "At"
+ case BracketL:
+ return "BracketL"
+ case BracketR:
+ return "BracketR"
+ case BraceL:
+ return "BraceL"
+ case BraceR:
+ return "BraceR"
+ case Pipe:
+ return "Pipe"
+ case Name:
+ return "Name"
+ case Int:
+ return "Int"
+ case Float:
+ return "Float"
+ case String:
+ return "String"
+ case BlockString:
+ return "BlockString"
+ case Comment:
+ return "Comment"
+ }
+ return "Unknown " + strconv.Itoa(int(t))
+}
+
+func (t Type) String() string {
+ switch t {
+ case Invalid:
+ return "<Invalid>"
+ case EOF:
+ return "<EOF>"
+ case Bang:
+ return "!"
+ case Dollar:
+ return "$"
+ case Amp:
+ return "&"
+ case ParenL:
+ return "("
+ case ParenR:
+ return ")"
+ case Spread:
+ return "..."
+ case Colon:
+ return ":"
+ case Equals:
+ return "="
+ case At:
+ return "@"
+ case BracketL:
+ return "["
+ case BracketR:
+ return "]"
+ case BraceL:
+ return "{"
+ case BraceR:
+ return "}"
+ case Pipe:
+ return "|"
+ case Name:
+ return "Name"
+ case Int:
+ return "Int"
+ case Float:
+ return "Float"
+ case String:
+ return "String"
+ case BlockString:
+ return "BlockString"
+ case Comment:
+ return "Comment"
+ }
+ return "Unknown " + strconv.Itoa(int(t))
+}
+
+// Kind represents a type of token. The types are predefined as constants.
+type Type int
+
+type Token struct {
+ Kind Type // The token type.
+ Value string // The literal value consumed.
+ Pos ast.Position // The file and line this token was read from
+}
+
+func (t Token) String() string {
+ if t.Value != "" {
+ return t.Kind.String() + " " + strconv.Quote(t.Value)
+ }
+ return t.Kind.String()
+}