private void AssertExpected(AllowedToken match) { if ((_expected & match) == 0) { ParseException("Expected a " + string.Join(", ", Definition(_expected).ToArray()) + ", but found a " + string.Join(", ", Definition(match).ToArray())); } }
private static IEnumerable <string> Definition(AllowedToken match) { var parts = new List <string>(); if ((match & AllowedToken.Array) != 0) { parts.Add("`[`"); } if ((match & AllowedToken.Boolean) != 0) { parts.Add("boolean"); } if ((match & AllowedToken.Colon) != 0) { parts.Add("`:`"); } if ((match & AllowedToken.Comma) != 0) { parts.Add("`,`"); } if ((match & AllowedToken.EndObject) != 0) { parts.Add("`}`"); } if ((match & AllowedToken.EndArray) != 0) { parts.Add("`]`"); } if ((match & AllowedToken.Null) != 0) { parts.Add("`null`"); } if ((match & AllowedToken.Number) != 0) { parts.Add("number"); } if ((match & AllowedToken.Object) != 0) { parts.Add("`{`"); } if ((match & AllowedToken.Property) != 0) { parts.Add("property name"); } if ((match & AllowedToken.String) != 0) { parts.Add("string"); } return(parts); }
public bool Read() { SkipWhitespace(); var next = Peek(); if (next == ':' && (_expected & AllowedToken.Colon) != 0) { ReadChar(); _expected = AllowedToken.Value; SkipWhitespace(); next = Peek(); } else if (next == ',' && (_expected & AllowedToken.Comma) != 0 && _groups.Count > 0) { ReadChar(); _expected = _groups.Peek() == JsonToken.StartObject ? AllowedToken.Property : AllowedToken.Value; SkipWhitespace(); next = Peek(); } switch (next) { case '{': AssertExpected(AllowedToken.Object); _expected = AllowedToken.Property | AllowedToken.EndObject; TokenType = JsonToken.StartObject; Value = null; ReadChar(); _groups.Push(TokenType); return(true); case '[': AssertExpected(AllowedToken.Array); _expected = AllowedToken.Value | AllowedToken.EndArray; TokenType = JsonToken.StartArray; Value = null; ReadChar(); _groups.Push(TokenType); return(true); case '}': if (_groups.Count < 1) { ParseException($"Too many closing `{next}`"); } var open = _groups.Pop(); if (open != JsonToken.StartObject) { ParseException($"Closing character `{next}` does not match the last opening character `{Definition(open)}`"); } AssertExpected(AllowedToken.EndObject); _expected = AllowedToken.EndValue; TokenType = JsonToken.EndObject; Value = null; ReadChar(); return(true); case ']': if (_groups.Count < 1) { ParseException($"Too many closing `{next}`"); } var open2 = _groups.Pop(); if (open2 != JsonToken.StartArray) { ParseException($"Closing character `{next}` does not match the last opening character `{Definition(open2)}`"); } AssertExpected(AllowedToken.EndArray); _expected = AllowedToken.EndValue; TokenType = JsonToken.EndArray; Value = null; ReadChar(); return(true); case '"': AssertExpected(AllowedToken.Property | AllowedToken.String); Value = ReadString(); if ((_expected & AllowedToken.Property) != 0) { TokenType = JsonToken.PropertyName; _expected = AllowedToken.Colon; } else { TokenType = JsonToken.String; _expected = AllowedToken.EndValue; } return(true); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': AssertExpected(AllowedToken.Number); _expected = AllowedToken.EndValue; TokenType = JsonToken.Number; Value = ReadNumber(); return(true); case 't': case 'f': AssertExpected(AllowedToken.Boolean); _expected = AllowedToken.EndValue; TokenType = JsonToken.Boolean; Value = ReadBoolean(); return(true); case 'n': AssertExpected(AllowedToken.Null); _expected = AllowedToken.EndValue; TokenType = JsonToken.Null; Value = ReadNull(); return(true); case '\0': if (_groups.Count > 0) { ParseException($"The last group `{Definition(_groups.Peek())}` is not closed"); } TokenType = JsonToken.None; Value = null; return(false); default: ParseException(); return(false); } }