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: IdKeyPattern.java 1225842 2011-12-30 15:14:35Z mrglavas $
020     */
021    
022    package org.apache.xalan.xsltc.compiler;
023    
024    import org.apache.bcel.generic.ConstantPoolGen;
025    import org.apache.bcel.generic.GOTO;
026    import org.apache.bcel.generic.IFNE;
027    import org.apache.bcel.generic.INVOKEVIRTUAL;
028    import org.apache.bcel.generic.InstructionList;
029    import org.apache.bcel.generic.PUSH;
030    import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
031    import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
032    import org.apache.xalan.xsltc.compiler.util.Type;
033    import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
034    
035    /**
036     * @author Jacek Ambroziak
037     * @author Santiago Pericas-Geertsen
038     */
039    abstract class IdKeyPattern extends LocationPathPattern {
040    
041        protected RelativePathPattern _left = null;;
042        private String _index = null;
043        private String _value = null;;
044    
045        public IdKeyPattern(String index, String value) {
046            _index = index;
047            _value = value;
048        }
049    
050        public String getIndexName() {
051            return(_index);
052        }
053    
054        public Type typeCheck(SymbolTable stable) throws TypeCheckError {
055            return Type.NodeSet;
056        }
057        
058        public boolean isWildcard() {
059            return false;
060        }
061        
062        public void setLeft(RelativePathPattern left) {
063            _left = left;
064        }
065    
066        public StepPattern getKernelPattern() {
067            return(null);
068        }
069        
070        public void reduceKernelPattern() { }
071    
072        public String toString() {
073            return "id/keyPattern(" + _index + ", " + _value + ')';
074        }
075    
076        /**
077         * This method is called when the constructor is compiled in
078         * Stylesheet.compileConstructor() and not as the syntax tree is traversed.
079         */
080        public void translate(ClassGenerator classGen,
081                              MethodGenerator methodGen) {
082    
083            final ConstantPoolGen cpg = classGen.getConstantPool();
084            final InstructionList il = methodGen.getInstructionList();
085    
086            // Returns the KeyIndex object of a given name
087            final int getKeyIndex = cpg.addMethodref(TRANSLET_CLASS,
088                                                     "getKeyIndex",
089                                                     "(Ljava/lang/String;)"+
090                                                     KEY_INDEX_SIG);
091            
092            // Initialises a KeyIndex to return nodes with specific values
093            final int lookupId = cpg.addMethodref(KEY_INDEX_CLASS,
094                                                  "containsID",
095                                                  "(ILjava/lang/Object;)I");
096            final int lookupKey = cpg.addMethodref(KEY_INDEX_CLASS,
097                                                   "containsKey",
098                                                   "(ILjava/lang/Object;)I");
099            final int getNodeIdent = cpg.addInterfaceMethodref(DOM_INTF,
100                                                               "getNodeIdent",
101                                                               "(I)"+NODE_SIG);                                    
102    
103            // Call getKeyIndex in AbstractTranslet with the name of the key
104            // to get the index for this key (which is also a node iterator).
105            il.append(classGen.loadTranslet());
106            il.append(new PUSH(cpg,_index));
107            il.append(new INVOKEVIRTUAL(getKeyIndex));
108            
109            // Now use the value in the second argument to determine what nodes
110            // the iterator should return.
111            il.append(SWAP);
112            il.append(new PUSH(cpg,_value));
113            if (this instanceof IdPattern)
114            {
115                il.append(new INVOKEVIRTUAL(lookupId));
116            }
117            else
118            {
119                il.append(new INVOKEVIRTUAL(lookupKey));
120            }
121    
122            _trueList.add(il.append(new IFNE(null)));
123            _falseList.add(il.append(new GOTO(null)));
124        }
125    
126    }
127