C#: Add source generator for method list
This commit is contained in:
@@ -400,6 +400,12 @@ namespace Godot.SourceGenerators
|
||||
source.Append(VariantUtils, ".ConvertToQuaternion(", inputExpr, ")"),
|
||||
MarshalType.Transform3D =>
|
||||
source.Append(VariantUtils, ".ConvertToTransform3D(", inputExpr, ")"),
|
||||
MarshalType.Vector4 =>
|
||||
source.Append(VariantUtils, ".ConvertToVector4(", inputExpr, ")"),
|
||||
MarshalType.Vector4i =>
|
||||
source.Append(VariantUtils, ".ConvertToVector4i(", inputExpr, ")"),
|
||||
MarshalType.Projection =>
|
||||
source.Append(VariantUtils, ".ConvertToProjection(", inputExpr, ")"),
|
||||
MarshalType.AABB =>
|
||||
source.Append(VariantUtils, ".ConvertToAABB(", inputExpr, ")"),
|
||||
MarshalType.Color =>
|
||||
@@ -535,6 +541,12 @@ namespace Godot.SourceGenerators
|
||||
source.Append(VariantUtils, ".CreateFromQuaternion(", inputExpr, ")"),
|
||||
MarshalType.Transform3D =>
|
||||
source.Append(VariantUtils, ".CreateFromTransform3D(", inputExpr, ")"),
|
||||
MarshalType.Vector4 =>
|
||||
source.Append(VariantUtils, ".CreateFromVector4(", inputExpr, ")"),
|
||||
MarshalType.Vector4i =>
|
||||
source.Append(VariantUtils, ".CreateFromVector4i(", inputExpr, ")"),
|
||||
MarshalType.Projection =>
|
||||
source.Append(VariantUtils, ".CreateFromProjection(", inputExpr, ")"),
|
||||
MarshalType.AABB =>
|
||||
source.Append(VariantUtils, ".CreateFromAABB(", inputExpr, ")"),
|
||||
MarshalType.Color =>
|
||||
|
||||
+176
-231
@@ -8,8 +8,12 @@ using Microsoft.CodeAnalysis.Text;
|
||||
namespace Godot.SourceGenerators
|
||||
{
|
||||
[Generator]
|
||||
public class ScriptMemberInvokerGenerator : ISourceGenerator
|
||||
public class ScriptMethodsGenerator : ISourceGenerator
|
||||
{
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
if (context.AreGodotSourceGeneratorsDisabled())
|
||||
@@ -54,6 +58,20 @@ namespace Godot.SourceGenerators
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void VisitGodotScriptClass(
|
||||
GeneratorExecutionContext context,
|
||||
MarshalUtils.TypeCache typeCache,
|
||||
@@ -69,7 +87,7 @@ namespace Godot.SourceGenerators
|
||||
bool isInnerClass = symbol.ContainingType != null;
|
||||
|
||||
string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
|
||||
+ "_ScriptMemberInvoker_Generated";
|
||||
+ "_ScriptMethods_Generated";
|
||||
|
||||
var source = new StringBuilder();
|
||||
|
||||
@@ -111,54 +129,21 @@ namespace Godot.SourceGenerators
|
||||
.Cast<IMethodSymbol>()
|
||||
.Where(m => m.MethodKind == MethodKind.Ordinary);
|
||||
|
||||
var propertySymbols = members
|
||||
.Where(s => !s.IsStatic && s.Kind == SymbolKind.Property)
|
||||
.Cast<IPropertySymbol>();
|
||||
|
||||
var fieldSymbols = members
|
||||
.Where(s => !s.IsStatic && s.Kind == SymbolKind.Field && !s.IsImplicitlyDeclared)
|
||||
.Cast<IFieldSymbol>();
|
||||
|
||||
var godotClassMethods = methodSymbols.WhereHasGodotCompatibleSignature(typeCache).ToArray();
|
||||
var godotClassProperties = propertySymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
|
||||
var godotClassFields = fieldSymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
|
||||
|
||||
var signalDelegateSymbols = members
|
||||
.Where(s => s.Kind == SymbolKind.NamedType)
|
||||
.Cast<INamedTypeSymbol>()
|
||||
.Where(namedTypeSymbol => namedTypeSymbol.TypeKind == TypeKind.Delegate)
|
||||
.Where(s => s.GetAttributes()
|
||||
.Any(a => a.AttributeClass?.IsGodotSignalAttribute() ?? false));
|
||||
|
||||
List<GodotSignalDelegateData> godotSignalDelegates = new();
|
||||
|
||||
foreach (var signalDelegateSymbol in signalDelegateSymbols)
|
||||
{
|
||||
if (!signalDelegateSymbol.Name.EndsWith(ScriptSignalsGenerator.SignalDelegateSuffix))
|
||||
continue;
|
||||
|
||||
string signalName = signalDelegateSymbol.Name;
|
||||
signalName = signalName.Substring(0,
|
||||
signalName.Length - ScriptSignalsGenerator.SignalDelegateSuffix.Length);
|
||||
|
||||
var invokeMethodData = signalDelegateSymbol
|
||||
.DelegateInvokeMethod?.HasGodotCompatibleSignature(typeCache);
|
||||
|
||||
if (invokeMethodData == null)
|
||||
continue;
|
||||
|
||||
godotSignalDelegates.Add(new(signalName, signalDelegateSymbol, invokeMethodData.Value));
|
||||
}
|
||||
var godotClassMethods = methodSymbols.WhereHasGodotCompatibleSignature(typeCache)
|
||||
.Distinct(new MethodOverloadEqualityComparer())
|
||||
.ToArray();
|
||||
|
||||
source.Append(" private partial class GodotInternal {\n");
|
||||
|
||||
// Generate cached StringNames for methods and properties, for fast lookup
|
||||
|
||||
// TODO: Move the generation of these cached StringNames to its own generator
|
||||
var distinctMethodNames = godotClassMethods
|
||||
.Select(m => m.Method.Name)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
foreach (var method in godotClassMethods)
|
||||
foreach (string methodName in distinctMethodNames)
|
||||
{
|
||||
string methodName = method.Method.Name;
|
||||
source.Append(" public static readonly StringName MethodName_");
|
||||
source.Append(methodName);
|
||||
source.Append(" = \"");
|
||||
@@ -168,6 +153,36 @@ namespace Godot.SourceGenerators
|
||||
|
||||
source.Append(" }\n"); // class GodotInternal
|
||||
|
||||
// Generate GetGodotMethodList
|
||||
|
||||
if (godotClassMethods.Length > 0)
|
||||
{
|
||||
source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
|
||||
|
||||
const string listType = "System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>";
|
||||
|
||||
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");
|
||||
|
||||
source.Append("#pragma warning restore CS0109\n");
|
||||
}
|
||||
|
||||
// Generate InvokeGodotClassMethod
|
||||
|
||||
if (godotClassMethods.Length > 0)
|
||||
@@ -187,14 +202,14 @@ namespace Godot.SourceGenerators
|
||||
|
||||
// Generate HasGodotClassMethod
|
||||
|
||||
if (godotClassMethods.Length > 0)
|
||||
if (distinctMethodNames.Length > 0)
|
||||
{
|
||||
source.Append(" protected override bool HasGodotClassMethod(in godot_string_name method)\n {\n");
|
||||
|
||||
bool isFirstEntry = true;
|
||||
foreach (var method in godotClassMethods)
|
||||
foreach (string methodName in distinctMethodNames)
|
||||
{
|
||||
GenerateHasMethodEntry(method, source, isFirstEntry);
|
||||
GenerateHasMethodEntry(methodName, source, isFirstEntry);
|
||||
isFirstEntry = false;
|
||||
}
|
||||
|
||||
@@ -203,91 +218,6 @@ namespace Godot.SourceGenerators
|
||||
source.Append(" }\n");
|
||||
}
|
||||
|
||||
// Generate RaiseGodotClassSignalCallbacks
|
||||
|
||||
if (godotSignalDelegates.Count > 0)
|
||||
{
|
||||
source.Append(
|
||||
" protected override void RaiseGodotClassSignalCallbacks(in godot_string_name signal, ");
|
||||
source.Append("NativeVariantPtrArgs args, int argCount)\n {\n");
|
||||
|
||||
foreach (var signal in godotSignalDelegates)
|
||||
{
|
||||
GenerateSignalEventInvoker(signal, source);
|
||||
}
|
||||
|
||||
source.Append(" base.RaiseGodotClassSignalCallbacks(signal, args, argCount);\n");
|
||||
|
||||
source.Append(" }\n");
|
||||
}
|
||||
|
||||
// Generate Set/GetGodotClassPropertyValue
|
||||
|
||||
if (godotClassProperties.Length > 0 || godotClassFields.Length > 0)
|
||||
{
|
||||
bool isFirstEntry;
|
||||
|
||||
// Setters
|
||||
|
||||
bool allPropertiesAreReadOnly = godotClassFields.All(fi => fi.FieldSymbol.IsReadOnly) &&
|
||||
godotClassProperties.All(pi => pi.PropertySymbol.IsReadOnly);
|
||||
|
||||
if (!allPropertiesAreReadOnly)
|
||||
{
|
||||
source.Append(" protected override bool SetGodotClassPropertyValue(in godot_string_name name, ");
|
||||
source.Append("in godot_variant value)\n {\n");
|
||||
|
||||
isFirstEntry = true;
|
||||
foreach (var property in godotClassProperties)
|
||||
{
|
||||
if (property.PropertySymbol.IsReadOnly)
|
||||
continue;
|
||||
|
||||
GeneratePropertySetter(property.PropertySymbol.Name,
|
||||
property.PropertySymbol.Type, property.Type, source, isFirstEntry);
|
||||
isFirstEntry = false;
|
||||
}
|
||||
|
||||
foreach (var field in godotClassFields)
|
||||
{
|
||||
if (field.FieldSymbol.IsReadOnly)
|
||||
continue;
|
||||
|
||||
GeneratePropertySetter(field.FieldSymbol.Name,
|
||||
field.FieldSymbol.Type, field.Type, source, isFirstEntry);
|
||||
isFirstEntry = false;
|
||||
}
|
||||
|
||||
source.Append(" return base.SetGodotClassPropertyValue(name, value);\n");
|
||||
|
||||
source.Append(" }\n");
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
source.Append(" protected override bool GetGodotClassPropertyValue(in godot_string_name name, ");
|
||||
source.Append("out godot_variant value)\n {\n");
|
||||
|
||||
isFirstEntry = true;
|
||||
foreach (var property in godotClassProperties)
|
||||
{
|
||||
GeneratePropertyGetter(property.PropertySymbol.Name,
|
||||
property.Type, source, isFirstEntry);
|
||||
isFirstEntry = false;
|
||||
}
|
||||
|
||||
foreach (var field in godotClassFields)
|
||||
{
|
||||
GeneratePropertyGetter(field.FieldSymbol.Name,
|
||||
field.Type, source, isFirstEntry);
|
||||
isFirstEntry = false;
|
||||
}
|
||||
|
||||
source.Append(" return base.GetGodotClassPropertyValue(name, out value);\n");
|
||||
|
||||
source.Append(" }\n");
|
||||
}
|
||||
|
||||
source.Append("}\n"); // partial class
|
||||
|
||||
if (isInnerClass)
|
||||
@@ -310,6 +240,121 @@ namespace Godot.SourceGenerators
|
||||
context.AddSource(uniqueHint, SourceText.From(source.ToString(), Encoding.UTF8));
|
||||
}
|
||||
|
||||
private static void AppendMethodInfo(StringBuilder source, MethodInfo methodInfo)
|
||||
{
|
||||
source.Append(" methods.Add(new(name: GodotInternal.MethodName_")
|
||||
.Append(methodInfo.Name)
|
||||
.Append(", returnVal: ");
|
||||
|
||||
AppendPropertyInfo(source, methodInfo.ReturnVal);
|
||||
|
||||
source.Append(", flags: (Godot.MethodFlags)")
|
||||
.Append((int)methodInfo.Flags)
|
||||
.Append(", arguments: ");
|
||||
|
||||
if (methodInfo.Arguments is { Count: > 0 })
|
||||
{
|
||||
source.Append("new() { ");
|
||||
|
||||
foreach (var param in methodInfo.Arguments)
|
||||
{
|
||||
AppendPropertyInfo(source, param);
|
||||
|
||||
// C# allows colon after the last element
|
||||
source.Append(", ");
|
||||
}
|
||||
|
||||
source.Append(" }");
|
||||
}
|
||||
else
|
||||
{
|
||||
source.Append("null");
|
||||
}
|
||||
|
||||
source.Append(", defaultArguments: null));\n");
|
||||
}
|
||||
|
||||
private static void AppendPropertyInfo(StringBuilder source, PropertyInfo propertyInfo)
|
||||
{
|
||||
source.Append("new(type: (Godot.Variant.Type)")
|
||||
.Append((int)propertyInfo.Type)
|
||||
.Append(", name: \"")
|
||||
.Append(propertyInfo.Name)
|
||||
.Append("\", hint: (Godot.PropertyHint)")
|
||||
.Append((int)propertyInfo.Hint)
|
||||
.Append(", hintString: \"")
|
||||
.Append(propertyInfo.HintString)
|
||||
.Append("\", usage: (Godot.PropertyUsageFlags)")
|
||||
.Append((int)propertyInfo.Usage)
|
||||
.Append(", exported: ")
|
||||
.Append(propertyInfo.Exported ? "true" : "false")
|
||||
.Append(")");
|
||||
}
|
||||
|
||||
private static MethodInfo DetermineMethodInfo(GodotMethodData method)
|
||||
{
|
||||
PropertyInfo returnVal;
|
||||
|
||||
if (method.RetType != null)
|
||||
{
|
||||
returnVal = DeterminePropertyInfo(method.RetType.Value, name: string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
returnVal = new PropertyInfo(VariantType.Nil, string.Empty, PropertyHint.None,
|
||||
hintString: null, PropertyUsageFlags.Default, exported: false);
|
||||
}
|
||||
|
||||
int paramCount = method.ParamTypes.Length;
|
||||
|
||||
List<PropertyInfo>? arguments;
|
||||
|
||||
if (paramCount > 0)
|
||||
{
|
||||
arguments = new(capacity: paramCount);
|
||||
|
||||
for (int i = 0; i < paramCount; i++)
|
||||
{
|
||||
arguments.Add(DeterminePropertyInfo(method.ParamTypes[i],
|
||||
name: method.Method.Parameters[i].Name));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arguments = null;
|
||||
}
|
||||
|
||||
return new MethodInfo(method.Method.Name, returnVal, MethodFlags.Default, arguments,
|
||||
defaultArguments: null);
|
||||
}
|
||||
|
||||
private static PropertyInfo DeterminePropertyInfo(MarshalType marshalType, string name)
|
||||
{
|
||||
var memberVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(marshalType)!.Value;
|
||||
|
||||
var propUsage = PropertyUsageFlags.Default;
|
||||
|
||||
if (memberVariantType == VariantType.Nil)
|
||||
propUsage |= PropertyUsageFlags.NilIsVariant;
|
||||
|
||||
return new PropertyInfo(memberVariantType, name,
|
||||
PropertyHint.None, string.Empty, propUsage, exported: false);
|
||||
}
|
||||
|
||||
private static void GenerateHasMethodEntry(
|
||||
string methodName,
|
||||
StringBuilder source,
|
||||
bool isFirstEntry
|
||||
)
|
||||
{
|
||||
source.Append(" ");
|
||||
if (!isFirstEntry)
|
||||
source.Append("else ");
|
||||
source.Append("if (method == GodotInternal.MethodName_");
|
||||
source.Append(methodName);
|
||||
source.Append(") {\n return true;\n }\n");
|
||||
}
|
||||
|
||||
private static void GenerateMethodInvoker(
|
||||
GodotMethodData method,
|
||||
StringBuilder source
|
||||
@@ -359,105 +404,5 @@ namespace Godot.SourceGenerators
|
||||
|
||||
source.Append(" }\n");
|
||||
}
|
||||
|
||||
private static void GenerateSignalEventInvoker(
|
||||
GodotSignalDelegateData signal,
|
||||
StringBuilder source
|
||||
)
|
||||
{
|
||||
string signalName = signal.Name;
|
||||
var invokeMethodData = signal.InvokeMethodData;
|
||||
|
||||
source.Append(" if (signal == GodotInternal.SignalName_");
|
||||
source.Append(signalName);
|
||||
source.Append(" && argCount == ");
|
||||
source.Append(invokeMethodData.ParamTypes.Length);
|
||||
source.Append(") {\n");
|
||||
source.Append(" backing_");
|
||||
source.Append(signalName);
|
||||
source.Append("?.Invoke(");
|
||||
|
||||
for (int i = 0; i < invokeMethodData.ParamTypes.Length; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
source.Append(", ");
|
||||
|
||||
source.AppendVariantToManagedExpr(string.Concat("args[", i.ToString(), "]"),
|
||||
invokeMethodData.ParamTypeSymbols[i], invokeMethodData.ParamTypes[i]);
|
||||
}
|
||||
|
||||
source.Append(");\n");
|
||||
|
||||
source.Append(" return;\n");
|
||||
|
||||
source.Append(" }\n");
|
||||
}
|
||||
|
||||
private static void GeneratePropertySetter(
|
||||
string propertyMemberName,
|
||||
ITypeSymbol propertyTypeSymbol,
|
||||
MarshalType propertyMarshalType,
|
||||
StringBuilder source,
|
||||
bool isFirstEntry
|
||||
)
|
||||
{
|
||||
source.Append(" ");
|
||||
|
||||
if (!isFirstEntry)
|
||||
source.Append("else ");
|
||||
|
||||
source.Append("if (name == GodotInternal.PropName_")
|
||||
.Append(propertyMemberName)
|
||||
.Append(") {\n")
|
||||
.Append(" ")
|
||||
.Append(propertyMemberName)
|
||||
.Append(" = ")
|
||||
.AppendVariantToManagedExpr("value", propertyTypeSymbol, propertyMarshalType)
|
||||
.Append(";\n")
|
||||
.Append(" return true;\n")
|
||||
.Append(" }\n");
|
||||
}
|
||||
|
||||
private static void GeneratePropertyGetter(
|
||||
string propertyMemberName,
|
||||
MarshalType propertyMarshalType,
|
||||
StringBuilder source,
|
||||
bool isFirstEntry
|
||||
)
|
||||
{
|
||||
source.Append(" ");
|
||||
|
||||
if (!isFirstEntry)
|
||||
source.Append("else ");
|
||||
|
||||
source.Append("if (name == GodotInternal.PropName_")
|
||||
.Append(propertyMemberName)
|
||||
.Append(") {\n")
|
||||
.Append(" value = ")
|
||||
.AppendManagedToVariantExpr(propertyMemberName, propertyMarshalType)
|
||||
.Append(";\n")
|
||||
.Append(" return true;\n")
|
||||
.Append(" }\n");
|
||||
}
|
||||
|
||||
private static void GenerateHasMethodEntry(
|
||||
GodotMethodData method,
|
||||
StringBuilder source,
|
||||
bool isFirstEntry
|
||||
)
|
||||
{
|
||||
string methodName = method.Method.Name;
|
||||
|
||||
source.Append(" ");
|
||||
if (!isFirstEntry)
|
||||
source.Append("else ");
|
||||
source.Append("if (method == GodotInternal.MethodName_");
|
||||
source.Append(methodName);
|
||||
source.Append(") {\n return true;\n }\n");
|
||||
}
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
+111
-2
@@ -146,10 +146,72 @@ namespace Godot.SourceGenerators
|
||||
|
||||
source.Append(" }\n"); // class GodotInternal
|
||||
|
||||
// Generate GetGodotPropertyList
|
||||
|
||||
if (godotClassProperties.Length > 0 || godotClassFields.Length > 0)
|
||||
{
|
||||
bool isFirstEntry;
|
||||
|
||||
// Generate SetGodotClassPropertyValue
|
||||
|
||||
bool allPropertiesAreReadOnly = godotClassFields.All(fi => fi.FieldSymbol.IsReadOnly) &&
|
||||
godotClassProperties.All(pi => pi.PropertySymbol.IsReadOnly);
|
||||
|
||||
if (!allPropertiesAreReadOnly)
|
||||
{
|
||||
source.Append(" protected override bool SetGodotClassPropertyValue(in godot_string_name name, ");
|
||||
source.Append("in godot_variant value)\n {\n");
|
||||
|
||||
isFirstEntry = true;
|
||||
foreach (var property in godotClassProperties)
|
||||
{
|
||||
if (property.PropertySymbol.IsReadOnly)
|
||||
continue;
|
||||
|
||||
GeneratePropertySetter(property.PropertySymbol.Name,
|
||||
property.PropertySymbol.Type, property.Type, source, isFirstEntry);
|
||||
isFirstEntry = false;
|
||||
}
|
||||
|
||||
foreach (var field in godotClassFields)
|
||||
{
|
||||
if (field.FieldSymbol.IsReadOnly)
|
||||
continue;
|
||||
|
||||
GeneratePropertySetter(field.FieldSymbol.Name,
|
||||
field.FieldSymbol.Type, field.Type, source, isFirstEntry);
|
||||
isFirstEntry = false;
|
||||
}
|
||||
|
||||
source.Append(" return base.SetGodotClassPropertyValue(name, value);\n");
|
||||
|
||||
source.Append(" }\n");
|
||||
}
|
||||
|
||||
// Generate GetGodotClassPropertyValue
|
||||
|
||||
source.Append(" protected override bool GetGodotClassPropertyValue(in godot_string_name name, ");
|
||||
source.Append("out godot_variant value)\n {\n");
|
||||
|
||||
isFirstEntry = true;
|
||||
foreach (var property in godotClassProperties)
|
||||
{
|
||||
GeneratePropertyGetter(property.PropertySymbol.Name,
|
||||
property.Type, source, isFirstEntry);
|
||||
isFirstEntry = false;
|
||||
}
|
||||
|
||||
foreach (var field in godotClassFields)
|
||||
{
|
||||
GeneratePropertyGetter(field.FieldSymbol.Name,
|
||||
field.Type, source, isFirstEntry);
|
||||
isFirstEntry = false;
|
||||
}
|
||||
|
||||
source.Append(" return base.GetGodotClassPropertyValue(name, out value);\n");
|
||||
|
||||
source.Append(" }\n");
|
||||
|
||||
// Generate GetGodotPropertyList
|
||||
|
||||
source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
|
||||
|
||||
string dictionaryType = "System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>";
|
||||
@@ -212,6 +274,53 @@ namespace Godot.SourceGenerators
|
||||
context.AddSource(uniqueHint, SourceText.From(source.ToString(), Encoding.UTF8));
|
||||
}
|
||||
|
||||
private static void GeneratePropertySetter(
|
||||
string propertyMemberName,
|
||||
ITypeSymbol propertyTypeSymbol,
|
||||
MarshalType propertyMarshalType,
|
||||
StringBuilder source,
|
||||
bool isFirstEntry
|
||||
)
|
||||
{
|
||||
source.Append(" ");
|
||||
|
||||
if (!isFirstEntry)
|
||||
source.Append("else ");
|
||||
|
||||
source.Append("if (name == GodotInternal.PropName_")
|
||||
.Append(propertyMemberName)
|
||||
.Append(") {\n")
|
||||
.Append(" ")
|
||||
.Append(propertyMemberName)
|
||||
.Append(" = ")
|
||||
.AppendVariantToManagedExpr("value", propertyTypeSymbol, propertyMarshalType)
|
||||
.Append(";\n")
|
||||
.Append(" return true;\n")
|
||||
.Append(" }\n");
|
||||
}
|
||||
|
||||
private static void GeneratePropertyGetter(
|
||||
string propertyMemberName,
|
||||
MarshalType propertyMarshalType,
|
||||
StringBuilder source,
|
||||
bool isFirstEntry
|
||||
)
|
||||
{
|
||||
source.Append(" ");
|
||||
|
||||
if (!isFirstEntry)
|
||||
source.Append("else ");
|
||||
|
||||
source.Append("if (name == GodotInternal.PropName_")
|
||||
.Append(propertyMemberName)
|
||||
.Append(") {\n")
|
||||
.Append(" value = ")
|
||||
.AppendManagedToVariantExpr(propertyMemberName, propertyMarshalType)
|
||||
.Append(";\n")
|
||||
.Append(" return true;\n")
|
||||
.Append(" }\n");
|
||||
}
|
||||
|
||||
private static void AppendPropertyInfo(StringBuilder source, PropertyInfo propertyInfo)
|
||||
{
|
||||
source.Append(" properties.Add(new(type: (Godot.Variant.Type)")
|
||||
|
||||
@@ -232,6 +232,24 @@ namespace Godot.SourceGenerators
|
||||
.Append("}\n");
|
||||
}
|
||||
|
||||
// Generate RaiseGodotClassSignalCallbacks
|
||||
|
||||
if (godotSignalDelegates.Count > 0)
|
||||
{
|
||||
source.Append(
|
||||
" protected override void RaiseGodotClassSignalCallbacks(in godot_string_name signal, ");
|
||||
source.Append("NativeVariantPtrArgs args, int argCount)\n {\n");
|
||||
|
||||
foreach (var signal in godotSignalDelegates)
|
||||
{
|
||||
GenerateSignalEventInvoker(signal, source);
|
||||
}
|
||||
|
||||
source.Append(" base.RaiseGodotClassSignalCallbacks(signal, args, argCount);\n");
|
||||
|
||||
source.Append(" }\n");
|
||||
}
|
||||
|
||||
source.Append("}\n"); // partial class
|
||||
|
||||
if (isInnerClass)
|
||||
@@ -356,5 +374,38 @@ namespace Godot.SourceGenerators
|
||||
return new PropertyInfo(memberVariantType, name,
|
||||
PropertyHint.None, string.Empty, propUsage, exported: false);
|
||||
}
|
||||
|
||||
private static void GenerateSignalEventInvoker(
|
||||
GodotSignalDelegateData signal,
|
||||
StringBuilder source
|
||||
)
|
||||
{
|
||||
string signalName = signal.Name;
|
||||
var invokeMethodData = signal.InvokeMethodData;
|
||||
|
||||
source.Append(" if (signal == GodotInternal.SignalName_");
|
||||
source.Append(signalName);
|
||||
source.Append(" && argCount == ");
|
||||
source.Append(invokeMethodData.ParamTypes.Length);
|
||||
source.Append(") {\n");
|
||||
source.Append(" backing_");
|
||||
source.Append(signalName);
|
||||
source.Append("?.Invoke(");
|
||||
|
||||
for (int i = 0; i < invokeMethodData.ParamTypes.Length; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
source.Append(", ");
|
||||
|
||||
source.AppendVariantToManagedExpr(string.Concat("args[", i.ToString(), "]"),
|
||||
invokeMethodData.ParamTypeSymbols[i], invokeMethodData.ParamTypes[i]);
|
||||
}
|
||||
|
||||
source.Append(");\n");
|
||||
|
||||
source.Append(" return;\n");
|
||||
|
||||
source.Append(" }\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user