1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Licensed to the Apache Software Foundation (ASF) under one or more 6 * contributor license agreements. See the NOTICE file distributed with 7 * this work for additional information regarding copyright ownership. 8 * The ASF licenses this file to You under the Apache License, Version 2.0 9 * (the "License"); you may not use this file except in compliance with 10 * the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 package com.sun.org.apache.xalan.internal.xsltc.compiler; 22 23 import com.sun.org.apache.bcel.internal.generic.BranchHandle; 24 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; 25 import com.sun.org.apache.bcel.internal.generic.GOTO_W; 26 import com.sun.org.apache.bcel.internal.generic.IFEQ; 27 import com.sun.org.apache.bcel.internal.generic.InstructionHandle; 28 import com.sun.org.apache.bcel.internal.generic.InstructionList; 29 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType; 30 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; 31 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; 32 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; 33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType; 34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType; 35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; 36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; 37 import java.util.List; 38 39 /** 40 * @author Jacek Ambroziak 41 * @author Santiago Pericas-Geertsen 42 * @author Morten Jorgensen 43 * @author Erwin Bolwidt <ejb@klomp.org> 44 * @LastModified: Oct 2017 45 */ 46 abstract class Expression extends SyntaxTreeNode { 47 /** 48 * The type of this expression. It is set after calling 49 * <code>typeCheck()</code>. 50 */ 51 protected Type _type; 52 53 /** 54 * Instruction handles that comprise the true list. 55 */ 56 protected FlowList _trueList = new FlowList(); 57 58 /** 59 * Instruction handles that comprise the false list. 60 */ 61 protected FlowList _falseList = new FlowList(); 62 63 public Type getType() { 64 return _type; 65 } 66 67 public abstract String toString(); 68 69 public boolean hasPositionCall() { 70 return false; // default should be 'false' for StepPattern 71 } 72 73 public boolean hasLastCall() { 74 return false; 75 } 76 77 /** 78 * Returns an object representing the compile-time evaluation 79 * of an expression. We are only using this for function-available 80 * and element-available at this time. 81 */ 82 public Object evaluateAtCompileTime() { 83 return null; 84 } 85 86 /** 87 * Type check all the children of this node. 88 */ 89 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 90 return typeCheckContents(stable); 91 } 92 93 /** 94 * Translate this node into JVM bytecodes. 95 */ 96 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 97 ErrorMsg msg = new ErrorMsg(ErrorMsg.NOT_IMPLEMENTED_ERR, 98 getClass(), this); 99 getParser().reportError(FATAL, msg); 100 } 101 102 /** 103 * Translate this node into a fresh instruction list. 104 * The original instruction list is saved and restored. 105 */ 106 public final InstructionList compile(ClassGenerator classGen, 107 MethodGenerator methodGen) { 108 final InstructionList result, save = methodGen.getInstructionList(); 109 methodGen.setInstructionList(result = new InstructionList()); 110 translate(classGen, methodGen); 111 methodGen.setInstructionList(save); 112 return result; 113 } 114 115 /** 116 * Redefined by expressions of type boolean that use flow lists. 117 */ 118 public void translateDesynthesized(ClassGenerator classGen, 119 MethodGenerator methodGen) { 120 translate(classGen, methodGen); 121 if (_type instanceof BooleanType) { 122 desynthesize(classGen, methodGen); 123 } 124 } 125 126 /** 127 * If this expression is of type node-set and it is not a variable 128 * reference, then call setStartNode() passing the context node. 129 */ 130 public void startIterator(ClassGenerator classGen, 131 MethodGenerator methodGen) { 132 // Ignore if type is not node-set 133 if (_type instanceof NodeSetType == false) { 134 return; 135 } 136 137 // setStartNode() should not be called if expr is a variable ref 138 Expression expr = this; 139 if (expr instanceof CastExpr) { 140 expr = ((CastExpr) expr).getExpr(); 141 } 142 if (expr instanceof VariableRefBase == false) { 143 final InstructionList il = methodGen.getInstructionList(); 144 il.append(methodGen.loadContextNode()); 145 il.append(methodGen.setStartNode()); 146 } 147 } 148 149 /** 150 * Synthesize a boolean expression, i.e., either push a 0 or 1 onto the 151 * operand stack for the next statement to succeed. Returns the handle 152 * of the instruction to be backpatched. 153 */ 154 public void synthesize(ClassGenerator classGen, MethodGenerator methodGen) { 155 final ConstantPoolGen cpg = classGen.getConstantPool(); 156 final InstructionList il = methodGen.getInstructionList(); 157 _trueList.backPatch(il.append(ICONST_1)); 158 final BranchHandle truec = il.append(new GOTO_W(null)); 159 _falseList.backPatch(il.append(ICONST_0)); 160 truec.setTarget(il.append(NOP)); 161 } 162 163 public void desynthesize(ClassGenerator classGen, 164 MethodGenerator methodGen) { 165 final InstructionList il = methodGen.getInstructionList(); 166 _falseList.add(il.append(new IFEQ(null))); 167 } 168 169 public FlowList getFalseList() { 170 return _falseList; 171 } 172 173 public FlowList getTrueList() { 174 return _trueList; 175 } 176 177 public void backPatchFalseList(InstructionHandle ih) { 178 _falseList.backPatch(ih); 179 } 180 181 public void backPatchTrueList(InstructionHandle ih) { 182 _trueList.backPatch(ih); 183 } 184 185 /** 186 * Search for a primop in the symbol table that matches the method type 187 * <code>ctype</code>. Two methods match if they have the same arity. 188 * If a primop is overloaded then the "closest match" is returned. The 189 * first entry in the vector of primops that has the right arity is 190 * considered to be the default one. 191 */ 192 public MethodType lookupPrimop(SymbolTable stable, String op, 193 MethodType ctype) { 194 MethodType result = null; 195 final List<MethodType> primop = stable.lookupPrimop(op); 196 if (primop != null) { 197 final int n = primop.size(); 198 int minDistance = Integer.MAX_VALUE; 199 for (int i = 0; i < n; i++) { 200 final MethodType ptype = primop.get(i); 201 // Skip if different arity 202 if (ptype.argsCount() != ctype.argsCount()) { 203 continue; 204 } 205 206 // The first method with the right arity is the default 207 if (result == null) { 208 result = ptype; // default method 209 } 210 211 // Check if better than last one found 212 final int distance = ctype.distanceTo(ptype); 213 if (distance < minDistance) { 214 minDistance = distance; 215 result = ptype; 216 } 217 } 218 } 219 return result; 220 } 221 }