private byte ReadDigits(byte firstCode)
        {
            if (!GraphQLConstants.IsDigit(firstCode))
            {
                throw new SyntaxException(this,
                                          "Invalid number, expected digit but got: " +
                                          $"`{(char)firstCode}` ({firstCode}).");
            }

            byte code = firstCode;

            while (true)
            {
                if (++_position >= _length)
                {
                    code = GraphQLConstants.Space;
                    break;
                }

                code = _graphQLData[_position];
                if (!GraphQLConstants.IsDigit(code))
                {
                    break;
                }
            }

            return(code);
        }
        private void ReadPunctuatorToken(byte code)
        {
            _start = _position;
            _end   = ++_position;
            _value = null;

            if (code == GraphQLConstants.Dot)
            {
                if (_graphQLData[_position] == GraphQLConstants.Dot &&
                    _graphQLData[_position + 1] == GraphQLConstants.Dot)
                {
                    _position += 2;
                    _end       = _position;
                    _kind      = TokenKind.Spread;
                }
                else
                {
                    _position--;
                    throw new SyntaxException(this,
                                              string.Format(CultureInfo.InvariantCulture,
                                                            LangResources.Reader_InvalidToken,
                                                            TokenKind.Spread));
                }
            }
            else
            {
                _kind = GraphQLConstants.PunctuatorKind(code);
            }
        }
        private void ReadNumberToken(byte firstCode)
        {
            int  start   = _position;
            byte code    = firstCode;
            var  isFloat = false;

            if (code == GraphQLConstants.Minus)
            {
                code = _graphQLData[++_position];
            }

            if (code == GraphQLConstants.Zero && !IsEndOfStream(_position + 1))
            {
                code = _graphQLData[++_position];
                if (GraphQLConstants.IsDigit(code))
                {
                    throw new SyntaxException(this,
                                              "Invalid number, unexpected digit after 0: " +
                                              $"`{(char)code}` ({code}).");
                }
            }
            else
            {
                code = ReadDigits(code);
            }

            if (code == GraphQLConstants.Dot)
            {
                isFloat      = true;
                _floatFormat = Language.FloatFormat.FixedPoint;
                code         = _graphQLData[++_position];
                code         = ReadDigits(code);
            }

            if ((code | 0x20) == GraphQLConstants.E)
            {
                isFloat      = true;
                _floatFormat = Language.FloatFormat.Exponential;
                code         = _graphQLData[++_position];
                if (code == GraphQLConstants.Plus ||
                    code == GraphQLConstants.Minus)
                {
                    code = _graphQLData[++_position];
                }
                ReadDigits(code);
            }

            _kind  = isFloat ? TokenKind.Float : TokenKind.Integer;
            _start = start;
            _end   = _position;
            _value = _graphQLData.Slice(start, _position - start);
        }
        private void ReadNameToken()
        {
            var start    = _position;
            var position = _position;

            while (++position < _length &&
                   GraphQLConstants.IsLetterOrDigitOrUnderscore(
                       _graphQLData[position]))
            {
            }

            _kind     = TokenKind.Name;
            _start    = start;
            _end      = position;
            _value    = _graphQLData.Slice(start, position - start);
            _position = position;
        }
        public bool Read()
        {
            _floatFormat = null;

            if (_position == 0)
            {
                SkipBoml();
            }

            SkipWhitespaces();
            UpdateColumn();

            if (IsEndOfStream())
            {
                _start = _position;
                _end   = _position;
                _kind  = TokenKind.EndOfFile;
                _value = null;
                return(false);
            }

            byte code = _graphQLData[_position];

            if (GraphQLConstants.IsPunctuator(code))
            {
                ReadPunctuatorToken(code);
                return(true);
            }

            if (GraphQLConstants.IsLetterOrUnderscore(code))
            {
                ReadNameToken();
                return(true);
            }

            if (GraphQLConstants.IsDigitOrMinus(code))
            {
                ReadNumberToken(code);
                return(true);
            }

            if (code == GraphQLConstants.Hash)
            {
                ReadCommentToken();
                return(true);
            }

            if (code == GraphQLConstants.Quote)
            {
                if (_length > _position + 2 &&
                    _graphQLData[_position + 1] == GraphQLConstants.Quote &&
                    _graphQLData[_position + 2] == GraphQLConstants.Quote)
                {
                    _position += 2;
                    ReadBlockStringToken();
                }
                else
                {
                    ReadStringValueToken();
                }
                return(true);
            }

            throw new SyntaxException(this,
                                      $"Unexpected character `{(char)code}` ({code}).");
        }
        private void ReadStringValueToken()
        {
            var start = _position;

            while (++_position < _length)
            {
                byte code = _graphQLData[_position];

                switch (code)
                {
                case GraphQLConstants.NewLine:
                case GraphQLConstants.Return:
                    return;

                // closing Quote (")
                case GraphQLConstants.Quote:
                    _kind  = TokenKind.String;
                    _start = start;
                    _end   = _position;
                    _value = _graphQLData.Slice(
                        start + 1,
                        _position - start - 1);
                    _position++;
                    return;

                case GraphQLConstants.Backslash:
                    code = _graphQLData[++_position];
                    if (!GraphQLConstants.IsValidEscapeCharacter(code))
                    {
                        throw new SyntaxException(this,
                                                  $"Invalid character escape sequence: \\{code}.");
                    }
                    break;

                // SourceCharacter
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 11:
                case 12:
                case 14:
                case 15:
                case 16:
                case 17:
                case 18:
                case 19:
                case 20:
                case 21:
                case 22:
                case 23:
                case 24:
                case 25:
                case 26:
                case 27:
                case 28:
                case 29:
                case 30:
                case 31:
                case 127:
                    throw new SyntaxException(this,
                                              $"Invalid character within String: {code}.");
                }
            }

            throw new SyntaxException(this, "Unterminated string.");
        }