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
22package com.sun.org.apache.xalan.internal.xsltc.compiler;
23
24import com.sun.org.apache.bcel.internal.generic.BranchHandle;
25import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
26import com.sun.org.apache.bcel.internal.generic.GOTO;
27import com.sun.org.apache.bcel.internal.generic.IFEQ;
28import com.sun.org.apache.bcel.internal.generic.IF_ICMPEQ;
29import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
30import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
31import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
32import com.sun.org.apache.bcel.internal.generic.InstructionList;
33import com.sun.org.apache.bcel.internal.generic.PUSH;
34import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
35import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
36import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
37import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
38import com.sun.org.apache.xml.internal.dtm.Axis;
39import com.sun.org.apache.xml.internal.dtm.DTM;
40
41/**
42 * @author Morten Jorgensen
43 */
44final 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}
159