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. /*
  17. * $Id: Compiler.java,v 1.36 2004/02/17 04:32:49 minchau Exp $
  18. */
  19. package com.sun.org.apache.xpath.internal.compiler;
  20. import javax.xml.transform.ErrorListener;
  21. import javax.xml.transform.SourceLocator;
  22. import javax.xml.transform.TransformerException;
  23. import com.sun.org.apache.xalan.internal.res.XSLMessages;
  24. import com.sun.org.apache.xml.internal.dtm.Axis;
  25. import com.sun.org.apache.xml.internal.dtm.DTMFilter;
  26. import com.sun.org.apache.xml.internal.dtm.DTMIterator;
  27. import com.sun.org.apache.xml.internal.utils.PrefixResolver;
  28. import com.sun.org.apache.xml.internal.utils.QName;
  29. import com.sun.org.apache.xml.internal.utils.SAXSourceLocator;
  30. import com.sun.org.apache.xpath.internal.Expression;
  31. import com.sun.org.apache.xpath.internal.axes.UnionPathIterator;
  32. import com.sun.org.apache.xpath.internal.axes.WalkerFactory;
  33. import com.sun.org.apache.xpath.internal.functions.FuncExtFunction;
  34. import com.sun.org.apache.xpath.internal.functions.Function;
  35. import com.sun.org.apache.xpath.internal.functions.WrongNumberArgsException;
  36. import com.sun.org.apache.xpath.internal.objects.XNumber;
  37. import com.sun.org.apache.xpath.internal.objects.XString;
  38. import com.sun.org.apache.xpath.internal.operations.And;
  39. import com.sun.org.apache.xpath.internal.operations.Div;
  40. import com.sun.org.apache.xpath.internal.operations.Equals;
  41. import com.sun.org.apache.xpath.internal.operations.Gt;
  42. import com.sun.org.apache.xpath.internal.operations.Gte;
  43. import com.sun.org.apache.xpath.internal.operations.Lt;
  44. import com.sun.org.apache.xpath.internal.operations.Lte;
  45. import com.sun.org.apache.xpath.internal.operations.Minus;
  46. import com.sun.org.apache.xpath.internal.operations.Mod;
  47. import com.sun.org.apache.xpath.internal.operations.Mult;
  48. import com.sun.org.apache.xpath.internal.operations.Neg;
  49. import com.sun.org.apache.xpath.internal.operations.NotEquals;
  50. import com.sun.org.apache.xpath.internal.operations.Operation;
  51. import com.sun.org.apache.xpath.internal.operations.Or;
  52. import com.sun.org.apache.xpath.internal.operations.Plus;
  53. import com.sun.org.apache.xpath.internal.operations.UnaryOperation;
  54. import com.sun.org.apache.xpath.internal.operations.Variable;
  55. import com.sun.org.apache.xpath.internal.patterns.FunctionPattern;
  56. import com.sun.org.apache.xpath.internal.patterns.NodeTest;
  57. import com.sun.org.apache.xpath.internal.patterns.StepPattern;
  58. import com.sun.org.apache.xpath.internal.patterns.UnionPattern;
  59. import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
  60. /**
  61. * An instance of this class compiles an XPath string expression into
  62. * a Expression object. This class compiles the string into a sequence
  63. * of operation codes (op map) and then builds from that into an Expression
  64. * tree.
  65. * @xsl.usage advanced
  66. */
  67. public class Compiler extends OpMap
  68. {
  69. /**
  70. * Construct a Compiler object with a specific ErrorListener and
  71. * SourceLocator where the expression is located.
  72. *
  73. * @param errorHandler Error listener where messages will be sent, or null
  74. * if messages should be sent to System err.
  75. * @param locator The location object where the expression lives, which
  76. * may be null, but which, if not null, must be valid over
  77. * the long haul, in other words, it will not be cloned.
  78. */
  79. public Compiler(ErrorListener errorHandler, SourceLocator locator)
  80. {
  81. m_errorHandler = errorHandler;
  82. m_locator = locator;
  83. }
  84. /**
  85. * Construct a Compiler instance that has a null error listener and a
  86. * null source locator.
  87. */
  88. public Compiler()
  89. {
  90. m_errorHandler = null;
  91. m_locator = null;
  92. }
  93. /**
  94. * Execute the XPath object from a given opcode position.
  95. * @param xctxt The execution context.
  96. * @param context The current source tree context node.
  97. * @param opPos The current position in the xpath.m_opMap array.
  98. * @param callback Interface that implements the processLocatedNode method.
  99. * @param callbackInfo Object that will be passed to the processLocatedNode method.
  100. * @return The result of the XPath.
  101. *
  102. * @throws TransformerException if there is a syntax or other error.
  103. * @xsl.usage advanced
  104. */
  105. public Expression compile(int opPos) throws TransformerException
  106. {
  107. int op = getOp(opPos);
  108. Expression expr = null;
  109. // System.out.println(getPatternString()+"op: "+op);
  110. switch (op)
  111. {
  112. case OpCodes.OP_XPATH :
  113. expr = compile(opPos + 2); break;
  114. case OpCodes.OP_OR :
  115. expr = or(opPos); break;
  116. case OpCodes.OP_AND :
  117. expr = and(opPos); break;
  118. case OpCodes.OP_NOTEQUALS :
  119. expr = notequals(opPos); break;
  120. case OpCodes.OP_EQUALS :
  121. expr = equals(opPos); break;
  122. case OpCodes.OP_LTE :
  123. expr = lte(opPos); break;
  124. case OpCodes.OP_LT :
  125. expr = lt(opPos); break;
  126. case OpCodes.OP_GTE :
  127. expr = gte(opPos); break;
  128. case OpCodes.OP_GT :
  129. expr = gt(opPos); break;
  130. case OpCodes.OP_PLUS :
  131. expr = plus(opPos); break;
  132. case OpCodes.OP_MINUS :
  133. expr = minus(opPos); break;
  134. case OpCodes.OP_MULT :
  135. expr = mult(opPos); break;
  136. case OpCodes.OP_DIV :
  137. expr = div(opPos); break;
  138. case OpCodes.OP_MOD :
  139. expr = mod(opPos); break;
  140. // case OpCodes.OP_QUO :
  141. // expr = quo(opPos); break;
  142. case OpCodes.OP_NEG :
  143. expr = neg(opPos); break;
  144. case OpCodes.OP_STRING :
  145. expr = string(opPos); break;
  146. case OpCodes.OP_BOOL :
  147. expr = bool(opPos); break;
  148. case OpCodes.OP_NUMBER :
  149. expr = number(opPos); break;
  150. case OpCodes.OP_UNION :
  151. expr = union(opPos); break;
  152. case OpCodes.OP_LITERAL :
  153. expr = literal(opPos); break;
  154. case OpCodes.OP_VARIABLE :
  155. expr = variable(opPos); break;
  156. case OpCodes.OP_GROUP :
  157. expr = group(opPos); break;
  158. case OpCodes.OP_NUMBERLIT :
  159. expr = numberlit(opPos); break;
  160. case OpCodes.OP_ARGUMENT :
  161. expr = arg(opPos); break;
  162. case OpCodes.OP_EXTFUNCTION :
  163. expr = compileExtension(opPos); break;
  164. case OpCodes.OP_FUNCTION :
  165. expr = compileFunction(opPos); break;
  166. case OpCodes.OP_LOCATIONPATH :
  167. expr = locationPath(opPos); break;
  168. case OpCodes.OP_PREDICATE :
  169. expr = null; break; // should never hit this here.
  170. case OpCodes.OP_MATCHPATTERN :
  171. expr = matchPattern(opPos + 2); break;
  172. case OpCodes.OP_LOCATIONPATHPATTERN :
  173. expr = locationPathPattern(opPos); break;
  174. case OpCodes.OP_QUO:
  175. error(XPATHErrorResources.ER_UNKNOWN_OPCODE,
  176. new Object[]{ "quo" }); //"ERROR! Unknown op code: "+m_opMap[opPos]);
  177. break;
  178. default :
  179. error(XPATHErrorResources.ER_UNKNOWN_OPCODE,
  180. new Object[]{ Integer.toString(getOp(opPos)) }); //"ERROR! Unknown op code: "+m_opMap[opPos]);
  181. }
  182. // if(null != expr)
  183. // expr.setSourceLocator(m_locator);
  184. return expr;
  185. }
  186. /**
  187. * Bottle-neck compilation of an operation with left and right operands.
  188. *
  189. * @param operation non-null reference to parent operation.
  190. * @param opPos The op map position of the parent operation.
  191. *
  192. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Operation} instance.
  193. *
  194. * @throws TransformerException if there is a syntax or other error.
  195. */
  196. private Expression compileOperation(Operation operation, int opPos)
  197. throws TransformerException
  198. {
  199. int leftPos = getFirstChildPos(opPos);
  200. int rightPos = getNextOpPos(leftPos);
  201. operation.setLeftRight(compile(leftPos), compile(rightPos));
  202. return operation;
  203. }
  204. /**
  205. * Bottle-neck compilation of a unary operation.
  206. *
  207. * @param unary The parent unary operation.
  208. * @param opPos The position in the op map of the parent operation.
  209. *
  210. * @return The unary argument.
  211. *
  212. * @throws TransformerException if syntax or other error occurs.
  213. */
  214. private Expression compileUnary(UnaryOperation unary, int opPos)
  215. throws TransformerException
  216. {
  217. int rightPos = getFirstChildPos(opPos);
  218. unary.setRight(compile(rightPos));
  219. return unary;
  220. }
  221. /**
  222. * Compile an 'or' operation.
  223. *
  224. * @param opPos The current position in the m_opMap array.
  225. *
  226. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Or} instance.
  227. *
  228. * @throws TransformerException if a error occurs creating the Expression.
  229. */
  230. protected Expression or(int opPos) throws TransformerException
  231. {
  232. return compileOperation(new Or(), opPos);
  233. }
  234. /**
  235. * Compile an 'and' operation.
  236. *
  237. * @param opPos The current position in the m_opMap array.
  238. *
  239. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.And} instance.
  240. *
  241. * @throws TransformerException if a error occurs creating the Expression.
  242. */
  243. protected Expression and(int opPos) throws TransformerException
  244. {
  245. return compileOperation(new And(), opPos);
  246. }
  247. /**
  248. * Compile a '!=' operation.
  249. *
  250. * @param opPos The current position in the m_opMap array.
  251. *
  252. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.NotEquals} instance.
  253. *
  254. * @throws TransformerException if a error occurs creating the Expression.
  255. */
  256. protected Expression notequals(int opPos) throws TransformerException
  257. {
  258. return compileOperation(new NotEquals(), opPos);
  259. }
  260. /**
  261. * Compile a '=' operation.
  262. *
  263. * @param opPos The current position in the m_opMap array.
  264. *
  265. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Equals} instance.
  266. *
  267. * @throws TransformerException if a error occurs creating the Expression.
  268. */
  269. protected Expression equals(int opPos) throws TransformerException
  270. {
  271. return compileOperation(new Equals(), opPos);
  272. }
  273. /**
  274. * Compile a '<=' operation.
  275. *
  276. * @param opPos The current position in the m_opMap array.
  277. *
  278. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Lte} instance.
  279. *
  280. * @throws TransformerException if a error occurs creating the Expression.
  281. */
  282. protected Expression lte(int opPos) throws TransformerException
  283. {
  284. return compileOperation(new Lte(), opPos);
  285. }
  286. /**
  287. * Compile a '<' operation.
  288. *
  289. * @param opPos The current position in the m_opMap array.
  290. *
  291. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Lt} instance.
  292. *
  293. * @throws TransformerException if a error occurs creating the Expression.
  294. */
  295. protected Expression lt(int opPos) throws TransformerException
  296. {
  297. return compileOperation(new Lt(), opPos);
  298. }
  299. /**
  300. * Compile a '>=' operation.
  301. *
  302. * @param opPos The current position in the m_opMap array.
  303. *
  304. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Gte} instance.
  305. *
  306. * @throws TransformerException if a error occurs creating the Expression.
  307. */
  308. protected Expression gte(int opPos) throws TransformerException
  309. {
  310. return compileOperation(new Gte(), opPos);
  311. }
  312. /**
  313. * Compile a '>' operation.
  314. *
  315. * @param opPos The current position in the m_opMap array.
  316. *
  317. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Gt} instance.
  318. *
  319. * @throws TransformerException if a error occurs creating the Expression.
  320. */
  321. protected Expression gt(int opPos) throws TransformerException
  322. {
  323. return compileOperation(new Gt(), opPos);
  324. }
  325. /**
  326. * Compile a '+' operation.
  327. *
  328. * @param opPos The current position in the m_opMap array.
  329. *
  330. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Plus} instance.
  331. *
  332. * @throws TransformerException if a error occurs creating the Expression.
  333. */
  334. protected Expression plus(int opPos) throws TransformerException
  335. {
  336. return compileOperation(new Plus(), opPos);
  337. }
  338. /**
  339. * Compile a '-' operation.
  340. *
  341. * @param opPos The current position in the m_opMap array.
  342. *
  343. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Minus} instance.
  344. *
  345. * @throws TransformerException if a error occurs creating the Expression.
  346. */
  347. protected Expression minus(int opPos) throws TransformerException
  348. {
  349. return compileOperation(new Minus(), opPos);
  350. }
  351. /**
  352. * Compile a '*' operation.
  353. *
  354. * @param opPos The current position in the m_opMap array.
  355. *
  356. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Mult} instance.
  357. *
  358. * @throws TransformerException if a error occurs creating the Expression.
  359. */
  360. protected Expression mult(int opPos) throws TransformerException
  361. {
  362. return compileOperation(new Mult(), opPos);
  363. }
  364. /**
  365. * Compile a 'div' operation.
  366. *
  367. * @param opPos The current position in the m_opMap array.
  368. *
  369. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Div} instance.
  370. *
  371. * @throws TransformerException if a error occurs creating the Expression.
  372. */
  373. protected Expression div(int opPos) throws TransformerException
  374. {
  375. return compileOperation(new Div(), opPos);
  376. }
  377. /**
  378. * Compile a 'mod' operation.
  379. *
  380. * @param opPos The current position in the m_opMap array.
  381. *
  382. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Mod} instance.
  383. *
  384. * @throws TransformerException if a error occurs creating the Expression.
  385. */
  386. protected Expression mod(int opPos) throws TransformerException
  387. {
  388. return compileOperation(new Mod(), opPos);
  389. }
  390. /*
  391. * Compile a 'quo' operation.
  392. *
  393. * @param opPos The current position in the m_opMap array.
  394. *
  395. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Quo} instance.
  396. *
  397. * @throws TransformerException if a error occurs creating the Expression.
  398. */
  399. // protected Expression quo(int opPos) throws TransformerException
  400. // {
  401. // return compileOperation(new Quo(), opPos);
  402. // }
  403. /**
  404. * Compile a unary '-' operation.
  405. *
  406. * @param opPos The current position in the m_opMap array.
  407. *
  408. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Neg} instance.
  409. *
  410. * @throws TransformerException if a error occurs creating the Expression.
  411. */
  412. protected Expression neg(int opPos) throws TransformerException
  413. {
  414. return compileUnary(new Neg(), opPos);
  415. }
  416. /**
  417. * Compile a 'string(...)' operation.
  418. *
  419. * @param opPos The current position in the m_opMap array.
  420. *
  421. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.String} instance.
  422. *
  423. * @throws TransformerException if a error occurs creating the Expression.
  424. */
  425. protected Expression string(int opPos) throws TransformerException
  426. {
  427. return compileUnary(new com.sun.org.apache.xpath.internal.operations.String(), opPos);
  428. }
  429. /**
  430. * Compile a 'boolean(...)' operation.
  431. *
  432. * @param opPos The current position in the m_opMap array.
  433. *
  434. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Bool} instance.
  435. *
  436. * @throws TransformerException if a error occurs creating the Expression.
  437. */
  438. protected Expression bool(int opPos) throws TransformerException
  439. {
  440. return compileUnary(new com.sun.org.apache.xpath.internal.operations.Bool(), opPos);
  441. }
  442. /**
  443. * Compile a 'number(...)' operation.
  444. *
  445. * @param opPos The current position in the m_opMap array.
  446. *
  447. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Number} instance.
  448. *
  449. * @throws TransformerException if a error occurs creating the Expression.
  450. */
  451. protected Expression number(int opPos) throws TransformerException
  452. {
  453. return compileUnary(new com.sun.org.apache.xpath.internal.operations.Number(), opPos);
  454. }
  455. /**
  456. * Compile a literal string value.
  457. *
  458. * @param opPos The current position in the m_opMap array.
  459. *
  460. * @return reference to {@link com.sun.org.apache.xpath.internal.objects.XString} instance.
  461. *
  462. * @throws TransformerException if a error occurs creating the Expression.
  463. */
  464. protected Expression literal(int opPos)
  465. {
  466. opPos = getFirstChildPos(opPos);
  467. return (XString) getTokenQueue().elementAt(getOp(opPos));
  468. }
  469. /**
  470. * Compile a literal number value.
  471. *
  472. * @param opPos The current position in the m_opMap array.
  473. *
  474. * @return reference to {@link com.sun.org.apache.xpath.internal.objects.XNumber} instance.
  475. *
  476. * @throws TransformerException if a error occurs creating the Expression.
  477. */
  478. protected Expression numberlit(int opPos)
  479. {
  480. opPos = getFirstChildPos(opPos);
  481. return (XNumber) getTokenQueue().elementAt(getOp(opPos));
  482. }
  483. /**
  484. * Compile a variable reference.
  485. *
  486. * @param opPos The current position in the m_opMap array.
  487. *
  488. * @return reference to {@link com.sun.org.apache.xpath.internal.operations.Variable} instance.
  489. *
  490. * @throws TransformerException if a error occurs creating the Expression.
  491. */
  492. protected Expression variable(int opPos) throws TransformerException
  493. {
  494. Variable var = new Variable();
  495. opPos = getFirstChildPos(opPos);
  496. int nsPos = getOp(opPos);
  497. java.lang.String namespace
  498. = (OpCodes.EMPTY == nsPos) ? null
  499. : (java.lang.String) getTokenQueue().elementAt(nsPos);
  500. java.lang.String localname
  501. = (java.lang.String) getTokenQueue().elementAt(getOp(opPos+1));
  502. QName qname = new QName(namespace, localname);
  503. var.setQName(qname);
  504. return var;
  505. }
  506. /**
  507. * Compile an expression group.
  508. *
  509. * @param opPos The current position in the m_opMap array.
  510. *
  511. * @return reference to the contained expression.
  512. *
  513. * @throws TransformerException if a error occurs creating the Expression.
  514. */
  515. protected Expression group(int opPos) throws TransformerException
  516. {
  517. // no-op
  518. return compile(opPos + 2);
  519. }
  520. /**
  521. * Compile a function argument.
  522. *
  523. * @param opPos The current position in the m_opMap array.
  524. *
  525. * @return reference to the argument expression.
  526. *
  527. * @throws TransformerException if a error occurs creating the Expression.
  528. */
  529. protected Expression arg(int opPos) throws TransformerException
  530. {
  531. // no-op
  532. return compile(opPos + 2);
  533. }
  534. /**
  535. * Compile a location path union. The UnionPathIterator itself may create
  536. * {@link com.sun.org.apache.xpath.internal.axes.LocPathIterator} children.
  537. *
  538. * @param opPos The current position in the m_opMap array.
  539. *
  540. * @return reference to {@link com.sun.org.apache.xpath.internal.axes.LocPathIterator} instance.
  541. *
  542. * @throws TransformerException if a error occurs creating the Expression.
  543. */
  544. protected Expression union(int opPos) throws TransformerException
  545. {
  546. locPathDepth++;
  547. try
  548. {
  549. return UnionPathIterator.createUnionIterator(this, opPos);
  550. }
  551. finally
  552. {
  553. locPathDepth--;
  554. }
  555. }
  556. private int locPathDepth = -1;
  557. /**
  558. * Get the level of the location path or union being constructed.
  559. * @return 0 if it is a top-level path.
  560. */
  561. public int getLocationPathDepth()
  562. {
  563. return locPathDepth;
  564. }
  565. /**
  566. * Compile a location path. The LocPathIterator itself may create
  567. * {@link com.sun.org.apache.xpath.internal.axes.AxesWalker} children.
  568. *
  569. * @param opPos The current position in the m_opMap array.
  570. *
  571. * @return reference to {@link com.sun.org.apache.xpath.internal.axes.LocPathIterator} instance.
  572. *
  573. * @throws TransformerException if a error occurs creating the Expression.
  574. */
  575. public Expression locationPath(int opPos) throws TransformerException
  576. {
  577. locPathDepth++;
  578. try
  579. {
  580. DTMIterator iter = WalkerFactory.newDTMIterator(this, opPos, (locPathDepth == 0));
  581. return (Expression)iter; // cast OK, I guess.
  582. }
  583. finally
  584. {
  585. locPathDepth--;
  586. }
  587. }
  588. /**
  589. * Compile a location step predicate expression.
  590. *
  591. * @param opPos The current position in the m_opMap array.
  592. *
  593. * @return the contained predicate expression.
  594. *
  595. * @throws TransformerException if a error occurs creating the Expression.
  596. */
  597. public Expression predicate(int opPos) throws TransformerException
  598. {
  599. return compile(opPos + 2);
  600. }
  601. /**
  602. * Compile an entire match pattern expression.
  603. *
  604. * @param opPos The current position in the m_opMap array.
  605. *
  606. * @return reference to {@link com.sun.org.apache.xpath.internal.patterns.UnionPattern} instance.
  607. *
  608. * @throws TransformerException if a error occurs creating the Expression.
  609. */
  610. protected Expression matchPattern(int opPos) throws TransformerException
  611. {
  612. locPathDepth++;
  613. try
  614. {
  615. // First, count...
  616. int nextOpPos = opPos;
  617. int i;
  618. for (i = 0; getOp(nextOpPos) == OpCodes.OP_LOCATIONPATHPATTERN; i++)
  619. {
  620. nextOpPos = getNextOpPos(nextOpPos);
  621. }
  622. if (i == 1)
  623. return compile(opPos);
  624. UnionPattern up = new UnionPattern();
  625. StepPattern[] patterns = new StepPattern[i];
  626. for (i = 0; getOp(opPos) == OpCodes.OP_LOCATIONPATHPATTERN; i++)
  627. {
  628. nextOpPos = getNextOpPos(opPos);
  629. patterns[i] = (StepPattern) compile(opPos);
  630. opPos = nextOpPos;
  631. }
  632. up.setPatterns(patterns);
  633. return up;
  634. }
  635. finally
  636. {
  637. locPathDepth--;
  638. }
  639. }
  640. /**
  641. * Compile a location match pattern unit expression.
  642. *
  643. * @param opPos The current position in the m_opMap array.
  644. *
  645. * @return reference to {@link com.sun.org.apache.xpath.internal.patterns.StepPattern} instance.
  646. *
  647. * @throws TransformerException if a error occurs creating the Expression.
  648. */
  649. public Expression locationPathPattern(int opPos)
  650. throws TransformerException
  651. {
  652. opPos = getFirstChildPos(opPos);
  653. return stepPattern(opPos, 0, null);
  654. }
  655. /**
  656. * Get a {@link org.w3c.dom.traversal.NodeFilter} bit set that tells what
  657. * to show for a given node test.
  658. *
  659. * @param opPos the op map position for the location step.
  660. *
  661. * @return {@link org.w3c.dom.traversal.NodeFilter} bit set that tells what
  662. * to show for a given node test.
  663. */
  664. public int getWhatToShow(int opPos)
  665. {
  666. int axesType = getOp(opPos);
  667. int testType = getOp(opPos + 3);
  668. // System.out.println("testType: "+testType);
  669. switch (testType)
  670. {
  671. case OpCodes.NODETYPE_COMMENT :
  672. return DTMFilter.SHOW_COMMENT;
  673. case OpCodes.NODETYPE_TEXT :
  674. // return DTMFilter.SHOW_TEXT | DTMFilter.SHOW_COMMENT;
  675. return DTMFilter.SHOW_TEXT | DTMFilter.SHOW_CDATA_SECTION ;
  676. case OpCodes.NODETYPE_PI :
  677. return DTMFilter.SHOW_PROCESSING_INSTRUCTION;
  678. case OpCodes.NODETYPE_NODE :
  679. // return DTMFilter.SHOW_ALL;
  680. switch (axesType)
  681. {
  682. case OpCodes.FROM_NAMESPACE:
  683. return DTMFilter.SHOW_NAMESPACE;
  684. case OpCodes.FROM_ATTRIBUTES :
  685. case OpCodes.MATCH_ATTRIBUTE :
  686. return DTMFilter.SHOW_ATTRIBUTE;
  687. case OpCodes.FROM_SELF:
  688. case OpCodes.FROM_ANCESTORS_OR_SELF:
  689. case OpCodes.FROM_DESCENDANTS_OR_SELF:
  690. return DTMFilter.SHOW_ALL;
  691. default:
  692. if (getOp(0) == OpCodes.OP_MATCHPATTERN)
  693. return ~DTMFilter.SHOW_ATTRIBUTE
  694. & ~DTMFilter.SHOW_DOCUMENT
  695. & ~DTMFilter.SHOW_DOCUMENT_FRAGMENT;
  696. else
  697. return ~DTMFilter.SHOW_ATTRIBUTE;
  698. }
  699. case OpCodes.NODETYPE_ROOT :
  700. return DTMFilter.SHOW_DOCUMENT | DTMFilter.SHOW_DOCUMENT_FRAGMENT;
  701. case OpCodes.NODETYPE_FUNCTEST :
  702. return NodeTest.SHOW_BYFUNCTION;
  703. case OpCodes.NODENAME :
  704. switch (axesType)
  705. {
  706. case OpCodes.FROM_NAMESPACE :
  707. return DTMFilter.SHOW_NAMESPACE;
  708. case OpCodes.FROM_ATTRIBUTES :
  709. case OpCodes.MATCH_ATTRIBUTE :
  710. return DTMFilter.SHOW_ATTRIBUTE;
  711. // break;
  712. case OpCodes.MATCH_ANY_ANCESTOR :
  713. case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
  714. return DTMFilter.SHOW_ELEMENT;
  715. // break;
  716. default :
  717. return DTMFilter.SHOW_ELEMENT;
  718. }
  719. default :
  720. // System.err.println("We should never reach here.");
  721. return DTMFilter.SHOW_ALL;
  722. }
  723. }
  724. private static final boolean DEBUG = false;
  725. /**
  726. * Compile a step pattern unit expression, used for both location paths
  727. * and match patterns.
  728. *
  729. * @param opPos The current position in the m_opMap array.
  730. * @param stepCount The number of steps to expect.
  731. * @param ancestorPattern The owning StepPattern, which may be null.
  732. *
  733. * @return reference to {@link com.sun.org.apache.xpath.internal.patterns.StepPattern} instance.
  734. *
  735. * @throws TransformerException if a error occurs creating the Expression.
  736. */
  737. protected StepPattern stepPattern(
  738. int opPos, int stepCount, StepPattern ancestorPattern)
  739. throws TransformerException
  740. {
  741. int startOpPos = opPos;
  742. int stepType = getOp(opPos);
  743. if (OpCodes.ENDOP == stepType)
  744. {
  745. return null;
  746. }
  747. boolean addMagicSelf = true;
  748. int endStep = getNextOpPos(opPos);
  749. // int nextStepType = getOpMap()[endStep];
  750. StepPattern pattern;
  751. // boolean isSimple = ((OpCodes.ENDOP == nextStepType) && (stepCount == 0));
  752. int argLen;
  753. switch (stepType)
  754. {
  755. case OpCodes.OP_FUNCTION :
  756. if(DEBUG)
  757. System.out.println("MATCH_FUNCTION: "+m_currentPattern);
  758. addMagicSelf = false;
  759. argLen = getOp(opPos + OpMap.MAPINDEX_LENGTH);
  760. pattern = new FunctionPattern(compileFunction(opPos), Axis.PARENT, Axis.CHILD);
  761. break;
  762. case OpCodes.FROM_ROOT :
  763. if(DEBUG)
  764. System.out.println("FROM_ROOT, "+m_currentPattern);
  765. addMagicSelf = false;
  766. argLen = getArgLengthOfStep(opPos);
  767. opPos = getFirstChildPosOfStep(opPos);
  768. pattern = new StepPattern(DTMFilter.SHOW_DOCUMENT |
  769. DTMFilter.SHOW_DOCUMENT_FRAGMENT,
  770. Axis.PARENT, Axis.CHILD);
  771. break;
  772. case OpCodes.MATCH_ATTRIBUTE :
  773. if(DEBUG)
  774. System.out.println("MATCH_ATTRIBUTE: "+getStepLocalName(startOpPos)+", "+m_currentPattern);
  775. argLen = getArgLengthOfStep(opPos);
  776. opPos = getFirstChildPosOfStep(opPos);
  777. pattern = new StepPattern(DTMFilter.SHOW_ATTRIBUTE,
  778. getStepNS(startOpPos),
  779. getStepLocalName(startOpPos),
  780. Axis.PARENT, Axis.ATTRIBUTE);
  781. break;
  782. case OpCodes.MATCH_ANY_ANCESTOR :
  783. if(DEBUG)
  784. System.out.println("MATCH_ANY_ANCESTOR: "+getStepLocalName(startOpPos)+", "+m_currentPattern);
  785. argLen = getArgLengthOfStep(opPos);
  786. opPos = getFirstChildPosOfStep(opPos);
  787. int what = getWhatToShow(startOpPos);
  788. // bit-o-hackery, but this code is due for the morgue anyway...
  789. if(0x00000500 == what)
  790. addMagicSelf = false;
  791. pattern = new StepPattern(getWhatToShow(startOpPos),
  792. getStepNS(startOpPos),
  793. getStepLocalName(startOpPos),
  794. Axis.ANCESTOR, Axis.CHILD);
  795. break;
  796. case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
  797. if(DEBUG)
  798. System.out.println("MATCH_IMMEDIATE_ANCESTOR: "+getStepLocalName(startOpPos)+", "+m_currentPattern);
  799. argLen = getArgLengthOfStep(opPos);
  800. opPos = getFirstChildPosOfStep(opPos);
  801. pattern = new StepPattern(getWhatToShow(startOpPos),
  802. getStepNS(startOpPos),
  803. getStepLocalName(startOpPos),
  804. Axis.PARENT, Axis.CHILD);
  805. break;
  806. default :
  807. error(XPATHErrorResources.ER_UNKNOWN_MATCH_OPERATION, null); //"unknown match operation!");
  808. return null;
  809. }
  810. pattern.setPredicates(getCompiledPredicates(opPos + argLen));
  811. if(null == ancestorPattern)
  812. {
  813. // This is the magic and invisible "." at the head of every
  814. // match pattern, and corresponds to the current node in the context
  815. // list, from where predicates are counted.
  816. // So, in order to calculate "foo[3]", it has to count from the
  817. // current node in the context list, so, from that current node,
  818. // the full pattern is really "self::node()/child::foo[3]". If you
  819. // translate this to a select pattern from the node being tested,
  820. // which is really how we're treating match patterns, it works out to
  821. // self::foo/parent::node[child::foo[3]]", or close enough.
  822. /* if(addMagicSelf && pattern.getPredicateCount() > 0)
  823. {
  824. StepPattern selfPattern = new StepPattern(DTMFilter.SHOW_ALL,
  825. Axis.PARENT, Axis.CHILD);
  826. // We need to keep the new nodetest from affecting the score...
  827. XNumber score = pattern.getStaticScore();
  828. pattern.setRelativePathPattern(selfPattern);
  829. pattern.setStaticScore(score);
  830. selfPattern.setStaticScore(score);
  831. }*/
  832. }
  833. else
  834. {
  835. // System.out.println("Setting "+ancestorPattern+" as relative to "+pattern);
  836. pattern.setRelativePathPattern(ancestorPattern);
  837. }
  838. StepPattern relativePathPattern = stepPattern(endStep, stepCount + 1,
  839. pattern);
  840. return (null != relativePathPattern) ? relativePathPattern : pattern;
  841. }
  842. /**
  843. * Compile a zero or more predicates for a given match pattern.
  844. *
  845. * @param opPos The position of the first predicate the m_opMap array.
  846. *
  847. * @return reference to array of {@link com.sun.org.apache.xpath.internal.Expression} instances.
  848. *
  849. * @throws TransformerException if a error occurs creating the Expression.
  850. */
  851. public Expression[] getCompiledPredicates(int opPos)
  852. throws TransformerException
  853. {
  854. int count = countPredicates(opPos);
  855. if (count > 0)
  856. {
  857. Expression[] predicates = new Expression[count];
  858. compilePredicates(opPos, predicates);
  859. return predicates;
  860. }
  861. return null;
  862. }
  863. /**
  864. * Count the number of predicates in the step.
  865. *
  866. * @param opPos The position of the first predicate the m_opMap array.
  867. *
  868. * @return The number of predicates for this step.
  869. *
  870. * @throws TransformerException if a error occurs creating the Expression.
  871. */
  872. public int countPredicates(int opPos) throws TransformerException
  873. {
  874. int count = 0;
  875. while (OpCodes.OP_PREDICATE == getOp(opPos))
  876. {
  877. count++;
  878. opPos = getNextOpPos(opPos);
  879. }
  880. return count;
  881. }
  882. /**
  883. * Compiles predicates in the step.
  884. *
  885. * @param opPos The position of the first predicate the m_opMap array.
  886. * @param predicates An empty pre-determined array of
  887. * {@link com.sun.org.apache.xpath.internal.Expression}s, that will be filled in.
  888. *
  889. * @throws TransformerException
  890. */
  891. private void compilePredicates(int opPos, Expression[] predicates)
  892. throws TransformerException
  893. {
  894. for (int i = 0; OpCodes.OP_PREDICATE == getOp(opPos); i++)
  895. {
  896. predicates[i] = predicate(opPos);
  897. opPos = getNextOpPos(opPos);
  898. }
  899. }
  900. /**
  901. * Compile a built-in XPath function.
  902. *
  903. * @param opPos The current position in the m_opMap array.
  904. *
  905. * @return reference to {@link com.sun.org.apache.xpath.internal.functions.Function} instance.
  906. *
  907. * @throws TransformerException if a error occurs creating the Expression.
  908. */
  909. Expression compileFunction(int opPos) throws TransformerException
  910. {
  911. int endFunc = opPos + getOp(opPos + 1) - 1;
  912. opPos = getFirstChildPos(opPos);
  913. int funcID = getOp(opPos);
  914. opPos++;
  915. if (-1 != funcID)
  916. {
  917. Function func = FunctionTable.getFunction(funcID);
  918. func.postCompileStep(this);
  919. try
  920. {
  921. int i = 0;
  922. for (int p = opPos; p < endFunc; p = getNextOpPos(p), i++)
  923. {
  924. // System.out.println("argPos: "+ p);
  925. // System.out.println("argCode: "+ m_opMap[p]);
  926. func.setArg(compile(p), i);
  927. }
  928. func.checkNumberArgs(i);
  929. }
  930. catch (WrongNumberArgsException wnae)
  931. {
  932. java.lang.String name = FunctionTable.getFunctionName(funcID);
  933. m_errorHandler.fatalError( new TransformerException(
  934. XSLMessages.createXPATHMessage(XPATHErrorResources.ER_ONLY_ALLOWS,
  935. new Object[]{name, wnae.getMessage()}), m_locator));
  936. //"name + " only allows " + wnae.getMessage() + " arguments", m_locator));
  937. }
  938. return func;
  939. }
  940. else
  941. {
  942. error(XPATHErrorResources.ER_FUNCTION_TOKEN_NOT_FOUND, null); //"function token not found.");
  943. return null;
  944. }
  945. }
  946. // The current id for extension functions.
  947. private static long s_nextMethodId = 0;
  948. /**
  949. * Get the next available method id
  950. */
  951. synchronized private long getNextMethodId()
  952. {
  953. if (s_nextMethodId == Long.MAX_VALUE)
  954. s_nextMethodId = 0;
  955. return s_nextMethodId++;
  956. }
  957. /**
  958. * Compile an extension function.
  959. *
  960. * @param opPos The current position in the m_opMap array.
  961. *
  962. * @return reference to {@link com.sun.org.apache.xpath.internal.functions.FuncExtFunction} instance.
  963. *
  964. * @throws TransformerException if a error occurs creating the Expression.
  965. */
  966. private Expression compileExtension(int opPos)
  967. throws TransformerException
  968. {
  969. int endExtFunc = opPos + getOp(opPos + 1) - 1;
  970. opPos = getFirstChildPos(opPos);
  971. java.lang.String ns = (java.lang.String) getTokenQueue().elementAt(getOp(opPos));
  972. opPos++;
  973. java.lang.String funcName =
  974. (java.lang.String) getTokenQueue().elementAt(getOp(opPos));
  975. opPos++;
  976. // We create a method key to uniquely identify this function so that we
  977. // can cache the object needed to invoke it. This way, we only pay the
  978. // reflection overhead on the first call.
  979. Function extension = new FuncExtFunction(ns, funcName, String.valueOf(getNextMethodId()));
  980. try
  981. {
  982. int i = 0;
  983. while (opPos < endExtFunc)
  984. {
  985. int nextOpPos = getNextOpPos(opPos);
  986. extension.setArg(this.compile(opPos), i);
  987. opPos = nextOpPos;
  988. i++;
  989. }
  990. }
  991. catch (WrongNumberArgsException wnae)
  992. {
  993. ; // should never happen
  994. }
  995. return extension;
  996. }
  997. /**
  998. * Warn the user of an problem.
  999. *
  1000. * @param msg An error msgkey that corresponds to one of the constants found
  1001. * in {@link com.sun.org.apache.xpath.internal.res.XPATHErrorResources}, which is
  1002. * a key for a format string.
  1003. * @param args An array of arguments represented in the format string, which
  1004. * may be null.
  1005. *
  1006. * @throws TransformerException if the current ErrorListoner determines to
  1007. * throw an exception.
  1008. */
  1009. public void warn(String msg, Object[] args) throws TransformerException
  1010. {
  1011. java.lang.String fmsg = XSLMessages.createXPATHWarning(msg, args);
  1012. if (null != m_errorHandler)
  1013. {
  1014. m_errorHandler.warning(new TransformerException(fmsg, m_locator));
  1015. }
  1016. else
  1017. {
  1018. System.out.println(fmsg
  1019. +"; file "+m_locator.getSystemId()
  1020. +"; line "+m_locator.getLineNumber()
  1021. +"; column "+m_locator.getColumnNumber());
  1022. }
  1023. }
  1024. /**
  1025. * Tell the user of an assertion error, and probably throw an
  1026. * exception.
  1027. *
  1028. * @param b If false, a runtime exception will be thrown.
  1029. * @param msg The assertion message, which should be informative.
  1030. *
  1031. * @throws RuntimeException if the b argument is false.
  1032. */
  1033. public void assertion(boolean b, java.lang.String msg)
  1034. {
  1035. if (!b)
  1036. {
  1037. java.lang.String fMsg = XSLMessages.createXPATHMessage(
  1038. XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION,
  1039. new Object[]{ msg });
  1040. throw new RuntimeException(fMsg);
  1041. }
  1042. }
  1043. /**
  1044. * Tell the user of an error, and probably throw an
  1045. * exception.
  1046. *
  1047. * @param msg An error msgkey that corresponds to one of the constants found
  1048. * in {@link com.sun.org.apache.xpath.internal.res.XPATHErrorResources}, which is
  1049. * a key for a format string.
  1050. * @param args An array of arguments represented in the format string, which
  1051. * may be null.
  1052. *
  1053. * @throws TransformerException if the current ErrorListoner determines to
  1054. * throw an exception.
  1055. */
  1056. public void error(String msg, Object[] args) throws TransformerException
  1057. {
  1058. java.lang.String fmsg = XSLMessages.createXPATHMessage(msg, args);
  1059. if (null != m_errorHandler)
  1060. {
  1061. m_errorHandler.fatalError(new TransformerException(fmsg, m_locator));
  1062. }
  1063. else
  1064. {
  1065. // System.out.println(te.getMessage()
  1066. // +"; file "+te.getSystemId()
  1067. // +"; line "+te.getLineNumber()
  1068. // +"; column "+te.getColumnNumber());
  1069. throw new TransformerException(fmsg, (SAXSourceLocator)m_locator);
  1070. }
  1071. }
  1072. /**
  1073. * The current prefixResolver for the execution context.
  1074. */
  1075. private PrefixResolver m_currentPrefixResolver = null;
  1076. /**
  1077. * Get the current namespace context for the xpath.
  1078. *
  1079. * @return The current prefix resolver, *may* be null, though hopefully not.
  1080. */
  1081. public PrefixResolver getNamespaceContext()
  1082. {
  1083. return m_currentPrefixResolver;
  1084. }
  1085. /**
  1086. * Set the current namespace context for the xpath.
  1087. *
  1088. * @param pr The resolver for prefixes in the XPath expression.
  1089. */
  1090. public void setNamespaceContext(PrefixResolver pr)
  1091. {
  1092. m_currentPrefixResolver = pr;
  1093. }
  1094. /** The error listener where errors will be sent. If this is null, errors
  1095. * and warnings will be sent to System.err. May be null. */
  1096. ErrorListener m_errorHandler;
  1097. /** The source locator for the expression being compiled. May be null. */
  1098. SourceLocator m_locator;
  1099. }