KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xpath > compiler > Compiler


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: Compiler.java,v 1.36 2004/02/17 04:32:49 minchau Exp $
18  */

19 package org.apache.xpath.compiler;
20
21 import javax.xml.transform.ErrorListener JavaDoc;
22 import javax.xml.transform.SourceLocator JavaDoc;
23 import javax.xml.transform.TransformerException JavaDoc;
24
25 import org.apache.xalan.res.XSLMessages;
26 import org.apache.xml.dtm.Axis;
27 import org.apache.xml.dtm.DTMFilter;
28 import org.apache.xml.dtm.DTMIterator;
29 import org.apache.xml.utils.PrefixResolver;
30 import org.apache.xml.utils.QName;
31 import org.apache.xml.utils.SAXSourceLocator;
32 import org.apache.xpath.Expression;
33 import org.apache.xpath.axes.UnionPathIterator;
34 import org.apache.xpath.axes.WalkerFactory;
35 import org.apache.xpath.functions.FuncExtFunction;
36 import org.apache.xpath.functions.Function;
37 import org.apache.xpath.functions.WrongNumberArgsException;
38 import org.apache.xpath.objects.XNumber;
39 import org.apache.xpath.objects.XString;
40 import org.apache.xpath.operations.And;
41 import org.apache.xpath.operations.Div;
42 import org.apache.xpath.operations.Equals;
43 import org.apache.xpath.operations.Gt;
44 import org.apache.xpath.operations.Gte;
45 import org.apache.xpath.operations.Lt;
46 import org.apache.xpath.operations.Lte;
47 import org.apache.xpath.operations.Minus;
48 import org.apache.xpath.operations.Mod;
49 import org.apache.xpath.operations.Mult;
50 import org.apache.xpath.operations.Neg;
51 import org.apache.xpath.operations.NotEquals;
52 import org.apache.xpath.operations.Operation;
53 import org.apache.xpath.operations.Or;
54 import org.apache.xpath.operations.Plus;
55 import org.apache.xpath.operations.UnaryOperation;
56 import org.apache.xpath.operations.Variable;
57 import org.apache.xpath.patterns.FunctionPattern;
58 import org.apache.xpath.patterns.NodeTest;
59 import org.apache.xpath.patterns.StepPattern;
60 import org.apache.xpath.patterns.UnionPattern;
61 import org.apache.xpath.res.XPATHErrorResources;
62
63 /**
64  * An instance of this class compiles an XPath string expression into
65  * a Expression object. This class compiles the string into a sequence
66  * of operation codes (op map) and then builds from that into an Expression
67  * tree.
68  * @xsl.usage advanced
69  */

70 public class Compiler extends OpMap
71 {
72
73   /**
74    * Construct a Compiler object with a specific ErrorListener and
75    * SourceLocator where the expression is located.
76    *
77    * @param errorHandler Error listener where messages will be sent, or null
78    * if messages should be sent to System err.
79    * @param locator The location object where the expression lives, which
80    * may be null, but which, if not null, must be valid over
81    * the long haul, in other words, it will not be cloned.
82    */

83   public Compiler(ErrorListener JavaDoc errorHandler, SourceLocator JavaDoc locator)
84   {
85     m_errorHandler = errorHandler;
86     m_locator = locator;
87   }
88
89   /**
90    * Construct a Compiler instance that has a null error listener and a
91    * null source locator.
92    */

93   public Compiler()
94   {
95     m_errorHandler = null;
96     m_locator = null;
97   }
98
99   /**
100    * Execute the XPath object from a given opcode position.
101    * @param xctxt The execution context.
102    * @param context The current source tree context node.
103    * @param opPos The current position in the xpath.m_opMap array.
104    * @param callback Interface that implements the processLocatedNode method.
105    * @param callbackInfo Object that will be passed to the processLocatedNode method.
106    * @return The result of the XPath.
107    *
108    * @throws TransformerException if there is a syntax or other error.
109    * @xsl.usage advanced
110    */

111   public Expression compile(int opPos) throws TransformerException JavaDoc
112   {
113
114     int op = getOp(opPos);
115
116     Expression expr = null;
117     // System.out.println(getPatternString()+"op: "+op);
118
switch (op)
119     {
120     case OpCodes.OP_XPATH :
121       expr = compile(opPos + 2); break;
122     case OpCodes.OP_OR :
123       expr = or(opPos); break;
124     case OpCodes.OP_AND :
125       expr = and(opPos); break;
126     case OpCodes.OP_NOTEQUALS :
127       expr = notequals(opPos); break;
128     case OpCodes.OP_EQUALS :
129       expr = equals(opPos); break;
130     case OpCodes.OP_LTE :
131       expr = lte(opPos); break;
132     case OpCodes.OP_LT :
133       expr = lt(opPos); break;
134     case OpCodes.OP_GTE :
135       expr = gte(opPos); break;
136     case OpCodes.OP_GT :
137       expr = gt(opPos); break;
138     case OpCodes.OP_PLUS :
139       expr = plus(opPos); break;
140     case OpCodes.OP_MINUS :
141       expr = minus(opPos); break;
142     case OpCodes.OP_MULT :
143       expr = mult(opPos); break;
144     case OpCodes.OP_DIV :
145       expr = div(opPos); break;
146     case OpCodes.OP_MOD :
147       expr = mod(opPos); break;
148 // case OpCodes.OP_QUO :
149
// expr = quo(opPos); break;
150
case OpCodes.OP_NEG :
151       expr = neg(opPos); break;
152     case OpCodes.OP_STRING :
153       expr = string(opPos); break;
154     case OpCodes.OP_BOOL :
155       expr = bool(opPos); break;
156     case OpCodes.OP_NUMBER :
157       expr = number(opPos); break;
158     case OpCodes.OP_UNION :
159       expr = union(opPos); break;
160     case OpCodes.OP_LITERAL :
161       expr = literal(opPos); break;
162     case OpCodes.OP_VARIABLE :
163       expr = variable(opPos); break;
164     case OpCodes.OP_GROUP :
165       expr = group(opPos); break;
166     case OpCodes.OP_NUMBERLIT :
167       expr = numberlit(opPos); break;
168     case OpCodes.OP_ARGUMENT :
169       expr = arg(opPos); break;
170     case OpCodes.OP_EXTFUNCTION :
171       expr = compileExtension(opPos); break;
172     case OpCodes.OP_FUNCTION :
173       expr = compileFunction(opPos); break;
174     case OpCodes.OP_LOCATIONPATH :
175       expr = locationPath(opPos); break;
176     case OpCodes.OP_PREDICATE :
177       expr = null; break; // should never hit this here.
178
case OpCodes.OP_MATCHPATTERN :
179       expr = matchPattern(opPos + 2); break;
180     case OpCodes.OP_LOCATIONPATHPATTERN :
181       expr = locationPathPattern(opPos); break;
182     case OpCodes.OP_QUO:
183       error(XPATHErrorResources.ER_UNKNOWN_OPCODE,
184             new Object JavaDoc[]{ "quo" }); //"ERROR! Unknown op code: "+m_opMap[opPos]);
185
break;
186     default :
187       error(XPATHErrorResources.ER_UNKNOWN_OPCODE,
188             new Object JavaDoc[]{ Integer.toString(getOp(opPos)) }); //"ERROR! Unknown op code: "+m_opMap[opPos]);
189
}
190 // if(null != expr)
191
// expr.setSourceLocator(m_locator);
192

193     return expr;
194   }
195
196   /**
197    * Bottle-neck compilation of an operation with left and right operands.
198    *
199    * @param operation non-null reference to parent operation.
200    * @param opPos The op map position of the parent operation.
201    *
202    * @return reference to {@link org.apache.xpath.operations.Operation} instance.
203    *
204    * @throws TransformerException if there is a syntax or other error.
205    */

206   private Expression compileOperation(Operation operation, int opPos)
207           throws TransformerException JavaDoc
208   {
209
210     int leftPos = getFirstChildPos(opPos);
211     int rightPos = getNextOpPos(leftPos);
212
213     operation.setLeftRight(compile(leftPos), compile(rightPos));
214
215     return operation;
216   }
217
218   /**
219    * Bottle-neck compilation of a unary operation.
220    *
221    * @param unary The parent unary operation.
222    * @param opPos The position in the op map of the parent operation.
223    *
224    * @return The unary argument.
225    *
226    * @throws TransformerException if syntax or other error occurs.
227    */

228   private Expression compileUnary(UnaryOperation unary, int opPos)
229           throws TransformerException JavaDoc
230   {
231
232     int rightPos = getFirstChildPos(opPos);
233
234     unary.setRight(compile(rightPos));
235
236     return unary;
237   }
238
239   /**
240    * Compile an 'or' operation.
241    *
242    * @param opPos The current position in the m_opMap array.
243    *
244    * @return reference to {@link org.apache.xpath.operations.Or} instance.
245    *
246    * @throws TransformerException if a error occurs creating the Expression.
247    */

248   protected Expression or(int opPos) throws TransformerException JavaDoc
249   {
250     return compileOperation(new Or(), opPos);
251   }
252
253   /**
254    * Compile an 'and' operation.
255    *
256    * @param opPos The current position in the m_opMap array.
257    *
258    * @return reference to {@link org.apache.xpath.operations.And} instance.
259    *
260    * @throws TransformerException if a error occurs creating the Expression.
261    */

262   protected Expression and(int opPos) throws TransformerException JavaDoc
263   {
264     return compileOperation(new And(), opPos);
265   }
266
267   /**
268    * Compile a '!=' operation.
269    *
270    * @param opPos The current position in the m_opMap array.
271    *
272    * @return reference to {@link org.apache.xpath.operations.NotEquals} instance.
273    *
274    * @throws TransformerException if a error occurs creating the Expression.
275    */

276   protected Expression notequals(int opPos) throws TransformerException JavaDoc
277   {
278     return compileOperation(new NotEquals(), opPos);
279   }
280
281   /**
282    * Compile a '=' operation.
283    *
284    * @param opPos The current position in the m_opMap array.
285    *
286    * @return reference to {@link org.apache.xpath.operations.Equals} instance.
287    *
288    * @throws TransformerException if a error occurs creating the Expression.
289    */

290   protected Expression equals(int opPos) throws TransformerException JavaDoc
291   {
292     return compileOperation(new Equals(), opPos);
293   }
294
295   /**
296    * Compile a '<=' operation.
297    *
298    * @param opPos The current position in the m_opMap array.
299    *
300    * @return reference to {@link org.apache.xpath.operations.Lte} instance.
301    *
302    * @throws TransformerException if a error occurs creating the Expression.
303    */

304   protected Expression lte(int opPos) throws TransformerException JavaDoc
305   {
306     return compileOperation(new Lte(), opPos);
307   }
308
309   /**
310    * Compile a '<' operation.
311    *
312    * @param opPos The current position in the m_opMap array.
313    *
314    * @return reference to {@link org.apache.xpath.operations.Lt} instance.
315    *
316    * @throws TransformerException if a error occurs creating the Expression.
317    */

318   protected Expression lt(int opPos) throws TransformerException JavaDoc
319   {
320     return compileOperation(new Lt(), opPos);
321   }
322
323   /**
324    * Compile a '>=' operation.
325    *
326    * @param opPos The current position in the m_opMap array.
327    *
328    * @return reference to {@link org.apache.xpath.operations.Gte} instance.
329    *
330    * @throws TransformerException if a error occurs creating the Expression.
331    */

332   protected Expression gte(int opPos) throws TransformerException JavaDoc
333   {
334     return compileOperation(new Gte(), opPos);
335   }
336
337   /**
338    * Compile a '>' operation.
339    *
340    * @param opPos The current position in the m_opMap array.
341    *
342    * @return reference to {@link org.apache.xpath.operations.Gt} instance.
343    *
344    * @throws TransformerException if a error occurs creating the Expression.
345    */

346   protected Expression gt(int opPos) throws TransformerException JavaDoc
347   {
348     return compileOperation(new Gt(), opPos);
349   }
350
351   /**
352    * Compile a '+' operation.
353    *
354    * @param opPos The current position in the m_opMap array.
355    *
356    * @return reference to {@link org.apache.xpath.operations.Plus} instance.
357    *
358    * @throws TransformerException if a error occurs creating the Expression.
359    */

360   protected Expression plus(int opPos) throws TransformerException JavaDoc
361   {
362     return compileOperation(new Plus(), opPos);
363   }
364
365   /**
366    * Compile a '-' operation.
367    *
368    * @param opPos The current position in the m_opMap array.
369    *
370    * @return reference to {@link org.apache.xpath.operations.Minus} instance.
371    *
372    * @throws TransformerException if a error occurs creating the Expression.
373    */

374   protected Expression minus(int opPos) throws TransformerException JavaDoc
375   {
376     return compileOperation(new Minus(), opPos);
377   }
378
379   /**
380    * Compile a '*' operation.
381    *
382    * @param opPos The current position in the m_opMap array.
383    *
384    * @return reference to {@link org.apache.xpath.operations.Mult} instance.
385    *
386    * @throws TransformerException if a error occurs creating the Expression.
387    */

388   protected Expression mult(int opPos) throws TransformerException JavaDoc
389   {
390     return compileOperation(new Mult(), opPos);
391   }
392
393   /**
394    * Compile a 'div' operation.
395    *
396    * @param opPos The current position in the m_opMap array.
397    *
398    * @return reference to {@link org.apache.xpath.operations.Div} instance.
399    *
400    * @throws TransformerException if a error occurs creating the Expression.
401    */

402   protected Expression div(int opPos) throws TransformerException JavaDoc
403   {
404     return compileOperation(new Div(), opPos);
405   }
406
407   /**
408    * Compile a 'mod' operation.
409    *
410    * @param opPos The current position in the m_opMap array.
411    *
412    * @return reference to {@link org.apache.xpath.operations.Mod} instance.
413    *
414    * @throws TransformerException if a error occurs creating the Expression.
415    */

416   protected Expression mod(int opPos) throws TransformerException JavaDoc
417   {
418     return compileOperation(new Mod(), opPos);
419   }
420
421   /*
422    * Compile a 'quo' operation.
423    *
424    * @param opPos The current position in the m_opMap array.
425    *
426    * @return reference to {@link org.apache.xpath.operations.Quo} instance.
427    *
428    * @throws TransformerException if a error occurs creating the Expression.
429    */

430 // protected Expression quo(int opPos) throws TransformerException
431
// {
432
// return compileOperation(new Quo(), opPos);
433
// }
434

435   /**
436    * Compile a unary '-' operation.
437    *
438    * @param opPos The current position in the m_opMap array.
439    *
440    * @return reference to {@link org.apache.xpath.operations.Neg} instance.
441    *
442    * @throws TransformerException if a error occurs creating the Expression.
443    */

444   protected Expression neg(int opPos) throws TransformerException JavaDoc
445   {
446     return compileUnary(new Neg(), opPos);
447   }
448
449   /**
450    * Compile a 'string(...)' operation.
451    *
452    * @param opPos The current position in the m_opMap array.
453    *
454    * @return reference to {@link org.apache.xpath.operations.String} instance.
455    *
456    * @throws TransformerException if a error occurs creating the Expression.
457    */

458   protected Expression string(int opPos) throws TransformerException JavaDoc
459   {
460     return compileUnary(new org.apache.xpath.operations.String(), opPos);
461   }
462
463   /**
464    * Compile a 'boolean(...)' operation.
465    *
466    * @param opPos The current position in the m_opMap array.
467    *
468    * @return reference to {@link org.apache.xpath.operations.Bool} instance.
469    *
470    * @throws TransformerException if a error occurs creating the Expression.
471    */

472   protected Expression bool(int opPos) throws TransformerException JavaDoc
473   {
474     return compileUnary(new org.apache.xpath.operations.Bool(), opPos);
475   }
476
477   /**
478    * Compile a 'number(...)' operation.
479    *
480    * @param opPos The current position in the m_opMap array.
481    *
482    * @return reference to {@link org.apache.xpath.operations.Number} instance.
483    *
484    * @throws TransformerException if a error occurs creating the Expression.
485    */

486   protected Expression number(int opPos) throws TransformerException JavaDoc
487   {
488     return compileUnary(new org.apache.xpath.operations.Number(), opPos);
489   }
490
491   /**
492    * Compile a literal string value.
493    *
494    * @param opPos The current position in the m_opMap array.
495    *
496    * @return reference to {@link org.apache.xpath.objects.XString} instance.
497    *
498    * @throws TransformerException if a error occurs creating the Expression.
499    */

500   protected Expression literal(int opPos)
501   {
502
503     opPos = getFirstChildPos(opPos);
504
505     return (XString) getTokenQueue().elementAt(getOp(opPos));
506   }
507
508   /**
509    * Compile a literal number value.
510    *
511    * @param opPos The current position in the m_opMap array.
512    *
513    * @return reference to {@link org.apache.xpath.objects.XNumber} instance.
514    *
515    * @throws TransformerException if a error occurs creating the Expression.
516    */

517   protected Expression numberlit(int opPos)
518   {
519
520     opPos = getFirstChildPos(opPos);
521
522     return (XNumber) getTokenQueue().elementAt(getOp(opPos));
523   }
524
525   /**
526    * Compile a variable reference.
527    *
528    * @param opPos The current position in the m_opMap array.
529    *
530    * @return reference to {@link org.apache.xpath.operations.Variable} instance.
531    *
532    * @throws TransformerException if a error occurs creating the Expression.
533    */

534   protected Expression variable(int opPos) throws TransformerException JavaDoc
535   {
536
537     Variable var = new Variable();
538
539     opPos = getFirstChildPos(opPos);
540
541     int nsPos = getOp(opPos);
542     java.lang.String JavaDoc namespace
543       = (OpCodes.EMPTY == nsPos) ? null
544                                    : (java.lang.String JavaDoc) getTokenQueue().elementAt(nsPos);
545     java.lang.String JavaDoc localname
546       = (java.lang.String JavaDoc) getTokenQueue().elementAt(getOp(opPos+1));
547     QName qname = new QName(namespace, localname);
548
549     var.setQName(qname);
550
551     return var;
552   }
553
554   /**
555    * Compile an expression group.
556    *
557    * @param opPos The current position in the m_opMap array.
558    *
559    * @return reference to the contained expression.
560    *
561    * @throws TransformerException if a error occurs creating the Expression.
562    */

563   protected Expression group(int opPos) throws TransformerException JavaDoc
564   {
565
566     // no-op
567
return compile(opPos + 2);
568   }
569
570   /**
571    * Compile a function argument.
572    *
573    * @param opPos The current position in the m_opMap array.
574    *
575    * @return reference to the argument expression.
576    *
577    * @throws TransformerException if a error occurs creating the Expression.
578    */

579   protected Expression arg(int opPos) throws TransformerException JavaDoc
580   {
581
582     // no-op
583
return compile(opPos + 2);
584   }
585
586   /**
587    * Compile a location path union. The UnionPathIterator itself may create
588    * {@link org.apache.xpath.axes.LocPathIterator} children.
589    *
590    * @param opPos The current position in the m_opMap array.
591    *
592    * @return reference to {@link org.apache.xpath.axes.LocPathIterator} instance.
593    *
594    * @throws TransformerException if a error occurs creating the Expression.
595    */

596   protected Expression union(int opPos) throws TransformerException JavaDoc
597   {
598     locPathDepth++;
599     try
600     {
601       return UnionPathIterator.createUnionIterator(this, opPos);
602     }
603     finally
604     {
605       locPathDepth--;
606     }
607   }
608   
609   private int locPathDepth = -1;
610   
611   /**
612    * Get the level of the location path or union being constructed.
613    * @return 0 if it is a top-level path.
614    */

615   public int getLocationPathDepth()
616   {
617     return locPathDepth;
618   }
619
620   /**
621    * Compile a location path. The LocPathIterator itself may create
622    * {@link org.apache.xpath.axes.AxesWalker} children.
623    *
624    * @param opPos The current position in the m_opMap array.
625    *
626    * @return reference to {@link org.apache.xpath.axes.LocPathIterator} instance.
627    *
628    * @throws TransformerException if a error occurs creating the Expression.
629    */

630   public Expression locationPath(int opPos) throws TransformerException JavaDoc
631   {
632     locPathDepth++;
633     try
634     {
635       DTMIterator iter = WalkerFactory.newDTMIterator(this, opPos, (locPathDepth == 0));
636       return (Expression)iter; // cast OK, I guess.
637
}
638     finally
639     {
640       locPathDepth--;
641     }
642   }
643
644   /**
645    * Compile a location step predicate expression.
646    *
647    * @param opPos The current position in the m_opMap array.
648    *
649    * @return the contained predicate expression.
650    *
651    * @throws TransformerException if a error occurs creating the Expression.
652    */

653   public Expression predicate(int opPos) throws TransformerException JavaDoc
654   {
655     return compile(opPos + 2);
656   }
657
658   /**
659    * Compile an entire match pattern expression.
660    *
661    * @param opPos The current position in the m_opMap array.
662    *
663    * @return reference to {@link org.apache.xpath.patterns.UnionPattern} instance.
664    *
665    * @throws TransformerException if a error occurs creating the Expression.
666    */

667   protected Expression matchPattern(int opPos) throws TransformerException JavaDoc
668   {
669     locPathDepth++;
670     try
671     {
672       // First, count...
673
int nextOpPos = opPos;
674       int i;
675
676       for (i = 0; getOp(nextOpPos) == OpCodes.OP_LOCATIONPATHPATTERN; i++)
677       {
678         nextOpPos = getNextOpPos(nextOpPos);
679       }
680
681       if (i == 1)
682         return compile(opPos);
683
684       UnionPattern up = new UnionPattern();
685       StepPattern[] patterns = new StepPattern[i];
686
687       for (i = 0; getOp(opPos) == OpCodes.OP_LOCATIONPATHPATTERN; i++)
688       {
689         nextOpPos = getNextOpPos(opPos);
690         patterns[i] = (StepPattern) compile(opPos);
691         opPos = nextOpPos;
692       }
693
694       up.setPatterns(patterns);
695
696       return up;
697     }
698     finally
699     {
700       locPathDepth--;
701     }
702   }
703
704   /**
705    * Compile a location match pattern unit expression.
706    *
707    * @param opPos The current position in the m_opMap array.
708    *
709    * @return reference to {@link org.apache.xpath.patterns.StepPattern} instance.
710    *
711    * @throws TransformerException if a error occurs creating the Expression.
712    */

713   public Expression locationPathPattern(int opPos)
714           throws TransformerException JavaDoc
715   {
716
717     opPos = getFirstChildPos(opPos);
718
719     return stepPattern(opPos, 0, null);
720   }
721
722   /**
723    * Get a {@link org.w3c.dom.traversal.NodeFilter} bit set that tells what
724    * to show for a given node test.
725    *
726    * @param opPos the op map position for the location step.
727    *
728    * @return {@link org.w3c.dom.traversal.NodeFilter} bit set that tells what
729    * to show for a given node test.
730    */

731   public int getWhatToShow(int opPos)
732   {
733
734     int axesType = getOp(opPos);
735     int testType = getOp(opPos + 3);
736
737     // System.out.println("testType: "+testType);
738
switch (testType)
739     {
740     case OpCodes.NODETYPE_COMMENT :
741       return DTMFilter.SHOW_COMMENT;
742     case OpCodes.NODETYPE_TEXT :
743 // return DTMFilter.SHOW_TEXT | DTMFilter.SHOW_COMMENT;
744
return DTMFilter.SHOW_TEXT | DTMFilter.SHOW_CDATA_SECTION ;
745     case OpCodes.NODETYPE_PI :
746       return DTMFilter.SHOW_PROCESSING_INSTRUCTION;
747     case OpCodes.NODETYPE_NODE :
748 // return DTMFilter.SHOW_ALL;
749
switch (axesType)
750       {
751       case OpCodes.FROM_NAMESPACE:
752         return DTMFilter.SHOW_NAMESPACE;
753       case OpCodes.FROM_ATTRIBUTES :
754       case OpCodes.MATCH_ATTRIBUTE :
755         return DTMFilter.SHOW_ATTRIBUTE;
756       case OpCodes.FROM_SELF:
757       case OpCodes.FROM_ANCESTORS_OR_SELF:
758       case OpCodes.FROM_DESCENDANTS_OR_SELF:
759         return DTMFilter.SHOW_ALL;
760       default:
761         if (getOp(0) == OpCodes.OP_MATCHPATTERN)
762           return ~DTMFilter.SHOW_ATTRIBUTE
763                   & ~DTMFilter.SHOW_DOCUMENT
764                   & ~DTMFilter.SHOW_DOCUMENT_FRAGMENT;
765         else
766           return ~DTMFilter.SHOW_ATTRIBUTE;
767       }
768     case OpCodes.NODETYPE_ROOT :
769       return DTMFilter.SHOW_DOCUMENT | DTMFilter.SHOW_DOCUMENT_FRAGMENT;
770     case OpCodes.NODETYPE_FUNCTEST :
771       return NodeTest.SHOW_BYFUNCTION;
772     case OpCodes.NODENAME :
773       switch (axesType)
774       {
775       case OpCodes.FROM_NAMESPACE :
776         return DTMFilter.SHOW_NAMESPACE;
777       case OpCodes.FROM_ATTRIBUTES :
778       case OpCodes.MATCH_ATTRIBUTE :
779         return DTMFilter.SHOW_ATTRIBUTE;
780
781       // break;
782
case OpCodes.MATCH_ANY_ANCESTOR :
783       case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
784         return DTMFilter.SHOW_ELEMENT;
785
786       // break;
787
default :
788         return DTMFilter.SHOW_ELEMENT;
789       }
790     default :
791       // System.err.println("We should never reach here.");
792
return DTMFilter.SHOW_ALL;
793     }
794   }
795   
796 private static final boolean DEBUG = false;
797
798   /**
799    * Compile a step pattern unit expression, used for both location paths
800    * and match patterns.
801    *
802    * @param opPos The current position in the m_opMap array.
803    * @param stepCount The number of steps to expect.
804    * @param ancestorPattern The owning StepPattern, which may be null.
805    *
806    * @return reference to {@link org.apache.xpath.patterns.StepPattern} instance.
807    *
808    * @throws TransformerException if a error occurs creating the Expression.
809    */

810   protected StepPattern stepPattern(
811           int opPos, int stepCount, StepPattern ancestorPattern)
812             throws TransformerException JavaDoc
813   {
814
815     int startOpPos = opPos;
816     int stepType = getOp(opPos);
817
818     if (OpCodes.ENDOP == stepType)
819     {
820       return null;
821     }
822     
823     boolean addMagicSelf = true;
824
825     int endStep = getNextOpPos(opPos);
826
827     // int nextStepType = getOpMap()[endStep];
828
StepPattern pattern;
829     
830     // boolean isSimple = ((OpCodes.ENDOP == nextStepType) && (stepCount == 0));
831
int argLen;
832
833     switch (stepType)
834     {
835     case OpCodes.OP_FUNCTION :
836       if(DEBUG)
837         System.out.println("MATCH_FUNCTION: "+m_currentPattern);
838       addMagicSelf = false;
839       argLen = getOp(opPos + OpMap.MAPINDEX_LENGTH);
840       pattern = new FunctionPattern(compileFunction(opPos), Axis.PARENT, Axis.CHILD);
841       break;
842     case OpCodes.FROM_ROOT :
843       if(DEBUG)
844         System.out.println("FROM_ROOT, "+m_currentPattern);
845       addMagicSelf = false;
846       argLen = getArgLengthOfStep(opPos);
847       opPos = getFirstChildPosOfStep(opPos);
848       pattern = new StepPattern(DTMFilter.SHOW_DOCUMENT |
849                                 DTMFilter.SHOW_DOCUMENT_FRAGMENT,
850                                 Axis.PARENT, Axis.CHILD);
851       break;
852     case OpCodes.MATCH_ATTRIBUTE :
853      if(DEBUG)
854         System.out.println("MATCH_ATTRIBUTE: "+getStepLocalName(startOpPos)+", "+m_currentPattern);
855       argLen = getArgLengthOfStep(opPos);
856       opPos = getFirstChildPosOfStep(opPos);
857       pattern = new StepPattern(DTMFilter.SHOW_ATTRIBUTE,
858                                 getStepNS(startOpPos),
859                                 getStepLocalName(startOpPos),
860                                 Axis.PARENT, Axis.ATTRIBUTE);
861       break;
862     case OpCodes.MATCH_ANY_ANCESTOR :
863       if(DEBUG)
864         System.out.println("MATCH_ANY_ANCESTOR: "+getStepLocalName(startOpPos)+", "+m_currentPattern);
865       argLen = getArgLengthOfStep(opPos);
866       opPos = getFirstChildPosOfStep(opPos);
867       int what = getWhatToShow(startOpPos);
868       // bit-o-hackery, but this code is due for the morgue anyway...
869
if(0x00000500 == what)
870         addMagicSelf = false;
871       pattern = new StepPattern(getWhatToShow(startOpPos),
872                                         getStepNS(startOpPos),
873                                         getStepLocalName(startOpPos),
874                                         Axis.ANCESTOR, Axis.CHILD);
875       break;
876     case OpCodes.MATCH_IMMEDIATE_ANCESTOR :
877       if(DEBUG)
878         System.out.println("MATCH_IMMEDIATE_ANCESTOR: "+getStepLocalName(startOpPos)+", "+m_currentPattern);
879       argLen = getArgLengthOfStep(opPos);
880       opPos = getFirstChildPosOfStep(opPos);
881       pattern = new StepPattern(getWhatToShow(startOpPos),
882                                 getStepNS(startOpPos),
883                                 getStepLocalName(startOpPos),
884                                 Axis.PARENT, Axis.CHILD);
885       break;
886     default :
887       error(XPATHErrorResources.ER_UNKNOWN_MATCH_OPERATION, null); //"unknown match operation!");
888

889       return null;
890     }
891
892     pattern.setPredicates(getCompiledPredicates(opPos + argLen));
893     if(null == ancestorPattern)
894     {
895       // This is the magic and invisible "." at the head of every
896
// match pattern, and corresponds to the current node in the context
897
// list, from where predicates are counted.
898
// So, in order to calculate "foo[3]", it has to count from the
899
// current node in the context list, so, from that current node,
900
// the full pattern is really "self::node()/child::foo[3]". If you
901
// translate this to a select pattern from the node being tested,
902
// which is really how we're treating match patterns, it works out to
903
// self::foo/parent::node[child::foo[3]]", or close enough.
904
/* if(addMagicSelf && pattern.getPredicateCount() > 0)
905       {
906         StepPattern selfPattern = new StepPattern(DTMFilter.SHOW_ALL,
907                                                   Axis.PARENT, Axis.CHILD);
908         // We need to keep the new nodetest from affecting the score...
909         XNumber score = pattern.getStaticScore();
910         pattern.setRelativePathPattern(selfPattern);
911         pattern.setStaticScore(score);
912         selfPattern.setStaticScore(score);
913     }*/

914     }
915     else
916     {
917       // System.out.println("Setting "+ancestorPattern+" as relative to "+pattern);
918
pattern.setRelativePathPattern(ancestorPattern);
919     }
920
921     StepPattern relativePathPattern = stepPattern(endStep, stepCount + 1,
922                                         pattern);
923
924     return (null != relativePathPattern) ? relativePathPattern : pattern;
925   }
926
927   /**
928    * Compile a zero or more predicates for a given match pattern.
929    *
930    * @param opPos The position of the first predicate the m_opMap array.
931    *
932    * @return reference to array of {@link org.apache.xpath.Expression} instances.
933    *
934    * @throws TransformerException if a error occurs creating the Expression.
935    */

936   public Expression[] getCompiledPredicates(int opPos)
937           throws TransformerException JavaDoc
938   {
939
940     int count = countPredicates(opPos);
941
942     if (count > 0)
943     {
944       Expression[] predicates = new Expression[count];
945
946       compilePredicates(opPos, predicates);
947
948       return predicates;
949     }
950
951     return null;
952   }
953
954   /**
955    * Count the number of predicates in the step.
956    *
957    * @param opPos The position of the first predicate the m_opMap array.
958    *
959    * @return The number of predicates for this step.
960    *
961    * @throws TransformerException if a error occurs creating the Expression.
962    */

963   public int countPredicates(int opPos) throws TransformerException JavaDoc
964   {
965
966     int count = 0;
967
968     while (OpCodes.OP_PREDICATE == getOp(opPos))
969     {
970       count++;
971
972       opPos = getNextOpPos(opPos);
973     }
974
975     return count;
976   }
977
978   /**
979    * Compiles predicates in the step.
980    *
981    * @param opPos The position of the first predicate the m_opMap array.
982    * @param predicates An empty pre-determined array of
983    * {@link org.apache.xpath.Expression}s, that will be filled in.
984    *
985    * @throws TransformerException
986    */

987   private void compilePredicates(int opPos, Expression[] predicates)
988           throws TransformerException JavaDoc
989   {
990
991     for (int i = 0; OpCodes.OP_PREDICATE == getOp(opPos); i++)
992     {
993       predicates[i] = predicate(opPos);
994       opPos = getNextOpPos(opPos);
995     }
996   }
997
998   /**
999    * Compile a built-in XPath function.
1000   *
1001   * @param opPos The current position in the m_opMap array.
1002   *
1003   * @return reference to {@link org.apache.xpath.functions.Function} instance.
1004   *
1005   * @throws TransformerException if a error occurs creating the Expression.
1006   */

1007  Expression compileFunction(int opPos) throws TransformerException JavaDoc
1008  {
1009
1010    int endFunc = opPos + getOp(opPos + 1) - 1;
1011
1012    opPos = getFirstChildPos(opPos);
1013
1014    int funcID = getOp(opPos);
1015
1016    opPos++;
1017
1018    if (-1 != funcID)
1019    {
1020      Function func = FunctionTable.getFunction(funcID);
1021
1022      func.postCompileStep(this);
1023      
1024      try
1025      {
1026        int i = 0;
1027
1028        for (int p = opPos; p < endFunc; p = getNextOpPos(p), i++)
1029        {
1030
1031          // System.out.println("argPos: "+ p);
1032
// System.out.println("argCode: "+ m_opMap[p]);
1033
func.setArg(compile(p), i);
1034        }
1035
1036        func.checkNumberArgs(i);
1037      }
1038      catch (WrongNumberArgsException wnae)
1039      {
1040        java.lang.String JavaDoc name = FunctionTable.m_functions[funcID].getName();
1041
1042        m_errorHandler.fatalError( new TransformerException JavaDoc(
1043                  XSLMessages.createXPATHMessage(XPATHErrorResources.ER_ONLY_ALLOWS,
1044                      new Object JavaDoc[]{name, wnae.getMessage()}), m_locator));
1045              //"name + " only allows " + wnae.getMessage() + " arguments", m_locator));
1046
}
1047
1048      return func;
1049    }
1050    else
1051    {
1052      error(XPATHErrorResources.ER_FUNCTION_TOKEN_NOT_FOUND, null); //"function token not found.");
1053

1054      return null;
1055    }
1056  }
1057
1058  // The current id for extension functions.
1059
private static long s_nextMethodId = 0;
1060
1061  /**
1062   * Get the next available method id
1063   */

1064  synchronized private long getNextMethodId()
1065  {
1066    if (s_nextMethodId == Long.MAX_VALUE)
1067      s_nextMethodId = 0;
1068    
1069    return s_nextMethodId++;
1070  }
1071  
1072  /**
1073   * Compile an extension function.
1074   *
1075   * @param opPos The current position in the m_opMap array.
1076   *
1077   * @return reference to {@link org.apache.xpath.functions.FuncExtFunction} instance.
1078   *
1079   * @throws TransformerException if a error occurs creating the Expression.
1080   */

1081  private Expression compileExtension(int opPos)
1082          throws TransformerException JavaDoc
1083  {
1084
1085    int endExtFunc = opPos + getOp(opPos + 1) - 1;
1086
1087    opPos = getFirstChildPos(opPos);
1088
1089    java.lang.String JavaDoc ns = (java.lang.String JavaDoc) getTokenQueue().elementAt(getOp(opPos));
1090
1091    opPos++;
1092
1093    java.lang.String JavaDoc funcName =
1094      (java.lang.String JavaDoc) getTokenQueue().elementAt(getOp(opPos));
1095
1096    opPos++;
1097
1098    // We create a method key to uniquely identify this function so that we
1099
// can cache the object needed to invoke it. This way, we only pay the
1100
// reflection overhead on the first call.
1101

1102    Function extension = new FuncExtFunction(ns, funcName, String.valueOf(getNextMethodId()));
1103
1104    try
1105    {
1106      int i = 0;
1107
1108      while (opPos < endExtFunc)
1109      {
1110        int nextOpPos = getNextOpPos(opPos);
1111
1112        extension.setArg(this.compile(opPos), i);
1113
1114        opPos = nextOpPos;
1115
1116        i++;
1117      }
1118    }
1119    catch (WrongNumberArgsException wnae)
1120    {
1121      ; // should never happen
1122
}
1123
1124    return extension;
1125  }
1126
1127  /**
1128   * Warn the user of an problem.
1129   *
1130   * @param msg An error msgkey that corresponds to one of the constants found
1131   * in {@link org.apache.xpath.res.XPATHErrorResources}, which is
1132   * a key for a format string.
1133   * @param args An array of arguments represented in the format string, which
1134   * may be null.
1135   *
1136   * @throws TransformerException if the current ErrorListoner determines to
1137   * throw an exception.
1138   */

1139  public void warn(String JavaDoc msg, Object JavaDoc[] args) throws TransformerException JavaDoc
1140  {
1141
1142    java.lang.String JavaDoc fmsg = XSLMessages.createXPATHWarning(msg, args);
1143
1144    if (null != m_errorHandler)
1145    {
1146      m_errorHandler.warning(new TransformerException JavaDoc(fmsg, m_locator));
1147    }
1148    else
1149    {
1150      System.out.println(fmsg
1151                          +"; file "+m_locator.getSystemId()
1152                          +"; line "+m_locator.getLineNumber()
1153                          +"; column "+m_locator.getColumnNumber());
1154    }
1155  }
1156
1157  /**
1158   * Tell the user of an assertion error, and probably throw an
1159   * exception.
1160   *
1161   * @param b If false, a runtime exception will be thrown.
1162   * @param msg The assertion message, which should be informative.
1163   *
1164   * @throws RuntimeException if the b argument is false.
1165   */

1166  public void assertion(boolean b, java.lang.String JavaDoc msg)
1167  {
1168
1169    if (!b)
1170    {
1171      java.lang.String JavaDoc fMsg = XSLMessages.createXPATHMessage(
1172        XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION,
1173        new Object JavaDoc[]{ msg });
1174
1175      throw new RuntimeException JavaDoc(fMsg);
1176    }
1177  }
1178
1179  /**
1180   * Tell the user of an error, and probably throw an
1181   * exception.
1182   *
1183   * @param msg An error msgkey that corresponds to one of the constants found
1184   * in {@link org.apache.xpath.res.XPATHErrorResources}, which is
1185   * a key for a format string.
1186   * @param args An array of arguments represented in the format string, which
1187   * may be null.
1188   *
1189   * @throws TransformerException if the current ErrorListoner determines to
1190   * throw an exception.
1191   */

1192  public void error(String JavaDoc msg, Object JavaDoc[] args) throws TransformerException JavaDoc
1193  {
1194
1195    java.lang.String JavaDoc fmsg = XSLMessages.createXPATHMessage(msg, args);
1196    
1197
1198    if (null != m_errorHandler)
1199    {
1200      m_errorHandler.fatalError(new TransformerException JavaDoc(fmsg, m_locator));
1201    }
1202    else
1203    {
1204
1205      // System.out.println(te.getMessage()
1206
// +"; file "+te.getSystemId()
1207
// +"; line "+te.getLineNumber()
1208
// +"; column "+te.getColumnNumber());
1209
throw new TransformerException JavaDoc(fmsg, (SAXSourceLocator)m_locator);
1210    }
1211  }
1212
1213  /**
1214   * The current prefixResolver for the execution context.
1215   */

1216  private PrefixResolver m_currentPrefixResolver = null;
1217
1218  /**
1219   * Get the current namespace context for the xpath.
1220   *
1221   * @return The current prefix resolver, *may* be null, though hopefully not.
1222   */

1223  public PrefixResolver getNamespaceContext()
1224  {
1225    return m_currentPrefixResolver;
1226  }
1227
1228  /**
1229   * Set the current namespace context for the xpath.
1230   *
1231   * @param pr The resolver for prefixes in the XPath expression.
1232   */

1233  public void setNamespaceContext(PrefixResolver pr)
1234  {
1235    m_currentPrefixResolver = pr;
1236  }
1237
1238  /** The error listener where errors will be sent. If this is null, errors
1239   * and warnings will be sent to System.err. May be null. */

1240  ErrorListener JavaDoc m_errorHandler;
1241
1242  /** The source locator for the expression being compiled. May be null. */
1243  SourceLocator JavaDoc m_locator;
1244}
1245
Popular Tags