2
* Licensed to the Apache Software Foundation (ASF) under one
3
* or more contributor license agreements. See the NOTICE file
4
* distributed with this work for additional information
5
* regarding copyright ownership. The ASF licenses this file
6
* to you under the Apache License, Version 2.0 (the "License");
7
* you may not use this file except in compliance with the License.
8
* You may obtain a copy of the License at
10
* http://www.apache.org/licenses/LICENSE-2.0
12
* Unless required by applicable law or agreed to in writing, software
13
* distributed under the License is distributed on an "AS IS" BASIS,
14
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
* See the License for the specific language governing permissions and
16
* limitations under the License.
19
* $Id: KeyCall.java,v 1.2 2009/12/10 03:18:18 matthewoliver Exp $
22
package org.apache.xalan.xsltc.compiler;
24
import java.util.Vector;
26
import org.apache.bcel.generic.ALOAD;
27
import org.apache.bcel.generic.ASTORE;
28
import org.apache.bcel.generic.BranchHandle;
29
import org.apache.bcel.generic.ConstantPoolGen;
30
import org.apache.bcel.generic.GOTO;
31
import org.apache.bcel.generic.IFGT;
32
import org.apache.bcel.generic.INVOKEINTERFACE;
33
import org.apache.bcel.generic.INVOKESPECIAL;
34
import org.apache.bcel.generic.INVOKEVIRTUAL;
35
import org.apache.bcel.generic.InstructionHandle;
36
import org.apache.bcel.generic.InstructionList;
37
import org.apache.bcel.generic.LocalVariableGen;
38
import org.apache.bcel.generic.NEW;
39
import org.apache.bcel.generic.PUSH;
40
import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
41
import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
42
import org.apache.xalan.xsltc.compiler.util.StringType;
43
import org.apache.xalan.xsltc.compiler.util.Type;
44
import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
45
import org.apache.xalan.xsltc.compiler.util.Util;
48
* @author Morten Jorgensen
49
* @author Santiago Pericas-Geertsen
51
final class KeyCall extends FunctionCall {
54
* The name of the key.
56
private Expression _name;
59
* The value to look up in the key/index.
61
private Expression _value;
64
* The value's data type.
66
private Type _valueType; // The value's data type
69
* Expanded qname when name is literal.
71
private QName _resolvedQName = null;
74
* Get the parameters passed to function:
75
* key(String name, String value)
76
* key(String name, NodeSet value)
77
* The 'arguments' vector should contain two parameters for key() calls,
78
* one holding the key name and one holding the value(s) to look up. The
79
* vector has only one parameter for id() calls (the key name is always
80
* "##id" for id() calls).
82
* @param fname The function name (should be 'key' or 'id')
83
* @param arguments A vector containing the arguments the the function
85
public KeyCall(QName fname, Vector arguments) {
86
super(fname, arguments);
87
switch(argumentCount()) {
97
_name = _value = null;
103
* If this call to key() is in a top-level element like another variable
104
* or param, add a dependency between that top-level element and the
105
* referenced key. For example,
107
* <xsl:key name="x" .../>
108
* <xsl:variable name="y" select="key('x', 1)"/>
110
* and assuming this class represents "key('x', 1)", add a reference
111
* between variable y and key x. Note that if 'x' is unknown statically
112
* in key('x', 1), there's nothing we can do at this point.
114
public void addParentDependency() {
115
// If name unknown statically, there's nothing we can do
116
if (_resolvedQName == null) return;
118
SyntaxTreeNode node = this;
119
while (node != null && node instanceof TopLevelElement == false) {
120
node = node.getParent();
123
TopLevelElement parent = (TopLevelElement) node;
124
if (parent != null) {
125
parent.addDependency(getSymbolTable().getKey(_resolvedQName));
130
* Type check the parameters for the id() or key() function.
131
* The index name (for key() call only) must be a string or convertable
132
* to a string, and the lookup-value must be a string or a node-set.
133
* @param stable The parser's symbol table
134
* @throws TypeCheckError When the parameters have illegal type
136
public Type typeCheck(SymbolTable stable) throws TypeCheckError {
137
final Type returnType = super.typeCheck(stable);
139
// Run type check on the key name (first argument) - must be a string,
140
// and if it is not it must be converted to one using string() rules.
142
final Type nameType = _name.typeCheck(stable);
144
if (_name instanceof LiteralExpr) {
145
final LiteralExpr literal = (LiteralExpr) _name;
147
getParser().getQNameIgnoreDefaultNs(literal.getValue());
149
else if (nameType instanceof StringType == false) {
150
_name = new CastExpr(_name, Type.String);
154
// Run type check on the value for this key. This value can be of
155
// any data type, so this should never cause any type-check errors.
156
// If the value is a reference, then we have to defer the decision
157
// of how to process it until run-time.
158
// If the value is known not to be a node-set, then it should be
159
// converted to a string before the lookup is done. If the value is
160
// known to be a node-set then this process (convert to string, then
161
// do lookup) should be applied to every node in the set, and the
162
// result from all lookups should be added to the resulting node-set.
163
_valueType = _value.typeCheck(stable);
165
if (_valueType != Type.NodeSet
166
&& _valueType != Type.Reference
167
&& _valueType != Type.String) {
168
_value = new CastExpr(_value, Type.String);
169
_valueType = _value.typeCheck(stable);
172
// If in a top-level element, create dependency to the referenced key
173
addParentDependency();
179
* This method is called when the constructor is compiled in
180
* Stylesheet.compileConstructor() and not as the syntax tree is traversed.
181
* <p>This method will generate byte code that produces an iterator
182
* for the nodes in the node set for the key or id function call.
183
* @param classGen The Java class generator
184
* @param methodGen The method generator
186
public void translate(ClassGenerator classGen,
187
MethodGenerator methodGen) {
188
final ConstantPoolGen cpg = classGen.getConstantPool();
189
final InstructionList il = methodGen.getInstructionList();
191
// Returns the KeyIndex object of a given name
192
final int getKeyIndex = cpg.addMethodref(TRANSLET_CLASS,
194
"(Ljava/lang/String;)"+
197
// KeyIndex.setDom(Dom) => void
198
final int keyDom = cpg.addMethodref(KEY_INDEX_CLASS,
200
"("+DOM_INTF_SIG+")V");
202
// Initialises a KeyIndex to return nodes with specific values
203
final int getKeyIterator =
204
cpg.addMethodref(KEY_INDEX_CLASS,
205
"getKeyIndexIterator",
206
"(" + _valueType.toSignature() + "Z)"
207
+ KEY_INDEX_ITERATOR_SIG);
209
// Initialise the index specified in the first parameter of key()
210
il.append(classGen.loadTranslet());
212
il.append(new PUSH(cpg,"##id"));
213
} else if (_resolvedQName != null) {
214
il.append(new PUSH(cpg, _resolvedQName.toString()));
216
_name.translate(classGen, methodGen);
219
// Generate following byte code:
221
// KeyIndex ki = translet.getKeyIndex(_name)
222
// ki.setDom(translet.dom);
223
// ki.getKeyIndexIterator(_value, true) - for key()
225
// ki.getKeyIndexIterator(_value, false) - for id()
226
il.append(new INVOKEVIRTUAL(getKeyIndex));
228
il.append(methodGen.loadDOM());
229
il.append(new INVOKEVIRTUAL(keyDom));
231
_value.translate(classGen, methodGen);
232
il.append((_name != null) ? ICONST_1: ICONST_0);
233
il.append(new INVOKEVIRTUAL(getKeyIterator));