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