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 override IEnumerable <MemberDeclarationSyntax> GenerateCode(CsCallable csElement) { // Documentation var documentationTrivia = GenerateDocumentationTrivia(csElement); // method signature var parameters = csElement.PublicParameters.Select( param => Generators.Marshalling.GetMarshaller(param) .GenerateManagedParameter(param) .WithDefault(param.DefaultValue == null ? default : EqualsValueClause(ParseExpression(param.DefaultValue)) ) ); var methodDeclaration = MethodDeclaration( ParseTypeName(csElement.GetPublicReturnTypeQualifiedName(globalNamespace)), csElement.Name ) .WithModifiers(csElement.VisibilityTokenList.Add(Token(SyntaxKind.UnsafeKeyword))) .WithParameterList(ParameterList(SeparatedList(parameters))) .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.SingleOrDefault(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.GenerateCall( 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.IsReturnTypeResult(globalNamespace) && csElement.CheckReturnType) { statements.Add(ExpressionStatement( InvocationExpression( MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName(csElement.ReturnValue.Name), IdentifierName("CheckError"))))); } // Return if (csElement.HasReturnStatement(globalNamespace)) { statements.Add(ReturnStatement(IdentifierName(csElement.ReturnName))); } yield return(methodDeclaration.WithBody(Block(statements))); }
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))); }