forked from ln-dotnet/ln.json
322 lines
8.8 KiB
C#
322 lines
8.8 KiB
C#
using System;
|
|
using sharp.parser;
|
|
using Microsoft.Win32.SafeHandles;
|
|
using System.Globalization;
|
|
using System.Net.Mime;
|
|
using System.Collections.Generic;
|
|
|
|
namespace sharp.json
|
|
{
|
|
public class JSONParser : Parser<JSON>
|
|
{
|
|
delegate JSON ParseObjectDelegate(TokenQueue tokens);
|
|
|
|
Dictionary<TokenDefinition, ParseObjectDelegate> parserDelegates = new Dictionary<TokenDefinition, ParseObjectDelegate>();
|
|
|
|
public JSONParser()
|
|
:base(tokenDefinitions)
|
|
{
|
|
parserDelegates.Add(tString,parseString);
|
|
parserDelegates.Add(tNumber,parseNumber);
|
|
parserDelegates.Add(tObjectOpen,parseObject);
|
|
parserDelegates.Add(tArrayOpen,parseArray);
|
|
parserDelegates.Add(tTrue,parseTrue);
|
|
parserDelegates.Add(tFalse,parseFalse);
|
|
parserDelegates.Add(tNull,parseNull);
|
|
}
|
|
|
|
protected override JSON ParseTokens(Token[] tokens)
|
|
{
|
|
TokenQueue qtoken = new TokenQueue();
|
|
foreach (Token t in tokens){
|
|
if (t.Definition != tWhiteSpace){
|
|
qtoken.Enqueue(t);
|
|
}
|
|
}
|
|
return parseValue(qtoken);
|
|
}
|
|
|
|
private JSON parseValue(TokenQueue tokens){
|
|
foreach (TokenDefinition tdef in this.parserDelegates.Keys){
|
|
if (tdef == tokens.Peek().Definition){
|
|
return this.parserDelegates[tokens.Peek().Definition](tokens);
|
|
}
|
|
}
|
|
throw new Exception(String.Format("Parser got unexpected token: {0}", tokens.Peek().ToString()));
|
|
}
|
|
|
|
JSON parseString(TokenQueue tokens){
|
|
Token t = tokens.Expect(tString);
|
|
return new JSONString(t.Value.Substring(1, t.Value.Length - 2));
|
|
}
|
|
|
|
JSON parseNumber(TokenQueue tokens)
|
|
{
|
|
Token t = tokens.Expect(tNumber);
|
|
Double dv = double.Parse(t.Value,CultureInfo.InvariantCulture);
|
|
return new JSONNumber(dv);
|
|
}
|
|
|
|
JSON parseObject(TokenQueue tokens)
|
|
{
|
|
Token t = tokens.Expect(tObjectOpen);
|
|
JSONObject jo = new JSONObject();
|
|
|
|
if (tokens.Peek().Definition == tObjectClose){
|
|
tokens.Dequeue();
|
|
return jo;
|
|
}
|
|
|
|
do
|
|
{
|
|
JSONString js = (JSONString)parseString(tokens);
|
|
|
|
tokens.Expect(tColon);
|
|
|
|
JSON json = parseValue(tokens);
|
|
jo[js.String] = json;
|
|
|
|
t = tokens.Expect(tObjectClose, tComma);
|
|
|
|
if (t.Definition == tObjectClose){
|
|
break;
|
|
}
|
|
} while (true);
|
|
|
|
return jo;
|
|
}
|
|
|
|
JSON parseArray(TokenQueue tokens)
|
|
{
|
|
Token t = tokens.Expect(tArrayOpen);
|
|
JSONArray ja = new JSONArray();
|
|
|
|
if (tokens.Peek().Definition == tArrayClose)
|
|
{
|
|
tokens.Dequeue();
|
|
return ja;
|
|
}
|
|
|
|
do
|
|
{
|
|
JSON json = parseValue(tokens);
|
|
ja.Add(json);
|
|
|
|
t = tokens.Expect(tArrayClose, tComma);
|
|
|
|
if (t.Definition == tArrayClose)
|
|
{
|
|
break;
|
|
}
|
|
} while (true);
|
|
|
|
return ja;
|
|
}
|
|
|
|
JSON parseTrue(TokenQueue tokens)
|
|
{
|
|
if (tokens.Peek().Definition == tTrue){
|
|
Token t = tokens.Dequeue();
|
|
return JSONSpecial.True;
|
|
}
|
|
throw new Exception("Unexpected Token: " + tokens.Peek());
|
|
}
|
|
JSON parseFalse(TokenQueue tokens)
|
|
{
|
|
if (tokens.Peek().Definition == tFalse){
|
|
Token t = tokens.Dequeue();
|
|
return JSONSpecial.False;
|
|
}
|
|
throw new Exception("Unexpected Token: " + tokens.Peek());
|
|
}
|
|
JSON parseNull(TokenQueue tokens)
|
|
{
|
|
if (tokens.Peek().Definition == tNull){
|
|
Token t = tokens.Dequeue();
|
|
return JSONSpecial.Null;
|
|
}
|
|
throw new Exception("Unexpected Token: " + tokens.Peek());
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool initializer = initialize();
|
|
|
|
static TokenDefinition[] tokenDefinitions;
|
|
|
|
static CharGroup eE = new CharGroup(new char[] { 'e', 'E' } );
|
|
|
|
static LexerPathSegment null_ll;
|
|
static LexerPathSegment null_l;
|
|
static LexerPathSegment null_u;
|
|
static LexerPathSegment null_n;
|
|
|
|
static LexerPathSegment true_e;
|
|
static LexerPathSegment true_u;
|
|
static LexerPathSegment true_r;
|
|
static LexerPathSegment true_t;
|
|
|
|
static LexerPathSegment false_e;
|
|
static LexerPathSegment false_s;
|
|
static LexerPathSegment false_l;
|
|
static LexerPathSegment false_a;
|
|
static LexerPathSegment false_f;
|
|
|
|
static LexerPathSegment ws;
|
|
|
|
static TokenDefinition tNumber;
|
|
static TokenDefinition tString;
|
|
static TokenDefinition tColon;
|
|
static TokenDefinition tComma;
|
|
static TokenDefinition tObjectOpen;
|
|
static TokenDefinition tObjectClose;
|
|
static TokenDefinition tArrayOpen;
|
|
static TokenDefinition tArrayClose;
|
|
static TokenDefinition tTrue;
|
|
static TokenDefinition tFalse;
|
|
static TokenDefinition tNull;
|
|
static TokenDefinition tWhiteSpace;
|
|
|
|
static private bool initialize(){
|
|
eE = new CharGroup(new char[] { 'e', 'E' });
|
|
|
|
null_ll = new LexerPathSegment('l', true);
|
|
null_l = new LexerPathSegment('l', null_ll);
|
|
null_u = new LexerPathSegment('u', null_l);
|
|
null_n = new LexerPathSegment('n', null_u);
|
|
|
|
true_e = new LexerPathSegment('e', true);
|
|
true_u = new LexerPathSegment('u', true_e);
|
|
true_r = new LexerPathSegment('r', true_u);
|
|
true_t = new LexerPathSegment('t', true_r);
|
|
|
|
false_e = new LexerPathSegment('e', true);
|
|
false_s = new LexerPathSegment('s', false_e);
|
|
false_l = new LexerPathSegment('l', false_s);
|
|
false_a = new LexerPathSegment('a', false_l);
|
|
false_f = new LexerPathSegment('f', false_a);
|
|
|
|
ws = new LexerPathSegment(CharGroup.WS, true);
|
|
ws.AddFollower(ws);
|
|
|
|
tNumber = new TokenDefinition("JSON.number", initializeNumberHead());
|
|
tString = new TokenDefinition("JSON.string", initializeStringHead());
|
|
tColon = new TokenDefinition("JSON.colon", new LexerPathSegment(':',true));
|
|
tComma = new TokenDefinition("JSON.comma", new LexerPathSegment(',',true));
|
|
tObjectOpen = new TokenDefinition("JSON.obj.open", new LexerPathSegment('{',true));
|
|
tObjectClose = new TokenDefinition("JSON.obj.close", new LexerPathSegment('}',true));
|
|
tArrayOpen = new TokenDefinition("JSON.array.open", new LexerPathSegment('[',true));
|
|
tArrayClose = new TokenDefinition("JSON.array.close", new LexerPathSegment(']',true));
|
|
tTrue = new TokenDefinition("JSON.true", true_t);
|
|
tFalse = new TokenDefinition("JSON.false", false_f);
|
|
tNull = new TokenDefinition("JSON.null", null_n);
|
|
tWhiteSpace = new TokenDefinition("JSON.WhiteSpace",ws);
|
|
|
|
tokenDefinitions = new TokenDefinition[]{
|
|
tWhiteSpace,
|
|
tNumber,
|
|
tString,
|
|
tColon,
|
|
tComma,
|
|
tObjectOpen,
|
|
tObjectClose,
|
|
tArrayOpen,
|
|
tArrayClose,
|
|
tTrue,
|
|
tFalse,
|
|
tNull
|
|
};
|
|
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
static private LexerPathSegment initializeStringHead(){
|
|
LexerPathSegment head = new LexerPathSegment('\"');
|
|
LexerPathSegment finish = new LexerPathSegment('\"',true);
|
|
LexerPathSegment backslash = new LexerPathSegment('\\');
|
|
LexerPathSegment control = new LexerPathSegment(new char[] { '\"','\\','/','b','f','n','r','t'} );
|
|
LexerPathSegment u4 = new LexerPathSegment(CharGroup.hexdigits);
|
|
LexerPathSegment u3 = new LexerPathSegment(CharGroup.hexdigits,u4);
|
|
LexerPathSegment u2 = new LexerPathSegment(CharGroup.hexdigits,u3);
|
|
LexerPathSegment u1 = new LexerPathSegment(CharGroup.hexdigits,u2);
|
|
LexerPathSegment ucontrol = new LexerPathSegment('u',u1);
|
|
|
|
CharGroup anyChar = new CharGroup((char)0x20, (char)0xff) - backslash.CharGroup - finish.CharGroup;
|
|
LexerPathSegment any = new LexerPathSegment(anyChar);
|
|
|
|
head.AddFollower(finish);
|
|
head.AddFollower(any);
|
|
head.AddFollower(backslash);
|
|
|
|
any.AddFollower(any);
|
|
any.AddFollower(backslash);
|
|
any.AddFollower(finish);
|
|
|
|
backslash.AddFollower(control);
|
|
backslash.AddFollower(ucontrol);
|
|
|
|
control.AddFollower(any);
|
|
control.AddFollower(backslash);
|
|
control.AddFollower(finish);
|
|
|
|
u4.AddFollower(any);
|
|
u4.AddFollower(backslash);
|
|
u4.AddFollower(finish);
|
|
|
|
return head;
|
|
}
|
|
|
|
static private LexerPathSegment initializeNumberHead()
|
|
{
|
|
LexerPathSegment head = new LexerPathSegment();
|
|
LexerPathSegment minus = new LexerPathSegment(CharGroup.minus);
|
|
LexerPathSegment zero = new LexerPathSegment('0',true);
|
|
LexerPathSegment d19 = new LexerPathSegment('1', '9', true);
|
|
LexerPathSegment digit_a = new LexerPathSegment(CharGroup.digit,true);
|
|
LexerPathSegment digit_b = new LexerPathSegment(CharGroup.digit,true);
|
|
LexerPathSegment digit_c = new LexerPathSegment(CharGroup.digit,true);
|
|
LexerPathSegment dot = new LexerPathSegment('.');
|
|
LexerPathSegment ee = new LexerPathSegment(eE);
|
|
LexerPathSegment eminus = new LexerPathSegment(CharGroup.minus);
|
|
LexerPathSegment plusminus = new LexerPathSegment(CharGroup.plusminus);
|
|
|
|
head.AddFollower(minus);
|
|
head.AddFollower(zero);
|
|
head.AddFollower(d19);
|
|
|
|
minus.AddFollower(zero);
|
|
minus.AddFollower(d19);
|
|
|
|
zero.AddFollower(dot);
|
|
zero.AddFollower(ee);
|
|
|
|
d19.AddFollower(digit_a);
|
|
d19.AddFollower(dot);
|
|
d19.AddFollower(ee);
|
|
|
|
digit_a.AddFollower(digit_a);
|
|
digit_a.AddFollower(dot);
|
|
digit_a.AddFollower(ee);
|
|
|
|
dot.AddFollower(digit_b);
|
|
|
|
digit_b.AddFollower(digit_b);
|
|
digit_b.AddFollower(ee);
|
|
|
|
ee.AddFollower(digit_c);
|
|
ee.AddFollower(plusminus);
|
|
|
|
plusminus.AddFollower(digit_c);
|
|
|
|
digit_c.AddFollower(digit_c);
|
|
|
|
return head;
|
|
}
|
|
|
|
}
|
|
}
|