OSDN Git Service

libjava/ChangeLog:
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / xml / xpath / EqualityExpr.java
1 /* EqualityExpr.java -- 
2    Copyright (C) 2004 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38 package gnu.xml.xpath;
39
40 import java.util.Collection;
41 import java.util.Iterator;
42 import javax.xml.namespace.QName;
43 import org.w3c.dom.Node;
44
45 /**
46  * Boolean equality expression.
47  *
48  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
49  */
50 final class EqualityExpr
51   extends Expr
52 {
53
54   final Expr lhs;
55   final Expr rhs;
56   final boolean invert;
57
58   EqualityExpr(Expr lhs, Expr rhs, boolean invert)
59   {
60     this.lhs = lhs;
61     this.rhs = rhs;
62     this.invert = invert;
63   }
64
65   @Override
66   public Object evaluate(Node context, int pos, int len)
67   {
68     boolean val = evaluateImpl(context, pos, len);
69     if (invert)
70       {
71         return val ? Boolean.FALSE : Boolean.TRUE;
72       }
73     else
74       {
75         return val ? Boolean.TRUE : Boolean.FALSE;
76       }
77   }
78
79   private boolean evaluateImpl(Node context, int pos, int len)
80   {
81     Object left = lhs.evaluate(context, pos, len);
82     Object right = rhs.evaluate(context, pos, len);
83
84     /*
85      * If both objects to be compared are node-sets, then the comparison
86      * will be true if and only if there is a node in the first node-set and
87      * a node in the second node-set such that the result of performing the
88      * comparison on the string-values of the two nodes is true.
89      */
90     boolean flns = left instanceof Collection;
91     boolean frns = right instanceof Collection;
92     if (flns && frns)
93       {
94         /* Suppression is safe, as we know context produces Collection<Node> */
95         @SuppressWarnings("unchecked") 
96           Collection<Node> lns = (Collection<Node>) left;
97         @SuppressWarnings("unchecked")
98           Collection<Node> rns = (Collection<Node>) right;
99         if (lns.isEmpty())
100           {
101             return false;
102           }
103         boolean all = true;
104         for (Node ltest : lns)
105           {
106             for (Node rtest : rns)
107               {
108                 if (ltest == rtest || ltest.equals(rtest))
109                   {
110                     // much shorter
111                     if (!invert)
112                       {
113                         return true;
114                       }
115                   }
116                 else if (stringValue(ltest).equals(stringValue(rtest)))
117                   {
118                     if (!invert)
119                       {
120                         return true;
121                       }
122                   }
123                 else
124                   {
125                     all = false;
126                   }
127               }
128           }
129         return all;
130       }
131     /* 
132      * If one object to be compared is a node-set and the other is a number,
133      * then the comparison will be true if and only if there is a node in
134      * the node-set such that the result of performing the comparison on the
135      * number to be compared and on the result of converting the
136      * string-value of that node to a number using the number function is
137      * true.
138      */
139     boolean fln = left instanceof Double;
140     boolean frn = right instanceof Double;
141     if ((flns && frn) || (frns && fln))
142       {
143         /* Suppression is safe, as we know context produces Collection<Node> */
144         @SuppressWarnings("unchecked") 
145           Collection<Node> ns = flns ? (Collection<Node>) left : (Collection<Node>) right;
146         double n = fln ? ((Double) left).doubleValue() :
147           ((Double) right).doubleValue();
148         boolean all = true;
149         for (Node test : ns)
150           {
151             double nn = _number(context, stringValue(test));
152             if (nn == n)
153               {
154                 if (!invert)
155                   {
156                     return true;
157                   }
158               }
159             else
160               {
161                 all = false;
162               }
163           }
164         return invert ? all : false;
165       }
166     /*
167      * If one object to be compared is a node-set and the other is a
168      * string, then the comparison will be true if and only if there is a
169      * node in the node-set such that the result of performing the
170      * comparison on the string-value of the node and the other string is
171      * true.
172      */
173     boolean fls = left instanceof String;
174     boolean frs = right instanceof String;
175     if ((flns && frs) || (frns && fls))
176       {
177         /* Suppression is safe, as we know context produces Collection<Node> */
178         @SuppressWarnings("unchecked") 
179           Collection<Node> ns = flns ? (Collection<Node>) left : (Collection<Node>) right;
180         String s = fls ? (String) left : (String) right;
181         boolean all = true;
182         for (Node test : ns)
183           {
184             if (stringValue(test).equals(s))
185               {
186                 if (!invert)
187                   {
188                     return true;
189                   }
190               }
191             else
192               {
193                 all = false;
194               }
195           }
196         return invert ? all : false;
197       }
198     /*
199      * If one object to be compared is a node-set and the other is a
200      * boolean, then the comparison will be true if and only if the result
201      * of performing the comparison on the boolean and on the result of
202      * converting the node-set to a boolean using the boolean function is
203      * true.
204      */
205     boolean flb = left instanceof Boolean;
206     boolean frb = right instanceof Boolean;
207     if ((flns && frb) || (frns && flb))
208       {
209         /* Suppression is safe, as we know context produces Collection<Node> */
210         @SuppressWarnings("unchecked") 
211           Collection<Node> ns = flns ? (Collection<Node>) left : (Collection<Node>) right;
212         boolean b = flb ? ((Boolean) left).booleanValue() :
213           ((Boolean) right).booleanValue();
214         return _boolean(context, ns) == b;
215       }
216     /*
217      * If at least one object to be compared is a boolean, then each object
218      * to be compared is converted to a boolean as if by applying the
219      * boolean function.
220      */
221     if (flb || frb)
222       {
223         boolean lb = flb ? ((Boolean) left).booleanValue() :
224           _boolean(context, left);
225         boolean rb = frb ? ((Boolean) right).booleanValue() :
226           _boolean(context, right);
227         return lb == rb;
228       }
229     /*
230      * Otherwise, if at least one object to be compared is
231      * a number, then each object to be compared is converted to a number as
232      * if by applying the number function.
233      */
234     if (fln || frn)
235       {
236         double ln = fln ? ((Double) left).doubleValue() :
237           _number(context, left);
238         double rn = frn ? ((Double) right).doubleValue() :
239           _number(context, right);
240         return ln == rn;
241       }
242     /*
243      * Otherwise, both objects to be
244      * compared are converted to strings as if by applying the string
245      * function.
246      */
247     String ls = fls ? (String) left : _string(context, left);
248     String rs = frs ? (String) right : _string(context, right);
249     return ls.equals(rs);
250   }
251
252   public Expr clone(Object context)
253   {
254     return new EqualityExpr(lhs.clone(context), rhs.clone(context), invert);
255   }
256
257   public boolean references(QName var)
258   {
259     return (lhs.references(var) || rhs.references(var));
260   }
261
262   public String toString()
263   {
264     if (invert)
265       {
266         return lhs + " != " + rhs;
267       }
268     else
269       {
270         return lhs + " = " + rhs;
271       }
272   }
273   
274 }