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: ResultTreeType.java 468649 2006-10-28 07:00:55Z minchau $
020 */
021
022 package org.apache.xalan.xsltc.compiler.util;
023
024 import org.apache.bcel.generic.ALOAD;
025 import org.apache.bcel.generic.ASTORE;
026 import org.apache.bcel.generic.CHECKCAST;
027 import org.apache.bcel.generic.ConstantPoolGen;
028 import org.apache.bcel.generic.GETFIELD;
029 import org.apache.bcel.generic.IFEQ;
030 import org.apache.bcel.generic.INVOKEINTERFACE;
031 import org.apache.bcel.generic.INVOKESPECIAL;
032 import org.apache.bcel.generic.INVOKEVIRTUAL;
033 import org.apache.bcel.generic.Instruction;
034 import org.apache.bcel.generic.InstructionList;
035 import org.apache.bcel.generic.LocalVariableGen;
036 import org.apache.bcel.generic.NEW;
037 import org.apache.bcel.generic.PUSH;
038 import org.apache.xalan.xsltc.compiler.Constants;
039 import org.apache.xalan.xsltc.compiler.FlowList;
040
041 /**
042 * @author Jacek Ambroziak
043 * @author Santiago Pericas-Geertsen
044 * @author Morten Jorgensen
045 */
046 public final class ResultTreeType extends Type {
047 private final String _methodName;
048
049 protected ResultTreeType() {
050 _methodName = null;
051 }
052
053 public ResultTreeType(String methodName) {
054 _methodName = methodName;
055 }
056
057 public String toString() {
058 return "result-tree";
059 }
060
061 public boolean identicalTo(Type other) {
062 return (other instanceof ResultTreeType);
063 }
064
065 public String toSignature() {
066 return DOM_INTF_SIG;
067 }
068
069 public org.apache.bcel.generic.Type toJCType() {
070 return Util.getJCRefType(toSignature());
071 }
072
073 public String getMethodName() {
074 return _methodName;
075 }
076
077 public boolean implementedAsMethod() {
078 return _methodName != null;
079 }
080
081 /**
082 * Translates a result tree to object of internal type <code>type</code>.
083 * The translation to int is undefined since result trees
084 * are always converted to reals in arithmetic expressions.
085 *
086 * @param classGen A BCEL class generator
087 * @param methodGen A BCEL method generator
088 * @param type An instance of the type to translate the result tree to
089 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo
090 */
091 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
092 Type type) {
093 if (type == Type.String) {
094 translateTo(classGen, methodGen, (StringType)type);
095 }
096 else if (type == Type.Boolean) {
097 translateTo(classGen, methodGen, (BooleanType)type);
098 }
099 else if (type == Type.Real) {
100 translateTo(classGen, methodGen, (RealType)type);
101 }
102 else if (type == Type.NodeSet) {
103 translateTo(classGen, methodGen, (NodeSetType)type);
104 }
105 else if (type == Type.Reference) {
106 translateTo(classGen, methodGen, (ReferenceType)type);
107 }
108 else if (type == Type.Object) {
109 translateTo(classGen, methodGen, (ObjectType) type);
110 }
111 else {
112 ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
113 toString(), type.toString());
114 classGen.getParser().reportError(Constants.FATAL, err);
115 }
116 }
117
118 /**
119 * Expects an result tree on the stack and pushes a boolean.
120 * Translates a result tree to a boolean by first converting it to string.
121 *
122 * @param classGen A BCEL class generator
123 * @param methodGen A BCEL method generator
124 * @param type An instance of BooleanType (any)
125 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo
126 */
127 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
128 BooleanType type) {
129 // A result tree is always 'true' when converted to a boolean value,
130 // since the tree always has at least one node (the root).
131 final ConstantPoolGen cpg = classGen.getConstantPool();
132 final InstructionList il = methodGen.getInstructionList();
133 il.append(POP); // don't need the DOM reference
134 il.append(ICONST_1); // push 'true' on the stack
135 }
136
137 /**
138 * Expects an result tree on the stack and pushes a string.
139 *
140 * @param classGen A BCEL class generator
141 * @param methodGen A BCEL method generator
142 * @param type An instance of StringType (any)
143 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo
144 */
145 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
146 StringType type) {
147 final ConstantPoolGen cpg = classGen.getConstantPool();
148 final InstructionList il = methodGen.getInstructionList();
149
150 if (_methodName == null) {
151 int index = cpg.addInterfaceMethodref(DOM_INTF,
152 "getStringValue",
153 "()"+STRING_SIG);
154 il.append(new INVOKEINTERFACE(index, 1));
155 }
156 else {
157 final String className = classGen.getClassName();
158 final int current = methodGen.getLocalIndex("current");
159
160 // Push required parameters
161 il.append(classGen.loadTranslet());
162 if (classGen.isExternal()) {
163 il.append(new CHECKCAST(cpg.addClass(className)));
164 }
165 il.append(DUP);
166 il.append(new GETFIELD(cpg.addFieldref(className, "_dom",
167 DOM_INTF_SIG)));
168
169 // Create a new instance of a StringValueHandler
170 int index = cpg.addMethodref(STRING_VALUE_HANDLER, "<init>", "()V");
171 il.append(new NEW(cpg.addClass(STRING_VALUE_HANDLER)));
172 il.append(DUP);
173 il.append(DUP);
174 il.append(new INVOKESPECIAL(index));
175
176 // Store new Handler into a local variable
177 final LocalVariableGen handler =
178 methodGen.addLocalVariable("rt_to_string_handler",
179 Util.getJCRefType(STRING_VALUE_HANDLER_SIG),
180 null, null);
181 handler.setStart(il.append(new ASTORE(handler.getIndex())));
182
183 // Call the method that implements this result tree
184 index = cpg.addMethodref(className, _methodName,
185 "("+DOM_INTF_SIG+TRANSLET_OUTPUT_SIG+")V");
186 il.append(new INVOKEVIRTUAL(index));
187
188 // Restore new handler and call getValue()
189 handler.setEnd(il.append(new ALOAD(handler.getIndex())));
190 index = cpg.addMethodref(STRING_VALUE_HANDLER,
191 "getValue",
192 "()" + STRING_SIG);
193 il.append(new INVOKEVIRTUAL(index));
194 }
195 }
196
197 /**
198 * Expects an result tree on the stack and pushes a real.
199 * Translates a result tree into a real by first converting it to string.
200 *
201 * @param classGen A BCEL class generator
202 * @param methodGen A BCEL method generator
203 * @param type An instance of RealType (any)
204 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo
205 */
206 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
207 RealType type) {
208 translateTo(classGen, methodGen, Type.String);
209 Type.String.translateTo(classGen, methodGen, Type.Real);
210 }
211
212 /**
213 * Expects a result tree on the stack and pushes a boxed result tree.
214 * Result trees are already boxed so the translation is just a NOP.
215 *
216 * @param classGen A BCEL class generator
217 * @param methodGen A BCEL method generator
218 * @param type An instance of ReferenceType (any)
219 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo
220 */
221 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
222 ReferenceType type) {
223 final ConstantPoolGen cpg = classGen.getConstantPool();
224 final InstructionList il = methodGen.getInstructionList();
225
226 if (_methodName == null) {
227 il.append(NOP);
228 }
229 else {
230 LocalVariableGen domBuilder, newDom;
231 final String className = classGen.getClassName();
232 final int current = methodGen.getLocalIndex("current");
233
234 // Push required parameters
235 il.append(classGen.loadTranslet());
236 if (classGen.isExternal()) {
237 il.append(new CHECKCAST(cpg.addClass(className)));
238 }
239 il.append(methodGen.loadDOM());
240
241 // Create new instance of DOM class (with RTF_INITIAL_SIZE nodes)
242 il.append(methodGen.loadDOM());
243 int index = cpg.addInterfaceMethodref(DOM_INTF,
244 "getResultTreeFrag",
245 "(IZ)" + DOM_INTF_SIG);
246 il.append(new PUSH(cpg, RTF_INITIAL_SIZE));
247 il.append(new PUSH(cpg, false));
248 il.append(new INVOKEINTERFACE(index,3));
249 il.append(DUP);
250
251 // Store new DOM into a local variable
252 newDom = methodGen.addLocalVariable("rt_to_reference_dom",
253 Util.getJCRefType(DOM_INTF_SIG),
254 null, null);
255 il.append(new CHECKCAST(cpg.addClass(DOM_INTF_SIG)));
256 newDom.setStart(il.append(new ASTORE(newDom.getIndex())));
257
258 // Overwrite old handler with DOM handler
259 index = cpg.addInterfaceMethodref(DOM_INTF,
260 "getOutputDomBuilder",
261 "()" + TRANSLET_OUTPUT_SIG);
262
263 il.append(new INVOKEINTERFACE(index,1));
264 //index = cpg.addMethodref(DOM_IMPL,
265 // "getOutputDomBuilder",
266 // "()" + TRANSLET_OUTPUT_SIG);
267 //il.append(new INVOKEVIRTUAL(index));
268 il.append(DUP);
269 il.append(DUP);
270
271 // Store DOM handler in a local in order to call endDocument()
272 domBuilder =
273 methodGen.addLocalVariable("rt_to_reference_handler",
274 Util.getJCRefType(TRANSLET_OUTPUT_SIG),
275 null, null);
276 domBuilder.setStart(il.append(new ASTORE(domBuilder.getIndex())));
277
278 // Call startDocument on the new handler
279 index = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE,
280 "startDocument", "()V");
281 il.append(new INVOKEINTERFACE(index, 1));
282
283 // Call the method that implements this result tree
284 index = cpg.addMethodref(className,
285 _methodName,
286 "("
287 + DOM_INTF_SIG
288 + TRANSLET_OUTPUT_SIG
289 +")V");
290 il.append(new INVOKEVIRTUAL(index));
291
292 // Call endDocument on the DOM handler
293 domBuilder.setEnd(il.append(new ALOAD(domBuilder.getIndex())));
294 index = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE,
295 "endDocument", "()V");
296 il.append(new INVOKEINTERFACE(index, 1));
297
298 // Push the new DOM on the stack
299 newDom.setEnd(il.append(new ALOAD(newDom.getIndex())));
300 }
301 }
302
303 /**
304 * Expects a result tree on the stack and pushes a node-set (iterator).
305 * Note that the produced iterator is an iterator for the DOM that
306 * contains the result tree, and not the DOM that is currently in use.
307 * This conversion here will therefore not directly work with elements
308 * such as <xsl:apply-templates> and <xsl:for-each> without the DOM
309 * parameter/variable being updates as well.
310 *
311 * @param classGen A BCEL class generator
312 * @param methodGen A BCEL method generator
313 * @param type An instance of NodeSetType (any)
314 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo
315 */
316 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
317 NodeSetType type) {
318 final ConstantPoolGen cpg = classGen.getConstantPool();
319 final InstructionList il = methodGen.getInstructionList();
320
321 // Put an extra copy of the result tree (DOM) on the stack
322 il.append(DUP);
323
324 // DOM adapters containing a result tree are not initialised with
325 // translet-type to DOM-type mapping. This must be done now for
326 // XPath expressions and patterns to work for the iterator we create.
327 il.append(classGen.loadTranslet()); // get names array
328 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
329 NAMES_INDEX,
330 NAMES_INDEX_SIG)));
331 il.append(classGen.loadTranslet()); // get uris array
332 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
333 URIS_INDEX,
334 URIS_INDEX_SIG)));
335 il.append(classGen.loadTranslet()); // get types array
336 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
337 TYPES_INDEX,
338 TYPES_INDEX_SIG)));
339 il.append(classGen.loadTranslet()); // get namespaces array
340 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
341 NAMESPACE_INDEX,
342 NAMESPACE_INDEX_SIG)));
343 // Pass the type mappings to the DOM adapter
344 final int mapping = cpg.addInterfaceMethodref(DOM_INTF,
345 "setupMapping",
346 "(["+STRING_SIG+
347 "["+STRING_SIG+
348 "[I" +
349 "["+STRING_SIG+")V");
350 il.append(new INVOKEINTERFACE(mapping, 5));
351 il.append(DUP);
352
353 // Create an iterator for the root node of the DOM adapter
354 final int iter = cpg.addInterfaceMethodref(DOM_INTF,
355 "getIterator",
356 "()"+NODE_ITERATOR_SIG);
357 il.append(new INVOKEINTERFACE(iter, 1));
358 }
359
360 /**
361 * Subsume result tree into ObjectType.
362 *
363 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo
364 */
365 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
366 ObjectType type) {
367 methodGen.getInstructionList().append(NOP);
368 }
369
370 /**
371 * Translates a result tree into a non-synthesized boolean.
372 * It does not push a 0 or a 1 but instead returns branchhandle list
373 * to be appended to the false list.
374 *
375 * @param classGen A BCEL class generator
376 * @param methodGen A BCEL method generator
377 * @param type An instance of BooleanType (any)
378 * @see org.apache.xalan.xsltc.compiler.util.Type#translateToDesynthesized
379 */
380 public FlowList translateToDesynthesized(ClassGenerator classGen,
381 MethodGenerator methodGen,
382 BooleanType type) {
383 final InstructionList il = methodGen.getInstructionList();
384 translateTo(classGen, methodGen, Type.Boolean);
385 return new FlowList(il.append(new IFEQ(null)));
386 }
387
388 /**
389 * Translates a result tree to a Java type denoted by <code>clazz</code>.
390 * Expects a result tree on the stack and pushes an object
391 * of the appropriate type after coercion. Result trees are translated
392 * to W3C Node or W3C NodeList and the translation is done
393 * via node-set type.
394 *
395 * @param classGen A BCEL class generator
396 * @param methodGen A BCEL method generator
397 * @param clazz An reference to the Class to translate to
398 * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo
399 */
400 public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
401 Class clazz) {
402 final String className = clazz.getName();
403 final ConstantPoolGen cpg = classGen.getConstantPool();
404 final InstructionList il = methodGen.getInstructionList();
405
406 if (className.equals("org.w3c.dom.Node")) {
407 translateTo(classGen, methodGen, Type.NodeSet);
408 int index = cpg.addInterfaceMethodref(DOM_INTF,
409 MAKE_NODE,
410 MAKE_NODE_SIG2);
411 il.append(new INVOKEINTERFACE(index, 2));
412 }
413 else if (className.equals("org.w3c.dom.NodeList")) {
414 translateTo(classGen, methodGen, Type.NodeSet);
415 int index = cpg.addInterfaceMethodref(DOM_INTF,
416 MAKE_NODE_LIST,
417 MAKE_NODE_LIST_SIG2);
418 il.append(new INVOKEINTERFACE(index, 2));
419 }
420 else if (className.equals("java.lang.Object")) {
421 il.append(NOP);
422 }
423 else if (className.equals("java.lang.String")) {
424 translateTo(classGen, methodGen, Type.String);
425 }
426 else {
427 ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
428 toString(), className);
429 classGen.getParser().reportError(Constants.FATAL, err);
430 }
431 }
432
433 /**
434 * Translates an object of this type to its boxed representation.
435 */
436 public void translateBox(ClassGenerator classGen,
437 MethodGenerator methodGen) {
438 translateTo(classGen, methodGen, Type.Reference);
439 }
440
441 /**
442 * Translates an object of this type to its unboxed representation.
443 */
444 public void translateUnBox(ClassGenerator classGen,
445 MethodGenerator methodGen) {
446 methodGen.getInstructionList().append(NOP);
447 }
448
449 /**
450 * Returns the class name of an internal type's external representation.
451 */
452 public String getClassName() {
453 return(DOM_INTF);
454 }
455
456 public Instruction LOAD(int slot) {
457 return new ALOAD(slot);
458 }
459
460 public Instruction STORE(int slot) {
461 return new ASTORE(slot);
462 }
463 }