1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.xalan.internal.xsltc.compiler;
  23 
  24 import com.sun.org.apache.bcel.internal.generic.ALOAD;
  25 import com.sun.org.apache.bcel.internal.generic.ASTORE;
  26 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  27 import com.sun.org.apache.bcel.internal.generic.GETFIELD;
  28 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  29 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
  30 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  31 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  32 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
  33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  37 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  38 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
  39 import com.sun.org.apache.xml.internal.utils.XML11Char;
  40 
  41 /**
  42  * @author Jacek Ambroziak
  43  * @author Santiago Pericas-Geertsen
  44  */
  45 final class ProcessingInstruction extends Instruction {
  46 
  47     private AttributeValue _name; // name treated as AVT (7.1.3)
  48     private boolean _isLiteral = false;  // specified name is not AVT
  49 
  50     public void parseContents(Parser parser) {
  51         final String name  = getAttribute("name");
  52 
  53         if (name.length() > 0) {
  54             _isLiteral = Util.isLiteral(name);
  55             if (_isLiteral) {
  56                 if (!XML11Char.isXML11ValidNCName(name)) {
  57                     ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_NCNAME_ERR, name, this);
  58                     parser.reportError(Constants.ERROR, err);
  59                 }
  60             }
  61             _name = AttributeValue.create(this, name, parser);
  62         }
  63         else
  64             reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "name");
  65 
  66         if (name.equals("xml")) {
  67             reportError(this, parser, ErrorMsg.ILLEGAL_PI_ERR, "xml");
  68         }
  69         parseChildren(parser);
  70     }
  71 
  72     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  73         _name.typeCheck(stable);
  74         typeCheckContents(stable);
  75         return Type.Void;
  76     }
  77 
  78     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
  79         final ConstantPoolGen cpg = classGen.getConstantPool();
  80         final InstructionList il = methodGen.getInstructionList();
  81 
  82         if (!_isLiteral) {
  83             // if the ncname is an AVT, then the ncname has to be checked at runtime if it is a valid ncname
  84             LocalVariableGen nameValue =
  85                     methodGen.addLocalVariable2("nameValue",
  86             Util.getJCRefType(STRING_SIG),
  87                                                 null);
  88 
  89             // store the name into a variable first so _name.translate only needs to be called once
  90             _name.translate(classGen, methodGen);
  91             nameValue.setStart(il.append(new ASTORE(nameValue.getIndex())));
  92             il.append(new ALOAD(nameValue.getIndex()));
  93 
  94             // call checkNCName if the name is an AVT
  95             final int check = cpg.addMethodref(BASIS_LIBRARY_CLASS, "checkNCName",
  96                                 "("
  97                                 +STRING_SIG
  98                                 +")V");
  99                                 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 }