in src/tools/DevGenerators/CompositionGenerator/Generator.cs [45:305]
static ExpressionSyntax ClientProperty(GClass c, GProperty p) =>
MemberAccess(ServerName(c.Name), CompositionPropertyField(p));
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 visibilityModifier = cl.Internal ? SyntaxKind.InternalKeyword : SyntaxKind.PublicKeyword;
var client = ClassDeclaration(cl.Name)
.AddModifiers(abstractModifier)
.AddModifiers(visibilityModifier, 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()));
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 typeInfo = GetTypeInfo(prop.Type);
var (propType, filteredPropertyType, isObject, isNullable, isPassthrough,
serverPropertyType) = (typeInfo.RoslynType,
typeInfo.FilteredTypeName,
typeInfo.IsObject, typeInfo.IsNullable, typeInfo.IsPassthrough, typeInfo.ServerType);
var animatedServer = prop.Animated;
client = GenerateClientProperty(client, cl, prop, propType, isObject, isNullable);
if (animatedServer)
server = server.AddMembers(
DeclareField(serverPropertyType, fieldName),
PropertyDeclaration(ParseTypeName(serverPropertyType), prop.Name)
.AddModifiers(SyntaxKind.PublicKeyword)
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithExpressionBody(
ArrowExpressionClause(IdentifierName(fieldName))).WithSemicolonToken(Semicolon()),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithExpressionBody(ArrowExpressionClause(
ParseExpression($"SetAnimatedValue({CompositionPropertyField(prop)}, out {PropertyBackingFieldName(prop)}, value)")))
.WithSemicolonToken(Semicolon())));
else
{
server = server
.AddMembers(DeclareField(serverPropertyType, fieldName))
.AddMembers(PropertyDeclaration(ParseTypeName(serverPropertyType), prop.Name)
.AddModifiers(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;"))
),
ExpressionStatement(InvocationExpression(IdentifierName("SetValue"),
ArgumentList(SeparatedList(new[]{
Argument(IdentifierName(CompositionPropertyField(prop))),
Argument(null, Token(SyntaxKind.RefKeyword), 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));
string compositionPropertyVariantGetter = "null";
if(VariantPropertyTypes.Contains(prop.Type))
compositionPropertyVariantGetter = $"obj => (({serverName})obj).{fieldName}";
server = server.AddMembers(DeclareField($"CompositionProperty<{serverPropertyType}>", CompositionPropertyField(prop),
EqualsValueClause(ParseExpression(
$"CompositionProperty.Register<{serverName}, {serverPropertyType}>(\"{prop.Name}\", obj => (({serverName})obj).{fieldName}, (obj, v) => (({serverName})obj).{fieldName} = v, {compositionPropertyVariantGetter})")),
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 committedAt){{}}")
!)
.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);
if (!cl.ServerOnly)
{
//server = WithGetPropertyForAnimation(server, serverGetPropertyBody);
server = WithGetCompositionProperty(server, serverGetCompositionPropertyBody);
}
if (cl.ServerOnly)
server = server.AddMembers(GenerateSerializeAllMethod(cl));
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))));
if(ParseMemberDeclaration($"{impl.ServerName} {impl.Name}.Server => Server;") is { } member)
client = client.AddMembers(member);
}
SaveTo(unit.AddMembers(GenerateChangedFieldsEnum(cl)), "Transport",
ChangedFieldsTypeName(cl) + ".generated.cs");
if (!cl.ServerOnly)
SaveTo(unit.AddMembers(clientNs.AddMembers(client)),
cl.Name + ".generated.cs");
SaveTo(unit.AddMembers(serverNs.AddMembers(server)),
"Server", "Server" + cl.Name + ".generated.cs");
}