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