src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Whitespace.java
changeset 47359 e1a6c0168741
parent 47216 71c04702a3d5
child 47477 115ed64c7822
equal deleted inserted replaced
47358:d07d5f7cab35 47359:e1a6c0168741
     1 /*
     1 /*
     2  * reserved comment block
     2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT REMOVE OR ALTER!
     3  * @LastModified: Oct 2017
     4  */
     4  */
     5 /*
     5 /*
     6  * Licensed to the Apache Software Foundation (ASF) under one or more
     6  * Licensed to the Apache Software Foundation (ASF) under one or more
     7  * contributor license agreements.  See the NOTICE file distributed with
     7  * contributor license agreements.  See the NOTICE file distributed with
     8  * this work for additional information regarding copyright ownership.
     8  * this work for additional information regarding copyright ownership.
    19  * limitations under the License.
    19  * limitations under the License.
    20  */
    20  */
    21 
    21 
    22 package com.sun.org.apache.xalan.internal.xsltc.compiler;
    22 package com.sun.org.apache.xalan.internal.xsltc.compiler;
    23 
    23 
    24 import java.util.StringTokenizer;
       
    25 import java.util.Vector;
       
    26 
       
    27 import com.sun.org.apache.bcel.internal.generic.ALOAD;
    24 import com.sun.org.apache.bcel.internal.generic.ALOAD;
    28 import com.sun.org.apache.bcel.internal.generic.BranchHandle;
    25 import com.sun.org.apache.bcel.internal.generic.BranchHandle;
    29 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
    26 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
    30 import com.sun.org.apache.bcel.internal.generic.IF_ICMPEQ;
    27 import com.sun.org.apache.bcel.internal.generic.IF_ICMPEQ;
    31 import com.sun.org.apache.bcel.internal.generic.ILOAD;
    28 import com.sun.org.apache.bcel.internal.generic.ILOAD;
    38 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
    35 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
    39 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
    36 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
    40 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
    37 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
    41 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
    38 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
    42 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
    39 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
       
    40 import java.util.ArrayList;
       
    41 import java.util.List;
       
    42 import java.util.StringTokenizer;
    43 
    43 
    44 /**
    44 /**
    45  * @author Morten Jorgensen
    45  * @author Morten Jorgensen
    46  */
    46  */
    47 final class Whitespace extends TopLevelElement {
    47 final class Whitespace extends TopLevelElement {
    61     private int    _importPrecedence;
    61     private int    _importPrecedence;
    62 
    62 
    63     /**
    63     /**
    64      * Auxillary class for encapsulating a single strip/preserve rule
    64      * Auxillary class for encapsulating a single strip/preserve rule
    65      */
    65      */
    66     private final static class WhitespaceRule {
    66     final static class WhitespaceRule {
    67         private final int _action;
    67         private final int _action;
    68         private String _namespace; // Should be replaced by NS type (int)
    68         private String _namespace; // Should be replaced by NS type (int)
    69         private String _element;   // Should be replaced by node type (int)
    69         private String _element;   // Should be replaced by node type (int)
    70         private int    _type;
    70         private int    _type;
    71         private int    _priority;
    71         private int    _priority;
   172 
   172 
   173     /**
   173     /**
   174      * De-tokenize the elements listed in the 'elements' attribute and
   174      * De-tokenize the elements listed in the 'elements' attribute and
   175      * instanciate a set of strip/preserve rules.
   175      * instanciate a set of strip/preserve rules.
   176      */
   176      */
   177     public Vector getRules() {
   177     public List<WhitespaceRule> getRules() {
   178         final Vector rules = new Vector();
   178         final List<WhitespaceRule> rules = new ArrayList<>();
   179         // Go through each element and instanciate strip/preserve-object
   179         // Go through each element and instanciate strip/preserve-object
   180         final StringTokenizer list = new StringTokenizer(_elementList);
   180         final StringTokenizer list = new StringTokenizer(_elementList);
   181         while (list.hasMoreElements()) {
   181         while (list.hasMoreElements()) {
   182             rules.add(new WhitespaceRule(_action,
   182             rules.add(new WhitespaceRule(_action,
   183                                          list.nextToken(),
   183                                          list.nextToken(),
   189 
   189 
   190     /**
   190     /**
   191      * Scans through the rules vector and looks for a rule of higher
   191      * Scans through the rules vector and looks for a rule of higher
   192      * priority that contradicts the current rule.
   192      * priority that contradicts the current rule.
   193      */
   193      */
   194     private static WhitespaceRule findContradictingRule(Vector rules,
   194     private static WhitespaceRule findContradictingRule(List<WhitespaceRule> rules,
   195                                                         WhitespaceRule rule) {
   195                                                         WhitespaceRule rule) {
   196         for (int i = 0; i < rules.size(); i++) {
   196         for (WhitespaceRule currentRule : rules) {
   197             // Get the next rule in the prioritized list
       
   198             WhitespaceRule currentRule = (WhitespaceRule)rules.elementAt(i);
       
   199             // We only consider rules with higher priority
   197             // We only consider rules with higher priority
   200             if (currentRule == rule) {
   198             if (currentRule == rule) {
   201                 return null;
   199                 return null;
   202             }
   200             }
   203 
   201 
   204             /*
   202             /*
   205              * See if there is a contradicting rule with higher priority.
   203             * See if there is a contradicting rule with higher priority.
   206              * If the rules has the same action then this rule is redundant,
   204             * If the rules has the same action then this rule is redundant,
   207              * if they have different action then this rule will never win.
   205             * if they have different action then this rule will never win.
   208              */
   206             */
   209             switch (currentRule.getStrength()) {
   207             switch (currentRule.getStrength()) {
   210             case RULE_ALL:
   208                 case RULE_ALL:
   211                 return currentRule;
   209                     return currentRule;
   212 
   210 
   213             case RULE_ELEMENT:
   211                 case RULE_ELEMENT:
   214                 if (!rule.getElement().equals(currentRule.getElement())) {
   212                     if (!rule.getElement().equals(currentRule.getElement())) {
       
   213                         break;
       
   214                     }
       
   215                 // intentional fall-through
       
   216                 case RULE_NAMESPACE:
       
   217                     if (rule.getNamespace().equals(currentRule.getNamespace())) {
       
   218                         return currentRule;
       
   219                     }
   215                     break;
   220                     break;
   216                 }
       
   217                 // intentional fall-through
       
   218             case RULE_NAMESPACE:
       
   219                 if (rule.getNamespace().equals(currentRule.getNamespace())) {
       
   220                     return currentRule;
       
   221                 }
       
   222                 break;
       
   223             }
   221             }
   224         }
   222         }
   225         return null;
   223         return null;
   226     }
   224     }
   227 
   225 
   228 
   226 
   229     /**
   227     /**
   230      * Orders a set or rules by priority, removes redundant rules and rules
   228      * Orders a set or rules by priority, removes redundant rules and rules
   231      * that are shadowed by stronger, contradicting rules.
   229      * that are shadowed by stronger, contradicting rules.
   232      */
   230      */
   233     private static int prioritizeRules(Vector rules) {
   231     private static int prioritizeRules(List<WhitespaceRule> rules) {
   234         WhitespaceRule currentRule;
   232         WhitespaceRule currentRule;
   235         int defaultAction = PRESERVE_SPACE;
   233         int defaultAction = PRESERVE_SPACE;
   236 
   234 
   237         // Sort all rules with regard to priority
   235         // Sort all rules with regard to priority
   238         quicksort(rules, 0, rules.size()-1);
   236         quicksort(rules, 0, rules.size()-1);
   240         // Check if there are any "xsl:strip-space" elements at all.
   238         // Check if there are any "xsl:strip-space" elements at all.
   241         // If there are no xsl:strip elements we can ignore all xsl:preserve
   239         // If there are no xsl:strip elements we can ignore all xsl:preserve
   242         // elements and signal that all whitespaces should be preserved
   240         // elements and signal that all whitespaces should be preserved
   243         boolean strip = false;
   241         boolean strip = false;
   244         for (int i = 0; i < rules.size(); i++) {
   242         for (int i = 0; i < rules.size(); i++) {
   245             currentRule = (WhitespaceRule)rules.elementAt(i);
   243             currentRule = rules.get(i);
   246             if (currentRule.getAction() == STRIP_SPACE) {
   244             if (currentRule.getAction() == STRIP_SPACE) {
   247                 strip = true;
   245                 strip = true;
   248             }
   246             }
   249         }
   247         }
   250         // Return with default action: PRESERVE_SPACE
   248         // Return with default action: PRESERVE_SPACE
   251         if (!strip) {
   249         if (!strip) {
   252             rules.removeAllElements();
   250             rules.clear();
   253             return PRESERVE_SPACE;
   251             return PRESERVE_SPACE;
   254         }
   252         }
   255 
   253 
   256         // Remove all rules that are contradicted by rules with higher priority
   254         // Remove all rules that are contradicted by rules with higher priority
   257         for (int idx = 0; idx < rules.size(); ) {
   255         for (int idx = 0; idx < rules.size(); ) {
   258             currentRule = (WhitespaceRule)rules.elementAt(idx);
   256             currentRule = rules.get(idx);
   259 
   257 
   260             // Remove this single rule if it has no purpose
   258             // Remove this single rule if it has no purpose
   261             if (findContradictingRule(rules,currentRule) != null) {
   259             if (findContradictingRule(rules,currentRule) != null) {
   262                 rules.remove(idx);
   260                 rules.remove(idx);
   263             }
   261             }
   264             else {
   262             else {
   265                 // Remove all following rules if this one overrides all
   263                 // Remove all following rules if this one overrides all
   266                 if (currentRule.getStrength() == RULE_ALL) {
   264                 if (currentRule.getStrength() == RULE_ALL) {
   267                     defaultAction = currentRule.getAction();
   265                     defaultAction = currentRule.getAction();
   268                     for (int i = idx; i < rules.size(); i++) {
   266                     for (int i = idx; i < rules.size(); i++) {
   269                         rules.removeElementAt(i);
   267                         rules.remove(i);
   270                     }
   268                     }
   271                 }
   269                 }
   272                 // Skip to next rule (there might not be any)...
   270                 // Skip to next rule (there might not be any)...
   273                 idx++;
   271                 idx++;
   274             }
   272             }
   275         }
   273         }
   276 
   274 
   277         // The rules vector could be empty if first rule has strength RULE_ALL
   275         // The rules vector could be empty if first rule has strength RULE_ALL
   278         if (rules.size() == 0) {
   276         if (rules.isEmpty()) {
   279             return defaultAction;
   277             return defaultAction;
   280         }
   278         }
   281 
   279 
   282         // Now work backwards and strip away all rules that have the same
   280         // Now work backwards and strip away all rules that have the same
   283         // action as the default rule (no reason the check them at the end).
   281         // action as the default rule (no reason the check them at the end).
   284         do {
   282         do {
   285             currentRule = (WhitespaceRule)rules.lastElement();
   283             currentRule = rules.get(rules.size() - 1);
   286             if (currentRule.getAction() == defaultAction) {
   284             if (currentRule.getAction() == defaultAction) {
   287                 rules.removeElementAt(rules.size() - 1);
   285                 rules.remove(rules.size() - 1);
   288             }
   286             }
   289             else {
   287             else {
   290                 break;
   288                 break;
   291             }
   289             }
   292         } while (rules.size() > 0);
   290         } while (rules.size() > 0);
   328     */
   326     */
   329 
   327 
   330     /**
   328     /**
   331      * Compiles the predicate method
   329      * Compiles the predicate method
   332      */
   330      */
   333     private static void compilePredicate(Vector rules,
   331     private static void compilePredicate(List<WhitespaceRule> rules,
   334                                          int defaultAction,
   332                                          int defaultAction,
   335                                          ClassGenerator classGen) {
   333                                          ClassGenerator classGen) {
   336         final ConstantPoolGen cpg = classGen.getConstantPool();
   334         final ConstantPoolGen cpg = classGen.getConstantPool();
   337         final InstructionList il = new InstructionList();
   335         final InstructionList il = new InstructionList();
   338         final XSLTC xsltc = classGen.getParser().getXSLTC();
   336         final XSLTC xsltc = classGen.getParser().getXSLTC();
   361         int pCount = 0;
   359         int pCount = 0;
   362 
   360 
   363         // Traverse all strip/preserve rules
   361         // Traverse all strip/preserve rules
   364         for (int i = 0; i<rules.size(); i++) {
   362         for (int i = 0; i<rules.size(); i++) {
   365             // Get the next rule in the prioritised list
   363             // Get the next rule in the prioritised list
   366             WhitespaceRule rule = (WhitespaceRule)rules.elementAt(i);
   364             WhitespaceRule rule = rules.get(i);
   367 
   365 
   368             // Returns the namespace for a node in the DOM
   366             // Returns the namespace for a node in the DOM
   369             final int gns = cpg.addInterfaceMethodref(DOM_INTF,
   367             final int gns = cpg.addInterfaceMethodref(DOM_INTF,
   370                                                       "getNamespaceName",
   368                                                       "getNamespaceName",
   371                                                       "(I)Ljava/lang/String;");
   369                                                       "(I)Ljava/lang/String;");
   465      * whitespace text-nodes:
   463      * whitespace text-nodes:
   466      *    - USE_PREDICATE  (run the method generated by this method)
   464      *    - USE_PREDICATE  (run the method generated by this method)
   467      *    - STRIP_SPACE    (always strip whitespace text-nodes)
   465      *    - STRIP_SPACE    (always strip whitespace text-nodes)
   468      *    - PRESERVE_SPACE (always preserve whitespace text-nodes)
   466      *    - PRESERVE_SPACE (always preserve whitespace text-nodes)
   469      */
   467      */
   470     public static int translateRules(Vector rules,
   468     public static int translateRules(List<WhitespaceRule> rules,
   471                                      ClassGenerator classGen) {
   469                                      ClassGenerator classGen) {
   472         // Get the core rules in prioritized order
   470         // Get the core rules in prioritized order
   473         final int defaultAction = prioritizeRules(rules);
   471         final int defaultAction = prioritizeRules(rules);
   474         // The rules vector may be empty after prioritising
   472         // The rules vector may be empty after prioritising
   475         if (rules.size() == 0) {
   473         if (rules.size() == 0) {
   483     }
   481     }
   484 
   482 
   485     /**
   483     /**
   486      * Sorts a range of rules with regard to PRIORITY only
   484      * Sorts a range of rules with regard to PRIORITY only
   487      */
   485      */
   488     private static void quicksort(Vector rules, int p, int r) {
   486     private static void quicksort(List<WhitespaceRule> rules, int p, int r) {
   489         while (p < r) {
   487         while (p < r) {
   490             final int q = partition(rules, p, r);
   488             final int q = partition(rules, p, r);
   491             quicksort(rules, p, q);
   489             quicksort(rules, p, q);
   492             p = q + 1;
   490             p = q + 1;
   493         }
   491         }
   494     }
   492     }
   495 
   493 
   496     /**
   494     /**
   497      * Used with quicksort method above
   495      * Used with quicksort method above
   498      */
   496      */
   499     private static int partition(Vector rules, int p, int r) {
   497     private static int partition(List<WhitespaceRule> rules, int p, int r) {
   500         final WhitespaceRule x = (WhitespaceRule)rules.elementAt((p+r) >>> 1);
   498         final WhitespaceRule x = rules.get((p+r) >>> 1);
   501         int i = p - 1, j = r + 1;
   499         int i = p - 1, j = r + 1;
   502         while (true) {
   500         while (true) {
   503             while (x.compareTo((WhitespaceRule)rules.elementAt(--j)) < 0) {
   501             while (x.compareTo(rules.get(--j)) < 0) {
   504             }
   502             }
   505             while (x.compareTo((WhitespaceRule)rules.elementAt(++i)) > 0) {
   503             while (x.compareTo(rules.get(++i)) > 0) {
   506             }
   504             }
   507             if (i < j) {
   505             if (i < j) {
   508                 final WhitespaceRule tmp = (WhitespaceRule)rules.elementAt(i);
   506                 final WhitespaceRule tmp = rules.get(i);
   509                 rules.setElementAt(rules.elementAt(j), i);
   507                 rules.set(i, rules.get(j));
   510                 rules.setElementAt(tmp, j);
   508                 rules.set(j, tmp);
   511             }
   509             }
   512             else {
   510             else {
   513                 return j;
   511                 return j;
   514             }
   512             }
   515         }
   513         }