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: Copy.java 468650 2006-10-28 07:03:30Z minchau $
020 */
021
022 package org.apache.xalan.xsltc.compiler;
023
024 import org.apache.bcel.generic.ALOAD;
025 import org.apache.bcel.generic.ASTORE;
026 import org.apache.bcel.generic.BranchHandle;
027 import org.apache.bcel.generic.ConstantPoolGen;
028 import org.apache.bcel.generic.IFEQ;
029 import org.apache.bcel.generic.IFNULL;
030 import org.apache.bcel.generic.ILOAD;
031 import org.apache.bcel.generic.INVOKEINTERFACE;
032 import org.apache.bcel.generic.INVOKEVIRTUAL;
033 import org.apache.bcel.generic.ISTORE;
034 import org.apache.bcel.generic.InstructionHandle;
035 import org.apache.bcel.generic.InstructionList;
036 import org.apache.bcel.generic.LocalVariableGen;
037 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
038 import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
039 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
040 import org.apache.xalan.xsltc.compiler.util.Type;
041 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
042 import org.apache.xalan.xsltc.compiler.util.Util;
043
044 /**
045 * @author Jacek Ambroziak
046 * @author Santiago Pericas-Geertsen
047 */
048 final class Copy extends Instruction {
049 private UseAttributeSets _useSets;
050
051 public void parseContents(Parser parser) {
052 final String useSets = getAttribute("use-attribute-sets");
053 if (useSets.length() > 0) {
054 if (!Util.isValidQNames(useSets)) {
055 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, useSets, this);
056 parser.reportError(Constants.ERROR, err);
057 }
058 _useSets = new UseAttributeSets(useSets, parser);
059 }
060 parseChildren(parser);
061 }
062
063 public void display(int indent) {
064 indent(indent);
065 Util.println("Copy");
066 indent(indent + IndentIncrement);
067 displayContents(indent + IndentIncrement);
068 }
069
070 public Type typeCheck(SymbolTable stable) throws TypeCheckError {
071 if (_useSets != null) {
072 _useSets.typeCheck(stable);
073 }
074 typeCheckContents(stable);
075 return Type.Void;
076 }
077
078 public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
079 final ConstantPoolGen cpg = classGen.getConstantPool();
080 final InstructionList il = methodGen.getInstructionList();
081
082 final LocalVariableGen name =
083 methodGen.addLocalVariable2("name",
084 Util.getJCRefType(STRING_SIG),
085 null);
086 final LocalVariableGen length =
087 methodGen.addLocalVariable2("length",
088 Util.getJCRefType("I"),
089 null);
090
091 // Get the name of the node to copy and save for later
092 il.append(methodGen.loadDOM());
093 il.append(methodGen.loadCurrentNode());
094 il.append(methodGen.loadHandler());
095 final int cpy = cpg.addInterfaceMethodref(DOM_INTF,
096 "shallowCopy",
097 "("
098 + NODE_SIG
099 + TRANSLET_OUTPUT_SIG
100 + ")" + STRING_SIG);
101 il.append(new INVOKEINTERFACE(cpy, 3));
102 il.append(DUP);
103 name.setStart(il.append(new ASTORE(name.getIndex())));
104 final BranchHandle ifBlock1 = il.append(new IFNULL(null));
105
106 // Get the length of the node name and save for later
107 il.append(new ALOAD(name.getIndex()));
108 final int lengthMethod = cpg.addMethodref(STRING_CLASS,"length","()I");
109 il.append(new INVOKEVIRTUAL(lengthMethod));
110 length.setStart(il.append(new ISTORE(length.getIndex())));
111
112 // Copy in attribute sets if specified
113 if (_useSets != null) {
114 // If the parent of this element will result in an element being
115 // output then we know that it is safe to copy out the attributes
116 final SyntaxTreeNode parent = getParent();
117 if ((parent instanceof LiteralElement) ||
118 (parent instanceof LiteralElement)) {
119 _useSets.translate(classGen, methodGen);
120 }
121 // If not we have to check to see if the copy will result in an
122 // element being output.
123 else {
124 // check if element; if not skip to translate body
125 il.append(new ILOAD(length.getIndex()));
126 final BranchHandle ifBlock2 = il.append(new IFEQ(null));
127 // length != 0 -> element -> do attribute sets
128 _useSets.translate(classGen, methodGen);
129 // not an element; root
130 ifBlock2.setTarget(il.append(NOP));
131 }
132 }
133
134 // Instantiate body of xsl:copy
135 translateContents(classGen, methodGen);
136
137 // Call the output handler's endElement() if we copied an element
138 // (The DOM.shallowCopy() method calls startElement().)
139 length.setEnd(il.append(new ILOAD(length.getIndex())));
140 final BranchHandle ifBlock3 = il.append(new IFEQ(null));
141 il.append(methodGen.loadHandler());
142 name.setEnd(il.append(new ALOAD(name.getIndex())));
143 il.append(methodGen.endElement());
144
145 final InstructionHandle end = il.append(NOP);
146 ifBlock1.setTarget(end);
147 ifBlock3.setTarget(end);
148 methodGen.removeLocalVariable(name);
149 methodGen.removeLocalVariable(length);
150 }
151 }