Project

Profile

Help

Revision c2310264

Added by O'Neil Delpratt almost 10 years ago

Bug fix to typeInference logic. Bug report ID: 3419499

View differences:

latest9.3/hej/net/sf/saxon/pattern/CombinedNodeTest.java
10 10
import net.sf.saxon.type.*;
11 11

  
12 12
/**
13
  * A CombinedNodeTest combines two nodetests using one of the operators
14
  * union (=or), intersect (=and), difference (= "and not"). This arises
15
  * when optimizing a union (etc) of two path expressions using the same axis.
16
  * A CombinedNodeTest is also used to support constructs such as element(N,T),
17
  * which can be expressed as (element(N,*) AND element(*,T))
18
  *
19
  * @author Michael H. Kay
20
  */
13
 * A CombinedNodeTest combines two nodetests using one of the operators
14
 * union (=or), intersect (=and), difference (= "and not"). This arises
15
 * when optimizing a union (etc) of two path expressions using the same axis.
16
 * A CombinedNodeTest is also used to support constructs such as element(N,T),
17
 * which can be expressed as (element(N,*) AND element(*,T))
18
 *
19
 * @author Michael H. Kay
20
 */
21 21

  
22 22
public class CombinedNodeTest extends NodeTest {
23 23

  
......
27 27

  
28 28
    /**
29 29
     * Create a NodeTest that combines two other node tests
30
     * @param nt1 the first operand. Note that if the defaultPriority of the pattern
31
     * is required, it will be taken from that of the first operand.
30
     *
31
     * @param nt1      the first operand. Note that if the defaultPriority of the pattern
32
     *                 is required, it will be taken from that of the first operand.
32 33
     * @param operator one of Token.UNION, Token.INTERSECT, Token.EXCEPT
33
     * @param nt2 the second operand
34
     * @param nt2      the second operand
34 35
     */
35 36

  
36 37
    public CombinedNodeTest(NodeTest nt1, int operator, NodeTest nt2) {
......
40 41
    }
41 42

  
42 43
    /**
43
    * Test whether this node test is satisfied by a given node.
44
    * @param nodeType The type of node to be matched
45
     @param fingerprint identifies the expanded name of the node to be matched.
46

  
44
     * Test whether this node test is satisfied by a given node.
45
     *
46
     * @param nodeType    The type of node to be matched
47
     * @param fingerprint identifies the expanded name of the node to be matched.
47 48
     */
48 49

  
49 50
    public boolean matches(int nodeType, int fingerprint, int annotation) {
50 51
        switch (operator) {
51 52
            case Token.UNION:
52
                return nodetest1==null ||
53
                       nodetest2==null ||
54
                       nodetest1.matches(nodeType, fingerprint, annotation) ||
55
                       nodetest2.matches(nodeType, fingerprint, annotation);
53
                return nodetest1 == null ||
54
                        nodetest2 == null ||
55
                        nodetest1.matches(nodeType, fingerprint, annotation) ||
56
                        nodetest2.matches(nodeType, fingerprint, annotation);
56 57
            case Token.INTERSECT:
57
                return (nodetest1==null || nodetest1.matches(nodeType, fingerprint, annotation)) &&
58
                       (nodetest2==null || nodetest2.matches(nodeType, fingerprint, annotation));
58
                return (nodetest1 == null || nodetest1.matches(nodeType, fingerprint, annotation)) &&
59
                        (nodetest2 == null || nodetest2.matches(nodeType, fingerprint, annotation));
59 60
            case Token.EXCEPT:
60
                return (nodetest1==null || nodetest1.matches(nodeType, fingerprint, annotation)) &&
61
                       !(nodetest2==null || nodetest2.matches(nodeType, fingerprint, annotation));
61
                return (nodetest1 == null || nodetest1.matches(nodeType, fingerprint, annotation)) &&
62
                        !(nodetest2 == null || nodetest2.matches(nodeType, fingerprint, annotation));
62 63
            default:
63 64
                throw new IllegalArgumentException("Unknown operator in Combined Node Test");
64 65
        }
......
79 80
    public boolean matches(TinyTree tree, int nodeNr) {
80 81
        switch (operator) {
81 82
            case Token.UNION:
82
                return nodetest1==null ||
83
                       nodetest2==null ||
84
                       nodetest1.matches(tree, nodeNr) ||
85
                       nodetest2.matches(tree, nodeNr);
83
                return nodetest1 == null ||
84
                        nodetest2 == null ||
85
                        nodetest1.matches(tree, nodeNr) ||
86
                        nodetest2.matches(tree, nodeNr);
86 87
            case Token.INTERSECT:
87
                return (nodetest1==null || nodetest1.matches(tree, nodeNr)) &&
88
                       (nodetest2==null || nodetest2.matches(tree, nodeNr));
88
                return (nodetest1 == null || nodetest1.matches(tree, nodeNr)) &&
89
                        (nodetest2 == null || nodetest2.matches(tree, nodeNr));
89 90
            case Token.EXCEPT:
90
                return (nodetest1==null || nodetest1.matches(tree, nodeNr)) &&
91
                       !(nodetest2==null || nodetest2.matches(tree, nodeNr));
91
                return (nodetest1 == null || nodetest1.matches(tree, nodeNr)) &&
92
                        !(nodetest2 == null || nodetest2.matches(tree, nodeNr));
92 93
            default:
93 94
                throw new IllegalArgumentException("Unknown operator in Combined Node Test");
94 95
        }
......
98 99
     * Test whether this node test is satisfied by a given node. This alternative
99 100
     * method is used in the case of nodes where calculating the fingerprint is expensive,
100 101
     * for example DOM or JDOM nodes.
102
     *
101 103
     * @param node the node to be matched
102 104
     */
103 105

  
104 106
    public boolean matches(NodeInfo node) {
105 107
        switch (operator) {
106 108
            case Token.UNION:
107
                return nodetest1==null ||
108
                       nodetest2==null ||
109
                       nodetest1.matches(node) ||
110
                       nodetest2.matches(node);
109
                return nodetest1 == null ||
110
                        nodetest2 == null ||
111
                        nodetest1.matches(node) ||
112
                        nodetest2.matches(node);
111 113
            case Token.INTERSECT:
112
                return (nodetest1==null || nodetest1.matches(node)) &&
113
                       (nodetest2==null || nodetest2.matches(node));
114
                return (nodetest1 == null || nodetest1.matches(node)) &&
115
                        (nodetest2 == null || nodetest2.matches(node));
114 116
            case Token.EXCEPT:
115
                return (nodetest1==null || nodetest1.matches(node)) &&
116
                       !(nodetest2==null || nodetest2.matches(node));
117
                return (nodetest1 == null || nodetest1.matches(node)) &&
118
                        !(nodetest2 == null || nodetest2.matches(node));
117 119
            default:
118 120
                throw new IllegalArgumentException("Unknown operator in Combined Node Test");
119 121
        }
120 122
    }
121 123

  
122 124
    public String toString(NamePool pool) {
123
        if (nodetest1 instanceof NameTest && operator==Token.INTERSECT) {
125
        if (nodetest1 instanceof NameTest && operator == Token.INTERSECT) {
124 126
            int kind = nodetest1.getPrimitiveType();
125 127
            String skind = (kind == Type.ELEMENT ? "element(" : "attribute(");
126 128
            String content = "";
127 129
            if (nodetest2 instanceof ContentTypeTest) {
128
                final SchemaType schemaType = ((ContentTypeTest)nodetest2).getSchemaType();
130
                final SchemaType schemaType = ((ContentTypeTest) nodetest2).getSchemaType();
129 131
                content = ", " + pool.getClarkName(schemaType.getFingerprint());
130 132
            }
131 133
            String name = pool.getClarkName(nodetest1.getFingerprint());
132 134
            return skind + name + content + ')';
133 135
        } else {
134
            String nt1 = (nodetest1==null ? "true()" : nodetest1.toString(pool));
135
            String nt2 = (nodetest2==null ? "true()" : nodetest2.toString(pool));
136
            String nt1 = (nodetest1 == null ? "true()" : nodetest1.toString(pool));
137
            String nt2 = (nodetest2 == null ? "true()" : nodetest2.toString(pool));
136 138
            return '(' + nt1 + ' ' + Token.tokens[operator] + ' ' + nt2 + ')';
137 139
        }
138 140
    }
139 141

  
140 142
    public String toString() {
141
        if (nodetest1 instanceof NameTest && operator==Token.INTERSECT) {
143
        if (nodetest1 instanceof NameTest && operator == Token.INTERSECT) {
142 144
            int kind = nodetest1.getPrimitiveType();
143 145
            String skind = (kind == Type.ELEMENT ? "element(" : "attribute(");
144 146
            String content = "";
145 147
            if (nodetest2 instanceof ContentTypeTest) {
146
                final SchemaType schemaType = ((ContentTypeTest)nodetest2).getSchemaType();
148
                final SchemaType schemaType = ((ContentTypeTest) nodetest2).getSchemaType();
147 149
                content = ", " + schemaType.getFingerprint();
148 150
            }
149 151
            String name = nodetest1.toString();
150 152
            return skind + name + content + ')';
151 153
        } else {
152
            String nt1 = (nodetest1==null ? "true()" : nodetest1.toString());
153
            String nt2 = (nodetest2==null ? "true()" : nodetest2.toString());
154
            String nt1 = (nodetest1 == null ? "true()" : nodetest1.toString());
155
            String nt2 = (nodetest2 == null ? "true()" : nodetest2.toString());
154 156
            return '(' + nt1 + ' ' + Token.tokens[operator] + ' ' + nt2 + ')';
155 157
        }
156 158
    }
......
159 161
    /**
160 162
     * Get the supertype of this type. This isn't actually a well-defined concept: the types
161 163
     * form a lattice rather than a strict hierarchy.
164
     *
162 165
     * @param th the type hierarchy cache
163 166
     */
164 167

  
......
203 206

  
204 207
    public int getPrimitiveType() {
205 208
        int mask = getNodeKindMask();
206
        if (mask == (1<<Type.ELEMENT)) {
209
        if (mask == (1 << Type.ELEMENT)) {
207 210
            return Type.ELEMENT;
208 211
        }
209
        if (mask == (1<<Type.ATTRIBUTE)) {
212
        if (mask == (1 << Type.ATTRIBUTE)) {
210 213
            return Type.ATTRIBUTE;
211 214
        }
212
        if (mask == (1<<Type.DOCUMENT)) {
215
        if (mask == (1 << Type.DOCUMENT)) {
213 216
            return Type.DOCUMENT;
214 217
        }
215 218
        return Type.NODE;
......
225 228
        IntSet s1 = nodetest1.getRequiredNodeNames();
226 229
        IntSet s2 = nodetest2.getRequiredNodeNames();
227 230
        if (s2 == null) {
228
            return s1;
231
            switch (operator) {
232
                case Token.UNION: {
233
                    return null;
234
                }
235
                case Token.INTERSECT: {
236
                    return s1;
237
                }
238
                case Token.EXCEPT: {
239
                    return new IntHashSet();
240
                }
241
                default:
242
                    throw new UnsupportedOperationException();
243
            }
229 244
        }
230 245
        if (s1 == null) {
231
            return s2;
246
            switch (operator) {
247
                case Token.UNION: {
248
                    return null;
249
                }
250
                case Token.INTERSECT: {
251
                    return s2;
252
                }
253
                case Token.EXCEPT: {
254
                    return null;
255
                }
256
                default:
257
                    throw new UnsupportedOperationException();
258
            }
232 259
        }
233 260
        switch (operator) {
234 261
            case Token.UNION: {
......
287 314

  
288 315
    /**
289 316
     * Ask whether values of this type are atomizable
317
     *
290 318
     * @return true unless it is known that these items will be elements with element-only
291 319
     *         content, in which case return false
292 320
     */
293 321

  
294 322
    public boolean isAtomizable() {
295
        return nodetest1.isAtomizable() && nodetest2.isAtomizable(); 
323
        return nodetest1.isAtomizable() && nodetest2.isAtomizable();
296 324
    }
297 325

  
298 326
    /**
......
304 332
        int fp1 = nodetest1.getFingerprint();
305 333
        int fp2 = nodetest2.getFingerprint();
306 334
        if (fp1 == fp2) return fp1;
307
        if (fp2 == -1 && operator==Token.INTERSECT) return fp1;
308
        if (fp1 == -1 && operator==Token.INTERSECT) return fp2;
335
        if (fp2 == -1 && operator == Token.INTERSECT) return fp1;
336
        if (fp1 == -1 && operator == Token.INTERSECT) return fp2;
309 337
        return -1;
310 338
    }
311 339

  
312 340
    /**
313 341
     * Determine whether the content type (if present) is nillable
342
     *
314 343
     * @return true if the content test (when present) can match nodes that are nilled
315 344
     */
316 345

  
......
320 349
    }
321 350

  
322 351
    /**
323
      * Returns a hash code value for the object.
324
      */
352
     * Returns a hash code value for the object.
353
     */
325 354

  
326
     public int hashCode() {
327
         return nodetest1.hashCode() ^ nodetest2.hashCode();
328
     }
355
    public int hashCode() {
356
        return nodetest1.hashCode() ^ nodetest2.hashCode();
357
    }
329 358

  
330 359
    /**
331 360
     * Indicates whether some other object is "equal to" this one.
332 361
     */
333 362
    public boolean equals(Object other) {
334 363
        return other instanceof CombinedNodeTest &&
335
                ((CombinedNodeTest)other).nodetest1.equals(nodetest1) &&
336
                ((CombinedNodeTest)other).nodetest2.equals(nodetest2) &&
337
                ((CombinedNodeTest)other).operator == operator;
364
                ((CombinedNodeTest) other).nodetest1.equals(nodetest1) &&
365
                ((CombinedNodeTest) other).nodetest2.equals(nodetest2) &&
366
                ((CombinedNodeTest) other).operator == operator;
338 367
    }
339 368

  
340 369
    /**
......
346 375
    public double getDefaultPriority() {
347 376
        if (operator == Token.UNION) {
348 377
            return nodetest1.getDefaultPriority();
349
         } else {
378
        } else {
350 379
            // typically it's element(E, T)
351 380
            return 0.25;
352 381
        }
......
354 383

  
355 384
    /**
356 385
     * Get the two parts of the combined node test
386
     *
357 387
     * @return the two operands
358 388
     */
359 389

  
360 390
    public NodeTest[] getComponentNodeTests() {
361
        return new NodeTest[] {nodetest1, nodetest2};
391
        return new NodeTest[]{nodetest1, nodetest2};
362 392
    }
363 393

  
364 394
    /**
365 395
     * Get the operator used to combine the two node tests: one of {@link Token#UNION},
366
     * {@link Token#INTERSECT}, {@link Token#EXCEPT}, 
396
     * {@link Token#INTERSECT}, {@link Token#EXCEPT},
397
     *
367 398
     * @return the operator
368 399
     */
369 400

  
......
373 404

  
374 405
    /**
375 406
     * Visit all the schema components used in this ItemType definition
407
     *
376 408
     * @param visitor the visitor class to be called when each component is visited
377 409
     */
378 410

  

Also available in: Unified diff