add bindings

This commit is contained in:
2026-06-15 16:28:17 +02:00
commit 14a89ef1e3
11 changed files with 947 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
FileVersion = 1
[Project]
Name = "MicroUI.Setup"
StartupObject = "MicroUI.Setup.Program"
[Dependencies]
corlib = "*"
"Cpp2Beef.git" = {Git = "https://git.unicon-gmbh.de/Rune/Cpp2Beef.git"}
+8
View File
@@ -0,0 +1,8 @@
FileVersion = 1
[Workspace]
StartupProject = "MicroUI.Setup"
[Projects]
"MicroUI.Setup" = {Path = "."}
"Cpp2Beef.git" = {Git = "https://git.unicon-gmbh.de/Rune/Cpp2Beef.git"}
+254
View File
@@ -0,0 +1,254 @@
using System;
using System.IO;
using System.Collections;
using System.Diagnostics;
using Cpp2Beef;
using LibClang;
namespace MicroUI.Setup;
class MicroUIGenerator : Cpp2BeefGenerator, this(Span<char8*> args)
{
protected override Span<char8*> Args => args;
protected override Flags Flags => .None;
StreamWriter writer = new .()..Create("../src/MicroUI.bf")..Write("""
// This file was generated by Cpp2Beef
using System;
using System.Interop;
namespace MicroUI;
""") ~ delete _;
protected override StreamWriter GetWriterForHeader(StringView header)
{
if (header.EndsWith("microui.h"))
return writer;
return null;
}
protected override Block GetCursorBlock(CXCursor cursor)
{
if (cursor.kind == .FunctionDecl)
return .CustomBlock("MicroUI");
return base.GetCursorBlock(cursor);
}
static int enumParentLen;
protected override void HandleCursor(CXCursor cursor)
{
switch (cursor.kind)
{
case .MacroDefinition:
let spelling = GetCursorSpelling!(cursor);
if (spelling == "MU_REAL")
return;
case .EnumDecl:
BeginCursor(cursor);
Clang.VisitChildren(cursor, (cursor, parent, client_data) =>
{
(Self self, int* parentLen) = *(.)client_data;
var spelling = GetCursorSpelling!(cursor);
Runtime.Assert(spelling.StartsWith("MU_"));
spelling.RemoveFromStart(3);
spelling = spelling[..<spelling.IndexOf('_')];
*parentLen = spelling.Length + 4;
self.str.Append("[CRepr] enum mu_");
self.str.Append(spelling);
return .Break;
}, &(this, &enumParentLen));
BeginBody!(cursor);
Clang.VisitChildren(cursor, (cursor, parent, client_data) =>
{
Self self = (.)Internal.UnsafeCastToObject(client_data);
self.HandleCursor(cursor);
return .Continue;
}, Internal.UnsafeCastToPtr(this));
enumParentLen = 0;
case .StructDecl:
if (Clang.GetCursorSemanticParent(cursor).kind == .StructDecl)
return;
if (Clang.VisitChildren(cursor, (cursor, parent, client_data) =>
{
return .Break;
}, null) == 0) return;
BeginCursor(cursor);
Record(cursor);
return;
case .FieldDecl:
let spelling = GetCursorSpelling!(cursor);
if (spelling.EndsWith("_stack") || spelling.EndsWith("_list"))
{
BeginCursor(cursor);
str.Append("[CRepr] ");
AccessSpecifier(cursor);
str.Append("struct { public c_int idx; public c_char[MU_");
for (let char in spelling)
if (char.IsLetter)
str.Append(char.ToUpper);
str.Append("_SIZE] items; } ", spelling);
str.Append(';');
return;
}
default:
}
base.HandleCursor(cursor);
}
protected override void GetNameInBindings(CXCursor cursor, String outString)
{
if (!cGetNameInBindings(cursor, outString))
base.GetNameInBindings(cursor, outString);
}
protected override void Type(CXType type, TypeParamMode paramMode = .None)
{
if (!cType(type, str, currentCursor))
base.Type(type, paramMode);
}
public static bool cGetNameInBindings(LibClang.CXCursor cursor, String outString)
{
switch (cursor.kind)
{
case .FunctionDecl:
var spelling = GetCursorSpelling!(cursor);
Runtime.Assert(spelling.StartsWith("mu_"));
spelling.RemoveFromStart(3);
UpperSnakeCase2PascalCase(spelling, outString);
case .EnumConstantDecl:
var spelling = GetCursorSpelling!(cursor);
spelling.RemoveFromStart(enumParentLen);
UpperSnakeCase2PascalCase(spelling, outString);
default:
return false;
}
return true;
}
public static bool cType(CXType type, String str, CXCursor cursor)
{
if (type.kind == .Int && cursor.kind == .FieldDecl || cursor.kind == .ParmDecl)
{
let spelling = GetCursorSpelling!(cursor);
switch (spelling)
{
case "key": str.Append("mu_KEY");
case "type": str.Append("mu_COMMAND");
case "colorid": str.Append("mu_COLOR");
case "opt": str.Append("mu_OPT");
case "icon": str.Append("mu_ICON");
case "btn": str.Append("mu_MOUSE");
default:
return false;
}
return true;
}
if (type.kind == .Int && cursor.kind == .FunctionDecl)
{
str.Append("mu_RES");
return true;
}
return false;
}
}
class MicroUIWrapperGenerator : Cpp2BeefGenerator, this(Span<char8*> args)
{
protected override Span<char8*> Args => args;
protected override Flags Flags => .None;
StreamWriter writer = new .()..Create("../src/Wrapper.bf")..Write("""
// This file was generated by Cpp2Beef
using System;
using System.Interop;
namespace MicroUI;
extension MicroUIContext
{
""") ~ delete _..Write("}\n");
protected override StreamWriter GetWriterForHeader(StringView header)
{
if (header.EndsWith("microui.h"))
return writer;
return null;
}
protected override Block GetCursorBlock(CXCursor cursor)
{
return .NoBlock;
}
protected override void GetNameInBindings(CXCursor cursor, String outString)
{
if (!MicroUIGenerator.cGetNameInBindings(cursor, outString))
base.GetNameInBindings(cursor, outString);
}
protected override void Type(CXType type, TypeParamMode paramMode = .None)
{
if (!MicroUIGenerator.cType(type, str, currentCursor))
base.Type(type, paramMode);
}
protected override void HandleCursor(CXCursor cursor)
{
if (cursor.kind != .FunctionDecl || GetCursorSpelling!(cursor) == "mu_init") return;
Flush();
Method_Parameters(cursor);
StringView parameters = scope String(str);
str.Clear();
if (!parameters.StartsWith("mu_Context* ctx"))
return;
parameters.RemoveFromStart("mu_Context* ctx".Length);
if (parameters.StartsWith(", "))
parameters.RemoveFromStart(2);
BeginCursor(cursor);
AccessSpecifier(cursor);
WriteTypeAndName(cursor, Clang.GetCursorResultType(cursor));
str.Append('(');
str.Append(parameters, ") => MicroUI.");
GetNameInBindings(cursor, str);
str.Append("(&");
let numArgs = Clang.Cursor_GetNumArguments(cursor);
for (let i < numArgs)
{
if (i > 0) str.Append(", ");
str.Append(GetCursorSpelling!(Clang.Cursor_GetArgument(cursor, (.)i)));
}
if (Clang.Cursor_IsVariadic(cursor) != 0)
{
if (numArgs > 0) str.Append(", ");
str.Append("...");
}
str.Append(");");
}
}
class Program
{
[CLink] static extern int32 system(char8*);
public static int Main(String[] args)
{
if (system("git -C .. submodule update") != 0)
{
Console.WriteLine("Failed to fetch microui, check your internet connection");
return 1;
}
scope MicroUIGenerator(char8*[?]("--language=c")).Generate("../microui/src/microui.h");
scope MicroUIWrapperGenerator(char8*[?]("--language=c")).Generate("../microui/src/microui.h");
return 0;
}
}