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); } } }
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(); } } }
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)); } }
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); } }
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); } } }
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); } }
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); }