Compare commits
10 Commits
fa90624c84
...
69ed4727dd
| Author | SHA1 | Date | |
|---|---|---|---|
| 69ed4727dd | |||
| 57b94c558e | |||
| 0bb0a4e4fc | |||
|
|
69ed2da625 | ||
|
|
98d72bc6cd | ||
|
|
f56fad47af | ||
|
|
27c414501a | ||
|
|
6c648ae0cb | ||
|
|
8766c55bbb | ||
|
|
09748b9eeb |
6
CxxBuilder/.gitignore
vendored
6
CxxBuilder/.gitignore
vendored
@@ -1,6 +0,0 @@
|
||||
build
|
||||
recovery
|
||||
test
|
||||
BeefSpace_User.toml
|
||||
|
||||
dist/*
|
||||
@@ -1,29 +0,0 @@
|
||||
FileVersion = 1
|
||||
|
||||
[Project]
|
||||
Name = "CxxBuilder"
|
||||
StartupObject = "CxxBuilder.Program"
|
||||
|
||||
[Configs.Debug.Win32]
|
||||
TargetDirectory = "$(ProjectDir)/dist"
|
||||
|
||||
[Configs.Debug.Win64]
|
||||
TargetDirectory = "$(ProjectDir)/dist"
|
||||
|
||||
[Configs.Release.Win32]
|
||||
TargetDirectory = "$(ProjectDir)/dist"
|
||||
|
||||
[Configs.Release.Win64]
|
||||
TargetDirectory = "$(ProjectDir)/dist"
|
||||
|
||||
[Configs.Paranoid.Win32]
|
||||
TargetDirectory = "$(ProjectDir)/dist"
|
||||
|
||||
[Configs.Paranoid.Win64]
|
||||
TargetDirectory = "$(ProjectDir)/dist"
|
||||
|
||||
[Configs.Test.Win32]
|
||||
TargetDirectory = "$(ProjectDir)/dist"
|
||||
|
||||
[Configs.Test.Win64]
|
||||
TargetDirectory = "$(ProjectDir)/dist"
|
||||
@@ -1,5 +0,0 @@
|
||||
FileVersion = 1
|
||||
Projects = {CxxBuilder = {Path = "."}}
|
||||
|
||||
[Workspace]
|
||||
StartupProject = "CxxBuilder"
|
||||
@@ -1,157 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace CxxBuilder;
|
||||
|
||||
static class FileMatcher
|
||||
{
|
||||
public enum Error
|
||||
{
|
||||
ExpectedEscapeSequence,
|
||||
CharacterClassNotClosed,
|
||||
}
|
||||
|
||||
public static Result<void, Error> HandleMatches(Span<StringView> patterns, StringView directory, delegate void(StringView match) callback)
|
||||
{
|
||||
Runtime.Assert(Directory.Exists(directory), scope $"No such directory {directory}");
|
||||
void Dir(StringView dir)
|
||||
{
|
||||
dir: for (let element in Directory.Enumerate(dir))
|
||||
{
|
||||
let path = element.GetFilePath(..scope .());
|
||||
path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
if (element.IsDirectory)
|
||||
{
|
||||
Dir(path);
|
||||
continue;
|
||||
}
|
||||
let relpath = Path.GetRelativePath(path, directory, ..scope .());
|
||||
for (let pattern in patterns)
|
||||
{
|
||||
if (!pattern.StartsWith('^') && !pattern.StartsWith('!')) continue;
|
||||
if (IsMatch(pattern[1...], relpath))
|
||||
continue dir;
|
||||
}
|
||||
for (let pattern in patterns)
|
||||
{
|
||||
if (pattern.StartsWith('^') || pattern.StartsWith('!')) continue;
|
||||
if (!IsMatch(pattern, relpath)) continue;
|
||||
callback(relpath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Dir(directory);
|
||||
return .Ok;
|
||||
}
|
||||
|
||||
public static Result<bool, Error> IsMatch(StringView pattern, StringView path)
|
||||
{
|
||||
var pattern, path;
|
||||
|
||||
Result<bool, Error> Matches(StringView pattern, char8 c)
|
||||
{
|
||||
if (pattern.IsEmpty) return false;
|
||||
|
||||
switch (pattern[0])
|
||||
{
|
||||
case '*':
|
||||
if (pattern.Length > 1 && pattern[1] == '*')
|
||||
return true;
|
||||
return !Path.IsDirectorySeparatorChar(c);
|
||||
case '?': return true;
|
||||
case '\\':
|
||||
if (pattern.Length <= 1) return .Err(.ExpectedEscapeSequence);
|
||||
return c == pattern[1];
|
||||
case '/': return Path.IsDirectorySeparatorChar(c);
|
||||
case '[':
|
||||
int i = 0;
|
||||
char8 Next()
|
||||
{
|
||||
if (pattern.Length <= ++i)
|
||||
return (.)7;
|
||||
return pattern[i];
|
||||
}
|
||||
bool negated = false;
|
||||
char8 current;
|
||||
switch (Next())
|
||||
{
|
||||
case (.)7: return .Err(.CharacterClassNotClosed);
|
||||
case '^', '!': negated = true; fallthrough;
|
||||
case '\\': current = Next();
|
||||
case ']': return false;
|
||||
default: current = _;
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
if (c == current) return !negated;
|
||||
switch (Next())
|
||||
{
|
||||
case ']': return negated;
|
||||
case '-':
|
||||
let end = Next();
|
||||
if (c >= current && c <= end)
|
||||
return !negated;
|
||||
current = Next();
|
||||
case '\\': current = Next();
|
||||
default: current = _;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return c == _;
|
||||
}
|
||||
}
|
||||
|
||||
reduce: while (true)
|
||||
{
|
||||
if (path.IsEmpty) return true;
|
||||
if (pattern.IsEmpty) return false;
|
||||
switch (Matches(pattern, path[0]))
|
||||
{
|
||||
case .Err: return _;
|
||||
case .Ok(false): return false;
|
||||
case .Ok:
|
||||
}
|
||||
switch (pattern[0])
|
||||
{
|
||||
case '*':
|
||||
StringView lazy;
|
||||
if (pattern.Length > 1)
|
||||
{
|
||||
lazy = pattern;
|
||||
lazy.RemoveFromStart(pattern[1] == '*' ? 2 : 1);
|
||||
}
|
||||
else lazy = .();
|
||||
defer { pattern = lazy; }
|
||||
while (true)
|
||||
{
|
||||
if (Try!(IsMatch(lazy, path))) continue reduce;
|
||||
if (!Try!(Matches(pattern, path[0]))) continue reduce;
|
||||
path.RemoveFromStart(1);
|
||||
if (path.IsEmpty) return lazy.IsEmpty;
|
||||
}
|
||||
case '[':
|
||||
bool escaped = false;
|
||||
while (true)
|
||||
{
|
||||
let c = pattern[0];
|
||||
pattern.RemoveFromStart(1);
|
||||
if (c == ']' && !escaped)
|
||||
{
|
||||
path.RemoveFromStart(1);
|
||||
continue reduce;
|
||||
}
|
||||
escaped = c == '\\';
|
||||
}
|
||||
case '\\':
|
||||
pattern.RemoveFromStart(2);
|
||||
path.RemoveFromStart(1);
|
||||
default:
|
||||
pattern.RemoveFromStart(1);
|
||||
path.RemoveFromStart(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace CxxBuilder;
|
||||
|
||||
static class Program
|
||||
{
|
||||
[CLink] static extern int32 system(char8*);
|
||||
|
||||
public static int Main(String[] args)
|
||||
{
|
||||
mixin PrintUsage()
|
||||
{
|
||||
Console.WriteLine("""
|
||||
Simple and fast build tool using clang and ninja.
|
||||
|
||||
Usage: $(Var CxxBuilderExe) [<options>] <patterns...> -- src=<> target=<> config=<> builddir=<> output=<> [cflags=<>]
|
||||
Example: $(Var CxxBuilderExe) **.c vk_*.cpp -- "src=$(ProjectDir)/MyLib/src" target=$(TargetTriple) config=$(Configuration) "builddir=$(BuildDir)" output=MyLib cflags=-Isome/dir
|
||||
|
||||
--template - TODO
|
||||
--cmake - builds $src/CMakeLists.txt to build, patterns and output are ignored
|
||||
|
||||
$src - The source dir, all patterns are rooted here
|
||||
$target - the llvm target triple passed to clang
|
||||
$config - the build configuration
|
||||
$builddir - contains build artifacts and ninja files
|
||||
$output - the name of the output object archive $builddir/$output.lib on windows and $builddir/$output.a elsewhere
|
||||
$cflags - additional flags passed to clang
|
||||
""");
|
||||
return 1;
|
||||
}
|
||||
|
||||
mixin Assert(bool condition, StringView str)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
Console.WriteLine(str);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
enum { Default, CMake, Template } mode = .Default;
|
||||
StringView src = null, target = null, config = null, builddir = null, output = null, cflags = null;
|
||||
var iter = args.GetEnumerator();
|
||||
skipPatterns: do
|
||||
{
|
||||
for (let arg in iter)
|
||||
{
|
||||
if (arg == "--") break skipPatterns;
|
||||
if (arg == "--cmake")
|
||||
{
|
||||
Assert!(mode == .Default, "Conflicting options");
|
||||
mode = .CMake;
|
||||
}
|
||||
}
|
||||
PrintUsage!();
|
||||
}
|
||||
for (let arg in iter)
|
||||
{
|
||||
var parts = arg.Split('=', 2);
|
||||
StringView key = parts.GetNext().Value;
|
||||
StringView value;
|
||||
switch (parts.GetNext())
|
||||
{
|
||||
case .Err: PrintUsage!();
|
||||
case .Ok(out value):
|
||||
}
|
||||
key.Trim();
|
||||
value.Trim();
|
||||
switch (key)
|
||||
{
|
||||
case "src": Assert!(src.IsNull, "Duplicate var 'src'"); src = value;
|
||||
case "target": Assert!(target.IsNull, "Duplicate var 'target'"); target = value;
|
||||
case "config": Assert!(config.IsNull, "Duplicate var 'config'"); config = value;
|
||||
case "builddir": Assert!(builddir.IsNull, "Duplicate var 'builddir'"); builddir = value;
|
||||
case "output": Assert!(output.IsNull, "Duplicate var 'output'"); output = value;
|
||||
case "cflags": Assert!(cflags.IsNull, "Duplicate var 'cflags'"); cflags = value;
|
||||
default: PrintUsage!();
|
||||
}
|
||||
}
|
||||
Assert!(!src.IsNull, "Missing var 'src'");
|
||||
Assert!(!target.IsNull, "Missing var 'target'");
|
||||
Assert!(!config.IsNull, "Missing var 'config'");
|
||||
Assert!(!builddir.IsNull, "Missing var 'builddir'");
|
||||
Assert!(!output.IsNull || mode == .CMake, "Missing var 'output'");
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case .Default:
|
||||
StreamWriter writer = scope .()..Create(scope $"{builddir}/build.ninja");
|
||||
{
|
||||
String buffer = scope .(1024);
|
||||
let currentDir = Directory.GetCurrentDirectory(..scope .(128));
|
||||
void WriteVarPath(StringView key, StringView value)
|
||||
{
|
||||
buffer.Append(key);
|
||||
buffer.Append(" = ");
|
||||
Path.GetAbsolutePath(value, currentDir, buffer);
|
||||
buffer.Append('\n');
|
||||
}
|
||||
WriteVarPath("src", src);
|
||||
WriteVarPath("builddir", builddir);
|
||||
buffer.AppendF($"""
|
||||
target = {target}
|
||||
cflags = {(config == "Release") ? "-O2" : "-O2 -g"} {cflags}
|
||||
""");
|
||||
writer.Write(buffer);
|
||||
}
|
||||
writer.Write("""
|
||||
\n
|
||||
cc = clang
|
||||
ar = ar
|
||||
|
||||
rule cc
|
||||
command = $cc $cflags -target $target -MD -MF $out.d -c -o $out $in
|
||||
deps = gcc
|
||||
depfile = $out.d
|
||||
description = Building $in
|
||||
|
||||
rule ar
|
||||
command = $ar crs $out $in
|
||||
description = Creating static lib $out
|
||||
|
||||
|
||||
""");
|
||||
String ar = scope .(1024);
|
||||
ar.AppendF($"\nbuild $builddir/{output}.{target.Contains("windows") ? "lib" : "a"}: ar");
|
||||
|
||||
int pcount = 0;
|
||||
for (let arg in args)
|
||||
{
|
||||
if (arg == "--") break;
|
||||
pcount++;
|
||||
}
|
||||
StringView[] patterns = scope .[pcount];
|
||||
for (var pattern in ref patterns)
|
||||
{
|
||||
pattern = args[@pattern];
|
||||
}
|
||||
|
||||
void HandleMatch(StringView match)
|
||||
{
|
||||
writer.Write($"build $builddir/{match}.o: cc $src/{match}\n");
|
||||
ar.Append(" $builddir/", match, ".o");
|
||||
}
|
||||
let abssrc = Path.GetAbsolutePath(src, Directory.GetCurrentDirectory(..scope .(128)), ..scope .(128));
|
||||
if (FileMatcher.HandleMatches(patterns, abssrc, scope => HandleMatch) case .Err(let err))
|
||||
{
|
||||
Console.WriteLine($"Syntax Error in Pattern: {err}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
writer.WriteLine(ar);
|
||||
case .CMake:
|
||||
#if !DEBUG
|
||||
if (File.Exists(scope $"{builddir}/build.ninja"))
|
||||
break;
|
||||
#endif
|
||||
String cmd = scope .(512);
|
||||
cmd.Append("cmake -S \"", src, "\" -B \"", builddir, "\" -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ");
|
||||
cmd.Append("-DCMAKE_C_FLAGS=\"-target ", target, " ", cflags, "\" -DCMAKE_CXX_FLAGS=\"-target ", target, " ", cflags, "\" -DCMAKE_BUILD_TYPE=");
|
||||
if (config == "Release") cmd.Append("Release");
|
||||
else cmd.Append("RelWithDebInfo");
|
||||
Assert!(system(cmd) == 0, "Build file generation failed");
|
||||
case .Template: //TODO
|
||||
}
|
||||
|
||||
let ret = system(scope $"ninja -C {builddir}");
|
||||
if (ret != 0)
|
||||
Console.WriteLine($"Failed to build {output}");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
3
Setup/.gitignore
vendored
3
Setup/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
build
|
||||
recovery
|
||||
BeefSapce_user.toml
|
||||
@@ -1,5 +0,0 @@
|
||||
FileVersion = 1
|
||||
|
||||
[Project]
|
||||
Name = "Cpp2Beef.Setup"
|
||||
StartupObject = "Cpp2Beef.Setup.Program"
|
||||
@@ -1,5 +0,0 @@
|
||||
FileVersion = 1
|
||||
Projects = {"Cpp2Beef.Setup" = {Path = "."}}
|
||||
|
||||
[Workspace]
|
||||
StartupProject = "Cpp2Beef.Setup"
|
||||
@@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Cpp2Beef.Setup;
|
||||
|
||||
static class Program
|
||||
{
|
||||
[CLink] static extern int32 system(char8*);
|
||||
static void RunCommand(char8* cmd)
|
||||
{
|
||||
Console.WriteLine($"> {StringView(cmd)}");
|
||||
if (system(cmd) != 0)
|
||||
Runtime.FatalError("Command failed");
|
||||
}
|
||||
|
||||
public static int Main(String[] args)
|
||||
{
|
||||
RunCommand("beefbuild -workspace=\"../CxxBuilder\" -config=Release");
|
||||
String setCxxBuilderExe = scope .(512);
|
||||
Path.GetAbsolutePath("../CxxBuilder/dist/CxxBuilder", Directory.GetCurrentDirectory(..scope .(128)), setCxxBuilderExe);
|
||||
#if BF_PLATFORM_WINDOWS
|
||||
setCxxBuilderExe.Append(".exe");
|
||||
#endif
|
||||
File.WriteAllText("../CxxBuilder/dist/CxxBuilderPath.txt", setCxxBuilderExe);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -157,14 +157,14 @@ static class Program
|
||||
StreamWriter includeAll = scope .()..Create("clang-c.h");
|
||||
for (let file in clangFiles)
|
||||
{
|
||||
//if (system(scope $"curl -o {clangHeaders}/{file}.h https://raw.githubusercontent.com/llvm/llvm-project/refs/heads/main/clang/include/clang-c/{file}.h") != 0)
|
||||
// Runtime.FatalError(scope $"Failed to download clang-c/{file}");
|
||||
if (system(scope $"wget -O {clangHeaders}/{file}.h https://raw.githubusercontent.com/llvm/llvm-project/refs/heads/main/clang/include/clang-c/{file}.h") != 0)
|
||||
Runtime.FatalError(scope $"Failed to download clang-c/{file}");
|
||||
includeAll.Write($"#include <clang-c/{file}.h>\n");
|
||||
}
|
||||
}
|
||||
|
||||
Directory.CreateDirectory("clang-c");
|
||||
generator.Generate("clang-c.h", null);
|
||||
generator.Generate("clang-c.h");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
266
src/Generator.bf
266
src/Generator.bf
@@ -64,6 +64,7 @@ abstract class Cpp2BeefGenerator
|
||||
}, &attrs);
|
||||
|
||||
if (Clang.GetCursorAvailability(cursor) == .Deprecated) str.Append("[Obsolete] ");
|
||||
//if (Clang.Cursor_IsFunctionInlined(cursor) != 0) str.Append("[Inline] ");
|
||||
if (cursor.kind == .EnumDecl) str.Append("[AllowDuplicates] ");
|
||||
else if (attrs.HasFlag(.Packed)) str.Append("[Packed] ");
|
||||
if (attrs.HasFlag(.NoDiscard)) str.Append("[NoDiscard] ");
|
||||
@@ -154,6 +155,9 @@ abstract class Cpp2BeefGenerator
|
||||
case .Namespace: BeginCursor(cursor); Namespace(cursor);
|
||||
case .FunctionDecl: BeginCursor(cursor); FunctionDecl(cursor);
|
||||
|
||||
case .FunctionTemplate, .ClassTemplate, .TypeAliasTemplateDecl:
|
||||
Runtime.FatalError("Templates are currently unsupported but Coming Soon tm");
|
||||
|
||||
case .CXXMethod,
|
||||
.Constructor,
|
||||
.Destructor,
|
||||
@@ -165,6 +169,7 @@ abstract class Cpp2BeefGenerator
|
||||
|
||||
case .FieldDecl: BeginCursor(cursor); FieldDecl(cursor);
|
||||
case .VarDecl: BeginCursor(cursor); VarDecl(cursor);
|
||||
case .EnumConstantDecl: BeginCursor(cursor); EnumConstantDecl(cursor);
|
||||
|
||||
case .MacroDefinition:
|
||||
if (Clang.Cursor_IsMacroFunctionLike(cursor) != 0) return;
|
||||
@@ -194,13 +199,10 @@ abstract class Cpp2BeefGenerator
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual void ModifyWrapperPrintingPolicy(CXPrintingPolicy policy) {}
|
||||
|
||||
protected CXIndex index = Clang.CreateIndex(excludeDeclarationsFromPCH: 0, displayDiagnostics: 1) ~ Clang.DisposeIndex(_);
|
||||
protected CXTranslationUnit unit;
|
||||
|
||||
protected append String str = .(1024);
|
||||
protected append String wrapperBuf = .(1024);
|
||||
protected CXCursor currentCursor = Clang.GetNullCursor();
|
||||
protected append String cursorIndent = .(16);
|
||||
|
||||
@@ -210,8 +212,6 @@ abstract class Cpp2BeefGenerator
|
||||
protected CXPrintingPolicy printingPolicy;
|
||||
|
||||
private StreamWriter currentWritter;
|
||||
private StreamWriter wrapperWritter;
|
||||
protected StringView WrapperFilePath;
|
||||
|
||||
private append String wrapperTemplateChain = .(16);
|
||||
private append String templateParams = .(16);
|
||||
@@ -226,7 +226,7 @@ abstract class Cpp2BeefGenerator
|
||||
protected class FileInfo : this(CXSourceLocation prevEnd, CXFile file)
|
||||
{
|
||||
public append String block = .(64);
|
||||
public enum { None = 0, LSquirly = 1, RSquirly = 0b10 } queuedTokens = .None;
|
||||
public enum { None = 0, LSquirly = 1, RSquirly = _<<1, Semicolon = _<<1 } queuedTokens = .None;
|
||||
public (CXType type, int32 curWidth) bitfield = default;
|
||||
}
|
||||
protected FileInfo fileInfo = null;
|
||||
@@ -276,37 +276,12 @@ abstract class Cpp2BeefGenerator
|
||||
ParsingFailed
|
||||
}
|
||||
|
||||
public Result<void, GenerationError> Generate(char8* headerPath, StringView wrapperPath)
|
||||
public Result<void, GenerationError> Generate(char8* headerPath)
|
||||
{
|
||||
unitMacros.Clear();
|
||||
fileInfos.Clear();
|
||||
lastRecordOrEnum = Clang.GetNullCursor();
|
||||
|
||||
wrapperWritter = scope .();
|
||||
if (!wrapperPath.IsNull)
|
||||
wrapperWritter.Create(wrapperPath);
|
||||
else
|
||||
wrapperWritter = null;
|
||||
WrapperFilePath = wrapperPath;
|
||||
wrapperBuf.Set("""
|
||||
#define private public
|
||||
#define protected public
|
||||
|
||||
#include <
|
||||
""");
|
||||
wrapperBuf.Append(headerPath);
|
||||
wrapperBuf.Append("""
|
||||
>
|
||||
#include <stdint.h>
|
||||
|
||||
template <typename T>
|
||||
using __type = T;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
""");
|
||||
|
||||
let args = Args;
|
||||
#if DEBUG
|
||||
findLang: do
|
||||
@@ -323,9 +298,9 @@ abstract class Cpp2BeefGenerator
|
||||
CXTranslationUnit_Flags unitFlags = .SkipFunctionBodies | .DetailedPreprocessingRecord;
|
||||
unit = Clang.ParseTranslationUnit(index, headerPath, args.Ptr, (.)args.Length, null, 0, (.)unitFlags);
|
||||
if (unit == default) return .Err(.ParsingFailed);
|
||||
|
||||
|
||||
printingPolicy = Clang.GetCursorPrintingPolicy(Clang.GetTranslationUnitCursor(unit));
|
||||
ModifyWrapperPrintingPolicy(printingPolicy);
|
||||
Clang.PrintingPolicy_SetProperty(printingPolicy, .TerseOutput, 1);
|
||||
defer Clang.PrintingPolicy_Dispose(printingPolicy);
|
||||
|
||||
PreGeneration();
|
||||
@@ -365,9 +340,6 @@ abstract class Cpp2BeefGenerator
|
||||
}, Internal.UnsafeCastToPtr(this));
|
||||
PostGeneration();
|
||||
|
||||
if (wrapperBuf.IsEmpty)
|
||||
wrapperWritter.Write("}\n\n//begin-comptime\n");
|
||||
|
||||
for (let kv in fileInfos)
|
||||
{
|
||||
fileInfo = kv.value;
|
||||
@@ -408,7 +380,6 @@ abstract class Cpp2BeefGenerator
|
||||
switch (cursor.kind)
|
||||
{
|
||||
case .FunctionTemplate, .ClassTemplate, .TypeAliasTemplateDecl:
|
||||
Runtime.FatalError("Templates are currently unsupported but Coming Soon tm");
|
||||
templateParams.Append('<');
|
||||
let len = wrapperTemplateChain.Length;
|
||||
Clang.VisitChildren(cursor, (cursor, parent, client_data) =>
|
||||
@@ -457,11 +428,6 @@ abstract class Cpp2BeefGenerator
|
||||
currentWritter.Write(str);
|
||||
str.Clear();
|
||||
}
|
||||
protected void FlushWrapper()
|
||||
{
|
||||
wrapperWritter.Write(wrapperBuf);
|
||||
wrapperBuf.Clear();
|
||||
}
|
||||
|
||||
protected virtual void GetIndentation(CXSourceLocation location, String outString)
|
||||
{
|
||||
@@ -479,7 +445,8 @@ abstract class Cpp2BeefGenerator
|
||||
for (; i < file.Length && file[i].IsWhiteSpace; i++) outString.Append(file[i]);
|
||||
}
|
||||
|
||||
protected virtual void AllWhiteSpaceUntil(CXSourceLocation from, enum { NoNewLines, YesNewLines } newlineMode)
|
||||
protected enum WhiteSpaceNewLineMode { NoNewLines, YesNewLines }
|
||||
protected virtual void AllWhiteSpaceUntil(CXSourceLocation from, WhiteSpaceNewLineMode newlineMode)
|
||||
{
|
||||
StringView file;
|
||||
uint32 offset;
|
||||
@@ -523,7 +490,7 @@ abstract class Cpp2BeefGenerator
|
||||
let cursorLocation = Clang.GetCursorLocation(cursor);
|
||||
//let rangeLocation = Clang.GetRangeStart(Clang.GetCursorExtent(cursor));
|
||||
//if (Clang.File_IsEqual(Clang.GetSpellingLocation(cursorLocation, file: ..?, ?, ?, ?), Clang.GetSpellingLocation(rangeLocation, file: ..?, ?, ?, ?)) == 0)
|
||||
return cursorLocation;
|
||||
return cursorLocation;
|
||||
//return rangeLocation;
|
||||
}
|
||||
|
||||
@@ -542,6 +509,9 @@ abstract class Cpp2BeefGenerator
|
||||
}
|
||||
protected virtual void WriteComments(CXSourceLocation writeUntil, Block? block = null)
|
||||
{
|
||||
var block;
|
||||
if (fileInfo.queuedTokens != .None) block = null;
|
||||
|
||||
Clang.GetFileLocation(writeUntil, let curFile, let curLine, let curColumn, let curOffset);
|
||||
Clang.GetFileLocation(fileInfo.prevEnd, let prevFile, let prevLine, let prevColumn, let prevOffset);
|
||||
|
||||
@@ -587,6 +557,7 @@ abstract class Cpp2BeefGenerator
|
||||
|
||||
void Block()
|
||||
{
|
||||
if (fileInfo.queuedTokens != .None) return;
|
||||
findMacros: do
|
||||
{
|
||||
for (uint32 ln = line; ln < curLine; ln++)
|
||||
@@ -618,8 +589,11 @@ abstract class Cpp2BeefGenerator
|
||||
|
||||
QueuedToken!(decltype(fileInfo.queuedTokens).LSquirly, "{");
|
||||
QueuedToken!(decltype(fileInfo.queuedTokens).RSquirly, "}");
|
||||
if (!fileInfo.queuedTokens.HasFlag(.RSquirly))
|
||||
QueuedToken!(decltype(fileInfo.queuedTokens).Semicolon, ";");
|
||||
|
||||
if (!isWritingQueuedToken) continue;
|
||||
if (fileInfo.queuedTokens == .None) block = @block;
|
||||
default: continue;
|
||||
}
|
||||
let location = Clang.GetTokenLocation(unit, token);
|
||||
@@ -637,7 +611,7 @@ abstract class Cpp2BeefGenerator
|
||||
Flush();
|
||||
}
|
||||
WriteLinesUntil!(curLine, writeUntil);
|
||||
if (block.HasValue) WriteBlock(block.Value);
|
||||
if (@block.HasValue) WriteBlock(@block.Value);
|
||||
}
|
||||
|
||||
protected enum TypeParamMode { None, InParam, OutParam }
|
||||
@@ -807,7 +781,7 @@ abstract class Cpp2BeefGenerator
|
||||
str.Append(')');
|
||||
}
|
||||
|
||||
protected void AccessSpecifier(CXCursor cursor)
|
||||
protected virtual void AccessSpecifier(CXCursor cursor)
|
||||
{
|
||||
switch (Clang.GetCXXAccessSpecifier(cursor))
|
||||
{
|
||||
@@ -818,6 +792,11 @@ abstract class Cpp2BeefGenerator
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual bool IsEmptyStructOpaque(CXCursor cursor)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected mixin BeginBody(CXCursor cursor)
|
||||
{
|
||||
fileInfo.prevEnd = GetCursorAnchor(cursor);
|
||||
@@ -845,6 +824,8 @@ abstract class Cpp2BeefGenerator
|
||||
switch (cursor.kind)
|
||||
{
|
||||
case .StructDecl, .UnionDecl, .ClassDecl:
|
||||
if (!IsEmptyStructOpaque(cursor))
|
||||
fallthrough;
|
||||
str.Append(';');
|
||||
default:
|
||||
str.Append(" {}");
|
||||
@@ -856,22 +837,18 @@ abstract class Cpp2BeefGenerator
|
||||
}
|
||||
}
|
||||
|
||||
const int int_maxDigits = scope $"{int.MaxValue:X}".Length + 1;
|
||||
protected virtual void CppWrapperName(CXCursor cursor, String outString)
|
||||
{
|
||||
String hashCode = ScopeCXString!(Clang.GetCursorUSR(cursor))
|
||||
.GetHashCode().ToString(..scope .(int_maxDigits), "X", null);
|
||||
outString.Append("cpp2beef_");
|
||||
if (hashCode.StartsWith('-')) hashCode[0] = 'm';
|
||||
outString.Append('0', int_maxDigits - hashCode.Length);
|
||||
outString.Append(hashCode);
|
||||
}
|
||||
|
||||
protected virtual enum { C, Cpp } Linkable_Attributes(CXCursor cursor)
|
||||
{
|
||||
let mangledName = ScopeCXString!(Clang.Cursor_GetMangling(cursor));
|
||||
let name = GetNameInBindings(cursor, ..scope .(mangledName.Length));
|
||||
WriteCustomAttributes(cursor);
|
||||
void LinkNameWhitespace()
|
||||
{
|
||||
if (Flags.HasFlag(.PreseveColumns))
|
||||
str..Append('\n')..Append(cursorIndent);
|
||||
else
|
||||
str.Append(' ');
|
||||
}
|
||||
if (mangledName == name)
|
||||
{
|
||||
str.Append("[CLink] ");
|
||||
@@ -881,20 +858,16 @@ abstract class Cpp2BeefGenerator
|
||||
{
|
||||
str.Append("[LinkName(");
|
||||
mangledName.QuoteString(str);
|
||||
str.Append(")] ");
|
||||
str.Append(")]");
|
||||
LinkNameWhitespace();
|
||||
return .C;
|
||||
}
|
||||
else
|
||||
{
|
||||
str.Append("[LinkName(\"");
|
||||
CppWrapperName(cursor, str);
|
||||
str.Append('"');
|
||||
if (!wrapperTemplateChain.IsEmpty)
|
||||
if (templateParams.IsEmpty)
|
||||
str.Append(" + __template_chain");
|
||||
else
|
||||
str.Append(" + CppWrapperF($\"", wrapperTemplateChain, "\")");
|
||||
str.Append(")] ");
|
||||
str.Append("[LinkName(");
|
||||
ScopeCXString!(Clang.GetCursorPrettyPrinted(cursor, printingPolicy)).QuoteString(str);
|
||||
str.Append(")]");
|
||||
LinkNameWhitespace();
|
||||
return .Cpp;
|
||||
}
|
||||
}
|
||||
@@ -923,7 +896,8 @@ abstract class Cpp2BeefGenerator
|
||||
currentCursor = cursor;
|
||||
}
|
||||
|
||||
protected virtual void WriteTypeAndName(CXCursor cursor, CXType type, enum { Standard, TypeAlias, ConversionFunction, Ctor, Dtor } format = .Standard)
|
||||
protected enum TypeAndNameKind { Standard, TypeAlias, ConversionFunction, Ctor, Dtor }
|
||||
protected virtual void WriteTypeAndName(CXCursor cursor, CXType type, TypeAndNameKind format = .Standard)
|
||||
{
|
||||
bool preserveColumns = Flags.HasFlag(.PreseveColumns);
|
||||
Flush();
|
||||
@@ -940,7 +914,7 @@ abstract class Cpp2BeefGenerator
|
||||
String whitespace;
|
||||
if (preserveColumns)
|
||||
{
|
||||
whitespace = scope .(str);
|
||||
whitespace = scope:: .(str);
|
||||
str.Clear();
|
||||
Type(type);
|
||||
whitespace.Length -= Math.Min(str.Length, whitespace.Length);
|
||||
@@ -1057,7 +1031,7 @@ abstract class Cpp2BeefGenerator
|
||||
if (Clang.Cursor_IsNull(cursor) != 0) break;
|
||||
GetNameInBindings(cursor, str);
|
||||
break token;
|
||||
}
|
||||
}
|
||||
str.Append(spelling);
|
||||
if (kind == .Literal && str.EndsWith("LL"))
|
||||
str.Length--;
|
||||
@@ -1101,89 +1075,9 @@ abstract class Cpp2BeefGenerator
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void WriteMethodWrapper(CXCursor cursor)
|
||||
{
|
||||
let parent = Clang.GetCursorType(Clang.GetCursorSemanticParent(cursor));
|
||||
var resultType = Clang.GetCursorResultType(cursor);
|
||||
bool nonStatic = (cursor.kind == .CXXMethod && Clang.CXXMethod_IsStatic(cursor) == 0) || cursor.kind == .Destructor || cursor.kind == .ConversionFunction;
|
||||
|
||||
if (!wrapperTemplateChain.IsEmpty)
|
||||
FlushWrapper();
|
||||
StringView parentSpelling = "\" + __cpp_type + \"";
|
||||
if (wrapperTemplateChain.IsEmpty)
|
||||
parentSpelling = ScopeCXString!::(Clang.GetFullyQualifiedName(parent, printingPolicy, 0));
|
||||
|
||||
if (cursor.kind == .Constructor)
|
||||
wrapperBuf.Append("__type<", parentSpelling, "> ");
|
||||
else
|
||||
{
|
||||
wrapperBuf.Append("__type<");
|
||||
wrapperBuf.Append(ScopeCXString!(Clang.GetFullyQualifiedName(resultType, printingPolicy, 0)));
|
||||
wrapperBuf.Append("> ");
|
||||
}
|
||||
CppWrapperName(cursor, wrapperBuf);
|
||||
if (!wrapperTemplateChain.IsEmpty)
|
||||
{
|
||||
if (templateParams.IsEmpty)
|
||||
wrapperBuf.Append("\" + __template_chain + \"");
|
||||
else
|
||||
wrapperBuf.Append("\" + CppWrapperF($\"", wrapperTemplateChain, "\") + \"");
|
||||
}
|
||||
wrapperBuf.Append('(');
|
||||
if (nonStatic)
|
||||
wrapperBuf.Append(parentSpelling, " *self");
|
||||
for (int i < Clang.Cursor_GetNumArguments(cursor))
|
||||
{
|
||||
let arg = Clang.Cursor_GetArgument(cursor, (.)i);
|
||||
if (nonStatic || i > 0) wrapperBuf.Append(", ");
|
||||
wrapperBuf.Append("__type<");
|
||||
wrapperBuf.Append(ScopeCXString!(Clang.GetFullyQualifiedName(Clang.GetCursorType(arg), printingPolicy, 0)));
|
||||
wrapperBuf.Append("> p");
|
||||
i.ToString(wrapperBuf);
|
||||
}
|
||||
wrapperBuf.Append(") { ");
|
||||
if (resultType.kind != .Void) wrapperBuf.Append("return ");
|
||||
if (nonStatic)
|
||||
{
|
||||
if (cursor.kind != .Destructor)
|
||||
wrapperBuf.Append("self->", GetCursorSpelling!(cursor));
|
||||
else
|
||||
wrapperBuf.Append("self->~", parentSpelling);
|
||||
}
|
||||
else if (cursor.kind == .Constructor)
|
||||
wrapperBuf.Append(parentSpelling);
|
||||
else
|
||||
wrapperBuf.Append(fullCursorName);
|
||||
wrapperBuf.Append('(');
|
||||
for (int i < Clang.Cursor_GetNumArguments(cursor))
|
||||
{
|
||||
if (i > 0) wrapperBuf.Append(", ");
|
||||
wrapperBuf.Append('p');
|
||||
i.ToString(wrapperBuf);
|
||||
}
|
||||
wrapperBuf.Append("); }");
|
||||
|
||||
if (wrapperTemplateChain.IsEmpty)
|
||||
{
|
||||
wrapperBuf.Append('\n');
|
||||
FlushWrapper();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (defferedWrapperWrite == null)
|
||||
defferedWrapperWrite = new .(1024);
|
||||
defferedWrapperWrite.Append(cursorIndent, "\t + \"extern \\\"C\\\" ");
|
||||
wrapperBuf.ToString(defferedWrapperWrite);
|
||||
defferedWrapperWrite.Append("\\n\"\n");
|
||||
wrapperBuf.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void FunctionDecl(CXCursor cursor)
|
||||
{
|
||||
if (Linkable_Attributes(cursor) == .Cpp)
|
||||
WriteMethodWrapper(cursor);
|
||||
|
||||
Linkable_Attributes(cursor);
|
||||
AccessSpecifier(cursor);
|
||||
str.Append("static extern ");
|
||||
WriteTypeAndName(cursor, Clang.GetCursorResultType(cursor));
|
||||
@@ -1198,8 +1092,7 @@ abstract class Cpp2BeefGenerator
|
||||
{
|
||||
void Attributes()
|
||||
{
|
||||
if (Linkable_Attributes(cursor) == .Cpp)
|
||||
WriteMethodWrapper(cursor);
|
||||
Linkable_Attributes(cursor);
|
||||
}
|
||||
|
||||
let spelling = GetCursorSpelling!(cursor);
|
||||
@@ -1335,18 +1228,6 @@ abstract class Cpp2BeefGenerator
|
||||
if (linkLang == .Cpp && type.kind != .LValueReference && type.kind != .RValueReference)
|
||||
str.Append("ref ");
|
||||
WriteTypeAndName(cursor, type);
|
||||
if (linkLang == .Cpp)
|
||||
{
|
||||
let wrapperName = CppWrapperName(cursor, ..scope .());
|
||||
str.Append(" { [LinkName(\"", wrapperName, "\")] get; }");
|
||||
wrapperBuf.Append("__type<");
|
||||
wrapperBuf.Append(ScopeCXString!(Clang.GetFullyQualifiedName(type, printingPolicy, 0)));
|
||||
wrapperBuf.Append("> ");
|
||||
if (type.kind != .LValueReference && type.kind != .RValueReference)
|
||||
wrapperBuf.Append('&');
|
||||
wrapperBuf.Append(wrapperName, "() { return ", fullCursorName, "; }\n");
|
||||
FlushWrapper();
|
||||
}
|
||||
str.Append(';');
|
||||
default:
|
||||
Runtime.FatalError(scope $"Unhandled var linkage: {_}");
|
||||
@@ -1371,15 +1252,16 @@ abstract class Cpp2BeefGenerator
|
||||
}, null) != 0;
|
||||
}
|
||||
|
||||
protected virtual void Record(CXCursor cursor)
|
||||
protected virtual void Record(CXCursor cursor, bool attributes = true)
|
||||
{
|
||||
WriteCustomAttributes(cursor);
|
||||
switch (cursor.kind)
|
||||
{
|
||||
case .StructDecl, .ClassDecl: str.Append("[CRepr] ");
|
||||
case .UnionDecl: str.Append("[CRepr, Union] ");
|
||||
default: Runtime.FatalError("Unhandled record type");
|
||||
}
|
||||
if (attributes)
|
||||
switch (cursor.kind)
|
||||
{
|
||||
case .StructDecl, .ClassDecl: str.Append("[CRepr] ");
|
||||
case .UnionDecl: str.Append("[CRepr, Union] ");
|
||||
default: Runtime.FatalError("Unhandled record type");
|
||||
}
|
||||
AccessSpecifier(cursor);
|
||||
str.Append("struct ");
|
||||
if (Clang.Cursor_IsAnonymous(cursor) == 0)
|
||||
@@ -1473,9 +1355,22 @@ abstract class Cpp2BeefGenerator
|
||||
Self self = (.)Internal.UnsafeCastToObject(client_data);
|
||||
if (self.fileInfo.bitfield != default && Clang.Cursor_IsBitField(cursor) == 0)
|
||||
self.DumpBitfieldStorage();
|
||||
self.WriteCursor(cursor);
|
||||
if (Clang.Cursor_IsAnonymousRecordDecl(cursor) != 0)
|
||||
self.str..TrimEnd()..Append(";");
|
||||
{
|
||||
self.BeginCursor(cursor);
|
||||
switch (cursor.kind)
|
||||
{
|
||||
case .StructDecl, .ClassDecl: self.str.Append("[CRepr] ");
|
||||
case .UnionDecl: self.str.Append("[CRepr, Union] ");
|
||||
default: Runtime.FatalError("Unhandled record type");
|
||||
}
|
||||
self.AccessSpecifier(cursor);
|
||||
self.str.Append("using ");
|
||||
self.Record(cursor, attributes: false);
|
||||
self.fileInfo.queuedTokens |= .Semicolon;
|
||||
}
|
||||
else
|
||||
self.WriteCursor(cursor);
|
||||
return .Continue;
|
||||
}, Internal.UnsafeCastToPtr(this));
|
||||
|
||||
@@ -1501,24 +1396,27 @@ abstract class Cpp2BeefGenerator
|
||||
str.Append(" : ");
|
||||
Type(Clang.GetEnumDeclIntegerType(cursor));
|
||||
str.Append(templateParamsWhere);
|
||||
}
|
||||
}
|
||||
BeginBody!(cursor);
|
||||
Clang.VisitChildren(cursor, (cursor, parent, client_data) =>
|
||||
{
|
||||
Self self = (.)Internal.UnsafeCastToObject(client_data);
|
||||
Runtime.Assert(cursor.kind == .EnumConstantDecl);
|
||||
|
||||
self.BeginCursor(cursor);
|
||||
self.WriteCustomAttributes(cursor);
|
||||
self.GetNameInBindings(cursor, self.str);
|
||||
self.WriteTokensAfterEquals(cursor);
|
||||
//Clang.GetEnumConstantDeclValue(cursor).ToString(self.str);
|
||||
self.str.Append(',');
|
||||
|
||||
self.HandleCursor(cursor);
|
||||
return .Continue;
|
||||
}, Internal.UnsafeCastToPtr(this));
|
||||
}
|
||||
|
||||
protected virtual void EnumConstantDecl(CXCursor cursor)
|
||||
{
|
||||
BeginCursor(cursor);
|
||||
WriteCustomAttributes(cursor);
|
||||
GetNameInBindings(cursor, str);
|
||||
WriteTokensAfterEquals(cursor);
|
||||
//Clang.GetEnumConstantDeclValue(cursor).ToString(str);
|
||||
str.Append(',');
|
||||
}
|
||||
|
||||
protected virtual void TypeAlias(CXCursor cursor)
|
||||
{
|
||||
CXType type;
|
||||
|
||||
Reference in New Issue
Block a user