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: ProcessingInstruction.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.ConstantPoolGen;
027    import org.apache.bcel.generic.GETFIELD;
028    import org.apache.bcel.generic.INVOKEINTERFACE;
029    import org.apache.bcel.generic.INVOKESTATIC;
030    import org.apache.bcel.generic.INVOKEVIRTUAL;
031    import org.apache.bcel.generic.InstructionList;
032    import org.apache.bcel.generic.LocalVariableGen;
033    import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
034    import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
035    import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
036    import org.apache.xalan.xsltc.compiler.util.Type;
037    import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
038    import org.apache.xalan.xsltc.compiler.util.Util;
039    import org.apache.xml.utils.XML11Char;
040    
041    /**
042     * @author Jacek Ambroziak
043     * @author Santiago Pericas-Geertsen
044     */
045    final class ProcessingInstruction extends Instruction {
046    
047        private AttributeValue _name; // name treated as AVT (7.1.3)
048        private boolean _isLiteral = false;  // specified name is not AVT  
049        
050        public void parseContents(Parser parser) {
051            final String name  = getAttribute("name");
052        
053            if (name.length() > 0) {
054                _isLiteral = Util.isLiteral(name);
055                if (_isLiteral) {
056                    if (!XML11Char.isXML11ValidNCName(name)) {
057                        ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_NCNAME_ERR, name, this);
058                        parser.reportError(Constants.ERROR, err);           
059                    }
060                }   
061                _name = AttributeValue.create(this, name, parser);
062            }
063            else
064                reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "name");
065                
066            if (name.equals("xml")) {
067                reportError(this, parser, ErrorMsg.ILLEGAL_PI_ERR, "xml");
068            }
069            parseChildren(parser);
070        }
071    
072        public Type typeCheck(SymbolTable stable) throws TypeCheckError {
073            _name.typeCheck(stable);
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            if (!_isLiteral) {
083                // if the ncname is an AVT, then the ncname has to be checked at runtime if it is a valid ncname
084                LocalVariableGen nameValue =
085                        methodGen.addLocalVariable2("nameValue",
086                                                    Util.getJCRefType(STRING_SIG),
087                                                    null);
088                
089                // store the name into a variable first so _name.translate only needs to be called once  
090                _name.translate(classGen, methodGen);
091                nameValue.setStart(il.append(new ASTORE(nameValue.getIndex())));
092                il.append(new ALOAD(nameValue.getIndex()));
093                
094                // call checkNCName if the name is an AVT
095                final int check = cpg.addMethodref(BASIS_LIBRARY_CLASS, "checkNCName",
096                                    "("
097                                    +STRING_SIG
098                                    +")V");                 
099                                    il.append(new INVOKESTATIC(check));
100                
101                // Save the current handler base on the stack
102                il.append(methodGen.loadHandler());
103                il.append(DUP);     // first arg to "attributes" call            
104                
105                // load name value again    
106                nameValue.setEnd(il.append(new ALOAD(nameValue.getIndex())));            
107            } else {    
108                // Save the current handler base on the stack
109                il.append(methodGen.loadHandler());
110                il.append(DUP);     // first arg to "attributes" call
111                
112                // Push attribute name
113                _name.translate(classGen, methodGen);// 2nd arg
114            
115            }
116            
117            il.append(classGen.loadTranslet());
118            il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
119                                                   "stringValueHandler",
120                                                   STRING_VALUE_HANDLER_SIG)));
121            il.append(DUP);
122            il.append(methodGen.storeHandler());
123    
124            // translate contents with substituted handler
125            translateContents(classGen, methodGen);
126    
127            // get String out of the handler
128            il.append(new INVOKEVIRTUAL(cpg.addMethodref(STRING_VALUE_HANDLER,
129                                                         "getValueOfPI",
130                                                         "()" + STRING_SIG)));
131            // call "processingInstruction"
132            final int processingInstruction =
133                cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE,
134                                          "processingInstruction", 
135                                          "(" + STRING_SIG + STRING_SIG + ")V");
136            il.append(new INVOKEINTERFACE(processingInstruction, 3));
137            // Restore old handler base from stack
138            il.append(methodGen.storeHandler());
139        }
140    }