add bindings

This commit is contained in:
2026-07-12 16:21:19 +02:00
commit edb45f2a10
11 changed files with 7070 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
FileVersion = 1
[Project]
Name = "SpirVCross.Setup"
StartupObject = "SpirVCross.Setup.Program"
[Dependencies]
corlib = "*"
"Cpp2Beef.git" = {Git = "https://git.unicon-gmbh.de/Rune/Cpp2Beef.git"}
+9
View File
@@ -0,0 +1,9 @@
FileVersion = 1
ExtraPlatforms = ["Linux32", "Linux64", "macOS"]
[Workspace]
StartupProject = "SpirVCross.Setup"
[Projects]
"SpirVCross.Setup" = {Path = "."}
"Cpp2Beef.git" = {Git = "https://git.unicon-gmbh.de/Rune/Cpp2Beef.git"}
+218
View File
@@ -0,0 +1,218 @@
using System;
using System.IO;
using System.Collections;
using System.Diagnostics;
using Cpp2Beef;
using LibClang;
namespace SpirVCross.Setup;
class SpriVCrossGenerator : Cpp2BeefGenerator, this(Span<char8*> args)
{
protected override Span<char8*> Args => args;
protected override Flags Flags => .None;
StreamWriter spvWriter = new .()..Create("../src/SpirV.bf")..Write("""
// This file was generated by Cpp2Beef
using System;
using System.Interop;
namespace SpirVCross;
""") ~ delete _;
StreamWriter spvcWriter = new .()..Create("../src/SpirVCross.bf")..Write("""
// This file was generated by Cpp2Beef
using System;
using System.Interop;
namespace SpirVCross;
""") ~ delete _;
protected override StreamWriter GetWriterForHeader(StringView header)
{
// Here you define the target file to which a cursor should be written
// Returning null skips the cursor
if (header.EndsWith("spirv_cross_c.h"))
return spvcWriter;
if (header.EndsWith("spirv.h"))
return spvWriter;
return null;
}
protected override bool IsOutParam(CXCursor arg, CXCursor method)
{
let type = Clang.GetCursorType(arg);
if (type.kind != .Pointer) return false;
let spelling = GetTypeSpelling!(Clang.GetPointeeType(type));
return handles.ContainsAlt(spelling);
}
HashSet<String> handles = new .(16) ~ DeleteContainerAndItems!(_);
protected override void HandleCursor(CXCursor cursor)
{
switch (cursor.kind)
{
case .TypedefDecl:
let spelling = GetCursorSpelling!(cursor);
if (spelling == "spvc_bool")
return;
if (spelling.EndsWith("_flags"))
{
BeginCursor(cursor);
AccessSpecifier(cursor);
str.Append("typealias ");
GetNameInBindings(cursor, str);
str.Append(" = ");
GetNameInBindings(cursor, str);
str.Length--;
str.Append("Bits;");
return;
}
let type = Clang.GetTypedefDeclUnderlyingType(cursor);
let typeSpelling = GetTypeSpelling!(type);
if (!(typeSpelling.StartsWith("struct spvc_") || typeSpelling.StartsWith("const struct spvc_")) || !typeSpelling.EndsWith("_s *"))
break;
BeginCursor(cursor);
AccessSpecifier(cursor);
str.Append("struct ");
GetNameInBindings(cursor, str);
str.Append(" : int {}");
handles.Add(new .(spelling));
return;
case .StructDecl:
let spelling = GetCursorSpelling!(cursor);
if (spelling.EndsWith("_s"))
return;
default:
}
base.HandleCursor(cursor);
}
protected override void GetNameInBindings(CXCursor cursor, String outString)
{
switch (cursor.kind)
{
case .EnumDecl:
let spelling = GetCursorSpelling!(cursor);
if (spelling.StartsWith("Spv") && spelling.EndsWith('_'))
{
outString.Append(spelling[..<^1]);
return;
}
fallthrough;
case .StructDecl, .UnionDecl, .TypedefDecl:
let spelling = GetCursorSpelling!(cursor);
if (!spelling.StartsWith("spvc_"))
break;
UpperSnakeCase2PascalCase(spelling, outString);
return;
case .EnumConstantDecl:
var parentSpelling = GetCursorSpelling!(Clang.GetCursorSemanticParent(cursor));
var spelling = GetCursorSpelling!(cursor);
if (parentSpelling.StartsWith("spvc_"))
{
bool bit = false;
if (parentSpelling.EndsWith("_flag_bits"))
{
parentSpelling.RemoveFromEnd("_flag_bits".Length);
bit = true;
}
if (spelling.EndsWith("_INT_MAX") || spelling.EndsWith("_MAX_INT"))
outString.Append("//");
if (spelling.StartsWith(parentSpelling, .OrdinalIgnoreCase))
spelling.RemoveFromStart(parentSpelling.Length);
else
break;
if (bit && spelling.EndsWith("_BIT"))
spelling.RemoveFromEnd(4);
if (spelling[0] == '_' && spelling[1].IsDigit)
outString.Append('_');
UpperSnakeCase2PascalCase(spelling, outString);
}
else if (parentSpelling.StartsWith("Spv"))
{
if (parentSpelling == "SpvOp_")
parentSpelling = "Spv";
if (parentSpelling.EndsWith('_'))
parentSpelling.RemoveFromEnd(1);
StringView suffix = null;
if (parentSpelling.EndsWith("Shift"))
suffix = "Shift";
else if (parentSpelling.EndsWith("Mask"))
suffix = "Mask";
parentSpelling.RemoveFromEnd(suffix.Length);
if (spelling.StartsWith(parentSpelling))
spelling.RemoveFromStart(parentSpelling.Length);
if (spelling.EndsWith(suffix))
spelling.RemoveFromEnd(suffix.Length);
else if (spelling.StartsWith(suffix))
spelling.RemoveFromStart(suffix.Length);
if (spelling == "Max")
outString.Append("//");
if (spelling[0].IsDigit)
outString.Append('_');
outString.Append(spelling);
}
else break;
return;
case .FunctionDecl:
if (!IsInstanceMethod(cursor)) break;
let arg = Clang.Cursor_GetArgument(cursor, 0);
let handle = GetTypeSpelling!(Clang.GetCursorType(arg));
var spelling = GetCursorSpelling!(cursor);
Runtime.Assert(spelling.StartsWith(handle));
spelling.RemoveFromStart(handle.Length + 1);
UpperSnakeCase2PascalCase(spelling, outString);
return;
default:
}
base.GetNameInBindings(cursor, outString);
}
protected override void WriteToken(CXToken token)
{
let spelling = GetTokenSpelling!(token);
if (Clang.GetTokenKind(token) == .Identifier && spelling == "spvc_bool")
str.Append("SpvcBool");
else if (Clang.GetTokenKind(token) == .Literal && spelling.Length == 9 && spelling.StartsWith("0x"))
str.Append("0x0", spelling[2...]);
else
base.WriteToken(token);
}
bool IsInstanceMethod(CXCursor cursor)
{
if (Clang.Cursor_GetNumArguments(cursor) < 1)
return false;
let arg = Clang.Cursor_GetArgument(cursor, 0);
let type = GetTypeSpelling!(Clang.GetCursorType(arg));
return handles.ContainsAlt(type);
}
protected override void Method_Parameters(CXCursor cursor)
{
if (IsInstanceMethod(cursor))
str.Append("this ");
base.Method_Parameters(cursor);
}
}
class Program
{
public static int Main(String[] args)
{
scope SpriVCrossGenerator(char8*[?]("--language=c")).Generate("../SPIRV-Cross/spirv_cross_c.h");
return 0;
}
}