public QilNode GenerateInvoke(QilFunction func, IList <XslNode> actualArgs) { _iterStack.Clear(); _formalArgs = func.Arguments; _invokeArgs = _fac.ActualParameterList(); // curArg is an instance variable used in Clone() method for (_curArg = 0; _curArg < _formalArgs.Count; _curArg++) { // Find actual value for a given formal arg QilParameter formalArg = (QilParameter)_formalArgs[_curArg]; QilNode? invokeArg = FindActualArg(formalArg, actualArgs); // If actual value was not specified, use the default value and copy its debug comment if (invokeArg == null) { if (_debug) { if (formalArg.Name !.NamespaceUri == XmlReservedNs.NsXslDebug) { Debug.Assert(formalArg.Name.LocalName == "namespaces", "Cur,Pos,Last don't have default values and should be always added to by caller in AddImplicitArgs()"); Debug.Assert(formalArg.DefaultValue != null, "PrecompileProtoTemplatesHeaders() set it"); invokeArg = Clone(formalArg.DefaultValue); } else { invokeArg = _fac.DefaultValueMarker(); } } else { Debug.Assert(formalArg.Name !.NamespaceUri != XmlReservedNs.NsXslDebug, "Cur,Pos,Last don't have default values and should be always added to by caller in AddImplicitArgs(). We don't have $namespaces in !debug."); invokeArg = Clone(formalArg.DefaultValue !); } } XmlQueryType formalType = formalArg.XmlType !; XmlQueryType invokeType = invokeArg.XmlType !; // Possible arg types: anyType, node-set, string, boolean, and number _fac.CheckXsltType(formalArg); _fac.CheckXsltType(invokeArg); if (!invokeType.IsSubtypeOf(formalType)) { // This may occur only if inferred type of invokeArg is XslFlags.None Debug.Assert(invokeType == T.ItemS, "Actual argument type is not a subtype of formal argument type"); invokeArg = _fac.TypeAssert(invokeArg, formalType); } _invokeArgs.Add(invokeArg); }
//----------------------------------------------- // QilVisitor overrides //----------------------------------------------- protected override QilNode VisitChildren(QilNode parent) { if (this.parents.Contains(parent)) { // We have already visited the node that starts the infinite loop, but don't visit its children SetError(parent, "Infinite loop"); } else if (AddNode(parent)) { if (parent.XmlType == null) { SetError(parent, "Type information missing"); } else { XmlQueryType type = _typeCheck.Check(parent); // BUGBUG: Hack to account for Xslt compiler type fixups if (!type.IsSubtypeOf(parent.XmlType)) { SetError(parent, "Type information was not correctly inferred"); } } this.parents.Add(parent, parent); for (int i = 0; i < parent.Count; i++) { if (parent[i] == null) { // Allow parameter name and default value to be null if (parent.NodeType == QilNodeType.Parameter) { continue; } // Do not allow null anywhere else in the graph else { SetError(parent, "Child " + i + " must not be null"); } } if (parent.NodeType == QilNodeType.GlobalVariableList || parent.NodeType == QilNodeType.GlobalParameterList || parent.NodeType == QilNodeType.FunctionList) { if (((QilReference)parent[i]).DebugName == null) { SetError(parent[i], "DebugName must not be null"); } } // If child is a reference, then call VisitReference instead of Visit in order to avoid circular visits. if (IsReference(parent, i)) { VisitReference(parent[i]); } else { Visit(parent[i]); } } this.parents.Remove(parent); } return(parent); }
/// <summary> /// Adds itemType to a union. Returns false if new item is a subtype of one of the types in the list. /// </summary> private static void AddItemToChoice(List<XmlQueryType> accumulator, XmlQueryType itemType) { Debug.Assert(itemType.IsSingleton, "All types should be prime."); bool addToList = true; for (int i = 0; i < accumulator.Count; i++) { // If new prime is a subtype of existing prime, don't add it to the union if (itemType.IsSubtypeOf(accumulator[i])) { return; } // If new prime is a subtype of existing prime, then replace the existing prime with new prime if (accumulator[i].IsSubtypeOf(itemType)) { if (addToList) { addToList = false; accumulator[i] = itemType; } else { accumulator.RemoveAt(i); i --; } } } if (addToList) { accumulator.Add(itemType); } }
/// <summary> /// Construct the intersection of two lists of prime XmlQueryTypes. /// </summary> private XmlQueryType IntersectItemTypes(XmlQueryType left, XmlQueryType right) { Debug.Assert(left.Count == 1 && left.IsSingleton, "left should be an item"); Debug.Assert(right.Count == 1 && right.IsSingleton, "right should be an item"); if (left.TypeCode == right.TypeCode && (left.NodeKinds & (XmlNodeKindFlags.Document | XmlNodeKindFlags.Element | XmlNodeKindFlags.Attribute)) != 0) { if (left.TypeCode == XmlTypeCode.Node) { return left; } // Intersect name tests XmlQualifiedNameTest nameTest = left.NameTest.Intersect(right.NameTest); // Intersect types XmlSchemaType type = XmlSchemaType.IsDerivedFrom(left.SchemaType, right.SchemaType, /* except:*/XmlSchemaDerivationMethod.Empty) ? left.SchemaType : XmlSchemaType.IsDerivedFrom(right.SchemaType, left.SchemaType, /* except:*/XmlSchemaDerivationMethod.Empty) ? right.SchemaType : null; bool isNillable = left.IsNillable && right.IsNillable; if ((object)nameTest == (object)left.NameTest && type == left.SchemaType && isNillable == left.IsNillable) { // left is a subtype of right return left return left; } else if ((object)nameTest == (object)right.NameTest && type == right.SchemaType && isNillable == right.IsNillable) { // right is a subtype of left return right return right; } else if (nameTest != null && type != null) { // create a new type return ItemType.Create(left.TypeCode, nameTest, type, isNillable); } } else if (left.IsSubtypeOf(right)) { // left is a subset of right, so left is in the intersection return left; } else if (right.IsSubtypeOf(left)) { // right is a subset of left, so right is in the intersection return right; } return None; }