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 }