most of the bindings
This commit is contained in:
parent
f53c2965fb
commit
9186c0b444
10 changed files with 350 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,4 +2,5 @@
|
|||
build/
|
||||
recovery/
|
||||
BeefSpace_User.toml
|
||||
output.bf
|
||||
|
||||
|
|
9
BeefProj.toml
Normal file
9
BeefProj.toml
Normal 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
6
BeefSpace.toml
Normal file
|
@ -0,0 +1,6 @@
|
|||
FileVersion = 1
|
||||
Projects = {Caa = {Path = "."}, libclang-beef = "*"}
|
||||
Unlocked = ["libclang-beef"]
|
||||
|
||||
[Workspace]
|
||||
StartupProject = "Caa"
|
88
src/Binding.bf
Normal file
88
src/Binding.bf
Normal 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
41
src/BindingEnum.bf
Normal 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
39
src/BindingFunction.bf
Normal 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
5
src/BindingOptions.bf
Normal file
|
@ -0,0 +1,5 @@
|
|||
namespace Caa;
|
||||
|
||||
class BindingOptions
|
||||
{
|
||||
}
|
41
src/BindingStruct.bf
Normal file
41
src/BindingStruct.bf
Normal 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
46
src/BindingType.bf
Normal 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
74
src/Program.bf
Normal 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;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue