/// <summary> /// Consume a JSON numeric token /// </summary> /// <param name="ctx"></param> /// <param name="throws"></param> /// <returns></returns> private static JsonParserContext ConsumeNumber( this JsonParserContext ctx, bool throws ) { const string Leading = "-0123456789"; const string Allowed = Leading + ".Ee+"; if (ctx.ConsumeWhiteSpace().ConsumeAnyChar(Leading, throws).IsSucceeded) { JSonReader src = ctx.Begin(); for (int p = src.Position, len = src.Text.Length; p < len; p++) { if (Allowed.IndexOf(src.Text[p]) < 0) { ctx.SetResult( new JValue { BoxedValue = double.Parse(src.Text.Substring(src.Position - 1, p - src.Position + 1)) } ); src.Position = p; break; } } } return(ctx); }
/// <summary> /// Consume a JSON array /// </summary> /// <param name="ctx"></param> /// <param name="throws"></param> /// <returns></returns> private static JsonParserContext ConsumeArray( this JsonParserContext ctx, bool throws ) { if (ctx.ConsumeWhiteSpace().ConsumeAnyChar("[", throws).IsSucceeded) { var jctr = new JArray(); bool shouldThrow = false; do { ctx.Begin(); if (ctx.ConsumeValue(shouldThrow).IsSucceeded) { jctr.Add((JToken)ctx.Result); } shouldThrow = true; }while ((char)ctx.ConsumeWhiteSpace().ConsumeAnyChar(",]", true).Result == ','); ctx.SetResult(jctr); } return(ctx); }
/// <summary> /// Consume a JSON object /// </summary> /// <param name="ctx"></param> /// <param name="throws"></param> /// <returns></returns> private static JsonParserContext ConsumeObject( this JsonParserContext ctx, bool throws ) { if (ctx.ConsumeWhiteSpace().ConsumeAnyChar("{", throws).IsSucceeded) { var jctr = new JObject(); bool shouldThrow = false; do { ctx.Begin(); if (ctx.ConsumeString(shouldThrow).IsSucceeded) { var name = (string)(JValue)ctx.Result; ctx.ConsumeWhiteSpace() .ConsumeAnyChar(":", true) .ConsumeValue(true); jctr.Add(name, (JToken)ctx.Result); } shouldThrow = true; }while ((char)ctx.ConsumeWhiteSpace().ConsumeAnyChar(",}", true).Result == ','); ctx.SetResult(jctr); } return(ctx); }
/// <summary> /// Consume all the characters in the specified sequence /// </summary> /// <param name="ctx"></param> /// <param name="sequence"></param> /// <param name="throws"></param> /// <returns></returns> private static JsonParserContext ConsumeAllChars( this JsonParserContext ctx, string sequence, bool throws ) { JSonReader src = ctx.Begin(); for (int q = 0, p = src.Position; q < sequence.Length; q++, p++) { if (src.Text[p] != sequence[q]) { if (throws) { throw new JsonParseException("Expected char not found."); } return(ctx); } } src.Position += sequence.Length; ctx.SetResult(sequence); return(ctx); }
/// <summary> /// Consume any suitable JSON value token /// </summary> /// <param name="ctx"></param> /// <param name="throws"></param> /// <returns></returns> private static JsonParserContext ConsumeValue( this JsonParserContext ctx, bool throws ) { return(ctx.First( throws, JsonHelpers.ConsumeString, JsonHelpers.ConsumeNumber, JsonHelpers.ConsumeObject, JsonHelpers.ConsumeArray, JsonHelpers.ConsumeBoolean, JsonHelpers.ConsumeNull )); }
/// <summary> /// Consume an arbitrary number of whitespace characters /// </summary> /// <param name="ctx"></param> /// <returns></returns> private static JsonParserContext ConsumeWhiteSpace( this JsonParserContext ctx ) { JSonReader src = ctx.Begin(); for (int p = src.Position, len = src.Text.Length; p < len; p++) { if (WhiteSpace.IndexOf(src.Text[p]) < 0) { src.Position = p; break; } } return(ctx); }
/// <summary> /// Consume the JSON "null" token /// </summary> /// <param name="ctx"></param> /// <param name="throws"></param> /// <returns></returns> private static JsonParserContext ConsumeNull( this JsonParserContext ctx, bool throws ) { if (ctx.ConsumeWhiteSpace().ConsumeAnyChar("n", throws).IsSucceeded) { ctx.ConsumeAllChars("ull", true); ctx.SetResult( new JValue { BoxedValue = null } ); } return(ctx); }
/// <summary> /// Consume a JSON boolean token /// </summary> /// <param name="ctx"></param> /// <param name="throws"></param> /// <returns></returns> private static JsonParserContext ConsumeBoolean( this JsonParserContext ctx, bool throws ) { if (ctx.ConsumeWhiteSpace().ConsumeAnyChar("ft", throws).IsSucceeded) { bool flag = (char)ctx.Result == 't'; ctx.ConsumeAllChars(flag ? "rue" : "alse", true); ctx.SetResult( new JValue { BoxedValue = flag } ); } return(ctx); }
/// <summary> /// Parse a JSON-string to a specific DOM /// </summary> /// <param name="text"></param> /// <returns></returns> public static JToken Parse(string text) { #if NETF CultureInfo culture = (CultureInfo)CultureInfo.CurrentCulture.Clone(); culture.DateTimeFormat.DateSeparator = "-"; culture.DateTimeFormat.ShortDatePattern = "yyyy-MM-dd"; culture.NumberFormat.NumberDecimalSeparator = "."; Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; #endif var rd = new JSonReader(text); var ctx = new JsonParserContext(rd) .ConsumeWhiteSpace() .First(true, JsonHelpers.ConsumeObject, JsonHelpers.ConsumeArray); return((JToken)ctx.Result); }
/// <summary> /// Consume a JSON string token /// </summary> /// <param name="ctx"></param> /// <param name="throws"></param> /// <returns></returns> private static JsonParserContext ConsumeString( this JsonParserContext ctx, bool throws ) { if (ctx.ConsumeWhiteSpace().ConsumeAnyChar("\"", throws).IsSucceeded) { JSonReader src = ctx.Begin(); for (int p = src.Position, len = src.Text.Length; p < len; p++) { if ((src.Text[p]) == '"' && (p > 0 ? (src.Text[p - 1]) != '\\' : true)) { string temp = src.Text.Substring(src.Position, p - src.Position); int index = 0; while (index < temp.Length) { if (temp[index] == '\\') { temp = temp.Substring(0, index) + temp.Substring(index + 1, temp.Length - (index + 1)); } index++; } ctx.SetResult( new JValue { BoxedValue = temp } ); src.Position = p + 1; break; } } } return(ctx); }
/// <summary> /// Consume any character (at least one) in the specified set /// </summary> /// <param name="ctx"></param> /// <param name="charset"></param> /// <param name="throws"></param> /// <returns></returns> private static JsonParserContext ConsumeAnyChar( this JsonParserContext ctx, string charset, bool throws ) { JSonReader src = ctx.Begin(); char c; if (charset.IndexOf(c = src.Text[src.Position]) >= 0) { src.Position++; ctx.SetResult(c); } else if (throws) { throw new JsonParseException("Expected char not found."); } return(ctx); }
/// <summary> /// Yield the consumption of the current context to a series of possible parsers /// The control will pass to the first one able to manage the source. /// </summary> /// <param name="ctx"></param> /// <param name="throws"></param> /// <param name="funcs"></param> /// <returns></returns> private static JsonParserContext First( this JsonParserContext ctx, bool throws, params JsonParseDelegate[] funcs ) { for (int i = 0; i < funcs.Length; i++) { if (funcs[i](ctx, false).IsSucceeded) { return(ctx); } } if (throws) { throw new JsonParseException("Unmatched handler for context."); } else { return(ctx); } }