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: UnionPathExpr.java 468650 2006-10-28 07:03:30Z minchau $
020     */
021    
022    package org.apache.xalan.xsltc.compiler;
023    
024    import java.util.Vector;
025    
026    import org.apache.bcel.generic.ConstantPoolGen;
027    import org.apache.bcel.generic.INVOKEINTERFACE;
028    import org.apache.bcel.generic.INVOKESPECIAL;
029    import org.apache.bcel.generic.INVOKEVIRTUAL;
030    import org.apache.bcel.generic.InstructionList;
031    import org.apache.bcel.generic.NEW;
032    import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
033    import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
034    import org.apache.xalan.xsltc.compiler.util.Type;
035    import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
036    import org.apache.xml.dtm.Axis;
037    import org.apache.xml.dtm.DTM;
038    
039    /**
040     * @author Jacek Ambroziak
041     * @author Santiago Pericas-Geertsen
042     */
043    final class UnionPathExpr extends Expression {
044    
045        private final Expression _pathExpr;
046        private final Expression _rest;
047        private boolean _reverse = false;
048    
049        // linearization for top level UnionPathExprs
050        private Expression[] _components;
051        
052        public UnionPathExpr(Expression pathExpr, Expression rest) {
053            _pathExpr = pathExpr;
054            _rest     = rest;
055        }
056    
057        public void setParser(Parser parser) {
058            super.setParser(parser);
059            // find all expressions in this Union
060            final Vector components = new Vector();
061            flatten(components);
062            final int size = components.size();
063            _components = (Expression[])components.toArray(new Expression[size]);
064            for (int i = 0; i < size; i++) {
065                _components[i].setParser(parser);
066                _components[i].setParent(this);
067                if (_components[i] instanceof Step) {
068                    final Step step = (Step)_components[i];
069                    final int axis = step.getAxis();
070                    final int type = step.getNodeType();
071                    // Put attribute iterators first
072                    if ((axis == Axis.ATTRIBUTE) || (type == DTM.ATTRIBUTE_NODE)) {
073                        _components[i] = _components[0];
074                        _components[0] = step;
075                    }
076                    // Check if the union contains a reverse iterator
077            if (Axis.isReverse(axis)) _reverse = true;
078                }
079            }
080            // No need to reverse anything if another expression lies on top of this
081            if (getParent() instanceof Expression) _reverse = false;
082        }
083        
084        public Type typeCheck(SymbolTable stable) throws TypeCheckError {
085            final int length = _components.length;
086            for (int i = 0; i < length; i++) {
087                if (_components[i].typeCheck(stable) != Type.NodeSet) {
088                    _components[i] = new CastExpr(_components[i], Type.NodeSet);
089                }
090            }
091            return _type = Type.NodeSet;    
092        }
093    
094        public String toString() {
095            return "union(" + _pathExpr + ", " + _rest + ')';
096        }
097            
098        private void flatten(Vector components) {
099            components.addElement(_pathExpr);
100            if (_rest != null) {
101                if (_rest instanceof UnionPathExpr) {
102                    ((UnionPathExpr)_rest).flatten(components);
103                }
104                else {
105                    components.addElement(_rest);
106                }
107            }
108        }
109    
110        public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
111            final ConstantPoolGen cpg = classGen.getConstantPool();
112            final InstructionList il = methodGen.getInstructionList();
113    
114            final int init = cpg.addMethodref(UNION_ITERATOR_CLASS,
115                                              "<init>",
116                                              "("+DOM_INTF_SIG+")V");
117            final int iter = cpg.addMethodref(UNION_ITERATOR_CLASS,
118                                              ADD_ITERATOR,
119                                              ADD_ITERATOR_SIG);
120    
121            // Create the UnionIterator and leave it on the stack
122            il.append(new NEW(cpg.addClass(UNION_ITERATOR_CLASS)));
123            il.append(DUP);
124            il.append(methodGen.loadDOM());
125            il.append(new INVOKESPECIAL(init));
126    
127            // Add the various iterators to the UnionIterator
128            final int length = _components.length;
129            for (int i = 0; i < length; i++) {
130                _components[i].translate(classGen, methodGen);
131                il.append(new INVOKEVIRTUAL(iter));
132            }
133    
134            // Order the iterator only if strictly needed
135            if (_reverse) {
136                final int order = cpg.addInterfaceMethodref(DOM_INTF,
137                                                            ORDER_ITERATOR,
138                                                            ORDER_ITERATOR_SIG);
139                il.append(methodGen.loadDOM());
140                il.append(SWAP);
141                il.append(methodGen.loadContextNode());
142                il.append(new INVOKEINTERFACE(order, 3));
143    
144            }
145        }
146    }