/// <summary> /// Get the next value. The value can be wrapped in quotes. /// The value can be empty. /// </summary> private string GetValue(TextParser parser) { char ch; do { ch = parser.Next(); } while (ch <= ' ' && ch != TextParser.EOF); switch (ch) { case TextParser.EOF: return null; case '"': case '\'': return parser.NextString(ch); case ',': parser.Back(); return ""; default: parser.Back(); return parser.NextTo(','); } }
/// <summary> /// Get the next char in the string, skipping whitespace /// and comments (slashslash and slashstar). /// </summary> /// <returns>A character, or 0 if there are no more characters.</returns> private char NextClean(TextParser parser) { Debug.Assert(parser != null); while (true) { char ch = parser.Next(); if (ch == '/') { switch (parser.Next()) { case '/' : { do { ch = parser.Next(); } while (ch != '\n' && ch != '\r' && ch != EOF); break; } case '*' : { while (true) { ch = parser.Next(); if (ch == EOF) throw new ParseException("Unclosed comment."); if (ch == '*') { if (parser.Next() == '/') break; parser.Back(); } } break; } default : { parser.Back(); return '/'; } } } else if (ch == EOF || ch > ' ') { return ch; } } }
private object ParseArray(TextParser parser) { Debug.Assert(parser != null); if (NextClean(parser) != '[') throw new ParseException("An array must start with '['."); _output.StartArray(); if (NextClean(parser) != ']') { parser.Back(); bool end = false; do { _output.ArrayPut(NextObject(parser)); switch (NextClean(parser)) { case ',' : { if (NextClean(parser) == ']') end = true; else parser.Back(); break; } case ']' : { end = true; break; } default : throw new ParseException("Expected a ',' or ']'."); } } while (!end); } return _output.EndArray(); }
private object ParseObject(TextParser parser) { Debug.Assert(parser != null); if (parser.Next() == '%') parser.Restart(Unescape(parser.Source), parser.Index); parser.Back(); if (NextClean(parser) != '{') throw new ParseException("An object must begin with '{'."); _output.StartObject(); char ch = NextClean(parser); while (ch != '}') { string memberName; switch (ch) { case JsonParser.EOF : throw new ParseException("An object must end with '}'."); case '}' : continue; default : { parser.Back(); memberName = NextObject(parser).ToString(); break; } } if (NextClean(parser) != ':') throw new ParseException("Expected a ':' after a key."); object memberValue = NextObject(parser); _output.ObjectPut(memberName, memberValue); switch (ch = NextClean(parser)) { case ',' : { if ((ch = NextClean(parser)) == '}') continue; parser.Back(); break; } case '}' : continue; default : throw new ParseException("Expected a ',' or '}'."); } ch = NextClean(parser); } return _output.EndObject(); }
/// <summary> /// Gets the next value as object. The value can be a Boolean, a Double, /// an Integer, an object array, a JObject, a String, or /// JObject.NULL. /// </summary> private object NextObject(TextParser parser) { Debug.Assert(parser != null); char ch = NextClean(parser); // // String // if (ch == '"' || ch == '\'') return _output.ToStringPrimitive(parser.NextString(ch)); // // Object // if (ch == '{') { parser.Back(); return ParseObject(parser); } // // JSON Array // if (ch == '[') { parser.Back(); return ParseArray(parser); } StringBuilder sb = new StringBuilder(); char b = ch; while (ch >= ' ' && ch != ':' && ch != ',' && ch != ']' && ch != '}' && ch != '/') { sb.Append(ch); ch = parser.Next(); } parser.Back(); string s = sb.ToString().Trim(); if (s == "true") return _output.TruePrimitive; if (s == "false") return _output.FalsePrimitive; if (s == "null") return _output.NullPrimitive; if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+') { object number = _output.ToNumberPrimitive(s); if (number == null) throw new ParseException(string.Format("Cannot convert '{0}' to a number.", s)); return number; } if (s.Length == 0) throw new ParseException("Missing value."); return s; }