new dtsod parser

This commit is contained in:
Timerix 2021-07-21 22:54:35 +03:00
parent 4957b7a406
commit 17915621f3
6 changed files with 503 additions and 64 deletions

View File

@ -35,6 +35,7 @@
<Compile Include="CompressedArray.cs" />
<Compile Include="Dtsod.cs" />
<Compile Include="cs9somefix.cs" />
<Compile Include="DtsodParser2.cs" />
<Compile Include="Filework.cs" />
<Compile Include="ColoredConsole.cs" />
<Compile Include="PublicLog.cs" />

View File

@ -1,23 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using static DTLib.PublicLog;
namespace DTLib
{
//
// это как json но не совсем
//
public class Dtsod
public class Dtsod : Dictionary<string, dynamic>
{
string Text;
public Dictionary<string, dynamic> Values { get; }
static readonly bool debug = false;
public string Text { get; }
//public Dictionary<string, dynamic> Values { get; set; }
public Dtsod(string text)
{
Text = text;
Values = Parse(text);
foreach (KeyValuePair<string, dynamic> pair in ParseNew(text))
Add(pair.Key, pair.Value);
}
// выдаёт Exception
/*// выдаёт Exception
public dynamic this[string key]
{
get
@ -25,6 +30,11 @@ namespace DTLib
if (TryGet(key, out dynamic value)) return value;
else throw new Exception($"Dtsod[{key}] key not found");
}
set
{
if (TrySet(key, value)) return;
else throw new Exception($"Dtsod[{key}] key not found");
}
}
// не выдаёт KeyNotFoundException
@ -37,16 +47,246 @@ namespace DTLib
}
catch (KeyNotFoundException)
{
//PublicLog.Log("y", $"key {key} not found\n");
value = null;
return false;
}
}
public bool TrySet(string key, dynamic value)
{
try
{
Values[key] = value;
return true;
}
catch (KeyNotFoundException)
{
return false;
}
}*/
public override string ToString() => Text;
enum ValueType
{
List,
Complex,
String,
/*Double,
Long,
Ulong,
Short,
Ushort,
Int,
Uint,
Null,
Boolean,*/
Default
}
Dictionary<string, dynamic> Parse(string text)
Dictionary<string, dynamic> ParseNew(string text)
{
Dictionary<string, dynamic> parsed = new();
int i = 0;
for (; i < text.Length; i++) ReadName();
return parsed;
void ReadName()
{
void ReadCommentLine()
{
for (; i < text.Length && text[i] != '\n'; i++) ;
}
bool isListElem = false;
dynamic value = null;
StringBuilder defaultNameBuilder = new();
if (debug) LogNoTime("m", "ReadName");
for (; i < text.Length; i++)
{
if (debug) LogNoTime("w", text[i].ToString());
switch (text[i])
{
case ' ':
case '\t':
case '\r':
case '\n':
break;
case ':':
i++;
value = ReadValue();
string name = defaultNameBuilder.ToString();
if (debug) LogNoTime("c", $"parsed.Add({name}, {value})\n");
if (isListElem)
{
if (!parsed.ContainsKey(name)) parsed.Add(name, new List<dynamic>());
parsed[name].Add(value);
}
else parsed.Add(name, value);
if (debug) LogNoTime("g", "ReadName return\n");
return;
// строка, начинающаяся с # будет считаться комментом
case '#':
ReadCommentLine();
break;
case '}':
throw new Exception("Parse.ReadName() error: unexpected '}' at " + i + "char");
// если $ перед названием параметра поставить, значение value добавится в лист с названием name
case '$':
if (defaultNameBuilder.ToString().Length != 0) throw new Exception("unexpected usage of '$' at char " + i.ToString());
isListElem = true;
break;
case ';':
throw new Exception("Parse.ReadName() error: unexpected ';' at " + i + "char");
default:
defaultNameBuilder.Append(text[i]);
break;
}
}
}
dynamic ReadValue()
{
ValueType type = ValueType.Default;
string ReadString()
{
i++;
StringBuilder valueBuilder = new();
valueBuilder.Append('"');
for (; text[i] != '"' || text[i - 1] == '\\'; i++)
{
if (debug) LogNoTime("gray", text[i].ToString());
valueBuilder.Append(text[i]);
}
valueBuilder.Append('"');
if (debug) LogNoTime("gray", text[i].ToString());
type = ValueType.String;
return valueBuilder.ToString();
}
List<dynamic> ReadList()
{
i++;
List<dynamic> output = new();
StringBuilder valueBuilder = new();
for (; text[i] != ']'; i++)
{
if (debug) LogNoTime("c", text[i].ToString());
switch (text[i])
{
case ' ':
case '\t':
case '\r':
case '\n':
break;
case ',':
output.Add(ParseValueToRightType(valueBuilder.ToString()));
valueBuilder.Clear();
break;
default:
valueBuilder.Append(text[i]);
break;
}
}
output.Add(ParseValueToRightType(valueBuilder.ToString()));
if (debug) LogNoTime("c", text[i].ToString());
type = ValueType.List;
return output;
}
Dictionary<string, dynamic> ReadComplex()
{
i++;
StringBuilder valueBuilder = new();
for (; text[i] != '}'; i++)
{
if (debug) LogNoTime("y", text[i].ToString());
if (text[i] == '"')
{
valueBuilder.Append(ReadString());
}
else valueBuilder.Append(text[i]);
}
if (debug) LogNoTime("y", text[i].ToString());
type = ValueType.Complex;
if (debug) LogNoTime("g", valueBuilder.ToString());
return ParseNew(valueBuilder.ToString());
}
dynamic ParseValueToRightType(string stringValue)
{
if (debug) LogNoTime("g", $"\nParseValueToRightType({stringValue})");
return stringValue switch
{
_ when stringValue.Contains('"') => stringValue.Remove(stringValue.Length - 1).Remove(0, 1),
// bool
"true" or "false" => stringValue.ToBool(),
// null
"null" => null,
// double
_ when stringValue.Contains('.') => stringValue.ToDouble(),
// ushort, ulong, uint
_ when (stringValue.Length > 2 && stringValue[stringValue.Length - 2] == 'u') => stringValue[stringValue.Length - 1] switch
{
's' => stringValue.Remove(stringValue.Length - 2).ToUShort(),
'i' => stringValue.Remove(stringValue.Length - 2).ToUInt(),
'l' => stringValue.Remove(stringValue.Length - 2).ToULong(),
_ => throw new Exception($"Dtsod.Parse.ReadValue() error: wrong type <u{stringValue[stringValue.Length - 1]}>")
},
// short, long, int
_ => stringValue[stringValue.Length - 1] switch
{
's' => stringValue.Remove(stringValue.Length - 1).ToShort(),
'l' => stringValue.Remove(stringValue.Length - 1).ToLong(),
_ => stringValue.ToInt()
}
};
}
dynamic value = null;
StringBuilder defaultValueBuilder = new();
if (debug) LogNoTime("m", "\nReadValue\n");
for (; i < text.Length; i++)
{
if (debug) LogNoTime("b", text[i].ToString());
switch (text[i])
{
case ' ':
case '\t':
case '\r':
case '\n':
break;
case '"':
value = ReadString();
break;
case ';':
if (debug) LogNoTime("g", $"\nReadValue returns type {type} value <{value}>\n");
return type switch
{
ValueType.List or ValueType.Complex => value,
ValueType.String => ParseValueToRightType(value),
ValueType.Default => ParseValueToRightType(defaultValueBuilder.ToString()),
_ => throw new Exception($"Dtlib.Parse.ReadValue() error: can't convert value to type <{type}>")
};
case '[':
value = ReadList();
break;
case '{':
value = ReadComplex();
break;
default:
defaultValueBuilder.Append(text[i]);
break;
}
}
throw new Exception("Dtsod.Parse.ReadValue error: end of text");
}
}
Dictionary<string, dynamic> ParseOld(string text)
{
Dictionary<string, dynamic> output = new();
StringBuilder nameStrB = new();
@ -59,13 +299,17 @@ namespace DTLib
dynamic StringToElse(string str)
{
//PublicLog.Log("m", $"StringToElse({str})\n");
if (readString) return str;
// bool
if (str == "true") return true;
else if (str == "false") return false;
switch (str)
{
// предустановленные значения
case "true": return true;
case "false": return false;
case "null": return null;
default:
// double
else if (str.Contains(".")) return SimpleConverter.ToDouble(str);
if (str.Contains(".")) return SimpleConverter.ToDouble(str);
// ushort, uint, ulong
else if (str.Length > 2 && str[str.Length - 2] == 'u')
return str[str.Length - 1] switch
@ -83,39 +327,40 @@ namespace DTLib
_ => SimpleConverter.ToInt(str),
};
}
}
for (int i = 0; i < text.Length; i++)
{
if (debug) LogNoTime(text[i].ToString());
void ReadString()
{
i++;
while (text[i] != '"' || text[i - 1] == '\\')
{
if (debug) LogNoTime(text[i].ToString());
valStrB.Append(text[i]);
i++;
}
}
switch (text[i])
{
case '{':
i++;
for (; text[i] != '}'; i++) valStrB.Append(text[i]);
value = Parse(valStrB.ToString());
for (; text[i] != '}'; i++)
{
if (text[i] == '"') ReadString();
else valStrB.Append(text[i]);
}
value = ParseOld(valStrB.ToString());
valStrB.Clear();
break;
case '}':
throw new Exception("ParseConfig() error: unexpected '}' at " + i + "char");
case '<':
readString = true;
short balance = 1;
while (balance != 0)
{
i++;
if (text[i] == '>') balance--;
else if (text[i] == '<') balance++;
valStrB.Append(text[i]);
}
valStrB.Remove(valStrB.Length - 1, 1);
break;
case '"':
readString = true;
i++;
while (text[i] != '"' || text[i - 1] == '\\')
{
valStrB.Append(text[i]);
i++;
}
ReadString();
break;
case ':':
readValue = true;
@ -169,7 +414,5 @@ namespace DTLib
}
return output;
}
}
}

207
DTLib/DtsodParser2.cs Normal file
View File

@ -0,0 +1,207 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DTLib
{
class DtsodParser2
{
enum ValueType
{
List,
Complex,
String,
Double,
Long,
Ulong,
Short,
Ushort,
Int,
Uint,
Null,
Boolean,
Default
}
Dictionary<string, dynamic> ParseNew(string text)
{
Dictionary<string, dynamic> parsed = new();
int i = 0;
for (; i < text.Length; i++) ReadName();
return parsed;
void ReadName()
{
bool isListElem = false;
void ReadCommentLine()
{
for (; i < text.Length && text[i] != '\n'; i++) ;
}
dynamic value = null;
StringBuilder defaultNameBuilder = new();
for (; i < text.Length; i++)
{
switch (text[i])
{
case ' ':
case '\t':
case '\r':
case '\n':
break;
case ':':
value = ReadValue();
break;
// строка, начинающаяся с # будет считаться комментом
case '#':
ReadCommentLine();
break;
case '}':
throw new Exception("ParseConfig() error: unexpected '}' at " + i + "char");
// если $ перед названием параметра поставить, значение value добавится в лист с названием name
case '$':
if (defaultNameBuilder.ToString().Length != 0) throw new Exception("unexpected usage of '$' at char " + i.ToString());
isListElem = true;
break;
case ';':
string name = defaultNameBuilder.ToString();
if (isListElem)
{
if (!parsed.ContainsKey(name)) parsed.Add(name, new List<dynamic>());
parsed[name].Add(value);
}
else parsed.Add(name, value);
return;
default:
defaultNameBuilder.Append(text[i]);
break;
}
}
}
dynamic ReadValue()
{
ValueType type = ValueType.Default;
string ReadString()
{
i++;
StringBuilder valueBuilder = new();
for (; text[i] != '"' || text[i - 1] == '\\'; i++)
valueBuilder.Append(text[i]);
type = ValueType.String;
return valueBuilder.ToString();
}
List<string> ReadList()
{
List<string> output = new();
StringBuilder valueBuilder = new();
for (; text[i] != ']'; i++)
{
switch (text[i])
{
case ' ':
case '\t':
case '\r':
case '\n':
break;
case ',':
output.Add(valueBuilder.ToString());
break;
default:
valueBuilder.Append(text[i]);
break;
}
}
type = ValueType.List;
return output;
}
Dictionary<string, dynamic> ReadComplex()
{
i++;
StringBuilder valueBuilder = new();
for (; text[i] != '}'; i++)
{
if (text[i] == '"') valueBuilder.Append(ReadString());
else valueBuilder.Append(text[i]);
}
type = ValueType.Complex;
return ParseNew(valueBuilder.ToString());
}
dynamic value = null;
StringBuilder defaultValueBuilder = new();
for (; i < text.Length; i++)
{
switch (text[i])
{
case ' ':
case '\t':
case '\r':
case '\n':
break;
case '"':
value = ReadString();
break;
case ';':
if (type == ValueType.Default)
{
string valueString = defaultValueBuilder.ToString();
type = valueString switch
{
"true" or "false" => ValueType.Boolean,
"null" => ValueType.Null,
_ when valueString.Contains('.') => ValueType.Null,
_ when (valueString.Length > 2 && valueString[valueString.Length - 2] == 'u') => valueString[valueString.Length - 1] switch
{
's' => ValueType.Ushort,
'i' => ValueType.Uint,
'l' => ValueType.Ulong,
_ => throw new Exception($"Dtsod.Parse.ReadValue() error: wrong type <u{valueString[valueString.Length - 1]}>")
},
_ => valueString[valueString.Length - 1] switch
{
's' => ValueType.Short,
'l' => ValueType.Long,
_ => ValueType.Int
}
};
}
return type switch
{
ValueType.String or ValueType.List or ValueType.Complex => value,
ValueType.Double => SimpleConverter.ToDouble(value),
ValueType.Long => SimpleConverter.ToLong(value.Remove(value.Length - 1)),
ValueType.Ulong => SimpleConverter.ToULong(value.Remove(value.Length - 2)),
ValueType.Short => SimpleConverter.ToShort(value.Remove(value.Length - 1)),
ValueType.Ushort => SimpleConverter.ToUShort(value.Remove(value.Length - 2)),
ValueType.Int => SimpleConverter.ToInt(value),
ValueType.Uint => SimpleConverter.ToUInt(value),
ValueType.Boolean => SimpleConverter.ToBool(value),
ValueType.Null => null,
_ => throw new Exception($"Dtlib.Parse.ReadValue() error: can't convert value to type <{type}>")
};
case '[':
value = ReadList();
break;
case '{':
value = ReadComplex();
break;
default:
defaultValueBuilder.Append(text[i]);
break;
}
}
throw new Exception("Dtsod.Parse.ReadValue error: end of text");
}
}
}
}

View File

@ -224,7 +224,6 @@ namespace DTLib
public static void AppendAllBytes(string file, byte[] content)
{
File.Create(file);
using var stream = File.OpenAppend(file);
stream.Write(content, 0, content.Length);
stream.Close();

View File

@ -4,8 +4,8 @@ using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using static DTLib.PublicLog;
using static DTLib.Filework;
using static DTLib.PublicLog;
namespace DTLib
{
@ -248,7 +248,7 @@ namespace DTLib
var manifest = new Dtsod(File.ReadAllText("TEMP\\manifest.dtsod"));
Log("g", $"found {manifest.Values.Count} files in manifest\n");
var hasher = new Hasher();
foreach (string fileOnServer in manifest.Values.Keys)
foreach (string fileOnServer in manifest.Keys)
{
string fileOnClient = $"{dirOnClient}\\{fileOnServer}";
Log("b", "file <", "c", fileOnClient, "b", ">... ");

View File

@ -95,17 +95,6 @@ namespace DTLib
}
return b.ToString();
}
public static string MergeToString<T>(this List<T> list, string separator)
{
var b = new StringBuilder();
b.Append(list[0].ToString());
for (int i = 1; i < list.Count; i++)
{
b.Append(separator);
b.Append(list[i].ToString());
}
return b.ToString();
}
// сокращение конвертации
public static int ToInt<T>(this T input) => Convert.ToInt32(input);