ln.json/JSONParser.cs

237 lines
6.9 KiB
C#

// /**
// * File: JSONParser.cs
// * Author: haraldwolff
// *
// * This file and it's content is copyrighted by the Author and / or copyright holder.
// * Any use wihtout proper permission is illegal and may lead to legal actions.
// *
// *
// **/
using System;
using System.Collections.Generic;
using ln.types;
using ln.types.stream;
using System.Text;
using System.Globalization;
namespace ln.json
{
public class JSONParser
{
static char[] chNull = new char[] { 'n', 'u', 'l', 'l' };
static char[] chTrue = new char[] { 't', 'r', 'u', 'e' };
static char[] chFalse = new char[] { 'f', 'a', 'l', 's', 'e' };
public static JSONValue Parse(String jsonSource)
{
CharStream chars = new CharStream(jsonSource);
return ParseValue(chars);
}
/**
* Für alle Parser Methoden welche als Parameter ein CharStream erhalten
* gilt folgendes:
*
* - CharStream.Current zeitg auf das erste Zeichen,
* welches interpretiert werden soll
* - Bei Rücksprung zeigt CharStream.Current auf das erste zeichen,
* welches nicht mehr zum aktuellen Wert gehört und kein Whitespace
* ist
*
**/
static JSONValue ParseValue(CharStream chars)
{
chars.Skip(char.IsWhiteSpace);
switch (chars.Current)
{
case '"':
return parseString(chars);
case 't':
return parseTrue(chars);
case 'f':
return parseFalse(chars);
case 'n':
return parseNull(chars);
case '[':
return parseArray(chars);
case '{':
return parseObject(chars);
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
return parseNumber(chars);
default:
throw new FormatException(String.Format("Unexpected character: {0} [ 0x{0:x4} ]", chars.Current));
}
}
static JSONString parseString(CharStream chars)
{
if (chars.Current != '"')
throw new FormatException("Unexpected character");
StringBuilder stringBuilder = new StringBuilder();
chars.MoveNext();
while (chars.Current != '"')
{
stringBuilder.Append(chars.Current);
if (chars.Current == '\\')
{
chars.MoveNext();
stringBuilder.Append(chars.Current);
}
chars.MoveNext();
}
chars.TryNext();
chars.Skip(char.IsWhiteSpace);
return new JSONString(JSONString.Unescape(stringBuilder.ToString()));
}
static JSONNumber parseNumber(CharStream chars)
{
StringBuilder sb = new StringBuilder();
if (chars.Current == '-')
{
sb.Append(chars.Current);
chars.MoveNext();
}
sb.Append(chars.Read(char.IsDigit));
if (chars.Current == '.')
{
sb.Append('.');
chars.MoveNext();
sb.Append(chars.Read(char.IsDigit));
}
if ((chars.Current == 'e')|| (chars.Current == 'E'))
{
sb.Append('e');
if ((chars.Current == '-')|| (chars.Current == '+'))
{
sb.Append(chars.Current);
chars.MoveNext();
}
sb.Append(chars.Read(char.IsDigit));
}
chars.Skip(char.IsWhiteSpace);
return new JSONNumber(decimal.Parse(sb.ToString(),CultureInfo.InvariantCulture));
}
static JSONArray parseArray(CharStream chars)
{
if (chars.Current != '[')
throw new FormatException("Unexpected character");
JSONArray array = new JSONArray();
chars.MoveNext();
while (chars.Current != ']')
{
array.Add(ParseValue(chars));
if (chars.Current == ',')
{
chars.MoveNext();
chars.Skip(char.IsWhiteSpace);
}
}
chars.TryNext();
chars.Skip(char.IsWhiteSpace);
return array;
}
static JSONObject parseObject(CharStream chars)
{
if (chars.Current != '{')
throw new FormatException("Unexpected character");
JSONObject o = new JSONObject();
chars.MoveNext();
chars.Skip(char.IsWhiteSpace);
while (chars.Current != '}')
{
JSONString s = parseString(chars);
if (chars.Current != ':')
throw new FormatException("expected :");
chars.MoveNext();
o.Add(s.Value, ParseValue(chars));
if (chars.Current == ',')
{
chars.MoveNext();
chars.Skip(char.IsWhiteSpace);
}
}
chars.TryNext();
chars.Skip(char.IsWhiteSpace);
return o;
}
static JSONTrue parseTrue(CharStream chars)
{
char[] ch = new char[4];
for (int n = 0; n < ch.Length; n++)
{
ch[n] = chars.Current;
chars.MoveNext();
}
if (ch.AreEqual(chTrue))
{
chars.Skip(char.IsWhiteSpace);
return JSONTrue.Instance;
}
throw new FormatException();
}
static JSONFalse parseFalse(CharStream chars)
{
char[] ch = new char[5];
for (int n = 0; n < ch.Length; n++)
{
ch[n] = chars.Current;
chars.MoveNext();
}
if (ch.AreEqual(chFalse))
{
chars.Skip(char.IsWhiteSpace);
return JSONFalse.Instance;
}
throw new FormatException();
}
static JSONNull parseNull(CharStream chars)
{
char[] ch = new char[4];
for (int n=0;n<ch.Length;n++)
{
ch[n] = chars.Current;
chars.MoveNext();
}
if (ch.AreEqual(chNull))
{
chars.Skip(char.IsWhiteSpace);
return JSONNull.Instance;
}
throw new FormatException();
}
}
}