/** * This method returns a vector with variables/params and keys in the order in which they are to * be compiled for initialization. The order is determined by analyzing the dependencies between * them. The XSLT 1.0 spec does not allow a key to depend on a variable. However, for * compatibility with Xalan interpretive, that type of dependency is allowed and, therefore, * consider to determine the partial order. */ private Vector resolveDependencies(Vector input) { /* DEBUG CODE - INGORE for (int i = 0; i < input.size(); i++) { final TopLevelElement e = (TopLevelElement) input.elementAt(i); System.out.println("e = " + e + " depends on:"); Vector dep = e.getDependencies(); for (int j = 0; j < (dep != null ? dep.size() : 0); j++) { System.out.println("\t" + dep.elementAt(j)); } } System.out.println("================================="); */ Vector result = new Vector(); while (input.size() > 0) { boolean changed = false; for (int i = 0; i < input.size(); ) { final TopLevelElement vde = (TopLevelElement) input.elementAt(i); final Vector dep = vde.getDependencies(); if (dep == null || result.containsAll(dep)) { result.addElement(vde); input.remove(i); changed = true; } else { i++; } } // If nothing was changed in this pass then we have a circular ref if (!changed) { ErrorMsg err = new ErrorMsg(ErrorMsg.CIRCULAR_VARIABLE_ERR, input.toString(), this); getParser().reportError(Constants.ERROR, err); return (result); } } /* DEBUG CODE - INGORE System.out.println("================================="); for (int i = 0; i < result.size(); i++) { final TopLevelElement e = (TopLevelElement) result.elementAt(i); System.out.println("e = " + e); } */ return result; }
/* 27: */ /* 28: */ public void addParentDependency() /* 29: */ { /* 30: 73 */ SyntaxTreeNode node = this; /* 31: 74 */ while ((node != null) && (!(node instanceof TopLevelElement))) { /* 32: 75 */ node = node.getParent(); /* 33: */ } /* 34: 78 */ TopLevelElement parent = (TopLevelElement) node; /* 35: 79 */ if (parent != null) /* 36: */ { /* 37: 80 */ VariableBase var = this._variable; /* 38: 81 */ if (this._variable._ignore) { /* 39: 82 */ if ((this._variable instanceof Variable)) { /* 40: 83 */ var = parent.getSymbolTable().lookupVariable(this._variable._name); /* 41: 85 */ } else if ((this._variable instanceof Param)) { /* 42: 86 */ var = parent.getSymbolTable().lookupParam(this._variable._name); /* 43: */ } /* 44: */ } /* 45: 90 */ parent.addDependency(var); /* 46: */ } /* 47: */ }
/** * Compile a topLevel() method into the output class. This method is called from transform() to * handle all non-template top-level elements. Returns the signature of the topLevel() method. * * <p>Global variables/params and keys are first sorted to resolve dependencies between them. The * XSLT 1.0 spec does not allow a key to depend on a variable. However, for compatibility with * Xalan interpretive, that type of dependency is allowed. Note also that the buildKeys() method * is still generated as it is used by the LoadDocument class, but it no longer called from * transform(). */ private String compileTopLevel(ClassGenerator classGen) { final ConstantPoolGen cpg = classGen.getConstantPool(); final com.sun.org.apache.bcel.internal.generic.Type[] argTypes = { Util.getJCRefType(DOM_INTF_SIG), Util.getJCRefType(NODE_ITERATOR_SIG), Util.getJCRefType(TRANSLET_OUTPUT_SIG) }; final String[] argNames = {DOCUMENT_PNAME, ITERATOR_PNAME, TRANSLET_OUTPUT_PNAME}; final InstructionList il = new InstructionList(); final MethodGenerator toplevel = new MethodGenerator( ACC_PUBLIC, com.sun.org.apache.bcel.internal.generic.Type.VOID, argTypes, argNames, "topLevel", _className, il, classGen.getConstantPool()); toplevel.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException"); // Define and initialize 'current' variable with the root node final LocalVariableGen current = toplevel.addLocalVariable( "current", com.sun.org.apache.bcel.internal.generic.Type.INT, null, null); final int setFilter = cpg.addInterfaceMethodref( DOM_INTF, "setFilter", "(Lcom/sun/org/apache/xalan/internal/xsltc/StripFilter;)V"); final int gitr = cpg.addInterfaceMethodref(DOM_INTF, "getIterator", "()" + NODE_ITERATOR_SIG); il.append(toplevel.loadDOM()); il.append(new INVOKEINTERFACE(gitr, 1)); il.append(toplevel.nextNode()); current.setStart(il.append(new ISTORE(current.getIndex()))); // Create a new list containing variables/params + keys Vector varDepElements = new Vector(_globals); Enumeration elements = elements(); while (elements.hasMoreElements()) { final Object element = elements.nextElement(); if (element instanceof Key) { varDepElements.add(element); } } // Determine a partial order for the variables/params and keys varDepElements = resolveDependencies(varDepElements); // Translate vars/params and keys in the right order final int count = varDepElements.size(); for (int i = 0; i < count; i++) { final TopLevelElement tle = (TopLevelElement) varDepElements.elementAt(i); tle.translate(classGen, toplevel); if (tle instanceof Key) { final Key key = (Key) tle; _keys.put(key.getName(), key); } } // Compile code for other top-level elements Vector whitespaceRules = new Vector(); elements = elements(); while (elements.hasMoreElements()) { final Object element = elements.nextElement(); // xsl:decimal-format if (element instanceof DecimalFormatting) { ((DecimalFormatting) element).translate(classGen, toplevel); } // xsl:strip/preserve-space else if (element instanceof Whitespace) { whitespaceRules.addAll(((Whitespace) element).getRules()); } } // Translate all whitespace strip/preserve rules if (whitespaceRules.size() > 0) { Whitespace.translateRules(whitespaceRules, classGen); } if (classGen.containsMethod(STRIP_SPACE, STRIP_SPACE_PARAMS) != null) { il.append(toplevel.loadDOM()); il.append(classGen.loadTranslet()); il.append(new INVOKEINTERFACE(setFilter, 2)); } il.append(RETURN); // Compute max locals + stack and add method to class classGen.addMethod(toplevel); return ("(" + DOM_INTF_SIG + NODE_ITERATOR_SIG + TRANSLET_OUTPUT_SIG + ")V"); }