353 lines
10 KiB
Beef
353 lines
10 KiB
Beef
using System;
|
|
using System.IO;
|
|
using System.Collections;
|
|
using System.Diagnostics;
|
|
|
|
using Cpp2Beef;
|
|
using LibClang;
|
|
|
|
namespace SDL3.Setup;
|
|
|
|
class SDL3Generator : Cpp2BeefGenerator, this(Span<char8*> args)
|
|
{
|
|
protected override Span<char8*> Args => args;
|
|
protected override Flags Flags => .None;
|
|
|
|
private BumpAllocator alloc = new .() ~ delete _;
|
|
|
|
append Dictionary<String, StreamWriter> writers = .(16);
|
|
protected override StreamWriter GetWriterForHeader(StringView header)
|
|
{
|
|
String filename = Path.GetFileNameWithoutExtension(header, ..scope .(64));
|
|
if (!filename.StartsWith("SDL_") || filename == "SDL_begin_code") return null;
|
|
if (writers.TryAdd(filename, let keyPtr, let valuePtr))
|
|
{
|
|
*keyPtr = new:alloc .(filename);
|
|
*valuePtr = new:alloc .()..Create(scope $"../src/{filename}.bf")..Write("""
|
|
// This file was generated by Cpp2Beef
|
|
|
|
using System;
|
|
using System.Interop;
|
|
using static SDL3.SDL;
|
|
|
|
namespace SDL3;
|
|
|
|
|
|
""");
|
|
}
|
|
return *valuePtr;
|
|
}
|
|
|
|
protected override Block GetCursorBlock(CXCursor cursor)
|
|
{
|
|
if (Path.GetFileName(GetFilePath!(fileInfo.file), ..scope .(128)).StartsWith("SDL_test"))
|
|
return .CustomBlock("SDLTest");
|
|
return .CustomBlock("SDL");
|
|
}
|
|
|
|
protected override void HandleCursor(CXCursor cursor)
|
|
{
|
|
switch (cursor.kind)
|
|
{
|
|
case .MacroDefinition:
|
|
if (Clang.Cursor_IsMacroFunctionLike(cursor) != 0 && GetFilePath!(fileInfo.file).EndsWith("SDL_version.h"))
|
|
{
|
|
BeginCursor(cursor);
|
|
let tokens = ScopeTokenize!(cursor, unit);
|
|
WriteCustomAttributes(cursor);
|
|
str.Append("public static ");
|
|
if (GetCursorSpelling!(cursor) == "SDL_VERSION_ATLEAST")
|
|
str.Append("bool ");
|
|
else
|
|
str.Append("c_int ");
|
|
GetNameInBindings(cursor, str);
|
|
bool inArgs = true;
|
|
for (let token in tokens[1...])
|
|
{
|
|
if (inArgs)
|
|
{
|
|
let spelling = GetTokenSpelling!(token);
|
|
if (spelling == ")")
|
|
{
|
|
inArgs = false;
|
|
str.Append(") => ");
|
|
continue;
|
|
}
|
|
if (Clang.GetTokenKind(token) == .Identifier)
|
|
str.Append("c_int ");
|
|
str.Append(spelling);
|
|
if (spelling == ",")
|
|
str.Append(' ');
|
|
}
|
|
else
|
|
WriteToken(token);
|
|
}
|
|
str.Append(';');
|
|
return;
|
|
}
|
|
|
|
let spelling = GetCursorSpelling!(cursor);
|
|
if (spelling.StartsWith("SDL_PRI") || spelling.StartsWith("VK_DEFINE_"))
|
|
return;
|
|
switch (spelling)
|
|
{
|
|
case "FONT_LINE_HEIGHT":
|
|
BeginCursor(cursor);
|
|
str.Append("public static c_int FONT_LINE_HEIGHT => (FONT_CHARACTER_SIZE + 2);");
|
|
return;
|
|
case "PFN_xrGetInstanceProcAddr":
|
|
BeginCursor(cursor);
|
|
str.Append("public typealias PFN_xrGetInstanceProcAddr = SDL.FunctionPointer;");
|
|
return;
|
|
case "main", "SDL_SIZE_MAX", "SDL_FUNCTION", "SDL_FILE", "SDL_ASSERT_FILE", "SDL_LINE", "SDL_SCOPED_CAPABILITY", "SDL_NO_THREAD_SAFETY_ANALYSIS":
|
|
return;
|
|
}
|
|
case .TypedefDecl:
|
|
String prefix = scope .(64);
|
|
var spelling = GetCursorSpelling!(cursor);
|
|
|
|
if (spelling == "SDL_Keycode")
|
|
prefix.Set("SDLK_");
|
|
else
|
|
{
|
|
if (!spelling.StartsWith("SDL_")) fallthrough;
|
|
spelling.RemoveFromStart(4);
|
|
|
|
/*if (GetTypeSpelling!(Clang.GetTypedefDeclUnderlyingType(cursor)) != "Uint32")
|
|
fallthrough;*/
|
|
|
|
if (spelling == "TrayEntryFlags")
|
|
spelling = "Trayentry";
|
|
else if (spelling == "MouseButtonFlags")
|
|
spelling = "Button";
|
|
else if (spelling.EndsWith("Flags"))
|
|
spelling.RemoveFromEnd(5);
|
|
else if (spelling.EndsWith("Flag"))
|
|
spelling.RemoveFromEnd(4);
|
|
/*else if (spelling.EndsWith("ID"))
|
|
spelling.RemoveFromEnd(2);*/
|
|
else if (spelling == "BlendMode")
|
|
spelling = "Blendmode";
|
|
else if (spelling == "GLContextResetNotification")
|
|
spelling = "GlContextReset";
|
|
else if (spelling == "GLProfile")
|
|
spelling = "GlContextProfile";
|
|
else if (spelling == "Keycode")
|
|
spelling = "K";
|
|
else if (spelling != "GPUShaderFormat")
|
|
fallthrough;
|
|
if (spelling.StartsWith("GL"))
|
|
{
|
|
spelling = scope:: String(spelling);
|
|
spelling[1] = 'l';
|
|
}
|
|
|
|
prefix.Append("SDL");
|
|
if (spelling.StartsWith("GPU"))
|
|
{
|
|
prefix.Append("_GPU_");
|
|
for (let c in spelling[3...])
|
|
prefix.Append(c.ToUpper);
|
|
prefix.Append('_');
|
|
}
|
|
else
|
|
{
|
|
for (let c in spelling)
|
|
{
|
|
if (c.IsUpper) prefix.Append('_');
|
|
prefix.Append(c.ToUpper);
|
|
}
|
|
prefix.Append('_');
|
|
}
|
|
}
|
|
|
|
BeginCursor(cursor);
|
|
if (spelling == "Button") str.Append("[AllowDuplicates] ");
|
|
AccessSpecifier(cursor);
|
|
str.Append("enum ");
|
|
GetNameInBindings(cursor, str);
|
|
str.Append(" : ");
|
|
Type(Clang.GetTypedefDeclUnderlyingType(cursor));
|
|
void FixCurly()
|
|
{
|
|
if (fileInfo.queuedTokens.HasFlag(.LSquirly))
|
|
str.Append("\n{");
|
|
if (fileInfo.queuedTokens.HasFlag(.RSquirly))
|
|
str.Append("\n}");
|
|
else
|
|
str.Append("\n\t");
|
|
fileInfo.queuedTokens = .None;
|
|
}
|
|
bool isSDL_GLContextFlag = spelling == "GlContext";
|
|
{
|
|
BeginBody!(cursor);
|
|
for (let macro in this.[Friend]unitMacros)
|
|
{
|
|
let macroCursor = macro.value;
|
|
if (Clang.Cursor_IsMacroFunctionLike(macroCursor) != 0)
|
|
continue;
|
|
if (Clang.GetFileLocation(Clang.GetCursorLocation(macroCursor), ..?, ?, ?, ?) != fileInfo.file)
|
|
continue;
|
|
var macroSpelling = GetCursorSpelling!(macroCursor);
|
|
if (!macroSpelling.StartsWith(prefix))
|
|
continue;
|
|
if (isSDL_GLContextFlag)
|
|
{
|
|
if (!macroSpelling.EndsWith("_FLAG"))
|
|
continue;
|
|
macroSpelling.RemoveFromEnd(5);
|
|
}
|
|
macroSpelling.RemoveFromStart(prefix.Length);
|
|
BeginCursor(macroCursor);
|
|
FixCurly();
|
|
if (macroSpelling[0].IsDigit) str.Append('_');
|
|
UpperSnakeCase2PascalCase(macroSpelling, str);
|
|
let tokens = ScopeTokenize!(macroCursor, unit);
|
|
AllWhiteSpaceBetween(Clang.GetRangeEnd(Clang.GetTokenExtent(unit, tokens[0])), Clang.GetRangeStart(Clang.GetTokenExtent(unit, tokens[1])));
|
|
str.Append("= ");
|
|
WriteTokens(tokens[1...], Clang.GetNullLocation(), .Punctuation);
|
|
str.Append(',');
|
|
@macro.Remove();
|
|
WriteComments(Clang.GetCursorLocation(macroCursor));
|
|
}
|
|
}
|
|
FixCurly();
|
|
return;
|
|
default:
|
|
}
|
|
base.HandleCursor(cursor);
|
|
}
|
|
|
|
protected override void GetNameInBindings(CXCursor cursor, String outString)
|
|
{
|
|
bool RemovePrefix(ref StringView view)
|
|
{
|
|
if (view.StartsWith("SDLTest_")) view.RemoveFromStart(8);
|
|
else if (view.StartsWith("SDL_")) view.RemoveFromStart(4);
|
|
else return false;
|
|
return true;
|
|
}
|
|
|
|
var spelling = GetCursorSpelling!(cursor);
|
|
if (!RemovePrefix(ref spelling))
|
|
{
|
|
if (cursor.kind == .MacroDefinition)
|
|
switch (spelling)
|
|
{
|
|
case "NULL": outString.Append("null"); return;
|
|
case "TRUE": outString.Append("true"); return;
|
|
case "FALSE": outString.Append("false"); return;
|
|
}
|
|
base.GetNameInBindings(cursor, outString);
|
|
return;
|
|
}
|
|
switch (cursor.kind)
|
|
{
|
|
case .EnumConstantDecl:
|
|
var parentSpelling = GetCursorSpelling!(Clang.GetCursorSemanticParent(cursor));
|
|
if (parentSpelling == "SDL_GPUTextureFormat")
|
|
{
|
|
spelling.RemoveFromStart("GPU_TEXTUREFORMAT_".Length);
|
|
outString.Append(spelling);
|
|
break;
|
|
}
|
|
|
|
StringView name = UpperSnakeCase2PascalCase(spelling, ..scope .(spelling.Length));
|
|
switch (parentSpelling)
|
|
{
|
|
case "SDL_AudioFormat": parentSpelling = "Audio";
|
|
case "SDL_AssertState": parentSpelling = "Assertion";
|
|
case "SDL_GamepadBindingType": parentSpelling = "GamepadBindtype";
|
|
case "SDL_RendererLogicalPresentation": parentSpelling = "LogicalPresentation";
|
|
default:
|
|
RemovePrefix(ref parentSpelling);
|
|
}
|
|
for (let c in parentSpelling)
|
|
{
|
|
if (name[0].ToLower == c.ToLower)
|
|
name.RemoveFromStart(1);
|
|
else
|
|
break;
|
|
}
|
|
if (name[0].IsDigit)
|
|
outString.Append('_');
|
|
outString.Append(name);
|
|
default:
|
|
outString.Append(spelling);
|
|
}
|
|
}
|
|
|
|
protected override void WriteToken(CXToken token)
|
|
{
|
|
var spelling = GetTokenSpelling!(token);
|
|
switch (spelling)
|
|
{
|
|
case "size_t": str.Append("c_size"); return;
|
|
case "SDL_BUTTON_LEFT": str.Append("Left"); return;
|
|
case "SDL_BUTTON_MIDDLE": str.Append("Middle"); return;
|
|
case "SDL_BUTTON_RIGHT": str.Append("Right"); return;
|
|
case "SDL_BUTTON_X1": str.Append("X1"); return;
|
|
case "SDL_BUTTON_X2": str.Append("X2"); return;
|
|
}
|
|
if (!spelling.StartsWith("SDL_") || !spelling.EndsWith("ID"))
|
|
{
|
|
base.WriteToken(token);
|
|
return;
|
|
}
|
|
spelling.RemoveFromStart(4);
|
|
str.Append("SDL.");
|
|
str.Append(spelling);
|
|
}
|
|
|
|
protected override bool IsOutParam(CXCursor arg, CXCursor method)
|
|
{
|
|
let comment = Clang.Cursor_GetParsedComment(method);
|
|
let spelling = GetCursorSpelling!(arg);
|
|
for (let i < Clang.Comment_GetNumChildren(comment))
|
|
{
|
|
let param = Clang.Comment_GetChild(comment, i);
|
|
if (Clang.Comment_GetKind(param) != .ParamCommand ||
|
|
ScopeCXString!(Clang.ParamCommandComment_GetParamName(param)) != spelling) continue;
|
|
let paragraph = Clang.BlockCommandComment_GetParagraph(param);
|
|
if (Clang.Comment_GetNumChildren(paragraph) == 0) continue;
|
|
let paragraphChild = Clang.Comment_GetChild(paragraph, 0);
|
|
if (Clang.Comment_GetKind(paragraphChild) != .Text) continue;
|
|
StringView paragraphText = ScopeCXString!(Clang.TextComment_GetText(paragraphChild))..TrimStart();
|
|
if (paragraphText.StartsWith("a pointer filled in") || paragraphText.StartsWith("a pointer to receive")) return true;
|
|
else break;
|
|
}
|
|
return base.IsOutParam(arg, method);
|
|
}
|
|
}
|
|
|
|
class Program
|
|
{
|
|
[CLink] static extern int32 system(char8*);
|
|
|
|
public static int Main(String[] args)
|
|
{
|
|
//Runtime.Assert(system("git -C .. submodule update") == 0, "Failed to fetch SDL3, check your internet connection");
|
|
|
|
{
|
|
StreamWriter all = scope .()..Create("SDL3_all.h");
|
|
for (let file in Directory.EnumerateFiles("../SDL/include/SDL3"))
|
|
{
|
|
let filename = file.GetFileName(..scope .(64));
|
|
if (filename == "SDL_oldnames.h" || filename == "SDL_egl.h" || filename == "SDL_intrin.h" || filename == "SDL_endian.h" ||
|
|
filename == "SDL_platform_defines.h" || filename == "SDL_begin_code.h" || filename == "SDL_close_code.h" || filename.StartsWith("SDL_opengl"))
|
|
continue;
|
|
all.Write("#include <SDL3/");
|
|
all.Write(filename);
|
|
all.Write(">\n");
|
|
}
|
|
}
|
|
|
|
SDL3Generator generator = scope .(char8*[?]("--language=c", "-I../SDL/include",
|
|
"-DSDL_oldnames_h_", "-DSDL_platform_defines_h_", "-DSDL_endian_h_",
|
|
"-DCrcUint32=Uint32", "-DCrcUint8=Uint8",
|
|
"-DSDL_SLOW_MEMCPY", "-DSDL_SLOW_MEMMOVE", "-DSDL_SLOW_MEMSET", "-DSDL_DISABLE_ALLOCA", "-DSDL_DISABLE_ANALYZE_MACROS"));
|
|
generator.Generate("SDL3_all.h", null);
|
|
|
|
return 0;
|
|
}
|
|
} |