286N/A/*
286N/A * reserved comment block
286N/A * DO NOT REMOVE OR ALTER!
286N/A */
286N/A/*
286N/A * Copyright 2001-2005 The Apache Software Foundation.
286N/A *
286N/A * Licensed under the Apache License, Version 2.0 (the "License");
286N/A * you may not use this file except in compliance with the License.
286N/A * You may obtain a copy of the License at
286N/A *
286N/A * http://www.apache.org/licenses/LICENSE-2.0
286N/A *
286N/A * Unless required by applicable law or agreed to in writing, software
286N/A * distributed under the License is distributed on an "AS IS" BASIS,
286N/A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
286N/A * See the License for the specific language governing permissions and
286N/A * limitations under the License.
286N/A */
286N/A/*
286N/A * $Id: FilterParentPath.java,v 1.2.4.1 2005/09/12 10:24:55 pvedula Exp $
286N/A */
286N/A
286N/Apackage com.sun.org.apache.xalan.internal.xsltc.compiler;
286N/A
286N/Aimport com.sun.org.apache.bcel.internal.generic.ALOAD;
286N/Aimport com.sun.org.apache.bcel.internal.generic.ASTORE;
286N/Aimport com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
286N/Aimport com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
286N/Aimport com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
286N/Aimport com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
286N/Aimport com.sun.org.apache.bcel.internal.generic.InstructionList;
286N/Aimport com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
286N/Aimport com.sun.org.apache.bcel.internal.generic.NEW;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeType;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
286N/A
286N/A/**
286N/A * @author Jacek Ambroziak
286N/A * @author Santiago Pericas-Geertsen
286N/A */
286N/Afinal class FilterParentPath extends Expression {
286N/A
286N/A private Expression _filterExpr;
286N/A private Expression _path;
286N/A private boolean _hasDescendantAxis = false;
286N/A
286N/A public FilterParentPath(Expression filterExpr, Expression path) {
286N/A (_path = path).setParent(this);
286N/A (_filterExpr = filterExpr).setParent(this);
286N/A }
286N/A
286N/A public void setParser(Parser parser) {
286N/A super.setParser(parser);
286N/A _filterExpr.setParser(parser);
286N/A _path.setParser(parser);
286N/A }
286N/A
286N/A public String toString() {
286N/A return "FilterParentPath(" + _filterExpr + ", " + _path + ')';
286N/A }
286N/A
286N/A public void setDescendantAxis() {
286N/A _hasDescendantAxis = true;
286N/A }
286N/A
286N/A /**
286N/A * Type check a FilterParentPath. If the filter is not a node-set add a
286N/A * cast to node-set only if it is of reference type. This type coercion is
286N/A * needed for expressions like $x/LINE where $x is a parameter reference.
286N/A */
286N/A public Type typeCheck(SymbolTable stable) throws TypeCheckError {
286N/A final Type ftype = _filterExpr.typeCheck(stable);
286N/A if (ftype instanceof NodeSetType == false) {
286N/A if (ftype instanceof ReferenceType) {
286N/A _filterExpr = new CastExpr(_filterExpr, Type.NodeSet);
286N/A }
286N/A /*
286N/A else if (ftype instanceof ResultTreeType) {
286N/A _filterExpr = new CastExpr(_filterExpr, Type.NodeSet);
286N/A }
286N/A */
286N/A else if (ftype instanceof NodeType) {
286N/A _filterExpr = new CastExpr(_filterExpr, Type.NodeSet);
286N/A }
286N/A else {
286N/A throw new TypeCheckError(this);
286N/A }
286N/A }
286N/A
286N/A // Wrap single node path in a node set
286N/A final Type ptype = _path.typeCheck(stable);
286N/A if (!(ptype instanceof NodeSetType)) {
286N/A _path = new CastExpr(_path, Type.NodeSet);
286N/A }
286N/A
286N/A return _type = Type.NodeSet;
286N/A }
286N/A
286N/A public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
286N/A final ConstantPoolGen cpg = classGen.getConstantPool();
286N/A final InstructionList il = methodGen.getInstructionList();
286N/A // Create new StepIterator
286N/A final int initSI = cpg.addMethodref(STEP_ITERATOR_CLASS,
286N/A "<init>",
286N/A "("
286N/A +NODE_ITERATOR_SIG
286N/A +NODE_ITERATOR_SIG
286N/A +")V");
286N/A
286N/A // Backwards branches are prohibited if an uninitialized object is
286N/A // on the stack by section 4.9.4 of the JVM Specification, 2nd Ed.
286N/A // We don't know whether this code might contain backwards branches,
286N/A // so we mustn't create the new object until after we've created
286N/A // the suspect arguments to its constructor. Instead we calculate
286N/A // the values of the arguments to the constructor first, store them
286N/A // in temporary variables, create the object and reload the
286N/A // arguments from the temporaries to avoid the problem.
286N/A
286N/A // Recursively compile 2 iterators
286N/A _filterExpr.translate(classGen, methodGen);
286N/A LocalVariableGen filterTemp =
286N/A methodGen.addLocalVariable("filter_parent_path_tmp1",
286N/A Util.getJCRefType(NODE_ITERATOR_SIG),
286N/A null, null);
286N/A filterTemp.setStart(il.append(new ASTORE(filterTemp.getIndex())));
286N/A
286N/A _path.translate(classGen, methodGen);
286N/A LocalVariableGen pathTemp =
286N/A methodGen.addLocalVariable("filter_parent_path_tmp2",
286N/A Util.getJCRefType(NODE_ITERATOR_SIG),
286N/A null, null);
286N/A pathTemp.setStart(il.append(new ASTORE(pathTemp.getIndex())));
286N/A
286N/A il.append(new NEW(cpg.addClass(STEP_ITERATOR_CLASS)));
286N/A il.append(DUP);
286N/A filterTemp.setEnd(il.append(new ALOAD(filterTemp.getIndex())));
286N/A pathTemp.setEnd(il.append(new ALOAD(pathTemp.getIndex())));
286N/A
286N/A // Initialize StepIterator with iterators from the stack
286N/A il.append(new INVOKESPECIAL(initSI));
286N/A
286N/A // This is a special case for the //* path with or without predicates
286N/A if (_hasDescendantAxis) {
286N/A final int incl = cpg.addMethodref(NODE_ITERATOR_BASE,
286N/A "includeSelf",
286N/A "()" + NODE_ITERATOR_SIG);
286N/A il.append(new INVOKEVIRTUAL(incl));
286N/A }
286N/A
286N/A SyntaxTreeNode parent = getParent();
286N/A
286N/A boolean parentAlreadyOrdered =
286N/A (parent instanceof RelativeLocationPath)
286N/A || (parent instanceof FilterParentPath)
286N/A || (parent instanceof KeyCall)
286N/A || (parent instanceof CurrentCall)
286N/A || (parent instanceof DocumentCall);
286N/A
286N/A if (!parentAlreadyOrdered) {
286N/A final int order = cpg.addInterfaceMethodref(DOM_INTF,
286N/A ORDER_ITERATOR,
286N/A ORDER_ITERATOR_SIG);
286N/A il.append(methodGen.loadDOM());
286N/A il.append(SWAP);
286N/A il.append(methodGen.loadContextNode());
286N/A il.append(new INVOKEINTERFACE(order, 3));
286N/A }
286N/A }
286N/A}