001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: Compiler.java 468655 2006-10-28 07:12:06Z minchau $
020     */
021    package org.apache.xpath.compiler;
022    
023    import javax.xml.transform.ErrorListener;
024    import javax.xml.transform.SourceLocator;
025    import javax.xml.transform.TransformerException;
026    
027    import org.apache.xalan.res.XSLMessages;
028    import org.apache.xml.dtm.Axis;
029    import org.apache.xml.dtm.DTMFilter;
030    import org.apache.xml.dtm.DTMIterator;
031    import org.apache.xml.utils.PrefixResolver;
032    import org.apache.xml.utils.QName;
033    import org.apache.xml.utils.SAXSourceLocator;
034    import org.apache.xpath.Expression;
035    import org.apache.xpath.axes.UnionPathIterator;
036    import org.apache.xpath.axes.WalkerFactory;
037    import org.apache.xpath.functions.FuncExtFunction;
038    import org.apache.xpath.functions.FuncExtFunctionAvailable;
039    import org.apache.xpath.functions.Function;
040    import org.apache.xpath.functions.WrongNumberArgsException;
041    import org.apache.xpath.objects.XNumber;
042    import org.apache.xpath.objects.XString;
043    import org.apache.xpath.operations.And;
044    import org.apache.xpath.operations.Div;
045    import org.apache.xpath.operations.Equals;
046    import org.apache.xpath.operations.Gt;
047    import org.apache.xpath.operations.Gte;
048    import org.apache.xpath.operations.Lt;
049    import org.apache.xpath.operations.Lte;
050    import org.apache.xpath.operations.Minus;
051    import org.apache.xpath.operations.Mod;
052    import org.apache.xpath.operations.Mult;
053    import org.apache.xpath.operations.Neg;
054    import org.apache.xpath.operations.NotEquals;
055    import org.apache.xpath.operations.Operation;
056    import org.apache.xpath.operations.Or;
057    import org.apache.xpath.operations.Plus;
058    import org.apache.xpath.operations.UnaryOperation;
059    import org.apache.xpath.operations.Variable;
060    import org.apache.xpath.patterns.FunctionPattern;
061    import org.apache.xpath.patterns.NodeTest;
062    import org.apache.xpath.patterns.StepPattern;
063    import org.apache.xpath.patterns.UnionPattern;
064    import org.apache.xpath.res.XPATHErrorResources;
065    
066    /**
067     * An instance of this class compiles an XPath string expression into 
068     * a Expression object.  This class compiles the string into a sequence 
069     * of operation codes (op map) and then builds from that into an Expression 
070     * tree.
071     * @xsl.usage advanced
072     */
073    public class Compiler extends OpMap
074    {
075    
076      /**
077       * Construct a Compiler object with a specific ErrorListener and 
078       * SourceLocator where the expression is located.
079       *
080       * @param errorHandler Error listener where messages will be sent, or null 
081       *                     if messages should be sent to System err.
082       * @param locator The location object where the expression lives, which 
083       *                may be null, but which, if not null, must be valid over 
084       *                the long haul, in other words, it will not be cloned.
085       * @param fTable  The FunctionTable object where the xpath build-in 
086       *                functions are stored.
087       */
088      public Compiler(ErrorListener errorHandler, SourceLocator locator, 
089                FunctionTable fTable)
090      {
091        m_errorHandler = errorHandler;
092        m_locator = locator;
093        m_functionTable = fTable;
094      }
095    
096      /**
097       * Construct a Compiler instance that has a null error listener and a 
098       * null source locator.
099       */
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      
807    private 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    }