public static string WrapWithThrow(bool isVoid, string name, IEnumerable <string> args) { var argList = string.Join("", args.Select(a => $"{a}, ")); var cs = new IndentedCodeBuilder(); cs.StartBlock("{"); cs.AppendLine($"{(isVoid ? "" : "var result = ")}{name}({argList}out char_ptr_ptr errptr);"); cs.AppendLine($"if (errptr != IntPtr.Zero)"); cs.AppendIndentedLine("throw new RocksDbException(errptr);"); if (!isVoid) { cs.AppendLine($"return result;"); } cs.EndBlock("}"); return(cs.ToString()); }
static void Main(string[] args) { if (args.Length == 0) { Console.Error.WriteLine("Usage: <exe> <version>"); Console.Error.WriteLine(" Where <exe> is this executable and <version> is something like v5.18.3"); return; } var version = args[0]; // Download the original by commit id var urlOfCHeader = $"https://raw.githubusercontent.com/facebook/rocksdb/{version}/include/rocksdb/c.h"; var original = Download(urlOfCHeader); Console.Error.WriteLine($"Using: {urlOfCHeader}"); // Transform from CRLF to LF var modified = original.Replace("\r\n", "\n"); var regions = ParseRocksHeaderFileRegion(modified).ToList(); var managedFunctions = regions.ToDictionary(r => r.Title, r => GetManagedFunctions(r).ToArray()); var nativeRawCs = new IndentedCodeBuilder(); nativeRawCs.AppendLine($"/* WARNING: This file was autogenerated from version {version} of rocksdb/c.h at"); nativeRawCs.AppendLine($" {urlOfCHeader}"); nativeRawCs.AppendLine($" */"); nativeRawCs.AppendLine(GetCsharpHeader()); nativeRawCs.AppendLine("namespace RocksDbSharp"); nativeRawCs.StartBlock("{"); nativeRawCs.AppendLine("#region Type aliases"); // Get every type in use as an argument type or a return type var typeVariations = managedFunctions .SelectMany(rmf => rmf.Value) .SelectMany(mf => mf.ReturnType.Once() .Concat(mf.Args .SelectMany(mfa => mfa.Variations.Where(mfav => mfav.TypeStrategy != "delegate")) .Select(mfav => mfav.Type) ) ) .Select(v => Regex.Replace(v, @"\[\]$", "")) .ToHashSet(); foreach (var typeAlias in GetTypeAliases(regions)) { // Find all the variations that are actually in use and include those foreach (var typeVariation in typeVariations.Where(tv => tv.Contains(typeAlias.Name))) { nativeRawCs.AppendLine(typeAlias.Variation(typeVariation)); } } nativeRawCs.AppendLine("#endregion"); nativeRawCs.AppendLine("#region Delegates"); var delegateSignatures = managedFunctions .SelectMany(rmf => rmf.Value) .SelectMany(mf => mf.Args.Select(mfa => (FuncName: mf.Name.RegexReplace(@"^rocksdb_|_create$", ""), Arg: mfa))) .SelectMany(mfa => mfa.Arg.Variations .Where(mfav => mfav.TypeStrategy == "delegate") .Select(mfav => (mfa.FuncName, mfav.Type, ArgName: mfav.Name)) ) .ToList(); var delegatesByName = delegateSignatures.GroupBy(ds => ds.ArgName); foreach (var nameGroup in delegatesByName) { var unique = nameGroup.Select(ng => ng.Type).Distinct(); if (unique.Count() == 1) { var definition = nameGroup.First(); var parsed = Regex.Match(definition.Type, @"^\((.*?)\) -> (.+)$"); var delegateReturnType = parsed.Groups[2].Value; var delegateSignature = parsed.Groups[1].Value; var delegateName = nameGroup.Key; var name = $"{SnakeCaseToPascalCase(delegateName)}Delegate"; nativeRawCs.AppendLine($"public delegate {delegateReturnType} {name}({delegateSignature});"); } else { nativeRawCs.AppendLine("// If you get the below error, then that means the c.h file in the rocksdb project"); nativeRawCs.AppendLine("// now contains delegate arguments which share a name, but have different signatures."); nativeRawCs.AppendLine("// The code generator will need logic to try to generate different names for the"); nativeRawCs.AppendLine("// different arguments"); nativeRawCs.AppendLine(string.Join("", nameGroup.Select((ng, i) => $" Arg {i + 1}: {ng.ArgName} in {ng.FuncName} with signature {ng.Type}\n"))); nativeRawCs.AppendLineWithoutIndent($"#error Unable to create single delegate because arguments named {nameGroup.Key} have different delegate signatures"); } } nativeRawCs.AppendLine("#endregion"); foreach (var region in regions.Where(r => (r.NativeEnums.Length + r.NativeFunctions.Length) > 0)) { nativeRawCs.AppendLine($"#region {region.Title}"); foreach (var managedEnum in GetManagedEnums(region)) { nativeRawCs.AppendLine(managedEnum); } nativeRawCs.AppendLine($"public partial class Native"); nativeRawCs.StartBlock("{"); foreach (var managedFunction in managedFunctions[region.Title]) { nativeRawCs.AppendLine(managedFunction.WithTypeLookup((name, type, strategy) => strategy == "delegate" ? $"{SnakeCaseToPascalCase(name)}Delegate" : type)); } nativeRawCs.EndBlock($"}} // class Native"); nativeRawCs.AppendLine($"#endregion // {region.Title}"); } nativeRawCs.EndBlock("} // namespace RocksDbSharp"); var output = nativeRawCs.ToString(); Console.WriteLine(output); Console.Error.WriteLine($"Done"); }