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: FilterParentPath.java 468650 2006-10-28 07:03:30Z minchau $ 020 */ 021 022 package org.apache.xalan.xsltc.compiler; 023 024 import org.apache.bcel.generic.ALOAD; 025 import org.apache.bcel.generic.ASTORE; 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.LocalVariableGen; 032 import org.apache.bcel.generic.NEW; 033 import org.apache.xalan.xsltc.compiler.util.ClassGenerator; 034 import org.apache.xalan.xsltc.compiler.util.MethodGenerator; 035 import org.apache.xalan.xsltc.compiler.util.NodeSetType; 036 import org.apache.xalan.xsltc.compiler.util.NodeType; 037 import org.apache.xalan.xsltc.compiler.util.ReferenceType; 038 import org.apache.xalan.xsltc.compiler.util.Type; 039 import org.apache.xalan.xsltc.compiler.util.TypeCheckError; 040 import org.apache.xalan.xsltc.compiler.util.Util; 041 042 /** 043 * @author Jacek Ambroziak 044 * @author Santiago Pericas-Geertsen 045 */ 046 final class FilterParentPath extends Expression { 047 048 private Expression _filterExpr; 049 private Expression _path; 050 private boolean _hasDescendantAxis = false; 051 052 public FilterParentPath(Expression filterExpr, Expression path) { 053 (_path = path).setParent(this); 054 (_filterExpr = filterExpr).setParent(this); 055 } 056 057 public void setParser(Parser parser) { 058 super.setParser(parser); 059 _filterExpr.setParser(parser); 060 _path.setParser(parser); 061 } 062 063 public String toString() { 064 return "FilterParentPath(" + _filterExpr + ", " + _path + ')'; 065 } 066 067 public void setDescendantAxis() { 068 _hasDescendantAxis = true; 069 } 070 071 /** 072 * Type check a FilterParentPath. If the filter is not a node-set add a 073 * cast to node-set only if it is of reference type. This type coercion is 074 * needed for expressions like $x/LINE where $x is a parameter reference. 075 */ 076 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 077 final Type ftype = _filterExpr.typeCheck(stable); 078 if (ftype instanceof NodeSetType == false) { 079 if (ftype instanceof ReferenceType) { 080 _filterExpr = new CastExpr(_filterExpr, Type.NodeSet); 081 } 082 /* 083 else if (ftype instanceof ResultTreeType) { 084 _filterExpr = new CastExpr(_filterExpr, Type.NodeSet); 085 } 086 */ 087 else if (ftype instanceof NodeType) { 088 _filterExpr = new CastExpr(_filterExpr, Type.NodeSet); 089 } 090 else { 091 throw new TypeCheckError(this); 092 } 093 } 094 095 // Wrap single node path in a node set 096 final Type ptype = _path.typeCheck(stable); 097 if (!(ptype instanceof NodeSetType)) { 098 _path = new CastExpr(_path, Type.NodeSet); 099 } 100 101 return _type = Type.NodeSet; 102 } 103 104 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 105 final ConstantPoolGen cpg = classGen.getConstantPool(); 106 final InstructionList il = methodGen.getInstructionList(); 107 // Create new StepIterator 108 final int initSI = cpg.addMethodref(STEP_ITERATOR_CLASS, 109 "<init>", 110 "(" 111 +NODE_ITERATOR_SIG 112 +NODE_ITERATOR_SIG 113 +")V"); 114 115 // Backwards branches are prohibited if an uninitialized object is 116 // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed. 117 // We don't know whether this code might contain backwards branches, 118 // so we mustn't create the new object until after we've created 119 // the suspect arguments to its constructor. Instead we calculate 120 // the values of the arguments to the constructor first, store them 121 // in temporary variables, create the object and reload the 122 // arguments from the temporaries to avoid the problem. 123 124 // Recursively compile 2 iterators 125 _filterExpr.translate(classGen, methodGen); 126 LocalVariableGen filterTemp = 127 methodGen.addLocalVariable("filter_parent_path_tmp1", 128 Util.getJCRefType(NODE_ITERATOR_SIG), 129 null, null); 130 filterTemp.setStart(il.append(new ASTORE(filterTemp.getIndex()))); 131 132 _path.translate(classGen, methodGen); 133 LocalVariableGen pathTemp = 134 methodGen.addLocalVariable("filter_parent_path_tmp2", 135 Util.getJCRefType(NODE_ITERATOR_SIG), 136 null, null); 137 pathTemp.setStart(il.append(new ASTORE(pathTemp.getIndex()))); 138 139 il.append(new NEW(cpg.addClass(STEP_ITERATOR_CLASS))); 140 il.append(DUP); 141 filterTemp.setEnd(il.append(new ALOAD(filterTemp.getIndex()))); 142 pathTemp.setEnd(il.append(new ALOAD(pathTemp.getIndex()))); 143 144 // Initialize StepIterator with iterators from the stack 145 il.append(new INVOKESPECIAL(initSI)); 146 147 // This is a special case for the //* path with or without predicates 148 if (_hasDescendantAxis) { 149 final int incl = cpg.addMethodref(NODE_ITERATOR_BASE, 150 "includeSelf", 151 "()" + NODE_ITERATOR_SIG); 152 il.append(new INVOKEVIRTUAL(incl)); 153 } 154 155 SyntaxTreeNode parent = getParent(); 156 157 boolean parentAlreadyOrdered = 158 (parent instanceof RelativeLocationPath) 159 || (parent instanceof FilterParentPath) 160 || (parent instanceof KeyCall) 161 || (parent instanceof CurrentCall) 162 || (parent instanceof DocumentCall); 163 164 if (!parentAlreadyOrdered) { 165 final int order = cpg.addInterfaceMethodref(DOM_INTF, 166 ORDER_ITERATOR, 167 ORDER_ITERATOR_SIG); 168 il.append(methodGen.loadDOM()); 169 il.append(SWAP); 170 il.append(methodGen.loadContextNode()); 171 il.append(new INVOKEINTERFACE(order, 3)); 172 } 173 } 174 }