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 }