diff --git a/src/Generator.bf b/src/Generator.bf index 31daa52..3650d3a 100644 --- a/src/Generator.bf +++ b/src/Generator.bf @@ -17,6 +17,9 @@ abstract class Cpp2BeefGenerator { None = 0, PreseveColumns = 1, + + /// WIP + Port = 2, } protected virtual void GetNameInBindings(CXCursor cursor, String outString) @@ -156,7 +159,7 @@ abstract class Cpp2BeefGenerator case .FunctionDecl: BeginCursor(cursor); FunctionDecl(cursor); case .FunctionTemplate, .ClassTemplate, .TypeAliasTemplateDecl: - Runtime.FatalError("Templates are currently unsupported but Coming Soon tm"); + Internal.FatalError(scope $"Templates are currently unsupported but Coming Soon tm {FatalErrorMsg(..scope .(256))}"); case .CXXMethod, .Constructor, @@ -225,8 +228,10 @@ abstract class Cpp2BeefGenerator } protected class FileInfo : this(CXSourceLocation prevEnd, CXFile file) { + public enum QueuedTokens { None = 0, LSquirly = 1, RSquirly = _<<1, Semicolon = _<<1 } + public append String block = .(64); - public enum { None = 0, LSquirly = 1, RSquirly = _<<1, Semicolon = _<<1 } queuedTokens = .None; + public QueuedTokens queuedTokens = .None; public (CXType type, int32 curWidth) bitfield = default; } protected FileInfo fileInfo = null; @@ -295,7 +300,8 @@ abstract class Cpp2BeefGenerator Runtime.FatalError("You must set a language via Args (e.g. --language=c++)"); } #endif - CXTranslationUnit_Flags unitFlags = .SkipFunctionBodies | .DetailedPreprocessingRecord; + CXTranslationUnit_Flags unitFlags = .DetailedPreprocessingRecord; + if (!Flags.HasFlag(.Port)) unitFlags |= .SkipFunctionBodies; unit = Clang.ParseTranslationUnit(index, headerPath, args.Ptr, (.)args.Length, null, 0, (.)unitFlags); if (unit == default) return .Err(.ParsingFailed); @@ -516,7 +522,8 @@ abstract class Cpp2BeefGenerator Clang.GetFileLocation(fileInfo.prevEnd, let prevFile, let prevLine, let prevColumn, let prevOffset); defer { fileInfo.prevEnd = writeUntil; } - if (Clang.File_IsEqual(curFile, prevFile) == 0) Runtime.FatalError(scope $"{GetFilePath!(curFile)} != {GetFilePath!(prevFile)}"); + if (!Flags.HasFlag(.Port) && Clang.File_IsEqual(curFile, prevFile) == 0) + Internal.FatalError(scope $"{GetFilePath!(curFile)} does not match {GetFilePath!(prevFile)} {FatalErrorMsg(..scope .(256))}"); var between = Clang.GetRange( Clang.GetLocationForOffset(unit, prevFile, prevOffset), @@ -658,7 +665,8 @@ abstract class Cpp2BeefGenerator fallthrough; case .RValueReference: str.Append("in "); - default: Runtime.FatalError(); + default: + Internal.FatalError(scope $"Unhandled in-param cursor {FatalErrorMsg(..scope .(256))}"); } case .OutParam: str.Append("out "); } @@ -676,7 +684,7 @@ abstract class Cpp2BeefGenerator { case .EnumDecl: Enum(decl); case .StructDecl, .ClassDecl, .UnionDecl: Record(decl); - default: Runtime.FatalError(scope $"Unhandled anon type: {_}"); + default: Internal.FatalError(scope $"Unhandled anon type: {_} {FatalErrorMsg(..scope .(256))}"); } if (fileInfo.queuedTokens.HasFlag(.RSquirly)) { @@ -693,7 +701,7 @@ abstract class Cpp2BeefGenerator String buffer = scope .(256); GetNameInBindings(decl, qualified); CXCursor parent = decl; - while (true) + qualify: while (true) { parent = Clang.GetCursorSemanticParent(parent); if (Clang.IsDeclaration(parent.kind) == 0 || parent.kind == .LinkageSpec) break; @@ -705,22 +713,25 @@ abstract class Cpp2BeefGenerator buffer.Append('<'); Clang.VisitChildren(parent, (cursor, parent, client_data) => { - String buffer = (.)Internal.UnsafeCastToObject(client_data); + (Self self, String buffer) = *(.)client_data; switch (cursor.kind) { case .TemplateTypeParameter, .NonTypeTemplateParameter: case .TemplateTemplateParameter: - Runtime.FatalError(scope $"C++ template template parameters are not supported"); + Internal.FatalError(scope $"C++ template template parameters are not supported {self.FatalErrorMsg(..scope .(256))}"); default: return .Continue; } buffer.Append(GetCursorSpelling!(cursor), ", "); return .Continue; - }, Internal.UnsafeCastToPtr(buffer)); + }, &(this, buffer)); buffer.Length -= 2; buffer.Append('>'); default: + let parentType = Clang.GetCursorType(parent); + if (parentType.kind == .Invalid) break qualify; + Flush(); - Type(Clang.GetCursorType(parent)); + Type(parentType); buffer.Append(str); str.Clear(); } @@ -737,12 +748,16 @@ abstract class Cpp2BeefGenerator for (let i < numTemplateArgs) { if (i > 0) str.Append(", "); - Type(Clang.Type_GetTemplateArgumentAsType(type, (.)i)); + let templateType = Clang.Type_GetTemplateArgumentAsType(type, (.)i); + if (templateType.kind == .Invalid) + str.Append(GetTypeSpelling!(type)); + else + Type(templateType); } str.Append('>'); } case .Unexposed, .DependentSizedArray: str.Append(ScopeCXString!(Clang.GetTypeSpelling(Clang.GetUnqualifiedType(type)))); // template param - default: Runtime.FatalError(scope $"Unhandled type: {_} \"{GetTypeSpelling!(type)}\""); + default: Internal.FatalError(scope $"Unhandled type: {_} \"{GetTypeSpelling!(type)}\" {FatalErrorMsg(..scope .(256))}"); } } @@ -799,8 +814,14 @@ abstract class Cpp2BeefGenerator protected mixin BeginBody(CXCursor cursor) { + static void SetQueuedTokens(FileInfo fileInfo, FileInfo.QueuedTokens queuedTokens) + { + fileInfo.queuedTokens |= queuedTokens; + } + fileInfo.prevEnd = GetCursorAnchor(cursor); - fileInfo.queuedTokens |= .LSquirly; + defer:mixin SetQueuedTokens(fileInfo, fileInfo.queuedTokens); + fileInfo.queuedTokens = .LSquirly; // [Friend] is needed in case you use BeginBody! in your code if (canChangeBlock) @@ -837,8 +858,10 @@ abstract class Cpp2BeefGenerator } } - protected virtual enum { C, Cpp } Linkable_Attributes(CXCursor cursor) + 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); @@ -942,7 +965,7 @@ abstract class Cpp2BeefGenerator String typeStr = scope .(str); str.Clear(); str.Append("operator", whitespace, typeStr, templateParams); - case .Ctor: Runtime.FatalError(); + case .Ctor: Internal.FatalError(scope $"unhandled ctor {FatalErrorMsg(..scope .(256))}"); case .Dtor: str.Append(whitespace, "Dispose"); } } @@ -1075,6 +1098,35 @@ 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); @@ -1085,7 +1137,7 @@ abstract class Cpp2BeefGenerator Method_Parameters(cursor); str.Append(')'); str.Append(templateParamsWhere); - str.Append(';'); + PortCodeBody(cursor); } protected virtual void CXXMethod(CXCursor cursor) //TODO: conversion function @@ -1100,7 +1152,8 @@ abstract class Cpp2BeefGenerator { if (spelling == "operator[]") { - Runtime.Assert(templateParams.IsEmpty, "Properties can't have generics"); + if (!templateParams.IsEmpty) + Internal.FatalError(scope $"Properties can't have generics {FatalErrorMsg(..scope .(256))}"); AccessSpecifier(cursor); if (Clang.CXXMethod_IsStatic(cursor) != 0) str.Append("static "); str.Append("extern "); @@ -1123,7 +1176,7 @@ abstract class Cpp2BeefGenerator if (str.EndsWith(", ")) str.Length -= 2; str.Append(')'); str.Append(templateParamsWhere); - str.Append(';'); + PortCodeBody(cursor); return; } @@ -1138,7 +1191,7 @@ abstract class Cpp2BeefGenerator case .CXXMethod: WriteTypeAndName(cursor, Clang.GetCursorResultType(cursor)); default: - Runtime.FatalError("Unhandled c++ method kind"); + Internal.FatalError(scope $"Unhandled c++ method kind {FatalErrorMsg(..scope .(256))}"); } str.Append('('); Method_Parameters(cursor); @@ -1146,7 +1199,7 @@ abstract class Cpp2BeefGenerator if (Clang.CXXMethod_IsStatic(cursor) == 0 && Clang.CXXMethod_IsConst(cursor) == 0 && cursor.kind == .CXXMethod) str.Append(" mut"); str.Append(templateParamsWhere); - str.Append(';'); + PortCodeBody(cursor); } int bitfieldUniquenessCounter = 0; @@ -1213,24 +1266,30 @@ abstract class Cpp2BeefGenerator let type = Clang.GetCursorType(cursor); switch (Clang.GetCursorLinkage(cursor)) { - case .Internal when Clang.IsConstQualifiedType(type) != 0: + case .Internal when Clang.IsConstQualifiedType(type) != 0 + || ScopeCXString!(Clang.GetCursorPrettyPrinted(cursor, printingPolicy)).Contains("constexpr"): AccessSpecifier(cursor); str.Append("const "); WriteTypeAndName(cursor, type); WriteTokensAfterEquals(cursor); str.Append(';'); case .External, .UniqueExternal: - Flush(); - let linkLang = Linkable_Attributes(cursor); - if (linkLang == .Cpp) str.Clear(); + Linkable_Attributes(cursor); AccessSpecifier(cursor); str.Append("static extern "); - if (linkLang == .Cpp && type.kind != .LValueReference && type.kind != .RValueReference) - str.Append("ref "); WriteTypeAndName(cursor, type); str.Append(';'); default: - Runtime.FatalError(scope $"Unhandled var linkage: {_}"); + 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))}"); } } @@ -1254,26 +1313,31 @@ abstract class Cpp2BeefGenerator protected virtual void Record(CXCursor cursor, bool attributes = true) { + bool port = Flags.HasFlag(.Port); WriteCustomAttributes(cursor); - if (attributes) + if (attributes && !port) switch (cursor.kind) { case .StructDecl, .ClassDecl: str.Append("[CRepr] "); case .UnionDecl: str.Append("[CRepr, Union] "); - default: Runtime.FatalError("Unhandled record type"); + default: Internal.FatalError(scope $"Unhandled record type {FatalErrorMsg(..scope .(256))}"); } AccessSpecifier(cursor); - str.Append("struct "); + if (cursor.kind == .ClassDecl && port) + str.Append("class "); + else + str.Append("struct "); if (Clang.Cursor_IsAnonymous(cursor) == 0) GetNameInBindings(cursor, str); str.Append(templateParams); - 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)); + 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)); str.Append(templateParamsWhere); BeginBody!(cursor); @@ -1293,7 +1357,7 @@ abstract class Cpp2BeefGenerator } }, Internal.UnsafeCastToPtr(this));*/ - if (!wrapperTemplateChain.IsEmpty) + if (!wrapperTemplateChain.IsEmpty && !port) { //WriteQueuedOpenSquirly(); str.Append("private const String __cpp_type = \"", GetCursorSpelling!(cursor), "<\""); @@ -1333,21 +1397,32 @@ abstract class Cpp2BeefGenerator { (Self self, bool* firstBase, bool hasVTable) = *(.)client_data; - Runtime.Assert(Clang.IsVirtualBase(cursor) == 0, "Virtual bases are not supported"); - //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"); + 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"); + } *firstBase = false; return .Continue; }, &(this, &firstBase, hasVTable)); - if (firstBase && hasVTable) + if (firstBase && hasVTable && !port) str.Append(cursorIndent, "private void* cppVtable;\n"); Clang.VisitChildren(cursor, (cursor, parent, client_data) => @@ -1362,7 +1437,7 @@ abstract class Cpp2BeefGenerator { case .StructDecl, .ClassDecl: self.str.Append("[CRepr] "); case .UnionDecl: self.str.Append("[CRepr, Union] "); - default: Runtime.FatalError("Unhandled record type"); + default: Internal.FatalError(scope $"Unhandled record type {self.FatalErrorMsg(..scope .(256))}"); } self.AccessSpecifier(cursor); self.str.Append("using "); @@ -1401,7 +1476,8 @@ abstract class Cpp2BeefGenerator Clang.VisitChildren(cursor, (cursor, parent, client_data) => { Self self = (.)Internal.UnsafeCastToObject(client_data); - Runtime.Assert(cursor.kind == .EnumConstantDecl); + if (cursor.kind != .EnumConstantDecl) + Internal.FatalError(scope $"Unhandled cursor: {cursor.kind} {self.FatalErrorMsg(..scope .(256))}"); self.HandleCursor(cursor); return .Continue; }, Internal.UnsafeCastToPtr(this)); @@ -1422,10 +1498,10 @@ abstract class Cpp2BeefGenerator CXType type; switch (cursor.kind) { - case .TypedefDecl: type = Clang.GetTypedefDeclUnderlyingType(cursor); - case .TypeAliasDecl: type = Clang.GetCursorType(cursor); + case .TypedefDecl, .TypeAliasDecl: + type = Clang.GetTypedefDeclUnderlyingType(cursor); default: - Runtime.FatalError("Unhandled type alias cursor kind"); + Internal.FatalError(scope $"Unhandled type alias cursor kind {FatalErrorMsg(..scope .(256))}"); } if (type.kind == .Pointer) do @@ -1447,7 +1523,8 @@ abstract class Cpp2BeefGenerator AccessSpecifier(cursor); str.Append("typealias"); WriteTypeAndName(cursor, type, .TypeAlias); - Runtime.Assert(templateParamsWhere.IsEmpty, "type aliases can't have constraints (yet)"); + if (!templateParamsWhere.IsEmpty) + Internal.FatalError(scope $"type aliases can't have constraints (yet) {FatalErrorMsg(..scope .(256))}"); } protected virtual void MacroDefinition(CXCursor cursor)