From 8055ab3162a402019be4af44c241d7663bf36f94 Mon Sep 17 00:00:00 2001 From: Mohammad Hadi Hosseinpour Date: Fri, 7 Apr 2017 05:52:55 +0430 Subject: [PATCH] Improved TL2JSON and formatted code a bit --- TeleSharp.Generator/Models.cs | 89 ++++++++++++-- TeleSharp.Generator/Program.cs | 207 +++++++++++++++++---------------- TeleSharp.Generator/TL2JSON.cs | 103 ++++++++-------- 3 files changed, 237 insertions(+), 162 deletions(-) diff --git a/TeleSharp.Generator/Models.cs b/TeleSharp.Generator/Models.cs index 8e43820..b379a1d 100644 --- a/TeleSharp.Generator/Models.cs +++ b/TeleSharp.Generator/Models.cs @@ -8,29 +8,98 @@ namespace TeleSharp.Generator { class Method { - public int id { get; set; } - public string method { get; set; } + [Newtonsoft.Json.JsonProperty("id")] + public int Id { get; set; } + + [Newtonsoft.Json.JsonProperty("method")] + public string MethodName { get; set; } + [Newtonsoft.Json.JsonProperty("params")] public List Params { get; set; } - public string type { get; set; } + [Newtonsoft.Json.JsonProperty("type")] + public string ResponseType { get; set; } + + public override bool Equals(Object obj) + { + return obj is Method && this == (Method)obj; + } + public override int GetHashCode() + { + return Id.GetHashCode() ^ MethodName.GetHashCode() ^ Params.GetHashCode() ^ ResponseType.GetHashCode(); + } + public static bool operator ==(Method x, Method y) + { + return Enumerable.SequenceEqual(x.Params, y.Params) && x.MethodName == y.MethodName && x.ResponseType == y.ResponseType && x.Id == y.Id; + } + public static bool operator !=(Method x, Method y) + { + return !(x == y); + } } class Param { - public string name { get; set; } - public string type { get; set; } + [Newtonsoft.Json.JsonProperty("name")] + public string Name { get; set; } + + [Newtonsoft.Json.JsonProperty("type")] + public string Type { get; set; } } class Constructor { - public int id { get; set; } - public string predicate { get; set; } + [Newtonsoft.Json.JsonProperty("id")] + public int Id { get; set; } + + [Newtonsoft.Json.JsonProperty("predicate")] + public string ConstructorName { get; set; } + [Newtonsoft.Json.JsonProperty("params")] public List Params { get; set; } - public string type { get; set; } + + [Newtonsoft.Json.JsonProperty("type")] + public string BaseType { get; set; } + + public override bool Equals(Object obj) + { + return obj is Constructor && this == (Constructor)obj; + } + public override int GetHashCode() + { + return Id.GetHashCode() ^ ConstructorName.GetHashCode() ^ Params.GetHashCode() ^ BaseType.GetHashCode(); + } + public static bool operator ==(Constructor x, Constructor y) + { + return Enumerable.SequenceEqual(x.Params, y.Params) && x.ConstructorName == y.ConstructorName && x.BaseType == y.BaseType && x.Id == y.Id; + } + public static bool operator !=(Constructor x, Constructor y) + { + return !(x == y); + } } class Schema { - public List constructors { get; set; } - public List methods { get; set; } + [Newtonsoft.Json.JsonProperty("constructors")] + public List Constructors { get; set; } + + [Newtonsoft.Json.JsonProperty("methods")] + public List Methods { get; set; } + + public override bool Equals(Object obj) + { + return obj is Schema && this == (Schema)obj; + } + public override int GetHashCode() + { + return Constructors.GetHashCode() ^ Methods.GetHashCode(); + } + public static bool operator ==(Schema x, Schema y) + { + return Enumerable.SequenceEqual(x.Methods.OrderBy(t=>t.MethodName),y.Methods.OrderBy(t => t.MethodName)) && + Enumerable.SequenceEqual(x.Constructors.OrderBy(t => t.ConstructorName), y.Constructors.OrderBy(t => t.ConstructorName)); + } + public static bool operator !=(Schema x, Schema y) + { + return !(x == y); + } } } diff --git a/TeleSharp.Generator/Program.cs b/TeleSharp.Generator/Program.cs index aa0ca72..9f0444e 100644 --- a/TeleSharp.Generator/Program.cs +++ b/TeleSharp.Generator/Program.cs @@ -147,8 +147,7 @@ namespace TeleSharp.Generator Console.WriteLine("Try `TeleSharp.Generator --help' for more information."); return; } - - + inputPath = extra[0]; if (!forceFormat) { @@ -189,24 +188,25 @@ namespace TeleSharp.Generator #region Translate to C# Schema schema = JsonConvert.DeserializeObject(Json); - foreach (var c in schema.constructors) + foreach (var c in schema.Constructors) { - interfacesList.Add(c.type); - classesList.Add(c.predicate); + interfacesList.Add(c.BaseType); + classesList.Add(c.ConstructorName); } Console.WriteLine("Implementing abstract classes..."); - var abstractParams = new Dictionary>(); - foreach (var c in schema.constructors) + var abstractParams = new Dictionary>(); + #region Abstract classes + foreach (var c in schema.Constructors) { - var list = schema.constructors.Where(x => x.type == c.type); // check if there is a dependence on this type (it is an abstract class) + var list = schema.Constructors.Where(x => x.BaseType == c.BaseType); // check if there is a dependence on base type of this class (base type is an abstract class) if (list.Count() > 1) { - string path = Path.Combine(outputPath, GetNameSpace(c.type, TargetNamespace).Replace(TargetNamespace, @"TL\").Replace(".", ""), GetNameofClass(c.type, true) + ".cs").Replace(@"\\", @"\"); + string path = Path.Combine(outputPath, GetNameSpace(c.BaseType, TargetNamespace).Replace(TargetNamespace, @"TL\").Replace(".", ""), GetNameofClass(c.BaseType, true) + ".cs").Replace(@"\\", @"\"); FileStream classFile = MakeFile(path); using (StreamWriter writer = new StreamWriter(classFile)) { - string temp = AbsStyle.Replace("/* NAMESPACE */", GetNameSpace(c.type, TargetNamespace).TrimEnd('.')); - temp = temp.Replace("/* NAME */", GetNameofClass(c.type, true)); + string temp = AbsStyle.Replace("/* NAMESPACE */", GetNameSpace(c.BaseType, TargetNamespace).TrimEnd('.')); + temp = temp.Replace("/* NAME */", GetNameofClass(c.BaseType, true)); writer.Write(temp); writer.Close(); classFile.Close(); @@ -214,70 +214,70 @@ namespace TeleSharp.Generator } else { - interfacesList.Remove(list.First().type); - list.First().type = "himself"; + interfacesList.Remove(list.First().BaseType); + list.First().BaseType = "himself"; } } + #endregion + Console.WriteLine("Implementing types..."); - foreach (var c in schema.constructors) + #region Constructors + foreach (var c in schema.Constructors) { - string path = Path.Combine(outputPath, GetNameSpace(c.predicate, TargetNamespace).Replace(TargetNamespace, @"TL\").Replace(".", ""), GetNameofClass(c.predicate, false) + ".cs").Replace(@"\\", @"\"); + string path = Path.Combine(outputPath, GetNameSpace(c.ConstructorName, TargetNamespace).Replace(TargetNamespace, @"TL\").Replace(".", ""), GetNameofClass(c.ConstructorName, false) + ".cs").Replace(@"\\", @"\"); FileStream classFile = MakeFile(path); using (StreamWriter writer = new StreamWriter(classFile)) { #region About Class - string temp = NormalStyle.Replace("/* NAMESPACE */", GetNameSpace(c.predicate, TargetNamespace).TrimEnd('.')); - temp = (c.type == "himself") ? + string temp = NormalStyle.Replace("/* NAMESPACE */", GetNameSpace(c.ConstructorName, TargetNamespace).TrimEnd('.')); + temp = (c.BaseType == "himself") ? temp.Replace("/* PARENT */", "TLObject") : - temp.Replace("/* PARENT */", GetNameofClass(c.type, true)); - temp = temp.Replace("/*Constructor*/", c.id.ToString()); - temp = temp.Replace("/* NAME */", GetNameofClass(c.predicate, false)); + temp.Replace("/* PARENT */", GetNameofClass(c.BaseType, true)); + temp = temp.Replace("/*Constructor*/", c.Id.ToString()); + temp = temp.Replace("/* NAME */", GetNameofClass(c.ConstructorName, false)); #endregion #region Fields /* Note: Fields were mostly moved to abstract classes to provide maximum polymorphism usability. */ //string fields = ""; - string parent_name = GetNameofClass(c.type, true); - if (c.type != "himself") + string parent_name = GetNameofClass(c.BaseType, true); + + if (c.BaseType != "himself") { foreach (var tmp in c.Params) { - Property field = new Property - { - Type = CheckForFlagBase(tmp.type, GetTypeName(tmp.type)), - Name = CheckForKeyword(tmp.name) - }; - if (!abstractParams.ContainsKey(c.type)) - abstractParams.Add(c.type, new List()); - else if (!abstractParams[c.type].Contains(field)) - abstractParams[c.type].Add(field); + Param field = new Param {Name = tmp.Name, Type = tmp.Type}; + if (abstractParams.All(item => item.Key != c.BaseType)) + abstractParams.Add(c.BaseType, new List()); + else if (!abstractParams[c.BaseType].Any(f => f.Name == field.Name && f.Type == field.Type)) + abstractParams[c.BaseType].Add(field); } } else { string fields = ""; - foreach (var tmp in c.Params) + foreach (var param in c.Params) { - fields += $" public {CheckForFlagBase(tmp.type, GetTypeName(tmp.type))} {CheckForKeyword(tmp.name)} " + "{ get; set; }" + Environment.NewLine; + fields += $" public {CheckForFlagBase(param.Type, GetTypeName(param.Type))} {CheckForKeyword(param.Name)} " + "{ get; set; }" + Environment.NewLine; } temp = temp.Replace("/* PARAMS */", fields); } #endregion #region ComputeFlagFunc - if (!c.Params.Any(x => x.name == "flags")) temp = temp.Replace("/* COMPUTE */", ""); + if (c.Params.All(x => x.Name != "flags")) temp = temp.Replace("/* COMPUTE */", ""); else { var compute = "flags = 0;" + Environment.NewLine; - foreach (var param in c.Params.Where(x => IsFlagBase(x.type))) + foreach (var param in c.Params.Where(x => IsFlagBase(x.Type))) { - if (IsTrueFlag(param.type)) + if (IsTrueFlag(param.Type)) { - compute += $"flags = {CheckForKeyword(param.name)} ? (flags | {GetBitMask(param.type)}) : (flags & ~{GetBitMask(param.type)});" + Environment.NewLine; + compute += $"flags = {CheckForKeyword(param.Name)} ? (flags | {GetBitMask(param.Type)}) : (flags & ~{GetBitMask(param.Type)});" + Environment.NewLine; } else { - compute += $"flags = {CheckForKeyword(param.name)} != null ? (flags | {GetBitMask(param.type)}) : (flags & ~{GetBitMask(param.type)});" + Environment.NewLine; + compute += $"flags = {CheckForKeyword(param.Name)} != null ? (flags | {GetBitMask(param.Type)}) : (flags & ~{GetBitMask(param.Type)});" + Environment.NewLine; } } temp = temp.Replace("/* COMPUTE */", compute); @@ -286,9 +286,9 @@ namespace TeleSharp.Generator #region SerializeFunc var serialize = ""; - if (c.Params.Any(x => x.name == "flags")) + if (c.Params.Any(x => x.Name == "flags")) serialize += "ComputeFlags();" + Environment.NewLine + "bw.Write(flags);" + Environment.NewLine; - foreach (var p in c.Params.Where(x => x.name != "flags")) + foreach (var p in c.Params.Where(x => x.Name != "flags")) { serialize += WriteWriteCode(p) + Environment.NewLine; } @@ -308,42 +308,45 @@ namespace TeleSharp.Generator classFile.Close(); } } + #endregion + Console.WriteLine("Implementing methods..."); - foreach (var c in schema.methods) + #region Methods + foreach (var c in schema.Methods) { - string path = Path.Combine(outputPath, GetNameSpace(c.method, TargetNamespace).Replace(TargetNamespace, @"TL\").Replace(".", ""), GetNameofClass(c.method, false, true) + ".cs").Replace(@"\\", @"\"); + string path = Path.Combine(outputPath, GetNameSpace(c.MethodName, TargetNamespace).Replace(TargetNamespace, @"TL\").Replace(".", ""), GetNameofClass(c.MethodName, false, true) + ".cs").Replace(@"\\", @"\"); FileStream classFile = MakeFile(path); using (StreamWriter writer = new StreamWriter(classFile)) { #region About Class - string temp = MethodStyle.Replace("/* NAMESPACE */", GetNameSpace(c.method, TargetNamespace).TrimEnd('.')); + string temp = MethodStyle.Replace("/* NAMESPACE */", GetNameSpace(c.MethodName, TargetNamespace).TrimEnd('.')); temp = temp.Replace("/* PARENT */", "TLMethod"); - temp = temp.Replace("/*Constructor*/", c.id.ToString()); - temp = temp.Replace("/* NAME */", GetNameofClass(c.method, false, true)); + temp = temp.Replace("/*Constructor*/", c.Id.ToString()); + temp = temp.Replace("/* NAME */", GetNameofClass(c.MethodName, false, true)); #endregion #region Fields string fields = ""; foreach (var tmp in c.Params) { - fields += $" public {CheckForFlagBase(tmp.type, GetTypeName(tmp.type))} {CheckForKeyword(tmp.name)} " + "{get;set;}" + Environment.NewLine; + fields += $" public {CheckForFlagBase(tmp.Type, GetTypeName(tmp.Type))} {CheckForKeyword(tmp.Name)} " + "{ get; set; }" + Environment.NewLine; } - fields += $" public {CheckForFlagBase(c.type, GetTypeName(c.type))} Response" + "{ get; set;}" + Environment.NewLine; + fields += $" public {CheckForFlagBase(c.ResponseType, GetTypeName(c.ResponseType))} Response" + "{ get; set; }" + Environment.NewLine; temp = temp.Replace("/* PARAMS */", fields); #endregion #region ComputeFlagFunc - if (!c.Params.Any(x => x.name == "flags")) temp = temp.Replace("/* COMPUTE */", ""); + if (!c.Params.Any(x => x.Name == "flags")) temp = temp.Replace("/* COMPUTE */", ""); else { var compute = "flags = 0;" + Environment.NewLine; - foreach (var param in c.Params.Where(x => IsFlagBase(x.type))) + foreach (var param in c.Params.Where(x => IsFlagBase(x.Type))) { - if (IsTrueFlag(param.type)) + if (IsTrueFlag(param.Type)) { - compute += $"flags = {CheckForKeyword(param.name)} ? (flags | {GetBitMask(param.type)}) : (flags & ~{GetBitMask(param.type)});" + Environment.NewLine; + compute += $"flags = {CheckForKeyword(param.Name)} ? (flags | {GetBitMask(param.Type)}) : (flags & ~{GetBitMask(param.Type)});" + Environment.NewLine; } else { - compute += $"flags = {CheckForKeyword(param.name)} != null ? (flags | {GetBitMask(param.type)}) : (flags & ~{GetBitMask(param.type)});" + Environment.NewLine; + compute += $"flags = {CheckForKeyword(param.Name)} != null ? (flags | {GetBitMask(param.Type)}) : (flags & ~{GetBitMask(param.Type)});" + Environment.NewLine; } } temp = temp.Replace("/* COMPUTE */", compute); @@ -352,8 +355,8 @@ namespace TeleSharp.Generator #region SerializeFunc var serialize = ""; - if (c.Params.Any(x => x.name == "flags")) serialize += "ComputeFlags();" + Environment.NewLine + "bw.Write(flags);" + Environment.NewLine; - foreach (var p in c.Params.Where(x => x.name != "flags")) + if (c.Params.Any(x => x.Name == "flags")) serialize += "ComputeFlags();" + Environment.NewLine + "bw.Write(flags);" + Environment.NewLine; + foreach (var p in c.Params.Where(x => x.Name != "flags")) { serialize += WriteWriteCode(p) + Environment.NewLine; } @@ -370,7 +373,7 @@ namespace TeleSharp.Generator #endregion #region DeSerializeRespFunc var deserializeResp = ""; - Param p2 = new Param() { name = "Response", type = c.type }; + Param p2 = new Param() { Name = "Response", Type = c.ResponseType }; deserializeResp += WriteReadCode(p2) + Environment.NewLine; temp = temp.Replace("/* DESERIALIZEResp */", deserializeResp); #endregion @@ -379,28 +382,28 @@ namespace TeleSharp.Generator classFile.Close(); } } + #endregion + Console.WriteLine("Adding fields to abstract classes..."); // add fields to abstract classes - foreach (KeyValuePair> absClass in abstractParams) + foreach (KeyValuePair> absClass in abstractParams) { - if(absClass.Key == "himself") - throw new InvalidOperationException("ARGH! It was a class without a parent, why it came into the list? :|"); string path = Path.Combine(outputPath, GetNameSpace(absClass.Key, TargetNamespace).Replace(TargetNamespace, @"TL\").Replace(".", ""), GetNameofClass(absClass.Key, true) + ".cs").Replace(@"\\", @"\"); string tmp = File.ReadAllText(path); tmp = tmp.Replace("/* PARAMS */", ConvertPropertyList(absClass.Value)); File.WriteAllText(path, tmp); } - #endregion + Console.WriteLine("Done."); } - public static string ConvertPropertyList(List list) + public static string ConvertPropertyList(List list) { string output = ""; - foreach (var property in list) + foreach (var param in list) { - output += $" public {property.Type} {property.Name} {{ get; set; }}" + Environment.NewLine; + output += $" public {CheckForFlagBase(param.Type, GetTypeName(param.Type))} {CheckForKeyword(param.Name)} " + "{ get; set; }" + Environment.NewLine; } return output; } @@ -470,13 +473,16 @@ namespace TeleSharp.Generator { if (type.IndexOf('?') == -1) return result; - else - { - string innerType = type.Split('?')[1]; - if (innerType == "true") return result; - else if ((new string[] { "bool", "int", "uint", "long", "double" }).Contains(result)) return result + "?"; - else return result; - } + + string innerType = type.Split('?')[1]; + + if (innerType == "true") + return result; + + if ((new string[] { "bool", "int", "uint", "long", "BigMath.Int128", "BigMath.Int256", "double" }).Contains(result)) + return result + "?"; + + return result; } public static string GetTypeName(string type) { @@ -485,6 +491,10 @@ namespace TeleSharp.Generator case "#": case "int": return "int"; + case "int128": + return "BigMath.Int128"; + case "int256": + return "BigMath.Int256"; case "uint": return "uint"; case "long": @@ -514,7 +524,6 @@ namespace TeleSharp.Generator if (type.IndexOf('.') != -1 && type.IndexOf('?') == -1) { - if (interfacesList.Any(x => x.ToLower() == (type).ToLower())) return FormatName(type.Split('.')[0]) + "." + "TLAbs" + type.Split('.')[1]; else if (classesList.Any(x => x.ToLower() == (type).ToLower())) @@ -549,34 +558,34 @@ namespace TeleSharp.Generator } public static string WriteWriteCode(Param p, bool flag = false) { - switch (p.type.ToLower()) + switch (p.Type.ToLower()) { case "#": case "int": - return flag ? $"bw.Write({CheckForKeyword(p.name)}.Value);" : $"bw.Write({CheckForKeyword(p.name)});"; + return flag ? $"bw.Write({CheckForKeyword(p.Name)}.Value);" : $"bw.Write({CheckForKeyword(p.Name)});"; case "long": - return flag ? $"bw.Write({CheckForKeyword(p.name)}.Value);" : $"bw.Write({CheckForKeyword(p.name)});"; + return flag ? $"bw.Write({CheckForKeyword(p.Name)}.Value);" : $"bw.Write({CheckForKeyword(p.Name)});"; case "string": - return $"StringUtil.Serialize({CheckForKeyword(p.name)},bw);"; + return $"StringUtil.Serialize({CheckForKeyword(p.Name)},bw);"; case "bool": - return flag ? $"BoolUtil.Serialize({CheckForKeyword(p.name)}.Value,bw);" : $"BoolUtil.Serialize({CheckForKeyword(p.name)},bw);"; + return flag ? $"BoolUtil.Serialize({CheckForKeyword(p.Name)}.Value,bw);" : $"BoolUtil.Serialize({CheckForKeyword(p.Name)},bw);"; case "true": - return $"BoolUtil.Serialize({CheckForKeyword(p.name)},bw);"; + return $"BoolUtil.Serialize({CheckForKeyword(p.Name)},bw);"; case "bytes": - return $"BytesUtil.Serialize({CheckForKeyword(p.name)},bw);"; + return $"BytesUtil.Serialize({CheckForKeyword(p.Name)},bw);"; case "double": - return flag ? $"bw.Write({CheckForKeyword(p.name)}.Value);" : $"bw.Write({CheckForKeyword(p.name)});"; + return flag ? $"bw.Write({CheckForKeyword(p.Name)}.Value);" : $"bw.Write({CheckForKeyword(p.Name)});"; default: - if (!IsFlagBase(p.type)) - return $"ObjectUtils.SerializeObject({CheckForKeyword(p.name)},bw);"; + if (!IsFlagBase(p.Type)) + return $"ObjectUtils.SerializeObject({CheckForKeyword(p.Name)},bw);"; else { - if (IsTrueFlag(p.type)) + if (IsTrueFlag(p.Type)) return $""; else { - Param p2 = new Param() { name = p.name, type = p.type.Split('?')[1] }; - return $"if ((flags & {GetBitMask(p.type).ToString()}) != 0)" + Environment.NewLine + + Param p2 = new Param() { Name = p.Name, Type = p.Type.Split('?')[1] }; + return $"if ((flags & {GetBitMask(p.Type).ToString()}) != 0)" + Environment.NewLine + WriteWriteCode(p2, true); } } @@ -584,42 +593,42 @@ namespace TeleSharp.Generator } public static string WriteReadCode(Param p) { - switch (p.type.ToLower()) + switch (p.Type.ToLower()) { case "#": case "int": - return $"{CheckForKeyword(p.name)} = br.ReadInt32();"; + return $"{CheckForKeyword(p.Name)} = br.ReadInt32();"; case "long": - return $"{CheckForKeyword(p.name)} = br.ReadInt64();"; + return $"{CheckForKeyword(p.Name)} = br.ReadInt64();"; case "string": - return $"{CheckForKeyword(p.name)} = StringUtil.Deserialize(br);"; + return $"{CheckForKeyword(p.Name)} = StringUtil.Deserialize(br);"; case "bool": case "true": - return $"{CheckForKeyword(p.name)} = BoolUtil.Deserialize(br);"; + return $"{CheckForKeyword(p.Name)} = BoolUtil.Deserialize(br);"; case "bytes": - return $"{CheckForKeyword(p.name)} = BytesUtil.Deserialize(br);"; + return $"{CheckForKeyword(p.Name)} = BytesUtil.Deserialize(br);"; case "double": - return $"{CheckForKeyword(p.name)} = br.ReadDouble();"; + return $"{CheckForKeyword(p.Name)} = br.ReadDouble();"; default: - if (!IsFlagBase(p.type)) + if (!IsFlagBase(p.Type)) { - if (p.type.ToLower().Contains("vector")) + if (p.Type.ToLower().Contains("vector")) { - return $"{CheckForKeyword(p.name)} = ({GetTypeName(p.type)})ObjectUtils.DeserializeVector<{GetTypeName(p.type).Replace("TLVector<", "").Replace(">", "")}>(br);"; + return $"{CheckForKeyword(p.Name)} = ({GetTypeName(p.Type)})ObjectUtils.DeserializeVector<{GetTypeName(p.Type).Replace("TLVector<", "").Replace(">", "")}>(br);"; } - else return $"{CheckForKeyword(p.name)} = ({GetTypeName(p.type)})ObjectUtils.DeserializeObject(br);"; + else return $"{CheckForKeyword(p.Name)} = ({GetTypeName(p.Type)})ObjectUtils.DeserializeObject(br);"; } else { - if (IsTrueFlag(p.type)) - return $"{CheckForKeyword(p.name)} = (flags & {GetBitMask(p.type).ToString()}) != 0;"; + if (IsTrueFlag(p.Type)) + return $"{CheckForKeyword(p.Name)} = (flags & {GetBitMask(p.Type).ToString()}) != 0;"; else { - Param p2 = new Param() { name = p.name, type = p.type.Split('?')[1] }; - return $"if ((flags & {GetBitMask(p.type).ToString()}) != 0)" + Environment.NewLine + + Param p2 = new Param() { Name = p.Name, Type = p.Type.Split('?')[1] }; + return $"if ((flags & {GetBitMask(p.Type).ToString()}) != 0)" + Environment.NewLine + WriteReadCode(p2) + Environment.NewLine + "else" + Environment.NewLine + - $"{CheckForKeyword(p.name)} = null;" + Environment.NewLine; + $"{CheckForKeyword(p.Name)} = null;" + Environment.NewLine; } } } diff --git a/TeleSharp.Generator/TL2JSON.cs b/TeleSharp.Generator/TL2JSON.cs index ac11b6a..96f2fc8 100644 --- a/TeleSharp.Generator/TL2JSON.cs +++ b/TeleSharp.Generator/TL2JSON.cs @@ -9,7 +9,6 @@ namespace TeleSharp.Generator { static class TL2JSON { - public static string RemoveComments(string input) { var blockComments = @"/\*(.*?)\*/"; @@ -28,84 +27,82 @@ namespace TeleSharp.Generator RegexOptions.Singleline); } public static string RemoveEmptyLines(string input) => - Regex.Replace(input, @"^\s+$[\r\n]*", "", RegexOptions.Multiline); + input.Replace("\r\n\r\n", "\r\n").Replace("\n\n","\n"); - public static string ParseTypeLine(string line) + public static string ParseLine(string line, BlockType blockType) { List convertedParamsList = new List(); - var regex = @"([a-zA-Z0-9.]+)#([0-9a-fA-F]+)([a-zA-Z0-9_:<>. !]+)= ([a-zA-Z0-9 .!]+);"; // 0 = type name, 1 = constructor code, 2 = params, 3 = base type name + var regex = @"([a-zA-Z0-9._]+)#([0-9a-fA-F]+) ((([{])([A-z0-9_.:\(\)]+)([}]))?)([a-zA-Z0-9_:<>.#? !\(\)]+)?(([ #\[]+)([A-z0-9._ ]+)([\]]))?([ ]?)=([ ]?)([a-zA-Z0-9 .!_<>\(\)]+)([ ]?);"; + // 1 = type name, 2 = constructor code, 3 = template parameters, 8 = params, 11 = Don't know what it is (seen in vector definition , 15 = base type + // template parameters are ignored in json schema + var match = Regex.Match(line, regex); if (!match.Success) throw new FormatException($"Cannot parse line: \"{line}\""); // now parse the params to json - - string[] paramslist = Regex.Replace(match.Groups[3].Value, "[ ]{2,}", " ", RegexOptions.None).Split(' '); - - foreach (var param in paramslist) + + string paramsline = Regex.Replace(match.Groups[8].Value, "[ ]{2,}", " ", RegexOptions.None); + MatchCollection paramslist = + Regex.Matches( + paramsline, + @"([A-z0-9._]+):(([A-z0-9._?<>]+)|(\([\(A-z0-9._<> \)]+\)))" + ); + foreach (var param in paramslist.Cast()) { - string[] param_split = param.Split(':'); // 0=name,1=type - if(param_split.Length == 2) - convertedParamsList.Add($"{{\"name\": \"{param_split[0]}\", \"type\": \"{param_split[1]}\"}}"); + convertedParamsList.Add($"{{\"name\":\"{param.Groups[1].Value.Trim()}\", \"type\":\"{param.Groups[2].Value.TrimStart('(').TrimEnd(')').Trim(' ')}\"}}"); } string convertedParams = $"[{string.Join(",", convertedParamsList)}]"; // [ {"name":"NAME","type":"TYPE"}, {"name":"NAME","type":"TYPE"} ] // now, make the final object return $"{{" + $"\"id\": \"{Convert.ToInt32("0x"+match.Groups[2].Value, 16)}\"" + "," + - $"\"predicate\": \"{match.Groups[1].Value}\"" + "," + + $"\"{(blockType == BlockType.Class ? "predicate" : "method")}\": \"{match.Groups[1].Value}\"" + "," + $"\"params\": {convertedParams}" + "," + - $"\"type\": \"{match.Groups[4].Value}\"" + + $"\"type\": \"{match.Groups[15].Value}\"" + $"}}"; } - - public static string ParseMethodLine(string line) - { - List convertedParamsList = new List(); - var regex = @"([a-zA-Z0-9.]+)#([0-9a-fA-F]+)([a-zA-Z0-9_:<>. !]+)= ([a-zA-Z0-9 .!]+);"; // 0 = method name, 1 = method code, 2 = params, 3 = base type name - var match = Regex.Match(line, regex); - if (!match.Success) - throw new FormatException($"Cannot parse line: \"{line}\""); - // now parse the params to json - - string[] paramslist = Regex.Replace(match.Groups[3].Value, "[ ]{2,}", " ", RegexOptions.None).Split(' '); - - foreach (var param in paramslist) - { - string[] param_split = param.Split(':'); // 0=name,1=type - if (param_split.Length == 2) - convertedParamsList.Add($"{{\"name\": \"{param_split[0]}\", \"type\": \"{param_split[1]}\"}}"); - } - string convertedParams = $"[{string.Join(",", convertedParamsList)}]"; // [ {"name":"NAME","type":"TYPE"}, {"name":"NAME","type":"TYPE"} ] - - // now, make the final object - return $"{{" + - $"\"id\": \"{Convert.ToInt32("0x" + match.Groups[2].Value, 16)}\"" + "," + - $"\"method\": \"{match.Groups[1].Value}\"" + "," + - $"\"params\": {convertedParams}" + "," + - $"\"type\": \"{match.Groups[4].Value}\"" + - $"}}"; - } - + public static string ParseToJson(string input) { List convertedTypesList = new List(); List convertedMethodsList = new List(); - string[] lines = RemoveEmptyLines(RemoveComments(input)).Replace("\r\n","\n").Split('\n'); - - int functions_splitter = Array.IndexOf(lines, "---functions---"); - string[] typeLines = lines.Take(functions_splitter - 1).ToArray(); - string[] methodLines = lines.Skip(functions_splitter + 1).ToArray(); - foreach (var line in typeLines) + string[] lines = RemoveEmptyLines(RemoveComments(input)).Replace("\r\n","\n").Trim('\n').Split('\n'); + + //int functions_splitter = Array.IndexOf(lines, "---functions---"); + //string[] typeLines = lines.Take(functions_splitter - 1).ToArray(); + //string[] methodLines = lines.Skip(functions_splitter + 1).ToArray(); + + BlockType blockType = BlockType.Class; + foreach (var line in lines) { - convertedTypesList.Add(ParseTypeLine(line)); - } - foreach (var line in typeLines) - { - convertedMethodsList.Add(ParseMethodLine(line)); + if (line == "") + continue; + + if (line == "---functions---") + { + blockType = BlockType.Method; + continue; + } + if (line == "---types---") + { + blockType = BlockType.Class; + continue; + } + + if (blockType == BlockType.Class) + convertedTypesList.Add(ParseLine(line, blockType)); + else + convertedMethodsList.Add(ParseLine(line, blockType)); } return $"{{\"constructors\":[{string.Join(",", convertedTypesList)}], \"methods\": [{string.Join(",", convertedMethodsList)}]}}"; // { "constructors": [ OBJECT, OBJECT ], "methods": [ OBJECT, OBJECT ] } } + + public enum BlockType + { + Class, + Method + } } }