1 /*
   2  * Copyright (c) 2015, 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.ConstantPoolGen;
  24 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  25 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  26 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  27 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  28 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  29 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  30 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType;
  31 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeType;
  32 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
  33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ResultTreeType;
  34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
  37 import com.sun.org.apache.xml.internal.utils.XML11Char;
  38 import java.util.ArrayList;
  39 import java.util.List;
  40 
  41 /**
  42  * @author Jacek Ambroziak
  43  * @author Santiago Pericas-Geertsen
  44  * @LastModified: Oct 2017
  45  */
  46 final class ApplyTemplates extends Instruction {
  47     private Expression _select;
  48     private Type       _type = null;
  49     private QName      _modeName;
  50     private String     _functionName;
  51 
  52     public void display(int indent) {
  53         indent(indent);
  54         Util.println("ApplyTemplates");
  55         indent(indent + IndentIncrement);
  56         Util.println("select " + _select.toString());
  57         if (_modeName != null) {
  58             indent(indent + IndentIncrement);
  59             Util.println("mode " + _modeName);
  60         }
  61     }
  62 
  63     public boolean hasWithParams() {
  64         return hasContents();
  65     }
  66 
  67     public void parseContents(Parser parser) {
  68         final String select = getAttribute("select");
  69         final String mode   = getAttribute("mode");
  70 
  71         if (select.length() > 0) {
  72             _select = parser.parseExpression(this, "select", null);
  73 
  74         }
  75 
  76         if (mode.length() > 0) {
  77             if (!XML11Char.isXML11ValidQName(mode)) {
  78                 ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, mode, this);
  79                 parser.reportError(Constants.ERROR, err);
  80             }
  81             _modeName = parser.getQNameIgnoreDefaultNs(mode);
  82         }
  83 
  84         // instantiate Mode if needed, cache (apply temp) function name
  85         _functionName =
  86             parser.getTopLevelStylesheet().getMode(_modeName).functionName();
  87         parseChildren(parser);// with-params
  88     }
  89 
  90     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  91         if (_select != null) {
  92             _type = _select.typeCheck(stable);
  93             if (_type instanceof NodeType || _type instanceof ReferenceType) {
  94                 _select = new CastExpr(_select, Type.NodeSet);
  95                 _type = Type.NodeSet;
  96             }
  97             if (_type instanceof NodeSetType||_type instanceof ResultTreeType) {
  98                 typeCheckContents(stable); // with-params
  99                 return Type.Void;
 100             }
 101             throw new TypeCheckError(this);
 102         }
 103         else {
 104             typeCheckContents(stable);          // with-params
 105             return Type.Void;
 106         }
 107     }
 108 
 109     /**
 110      * Translate call-template. A parameter frame is pushed only if
 111      * some template in the stylesheet uses parameters.
 112      */
 113     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
 114         boolean setStartNodeCalled = false;
 115         final Stylesheet stylesheet = classGen.getStylesheet();
 116         final ConstantPoolGen cpg = classGen.getConstantPool();
 117         final InstructionList il = methodGen.getInstructionList();
 118         final int current = methodGen.getLocalIndex("current");
 119 
 120         // check if sorting nodes is required
 121         final List<Sort> sortObjects = new ArrayList<>();
 122         for (final SyntaxTreeNode child : getContents()) {
 123             if (child instanceof Sort) {
 124                 sortObjects.add((Sort)child);
 125             }
 126         }
 127 
 128         // Push a new parameter frame
 129         if (stylesheet.hasLocalParams() || hasContents()) {
 130             il.append(classGen.loadTranslet());
 131             final int pushFrame = cpg.addMethodref(TRANSLET_CLASS,
 132                                                    PUSH_PARAM_FRAME,
 133                                                    PUSH_PARAM_FRAME_SIG);
 134             il.append(new INVOKEVIRTUAL(pushFrame));
 135             // translate with-params
 136             translateContents(classGen, methodGen);
 137         }
 138 
 139 
 140         il.append(classGen.loadTranslet());
 141 
 142         // The 'select' expression is a result-tree
 143         if ((_type != null) && (_type instanceof ResultTreeType)) {
 144             // <xsl:sort> cannot be applied to a result tree - issue warning
 145             if (sortObjects.size() > 0) {
 146                 ErrorMsg err = new ErrorMsg(ErrorMsg.RESULT_TREE_SORT_ERR,this);
 147                 getParser().reportError(WARNING, err);
 148             }
 149             // Put the result tree (a DOM adapter) on the stack
 150             _select.translate(classGen, methodGen);
 151             // Get back the DOM and iterator (not just iterator!!!)
 152             _type.translateTo(classGen, methodGen, Type.NodeSet);
 153         }
 154         else {
 155             il.append(methodGen.loadDOM());
 156 
 157             // compute node iterator for applyTemplates
 158             if (sortObjects.size() > 0) {
 159                 Sort.translateSortIterator(classGen, methodGen,
 160                                            _select, sortObjects);
 161                 int setStartNode = cpg.addInterfaceMethodref(NODE_ITERATOR,
 162                                                              SET_START_NODE,
 163                                                              "(I)"+
 164                                                              NODE_ITERATOR_SIG);
 165                 il.append(methodGen.loadCurrentNode());
 166                 il.append(new INVOKEINTERFACE(setStartNode,2));
 167                 setStartNodeCalled = true;
 168             }
 169             else {
 170                 if (_select == null)
 171                     Mode.compileGetChildren(classGen, methodGen, current);
 172                 else
 173                     _select.translate(classGen, methodGen);
 174             }
 175         }
 176 
 177         if (_select != null && !setStartNodeCalled) {
 178             _select.startIterator(classGen, methodGen);
 179         }
 180 
 181         //!!! need to instantiate all needed modes
 182         final String className = classGen.getStylesheet().getClassName();
 183         il.append(methodGen.loadHandler());
 184         final String applyTemplatesSig = classGen.getApplyTemplatesSig();
 185         final int applyTemplates = cpg.addMethodref(className,
 186                                                     _functionName,
 187                                                     applyTemplatesSig);
 188         il.append(new INVOKEVIRTUAL(applyTemplates));
 189 
 190         // unmap parameters to release temporary result trees
 191         for (final SyntaxTreeNode child : getContents()) {
 192             if (child instanceof WithParam) {
 193                 ((WithParam)child).releaseResultTree(classGen, methodGen);
 194             }
 195         }
 196 
 197         // Pop parameter frame
 198         if (stylesheet.hasLocalParams() || hasContents()) {
 199             il.append(classGen.loadTranslet());
 200             final int popFrame = cpg.addMethodref(TRANSLET_CLASS,
 201                                                   POP_PARAM_FRAME,
 202                                                   POP_PARAM_FRAME_SIG);
 203             il.append(new INVOKEVIRTUAL(popFrame));
 204         }
 205     }
 206 }