KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xalan > internal > xsltc > compiler > ParentLocationPath


1 /*
2  * Copyright 2001-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: ParentLocationPath.java,v 1.23 2004/02/16 22:24:29 minchau Exp $
18  */

19
20 package com.sun.org.apache.xalan.internal.xsltc.compiler;
21
22 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
23 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
24 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
25 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
26 import com.sun.org.apache.bcel.internal.generic.InstructionList;
27 import com.sun.org.apache.bcel.internal.generic.NEW;
28 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
29 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
30 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
31 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
32 import com.sun.org.apache.xalan.internal.xsltc.dom.Axis;
33 import com.sun.org.apache.xml.internal.dtm.DTM;
34
35 /**
36  * @author Jacek Ambroziak
37  * @author Santiago Pericas-Geertsen
38  */

39 final class ParentLocationPath extends RelativeLocationPath {
40     private Expression _step;
41     private final RelativeLocationPath _path;
42     private Type stype;
43     private boolean _orderNodes = false;
44     private boolean _axisMismatch = false;
45
46     public ParentLocationPath(RelativeLocationPath path, Expression step) {
47     _path = path;
48     _step = step;
49     _path.setParent(this);
50     _step.setParent(this);
51
52     if (_step instanceof Step) {
53         _axisMismatch = checkAxisMismatch();
54     }
55     }
56         
57     public void setAxis(int axis) {
58     _path.setAxis(axis);
59     }
60
61     public int getAxis() {
62     return _path.getAxis();
63     }
64
65     public RelativeLocationPath getPath() {
66     return(_path);
67     }
68
69     public Expression getStep() {
70     return(_step);
71     }
72
73     public void setParser(Parser parser) {
74     super.setParser(parser);
75     _step.setParser(parser);
76     _path.setParser(parser);
77     }
78     
79     public String JavaDoc toString() {
80     return "ParentLocationPath(" + _path + ", " + _step + ')';
81     }
82
83     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
84     stype = _step.typeCheck(stable);
85     _path.typeCheck(stable);
86
87     if (_axisMismatch) enableNodeOrdering();
88
89     return _type = Type.NodeSet;
90     }
91
92     public void enableNodeOrdering() {
93     SyntaxTreeNode parent = getParent();
94     if (parent instanceof ParentLocationPath)
95         ((ParentLocationPath)parent).enableNodeOrdering();
96     else {
97         _orderNodes = true;
98     }
99     }
100
101     /**
102      * This method is used to determine if this parent location path is a
103      * combination of two step's with axes that will create duplicate or
104      * unordered nodes.
105      */

106     public boolean checkAxisMismatch() {
107
108     int left = _path.getAxis();
109     int right = ((Step)_step).getAxis();
110
111     if (((left == Axis.ANCESTOR) || (left == Axis.ANCESTORORSELF)) &&
112         ((right == Axis.CHILD) ||
113          (right == Axis.DESCENDANT) ||
114          (right == Axis.DESCENDANTORSELF) ||
115          (right == Axis.PARENT) ||
116          (right == Axis.PRECEDING) ||
117          (right == Axis.PRECEDINGSIBLING)))
118         return true;
119
120     if ((left == Axis.CHILD) &&
121         (right == Axis.ANCESTOR) ||
122         (right == Axis.ANCESTORORSELF) ||
123         (right == Axis.PARENT) ||
124         (right == Axis.PRECEDING))
125         return true;
126
127     if ((left == Axis.DESCENDANT) || (left == Axis.DESCENDANTORSELF))
128         return true;
129
130     if (((left == Axis.FOLLOWING) || (left == Axis.FOLLOWINGSIBLING)) &&
131         ((right == Axis.FOLLOWING) ||
132          (right == Axis.PARENT) ||
133          (right == Axis.PRECEDING) ||
134          (right == Axis.PRECEDINGSIBLING)))
135         return true;
136
137     if (((left == Axis.PRECEDING) || (left == Axis.PRECEDINGSIBLING)) &&
138         ((right == Axis.DESCENDANT) ||
139          (right == Axis.DESCENDANTORSELF) ||
140          (right == Axis.FOLLOWING) ||
141          (right == Axis.FOLLOWINGSIBLING) ||
142          (right == Axis.PARENT) ||
143          (right == Axis.PRECEDING) ||
144          (right == Axis.PRECEDINGSIBLING)))
145         return true;
146
147     if ((right == Axis.FOLLOWING) && (left == Axis.CHILD)) {
148         // Special case for '@*/following::*' expressions. The resulting
149
// iterator is initialised with the parent's first child, and this
150
// can cause duplicates in the output if the parent has more than
151
// one attribute that matches the left step.
152
if (_path instanceof Step) {
153         int type = ((Step)_path).getNodeType();
154         if (type == DTM.ATTRIBUTE_NODE) return true;
155         }
156     }
157
158     return false;
159     }
160
161     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
162     final ConstantPoolGen cpg = classGen.getConstantPool();
163     final InstructionList il = methodGen.getInstructionList();
164
165     // Create new StepIterator
166
final int initSI = cpg.addMethodref(STEP_ITERATOR_CLASS,
167                         "<init>",
168                         "("
169                         +NODE_ITERATOR_SIG
170                         +NODE_ITERATOR_SIG
171                         +")V");
172     il.append(new NEW(cpg.addClass(STEP_ITERATOR_CLASS)));
173     il.append(DUP);
174
175     // Compile path iterator
176
_path.translate(classGen, methodGen); // iterator on stack....
177
_step.translate(classGen, methodGen);
178
179     // Initialize StepIterator with iterators from the stack
180
il.append(new INVOKESPECIAL(initSI));
181
182     // This is a special case for the //* path with or without predicates
183
Expression stp = _step;
184     if (stp instanceof ParentLocationPath)
185         stp = ((ParentLocationPath)stp).getStep();
186
187     if ((_path instanceof Step) && (stp instanceof Step)) {
188         final int path = ((Step)_path).getAxis();
189         final int step = ((Step)stp).getAxis();
190         if ((path == Axis.DESCENDANTORSELF && step == Axis.CHILD) ||
191         (path == Axis.PRECEDING && step == Axis.PARENT)) {
192         final int incl = cpg.addMethodref(NODE_ITERATOR_BASE,
193                           "includeSelf",
194                           "()" + NODE_ITERATOR_SIG);
195         il.append(new INVOKEVIRTUAL(incl));
196         }
197     }
198
199     /*
200      * If this pattern contains a sequence of descendant iterators we
201      * run the risk of returning the same node several times. We put
202      * a new iterator on top of the existing one to assure node order
203      * and prevent returning a single node multiple times.
204      */

205     if (_orderNodes) {
206         final int order = cpg.addInterfaceMethodref(DOM_INTF,
207                             ORDER_ITERATOR,
208                             ORDER_ITERATOR_SIG);
209         il.append(methodGen.loadDOM());
210         il.append(SWAP);
211         il.append(methodGen.loadContextNode());
212         il.append(new INVOKEINTERFACE(order, 3));
213     }
214     }
215 }
216
Popular Tags