001: package net.sf.saxon.query;
002:
003: import net.sf.saxon.event.LocationProvider;
004: import net.sf.saxon.expr.*;
005: import net.sf.saxon.functions.ExecutableFunctionLibrary;
006: import net.sf.saxon.instruct.*;
007: import net.sf.saxon.om.NamePool;
008: import net.sf.saxon.om.NamespaceResolver;
009: import net.sf.saxon.style.StandardNames;
010: import net.sf.saxon.trace.InstructionInfo;
011: import net.sf.saxon.trace.Location;
012: import net.sf.saxon.trans.StaticError;
013: import net.sf.saxon.trans.XPathException;
014: import net.sf.saxon.value.SequenceType;
015:
016: import java.util.ArrayList;
017: import java.util.Iterator;
018: import java.util.List;
019:
020: public class XQueryFunction implements InstructionInfo, Container,
021: Declaration {
022: private int nameCode;
023: List arguments; // A list of RangeVariableDeclaration objects
024: SequenceType resultType;
025: Expression body = null;
026: List references = new ArrayList(10);
027: int lineNumber;
028: int columnNumber;
029: String systemId;
030: private Executable executable;
031: private UserFunction compiledFunction = null;
032: NamespaceResolver namespaceResolver;
033: private StaticContext staticContext;
034:
035: public XQueryFunction() {
036: }
037:
038: public void setNameCode(int nameCode) {
039: this .nameCode = nameCode;
040: }
041:
042: public int getNameCode() {
043: return nameCode;
044: }
045:
046: public String getFunctionDisplayName(NamePool pool) {
047: return pool.getDisplayName(nameCode);
048: }
049:
050: public int getFunctionFingerprint() {
051: return nameCode & 0xfffff;
052: }
053:
054: public SequenceType getResultType() {
055: return resultType;
056: }
057:
058: public void setExecutable(Executable exec) {
059: executable = exec;
060: }
061:
062: public Executable getExecutable() {
063: return executable;
064: }
065:
066: /**
067: * Get the LocationProvider allowing location identifiers to be resolved.
068: */
069:
070: public LocationProvider getLocationProvider() {
071: return executable.getLocationMap();
072: }
073:
074: public StaticContext getStaticContext() {
075: return staticContext;
076: }
077:
078: public SequenceType[] getArgumentTypes() {
079: SequenceType[] types = new SequenceType[arguments.size()];
080: for (int i = 0; i < arguments.size(); i++) {
081: types[i] = ((RangeVariableDeclaration) arguments.get(i))
082: .getRequiredType();
083: }
084: return types;
085: }
086:
087: public UserFunctionParameter[] getParameterDefinitions() {
088: UserFunctionParameter[] params = new UserFunctionParameter[arguments
089: .size()];
090: for (int i = 0; i < arguments.size(); i++) {
091: SequenceType type = ((RangeVariableDeclaration) arguments
092: .get(i)).getRequiredType();
093: UserFunctionParameter param = new UserFunctionParameter();
094: param.setRequiredType(type);
095: params[i] = param;
096: }
097: return params;
098: }
099:
100: public int getNumberOfArguments() {
101: return arguments.size();
102: }
103:
104: public void registerReference(UserFunctionCall ufc) {
105: references.add(ufc);
106: }
107:
108: public UserFunction compile(StaticQueryContext env)
109: throws StaticError {
110: staticContext = env;
111: try {
112: // If a query function is imported into several modules, then the compile()
113: // method will be called once for each importing module. If the compiled
114: // function already exists, then this is a repeat call, and the only thing
115: // needed is to fix up references to the function from within the importing
116: // module.
117:
118: if (compiledFunction == null) {
119: // first get the UserFunctionParameter object for each declared
120: // argument of the function, and bind the references to that argument
121: SlotManager map = env.getConfiguration()
122: .makeSlotManager();
123: UserFunctionParameter[] params = getParameterDefinitions();
124: Iterator iter = arguments.iterator();
125: int slot = 0;
126: while (iter.hasNext()) {
127: RangeVariableDeclaration decl = (RangeVariableDeclaration) iter
128: .next();
129: UserFunctionParameter param = params[slot];
130: param.setSlotNumber(slot++);
131: param.setRequiredType(decl.getRequiredType());
132: map
133: .allocateSlotNumber(decl.getNameCode() & 0xfffff);
134: decl.fixupReferences(param);
135: }
136:
137: // type-check the body of the function
138:
139: body = body.simplify(env).typeCheck(env, null);
140: body = body.optimize(env.getConfiguration()
141: .getOptimizer(), env, null);
142: if (body instanceof ComputedExpression) {
143: ((ComputedExpression) body)
144: .setParentExpression(this );
145: }
146: RoleLocator role = new RoleLocator(
147: RoleLocator.FUNCTION_RESULT, new Integer(
148: nameCode), 0, env.getNamePool());
149: role.setSourceLocator(this );
150: body = TypeChecker.staticTypeCheck(body, resultType,
151: false, role, env);
152: if (body instanceof ComputedExpression) {
153: ((ComputedExpression) body)
154: .setParentExpression(this );
155: }
156: ExpressionTool.allocateSlots(body, slot, map);
157:
158: if (env.getConfiguration().getTraceListener() != null) {
159: namespaceResolver = env.getNamespaceResolver();
160: TraceExpression trace = new TraceExpression(body);
161: trace.setLineNumber(lineNumber);
162: trace.setColumnNumber(columnNumber);
163: trace.setSystemId(env.getBaseURI());
164: trace.setConstructType(StandardNames.XSL_FUNCTION);
165: trace.setObjectNameCode(nameCode);
166: trace.setLocationId(env.getLocationMap()
167: .allocateLocationId(systemId, lineNumber));
168: body = trace;
169: }
170:
171: compiledFunction = new UserFunction(body);
172: compiledFunction.setFunctionNameCode(nameCode);
173: compiledFunction.setParameterDefinitions(params);
174: //compiledFunction.setArgumentTypes(getArgumentTypes());
175: compiledFunction.setResultType(getResultType());
176: compiledFunction.setLineNumber(lineNumber);
177: compiledFunction.setSystemId(systemId);
178: compiledFunction.setExecutable(executable);
179: compiledFunction.setStackFrameMap(map);
180:
181: // mark tail calls within the function body
182:
183: boolean tailCalls = ExpressionTool
184: .markTailFunctionCalls(body);
185: compiledFunction.setTailRecursive(tailCalls);
186:
187: for (int i = 0; i < params.length; i++) {
188: RangeVariableDeclaration decl = (RangeVariableDeclaration) arguments
189: .get(i);
190: UserFunctionParameter param = params[i];
191: int refs = decl.getReferenceCount(param, env);
192: param.setReferenceCount(refs);
193: }
194:
195: }
196:
197: // bind all references to this function to the UserFunction object
198:
199: fixupReferences(env);
200:
201: // register this function with the function library available at run-time (e.g. for saxon:evaluate())
202:
203: if (executable.getFunctionLibrary() instanceof ExecutableFunctionLibrary) {
204: ExecutableFunctionLibrary lib = (ExecutableFunctionLibrary) executable
205: .getFunctionLibrary();
206: lib.addFunction(compiledFunction);
207: } else {
208: throw new AssertionError(
209: "executable.getFunctionLibrary() is an instance of "
210: + executable.getFunctionLibrary()
211: .getClass().getName());
212: }
213:
214: return compiledFunction;
215: } catch (XPathException e) {
216: if (e.getLocator() == null) {
217: e.setLocator(this );
218: }
219: if (e instanceof StaticError) {
220: throw (StaticError) e;
221: } else {
222: throw new StaticError(e);
223: }
224: }
225: }
226:
227: /**
228: * Fix up references to this function
229: */
230:
231: public void fixupReferences(StaticContext env)
232: throws XPathException {
233: Iterator iter = references.iterator();
234: while (iter.hasNext()) {
235: UserFunctionCall ufc = (UserFunctionCall) iter.next();
236: ufc.setFunction(compiledFunction, env);
237: }
238: }
239:
240: /**
241: * Type-check references to this function
242: */
243:
244: public void checkReferences(StaticContext env)
245: throws XPathException {
246: Iterator iter = references.iterator();
247: while (iter.hasNext()) {
248: UserFunctionCall ufc = (UserFunctionCall) iter.next();
249: ufc.checkFunctionCall(compiledFunction, env);
250: }
251:
252: // clear the list of references, so that more can be added in another module
253: references = new ArrayList(0);
254:
255: }
256:
257: /**
258: * Produce diagnostic output showing the compiled and optimized expression tree for a function
259: * @param pool the namepool to be used
260: */
261: public void explain(NamePool pool) {
262: System.err.println("declare function "
263: + pool.getDisplayName(nameCode) + " {");
264: body.display(4, pool, System.err);
265: System.err.println("}");
266: }
267:
268: /**
269: * Get the callable compiled function contained within this XQueryFunction definition.
270: */
271:
272: public UserFunction getUserFunction() {
273: return compiledFunction;
274: }
275:
276: /**
277: * Get the type of construct. This will be a constant in
278: * class {@link Location}.
279: */
280:
281: public int getConstructType() {
282: return StandardNames.XSL_FUNCTION;
283: }
284:
285: /**
286: * Get a description of the instruction for use in error messages. For an XSLT instruction this
287: * will be the display name
288: */
289:
290: // public String getDescription(NamePool pool) {
291: // return "declare function";
292: // }
293: /**
294: * Get a name identifying the object of the expression, for example a function name, template name,
295: * variable name, key name, element name, etc. This is used only where the name is known statically.
296: */
297:
298: public int getObjectNameCode() {
299: return nameCode;
300: }
301:
302: /**
303: * Get the system identifier (URI) of the source module containing
304: * the instruction. This will generally be an absolute URI. If the system
305: * identifier is not known, the method may return null. In some cases, for example
306: * where XML external entities are used, the correct system identifier is not
307: * always retained.
308: */
309:
310: public String getSystemId() {
311: return systemId;
312: }
313:
314: /**
315: * Get the line number of the instruction in the source stylesheet module.
316: * If this is not known, or if the instruction is an artificial one that does
317: * not relate to anything in the source code, the value returned may be -1.
318: */
319:
320: public int getLineNumber() {
321: return lineNumber;
322: }
323:
324: /**
325: * Return the public identifier for the current document event.
326: * @return A string containing the public identifier, or
327: * null if none is available.
328: * @see #getSystemId
329: */
330: public String getPublicId() {
331: return null;
332: }
333:
334: /**
335: * Return the column number
336: * @return The column number, or -1 if none is available.
337: * @see #getLineNumber
338: */
339:
340: public int getColumnNumber() {
341: return -1;
342: }
343:
344: public String getSystemId(int locationId) {
345: return getSystemId();
346: }
347:
348: public int getLineNumber(int locationId) {
349: return getLineNumber();
350: }
351:
352: /**
353: * Get the namespace context of the instruction. This will not always be available, in which
354: * case the method returns null.
355: */
356:
357: public NamespaceResolver getNamespaceResolver() {
358: return namespaceResolver;
359: }
360:
361: /**
362: * Get the value of a particular property of the instruction. Properties
363: * of XSLT instructions are generally known by the name of the stylesheet attribute
364: * that defines them.
365: * @param name The name of the required property
366: * @return The value of the requested property, or null if the property is not available
367: */
368:
369: public Object getProperty(String name) {
370: if ("name".equals(name)) {
371: return staticContext.getNamePool().getDisplayName(nameCode);
372: } else if ("as".equals(name)) {
373: return resultType.toString();
374: } else {
375: return null;
376: }
377: }
378:
379: /**
380: * Get an iterator over all the properties available. The values returned by the iterator
381: * will be of type String, and each string can be supplied as input to the getProperty()
382: * method to retrieve the value of the property.
383: */
384:
385: public Iterator getProperties() {
386: return new PairIterator("name", "as");
387: }
388:
389: }
390:
391: //
392: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
393: // you may not use this file except in compliance with the License. You may obtain a copy of the
394: // License at http://www.mozilla.org/MPL/
395: //
396: // Software distributed under the License is distributed on an "AS IS" basis,
397: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
398: // See the License for the specific language governing rights and limitations under the License.
399: //
400: // The Original Code is: all this file.
401: //
402: // The Initial Developer of the Original Code is Michael H. Kay
403: //
404: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
405: //
406: // Contributor(s): none
407: //
|