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
{
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<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
{
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<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
{
public List<Constructor> constructors { get; set; }
public List<Method> methods { get; set; }
[Newtonsoft.Json.JsonProperty("constructors")]
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;
}
inputPath = extra[0];
if (!forceFormat)
{
@ -189,24 +188,25 @@ namespace TeleSharp.Generator
#region Translate to C#
Schema schema = JsonConvert.DeserializeObject<Schema>(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<string, List<Property>>();
foreach (var c in schema.constructors)
var abstractParams = new Dictionary<string, List<Param>>();
#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<Property>());
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<Param>());
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<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 tmp = File.ReadAllText(path);
tmp = tmp.Replace("/* PARAMS */", ConvertPropertyList(absClass.Value));
File.WriteAllText(path, tmp);
}
#endregion
Console.WriteLine("Done.");
}
public static string ConvertPropertyList(List<Property> list)
public static string ConvertPropertyList(List<Param> 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;
}
}
}

View file

@ -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<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);
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<Match>())
{
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<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)
{
List<string> convertedTypesList = 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---");
string[] typeLines = lines.Take(functions_splitter - 1).ToArray();
string[] methodLines = lines.Skip(functions_splitter + 1).ToArray();
foreach (var line in typeLines)
//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
}
}
}