diff --git a/src/Generator.bf b/src/Generator.bf index 064aaa3..a4a6bd6 100644 --- a/src/Generator.bf +++ b/src/Generator.bf @@ -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,16 +1265,7 @@ 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))}"); + 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,21 +1298,20 @@ 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; - String str = (.)Internal.UnsafeCastToObject(client_data); - str.Append(" : IDisposable"); - return .Break; - }, Internal.UnsafeCastToPtr(str)); + Clang.VisitChildren(cursor, (cursor, parent, client_data) => + { + if (cursor.kind != .Destructor) return .Continue; + String str = (.)Internal.UnsafeCastToObject(client_data); + str.Append(" : IDisposable"); + return .Break; + }, Internal.UnsafeCastToPtr(str)); str.Append(templateParamsWhere); BeginBody!(cursor); @@ -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,29 +1374,20 @@ 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"); - self.str.Append(self.cursorIndent); - self.AccessSpecifier(cursor); - self.str.Append("using "); - self.Type(Clang.GetCursorType(cursor)); - self.str.Append(";\n"); - } + //self.WriteQueuedOpenSquirly(); + if (*firstBase && hasVTable && !HasVTable(Clang.GetCursorDefinition(cursor))) + self.str.Append(self.cursorIndent, "private void* cppVtable;\n"); + self.str.Append(self.cursorIndent); + self.AccessSpecifier(cursor); + 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);