public static (ClassDeclarationSyntax, IGeneratedProxyDescription) Generate( LibraryTypes libraryTypes, IInvokableInterfaceDescription interfaceDescription, MetadataModel metadataModel) { var generatedClassName = GetSimpleClassName(interfaceDescription.InterfaceType); var ctors = GenerateConstructors(generatedClassName, interfaceDescription).ToArray(); var proxyMethods = CreateProxyMethods(libraryTypes, interfaceDescription, metadataModel).ToArray(); var classDeclaration = ClassDeclaration(generatedClassName) .AddBaseListTypes( SimpleBaseType(interfaceDescription.ProxyBaseType.ToTypeSyntax()), SimpleBaseType(interfaceDescription.InterfaceType.ToTypeSyntax())) .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword)) .AddAttributeLists( AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax()))) .AddMembers(ctors) .AddMembers(proxyMethods); if (interfaceDescription.InterfaceType.TypeParameters.Length > 0) { classDeclaration = AddGenericTypeConstraints(classDeclaration, interfaceDescription.InterfaceType); } return(classDeclaration, new GeneratedProxyDescription(interfaceDescription)); }
private static MemberDeclarationSyntax GenerateGetResultProperty( LibraryTypes libraryTypes, ResultFieldDescription resultField) { var type = IdentifierName("TResult"); var typeToken = Identifier("TResult"); ExpressionSyntax body; if (resultField != null) { body = CastExpression( type, CastExpression(libraryTypes.Object.ToTypeSyntax(), ThisExpression().Member(resultField.FieldName))); } else { body = ThrowExpression( ObjectCreationExpression(libraryTypes.InvalidOperationException.ToTypeSyntax()) .WithArgumentList( ArgumentList( SingletonSeparatedList( Argument("Method does not have a return value.".GetLiteralExpression()))))); } return(MethodDeclaration(type, "GetResult") .WithTypeParameterList(TypeParameterList(SingletonSeparatedList(TypeParameter(typeToken)))) .WithParameterList(ParameterList()) .WithExpressionBody(ArrowExpressionClause(body)) .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword))) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))); }
private static MemberDeclarationSyntax GenerateDisposeMethod( LibraryTypes libraryTypes, List <FieldDescription> fields) { var body = new List <StatementSyntax>(); foreach (var field in fields) { if (!field.IsInjected) { body.Add( ExpressionStatement( AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, ThisExpression().Member(field.FieldName), DefaultExpression(field.FieldType.ToTypeSyntax())))); } } body.Add(ExpressionStatement(InvocationExpression(libraryTypes.InvokablePool.ToTypeSyntax().Member("Return")) .WithArgumentList(ArgumentList(SingletonSeparatedList <ArgumentSyntax>(Argument(ThisExpression())))))); return(MethodDeclaration(libraryTypes.Void.ToTypeSyntax(), "Dispose") .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword))) .WithBody(Block(body))); }
public SerializableMethodMember(LibraryTypes wellKnownTypes, MethodParameterFieldDescription member, int ordinal) { this.member = member; this.wellKnownTypes = wellKnownTypes; this.Description = member; this.ordinal = ordinal; }
public static ClassDeclarationSyntax GenerateSerializer(Compilation compilation, TypeDescription typeDescription) { var type = typeDescription.Type; var simpleClassName = GetSimpleClassName(type); var libraryTypes = LibraryTypes.FromCompilation(compilation); var serializerInterface = type.IsValueType ? libraryTypes.ValueSerializer : libraryTypes.PartialSerializer; var baseInterface = serializerInterface.Construct(type).ToTypeSyntax(); var fieldDescriptions = GetFieldDescriptions(typeDescription, libraryTypes); var fields = GetFieldDeclarations(fieldDescriptions); var ctor = GenerateConstructor(simpleClassName, fieldDescriptions); var serializeMethod = GenerateSerializeMethod(typeDescription, fieldDescriptions, libraryTypes); var deserializeMethod = GenerateDeserializeMethod(typeDescription, fieldDescriptions, libraryTypes); var classDeclaration = ClassDeclaration(simpleClassName) .AddBaseListTypes(SimpleBaseType(baseInterface)) .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword)) .AddAttributeLists(AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax()))) .AddMembers(fields) .AddMembers(ctor, serializeMethod, deserializeMethod); if (type.IsGenericType) { classDeclaration = AddGenericTypeConstraints(classDeclaration, type); } return(classDeclaration); }
private static MemberDeclarationSyntax GenerateResultProperty( LibraryTypes libraryTypes, ResultFieldDescription resultField) { var getter = AccessorDeclaration(SyntaxKind.GetAccessorDeclaration) .WithExpressionBody( ArrowExpressionClause( CastExpression( libraryTypes.Object.ToTypeSyntax(), ThisExpression().Member(resultField.FieldName)))) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)); var setter = AccessorDeclaration(SyntaxKind.SetAccessorDeclaration) .WithExpressionBody( ArrowExpressionClause( AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, ThisExpression().Member(resultField.FieldName), CastExpression(resultField.FieldType.ToTypeSyntax(), IdentifierName("value"))))) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)); return(PropertyDeclaration(libraryTypes.Object.ToTypeSyntax(), "Result") .WithAccessorList( AccessorList() .AddAccessors( getter, setter)) .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)))); }
public SerializableTypeDescription(SemanticModel semanticModel, INamedTypeSymbol type, IEnumerable <IMemberDescription> members, LibraryTypes libraryTypes) { Type = type; Members = members.ToList(); SemanticModel = semanticModel; _libraryTypes = libraryTypes; }
public SerializableMember(LibraryTypes wellKnownTypes, ISerializableTypeDescription type, IMemberDescription member, int ordinal) { this.wellKnownTypes = wellKnownTypes; this.model = type.SemanticModel; this.Description = member; this.ordinal = ordinal; }
private static MemberDeclarationSyntax GenerateSetTargetMethod( LibraryTypes libraryTypes, IInvokableInterfaceDescription interfaceDescription, TargetFieldDescription targetField) { var type = IdentifierName("TTargetHolder"); var typeToken = Identifier("TTargetHolder"); var holderParameter = Identifier("holder"); var holder = IdentifierName("holder"); var getTarget = InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, holder, GenericName(interfaceDescription.IsExtension ? "GetExtension" : "GetTarget") .WithTypeArgumentList( TypeArgumentList( SingletonSeparatedList(interfaceDescription.InterfaceType.ToTypeSyntax()))))) .WithArgumentList(ArgumentList()); var body = AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, ThisExpression().Member(targetField.FieldName), getTarget); return(MethodDeclaration(libraryTypes.Void.ToTypeSyntax(), "SetTarget") .WithTypeParameterList(TypeParameterList(SingletonSeparatedList(TypeParameter(typeToken)))) .WithParameterList(ParameterList(SingletonSeparatedList(Parameter(holderParameter).WithType(type)))) .WithExpressionBody(ArrowExpressionClause(body)) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)))); }
private static MemberDeclarationSyntax GenerateCreateMethod(LibraryTypes libraryTypes, ISerializableTypeDescription type) { var createObject = type.GetObjectCreationExpression(libraryTypes); return(MethodDeclaration(type.TypeSyntax, "Create") .WithExpressionBody(ArrowExpressionClause(createObject)) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) .AddModifiers(Token(SyntaxKind.PublicKeyword))); }
private static BlockSyntax CreateProxyMethodBody( LibraryTypes libraryTypes, MetadataModel metadataModel, IInvokableInterfaceDescription interfaceDescription, MethodDescription methodDescription) { var statements = new List <StatementSyntax>(); // Create request object var requestVar = IdentifierName("request"); var requestDescription = metadataModel.GeneratedInvokables[methodDescription]; var createRequestExpr = ObjectCreationExpression(requestDescription.TypeSyntax) .WithArgumentList(ArgumentList(SeparatedList <ArgumentSyntax>())); statements.Add( LocalDeclarationStatement( VariableDeclaration( ParseTypeName("var"), SingletonSeparatedList( VariableDeclarator( Identifier("request")) .WithInitializer( EqualsValueClause(createRequestExpr)))))); // Set request object fields from method parameters. var parameterIndex = 0; foreach (var parameter in methodDescription.Method.Parameters) { statements.Add( ExpressionStatement( AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, requestVar.Member($"arg{parameterIndex}"), IdentifierName(parameter.Name)))); parameterIndex++; } // Issue request statements.Add( ExpressionStatement( AwaitExpression( InvocationExpression( BaseExpression().Member("Invoke"), ArgumentList(SingletonSeparatedList(Argument(requestVar))))))); // Return result if (methodDescription.Method.ReturnType is INamedTypeSymbol named && named.TypeParameters.Length == 1) { statements.Add(ReturnStatement(requestVar.Member("result"))); } return(Block(statements)); }
private static MemberDeclarationSyntax GenerateSerializeMethod(TypeDescription typeDescription, List <SerializerFieldDescription> fieldDescriptions, LibraryTypes libraryTypes) { var returnType = PredefinedType(Token(SyntaxKind.VoidKeyword)); var writerParam = "writer".ToIdentifierName(); var sessionParam = "session".ToIdentifierName(); var instanceParam = "instance".ToIdentifierName(); var body = new List <StatementSyntax>(); if (HasComplexBaseType(typeDescription.Type)) { body.Add( ExpressionStatement( InvocationExpression( ThisExpression().Member(BaseTypeSerializerFieldName.ToIdentifierName()).Member(SerializeMethodName), ArgumentList(SeparatedList(new[] { Argument(writerParam), Argument(sessionParam), Argument(instanceParam) }))))); body.Add(ExpressionStatement(InvocationExpression(writerParam.Member("WriteEndBase"), ArgumentList()))); } // Order members according to their FieldId, since fields must be serialized in order and FieldIds are serialized as deltas. uint previousFieldId = 0; foreach (var member in typeDescription.Members.OrderBy(m => m.FieldId)) { var fieldIdDelta = member.FieldId - previousFieldId; previousFieldId = member.FieldId; var codec = fieldDescriptions.OfType <CodecFieldDescription>().First(f => f.UnderlyingType.Equals(GetExpectedType(member.Type))); var expectedType = fieldDescriptions.OfType <TypeFieldDescription>().First(f => f.UnderlyingType.Equals(GetExpectedType(member.Type))); body.Add( ExpressionStatement( InvocationExpression( ThisExpression().Member(codec.FieldName).Member("WriteField"), ArgumentList( SeparatedList( new[] { Argument(writerParam), Argument(sessionParam), Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(fieldIdDelta))), Argument(expectedType.FieldName.ToIdentifierName()), Argument(instanceParam.Member(member.Member.Name)) }))))); } return(MethodDeclaration(returnType, SerializeMethodName) .AddModifiers(Token(SyntaxKind.PublicKeyword)) .AddParameterListParameters( Parameter("writer".ToIdentifier()).WithType(libraryTypes.Writer.ToTypeSyntax()), Parameter("session".ToIdentifier()).WithType(libraryTypes.SerializerSession.ToTypeSyntax()), Parameter("instance".ToIdentifier()).WithType(typeDescription.Type.ToTypeSyntax())) .AddBodyStatements(body.ToArray())); }
public CodeGenerator(Compilation compilation, CodeGeneratorOptions options) { this.compilation = compilation; this.options = options; this.libraryTypes = LibraryTypes.FromCompilation(compilation, options); if (options.GenerateSerializerAttributes != null) { this.generateSerializerAttributes = options.GenerateSerializerAttributes.Select(compilation.GetTypeByMetadataName).ToArray(); } }
private static MemberDeclarationSyntax GenerateGetArgumentCount( LibraryTypes libraryTypes, MethodDescription methodDescription) => PropertyDeclaration(libraryTypes.Int32.ToTypeSyntax(), "ArgumentCount") .WithExpressionBody( ArrowExpressionClause( LiteralExpression( SyntaxKind.NumericLiteralExpression, Literal(methodDescription.Method.Parameters.Length)))) .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword))) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
public static (ClassDeclarationSyntax, IGeneratedInvokerDescription) Generate( Compilation compilation, LibraryTypes libraryTypes, IInvokableInterfaceDescription interfaceDescription, MethodDescription methodDescription) { var method = methodDescription.Method; var generatedClassName = GetSimpleClassName(method); var fieldDescriptions = GetFieldDescriptions(methodDescription.Method, interfaceDescription); var fields = GetFieldDeclarations(fieldDescriptions, libraryTypes); var ctor = GenerateConstructor(generatedClassName, fieldDescriptions); var targetField = fieldDescriptions.OfType <TargetFieldDescription>().Single(); var resultField = fieldDescriptions.OfType <ResultFieldDescription>().FirstOrDefault(); var classDeclaration = ClassDeclaration(generatedClassName) .AddBaseListTypes(SimpleBaseType(libraryTypes.Invokable.ToTypeSyntax())) .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword)) .AddAttributeLists( AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax()))) .AddMembers(fields) .AddMembers(ctor) .AddMembers( GenerateGetArgumentCount(libraryTypes, methodDescription), GenerateSetTargetMethod(libraryTypes, interfaceDescription, targetField), GenerateGetTargetMethod(libraryTypes, targetField), GenerateResetMethod(libraryTypes, fieldDescriptions), GenerateGetArgumentMethod(libraryTypes, methodDescription, fieldDescriptions), GenerateSetArgumentMethod(libraryTypes, methodDescription, fieldDescriptions), GenerateInvokeMethod(libraryTypes, methodDescription, fieldDescriptions, targetField, resultField), GenerateSetResultProperty(libraryTypes, resultField), GenerateGetResultProperty(libraryTypes, resultField)); var typeParameters = interfaceDescription.InterfaceType.TypeParameters.Select(tp => (tp, tp.Name)) .Concat(method.TypeParameters.Select(tp => (tp, tp.Name))) .ToList(); if (typeParameters.Count > 0) { classDeclaration = AddGenericTypeConstraints(classDeclaration, typeParameters); } return(classDeclaration, new GeneratedInvokerDescription( interfaceDescription, methodDescription, generatedClassName, fieldDescriptions.OfType <IMemberDescription>().ToList())); }
public InvokableInterfaceDescription( LibraryTypes libraryTypes, SemanticModel semanticModel, INamedTypeSymbol interfaceType, IEnumerable <MethodDescription> methods, INamedTypeSymbol proxyBaseType, bool isExtension) { this.ValidateBaseClass(libraryTypes, proxyBaseType); this.SemanticModel = semanticModel; this.InterfaceType = interfaceType; this.ProxyBaseType = proxyBaseType; this.IsExtension = isExtension; this.Methods = methods.ToList(); }
private static MemberDeclarationSyntax GenerateGetTargetMethod( LibraryTypes libraryTypes, TargetFieldDescription targetField) { var type = IdentifierName("TTarget"); var typeToken = Identifier("TTarget"); var body = CastExpression(type, ThisExpression().Member(targetField.FieldName)); return(MethodDeclaration(type, "GetTarget") .WithTypeParameterList(TypeParameterList(SingletonSeparatedList(TypeParameter(typeToken)))) .WithParameterList(ParameterList()) .WithExpressionBody(ArrowExpressionClause(body)) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)))); }
private static void ValidateBaseClass(LibraryTypes l, INamedTypeSymbol baseClass) { var found = false; foreach (var member in baseClass.GetMembers("SendRequest")) { if (member is not IMethodSymbol method) { Throw(member, "not method"); } if (method.TypeParameters.Length != 0) { Throw(member, "type params"); } if (method.Parameters.Length != 2) { Throw(member, "params length"); } if (!SymbolEqualityComparer.Default.Equals(method.Parameters[0].Type, l.IResponseCompletionSource)) { Throw(member, "param 0"); } if (!SymbolEqualityComparer.Default.Equals(method.Parameters[1].Type, l.IInvokable)) { Throw(member, "param 1"); } if (!method.ReturnsVoid) { Throw(member, "return type"); } found = true; } if (!found) { throw new InvalidOperationException( $"Proxy base class {baseClass} does not contain a definition for void SendRequest(IResponseCompletionSource, IInvokable)"); }
public static ClassDeclarationSyntax GenerateActivator(LibraryTypes libraryTypes, ISerializableTypeDescription type) { var simpleClassName = GetSimpleClassName(type); var baseInterface = libraryTypes.IActivator_1.ToTypeSyntax(type.TypeSyntax); var classDeclaration = ClassDeclaration(simpleClassName) .AddBaseListTypes(SimpleBaseType(baseInterface)) .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword)) .AddAttributeLists(AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax()))) .AddMembers(GenerateCreateMethod(libraryTypes, type)); if (type.IsGenericType) { classDeclaration = AddGenericTypeConstraints(classDeclaration, type); } return(classDeclaration); }
public static ClassDeclarationSyntax GenerateMetadata(Compilation compilation, List <TypeDescription> serializableTypes) { var configParam = "config".ToIdentifierName(); var addMethod = configParam.Member("PartialSerializers").Member("Add"); var body = new List <StatementSyntax>(); body.AddRange( serializableTypes.Select( type => (StatementSyntax)ExpressionStatement(InvocationExpression(addMethod, ArgumentList(SingletonSeparatedList(Argument(TypeOfExpression(GetPartialSerializerTypeName(type.Type))))))) )); var libraryTypes = LibraryTypes.FromCompilation(compilation); var configType = libraryTypes.SerializerConfiguration; var configureMethod = MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), "Configure") .AddModifiers(Token(SyntaxKind.PublicKeyword)) .AddParameterListParameters( Parameter(configParam.Identifier).WithType(configType.ToTypeSyntax())) .AddBodyStatements(body.ToArray()); var interfaceType = libraryTypes.ConfigurationProvider.Construct(configType); return(ClassDeclaration(CodeGenerator.CodeGeneratorName + "_Metadata_" + compilation.AssemblyName.Replace('.', '_')) .AddBaseListTypes(SimpleBaseType(interfaceType.ToTypeSyntax())) .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword)) .AddAttributeLists(AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax()))) .AddMembers(configureMethod)); TypeSyntax GetPartialSerializerTypeName(INamedTypeSymbol type) { var genericArity = type.TypeParameters.Length; var name = PartialSerializerGenerator.GetSimpleClassName(type); if (genericArity > 0) { name += $"<{new string(',', genericArity - 1)}>"; } return(ParseTypeName(name)); } }
void ValidateBaseClass(LibraryTypes l, INamedTypeSymbol baseClass) { var found = false; foreach (var member in baseClass.GetMembers("SendRequest")) { if (!(member is IMethodSymbol method)) { Throw(member, "not method"); } if (method.TypeParameters.Length != 0) { Throw(member, "type params"); } if (method.Parameters.Length != 2) { Throw(member, "params length"); } if (!method.Parameters[0].Type.Equals(l.IResponseCompletionSource)) { Throw(member, "param 0"); } if (!method.Parameters[1].Type.Equals(l.IInvokable)) { Throw(member, "param 1"); } if (!method.ReturnsVoid) { Throw(member, "return type"); } found = true; } if (!found) { throw new InvalidOperationException( $"Proxy base class {baseClass} does not contain a definition for void SendRequest(IResponseCompletionSource, IInvokable)"); } void Throw(ISymbol m, string x) => throw new InvalidOperationException("Complaint: " + x + " for symbol: " + m.ToDisplayString()); }
private static IEnumerable <MemberDeclarationSyntax> CreateProxyMethods( LibraryTypes libraryTypes, IInvokableInterfaceDescription interfaceDescription, MetadataModel metadataModel) { foreach (var methodDescription in interfaceDescription.Methods) { yield return(CreateProxyMethod(methodDescription)); } MethodDeclarationSyntax CreateProxyMethod(MethodDescription methodDescription) { var method = methodDescription.Method; var declaration = MethodDeclaration(method.ReturnType.ToTypeSyntax(), method.Name) .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.AsyncKeyword)) .AddParameterListParameters(method.Parameters.Select(GetParameterSyntax).ToArray()) .WithBody( CreateProxyMethodBody(libraryTypes, metadataModel, interfaceDescription, methodDescription)); var typeParameters = GetTypeParametersWithConstraints(method.TypeParameters); foreach (var(name, constraints) in typeParameters) { if (constraints.Count > 0) { declaration = declaration.AddConstraintClauses( TypeParameterConstraintClause(name).AddConstraints(constraints.ToArray())); } } if (typeParameters.Count > 0) { declaration = declaration.WithTypeParameterList( TypeParameterList(SeparatedList(typeParameters.Select(tp => TypeParameter(tp.Item1))))); } return(declaration); } }
void ValidateBaseClass(LibraryTypes l, INamedTypeSymbol baseClass) { var found = false; foreach (var member in baseClass.GetMembers("Invoke")) { if (!(member is IMethodSymbol method)) { continue; } if (method.TypeParameters.Length != 1) { continue; } if (method.Parameters.Length != 1) { continue; } if (!method.Parameters[0].Type.Equals(method.TypeParameters[0])) { continue; } if (!method.TypeParameters[0].ConstraintTypes.Contains(l.IInvokable)) { continue; } if (!method.ReturnType.Equals(l.ValueTask)) { continue; } found = true; } if (!found) { throw new InvalidOperationException( $"Proxy base class {baseClass} does not contain a definition for ValueTask Invoke<T>(T) where T : IInvokable"); } }
private static MemberDeclarationSyntax GenerateResetMethod( LibraryTypes libraryTypes, List <FieldDescription> fields) { var body = new List <StatementSyntax>(); foreach (var field in fields) { if (!field.IsInjected) { body.Add( ExpressionStatement( AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, ThisExpression().Member(field.FieldName), DefaultExpression(field.FieldType.ToTypeSyntax())))); } } return(MethodDeclaration(libraryTypes.Void.ToTypeSyntax(), "Reset") .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword))) .WithBody(Block(body))); }
private static MemberDeclarationSyntax GenerateInvokeInnerMethod( LibraryTypes libraryTypes, MethodDescription method, List <FieldDescription> fields, TargetFieldDescription target) { var resultTask = IdentifierName("resultTask"); // C# var resultTask = this.target.{Method}({params}); var args = SeparatedList( fields.OfType <MethodParameterFieldDescription>() .OrderBy(p => p.ParameterOrdinal) .Select(p => Argument(ThisExpression().Member(p.FieldName)))); ExpressionSyntax methodCall; if (method.Method.TypeParameters.Length > 0) { methodCall = MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, ThisExpression().Member(target.FieldName), GenericName( Identifier(method.Method.Name), TypeArgumentList( SeparatedList <TypeSyntax>( method.Method.TypeParameters.Select(p => IdentifierName(p.Name)))))); } else { methodCall = ThisExpression().Member(target.FieldName).Member(method.Method.Name); } return(MethodDeclaration(method.Method.ReturnType.ToTypeSyntax(), "InvokeInner") .WithParameterList(ParameterList()) .WithExpressionBody(ArrowExpressionClause(InvocationExpression(methodCall, ArgumentList(args)))) .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)) .WithModifiers(TokenList(Token(SyntaxKind.ProtectedKeyword), Token(SyntaxKind.OverrideKeyword)))); }
public ExpressionSyntax GetObjectCreationExpression(LibraryTypes libraryTypes) => InvocationExpression(ObjectCreationExpression(this.TypeSyntax));
private static MemberDeclarationSyntax GenerateDeserializeMethod(TypeDescription typeDescription, List <SerializerFieldDescription> fieldDescriptions, LibraryTypes libraryTypes) { var returnType = PredefinedType(Token(SyntaxKind.VoidKeyword)); var readerParam = "reader".ToIdentifierName(); var sessionParam = "session".ToIdentifierName(); var instanceParam = "instance".ToIdentifierName(); var fieldIdVar = "fieldId".ToIdentifierName(); var headerVar = "header".ToIdentifierName(); var body = new List <StatementSyntax> { // C#: uint fieldId = 0; LocalDeclarationStatement( VariableDeclaration( PredefinedType(Token(SyntaxKind.UIntKeyword)), SingletonSeparatedList(VariableDeclarator(fieldIdVar.Identifier) .WithInitializer(EqualsValueClause(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0))))))) }; if (HasComplexBaseType(typeDescription.Type)) { // C#: this.baseTypeSerializer.Deserialize(ref reader, session, instance); body.Add( ExpressionStatement( InvocationExpression( ThisExpression().Member(BaseTypeSerializerFieldName.ToIdentifierName()).Member(DeserializeMethodName), ArgumentList(SeparatedList(new[] { Argument(readerParam).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)), Argument(sessionParam), Argument(instanceParam) }))))); } body.Add(WhileStatement(LiteralExpression(SyntaxKind.TrueLiteralExpression), Block(GetDeserializerLoopBody()))); var parameters = new[] { Parameter(readerParam.Identifier).WithType(libraryTypes.Reader.ToTypeSyntax()).WithModifiers(TokenList(Token(SyntaxKind.RefKeyword))), Parameter(sessionParam.Identifier).WithType(libraryTypes.SerializerSession.ToTypeSyntax()), Parameter(instanceParam.Identifier).WithType(typeDescription.Type.ToTypeSyntax()) }; if (typeDescription.Type.IsValueType) { parameters[2] = parameters[2].WithModifiers(TokenList(Token(SyntaxKind.RefKeyword))); } return(MethodDeclaration(returnType, DeserializeMethodName) .AddModifiers(Token(SyntaxKind.PublicKeyword)) .AddParameterListParameters(parameters) .AddBodyStatements(body.ToArray())); // Create the loop body. List <StatementSyntax> GetDeserializerLoopBody() { return(new List <StatementSyntax> { // C#: var header = reader.ReadFieldHeader(session); LocalDeclarationStatement( VariableDeclaration( IdentifierName("var"), SingletonSeparatedList( VariableDeclarator(headerVar.Identifier) .WithInitializer(EqualsValueClause(InvocationExpression(readerParam.Member("ReadFieldHeader"), ArgumentList(SingletonSeparatedList(Argument(sessionParam))))))))), // C#: if (header.IsEndBaseOrEndObject) break; IfStatement(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, headerVar, IdentifierName("IsEndBaseOrEndObject")), BreakStatement()), // C#: fieldId += header.FieldIdDelta; ExpressionStatement( AssignmentExpression( SyntaxKind.AddAssignmentExpression, fieldIdVar, Token(SyntaxKind.PlusEqualsToken), MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, headerVar, IdentifierName("FieldIdDelta")))), // C#: switch (fieldId) { ... } SwitchStatement(fieldIdVar, List(GetSwitchSections())) }); } // Creates switch sections for each member. List <SwitchSectionSyntax> GetSwitchSections() { var switchSections = new List <SwitchSectionSyntax>(); foreach (var member in typeDescription.Members) { // C#: case <fieldId>: var label = CaseSwitchLabel(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(member.FieldId))); // C#: instance.<member> = this.<codec>.ReadValue(ref reader, session, header); var codec = fieldDescriptions.OfType <ICodecDescription>() .Concat(libraryTypes.StaticCodecs) .First(f => f.UnderlyingType.Equals(GetExpectedType(member.Type))); // Codecs can either be static classes or injected into the constructor. // Either way, the member signatures are the same. var memberType = GetExpectedType(member.Type); var staticCodec = libraryTypes.StaticCodecs.FirstOrDefault(c => c.UnderlyingType.Equals(memberType)); ExpressionSyntax codecExpression; if (staticCodec != null) { codecExpression = staticCodec.CodecType.ToNameSyntax(); } else { var instanceCodec = fieldDescriptions.OfType <CodecFieldDescription>().First(f => f.UnderlyingType.Equals(memberType)); codecExpression = ThisExpression().Member(instanceCodec.FieldName); } ExpressionSyntax readValueExpression = InvocationExpression( codecExpression.Member("ReadValue"), ArgumentList(SeparatedList(new[] { Argument(readerParam).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)), Argument(sessionParam), Argument(headerVar) }))); if (!codec.UnderlyingType.Equals(member.Type)) { // If the member type type differs from the codec type (eg because the member is an array), cast the result. readValueExpression = CastExpression(member.Type.ToTypeSyntax(), readValueExpression); } var memberAssignment = ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, instanceParam.Member(member.Member.Name), readValueExpression)); var caseBody = List(new StatementSyntax[] { memberAssignment, BreakStatement() }); // Create the switch section with a break at the end. // C#: break; switchSections.Add(SwitchSection(SingletonList <SwitchLabelSyntax>(label), caseBody)); } // Add the default switch section. var consumeUnknown = ExpressionStatement(InvocationExpression(readerParam.Member("ConsumeUnknownField"), ArgumentList(SeparatedList(new[] { Argument(sessionParam), Argument(headerVar) })))); switchSections.Add(SwitchSection(SingletonList <SwitchLabelSyntax>(DefaultSwitchLabel()), List(new StatementSyntax[] { consumeUnknown, BreakStatement() }))); return(switchSections); } }
private static MemberDeclarationSyntax GenerateSerializeMethod( TypeDescription typeDescription, List <SerializerFieldDescription> fieldDescriptions, LibraryTypes libraryTypes) { var returnType = PredefinedType(Token(SyntaxKind.VoidKeyword)); var writerParam = "writer".ToIdentifierName(); var sessionParam = "session".ToIdentifierName(); var instanceParam = "instance".ToIdentifierName(); var body = new List <StatementSyntax>(); if (HasComplexBaseType(typeDescription.Type)) { body.Add( ExpressionStatement( InvocationExpression( ThisExpression().Member(BaseTypeSerializerFieldName.ToIdentifierName()).Member(SerializeMethodName), ArgumentList(SeparatedList(new[] { Argument(writerParam).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)), Argument(sessionParam), Argument(instanceParam) }))))); body.Add(ExpressionStatement(InvocationExpression(writerParam.Member("WriteEndBase"), ArgumentList()))); } // Order members according to their FieldId, since fields must be serialized in order and FieldIds are serialized as deltas. uint previousFieldId = 0; foreach (var member in typeDescription.Members.OrderBy(m => m.FieldId)) { var fieldIdDelta = member.FieldId - previousFieldId; previousFieldId = member.FieldId; // Codecs can either be static classes or injected into the constructor. // Either way, the member signatures are the same. var memberType = GetExpectedType(member.Type); var staticCodec = libraryTypes.StaticCodecs.FirstOrDefault(c => c.UnderlyingType.Equals(memberType)); ExpressionSyntax codecExpression; if (staticCodec != null) { codecExpression = staticCodec.CodecType.ToNameSyntax(); } else { var instanceCodec = fieldDescriptions.OfType <CodecFieldDescription>().First(f => f.UnderlyingType.Equals(memberType)); codecExpression = ThisExpression().Member(instanceCodec.FieldName); } var expectedType = fieldDescriptions.OfType <TypeFieldDescription>().First(f => f.UnderlyingType.Equals(memberType)); body.Add( ExpressionStatement( InvocationExpression( codecExpression.Member("WriteField"), ArgumentList( SeparatedList( new[] { Argument(writerParam).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)), Argument(sessionParam), Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(fieldIdDelta))), Argument(expectedType.FieldName.ToIdentifierName()), Argument(instanceParam.Member(member.Member.Name)) }))))); } var parameters = new[] { Parameter("writer".ToIdentifier()).WithType(libraryTypes.Writer.ToTypeSyntax()).WithModifiers(TokenList(Token(SyntaxKind.RefKeyword))), Parameter("session".ToIdentifier()).WithType(libraryTypes.SerializerSession.ToTypeSyntax()), Parameter("instance".ToIdentifier()).WithType(typeDescription.Type.ToTypeSyntax()) }; if (typeDescription.Type.IsValueType) { parameters[2] = parameters[2].WithModifiers(TokenList(Token(SyntaxKind.RefKeyword))); } return(MethodDeclaration(returnType, SerializeMethodName) .AddModifiers(Token(SyntaxKind.PublicKeyword)) .AddParameterListParameters(parameters) .AddBodyStatements(body.ToArray())); }
private static List <SerializerFieldDescription> GetFieldDescriptions(TypeDescription typeDescription, LibraryTypes libraryTypes) { var type = typeDescription.Type; var fields = new List <SerializerFieldDescription>(); fields.AddRange(typeDescription.Members.Select(m => GetExpectedType(m.Type)).Distinct().Select(GetTypeDescription)); if (HasComplexBaseType(type)) { fields.Add(new InjectedFieldDescription(libraryTypes.PartialSerializer.Construct(type.BaseType), BaseTypeSerializerFieldName)); } // Add a codec field for any field in the target which does not have a static codec. fields.AddRange(typeDescription.Members .Select(m => GetExpectedType(m.Type)).Distinct() .Where(t => !libraryTypes.StaticCodecs.Any(c => c.UnderlyingType.Equals(t))) .Select(GetCodecDescription)); return(fields); CodecFieldDescription GetCodecDescription(ITypeSymbol t) { var codecType = libraryTypes.FieldCodec.Construct(t); var fieldName = '_' + ToLowerCamelCase(t.GetValidIdentifier()) + "Codec"; return(new CodecFieldDescription(codecType, fieldName, t)); } TypeFieldDescription GetTypeDescription(ITypeSymbol t) { var fieldName = ToLowerCamelCase(t.GetValidIdentifier()) + "Type"; return(new TypeFieldDescription(libraryTypes.Type, fieldName, t)); } string ToLowerCamelCase(string input) => char.IsLower(input, 0) ? input : char.ToLowerInvariant(input[0]) + input.Substring(1); }
private static MemberDeclarationSyntax GenerateInvokeMethod( LibraryTypes libraryTypes, MethodDescription method, List <FieldDescription> fields, TargetFieldDescription target, ResultFieldDescription result) { var body = new List <StatementSyntax>(); var resultTask = IdentifierName("resultTask"); // C# var resultTask = this.target.{Method}({params}); var args = SeparatedList( fields.OfType <MethodParameterFieldDescription>() .OrderBy(p => p.ParameterOrdinal) .Select(p => Argument(ThisExpression().Member(p.FieldName)))); ExpressionSyntax methodCall; if (method.Method.TypeParameters.Length > 0) { methodCall = MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, ThisExpression().Member(target.FieldName), GenericName( Identifier(method.Method.Name), TypeArgumentList( SeparatedList <TypeSyntax>( method.Method.TypeParameters.Select(p => IdentifierName(p.Name)))))); } else { methodCall = ThisExpression().Member(target.FieldName).Member(method.Method.Name); } body.Add( LocalDeclarationStatement( VariableDeclaration( ParseTypeName("var"), SingletonSeparatedList( VariableDeclarator(resultTask.Identifier) .WithInitializer( EqualsValueClause( InvocationExpression( methodCall, ArgumentList(args)))))))); // C#: if (resultTask.IsCompleted) // Even if it failed. // C#: { // C#: this.result = resultTask.GetAwaiter().GetResult(); // C#: return default; // default(ValueTask) is a successfully completed ValueTask. // C#: } var synchronousCompletionBody = new List <StatementSyntax>(); if (result != null) { synchronousCompletionBody.Add( ExpressionStatement( AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, ThisExpression().Member(result.FieldName), InvocationExpression( InvocationExpression(resultTask.Member("GetAwaiter")).Member("GetResult"))))); } synchronousCompletionBody.Add(ReturnStatement(DefaultExpression(libraryTypes.ValueTask.ToTypeSyntax()))); body.Add(IfStatement(resultTask.Member("IsCompleted"), Block(synchronousCompletionBody))); // C#: async ValueTask InvokeAsync(ValueTask<int> asyncValue) // C#: { // C#: this.result = await asyncValue.ConfigureAwait(false); // C#: } var invokeAsyncParam = IdentifierName("asyncTask"); var invokeAsyncBody = new List <StatementSyntax>(); var awaitExpression = AwaitExpression( InvocationExpression( invokeAsyncParam.Member("ConfigureAwait"), ArgumentList( SingletonSeparatedList(Argument(LiteralExpression(SyntaxKind.FalseLiteralExpression)))))); if (result != null) { invokeAsyncBody.Add( ExpressionStatement( AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, ThisExpression().Member(result.FieldName), awaitExpression))); } else { invokeAsyncBody.Add(ExpressionStatement(AwaitExpression(invokeAsyncParam))); } var invokeAsync = LocalFunctionStatement(libraryTypes.ValueTask.ToTypeSyntax(), "InvokeAsync") .WithModifiers(TokenList(Token(SyntaxKind.AsyncKeyword))) .WithParameterList( ParameterList( SingletonSeparatedList( Parameter(invokeAsyncParam.Identifier).WithType(method.Method.ReturnType.ToTypeSyntax())))) .WithBody(Block(invokeAsyncBody)); // C#: return InvokeAsync(resultTask); body.Add( ReturnStatement( InvocationExpression( IdentifierName("InvokeAsync"), ArgumentList(SingletonSeparatedList(Argument(resultTask)))))); body.Add(invokeAsync); return(MethodDeclaration(libraryTypes.ValueTask.ToTypeSyntax(), "Invoke") .WithParameterList(ParameterList()) .WithBody(Block(body)) .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)))); }