From 8766c55bbb116b4faf52875006bbaf19309b2816 Mon Sep 17 00:00:00 2001 From: Rune Date: Fri, 6 Mar 2026 18:39:22 +0100 Subject: [PATCH] fix wrapper.cpp --- src/Generator.bf | 1683 +++++++++++++++++++++++----------------------- 1 file changed, 843 insertions(+), 840 deletions(-) diff --git a/src/Generator.bf b/src/Generator.bf index 6b14505..eb339ba 100644 --- a/src/Generator.bf +++ b/src/Generator.bf @@ -24,26 +24,26 @@ abstract class Cpp2BeefGenerator let spelling = GetCursorSpelling!(cursor); getName: switch (cursor.kind) { - case .TypedefDecl: - switch (spelling) - { - case "size_t": outString.Append("c_size"); - case "wchar_t": outString.Append("c_wchar"); - case "va_list": outString.Append("VarArgs"); - case "int8_t": outString.Append("int8"); - case "int16_t": outString.Append("int16"); - case "int32_t": outString.Append("int32"); - case "int64_t": outString.Append("int64"); - case "uint8_t": outString.Append("uint8"); - case "uint16_t": outString.Append("uint16"); - case "uint32_t": outString.Append("uint32"); - case "uint64_t": outString.Append("uint64"); - case "intptr_t": outString.Append("c_intptr"); - case "uintptr_t": outString.Append("c_uintptr"); - default: fallthrough getName; - } - default: - Compiler.Identifier.GetSourceName(spelling, outString); + case .TypedefDecl: + switch (spelling) + { + case "size_t": outString.Append("c_size"); + case "wchar_t": outString.Append("c_wchar"); + case "va_list": outString.Append("VarArgs"); + case "int8_t": outString.Append("int8"); + case "int16_t": outString.Append("int16"); + case "int32_t": outString.Append("int32"); + case "int64_t": outString.Append("int64"); + case "uint8_t": outString.Append("uint8"); + case "uint16_t": outString.Append("uint16"); + case "uint32_t": outString.Append("uint32"); + case "uint64_t": outString.Append("uint64"); + case "intptr_t": outString.Append("c_intptr"); + case "uintptr_t": outString.Append("c_uintptr"); + default: fallthrough getName; + } + default: + Compiler.Identifier.GetSourceName(spelling, outString); } } @@ -56,11 +56,11 @@ abstract class Cpp2BeefGenerator AttrFlags* attrs = (.)client_data; switch (cursor.kind) { - case .PackedAttr: *attrs |= .Packed; - case .WarnUnusedResultAttr: *attrs |= .NoDiscard; - default: + case .PackedAttr: *attrs |= .Packed; + case .WarnUnusedResultAttr: *attrs |= .NoDiscard; + default: } - return .Continue; + return .Continue; }, &attrs); if (Clang.GetCursorAvailability(cursor) == .Deprecated) str.Append("[Obsolete] "); @@ -74,24 +74,24 @@ abstract class Cpp2BeefGenerator { switch (cursor.kind) { - case .StructDecl, - .ClassDecl, - .UnionDecl, - .EnumDecl, - .TypeAliasDecl, - .TypedefDecl, - .Namespace: return .NoBlock; + case .StructDecl, + .ClassDecl, + .UnionDecl, + .EnumDecl, + .TypeAliasDecl, + .TypedefDecl, + .Namespace: return .NoBlock; - case .FunctionDecl, - .CXXMethod, - .Constructor, - .Destructor, - .ConversionFunction, - .FieldDecl, - .VarDecl, - .MacroDefinition: return .StaticBlock; + case .FunctionDecl, + .CXXMethod, + .Constructor, + .Destructor, + .ConversionFunction, + .FieldDecl, + .VarDecl, + .MacroDefinition: return .StaticBlock; - default: Internal.FatalError(scope $"Missing GetCursorBlock implementation {FatalErrorMsg(..scope .(256))}"); + default: Internal.FatalError(scope $"Missing GetCursorBlock implementation {FatalErrorMsg(..scope .(256))}"); } } @@ -100,9 +100,9 @@ abstract class Cpp2BeefGenerator StringView target; switch (block) { - case .NoBlock: target = ""; - case .StaticBlock: target = "static"; - case .CustomBlock(let p0): target = p0; + case .NoBlock: target = ""; + case .StaticBlock: target = "static"; + case .CustomBlock(let p0): target = p0; } if (fileInfo.block == target) return; @@ -110,673 +110,676 @@ abstract class Cpp2BeefGenerator { str.TrimEnd(); str.Append("\n", cursorIndent, "}\n\n"); - } - fileInfo.block.Set(target); + } + fileInfo.block.Set(target); - switch (block) - { + switch (block) + { case .NoBlock: case .StaticBlock: str.Append("static\n{\n"); case .CustomBlock(let p0): str.Append("extension ", p0, "\n{\n"); - } - } - protected void BeginCursor(CXCursor cursor) - { - WriteComments(cursor, canChangeBlock ? (Block?)GetCursorBlock(cursor) : null); - fileInfo.prevEnd = Clang.GetRangeEnd(Clang.GetCursorExtent(cursor)); - } - - protected virtual void HandleCursor(CXCursor cursor) - { - switch (cursor.kind) - { - case .StructDecl, .ClassDecl, .UnionDecl, .EnumDecl: - if (Clang.Cursor_IsAnonymous(cursor) != 0) - return; - if (templateParams.IsEmpty && Clang.EqualCursors(cursor, Clang.GetTypeDeclaration(Clang.GetCursorType(cursor))) == 0) - return; - BeginCursor(cursor); - if (_ case .EnumDecl) Enum(cursor); - else Record(cursor); - - case .TypeAliasDecl, .TypedefDecl: - if (Clang.Cursor_IsNull(lastRecordOrEnum) == 0) - { - let lastName = GetNameInBindings(lastRecordOrEnum, ..scope .(64)); - let curName = GetNameInBindings(cursor, ..scope .(64)); - if (lastName == curName) return; } - BeginCursor(cursor); - TypeAlias(cursor); - - 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, - .ConversionFunction: - if (templateParams.IsEmpty && Clang.EqualCursors(Clang.GetCursorLexicalParent(cursor), Clang.GetCursorSemanticParent(cursor)) == 0) - return; - BeginCursor(cursor); - CXXMethod(cursor); - - case .FieldDecl: BeginCursor(cursor); FieldDecl(cursor); - case .VarDecl: BeginCursor(cursor); VarDecl(cursor); - - case .MacroDefinition: - if (Clang.Cursor_IsMacroFunctionLike(cursor) != 0) return; - let tokens = ScopeTokenize!(cursor, unit); - if (tokens.Length <= 1) return; - BeginCursor(cursor); - MacroDefinition(cursor); - - case .InclusionDirective, .MacroExpansion, .CXXBaseSpecifier, .CXXAccessSpecifier, - .LinkageSpec, .TemplateTypeParameter, .NonTypeTemplateParameter, .StaticAssert: // ignored - default: Debug.WriteLine(scope $"Unhandled cursor: {_}"); - } - } - - protected virtual bool IsOutParam(CXCursor arg, CXCursor method) - { - let comment = Clang.Cursor_GetParsedComment(method); - let spelling = GetCursorSpelling!(arg); - for (let i < Clang.Comment_GetNumChildren(comment)) - { - let param = Clang.Comment_GetChild(comment, i); - if (Clang.Comment_GetKind(param) != .ParamCommand) continue; - if (ScopeCXString!(Clang.ParamCommandComment_GetParamName(param)) != spelling) continue; - return Clang.ParamCommandComment_GetDirection(param) == .Out; - } - - 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); - - private bool canChangeBlock = true; - private CXCursor lastRecordOrEnum = Clang.GetNullCursor(); - protected append String fullCursorName = .(256); - protected CXPrintingPolicy printingPolicy; - - private StreamWriter currentWritter; - private StreamWriter wrapperWritter; - protected StringView WrapperFilePath; - - private append String wrapperTemplateChain = .(16); - private append String templateParams = .(16); - private append String templateParamsWhere = .(64); - private String defferedWrapperWrite = null; - - private struct UnitMacroIndex : this(uint32 line, CXFile file), IHashable - { - public int GetHashCode() => line; - public static bool operator==(Self lhs, Self rhs) => lhs.line == rhs.line && Clang.File_IsEqual(lhs.file, rhs.file) != 0; - } - protected class FileInfo : this(CXSourceLocation prevEnd, CXFile file) - { - public append String block = .(64); - public enum { None = 0, LSquirly = 1, RSquirly = 0b10 } queuedTokens = .None; - public (CXType type, int32 curWidth) bitfield = default; - } - protected FileInfo fileInfo = null; - private Dictionary fileInfos = new .(32) ~ DeleteDictionaryAndKeysAndValues!(_); - private append Dictionary unitMacros = .(128); - - public static mixin ScopeCXString(CXString str) - { - defer:mixin Clang.DisposeString(str); - StringView(Clang.GetCString(str)) - } - - public static mixin GetCursorSpelling(CXCursor cursor) - { - ScopeCXString!:mixin(Clang.GetCursorSpelling(cursor)) - } - public static mixin GetTypeSpelling(CXType type) - { - ScopeCXString!:mixin(Clang.GetTypeSpelling(type)) - } - public static mixin GetFilePath(CXFile file) - { - ScopeCXString!:mixin(Clang.GetFileName(file)) - } - protected mixin GetTokenSpelling(CXToken token) - { - ScopeCXString!:mixin(Clang.GetTokenSpelling(unit, token)) - } - - public static void UpperSnakeCase2PascalCase(StringView snakeCase, String outString) - { - bool upper = true; - for (let c in snakeCase) - if (c == '_') upper = true; - else - { - outString.Append(upper ? c.ToUpper : c.ToLower); - upper = false; } - } - - protected virtual void PreGeneration() {} - protected virtual void PostGeneration() {} - - public enum GenerationError - { - ParsingFailed - } - - public Result Generate(char8* headerPath, StringView wrapperPath) - { - 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 - - template - using __type = T; - - extern "C" + protected void BeginCursor(CXCursor cursor) { - - """); - - let args = Args; -#if DEBUG - findLang: do - { - for (let arg in args) - { - StringView view = .(arg); - if (view == "-x" || view.StartsWith("--language")) - break findLang; + WriteComments(cursor, canChangeBlock ? (Block?)GetCursorBlock(cursor) : null); + fileInfo.prevEnd = Clang.GetRangeEnd(Clang.GetCursorExtent(cursor)); } - Runtime.FatalError("You must set a language via Args (e.g. --language=c++)"); - } -#endif - 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); - defer Clang.PrintingPolicy_Dispose(printingPolicy); - - PreGeneration(); - Clang.VisitChildren(Clang.GetTranslationUnitCursor(unit), (cursor, parent, client_data) => - { - Self self = (.)Internal.UnsafeCastToObject(client_data); + protected virtual void HandleCursor(CXCursor cursor) { - let location = Clang.GetCursorLocation(cursor); - Clang.GetFileLocation(location, let file, let line, ?, ?); - let header = ScopeCXString!(Clang.GetFileName(file)); - self.currentWritter = self.GetWriterForHeader(header); - if (self.currentWritter == null) return .Continue; - - if (cursor.kind == .MacroDefinition) + switch (cursor.kind) { - self.unitMacros[.(line, file)] = cursor; - return .Continue; - } + case .StructDecl, .ClassDecl, .UnionDecl, .EnumDecl: + if (Clang.Cursor_IsAnonymous(cursor) != 0) + return; + if (templateParams.IsEmpty && Clang.EqualCursors(cursor, Clang.GetTypeDeclaration(Clang.GetCursorType(cursor))) == 0) + return; + BeginCursor(cursor); + if (_ case .EnumDecl) Enum(cursor); + else Record(cursor); - if (!self.fileInfos.TryGetAlt(header, ?, out self.fileInfo)) - { - self.fileInfo = new .(Clang.GetLocation(self.unit, file, 1, 1), file); - self.fileInfos.Add(new .(header), self.fileInfo); + case .TypeAliasDecl, .TypedefDecl: + if (Clang.Cursor_IsNull(lastRecordOrEnum) == 0) + { + let lastName = GetNameInBindings(lastRecordOrEnum, ..scope .(64)); + let curName = GetNameInBindings(cursor, ..scope .(64)); + if (lastName == curName) return; + } + BeginCursor(cursor); + TypeAlias(cursor); + + 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, + .ConversionFunction: + if (templateParams.IsEmpty && Clang.EqualCursors(Clang.GetCursorLexicalParent(cursor), Clang.GetCursorSemanticParent(cursor)) == 0) + return; + BeginCursor(cursor); + CXXMethod(cursor); + + case .FieldDecl: BeginCursor(cursor); FieldDecl(cursor); + case .VarDecl: BeginCursor(cursor); VarDecl(cursor); + + case .MacroDefinition: + if (Clang.Cursor_IsMacroFunctionLike(cursor) != 0) return; + let tokens = ScopeTokenize!(cursor, unit); + if (tokens.Length <= 1) return; + BeginCursor(cursor); + MacroDefinition(cursor); + + case .InclusionDirective, .MacroExpansion, .CXXBaseSpecifier, .CXXAccessSpecifier, + .LinkageSpec, .TemplateTypeParameter, .NonTypeTemplateParameter, .StaticAssert: // ignored + default: Debug.WriteLine(scope $"Unhandled cursor: {_}"); } } - self.WriteCursor(cursor); - - switch (cursor.kind) + protected virtual bool IsOutParam(CXCursor arg, CXCursor method) { - case .ClassDecl, .StructDecl, .EnumDecl, .UnionDecl: - self.lastRecordOrEnum = cursor; - default: - } - return .Continue; - }, Internal.UnsafeCastToPtr(this)); - PostGeneration(); - - if (wrapperBuf.IsEmpty) - wrapperWritter.Write("}\n\n//begin-comptime\n"); - - for (let kv in fileInfos) - { - fileInfo = kv.value; - currentWritter = GetWriterForHeader(kv.key); - Clang.GetFileContents(unit, kv.value.file, let size); - WriteComments(Clang.GetLocationForOffset(unit, kv.value.file, (.)size-1), .NoBlock); - Flush(); - } - - return .Ok; - } - - protected void WriteCursor(CXCursor cursor, bool macro = false) - { - if ((macro) != (cursor.kind == .MacroDefinition)) return; - - CXCursor prevCursor = currentCursor; - currentCursor = cursor; - defer { currentCursor = prevCursor; } - - int removeLenFullCursorName; - { - int curLen = fullCursorName.Length; - if (!fullCursorName.IsEmpty) - fullCursorName.Append("::"); - fullCursorName.Append(GetCursorSpelling!(cursor)); - removeLenFullCursorName = fullCursorName.Length - curLen; - } - defer { fullCursorName.Length -= removeLenFullCursorName; } - - var cursor; - int removeLenWrapperTemplateChain = 0; - defer { wrapperTemplateChain.Length -= removeLenWrapperTemplateChain; } - if (!macro) - { - templateParams.Clear(); - templateParamsWhere.Clear(); - switch (cursor.kind) - { - case .FunctionTemplate, .ClassTemplate, .TypeAliasTemplateDecl: - templateParams.Append('<'); - let len = wrapperTemplateChain.Length; - Clang.VisitChildren(cursor, (cursor, parent, client_data) => + let comment = Clang.Cursor_GetParsedComment(method); + let spelling = GetCursorSpelling!(arg); + for (let i < Clang.Comment_GetNumChildren(comment)) { - Self self = (.)Internal.UnsafeCastToObject(client_data); + let param = Clang.Comment_GetChild(comment, i); + if (Clang.Comment_GetKind(param) != .ParamCommand) continue; + if (ScopeCXString!(Clang.ParamCommandComment_GetParamName(param)) != spelling) continue; + return Clang.ParamCommandComment_GetDirection(param) == .Out; + } + + 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); + + private bool canChangeBlock = true; + private CXCursor lastRecordOrEnum = Clang.GetNullCursor(); + protected append String fullCursorName = .(256); + protected CXPrintingPolicy printingPolicy; + + private StreamWriter currentWritter; + private StreamWriter wrapperWritter; + protected StringView WrapperFilePath; + + private append String wrapperTemplateChain = .(16); + private append String templateParams = .(16); + private append String templateParamsWhere = .(64); + private String defferedWrapperWrite = null; + + private struct UnitMacroIndex : this(uint32 line, CXFile file), IHashable + { + public int GetHashCode() => line; + public static bool operator==(Self lhs, Self rhs) => lhs.line == rhs.line && Clang.File_IsEqual(lhs.file, rhs.file) != 0; + } + protected class FileInfo : this(CXSourceLocation prevEnd, CXFile file) + { + public append String block = .(64); + public enum { None = 0, LSquirly = 1, RSquirly = 0b10 } queuedTokens = .None; + public (CXType type, int32 curWidth) bitfield = default; + } + protected FileInfo fileInfo = null; + private Dictionary fileInfos = new .(32) ~ DeleteDictionaryAndKeysAndValues!(_); + private append Dictionary unitMacros = .(128); + + public static mixin ScopeCXString(CXString str) + { + defer:mixin Clang.DisposeString(str); + StringView(Clang.GetCString(str)) + } + + public static mixin GetCursorSpelling(CXCursor cursor) + { + ScopeCXString!:mixin(Clang.GetCursorSpelling(cursor)) + } + public static mixin GetTypeSpelling(CXType type) + { + ScopeCXString!:mixin(Clang.GetTypeSpelling(type)) + } + public static mixin GetFilePath(CXFile file) + { + ScopeCXString!:mixin(Clang.GetFileName(file)) + } + protected mixin GetTokenSpelling(CXToken token) + { + ScopeCXString!:mixin(Clang.GetTokenSpelling(unit, token)) + } + + public static void UpperSnakeCase2PascalCase(StringView snakeCase, String outString) + { + bool upper = true; + for (let c in snakeCase) + if (c == '_') upper = true; + else + { + outString.Append(upper ? c.ToUpper : c.ToLower); + upper = false; + } + } + + protected virtual void PreGeneration() {} + protected virtual void PostGeneration() {} + + public enum GenerationError + { + ParsingFailed + } + + public Result Generate(char8* headerPath, StringView wrapperPath = null) + { + unitMacros.Clear(); + fileInfos.Clear(); + lastRecordOrEnum = Clang.GetNullCursor(); + + if (!wrapperPath.IsNull) + { + wrapperWritter = scope:: .(); + wrapperWritter.Create(wrapperPath); + WrapperFilePath = wrapperPath; + wrapperBuf.Set(""" + #define private public + #define protected public + + #include " + """); + Path.GetFileName(.(headerPath), wrapperBuf); + wrapperBuf.Append(""" + " + #include + + template + using __type = T; + + extern "C" + { + + """); + FlushWrapper(); + } + else + wrapperWritter = null; + + let args = Args; + #if DEBUG + findLang: do + { + for (let arg in args) + { + StringView view = .(arg); + if (view == "-x" || view.StartsWith("--language")) + break findLang; + } + Runtime.FatalError("You must set a language via Args (e.g. --language=c++)"); + } + #endif + 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); + defer Clang.PrintingPolicy_Dispose(printingPolicy); + + PreGeneration(); + Clang.VisitChildren(Clang.GetTranslationUnitCursor(unit), (cursor, parent, client_data) => + { + Self self = (.)Internal.UnsafeCastToObject(client_data); + + { + let location = Clang.GetCursorLocation(cursor); + Clang.GetFileLocation(location, let file, let line, ?, ?); + let header = ScopeCXString!(Clang.GetFileName(file)); + self.currentWritter = self.GetWriterForHeader(header); + if (self.currentWritter == null) return .Continue; + + if (cursor.kind == .MacroDefinition) + { + self.unitMacros[.(line, file)] = cursor; + return .Continue; + } + + if (!self.fileInfos.TryGetAlt(header, ?, out self.fileInfo)) + { + self.fileInfo = new .(Clang.GetLocation(self.unit, file, 1, 1), file); + self.fileInfos.Add(new .(header), self.fileInfo); + } + } + + self.WriteCursor(cursor); + + switch (cursor.kind) + { + case .ClassDecl, .StructDecl, .EnumDecl, .UnionDecl: + self.lastRecordOrEnum = cursor; + default: + } + return .Continue; + }, Internal.UnsafeCastToPtr(this)); + PostGeneration(); + + if (wrapperBuf.IsEmpty) + wrapperWritter.Write("}\n\n//begin-comptime\n"); + + for (let kv in fileInfos) + { + fileInfo = kv.value; + currentWritter = GetWriterForHeader(kv.key); + Clang.GetFileContents(unit, kv.value.file, let size); + WriteComments(Clang.GetLocationForOffset(unit, kv.value.file, (.)size-1), .NoBlock); + Flush(); + } + + return .Ok; + } + + protected void WriteCursor(CXCursor cursor, bool macro = false) + { + if ((macro) != (cursor.kind == .MacroDefinition)) return; + + CXCursor prevCursor = currentCursor; + currentCursor = cursor; + defer { currentCursor = prevCursor; } + + int removeLenFullCursorName; + { + int curLen = fullCursorName.Length; + if (!fullCursorName.IsEmpty) + fullCursorName.Append("::"); + fullCursorName.Append(GetCursorSpelling!(cursor)); + removeLenFullCursorName = fullCursorName.Length - curLen; + } + defer { fullCursorName.Length -= removeLenFullCursorName; } + + var cursor; + int removeLenWrapperTemplateChain = 0; + defer { wrapperTemplateChain.Length -= removeLenWrapperTemplateChain; } + if (!macro) + { + templateParams.Clear(); + templateParamsWhere.Clear(); switch (cursor.kind) { - case .TemplateTypeParameter: - case .NonTypeTemplateParameter: - self.templateParamsWhere.Append(" where ", GetCursorSpelling!(cursor), " : const "); - self.Flush(); - self.Type(Clang.GetCursorType(cursor)); - self.templateParamsWhere.Append(self.str); - self.str.Clear(); - case .TemplateTemplateParameter: - Internal.FatalError(scope $"C++ template template parameters are not supported {self.FatalErrorMsg(..scope .(256))}"); - default: return .Continue; + case .FunctionTemplate, .ClassTemplate, .TypeAliasTemplateDecl: + templateParams.Append('<'); + let len = wrapperTemplateChain.Length; + Clang.VisitChildren(cursor, (cursor, parent, client_data) => + { + Self self = (.)Internal.UnsafeCastToObject(client_data); + switch (cursor.kind) + { + case .TemplateTypeParameter: + case .NonTypeTemplateParameter: + self.templateParamsWhere.Append(" where ", GetCursorSpelling!(cursor), " : const "); + self.Flush(); + self.Type(Clang.GetCursorType(cursor)); + self.templateParamsWhere.Append(self.str); + self.str.Clear(); + case .TemplateTemplateParameter: + Internal.FatalError(scope $"C++ template template parameters are not supported {self.FatalErrorMsg(..scope .(256))}"); + default: return .Continue; + } + let spelling = GetCursorSpelling!(cursor); + self.templateParams.Append(spelling, ", "); + self.wrapperTemplateChain.Append("__{typeof(", spelling, ")}"); + return .Continue; + }, Internal.UnsafeCastToPtr(this)); + templateParams.Length -= 2; + templateParams.Append('>'); + removeLenWrapperTemplateChain = wrapperTemplateChain.Length - len; + cursor.kind = Clang.GetTemplateCursorKind(cursor); + default: } - let spelling = GetCursorSpelling!(cursor); - self.templateParams.Append(spelling, ", "); - self.wrapperTemplateChain.Append("__{typeof(", spelling, ")}"); - return .Continue; - }, Internal.UnsafeCastToPtr(this)); - templateParams.Length -= 2; - templateParams.Append('>'); - removeLenWrapperTemplateChain = wrapperTemplateChain.Length - len; - cursor.kind = Clang.GetTemplateCursorKind(cursor); - default: + } + + HandleCursor(cursor); + Flush(); } - } - HandleCursor(cursor); - Flush(); - } - - protected void FatalErrorMsg(String outString) - { - Clang.GetFileLocation(Clang.GetCursorLocation(currentCursor), let file, let line, let col, ?); - outString.Append("in cursor '", GetCursorSpelling!(currentCursor), "' at line "); - outString.AppendF($"{line}:{col}"); - outString.Append(" in file ", GetFilePath!(file)); - } - - protected void Flush() - { - currentWritter.Write(str); - str.Clear(); - } - protected void FlushWrapper() - { - wrapperWritter.Write(wrapperBuf); - wrapperBuf.Clear(); - } - - protected virtual void GetIndentation(CXSourceLocation location, String outString) - { - StringView file; - uint32 offset; - { - Clang.GetFileLocation(location, let cxfile, ?, ?, out offset); - char8* ptr = Clang.GetFileContents(unit, cxfile, let size); - file = .(ptr, (.)size); - } - - int i = offset; - for (; i >= 0 && file[i] != '\n'; i--) {} - i++; - for (; i < file.Length && file[i].IsWhiteSpace; i++) outString.Append(file[i]); - } - - protected virtual void AllWhiteSpaceUntil(CXSourceLocation from, enum { NoNewLines, YesNewLines } newlineMode) - { - StringView file; - uint32 offset; - { - Clang.GetFileLocation(from, let cxfile, ?, ?, out offset); - char8* ptr = Clang.GetFileContents(unit, cxfile, let size); - file = .(ptr, (.)size); - } - - for (int i = offset-1; i >= 0; i--) - { - char8 c = file[i]; - if (c == '/' || c == '*') continue; - if ((!c.IsWhiteSpace) || (newlineMode == .NoNewLines && c == '\n')) break; - str.Append(c); - } - } - - protected virtual void AllWhiteSpaceBetween(CXSourceLocation start, CXSourceLocation end) - { - if (Clang.EqualLocations(start, Clang.GetNullLocation()) != 0 || - Clang.EqualLocations(end, Clang.GetNullLocation()) != 0) return; - - StringView file; - Clang.GetFileLocation(start, let startFile, ?, ?, let startOffset); - Clang.GetFileLocation(end, let endfile, ?, ?, let endOffset); - if (Clang.File_IsEqual(startFile, endfile) == 0) return; - char8* ptr = Clang.GetFileContents(unit, startFile, let size); - file = .(ptr, (.)size); - - for (int i = startOffset; i < endOffset; i++) - { - char8 c = file[i]; - //if (c.IsWhiteSpace) str.Append(c); - str.Append(c.IsWhiteSpace ? c : ' '); - } - } - - protected virtual CXSourceLocation GetCursorAnchor(CXCursor cursor) - { - 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 rangeLocation; - } - - protected virtual void WriteComments(CXCursor cursor, Block? block = null) - { - let location = GetCursorAnchor(cursor); - if (cursor.kind == .MacroDefinition) - { - if (block.HasValue) WriteBlock(block.Value); - GetIndentation(location, str); - return; - } - cursorIndent.Clear(); - GetIndentation(location, cursorIndent); - WriteComments(location, block); - } - 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); - - defer { fileInfo.prevEnd = writeUntil; } - if (Clang.File_IsEqual(curFile, prevFile) == 0) Runtime.FatalError(scope $"{GetFilePath!(curFile)} != {GetFilePath!(prevFile)}"); - - var between = Clang.GetRange( - Clang.GetLocationForOffset(unit, prevFile, prevOffset), - Clang.GetLocationForOffset(unit, curFile, curOffset) - ); - - CXToken* tokenPtr = null; uint32 tokenCount = 0; - Clang.Tokenize(unit, between, &tokenPtr, &tokenCount); - defer Clang.DisposeTokens(unit, tokenPtr, tokenCount); - Span tokens = .(tokenPtr, tokenCount); - - uint32 line = prevLine; - mixin WriteLinesUntil(uint32 targetLine, CXSourceLocation from) - { - int numNewLines = targetLine - line; - for (let i < numNewLines) + protected void FatalErrorMsg(String outString) { - str.Append('\n'); - line++; - if (unitMacros.TryGetValue(.(line, curFile), let macro)) + Clang.GetFileLocation(Clang.GetCursorLocation(currentCursor), let file, let line, let col, ?); + outString.Append("in cursor '", GetCursorSpelling!(currentCursor), "' at line "); + outString.AppendF($"{line}:{col}"); + outString.Append(" in file ", GetFilePath!(file)); + } + + protected void Flush() + { + currentWritter.Write(str); + str.Clear(); + } + protected void FlushWrapper() + { + wrapperWritter.Write(wrapperBuf); + wrapperBuf.Clear(); + } + + protected virtual void GetIndentation(CXSourceLocation location, String outString) + { + StringView file; + uint32 offset; { - WriteCursor(macro, macro: true); - if (block.HasValue) remainingMacros: do + Clang.GetFileLocation(location, let cxfile, ?, ?, out offset); + char8* ptr = Clang.GetFileContents(unit, cxfile, let size); + file = .(ptr, (.)size); + } + + int i = offset; + for (; i >= 0 && file[i] != '\n'; i--) {} + i++; + for (; i < file.Length && file[i].IsWhiteSpace; i++) outString.Append(file[i]); + } + + protected virtual void AllWhiteSpaceUntil(CXSourceLocation from, enum { NoNewLines, YesNewLines } newlineMode) + { + StringView file; + uint32 offset; + { + Clang.GetFileLocation(from, let cxfile, ?, ?, out offset); + char8* ptr = Clang.GetFileContents(unit, cxfile, let size); + file = .(ptr, (.)size); + } + + for (int i = offset-1; i >= 0; i--) + { + char8 c = file[i]; + if (c == '/' || c == '*') continue; + if ((!c.IsWhiteSpace) || (newlineMode == .NoNewLines && c == '\n')) break; + str.Append(c); + } + } + + protected virtual void AllWhiteSpaceBetween(CXSourceLocation start, CXSourceLocation end) + { + if (Clang.EqualLocations(start, Clang.GetNullLocation()) != 0 || + Clang.EqualLocations(end, Clang.GetNullLocation()) != 0) return; + + StringView file; + Clang.GetFileLocation(start, let startFile, ?, ?, let startOffset); + Clang.GetFileLocation(end, let endfile, ?, ?, let endOffset); + if (Clang.File_IsEqual(startFile, endfile) == 0) return; + char8* ptr = Clang.GetFileContents(unit, startFile, let size); + file = .(ptr, (.)size); + + for (int i = startOffset; i < endOffset; i++) + { + char8 c = file[i]; + //if (c.IsWhiteSpace) str.Append(c); + str.Append(c.IsWhiteSpace ? c : ' '); + } + } + + protected virtual CXSourceLocation GetCursorAnchor(CXCursor cursor) + { + 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 rangeLocation; + } + + protected virtual void WriteComments(CXCursor cursor, Block? block = null) + { + let location = GetCursorAnchor(cursor); + if (cursor.kind == .MacroDefinition) + { + if (block.HasValue) WriteBlock(block.Value); + GetIndentation(location, str); + return; + } + cursorIndent.Clear(); + GetIndentation(location, cursorIndent); + WriteComments(location, block); + } + 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); + + defer { fileInfo.prevEnd = writeUntil; } + if (Clang.File_IsEqual(curFile, prevFile) == 0) Runtime.FatalError(scope $"{GetFilePath!(curFile)} != {GetFilePath!(prevFile)}"); + + var between = Clang.GetRange( + Clang.GetLocationForOffset(unit, prevFile, prevOffset), + Clang.GetLocationForOffset(unit, curFile, curOffset) + ); + + CXToken* tokenPtr = null; uint32 tokenCount = 0; + Clang.Tokenize(unit, between, &tokenPtr, &tokenCount); + defer Clang.DisposeTokens(unit, tokenPtr, tokenCount); + Span tokens = .(tokenPtr, tokenCount); + + uint32 line = prevLine; + mixin WriteLinesUntil(uint32 targetLine, CXSourceLocation from) + { + int numNewLines = targetLine - line; + for (let i < numNewLines) { - let line = line; - for (uint32 ln = line+1; ln < curLine; ln++) - if (unitMacros.ContainsKey(.(ln, curFile))) - break remainingMacros; - WriteBlock(block.Value); + str.Append('\n'); + line++; + if (unitMacros.TryGetValue(.(line, curFile), let macro)) + { + WriteCursor(macro, macro: true); + if (block.HasValue) remainingMacros: do + { + let line = line; + for (uint32 ln = line+1; ln < curLine; ln++) + if (unitMacros.ContainsKey(.(ln, curFile))) + break remainingMacros; + WriteBlock(block.Value); + } + } } + if (numNewLines == 0) + AllWhiteSpaceUntil(from, .NoNewLines); + else + GetIndentation(from, str); } - } - if (numNewLines == 0) - AllWhiteSpaceUntil(from, .NoNewLines); - else - GetIndentation(from, str); - } - void Block() - { - if (fileInfo.queuedTokens != .None) return; - findMacros: do - { - for (uint32 ln = line; ln < curLine; ln++) + void Block() { - if (!unitMacros.TryGetValue(.(ln, curFile), let macro)) continue; - WriteBlock(GetCursorBlock(macro)); - break findMacros; - } - if (block.HasValue) WriteBlock(block.Value); - } - } - - bool first = true; - for (let token in tokens) - { - bool isWritingQueuedToken = false; - switch (Clang.GetTokenKind(token)) - { - case .Comment: - case .Punctuation: - mixin QueuedToken(var queuedToken, StringView spelling) - { - if (fileInfo.queuedTokens.HasFlag(queuedToken) && GetTokenSpelling!(token) == spelling) + if (fileInfo.queuedTokens != .None) return; + findMacros: do { - fileInfo.queuedTokens ^= queuedToken; - isWritingQueuedToken = true; + for (uint32 ln = line; ln < curLine; ln++) + { + if (!unitMacros.TryGetValue(.(ln, curFile), let macro)) continue; + WriteBlock(GetCursorBlock(macro)); + break findMacros; + } + if (block.HasValue) WriteBlock(block.Value); } } - QueuedToken!(decltype(fileInfo.queuedTokens).LSquirly, "{"); - QueuedToken!(decltype(fileInfo.queuedTokens).RSquirly, "}"); + bool first = true; + for (let token in tokens) + { + bool 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; + } + } - if (!isWritingQueuedToken) continue; - if (fileInfo.queuedTokens == .None) block = @block; - default: continue; - } - let location = Clang.GetTokenLocation(unit, token); - Clang.GetFileLocation(location, ?, let startLine, ?, ?); - WriteLinesUntil!(startLine, location); - if (!isWritingQueuedToken) - { - if (first) Block(); - first = false; - } - WriteToken(token); - for (let c in GetTokenSpelling!(token)) - if (c == '\n') - line++; - Flush(); - } - WriteLinesUntil!(curLine, writeUntil); - if (@block.HasValue) WriteBlock(@block.Value); - } + QueuedToken!(decltype(fileInfo.queuedTokens).LSquirly, "{"); + QueuedToken!(decltype(fileInfo.queuedTokens).RSquirly, "}"); - protected enum TypeParamMode { None, InParam, OutParam } - protected virtual void Type(CXType type, TypeParamMode paramMode = .None) - { - switch (type.kind) - { - case .Void: str.Append("void"); - case .Bool: str.Append("bool"); - case .Char_U, .UChar: str.Append("c_uchar"); - case .Char16: str.Append("char16"); - case .Char32: str.Append("char32"); - case .UShort: str.Append("c_ushort"); - case .UInt: str.Append("c_uint"); - case .ULong: str.Append("c_ulong"); - case .ULongLong: str.Append("c_ulonglong"); - case .Char_S, .SChar: str.Append("c_char"); - case .WChar: str.Append("c_wchar"); - case .Short: str.Append("c_short"); - case .Int: str.Append("c_int"); - case .Long: str.Append("c_long"); - case .LongLong: str.Append("c_longlong"); - case .Float: str.Append("float"); - case .Double: str.Append("double"); - case .NullPtr: str.Append("decltype(null)"); - case .Pointer: - let pointee = Clang.GetPointeeType(type); - if (paramMode == .OutParam) str.Append("out "); - Type(pointee); - if (paramMode != .OutParam && pointee.kind != .FunctionProto && pointee.kind != .FunctionNoProto) - str.Append('*'); - case .LValueReference, .RValueReference: - let nonRefType = Clang.GetNonReferenceType(type); - switch (paramMode) + if (!isWritingQueuedToken) continue; + if (fileInfo.queuedTokens == .None) block = @block; + default: continue; + } + let location = Clang.GetTokenLocation(unit, token); + Clang.GetFileLocation(location, ?, let startLine, ?, ?); + WriteLinesUntil!(startLine, location); + if (!isWritingQueuedToken) + { + if (first) Block(); + first = false; + } + WriteToken(token); + for (let c in GetTokenSpelling!(token)) + if (c == '\n') + line++; + Flush(); + } + WriteLinesUntil!(curLine, writeUntil); + if (@block.HasValue) WriteBlock(@block.Value); + } + + protected enum TypeParamMode { None, InParam, OutParam } + protected virtual void Type(CXType type, TypeParamMode paramMode = .None) { - case .None: str.Append("ref "); - case .InParam: switch (type.kind) { - case .LValueReference: - if (Clang.IsConstQualifiedType(nonRefType) == 0) - str.Append("ref "); - else - fallthrough; - case .RValueReference: - str.Append("in "); - default: Runtime.FatalError(); - } - case .OutParam: str.Append("out "); - } - Type(nonRefType); - case .FunctionNoProto: str.Append("function "); Type(Clang.GetResultType(type)); str.Append("()"); - case .FunctionProto: str.Append("function "); Type(Clang.GetResultType(type)); WriteFunctionProtoParams(type, ScopeTokenize!(currentCursor, unit)); - case .ConstantArray: Type(Clang.GetArrayElementType(type)); str.Append('['); Clang.GetArraySize(type).ToString(str); str.Append(']'); - case .IncompleteArray: Type(Clang.GetArrayElementType(type)); str.Append('*'); - case .Auto: str.Append("var"); - case .Elaborated, .Record, .Enum, .Typedef: - CXCursor decl = Clang.GetTypeDeclaration(type); - if (Clang.Cursor_IsAnonymous(decl) != 0) - { - switch (decl.kind) - { - case .EnumDecl: Enum(decl); - case .StructDecl, .ClassDecl, .UnionDecl: Record(decl); - default: Runtime.FatalError(scope $"Unhandled anon type: {_}"); - } - if (fileInfo.queuedTokens.HasFlag(.RSquirly)) - { - str.Append('\n'); - GetIndentation(GetCursorAnchor(decl), str); - str.Append('}'); - fileInfo.queuedTokens ^= .RSquirly; - } - break; - } - - { - String qualified = scope .(256); - String buffer = scope .(256); - GetNameInBindings(decl, qualified); - CXCursor parent = decl; - while (true) - { - parent = Clang.GetCursorSemanticParent(parent); - if (Clang.IsDeclaration(parent.kind) == 0 || parent.kind == .LinkageSpec) break; - buffer.Clear(); - switch (parent.kind) - { - case .FunctionTemplate, .ClassTemplate, .TypeAliasTemplateDecl: - GetNameInBindings(parent, buffer); - buffer.Append('<'); - Clang.VisitChildren(parent, (cursor, parent, client_data) => + case .Void: str.Append("void"); + case .Bool: str.Append("bool"); + case .Char_U, .UChar: str.Append("c_uchar"); + case .Char16: str.Append("char16"); + case .Char32: str.Append("char32"); + case .UShort: str.Append("c_ushort"); + case .UInt: str.Append("c_uint"); + case .ULong: str.Append("c_ulong"); + case .ULongLong: str.Append("c_ulonglong"); + case .Char_S, .SChar: str.Append("c_char"); + case .WChar: str.Append("c_wchar"); + case .Short: str.Append("c_short"); + case .Int: str.Append("c_int"); + case .Long: str.Append("c_long"); + case .LongLong: str.Append("c_longlong"); + case .Float: str.Append("float"); + case .Double: str.Append("double"); + case .NullPtr: str.Append("decltype(null)"); + case .Pointer: + let pointee = Clang.GetPointeeType(type); + if (paramMode == .OutParam) str.Append("out "); + Type(pointee); + if (paramMode != .OutParam && pointee.kind != .FunctionProto && pointee.kind != .FunctionNoProto) + str.Append('*'); + case .LValueReference, .RValueReference: + let nonRefType = Clang.GetNonReferenceType(type); + switch (paramMode) { - String buffer = (.)Internal.UnsafeCastToObject(client_data); - switch (cursor.kind) - { - case .TemplateTypeParameter, .NonTypeTemplateParameter: - case .TemplateTemplateParameter: - Runtime.FatalError(scope $"C++ template template parameters are not supported"); - default: return .Continue; - } - buffer.Append(GetCursorSpelling!(cursor), ", "); - return .Continue; - }, Internal.UnsafeCastToPtr(buffer)); - buffer.Length -= 2; - buffer.Append('>'); - default: - Flush(); - Type(Clang.GetCursorType(parent)); - buffer.Append(str); - str.Clear(); - } - buffer.Append('.'); - qualified.Insert(0, buffer); + case .None: str.Append("ref "); + case .InParam: + switch (type.kind) + { + case .LValueReference: + if (Clang.IsConstQualifiedType(nonRefType) == 0) + str.Append("ref "); + else + fallthrough; + case .RValueReference: + str.Append("in "); + default: Runtime.FatalError(); + } + case .OutParam: str.Append("out "); + } + Type(nonRefType); + case .FunctionNoProto: str.Append("function "); Type(Clang.GetResultType(type)); str.Append("()"); + case .FunctionProto: str.Append("function "); Type(Clang.GetResultType(type)); WriteFunctionProtoParams(type, ScopeTokenize!(currentCursor, unit)); + case .ConstantArray: Type(Clang.GetArrayElementType(type)); str.Append('['); Clang.GetArraySize(type).ToString(str); str.Append(']'); + case .IncompleteArray: Type(Clang.GetArrayElementType(type)); str.Append('*'); + case .Auto: str.Append("var"); + case .Elaborated, .Record, .Enum, .Typedef: + CXCursor decl = Clang.GetTypeDeclaration(type); + if (Clang.Cursor_IsAnonymous(decl) != 0) + { + switch (decl.kind) + { + case .EnumDecl: Enum(decl); + case .StructDecl, .ClassDecl, .UnionDecl: Record(decl); + default: Runtime.FatalError(scope $"Unhandled anon type: {_}"); + } + if (fileInfo.queuedTokens.HasFlag(.RSquirly)) + { + str.Append('\n'); + GetIndentation(GetCursorAnchor(decl), str); + str.Append('}'); + fileInfo.queuedTokens ^= .RSquirly; + } + break; } - str.Append(qualified); - } - let numTemplateArgs = Clang.Type_GetNumTemplateArguments(type); - if (numTemplateArgs > 0) - { - str.Append('<'); - for (let i < numTemplateArgs) { - if (i > 0) str.Append(", "); - Type(Clang.Type_GetTemplateArgumentAsType(type, (.)i)); + String qualified = scope .(256); + String buffer = scope .(256); + GetNameInBindings(decl, qualified); + CXCursor parent = decl; + while (true) + { + parent = Clang.GetCursorSemanticParent(parent); + if (Clang.IsDeclaration(parent.kind) == 0 || parent.kind == .LinkageSpec) break; + buffer.Clear(); + switch (parent.kind) + { + case .FunctionTemplate, .ClassTemplate, .TypeAliasTemplateDecl: + GetNameInBindings(parent, buffer); + buffer.Append('<'); + Clang.VisitChildren(parent, (cursor, parent, client_data) => + { + String buffer = (.)Internal.UnsafeCastToObject(client_data); + switch (cursor.kind) + { + case .TemplateTypeParameter, .NonTypeTemplateParameter: + case .TemplateTemplateParameter: + Runtime.FatalError(scope $"C++ template template parameters are not supported"); + default: return .Continue; + } + buffer.Append(GetCursorSpelling!(cursor), ", "); + return .Continue; + }, Internal.UnsafeCastToPtr(buffer)); + buffer.Length -= 2; + buffer.Append('>'); + default: + Flush(); + Type(Clang.GetCursorType(parent)); + buffer.Append(str); + str.Clear(); + } + buffer.Append('.'); + qualified.Insert(0, buffer); + } + str.Append(qualified); } - str.Append('>'); + + let numTemplateArgs = Clang.Type_GetNumTemplateArguments(type); + if (numTemplateArgs > 0) + { + str.Append('<'); + for (let i < numTemplateArgs) + { + if (i > 0) str.Append(", "); + Type(Clang.Type_GetTemplateArgumentAsType(type, (.)i)); + } + str.Append('>'); + } + case .Unexposed, .DependentSizedArray: str.Append(ScopeCXString!(Clang.GetTypeSpelling(Clang.GetUnqualifiedType(type)))); // template param + default: Runtime.FatalError(scope $"Unhandled type: {_} \"{GetTypeSpelling!(type)}\""); } - case .Unexposed, .DependentSizedArray: str.Append(ScopeCXString!(Clang.GetTypeSpelling(Clang.GetUnqualifiedType(type)))); // template param - default: Runtime.FatalError(scope $"Unhandled type: {_} \"{GetTypeSpelling!(type)}\""); - } } protected virtual void WriteFunctionProtoParams(CXType type, Span tokens = null) @@ -797,19 +800,19 @@ abstract class Cpp2BeefGenerator for (let token in iter) { if (Clang.GetTokenKind(token) == .Punctuation && { let spelling = GetTokenSpelling!(token); spelling == "," || spelling == ")" }) - { - if (Clang.GetTokenKind(last) != .Identifier) break; + { + if (Clang.GetTokenKind(last) != .Identifier) break; str.Append(' '); - Compiler.Identifier.GetSourceName(GetTokenSpelling!(last), str); - break; - } - last = token; + Compiler.Identifier.GetSourceName(GetTokenSpelling!(last), str); + break; + } + last = token; } } if (Clang.IsFunctionTypeVariadic(type) != 0) { if (numArgs > 0) str.Append(", "); - str.Append("..."); + str.Append("..."); } str.Append(')'); } @@ -818,10 +821,10 @@ abstract class Cpp2BeefGenerator { switch (Clang.GetCXXAccessSpecifier(cursor)) { - case .InvalidAccessSpecifier, - .Public: str.Append("public "); - case .Protected: str.Append("protected "); - case .Private: str.Append("private "); + case .InvalidAccessSpecifier, + .Public: str.Append("public "); + case .Protected: str.Append("protected "); + case .Private: str.Append("private "); } } @@ -842,7 +845,7 @@ abstract class Cpp2BeefGenerator if (this.[Friend]defferedWrapperWrite != null) { str.Append("\n\n", cursorIndent, "const String _wrapperText = \"\\n\"\n", - this.[Friend]defferedWrapperWrite, ";"); + this.[Friend]defferedWrapperWrite, ";"); delete this.[Friend]defferedWrapperWrite; this.[Friend]defferedWrapperWrite = null; } @@ -851,10 +854,10 @@ abstract class Cpp2BeefGenerator { switch (cursor.kind) { - case .StructDecl, .UnionDecl, .ClassDecl: - str.Append(';'); - default: - str.Append(" {}"); + case .StructDecl, .UnionDecl, .ClassDecl: + str.Append(';'); + default: + str.Append(" {}"); } fileInfo.queuedTokens = .None; } @@ -867,7 +870,7 @@ abstract class Cpp2BeefGenerator protected virtual void CppWrapperName(CXCursor cursor, String outString) { String hashCode = ScopeCXString!(Clang.GetCursorUSR(cursor)) - .GetHashCode().ToString(..scope .(int_maxDigits), "X", null); + .GetHashCode().ToString(..scope .(int_maxDigits), "X", null); outString.Append("cpp2beef_"); if (hashCode.StartsWith('-')) hashCode[0] = 'm'; outString.Append('0', int_maxDigits - hashCode.Length); @@ -899,8 +902,8 @@ abstract class Cpp2BeefGenerator if (!wrapperTemplateChain.IsEmpty) if (templateParams.IsEmpty) str.Append(" + __template_chain"); - else - str.Append(" + CppWrapperF($\"", wrapperTemplateChain, "\")"); + else + str.Append(" + CppWrapperF($\"", wrapperTemplateChain, "\")"); str.Append(")] "); return .Cpp; } @@ -937,7 +940,7 @@ abstract class Cpp2BeefGenerator if (preserveColumns) AllWhiteSpaceBetween( Clang.GetRangeStart(Clang.GetCursorExtent(cursor)), - Clang.GetRangeStart(Clang.Cursor_GetSpellingNameRange(cursor, 0, 0)) + Clang.GetRangeStart(Clang.Cursor_GetSpellingNameRange(cursor, 0, 0)) ); if (format == .Ctor) { @@ -960,23 +963,23 @@ abstract class Cpp2BeefGenerator } switch (format) { - case .Standard: - str.Append(whitespace); - GetNameInBindings(cursor, str); - str.Append(templateParams); - case .TypeAlias: - String typeStr = scope .(str); - str.Clear(); - str.Append(' '); - GetNameInBindings(cursor, str); - str.Append(templateParams, " = ", typeStr, ";"); - if (preserveColumns) str.Append(whitespace); - case .ConversionFunction: - String typeStr = scope .(str); - str.Clear(); - str.Append("operator", whitespace, typeStr, templateParams); - case .Ctor: Runtime.FatalError(); - case .Dtor: str.Append(whitespace, "Dispose"); + case .Standard: + str.Append(whitespace); + GetNameInBindings(cursor, str); + str.Append(templateParams); + case .TypeAlias: + String typeStr = scope .(str); + str.Clear(); + str.Append(' '); + GetNameInBindings(cursor, str); + str.Append(templateParams, " = ", typeStr, ";"); + if (preserveColumns) str.Append(whitespace); + case .ConversionFunction: + String typeStr = scope .(str); + str.Clear(); + str.Append("operator", whitespace, typeStr, templateParams); + case .Ctor: Runtime.FatalError(); + case .Dtor: str.Append(whitespace, "Dispose"); } } @@ -1017,18 +1020,18 @@ abstract class Cpp2BeefGenerator let kind = Clang.GetTokenKind(token); token: switch (kind) { - case .Literal: - str.Append(spelling); - if (str.EndsWith("LL")) - str.Length--; - case .Identifier: - var cursor = Clang.GetCursor(unit, Clang.GetTokenLocation(unit, token)); - if (Clang.Cursor_IsNull(cursor) != 0) fallthrough; - cursor = Clang.GetCursorDefinition(cursor); + case .Literal: + str.Append(spelling); + if (str.EndsWith("LL")) + str.Length--; + case .Identifier: + var cursor = Clang.GetCursor(unit, Clang.GetTokenLocation(unit, token)); + if (Clang.Cursor_IsNull(cursor) != 0) fallthrough; + cursor = Clang.GetCursorDefinition(cursor); if (Clang.Cursor_IsNull(cursor) != 0) fallthrough; GetNameInBindings(cursor, str); - case .Punctuation, .Comment, .Keyword: - str.Append(spelling); + case .Punctuation, .Comment, .Keyword: + str.Append(spelling); } } @@ -1045,29 +1048,29 @@ abstract class Cpp2BeefGenerator //TODO: move to custom utils /* // This formats the tokens instead of copying the format 1:1 - const CXTokenKind Unary = (.)-1; - var prevKind; - for (let token in tokens) - { - let spelling = ScopeCXString!(Clang.GetTokenSpelling(unit, token)); - let kind = Clang.GetTokenKind(token); - token: switch (kind) - { - case .Keyword, .Identifier, .Literal: - if (prevKind == .Keyword || prevKind == .Identifier || prevKind == .Punctuation) - str.Append(' '); - if (kind == .Identifier) do - { - var cursor = Clang.GetCursor(unit, Clang.GetTokenLocation(unit, token)); - if (Clang.Cursor_IsNull(cursor) != 0) break; - cursor = Clang.GetCursorDefinition(cursor); - if (Clang.Cursor_IsNull(cursor) != 0) break; - GetNameInBindings(cursor, str); - break token; - } - str.Append(spelling); - if (kind == .Literal && str.EndsWith("LL")) - str.Length--; + * const CXTokenKind Unary = (.)-1; + * var prevKind; + * for (let token in tokens) + * { + * let spelling = ScopeCXString!(Clang.GetTokenSpelling(unit, token)); + * let kind = Clang.GetTokenKind(token); + * token: switch (kind) + * { + * case .Keyword, .Identifier, .Literal: + * if (prevKind == .Keyword || prevKind == .Identifier || prevKind == .Punctuation) + * str.Append(' '); + * if (kind == .Identifier) do + * { + * var cursor = Clang.GetCursor(unit, Clang.GetTokenLocation(unit, token)); + * if (Clang.Cursor_IsNull(cursor) != 0) break; + * cursor = Clang.GetCursorDefinition(cursor); + * if (Clang.Cursor_IsNull(cursor) != 0) break; + * GetNameInBindings(cursor, str); + * break token; + } + str.Append(spelling); + if (kind == .Literal && str.EndsWith("LL")) + str.Length--; case .Punctuation: defer str.Append(spelling); if (prevKind != Unary && !(spelling == "(" && prevKind != .Punctuation) && spelling != ")") @@ -1080,9 +1083,9 @@ abstract class Cpp2BeefGenerator prevKind = Unary; continue; case .Comment: - } - prevKind = kind; - }*/ + } + prevKind = kind; + }*/ } protected virtual void Namespace(CXCursor cursor) @@ -1149,41 +1152,41 @@ abstract class Cpp2BeefGenerator i.ToString(wrapperBuf); } wrapperBuf.Append(") { "); - if (resultType.kind != .Void) wrapperBuf.Append("return "); - if (nonStatic) - { - if (cursor.kind != .Destructor) - wrapperBuf.Append("self->", GetCursorSpelling!(cursor)); + 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("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("); }"); + 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(); - } + 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) @@ -1222,16 +1225,16 @@ abstract class Cpp2BeefGenerator str.Append(" this["); Method_Parameters(cursor); str.Append("] { "); - Attributes(); - str.Append("get; }"); - return; + Attributes(); + str.Append("get; }"); + return; } Attributes(); AccessSpecifier(cursor); str.Append("static extern "); WriteTypeAndName(cursor, Clang.GetCursorResultType(cursor), - cursor.kind == .ConversionFunction ? .ConversionFunction : .Standard); + cursor.kind == .ConversionFunction ? .ConversionFunction : .Standard); str.Append("(in Self, "); Method_Parameters(cursor); if (str.EndsWith(", ")) str.Length -= 2; @@ -1247,12 +1250,12 @@ abstract class Cpp2BeefGenerator str.Append("extern "); switch (cursor.kind) { - case .Constructor: WriteTypeAndName(cursor, default, .Ctor); - case .Destructor: WriteTypeAndName(cursor, Clang.GetCursorResultType(cursor), .Dtor); - case .CXXMethod: - WriteTypeAndName(cursor, Clang.GetCursorResultType(cursor)); - default: - Runtime.FatalError("Unhandled c++ method kind"); + case .Constructor: WriteTypeAndName(cursor, default, .Ctor); + case .Destructor: WriteTypeAndName(cursor, Clang.GetCursorResultType(cursor), .Dtor); + case .CXXMethod: + WriteTypeAndName(cursor, Clang.GetCursorResultType(cursor)); + default: + Runtime.FatalError("Unhandled c++ method kind"); } str.Append('('); Method_Parameters(cursor); @@ -1327,17 +1330,17 @@ abstract class Cpp2BeefGenerator let type = Clang.GetCursorType(cursor); switch (Clang.GetCursorLinkage(cursor)) { - case .Internal when Clang.IsConstQualifiedType(type) != 0: - 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(); - AccessSpecifier(cursor); + case .Internal when Clang.IsConstQualifiedType(type) != 0: + 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(); + AccessSpecifier(cursor); str.Append("static extern "); if (linkLang == .Cpp && type.kind != .LValueReference && type.kind != .RValueReference) str.Append("ref "); @@ -1355,8 +1358,8 @@ abstract class Cpp2BeefGenerator FlushWrapper(); } str.Append(';'); - default: - Runtime.FatalError(scope $"Unhandled var linkage: {_}"); + default: + Runtime.FatalError(scope $"Unhandled var linkage: {_}"); } } @@ -1366,13 +1369,13 @@ abstract class Cpp2BeefGenerator { switch (cursor.kind) { - case .CXXBaseSpecifier: - if (HasVTable(Clang.GetCursorDefinition(cursor))) - return .Break; - case .CXXMethod, .Constructor, .Destructor, .ConversionFunction: - if (Clang.CXXMethod_IsVirtual(cursor) != 0) - return .Break; - default: + case .CXXBaseSpecifier: + if (HasVTable(Clang.GetCursorDefinition(cursor))) + return .Break; + case .CXXMethod, .Constructor, .Destructor, .ConversionFunction: + if (Clang.CXXMethod_IsVirtual(cursor) != 0) + return .Break; + default: } return .Continue; }, null) != 0; @@ -1383,9 +1386,9 @@ abstract class Cpp2BeefGenerator WriteCustomAttributes(cursor); switch (cursor.kind) { - case .StructDecl, .ClassDecl: str.Append("[CRepr] "); - case .UnionDecl: str.Append("[CRepr, Union] "); - default: Runtime.FatalError("Unhandled record type"); + case .StructDecl, .ClassDecl: str.Append("[CRepr] "); + case .UnionDecl: str.Append("[CRepr, Union] "); + default: Runtime.FatalError("Unhandled record type"); } AccessSpecifier(cursor); str.Append("struct "); @@ -1404,19 +1407,19 @@ abstract class Cpp2BeefGenerator BeginBody!(cursor); //TODO /*Clang.VisitChildren(cursor, (cursor, parent, client_data) => - { - Self self = (.)Internal.UnsafeCastToObject(client_data); - switch (cursor.kind) - { - case .FieldDecl, .CXXMethod, .Constructor, .Destructor, .ConversionFunction, .FunctionDecl, .VarDecl, - .FunctionTemplate, .ClassTemplate, .TypeAliasTemplateDecl, .StructDecl, .ClassDecl, - .UnionDecl, .EnumDecl, .TypeAliasDecl, .TypedefDecl: - self.WriteComments(cursor); - return .Break; - default: - return .Continue; - } - }, Internal.UnsafeCastToPtr(this));*/ + * { + * Self self = (.)Internal.UnsafeCastToObject(client_data); + * switch (cursor.kind) + * { + * case .FieldDecl, .CXXMethod, .Constructor, .Destructor, .ConversionFunction, .FunctionDecl, .VarDecl, + * .FunctionTemplate, .ClassTemplate, .TypeAliasTemplateDecl, .StructDecl, .ClassDecl, + * .UnionDecl, .EnumDecl, .TypeAliasDecl, .TypedefDecl: + * self.WriteComments(cursor); + * return .Break; + * default: + * return .Continue; + } + }, Internal.UnsafeCastToPtr(this));*/ if (!wrapperTemplateChain.IsEmpty) { @@ -1427,13 +1430,13 @@ abstract class Cpp2BeefGenerator Self self = (.)Internal.UnsafeCastToObject(client_data); switch (cursor.kind) { - case .TemplateTypeParameter: - self.str.Append(" + CppTypeToC(typeof(", GetCursorSpelling!(cursor), "))"); - case .NonTypeTemplateParameter: - self.str.Append(" + CppConstValue<"); - self.Type(Clang.GetCursorType(cursor)); - self.str.Append(">(", GetCursorSpelling!(cursor), ")"); - default: return .Continue; + case .TemplateTypeParameter: + self.str.Append(" + CppTypeToC(typeof(", GetCursorSpelling!(cursor), "))"); + case .NonTypeTemplateParameter: + self.str.Append(" + CppConstValue<"); + self.Type(Clang.GetCursorType(cursor)); + self.str.Append(">(", GetCursorSpelling!(cursor), ")"); + default: return .Continue; } self.str.Append(" + \", \""); return .Continue; @@ -1442,14 +1445,14 @@ abstract class Cpp2BeefGenerator str.Append(">\";\n", cursorIndent); str.Append("private const String __template_chain = CppWrapperF($\"", wrapperTemplateChain, "\");\n\n", cursorIndent); /*str.Append("[CppWriteToWrapper<\"", WrapperFilePath, "\">(\"\\ntemplate "); - switch (cursor.kind) - { - case .StructDecl: str.Append("struct "); - case . ClassDecl: str.Append("class " ); - case . UnionDecl: str.Append("union " ); - default: Runtime.FatalError(); - } - str.Append("\" + __cpp_type + \";\\n\")]\n\n", indent);*/ + * switch (cursor.kind) + * { + * case .StructDecl: str.Append("struct "); + * case . ClassDecl: str.Append("class " ); + * case . UnionDecl: str.Append("union " ); + * default: Runtime.FatalError(); + } + str.Append("\" + __cpp_type + \";\\n\")]\n\n", indent);*/ } bool firstBase = true; @@ -1499,11 +1502,11 @@ abstract class Cpp2BeefGenerator GetNameInBindings(cursor, str); str.Append(templateParams); if (Clang.VisitChildren(cursor, (cursor, parent, client_data) => - { - if (cursor.kind == .PackedAttr) - return .Break; - return .Continue; - }, null) == 0) + { + if (cursor.kind == .PackedAttr) + return .Break; + return .Continue; + }, null) == 0) { str.Append(" : "); Type(Clang.GetEnumDeclIntegerType(cursor)); @@ -1531,10 +1534,10 @@ abstract class Cpp2BeefGenerator CXType type; switch (cursor.kind) { - case .TypedefDecl: type = Clang.GetTypedefDeclUnderlyingType(cursor); - case .TypeAliasDecl: type = Clang.GetCursorType(cursor); - default: - Runtime.FatalError("Unhandled type alias cursor kind"); + case .TypedefDecl: type = Clang.GetTypedefDeclUnderlyingType(cursor); + case .TypeAliasDecl: type = Clang.GetCursorType(cursor); + default: + Runtime.FatalError("Unhandled type alias cursor kind"); } if (type.kind == .Pointer) do