コード例 #1
0
        public override InvocationExpressionSyntax Create()
        {
            //TODO: Support custom primitivie specifier.
            //Primitive serialization YAY
            if (!Member.HasAttributeExact <EnumStringAttribute>())
            {
                //What type to serialize the enum as
                string serializeAsType = ComputeTypeToSerializeTo();

                var generator = new RawEnumPrimitiveSerializationGenerator(ActualType, Member, Mode, serializeAsType);
                return(generator.Create());
            }
            else
            {
                //They want STRING serialization for the enum, so defer it to the string type serializer.
                InvocationExpressionSyntax invocation = new StringTypeSerializationStatementsBlockEmitter(ActualType, Member, Mode)
                                                        .Create();

                if (Mode == SerializationMode.Write)
                {
                    return(invocation);
                }

                //We need special handling when READ mode, because we need to parse back to enum
                //which by the way is QUITE slow.
                //Enum.Parse<TType>
                EnumParseInvocationExpressionEmitter emitter = new EnumParseInvocationExpressionEmitter(ActualType, Member, invocation);
                return(emitter.Create());
            }
        }
コード例 #2
0
        private SyntaxNodeOrToken YieldSerializerTypeName()
        {
            //We need special case handling for string arrays.
            if (ElementType.IsTypeExact <string>())
            {
                StringTypeSerializationStatementsBlockEmitter stringSerializerEmitter = new StringTypeSerializationStatementsBlockEmitter(ActualType, Member, Mode);
                InvocationExpressionSyntax expressionSyntax = stringSerializerEmitter.Create();

                TypeNameTypeCollector genericNameCollector = new TypeNameTypeCollector();
                genericNameCollector.Visit(expressionSyntax);

                //Now we analyze the expression to determine the string type information
                return(genericNameCollector.Types.First());
            }
            else if (ElementType.IsEnumType())
            {
                //TODO: Enum string arrays aren't supported. This will break if they send EnumString
                //Send element type instead of array type, it's SO much easier that way! But kinda hacky
                EnumTypeSerializerStatementsBlockEmitter emitter = new EnumTypeSerializerStatementsBlockEmitter(ActualType.ElementType, Member, Mode);
                InvocationExpressionSyntax invokeSyntax          = emitter.Create();

                TypeNameTypeCollector genericNameCollector = new TypeNameTypeCollector();
                genericNameCollector.Visit(invokeSyntax);

                //Now we analyze the expression to determine the Enum serializer type.
                return(genericNameCollector.Types.First());
            }
            else
            {
                return(IdentifierName(GeneratedSerializerNameStringBuilder.Create(ElementType).BuildName(Member)));
            }
        }
        private SyntaxList <StatementSyntax> EmitTypesMemberSerialization(ITypeSymbol currentType, SyntaxList <StatementSyntax> statements)
        {
            if (currentType is INamedTypeSymbol namedSymbol)
            {
                if (namedSymbol.IsUnboundGenericType)
                {
                    throw new InvalidOperationException($"Cannot emit member serialization for open generic Type: {namedSymbol.Name}");
                }
            }

            //Conceptually, we need to find ALL serializable members
            foreach (ISymbol mi in currentType
                     .GetMembers()
                     .Where(m => !m.IsStatic)
                     .Where(m => m.HasAttributeExact <WireMemberAttribute>())
                     .OrderBy(m =>
            {
                //Seperated lines for debugging purposes.
                AttributeData attri = m.GetAttributeExact <WireMemberAttribute>();
                ImmutableArray <TypedConstant> attriArgs = attri.ConstructorArguments;
                string value = attriArgs.First().ToCSharpString();
                return(WireMemberAttribute.Parse(value));
            }))                     //order is important, we must emit in order!!
            {
                //Basically doesn't matter if it's a field or property, we just wanna know the Type
                //The reason is, setting and getting fields vs members are same syntax
                ITypeSymbol memberType = GetMemberTypeInfo(mi);

                AnalyzeMemberTypeForGenerics(memberType);

                FieldDocumentationStatementsBlockEmitter commentEmitter = new FieldDocumentationStatementsBlockEmitter(memberType, mi);
                statements = statements.AddRange(commentEmitter.CreateStatements());

                //The serializer is requesting we DON'T WRITE THIS! So we skip
                if (Mode == SerializationMode.Write)
                {
                    if (mi.HasAttributeExact <DontWriteAttribute>())
                    {
                        continue;
                    }
                }
                else if (Mode == SerializationMode.Read)
                {
                    if (mi.HasAttributeExact <DontReadAttribute>())
                    {
                        continue;
                    }
                }

                //This handles OPTIONAL fields that may or may not be included
                if (mi.HasAttributeExact <OptionalAttribute>())
                {
                    OptionalFieldStatementsBlockEmitter emitter = new OptionalFieldStatementsBlockEmitter(memberType, mi);
                    statements = statements.AddRange(emitter.CreateStatements());
                }

                InvocationExpressionSyntax invokeSyntax = null;

                //We know the type, but we have to do special handling depending on on its type
                if (mi.HasAttributeExact <CustomTypeSerializerAttribute>() || memberType.HasAttributeExact <CustomTypeSerializerAttribute>())
                {
                    //So TYPES and PROPERTIES may both reference a custom serializer.
                    //So we should prefer field/prop attributes over the type.
                    AttributeData attribute = mi.HasAttributeExact <CustomTypeSerializerAttribute>()
                                                ? mi.GetAttributeExact <CustomTypeSerializerAttribute>()
                                                : memberType.GetAttributeExact <CustomTypeSerializerAttribute>();

                    //It's DEFINITELY not null.
                    OverridenSerializationGenerator emitter = new OverridenSerializationGenerator(memberType, mi, Mode, (ITypeSymbol)attribute.ConstructorArguments.First().Value);
                    invokeSyntax = emitter.Create();
                }
                else if (memberType.IsPrimitive())
                {
                    //Easy case of primitive serialization
                    PrimitiveTypeSerializationStatementsBlockEmitter emitter = new PrimitiveTypeSerializationStatementsBlockEmitter(memberType, mi, Mode);
                    invokeSyntax = emitter.Create();
                }
                else if (memberType.SpecialType == SpecialType.System_String)
                {
                    var emitter = new StringTypeSerializationStatementsBlockEmitter(memberType, mi, Mode);
                    invokeSyntax = emitter.Create();
                }
                else if (memberType.SpecialType == SpecialType.System_Array || memberType is IArrayTypeSymbol)
                {
                    var emitter = new ArrayTypeSerializationStatementsBlockEmitter((IArrayTypeSymbol)memberType, mi, Mode);
                    invokeSyntax = emitter.Create();
                }
                else if (memberType.IsEnumType())                 //Enum type
                {
                    var emitter = new EnumTypeSerializerStatementsBlockEmitter(memberType, mi, Mode);
                    invokeSyntax = emitter.Create();
                }
                else if (memberType.IsReferenceType && memberType.TypeKind == TypeKind.Class)
                {
                    var emitter = new ComplexTypeSerializerStatementsBlockEmitter((INamedTypeSymbol)memberType, mi, Mode);
                    invokeSyntax = emitter.Create();
                }
                else
                {
                    bool isGenericType          = currentType is INamedTypeSymbol n && n.IsGenericType;
                    bool isUnboundedGenericType = currentType is INamedTypeSymbol n2 && n2.IsUnboundGenericType;
                    throw new NotImplementedException($"TODO: Cannot handle Type: {memberType} ContainingType: {currentType} MetadataType: {currentType.GetType().Name} Generic: {isGenericType} UnboundGeneric: {isUnboundedGenericType}");
                }

                //Now we check if compression was requested
                if (invokeSyntax != null && mi.HasAttributeExact <CompressAttribute>())
                {
                    TypeNameTypeCollector collector = new TypeNameTypeCollector();
                    collector.Visit(invokeSyntax);

                    //Replace the invokcation with an invokation to the compression decorator.
                    FullSerializerMethodInvokationEmitter emitter = new FullSerializerMethodInvokationEmitter(Mode, $"{WoWZLibCompressionTypeSerializerDecorator.TYPE_NAME}<{collector.Types.First().ToFullString()}, {memberType.ToFullName()}>", mi);
                    invokeSyntax = emitter.Create();
                }

                if (invokeSyntax != null)
                {
                    if (Mode == SerializationMode.Write)
                    {
                        statements = statements.Add(invokeSyntax.ToStatement());
                    }
                    else if (Mode == SerializationMode.Read)
                    {
                        //Read generation is abit more complicated.
                        //We must emit the assignment too
                        ReadAssignmentStatementsBlockEmitter emitter = new ReadAssignmentStatementsBlockEmitter(memberType, mi, Mode, invokeSyntax);
                        statements = statements.AddRange(emitter.CreateStatements());
                    }
                }

                //TODO: These don't work!!
                //Add 2 line breaks
                //statements = statements.AddRange(new EmptyLineStatementBlockEmitter().CreateStatements());
                //statements = statements.AddRange(new EmptyLineStatementBlockEmitter().CreateStatements());
            }

            return(statements);
        }