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.Generic;
19 using System.Globalization;
26 using static Mono.Cecil.Cil.Instruction;
27 using static Mono.Cecil.Cil.OpCodes;
29 namespace Tizen.NUI.Xaml.Build.Tasks
31 class CreateObjectVisitor : IXamlNodeVisitor
33 public CreateObjectVisitor(ILContext context)
36 Module = context.Body.Method.Module;
39 public ILContext Context { get; }
41 ModuleDefinition Module { get; }
43 public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
44 public bool StopOnDataTemplate => true;
45 public bool StopOnResourceDictionary => false;
46 public bool VisitNodeOnDataTemplate => false;
47 public bool SkipChildren(INode node, INode parentNode) => false;
49 public bool IsResourceDictionary(ElementNode node)
51 var parentVar = Context.Variables[(IElementNode)node];
52 return parentVar.VariableType.FullName == "Tizen.NUI.Binding.ResourceDictionary"
53 || parentVar.VariableType.Resolve().BaseType?.FullName == "Tizen.NUI.Binding.ResourceDictionary";
56 public void Visit(ValueNode node, INode parentNode)
58 Context.Values[node] = node.Value;
61 public void Visit(MarkupNode node, INode parentNode)
63 //At this point, all MarkupNodes are expanded to ElementNodes
66 public void Visit(ElementNode node, INode parentNode)
68 var typeref = Module.ImportReference(node.XmlType.GetTypeReference(XmlTypeExtensions.ModeOfGetType.Both, Module, node));
69 TypeDefinition typedef = typeref.ResolveCached();
71 if (IsXaml2009LanguagePrimitive(node))
73 var vardef = new VariableDefinition(typeref);
74 Context.Variables[node] = vardef;
75 Context.Body.Variables.Add(vardef);
77 Context.IL.Append(PushValueFromLanguagePrimitive(typeref, node));
78 Context.IL.Emit(OpCodes.Stloc, vardef);
82 //if this is a MarkupExtension that can be compiled directly, compile and returns the value
83 var compiledMarkupExtensionName = typeref
84 .GetCustomAttribute(Module, (XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "ProvideCompiledAttribute"))
85 ?.ConstructorArguments?[0].Value as string;
86 Type compiledMarkupExtensionType;
87 ICompiledMarkupExtension markupProvider;
88 if (compiledMarkupExtensionName != null &&
89 (compiledMarkupExtensionType = Type.GetType(compiledMarkupExtensionName)) != null &&
90 (markupProvider = Activator.CreateInstance(compiledMarkupExtensionType) as ICompiledMarkupExtension) != null)
93 var il = markupProvider.ProvideValue(node, Module, Context, out typeref);
94 typeref = Module.ImportReference(typeref);
96 var vardef = new VariableDefinition(typeref);
97 Context.Variables[node] = vardef;
98 Context.Body.Variables.Add(vardef);
100 Context.IL.Append(il);
101 Context.IL.Emit(OpCodes.Stloc, vardef);
103 //clean the node as it has been fully exhausted
104 foreach (var prop in node.Properties)
105 if (!node.SkipProperties.Contains(prop.Key))
106 node.SkipProperties.Add(prop.Key);
107 node.CollectionItems.Clear();
111 MethodDefinition factoryCtorInfo = null;
112 MethodDefinition factoryMethodInfo = null;
113 TypeDefinition ownerTypeOfFactoryMethod = null;
114 MethodDefinition parameterizedCtorInfo = null;
115 MethodDefinition ctorInfo = null;
117 if (node.Properties.ContainsKey(XmlName.xArguments) && !node.Properties.ContainsKey(XmlName.xFactoryMethod))
119 factoryCtorInfo = typedef.AllMethods().FirstOrDefault(md => md.IsConstructor &&
122 md.MatchXArguments(node, typeref, Module, Context));
123 if (factoryCtorInfo == null)
125 throw new XamlParseException(
126 string.Format("No constructors found for {0} with matching x:Arguments", typedef.FullName), node);
128 ctorInfo = factoryCtorInfo;
129 if (!typedef.IsValueType) //for ctor'ing typedefs, we first have to ldloca before the params
130 Context.IL.Append(PushCtorXArguments(factoryCtorInfo, node));
132 else if (node.Properties.ContainsKey(XmlName.xFactoryMethod))
134 var factoryMethod = (string)(node.Properties[XmlName.xFactoryMethod] as ValueNode).Value;
135 factoryMethodInfo = typedef.AllMethods().FirstOrDefault(md => !md.IsConstructor &&
136 md.Name == factoryMethod &&
138 md.MatchXArguments(node, typeref, Module, Context));
139 if (factoryMethodInfo == null)
141 var typeExtensionRef = Module.ImportReference(node.XmlType.GetTypeReference(XmlTypeExtensions.ModeOfGetType.OnlyGetTypeExtension, Module, node));
142 typeExtensionRef = typeExtensionRef?.ResolveCached();
144 if (null != typeExtensionRef?.Resolve())
146 factoryMethodInfo = typeExtensionRef.Resolve().AllMethods().FirstOrDefault(md => !md.IsConstructor &&
147 md.Name == factoryMethod &&
149 md.MatchXArguments(node, typeref, Module, Context));
151 if (null != factoryMethod)
153 ownerTypeOfFactoryMethod = typeExtensionRef.ResolveCached();
159 ownerTypeOfFactoryMethod = typedef;
163 if (factoryMethodInfo == null)
165 throw new XamlParseException(
166 String.Format("No static method found for {0}::{1} ({2})", typedef.FullName, factoryMethod, null), node);
168 Context.IL.Append(PushCtorXArguments(factoryMethodInfo, node));
170 if (ctorInfo == null && factoryMethodInfo == null)
172 parameterizedCtorInfo = typedef.Methods.FirstOrDefault(md => md.IsConstructor &&
177 pd.CustomAttributes.Any(
179 ca.AttributeType.FullName ==
180 "Tizen.NUI.Binding.ParameterAttribute")));
182 string missingCtorParameter = null;
183 if (parameterizedCtorInfo != null && ValidateCtorArguments(parameterizedCtorInfo, node, out missingCtorParameter))
185 ctorInfo = parameterizedCtorInfo;
186 // IL_0000: ldstr "foo"
187 Context.IL.Append(PushCtorArguments(parameterizedCtorInfo, node));
190 ctorInfo = ctorInfo ?? typedef.Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters && !md.IsStatic);
192 if (null == ctorInfo && null == factoryMethodInfo)
194 foreach (var method in typedef.Methods)
196 if (method.IsConstructor && !method.IsStatic)
198 bool areAllParamsDefault = true;
200 foreach (var param in method.Parameters)
202 if (!param.HasDefault)
204 areAllParamsDefault = false;
209 if (areAllParamsDefault)
211 if (null == ctorInfo)
217 throw new XamlParseException($"{typedef.FullName} has more than one constructor which params are all default.", node);
223 if (null == ctorInfo)
225 if (!typedef.IsValueType)
227 throw new XamlParseException($"{typedef.FullName} has no constructor which params are all default.", node);
232 factoryCtorInfo = ctorInfo;
234 if (!typedef.IsValueType) //for ctor'ing typedefs, we first have to ldloca before the params
236 Context.IL.Append(PushCtorDefaultArguments(factoryCtorInfo, node));
241 if (parameterizedCtorInfo != null && ctorInfo == null)
242 //there was a parameterized ctor, we didn't use it
243 throw new XamlParseException($"The Property '{missingCtorParameter}' is required to create a '{typedef.FullName}' object.", node);
244 var ctorinforef = ctorInfo?.ResolveGenericParameters(typeref, Module);
246 var factorymethodinforef = factoryMethodInfo?.ResolveGenericParameters(ownerTypeOfFactoryMethod, Module);
247 var implicitOperatorref = typedef.Methods.FirstOrDefault(md =>
251 md.Name == "op_Implicit" && md.Parameters[0].ParameterType.FullName == "System.String");
253 if (ctorinforef != null || factorymethodinforef != null || typedef.IsValueType)
255 VariableDefinition vardef = new VariableDefinition(typeref);
256 Context.Variables[node] = vardef;
257 Context.Body.Variables.Add(vardef);
259 ValueNode vnode = null;
260 if (node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null &&
261 vardef.VariableType.IsValueType)
263 //<Color>Purple</Color>
264 Context.IL.Append(vnode.PushConvertedValue(Context, typeref, new ICustomAttributeProvider[] { typedef },
265 node.PushServiceProvider(Context), false, true));
266 Context.IL.Emit(OpCodes.Stloc, vardef);
268 else if (node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null &&
269 implicitOperatorref != null)
271 //<FileImageSource>path.png</FileImageSource>
272 var implicitOperator = Module.ImportReference(implicitOperatorref);
273 Context.IL.Emit(OpCodes.Ldstr, ((ValueNode)(node.CollectionItems.First())).Value as string);
274 Context.IL.Emit(OpCodes.Call, implicitOperator);
275 Context.IL.Emit(OpCodes.Stloc, vardef);
277 else if (factorymethodinforef != null)
279 Context.IL.Emit(OpCodes.Call, Module.ImportReference(factorymethodinforef));
280 Context.IL.Emit(OpCodes.Stloc, vardef);
282 else if (!typedef.IsValueType)
284 var ctor = Module.ImportReference(ctorinforef);
285 // IL_0001: newobj instance void class [Tizen.NUI.Xaml.UIComponents]Tizen.NUI.Xaml.UIComponents.Button::'.ctor'()
287 bool isConvertValue = false;
288 if (node.CollectionItems.Count == 1 && node.CollectionItems.First() is ValueNode valueNode)
290 if (valueNode.CanConvertValue(Context.Module, typeref, (TypeReference)null))
292 var converterType = valueNode.GetConverterType(new ICustomAttributeProvider[] { typeref.Resolve() });
293 if (null != converterType)
295 isConvertValue = true;
296 Context.IL.Append(vnode.PushConvertedValue(Context, typeref, new ICustomAttributeProvider[] { typedef },
297 node.PushServiceProvider(Context), false, true));
302 if (false == isConvertValue)
304 Context.IL.Emit(OpCodes.Newobj, ctor);
306 Context.IL.Emit(OpCodes.Stloc, vardef);
308 else if (ctorInfo != null && node.Properties.ContainsKey(XmlName.xArguments) &&
309 !node.Properties.ContainsKey(XmlName.xFactoryMethod) && ctorInfo.MatchXArguments(node, typeref, Module, Context))
311 // IL_0008: ldloca.s 1
313 // IL_000b: call instance void valuetype Test/Foo::'.ctor'(bool)
315 var ctor = Module.ImportReference(ctorinforef);
316 Context.IL.Emit(OpCodes.Ldloca, vardef);
317 Context.IL.Append(PushCtorXArguments(factoryCtorInfo, node));
318 Context.IL.Emit(OpCodes.Call, ctor);
322 // IL_0000: ldloca.s 0
323 // IL_0002: initobj Test/Foo
324 Context.IL.Emit(OpCodes.Ldloca, vardef);
325 Context.IL.Emit(OpCodes.Initobj, Module.ImportReference(typedef));
328 if (null != XamlCTask.BaseTypeDefiniation && typedef.InheritsFromOrImplements(XamlCTask.BaseTypeDefiniation))
330 var field = XamlCTask.BaseTypeDefiniation.Properties.SingleOrDefault(fd => fd.Name == "IsCreateByXaml");
334 ValueNode value = new ValueNode("true", node.NamespaceResolver);
335 Set(Context.Variables[node], "IsCreateByXaml", value, null);
338 if (typeref.FullName == "Tizen.NUI.Xaml.ArrayExtension")
340 var visitor = new SetPropertiesVisitor(Context);
341 foreach (var cnode in node.Properties.Values.ToList())
342 cnode.Accept(visitor, node);
343 foreach (var cnode in node.CollectionItems)
344 cnode.Accept(visitor, node);
346 markupProvider = new ArrayExtension();
348 var il = markupProvider.ProvideValue(node, Module, Context, out typeref);
350 vardef = new VariableDefinition(typeref);
351 Context.Variables[node] = vardef;
352 Context.Body.Variables.Add(vardef);
354 Context.IL.Append(il);
355 Context.IL.Emit(OpCodes.Stloc, vardef);
357 //clean the node as it has been fully exhausted
358 foreach (var prop in node.Properties)
359 if (!node.SkipProperties.Contains(prop.Key))
360 node.SkipProperties.Add(prop.Key);
367 private void Set(VariableDefinition parent, string localName, INode node, IXmlLineInfo iXmlLineInfo)
369 var module = Context.Body.Method.Module;
370 TypeReference declaringTypeReference;
371 var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
372 var propertySetter = property.SetMethod;
374 module.ImportReference(parent.VariableType.ResolveCached());
375 var propertySetterRef = module.ImportReference(module.ImportReference(propertySetter).ResolveGenericParameters(declaringTypeReference, module));
376 propertySetterRef.ImportTypes(module);
377 var propertyType = property.ResolveGenericPropertyType(declaringTypeReference, module);
378 var valueNode = node as ValueNode;
379 var elementNode = node as IElementNode;
381 if (parent.VariableType.IsValueType)
382 Context.IL.Emit(OpCodes.Ldloca, parent);
384 Context.IL.Emit(OpCodes.Ldloc, parent);
386 if (valueNode != null)
388 foreach (var instruction in valueNode.PushConvertedValue(Context, propertyType, new ICustomAttributeProvider[] { property, propertyType.ResolveCached() }, valueNode.PushServiceProvider(Context, propertyRef: property), false, true))
390 Context.IL.Append(instruction);
393 if (parent.VariableType.IsValueType)
394 Context.IL.Emit(OpCodes.Call, propertySetterRef);
396 Context.IL.Emit(OpCodes.Callvirt, propertySetterRef);
400 public void Visit(RootNode node, INode parentNode)
405 var ilnode = (ILRootNode)node;
406 var typeref = ilnode.TypeReference;
407 var vardef = new VariableDefinition(typeref);
408 Context.Variables[node] = vardef;
409 Context.Root = vardef;
410 Context.Body.Variables.Add(vardef);
411 Context.IL.Emit(OpCodes.Ldarg_0);
412 Context.IL.Emit(OpCodes.Stloc, vardef);
415 public void Visit(ListNode node, INode parentNode)
418 if (SetPropertiesVisitor.TryGetPropertyName(node, parentNode, out name))
422 bool ValidateCtorArguments(MethodDefinition ctorinfo, ElementNode enode, out string firstMissingProperty)
424 firstMissingProperty = null;
425 foreach (var parameter in ctorinfo.Parameters)
428 parameter.CustomAttributes.First(ca => ca.AttributeType.FullName == "Tizen.NUI.Binding.ParameterAttribute")
429 .ConstructorArguments.First()
431 if (!enode.Properties.ContainsKey(new XmlName("", propname)))
433 firstMissingProperty = propname;
440 IEnumerable<Instruction> PushCtorArguments(MethodDefinition ctorinfo, ElementNode enode)
442 foreach (var parameter in ctorinfo.Parameters)
445 parameter.CustomAttributes.First(ca => ca.AttributeType.FullName == "Tizen.NUI.Binding.ParameterAttribute")
446 .ConstructorArguments.First()
448 var node = enode.Properties[new XmlName("", propname)];
449 if (!enode.SkipProperties.Contains(new XmlName("", propname)))
450 enode.SkipProperties.Add(new XmlName("", propname));
451 VariableDefinition vardef;
452 ValueNode vnode = null;
454 if (node is IElementNode && (vardef = Context.Variables[node as IElementNode]) != null)
455 yield return Instruction.Create(OpCodes.Ldloc, vardef);
456 else if ((vnode = node as ValueNode) != null)
458 foreach (var instruction in vnode.PushConvertedValue(Context,
459 parameter.ParameterType,
460 new ICustomAttributeProvider[] { parameter, parameter.ParameterType.ResolveCached() },
461 enode.PushServiceProvider(Context), false, true))
462 yield return instruction;
467 IEnumerable<Instruction> PushCtorDefaultArguments(MethodDefinition factoryCtorInfo, ElementNode enode)
469 var arguments = new List<INode>();
471 for (var i = 0; i < factoryCtorInfo.Parameters.Count; i++)
473 var parameter = factoryCtorInfo.Parameters[i];
475 ValueNode arg = new ValueNode(parameter.Constant?.ToString(), enode.NamespaceResolver);
479 foreach (var instruction in arg.PushConvertedValue(Context,
480 parameter.ParameterType,
481 new ICustomAttributeProvider[] { parameter, parameter.ParameterType.ResolveCached() },
482 enode.PushServiceProvider(Context), false, true))
483 yield return instruction;
489 IEnumerable<Instruction> PushCtorXArguments(MethodDefinition factoryCtorInfo, ElementNode enode)
491 if (!enode.Properties.ContainsKey(XmlName.xArguments))
494 var arguments = new List<INode>();
495 var node = enode.Properties[XmlName.xArguments] as ElementNode;
498 node.Accept(new SetPropertiesVisitor(Context, true), null);
502 var list = enode.Properties[XmlName.xArguments] as ListNode;
505 foreach (var n in list.CollectionItems)
509 for (var i = 0; i < arguments.Count; i++)
511 var parameter = factoryCtorInfo.Parameters[i];
512 var arg = arguments[i];
513 VariableDefinition vardef;
514 ValueNode vnode = null;
516 if (arg is IElementNode && (vardef = Context.Variables[arg as IElementNode]) != null)
517 yield return Instruction.Create(OpCodes.Ldloc, vardef);
518 else if ((vnode = arg as ValueNode) != null)
520 foreach (var instruction in vnode.PushConvertedValue(Context,
521 parameter.ParameterType,
522 new ICustomAttributeProvider[] { parameter, parameter.ParameterType.ResolveCached() },
523 enode.PushServiceProvider(Context), false, true))
524 yield return instruction;
528 for (var i = arguments.Count; i < factoryCtorInfo.Parameters.Count; i++)
530 var parameter = factoryCtorInfo.Parameters[i];
531 var arg = new ValueNode(parameter.Constant?.ToString(), node?.NamespaceResolver);
533 foreach (var instruction in arg.PushConvertedValue(Context,
534 parameter.ParameterType,
535 new ICustomAttributeProvider[] { parameter, parameter.ParameterType.ResolveCached() },
536 enode.PushServiceProvider(Context), false, true))
537 yield return instruction;
541 static bool IsXaml2009LanguagePrimitive(IElementNode node)
543 if (node.NamespaceURI == XamlParser.X2009Uri)
545 var n = node.XmlType.Name.Split(':')[1];
546 return n != "Array" && n != "Nullable";
548 if (node.NamespaceURI != "clr-namespace:System;assembly=mscorlib")
550 var name = node.XmlType.Name.Split(':')[1];
551 if (name == "SByte" ||
565 name == "TimeSpan" ||
571 IEnumerable<Instruction> PushValueFromLanguagePrimitive(TypeReference typeRef, ElementNode node)
573 var module = Context.Body.Method.Module;
574 var hasValue = node.CollectionItems.Count == 1 && node.CollectionItems[0] is ValueNode &&
575 ((ValueNode)node.CollectionItems[0]).Value is string;
576 var valueString = hasValue ? ((ValueNode)node.CollectionItems[0]).Value as string : string.Empty;
577 switch (typeRef.FullName)
580 if (hasValue && sbyte.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out sbyte outsbyte))
581 yield return Create(Ldc_I4, (int)outsbyte);
583 yield return Create(Ldc_I4, 0x00);
586 if (hasValue && short.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out short outshort))
587 yield return Create(Ldc_I4, outshort);
589 yield return Create(Ldc_I4, 0x00);
592 if (hasValue && int.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out int outint))
593 yield return Create(Ldc_I4, outint);
595 yield return Create(Ldc_I4, 0x00);
598 if (hasValue && long.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out long outlong))
599 yield return Create(Ldc_I8, outlong);
601 yield return Create(Ldc_I8, 0L);
604 if (hasValue && byte.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out byte outbyte))
605 yield return Create(Ldc_I4, (int)outbyte);
607 yield return Create(Ldc_I4, 0x00);
609 case "System.UInt16":
610 if (hasValue && short.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out short outushort))
611 yield return Create(Ldc_I4, outushort);
613 yield return Create(Ldc_I4, 0x00);
615 case "System.UInt32":
616 if (hasValue && int.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out int outuint))
617 yield return Create(Ldc_I4, outuint);
619 yield return Create(Ldc_I4, 0x00);
621 case "System.UInt64":
622 if (hasValue && long.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out long outulong))
623 yield return Create(Ldc_I8, outulong);
625 yield return Create(Ldc_I8, 0L);
627 case "System.Boolean":
628 if (hasValue && bool.TryParse(valueString, out bool outbool))
629 yield return Create(outbool ? Ldc_I4_1 : Ldc_I4_0);
631 yield return Create(Ldc_I4_0);
633 case "System.String":
634 yield return Create(Ldstr, valueString);
636 case "System.Object":
638 module.TypeSystem.Object.ResolveCached()
639 .Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters);
640 var ctor = module.ImportReference(ctorinfo);
641 yield return Create(Newobj, ctor);
644 if (hasValue && char.TryParse(valueString, out char outchar))
645 yield return Create(Ldc_I4, outchar);
647 yield return Create(Ldc_I4, 0x00);
649 case "System.Decimal":
651 if (hasValue && decimal.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outdecimal))
653 var vardef = new VariableDefinition(module.ImportReference(("mscorlib", "System", "Decimal")));
654 Context.Body.Variables.Add(vardef);
655 //Use an extra temp var so we can push the value to the stack, just like other cases
656 // IL_0003: ldstr "adecimal"
657 // IL_0008: ldc.i4.s 0x6f
658 // IL_000a: call class [mscorlib]System.Globalization.CultureInfo class [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture()
659 // IL_000f: ldloca.s 0
660 // IL_0011: call bool valuetype [mscorlib]System.Decimal::TryParse(string, valuetype [mscorlib]System.Globalization.NumberStyles, class [mscorlib]System.IFormatProvider, [out] valuetype [mscorlib]System.Decimal&)
662 yield return Create(Ldstr, valueString);
663 yield return Create(Ldc_I4, 0x6f); //NumberStyles.Number
664 yield return Create(Call, module.ImportPropertyGetterReference(("mscorlib", "System.Globalization", "CultureInfo"),
665 propertyName: "InvariantCulture",
667 yield return Create(Ldloca, vardef);
668 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Decimal"),
669 methodName: "TryParse",
670 parameterTypes: new[] {
671 ("mscorlib", "System", "String"),
672 ("mscorlib", "System.Globalization", "NumberStyles"),
673 ("mscorlib", "System", "IFormatProvider"),
674 ("mscorlib", "System", "Decimal"),
677 yield return Create(Pop);
678 yield return Create(Ldloc, vardef);
682 yield return Create(Ldc_I4_0);
683 yield return Create(Newobj, module.ImportCtorReference(("mscorlib", "System", "Decimal"), parameterTypes: new[] { ("mscorlib", "System", "Int32") }));
686 case "System.Single":
687 if (hasValue && float.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out float outfloat))
688 yield return Create(Ldc_R4, outfloat);
690 yield return Create(Ldc_R4, 0f);
692 case "System.Double":
693 if (hasValue && double.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out double outdouble))
694 yield return Create(Ldc_R8, outdouble);
696 yield return Create(Ldc_R8, 0d);
698 case "System.TimeSpan":
699 if (hasValue && TimeSpan.TryParse(valueString, CultureInfo.InvariantCulture, out TimeSpan outspan))
701 var vardef = new VariableDefinition(module.ImportReference(("mscorlib", "System", "TimeSpan")));
702 Context.Body.Variables.Add(vardef);
703 //Use an extra temp var so we can push the value to the stack, just like other cases
704 yield return Create(Ldstr, valueString);
705 yield return Create(Call, module.ImportPropertyGetterReference(("mscorlib", "System.Globalization", "CultureInfo"),
706 propertyName: "InvariantCulture", isStatic: true));
707 yield return Create(Ldloca, vardef);
708 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "TimeSpan"),
709 methodName: "TryParse",
710 parameterTypes: new[] {
711 ("mscorlib", "System", "String"),
712 ("mscorlib", "System", "IFormatProvider"),
713 ("mscorlib", "System", "TimeSpan"),
716 yield return Create(Pop);
717 yield return Create(Ldloc, vardef);
721 yield return Create(Ldc_I8, 0L);
722 yield return Create(Newobj, module.ImportCtorReference(("mscorlib", "System", "TimeSpan"), parameterTypes: new[] { ("mscorlib", "System", "Int64") }));
726 if (hasValue && Uri.TryCreate(valueString, UriKind.RelativeOrAbsolute, out Uri outuri))
728 var vardef = new VariableDefinition(module.ImportReference(("System", "System", "Uri")));
729 Context.Body.Variables.Add(vardef);
730 //Use an extra temp var so we can push the value to the stack, just like other cases
731 yield return Create(Ldstr, valueString);
732 yield return Create(Ldc_I4, (int)UriKind.RelativeOrAbsolute);
733 yield return Create(Ldloca, vardef);
734 yield return Create(Call, module.ImportMethodReference(("System", "System", "Uri"),
735 methodName: "TryCreate",
736 parameterTypes: new[] {
737 ("mscorlib", "System", "String"),
738 ("System", "System", "UriKind"),
739 ("System", "System", "Uri"),
742 yield return Create(Pop);
743 yield return Create(Ldloc, vardef);
746 yield return Create(Ldnull);
749 var defaultCtor = module.ImportCtorReference(typeRef, parameterTypes: null);
750 if (defaultCtor != null)
751 yield return Create(Newobj, defaultCtor);
754 //should never happen. but if it does, this prevents corrupting the IL stack
755 yield return Create(Ldnull);