Example #1
0
 // valueType maybe a ConstantExpression and then Prune optimizes unreachable branches out
 static Expression MatchOrElse(Expression valueType, BondDataType expectedType, TypeHandlerCompiletime handler, Expression orElse)
 {
     return(PrunedExpression.IfThenElse(
                Expression.Equal(valueType, Expression.Constant(expectedType)),
                handler(expectedType),
                orElse));
 }
Example #2
0
        Expression Value(IParser parser, Expression valueType, RuntimeSchema schema)
        {
            Debug.Assert(schema.HasValue);

            if (parser.IsBonded || (untaggedWriter && schema.IsBonded))
            {
                return(parser.Bonded(value =>
                                     writer.WriteBonded(PrunedExpression.Convert(value, typeof(IBonded)))));
            }


            if (schema.IsStruct)
            {
                return(GenerateSerialize(Struct, parser, schema));
            }

            if (schema.IsMap)
            {
                return(GenerateSerialize(Map, parser, schema));
            }

            if (schema.IsContainer)
            {
                return(GenerateSerialize(Container, parser, schema));
            }

            return(parser.Scalar(valueType, schema.TypeDef.id,
                                 value => writer.Write(value, schema.TypeDef.id)));
        }
Example #3
0
        Expression FieldValue(IParser parser, Expression var, Expression valueType, Type schemaType, bool initialize)
        {
            Expression body;

            if (schemaType.IsBondStruct() && var.Type.IsValueType())
            {
                // Special handling for properties of struct types: we deserialize into
                // a temp variable and then assign the value to the property.
                var temp = Expression.Variable(var.Type, "temp");
                body = Expression.Block(
                    new[] { temp },
                    Value(parser, temp, valueType, schemaType, true),
                    Expression.Assign(var, temp));
            }
            else
            {
                body = Value(parser, var, valueType, schemaType, initialize);
            }

            if (schemaType.IsBondContainer() || schemaType.IsBondStruct() || schemaType.IsBondNullable())
            {
                var expectedType = Expression.Constant(schemaType.GetBondDataType());
                return(PrunedExpression.IfThenElse(
                           Expression.Equal(valueType, expectedType),
                           body,
                           ThrowExpression.InvalidTypeException(expectedType, valueType)));
            }

            return(body);
        }
Example #4
0
 public static Expression While(Expression whileCondition, Expression body, LabelTarget breakLabel)
 {
     return(Expression.Loop(
                PrunedExpression.IfThenElse(
                    whileCondition,
                    body,
                    Expression.Break(breakLabel)),
                breakLabel));
 }
Example #5
0
        Expression Value(IParser parser, Expression valueType)
        {
            if (parser.IsBonded)
            {
                return(parser.Bonded(value =>
                                     writer.WriteBonded(PrunedExpression.Convert(value, typeof(IBonded)))));
            }

            var switchCases = new List <DeferredSwitchCase>
            {
                PrunedExpression.SwitchCase(
                    () => GenerateSerialize(Container, parser),
                    BondDataType.BT_LIST,
                    BondDataType.BT_SET),
                PrunedExpression.SwitchCase(
                    () => GenerateSerialize(Map, parser),
                    BondDataType.BT_MAP),
                PrunedExpression.SwitchCase(
                    () => GenerateSerialize(Struct, parser),
                    BondDataType.BT_STRUCT)
            };

            switchCases.AddRange(
                from type in new[]
            {
                BondDataType.BT_BOOL,
                BondDataType.BT_UINT8,
                BondDataType.BT_UINT16,
                BondDataType.BT_UINT32,
                BondDataType.BT_UINT64,
                BondDataType.BT_FLOAT,
                BondDataType.BT_DOUBLE,
                BondDataType.BT_STRING,
                BondDataType.BT_INT8,
                BondDataType.BT_INT16,
                BondDataType.BT_INT32,
                BondDataType.BT_INT64,
                BondDataType.BT_WSTRING
            }
                select
                PrunedExpression.SwitchCase(
                    () => parser.Scalar(Expression.Constant(type), type,
                                        value => writer.Write(value, type)),
                    type));

            return(PrunedExpression.Switch(
                       valueType,
                       ThrowExpression.InvalidTypeException(valueType),
                       switchCases));
        }
Example #6
0
        public Expression Assign(Expression left, Expression right)
        {
            var leftType = left.Type;

            if (leftType != right.Type &&
                leftType.IsGenericType() &&
                leftType.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                leftType = leftType.GetGenericArguments()[0];
            }

            var value = Convert(right, leftType);

            return(Expression.Assign(left, PrunedExpression.Convert(value, left.Type)));
        }
Example #7
0
        Expression CheckedValue(IParser parser, Expression var, Expression valueType, Type schemaType, bool initialize)
        {
            var body = Value(parser, var, valueType, schemaType, initialize);

            if (schemaType.IsBondContainer() || schemaType.IsBondStruct() || schemaType.IsBondNullable())
            {
                var expectedType = Expression.Constant(schemaType.GetBondDataType());
                return(PrunedExpression.IfThenElse(
                           Expression.Equal(valueType, expectedType),
                           body,
                           ThrowExpression.InvalidTypeException(expectedType, valueType)));
            }

            return(body);
        }
Example #8
0
        Expression Field(ITransform transform, Expression structVar, UInt16 id, ISchemaField schemaField, IField field)
        {
            var fieldSchemaType = schemaField.GetSchemaType();
            var fieldId         = Expression.Constant(id);
            var fieldType       = Expression.Constant(fieldSchemaType.GetBondDataType());
            var fieldValue      = DataExpression.PropertyOrField(structVar, schemaField.Name);
            var parser          = new ObjectParser(this, fieldValue, fieldSchemaType);

            var processField = field != null
                ? field.Value(parser, fieldType)
                : transform.UnknownField(parser, fieldType, fieldId) ?? Expression.Empty();

            var omitField = field != null
                ? field.Omitted : Expression.Empty();

            Expression cannotOmit;

            if (fieldSchemaType.IsBondStruct() || fieldSchemaType.IsBonded() || schemaField.GetModifier() != Modifier.Optional)
            {
                cannotOmit = Expression.Constant(true);
            }
            else
            {
                var defaultValue = schemaField.GetDefaultValue();

                if (fieldSchemaType.IsBondBlob())
                {
                    cannotOmit = Expression.NotEqual(
                        typeAlias.Convert(fieldValue, fieldSchemaType),
                        Expression.Default(typeof(ArraySegment <byte>)));
                }
                else if (fieldSchemaType.IsBondContainer())
                {
                    cannotOmit = defaultValue == null
                        ? Expression.NotEqual(fieldValue, Expression.Constant(null))
                        : Expression.NotEqual(ContainerCount(fieldValue), Expression.Constant(0));
                }
                else
                {
                    cannotOmit = Expression.NotEqual(fieldValue, Expression.Constant(defaultValue));
                }
            }

            return(PrunedExpression.IfThenElse(cannotOmit, processField, omitField));
        }
Example #9
0
        /// <summary>
        /// Generate expression provided by Serialize delegate, either as inline expression or a lambda call
        /// </summary>
        /// <param name="serialize">Delegate to generate serialization expression</param>
        /// <param name="parser">Parser used for the source of serialization</param>
        /// <param name="writer">Writer to use for serialization</param>
        /// <param name="inline">True if the expression can be inlined</param>
        /// <remarks>
        /// Generates lambda calls for recursive schemas to avoid infinitely inlining the same expression.
        /// Expression is considered the same when both serialize delegate and parser are the same. It is
        /// caller's responsibility to assure that the pair of serialize delegate and parser can be used
        /// to identify generated expression. For object serializer, when the parser is ObjectParser, this
        /// is generally guaranteed by using parser instance per schema type. Transcoding may use a single
        /// parser instance but different Serialize delegates for each transcoded schema type (e.g. when
        /// the delegate captures schema metadata).
        /// </remarks>
        protected Expression GenerateSerialize(Serialize serialize, IParser parser, ParameterExpression writer, bool inline)
        {
            var key = new KeyValuePair <IParser, Serialize>(parser, serialize);

            inline = inline && inProgress.Count != 0 && !inProgress.Contains(key);
            Expression body;

            inProgress.Push(key);

            if (inline)
            {
                body = serialize(parser);

                if (parser.ReaderParam != parser.ReaderValue && parser.ReaderValue.Type.IsBondStruct())
                {
                    body = Expression.Block(
                        new[] { parser.ReaderParam },
                        Expression.Assign(parser.ReaderParam, Expression.Convert(parser.ReaderValue, parser.ReaderParam.Type)),
                        body);
                }
            }
            else
            {
                int index;
                if (!serializeIndex.TryGetValue(key, out index))
                {
                    index = serializeActions.Count;
                    serializeIndex[key] = index;
                    serializeActions.Add(null);
                    serializeActions[index] = Expression.Lambda <Action <R, W> >(
                        serialize(parser),
                        parser.ReaderParam,
                        writer);
                }

                body = Expression.Invoke(
                    deferredSerialize,
                    PrunedExpression.Convert(parser.ReaderValue, parser.ReaderParam.Type),
                    writer,
                    Expression.Constant(index));
            }

            inProgress.Pop();
            return(body);
        }
Example #10
0
        Expression Container(IParser parser, RuntimeSchema schema)
        {
            var expectedValueType = schema.HasValue ? schema.TypeDef.element.id : (BondDataType?)null;

            return(parser.Container(expectedValueType,
                                    (valueParser, elementType, next, count) =>
            {
                var body = ControlExpression.While(next,
                                                   Expression.Block(
                                                       writer.WriteItemBegin(),
                                                       schema.HasValue ?
                                                       Value(valueParser, elementType, schema.GetElementSchema()) :
                                                       Value(valueParser, elementType),
                                                       writer.WriteItemEnd()));

                var blob = parser.Blob(count);
                if (blob != null)
                {
                    body = PrunedExpression.IfThenElse(
                        Expression.Equal(elementType, Expression.Constant(BondDataType.BT_INT8)),
                        writer.WriteBytes(blob),
                        body);

                    // For binary protocols we can write blob directly using protocols's WriteBytes
                    // even if the container is not a blob (blob is BT_LIST of BT_INT8).
                    if (binaryWriter)
                    {
                        body = PrunedExpression.IfThenElse(
                            Expression.Equal(elementType, Expression.Constant(BondDataType.BT_UINT8)),
                            writer.WriteBytes(blob),
                            body);
                    }
                }

                return Expression.Block(
                    writer.WriteContainerBegin(count, elementType),
                    body,
                    writer.WriteContainerEnd());
            }));
        }
Example #11
0
        Expression Value(IParser parser, Expression var, Expression valueType, Type schemaType, bool initialize)
        {
            if (schemaType.IsBondNullable())
            {
                return(Nullable(parser, var, schemaType.GetValueType(), initialize));
            }

            if (schemaType.IsBonded())
            {
                var convert = bondedConvert.MakeGenericMethod(var.Type.GetValueType());
                return(parser.Bonded(value => Expression.Assign(var, Expression.Call(value, convert))));
            }

            if (schemaType.IsBondStruct())
            {
                if (parser.IsBonded)
                {
                    var deserialize = bondedDeserialize.MakeGenericMethod(schemaType);
                    return(parser.Bonded(value => Expression.Assign(var, Expression.Call(value, deserialize))));
                }
                return(Deserialize(parser, var, var.Type, schemaType, initialize));
            }

            if (schemaType.IsBondMap())
            {
                return(Map(parser, var, schemaType, initialize));
            }

            if (schemaType.IsBondContainer())
            {
                return(Container(parser, var, schemaType, initialize));
            }

            return(parser.Scalar(valueType, schemaType.GetBondDataType(),
                                 value => typeAlias.Assign(var, PrunedExpression.Convert(value, schemaType))));
        }
Example #12
0
        public Expression Assign(Expression left, Expression right)
        {
            var value = Convert(right, left.Type);

            return(Expression.Assign(left, PrunedExpression.Convert(value, left.Type)));
        }
Example #13
0
        Expression Field(ITransform transform, Expression structVar, UInt16 id, ISchemaField schemaField, IField field)
        {
            var fieldSchemaType = schemaField.GetSchemaType();
            var fieldId         = Expression.Constant(id);
            var fieldType       = Expression.Constant(fieldSchemaType.GetBondDataType());
            var fieldValue      = DataExpression.PropertyOrField(structVar, schemaField.Name);

            ObjectParser parser = null;

            Expression          blob          = null;
            ParameterExpression convertedBlob = null;

            // To avoid calling Convert multiple times on the same aliased Blob
            // we must construct a new ObjectParser with the expected return type of
            // of Convert
            if (fieldSchemaType.IsBondBlob())
            {
                blob          = typeAlias.Convert(fieldValue, fieldSchemaType);
                convertedBlob = Expression.Variable(blob.Type, "convertedBlob");

                if (blob.Type != fieldValue.Type)
                {
                    parser = new ObjectParser(this, convertedBlob, convertedBlob.Type);
                }
            }

            parser = parser ?? new ObjectParser(this, fieldValue, fieldSchemaType);

            var processField = field != null
                ? field.Value(parser, fieldType)
                : transform.UnknownField(parser, fieldType, fieldId) ?? Expression.Empty();

            var omitField = field != null
                ? field.Omitted : Expression.Empty();

            Expression cannotOmit;

            if (fieldSchemaType.IsBondStruct() || fieldSchemaType.IsBonded() || schemaField.GetModifier() != Modifier.Optional)
            {
                cannotOmit = Expression.Constant(true);

                if (fieldSchemaType.IsBondBlob())
                {
                    return(Expression.Block(
                               new[] { convertedBlob },
                               Expression.Assign(convertedBlob, blob),
                               processField));
                }
            }
            else
            {
                var defaultValue = schemaField.GetDefaultValue();

                if (fieldSchemaType.IsBondBlob())
                {
                    var notEqual = Expression.NotEqual(
                        convertedBlob,
                        Expression.Default(typeof(ArraySegment <byte>)));

                    return(Expression.Block(
                               new[] { convertedBlob },
                               Expression.Assign(convertedBlob, blob),
                               PrunedExpression.IfThenElse(notEqual, processField, omitField)));
                }
                else if (fieldSchemaType.IsBondContainer())
                {
                    cannotOmit = defaultValue == null
                        ? Expression.NotEqual(fieldValue, Expression.Constant(null))
                        : Expression.NotEqual(ContainerCount(fieldValue), Expression.Constant(0));
                }
                else
                {
                    cannotOmit = Expression.NotEqual(fieldValue, Expression.Constant(defaultValue));
                }
            }

            return(PrunedExpression.IfThenElse(cannotOmit, processField, omitField));
        }