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             localCtx.update(recurseVisitor.getContext());
788             expr2 = recurseVisitor.getExpr();
789             //Update the normalized flag:
790
this.normalized = this.normalized | recurseVisitor.wasNormalized();
791             if (recurseVisitor.wasNormalized() && (expr2 != null)) {
792                 arg.setExpression2(expr2);
793             }
794             if (expr1 == null) {
795                 this.expr = expr2;
796             } else if (expr2 == null) {
797                 this.expr = expr1;
798             } else {
799                 this.expr = arg;
800             }
801             //Re-type this expression :
802
if (reType && this.normalized && this.expr != null) {
803                 this.expr.accept(typeVisitor);
804             }
805             /*
806              * // CHANGE LARS 07/10/2003 to avoid union of FLWRs //For FLWR expression: if (this.context.existsMemo(this.depth, VisitorContext._LISTOPUNIONEXPRESSION_GETEXPRESSIONS) && (expr1 != null) && (expr2 != null)) { ArrayList exprs = new ArrayList(); exprs.add(expr1); exprs.add(expr2); localCtx.setMemo(this.depth, VisitorContext._LISTOPUNIONEXPRESSION_GETEXPRESSIONS, exprs, true); }
807              */

808             //Update response context with current context to pass the answers of parent questions:
809
this.context.update(localCtx);
810         } catch (XQueryException e) {
811             throw new NormalizeException(0, e);
812         }
813     }
814
815     /**
816      * This visit method normalizes a QuantifiedExpression (some|every $var in E1 satisfies E2) and its sub expressions (E1 and E2). <BR>
817      * This method apply theses rules: <BR>
818      * <OL>
819      * <LI>N(every|some $var in E satisfies null|false()) => false()</LI>
820      * <LI>N(every|some $var in E satisfies true()) => true()</LI>
821      * <LI>N(every $var in null satisfies E) => true()</LI>
822      * <LI>N(some $var in null satisfies E) => false()</LI>
823      * <LI>N(some %xi in Ei, $y in ( for $z in E2 where C2 return R2) satisfies C1(%xi, $y)) => some %xi in Ei, $z in E2 satisfies C1(%xi, R2) and C2</LI>
824      * </OL>
825      * It possibly answers the questions of the current context.
826      *
827      * @param arg
828      * a QuantifiedExpression to normalize.
829      */

830     public void visit(QuantifiedExpression arg) throws NormalizeException {
831         try {
832             // add LARS 27/02/04
833
if (arg.getKind() == Constants.EVERY_QUANTIFIER) {
834                 arg.setKind(Constants.SOME_QUANTIFIER);
835                 ArrayList args = new ArrayList(1);
836                 args.add(arg.getConstraintExpresson());
837                 arg.setConstraintExpresson(new FunctionNOT(args, arg.getParentModule()));
838                 args = new ArrayList(1);
839                 args.add(arg);
840                 this.expr = new FunctionNOT(args, arg.getParentModule());
841                 this.normalized = true;
842                 return;
843             }
844             // end add LARS
845
ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
846             VisitorContext localCtx = new VisitorContext();
847             localCtx.merge(this.context, false);
848             //Clean all questions which depth is smaller than current depth :
849
localCtx.filter(this.depth);
850             //To inform the sub variable to normalize its subexpression because it is a variable declaration :
851
localCtx.setMemo(this.depth + 1, VisitorContext._VARIABLE_DECLARATION, null, true);
852             this.normalized = false;
853             //Questions for the rule SOME(FLWR) :
854
localCtx.setMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS, null, true);
855             localCtx.setMemo(this.depth + 2, VisitorContext._QUANTIFIED_INNERFLWR, null, true);
856             localCtx.setMemo(this.depth + 3, VisitorContext._QUANTIFIED_INNERFLWR, null, true);
857             // localCtx.setMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETVARCLAUSE4QUANTIFIED, null, true);
858
// localCtx.setMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETWHERECLAUSE4QUANTIFIED, null, true);
859
// localCtx.setMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETRETURNCLAUSE4QUANTIFIED, null, true);
860
// localCtx.setMemo(this.depth + 3, VisitorContext._FLWREXPRESSION_GETVARCLAUSE4QUANTIFIED, null, true);
861
// localCtx.setMemo(this.depth + 3, VisitorContext._FLWREXPRESSION_GETWHERECLAUSE4QUANTIFIED, null, true);
862
// localCtx.setMemo(this.depth + 3, VisitorContext._FLWREXPRESSION_GETRETURNCLAUSE4QUANTIFIED, null, true);
863
//Some or Every variables ?
864
int kind = arg.getKind();
865             //Normalize each Variables :
866
ArrayList variables = arg.getVariables();
867             ArrayList newQEVariables = new ArrayList();
868             ArrayList innerWhereClauses = new ArrayList();
869             Variable currentVariable, newVariable;
870             HashMap toSubstitute = new HashMap();
871             //Add existing substitutions hashmap :
872
if (localCtx.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4QUANTIFIED)) {
873                 HashMap substToAdd = (HashMap) localCtx.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4QUANTIFIED);
874                 toSubstitute.putAll(substToAdd);
875             }
876             //------------------ LOOP FOR QUANTIFIED VARIABLES :
877
for (int i = 0; i < variables.size(); i++) {
878                 currentVariable = (Variable) variables.get(i);
879                 //Normalize this variable :
880
recurseVisitor.setContext(localCtx);
881                 currentVariable.accept(recurseVisitor);
882                 localCtx.update(recurseVisitor.getContext());
883                 newVariable = (Variable) recurseVisitor.getExpr();
884                 //Update the normalized flag :
885
this.normalized = this.normalized | recurseVisitor.wasNormalized();
886                 if (newVariable == null) {
887                     toSubstitute.put(currentVariable.getVarName(), null);
888                 } else {
889                     //Here : there is still the variable :
890
//Test if rule SOME(FLWR) can be apply :
891
//if ((kind == Constants.SOME_QUANTIFIER) && ((localCtx.getMemo(this.depth + 2, VisitorContext._QUANTIFIED_INNERFLWR) != null) || ((localCtx.getMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS) != null) && (localCtx.getMemo(this.depth + 3, VisitorContext._QUANTIFIED_INNERFLWR) != null)))) {
892
//if ((kind == Constants.SOME_QUANTIFIER) && ((localCtx.getMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETVARCLAUSE4QUANTIFIED) != null) || ((localCtx.getMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS) != null) && (localCtx.getMemo(this.depth + 3, VisitorContext._FLWREXPRESSION_GETVARCLAUSE4QUANTIFIED) != null)))) {
893
// change LARS 27/02/04
894
// SOME(FLWR) :
895
// EVERY(FLWR) SATISFIES COND : NOT SOME(FWLR) NOT COND
896
if (localCtx.getMemo(this.depth + 2, VisitorContext._QUANTIFIED_INNERFLWR) != null || (localCtx.getMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS) != null && localCtx.getMemo(this.depth + 3, VisitorContext._QUANTIFIED_INNERFLWR) != null)) {
897                         boolean existSequence = (localCtx.getMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS) != null);
898                         //Get inner FLWR parts :
899
FLWRExpression innerFLWR = (FLWRExpression) (existSequence ? localCtx.getMemo(this.depth + 3, VisitorContext._QUANTIFIED_INNERFLWR) : localCtx.getMemo(this.depth + 2, VisitorContext._QUANTIFIED_INNERFLWR));
900                         //Variable innerVar = (Variable) (existSequence ? localCtx.getMemo(this.depth + 3, VisitorContext._QUANTIFIED_INNERFLWR) : localCtx.getMemo(this.depth + 2, VisitorContext._QUANTIFIED_INNERFLWR));
901
//Variable innerVar = (Variable) (existSequence ? localCtx.getMemo(this.depth + 3, VisitorContext._FLWREXPRESSION_GETVARCLAUSE4QUANTIFIED) : localCtx.getMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETVARCLAUSE4QUANTIFIED));
902
ArrayList innerVars = innerFLWR.getVariables();
903                         //Replace current var by this var :
904
for (int j = 0; j < innerVars.size(); j++)
905                             ((Variable) innerVars.get(j)).setBindingType(Constants.QUANTIFIER_BINDINGTYPE);
906                         newQEVariables.addAll(innerVars);
907                         XQueryExpression innerReturn = innerFLWR.getReturnClause();
908                         //XQueryExpression innerReturn = (XQueryExpression) (existSequence ? localCtx.getMemo(this.depth + 3, VisitorContext._FLWREXPRESSION_GETRETURNCLAUSE4QUANTIFIED) : localCtx.getMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETRETURNCLAUSE4QUANTIFIED));
909
//Add return clause in substitution hashmap :
910
toSubstitute.put(currentVariable.getVarName(), innerReturn);
911                         localCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4QUANTIFIED, toSubstitute, true);
912                         XQueryExpression innerWhere = innerFLWR.getWhereClause();
913                         //XQueryExpression innerWhere = (XQueryExpression) (existSequence ? localCtx.getMemo(this.depth + 3, VisitorContext._FLWREXPRESSION_GETWHERECLAUSE4QUANTIFIED) : localCtx.getMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETWHERECLAUSE4QUANTIFIED));
914
//Add where clause :
915
if (innerWhere != null)
916                             innerWhereClauses.add(innerWhere);
917                         //Clean context :
918
localCtx.setMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS, null, true);
919                         if (existSequence) {
920                             localCtx.setMemo(this.depth + 3, VisitorContext._QUANTIFIED_INNERFLWR, null, true);
921                         } else {
922                             localCtx.setMemo(this.depth + 2, VisitorContext._QUANTIFIED_INNERFLWR, null, true);
923                         }
924                     } else {
925                         newQEVariables.add(newVariable);
926                     }
927                 }
928             }
929             //Remove questions :
930
localCtx.removeMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS);
931             localCtx.removeMemo(this.depth + 2, VisitorContext._QUANTIFIED_INNERFLWR);
932             localCtx.removeMemo(this.depth + 3, VisitorContext._QUANTIFIED_INNERFLWR);
933             //Clean context (if we found a variable, this is not a declaration now) :
934
localCtx.removeMemo(this.depth + 1, VisitorContext._VARIABLE_DECLARATION);
935             //------------------ END LOOP FOR QUANTIFIED VARIABLES.
936
if (newQEVariables.size() == 0) {
937                 //Expressions of variables where eliminated. (this.normalized is true !)
938
if (kind == Constants.EVERY_QUANTIFIER) {
939                     this.expr = new FunctionTRUE(null, arg.getParentModule());
940                 } else { //kind == Constants.SOME_QUANTIFIER
941
this.expr = new FunctionFALSE(null, arg.getParentModule());
942                 }
943             } else {
944                 //Update variables :
945
arg.setVariables(newQEVariables);
946                 //--------------------- Normalize constraint :
947
//Update context :
948
recurseVisitor.setContext(localCtx);
949                 //Get constraint :
950
XQueryExpression constraint = arg.getConstraintExpresson();
951                 //Add inner where clauses to constraint :
952
if (innerWhereClauses.size() > 0) {
953                     constraint.setParenthesis(true);
954                     this.normalized = true;
955                     do {
956                         constraint = new BinOpANDExpression((XQueryExpression) innerWhereClauses.get(0), constraint, arg.getParentModule());
957                         constraint.setParenthesis(true);
958                         innerWhereClauses.remove(0);
959                     } while (innerWhereClauses.size() > 0);
960                 }
961                 //For multivalued expression (put in exists function) :
962
localCtx.setMemo((this.depth + 1), VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION, null, true);
963                 //Normalize constraint :
964
constraint.accept(recurseVisitor);
965                 localCtx.update(recurseVisitor.getContext());
966                 constraint = recurseVisitor.getExpr();
967                 //Update the normalized flag :
968
this.normalized = this.normalized | recurseVisitor.wasNormalized();
969                 //For multivalued expression (put in exists function) :
970
localCtx.removeMemo((this.depth + 1), VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION);
971                 if (this.normalized) {
972                     if (constraint == null) {
973                         this.expr = new FunctionFALSE(null, arg.getParentModule());
974                     } else if ((constraint instanceof FunctionFALSE) || (constraint instanceof FunctionTRUE)) {
975                         this.expr = constraint;
976                         this.normalized = true;
977                     } else {
978                         arg.setExpression(constraint);
979                         this.expr = arg;
980                     }
981                 } else {
982                     this.expr = arg;
983                 }
984                 //Remove substitution memo :
985
localCtx.removeMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4QUANTIFIED);
986             }
987             //Re-type this expression :
988
if (reType && this.normalized && this.expr != null) {
989                 this.expr.accept(typeVisitor);
990             }
991             //Update response context with current context to pass the answers of parent questions :
992
this.context.update(localCtx);
993         } catch (XQueryException e) {
994             throw new NormalizeException(0, e);
995         }
996     }
997
998     /** ****** Values ******* */
999
1000    /** ****** Functions definition & call ******* */
1001
1002    /**
1003     * This visit method normalizes a LibraryFunctionCall (i.e. userFunctionNameCall(E) and its arguments (E can be a sequence of parameters and can be empty). <BR>
1004     * This method apply theses rules: <BR>
1005     * <OL>
1006     * <LI>N(userFunctionNameCall(E)) => userFunctionNameCall(N(E))</LI>
1007     * <LI>N(userFunctionNameCall()) => userFunctionNameCall()</LI>
1008     * <LI>N(userFunctionNameCall(null)) => userFunctionNameCall(())</LI>
1009     * </OL>
1010     * It possibly answers the questions of the current context.
1011     *
1012     * @param arg
1013     * a LibraryFunctionCall to normalize.
1014     */

1015    public void visit(LibraryFunctionCall arg) throws NormalizeException {
1016        try {
1017            FunctionDeclaration funDecl = arg.getFunctionDefinition();
1018            ArrayList params = arg.getArguments();
1019            // verify arguments
1020
// verify number
1021
if (funDecl.getParameters() != null && funDecl.getParameters().size() != params.size())
1022                throw new NormalizeException(0, "Invalid number of argument for function call " + arg.getFuncName().toString());
1023            // normalize parameters
1024
ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
1025            VisitorContext localCtx = new VisitorContext();
1026            localCtx.merge(this.context, false);
1027            //Clean all questions which depth is smaller than current depth:
1028
localCtx.filter(this.depth);
1029            //Set one information memo for not create useless sequence:
1030
localCtx.setMemo(this.depth + 1, VisitorContext._INCLUDEINPARENTHESIS, null, true);
1031            recurseVisitor.setContext(localCtx);
1032            //Get and normalize all parameters:
1033
if ((params != null) && (params.size() > 0)) {
1034                int paramLen = params.size();
1035                for (int i = paramLen - 1; i >= 0; i--) {
1036                    XQueryExpression parami = (XQueryExpression) params.get(i);
1037                    boolean isAtom = parami.getQType() != null && parami.getQType().isAtom();
1038                    parami.accept(recurseVisitor);
1039                    localCtx.update(recurseVisitor.getContext());
1040                    parami = recurseVisitor.getExpr();
1041                    if (parami != null && isAtom) {
1042                        parami.accept(atomizeVisitor);
1043                        parami = atomizeVisitor.getExpression();
1044                    }
1045                    if (parami != null) {
1046                        params.set(i, parami);
1047                    } else {
1048                        XQueryVoid emptyExpr = new XQueryVoid(arg.getParentModule());
1049                        //TOREMOVE ? only for testing !
1050
emptyExpr.setParenthesis(true);
1051                        params.set(i, emptyExpr);
1052                    }
1053                    //Update the normalized flag:
1054
this.normalized = this.normalized | recurseVisitor.wasNormalized();
1055                }
1056                if (this.normalized) {
1057                    if (params.size() == 0) {
1058                        arg = null;
1059                    } else {
1060                        arg.setArguments(params);
1061                        //Re-type this expression :
1062
if (reType) {
1063                            arg.accept(typeVisitor);
1064                        }
1065                    }
1066                }
1067            }
1068            // import needed schemas // add LARS 30/03/04
1069
HashMap schemaMap = funDecl.getHomeModule().getImportSchemas();
1070            if (schemaMap != null) {
1071                if (arg.getParentModule().getImportSchemas() == null)
1072                    arg.getParentModule().setImportSchemas(new HashMap());
1073                arg.getParentModule().getImportSchemas().putAll(schemaMap);
1074                for (Iterator it = schemaMap.keySet().iterator(); it.hasNext();) {
1075                    String JavaDoc ns = (String JavaDoc) it.next();
1076                    Schema schema = funDecl.getHomeModule().getStaticContext().getSchemaManager().getSchema(ns);
1077                    try {
1078                        arg.getParentModule().getStaticContext().getTypeVisitor().getSchemaManager().putSchema(schema);
1079                    } catch (SAXException JavaDoc e) {
1080                        throw new NormalizeException(e.getMessage());
1081                    }
1082                }
1083            }
1084            ArrayList schemaList = funDecl.getHomeModule().getSchemaList();
1085            if (schemaList != null) {
1086                if (arg.getParentModule().getSchemaList() == null)
1087                    arg.getParentModule().setSchemaList(new ArrayList());
1088                arg.getParentModule().getSchemaList().addAll(schemaList);
1089            }
1090            // replace function call with expressions
1091
ArrayList exprs = null;
1092            if (funDecl.getExpressions() != null && !funDecl.getExpressions().isEmpty()) {
1093                exprs = new ArrayList(funDecl.getExpressions().size());
1094                for (int i = 0; i < funDecl.getExpressions().size(); i++) {
1095                    exprs.add(((XQueryExpression) funDecl.getExpressions().get(i)).clone());
1096                }
1097            }
1098
1099            ArrayList parameters = funDecl.getParameters();
1100            // replace arguments
1101
if (exprs != null && params != null) {
1102                HashMap subMap = new HashMap();
1103                for (int i = 0; i < params.size(); i++) {
1104                    subMap.put(parameters.get(i), params.get(i));
1105                }
1106                for (int i = 0; i < exprs.size(); i++) {
1107                    ((XQueryExpression) exprs.get(i)).substitute(subMap, typeVisitor);
1108                }
1109            }
1110            // create sequence of exprs
1111
if (exprs != null) {
1112                if (exprs.size() == 1)
1113                    this.expr = (XQueryExpression) exprs.get(0);
1114                else
1115                    this.expr = new XQueryExpressionSequence(exprs, arg.getParentModule());
1116                this.normalized = true;
1117            } else
1118                this.expr = arg;
1119            //Update response context with current context to pass the answers of parent questions:
1120
this.context.update(localCtx);
1121        } catch (CloneNotSupportedException JavaDoc e) {
1122            throw new NormalizeException(0, e);
1123        } catch (XQueryException e) {
1124            throw new NormalizeException(0, e);
1125        }
1126    }
1127
1128    /** ****** Primitive functions ******* */
1129
1130    /**
1131     * This method contains the factorized code of the methods "visit" of some PrimitiveFunctionCall subclasses.
1132     *
1133     * @param arg
1134     * a subclasse of PrimitiveFunctionCall.
1135     * @param aggregate
1136     * true if this is an aggregate function, false otherwise.
1137     * @return normalized parameters of this function.
1138     */

1139    protected ArrayList visitPrimitiveFunctionCall(PrimitiveFunctionCall arg, boolean aggregate) throws NormalizeException {
1140        try {
1141            //Get and normalize all parameters:
1142
ArrayList params = arg.getArguments();
1143            if ((params != null) && (params.size() > 0)) {
1144                ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
1145                VisitorContext localCtx = new VisitorContext();
1146                localCtx.merge(this.context, false);
1147                //Clean all questions which depth is smaller than current depth:
1148
localCtx.filter(this.depth);
1149                //Set one information memo for not create useless sequence:
1150
localCtx.setMemo(this.depth + 1, VisitorContext._INCLUDEINPARENTHESIS, null, true);
1151                if (aggregate) {
1152                    //To inform the possible variables which they are in an aggregate function :
1153
localCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._INAGGREGATEFUNCTION, null, true);
1154                }
1155                recurseVisitor.setContext(localCtx);
1156                for (int i = params.size() - 1; i >= 0; i--) {
1157                    XQueryExpression parami = (XQueryExpression) params.get(i);
1158                    parami.accept(recurseVisitor);
1159                    localCtx.update(recurseVisitor.getContext());
1160                    XQueryExpression expri = recurseVisitor.getExpr();
1161                    // if (expri == null)
1162
// throw new NormalizeException(0, "Incorrect argument : " + parami + " for primitive function call : " + arg.getClass().getName());
1163
if (expri != null) {
1164                        if (arg instanceof FunctionCOUNT || arg instanceof FunctionEMPTY || arg instanceof FunctionEXISTS)
1165                            atomizeVisitor.isSpecial();
1166                        expri.accept(atomizeVisitor);
1167                        expri = atomizeVisitor.getExpression();
1168                    }
1169                    if (expri != null) {
1170                        params.set(i, expri);
1171                    } else {
1172                        params.set(i, new XQueryVoid(arg.getParentModule()));
1173                    }
1174                    //Update the normalized flag:
1175
this.normalized = this.normalized | recurseVisitor.wasNormalized();
1176                }
1177                //Update response context with current context to pass the answers of parent questions:
1178
this.context.update(localCtx);
1179            }
1180            return params;
1181        } catch (XQueryException e) {
1182            throw new NormalizeException(0, e);
1183        }
1184    }
1185
1186    // Default primitive function call
1187
public void visit(PrimitiveFunctionCall arg) throws NormalizeException {
1188        ArrayList params = this.visitPrimitiveFunctionCall(arg, arg instanceof AggregateFunctionCall);
1189        if (params != null) {
1190            try {
1191                boolean norm = false;
1192                //We suppose that the parser did his work and that the number of parameters is correct !
1193
for (int i = 0; i < params.size(); i++) {
1194                    if (params.get(i) instanceof XQueryVoid) {
1195                        //this.normalized = true;
1196
norm = true;
1197                        //this.expr = new XQueryVoid(typeVisitor);
1198
break;
1199                    }
1200                }
1201                if (!norm && this.normalized) {
1202                    // if (this.normalized) {
1203
//Update its parameters :
1204
arg.setArguments(params);
1205                    //Re-type this expression :
1206
if (reType)
1207                        arg.accept(typeVisitor);
1208                    this.expr = arg;
1209                } else {
1210                    this.expr = arg;
1211                }
1212            } catch (XQueryException e) {
1213                throw new NormalizeException(0, e);
1214            }
1215        } else
1216            this.expr = arg;
1217    }
1218
1219    /**
1220     * This method normalizes the argument of the function collection It erases the source name when the name corresponds to the actual source.
1221     */

1222    public void visit(FunctionCOLLECTION arg) throws NormalizeException {
1223        try {
1224            if (arg.getSourceName().equals(sourceName))
1225                arg.eraseSourceName();
1226        } catch (XQueryException e) {
1227            throw new NormalizeException(0, e);
1228        }
1229        this.expr = arg;
1230    }
1231
1232    /**
1233     * This visit method normalizes a FunctionCONCAT <CODE>string concat()</CODE> or <CODE>string concat(string? E1)</CODE> or <CODE>string concat(string? E1, string? E2,...)</CODE> and its sub expressions (Ei). <BR>
1234     * This method apply theses rules: <BR>
1235     * <OL>
1236     * <LI>N(concat(E)) => concat(N(E))</LI>
1237     * <LI>N(concat(E1, E2, ...)) => concat(N(E1), N(E2), ...)</LI>
1238     * <LI>N(concat(()|null))) => "" (empty string)</LI>
1239     * </OL>
1240     * It possibly answers the questions of the current context.
1241     *
1242     * @param arg
1243     * a FunctionCONCAT to normalize.
1244     */

1245    public void visit(FunctionCONCAT arg) throws NormalizeException {
1246        ArrayList params = this.visitPrimitiveFunctionCall(arg, false);
1247        try {
1248            //We suppose that the parser did his work and that the number of parameters is correct !
1249
if ((params.size() == 0) || ((params.size() == 1) && (params.get(0) instanceof XQueryVoid))) {
1250                this.normalized = true;
1251                this.expr = new ValueString("", arg.getParentModule());
1252            } else if (this.normalized) {
1253                //Update its parameters :
1254
arg.setArguments(params);
1255                //Re-type this expression :
1256
if (reType)
1257                    arg.accept(typeVisitor);
1258                this.expr = arg;
1259            } else {
1260                this.expr = arg;
1261            }
1262        } catch (XQueryException e) {
1263            throw new NormalizeException(0, e);
1264        }
1265    }
1266
1267    /**
1268     * This visit method normalizes a FunctionEMPTY <CODE>boolean empty(item* E)</CODE> and its sub expression (E). <BR>
1269     * This method apply theses rules: <BR>
1270     * <OL>
1271     * <LI>N(empty(E)) => empty(N(E))</LI>
1272     * <LI>N(empty(()|null)) => true()</LI>
1273     * </OL>
1274     * It possibly answers the questions of the current context.
1275     *
1276     * @param arg
1277     * a FunctionEMPTY to normalize.
1278     */

1279    public void visit(FunctionEMPTY arg) throws NormalizeException {
1280        //trace("<o-"+(nodeNumber++)+">FunctionEMPTY<o>(hc="+arg.hashCode()+") : "+arg.toString()+" QType="+this.typeToString(arg.getQType()),0);
1281
ArrayList params = this.visitPrimitiveFunctionCall(arg, false);
1282        try {
1283            //We suppose that the parser did his work and that the number of parameters is correct !
1284
if (params.get(0) instanceof XQueryVoid) {
1285                this.normalized = true;
1286                this.expr = new FunctionTRUE(null, arg.getParentModule());
1287            } else if (this.normalized) {
1288                //Update its parameters :
1289
arg.setArguments(params);
1290                //Re-type this expression :
1291
if (reType)
1292                    arg.accept(typeVisitor);
1293                this.expr = arg;
1294            } else {
1295                this.expr = arg;
1296            }
1297        } catch (XQueryException e) {
1298            throw new NormalizeException(0, e);
1299        }
1300        //untrace();
1301
}
1302
1303    /**
1304     * This visit method normalizes a FunctionEXISTS <CODE>boolean? exists(item* E)</CODE> and its sub expression (E). <BR>
1305     * This method apply theses rules: <BR>
1306     * <OL>
1307     * <LI>N(exists(E)) => exists(N(E))</LI>
1308     * <LI>N(exists(()|null)) => false()</LI>
1309     * </OL>
1310     * It possibly answers the questions of the current context.
1311     *
1312     * @param arg
1313     * a FunctionEXISTS to normalize.
1314     */

1315
1316    // add LARS 15/09/2003
1317
//private GetBoundVariablesVisitor gbvv = new GetBoundVariablesVisitor(true, false);
1318
public void visit(FunctionEXISTS arg) throws NormalizeException {
1319        //trace("<o-"+(nodeNumber++)+">FunctionEXISTS<o>(hc="+arg.hashCode()+") : "+arg.toString()+" QType="+this.typeToString(arg.getQType()),0);
1320
ArrayList params = this.visitPrimitiveFunctionCall(arg, false);
1321        try {
1322            //We suppose that the parser did his work and that the number of parameters is correct !
1323
if (params.get(0) instanceof XQueryVoid) {
1324                this.normalized = true;
1325                this.expr = new FunctionFALSE(null, arg.getParentModule());
1326                return;
1327            }
1328            // add LARS 08/10/2003
1329
// TODO : attention if computed ?
1330
if (params.get(0) instanceof Element || params.get(0) instanceof Value) {
1331                this.normalized = true;
1332                this.expr = new FunctionTRUE(null, arg.getParentModule());
1333                return;
1334            }
1335            // add LARS 15/09/2003 to be generalized???
1336
// TODO : generalize this?
1337
if (params.get(0) instanceof XQueryExpressionSequence) {
1338                ArrayList subExprs = ((XQueryExpressionSequence) params.get(0)).getSubExpressions();
1339                if (subExprs == null || subExprs.isEmpty()) {
1340                    this.normalized = true;
1341                    this.expr = new FunctionFALSE(null, arg.getParentModule());
1342                    return;
1343                }
1344            }
1345            // gbvv.reset();
1346
// ((XQueryExpression) params.get(0)).accept(gbvv);
1347
// if (gbvv.getVariables() == null || gbvv.getVariables().isEmpty()) {
1348
// this.normalized = true;
1349
// this.expr = new FunctionTRUE(null, arg.getParentModule());
1350
// return;
1351
// }
1352
if (this.normalized) {
1353                //Update its parameters :
1354
arg.setArguments(params);
1355                //Re-type this expression :
1356
if (reType)
1357                    arg.accept(typeVisitor);
1358                this.expr = arg;
1359            } else {
1360                this.expr = arg;
1361            }
1362        } catch (XQueryException e) {
1363            throw new NormalizeException(0, e);
1364        }
1365        //untrace();
1366
}
1367
1368    /**
1369     * This visit method normalizes a FunctionLOCAL_NAME <CODE>string name(E)</CODE> and its sub expression (E). <BR>
1370     * This method apply theses rules: <BR>
1371     * <OL>
1372     * <LI>N(name(E)) => name(N(E))</LI>
1373     * <LI>N(name(()|null)) => ()</LI>
1374     * </OL>
1375     * It possibly answers the questions of the current context.
1376     *
1377     * @param arg
1378     * a FunctionLOCAL_NAME to normalize.
1379     */

1380    public void visit(FunctionLOCAL_NAME arg) throws NormalizeException {
1381        //trace("<o-"+(nodeNumber++)+">FunctionLOCAL_NAME<o>(hc="+arg.hashCode()+") : "+arg.toString()+" QType="+this.typeToString(arg.getQType()),0);
1382
ArrayList params = this.visitPrimitiveFunctionCall(arg, false);
1383        try {
1384            //We suppose that the parser did his work and that the number of parameters is correct !
1385
if (params.get(0) instanceof XQueryVoid) {
1386                this.normalized = true;
1387                this.expr = new ValueString("", arg.getParentModule());
1388            } else if (this.normalized) {
1389                //Update its parameters :
1390
arg.setArguments(params);
1391                //Re-type this expression :
1392
if (reType)
1393                    arg.accept(typeVisitor);
1394                this.expr = arg;
1395            } else {
1396                this.expr = arg;
1397            }
1398        } catch (XQueryException e) {
1399            throw new NormalizeException(0, e);
1400        }
1401        //untrace();
1402
}
1403
1404    /**
1405     * This visit method normalizes a FunctionNOT <CODE>boolean not(item* E)</CODE> and its sub expression (E). <BR>
1406     * This method apply theses rules: <BR>
1407     * <OL>
1408     * <LI>N(not(E)) => not(N(E))</LI>
1409     * <LI>N(not(()|null|false())) => true()</LI>
1410     * <LI>N(not(true())) => false()</LI>
1411     * </OL>
1412     * It possibly answers the questions of the current context.
1413     *
1414     * @param arg
1415     * a FunctionNOT to normalize.
1416     */

1417    public void visit(FunctionNOT arg) throws NormalizeException {
1418        //trace("<o-"+(nodeNumber++)+">FunctionNOT<o>(hc="+arg.hashCode()+") : "+arg.toString()+" QType="+this.typeToString(arg.getQType()),0);
1419
//For multivalued expression (put in exists function) :
1420
this.context.setMemo((this.depth + 1), VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION, null, true);
1421        ArrayList params = this.visitPrimitiveFunctionCall(arg, false);
1422        //For multivalued expression (put in exists function) :
1423
this.context.removeMemo((this.depth + 1), VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION);
1424        //Apply specifics rules :
1425
try {
1426            if (this.normalized) {
1427                if ((params.get(0) == null) || (params.get(0) instanceof FunctionFALSE) || (params.get(0) instanceof XQueryVoid)) {
1428                    this.expr = new FunctionTRUE(null, arg.getParentModule());
1429                } else if (params.get(0) instanceof FunctionTRUE) {
1430                    this.expr = new FunctionFALSE(null, arg.getParentModule());
1431                } else {
1432                    arg.setArguments(params);
1433                    this.expr = arg;
1434                }
1435                //Re-type this expression :
1436
if (reType)
1437                    this.expr.accept(typeVisitor);
1438            } else {
1439                if ((params.get(0) instanceof FunctionFALSE) || (params.get(0) instanceof XQueryVoid)) {
1440                    this.expr = new FunctionTRUE(null, arg.getParentModule());
1441                    this.normalized = true;
1442                } else if (params.get(0) instanceof FunctionTRUE) {
1443                    this.expr = new FunctionFALSE(null, arg.getParentModule());
1444                    this.normalized = true;
1445                } else {
1446                    this.expr = arg;
1447                }
1448            }
1449        } catch (XQueryException e) {
1450            throw new NormalizeException(0, e);
1451        }
1452        //untrace();
1453
}
1454
1455    /**
1456     * This visit method normalizes a FunctionSTRING <CODE>string string(item E)</CODE> and its sub expression (E). <BR>
1457     * This method apply theses rules: <BR>
1458     * <OL>
1459     * <LI>N(string(E)) => string(N(E))</LI>
1460     * <LI>N(string(()|null)) => ""</LI>
1461     * </OL>
1462     * It possibly answers the questions of the current context.
1463     *
1464     * @param arg
1465     * a FunctionSTRING to normalize.
1466     */

1467    public void visit(FunctionSTRING arg) throws NormalizeException {
1468        //trace("<o-"+(nodeNumber++)+">FunctionSTRING<o>(hc="+arg.hashCode()+") : "+arg.toString()+" QType="+this.typeToString(arg.getQType()),0);
1469
ArrayList params = this.visitPrimitiveFunctionCall(arg, false);
1470        try {
1471            //We suppose that the parser did his work and that the number of parameters is correct !
1472
if ((params.size() != 0) && (params.get(0) instanceof XQueryVoid)) {
1473                this.normalized = true;
1474                this.expr = new ValueString("", arg.getParentModule());
1475            } else if (this.normalized) {
1476                //Update its parameters :
1477
arg.setArguments(params);
1478                //Re-type this expression :
1479
if (reType)
1480                    arg.accept(typeVisitor);
1481                this.expr = arg;
1482            } else {
1483                this.expr = arg;
1484            }
1485        } catch (XQueryException e) {
1486            throw new NormalizeException(0, e);
1487        }
1488        //untrace();
1489
}
1490
1491    /**
1492     * This visit method normalizes a FunctionSUM <CODE>double sum(item* E)</CODE> and its sub expression (E). <BR>
1493     * This method apply theses rules: <BR>
1494     * <OL>
1495     * <LI>N(sum(E)) => sum(N(E))</LI>
1496     * <LI>N(sum(()|null)) => 0</LI>
1497     * </OL>
1498     * It possibly answers the questions of the current context.
1499     *
1500     * @param arg
1501     * a FunctionSUM to normalize.
1502     */

1503    public void visit(FunctionSUM arg) throws NormalizeException {
1504        //trace("<o-"+(nodeNumber++)+">FunctionSUM<o>(hc="+arg.hashCode()+") : "+arg.toString()+" QType="+this.typeToString(arg.getQType()),0);
1505
ArrayList params = this.visitPrimitiveFunctionCall(arg, true);
1506        try {
1507            //We suppose that the parser did his work and that the number of parameters is correct !
1508
if (params.get(0) instanceof XQueryVoid) {
1509                this.normalized = true;
1510                this.expr = new ValueDouble("0", arg.getParentModule());
1511            } else if (this.normalized) {
1512                //Update its parameters :
1513
arg.setArguments(params);
1514                //Re-type this expression :
1515
if (reType)
1516                    arg.accept(typeVisitor);
1517                this.expr = arg;
1518            } else {
1519                this.expr = arg;
1520            }
1521        } catch (XQueryException e) {
1522            throw new NormalizeException(0, e);
1523        }
1524        //untrace();
1525
}
1526
1527    public void visit(FunctionDATA arg) throws NormalizeException {
1528        //trace("<o-"+(nodeNumber++)+">FunctionSUM<o>(hc="+arg.hashCode()+") : "+arg.toString()+" QType="+this.typeToString(arg.getQType()),0);
1529
// test if argument is multivaluated
1530
XQueryExpression argument = arg.getArgument(0);
1531        if ((!(argument instanceof LocatedExpression) || !((LocatedExpression) argument).isRelative()) && argument.getQType() != null && arg.getArgument(0).getQType().isMultiple()) {
1532            try {
1533                ArrayList vars = new ArrayList(1);
1534                Variable var = typeVisitor.getStaticContext().createVariable(Constants.FOR_BINDINGTYPE, arg.getArgument(0), Variable.NORM_CREATOR);
1535                arg.getArguments().set(0, var);
1536                if (reType)
1537                    arg.accept(typeVisitor);
1538                vars.add(var);
1539                this.expr = new FLWRExpression(vars, null, null, arg, arg.getParentModule());
1540                this.normalized = true;
1541                return;
1542            } catch (XQueryException e) {
1543                throw new NormalizeException(0, e);
1544            }
1545        }
1546        ArrayList params = this.visitPrimitiveFunctionCall(arg, true);
1547        try {
1548            //We suppose that the parser did his work and that the number of parameters is correct !
1549
if (params.get(0) instanceof XQueryVoid) {
1550                this.normalized = true;
1551                this.expr = new XQueryVoid(arg.getParentModule());
1552            } else if (this.normalized) {
1553                //Update its parameters :
1554
arg.setArguments(params);
1555                //Re-type this expression :
1556
if (reType)
1557                    arg.accept(typeVisitor);
1558                this.expr = arg;
1559            } else {
1560                this.expr = arg;
1561            }
1562        } catch (XQueryException e) {
1563            throw new NormalizeException(0, e);
1564        }
1565        //untrace();
1566
}
1567
1568    /** ****** XPath/Element ******* */
1569
1570    /**
1571     * This visit method normalizes an AttributeValuePair (attributeName="E") and its sub expressions (attributeName and E). <BR>
1572     * This method apply theses rules: <BR>
1573     * <OL>
1574     * <LI>N(attributeName = "E") => N(attributeName) = "N(E)"</LI>
1575     * <LI>N(attributeName = "null") => attributeName = ""</LI>
1576     * <LI>N(null = "E") => null</LI>
1577     * </OL>
1578     * It possibly answers the questions of the current context.
1579     *
1580     * @param arg
1581     * an AttributeValuePair to normalize.
1582     */

1583    public void visit(AttributeValuePair arg) throws NormalizeException {
1584        try {
1585            //trace("<o-"+(nodeNumber++)+">AttributeValuePair<o>(hc="+arg.hashCode()+") : "+arg.toString()+" QType="+this.typeToString(arg.getQType()),0);
1586
ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
1587            VisitorContext localCtx = new VisitorContext();
1588            localCtx.merge(this.context, false);
1589            //Clean all questions which depth is smaller than current depth:
1590
localCtx.filter(this.depth);
1591            recurseVisitor.setContext(localCtx);
1592            //Normalize attribut name:
1593
XQueryExpression attrName = arg.getAttributeName();
1594            attrName.accept(recurseVisitor);
1595            localCtx.update(recurseVisitor.getContext());
1596            attrName = recurseVisitor.getExpr();
1597            //Update the normalized flag:
1598
this.normalized = recurseVisitor.wasNormalized();
1599            if (this.normalized) {
1600                if (attrName != null) {
1601                    //attrName.setBrace(false);
1602
arg.setAttibuteName(attrName);
1603                } else {
1604                    arg = null;
1605                }
1606            }
1607            if (arg != null) {
1608                //Normalize attribut value:
1609
XQueryExpression attrValue = arg.getAttributeValue();
1610                attrValue.accept(recurseVisitor);
1611                localCtx.update(recurseVisitor.getContext());
1612                attrValue = recurseVisitor.getExpr();
1613                attrValue.accept(atomizeVisitor);
1614                attrValue = atomizeVisitor.getExpression();
1615                //Update the normalized flag:
1616
this.normalized = this.normalized | recurseVisitor.wasNormalized();
1617                if (recurseVisitor.wasNormalized()) {
1618                    if (attrValue != null) {
1619                        arg.setAttributeValue(attrValue);
1620                    } else {
1621                        arg.setAttributeValue(new ValueString("", arg.getParentModule()));
1622                    }
1623                    //Re-type this expression :
1624
if (reType)
1625                        arg.accept(typeVisitor);
1626                }
1627            }
1628            this.expr = arg;
1629            //Update response context with current context to pass the answers of parent questions:
1630
this.context.update(localCtx);
1631            //untrace();
1632
} catch (XQueryException e) {
1633            throw new NormalizeException(0, e);
1634        }
1635    }
1636
1637    /**
1638     * This visit method normalizes an Element ( <tag>E </tag>) and its sub expressions (E and tag). <BR>
1639     * This method apply theses rules: <BR>
1640     * <OL>
1641     * <LI>N( <tag>E </tag>) => <N(tag)>N(E) </N(tag)> with N(E) = N(E1, E2, E3...) where :<BR>- if Ei = ValueText or Element => Ei <BR>- if Ei = enclosedExpression (ex: FLWR, Var, LocatedExpression...) like {Ei1, Ei2...Ein} => {Ei1}{Ei2}...{Ein}</LI>
1642     * <LI>N( <tag>null </tag>) =><tag></tag></LI>
1643     * <LI>N( <null>E </null>) => null</LI>
1644     * </OL>
1645     * It possibly answers the questions of the current context.
1646     *
1647     * @param arg
1648     * an Element to normalize.
1649     */

1650    public void visit(Element arg) throws NormalizeException {
1651        try {
1652            //trace("<o-"+(nodeNumber++)+">Element<o>(hc="+arg.hashCode()+") : "+arg.toString()+" QType="+this.typeToString(arg.getQType()),0);
1653
ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
1654            VisitorContext localCtx = new VisitorContext();
1655            localCtx.merge(this.context, false);
1656            //Clean all questions which depth is smaller than current depth:
1657
localCtx.filter(this.depth);
1658            recurseVisitor.setContext(localCtx);
1659            //Normalize tag:
1660
XQueryExpression tagExpr = arg.getStartTag();
1661            tagExpr.accept(recurseVisitor);
1662            localCtx.update(recurseVisitor.getContext());
1663            tagExpr = recurseVisitor.getExpr();
1664            //Update the normalized flag:
1665
this.normalized = recurseVisitor.wasNormalized();
1666            if (this.normalized) {
1667                if (tagExpr != null) {
1668                    if (tagExpr instanceof ValueText) {
1669                        //tagExpr.setBrace(false);
1670
arg.setStartTag(tagExpr);
1671                    } else {
1672                        throw new NormalizeException(0, "Tag name of Element is not correctly defined. Its type is " + tagExpr.getClass().getName() + ".");
1673                    }
1674                } else {
1675                    arg = null;
1676                }
1677            }
1678            ArrayList expressions = null;
1679            ArrayList attributes = null;
1680            if (arg != null) {
1681                //Normalize attributs (if exists):
1682
attributes = arg.getAttributes();
1683                if (attributes != null) {
1684                    int attrLen = attributes.size();
1685                    for (int i = attrLen - 1; i >= 0; i--) {
1686                        ((AttributeValuePair) attributes.get(i)).accept(recurseVisitor);
1687                        localCtx.update(recurseVisitor.getContext());
1688                        if (recurseVisitor.getExpr() != null) {
1689                            attributes.set(i, recurseVisitor.getExpr());
1690                        } else {
1691                            attributes.remove(i);
1692                        }
1693                        //Update the normalized flag:
1694
this.normalized = this.normalized | recurseVisitor.wasNormalized();
1695                    }
1696                    if (this.normalized) {
1697                        arg.setAttributes(attributes);
1698                    }
1699                }
1700                //Get sub expressions:
1701
expressions = arg.getSubExpressions();
1702                if (expressions != null) {
1703                    //Normalize sub expressions :
1704
int exprLen = expressions.size();
1705                    for (int i = exprLen - 1; i >= 0; i--) {
1706                        ((XQueryExpression) expressions.get(i)).accept(recurseVisitor);
1707                        localCtx.update(recurseVisitor.getContext());
1708                        if (recurseVisitor.getExpr() != null) {
1709                            expressions.set(i, recurseVisitor.getExpr());
1710                        } else {
1711                            expressions.remove(i);
1712                        }
1713                        //Update the normalized flag:
1714
this.normalized = this.normalized | recurseVisitor.wasNormalized();
1715                    }
1716                    //Normalize sub expressions according to type of sub expressions (ex: enclosed expr. {E}):
1717
if (expressions.size() > 0) { //Can not be null !
1718
//To normalize sub sequences of expressions :
1719
ArrayList newExpressions = new ArrayList();
1720                        for (int i = 0; i < expressions.size(); i++) {
1721                            if (expressions.get(i) instanceof XQueryExpressionSequence) {
1722                                ArrayList subExpr = ((XQueryExpressionSequence) expressions.get(i)).getSubExpressions();
1723                                for (int j = 0; j < subExpr.size(); j++) {
1724                                    if ((subExpr.get(j) instanceof Element) || (subExpr.get(j) instanceof Value)) {
1725                                        newExpressions.add(subExpr.get(j));
1726                                    } else {
1727                                        ArrayList newSubExpr = new ArrayList();
1728                                        newSubExpr.add(subExpr.get(j));
1729                                        XQueryExpressionSequence aSeq = new XQueryExpressionSequence(newSubExpr, arg.getParentModule());
1730                                        //this.setSequenceDelimiters(aSeq, false, true, false);
1731
newExpressions.add(aSeq);
1732                                    }
1733                                }
1734                            } else {
1735                                newExpressions.add(expressions.get(i));
1736                            }
1737                        }
1738                        arg.setSubExpressions(newExpressions);
1739                    } else {
1740                        arg.setSubExpressions(expressions);
1741                    }
1742                }
1743            }
1744            this.expr = arg;
1745            //Re-type this expression :
1746
if (reType && this.normalized && this.expr != null) {
1747                this.expr.accept(typeVisitor);
1748            }
1749            //Answer questions of the current context (we must use the normalized Element to answer):
1750
//For FLWRExpression:
1751
if (localCtx.existsMemo(this.depth, VisitorContext._ELEMENT_EXISTS)) {
1752                localCtx.setMemo(this.depth, VisitorContext._ELEMENT_EXISTS, Boolean.TRUE, true);
1753            }
1754            //Update response context with current context to pass the answers of parent questions:
1755
this.context.update(localCtx);
1756            //untrace();
1757
} catch (XQueryException e) {
1758            throw new NormalizeException(0, e.getMessage());
1759        }
1760    }
1761
1762    /**
1763     * To analyse a FLWRExpression (and its subnodes) to determine if a rules can be applied. <BR>
1764     * This method apply theses rules: <BR>
1765     * <OL>
1766     * <LI>N(for %xi in Ei,let %yi := E'i where C return R) => for %xi in N(Ei), let %yi := N(E'i) where N(C) return N(R)</LI>
1767     * <LI>N(for %xi in Ei,let %yi := E'i where null return R) => null</LI>
1768     * <LI>N(for %xi in Ei,let %yi := E'i where C return null) => null</LI>
1769     * <LI>N(for $x in null for %xi in Ei($x) let %yi := E'i($x) where C($x) return R($x)) => null</LI>
1770     * <LI>N(let $y := null for %xi in Ei($y) let %yi := E'i($y) where C($y) return R($y)) => for %xi in Ei(null) let %yi := E'i(null) where C(null) return R(null)</LI>
1771     * <LI>N(for %xi in Ei, $y in EC(%xi) where C(%xi,$y) return R(%xi,$y)) => N(for %xi in N(Ei), where N(C(%xi,EC(%xi))) return N(R(%xi,EC(%xi))))</LI>
1772     * <LI>N(for $x in EC where C($x) return R($x)) => N(R(EC)) if N(C(EC)) = true</LI>
1773     * <LI>N(for $x in EC return R($x)) => N(R(EC))</LI>
1774     * <LI>N(for %xi in Ei, $y in ( for $z in E2(%xi) where C2(%xi, $z) return R2(%xi, $z)) where C1(%xi, $y) return R1(%xi, $y)) => for %xi in N(Ei), $z in N(E2(%xi)) where N(C2(%xi, $z) and C1(%xi, R2(%xi, $z))) return N(R1(%xi, R2(%xi, $z))) if R2(%xi, $z) is mono valued.</LI>
1775     * <LI>N(for %xi in Ei, $y in ( for $z in E2(%xi) where C2(%xi, $z) return R2(%xi, $z)) where C1(%xi, $y) return R1(%xi, $y)) => for %xi in N(Ei), $z in N(E2(%xi)) where N(C2(%xi, $z) and C1(%xi, R2(%xi, $z))) return N(R1(%xi, R2(%xi, $z))) if R2(%xi, $z) is multi valued or not typed</LI>
1776     * <LI>N(for %xi in Ei, $z in (E2(%xi) UNION E3(%xi)) where C(%xi, $z) return R(%xi, $z)) => (for %xi in N(Ei), $z in N(E2(%xi)) where N(C(%xi, $z)) return N(R(%xi, $z))) UNION (for %xi in N(Ei), $z in N(E3(%xi)) where N(C(%xi, $z)) return N(R(%xi, $z)))</LI>
1777     * <LI>N(let %x := Ex, let $y := FLWR for %z in Ez($y) where some $t in E(%x,$y,%z) satisfies C(%x,$y,%z) return R(%x,$y,%z))=> let %x := N(Ex), let $y := N(FLWR) for %z in N(Ez(N(FLWR))) where N(some $t in E(%x,N(FLWR),%z) satisfies C(%x,N(FLWR),%z)) return N(R(%x,N(FLWR),%z)) (no substitution of $y if it is in an aggregate function like count, avg, max, min or sum)</LI>
1778     * <LI>N(let %x := Ex, let $y := FLWR for %z in Ez($y) where C(%x,$y,%z) return R(%x,$y,%z)) (with C <>QuantifiedExpression)=> let %x := N(Ex), let $y := N(FLWR) for %z in N(Ez(N(FLWR))) where some $t in N(FLWR) satisfies N(C(%x,$t,%z)) return N(R(%x,N(FLWR),%z)) (no substitution of $y if it is in an aggregate function like count, avg, max, min or sum)</LI>
1779     * <LI>N(C(E)) C = condition and E = LE || FLWR || VAR => N(C(EXISTS(E)))</LI>
1780     * </OL>
1781     * (See class header to learn more about these symbols). <BR>
1782     * It possibly answers the questions of the current context.
1783     *
1784     * @param arg
1785     * a FLWRExpression to normalize.
1786     */

1787    public void visit(FLWRExpression arg) throws NormalizeException {
1788        try {
1789            this.expr = null;
1790            ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
1791            VisitorContext localCtx = new VisitorContext();
1792            //For rule WHERE(FLWR) : push the data
1793
ArrayList whereFLWRStack = null;
1794            if (this.context.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._FLWREXPRESSION_GETANDREPLACEFLWRINWHERE)) {
1795                whereFLWRStack = (ArrayList) this.context.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._FLWREXPRESSION_GETANDREPLACEFLWRINWHERE);
1796                this.context.removeMemo(VisitorContext._ANY_DEPTH, VisitorContext._FLWREXPRESSION_GETANDREPLACEFLWRINWHERE);
1797            }
1798            localCtx.merge(this.context, false);
1799            //Clean all questions which depth is smaller than current depth:
1800
localCtx.filter(this.depth);
1801            //Set common context :
1802
localCtx.setMemo(this.depth + 1, VisitorContext._VARIABLE_DECLARATION, null, true);
1803            // Order not a question !
1804
localCtx.setMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS, null, true);
1805            localCtx.setMemo(this.depth + 2, VisitorContext._ELEMENT_EXISTS, null, true);
1806            localCtx.setMemo(this.depth + 3, VisitorContext._ELEMENT_EXISTS, null, true);
1807            //Prepare FOR context :
1808
VisitorContext localForCtx = new VisitorContext();
1809            localForCtx.setMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_INNERFLWR, null, true);
1810            localForCtx.setMemo(this.depth + 3, VisitorContext._FLWREXPRESSION_INNERFLWR, null, true);
1811            localForCtx.setMemo(this.depth + 2, VisitorContext._LISTOPUNIONEXPRESSION_GETEXPRESSIONS, null, true);
1812            localForCtx.setMemo(this.depth + 3, VisitorContext._LISTOPUNIONEXPRESSION_GETEXPRESSIONS, null, true);
1813            localForCtx.merge(localCtx, false);
1814            //Prepare LET context :
1815
VisitorContext localLetCtx = new VisitorContext();
1816            //To deactivate LET(FLWR) rule :
1817
//For :
1818
localLetCtx.setMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETFLWR, null, true);
1819            localLetCtx.setMemo(this.depth + 3, VisitorContext._FLWREXPRESSION_GETFLWR, null, true);
1820            localLetCtx.setMemo(this.depth + 2, VisitorContext._FLWR_RETURNS_TAG, null, true);
1821            localLetCtx.setMemo(this.depth + 3, VisitorContext._FLWR_RETURNS_TAG, null, true);
1822            localLetCtx.merge(localCtx, false);
1823            //Create structure to store rule informations :
1824
HashMap substFor = new HashMap();
1825            ArrayList newWhere = new ArrayList();
1826            HashMap exprUnion = new HashMap();
1827            HashMap substLet = new HashMap();
1828            HashMap substVarTmp = new HashMap();
1829            //Local flags:
1830
boolean allVariablesAreEliminated = false;
1831            boolean eliminateThisFLWR = false;
1832            //Get all variables for and/or lets:
1833
ArrayList variables = arg.getVariables();
1834            //We supposed that there is at least a variable.
1835
//--------------------------------------------- NORMALIZE FOR AND LET CLAUSES
1836
// REMOVE LARS ArrayList newFLWRVariables = new ArrayList();
1837
Variable currentVar = null;
1838            //Normalize each variables and search which rule(s) to apply :
1839
for (int i = 0; (i < variables.size()) && !eliminateThisFLWR; i++) {
1840                currentVar = (Variable) variables.get(i);
1841                // start add LARS 22/02/04
1842
if (currentVar.getCreator() != Variable.NORM_CREATOR && currentVar.getBindingType() == Constants.FOR_BINDINGTYPE && !currentVar.isInput() && // for testing only(tmpVar.getExpression().getQType().getOccurence() == QType.OCC_1_1 || tmpVar.getExpression().getQType().getOccurence() == QType.OCC_0_1) &&
1843
currentVar.getExpression().getQType().getOccurence() == QType.OCC_1_1 && (variables.size() != 1 || arg.getParentExpression() != null)) {
1844                    currentVar.setBindingType(Constants.LET_BINDINGTYPE);
1845                }
1846                // end add LARS 22/02/04
1847
if (currentVar.getBindingType() == Constants.FOR_BINDINGTYPE) {
1848                    //++++++++++++++++++++++++++++++++++++++ FOR variables :
1849
recurseVisitor.setContext(localForCtx);
1850                    //Normalize sub expression:
1851
currentVar.accept(recurseVisitor);
1852                    localForCtx.update(recurseVisitor.getContext());
1853                    //Update the normalized flag:
1854
this.normalized = this.normalized | recurseVisitor.wasNormalized();
1855                    if (recurseVisitor.getExpr() == null) {
1856                        //To eliminate this variable.
1857
eliminateThisFLWR = true;
1858                    } else { //recurseVisitor.getExpr() != null
1859
boolean existSequence = (localForCtx.getMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS) != null);
1860                        //Choice which rule(s) can be apply :
1861
if ((localForCtx.getMemo(this.depth + 2, VisitorContext._ELEMENT_EXISTS) != null) || ((localForCtx.getMemo(this.depth + 3, VisitorContext._ELEMENT_EXISTS) != null) && existSequence && (((Integer JavaDoc) localForCtx.getMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS)).intValue() <= 1))) {
1862                            variables.remove(i);
1863                            i--;
1864                            //This is a FOR(EC) or FOR(SEQ(EC)) but not FOR(SEQ(EC1,...,ECn)).
1865
//Rule FOR(EC) :
1866
substFor.put(currentVar.getVarName(), currentVar.getExpression());
1867                            //Update substitution orders :
1868
substVarTmp.clear();
1869                            substVarTmp.putAll(substFor);
1870                            substVarTmp.putAll(substLet);
1871                            localForCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4FLWR, substVarTmp, true);
1872                            localLetCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4FLWR, substVarTmp, true);
1873                            //Clean context :
1874
if (existSequence) {
1875                                localForCtx.setMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS, null, true);
1876                                localForCtx.setMemo(this.depth + 3, VisitorContext._ELEMENT_EXISTS, null, true);
1877                            } else {
1878                                localForCtx.setMemo(this.depth + 2, VisitorContext._ELEMENT_EXISTS, null, true);
1879                            }
1880                            this.normalized = true;
1881                            //} else if ((localForCtx.getMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETVARCLAUSE) != null) || ((localForCtx.getMemo(this.depth + 3, VisitorContext._FLWREXPRESSION_GETVARCLAUSE) != null) && existSequence)) {
1882
} else if ((localForCtx.getMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_INNERFLWR) != null) || ((localForCtx.getMemo(this.depth + 3, VisitorContext._FLWREXPRESSION_INNERFLWR) != null) && existSequence)) {
1883                            //Rule FOR(FLWR) :
1884
FLWRExpression innerFLWR = (FLWRExpression) (existSequence ? localForCtx.getMemo(this.depth + 3, VisitorContext._FLWREXPRESSION_INNERFLWR) : localForCtx.getMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_INNERFLWR));
1885                            ArrayList innerOrderBy = innerFLWR.getOrderBy();
1886                            // TODO add order by on flwr to order outer flwr
1887
ArrayList outerOrderBy = arg.getOrderBy();
1888
1889                            ArrayList innerVars = innerFLWR.getVariables();
1890                            XQueryExpression innerWhere = innerFLWR.getWhereClause();
1891                            XQueryExpression innerReturn = innerFLWR.getReturnClause();
1892
1893                            if (innerOrderBy != null && !innerOrderBy.isEmpty()) {
1894                                if (arg.getOrderBy() == null || arg.getOrderBy().isEmpty()) {
1895                                    for (int j = 0; j < i; j++) {
1896                                        Variable varj = (Variable) variables.get(j);
1897                                        if (varj.getBindingType() == Constants.FOR_BINDINGTYPE) {
1898                                            varj.setOrder(Constants.PLACE_ORDER);
1899                                            arg.addOrderBy(varj);
1900                                        }
1901                                    }
1902                                }
1903                                if (arg.getOrderBy() == null)
1904                                    arg.setOrderBy(innerOrderBy);
1905                                else
1906                                    arg.getOrderBy().addAll(innerOrderBy);
1907                            }
1908
1909                            //Add inner var :
1910
arg.addVariables(i, innerVars);
1911                            i += innerVars.size();
1912                            //Choose between FOR(FLWR_1) and FOR(FLWR_2) :
1913
if ((arg.getQType() == null) || (innerReturn.getQType().isMultiple())) {
1914                                //FOR(FLWR) where return of inner FLWR is multi valued (or not typed) :
1915
currentVar.setExpression(innerReturn, true);
1916                            } else {
1917                                variables.remove(i);
1918                                i--;
1919                                //FOR(FLWR) where return of inner FLWR is mono valued :
1920
substFor.put(currentVar.getVarName(), innerReturn);
1921                                //Update substitution orders :
1922
substVarTmp.clear();
1923                                substVarTmp.putAll(substFor);
1924                                substVarTmp.putAll(substLet);
1925                                localForCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4FLWR, substVarTmp, true);
1926                                localLetCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4FLWR, substVarTmp, true);
1927                            }
1928                            if (innerWhere != null) {
1929                                newWhere.add(innerWhere);
1930                            }
1931                            this.normalized = true;
1932                            //Clean context :
1933
if (existSequence) {
1934                                localForCtx.setMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS, null, true);
1935                                localForCtx.setMemo(this.depth + 3, VisitorContext._FLWREXPRESSION_INNERFLWR, null, true);
1936                            } else {
1937                                localForCtx.setMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_INNERFLWR, null, true);
1938                            }
1939                        } else if ((localForCtx.getMemo(this.depth + 2, VisitorContext._LISTOPUNIONEXPRESSION_GETEXPRESSIONS) != null) || ((localForCtx.getMemo(this.depth + 3, VisitorContext._LISTOPUNIONEXPRESSION_GETEXPRESSIONS) != null) && existSequence)) {
1940                            //Rule FOR(UNION) :
1941
ArrayList innerUnionExpr = (ArrayList) (existSequence ? localForCtx.getMemo(this.depth + 3, VisitorContext._LISTOPUNIONEXPRESSION_GETEXPRESSIONS) : localForCtx.getMemo(this.depth + 2, VisitorContext._LISTOPUNIONEXPRESSION_GETEXPRESSIONS));
1942                            currentVar.setExpression((XQueryExpression) innerUnionExpr.get(0), true);
1943                            exprUnion.put(currentVar.getVarName(), innerUnionExpr.get(1));
1944                            //Clean context :
1945
if (existSequence) {
1946                                localForCtx.setMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS, null, true);
1947                                localForCtx.setMemo(this.depth + 3, VisitorContext._LISTOPUNIONEXPRESSION_GETEXPRESSIONS, null, true);
1948                            } else {
1949                                localForCtx.setMemo(this.depth + 2, VisitorContext._LISTOPUNIONEXPRESSION_GETEXPRESSIONS, null, true);
1950                            }
1951                            this.normalized = true;
1952                        }
1953                    }
1954                } else if (currentVar.getBindingType() == Constants.LET_BINDINGTYPE) {
1955                    //++++++++++++++++++++++++++++++++++++++ LET variables :
1956
// add LARS 27/02/04
1957
ArrayList parents = currentVar.getParentExpression();
1958                    if (parents == null || parents.isEmpty()) { // only declaration!!!
1959
variables.remove(i);
1960                        i--;
1961                        // this should be done otherwise we might run into a problem!
1962
substLet.put(currentVar.getVarName(), currentVar.getExpression());
1963                        continue;
1964                    }
1965                    // end add LARS 27/02/04
1966
recurseVisitor.setContext(localLetCtx);
1967                    //Normalize sub expression:
1968
currentVar.accept(recurseVisitor);
1969                    localLetCtx.update(recurseVisitor.getContext());
1970                    //Update the normalized flag:
1971
this.normalized = this.normalized | recurseVisitor.wasNormalized();
1972                    if (recurseVisitor.getExpr() == null) {
1973                        // ADD LARS
1974
variables.remove(i);
1975                        i--;
1976                        substLet.put(currentVar.getVarName(), null);
1977                        //To eliminate this variable.
1978
substVarTmp.clear();
1979                        substVarTmp.putAll(substLet);
1980                        substVarTmp.putAll(substFor);
1981                        localForCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR, substVarTmp, true);
1982                        localLetCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR, substVarTmp, true);
1983                        this.normalized = true;
1984                    } else { //recurseVisitor.getExpr() != null
1985
boolean existSequence = (localForCtx.getMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS) != null);
1986                        //Choice which rule(s) can be apply :
1987
if ((localForCtx.getMemo(this.depth + 2, VisitorContext._ELEMENT_EXISTS) != null) || ((localForCtx.getMemo(this.depth + 3, VisitorContext._ELEMENT_EXISTS) != null) && existSequence && (((Integer JavaDoc) localForCtx.getMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS)).intValue() <= 1))) {
1988                            // ADD LARS
1989
variables.remove(i);
1990                            i--;
1991                            //This is a LET(EC) or LET(SEQ(EC)) but not LET(SEQ(EC1,...,ECn)).
1992
//Rule LET(EC) :
1993
substLet.put(currentVar.getVarName(), currentVar.getExpression());
1994                            //Update substitution orders :
1995
substVarTmp.clear();
1996                            substVarTmp.putAll(substFor);
1997                            substVarTmp.putAll(substLet);
1998                            localForCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR, substVarTmp, true);
1999                            localLetCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR, substVarTmp, true);
2000                            //Clean context :
2001
if (existSequence) {
2002                                localForCtx.setMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS, null, true);
2003                                localForCtx.setMemo(this.depth + 3, VisitorContext._ELEMENT_EXISTS, null, true);
2004                            } else {
2005                                localForCtx.setMemo(this.depth + 2, VisitorContext._ELEMENT_EXISTS, null, true);
2006                            }
2007                            this.normalized = true;
2008                        } else if (localLetCtx.getMemo(this.depth + 2, VisitorContext._FLWR_RETURNS_TAG) != null) {
2009                            variables.remove(i);
2010                            i--;
2011                            substLet.put(currentVar.getVarName(), localLetCtx.getMemo(this.depth + 2, VisitorContext._FLWR_RETURNS_TAG));
2012                            //To eliminate this variable.
2013
substVarTmp.clear();
2014                            substVarTmp.putAll(substLet);
2015                            substVarTmp.putAll(substFor);
2016                            localForCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR, substVarTmp, true);
2017                            localLetCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR, substVarTmp, true);
2018                            this.normalized = true;
2019                            //Clean context :
2020
localLetCtx.setMemo(this.depth + 2, VisitorContext._FLWR_RETURNS_TAG, null, true);
2021                        } else if (localLetCtx.getMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETFLWR) != null || (localLetCtx.getMemo(this.depth + 3, VisitorContext._FLWREXPRESSION_GETFLWR) != null && existSequence)) {
2022                            // add test LARS 27/02/04
2023
// TODO modify test to be less specific
2024
if (parents.size() == 1 && currentVar.getCreator() != Variable.NORM_CREATOR && !(currentVar.getExpression() instanceof AggregateFunctionCall)) {
2025                                //Rule LET(FLWR) :
2026
//outln("Rule LET(FLWR) detected !");
2027
FLWRExpression innerFLWR = (FLWRExpression) (existSequence ? localLetCtx.getMemo(this.depth + 3, VisitorContext._FLWREXPRESSION_GETFLWR) : localLetCtx.getMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETFLWR));
2028                                //We keep the current let variable :
2029
// REMOVE LARS newFLWRVariables.add(currentVar);
2030
variables.remove(i);
2031                                i--;
2032                                substLet.put(currentVar.getVarName(), innerFLWR);
2033                                //Update substitution orders (different of FOR because no substitution if aggregate function) :
2034
localForCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR, substLet, true);
2035                                localLetCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR, substLet, true);
2036                                this.normalized = true;
2037                            }
2038                            //Clean context :
2039
if (existSequence) {
2040                                localLetCtx.setMemo(this.depth + 2, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS, null, true);
2041                                localLetCtx.setMemo(this.depth + 3, VisitorContext._FLWREXPRESSION_GETFLWR, null, true);
2042                            } else {
2043                                localLetCtx.setMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETFLWR, null, true);
2044                            }
2045                        } else {
2046                            //Default case :
2047
// REMOVE LARS newFLWRVariables.add(currentVar);
2048
}
2049                    }
2050                } else { //Not FOR or LET variables :
2051
throw new NormalizeException("The variable \"" + currentVar + "\" in " + arg.toString() + " has not a valid binding type (" + currentVar.getBindingType() + ") !");
2052                }
2053            } //End for loop !
2054
// ADD LARS 23/02/04
2055
if (variables.size() > 0) {
2056                for (int j = 0; j < variables.size(); j++) {
2057                    Variable tmpVar = (Variable) variables.get(j);
2058                    XQueryExpression tmpVarExpr = tmpVar.getExpression();
2059                    int bindingtype = tmpVar.getBindingType();
2060                    // replacing expressions
2061
// for $x in value
2062
// let $x := notcollection && not aggregatefunctioncall
2063
// let $x := collection && locatedexpression starting with variable
2064
if (tmpVar.getCreator() != Variable.NORM_CREATOR && (// first condition
2065
tmpVarExpr instanceof Value || // second condition
2066
(bindingtype == Constants.LET_BINDINGTYPE && !tmpVarExpr.getQType().isMultiple() && !(tmpVarExpr instanceof LocatedExpression) && !(tmpVarExpr instanceof FunctionCall) && !(tmpVarExpr instanceof ListOpArithExpression) && !(tmpVarExpr instanceof FLWRExpression)) || // third condition
2067
(bindingtype == Constants.LET_BINDINGTYPE && tmpVarExpr instanceof LocatedExpression && ((LocatedExpression) tmpVarExpr).getSteps().size() != 1 && ((LocatedExpression) tmpVarExpr).getExpression() instanceof Variable && tmpVarExpr.getQType().isMultiple()))) {
2068                        // create substitute map
2069
HashMap map = new HashMap(1);
2070                        map.put(tmpVar, tmpVarExpr);
2071                        // replace in all LET variable after this one
2072
for (int i = j + 1; i < variables.size(); i++)
2073                            ((Variable) variables.get(i)).getExpression().substitute(map, typeVisitor);
2074                        // replace in WHERE clause
2075
XQueryExpression tmpSubExpr = null;
2076                        XQueryExpression whereClause = arg.getWhereClause();
2077                        if (whereClause != null) {
2078                            if ((tmpSubExpr = (XQueryExpression) map.get(whereClause)) != null)
2079                                arg.setWhereClause(tmpSubExpr);
2080                            else
2081                                whereClause.substitute(map, typeVisitor);
2082                        }
2083                        //replace in orderby (not necessary -> only mono values accepted)
2084
ArrayList orderBys = arg.getOrderBy();
2085                        if (orderBys != null) {
2086                            for (int i = 0; i < orderBys.size(); i++) {
2087                                XQueryExpression orderby = (XQueryExpression) orderBys.get(i);
2088                                if ((tmpSubExpr = (XQueryExpression) map.get(orderby)) != null)
2089                                    orderBys.set(i, tmpSubExpr);
2090                                else
2091                                    orderby.substitute(map, typeVisitor);
2092                            }
2093                        }
2094                        // replace in RETURN clause
2095
XQueryExpression returnClause = arg.getReturnClause();
2096                        if ((tmpSubExpr = (XQueryExpression) map.get(returnClause)) != null)
2097                            arg.setReturnClause(tmpSubExpr);
2098                        else
2099                            returnClause.substitute(map, typeVisitor);
2100                        variables.remove(j);
2101                        j--;
2102                    }
2103                }
2104                if (variables.size() == 0)
2105                    allVariablesAreEliminated = true;
2106            }
2107            // END ADD LARS 23/02/04
2108
if (eliminateThisFLWR) {
2109                arg = null;
2110            } else {
2111                //Update variables :
2112
// REMOVE LARS
2113
/*
2114                 * if (newFLWRVariables.size() > 0) { arg.setVariables(newFLWRVariables); } else { //newVariables.size() == 0
2115                 */

2116                // ADD LARS
2117
if (variables.size() == 0 && !allVariablesAreEliminated) {
2118                    //We test if there is no substitution or there is only null substitutions :
2119
Object JavaDoc[] substForValues = substFor.values().toArray();
2120                    boolean substForValuesAllNull = true;
2121                    for (int sfv = 0; (sfv < substForValues.length) && substForValuesAllNull; sfv++) {
2122                        if (substForValues[sfv] != null) {
2123                            substForValuesAllNull = false;
2124                        }
2125                    }
2126                    Object JavaDoc[] substLetValues = substLet.values().toArray();
2127                    boolean substLetValuesAllNull = true;
2128                    for (int slv = 0; (slv < substLetValues.length) && substForValuesAllNull && substLetValuesAllNull; slv++) {
2129                        if (substLetValues[slv] != null) {
2130                            substLetValuesAllNull = false;
2131                        }
2132                    }
2133                    if (substForValuesAllNull && substLetValuesAllNull) {
2134                        //Eliminate this FLWR :
2135
arg = null;
2136                    } else {
2137                        //There is at least one not null substitution :
2138
allVariablesAreEliminated = true;
2139                    }
2140                }
2141            }
2142            if (arg != null) {
2143                //--------------------------------------------- NORMALIZE WHERE CLAUSE
2144
//Normalize where (and apply rule(s)) :
2145
XQueryExpression whereClause = arg.getWhereClause();
2146                //outln("WHERE CLAUSE = "+whereClause+" CTX \n"+);
2147
if (newWhere.size() > 0) {
2148                    if (whereClause != null) {
2149                        //Add inner where clause :
2150
for (int iwc = 0; iwc < newWhere.size(); iwc++) {
2151                            whereClause = new BinOpANDExpression(whereClause, (XQueryExpression) newWhere.get(iwc), arg.getParentModule());
2152                            whereClause.setParenthesis(true);
2153                        }
2154                    } else {
2155                        whereClause = (XQueryExpression) newWhere.get(0);
2156                        for (int iwc = 1; iwc < newWhere.size(); iwc++) {
2157                            whereClause = new BinOpANDExpression(whereClause, (XQueryExpression) newWhere.get(iwc), arg.getParentModule());
2158                            whereClause.setParenthesis(true);
2159                        }
2160                    }
2161                }
2162                if (whereClause != null) {
2163                    VisitorContext localWhereCtx = new VisitorContext();
2164                    //Test if where clause is quantified expression for rule LET(FLWR) :
2165
//Note : where clause is not yet normalize !
2166
boolean stop = false;
2167                    XQueryExpression whereContent = whereClause;
2168                    ArrayList subExpr = null;
2169                    //Pass sequence(s) :
2170
while ((whereContent instanceof XQueryExpressionSequence) && !stop) {
2171                        subExpr = ((XQueryExpressionSequence) whereContent).getSubExpressions();
2172                        if (subExpr.size() != 1) {
2173                            stop = true;
2174                        } else {
2175                            whereContent = (XQueryExpression) subExpr.get(0);
2176                        }
2177
2178                    }
2179                    // //Change where clause in quantified expression for rule LET(FLWR) :
2180
// XQueryExpression substExpr = null;
2181
boolean buildWhereQuantified = false;
2182                    Variable newQuantifiedVar = null;
2183                    HashMap substLetClone = (HashMap) substLet.clone();
2184                    // //Search for substitution of variable by FLWR
2185
// Object[] keys = substLetClone.keySet().toArray();
2186
// int substPos = -1;
2187
// for (int k = 0; k < keys.length; k++) {
2188
// Object substitutionExpr = substLetClone.get(keys[k]);
2189
// if ((substitutionExpr != null) && (substitutionExpr instanceof FLWRExpression)) {
2190
// if (substPos == -1) {
2191
// substPos = k;
2192
// } else {
2193
// throw new NormalizeException(0, "CAN NOT BE MORE THAN ONE SUBSTITUTION FOR RULE LET(FLWR)!");
2194
// }
2195
// }
2196
// }
2197
// //Prepare to change where clause in quantified expression :
2198
// if (!(whereContent instanceof QuantifiedExpression) && (substPos != -1) && (substLetClone.get(keys[substPos]) != null)) {
2199
// substExpr = (XQueryExpression) ((XQueryExpression) substLetClone.get(keys[0])).clone();
2200
// substExpr.setParenthesis(true);
2201
// newQuantifiedVar = createVariable(Constants.QUANTIFIER_BINDINGTYPE, substExpr);
2202
// substLetClone.put(keys[substPos], newQuantifiedVar);
2203
// localWhereCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_WASSUBSTITUTELETFLWR, Boolean.FALSE, true);
2204
// buildWhereQuantified = true;
2205
// } else {
2206
// //outln("===> WARNING : IT IS A QUANTIFIED !");
2207
// }
2208
//Merge local context for where clause with current context (and merge inner substitution hashmaps):
2209
localWhereCtx.merge(this.context, false);
2210                    //Set contexts (add substitutions to do) :
2211
if (!substLetClone.isEmpty()) {
2212                        if (localWhereCtx.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR)) {
2213                            HashMap substToAdd = (HashMap) localWhereCtx.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR);
2214                            substLetClone.putAll(substToAdd);
2215                        }
2216                        localWhereCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR, substLetClone, true);
2217                    }
2218                    if (!substFor.isEmpty()) {
2219                        if (localWhereCtx.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4FLWR)) {
2220                            HashMap substToAdd = (HashMap) localWhereCtx.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4FLWR);
2221                            substFor.putAll(substToAdd);
2222                        }
2223                        localWhereCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4FLWR, substFor, true);
2224                    }
2225                    //For multivalued expression (put in exists function) :
2226
localWhereCtx.setMemo((this.depth + 1), VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION, null, true);
2227                    //For rule WHERE(FLWR) :
2228
localWhereCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._FLWREXPRESSION_GETANDREPLACEFLWRINWHERE, new ArrayList(), true);
2229                    recurseVisitor.setContext(localWhereCtx);
2230                    //Normalize sub expression:
2231
whereClause.accept(recurseVisitor);
2232                    this.context.update(recurseVisitor.getContext());
2233                    localWhereCtx.update(recurseVisitor.getContext());
2234                    //Update the normalized flag:
2235
this.normalized = this.normalized | recurseVisitor.wasNormalized();
2236                    //For multivalued expression (put in exists function) :
2237
localWhereCtx.removeMemo((this.depth + 1), VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION);
2238                    //Get possible new LET variables (rule WHERE(FLWR)) :
2239
ArrayList newLetVariables = (ArrayList) localWhereCtx.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._FLWREXPRESSION_GETANDREPLACEFLWRINWHERE);
2240                    localWhereCtx.removeMemo(VisitorContext._ANY_DEPTH, VisitorContext._FLWREXPRESSION_GETANDREPLACEFLWRINWHERE);
2241                    //Add this LET variables in current FLWR :
2242
//Note : here newLetVariables always != null :
2243
while (!newLetVariables.isEmpty()) {
2244                        arg.addVariable((Variable) newLetVariables.remove(0));
2245                    }
2246                    //Update where clause :
2247
if (recurseVisitor.getExpr() == null) {
2248                        arg = null;
2249                    } else {
2250                        //End of LET(FLWR) rule. Build a new quantified expression :
2251
if (buildWhereQuantified) {
2252                            if (((Boolean JavaDoc) localWhereCtx.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_WASSUBSTITUTELETFLWR)).booleanValue()) {
2253                                ArrayList quantifiedVar = new ArrayList();
2254                                quantifiedVar.add(newQuantifiedVar);
2255                                arg.setWhereClause(new QuantifiedExpression(Constants.SOME_QUANTIFIER, quantifiedVar, recurseVisitor.getExpr(), arg.getParentModule()));
2256                            }
2257                            //Set the initial substLet context (before rule LET(FLWR)) :
2258
//substLetClone.put(keys[0], substExpr);
2259
} else {
2260                            arg.setWhereClause(recurseVisitor.getExpr());
2261                        }
2262                    }
2263                    //For gc :
2264
localWhereCtx = null;
2265                }
2266                if (arg != null) {
2267                    //Normalize sort clauses:
2268
ArrayList sortClauses = arg.getOrderBy();
2269                    if ((sortClauses != null) && (sortClauses.size() != 0)) {
2270                        //Normalize each clause :
2271
int sortClauseLen = sortClauses.size();
2272                        for (int i = sortClauseLen - 1; i >= 0; i--) {
2273                            //Get order:
2274
int[] direction = ((XQueryExpression) sortClauses.get(i)).getOrder();
2275                            //Normalize this clause :
2276
VisitorContext localSortbyCtx = new VisitorContext();
2277                            localSortbyCtx.merge(this.context, false);
2278                            //Set contexts (add substitutions to do) :
2279
if (!substLet.isEmpty()) {
2280                                if (localSortbyCtx.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR)) {
2281                                    HashMap substToAdd = (HashMap) localSortbyCtx.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR);
2282                                    substLet.putAll(substToAdd);
2283                                }
2284                                localSortbyCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR, substLet, true);
2285                            }
2286                            if (!substFor.isEmpty()) {
2287                                if (localSortbyCtx.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4FLWR)) {
2288                                    HashMap substToAdd = (HashMap) localSortbyCtx.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4FLWR);
2289                                    substFor.putAll(substToAdd);
2290                                }
2291                                localSortbyCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4FLWR, substFor, true);
2292                            }
2293                            recurseVisitor.setContext(localSortbyCtx);
2294                            XQueryExpression expri = (XQueryExpression) sortClauses.get(i);
2295                            expri.accept(recurseVisitor);
2296                            localCtx.update(recurseVisitor.getContext());
2297                            expri = recurseVisitor.getExpr();
2298                            // XQueryExpression aClause = null;
2299
if (expri != null) {
2300                                expri.accept(atomizeVisitor);
2301                                expri = atomizeVisitor.getExpression();
2302                                // order by clause must be variable or located expression starting with variable
2303
// if (!(expri instanceof Variable) && (!(expri instanceof LocatedExpression) || !(((LocatedExpression)expri).getStepNum(0).getExpression() instanceof Variable))) {
2304
// Variable var = this.createVariable(Constants.LET_BINDINGTYPE,expri);
2305
// arg.addVariable(var);
2306
// aClause = var;
2307
// } else {
2308
// aClause = expri;
2309
// }
2310
}
2311                            //Update the normalized flag:
2312
this.normalized = this.normalized | recurseVisitor.wasNormalized();
2313                            if (recurseVisitor.wasNormalized()) {
2314                                if (expri != null) {
2315                                    expri.setOrder(direction);
2316                                    sortClauses.set(i, expri);
2317                                } else {
2318                                    sortClauses.remove(i);
2319                                }
2320                            }
2321                        }
2322                        if (sortClauses.size() == 0) {
2323                            arg.setOrderBy(null);
2324                        } else {
2325                            arg.setOrderBy(sortClauses);
2326                        }
2327                    }
2328                }
2329                if (arg != null) {
2330                    //--------------------------------------------- NORMALIZE RETURN CLAUSE
2331
//Normalize return (and apply rule(s)) :
2332
XQueryExpression returnClause = arg.getReturnClause();
2333                    VisitorContext localReturnCtx = new VisitorContext();
2334                    //outln("===> RETURN ("+nn+") ");
2335
//Merge local context for where clause with current context (and merge inner substitution hashmaps):
2336
localReturnCtx.merge(this.context, false);
2337                    //Set contexts (add substitutions to do) :
2338
if (!substLet.isEmpty()) {
2339                        if (localReturnCtx.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR)) {
2340                            HashMap substToAdd = (HashMap) localReturnCtx.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR);
2341                            substLet.putAll(substToAdd);
2342                        }
2343                        localReturnCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR, substLet, true);
2344                    }
2345                    if (!substFor.isEmpty()) {
2346                        if (localReturnCtx.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4FLWR)) {
2347                            HashMap substToAdd = (HashMap) localReturnCtx.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4FLWR);
2348                            substFor.putAll(substToAdd);
2349                        }
2350                        localReturnCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4FLWR, substFor, true);
2351                    }
2352                    //Add context rules for RETURN(FLWR) :
2353
localReturnCtx.setMemo(this.depth + 1, VisitorContext._FLWREXPRESSION_INNERFLWR, null, true);
2354                    // localReturnCtx.setMemo(this.depth + 1, VisitorContext._FLWREXPRESSION_GETVARCLAUSE, null, true);
2355
// localReturnCtx.setMemo(this.depth + 1, VisitorContext._FLWREXPRESSION_GETWHERECLAUSE, null, true);
2356
// localReturnCtx.setMemo(this.depth + 1, VisitorContext._FLWREXPRESSION_GETORDERBYCLAUSE, null, true);
2357
// localReturnCtx.setMemo(this.depth + 1, VisitorContext._FLWREXPRESSION_GETRETURNCLAUSE, null, true);
2358
localReturnCtx.setMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_INNERFLWR, null, true);
2359                    // localReturnCtx.setMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETVARCLAUSE, null, true);
2360
// localReturnCtx.setMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETWHERECLAUSE, null, true);
2361
// localReturnCtx.setMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETORDERBYCLAUSE, null, true);
2362
// localReturnCtx.setMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETRETURNCLAUSE, null, true);
2363
localReturnCtx.setMemo(this.depth + 1, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS, null, true);
2364                    //Normalize sub expression:
2365
recurseVisitor.setContext(localReturnCtx);
2366                    returnClause.accept(recurseVisitor);
2367                    this.context.update(recurseVisitor.getContext());
2368                    //Update the normalized flag:
2369
this.normalized = this.normalized | recurseVisitor.wasNormalized();
2370                    if (recurseVisitor.getExpr() != null) {
2371                        //Rule RETURN(FLWR) :
2372
Integer JavaDoc cardSeqTmp = (Integer JavaDoc) localReturnCtx.getMemo(this.depth + 1, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS);
2373                        int cardSequence = 0;
2374                        if (cardSeqTmp != null) {
2375                            cardSequence = cardSeqTmp.intValue();
2376                        }
2377                        //if ((localReturnCtx.getMemo(this.depth + 1, VisitorContext._FLWREXPRESSION_GETVARCLAUSE) != null) || ((localReturnCtx.getMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_GETVARCLAUSE) != null) && (cardSequence == 1))) {
2378
if ((localReturnCtx.getMemo(this.depth + 1, VisitorContext._FLWREXPRESSION_INNERFLWR) != null) || ((localReturnCtx.getMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_INNERFLWR) != null) && (cardSequence == 1))) {
2379                            //Get inner FLWR clauses :
2380
FLWRExpression innerFLWR = (FLWRExpression) ((cardSequence == 1) ? localReturnCtx.getMemo(this.depth + 2, VisitorContext._FLWREXPRESSION_INNERFLWR) : localReturnCtx.getMemo(this.depth + 1, VisitorContext._FLWREXPRESSION_INNERFLWR));
2381                            ArrayList innerOrderBy = innerFLWR.getOrderBy();
2382                            // TODO add order by on flwr to order outer flwr
2383
ArrayList outerOrderBy = arg.getOrderBy();
2384
2385                            ArrayList innerVars = innerFLWR.getVariables();
2386                            XQueryExpression innerWhere = innerFLWR.getWhereClause();
2387                            XQueryExpression innerReturn = innerFLWR.getReturnClause();
2388                            //AND of where clauses :
2389
arg.addWhereClause(innerWhere);
2390                            if (innerOrderBy != null && !innerOrderBy.isEmpty()) {
2391                                if (arg.getOrderBy() == null || arg.getOrderBy().isEmpty()) {
2392                                    for (int j = 0; j < variables.size(); j++) {
2393                                        Variable varj = (Variable) variables.get(j);
2394                                        if (varj.getBindingType() == Constants.FOR_BINDINGTYPE) {
2395                                            varj.setOrder(Constants.PLACE_ORDER);
2396                                            arg.addOrderBy(varj);
2397                                        }
2398                                    }
2399                                }
2400                                if (arg.getOrderBy() == null)
2401                                    arg.setOrderBy(innerOrderBy);
2402                                else
2403                                    arg.getOrderBy().addAll(innerOrderBy);
2404                            }
2405                            // add LARS 02/10/2003 this is hacking
2406
arg.addVariables(innerVars);
2407                            arg.setReturnClause(innerReturn);
2408                            allVariablesAreEliminated = false;
2409                            this.normalized = true;
2410                        } else {
2411                            arg.setReturnClause(recurseVisitor.getExpr());
2412                        }
2413                        //Update return clause :
2414
if (allVariablesAreEliminated) {
2415                            //Special case where all variables are eliminated (but substituted by 'not null' expressions)
2416
if (arg.getWhereClause() == null) {
2417                                //We keep only the return expression :
2418
this.expr = recurseVisitor.getExpr();
2419                            } else if (arg.getWhereClause() instanceof FunctionTRUE) {
2420                                //We keep only the return expression :
2421
this.expr = recurseVisitor.getExpr();
2422                            } else if (arg.getWhereClause() instanceof FunctionFALSE) {
2423                                //This FLWR is eliminated :
2424
arg = null;
2425                            } else { //whereClause != null and !(whereClause instanceof FunctionTRUE or FunctionFALSE)
2426
//This FLWR change to ITEExpression :
2427
//XQueryVoid emptyExpr = new XQueryVoid(arg.getParentModule());
2428
//emptyExpr.setParenthesis(true);
2429
// change LARS 15/09/2003 to be removed when ITE is supported
2430
this.expr = createDummyFLWR(arg.getWhereClause(), recurseVisitor.getExpr());
2431                                //this.expr = new ITEExpression(arg.getWhereClause(), recurseVisitor.getExpr(), emptyExpr, typeVisitor);
2432
}
2433                        } else { //There is some variables :
2434
if (exprUnion.size() > 0) {
2435                                //*** UNION of two FLWR
2436
Object JavaDoc[] keys = exprUnion.keySet().toArray();
2437                                for (int ik = 0; ik < keys.length; ik++) {
2438                                    FLWRExpression newFLWR = (FLWRExpression) arg.clone();
2439                                    //Set context :
2440
VisitorContext localUnionFLWRCtx = new VisitorContext();
2441                                    Variable varSubstExpr = new Variable((QName) keys[ik], arg.getParentModule());
2442                                    varSubstExpr.setExpression((XQueryExpression) exprUnion.get(keys[ik]), true);
2443                                    localUnionFLWRCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_CHANGEEXPRESSION4FLWR, varSubstExpr, true);
2444                                    localUnionFLWRCtx.merge(this.context, false);
2445                                    recurseVisitor.setContext(localUnionFLWRCtx);
2446                                    //Normalize new FLWR:
2447
newFLWR.accept(recurseVisitor);
2448                                    this.context.update(recurseVisitor.getContext());
2449                                    //Update the normalized flag:
2450
this.normalized = this.normalized | recurseVisitor.wasNormalized();
2451                                    this.expr = arg;
2452                                    this.expr = new ListOpUNIONExpression(this.expr, newFLWR, arg.getParentModule());
2453                                }
2454                            }
2455                            // check if return clause is tag
2456
else if (recurseVisitor.getExpr() instanceof Element) {
2457                                this.context.setMemo(this.depth, VisitorContext._FLWR_RETURNS_TAG, arg, true);
2458                                // TODO
2459
}
2460                        }
2461                    } else { //recurseVisitor.getExpr() == null
2462
arg = null;
2463                    }
2464                    if (this.expr == null) {
2465                        this.expr = arg;
2466                    }
2467                    //For gc :
2468
localReturnCtx = null;
2469                } else {
2470                    //Where clause was eliminated :
2471
this.expr = null;
2472                }
2473            } else {
2474                //All variables was eliminated and all variables substitutions are by null :
2475
this.expr = null;
2476            }
2477
2478            // if (arg != null) {
2479
// //Update variables :
2480
// if (newFLWRVariables.size() > 0) {
2481
// arg.setVariables(newFLWRVariables);
2482
// } else { //newVariables.size() == 0
2483
// //We test if there is no substitution or there is only null substitutions :
2484
// Object[] substForValues = substFor.values().toArray();
2485
// boolean substForValuesAllNull = true;
2486
// for (int sfv = 0;(sfv < substForValues.length) && substForValuesAllNull; sfv++) {
2487
// if (substForValues[sfv] != null) {
2488
// substForValuesAllNull = false;
2489
// }
2490
// }
2491
// Object[] substLetValues = substLet.values().toArray();
2492
// boolean substLetValuesAllNull = true;
2493
// for (int slv = 0;(slv < substLetValues.length) && substForValuesAllNull && substLetValuesAllNull; slv++) {
2494
// if (substLetValues[slv] != null) {
2495
// substLetValuesAllNull = false;
2496
// }
2497
// }
2498
// if (substForValuesAllNull && substLetValuesAllNull) {
2499
// //Eliminate this FLWR :
2500
// arg = null;
2501
// } else {
2502
// //There is at least one not null substitution :
2503
// allVariablesAreEliminated = true;
2504
// }
2505
// }
2506
// }
2507

2508            //For rule WHERE(FLWR) : pop the data
2509
if (whereFLWRStack != null) {
2510                this.context.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._FLWREXPRESSION_GETANDREPLACEFLWRINWHERE, whereFLWRStack, true);
2511            }
2512            //For rule WHERE(FLWR) :
2513
if ((this.expr != null) && (this.expr instanceof FLWRExpression) && (this.expr.getParentExpression() == null || this.expr.getParentExpression().isEmpty() || !(this.expr.getParentExpression().get(0) instanceof Variable)) && (this.context.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._FLWREXPRESSION_GETANDREPLACEFLWRINWHERE))) {
2514                //Replace this FLWR by a new LET variable :
2515
ArrayList letVariables = (ArrayList) this.context.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._FLWREXPRESSION_GETANDREPLACEFLWRINWHERE);
2516                //Create the new variable :
2517
Variable newLetVariable = typeVisitor.getStaticContext().createVariable(Constants.LET_BINDINGTYPE, expr, Variable.NORM_CREATOR);
2518                //Add in context :
2519
letVariables.add(newLetVariable);
2520                this.context.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._FLWREXPRESSION_GETANDREPLACEFLWRINWHERE, letVariables, true);
2521                //Change current expression :
2522
this.expr = newLetVariable;
2523                this.normalized = true;
2524            }
2525            //For multivalued expression (put in exists function) :
2526
if ((this.expr != null) && (localCtx.existsMemo(this.depth, VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION))) {
2527                this.normalized = true;
2528                // boolean brace = this.expr.getBrace();
2529
// boolean bracket = this.expr.getBracket();
2530
boolean parenthesis = this.expr.getParenthesis();
2531                // this.expr.setBrace(false);
2532
// this.expr.setBracket(false);
2533
this.expr.setParenthesis(false);
2534                ArrayList parameter = new ArrayList();
2535                parameter.add(this.expr);
2536                this.expr = new FunctionEXISTS(parameter, arg.getParentModule());
2537                // this.expr.setBrace(brace);
2538
// this.expr.setBracket(bracket);
2539
this.expr.setParenthesis(parenthesis);
2540            }
2541            //Re-type this expression :
2542
if (reType && this.normalized && this.expr != null) {
2543                this.expr.accept(typeVisitor);
2544            }
2545            //--------------------------------------------- ANSWER QUESTION(S) OF CURRENT CONTEXT
2546
if ((this.expr != null) && (this.expr instanceof FLWRExpression)) {
2547                //Answer questions of the current context (we must use the normalized FLWRExpression to answer) :
2548
FLWRExpression thisFLWR = (FLWRExpression) this.expr;
2549                //For FWLRExpression :
2550
//if ((this.context.existsMemo(this.depth, VisitorContext._FLWREXPRESSION_GETVARCLAUSE)) && (this.context.existsMemo(this.depth, VisitorContext._FLWREXPRESSION_GETWHERECLAUSE)) && (this.context.existsMemo(this.depth, VisitorContext._FLWREXPRESSION_GETRETURNCLAUSE))) {
2551
if (this.context.existsMemo(this.depth, VisitorContext._FLWREXPRESSION_INNERFLWR)) {
2552                    //Answers:
2553
this.context.setMemo(this.depth, VisitorContext._FLWREXPRESSION_INNERFLWR, thisFLWR, true);
2554                }
2555                //For FLWRExpression :
2556
if (this.context.existsMemo(this.depth, VisitorContext._FLWREXPRESSION_GETFLWR)) {
2557                    //Answers:
2558
this.context.setMemo(this.depth, VisitorContext._FLWREXPRESSION_GETFLWR, thisFLWR, true);
2559                }
2560                //For QuantifiedExpression :
2561
// remove condion LARS 27/02/04
2562
//if ((thisFLWR.getVariables().size() == 1) && (((Variable) thisFLWR.getVariables().get(0)).getBindingType() == Constants.FOR_BINDINGTYPE)) {
2563
//if ((this.context.existsMemo(this.depth, VisitorContext._FLWREXPRESSION_GETVARCLAUSE4QUANTIFIED)) && (this.context.existsMemo(this.depth, VisitorContext._FLWREXPRESSION_GETWHERECLAUSE4QUANTIFIED)) && (this.context.existsMemo(this.depth, VisitorContext._FLWREXPRESSION_GETRETURNCLAUSE4QUANTIFIED))) {
2564
if (this.context.existsMemo(this.depth, VisitorContext._QUANTIFIED_INNERFLWR)) {
2565                    //Answers:
2566
this.context.setMemo(this.depth, VisitorContext._QUANTIFIED_INNERFLWR, thisFLWR, true);
2567                }
2568                //}
2569
}
2570            //For gc :
2571
localCtx = null;
2572            localForCtx = null;
2573            localLetCtx = null;
2574            //TOREMOVE ?
2575
//Update response context with current context to pass the answers of parent questions:
2576
//this.context.update(localCtx);
2577
//outln("=====> New FLWR ("+nn+") = ("+this.normalized+"):\n\t>>>"+this.expr);
2578
//untrace();
2579
} catch (CloneNotSupportedException JavaDoc e) {
2580            throw new NormalizeException(0, e);
2581        } catch (XQueryException e) {
2582            throw new NormalizeException(0, e);
2583        }
2584    }
2585
2586    /**
2587     * This visit method normalizes a ITEExpression (If C then E1 else E2) and its sub expressions (C,E1 and E2). <BR>
2588     * This method apply theses rules: <BR>
2589     * <OL>
2590     * <LI>N(if C then E1 else E2) => if N(C) then N(E1) else N(E2)</LI>
2591     * <LI>N(if null|false() then E1 else E2) => N(E2)</LI>
2592     * <LI>N(if true() then E1 else E2) => N(E1)</LI>
2593     * </OL>
2594     * It possibly answers the questions of the current context.
2595     *
2596     * @param arg
2597     * a ITEExpression to normalize.
2598     */

2599    public void visit(ITEExpression arg) throws NormalizeException {
2600        try {
2601            //trace("<o-"+(nodeNumber++)+">ITEExpression<o>(hc="+arg.hashCode()+") : "+arg.toString()+" QType="+this.typeToString(arg.getQType()),0);
2602
ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
2603            VisitorContext localCtx = new VisitorContext();
2604            localCtx.merge(this.context, false);
2605            //Clean all questions which depth is smaller than current depth:
2606
localCtx.filter(this.depth);
2607            recurseVisitor.setContext(localCtx);
2608            //For multivalued expression (put in exists function) :
2609
localCtx.setMemo((this.depth + 1), VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION, null, true);
2610            //Normalize condition :
2611
XQueryExpression ifClause = arg.getIfExpression();
2612            ifClause.accept(recurseVisitor);
2613            localCtx.update(recurseVisitor.getContext());
2614            ifClause = recurseVisitor.getExpr();
2615            //Update the normalized flag:
2616
this.normalized = recurseVisitor.wasNormalized();
2617            //For multivalued expression (put in exists function) :
2618
localCtx.removeMemo((this.depth + 1), VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION);
2619            byte ifValue = 0; //0 = undefined, 1 = true and 2 = false.
2620
if (this.normalized) {
2621                if (ifClause != null) {
2622                    arg.setIfExpression(ifClause);
2623                } else {
2624                    ifValue = 2;
2625                }
2626            }
2627            //Determine if the condition value is true, false or unknown :
2628
if (ifClause instanceof FunctionTRUE) {
2629                ifValue = 1;
2630            } else if (ifClause instanceof FunctionFALSE) {
2631                ifValue = 2;
2632            } else if (ifClause instanceof XQueryExpressionSequence) {
2633                ArrayList subExpr = ((XQueryExpressionSequence) ifClause).getSubExpressions();
2634                if (subExpr.size() == 1) {
2635                    if (subExpr.get(0) instanceof FunctionTRUE) {
2636                        ifValue = 1;
2637                    } else if (subExpr.get(0) instanceof FunctionFALSE) {
2638                        ifValue = 2;
2639                    }
2640                }
2641            }
2642            XQueryExpression thenClause = arg.getThenExpression();
2643            XQueryExpression elseClause = arg.getElseExpression();
2644            if (ifValue <= 1) {
2645                //Normalize then clause :
2646
if (!(thenClause instanceof XQueryVoid)) {
2647                    thenClause.accept(recurseVisitor);
2648                    localCtx.update(recurseVisitor.getContext());
2649                    thenClause = recurseVisitor.getExpr();
2650                    //Update the normalized flag:
2651
this.normalized = this.normalized | recurseVisitor.wasNormalized();
2652                }
2653            }
2654            if ((ifValue == 0) || (ifValue == 2)) {
2655                //Normalize else clause :
2656
if (!(elseClause instanceof XQueryVoid)) {
2657                    elseClause.accept(recurseVisitor);
2658                    localCtx.update(recurseVisitor.getContext());
2659                    elseClause = recurseVisitor.getExpr();
2660                    //Update the normalized flag:
2661
this.normalized = this.normalized | recurseVisitor.wasNormalized();
2662                }
2663            }
2664            //Update result :
2665
if (this.normalized || (ifValue >= 1)) {
2666                if (ifValue == 1) {
2667                    this.expr = thenClause;
2668                } else if (ifValue == 2) {
2669                    this.expr = elseClause;
2670                } else {
2671                    arg.setIfExpression(ifClause);
2672                    arg.setThenExpression(thenClause);
2673                    arg.setElseExpression(elseClause);
2674                    this.expr = arg;
2675                }
2676                this.normalized = true;
2677            } else {
2678                this.expr = arg;
2679            }
2680            //Re-type this expression :
2681
if (reType && this.normalized && this.expr != null) {
2682                this.expr.accept(typeVisitor);
2683            }
2684            //Update response context with current context to pass the answers of parent questions:
2685
this.context.update(localCtx);
2686            //untrace();
2687
} catch (XQueryException e) {
2688            throw new NormalizeException(0, e);
2689        }
2690    }
2691
2692    /**
2693     * To analyse a LocatedExpression (and its subnodes) to determine if a rules can be applied. <BR>
2694     * This method apply theses rules: <BR>
2695     * <OL>
2696     * <LI>N(step1/.../stepi[predi]/.../stepN) => N(step1)/.../N(step2)[N(predi)]/.../N(stepN)</LI>
2697     * <LI>N(E) = N(S1/.../Si[Pi]..[Pi+m]/Si+1/.../Sn) <BR>=><BR>
2698     * for $x1 in S1/.../Si <BR>
2699     * for $x2 in $x1/Si+1/.../Sn <BR>
2700     * where N([Pi]) and ... N([Pi+m]) <BR>
2701     * return $x2 <BR>
2702     * WHERE :<BR>
2703     * If N(Pi) = QName :<BR>=> N([Pi]) = $x/Pi <BR>
2704     * If N(Pi) = true() :<BR>=> N([Pi]) = null <BR>
2705     * If N(Pi) = false() | null :<BR>=> N(E) = null <BR>
2706     * If N(Pi) = relative LocatedExpression :<BR>=> N([Pi]) = $x/Pi <BR>
2707     * If N(Pi) = absolute LocatedExpression :<BR>=> N([Pi]) = Pi <BR>
2708     * If N(Pi) = FLWRExpression :<BR>=> N([Pi]) = Pi <BR>
2709     * If N(Pi) = Variable :<BR>=> N([Pi]) = Pi</LI>
2710     * <BR>
2711     * <LI>Apply XPath on all types of expressions...see org.xquark.xml.xqueryparser.normalize.LocatedExpressionReducer class (source and javadoc) for more informations.</LI>
2712     * <LI>N(C(E)) C = condition and E = LE || FLWR || VAR => N(C(EXISTS(E)))</LI>
2713     * </OL>
2714     * It possibly answers the questions of the current context.
2715     *
2716     * @param arg
2717     * a LocatedExpression to normalize.
2718     * @see org.xquark.xml.xqueryparser.normalize.LocatedExpressionReducer
2719     */

2720
2721    private LocatedExpressionReducer ler = new LocatedExpressionReducer();
2722
2723    public void visit(LocatedExpression arg) throws NormalizeException {
2724        try {
2725            //Steps can not be null and steps.size() must be greater or egals 1
2726
ArrayList steps = arg.getSteps();
2727            if ((steps == null) || (steps.size() < 1))
2728                throw new NormalizeException(0, "This located expression form \"" + arg + "\" is not supported !");
2729            if (((Step) steps.get(0)).hasSeparator()) {
2730                throw new NormalizeException(0, "This located expression form \"" + arg + "\" is not supported : first step with separator !");
2731            }
2732            // ADD LARS to avoid having a located expression with single step and no predicates
2733
if (!arg.getInPredicate() && steps.size() == 1 && !arg.hasPredicates() && (arg.getParentExpression() == null || arg.getParentExpression().isEmpty() || !(arg.getParentExpression().get(0) instanceof ListOpUNIONExpression))) {
2734                this.normalized = true;
2735                this.expr = ((Step) steps.get(0)).getExpression();
2736                return;
2737            }
2738            //Prepare Normalization :
2739
ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
2740            VisitorContext localCtx = new VisitorContext();
2741            localCtx.merge(this.context, false);
2742            //Clean all questions which depth is smaller than current depth:
2743
localCtx.filter(this.depth);
2744            recurseVisitor.setContext(localCtx);
2745            //Save the braces, brackets and parenthesis :
2746
// boolean braces = arg.getBrace();
2747
// boolean brackets = arg.getBracket();
2748
boolean parenthesis = arg.getParenthesis();
2749            //Set local context :
2750
// comment LARS 25/09.2003
2751
//localCtx.setMemo(this.depth + 1, VisitorContext._STEP_ISPARENTAXISSTEP, null, true);
2752
//Variables declarations :
2753
boolean eliminateThisLE = false;
2754            //comment LARS 25/09.2003
2755
//boolean doNotReduce = false;
2756
//For rule LE(PRED) => FLWR(LE) :
2757
//Push the possible Step context for LE (if this located expression is in a step predicate) :
2758
Variable newVar4LE_Predicate = null;
2759            if (localCtx.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._LOCATEDEXPRESSION_INPREDICATE)) {
2760                newVar4LE_Predicate = (Variable) localCtx.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._LOCATEDEXPRESSION_INPREDICATE);
2761                localCtx.removeMemo(VisitorContext._ANY_DEPTH, VisitorContext._LOCATEDEXPRESSION_INPREDICATE);
2762                // ADD 12/05/03
2763
if (newVar4LE_Predicate != null && !arg.getStep(0).hasSeparator() && arg.getStep(0).getAxis() != Axis.NONE) {
2764                    // erase fisrt step if self::node
2765
int stepindex = 0;
2766                    if (arg.getExpression() instanceof NodeTest && ((NodeTest) arg.getExpression()).getKind() == NodeKind.NODE && arg.getStep(0).getAxis() == Axis.SELF) {
2767                        steps.remove(0);
2768                    } else {
2769                        // put child axis to first step
2770
arg.getStepNum(0).setHasSeparator(true);
2771                    }
2772                    // add step with variable
2773
arg.addStepAt(0, new Step(false, Axis.NONE, newVar4LE_Predicate, null, null));
2774                    arg.setContext(false);
2775                }
2776                // END ADD 12/05/03
2777
}
2778            ArrayList newLEVariables = new ArrayList();
2779            XQueryExpression newWhereExpr = null;
2780            ArrayList expression4VariableBuffer = new ArrayList();
2781            Variable parentVar = (arg.getParentExpression() != null && arg.getParentExpression().get(0) instanceof Variable && ((Variable) arg.getParentExpression().get(0)).getBindingType() == Constants.FOR_BINDINGTYPE) ? (Variable) arg.getParentExpression().get(0) : null;
2782            boolean firstPredicate = true;
2783            boolean hasPredicates = false;
2784            //Normalize all the steps :
2785
for (int i = 0; (i < steps.size()) && (!eliminateThisLE); i++) {
2786                //For rule LE(PRED) => FLWR(LE) :
2787
//Pass to step class the previous steps expressions for variable expression :
2788
localCtx.setMemo(this.depth + 1, VisitorContext._STEP_GETPREDICATE, expression4VariableBuffer, true);
2789                //Test if current step has predicates :
2790
// CHANGE 12/05/03
2791
boolean hadPredicates = ((Step) steps.get(i)).hasPredicates();
2792                hasPredicates = hasPredicates || hadPredicates;
2793                if (firstPredicate && hadPredicates && parentVar != null) {
2794                    localCtx.setMemo(this.depth + 1, VisitorContext._STEP_GETPREDICATE_VAR, parentVar, true);
2795                } else {
2796                    localCtx.setMemo(this.depth + 1, VisitorContext._STEP_GETPREDICATE_VAR, null, true);
2797                }
2798                //Normalize one step :
2799
recurseVisitor.setContext(localCtx);
2800                ((Step) steps.get(i)).accept(recurseVisitor);
2801                localCtx.update(recurseVisitor.getContext());
2802                if (recurseVisitor.getExpr() != null) {
2803                    steps.set(i, recurseVisitor.getExpr());
2804                    //Test context :
2805
// comment LARS 25/09.2003
2806
// if (localCtx.getMemo(this.depth + 1, VisitorContext._STEP_ISPARENTAXISSTEP) != null) {
2807
// doNotReduce = true;
2808
// localCtx.setMemo(this.depth + 1, VisitorContext._STEP_ISPARENTAXISSTEP, null, true);
2809
// }
2810
//For rule LE(PRED) => FLWR(LE) :
2811
//Test context :
2812
if (hadPredicates) {
2813                        if (localCtx.getMemo(this.depth + 1, VisitorContext._STEP_GETPREDICATE) == null) {
2814                            //There is no more predicates for the current step!
2815
//The current step without its predicates was already added in
2816
//expression4VariableBuffer by Step
2817
} else { //Context _STEP_GETPREDICATE != null
2818
ArrayList variableAndPredicate = (ArrayList) localCtx.getMemo(this.depth + 1, VisitorContext._STEP_GETPREDICATE);
2819                            //Get the new variable :
2820
if (!firstPredicate || parentVar == null) {
2821                                Variable newVar = (Variable) variableAndPredicate.get(0);
2822                                newLEVariables.add(newVar);
2823                                //Get the new predicate for new where clause :
2824
XQueryExpression newPredicate = (XQueryExpression) variableAndPredicate.get(1);
2825                                //Create/update new where clause :
2826
if (newWhereExpr == null)
2827                                    newWhereExpr = newPredicate;
2828                                else
2829                                    newWhereExpr = new BinOpANDExpression(newWhereExpr, newPredicate, arg.getParentModule());
2830                                //Re-initialization :
2831
localCtx.setMemo(this.depth + 1, VisitorContext._STEP_GETPREDICATE, null, true);
2832                                expression4VariableBuffer = new ArrayList();
2833                                expression4VariableBuffer.add(newVar);
2834                                //The previous variable for the possible next variable.
2835
} else {
2836                                // add LARS 16/04/04
2837
firstPredicate = false;
2838                                XQueryExpression newPredicate = (XQueryExpression) variableAndPredicate.get(1);
2839                                if (newWhereExpr == null)
2840                                    newWhereExpr = newPredicate;
2841                                else
2842                                    newWhereExpr = new BinOpANDExpression(newWhereExpr, newPredicate, arg.getParentModule());
2843                                //Re-initialization :
2844
localCtx.setMemo(this.depth + 1, VisitorContext._STEP_GETPREDICATE, null, true);
2845                                expression4VariableBuffer = new ArrayList();
2846                                expression4VariableBuffer.add(parentVar);
2847                            }
2848                        }
2849                    } else {
2850                        //Add the current Step in buffer :
2851
expression4VariableBuffer.add(recurseVisitor.getExpr());
2852                    }
2853
2854                } else {
2855                    eliminateThisLE = true;
2856                }
2857                //Update the normalized flag:
2858
this.normalized = this.normalized | recurseVisitor.wasNormalized();
2859            } //End for each steps
2860
//Remove memo :
2861
localCtx.removeMemo(this.depth + 1, VisitorContext._STEP_ISPARENTAXISSTEP);
2862            localCtx.removeMemo(this.depth + 1, VisitorContext._STEP_GETPREDICATE);
2863
2864            // add LARS 25/09/2003 test elimination !!!
2865
if (eliminateThisLE) {
2866                this.expr = null;
2867                return;
2868            }
2869            // end add LARS 25/09/2003 test elimination
2870

2871            //Three case (by priority) :
2872
// 1- rule LE(PRED) => FLWR(LE)
2873
// 2- do not reduce because there is parent axis
2874
// 3- do steps reduction and apply step on expression
2875
if (newLEVariables.size() > 0 || (parentVar != null && hasPredicates)) { //Case 1- rule LE(PRED) => FLWR(LE)
2876
//Create new FLWRExpression
2877
//Create last FOR variable with the last steps (if exist) :
2878
XQueryExpression newReturnExpr = null;
2879                if (expression4VariableBuffer.get(0) instanceof Variable) {
2880                    Variable headerVariable = (Variable) expression4VariableBuffer.get(0);
2881                    if (expression4VariableBuffer.size() > 1) {
2882                        //Prepare to create a new located expression for last variable :
2883
Step headerStep = new Step(false, Axis.NONE, headerVariable, null, null);
2884                        expression4VariableBuffer.set(0, headerStep);
2885                        ((Step) expression4VariableBuffer.get(1)).setHasSeparator(true);
2886                        //Create the last variable :
2887
Variable lastVar = typeVisitor.getStaticContext().createVariable(Constants.FOR_BINDINGTYPE, new LocatedExpression(expression4VariableBuffer, arg.getParentModule()), Variable.NORM_CREATOR);
2888                        newLEVariables.add(lastVar);
2889                        //Create the return clause :
2890
newReturnExpr = lastVar;
2891                    } else { //Size <= 1, but in fact : size is >= 1 so size == 1
2892
newReturnExpr = headerVariable;
2893                    }
2894                } else {
2895                    //Create the last variable :
2896
Variable lastVar = typeVisitor.getStaticContext().createVariable(Constants.FOR_BINDINGTYPE, new LocatedExpression(expression4VariableBuffer, arg.getParentModule()), Variable.NORM_CREATOR);
2897                    newLEVariables.add(lastVar);
2898                    //Create the return clause :
2899
newReturnExpr = lastVar;
2900                }
2901                //Create a FLWR expression instead of the located expression :
2902
this.normalized = true;
2903                if (parentVar == null) {
2904                    this.expr = new FLWRExpression(newLEVariables, null, newWhereExpr, newReturnExpr, arg.getParentModule());
2905                    // add 23/06/2003
2906
this.expr.setParentModule(arg.getParentModule());
2907                } else {
2908                    FLWRExpression flwr = parentVar.getParentFLWRExpression();
2909                    if (!newLEVariables.isEmpty())
2910                        flwr.addVariables(flwr.getVarPosition(parentVar) + 1, newLEVariables);
2911                    HashMap substituteMap = new HashMap();
2912                    substituteMap.put(parentVar, newReturnExpr);
2913                    if (flwr.getWhereClause() != null) {
2914                        if (flwr.getWhereClause().equals(parentVar))
2915                            flwr.setWhereClause(newReturnExpr);
2916                        else
2917                            flwr.getWhereClause().substitute(substituteMap, typeVisitor);
2918                    }
2919                    ArrayList tmpList = flwr.getOrderBy();
2920                    if (tmpList != null)
2921                        for (int i = 0; i < tmpList.size(); i++) {
2922                            XQueryExpression orderi = (XQueryExpression) tmpList.get(i);
2923                            if (orderi.equals(parentVar))
2924                                tmpList.set(i, newReturnExpr);
2925                            else
2926                                orderi.substitute(substituteMap, typeVisitor);
2927                        }
2928                    if (flwr.getReturnClause().equals(parentVar))
2929                        flwr.setReturnClause(newReturnExpr);
2930                    else
2931                        flwr.getReturnClause().substitute(substituteMap, typeVisitor);
2932                    flwr.addWhereClause(newWhereExpr);
2933                    this.expr = parentVar.getExpression();
2934                }
2935            } else { //Case 2 or 3 :
2936
// if (doNotReduce) {
2937
// doNotReduce = true;
2938
// //Case 2- do not reduce because there is parent axis
2939
// // //Get the first step :
2940
// // Step first = ((Step) steps.get(0));
2941
// // steps.remove(0);
2942
// // //Reduce only the steps 2 by 2 (but not the entire located expression because we do not know how
2943
// // //reduce LE with parent axis) :
2944
// // LocatedExpressionReducer ler = new LocatedExpressionReducer(first, steps, typeVisitor);
2945
// // if (ler.simplifySteps()) {
2946
// // //Eliminate this located expression :
2947
// // this.expr = null;
2948
// // }
2949
// // //Update the steps :
2950
// // steps = ler.getReducedSteps();
2951
// // steps.add(0, first);
2952
// // arg.setSteps(steps);
2953
// // this.expr = arg;
2954
// // this.expr.setBrace(braces);
2955
// // this.expr.setBracket(brackets);
2956
// // this.expr.setParenthesis(parenthesis);
2957
// // //Re-type this expression :
2958
// // if (typeVisitor != null) {
2959
// // this.expr.accept(typeVisitor);
2960
// // }
2961
// //-------------------------------
2962
// // change 22/08/2003
2963
// //Get the first step :
2964
// //Reduce only the steps 2 by 2 (but not the entire located expression because we do not know how
2965
// //reduce LE with parent axis) :
2966
//
2967
// //ler.reset(arg,typeVisitor);
2968
// LocatedExpressionReducer.simplifySteps(arg.getSteps(), true, (arg.getExpression() instanceof Variable));
2969
// //Update the steps :
2970
// //arg.setSteps(ler.getReducedSteps());
2971
// this.expr = arg;
2972
// //Re-type this expression :
2973
// if (typeVisitor != null) {
2974
// this.expr.accept(typeVisitor);
2975
// }
2976
// } else { //Case 3- do steps reduction and apply step on expression
2977
//Get the first step :
2978
//Step first = ((Step) steps.get(0));
2979
//Analyse the first normalize step :
2980
// comment LARS 26/09/2003
2981
/*
2982                 * if (eliminateThisLE) { //Eliminate this located expression : this.expr = null; } else {
2983                 */

2984                // if ((first.getAxis() != Axis.NONE) || (first.getPredicates() != null)) {
2985
// //First step has no separator but has an axis or predicates :
2986
// if (this.normalized) {
2987
// arg.setSteps(steps);
2988
// arg.setBrace(braces);
2989
// arg.setBracket(brackets);
2990
// arg.setParenthesis(parenthesis);
2991
// //Re-type this expression :
2992
// if (typeVisitor != null) {
2993
// arg.accept(typeVisitor);
2994
// }
2995
// }
2996
// this.expr = arg;
2997
// } else {
2998
// //Gets first step :
2999
// XQueryExpression firstExpr = first.getExpression();
3000
// steps.remove(0);
3001
// //Reduce this located expression :
3002
// LocatedExpressionReducer ler = new LocatedExpressionReducer(firstExpr, steps, typeVisitor);
3003
// if (ler.reduceLocatedExpression()) {
3004
// this.expr = ler.getReducedExpression();
3005
// this.normalized = true;
3006
// } else {
3007
// Step newExprStep = new Step(false, Axis.NONE, firstExpr, null, null);
3008
// arg.getSteps().add(0, newExprStep);
3009
// this.expr = arg;
3010
// }
3011
// //Set braces, brackets and parenthesis, and re-type :
3012
// if (this.expr != null) {
3013
// this.expr.setBrace(braces);
3014
// this.expr.setBracket(brackets);
3015
// this.expr.setParenthesis(parenthesis);
3016
// //Re-type this expression :
3017
// if (typeVisitor != null) {
3018
// this.expr.accept(typeVisitor);
3019
// }
3020
// }
3021
//------------------------------------
3022
// change 22/08/2003
3023
//Reduce this located expression :
3024
ler.reset(arg, typeVisitor);
3025                if (ler.reduceLocatedExpression(arg.getParentModule())) {
3026                    this.expr = ler.getReducedExpression();
3027                    this.normalized = true;
3028                    if (this.expr != null) {
3029                        // this.expr.setBrace(braces);
3030
// this.expr.setBracket(brackets);
3031
this.expr.setParenthesis(parenthesis);
3032                        if (reType)
3033                        this.expr.accept(typeVisitor);
3034                    }
3035                } else {
3036                    this.expr = arg;
3037                }
3038                // }
3039
// }
3040
// }
3041
//Answer/execute questions/orders found in local context :
3042
if ((newVar4LE_Predicate != null) && (this.expr instanceof LocatedExpression)) {
3043                    //For rule LE(PRED) => FLWR(LE) :
3044
//Pop the Step context for LE :
3045
localCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._LOCATEDEXPRESSION_INPREDICATE, newVar4LE_Predicate, true);
3046                    //Test if this located expression begins with relative step :
3047
ArrayList newSteps = ((LocatedExpression) this.expr).getSteps();
3048                    //Any located expression has at least one step :
3049
Step firstStep = (Step) newSteps.get(0);
3050                    if (!firstStep.hasSeparator() && (firstStep.getAxis() != Axis.NONE)) {
3051                        //outln(nn+" firstStep "+firstStep+" "+firstStep.getAxis()+" "+firstStep.getSeparator());
3052
//This is a located which begins with a relative step as '.', '..', child::A, ...etc :
3053
//Add the given variable at the beginning :
3054
//Modifiy this located expression (add the variable at the beginning) :
3055
this.normalized = true;
3056                        Step newFirstStep = new Step(false, Axis.NONE, newVar4LE_Predicate, null, null);
3057                        firstStep.setHasSeparator(true);
3058                        //To indicate that this LocatedExpression is no more contextual :
3059
this.expr.setContext(false);
3060                        //Particular case : if first step is '.', eliminate it :
3061
boolean isSelfNode = false;
3062                        if ((newSteps.size() >= 2) && (firstStep != null) && (firstStep.getPredicates() == null) && (firstStep.getAxis() == Axis.SELF)) {
3063                            XQueryExpression test = firstStep.getExpression();
3064                            if ((test != null) && (test instanceof NodeTest) && (((NodeTest) test).getKind() == NodeKind.NODE)) {
3065                                isSelfNode = true;
3066                            }
3067                        }
3068                        if (isSelfNode) {
3069                            newSteps.set(0, newFirstStep);
3070                        } else {
3071                            newSteps.add(0, newFirstStep);
3072                        }
3073                    }
3074                    //Re-type this expression :
3075
if (reType)
3076                    this.expr.accept(typeVisitor);
3077                }
3078                // add LARS 26/09/2003
3079

3080                else {
3081                    // this part of the code nomalize the following pattern
3082
// there are no more predicates
3083
/*
3084                     * $x -> xp1 $y -> $x/xp2/parent::node()/xp3 It is assumed that xp2 is either empty or ending with descendant-or-self::node() case 1 : xp2 is empty and xp3 is empty the expression becomes $y -> xp1/parent::node() $x -> $y/child::(expression of last step of xp1) case 2 : xp2 is empty and xp3 is not empty the expression becomes $newVar -> xp1/parent::node() $x -> $newVar/child::(expression of last step of xp1) $y -> $newVar/xp3 case 3 : xp2 is not empty and xp3 is empty the expression becomes case 4 : xp2 is not empty and xp3 is not empty the expression becomes $x -> xp1 $y -> $x/xp2/parent::node() union $x/xp2/descendant-or-self::node() $newVar -> $y/xp3 where exists($y/child::node())
3085                     *
3086                     *
3087                     *
3088                     * $newVar -> xp1/parent::node() $x -> $newVar/child::(expression of last step of xp1) $y -> $newVar/xp3 union $x/descendant-or-self::node() where exists $y[child::node()]
3089                     */

3090                    int parentIndex = arg.hasParentStep();
3091                    if (parentIndex != -1 && arg.startsWithVariable()) {
3092                        XQueryExpression argParent = (XQueryExpression) arg.getParentExpression().get(0);
3093                        // parent step must be just after variable
3094
if (parentIndex != 1 && arg.getStepNum(parentIndex - 1).getAxis() != Axis.DESCENDANT_OR_SELF)
3095                            throw new NormalizeException("Could not normalize located expression with parent::node : " + arg);
3096                        // get variable starting located expression
3097
Variable var = (Variable) arg.getExpression();
3098                        // verify that expression is located ending with child or descendant-or-self
3099
if (!(var.getExpression() instanceof LocatedExpression))
3100                            throw new NormalizeException("Could not normalize located expression with parent::node : " + arg);
3101                        // get parent FLWR
3102
FLWRExpression parentflwr = var.getParentFLWRExpression();
3103                        // verify that variables are in the same FLWR otherwise create temporary variable
3104
if (!(argParent instanceof Variable) || parentflwr != ((Variable) argParent).getParentFLWRExpression()) {
3105                            // add variable in parentflwr newVar -> arg
3106
// substitute arg with newVar
3107
Variable newVar = typeVisitor.getStaticContext().createVariable(Constants.LET_BINDINGTYPE, arg, Variable.NORM_CREATOR);
3108                            HashMap substituteMap = new HashMap();
3109                            substituteMap.put(arg, newVar);
3110                            parentflwr.substitute(substituteMap, typeVisitor);
3111                            parentflwr.addVariable(parentflwr.getVarPosition(var) + 1, newVar);
3112                            this.normalized = true;
3113                            this.expr = newVar;
3114                        } else {
3115                            // get starting variable
3116
Variable varParent = (Variable) argParent;
3117                            // get expression of variable
3118
LocatedExpression varLoc = (LocatedExpression) var.getExpression();
3119                            // verify last step
3120
ArrayList varLocSteps = varLoc.getSteps();
3121                            Step lastStep = varLoc.getStepNum(varLocSteps.size() - 1);
3122                            if (lastStep.getAxis() != Axis.CHILD && lastStep.getAxis() != Axis.DESCENDANT_OR_SELF)
3123                                throw new NormalizeException("Could not normalize located expression with parent::node : " + arg);
3124                            int varPos = parentflwr.getVarPosition(var);
3125                            // do the stuff!!!
3126
if (parentIndex == 1) {
3127                                // CASE 1
3128
if (parentIndex == steps.size() - 1) {
3129                                    // reset variable positions
3130
parentflwr.getVariables().remove(varPos);
3131                                    parentflwr.addVariable(parentflwr.getVarPosition(varParent) + 1, var);
3132                                    // reset arg steps
3133
arg.getSteps().remove(0);
3134                                    arg.getSteps().addAll(0, varLocSteps);
3135                                    this.expr = arg;
3136                                    // simplify var
3137
int retValue = LocatedExpressionReducer.simplifySteps(arg.getSteps(), false, arg.getParentModule());
3138                                    if (retValue == 0)
3139                                        throw new NormalizeException("Could not normalize located expression with parent::node : " + arg);
3140                                    // reset varLoc steps
3141
ArrayList newSteps = new ArrayList(2);
3142                                    newSteps.add(new Step(false, Axis.NONE, varParent, null, null));
3143                                    newSteps.add(new Step(true, Axis.CHILD, lastStep.getExpression(), null, null));
3144                                    varLoc.setSteps(newSteps);
3145                                } else { // CASE 2
3146
// create variable newVar -> xp1/PN
3147
List xp3 = steps.subList(parentIndex + 1, steps.size());
3148                                    List xp2pn = steps.subList(1, parentIndex + 1);
3149                                    arg.setSteps((ArrayList) varLocSteps.clone());
3150                                    arg.getSteps().addAll(xp2pn);
3151                                    // simplify new variable
3152
int retValue = LocatedExpressionReducer.simplifySteps(arg.getSteps(), false, arg.getParentModule());
3153                                    if (retValue == 0)
3154                                        throw new NormalizeException("Could not normalize located expression with parent::node : " + arg);
3155                                    Variable newVar = typeVisitor.getStaticContext().createVariable(var.getBindingType(), arg, Variable.NORM_CREATOR);
3156                                    parentflwr.addVariable(varPos, newVar);
3157                                    // localCtx.setMemo(this.depth, VisitorContext._ADDED_VARIABLE_BEFORE, newVar, true);
3158
// localCtx.setMemo(this.depth, VisitorContext._ADDED_VARIABLE_BEFORE_VAR, var, true);
3159
// modify expression of var -> newVar/DCN
3160
Step newVarStep = new Step(false, Axis.NONE, newVar, null, null);
3161                                    ArrayList newSteps = new ArrayList(2);
3162                                    newSteps.add(newVarStep);
3163                                    newSteps.add(new Step(true, Axis.CHILD, lastStep.getExpression(), null, null));
3164                                    varLoc.setSteps(newSteps);
3165                                    // modify expression of arg = newVar/xp3
3166
newSteps = new ArrayList();
3167                                    newSteps.add(newVarStep.clone());
3168                                    newSteps.addAll(xp3);
3169                                    //varParent.setExpression(new LocatedExpression(newSteps,typeVisitor),typeVisitor);
3170
this.expr = new LocatedExpression(newSteps, arg.getParentModule());
3171                                }
3172                            } else {
3173                                /*
3174                                 * $x -> xp1 $y -> $x/xp2/descendant-or-self::node()/parent::node()/xp3 ------------------------------------------------- $x -> xp1 $newVar -> $x/xp2/parent::node() union $x/xp2/descendant-or-self::node() $y -> $newVar/xp3 where exists($newVar/child::node())
3175                                 */

3176                                if (parentIndex == steps.size() - 1) {
3177                                    // set varParent expression
3178
ArrayList newSteps = new ArrayList();
3179                                    for (int i = 0; i < parentIndex - 1; i++)
3180                                        newSteps.add(((Step) steps.get(i)).clone());
3181                                    newSteps.add(steps.get(parentIndex));
3182                                    LocatedExpression locParent = new LocatedExpression(newSteps, false, arg.getParentModule());
3183                                    newSteps = new ArrayList();
3184                                    for (int i = 0; i < parentIndex - 1; i++)
3185                                        newSteps.add(steps.get(i));
3186                                    newSteps.add(steps.get(parentIndex - 1));
3187                                    LocatedExpression locDosNode = new LocatedExpression(newSteps, false, arg.getParentModule());
3188                                    this.expr = new ListOpUNIONExpression(locParent, locDosNode, arg.getParentModule());
3189                                    // add where clause
3190
newSteps = new ArrayList(2);
3191                                    newSteps.add(new Step(false, Axis.NONE, varParent, null, null));
3192                                    newSteps.add(new Step(true, Axis.CHILD, new NodeTest(NodeKind.NODE, null, null), null, null));
3193                                    parentflwr.addWhereClause(new LocatedExpression(newSteps, false, arg.getParentModule(), false));
3194                                } else {
3195                                    // set newVar expression
3196
ArrayList newSteps = new ArrayList();
3197                                    for (int i = 0; i < parentIndex - 1; i++)
3198                                        newSteps.add(((Step) steps.get(i)).clone());
3199                                    newSteps.add(steps.get(parentIndex));
3200                                    LocatedExpression locParent = new LocatedExpression(newSteps, false, arg.getParentModule());
3201                                    newSteps = new ArrayList();
3202                                    for (int i = 0; i < parentIndex - 1; i++)
3203                                        newSteps.add(steps.get(i));
3204                                    newSteps.add(steps.get(parentIndex - 1));
3205                                    LocatedExpression locDosNode = new LocatedExpression(newSteps, false, arg.getParentModule());
3206                                    XQueryExpression newVarExpr = new ListOpUNIONExpression(locParent, locDosNode, arg.getParentModule());
3207                                    Variable newVar = typeVisitor.getStaticContext().createVariable(varParent.getBindingType(), newVarExpr, Variable.NORM_CREATOR);
3208                                    parentflwr.addVariable(parentflwr.getVarPosition(varParent), newVar);
3209                                    // set varParent expression
3210
newSteps = new ArrayList();
3211                                    newSteps.add(new Step(false, Axis.NONE, newVar, null, null));
3212                                    newSteps.addAll(steps.subList(parentIndex + 1, steps.size()));
3213                                    this.expr = new LocatedExpression(newSteps, false, arg.getParentModule());
3214                                    // add where clause
3215
newSteps = new ArrayList(2);
3216                                    newSteps.add(new Step(false, Axis.NONE, newVar, null, null));
3217                                    newSteps.add(new Step(true, Axis.CHILD, new NodeTest(NodeKind.NODE, null, null), null, null));
3218                                    parentflwr.addWhereClause(new LocatedExpression(newSteps, false, arg.getParentModule(), false));
3219                                }
3220                                /*
3221                                 * // remove descendant-or-self::node() Step dosnodeStep = (Step) steps.get(parentIndex - 1); dosnodeStep.setHasSeparator(false); steps.remove(parentIndex - 1); // remove parent::node() Step parentStep = (Step) steps.get(parentIndex - 1); parentStep.setHasSeparator(false); steps.remove(parentIndex - 1); //create step list ArrayList newSteps = new ArrayList(1); newSteps.add(new Step(false, Axis.CHILD, new NodeType(NodeKind.NODE, null, null), null, null)); //create predicate list ArrayList predicates = new ArrayList(1); LocatedExpression predLoc = new LocatedExpression(newSteps, true, typeVisitor, false); predLoc.setBracket(true); predicates.add(predLoc); // add new step newSteps = new ArrayList(1); newSteps.add(parentStep); LocatedExpression locParent = new LocatedExpression(newSteps, false, null, false); newSteps = new ArrayList(1); newSteps.add(dosnodeStep); LocatedExpression locDosNode = new LocatedExpression(newSteps, false, null, false);
3222                                 * steps.add(parentIndex - 1, new Step(true, Axis.NONE, new ListOpUNIONExpression(locParent, locDosNode, null), predicates, null));
3223                                 */

3224
3225                                /*
3226                                 * // CASE 3 if (parentIndex == steps.size() - 1) { throw new NormalizeException("CASE 3 : Could not normalize located expression with parent::node : " + arg); } else { // CASE 4 throw new NormalizeException("CASE 4 : Could not normalize located expression with parent::node : " + arg); }
3227                                 */

3228                            }
3229                            this.normalized = true;
3230                        }
3231                    }
3232                }
3233
3234                //For multivalued expression :
3235
if ((this.expr != null) && (this.expr instanceof LocatedExpression) && (localCtx.existsMemo(this.depth, VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION))) {
3236                    //Put this expression in exists function :
3237
this.normalized = true;
3238                    // boolean brace = this.expr.getBrace();
3239
// boolean bracket = this.expr.getBracket();
3240
boolean parenthesis2 = this.expr.getParenthesis();
3241                    // this.expr.setBrace(false);
3242
// this.expr.setBracket(false);
3243
this.expr.setParenthesis(false);
3244                    ArrayList parameter = new ArrayList();
3245                    parameter.add(this.expr);
3246                    this.expr = new FunctionEXISTS(parameter, arg.getParentModule());
3247                    // this.expr.setBrace(brace);
3248
// this.expr.setBracket(bracket);
3249
this.expr.setParenthesis(parenthesis2);
3250                }
3251            }
3252            //outln("("+nn+")==>LOCATED EXPRESSION AFTER (final) ("+this.normalized+")= "+this.expr);
3253
//if (this.expr != null) {printClass(this.expr);outln("QTYPE = "+this.typeToString(this.expr.getQType()));}
3254

3255            localCtx.removeMemo(VisitorContext._ANY_DEPTH, VisitorContext._LOCATEDEXPRESSION_INPREDICATE);
3256
3257            //Update response context with current context to pass the answers of parent questions:
3258
this.context.update(localCtx);
3259            //untrace();
3260
} catch (CloneNotSupportedException JavaDoc e) {
3261            throw new NormalizeException(0, e.getMessage(), e);
3262        } catch (XQueryException e) {
3263            throw new NormalizeException(0, e.getMessage());
3264        }
3265    }
3266
3267    /**
3268     * This visit method normalizes a NodeType (do nothing: this is a terminal node). A NodeType is a node like :<BR>
3269     * <OL>
3270     * <LI>node()</LI>
3271     * <LI>text()</LI>
3272     * <LI>comment()</LI>
3273     * <LI>comment()</LI>
3274     * <LI>processing-instruction("...")</LI>
3275     * </OL>
3276     * It possibly answers the questions of the current context.
3277     *
3278     * @param arg
3279     * a NodeType to normalize.
3280     */

3281    public void visit(NodeTest arg) throws NormalizeException {
3282        try {
3283            //trace("<o-"+(nodeNumber++)+">NodeType<o>(hc="+arg.hashCode()+") : "+arg.toString()+" QType="+this.typeToString(arg.getQType()),0);
3284
//Set new expression:
3285
this.expr = arg;
3286            //Answer/execute questions/orders found in local context :
3287
// boolean brace = this.expr.getBrace();
3288
// boolean bracket = this.expr.getBracket();
3289
boolean parenthesis = this.expr.getParenthesis();
3290            //For LocatedExpression :
3291
if (this.context.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._LOCATEDEXPRESSION_INPREDICATE)) {
3292                //For rule LE(PRED) => FLWR(LE) :
3293
Variable newVar4LE_Predicate = (Variable) this.context.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._LOCATEDEXPRESSION_INPREDICATE);
3294                //Put variable in front of this QName (and transform it in a child Step) :
3295
this.normalized = true;
3296                ArrayList newSteps = new ArrayList();
3297                Step firstStep = new Step(false, Axis.NONE, newVar4LE_Predicate, null, null);
3298                newSteps.add(firstStep);
3299                // this.expr.setBrace(false);
3300
// this.expr.setBracket(false);
3301
this.expr.setParenthesis(false);
3302                //To indicate that this QName is no more contextual :
3303
this.expr.setContext(false);
3304                Step secondStep = new Step(true, Axis.CHILD, this.expr, null, null);
3305                newSteps.add(secondStep);
3306                LocatedExpression newLocated = new LocatedExpression(newSteps, arg.getParentModule());
3307                this.expr = newLocated;
3308                //For multivalued expression (put in exists function) :
3309
if (this.context.existsMemo(this.depth, VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION)) {
3310                    //Put the located expression in function EXISTS :
3311
ArrayList parameter = new ArrayList();
3312                    parameter.add(this.expr);
3313                    this.expr = new FunctionEXISTS(parameter, arg.getParentModule());
3314                }
3315                // this.expr.setBrace(brace);
3316
// this.expr.setBracket(bracket);
3317
this.expr.setParenthesis(parenthesis);
3318            }
3319            //Re-type this expression :
3320
if (reType)
3321                this.expr.accept(typeVisitor);
3322            //untrace();
3323
} catch (XQueryException e) {
3324            throw new NormalizeException(0, e);
3325        }
3326    }
3327
3328    /**
3329     * This visit method normalizes a QName (do nothing: this is a terminal node). <BR>
3330     * It possibly answers the questions of the current context.
3331     *
3332     * @param arg
3333     * a QName to normalize.
3334     */

3335    public void visit(QName arg) throws NormalizeException {
3336        try {
3337            //trace("<o-"+(nodeNumber++)+">QName<o>(hc="+arg.hashCode()+") : "+arg.toString()+" QType="+this.typeToString(arg.getQType()),0);
3338
//Set new expression:
3339
this.expr = arg;
3340            //Answer/execute questions/orders found in local context :
3341
// boolean brace = this.expr.getBrace();
3342
// boolean bracket = this.expr.getBracket();
3343
boolean parenthesis = this.expr.getParenthesis();
3344            //For LocatedExpression :
3345
if (this.context.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._LOCATEDEXPRESSION_INPREDICATE)) {
3346                //For rule LE(PRED) => FLWR(LE) :
3347
Variable newVar4LE_Predicate = (Variable) this.context.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._LOCATEDEXPRESSION_INPREDICATE);
3348                //Put variable in front of this QName (and transform it in a child Step) :
3349
this.normalized = true;
3350                ArrayList newSteps = new ArrayList();
3351                Step firstStep = new Step(false, Axis.NONE, newVar4LE_Predicate, null, null);
3352                newSteps.add(firstStep);
3353                // this.expr.setBrace(false);
3354
// this.expr.setBracket(false);
3355
this.expr.setParenthesis(false);
3356                //To indicate that this QName is no more contextual :
3357
this.expr.setContext(false);
3358                Step secondStep = new Step(true, Axis.CHILD, this.expr, null, null);
3359                newSteps.add(secondStep);
3360                LocatedExpression newLocated = new LocatedExpression(newSteps, arg.getParentModule());
3361                this.expr = newLocated;
3362                //For multivalued expression (put in exists function) :
3363
if (this.context.existsMemo(this.depth, VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION)) {
3364                    //Put the located expression in function EXISTS :
3365
ArrayList parameter = new ArrayList();
3366                    parameter.add(this.expr);
3367                    this.expr = new FunctionEXISTS(parameter, arg.getParentModule());
3368                }
3369                // this.expr.setBrace(brace);
3370
// this.expr.setBracket(bracket);
3371
this.expr.setParenthesis(parenthesis);
3372            }
3373            //Re-type this expression :
3374
/*
3375             * if (typeVisitor != null) { this.expr.accept(typeVisitor); }
3376             */

3377            //untrace();
3378
} catch (XQueryException e) {
3379            throw new NormalizeException(0, e);
3380        }
3381    }
3382
3383    /**
3384     * This visit method normalizes an SequenceTypeExpression. <BR>
3385     * It possibly answers the questions of the current context.
3386     *
3387     * @param arg
3388     * a SequenceTypeExpression to normalize.
3389     */

3390    public void visit(SequenceType arg) throws NormalizeException {
3391        try {
3392            //trace("<o-"+(nodeNumber++)+">SequenceTypeExpression<o>(hc="+arg.hashCode()+") : "+arg.toString()+" QType="+this.typeToString(arg.getQType()),0);
3393
throw new NormalizeException(0, "SequenceTypeExpression not supported : (" + arg + ")");
3394            /*
3395             * this.expr = arg; //Re-type this expression : if (typeVisitor != null) { this.expr.accept(typeVisitor); } //untrace();
3396             */

3397        } catch (XQueryException e) {
3398            throw new NormalizeException(0, e);
3399        }
3400    }
3401
3402    /**
3403     * This visit method normalizes a SortedExpression (E sortby (sort clause(s))) and its sub expressions (E and sort clauses). <BR>
3404     * This method apply theses rules: <BR>
3405     * <OL>
3406     * <LI>N(E sortby (C1, C2...Cn)) => N(E) sortby (N(C1), N(C2)...N(Cn))</LI>
3407     * <LI>N(null sortby (Ci)) => null</LI>
3408     * <LI>N(E sortby (null)) => N(E)</LI>
3409     * </OL>
3410     * It possibly answers the questions of the current context.
3411     *
3412     * @param arg
3413     * a SortedExpression to normalize.
3414     */

3415    public void visit(SortedExpression arg) throws NormalizeException {
3416        try {
3417            //trace("<o-"+(nodeNumber++)+">SortedExpression<o>(hc="+arg.hashCode()+") : "+arg.toString()+" QType="+this.typeToString(arg.getQType()),0);
3418
ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
3419            VisitorContext localCtx = new VisitorContext();
3420            localCtx.merge(this.context, false);
3421            //Clean all questions which depth is smaller than current depth:
3422
localCtx.filter(this.depth);
3423            recurseVisitor.setContext(localCtx);
3424            //Normalize sub expression:
3425
XQueryExpression exprSeq = arg.getExpression();
3426            exprSeq.accept(recurseVisitor);
3427            localCtx.update(recurseVisitor.getContext());
3428            exprSeq = recurseVisitor.getExpr();
3429            //Update the normalized flag:
3430
this.normalized = recurseVisitor.wasNormalized();
3431            if (recurseVisitor.wasNormalized()) {
3432                if (exprSeq != null) {
3433                    arg.setExpression(exprSeq);
3434                } else {
3435                    arg = null;
3436                }
3437            }
3438            if (arg != null) {
3439                //Normalize sort clauses:
3440
ArrayList sortClauses = arg.getSortClauses();
3441                if ((sortClauses != null) && (sortClauses.size() != 0)) {
3442                    //Normalize each clause :
3443
int sortClauseLen = sortClauses.size();
3444                    XQueryExpression aClause = null;
3445                    for (int i = sortClauseLen - 1; i >= 0; i--) {
3446                        //Get order:
3447
int[] direction = ((XQueryExpression) sortClauses.get(i)).getOrder();
3448                        //Normalize this clause :
3449
((XQueryExpression) sortClauses.get(i)).accept(recurseVisitor);
3450                        localCtx.update(recurseVisitor.getContext());
3451                        aClause = recurseVisitor.getExpr();
3452                        //Update the normalized flag:
3453
this.normalized = this.normalized | recurseVisitor.wasNormalized();
3454                        if (recurseVisitor.wasNormalized()) {
3455                            aClause = recurseVisitor.getExpr();
3456                            if (aClause != null) {
3457                                aClause.setOrder(direction);
3458                                sortClauses.set(i, aClause);
3459                            } else {
3460                                sortClauses.remove(i);
3461                            }
3462                        }
3463                    }
3464                    if (sortClauses.size() == 0) {
3465                        this.expr = exprSeq;
3466                    } else {
3467                        arg.setSortClauses(sortClauses);
3468                        this.expr = arg;
3469                    }
3470                } else {
3471                    this.expr = exprSeq;
3472                }
3473                //Re-type this expression :
3474
if (reType && this.normalized && this.expr != null) {
3475                    this.expr.accept(typeVisitor);
3476                }
3477            } else {
3478                this.expr = null;
3479            }
3480            //Update response context with current context to pass the answers of parent questions:
3481
this.context.update(localCtx);
3482            //untrace();
3483
} catch (XQueryException e) {
3484            throw new NormalizeException(0, e);
3485        }
3486    }
3487
3488    /**
3489     * This visit method normalizes a Step and its sub expression. <BR>
3490     * This method apply theses rules: <BR>
3491     * <OL>
3492     * <LI>N(/Axis::E1[E2]) => /Axis::N(E1)[N(E2)]</LI>
3493     * <LI>N(/Axis::null[E]) => null</LI>
3494     * <LI>N(/Axis::E[null|false()|(empty sequence)]) => null</LI>
3495     * <LI>N(/Axis::E[true()|(not empty sequence)]) => /Axis::N(E)</LI>
3496     * <LI>N(/Axis::E[P1][P2][P3]...) => /Axis::N(E)[N(P1 AND P2 AND P3 AND ...)]</LI>
3497     * </OL>
3498     * It possibly answers the questions of the current context.
3499     *
3500     * @param arg
3501     * a Step to normalize.
3502     */

3503    public void visit(Step arg) throws NormalizeException {
3504        try {
3505            //outln(nn+" "+arg.getSeparator()+" "+arg.getAxis());
3506
ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
3507            VisitorContext localCtx = new VisitorContext();
3508            localCtx.merge(this.context, false);
3509            //Clean all questions which depth is smaller than current depth:
3510
localCtx.filter(this.depth);
3511            recurseVisitor.setContext(localCtx);
3512            //Get Step separator and axis:
3513
// boolean separator = arg.hasSeparator();
3514
// if (separator > Constants.MAX_SEPARATOR)
3515
// throw new NormalizeException(0,"Separator of a step must be always \"/\" or nothing.");
3516
// int axis = arg.getAxis();
3517
// erase LARS not needed should have been tested before
3518
//Only supported axis :
3519
// if (!((axis == Axis.NONE) || (axis == Axis.CHILD) || (axis == Axis.DESCENDANT_OR_SELF) || (axis == Axis.SELF) || (axis == Axis.ATTRIBUTE) || (axis == Axis.DESCENDANT) || (axis == Axis.PARENT))) {
3520
// throw new NormalizeException(0, "Axis " + Axis.AXISSTRINGS[axis] + " not supported in step " + arg + ".");
3521
// }
3522
//Normalize sub expression:
3523
XQueryExpression subExpr = arg.getExpression();
3524            subExpr.accept(recurseVisitor);
3525            localCtx.update(recurseVisitor.getContext());
3526            subExpr = recurseVisitor.getExpr();
3527            //Update the normalized flag:
3528
this.normalized = recurseVisitor.wasNormalized();
3529            if (recurseVisitor.wasNormalized()) {
3530                if (subExpr != null) {
3531                    arg.setExpression(subExpr);
3532                } else {
3533                    arg = null;
3534                }
3535            }
3536            //For LE(PRED) (See LocatedExpression) :
3537
//Note this arraylist is empty :
3538
ArrayList expression4VariableBuffer = (ArrayList) localCtx.getMemo(this.depth, VisitorContext._STEP_GETPREDICATE);
3539            localCtx.setMemo(this.depth, VisitorContext._STEP_GETPREDICATE, null, true);
3540            if (arg != null) {
3541                //Get predicates if exists :
3542
ArrayList predicates = arg.getPredicates();
3543                if ((predicates != null) && (predicates.size() > 0)) {
3544                    //For rule LE(PRED) :
3545
// change LARS 16/04/04
3546
Variable newVar = null;
3547                    if (expression4VariableBuffer != null) {
3548                        newVar = (Variable) localCtx.getMemo(this.depth, VisitorContext._STEP_GETPREDICATE_VAR);
3549                        //Add the current step without its predicate :
3550
arg.setPredicates(null);
3551                        expression4VariableBuffer.add(arg);
3552                        if (expression4VariableBuffer.get(0) instanceof Variable) {
3553                            Variable headerVariable = (Variable) expression4VariableBuffer.get(0);
3554                            Step headerStep = new Step(false, Axis.NONE, headerVariable, null, null);
3555                            expression4VariableBuffer.set(0, headerStep);
3556                        }
3557                        if (newVar == null) {
3558                            //Create new variable :
3559
// ADD LARS to avoid located expression with a single step without predicates
3560
if (expression4VariableBuffer.size() == 1)
3561                                newVar = typeVisitor.getStaticContext().createVariable(Constants.FOR_BINDINGTYPE, ((Step) expression4VariableBuffer.get(0)).getExpression(), Variable.NORM_CREATOR);
3562                            else
3563                                newVar = typeVisitor.getStaticContext().createVariable(Constants.FOR_BINDINGTYPE, new LocatedExpression(expression4VariableBuffer, arg.getParentModule()), Variable.NORM_CREATOR);
3564                        } else {
3565                            if (expression4VariableBuffer.size() == 1)
3566                                newVar.setExpression(((Step) expression4VariableBuffer.get(0)).getExpression(), true);
3567                            else
3568                                newVar.setExpression(new LocatedExpression(expression4VariableBuffer, arg.getParentModule()), true);
3569                        }
3570                        localCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._LOCATEDEXPRESSION_INPREDICATE, newVar, true);
3571                    }
3572
3573                    /*
3574                     * Variable newVar = null; //Always true if steps are only in LocatedExpression : if (localCtx.existsMemo(this.depth, VisitorContext._STEP_GETPREDICATE)) { //Add the current step without its predicate : arg.setPredicates(null); expression4VariableBuffer.add(arg); //Create expression of the variable : if (expression4VariableBuffer.get(0) instanceof Variable) { Variable headerVariable = (Variable) expression4VariableBuffer.get(0); Step headerStep = new Step(false, Axis.NONE, headerVariable, null, null); expression4VariableBuffer.set(0, headerStep); } //Create new variable : // ADD LARS to avoid located expression with a single step without predicates if (expression4VariableBuffer.size() == 1) newVar = createVariable(Constants.FOR_BINDINGTYPE, ((Step) expression4VariableBuffer.get(0)).getExpression()); else newVar = createVariable(Constants.FOR_BINDINGTYPE, new LocatedExpression(expression4VariableBuffer, arg.getParentModule())); //Prepare context order for sub
3575                     * expressions in predicates : localCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._LOCATEDEXPRESSION_INPREDICATE, newVar, true); }
3576                     */

3577                    //Normalize all predicates:
3578
int predicatesLen = predicates.size();
3579                    boolean eliminateThis = false;
3580                    XQueryExpression lastPredicate = null;
3581                    for (int i = predicatesLen - 1; (i >= 0) && (arg != null); i--) {
3582                        //For multivalued expression (put in exists function) :
3583
localCtx.setMemo((this.depth + 1), VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION, null, true);
3584                        //Normalize the current predicate :
3585
((XQueryExpression) predicates.get(i)).accept(recurseVisitor);
3586                        localCtx.update(recurseVisitor.getContext());
3587                        //Update the normalized flag:
3588
this.normalized = this.normalized | recurseVisitor.wasNormalized();
3589                        if (recurseVisitor.getExpr() != null) {
3590                            XQueryExpression aPredicate = recurseVisitor.getExpr();
3591                            //Test if predicate or step can be eliminated :
3592
if (aPredicate instanceof FunctionTRUE) {
3593                                //Case predicate == true() :
3594
this.normalized = true;
3595                                aPredicate = null;
3596                            } else if (aPredicate instanceof FunctionFALSE) {
3597                                //Case predicate == false() :
3598
this.normalized = true;
3599                                arg = null;
3600                            } else if (aPredicate instanceof XQueryExpressionSequence) {
3601                                //Case predicate == sequence :
3602
int size = ((XQueryExpressionSequence) aPredicate).getSubExpressions().size();
3603                                this.normalized = true;
3604                                if (size == 0) {
3605                                    arg = null; //Empty sequence == false
3606
} else {
3607                                    aPredicate = null;
3608                                    //Not empty sequence == true
3609
}
3610                            }
3611                            //Concat predicates (AND) :
3612
if (arg != null) {
3613                                if (aPredicate != null) {
3614                                    // aPredicate.setBracket(false);
3615
if (!(aPredicate instanceof XQueryExpressionSequence)) {
3616                                        aPredicate.setParenthesis(true);
3617                                    }
3618                                    if ((predicatesLen >= 2) && (lastPredicate != null)) {
3619                                        this.normalized = true;
3620                                        lastPredicate = new BinOpANDExpression(aPredicate, lastPredicate, arg.getParentModule());
3621                                    } else {
3622                                        lastPredicate = aPredicate;
3623                                    }
3624                                }
3625                            }
3626                        } else {
3627                            this.normalized = true;
3628                            arg = null;
3629                        }
3630                    } //End for
3631
//For multivalued expression (put in exists function) :
3632
localCtx.removeMemo((this.depth + 1), VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION);
3633                    if (arg != null) {
3634                        if (lastPredicate != null) {
3635                            //For LocatedExpression rule LE(PRED) :
3636
ArrayList variableAndPredicate = new ArrayList();
3637                            variableAndPredicate.add(newVar);
3638                            variableAndPredicate.add(lastPredicate);
3639                            localCtx.setMemo(this.depth, VisitorContext._STEP_GETPREDICATE, variableAndPredicate, true);
3640                            //Remove predicate of the current step :
3641
this.normalized = true;
3642                        }
3643                        arg.setPredicates(null);
3644                    }
3645                }
3646                //Remove memo :
3647
//For LocatedExpression rule LE(PRED) :
3648
if (localCtx.existsMemo(this.depth, VisitorContext._STEP_GETPREDICATE)) {
3649                    localCtx.removeMemo(VisitorContext._ANY_DEPTH, VisitorContext._LOCATEDEXPRESSION_INPREDICATE);
3650                }
3651            }
3652            this.expr = arg;
3653            //Answer/execute questions of the current context (we must use the normalized Step to answer):
3654
if (this.expr != null) {
3655                //For LocatedExpression:
3656
//Answer question : it is a parent axis step ?
3657
if ((localCtx.existsMemo(this.depth, VisitorContext._STEP_ISPARENTAXISSTEP)) && (this.expr instanceof Step) && (((Step) this.expr).getAxis() == Axis.PARENT)) {
3658                    localCtx.setMemo(this.depth, VisitorContext._STEP_ISPARENTAXISSTEP, Boolean.TRUE, true);
3659                }
3660            }
3661            //Re-type this expression :
3662
if (reType && this.normalized && this.expr != null) {
3663                this.expr.accept(typeVisitor);
3664            }
3665            //outln("("+nn+") STEP AFTER ("+this.normalized+") = "+this.expr);
3666
//Update response context with current context to pass the answers of parent questions:
3667
this.context.update(localCtx);
3668            //untrace();
3669
} catch (XQueryException e) {
3670            throw new NormalizeException(0, e);
3671        }
3672    }
3673
3674    /**
3675     * This visit method normalizes a Variable and its expression (its value). <BR>
3676     * If it is a variable declaration, we normalize its expression. This method apply theses rules: <BR>
3677     * <OL>
3678     * <LI>N(Var(E)) => Var(N(E)) if this instance of Var is a declaration</LI>
3679     * <LI>N(Var(E1)) and substitution order of Var(E1) by E2 => N(E2)</LI>
3680     * <LI>N(Var(E1)) and substitution order of E1 by E2 => Var(N(E2))</LI>
3681     * <LI>N(C(E)) C = condition and E = LE || FLWR || VAR => N(C(EXISTS(E)))</LI>
3682     * </OL>
3683     * It possibly answers the questions of the current context.
3684     *
3685     * @param arg
3686     * a Variable to normalize.
3687     */

3688    public void visit(Variable arg) throws NormalizeException {
3689        try {
3690            //normalize declared variable ADD LARS 19/01/04
3691
if (arg.getBindingType() == Constants.DECLARATION_BINDINGTYPE) {
3692                if (arg.getExpression() != null) {
3693                    this.expr = arg.getExpression();
3694                    this.normalized = true;
3695                }
3696                return;
3697            }
3698            ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
3699            VisitorContext localCtx = new VisitorContext();
3700            localCtx.merge(this.context, false);
3701            //outln("VAR CONTEXT = "+localCtx);
3702
//Clean all questions which depth is smaller than current depth:
3703
localCtx.filter(this.depth);
3704            recurseVisitor.setContext(localCtx);
3705            //Normalize expression of this variable if this is a variable declaration (one time):
3706
if (localCtx.existsMemo(this.depth, VisitorContext._VARIABLE_DECLARATION)) {
3707                (arg.getExpression()).accept(recurseVisitor);
3708                localCtx.update(recurseVisitor.getContext());
3709                if (recurseVisitor.getExpr() != null) {
3710                    arg.setExpression(recurseVisitor.getExpr(), true);
3711                } else {
3712                    arg = null;
3713                }
3714                //Update the normalized flag:
3715
this.normalized = recurseVisitor.wasNormalized();
3716            }
3717            this.expr = arg;
3718            //Answer/execute questions of the current context (we must use the normalized Variable to answer):
3719
if (this.expr != null) {
3720                // add LARS test if variable is bound to FLWR that should be replaced
3721
// end add LARS
3722

3723                //For FLWRExpression:
3724
//Execute orders : change expression of variable :
3725
if (localCtx.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_CHANGEEXPRESSION4FLWR)) {
3726                    Variable changeExpr = (Variable) localCtx.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_CHANGEEXPRESSION4FLWR);
3727                    if (changeExpr.getVarName().equals(arg.getVarName())) {
3728                        //outln(" ("+nn+") Change Expr for FLWR (var = "+arg.getVarName()+") : "
3729
//+arg.getExpression()+" by "+(XQueryExpression)changeExpr.getExpression().clone());
3730
//We MUST clone the expression because it can be change many time !
3731
arg.setExpression((XQueryExpression) changeExpr.getExpression().clone(), true);
3732                        this.expr = arg;
3733                        //Indicate that we normalized this expression:
3734
this.normalized = true;
3735                    }
3736
3737                }
3738                HashMap substVariables = null;
3739                //For FLWRExpression:
3740
//Execute orders : substitution of variable by an expression :
3741
if (this.expr != null) {
3742                    if (localCtx.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4FLWR)) {
3743                        substVariables = (HashMap) localCtx.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4FLWR);
3744                        if (substVariables.containsKey(arg.getVarName())) {
3745                            XQueryExpression substExpr = (XQueryExpression) substVariables.get(arg.getVarName());
3746                            //outln(" ("+nn+") ON SUBSTITUE(1) "+this.expr+" par "+substExpr);
3747
if (substExpr != null) {
3748                                //We MUST clone the substitution expression because it can be substitute many time !
3749
this.expr = (XQueryExpression) substExpr.clone();
3750                            } else { //substExpr == null
3751
this.expr = null;
3752                            }
3753                            //Indicate that we normalized this expression:
3754
this.normalized = true;
3755                        }
3756                    }
3757                    if (localCtx.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR)) {
3758                        substVariables = (HashMap) localCtx.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4LETFLWR);
3759                        if (substVariables.containsKey(arg.getVarName())) {
3760                            XQueryExpression substExpr = (XQueryExpression) substVariables.get(arg.getVarName());
3761                            //outln(" ("+nn+") ON SUBSTITUE(2) "+this.expr+" par "+substExpr+" AGREGAT ? "+localCtx.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._INAGGREGATEFUNCTION));
3762
//if ((substExpr != null) && !localCtx.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._INAGGREGATEFUNCTION)) {
3763
if (substExpr != null) {
3764                                //We MUST clone the substitution expression because it can be substitute many time !
3765
this.expr = (XQueryExpression) substExpr.clone();
3766                                // if (!this.expr.getBracket() && !this.expr.getBrace()) {
3767
// this.expr.setParenthesis(true);
3768
// }
3769
//Indicate that we normalized this expression:
3770
this.normalized = true;
3771                                //To inform FLWR (where clause) of this variable substitution :
3772
if (localCtx.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_WASSUBSTITUTELETFLWR)) {
3773                                    localCtx.setMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_WASSUBSTITUTELETFLWR, Boolean.TRUE, true);
3774                                }
3775                            } else if (substExpr == null) {
3776                                this.expr = null;
3777                                //Indicate that we normalized this expression:
3778
this.normalized = true;
3779                            }
3780                        }
3781
3782                    }
3783                }
3784                //For QuantifiedExpression:
3785
//Execute orders
3786
if ((this.expr != null) && (localCtx.existsMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4QUANTIFIED))) {
3787                    substVariables = (HashMap) localCtx.getMemo(VisitorContext._ANY_DEPTH, VisitorContext._VARIABLE_SUBSTITUTION4QUANTIFIED);
3788                    //outln(" ("+nn+") SUBSTITUTION DE VARIABLE(3) ? Current Varname = "+arg.getVarName()+" in "+substVariables);
3789
if (substVariables.containsKey(arg.getVarName())) {
3790                        XQueryExpression substExpr = (XQueryExpression) substVariables.get(arg.getVarName());
3791                        //outln(" ("+nn+") ON SUBSTITUE(3) "+this.expr+" par "+substExpr);
3792
if (substExpr != null) {
3793                            //We MUST clone the substitution expression because it can be substitute many time !
3794
this.expr = (XQueryExpression) substExpr.clone();
3795                        } else { //substExpr == null
3796
this.expr = null;
3797                        }
3798                        //Indicate that we normalized this expression:
3799
this.normalized = true;
3800                    }
3801                }
3802            }
3803            //For multivalued expression (put in exists function) :
3804
if ((this.expr != null) && (localCtx.existsMemo(this.depth, VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION))) {
3805                this.normalized = true;
3806                // boolean brace = this.expr.getBrace();
3807
// boolean bracket = this.expr.getBracket();
3808
boolean parenthesis = this.expr.getParenthesis();
3809                // this.expr.setBrace(false);
3810
// this.expr.setBracket(false);
3811
this.expr.setParenthesis(false);
3812                ArrayList parameter = new ArrayList();
3813                parameter.add(this.expr);
3814                this.expr = new FunctionEXISTS(parameter, arg.getParentModule());
3815                // this.expr.setBrace(brace);
3816
// this.expr.setBracket(bracket);
3817
this.expr.setParenthesis(parenthesis);
3818            }
3819            //Re-type this expression :
3820
if (reType && this.normalized && this.expr != null) {
3821                this.expr.accept(typeVisitor);
3822            }
3823            //Update response context with current context to pass the answers of parent questions:
3824
this.context.update(localCtx);
3825            //outln(" ("+nn+") CTX VAR : "+localCtx);
3826
//outln(" ("+nn+") NEW VARIABLE (hc="+this.expr.hashCode()+") = "+this.expr+" "+this.normalized); //+" "+((Variable)this.expr).getExpression());
3827
} catch (CloneNotSupportedException JavaDoc e) {
3828            throw new NormalizeException(0, e);
3829        } catch (XQueryException e) {
3830            throw new NormalizeException(0, e);
3831        }
3832    }
3833
3834    /**
3835     * This visit method normalizes a XQueryExpressionSequence (E1, E2, E3...). <BR>
3836     * This method apply theses rules: <BR>
3837     * <OL>
3838     * <!-- 1 -->
3839     * <LI>N(SEQ(E)) => SEQ(N(E))</LI>
3840     * <!-- 2 -->
3841     * <LI>N(SEQ(null)) => null</LI>
3842     * <!-- 3 -->
3843     * <LI>N(SEQ(SEQ(...SEQ(E)...))) => SEQ(N(E)) with E <>SEQ</LI>
3844     * <!-- 4 -->
3845     * <LI>N(SEQ(E1, SEQ(), SEQ(E2,E3), SEQ(E4))) => SEQ(N(E1), N(E2), N(E3), N(E4)) (sequence linearization)</LI>
3846     * <!-- 5 -->
3847     * <LI>N("{"E"}") AND E <- EC (subsitution by EC expression) => N(EC)</LI>
3848     * <!-- 6 -->
3849     * <LI>N("("E")") AND (DEPTH = 0 OR parent expression is a parenthesed) AND E is not a sequence (multivalued) => N(E)</LI>
3850     * <!-- 7 -->
3851     * <LI>N("{""("E")""}") => "{"N(E)"}"</LI>
3852     * <!-- 8 -->
3853     * <LI>N(FC"(""("E")"")") AND E is not a sequence => FC"("N(E)")"</LI>
3854     * </OL>
3855     * It possibly answers the questions of the current context.
3856     *
3857     * @param arg
3858     * a XQueryExpressionSequence to normalize.
3859     */

3860    public void visit(XQueryExpressionSequence arg) throws NormalizeException {
3861        try {
3862            //NOTE: method getExpressions() can not return null or anempty ArrayList (see XQueryExpressionSequence).
3863
ExpressionNormalizationVisitor recurseVisitor = new ExpressionNormalizationVisitor(this.depth, typeVisitor, sourceName);
3864            VisitorContext localCtx = new VisitorContext();
3865            //Get parent context content:
3866
localCtx.merge(this.context, false);
3867            //Clean all questions which depth is smaller than current depth:
3868
localCtx.filter(this.depth);
3869            // Useless : if (localCtx.existsMemo(this.depth, VisitorContext._XQUERYEXPRESSIONSEQUENCE_ELEMENT_CHILDREN))
3870
//localCtx.setMemo(this.depth+1, VisitorContext._ELEMENT_CHILDREN,null, true);
3871
recurseVisitor.setContext(localCtx);
3872            //Get sub expression(s) :
3873
ArrayList expressions = arg.getSubExpressions();
3874            // boolean brace = arg.getBrace();
3875
boolean isASequence = true;
3876            //Normalization rule 3 (and implicitly rule 1):
3877
while ((expressions != null) && (expressions.size() == 1) && (expressions.get(0) instanceof XQueryExpressionSequence)) {
3878                //We ignore current sequence (useless sequence) :
3879
arg = (XQueryExpressionSequence) expressions.get(0);
3880                expressions = arg.getSubExpressions();
3881                // brace = brace | arg.getBrace();
3882
//Update the normalized flag:
3883
this.normalized = true;
3884            }
3885            //Here: arg is the new XQueryExpressionSequence to analyse and expressions are its child(s) expression(s).
3886
//To apply normalization rule 4 (not by recursiv way):
3887
if (expressions.size() > 1) {
3888                Object JavaDoc[] childExpr = expressions.toArray();
3889                ArrayList subExprTmp;
3890                expressions.clear();
3891                for (int i = 0; i < childExpr.length; i++) {
3892                    if (childExpr[i] instanceof XQueryExpressionSequence) {
3893                        //Note: subexpression of a sequence can not be null or empty (see XQueryExpressionSequence) !
3894
subExprTmp = ((XQueryExpressionSequence) childExpr[i]).getSubExpressions();
3895                        //Add all children in result expressions ArrayList :
3896
for (int j = 0; j < subExprTmp.size(); j++) {
3897                            expressions.add(subExprTmp.get(j));
3898                        }
3899                        //Update the normalized flag:
3900
this.normalized = true;
3901                    } else if (!(childExpr[i] instanceof XQueryVoid)) {
3902                        //Add child expression just "as it is":
3903
expressions.add(childExpr[i]);
3904                    } //Else : ignore current expression.
3905
}
3906            }
3907            //Normalize the (linearized) sequence of expression(s) after the rules 3 and 4 were applied :
3908
ArrayList childNormalizedExpr = new ArrayList();
3909            //For multivalued expression (put in exists function) :
3910
boolean mustBeInExistsFunction = false;
3911            if (localCtx.existsMemo(this.depth, VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION)) {
3912                localCtx.removeMemo(this.depth, VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION);
3913                mustBeInExistsFunction = true;
3914            }
3915            //Normalize child expressions:
3916
for (int i = 0; i < expressions.size(); i++) {
3917                //For multivalued expression (put in exists function) :
3918
if (mustBeInExistsFunction) {
3919                    localCtx.setMemo((this.depth + 1), VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION, null, true);
3920                }
3921                ((XQueryExpression) expressions.get(i)).accept(recurseVisitor);
3922                localCtx.update(recurseVisitor.getContext());
3923                if (recurseVisitor.getExpr() != null) {
3924                    childNormalizedExpr.add(recurseVisitor.getExpr());
3925                }
3926                //Update the normalized flag:
3927
this.normalized = this.normalized | recurseVisitor.wasNormalized();
3928            }
3929            //For multivalued expression (put in exists function) :
3930
localCtx.removeMemo((this.depth + 1), VisitorContext._MULTIVALUED_NEEDEXISTSFUNCTION);
3931            //For rule 5 :
3932
if ((childNormalizedExpr.size() == 1) /* && (arg.getBrace()) */
3933                    && (childNormalizedExpr.get(0) instanceof Element)) {
3934                //Return the sub expression without braces :
3935
this.expr = (XQueryExpression) childNormalizedExpr.get(0);
3936                isASequence = false;
3937                //Indicate that at least a rule was applied:
3938
this.normalized = true;
3939            } else if ((childNormalizedExpr.size() == 1) && (arg.getParenthesis()) && (this.depth == 1)) {
3940                //Rule 6 :
3941
//Return the sub expression without parenthesis:
3942
this.expr = (XQueryExpression) childNormalizedExpr.get(0);
3943                isASequence = false;
3944                //Indicate that at least a rule was applied:
3945
this.normalized = true;
3946            } else {
3947                //Test if sub expressions were normalized:
3948
if (this.normalized) {
3949                    if (childNormalizedExpr.size() == 0) {
3950                        expr = null;
3951                    } else if (childNormalizedExpr.size() == 1) {
3952                        expr = (XQueryExpression) childNormalizedExpr.get(0);
3953                    } else {
3954                        //Update current XQueryExpressionSequence:
3955
expr = new XQueryExpressionSequence(childNormalizedExpr, arg.getParentModule());
3956                    }
3957                } else
3958                    this.expr = arg;
3959            }
3960            //Set delimiters :
3961
if (this.expr != null) {
3962                //Set parenthesis, braces...:
3963
// if (isASequence) {
3964
// if (brace) {
3965
// //Normalization rule 7
3966
// this.setSequenceDelimiters(this.expr, true, true, arg.getBracket());
3967
// } else {
3968
// this.setSequenceDelimiters(this.expr, true, arg.getBrace(), arg.getBracket());
3969
// }
3970
// }
3971
//Execute order:
3972
//For rule 8 (order, not question):
3973
if ((this.expr instanceof XQueryExpressionSequence) && (localCtx.existsMemo(this.depth, VisitorContext._INCLUDEINPARENTHESIS))) {
3974                    ArrayList subExpr = ((XQueryExpressionSequence) this.expr).getSubExpressions();
3975                    if (subExpr.size() == 1) {
3976                        this.expr = (XQueryExpression) subExpr.get(0);
3977                    }
3978                }
3979
3980            }
3981            //Re-type and answer question(s) :
3982
if (this.expr != null) {
3983                //Re-type this expression :
3984
if (reType && this.normalized) {
3985                    this.expr.accept(typeVisitor);
3986                }
3987                //Answer questions of the current context (we must use the normalized XQueryExpressionSequence to answer):
3988
//For FWLRExpression :
3989
if ((localCtx.existsMemo(this.depth, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS)) && (this.expr instanceof XQueryExpressionSequence)) {
3990                    int sequenceSize = ((XQueryExpressionSequence) this.expr).getSubExpressions().size();
3991                    localCtx.setMemo(this.depth, VisitorContext._XQUERYEXPRESSIONSEQUENCE_EXISTS, new Integer JavaDoc(sequenceSize), true);
3992                }
3993            }
3994            //Update response context with current context to pass the answers of parent questions:
3995
this.context.update(localCtx);
3996        } catch (XQueryException e) {
3997            throw new NormalizeException(0, e);
3998        }
3999    }
4000
4001    /**
4002     * This visit method normalizes a XQueryVoid (return null because XQueryVoid is an empty sequence : () ).<BR>
4003     * It possibly answers the questions of the current context.
4004     *
4005     * @param arg
4006     * a XQueryVoid to normalize.
4007     */

4008    public void visit(XQueryVoid arg) throws NormalizeException {
4009        this.expr = null;
4010    }
4011}
Popular Tags