001: package net.sf.saxon.instruct;
002:
003: import net.sf.saxon.expr.TypeChecker;
004: import net.sf.saxon.expr.XPathContext;
005: import net.sf.saxon.om.ValueRepresentation;
006: import net.sf.saxon.trans.DynamicError;
007: import net.sf.saxon.trans.XPathException;
008: import net.sf.saxon.type.AtomicType;
009: import net.sf.saxon.type.ItemType;
010: import net.sf.saxon.value.AtomicValue;
011: import net.sf.saxon.value.EmptySequence;
012: import net.sf.saxon.value.ValidationErrorValue;
013: import net.sf.saxon.value.Value;
014: import net.sf.saxon.Configuration;
015:
016: /**
017: * The Bindery class holds information about variables and their values. From Saxon 8.1, it is
018: * used only for global variables: local variables are now held in the XPathContext object.
019: *
020: * Variables are identified by a Binding object. Values will always be of class Value.
021: */
022:
023: public final class Bindery {
024:
025: private ValueRepresentation[] globals; // values of global variables and parameters
026: private boolean[] busy; // set to true while variable is being evaluated
027: private GlobalParameterSet globalParameters; // supplied global parameters
028: private SlotManager globalVariableMap; // contains the mapping of variable names to slot numbers
029:
030: /**
031: * Define how many slots are needed for global variables
032: */
033:
034: public void allocateGlobals(SlotManager map) {
035: globalVariableMap = map;
036: int n = map.getNumberOfVariables() + 1;
037: globals = new ValueRepresentation[n];
038: busy = new boolean[n];
039: for (int i = 0; i < n; i++) {
040: globals[i] = null;
041: busy[i] = false;
042: }
043: }
044:
045: /**
046: * Define global parameters
047: * @param params The ParameterSet passed in by the user, eg. from the command line
048: */
049:
050: public void defineGlobalParameters(GlobalParameterSet params) {
051: globalParameters = params;
052: }
053:
054: /**
055: * Use global parameter. This is called when a global xsl:param element is processed.
056: * If a parameter of the relevant name was supplied, it is bound to the xsl:param element.
057: * Otherwise the method returns false, so the xsl:param default will be evaluated.
058: * @param fingerprint The fingerprint of the parameter
059: * @param binding The XSLParam element to bind its value to
060: * @return true if a parameter of this name was supplied, false if not
061: */
062:
063: public boolean useGlobalParameter(int fingerprint,
064: GlobalParam binding, XPathContext context)
065: throws XPathException {
066: int slot = binding.getSlotNumber();
067: if (globals[slot] != null) {
068: return true;
069: }
070:
071: if (globalParameters == null) {
072: return false;
073: }
074: Object obj = globalParameters.get(fingerprint);
075: if (obj == null) {
076: return false;
077: }
078:
079: Value val;
080: final Configuration config = context.getConfiguration();
081: try {
082: val = Value.convertJavaObjectToXPath(obj, binding
083: .getRequiredType(), config);
084: if (val == null) {
085: val = EmptySequence.getInstance();
086: }
087: } catch (XPathException err) {
088: err.setLocator(binding);
089: throw err;
090: }
091:
092: ItemType reqItemType = binding.getRequiredType()
093: .getPrimaryType();
094: if (val instanceof AtomicValue
095: && reqItemType instanceof AtomicType) {
096: // If the parameter is an atomic value, typically a string supplied on
097: // the command line, we attempt to convert it to the required type. This
098: // will not always succeed.
099: val = ((AtomicValue) val).convert((AtomicType) reqItemType,
100: context, true);
101: if (val instanceof ValidationErrorValue) {
102: throw ((ValidationErrorValue) val).getException();
103: }
104: } else {
105: // For any other parameter value, we verify that if conforms to the
106: // required type. This must be precise conformance, we don't attempt to
107: // do atomization or to convert untypedAtomic values
108: DynamicError err = TypeChecker.testConformance(val, binding
109: .getRequiredType(), config);
110: if (err != null) {
111: throw err;
112: }
113: }
114: globals[slot] = val;
115: return true;
116: }
117:
118: /**
119: * Provide a value for a global variable
120: * @param binding identifies the variable
121: * @param value the value of the variable
122: */
123:
124: public void defineGlobalVariable(GlobalVariable binding,
125: ValueRepresentation value) {
126: globals[binding.getSlotNumber()] = value;
127: }
128:
129: /**
130: * Set/Unset a flag to indicate that a particular global variable is currently being
131: * evaluated.
132: * @throws net.sf.saxon.trans.XPathException If an attempt is made to set the flag when it is already set, this means
133: * the definition of the variable is circular.
134: */
135:
136: public void setExecuting(GlobalVariable binding, boolean executing)
137: throws XPathException {
138: int slot = binding.getSlotNumber();
139: if (executing) {
140: if (busy[slot]) {
141: throw new XPathException.Circularity(
142: "Circular definition");
143: }
144: // It would be better to detect circular references statically
145: // at compile time. However, this is not always possible, because they
146: // can arise via execution of templates or stylesheet functions.
147: busy[slot] = true;
148: } else {
149: busy[slot] = false;
150: }
151: }
152:
153: /**
154: * Get the value of a global variable
155: * @param binding the Binding that establishes the unique instance of the variable
156: * @return the Value of the variable if defined, null otherwise.
157: */
158:
159: public ValueRepresentation getGlobalVariableValue(
160: GlobalVariable binding) {
161: return globals[binding.getSlotNumber()];
162: }
163:
164: /**
165: * Get the value of a global variable whose slot number is known
166: * @param slot the slot number of the required variable
167: * @return the Value of the variable if defined, null otherwise.
168: */
169:
170: public ValueRepresentation getGlobalVariable(int slot) {
171: return globals[slot];
172: }
173:
174: /**
175: * Assign a new value to a global variable. Supports saxon:assign.
176: * @param binding identifies the local or global variable or parameter
177: */
178:
179: public void assignGlobalVariable(GlobalVariable binding,
180: ValueRepresentation value) {
181: defineGlobalVariable(binding, value);
182: }
183:
184: /**
185: * Get the Global Variable Map, containing the mapping of variable names (fingerprints)
186: * to slot numbers. This is provided for use by debuggers.
187: */
188:
189: public SlotManager getGlobalVariableMap() {
190: return globalVariableMap;
191: }
192:
193: /**
194: * Get all the global variables, as an array. This is provided for use by debuggers
195: * that know the layout of the global variables within the array.
196: */
197:
198: public ValueRepresentation[] getGlobalVariables() {
199: return globals;
200: }
201:
202: }
203:
204: //
205: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
206: // you may not use this file except in compliance with the License. You may obtain a copy of the
207: // License at http://www.mozilla.org/MPL/
208: //
209: // Software distributed under the License is distributed on an "AS IS" basis,
210: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
211: // See the License for the specific language governing rights and limitations under the License.
212: //
213: // The Original Code is: all this file.
214: //
215: // The Initial Developer of the Original Code is Michael H. Kay.
216: //
217: //
218: //
|