private static void WriteArray_(
            ICurlyBracketStringBuilder cbsb,
            ITypeSymbol sourceSymbol,
            ISchemaMember member)
        {
            var arrayType = member.MemberType as ISequenceMemberType;

            if (arrayType.LengthSourceType != SequenceLengthSourceType.CONST)
            {
                var isImmediate =
                    arrayType.LengthSourceType ==
                    SequenceLengthSourceType.IMMEDIATE_VALUE;

                if (isImmediate)
                {
                    var writeType = SchemaGeneratorUtil.GetIntLabel(
                        arrayType.ImmediateLengthType);

                    var castType = SchemaGeneratorUtil.GetTypeName(
                        SchemaPrimitiveTypesUtil.ConvertIntToNumber(
                            arrayType.ImmediateLengthType));

                    var arrayLengthName = arrayType.SequenceType == SequenceType.ARRAY
                                    ? "Length"
                                    : "Count";
                    var arrayLengthAccessor = $"this.{member.Name}.{arrayLengthName}";

                    cbsb.WriteLine(
                        $"ew.Write{writeType}(({castType}) {arrayLengthAccessor});");
                }
            }

            SchemaWriterGenerator.WriteIntoArray_(cbsb, sourceSymbol, member);
        }
        private static void ReadPrimitive_(
            ICurlyBracketStringBuilder cbsb,
            ITypeSymbol sourceSymbol,
            ISchemaMember member)
        {
            var primitiveType = member.MemberType as IPrimitiveMemberType;

            if (primitiveType.PrimitiveType == SchemaPrimitiveType.BOOLEAN)
            {
                SchemaReaderGenerator.ReadBoolean_(cbsb, member);
                return;
            }

            var readType = SchemaGeneratorUtil.GetPrimitiveLabel(
                primitiveType.UseAltFormat
              ? SchemaPrimitiveTypesUtil.ConvertNumberToPrimitive(
                    primitiveType.AltFormat)
              : primitiveType.PrimitiveType);

            var needToCast = primitiveType.UseAltFormat &&
                             primitiveType.PrimitiveType !=
                             SchemaPrimitiveTypesUtil.GetUnderlyingPrimitiveType(
                SchemaPrimitiveTypesUtil.ConvertNumberToPrimitive(
                    primitiveType.AltFormat));

            if (!primitiveType.IsReadonly)
            {
                var castText = "";
                if (needToCast)
                {
                    var castType =
                        primitiveType.PrimitiveType == SchemaPrimitiveType.ENUM
                  ? SymbolTypeUtil.GetQualifiedNameFromCurrentSymbol(
                            sourceSymbol,
                            primitiveType.TypeSymbol)
                  : primitiveType.TypeSymbol.Name;
                    castText = $"({castType}) ";
                }
                cbsb.WriteLine(
                    $"this.{member.Name} = {castText}er.Read{readType}();");
            }
            else
            {
                var castText = "";
                if (needToCast)
                {
                    var castType =
                        SchemaGeneratorUtil.GetTypeName(primitiveType.AltFormat);
                    castText = $"({castType}) ";
                }
                cbsb.WriteLine($"er.Assert{readType}({castText}this.{member.Name});");
            }
        }
        private static void WriteBoolean_(
            ICurlyBracketStringBuilder cbsb,
            ISchemaMember member)
        {
            var primitiveType = member.MemberType as IPrimitiveMemberType;

            var writeType = SchemaGeneratorUtil.GetPrimitiveLabel(
                SchemaPrimitiveTypesUtil.ConvertNumberToPrimitive(
                    primitiveType.AltFormat));
            var castType = SchemaGeneratorUtil.GetTypeName(
                primitiveType.AltFormat);

            cbsb.WriteLine(
                $"ew.Write{writeType}(({castType}) (this.{member.Name} ? 1 : 0));");
        }
        private static void ReadBoolean_(
            ICurlyBracketStringBuilder cbsb,
            ISchemaMember member)
        {
            var primitiveType = member.MemberType as IPrimitiveMemberType;

            var readType = SchemaGeneratorUtil.GetPrimitiveLabel(
                SchemaPrimitiveTypesUtil.ConvertNumberToPrimitive(
                    primitiveType.AltFormat));

            if (!primitiveType.IsReadonly)
            {
                cbsb.WriteLine(
                    $"this.{member.Name} = er.Read{readType}() != 0;");
            }
            else
            {
                cbsb.WriteLine(
                    $"er.Assert{readType}(this.{member.Name} ? 1 : 0);");
            }
        }
        private static void WritePrimitive_(
            ICurlyBracketStringBuilder cbsb,
            ISchemaMember member)
        {
            var primitiveType = member.MemberType as IPrimitiveMemberType;

            if (primitiveType.PrimitiveType == SchemaPrimitiveType.BOOLEAN)
            {
                SchemaWriterGenerator.WriteBoolean_(cbsb, member);
                return;
            }

            var readType = SchemaGeneratorUtil.GetPrimitiveLabel(
                primitiveType.UseAltFormat
              ? SchemaPrimitiveTypesUtil.ConvertNumberToPrimitive(
                    primitiveType.AltFormat)
              : primitiveType.PrimitiveType);

            var needToCast = primitiveType.UseAltFormat &&
                             primitiveType.PrimitiveType !=
                             SchemaPrimitiveTypesUtil.GetUnderlyingPrimitiveType(
                SchemaPrimitiveTypesUtil.ConvertNumberToPrimitive(
                    primitiveType.AltFormat));

            var castText = "";

            if (needToCast)
            {
                var castType =
                    SchemaGeneratorUtil.GetTypeName(primitiveType.AltFormat);
                castText = $"({castType}) ";
            }

            cbsb.WriteLine(
                $"ew.Write{readType}({castText}this.{member.Name});");
        }
        private static void WriteMember_(
            ICurlyBracketStringBuilder cbsb,
            ITypeSymbol sourceSymbol,
            ISchemaMember member)
        {
            if (member.IsPosition)
            {
                return;
            }

            if (member.Offset != null)
            {
                cbsb.WriteLine("throw new NotImplementedException();");
                return;
            }

            SchemaWriterGenerator.Align_(cbsb, member);

            var ifBoolean = member.IfBoolean;

            if (ifBoolean != null)
            {
                if (ifBoolean.SourceType == IfBooleanSourceType.IMMEDIATE_VALUE)
                {
                    var booleanNumberType =
                        SchemaPrimitiveTypesUtil.ConvertIntToNumber(
                            ifBoolean.ImmediateBooleanType);
                    var booleanPrimitiveType =
                        SchemaPrimitiveTypesUtil.ConvertNumberToPrimitive(
                            booleanNumberType);
                    var booleanNumberLabel =
                        SchemaGeneratorUtil.GetTypeName(booleanNumberType);
                    var booleanPrimitiveLabel =
                        SchemaGeneratorUtil.GetPrimitiveLabel(booleanPrimitiveType);
                    cbsb.WriteLine(
                        $"ew.Write{booleanPrimitiveLabel}(({booleanNumberLabel}) (this.{member.Name} != null ? 1 : 0));")
                    .EnterBlock($"if (this.{member.Name} != null)");
                }
                else
                {
                    cbsb.EnterBlock($"if (this.{ifBoolean.BooleanMember.Name})");
                }
            }

            var memberType = member.MemberType;

            if (memberType is IGenericMemberType genericMemberType)
            {
                memberType = genericMemberType.ConstraintType;
            }

            switch (memberType)
            {
            case IPrimitiveMemberType: {
                SchemaWriterGenerator.WritePrimitive_(cbsb, member);
                break;
            }

            case IStringType: {
                SchemaWriterGenerator.WriteString_(cbsb, member);
                break;
            }

            case IStructureMemberType structureMemberType: {
                SchemaWriterGenerator.WriteStructure_(cbsb, member);
                break;
            }

            case ISequenceMemberType: {
                SchemaWriterGenerator.WriteArray_(cbsb, sourceSymbol, member);
                break;
            }

            default:
                // Anything that makes it down here probably isn't meant to be read.
                throw new NotImplementedException();
            }

            if (ifBoolean != null)
            {
                cbsb.ExitBlock();
            }
        }
        private static void WriteIntoArray_(
            ICurlyBracketStringBuilder cbsb,
            ITypeSymbol sourceSymbol,
            ISchemaMember member)
        {
            var arrayType = member.MemberType as ISequenceMemberType;

            var elementType = arrayType.ElementType;

            if (elementType is IGenericMemberType genericElementType)
            {
                elementType = genericElementType.ConstraintType;
            }

            if (elementType is IPrimitiveMemberType primitiveElementType)
            {
                // Primitives that don't need to be cast are the easiest to write.
                if (!primitiveElementType.UseAltFormat)
                {
                    var label =
                        SchemaGeneratorUtil.GetPrimitiveLabel(
                            primitiveElementType.PrimitiveType);
                    cbsb.WriteLine($"ew.Write{label}s(this.{member.Name});");
                    return;
                }

                // Primitives that *do* need to be cast have to be written individually.
                var writeType = SchemaGeneratorUtil.GetPrimitiveLabel(
                    SchemaPrimitiveTypesUtil.ConvertNumberToPrimitive(
                        primitiveElementType.AltFormat));
                var arrayLengthName = arrayType.SequenceType == SequenceType.ARRAY
                                  ? "Length"
                                  : "Count";
                var castType =
                    primitiveElementType.PrimitiveType == SchemaPrimitiveType.ENUM
                ? SymbolTypeUtil.GetQualifiedNameFromCurrentSymbol(
                        sourceSymbol,
                        primitiveElementType.TypeSymbol)
                : primitiveElementType.TypeSymbol.Name;
                cbsb.EnterBlock(
                    $"for (var i = 0; i < this.{member.Name}.{arrayLengthName}; ++i)")
                .WriteLine(
                    $"ew.Write{writeType}(({castType}) this.{member.Name}[i]);")
                .ExitBlock();
                return;
            }

            if (elementType is IStructureMemberType structureElementType)
            {
                //if (structureElementType.IsReferenceType) {
                cbsb.EnterBlock($"foreach (var e in this.{member.Name})")
                .WriteLine("e.Write(ew);")
                .ExitBlock();
                // TODO: Do value types need to be read like below?

                /*}
                 * // Value types (mainly structs) have to be pulled out, read, then put
                 * // back in.
                 * else {
                 * var arrayLengthName = arrayType.SequenceType == SequenceType.ARRAY
                 *                          ? "Length"
                 *                          : "Count";
                 * cbsb.EnterBlock(
                 *        $"for (var i = 0; i < this.{member.Name}.{arrayLengthName}; ++i)")
                 *    .WriteLine($"var e = this.{member.Name}[i];")
                 *    .WriteLine("e.Read(ew);")
                 *    .WriteLine($"this.{member.Name}[i] = e;")
                 *    .ExitBlock();
                 * }*/
                return;
            }

// Anything that makes it down here probably isn't meant to be read.
            throw new NotImplementedException();
        }
Пример #8
0
        public ParseStatus ParseTypeSymbol(
            ITypeSymbol typeSymbol,
            bool isReadonly,
            out ITypeInfo typeInfo)
        {
            this.ParseNullable_(ref typeSymbol, out var isNullable);

            var primitiveType =
                SchemaPrimitiveTypesUtil.GetPrimitiveTypeFromTypeSymbol(
                    typeSymbol);

            if (primitiveType != SchemaPrimitiveType.UNDEFINED)
            {
                switch (primitiveType)
                {
                case SchemaPrimitiveType.BOOLEAN: {
                    typeInfo = new BoolTypeInfo(
                        typeSymbol,
                        isReadonly,
                        isNullable);
                    return(ParseStatus.SUCCESS);
                }

                case SchemaPrimitiveType.BYTE:
                case SchemaPrimitiveType.SBYTE:
                case SchemaPrimitiveType.INT16:
                case SchemaPrimitiveType.UINT16:
                case SchemaPrimitiveType.INT32:
                case SchemaPrimitiveType.UINT32:
                case SchemaPrimitiveType.INT64:
                case SchemaPrimitiveType.UINT64: {
                    typeInfo = new IntegerTypeInfo(
                        typeSymbol,
                        SchemaTypeKind.INTEGER,
                        SchemaPrimitiveTypesUtil.ConvertNumberToInt(
                            SchemaPrimitiveTypesUtil
                            .ConvertPrimitiveToNumber(primitiveType)),
                        isReadonly,
                        isNullable);
                    return(ParseStatus.SUCCESS);
                }

                case SchemaPrimitiveType.SN8:
                case SchemaPrimitiveType.UN8:
                case SchemaPrimitiveType.SN16:
                case SchemaPrimitiveType.UN16:
                case SchemaPrimitiveType.SINGLE:
                case SchemaPrimitiveType.DOUBLE: {
                    typeInfo = new FloatTypeInfo(
                        typeSymbol,
                        SchemaTypeKind.FLOAT,
                        SchemaPrimitiveTypesUtil
                        .ConvertPrimitiveToNumber(primitiveType),
                        isReadonly,
                        isNullable);
                    return(ParseStatus.SUCCESS);
                }

                case SchemaPrimitiveType.CHAR: {
                    typeInfo = new CharTypeInfo(
                        typeSymbol,
                        isReadonly,
                        isNullable);
                    return(ParseStatus.SUCCESS);
                }

                case SchemaPrimitiveType.ENUM: {
                    typeInfo = new EnumTypeInfo(
                        typeSymbol,
                        isReadonly,
                        isNullable);
                    return(ParseStatus.SUCCESS);
                }

                default: throw new ArgumentOutOfRangeException();
                }
            }

            if (typeSymbol.SpecialType == SpecialType.System_String)
            {
                typeInfo = new StringTypeInfo(
                    typeSymbol,
                    isReadonly,
                    isNullable);
                return(ParseStatus.SUCCESS);
            }

            if (typeSymbol.SpecialType is SpecialType
                .System_Collections_Generic_IReadOnlyList_T)
            {
                var listTypeSymbol = typeSymbol as INamedTypeSymbol;

                var containedTypeSymbol  = listTypeSymbol.TypeArguments[0];
                var containedParseStatus = this.ParseTypeSymbol(
                    containedTypeSymbol,
                    true,
                    out var containedTypeInfo);
                if (containedParseStatus != ParseStatus.SUCCESS)
                {
                    typeInfo = default;
                    return(containedParseStatus);
                }

                typeInfo = new SequenceTypeInfo(
                    typeSymbol,
                    isReadonly,
                    isNullable,
                    false,
                    isReadonly,
                    containedTypeInfo);
                return(ParseStatus.SUCCESS);
            }

            if (typeSymbol.TypeKind is TypeKind.Array)
            {
                var arrayTypeSymbol = typeSymbol as IArrayTypeSymbol;

                var containedTypeSymbol  = arrayTypeSymbol.ElementType;
                var containedParseStatus = this.ParseTypeSymbol(
                    containedTypeSymbol,
                    false,
                    out var containedTypeInfo);
                if (containedParseStatus != ParseStatus.SUCCESS)
                {
                    typeInfo = default;
                    return(containedParseStatus);
                }

                typeInfo = new SequenceTypeInfo(
                    typeSymbol,
                    isReadonly,
                    isNullable,
                    true,
                    isReadonly,
                    containedTypeInfo);
                return(ParseStatus.SUCCESS);
            }

            if (typeSymbol.SpecialType is SpecialType
                .System_Collections_Generic_IList_T)
            {
                var listTypeSymbol = typeSymbol as INamedTypeSymbol;

                var containedTypeSymbol  = listTypeSymbol.TypeArguments[0];
                var containedParseStatus = this.ParseTypeSymbol(
                    containedTypeSymbol,
                    false,
                    out var containedTypeInfo);
                if (containedParseStatus != ParseStatus.SUCCESS)
                {
                    typeInfo = default;
                    return(containedParseStatus);
                }

                typeInfo = new SequenceTypeInfo(
                    typeSymbol,
                    isReadonly,
                    isNullable,
                    false,
                    false,
                    containedTypeInfo);
                return(ParseStatus.SUCCESS);
            }

            if (typeSymbol is INamedTypeSymbol namedTypeSymbol)
            {
                typeInfo = new StructureTypeInfo(
                    namedTypeSymbol,
                    isReadonly,
                    isNullable);
                return(ParseStatus.SUCCESS);
            }

            if (typeSymbol is ITypeParameterSymbol typeParameterSymbol)
            {
                var constraintTypeInfos =
                    typeParameterSymbol
                    .ConstraintTypes
                    .Select(constraintType => {
                    var parseStatus = this.ParseTypeSymbol(
                        constraintType, isReadonly, out var constraintTypeInfo);
                    Asserts.Equal(ParseStatus.SUCCESS, parseStatus);
                    return(constraintTypeInfo);
                })
                    .ToArray();

                typeInfo = new GenericTypeInfo(
                    constraintTypeInfos,
                    typeParameterSymbol,
                    isReadonly,
                    isNullable);
                return(ParseStatus.SUCCESS);
            }

            typeInfo = default;
            return(ParseStatus.NOT_IMPLEMENTED);
        }
        private static void ReadMember_(
            ICurlyBracketStringBuilder cbsb,
            ITypeSymbol sourceSymbol,
            ISchemaMember member)
        {
            if (member.IsPosition)
            {
                if (member.MemberType.IsReadonly)
                {
                    cbsb.WriteLine($"er.AssertPosition(this.{member.Name});");
                }
                else
                {
                    cbsb.WriteLine($"this.{member.Name} = er.Position;");
                }
                return;
            }

            SchemaReaderGenerator.Align_(cbsb, member);

            // TODO: How to handle both offset & if boolean together?

            var offset = member.Offset;

            if (offset != null)
            {
                cbsb.EnterBlock()
                .WriteLine("var tempLocation = er.Position;")
                .WriteLine(
                    $"er.Position = this.{offset.StartIndexName.Name} + this.{offset.OffsetName.Name};");
            }

            var ifBoolean          = member.IfBoolean;
            var immediateIfBoolean =
                ifBoolean?.SourceType == IfBooleanSourceType.IMMEDIATE_VALUE;

            if (immediateIfBoolean)
            {
                cbsb.EnterBlock();
            }
            if (ifBoolean != null)
            {
                if (ifBoolean.SourceType == IfBooleanSourceType.IMMEDIATE_VALUE)
                {
                    var booleanNumberType =
                        SchemaPrimitiveTypesUtil.ConvertIntToNumber(
                            ifBoolean.ImmediateBooleanType);
                    var booleanPrimitiveType =
                        SchemaPrimitiveTypesUtil.ConvertNumberToPrimitive(
                            booleanNumberType);
                    var booleanPrimitiveLabel =
                        SchemaGeneratorUtil.GetPrimitiveLabel(booleanPrimitiveType);
                    cbsb.WriteLine($"var b = er.Read{booleanPrimitiveLabel}() != 0;")
                    .EnterBlock("if (b)");
                }
                else
                {
                    cbsb.EnterBlock($"if (this.{ifBoolean.BooleanMember.Name})");
                }

                if (member.MemberType is not IPrimitiveMemberType)
                {
                    cbsb.WriteLine(
                        $"this.{member.Name} = new {SymbolTypeUtil.GetQualifiedNameFromCurrentSymbol(sourceSymbol, member.MemberType.TypeSymbol)}();");
                }
            }

            var memberType = member.MemberType;

            if (memberType is IGenericMemberType genericMemberType)
            {
                memberType = genericMemberType.ConstraintType;
            }

            switch (memberType)
            {
            case IPrimitiveMemberType: {
                SchemaReaderGenerator.ReadPrimitive_(cbsb, sourceSymbol, member);
                break;
            }

            case IStringType: {
                SchemaReaderGenerator.ReadString_(cbsb, member);
                break;
            }

            case IStructureMemberType structureMemberType: {
                SchemaReaderGenerator.ReadStructure_(cbsb,
                                                     structureMemberType,
                                                     member);
                break;
            }

            case ISequenceMemberType: {
                SchemaReaderGenerator.ReadArray_(cbsb, sourceSymbol, member);
                break;
            }

            default: {
                // Anything that makes it down here probably isn't meant to be read.
                throw new NotImplementedException();
            }
            }

            if (ifBoolean != null)
            {
                cbsb.ExitBlock()
                .EnterBlock("else")
                .WriteLine($"this.{member.Name} = null;")
                .ExitBlock();
                if (immediateIfBoolean)
                {
                    cbsb.ExitBlock();
                }
            }

            if (offset != null)
            {
                cbsb.WriteLine("er.Position = tempLocation;")
                .ExitBlock();
            }
        }