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);
public override IEnumerable <MemberDeclarationSyntax> GenerateCode(CsField csElement) { if (csElement.IsBoolToInt && !csElement.IsArray) { yield return(GenerateBackingField(csElement, csElement.MarshalType)); yield return(GenerateProperty( csElement, PredefinedType(Token(SyntaxKind.BoolKeyword)), GeneratorHelpers.GenerateIntToBoolConversion, (_, value) => GeneratorHelpers.CastExpression( ParseTypeName(csElement.MarshalType.QualifiedName), GeneratorHelpers.GenerateBoolToIntConversion(value) ) )); } else if (csElement.IsArray && !csElement.IsString) { var elementType = ParseTypeName(csElement.PublicType.QualifiedName); yield return(GenerateBackingField(csElement, csElement.PublicType, isArray: true)); yield return(GenerateProperty( csElement, ArrayType(elementType, SingletonList(ArrayRankSpecifier())), value => AssignmentExpression( SyntaxKind.CoalesceAssignmentExpression, value, ObjectCreationExpression( ArrayType( elementType, SingletonList( ArrayRankSpecifier( SingletonSeparatedList <ExpressionSyntax>( LiteralExpression( SyntaxKind.NumericLiteralExpression, Literal(csElement.ArrayDimensionValue) ) ) ) ) ) ) ), null )); } else if (csElement.IsBitField) { PropertyValueGetTransform getterTransform; PropertyValueSetTransform setterTransform; TypeSyntax propertyType; if (csElement.IsBoolBitField) { getterTransform = GeneratorHelpers.GenerateIntToBoolConversion; setterTransform = (_, value) => GeneratorHelpers.GenerateBoolToIntConversion(value); propertyType = PredefinedType(Token(SyntaxKind.BoolKeyword)); } else { getterTransform = valueExpression => GeneratorHelpers.CastExpression( ParseTypeName(csElement.PublicType.QualifiedName), valueExpression ); setterTransform = null; propertyType = ParseTypeName(csElement.PublicType.QualifiedName); } yield return(GenerateBackingField(csElement, csElement.PublicType)); var bitMask = LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(csElement.BitMask)); var bitOffset = LiteralExpression( SyntaxKind.NumericLiteralExpression, Literal(csElement.BitOffset) ); yield return(GenerateProperty( csElement, propertyType, Compose( getterTransform, value => BinaryExpression( SyntaxKind.BitwiseAndExpression, GeneratorHelpers.WrapInParentheses( BinaryExpression(SyntaxKind.RightShiftExpression, value, bitOffset) ), bitMask ) ), Compose( (oldValue, value) => GeneratorHelpers.CastExpression( ParseTypeName(csElement.PublicType.QualifiedName), BinaryExpression( SyntaxKind.BitwiseOrExpression, GeneratorHelpers.WrapInParentheses( BinaryExpression( SyntaxKind.BitwiseAndExpression, oldValue, PrefixUnaryExpression( SyntaxKind.BitwiseNotExpression, GeneratorHelpers.WrapInParentheses( BinaryExpression(SyntaxKind.LeftShiftExpression, bitMask, bitOffset) ) ) ) ), GeneratorHelpers.WrapInParentheses( BinaryExpression( SyntaxKind.LeftShiftExpression, GeneratorHelpers.WrapInParentheses( BinaryExpression(SyntaxKind.BitwiseAndExpression, value, bitMask) ), bitOffset ) ) ) ), setterTransform ) )); } else { yield return(GenerateBackingField( csElement, csElement.PublicType, propertyBacking: false, document: true )); } }
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.CallingConvention))) .WithNameEquals( NameEquals( IdentifierName("CallingConvention"))) }))))))) .WithParameterList(ParameterList(SeparatedList( sig.Value.ParameterTypes.Select((param, i) => Parameter(Identifier($"param{i}")) .WithType(ParseTypeName(param.TypeName)))))) .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 override IEnumerable <MemberDeclarationSyntax> GenerateCode(CsCallable csElement) { // Documentation var documentationTrivia = GenerateDocumentationTrivia(csElement); // method signature var methodDeclaration = MethodDeclaration(ParseTypeName(csElement.PublicReturnTypeQualifiedName), csElement.Name) .WithModifiers(TokenList(ParseTokens(csElement.VisibilityName)).Add(Token(SyntaxKind.UnsafeKeyword))) .WithParameterList( ParameterList( SeparatedList( csElement.PublicParameters.Select(param => Generators.Marshalling.GetMarshaller(param).GenerateManagedParameter(param) .WithDefault(param.DefaultValue == null ? default : EqualsValueClause(ParseExpression(param.DefaultValue))) ) ) ) ) .WithLeadingTrivia(Trivia(documentationTrivia)); if (csElement.SignatureOnly) { yield return(methodDeclaration .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) .WithModifiers(TokenList())); yield break; } var statements = new List <StatementSyntax>(); foreach (var param in csElement.Parameters) { if ((param.Relations?.Count ?? 0) == 0) { if (param.UsedAsReturn) { statements.Add(GenerateManagedHiddenMarshallableProlog(param)); } statements.AddRange(Generators.Marshalling.GetMarshaller(param).GenerateManagedToNativeProlog(param)); } else { statements.Add(GenerateManagedHiddenMarshallableProlog(param)); foreach (var relation in param.Relations) { if (!ValidRelationInScenario(relation)) { logger.Error(LoggingCodes.InvalidRelationInScenario, $"The relation \"{relation}\" is invalid in a method/function."); continue; } var marshaller = Generators.Marshalling.GetRelationMarshaller(relation); StatementSyntax marshalToNative; var relatedMarshallableName = (relation as LengthRelation)?.Identifier; if (relatedMarshallableName is null) { marshalToNative = marshaller.GenerateManagedToNative(null, param); } else { var relatedParameter = csElement.Parameters.Find(p => p.CppElementName == relatedMarshallableName); if (relatedParameter is null) { logger.Error(LoggingCodes.InvalidRelationInScenario, $"The relation with \"{relatedMarshallableName}\" parameter is invalid in a method/function \"{csElement.Name}\"."); continue; } marshalToNative = marshaller.GenerateManagedToNative(relatedParameter, param); } if (marshalToNative != null) { statements.Add(marshalToNative); } } statements.AddRange(Generators.Marshalling.GetMarshaller(param).GenerateManagedToNativeProlog(param)); } } if (csElement.HasReturnType) { statements.Add(GenerateManagedHiddenMarshallableProlog(csElement.ReturnValue)); statements.AddRange( Generators.Marshalling.GetMarshaller(csElement.ReturnValue) .GenerateManagedToNativeProlog(csElement.ReturnValue)); } foreach (var param in csElement.Parameters) { if (param.IsIn || param.IsRefIn || param.IsRef) { var marshaller = Generators.Marshalling.GetMarshaller(param); var marshalToNative = marshaller.GenerateManagedToNative(param, true); if (marshalToNative != null) { statements.Add(marshalToNative); } } } var fixedStatements = csElement.PublicParameters .Select(param => Generators.Marshalling.GetMarshaller(param).GeneratePin(param)) .Where(stmt => stmt != null).ToList(); var callStmt = GeneratorHelpers.GetPlatformSpecificStatements( globalNamespace, Generators.Config, csElement.InteropSignatures.Keys, (platform) => ExpressionStatement( Generators.NativeInvocation.GenerateCode((csElement, platform, csElement.InteropSignatures[platform])))); var fixedStatement = fixedStatements.FirstOrDefault()?.WithStatement(callStmt); foreach (var statement in fixedStatements.Skip(1)) { fixedStatement = statement.WithStatement(fixedStatement); } statements.Add(fixedStatement ?? callStmt); foreach (var param in csElement.Parameters) { if (param.IsRef || param.IsOut) { var marshaller = Generators.Marshalling.GetMarshaller(param); var marshalFromNative = marshaller.GenerateNativeToManaged(param, true); if (marshalFromNative != null) { statements.Add(marshalFromNative); } } } if (csElement.HasReturnType) { var marshaller = Generators.Marshalling.GetMarshaller(csElement.ReturnValue); var marshalReturnType = marshaller.GenerateNativeToManaged(csElement.ReturnValue, true); if (marshalReturnType != null) { statements.Add(marshalReturnType); } } statements.AddRange(csElement.Parameters .Where(param => !param.IsOut) .Select(param => Generators.Marshalling.GetMarshaller(param).GenerateNativeCleanup(param, true)) .Where(param => param != null)); if ((csElement.ReturnValue.PublicType.Name == globalNamespace.GetTypeName(WellKnownName.Result)) && csElement.CheckReturnType) { statements.Add(ExpressionStatement( InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(csElement.ReturnValue.Name), IdentifierName("CheckError"))))); } // Return if (csElement.HasPublicReturnType) { if (csElement.HasReturnTypeParameter || csElement.ForceReturnType || !csElement.HideReturnType) { statements.Add(ReturnStatement(IdentifierName(csElement.ReturnName))); } } yield return(methodDeclaration.WithBody(Block(statements))); }