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    */
Compiler(ErrorListener errorHandler, SourceLocator locator, FunctionTable fTable)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    */
Compiler()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    */
compile(int opPos)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    */
compileOperation(Operation operation, int opPos)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    */
compileUnary(UnaryOperation unary, int opPos)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    */
or(int opPos)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    */
and(int opPos)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    */
notequals(int opPos)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    */
equals(int opPos)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    */
lte(int opPos)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    */
lt(int opPos)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    */
gte(int opPos)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    */
gt(int opPos)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    */
plus(int opPos)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    */
minus(int opPos)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    */
mult(int opPos)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    */
div(int opPos)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    */
mod(int opPos)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    */
neg(int opPos)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    */
string(int opPos)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    */
bool(int opPos)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    */
number(int opPos)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    */
literal(int opPos)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    */
numberlit(int opPos)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    */
variable(int opPos)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    */
group(int opPos)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    */
arg(int opPos)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    */
union(int opPos)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    */
getLocationPathDepth()618   public int getLocationPathDepth()
619   {
620     return locPathDepth;
621   }
622 
623   /**
624    * Get the function table
625    */
getFunctionTable()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    */
locationPath(int opPos)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    */
predicate(int opPos)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    */
matchPattern(int opPos)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    */
locationPathPattern(int opPos)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    */
getWhatToShow(int opPos)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    */
stepPattern( int opPos, int stepCount, StepPattern ancestorPattern)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    */
getCompiledPredicates(int opPos)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    */
countPredicates(int opPos)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    */
compilePredicates(int opPos, Expression[] predicates)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    */
compileFunction(int opPos)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    */
getNextMethodId()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    */
compileExtension(int opPos)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    */
warn(String msg, Object[] args)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    */
assertion(boolean b, java.lang.String msg)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    */
error(String msg, Object[] args)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    */
getNamespaceContext()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    */
setNamespaceContext(PrefixResolver pr)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