001: /*
002: * Copyright 2001-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: /*
017: * $Id: UnionPathExpr.java,v 1.11 2004/12/15 17:35:39 jycli Exp $
018: */
019:
020: package org.apache.xalan.xsltc.compiler;
021:
022: import java.util.Vector;
023:
024: import org.apache.bcel.generic.ConstantPoolGen;
025: import org.apache.bcel.generic.INVOKEINTERFACE;
026: import org.apache.bcel.generic.INVOKESPECIAL;
027: import org.apache.bcel.generic.INVOKEVIRTUAL;
028: import org.apache.bcel.generic.InstructionList;
029: import org.apache.bcel.generic.NEW;
030: import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
031: import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
032: import org.apache.xalan.xsltc.compiler.util.Type;
033: import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
034: import org.apache.xml.dtm.Axis;
035: import org.apache.xml.dtm.DTM;
036:
037: /**
038: * @author Jacek Ambroziak
039: * @author Santiago Pericas-Geertsen
040: */
041: final class UnionPathExpr extends Expression {
042:
043: private final Expression _pathExpr;
044: private final Expression _rest;
045: private boolean _reverse = false;
046:
047: // linearization for top level UnionPathExprs
048: private Expression[] _components;
049:
050: public UnionPathExpr(Expression pathExpr, Expression rest) {
051: _pathExpr = pathExpr;
052: _rest = rest;
053: }
054:
055: public void setParser(Parser parser) {
056: super .setParser(parser);
057: // find all expressions in this Union
058: final Vector components = new Vector();
059: flatten(components);
060: final int size = components.size();
061: _components = (Expression[]) components
062: .toArray(new Expression[size]);
063: for (int i = 0; i < size; i++) {
064: _components[i].setParser(parser);
065: _components[i].setParent(this );
066: if (_components[i] instanceof Step) {
067: final Step step = (Step) _components[i];
068: final int axis = step.getAxis();
069: final int type = step.getNodeType();
070: // Put attribute iterators first
071: if ((axis == Axis.ATTRIBUTE)
072: || (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))
078: _reverse = true;
079: }
080: }
081: // No need to reverse anything if another expression lies on top of this
082: if (getParent() instanceof Expression)
083: _reverse = false;
084: }
085:
086: public Type typeCheck(SymbolTable stable) throws TypeCheckError {
087: final int length = _components.length;
088: for (int i = 0; i < length; i++) {
089: if (_components[i].typeCheck(stable) != Type.NodeSet) {
090: _components[i] = new CastExpr(_components[i],
091: Type.NodeSet);
092: }
093: }
094: return _type = Type.NodeSet;
095: }
096:
097: public String toString() {
098: return "union(" + _pathExpr + ", " + _rest + ')';
099: }
100:
101: private void flatten(Vector components) {
102: components.addElement(_pathExpr);
103: if (_rest != null) {
104: if (_rest instanceof UnionPathExpr) {
105: ((UnionPathExpr) _rest).flatten(components);
106: } else {
107: components.addElement(_rest);
108: }
109: }
110: }
111:
112: public void translate(ClassGenerator classGen,
113: MethodGenerator methodGen) {
114: final ConstantPoolGen cpg = classGen.getConstantPool();
115: final InstructionList il = methodGen.getInstructionList();
116:
117: final int init = cpg.addMethodref(UNION_ITERATOR_CLASS,
118: "<init>", "(" + DOM_INTF_SIG + ")V");
119: final int iter = cpg.addMethodref(UNION_ITERATOR_CLASS,
120: ADD_ITERATOR, ADD_ITERATOR_SIG);
121:
122: // Create the UnionIterator and leave it on the stack
123: il.append(new NEW(cpg.addClass(UNION_ITERATOR_CLASS)));
124: il.append(DUP);
125: il.append(methodGen.loadDOM());
126: il.append(new INVOKESPECIAL(init));
127:
128: // Add the various iterators to the UnionIterator
129: final int length = _components.length;
130: for (int i = 0; i < length; i++) {
131: _components[i].translate(classGen, methodGen);
132: il.append(new INVOKEVIRTUAL(iter));
133: }
134:
135: // Order the iterator only if strictly needed
136: if (_reverse) {
137: final int order = cpg.addInterfaceMethodref(DOM_INTF,
138: ORDER_ITERATOR, 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: }
|