/// <summary> /// Create MethodBuilder metadata for the specified QilExpression function. Annotate ndFunc with the /// MethodBuilder. Also, each QilExpression argument type should be converted to a corresponding Clr type. /// Each argument QilExpression node should be annotated with the resulting ParameterBuilder. /// </summary> private void CreateFunctionMetadata(IList <QilNode> funcList) { MethodInfo methInfo; Type[] paramTypes; string[] paramNames; Type typReturn; XmlILMethodAttributes methAttrs; foreach (QilFunction ndFunc in funcList) { paramTypes = new Type[ndFunc.Arguments.Count]; paramNames = new string[ndFunc.Arguments.Count]; // Loop through all other parameters and save their types in the array for (int arg = 0; arg < ndFunc.Arguments.Count; arg++) { QilParameter ndParam = (QilParameter)ndFunc.Arguments[arg]; Debug.Assert(ndParam.NodeType == QilNodeType.Parameter); // Get the type of each argument as a Clr type paramTypes[arg] = XmlILTypeHelper.GetStorageType(ndParam.XmlType); // Get the name of each argument if (ndParam.DebugName != null) { paramNames[arg] = ndParam.DebugName; } } // Get the type of the return value if (XmlILConstructInfo.Read(ndFunc).PushToWriterLast) { // Push mode functions do not have a return value typReturn = typeof(void); } else { // Pull mode functions have a return value typReturn = XmlILTypeHelper.GetStorageType(ndFunc.XmlType); } // Create the method metadata methAttrs = ndFunc.SourceLine == null ? XmlILMethodAttributes.NonUser : XmlILMethodAttributes.None; methInfo = _module.DefineMethod(ndFunc.DebugName, typReturn, paramTypes, paramNames, methAttrs); for (int arg = 0; arg < ndFunc.Arguments.Count; arg++) { // Set location of parameter on Let node annotation XmlILAnnotation.Write(ndFunc.Arguments[arg]).ArgumentPosition = arg; } // Annotate function with the MethodInfo XmlILAnnotation.Write(ndFunc).FunctionBinding = methInfo; } }
/// <summary> /// Generate metadata for a method that calculates a global value. /// </summary> private void CreateGlobalValueMetadata(IList <QilNode> globalList) { MethodInfo methInfo; Type typReturn; XmlILMethodAttributes methAttrs; foreach (QilReference ndRef in globalList) { // public T GlobalValue() typReturn = XmlILTypeHelper.GetStorageType(ndRef.XmlType); methAttrs = ndRef.SourceLine == null ? XmlILMethodAttributes.NonUser : XmlILMethodAttributes.None; methInfo = _module.DefineMethod(ndRef.DebugName.ToString(), typReturn, Array.Empty <Type>(), Array.Empty <string>(), methAttrs); // Annotate function with MethodBuilder XmlILAnnotation.Write(ndRef).FunctionBinding = methInfo; } }
/// <summary> /// Convert from the Clr type of "value" to the default Clr type that ILGen uses to represent the xml type, using /// the conversion rules of the xml type. /// </summary> internal object ChangeTypeXsltResult(XmlQueryType xmlType, object value) { if (value == null) { throw new XslTransformException(SR.Xslt_ItemNull, string.Empty); } switch (xmlType.TypeCode) { case XmlTypeCode.String: if (value.GetType() == XsltConvert.DateTimeType) { value = XsltConvert.ToString((DateTime)value); } break; case XmlTypeCode.Double: if (value.GetType() != XsltConvert.DoubleType) { value = ((IConvertible)value).ToDouble(null); } break; case XmlTypeCode.Node: if (!xmlType.IsSingleton) { XPathArrayIterator iter = value as XPathArrayIterator; // Special-case XPathArrayIterator in order to avoid copies if (iter != null && iter.AsList is XmlQueryNodeSequence) { value = iter.AsList as XmlQueryNodeSequence; } else { // Iterate over list and ensure it only contains nodes XmlQueryNodeSequence seq = new XmlQueryNodeSequence(); IList list = value as IList; if (list != null) { for (int i = 0; i < list.Count; i++) { seq.Add(EnsureNavigator(list[i])); } } else { foreach (object o in (IEnumerable)value) { seq.Add(EnsureNavigator(o)); } } value = seq; } // Always sort node-set by document order value = ((XmlQueryNodeSequence)value).DocOrderDistinct(_docOrderCmp); } break; case XmlTypeCode.Item: { Type sourceType = value.GetType(); IXPathNavigable navigable; // If static type is item, then infer type based on dynamic value switch (XsltConvert.InferXsltType(sourceType).TypeCode) { case XmlTypeCode.Boolean: value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Boolean), value)); break; case XmlTypeCode.Double: value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Double), ((IConvertible)value).ToDouble(null))); break; case XmlTypeCode.String: if (sourceType == XsltConvert.DateTimeType) { value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String), XsltConvert.ToString((DateTime)value))); } else { value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String), value)); } break; case XmlTypeCode.Node: // Support XPathNavigator[] value = ChangeTypeXsltResult(XmlQueryTypeFactory.NodeS, value); break; case XmlTypeCode.Item: // Support XPathNodeIterator if (value is XPathNodeIterator) { value = ChangeTypeXsltResult(XmlQueryTypeFactory.NodeS, value); break; } // Support IXPathNavigable and XPathNavigator navigable = value as IXPathNavigable; if (navigable != null) { if (value is XPathNavigator) { value = new XmlQueryNodeSequence((XPathNavigator)value); } else { value = new XmlQueryNodeSequence(navigable.CreateNavigator()); } break; } throw new XslTransformException(SR.Xslt_UnsupportedClrType, sourceType.Name); } break; } } #if FEATURE_COMPILED_XSL Debug.Assert(XmlILTypeHelper.GetStorageType(xmlType).IsAssignableFrom(value.GetType()), "Xml type " + xmlType + " is not represented in ILGen as " + value.GetType().Name); #endif return(value); }
/// <summary> /// Convert from the Clr type of "value" to Clr type "destinationType" using V1 Xslt rules. /// These rules include converting any Rtf values to Nodes. /// </summary> internal object ChangeTypeXsltArgument(XmlQueryType xmlType, object value, Type destinationType) { #if FEATURE_COMPILED_XSL Debug.Assert(XmlILTypeHelper.GetStorageType(xmlType).IsAssignableFrom(value.GetType()), "Values passed to ChangeTypeXsltArgument should be in ILGen's default Clr representation."); #endif Debug.Assert(destinationType == XsltConvert.ObjectType || !destinationType.IsAssignableFrom(value.GetType()), "No need to call ChangeTypeXsltArgument since value is already assignable to destinationType " + destinationType); switch (xmlType.TypeCode) { case XmlTypeCode.String: if (destinationType == XsltConvert.DateTimeType) { value = XsltConvert.ToDateTime((string)value); } break; case XmlTypeCode.Double: if (destinationType != XsltConvert.DoubleType) { value = Convert.ChangeType(value, destinationType, CultureInfo.InvariantCulture); } break; case XmlTypeCode.Node: Debug.Assert(xmlType != XmlQueryTypeFactory.Node && xmlType != XmlQueryTypeFactory.NodeS, "Rtf values should have been eliminated by caller."); if (destinationType == XsltConvert.XPathNodeIteratorType) { value = new XPathArrayIterator((IList)value); } else if (destinationType == XsltConvert.XPathNavigatorArrayType) { // Copy sequence to XPathNavigator[] IList <XPathNavigator> seq = (IList <XPathNavigator>)value; XPathNavigator[] navArray = new XPathNavigator[seq.Count]; for (int i = 0; i < seq.Count; i++) { navArray[i] = seq[i]; } value = navArray; } break; case XmlTypeCode.Item: { // Only typeof(object) is supported as a destination type if (destinationType != XsltConvert.ObjectType) { throw new XslTransformException(SR.Xslt_UnsupportedClrType, destinationType.Name); } // Convert to default, backwards-compatible representation // 1. NodeSet: System.Xml.XPath.XPathNodeIterator // 2. Rtf: System.Xml.XPath.XPathNavigator // 3. Other: Default V1 representation IList <XPathItem> seq = (IList <XPathItem>)value; if (seq.Count == 1) { XPathItem item = seq[0]; if (item.IsNode) { // Node or Rtf RtfNavigator rtf = item as RtfNavigator; if (rtf != null) { value = rtf.ToNavigator(); } else { value = new XPathArrayIterator((IList)value); } } else { // Atomic value value = item.TypedValue; } } else { // Nodeset value = new XPathArrayIterator((IList)value); } break; } } Debug.Assert(destinationType.IsAssignableFrom(value.GetType()), "ChangeType from type " + value.GetType().Name + " to type " + destinationType.Name + " failed"); return(value); }