2021-08-04 00:40:09 +02:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Linq;
|
2021-08-07 03:44:11 +02:00
|
|
|
|
using System.Net.Http;
|
2021-08-20 14:45:39 +02:00
|
|
|
|
using System.Text;
|
2021-08-04 00:40:09 +02:00
|
|
|
|
using System.Text.Json;
|
2021-08-07 03:44:11 +02:00
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
|
using System.Threading.Tasks;
|
2021-08-04 00:40:09 +02:00
|
|
|
|
|
|
|
|
|
|
namespace WTelegram
|
|
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
public class Generator
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
readonly Dictionary<int, string> ctorToTypes = new();
|
|
|
|
|
|
readonly HashSet<string> allTypes = new();
|
|
|
|
|
|
readonly Dictionary<int, Dictionary<string, TypeInfo>> typeInfosByLayer = new();
|
2021-08-09 11:41:50 +02:00
|
|
|
|
readonly Dictionary<string, int> knownStyles = new() { ["InitConnection"] = 1, ["Help_GetConfig"] = 0, ["HttpWait"] = -1 };
|
2021-08-07 03:44:11 +02:00
|
|
|
|
Dictionary<string, TypeInfo> typeInfos;
|
2021-09-18 02:11:23 +02:00
|
|
|
|
readonly HashSet<string> enumTypes = new();
|
2021-08-07 03:44:11 +02:00
|
|
|
|
int currentLayer;
|
|
|
|
|
|
string tabIndent;
|
2021-08-12 11:01:15 +02:00
|
|
|
|
private string currentJson;
|
2021-08-04 00:40:09 +02:00
|
|
|
|
|
2021-08-07 03:44:11 +02:00
|
|
|
|
public async Task FromWeb()
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
Console.WriteLine("Fetch web pages...");
|
2021-08-12 11:01:15 +02:00
|
|
|
|
#if DEBUG
|
2021-09-17 04:53:02 +02:00
|
|
|
|
currentLayer = await Task.FromResult(TL.Layer.Version);
|
2021-08-12 11:01:15 +02:00
|
|
|
|
#else
|
2021-08-10 03:12:33 +02:00
|
|
|
|
using var http = new HttpClient();
|
2021-08-20 14:45:39 +02:00
|
|
|
|
//var html = await http.GetStringAsync("https://core.telegram.org/api/layers");
|
|
|
|
|
|
//currentLayer = int.Parse(Regex.Match(html, @"#layer-(\d+)").Groups[1].Value);
|
|
|
|
|
|
//File.WriteAllBytes("TL.MTProto.json", await http.GetByteArrayAsync("https://core.telegram.org/schema/mtproto-json"));
|
|
|
|
|
|
//File.WriteAllBytes("TL.Schema.json", await http.GetByteArrayAsync("https://core.telegram.org/schema/json"));
|
|
|
|
|
|
File.WriteAllBytes("TL.MTProto.tl", await http.GetByteArrayAsync("https://raw.githubusercontent.com/telegramdesktop/tdesktop/dev/Telegram/Resources/tl/mtproto.tl"));
|
|
|
|
|
|
File.WriteAllBytes("TL.Schema.tl", await http.GetByteArrayAsync("https://raw.githubusercontent.com/telegramdesktop/tdesktop/dev/Telegram/Resources/tl/api.tl"));
|
2021-08-16 22:52:33 +02:00
|
|
|
|
File.WriteAllBytes("TL.Secret.json", await http.GetByteArrayAsync("https://core.telegram.org/schema/end-to-end-json"));
|
2021-08-12 11:01:15 +02:00
|
|
|
|
#endif
|
2021-08-20 14:45:39 +02:00
|
|
|
|
//FromJson("TL.MTProto.json", "TL.MTProto.cs", @"TL.Table.cs");
|
|
|
|
|
|
//FromJson("TL.Schema.json", "TL.Schema.cs", @"TL.Table.cs");
|
|
|
|
|
|
FromTL("TL.MTProto.tl", "TL.MTProto.cs");
|
|
|
|
|
|
FromTL("TL.Schema.tl", "TL.Schema.cs");
|
|
|
|
|
|
FromJson("TL.Secret.json", "TL.Secret.cs");
|
2021-08-07 03:44:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-08-20 14:45:39 +02:00
|
|
|
|
private void FromTL(string tlPath, string outputCs)
|
|
|
|
|
|
{
|
|
|
|
|
|
using var sr = new StreamReader(tlPath);
|
|
|
|
|
|
var schema = new SchemaJson { constructors = new(), methods = new() };
|
|
|
|
|
|
string line;
|
|
|
|
|
|
bool inFunctions = false;
|
|
|
|
|
|
while ((line = sr.ReadLine()) != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
line = line.Trim();
|
|
|
|
|
|
if (line == "---functions---")
|
|
|
|
|
|
inFunctions = true;
|
|
|
|
|
|
else if (line == "---types---")
|
|
|
|
|
|
inFunctions = false;
|
|
|
|
|
|
else if (line.StartsWith("// LAYER "))
|
|
|
|
|
|
currentLayer = int.Parse(line[9..]);
|
|
|
|
|
|
else if (line != "" && !line.StartsWith("//"))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!line.EndsWith(";")) System.Diagnostics.Debugger.Break();
|
|
|
|
|
|
var words = line.Split(' ');
|
|
|
|
|
|
int hash = words[0].IndexOf('#');
|
|
|
|
|
|
if (hash == -1) { Console.WriteLine(line); continue; }
|
|
|
|
|
|
if (words[^2] != "=") { Console.WriteLine(line); continue; }
|
|
|
|
|
|
string name = words[0][0..hash];
|
|
|
|
|
|
int id = int.Parse(words[0][(hash + 1)..], System.Globalization.NumberStyles.HexNumber);
|
|
|
|
|
|
string type = words[^1].TrimEnd(';');
|
|
|
|
|
|
var @params = words[1..^2].Where(word => word != "{X:Type}").Select(word =>
|
|
|
|
|
|
{
|
|
|
|
|
|
int colon = word.IndexOf(':');
|
|
|
|
|
|
string name = word[0..colon];
|
|
|
|
|
|
string type = word[(colon + 1)..];
|
|
|
|
|
|
if (type == "string" && outputCs == "TL.MTProto.cs" && !name.Contains("message")) type = "bytes";
|
|
|
|
|
|
return new Param { name = name, type = type };
|
|
|
|
|
|
}).ToArray();
|
|
|
|
|
|
if (inFunctions)
|
|
|
|
|
|
schema.methods.Add(new Method { id = id.ToString(), method = name, type = type, @params = @params });
|
|
|
|
|
|
else
|
|
|
|
|
|
schema.constructors.Add(new Constructor { id = id.ToString(), predicate = name, type = type, @params = @params });
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
FromSchema(schema, outputCs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void FromJson(string jsonPath, string outputCs)
|
2021-08-07 03:44:11 +02:00
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine("Parsing " + jsonPath);
|
2021-08-04 00:40:09 +02:00
|
|
|
|
var schema = JsonSerializer.Deserialize<SchemaJson>(File.ReadAllText(jsonPath));
|
2021-08-20 14:45:39 +02:00
|
|
|
|
FromSchema(schema, outputCs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void FromSchema(SchemaJson schema, string outputCs)
|
|
|
|
|
|
{
|
|
|
|
|
|
currentJson = Path.GetFileNameWithoutExtension(outputCs);
|
|
|
|
|
|
using var sw = new StreamWriter(outputCs, false, Encoding.UTF8);
|
2021-09-17 04:53:02 +02:00
|
|
|
|
sw.WriteLine("// This file is generated automatically using the Generator class");
|
2021-08-04 00:40:09 +02:00
|
|
|
|
sw.WriteLine("using System;");
|
2021-08-09 11:41:50 +02:00
|
|
|
|
if (schema.methods.Count != 0) sw.WriteLine("using System.Threading.Tasks;");
|
2021-08-04 00:40:09 +02:00
|
|
|
|
sw.WriteLine();
|
|
|
|
|
|
sw.WriteLine("namespace TL");
|
2021-09-17 04:53:02 +02:00
|
|
|
|
sw.WriteLine("{");
|
|
|
|
|
|
sw.WriteLine("\tusing BinaryWriter = System.IO.BinaryWriter;");
|
|
|
|
|
|
sw.WriteLine("\tusing Client = WTelegram.Client;");
|
2021-08-07 03:44:11 +02:00
|
|
|
|
tabIndent = "\t";
|
|
|
|
|
|
var layers = schema.constructors.GroupBy(c => c.layer).OrderBy(g => g.Key);
|
|
|
|
|
|
foreach (var layer in layers)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
typeInfos = typeInfosByLayer.GetOrCreate(layer.Key);
|
|
|
|
|
|
if (layer.Key != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
sw.WriteLine();
|
|
|
|
|
|
sw.WriteLine("\tnamespace Layer" + layer.Key);
|
|
|
|
|
|
sw.Write("\t{");
|
|
|
|
|
|
tabIndent += "\t";
|
|
|
|
|
|
}
|
|
|
|
|
|
string layerPrefix = layer.Key == 0 ? "" : $"Layer{layer.Key}.";
|
|
|
|
|
|
foreach (var ctor in layer)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ctorToTypes.ContainsKey(ctor.ID)) continue;
|
2021-08-12 11:01:15 +02:00
|
|
|
|
if (ctor.type == "Vector t") continue;
|
2021-08-07 03:44:11 +02:00
|
|
|
|
var structName = CSharpName(ctor.predicate);
|
|
|
|
|
|
ctorToTypes[ctor.ID] = layerPrefix + structName;
|
|
|
|
|
|
var typeInfo = typeInfos.GetOrCreate(ctor.type);
|
|
|
|
|
|
if (ctor.ID == 0x5BB8E511) { ctorToTypes[ctor.ID] = structName = ctor.predicate = ctor.type = "_Message"; }
|
|
|
|
|
|
if (typeInfo.ReturnName == null) typeInfo.ReturnName = CSharpName(ctor.type);
|
|
|
|
|
|
typeInfo.Structs.Add(ctor);
|
|
|
|
|
|
if (structName == typeInfo.ReturnName) typeInfo.SameName = ctor;
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (var (name, typeInfo) in typeInfos)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-20 14:45:39 +02:00
|
|
|
|
if (allTypes.Contains(typeInfo.ReturnName))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (typeInfosByLayer[0].TryGetValue(typeInfo.ReturnName, out var existingType))
|
|
|
|
|
|
typeInfo.ReturnName = existingType.ReturnName;
|
|
|
|
|
|
typeInfo.NeedAbstract = -2; continue;
|
|
|
|
|
|
}
|
2021-08-07 03:44:11 +02:00
|
|
|
|
if (typeInfo.SameName == null)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
typeInfo.NeedAbstract = -1;
|
|
|
|
|
|
if (typeInfo.Structs.Count > 1)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
List<Param> fakeCtorParams = new();
|
|
|
|
|
|
while (typeInfo.Structs[0].@params.Length > fakeCtorParams.Count)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
fakeCtorParams.Add(typeInfo.Structs[0].@params[fakeCtorParams.Count]);
|
|
|
|
|
|
if (!typeInfo.Structs.All(ctor => HasPrefix(ctor, fakeCtorParams)))
|
|
|
|
|
|
{
|
|
|
|
|
|
fakeCtorParams.RemoveAt(fakeCtorParams.Count - 1);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (fakeCtorParams.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
typeInfo.Structs.Insert(0, typeInfo.SameName = new Constructor
|
|
|
|
|
|
{ id = null, @params = fakeCtorParams.ToArray(), predicate = typeInfo.ReturnName, type = typeInfo.ReturnName });
|
|
|
|
|
|
typeInfo.NeedAbstract = fakeCtorParams.Count;
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-08-07 03:44:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
else if (typeInfo.Structs.Count > 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
typeInfo.NeedAbstract = typeInfo.SameName.@params.Length;
|
|
|
|
|
|
foreach (var ctor in typeInfo.Structs)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
if (ctor == typeInfo.SameName) continue;
|
|
|
|
|
|
if (!HasPrefix(ctor, typeInfo.SameName.@params)) { typeInfo.NeedAbstract = -1; typeInfo.ReturnName += "Base"; break; }
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-08-07 03:44:11 +02:00
|
|
|
|
foreach (var typeInfo in typeInfos.Values)
|
2021-08-09 11:41:50 +02:00
|
|
|
|
WriteTypeInfo(sw, typeInfo, layerPrefix, false);
|
2021-08-07 03:44:11 +02:00
|
|
|
|
if (layer.Key != 0)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
sw.WriteLine("\t}");
|
|
|
|
|
|
tabIndent = tabIndent[1..];
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-08-20 14:45:39 +02:00
|
|
|
|
if (typeInfosByLayer[0].GetValueOrDefault("Message")?.SameName.ID == 0x5BB8E511) typeInfosByLayer[0].Remove("Message");
|
2021-08-04 00:40:09 +02:00
|
|
|
|
|
2021-08-09 11:41:50 +02:00
|
|
|
|
if (schema.methods.Count != 0)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
typeInfos = typeInfosByLayer[0];
|
2021-08-14 15:15:41 +02:00
|
|
|
|
var ping = schema.methods.FirstOrDefault(m => m.method == "ping");
|
|
|
|
|
|
if (ping != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var typeInfo = new TypeInfo { ReturnName = ping.type };
|
|
|
|
|
|
typeInfo.Structs.Add(new Constructor { id = ping.id, @params = ping.@params, predicate = ping.method, type = ping.type });
|
|
|
|
|
|
ctorToTypes[int.Parse(ping.id)] = CSharpName(ping.method);
|
|
|
|
|
|
WriteTypeInfo(sw, typeInfo, "", false);
|
|
|
|
|
|
}
|
2021-08-09 11:41:50 +02:00
|
|
|
|
sw.WriteLine();
|
2021-09-17 04:53:02 +02:00
|
|
|
|
sw.WriteLine("\t// ---functions---");
|
|
|
|
|
|
sw.WriteLine();
|
|
|
|
|
|
sw.WriteLine($"\tpublic static class {currentJson[3..]}");
|
2021-08-09 11:41:50 +02:00
|
|
|
|
//sw.WriteLine("\tpublic static partial class Fn // ---functions---");
|
2021-08-07 03:44:11 +02:00
|
|
|
|
sw.Write("\t{");
|
|
|
|
|
|
tabIndent = "\t\t";
|
|
|
|
|
|
foreach (var method in schema.methods)
|
|
|
|
|
|
{
|
2021-08-09 11:41:50 +02:00
|
|
|
|
WriteMethod(sw, method);
|
|
|
|
|
|
//var typeInfo = new TypeInfo { ReturnName = method.type };
|
|
|
|
|
|
//typeInfo.Structs.Add(new Constructor { id = method.id, @params = method.@params, predicate = method.method, type = method.type });
|
|
|
|
|
|
//methods.Add(typeInfo);
|
|
|
|
|
|
//WriteTypeInfo(sw, typeInfo, "", true);
|
2021-08-07 03:44:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
sw.WriteLine("\t}");
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
sw.WriteLine("}");
|
|
|
|
|
|
|
2021-08-20 14:45:39 +02:00
|
|
|
|
UpdateTable("TL.Table.cs");
|
2021-08-07 03:44:11 +02:00
|
|
|
|
}
|
2021-08-06 20:17:19 +02:00
|
|
|
|
|
2021-08-09 11:41:50 +02:00
|
|
|
|
void WriteTypeInfo(StreamWriter sw, TypeInfo typeInfo, string layerPrefix, bool isMethod)
|
2021-08-07 03:44:11 +02:00
|
|
|
|
{
|
|
|
|
|
|
var parentClass = typeInfo.NeedAbstract != 0 ? typeInfo.ReturnName : "ITLObject";
|
|
|
|
|
|
var genericType = typeInfo.ReturnName.Length == 1 ? $"<{typeInfo.ReturnName}>" : null;
|
2021-08-12 12:37:56 +02:00
|
|
|
|
if (isMethod) parentClass = "ITLFunction";
|
2021-08-07 03:44:11 +02:00
|
|
|
|
bool needNewLine = true;
|
|
|
|
|
|
if (typeInfo.NeedAbstract == -1 && allTypes.Add(layerPrefix + parentClass))
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
needNewLine = false;
|
2021-08-06 20:17:19 +02:00
|
|
|
|
sw.WriteLine();
|
2021-08-12 11:01:15 +02:00
|
|
|
|
if (currentJson != "TL.MTProto")
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}///<summary>See <a href=\"https://core.telegram.org/type/{typeInfo.Structs[0].type}\"/></summary>");
|
2021-09-18 02:11:23 +02:00
|
|
|
|
if (typeInfo.Structs.All(ctor => ctor.@params.Length == 0))
|
|
|
|
|
|
{
|
|
|
|
|
|
WriteTypeAsEnum(sw, typeInfo);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}public abstract partial class {parentClass} : ITLObject {{ }}");
|
2021-08-07 03:44:11 +02:00
|
|
|
|
}
|
|
|
|
|
|
int skipParams = 0;
|
|
|
|
|
|
foreach (var ctor in typeInfo.Structs)
|
|
|
|
|
|
{
|
|
|
|
|
|
string className = CSharpName(ctor.predicate) + genericType;
|
|
|
|
|
|
//if (typeInfo.ReturnName == "SendMessageAction") System.Diagnostics.Debugger.Break();
|
|
|
|
|
|
if (layerPrefix != "" && className == parentClass) { className += "_"; ctorToTypes[ctor.ID] = layerPrefix + className; }
|
|
|
|
|
|
if (!allTypes.Add(layerPrefix + className)) continue;
|
|
|
|
|
|
if (needNewLine) { needNewLine = false; sw.WriteLine(); }
|
|
|
|
|
|
if (ctor.id == null)
|
2021-08-12 11:01:15 +02:00
|
|
|
|
{
|
|
|
|
|
|
if (currentJson != "TL.MTProto")
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}///<summary>See <a href=\"https://core.telegram.org/type/{typeInfo.Structs[0].type}\"/></summary>");
|
2021-08-10 03:12:33 +02:00
|
|
|
|
sw.Write($"{tabIndent}public abstract partial class {className} : ITLObject");
|
2021-08-12 11:01:15 +02:00
|
|
|
|
}
|
2021-08-07 03:44:11 +02:00
|
|
|
|
else
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-12 11:01:15 +02:00
|
|
|
|
if (currentJson != "TL.MTProto")
|
|
|
|
|
|
{
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}///<summary>See <a href=\"https://core.telegram.org/constructor/{ctor.predicate}\"/></summary>");
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}[TLDef(0x{ctor.ID:X8})]");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
sw.Write($"{tabIndent}[TLDef(0x{ctor.ID:X8})] //{ctor.predicate}#{ctor.ID:x8} ");
|
|
|
|
|
|
if (genericType != null) sw.Write($"{{{typeInfo.ReturnName}:Type}} ");
|
|
|
|
|
|
foreach (var parm in ctor.@params) sw.Write($"{parm.name}:{parm.type} ");
|
|
|
|
|
|
sw.WriteLine($"= {ctor.type}");
|
|
|
|
|
|
}
|
2021-08-10 03:12:33 +02:00
|
|
|
|
sw.Write($"{tabIndent}public partial class {className} : ");
|
2021-08-07 03:44:11 +02:00
|
|
|
|
sw.Write(skipParams == 0 && typeInfo.NeedAbstract > 0 ? "ITLObject" : parentClass);
|
|
|
|
|
|
}
|
|
|
|
|
|
var parms = ctor.@params.Skip(skipParams).ToArray();
|
|
|
|
|
|
if (parms.Length == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
sw.WriteLine(" { }");
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
var hasFlagEnum = parms.Any(p => p.type.StartsWith("flags."));
|
|
|
|
|
|
bool multiline = hasFlagEnum || parms.Length > 1;
|
|
|
|
|
|
if (multiline)
|
|
|
|
|
|
{
|
|
|
|
|
|
sw.WriteLine();
|
|
|
|
|
|
sw.WriteLine(tabIndent + "{");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
sw.Write(" { ");
|
|
|
|
|
|
if (hasFlagEnum)
|
|
|
|
|
|
{
|
|
|
|
|
|
var list = new SortedList<int, string>();
|
|
|
|
|
|
foreach (var parm in parms)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
if (!parm.type.StartsWith("flags.") || !parm.type.EndsWith("?true")) continue;
|
|
|
|
|
|
var mask = 1 << int.Parse(parm.type[6..parm.type.IndexOf('?')]);
|
|
|
|
|
|
if (!list.ContainsKey(mask)) list[mask] = MapName(parm.name);
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
2021-08-07 03:44:11 +02:00
|
|
|
|
foreach (var parm in parms)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
if (!parm.type.StartsWith("flags.") || parm.type.EndsWith("?true")) continue;
|
|
|
|
|
|
var mask = 1 << int.Parse(parm.type[6..parm.type.IndexOf('?')]);
|
|
|
|
|
|
if (list.ContainsKey(mask)) continue;
|
|
|
|
|
|
var name = MapName("has_" + parm.name);
|
|
|
|
|
|
if (list.Values.Contains(name)) name += "_field";
|
|
|
|
|
|
list[mask] = name;
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
2021-08-07 03:44:11 +02:00
|
|
|
|
string line = tabIndent + "\t[Flags] public enum Flags { ";
|
|
|
|
|
|
foreach (var (mask, name) in list)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
var str = $"{name} = 0x{mask:X}, ";
|
|
|
|
|
|
if (line.Length + str.Length + tabIndent.Length * 3 >= 134) { sw.WriteLine(line); line = tabIndent + "\t\t"; }
|
|
|
|
|
|
line += str;
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
2021-08-07 03:44:11 +02:00
|
|
|
|
sw.WriteLine(line.TrimEnd(',', ' ') + " }");
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (var parm in parms)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (parm.type.EndsWith("?true")) continue;
|
|
|
|
|
|
if (multiline) sw.Write(tabIndent + "\t");
|
|
|
|
|
|
if (parm.type == "#")
|
|
|
|
|
|
sw.Write($"public {(hasFlagEnum ? "Flags" : "int")} {parm.name};");
|
2021-08-06 07:28:54 +02:00
|
|
|
|
else
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
if (parm.type.StartsWith("flags."))
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
int qm = parm.type.IndexOf('?');
|
|
|
|
|
|
sw.Write($"[IfFlag({parm.type[6..qm]})] public {MapType(parm.type[(qm + 1)..], parm.name)} {MapName(parm.name)};");
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
else
|
2021-08-07 03:44:11 +02:00
|
|
|
|
sw.Write($"public {MapType(parm.type, parm.name)} {MapName(parm.name)};");
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
2021-08-07 03:44:11 +02:00
|
|
|
|
if (multiline) sw.WriteLine();
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-08-07 03:44:11 +02:00
|
|
|
|
if (multiline)
|
|
|
|
|
|
sw.WriteLine(tabIndent + "}");
|
|
|
|
|
|
else
|
|
|
|
|
|
sw.WriteLine(" }");
|
|
|
|
|
|
skipParams = typeInfo.NeedAbstract;
|
|
|
|
|
|
}
|
2021-08-09 11:41:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-09-18 02:11:23 +02:00
|
|
|
|
private void WriteTypeAsEnum(StreamWriter sw, TypeInfo typeInfo)
|
|
|
|
|
|
{
|
|
|
|
|
|
enumTypes.Add(typeInfo.ReturnName);
|
2021-09-23 13:13:36 +02:00
|
|
|
|
bool lowercase = typeInfo.ReturnName == "Storage_FileType";
|
2021-09-18 02:11:23 +02:00
|
|
|
|
sw.WriteLine($"{tabIndent}public enum {typeInfo.ReturnName} : uint");
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}{{");
|
|
|
|
|
|
string prefix = "";
|
|
|
|
|
|
while ((prefix += typeInfo.Structs[0].predicate[prefix.Length]) != null)
|
|
|
|
|
|
if (!typeInfo.Structs.All(ctor => ctor.predicate.StartsWith(prefix)))
|
|
|
|
|
|
break;
|
|
|
|
|
|
int prefixLen = CSharpName(prefix).Length - 1;
|
|
|
|
|
|
foreach (var ctor in typeInfo.Structs)
|
|
|
|
|
|
{
|
|
|
|
|
|
string className = CSharpName(ctor.predicate);
|
|
|
|
|
|
if (!allTypes.Add(className)) continue;
|
2021-09-23 13:13:36 +02:00
|
|
|
|
if (lowercase) className = className.ToLowerInvariant();
|
2021-09-18 02:11:23 +02:00
|
|
|
|
ctorToTypes.Remove(ctor.ID);
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}\t///<summary>See <a href=\"https://core.telegram.org/constructor/{ctor.predicate}\"/></summary>");
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}\t{className[prefixLen..]} = 0x{ctor.ID:X8},");
|
|
|
|
|
|
}
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}}}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-08-09 11:41:50 +02:00
|
|
|
|
private static string MapName(string name) => name switch
|
|
|
|
|
|
{
|
|
|
|
|
|
"out" => "out_",
|
|
|
|
|
|
"static" => "static_",
|
|
|
|
|
|
"long" => "long_",
|
|
|
|
|
|
"default" => "default_",
|
|
|
|
|
|
"public" => "public_",
|
|
|
|
|
|
"params" => "params_",
|
|
|
|
|
|
"private" => "private_",
|
|
|
|
|
|
_ => name
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
private string MapType(string type, string name)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (type.StartsWith("Vector<", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
return MapType(type[7..^1], name) + "[]";
|
|
|
|
|
|
else if (type == "Bool")
|
|
|
|
|
|
return "bool";
|
|
|
|
|
|
else if (type == "bytes")
|
|
|
|
|
|
return "byte[]";
|
|
|
|
|
|
else if (type == "int128")
|
|
|
|
|
|
return "Int128";
|
|
|
|
|
|
else if (type == "int256")
|
|
|
|
|
|
return "Int256";
|
|
|
|
|
|
else if (type == "Object")
|
|
|
|
|
|
return "ITLObject";
|
|
|
|
|
|
else if (type == "!X")
|
2021-08-12 12:37:56 +02:00
|
|
|
|
return "ITLFunction";
|
2021-08-09 11:41:50 +02:00
|
|
|
|
else if (type == "int")
|
|
|
|
|
|
{
|
|
|
|
|
|
var name2 = '_' + name + '_';
|
|
|
|
|
|
if (name2.EndsWith("_date_") || name2.EndsWith("_time_") || name2.StartsWith("_valid_") ||
|
|
|
|
|
|
name2 == "_expires_" || name2 == "_expires_at_" || name2 == "_now_")
|
|
|
|
|
|
return "DateTime";
|
|
|
|
|
|
else
|
|
|
|
|
|
return "int";
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (type == "string")
|
|
|
|
|
|
return name.StartsWith("md5") ? "byte[]" : "string";
|
2021-08-20 14:45:39 +02:00
|
|
|
|
else if (type == "long" || type == "double" || type == "X")
|
2021-08-09 11:41:50 +02:00
|
|
|
|
return type;
|
2021-08-20 14:45:39 +02:00
|
|
|
|
else if (typeInfos.TryGetValue(type, out var typeInfo))
|
|
|
|
|
|
return typeInfo.ReturnName;
|
|
|
|
|
|
else
|
|
|
|
|
|
{ // try to find type in a lower layer
|
|
|
|
|
|
foreach (var layer in typeInfosByLayer.OrderByDescending(kvp => kvp.Key))
|
|
|
|
|
|
if (layer.Value.TryGetValue(type, out typeInfo))
|
|
|
|
|
|
return layer.Key == 0 ? typeInfo.ReturnName : $"Layer{layer.Key}.{typeInfo.ReturnName}";
|
|
|
|
|
|
return CSharpName(type);
|
|
|
|
|
|
}
|
2021-08-09 11:41:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string MapOptionalType(string type, string name)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (type == "Bool")
|
|
|
|
|
|
return "bool?";
|
|
|
|
|
|
else if (type == "long")
|
|
|
|
|
|
return "long?";
|
|
|
|
|
|
else if (type == "double")
|
|
|
|
|
|
return "double?";
|
|
|
|
|
|
else if (type == "int128")
|
|
|
|
|
|
return "Int128?";
|
|
|
|
|
|
else if (type == "int256")
|
|
|
|
|
|
return "Int256?";
|
|
|
|
|
|
else if (type == "int")
|
2021-08-07 03:44:11 +02:00
|
|
|
|
{
|
2021-08-09 11:41:50 +02:00
|
|
|
|
var name2 = '_' + name + '_';
|
|
|
|
|
|
if (name2.EndsWith("_date_") || name2.EndsWith("_time_") || name2 == "_expires_" || name2 == "_now_" || name2.StartsWith("_valid_"))
|
|
|
|
|
|
return "DateTime?";
|
|
|
|
|
|
else
|
|
|
|
|
|
return "int?";
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
return MapType(type, name);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void WriteMethod(StreamWriter sw, Method method)
|
|
|
|
|
|
{
|
|
|
|
|
|
int ctorNb = int.Parse(method.id);
|
|
|
|
|
|
var funcName = CSharpName(method.method);
|
|
|
|
|
|
string returnType = MapType(method.type, "");
|
|
|
|
|
|
int style = knownStyles.GetValueOrDefault(funcName, 2);
|
|
|
|
|
|
// styles: 0 = static string, 1 = static ITLFunction<>, 2 = Task<>, -1 = skip method
|
|
|
|
|
|
if (style == -1) return;
|
|
|
|
|
|
sw.WriteLine();
|
2021-08-07 03:44:11 +02:00
|
|
|
|
|
2021-08-14 15:15:41 +02:00
|
|
|
|
var callAsync = "CallAsync";
|
2021-08-12 12:37:56 +02:00
|
|
|
|
if (method.type.Length == 1 && style != 1) funcName += $"<{returnType}>";
|
2021-08-12 11:01:15 +02:00
|
|
|
|
if (currentJson != "TL.MTProto")
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}///<summary>See <a href=\"https://core.telegram.org/method/{method.method}\"/></summary>");
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2021-08-14 15:15:41 +02:00
|
|
|
|
if (method.type is not "FutureSalts" and not "Pong") callAsync = "CallBareAsync";
|
2021-08-12 11:01:15 +02:00
|
|
|
|
sw.Write($"{tabIndent}//{method.method}#{ctorNb:x8} ");
|
|
|
|
|
|
if (method.type.Length == 1) sw.Write($"{{{method.type}:Type}} ");
|
|
|
|
|
|
foreach (var parm in method.@params) sw.Write($"{parm.name}:{parm.type} ");
|
|
|
|
|
|
sw.WriteLine($"= {method.type}");
|
|
|
|
|
|
}
|
2021-08-09 11:41:50 +02:00
|
|
|
|
|
2021-09-17 04:53:02 +02:00
|
|
|
|
if (style == 0) sw.WriteLine($"{tabIndent}public static Task<{returnType}> {funcName}(this Client client) => client.{callAsync}<{returnType}>({funcName});");
|
2021-08-09 11:41:50 +02:00
|
|
|
|
if (style == 0) sw.Write($"{tabIndent}public static string {funcName}(BinaryWriter writer");
|
2021-08-12 12:37:56 +02:00
|
|
|
|
if (style == 1) sw.Write($"{tabIndent}public static ITLFunction {funcName}(");
|
2021-09-17 04:53:02 +02:00
|
|
|
|
if (style == 2) sw.Write($"{tabIndent}public static Task<{returnType}> {funcName}(this Client client");
|
|
|
|
|
|
bool first = style == 1;
|
2021-08-09 11:41:50 +02:00
|
|
|
|
foreach (var parm in method.@params) // output non-optional parameters
|
|
|
|
|
|
{
|
|
|
|
|
|
if (parm.type == "#" || parm.type.StartsWith("flags.")) continue;
|
|
|
|
|
|
if (first) first = false; else sw.Write(", ");
|
|
|
|
|
|
sw.Write($"{MapType(parm.type, parm.name)} {MapName(parm.name)}");
|
|
|
|
|
|
}
|
|
|
|
|
|
string flagExpr = null;
|
|
|
|
|
|
foreach (var parm in method.@params) // output optional parameters
|
2021-08-07 03:44:11 +02:00
|
|
|
|
{
|
2021-08-09 11:41:50 +02:00
|
|
|
|
if (!parm.type.StartsWith("flags.")) continue;
|
|
|
|
|
|
var parmName = MapName(parm.name);
|
|
|
|
|
|
int qm = parm.type.IndexOf('?');
|
|
|
|
|
|
int bit = int.Parse(parm.type[6..qm]);
|
|
|
|
|
|
if (first) first = false; else sw.Write(", ");
|
|
|
|
|
|
if (parm.type.EndsWith("?true"))
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-09 11:41:50 +02:00
|
|
|
|
sw.Write($"bool {parmName} = false");
|
|
|
|
|
|
flagExpr += $" | ({parmName} ? 0x{1 << bit:X} : 0)";
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
2021-08-07 03:44:11 +02:00
|
|
|
|
else
|
2021-08-09 11:41:50 +02:00
|
|
|
|
{
|
|
|
|
|
|
sw.Write($"{MapOptionalType(parm.type[(qm + 1)..], parm.name)} {parmName} = null");
|
|
|
|
|
|
flagExpr += $" | ({parmName} != null ? 0x{1 << bit:X} : 0)";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (flagExpr != null) flagExpr = flagExpr.IndexOf('|', 3) >= 0 ? flagExpr[3..] : flagExpr[4..^1];
|
|
|
|
|
|
sw.WriteLine(")");
|
|
|
|
|
|
if (style != 0) tabIndent += "\t";
|
|
|
|
|
|
if (style == 1) sw.WriteLine($"{tabIndent}=> writer =>");
|
2021-09-17 04:53:02 +02:00
|
|
|
|
if (style == 2) sw.WriteLine($"{tabIndent}=> client.{callAsync}<{returnType}>(writer =>");
|
2021-08-09 11:41:50 +02:00
|
|
|
|
sw.WriteLine(tabIndent + "{");
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}\twriter.Write(0x{ctorNb:X8});");
|
|
|
|
|
|
foreach (var parm in method.@params) // serialize request
|
|
|
|
|
|
{
|
|
|
|
|
|
var parmName = MapName(parm.name);
|
|
|
|
|
|
var parmType = parm.type;
|
|
|
|
|
|
if (parmType.StartsWith("flags."))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (parmType.EndsWith("?true")) continue;
|
|
|
|
|
|
int qm = parmType.IndexOf('?');
|
|
|
|
|
|
parmType = parmType[(qm + 1)..];
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}\tif ({parmName} != null)");
|
|
|
|
|
|
sw.Write('\t');
|
2021-08-16 22:30:45 +02:00
|
|
|
|
if (MapOptionalType(parmType, parm.name).EndsWith("?"))
|
2021-08-09 11:41:50 +02:00
|
|
|
|
parmName += ".Value";
|
|
|
|
|
|
}
|
|
|
|
|
|
switch (parmType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "Bool":
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}\twriter.Write({parmName} ? 0x997275B5 : 0xBC799737);");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "bytes":
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}\twriter.WriteTLBytes({parmName});");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "long": case "int128": case "int256": case "double":
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}\twriter.Write({parmName});");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "int":
|
|
|
|
|
|
if (MapType(parmType, parm.name) == "int")
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}\twriter.Write({parmName});");
|
|
|
|
|
|
else
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}\twriter.WriteTLStamp({parmName});");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "string":
|
|
|
|
|
|
if (parm.name.StartsWith("md5"))
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}\twriter.WriteTLBytes({parmName});");
|
|
|
|
|
|
else
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}\twriter.WriteTLString({parmName});");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "#":
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}\twriter.Write({flagExpr});");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "!X":
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}\t{parmName}(writer);");
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
if (parmType.StartsWith("Vector<", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}\twriter.WriteTLVector({parmName});");
|
2021-09-18 02:11:23 +02:00
|
|
|
|
else if (enumTypes.Contains(parmType))
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}\twriter.Write((uint){parmName});");
|
2021-08-09 11:41:50 +02:00
|
|
|
|
else
|
|
|
|
|
|
sw.WriteLine($"{tabIndent}\twriter.WriteTLObject({parmName});");
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
2021-08-09 11:41:50 +02:00
|
|
|
|
sw.WriteLine($"{tabIndent}\treturn \"{funcName}\";");
|
|
|
|
|
|
if (style == 0) sw.WriteLine(tabIndent + "}");
|
|
|
|
|
|
if (style == 1) sw.WriteLine(tabIndent + "};");
|
|
|
|
|
|
if (style == 2) sw.WriteLine(tabIndent + "});");
|
|
|
|
|
|
if (style != 0) tabIndent = tabIndent[0..^1];
|
2021-08-07 03:44:11 +02:00
|
|
|
|
}
|
2021-08-06 20:17:19 +02:00
|
|
|
|
|
2021-08-14 15:15:41 +02:00
|
|
|
|
void UpdateTable(string tableCs)
|
2021-08-07 03:44:11 +02:00
|
|
|
|
{
|
2021-08-12 11:01:15 +02:00
|
|
|
|
var myTag = $"\t\t\t// from {currentJson}:";
|
2021-08-07 03:44:11 +02:00
|
|
|
|
var seen_ids = new HashSet<int>();
|
|
|
|
|
|
using (var sr = new StreamReader(tableCs))
|
2021-08-20 14:45:39 +02:00
|
|
|
|
using (var sw = new StreamWriter(tableCs + ".new", false, Encoding.UTF8))
|
2021-08-06 20:17:19 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
string line;
|
|
|
|
|
|
while ((line = sr.ReadLine()) != null)
|
2021-08-06 20:17:19 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
if (currentLayer != 0 && line.StartsWith("\t\tpublic const int Layer"))
|
2021-08-07 06:23:13 +02:00
|
|
|
|
sw.WriteLine($"\t\tpublic const int Layer = {currentLayer};\t\t\t\t\t// fetched {DateTime.UtcNow}");
|
2021-08-07 03:44:11 +02:00
|
|
|
|
else
|
|
|
|
|
|
sw.WriteLine(line);
|
|
|
|
|
|
if (line == myTag)
|
2021-08-06 20:17:19 +02:00
|
|
|
|
{
|
2021-08-07 03:44:11 +02:00
|
|
|
|
foreach (var ctor in ctorToTypes)
|
|
|
|
|
|
if (seen_ids.Add(ctor.Key))
|
|
|
|
|
|
sw.WriteLine($"\t\t\t[0x{ctor.Key:X8}] = typeof({ctor.Value}),");
|
|
|
|
|
|
while ((line = sr.ReadLine()) != null)
|
|
|
|
|
|
if (line.StartsWith("\t\t\t// "))
|
|
|
|
|
|
break;
|
2021-08-06 20:17:19 +02:00
|
|
|
|
sw.WriteLine(line);
|
|
|
|
|
|
}
|
2021-08-07 03:44:11 +02:00
|
|
|
|
else if (line.StartsWith("\t\t\t[0x"))
|
|
|
|
|
|
seen_ids.Add(int.Parse(line[6..14], System.Globalization.NumberStyles.HexNumber));
|
2021-08-06 20:17:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-08-07 03:44:11 +02:00
|
|
|
|
File.Replace(tableCs + ".new", tableCs, null);
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static bool HasPrefix(Constructor ctor, IList<Param> prefixParams)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ctor.@params.Length < prefixParams.Count) return false;
|
|
|
|
|
|
for (int i = 0; i < prefixParams.Count; i++)
|
|
|
|
|
|
if (ctor.@params[i].name != prefixParams[i].name || ctor.@params[i].type != prefixParams[i].type)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static string CSharpName(string name)
|
|
|
|
|
|
{
|
|
|
|
|
|
name = char.ToUpper(name[0]) + name[1..];
|
|
|
|
|
|
int i;
|
|
|
|
|
|
while ((i = name.IndexOf('_')) > 0)
|
|
|
|
|
|
name = name[..i] + char.ToUpper(name[i + 1]) + name[(i + 2)..];
|
|
|
|
|
|
while ((i = name.IndexOf('.')) > 0)
|
|
|
|
|
|
name = name[..i] + '_' + char.ToUpper(name[i + 1]) + name[(i + 2)..];
|
|
|
|
|
|
return name;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class TypeInfo
|
|
|
|
|
|
{
|
|
|
|
|
|
public string ReturnName;
|
|
|
|
|
|
public Constructor SameName;
|
|
|
|
|
|
public List<Constructor> Structs = new();
|
|
|
|
|
|
internal int NeedAbstract; // 0:no, -1:create auto, n:use first generated constructor and skip n params
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma warning disable IDE1006 // Naming Styles
|
|
|
|
|
|
public class SchemaJson
|
|
|
|
|
|
{
|
2021-08-09 11:41:50 +02:00
|
|
|
|
public List<Constructor> constructors { get; set; }
|
|
|
|
|
|
public List<Method> methods { get; set; }
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public class Constructor
|
|
|
|
|
|
{
|
|
|
|
|
|
public string id { get; set; }
|
|
|
|
|
|
public string predicate { get; set; }
|
|
|
|
|
|
public Param[] @params { get; set; }
|
|
|
|
|
|
public string type { get; set; }
|
2021-08-07 03:44:11 +02:00
|
|
|
|
public int layer { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public int ID => int.Parse(id);
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public class Param
|
|
|
|
|
|
{
|
|
|
|
|
|
public string name { get; set; }
|
|
|
|
|
|
public string type { get; set; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public class Method
|
|
|
|
|
|
{
|
|
|
|
|
|
public string id { get; set; }
|
|
|
|
|
|
public string method { get; set; }
|
|
|
|
|
|
public Param[] @params { get; set; }
|
|
|
|
|
|
public string type { get; set; }
|
|
|
|
|
|
}
|
|
|
|
|
|
#pragma warning restore IDE1006 // Naming Styles
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|