|
//------------------------------------------------------------------------------
// <copyright file="QilCloneVisitor.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
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 QilFactory fac;
private SubstitutionList subs;
//-----------------------------------------------
// Constructors
//-----------------------------------------------
public QilCloneVisitor(QilFactory fac) : this(fac, new SubstitutionList()) {
}
public QilCloneVisitor(QilFactory fac, SubstitutionList subs) {
this.fac = fac;
this.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);
}
if (newNode == null)
newNode = oldNode.ShallowClone(this.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
if (parent[i] == null)
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 == null ? oldNode : newNode);
}
//-----------------------------------------------
// QilScopedVisitor methods
//-----------------------------------------------
/// <summary>
/// Push node and its shallow clone onto the substitution list.
/// </summary>
protected override void BeginScope(QilNode node) {
this.subs.AddSubstitutionPair(node, node.ShallowClone(this.fac));
}
/// <summary>
/// Pop entry from substitution list.
/// </summary>
protected override void EndScope(QilNode node) {
this.subs.RemoveLastSubstitutionPair();
}
//-----------------------------------------------
// QilCloneVisitor methods
//-----------------------------------------------
/// <summary>
/// Find the clone of an in-scope reference.
/// </summary>
protected QilNode FindClonedReference(QilNode node) {
return this.subs.FindReplacement(node);
}
}
}
|