most of the bindings

This commit is contained in:
Booklordofthedings 2024-05-21 11:12:32 +02:00
parent f53c2965fb
commit 9186c0b444
10 changed files with 350 additions and 0 deletions

1
.gitignore vendored
View file

@ -2,4 +2,5 @@
build/ build/
recovery/ recovery/
BeefSpace_User.toml BeefSpace_User.toml
output.bf

9
BeefProj.toml Normal file
View file

@ -0,0 +1,9 @@
FileVersion = 1
Dependencies = {corlib = "*", libclang-beef = "*"}
[Project]
Name = "Caa"
StartupObject = "Caa.Program"
[Configs.Debug.Win64]
DebugCommandArguments = "generate \"C:\\Users\\b\\Downloads\\sqlite-snapshot-202405081757.tar\\sqlite-snapshot-202405081757\\sqlite3.h\""

6
BeefSpace.toml Normal file
View file

@ -0,0 +1,6 @@
FileVersion = 1
Projects = {Caa = {Path = "."}, libclang-beef = "*"}
Unlocked = ["libclang-beef"]
[Workspace]
StartupProject = "Caa"

88
src/Binding.bf Normal file
View file

@ -0,0 +1,88 @@
namespace Caa;
using System;
using System.Collections;
using libclang_beef;
class Binding
{
public static List<BindingFunction> Function = new .() ~ DeleteContainerAndItems!(_);
public static List<BindingEnum> Enums = new .() ~ DeleteContainerAndItems!(_);
public static List<BindingStruct> Structs = new .() ~ DeleteContainerAndItems!(_);
public static BindingOptions Options;
public static void Bind(ref String[] pArgs, BindingOptions pOptions)
{
CXIndex index = clang_createIndex(0, 0);
CXTranslationUnit* unit;
clang_parseTranslationUnit2(
index,
pArgs[0], //TODO: This is a hack, allegedly it would be fine if we just input the file as an arg but that doesnt seem to work
(.)&pArgs, (.)pArgs.Count, null, 0,
(.)CXTranslationUnit_Flags.CXTranslationUnit_None,
out unit
);
//TODO: Error Handling
CXCursor cursor = clang_getTranslationUnitCursor(*unit);
clang_visitChildren(
cursor,
(cursor, parent, client_data) => {
if(clang_getCursorKind(cursor) == .CXCursor_FunctionDecl)
{
var name = clang_getCursorSpelling(cursor);
BindingFunction func = new .(name.text, clang_getCursorResultType(cursor));
var count = clang_Cursor_getNumArguments(cursor);
for(int i < count)
{
var arg = clang_Cursor_getArgument(cursor, (.)i);
var argType = clang_getCursorType(arg);
var argName = clang_getCursorSpelling(arg);
func.Args.Add(new .(argName.text, argType));
}
Function.Add(func);
}
else if(clang_getCursorKind(cursor) == .CXCursor_StructDecl)
{
var name = clang_getCursorSpelling(cursor);
BindingStruct strct = new .(name.text);
Structs.Add(strct);
}
else if(clang_getCursorKind(cursor) == .CXCursor_FieldDecl)
{
if(Structs.Count > 0)
Structs[Structs.Count-1].Fields.Add(new .(clang_getCursorSpelling(cursor).text, clang_getCursorType(cursor)));
}
return CXChildVisitResult.CXChildVisit_Recurse;
}, null );
clang_disposeTranslationUnit(*unit);
clang_disposeIndex(index);
}
///Generate the actual file strings and try to write them according to the input parameter and the options
public static Result<void> Generate(StringView pOutputDir = "")
{
if(pOutputDir == "")
return .Err;
String toWrite = new .();
defer delete toWrite;
for(var i in Function)
i.ToBeef(toWrite);
for(var i in Structs)
i.ToBeef(toWrite);
for(var i in Enums)
i.ToBeef(toWrite);
return System.IO.File.WriteAllText(pOutputDir, toWrite);
}
}

41
src/BindingEnum.bf Normal file
View file

@ -0,0 +1,41 @@
namespace Caa;
using System;
using System.Collections;
using System.Interop;
class BindingEnum
{
public class BindingEnumEntry
{
public String Name ~ delete _;
public c_int Value;
public this(StringView pName, c_int pValue)
{
Name = new .(pName);
Value = pValue;
}
}
public String Name ~ delete _;
public List<BindingEnumEntry> Entries = new .() ~ delete _;
public this(StringView pName)
{
Name = new .(pName);
}
///Generate the beef representation of an enum
public void ToBeef(String pBuffer)
{
pBuffer.Append(scope $"""
[AllowDublicates]
public enum {Name}
\{\n
""");
for(var i in Entries)
pBuffer.Append(scope $"{i.Name} = {i.Value},\n");
pBuffer.Append("}\n");
}
}

39
src/BindingFunction.bf Normal file
View file

@ -0,0 +1,39 @@
namespace Caa;
using System;
using System.Collections;
using libclang_beef;
class BindingFunction
{
public class BindingFunctionArgument
{
public String Name ~ delete _;
public BindingType Type ~ delete _;
public this(StringView pName, CXType pType)
{
Name = new .(pName);
Type = new .(pType);
}
}
public String Name ~ delete _;
public BindingType Output ~ delete _;
public List<BindingFunctionArgument> Args = new .() ~ DeleteContainerAndItems!(_);
public this(StringView pName, CXType pOutput)
{
Name = new .(pName);
Output = new .(pOutput);
}
public void ToBeef(String pBuffer)
{
pBuffer.Append("[CLink]\n");
pBuffer.Append(scope $"public static extern {Output.TypeName} {Name}(");
for(var i in Args)
pBuffer.Append(scope $"{@i.Index != 0 ? ',' : ' '} {i.Type.TypeName} {i.Name != String.Empty ? i.Name : scope String(scope $"bf_arg{@i.Index}")}");
pBuffer.Append(");\n");
}
}

5
src/BindingOptions.bf Normal file
View file

@ -0,0 +1,5 @@
namespace Caa;
class BindingOptions
{
}

41
src/BindingStruct.bf Normal file
View file

@ -0,0 +1,41 @@
namespace Caa;
using System;
using System.Collections;
using libclang_beef;
class BindingStruct
{
public class BindingStructField
{
public String Name ~ delete _;
public BindingType Type ~ delete _;
public this(StringView pName, CXType pType)
{
Name = new .(pName);
Type = new .(pType);
}
}
public String Name ~ delete _;
public List<BindingStructField> Fields = new .() ~ DeleteContainerAndItems!(_);
public this(StringView pName)
{
Name = new .(pName);
}
public void ToBeef(String pBuffer)
{
pBuffer.Append(scope $"""
[CRepr]
public struct {Name}
\{\n
""");
for(var i in Fields)
pBuffer.Append(scope $"\tpublic {i.Type.TypeName} {i.Name};\n");
pBuffer.Append("}\n");
}
}

46
src/BindingType.bf Normal file
View file

@ -0,0 +1,46 @@
namespace Caa;
using System;
using System.Collections;
using libclang_beef;
class BindingType
{
///how the basic c types convert to beef
public static Dictionary<String, String> TypeConversions = new .() {
("unsigned short","c_ushort"),
("short","c_short"),
("unsigned int","c_uint"),
("int","c_int"),
("unsigned","c_uint"),
("long","c_long"),
("unsigned long","c_ulong"),
("long long","c_longlong"),
("unsigned long long","c_ulonglong"),
("char","c_char"),
("unsigned char","c_uchar"),
("intptr_t","c_intptr"),
("uintptr_t","c_uintptr"),
("wchar_t","c_wchar"),
} ~ delete _;
public String TypeName ~ delete _;
public this(CXType pType)
{
var spelling = clang_getTypeSpelling(pType);
TypeName = new .(spelling.text);
TypeName.Replace("const"," ");
//First we try to see if we can translate the spelling
String translate = scope .(TypeName);
translate.Replace("*","");
translate.TrimEnd();
translate.TrimStart();
if(TypeConversions.ContainsKey(translate))
TypeName.Replace(translate, TypeConversions[translate]);
TypeName.Replace(" ", "");
//TODO: bools exist and we should really be able to autoparse those
}
}

74
src/Program.bf Normal file
View file

@ -0,0 +1,74 @@
namespace Caa;
using System;
class Program
{
public static int Main(String[] args)
{
Console.WriteLine("""
Caa - Generate a Beef binding for c headers
Version 1.0.0
-------------------------------------------
First you need to input your arguments like the ones you would pass into clang
(This includes the path to the input header)
First give me the amount of arguments you want to have.
""");
String paramCount = scope .();
if(Console.ReadLine(paramCount) case .Err)
{
PrintError("ERROR: Could not read your input");
return -1;
}
var count = int.Parse(paramCount);
if(count case .Err)
{
PrintError("ERROR: Could not parse the input number into a int");
return -1;
}
String[] arguments = new String[count.Value];
defer delete arguments;
for(var i < arguments.Count)
{
Console.WriteLine(scope $"Please input your argument at offset {i}");
String arg = scope:: .();
if(Console.ReadLine(arg) case .Err)
{
PrintError("ERROR: Could not read your argument");
return -1;
}
arguments[i] = arg;
}
BindingOptions options = scope .();
Binding.Bind(ref arguments, options);
Console.WriteLine("Finished analyzing the file now please input your output directory/file");
String output = scope .();
if(Console.ReadLine(output) case .Err)
{
PrintError("ERROR: Could not read the output directory");
return -1;
}
if(Binding.Generate(output) case .Err)
{
PrintError("ERROR: Could not properly generate or output the binding");
return -1;
}
Console.Read();
return 0;
}
private static void PrintError(StringView pText)
{
Console.ForegroundColor = .Red;
Console.WriteLine(pText);
Console.ForegroundColor = .White;
}
}