Home | History | Annotate | Download | only in compiler
      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  */
     21 package org.apache.xpath.compiler;
     22 
     23 import javax.xml.transform.ErrorListener;
     24 import javax.xml.transform.SourceLocator;
     25 import javax.xml.transform.TransformerException;
     26 
     27 import org.apache.xalan.res.XSLMessages;
     28 import org.apache.xml.dtm.Axis;
     29 import org.apache.xml.dtm.DTMFilter;
     30 import org.apache.xml.dtm.DTMIterator;
     31 import org.apache.xml.utils.PrefixResolver;
     32 import org.apache.xml.utils.QName;
     33 import org.apache.xml.utils.SAXSourceLocator;
     34 import org.apache.xpath.Expression;
     35 import org.apache.xpath.axes.UnionPathIterator;
     36 import org.apache.xpath.axes.WalkerFactory;
     37 import org.apache.xpath.functions.FuncExtFunction;
     38 import org.apache.xpath.functions.FuncExtFunctionAvailable;
     39 import org.apache.xpath.functions.Function;
     40 import org.apache.xpath.functions.WrongNumberArgsException;
     41 import org.apache.xpath.objects.XNumber;
     42 import org.apache.xpath.objects.XString;
     43 import org.apache.xpath.operations.And;
     44 import org.apache.xpath.operations.Div;
     45 import org.apache.xpath.operations.Equals;
     46 import org.apache.xpath.operations.Gt;
     47 import org.apache.xpath.operations.Gte;
     48 import org.apache.xpath.operations.Lt;
     49 import org.apache.xpath.operations.Lte;
     50 import org.apache.xpath.operations.Minus;
     51 import org.apache.xpath.operations.Mod;
     52 import org.apache.xpath.operations.Mult;
     53 import org.apache.xpath.operations.Neg;
     54 import org.apache.xpath.operations.NotEquals;
     55 import org.apache.xpath.operations.Operation;
     56 import org.apache.xpath.operations.Or;
     57 import org.apache.xpath.operations.Plus;
     58 import org.apache.xpath.operations.UnaryOperation;
     59 import org.apache.xpath.operations.Variable;
     60 import org.apache.xpath.patterns.FunctionPattern;
     61 import org.apache.xpath.patterns.NodeTest;
     62 import org.apache.xpath.patterns.StepPattern;
     63 import org.apache.xpath.patterns.UnionPattern;
     64 import 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  */
     73 public 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 
    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 }
   1269