Add support for generic types in Scripting API with Template flag
This commit is contained in:
@@ -28,6 +28,7 @@ namespace Flax.Build.Bindings
|
||||
public virtual bool IsValueType => false;
|
||||
public virtual bool IsScriptingObject => false;
|
||||
public virtual bool IsPod => false;
|
||||
public virtual bool SkipGeneration => IsInBuild;
|
||||
|
||||
public FileInfo File
|
||||
{
|
||||
|
||||
@@ -235,10 +235,10 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
|
||||
// Object reference property
|
||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
||||
typeInfo.Type == "AssetReference" ||
|
||||
typeInfo.Type == "WeakAssetReference" ||
|
||||
typeInfo.Type == "SoftAssetReference" ||
|
||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
||||
typeInfo.Type == "AssetReference" ||
|
||||
typeInfo.Type == "WeakAssetReference" ||
|
||||
typeInfo.Type == "SoftAssetReference" ||
|
||||
typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null)
|
||||
return GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller);
|
||||
|
||||
@@ -284,21 +284,23 @@ namespace Flax.Build.Bindings
|
||||
|
||||
// Find API type info
|
||||
var apiType = FindApiTypeInfo(buildData, typeInfo, caller);
|
||||
var typeName = typeInfo.Type.Replace("::", ".");
|
||||
if (apiType != null)
|
||||
{
|
||||
CSharpUsedNamespaces.Add(apiType.Namespace);
|
||||
|
||||
if (apiType.IsScriptingObject || apiType.IsInterface)
|
||||
return typeInfo.Type.Replace("::", ".");
|
||||
return typeName;
|
||||
if (typeInfo.IsPtr && apiType.IsPod)
|
||||
return typeInfo.Type.Replace("::", ".") + '*';
|
||||
return typeName + '*';
|
||||
if (apiType is LangType && CSharpNativeToManagedBasicTypes.TryGetValue(apiType.Name, out result))
|
||||
return result;
|
||||
}
|
||||
|
||||
// Pointer
|
||||
if (typeInfo.IsPtr)
|
||||
return "IntPtr";
|
||||
|
||||
return typeInfo.Type.Replace("::", ".");
|
||||
return typeName;
|
||||
}
|
||||
|
||||
private static string GenerateCSharpManagedToNativeType(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller)
|
||||
@@ -316,10 +318,10 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
|
||||
// Object reference property
|
||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
||||
typeInfo.Type == "AssetReference" ||
|
||||
typeInfo.Type == "WeakAssetReference" ||
|
||||
typeInfo.Type == "SoftAssetReference" ||
|
||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
||||
typeInfo.Type == "AssetReference" ||
|
||||
typeInfo.Type == "WeakAssetReference" ||
|
||||
typeInfo.Type == "SoftAssetReference" ||
|
||||
typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null)
|
||||
return "IntPtr";
|
||||
|
||||
@@ -374,10 +376,10 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
|
||||
// Object reference property
|
||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
||||
typeInfo.Type == "AssetReference" ||
|
||||
typeInfo.Type == "WeakAssetReference" ||
|
||||
typeInfo.Type == "SoftAssetReference" ||
|
||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
||||
typeInfo.Type == "AssetReference" ||
|
||||
typeInfo.Type == "WeakAssetReference" ||
|
||||
typeInfo.Type == "SoftAssetReference" ||
|
||||
typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null)
|
||||
return "FlaxEngine.Object.GetUnmanagedPtr({0})";
|
||||
|
||||
@@ -1355,7 +1357,7 @@ namespace Flax.Build.Bindings
|
||||
|
||||
private static bool GenerateCSharpType(BuildData buildData, StringBuilder contents, string indent, object type)
|
||||
{
|
||||
if (type is ApiTypeInfo apiTypeInfo && apiTypeInfo.IsInBuild)
|
||||
if (type is ApiTypeInfo apiTypeInfo && apiTypeInfo.SkipGeneration)
|
||||
return false;
|
||||
|
||||
try
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Flax.Build.Bindings
|
||||
partial class BindingsGenerator
|
||||
{
|
||||
private static readonly Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
|
||||
private const int CacheVersion = 12;
|
||||
private const int CacheVersion = 13;
|
||||
|
||||
internal static void Write(BinaryWriter writer, string e)
|
||||
{
|
||||
|
||||
@@ -131,10 +131,10 @@ namespace Flax.Build.Bindings
|
||||
return value;
|
||||
if (typeInfo.Type == "String")
|
||||
return $"Variant(StringView({value}))";
|
||||
if (typeInfo.Type == "AssetReference" ||
|
||||
typeInfo.Type == "WeakAssetReference" ||
|
||||
typeInfo.Type == "SoftAssetReference" ||
|
||||
typeInfo.Type == "ScriptingObjectReference" ||
|
||||
if (typeInfo.Type == "AssetReference" ||
|
||||
typeInfo.Type == "WeakAssetReference" ||
|
||||
typeInfo.Type == "SoftAssetReference" ||
|
||||
typeInfo.Type == "ScriptingObjectReference" ||
|
||||
typeInfo.Type == "SoftObjectReference")
|
||||
return $"Variant({value}.Get())";
|
||||
if (typeInfo.IsArray)
|
||||
@@ -254,7 +254,7 @@ namespace Flax.Build.Bindings
|
||||
CppReferencesFiles.Add(apiType.File);
|
||||
if (apiType.IsStruct && !apiType.IsPod && !CppUsedNonPodTypes.Contains(apiType))
|
||||
CppUsedNonPodTypes.Add(apiType);
|
||||
if (!apiType.IsInBuild && !apiType.IsEnum)
|
||||
if (!apiType.SkipGeneration && !apiType.IsEnum)
|
||||
{
|
||||
// Use declared type initializer
|
||||
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h");
|
||||
@@ -329,7 +329,7 @@ namespace Flax.Build.Bindings
|
||||
CppReferencesFiles.Add(apiType.File);
|
||||
if (apiType.IsStruct && !apiType.IsPod && !CppUsedNonPodTypes.Contains(apiType))
|
||||
CppUsedNonPodTypes.Add(apiType);
|
||||
if (!apiType.IsInBuild && !apiType.IsEnum)
|
||||
if (!apiType.SkipGeneration && !apiType.IsEnum)
|
||||
{
|
||||
// Use declared type initializer
|
||||
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h");
|
||||
@@ -406,10 +406,10 @@ namespace Flax.Build.Bindings
|
||||
return "MUtils::ToManaged({0})";
|
||||
default:
|
||||
// Object reference property
|
||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
||||
typeInfo.Type == "AssetReference" ||
|
||||
typeInfo.Type == "WeakAssetReference" ||
|
||||
typeInfo.Type == "SoftAssetReference" ||
|
||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
||||
typeInfo.Type == "AssetReference" ||
|
||||
typeInfo.Type == "WeakAssetReference" ||
|
||||
typeInfo.Type == "SoftAssetReference" ||
|
||||
typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null)
|
||||
{
|
||||
type = "MonoObject*";
|
||||
@@ -578,10 +578,10 @@ namespace Flax.Build.Bindings
|
||||
return "MUtils::ToNative({0})";
|
||||
default:
|
||||
// Object reference property
|
||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
||||
typeInfo.Type == "AssetReference" ||
|
||||
typeInfo.Type == "WeakAssetReference" ||
|
||||
typeInfo.Type == "SoftAssetReference" ||
|
||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
||||
typeInfo.Type == "AssetReference" ||
|
||||
typeInfo.Type == "WeakAssetReference" ||
|
||||
typeInfo.Type == "SoftAssetReference" ||
|
||||
typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null)
|
||||
{
|
||||
// For non-pod types converting only, other API converts managed to unmanaged object in C# wrapper code)
|
||||
@@ -2156,7 +2156,7 @@ namespace Flax.Build.Bindings
|
||||
|
||||
private static void GenerateCppType(BuildData buildData, StringBuilder contents, ModuleInfo moduleInfo, object type)
|
||||
{
|
||||
if (type is ApiTypeInfo apiTypeInfo && apiTypeInfo.IsInBuild)
|
||||
if (type is ApiTypeInfo apiTypeInfo && apiTypeInfo.SkipGeneration)
|
||||
return;
|
||||
|
||||
try
|
||||
@@ -2197,6 +2197,11 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
}
|
||||
}
|
||||
if (apiType is ClassStructInfo classStructInfo)
|
||||
{
|
||||
if (classStructInfo.IsTemplate)
|
||||
throw new Exception($"Cannot use template type '{classStructInfo}' as non-POD type for cross-language bindings.");
|
||||
}
|
||||
if (!CppUsedNonPodTypesList.Contains(apiType))
|
||||
CppUsedNonPodTypesList.Add(apiType);
|
||||
}
|
||||
|
||||
@@ -499,7 +499,7 @@ namespace Flax.Build.Bindings
|
||||
// Read 'class' keyword
|
||||
var token = context.Tokenizer.NextToken();
|
||||
if (token.Value != "class")
|
||||
throw new Exception($"Invalid API_CLASS usage (expected 'class' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}').");
|
||||
throw new Exception($"Invalid {ApiTokens.Class} usage (expected 'class' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}').");
|
||||
|
||||
// Read specifiers
|
||||
while (true)
|
||||
@@ -551,6 +551,9 @@ namespace Flax.Build.Bindings
|
||||
case "private":
|
||||
desc.Access = AccessLevel.Private;
|
||||
break;
|
||||
case "template":
|
||||
desc.IsTemplate = true;
|
||||
break;
|
||||
case "inbuild":
|
||||
desc.IsInBuild = true;
|
||||
break;
|
||||
@@ -592,7 +595,7 @@ namespace Flax.Build.Bindings
|
||||
// Read 'class' keyword
|
||||
var token = context.Tokenizer.NextToken();
|
||||
if (token.Value != "class")
|
||||
throw new Exception($"Invalid API_INTERFACE usage (expected 'class' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}').");
|
||||
throw new Exception($"Invalid {ApiTokens.Interface} usage (expected 'class' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}').");
|
||||
|
||||
// Read specifiers
|
||||
while (true)
|
||||
@@ -629,6 +632,9 @@ namespace Flax.Build.Bindings
|
||||
case "private":
|
||||
desc.Access = AccessLevel.Private;
|
||||
break;
|
||||
case "template":
|
||||
desc.IsTemplate = true;
|
||||
break;
|
||||
case "inbuild":
|
||||
desc.IsInBuild = true;
|
||||
break;
|
||||
@@ -876,7 +882,7 @@ namespace Flax.Build.Bindings
|
||||
// Read 'enum' or `enum class` keywords
|
||||
var token = context.Tokenizer.NextToken();
|
||||
if (token.Value != "enum")
|
||||
throw new Exception($"Invalid API_ENUM usage at line {context.Tokenizer.CurrentLine} (expected 'enum' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}').");
|
||||
throw new Exception($"Invalid {ApiTokens.Enum} usage at line {context.Tokenizer.CurrentLine} (expected 'enum' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}').");
|
||||
token = context.Tokenizer.NextToken();
|
||||
if (token.Value != "class")
|
||||
context.Tokenizer.PreviousToken();
|
||||
@@ -1046,7 +1052,7 @@ namespace Flax.Build.Bindings
|
||||
// Read 'struct' keyword
|
||||
var token = context.Tokenizer.NextToken();
|
||||
if (token.Value != "struct")
|
||||
throw new Exception($"Invalid API_STRUCT usage (expected 'struct' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}').");
|
||||
throw new Exception($"Invalid {ApiTokens.Struct} usage (expected 'struct' keyword but got '{token.Value} {context.Tokenizer.NextToken().Value}').");
|
||||
|
||||
// Read name
|
||||
desc.Name = desc.NativeName = ParseName(ref context);
|
||||
@@ -1068,6 +1074,9 @@ namespace Flax.Build.Bindings
|
||||
case "private":
|
||||
desc.Access = AccessLevel.Private;
|
||||
break;
|
||||
case "template":
|
||||
desc.IsTemplate = true;
|
||||
break;
|
||||
case "inbuild":
|
||||
desc.IsInBuild = true;
|
||||
break;
|
||||
@@ -1232,7 +1241,7 @@ namespace Flax.Build.Bindings
|
||||
if (desc.Type.Type == "Action")
|
||||
desc.Type = new TypeInfo { Type = "Delegate", GenericArgs = new List<TypeInfo>() };
|
||||
else if (desc.Type.Type != "Delegate")
|
||||
throw new Exception($"Invalid API_EVENT type. Only Action and Delegate<> types are supported. '{desc.Type}' used on event at line {context.Tokenizer.CurrentLine}.");
|
||||
throw new Exception($"Invalid {ApiTokens.Event} type. Only Action and Delegate<> types are supported. '{desc.Type}' used on event at line {context.Tokenizer.CurrentLine}.");
|
||||
|
||||
// Read name
|
||||
desc.Name = ParseName(ref context);
|
||||
|
||||
@@ -541,7 +541,7 @@ namespace Flax.Build.Bindings
|
||||
private static bool UseBindings(object type)
|
||||
{
|
||||
var apiTypeInfo = type as ApiTypeInfo;
|
||||
if (apiTypeInfo != null && apiTypeInfo.IsInBuild)
|
||||
if (apiTypeInfo != null && apiTypeInfo.SkipGeneration)
|
||||
return false;
|
||||
if ((type is ModuleInfo || type is FileInfo) && apiTypeInfo != null)
|
||||
{
|
||||
|
||||
@@ -13,11 +13,14 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
public AccessLevel Access;
|
||||
public AccessLevel BaseTypeInheritance;
|
||||
public bool IsTemplate;
|
||||
public ClassStructInfo BaseType;
|
||||
public List<InterfaceInfo> Interfaces;
|
||||
public List<TypeInfo> Inheritance; // Data from parsing, used to interfaces and base type construct in Init
|
||||
public List<FunctionInfo> Functions = new List<FunctionInfo>();
|
||||
|
||||
public override bool SkipGeneration => IsInBuild || IsTemplate;
|
||||
|
||||
public override void Init(Builder.BuildData buildData)
|
||||
{
|
||||
base.Init(buildData);
|
||||
@@ -51,6 +54,7 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
writer.Write((byte)Access);
|
||||
writer.Write((byte)BaseTypeInheritance);
|
||||
writer.Write(IsTemplate);
|
||||
BindingsGenerator.Write(writer, BaseType);
|
||||
BindingsGenerator.Write(writer, Inheritance);
|
||||
BindingsGenerator.Write(writer, Functions);
|
||||
@@ -62,6 +66,7 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
Access = (AccessLevel)reader.ReadByte();
|
||||
BaseTypeInheritance = (AccessLevel)reader.ReadByte();
|
||||
IsTemplate = reader.ReadBoolean();
|
||||
BaseType = BindingsGenerator.Read(reader, BaseType);
|
||||
Inheritance = BindingsGenerator.Read(reader, Inheritance);
|
||||
Functions = BindingsGenerator.Read(reader, Functions);
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
base.Init(buildData);
|
||||
|
||||
if (ForceNoPod || (Interfaces != null && Interfaces.Count != 0))
|
||||
if (ForceNoPod || (Interfaces != null && Interfaces.Count != 0) || IsTemplate)
|
||||
{
|
||||
_isPod = false;
|
||||
return;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Flax.Build.Platforms
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool HasSharedLibrarySupport => true;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool HasExecutableFileReferenceSupport => true;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user