dtsod
This commit is contained in:
parent
843155d8d7
commit
d04855bff2
@ -1,27 +1,17 @@
|
|||||||
using DTLib.Extensions;
|
namespace DTLib.Dtsod;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using static DTLib.PublicLog;
|
|
||||||
|
|
||||||
namespace DTLib.Dtsod
|
// v21
|
||||||
{
|
|
||||||
//
|
|
||||||
// это как json но не совсем
|
|
||||||
//
|
|
||||||
// v2.0
|
|
||||||
// полностью переписан парсер
|
|
||||||
//
|
|
||||||
// v2.1
|
|
||||||
// парсер теперь не может игнорировать комменты, потом починю
|
// парсер теперь не может игнорировать комменты, потом починю
|
||||||
// теперь числовые значения конвертируются в правильный тип, а не в int64/uint64 (новый вариант switch из c#9.0 делал какую-то херню)
|
// теперь числовые значения конвертируются в правильный тип, а не в int64/uint64 (новый вариант switch из c#9.0 делал какую-то дичь)
|
||||||
// исправлены некоторые другие баги
|
// исправлены некоторые другие баги
|
||||||
|
|
||||||
public class DtsodV21 : Dictionary<string, dynamic>
|
public class DtsodV21 : Dictionary<string, dynamic>, IDtsod
|
||||||
{
|
{
|
||||||
static readonly bool debug = false;
|
public DtsodVersion Version { get; } = DtsodVersion.V21;
|
||||||
string Text;
|
|
||||||
|
public IDictionary<string, dynamic> ToDictionary() => this;
|
||||||
|
|
||||||
|
readonly string Text;
|
||||||
|
|
||||||
//public Dictionary<string, dynamic> Values { get; set; }
|
//public Dictionary<string, dynamic> Values { get; set; }
|
||||||
public DtsodV21(string text)
|
public DtsodV21(string text)
|
||||||
@ -30,7 +20,7 @@ namespace DTLib.Dtsod
|
|||||||
foreach (KeyValuePair<string, dynamic> pair in Parse(text))
|
foreach (KeyValuePair<string, dynamic> pair in Parse(text))
|
||||||
Add(pair.Key, pair.Value);
|
Add(pair.Key, pair.Value);
|
||||||
}
|
}
|
||||||
public DtsodV21(Dictionary<string, dynamic> rawDict)
|
public DtsodV21(IDictionary<string, dynamic> rawDict)
|
||||||
{
|
{
|
||||||
Text = "";
|
Text = "";
|
||||||
foreach (KeyValuePair<string, dynamic> pair in rawDict)
|
foreach (KeyValuePair<string, dynamic> pair in rawDict)
|
||||||
@ -91,7 +81,9 @@ namespace DTLib.Dtsod
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i < text.Length; i++)
|
for (; i < text.Length; i++)
|
||||||
ReadName();
|
ReadName();
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("g", $"Parse returns {parsed.Keys.Count} keys\n");
|
DebugNoTime("g", $"Parse returns {parsed.Keys.Count} keys\n");
|
||||||
|
#endif
|
||||||
return parsed;
|
return parsed;
|
||||||
|
|
||||||
// СЛОМАНО
|
// СЛОМАНО
|
||||||
@ -107,7 +99,9 @@ namespace DTLib.Dtsod
|
|||||||
dynamic value;
|
dynamic value;
|
||||||
StringBuilder defaultNameBuilder = new();
|
StringBuilder defaultNameBuilder = new();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("m", "ReadName\n");
|
DebugNoTime("m", "ReadName\n");
|
||||||
|
#endif
|
||||||
for (; i < text.Length; i++)
|
for (; i < text.Length; i++)
|
||||||
{
|
{
|
||||||
switch (text[i])
|
switch (text[i])
|
||||||
@ -140,7 +134,9 @@ namespace DTLib.Dtsod
|
|||||||
throw new Exception("Parse.ReadName() error: unexpected '}' at " + i + " char");
|
throw new Exception("Parse.ReadName() error: unexpected '}' at " + i + " char");
|
||||||
// если $ перед названием параметра поставить, значение value добавится в лист с названием name
|
// если $ перед названием параметра поставить, значение value добавится в лист с названием name
|
||||||
case '$':
|
case '$':
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("w", text[i].ToString());
|
DebugNoTime("w", text[i].ToString());
|
||||||
|
#endif
|
||||||
if (defaultNameBuilder.ToString().Length != 0)
|
if (defaultNameBuilder.ToString().Length != 0)
|
||||||
throw new Exception("Parse.ReadName() error: unexpected '$' at " + i + " char");
|
throw new Exception("Parse.ReadName() error: unexpected '$' at " + i + " char");
|
||||||
isListElem = true;
|
isListElem = true;
|
||||||
@ -148,7 +144,9 @@ namespace DTLib.Dtsod
|
|||||||
case ';':
|
case ';':
|
||||||
throw new Exception("Parse.ReadName() error: unexpected ';' at " + i + " char");
|
throw new Exception("Parse.ReadName() error: unexpected ';' at " + i + " char");
|
||||||
default:
|
default:
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("w", text[i].ToString());
|
DebugNoTime("w", text[i].ToString());
|
||||||
|
#endif
|
||||||
defaultNameBuilder.Append(text[i]);
|
defaultNameBuilder.Append(text[i]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -167,11 +165,15 @@ namespace DTLib.Dtsod
|
|||||||
valueBuilder.Append('"');
|
valueBuilder.Append('"');
|
||||||
for (; text[i] != '"' || text[i - 1] == '\\'; i++)
|
for (; text[i] != '"' || text[i - 1] == '\\'; i++)
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("h", text[i].ToString());
|
DebugNoTime("h", text[i].ToString());
|
||||||
|
#endif
|
||||||
valueBuilder.Append(text[i]);
|
valueBuilder.Append(text[i]);
|
||||||
}
|
}
|
||||||
valueBuilder.Append('"');
|
valueBuilder.Append('"');
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("h", text[i].ToString());
|
DebugNoTime("h", text[i].ToString());
|
||||||
|
#endif
|
||||||
type = ValueType.String;
|
type = ValueType.String;
|
||||||
return valueBuilder.ToString();
|
return valueBuilder.ToString();
|
||||||
}
|
}
|
||||||
@ -183,7 +185,9 @@ namespace DTLib.Dtsod
|
|||||||
StringBuilder valueBuilder = new();
|
StringBuilder valueBuilder = new();
|
||||||
for (; text[i] != ']'; i++)
|
for (; text[i] != ']'; i++)
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("c", text[i].ToString());
|
DebugNoTime("c", text[i].ToString());
|
||||||
|
#endif
|
||||||
switch (text[i])
|
switch (text[i])
|
||||||
{
|
{
|
||||||
case ' ':
|
case ' ':
|
||||||
@ -206,7 +210,9 @@ namespace DTLib.Dtsod
|
|||||||
ParseValueToRightType(valueBuilder.ToString());
|
ParseValueToRightType(valueBuilder.ToString());
|
||||||
output.Add(value);
|
output.Add(value);
|
||||||
}
|
}
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("c", text[i].ToString());
|
DebugNoTime("c", text[i].ToString());
|
||||||
|
#endif
|
||||||
type = ValueType.List;
|
type = ValueType.List;
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@ -218,7 +224,9 @@ namespace DTLib.Dtsod
|
|||||||
i++;
|
i++;
|
||||||
for (; balance != 0; i++)
|
for (; balance != 0; i++)
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("y", text[i].ToString());
|
DebugNoTime("y", text[i].ToString());
|
||||||
|
#endif
|
||||||
switch (text[i])
|
switch (text[i])
|
||||||
{
|
{
|
||||||
case '"':
|
case '"':
|
||||||
@ -226,13 +234,17 @@ namespace DTLib.Dtsod
|
|||||||
break;
|
break;
|
||||||
case '}':
|
case '}':
|
||||||
balance--;
|
balance--;
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("b", $"\nbalance -- = {balance}\n");
|
DebugNoTime("b", $"\nbalance -- = {balance}\n");
|
||||||
|
#endif
|
||||||
if (balance != 0)
|
if (balance != 0)
|
||||||
valueBuilder.Append(text[i]);
|
valueBuilder.Append(text[i]);
|
||||||
break;
|
break;
|
||||||
case '{':
|
case '{':
|
||||||
balance++;
|
balance++;
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("b", $"\nbalance ++ = {balance}\n");
|
DebugNoTime("b", $"\nbalance ++ = {balance}\n");
|
||||||
|
#endif
|
||||||
valueBuilder.Append(text[i]);
|
valueBuilder.Append(text[i]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -248,7 +260,9 @@ namespace DTLib.Dtsod
|
|||||||
void ParseValueToRightType(string stringValue)
|
void ParseValueToRightType(string stringValue)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("b", $"\nParseValueToRightType({stringValue})\n");
|
DebugNoTime("b", $"\nParseValueToRightType({stringValue})\n");
|
||||||
|
#endif
|
||||||
switch (stringValue)
|
switch (stringValue)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -304,10 +318,14 @@ namespace DTLib.Dtsod
|
|||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder defaultValueBuilder = new();
|
StringBuilder defaultValueBuilder = new();
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("m", "\nReadValue\n");
|
DebugNoTime("m", "\nReadValue\n");
|
||||||
|
#endif
|
||||||
for (; i < text.Length; i++)
|
for (; i < text.Length; i++)
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("b", text[i].ToString());
|
DebugNoTime("b", text[i].ToString());
|
||||||
|
#endif
|
||||||
switch (text[i])
|
switch (text[i])
|
||||||
{
|
{
|
||||||
case ' ':
|
case ' ':
|
||||||
@ -348,16 +366,9 @@ namespace DTLib.Dtsod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Debug(params string[] msg)
|
#if DEBUG
|
||||||
{
|
void Debug(params string[] msg) => PublicLog.Log(msg);
|
||||||
if (debug)
|
void DebugNoTime(params string[] msg) => PublicLog.LogNoTime(msg);
|
||||||
Log(msg);
|
#endif
|
||||||
}
|
|
||||||
void DebugNoTime(params string[] msg)
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
LogNoTime(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,29 +1,20 @@
|
|||||||
using DTLib.Extensions;
|
namespace DTLib.Dtsod;
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DTLib.Dtsod
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// это как json но не совсем
|
|
||||||
//
|
|
||||||
// v20
|
|
||||||
// полностью переписан парсер
|
|
||||||
//
|
|
||||||
// v21
|
|
||||||
// парсер теперь не может игнорировать комменты, потом починю
|
|
||||||
// теперь числовые значения конвертируются в правильный тип, а не в int64/uint64 (новый вариант switch из c#9.0 делал какую-то херню)
|
|
||||||
// исправлены некоторые другие баги
|
|
||||||
//
|
|
||||||
// v22
|
// v22
|
||||||
// метод ToString() теперь действительно деконструирует объект в текст, а не возвращает параметр text из конструктора
|
// метод ToString() теперь деконструирует объект в текст, а не возвращает параметр text из конструктора
|
||||||
|
// деконструкция листов не работает из-за костыльного определения типов данных
|
||||||
|
|
||||||
public class DtsodV22 : Dictionary<string, DtsodV22.ValueStruct>
|
public class DtsodV22 : Dictionary<string, DtsodV22.ValueStruct>, IDtsod
|
||||||
{
|
{
|
||||||
static readonly bool debug = false;
|
public DtsodVersion Version { get; } = DtsodVersion.V22;
|
||||||
|
|
||||||
|
public IDictionary<string, dynamic> ToDictionary()
|
||||||
|
{
|
||||||
|
Dictionary<string, dynamic> newdict = new();
|
||||||
|
foreach (KeyValuePair<string, ValueStruct> pair in this)
|
||||||
|
newdict.Add(pair.Key, pair.Value.Value);
|
||||||
|
return newdict;
|
||||||
|
}
|
||||||
|
|
||||||
public struct ValueStruct
|
public struct ValueStruct
|
||||||
{
|
{
|
||||||
@ -111,7 +102,9 @@ namespace DTLib.Dtsod
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i < text.Length; i++)
|
for (; i < text.Length; i++)
|
||||||
ReadName();
|
ReadName();
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("g", $"Parse returns {parsed.Keys.Count} keys\n");
|
DebugNoTime("g", $"Parse returns {parsed.Keys.Count} keys\n");
|
||||||
|
#endif
|
||||||
return new DtsodV22(parsed);
|
return new DtsodV22(parsed);
|
||||||
|
|
||||||
// СЛОМАНО
|
// СЛОМАНО
|
||||||
@ -127,7 +120,9 @@ namespace DTLib.Dtsod
|
|||||||
dynamic value;
|
dynamic value;
|
||||||
StringBuilder defaultNameBuilder = new();
|
StringBuilder defaultNameBuilder = new();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("m", "ReadName\n");
|
DebugNoTime("m", "ReadName\n");
|
||||||
|
#endif
|
||||||
for (; i < text.Length; i++)
|
for (; i < text.Length; i++)
|
||||||
{
|
{
|
||||||
switch (text[i])
|
switch (text[i])
|
||||||
@ -141,15 +136,16 @@ namespace DTLib.Dtsod
|
|||||||
i++;
|
i++;
|
||||||
string name = defaultNameBuilder.ToString();
|
string name = defaultNameBuilder.ToString();
|
||||||
value = ReadValue(out ValueTypes type, out bool isList);
|
value = ReadValue(out ValueTypes type, out bool isList);
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("c", $"parsed.Add({name},{type} {value} )\n");
|
DebugNoTime("c", $"parsed.Add({name},{type} {value} )\n");
|
||||||
|
#endif
|
||||||
if (isListElem)
|
if (isListElem)
|
||||||
{
|
{
|
||||||
if (!parsed.ContainsKey(name))
|
if (!parsed.ContainsKey(name))
|
||||||
parsed.Add(name, new(type, new List<dynamic>(), isList));
|
parsed.Add(name, new(type, new List<dynamic>(), isList));
|
||||||
parsed[name].Value.Add(value);
|
parsed[name].Value.Add(value);
|
||||||
}
|
}
|
||||||
else
|
else parsed.Add(name, new(type, value, isList));
|
||||||
parsed.Add(name, new(type, value, isList));
|
|
||||||
return;
|
return;
|
||||||
// строка, начинающаяся с # будет считаться комментом
|
// строка, начинающаяся с # будет считаться комментом
|
||||||
case '#':
|
case '#':
|
||||||
@ -159,7 +155,9 @@ namespace DTLib.Dtsod
|
|||||||
throw new Exception("Parse.ReadName() error: unexpected '}' at " + i + " char");
|
throw new Exception("Parse.ReadName() error: unexpected '}' at " + i + " char");
|
||||||
// если $ перед названием параметра поставить, значение value добавится в лист с названием name
|
// если $ перед названием параметра поставить, значение value добавится в лист с названием name
|
||||||
case '$':
|
case '$':
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("w", text[i].ToString());
|
DebugNoTime("w", text[i].ToString());
|
||||||
|
#endif
|
||||||
if (defaultNameBuilder.ToString().Length != 0)
|
if (defaultNameBuilder.ToString().Length != 0)
|
||||||
throw new Exception("Parse.ReadName() error: unexpected '$' at " + i + " char");
|
throw new Exception("Parse.ReadName() error: unexpected '$' at " + i + " char");
|
||||||
isListElem = true;
|
isListElem = true;
|
||||||
@ -167,7 +165,9 @@ namespace DTLib.Dtsod
|
|||||||
case ';':
|
case ';':
|
||||||
throw new Exception("Parse.ReadName() error: unexpected ';' at " + i + " char");
|
throw new Exception("Parse.ReadName() error: unexpected ';' at " + i + " char");
|
||||||
default:
|
default:
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("w", text[i].ToString());
|
DebugNoTime("w", text[i].ToString());
|
||||||
|
#endif
|
||||||
defaultNameBuilder.Append(text[i]);
|
defaultNameBuilder.Append(text[i]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -187,11 +187,15 @@ namespace DTLib.Dtsod
|
|||||||
valueBuilder.Append('"');
|
valueBuilder.Append('"');
|
||||||
for (; text[i] != '"' || text[i - 1] == '\\'; i++)
|
for (; text[i] != '"' || text[i - 1] == '\\'; i++)
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("h", text[i].ToString());
|
DebugNoTime("h", text[i].ToString());
|
||||||
|
#endif
|
||||||
valueBuilder.Append(text[i]);
|
valueBuilder.Append(text[i]);
|
||||||
}
|
}
|
||||||
valueBuilder.Append('"');
|
valueBuilder.Append('"');
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("h", text[i].ToString());
|
DebugNoTime("h", text[i].ToString());
|
||||||
|
#endif
|
||||||
type = ValueTypes.String;
|
type = ValueTypes.String;
|
||||||
return valueBuilder.ToString();
|
return valueBuilder.ToString();
|
||||||
}
|
}
|
||||||
@ -203,7 +207,9 @@ namespace DTLib.Dtsod
|
|||||||
StringBuilder valueBuilder = new();
|
StringBuilder valueBuilder = new();
|
||||||
for (; text[i] != ']'; i++)
|
for (; text[i] != ']'; i++)
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("c", text[i].ToString());
|
DebugNoTime("c", text[i].ToString());
|
||||||
|
#endif
|
||||||
switch (text[i])
|
switch (text[i])
|
||||||
{
|
{
|
||||||
case ' ':
|
case ' ':
|
||||||
@ -226,7 +232,9 @@ namespace DTLib.Dtsod
|
|||||||
ParseValueToRightType(valueBuilder.ToString());
|
ParseValueToRightType(valueBuilder.ToString());
|
||||||
output.Add(value);
|
output.Add(value);
|
||||||
}
|
}
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("c", text[i].ToString());
|
DebugNoTime("c", text[i].ToString());
|
||||||
|
#endif
|
||||||
type = ValueTypes.List;
|
type = ValueTypes.List;
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@ -238,7 +246,9 @@ namespace DTLib.Dtsod
|
|||||||
i++;
|
i++;
|
||||||
for (; balance != 0; i++)
|
for (; balance != 0; i++)
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("y", text[i].ToString());
|
DebugNoTime("y", text[i].ToString());
|
||||||
|
#endif
|
||||||
switch (text[i])
|
switch (text[i])
|
||||||
{
|
{
|
||||||
case '"':
|
case '"':
|
||||||
@ -246,13 +256,17 @@ namespace DTLib.Dtsod
|
|||||||
break;
|
break;
|
||||||
case '}':
|
case '}':
|
||||||
balance--;
|
balance--;
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("b", $"\nbalance -- = {balance}\n");
|
DebugNoTime("b", $"\nbalance -- = {balance}\n");
|
||||||
|
#endif
|
||||||
if (balance != 0)
|
if (balance != 0)
|
||||||
valueBuilder.Append(text[i]);
|
valueBuilder.Append(text[i]);
|
||||||
break;
|
break;
|
||||||
case '{':
|
case '{':
|
||||||
balance++;
|
balance++;
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("b", $"\nbalance ++ = {balance}\n");
|
DebugNoTime("b", $"\nbalance ++ = {balance}\n");
|
||||||
|
#endif
|
||||||
valueBuilder.Append(text[i]);
|
valueBuilder.Append(text[i]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -267,7 +281,9 @@ namespace DTLib.Dtsod
|
|||||||
|
|
||||||
void ParseValueToRightType(string stringValue)
|
void ParseValueToRightType(string stringValue)
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("b", $"\nParseValueToRightType({stringValue})\n");
|
DebugNoTime("b", $"\nParseValueToRightType({stringValue})\n");
|
||||||
|
#endif
|
||||||
switch (stringValue)
|
switch (stringValue)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -337,10 +353,14 @@ namespace DTLib.Dtsod
|
|||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder defaultValueBuilder = new();
|
StringBuilder defaultValueBuilder = new();
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("m", "\nReadValue\n");
|
DebugNoTime("m", "\nReadValue\n");
|
||||||
|
#endif
|
||||||
for (; i < text.Length; i++)
|
for (; i < text.Length; i++)
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
DebugNoTime("b", text[i].ToString());
|
DebugNoTime("b", text[i].ToString());
|
||||||
|
#endif
|
||||||
switch (text[i])
|
switch (text[i])
|
||||||
{
|
{
|
||||||
case ' ':
|
case ' ':
|
||||||
@ -459,11 +479,7 @@ namespace DTLib.Dtsod
|
|||||||
return outBuilder.ToString();
|
return outBuilder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugNoTime(params string[] msg)
|
public void Add(KeyValuePair<string, ValueStruct> a) => Add(a.Key, a.Value);
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
PublicLog.LogNoTime(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DtsodV22 Extend(DtsodV22 newPart)
|
public DtsodV22 Extend(DtsodV22 newPart)
|
||||||
{
|
{
|
||||||
@ -472,6 +488,8 @@ namespace DTLib.Dtsod
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(KeyValuePair<string, ValueStruct> a) => Add(a.Key, a.Value);
|
#if DEBUG
|
||||||
}
|
void Debug(params string[] msg) => PublicLog.Log(msg);
|
||||||
|
void DebugNoTime(params string[] msg) => PublicLog.LogNoTime(msg);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
8
Dtsod/DtsodVersion.cs
Normal file
8
Dtsod/DtsodVersion.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace DTLib.Dtsod;
|
||||||
|
|
||||||
|
public enum DtsodVersion : byte
|
||||||
|
{
|
||||||
|
V21 = 21,
|
||||||
|
V22 = 22,
|
||||||
|
V30 = 30
|
||||||
|
}
|
||||||
13
Dtsod/DtsodVersionConverter.cs
Normal file
13
Dtsod/DtsodVersionConverter.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace DTLib.Dtsod;
|
||||||
|
|
||||||
|
public static class DtsodVersionConverter
|
||||||
|
{
|
||||||
|
public static IDtsod Convert(IDtsod src, DtsodVersion targetVersion)
|
||||||
|
=> targetVersion switch
|
||||||
|
{
|
||||||
|
DtsodVersion.V21 => new DtsodV21(src.ToDictionary()),
|
||||||
|
DtsodVersion.V22 => throw new NotImplementedException("Converting dtsods to V22 isn't implemented"),
|
||||||
|
DtsodVersion.V30 => new DtsodV30(src.ToDictionary()),
|
||||||
|
_ => throw new Exception($"DtsodVersionConverter.Convert() error: unknown target version <{targetVersion}>"),
|
||||||
|
};
|
||||||
|
}
|
||||||
8
Dtsod/IDtsod.cs
Normal file
8
Dtsod/IDtsod.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace DTLib.Dtsod;
|
||||||
|
|
||||||
|
public interface IDtsod
|
||||||
|
{
|
||||||
|
public DtsodVersion Version { get; }
|
||||||
|
|
||||||
|
public IDictionary<string, dynamic> ToDictionary();
|
||||||
|
}
|
||||||
67
Dtsod/V30/DtsodDict.cs
Normal file
67
Dtsod/V30/DtsodDict.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
namespace DTLib.Dtsod;
|
||||||
|
|
||||||
|
public class DtsodDict<TKey, TVal> : IDictionary<TKey, TVal>
|
||||||
|
{
|
||||||
|
// да, вместо собственной реализации интерфейса это ссылки на Dictionary
|
||||||
|
readonly Dictionary<TKey, TVal> baseDict;
|
||||||
|
|
||||||
|
public DtsodDict() => baseDict = new();
|
||||||
|
public DtsodDict(IDictionary<TKey, TVal> srcDict) => baseDict = new(srcDict);
|
||||||
|
|
||||||
|
|
||||||
|
public virtual TVal this[TKey key]
|
||||||
|
{
|
||||||
|
get => TryGetValue(key, out TVal value) ? value : throw new Exception($"Dtsod[{key}] key not found");
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!TrySetValue(key, value)) throw new KeyNotFoundException($"DtsodDict[{key}] key not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool TryGetValue(TKey key, out TVal value) => baseDict.TryGetValue(key, out value);
|
||||||
|
|
||||||
|
public virtual bool TrySetValue(TKey key, TVal value)
|
||||||
|
{
|
||||||
|
if (ContainsKey(key))
|
||||||
|
{
|
||||||
|
baseDict[key] = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
public virtual void Append(ICollection<KeyValuePair<TKey, TVal>> anotherDtsod)
|
||||||
|
{
|
||||||
|
foreach (var pair in anotherDtsod)
|
||||||
|
Add(pair.Key, pair.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Add(TKey key, TVal value) => baseDict.Add(key, value);
|
||||||
|
|
||||||
|
public virtual void Add(KeyValuePair<TKey, TVal> pair)
|
||||||
|
=> ((ICollection<KeyValuePair<TKey, TVal>>)baseDict).Add(pair);
|
||||||
|
|
||||||
|
|
||||||
|
public int Count => baseDict.Count;
|
||||||
|
public ICollection<TKey> Keys { get => baseDict.Keys; }
|
||||||
|
public ICollection<TVal> Values { get => baseDict.Values; }
|
||||||
|
public bool IsReadOnly { get; } = false;
|
||||||
|
|
||||||
|
public virtual void Clear() => baseDict.Clear();
|
||||||
|
|
||||||
|
public virtual bool ContainsKey(TKey key) => baseDict.ContainsKey(key);
|
||||||
|
|
||||||
|
bool ICollection<KeyValuePair<TKey, TVal>>.Contains(KeyValuePair<TKey, TVal> pair)
|
||||||
|
=> ((ICollection<KeyValuePair<TKey, TVal>>)baseDict).Contains(pair);
|
||||||
|
|
||||||
|
void ICollection<KeyValuePair<TKey, TVal>>.CopyTo(KeyValuePair<TKey, TVal>[] array, int arrayIndex)
|
||||||
|
=> ((ICollection<KeyValuePair<TKey, TVal>>)baseDict).CopyTo(array, arrayIndex);
|
||||||
|
|
||||||
|
public virtual bool Remove(TKey key) => baseDict.Remove(key);
|
||||||
|
bool ICollection<KeyValuePair<TKey, TVal>>.Remove(KeyValuePair<TKey, TVal> pair)
|
||||||
|
=> ((ICollection<KeyValuePair<TKey, TVal>>)baseDict).Remove(pair);
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => baseDict.GetEnumerator();
|
||||||
|
public IEnumerator<KeyValuePair<TKey, TVal>> GetEnumerator() => baseDict.GetEnumerator();
|
||||||
|
}
|
||||||
@ -1,10 +1,7 @@
|
|||||||
using System;
|
namespace DTLib.Dtsod;
|
||||||
|
|
||||||
namespace DTLib.Dtsod
|
|
||||||
{
|
|
||||||
public class DtsodSerializableAttribute : Attribute
|
public class DtsodSerializableAttribute : Attribute
|
||||||
{
|
{
|
||||||
public DtsodVersion Version;
|
public DtsodVersion Version;
|
||||||
public DtsodSerializableAttribute(DtsodVersion ver) => Version = ver;
|
public DtsodSerializableAttribute(DtsodVersion ver) => Version = ver;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@ -1,17 +1,287 @@
|
|||||||
namespace DTLib.Dtsod
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace DTLib.Dtsod;
|
||||||
|
|
||||||
|
public class DtsodV30 : DtsodDict<string, dynamic>, IDtsod
|
||||||
{
|
{
|
||||||
public static class DtsodV30
|
public DtsodVersion Version { get; } = DtsodVersion.V30;
|
||||||
|
|
||||||
|
public IDictionary<string, dynamic> ToDictionary() => this;
|
||||||
|
|
||||||
|
public DtsodV30() : base() => UpdateLazy();
|
||||||
|
public DtsodV30(IDictionary<string, dynamic> dict) : base(dict) => UpdateLazy();
|
||||||
|
public DtsodV30(string serialized) : this() { Append(Deserialize(serialized)); }
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
static void DebugLog(params string[] msg) => PublicLog.Log(msg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static IDictionary<string, dynamic> Deserialize(string text)
|
||||||
{
|
{
|
||||||
/*
|
char c;
|
||||||
public static DtsodV30 FromObject(object target)
|
int i = -1; // ++i в ReadType
|
||||||
|
StringBuilder b = new();
|
||||||
|
|
||||||
|
|
||||||
|
Type ReadType()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
while (i < text.Length)
|
||||||
|
|
||||||
public T ToObject<T>()
|
|
||||||
{
|
{
|
||||||
|
c = text[++i];
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
SkipComment();
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
string _type = b.ToString();
|
||||||
|
b.Clear();
|
||||||
|
return TypeHelper.TypeFromString(_type);
|
||||||
|
case '=':
|
||||||
|
case '"':
|
||||||
|
case ';':
|
||||||
|
case '[':
|
||||||
|
case ']':
|
||||||
|
case '{':
|
||||||
|
case '}':
|
||||||
|
throw new Exception($"DtsodV30.Deserialize() error: unexpected {c}");
|
||||||
|
default:
|
||||||
|
b.Append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("DtsodV30.Deserialize.ReadType() error: end of text\ntext:\n" + text);
|
||||||
|
}
|
||||||
|
|
||||||
|
string ReadName()
|
||||||
|
{
|
||||||
|
while (i < text.Length)
|
||||||
|
{
|
||||||
|
c = text[++i];
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
SkipComment();
|
||||||
|
break;
|
||||||
|
case '=':
|
||||||
|
string _name = b.ToString();
|
||||||
|
b.Clear();
|
||||||
|
return _name;
|
||||||
|
case ':':
|
||||||
|
case '"':
|
||||||
|
case ';':
|
||||||
|
case '[':
|
||||||
|
case ']':
|
||||||
|
case '{':
|
||||||
|
case '}':
|
||||||
|
throw new Exception($"DtsodV30.Deserialize() error: unexpected {c}");
|
||||||
|
default:
|
||||||
|
b.Append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("DtsodV30.Deserialize.ReadName() error: end of text\ntext:\n" + text);
|
||||||
|
}
|
||||||
|
|
||||||
|
object[] ReadValue()
|
||||||
|
{
|
||||||
|
void ReadString()
|
||||||
|
{
|
||||||
|
c = text[++i]; //пропускает начальный символ '"'
|
||||||
|
while (c != '"' || (text[i - 1] == '\\' && text[i - 2] != '\\'))
|
||||||
|
{
|
||||||
|
b.Append(c);
|
||||||
|
if (++i >= text.Length) throw new Exception("DtsodV30.Deserialize() error: end of text\ntext:\n" + text);
|
||||||
|
c = text[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool endoflist = false; // выставляется в цикле в ReadValue()
|
||||||
|
List<object> ReadList()
|
||||||
|
{
|
||||||
|
List<dynamic> list = new();
|
||||||
|
while (!endoflist)
|
||||||
|
list.Add(CreateInstance(ReadType(), ReadValue()));
|
||||||
|
endoflist = false;
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDictionary<string, dynamic> ReadDictionary()
|
||||||
|
{
|
||||||
|
short bracketBalance = 1;
|
||||||
|
c = text[++i]; //пропускает начальный символ '{'
|
||||||
|
while (bracketBalance != 0)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
SkipComment();
|
||||||
|
break;
|
||||||
|
case '{':
|
||||||
|
bracketBalance++;
|
||||||
|
b.Append(c);
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
bracketBalance--;
|
||||||
|
if (bracketBalance != 0)
|
||||||
|
b.Append(c);
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
b.Append('"');
|
||||||
|
ReadString();
|
||||||
|
b.Append('"');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
b.Append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++i >= text.Length) throw new Exception("DtsodV30.Deserialize() error: end of text\ntext:\n" + text);
|
||||||
|
c = text[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Deserialize(b.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < text.Length)
|
||||||
|
{
|
||||||
|
c = text[++i];
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
SkipComment();
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
ReadString();
|
||||||
|
break;
|
||||||
|
case ';': // один параметр
|
||||||
|
case ',': // для листов
|
||||||
|
var str = b.ToString();
|
||||||
|
b.Clear();
|
||||||
|
// hardcoded "null" value
|
||||||
|
return str == "null" ? (new object[] { null }) : (new object[] { str });
|
||||||
|
case '[':
|
||||||
|
{
|
||||||
|
object[] _value = ReadList().ToArray();
|
||||||
|
b.Clear();
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
case ']':
|
||||||
|
endoflist = true;
|
||||||
|
goto case ',';
|
||||||
|
case '{':
|
||||||
|
{
|
||||||
|
object[] _value = new object[] { ReadDictionary() };
|
||||||
|
b.Clear();
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
case '=':
|
||||||
|
case ':':
|
||||||
|
case '}':
|
||||||
|
throw new Exception($"DtsodV30.Deserialize() error: unexpected {c}");
|
||||||
|
default:
|
||||||
|
b.Append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("DtsodV30.Deserialize.ReadValue() error: end of text\ntext:\n" + text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkipComment()
|
||||||
|
{
|
||||||
|
while (text[i] != '\n')
|
||||||
|
if (++i >= text.Length) throw new Exception("DtsodV30.Deserialize() error: end of text\ntext:\n" + text);
|
||||||
|
}
|
||||||
|
|
||||||
|
object CreateInstance(Type type, object[] ctor_args)
|
||||||
|
{
|
||||||
|
if (TypeHelper.BaseTypeConstructors.TryGetValue(type, out var ctor))
|
||||||
|
return (object)ctor.Invoke((string)ctor_args[0]);
|
||||||
|
else if (type.CustomAttributes.Any(a => a.AttributeType == typeof(DtsodSerializableAttribute)))
|
||||||
|
return Activator.CreateInstance(type, ctor_args);
|
||||||
|
else throw new Exception($"type {type.AssemblyQualifiedName} doesn't have DtsodSerializableAttribute");
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary<string, dynamic> output = new();
|
||||||
|
Type type;
|
||||||
|
string name;
|
||||||
|
object[] value;
|
||||||
|
|
||||||
|
for (; i < text.Length; i++)
|
||||||
|
{
|
||||||
|
type = ReadType();
|
||||||
|
name = ReadName();
|
||||||
|
value = ReadValue();
|
||||||
|
output.Add(name, CreateInstance(type, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Append(ICollection<KeyValuePair<string, dynamic>> anotherDtsod)
|
||||||
|
{
|
||||||
|
base.Append(anotherDtsod);
|
||||||
|
//UpdateLazy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Add(string key, dynamic value)
|
||||||
|
{
|
||||||
|
base.Add(key, (object)value);
|
||||||
|
//UpdateLazy();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static string Serialize(IDictionary<string, dynamic> dtsod, ushort tabsCount = 0)
|
||||||
|
{
|
||||||
|
StringBuilder b = new();
|
||||||
|
foreach (var pair in dtsod)
|
||||||
|
{
|
||||||
|
Type type = pair.Value.GetType();
|
||||||
|
b.Append(TypeHelper.TypeToString(type)).Append(':')
|
||||||
|
.Append(pair.Key).Append('=');
|
||||||
|
if (TypeHelper.BaseTypeNames.ContainsKey(type))
|
||||||
|
{
|
||||||
|
if (type == typeof(decimal) || type == typeof(double) || type == typeof(float))
|
||||||
|
b.Append(pair.Value.ToString(CultureInfo.InvariantCulture));
|
||||||
|
else b.Append(pair.Value.ToString());
|
||||||
|
}
|
||||||
|
else if (typeof(IDictionary<string, dynamic>).IsAssignableFrom(type))
|
||||||
|
b.Append("\n{\n").Append(Serialize(pair.Value, tabsCount++)).Append("};\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type.GetProperties().Where(p => p.CustomAttributes.Any(a => a.AttributeType == typeof(DtsodSerializableAttribute)));
|
||||||
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return b.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Lazy<string> serialized;
|
||||||
|
protected void UpdateLazy() => serialized = new(() => Serialize(this));
|
||||||
|
public override string ToString() => serialized.Value;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
namespace DTLib.Dtsod
|
|
||||||
{
|
|
||||||
public enum DtsodVersion : byte
|
|
||||||
{
|
|
||||||
V21 = 21,
|
|
||||||
V22 = 22,
|
|
||||||
V30 = 30
|
|
||||||
}
|
|
||||||
}
|
|
||||||
66
Dtsod/V30/TypeHelper.cs
Normal file
66
Dtsod/V30/TypeHelper.cs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
namespace DTLib.Dtsod;
|
||||||
|
|
||||||
|
public static class TypeHelper
|
||||||
|
{
|
||||||
|
static public readonly Dictionary<Type, Func<string, dynamic>> BaseTypeConstructors = new()
|
||||||
|
{
|
||||||
|
{ typeof(bool), (inp) => inp.ToBool() },
|
||||||
|
{ typeof(char), (inp) => inp.ToChar() },
|
||||||
|
{ typeof(string), (inp) => inp.ToString() },
|
||||||
|
{ typeof(byte), (inp) => inp.ToByte() },
|
||||||
|
{ typeof(sbyte), (inp) => inp.ToSByte() },
|
||||||
|
{ typeof(short), (inp) => inp.ToShort() },
|
||||||
|
{ typeof(ushort), (inp) => inp.ToUShort() },
|
||||||
|
{ typeof(int), (inp) => inp.ToInt() },
|
||||||
|
{ typeof(uint), (inp) => inp.ToUInt() },
|
||||||
|
{ typeof(long), (inp) => inp.ToLong() },
|
||||||
|
{ typeof(ulong), (inp) => inp.ToULong() },
|
||||||
|
{ typeof(float), (inp) => inp.ToFloat() },
|
||||||
|
{ typeof(double), (inp) => inp.ToDouble() },
|
||||||
|
{ typeof(decimal), (inp) => inp.ToDecimal() }
|
||||||
|
};
|
||||||
|
|
||||||
|
static public Dictionary<Type, string> BaseTypeNames = new()
|
||||||
|
{
|
||||||
|
{ typeof(bool), "bool" },
|
||||||
|
{ typeof(char), "char" },
|
||||||
|
{ typeof(string), "string" },
|
||||||
|
{ typeof(byte), "byte" },
|
||||||
|
{ typeof(sbyte), "sbyte" },
|
||||||
|
{ typeof(short), "short" },
|
||||||
|
{ typeof(ushort), "ushort" },
|
||||||
|
{ typeof(int), "int" },
|
||||||
|
{ typeof(uint), "uint" },
|
||||||
|
{ typeof(long), "long" },
|
||||||
|
{ typeof(ulong), "ulong" },
|
||||||
|
{ typeof(float), "float" },
|
||||||
|
{ typeof(double), "double" },
|
||||||
|
{ typeof(decimal), "decimal" }
|
||||||
|
};
|
||||||
|
|
||||||
|
static public string TypeToString(Type t) =>
|
||||||
|
BaseTypeNames.TryGetValue(t, out var name)
|
||||||
|
? name
|
||||||
|
: t.AssemblyQualifiedName;
|
||||||
|
|
||||||
|
static public Type TypeFromString(string str) => str switch
|
||||||
|
{
|
||||||
|
"bool" => typeof(bool),
|
||||||
|
"char" => typeof(char),
|
||||||
|
"string" => typeof(string),
|
||||||
|
"byte" => typeof(byte),
|
||||||
|
"sbyte" => typeof(sbyte),
|
||||||
|
"short" => typeof(short),
|
||||||
|
"ushort" => typeof(ushort),
|
||||||
|
"int" => typeof(int),
|
||||||
|
"uint" => typeof(uint),
|
||||||
|
"long" => typeof(long),
|
||||||
|
"ulong" => typeof(ulong),
|
||||||
|
"float" => typeof(float),
|
||||||
|
"double" => typeof(double),
|
||||||
|
"decimal" => typeof(decimal),
|
||||||
|
_ => Type.GetType(str, false) ??
|
||||||
|
throw new Exception($"DtsodV30.Deserialize.ParseType() error: type {str} doesn't exists")
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user