Improved TL2JSON and formatted code a bit

This commit is contained in:
Mohammad Hadi Hosseinpour 2017-04-07 05:52:55 +04:30
parent 76d2e9ad40
commit 8055ab3162
3 changed files with 237 additions and 162 deletions

View file

@ -8,29 +8,98 @@ namespace TeleSharp.Generator
{ {
class Method class Method
{ {
public int id { get; set; } [Newtonsoft.Json.JsonProperty("id")]
public string method { get; set; } public int Id { get; set; }
[Newtonsoft.Json.JsonProperty("method")]
public string MethodName { get; set; }
[Newtonsoft.Json.JsonProperty("params")] [Newtonsoft.Json.JsonProperty("params")]
public List<Param> Params { get; set; } public List<Param> 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 class Param
{ {
public string name { get; set; } [Newtonsoft.Json.JsonProperty("name")]
public string type { get; set; } public string Name { get; set; }
[Newtonsoft.Json.JsonProperty("type")]
public string Type { get; set; }
} }
class Constructor class Constructor
{ {
public int id { get; set; } [Newtonsoft.Json.JsonProperty("id")]
public string predicate { get; set; } public int Id { get; set; }
[Newtonsoft.Json.JsonProperty("predicate")]
public string ConstructorName { get; set; }
[Newtonsoft.Json.JsonProperty("params")] [Newtonsoft.Json.JsonProperty("params")]
public List<Param> Params { get; set; } public List<Param> 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 class Schema
{ {
public List<Constructor> constructors { get; set; } [Newtonsoft.Json.JsonProperty("constructors")]
public List<Method> methods { get; set; } public List<Constructor> Constructors { get; set; }
[Newtonsoft.Json.JsonProperty("methods")]
public List<Method> 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);
}
} }
} }

View file

@ -148,7 +148,6 @@ namespace TeleSharp.Generator
return; return;
} }
inputPath = extra[0]; inputPath = extra[0];
if (!forceFormat) if (!forceFormat)
{ {
@ -189,24 +188,25 @@ namespace TeleSharp.Generator
#region Translate to C# #region Translate to C#
Schema schema = JsonConvert.DeserializeObject<Schema>(Json); Schema schema = JsonConvert.DeserializeObject<Schema>(Json);
foreach (var c in schema.constructors) foreach (var c in schema.Constructors)
{ {
interfacesList.Add(c.type); interfacesList.Add(c.BaseType);
classesList.Add(c.predicate); classesList.Add(c.ConstructorName);
} }
Console.WriteLine("Implementing abstract classes..."); Console.WriteLine("Implementing abstract classes...");
var abstractParams = new Dictionary<string, List<Property>>(); var abstractParams = new Dictionary<string, List<Param>>();
foreach (var c in schema.constructors) #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) 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); FileStream classFile = MakeFile(path);
using (StreamWriter writer = new StreamWriter(classFile)) using (StreamWriter writer = new StreamWriter(classFile))
{ {
string temp = AbsStyle.Replace("/* NAMESPACE */", GetNameSpace(c.type, TargetNamespace).TrimEnd('.')); string temp = AbsStyle.Replace("/* NAMESPACE */", GetNameSpace(c.BaseType, TargetNamespace).TrimEnd('.'));
temp = temp.Replace("/* NAME */", GetNameofClass(c.type, true)); temp = temp.Replace("/* NAME */", GetNameofClass(c.BaseType, true));
writer.Write(temp); writer.Write(temp);
writer.Close(); writer.Close();
classFile.Close(); classFile.Close();
@ -214,70 +214,70 @@ namespace TeleSharp.Generator
} }
else else
{ {
interfacesList.Remove(list.First().type); interfacesList.Remove(list.First().BaseType);
list.First().type = "himself"; list.First().BaseType = "himself";
} }
} }
#endregion
Console.WriteLine("Implementing types..."); 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); FileStream classFile = MakeFile(path);
using (StreamWriter writer = new StreamWriter(classFile)) using (StreamWriter writer = new StreamWriter(classFile))
{ {
#region About Class #region About Class
string temp = NormalStyle.Replace("/* NAMESPACE */", GetNameSpace(c.predicate, TargetNamespace).TrimEnd('.')); string temp = NormalStyle.Replace("/* NAMESPACE */", GetNameSpace(c.ConstructorName, TargetNamespace).TrimEnd('.'));
temp = (c.type == "himself") ? temp = (c.BaseType == "himself") ?
temp.Replace("/* PARENT */", "TLObject") : temp.Replace("/* PARENT */", "TLObject") :
temp.Replace("/* PARENT */", GetNameofClass(c.type, true)); temp.Replace("/* PARENT */", GetNameofClass(c.BaseType, true));
temp = temp.Replace("/*Constructor*/", c.id.ToString()); temp = temp.Replace("/*Constructor*/", c.Id.ToString());
temp = temp.Replace("/* NAME */", GetNameofClass(c.predicate, false)); temp = temp.Replace("/* NAME */", GetNameofClass(c.ConstructorName, false));
#endregion #endregion
#region Fields #region Fields
/* /*
Note: Fields were mostly moved to abstract classes to provide maximum polymorphism usability. Note: Fields were mostly moved to abstract classes to provide maximum polymorphism usability.
*/ */
//string fields = ""; //string fields = "";
string parent_name = GetNameofClass(c.type, true); string parent_name = GetNameofClass(c.BaseType, true);
if (c.type != "himself")
if (c.BaseType != "himself")
{ {
foreach (var tmp in c.Params) foreach (var tmp in c.Params)
{ {
Property field = new Property Param field = new Param {Name = tmp.Name, Type = tmp.Type};
{ if (abstractParams.All(item => item.Key != c.BaseType))
Type = CheckForFlagBase(tmp.type, GetTypeName(tmp.type)), abstractParams.Add(c.BaseType, new List<Param>());
Name = CheckForKeyword(tmp.name) else if (!abstractParams[c.BaseType].Any(f => f.Name == field.Name && f.Type == field.Type))
}; abstractParams[c.BaseType].Add(field);
if (!abstractParams.ContainsKey(c.type))
abstractParams.Add(c.type, new List<Property>());
else if (!abstractParams[c.type].Contains(field))
abstractParams[c.type].Add(field);
} }
} }
else else
{ {
string fields = ""; 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); temp = temp.Replace("/* PARAMS */", fields);
} }
#endregion #endregion
#region ComputeFlagFunc #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 else
{ {
var compute = "flags = 0;" + Environment.NewLine; 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 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); temp = temp.Replace("/* COMPUTE */", compute);
@ -286,9 +286,9 @@ namespace TeleSharp.Generator
#region SerializeFunc #region SerializeFunc
var serialize = ""; 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; 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; serialize += WriteWriteCode(p) + Environment.NewLine;
} }
@ -308,42 +308,45 @@ namespace TeleSharp.Generator
classFile.Close(); classFile.Close();
} }
} }
#endregion
Console.WriteLine("Implementing methods..."); 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); FileStream classFile = MakeFile(path);
using (StreamWriter writer = new StreamWriter(classFile)) using (StreamWriter writer = new StreamWriter(classFile))
{ {
#region About Class #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("/* PARENT */", "TLMethod");
temp = temp.Replace("/*Constructor*/", c.id.ToString()); temp = temp.Replace("/*Constructor*/", c.Id.ToString());
temp = temp.Replace("/* NAME */", GetNameofClass(c.method, false, true)); temp = temp.Replace("/* NAME */", GetNameofClass(c.MethodName, false, true));
#endregion #endregion
#region Fields #region Fields
string fields = ""; string fields = "";
foreach (var tmp in c.Params) 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); temp = temp.Replace("/* PARAMS */", fields);
#endregion #endregion
#region ComputeFlagFunc #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 else
{ {
var compute = "flags = 0;" + Environment.NewLine; 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 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); temp = temp.Replace("/* COMPUTE */", compute);
@ -352,8 +355,8 @@ namespace TeleSharp.Generator
#region SerializeFunc #region SerializeFunc
var serialize = ""; var serialize = "";
if (c.Params.Any(x => x.name == "flags")) serialize += "ComputeFlags();" + Environment.NewLine + "bw.Write(flags);" + Environment.NewLine; 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; serialize += WriteWriteCode(p) + Environment.NewLine;
} }
@ -370,7 +373,7 @@ namespace TeleSharp.Generator
#endregion #endregion
#region DeSerializeRespFunc #region DeSerializeRespFunc
var deserializeResp = ""; 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; deserializeResp += WriteReadCode(p2) + Environment.NewLine;
temp = temp.Replace("/* DESERIALIZEResp */", deserializeResp); temp = temp.Replace("/* DESERIALIZEResp */", deserializeResp);
#endregion #endregion
@ -379,28 +382,28 @@ namespace TeleSharp.Generator
classFile.Close(); classFile.Close();
} }
} }
#endregion
Console.WriteLine("Adding fields to abstract classes..."); Console.WriteLine("Adding fields to abstract classes...");
// add fields to abstract classes // add fields to abstract classes
foreach (KeyValuePair<string, List<Property>> absClass in abstractParams) foreach (KeyValuePair<string, List<Param>> 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 path = Path.Combine(outputPath, GetNameSpace(absClass.Key, TargetNamespace).Replace(TargetNamespace, @"TL\").Replace(".", ""), GetNameofClass(absClass.Key, true) + ".cs").Replace(@"\\", @"\");
string tmp = File.ReadAllText(path); string tmp = File.ReadAllText(path);
tmp = tmp.Replace("/* PARAMS */", ConvertPropertyList(absClass.Value)); tmp = tmp.Replace("/* PARAMS */", ConvertPropertyList(absClass.Value));
File.WriteAllText(path, tmp); File.WriteAllText(path, tmp);
} }
#endregion #endregion
Console.WriteLine("Done."); Console.WriteLine("Done.");
} }
public static string ConvertPropertyList(List<Property> list) public static string ConvertPropertyList(List<Param> list)
{ {
string output = ""; 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; return output;
} }
@ -470,13 +473,16 @@ namespace TeleSharp.Generator
{ {
if (type.IndexOf('?') == -1) if (type.IndexOf('?') == -1)
return result; return result;
else
{
string innerType = type.Split('?')[1]; string innerType = type.Split('?')[1];
if (innerType == "true") return result;
else if ((new string[] { "bool", "int", "uint", "long", "double" }).Contains(result)) return result + "?"; if (innerType == "true")
else return result; 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) public static string GetTypeName(string type)
{ {
@ -485,6 +491,10 @@ namespace TeleSharp.Generator
case "#": case "#":
case "int": case "int":
return "int"; return "int";
case "int128":
return "BigMath.Int128";
case "int256":
return "BigMath.Int256";
case "uint": case "uint":
return "uint"; return "uint";
case "long": case "long":
@ -514,7 +524,6 @@ namespace TeleSharp.Generator
if (type.IndexOf('.') != -1 && type.IndexOf('?') == -1) if (type.IndexOf('.') != -1 && type.IndexOf('?') == -1)
{ {
if (interfacesList.Any(x => x.ToLower() == (type).ToLower())) if (interfacesList.Any(x => x.ToLower() == (type).ToLower()))
return FormatName(type.Split('.')[0]) + "." + "TLAbs" + type.Split('.')[1]; return FormatName(type.Split('.')[0]) + "." + "TLAbs" + type.Split('.')[1];
else if (classesList.Any(x => x.ToLower() == (type).ToLower())) 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) public static string WriteWriteCode(Param p, bool flag = false)
{ {
switch (p.type.ToLower()) switch (p.Type.ToLower())
{ {
case "#": case "#":
case "int": 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": 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": case "string":
return $"StringUtil.Serialize({CheckForKeyword(p.name)},bw);"; return $"StringUtil.Serialize({CheckForKeyword(p.Name)},bw);";
case "bool": 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": case "true":
return $"BoolUtil.Serialize({CheckForKeyword(p.name)},bw);"; return $"BoolUtil.Serialize({CheckForKeyword(p.Name)},bw);";
case "bytes": case "bytes":
return $"BytesUtil.Serialize({CheckForKeyword(p.name)},bw);"; return $"BytesUtil.Serialize({CheckForKeyword(p.Name)},bw);";
case "double": 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: default:
if (!IsFlagBase(p.type)) if (!IsFlagBase(p.Type))
return $"ObjectUtils.SerializeObject({CheckForKeyword(p.name)},bw);"; return $"ObjectUtils.SerializeObject({CheckForKeyword(p.Name)},bw);";
else else
{ {
if (IsTrueFlag(p.type)) if (IsTrueFlag(p.Type))
return $""; return $"";
else else
{ {
Param p2 = new Param() { name = p.name, type = p.type.Split('?')[1] }; Param p2 = new Param() { Name = p.Name, Type = p.Type.Split('?')[1] };
return $"if ((flags & {GetBitMask(p.type).ToString()}) != 0)" + Environment.NewLine + return $"if ((flags & {GetBitMask(p.Type).ToString()}) != 0)" + Environment.NewLine +
WriteWriteCode(p2, true); WriteWriteCode(p2, true);
} }
} }
@ -584,42 +593,42 @@ namespace TeleSharp.Generator
} }
public static string WriteReadCode(Param p) public static string WriteReadCode(Param p)
{ {
switch (p.type.ToLower()) switch (p.Type.ToLower())
{ {
case "#": case "#":
case "int": case "int":
return $"{CheckForKeyword(p.name)} = br.ReadInt32();"; return $"{CheckForKeyword(p.Name)} = br.ReadInt32();";
case "long": case "long":
return $"{CheckForKeyword(p.name)} = br.ReadInt64();"; return $"{CheckForKeyword(p.Name)} = br.ReadInt64();";
case "string": case "string":
return $"{CheckForKeyword(p.name)} = StringUtil.Deserialize(br);"; return $"{CheckForKeyword(p.Name)} = StringUtil.Deserialize(br);";
case "bool": case "bool":
case "true": case "true":
return $"{CheckForKeyword(p.name)} = BoolUtil.Deserialize(br);"; return $"{CheckForKeyword(p.Name)} = BoolUtil.Deserialize(br);";
case "bytes": case "bytes":
return $"{CheckForKeyword(p.name)} = BytesUtil.Deserialize(br);"; return $"{CheckForKeyword(p.Name)} = BytesUtil.Deserialize(br);";
case "double": case "double":
return $"{CheckForKeyword(p.name)} = br.ReadDouble();"; return $"{CheckForKeyword(p.Name)} = br.ReadDouble();";
default: 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 else
{ {
if (IsTrueFlag(p.type)) if (IsTrueFlag(p.Type))
return $"{CheckForKeyword(p.name)} = (flags & {GetBitMask(p.type).ToString()}) != 0;"; return $"{CheckForKeyword(p.Name)} = (flags & {GetBitMask(p.Type).ToString()}) != 0;";
else else
{ {
Param p2 = new Param() { name = p.name, type = p.type.Split('?')[1] }; Param p2 = new Param() { Name = p.Name, Type = p.Type.Split('?')[1] };
return $"if ((flags & {GetBitMask(p.type).ToString()}) != 0)" + Environment.NewLine + return $"if ((flags & {GetBitMask(p.Type).ToString()}) != 0)" + Environment.NewLine +
WriteReadCode(p2) + Environment.NewLine + WriteReadCode(p2) + Environment.NewLine +
"else" + Environment.NewLine + "else" + Environment.NewLine +
$"{CheckForKeyword(p.name)} = null;" + Environment.NewLine; $"{CheckForKeyword(p.Name)} = null;" + Environment.NewLine;
} }
} }
} }

View file

@ -9,7 +9,6 @@ namespace TeleSharp.Generator
{ {
static class TL2JSON static class TL2JSON
{ {
public static string RemoveComments(string input) public static string RemoveComments(string input)
{ {
var blockComments = @"/\*(.*?)\*/"; var blockComments = @"/\*(.*?)\*/";
@ -28,84 +27,82 @@ namespace TeleSharp.Generator
RegexOptions.Singleline); RegexOptions.Singleline);
} }
public static string RemoveEmptyLines(string input) => 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<string> convertedParamsList = new List<string>(); List<string> convertedParamsList = new List<string>();
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); var match = Regex.Match(line, regex);
if (!match.Success) if (!match.Success)
throw new FormatException($"Cannot parse line: \"{line}\""); throw new FormatException($"Cannot parse line: \"{line}\"");
// now parse the params to json // now parse the params to json
string[] paramslist = Regex.Replace(match.Groups[3].Value, "[ ]{2,}", " ", RegexOptions.None).Split(' '); string paramsline = Regex.Replace(match.Groups[8].Value, "[ ]{2,}", " ", RegexOptions.None);
MatchCollection paramslist =
foreach (var param in paramslist) Regex.Matches(
paramsline,
@"([A-z0-9._]+):(([A-z0-9._?<>]+)|(\([\(A-z0-9._<> \)]+\)))"
);
foreach (var param in paramslist.Cast<Match>())
{ {
string[] param_split = param.Split(':'); // 0=name,1=type convertedParamsList.Add($"{{\"name\":\"{param.Groups[1].Value.Trim()}\", \"type\":\"{param.Groups[2].Value.TrimStart('(').TrimEnd(')').Trim(' ')}\"}}");
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"} ] string convertedParams = $"[{string.Join(",", convertedParamsList)}]"; // [ {"name":"NAME","type":"TYPE"}, {"name":"NAME","type":"TYPE"} ]
// now, make the final object // now, make the final object
return $"{{" + return $"{{" +
$"\"id\": \"{Convert.ToInt32("0x"+match.Groups[2].Value, 16)}\"" + "," + $"\"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}" + "," + $"\"params\": {convertedParams}" + "," +
$"\"type\": \"{match.Groups[4].Value}\"" + $"\"type\": \"{match.Groups[15].Value}\"" +
$"}}"; $"}}";
} }
public static string ParseMethodLine(string line)
{
List<string> convertedParamsList = new List<string>();
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) public static string ParseToJson(string input)
{ {
List<string> convertedTypesList = new List<string>(); List<string> convertedTypesList = new List<string>();
List<string> convertedMethodsList = new List<string>(); List<string> convertedMethodsList = new List<string>();
string[] lines = RemoveEmptyLines(RemoveComments(input)).Replace("\r\n","\n").Split('\n'); string[] lines = RemoveEmptyLines(RemoveComments(input)).Replace("\r\n","\n").Trim('\n').Split('\n');
int functions_splitter = Array.IndexOf(lines, "---functions---"); //int functions_splitter = Array.IndexOf(lines, "---functions---");
string[] typeLines = lines.Take(functions_splitter - 1).ToArray(); //string[] typeLines = lines.Take(functions_splitter - 1).ToArray();
string[] methodLines = lines.Skip(functions_splitter + 1).ToArray(); //string[] methodLines = lines.Skip(functions_splitter + 1).ToArray();
foreach (var line in typeLines)
BlockType blockType = BlockType.Class;
foreach (var line in lines)
{ {
convertedTypesList.Add(ParseTypeLine(line)); if (line == "")
continue;
if (line == "---functions---")
{
blockType = BlockType.Method;
continue;
} }
foreach (var line in typeLines) if (line == "---types---")
{ {
convertedMethodsList.Add(ParseMethodLine(line)); 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 ] } return $"{{\"constructors\":[{string.Join(",", convertedTypesList)}], \"methods\": [{string.Join(",", convertedMethodsList)}]}}"; // { "constructors": [ OBJECT, OBJECT ], "methods": [ OBJECT, OBJECT ] }
} }
public enum BlockType
{
Class,
Method
}
} }
} }