1 /*
2  * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
3  */
4 /*
5  * Licensed to the Apache Software Foundation (ASF) under one or more
6  * contributor license agreements.  See the NOTICE file distributed with
7  * this work for additional information regarding copyright ownership.
8  * The ASF licenses this file to You under the Apache License, Version 2.0
9  * (the "License"); you may not use this file except in compliance with
10  * the License.  You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 package com.sun.org.apache.xalan.internal.xsltc.compiler;
22 
23 import com.sun.org.apache.bcel.internal.generic.ANEWARRAY;
24 import com.sun.org.apache.bcel.internal.generic.BasicType;
25 import com.sun.org.apache.bcel.internal.generic.CHECKCAST;
26 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
27 import com.sun.org.apache.bcel.internal.generic.DUP_X1;
28 import com.sun.org.apache.bcel.internal.generic.GETFIELD;
29 import com.sun.org.apache.bcel.internal.generic.ICONST;
30 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
31 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
32 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
33 import com.sun.org.apache.bcel.internal.generic.InstructionList;
34 import com.sun.org.apache.bcel.internal.generic.NEW;
35 import com.sun.org.apache.bcel.internal.generic.NEWARRAY;
36 import com.sun.org.apache.bcel.internal.generic.PUSH;
37 import com.sun.org.apache.xalan.internal.xsltc.DOM;
38 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
39 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
40 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
41 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
42 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
43 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
44 import java.util.ArrayList;
45 import java.util.HashMap;
46 import java.util.Iterator;
47 import java.util.List;
48 import java.util.Map;
49 import org.xml.sax.Attributes;
50 import org.xml.sax.helpers.AttributesImpl;
51 
52 
53 /**
54  * @author Jacek Ambroziak
55  * @author Santiago Pericas-Geertsen
56  * @author G. Todd Miller
57  * @author Morten Jorensen
58  * @author Erwin Bolwidt <ejb@klomp.org>
59  * @author John Howard <JohnH@schemasoft.com>
60  * @LastModified: Nov 2017
61  */
62 public abstract class SyntaxTreeNode implements Constants {
63 
64     // Reference to the AST parser
65     private Parser _parser;
66 
67     // AST navigation pointers
68     protected SyntaxTreeNode _parent;          // Parent node
69     private Stylesheet       _stylesheet;      // Stylesheet ancestor node
70     private Template         _template;        // Template ancestor node
71     private final List<SyntaxTreeNode> _contents = new ArrayList<>(2); // Child nodes
72 
73     // Element description data
74     protected QName _qname;                    // The element QName
75     private int _line;                         // Source file line number
76     protected AttributesImpl _attributes = null;   // Attributes of this element
77     private Map<String, String> _prefixMapping = null; // Namespace declarations
78 
79     // Sentinel - used to denote unrecognised syntaxt tree nodes.
80     protected static final SyntaxTreeNode Dummy = new AbsolutePathPattern(null);
81 
82     // These two are used for indenting nodes in the AST (debug output)
83     protected static final int IndentIncrement = 4;
84     private static final char[] _spaces =
85         "                                                       ".toCharArray();
86 
87     /**
88      * Creates a new SyntaxTreeNode with a 'null' QName and no source file
89      * line number reference.
90      */
SyntaxTreeNode()91     public SyntaxTreeNode() {
92         _line = 0;
93         _qname = null;
94     }
95 
96     /**
97      * Creates a new SyntaxTreeNode with a 'null' QName.
98      * @param line Source file line number reference
99      */
SyntaxTreeNode(int line)100     public SyntaxTreeNode(int line) {
101         _line = line;
102         _qname = null;
103     }
104 
105     /**
106      * Creates a new SyntaxTreeNode with no source file line number reference.
107      * @param uri The element's namespace URI
108      * @param prefix The element's namespace prefix
109      * @param local The element's local name
110      */
SyntaxTreeNode(String uri, String prefix, String local)111     public SyntaxTreeNode(String uri, String prefix, String local) {
112         _line = 0;
113         setQName(uri, prefix, local);
114     }
115 
116     /**
117      * Set the source file line number for this element
118      * @param line The source file line number.
119      */
setLineNumber(int line)120     protected final void setLineNumber(int line) {
121         _line = line;
122     }
123 
124     /**
125      * Get the source file line number for this element. If unavailable, lookup
126      * in ancestors.
127      *
128      * @return The source file line number.
129      */
getLineNumber()130     public final int getLineNumber() {
131         if (_line > 0) return _line;
132         SyntaxTreeNode parent = getParent();
133         return (parent != null) ? parent.getLineNumber() : 0;
134     }
135 
136     /**
137      * Set the QName for the syntax tree node.
138      * @param qname The QName for the syntax tree node
139      */
setQName(QName qname)140     protected void setQName(QName qname) {
141         _qname = qname;
142     }
143 
144     /**
145      * Set the QName for the SyntaxTreeNode
146      * @param uri The element's namespace URI
147      * @param prefix The element's namespace prefix
148      * @param local The element's local name
149      */
setQName(String uri, String prefix, String localname)150     protected void setQName(String uri, String prefix, String localname) {
151         _qname = new QName(uri, prefix, localname);
152     }
153 
154     /**
155      * Set the QName for the SyntaxTreeNode
156      * @param qname The QName for the syntax tree node
157      */
getQName()158     protected QName getQName() {
159         return(_qname);
160     }
161 
162     /**
163      * Set the attributes for this SyntaxTreeNode.
164      * @param attributes Attributes for the element. Must be passed in as an
165      *                   implementation of org.xml.sax.Attributes.
166      */
setAttributes(AttributesImpl attributes)167     protected void setAttributes(AttributesImpl attributes) {
168         _attributes = attributes;
169     }
170 
171     /**
172      * Returns a value for an attribute from the source element.
173      * @param qname The QName of the attribute to return.
174      * @return The value of the attribute of name 'qname'.
175      */
getAttribute(String qname)176     protected String getAttribute(String qname) {
177         if (_attributes == null) {
178             return EMPTYSTRING;
179         }
180         final String value = _attributes.getValue(qname);
181         return (value == null || value.equals(EMPTYSTRING)) ?
182             EMPTYSTRING : value;
183     }
184 
getAttribute(String prefix, String localName)185     protected String getAttribute(String prefix, String localName) {
186         return getAttribute(prefix + ':' + localName);
187     }
188 
hasAttribute(String qname)189     protected boolean hasAttribute(String qname) {
190         return (_attributes != null && _attributes.getValue(qname) != null);
191     }
192 
addAttribute(String qname, String value)193     protected void addAttribute(String qname, String value) {
194         int index = _attributes.getIndex(qname);
195         if (index != -1) {
196             _attributes.setAttribute(index, "", Util.getLocalName(qname),
197                     qname, "CDATA", value);
198         }
199         else {
200             _attributes.addAttribute("", Util.getLocalName(qname), qname,
201                     "CDATA", value);
202         }
203     }
204 
205     /**
206      * Returns a list of all attributes declared for the element represented by
207      * this syntax tree node.
208      * @return Attributes for this syntax tree node
209      */
getAttributes()210     protected Attributes getAttributes() {
211         return(_attributes);
212     }
213 
214     /**
215      * Sets the prefix mapping for the namespaces that were declared in this
216      * element. This does not include all prefix mappings in scope, so one
217      * may have to check ancestor elements to get all mappings that are in
218      * in scope. The prefixes must be passed in as a Map that maps
219      * namespace prefixes (String objects) to namespace URIs (also String).
220      * @param mapping The Map containing the mappings.
221      */
setPrefixMapping(Map<String, String> mapping)222     protected void setPrefixMapping(Map<String, String> mapping) {
223         _prefixMapping = mapping;
224     }
225 
226     /**
227      * Returns a Map containing the prefix mappings that were declared
228      * for this element. This does not include all prefix mappings in scope,
229      * so one may have to check ancestor elements to get all mappings that are
230      * in in scope.
231      * @return Prefix mappings (for this element only).
232      */
getPrefixMapping()233     protected Map<String, String> getPrefixMapping() {
234         return _prefixMapping;
235     }
236 
237     /**
238      * Adds a single prefix mapping to this syntax tree node.
239      * @param prefix Namespace prefix.
240      * @param uri Namespace URI.
241      */
addPrefixMapping(String prefix, String uri)242     protected void addPrefixMapping(String prefix, String uri) {
243         if (_prefixMapping == null)
244             _prefixMapping = new HashMap<>();
245         _prefixMapping.put(prefix, uri);
246     }
247 
248     /**
249      * Returns any namespace URI that is in scope for a given prefix. This
250      * method checks namespace mappings for this element, and if necessary
251      * for ancestor elements as well (ie. if the prefix maps to an URI in this
252      * scope then you'll definately get the URI from this method).
253      * @param prefix Namespace prefix.
254      * @return Namespace URI.
255      */
lookupNamespace(String prefix)256     protected String lookupNamespace(String prefix) {
257         // Initialise the output (default is 'null' for undefined)
258         String uri = null;
259 
260         // First look up the prefix/uri mapping in our own map...
261         if (_prefixMapping != null)
262             uri = _prefixMapping.get(prefix);
263         // ... but if we can't find it there we ask our parent for the mapping
264         if ((uri == null) && (_parent != null)) {
265             uri = _parent.lookupNamespace(prefix);
266             if ((prefix == Constants.EMPTYSTRING) && (uri == null))
267                 uri = Constants.EMPTYSTRING;
268         }
269         // ... and then we return whatever URI we've got.
270         return(uri);
271     }
272 
273     /**
274      * Returns any namespace prefix that is mapped to a prefix in the current
275      * scope. This method checks namespace mappings for this element, and if
276      * necessary for ancestor elements as well (ie. if the URI is declared
277      * within the current scope then you'll definately get the prefix from
278      * this method). Note that this is a very slow method and consequentially
279      * it should only be used strictly when needed.
280      * @param uri Namespace URI.
281      * @return Namespace prefix.
282      */
lookupPrefix(String uri)283     protected String lookupPrefix(String uri) {
284         // Initialise the output (default is 'null' for undefined)
285         String prefix = null;
286 
287         // First look up the prefix/uri mapping in our own map...
288         if ((_prefixMapping != null) &&
289             (_prefixMapping.containsValue(uri))) {
290             for (Map.Entry<String, String> entry : _prefixMapping.entrySet()) {
291                 prefix = entry.getKey();
292                 String mapsTo = entry.getValue();
293                 if (mapsTo.equals(uri)) return(prefix);
294             }
295         }
296         // ... but if we can't find it there we ask our parent for the mapping
297         else if (_parent != null) {
298             prefix = _parent.lookupPrefix(uri);
299             if ((uri == Constants.EMPTYSTRING) && (prefix == null))
300                 prefix = Constants.EMPTYSTRING;
301         }
302         return(prefix);
303     }
304 
305     /**
306      * Set this node's parser. The parser (the XSLT parser) gives this
307      * syntax tree node access to the symbol table and XPath parser.
308      * @param parser The XSLT parser.
309      */
setParser(Parser parser)310     protected void setParser(Parser parser) {
311         _parser = parser;
312     }
313 
314     /**
315      * Returns this node's XSLT parser.
316      * @return The XSLT parser.
317      */
getParser()318     public final Parser getParser() {
319         return _parser;
320     }
321 
322     /**
323      * Set this syntax tree node's parent node, if unset. For
324      * re-parenting just use <code>node._parent = newparent</code>.
325      *
326      * @param parent The parent node.
327      */
setParent(SyntaxTreeNode parent)328     protected void setParent(SyntaxTreeNode parent) {
329         if (_parent == null) _parent = parent;
330     }
331 
332     /**
333      * Returns this syntax tree node's parent node.
334      * @return The parent syntax tree node.
335      */
getParent()336     protected final SyntaxTreeNode getParent() {
337         return _parent;
338     }
339 
340     /**
341      * Returns 'true' if this syntax tree node is the Sentinal node.
342      * @return 'true' if this syntax tree node is the Sentinal node.
343      */
isDummy()344     protected final boolean isDummy() {
345         return this == Dummy;
346     }
347 
348     /**
349      * Get the import precedence of this element. The import precedence equals
350      * the import precedence of the stylesheet in which this element occured.
351      * @return The import precedence of this syntax tree node.
352      */
getImportPrecedence()353     protected int getImportPrecedence() {
354         Stylesheet stylesheet = getStylesheet();
355         if (stylesheet == null) return Integer.MIN_VALUE;
356         return stylesheet.getImportPrecedence();
357     }
358 
359     /**
360      * Get the Stylesheet node that represents the <xsl:stylesheet/> element
361      * that this node occured under.
362      * @return The Stylesheet ancestor node of this node.
363      */
getStylesheet()364     public Stylesheet getStylesheet() {
365         if (_stylesheet == null) {
366             SyntaxTreeNode parent = this;
367             while (parent != null) {
368                 if (parent instanceof Stylesheet)
369                     return((Stylesheet)parent);
370                 parent = parent.getParent();
371             }
372             _stylesheet = (Stylesheet)parent;
373         }
374         return(_stylesheet);
375     }
376 
377     /**
378      * Get the Template node that represents the <xsl:template/> element
379      * that this node occured under. Note that this method will return 'null'
380      * for nodes that represent top-level elements.
381      * @return The Template ancestor node of this node or 'null'.
382      */
getTemplate()383     protected Template getTemplate() {
384         if (_template == null) {
385             SyntaxTreeNode parent = this;
386             while ((parent != null) && (!(parent instanceof Template)))
387                 parent = parent.getParent();
388             _template = (Template)parent;
389         }
390         return(_template);
391     }
392 
393     /**
394      * Returns a reference to the XSLTC (XSLT compiler) in use.
395      * @return XSLTC - XSLT compiler.
396      */
getXSLTC()397     protected final XSLTC getXSLTC() {
398         return _parser.getXSLTC();
399     }
400 
401     /**
402      * Returns the XSLT parser's symbol table.
403      * @return Symbol table.
404      */
getSymbolTable()405     protected final SymbolTable getSymbolTable() {
406         return (_parser == null) ? null : _parser.getSymbolTable();
407     }
408 
409     /**
410      * Parse the contents of this syntax tree nodes (child nodes, XPath
411      * expressions, patterns and functions). The default behaviour is to parser
412      * the syntax tree node's children (since there are no common expressions,
413      * patterns, etc. that can be handled in this base class.
414      * @param parser reference to the XSLT parser
415      */
parseContents(Parser parser)416     public void parseContents(Parser parser) {
417         parseChildren(parser);
418     }
419 
420     /**
421      * Parse all children of this syntax tree node. This method is normally
422      * called by the parseContents() method.
423      * @param parser reference to the XSLT parser
424      */
parseChildren(Parser parser)425     protected final void parseChildren(Parser parser) {
426 
427         List<QName> locals = null;   // only create when needed
428 
429         for (SyntaxTreeNode child : _contents) {
430             parser.getSymbolTable().setCurrentNode(child);
431             child.parseContents(parser);
432             // if variable or parameter, add it to scope
433             final QName varOrParamName = updateScope(parser, child);
434             if (varOrParamName != null) {
435                 if (locals == null) {
436                     locals = new ArrayList<>(2);
437                 }
438                 locals.add(varOrParamName);
439             }
440         }
441 
442         parser.getSymbolTable().setCurrentNode(this);
443 
444         // after the last element, remove any locals from scope
445         if (locals != null) {
446             for (QName varOrParamName : locals) {
447                 parser.removeVariable(varOrParamName);
448             }
449         }
450     }
451 
452     /**
453      * Add a node to the current scope and return name of a variable or
454      * parameter if the node represents a variable or a parameter.
455      */
updateScope(Parser parser, SyntaxTreeNode node)456     protected QName updateScope(Parser parser, SyntaxTreeNode node) {
457         if (node instanceof Variable) {
458             final Variable var = (Variable)node;
459             parser.addVariable(var);
460             return var.getName();
461         }
462         else if (node instanceof Param) {
463             final Param param = (Param)node;
464             parser.addParameter(param);
465             return param.getName();
466         }
467         else {
468             return null;
469         }
470     }
471 
472     /**
473      * Type check the children of this node. The type check phase may add
474      * coercions (CastExpr) to the AST.
475      * @param stable The compiler/parser's symbol table
476      */
typeCheck(SymbolTable stable)477     public abstract Type typeCheck(SymbolTable stable) throws TypeCheckError;
478 
479     /**
480      * Call typeCheck() on all child syntax tree nodes.
481      * @param stable The compiler/parser's symbol table
482      */
typeCheckContents(SymbolTable stable)483     protected Type typeCheckContents(SymbolTable stable) throws TypeCheckError {
484         for (SyntaxTreeNode item : _contents) {
485             item.typeCheck(stable);
486         }
487         return Type.Void;
488     }
489 
490     /**
491      * Translate this abstract syntax tree node into JVM bytecodes.
492      * @param classGen BCEL Java class generator
493      * @param methodGen BCEL Java method generator
494      */
translate(ClassGenerator classGen, MethodGenerator methodGen)495     public abstract void translate(ClassGenerator classGen,
496                                    MethodGenerator methodGen);
497 
498     /**
499      * Call translate() on all child syntax tree nodes.
500      * @param classGen BCEL Java class generator
501      * @param methodGen BCEL Java method generator
502      */
translateContents(ClassGenerator classGen, MethodGenerator methodGen)503     protected void translateContents(ClassGenerator classGen,
504                                      MethodGenerator methodGen) {
505         // Call translate() on all child nodes
506         final int n = elementCount();
507 
508         for (SyntaxTreeNode item : _contents) {
509             methodGen.markChunkStart();
510             item.translate(classGen, methodGen);
511             methodGen.markChunkEnd();
512         }
513 
514         // After translation, unmap any registers for any variables/parameters
515         // that were declared in this scope. Performing this unmapping in the
516         // same AST scope as the declaration deals with the problems of
517         // references falling out-of-scope inside the for-each element.
518         // (the cause of which being 'lazy' register allocation for references)
519         for (int i = 0; i < n; i++) {
520             if ( _contents.get(i) instanceof VariableBase) {
521                 final VariableBase var = (VariableBase)_contents.get(i);
522                 var.unmapRegister(classGen, methodGen);
523             }
524         }
525     }
526 
527     /**
528      * Checks whether any children of this node is not of the specified type.
529      *
530      * @param type the type to be checked against
531      * @return true if there is at least one child that is not of the specified
532      * type, false otherwise.
533      */
notTypeOf(Class<?> type)534     public boolean notTypeOf(Class<?> type) {
535         if (_contents.size() > 0) {
536             for (SyntaxTreeNode item : _contents) {
537                 if (!item.getClass().isAssignableFrom(type)) {
538                     return true;
539                 }
540             }
541         }
542         return false;
543     }
544 
545     /**
546      * Return true if the node represents a simple RTF.
547      *
548      * A node is a simple RTF if all children only produce Text value.
549      *
550      * @param node A node
551      * @return true if the node content can be considered as a simple RTF.
552      */
isSimpleRTF(SyntaxTreeNode node)553     private boolean isSimpleRTF(SyntaxTreeNode node) {
554 
555         List<SyntaxTreeNode> contents = node.getContents();
556         if (!contents.stream().noneMatch((item) -> (!isTextElement(item, false)))) {
557                 return false;
558         }
559 
560         return true;
561     }
562 
563      /**
564      * Return true if the node represents an adaptive RTF.
565      *
566      * A node is an adaptive RTF if each children is a Text element
567      * or it is <xsl:call-template> or <xsl:apply-templates>.
568      *
569      * @param node A node
570      * @return true if the node content can be considered as an adaptive RTF.
571      */
isAdaptiveRTF(SyntaxTreeNode node)572     private boolean isAdaptiveRTF(SyntaxTreeNode node) {
573 
574         List<SyntaxTreeNode> contents = node.getContents();
575         for (SyntaxTreeNode item : contents) {
576             if (!isTextElement(item, true))
577                 return false;
578         }
579 
580         return true;
581     }
582 
583     /**
584      * Return true if the node only produces Text content.
585      *
586      * A node is a Text element if it is Text, xsl:value-of, xsl:number,
587      * or a combination of these nested in a control instruction (xsl:if or
588      * xsl:choose).
589      *
590      * If the doExtendedCheck flag is true, xsl:call-template and xsl:apply-templates
591      * are also considered as Text elements.
592      *
593      * @param node A node
594      * @param doExtendedCheck If this flag is true, <xsl:call-template> and
595      * <xsl:apply-templates> are also considered as Text elements.
596      *
597      * @return true if the node of Text type
598      */
isTextElement(SyntaxTreeNode node, boolean doExtendedCheck)599     private boolean isTextElement(SyntaxTreeNode node, boolean doExtendedCheck) {
600         if (node instanceof ValueOf || node instanceof Number
601             || node instanceof Text)
602         {
603             return true;
604         }
605         else if (node instanceof If) {
606             return doExtendedCheck ? isAdaptiveRTF(node) : isSimpleRTF(node);
607         }
608         else if (node instanceof Choose) {
609             List<SyntaxTreeNode> contents = node.getContents();
610             for (SyntaxTreeNode item : contents) {
611                 if (item instanceof Text ||
612                      ((item instanceof When || item instanceof Otherwise)
613                      && ((doExtendedCheck && isAdaptiveRTF(item))
614                          || (!doExtendedCheck && isSimpleRTF(item)))))
615                     continue;
616                 else
617                     return false;
618             }
619             return true;
620         }
621         else if (doExtendedCheck &&
622                   (node instanceof CallTemplate
623                    || node instanceof ApplyTemplates))
624             return true;
625         else
626             return false;
627     }
628 
629     /**
630      * Utility method used by parameters and variables to store result trees
631      * @param classGen BCEL Java class generator
632      * @param methodGen BCEL Java method generator
633      */
compileResultTree(ClassGenerator classGen, MethodGenerator methodGen)634     protected void compileResultTree(ClassGenerator classGen,
635                                      MethodGenerator methodGen)
636     {
637         final ConstantPoolGen cpg = classGen.getConstantPool();
638         final InstructionList il = methodGen.getInstructionList();
639         final Stylesheet stylesheet = classGen.getStylesheet();
640 
641         boolean isSimple = isSimpleRTF(this);
642         boolean isAdaptive = false;
643         if (!isSimple) {
644             isAdaptive = isAdaptiveRTF(this);
645         }
646 
647         int rtfType = isSimple ? DOM.SIMPLE_RTF
648                                : (isAdaptive ? DOM.ADAPTIVE_RTF : DOM.TREE_RTF);
649 
650         // Save the current handler base on the stack
651         il.append(methodGen.loadHandler());
652 
653         final String DOM_CLASS = classGen.getDOMClass();
654 
655         // Create new instance of DOM class (with RTF_INITIAL_SIZE nodes)
656         //int index = cpg.addMethodref(DOM_IMPL, "<init>", "(I)V");
657         //il.append(new NEW(cpg.addClass(DOM_IMPL)));
658 
659         il.append(methodGen.loadDOM());
660         int index = cpg.addInterfaceMethodref(DOM_INTF,
661                                  "getResultTreeFrag",
662                                  "(IIZ)" + DOM_INTF_SIG);
663         il.append(new PUSH(cpg, RTF_INITIAL_SIZE));
664         il.append(new PUSH(cpg, rtfType));
665         il.append(new PUSH(cpg, stylesheet.callsNodeset()));
666         il.append(new INVOKEINTERFACE(index,4));
667 
668         il.append(DUP);
669 
670         // Overwrite old handler with DOM handler
671         index = cpg.addInterfaceMethodref(DOM_INTF,
672                                  "getOutputDomBuilder",
673                                  "()" + TRANSLET_OUTPUT_SIG);
674 
675         il.append(new INVOKEINTERFACE(index,1));
676         il.append(DUP);
677         il.append(methodGen.storeHandler());
678 
679         // Call startDocument on the new handler
680         il.append(methodGen.startDocument());
681 
682         // Instantiate result tree fragment
683         translateContents(classGen, methodGen);
684 
685         // Call endDocument on the new handler
686         il.append(methodGen.loadHandler());
687         il.append(methodGen.endDocument());
688 
689         // Check if we need to wrap the DOMImpl object in a DOMAdapter object.
690         // DOMAdapter is not needed if the RTF is a simple RTF and the nodeset()
691         // function is not used.
692         if (stylesheet.callsNodeset()
693             && !DOM_CLASS.equals(DOM_IMPL_CLASS)) {
694             // new com.sun.org.apache.xalan.internal.xsltc.dom.DOMAdapter(DOMImpl,String[]);
695             index = cpg.addMethodref(DOM_ADAPTER_CLASS,
696                                      "<init>",
697                                      "("+DOM_INTF_SIG+
698                                      "["+STRING_SIG+
699                                      "["+STRING_SIG+
700                                      "[I"+
701                                      "["+STRING_SIG+")V");
702             il.append(new NEW(cpg.addClass(DOM_ADAPTER_CLASS)));
703             il.append(new DUP_X1());
704             il.append(SWAP);
705 
706             /*
707              * Give the DOM adapter an empty type mapping if the nodeset
708              * extension function is never called.
709              */
710             if (!stylesheet.callsNodeset()) {
711                 il.append(new ICONST(0));
712                 il.append(new ANEWARRAY(cpg.addClass(STRING)));
713                 il.append(DUP);
714                 il.append(DUP);
715                 il.append(new ICONST(0));
716                 il.append(new NEWARRAY(BasicType.INT));
717                 il.append(SWAP);
718                 il.append(new INVOKESPECIAL(index));
719             }
720             else {
721                 // Push name arrays on the stack
722                 il.append(ALOAD_0);
723                 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
724                                            NAMES_INDEX,
725                                            NAMES_INDEX_SIG)));
726                 il.append(ALOAD_0);
727                 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
728                                            URIS_INDEX,
729                                            URIS_INDEX_SIG)));
730                 il.append(ALOAD_0);
731                 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
732                                            TYPES_INDEX,
733                                            TYPES_INDEX_SIG)));
734                 il.append(ALOAD_0);
735                 il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
736                                            NAMESPACE_INDEX,
737                                            NAMESPACE_INDEX_SIG)));
738 
739                 // Initialized DOM adapter
740                 il.append(new INVOKESPECIAL(index));
741 
742                 // Add DOM adapter to MultiDOM class by calling addDOMAdapter()
743                 il.append(DUP);
744                 il.append(methodGen.loadDOM());
745                 il.append(new CHECKCAST(cpg.addClass(classGen.getDOMClass())));
746                 il.append(SWAP);
747                 index = cpg.addMethodref(MULTI_DOM_CLASS,
748                                          "addDOMAdapter",
749                                          "(" + DOM_ADAPTER_SIG + ")I");
750                 il.append(new INVOKEVIRTUAL(index));
751                 il.append(POP);         // ignore mask returned by addDOMAdapter
752             }
753         }
754 
755         // Restore old handler base from stack
756         il.append(SWAP);
757         il.append(methodGen.storeHandler());
758     }
759 
760     /**
761      * Returns true if this expression/instruction depends on the context. By
762      * default, every expression/instruction depends on the context unless it
763      * overrides this method. Currently used to determine if result trees are
764      * compiled using procedures or little DOMs (result tree fragments).
765      * @return 'true' if this node depends on the context.
766      */
contextDependent()767     protected boolean contextDependent() {
768         return true;
769     }
770 
771     /**
772      * Return true if any of the expressions/instructions in the contents of
773      * this node is context dependent.
774      * @return 'true' if the contents of this node is context dependent.
775      */
dependentContents()776     protected boolean dependentContents() {
777         for (SyntaxTreeNode item : _contents) {
778             if (item.contextDependent()) {
779                 return true;
780             }
781         }
782         return false;
783     }
784 
785     /**
786      * Adds a child node to this syntax tree node.
787      * @param element is the new child node.
788      */
addElement(SyntaxTreeNode element)789     protected final void addElement(SyntaxTreeNode element) {
790         _contents.add(element);
791         element.setParent(this);
792     }
793 
794     /**
795      * Inserts the first child node of this syntax tree node. The existing
796      * children are shifted back one position.
797      * @param element is the new child node.
798      */
setFirstElement(SyntaxTreeNode element)799     protected final void setFirstElement(SyntaxTreeNode element) {
800         _contents.add(0, element);
801         element.setParent(this);
802     }
803 
804     /**
805      * Removed a child node of this syntax tree node.
806      * @param element is the child node to remove.
807      */
removeElement(SyntaxTreeNode element)808     protected final void removeElement(SyntaxTreeNode element) {
809         _contents.remove(element);
810         element.setParent(null);
811     }
812 
813     /**
814      * Returns a List containing all the child nodes of this node.
815      * @return A List containing all the child nodes of this node.
816      */
getContents()817     protected final List<SyntaxTreeNode> getContents() {
818         return _contents;
819     }
820 
821     /**
822      * Tells you if this node has any child nodes.
823      * @return 'true' if this node has any children.
824      */
hasContents()825     protected final boolean hasContents() {
826         return elementCount() > 0;
827     }
828 
829     /**
830      * Returns the number of children this node has.
831      * @return Number of child nodes.
832      */
elementCount()833     protected final int elementCount() {
834         return _contents.size();
835     }
836 
837     /**
838      * Returns an Iterator of all child nodes of this node.
839      * @return An Iterator of all child nodes of this node.
840      */
elements()841     protected final Iterator<SyntaxTreeNode> elements() {
842         return _contents.iterator();
843     }
844 
845     /**
846      * Returns a child node at a given position.
847      * @param pos The child node's position.
848      * @return The child node.
849      */
elementAt(int pos)850     protected final SyntaxTreeNode elementAt(int pos) {
851         return _contents.get(pos);
852     }
853 
854     /**
855      * Returns this element's last child
856      * @return The child node.
857      */
lastChild()858     protected final SyntaxTreeNode lastChild() {
859         if (_contents.isEmpty()) return null;
860         return _contents.get(_contents.size() - 1);
861     }
862 
863     /**
864      * Displays the contents of this syntax tree node (to stdout).
865      * This method is intended for debugging _only_, and should be overridden
866      * by all syntax tree node implementations.
867      * @param indent Indentation level for syntax tree levels.
868      */
display(int indent)869     public void display(int indent) {
870         displayContents(indent);
871     }
872 
873     /**
874      * Displays the contents of this syntax tree node (to stdout).
875      * This method is intended for debugging _only_ !!!
876      * @param indent Indentation level for syntax tree levels.
877      */
displayContents(int indent)878     protected void displayContents(int indent) {
879         for (SyntaxTreeNode item : _contents) {
880             item.display(indent);
881         }
882     }
883 
884     /**
885      * Set the indentation level for debug output.
886      * @param indent Indentation level for syntax tree levels.
887      */
indent(int indent)888     protected final void indent(int indent) {
889         System.out.print(new String(_spaces, 0, indent));
890     }
891 
892     /**
893      * Report an error to the parser.
894      * @param element The element in which the error occured (normally 'this'
895      * but it could also be an expression/pattern/etc.)
896      * @param parser The XSLT parser to report the error to.
897      * @param error The error code (from util/ErrorMsg).
898      * @param message Any additional error message.
899      */
reportError(SyntaxTreeNode element, Parser parser, String errorCode, String message)900     protected void reportError(SyntaxTreeNode element, Parser parser,
901                                String errorCode, String message) {
902         final ErrorMsg error = new ErrorMsg(errorCode, message, element);
903         parser.reportError(Constants.ERROR, error);
904     }
905 
906     /**
907      * Report a recoverable error to the parser.
908      * @param element The element in which the error occured (normally 'this'
909      * but it could also be an expression/pattern/etc.)
910      * @param parser The XSLT parser to report the error to.
911      * @param error The error code (from util/ErrorMsg).
912      * @param message Any additional error message.
913      */
reportWarning(SyntaxTreeNode element, Parser parser, String errorCode, String message)914     protected  void reportWarning(SyntaxTreeNode element, Parser parser,
915                                   String errorCode, String message) {
916         final ErrorMsg error = new ErrorMsg(errorCode, message, element);
917         parser.reportError(Constants.WARNING, error);
918     }
919 
920 }
921