| 
									
										
										
										
											2022-07-28 17:41:47 +02:00
										 |  |  | using System.Collections.Generic; | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | using System.Linq; | 
					
						
							|  |  |  | using System.Text; | 
					
						
							|  |  |  | using Microsoft.CodeAnalysis; | 
					
						
							|  |  |  | using Microsoft.CodeAnalysis.CSharp.Syntax; | 
					
						
							|  |  |  | using Microsoft.CodeAnalysis.Text; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Godot.SourceGenerators | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     [Generator] | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |     public class ScriptMethodsGenerator : ISourceGenerator | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |         public void Initialize(GeneratorInitializationContext context) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |         public void Execute(GeneratorExecutionContext context) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2023-01-08 12:04:15 +11:00
										 |  |  |             if (context.IsGodotSourceGeneratorDisabled("ScriptMethods")) | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                 return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             INamedTypeSymbol[] godotClasses = context | 
					
						
							|  |  |  |                 .Compilation.SyntaxTrees | 
					
						
							|  |  |  |                 .SelectMany(tree => | 
					
						
							|  |  |  |                     tree.GetRoot().DescendantNodes() | 
					
						
							|  |  |  |                         .OfType<ClassDeclarationSyntax>() | 
					
						
							|  |  |  |                         .SelectGodotScriptClasses(context.Compilation) | 
					
						
							|  |  |  |                         // Report and skip non-partial classes | 
					
						
							|  |  |  |                         .Where(x => | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             if (x.cds.IsPartial()) | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                             { | 
					
						
							|  |  |  |                                 if (x.cds.IsNested() && !x.cds.AreAllOuterTypesPartial(out var typeMissingPartial)) | 
					
						
							|  |  |  |                                 { | 
					
						
							|  |  |  |                                     Common.ReportNonPartialGodotScriptOuterClass(context, typeMissingPartial!); | 
					
						
							|  |  |  |                                     return false; | 
					
						
							|  |  |  |                                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                                 return true; | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                             Common.ReportNonPartialGodotScriptClass(context, x.cds, x.symbol); | 
					
						
							|  |  |  |                             return false; | 
					
						
							|  |  |  |                         }) | 
					
						
							|  |  |  |                         .Select(x => x.symbol) | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 .Distinct<INamedTypeSymbol>(SymbolEqualityComparer.Default) | 
					
						
							|  |  |  |                 .ToArray(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (godotClasses.Length > 0) | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2022-08-15 05:57:52 +02:00
										 |  |  |                 var typeCache = new MarshalUtils.TypeCache(context.Compilation); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 foreach (var godotClass in godotClasses) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     VisitGodotScriptClass(context, typeCache, godotClass); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |         private class MethodOverloadEqualityComparer : IEqualityComparer<GodotMethodData> | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             public bool Equals(GodotMethodData x, GodotMethodData y) | 
					
						
							|  |  |  |                 => x.ParamTypes.Length == y.ParamTypes.Length && x.Method.Name == y.Method.Name; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             public int GetHashCode(GodotMethodData obj) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 unchecked | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     return (obj.ParamTypes.Length.GetHashCode() * 397) ^ obj.Method.Name.GetHashCode(); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |         private static void VisitGodotScriptClass( | 
					
						
							|  |  |  |             GeneratorExecutionContext context, | 
					
						
							|  |  |  |             MarshalUtils.TypeCache typeCache, | 
					
						
							|  |  |  |             INamedTypeSymbol symbol | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace; | 
					
						
							|  |  |  |             string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ? | 
					
						
							| 
									
										
										
										
											2022-11-24 01:04:15 +01:00
										 |  |  |                 namespaceSymbol.FullQualifiedNameOmitGlobal() : | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                 string.Empty; | 
					
						
							|  |  |  |             bool hasNamespace = classNs.Length != 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             bool isInnerClass = symbol.ContainingType != null; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-24 01:04:15 +01:00
										 |  |  |             string uniqueHint = symbol.FullQualifiedNameOmitGlobal().SanitizeQualifiedNameForUniqueHint() | 
					
						
							| 
									
										
										
										
											2022-10-22 23:13:52 +02:00
										 |  |  |                                 + "_ScriptMethods.generated"; | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             var source = new StringBuilder(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             source.Append("using Godot;\n"); | 
					
						
							|  |  |  |             source.Append("using Godot.NativeInterop;\n"); | 
					
						
							|  |  |  |             source.Append("\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (hasNamespace) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 source.Append("namespace "); | 
					
						
							|  |  |  |                 source.Append(classNs); | 
					
						
							|  |  |  |                 source.Append(" {\n\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             if (isInnerClass) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 var containingType = symbol.ContainingType; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 while (containingType != null) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     source.Append("partial "); | 
					
						
							|  |  |  |                     source.Append(containingType.GetDeclarationKeyword()); | 
					
						
							|  |  |  |                     source.Append(" "); | 
					
						
							| 
									
										
										
										
											2022-02-27 21:57:30 +01:00
										 |  |  |                     source.Append(containingType.NameWithTypeParameters()); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                     source.Append("\n{\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     containingType = containingType.ContainingType; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             source.Append("partial class "); | 
					
						
							| 
									
										
										
										
											2022-02-27 21:57:30 +01:00
										 |  |  |             source.Append(symbol.NameWithTypeParameters()); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             source.Append("\n{\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             var members = symbol.GetMembers(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             var methodSymbols = members | 
					
						
							| 
									
										
										
										
											2023-09-20 22:49:33 +08:00
										 |  |  |                 .Where(s => s.Kind == SymbolKind.Method && !s.IsImplicitlyDeclared) | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                 .Cast<IMethodSymbol>() | 
					
						
							| 
									
										
										
										
											2022-02-27 21:57:30 +01:00
										 |  |  |                 .Where(m => m.MethodKind == MethodKind.Ordinary); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             var godotClassMethods = methodSymbols.WhereHasGodotCompatibleSignature(typeCache) | 
					
						
							|  |  |  |                 .Distinct(new MethodOverloadEqualityComparer()) | 
					
						
							|  |  |  |                 .ToArray(); | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-06 20:43:40 +08:00
										 |  |  |             source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-09 14:14:36 +02:00
										 |  |  |             source.Append("    /// <summary>\n") | 
					
						
							|  |  |  |                 .Append("    /// Cached StringNames for the methods contained in this class, for fast lookup.\n") | 
					
						
							|  |  |  |                 .Append("    /// </summary>\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-01 01:45:11 +01:00
										 |  |  |             source.Append( | 
					
						
							|  |  |  |                 $"    public new class MethodName : {symbol.BaseType.FullQualifiedNameIncludeGlobal()}.MethodName {{\n"); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // Generate cached StringNames for methods and properties, for fast lookup | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             var distinctMethodNames = godotClassMethods | 
					
						
							|  |  |  |                 .Select(m => m.Method.Name) | 
					
						
							|  |  |  |                 .Distinct() | 
					
						
							|  |  |  |                 .ToArray(); | 
					
						
							| 
									
										
										
										
											2022-02-27 21:57:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             foreach (string methodName in distinctMethodNames) | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2023-07-09 14:14:36 +02:00
										 |  |  |                 source.Append("        /// <summary>\n") | 
					
						
							|  |  |  |                     .Append("        /// Cached name for the '") | 
					
						
							|  |  |  |                     .Append(methodName) | 
					
						
							|  |  |  |                     .Append("' method.\n") | 
					
						
							|  |  |  |                     .Append("        /// </summary>\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-24 01:04:15 +01:00
										 |  |  |                 source.Append("        public new static readonly global::Godot.StringName "); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                 source.Append(methodName); | 
					
						
							|  |  |  |                 source.Append(" = \""); | 
					
						
							|  |  |  |                 source.Append(methodName); | 
					
						
							|  |  |  |                 source.Append("\";\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             source.Append("    }\n"); // class GodotInternal | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             // Generate GetGodotMethodList | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (godotClassMethods.Length > 0) | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2022-11-24 01:04:15 +01:00
										 |  |  |                 const string listType = "global::System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>"; | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-09 14:14:36 +02:00
										 |  |  |                 source.Append("    /// <summary>\n") | 
					
						
							|  |  |  |                     .Append("    /// Get the method information for all the methods declared in this class.\n") | 
					
						
							|  |  |  |                     .Append("    /// This method is used by Godot to register the available methods in the editor.\n") | 
					
						
							|  |  |  |                     .Append("    /// Do not call this method.\n") | 
					
						
							|  |  |  |                     .Append("    /// </summary>\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 source.Append("    [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                 source.Append("    internal new static ") | 
					
						
							|  |  |  |                     .Append(listType) | 
					
						
							|  |  |  |                     .Append(" GetGodotMethodList()\n    {\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 source.Append("        var methods = new ") | 
					
						
							|  |  |  |                     .Append(listType) | 
					
						
							|  |  |  |                     .Append("(") | 
					
						
							|  |  |  |                     .Append(godotClassMethods.Length) | 
					
						
							|  |  |  |                     .Append(");\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 foreach (var method in godotClassMethods) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     var methodInfo = DetermineMethodInfo(method); | 
					
						
							|  |  |  |                     AppendMethodInfo(source, methodInfo); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 source.Append("        return methods;\n"); | 
					
						
							|  |  |  |                 source.Append("    }\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-06 20:43:40 +08:00
										 |  |  |             source.Append("#pragma warning restore CS0109\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             // Generate InvokeGodotClassMethod | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             if (godotClassMethods.Length > 0) | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2023-07-09 14:14:36 +02:00
										 |  |  |                 source.Append("    /// <inheritdoc/>\n"); | 
					
						
							|  |  |  |                 source.Append("    [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n"); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                 source.Append("    protected override bool InvokeGodotClassMethod(in godot_string_name method, "); | 
					
						
							| 
									
										
											  
											
												C#: Remove need for reflection to invoking callable delegates
We aim to make the C# API reflection-free, mainly for concerns about
performance, and to be able to target NativeAOT in refletion-free mode,
which reduces the binary size.
One of the main usages of reflection still left was the dynamic
invokation of callable delegates, and for some time I wasn't sure
I would find an alternative solution that I'd be happy with.
The new solution uses trampoline functions to invoke the delegates:
```
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
{
    if (args.Count != 1)
        throw new ArgumentException($"Callable expected 1 arguments but received {args.Count}.");
    string res = ((Func<int, string>)delegateObj)(
        VariantConversionCallbacks.GetToManagedCallback<int>()(args[0])
    );
    ret = VariantConversionCallbacks.GetToVariantCallback<string>()(res);
}
Callable.CreateWithUnsafeTrampoline((int num) => "Foo" + num, &Trampoline);
```
Of course, this is too much boilerplate for user code. To improve this,
the `Callable.From` methods were added. These are overloads that take
`Action` and `Func` delegates, which covers the most common use cases:
lambdas and method groups:
```
// Lambda
Callable.From((int num) => "Foo" + num);
// Method group
string AppendNum(int num) => "Foo" + num;
Callable.From(AppendNum);
```
Unfortunately, due to limitations in the C# language, implicit
conversions from delegates to `Callable` are not supported.
`Callable.From` does not support custom delegates. These should be
uncommon, but the Godot C# API actually uses them for event signals.
As such, the bindings generator was updated to generate trampoline
functions for event signals. It was also optimized to use `Action`
instead of a custom delegate for parameterless signals, which removes
the need for the trampoline functions for those signals.
The change to reflection-free invokation removes one of the last needs
for `ConvertVariantToManagedObjectOfType`. The only remaining usage is
from calling script constructors with parameters from the engine
(`CreateManagedForGodotObjectScriptInstance`). Once that one is made
reflection-free, `ConvertVariantToManagedObjectOfType` can be removed.
											
										 
											2022-10-28 22:59:13 +02:00
										 |  |  |                 source.Append("NativeVariantPtrArgs args, out godot_variant ret)\n    {\n"); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                 foreach (var method in godotClassMethods) | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                 { | 
					
						
							|  |  |  |                     GenerateMethodInvoker(method, source); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												C#: Remove need for reflection to invoking callable delegates
We aim to make the C# API reflection-free, mainly for concerns about
performance, and to be able to target NativeAOT in refletion-free mode,
which reduces the binary size.
One of the main usages of reflection still left was the dynamic
invokation of callable delegates, and for some time I wasn't sure
I would find an alternative solution that I'd be happy with.
The new solution uses trampoline functions to invoke the delegates:
```
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
{
    if (args.Count != 1)
        throw new ArgumentException($"Callable expected 1 arguments but received {args.Count}.");
    string res = ((Func<int, string>)delegateObj)(
        VariantConversionCallbacks.GetToManagedCallback<int>()(args[0])
    );
    ret = VariantConversionCallbacks.GetToVariantCallback<string>()(res);
}
Callable.CreateWithUnsafeTrampoline((int num) => "Foo" + num, &Trampoline);
```
Of course, this is too much boilerplate for user code. To improve this,
the `Callable.From` methods were added. These are overloads that take
`Action` and `Func` delegates, which covers the most common use cases:
lambdas and method groups:
```
// Lambda
Callable.From((int num) => "Foo" + num);
// Method group
string AppendNum(int num) => "Foo" + num;
Callable.From(AppendNum);
```
Unfortunately, due to limitations in the C# language, implicit
conversions from delegates to `Callable` are not supported.
`Callable.From` does not support custom delegates. These should be
uncommon, but the Godot C# API actually uses them for event signals.
As such, the bindings generator was updated to generate trampoline
functions for event signals. It was also optimized to use `Action`
instead of a custom delegate for parameterless signals, which removes
the need for the trampoline functions for those signals.
The change to reflection-free invokation removes one of the last needs
for `ConvertVariantToManagedObjectOfType`. The only remaining usage is
from calling script constructors with parameters from the engine
(`CreateManagedForGodotObjectScriptInstance`). Once that one is made
reflection-free, `ConvertVariantToManagedObjectOfType` can be removed.
											
										 
											2022-10-28 22:59:13 +02:00
										 |  |  |                 source.Append("        return base.InvokeGodotClassMethod(method, args, out ret);\n"); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 source.Append("    }\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-20 22:49:33 +08:00
										 |  |  |             // Generate InvokeGodotClassStaticMethod | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             var godotClassStaticMethods = godotClassMethods.Where(m => m.Method.IsStatic).ToArray(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (godotClassStaticMethods.Length > 0) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n"); | 
					
						
							|  |  |  |                 source.Append("    [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n"); | 
					
						
							|  |  |  |                 source.Append("    internal new static bool InvokeGodotClassStaticMethod(in godot_string_name method, "); | 
					
						
							|  |  |  |                 source.Append("NativeVariantPtrArgs args, out godot_variant ret)\n    {\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 foreach (var method in godotClassStaticMethods) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     GenerateMethodInvoker(method, source); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 source.Append("        ret = default;\n"); | 
					
						
							|  |  |  |                 source.Append("        return false;\n"); | 
					
						
							|  |  |  |                 source.Append("    }\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 source.Append("#pragma warning restore CS0109\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:47 +02:00
										 |  |  |             // Generate HasGodotClassMethod | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             if (distinctMethodNames.Length > 0) | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:47 +02:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2023-07-09 14:14:36 +02:00
										 |  |  |                 source.Append("    /// <inheritdoc/>\n"); | 
					
						
							|  |  |  |                 source.Append("    [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n"); | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:47 +02:00
										 |  |  |                 source.Append("    protected override bool HasGodotClassMethod(in godot_string_name method)\n    {\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 bool isFirstEntry = true; | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                 foreach (string methodName in distinctMethodNames) | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:47 +02:00
										 |  |  |                 { | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                     GenerateHasMethodEntry(methodName, source, isFirstEntry); | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:47 +02:00
										 |  |  |                     isFirstEntry = false; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 source.Append("        return base.HasGodotClassMethod(method);\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 source.Append("    }\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             source.Append("}\n"); // partial class | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             if (isInnerClass) | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:47 +02:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                 var containingType = symbol.ContainingType; | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                 while (containingType != null) | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:47 +02:00
										 |  |  |                 { | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                     source.Append("}\n"); // outer class | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                     containingType = containingType.ContainingType; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:47 +02:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             if (hasNamespace) | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                 source.Append("\n}\n"); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             context.AddSource(uniqueHint, SourceText.From(source.ToString(), Encoding.UTF8)); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |         private static void AppendMethodInfo(StringBuilder source, MethodInfo methodInfo) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2022-09-06 20:43:40 +08:00
										 |  |  |             source.Append("        methods.Add(new(name: MethodName.") | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                 .Append(methodInfo.Name) | 
					
						
							|  |  |  |                 .Append(", returnVal: "); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             AppendPropertyInfo(source, methodInfo.ReturnVal); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-24 01:04:15 +01:00
										 |  |  |             source.Append(", flags: (global::Godot.MethodFlags)") | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                 .Append((int)methodInfo.Flags) | 
					
						
							|  |  |  |                 .Append(", arguments: "); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             if (methodInfo.Arguments is { Count: > 0 }) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 source.Append("new() { "); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                 foreach (var param in methodInfo.Arguments) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     AppendPropertyInfo(source, param); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                     // C# allows colon after the last element | 
					
						
							|  |  |  |                     source.Append(", "); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                 source.Append(" }"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 source.Append("null"); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             source.Append(", defaultArguments: null));\n"); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |         private static void AppendPropertyInfo(StringBuilder source, PropertyInfo propertyInfo) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2022-11-24 01:04:15 +01:00
										 |  |  |             source.Append("new(type: (global::Godot.Variant.Type)") | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                 .Append((int)propertyInfo.Type) | 
					
						
							|  |  |  |                 .Append(", name: \"") | 
					
						
							|  |  |  |                 .Append(propertyInfo.Name) | 
					
						
							| 
									
										
										
										
											2022-11-24 01:04:15 +01:00
										 |  |  |                 .Append("\", hint: (global::Godot.PropertyHint)") | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                 .Append((int)propertyInfo.Hint) | 
					
						
							|  |  |  |                 .Append(", hintString: \"") | 
					
						
							|  |  |  |                 .Append(propertyInfo.HintString) | 
					
						
							| 
									
										
										
										
											2022-11-24 01:04:15 +01:00
										 |  |  |                 .Append("\", usage: (global::Godot.PropertyUsageFlags)") | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                 .Append((int)propertyInfo.Usage) | 
					
						
							|  |  |  |                 .Append(", exported: ") | 
					
						
							| 
									
										
										
										
											2023-06-16 23:05:11 +02:00
										 |  |  |                 .Append(propertyInfo.Exported ? "true" : "false"); | 
					
						
							|  |  |  |             if (propertyInfo.ClassName != null) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 source.Append(", className: new global::Godot.StringName(\"") | 
					
						
							|  |  |  |                     .Append(propertyInfo.ClassName) | 
					
						
							|  |  |  |                     .Append("\")"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             source.Append(")"); | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |         private static MethodInfo DetermineMethodInfo(GodotMethodData method) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             PropertyInfo returnVal; | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             if (method.RetType != null) | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2023-06-16 23:05:11 +02:00
										 |  |  |                 returnVal = DeterminePropertyInfo(method.RetType.Value.MarshalType, | 
					
						
							|  |  |  |                     method.RetType.Value.TypeSymbol, | 
					
						
							|  |  |  |                     name: string.Empty); | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 returnVal = new PropertyInfo(VariantType.Nil, string.Empty, PropertyHint.None, | 
					
						
							|  |  |  |                     hintString: null, PropertyUsageFlags.Default, exported: false); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             int paramCount = method.ParamTypes.Length; | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             List<PropertyInfo>? arguments; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (paramCount > 0) | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                 arguments = new(capacity: paramCount); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                 for (int i = 0; i < paramCount; i++) | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                 { | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                     arguments.Add(DeterminePropertyInfo(method.ParamTypes[i], | 
					
						
							| 
									
										
										
										
											2023-06-16 23:05:11 +02:00
										 |  |  |                         method.Method.Parameters[i].Type, | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                         name: method.Method.Parameters[i].Name)); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             else | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             { | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                 arguments = null; | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-20 22:49:33 +08:00
										 |  |  |             MethodFlags flags = MethodFlags.Default; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (method.Method.IsStatic) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 flags |= MethodFlags.Static; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return new MethodInfo(method.Method.Name, returnVal, flags, arguments, | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |                 defaultArguments: null); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-16 23:05:11 +02:00
										 |  |  |         private static PropertyInfo DeterminePropertyInfo(MarshalType marshalType, ITypeSymbol typeSymbol, string name) | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |         { | 
					
						
							|  |  |  |             var memberVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(marshalType)!.Value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             var propUsage = PropertyUsageFlags.Default; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (memberVariantType == VariantType.Nil) | 
					
						
							|  |  |  |                 propUsage |= PropertyUsageFlags.NilIsVariant; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-16 23:05:11 +02:00
										 |  |  |             string? className = null; | 
					
						
							|  |  |  |             if (memberVariantType == VariantType.Object && typeSymbol is INamedTypeSymbol namedTypeSymbol) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 className = namedTypeSymbol.GetGodotScriptNativeClassName(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             return new PropertyInfo(memberVariantType, name, | 
					
						
							| 
									
										
										
										
											2023-06-16 23:05:11 +02:00
										 |  |  |                 PropertyHint.None, string.Empty, propUsage, className, exported: false); | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         private static void GenerateHasMethodEntry( | 
					
						
							|  |  |  |             string methodName, | 
					
						
							|  |  |  |             StringBuilder source, | 
					
						
							|  |  |  |             bool isFirstEntry | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             source.Append("        "); | 
					
						
							|  |  |  |             if (!isFirstEntry) | 
					
						
							|  |  |  |                 source.Append("else "); | 
					
						
							| 
									
										
										
										
											2022-09-06 20:43:40 +08:00
										 |  |  |             source.Append("if (method == MethodName."); | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:48 +02:00
										 |  |  |             source.Append(methodName); | 
					
						
							|  |  |  |             source.Append(") {\n           return true;\n        }\n"); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         private static void GenerateMethodInvoker( | 
					
						
							| 
									
										
										
										
											2022-02-27 21:57:30 +01:00
										 |  |  |             GodotMethodData method, | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             StringBuilder source | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             string methodName = method.Method.Name; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-06 20:43:40 +08:00
										 |  |  |             source.Append("        if (method == MethodName."); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             source.Append(methodName); | 
					
						
							| 
									
										
											  
											
												C#: Remove need for reflection to invoking callable delegates
We aim to make the C# API reflection-free, mainly for concerns about
performance, and to be able to target NativeAOT in refletion-free mode,
which reduces the binary size.
One of the main usages of reflection still left was the dynamic
invokation of callable delegates, and for some time I wasn't sure
I would find an alternative solution that I'd be happy with.
The new solution uses trampoline functions to invoke the delegates:
```
static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
{
    if (args.Count != 1)
        throw new ArgumentException($"Callable expected 1 arguments but received {args.Count}.");
    string res = ((Func<int, string>)delegateObj)(
        VariantConversionCallbacks.GetToManagedCallback<int>()(args[0])
    );
    ret = VariantConversionCallbacks.GetToVariantCallback<string>()(res);
}
Callable.CreateWithUnsafeTrampoline((int num) => "Foo" + num, &Trampoline);
```
Of course, this is too much boilerplate for user code. To improve this,
the `Callable.From` methods were added. These are overloads that take
`Action` and `Func` delegates, which covers the most common use cases:
lambdas and method groups:
```
// Lambda
Callable.From((int num) => "Foo" + num);
// Method group
string AppendNum(int num) => "Foo" + num;
Callable.From(AppendNum);
```
Unfortunately, due to limitations in the C# language, implicit
conversions from delegates to `Callable` are not supported.
`Callable.From` does not support custom delegates. These should be
uncommon, but the Godot C# API actually uses them for event signals.
As such, the bindings generator was updated to generate trampoline
functions for event signals. It was also optimized to use `Action`
instead of a custom delegate for parameterless signals, which removes
the need for the trampoline functions for those signals.
The change to reflection-free invokation removes one of the last needs
for `ConvertVariantToManagedObjectOfType`. The only remaining usage is
from calling script constructors with parameters from the engine
(`CreateManagedForGodotObjectScriptInstance`). Once that one is made
reflection-free, `ConvertVariantToManagedObjectOfType` can be removed.
											
										 
											2022-10-28 22:59:13 +02:00
										 |  |  |             source.Append(" && args.Count == "); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             source.Append(method.ParamTypes.Length); | 
					
						
							|  |  |  |             source.Append(") {\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (method.RetType != null) | 
					
						
							| 
									
										
										
										
											2022-02-27 21:57:46 +01:00
										 |  |  |                 source.Append("            var callRet = "); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             else | 
					
						
							|  |  |  |                 source.Append("            "); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             source.Append(methodName); | 
					
						
							|  |  |  |             source.Append("("); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for (int i = 0; i < method.ParamTypes.Length; i++) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if (i != 0) | 
					
						
							|  |  |  |                     source.Append(", "); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-28 17:41:50 +02:00
										 |  |  |                 source.AppendNativeVariantToManagedExpr(string.Concat("args[", i.ToString(), "]"), | 
					
						
							| 
									
										
										
										
											2022-02-27 21:57:46 +01:00
										 |  |  |                     method.ParamTypeSymbols[i], method.ParamTypes[i]); | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             source.Append(");\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (method.RetType != null) | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2022-02-27 21:57:46 +01:00
										 |  |  |                 source.Append("            ret = "); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-01 01:45:11 +01:00
										 |  |  |                 source.AppendManagedToNativeVariantExpr("callRet", | 
					
						
							|  |  |  |                     method.RetType.Value.TypeSymbol, method.RetType.Value.MarshalType); | 
					
						
							| 
									
										
										
										
											2022-02-27 21:57:46 +01:00
										 |  |  |                 source.Append(";\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |                 source.Append("            return true;\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 source.Append("            ret = default;\n"); | 
					
						
							|  |  |  |                 source.Append("            return true;\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             source.Append("        }\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |