1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * @LastModified: Nov 2017 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.ConstantPoolGen; 25 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; 26 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL; 27 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; 28 import com.sun.org.apache.bcel.internal.generic.InstructionList; 29 import com.sun.org.apache.bcel.internal.generic.NEW; 30 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; 31 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; 32 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; 33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError; 34 import com.sun.org.apache.xml.internal.dtm.Axis; 35 import com.sun.org.apache.xml.internal.dtm.DTM; 36 import java.util.ArrayList; 37 import java.util.List; 38 39 /** 40 * @author Jacek Ambroziak 41 * @author Santiago Pericas-Geertsen 42 */ 43 final class UnionPathExpr extends Expression { 44 45 private final Expression _pathExpr; 46 private final Expression _rest; 47 private boolean _reverse = false; 48 49 // linearization for top level UnionPathExprs 50 private Expression[] _components; 51 52 public UnionPathExpr(Expression pathExpr, Expression rest) { 53 _pathExpr = pathExpr; 54 _rest = rest; 55 } 56 57 public void setParser(Parser parser) { 58 super.setParser(parser); 59 // find all expressions in this Union 60 final List<Expression> components = new ArrayList<>(); 61 flatten(components); 62 final int size = components.size(); 63 _components = components.toArray(new Expression[size]); 64 for (int i = 0; i < size; i++) { 65 _components[i].setParser(parser); 66 _components[i].setParent(this); 67 if (_components[i] instanceof Step) { 68 final Step step = (Step)_components[i]; 69 final int axis = step.getAxis(); 70 final int type = step.getNodeType(); 71 // Put attribute iterators first 72 if ((axis == Axis.ATTRIBUTE) || (type == DTM.ATTRIBUTE_NODE)) { 73 _components[i] = _components[0]; 74 _components[0] = step; 75 } 76 // Check if the union contains a reverse iterator 77 if (Axis.isReverse(axis)) _reverse = true; 78 } 79 } 80 // No need to reverse anything if another expression lies on top of this 81 if (getParent() instanceof Expression) _reverse = false; 82 } 83 84 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 85 final int length = _components.length; 86 for (int i = 0; i < length; i++) { 87 if (_components[i].typeCheck(stable) != Type.NodeSet) { 88 _components[i] = new CastExpr(_components[i], Type.NodeSet); 89 } 90 } 91 return _type = Type.NodeSet; 92 } 93 94 public String toString() { 95 return "union(" + _pathExpr + ", " + _rest + ')'; 96 } 97 98 private void flatten(List<Expression> components) { 99 components.add(_pathExpr); 100 if (_rest != null) { 101 if (_rest instanceof UnionPathExpr) { 102 ((UnionPathExpr)_rest).flatten(components); 103 } 104 else { 105 components.add(_rest); 106 } 107 } 108 } 109 110 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 111 final ConstantPoolGen cpg = classGen.getConstantPool(); 112 final InstructionList il = methodGen.getInstructionList(); 113 114 final int init = cpg.addMethodref(UNION_ITERATOR_CLASS, 115 "<init>", 116 "("+DOM_INTF_SIG+")V"); 117 final int iter = cpg.addMethodref(UNION_ITERATOR_CLASS, 118 ADD_ITERATOR, 119 ADD_ITERATOR_SIG); 120 121 // Create the UnionIterator and leave it on the stack 122 il.append(new NEW(cpg.addClass(UNION_ITERATOR_CLASS))); 123 il.append(DUP); 124 il.append(methodGen.loadDOM()); 125 il.append(new INVOKESPECIAL(init)); 126 127 // Add the various iterators to the UnionIterator 128 final int length = _components.length; 129 for (int i = 0; i < length; i++) { 130 _components[i].translate(classGen, methodGen); 131 il.append(new INVOKEVIRTUAL(iter)); 132 } 133 134 // Order the iterator only if strictly needed 135 if (_reverse) { 136 final int order = cpg.addInterfaceMethodref(DOM_INTF, 137 ORDER_ITERATOR, 138 ORDER_ITERATOR_SIG); 139 il.append(methodGen.loadDOM()); 140 il.append(SWAP); 141 il.append(methodGen.loadContextNode()); 142 il.append(new INVOKEINTERFACE(order, 3)); 143 144 } 145 } 146 }