All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.org.apache.xalan.internal.xsltc.compiler.TestSeq Maven / Gradle / Ivy

The newest version!
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 *
 *
 * This file incorporates work covered by the following copyright and
 * permission notice:
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * $Id: TestSeq.java,v 1.10 2010-11-01 04:34:18 joehw Exp $
 */
package com.sun.org.apache.xalan.internal.xsltc.compiler;

import java.util.Dictionary;
import java.util.Vector;

import com.sun.org.apache.bcel.internal.generic.GOTO_W;
import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
import com.sun.org.apache.bcel.internal.generic.InstructionList;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;

/**
 * A test sequence is a sequence of patterns that
 *
 *  (1) occured in templates in the same mode
 *  (2) share the same kernel node type (e.g. A/B and C/C/B)
 *  (3) may also contain patterns matching "*" and "node()"
 *      (element sequence only) or matching "@*" (attribute
 *      sequence only).
 *
 * A test sequence may have a default template, which will be 
 * instantiated if none of the other patterns match. 
 * @author Jacek Ambroziak
 * @author Santiago Pericas-Geertsen
 * @author Erwin Bolwidt 
 * @author Morten Jorgensen 
 */
final class TestSeq {

    /**
     * Integer code for the kernel type of this test sequence
     */
    private int _kernelType;

    /**
     * Vector of all patterns in the test sequence. May include
     * patterns with "*", "@*" or "node()" kernel.
     */
    private Vector _patterns = null;

    /**
     * A reference to the Mode object.
     */
    private Mode _mode = null;

    /**
     * Default template for this test sequence
     */
    private Template _default = null;

    /**
     * Instruction list representing this test sequence.
     */
    private InstructionList _instructionList;

    /**
     * Cached handle to avoid compiling more than once.
     */
    private InstructionHandle _start = null;

    /**
     * Creates a new test sequence given a set of patterns and a mode.
     */
    public TestSeq(Vector patterns, Mode mode) {
	this(patterns, -2, mode);
    }

    public TestSeq(Vector patterns, int kernelType, Mode mode) {
	_patterns = patterns;
	_kernelType = kernelType;
	_mode = mode;
    }

    /**
     * Returns a string representation of this test sequence. Notice
     * that test sequences are mutable, so the value returned by this
     * method is different before and after calling reduce().
     */
    public String toString() {
	final int count = _patterns.size();
	final StringBuffer result = new StringBuffer();

	for (int i = 0; i < count; i++) {
	    final LocationPathPattern pattern =
		(LocationPathPattern) _patterns.elementAt(i);

	    if (i == 0) {
		result.append("Testseq for kernel " + _kernelType)
		      .append('\n');
	    }
	    result.append("   pattern " + i + ": ")
	          .append(pattern.toString())
		  .append('\n');
	}
	return result.toString();
    }

    /**
     * Returns the instruction list for this test sequence
     */
    public InstructionList getInstructionList() {
	return _instructionList;
    }

    /**
     * Return the highest priority for a pattern in this test
     * sequence. This is either the priority of the first or
     * of the default pattern.
     */
    public double getPriority() {
	final Template template = (_patterns.size() == 0) ? _default 
	    : ((Pattern) _patterns.elementAt(0)).getTemplate();
	return template.getPriority();
    }

    /**
     * Returns the position of the highest priority pattern in 
     * this test sequence.
     */
    public int getPosition() {
	final Template template = (_patterns.size() == 0) ? _default 
	    : ((Pattern) _patterns.elementAt(0)).getTemplate();
	return template.getPosition();
    }

    /**
     * Reduce the patterns in this test sequence. Creates a new
     * vector of patterns and sets the default pattern if it
     * finds a patterns that is fully reduced.
     */
    public void reduce() {
	final Vector newPatterns = new Vector();

	final int count = _patterns.size();
	for (int i = 0; i < count; i++) {
	    final LocationPathPattern pattern =
		(LocationPathPattern)_patterns.elementAt(i);
		
	    // Reduce this pattern
	    pattern.reduceKernelPattern();
			
	    // Is this pattern fully reduced?
	    if (pattern.isWildcard()) {
		_default = pattern.getTemplate();
		break; 		// Ignore following patterns 
	    }
	    else {
		newPatterns.addElement(pattern);
	    }
	}
	_patterns = newPatterns;
    }

    /**
     * Returns, by reference, the templates that are included in 
     * this test sequence. Note that a single template can occur 
     * in several test sequences if its pattern is a union.
     */
    public void findTemplates(Dictionary templates) {
	if (_default != null) {
	    templates.put(_default, this);
	}
	for (int i = 0; i < _patterns.size(); i++) {
	    final LocationPathPattern pattern =
		(LocationPathPattern)_patterns.elementAt(i);
	    templates.put(pattern.getTemplate(), this);
	}
    }

    /**
     * Get the instruction handle to a template's code. This is 
     * used when a single template occurs in several test 
     * sequences; that is, if its pattern is a union of patterns 
     * (e.g. match="A/B | A/C").
     */
    private InstructionHandle getTemplateHandle(Template template) {
	return (InstructionHandle)_mode.getTemplateInstructionHandle(template);
    }

    /**
     * Returns pattern n in this test sequence
     */
    private LocationPathPattern getPattern(int n) {
	return (LocationPathPattern)_patterns.elementAt(n);
    }

    /**
     * Compile the code for this test sequence. Compile patterns 
     * from highest to lowest priority. Note that since patterns 
     * can be share by multiple test sequences, instruction lists 
     * must be copied before backpatching.
     */
    public InstructionHandle compile(ClassGenerator classGen,
				     MethodGenerator methodGen,
				     InstructionHandle continuation) 
    {
	// Returned cached value if already compiled
	if (_start != null) {
	    return _start;
	}

	// If not patterns, then return handle for default template
	final int count = _patterns.size();
	if (count == 0) {
	    return (_start = getTemplateHandle(_default));
	}

	// Init handle to jump when all patterns failed
	InstructionHandle fail = (_default == null) ? continuation
	    : getTemplateHandle(_default);
	
	// Compile all patterns in reverse order
	for (int n = count - 1; n >= 0; n--) {
	    final LocationPathPattern pattern = getPattern(n);
	    final Template template = pattern.getTemplate();
	    final InstructionList il = new InstructionList();

	    // Patterns expect current node on top of stack
	    il.append(methodGen.loadCurrentNode());

	    // Apply the test-code compiled for the pattern
	    InstructionList ilist = methodGen.getInstructionList(pattern);
	    if (ilist == null) {
		ilist = pattern.compile(classGen, methodGen);
		methodGen.addInstructionList(pattern, ilist);
	    }

	    // Make a copy of the instruction list for backpatching
	    InstructionList copyOfilist = ilist.copy();

	    FlowList trueList = pattern.getTrueList();
	    if (trueList != null) {
		trueList = trueList.copyAndRedirect(ilist, copyOfilist);
	    }
	    FlowList falseList = pattern.getFalseList();
	    if (falseList != null) {
		falseList = falseList.copyAndRedirect(ilist, copyOfilist);
	    }

	    il.append(copyOfilist);

	    // On success branch to the template code
	    final InstructionHandle gtmpl = getTemplateHandle(template);
	    final InstructionHandle success = il.append(new GOTO_W(gtmpl));

	    if (trueList != null) {
		trueList.backPatch(success);
	    }
	    if (falseList != null) {
		falseList.backPatch(fail);
	    } 

	    // Next pattern's 'fail' target is this pattern's first instruction
	    fail = il.getStart();

	    // Append existing instruction list to the end of this one
	    if (_instructionList != null) {
		il.append(_instructionList);
	    }

	    // Set current instruction list to be this one
	    _instructionList = il;
	}
	return (_start = fail);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy