Ejemplo n.º 1
0
        public void Visit(ElementNode node, INode parentNode)
        {
            XmlName propertyName = XmlName.Empty;

            //Simplify ListNodes with single elements
            var pList = parentNode as ListNode;

            if (pList != null && pList.CollectionItems.Count == 1)
            {
                propertyName = pList.XmlName;
                parentNode   = parentNode.Parent;
            }

            //if this node is an IMarkupExtension, invoke ProvideValue() and replace the variable
            var vardef    = Context.Variables[node];
            var vardefref = new VariableDefinitionReference(vardef);

            Context.IL.Append(ProvideValue(vardefref, Context, Module, node));
            if (vardef != vardefref.VariableDefinition)
            {
                vardef = vardefref.VariableDefinition;
                Context.Body.Variables.Add(vardef);
                Context.Variables[node] = vardef;
            }

            if (propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName))
            {
                if (skips.Contains(propertyName))
                {
                    return;
                }

                if (propertyName == XmlName._CreateContent)
                {
                    SetDataTemplate((IElementNode)parentNode, node, Context, node);
                }
                else
                {
                    Context.IL.Append(SetPropertyValue(Context.Variables[(IElementNode)parentNode], propertyName, node, Context, node));
                }
            }
            else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode)
            {
                // Collection element, implicit content, or implicit collection element.
                string contentProperty;
                var    parentVar = Context.Variables[(IElementNode)parentNode];
                if (parentVar.VariableType.ImplementsInterface(Module.Import(typeof(IEnumerable))))
                {
                    var elementType = parentVar.VariableType;
                    if (elementType.FullName != "Xamarin.Forms.ResourceDictionary" && elementType.Resolve().BaseType.FullName != "Xamarin.Forms.ResourceDictionary")
                    {
                        var adderTuple = elementType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).First();
                        var adderRef   = Module.Import(adderTuple.Item1);
                        adderRef = Module.Import(adderRef.ResolveGenericParameters(adderTuple.Item2, Module));

                        Context.IL.Emit(OpCodes.Ldloc, parentVar);
                        Context.IL.Emit(OpCodes.Ldloc, vardef);
                        Context.IL.Emit(OpCodes.Callvirt, adderRef);
                        if (adderRef.ReturnType.FullName != "System.Void")
                        {
                            Context.IL.Emit(OpCodes.Pop);
                        }
                    }
                }
                else if ((contentProperty = GetContentProperty(parentVar.VariableType)) != null)
                {
                    var name = new XmlName(node.NamespaceURI, contentProperty);
                    if (skips.Contains(name))
                    {
                        return;
                    }
                    Context.IL.Append(SetPropertyValue(Context.Variables[(IElementNode)parentNode], name, node, Context, node));
                }
            }
            else if (IsCollectionItem(node, parentNode) && parentNode is ListNode)
            {
//				IL_000d:  ldloc.2
//				IL_000e:  callvirt instance class [mscorlib]System.Collections.Generic.IList`1<!0> class [Xamarin.Forms.Core]Xamarin.Forms.Layout`1<class [Xamarin.Forms.Core]Xamarin.Forms.View>::get_Children()
//				IL_0013:  ldloc.0
//				IL_0014:  callvirt instance void class [mscorlib]System.Collections.Generic.ICollection`1<class [Xamarin.Forms.Core]Xamarin.Forms.View>::Add(!0)

                var parentList = (ListNode)parentNode;
                var parent     = Context.Variables[((IElementNode)parentNode.Parent)];

                if (skips.Contains(parentList.XmlName))
                {
                    return;
                }

                var elementType = parent.VariableType;
                var localname   = parentList.XmlName.LocalName;

                GetNameAndTypeRef(ref elementType, parentList.XmlName.NamespaceURI, ref localname, Context, node);

                TypeReference    propertyDeclaringType;
                var              property = elementType.GetProperty(pd => pd.Name == localname, out propertyDeclaringType);
                MethodDefinition propertyGetter;

                if (property != null && (propertyGetter = property.GetMethod) != null && propertyGetter.IsPublic)
                {
                    var propertyGetterRef = Module.Import(propertyGetter);
                    propertyGetterRef = Module.Import(propertyGetterRef.ResolveGenericParameters(propertyDeclaringType, Module));
                    var propertyType = propertyGetterRef.ReturnType.ResolveGenericParameters(propertyDeclaringType);

                    var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).First();
                    var adderRef   = Module.Import(adderTuple.Item1);
                    adderRef = Module.Import(adderRef.ResolveGenericParameters(adderTuple.Item2, Module));

                    Context.IL.Emit(OpCodes.Ldloc, parent);
                    Context.IL.Emit(OpCodes.Callvirt, propertyGetterRef);
                    Context.IL.Emit(OpCodes.Ldloc, vardef);
                    Context.IL.Emit(OpCodes.Callvirt, adderRef);
                    if (adderRef.ReturnType.FullName != "System.Void")
                    {
                        Context.IL.Emit(OpCodes.Pop);
                    }
                }
                else
                {
                    throw new XamlParseException(string.Format("Property {0} not found", localname), node);
                }
            }
        }
Ejemplo n.º 2
0
        public void Visit(ElementNode node, INode parentNode)
        {
            var            typeref = Module.Import(node.XmlType.GetTypeReference(Module, node));
            TypeDefinition typedef = typeref.Resolve();

            if (IsXaml2009LanguagePrimitive(node))
            {
                var vardef = new VariableDefinition(typeref);
                Context.Variables [node] = vardef;
                Context.Body.Variables.Add(vardef);

                Context.IL.Append(PushValueFromLanguagePrimitive(typedef, node));
                Context.IL.Emit(OpCodes.Stloc, vardef);
                return;
            }

            if (typeref.FullName == "Xamarin.Forms.Xaml.StaticExtension")
            {
                var markupProvider = new StaticExtension();

                var il = markupProvider.ProvideValue(node, Module, Context, out typeref);
                typeref = Module.Import(typeref);

                var vardef = new VariableDefinition(typeref);
                Context.Variables [node] = vardef;
                Context.Body.Variables.Add(vardef);

                Context.IL.Append(il);
                Context.IL.Emit(OpCodes.Stloc, vardef);

                //clean the node as it has been fully exhausted
                node.Properties.Clear();
                node.CollectionItems.Clear();
                return;
            }

            MethodDefinition factoryCtorInfo       = null;
            MethodDefinition factoryMethodInfo     = null;
            MethodDefinition parameterizedCtorInfo = null;
            MethodDefinition ctorInfo = null;

            if (node.Properties.ContainsKey(XmlName.xArguments) && !node.Properties.ContainsKey(XmlName.xFactoryMethod))
            {
                factoryCtorInfo = typedef.AllMethods().FirstOrDefault(md => md.IsConstructor &&
                                                                      !md.IsStatic &&
                                                                      md.HasParameters &&
                                                                      md.MatchXArguments(node, Module, Context));
                if (factoryCtorInfo == null)
                {
                    throw new XamlParseException(
                              string.Format("No constructors found for {0} with matching x:Arguments", typedef.FullName), node);
                }
                ctorInfo = factoryCtorInfo;
                if (!typedef.IsValueType)                 //for ctor'ing typedefs, we first have to ldloca before the params
                {
                    Context.IL.Append(PushCtorXArguments(factoryCtorInfo, node));
                }
            }
            else if (node.Properties.ContainsKey(XmlName.xFactoryMethod))
            {
                var factoryMethod = (string)(node.Properties [XmlName.xFactoryMethod] as ValueNode).Value;
                factoryMethodInfo = typedef.AllMethods().FirstOrDefault(md => !md.IsConstructor &&
                                                                        md.Name == factoryMethod &&
                                                                        md.IsStatic &&
                                                                        md.MatchXArguments(node, Module, Context));
                if (factoryMethodInfo == null)
                {
                    throw new XamlParseException(
                              String.Format("No static method found for {0}::{1} ({2})", typedef.FullName, factoryMethod, null), node);
                }
                Context.IL.Append(PushCtorXArguments(factoryMethodInfo, node));
            }
            if (ctorInfo == null && factoryMethodInfo == null)
            {
                parameterizedCtorInfo = typedef.Methods.FirstOrDefault(md => md.IsConstructor &&
                                                                       !md.IsStatic &&
                                                                       md.HasParameters &&
                                                                       md.Parameters.All(
                                                                           pd =>
                                                                           pd.CustomAttributes.Any(
                                                                               ca =>
                                                                               ca.AttributeType.FullName ==
                                                                               "Xamarin.Forms.ParameterAttribute")));
            }
            if (parameterizedCtorInfo != null && ValidateCtorArguments(parameterizedCtorInfo, node))
            {
                ctorInfo = parameterizedCtorInfo;
//				IL_0000:  ldstr "foo"
                Context.IL.Append(PushCtorArguments(parameterizedCtorInfo, node));
            }
            ctorInfo = ctorInfo ?? typedef.Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters && !md.IsStatic);

            var ctorinforef          = ctorInfo?.ResolveGenericParameters(typeref, Module);
            var factorymethodinforef = factoryMethodInfo?.ResolveGenericParameters(typeref, Module);
            var implicitOperatorref  = typedef.Methods.FirstOrDefault(md =>
                                                                      md.IsPublic &&
                                                                      md.IsStatic &&
                                                                      md.IsSpecialName &&
                                                                      md.Name == "op_Implicit" && md.Parameters [0].ParameterType.FullName == "System.String");

            if (ctorinforef != null || factorymethodinforef != null || typedef.IsValueType)
            {
                VariableDefinition vardef = new VariableDefinition(typeref);
                Context.Variables [node] = vardef;
                Context.Body.Variables.Add(vardef);

                ValueNode vnode = null;
                if (node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null &&
                    vardef.VariableType.IsValueType)
                {
                    //<Color>Purple</Color>
                    Context.IL.Append(vnode.PushConvertedValue(Context, typeref, new ICustomAttributeProvider [] { typedef },
                                                               node.PushServiceProvider(Context), false, true));
                    Context.IL.Emit(OpCodes.Stloc, vardef);
                }
                else if (node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null &&
                         implicitOperatorref != null)
                {
                    //<FileImageSource>path.png</FileImageSource>
                    var implicitOperator = Module.Import(implicitOperatorref);
                    Context.IL.Emit(OpCodes.Ldstr, ((ValueNode)(node.CollectionItems.First())).Value as string);
                    Context.IL.Emit(OpCodes.Call, implicitOperator);
                    Context.IL.Emit(OpCodes.Stloc, vardef);
                }
                else if (factorymethodinforef != null)
                {
                    Context.IL.Emit(OpCodes.Call, Module.Import(factorymethodinforef));
                    Context.IL.Emit(OpCodes.Stloc, vardef);
                }
                else if (!typedef.IsValueType)
                {
                    var ctor = Module.Import(ctorinforef);
//					IL_0001:  newobj instance void class [Xamarin.Forms.Core]Xamarin.Forms.Button::'.ctor'()
//					IL_0006:  stloc.0
                    Context.IL.Emit(OpCodes.Newobj, ctor);
                    Context.IL.Emit(OpCodes.Stloc, vardef);
                }
                else if (ctorInfo != null && node.Properties.ContainsKey(XmlName.xArguments) &&
                         !node.Properties.ContainsKey(XmlName.xFactoryMethod) && ctorInfo.MatchXArguments(node, Module, Context))
                {
//					IL_0008:  ldloca.s 1
//					IL_000a:  ldc.i4.1
//					IL_000b:  call instance void valuetype Test/Foo::'.ctor'(bool)

                    var ctor = Module.Import(ctorinforef);
                    Context.IL.Emit(OpCodes.Ldloca, vardef);
                    Context.IL.Append(PushCtorXArguments(factoryCtorInfo, node));
                    Context.IL.Emit(OpCodes.Call, ctor);
                }
                else
                {
//					IL_0000:  ldloca.s 0
//					IL_0002:  initobj Test/Foo
                    Context.IL.Emit(OpCodes.Ldloca, vardef);
                    Context.IL.Emit(OpCodes.Initobj, Module.Import(typedef));
                }

                if (typeref.FullName == "Xamarin.Forms.Xaml.TypeExtension")
                {
                    var visitor = new SetPropertiesVisitor(Context);
                    foreach (var cnode in node.Properties.Values.ToList())
                    {
                        cnode.Accept(visitor, node);
                    }
                    foreach (var cnode in node.CollectionItems)
                    {
                        cnode.Accept(visitor, node);
                    }

                    //As we're stripping the TypeExtension bare, keep the type if we need it later (hint: we do need it)
                    INode ntype;
                    if (!node.Properties.TryGetValue(new XmlName("", "TypeName"), out ntype))
                    {
                        ntype = node.CollectionItems [0];
                    }

                    var type   = ((ValueNode)ntype).Value as string;
                    var prefix = "";
                    if (type.Contains(":"))
                    {
                        prefix = type.Split(':') [0].Trim();
                        type   = type.Split(':') [1].Trim();
                    }
                    var namespaceuri = node.NamespaceResolver.LookupNamespace(prefix);
                    Context.TypeExtensions [node] = new XmlType(namespaceuri, type, null).GetTypeReference(Module, node);

                    if (!node.SkipProperties.Contains(new XmlName("", "TypeName")))
                    {
                        node.SkipProperties.Add(new XmlName("", "TypeName"));
                    }

                    var vardefref = new VariableDefinitionReference(vardef);
                    Context.IL.Append(SetPropertiesVisitor.ProvideValue(vardefref, Context, Module, node));
                    if (vardef != vardefref.VariableDefinition)
                    {
                        Context.Variables [node] = vardefref.VariableDefinition;
                        Context.Body.Variables.Add(vardefref.VariableDefinition);
                    }
                }

                if (typeref.FullName == "Xamarin.Forms.Xaml.ArrayExtension")
                {
                    var visitor = new SetPropertiesVisitor(Context);
                    foreach (var cnode in node.Properties.Values.ToList())
                    {
                        cnode.Accept(visitor, node);
                    }
                    foreach (var cnode in node.CollectionItems)
                    {
                        cnode.Accept(visitor, node);
                    }

                    var markupProvider = new ArrayExtension();

                    var il = markupProvider.ProvideValue(node, Module, Context, out typeref);

                    vardef = new VariableDefinition(typeref);
                    Context.Variables[node] = vardef;
                    Context.Body.Variables.Add(vardef);

                    Context.IL.Append(il);
                    Context.IL.Emit(OpCodes.Stloc, vardef);

                    //clean the node as it has been fully exhausted
                    node.Properties.Remove(new XmlName("", "Type"));
                    node.CollectionItems.Clear();
                }
            }
        }
Ejemplo n.º 3
0
        public static IEnumerable <Instruction> ProvideValue(VariableDefinitionReference vardefref, ILContext context,
                                                             ModuleDefinition module, ElementNode node)
        {
            GenericInstanceType   markupExtension;
            IList <TypeReference> genericArguments;

            if (vardefref.VariableDefinition.VariableType.FullName == "Xamarin.Forms.Xaml.ArrayExtension" &&
                vardefref.VariableDefinition.VariableType.ImplementsGenericInterface("Xamarin.Forms.Xaml.IMarkupExtension`1",
                                                                                     out markupExtension, out genericArguments))
            {
                var markExt          = markupExtension.Resolve();
                var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
                var provideValue     = module.Import(provideValueInfo);
                provideValue =
                    module.Import(provideValue.ResolveGenericParameters(markupExtension, module));

                var           typeNode = node.Properties[new XmlName("", "Type")];
                TypeReference arrayTypeRef;
                if (context.TypeExtensions.TryGetValue(typeNode, out arrayTypeRef))
                {
                    vardefref.VariableDefinition = new VariableDefinition(module.Import(arrayTypeRef.MakeArrayType()));
                }
                else
                {
                    vardefref.VariableDefinition = new VariableDefinition(module.Import(genericArguments.First()));
                }
                yield return(Instruction.Create(OpCodes.Ldloc, context.Variables[node]));

                foreach (var instruction in node.PushServiceProvider(context))
                {
                    yield return(instruction);
                }
                yield return(Instruction.Create(OpCodes.Callvirt, provideValue));

                if (arrayTypeRef != null)
                {
                    yield return(Instruction.Create(OpCodes.Castclass, module.Import(arrayTypeRef.MakeArrayType())));
                }
                yield return(Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition));
            }
            else if (vardefref.VariableDefinition.VariableType.ImplementsGenericInterface("Xamarin.Forms.Xaml.IMarkupExtension`1",
                                                                                          out markupExtension, out genericArguments))
            {
                var markExt          = markupExtension.Resolve();
                var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
                var provideValue     = module.Import(provideValueInfo);
                provideValue =
                    module.Import(provideValue.ResolveGenericParameters(markupExtension, module));

                vardefref.VariableDefinition = new VariableDefinition(module.Import(genericArguments.First()));
                yield return(Instruction.Create(OpCodes.Ldloc, context.Variables[node]));

                foreach (var instruction in node.PushServiceProvider(context))
                {
                    yield return(instruction);
                }
                yield return(Instruction.Create(OpCodes.Callvirt, provideValue));

                yield return(Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition));
            }
            else if (context.Variables[node].VariableType.ImplementsInterface(module.Import(typeof(IMarkupExtension))))
            {
                var markExt          = module.Import(typeof(IMarkupExtension)).Resolve();
                var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
                var provideValue     = module.Import(provideValueInfo);

                vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object);
                yield return(Instruction.Create(OpCodes.Ldloc, context.Variables[node]));

                foreach (var instruction in node.PushServiceProvider(context))
                {
                    yield return(instruction);
                }
                yield return(Instruction.Create(OpCodes.Callvirt, provideValue));

                yield return(Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition));
            }
            else if (context.Variables[node].VariableType.ImplementsInterface(module.Import(typeof(IValueProvider))))
            {
                var markExt          = module.Import(typeof(IValueProvider)).Resolve();
                var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
                var provideValue     = module.Import(provideValueInfo);

                vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object);
                yield return(Instruction.Create(OpCodes.Ldloc, context.Variables[node]));

                foreach (var instruction in node.PushServiceProvider(context))
                {
                    yield return(instruction);
                }
                yield return(Instruction.Create(OpCodes.Callvirt, provideValue));

                yield return(Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition));
            }
        }
Ejemplo n.º 4
0
        public void Visit(ElementNode node, INode parentNode)
        {
            //Set Resources in ResourcesDictionaries
            if (IsCollectionItem(node, parentNode) && parentNode is IElementNode)
            {
                // Collection element, implicit content, or implicit collection element.
                CustomAttribute cpAttr;
                var             parentVar = Context.Variables[(IElementNode)parentNode];
                if (parentVar.VariableType.ImplementsInterface(Module.Import(typeof(IEnumerable))))
                {
                    if ((parentVar.VariableType.FullName == "Xamarin.Forms.ResourceDictionary" ||
                         parentVar.VariableType.Resolve().BaseType.FullName == "Xamarin.Forms.ResourceDictionary") &&
                        !node.Properties.ContainsKey(XmlName.xKey))
                    {
                        node.Accept(new SetPropertiesVisitor(Context), parentNode);

                        if (node.XmlType.Name != "Style")
                        {
                            throw new XamlParseException("resources in ResourceDictionary require a x:Key attribute", node);
                        }

                        //if this node is an IMarkupExtension, invoke ProvideValue() and replace the variable
                        var vardef    = Context.Variables[node];
                        var vardefref = new VariableDefinitionReference(vardef);
                        Context.IL.Append(SetPropertiesVisitor.ProvideValue(vardefref, Context, Module, node));
                        if (vardef != vardefref.VariableDefinition)
                        {
                            vardef = vardefref.VariableDefinition;
                            Context.Body.Variables.Add(vardef);
                            Context.Variables[node] = vardef;
                        }

                        Context.IL.Emit(OpCodes.Ldloc, parentVar);
                        Context.IL.Emit(OpCodes.Ldloc, Context.Variables[node]);
                        Context.IL.Emit(OpCodes.Callvirt,
                                        Module.Import(
                                            Module.Import(typeof(ResourceDictionary))
                                            .Resolve()
                                            .Methods.Single(md => md.Name == "Add" && md.Parameters.Count == 1)));
                    }
                    else if ((parentVar.VariableType.FullName == "Xamarin.Forms.ResourceDictionary" ||
                              parentVar.VariableType.Resolve().BaseType.FullName == "Xamarin.Forms.ResourceDictionary") &&
                             node.Properties.ContainsKey(XmlName.xKey))
                    {
                        node.Accept(new SetPropertiesVisitor(Context), parentNode);

                        //if this node is an IMarkupExtension, invoke ProvideValue() and replace the variable
                        var vardef    = Context.Variables[node];
                        var vardefref = new VariableDefinitionReference(vardef);
                        Context.IL.Append(SetPropertiesVisitor.ProvideValue(vardefref, Context, Module, node));
                        if (vardef != vardefref.VariableDefinition)
                        {
                            vardef = vardefref.VariableDefinition;
                            Context.Body.Variables.Add(vardef);
                            Context.Variables[node] = vardef;
                        }

                        //						IL_0013:  ldloc.0
                        //						IL_0014:  ldstr "key"
                        //						IL_0019:  ldstr "foo"
                        //						IL_001e:  callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.ResourceDictionary::Add(string, object)
                        Context.IL.Emit(OpCodes.Ldloc, parentVar);
                        Context.IL.Emit(OpCodes.Ldstr, (node.Properties[XmlName.xKey] as ValueNode).Value as string);
                        var varDef = Context.Variables[node];
                        Context.IL.Emit(OpCodes.Ldloc, varDef);
                        if (varDef.VariableType.IsValueType)
                        {
                            Context.IL.Emit(OpCodes.Box, Module.Import(varDef.VariableType));
                        }
                        Context.IL.Emit(OpCodes.Callvirt,
                                        Module.Import(
                                            Module.Import(typeof(ResourceDictionary))
                                            .Resolve()
                                            .Methods.Single(md => md.Name == "Add" && md.Parameters.Count == 2)));
                    }
                }
            }

            //Set ResourcesDictionaries to their parents
            XmlName propertyName;

            if (SetPropertiesVisitor.TryGetPropertyName(node, parentNode, out propertyName) &&
                (propertyName.LocalName == "Resources" || propertyName.LocalName.EndsWith(".Resources", StringComparison.Ordinal)) &&
                (Context.Variables[node].VariableType.FullName == "Xamarin.Forms.ResourceDictionary" ||
                 Context.Variables[node].VariableType.Resolve().BaseType.FullName == "Xamarin.Forms.ResourceDictionary"))
            {
                SetPropertiesVisitor.SetPropertyValue(Context.Variables[(IElementNode)parentNode], propertyName, node, Context, node);
            }
        }
Ejemplo n.º 5
0
		public void Visit(ElementNode node, INode parentNode)
		{
			if (node.SkipPrefix((node.NamespaceResolver ?? parentNode.NamespaceResolver)?.LookupPrefix(node.NamespaceURI)))
				return;

			//if this node is an IMarkupExtension, invoke ProvideValue() and replace the variable
			var vardef = Context.Variables[node];
			var vardefref = new VariableDefinitionReference(vardef);
			Context.IL.Append(ProvideValue(vardefref, Context, Module, node));
			if (vardef != vardefref.VariableDefinition)
			{
				vardef = vardefref.VariableDefinition;
				Context.Body.Variables.Add(vardef);
				Context.Variables[node] = vardef;
			}

			XmlName propertyName;
			if (TryGetPropertyName(node, parentNode, out propertyName))
			{
				if (skips.Contains(propertyName))
					return;

				if (propertyName == XmlName._CreateContent)
					SetDataTemplate((IElementNode)parentNode, node, Context, node);
				else
					SetPropertyValue(Context.Variables[(IElementNode)parentNode], propertyName, node, Context, node);
			}
			else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode)
			{
				// Collection element, implicit content, or implicit collection element.
				string contentProperty;
				var parentVar = Context.Variables[(IElementNode)parentNode];
				if (parentVar.VariableType.ImplementsInterface(Module.Import(typeof (IEnumerable))))
				{
					var elementType = parentVar.VariableType;
					if (elementType.FullName != "Xamarin.Forms.ResourceDictionary" && elementType.Resolve().BaseType.FullName != "Xamarin.Forms.ResourceDictionary")
					{
						var adderTuple = elementType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).First();
						var adderRef = Module.Import(adderTuple.Item1);
						adderRef = Module.Import(adderRef.ResolveGenericParameters(adderTuple.Item2, Module));

						Context.IL.Emit(OpCodes.Ldloc, parentVar);
						Context.IL.Emit(OpCodes.Ldloc, vardef);
						Context.IL.Emit(OpCodes.Callvirt, adderRef);
						if (adderRef.ReturnType.FullName != "System.Void")
							Context.IL.Emit(OpCodes.Pop);
					}
				}
				else if ((contentProperty = GetContentProperty(parentVar.VariableType)) != null)
				{
					var name = new XmlName(node.NamespaceURI, contentProperty);
					if (skips.Contains(name))
						return;
					SetPropertyValue(Context.Variables[(IElementNode)parentNode], name, node, Context, node);
				}
			}
			else if (IsCollectionItem(node, parentNode) && parentNode is ListNode)
			{
				//				IL_000d:  ldloc.2 
				//				IL_000e:  callvirt instance class [mscorlib]System.Collections.Generic.IList`1<!0> class [Xamarin.Forms.Core]Xamarin.Forms.Layout`1<class [Xamarin.Forms.Core]Xamarin.Forms.View>::get_Children()
				//				IL_0013:  ldloc.0 
				//				IL_0014:  callvirt instance void class [mscorlib]System.Collections.Generic.ICollection`1<class [Xamarin.Forms.Core]Xamarin.Forms.View>::Add(!0)

				var parentList = (ListNode)parentNode;
				var parent = Context.Variables[((IElementNode)parentNode.Parent)];

				if (skips.Contains(parentList.XmlName))
					return;

				var elementType = parent.VariableType;
				var localname = parentList.XmlName.LocalName;

				GetNameAndTypeRef(ref elementType, parentList.XmlName.NamespaceURI, ref localname, Context, node);

				TypeReference propertyDeclaringType;
				var property = elementType.GetProperty(pd => pd.Name == localname, out propertyDeclaringType);
				MethodDefinition propertyGetter;

				if (property != null && (propertyGetter = property.GetMethod) != null && propertyGetter.IsPublic)
				{
					var propertyGetterRef = Module.Import(propertyGetter);
					propertyGetterRef = Module.Import(propertyGetterRef.ResolveGenericParameters(propertyDeclaringType, Module));
					var propertyType = propertyGetterRef.ReturnType.ResolveGenericParameters(propertyDeclaringType);

					var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).First();
					var adderRef = Module.Import(adderTuple.Item1);
					adderRef = Module.Import(adderRef.ResolveGenericParameters(adderTuple.Item2, Module));

					Context.IL.Emit(OpCodes.Ldloc, parent);
					Context.IL.Emit(OpCodes.Callvirt, propertyGetterRef);
					Context.IL.Emit(OpCodes.Ldloc, vardef);
					Context.IL.Emit(OpCodes.Callvirt, adderRef);
					if (adderRef.ReturnType.FullName != "System.Void")
						Context.IL.Emit(OpCodes.Pop);
				}
			}
		}
Ejemplo n.º 6
0
		public static IEnumerable<Instruction> ProvideValue(VariableDefinitionReference vardefref, ILContext context,
			ModuleDefinition module, ElementNode node)
		{
			GenericInstanceType markupExtension;
			IList<TypeReference> genericArguments;
			if (vardefref.VariableDefinition.VariableType.FullName == "Xamarin.Forms.Xaml.ArrayExtension" &&
			    vardefref.VariableDefinition.VariableType.ImplementsGenericInterface("Xamarin.Forms.Xaml.IMarkupExtension`1",
				    out markupExtension, out genericArguments))
			{
				var markExt = markupExtension.Resolve();
				var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
				var provideValue = module.Import(provideValueInfo);
				provideValue =
					module.Import(provideValue.MakeGeneric(markupExtension.GenericArguments.Select(tr => module.Import(tr)).ToArray()));

				var typeNode = node.Properties[new XmlName("", "Type")];
				TypeReference arrayTypeRef;
				if (context.TypeExtensions.TryGetValue(typeNode, out arrayTypeRef))
					vardefref.VariableDefinition = new VariableDefinition(module.Import(arrayTypeRef.MakeArrayType()));
				else
					vardefref.VariableDefinition = new VariableDefinition(module.Import(genericArguments.First()));
				yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]);
				foreach (var instruction in node.PushServiceProvider(context))
					yield return instruction;
				yield return Instruction.Create(OpCodes.Callvirt, provideValue);

				if (arrayTypeRef != null)
					yield return Instruction.Create(OpCodes.Castclass, module.Import(arrayTypeRef.MakeArrayType()));
				yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition);
			}
			else if (vardefref.VariableDefinition.VariableType.ImplementsGenericInterface("Xamarin.Forms.Xaml.IMarkupExtension`1",
				out markupExtension, out genericArguments))
			{
				var markExt = markupExtension.Resolve();
				var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
				var provideValue = module.Import(provideValueInfo);
				provideValue =
					module.Import(provideValue.MakeGeneric(markupExtension.GenericArguments.Select(tr => module.Import(tr)).ToArray()));

				vardefref.VariableDefinition = new VariableDefinition(module.Import(genericArguments.First()));
				yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]);
				foreach (var instruction in node.PushServiceProvider(context))
					yield return instruction;
				yield return Instruction.Create(OpCodes.Callvirt, provideValue);
				yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition);
			}
			else if (context.Variables[node].VariableType.ImplementsInterface(module.Import(typeof (IMarkupExtension))))
			{
				var markExt = module.Import(typeof (IMarkupExtension)).Resolve();
				var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
				var provideValue = module.Import(provideValueInfo);

				vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object);
				yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]);
				foreach (var instruction in node.PushServiceProvider(context))
					yield return instruction;
				yield return Instruction.Create(OpCodes.Callvirt, provideValue);
				yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition);
			}
			else if (context.Variables[node].VariableType.ImplementsInterface(module.Import(typeof (IValueProvider))))
			{
				var markExt = module.Import(typeof (IValueProvider)).Resolve();
				var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
				var provideValue = module.Import(provideValueInfo);

				vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object);
				yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]);
				foreach (var instruction in node.PushServiceProvider(context))
					yield return instruction;
				yield return Instruction.Create(OpCodes.Callvirt, provideValue);
				yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition);
			}
		}
Ejemplo n.º 7
0
		public void Visit(ElementNode node, INode parentNode)
		{
			//Set Resources in ResourcesDictionaries
			if (IsCollectionItem(node, parentNode) && parentNode is IElementNode)
			{
				// Collection element, implicit content, or implicit collection element.
				CustomAttribute cpAttr;
				var parentVar = Context.Variables[(IElementNode)parentNode];
				if (parentVar.VariableType.ImplementsInterface(Module.Import(typeof (IEnumerable))))
				{
					if ((parentVar.VariableType.FullName == "Xamarin.Forms.ResourceDictionary" ||
						parentVar.VariableType.Resolve().BaseType.FullName == "Xamarin.Forms.ResourceDictionary") &&
					    !node.Properties.ContainsKey(XmlName.xKey))
					{
						node.Accept(new SetPropertiesVisitor(Context), parentNode);

						if (node.XmlType.Name != "Style")
							throw new XamlParseException("resources in ResourceDictionary require a x:Key attribute", node);

						//if this node is an IMarkupExtension, invoke ProvideValue() and replace the variable
						var vardef = Context.Variables[node];
						var vardefref = new VariableDefinitionReference(vardef);
						Context.IL.Append(SetPropertiesVisitor.ProvideValue(vardefref, Context, Module, node));
						if (vardef != vardefref.VariableDefinition)
						{
							vardef = vardefref.VariableDefinition;
							Context.Body.Variables.Add(vardef);
							Context.Variables[node] = vardef;
						}

						Context.IL.Emit(OpCodes.Ldloc, parentVar);
						Context.IL.Emit(OpCodes.Ldloc, Context.Variables[node]);
						Context.IL.Emit(OpCodes.Callvirt,
							Module.Import(
								Module.Import(typeof (ResourceDictionary))
									.Resolve()
									.Methods.Single(md => md.Name == "Add" && md.Parameters.Count == 1)));
					}
					else if ((parentVar.VariableType.FullName == "Xamarin.Forms.ResourceDictionary" ||
						parentVar.VariableType.Resolve().BaseType.FullName == "Xamarin.Forms.ResourceDictionary") &&
					         node.Properties.ContainsKey(XmlName.xKey))
					{
						node.Accept(new SetPropertiesVisitor(Context), parentNode);

						//if this node is an IMarkupExtension, invoke ProvideValue() and replace the variable
						var vardef = Context.Variables[node];
						var vardefref = new VariableDefinitionReference(vardef);
						Context.IL.Append(SetPropertiesVisitor.ProvideValue(vardefref, Context, Module, node));
						if (vardef != vardefref.VariableDefinition)
						{
							vardef = vardefref.VariableDefinition;
							Context.Body.Variables.Add(vardef);
							Context.Variables[node] = vardef;
						}

						//						IL_0013:  ldloc.0 
						//						IL_0014:  ldstr "key"
						//						IL_0019:  ldstr "foo"
						//						IL_001e:  callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.ResourceDictionary::Add(string, object)
						Context.IL.Emit(OpCodes.Ldloc, parentVar);
						Context.IL.Emit(OpCodes.Ldstr, (node.Properties[XmlName.xKey] as ValueNode).Value as string);
						var varDef = Context.Variables[node];
						Context.IL.Emit(OpCodes.Ldloc, varDef);
						if (varDef.VariableType.IsValueType)
							Context.IL.Emit(OpCodes.Box, Module.Import(varDef.VariableType));
						Context.IL.Emit(OpCodes.Callvirt,
							Module.Import(
								Module.Import(typeof (ResourceDictionary))
									.Resolve()
									.Methods.Single(md => md.Name == "Add" && md.Parameters.Count == 2)));
					}
				}
			}

			//Set ResourcesDictionaries to their parents
			XmlName propertyName;
			if (SetPropertiesVisitor.TryGetPropertyName(node, parentNode, out propertyName) &&
			    (propertyName.LocalName == "Resources" || propertyName.LocalName.EndsWith(".Resources", StringComparison.Ordinal)) &&
				(Context.Variables[node].VariableType.FullName == "Xamarin.Forms.ResourceDictionary" ||
					Context.Variables[node].VariableType.Resolve().BaseType.FullName == "Xamarin.Forms.ResourceDictionary"))
				SetPropertiesVisitor.SetPropertyValue(Context.Variables[(IElementNode)parentNode], propertyName, node, Context, node);
		}