FileDocCategorySizeDatePackage
Predicate.javaAPI DocJava SE 5 API19520Fri Aug 26 14:55:36 BST 2005com.sun.org.apache.xalan.internal.xsltc.compiler

Predicate

public final class Predicate extends Expression implements Closure
author
Jacek Ambroziak
author
Santiago Pericas-Geertsen
author
Morten Jorgensen

Fields Summary
private Expression
_exp
The predicate's expression.
private boolean
_canOptimize
This flag indicates if optimizations are turned on. The method dontOptimize() can be called to turn optimizations off.
private boolean
_nthPositionFilter
Flag indicatig if the nth position optimization is on. It is set in typeCheck().
private boolean
_nthDescendant
Flag indicatig if the nth position descendant is on. It is set in typeCheck().
int
_ptype
Cached node type of the expression that owns this predicate.
private String
_className
Name of the inner class.
private ArrayList
_closureVars
List of variables in closure.
private Closure
_parentClosure
Reference to parent closure.
private Expression
_value
Cached value of method getCompareValue().
private Step
_step
Cached value of method getCompareValue().
Constructors Summary
public Predicate(Expression exp)
Initializes a predicate.


             
       
        _exp = exp;
        _exp.setParent(this);

    
Methods Summary
public voidaddVariable(com.sun.org.apache.xalan.internal.xsltc.compiler.VariableRefBase variableRef)
Add new variable to the closure.

	if (_closureVars == null) {
	    _closureVars = new ArrayList();
	}

	// Only one reference per variable
	if (!_closureVars.contains(variableRef)) {
	    _closureVars.add(variableRef);

	    // Add variable to parent closure as well
	    Closure parentClosure = getParentClosure();
	    if (parentClosure != null) {
		parentClosure.addVariable(variableRef);
	    }
	}
    
private voidcompileFilter(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)
Create a new "Filter" class implementing CurrentNodeListFilter. Allocate registers for local variables and local parameters passed in the closure to test(). Notice that local variables need to be "unboxed".

	TestGenerator testGen;
	LocalVariableGen local;
	FilterGenerator filterGen;

	_className = getXSLTC().getHelperClassName();
	filterGen = new FilterGenerator(_className,
					"java.lang.Object",
					toString(), 
					ACC_PUBLIC | ACC_SUPER,
					new String[] {
					    CURRENT_NODE_LIST_FILTER
					},
					classGen.getStylesheet());	

	final ConstantPoolGen cpg = filterGen.getConstantPool();
	final int length = (_closureVars == null) ? 0 : _closureVars.size();

	// Add a new instance variable for each var in closure
	for (int i = 0; i < length; i++) {
	    VariableBase var = ((VariableRefBase) _closureVars.get(i)).getVariable();

	    filterGen.addField(new Field(ACC_PUBLIC, 
					cpg.addUtf8(var.getEscapedName()),
					cpg.addUtf8(var.getType().toSignature()),
					null, cpg.getConstantPool()));
	}

	final InstructionList il = new InstructionList();
	testGen = new TestGenerator(ACC_PUBLIC | ACC_FINAL,
				    com.sun.org.apache.bcel.internal.generic.Type.BOOLEAN, 
				    new com.sun.org.apache.bcel.internal.generic.Type[] {
					com.sun.org.apache.bcel.internal.generic.Type.INT,
					com.sun.org.apache.bcel.internal.generic.Type.INT,
					com.sun.org.apache.bcel.internal.generic.Type.INT,
					com.sun.org.apache.bcel.internal.generic.Type.INT,
					Util.getJCRefType(TRANSLET_SIG),
					Util.getJCRefType(NODE_ITERATOR_SIG)
				    },
				    new String[] {
					"node",
					"position",
					"last",
					"current",
					"translet",
					"iterator"
				    },
				    "test", _className, il, cpg);
		
	// Store the dom in a local variable
	local = testGen.addLocalVariable("document",
					 Util.getJCRefType(DOM_INTF_SIG),
					 null, null);
	final String className = classGen.getClassName();
	il.append(filterGen.loadTranslet());
	il.append(new CHECKCAST(cpg.addClass(className)));
	il.append(new GETFIELD(cpg.addFieldref(className,
					       DOM_FIELD, DOM_INTF_SIG)));
	il.append(new ASTORE(local.getIndex()));

	// Store the dom index in the test generator
	testGen.setDomIndex(local.getIndex());

	_exp.translate(filterGen, testGen);
	il.append(IRETURN);
	
	testGen.stripAttributes(true);
	testGen.setMaxLocals();
	testGen.setMaxStack();
	testGen.removeNOPs();
	filterGen.addEmptyConstructor(ACC_PUBLIC);
	filterGen.addMethod(testGen.getMethod());
		
	getXSLTC().dumpClass(filterGen.getJavaClass());
    
public voiddontOptimize()
Turns off all optimizations for this predicate.

	_canOptimize = false;
    
public com.sun.org.apache.xalan.internal.xsltc.compiler.ExpressiongetCompareValue()
Returns the value in an expression of the form 'step = value'. A value may be either a literal string or a variable whose type is string. Optimization if off if null is returned.

        // Returned cached value if called more than once
	if (_value != null) {
            return _value;
        }
        
        // Nothing to to do if _exp is null
	if (_exp == null) {
            return null;
        }

        // Ignore if not an equality expression
	if (_exp instanceof EqualityExpr) {
	    EqualityExpr exp = (EqualityExpr) _exp;
	    Expression left = exp.getLeft();
	    Expression right = exp.getRight();
            
            // Return if left is literal string
            if (left instanceof LiteralExpr) {
                _value = left;
                return _value;
            }
            // Return if left is a variable reference of type string
            if (left instanceof VariableRefBase &&
                left.getType() == Type.String) 
            {
                _value = left;
                return _value;
            }
            
            // Return if right is literal string
            if (right instanceof LiteralExpr) {
                _value = right;
                return _value;
            }
            // Return if left is a variable reference whose type is string
            if (right instanceof VariableRefBase &&
                right.getType() == Type.String) 
            {
                _value = right;
                return _value;
            }
	}
	return null;
    
public com.sun.org.apache.xalan.internal.xsltc.compiler.ExpressiongetExpr()

	return _exp;
    
public java.lang.StringgetInnerClassName()
Returns the name of the auxiliary class or null if this predicate is compiled inside the Translet.

	return _className;
    
public com.sun.org.apache.xalan.internal.xsltc.compiler.ClosuregetParentClosure()
Returns a reference to its parent closure or null if outermost.

	if (_parentClosure == null) {
	    SyntaxTreeNode node = getParent();
	    do {
		if (node instanceof Closure) {
		    _parentClosure = (Closure) node;
		    break;
		}
		if (node instanceof TopLevelElement) {
		    break;	// way up in the tree
		}
		node = node.getParent();
	    } while (node != null);
	}
	return _parentClosure;
    
public intgetPosType()
Returns the node type of the expression owning this predicate. The return value is cached in _ptype.

	if (_ptype == -1) {
	    SyntaxTreeNode parent = getParent();
	    if (parent instanceof StepPattern) {
		_ptype = ((StepPattern)parent).getNodeType();
	    }
	    else if (parent instanceof AbsoluteLocationPath) {
		AbsoluteLocationPath path = (AbsoluteLocationPath)parent;
		Expression exp = path.getPath();
		if (exp instanceof Step) {
		    _ptype = ((Step)exp).getNodeType();
		}
	    }
	    else if (parent instanceof VariableRefBase) {
		final VariableRefBase ref = (VariableRefBase)parent;
		final VariableBase var = ref.getVariable();
		final Expression exp = var.getExpression();
		if (exp instanceof Step) {
		    _ptype = ((Step)exp).getNodeType();
		}
	    }
	    else if (parent instanceof Step) {
		_ptype = ((Step)parent).getNodeType();
	    }
	}
	return _ptype;
    
public com.sun.org.apache.xalan.internal.xsltc.compiler.StepgetStep()
Returns the step in an expression of the form 'step = value'. Null is returned if the expression is not of the right form. Optimization if off if null is returned.

        // Returned cached value if called more than once
	if (_step != null) {
            return _step;
        }
        
        // Nothing to do if _exp is null
	if (_exp == null) {
            return null;
        }

        // Ignore if not equality expression
	if (_exp instanceof EqualityExpr) {
	    EqualityExpr exp = (EqualityExpr)_exp;
	    Expression left = exp.getLeft();
	    Expression right = exp.getRight();

            // Unwrap and set _step if appropriate
	    if (left instanceof CastExpr) {
                left = ((CastExpr) left).getExpr();
            }
	    if (left instanceof Step) {
                _step = (Step) left;
            }
	    
            // Unwrap and set _step if appropriate
	    if (right instanceof CastExpr) {
                right = ((CastExpr)right).getExpr();
            }
	    if (right instanceof Step) {
                _step = (Step)right;
            }
	}
	return _step;
    
public booleanhasLastCall()
Returns true if the expression in this predicate contains a call to last().

	return _exp.hasLastCall();
    
public booleanhasPositionCall()
Returns true if the expression in this predicate contains a call to position().

	return _exp.hasPositionCall();
    
public booleaninInnerClass()
Returns true if this closure is compiled in an inner class (i.e. if this is a real closure).

	return (_className != null);
    
public booleanisBooleanTest()
Returns true if the predicate is a test for the existance of an element or attribute. All we have to do is to get the first node from the step, check if it is there, and then return true/false.

	return (_exp instanceof BooleanExpr);
    
public booleanisNodeValueTest()
Method to see if we can optimise the predicate by using a specialised iterator for expressions like '/foo/bar[@attr = $var]', which are very common in many stylesheets

	if (!_canOptimize) return false;
	return (getStep() != null && getCompareValue() != null);
    
public booleanisNthDescendant()
Returns a boolean value indicating if the nth descendant optimization is on. Must be call after type checking!

	return _nthDescendant;
    
public booleanisNthPositionFilter()
Returns a boolean value indicating if the nth position optimization is on. Must be call after type checking!

	return _nthPositionFilter;
    
public booleanparentIsPattern()

	return (getParent() instanceof Pattern);
    
public voidsetParser(com.sun.org.apache.xalan.internal.xsltc.compiler.Parser parser)
Set the parser for this expression.

	super.setParser(parser);
	_exp.setParser(parser);
    
public java.lang.StringtoString()

        return "pred(" + _exp + ')";
    
public voidtranslate(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)
Translate a predicate expression. If non of the optimizations apply then this translation pushes two references on the stack: a reference to a newly created filter object and a reference to the predicate's closure. See class Step for further details.


	final ConstantPoolGen cpg = classGen.getConstantPool();
	final InstructionList il = methodGen.getInstructionList();

	if (_nthPositionFilter || _nthDescendant) {
	    _exp.translate(classGen, methodGen);
	}
	else if (isNodeValueTest() && (getParent() instanceof Step)) {
	    _value.translate(classGen, methodGen);
	    il.append(new CHECKCAST(cpg.addClass(STRING_CLASS)));
	    il.append(new PUSH(cpg, ((EqualityExpr)_exp).getOp()));
	}
	else {
	    translateFilter(classGen, methodGen);
	}
    
public voidtranslateFilter(com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator classGen, com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator methodGen)
Translate a predicate expression. This translation pushes two references on the stack: a reference to a newly created filter object and a reference to the predicate's closure.

	final ConstantPoolGen cpg = classGen.getConstantPool();
	final InstructionList il = methodGen.getInstructionList();

	// Compile auxiliary class for filter
	compileFilter(classGen, methodGen);
	
	// Create new instance of filter
	il.append(new NEW(cpg.addClass(_className)));
	il.append(DUP);
	il.append(new INVOKESPECIAL(cpg.addMethodref(_className,
						     "<init>", "()V")));

	// Initialize closure variables
	final int length = (_closureVars == null) ? 0 : _closureVars.size();

	for (int i = 0; i < length; i++) {
	    VariableRefBase varRef = (VariableRefBase) _closureVars.get(i);
	    VariableBase var = varRef.getVariable();
	    Type varType = var.getType();

	    il.append(DUP);

	    // Find nearest closure implemented as an inner class
	    Closure variableClosure = _parentClosure;
	    while (variableClosure != null) {
		if (variableClosure.inInnerClass()) break;
		variableClosure = variableClosure.getParentClosure();
	    }

	    // Use getfield if in an inner class
	    if (variableClosure != null) {
		il.append(ALOAD_0);
		il.append(new GETFIELD(
		    cpg.addFieldref(variableClosure.getInnerClassName(), 
			var.getEscapedName(), varType.toSignature())));
	    }
	    else {
		// Use a load of instruction if in translet class
		il.append(var.loadInstruction());
	    }

	    // Store variable in new closure
	    il.append(new PUTFIELD(
		    cpg.addFieldref(_className, var.getEscapedName(), 
			varType.toSignature())));
	}
    
public com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypetypeCheck(com.sun.org.apache.xalan.internal.xsltc.compiler.SymbolTable stable)
Type check a predicate expression. If the type of the expression is number convert it to boolean by adding a comparison with position(). Note that if the expression is a parameter, we cannot distinguish at compile time if its type is number or not. Hence, expressions of reference type are always converted to booleans. This method may be called twice, before and after calling dontOptimize(). If so, the second time it should honor the new value of _canOptimize.

        
	Type texp = _exp.typeCheck(stable);

	// We need explicit type information for reference types - no good!
	if (texp instanceof ReferenceType) {
	    _exp = new CastExpr(_exp, texp = Type.Real);
	}

	// A result tree fragment should not be cast directly to a number type,
	// but rather to a boolean value, and then to a numer (0 or 1).
	// Ref. section 11.2 of the XSLT 1.0 spec
	if (texp instanceof ResultTreeType) {
	    _exp = new CastExpr(_exp, Type.Boolean);
	    _exp = new CastExpr(_exp, Type.Real);
	    texp = _exp.typeCheck(stable);
	}

	// Numerical types will be converted to a position filter
	if (texp instanceof NumberType) {
	    // Cast any numerical types to an integer
	    if (texp instanceof IntType == false) {
		_exp = new CastExpr(_exp, Type.Int);
	    }
                    
            if (_canOptimize) {
                // Nth position optimization. Expression must not depend on context
                _nthPositionFilter = 
                    !_exp.hasLastCall() && !_exp.hasPositionCall();
                
                // _nthDescendant optimization - only if _nthPositionFilter is on
                if (_nthPositionFilter) {
                    SyntaxTreeNode parent = getParent();
                    _nthDescendant = (parent instanceof Step) &&
                        (parent.getParent() instanceof AbsoluteLocationPath);
                    return _type = Type.NodeSet;
                }
            }          

           // Reset optimization flags
            _nthPositionFilter = _nthDescendant = false;
            
           // Otherwise, expand [e] to [position() = e]
           final QName position = 
                getParser().getQNameIgnoreDefaultNs("position");
           final PositionCall positionCall =
                new PositionCall(position);
           positionCall.setParser(getParser());
           positionCall.setParent(this);

           _exp = new EqualityExpr(EqualityExpr.EQ, positionCall,
                                    _exp);
           if (_exp.typeCheck(stable) != Type.Boolean) {
               _exp = new CastExpr(_exp, Type.Boolean);
           }
           return _type = Type.Boolean;
	}
	else {
            // All other types will be handled as boolean values
	    if (texp instanceof BooleanType == false) {
		_exp = new CastExpr(_exp, Type.Boolean);
            }
            return _type = Type.Boolean;
	}