package client.net.sf.saxon.ce.expr.instruct; import client.net.sf.saxon.ce.Controller; import client.net.sf.saxon.ce.expr.XPathContext; import client.net.sf.saxon.ce.expr.XPathContextMajor; import client.net.sf.saxon.ce.om.Item; import client.net.sf.saxon.ce.om.NodeInfo; import client.net.sf.saxon.ce.om.StandardNames; import client.net.sf.saxon.ce.trans.Mode; import client.net.sf.saxon.ce.trans.Rule; import client.net.sf.saxon.ce.trans.XPathException; import java.util.Arrays; /** * An xsl:next-match element in the stylesheet */ public class NextMatch extends ApplyImports { boolean useTailRecursion; public NextMatch(boolean useTailRecursion) { this.useTailRecursion = useTailRecursion; } /** * Get the name of this instruction for diagnostic and tracing purposes */ public int getInstructionNameCode() { return StandardNames.XSL_NEXT_MATCH; } public TailCall processLeavingTail(XPathContext context) throws XPathException { Controller controller = context.getController(); // handle parameters if any ParameterSet params = assembleParams(context, actualParams); ParameterSet tunnels = assembleTunnelParams(context, tunnelParams); Rule currentRule = context.getCurrentTemplateRule(); if (currentRule==null) { XPathException e = new XPathException("There is no current template rule"); e.setXPathContext(context); e.setErrorCode("XTDE0560"); throw e; } Mode mode = context.getCurrentMode(); if (mode == null) { mode = controller.getRuleManager().getUnnamedMode(); } if (context.getCurrentIterator()==null) { XPathException e = new XPathException("There is no context item"); e.setXPathContext(context); e.setErrorCode("XTDE0565"); throw e; } Item currentItem = context.getCurrentIterator().current(); if (!(currentItem instanceof NodeInfo)) { XPathException e = new XPathException("Cannot call xsl:next-match when context item is not a node"); e.setXPathContext(context); e.setErrorCode("XTDE0565"); throw e; } NodeInfo node = (NodeInfo)currentItem; Rule rule = controller.getRuleManager().getNextMatchHandler(node, mode, currentRule, context); if (rule==null) { // use the default action for the node mode.getBuiltInRuleSet().process(node, params, tunnels, context, getSourceLocator()); } else if (useTailRecursion) { //Template nh = (Template)rule.getAction(); // clear all the local variables: they are no longer needed Arrays.fill(context.getStackFrame().getStackFrameValues(), null); return new NextMatchPackage(rule, params, tunnels, context); } else { Template nh = rule.getAction(); XPathContextMajor c2 = context.newContext(); c2.openStackFrame(nh.getStackFrameMap()); c2.setLocalParameters(params); c2.setTunnelParameters(tunnels); c2.setCurrentTemplateRule(rule); nh.apply(c2); } return null; } /** * A NextMatchPackage is an object that encapsulates the name of a template to be called, * the parameters to be supplied, and the execution context. This object can be returned as a tail * call, so that the actual call is made from a lower point on the stack, allowing a tail-recursive * template to execute in a finite stack size */ private class NextMatchPackage implements TailCall { private Rule rule; private ParameterSet params; private ParameterSet tunnelParams; private XPathContext evaluationContext; /** * Construct a NextMatchPackage that contains information about a call. * @param rule the rule identifying the Template to be called * @param params the parameters to be supplied to the called template * @param tunnelParams the tunnel parameter supplied to the called template * @param evaluationContext saved context information from the Controller (current mode, etc) * which must be reset to ensure that the template is called with all the context information * intact */ public NextMatchPackage(Rule rule, ParameterSet params, ParameterSet tunnelParams, XPathContext evaluationContext) { this.rule = rule; this.params = params; this.tunnelParams = tunnelParams; this.evaluationContext = evaluationContext; } /** * Process the template call encapsulated by this package. * @return another TailCall. This will never be the original call, but it may be the next * recursive call. For example, if A calls B which calls C which calls D, then B may return * a TailCall to A representing the call from B to C; when this is processed, the result may be * a TailCall representing the call from C to D. * @throws XPathException if a dynamic error occurs */ public TailCall processLeavingTail() throws XPathException { Template nh = rule.getAction(); XPathContextMajor c2 = evaluationContext.newContext(); c2.setLocalParameters(params); c2.setTunnelParameters(tunnelParams); c2.openStackFrame(nh.getStackFrameMap()); c2.setCurrentTemplateRule(rule); // System.err.println("Tail call on template"); return nh.applyLeavingTail(c2); } } } // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.