2 * Copyright(c) 2022 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 using System.Collections;
19 using System.Collections.Generic;
20 using System.Globalization;
25 using Tizen.NUI.Binding;
26 using Tizen.NUI.EXaml;
27 using Tizen.NUI.EXaml.Build.Tasks;
30 using static Mono.Cecil.Cil.Instruction;
31 using static Mono.Cecil.Cil.OpCodes;
33 namespace Tizen.NUI.Xaml.Build.Tasks
35 static class NodeILExtensions
37 public static bool CanConvertValue(this ValueNode node, ModuleDefinition module, TypeReference targetTypeRef, IEnumerable<ICustomAttributeProvider> attributeProviders)
39 TypeReference typeConverter = null;
40 foreach (var attributeProvider in attributeProviders) {
41 CustomAttribute typeConverterAttribute;
43 (typeConverterAttribute =
44 attributeProvider.CustomAttributes.FirstOrDefault(
45 cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName))) != null) {
46 typeConverter = typeConverterAttribute.ConstructorArguments[0].Value as TypeReference;
51 return node.CanConvertValue(module, targetTypeRef, typeConverter);
54 public static bool CanConvertValue(this ValueNode node, ModuleDefinition module, MemberReference bpRef)
56 var targetTypeRef = bpRef.GetBindablePropertyType(node, module);
57 var typeConverter = bpRef.GetBindablePropertyTypeConverter(module);
58 return node.CanConvertValue(module, targetTypeRef, typeConverter);
61 public static bool CanConvertValue(this ValueNode node, ModuleDefinition module, TypeReference targetTypeRef, TypeReference typeConverter)
63 var str = (string)node.Value;
65 //If there's a [TypeConverter], use it
66 if (typeConverter != null && str != null) {
67 var typeConvAttribute = typeConverter.GetCustomAttribute(module, (XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "TypeConversionAttribute"));
68 if (typeConvAttribute == null) //trust the unattributed TypeConverter
70 var toType = typeConvAttribute.ConstructorArguments.First().Value as TypeReference;
71 return toType.InheritsFromOrImplements(targetTypeRef);
74 if (targetTypeRef.FullName == "System.String")
79 var implicitOperator = targetTypeRef.GetImplicitOperatorTo(module.ImportReference(node.Value.GetType()), module);
80 if (implicitOperator != null)
85 if (true == targetTypeRef.IsInterface(typeof(IList).FullName))
90 ///No reason to return false
94 public static object GetBaseValue(EXamlContext context, string str, TypeReference targetTypeRef)
96 //Obvious Built-in conversions
97 if (str == null) //if default parameter is null, exception will throw
99 else if (targetTypeRef.ResolveCached().BaseType != null && targetTypeRef.ResolveCached().BaseType.FullName == "System.Enum")
100 return GetParsedEnum(context, targetTypeRef, str);
101 else if (targetTypeRef.FullName == "System.Char")
102 return Char.Parse(str);
103 else if (targetTypeRef.FullName == "System.SByte")
104 return SByte.Parse(str, CultureInfo.InvariantCulture);
105 else if (targetTypeRef.FullName == "System.Int16")
106 return Int16.Parse(str, CultureInfo.InvariantCulture);
107 else if (targetTypeRef.FullName == "System.Int32")
108 return Int32.Parse(str, CultureInfo.InvariantCulture);
109 else if (targetTypeRef.FullName == "System.Int64")
110 return Int64.Parse(str, CultureInfo.InvariantCulture);
111 else if (targetTypeRef.FullName == "System.Byte")
112 return Byte.Parse(str, CultureInfo.InvariantCulture);
113 else if (targetTypeRef.FullName == "System.UInt16")
114 return UInt16.Parse(str, CultureInfo.InvariantCulture);
115 else if (targetTypeRef.FullName == "System.UInt32")
116 return UInt32.Parse(str, CultureInfo.InvariantCulture);
117 else if (targetTypeRef.FullName == "System.UInt64")
118 return UInt64.Parse(str, CultureInfo.InvariantCulture);
119 else if (targetTypeRef.FullName == "System.Single")
120 return Single.Parse(str, CultureInfo.InvariantCulture);
121 else if (targetTypeRef.FullName == "System.Double")
122 return Double.Parse(str, CultureInfo.InvariantCulture);
123 else if (targetTypeRef.FullName == "System.Boolean")
125 if (Boolean.Parse(str))
130 else if (targetTypeRef.FullName == "System.TimeSpan")
132 var ts = TimeSpan.Parse(str, CultureInfo.InvariantCulture);
135 else if (targetTypeRef.FullName == "System.DateTime")
137 var dt = DateTime.Parse(str, CultureInfo.InvariantCulture);
140 else if (targetTypeRef.FullName == "System.String" && str.StartsWith("{}", StringComparison.Ordinal))
141 return str.Substring(2);
142 else if (targetTypeRef.FullName == "System.String")
144 else if (targetTypeRef.FullName == "System.Object")
146 else if (targetTypeRef.FullName == "System.Decimal")
149 if (decimal.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out outdecimal))
159 var originalTypeRef = targetTypeRef;
160 var module = targetTypeRef.Resolve().Module;
162 var isNullable = false;
163 MethodReference nullableCtor = null;
164 if (targetTypeRef.ResolveCached().FullName == "System.Nullable`1")
166 var nullableTypeRef = targetTypeRef;
167 targetTypeRef = ((GenericInstanceType)targetTypeRef).GenericArguments[0];
169 nullableCtor = originalTypeRef.GetMethods(md => md.IsConstructor && md.Parameters.Count == 1, module).Single().Item1;
170 nullableCtor = nullableCtor.ResolveGenericParameters(nullableTypeRef, module);
173 var implicitOperator = module.TypeSystem.String.GetImplicitOperatorTo(targetTypeRef, module);
175 if (implicitOperator != null)
178 //yield return Create(Ldstr, node.Value as string);
179 //yield return Create(Call, module.ImportReference(implicitOperator));
183 bool isNotNull = false;
185 var targetType = targetTypeRef.ResolveCached();
187 foreach (var method in targetType.Methods.Where(a => a.Name == "op_Implicit"))
189 TypeReference typeReference = null;
191 if (method.Parameters[0].ParameterType.IsGenericParameter)
193 var genericType = targetTypeRef as GenericInstanceType;
195 if (null != genericType)
197 for (int i = 0; i < targetType.GenericParameters.Count; i++)
199 if (method.Parameters[0].ParameterType == targetType.GenericParameters[i])
201 typeReference = genericType.GenericArguments[i];
208 typeReference = method.Parameters[0].ParameterType;
211 if (null != typeReference)
214 if (typeReference.ResolveCached().FullName == "System.Nullable`1")
216 var genericType = typeReference as GenericInstanceType;
217 typeReference = genericType.GenericArguments[0];
220 //Fang: Need to deal nullable type
221 //TypeReference convertType = null;
222 //var insList = PushConvertedValue(node, context, typeReference, convertType, pushServiceProvider, boxValueTypes, unboxValueTypes);
224 //foreach (var ins in insList)
239 //yield return Create(Newobj, module.ImportReference(nullableCtor));
241 //if (originalTypeRef.IsValueType && boxValueTypes)
243 // yield return Create(Box, module.ImportReference(originalTypeRef));
248 public static object GetBaseValue(this ValueNode node, EXamlContext context, TypeReference targetTypeRef)
250 var str = (string)node.Value;
253 if ("System.String" != targetTypeRef.FullName)
255 if (str.EndsWith("dp"))
257 var value = GetBaseValue(context, str.Substring(0, str.Length - "dp".Length), targetTypeRef);
258 ret = new EXamlCreateDPObject(context, value, targetTypeRef, "dp");
260 else if (str.EndsWith("px"))
262 var value = GetBaseValue(context, str.Substring(0, str.Length - "px".Length), targetTypeRef);
263 ret = new EXamlCreateDPObject(context, value, targetTypeRef, "px");
269 ret = GetBaseValue(context, str, targetTypeRef);
275 public static TypeReference GetConverterType(this ValueNode node, IEnumerable<ICustomAttributeProvider> attributeProviders)
277 TypeReference typeConverter = null;
278 foreach (var attributeProvider in attributeProviders)
280 CustomAttribute typeConverterAttribute;
282 (typeConverterAttribute =
283 attributeProvider.CustomAttributes.FirstOrDefault(
284 cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName))) != null)
286 typeConverter = typeConverterAttribute.ConstructorArguments[0].Value as TypeReference;
291 return typeConverter;
294 public static IEnumerable<Instruction> PushConvertedValue(this ValueNode node, ILContext context,
295 TypeReference targetTypeRef, IEnumerable<ICustomAttributeProvider> attributeProviders,
296 IEnumerable<Instruction> pushServiceProvider, bool boxValueTypes, bool unboxValueTypes)
298 TypeReference typeConverter = null;
299 foreach (var attributeProvider in attributeProviders)
301 CustomAttribute typeConverterAttribute;
303 (typeConverterAttribute =
304 attributeProvider.CustomAttributes.FirstOrDefault(
305 cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName))) != null)
307 typeConverter = typeConverterAttribute.ConstructorArguments[0].Value as TypeReference;
311 return node.PushConvertedValue(context, targetTypeRef, typeConverter, pushServiceProvider, boxValueTypes,
315 public static IEnumerable<Instruction> PushConvertedValue(this ValueNode node, ILContext context, FieldReference bpRef,
316 IEnumerable<Instruction> pushServiceProvider, bool boxValueTypes, bool unboxValueTypes)
318 var module = context.Body.Method.Module;
319 var targetTypeRef = bpRef.GetBindablePropertyType(node, module);
320 var typeConverter = bpRef.GetBindablePropertyTypeConverter(module);
322 return node.PushConvertedValue(context, targetTypeRef, typeConverter, pushServiceProvider, boxValueTypes,
326 public static IEnumerable<Instruction> PushConvertedValue(this ValueNode node, ILContext context,
327 TypeReference targetTypeRef, TypeReference typeConverter, IEnumerable<Instruction> pushServiceProvider,
328 bool boxValueTypes, bool unboxValueTypes)
330 var module = context.Body.Method.Module;
331 var str = (string)node.Value;
333 //If the TypeConverter has a ProvideCompiledAttribute that can be resolved, shortcut this
334 var compiledConverterName = typeConverter?.GetCustomAttribute(module, (XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "ProvideCompiledAttribute"))?.ConstructorArguments?.First().Value as string;
336 if (null == compiledConverterName)
338 compiledConverterName = "Tizen.NUI.Xaml.Core.XamlC." + targetTypeRef.Name + "TypeConverter";
341 Type compiledConverterType;
342 if (compiledConverterName != null && (compiledConverterType = Type.GetType (compiledConverterName)) != null) {
343 var compiledConverter = Activator.CreateInstance (compiledConverterType);
344 var converter = typeof(ICompiledTypeConverter).GetMethods ().FirstOrDefault (md => md.Name == "ConvertFromString");
345 IEnumerable<Instruction> instructions = (IEnumerable<Instruction>)converter.Invoke (compiledConverter, new object[] {
346 node.Value as string, context, node as BaseNode});
348 if (null != instructions)
350 foreach (var i in instructions)
352 if (targetTypeRef.IsValueType && boxValueTypes)
353 yield return Instruction.Create(OpCodes.Box, module.ImportReference(targetTypeRef));
358 //If there's a [TypeConverter], use it
359 if (typeConverter != null)
361 var isExtendedConverter = typeConverter.ImplementsInterface(module.ImportReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "IExtendedTypeConverter")));
362 var typeConverterCtorRef = module.ImportCtorReference(typeConverter, paramCount: 0);
363 var convertFromInvariantStringDefinition = isExtendedConverter
364 ? module.ImportReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "IExtendedTypeConverter"))
366 .Methods.FirstOrDefault(md => md.Name == "ConvertFromInvariantString" && md.Parameters.Count == 2)
367 : typeConverter.ResolveCached()
369 .FirstOrDefault(md => md.Name == "ConvertFromInvariantString" && md.Parameters.Count == 1);
370 var convertFromInvariantStringReference = module.ImportReference(convertFromInvariantStringDefinition);
372 yield return Instruction.Create(OpCodes.Newobj, typeConverterCtorRef);
373 yield return Instruction.Create(OpCodes.Ldstr, node.Value as string);
375 if (isExtendedConverter)
377 foreach (var instruction in pushServiceProvider)
378 yield return instruction;
381 yield return Instruction.Create(OpCodes.Callvirt, convertFromInvariantStringReference);
383 if (targetTypeRef.IsValueType && unboxValueTypes)
384 yield return Instruction.Create(OpCodes.Unbox_Any, module.ImportReference(targetTypeRef));
386 //ConvertFrom returns an object, no need to Box
389 var originalTypeRef = targetTypeRef;
390 var isNullable = false;
391 MethodReference nullableCtor = null;
392 if (targetTypeRef.ResolveCached().FullName == "System.Nullable`1")
394 var nullableTypeRef = targetTypeRef;
395 targetTypeRef = ((GenericInstanceType)targetTypeRef).GenericArguments[0];
397 nullableCtor = originalTypeRef.GetMethods(md => md.IsConstructor && md.Parameters.Count == 1, module).Single().Item1;
398 nullableCtor = nullableCtor.ResolveGenericParameters(nullableTypeRef, module);
401 var implicitOperator = module.TypeSystem.String.GetImplicitOperatorTo(targetTypeRef, module);
403 //Obvious Built-in conversions
404 if (str == null) //if default parameter is null, exception will throw
405 yield return Create(OpCodes.Ldnull);
406 else if (targetTypeRef.ResolveCached().BaseType != null && targetTypeRef.ResolveCached().BaseType.FullName == "System.Enum")
407 yield return PushParsedEnum(targetTypeRef, str, node);
408 else if (targetTypeRef.FullName == "System.Char")
409 yield return Instruction.Create(OpCodes.Ldc_I4, Char.Parse(str));
410 else if (targetTypeRef.FullName == "System.SByte")
411 yield return Instruction.Create(OpCodes.Ldc_I4, SByte.Parse(str, CultureInfo.InvariantCulture));
412 else if (targetTypeRef.FullName == "System.Int16")
414 if (str.EndsWith("dp") || str.EndsWith("px"))
416 var insOfDPValue = GetDPValue(module, node, targetTypeRef, str);
418 foreach (var ins in insOfDPValue)
425 yield return Instruction.Create(OpCodes.Ldc_I4, Int16.Parse(str, CultureInfo.InvariantCulture));
428 else if (targetTypeRef.FullName == "System.Int32")
429 yield return Instruction.Create(OpCodes.Ldc_I4, Int32.Parse(str, CultureInfo.InvariantCulture));
430 else if (targetTypeRef.FullName == "System.Int64")
431 yield return Instruction.Create(OpCodes.Ldc_I8, Int64.Parse(str, CultureInfo.InvariantCulture));
432 else if (targetTypeRef.FullName == "System.Byte")
433 yield return Instruction.Create(OpCodes.Ldc_I4, Byte.Parse(str, CultureInfo.InvariantCulture));
434 else if (targetTypeRef.FullName == "System.UInt16")
435 yield return Instruction.Create(OpCodes.Ldc_I4, unchecked((int)UInt16.Parse(str, CultureInfo.InvariantCulture)));
436 else if (targetTypeRef.FullName == "System.UInt32")
437 yield return Instruction.Create(OpCodes.Ldc_I8, unchecked((uint)UInt32.Parse(str, CultureInfo.InvariantCulture)));
438 else if (targetTypeRef.FullName == "System.UInt64")
439 yield return Instruction.Create(OpCodes.Ldc_I8, unchecked((long)UInt64.Parse(str, CultureInfo.InvariantCulture)));
440 else if (targetTypeRef.FullName == "System.Single")
442 if (str.EndsWith("dp") || str.EndsWith("px"))
444 var insOfDPValue = GetDPValue(module, node, targetTypeRef, str);
446 foreach (var ins in insOfDPValue)
453 yield return Instruction.Create(OpCodes.Ldc_R4, Single.Parse(str, CultureInfo.InvariantCulture));
456 else if (targetTypeRef.FullName == "System.Double")
457 yield return Instruction.Create(OpCodes.Ldc_R8, Double.Parse(str, CultureInfo.InvariantCulture));
458 else if (targetTypeRef.FullName == "System.Boolean")
460 if (Boolean.Parse(str))
461 yield return Instruction.Create(OpCodes.Ldc_I4_1);
463 yield return Instruction.Create(OpCodes.Ldc_I4_0);
465 else if (targetTypeRef.FullName == "System.TimeSpan")
467 var ts = TimeSpan.Parse(str, CultureInfo.InvariantCulture);
468 var ticks = ts.Ticks;
469 yield return Instruction.Create(OpCodes.Ldc_I8, ticks);
470 yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference(("mscorlib", "System", "TimeSpan"), parameterTypes: new[] { ("mscorlib", "System", "Int64") }));
472 else if (targetTypeRef.FullName == "System.DateTime")
474 var dt = DateTime.Parse(str, CultureInfo.InvariantCulture);
475 var ticks = dt.Ticks;
476 yield return Instruction.Create(OpCodes.Ldc_I8, ticks);
477 yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference(("mscorlib", "System", "DateTime"), parameterTypes: new[] { ("mscorlib", "System", "Int64") }));
479 else if (targetTypeRef.FullName == "System.String" && str.StartsWith("{}", StringComparison.Ordinal))
480 yield return Instruction.Create(OpCodes.Ldstr, str.Substring(2));
481 else if (targetTypeRef.FullName == "System.String")
482 yield return Instruction.Create(OpCodes.Ldstr, str);
483 else if (targetTypeRef.FullName == "System.Object")
484 yield return Instruction.Create(OpCodes.Ldstr, str);
485 else if (targetTypeRef.FullName == "System.Decimal")
488 if (decimal.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out outdecimal))
490 var vardef = new VariableDefinition(module.ImportReference(("mscorlib", "System", "Decimal")));
491 context.Body.Variables.Add(vardef);
492 //Use an extra temp var so we can push the value to the stack, just like other cases
493 //IL_0003: ldstr "adecimal"
494 //IL_0008: ldc.i4.s 0x6f
495 //IL_000a: call class [mscorlib]System.Globalization.CultureInfo class [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture()
496 //IL_000f: ldloca.s 0
497 //IL_0011: call bool valuetype [mscorlib]System.Decimal::TryParse(string, valuetype [mscorlib]System.Globalization.NumberStyles, class [mscorlib]System.IFormatProvider, [out] valuetype [mscorlib]System.Decimal&)
499 yield return Create(Ldstr, str);
500 yield return Create(Ldc_I4, 0x6f); //NumberStyles.Number
501 yield return Create(Call, module.ImportPropertyGetterReference(("mscorlib", "System.Globalization", "CultureInfo"),
502 propertyName: "InvariantCulture", isStatic: true));
503 yield return Create(Ldloca, vardef);
504 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Decimal"),
505 methodName: "TryParse",
506 parameterTypes: new[] {
507 ("mscorlib", "System", "String"),
508 ("mscorlib", "System.Globalization", "NumberStyles"),
509 ("mscorlib", "System", "IFormatProvider"),
510 ("mscorlib", "System", "Decimal"),
513 yield return Create(Pop);
514 yield return Create(Ldloc, vardef);
518 yield return Create(Ldc_I4_0);
519 yield return Create(Newobj, module.ImportCtorReference(("mscorlib", "System", "Decimal"), parameterTypes: new[] { ("mscorlib", "System", "Int32") }));
522 else if (implicitOperator != null)
524 yield return Create(Ldstr, node.Value as string);
525 yield return Create(Call, module.ImportReference(implicitOperator));
529 bool isNotNull = false;
531 var targetType = targetTypeRef.ResolveCached();
533 foreach (var method in targetType.Methods.Where(a => a.Name == "op_Implicit"))
535 TypeReference typeReference = null;
537 if (method.Parameters[0].ParameterType.IsGenericParameter)
539 var genericType = targetTypeRef as GenericInstanceType;
541 if (null != genericType)
543 for (int i = 0; i < targetType.GenericParameters.Count; i++)
545 if (method.Parameters[0].ParameterType == targetType.GenericParameters[i])
547 typeReference = genericType.GenericArguments[i];
554 typeReference = method.Parameters[0].ParameterType;
557 if (null != typeReference)
560 if (typeReference.ResolveCached().FullName == "System.Nullable`1")
562 var genericType = typeReference as GenericInstanceType;
563 typeReference = genericType.GenericArguments[0];
566 TypeReference convertType = null;
567 var insList = PushConvertedValue(node, context, typeReference, convertType, pushServiceProvider, boxValueTypes, unboxValueTypes);
569 foreach (var ins in insList)
578 yield return Create(Ldnull);
583 yield return Create(Newobj, module.ImportReference(nullableCtor));
584 if (originalTypeRef.IsValueType && boxValueTypes)
585 yield return Create(Box, module.ImportReference(originalTypeRef));
588 private static TypeDefinition typeOfGraphicManager;
589 private static MethodReference getMethodOfInstance;
590 private static MethodReference methodOfConvertScriptToPixel;
592 static private IEnumerable<Instruction> GetDPValue(ModuleDefinition module, ValueNode node, TypeReference targetTypeRef, string str)
594 if (null == typeOfGraphicManager)
596 typeOfGraphicManager = module.GetTypeDefinition(("Tizen.NUI", "Tizen.NUI", "GraphicsTypeManager"));
599 if (null == getMethodOfInstance)
601 var propertyOfInstance = typeOfGraphicManager.Properties.FirstOrDefault(a => a.Name == "Instance");
602 getMethodOfInstance = propertyOfInstance.GetMethod;
603 getMethodOfInstance = module.ImportReference(getMethodOfInstance);
606 yield return Create(Call, getMethodOfInstance);
607 yield return Create(Ldstr, str);
609 if (null == methodOfConvertScriptToPixel)
611 methodOfConvertScriptToPixel = typeOfGraphicManager.Methods.FirstOrDefault(a => a.Name == "ConvertScriptToPixel");
612 methodOfConvertScriptToPixel = module.ImportReference(methodOfConvertScriptToPixel);
615 yield return Create(Callvirt, methodOfConvertScriptToPixel);
617 var convertType = typeof(System.Convert);
618 var typeOfConvert = module.GetTypeDefinition((convertType.Assembly.FullName, convertType.Namespace, convertType.Name));
620 var methodOfTo = typeOfConvert.Methods.FirstOrDefault(a => a.Name == "To" + targetTypeRef.Name);
622 yield return Create(Box, module.ImportReference(targetTypeRef));
624 yield return Create(Call, module.ImportReference(methodOfTo));
627 static public object GetParsedEnum(EXamlContext context, TypeReference enumRef, string value)
629 var enumDef = enumRef.ResolveCached();
631 throw new InvalidOperationException();
633 bool isStrMatchEnumValue = false;
635 foreach (var field in enumDef.Fields)
637 if (field.Name == "value__")
640 if (field.Name == value)
642 isStrMatchEnumValue = true;
647 if (!isStrMatchEnumValue)
649 foreach (var field in enumDef.Fields)
651 if (field.Name == "value__")
653 if (IsStringMatchObject(field.Constant, value))
655 isStrMatchEnumValue = true;
662 if (!isStrMatchEnumValue)
664 throw new Exception($"{value} is not value of {enumRef.FullName}");
667 return new EXamlCreateObject(context, value, enumRef);
670 static Instruction PushParsedEnum(TypeReference enumRef, string value, IXmlLineInfo lineInfo)
672 var enumDef = enumRef.ResolveCached();
674 throw new InvalidOperationException();
676 // The approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong.
677 // https://msdn.microsoft.com/en-us/library/sbbt4032.aspx
678 byte b = 0; sbyte sb = 0; short s = 0; ushort us = 0;
679 int i = 0; uint ui = 0; long l = 0; ulong ul = 0;
681 TypeReference typeRef = null;
683 foreach (var field in enumDef.Fields)
684 if (field.Name == "value__")
685 typeRef = field.FieldType;
688 throw new ArgumentException();
690 foreach (var v in value.Split(',')) {
691 foreach (var field in enumDef.Fields) {
692 if (field.Name == "value__")
694 if (field.Name == v.Trim()) {
695 switch (typeRef.FullName) {
697 b |= (byte)field.Constant;
701 throw new XamlParseException($"Multi-valued enums are not valid on sbyte enum types", lineInfo);
702 sb = (sbyte)field.Constant;
705 s |= (short)field.Constant;
707 case "System.UInt16":
708 us |= (ushort)field.Constant;
711 i |= (int)field.Constant;
713 case "System.UInt32":
714 ui |= (uint)field.Constant;
717 l |= (long)field.Constant;
719 case "System.UInt64":
720 ul |= (ulong)field.Constant;
729 foreach (var field in enumDef.Fields)
731 if (field.Name == "value__")
733 if (IsStringMatchObject(field.Constant, v))
735 switch (typeRef.FullName)
738 b |= (byte)field.Constant;
742 throw new XamlParseException($"Multi-valued enums are not valid on sbyte enum types", lineInfo);
743 sb = (sbyte)field.Constant;
746 s |= (short)field.Constant;
748 case "System.UInt16":
749 us |= (ushort)field.Constant;
752 i |= (int)field.Constant;
754 case "System.UInt32":
755 ui |= (uint)field.Constant;
758 l |= (long)field.Constant;
760 case "System.UInt64":
761 ul |= (ulong)field.Constant;
771 throw new XamlParseException($"Enum value not found for {value}", lineInfo);
773 switch (typeRef.FullName) {
775 return Instruction.Create(OpCodes.Ldc_I4, (int)b);
777 return Instruction.Create(OpCodes.Ldc_I4, (int)sb);
779 return Instruction.Create(OpCodes.Ldc_I4, (int)s);
780 case "System.UInt16":
781 return Instruction.Create(OpCodes.Ldc_I4, (int)us);
783 return Instruction.Create(OpCodes.Ldc_I4, (int)i);
784 case "System.UInt32":
785 return Instruction.Create(OpCodes.Ldc_I8, (uint)ui);
787 return Instruction.Create(OpCodes.Ldc_I8, (long)l);
788 case "System.UInt64":
789 return Instruction.Create(OpCodes.Ldc_I8, (ulong)ul);
791 throw new XamlParseException($"Enum value not found for {value}", lineInfo);
795 private static bool IsStringMatchObject(object obj, string str)
799 switch (obj.GetType().FullName)
802 return (byte)obj == byte.Parse(str);
804 return (sbyte)obj == sbyte.Parse(str);
806 return (Int16)obj == Int16.Parse(str);
807 case "System.UInt16":
808 return (UInt16)obj == UInt16.Parse(str);
810 return (Int32)obj == Int32.Parse(str);
811 case "System.UInt32":
812 return (UInt32)obj == UInt32.Parse(str);
814 return (Int64)obj == Int64.Parse(str);
815 case "System.UInt64":
816 return (UInt64)obj == UInt64.Parse(str);
826 public static IEnumerable<Instruction> PushXmlLineInfo(this INode node, ILContext context)
828 var module = context.Body.Method.Module;
830 var xmlLineInfo = node as IXmlLineInfo;
831 if (xmlLineInfo == null) {
832 yield return Create(Ldnull);
835 MethodReference ctor;
836 if (xmlLineInfo.HasLineInfo()) {
837 yield return Create(Ldc_I4, xmlLineInfo.LineNumber);
838 yield return Create(Ldc_I4, xmlLineInfo.LinePosition);
839 ctor = module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XmlLineInfo"), parameterTypes: new[] {
840 ("mscorlib", "System", "Int32"),
841 ("mscorlib", "System", "Int32"),
845 ctor = module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XmlLineInfo"), parameterTypes: null);
846 yield return Create(Newobj, ctor);
849 public static IEnumerable<Instruction> PushParentObjectsArray(this INode node, ILContext context)
851 var module = context.Body.Method.Module;
853 var nodes = new List<IElementNode>();
854 INode n = node.Parent;
857 var en = n as IElementNode;
858 if (en != null && context.Variables.ContainsKey(en))
863 if (nodes.Count == 0 && context.ParentContextValues == null)
865 yield return Instruction.Create(OpCodes.Ldnull);
869 if (nodes.Count == 0)
871 yield return Instruction.Create(OpCodes.Ldarg_0);
872 yield return Instruction.Create(OpCodes.Ldfld, context.ParentContextValues);
876 //Compute parent object length
877 if (context.ParentContextValues != null)
879 yield return Instruction.Create(OpCodes.Ldarg_0);
880 yield return Instruction.Create(OpCodes.Ldfld, context.ParentContextValues);
881 yield return Instruction.Create(OpCodes.Ldlen);
882 yield return Instruction.Create(OpCodes.Conv_I4);
885 yield return Instruction.Create(OpCodes.Ldc_I4_0);
886 var parentObjectLength = new VariableDefinition(module.TypeSystem.Int32);
887 context.Body.Variables.Add(parentObjectLength);
888 yield return Instruction.Create(OpCodes.Stloc, parentObjectLength);
890 //Create the final array
891 yield return Instruction.Create(OpCodes.Ldloc, parentObjectLength);
892 yield return Instruction.Create(OpCodes.Ldc_I4, nodes.Count);
893 yield return Instruction.Create(OpCodes.Add);
894 yield return Instruction.Create(OpCodes.Newarr, module.TypeSystem.Object);
895 var finalArray = new VariableDefinition(module.ImportArrayReference(("mscorlib", "System", "Object")));
896 context.Body.Variables.Add(finalArray);
897 yield return Instruction.Create(OpCodes.Stloc, finalArray);
899 //Copy original array to final
900 if (context.ParentContextValues != null)
902 yield return Create(Ldarg_0);
903 yield return Create(Ldfld, context.ParentContextValues); //sourceArray
904 yield return Create(Ldc_I4_0); //sourceIndex
905 yield return Create(Ldloc, finalArray); //destinationArray
906 yield return Create(Ldc_I4, nodes.Count); //destinationIndex
907 yield return Create(Ldloc, parentObjectLength); //length
908 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Array"),
910 parameterTypes: new[] {
911 ("mscorlib", "System", "Array"),
912 ("mscorlib", "System", "Int32"),
913 ("mscorlib", "System", "Array"),
914 ("mscorlib", "System", "Int32"),
915 ("mscorlib", "System", "Int32"),
921 yield return Instruction.Create(OpCodes.Ldloc, finalArray);
924 for (var i = 0; i < nodes.Count; i++)
927 yield return Instruction.Create(OpCodes.Dup);
928 yield return Instruction.Create(OpCodes.Ldc_I4, i);
929 yield return Instruction.Create(OpCodes.Ldloc, context.Variables[en]);
930 if (context.Variables[en].VariableType.IsValueType)
931 yield return Instruction.Create(OpCodes.Box, module.ImportReference(context.Variables[en].VariableType));
932 yield return Instruction.Create(OpCodes.Stelem_Ref);
937 static IEnumerable<Instruction> PushTargetProperty(FieldReference bpRef, PropertyReference propertyRef, TypeReference declaringTypeReference, ModuleDefinition module)
940 yield return Create(Ldsfld, bpRef);
943 if (propertyRef != null) {
944 yield return Create(Ldtoken, module.ImportReference(declaringTypeReference ?? propertyRef.DeclaringType));
945 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
946 yield return Create(Ldstr, propertyRef.Name);
947 yield return Create(Call, module.ImportMethodReference(("System.Reflection.Extensions", "System.Reflection", "RuntimeReflectionExtensions"),
948 methodName: "GetRuntimeProperty",
949 parameterTypes: new[]{
950 ("mscorlib", "System", "Type"),
951 ("mscorlib", "System", "String"),
956 yield return Create(Ldnull);
960 public static IEnumerable<Instruction> PushServiceProvider(this INode node, ILContext context, FieldReference bpRef = null, PropertyReference propertyRef = null, TypeReference declaringTypeReference = null)
962 var module = context.Body.Method.Module;
964 #if NOSERVICEPROVIDER
965 yield return Instruction.Create (OpCodes.Ldnull);
969 var addService = module.ImportMethodReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XamlServiceProvider"),
971 parameterTypes: new[] {
972 ("mscorlib", "System", "Type"),
973 ("mscorlib", "System", "Object"),
976 yield return Create(Newobj, module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XamlServiceProvider"), parameterTypes: null));
978 //Add a SimpleValueTargetProvider and register it as IProvideValueTarget and IReferenceProvider
979 var pushParentIl = node.PushParentObjectsArray(context).ToList();
980 if (pushParentIl[pushParentIl.Count - 1].OpCode != Ldnull) {
981 yield return Create(Dup); //Keep the serviceProvider on the stack
982 yield return Create(Ldtoken, module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "IProvideValueTarget")));
983 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
985 foreach (var instruction in pushParentIl)
986 yield return instruction;
988 foreach (var instruction in PushTargetProperty(bpRef, propertyRef, declaringTypeReference, module))
989 yield return instruction;
991 yield return Create(Newobj, module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "SimpleValueTargetProvider"), paramCount: 2));
992 //store the provider so we can register it again with a different key
993 yield return Create(Dup);
994 var refProvider = new VariableDefinition(module.ImportReference(("mscorlib", "System", "Object")));
995 context.Body.Variables.Add(refProvider);
996 yield return Create(Stloc, refProvider);
997 yield return Create(Callvirt, addService);
999 yield return Create(Dup); //Keep the serviceProvider on the stack
1000 yield return Create(Ldtoken, module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "IReferenceProvider")));
1001 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
1002 yield return Create(Ldloc, refProvider);
1003 yield return Create(Callvirt, addService);
1006 //Add a XamlTypeResolver
1007 if (node.NamespaceResolver != null) {
1008 yield return Create(Dup); //Duplicate the serviceProvider
1009 yield return Create(Ldtoken, module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "IXamlTypeResolver")));
1010 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
1011 yield return Create(Newobj, module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XmlNamespaceResolver"), parameterTypes: null));
1012 foreach (var kvp in node.NamespaceResolver.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml)) {
1013 yield return Create(Dup); //dup the resolver
1014 yield return Create(Ldstr, kvp.Key);
1015 yield return Create(Ldstr, kvp.Value);
1016 yield return Create(Callvirt, module.ImportMethodReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XmlNamespaceResolver"),
1018 parameterTypes: new[] {
1019 ("mscorlib", "System", "String"),
1020 ("mscorlib", "System", "String"),
1023 yield return Create(Ldtoken, context.Body.Method.DeclaringType);
1024 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
1025 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System.Reflection", "IntrospectionExtensions"), methodName: "GetTypeInfo", parameterTypes: new[] { ("mscorlib", "System", "Type") }, isStatic: true));
1026 yield return Create(Callvirt, module.ImportPropertyGetterReference(("mscorlib", "System.Reflection", "TypeInfo"), propertyName: "Assembly", flatten: true));
1027 yield return Create(Newobj, module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XamlTypeResolver"), paramCount: 2));
1028 yield return Create(Callvirt, addService);
1031 if (node is IXmlLineInfo) {
1032 yield return Create(Dup); //Duplicate the serviceProvider
1033 yield return Create(Ldtoken, module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "IXmlLineInfoProvider")));
1034 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
1035 foreach (var instruction in node.PushXmlLineInfo(context))
1036 yield return instruction;
1037 yield return Create(Newobj, module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XmlLineInfoProvider"), parameterTypes: new[] { ("System.Xml.ReaderWriter", "System.Xml", "IXmlLineInfo") }));
1038 yield return Create(Callvirt, addService);