diff options
Diffstat (limited to 'vendor/github.com/graphql-go/graphql/language/lexer/lexer.go')
-rw-r--r-- | vendor/github.com/graphql-go/graphql/language/lexer/lexer.go | 656 |
1 files changed, 0 insertions, 656 deletions
diff --git a/vendor/github.com/graphql-go/graphql/language/lexer/lexer.go b/vendor/github.com/graphql-go/graphql/language/lexer/lexer.go deleted file mode 100644 index 62589f4e..00000000 --- a/vendor/github.com/graphql-go/graphql/language/lexer/lexer.go +++ /dev/null @@ -1,656 +0,0 @@ -package lexer - -import ( - "bytes" - "fmt" - "regexp" - "strings" - "unicode/utf8" - - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/language/source" -) - -const ( - EOF = iota + 1 - BANG - DOLLAR - PAREN_L - PAREN_R - SPREAD - COLON - EQUALS - AT - BRACKET_L - BRACKET_R - BRACE_L - PIPE - BRACE_R - NAME - INT - FLOAT - STRING - BLOCK_STRING -) - -var TokenKind map[int]int -var tokenDescription map[int]string - -func init() { - TokenKind = make(map[int]int) - tokenDescription = make(map[int]string) - TokenKind[EOF] = EOF - TokenKind[BANG] = BANG - TokenKind[DOLLAR] = DOLLAR - TokenKind[PAREN_L] = PAREN_L - TokenKind[PAREN_R] = PAREN_R - TokenKind[SPREAD] = SPREAD - TokenKind[COLON] = COLON - TokenKind[EQUALS] = EQUALS - TokenKind[AT] = AT - TokenKind[BRACKET_L] = BRACKET_L - TokenKind[BRACKET_R] = BRACKET_R - TokenKind[BRACE_L] = BRACE_L - TokenKind[PIPE] = PIPE - TokenKind[BRACE_R] = BRACE_R - TokenKind[NAME] = NAME - TokenKind[INT] = INT - TokenKind[FLOAT] = FLOAT - TokenKind[STRING] = STRING - TokenKind[BLOCK_STRING] = BLOCK_STRING - tokenDescription[TokenKind[EOF]] = "EOF" - tokenDescription[TokenKind[BANG]] = "!" - tokenDescription[TokenKind[DOLLAR]] = "$" - tokenDescription[TokenKind[PAREN_L]] = "(" - tokenDescription[TokenKind[PAREN_R]] = ")" - tokenDescription[TokenKind[SPREAD]] = "..." - tokenDescription[TokenKind[COLON]] = ":" - tokenDescription[TokenKind[EQUALS]] = "=" - tokenDescription[TokenKind[AT]] = "@" - tokenDescription[TokenKind[BRACKET_L]] = "[" - tokenDescription[TokenKind[BRACKET_R]] = "]" - tokenDescription[TokenKind[BRACE_L]] = "{" - tokenDescription[TokenKind[PIPE]] = "|" - tokenDescription[TokenKind[BRACE_R]] = "}" - tokenDescription[TokenKind[NAME]] = "Name" - tokenDescription[TokenKind[INT]] = "Int" - tokenDescription[TokenKind[FLOAT]] = "Float" - tokenDescription[TokenKind[STRING]] = "String" - tokenDescription[TokenKind[BLOCK_STRING]] = "BlockString" -} - -// Token is a representation of a lexed Token. Value only appears for non-punctuation -// tokens: NAME, INT, FLOAT, and STRING. -type Token struct { - Kind int - Start int - End int - Value string -} - -type Lexer func(resetPosition int) (Token, error) - -func Lex(s *source.Source) Lexer { - var prevPosition int - return func(resetPosition int) (Token, error) { - if resetPosition == 0 { - resetPosition = prevPosition - } - token, err := readToken(s, resetPosition) - if err != nil { - return token, err - } - prevPosition = token.End - return token, nil - } -} - -// Reads an alphanumeric + underscore name from the source. -// [_A-Za-z][_0-9A-Za-z]* -// position: Points to the byte position in the byte array -// runePosition: Points to the rune position in the byte array -func readName(source *source.Source, position, runePosition int) Token { - body := source.Body - bodyLength := len(body) - endByte := position + 1 - endRune := runePosition + 1 - for { - code, _ := runeAt(body, endByte) - if (endByte != bodyLength) && - (code == '_' || // _ - code >= '0' && code <= '9' || // 0-9 - code >= 'A' && code <= 'Z' || // A-Z - code >= 'a' && code <= 'z') { // a-z - endByte++ - endRune++ - continue - } else { - break - } - } - return makeToken(TokenKind[NAME], runePosition, endRune, string(body[position:endByte])) -} - -// Reads a number token from the source file, 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 readNumber(s *source.Source, start int, firstCode rune, codeLength int) (Token, error) { - code := firstCode - body := s.Body - position := start - isFloat := false - if code == '-' { // - - position += codeLength - code, codeLength = runeAt(body, position) - } - if code == '0' { // 0 - position += codeLength - code, codeLength = runeAt(body, position) - if code >= '0' && code <= '9' { - description := fmt.Sprintf("Invalid number, unexpected digit after 0: %v.", printCharCode(code)) - return Token{}, gqlerrors.NewSyntaxError(s, position, description) - } - } else { - p, err := readDigits(s, position, code, codeLength) - if err != nil { - return Token{}, err - } - position = p - code, codeLength = runeAt(body, position) - } - if code == '.' { // . - isFloat = true - position += codeLength - code, codeLength = runeAt(body, position) - p, err := readDigits(s, position, code, codeLength) - if err != nil { - return Token{}, err - } - position = p - code, codeLength = runeAt(body, position) - } - if code == 'E' || code == 'e' { // E e - isFloat = true - position += codeLength - code, codeLength = runeAt(body, position) - if code == '+' || code == '-' { // + - - position += codeLength - code, codeLength = runeAt(body, position) - } - p, err := readDigits(s, position, code, codeLength) - if err != nil { - return Token{}, err - } - position = p - } - kind := TokenKind[INT] - if isFloat { - kind = TokenKind[FLOAT] - } - - return makeToken(kind, start, position, string(body[start:position])), nil -} - -// Returns the new position in the source after reading digits. -func readDigits(s *source.Source, start int, firstCode rune, codeLength int) (int, error) { - body := s.Body - position := start - code := firstCode - if code >= '0' && code <= '9' { // 0 - 9 - for { - if code >= '0' && code <= '9' { // 0 - 9 - position += codeLength - code, codeLength = runeAt(body, position) - continue - } else { - break - } - } - return position, nil - } - var description string - description = fmt.Sprintf("Invalid number, expected digit but got: %v.", printCharCode(code)) - return position, gqlerrors.NewSyntaxError(s, position, description) -} - -func readString(s *source.Source, start int) (Token, error) { - body := s.Body - position := start + 1 - runePosition := start + 1 - chunkStart := position - var code rune - var n int - var valueBuffer bytes.Buffer - for { - code, n = runeAt(body, position) - if position < len(body) && - // not LineTerminator - code != 0x000A && code != 0x000D && - // not Quote (") - code != '"' { - - // SourceCharacter - if code < 0x0020 && code != 0x0009 { - return Token{}, gqlerrors.NewSyntaxError(s, runePosition, fmt.Sprintf(`Invalid character within String: %v.`, printCharCode(code))) - } - position += n - runePosition++ - if code == '\\' { // \ - valueBuffer.Write(body[chunkStart : position-1]) - code, n = runeAt(body, position) - switch code { - case '"': - valueBuffer.WriteRune('"') - break - case '/': - valueBuffer.WriteRune('/') - break - case '\\': - valueBuffer.WriteRune('\\') - break - case 'b': - valueBuffer.WriteRune('\b') - break - case 'f': - valueBuffer.WriteRune('\f') - break - case 'n': - valueBuffer.WriteRune('\n') - break - case 'r': - valueBuffer.WriteRune('\r') - break - case 't': - valueBuffer.WriteRune('\t') - break - case 'u': - // Check if there are at least 4 bytes available - if len(body) <= position+4 { - return Token{}, gqlerrors.NewSyntaxError(s, runePosition, - fmt.Sprintf("Invalid character escape sequence: "+ - "\\u%v", string(body[position+1:]))) - } - charCode := uniCharCode( - rune(body[position+1]), - rune(body[position+2]), - rune(body[position+3]), - rune(body[position+4]), - ) - if charCode < 0 { - return Token{}, gqlerrors.NewSyntaxError(s, runePosition, - fmt.Sprintf("Invalid character escape sequence: "+ - "\\u%v", string(body[position+1:position+5]))) - } - valueBuffer.WriteRune(charCode) - position += 4 - runePosition += 4 - break - default: - return Token{}, gqlerrors.NewSyntaxError(s, runePosition, - fmt.Sprintf(`Invalid character escape sequence: \\%c.`, code)) - } - position += n - runePosition++ - chunkStart = position - } - continue - } else { - break - } - } - if code != '"' { // quote (") - return Token{}, gqlerrors.NewSyntaxError(s, runePosition, "Unterminated string.") - } - stringContent := body[chunkStart:position] - valueBuffer.Write(stringContent) - value := valueBuffer.String() - return makeToken(TokenKind[STRING], start, position+1, value), nil -} - -// readBlockString reads a block string token from the source file. -// -// """("?"?(\\"""|\\(?!=""")|[^"\\]))*""" -func readBlockString(s *source.Source, start int) (Token, error) { - body := s.Body - position := start + 3 - runePosition := start + 3 - chunkStart := position - var valueBuffer bytes.Buffer - - for { - // Stop if we've reached the end of the buffer - if position >= len(body) { - break - } - - code, n := runeAt(body, position) - - // Closing Triple-Quote (""") - if code == '"' { - x, _ := runeAt(body, position+1) - y, _ := runeAt(body, position+2) - if x == '"' && y == '"' { - stringContent := body[chunkStart:position] - valueBuffer.Write(stringContent) - value := blockStringValue(valueBuffer.String()) - return makeToken(TokenKind[BLOCK_STRING], start, position+3, value), nil - } - } - - // SourceCharacter - if code < 0x0020 && - code != 0x0009 && - code != 0x000a && - code != 0x000d { - return Token{}, gqlerrors.NewSyntaxError(s, runePosition, fmt.Sprintf(`Invalid character within String: %v.`, printCharCode(code))) - } - - // Escape Triple-Quote (\""") - if code == '\\' { // \ - x, _ := runeAt(body, position+1) - y, _ := runeAt(body, position+2) - z, _ := runeAt(body, position+3) - if x == '"' && y == '"' && z == '"' { - stringContent := append(body[chunkStart:position], []byte(`"""`)...) - valueBuffer.Write(stringContent) - position += 4 // account for `"""` characters - runePosition += 4 // " " " " - chunkStart = position - continue - } - } - - position += n - runePosition++ - } - - return Token{}, gqlerrors.NewSyntaxError(s, runePosition, "Unterminated string.") -} - -var splitLinesRegex = regexp.MustCompile("\r\n|[\n\r]") - -// This implements the GraphQL spec's BlockStringValue() static algorithm. -// -// 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. -// -// Spec: http://facebook.github.io/graphql/draft/#BlockStringValue() -// Heavily borrows from: https://github.com/graphql/graphql-js/blob/8e0c599ceccfa8c40d6edf3b72ee2a71490b10e0/src/language/blockStringValue.js -func blockStringValue(in string) string { - // Expand a block string's raw value into independent lines. - lines := splitLinesRegex.Split(in, -1) - - // Remove common indentation from all lines but first - commonIndent := -1 - for i := 1; i < len(lines); i++ { - line := lines[i] - indent := leadingWhitespaceLen(line) - if indent < len(line) && (commonIndent == -1 || indent < commonIndent) { - commonIndent = indent - if commonIndent == 0 { - break - } - } - } - if commonIndent > 0 { - for i, line := range lines { - if commonIndent > len(line) { - continue - } - lines[i] = line[commonIndent:] - } - } - - // Remove leading blank lines. - for { - if isBlank := lineIsBlank(lines[0]); !isBlank { - break - } - lines = lines[1:] - } - - // Remove trailing blank lines. - for { - i := len(lines) - 1 - if isBlank := lineIsBlank(lines[i]); !isBlank { - break - } - lines = append(lines[:i], lines[i+1:]...) - } - - // Return a string of the lines joined with U+000A. - return strings.Join(lines, "\n") -} - -// leadingWhitespaceLen returns count of whitespace characters on given line. -func leadingWhitespaceLen(in string) (n int) { - for _, ch := range in { - if ch == ' ' || ch == '\t' { - n++ - } else { - break - } - } - return -} - -// lineIsBlank returns true when given line has no content. -func lineIsBlank(in string) bool { - return leadingWhitespaceLen(in) == len(in) -} - -// Converts four hexidecimal chars to the integer that the -// string represents. For example, uniCharCode('0','0','0','f') -// will return 15, and uniCharCode('0','0','f','f') returns 255. -// Returns a negative number on error, if a char was invalid. -// This is implemented by noting that char2hex() returns -1 on error, -// which means the result of ORing the char2hex() will also be negative. -func uniCharCode(a, b, c, d rune) rune { - return rune(char2hex(a)<<12 | char2hex(b)<<8 | char2hex(c)<<4 | char2hex(d)) -} - -// Converts a hex character to its integer value. -// '0' becomes 0, '9' becomes 9 -// 'A' becomes 10, 'F' becomes 15 -// 'a' becomes 10, 'f' becomes 15 -// Returns -1 on error. -func char2hex(a rune) int { - if a >= 48 && a <= 57 { // 0-9 - return int(a) - 48 - } else if a >= 65 && a <= 70 { // A-F - return int(a) - 55 - } else if a >= 97 && a <= 102 { - // a-f - return int(a) - 87 - } - return -1 -} - -func makeToken(kind int, start int, end int, value string) Token { - return Token{Kind: kind, Start: start, End: end, Value: value} -} - -func printCharCode(code rune) string { - // NaN/undefined represents access beyond the end of the file. - if code < 0 { - return "<EOF>" - } - // print as ASCII for printable range - if code >= 0x0020 && code < 0x007F { - return fmt.Sprintf(`"%c"`, code) - } - // Otherwise print the escaped form. e.g. `"\\u0007"` - return fmt.Sprintf(`"\\u%04X"`, code) -} - -func readToken(s *source.Source, fromPosition int) (Token, error) { - body := s.Body - bodyLength := len(body) - position, runePosition := positionAfterWhitespace(body, fromPosition) - if position >= bodyLength { - return makeToken(TokenKind[EOF], position, position, ""), nil - } - code, codeLength := runeAt(body, position) - - // SourceCharacter - if code < 0x0020 && code != 0x0009 && code != 0x000A && code != 0x000D { - return Token{}, gqlerrors.NewSyntaxError(s, runePosition, fmt.Sprintf(`Invalid character %v`, printCharCode(code))) - } - - switch code { - // ! - case '!': - return makeToken(TokenKind[BANG], position, position+1, ""), nil - // $ - case '$': - return makeToken(TokenKind[DOLLAR], position, position+1, ""), nil - // ( - case '(': - return makeToken(TokenKind[PAREN_L], position, position+1, ""), nil - // ) - case ')': - return makeToken(TokenKind[PAREN_R], position, position+1, ""), nil - // . - case '.': - next1, _ := runeAt(body, position+1) - next2, _ := runeAt(body, position+2) - if next1 == '.' && next2 == '.' { - return makeToken(TokenKind[SPREAD], position, position+3, ""), nil - } - break - // : - case ':': - return makeToken(TokenKind[COLON], position, position+1, ""), nil - // = - case '=': - return makeToken(TokenKind[EQUALS], position, position+1, ""), nil - // @ - case '@': - return makeToken(TokenKind[AT], position, position+1, ""), nil - // [ - case '[': - return makeToken(TokenKind[BRACKET_L], position, position+1, ""), nil - // ] - case ']': - return makeToken(TokenKind[BRACKET_R], position, position+1, ""), nil - // { - case '{': - return makeToken(TokenKind[BRACE_L], position, position+1, ""), nil - // | - case '|': - return makeToken(TokenKind[PIPE], position, position+1, ""), nil - // } - case '}': - return makeToken(TokenKind[BRACE_R], position, position+1, ""), nil - // A-Z - 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': - return readName(s, position, runePosition), nil - // _ - // a-z - 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': - return readName(s, position, runePosition), nil - // - - // 0-9 - case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - token, err := readNumber(s, position, code, codeLength) - if err != nil { - return token, err - } - return token, nil - // " - case '"': - var token Token - var err error - x, _ := runeAt(body, position+1) - y, _ := runeAt(body, position+2) - if x == '"' && y == '"' { - token, err = readBlockString(s, position) - } else { - token, err = readString(s, position) - } - return token, err - } - description := fmt.Sprintf("Unexpected character %v.", printCharCode(code)) - return Token{}, gqlerrors.NewSyntaxError(s, runePosition, description) -} - -// Gets the rune from the byte array at given byte position and it's width in bytes -func runeAt(body []byte, position int) (code rune, charWidth int) { - if len(body) <= position { - // <EOF> - return -1, utf8.RuneError - } - - c := body[position] - if c < utf8.RuneSelf { - return rune(c), 1 - } - - r, n := utf8.DecodeRune(body[position:]) - return r, n -} - -// Reads from body starting at startPosition until it finds a non-whitespace -// or commented character, then returns the position of that character for lexing. -// lexing. -// Returns both byte positions and rune position -func positionAfterWhitespace(body []byte, startPosition int) (position int, runePosition int) { - bodyLength := len(body) - position = startPosition - runePosition = startPosition - for { - if position < bodyLength { - code, n := runeAt(body, position) - - // Skip Ignored - if code == 0xFEFF || // BOM - // White Space - code == 0x0009 || // tab - code == 0x0020 || // space - // Line Terminator - code == 0x000A || // new line - code == 0x000D || // carriage return - // Comma - code == 0x002C { - position += n - runePosition++ - } else if code == 35 { // # - position += n - runePosition++ - for { - code, n := runeAt(body, position) - if position < bodyLength && - code != 0 && - // SourceCharacter but not LineTerminator - (code > 0x001F || code == 0x0009) && code != 0x000A && code != 0x000D { - position += n - runePosition++ - continue - } else { - break - } - } - } else { - break - } - continue - } else { - break - } - } - return position, runePosition -} - -func GetTokenDesc(token Token) string { - if token.Value == "" { - return GetTokenKindDesc(token.Kind) - } - return fmt.Sprintf("%s \"%s\"", GetTokenKindDesc(token.Kind), token.Value) -} - -func GetTokenKindDesc(kind int) string { - return tokenDescription[kind] -} |