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    }