Fork of mellinoe/ImGui.NET, an ImGui wrapper for .NET, which includes access to internal functions.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

542 lines
19 KiB

using System;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace CodeGenerator
{
class ImguiDefinitions
{
public EnumDefinition[] Enums;
public TypeDefinition[] Types;
public FunctionDefinition[] Functions;
public Dictionary<string, MethodVariant> Variants;
static int GetInt(JToken token, string key)
{
var v = token[key];
if (v == null) return 0;
return v.ToObject<int>();
}
public void LoadFrom(string directory, bool excludeInternals = true)
{
JObject typesJson;
using (StreamReader fs = File.OpenText(Path.Combine(directory, "structs_and_enums.json")))
using (JsonTextReader jr = new JsonTextReader(fs))
{
typesJson = JObject.Load(jr);
}
JObject functionsJson;
using (StreamReader fs = File.OpenText(Path.Combine(directory, "definitions.json")))
using (JsonTextReader jr = new JsonTextReader(fs))
{
functionsJson = JObject.Load(jr);
}
JObject variantsJson = null;
if (File.Exists(Path.Combine(directory, "variants.json")))
{
using (StreamReader fs = File.OpenText(Path.Combine(directory, "variants.json")))
using (JsonTextReader jr = new JsonTextReader(fs))
{
variantsJson = JObject.Load(jr);
}
}
Variants = new Dictionary<string, MethodVariant>();
foreach (var jt in variantsJson.Children())
{
JProperty jp = (JProperty)jt;
ParameterVariant[] methodVariants = jp.Values().Select(jv =>
{
return new ParameterVariant(jv["name"].ToString(), jv["type"].ToString(), jv["variants"].Select(s => s.ToString()).ToArray());
}).ToArray();
Variants.Add(jp.Name, new MethodVariant(jp.Name, methodVariants));
}
var typeLocations = typesJson["locations"];
Enums = typesJson["enums"].Select(jt =>
{
JProperty jp = (JProperty)jt;
string name = jp.Name;
bool isInternal = typeLocations?[jp.Name]?.Value<string>().Contains("internal") ?? false;
if (excludeInternals && isInternal)
return null;
EnumMember[] elements = jp.Values().Select(v =>
{
return new EnumMember(v["name"].ToString(), v["calc_value"].ToString());
}).ToArray();
return new EnumDefinition(name, elements, isInternal);
}).Where(x => x != null).ToArray();
Types = typesJson["structs"].Select(jt =>
{
JProperty jp = (JProperty)jt;
string name = jp.Name;
bool isInternal = typeLocations?[jp.Name]?.Value<string>().Contains("internal") ?? false;
if (excludeInternals && isInternal)
return null;
TypeReference[] fields = jp.Values().Select(v =>
{
if (v["type"].ToString().Contains("static")) { return null; }
return new TypeReference(
v["name"].ToString(),
v["type"].ToString(),
GetInt(v, "size"),
v["template_type"]?.ToString(),
Enums);
}).Where(tr => tr != null).ToArray();
return new TypeDefinition(name, fields, isInternal);
}).Where(x => x != null).ToArray();
Functions = functionsJson.Children().Select(jt =>
{
JProperty jp = (JProperty)jt;
string name = jp.Name;
bool hasNonUdtVariants = jp.Values().Any(val => val["ov_cimguiname"]?.ToString().EndsWith("nonUDT") ?? false);
OverloadDefinition[] overloads = jp.Values().Select(val =>
{
string ov_cimguiname = val["ov_cimguiname"]?.ToString();
string cimguiname = val["cimguiname"].ToString();
string friendlyName = val["funcname"]?.ToString();
if (cimguiname.EndsWith("_destroy"))
{
friendlyName = "Destroy";
}
//skip internal functions
var typename = val["stname"]?.ToString();
if (!string.IsNullOrEmpty(typename))
{
if (!Types.Any(x => x.Name == val["stname"]?.ToString())) {
return null;
}
}
if (friendlyName == null) { return null; }
bool isInternal = val["location"]?.ToString().Contains("internal") ?? false;
if (excludeInternals && isInternal)
return null;
string exportedName = ov_cimguiname;
if (exportedName == null)
{
exportedName = cimguiname;
}
if (hasNonUdtVariants && !exportedName.EndsWith("nonUDT2"))
{
return null;
}
string selfTypeName = null;
int underscoreIndex = exportedName.IndexOf('_');
if (underscoreIndex > 0 && !exportedName.StartsWith("ig")) // Hack to exclude some weirdly-named non-instance functions.
{
selfTypeName = exportedName.Substring(0, underscoreIndex);
}
List<TypeReference> parameters = new List<TypeReference>();
// find any variants that can be applied to the parameters of this method based on the method name
MethodVariant methodVariants = null;
Variants.TryGetValue(jp.Name, out methodVariants);
foreach (JToken p in val["argsT"])
{
string pType = p["type"].ToString();
string pName = p["name"].ToString();
// if there are possible variants for this method then try to match them based on the parameter name and expected type
ParameterVariant matchingVariant = methodVariants?.Parameters.Where(pv => pv.Name == pName && pv.OriginalType == pType).FirstOrDefault() ?? null;
if (matchingVariant != null) matchingVariant.Used = true;
parameters.Add(new TypeReference(pName, pType, 0, Enums, matchingVariant?.VariantTypes));
}
Dictionary<string, string> defaultValues = new Dictionary<string, string>();
foreach (JToken dv in val["defaults"])
{
JProperty dvProp = (JProperty)dv;
defaultValues.Add(dvProp.Name, dvProp.Value.ToString());
}
string returnType = val["ret"]?.ToString() ?? "void";
string comment = null;
string structName = val["stname"].ToString();
bool isConstructor = val.Value<bool>("constructor");
bool isDestructor = val.Value<bool>("destructor");
if (isConstructor)
{
returnType = structName + "*";
}
return new OverloadDefinition(
exportedName,
friendlyName,
parameters.ToArray(),
defaultValues,
returnType,
structName,
comment,
isConstructor,
isDestructor,
isInternal);
}).Where(od => od != null).ToArray();
if(overloads.Length == 0) return null;
return new FunctionDefinition(name, overloads, Enums);
}).Where(x => x != null).OrderBy(fd => fd.Name).ToArray();
}
}
class MethodVariant
{
public string Name { get; }
public ParameterVariant[] Parameters { get; }
public MethodVariant(string name, ParameterVariant[] parameters)
{
Name = name;
Parameters = parameters;
}
}
class ParameterVariant
{
public string Name { get; }
public string OriginalType { get; }
public string[] VariantTypes { get; }
public bool Used { get; set; }
public ParameterVariant(string name, string originalType, string[] variantTypes)
{
Name = name;
OriginalType = originalType;
VariantTypes = variantTypes;
Used = false;
}
}
class EnumDefinition
{
private readonly Dictionary<string, string> _sanitizedNames;
public string Name { get; }
public string FriendlyName { get; }
public EnumMember[] Members { get; }
public bool IsInternal { get; }
public EnumDefinition(string name, EnumMember[] elements, bool isInternal)
{
Name = name;
if (Name.EndsWith('_'))
{
FriendlyName = Name.Substring(0, Name.Length - 1);
}
else
{
FriendlyName = Name;
}
Members = elements;
_sanitizedNames = new Dictionary<string, string>();
foreach (EnumMember el in elements)
{
_sanitizedNames.Add(el.Name, SanitizeMemberName(el.Name));
}
IsInternal = isInternal;
}
public string SanitizeNames(string text)
{
foreach (KeyValuePair<string, string> kvp in _sanitizedNames)
{
text = text.Replace(kvp.Key, kvp.Value);
}
return text;
}
private string SanitizeMemberName(string memberName)
{
string ret = memberName;
if (memberName.StartsWith(Name))
{
ret = memberName.Substring(Name.Length);
if (ret.StartsWith("_"))
{
ret = ret.Substring(1);
}
}
if (ret.EndsWith('_'))
{
ret = ret.Substring(0, ret.Length - 1);
}
if (Char.IsDigit(ret.First()))
ret = "_" + ret;
return ret;
}
}
class EnumMember
{
public EnumMember(string name, string value)
{
Name = name;
Value = value;
}
public string Name { get; }
public string Value { get; }
}
class TypeDefinition
{
public string Name { get; }
public TypeReference[] Fields { get; }
public bool IsInternal { get; }
public TypeDefinition(string name, TypeReference[] fields, bool isInternal)
{
Name = name;
Fields = fields;
IsInternal = isInternal;
}
}
class TypeReference
{
public string Name { get; }
public string Type { get; }
public string TemplateType { get; }
public int ArraySize { get; }
public bool IsFunctionPointer { get; }
public string[] TypeVariants { get; }
public bool IsEnum { get; }
public TypeReference(string name, string type, int asize, EnumDefinition[] enums)
: this(name, type, asize, null, enums, null) { }
public TypeReference(string name, string type, int asize, EnumDefinition[] enums, string[] typeVariants)
: this(name, type, asize, null, enums, typeVariants) { }
public TypeReference(string name, string type, int asize, string templateType, EnumDefinition[] enums)
: this(name, type, asize, templateType, enums, null) { }
public TypeReference(string name, string type, int asize, string templateType, EnumDefinition[] enums, string[] typeVariants)
{
Name = name;
Type = type.Replace("const", string.Empty).Trim();
if (Type.StartsWith("ImVector_"))
{
if (Type.EndsWith("*"))
{
Type = "ImVector*";
}
else
{
Type = "ImVector";
}
}
if (Type.StartsWith("ImChunkStream_"))
{
if (Type.EndsWith("*"))
{
Type = "ImChunkStream*";
}
else
{
Type = "ImChunkStream";
}
}
TemplateType = templateType;
ArraySize = asize;
int startBracket = name.IndexOf('[');
if (startBracket != -1)
{
//This is only for older cimgui binding jsons
int endBracket = name.IndexOf(']');
string sizePart = name.Substring(startBracket + 1, endBracket - startBracket - 1);
if(ArraySize == 0)
ArraySize = ParseSizeString(sizePart, enums);
Name = Name.Substring(0, startBracket);
}
IsFunctionPointer = Type.IndexOf('(') != -1;
TypeVariants = typeVariants;
IsEnum = enums.Any(t => t.Name == type || t.FriendlyName == type || TypeInfo.WellKnownEnums.Contains(type));
}
private int ParseSizeString(string sizePart, EnumDefinition[] enums)
{
int plusStart = sizePart.IndexOf('+');
if (plusStart != -1)
{
string first = sizePart.Substring(0, plusStart);
string second = sizePart.Substring(plusStart, sizePart.Length - plusStart);
int firstVal = int.Parse(first);
int secondVal = int.Parse(second);
return firstVal + secondVal;
}
if (!int.TryParse(sizePart, out int ret))
{
foreach (EnumDefinition ed in enums)
{
if (sizePart.StartsWith(ed.Name))
{
foreach (EnumMember member in ed.Members)
{
if (member.Name == sizePart)
{
return int.Parse(member.Value);
}
}
}
}
ret = -1;
}
return ret;
}
public TypeReference WithVariant(int variantIndex, EnumDefinition[] enums)
{
if (variantIndex == 0) return this;
else return new TypeReference(Name, TypeVariants[variantIndex - 1], ArraySize, TemplateType, enums);
}
}
class FunctionDefinition
{
public string Name { get; }
public OverloadDefinition[] Overloads { get; }
public FunctionDefinition(string name, OverloadDefinition[] overloads, EnumDefinition[] enums)
{
Name = name;
Overloads = ExpandOverloadVariants(overloads, enums);
}
private OverloadDefinition[] ExpandOverloadVariants(OverloadDefinition[] overloads, EnumDefinition[] enums)
{
List<OverloadDefinition> newDefinitions = new List<OverloadDefinition>();
foreach (OverloadDefinition overload in overloads)
{
bool hasVariants = false;
int[] variantCounts = new int[overload.Parameters.Length];
for (int i = 0; i < overload.Parameters.Length; i++)
{
if (overload.Parameters[i].TypeVariants != null)
{
hasVariants = true;
variantCounts[i] = overload.Parameters[i].TypeVariants.Length + 1;
}
else
{
variantCounts[i] = 1;
}
}
if (hasVariants)
{
int totalVariants = variantCounts[0];
for (int i = 1; i < variantCounts.Length; i++) totalVariants *= variantCounts[i];
for (int i = 0; i < totalVariants; i++)
{
TypeReference[] parameters = new TypeReference[overload.Parameters.Length];
int div = 1;
for (int j = 0; j < parameters.Length; j++)
{
int k = (i / div) % variantCounts[j];
parameters[j] = overload.Parameters[j].WithVariant(k, enums);
if (j > 0) div *= variantCounts[j];
}
newDefinitions.Add(overload.WithParameters(parameters));
}
}
else
{
newDefinitions.Add(overload);
}
}
return newDefinitions.ToArray();
}
}
class OverloadDefinition
{
public string ExportedName { get; }
public string FriendlyName { get; }
public TypeReference[] Parameters { get; }
public Dictionary<string, string> DefaultValues { get; }
public string ReturnType { get; }
public string StructName { get; }
public bool IsMemberFunction { get; }
public string Comment { get; }
public bool IsConstructor { get; }
public bool IsDestructor { get; }
public bool IsInternal { get; }
public OverloadDefinition(
string exportedName,
string friendlyName,
TypeReference[] parameters,
Dictionary<string, string> defaultValues,
string returnType,
string structName,
string comment,
bool isConstructor,
bool isDestructor,
bool isInternal)
{
ExportedName = exportedName;
FriendlyName = friendlyName;
Parameters = parameters;
DefaultValues = defaultValues;
ReturnType = returnType.Replace("const", string.Empty).Replace("inline", string.Empty).Trim();
StructName = structName;
IsMemberFunction = !string.IsNullOrEmpty(structName);
Comment = comment;
IsConstructor = isConstructor;
IsDestructor = isDestructor;
IsInternal = isInternal;
}
public OverloadDefinition WithParameters(TypeReference[] parameters)
{
return new OverloadDefinition(ExportedName, FriendlyName, parameters, DefaultValues, ReturnType, StructName, Comment, IsConstructor, IsDestructor, IsInternal);
}
}
}