예제 #1
0
        EnumDeclarationSyntax GenerateChangedFieldsEnum(GClass cl)
        {
            var changedFieldsEnum = EnumDeclaration(Identifier(ChangedFieldsTypeName(cl)));
            int count             = 0;

            void AddValue(string name)
            {
                var value = 1ul << count;

                changedFieldsEnum = changedFieldsEnum.AddMembers(
                    EnumMemberDeclaration(name)
                    .WithEqualsValue(EqualsValueClause(ParseExpression(value.ToString()))));
                count++;
            }

            foreach (var prop in cl.Properties)
            {
                AddValue(prop.Name);

                if (prop.Animated)
                {
                    AddValue(prop.Name + "Animated");
                }
            }

            var baseType = count <= 8 ? "byte" : count <= 16 ? "ushort" : count <= 32 ? "uint" : "ulong";

            return(changedFieldsEnum.AddBaseListTypes(SimpleBaseType(ParseTypeName(baseType)))
                   .AddAttributeLists(AttributeList(SingletonSeparatedList(Attribute(IdentifierName("System.Flags"))))));
        }
예제 #2
0
     StatementSyntax GeneratePropertySetterAssignment(GClass cl, GProperty prop, bool isObject, bool isNullable)
     {
         var code = @$ "
 // Update the backing value
 {PropertyBackingFieldName(prop)} = value;
 
 // Register object for serialization in the next batch
 {ChangedFieldsFieldName(cl)} |= {ChangedFieldsTypeName(cl)}.{prop.Name};
예제 #3
0
        void GenerateClass(GClass cl)
        {
            var list = cl as GList;

            var unit = Unit();

            var clientNs    = NamespaceDeclaration(IdentifierName("Avalonia.Rendering.Composition"));
            var serverNs    = NamespaceDeclaration(IdentifierName("Avalonia.Rendering.Composition.Server"));
            var transportNs = NamespaceDeclaration(IdentifierName("Avalonia.Rendering.Composition.Transport"));

            var inherits         = cl.Inherits ?? "CompositionObject";
            var abstractModifier = cl.Abstract ? new[] { SyntaxKind.AbstractKeyword } : null;

            var client = ClassDeclaration(cl.Name)
                         .AddModifiers(abstractModifier)
                         .AddModifiers(SyntaxKind.PublicKeyword, SyntaxKind.UnsafeKeyword, SyntaxKind.PartialKeyword)
                         .WithBaseType(inherits);

            var serverName = ServerName(cl.Name);
            var serverBase = cl.ServerBase ?? ServerName(cl.Inherits);

            if (list != null)
            {
                serverBase = "ServerList<" + ServerName(list.ItemType) + ">";
            }

            var server = ClassDeclaration(serverName)
                         .AddModifiers(abstractModifier)
                         .AddModifiers(SyntaxKind.UnsafeKeyword, SyntaxKind.PartialKeyword)
                         .WithBaseType(serverBase);

            string changesName           = ChangesName(cl.Name);
            string changedFieldsTypeName = ChangedFieldsTypeName(cl);
            string changedFieldsName     = ChangedFieldsFieldName(cl);

            if (cl.Properties.Count > 0)
            {
                client = client
                         .AddMembers(DeclareField(changedFieldsTypeName, changedFieldsName));
            }


            if (!cl.CustomCtor)
            {
                client = client.AddMembers(PropertyDeclaration(ParseTypeName(serverName), "Server")
                                           .AddModifiers(SyntaxKind.InternalKeyword, SyntaxKind.NewKeyword)
                                           .AddAccessorListAccessors(AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
                                                                     .WithSemicolonToken(Semicolon())));
                client = client.AddMembers(
                    ConstructorDeclaration(cl.Name)
                    .AddModifiers(SyntaxKind.InternalKeyword)
                    .WithParameterList(ParameterList(SeparatedList(new[]
                {
                    Parameter(Identifier("compositor")).WithType(ParseTypeName("Compositor")),
                    Parameter(Identifier("server")).WithType(ParseTypeName(serverName)),
                })))
                    .WithInitializer(ConstructorInitializer(SyntaxKind.BaseConstructorInitializer,
                                                            ArgumentList(SeparatedList(new[]
                {
                    Argument(IdentifierName("compositor")),
                    Argument(IdentifierName("server")),
                })))).WithBody(Block(
                                   ExpressionStatement(
                                       AssignmentExpression(
                                           SyntaxKind.SimpleAssignmentExpression,
                                           IdentifierName("Server"),
                                           CastExpression(ParseTypeName(serverName), IdentifierName("server")))),
                                   ExpressionStatement(InvocationExpression(IdentifierName("InitializeDefaults")))
                                   )));
            }

            if (!cl.CustomServerCtor)
            {
                server = server.AddMembers(
                    ConstructorDeclaration(serverName)
                    .AddModifiers(SyntaxKind.InternalKeyword)
                    .WithParameterList(ParameterList(SeparatedList(new[]
                {
                    Parameter(Identifier("compositor")).WithType(ParseTypeName("ServerCompositor")),
                })))
                    .WithInitializer(ConstructorInitializer(SyntaxKind.BaseConstructorInitializer,
                                                            ArgumentList(SeparatedList(new[]
                {
                    Argument(IdentifierName("compositor")),
                })))).WithBody(Block(ParseStatement("Initialize();"))));
            }

            server = server.AddMembers(
                MethodDeclaration(ParseTypeName("void"), "Initialize")
                .AddModifiers(SyntaxKind.PartialKeyword).WithSemicolonToken(Semicolon()));


            var changesVarName = "c";
            var changesVar     = IdentifierName(changesVarName);

            server = server.AddMembers(
                MethodDeclaration(ParseTypeName("void"), "DeserializeChangesExtra")
                .AddParameterListParameters(Parameter(Identifier("c")).WithType(ParseTypeName("BatchStreamReader")))
                .AddModifiers(SyntaxKind.PartialKeyword).WithSemicolonToken(Semicolon()));

            var resetBody                        = Block();
            var startAnimationBody               = Block();
            var serverGetPropertyBody            = Block();
            var serverGetCompositionPropertyBody = Block();
            var serializeMethodBody              = SerializeChangesPrologue(cl);
            var deserializeMethodBody            = DeserializeChangesPrologue(cl);

            var defaultsMethodBody = Block(ParseStatement("InitializeDefaultsExtra();"));

            foreach (var prop in cl.Properties)
            {
                var  fieldName            = PropertyBackingFieldName(prop);
                var  propType             = ParseTypeName(prop.Type);
                var  filteredPropertyType = prop.Type.TrimEnd('?');
                var  isObject             = _objects.Contains(filteredPropertyType);
                var  isNullable           = prop.Type.EndsWith("?");
                bool isPassthrough        = false;

                client = GenerateClientProperty(client, cl, prop, propType, isObject, isNullable);

                var animatedServer = prop.Animated;

                var serverPropertyType = ((isObject ? "Server" : "") + prop.Type);
                if (_manuals.TryGetValue(filteredPropertyType, out var manual))
                {
                    if (manual.Passthrough)
                    {
                        isPassthrough      = true;
                        serverPropertyType = prop.Type;
                    }

                    if (manual.ServerName != null)
                    {
                        serverPropertyType = manual.ServerName + (isNullable ? "?" : "");
                    }
                }

                if (animatedServer)
                {
                    server = server.AddMembers(
                        DeclareField(serverPropertyType, fieldName),
                        PropertyDeclaration(ParseTypeName(serverPropertyType), prop.Name)
                        .AddModifiers(SyntaxKind.PublicKeyword)
                        .WithExpressionBody(ArrowExpressionClause(
                                                InvocationExpression(IdentifierName("GetAnimatedValue"),
                                                                     ArgumentList(SeparatedList(new[] {
                        Argument(IdentifierName(CompositionPropertyField(prop))),
                        Argument(null, Token(SyntaxKind.RefKeyword), IdentifierName(fieldName))
                    }
                                                                                                )))))
                        .WithSemicolonToken(Semicolon())
                        );
                }
                else
                {
                    server = server
                             .AddMembers(DeclareField(serverPropertyType, fieldName))
                             .AddMembers(PropertyDeclaration(ParseTypeName(serverPropertyType), prop.Name)
                                         .AddModifiers(SyntaxKind.PublicKeyword)
                                         .AddAccessorListAccessors(
                                             AccessorDeclaration(SyntaxKind.GetAccessorDeclaration,
                                                                 Block(ReturnStatement(
                                                                           InvocationExpression(IdentifierName("GetValue"),
                                                                                                ArgumentList(SeparatedList(new[] {
                        Argument(IdentifierName(CompositionPropertyField(prop))),
                        Argument(null, Token(SyntaxKind.RefKeyword), IdentifierName(fieldName))
                    }
                                                                                                                           )))))),
                                             AccessorDeclaration(SyntaxKind.SetAccessorDeclaration,
                                                                 Block(
                                                                     ParseStatement("var changed = false;"),
                                                                     IfStatement(BinaryExpression(SyntaxKind.NotEqualsExpression,
                                                                                                  IdentifierName(fieldName),
                                                                                                  IdentifierName("value")),
                                                                                 Block(
                                                                                     ParseStatement("On" + prop.Name + "Changing();"),
                                                                                     ParseStatement($"changed = true;"))
                                                                                 ),
                                                                     ExpressionStatement(InvocationExpression(IdentifierName("SetValue"),
                                                                                                              ArgumentList(SeparatedList(new[] {
                        Argument(IdentifierName(CompositionPropertyField(prop))),
                        Argument(null, Token(SyntaxKind.OutKeyword), IdentifierName(fieldName)),
                        Argument(IdentifierName("value"))
                    }
                                                                                                                                         )))),
                                                                     ParseStatement($"if(changed) On" + prop.Name + "Changed();")
                                                                     ))
                                             ))
                             .AddMembers(MethodDeclaration(ParseTypeName("void"), "On" + prop.Name + "Changed")
                                         .AddModifiers(SyntaxKind.PartialKeyword).WithSemicolonToken(Semicolon()))
                             .AddMembers(MethodDeclaration(ParseTypeName("void"), "On" + prop.Name + "Changing")
                                         .AddModifiers(SyntaxKind.PartialKeyword).WithSemicolonToken(Semicolon()));
                }

                resetBody = resetBody.AddStatements(
                    ExpressionStatement(InvocationExpression(MemberAccess(prop.Name, "Reset"))));

                serializeMethodBody   = ApplySerializeField(serializeMethodBody, cl, prop, isObject, isPassthrough);
                deserializeMethodBody = ApplyDeserializeField(deserializeMethodBody, cl, prop, serverPropertyType, isObject);

                if (animatedServer)
                {
                    startAnimationBody = ApplyStartAnimation(startAnimationBody, cl, prop);
                }


                serverGetPropertyBody            = ApplyGetProperty(serverGetPropertyBody, prop);
                serverGetCompositionPropertyBody = ApplyGetProperty(serverGetCompositionPropertyBody, prop, CompositionPropertyField(prop));

                server = server.AddMembers(DeclareField("CompositionProperty", CompositionPropertyField(prop),
                                                        EqualsValueClause(ParseExpression("CompositionProperty.Register()")),
                                                        SyntaxKind.InternalKeyword, SyntaxKind.StaticKeyword));

                if (prop.DefaultValue != null)
                {
                    defaultsMethodBody = defaultsMethodBody.AddStatements(
                        ExpressionStatement(
                            AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
                                                 IdentifierName(prop.Name), ParseExpression(prop.DefaultValue))));
                }
            }

            if (cl.Properties.Count > 0)
            {
                server = server.AddMembers(((MethodDeclarationSyntax)ParseMemberDeclaration(
                                                $"protected override void DeserializeChangesCore(BatchStreamReader reader, TimeSpan commitedAt){{}}")
                                            !)
                                           .WithBody(ApplyDeserializeChangesEpilogue(deserializeMethodBody, cl)));
                server = server.AddMembers(MethodDeclaration(ParseTypeName("void"), "OnFieldsDeserialized")
                                           .WithParameterList(ParameterList(SingletonSeparatedList(Parameter(Identifier("changed"))
                                                                                                   .WithType(ParseTypeName(ChangedFieldsTypeName(cl))))))
                                           .AddModifiers(SyntaxKind.PartialKeyword).WithSemicolonToken(Semicolon()));
            }

            client = client.AddMembers(
                MethodDeclaration(ParseTypeName("void"), "InitializeDefaults").WithBody(defaultsMethodBody))
                     .AddMembers(
                MethodDeclaration(ParseTypeName("void"), "InitializeDefaultsExtra")
                .AddModifiers(SyntaxKind.PartialKeyword).WithSemicolonToken(Semicolon()));

            if (cl.Properties.Count > 0)
            {
                serializeMethodBody = serializeMethodBody.AddStatements(SerializeChangesEpilogue(cl));
                client = client.AddMembers(((MethodDeclarationSyntax)ParseMemberDeclaration(
                                                $"private protected override void SerializeChangesCore(BatchStreamWriter writer){{}}") !)
                                           .WithBody(serializeMethodBody));
            }

            if (list != null)
            {
                client = AppendListProxy(list, client);
            }

            if (startAnimationBody.Statements.Count != 0)
            {
                client = WithStartAnimation(client, startAnimationBody);
            }

            server = WithGetPropertyForAnimation(server, serverGetPropertyBody);
            server = WithGetCompositionProperty(server, serverGetCompositionPropertyBody);

            if (cl.Implements.Count > 0)
            {
                foreach (var impl in cl.Implements)
                {
                    client = client.WithBaseList(client.BaseList.AddTypes(SimpleBaseType(ParseTypeName(impl.Name))));
                    if (impl.ServerName != null)
                    {
                        server = server.WithBaseList(
                            server.BaseList.AddTypes(SimpleBaseType(ParseTypeName(impl.ServerName))));
                    }

                    client = client.AddMembers(
                        ParseMemberDeclaration($"{impl.ServerName} {impl.Name}.Server => Server;"));
                }
            }


            SaveTo(unit.AddMembers(GenerateChangedFieldsEnum(cl)), "Transport",
                   ChangedFieldsTypeName(cl) + ".generated.cs");

            SaveTo(unit.AddMembers(clientNs.AddMembers(client)),
                   cl.Name + ".generated.cs");
            SaveTo(unit.AddMembers(serverNs.AddMembers(server)),
                   "Server", "Server" + cl.Name + ".generated.cs");
        }
예제 #4
0
 ExpressionSyntax ClientProperty(GClass c, GProperty p) =>
 MemberAccess(ServerName(c.Name), CompositionPropertyField(p));
예제 #5
0
 string ChangedFieldsFieldName(GClass c) => "_changedFieldsOf" + c.Name;
예제 #6
0
 string ChangedFieldsTypeName(GClass c) => c.Name + "ChangedFields";
예제 #7
0
        private ClassDeclarationSyntax GenerateClientProperty(ClassDeclarationSyntax client, GClass cl, GProperty prop,
                                                              TypeSyntax propType, bool isObject, bool isNullable)
        {
            var fieldName = PropertyBackingFieldName(prop);

            return(client
                   .AddMembers(DeclareField(prop.Type, fieldName))
                   .AddMembers(PropertyDeclaration(propType, prop.Name)
                               .AddModifiers(prop.Internal ? SyntaxKind.InternalKeyword : SyntaxKind.PublicKeyword)
                               .AddAccessorListAccessors(
                                   AccessorDeclaration(SyntaxKind.GetAccessorDeclaration,
                                                       Block(ReturnStatement(IdentifierName(fieldName)))),
                                   AccessorDeclaration(SyntaxKind.SetAccessorDeclaration,
                                                       Block(
                                                           ParseStatement("var changed = false;"),
                                                           IfStatement(BinaryExpression(SyntaxKind.NotEqualsExpression,
                                                                                        IdentifierName(fieldName),
                                                                                        IdentifierName("value")),
                                                                       Block(
                                                                           ParseStatement("On" + prop.Name + "Changing();"),
                                                                           ParseStatement("changed = true;"),
                                                                           GeneratePropertySetterAssignment(cl, prop, isObject, isNullable))
                                                                       ),
                                                           ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
                                                                                                    IdentifierName(fieldName), IdentifierName("value"))),
                                                           ParseStatement($"if(changed) On" + prop.Name + "Changed();")
                                                           )).WithModifiers(TokenList(prop.InternalSet ? new[] { Token(SyntaxKind.InternalKeyword) } : Array.Empty <SyntaxToken>()))
                                   ))
                   .AddMembers(MethodDeclaration(ParseTypeName("void"), "On" + prop.Name + "Changed")
                               .AddModifiers(SyntaxKind.PartialKeyword).WithSemicolonToken(Semicolon()))
                   .AddMembers(MethodDeclaration(ParseTypeName("void"), "On" + prop.Name + "Changing")
                               .AddModifiers(SyntaxKind.PartialKeyword).WithSemicolonToken(Semicolon())));
        }