1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.xalan.internal.xsltc.compiler;
  23 
  24 import com.sun.org.apache.bcel.internal.generic.BranchHandle;
  25 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  26 import com.sun.org.apache.bcel.internal.generic.GOTO;
  27 import com.sun.org.apache.bcel.internal.generic.IFEQ;
  28 import com.sun.org.apache.bcel.internal.generic.IF_ICMPEQ;
  29 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  30 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  31 import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
  32 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  33 import com.sun.org.apache.bcel.internal.generic.PUSH;
  34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  37 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  38 import com.sun.org.apache.xml.internal.dtm.Axis;
  39 import com.sun.org.apache.xml.internal.dtm.DTM;
  40 
  41 /**
  42  * @author Morten Jorgensen
  43  */
  44 final class ProcessingInstructionPattern extends StepPattern {
  45 
  46     private String _name = null;
  47     private boolean _typeChecked = false;
  48 
  49     /**
  50      * Handles calls with no parameter (current node is implicit parameter).
  51      */
  52     public ProcessingInstructionPattern(String name) {
  53         super(Axis.CHILD, DTM.PROCESSING_INSTRUCTION_NODE, null);
  54         _name = name;
  55         //if (_name.equals("*")) _typeChecked = true; no wildcard allowed!
  56     }
  57 
  58     /**
  59      *
  60      */
  61      public double getDefaultPriority() {
  62         return (_name != null) ? 0.0 : -0.5;
  63      }
  64     public String toString() {
  65         if (_predicates == null)
  66             return "processing-instruction("+_name+")";
  67         else
  68             return "processing-instruction("+_name+")"+_predicates;
  69     }
  70 
  71     public void reduceKernelPattern() {
  72         _typeChecked = true;
  73     }
  74 
  75     public boolean isWildcard() {
  76         return false;
  77     }
  78 
  79     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  80         if (hasPredicates()) {
  81             // Type check all the predicates (e -> position() = e)
  82             final int n = _predicates.size();
  83             for (int i = 0; i < n; i++) {
  84                 final Predicate pred = (Predicate)_predicates.elementAt(i);
  85                 pred.typeCheck(stable);
  86             }
  87         }
  88         return Type.NodeSet;
  89     }
  90 
  91     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
  92         final ConstantPoolGen cpg = classGen.getConstantPool();
  93         final InstructionList il = methodGen.getInstructionList();
  94 
  95         // context node is on the stack
  96         int gname = cpg.addInterfaceMethodref(DOM_INTF,
  97                                               "getNodeName",
  98                                               "(I)Ljava/lang/String;");
  99         int cmp = cpg.addMethodref(STRING_CLASS,
 100                                    "equals", "(Ljava/lang/Object;)Z");
 101 
 102         // Push current node on the stack
 103         il.append(methodGen.loadCurrentNode());
 104         il.append(SWAP);
 105 
 106         // Overwrite current node with matching node
 107         il.append(methodGen.storeCurrentNode());
 108 
 109         // If pattern not reduced then check kernel
 110         if (!_typeChecked) {
 111             il.append(methodGen.loadCurrentNode());
 112             final int getType = cpg.addInterfaceMethodref(DOM_INTF,
 113                                                           "getExpandedTypeID",
 114                                                           "(I)I");
 115             il.append(methodGen.loadDOM());
 116             il.append(methodGen.loadCurrentNode());
 117             il.append(new INVOKEINTERFACE(getType, 2));
 118             il.append(new PUSH(cpg, DTM.PROCESSING_INSTRUCTION_NODE));
 119             _falseList.add(il.append(new IF_ICMPEQ(null)));
 120         }
 121 
 122         // Load the requested processing instruction name
 123         il.append(new PUSH(cpg, _name));
 124         // Load the current processing instruction's name
 125         il.append(methodGen.loadDOM());
 126         il.append(methodGen.loadCurrentNode());
 127         il.append(new INVOKEINTERFACE(gname, 2));
 128         // Compare the two strings
 129         il.append(new INVOKEVIRTUAL(cmp));
 130         _falseList.add(il.append(new IFEQ(null)));
 131 
 132         // Compile the expressions within the predicates
 133         if (hasPredicates()) {
 134             final int n = _predicates.size();
 135             for (int i = 0; i < n; i++) {
 136                 Predicate pred = (Predicate)_predicates.elementAt(i);
 137                 Expression exp = pred.getExpr();
 138                 exp.translateDesynthesized(classGen, methodGen);
 139                 _trueList.append(exp._trueList);
 140                 _falseList.append(exp._falseList);
 141             }
 142         }
 143 
 144         // Backpatch true list and restore current iterator/node
 145         InstructionHandle restore;
 146         restore = il.append(methodGen.storeCurrentNode());
 147         backPatchTrueList(restore);
 148         BranchHandle skipFalse = il.append(new GOTO(null));
 149 
 150         // Backpatch false list and restore current iterator/node
 151         restore = il.append(methodGen.storeCurrentNode());
 152         backPatchFalseList(restore);
 153         _falseList.add(il.append(new GOTO(null)));
 154 
 155         // True list falls through
 156         skipFalse.setTarget(il.append(NOP));
 157     }
 158 }