Ejemplo n.º 1
0
        /// <summary>
        /// Lexes and parses a JSON object as a hash table in the specified string starting from the specified index.
        /// </summary>
        /// <typeparam name="TValue">The type of the values to deserialize.</typeparam>
        /// <param name="str">The string to lex and parse an object from.</param>
        /// <param name="len">The length of the string.</param>
        /// <param name="i">The index in the string to start lexing from. This value gets updated to the first index position after the JSON value, if found.</param>
        /// <param name="context">The parser context.</param>
        /// <param name="parseValue">The parser to use for values.</param>
        /// <returns>A hash table, if found; otherwise, a ParseException is thrown.</returns>
        /// <remarks>
        /// This method does not consume whitespace; the character at the specified start index in the string is expected to be the start of a valid JSON object.
        /// </remarks>
        internal static Dictionary <string, TValue> ParseAnyObject <TValue>(string str, int len, ref int i, ParserContext context, ParseStringFunc <TValue> parseValue)
        {
            Debug.Assert(str[i] == '{');

            //
            // CONSIDER: Add support for different representations of objects, e.g. ExpandoObject from the DLR. For
            //           now, we'll go with the most obvious choice and users can wrap the resulting value in case
            //           they want to support dynamic behavior.
            //

            var res = new Dictionary <string, TValue>();

            i++;

            SkipWhiteSpace(str, len, ref i); // NB: We *have* to skip trailing whitespace after the { token.

            if (i == len)
            {
                throw new ParseException("Unexpected end of stream when parsing object expecting an object body or '}' terminator.", i, ParseError.PrematureEndOfInput);
            }

            if (str[i] == '}')
            {
                i++;
                SkipWhiteSpace(str, len, ref i); // NB: We *have* to skip trailing whitespace after the } token.
                return(res);
            }

            while (i < len)
            {
                var key = ParseStringNonNull(str, len, ref i);

                SkipWhiteSpace(str, len, ref i); // NB: This skips leading whitespace before the : token; we can't rely on the trie to do it.

                if (i == len)
                {
                    throw new ParseException("Unexpected end of stream when parsing object expecting a ':' separator between a key name and a value.", i, ParseError.PrematureEndOfInput);
                }

                if (str[i] != ':')
                {
                    throw new ParseException(string.Format(CultureInfo.InvariantCulture, "Unexpected character '{0}' encountered when parsing object expecting a ':' token to separate key name and a value.", str[i]), i, ParseError.UnexpectedToken);
                }

                i++;

                SkipWhiteSpace(str, len, ref i); // NB: We *have* to skip trailing whitespace after the : token.

                //
                // NB: We're not using Add here in order to allow for duplicate keys. The last one in lexical order wins, which is
                //     consistent with behavior of other popular JSON frameworks and the behavior of our strongly typed object
                //     deserializer.
                //

                res[key] = parseValue(str, len, ref i, context);

                //
                // CONSIDER: Parsers for primitives don't trim trailing whitespace. We could change this and eliminate the need to
                //           skip whitespace here ourselves. This trimming is duplicate work if we're dealing with objects or
                //           arrays which already guarantee trimming trailing whitespace.
                //

                SkipWhiteSpace(str, len, ref i);

                if (i == len)
                {
                    throw new ParseException("Unexpected end of stream when parsing object.", i, ParseError.PrematureEndOfInput);
                }

                switch (str[i])
                {
                case ',':
                    i++;
                    SkipWhiteSpace(str, len, ref i);     // NB: We *have* to skip trailing whitespace after the , token.
                    break;

                case '}':
                    i++;
                    SkipWhiteSpace(str, len, ref i);     // NB: We *have* to skip trailing whitespace after the } token.
                    return(res);

                default:
                    throw new ParseException(string.Format(CultureInfo.InvariantCulture, "Unexpected character '{0}' encountered when parsing object expecting either ',' or '}}'.", str[i]), i, ParseError.UnexpectedToken);
                }
            }

            Debug.Assert(i == len);

            throw new ParseException("Unexpected end of stream when parsing object and expecting a key.", i, ParseError.PrematureEndOfInput);
        }
Ejemplo n.º 2
0
 /// <summary>
 /// Creates a new deserializer given the specified parser implementation.
 /// </summary>
 /// <param name="parseString">The parser to use to deserialize JSON payloads from string inputs.</param>
 public DeserializerBase(ParseStringFunc <T> parseString)
 {
     _parseString = parseString;
 }
Ejemplo n.º 3
0
 /// <summary>
 /// Creates a new deserializer given the specified parser implementations.
 /// </summary>
 /// <param name="parseString">The parser to use to deserialize JSON payloads from string inputs.</param>
 /// <param name="parseReader">The parser to use to deserialize JSON payloads from text reader inputs.</param>
 public DeserializerBase(ParseStringFunc <T> parseString, ParseReaderFunc <T> parseReader)
 {
     _parseString = parseString;
     _parseReader = parseReader;
 }
 /// <summary>
 /// Creates a new deserializer given the specified parser implementation.
 /// </summary>
 /// <param name="parseString">The parser to use to deserialize JSON payloads from string inputs.</param>
 public Deserializer(ParseStringFunc <T> parseString)
     : base(parseString)
 {
     _context = new ParserContext();
 }
 /// <summary>
 /// Creates a new deserializer given the specified parser implementation.
 /// </summary>
 /// <param name="parseString">The parser to use to deserialize JSON payloads from string inputs.</param>
 /// <param name="parseReader">The parser to use to deserialize JSON payloads from text reader inputs.</param>
 public Deserializer(ParseStringFunc <T> parseString, ParseReaderFunc <T> parseReader)
     : base(parseString, parseReader)
 {
     _context = new ParserContext();
 }
 /// <summary>
 /// Creates a new deserializer given the specified parser implementation.
 /// </summary>
 /// <param name="parseString">The parser to use to deserialize JSON payloads from string inputs.</param>
 public SafeDeserializer(ParseStringFunc <T> parseString)
     : base(parseString)
 {
     _contextPool = new ObjectPool <ParserContext>(() => new ParserContext());
 }