public IEnumerable <MemberDeclarationSyntax> GenerateCode(CsFunction csElement) { foreach (var member in Generators.Callable.GenerateCode(csElement)) { yield return(member); } foreach (var sig in csElement.InteropSignatures) { yield return(MethodDeclaration(ParseTypeName(sig.Value.ReturnType.TypeName), $"{csElement.CppElementName}{GeneratorHelpers.GetPlatformSpecificSuffix(sig.Key)}") .WithModifiers( TokenList( Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.UnsafeKeyword), Token(SyntaxKind.StaticKeyword), Token(SyntaxKind.ExternKeyword))) .WithAttributeLists(SingletonList(AttributeList(SingletonSeparatedList( Attribute( QualifiedName( QualifiedName( QualifiedName( IdentifierName("System"), IdentifierName("Runtime")), IdentifierName("InteropServices")), IdentifierName("DllImportAttribute"))) .WithArgumentList( AttributeArgumentList( SeparatedList( new[] { AttributeArgument( IdentifierName(csElement.DllName)), AttributeArgument( LiteralExpression( SyntaxKind.StringLiteralExpression, Literal(csElement.CppElementName))) .WithNameEquals( NameEquals( IdentifierName("EntryPoint"))), AttributeArgument( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName("System"), IdentifierName("Runtime")), IdentifierName("InteropServices")), IdentifierName("CallingConvention")), IdentifierName(csElement.CppCallingConvention.ToManagedCallingConventionName()))) .WithNameEquals( NameEquals( IdentifierName("CallingConvention"))) }))))))) .WithParameterList(ParameterList(SeparatedList( sig.Value.ParameterTypes.Select(param => Parameter(Identifier(param.Name)) .WithType(param.InteropTypeSyntax))))) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))); } }
private DelegateDeclarationSyntax GenerateDelegateDeclaration(CsCallable csElement, PlatformDetectionType platform, InteropMethodSignature sig) { return(DelegateDeclaration(ParseTypeName(sig.ReturnType.TypeName), $"{csElement.Name}Delegate{GeneratorHelpers.GetPlatformSpecificSuffix(platform)}") .AddAttributeLists( AttributeList( SingletonSeparatedList( Attribute( ParseName("System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute")) .AddArgumentListArguments( AttributeArgument( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName("System"), IdentifierName("Runtime")), IdentifierName("InteropServices")), IdentifierName("CallingConvention")), IdentifierName(sig.CallingConvention))))))) .WithParameterList( ParameterList( (csElement is CsMethod ? SingletonSeparatedList( Parameter(Identifier("thisObject")) .WithType(ParseTypeName("System.IntPtr"))) : default)
public MemberDeclarationSyntax GenerateCode(CsInterface csElement) { var vtblClassName = csElement.VtblName.Split('.').Last(); return(ClassDeclaration(vtblClassName) .WithModifiers( TokenList( Token(SyntaxKind.ProtectedKeyword), Token(SyntaxKind.UnsafeKeyword))) .WithBaseList( BaseList( SingletonSeparatedList <BaseTypeSyntax>( SimpleBaseType( csElement.Base != null ? (NameSyntax)IdentifierName(csElement.Base.VtblName) : globalNamespace.GetTypeNameSyntax(WellKnownName.CppObjectVtbl))))) .WithMembers( List( new MemberDeclarationSyntax[] { ConstructorDeclaration( Identifier(vtblClassName)) .WithModifiers( TokenList( Token(SyntaxKind.PublicKeyword))) .WithParameterList( ParameterList( SingletonSeparatedList( Parameter( Identifier("numberOfCallbackMethods")) .WithType( PredefinedType( Token(SyntaxKind.IntKeyword)))))) .WithInitializer( ConstructorInitializer( SyntaxKind.BaseConstructorInitializer, ArgumentList( SingletonSeparatedList( Argument( BinaryExpression( SyntaxKind.AddExpression, IdentifierName("numberOfCallbackMethods"), LiteralExpression( SyntaxKind.NumericLiteralExpression, Literal(csElement.Methods.Count())))))))) .WithBody( Block(csElement.Methods .OrderBy(method => method.Offset) .Select(method => GeneratorHelpers.GetPlatformSpecificStatements(globalNamespace, generators.Config, method.InteropSignatures.Keys, platform => ExpressionStatement( InvocationExpression( IdentifierName("AddMethod")) .WithArgumentList( ArgumentList( SeparatedList( new [] { Argument( ObjectCreationExpression( IdentifierName($"{method.Name}Delegate{GeneratorHelpers.GetPlatformSpecificSuffix(platform)}")) .WithArgumentList( ArgumentList( SingletonSeparatedList( Argument( IdentifierName($"{method.Name}{GeneratorHelpers.GetPlatformSpecificSuffix(platform)}")))))), Argument( LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal((platform & PlatformDetectionType.IsWindows) != 0 ? method.WindowsOffset : method.Offset))) } )))))))) } .Concat(csElement.Methods .SelectMany(method => generators.ShadowCallable.GenerateCode(method)))))); }
public ExpressionSyntax GenerateCall(CsCallable callable, PlatformDetectionType platform, InteropMethodSignature interopSig) { var arguments = IterateNativeArguments(callable, interopSig).ToArray(); ElementAccessExpressionSyntax vtblAccess = null; if (callable is CsMethod method) { var windowsOffsetExpression = LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(method.WindowsOffset)); var nonWindowsOffsetExpression = LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(method.Offset)); ExpressionSyntax vtableOffsetExpression; if ((platform & PlatformDetectionType.Any) == PlatformDetectionType.Any && method.Offset != method.WindowsOffset) { vtableOffsetExpression = ConditionalExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, GlobalNamespace.GetTypeNameSyntax(WellKnownName.PlatformDetection), IdentifierName("Is" + nameof(PlatformDetectionType.Windows))), windowsOffsetExpression, nonWindowsOffsetExpression); } else if ((platform & PlatformDetectionType.Windows) != 0) { vtableOffsetExpression = windowsOffsetExpression; } else { vtableOffsetExpression = nonWindowsOffsetExpression; } vtblAccess = ElementAccessExpression( ThisExpression(), BracketedArgumentList( SingletonSeparatedList( Argument( method.CustomVtbl ? MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName($"{callable.Name}__vtbl_index") ) : vtableOffsetExpression ) ) ) ); } ExpressionSyntax FnPtrCall() { var fnptrParameters = arguments .Select(x => x.Type) .Append(ParseTypeName(interopSig.ReturnType.TypeName)) .Select(FunctionPointerParameter); return(GeneratorHelpers.CastExpression( FunctionPointerType( FunctionPointerCallingConvention( Token(SyntaxKind.UnmanagedKeyword), FunctionPointerUnmanagedCallingConventionList( SingletonSeparatedList( FunctionPointerUnmanagedCallingConvention( Identifier(callable.CppCallingConvention.ToCallConvShortName()) ) ) ) ), FunctionPointerParameterList(SeparatedList(fnptrParameters)) ), vtblAccess )); } var what = callable switch { CsFunction => IdentifierName( callable.CppElementName + GeneratorHelpers.GetPlatformSpecificSuffix(platform) ), CsMethod => GeneratorHelpers.WrapInParentheses(FnPtrCall()), _ => throw new ArgumentOutOfRangeException() }; ExpressionSyntax call = InvocationExpression( what, ArgumentList(SeparatedList(arguments.Select(x => x.Argument))) ); if (interopSig.CastToNativeLong) { call = CastExpression(GlobalNamespace.GetTypeNameSyntax(WellKnownName.NativeLong), call); } if (interopSig.CastToNativeULong) { call = CastExpression(GlobalNamespace.GetTypeNameSyntax(WellKnownName.NativeULong), call); } if (interopSig.ForcedReturnBufferSig || !callable.HasReturnType) { return(call); } return(AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, GetMarshaller(callable.ReturnValue).GeneratesMarshalVariable(callable.ReturnValue) ? MarshallerBase.GetMarshalStorageLocation(callable.ReturnValue) : IdentifierName(callable.ReturnValue.Name), call )); }
public MemberDeclarationSyntax GenerateCode(CsInterface csElement) { var vtblClassName = csElement.VtblName.Split('.').Last(); // Default: at least protected to enable inheritance. var vtblVisibility = csElement.VtblVisibility ?? Visibility.ProtectedInternal; StatementSyntax VtblMethodSelector(CsMethod method) { StatementSyntax MethodBuilder(PlatformDetectionType platform) { var arguments = new[] { Argument( ObjectCreationExpression(IdentifierName(GetMethodDelegateName(method, platform))) .WithArgumentList( ArgumentList( SingletonSeparatedList( Argument( IdentifierName( $"{method.Name}{GeneratorHelpers.GetPlatformSpecificSuffix(platform)}" ) ) ) ) ) ), Argument( LiteralExpression( SyntaxKind.NumericLiteralExpression, Literal((platform & PlatformDetectionType.Windows) != 0 ? method.WindowsOffset : method.Offset) ) ) }; return(ExpressionStatement( InvocationExpression(IdentifierName("AddMethod")) .WithArgumentList(ArgumentList(SeparatedList(arguments))) )); } return(GeneratorHelpers.GetPlatformSpecificStatements(GlobalNamespace, Generators.Config, method.InteropSignatures.Keys, MethodBuilder)); } List <MemberDeclarationSyntax> members = new() { ConstructorDeclaration(Identifier(vtblClassName)) .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) .WithParameterList( ParameterList( SingletonSeparatedList( Parameter(Identifier("numberOfCallbackMethods")) .WithType(PredefinedType(Token(SyntaxKind.IntKeyword))) ) ) ) .WithInitializer( ConstructorInitializer( SyntaxKind.BaseConstructorInitializer, ArgumentList( SingletonSeparatedList( Argument( BinaryExpression( SyntaxKind.AddExpression, IdentifierName("numberOfCallbackMethods"), LiteralExpression( SyntaxKind.NumericLiteralExpression, Literal(csElement.MethodList.Count) ) ) ) ) ) ) ) .WithBody( Block( csElement.Methods .OrderBy(method => method.Offset) .Select(VtblMethodSelector) ) ) }; members.AddRange(csElement.Methods.SelectMany(method => Generators.ShadowCallable.GenerateCode(method))); return(ClassDeclaration(vtblClassName) .WithModifiers( ModelUtilities.VisibilityToTokenList(vtblVisibility, SyntaxKind.UnsafeKeyword, SyntaxKind.PartialKeyword) ) .WithAttributeLists(DebuggerTypeProxyAttribute) .WithBaseList( BaseList( SingletonSeparatedList <BaseTypeSyntax>( SimpleBaseType( csElement.Base != null ? IdentifierName(csElement.Base.VtblName) : GlobalNamespace.GetTypeNameSyntax(WellKnownName.CppObjectVtbl) ) ) ) ) .WithMembers(List(members))); }
internal static string GetMethodDelegateName(CsCallable csElement, PlatformDetectionType platform) => csElement.Name + "Delegate" + GeneratorHelpers.GetPlatformSpecificSuffix(platform);