Пример #1
0
        // Generates an expression that creates an NbtTag for given property of a directly-mappable types.
        // Directly-mappable types are: primitives, enums, byte[], int[], and string.
        // HandlePrimitiveOrEnum is actually more efficient (and preferred by NbtCompiler) for primitives and enums,
        // because it skips boxing and NullPolicy checks. This one is pretty much only used for byte[]/int[]/string.
        public override Expression HandleDirectlyMappedType(string tagName, PropertyInfo property, NullPolicy selfPolicy)
        {
            // declare a local var, which will hold the property's value
            ParameterExpression varValue = Expression.Parameter(property.PropertyType);

            // Fallback path, in case value is null and NullPolicy is InsertDefaults
            Expression defaultVal = Expression.Constant(SerializationUtil.GetDefaultValue(property.PropertyType));
            // varRootTag.Add( new NbtTag(tagName, <defaultVal>) );
            Expression defaultValExpr =
                Expression.Call(varRootTag,
                                NbtCompoundAddMethod,
                                MakeNbtTagCtor(property.PropertyType,
                                               Expression.Constant(tagName, typeof(string)),
                                               defaultVal));

            // varRootTag.Add( new NbtTag(tagName, <varValue>) );
            Expression makeTagExpr =
                Expression.Call(varRootTag,
                                NbtCompoundAddMethod,
                                MakeNbtTagCtor(property.PropertyType,
                                               Expression.Constant(tagName, typeof(string)),
                                               varValue));

            // Getter for the property value
            Expression getPropertyExpr = Expression.MakeMemberAccess(argValue, property);

            // generate the appropriate enclosing expressions, depending on NullPolicy
            return(NbtCompiler.MakeNullHandler(varValue, getPropertyExpr, selfPolicy,
                                               makeTagExpr, defaultValExpr, MakePropertyNullMessage(property)));
        }
Пример #2
0
        Expression MakeNbtTagHandler([NotNull] Type tagType, [NotNull] Type valueType, [NotNull] Expression tagNameExpr,
                                     [NotNull] Expression getPropertyExpr, NullPolicy selfPolicy,
                                     [NotNull] String nullMsg,
                                     [NotNull] Func <ParameterExpression, Expression> conversionFunc,
                                     [NotNull] Func <Expression, Expression> processTagExpr)
        {
            // declare a local var, which will hold the property's value
            ParameterExpression varValue = Expression.Parameter(valueType, "value");

            // Primary path, adds the root tag of the NbtFile
            Expression makeTagExpr = processTagExpr(conversionFunc(varValue));

            // Fallback path, in case value is null and NullPolicy is InsertDefaults
            ConstructorInfo tagCtor;

            if (tagType == typeof(NbtTag))
            {
                tagCtor = NbtCompoundCtor;
            }
            else
            {
                tagCtor = tagType.GetConstructor(new[] { typeof(string) });
            }
            Expression defaultVal     = Expression.New(tagCtor, tagNameExpr);
            Expression defaultValExpr = processTagExpr(defaultVal);

            // Generate the appropriate enclosing expressions, which choose path depending on NullPolicy
            return(NbtCompiler.MakeNullHandler(varValue, getPropertyExpr, selfPolicy,
                                               makeTagExpr, defaultValExpr, nullMsg));
        }
Пример #3
0
        public override Expression HandleINbtSerializable(string tagName, PropertyInfo property, NullPolicy selfPolicy)
        {
            MethodInfo          serializeMethod = property.PropertyType.GetMethod("Serialize", new[] { typeof(string) });
            ParameterExpression varValue        = Expression.Parameter(property.PropertyType, "value");
            string nullMsg = MakePropertyNullMessage(property);

            // rootTag.Add( value.Serialize() )
            Expression serializeExpr = Expression.Call(
                varRootTag, NbtCompoundAddMethod,
                Expression.Call(varValue, serializeMethod, Expression.Constant(tagName)));

            // Fallback path, in case value is null and NullPolicy is InsertDefaults
            Expression defaultExpr = Expression.New(NbtCompoundCtor, Expression.Constant(tagName));

            // Getter for the property value
            Expression propValue = Expression.MakeMemberAccess(argValue, property);

            return(NbtCompiler.MakeNullHandler(varValue, propValue, selfPolicy, serializeExpr, defaultExpr, nullMsg));
        }
Пример #4
0
        Expression MakeElementHandler([NotNull] Type elementType, [NotNull] Expression tagNameExpr,
                                      [NotNull] Expression tagValueExpr,
                                      NullPolicy elementPolicy, [NotNull] string nullElementMsg,
                                      [NotNull] Func <Expression, Expression> addTagExprFunc)
        {
            if (tagValueExpr.Type != elementType)
            {
                // In case value getter's return type is different from value return type (e.g. Array.GetValue(int))
                tagValueExpr = Expression.Convert(tagValueExpr, elementType);
            }

            if (elementType.IsPrimitive || elementType.IsEnum)
            {
                //=== Serializing primitives and enums ===
                // tag.Add( new NbtTag(kvp.Key, kvp.Value) );
                return(addTagExprFunc(MakeNbtTagCtor(elementType, tagNameExpr, tagValueExpr)));
            }
            else if (SerializationUtil.IsDirectlyMappedType(elementType))
            {
                //=== Serializing directly-mapped reference types (byte[], int[], string) ===
                // declare a local var, which will hold the property's value
                ParameterExpression varElementValue = Expression.Parameter(elementType, "elementValue");

                // Primary path, in case element value is not null:
                // iDictTag.Add(new NbtTag(kvp.Key, <getValueExpr>));
                Expression addElementExpr =
                    addTagExprFunc(MakeNbtTagCtor(elementType, tagNameExpr, tagValueExpr));

                // Fallback path, in case element value is null and elementPolicy is InsertDefaults:
                // Add a default-value tag to the list: listTag.Add(new NbtTag(null, <default>))
                Expression defaultValExpr     = Expression.Constant(SerializationUtil.GetDefaultValue(elementType));
                Expression defaultElementExpr =
                    addTagExprFunc(MakeNbtTagCtor(elementType, tagNameExpr, defaultValExpr));

                // generate the appropriate enclosing expressions, depending on NullPolicy
                return(NbtCompiler.MakeNullHandler(varElementValue, tagValueExpr, elementPolicy,
                                                   addElementExpr, defaultElementExpr, nullElementMsg));
            }
            else
            {
                //=== Serializing everything else ===
                // Check if this is an IList-of-ILists
                Type iListImpl = SerializationUtil.GetGenericInterfaceImpl(elementType, typeof(IList <>));
                Type iDictImpl = SerializationUtil.GetStringIDictionaryImpl(elementType);

                // check if this type can handle its own serialization
                if (typeof(INbtSerializable).IsAssignableFrom(elementType))
                {
                    // element is INbtSerializable
                    MethodInfo serializeMethod = elementType.GetMethod("Serialize", new[] { typeof(string) });
                    Expression newTagExpr      = Expression.Call(tagValueExpr, serializeMethod, tagNameExpr);
                    return(addTagExprFunc(newTagExpr));
                }
                else if (typeof(NbtTag).IsAssignableFrom(elementType))
                {
                    // element is NbtTag
                    return(MakeNbtTagHandler(
                               elementType, elementType, tagNameExpr, tagValueExpr, elementPolicy, nullElementMsg,
                               expr => expr, addTagExprFunc));
                }
                else if (typeof(NbtFile).IsAssignableFrom(elementType))
                {
                    // element is NbtFile
                    return(MakeNbtTagHandler(
                               typeof(NbtCompound), typeof(NbtFile), tagNameExpr, tagValueExpr, elementPolicy, nullElementMsg,
                               expr => Expression.MakeMemberAccess(expr, NbtFileRootTagProperty), addTagExprFunc));
                }
                else if (iListImpl != null)
                {
                    // element is IList<?>
                    Type subElementType = iListImpl.GetGenericArguments()[0];
                    return(MakeIListHandler(tagValueExpr, subElementType, tagNameExpr, elementPolicy,
                                            elementPolicy, nullElementMsg, nullElementMsg, addTagExprFunc));
                }
                else if (iDictImpl != null)
                {
                    // element is IDictionary<string,?>
                    return(MakeStringIDictionaryHandler(tagNameExpr, tagValueExpr, iDictImpl, elementPolicy,
                                                        elementPolicy, nullElementMsg, nullElementMsg, addTagExprFunc));
                }
                else
                {
                    // Get NbtSerialize<T> method for elementType
                    Expression makeElementTagExpr = callResolver.MakeCall(elementType, tagNameExpr, tagValueExpr);

                    // declare a local var, which will hold the element's value
                    ParameterExpression varElementValue = Expression.Parameter(elementType, "elementValue");

                    // Primary path, adds the newly-made Compound tag to our list
                    Expression addSerializedCompoundExpr = addTagExprFunc(makeElementTagExpr);

                    // Fallback path, in case element's value is null and NullPolicy is InsertDefaults
                    Expression addEmptyCompoundExpr =
                        addTagExprFunc(Expression.New(NbtCompoundCtor, tagNameExpr));

                    // Generate the appropriate enclosing expressions, which choose path depending on NullPolicy
                    return(NbtCompiler.MakeNullHandler(varElementValue, tagValueExpr, elementPolicy,
                                                       addSerializedCompoundExpr, addEmptyCompoundExpr, nullElementMsg));
                }
            }
        }
Пример #5
0
        Expression MakeStringIDictionaryHandler([NotNull] Expression tagNameExpr, [NotNull] Expression getIDictExpr,
                                                [NotNull] Type iDictImpl,
                                                NullPolicy selfPolicy, NullPolicy elementPolicy,
                                                [NotNull] string selfNullMsg, [NotNull] string elementNullMsg,
                                                [NotNull] Func <Expression, Expression> processTagExpr)
        {
            Type elementType = iDictImpl.GetGenericArguments()[1];

            // find type of KeyValuePair<string,?> that the enumerator will return
            Type         kvpType   = typeof(KeyValuePair <,>).MakeGenericType(iDictImpl.GetGenericArguments());
            PropertyInfo keyProp   = kvpType.GetProperty("Key");
            PropertyInfo valueProp = kvpType.GetProperty("Value");

            // locate IDictionary.GetEnumerator()
            Type       enumerableType    = typeof(IEnumerable <>).MakeGenericType(kvpType);
            Type       enumeratorType    = typeof(IEnumerator <>).MakeGenericType(kvpType);
            MethodInfo getEnumeratorImpl =
                SerializationUtil.GetGenericInterfaceMethodImpl(
                    iDictImpl, enumerableType, "GetEnumerator", Type.EmptyTypes);

            // locate IEnumerator.MoveNext()
            MethodInfo   moveNextMethod = typeof(IEnumerator).GetMethod("MoveNext");
            MethodInfo   disposeMethod  = typeof(IDisposable).GetMethod("Dispose");
            PropertyInfo currentProp    = enumeratorType.GetProperty("Current");

            ParameterExpression varIDict      = Expression.Parameter(iDictImpl, "iDict");
            ParameterExpression varCompTag    = Expression.Parameter(typeof(NbtCompound), "compTag");
            ParameterExpression varEnumerator = Expression.Parameter(enumeratorType, "enumerator");
            ParameterExpression varKvp        = Expression.Parameter(kvpType, "element");

            // generate handlers for individual elements
            Expression getNameExpr          = Expression.MakeMemberAccess(varKvp, keyProp);
            Expression getValueExpr         = Expression.MakeMemberAccess(varKvp, valueProp);
            Expression handleOneElementExpr = MakeElementHandler(
                elementType, getNameExpr, getValueExpr, elementPolicy, elementNullMsg,
                tag => Expression.Call(varCompTag, NbtCompoundAddMethod, tag));

            // Make glue code to hold everything together
            LabelTarget loopBreak = Expression.Label(typeof(void));

            Expression loopBody = Expression.Block(
                new[] { varKvp },
                Expression.Assign(varKvp, Expression.MakeMemberAccess(varEnumerator, currentProp)),
                handleOneElementExpr);

            Expression makeIDictTagExpr =
                Expression.Block(
                    new[] { varCompTag, varEnumerator },

                    // varCompTag = new NbtCompound(tagName)
                    Expression.Assign(varCompTag, Expression.New(NbtCompoundCtor, tagNameExpr)),
                    // varEnumerator = iDict.GetEnumerator()
                    Expression.Assign(varEnumerator, Expression.Call(varIDict, getEnumeratorImpl)),

                    // try {
                    Expression.MakeTry(
                        typeof(void),
                        // while (enumerator.MoveNext()) <loopBody>;
                        Expression.Loop(
                            Expression.IfThenElse(Expression.Call(varEnumerator, moveNextMethod),
                                                  loopBody,
                                                  Expression.Break(loopBreak)),
                            loopBreak),

                        // } finally { enumerator.Dispose(); }
                        Expression.Call(varEnumerator, disposeMethod),
                        null, null),

                    processTagExpr(varCompTag));

            // default value (in case selfPolicy is InsertDefault): new NbtCompound(tagName)
            Expression defaultValExpr = Expression.New(NbtCompoundCtor, tagNameExpr);

            return(NbtCompiler.MakeNullHandler(varIDict, getIDictExpr, selfPolicy,
                                               makeIDictTagExpr, defaultValExpr, selfNullMsg));
        }
Пример #6
0
        Expression MakeIListHandler([NotNull] Expression getIListExpr, [NotNull] Type elementType,
                                    [NotNull] Expression tagNameExpr,
                                    NullPolicy selfPolicy, NullPolicy elementPolicy, [NotNull] string selfNullMsg,
                                    [NotNull] string elementNullMsg,
                                    [NotNull] Func <Expression, Expression> processTagExpr)
        {
            Type listType = getIListExpr.Type;

            // Declare locals
            ParameterExpression varIList   = Expression.Parameter(listType, "iList");
            ParameterExpression varListTag = Expression.Parameter(typeof(NbtList), "listTag");
            ParameterExpression varLength  = Expression.Parameter(typeof(int), "length");
            ParameterExpression varIndex   = Expression.Parameter(typeof(int), "i");

            // Find getters for this IList
            MethodInfo countGetterImpl, itemGetterImpl;

            if (listType.IsArray)
            {
                // Although Array claims to implement IList<>, there is no way to retrieve
                // the interface implementation: it's handled in an unusual way by the runtime.
                // So we have to resort to getting Length/GetValue instead of Count/Item
                countGetterImpl = listType.GetProperty("Length").GetGetMethod();
                itemGetterImpl  = listType.GetMethod("GetValue", new[] { typeof(int) });
            }
            else
            {
                // For non-array IList<> types, grab this.Count getter (which maps to get_Count())
                countGetterImpl = SerializationUtil.GetGenericInterfaceMethodImpl(
                    listType, typeof(ICollection <>), "get_Count", Type.EmptyTypes);
                // ...and the getter for indexer this[int], which maps to get_Item(int)
                itemGetterImpl = SerializationUtil.GetGenericInterfaceMethodImpl(
                    listType, typeof(IList <>), "get_Item", new[] { typeof(int) });
            }

            // Create handler for a single element
            Expression getElementExpr       = Expression.Call(varIList, itemGetterImpl, varIndex);
            Expression getCountExpr         = Expression.Call(varIList, countGetterImpl);
            Expression handleOneElementExpr = MakeElementHandler(
                elementType, NbtCompiler.NullStringExpr, getElementExpr, elementPolicy, elementNullMsg,
                tag => Expression.Call(varListTag, NbtListAddMethod, tag));

            // Arrange tag construction in a loop
            LabelTarget loopBreak = Expression.Label(typeof(void));
            Expression  mainLoop  =
                // while (true)
                Expression.Loop(
                    Expression.Block(
                        // if (i >= length) break;
                        Expression.IfThen(
                            Expression.GreaterThanOrEqual(varIndex, varLength),
                            Expression.Break(loopBreak)),

                        // <process and add one element to the list>
                        handleOneElementExpr,

                        // ++i;
                        Expression.PreIncrementAssign(varIndex)),
                    loopBreak);

            // new NbtList(tagName, NbtTagType.*)
            ConstructorInfo listTagCtor =
                typeof(NbtList).GetConstructor(new[] { typeof(string), typeof(NbtTagType) });
            Expression makeListTagExpr =
                Expression.New(listTagCtor, tagNameExpr, Expression.Constant(GetNbtTagType(elementType)));

            // Fallback path, in case value our IList null and NullPolicy is InsertDefaults:
            // Add an empty list to root.
            Expression defaultValExpr = processTagExpr(makeListTagExpr);

            // Primary path, in case our IList is not null:
            // Package the list-building loop into a neat block, with locals
            Expression makeTagExpr = Expression.Block(
                new[] { varListTag, varIndex, varLength },

                // NbtList listTag = new NbtList(tagName, NbtTagType.*);
                Expression.Assign(varListTag, makeListTagExpr),

                // int length = iList.Count;
                Expression.Assign(varLength, getCountExpr),

                // int i=0;
                Expression.Assign(varIndex, Expression.Constant(0)),

                // (fill the list tag)
                mainLoop,

                // rootTag.Add( listTag );
                processTagExpr(varListTag));

            // Generate the appropriate enclosing expressions, which choose path depending on NullPolicy
            return(NbtCompiler.MakeNullHandler(varIList, getIListExpr, selfPolicy,
                                               makeTagExpr, defaultValExpr, selfNullMsg));
        }