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: Expression.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.BranchHandle; 027 import org.apache.bcel.generic.ConstantPoolGen; 028 import org.apache.bcel.generic.GOTO_W; 029 import org.apache.bcel.generic.IFEQ; 030 import org.apache.bcel.generic.InstructionHandle; 031 import org.apache.bcel.generic.InstructionList; 032 import org.apache.xalan.xsltc.compiler.util.BooleanType; 033 import org.apache.xalan.xsltc.compiler.util.ClassGenerator; 034 import org.apache.xalan.xsltc.compiler.util.ErrorMsg; 035 import org.apache.xalan.xsltc.compiler.util.MethodGenerator; 036 import org.apache.xalan.xsltc.compiler.util.MethodType; 037 import org.apache.xalan.xsltc.compiler.util.NodeSetType; 038 import org.apache.xalan.xsltc.compiler.util.Type; 039 import org.apache.xalan.xsltc.compiler.util.TypeCheckError; 040 041 /** 042 * @author Jacek Ambroziak 043 * @author Santiago Pericas-Geertsen 044 * @author Morten Jorgensen 045 * @author Erwin Bolwidt <ejb@klomp.org> 046 */ 047 abstract class Expression extends SyntaxTreeNode { 048 /** 049 * The type of this expression. It is set after calling 050 * <code>typeCheck()</code>. 051 */ 052 protected Type _type; 053 054 /** 055 * Instruction handles that comprise the true list. 056 */ 057 protected FlowList _trueList = new FlowList(); 058 059 /** 060 * Instruction handles that comprise the false list. 061 */ 062 protected FlowList _falseList = new FlowList(); 063 064 public Type getType() { 065 return _type; 066 } 067 068 public abstract String toString(); 069 070 public boolean hasPositionCall() { 071 return false; // default should be 'false' for StepPattern 072 } 073 074 public boolean hasLastCall() { 075 return false; 076 } 077 078 /** 079 * Returns an object representing the compile-time evaluation 080 * of an expression. We are only using this for function-available 081 * and element-available at this time. 082 */ 083 public Object evaluateAtCompileTime() { 084 return null; 085 } 086 087 /** 088 * Type check all the children of this node. 089 */ 090 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 091 return typeCheckContents(stable); 092 } 093 094 /** 095 * Translate this node into JVM bytecodes. 096 */ 097 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 098 ErrorMsg msg = new ErrorMsg(ErrorMsg.NOT_IMPLEMENTED_ERR, 099 getClass(), this); 100 getParser().reportError(FATAL, msg); 101 } 102 103 /** 104 * Translate this node into a fresh instruction list. 105 * The original instruction list is saved and restored. 106 */ 107 public final InstructionList compile(ClassGenerator classGen, 108 MethodGenerator methodGen) { 109 final InstructionList result, save = methodGen.getInstructionList(); 110 methodGen.setInstructionList(result = new InstructionList()); 111 translate(classGen, methodGen); 112 methodGen.setInstructionList(save); 113 return result; 114 } 115 116 /** 117 * Redefined by expressions of type boolean that use flow lists. 118 */ 119 public void translateDesynthesized(ClassGenerator classGen, 120 MethodGenerator methodGen) { 121 translate(classGen, methodGen); 122 if (_type instanceof BooleanType) { 123 desynthesize(classGen, methodGen); 124 } 125 } 126 127 /** 128 * If this expression is of type node-set and it is not a variable 129 * reference, then call setStartNode() passing the context node. 130 */ 131 public void startIterator(ClassGenerator classGen, 132 MethodGenerator methodGen) { 133 // Ignore if type is not node-set 134 if (_type instanceof NodeSetType == false) { 135 return; 136 } 137 138 // setStartNode() should not be called if expr is a variable ref 139 Expression expr = this; 140 if (expr instanceof CastExpr) { 141 expr = ((CastExpr) expr).getExpr(); 142 } 143 if (expr instanceof VariableRefBase == false) { 144 final InstructionList il = methodGen.getInstructionList(); 145 il.append(methodGen.loadContextNode()); 146 il.append(methodGen.setStartNode()); 147 } 148 } 149 150 /** 151 * Synthesize a boolean expression, i.e., either push a 0 or 1 onto the 152 * operand stack for the next statement to succeed. Returns the handle 153 * of the instruction to be backpatched. 154 */ 155 public void synthesize(ClassGenerator classGen, MethodGenerator methodGen) { 156 final ConstantPoolGen cpg = classGen.getConstantPool(); 157 final InstructionList il = methodGen.getInstructionList(); 158 _trueList.backPatch(il.append(ICONST_1)); 159 final BranchHandle truec = il.append(new GOTO_W(null)); 160 _falseList.backPatch(il.append(ICONST_0)); 161 truec.setTarget(il.append(NOP)); 162 } 163 164 public void desynthesize(ClassGenerator classGen, 165 MethodGenerator methodGen) { 166 final InstructionList il = methodGen.getInstructionList(); 167 _falseList.add(il.append(new IFEQ(null))); 168 } 169 170 public FlowList getFalseList() { 171 return _falseList; 172 } 173 174 public FlowList getTrueList() { 175 return _trueList; 176 } 177 178 public void backPatchFalseList(InstructionHandle ih) { 179 _falseList.backPatch(ih); 180 } 181 182 public void backPatchTrueList(InstructionHandle ih) { 183 _trueList.backPatch(ih); 184 } 185 186 /** 187 * Search for a primop in the symbol table that matches the method type 188 * <code>ctype</code>. Two methods match if they have the same arity. 189 * If a primop is overloaded then the "closest match" is returned. The 190 * first entry in the vector of primops that has the right arity is 191 * considered to be the default one. 192 */ 193 public MethodType lookupPrimop(SymbolTable stable, String op, 194 MethodType ctype) { 195 MethodType result = null; 196 final Vector primop = stable.lookupPrimop(op); 197 if (primop != null) { 198 final int n = primop.size(); 199 int minDistance = Integer.MAX_VALUE; 200 for (int i = 0; i < n; i++) { 201 final MethodType ptype = (MethodType) primop.elementAt(i); 202 // Skip if different arity 203 if (ptype.argsCount() != ctype.argsCount()) { 204 continue; 205 } 206 207 // The first method with the right arity is the default 208 if (result == null) { 209 result = ptype; // default method 210 } 211 212 // Check if better than last one found 213 final int distance = ctype.distanceTo(ptype); 214 if (distance < minDistance) { 215 minDistance = distance; 216 result = ptype; 217 } 218 } 219 } 220 return result; 221 } 222 }