예제 #1
0
파일: parser.go 프로젝트: cerisier/graphql
func parseObjectField(parser *Parser, isConst bool, fieldNames map[string]bool) (*ast.ObjectField, string, error) {
	start := parser.Token.Start
	name, err := parseName(parser)
	if err != nil {
		return nil, "", err
	}
	fieldName := name.Value
	if _, ok := fieldNames[fieldName]; ok {
		descp := fmt.Sprintf("Duplicate input object field %v.", fieldName)
		return nil, "", gqlerrors.NewSyntaxError(parser.Source, start, descp)
	}
	_, err = expect(parser, lexer.TokenKind[lexer.COLON])
	if err != nil {
		return nil, "", err
	}
	value, err := parseValueLiteral(parser, isConst)
	if err != nil {
		return nil, "", err
	}
	return ast.NewObjectField(&ast.ObjectField{
		Name:  name,
		Value: value,
		Loc:   loc(parser, start),
	}), fieldName, nil
}
예제 #2
0
파일: parser.go 프로젝트: cerisier/graphql
// If the next token is a keyword with the given value, return that token after
// advancing the parser. Otherwise, do not change the parser state and return false.
func expectKeyWord(parser *Parser, value string) (lexer.Token, error) {
	token := parser.Token
	if token.Kind == lexer.TokenKind[lexer.NAME] && token.Value == value {
		err := advance(parser)
		return token, err
	}
	descp := fmt.Sprintf("Expected \"%s\", found %s", value, lexer.GetTokenDesc(token))
	return token, gqlerrors.NewSyntaxError(parser.Source, token.Start, descp)
}
예제 #3
0
파일: parser.go 프로젝트: cerisier/graphql
// If the next token is of the given kind, return that token after advancing
// the parser. Otherwise, do not change the parser state and return false.
func expect(parser *Parser, kind int) (lexer.Token, error) {
	token := parser.Token
	if token.Kind == kind {
		err := advance(parser)
		return token, err
	}
	descp := fmt.Sprintf("Expected %s, found %s", lexer.GetTokenKindDesc(kind), lexer.GetTokenDesc(token))
	return token, gqlerrors.NewSyntaxError(parser.Source, token.Start, descp)
}
예제 #4
0
// 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
}
예제 #5
0
파일: parser.go 프로젝트: cerisier/graphql
// Helper function for creating an error when an unexpected lexed token
// is encountered.
func unexpected(parser *Parser, atToken lexer.Token) error {
	var token lexer.Token
	if (atToken == lexer.Token{}) {
		token = parser.Token
	} else {
		token = parser.Token
	}
	description := fmt.Sprintf("Unexpected %v", lexer.GetTokenDesc(token))
	return gqlerrors.NewSyntaxError(parser.Source, token.Start, description)
}
예제 #6
0
파일: lexer.go 프로젝트: cerisier/graphql
// 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) (Token, error) {
	code := firstCode
	body := s.Body
	position := start
	isFloat := false
	if code == 45 { // -
		position += 1
		code = charCodeAt(body, position)
	}
	if code == 48 { // 0
		position += 1
		code = charCodeAt(body, position)
		if code >= 48 && code <= 57 {
			description := fmt.Sprintf("Invalid number, unexpected digit after 0: \"%c\".", code)
			return Token{}, gqlerrors.NewSyntaxError(s, position, description)
		}
	} else {
		p, err := readDigits(s, position, code)
		if err != nil {
			return Token{}, err
		}
		position = p
		code = charCodeAt(body, position)
	}
	if code == 46 { // .
		isFloat = true
		position += 1
		code = charCodeAt(body, position)
		p, err := readDigits(s, position, code)
		if err != nil {
			return Token{}, err
		}
		position = p
		code = charCodeAt(body, position)
	}
	if code == 69 || code == 101 { // E e
		isFloat = true
		position += 1
		code = charCodeAt(body, position)
		if code == 43 || code == 45 { // + -
			position += 1
			code = charCodeAt(body, position)
		}
		p, err := readDigits(s, position, code)
		if err != nil {
			return Token{}, err
		}
		position = p
	}
	kind := TokenKind[INT]
	if isFloat {
		kind = TokenKind[FLOAT]
	}
	return makeToken(kind, start, position, body[start:position]), nil
}
예제 #7
0
// 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)
}
예제 #8
0
파일: lexer.go 프로젝트: cerisier/graphql
// Returns the new position in the source after reading digits.
func readDigits(s *source.Source, start int, firstCode rune) (int, error) {
	body := s.Body
	position := start
	code := firstCode
	if code >= 48 && code <= 57 { // 0 - 9
		for {
			if code >= 48 && code <= 57 { // 0 - 9
				position += 1
				code = charCodeAt(body, position)
				continue
			} else {
				break
			}
		}
		return position, nil
	}
	var description string
	if code != 0 {
		description = fmt.Sprintf("Invalid number, expected digit but got: \"%c\".", code)
	} else {
		description = fmt.Sprintf("Invalid number, expected digit but got: EOF.")
	}
	return position, gqlerrors.NewSyntaxError(s, position, description)
}
예제 #9
0
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 '"':
		token, err := readString(s, position)
		if err != nil {
			return token, err
		}
		return token, nil
	}
	description := fmt.Sprintf("Unexpected character %v.", printCharCode(code))
	return Token{}, gqlerrors.NewSyntaxError(s, runePosition, description)
}
예제 #10
0
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
}
예제 #11
0
파일: lexer.go 프로젝트: cerisier/graphql
func readToken(s *source.Source, fromPosition int) (Token, error) {
	body := s.Body
	bodyLength := len(body)
	position := positionAfterWhitespace(body, fromPosition)
	code := charCodeAt(body, position)
	if position >= bodyLength {
		return makeToken(TokenKind[EOF], position, position, ""), nil
	}
	switch code {
	// !
	case 33:
		return makeToken(TokenKind[BANG], position, position+1, ""), nil
	// $
	case 36:
		return makeToken(TokenKind[DOLLAR], position, position+1, ""), nil
	// (
	case 40:
		return makeToken(TokenKind[PAREN_L], position, position+1, ""), nil
	// )
	case 41:
		return makeToken(TokenKind[PAREN_R], position, position+1, ""), nil
	// .
	case 46:
		if charCodeAt(body, position+1) == 46 && charCodeAt(body, position+2) == 46 {
			return makeToken(TokenKind[SPREAD], position, position+3, ""), nil
		}
		break
	// :
	case 58:
		return makeToken(TokenKind[COLON], position, position+1, ""), nil
	// =
	case 61:
		return makeToken(TokenKind[EQUALS], position, position+1, ""), nil
	// @
	case 64:
		return makeToken(TokenKind[AT], position, position+1, ""), nil
	// [
	case 91:
		return makeToken(TokenKind[BRACKET_L], position, position+1, ""), nil
	// ]
	case 93:
		return makeToken(TokenKind[BRACKET_R], position, position+1, ""), nil
	// {
	case 123:
		return makeToken(TokenKind[BRACE_L], position, position+1, ""), nil
	// |
	case 124:
		return makeToken(TokenKind[PIPE], position, position+1, ""), nil
	// }
	case 125:
		return makeToken(TokenKind[BRACE_R], position, position+1, ""), nil
	// A-Z
	case 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
		82, 83, 84, 85, 86, 87, 88, 89, 90:
		return readName(s, position), nil
	// _
	// a-z
	case 95, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
		111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122:
		return readName(s, position), nil
	// -
	// 0-9
	case 45, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57:
		token, err := readNumber(s, position, code)
		if err != nil {
			return token, err
		} else {
			return token, nil
		}
	// "
	case 34:
		token, err := readString(s, position)
		if err != nil {
			return token, err
		}
		return token, nil
	}
	description := fmt.Sprintf("Unexpected character \"%c\".", code)
	return Token{}, gqlerrors.NewSyntaxError(s, position, description)
}
예제 #12
0
파일: lexer.go 프로젝트: cerisier/graphql
func readString(s *source.Source, start int) (Token, error) {
	body := s.Body
	position := start + 1
	chunkStart := position
	var code rune
	var value string
	for {
		code = charCodeAt(body, position)
		if position < len(body) && code != 34 && code != 10 && code != 13 && code != 0x2028 && code != 0x2029 {
			position += 1
			if code == 92 { // \
				value += body[chunkStart : position-1]
				code = charCodeAt(body, position)
				switch code {
				case 34:
					value += "\""
					break
				case 47:
					value += "\\/"
					break
				case 92:
					value += "\\"
					break
				case 98:
					value += "\b"
					break
				case 102:
					value += "\f"
					break
				case 110:
					value += "\n"
					break
				case 114:
					value += "\r"
					break
				case 116:
					value += "\t"
					break
				case 117:
					charCode := uniCharCode(
						charCodeAt(body, position+1),
						charCodeAt(body, position+2),
						charCodeAt(body, position+3),
						charCodeAt(body, position+4),
					)
					if charCode < 0 {
						return Token{}, gqlerrors.NewSyntaxError(s, position, "Bad character escape sequence.")
					}
					value += fmt.Sprintf("%c", charCode)
					position += 4
					break
				default:
					return Token{}, gqlerrors.NewSyntaxError(s, position, "Bad character escape sequence.")
				}
				position += 1
				chunkStart = position
			}
			continue
		} else {
			break
		}
	}
	if code != 34 {
		return Token{}, gqlerrors.NewSyntaxError(s, position, "Unterminated string.")
	}
	value += body[chunkStart:position]
	return makeToken(TokenKind[STRING], start, position+1, value), nil
}