235 строки
7.2 KiB
C#
235 строки
7.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text.Json;
|
|
using System.Threading.Tasks;
|
|
using CppAst;
|
|
|
|
namespace SkiaSharpGenerator
|
|
{
|
|
public abstract class BaseTool
|
|
{
|
|
protected readonly Dictionary<string, TypeMapping> typeMappings = new Dictionary<string, TypeMapping>();
|
|
protected readonly Dictionary<string, FunctionMapping> functionMappings = new Dictionary<string, FunctionMapping>();
|
|
protected readonly Dictionary<string, bool> skiaTypes = new Dictionary<string, bool>();
|
|
|
|
protected readonly List<string> excludedFiles = new List<string>();
|
|
protected readonly List<string> excludedTypes = new List<string>();
|
|
|
|
protected CppCompilation compilation = new CppCompilation();
|
|
protected Config config = new Config();
|
|
|
|
protected BaseTool(string skiaRoot, string configFile)
|
|
{
|
|
SkiaRoot = skiaRoot ?? throw new ArgumentNullException(nameof(skiaRoot));
|
|
ConfigFile = configFile ?? throw new ArgumentNullException(nameof(configFile));
|
|
}
|
|
|
|
public ILogger? Log { get; set; }
|
|
|
|
public string SkiaRoot { get; }
|
|
|
|
public string ConfigFile { get; }
|
|
|
|
public bool HasErrors =>
|
|
compilation?.Diagnostics?.HasErrors ?? false;
|
|
|
|
public IEnumerable<CppDiagnosticMessage> Messages =>
|
|
compilation?.Diagnostics?.Messages ?? Array.Empty<CppDiagnosticMessage>();
|
|
|
|
protected void ParseSkiaHeaders()
|
|
{
|
|
Log?.LogVerbose("Parsing skia headers...");
|
|
|
|
var options = new CppParserOptions();
|
|
|
|
foreach (var header in config.IncludeDirs)
|
|
{
|
|
var path = Path.Combine(SkiaRoot, header);
|
|
options.IncludeFolders.Add(path);
|
|
}
|
|
|
|
var headers = new List<string>();
|
|
foreach (var header in config.Headers)
|
|
{
|
|
var path = Path.Combine(SkiaRoot, header.Key);
|
|
options.IncludeFolders.Add(path);
|
|
foreach (var filter in header.Value)
|
|
{
|
|
headers.AddRange(Directory.EnumerateFiles(path, filter));
|
|
}
|
|
}
|
|
|
|
foreach (var filter in config.Exclude.Files)
|
|
{
|
|
excludedFiles.AddRange(Directory.EnumerateFiles(SkiaRoot, filter));
|
|
}
|
|
|
|
foreach (var filter in config.Exclude.Types)
|
|
{
|
|
excludedTypes.Add(filter);
|
|
excludedTypes.Add(filter + "*");
|
|
excludedTypes.Add(filter + "**");
|
|
}
|
|
|
|
foreach (var f in excludedFiles)
|
|
Log?.LogVerbose("Skipping everything in: " + f);
|
|
|
|
compilation = CppParser.ParseFiles(headers, options);
|
|
|
|
if (compilation == null || compilation.HasErrors)
|
|
{
|
|
Log?.LogError("Parsing headers failed.");
|
|
throw new Exception("Parsing headers failed.");
|
|
}
|
|
}
|
|
|
|
protected void LoadStandardMappings()
|
|
{
|
|
Log?.LogVerbose("Loading standard types...");
|
|
|
|
var standardMappings = new Dictionary<string, string>
|
|
{
|
|
// stdint.h types:
|
|
{ "uint8_t", nameof(Byte) },
|
|
{ "uint16_t", nameof(UInt16) },
|
|
{ "uint32_t", nameof(UInt32) },
|
|
{ "uint64_t", nameof(UInt64) },
|
|
{ "usize_t" , "/* usize_t */ " + nameof(UIntPtr) },
|
|
{ "uintptr_t" , nameof(UIntPtr) },
|
|
{ "int8_t", nameof(SByte) },
|
|
{ "int16_t", nameof(Int16) },
|
|
{ "int32_t", nameof(Int32) },
|
|
{ "int64_t", nameof(Int64) },
|
|
{ "size_t" , "/* size_t */ " + nameof(IntPtr) },
|
|
{ "intptr_t" , nameof(IntPtr) },
|
|
|
|
// standard types:
|
|
{ "bool", nameof(Byte) },
|
|
{ "char", "/* char */ void" },
|
|
{ "unsigned char", "/* unsigned char */ void" },
|
|
{ "signed char", "/* signed char */ void" },
|
|
{ "short", nameof(Int16) },
|
|
{ "short int", nameof(Int16) },
|
|
{ "signed short", nameof(Int16) },
|
|
{ "signed short int", nameof(Int16) },
|
|
{ "unsigned short", nameof(UInt16) },
|
|
{ "unsigned short int", nameof(UInt16) },
|
|
{ "int", nameof(Int32) },
|
|
{ "signed", nameof(Int32) },
|
|
{ "signed int", nameof(Int32) },
|
|
{ "unsigned", nameof(UInt32) },
|
|
{ "unsigned int", nameof(UInt32) },
|
|
{ "long", nameof(Int64) },
|
|
{ "long int", nameof(Int64) },
|
|
{ "long long", nameof(Int64) },
|
|
{ "long long int", nameof(Int64) },
|
|
{ "signed long", nameof(Int64) },
|
|
{ "signed long int", nameof(Int64) },
|
|
{ "unsigned long", nameof(UInt64) },
|
|
{ "unsigned long int", nameof(UInt64) },
|
|
{ "float", nameof(Single) },
|
|
{ "double", nameof(Double) },
|
|
// TODO: long double, wchar_t ?
|
|
|
|
{ "void", "void" },
|
|
};
|
|
|
|
foreach (var mapping in standardMappings)
|
|
{
|
|
var map = new TypeMapping { CsType = mapping.Value };
|
|
typeMappings[mapping.Key] = map;
|
|
}
|
|
}
|
|
|
|
protected void UpdatingMappings()
|
|
{
|
|
// load all the classes/structs
|
|
var typedefs = compilation.Classes;
|
|
foreach (var klass in typedefs)
|
|
{
|
|
typeMappings[klass.GetDisplayName()] = new TypeMapping();
|
|
}
|
|
|
|
// load all the enums
|
|
var enums = compilation.Enums;
|
|
foreach (var enm in enums)
|
|
{
|
|
typeMappings[enm.GetDisplayName()] = new TypeMapping();
|
|
}
|
|
|
|
// load the mapping file
|
|
foreach (var mapping in config.Mappings.Types)
|
|
{
|
|
typeMappings[mapping.Key] = mapping.Value;
|
|
}
|
|
foreach (var mapping in config.Mappings.Functions)
|
|
{
|
|
functionMappings[mapping.Key] = mapping.Value;
|
|
}
|
|
}
|
|
|
|
protected async Task<Config> LoadConfigAsync(string configPath)
|
|
{
|
|
Log?.LogVerbose("Loading configuration...");
|
|
|
|
using var configJson = File.OpenRead(configPath);
|
|
|
|
return await JsonSerializer.DeserializeAsync<Config>(configJson, new JsonSerializerOptions
|
|
{
|
|
AllowTrailingCommas = true,
|
|
ReadCommentHandling = JsonCommentHandling.Skip,
|
|
});
|
|
}
|
|
|
|
protected string GetType(CppType type)
|
|
{
|
|
var typeName = GetCppType(type);
|
|
|
|
// split the type from the pointers
|
|
var pointerIndex = typeName.IndexOf("*");
|
|
var pointers = pointerIndex == -1 ? "" : typeName.Substring(pointerIndex);
|
|
var noPointers = pointerIndex == -1 ? typeName : typeName.Substring(0, pointerIndex);
|
|
|
|
if (skiaTypes.TryGetValue(noPointers, out var isStruct))
|
|
{
|
|
if (!isStruct)
|
|
return noPointers + pointers.Substring(1);
|
|
if (typeMappings.TryGetValue(noPointers, out var map))
|
|
return (map.CsType ?? Utils.CleanName(noPointers)) + pointers;
|
|
}
|
|
else
|
|
{
|
|
if (typeMappings.TryGetValue(typeName, out var map))
|
|
return map.CsType ?? Utils.CleanName(typeName);
|
|
if (typeMappings.TryGetValue(noPointers, out map))
|
|
return (map.CsType ?? Utils.CleanName(noPointers)) + pointers;
|
|
if (functionMappings.TryGetValue(typeName, out var funcMap))
|
|
return funcMap.CsType ?? Utils.CleanName(typeName);
|
|
if (functionMappings.TryGetValue(noPointers, out funcMap))
|
|
return (funcMap.CsType ?? Utils.CleanName(noPointers)) + pointers;
|
|
}
|
|
|
|
return Utils.CleanName(typeName);
|
|
}
|
|
|
|
protected static string GetCppType(CppType type)
|
|
{
|
|
var typeName = type.GetDisplayName();
|
|
|
|
// remove the const
|
|
typeName = typeName.Replace("const ", "");
|
|
|
|
// replace the [] with a *
|
|
int start;
|
|
while ((start = typeName.IndexOf("[")) != -1)
|
|
{
|
|
var end = typeName.IndexOf("]");
|
|
typeName = typeName.Substring(0, start) + "*" + typeName.Substring(end + 1);
|
|
}
|
|
|
|
return typeName;
|
|
}
|
|
}
|
|
}
|