286N/A/*
286N/A * reserved comment block
286N/A * DO NOT REMOVE OR ALTER!
286N/A */
286N/A/*
286N/A * Copyright 2001-2004 The Apache Software Foundation.
286N/A *
286N/A * Licensed under the Apache License, Version 2.0 (the "License");
286N/A * you may not use this file except in compliance with the License.
286N/A * You may obtain a copy of the License at
286N/A *
286N/A * http://www.apache.org/licenses/LICENSE-2.0
286N/A *
286N/A * Unless required by applicable law or agreed to in writing, software
286N/A * distributed under the License is distributed on an "AS IS" BASIS,
286N/A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
286N/A * See the License for the specific language governing permissions and
286N/A * limitations under the License.
286N/A */
286N/A/*
286N/A * $Id: TestSeq.java,v 1.2.4.1 2005/09/12 11:31:38 pvedula Exp $
286N/A */
286N/A
286N/Apackage com.sun.org.apache.xalan.internal.xsltc.compiler;
286N/A
286N/Aimport java.util.Dictionary;
286N/Aimport java.util.Vector;
286N/A
286N/Aimport com.sun.org.apache.bcel.internal.generic.GOTO_W;
286N/Aimport com.sun.org.apache.bcel.internal.generic.InstructionHandle;
286N/Aimport com.sun.org.apache.bcel.internal.generic.InstructionList;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
286N/Aimport com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
286N/A
286N/A/**
286N/A * A test sequence is a sequence of patterns that
286N/A *
286N/A * (1) occured in templates in the same mode
286N/A * (2) share the same kernel node type (e.g. A/B and C/C/B)
286N/A * (3) may also contain patterns matching "*" and "node()"
286N/A * (element sequence only) or matching "@*" (attribute
286N/A * sequence only).
286N/A *
286N/A * A test sequence may have a default template, which will be
286N/A * instantiated if none of the other patterns match.
286N/A * @author Jacek Ambroziak
286N/A * @author Santiago Pericas-Geertsen
286N/A * @author Erwin Bolwidt <ejb@klomp.org>
286N/A * @author Morten Jorgensen <morten.jorgensen@sun.com>
286N/A */
286N/Afinal class TestSeq {
286N/A
286N/A /**
286N/A * Integer code for the kernel type of this test sequence
286N/A */
286N/A private int _kernelType;
286N/A
286N/A /**
286N/A * Vector of all patterns in the test sequence. May include
286N/A * patterns with "*", "@*" or "node()" kernel.
286N/A */
286N/A private Vector _patterns = null;
286N/A
286N/A /**
286N/A * A reference to the Mode object.
286N/A */
286N/A private Mode _mode = null;
286N/A
286N/A /**
286N/A * Default template for this test sequence
286N/A */
286N/A private Template _default = null;
286N/A
286N/A /**
286N/A * Instruction list representing this test sequence.
286N/A */
286N/A private InstructionList _instructionList;
286N/A
286N/A /**
286N/A * Cached handle to avoid compiling more than once.
286N/A */
286N/A private InstructionHandle _start = null;
286N/A
286N/A /**
286N/A * Creates a new test sequence given a set of patterns and a mode.
286N/A */
286N/A public TestSeq(Vector patterns, Mode mode) {
286N/A this(patterns, -2, mode);
286N/A }
286N/A
286N/A public TestSeq(Vector patterns, int kernelType, Mode mode) {
286N/A _patterns = patterns;
286N/A _kernelType = kernelType;
286N/A _mode = mode;
286N/A }
286N/A
286N/A /**
286N/A * Returns a string representation of this test sequence. Notice
286N/A * that test sequences are mutable, so the value returned by this
286N/A * method is different before and after calling reduce().
286N/A */
286N/A public String toString() {
286N/A final int count = _patterns.size();
286N/A final StringBuffer result = new StringBuffer();
286N/A
286N/A for (int i = 0; i < count; i++) {
286N/A final LocationPathPattern pattern =
286N/A (LocationPathPattern) _patterns.elementAt(i);
286N/A
286N/A if (i == 0) {
293N/A result.append("Testseq for kernel ").append(_kernelType)
286N/A .append('\n');
286N/A }
293N/A result.append(" pattern ").append(i).append(": ")
286N/A .append(pattern.toString())
286N/A .append('\n');
286N/A }
286N/A return result.toString();
286N/A }
286N/A
286N/A /**
286N/A * Returns the instruction list for this test sequence
286N/A */
286N/A public InstructionList getInstructionList() {
286N/A return _instructionList;
286N/A }
286N/A
286N/A /**
286N/A * Return the highest priority for a pattern in this test
286N/A * sequence. This is either the priority of the first or
286N/A * of the default pattern.
286N/A */
286N/A public double getPriority() {
286N/A final Template template = (_patterns.size() == 0) ? _default
286N/A : ((Pattern) _patterns.elementAt(0)).getTemplate();
286N/A return template.getPriority();
286N/A }
286N/A
286N/A /**
286N/A * Returns the position of the highest priority pattern in
286N/A * this test sequence.
286N/A */
286N/A public int getPosition() {
286N/A final Template template = (_patterns.size() == 0) ? _default
286N/A : ((Pattern) _patterns.elementAt(0)).getTemplate();
286N/A return template.getPosition();
286N/A }
286N/A
286N/A /**
286N/A * Reduce the patterns in this test sequence. Creates a new
286N/A * vector of patterns and sets the default pattern if it
286N/A * finds a patterns that is fully reduced.
286N/A */
286N/A public void reduce() {
286N/A final Vector newPatterns = new Vector();
286N/A
286N/A final int count = _patterns.size();
286N/A for (int i = 0; i < count; i++) {
286N/A final LocationPathPattern pattern =
286N/A (LocationPathPattern)_patterns.elementAt(i);
286N/A
286N/A // Reduce this pattern
286N/A pattern.reduceKernelPattern();
286N/A
286N/A // Is this pattern fully reduced?
286N/A if (pattern.isWildcard()) {
286N/A _default = pattern.getTemplate();
286N/A break; // Ignore following patterns
286N/A }
286N/A else {
286N/A newPatterns.addElement(pattern);
286N/A }
286N/A }
286N/A _patterns = newPatterns;
286N/A }
286N/A
286N/A /**
286N/A * Returns, by reference, the templates that are included in
286N/A * this test sequence. Note that a single template can occur
286N/A * in several test sequences if its pattern is a union.
286N/A */
286N/A public void findTemplates(Dictionary templates) {
286N/A if (_default != null) {
286N/A templates.put(_default, this);
286N/A }
286N/A for (int i = 0; i < _patterns.size(); i++) {
286N/A final LocationPathPattern pattern =
286N/A (LocationPathPattern)_patterns.elementAt(i);
286N/A templates.put(pattern.getTemplate(), this);
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Get the instruction handle to a template's code. This is
286N/A * used when a single template occurs in several test
286N/A * sequences; that is, if its pattern is a union of patterns
286N/A * (e.g. match="A/B | A/C").
286N/A */
286N/A private InstructionHandle getTemplateHandle(Template template) {
286N/A return (InstructionHandle)_mode.getTemplateInstructionHandle(template);
286N/A }
286N/A
286N/A /**
286N/A * Returns pattern n in this test sequence
286N/A */
286N/A private LocationPathPattern getPattern(int n) {
286N/A return (LocationPathPattern)_patterns.elementAt(n);
286N/A }
286N/A
286N/A /**
286N/A * Compile the code for this test sequence. Compile patterns
286N/A * from highest to lowest priority. Note that since patterns
286N/A * can be share by multiple test sequences, instruction lists
286N/A * must be copied before backpatching.
286N/A */
286N/A public InstructionHandle compile(ClassGenerator classGen,
286N/A MethodGenerator methodGen,
286N/A InstructionHandle continuation)
286N/A {
286N/A // Returned cached value if already compiled
286N/A if (_start != null) {
286N/A return _start;
286N/A }
286N/A
286N/A // If not patterns, then return handle for default template
286N/A final int count = _patterns.size();
286N/A if (count == 0) {
286N/A return (_start = getTemplateHandle(_default));
286N/A }
286N/A
286N/A // Init handle to jump when all patterns failed
286N/A InstructionHandle fail = (_default == null) ? continuation
286N/A : getTemplateHandle(_default);
286N/A
286N/A // Compile all patterns in reverse order
286N/A for (int n = count - 1; n >= 0; n--) {
286N/A final LocationPathPattern pattern = getPattern(n);
286N/A final Template template = pattern.getTemplate();
286N/A final InstructionList il = new InstructionList();
286N/A
286N/A // Patterns expect current node on top of stack
286N/A il.append(methodGen.loadCurrentNode());
286N/A
286N/A // Apply the test-code compiled for the pattern
286N/A InstructionList ilist = methodGen.getInstructionList(pattern);
286N/A if (ilist == null) {
286N/A ilist = pattern.compile(classGen, methodGen);
286N/A methodGen.addInstructionList(pattern, ilist);
286N/A }
286N/A
286N/A // Make a copy of the instruction list for backpatching
286N/A InstructionList copyOfilist = ilist.copy();
286N/A
286N/A FlowList trueList = pattern.getTrueList();
286N/A if (trueList != null) {
286N/A trueList = trueList.copyAndRedirect(ilist, copyOfilist);
286N/A }
286N/A FlowList falseList = pattern.getFalseList();
286N/A if (falseList != null) {
286N/A falseList = falseList.copyAndRedirect(ilist, copyOfilist);
286N/A }
286N/A
286N/A il.append(copyOfilist);
286N/A
286N/A // On success branch to the template code
286N/A final InstructionHandle gtmpl = getTemplateHandle(template);
286N/A final InstructionHandle success = il.append(new GOTO_W(gtmpl));
286N/A
286N/A if (trueList != null) {
286N/A trueList.backPatch(success);
286N/A }
286N/A if (falseList != null) {
286N/A falseList.backPatch(fail);
286N/A }
286N/A
286N/A // Next pattern's 'fail' target is this pattern's first instruction
286N/A fail = il.getStart();
286N/A
286N/A // Append existing instruction list to the end of this one
286N/A if (_instructionList != null) {
286N/A il.append(_instructionList);
286N/A }
286N/A
286N/A // Set current instruction list to be this one
286N/A _instructionList = il;
286N/A }
286N/A return (_start = fail);
286N/A }
286N/A}