This internal class contains methods that allow binding to extension functions and invoking them.
Example #1
0
        public XmlExtensionFunction Bind(
            string name,
            string namespaceUri,
            int numArgs,
            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type objectType,
            BindingFlags flags)
        {
            XmlExtensionFunction func;

            _funcCached ??= new XmlExtensionFunction();

            // If the extension function already exists in the table, then binding has already been performed
            _funcCached.Init(name, namespaceUri, numArgs, objectType, flags);
            if (!_table.TryGetValue(_funcCached, out func))
            {
                // Function doesn't exist, so bind it and enter it into the table
                func        = _funcCached;
                _funcCached = null;

                func.Bind();
                _table.Add(func, func);
            }

            return(func);
        }
Example #2
0
        /// <summary>
        /// Return true if this XmlExtensionFunction has the same values as another XmlExtensionFunction.
        /// </summary>
        public override bool Equals(object other)
        {
            XmlExtensionFunction that = other as XmlExtensionFunction;

            Debug.Assert(that != null);

            // Compare name, argument count, object type, and binding flags
            return(_hashCode == that._hashCode && _name == that._name && _namespaceUri == that._namespaceUri &&
                   _numArgs == that._numArgs && _objectType == that._objectType && _flags == that._flags);
        }
        public XmlExtensionFunction Bind(string name, string namespaceUri, int numArgs, Type objectType, BindingFlags flags) {
            XmlExtensionFunction func;

            if (this.funcCached == null)
                this.funcCached = new XmlExtensionFunction();

            // If the extension function already exists in the table, then binding has already been performed
            this.funcCached.Init(name, namespaceUri, numArgs, objectType, flags);
            if (!this.table.TryGetValue(this.funcCached, out func)) {
                // Function doesn't exist, so bind it and enter it into the table
                func = this.funcCached;
                this.funcCached = null;

                func.Bind();
                this.table.Add(func, func);
            }

            return func;
        }
Example #4
0
        public XmlExtensionFunction Bind(string name, string namespaceUri, int numArgs, Type objectType, BindingFlags flags)
        {
            XmlExtensionFunction func;

            if (_funcCached == null)
            {
                _funcCached = new XmlExtensionFunction();
            }

            // If the extension function already exists in the table, then binding has already been performed
            _funcCached.Init(name, namespaceUri, numArgs, objectType, flags);
            if (!_table.TryGetValue(_funcCached, out func))
            {
                // Function doesn't exist, so bind it and enter it into the table
                func        = _funcCached;
                _funcCached = null;

                func.Bind();
                _table.Add(func, func);
            }

            return(func);
        }
        public XmlQueryType CheckXsltInvokeEarlyBound(QilInvokeEarlyBound node) {
        #if DEBUG
            CheckLiteralValue(node[0], typeof(QilName));
            CheckLiteralValue(node[1], typeof(MethodInfo));
            CheckClassAndNodeType(node[2], typeof(QilList), QilNodeType.ActualParameterList);

            XmlExtensionFunction extFunc = new XmlExtensionFunction(node.Name.LocalName, node.Name.NamespaceUri, node.ClrMethod);
            QilList actualArgs = node.Arguments;
            Check(actualArgs.Count == extFunc.Method.GetParameters().Length, actualArgs, "InvokeEarlyBound argument count must match function's argument count");

            for (int i = 0; i < actualArgs.Count; i++) {
                Check(actualArgs[i].XmlType.IsSubtypeOf(extFunc.GetXmlArgumentType(i)), actualArgs[i], "InvokeEarlyBound argument must be a subtype of the invoked function's argument type");
            }
        #endif

            return node.XmlType;
        }
        private QilNode GenerateScriptCall(QilName name, XmlExtensionFunction scrFunc, IList<QilNode> args) {
            XmlQueryType xmlTypeFormalArg;

            for (int i = 0; i < args.Count; i++) {
                xmlTypeFormalArg = scrFunc.GetXmlArgumentType(i);
                switch (xmlTypeFormalArg.TypeCode) {
                    case XmlTypeCode.Boolean:       args[i] = f.ConvertToBoolean(args[i]); break;
                    case XmlTypeCode.Double:        args[i] = f.ConvertToNumber(args[i]); break;
                    case XmlTypeCode.String:        args[i] = f.ConvertToString(args[i]); break;
                    case XmlTypeCode.Node:          args[i] = xmlTypeFormalArg.IsSingleton ? f.ConvertToNode(args[i]) : f.ConvertToNodeSet(args[i]); break;
                    case XmlTypeCode.Item:          break;
                    default: Debug.Fail("This XmlTypeCode should never be inferred from a Clr type: " + xmlTypeFormalArg.TypeCode); break;
                }
            }

            return f.XsltInvokeEarlyBound(name, scrFunc.Method, scrFunc.XmlReturnType, args);
        }
Example #7
0
        /// <summary>
        /// Get a late-bound extension object from the external argument list.  Bind to a method on the object and invoke it,
        /// passing "args" as arguments.
        /// </summary>
        public IList <XPathItem> InvokeXsltLateBoundFunction(string name, string namespaceUri, IList <XPathItem>[] args)
        {
            object instance;

            object[]     objActualArgs;
            XmlQueryType xmlTypeFormalArg;
            Type         clrTypeFormalArg;
            object       objRet;

            // Get external object instance from argument list (throw if either the list or the instance doesn't exist)
            instance = (_argList != null) ? _argList.GetExtensionObject(namespaceUri) : null;
            if (instance == null)
            {
                throw new XslTransformException(SR.XmlIl_UnknownExtObj, namespaceUri);
            }

            // Bind to a method on the instance object
            if (_extFuncsLate == null)
            {
                _extFuncsLate = new XmlExtensionFunctionTable();
            }

            // Bind to the instance, looking for a matching method (throws if no matching method)
            XmlExtensionFunction extFunc = _extFuncsLate.Bind(name, namespaceUri, args.Length, instance.GetType(), XmlQueryRuntime.LateBoundFlags);

            // Create array which will contain the actual arguments
            objActualArgs = new object[args.Length];

            for (int i = 0; i < args.Length; i++)
            {
                // 1. Assume that the input value can only have one of the following 5 Xslt types:
                //      xs:double, xs:string, xs:boolean, node* (can be rtf)
                // 2. Convert each Rtf value to a NodeSet containing one node.  Now the value may only have one of the 4 Xslt types.
                // 3. Convert from one of the 4 Xslt internal types to the Xslt internal type which is closest to the formal
                //    argument's Xml type (inferred from the Clr type of the formal argument).

                xmlTypeFormalArg = extFunc.GetXmlArgumentType(i);
                switch (xmlTypeFormalArg.TypeCode)
                {
                case XmlTypeCode.Boolean: objActualArgs[i] = XsltConvert.ToBoolean(args[i]); break;

                case XmlTypeCode.Double: objActualArgs[i] = XsltConvert.ToDouble(args[i]); break;

                case XmlTypeCode.String: objActualArgs[i] = XsltConvert.ToString(args[i]); break;

                case XmlTypeCode.Node:
                    if (xmlTypeFormalArg.IsSingleton)
                    {
                        objActualArgs[i] = XsltConvert.ToNode(args[i]);
                    }
                    else
                    {
                        objActualArgs[i] = XsltConvert.ToNodeSet(args[i]);
                    }
                    break;

                case XmlTypeCode.Item:
                    objActualArgs[i] = args[i];
                    break;

                default:
                    Debug.Fail("This XmlTypeCode should never be inferred from a Clr type: " + xmlTypeFormalArg.TypeCode);
                    break;
                }

                // 4. Change the Clr representation to the Clr type of the formal argument
                clrTypeFormalArg = extFunc.GetClrArgumentType(i);
                if (xmlTypeFormalArg.TypeCode == XmlTypeCode.Item || !clrTypeFormalArg.IsAssignableFrom(objActualArgs[i].GetType()))
                {
                    objActualArgs[i] = _runtime.ChangeTypeXsltArgument(xmlTypeFormalArg, objActualArgs[i], clrTypeFormalArg);
                }
            }

            // 1. Invoke the late bound method
            objRet = extFunc.Invoke(instance, objActualArgs);

            // 2. Convert to IList<XPathItem>
            if (objRet == null && extFunc.ClrReturnType == XsltConvert.VoidType)
            {
                return(XmlQueryNodeSequence.Empty);
            }

            return((IList <XPathItem>)_runtime.ChangeTypeXsltResult(XmlQueryTypeFactory.ItemS, objRet));
        }
Example #8
0
        /// <summary>
        /// Generate code for for QilNodeType.XsltInvokeEarlyBound.
        /// </summary>
        protected override QilNode VisitXsltInvokeEarlyBound(QilInvokeEarlyBound ndInvoke)
        {
            QilName ndName = ndInvoke.Name;
            XmlExtensionFunction extFunc;
            Type clrTypeRetSrc, clrTypeRetDst;

            // Retrieve metadata from the extension function
            extFunc = new XmlExtensionFunction(ndName.LocalName, ndName.NamespaceUri, ndInvoke.ClrMethod);
            clrTypeRetSrc = extFunc.ClrReturnType;
            clrTypeRetDst = GetStorageType(ndInvoke);

            // Prepare to call runtime.ChangeTypeXsltResult
            if (clrTypeRetSrc != clrTypeRetDst && !ndInvoke.XmlType.IsEmpty)
            {
                _helper.LoadQueryRuntime();
                _helper.LoadInteger(_helper.StaticData.DeclareXmlType(ndInvoke.XmlType));
            }

            // If this is not a static method, then get the instance object
            if (!extFunc.Method.IsStatic)
            {
                // Special-case the XsltLibrary object
                if (ndName.NamespaceUri.Length == 0)
                    _helper.LoadXsltLibrary();
                else
                    _helper.CallGetEarlyBoundObject(_helper.StaticData.DeclareEarlyBound(ndName.NamespaceUri, extFunc.Method.DeclaringType), extFunc.Method.DeclaringType);
            }

            // Generate code to push each Invoke argument onto the stack
            for (int iArg = 0; iArg < ndInvoke.Arguments.Count; iArg++)
            {
                QilNode ndActualArg;
                XmlQueryType xmlTypeFormalArg;
                Type clrTypeActualArg, clrTypeFormalArg;

                ndActualArg = ndInvoke.Arguments[iArg];

                // Infer Xml type and Clr type of formal argument
                xmlTypeFormalArg = extFunc.GetXmlArgumentType(iArg);
                clrTypeFormalArg = extFunc.GetClrArgumentType(iArg);

                Debug.Assert(ndActualArg.XmlType.IsSubtypeOf(xmlTypeFormalArg), "Xml type of actual arg must be a subtype of the Xml type of the formal arg");

                // Use different conversion rules for internal Xslt libraries.  If the actual argument is
                // stored using Clr type T, then library must use type T, XPathItem, IList<T>, or IList<XPathItem>.
                // If the actual argument is stored using Clr type IList<T>, then library must use type
                // IList<T> or IList<XPathItem>.  This is to ensure that there will not be unnecessary
                // conversions that take place when calling into an internal library.
                if (ndName.NamespaceUri.Length == 0)
                {
                    Type itemType = GetItemStorageType(ndActualArg);

                    if (clrTypeFormalArg == XmlILMethods.StorageMethods[itemType].IListType)
                    {
                        // Formal type is IList<T>
                        NestedVisitEnsureStack(ndActualArg, itemType, true);
                    }
                    else if (clrTypeFormalArg == XmlILMethods.StorageMethods[typeof(XPathItem)].IListType)
                    {
                        // Formal type is IList<XPathItem>
                        NestedVisitEnsureStack(ndActualArg, typeof(XPathItem), true);
                    }
                    else if ((ndActualArg.XmlType.IsSingleton && clrTypeFormalArg == itemType) || ndActualArg.XmlType.TypeCode == XmlTypeCode.None)
                    {
                        // Formal type is T
                        NestedVisitEnsureStack(ndActualArg, clrTypeFormalArg, false);
                    }
                    else if (ndActualArg.XmlType.IsSingleton && clrTypeFormalArg == typeof(XPathItem))
                    {
                        // Formal type is XPathItem
                        NestedVisitEnsureStack(ndActualArg, typeof(XPathItem), false);
                    }
                    else
                        Debug.Fail("Internal Xslt library may not use parameters of type " + clrTypeFormalArg);
                }
                else
                {
                    // There is an implicit upcast to the Xml type of the formal argument.  This can change the Clr storage type.
                    clrTypeActualArg = GetStorageType(xmlTypeFormalArg);

                    // If the formal Clr type is typeof(object) or if it is not a supertype of the actual Clr type, then call ChangeTypeXsltArgument
                    if (xmlTypeFormalArg.TypeCode == XmlTypeCode.Item || !clrTypeFormalArg.IsAssignableFrom(clrTypeActualArg))
                    {
                        // (clrTypeFormalArg) runtime.ChangeTypeXsltArgument(xmlTypeFormalArg, (object) value, clrTypeFormalArg);
                        _helper.LoadQueryRuntime();
                        _helper.LoadInteger(_helper.StaticData.DeclareXmlType(xmlTypeFormalArg));
                        NestedVisitEnsureStack(ndActualArg, GetItemStorageType(xmlTypeFormalArg), !xmlTypeFormalArg.IsSingleton);
                        _helper.TreatAs(clrTypeActualArg, typeof(object));
                        _helper.LoadType(clrTypeFormalArg);
                        _helper.Call(XmlILMethods.ChangeTypeXsltArg);
                        _helper.TreatAs(typeof(object), clrTypeFormalArg);
                    }
                    else
                    {
                        NestedVisitEnsureStack(ndActualArg, GetItemStorageType(xmlTypeFormalArg), !xmlTypeFormalArg.IsSingleton);
                    }
                }
            }

            // Invoke the target method
            _helper.Call(extFunc.Method);

            // Return value is on the stack; convert it to canonical ILGen storage type
            if (ndInvoke.XmlType.IsEmpty)
            {
                _helper.Emit(OpCodes.Ldsfld, XmlILMethods.StorageMethods[typeof(XPathItem)].SeqEmpty);
            }
            else if (clrTypeRetSrc != clrTypeRetDst)
            {
                // (T) runtime.ChangeTypeXsltResult(idxType, (object) value);
                _helper.TreatAs(clrTypeRetSrc, typeof(object));
                _helper.Call(XmlILMethods.ChangeTypeXsltResult);
                _helper.TreatAs(typeof(object), clrTypeRetDst);
            }
            else if (ndName.NamespaceUri.Length != 0 && !clrTypeRetSrc.GetTypeInfo().IsValueType)
            {
                // Check for null if a user-defined extension function returns a reference type
                Label lblSkip = _helper.DefineLabel();
                _helper.Emit(OpCodes.Dup);
                _helper.Emit(OpCodes.Brtrue, lblSkip);
                _helper.LoadQueryRuntime();
                _helper.Emit(OpCodes.Ldstr, SR.Xslt_ItemNull);
                _helper.Call(XmlILMethods.ThrowException);
                _helper.MarkLabel(lblSkip);
            }

            _iterCurr.Storage = StorageDescriptor.Stack(GetItemStorageType(ndInvoke), !ndInvoke.XmlType.IsSingleton);

            return ndInvoke;
        }