1 package net.sf.saxon.style; 2 import net.sf.saxon.expr.*; 3 import net.sf.saxon.instruct.*; 4 import net.sf.saxon.om.*; 5 import net.sf.saxon.trans.XPathException; 6 import net.sf.saxon.value.EmptySequence; 7 import net.sf.saxon.value.SequenceType; 8 9 import java.util.ArrayList ; 10 import java.util.Iterator ; 11 import java.util.List ; 12 13 19 20 public class XSLFunction extends StyleElement implements StylesheetProcedure { 21 22 private String nameAtt = null; 23 private String asAtt = null; 24 private String overrideAtt = null; 25 26 private SequenceType resultType; 27 private String functionName; 28 private SlotManager stackFrameMap; 29 private boolean memoFunction = false; 30 private boolean override = true; 31 private int numberOfArguments = -1; private UserFunction compiledFunction; 33 34 List references = new ArrayList (10); 36 37 42 43 public void registerReference(UserFunctionCall ref) { 44 references.add(ref); 45 } 46 47 public void prepareAttributes() throws XPathException { 48 49 AttributeCollection atts = getAttributeList(); 50 51 for (int a=0; a<atts.getLength(); a++) { 52 int nc = atts.getNameCode(a); 53 String f = getNamePool().getClarkName(nc); 54 if (f==StandardNames.NAME) { 55 nameAtt = atts.getValue(a).trim(); 56 if (nameAtt.indexOf(':')<0) { 57 compileError("Function name must have a namespace prefix", "XTSE0740"); 58 } 59 try { 60 setObjectNameCode(makeNameCode(nameAtt.trim())); 61 } catch (NamespaceException err) { 62 compileError(err.getMessage(), "XTSE0280"); 63 } catch (XPathException err) { 64 compileError(err); 65 } 66 } else if (f==StandardNames.AS) { 67 asAtt = atts.getValue(a); 68 } else if (f==StandardNames.OVERRIDE) { 69 overrideAtt = atts.getValue(a).trim(); 70 if (overrideAtt.equals("yes")) { 71 override = true; 72 } else if (overrideAtt.equals("no")) { 73 override = false; 74 } else { 75 compileError("override must be 'yes' or 'no'", "XTSE0020"); 76 } 77 } else if (f==StandardNames.SAXON_MEMO_FUNCTION) { 78 String memoAtt = atts.getValue(a).trim(); 79 if (memoAtt.equals("yes")) { 80 memoFunction = true; 81 } else if (memoAtt.equals("no")) { 82 memoFunction = false; 83 } else { 84 compileError("saxon:memo-function must be 'yes' or 'no'", "XTSE0020"); 85 } 86 } else { 87 checkUnknownAttribute(nc); 88 } 89 } 90 91 if (nameAtt == null) { 92 reportAbsence("name"); 93 } 94 95 if (asAtt == null) { 96 resultType = SequenceType.ANY_SEQUENCE; 97 } else { 98 resultType = makeSequenceType(asAtt); 99 } 100 101 functionName = nameAtt; 102 } 103 104 108 109 public boolean mayContainSequenceConstructor() { 110 return true; 111 } 112 113 116 117 protected boolean isPermittedChild(StyleElement child) { 118 return (child instanceof XSLParam); 119 } 120 124 125 public boolean isOverriding() { 126 return override; 127 } 128 129 133 134 public void fixupReferences() throws XPathException { 135 Iterator iter = references.iterator(); 136 while (iter.hasNext()) { 137 ((UserFunctionCall)iter.next()).setStaticType(resultType); 138 } 139 super.fixupReferences(); 140 } 141 142 public void validate() throws XPathException { 143 144 stackFrameMap = getConfiguration().makeSlotManager(); 145 146 148 checkTopLevel(null); 149 getNumberOfArguments(); 150 151 153 XSLStylesheet root = getPrincipalStylesheet(); 154 List toplevel = root.getTopLevel(); 155 boolean isDuplicate = false; 156 for (int i=toplevel.size()-1; i>=0; i--) { 157 Object child = toplevel.get(i); 158 if (child instanceof XSLFunction && 159 !(child == this) && 160 ((XSLFunction)child).getFunctionFingerprint() == getFunctionFingerprint() && 161 ((XSLFunction)child).getNumberOfArguments() == numberOfArguments) { 162 if (((XSLFunction)child).getPrecedence() == getPrecedence()) { 163 isDuplicate = true; 164 } 165 if (((XSLFunction)child).getPrecedence() > getPrecedence()) { 166 isDuplicate = false; 168 break; 169 } 170 } 171 } 172 if (isDuplicate) { 173 compileError("Duplicate function declaration", "XTSE0770"); 174 } 175 } 176 177 178 186 187 public Expression compile(Executable exec) throws XPathException { 188 compileAsExpression(exec); 189 return null; 190 } 191 192 202 203 private void compileAsExpression(Executable exec) throws XPathException { 204 Expression exp = compileSequenceConstructor(exec, iterateAxis(Axis.CHILD), false); 207 if (exp == null) { 208 exp = EmptySequence.getInstance(); 209 } 210 211 213 UserFunction fn = new UserFunction(); 214 fn.setBody(exp); 215 fn.setFunctionNameCode(getObjectNameCode()); 216 setParameterDefinitions(fn); 217 fn.setResultType(getResultType()); 220 fn.setLineNumber(getLineNumber()); 221 fn.setSystemId(getSystemId()); 222 fn.setStackFrameMap(stackFrameMap); 223 fn.setMemoFunction(memoFunction); 224 fn.setExecutable(exec); 225 226 Expression exp2 = exp; 227 try { 228 exp2 = exp.typeCheck(staticContext, null); 231 exp2 = exp2.optimize(getConfiguration().getOptimizer(), staticContext, null); 232 if (resultType != null) { 233 RoleLocator role = 234 new RoleLocator(RoleLocator.FUNCTION_RESULT, functionName, 0, null); 235 role.setSourceLocator(new ExpressionLocation(this)); 236 exp2 = TypeChecker.staticTypeCheck(exp2, resultType, false, role, getStaticContext()); 237 } 238 239 } catch (XPathException err) { 240 compileError(err); 241 } 242 243 if (getConfiguration().getTraceListener() != null) { 244 TraceWrapper trace = new TraceInstruction(exp2, this); 245 trace.setLocationId(allocateLocationId(getSystemId(), getLineNumber())); 246 exp2 = trace; 247 } 248 249 allocateSlots(exp2); 250 if (exp2 != exp) { 251 fn.setBody(exp2); 252 } 253 254 boolean tailCalls = ExpressionTool.markTailFunctionCalls(exp2); 255 fn.setTailRecursive(tailCalls); 256 fixupInstruction(fn, getStaticContext()); 257 compiledFunction = fn; 258 259 if (isExplaining()) { 260 System.err.println("Optimized expression tree for function " 261 + functionName + " at line " + 262 getLineNumber() + " in " + getSystemId() + ":"); 263 exp2.display(10, getNamePool(), System.err); 264 } 265 } 266 267 272 273 private void fixupInstruction(UserFunction compiledFunction, StaticContext env) 274 throws XPathException { 275 try { 276 Iterator iter = references.iterator(); 277 while (iter.hasNext()) { 278 UserFunctionCall call = ((UserFunctionCall)iter.next()); 279 call.setFunction(compiledFunction, env); 280 call.checkFunctionCall(compiledFunction, env); 281 } 282 } catch (XPathException err) { 283 compileError(err); 284 } 285 } 286 287 291 292 public SlotManager getSlotManager() { 293 return stackFrameMap; 294 } 295 296 300 301 public int getFunctionFingerprint() { 302 if (getObjectFingerprint()==-1) { 303 try { 305 prepareAttributes(); 306 } catch (XPathException err) { 307 return -1; } 309 } 310 return getObjectFingerprint(); 311 } 312 313 318 public SequenceType getResultType() { 319 return resultType; 320 } 321 322 326 327 public int getNumberOfArguments() { 328 if (numberOfArguments == -1) { 329 numberOfArguments = 0; 330 AxisIterator kids = iterateAxis(Axis.CHILD); 331 while (true) { 332 Item child = kids.next(); 333 if (child instanceof XSLParam) { 334 numberOfArguments++; 335 } else { 336 return numberOfArguments; 337 } 338 } 339 } 340 return numberOfArguments; 341 } 342 343 346 347 public void setParameterDefinitions(UserFunction fn) { 348 UserFunctionParameter[] params = new UserFunctionParameter[getNumberOfArguments()]; 349 fn.setParameterDefinitions(params); 350 int count = 0; 351 AxisIterator kids = iterateAxis(Axis.CHILD); 352 while (true) { 353 NodeInfo node = (NodeInfo)kids.next(); 354 if (node == null) { 355 return; 356 } 357 if (node instanceof XSLParam) { 358 UserFunctionParameter param = new UserFunctionParameter(); 359 params[count++] = param; 360 param.setRequiredType(((XSLParam)node).getRequiredType()); 361 param.setSlotNumber(((XSLParam)node).getSlotNumber()); 362 ((XSLParam)node).fixupBinding(param); 363 List references = ((XSLParam)node).getReferences(); 364 int refs = RangeVariableDeclaration.getReferenceCount(references, param); 365 param.setReferenceCount(refs); 366 } 367 } 368 } 369 370 373 374 public UserFunction getCompiledFunction() { 375 return compiledFunction; 376 } 377 378 383 384 public int getConstructType() { 385 return StandardNames.XSL_FUNCTION; 386 } 387 388 } 389 390 | Popular Tags |