diff -r fd16c54261b3 -r 7f561c08de6b jaxp/src/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Expression.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/src/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Expression.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,224 @@ +/* + * reserved comment block + * DO NOT REMOVE OR ALTER! + */ +/* + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * $Id: Expression.java,v 1.2.4.1 2005/09/01 14:17:51 pvedula Exp $ + */ + +package com.sun.org.apache.xalan.internal.xsltc.compiler; + +import java.util.Vector; + +import com.sun.org.apache.bcel.internal.generic.BranchHandle; +import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; +import com.sun.org.apache.bcel.internal.generic.GOTO_W; +import com.sun.org.apache.bcel.internal.generic.IFEQ; +import com.sun.org.apache.bcel.internal.generic.InstructionHandle; +import com.sun.org.apache.bcel.internal.generic.InstructionList; +import com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType; +import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; +import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; +import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; +import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType; +import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType; +import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; +import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; + +/** + * @author Jacek Ambroziak + * @author Santiago Pericas-Geertsen + * @author Morten Jorgensen + * @author Erwin Bolwidt + */ +abstract class Expression extends SyntaxTreeNode { + /** + * The type of this expression. It is set after calling + * typeCheck(). + */ + protected Type _type; + + /** + * Instruction handles that comprise the true list. + */ + protected FlowList _trueList = new FlowList(); + + /** + * Instruction handles that comprise the false list. + */ + protected FlowList _falseList = new FlowList(); + + public Type getType() { + return _type; + } + + public abstract String toString(); + + public boolean hasPositionCall() { + return false; // default should be 'false' for StepPattern + } + + public boolean hasLastCall() { + return false; + } + + /** + * Returns an object representing the compile-time evaluation + * of an expression. We are only using this for function-available + * and element-available at this time. + */ + public Object evaluateAtCompileTime() { + return null; + } + + /** + * Type check all the children of this node. + */ + public Type typeCheck(SymbolTable stable) throws TypeCheckError { + return typeCheckContents(stable); + } + + /** + * Translate this node into JVM bytecodes. + */ + public void translate(ClassGenerator classGen, MethodGenerator methodGen) { + ErrorMsg msg = new ErrorMsg(ErrorMsg.NOT_IMPLEMENTED_ERR, + getClass(), this); + getParser().reportError(FATAL, msg); + } + + /** + * Translate this node into a fresh instruction list. + * The original instruction list is saved and restored. + */ + public final InstructionList compile(ClassGenerator classGen, + MethodGenerator methodGen) { + final InstructionList result, save = methodGen.getInstructionList(); + methodGen.setInstructionList(result = new InstructionList()); + translate(classGen, methodGen); + methodGen.setInstructionList(save); + return result; + } + + /** + * Redefined by expressions of type boolean that use flow lists. + */ + public void translateDesynthesized(ClassGenerator classGen, + MethodGenerator methodGen) { + translate(classGen, methodGen); + if (_type instanceof BooleanType) { + desynthesize(classGen, methodGen); + } + } + + /** + * If this expression is of type node-set and it is not a variable + * reference, then call setStartNode() passing the context node. + */ + public void startIterator(ClassGenerator classGen, + MethodGenerator methodGen) { + // Ignore if type is not node-set + if (_type instanceof NodeSetType == false) { + return; + } + + // setStartNode() should not be called if expr is a variable ref + Expression expr = this; + if (expr instanceof CastExpr) { + expr = ((CastExpr) expr).getExpr(); + } + if (expr instanceof VariableRefBase == false) { + final InstructionList il = methodGen.getInstructionList(); + il.append(methodGen.loadContextNode()); + il.append(methodGen.setStartNode()); + } + } + + /** + * Synthesize a boolean expression, i.e., either push a 0 or 1 onto the + * operand stack for the next statement to succeed. Returns the handle + * of the instruction to be backpatched. + */ + public void synthesize(ClassGenerator classGen, MethodGenerator methodGen) { + final ConstantPoolGen cpg = classGen.getConstantPool(); + final InstructionList il = methodGen.getInstructionList(); + _trueList.backPatch(il.append(ICONST_1)); + final BranchHandle truec = il.append(new GOTO_W(null)); + _falseList.backPatch(il.append(ICONST_0)); + truec.setTarget(il.append(NOP)); + } + + public void desynthesize(ClassGenerator classGen, + MethodGenerator methodGen) { + final InstructionList il = methodGen.getInstructionList(); + _falseList.add(il.append(new IFEQ(null))); + } + + public FlowList getFalseList() { + return _falseList; + } + + public FlowList getTrueList() { + return _trueList; + } + + public void backPatchFalseList(InstructionHandle ih) { + _falseList.backPatch(ih); + } + + public void backPatchTrueList(InstructionHandle ih) { + _trueList.backPatch(ih); + } + + /** + * Search for a primop in the symbol table that matches the method type + * ctype. Two methods match if they have the same arity. + * If a primop is overloaded then the "closest match" is returned. The + * first entry in the vector of primops that has the right arity is + * considered to be the default one. + */ + public MethodType lookupPrimop(SymbolTable stable, String op, + MethodType ctype) { + MethodType result = null; + final Vector primop = stable.lookupPrimop(op); + if (primop != null) { + final int n = primop.size(); + int minDistance = Integer.MAX_VALUE; + for (int i = 0; i < n; i++) { + final MethodType ptype = (MethodType) primop.elementAt(i); + // Skip if different arity + if (ptype.argsCount() != ctype.argsCount()) { + continue; + } + + // The first method with the right arity is the default + if (result == null) { + result = ptype; // default method + } + + // Check if better than last one found + final int distance = ctype.distanceTo(ptype); + if (distance < minDistance) { + minDistance = distance; + result = ptype; + } + } + } + return result; + } +}