private XamlIlNodeEmitResult EmitCore(IXamlIlAstNode value, IXamlIlCodeGen codeGen)
        {
            XamlIlNodeEmitResult res = null;

            foreach (var e in _emitters)
            {
                if (e is IXamlIlAstNodeEmitter ve)
                {
                    res = ve.Emit(value, this, codeGen);
                    if (res != null)
                    {
                        return(res);
                    }
                }
            }

            if (value is IXamlIlAstEmitableNode en)
            {
                return(en.Emit(this, codeGen));
            }
            else
            {
                throw new XamlIlLoadException("Unable to find emitter for node type: " + value.GetType().FullName,
                                              value);
            }
        }
        public XamlIlNodeEmitResult Emit(IXamlIlAstNode value, IXamlIlCodeGen codeGen, IXamlIlType expectedType)
        {
            var res          = EmitCore(value, codeGen);
            var returnedType = res.ReturnType;

            if (returnedType != null || expectedType != null)
            {
                if (returnedType != null && expectedType == null)
                {
                    throw new XamlIlLoadException(
                              $"Emit of node {value} resulted in {returnedType.GetFqn()} while caller expected void", value);
                }

                if (expectedType != null && returnedType == null)
                {
                    throw new XamlIlLoadException(
                              $"Emit of node {value} resulted in void while caller expected {expectedType.GetFqn()}", value);
                }

                if (!expectedType.IsAssignableFrom(returnedType))
                {
                    throw new XamlIlLoadException(
                              $"Emit of node {value} resulted in  {returnedType.GetFqn()} which is not convertible to expected {expectedType.GetFqn()}",
                              value);
                }

                if (returnedType.IsValueType && !expectedType.IsValueType)
                {
                    codeGen.Generator.Emit(OpCodes.Box, returnedType);
                }
            }

            return(res);
        }
Пример #3
0
        public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlCodeGen codeGen)
        {
            var type   = TargetType.GetClrType();
            var member = ResolveMember(type);

            if (member is IXamlIlProperty prop)
            {
                codeGen.Generator.Emit(OpCodes.Call, prop.Getter);
                return(XamlIlNodeEmitResult.Type(prop.Getter.ReturnType));
            }
            else if (member is IXamlIlField field)
            {
                if (field.IsLiteral)
                {
                    var ftype = field.FieldType.IsEnum ? field.FieldType.GetEnumUnderlyingType() : field.FieldType;

                    if (ftype.Name == "UInt64" || ftype.Name == "Int64")
                    {
                        codeGen.Generator.Emit(OpCodes.Ldc_I8,
                                               TypeSystemHelpers.ConvertLiteralToLong(field.GetLiteralValue()));
                    }
                    else if (ftype.Name == "Double")
                    {
                        codeGen.Generator.Emit(OpCodes.Ldc_R8, (double)field.GetLiteralValue());
                    }
                    else if (ftype.Name == "Single")
                    {
                        codeGen.Generator.Emit(OpCodes.Ldc_R4, (float)field.GetLiteralValue());
                    }
                    else if (ftype.Name == "String")
                    {
                        codeGen.Generator.Emit(OpCodes.Ldstr, (string)field.GetLiteralValue());
                    }
                    else
                    {
                        codeGen.Generator.Emit(OpCodes.Ldc_I4,
                                               TypeSystemHelpers.ConvertLiteralToInt(field.GetLiteralValue()));
                    }
                }
                else
                {
                    codeGen.Generator.Emit(OpCodes.Ldsfld, field);
                }
                return(XamlIlNodeEmitResult.Type(field.FieldType));
            }
            else
            {
                throw new XamlIlLoadException(
                          $"Unable to resolve {Member} as static field, property, constant or enum value", this);
            }
        }
Пример #4
0
        public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlCodeGen codeGen)
        {
            var type   = Value.GetClrType();
            var method = _systemType.Methods.FirstOrDefault(m =>
                                                            m.Name == "GetTypeFromHandle" && m.Parameters.Count == 1 &&
                                                            m.Parameters[0].Name == "RuntimeTypeHandle");

            if (method == null)
            {
                throw new XamlIlTypeSystemException(
                          $"Unable to find GetTypeFromHandle(RuntimeTypeHandle) on {_systemType.GetFqn()}");
            }
            codeGen.Generator
            .Emit(OpCodes.Ldtoken, type)
            .Emit(OpCodes.Call, method);
            return(XamlIlNodeEmitResult.Type(_systemType));
        }
        /// <summary>
        /// populate = true:
        /// void Populate(IServiceProvider sp, T target);
        /// populate = false
        /// T Build(IServiceProvider sp);
        /// </summary>

        public void Compile(IXamlIlAstNode root, IXamlIlCodeGen codeGen, XamlIlContext context, bool populate)
        {
            var contextLocal = codeGen.Generator.DefineLocal(context.ContextType);

            codeGen.Generator
            .Emit(OpCodes.Ldarg_0)
            .Emit(OpCodes.Newobj, context.Constructor)
            .Emit(OpCodes.Stloc, contextLocal);
            var rootGrp     = (XamlIlValueWithManipulationNode)root;
            var emitContext = new XamlIlEmitContext(_configuration, context, contextLocal, Emitters);

            if (populate)
            {
                codeGen.Generator
                .Emit(OpCodes.Ldloc, contextLocal)
                .Emit(OpCodes.Ldarg_1)
                .Emit(OpCodes.Stfld, context.RootObjectField)
                .Emit(OpCodes.Ldarg_1);
                emitContext.Emit(rootGrp.Manipulation, codeGen, null);
                codeGen.Generator.Emit(OpCodes.Ret);
            }
            else
            {
                codeGen.Generator.Emit(OpCodes.Ldloc, contextLocal);
                emitContext.Emit(rootGrp.Value, codeGen, rootGrp.Value.Type.GetClrType());
                codeGen.Generator
                .Emit(OpCodes.Stfld, context.RootObjectField);

                codeGen.Generator
                .Emit(OpCodes.Ldloc, contextLocal)
                .Emit(OpCodes.Ldfld, context.RootObjectField)
                .Emit(OpCodes.Dup);
                emitContext.Emit(rootGrp.Manipulation, codeGen, null);
                codeGen.Generator.Emit(OpCodes.Ret);
            }
        }
Пример #6
0
 public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlCodeGen codeGen)
 {
     if (Constant is string)
     {
         codeGen.Generator.Emit(OpCodes.Ldstr, (string)Constant);
     }
     else if (Constant is long || Constant is ulong)
     {
         codeGen.Generator.Emit(OpCodes.Ldc_I8, TypeSystemHelpers.ConvertLiteralToLong(Constant));
     }
     else if (Constant is float f)
     {
         codeGen.Generator.Emit(OpCodes.Ldc_R4, f);
     }
     else if (Constant is double d)
     {
         codeGen.Generator.Emit(OpCodes.Ldc_R8, d);
     }
     else
     {
         codeGen.Generator.Emit(OpCodes.Ldc_I4, TypeSystemHelpers.ConvertLiteralToInt(Constant));
     }
     return(XamlIlNodeEmitResult.Type(Type.GetClrType()));
 }
Пример #7
0
        public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen)
        {
            if (!(node is XamlIlPropertyValueManipulationNode pvm))
            {
                return(null);
            }
            codeGen.Generator.Emit(pvm.Property.Getter.IsStatic ? OpCodes.Call : OpCodes.Callvirt,
                                   pvm.Property.Getter);
            context.Emit(pvm.Manipulation, codeGen, null);

            return(XamlIlNodeEmitResult.Void);
        }
        public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen)
        {
            if (!(node is XamlIlManipulationGroupNode group))
            {
                return(null);
            }
            if (group.Children.Count == 0)
            {
                codeGen.Generator.Emit(OpCodes.Pop);
            }
            else
            {
                for (var c = 0; c < group.Children.Count; c++)
                {
                    if (c != group.Children.Count - 1)
                    {
                        codeGen.Generator.Emit(OpCodes.Dup);
                    }
                    context.Emit(group.Children[c], codeGen, null);
                }
            }

            return(XamlIlNodeEmitResult.Void);
        }
Пример #9
0
        public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen)
        {
            if (!(node is XamlIlAstNewClrObjectNode n))
            {
                return(null);
            }
            var type = n.Type.GetClrType();

            var argTypes = n.Arguments.Select(a => a.Type.GetClrType()).ToList();
            var ctor     = type.FindConstructor(argTypes);

            if (ctor == null)
            {
                throw new XamlIlLoadException(
                          $"Unable to find public constructor for type {type.GetFqn()}({string.Join(", ", argTypes.Select(at => at.GetFqn()))})",
                          n);
            }

            for (var c = 0; c < n.Arguments.Count; c++)
            {
                var ctorArg = n.Arguments[c];
                context.Emit(ctorArg, codeGen, ctor.Parameters[c]);
            }

            var gen = codeGen.Generator
                      .Emit(OpCodes.Newobj, ctor);


            return(XamlIlNodeEmitResult.Type(type));
        }
Пример #10
0
        public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen)
        {
            if (!(node is XamlIlInstanceMethodCallBaseNode mc))
            {
                return(null);
            }
            for (var c = 0; c < mc.Arguments.Count; c++)
            {
                context.Emit(mc.Arguments[c], codeGen, mc.Method.Parameters[c]);
            }
            codeGen.Generator.Emit(mc.Method.IsStatic ? OpCodes.Call : OpCodes.Callvirt, mc.Method);

            var isVoid = mc.Method.ReturnType.Equals(context.Configuration.WellKnownTypes.Void);

            if (mc is XamlIlInstanceNoReturnMethodCallNode && !isVoid)
            {
                codeGen.Generator.Emit(OpCodes.Pop);
            }
            if (mc is XamlIlStaticReturnMethodCallNode && isVoid)
            {
                throw new XamlIlLoadException(
                          $"XamlIlStaticReturnMethodCallNode expects a value while {mc.Method.Name} returns void", node);
            }

            return(isVoid ? XamlIlNodeEmitResult.Void : XamlIlNodeEmitResult.Type(mc.Method.ReturnType));
        }
Пример #11
0
        public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen)
        {
            if (!(node is XamlIlValueWithManipulationNode vwm))
            {
                return(null);
            }
            var created = context.Emit(vwm.Value, codeGen, vwm.Type.GetClrType());

            if (vwm.Manipulation != null &&
                !(vwm.Manipulation is XamlIlManipulationGroupNode grp && grp.Children.Count == 0))
            {
                codeGen.Generator.Emit(OpCodes.Dup);
                context.Emit(vwm.Manipulation, codeGen, null);
            }
            return(XamlIlNodeEmitResult.Type(created.ReturnType));
        }
        public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen)
        {
            if (!(node is XamlIlPropertyAssignmentNode an))
            {
                return(null);
            }
            var callOp = an.Property.Setter.IsStatic ? OpCodes.Call : OpCodes.Callvirt;

            context.Emit(an.Value, codeGen, an.Property.Setter.Parameters.Last());
            codeGen.Generator.Emit(callOp, an.Property.Setter);

            return(XamlIlNodeEmitResult.Void);
        }
Пример #13
0
 public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlCodeGen codeGen)
 {
     codeGen.Generator.Emit(OpCodes.Ldnull);
     return(XamlIlNodeEmitResult.Type(XamlIlPseudoType.Null));
 }
Пример #14
0
        public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen)
        {
            if (!(node is XamlIlMarkupExtensionNode me))
            {
                return(null);
            }


            var ptype = me.Manipulation?.Parameters[0] ?? me.Property.PropertyType;
            var rtype = me.ProvideValue.ReturnType;

            context.Emit(me.Value, codeGen, me.Value.Type.GetClrType());
            if (me.ProvideValue.Parameters.Count != 0)
            {
                //TODO: IProvideValueTarget
                codeGen.Generator
                .Emit(OpCodes.Ldloc, context.ContextLocal);
            }

            var resultLocal = codeGen.Generator.DefineLocal(rtype);

            codeGen.Generator
            .Emit(OpCodes.Call, me.ProvideValue)
            .Emit(OpCodes.Stloc, resultLocal);

            IXamlIlEmitter CallSetter()
            {
                if (me.Manipulation != null)
                {
                    // {target}.{Property}.{Method)(res)
                    var res = codeGen.Generator.DefineLocal(ptype);
                    if (me.Property != null)
                    {
                        codeGen.Generator
                        .Emit(OpCodes.Stloc, res)
                        .EmitCall(me.Property.Getter)
                        .Emit(OpCodes.Ldloc, res);
                    }
                    codeGen.Generator
                    .EmitCall(me.Manipulation, true);
                    return(codeGen.Generator);
                }

                return(codeGen.Generator.EmitCall(me.Property.Setter));
            }

            // Now we have the value returned by markup extension in resultLocal


            //Simplest case: exact type match
            if (ptype.Equals(rtype))
            {
                codeGen.Generator
                .Emit(OpCodes.Ldloc, resultLocal);
                CallSetter();
                return(XamlIlNodeEmitResult.Void);
            }
            var exit = codeGen.Generator.DefineLabel();


            if (ptype.IsValueType && rtype.IsValueType)
            {
                // If both are value types, try convert non-nullable to nullable
                if (ptype.IsNullableOf(rtype))
                {
                    codeGen.Generator
                    .Emit(OpCodes.Ldloc, resultLocal)
                    .Emit(OpCodes.Newobj,
                          ptype.Constructors.First(c =>
                                                   c.Parameters.Count == 1 && c.Parameters[0].Equals(rtype)));
                    CallSetter();
                    return(XamlIlNodeEmitResult.Void);
                }
            }
            else if (rtype.IsValueType && !ptype.IsValueType)
            {
                // If target is object, simply box
                if (ptype.Equals(context.Configuration.WellKnownTypes.Object))
                {
                    codeGen.Generator
                    .Emit(OpCodes.Ldloc, resultLocal)
                    .Emit(OpCodes.Box, rtype);
                    CallSetter();
                    return(XamlIlNodeEmitResult.Void);
                }
            }
            else if (ptype.IsValueType)
            {
                // Cast attempt only makes sense if it's an object
                if (rtype.Equals(context.Configuration.WellKnownTypes.Object))
                {
                    var notMatchedType = codeGen.Generator.DefineLabel();
                    codeGen.Generator
                    .Emit(OpCodes.Ldloc, resultLocal)
                    .Emit(OpCodes.Isinst, ptype)
                    .Emit(OpCodes.Brfalse, notMatchedType)
                    .Emit(OpCodes.Ldloc, resultLocal)
                    .Emit(OpCodes.Unbox_Any, ptype);
                    CallSetter()
                    .Emit(OpCodes.Br, exit)
                    .MarkLabel(notMatchedType);
                }
            }
            else
            {
                // if(res==null) target.Property = null;
                var notNull = codeGen.Generator.DefineLabel();
                codeGen.Generator
                .Emit(OpCodes.Ldloc, resultLocal)
                .Emit(OpCodes.Brtrue, notNull)
                .Emit(OpCodes.Ldloc, resultLocal);
                CallSetter()
                .Emit(OpCodes.Br, exit)
                .MarkLabel(notNull);

                // if (res is T matched)  target.Property = matched;
                var nonMatchedType = codeGen.Generator.DefineLabel();
                codeGen.Generator
                .Emit(OpCodes.Ldloc, resultLocal)
                .Emit(OpCodes.Isinst, ptype)
                .Emit(OpCodes.Dup)
                .Emit(OpCodes.Brfalse, nonMatchedType);
                CallSetter();
                codeGen.Generator.Emit(OpCodes.Br, exit)
                .MarkLabel(nonMatchedType)
                .Emit(OpCodes.Pop);
            }

            // Cast attempts have failed, call external method
            codeGen.Generator
            .Emit(OpCodes.Ldstr, me.Property?.Name)
            .Emit(OpCodes.Ldloc, context.ContextLocal)
            .Emit(OpCodes.Ldloc, resultLocal);
            if (rtype.IsValueType)
            {
                codeGen.Generator.Emit(OpCodes.Box, rtype);
            }
            codeGen.Generator
            .Emit(OpCodes.Call, context.Configuration.TypeMappings.ApplyNonMatchingMarkupExtension)
            .Emit(OpCodes.Br, exit);


            codeGen.Generator.MarkLabel(exit);
            return(XamlIlNodeEmitResult.Void);
        }
Пример #15
0
 public XamlIlNodeEmitResult Emit(IXamlIlAstNode node, XamlIlEmitContext context, IXamlIlCodeGen codeGen)
 {
     if (!(node is XamlIlAstTextNode text))
     {
         return(null);
     }
     if (!text.Type.GetClrType().Equals(context.Configuration.WellKnownTypes.String))
     {
         throw new XamlIlLoadException("Text node type wasn't resolved to well-known System.String", node);
     }
     codeGen.Generator.Emit(OpCodes.Ldstr, text.Text);
     return(XamlIlNodeEmitResult.Type(text.Type.GetClrType()));
 }