| File: System\Xml\Xsl\QIL\QilCloneVisitor.cs | Web Access |
| Project: src\runtime\src\libraries\System.Private.Xml\src\System.Private.Xml.csproj (System.Private.Xml) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Xml; using System.Xml.Xsl; namespace System.Xml.Xsl.Qil { // Create an exact replica of a QIL graph internal class QilCloneVisitor : QilScopedVisitor { private readonly QilFactory _fac; private readonly SubstitutionList _subs; //----------------------------------------------- // Constructors //----------------------------------------------- public QilCloneVisitor(QilFactory fac) : this(fac, new SubstitutionList()) { } public QilCloneVisitor(QilFactory fac, SubstitutionList subs) { _fac = fac; _subs = subs; } //----------------------------------------------- // Entry //----------------------------------------------- public QilNode Clone(QilNode node) { QilDepthChecker.Check(node); // Assume that iterator nodes at the top-level are references rather than definitions return VisitAssumeReference(node); } //----------------------------------------------- // QilVisitor overrides //----------------------------------------------- /// <summary> /// Visit all children of "parent", replacing each child with a copy of each child. /// </summary> protected override QilNode Visit(QilNode oldNode) { QilNode? newNode = null; if (oldNode == null) return null!; // ShallowClone any nodes which have not yet been cloned if (oldNode is QilReference) { // Reference nodes may have been cloned previously and put into scope newNode = FindClonedReference(oldNode); } newNode ??= oldNode.ShallowClone(_fac); return base.Visit(newNode); } /// <summary> /// Visit all children of "parent", replacing each child with a copy of each child. /// </summary> protected override QilNode VisitChildren(QilNode parent) { // Visit children for (int i = 0; i < parent.Count; i++) { QilNode child = parent[i]; // If child is a reference, if (IsReference(parent, i)) { // Visit the reference and substitute its copy parent[i] = VisitReference(child); // If no substutition found, then use original child parent[i] ??= child; } else { // Otherwise, visit the node and substitute its copy parent[i] = Visit(child)!; } } return parent; } /// <summary> /// If a cloned reference is in scope, replace "oldNode". Otherwise, return "oldNode". /// </summary> protected override QilNode VisitReference(QilNode oldNode) { QilNode? newNode = FindClonedReference(oldNode); return base.VisitReference(newNode ?? oldNode); } //----------------------------------------------- // QilScopedVisitor methods //----------------------------------------------- /// <summary> /// Push node and its shallow clone onto the substitution list. /// </summary> protected override void BeginScope(QilNode node) { _subs.AddSubstitutionPair(node, node.ShallowClone(_fac)); } /// <summary> /// Pop entry from substitution list. /// </summary> protected override void EndScope(QilNode node) { _subs.RemoveLastSubstitutionPair(); } //----------------------------------------------- // QilCloneVisitor methods //----------------------------------------------- /// <summary> /// Find the clone of an in-scope reference. /// </summary> protected QilNode? FindClonedReference(QilNode node) { return _subs.FindReplacement(node); } } }