1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.sun.org.apache.xpath.internal;
  17. import javax.xml.transform.TransformerException;
  18. import com.sun.org.apache.xalan.internal.res.XSLMessages;
  19. import com.sun.org.apache.xpath.internal.objects.XObject;
  20. import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
  21. /**
  22. * Defines a class to keep track of a stack for
  23. * template arguments and variables.
  24. *
  25. * <p>This has been changed from the previous incarnations of this
  26. * class to be fairly low level.</p>
  27. * @xsl.usage internal
  28. */
  29. public class VariableStack implements Cloneable
  30. {
  31. /**
  32. * limitation for 1K
  33. */
  34. public static final int CLEARLIMITATION= 1024;
  35. /**
  36. * Constructor for a variable stack.
  37. */
  38. public VariableStack()
  39. {
  40. reset();
  41. }
  42. /**
  43. * Returns a clone of this variable stack.
  44. *
  45. * @return a clone of this variable stack.
  46. *
  47. * @throws CloneNotSupportedException
  48. */
  49. public synchronized Object clone() throws CloneNotSupportedException
  50. {
  51. VariableStack vs = (VariableStack) super.clone();
  52. // I *think* I can get away with a shallow clone here?
  53. vs._stackFrames = (XObject[]) _stackFrames.clone();
  54. vs._links = (int[]) _links.clone();
  55. return vs;
  56. }
  57. /**
  58. * The stack frame where all variables and params will be kept.
  59. * @serial
  60. */
  61. XObject[] _stackFrames = new XObject[XPathContext.RECURSIONLIMIT * 2];
  62. /**
  63. * The top of the stack frame (<code>_stackFrames</code>).
  64. * @serial
  65. */
  66. int _frameTop;
  67. /**
  68. * The bottom index of the current frame (relative to <code>_stackFrames</code>).
  69. * @serial
  70. */
  71. private int _currentFrameBottom;
  72. /**
  73. * The stack of frame positions. I call 'em links because of distant
  74. * <a href="http://math.millikin.edu/mprogers/Courses/currentCourses/CS481-ComputerArchitecture/cs481.Motorola68000.html">
  75. * Motorola 68000 assembler</a> memories. :-)
  76. * @serial
  77. */
  78. int[] _links = new int[XPathContext.RECURSIONLIMIT];
  79. /**
  80. * The top of the links stack.
  81. */
  82. int _linksTop;
  83. /**
  84. * Get the element at the given index, regardless of stackframe.
  85. *
  86. * @param i index from zero.
  87. *
  88. * @return The item at the given index.
  89. */
  90. public XObject elementAt(final int i)
  91. {
  92. return _stackFrames[i];
  93. }
  94. /**
  95. * Get size of the stack.
  96. *
  97. * @return the total size of the execution stack.
  98. */
  99. public int size()
  100. {
  101. return _frameTop;
  102. }
  103. /**
  104. * Reset the stack to a start position.
  105. *
  106. * @return the total size of the execution stack.
  107. */
  108. public void reset()
  109. {
  110. _frameTop = 0;
  111. _linksTop = 0;
  112. // Adding one here to the stack of frame positions will allow us always
  113. // to look one under without having to check if we're at zero.
  114. // (As long as the caller doesn't screw up link/unlink.)
  115. _links[_linksTop++] = 0;
  116. _stackFrames = new XObject[_stackFrames.length];
  117. }
  118. /**
  119. * Set the current stack frame.
  120. *
  121. * @param sf The new stack frame position.
  122. */
  123. public void setStackFrame(int sf)
  124. {
  125. _currentFrameBottom = sf;
  126. }
  127. /**
  128. * Get the position from where the search should start,
  129. * which is either the searchStart property, or the top
  130. * of the stack if that value is -1.
  131. *
  132. * @return The current stack frame position.
  133. */
  134. public int getStackFrame()
  135. {
  136. return _currentFrameBottom;
  137. }
  138. /**
  139. * Allocates memory (called a stackframe) on the stack; used to store
  140. * local variables and parameter arguments.
  141. *
  142. * <p>I use the link/unlink concept because of distant
  143. * <a href="http://math.millikin.edu/mprogers/Courses/currentCourses/CS481-ComputerArchitecture/cs481.Motorola68000.html">
  144. * Motorola 68000 assembler</a> memories.</p>
  145. *
  146. * @param size The size of the stack frame allocation. This ammount should
  147. * normally be the maximum number of variables that you can have allocated
  148. * at one time in the new stack frame.
  149. *
  150. * @return The bottom of the stack frame, from where local variable addressing
  151. * should start from.
  152. */
  153. public int link(final int size)
  154. {
  155. _currentFrameBottom = _frameTop;
  156. _frameTop += size;
  157. if (_frameTop >= _stackFrames.length)
  158. {
  159. XObject newsf[] = new XObject[_stackFrames.length + XPathContext.RECURSIONLIMIT + size];
  160. System.arraycopy(_stackFrames, 0, newsf, 0, _stackFrames.length);
  161. _stackFrames = newsf;
  162. }
  163. if (_linksTop + 1 >= _links.length)
  164. {
  165. int newlinks[] = new int[_links.length + (CLEARLIMITATION * 2)];
  166. System.arraycopy(_links, 0, newlinks, 0, _links.length);
  167. _links = newlinks;
  168. }
  169. _links[_linksTop++] = _currentFrameBottom;
  170. return _currentFrameBottom;
  171. }
  172. /**
  173. * Free up the stack frame that was last allocated with
  174. * {@link link(int size)}.
  175. */
  176. public void unlink()
  177. {
  178. _frameTop = _links[--_linksTop];
  179. _currentFrameBottom = _links[_linksTop - 1];
  180. }
  181. /**
  182. * Free up the stack frame that was last allocated with
  183. * {@link link(int size)}.
  184. * @param currentFrame The current frame to set to
  185. * after the unlink.
  186. */
  187. public void unlink(int currentFrame)
  188. {
  189. _frameTop = _links[--_linksTop];
  190. _currentFrameBottom = currentFrame;
  191. }
  192. /**
  193. * Set a local variable or parameter in the current stack frame.
  194. *
  195. *
  196. * @param index Local variable index relative to the current stack
  197. * frame bottom.
  198. *
  199. * @param val The value of the variable that is being set.
  200. */
  201. public void setLocalVariable(int index, XObject val)
  202. {
  203. _stackFrames[index + _currentFrameBottom] = val;
  204. }
  205. /**
  206. * Set a local variable or parameter in the specified stack frame.
  207. *
  208. *
  209. * @param index Local variable index relative to the current stack
  210. * frame bottom.
  211. * NEEDSDOC @param stackFrame
  212. *
  213. * @param val The value of the variable that is being set.
  214. */
  215. public void setLocalVariable(int index, XObject val, int stackFrame)
  216. {
  217. _stackFrames[index + stackFrame] = val;
  218. }
  219. /**
  220. * Get a local variable or parameter in the current stack frame.
  221. *
  222. *
  223. * @param xctxt The XPath context, which must be passed in order to
  224. * lazy evaluate variables.
  225. *
  226. * @param index Local variable index relative to the current stack
  227. * frame bottom.
  228. *
  229. * @return The value of the variable.
  230. *
  231. * @throws TransformerException
  232. */
  233. public XObject getLocalVariable(XPathContext xctxt, int index)
  234. throws TransformerException
  235. {
  236. index += _currentFrameBottom;
  237. XObject val = _stackFrames[index];
  238. if(null == val)
  239. throw new TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VARIABLE_ACCESSED_BEFORE_BIND, null),
  240. xctxt.getSAXLocator());
  241. // "Variable accessed before it is bound!", xctxt.getSAXLocator());
  242. // Lazy execution of variables.
  243. if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
  244. return (_stackFrames[index] = val.execute(xctxt));
  245. return val;
  246. }
  247. /**
  248. * Get a local variable or parameter in the current stack frame.
  249. *
  250. *
  251. * @param index Local variable index relative to the given
  252. * frame bottom.
  253. * NEEDSDOC @param frame
  254. *
  255. * @return The value of the variable.
  256. *
  257. * @throws TransformerException
  258. */
  259. public XObject getLocalVariable(int index, int frame)
  260. throws TransformerException
  261. {
  262. index += frame;
  263. XObject val = _stackFrames[index];
  264. return val;
  265. }
  266. /**
  267. * Get a local variable or parameter in the current stack frame.
  268. *
  269. *
  270. * @param xctxt The XPath context, which must be passed in order to
  271. * lazy evaluate variables.
  272. *
  273. * @param index Local variable index relative to the current stack
  274. * frame bottom.
  275. *
  276. * @return The value of the variable.
  277. *
  278. * @throws TransformerException
  279. */
  280. public XObject getLocalVariable(XPathContext xctxt, int index, boolean destructiveOK)
  281. throws TransformerException
  282. {
  283. index += _currentFrameBottom;
  284. XObject val = _stackFrames[index];
  285. if(null == val)
  286. throw new TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VARIABLE_ACCESSED_BEFORE_BIND, null),
  287. xctxt.getSAXLocator());
  288. // "Variable accessed before it is bound!", xctxt.getSAXLocator());
  289. // Lazy execution of variables.
  290. if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
  291. return (_stackFrames[index] = val.execute(xctxt));
  292. return destructiveOK ? val : val.getFresh();
  293. }
  294. /**
  295. * Tell if a local variable has been set or not.
  296. *
  297. * @param index Local variable index relative to the current stack
  298. * frame bottom.
  299. *
  300. * @return true if the value at the index is not null.
  301. *
  302. * @throws TransformerException
  303. */
  304. public boolean isLocalSet(int index) throws TransformerException
  305. {
  306. return (_stackFrames[index + _currentFrameBottom] != null);
  307. }
  308. /** NEEDSDOC Field m_nulls */
  309. private static XObject[] m_nulls = new XObject[CLEARLIMITATION];
  310. /**
  311. * Use this to clear the variables in a section of the stack. This is
  312. * used to clear the parameter section of the stack, so that default param
  313. * values can tell if they've already been set. It is important to note that
  314. * this function has a 1K limitation.
  315. *
  316. * @param start The start position, relative to the current local stack frame.
  317. * @param len The number of slots to be cleared.
  318. */
  319. public void clearLocalSlots(int start, int len)
  320. {
  321. start += _currentFrameBottom;
  322. System.arraycopy(m_nulls, 0, _stackFrames, start, len);
  323. }
  324. /**
  325. * Set a global variable or parameter in the global stack frame.
  326. *
  327. *
  328. * @param index Local variable index relative to the global stack frame
  329. * bottom.
  330. *
  331. * @param val The value of the variable that is being set.
  332. */
  333. public void setGlobalVariable(final int index, final XObject val)
  334. {
  335. _stackFrames[index] = val;
  336. }
  337. /**
  338. * Get a global variable or parameter from the global stack frame.
  339. *
  340. *
  341. * @param xctxt The XPath context, which must be passed in order to
  342. * lazy evaluate variables.
  343. *
  344. * @param index Global variable index relative to the global stack
  345. * frame bottom.
  346. *
  347. * @return The value of the variable.
  348. *
  349. * @throws TransformerException
  350. */
  351. public XObject getGlobalVariable(XPathContext xctxt, final int index)
  352. throws TransformerException
  353. {
  354. XObject val = _stackFrames[index];
  355. // Lazy execution of variables.
  356. if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
  357. return (_stackFrames[index] = val.execute(xctxt));
  358. return val;
  359. }
  360. /**
  361. * Get a global variable or parameter from the global stack frame.
  362. *
  363. *
  364. * @param xctxt The XPath context, which must be passed in order to
  365. * lazy evaluate variables.
  366. *
  367. * @param index Global variable index relative to the global stack
  368. * frame bottom.
  369. *
  370. * @return The value of the variable.
  371. *
  372. * @throws TransformerException
  373. */
  374. public XObject getGlobalVariable(XPathContext xctxt, final int index, boolean destructiveOK)
  375. throws TransformerException
  376. {
  377. XObject val = _stackFrames[index];
  378. // Lazy execution of variables.
  379. if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE)
  380. return (_stackFrames[index] = val.execute(xctxt));
  381. return destructiveOK ? val : val.getFresh();
  382. }
  383. /**
  384. * Get a variable based on it's qualified name.
  385. * This is for external use only.
  386. *
  387. * @param xctxt The XPath context, which must be passed in order to
  388. * lazy evaluate variables.
  389. *
  390. * @param qname The qualified name of the variable.
  391. *
  392. * @return The evaluated value of the variable.
  393. *
  394. * @throws javax.xml.transform.TransformerException
  395. */
  396. public XObject getVariableOrParam(
  397. XPathContext xctxt, com.sun.org.apache.xml.internal.utils.QName qname)
  398. throws javax.xml.transform.TransformerException
  399. {
  400. // <<<<<<< TIGER SPECIFIC CHANGE >>>>>>>>>
  401. // As we are not supporting Xalan interpretive we are taking away the functionality
  402. // dependent on XSLT interpretive Transformer. Only way supported is to use XSLTC
  403. // and the execution path needed for supporting standard XPath API defined by
  404. // JAXP 1.3 . This method is overridden in XPath implementation to support
  405. // standard XPath functionality with xpath package of Xalan
  406. throw new javax.xml.transform.TransformerException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_VAR_NOT_RESOLVABLE, new Object[]{qname.toString()})); //"Variable not resolvable: " + qname);
  407. }
  408. } // end VariableStack