1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.xalan.internal.xsltc.compiler;
23
24import java.util.Vector;
25
26import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
27import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
28import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
29import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
30import com.sun.org.apache.bcel.internal.generic.InstructionList;
31import com.sun.org.apache.bcel.internal.generic.NEW;
32import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
33import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
34import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
35import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
36import com.sun.org.apache.xml.internal.dtm.Axis;
37import com.sun.org.apache.xml.internal.dtm.DTM;
38
39/**
40 * @author Jacek Ambroziak
41 * @author Santiago Pericas-Geertsen
42 */
43final class UnionPathExpr extends Expression {
44
45    private final Expression _pathExpr;
46    private final Expression _rest;
47    private boolean _reverse = false;
48
49    // linearization for top level UnionPathExprs
50    private Expression[] _components;
51
52    public UnionPathExpr(Expression pathExpr, Expression rest) {
53        _pathExpr = pathExpr;
54        _rest     = rest;
55    }
56
57    public void setParser(Parser parser) {
58        super.setParser(parser);
59        // find all expressions in this Union
60        final Vector components = new Vector();
61        flatten(components);
62        final int size = components.size();
63        _components = (Expression[])components.toArray(new Expression[size]);
64        for (int i = 0; i < size; i++) {
65            _components[i].setParser(parser);
66            _components[i].setParent(this);
67            if (_components[i] instanceof Step) {
68                final Step step = (Step)_components[i];
69                final int axis = step.getAxis();
70                final int type = step.getNodeType();
71                // Put attribute iterators first
72                if ((axis == Axis.ATTRIBUTE) || (type == DTM.ATTRIBUTE_NODE)) {
73                    _components[i] = _components[0];
74                    _components[0] = step;
75                }
76                // Check if the union contains a reverse iterator
77        if (Axis.isReverse(axis)) _reverse = true;
78            }
79        }
80        // No need to reverse anything if another expression lies on top of this
81        if (getParent() instanceof Expression) _reverse = false;
82    }
83
84    public Type typeCheck(SymbolTable stable) throws TypeCheckError {
85        final int length = _components.length;
86        for (int i = 0; i < length; i++) {
87            if (_components[i].typeCheck(stable) != Type.NodeSet) {
88                _components[i] = new CastExpr(_components[i], Type.NodeSet);
89            }
90        }
91        return _type = Type.NodeSet;
92    }
93
94    public String toString() {
95        return "union(" + _pathExpr + ", " + _rest + ')';
96    }
97
98    private void flatten(Vector components) {
99        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}
147