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 }