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 } |