示例#1
0
        CompilationUnitSyntax Generate(CompilationUnitSyntax code, WaylandProtocol protocol)
        {
            code = code.AddUsings(UsingDirective(IdentifierName("System")))
                   .AddUsings(UsingDirective(IdentifierName("System.Collections.Generic")))
                   .AddUsings(UsingDirective(IdentifierName("System.Linq")))
                   .AddUsings(UsingDirective(IdentifierName("System.Text")))
                   .AddUsings(UsingDirective(IdentifierName("NWayland.Protocols.Wayland")))
                   .AddUsings(UsingDirective(IdentifierName("NWayland.Interop")))
                   .AddUsings(UsingDirective(IdentifierName("System.Threading.Tasks")));


            var ns = NamespaceDeclaration(ProtocolNamespaceSyntax(protocol.Name));

            foreach (var iface in protocol.Interfaces)
            {
                var cl = ClassDeclaration(Pascalize(iface.Name))
                         .WithModifiers(new SyntaxTokenList(
                                            Token(SyntaxKind.PublicKeyword),
                                            Token(SyntaxKind.SealedKeyword),
                                            Token(SyntaxKind.UnsafeKeyword),
                                            Token(SyntaxKind.PartialKeyword)))
                         .AddBaseListTypes(
                    SimpleBaseType(SyntaxFactory.ParseTypeName("NWayland.Protocols.Wayland.WlProxy")));
                cl = WithSummary(cl, iface.Description);
                cl = WithSignature(cl, iface);
                cl = WithRequests(cl, protocol, iface);
                cl = WithEvents(cl, protocol, iface);
                cl = WithEnums(cl, protocol, iface);
                cl = WithFactory(cl, iface)
                     .AddMembers(DeclareConstant("string", "InterfaceName", MakeLiteralExpression(iface.Name)))
                     .AddMembers(DeclareConstant("int", "InterfaceVersion", MakeLiteralExpression(iface.Version)));


                if (iface.Name != "wl_display")
                {
                    var ctor = ConstructorDeclaration(cl.Identifier)
                               .AddModifiers(Token(SyntaxKind.PublicKeyword))
                               .WithParameterList(ParameterList(
                                                      SeparatedList(new[]
                    {
                        Parameter(Identifier("handle")).WithType(ParseTypeName("IntPtr")),
                        Parameter(Identifier("version")).WithType(ParseTypeName("int")),
                        Parameter(Identifier("display"))
                        .WithType(ParseTypeName("NWayland.Protocols.Wayland.WlDisplay")),
                    }))).WithBody(Block())
                               .WithInitializer(ConstructorInitializer(SyntaxKind.BaseConstructorInitializer,
                                                                       ArgumentList(SeparatedList(new[]
                    {
                        Argument(IdentifierName("handle")),
                        Argument(IdentifierName("version")),
                        Argument(IdentifierName("display"))
                    }))));
                    cl = cl.AddMembers(ctor);
                }

                ns = ns.AddMembers(cl);
            }

            return(code.AddMembers(ns));
        }
示例#2
0
        ClassDeclarationSyntax WithEnums(ClassDeclarationSyntax cl,
                                         WaylandProtocol protocol,
                                         WaylandProtocolInterface iface)
        {
            if (iface.Enums == null)
            {
                return(cl);
            }
            foreach (var en in iface.Enums)
            {
                cl = cl.AddMembers(CreateEnum(en));
            }

            return(cl);
        }
示例#3
0
        public string Generate(WaylandProtocol protocol)
        {
            var unit = CompilationUnit();

            unit = Generate(unit, protocol);
            var cw        = new AdhocWorkspace();
            var formatted = Microsoft.CodeAnalysis.Formatting.Formatter.Format(unit, cw, cw.Options
                                                                               .WithChangedOption(CSharpFormattingOptions.NewLineForMembersInObjectInit, true)
                                                                               .WithChangedOption(CSharpFormattingOptions.NewLinesForBracesInObjectCollectionArrayInitializers, true)
                                                                               .WithChangedOption(CSharpFormattingOptions.NewLineForMembersInAnonymousTypes, true)
                                                                               .WithChangedOption(CSharpFormattingOptions.NewLinesForBracesInMethods, true)

                                                                               );

            return(formatted.ToFullString());
        }
示例#4
0
        ClassDeclarationSyntax WithRequests(ClassDeclarationSyntax cl,
                                            WaylandProtocol protocol,
                                            WaylandProtocolInterface iface)
        {
            if (iface.Requests == null)
            {
                return(cl);
            }
            for (var idx = 0; idx < iface.Requests.Length; idx++)
            {
                var method = CreateMethod(protocol, iface, iface.Requests[idx], idx);
                if (method != null)
                {
                    cl = cl.AddMembers(method);
                }
            }

            return(cl);
        }
示例#5
0
        ClassDeclarationSyntax WithEvents(ClassDeclarationSyntax cl,
                                          WaylandProtocol protocol,
                                          WaylandProtocolInterface iface)
        {
            var evs            = iface.Events ?? Array.Empty <WaylandProtocolMessage>();
            var eventInterface = InterfaceDeclaration("IEvents")
                                 .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword)));

            var dispatcherBody = Block();

            for (var eventIndex = 0; eventIndex < evs.Length; eventIndex++)
            {
                var ev        = evs[eventIndex];
                var eventName = "On" + Pascalize(ev.Name);


                var handlerParameters = new SeparatedSyntaxList <ParameterSyntax>();
                var arguments         = new SeparatedSyntaxList <ArgumentSyntax>();
                handlerParameters = handlerParameters.Add(Parameter(Identifier("eventSender"))
                                                          .WithType(ParseTypeName(GetWlInterfaceTypeName(iface.Name))));
                arguments = arguments.Add(Argument(IdentifierName("this")));

                var eargs = ev.Arguments ?? Array.Empty <WaylandProtocolArgument>();
                for (var argIndex = 0; argIndex < eargs.Length; argIndex++)
                {
                    var        arg           = eargs[argIndex];
                    TypeSyntax parameterType = null;

                    ExpressionSyntax argument = ElementAccessExpression(IdentifierName("arguments"),
                                                                        BracketedArgumentList(SingletonSeparatedList(Argument(MakeLiteralExpression(argIndex)))));

                    var argName = "@" + Pascalize(arg.Name, true);
                    if (arg.Type == WaylandArgumentTypes.Int32 ||
                        arg.Type == WaylandArgumentTypes.Fixed ||
                        arg.Type == WaylandArgumentTypes.FileDescriptor ||
                        arg.Type == WaylandArgumentTypes.Uint32)
                    {
                        var nativeType = arg.Type == WaylandArgumentTypes.Uint32 ? "uint" : "int";

                        var managedType =
                            TryGetEnumTypeReference(protocol.Name, iface.Name, ev.Name, arg.Name, arg.Enum) ??
                            nativeType;

                        parameterType = ParseTypeName(managedType);
                        argument      = MemberAccess(argument,
                                                     arg.Type == WaylandArgumentTypes.Uint32 ? "UInt32" : "Int32");

                        if (managedType != nativeType)
                        {
                            argument = CastExpression(ParseTypeName(managedType), argument);
                        }
                    }
                    else if (arg.Type == WaylandArgumentTypes.NewId)
                    {
                        parameterType = ParseTypeName(Pascalize(arg.Interface));
                        argument      = ObjectCreationExpression(parameterType)
                                        .WithArgumentList(
                            ArgumentList(SeparatedList(new[]
                        {
                            Argument(MemberAccess(argument, "IntPtr")),
                            Argument(IdentifierName("Version")),
                            Argument(IdentifierName("Display"))
                        }
                                                       )));
                    }
                    else if (arg.Type == WaylandArgumentTypes.String)
                    {
                        parameterType = ParseTypeName("System.String");

                        argument = InvocationExpression(
                            MemberAccess(ParseTypeName("System.Runtime.InteropServices.Marshal"), "PtrToStringAnsi"),
                            ArgumentList(SingletonSeparatedList(Argument(MemberAccess(argument, "IntPtr")))));
                    }
                    else if (arg.Type == WaylandArgumentTypes.Object)
                    {
                        var parameterTypeString = arg.Interface == null
                            ? "WlProxy"
                            : GetWlInterfaceTypeName(arg.Interface);
                        parameterType = ParseTypeName(parameterTypeString);
                        argument      = InvocationExpression(MemberAccess(ParseTypeName("WlProxy"),
                                                                          "FromNative<" + parameterTypeString + ">"),
                                                             ArgumentList(SingletonSeparatedList(Argument(MemberAccess(argument, "IntPtr")))));
                    }
                    else if (arg.Type == WaylandArgumentTypes.Array)
                    {
                        var arrayElementType = _hints.GetTypeNameForArray(protocol.Name, iface.Name, ev.Name, arg.Name);
                        if (arg.AllowNull)
                        {
                            throw new NotSupportedException(
                                      "Wrapping nullable arrays is currently not supported");
                        }

                        parameterType = ParseTypeName("ReadOnlySpan<" + arrayElementType + ">");
                        argument      = InvocationExpression(
                            MemberAccess(ParseTypeName("NWayland.Interop.WlArray"),
                                         "SpanFromWlArrayPtr<" + arrayElementType + ">"),
                            ArgumentList(SingletonSeparatedList(Argument(MemberAccess(argument, "IntPtr")))));
                    }
                    handlerParameters = handlerParameters.Add(Parameter(Identifier(argName)).WithType(parameterType));
                    arguments         = arguments.Add(Argument(argument));
                }

                eventInterface = eventInterface.AddMembers(
                    MethodDeclaration(ParseTypeName("void"), eventName)
                    .WithParameterList(ParameterList(handlerParameters))
                    .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));


                dispatcherBody = dispatcherBody.AddStatements(
                    IfStatement(BinaryExpression(
                                    SyntaxKind.EqualsExpression, IdentifierName("opcode"), MakeLiteralExpression(eventIndex)),

                                ExpressionStatement(ConditionalAccessExpression(IdentifierName("Events"),
                                                                                InvocationExpression(MemberBindingExpression(IdentifierName(eventName)))
                                                                                .WithArgumentList(ArgumentList(arguments))))
                                ));
            }

            cl = cl.AddMembers(eventInterface);
            cl = cl.AddMembers(PropertyDeclaration(ParseTypeName("IEvents"), "Events")
                               .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword)))
                               .WithAccessorList(AccessorList(List(new[]
            {
                AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
                .WithSemicolonToken(Semicolon()),
                AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
                .WithSemicolonToken(Semicolon())
            })))
                               );

            cl = cl.AddMembers(MethodDeclaration(ParseTypeName("void"), "DispatchEvent")
                               .WithModifiers(TokenList(Token(SyntaxKind.ProtectedKeyword), Token(SyntaxKind.OverrideKeyword)))
                               .WithParameterList(ParameterList(SeparatedList(new[]
            {
                Parameter(Identifier("opcode")).WithType(ParseTypeName("uint")),
                Parameter(Identifier("arguments")).WithType(ParseTypeName("WlArgument*"))
            }
                                                                              )))
                               .WithBody(dispatcherBody)
                               );

            return(cl);
        }
示例#6
0
        MethodDeclarationSyntax CreateMethod(WaylandProtocol protocol, WaylandProtocolInterface iface,
                                             WaylandProtocolRequest request, int index)
        {
            var newIdArgument = request.Arguments?.FirstOrDefault(a => a.Type == WaylandArgumentTypes.NewId);

            if (newIdArgument != null && newIdArgument.Interface == null)
            {
                return(null);
            }
            var ctorType       = newIdArgument?.Interface;
            var dotNetCtorType = ctorType == null ? "void" : GetWlInterfaceTypeName(ctorType);

            var method = MethodDeclaration(
                ParseTypeName(dotNetCtorType), Pascalize(request.Name));

            var plist             = new SeparatedSyntaxList <ParameterSyntax>();
            var arglist           = new SeparatedSyntaxList <ExpressionSyntax>();
            var statements        = new SeparatedSyntaxList <StatementSyntax>();
            var callStatements    = new SeparatedSyntaxList <StatementSyntax>();
            var fixedDeclarations = new List <VariableDeclarationSyntax>();

            if (request.Since > 0)
            {
                statements = statements.Add(IfStatement(
                                                BinaryExpression(SyntaxKind.LessThanExpression,
                                                                 IdentifierName("Version"), MakeLiteralExpression(request.Since))
                                                ,
                                                request.Type == "destructor"
                        ? (StatementSyntax)ReturnStatement()
                        : ThrowStatement(ObjectCreationExpression(ParseTypeName("System.InvalidOperationException"))
                                         .WithArgumentList(
                                             ArgumentList(SingletonSeparatedList(Argument(MakeLiteralExpression(
                                                                                              $"Request {request.Name} is only supported since version {request.Since}"))))))));
            }

            if (request.Arguments != null)
            {
                foreach (var arg in request.Arguments ?? Array.Empty <WaylandProtocolArgument>())
                {
                    TypeSyntax parameterType = null;
                    var        nullCheck     = false;
                    var        argName       = "@" + Pascalize(arg.Name, true);

                    if (arg.Type == WaylandArgumentTypes.Int32 ||
                        arg.Type == WaylandArgumentTypes.Fixed ||
                        arg.Type == WaylandArgumentTypes.FileDescriptor ||
                        arg.Type == WaylandArgumentTypes.Uint32)
                    {
                        var nativeType = arg.Type == WaylandArgumentTypes.Uint32 ? "uint" : "int";

                        var managedType =
                            TryGetEnumTypeReference(protocol.Name, iface.Name, request.Name, arg.Name, arg.Enum) ??
                            nativeType;

                        parameterType = ParseTypeName(managedType);
                        if (nativeType != managedType)
                        {
                            arglist = arglist.Add(CastExpression(ParseTypeName(nativeType), IdentifierName(argName)));
                        }
                        else
                        {
                            arglist = arglist.Add(IdentifierName(argName));
                        }
                    }
                    else if (arg.Type == WaylandArgumentTypes.NewId)
                    {
                        arglist = arglist.Add(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                                     IdentifierName("WlArgument"), IdentifierName("NewId")));
                    }
                    else if (arg.Type == WaylandArgumentTypes.String)
                    {
                        nullCheck     = true;
                        parameterType = ParseTypeName("System.String");
                        var tempName   = "__marshalled__" + argName.TrimStart('@');
                        var bufferType = ParseTypeName("NWayland.Interop.NWaylandMarshalledString");

                        statements = statements.Add(LocalDeclarationStatement(
                                                        new SyntaxTokenList(Token(SyntaxKind.UsingKeyword)),
                                                        VariableDeclaration(ParseTypeName("var"))
                                                        .WithVariables(SingletonSeparatedList(
                                                                           VariableDeclarator(tempName)
                                                                           .WithInitializer(EqualsValueClause(ObjectCreationExpression(bufferType)
                                                                                                              .WithArgumentList(
                                                                                                                  ArgumentList(
                                                                                                                      SingletonSeparatedList(Argument(IdentifierName(argName)))))))
                                                                           ))));
                        arglist = arglist.Add(IdentifierName(tempName));
                    }
                    else if (arg.Type == WaylandArgumentTypes.Object)
                    {
                        nullCheck     = true;
                        parameterType = ParseTypeName(GetWlInterfaceTypeName(arg.Interface));
                        arglist       = arglist.Add(IdentifierName(argName));
                    }
                    else if (arg.Type == WaylandArgumentTypes.Array)
                    {
                        if (arg.AllowNull)
                        {
                            throw new NotSupportedException(
                                      "Wrapping nullable arrays is currently not supported");
                        }
                        var arrayElementType = _hints.GetTypeNameForArray(protocol.Name, iface.Name, request.Name, arg.Name);
                        parameterType = ParseTypeName("ReadOnlySpan<" + arrayElementType + ">");
                        var pointerName = "__pointer__" + argName.TrimStart('@');
                        var tempName    = "__marshalled__" + argName.TrimStart('@');
                        fixedDeclarations.Add(VariableDeclaration(ParseTypeName(arrayElementType + "*"),
                                                                  SingletonSeparatedList(VariableDeclarator(pointerName)
                                                                                         .WithInitializer(EqualsValueClause(IdentifierName(argName))))));

                        callStatements = callStatements.Add(LocalDeclarationStatement(VariableDeclaration(ParseTypeName("var"))
                                                                                      .WithVariables(SingletonSeparatedList(VariableDeclarator(tempName)
                                                                                                                            .WithInitializer(EqualsValueClause(
                                                                                                                                                 InvocationExpression(MemberAccess(ParseTypeName("NWayland.Interop.WlArray"),
                                                                                                                                                                                   "FromPointer"), ArgumentList(SeparatedList(new[]
                        {
                            Argument(IdentifierName(pointerName)),
                            Argument(MemberAccess(IdentifierName(argName), "Length"))
                        }
                                                                                                                                                                                                                              ))))

                                                                                                                                             )))));

                        arglist = arglist.Add(PrefixUnaryExpression(SyntaxKind.AddressOfExpression,
                                                                    IdentifierName(tempName)));
                    }

                    if (parameterType != null)
                    {
                        plist = plist.Add(Parameter(Identifier(argName)).WithType(parameterType));
                    }

                    if (nullCheck)
                    {
                        statements = statements.Insert(0, IfStatement(
                                                           BinaryExpression(SyntaxKind.EqualsExpression, IdentifierName(argName),
                                                                            MakeNullLiteralExpression()),
                                                           ThrowStatement(ObjectCreationExpression(ParseTypeName("System.ArgumentNullException"))
                                                                          .WithArgumentList(
                                                                              ArgumentList(
                                                                                  SingletonSeparatedList(
                                                                                      Argument(MakeLiteralExpression(argName.TrimStart('@')))))))));
                    }
                }
            }

            callStatements = callStatements.Add(LocalDeclarationStatement(VariableDeclaration(ParseTypeName("WlArgument*"))
                                                                          .WithVariables(SingletonSeparatedList(VariableDeclarator("__args")
                                                                                                                .WithInitializer(EqualsValueClause(StackAllocArrayCreationExpression(
                                                                                                                                                       ArrayType(ParseTypeName("WlArgument[]")),
                                                                                                                                                       InitializerExpression(SyntaxKind.ArrayInitializerExpression, arglist))))))));

            var marshalArgs = SeparatedList(new[]
            {
                Argument(MemberAccess(IdentifierName("this"), "Handle")),
                Argument(MakeLiteralExpression(index)),
                Argument(IdentifierName("__args"))
            });

            if (ctorType != null)
            {
                marshalArgs = marshalArgs.Add(Argument(GetWlInterfaceRefFor(ctorType)));
            }

            var callExpr = InvocationExpression(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                                       IdentifierName("LibWayland"),
                                                                       IdentifierName(ctorType == null
                        ? "wl_proxy_marshal_array"
                        : "wl_proxy_marshal_array_constructor")),
                                                ArgumentList(marshalArgs));



            if (ctorType == null)
            {
                callStatements = callStatements.Add(ExpressionStatement(callExpr));
            }
            else
            {
                callStatements = callStatements.Add(LocalDeclarationStatement(VariableDeclaration(ParseTypeName("var"))
                                                                              .WithVariables(SingletonSeparatedList(
                                                                                                 VariableDeclarator("__ret").WithInitializer(EqualsValueClause(callExpr))))));
                callStatements = callStatements.Add(ReturnStatement(ConditionalExpression(BinaryExpression(
                                                                                              SyntaxKind.EqualsExpression, IdentifierName("__ret"),
                                                                                              MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName("IntPtr"),
                                                                                                                     IdentifierName("Zero"))),
                                                                                          MakeNullLiteralExpression(),
                                                                                          ObjectCreationExpression(ParseTypeName(dotNetCtorType)).WithArgumentList(
                                                                                              ArgumentList(SeparatedList(new[]
                {
                    Argument(IdentifierName("__ret")),
                    Argument(IdentifierName("Version")),
                    Argument(IdentifierName("Display"))
                }))))));
            }

            if (fixedDeclarations.Count == 0)
            {
                statements = statements.AddRange(callStatements);
            }
            else
            {
                var callBlock = (StatementSyntax)Block(callStatements);
                fixedDeclarations.Reverse();
                foreach (var fd in fixedDeclarations)
                {
                    callBlock = FixedStatement(fd, callBlock);
                }
                statements = statements.Add(callBlock);
            }

            method = WithSummary(method.WithParameterList(ParameterList(plist))
                                 .WithBody(Block(statements))
                                 .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))),
                                 request.Description);

            if (request.Type == "destructor")
            {
                method = method
                         .WithIdentifier(Identifier("CallWaylandDestructor"))
                         .WithModifiers(TokenList(
                                            Token(SyntaxKind.ProtectedKeyword),
                                            Token(SyntaxKind.SealedKeyword),
                                            Token(SyntaxKind.OverrideKeyword)
                                            ));
            }


            return(method);
        }