286N/A/*
286N/A * reserved comment block
286N/A * DO NOT REMOVE OR ALTER!
286N/A */
286N/A/*
286N/A * Copyright 2001-2004 The Apache Software Foundation.
286N/A *
286N/A * Licensed under the Apache License, Version 2.0 (the "License");
286N/A * you may not use this file except in compliance with the License.
286N/A * You may obtain a copy of the License at
286N/A *
286N/A * http://www.apache.org/licenses/LICENSE-2.0
286N/A *
286N/A * Unless required by applicable law or agreed to in writing, software
286N/A * distributed under the License is distributed on an "AS IS" BASIS,
286N/A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
286N/A * See the License for the specific language governing permissions and
286N/A * limitations under the License.
286N/A */
286N/A/*
286N/A * $Id: Variable.java,v 1.2.4.1 2005/09/12 11:36:46 pvedula Exp $
286N/A */
286N/A
286N/Apackage com.sun.org.apache.xalan.internal.xsltc.compiler;
286N/A
286N/Aimport com.sun.org.apache.bcel.internal.classfile.Field;
286N/Aimport com.sun.org.apache.bcel.internal.generic.ACONST_NULL;
286N/Aimport com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
286N/Aimport com.sun.org.apache.bcel.internal.generic.DCONST;
286N/Aimport com.sun.org.apache.bcel.internal.generic.ICONST;
286N/Aimport com.sun.org.apache.bcel.internal.generic.InstructionHandle;
286N/Aimport com.sun.org.apache.bcel.internal.generic.InstructionList;
286N/Aimport com.sun.org.apache.bcel.internal.generic.PUTFIELD;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeType;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.RealType;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
286N/A
286N/Afinal class Variable extends VariableBase {
286N/A
286N/A public int getIndex() {
286N/A return (_local != null) ? _local.getIndex() : -1;
286N/A }
286N/A
286N/A /**
286N/A * Parse the contents of the variable
286N/A */
286N/A public void parseContents(Parser parser) {
286N/A // Parse 'name' and 'select' attributes plus parameter contents
286N/A super.parseContents(parser);
286N/A
286N/A // Add a ref to this var to its enclosing construct
286N/A SyntaxTreeNode parent = getParent();
286N/A if (parent instanceof Stylesheet) {
286N/A // Mark this as a global variable
286N/A _isLocal = false;
286N/A // Check if a global variable with this name already exists...
286N/A Variable var = parser.getSymbolTable().lookupVariable(_name);
286N/A // ...and if it does we need to check import precedence
286N/A if (var != null) {
286N/A final int us = this.getImportPrecedence();
286N/A final int them = var.getImportPrecedence();
286N/A // It is an error if the two have the same import precedence
286N/A if (us == them) {
286N/A final String name = _name.toString();
286N/A reportError(this, parser, ErrorMsg.VARIABLE_REDEF_ERR,name);
286N/A }
286N/A // Ignore this if previous definition has higher precedence
286N/A else if (them > us) {
286N/A _ignore = true;
286N/A copyReferences(var);
286N/A return;
286N/A }
286N/A else {
286N/A var.copyReferences(this);
286N/A var.disable();
286N/A }
286N/A // Add this variable if we have higher precedence
286N/A }
286N/A ((Stylesheet)parent).addVariable(this);
286N/A parser.getSymbolTable().addVariable(this);
286N/A }
286N/A else {
286N/A _isLocal = true;
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Runs a type check on either the variable element body or the
286N/A * expression in the 'select' attribute
286N/A */
286N/A public Type typeCheck(SymbolTable stable) throws TypeCheckError {
286N/A
286N/A // Type check the 'select' expression if present
286N/A if (_select != null) {
286N/A _type = _select.typeCheck(stable);
286N/A }
286N/A // Type check the element contents otherwise
286N/A else if (hasContents()) {
286N/A typeCheckContents(stable);
286N/A _type = Type.ResultTree;
286N/A }
286N/A else {
286N/A _type = Type.Reference;
286N/A }
286N/A // The return type is void as the variable element does not leave
286N/A // anything on the JVM's stack. The '_type' global will be returned
286N/A // by the references to this variable, and not by the variable itself.
286N/A return Type.Void;
286N/A }
286N/A
286N/A /**
286N/A * This method is part of a little trick that is needed to use local
286N/A * variables inside nested for-each loops. See the initializeVariables()
286N/A * method in the ForEach class for an explanation
286N/A */
286N/A public void initialize(ClassGenerator classGen, MethodGenerator methodGen) {
286N/A final ConstantPoolGen cpg = classGen.getConstantPool();
286N/A final InstructionList il = methodGen.getInstructionList();
286N/A
286N/A // This is only done for local variables that are actually used
286N/A if (isLocal() && !_refs.isEmpty()) {
286N/A // Create a variable slot if none is allocated
286N/A if (_local == null) {
286N/A _local = methodGen.addLocalVariable2(getEscapedName(),
286N/A _type.toJCType(),
286N/A null);
286N/A }
286N/A // Push the default value on the JVM's stack
286N/A if ((_type instanceof IntType) ||
286N/A (_type instanceof NodeType) ||
286N/A (_type instanceof BooleanType))
286N/A il.append(new ICONST(0)); // 0 for node-id, integer and boolean
286N/A else if (_type instanceof RealType)
286N/A il.append(new DCONST(0)); // 0.0 for floating point numbers
286N/A else
286N/A il.append(new ACONST_NULL()); // and 'null' for anything else
286N/A
286N/A // Mark the store as the start of the live range of the variable
286N/A _local.setStart(il.append(_type.STORE(_local.getIndex())));
286N/A
286N/A }
286N/A }
286N/A
286N/A public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
286N/A final ConstantPoolGen cpg = classGen.getConstantPool();
286N/A final InstructionList il = methodGen.getInstructionList();
286N/A
286N/A // Don't generate code for unreferenced variables
286N/A if (_refs.isEmpty()) {
286N/A _ignore = true;
286N/A }
286N/A
286N/A // Make sure that a variable instance is only compiled once
286N/A if (_ignore) return;
286N/A _ignore = true;
286N/A
286N/A final String name = getEscapedName();
286N/A
286N/A if (isLocal()) {
286N/A // Compile variable value computation
286N/A translateValue(classGen, methodGen);
286N/A
286N/A // Add a new local variable and store value
286N/A boolean createLocal = _local == null;
286N/A if (createLocal) {
286N/A mapRegister(methodGen);
286N/A }
286N/A InstructionHandle storeInst =
286N/A il.append(_type.STORE(_local.getIndex()));
286N/A
286N/A // If the local is just being created, mark the store as the start
286N/A // of its live range. Note that it might have been created by
286N/A // initializeVariables already, which would have set the start of
286N/A // the live range already.
286N/A if (createLocal) {
286N/A _local.setStart(storeInst);
286N/A }
286N/A }
286N/A else {
286N/A String signature = _type.toSignature();
286N/A
286N/A // Global variables are store in class fields
286N/A if (classGen.containsField(name) == null) {
286N/A classGen.addField(new Field(ACC_PUBLIC,
286N/A cpg.addUtf8(name),
286N/A cpg.addUtf8(signature),
286N/A null, cpg.getConstantPool()));
286N/A
286N/A // Push a reference to "this" for putfield
286N/A il.append(classGen.loadTranslet());
286N/A // Compile variable value computation
286N/A translateValue(classGen, methodGen);
286N/A // Store the variable in the allocated field
286N/A il.append(new PUTFIELD(cpg.addFieldref(classGen.getClassName(),
286N/A name, signature)));
286N/A }
286N/A }
286N/A }
286N/A}