001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: NodeType.java 468649 2006-10-28 07:00:55Z minchau $
020     */
021    
022    package org.apache.xalan.xsltc.compiler.util;
023    
024    import org.apache.bcel.generic.BranchHandle;
025    import org.apache.bcel.generic.CHECKCAST;
026    import org.apache.bcel.generic.ConstantPoolGen;
027    import org.apache.bcel.generic.GETFIELD;
028    import org.apache.bcel.generic.GOTO;
029    import org.apache.bcel.generic.IFEQ;
030    import org.apache.bcel.generic.ILOAD;
031    import org.apache.bcel.generic.INVOKEINTERFACE;
032    import org.apache.bcel.generic.INVOKESPECIAL;
033    import org.apache.bcel.generic.ISTORE;
034    import org.apache.bcel.generic.Instruction;
035    import org.apache.bcel.generic.InstructionList;
036    import org.apache.bcel.generic.NEW;
037    import org.apache.bcel.generic.PUSH;
038    import org.apache.xalan.xsltc.compiler.Constants;
039    import org.apache.xalan.xsltc.compiler.FlowList;
040    import org.apache.xalan.xsltc.compiler.NodeTest;
041    
042    /**
043     * @author Jacek Ambroziak
044     * @author Santiago Pericas-Geertsen
045     */
046    public final class NodeType extends Type {
047        private final int _type;
048    
049        protected NodeType() {
050            this(NodeTest.ANODE);
051        }
052    
053        protected NodeType(int type) {
054            _type = type;
055        }
056    
057        public int getType() {
058            return _type;
059        }
060    
061        public String toString() {
062            return "node-type";
063        }
064    
065        public boolean identicalTo(Type other) {
066            return other instanceof NodeType;
067        }
068    
069        public int hashCode() {
070            return _type;
071        }
072    
073        public String toSignature() {
074            return "I";
075        }
076    
077        public org.apache.bcel.generic.Type toJCType() {
078            return org.apache.bcel.generic.Type.INT;
079        }
080    
081        /**
082         * Translates a node into an object of internal type <code>type</code>.
083         * The translation to int is undefined since nodes are always converted
084         * to reals in arithmetic expressions.
085         *
086         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
087         */
088        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 
089                                Type type) {
090            if (type == Type.String) {
091                translateTo(classGen, methodGen, (StringType) type);
092            }
093            else if (type == Type.Boolean) {
094                translateTo(classGen, methodGen, (BooleanType) type);
095            }
096            else if (type == Type.Real) {
097                translateTo(classGen, methodGen, (RealType) type);
098            }
099            else if (type == Type.NodeSet) {
100                translateTo(classGen, methodGen, (NodeSetType) type);
101            }
102            else if (type == Type.Reference) {
103                translateTo(classGen, methodGen, (ReferenceType) type);
104            }
105            else if (type == Type.Object) {
106                translateTo(classGen, methodGen, (ObjectType) type);
107            }
108            else {
109                ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
110                                            toString(), type.toString());
111                classGen.getParser().reportError(Constants.FATAL, err);
112            }
113        }
114    
115        /**
116         * Expects a node on the stack and pushes its string value. 
117         *
118         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
119         */
120        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 
121                                StringType type) {
122            final ConstantPoolGen cpg = classGen.getConstantPool();
123            final InstructionList il = methodGen.getInstructionList();
124    
125            switch (_type) {
126            case NodeTest.ROOT:
127            case NodeTest.ELEMENT:
128                il.append(methodGen.loadDOM());
129                il.append(SWAP); // dom ref must be below node index
130                int index = cpg.addInterfaceMethodref(DOM_INTF,
131                                                      GET_ELEMENT_VALUE,
132                                                      GET_ELEMENT_VALUE_SIG);
133                il.append(new INVOKEINTERFACE(index, 2));
134                break;
135    
136            case NodeTest.ANODE:
137            case NodeTest.COMMENT:
138            case NodeTest.ATTRIBUTE:
139            case NodeTest.PI:
140                il.append(methodGen.loadDOM());
141                il.append(SWAP); // dom ref must be below node index
142                index = cpg.addInterfaceMethodref(DOM_INTF,
143                                                  GET_NODE_VALUE,
144                                                  GET_NODE_VALUE_SIG);
145                il.append(new INVOKEINTERFACE(index, 2));
146                break;
147                
148            default:
149                ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
150                                            toString(), type.toString());
151                classGen.getParser().reportError(Constants.FATAL, err);
152                break;
153            }
154        }
155    
156        /**
157         * Translates a node into a synthesized boolean.
158         * If the expression is "@attr", 
159         * then "true" is pushed iff "attr" is an attribute of the current node.
160         * If the expression is ".", the result is always "true".   
161         *
162         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
163         */
164        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 
165                                BooleanType type) {
166            final InstructionList il = methodGen.getInstructionList();
167            FlowList falsel = translateToDesynthesized(classGen, methodGen, type);
168            il.append(ICONST_1);
169            final BranchHandle truec = il.append(new GOTO(null));
170            falsel.backPatch(il.append(ICONST_0));
171            truec.setTarget(il.append(NOP));
172        }
173    
174        /**
175         * Expects a node on the stack and pushes a real.
176         * First the node is converted to string, and from string to real.
177         *
178         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
179         */
180        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 
181                                RealType type) {
182            translateTo(classGen, methodGen, Type.String);
183            Type.String.translateTo(classGen, methodGen, Type.Real);        
184        }
185    
186        /**
187         * Expects a node on the stack and pushes a singleton node-set. Singleton
188         * iterators are already started after construction.
189         *
190         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
191         */
192        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 
193                                NodeSetType type) {
194            ConstantPoolGen cpg = classGen.getConstantPool();
195            InstructionList il = methodGen.getInstructionList();
196    
197            // Create a new instance of SingletonIterator
198            il.append(new NEW(cpg.addClass(SINGLETON_ITERATOR)));
199            il.append(DUP_X1);
200            il.append(SWAP);
201            final int init = cpg.addMethodref(SINGLETON_ITERATOR, "<init>",
202                                              "(" + NODE_SIG +")V");
203            il.append(new INVOKESPECIAL(init));
204        }
205    
206        /**
207         * Subsume Node into ObjectType.
208         *
209         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
210         */
211        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 
212                                ObjectType type) {
213                methodGen.getInstructionList().append(NOP); 
214        }
215    
216        /**
217         * Translates a node into a non-synthesized boolean. It does not push a 
218         * 0 or a 1 but instead returns branchhandle list to be appended to the 
219         * false list.
220         *
221         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateToDesynthesized
222         */
223        public FlowList translateToDesynthesized(ClassGenerator classGen, 
224                                                 MethodGenerator methodGen, 
225                                                 BooleanType type) {
226            final InstructionList il = methodGen.getInstructionList();
227            return new FlowList(il.append(new IFEQ(null)));
228        }
229    
230        /**
231         * Expects a node on the stack and pushes a boxed node. Boxed nodes
232         * are represented by an instance of <code>org.apache.xalan.xsltc.dom.Node</code>.
233         *
234         * @see     org.apache.xalan.xsltc.compiler.util.Type#translateTo
235         */
236        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 
237                                ReferenceType type) {
238            final ConstantPoolGen cpg = classGen.getConstantPool();
239            final InstructionList il = methodGen.getInstructionList();
240            il.append(new NEW(cpg.addClass(RUNTIME_NODE_CLASS)));
241            il.append(DUP_X1);
242            il.append(SWAP);
243            il.append(new PUSH(cpg, _type));
244            il.append(new INVOKESPECIAL(cpg.addMethodref(RUNTIME_NODE_CLASS,
245                                                         "<init>", "(II)V")));
246        }
247    
248        /**
249         * Translates a node into the Java type denoted by <code>clazz</code>. 
250         * Expects a node on the stack and pushes an object of the appropriate
251         * type after coercion.
252         */
253        public void translateTo(ClassGenerator classGen, MethodGenerator methodGen, 
254                                Class clazz) {
255            final ConstantPoolGen cpg = classGen.getConstantPool();
256            final InstructionList il = methodGen.getInstructionList();
257    
258            String className = clazz.getName();
259            if (className.equals("java.lang.String")) {
260               translateTo(classGen, methodGen, Type.String);
261               return;
262            }
263    
264            il.append(methodGen.loadDOM());
265            il.append(SWAP);                // dom ref must be below node index
266    
267            if (className.equals("org.w3c.dom.Node") ||
268                className.equals("java.lang.Object")) {
269                int index = cpg.addInterfaceMethodref(DOM_INTF,
270                                                      MAKE_NODE,
271                                                      MAKE_NODE_SIG);
272                il.append(new INVOKEINTERFACE(index, 2));
273            }
274            else if (className.equals("org.w3c.dom.NodeList")) {
275                int index = cpg.addInterfaceMethodref(DOM_INTF,
276                                                      MAKE_NODE_LIST,
277                                                      MAKE_NODE_LIST_SIG);
278                il.append(new INVOKEINTERFACE(index, 2));
279            }
280            else {
281                ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
282                                            toString(), className);
283                classGen.getParser().reportError(Constants.FATAL, err);
284            }
285        }
286    
287        /**
288         * Translates an object of this type to its boxed representation.
289         */ 
290        public void translateBox(ClassGenerator classGen,
291                                 MethodGenerator methodGen) {
292            translateTo(classGen, methodGen, Type.Reference);
293        }
294    
295        /**
296         * Translates an object of this type to its unboxed representation.
297         */ 
298        public void translateUnBox(ClassGenerator classGen,
299                                   MethodGenerator methodGen) {
300            final ConstantPoolGen cpg = classGen.getConstantPool();
301            final InstructionList il = methodGen.getInstructionList();
302            il.append(new CHECKCAST(cpg.addClass(RUNTIME_NODE_CLASS)));
303            il.append(new GETFIELD(cpg.addFieldref(RUNTIME_NODE_CLASS,
304                                                   NODE_FIELD,
305                                                   NODE_FIELD_SIG)));
306        }
307    
308        /**
309         * Returns the class name of an internal type's external representation.
310         */
311        public String getClassName() {
312            return(RUNTIME_NODE_CLASS);
313        }
314    
315        public Instruction LOAD(int slot) {
316            return new ILOAD(slot);
317        }
318            
319        public Instruction STORE(int slot) {
320            return new ISTORE(slot);
321        }
322    }
323