001: package net.sf.saxon.functions;
002:
003: import net.sf.saxon.expr.*;
004: import net.sf.saxon.om.NamePool;
005: import net.sf.saxon.om.NamespaceConstant;
006: import net.sf.saxon.trans.StaticError;
007: import net.sf.saxon.trans.XPathException;
008: import net.sf.saxon.type.AnyItemType;
009: import net.sf.saxon.type.AtomicType;
010: import net.sf.saxon.type.ItemType;
011: import net.sf.saxon.type.TypeHierarchy;
012: import net.sf.saxon.value.SequenceType;
013:
014: import java.io.PrintStream;
015: import java.util.ArrayList;
016:
017: /**
018: * Abstract superclass for system-defined and user-defined functions
019: */
020:
021: public abstract class SystemFunction extends FunctionCall {
022:
023: /**
024: * Make a system function (one in the standard function namespace).
025: * @param name The local name of the function. It may also be a lexical QName for
026: * a recognized built-in function, e.g. saxon:evaluate, in which case the prefix is hard-coded.
027: * @return a FunctionCall that implements this function, if it
028: * exists, or null if the function is unknown.
029: */
030:
031: public static FunctionCall makeSystemFunction(String name,
032: int arity, NamePool pool) {
033: StandardFunction.Entry entry = StandardFunction.getFunction(
034: name, arity);
035: if (entry == null) {
036: return null;
037: }
038: Class functionClass = entry.implementationClass;
039: try {
040: SystemFunction f = (SystemFunction) functionClass
041: .newInstance();
042: f.setDetails(entry);
043: f.setFunctionNameCode(pool.allocate("",
044: NamespaceConstant.FN, name));
045: return f;
046: } catch (IllegalAccessException err) {
047: return null;
048: } catch (InstantiationException err) {
049: return null;
050: }
051: }
052:
053: /**
054: *
055: */
056:
057: private StandardFunction.Entry details;
058: protected int operation;
059:
060: /**
061: * Set the details of this type of function
062: */
063:
064: public void setDetails(StandardFunction.Entry entry) {
065: details = entry;
066: operation = details.opcode;
067: }
068:
069: /**
070: * Get the details
071: */
072:
073: protected StandardFunction.Entry getDetails() {
074: return details;
075: }
076:
077: /**
078: * Method called during static type checking
079: */
080:
081: public void checkArguments(StaticContext env) throws XPathException {
082: checkArgumentCount(details.minArguments, details.maxArguments,
083: env);
084: for (int i = 0; i < argument.length; i++) {
085: checkArgument(i, env);
086: }
087: }
088:
089: /**
090: * Perform static type checking on an argument to a function call, and add
091: * type conversion logic where necessary.
092: */
093:
094: private void checkArgument(int arg, StaticContext env)
095: throws XPathException {
096: RoleLocator role = new RoleLocator(RoleLocator.FUNCTION,
097: new Integer(getFunctionNameCode()), arg, env
098: .getNamePool());
099: role.setSourceLocator(this );
100: role.setErrorCode(getErrorCodeForTypeErrors());
101: argument[arg] = TypeChecker.staticTypeCheck(argument[arg],
102: getRequiredType(arg),
103: env.isInBackwardsCompatibleMode(), role, env);
104: argument[arg] = argument[arg].simplify(env);
105: }
106:
107: /**
108: * Return the error code to be used for type errors
109: */
110:
111: public String getErrorCodeForTypeErrors() {
112: return "XPTY0004";
113: }
114:
115: /**
116: * Get the required type of the nth argument
117: */
118:
119: protected SequenceType getRequiredType(int arg) {
120: if (details == null) {
121: return SequenceType.ANY_SEQUENCE;
122: }
123: return details.argumentTypes[arg];
124: // this is overridden for concat()
125: }
126:
127: /**
128: * Determine the item type of the value returned by the function
129: * @param th
130: */
131:
132: public ItemType getItemType(TypeHierarchy th) {
133: if (details == null) {
134: // probably an unresolved function call
135: return AnyItemType.getInstance();
136: }
137: ItemType type = details.itemType;
138: if (type == StandardFunction.SAME_AS_FIRST_ARGUMENT) {
139: if (argument.length > 0) {
140: return argument[0].getItemType(th);
141: } else {
142: return AnyItemType.getInstance();
143: // if there is no first argument, an error will be reported
144: }
145: } else {
146: return type;
147: }
148: }
149:
150: /**
151: * Determine the cardinality of the function.
152: */
153:
154: public int computeCardinality() {
155: if (details == null) {
156: //System.err.println("**** No details for " + getClass() + " at " + this);
157: return StaticProperty.ALLOWS_ZERO_OR_MORE;
158: }
159: return details.cardinality;
160: }
161:
162: /**
163: * Determine the special properties of this expression. The general rule
164: * is that a system function call is non-creative if its return type is
165: * atomic, or if all its arguments are non-creative. This is overridden
166: * for the generate-id() function, which is considered creative if
167: * its operand is creative (because the result depends on the
168: * identity of the operand)
169: */
170:
171: public int computeSpecialProperties() {
172: int p = super .computeSpecialProperties();
173: if (details == null) {
174: return p;
175: }
176: if (details.itemType instanceof AtomicType) {
177: return p | StaticProperty.NON_CREATIVE;
178: }
179: for (int i = 0; i < argument.length; i++) {
180: if ((argument[i].getSpecialProperties() & StaticProperty.NON_CREATIVE) != 0) {
181: // the argument is creative
182: return p;
183: }
184: }
185: return p | StaticProperty.NON_CREATIVE;
186: }
187:
188: /**
189: * Set "." as the default value for the first and only argument. Called from subclasses.
190: */
191:
192: protected final void useContextItemAsDefault() {
193: if (argument.length == 0) {
194: argument = new Expression[1];
195: argument[0] = new ContextItemExpression();
196: ExpressionTool.copyLocationInfo(this , argument[0]);
197: ((ContextItemExpression) argument[0])
198: .setParentExpression(this );
199: }
200: // Note that the extra argument is added before type-checking takes place. The
201: // type-checking will add any necessary checks to ensure that the context item
202: // is a node, in cases where this is required.
203: }
204:
205: /**
206: * Add an implicit argument referring to the context document. Called by functions such as
207: * id() and key() that take the context document as an implicit argument
208: */
209:
210: protected final void addContextDocumentArgument(int pos,
211: String augmentedName) throws StaticError {
212: if (argument.length > pos) {
213: return;
214: // this can happen during optimization, if the extra argument is already present
215: }
216: if (argument.length != pos) {
217: throw new StaticError("Too few arguments in call to "
218: + augmentedName + "() function");
219: }
220: Expression[] newArgs = new Expression[pos + 1];
221: System.arraycopy(argument, 0, newArgs, 0, argument.length);
222: final RootExpression rootExpression = new RootExpression();
223: ExpressionTool.copyLocationInfo(this , newArgs[pos]);
224: rootExpression.setParentExpression(this );
225: newArgs[pos] = rootExpression;
226: argument = newArgs;
227: setDetails(StandardFunction.getFunction(augmentedName,
228: newArgs.length));
229: }
230:
231: /**
232: * Diagnostic print of expression structure
233: */
234:
235: public void display(int level, NamePool pool, PrintStream out) {
236: out.println(ExpressionTool.indent(level) + "function "
237: + getDisplayName(pool));
238: for (int a = 0; a < argument.length; a++) {
239: argument[a].display(level + 1, pool, out);
240: }
241: }
242:
243: /**
244: * The main() method of this class is not intended to be called, it merely
245: * tells the code inspection tools in IDEA that the constructors of each
246: * function class are actual entry points
247: */
248:
249: public static void main(String[] args) throws Exception {
250: ArrayList a = new ArrayList(20);
251: a.add(new Adjust());
252: a.add(new Aggregate());
253: a.add(new Available());
254: a.add(new BaseURI());
255: a.add(new BooleanFn());
256: a.add(new Collection());
257: a.add(new Compare());
258: a.add(new Component());
259: a.add(new Concat());
260: a.add(new Contains());
261: a.add(new Current());
262: a.add(new CurrentDateTime());
263: a.add(new CurrentGroup());
264: a.add(new Data());
265: a.add(new DeepEqual());
266: a.add(new DefaultCollation());
267: a.add(new DistinctValues());
268: a.add(new Doc());
269: a.add(new Document());
270: a.add(new Error());
271: a.add(new EscapeURI());
272: a.add(new Evaluate());
273: a.add(new Existence());
274: a.add(new ForceCase());
275: a.add(new FormatDate());
276: a.add(new FormatNumber2());
277: a.add(new Id());
278: a.add(new Idref());
279: a.add(new IndexOf());
280: a.add(new InScopePrefixes());
281: a.add(new Insert());
282: a.add(new KeyFn());
283: a.add(new Lang());
284: a.add(new Last());
285: a.add(new Matches());
286: a.add(new Minimax());
287: a.add(new NamePart());
288: a.add(new NamespaceForPrefix());
289: a.add(new NormalizeSpace());
290: a.add(new NumberFn());
291: a.add(new Parse());
292: a.add(new Position());
293: a.add(new QNameFn());
294: a.add(new RegexGroup());
295: a.add(new Remove());
296: a.add(new Replace());
297: a.add(new ResolveQName());
298: a.add(new ResolveURI());
299: a.add(new Reverse());
300: a.add(new Root());
301: a.add(new Rounding());
302: a.add(new Serialize());
303: a.add(new StaticBaseURI());
304: a.add(new StringFn());
305: a.add(new StringJoin());
306: a.add(new StringLength());
307: a.add(new Subsequence());
308: a.add(new Substring());
309: a.add(new SystemProperty());
310: a.add(new Tokenize());
311: a.add(new Trace());
312: a.add(new Translate());
313: a.add(new TreatFn());
314: a.add(new Unicode());
315: a.add(new Unordered());
316: a.add(new UnparsedEntity());
317: a.add(new UnparsedText());
318: }
319:
320: }
321:
322: //
323: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
324: // you may not use this file except in compliance with the License. You may obtain a copy of the
325: // License at http://www.mozilla.org/MPL/
326: //
327: // Software distributed under the License is distributed on an "AS IS" basis,
328: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
329: // See the License for the specific language governing rights and limitations under the License.
330: //
331: // The Original Code is: all this file.
332: //
333: // The Initial Developer of the Original Code is Michael H. Kay.
334: //
335: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
336: //
337: // Contributor(s): none.
338: //
|