KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > xquery > normalize > ExpressionNormalizationVisitor


1 /*
2  * This file belongs to the XQuark distribution.
3  * Copyright (C) 2003 Universite de Versailles Saint-Quentin.
4  * Copyright (C) 2003 XQuark Group.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307.
19  * You can also get it at http://www.gnu.org/licenses/lgpl.html
20  *
21  * For more information on this software, see http://www.xquark.org.
22  */

23
24 package org.xquark.xquery.normalize;
25
26 //For all contants used in the structure:
27
import java.util.*;
28
29 import org.xml.sax.SAXException JavaDoc;
30 import org.xquark.schema.Schema;
31 import org.xquark.xpath.Axis;
32 import org.xquark.xpath.NodeKind;
33 import org.xquark.xquery.parser.*;
34 import org.xquark.xquery.parser.primitivefunctions.fnfunctions.*;
35 import org.xquark.xquery.parser.primitivefunctions.xsfunctions.FunctionSTRING;
36 import org.xquark.xquery.parser.util.Constants;
37 import org.xquark.xquery.typing.QType;
38 import org.xquark.xquery.typing.TypeException;
39 import org.xquark.xquery.typing.TypeVisitor;
40
41 /**
42  * This class is an implementation of org.xquark.xml.xqueryparser.common.ParserVisitor interface. <BR>
43  * It extends org.xquark.xml.xqueryparser.common.DefaultParserVisitor class. <BR>
44  * In each node of the XQuery structure, the ExpressionNormalizationVisitor identified if a normalization rule/concept can be applied and construct a new normalized XQuery structure. <BR>
45  * This visitor maintains the type of each node of the XQuery structure if they were typified in entry. <BR>
46  * <BR>- You MUST visit a XQueryFile node to begin the normalization. If you have a XQueryExpression, you must build a XQueryUnit with expresion and a XQueryFile with the XqueryUnit. <BR>
47  */

48
49 /*
50  * TODO List: - chercher et enlever les "REMOVE" et debug (sans casse): - chercher et enlever les appel _trace(..) et untrace() - chercher et faire les "TODO" - Faire modifier le type visiteur pour deplacer le test de retypage (force + qtype != null) au tout debut (pour ne pas perdre de temps au retypage.
51  */

52
53 public class ExpressionNormalizationVisitor extends org.xquark.xquery.parser.DefaultParserVisitor {
54
55     /** CVS/QA stuff. */
56     private static final String JavaDoc RCSRevision = "$Revision: 1.12 $";
57
58     /** CVS/QA stuff. */
59     private static final String JavaDoc RCSName = "$Name: $";
60
61     /*
62      * In this class, in this following order, you can found:
63      *
64      * 1) Protected properties 2) Protected constants 3) Constructors 4) Protected and package methods (except debug methods) 5) Public methods (except visit methods) 6) Protected debug methods 7) Public/protected visit methods in parameter type alphabetical order:
65      */

66
67     /** ************************* Protected properties ****************************** */
68
69     private final boolean reType = true;
70     
71     /** The type visitor. */
72     protected TypeVisitor typeVisitor = null;
73
74     /** The current normalised XQueryExpression. */
75     protected XQueryExpression expr = null;
76
77     /** The visitor context (contains some questions/responses). */
78     protected VisitorContext context = null;
79
80     /** Absolute depth in the XQuery structure (in the tree). */
81     protected int depth = -1;
82
83     /** To know if a normalize rule was applied. */
84     protected boolean normalized;
85
86     /** Hash map of all variables declarations (to clone partial xquery expressions). */
87     protected HashMap variablesDeclarations = null;
88
89     private AtomizeVisitor atomizeVisitor = new AtomizeVisitor(typeVisitor);
90
91     private String JavaDoc sourceName = null;
92
93     /** ************************* Protected constants ****************************** */
94
95     /** The default XML namespace prefix. */
96     protected final String JavaDoc DEFAULT_XML_PREFIX = "xml";
97
98     /** The default XML namespace url. */
99     protected final String JavaDoc DEFAULT_XML_URL = "http://www.w3.org/XML/1998/namespace";
100
101     /** The default Schema namespace prefix. */
102     protected final String JavaDoc DEFAULT_SCHEMA_PREFIX = "xs";
103
104     /** The default Schema namespace url. */
105     protected final String JavaDoc DEFAULT_SCHEMA_URL = "http://www.w3.org/2001/XMLSchema";
106
107     /** The default Schema instance namespace prefix. */
108     protected final String JavaDoc DEFAULT_SCHEMA_INSTANCE_PREFIX = "xsi";
109
110     /** The default Schema instance namespace url. */
111     protected final String JavaDoc DEFAULT_SCHEMA_INSTANCE_URL = "http://www.w3.org/2001/XMLSchema-instance";
112
113     /** The default function namespace prefix. */
114     protected final String JavaDoc DEFAULT_FUNCTION_PREFIX = "xf";
115
116     /** The default function namespace url. */
117     protected final String JavaDoc DEFAULT_FUNCTION_URL = "http://www.w3.org/2002/08/xquery-functions";
118
119     /** The default operator namespace prefix. */
120     protected final String JavaDoc DEFAULT_OPERATOR_PREFIX = "op";
121
122     /** The default operator namespace url. */
123     protected final String JavaDoc DEFAULT_OPERATOR_URL = "http://www.w3.org/2002/08/xquery-operators";
124
125     /** ************************* Constructors ****************************** */
126
127     /**
128      * To construct a new visitor to create a canonical request from a valid XQuery request.
129      *
130      * @throws NormalizeException
131      */

132     // public ExpressionNormalizationVisitor() throws NormalizeException {
133
// this(new VisitorContext(), -1, null);
134
// }
135
/**
136      * To construct a new visitor to create a canonical request from a valid XQuery request.
137      *
138      * @param typeVisitor
139      * a type visitor maintain typing of the XQuery structure.
140      * @throws NormalizeException
141      */

142     public ExpressionNormalizationVisitor(TypeVisitor typeVisitor, String JavaDoc sourceName) throws NormalizeException {
143         this(new VisitorContext(), -1, typeVisitor, sourceName);
144     }
145
146     /**
147      * To construct a new visitor to create a canonical request from a valid XQuery request.
148      *
149      * @param depth
150      * the absolute depth in the XQuery structure (it is a tree).
151      * @throws NormalizeException
152      */

153     // protected ExpressionNormalizationVisitor(int depth) throws NormalizeException {
154
// this(new VisitorContext(), depth, null);
155
// }
156
/**
157      * To construct a new visitor to create a canonical request from a valid XQuery request.
158      *
159      * @param depth
160      * the absolute depth in the XQuery structure (it is a tree).
161      * @param typeVisitor
162      * a type visitor maintain typing of the XQuery structure.
163      * @throws NormalizeException
164      */

165     protected ExpressionNormalizationVisitor(int depth, TypeVisitor typeVisitor, String JavaDoc sourceName) throws NormalizeException {
166         this(new VisitorContext(), depth, typeVisitor, sourceName);
167     }
168
169     /**
170      * To construct a new visitor to create a canonical request from a valid XQuery request.
171      *
172      * @param ctx
173      * a context to set as this visitor context.
174      * @param depth
175      * the absolute depth in the XQuery structure (it is a tree).
176      * @param typeVisitor
177      * a type visitor maintain typing of the XQuery structure.
178      * @throws NormalizeException
179      */

180     protected ExpressionNormalizationVisitor(VisitorContext ctx, int depth, TypeVisitor typeVisitor, String JavaDoc sourceName) throws NormalizeException {
181         this.context = ctx;
182         this.expr = null;
183         this.depth = depth + 1;
184         this.normalized = false;
185         this.typeVisitor = typeVisitor;
186         this.sourceName = sourceName;
187     }
188
189     /** ************************* Protected and package methods ****************************** */
190
191     private FLWRExpression createDummyFLWR(XQueryExpression whereClause, XQueryExpression returnClause) throws XQueryException, TypeException {
192         Variable var = typeVisitor.getStaticContext().createVariable(Constants.FOR_BINDINGTYPE, new ValueInteger("1", returnClause.getParentModule()), Variable.NORM_CREATOR);
193         ArrayList vars = new ArrayList(1);
194         vars.add(var);
195         XQueryModule unit = returnClause.getParentModule();
196         FLWRExpression flwr = new FLWRExpression(vars, null, whereClause, returnClause, returnClause.getParentModule());
197         flwr.setParentModule(unit);
198         return flwr;
199     }
200
201     /**
202      * To get the current context.
203      *
204      * @return the current context.
205      */

206     protected VisitorContext getContext() {
207         return this.context;
208     }
209
210     /**
211      * To set the current context.
212      *
213      * @param the
214      * new context.
215      */

216     protected void setContext(VisitorContext ctx) {
217         this.context = ctx;
218     }
219
220     /**
221      * To get the current depth.
222      *
223      * @return the current depth.
224      */

225     protected int getDepth() {
226         return this.depth;
227     }
228
229     /** ************************* Public methods ****************************** */
230
231     /**
232      * To re-initialize this object, like call constructor ExpressionNormalizationVisitor(-1).
233      *
234      * @throws NormalizeException
235      */

236     public void reInit() throws NormalizeException {
237         this.context = new VisitorContext();
238         this.expr = null;
239         this.depth = 0;
240         this.normalized = false;
241     }
242
243     /**
244      * Gets the current XQuery expression normalized.
245      *
246      * @return the current XQuery expression normalized.
247      */

248     public XQueryExpression getExpr() {
249         return this.expr;
250     }
251
252     /**
253      * To know if a normalize rule was applied.
254      *
255      * @return true if a normalize rule was applied, false otherwise.
256      */

257     public boolean wasNormalized() {
258         return this.normalized;
259     }
260
261     /** ***************************************************************************** */
262     /** ******************** Public/protected visit methods ************************* */
263     /** ***************************************************************************** */
264
265     /**
266      * This visit method normalizes a XQueryUnit : its context declaration, its function definition and its sub expressions. <BR>
267      * It also answers the questions of the current context.
268      *
269      * @param arg
270      * a XQueryUnit to normalize.
271      */

272     public void visit(XQueryModule arg) throws NormalizeException {
273         // ADD LARS 25/02/04
274
typeVisitor.setNoForce(false);
275         // END ADD LARS 25/02/04
276
try {
277             ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
278             int pass = 0;
279             //varCounter = 0;
280
boolean removed = false;
281             //Loop for each pass while at least a rule was apply.
282
do {
283                 normalized = false;
284                 pass++;
285                 //Normalize variable definitions:
286
/*
287                  * HashMap hashVarList = arg.getVariables(); if (hashVarList != null) { Collection varValues = hashVarList.values(); Iterator itValues = varValues.iterator(); while (itValues.hasNext()) { HashMap map = (HashMap)itValues.next(); Iterator keys = map.keySet().iterator(); while (keys.hasNext()) { Object key = keys.next(); ((Variable) map.get(key)).accept(recurseVisitor); XQueryExpression newVarDef = recurseVisitor.getExpr(); if (newVarDef == null) { map.remove(key); } else { //Set parent unit : newVarDef.setParentModule(arg); map.put(key, newVarDef); } //Update the normalized flag: this.normalized = this.normalized | recurseVisitor.wasNormalized(); } } }
288                  */

289                 //Normalize function definitions:
290
/*
291                  * HashMap hashFuncList = arg.getFunctions(); if (hashFuncList != null) { Collection funcValues = hashFuncList.values(); Iterator itValues = funcValues.iterator(); while (itValues.hasNext()) { HashMap map = (HashMap)itValues.next(); Iterator keys = map.keySet().iterator(); while (keys.hasNext()) { Object key = keys.next(); ((FunctionDeclaration) map.get(key)).accept(recurseVisitor); XQueryExpression newFuncDef = recurseVisitor.getExpr(); if (newFuncDef == null) { map.remove(key); } else { //Set parent unit : newFuncDef.setParentModule(arg); map.put(key, newFuncDef); } //Update the normalized flag: this.normalized = this.normalized | recurseVisitor.wasNormalized(); } } }
292                  */

293                 //Normalize expressions:
294
ArrayList expressions = arg.getExpressions();
295                 if (expressions != null) {
296                     int exprLen = expressions.size();
297                     for (int i = exprLen - 1; i >= 0; i--) {
298                         recurseVisitor.reInit();
299                         XQueryExpression expri = (XQueryExpression) expressions.get(i);
300                         expri.accept(recurseVisitor);
301                         XQueryExpression newExpr = recurseVisitor.getExpr();
302                         if (newExpr == null) {
303                             expressions.remove(i);
304                             removed = true;
305                         } else {
306                             //Set parent unit :
307
newExpr.setParentModule(arg);
308                             expressions.set(i, newExpr);
309                         }
310                         //Update the normalized flag:
311
this.normalized = this.normalized | recurseVisitor.wasNormalized();
312                     }
313                 }
314                 if (pass > 32)
315                     throw new NormalizeException(0, "Infinite loop on normalization of " + arg + "<==\n");
316             } while (this.normalized && !removed);
317
318         } catch (XQueryException e) {
319             throw new NormalizeException(0, e.getMessage());
320         }
321         // ADD LARS 25/02/04
322
typeVisitor.setNoForce(true);
323         // END ADD LARS 25/02/04
324
}
325
326     /**
327      * This visit method normalizes a XQueryExpression (abstract class). It do nothing : this is the default behaviour for all unsupported expressions type. <BR>
328      *
329      * @param arg
330      * a XQueryExpression to normalize.
331      */

332     public void visit(XQueryExpression arg) throws NormalizeException {
333         this.expr = arg;
334     }
335
336     /** ****** Unary/Binary operator ******* */
337
338     /**
339      * This visit method normalizes a Dereference LE(E1)=>E2 and its sub expressions (E1, E2). <BR>
340      * This method apply theses rules: <BR>
341      * <OL>
342      * <LI>N(LE(E1)=>E2) => N(LE(E1))=>N(E2)</LI>
343      * <LI>N(null=>E2) => null</LI>
344      * <LI>N(LE(E1)=>null) => null</LI>
345      * </OL>
346      * It possibly answers the questions of the current context.
347      *
348      * @param arg
349      * a Dereference to normalize.
350      */

351
352     /**
353      * This visit method normalizes an UnOpMinusExpression and its expression (its value). <BR>
354      * This method apply theses rules: <BR>
355      * <OL>
356      * <LI>N(-E) => -N(E)</LI>
357      * <LI>N(-null) => null</LI>
358      * </OL>
359      * It possibly answers the questions of the current context.
360      *
361      * @param arg
362      * an UnOpMinusExpression to normalize.
363      */

364     public void visit(UnOpMinusExpression arg) throws NormalizeException {
365         try {
366             ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
367             VisitorContext localCtx = new VisitorContext();
368             localCtx.merge(this.context, false);
369             //Clean all questions which depth is smaller than current depth:
370
localCtx.filter(this.depth);
371             recurseVisitor.setContext(localCtx);
372             //Normalize expression of this UnOpMinusExpression:
373
XQueryExpression anExpr = arg.getExpression();
374             anExpr.accept(recurseVisitor);
375             localCtx.update(recurseVisitor.getContext());
376             anExpr = recurseVisitor.getExpr();
377             //Update the normalized flag:
378
this.normalized = recurseVisitor.wasNormalized();
379             //Test if sub expression was normalized:
380
if (this.normalized) {
381                 if (anExpr != null) {
382                     //Update current UnOpMinusExpression:
383
arg.setExpression(anExpr);
384                     //Re-type this expression :
385
if (reType) {
386                         arg.accept(typeVisitor);
387                     }
388                 } else {
389                     arg = null;
390                 }
391             }
392             this.expr = arg;
393             //Update response context with current context to pass the answers of parent questions:
394
this.context.update(localCtx);
395         } catch (XQueryException e) {
396             throw new NormalizeException(0, e);
397         }
398     }
399
400     /**
401      * This visit method normalizes a BinOpANDExpression (E1 and E2) and its sub expressions (E1 and E2). <BR>
402      * This method apply theses rules: <BR>
403      * <OL>
404      * <LI>N(E1 and E2) => N(E1) and N(E2)</LI>
405      * <LI>N(true() and true()) => true()</LI>
406      * <LI>N(false()|null and E) => false()</LI>
407      * <LI>N(E and false()|null) => false()</LI>
408      * </OL>
409      * It also answers the questions of the current context.
410      *
411      * @param arg
412      * a BinOpANDExpression to normalize.
413      */

414     public void visit(BinOpANDExpression arg) throws NormalizeException {
415         try {
416             ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
417             VisitorContext localCtx = new VisitorContext();
418             localCtx.merge(this.context, false);
419             //Clean all questions which depth is smaller than current depth:
420
localCtx.filter(this.depth);
421             recurseVisitor.setContext(localCtx);
422             //For multivalued expression (put in exists function) :
423
localCtx.setMemo((this.depth + 1), VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION, null, true);
424             //Normalize first expression:
425
XQueryExpression expr1 = arg.getExpression1();
426             expr1.accept(recurseVisitor);
427             localCtx.update(recurseVisitor.getContext());
428             expr1 = recurseVisitor.getExpr();
429             //Update the normalized flag:
430
this.normalized = recurseVisitor.wasNormalized();
431             //Test if sub expression was normalized:
432
if (this.normalized) {
433                 if (expr1 != null) {
434                     //Update current UnOpMinusExpression:
435
arg.setExpression1(expr1);
436                 } else {
437                     arg = null;
438                 }
439             }
440             //Normalize second expression:
441
XQueryExpression expr2 = null;
442             if (arg != null) {
443                 expr2 = arg.getExpression2();
444                 expr2.accept(recurseVisitor);
445                 localCtx.update(recurseVisitor.getContext());
446                 expr2 = recurseVisitor.getExpr();
447                 //Update the normalized flag:
448
this.normalized = this.normalized | recurseVisitor.wasNormalized();
449                 //Test if sub expression was normalized:
450
if (recurseVisitor.wasNormalized()) {
451                     if (expr2 != null) {
452                         //Update current UnOpMinusExpression:
453
arg.setExpression2(expr2);
454                     } else {
455                         arg = null;
456                     }
457                 }
458             }
459             //For multivalued expression (put in exists function) :
460
localCtx.removeMemo((this.depth + 1), VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION);
461             //Evaluation of this AND expression :
462
if (arg == null) {
463                 //Here : we can evaluate this boolean expression :
464
this.expr = new FunctionFALSE(null, arg.getParentModule());
465                 this.normalized = true;
466             } else if ((expr1 instanceof FunctionFALSE) || (expr2 instanceof FunctionFALSE)) {
467                 //Here : we can evaluate this boolean expression :
468
this.expr = new FunctionFALSE(null, arg.getParentModule());
469                 this.normalized = true;
470             } else if ((expr1 instanceof FunctionTRUE) && (expr2 instanceof FunctionTRUE)) {
471                 //Here : we can evaluate this boolean expression :
472
this.expr = new FunctionTRUE(null, arg.getParentModule());
473                 this.normalized = true;
474             } else if (expr1 instanceof FunctionTRUE) {
475                 this.expr = expr2;
476                 this.normalized = true;
477             } else if (expr2 instanceof FunctionTRUE) {
478                 this.expr = expr1;
479                 this.normalized = true;
480             } else {
481                 this.expr = arg;
482             }
483             //Re-type this expression :
484
if (reType && this.normalized && (this.expr != null)) {
485                 this.expr.accept(typeVisitor);
486             }
487             //Update response context with current context to pass the answers of parent questions:
488
this.context.update(localCtx);
489         } catch (XQueryException e) {
490             throw new NormalizeException(0, e);
491         }
492     }
493
494     /**
495      * This visit method normalizes a BinOpORExpression (E1 or E2) and its sub expressions (E1 and E2). <BR>
496      * This method apply theses rules: <BR>
497      * <OL>
498      * <LI>N(E1 or E2) => N(E1) or N(E2)</LI>
499      * <LI>N(false()|null or false()|null) => false()</LI>
500      * <LI>N(true() or E) => true()</LI>
501      * <LI>N(E or true()) => true()</LI>
502      * </OL>
503      * It also answers the questions of the current context.
504      *
505      * @param arg
506      * a BinOpORExpression to normalize.
507      */

508     public void visit(BinOpORExpression arg) throws NormalizeException {
509         try {
510             ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
511             VisitorContext localCtx = new VisitorContext();
512             localCtx.merge(this.context, false);
513             //Clean all questions which depth is smaller than current depth:
514
localCtx.filter(this.depth);
515             recurseVisitor.setContext(localCtx);
516             //For multivalued expression (put in exists function) :
517
localCtx.setMemo((this.depth + 1), VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION, null, true);
518             //Normalize first expression:
519
XQueryExpression expr1 = arg.getExpression1();
520             expr1.accept(recurseVisitor);
521             localCtx.update(recurseVisitor.getContext());
522             expr1 = recurseVisitor.getExpr();
523             //Update the normalized flag:
524
this.normalized = recurseVisitor.wasNormalized();
525             if ((this.normalized) && (expr1 != null)) {
526                 arg.setExpression1(expr1);
527             }
528             //Normalize second expression:
529
XQueryExpression expr2 = arg.getExpression2();
530             expr2.accept(recurseVisitor);
531             localCtx.update(recurseVisitor.getContext());
532             expr2 = recurseVisitor.getExpr();
533             //Update the normalized flag:
534
this.normalized = this.normalized | recurseVisitor.wasNormalized();
535             if ((recurseVisitor.wasNormalized()) && (expr2 != null)) {
536                 arg.setExpression2(expr2);
537             }
538             //For multivalued expression (put in exists function) :
539
localCtx.removeMemo((this.depth + 1), VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION);
540             //Evaluation of this OR expression :
541
if (expr1 == null) {
542                 this.normalized = true;
543                 if (expr2 == null) {
544                     this.expr = new FunctionFALSE(null, arg.getParentModule());
545                 } else if (expr2 instanceof FunctionFALSE) {
546                     this.expr = new FunctionFALSE(null, arg.getParentModule());
547                 } else if (expr2 instanceof FunctionTRUE) {
548                     this.expr = new FunctionTRUE(null, arg.getParentModule());
549                 } else {
550                     this.expr = expr2;
551                 }
552             } else if (expr1 instanceof FunctionFALSE) {
553                 this.normalized = true;
554                 if (expr2 == null) {
555                     this.expr = new FunctionFALSE(null, arg.getParentModule());
556                 } else if (expr2 instanceof FunctionFALSE) {
557                     this.expr = new FunctionFALSE(null, arg.getParentModule());
558                 } else if (expr2 instanceof FunctionTRUE) {
559                     this.expr = new FunctionTRUE(null, arg.getParentModule());
560                 } else {
561                     this.expr = expr2;
562                 }
563             } else if (expr1 instanceof FunctionTRUE) {
564                 this.normalized = true;
565                 this.expr = new FunctionTRUE(null, arg.getParentModule());
566             } else {
567                 if (expr2 == null) {
568                     this.expr = expr1;
569                     this.normalized = true;
570                 } else if (expr2 instanceof FunctionFALSE) {
571                     this.expr = expr1;
572                     this.normalized = true;
573                 } else if (expr2 instanceof FunctionTRUE) {
574                     this.expr = new FunctionTRUE(null, arg.getParentModule());
575                     this.normalized = true;
576                 } else {
577                     this.expr = arg;
578                 }
579             }
580             //Re-type this expression :
581
if (reType && this.normalized && this.expr != null) {
582                 this.expr.accept(typeVisitor);
583             }
584             //Update response context with current context to pass the answers of parent questions:
585
this.context.update(localCtx);
586         } catch (XQueryException e) {
587             throw new NormalizeException(0, e);
588         }
589     }
590
591     /**
592      * This visit method normalizes a ListOpArithExpression (E1 operator E2) and its sub expressions (E1 and E2). <BR>
593      * This method apply theses rules: <BR>
594      * <OL>
595      * <LI>N(E1 operator E2) => N(E1) operator N(E2)</LI>
596      * <LI>N(null operator E) => null (where E cannot be evaluated)</LI>
597      * <LI>N(E operator null) => null (where E cannot be evaluated)</LI>
598      * <LI>N(null operator null) => null</LI>
599      * </OL>
600      * It also answers the questions of the current context.
601      *
602      * @param arg
603      * a ListOpArithExpression to normalize.
604      */

605     public void visit(ListOpArithExpression arg) throws NormalizeException {
606         try {
607             ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
608             VisitorContext localCtx = new VisitorContext();
609             localCtx.merge(this.context, false);
610             //Clean all questions which depth is smaller than current depth:
611
localCtx.filter(this.depth);
612             recurseVisitor.setContext(localCtx);
613             //Normalize first expression:
614
XQueryExpression expr1 = arg.getExpression1();
615             expr1.accept(recurseVisitor);
616             localCtx.update(recurseVisitor.getContext());
617             expr1 = recurseVisitor.getExpr();
618             expr1.accept(atomizeVisitor);
619             expr1 = atomizeVisitor.getExpression();
620             //Update the normalized flag:
621
this.normalized = recurseVisitor.wasNormalized();
622             if (this.normalized) {
623                 if (expr1 != null) {
624                     arg.setExpression1(expr1);
625                 } else {
626                     arg = null;
627                 }
628             }
629             //Normalize second expression:
630
XQueryExpression expr2 = null;
631             if (arg != null) {
632                 expr2 = arg.getExpression2();
633                 expr2.accept(recurseVisitor);
634                 localCtx.update(recurseVisitor.getContext());
635                 expr2 = recurseVisitor.getExpr();
636                 expr2.accept(atomizeVisitor);
637                 expr2 = atomizeVisitor.getExpression();
638                 //Update the normalized flag:
639
this.normalized = this.normalized | recurseVisitor.wasNormalized();
640                 if (recurseVisitor.wasNormalized()) {
641                     if (expr2 != null) {
642                         arg.setExpression2(expr2);
643                     } else {
644                         arg = null;
645                     }
646                 }
647             }
648             this.expr = arg;
649             //Re-type this expression :
650
if (reType && this.normalized && this.expr != null) {
651                 this.expr.accept(typeVisitor);
652             }
653             //Update response context with current context to pass the answers of parent questions:
654
this.context.update(localCtx);
655         } catch (XQueryException e) {
656             throw new NormalizeException(0, e);
657         }
658     }
659
660     /**
661      * This visit method normalizes a ListOpCompExpression (E1 " <"|">"|">="|" <="|"="|"!="|"=="|"!==" E2) and its sub expressions (E1 and E2). <BR>
662      * This method apply theses rules: <BR>
663      * <OL>
664      * <LI>N(E1 comparison E2) => N(E1) comparison N(E2)</LI>
665      * <LI>N(null comparison E) => null (where E cannot be evaluated)</LI>
666      * <LI>N(E comparison null) => null (where E cannot be evaluated)</LI>
667      * <LI>N(null comparison null) => null</LI>
668      * </OL>
669      * It also answers the questions of the current context.
670      *
671      * @param arg
672      * a ListOpCompExpression to normalize.
673      */

674
675     public void visit(ListOpCompExpression arg) throws NormalizeException {
676         try {
677             ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
678             VisitorContext localCtx = new VisitorContext();
679             localCtx.merge(this.context, false);
680             //Clean all questions which depth is smaller than current depth:
681
localCtx.filter(this.depth);
682             recurseVisitor.setContext(localCtx);
683             //Normalize first expression:
684
XQueryExpression expr1 = arg.getExpression1();
685             expr1.accept(recurseVisitor);
686             localCtx.update(recurseVisitor.getContext());
687             expr1 = recurseVisitor.getExpr();
688             expr1.accept(atomizeVisitor);
689             expr1 = atomizeVisitor.getExpression();
690             //Update the normalized flag:
691
this.normalized = this.normalized | recurseVisitor.wasNormalized();
692             if (this.normalized) {
693                 if (expr1 != null) {
694                     arg.setExpression1(expr1);
695                 } else {
696                     arg = null;
697                 }
698             }
699             //Normalize second expression:
700
XQueryExpression expr2 = null;
701             if (arg != null) {
702                 expr2 = arg.getExpression2();
703                 expr2.accept(recurseVisitor);
704                 localCtx.update(recurseVisitor.getContext());
705                 expr2 = recurseVisitor.getExpr();
706                 expr2.accept(atomizeVisitor);
707                 expr2 = atomizeVisitor.getExpression();
708                 //Update the normalized flag:
709
this.normalized = this.normalized | recurseVisitor.wasNormalized();
710                 if (recurseVisitor.wasNormalized()) {
711                     if (expr2 != null) {
712                         arg.setExpression2(expr2);
713                     } else {
714                         arg = null;
715                     }
716                 }
717             }
718             this.expr = arg;
719             //Re-type this expression :
720
if (reType && this.normalized && this.expr != null) {
721                 this.expr.accept(typeVisitor);
722             }
723             //Update response context with current context to pass the answers of parent questions:
724
this.context.update(localCtx);
725 // if (!this.normalized) {
726
// // add typing dependent action
727
// expr1 = arg.getExpression1();
728
// expr2 = arg.getExpression2();
729
// if (expr1.startsWithVariable() && expr2.startsWithVariable() && (expr1.getQType().isMultiple() || expr2.getQType().isMultiple())) {
730
// ArrayList vars = new ArrayList(2);
731
// if (expr1.getQType().isMultiple()) {
732
// Variable varExpr1 = this.typeVisitor.getStaticContext().createVariable(Constants.QUANTIFIER_BINDINGTYPE,expr1,Variable.NORM_CREATOR);
733
// vars.add(varExpr1);
734
// arg.setExpression1(varExpr1);
735
// }
736
// if (expr2.getQType().isMultiple()) {
737
// Variable varExpr2 = this.typeVisitor.getStaticContext().createVariable(Constants.QUANTIFIER_BINDINGTYPE,expr2,Variable.NORM_CREATOR);
738
// vars.add(varExpr2);
739
// arg.setExpression2(varExpr2);
740
// }
741
// this.expr = new QuantifiedExpression(Constants.SOME_QUANTIFIER,vars,arg, arg.getParentModule());
742
// this.normalized = true;
743
// return;
744
// }
745
// }
746
} catch (XQueryException e) {
747             throw new NormalizeException(0, e);
748         }
749     }
750
751     /**
752      * This visit method normalizes a ListOpUNIONExpression (E1 union E2) and its sub expressions. <BR>
753      * This method apply theses rules: <BR>
754      * <OL>
755      * <LI>N(E1 union E2) => N(E1) intersect N(E2)</LI>
756      * <LI>N(null union E) => N(E) (where E cannot be evaluated)</LI>
757      * <LI>N(E union null) => N(E) (where E cannot be evaluated)</LI>
758      * <LI>N(null union null) => null</LI>
759      * </OL>
760      * It also answers the questions of the current context.
761      *
762      * @param arg
763      * a ListOpUNIONExpression to normalize.
764      */

765     // erase for now 05/09/2003
766
public void visit(ListOpUNIONExpression arg) throws NormalizeException {
767         try {
768             ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
769             VisitorContext localCtx = new VisitorContext();
770             localCtx.merge(this.context, false);
771             //Clean all questions which depth is smaller than current depth:
772
localCtx.filter(this.depth);
773             recurseVisitor.setContext(localCtx);
774             //Normalize first expression:
775
XQueryExpression expr1 = arg.getExpression1();
776             expr1.accept(recurseVisitor);
777             localCtx.update(recurseVisitor.getContext());
778             expr1 = recurseVisitor.getExpr();
779             //Update the normalized flag:
780
this.normalized = recurseVisitor.wasNormalized();
781             if ((this.normalized) && (expr1 != null)) {
782                 arg.setExpression1(expr1);
783             }
784             //Normalize second expression:
785
XQueryExpression expr2 = arg.getExpression2();
786             expr2.accept(recurseVisitor);
787