From 17915621f356bd8f9d6e478d70260c803b7b9ee6 Mon Sep 17 00:00:00 2001 From: Timerix Date: Wed, 21 Jul 2021 22:54:35 +0300 Subject: [PATCH] new dtsod parser --- DTLib/DTLib.csproj | 1 + DTLib/Dtsod.cs | 341 +++++++++++++++++++++++++++++++++------ DTLib/DtsodParser2.cs | 207 ++++++++++++++++++++++++ DTLib/Filework.cs | 3 +- DTLib/Network.cs | 4 +- DTLib/SimpleConverter.cs | 11 -- 6 files changed, 503 insertions(+), 64 deletions(-) create mode 100644 DTLib/DtsodParser2.cs diff --git a/DTLib/DTLib.csproj b/DTLib/DTLib.csproj index 21cd6b5..03492d5 100644 --- a/DTLib/DTLib.csproj +++ b/DTLib/DTLib.csproj @@ -35,6 +35,7 @@ + diff --git a/DTLib/Dtsod.cs b/DTLib/Dtsod.cs index 1539fec..02c4f0a 100644 --- a/DTLib/Dtsod.cs +++ b/DTLib/Dtsod.cs @@ -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 Text; - public Dictionary Values { get; } + static readonly bool debug = false; + + public string Text { get; } + //public Dictionary Values { get; set; } public Dtsod(string text) { Text = text; - Values = Parse(text); + foreach (KeyValuePair 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 Parse(string text) + Dictionary ParseNew(string text) + { + Dictionary 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()); + 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 ReadList() + { + i++; + List 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 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 ") + }, + // 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 ParseOld(string text) { Dictionary output = new(); StringBuilder nameStrB = new(); @@ -59,63 +299,68 @@ 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; - // double - else 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 - { - 's' => SimpleConverter.ToUShort(str.Remove(str.Length - 2)), - 'i' => SimpleConverter.ToUInt(str.Remove(str.Length - 2)), - 'l' => SimpleConverter.ToULong(str.Remove(str.Length - 2)), - _ => throw new Exception($"ParseConfig() error: unknown data type "), - }; - // short, int, long - else return str[str.Length - 1] switch + switch (str) { - 's' => SimpleConverter.ToShort(str.Remove(str.Length - 1)), - 'l' => SimpleConverter.ToLong(str.Remove(str.Length - 1)), - _ => SimpleConverter.ToInt(str), - }; + // предустановленные значения + case "true": return true; + case "false": return false; + case "null": return null; + default: + // double + 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 + { + 's' => SimpleConverter.ToUShort(str.Remove(str.Length - 2)), + 'i' => SimpleConverter.ToUInt(str.Remove(str.Length - 2)), + 'l' => SimpleConverter.ToULong(str.Remove(str.Length - 2)), + _ => throw new Exception($"ParseConfig() error: unknown data type "), + }; + // short, int, long + else return str[str.Length - 1] switch + { + 's' => SimpleConverter.ToShort(str.Remove(str.Length - 1)), + 'l' => SimpleConverter.ToLong(str.Remove(str.Length - 1)), + _ => 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; } - - } } diff --git a/DTLib/DtsodParser2.cs b/DTLib/DtsodParser2.cs new file mode 100644 index 0000000..b2ade7e --- /dev/null +++ b/DTLib/DtsodParser2.cs @@ -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 ParseNew(string text) + { + Dictionary 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()); + 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 ReadList() + { + List 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 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 ") + }, + _ => 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"); + } + } + } +} diff --git a/DTLib/Filework.cs b/DTLib/Filework.cs index 1978c9a..36bbb05 100644 --- a/DTLib/Filework.cs +++ b/DTLib/Filework.cs @@ -192,7 +192,7 @@ namespace DTLib } } - public static void Copy(string srcPath, string newPath, bool replace = false) + public static void Copy(string srcPath, string newPath, bool replace = false) { if (!replace && Exists(newPath)) throw new Exception($"file <{newPath}> alredy exists"); Create(newPath); @@ -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(); diff --git a/DTLib/Network.cs b/DTLib/Network.cs index 5d7e75a..31b7c37 100644 --- a/DTLib/Network.cs +++ b/DTLib/Network.cs @@ -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", ">... "); diff --git a/DTLib/SimpleConverter.cs b/DTLib/SimpleConverter.cs index 4aacf9c..22bb7a5 100644 --- a/DTLib/SimpleConverter.cs +++ b/DTLib/SimpleConverter.cs @@ -95,17 +95,6 @@ namespace DTLib } return b.ToString(); } - public static string MergeToString(this List 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(this T input) => Convert.ToInt32(input);