1 package net.sf.saxon.expr; 2 import net.sf.saxon.instruct.InstructionDetails; 3 import net.sf.saxon.instruct.UserFunction; 4 import net.sf.saxon.om.*; 5 import net.sf.saxon.trace.InstructionInfo; 6 import net.sf.saxon.trace.InstructionInfoProvider; 7 import net.sf.saxon.trace.Location; 8 import net.sf.saxon.trans.DynamicError; 9 import net.sf.saxon.trans.XPathException; 10 import net.sf.saxon.type.AnyItemType; 11 import net.sf.saxon.type.ItemType; 12 import net.sf.saxon.value.*; 13 14 import java.io.PrintStream ; 15 16 17 23 24 public class UserFunctionCall extends FunctionCall implements InstructionInfoProvider { 25 26 private SequenceType staticType; 27 private UserFunction function; 28 private boolean tailRecursive = false; 29 private boolean confirmed = false; 30 34 public UserFunctionCall() {} 35 36 39 40 public void setStaticType(SequenceType type) { 41 staticType = type; 42 } 43 44 47 48 public void setFunction(UserFunction compiledFunction, 49 StaticContext env) throws XPathException { 50 function = compiledFunction; 51 confirmed = true; 52 } 53 54 57 58 public void checkFunctionCall(UserFunction compiledFunction, 59 StaticContext env) throws XPathException { 60 int n = compiledFunction.getNumberOfArguments(); 61 for (int i=0; i<n; i++) { 62 RoleLocator role = new RoleLocator( 63 RoleLocator.FUNCTION, new Integer (compiledFunction.getFunctionNameCode()), i, env.getNamePool()); 64 role.setSourceLocator(this); 65 argument[i] = TypeChecker.staticTypeCheck( 66 argument[i], 67 compiledFunction.getArgumentType(i), 68 false, 69 role, env); 70 } 71 } 72 73 74 77 78 public UserFunction getFunction() { 79 return function; 80 } 81 82 85 86 public void setConfirmed(boolean conf) { 87 confirmed = conf; 88 } 89 90 93 94 public boolean isConfirmed() { 95 return confirmed; 96 } 97 98 101 102 public void checkArguments(StaticContext env) throws XPathException { 103 } 106 107 111 112 public Expression preEvaluate(StaticContext env) { 113 return this; 114 } 115 116 120 121 public ItemType getItemType() { 122 if (staticType == null) { 123 return AnyItemType.getInstance(); 125 } else { 126 return staticType.getPrimaryType(); 127 } 128 } 129 130 public int getIntrinsicDependencies() { 131 return StaticProperty.DEPENDS_ON_USER_FUNCTIONS; 132 } 133 134 137 138 public int computeCardinality() { 139 if (staticType == null) { 140 return StaticProperty.ALLOWS_ZERO_OR_MORE; 142 } else { 143 return staticType.getCardinality(); 144 } 145 } 146 147 150 151 public Expression simplify(StaticContext env) throws XPathException { 152 for (int i=0; i<argument.length; i++) { 153 argument[i] = argument[i].simplify(env); 154 } 155 return this; 156 } 157 158 161 162 public boolean markTailFunctionCalls() { 163 tailRecursive = true; 164 return true; 165 } 166 167 175 180 181 public Item evaluateItem(XPathContext c) throws XPathException { 182 ValueRepresentation val = callFunction(c); 183 if (val instanceof Item) { 184 return (Item)val; 185 } else { 186 return Value.getIterator(val).next(); 187 } 188 } 189 190 194 195 public SequenceIterator iterate(XPathContext c) throws XPathException { 196 ValueRepresentation result = callFunction(c); 197 if (result instanceof FunctionCallPackage) { 198 return SingletonIterator.makeIterator(((FunctionCallPackage)result)); 199 } 200 return Value.getIterator(result); 201 } 202 203 209 private ValueRepresentation callFunction(XPathContext c) throws XPathException { 210 int numArgs = argument.length; 211 212 ValueRepresentation[] actualArgs = new ValueRepresentation[numArgs]; 213 for (int i=0; i<numArgs; i++) { 214 int refs = function.getParameterDefinitions()[i].getReferenceCount(); 216 if (argument[i] instanceof Value) { 217 actualArgs[i] = (Value)argument[i]; 218 } else { 219 if (refs == 0) { 220 actualArgs[i] = EmptySequence.getInstance(); 222 } else if ((argument[i].getDependencies() & StaticProperty.DEPENDS_ON_USER_FUNCTIONS) != 0) { 223 actualArgs[i] = ExpressionTool.eagerEvaluate(argument[i], c); 227 } else { 228 actualArgs[i] = ExpressionTool.lazyEvaluate(argument[i], c, refs); 229 } 230 } 231 if (refs > 1 && actualArgs[i] instanceof Closure && !(actualArgs[i] instanceof MemoClosure)) { 234 actualArgs[i] = ((Closure)actualArgs[i]).reduce(); 235 } 236 } 237 238 if (tailRecursive) { 239 return new FunctionCallPackage(function, actualArgs, c); 240 } 241 242 XPathContextMajor c2 = c.newCleanContext(); 243 c2.setOrigin(this); 244 try { 245 return function.call(actualArgs, c2, true); 246 } catch (StackOverflowError err) { 247 throw new DynamicError("Too many nested function calls. May be due to infinite recursion.", this); 248 } 249 } 250 251 256 257 public ValueRepresentation dynamicCall(ValueRepresentation[] suppliedArguments, XPathContext context) throws XPathException { 258 ValueRepresentation[] convertedArgs = new ValueRepresentation[suppliedArguments.length]; 259 XPathContextMajor c2 = context.newCleanContext(); 260 c2.setOrigin(this); 261 c2.setCaller(context); 262 c2.openStackFrame(suppliedArguments.length); 263 for (int i=0; i<suppliedArguments.length; i++) { 264 c2.setLocalVariable(i, suppliedArguments[i]); 265 convertedArgs[i] = ExpressionTool.lazyEvaluate(argument[i], c2, 10); 266 } 267 XPathContextMajor c3 = c2.newCleanContext(); 268 c3.setOrigin(this); 269 return function.call(convertedArgs, c3, true); 270 } 271 272 public void display(int level, NamePool pool, PrintStream out) { 273 out.println(ExpressionTool.indent(level) + "function " + getDisplayName(pool) + 274 (tailRecursive ? " (tail call)" : "")); 275 for (int a=0; a<argument.length; a++) { 276 argument[a].display(level+1, pool, out); 277 } 278 } 279 280 283 284 public InstructionInfo getInstructionInfo() { 285 InstructionDetails details = new InstructionDetails(); 286 details.setConstructType(Location.FUNCTION_CALL); 287 details.setLineNumber(getLineNumber()); 288 details.setSystemId(getSystemId()); 289 details.setObjectNameCode(getFunctionNameCode()); 290 details.setProperty("expression", this); 291 details.setProperty("target", function); 292 return details; 293 } 294 295 301 302 public class FunctionCallPackage extends ObjectValue { 303 304 private UserFunction function; 305 private ValueRepresentation[] actualArgs; 306 private XPathContext evaluationContext; 307 308 public FunctionCallPackage(UserFunction function, ValueRepresentation[] actualArgs, XPathContext c) { 309 super(function); 310 this.function = function; 311 this.actualArgs = actualArgs; 312 this.evaluationContext = c; 313 } 314 315 318 319 public ItemType getItemType() { 320 return UserFunctionCall.this.getItemType(); 321 } 322 323 public ValueRepresentation call() throws XPathException { 324 XPathContextMajor c2 = evaluationContext.newCleanContext(); 325 c2.setOrigin(UserFunctionCall.this); 326 return function.call(actualArgs, c2, false); 327 } 328 329 public SequenceIterator iterateResults(XPathContext context) throws XPathException { 330 ValueRepresentation result = call(); 331 return new MappingIterator(Value.getIterator(result), Flattener.THE_INSTANCE, context); 332 } 333 334 335 350 356 357 public Value reduce() throws XPathException { 358 return new SequenceExtent(iterateResults(null)).reduce(); 359 } 360 361 371 372 public AtomicValue getPrimitiveValue() { 373 try { 374 return ((AtomicValue)reduce()).getPrimitiveValue(); 375 } catch (XPathException e) { 376 throw new RuntimeException (e); 377 } 378 } 379 } 380 381 385 386 private static class Flattener implements MappingFunction { 387 388 public static final Flattener THE_INSTANCE = new Flattener(); 389 390 private Flattener() {} 391 403 404 public Object map(Item item, XPathContext context) throws XPathException { 405 if (item instanceof FunctionCallPackage) { 406 return (((FunctionCallPackage)item).iterateResults(context)); 407 } else { 408 return item; 409 } 410 } 411 412 413 } 414 415 416 417 } 418 419 | Popular Tags |