|
//------------------------------------------------------------------------------
// <copyright file="Processor.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------
namespace System.Xml.Xsl.XsltOld {
using Res = System.Xml.Utils.Res;
using System.Globalization;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Xml.XPath;
using MS.Internal.Xml.XPath;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Xml.Xsl.XsltOld.Debugger;
using System.Reflection;
using System.Security;
internal sealed class Processor : IXsltProcessor {
//
// Static constants
//
const int StackIncrement = 10;
//
// Execution result
//
internal enum ExecResult {
Continue, // Continues next iteration immediately
Interrupt, // Returns to caller, was processed enough
Done // Execution finished
}
internal enum OutputResult {
Continue,
Interrupt,
Overflow,
Error,
Ignore
}
private ExecResult execResult;
//
// Compiled stylesheet
//
private Stylesheet stylesheet; // Root of import tree of template managers
private RootAction rootAction;
private Key[] keyList;
private List<TheQuery> queryStore;
public PermissionSet permissions; // used by XsltCompiledContext in document and extension functions
//
// Document Being transformed
//
private XPathNavigator document;
//
// Execution action stack
//
private HWStack actionStack;
private HWStack debuggerStack;
//
// Register for returning value from calling nested action
//
private StringBuilder sharedStringBuilder;
//
// Output related member variables
//
int ignoreLevel;
StateMachine xsm;
RecordBuilder builder;
XsltOutput output;
XmlNameTable nameTable = new NameTable();
XmlResolver resolver;
#pragma warning disable 618
XsltArgumentList args;
#pragma warning restore 618
Hashtable scriptExtensions;
ArrayList numberList;
//
// Template lookup action
//
TemplateLookupAction templateLookup = new TemplateLookupAction();
private IXsltDebugger debugger;
Query[] queryList;
private ArrayList sortArray;
private Hashtable documentCache;
// NOTE: ValueOf() can call Matches() through XsltCompileContext.PreserveWhitespace(),
// that's why we use two different contexts here, valueOfContext and matchesContext
private XsltCompileContext valueOfContext;
private XsltCompileContext matchesContext;
internal XPathNavigator Current {
get {
ActionFrame frame = (ActionFrame) this.actionStack.Peek();
return frame != null ? frame.Node : null;
}
}
internal ExecResult ExecutionResult {
get { return this.execResult; }
set {
Debug.Assert(this.execResult == ExecResult.Continue);
this.execResult = value;
}
}
internal Stylesheet Stylesheet {
get { return this.stylesheet; }
}
internal XmlResolver Resolver {
get {
Debug.Assert(this.resolver != null, "Constructor should create it if null passed");
return this.resolver;
}
}
internal ArrayList SortArray {
get {
Debug.Assert(this.sortArray != null, "InitSortArray() wasn't called");
return this.sortArray;
}
}
internal Key[] KeyList {
get { return this.keyList; }
}
[SuppressMessage("Microsoft.Security.Xml", "CA3068:TextReaderImplNeedsSettingsAndResolver", Justification="XmlResolver and DtdProcessing is set on XmlTextReaderImpl after it is constructed or default to null resolver / prohibit DTD")]
internal XPathNavigator GetNavigator(Uri ruri) {
XPathNavigator result = null;
if (documentCache != null) {
result = documentCache[ruri] as XPathNavigator;
if (result != null) {
return result.Clone();
}
}
else {
documentCache = new Hashtable();
}
Object input = resolver.GetEntity(ruri, null, null);
if (input is Stream) {
XmlTextReaderImpl tr = new XmlTextReaderImpl(ruri.ToString(), (Stream) input); {
tr.XmlResolver = this.resolver;
}
// reader is closed by Compiler.LoadDocument()
result = ((IXPathNavigable)Compiler.LoadDocument(tr)).CreateNavigator();
}
else if (input is XPathNavigator){
result = (XPathNavigator) input;
}
else {
throw XsltException.Create(Res.Xslt_CantResolve, ruri.ToString());
}
documentCache[ruri] = result.Clone();
return result;
}
internal void AddSort(Sort sortinfo) {
Debug.Assert(this.sortArray != null, "InitSortArray() wasn't called");
this.sortArray.Add(sortinfo);
}
internal void InitSortArray() {
if (this.sortArray == null) {
this.sortArray = new ArrayList();
}
else {
this.sortArray.Clear();
}
}
internal object GetGlobalParameter(XmlQualifiedName qname) {
object parameter = args.GetParam(qname.Name, qname.Namespace);
if (parameter == null) {
return null;
}
//
if (
parameter is XPathNodeIterator ||
parameter is XPathNavigator ||
parameter is Boolean ||
parameter is Double ||
parameter is String
) {
// doing nothing
} else if (
parameter is Int16 || parameter is UInt16 ||
parameter is Int32 || parameter is UInt32 ||
parameter is Int64 || parameter is UInt64 ||
parameter is Single || parameter is Decimal
) {
parameter = XmlConvert.ToXPathDouble(parameter);
} else {
parameter = parameter.ToString();
}
return parameter;
}
internal object GetExtensionObject(string nsUri) {
return args.GetExtensionObject(nsUri);
}
internal object GetScriptObject(string nsUri) {
return scriptExtensions[nsUri];
}
internal RootAction RootAction {
get { return this.rootAction; }
}
internal XPathNavigator Document {
get { return this.document; }
}
#if DEBUG
private bool stringBuilderLocked = false;
#endif
internal StringBuilder GetSharedStringBuilder() {
#if DEBUG
Debug.Assert(! stringBuilderLocked);
#endif
if (sharedStringBuilder == null) {
sharedStringBuilder = new StringBuilder();
}
else {
sharedStringBuilder.Length = 0;
}
#if DEBUG
stringBuilderLocked = true;
#endif
return sharedStringBuilder;
}
internal void ReleaseSharedStringBuilder() {
// don't clean stringBuilderLocked here. ToString() will happen after this call
#if DEBUG
stringBuilderLocked = false;
#endif
}
internal ArrayList NumberList {
get {
if (this.numberList == null) {
this.numberList = new ArrayList();
}
return this.numberList;
}
}
internal IXsltDebugger Debugger {
get { return this.debugger; }
}
internal HWStack ActionStack {
get { return this.actionStack; }
}
internal RecordBuilder Builder {
get { return this.builder; }
}
internal XsltOutput Output {
get { return this.output; }
}
//
// Construction
//
public Processor(
XPathNavigator doc, XsltArgumentList args, XmlResolver resolver,
Stylesheet stylesheet, List<TheQuery> queryStore, RootAction rootAction,
IXsltDebugger debugger
) {
this.stylesheet = stylesheet;
this.queryStore = queryStore;
this.rootAction = rootAction;
this.queryList = new Query[queryStore.Count]; {
for(int i = 0; i < queryStore.Count; i ++) {
queryList[i] = Query.Clone(queryStore[i].CompiledQuery.QueryTree);
}
}
this.xsm = new StateMachine();
this.document = doc;
this.builder = null;
this.actionStack = new HWStack(StackIncrement);
this.output = this.rootAction.Output;
this.permissions = this.rootAction.permissions;
this.resolver = resolver ?? XmlNullResolver.Singleton;
this.args = args ?? new XsltArgumentList();
this.debugger = debugger;
if (this.debugger != null) {
this.debuggerStack = new HWStack(StackIncrement, /*limit:*/1000);
templateLookup = new TemplateLookupActionDbg();
}
// Clone the compile-time KeyList
if (this.rootAction.KeyList != null) {
this.keyList = new Key[this.rootAction.KeyList.Count];
for (int i = 0; i < this.keyList.Length; i ++) {
this.keyList[i] = this.rootAction.KeyList[i].Clone();
}
}
this.scriptExtensions = new Hashtable(this.stylesheet.ScriptObjectTypes.Count); {
foreach(DictionaryEntry entry in this.stylesheet.ScriptObjectTypes) {
string namespaceUri = (string)entry.Key;
if (GetExtensionObject(namespaceUri) != null) {
throw XsltException.Create(Res.Xslt_ScriptDub, namespaceUri);
}
scriptExtensions.Add(namespaceUri, Activator.CreateInstance((Type)entry.Value,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, null, null));
}
}
this.PushActionFrame(this.rootAction, /*nodeSet:*/null);
}
public ReaderOutput StartReader() {
ReaderOutput output = new ReaderOutput(this);
this.builder = new RecordBuilder(output, this.nameTable);
return output;
}
public void Execute(Stream stream) {
RecordOutput recOutput = null;
switch (this.output.Method) {
case XsltOutput.OutputMethod.Text:
recOutput = new TextOnlyOutput(this, stream);
break;
case XsltOutput.OutputMethod.Xml:
case XsltOutput.OutputMethod.Html:
case XsltOutput.OutputMethod.Other:
case XsltOutput.OutputMethod.Unknown:
recOutput = new TextOutput(this, stream);
break;
}
this.builder = new RecordBuilder(recOutput, this.nameTable);
Execute();
}
public void Execute(TextWriter writer) {
RecordOutput recOutput = null;
switch (this.output.Method) {
case XsltOutput.OutputMethod.Text:
recOutput = new TextOnlyOutput(this, writer);
break;
case XsltOutput.OutputMethod.Xml:
case XsltOutput.OutputMethod.Html:
case XsltOutput.OutputMethod.Other:
case XsltOutput.OutputMethod.Unknown:
recOutput = new TextOutput(this, writer);
break;
}
this.builder = new RecordBuilder(recOutput, this.nameTable);
Execute();
}
public void Execute(XmlWriter writer) {
this.builder = new RecordBuilder(new WriterOutput(this, writer), this.nameTable);
Execute();
}
//
// Execution part of processor
//
internal void Execute() {
Debug.Assert(this.actionStack != null);
while (this.execResult == ExecResult.Continue) {
ActionFrame frame = (ActionFrame) this.actionStack.Peek();
if (frame == null) {
Debug.Assert(this.builder != null);
this.builder.TheEnd();
ExecutionResult = ExecResult.Done;
break;
}
// Execute the action which was on the top of the stack
if (frame.Execute(this)) {
this.actionStack.Pop();
}
}
if (this.execResult == ExecResult.Interrupt) {
this.execResult = ExecResult.Continue;
}
}
//
// Action frame support
//
internal ActionFrame PushNewFrame() {
ActionFrame prent = (ActionFrame) this.actionStack.Peek();
ActionFrame frame = (ActionFrame) this.actionStack.Push();
if (frame == null) {
frame = new ActionFrame();
this.actionStack.AddToTop(frame);
}
Debug.Assert(frame != null);
if (prent != null) {
frame.Inherit(prent);
}
return frame;
}
internal void PushActionFrame(Action action, XPathNodeIterator nodeSet) {
ActionFrame frame = PushNewFrame();
frame.Init(action, nodeSet);
}
internal void PushActionFrame(ActionFrame container) {
this.PushActionFrame(container, container.NodeSet);
}
internal void PushActionFrame(ActionFrame container, XPathNodeIterator nodeSet) {
ActionFrame frame = PushNewFrame();
frame.Init(container, nodeSet);
}
internal void PushTemplateLookup(XPathNodeIterator nodeSet, XmlQualifiedName mode, Stylesheet importsOf) {
Debug.Assert(this.templateLookup != null);
this.templateLookup.Initialize(mode, importsOf);
PushActionFrame(this.templateLookup, nodeSet);
}
internal string GetQueryExpression(int key) {
Debug.Assert(key != Compiler.InvalidQueryKey);
return this.queryStore[key].CompiledQuery.Expression;
}
internal Query GetCompiledQuery(int key) {
Debug.Assert(key != Compiler.InvalidQueryKey);
TheQuery theQuery = this.queryStore[key];
theQuery.CompiledQuery.CheckErrors();
Query expr = Query.Clone(this.queryList[key]);
expr.SetXsltContext(new XsltCompileContext(theQuery._ScopeManager, this));
return expr;
}
internal Query GetValueQuery(int key) {
return GetValueQuery(key, null);
}
internal Query GetValueQuery(int key, XsltCompileContext context) {
Debug.Assert(key != Compiler.InvalidQueryKey);
TheQuery theQuery = this.queryStore[key];
theQuery.CompiledQuery.CheckErrors();
Query expr = this.queryList[key];
if (context == null) {
context = new XsltCompileContext(theQuery._ScopeManager, this);
} else {
context.Reinitialize(theQuery._ScopeManager, this);
}
expr.SetXsltContext(context);
return expr;
}
private XsltCompileContext GetValueOfContext() {
if (this.valueOfContext == null) {
this.valueOfContext = new XsltCompileContext();
}
return this.valueOfContext;
}
[Conditional("DEBUG")]
private void RecycleValueOfContext() {
if (this.valueOfContext != null) {
this.valueOfContext.Recycle();
}
}
private XsltCompileContext GetMatchesContext() {
if (this.matchesContext == null) {
this.matchesContext = new XsltCompileContext();
}
return this.matchesContext;
}
[Conditional("DEBUG")]
private void RecycleMatchesContext() {
if (this.matchesContext != null) {
this.matchesContext.Recycle();
}
}
internal String ValueOf(ActionFrame context, int key) {
string result;
Query query = this.GetValueQuery(key, GetValueOfContext());
object value = query.Evaluate(context.NodeSet);
if (value is XPathNodeIterator) {
XPathNavigator n = query.Advance();
result = n != null ? ValueOf(n) : string.Empty;
} else {
result = XmlConvert.ToXPathString(value);
}
RecycleValueOfContext();
return result;
}
internal String ValueOf(XPathNavigator n) {
if (this.stylesheet.Whitespace && n.NodeType == XPathNodeType.Element) {
StringBuilder builder = this.GetSharedStringBuilder();
ElementValueWithoutWS(n, builder);
this.ReleaseSharedStringBuilder();
return builder.ToString();
}
return n.Value;
}
private void ElementValueWithoutWS(XPathNavigator nav, StringBuilder builder) {
Debug.Assert(nav.NodeType == XPathNodeType.Element);
bool preserve = this.Stylesheet.PreserveWhiteSpace(this, nav);
if (nav.MoveToFirstChild()) {
do {
switch (nav.NodeType) {
case XPathNodeType.Text :
case XPathNodeType.SignificantWhitespace :
builder.Append(nav.Value);
break;
case XPathNodeType.Whitespace :
if (preserve) {
builder.Append(nav.Value);
}
break;
case XPathNodeType.Element :
ElementValueWithoutWS(nav, builder);
break;
}
}while (nav.MoveToNext());
nav.MoveToParent();
}
}
internal XPathNodeIterator StartQuery(XPathNodeIterator context, int key) {
Query query = GetCompiledQuery(key);
object result = query.Evaluate(context);
if (result is XPathNodeIterator) {
// ToDo: We create XPathSelectionIterator to count positions, but it's better create special query in this case at compile time.
return new XPathSelectionIterator(context.Current, query);
}
throw XsltException.Create(Res.XPath_NodeSetExpected);
}
internal object Evaluate(ActionFrame context, int key) {
return GetValueQuery(key).Evaluate(context.NodeSet);
}
internal object RunQuery(ActionFrame context, int key) {
Query query = GetCompiledQuery(key);
object value = query.Evaluate(context.NodeSet);
XPathNodeIterator it = value as XPathNodeIterator;
if (it != null) {
return new XPathArrayIterator(it);
}
return value;
}
internal string EvaluateString(ActionFrame context, int key) {
object objValue = Evaluate(context, key);
string value = null;
if (objValue != null)
value = XmlConvert.ToXPathString(objValue);
if (value == null)
value = string.Empty;
return value;
}
internal bool EvaluateBoolean(ActionFrame context, int key) {
object objValue = Evaluate(context, key);
if (objValue != null) {
XPathNavigator nav = objValue as XPathNavigator;
return nav != null ? Convert.ToBoolean(nav.Value, CultureInfo.InvariantCulture) : Convert.ToBoolean(objValue, CultureInfo.InvariantCulture);
}
else {
return false;
}
}
internal bool Matches(XPathNavigator context, int key) {
// We don't use XPathNavigator.Matches() to avoid cloning of Query on each call
Query query = this.GetValueQuery(key, GetMatchesContext());
try {
bool result = query.MatchNode(context) != null;
RecycleMatchesContext();
return result;
} catch(XPathException) {
throw XsltException.Create(Res.Xslt_InvalidPattern, this.GetQueryExpression(key));
}
}
//
// Outputting part of processor
//
internal XmlNameTable NameTable {
get { return this.nameTable; }
}
internal bool CanContinue {
get { return this.execResult == ExecResult.Continue; }
}
internal bool ExecutionDone {
get { return this.execResult == ExecResult.Done; }
}
internal void ResetOutput() {
Debug.Assert(this.builder != null);
this.builder.Reset();
}
internal bool BeginEvent(XPathNodeType nodeType, string prefix, string name, string nspace, bool empty) {
return BeginEvent(nodeType, prefix, name, nspace, empty, null, true);
}
internal bool BeginEvent(XPathNodeType nodeType, string prefix, string name, string nspace, bool empty, Object htmlProps, bool search) {
Debug.Assert(this.xsm != null);
int stateOutlook = this.xsm.BeginOutlook(nodeType);
if (this.ignoreLevel > 0 || stateOutlook == StateMachine.Error) {
this.ignoreLevel ++;
return true; // We consumed the event, so pretend it was output.
}
switch (this.builder.BeginEvent(stateOutlook, nodeType, prefix, name, nspace, empty, htmlProps, search)) {
case OutputResult.Continue:
this.xsm.Begin(nodeType);
Debug.Assert(StateMachine.StateOnly(stateOutlook) == this.xsm.State);
Debug.Assert(ExecutionResult == ExecResult.Continue);
return true;
case OutputResult.Interrupt:
this.xsm.Begin(nodeType);
Debug.Assert(StateMachine.StateOnly(stateOutlook) == this.xsm.State);
ExecutionResult = ExecResult.Interrupt;
return true;
case OutputResult.Overflow:
ExecutionResult = ExecResult.Interrupt;
return false;
case OutputResult.Error:
this.ignoreLevel ++;
return true;
case OutputResult.Ignore:
return true;
default:
Debug.Fail("Unexpected result of RecordBuilder.BeginEvent()");
return true;
}
}
internal bool TextEvent(string text) {
return this.TextEvent(text, false);
}
internal bool TextEvent(string text, bool disableOutputEscaping) {
Debug.Assert(this.xsm != null);
if (this.ignoreLevel > 0) {
return true;
}
int stateOutlook = this.xsm.BeginOutlook(XPathNodeType.Text);
switch (this.builder.TextEvent(stateOutlook, text, disableOutputEscaping)) {
case OutputResult.Continue:
this.xsm.Begin(XPathNodeType.Text);
Debug.Assert(StateMachine.StateOnly(stateOutlook) == this.xsm.State);
Debug.Assert(ExecutionResult == ExecResult.Continue);
return true;
case OutputResult.Interrupt:
this.xsm.Begin(XPathNodeType.Text);
Debug.Assert(StateMachine.StateOnly(stateOutlook) == this.xsm.State);
ExecutionResult = ExecResult.Interrupt;
return true;
case OutputResult.Overflow:
ExecutionResult = ExecResult.Interrupt;
return false;
case OutputResult.Error:
case OutputResult.Ignore:
return true;
default:
Debug.Fail("Unexpected result of RecordBuilder.TextEvent()");
return true;
}
}
internal bool EndEvent(XPathNodeType nodeType) {
Debug.Assert(this.xsm != null);
if (this.ignoreLevel > 0) {
this.ignoreLevel --;
return true;
}
int stateOutlook = this.xsm.EndOutlook(nodeType);
switch (this.builder.EndEvent(stateOutlook, nodeType)) {
case OutputResult.Continue:
this.xsm.End(nodeType);
Debug.Assert(StateMachine.StateOnly(stateOutlook) == this.xsm.State);
return true;
case OutputResult.Interrupt:
this.xsm.End(nodeType);
Debug.Assert(StateMachine.StateOnly(stateOutlook) == this.xsm.State,
"StateMachine.StateOnly(stateOutlook) == this.xsm.State");
ExecutionResult = ExecResult.Interrupt;
return true;
case OutputResult.Overflow:
ExecutionResult = ExecResult.Interrupt;
return false;
case OutputResult.Error:
case OutputResult.Ignore:
default:
Debug.Fail("Unexpected result of RecordBuilder.TextEvent()");
return true;
}
}
internal bool CopyBeginEvent(XPathNavigator node, bool emptyflag) {
switch (node.NodeType) {
case XPathNodeType.Element:
case XPathNodeType.Attribute:
case XPathNodeType.ProcessingInstruction:
case XPathNodeType.Comment:
return BeginEvent(node.NodeType, node.Prefix, node.LocalName, node.NamespaceURI, emptyflag);
case XPathNodeType.Namespace:
// value instead of namespace here!
return BeginEvent(XPathNodeType.Namespace, null, node.LocalName, node.Value, false);
case XPathNodeType.Text:
// Text will be copied in CopyContents();
break;
case XPathNodeType.Root:
case XPathNodeType.Whitespace:
case XPathNodeType.SignificantWhitespace:
case XPathNodeType.All:
break;
default:
Debug.Fail("Invalid XPathNodeType in CopyBeginEvent");
break;
}
return true;
}
internal bool CopyTextEvent(XPathNavigator node) {
switch (node.NodeType) {
case XPathNodeType.Element:
case XPathNodeType.Namespace:
break;
case XPathNodeType.Attribute:
case XPathNodeType.ProcessingInstruction:
case XPathNodeType.Comment:
case XPathNodeType.Text:
case XPathNodeType.Whitespace:
case XPathNodeType.SignificantWhitespace:
string text = node.Value;
return TextEvent(text);
case XPathNodeType.Root:
case XPathNodeType.All:
break;
default:
Debug.Fail("Invalid XPathNodeType in CopyTextEvent");
break;
}
return true;
}
internal bool CopyEndEvent(XPathNavigator node) {
switch (node.NodeType) {
case XPathNodeType.Element:
case XPathNodeType.Attribute:
case XPathNodeType.ProcessingInstruction:
case XPathNodeType.Comment:
case XPathNodeType.Namespace:
return EndEvent(node.NodeType);
case XPathNodeType.Text:
// Text was copied in CopyContents();
break;
case XPathNodeType.Root:
case XPathNodeType.Whitespace:
case XPathNodeType.SignificantWhitespace:
case XPathNodeType.All:
break;
default:
Debug.Fail("Invalid XPathNodeType in CopyEndEvent");
break;
}
return true;
}
internal static bool IsRoot(XPathNavigator navigator) {
Debug.Assert(navigator != null);
if (navigator.NodeType == XPathNodeType.Root) {
return true;
}
else if (navigator.NodeType == XPathNodeType.Element) {
XPathNavigator clone = navigator.Clone();
clone.MoveToRoot();
return clone.IsSamePosition(navigator);
}
else {
return false;
}
}
//
// Builder stack
//
internal void PushOutput(RecordOutput output) {
Debug.Assert(output != null);
this.builder.OutputState = this.xsm.State;
RecordBuilder lastBuilder = this.builder;
this.builder = new RecordBuilder(output, this.nameTable);
this.builder.Next = lastBuilder;
this.xsm.Reset();
}
internal RecordOutput PopOutput() {
Debug.Assert(this.builder != null);
RecordBuilder topBuilder = this.builder;
this.builder = topBuilder.Next;
this.xsm.State = this.builder.OutputState;
topBuilder.TheEnd();
return topBuilder.Output;
}
internal bool SetDefaultOutput(XsltOutput.OutputMethod method) {
if(Output.Method != method) {
this.output = this.output.CreateDerivedOutput(method);
return true;
}
return false;
}
internal object GetVariableValue(VariableAction variable) {
int variablekey = variable.VarKey;
if (variable.IsGlobal) {
ActionFrame rootFrame = (ActionFrame) this.actionStack[0];
object result = rootFrame.GetVariable(variablekey);
if (result == VariableAction.BeingComputedMark) {
throw XsltException.Create(Res.Xslt_CircularReference, variable.NameStr);
}
if (result != null) {
return result;
}
// Variable wasn't evaluated yet
int saveStackSize = this.actionStack.Length;
ActionFrame varFrame = PushNewFrame();
varFrame.Inherit(rootFrame);
varFrame.Init(variable, rootFrame.NodeSet);
do {
bool endOfFrame = ((ActionFrame) this.actionStack.Peek()).Execute(this);
if (endOfFrame) {
this.actionStack.Pop();
}
} while (saveStackSize < this.actionStack.Length);
Debug.Assert(saveStackSize == this.actionStack.Length);
result = rootFrame.GetVariable(variablekey);
Debug.Assert(result != null, "Variable was just calculated and result can't be null");
return result;
} else {
return ((ActionFrame) this.actionStack.Peek()).GetVariable(variablekey);
}
}
internal void SetParameter(XmlQualifiedName name, object value) {
Debug.Assert(1 < actionStack.Length);
ActionFrame parentFrame = (ActionFrame) this.actionStack[actionStack.Length - 2];
parentFrame.SetParameter(name, value);
}
internal void ResetParams() {
ActionFrame frame = (ActionFrame) this.actionStack[actionStack.Length - 1];
frame.ResetParams();
}
internal object GetParameter(XmlQualifiedName name) {
Debug.Assert(2 < actionStack.Length);
ActionFrame parentFrame = (ActionFrame) this.actionStack[actionStack.Length - 3];
return parentFrame.GetParameter(name);
}
// ---------------------- Debugger stack -----------------------
internal class DebuggerFrame {
internal ActionFrame actionFrame;
internal XmlQualifiedName currentMode;
}
internal void PushDebuggerStack() {
Debug.Assert(this.Debugger != null, "We don't generate calls this function if ! debugger");
DebuggerFrame dbgFrame = (DebuggerFrame) this.debuggerStack.Push();
if (dbgFrame == null) {
dbgFrame = new DebuggerFrame();
this.debuggerStack.AddToTop(dbgFrame);
}
dbgFrame.actionFrame = (ActionFrame) this.actionStack.Peek(); // In a case of next builtIn action.
}
internal void PopDebuggerStack() {
Debug.Assert(this.Debugger != null, "We don't generate calls this function if ! debugger");
this.debuggerStack.Pop();
}
internal void OnInstructionExecute() {
Debug.Assert(this.Debugger != null, "We don't generate calls this function if ! debugger");
DebuggerFrame dbgFrame = (DebuggerFrame) this.debuggerStack.Peek();
Debug.Assert(dbgFrame != null, "PushDebuggerStack() wasn't ever called");
dbgFrame.actionFrame = (ActionFrame) this.actionStack.Peek();
this.Debugger.OnInstructionExecute((IXsltProcessor) this);
}
internal XmlQualifiedName GetPrevioseMode() {
Debug.Assert(this.Debugger != null, "We don't generate calls this function if ! debugger");
Debug.Assert(2 <= this.debuggerStack.Length);
return ((DebuggerFrame) this.debuggerStack[this.debuggerStack.Length - 2]).currentMode;
}
internal void SetCurrentMode(XmlQualifiedName mode) {
Debug.Assert(this.Debugger != null, "We don't generate calls this function if ! debugger");
((DebuggerFrame) this.debuggerStack[this.debuggerStack.Length - 1]).currentMode = mode;
}
// ----------------------- IXsltProcessor : --------------------
int IXsltProcessor.StackDepth {
get {return this.debuggerStack.Length;}
}
IStackFrame IXsltProcessor.GetStackFrame(int depth) {
return ((DebuggerFrame) this.debuggerStack[depth]).actionFrame;
}
}
}
|