137 lines
4.5 KiB
C#
137 lines
4.5 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="QilCloneVisitor.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
// <owner current="true" primary="true">[....]</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);
|
|
}
|
|
}
|
|
}
|