Alpha commit
parent
a9a37de231
commit
659088b90e
|
@ -2,6 +2,7 @@
|
|||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using sharp.extensions;
|
||||
using System.Globalization;
|
||||
|
||||
namespace sharp.json
|
||||
{
|
||||
|
@ -20,6 +21,8 @@ namespace sharp.json
|
|||
System.Tuple.Create('t','\t'),
|
||||
};
|
||||
|
||||
static List<char> numberScan = new List<char>(new char[] { '-', '0', '1', '2', '3', '4', '5', '7', '8', '9', '.','E','e' });
|
||||
|
||||
char[] buffer;
|
||||
int position;
|
||||
|
||||
|
@ -37,7 +40,7 @@ namespace sharp.json
|
|||
}
|
||||
|
||||
public string Peek(int len){
|
||||
return new String(buffer.Segment(position,len));
|
||||
return new String(buffer.Segment(position,len).Extend(len));
|
||||
}
|
||||
|
||||
|
||||
|
@ -49,7 +52,7 @@ namespace sharp.json
|
|||
}
|
||||
public char[] Read(int len){
|
||||
if ((position) < buffer.Length){
|
||||
char[] r = buffer.Segment(position,len);
|
||||
char[] r = buffer.Segment(position, len).Extend(len);
|
||||
position += r.Length;
|
||||
return r;
|
||||
}
|
||||
|
@ -85,22 +88,43 @@ namespace sharp.json
|
|||
}
|
||||
|
||||
public JSON parseNumber(){
|
||||
Int64 i64 = parseInt64();
|
||||
List<char> digits = new List<char>();
|
||||
|
||||
if (Peek() == '.'){
|
||||
Read();
|
||||
Int64 dec = parseInt64();
|
||||
int lg10 = (int)Math.Log10(dec);
|
||||
i64 = i64 * lg10;
|
||||
if (i64 < 0){
|
||||
i64 -= dec;
|
||||
} else {
|
||||
i64 += dec;
|
||||
do
|
||||
{
|
||||
char n = (char)Peek();
|
||||
if (!numberScan.Contains(n)){
|
||||
break;
|
||||
}
|
||||
return new JSONNumber(((double)i64) / (double)lg10 );
|
||||
digits.Add(n);
|
||||
Read();
|
||||
} while (true);
|
||||
|
||||
string sv = new String(digits.ToArray());
|
||||
|
||||
if ((sv.IndexOf(".") > 0)||(sv.IndexOf("E") > 0)||(sv.IndexOf("e") > 0))
|
||||
{
|
||||
return new JSONNumber(double.Parse(sv,CultureInfo.InvariantCulture));
|
||||
} else {
|
||||
return new JSONNumber(i64);
|
||||
return new JSONNumber(Int64.Parse(sv));
|
||||
}
|
||||
|
||||
//Int64 i64 = parseInt64();
|
||||
|
||||
//if (Peek() == '.'){
|
||||
// Read();
|
||||
// Int64 dec = parseInt64();
|
||||
// int lg10 = (int)Math.Log10(dec);
|
||||
// i64 = i64 * lg10;
|
||||
// if (i64 < 0){
|
||||
// i64 -= dec;
|
||||
// } else {
|
||||
// i64 += dec;
|
||||
// }
|
||||
// return new JSONNumber(((double)i64) / (double)lg10 );
|
||||
//} else {
|
||||
// return new JSONNumber(i64);
|
||||
//}
|
||||
}
|
||||
|
||||
public JSON parseObject(){
|
||||
|
@ -138,7 +162,7 @@ namespace sharp.json
|
|||
scanWhitespace();
|
||||
continue;
|
||||
}
|
||||
throw new FormatException("parser error: expected ',' or '}' but got '{0}'");
|
||||
throw new FormatException("parser error: expected ',' or '}' but got '"+n+"'");
|
||||
}
|
||||
}
|
||||
return o;
|
||||
|
@ -185,20 +209,10 @@ namespace sharp.json
|
|||
|
||||
while (Peek() != '"'){
|
||||
char ch = Read();
|
||||
if (ch == '\\'){
|
||||
sb.Append(ch);
|
||||
if (ch == '\\')
|
||||
{
|
||||
ch = Read();
|
||||
foreach (System.Tuple<char,char> repl in escapeCharacters){
|
||||
if (repl.Item1 == ch){
|
||||
sb.Append(repl.Item2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ch == 'u'){
|
||||
char[] hex = Read(4);
|
||||
sb.Append("_");
|
||||
Console.WriteLine("JSON WARNING: UNICODE ESCAPE SEQUENCES ARE NOT IMPLEMENTED YET");
|
||||
}
|
||||
} else {
|
||||
sb.Append(ch);
|
||||
}
|
||||
}
|
||||
|
|
273
JSON.cs
273
JSON.cs
|
@ -2,65 +2,266 @@
|
|||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace sharp.json
|
||||
{
|
||||
public abstract class JSON
|
||||
public delegate object JSONActivationDelegate(Type t);
|
||||
|
||||
public abstract class JSON : IEnumerable<JSON>
|
||||
{
|
||||
List<string> keys = new List<string>();
|
||||
List<JSON> values = new List<JSON>();
|
||||
public virtual double Double { get { throw new NotImplementedException(); } }
|
||||
public virtual long Integer { get { throw new NotImplementedException(); } }
|
||||
public virtual string String { get { throw new NotImplementedException(); } }
|
||||
public virtual bool Boolean { get { throw new NotImplementedException(); } }
|
||||
|
||||
public JSON this[int n] {
|
||||
get {
|
||||
return values[n];
|
||||
}
|
||||
set{
|
||||
values[n] = value;
|
||||
}
|
||||
public virtual JSON this[int n]
|
||||
{
|
||||
get { throw new NotImplementedException(String.Format("{0} has no numbered elements",GetType().Name)); }
|
||||
set { throw new NotImplementedException(String.Format("{0} has no numbered elements",GetType().Name)); }
|
||||
}
|
||||
|
||||
public JSON this[string name] {
|
||||
get {
|
||||
return values[keys.IndexOf(name)];
|
||||
}
|
||||
set{
|
||||
if (keys.Contains(name)){
|
||||
values[keys.IndexOf(name)] = value;
|
||||
} else {
|
||||
keys.Add(name);
|
||||
values.Add(value);
|
||||
}
|
||||
}
|
||||
public virtual JSON this[string name] {
|
||||
get { throw new NotImplementedException(String.Format("{0} has no named elements", GetType().Name)); }
|
||||
set { throw new NotImplementedException(String.Format("{0} has no named elements", GetType().Name)); }
|
||||
}
|
||||
|
||||
public string[] Keys {
|
||||
get { return this.keys.ToArray(); }
|
||||
}
|
||||
public JSON[] Values {
|
||||
get { return this.values.ToArray(); }
|
||||
public virtual int Count { get { return 0; } }
|
||||
|
||||
public virtual bool Contains(object o){
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Add(JSON element){
|
||||
this.values.Add(element);
|
||||
public virtual void Add(JSON child)
|
||||
{
|
||||
throw new NotImplementedException(String.Format("{0} has no numbered elements", GetType().Name));
|
||||
}
|
||||
|
||||
public virtual bool isTrue(){
|
||||
return this.JSONType == JSONTypes.True;
|
||||
public virtual void Remove(JSON child)
|
||||
{
|
||||
throw new NotImplementedException(String.Format("{0} has no numbered elements", GetType().Name));
|
||||
}
|
||||
|
||||
|
||||
public int Count { get { return values.Count; } }
|
||||
public JSONTypes JSONType { get; private set; }
|
||||
|
||||
protected JSON(JSONTypes type){
|
||||
JSONType = type;
|
||||
}
|
||||
|
||||
public abstract string prettyPrint(int d);
|
||||
public abstract string[] prettyPrint();
|
||||
public override abstract string ToString();
|
||||
|
||||
public static JSON parse(String jsonSource){
|
||||
return new ByteParser(jsonSource).parse();
|
||||
|
||||
public string prettyFormat(){
|
||||
return String.Join("\n", prettyPrint());
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static implicit operator JSON(Double src)
|
||||
{
|
||||
return new JSONNumber(src);
|
||||
}
|
||||
public static implicit operator JSON(int src)
|
||||
{
|
||||
return new JSONNumber(src);
|
||||
}
|
||||
public static implicit operator JSON(string text)
|
||||
{
|
||||
return new JSONString(text);
|
||||
}
|
||||
public static implicit operator JSON(bool b)
|
||||
{
|
||||
return b ? JSONSpecial.True : JSONSpecial.False;
|
||||
}
|
||||
|
||||
public T To<T>(){
|
||||
object o = Create(typeof(T));
|
||||
return (T)o;
|
||||
}
|
||||
|
||||
public void WriteTo(Stream stream){
|
||||
byte[] data = Encoding.ASCII.GetBytes(ToString());
|
||||
stream.Write(data,0,data.Length);
|
||||
}
|
||||
|
||||
public void WriteTo(String filename)
|
||||
{
|
||||
FileStream fs = new FileStream(filename, FileMode.Create);
|
||||
WriteTo(fs);
|
||||
fs.Close();
|
||||
}
|
||||
|
||||
public static JSON ReadFrom(string filename){
|
||||
JSONParser parser = new JSONParser();
|
||||
string source = File.ReadAllText(filename);
|
||||
return parser.Parse(source);
|
||||
|
||||
}
|
||||
|
||||
private object Create(Type t)
|
||||
{
|
||||
if (t.IsPrimitive || (t == typeof(string)) )
|
||||
{
|
||||
return CreatePrimitive(t);
|
||||
}
|
||||
|
||||
if (this.JSONType == JSONTypes.Object)
|
||||
{
|
||||
return CreateObject(t);
|
||||
}
|
||||
|
||||
if ((this.JSONType == JSONTypes.Array) && (t.IsArray))
|
||||
{
|
||||
return CreateArray(t);
|
||||
}
|
||||
|
||||
throw new InvalidCastException(String.Format("JSON {0} can't be casted to {1}", this.JSONType.ToString(), t.Name));
|
||||
}
|
||||
|
||||
private object CreatePrimitive(Type t){
|
||||
|
||||
if ((this.JSONType == JSONTypes.Null)){
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((this.JSONType == JSONTypes.Array) || (this.JSONType == JSONTypes.Object)){
|
||||
throw new InvalidCastException(String.Format("JSON {0} can't be casted to {1}",this.JSONType.ToString(),t.Name));
|
||||
}
|
||||
|
||||
if (t.Equals(typeof(int)) || t.Equals(typeof(long)) || t.Equals(typeof(short))){
|
||||
return (object)this.Integer;
|
||||
}
|
||||
if (t.Equals(typeof(double)) || t.Equals(typeof(float)))
|
||||
{
|
||||
return (object)this.Double;
|
||||
}
|
||||
if (t.Equals(typeof(string)))
|
||||
{
|
||||
return (object)this.String;
|
||||
}
|
||||
if (t.Equals(typeof(Boolean)))
|
||||
{
|
||||
return (object)this.Boolean;
|
||||
}
|
||||
|
||||
throw new Exception(String.Format("Unsupported primitive type",t.Name));
|
||||
}
|
||||
|
||||
private object CreateObject(Type t){
|
||||
if (t.GetConstructor(new Type[] { typeof(JSON) } ) != null){
|
||||
return Activator.CreateInstance(t, this);
|
||||
}
|
||||
|
||||
|
||||
object instance = Activator.CreateInstance(t);
|
||||
Dictionary<string, FieldPropertyInfo> assignedFields = new Dictionary<string, FieldPropertyInfo>();
|
||||
|
||||
foreach (FieldInfo fi in t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
|
||||
{
|
||||
foreach (JSONField f in fi.GetCustomAttributes<JSONField>())
|
||||
{
|
||||
if (this.Contains(f.Alias))
|
||||
{
|
||||
if (!assignedFields.ContainsKey(f.Alias) || assignedFields[f.Alias].IsAutoAssigned){
|
||||
assignedFields[f.Alias] = new FieldPropertyInfo(fi, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!assignedFields.ContainsKey(fi.Name) && this.Contains(fi.Name)){
|
||||
assignedFields[fi.Name] = new FieldPropertyInfo(fi, true);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (PropertyInfo pi in t.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
|
||||
{
|
||||
foreach (JSONField f in pi.GetCustomAttributes<JSONField>())
|
||||
{
|
||||
if (this.Contains(f.Alias))
|
||||
{
|
||||
if (!assignedFields.ContainsKey(f.Alias) || assignedFields[f.Alias].IsAutoAssigned)
|
||||
{
|
||||
assignedFields[f.Alias] = new FieldPropertyInfo(pi, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!assignedFields.ContainsKey(pi.Name) && this.Contains(pi.Name))
|
||||
{
|
||||
assignedFields[pi.Name] = new FieldPropertyInfo(pi, true);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string,FieldPropertyInfo> e in assignedFields){
|
||||
e.Value.setValue(instance, this[e.Key].Create(e.Value.ValueType));
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private object CreateArray(Type t)
|
||||
{
|
||||
Array a = Array.CreateInstance(t.GetElementType(), this.Count);
|
||||
|
||||
for (int n = 0; n < this.Count;n++){
|
||||
a.SetValue(this[n].Create(t.GetElementType()),n);
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
public virtual IEnumerator<JSON> GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return (IEnumerator)GetEnumerator();
|
||||
}
|
||||
|
||||
|
||||
struct FieldPropertyInfo {
|
||||
public bool IsAutoAssigned { get; set; }
|
||||
FieldInfo FieldInfo { get; set; }
|
||||
PropertyInfo PropertyInfo { get; set; }
|
||||
|
||||
public FieldPropertyInfo(PropertyInfo propertyInfo,bool autoAssigned)
|
||||
{
|
||||
this.IsAutoAssigned = autoAssigned;
|
||||
this.PropertyInfo = propertyInfo;
|
||||
this.FieldInfo = null;
|
||||
}
|
||||
public FieldPropertyInfo(FieldInfo fieldInfo,bool autoAssigned)
|
||||
{
|
||||
this.IsAutoAssigned = autoAssigned;
|
||||
this.PropertyInfo = null;
|
||||
this.FieldInfo = fieldInfo;
|
||||
}
|
||||
|
||||
public void setValue(object inst,object value){
|
||||
if (PropertyInfo != null){
|
||||
PropertyInfo.SetValue(inst,value);
|
||||
} else if (FieldInfo != null){
|
||||
FieldInfo.SetValue(inst,value);
|
||||
}
|
||||
}
|
||||
|
||||
public Type ValueType {
|
||||
get {
|
||||
if (PropertyInfo != null){
|
||||
return PropertyInfo.PropertyType;
|
||||
} else if (FieldInfo != null){
|
||||
return FieldInfo.FieldType;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
82
JSONArray.cs
82
JSONArray.cs
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
@ -7,31 +7,95 @@ namespace sharp.json
|
|||
public class JSONArray : JSON
|
||||
{
|
||||
public JSONArray()
|
||||
:base(JSONTypes.Array){}
|
||||
|
||||
public override bool isTrue()
|
||||
: base(JSONTypes.Array) { }
|
||||
|
||||
List<JSON> values = new List<JSON>();
|
||||
|
||||
public override bool Boolean
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
get { return values.Count > 0; }
|
||||
}
|
||||
|
||||
public override string prettyPrint(int d = 0)
|
||||
public override JSON this[int n]
|
||||
{
|
||||
return ToString();
|
||||
get
|
||||
{
|
||||
return values[n];
|
||||
}
|
||||
set
|
||||
{
|
||||
values[n] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.values.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Contains(object o)
|
||||
{
|
||||
return this.values.Contains((JSON)o);
|
||||
}
|
||||
|
||||
public override void Add(JSON child)
|
||||
{
|
||||
this.values.Add(child);
|
||||
}
|
||||
|
||||
public override void Remove(JSON child)
|
||||
{
|
||||
this.values.Remove(child);
|
||||
}
|
||||
|
||||
public override string[] prettyPrint()
|
||||
{
|
||||
List<string> lines = new List<string>();
|
||||
|
||||
lines.Add("[");
|
||||
|
||||
for (int i = 0; i < this.values.Count; i++)
|
||||
{
|
||||
JSON cv = this.values[i];
|
||||
string[] clines = cv.prettyPrint();
|
||||
|
||||
for (int n = 0; n < clines.Length; n++)
|
||||
{
|
||||
lines.Add(String.Format(" {0}{1}", clines[n], (n < clines.Length - 1) || (i == this.values.Count - 1) ? "" : ","));
|
||||
}
|
||||
}
|
||||
|
||||
lines.Add("]");
|
||||
|
||||
return lines.ToArray();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("[");
|
||||
for (int n=0;n<this.Count;n++)
|
||||
for (int n = 0; n < this.Count; n++)
|
||||
{
|
||||
sb.Append(this[n].ToString());
|
||||
if (n+1 < this.Count){
|
||||
if (n + 1 < this.Count)
|
||||
{
|
||||
sb.Append(",");
|
||||
}
|
||||
}
|
||||
sb.Append("]");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override IEnumerator<JSON> GetEnumerator()
|
||||
{
|
||||
return this.values.GetEnumerator();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace sharp.json
|
||||
{
|
||||
public class JSONField : Attribute
|
||||
{
|
||||
public string Alias { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
namespace sharp.json
|
||||
{
|
||||
public class JSONNumber: JSON
|
||||
|
@ -25,18 +27,68 @@ namespace sharp.json
|
|||
doubleValue = d;
|
||||
}
|
||||
|
||||
public override string prettyPrint(int d = 0)
|
||||
public override double Double
|
||||
{
|
||||
if (Double.IsNaN(doubleValue)){
|
||||
return this.intValue.ToString();
|
||||
} else {
|
||||
return this.doubleValue.ToString();
|
||||
get
|
||||
{
|
||||
if (!Double.IsNaN(doubleValue)){
|
||||
return doubleValue;
|
||||
} else {
|
||||
return (double)intValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override long Integer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!Double.IsNaN(doubleValue)){
|
||||
return (int)doubleValue;
|
||||
} else {
|
||||
return intValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string String
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!Double.IsNaN(doubleValue))
|
||||
{
|
||||
return doubleValue.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
return intValue.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public override string[] prettyPrint()
|
||||
{
|
||||
return new string[] { ToString() };
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.prettyPrint(0);
|
||||
if (Double.IsNaN(doubleValue))
|
||||
{
|
||||
return this.intValue.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.doubleValue.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsInteger(){
|
||||
return Double.IsNaN(doubleValue);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using sharp.extensions;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
|
||||
namespace sharp.json
|
||||
{
|
||||
|
@ -9,29 +12,53 @@ namespace sharp.json
|
|||
public JSONObject()
|
||||
:base(JSONTypes.Object){}
|
||||
|
||||
public override bool isTrue()
|
||||
private Dictionary<string, JSON> values = new Dictionary<string, JSON>();
|
||||
|
||||
public override JSON this[string name]
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
get { return this.values[name]; }
|
||||
set { this.values[name] = value; }
|
||||
}
|
||||
|
||||
public override string prettyPrint(int d = 0)
|
||||
public override int Count
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("{");
|
||||
get { return this.values.Count; }
|
||||
}
|
||||
|
||||
string[] keys = Keys;
|
||||
public override bool Boolean
|
||||
{
|
||||
get { return this.values.Count > 0; }
|
||||
}
|
||||
|
||||
public override bool Contains(object o)
|
||||
{
|
||||
return this.values.ContainsKey((string)o);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override string[] prettyPrint()
|
||||
{
|
||||
List<string> lines = new List<string>();
|
||||
lines.Add("{");
|
||||
|
||||
string[] keys = this.values.Keys.ToArray();
|
||||
|
||||
for (int n=0;n<keys.Length;n++)
|
||||
{
|
||||
sb.Append(new JSONString(keys[n]));
|
||||
sb.Append(":");
|
||||
sb.Append(this[keys[n]].ToString());
|
||||
if (n+1 < keys.Length){
|
||||
sb.Append(",");
|
||||
string[] clines = this[keys[n]].prettyPrint();
|
||||
|
||||
lines.Add(String.Format(" {0} : {1}",new JSONString(keys[n]),clines[0]));
|
||||
foreach (string cline in clines.Segment(1)){
|
||||
lines.Add(String.Format(" {0}",cline));
|
||||
}
|
||||
|
||||
if (n < keys.Length-1){
|
||||
lines[lines.Count - 1] += ",";
|
||||
}
|
||||
}
|
||||
sb.Append("}");
|
||||
return sb.ToString();
|
||||
lines.Add("}");
|
||||
return lines.ToArray();
|
||||
|
||||
}
|
||||
|
||||
|
@ -40,7 +67,7 @@ namespace sharp.json
|
|||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("{");
|
||||
|
||||
string[] keys = Keys;
|
||||
string[] keys = this.values.Keys.ToArray();
|
||||
|
||||
for (int n=0;n<keys.Length;n++)
|
||||
{
|
||||
|
@ -54,5 +81,6 @@ namespace sharp.json
|
|||
sb.Append("}");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,318 @@
|
|||
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 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);
|
||||
|
||||
digit_c.AddFollower(digit_c);
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
namespace sharp.json
|
||||
{
|
||||
public static class JSONSerializer
|
||||
{
|
||||
|
||||
public static void Apply(JSON json,Object o){
|
||||
Type t = o.GetType();
|
||||
|
||||
if (t.IsPrimitive){
|
||||
ApplyPrimitive(json,o);
|
||||
} else {
|
||||
ApplyClass(json, o);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ApplyPrimitive(JSON json,Object o){
|
||||
|
||||
}
|
||||
|
||||
public static void ApplyClass(JSON json,Object o){
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
namespace sharp.json
|
||||
{
|
||||
public class JSONSpecial: JSON
|
||||
|
@ -12,12 +12,12 @@ namespace sharp.json
|
|||
{
|
||||
}
|
||||
|
||||
public override bool isTrue()
|
||||
public override string[] prettyPrint()
|
||||
{
|
||||
return (JSONType == JSONTypes.True);
|
||||
return new string[] { ToString() };
|
||||
}
|
||||
|
||||
public override string prettyPrint(int d = 0)
|
||||
public override string ToString()
|
||||
{
|
||||
switch (JSONType){
|
||||
case JSONTypes.Null:
|
||||
|
@ -30,9 +30,24 @@ namespace sharp.json
|
|||
throw new NotImplementedException("JSON Special Type badly wrong....");
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
public override bool Boolean
|
||||
{
|
||||
return prettyPrint();
|
||||
get
|
||||
{
|
||||
return this == True;
|
||||
}
|
||||
}
|
||||
|
||||
public override string String
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this == Null){
|
||||
return null;
|
||||
}
|
||||
return base.String;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Text;
|
||||
using sharp.extensions;
|
||||
|
||||
namespace sharp.json
|
||||
{
|
||||
|
@ -30,14 +31,30 @@ namespace sharp.json
|
|||
this.value = value;
|
||||
}
|
||||
|
||||
public override string prettyPrint(int d = 0)
|
||||
public override string String
|
||||
{
|
||||
return string.Format("\"{0}\"",escape(value));
|
||||
get { return this.value; }
|
||||
}
|
||||
|
||||
public override double Double
|
||||
{
|
||||
get { return Double.Parse(this.value); }
|
||||
}
|
||||
|
||||
public override long Integer
|
||||
{
|
||||
get { return long.Parse(this.value); }
|
||||
}
|
||||
|
||||
|
||||
public override string[] prettyPrint()
|
||||
{
|
||||
return new string[] { ToString() };
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return prettyPrint();
|
||||
return String.Format("\"{0}\"",escape(this.value));
|
||||
}
|
||||
|
||||
public static string escape(string source){
|
||||
|
@ -46,7 +63,7 @@ namespace sharp.json
|
|||
if ((ch >= 0x20) && (ch < 128)){
|
||||
sb.Append(ch);
|
||||
} else if (ch < 0x20){
|
||||
foreach (Tuple<char,char> repl in escapeCharacters){
|
||||
foreach (System.Tuple<char,char> repl in escapeCharacters){
|
||||
if (repl.Item2 == ch){
|
||||
sb.Append("\\");
|
||||
sb.Append(repl.Item1);
|
||||
|
@ -62,5 +79,40 @@ namespace sharp.json
|
|||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string unescape(string source)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
CharEnumerator ce = source.GetEnumerator();
|
||||
char[] hex = new char[4];
|
||||
|
||||
while (ce.MoveNext()){
|
||||
|
||||
if (ce.Current == '\\'){
|
||||
ce.MoveNext();
|
||||
|
||||
foreach (System.Tuple<char, char> repl in escapeCharacters)
|
||||
{
|
||||
if (repl.Item1 == ce.Current)
|
||||
{
|
||||
sb.Append(repl.Item2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ce.Current == 'u'){
|
||||
for (int n = 0; n < 4;n++){
|
||||
ce.MoveNext();
|
||||
hex[3 - n] = ce.Current;
|
||||
}
|
||||
sb.Append((char)( HexString.toBytes(hex).toUInt32()[0] ));
|
||||
}
|
||||
|
||||
} else {
|
||||
sb.Append(ce.Current);
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
using sharp.extensions;
|
||||
using System.Net;
|
||||
using sharp.webclient;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace sharp.json
|
||||
{
|
||||
public class JSONWebRequest
|
||||
{
|
||||
private static JSONParser jsonParser = new JSONParser();
|
||||
|
||||
public static JSON Call(string url){
|
||||
return Call(url, null);
|
||||
}
|
||||
|
||||
public static JSON Call(string url, JSON request)
|
||||
{
|
||||
return Call(url, request, null);
|
||||
}
|
||||
|
||||
public static JSON Call(string url, JSON request, IDictionary<string,string> headers)
|
||||
{
|
||||
HttpRequest req = new HttpRequest(url);
|
||||
if (request != null){
|
||||
byte[] rbody = request.ToString().toBytes();
|
||||
req.RequestStream.Write(rbody,0,rbody.Length);
|
||||
}
|
||||
|
||||
if (headers != null)
|
||||
{
|
||||
foreach (string hname in headers.Keys)
|
||||
{
|
||||
req.setHeader(hname, headers[hname]);
|
||||
}
|
||||
}
|
||||
|
||||
HttpResponse response = req.Send();
|
||||
return jsonParser.Parse(response.ContentText);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
using System.IO;
|
||||
|
||||
using sharp.json;
|
||||
using sharp.parser;
|
||||
|
||||
namespace json.test
|
||||
{
|
||||
|
@ -17,19 +18,17 @@ namespace json.test
|
|||
public static void Main(string[] args)
|
||||
{
|
||||
JSON json;
|
||||
JSONParser jsonparser = new JSONParser();
|
||||
|
||||
Console.WriteLine("JSON test Patterns:");
|
||||
Console.WriteLine();
|
||||
|
||||
foreach (string src in sources){
|
||||
json = JSON.parse(src);
|
||||
|
||||
Console.WriteLine("SOURCE: {0}",src);
|
||||
Console.WriteLine("PARSED: {0}",json.ToString());
|
||||
Console.WriteLine("REPARSED: {0}",JSON.parse(json.ToString()).ToString());
|
||||
json = jsonparser.Parse(src);
|
||||
Console.WriteLine("NEW PARSER: {0}",json.ToString());
|
||||
}
|
||||
|
||||
json = JSON.parse(File.ReadAllText("test.json"));
|
||||
json = jsonparser.Parse(File.ReadAllText("test.json"));
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine("test.json file:");
|
||||
Console.WriteLine("PARSED: {0}",json.ToString());
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>json.test</RootNamespace>
|
||||
<AssemblyName>json.test</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
@ -38,6 +38,10 @@
|
|||
<Project>{D9342117-3249-4D8B-87C9-51A50676B158}</Project>
|
||||
<Name>sharp.json</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\sharp-parser\sharp.parser.csproj">
|
||||
<Project>{32267133-ADB7-4A85-8CF1-03CBDF53715C}</Project>
|
||||
<Name>sharp.parser</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="test.json">
|
||||
|
|
|
@ -39,12 +39,28 @@
|
|||
<Compile Include="JSONString.cs" />
|
||||
<Compile Include="JSONTypes.cs" />
|
||||
<Compile Include="JSONNumber.cs" />
|
||||
<Compile Include="JSONWebRequest.cs" />
|
||||
<Compile Include="JSONSerializer.cs" />
|
||||
<Compile Include="JSONParser.cs" />
|
||||
<Compile Include="JSONField.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\sharp-extensions\sharp.extensions.csproj">
|
||||
<Project>{97CA3CA9-98B3-4492-B072-D7A5995B68E9}</Project>
|
||||
<Name>sharp.extensions</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\sharp-webclient\sharp.webclient.csproj">
|
||||
<Project>{01E98E3B-9462-4CF1-8421-4789763FBAA1}</Project>
|
||||
<Name>sharp.webclient</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\sharp-parser\sharp.parser.csproj">
|
||||
<Project>{32267133-ADB7-4A85-8CF1-03CBDF53715C}</Project>
|
||||
<Name>sharp.parser</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\sharp-contracts\sharp.contracts.csproj">
|
||||
<Project>{56733EC1-7D97-48D0-AA4C-98EA624A5A21}</Project>
|
||||
<Name>sharp.contracts</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
|
|
Loading…
Reference in New Issue