discont ports & change token queueing

This commit is contained in:
2026-06-22 15:54:20 +02:00
parent f3184ed633
commit 3d9a9cd158
+76 -120
View File
@@ -17,9 +17,6 @@ abstract class Cpp2BeefGenerator
{
None = 0,
PreseveColumns = 1,
/// WIP
Port = 2,
}
protected virtual void GetNameInBindings(CXCursor cursor, String outString)
@@ -182,8 +179,11 @@ abstract class Cpp2BeefGenerator
MacroDefinition(cursor);
case .InclusionDirective, .MacroExpansion, .CXXBaseSpecifier, .CXXAccessSpecifier,
.LinkageSpec, .TemplateTypeParameter, .NonTypeTemplateParameter, .StaticAssert: // ignored
default: Debug.WriteLine(scope $"Unhandled cursor: {_}");
.LinkageSpec, .TemplateTypeParameter, .NonTypeTemplateParameter, .StaticAssert,
.UsingDeclaration, .UnexposedDecl, .FriendDecl: // ignored
default:
if (Clang.IsAttribute(_) == 0)
Debug.WriteLine(scope $"Unhandled cursor: {_}");
}
}
@@ -217,8 +217,8 @@ abstract class Cpp2BeefGenerator
private StreamWriter currentWritter;
private append String wrapperTemplateChain = .(16);
private append String templateParams = .(16);
private append String templateParamsWhere = .(64);
public append String templateParams = .(16);
public append String templateParamsWhere = .(64);
private String defferedWrapperWrite = null;
private struct UnitMacroIndex : this(uint32 line, CXFile file), IHashable
@@ -228,10 +228,13 @@ abstract class Cpp2BeefGenerator
}
protected class FileInfo : this(CXSourceLocation prevEnd, CXFile file)
{
public enum QueuedTokens { None = 0, LSquirly = 1, RSquirly = _<<1, Semicolon = _<<1 }
public uint queuedRSquirly = 0;
public uint queuedLSquirly = 0;
public uint queuedSemicolon = 0;
public bool NoTokensQueued =>
queuedLSquirly == 0 && queuedRSquirly == 0 && queuedSemicolon == 0;
public append String block = .(64);
public QueuedTokens queuedTokens = .None;
public (CXType type, int32 curWidth) bitfield = default;
}
protected FileInfo fileInfo = null;
@@ -300,8 +303,7 @@ abstract class Cpp2BeefGenerator
Runtime.FatalError("You must set a language via Args (e.g. --language=c++)");
}
#endif
CXTranslationUnit_Flags unitFlags = .DetailedPreprocessingRecord;
if (!Flags.HasFlag(.Port)) unitFlags |= .SkipFunctionBodies;
CXTranslationUnit_Flags unitFlags = .DetailedPreprocessingRecord | .SkipFunctionBodies;
unit = Clang.ParseTranslationUnit(index, headerPath, args.Ptr, (.)args.Length, null, 0, (.)unitFlags);
if (unit == default) return .Err(.ParsingFailed);
@@ -516,13 +518,13 @@ abstract class Cpp2BeefGenerator
protected virtual void WriteComments(CXSourceLocation writeUntil, Block? block = null)
{
var block;
if (fileInfo.queuedTokens != .None) block = null;
if (!fileInfo.NoTokensQueued) 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);
defer { fileInfo.prevEnd = writeUntil; }
if (!Flags.HasFlag(.Port) && Clang.File_IsEqual(curFile, prevFile) == 0)
if (Clang.File_IsEqual(curFile, prevFile) == 0)
Internal.FatalError(scope $"{GetFilePath!(curFile)} does not match {GetFilePath!(prevFile)} {FatalErrorMsg(..scope .(256))}");
var between = Clang.GetRange(
@@ -564,7 +566,7 @@ abstract class Cpp2BeefGenerator
void Block()
{
if (fileInfo.queuedTokens != .None) return;
if (!fileInfo.NoTokensQueued) return;
findMacros: do
{
for (uint32 ln = line; ln < curLine; ln++)
@@ -578,11 +580,34 @@ abstract class Cpp2BeefGenerator
}
bool first = true;
bool isWritingQueuedToken = false;
for (let token in tokens)
{
if (!FilterTokensBetweenCursors(token, let isWritingQueuedToken))
bool prevWritingQueuedToken = isWritingQueuedToken;
isWritingQueuedToken = false;
switch (Clang.GetTokenKind(token))
{
case .Comment:
case .Punctuation:
mixin QueuedToken(ref uint queuedToken, StringView spelling)
{
if (queuedToken > 0 && GetTokenSpelling!(token) == spelling)
{
isWritingQueuedToken = true;
queuedToken--;
}
}
QueuedToken!(ref fileInfo.queuedLSquirly, "{");
QueuedToken!(ref fileInfo.queuedRSquirly, "}");
if (prevWritingQueuedToken) // only write a semicolon after a '}'
QueuedToken!(ref fileInfo.queuedSemicolon, ";");
if (!isWritingQueuedToken) continue;
default:
continue;
if (isWritingQueuedToken && fileInfo.queuedTokens == .None)
}
if (isWritingQueuedToken && fileInfo.NoTokensQueued)
block = @block;
let location = Clang.GetTokenLocation(unit, token);
Clang.GetFileLocation(location, ?, let startLine, ?, ?);
@@ -602,34 +627,6 @@ abstract class Cpp2BeefGenerator
if (@block.HasValue) WriteBlock(@block.Value);
}
protected virtual bool FilterTokensBetweenCursors(CXToken token, out bool isWritingQueuedToken)
{
isWritingQueuedToken = false;
switch (Clang.GetTokenKind(token))
{
case .Comment:
case .Punctuation:
mixin QueuedToken(var queuedToken, StringView spelling)
{
if (fileInfo.queuedTokens.HasFlag(queuedToken) && GetTokenSpelling!(token) == spelling)
{
fileInfo.queuedTokens ^= queuedToken;
isWritingQueuedToken = true;
}
}
QueuedToken!(decltype(fileInfo.queuedTokens).LSquirly, "{");
QueuedToken!(decltype(fileInfo.queuedTokens).RSquirly, "}");
if (!fileInfo.queuedTokens.HasFlag(.RSquirly))
QueuedToken!(decltype(fileInfo.queuedTokens).Semicolon, ";");
if (!isWritingQueuedToken) return false;
default:
return false;
}
return true;
}
protected enum TypeParamMode { None, InParam, OutParam }
protected virtual void Type(CXType type, TypeParamMode paramMode = .None)
{
@@ -695,12 +692,12 @@ abstract class Cpp2BeefGenerator
case .StructDecl, .ClassDecl, .UnionDecl: Record(decl);
default: Internal.FatalError(scope $"Unhandled anon type: {_} {FatalErrorMsg(..scope .(256))}");
}
if (fileInfo.queuedTokens.HasFlag(.RSquirly))
if (fileInfo.queuedRSquirly > 0)
{
str.Append('\n');
GetIndentation(GetCursorAnchor(decl), str);
str.Append('}');
fileInfo.queuedTokens ^= .RSquirly;
fileInfo.queuedRSquirly--;
}
break;
}
@@ -823,14 +820,8 @@ abstract class Cpp2BeefGenerator
protected mixin BeginBody(CXCursor cursor)
{
static void SetQueuedTokens(FileInfo fileInfo, FileInfo.QueuedTokens queuedTokens)
{
fileInfo.queuedTokens |= queuedTokens;
}
fileInfo.prevEnd = GetCursorAnchor(cursor);
defer:mixin SetQueuedTokens(fileInfo, fileInfo.queuedTokens);
fileInfo.queuedTokens = .LSquirly;
fileInfo.queuedLSquirly++;
// [Friend] is needed in case you use BeginBody! in your code
if (canChangeBlock)
@@ -849,7 +840,7 @@ abstract class Cpp2BeefGenerator
this.[Friend]defferedWrapperWrite = null;
}
if (fileInfo.queuedTokens.HasFlag(.LSquirly))
if (fileInfo.queuedLSquirly > 0)
{
switch (cursor.kind)
{
@@ -860,17 +851,16 @@ abstract class Cpp2BeefGenerator
default:
str.Append(" {}");
}
fileInfo.queuedTokens = .None;
fileInfo.queuedLSquirly--;
}
else
fileInfo.queuedTokens |= .RSquirly;
fileInfo.queuedRSquirly++;
}
}
protected enum LinkageLanguage { C, Cpp }
protected virtual LinkageLanguage Linkable_Attributes(CXCursor cursor)
{
if (Flags.HasFlag(.Port)) return .C;
let mangledName = ScopeCXString!(Clang.Cursor_GetMangling(cursor));
let name = GetNameInBindings(cursor, ..scope .(mangledName.Length));
WriteCustomAttributes(cursor);
@@ -928,7 +918,7 @@ abstract class Cpp2BeefGenerator
currentCursor = cursor;
}
protected enum TypeAndNameKind { Standard, TypeAlias, ConversionFunction, Ctor, Dtor }
protected enum TypeAndNameKind { Standard, TypeAlias, ConversionFunction, Ctor, Dtor, InvokeOperator }
protected virtual void WriteTypeAndName(CXCursor cursor, CXType type, TypeAndNameKind format = .Standard)
{
bool preserveColumns = Flags.HasFlag(.PreseveColumns);
@@ -976,6 +966,7 @@ abstract class Cpp2BeefGenerator
str.Append("operator", whitespace, typeStr, templateParams);
case .Ctor: Internal.FatalError(scope $"unhandled ctor {FatalErrorMsg(..scope .(256))}");
case .Dtor: str.Append(whitespace, "Dispose");
case .InvokeOperator: str.Append(whitespace, "Invoke");
}
}
@@ -1107,35 +1098,6 @@ abstract class Cpp2BeefGenerator
}
}
protected virtual void PortCodeBody(CXCursor cursor)
{
if (!Flags.HasFlag(.Port))
{
str.Append(';');
return;
}
var cursor;
if (Clang.IsCursorDefinition(cursor) == 0)
{
cursor = Clang.GetCursorDefinition(cursor);
if (Clang.Cursor_IsNull(cursor) != 0)
{
str.Append(';');
return;
}
}
BeginBody!(@cursor);
Clang.VisitChildren(cursor, (cursor, parent, client_data) =>
{
Self self = *(.)client_data;
self.BeginCursor(cursor);
self.str.Append(ScopeCXString!(Clang.GetCursorPrettyPrinted(cursor, self.printingPolicy)));
return .Continue;
}, &(this, default(void)));
}
protected virtual void FunctionDecl(CXCursor cursor)
{
Linkable_Attributes(cursor);
@@ -1146,7 +1108,7 @@ abstract class Cpp2BeefGenerator
Method_Parameters(cursor);
str.Append(')');
str.Append(templateParamsWhere);
PortCodeBody(cursor);
str.Append(';');
}
protected virtual void CXXMethod(CXCursor cursor) //TODO: conversion function
@@ -1156,8 +1118,9 @@ abstract class Cpp2BeefGenerator
Linkable_Attributes(cursor);
}
TypeAndNameKind invokeOperatorKind = .Standard;
let spelling = GetCursorSpelling!(cursor);
if (spelling.StartsWith("operator"))
if (spelling.StartsWith("operator")) do
{
if (spelling == "operator[]")
{
@@ -1175,17 +1138,30 @@ abstract class Cpp2BeefGenerator
return;
}
if (spelling == "operator()")
{
invokeOperatorKind = .InvokeOperator;
break;
}
int n = 0;
for (let c in spelling["operator".Length...])
if (c == '=')
n++;
Attributes();
AccessSpecifier(cursor);
str.Append("static extern ");
WriteTypeAndName(cursor, Clang.GetCursorResultType(cursor),
if (n != 1) str.Append("static ");
str.Append("extern ");
WriteTypeAndName(cursor, n == 1 ? .() { kind = .Void } : Clang.GetCursorResultType(cursor),
cursor.kind == .ConversionFunction ? .ConversionFunction : .Standard);
str.Append("(in Self, ");
str.Append('(');
if (n != 1) str.Append("in Self, ");
Method_Parameters(cursor);
if (str.EndsWith(", ")) str.Length -= 2;
str.Append(')');
str.Append(templateParamsWhere);
PortCodeBody(cursor);
str.Append(';');
return;
}
@@ -1198,7 +1174,7 @@ abstract class Cpp2BeefGenerator
case .Constructor: WriteTypeAndName(cursor, default, .Ctor);
case .Destructor: WriteTypeAndName(cursor, Clang.GetCursorResultType(cursor), .Dtor);
case .CXXMethod:
WriteTypeAndName(cursor, Clang.GetCursorResultType(cursor));
WriteTypeAndName(cursor, Clang.GetCursorResultType(cursor), invokeOperatorKind);
default:
Internal.FatalError(scope $"Unhandled c++ method kind {FatalErrorMsg(..scope .(256))}");
}
@@ -1208,7 +1184,7 @@ abstract class Cpp2BeefGenerator
if (Clang.CXXMethod_IsStatic(cursor) == 0 && Clang.CXXMethod_IsConst(cursor) == 0 && cursor.kind == .CXXMethod)
str.Append(" mut");
str.Append(templateParamsWhere);
PortCodeBody(cursor);
str.Append(';');
}
int bitfieldUniquenessCounter = 0;
@@ -1289,15 +1265,6 @@ abstract class Cpp2BeefGenerator
WriteTypeAndName(cursor, type);
str.Append(';');
default:
if (Flags.HasFlag(.Port))
{
AccessSpecifier(cursor);
str.Append("static ");
WriteTypeAndName(cursor, type);
WriteTokensAfterEquals(cursor);
str.Append(';');
}
else
Internal.FatalError(scope $"Unhandled var linkage: {_} {FatalErrorMsg(..scope .(256))}");
}
}
@@ -1322,9 +1289,8 @@ abstract class Cpp2BeefGenerator
protected virtual void Record(CXCursor cursor, bool attributes = true)
{
bool port = Flags.HasFlag(.Port);
WriteCustomAttributes(cursor);
if (attributes && !port)
if (attributes)
switch (cursor.kind)
{
case .StructDecl, .ClassDecl: str.Append("[CRepr] ");
@@ -1332,14 +1298,13 @@ abstract class Cpp2BeefGenerator
default: Internal.FatalError(scope $"Unhandled record type {FatalErrorMsg(..scope .(256))}");
}
AccessSpecifier(cursor);
if (cursor.kind == .ClassDecl && port)
if (cursor.kind == .ClassDecl)
str.Append("class ");
else
str.Append("struct ");
if (Clang.Cursor_IsAnonymous(cursor) == 0)
GetNameInBindings(cursor, str);
str.Append(templateParams);
if (!port)
Clang.VisitChildren(cursor, (cursor, parent, client_data) =>
{
if (cursor.kind != .Destructor) return .Continue;
@@ -1366,7 +1331,7 @@ abstract class Cpp2BeefGenerator
}
}, Internal.UnsafeCastToPtr(this));*/
if (!wrapperTemplateChain.IsEmpty && !port)
if (!wrapperTemplateChain.IsEmpty)
{
//WriteQueuedOpenSquirly();
str.Append("private const String __cpp_type = \"", GetCursorSpelling!(cursor), "<\"");
@@ -1409,14 +1374,6 @@ abstract class Cpp2BeefGenerator
if (Clang.IsVirtualBase(cursor) != 0)
Internal.FatalError(scope $"Virtual bases are not supported {self.FatalErrorMsg(..scope .(256))}");
if (self.Flags.HasFlag(.Port))
{
if (*firstBase) self.str.Append(" : ");
else self.str.Append(", ");
self.Type(Clang.GetCursorType(cursor));
}
else
{
//self.WriteQueuedOpenSquirly();
if (*firstBase && hasVTable && !HasVTable(Clang.GetCursorDefinition(cursor)))
self.str.Append(self.cursorIndent, "private void* cppVtable;\n");
@@ -1425,13 +1382,12 @@ abstract class Cpp2BeefGenerator
self.str.Append("using ");
self.Type(Clang.GetCursorType(cursor));
self.str.Append(";\n");
}
*firstBase = false;
return .Continue;
}, &(this, &firstBase, hasVTable));
if (firstBase && hasVTable && !port)
if (firstBase && hasVTable)
str.Append(cursorIndent, "private void* cppVtable;\n");
Clang.VisitChildren(cursor, (cursor, parent, client_data) =>
@@ -1451,7 +1407,7 @@ abstract class Cpp2BeefGenerator
self.AccessSpecifier(cursor);
self.str.Append("using ");
self.Record(cursor, attributes: false);
self.fileInfo.queuedTokens |= .Semicolon;
self.fileInfo.queuedSemicolon++;
}
else
self.WriteCursor(cursor);