finish bindings

This commit is contained in:
Rune
2026-03-13 19:30:09 +01:00
parent 0d1ef97b9c
commit 28f0bcfba5
6 changed files with 6924 additions and 24 deletions

View File

@@ -13,7 +13,7 @@ class GlfwGenerator : Cpp2BeefGenerator, this(Span<char8*> args)
protected override Span<char8*> Args => args;
protected override Flags Flags => .None;
StreamWriter writer = new .()..Create(TODO)..Write("""
StreamWriter writer = new .()..Create("../src/Glfw.bf")..Write("""
// This file was generated by Cpp2Beef
using System;
@@ -21,16 +21,234 @@ class GlfwGenerator : Cpp2BeefGenerator, this(Span<char8*> args)
namespace Glfw;
static class Glfw
{
public struct Bool : c_int
{
public static operator Self(bool b) => b ? True : False;
public static operator bool(Self b) => b != False;
}
""");
// Vulkan
public typealias PFN_vkGetInstanceProcAddr = void*;
public struct VkInstance : int;
public struct VkPhysicalDevice : int;
public typealias VkResult = c_int;
public struct VkAllocationCallbacks;
public struct VkSurfaceKHR : int;
}
""") ~ delete _;
protected override StreamWriter GetWriterForHeader(StringView header)
{
if (header.EndsWith(TODO))
if (header.EndsWith("glfw3.h"))
return writer;
return null;
}
protected override void HandleCursor(CXCursor cursor)
{
switch (cursor.kind)
{
case .MacroDefinition:
if (!GetCursorSpelling!(cursor).StartsWith("GLFW_"))
return;
if (groupEnum.IsEmpty || ScopeTokenize!(cursor, unit).Length <= 1) break;
BeginCursor(cursor);
Flush();
MacroDefinition(cursor);
str.Replace("public const let ", "\t");
str.Replace(';', ',');
return;
default:
}
base.HandleCursor(cursor);
}
protected override Block GetCursorBlock(CXCursor cursor)
{
if (GetCursorSpelling!(cursor).StartsWith("glfw", .OrdinalIgnoreCase))
return .CustomBlock("Glfw");
return base.GetCursorBlock(cursor);
}
protected override void GetNameInBindings(CXCursor cursor, String outString)
{
let spelling = GetCursorSpelling!(cursor);
if (spelling.StartsWith("GLFW_"))
{
var length = outString.Length;
UpperSnakeCase2PascalCase(spelling[5...], outString);
int i = 0;
if (!groupEnum.IsEmpty)
{
StringView prefix;
switch (groupEnum)
{
case "Modifier": prefix = "Mod";
case "HatState": prefix = "Hat";
case "CursorShape": prefix = "Cursor";
default: prefix = _;
}
if (outString[length...].StartsWith(prefix))
outString.Remove(length, prefix.Length);
if (outString.EndsWith(prefix))
outString.Length -= prefix.Length;
if (outString[length].IsNumber)
outString.Insert(length, '_');
}
length = outString.Length - length;
outString.Append(' ', spelling.Length - 5 - length - i);
}
else if (spelling.StartsWith("GLFW"))
{
int index = outString.Length;
outString.Append(spelling[4...]);
outString[index] = outString[index].ToUpper;
}
else if (spelling.StartsWith("glfw"))
outString.Append(spelling[4...]);
else
base.GetNameInBindings(cursor, outString);
}
StringView GetGroupEnumName(StringView group)
{
switch (group)
{
case "hat_state": return "HatState";
case "keys": return "Key";
case "mods": return "Modifier";
case "buttons": return "MouseButton";
case "joysticks": return "Joystick";
case "gamepad_buttons": return "GamepadButton";
case "gamepad_axes": return "GamepadAxis";
case "errors": return "Error";
case "shapes": return "CursorShape";
case "init_hints": return "InitHint";
case "window_hints": return "WindowHint";
default: return null;
}
}
append String groupEnum = .(32);
int initCounter = 0;
protected override void WriteToken(CXToken token)
{
var spelling = GetTokenSpelling!(token);
if (spelling == "/*! @} */" && !groupEnum.IsEmpty)
{
groupEnum.Clear();
str.Append("}\n", spelling);
return;
}
base.WriteToken(token);
if (Clang.GetTokenKind(token) != .Comment) return;
if (spelling.StartsWith("/*! @addtogroup window"))
groupEnum.Set("WindowHint");
else if (spelling.StartsWith("/*! @addtogroup init"))
switch (initCounter++)
{
case 0: groupEnum.Set("InitHint");
case 1: groupEnum.Set("Platform");
}
else
{
if (!spelling.StartsWith("/*! @defgroup ")) return;
spelling.RemoveFromStart("/*! @defgroup ".Length);
let group = spelling[..<spelling.IndexOf(' ')];
groupEnum.Set(GetGroupEnumName(group));
if (groupEnum.IsEmpty) return;
}
str.Append("\n[CRepr, AllowDuplicates] public enum ", groupEnum, "\n{");
}
bool ScanCommandComment(CXComment comment)
{
let paragraph = Clang.BlockCommandComment_GetParagraph(comment);
let numChildren = Clang.Comment_GetNumChildren(paragraph);
for (let k < numChildren)
{
let child = Clang.Comment_GetChild(paragraph, k);
switch (Clang.Comment_GetKind(child))
{
case .Text:
let text = ScopeCXString!(Clang.TextComment_GetText(child));
if (!text.Contains("GLFW_TRUE") && !text.Contains("GLFW_FALSE")) continue;
str.Append("Bool");
return false;
case .InlineCommand:
if (Clang.Comment_GetKind(child) != .InlineCommand) continue;
if (ScopeCXString!(Clang.InlineCommandComment_GetCommandName(child)) != "ref") continue;
var group = ScopeCXString!(Clang.InlineCommandComment_GetArgText(child, 0));
group..TrimEnd('.')..TrimEnd(')');
var genum = GetGroupEnumName(group);
if (genum.IsNull) continue;
str.Append(genum);
return false;
default:
}
}
return true;
}
protected override void Method_Parameters(CXCursor cursor)
{
let numArgs = Clang.Cursor_GetNumArguments(cursor);
for (let i < numArgs)
{
if (i > 0) str.Append(", ");
let arg = Clang.Cursor_GetArgument(cursor, (.)i);
currentCursor = arg;
TypeParamMode typeParamMode = .InParam;
bool writeType = true;
let comment = Clang.Cursor_GetParsedComment(cursor);
let spelling = GetCursorSpelling!(arg);
for (let j < Clang.Comment_GetNumChildren(comment))
{
let param = Clang.Comment_GetChild(comment, j);
if (Clang.Comment_GetKind(param) != .ParamCommand) continue;
if (ScopeCXString!(Clang.ParamCommandComment_GetParamName(param)) != spelling) continue;
if (Clang.ParamCommandComment_GetDirection(param) == .Out)
typeParamMode = .OutParam;
writeType = ScanCommandComment(param);
break;
}
if (writeType) Type(Clang.GetCursorType(arg), typeParamMode);
str.Append(' ');
GetNameInBindings(arg, str);
}
if (Clang.Cursor_IsVariadic(cursor) != 0)
{
if (numArgs > 0) str.Append(", ");
str.Append("...");
}
currentCursor = cursor;
}
protected override void WriteTypeAndName(CXCursor cursor, CXType type, TypeAndNameKind format = .Standard)
{
if (cursor.kind != .FunctionDecl)
{
base.WriteTypeAndName(cursor, type, format);
return;
}
bool writeType = true;
let comment = Clang.Cursor_GetParsedComment(cursor);
for (let j < Clang.Comment_GetNumChildren(comment))
{
let ret = Clang.Comment_GetChild(comment, j);
if (Clang.Comment_GetKind(ret) != .BlockCommand) continue;
if (ScopeCXString!(Clang.BlockCommandComment_GetCommandName(ret)) != "return") continue;
writeType = ScanCommandComment(ret);
break;
}
if (writeType) Type(type);
str.Append(' ');
GetNameInBindings(cursor, str);
}
}
class Program
@@ -46,7 +264,8 @@ class Program
public static int Main(String[] args)
{
scope GlfwGenerator(char8*[?]("--language=c")).Generate(TODO, null);
RunCommand!("git -C .. submodule update");
scope GlfwGenerator(char8*[?]("--language=c", "-DGLFW_INCLUDE_VULKAN", "-Imock_include")).Generate("../glfw/include/GLFW/glfw3.h");
return 0;
}
}