KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > xquery > typing > TypeVisitor


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.typing;
25
26 import java.util.*;
27
28 import org.xml.sax.SAXException JavaDoc;
29 import org.xquark.schema.*;
30 import org.xquark.schema.datatypes.PrimitiveType;
31 import org.xquark.xpath.*;
32 import org.xquark.xquery.ModuleLocator;
33 import org.xquark.xquery.ModuleManager;
34 import org.xquark.xquery.metadata.StaticContext;
35 import org.xquark.xquery.parser.*;
36 import org.xquark.xquery.parser.primitivefunctions.fnfunctions.*;
37 import org.xquark.xquery.parser.primitivefunctions.xsfunctions.*;
38 import org.xquark.xquery.parser.util.Constants;
39
40 public class TypeVisitor extends DefaultParserVisitor {
41     private static final String JavaDoc RCSRevision = "$Revision: 1.12 $";
42     private static final String JavaDoc RCSName = "$Name: $";
43
44     private static final String JavaDoc STAR = "*";
45     private static final String JavaDoc XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
46
47     public static final String JavaDoc SC_STRING = "string";
48     public static final String JavaDoc SC_BOOLEAN = "boolean";
49     public static final String JavaDoc SC_DOUBLE = "double";
50     public static final String JavaDoc SC_DECIMAL = "decimal";
51     public static final String JavaDoc SC_INTEGER = "integer";
52     public static final String JavaDoc SC_FLOAT = "float";
53     public static final String JavaDoc SC_DATE = "date";
54     public static final String JavaDoc SC_TIME = "time";
55     public static final String JavaDoc SC_DATETIME = "dateTime";
56     public static final String JavaDoc SC_ANYTYPE = "anyType";
57     //public static final String SC_ANYSIMPLETYPE = "anySimpleType";
58
public static final String JavaDoc SC_QNAME = "QName";
59     private static final String JavaDoc TEMP_NAME = "TEMP_NAME";
60
61     private StaticContext context = null;
62
63     // new context stuff
64
private ArrayList contextXNodes = null;
65     private QType contextQType = null;
66     private byte contextType = QTypeDocument.ANY_ORIGIN;
67     private LocatedExpression contextLocated = null;
68     private int contextLocatedStepIndex = -1;
69
70     // context stuff
71
private boolean inPredicate = false;
72     private boolean noForce = true;
73
74     private SchemaManager typingschemamanager = null;
75     private Schema typingschema = null;
76     // for qa only
77
boolean qaOnly = false;
78
79     // constructor
80

81     public TypeVisitor(StaticContext context, boolean qaOnly) throws TypeException {
82         this.context = context;
83         this.qaOnly = qaOnly;
84         if (typingschemamanager == null) {
85             this.typingschemamanager = new SchemaManager();
86             this.typingschema = new Schema("http://www.xquark.org/EXECUTIONPLAN", null, typingschemamanager);
87             try {
88                 typingschemamanager.putSchema(typingschema);
89             } catch (SAXException JavaDoc saxe) {
90                 throw new TypeException("Could not add schema to manager");
91             }
92         }
93     }
94
95     public TypeVisitor(StaticContext context) throws TypeException {
96         this.context = context;
97         if (typingschemamanager == null) {
98             this.typingschemamanager = new SchemaManager();
99             this.typingschema = new Schema("http://www.xquark.org/EXECUTIONPLAN", null, typingschemamanager);
100             try {
101                 typingschemamanager.putSchema(typingschema);
102             } catch (SAXException JavaDoc saxe) {
103                 throw new TypeException("Could not add schema to manager");
104             }
105         }
106     }
107
108     public StaticContext getStaticContext() {
109         return context;
110     }
111
112     public SchemaManager getSchemaManager() {
113         return context.getSchemaManager();
114     }
115
116     public SchemaLocator getSchemaLocator() {
117         return context.getSchemaManager();
118     }
119
120     public ModuleManager getModuleManager() {
121         return context.getModuleManager();
122     }
123
124     public ModuleLocator getModuleLocator() {
125         return context.getModuleManager();
126     }
127
128     public SchemaManager getTypingSchemaManager() {
129         return typingschemamanager;
130     }
131
132     public void setNoForce(boolean noForce) {
133         this.noForce = noForce;
134     }
135
136     // new context stuff
137

138     private void setTypingContext(ArrayList xnodes, QType qtype, LocatedExpression contextLocated, int contextLocatedStepIndex) throws XQueryException {
139         this.contextXNodes = xnodes;
140         this.contextQType = qtype;
141         this.contextLocated = contextLocated;
142         this.contextLocatedStepIndex = contextLocatedStepIndex;
143     }
144
145     // visitors
146

147     // public void visit(AggregateFunctionCall arg) throws XQueryException
148
/*
149     [102] CompAttrConstructor ::= (("attribute" QName "{") | ("attribute" "{" Expr "}" "{")) Expr? "}"
150     
151     The name expression of a computed attribute constructor is processed as follows:
152     
153     Atomization is applied to the value of the name expression. If the result of atomization is not a single atomic value of type xs:QName,
154     xs:string, or xdt:untypedAtomic, a type error is raised.[err:XP0004][err:XP0006]
155     
156     If the atomized value of the name expression is of type xs:QName, that value is used as the name of the constructed attribute.
157     
158     If the atomized value of the name expression is of type xs:string or xdt:untypedAtomic, that value is cast to the type xs:QName using
159     the rules in [XQuery 1.0 and XPath 2.0 Functions and Operators]. The resulting value is used as the name of the constructed attribute.
160     A dynamic error is raised if the cast is not successful.[err:XP0021] In addition, a dynamic error is raised if the URI
161     part of the resulting QName is http://www.w3.org/TR/REC-xml-names.[err:XQ0044]
162     
163     The content expression of a computed attribute constructor is processed as follows:
164     
165     Atomization is applied to the value of the content expression, converting it to a sequence of atomic values.
166     
167     If the result of atomization is an empty sequence, the value of the attribute is the zero-length string.
168     Otherwise, each atomic value in the atomized sequence is cast into a string.
169     If any of these atomic values cannot be cast into a string, a dynamic error [err:XQ0052] is raised.
170     
171     The individual strings resulting from the previous step are merged into a single string by concatenating them
172     with a single space character between each pair. The resulting string is the string value of the attribute.
173     
174     A computed attribute constructor does not perform any automatic validation of the constructed attribute.
175     However, if the computed attribute constructor is inside an element constructor, the attribute will be validated during validation
176     of its parent element. The type annotation of an unvalidated attribute node is xdt:untypedAtomic.
177     */

178     public void visit(AttributeValuePair arg) throws XQueryException {
179         // type checking
180
if (noForce && arg.getQType() != null)
181             return;
182         XQueryExpression attributeName = arg.getAttributeName(); // cannot be null
183
XQueryExpression attributeValue = arg.getAttributeValue(); // cannot be null
184
// forward checking and typing
185
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
186             if (attributeValue.getQType() == null)
187                 return;
188         }
189         if (/*!noForce ||*/
190             attributeValue.getQType() == null)
191             attributeValue.accept(this);
192         // type checking
193
if (attributeValue.getQType() == null)
194             throw new TypeException("Expression " + attributeValue + " could not be typed."); //return;
195

196         QType nameQType = attributeName.getQType();
197         if (nameQType != null && (!nameQType.isQName() || nameQType.isMultiple())) {
198             nameQType = nameQType.applyDATAFunction();
199             if (nameQType == null || !nameQType.isQName() || nameQType.isMultiple())
200                 throw new TypeException("Expression '" + attributeName + "', of attribute value pair has incorrect type.");
201         }
202         QType valueQType = attributeValue.getQType();
203         if (valueQType != null && !valueQType.canBeCastedInto(QType.PRIMITIVE_string) && !valueQType.isString()) {
204             valueQType = valueQType.applyDATAFunction();
205             if (valueQType == null || (!valueQType.canBeCastedInto(QType.PRIMITIVE_string) && !valueQType.isString()))
206                 throw new TypeException("Expression '" + attributeValue + "', of attribute value pair has incorrect type.");
207         }
208         QType attQType = attributeValue.getQType();
209         if (arg.getAttributeName() instanceof QName)
210             arg.setQType(new QTypeAttribute((QName)arg.getAttributeName(), attQType.getSimpleType()));
211         else if (arg.isXmlns())
212             arg.setQType(new QTypeAttribute(new QName(null, null, "xmlns", arg.getParentModule(), null), attQType.getSimpleType()));
213         else if (arg.getAttributeName() instanceof ValueString)
214             arg.setQType(new QTypeAttribute(new QName(null, null, ((ValueString)arg.getAttributeName()).getValue(), arg.getParentModule(), null), attQType.getSimpleType()));
215         else
216             arg.setQType(new QTypeAttribute(new QName("*", "*", "*", arg.getParentModule(), null), attQType.getSimpleType()));
217     }
218
219     public void visit(BinOpANDExpression arg) throws XQueryException {
220         // type checking
221
if (noForce && arg.getQType() != null)
222             return;
223         XQueryExpression expr1 = arg.getExpression1();
224         XQueryExpression expr2 = arg.getExpression2();
225         // forward checking and typing
226
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
227             if (expr1.getQType() == null)
228                 return;
229             if (expr2.getQType() == null)
230                 return;
231         }
232         if (/*!noForce ||*/
233             expr1.getQType() == null)
234             expr1.accept(this);
235         if (/*!noForce ||*/
236             expr2.getQType() == null)
237             expr2.accept(this);
238         // type verification
239
if (expr1.getQType() == null)
240             throw new TypeException("Expression " + expr1 + " could not be typed."); //return;
241
if (expr2.getQType() == null)
242             throw new TypeException("Expression " + expr2 + " could not be typed."); //return;
243
// type setting
244
arg.setQType(new QTypeAtom(context.getSchemaManager().getBooleanType()));
245     }
246
247     public void visit(BinOpORExpression arg) throws XQueryException {
248         XQueryExpression expr1 = arg.getExpression1();
249         XQueryExpression expr2 = arg.getExpression2();
250         // forward checking and typing
251
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
252             if (expr1.getQType() == null)
253                 return;
254             if (expr2.getQType() == null)
255                 return;
256         }
257         if (/*!noForce ||*/
258             expr1.getQType() == null)
259             expr1.accept(this);
260         if (/*!noForce ||*/
261             expr2.getQType() == null)
262             expr2.accept(this);
263         // type verification
264
if (expr1.getQType() == null)
265             throw new TypeException("Expression " + expr1 + " could not be typed."); //return;
266
if (expr2.getQType() == null)
267             throw new TypeException("Expression " + expr2 + " could not be typed."); //return;
268
// type setting
269
arg.setQType(new QTypeAtom(context.getSchemaManager().getBooleanType()));
270     }
271
272     public void visit(CastTreatExpression arg) throws XQueryException {
273         // type checking
274
if (noForce && arg.getQType() != null)
275             return;
276         XQueryExpression expr = arg.getExpression();
277         // forward checking and typing
278
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
279             if (expr.getQType() == null)
280                 return;
281         if (/*!noForce ||*/
282             expr.getQType() == null)
283             expr.accept(this);
284         // type checking
285
if (expr.getQType() == null)
286             throw new TypeException("Expression " + expr + " could not be typed."); //return;
287
// type setting
288
QType qtype = arg.getSequenceType().getQType();
289         arg.setQType(qtype);
290     }
291
292     public void visit(CData arg) throws XQueryException {
293         arg.setQType(new QTypeAtom((SimpleType) getType(SC_STRING)));
294     }
295
296     /*
297     [101] CompNSConstructor ::= ("namespace" NCName "{") Expr "}"
298     
299     A computed namespace constructor (CompNSConstructor) constructs a new namespace node with its own node identity.
300     The immediately enclosing expression of the computed namespace constructor must be a computed element constructor;
301     otherwise a static error is raised.[err:XQ0042] The constructed namespace node is attached to the element node constructed by the enclosing expression.
302     
303     A constructed namespace node is the dynamic equivalent of a namespace declaration attribute.
304     It binds a namespace prefix represented as NCName in the syntax) to a URI and adds the namespace prefix to the in-scope namespaces for its enclosing element.
305     
306     The content expression of a computed namespace constructor is processed as follows:
307     
308     Atomization is applied to the value of the content expression, converting it to a sequence of atomic values.
309     
310     If the result of atomization is an empty sequence, it is replaced by a zero-length string. Otherwise, each atomic value in the atomized sequence is cast into a string.
311     
312     The individual strings resulting from the previous step are merged into a single string by concatenating them with a single space character between each pair.
313     The resulting string becomes the content (URI) of the constructed namespace node.
314     */

315
316     public void visit(ComputedNamespace arg) throws XQueryException {
317         if (noForce && arg.getQType() != null)
318             return;
319         XQueryExpression expr = arg.getExpression();
320         // forward checking and typing
321
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
322             if (expr.getQType() == null)
323                 return;
324         if (/*!noForce ||*/
325             expr.getQType() == null)
326             expr.accept(this);
327         // type checking
328
if (expr.getQType() == null)
329             throw new TypeException("Computed namespace " + arg + " argument could not be typed."); //return;
330
QType valueQType = expr.getQType();
331         if (!valueQType.canBeCastedInto(QType.PRIMITIVE_string) && !valueQType.isString()) {
332             valueQType = valueQType.applyDATAFunction();
333             if (valueQType == null || (!valueQType.canBeCastedInto(QType.PRIMITIVE_string) && !valueQType.isString()))
334                 throw new TypeException("Computed namespace " + arg + " argument has incorrect type.");
335         }
336         // type setting
337
arg.setQType(new QTypeAtom((SimpleType) getType(SC_STRING)));
338     }
339
340     /*
341     [105] CompTextConstructor ::= "text" "{" Expr? "}"
342     
343     All text node constructors are computed constructors. The result of a text node constructor is a new text node, with its own node identity.
344     The content expression of a text node constructor is processed as follows:
345     
346     Atomization is applied to the value of the content expression, converting it to a sequence of atomic values.
347     
348     If the result of atomization is an empty sequence, no text node is constructed. Otherwise, each atomic value in the atomized sequence is cast into a string.
349     
350     The individual strings resulting from the previous step are merged into a single string by concatenating them with a single space character between each pair.
351     The resulting string becomes the content of the constructed text node.
352     */

353
354     public void visit(ComputedText arg) throws XQueryException {
355         if (noForce && arg.getQType() != null)
356             return;
357         XQueryExpression expr = arg.getExpression();
358         // forward checking and typing
359
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
360             if (expr.getQType() == null)
361                 return;
362         if (/*!noForce ||*/
363             expr.getQType() == null)
364             expr.accept(this);
365         // type checking
366
if (expr.getQType() == null)
367             throw new TypeException("Computed text " + arg + " argument could not be typed."); //return;
368
QType valueQType = expr.getQType();
369         if (!valueQType.canBeCastedInto(QType.PRIMITIVE_string) && !valueQType.isString()) {
370             valueQType = valueQType.applyDATAFunction();
371             if (valueQType == null || (!valueQType.canBeCastedInto(QType.PRIMITIVE_string) && !valueQType.isString()))
372                 throw new TypeException("Computed text " + arg + " argument has incorrect type.");
373         }
374         // type setting
375
arg.setQType(new QTypeAtom((SimpleType) getType(SC_STRING)));
376     }
377
378     // public void visit(ContextDeclaration arg) throws XQueryException;
379

380     /*
381     3.7.3.3 Document Node Constructors
382     [99] CompDocConstructor ::= "document" "{" Expr "}"
383     
384     All document node constructors are computed constructors. The result of a document node constructor
385     is a new document node, with its own node identity.
386     
387     The content expression of a document node constructor is processed as follows:
388     
389     For each node returned by the content expression, a new deep copy of the node is constructed,
390     including its children, attributes, and namespace nodes (if any). Each copied node has a new node identity.
391     Copied element nodes are given the type annotation xs:anyType, and copied attribute nodes are given the type annotation xs:anySimpleType.
392     For each adjacent sequence of one or more atomic values returned by the content expression, a new text node is constructed,
393     containing the result of casting each atomic value to a string, with a single blank character inserted between adjacent values.
394     The resulting sequence of nodes is called the content sequence.
395     
396     If the content sequence contains a document, attribute, or namespace node, a type error is raised.[err:XQ0028]
397     
398     The resulting sequence of nodes becomes the children of the new document node.
399     
400     The base URI of a constructed document node is taken from the static context.
401     
402     No schema validation is performed on the constructed document. The [XML 1.0] rules that govern the structure of an XML document
403     (for example, the document node must have exactly one child that is an element node) are not enforced by the XQuery document node constructor.
404     */

405
406     public void visit(Document arg) throws XQueryException {
407         // type checking
408
if (noForce && arg.getQType() != null)
409             return;
410         XQueryExpression expr = arg.getExpression();
411         // forward checking and typing
412
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
413             if (expr.getQType() == null)
414                 return;
415         if (/*!noForce ||*/
416             expr.getQType() == null)
417             expr.accept(this);
418         if (expr.getQType() == null)
419             throw new TypeException("Computed document '" + arg + "', argument could not be typed"); // return;
420
else {
421             if (!expr.getQType().isElement())
422                 throw new TypeException("Computed document '" + arg + "', argument should be an element"); // return;
423
}
424         // type setting
425
arg.setQType(new QTypeDocument(expr.getQType(), QTypeDocument.DOCUMENT_ORIGIN));
426     }
427
428     /*
429     3.7.3.1 Computed Element Constructors
430     [100] CompElemConstructor ::= (("element" QName "{") | ("element" "{" Expr "}" "{")) Expr? "}"
431     
432     The name expression of a computed element constructor is processed as follows:
433     Atomization is applied to the value of the name expression. If the result of atomization is not a single atomic value of type xs:QName, xs:string, or xdt:untypedAtomic, a type error is raised.[err:XP0004][err:XP0006]
434     If the atomized value of the name expression is of type xs:QName, that value is used as the name of the constructed element.
435     If the atomized value of the name expression is of type xs:string or xdt:untypedAtomic, that value is cast to the type xs:QName using the rules in [XQuery 1.0 and XPath 2.0 Functions and Operators].
436     The resulting value is used as the name of the constructed element. A dynamic error is raised if the cast is not successful.[err:XP0021]
437     
438     The content expression of a computed element constructor is processed as follows:
439     For each node returned by the content expression, a new deep copy of the node is constructed, including all its children, attributes, and namespace nodes (if any).
440     Each copied node has a new node identity. Copied element nodes are given the type annotation xs:anyType, and copied attribute nodes are given the type annotation xs:anySimpleType.
441     For each adjacent sequence of one or more atomic values returned by the content expression, a new text node is constructed, containing the result of casting each atomic value to a string, with a single blank character inserted between adjacent values.
442     If any of these atomic values cannot be cast into a string, a dynamic error [err:XQ0052] is raised. The resulting sequence of nodes is called the content sequence.
443     Any sequence of adjacent text nodes in the content sequence is merged into a single text node.
444     If the content sequence contains a document node, a type error is raised.[err:XQ0023]
445     If the content sequence contains a namespace node following a node that is not a namespace node, a type error is raised.[err:XQ0040] Namespace nodes occurring in the content sequence are attached to the constructed element node.
446     If the content sequence contains an attribute node following a node that is not an attribute node or a namespace node, a type error is raised.[err:XQ0024] Attribute nodes occurring in the content sequence become attributes of the new element node.
447     If two or more of these attribute nodes have the same name, an error is raised.[err:XQ0025]
448     Element, text, comment, and processing instruction nodes in the content sequence become the children of the constructed element node.
449     */

450     public void visit(Element arg) throws XQueryException {
451         if (noForce && arg.getQType() != null)
452             return;
453         ArrayList attributes = arg.getAttributes();
454         ArrayList expressions = arg.getSubExpressions();
455         XQueryExpression startTag = arg.getStartTag();
456         // forward type checking
457
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
458             if (attributes != null)
459                 for (int i = 0; i < attributes.size(); i++)
460                     if (((AttributeValuePair) attributes.get(i)).getQType() == null)
461                         return;
462             if (expressions != null)
463                 for (int j = 0; j < expressions.size(); j++)
464                     if (((XQueryExpression) expressions.get(j)).getQType() == null)
465                         return;
466         }
467         if (attributes != null)
468             for (int i = 0; i < attributes.size(); i++)
469                 if (/*!noForce ||*/
470                      ((AttributeValuePair) attributes.get(i)).getQType() == null) {
471                     ((AttributeValuePair) attributes.get(i)).accept(this);
472                     if (((AttributeValuePair) attributes.get(i)).getQType() == null)
473                         throw new TypeException("Expression " + (AttributeValuePair) attributes.get(i) + " could not be typed."); //return;
474
}
475         if (expressions != null)
476             for (int j = 0; j < expressions.size(); j++) {
477                 XQueryExpression exprj = (XQueryExpression) expressions.get(j);
478                 if (/*!noForce ||*/
479                     exprj.getQType() == null) {
480                     exprj.accept(this);
481                     if (exprj.getQType() == null)
482                         throw new TypeException("Expression " + exprj + " could not be typed."); //return;
483
}
484                 if (exprj.getQType().isBoolean()) {
485                     if (exprj instanceof XQueryExpressionSequence)
486                         exprj = (XQueryExpression) ((XQueryExpressionSequence) exprj).getSubExpressions().get(0);
487                     if (!(exprj instanceof LocatedExpression) && !(exprj instanceof Variable))
488                         throw new TypeException("Incorrect boolean typed expression in element " + exprj); //return;
489
}
490             }
491         // type checking
492
QType tagQType = startTag.getQType();
493         if (tagQType != null && (!tagQType.isQName() || tagQType.isMultiple())) {
494             tagQType = tagQType.applyDATAFunction();
495             if (tagQType == null || !tagQType.isQName() || tagQType.isMultiple())
496                 throw new TypeException("Expression '" + startTag + "', of element constructor has incorrect type.");
497         }
498         // type setting
499
Set allElements = new HashSet();
500         if (arg.getAttributes() != null)
501             allElements.addAll(arg.getAttributes());
502         if (arg.getSubExpressions() != null)
503             allElements.addAll(arg.getSubExpressions());
504         arg.setQType(buildQTypeElementFromSubElements(arg.getStartTag(), allElements));
505     }
506
507     public void visit(ExternalVariable arg) throws XQueryException {
508         Variable var = (Variable) arg.getObjectValue();
509         var.accept(this);
510         arg.setQType(var.getQType());
511     }
512
513     public void visit(FLWRExpression arg) throws XQueryException {
514         // type checking
515
if (noForce && arg.getQType() != null)
516             return;
517         ArrayList variables = arg.getVariables();
518         XQueryExpression whereClause = arg.getWhereClause();
519         XQueryExpression returnClause = arg.getReturnClause();
520         // forward type checking
521
boolean multiple = false;
522         for (int i = 0; i < variables.size(); i++) {
523             Variable vari = (Variable) variables.get(i);
524             if (/*!noForce ||*/
525                 vari.getQType() == null)
526                 vari.accept(this);
527             if (!multiple)
528                 if (vari.getBindingType() == Constants.FOR_BINDINGTYPE && vari.getExpression().getQType().isMultiple())
529                     multiple = true;
530
531         }
532         if (whereClause != null && (/*!noForce ||*/
533             whereClause.getQType() == null))
534             whereClause.accept(this);
535         if (/*!noForce ||*/
536             returnClause.getQType() == null)
537             returnClause.accept(this);
538         // type verification
539
if (returnClause.getQType() == null)
540             throw new TypeException("Incorrect 'return' clause : [ " + returnClause + " ], it could not be typed.");
541         if (whereClause != null && whereClause.getQType() == null)
542             throw new TypeException("Incorrect 'where' clause : [ " + whereClause + " ], it could not be typed.");
543         // verify sort clause typing
544
if (arg.getOrderBy() != null) {
545             for (int i = 0; i < arg.getOrderBy().size(); i++) {
546                 XQueryExpression sortiexpr = (XQueryExpression) arg.getOrderBy().get(i);
547                 if (sortiexpr.getOrder(0) != Constants.PLACE_ORDER) {
548                     QType qtypei = sortiexpr.getQType();
549                     if (qtypei == null || !qtypei.isAtomic() || qtypei.isMultiple())
550                         throw new TypeException("Invalid order by clause : " + sortiexpr);
551                 }
552             }
553         }
554         // type setting
555
arg.setQType((QType) arg.getReturnClause().getQType().changeOccurence(multiple ? QType.OCC_0_N : QType.OCC_1_1));
556     }
557
558     // public void visit(FunctionCall arg) throws XQueryException;
559

560     public void visit(FunctionDeclaration arg) throws XQueryException {
561         // type checking
562
if (noForce && arg.getQType() != null)
563             return;
564         // ArrayList expressions = arg.getExpressions();
565
SequenceType returnType = arg.getReturnType();
566         // forward type checking --> cannot be done because of variables not binded in parameters
567
// type setting
568
QType qtype = null;
569         // TODO verify that retrun type and calculated type are compatible
570
if (returnType == null) {
571             if (arg.getExpressions() != null) {
572                 ArrayList types = new ArrayList(arg.getExpressions().size());
573                 for (int i = 0; i < arg.getExpressions().size(); i++) {
574                     XQueryExpression expri = (XQueryExpression) arg.getExpressions().get(i);
575                     if (expri.getQType() != null)
576                         types.add(expri.getQType());
577                     else
578                         types = null;
579                 }
580                 if (types != null) {
581                     if (types.size() == 1)
582                         qtype = (QType) types.get(0);
583                     else
584                         qtype = new QTypeSequence(types);
585                 }
586             }
587             if (qtype == null) {
588                 SimpleType type = context.getSchemaManager().getAnySimpleType();
589                 //type.setPrimitive(PrimitiveType.createType(SC_ANYSIMPLETYPE));
590
ArrayList list = new ArrayList(3);
591                 list.add(new QTypeAtom(type));
592                 list.add(new QTypeAttribute(new QName("*", "*", "*", arg.getParentModule(), null), type));
593                 list.add(new QTypeElement(new QName("*", "*", "*", arg.getParentModule(), null), getType(SC_ANYTYPE)));
594                 qtype = new QTypeUnion(list, QType.OCC_0_N);
595             }
596         } else {
597             qtype = returnType.getQType();
598         }
599         arg.setQType(qtype);
600     }
601
602     // public void visit(InstanceOfExpression arg) throws XQueryException;
603

604     public void visit(InternalFunctionCall arg) throws XQueryException {
605         SimpleType type = context.getSchemaManager().getAnySimpleType();
606         ArrayList list = new ArrayList(3);
607         list.add(new QTypeAtom(type));
608         list.add(new QTypeAttribute(new QName("*", "*", "*", arg.getParentModule(), null), type));
609         list.add(new QTypeElement(new QName("*", "*", "*", arg.getParentModule(), null), getType(SC_ANYTYPE)));
610         QType qtype = new QTypeUnion(list, QType.OCC_0_N);
611         arg.setQType(qtype);
612     }
613
614     public void visit(ITEExpression arg) throws XQueryException {
615         if (noForce && arg.getQType() != null)
616             return;
617         XQueryExpression ifExpression = arg.getThenExpression();
618         XQueryExpression thenExpression = arg.getThenExpression();
619         XQueryExpression elseExpression = arg.getElseExpression();
620         // forward type checking
621
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
622             if (ifExpression.getQType() == null)
623                 return;
624             if (thenExpression.getQType() == null && !(thenExpression instanceof XQueryVoid))
625                 return;
626             if (elseExpression.getQType() == null && !(elseExpression instanceof XQueryVoid))
627                 return;
628         }
629         if (/*!noForce ||*/
630             ifExpression.getQType() == null)
631             ifExpression.accept(this);
632         if ((/*!noForce ||*/
633             thenExpression.getQType() == null) && !(thenExpression instanceof XQueryVoid))
634             thenExpression.accept(this);
635         if ((/*!noForce ||*/
636             elseExpression.getQType() == null) && !(elseExpression instanceof XQueryVoid))
637             elseExpression.accept(this);
638         // type checking
639
if (ifExpression.getQType() == null)
640             throw new TypeException("Expression " + ifExpression + " could not be typed."); //return;
641
if (thenExpression.getQType() == null && !(thenExpression instanceof XQueryVoid))
642             throw new TypeException("Expression " + thenExpression + " could not be typed."); //return;
643
if (elseExpression.getQType() == null && !(elseExpression instanceof XQueryVoid))
644             throw new TypeException("Expression " + elseExpression + " could not be typed."); //return;
645
// type setting
646
ArrayList tmpList = new ArrayList(2);
647         tmpList.add(thenExpression.getQType());
648         tmpList.add(elseExpression.getQType());
649         arg.setQType(makeUnion(tmpList));
650     }
651
652     /*
653     [127] ItemType ::= AtomicType | KindTest | ("item" "(" ")")
654     [126] AtomicType ::= QName
655     [128] KindTest ::= DocumentTest | ElementTest | AttributeTest | PITest | CommentTest | TextTest | AnyKindTest
656     */

657     /*
658     QNames appearing in a SequenceType have their prefixes expanded to namespace URIs by means of the in-scope namespaces and the default element/type namespace.
659     It is a static error [err:XP0008] to use a TypeName in an ElementTest or AttributeTest if that name is not found in the in-scope type definitions.
660     It is a static error [err:XP0008] to use an ElementName in an ElementTest if that name is not found in the in-scope element definitions unless a TypeNameOrWildcard is specified.
661     It is a static error [err:XP0008] to use a (SchemaContextPath ElementName) pair in an ElementTest if the ElementName can not be located from the in-scope element definitions using the SchemaContextPath.
662     It is a static error [err:XP0008] to use an AttributeName in an AttributeTest if that name is not found in the in-scope attribute definitions unless a TypeNameOrWildcard is specified.
663     It is a static error [err:XP0008] to use a (SchemaContextPath AttributeName) pair in an AttributeTest if the AttributeName can not be located from the in-scope attribute definitions using the SchemaContextPath.
664     If a QName that is used as an AtomicType is not defined as an atomic type in the in-scope type definitions, a static error is raised. [err:XP0051]
665     
666     Here are some examples of SequenceTypes that might be used in XQuery expressions:
667     xs:date refers to the built-in Schema type date
668     attribute()? refers to an optional attribute
669     element() refers to any element
670     element(po:shipto, po:address) refers to an element that has the name po:shipto (or is in the substitution group of that element), and has the type annotation po:address (or a subtype of that type)
671     element(po:shipto, *) refers to an element named po:shipto (or in the substitution group of po:shipto), with no restrictions on its type
672     element(*, po:address) refers to an element of any name that has the type annotation po:address (or a subtype of po:address). If the keyword nillable were used following po:address, that would indicate that the element may have empty content and the attribute xsi:nil="true", even though the declaration of the type po:address has required content.
673     node()* refers to a sequence of zero or more nodes of any type
674     item()+ refers to a sequence of one or more nodes or atomic values
675     */

676     public void visit(ItemType arg) throws XQueryException {
677         XQueryExpression expr = arg.getExpression();
678         QType qtype = null;
679         if (expr == null) {
680             ArrayList list = new ArrayList(7);
681             list.add(new QTypeAtom(context.getSchemaManager().getAnySimpleType()));
682             list.add(new QTypeDocument(null, QTypeDocument.ANY_ORIGIN));
683             list.add(new QTypeProcessingInstruction());
684             list.add(new QTypeComment());
685             list.add(new QTypeText((SimpleType) getType(SC_STRING)));
686             list.add(new QTypeElement(new QName("*", null), getType(SC_ANYTYPE)));
687             list.add(new QTypeAttribute(new QName("*", null), context.getSchemaManager().getAnySimpleType()));
688             qtype = new QTypeUnion(list);
689         } else if (expr instanceof QName) {
690             QName qname = (QName) expr;
691             Type st = null;
692             if (qname.getPrefixName() != null && qname.getPrefixName().equals("xs") && qname.getLocalName().equals("anySimpleType")) {
693                 st = context.getSchemaManager().getAnySimpleType();
694             } else {
695                 // generate QTypeAtom
696
st = context.getSchemaManager().getType(((QName) expr).getNameSpace(), ((QName) expr).getLocalName());
697             }
698             if (st != null && st instanceof SimpleType)
699                 qtype = new QTypeAtom((SimpleType) st);
700             else
701                 throw new TypeException("Expression " + expr + " is not a valid atomic type.");
702         } else if (expr instanceof NodeTest) {
703             NodeTest nodeType = (NodeTest) expr;
704             XQueryExpression ex = nodeType.getArg();
705             int kind = nodeType.getKind();
706             switch (kind) {
707                 case NodeKind.DOCUMENT :
708                     qtype = new QTypeDocument((ex == null) ? null : ex.getQType(), QTypeDocument.ANY_ORIGIN);
709                     break;
710                 case NodeKind.PI :
711                     qtype = new QTypeProcessingInstruction();
712                     break;
713                 case NodeKind.COMMENT :
714                     qtype = new QTypeComment();
715                     break;
716                 case NodeKind.TEXT :
717                     qtype = new QTypeText((SimpleType) getType(SC_STRING));
718                     break;
719                 case NodeKind.NODE :
720                     ArrayList list = new ArrayList(6);
721                     list.add(new QTypeDocument(null, QTypeDocument.ANY_ORIGIN));
722                     list.add(new QTypeProcessingInstruction());
723                     list.add(new QTypeComment());
724                     list.add(new QTypeText((SimpleType) getType(SC_STRING)));
725                     list.add(new QTypeElement(new QName("*", null), getType(SC_ANYTYPE)));
726                     list.add(new QTypeAttribute(new QName("*", null), context.getSchemaManager().getAnySimpleType()));
727                     qtype = new QTypeUnion(list);
728                     break;
729             }
730         } else if (expr instanceof ElementTest || expr instanceof AttributeTest) {
731             qtype = expr.getQType();
732         }
733         arg.setQType(qtype);
734     }
735
736     public void visit(ElementTest arg) throws XQueryException {
737         SchemaContextPath scp = arg.getSchemaContextPath();
738         if (scp != null) {
739             arg.setQType(getQTypeFromDeclaration(computeDeclFromPath(scp), QType.OCC_1_1));
740         } else {
741             Type type = null;
742             QName typeQName = arg.getTypeQName();
743             if (typeQName != null) {
744                 type = context.getSchemaManager().getType(typeQName.getNameSpace(), typeQName.getLocalName());
745                 if (type == null)
746                     throw new TypeException("Could not type ElementTest '" + arg + "' .");
747             }
748             if (arg.getDeclQName() == null || arg.getDeclQName().equals("*")) {
749                 if (type == null)
750                     type = getType(SC_ANYTYPE);
751                 arg.setQType(new QTypeElement(new QName("*", null), type));
752             } else {
753                 QName eltQName = arg.getDeclQName();
754                 ElementDeclaration eltDecl = context.getSchemaManager().getElementDeclaration(eltQName.getNameSpace(), eltQName.getLocalName());
755                 if (eltDecl == null)
756                     throw new TypeException("Could not type ElementTest '" + arg + "' .");
757                 // verifying type is compatible
758
if (type == null) {
759                     type = eltDecl.getType();
760                 } else if (eltDecl.getType() != type && !eltDecl.getType().isDerivedFrom(type))
761                     throw new TypeException("Could not type ElementTest '" + arg + "' .");
762                 arg.setQType(new QTypeElement(eltQName, eltDecl, type));
763             }
764         }
765     }
766
767     public void visit(AttributeTest arg) throws XQueryException {
768         SchemaContextPath scp = arg.getSchemaContextPath();
769         if (scp != null) {
770             arg.setQType(getQTypeFromDeclaration(computeDeclFromPath(scp), QType.OCC_1_1));
771         } else {
772             SimpleType stype = null;
773             QName typeQName = arg.getTypeQName();
774             if (typeQName != null) {
775                 Type type = context.getSchemaManager().getType(typeQName.getNameSpace(), typeQName.getLocalName());
776                 if (type == null || !(type instanceof SimpleType))
777                     throw new TypeException("Could not type AttributeTest '" + arg + "' .");
778                 stype = (SimpleType) type;
779             }
780             if (arg.getDeclQName() == null || arg.getDeclQName().equals("*")) {
781                 if (stype == null)
782                     stype = context.getSchemaManager().getAnySimpleType();
783                 arg.setQType(new QTypeAttribute(new QName("*", null), stype));
784             } else {
785                 QName qname = arg.getDeclQName();
786                 AttributeDeclaration attDecl = context.getSchemaManager().getAttributeDeclaration(qname.getNameSpace(), qname.getLocalName());
787                 if (attDecl == null)
788                     throw new TypeException("Could not type AttributeTest '" + arg + "' .");
789                 // verifying type is compatible
790
if (stype == null) {
791                     stype = attDecl.getType().getValueType();
792                 } else if (attDecl.getType() != stype && !attDecl.getType().isDerivedFrom(stype))
793                     throw new TypeException("Could not type AttributeTest '" + arg + "' .");
794                 arg.setQType(new QTypeAttribute(qname, attDecl, stype));
795             }
796         }
797     }
798
799     public void visit(LibraryFunctionCall arg) throws XQueryException {
800         // type checking
801
if (noForce && arg.getQType() != null)
802             return;
803         FunctionDeclaration funcdef = arg.getFunctionDefinition(); // cannot be null
804
// forward type checking
805
if (funcdef.getQType() == null)
806             funcdef.accept(this);
807         // type setting
808
arg.setQType(funcdef.getQType());
809     }
810
811     public void visit(ListOpAFTERExpression arg) throws XQueryException {
812         // type checking
813
if (noForce && arg.getQType() != null)
814             return;
815         // TYPE BUILDING
816
// the type returned is a sequence of elements that have the first sequence type
817

818         XQueryExpression expr1 = arg.getExpression1();
819         XQueryExpression expr2 = arg.getExpression2();
820         // forward checking and typing
821
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
822             if (expr1.getQType() == null)
823                 return;
824             if (expr2.getQType() == null)
825                 return;
826         }
827         if (/*!noForce ||*/
828             expr1.getQType() == null)
829             expr1.accept(this);
830         if (/*!noForce ||*/
831             expr2.getQType() == null)
832             expr2.accept(this);
833         // type verification
834
if (expr1.getQType() == null)
835             throw new TypeException("Expression " + expr1 + " could not be typed."); //return;
836
if (expr2.getQType() == null)
837             throw new TypeException("Expression " + expr2 + " could not be typed."); //return;
838
if (!expr1.getQType().isNode() || !expr2.getQType().isNode())
839             throw new TypeException("Expression '" + arg + "', at least one of the operands must be a node or collection of node.");
840         // type setting
841
arg.setQType(expr1.getQType());
842     }
843
844     /*
845     An arithmetic expression is evaluated by applying the following rules, in order, until an error is raised or a value is computed:
846     
847     Atomization is applied to each operand.
848     If either operand is now an empty sequence, the result of the operation is an empty sequence.
849     If either operand is now a sequence of length greater than one, a type error is raised.[err:XP0006]
850     If either operand is now of type xdt:untypedAtomic, it is cast to the default type for the given operator.
851     The default type for the idiv operator is xs:integer; the default type for all other arithmetic operators is xs:double.
852     If the cast fails, a dynamic error is raised.[err:XP0021]
853     If the operand types are now valid for the given operator, the operator is applied to the operands, resulting in an atomic value or a dynamic error (for example, an error might result from dividing by zero.)
854     The combinations of atomic types that are accepted by the various arithmetic operators, and their respective result types, are listed in B.2
855     Operator Mapping together with the functions in [XQuery 1.0 and XPath 2.0 Functions and Operators] that define the semantics of the operation for each type.
856     
857     If the operand types are still not valid for the given operator, a type error is raised.
858     
859     XQuery supports two division operators named div and idiv. When invoked with two integer operands, div returns a value of type xs:decimal, but idiv returns a value of type xs:integer.
860     */

861     /*
862      The following functions define the semantics of operators defined in [XQuery 1.0: An XML Query Language] and [XPath 2.0] on these numeric types.
863     Operators Meaning
864     op:numeric-add Addition
865     op:numeric-subtract Subtraction
866     op:numeric-multiply Multiplication
867     op:numeric-divide Division
868     op:numeric-integer-divide Integer division
869     op:numeric-mod Modulus
870     op:numeric-unary-plus Unary plus
871     op:numeric-unary-minus Unary minus (negation)
872     
873     The parameters and return types for the above operators are the basic numeric types: xs:integer, xs:decimal, xs:float and xs:double,
874     and types derived from them. The word "numeric" in function signatures signifies these four types.
875     For simplicity, each operator is defined to operate on operands of the same type and to return the same type.
876     The one exception is op:numeric-divide, which returns an xs:decimal if called with two xs:integer operands.)
877     
878     Operands of type xdt:untypedAtomic are converted to xs:double, except for arguments to 6.2.5 op:numeric-integer-divide which are converted to xs:integer.
879     If the two operands are not of the same type, subtype substitution and type promotion are used to obtain two operands of the same type.
880     Section B.1 Type PromotionXQ describes the semantics of these operations in detail.
881     
882     Subtype substitution: A derived type may substitute for its base type. In particular, xs:integer may be used where xs:decimal is expected.
883     
884     Type promotion: xs:decimal may be promoted to xs:float, and xs:float may be promoted to xs:double.
885     
886     The result type of operations depends on their argument datatypes and is defined in the following table:
887     
888     Operator Returns
889     op:operation(xs:integer, xs:integer) xs:integer (except for op:numeric-divide(integer, integer), which returns xs:decimal)
890     op:operation(xs:decimal, xs:decimal) xs:decimal
891     op:operation(xs:float, xs:float) xs:float
892     op:operation(xs:double, xs:double) xs:double
893     op:operation(xs:integer) xs:integer
894     op:operation(xs:decimal) xs:decimal
895     op:operation(xs:float) xs:float
896     op:operation(xs:double) xs:double
897     
898     */

899
900     public void visit(ListOpArithExpression arg) throws XQueryException {
901         // type checking
902
if (noForce && arg.getQType() != null)
903             return;
904         XQueryExpression expr1 = arg.getExpression1();
905         XQueryExpression expr2 = arg.getExpression2();
906         // forward checking and typing
907
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
908             if (expr1.getQType() == null)
909                 return;
910             if (expr2.getQType() == null)
911                 return;
912         }
913         if (/*!noForce ||*/
914             expr1.getQType() == null)
915             expr1.accept(this);
916         if (/*!noForce ||*/
917             expr2.getQType() == null)
918             expr2.accept(this);
919         // type verification
920
QType qtype1 = expr1.getQType();
921         QType qtype2 = expr2.getQType();
922         if (qtype1 == null)
923             throw new TypeException("Expression " + expr1 + " could not be typed."); //return;
924
if (qtype2 == null)
925             throw new TypeException("Expression " + expr2 + " could not be typed."); //return;
926
if (!qtype1.isAtomic())
927             qtype1 = qtype1.applyDATAFunction();
928         if (!qtype2.isAtomic())
929             qtype2 = qtype2.applyDATAFunction();
930         if (qtype1 == null || (!qtype1.isAtomic() /*&& !inPredicate*/))
931             throw new TypeException("Expression '" + arg + "', first operand is not an atomic value.");
932         if (qtype2 == null || (!qtype2.isAtomic() /*&& !inPredicate*/))
933             throw new TypeException("Expression '" + arg + "', second operand is not an atomic value.");
934         if (!qtype1.isNumeric())
935             throw new TypeException("Expression '" + arg + "', first operand is not numeric.");
936         if (!qtype2.isNumeric())
937             throw new TypeException("Expression '" + arg + "', second operand is not numeric.");
938         // type setting
939
int primType1 = ((SimpleType) qtype1.getType()).getPrimitive().getType();
940         int primType2 = ((SimpleType) qtype2.getType()).getPrimitive().getType();
941         if (primType1 == PrimitiveType.DOUBLE || primType2 == PrimitiveType.DOUBLE)
942             arg.setQType(new QTypeAtom((SimpleType) getType(SC_DOUBLE), (expr1.getQType().isMultiple() || expr2.getQType().isMultiple()) ? QType.OCC_0_N : QType.OCC_1_1));
943         else if (primType1 == PrimitiveType.FLOAT || primType2 == PrimitiveType.FLOAT)
944             arg.setQType(new QTypeAtom((SimpleType) getType(SC_FLOAT), (expr1.getQType().isMultiple() || expr2.getQType().isMultiple()) ? QType.OCC_0_N : QType.OCC_1_1));
945         else if (primType1 == PrimitiveType.DECIMAL || primType2 == PrimitiveType.DECIMAL)
946             arg.setQType(new QTypeAtom((SimpleType) getType(SC_DECIMAL), (expr1.getQType().isMultiple() || expr2.getQType().isMultiple()) ? QType.OCC_0_N : QType.OCC_1_1));
947         else
948             arg.setQType(new QTypeAtom((SimpleType) getType(SC_INTEGER), (expr1.getQType().isMultiple() || expr2.getQType().isMultiple()) ? QType.OCC_0_N : QType.OCC_1_1));
949     }
950
951     public void visit(ListOpBEFOREExpression arg) throws XQueryException {
952         // type checking
953
if (noForce && arg.getQType() != null)
954             return;
955         XQueryExpression expr1 = arg.getExpression1();
956         XQueryExpression expr2 = arg.getExpression2();
957         // forward checking and typing
958
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
959             if (expr1.getQType() == null)
960                 return;
961             if (expr2.getQType() == null)
962                 return;
963         }
964         if (/*!noForce ||*/
965             expr1.getQType() == null)
966             expr1.accept(this);
967         if (/*!noForce ||*/
968             expr2.getQType() == null)
969             expr2.accept(this);
970         // type verification
971
if (expr1.getQType() == null)
972             throw new TypeException("Expression " + expr1 + " could not be typed."); //return;
973
if (expr2.getQType() == null)
974             throw new TypeException("Expression " + expr2 + " could not be typed."); //return;
975
if (!expr1.getQType().isNode() || !expr2.getQType().isNode())
976             throw new TypeException("Expression '" + arg + "', at least one of the operands must be a node or collection of node.");
977         // type setting
978
arg.setQType(expr1.getQType());
979     }
980
981     public void visit(ListOpCompExpression arg) throws XQueryException {
982         // TYPE VERIFICATION
983
// both expressions must be sequences of elements of the same document
984
// TYPE BUILDING
985
// The =, !=, <, <=, >, and >= operators perform value comparisons.
986
// If both operands are simple values of the same type, the result is straightforward.
987
// If the operands are simple values of compatible types, the operand of the less-inclusive type is converted to the more-inclusive type for the purpose of comparison (for example, an integer might be converted to a float in order to be compared with a float.)
988
// If one operand is a node and the other is a simple value, the content of the node is extracted by an implicit invocation of the data function before the comparison is performed.
989
// If both operands are nodes, the string-values of the nodes are compared, as defined in [XPath 1.0].
990

991         if (noForce && arg.getQType() != null)
992             return;
993         //arg.setQType(new QTypeAtom((SimpleType) getType(SC_BOOLEAN)));
994

995         XQueryExpression expr1 = arg.getExpression1();
996         XQueryExpression expr2 = arg.getExpression2();
997         // forward checking and typing
998
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
999             if (expr1.getQType() == null)
1000                return;
1001            if (expr2.getQType() == null)
1002                return;
1003        }
1004        if (/*!noForce ||*/
1005            expr1.getQType() == null)
1006            expr1.accept(this);
1007        if (/*!noForce ||*/
1008            expr2.getQType() == null)
1009            expr2.accept(this);
1010        // type checking
1011
QType qtype1 = expr1.getQType();
1012        QType qtype2 = expr2.getQType();
1013        if (qtype1 == null)
1014            throw new TypeException("Expression " + expr1 + " could not be typed."); //return;
1015
if (qtype2 == null)
1016            throw new TypeException("Expression " + expr2 + " could not be typed."); //return;
1017
if (qtype1 != null && qtype2 != null) {
1018            if (!qtype1.isAtom())
1019                qtype1 = qtype1.applyDATAFunction();
1020            if (!qtype2.isAtom())
1021                qtype2 = qtype2.applyDATAFunction();
1022            // test for value comp
1023
if (arg.getOperator() >= Constants.EQ_VALUECOMP && arg.getOperator() <= Constants.NE_VALUECOMP) {
1024                // verify occurence is one
1025
if (qtype1.getOccurence() != QType.OCC_0_1 && qtype1.getOccurence() != QType.OCC_1_1)
1026                    throw new TypeException("Expression " + expr1 + " has wrong occurence.");
1027                if (qtype2.getOccurence() != QType.OCC_0_1 && qtype2.getOccurence() != QType.OCC_1_1)
1028                    throw new TypeException("Expression " + expr2 + " has wrong occurence.");
1029            }
1030            // if (!(qtype1.isNumeric() && qtype2.isNumeric()) && !(qtype1.canBeComparedTo(qtype2)))
1031
if (qtype1 == null || !(qtype1.canBeComparedTo(qtype2)))
1032                throw new TypeException("Could not compare types of expression --> " + arg);
1033        }
1034        // type setting
1035
arg.setQType(new QTypeAtom((SimpleType) getType(SC_BOOLEAN)));
1036    }
1037
1038    public void visit(ListOpEXCEPTExpression arg) throws XQueryException {
1039        // type checking
1040
if (noForce && arg.getQType() != null)
1041            return;
1042        XQueryExpression expr1 = arg.getExpression1();
1043        XQueryExpression expr2 = arg.getExpression2();
1044        // forward checking and typing
1045
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
1046            if (expr1.getQType() == null)
1047                return;
1048            if (expr2.getQType() == null)
1049                return;
1050        }
1051        if (/*!noForce ||*/
1052            expr1.getQType() == null)
1053            expr1.accept(this);
1054        if (/*!noForce ||*/
1055            expr2.getQType() == null)
1056            expr2.accept(this);
1057        // type verification
1058
if (expr1.getQType() == null)
1059            throw new TypeException("Expression " + expr1 + " could not be typed."); //return;
1060
if (expr2.getQType() == null)
1061            throw new TypeException("Expression " + expr2 + " could not be typed."); //return;
1062
// type setting
1063
arg.setQType(expr1.getQType());
1064    }
1065
1066    public void visit(ListOpINTERSECTExpression arg) throws XQueryException {
1067        // type checking
1068
if (noForce && arg.getQType() != null)
1069            return;
1070        XQueryExpression expr1 = arg.getExpression1();
1071        XQueryExpression expr2 = arg.getExpression2();
1072        // forward checking and typing
1073
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
1074            if (expr1.getQType() == null)
1075                return;
1076            if (expr2.getQType() == null)
1077                return;
1078        }
1079        if (/*!noForce ||*/
1080            expr1.getQType() == null)
1081            expr1.accept(this);
1082        if (/*!noForce ||*/
1083            expr2.getQType() == null)
1084            expr2.accept(this);
1085        // type verification
1086
if (expr1.getQType() == null)
1087            throw new TypeException("Expression " + expr1 + " could not be typed."); //return;
1088
if (expr2.getQType() == null)
1089            throw new TypeException("Expression " + expr2 + " could not be typed."); //return;
1090
// type setting
1091
arg.setQType(expr1.getQType());
1092    }
1093
1094    public void visit(ListOpUNIONExpression arg) throws XQueryException {
1095        // type checking
1096
if (noForce && arg.getQType() != null)
1097            return;
1098        XQueryExpression expr1 = arg.getExpression1();
1099        XQueryExpression expr2 = arg.getExpression2();
1100        // forward checking and typing
1101
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
1102            if (expr1.getQType() == null)
1103                return;
1104            if (expr2.getQType() == null)
1105                return;
1106        }
1107        if (/*!noForce ||*/
1108            expr1.getQType() == null)
1109            expr1.accept(this);
1110        if (/*!noForce ||*/
1111            expr2.getQType() == null)
1112            expr2.accept(this);
1113        // type verification
1114
if (expr1.getQType() == null)
1115            throw new TypeException("Expression " + expr1 + " could not be typed."); //return;
1116
if (expr2.getQType() == null)
1117            throw new TypeException("Expression " + expr2 + " could not be typed."); //return;
1118
// type setting
1119
ArrayList list = new ArrayList();
1120        list.add(expr1.getQType());
1121        list.add(expr2.getQType());
1122        arg.setQType(new QTypeUnion(list));
1123    }
1124
1125    public void visit(LocatedExpression arg) throws XQueryException {
1126        ArrayList steps = arg.getSteps();
1127        // checking force stuff
1128
if (noForce) {
1129            boolean alltyped = true;
1130            for (int i = 0; i < steps.size(); i++) {
1131                Step stepi = (Step) steps.get(i);
1132                if (stepi.getQType() == null || stepi.getAxis() == Axis.DESCENDANT || stepi.getAxis() == Axis.DESCENDANT_OR_SELF) {
1133                    alltyped = false;
1134                    break;
1135                }
1136            }
1137            // try to simplify if all steps have qtype
1138
if (alltyped) {
1139                arg.setQType(arg.getStepNum(steps.size() - 1).getQType());
1140                arg.setXTrees(arg.getStepNum(steps.size() - 1).getXTrees());
1141                return;
1142            }
1143        } else {
1144            arg.setQType(null);
1145            arg.setXTrees(null);
1146        }
1147
1148        // look for simple paths to be typed only with their context
1149
boolean simplePath = arg.isRelative();
1150
1151        // remember the current context
1152
ArrayList tmpContextXNodes = null;
1153        QType tmpContextQType = null;
1154        LocatedExpression tmpContextLocated = null;
1155        int tmpContextLocatedStepIndex = -1;
1156        // for simple paths chek context and set current context
1157
if (simplePath) {
1158            if (arg.getStepNum(0).getAxis() == Axis.NONE)
1159                arg.getStepNum(0).setAxis(Axis.CHILD);
1160            if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
1161                /*
1162                if (arg.getInPredicate())
1163                    return;
1164                else
1165                    throw new TypeException(arg + " could not be typed because context does not exist.");
1166                */

1167                return;
1168            }
1169            tmpContextXNodes = contextXNodes;
1170            tmpContextQType = contextQType;
1171            tmpContextLocated = contextLocated;
1172            tmpContextLocatedStepIndex = contextLocatedStepIndex;
1173            arg.setContext(true);
1174        }
1175        // if not simple path set current context anyway
1176
else {
1177            if (contextXNodes != null || contextQType != null) {
1178                tmpContextXNodes = contextXNodes;
1179                tmpContextQType = contextQType;
1180                tmpContextLocated = contextLocated;
1181                tmpContextLocatedStepIndex = contextLocatedStepIndex;
1182                contextXNodes = null;
1183                contextQType = null;
1184                tmpContextLocated = null;
1185                contextLocatedStepIndex = -1;
1186            }
1187        }
1188
1189        // forward checking and typing
1190

1191        byte occurence = QType.OCC_1_1;
1192
1193        boolean done = false;
1194        QType qtype = null;
1195        Step stepi = null;
1196
1197        for (int i = 0; i < steps.size(); i++) {
1198            // initialisation
1199
qtype = null;
1200            done = false;
1201            stepi = (Step) steps.get(i);
1202            XQueryExpression stepiExpr = stepi.getExpression();
1203
1204            // test to set the contextType for the first step
1205
if (i == 0 && contextType == QTypeDocument.ANY_ORIGIN) {
1206                if (stepiExpr.getQType() instanceof QTypeDocument && ((QTypeDocument) stepiExpr.getQType()).isFromDocument())
1207                    contextType = QTypeDocument.DOCUMENT_ORIGIN;
1208                else
1209                    contextType = QTypeDocument.COLLECTION_ORIGIN;
1210            }
1211
1212            // test for existing information
1213
if (noForce) {
1214                if (i == 0 && stepi.getQType() != null) {
1215                    contextXNodes = stepi.getXTrees();
1216                    contextQType = stepi.getQType();
1217                    qtype = stepi.getQType();
1218                    done = true;
1219                }
1220            } else {
1221                stepi.setQType(null);
1222                stepi.setXTrees(null);
1223            }
1224
1225            // handle special case of first step
1226
if (!done) {
1227                if (i == 0 && stepi.getAxis() == Axis.NONE) {
1228                    qtype = stepiExpr.getQType();
1229                    if (noForce && qtype != null) {
1230                        stepi.setXTrees(stepiExpr.getXTrees());
1231                        done = true;
1232                    }
1233                }
1234            }
1235
1236            // handle special case of step expression being a ListOpUNIONExpression
1237
if (!done && stepiExpr instanceof ListOpUNIONExpression) {
1238                this.setTypingContext(contextXNodes, contextQType, arg, i - 1);
1239                stepiExpr.accept(this);
1240                qtype = stepiExpr.getQType();
1241                if (qtype != null) {
1242                    stepi.setXTrees(stepiExpr.getXTrees());
1243                    done = true;
1244                }
1245            }
1246
1247            // special treatment to avoid bug on navigation (does not navigate on text nodes)
1248
boolean doNodes = true;
1249            boolean isTextNode = false;
1250            if (!done && stepiExpr instanceof NodeTest) {
1251                if (((NodeTest) stepiExpr).getKind() == NodeKind.TEXT) {
1252                    isTextNode = true;
1253                    doNodes = false;
1254                } else if (((NodeTest) stepiExpr).getKind() == NodeKind.NODE)
1255                    doNodes = false;
1256            }
1257
1258            // get next step type
1259
if (!done && doNodes && contextXNodes != null) {
1260                ArrayList xnodes = context.resolveXPath(contextXNodes, stepi);
1261                if (xnodes != null) {
1262                    qtype = this.buildQTypeFromXNodes(xnodes, occurence);
1263                    if (qtype != null) {
1264                        stepi.setXTrees(xnodes);
1265                        done = true;
1266                    }
1267                }
1268            }
1269            // get next step type if it could not be resolved with pathresolver
1270
if (!done && contextQType != null) {
1271                qtype = context.resolveQType(contextType, contextQType, stepi, inPredicate);
1272                if (qtype != null) {
1273                    if (isTextNode)
1274                        stepi.setXTrees(contextXNodes);
1275                    else
1276                        stepi.setXTrees(null);
1277                    done = true;
1278                }
1279
1280            }
1281
1282            // verification of type and collection setting
1283
if (done) {
1284                occurence = qtype.getOccurence();
1285            } else {
1286                // change LARS 22/09/2003
1287
if (stepi.getAxis() == Axis.PARENT) {
1288                    if (arg.startsWithVariable() || (arg.getParentExpression() != null && !arg.getParentExpression().isEmpty() && arg.getParentExpression().get(0) instanceof ListOpUNIONExpression)) {
1289                        // add LARS 22/09/2003
1290
// special code to be able to type parent::node when root expression is variable
1291
XQueryExpression tmpExpr = arg;
1292                        XQueryExpression firstExpr = arg.getStepNum(0).getExpression();
1293                        ArrayList stepList = new ArrayList();
1294                        int stepIndex = -1;
1295                        try {
1296                            while (true) {
1297                                if (tmpExpr instanceof LocatedExpression) {
1298                                    LocatedExpression tmpLoc = (LocatedExpression) tmpExpr;
1299
1300                                    if (stepIndex == -1)
1301                                        stepIndex = tmpLoc.getSteps().size() - 1;
1302                                    for (int j = stepIndex; j >= 0; j--) {
1303                                        Step clonedStep = (Step) tmpLoc.getStepNum(j).clone();
1304                                        clonedStep.setPredicates(null);
1305                                        stepList.add(0, clonedStep);
1306                                    }
1307                                    if (simplePath && (tmpLoc.getInPredicate() || (tmpLoc.getParentExpression() != null && !tmpLoc.getParentExpression().isEmpty() && tmpLoc.getParentExpression().get(0) instanceof ListOpUNIONExpression))) {
1308                                        tmpExpr = contextLocated;
1309                                        stepIndex = contextLocatedStepIndex;
1310                                        ((Step) stepList.get(0)).setHasSeparator(true);
1311                                    } else {
1312                                        stepIndex = -1;
1313                                        firstExpr = tmpLoc.getStepNum(0).getExpression();
1314                                        if (firstExpr instanceof Variable) {
1315                                            tmpExpr = ((Variable) firstExpr).getExpression();
1316                                            stepList.remove(0);
1317                                        } else {
1318                                            break;
1319                                        }
1320                                    }
1321                                } else if (tmpExpr instanceof Variable) {
1322                                    tmpExpr = ((Variable) tmpExpr).getExpression();
1323                                } else if (tmpExpr instanceof FunctionCall) {
1324                                    stepList.add(0, tmpExpr);
1325                                    break;
1326                                }
1327                            }
1328
1329                        } catch (CloneNotSupportedException JavaDoc cnse) {
1330                            stepList.clear();
1331                        }
1332
1333                        if (!stepList.isEmpty() && stepList.size() != steps.size()) {
1334                            LocatedExpression loc = new LocatedExpression(stepList, false, arg.getParentModule(), true);
1335                            if (loc.getQType() != null)
1336                                qtype = loc.getQType();
1337                        }
1338                    } else if (arg.getParentExpression() != null && !arg.getParentExpression().isEmpty() && arg.getParentExpression().get(0) instanceof ListOpUNIONExpression) {
1339                        boolean prev = inPredicate;
1340                        inPredicate = true;
1341                        arg.accept(this);
1342                        inPredicate = prev;
1343                    }
1344                }
1345            }
1346            if (qtype == null)
1347                throw new TypeException("Could not find path : " + arg.toString(false,false,true));
1348
1349            // set typing context
1350
stepi.setQType(qtype);
1351            contextXNodes = stepi.getXTrees();
1352            contextQType = stepi.getQType();
1353
1354            // handle predicates if any
1355
ArrayList predicates = stepi.getPredicates();
1356            if (predicates != null && !predicates.isEmpty()) {
1357                QType prevContextQType = null;
1358                if (contextQType != null && contextQType.isMultiple())
1359                    prevContextQType = contextQType.changeOccurence(QType.OCC_1_1);
1360                else
1361                    prevContextQType = contextQType;
1362                this.setTypingContext(contextXNodes, prevContextQType, arg, i);
1363                for (int j = 0; j < predicates.size(); j++) {
1364                    XQueryExpression predicate = (XQueryExpression) predicates.get(j);
1365                    if (/*!noForce ||*/
1366                        predicate.getQType() == null) {
1367                        boolean prev = inPredicate;
1368                        inPredicate = true;
1369                        predicate.accept(this);
1370                        inPredicate = prev;
1371                    }
1372                }
1373                if (prevContextQType != null)
1374                    contextQType = prevContextQType;
1375            }
1376        }
1377        // type checking
1378
// if (noForce && arg.getQType() != null) {
1379
// this.setTypingContext(tmpContextXNodes, tmpContextQType);
1380
// return;
1381
// }
1382
if (qtype != null) {
1383            arg.setQType(qtype);
1384            // } else if (noForce && arg.getQType() != null) {
1385
// // do nothing
1386

1387        } else {
1388            throw new TypeException("Could not find path : " + arg.toString(false,false,true));
1389        }
1390
1391        // reset the context type
1392
contextType = QTypeDocument.ANY_ORIGIN;
1393        // reset the context
1394
this.setTypingContext(tmpContextXNodes, tmpContextQType, tmpContextLocated, tmpContextLocatedStepIndex);
1395    }
1396
1397    public void visit(NodeTest arg) throws XQueryException {
1398        // type checking
1399
if (noForce && arg.getQType() != null)
1400            return;
1401
1402        if (contextQType == null)
1403            return;
1404
1405        QType qtype = Utils.getSubType(contextType, contextQType, new Step(true, Axis.CHILD, arg, null, null), context.getSchemaManager(), inPredicate);
1406        arg.setQType(qtype);
1407        // type setting
1408
// remove 04/06/2003
1409
//arg.setQType(new QTypeAtom((SimpleType) getType(SC_STRING)));
1410
}
1411
1412    // public void visit(PrimitiveFunctionCall arg) throws XQueryException;
1413

1414    public void visit(QName arg) throws XQueryException {
1415        if (contextXNodes != null && contextQType != null && arg.getParentExpression() != null && arg.getParentExpression().get(0) instanceof SortedExpression) {
1416            QType qtype = null;
1417            //setContextNodeStepListType();
1418
//else setContextNodeStepListType();
1419
if (contextQType != null) {
1420                qtype = Utils.getSubType(contextType, contextQType, new Step(false, Axis.CHILD, arg, null, null), context.getSchemaManager(), inPredicate);
1421            }
1422            if (qtype == null)
1423                throw new TypeException("Could not type expression : " + arg.toString(false,false,true));
1424            arg.setQType(qtype);
1425            return;
1426        }
1427        QType qtype = null;
1428        if (contextQType != null) {
1429            qtype = Utils.getSubType(contextType, contextQType, new Step(false, Axis.CHILD, arg, null, null), context.getSchemaManager(), inPredicate);
1430        }
1431        if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
1432            arg.setQType(new QTypeAtom((SimpleType) getType(SC_QNAME)));
1433            return;
1434        }
1435        // if (qtype == null) {
1436
// qtype = buildQTypeFromXNodes(contextXNodes, new Step(false, Axis.CHILD, arg, null, null), true);
1437
// }
1438
if (qtype == null)
1439            throw new TypeException("Could not type expression : " + arg.toString(false,false,true));
1440        arg.setQType(qtype);
1441    }
1442
1443    public void visit(QuantifiedExpression arg) throws XQueryException {
1444        // TYPE VERIFICATION
1445
// SATISFIES expression must retunr a boolean
1446
// TYPE BUILDING
1447
// type of the direct path (there should be only one!!!)
1448

1449        // type checking
1450
if (noForce && arg.getQType() != null)
1451            return;
1452        //arg.setQType(new QTypeAtom((SimpleType) getType(SC_BOOLEAN)));
1453

1454        ArrayList variables = arg.getVariables();
1455        XQueryExpression expr = arg.getExpression();
1456        // forward checking and typing
1457
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
1458            for (int i = 0; i < variables.size(); i++)
1459                if (((Variable) variables.get(i)).getExpression().getQType() == null)
1460                    return;
1461            if (expr.getQType() == null)
1462                return;
1463        }
1464        for (int i = 0; i < variables.size(); i++)
1465            if (/*!noForce ||*/
1466                 ((Variable) variables.get(i)).getExpression().getQType() == null) {
1467                ((Variable) variables.get(i)).getExpression().accept(this);
1468                if (((Variable) variables.get(i)).getExpression().getQType() == null)
1469                    throw new TypeException("Expression " + ((Variable) variables.get(i)).getExpression() + " could not be typed."); //return;
1470
}
1471        if (/*!noForce ||*/
1472            expr.getQType() == null)
1473            expr.accept(this);
1474        if (expr.getQType() == null)
1475            throw new TypeException("Expression " + expr + " could not be typed."); //return;
1476
// type verification
1477
if (!expr.getQType().isBoolean())
1478            throw new TypeException("SATISFIES clause must be a boolean.");
1479        // type setting
1480
arg.setQType(new QTypeAtom((SimpleType) getType(SC_BOOLEAN)));
1481    }
1482
1483    public void visit(RangeExpression arg) throws XQueryException {
1484        // TYPE VERIFICATION
1485
// both expression must be integers
1486
// TYPE BUILDING
1487
// --> NONE
1488

1489        XQueryExpression expr1 = arg.getExpression1();
1490        XQueryExpression expr2 = arg.getExpression2();
1491        // forward checking and typing
1492
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
1493            if (expr1.getQType() == null)
1494                return;
1495            if (expr2.getQType() == null)
1496                return;
1497        }
1498        if (/*!noForce ||*/
1499            expr1.getQType() == null)
1500            expr1.accept(this);
1501        if (/*!noForce ||*/
1502            expr2.getQType() == null)
1503            expr2.accept(this);
1504        // type verification
1505
if (expr1.getQType() == null)
1506            throw new TypeException("Expression " + expr1 + " could not be typed."); //return;
1507
if (expr2.getQType() == null)
1508            throw new TypeException("Expression " + expr2 + " could not be typed."); //return;
1509
if (!expr1.getQType().isInteger())
1510            throw new TypeException("Expression '" + arg + "', first expression is not an integer.");
1511        if (expr2 != null && !expr2.getQType().isInteger())
1512            throw new TypeException("Expression '" + arg + "', second expression is not an integer.");
1513    }
1514
1515    // public void visit(RootNodeFunctionCall arg) throws XQueryException;
1516

1517    // public void visit(SchemaContextPath arg) throws XQueryException {
1518
private Declaration computeDeclFromPath(SchemaContextPath arg) throws XQueryException {
1519        SchemaContextStep step = arg.getStep(0);
1520        QName expr = (QName) step.getExpression();
1521        Declaration decl = null;
1522        Type scope = null;
1523        if (step.getAxis() == Constants.WITHTYPE) {
1524            scope = context.getSchemaManager().getType(expr.getNameSpace(), expr.getLocalName());
1525        } else if (step.getAxis() == Constants.NOAXIS) {
1526            decl = context.getSchemaManager().getElementDeclaration(expr.getNameSpace(), expr.getLocalName());
1527            if (decl == null)
1528                throw new TypeException("Could not type SchemaContextPath '" + arg + "' .");
1529            scope = decl.getType();
1530        }
1531        for (int i = 1; i < arg.getSteps().size(); i++) {
1532            if (scope == null)
1533                throw new TypeException("Could not type SchemaContextPath '" + arg + "' .");
1534            step = arg.getStep(i);
1535            expr = (QName) step.getExpression();
1536            if (step.getAxis() == Constants.WITHAXIS)
1537                decl = scope.getElementDeclaration(expr.getNameSpace(), expr.getLocalName());
1538            else
1539                decl = scope.getAttributeDeclaration(expr.getNameSpace(), expr.getLocalName());
1540            if (decl == null)
1541                throw new TypeException("Could not type SchemaContextPath '" + arg + "' .");
1542            scope = decl.getType();
1543        }
1544        if (decl == null)
1545            throw new TypeException("Could not type SchemaContextPath '" + arg + "' .");
1546        return decl;
1547    }
1548
1549    /*
1550    QNames appearing in a SequenceType have their prefixes expanded to namespace URIs by means of the in-scope namespaces and the default element/type namespace.
1551    It is a static error [err:XP0008] to use a TypeName in an ElementTest or AttributeTest if that name is not found in the in-scope type definitions.
1552    It is a static error [err:XP0008] to use an ElementName in an ElementTest if that name is not found in the in-scope element definitions unless a TypeNameOrWildcard is specified.
1553    It is a static error [err:XP0008] to use a (SchemaContextPath ElementName) pair in an ElementTest if the ElementName can not be located from the in-scope element definitions using the SchemaContextPath.
1554    It is a static error [err:XP0008] to use an AttributeName in an AttributeTest if that name is not found in the in-scope attribute definitions unless a TypeNameOrWildcard is specified.
1555    It is a static error [err:XP0008] to use a (SchemaContextPath AttributeName) pair in an AttributeTest if the AttributeName can not be located from the in-scope attribute definitions using the SchemaContextPath.
1556    If a QName that is used as an AtomicType is not defined as an atomic type in the in-scope type definitions, a static error is raised. [err:XP0051]
1557    
1558    Here are some examples of SequenceTypes that might be used in XQuery expressions:
1559    xs:date refers to the built-in Schema type date
1560    attribute()? refers to an optional attribute
1561    element() refers to any element
1562    element(po:shipto, po:address) refers to an element that has the name po:shipto (or is in the substitution group of that element), and has the type annotation po:address (or a subtype of that type)
1563    element(po:shipto, *) refers to an element named po:shipto (or in the substitution group of po:shipto), with no restrictions on its type
1564    element(*, po:address) refers to an element of any name that has the type annotation po:address (or a subtype of po:address). If the keyword nillable were used following po:address, that would indicate that the element may have empty content and the attribute xsi:nil="true", even though the declaration of the type po:address has required content.
1565    node()* refers to a sequence of zero or more nodes of any type
1566    item()+ refers to a sequence of one or more nodes or atomic values
1567    */

1568    public void visit(SequenceType arg) throws XQueryException {
1569        QType qtype = null;
1570        if (arg.getItemType() != null)
1571            qtype = arg.getItemType().getQType();
1572        else {
1573            qtype = new QTypeSequence(null);
1574        }
1575        switch (arg.getOccurrence()) {
1576            case Constants.OCCURRENCE_PLUS :
1577                qtype = qtype.changeOccurence(QType.OCC_1_N);
1578                break;
1579            case Constants.OCCURRENCE_QUESTION_MARK :
1580                qtype = qtype.changeOccurence(QType.OCC_0_1);
1581                break;
1582            case Constants.OCCURRENCE_STAR :
1583                qtype = qtype.changeOccurence(QType.OCC_0_N);
1584                break;
1585        }
1586        if (qtype == null)
1587            throw new TypeException("Expression " + arg + " could not be typed."); //return;
1588
arg.setQType(qtype);
1589    }
1590
1591    public void visit(SortedExpression arg) throws XQueryException {
1592        // TYPE VERIFICATION
1593
// sort clauses must be simple xpaths expressions
1594
// ArrayList sortClauses = arg.getSortClauses();
1595
// for (int i = 0; i < sortClauses.size(); i++)
1596
// {
1597
// ((XQueryExpression) sortClauses.get(i)).accept(this);
1598
// }
1599
// TYPE BUILDING
1600
// build chooice type!!!
1601

1602        // type checking
1603
if (noForce && arg.getQType() != null)
1604            return;
1605        XQueryExpression expr = arg.getExpression();
1606        ArrayList sortClauses = arg.getSortClauses();
1607        // forward checking and typing
1608
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
1609            if (expr.getQType() == null)
1610                return;
1611        }
1612        if (/*!noForce ||*/
1613            expr.getQType() == null)
1614            expr.accept(this);
1615        // set the context (but only the type is present ... not so easy!)
1616
// not done for now
1617
if (expr.getQType() == null)
1618            throw new TypeException("Expression " + expr + " could not be typed."); //return;
1619

1620        // if (expr.getQType() != null) {
1621
// QType tmpContextType = contextQType;
1622
// setContextQType(expr.getQType());
1623
// for (int i = 0; i < sortClauses.size(); i++)
1624
// if (/*!noForce ||*/ ((XQueryExpression) sortClauses.get(i)).getQType() == null)
1625
// ((XQueryExpression) sortClauses.get(i)).accept(this);
1626
// setContextQType(tmpContextType);
1627
// }
1628
// type setting
1629
arg.setQType(expr.getQType());
1630    }
1631
1632    // do nothing (but implement otherwise it fails)
1633
public void visit(Step arg) throws XQueryException {
1634    }
1635
1636    // public void visit(TypeSwitchExpression arg) throws XQueryException;
1637

1638    public void visit(UnOpMinusExpression arg) throws XQueryException {
1639        // TYPE VERIFICATION
1640
// expression must be numeric
1641
// TYPE BUILDING
1642

1643        // type checking
1644
if (noForce && arg.getQType() != null)
1645            return;
1646        XQueryExpression expr = arg.getExpression();
1647        // forward checking and typing
1648
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
1649            if (expr.getQType() == null)
1650                return;
1651        }
1652        if (/*!noForce ||*/
1653            expr.getQType() == null)
1654            expr.accept(this);
1655        // type verification
1656
if (expr.getQType() == null)
1657            throw new TypeException("Expression " + expr + " could not be typed."); //return;
1658
if (expr.getQType() != null) {
1659            if (!expr.getQType().isAtomic() /*&& !inPredicate*/)
1660                throw new TypeException("Expression '" + arg + "', operand is not an atomic value.");
1661            if (!expr.getQType().isNumeric())
1662                throw new TypeException("Expression '" + arg + "', operand is not numeric.");
1663        }
1664        // type setting
1665
QType qtypedata = expr.getQType().applyDATAFunction();
1666        if (qtypedata != null)
1667            arg.setQType(qtypedata);
1668        else
1669            arg.setQType(expr.getQType());
1670    }
1671
1672    public void visit(ValidateExpression arg) throws XQueryException {
1673        if (noForce && arg.getQType() != null)
1674            return;
1675        XQueryExpression expr = arg.getExpression();
1676        arg.setQType(expr.getQType());
1677    }
1678
1679    // public void visit(Value arg) throws XQueryException;
1680

1681    public void visit(ValueBoolean arg) throws XQueryException {
1682        // TYPE VERIFICATION
1683
// --> NONE
1684
// TYPE BUILDING
1685
// the return type is boolean
1686

1687        // type checking
1688
if (noForce && arg.getQType() != null)
1689            return;
1690        // type setting
1691
arg.setQType(new QTypeAtom(context.getSchemaManager().getBooleanType()));
1692    }
1693
1694    public void visit(ValueDecimal arg) throws XQueryException {
1695        // TYPE VERIFICATION
1696
// --> NONE
1697
// TYPE BUILDING
1698
// the return type is decimal
1699

1700        // type checking
1701
if (noForce && arg.getQType() != null)
1702            return;
1703        // type setting
1704
arg.setQType(new QTypeAtom(context.getSchemaManager().getDecimalType()));
1705    }
1706
1707    public void visit(ValueDouble arg) throws XQueryException {
1708        // TYPE VERIFICATION
1709
// --> NONE
1710
// TYPE BUILDING
1711
// the return type is double
1712

1713        // type checking
1714
if (noForce && arg.getQType() != null)
1715            return;
1716        // type setting
1717
arg.setQType(new QTypeAtom(context.getSchemaManager().getDoubleType()));
1718    }
1719
1720    public void visit(ValueFloat arg) throws XQueryException {
1721        // TYPE VERIFICATION
1722
// --> NONE
1723
// TYPE BUILDING
1724
// the return type is float
1725

1726        // type checking
1727
if (noForce && arg.getQType() != null)
1728            return;
1729        // type setting
1730
arg.setQType(new QTypeAtom(context.getSchemaManager().getFloatType()));
1731    }
1732
1733    public void visit(ValueInteger arg) throws XQueryException {
1734        // TYPE VERIFICATION
1735
// --> NONE
1736
// TYPE BUILDING
1737
// the return type is integer
1738

1739        // type checking
1740
if (noForce && arg.getQType() != null)
1741            return;
1742        // type setting
1743
arg.setQType(new QTypeAtom(context.getSchemaManager().getIntegerType()));
1744    }
1745
1746    public void visit(ValueString arg) throws XQueryException {
1747        // TYPE VERIFICATION
1748
// --> NONE
1749
// TYPE BUILDING
1750
// the return type is string
1751

1752        // type checking
1753
if (noForce && arg.getQType() != null)
1754            return;
1755        // type setting
1756
arg.setQType(new QTypeAtom(context.getSchemaManager().getStringType()));
1757    }
1758
1759    public void visit(ValueText arg) throws XQueryException {
1760        // TYPE VERIFICATION
1761
// --> NONE
1762
// TYPE BUILDING
1763
// the return type is string
1764

1765        // type checking
1766
if (noForce && arg.getQType() != null)
1767            return;
1768        // type setting
1769
arg.setQType(new QTypeText((SimpleType) getType(SC_STRING)));
1770    }
1771
1772    public void visit(Variable arg) throws XQueryException {
1773        // TYPE VERIFICATION
1774
// --> NONE
1775
// TYPE BUILDING
1776
// the return type is the type of the associated expression, if any
1777

1778        if (noForce && arg.getQType() != null)
1779            return;
1780        XQueryExpression expression = arg.getExpression();
1781        if (expression != null) {
1782            // forward checking and typing
1783
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
1784                if (expression.getQType() == null)
1785                    return;
1786            }
1787            if (/*!noForce ||*/
1788                expression.getQType() == null)
1789                expression.accept(this);
1790            // type checking
1791
if (expression.getQType() == null)
1792                throw new TypeException("Expression " + expression + " could not be typed."); //return;
1793
if (expression instanceof XQueryVoid)
1794                throw new TypeException("Variable " + arg + " could not be bound to existing path."); //return;
1795
/*
1796            if (expression instanceof LocatedExpression && !arg.hasDocumentRoot() && (expression.getXTrees() == null || expression.getXTrees().isEmpty()))
1797                throw new TypeException("Variable " + arg + " could not be bound to existing path."); //return;
1798            */

1799            // type setting
1800
if (arg.getBindingType() == Constants.LET_BINDINGTYPE)
1801                arg.setQType(expression.getQType());
1802            else if (arg.getBindingType() == Constants.FOR_BINDINGTYPE || arg.getBindingType() == Constants.QUANTIFIER_BINDINGTYPE || arg.getBindingType() == Constants.OUTERFOR_BINDINGTYPE) {
1803                QType exprqtype = expression.getQType();
1804                if (exprqtype instanceof QTypeSequence)
1805                    exprqtype = new QTypeUnion(exprqtype.getList());
1806                if (exprqtype.isMultiple()) {
1807                    exprqtype = exprqtype.changeOccurence(QType.OCC_1_1);
1808                }
1809                arg.setQType(exprqtype);
1810
1811            }
1812            //else if (arg.getBindingType() == Constants.FUNCTION_BINDINGTYPE)
1813
// arg.setQType(new QTypeAtom((SimpleType)getType((QName)expression)));
1814
else
1815                arg.setQType(expression.getQType());
1816        } else if (arg.getTypeDeclaration() != null) {
1817            arg.setQType(arg.getTypeDeclaration().getQType());
1818        }
1819        // else arg.setQType(null);
1820
}
1821
1822    /*
1823    [104] CompXmlComment ::= "comment" "{" Expr "}"
1824    
1825    A computed comment constructor (CompXMLComment) constructs a new comment node with its own node identity.
1826    The content expression of a computed comment constructor is processed as follows:
1827    
1828    Atomization is applied to the value of the content expression, converting it to a sequence of atomic values.
1829    
1830    If the result of atomization is an empty sequence, it is replaced by a zero-length string.
1831    Otherwise, each atomic value in the atomized sequence is cast into a string.
1832    
1833    The individual strings resulting from the previous step are merged into a single string by concatenating them with
1834    a single space character between each pair. The resulting string becomes the content of the constructed comment.
1835    */

1836    public void visit(XMLComment arg) throws XQueryException {
1837        if (noForce && arg.getQType() != null)
1838            return;
1839        XQueryExpression comment = arg.getComment(); // cannot be null
1840
// forward checking and typing
1841
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
1842            if (comment.getQType() == null)
1843                return;
1844        }
1845        if (/*!noForce ||*/
1846            comment.getQType() == null)
1847            comment.accept(this);
1848        // type checking
1849
if (comment.getQType() == null)
1850            throw new TypeException("Expression " + comment + " could not be typed."); //return;
1851

1852        QType valueQType = comment.getQType();
1853        if (!valueQType.canBeCastedInto(QType.PRIMITIVE_string) && !valueQType.isString()) {
1854            valueQType = valueQType.applyDATAFunction();
1855            if (valueQType == null || (!valueQType.canBeCastedInto(QType.PRIMITIVE_string) && !valueQType.isString()))
1856                throw new TypeException("Expression '" + comment + "', of attribute value pair has incorrect type.");
1857        }
1858        // type setting
1859
arg.setQType(new QTypeComment());
1860    }
1861
1862    /*
1863    [103] CompXmlPI ::= (("processing-instruction" NCName "{") | ("processing-instruction" "{" Expr "}" "{")) Expr? "}"
1864    
1865    A computed processing instruction constructor (CompXmlPI) constructs a new processing instruction node with its own node identity.
1866    The name expression of a computed processing instruction constructor is processed as follows:
1867    
1868    If the name expression returns an expanded QName: If the URI part of the QName is empty,
1869    the local part of the QName is used as the name (target) of the processing instruction; otherwise a dynamic error is raised.[err:XQ0041]
1870    
1871    If the name expression returns a string, that string is cast to a QName, which is then treated as in the previous item.
1872    If the cast fails, a dynamic error is raised.[err:XP0021]
1873    
1874    If the name expression does not return a QName or a string, a type error is raised.[err:XP0004][err:XP0006]
1875    
1876    The content expression of a computed processing instruction constructor is processed as follows:
1877    
1878    Atomization is applied to the value of the content expression, converting it to a sequence of atomic values.
1879    
1880    If the result of atomization is an empty sequence, it is replaced by a zero-length string.
1881    Otherwise, each atomic value in the atomized sequence is cast into a string.
1882    
1883    The individual strings resulting from the previous step are merged into a single string by concatenating them with a single space
1884    character between each pair. The resulting string becomes the content of the constructed processing instruction.
1885    */

1886
1887    public void visit(XMLProcessingInstruction arg) throws XQueryException {
1888        if (noForce && arg.getQType() != null)
1889            return;
1890        XQueryExpression piName = arg.getExpression1(); // cannot be null
1891
XQueryExpression piValue = arg.getExpression2(); // cannot be null
1892
// forward checking and typing
1893
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null) {
1894            // if (!(piName instanceof QName) && piName.getQType() == null)
1895
// return;
1896
if (piValue.getQType() == null)
1897                return;
1898        }
1899        // if (!(piName instanceof QName) && (/*!noForce ||*/ piName.getQType() == null))
1900
// piName.accept(this);
1901
// type checking
1902
// if (!(piName instanceof QName) && piName.getQType() == null)
1903
// throw new TypeException("Expression " + piName + " could not be typed.");
1904
if (/*!noForce ||*/
1905            piValue.getQType() == null)
1906            piValue.accept(this);
1907        // type checking
1908
if (piValue.getQType() == null)
1909            throw new TypeException("Expression " + piValue + " could not be typed."); //return;
1910

1911        QType nameQType = piName.getQType();
1912        if (nameQType != null && (!nameQType.isQName() || nameQType.isMultiple())) {
1913            nameQType = nameQType.applyDATAFunction();
1914            if (nameQType == null || !nameQType.isQName() || nameQType.isMultiple())
1915                throw new TypeException("Expression '" + piName + "', of processing instruction value pair has incorrect type.");
1916        }
1917        QType valueQType = piValue.getQType();
1918        if (valueQType != null && !valueQType.canBeCastedInto(QType.PRIMITIVE_string) && !valueQType.isString()) {
1919            valueQType = valueQType.applyDATAFunction();
1920            if (valueQType == null || (!valueQType.canBeCastedInto(QType.PRIMITIVE_string) && !valueQType.isString()))
1921                throw new TypeException("Expression '" + piValue + "', of processing instruction pair has incorrect type.");
1922        }
1923        // CHANGE this is to restrictive
1924
// if (attributeValue.getQType().isMultiple())
1925
// throw new TypeException("QType of an attribute cannot be multiple.");
1926
// type setting
1927
QType attQType = piValue.getQType();
1928        arg.setQType(new QTypeProcessingInstruction());
1929    }
1930
1931    // public void visit(XQueryBinaryOperatorExpression arg) throws XQueryException;
1932
// public void visit(XQueryBooleanOperatorExpression arg) throws XQueryException;
1933
public void visit(XQueryExpression arg) throws XQueryException {
1934        throw new TypeException("Typing of expression : " + arg + " of class " + arg.getClass().getName() + " is not supported");
1935    }
1936
1937    public void visit(XQueryExpressionSequence arg) throws XQueryException {
1938        // TYPE VERIFICATION
1939
// --> NONE
1940
// TYPE BUILDING
1941
// the return type is the sequence of the types
1942

1943        // type checking
1944
if (noForce && arg.getQType() != null)
1945            return;
1946        ArrayList subExpressions = arg.getSubExpressions();
1947        // forward checking and typing
1948
for (int i = 0; i < subExpressions.size(); i++)
1949            if (/*!noForce ||*/
1950                 ((XQueryExpression) subExpressions.get(i)).getQType() == null) {
1951                ((XQueryExpression) subExpressions.get(i)).accept(this);
1952                if (((XQueryExpression) subExpressions.get(i)).getQType() == null)
1953                    throw new TypeException("Expression " + (XQueryExpression) subExpressions.get(i) + " could not be typed."); //return;
1954
}
1955        // type setting
1956
if (subExpressions.size() == 1)
1957            arg.setQType(((XQueryExpression) subExpressions.get(0)).getQType());
1958        else {
1959            ArrayList list = new ArrayList(subExpressions.size());
1960            boolean unique = true;
1961            for (int i = 0; i < subExpressions.size(); i++) {
1962                XQueryExpression expr = (XQueryExpression) subExpressions.get(i);
1963                QType qtype = expr.getQType();
1964                if (i != 0 && unique && !((QType) list.get(i - 1)).equals(qtype))
1965                    unique = false;
1966                list.add(qtype);
1967            }
1968            if (unique)
1969                arg.setQType(((QType) list.get(0)).changeOccurence(QType.OCC_0_N));
1970            // arg.setQType(new QTypeCollection((QType) list.get(0)));
1971
else
1972                arg.setQType(new QTypeSequence(list));
1973        }
1974    }
1975
1976    // public void visit(XQueryFile arg) throws XQueryException;
1977
// public void visit(XQueryListBinaryOperatorExpression arg) throws XQueryException;
1978
// public void visit(XQueryListUnaryOperatorExpression arg) throws XQueryException;
1979
// public void visit(XQueryUnaryOperatorExpression arg) throws XQueryException;
1980
// public void visit(XQueryUnit arg) throws XQueryException;
1981
public void visit(XQueryVoid arg) throws XQueryException {
1982        arg.setQType(new QTypeSequence(null));
1983    }
1984
1985    // primitive functions
1986

1987    public void visit(FunctionABS arg) throws XQueryException {
1988        // TYPE VERIFICATION
1989
// arguments must be numeric
1990
// TYPE BUILDING
1991
// the return type is a numeric
1992

1993        // type checking
1994
if (noForce && arg.getQType() != null)
1995            return;
1996        XQueryExpression expr = (XQueryExpression) arg.getArguments().get(0);
1997        // forward checking and typing
1998
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
1999            if (expr.getQType() == null)
2000                return;
2001        if (/*!noForce ||*/
2002            expr.getQType() == null)
2003            expr.accept(this);
2004        if (expr.getQType() == null)
2005            throw new TypeException("Function call abs '" + arg + "', argument could not be typed"); // return;
2006
// type verification
2007
QType qtype = expr.getQType();
2008        if (!qtype.isNumeric())
2009            qtype = qtype.applyDATAFunction();
2010        if (qtype == null || !qtype.isNumeric())
2011            throw new TypeException("Function call abs '" + arg + "', argument is not numeric");
2012        // type setting
2013
arg.setQType(new QTypeAtom(expr.getQType().getSimpleType()));
2014    }
2015
2016    public void visit(FunctionAVG arg) throws XQueryException {
2017        // TYPE VERIFICATION
2018
// arguments must be numeric (or can be casted into a numeric)
2019
// each argument must be either
2020
// - atom
2021
// - attribute (hopefully the value can be casted into a numeric)
2022
// - union (with at least a member being numeric)
2023
// - collection (of one of the previous types)
2024
// TYPE BUILDING
2025
// the return type is a float
2026

2027        // type checking
2028
if (noForce && arg.getQType() != null)
2029            return;
2030        //ArrayList arguments = arg.getArguments();
2031
XQueryExpression expr = (XQueryExpression) arg.getArguments().get(0);
2032        // forward checking and typing
2033
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2034            if (expr.getQType() == null)
2035                return;
2036        if (/*!noForce ||*/
2037            expr.getQType() == null)
2038            expr.accept(this);
2039        if (expr.getQType() == null)
2040            throw new TypeException("Function call avg '" + arg + "', argument could not be typed"); // return;
2041
// type verification
2042
QType qtype = expr.getQType();
2043        /*
2044        if (!(qtype instanceof QTypeAtom) || (!qtype.isNumeric() && !qtype.isDuration()))
2045            qtype = qtype.applyDATAFunction();
2046        if (qtype == null || (!qtype.isNumeric() && !qtype.isDuration()))
2047            throw new TypeException("Function call avg '" + arg + "', argument is not numeric or duration");
2048        */

2049        if (!qtype.isAtom())
2050            qtype = qtype.applyDATAFunction();
2051        if (qtype == null || !qtype.isAtom())
2052            throw new TypeException("Function call avg '" + arg + "', argument has incorrect type");
2053        // type setting
2054
if (qtype.getSubClass() == QType.SEQUENCE || qtype.getSubClass() == QType.UNION)
2055            arg.setQType(new QTypeAtom((SimpleType) getType(SC_DOUBLE)));
2056        else {
2057            PrimitiveType primType = ((SimpleType) qtype.getType()).getPrimitive();
2058            int prim = primType.getType();
2059            switch (prim) {
2060                case PrimitiveType.FLOAT :
2061                    arg.setQType(new QTypeAtom((SimpleType) getType(SC_FLOAT)));
2062                    break;
2063                case PrimitiveType.DECIMAL :
2064                    arg.setQType(new QTypeAtom((SimpleType) getType(SC_DECIMAL)));
2065                    break;
2066                case PrimitiveType.DOUBLE :
2067                    arg.setQType(new QTypeAtom((SimpleType) getType(SC_DOUBLE)));
2068                    break;
2069                default :
2070                    arg.setQType(new QTypeAtom((SimpleType) getType(SC_DOUBLE)));
2071                    break;
2072            }
2073        }
2074        //arg.setQType(new QTypeAtom((SimpleType) getType(SC_DOUBLE)));
2075
}
2076
2077    public void visit(FunctionCEILING arg) throws XQueryException {
2078        // TYPE VERIFICATION
2079
// arguments must be numeric
2080
// TYPE BUILDING
2081
// the return type is a numeric
2082

2083        // type checking
2084
if (noForce && arg.getQType() != null)
2085            return;
2086        XQueryExpression expr = (XQueryExpression) arg.getArguments().get(0);
2087        // forward checking and typing
2088
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2089            if (expr.getQType() == null)
2090                return;
2091        if (/*!noForce ||*/
2092            expr.getQType() == null)
2093            expr.accept(this);
2094        if (expr.getQType() == null)
2095            throw new TypeException("Function call ceiling '" + arg + "', argument could not be typed"); // return;
2096
// type verification
2097
QType qtype = expr.getQType();
2098        if (!qtype.isNumeric())
2099            qtype = qtype.applyDATAFunction();
2100        if (qtype == null || !qtype.isNumeric())
2101            throw new TypeException("Function call ceiling '" + arg + "', argument is not numeric");
2102        // type setting
2103
arg.setQType(new QTypeAtom((SimpleType) getType(SC_INTEGER)));
2104    }
2105
2106    public void visit(FunctionCOLLECTION arg) throws XQueryException {
2107        // TYPE VERIFICATION
2108
// arguments must be string
2109
// TYPE BUILDING
2110
// the return type is a node list
2111

2112        // type checking
2113
if (noForce && arg.getQType() != null)
2114            return;
2115        // type setting
2116
ArrayList xnodes = context.getCollectionRootNodes(arg.getSourceName(), arg.getCollectionName());
2117        arg.setXTrees(xnodes);
2118        QType qtype = null;
2119        if (xnodes != null) {
2120            ArrayList tmplist = new ArrayList();
2121            for (int i = 0; i < xnodes.size(); i++) {
2122                Collection childreni = ((XTreeNode) xnodes.get(i)).getChildren();
2123                if (childreni != null && !childreni.isEmpty()) {
2124                    ArrayList childlist = new ArrayList(1);
2125                    childlist.addAll(childreni);
2126                    QType qtypei = buildQTypeFromXNodes(childlist, QType.OCC_1_1, arg, true);
2127                    if (qtypei != null)
2128                        tmplist.add(new QTypeDocument(qtypei, QType.OCC_0_N, QTypeDocument.COLLECTION_ORIGIN));
2129                }
2130            }
2131            if (!tmplist.isEmpty()) {
2132                if (tmplist.size() == 1)
2133                    qtype = (QType) tmplist.get(0);
2134                else
2135                    qtype = new QTypeUnion(tmplist, QType.OCC_0_N);
2136            }
2137        }
2138
2139        //ArrayList vectTypes = getDeclarationsFromSteps(arg);
2140
//QType qtype = buildTypeFromPathResolver(vectTypes, arg, true);
2141
// add 04/06/2003
2142
// ATTENTION for mediatorxql only
2143
if (qaOnly && qtype == null)
2144            qtype = new QTypeDocument(new QTypeElement(new QName("*", "*", "*", arg.getParentModule(), null), getType(SC_ANYTYPE)), QType.OCC_0_N, QTypeDocument.DOCUMENT_ORIGIN);
2145        // end add
2146
arg.setQType(qtype);
2147
2148    }
2149
2150    public void visit(FunctionCONCAT arg) throws XQueryException {
2151        // TYPE VERIFICATION
2152
// arguments must be collections
2153
// TYPE BUILDING
2154
// the return type is a integer
2155

2156        // type checking
2157
if (noForce && arg.getQType() != null)
2158            return;
2159        ArrayList arguments = arg.getArguments();
2160        // forward checking and typing, and verification
2161
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2162            for (int i = 0; i < arguments.size(); i++)
2163                if (((XQueryExpression) arguments.get(i)).getQType() == null)
2164                    return;
2165        for (int i = 0; i < arguments.size(); i++) {
2166            XQueryExpression expri = (XQueryExpression) arguments.get(i);
2167            if (/*!noForce ||*/
2168                expri.getQType() == null)
2169                expri.accept(this);
2170            QType qtypei = expri.getQType();
2171            if (qtypei == null) //return;
2172
throw new TypeException("Function call concat '" + arg + "', argument " + (i + 1) + " could not be typed"); // return;
2173
if (!qtypei.isString())
2174                throw new TypeException("Function call concat '" + arg + "', argument " + (i + 1) + " is not a string.");
2175            if (!qtypei.isAtomic() /*&& !inPredicate*/)
2176                throw new TypeException("Function call concat '" + arg + "', argument " + (i + 1) + " is not an atomic value.'");
2177        }
2178        // type setting
2179
arg.setQType(new QTypeAtom((SimpleType) getType(SC_STRING)));
2180    }
2181
2182    public void visit(FunctionCONTAINS arg) throws XQueryException {
2183        // we treat now only signature like xf:contains(string $operand1, string $operand2) => boolean
2184
// but it exists signature like xf:contains(string $operand1, string $operand2, anyURI $collation) => boolean, later...
2185
// TYPE VERIFICATION
2186
// 2 arguments, and must be string
2187
// TYPE BUILDING
2188
// the return type is a boolean
2189

2190
2191        // type checking
2192
if (noForce && arg.getQType() != null)
2193            return;
2194
2195        ArrayList arguments = arg.getArguments();
2196        // forward checking and typing, and verification
2197
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2198            for (int i = 0; i < arguments.size(); i++)
2199                if (((XQueryExpression) arguments.get(i)).getQType() == null)
2200                    return;
2201        for (int i = 0; i < arguments.size(); i++) {
2202            XQueryExpression expri = (XQueryExpression) arguments.get(i);
2203            if (/*!noForce ||*/
2204                expri.getQType() == null)
2205                expri.accept(this);
2206            if (expri.getQType() == null) //return;
2207
throw new TypeException("Function call contains '" + arg + "', argument " + (i + 1) + " could not be typed"); // return;
2208
if (!expri.getQType().isAtomic() /*&& !inPredicate*/)
2209                throw new TypeException("Function call contains '" + arg + "', argument " + (i + 1) + " is not an atomic value.'");
2210            if (!expri.getQType().isString())
2211                throw new TypeException("Function call contains '" + arg + "', argument " + (i + 1) + " is not a string.");
2212        }
2213        // type setting
2214
arg.setQType(new QTypeAtom((SimpleType) getType(SC_BOOLEAN)));
2215    }
2216
2217    public void visit(FunctionCOUNT arg) throws XQueryException {
2218        // TYPE VERIFICATION
2219
// arguments must be collections
2220
// TYPE BUILDING
2221
// the return type is a integer
2222

2223        // type checking
2224
if (noForce && arg.getQType() != null)
2225            return;
2226        XQueryExpression expr = (XQueryExpression) arg.getArguments().get(0);
2227        // forward checking and typing
2228
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2229            if (expr.getQType() == null)
2230                return;
2231        if (/*!noForce ||*/
2232            expr.getQType() == null)
2233            expr.accept(this);
2234        if (expr.getQType() == null)
2235            throw new TypeException("Function call count '" + arg + "', argument could not be typed"); // return;
2236
// type setting
2237
arg.setQType(new QTypeAtom((SimpleType) getType(SC_INTEGER)));
2238    }
2239
2240    public void visit(FunctionCURRENT_DATE arg) throws XQueryException {
2241        // but it exists signature like xf:current-date() => date
2242
// TYPE VERIFICATION
2243
// 0 arguments
2244
// TYPE BUILDING
2245
// the return type is a simpletype dateTime
2246

2247        // ArrayList arguments = arg.getArguments();
2248
// forward checking and typing, and verification
2249
// type checking
2250
if (noForce && arg.getQType() != null)
2251            return;
2252        // type setting
2253
arg.setQType(new QTypeAtom((SimpleType) getType(SC_DATE)));
2254    }
2255
2256    public void visit(FunctionCURRENT_DATETIME arg) throws XQueryException {
2257        // but it exists signature like xf:current-dateTime() => date
2258
// TYPE VERIFICATION
2259
// 0 arguments
2260
// TYPE BUILDING
2261
// the return type is a simpletype dateTime
2262

2263        // ArrayList arguments = arg.getArguments();
2264
// forward checking and typing, and verification
2265
// type checking
2266
if (noForce && arg.getQType() != null)
2267            return;
2268        // type setting
2269
arg.setQType(new QTypeAtom((SimpleType) getType(SC_DATETIME)));
2270    }
2271
2272    public void visit(FunctionCURRENT_TIME arg) throws XQueryException {
2273        // but it exists signature like xf:current-time() => date
2274
// TYPE VERIFICATION
2275
// 0 arguments
2276
// TYPE BUILDING
2277
// the return type is a simpletype dateTime
2278

2279        // ArrayList arguments = arg.getArguments();
2280
// forward checking and typing, and verification
2281
// type checking
2282
if (noForce && arg.getQType() != null)
2283            return;
2284        // type setting
2285
arg.setQType(new QTypeAtom((SimpleType) getType(SC_TIME)));
2286    }
2287
2288    public void visit(FunctionDATA arg) throws XQueryException {
2289        // TYPE VERIFICATION
2290
// arguments must be simple type node
2291
// The built-in data function is implicitly invoked to extract the content of the node as a typed value.
2292
// If data is invoked with no argument, its implicit argument is the current (context) node.
2293
// For example, if the content of the current node is the integer 47, then data() has type integer and value 47.
2294
// If the content of its argument node cannot be expressed as a value of a simple type, the data function raises an error.
2295
// TYPE BUILDING
2296
// the return type depends on the node content
2297

2298        // type checking
2299
if (noForce && arg.getQType() != null)
2300            return;
2301        XQueryExpression expr = (XQueryExpression) arg.getArguments().get(0);
2302        // forward checking and typing
2303
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2304            if (expr.getQType() == null)
2305                return;
2306        if (/*!noForce ||*/
2307            expr.getQType() == null)
2308            expr.accept(this);
2309        if (expr.getQType() == null)
2310            throw new TypeException("Function call count '" + arg + "', argument could not be typed"); // return;
2311
QType qtype = expr.getQType();
2312        // if (qtype == null) throw new TypeException("Could not type Function DATA argument.");
2313
// DATA function must be applied successfully on qtye
2314
QType argqtype = null;
2315        if (qtype.isAtom())
2316            argqtype = qtype;
2317        else
2318            argqtype = qtype.applyDATAFunction();
2319        if (argqtype == null)
2320            throw new TypeException("Function call data '" + arg + "', could not apply data function to type '" + qtype + "'.");
2321        // type setting
2322
arg.setQType(argqtype);
2323    }
2324
2325    public void visit(FunctionDATE arg) throws XQueryException {
2326        // but it exists signature like xf:current-dateTime() => date
2327
// TYPE VERIFICATION
2328
// 0 arguments
2329
// TYPE BUILDING
2330
// the return type is a simpleType date
2331

2332        // type checking
2333
if (noForce && arg.getQType() != null)
2334            return;
2335        XQueryExpression argument = (XQueryExpression) arg.getArguments().get(0);
2336        // forward checking and typing, and verification
2337
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2338            if (argument.getQType() == null)
2339                return;
2340        if (!(argument instanceof ValueString))
2341            throw new TypeException("Function call date '" + arg + "', argument is not a string literal");
2342        try {
2343            SimpleType simpleType = context.getSchemaManager().getDateType();
2344            String JavaDoc dateValue = simpleType.normalizedValue(((ValueString) argument).getValue());
2345            simpleType.validate(dateValue, false, null);
2346            ((ValueString) argument).setValue(dateValue);
2347        } catch (SchemaException se) {
2348            throw new TypeException("Function call date '" + arg + "', argument has invalid date format");
2349        }
2350        // type setting
2351
arg.setQType(new QTypeAtom(context.getSchemaManager().getDateType()));
2352    }
2353
2354    public void visit(FunctionDATETIME arg) throws XQueryException {
2355        // but it exists signature like xf:current-dateTime() => date
2356
// TYPE VERIFICATION
2357
// 0 arguments
2358
// TYPE BUILDING
2359
// the return type is a simpleType date
2360

2361        // type checking
2362
if (noForce && arg.getQType() != null)
2363            return;
2364        XQueryExpression argument = (XQueryExpression) arg.getArguments().get(0);
2365        // forward checking and typing, and verification
2366
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2367            if (argument.getQType() == null)
2368                return;
2369        if (!(argument instanceof ValueString))
2370            throw new TypeException("Function call datetime '" + arg + "', argument is not a string literal");
2371        try {
2372            SimpleType simpleType = context.getSchemaManager().getDateTimeType();
2373            String JavaDoc dateValue = simpleType.normalizedValue(((ValueString) argument).getValue());
2374            simpleType.validate(dateValue, false, null);
2375            ((ValueString) argument).setValue(dateValue);
2376        } catch (SchemaException se) {
2377            throw new TypeException("Function call datetime '" + arg + "', argument has invalid datetime format");
2378        }
2379        // type setting
2380
arg.setQType(new QTypeAtom(context.getSchemaManager().getDateTimeType()));
2381    }
2382
2383    public void visit(FunctionDECIMAL arg) throws XQueryException {
2384        // TYPE VERIFICATION
2385
// arguments must be numeric
2386
// TYPE BUILDING
2387
// the return type is a numeric
2388

2389        // type checking
2390
if (noForce && arg.getQType() != null)
2391            return;
2392        XQueryExpression expr = (XQueryExpression) arg.getArguments().get(0);
2393        // forward checking and typing, and verification
2394
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2395            if (expr.getQType() == null)
2396                return;
2397        if (/*!noForce ||*/
2398            expr.getQType() == null)
2399            expr.accept(this);
2400        if (expr.getQType() == null)
2401            throw new TypeException("Function call decimal '" + arg + "', argument could not be typed"); // return;
2402
// CHANGE
2403
QType qtype = expr.getQType();
2404        if (!qtype.isAtom()) {
2405            qtype = qtype.applyDATAFunction();
2406            if (!qtype.isAtom())
2407                throw new TypeException("Function call decimal '" + arg + "', argument has invalid type, not an atom");
2408        }
2409        if (!qtype.canBeCastedInto(QType.PRIMITIVE_decimal))
2410            throw new TypeException("Function call decimal '" + arg + "', argument has type that can not be casted");
2411        if (expr instanceof ValueString) {
2412            try {
2413                SimpleType simpleType = context.getSchemaManager().getDecimalType();
2414                String JavaDoc decimalValue = simpleType.normalizedValue(((ValueString) expr).getValue());
2415                simpleType.validate(decimalValue, false, null);
2416                ((ValueString) expr).setValue(decimalValue);
2417            } catch (SchemaException se) {
2418                throw new TypeException("Function call decimal '" + arg + "', argument is string with invalid format");
2419            }
2420        }
2421        // type setting
2422
arg.setQType(new QTypeAtom(context.getSchemaManager().getDecimalType()));
2423    }
2424
2425    public void visit(FunctionDISTINCT_VALUES arg) throws XQueryException {
2426        // TYPE VERIFICATION
2427
// argument must be node list
2428
// TYPE BUILDING
2429
// the return type is a node list
2430

2431        // type checking
2432
if (noForce && arg.getQType() != null)
2433            return;
2434        XQueryExpression expr = (XQueryExpression) arg.getArgument(0);
2435        // forward checking and typing
2436
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2437            if (expr.getQType() == null)
2438                return;
2439        if (/*!noForce ||*/
2440            expr.getQType() == null)
2441            expr.accept(this);
2442        if (expr.getQType() == null)
2443            throw new TypeException("Function call distinct-values '" + arg + "', argument could not be typed"); // return;
2444
// type checking
2445
// REMOVE 16/04/2003
2446
QType qtype = expr.getQType();
2447        if (!qtype.isAtom() /*&& !qtype.isSimpleTypeNode()*/
2448            ) {
2449            qtype = qtype.applyDATAFunction();
2450            if (qtype == null || !qtype.isAtom() /*|| !qtype.isSimpleTypeNode()*/
2451                )
2452                throw new TypeException("Function call distinct-values '" + arg + "', argument is not a collection of simple values");
2453        }
2454        // type setting
2455
arg.setQType(qtype);
2456    }
2457
2458    public void visit(FunctionDOC arg) throws XQueryException {
2459
2460        // TYPE VERIFICATION
2461
// arguments must be string
2462
// TYPE BUILDING
2463
// the return type is a node list
2464

2465
2466        // type checking
2467
if (noForce && arg.getQType() != null)
2468            return;
2469        // type setting
2470
//arg.setQType(new QTypeDocument(null, QTypeDocument.DOCUMENT_ORIGIN));
2471
arg.setQType(new QTypeDocument(new QTypeElement(new QName("*", "*", "*", arg.getParentModule(), null), this.getType(SC_ANYTYPE)), QTypeDocument.DOCUMENT_ORIGIN));
2472
2473    }
2474
2475    public void visit(FunctionDOUBLE arg) throws XQueryException {
2476        // TYPE VERIFICATION
2477
// arguments must be numeric
2478
// TYPE BUILDING
2479
// the return type is a numeric
2480

2481        //ArrayList arguments = arg.getArguments();
2482
XQueryExpression expr = (XQueryExpression) arg.getArguments().get(0);
2483        // forward checking and typing, and verification
2484
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2485            if (expr.getQType() == null)
2486                return;
2487        if (/*!noForce ||*/
2488            expr.getQType() == null)
2489            expr.accept(this);
2490        if (expr.getQType() == null)
2491            throw new TypeException("Function call double '" + arg + "', argument could not be typed"); // return;
2492
QType qtype = expr.getQType();
2493        if (!qtype.isAtom()) {
2494            qtype = qtype.applyDATAFunction();
2495            if (qtype == null || !qtype.isAtom())
2496                throw new TypeException("Function call double '" + arg + "', argument has invalid type, not an atom");
2497        }
2498        if (!qtype.canBeCastedInto(QType.PRIMITIVE_double))
2499            throw new TypeException("Function call double '" + arg + "', argument has type that can not be casted");
2500        if (expr instanceof ValueString) {
2501            try {
2502                SimpleType simpleType = context.getSchemaManager().getDoubleType();
2503                String JavaDoc value = simpleType.normalizedValue(((ValueString) expr).getValue());
2504                simpleType.validate(value, false, null);
2505                ((ValueString) expr).setValue(value);
2506            } catch (SchemaException se) {
2507                throw new TypeException("Function call double '" + arg + "', argument is string with invalid format");
2508            }
2509        }
2510        // type setting
2511
arg.setQType(new QTypeAtom(context.getSchemaManager().getDoubleType()));
2512    }
2513
2514    public void visit(FunctionEMPTY arg) throws XQueryException {
2515        // TYPE VERIFICATION
2516
// arguments must be sequence
2517
// TYPE BUILDING
2518
// the return type is a boolean
2519

2520
2521        //arg.setQType(new QTypeAtom((SimpleType) getType(SC_BOOLEAN)));
2522

2523        // type checking
2524
if (noForce && arg.getQType() != null)
2525            return;
2526        XQueryExpression expr = arg.getArgument(0);
2527        // forward checking and typing
2528
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2529            if (expr.getQType() == null)
2530                return;
2531        if (/*!noForce ||*/
2532            expr.getQType() == null)
2533            expr.accept(this);
2534        if (expr.getQType() == null)
2535            throw new TypeException("Function call empty '" + arg + "', argument could not be typed"); // return;
2536
// if (!expr.getQType().isNode())
2537
// throw new TypeException("Function call empty '" + arg + "', argument is not a node or collection of nodes");
2538
// type setting
2539
arg.setQType(new QTypeAtom((SimpleType) getType(SC_BOOLEAN)));
2540    }
2541
2542    public void visit(FunctionENDS_WITH arg) throws XQueryException {
2543        // TYPE VERIFICATION
2544
// arguments must be sequence
2545
// TYPE BUILDING
2546
// the return type is a boolean
2547

2548        //arg.setQType(new QTypeAtom((SimpleType) getType(SC_BOOLEAN)));
2549

2550        // type checking
2551
if (noForce && arg.getQType() != null)
2552            return;
2553        ArrayList arguments = arg.getArguments();
2554        // forward checking and typing, and verification
2555
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2556            for (int i = 0; i < arguments.size(); i++)
2557                if (((XQueryExpression) arguments.get(i)).getQType() == null)
2558                    return;
2559        for (int i = 0; i < arguments.size(); i++) {
2560            XQueryExpression expri = (XQueryExpression) arguments.get(i);
2561            if (/*!noForce ||*/
2562                expri.getQType() == null)
2563                expri.accept(this);
2564            if (expri.getQType() == null) //return;
2565
throw new TypeException("Function call ends-with '" + arg + "', argument " + (i + 1) + " could not be typed"); // return;
2566
if (!expri.getQType().isString())
2567                throw new TypeException("Function call ends-with '" + arg + "', argument " + (i + 1) + " is not a string");
2568        }
2569        // type setting
2570
arg.setQType(new QTypeAtom((SimpleType) getType(SC_BOOLEAN)));
2571    }
2572
2573    public void visit(FunctionEXISTS arg) throws XQueryException {
2574        // TYPE VERIFICATION
2575
// arguments must be sequence
2576
// TYPE BUILDING
2577
// the return type is a boolean
2578

2579        // type checking
2580
if (noForce && arg.getQType() != null)
2581            return;
2582
2583        XQueryExpression expr = (XQueryExpression) arg.getArguments().get(0);
2584        // forward checking and typing
2585
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2586            if (expr.getQType() == null)
2587                return;
2588        if (/*!noForce ||*/
2589            expr.getQType() == null)
2590            expr.accept(this);
2591        if (expr.getQType() == null)
2592            throw new TypeException("Function call empty '" + arg + "', argument could not be typed"); // return;
2593
// type setting
2594
arg.setQType(new QTypeAtom((SimpleType) getType(SC_BOOLEAN)));
2595    }
2596
2597    public void visit(FunctionEXPANDED_QNAME arg) throws XQueryException {
2598        if (noForce && arg.getQType() != null)
2599            return;
2600
2601        ArrayList arguments = arg.getArguments();
2602        // forward checking and typing, and verification
2603
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2604            for (int i = 0; i < arguments.size(); i++)
2605                if (((XQueryExpression) arguments.get(i)).getQType() == null)
2606                    return;
2607        for (int i = 0; i < arguments.size(); i++) {
2608            XQueryExpression expri = (XQueryExpression) arguments.get(i);
2609            if (/*!noForce ||*/
2610                expri.getQType() == null)
2611                expri.accept(this);
2612            if (expri.getQType() == null) //return;
2613
throw new TypeException("Function call expanded-QName '" + arg + "', argument " + (i + 1) + " could not be typed"); // return;
2614
if (!expri.getQType().isAtom() || !expri.getQType().isString())
2615                throw new TypeException("Function call expanded-QName '" + arg + "', argument " + (i + 1) + " is not an atomic string.'");
2616        }
2617        // type setting
2618
arg.setQType(new QTypeAtom((SimpleType) getType(SC_QNAME)));
2619    }
2620
2621    public void visit(FunctionFALSE arg) throws XQueryException {
2622        // TYPE VERIFICATION
2623
// TYPE BUILDING
2624
// the return type is a boolean atom
2625

2626        // type checking
2627
if (noForce && arg.getQType() != null)
2628            return;
2629        // type setting
2630
arg.setQType(new QTypeAtom((SimpleType) getType(SC_BOOLEAN)));
2631    }
2632
2633    public void visit(FunctionFLOAT arg) throws XQueryException {
2634        // TYPE VERIFICATION
2635
// arguments must be numeric
2636
// TYPE BUILDING
2637
// the return type is a numeric
2638

2639        // type checking
2640
if (noForce && arg.getQType() != null)
2641            return;
2642        XQueryExpression expr = (XQueryExpression) arg.getArguments().get(0);
2643        // forward checking and typing, and verification
2644
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2645            if (expr.getQType() == null)
2646                return;
2647        if (/*!noForce ||*/
2648            expr.getQType() == null)
2649            expr.accept(this);
2650        if (expr.getQType() == null)
2651            throw new TypeException("Function call float '" + arg + "', argument could not be typed"); // return;
2652
QType qtype = expr.getQType();
2653        if (!qtype.isAtom()) {
2654            qtype = qtype.applyDATAFunction();
2655            if (qtype == null || !qtype.isAtom())
2656                throw new TypeException("Function call float '" + arg + "', argument has invalid type, not an atom");
2657        }
2658        if (!qtype.canBeCastedInto(QType.PRIMITIVE_float))
2659            throw new TypeException("Function call float '" + arg + "', argument has type that can not be casted");
2660        if (expr instanceof ValueString) {
2661            try {
2662                SimpleType simpleType = context.getSchemaManager().getFloatType();
2663                String JavaDoc value = simpleType.normalizedValue(((ValueString) expr).getValue());
2664                simpleType.validate(value, false, null);
2665                ((ValueString) expr).setValue(value);
2666            } catch (SchemaException se) {
2667                throw new TypeException("Function call float '" + arg + "', argument is string with invalid format");
2668            }
2669        }
2670        // type setting
2671
arg.setQType(new QTypeAtom(context.getSchemaManager().getFloatType()));
2672    }
2673
2674    public void visit(FunctionFLOOR arg) throws XQueryException {
2675        // TYPE VERIFICATION
2676
// arguments must be numeric
2677
// TYPE BUILDING
2678
// the return type is a numeric
2679

2680        // type checking
2681
if (noForce && arg.getQType() != null)
2682            return;
2683        XQueryExpression expr = (XQueryExpression) arg.getArguments().get(0);
2684        // forward checking and typing
2685
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2686            if (expr.getQType() == null)
2687                return;
2688        if (/*!noForce ||*/
2689            expr.getQType() == null)
2690            expr.accept(this);
2691        if (expr.getQType() == null)
2692            throw new TypeException("Function call floor '" + arg + "', argument could not be typed"); // return;
2693
// type verification
2694
QType qtype = expr.getQType();
2695        if (!qtype.isNumeric())
2696            qtype = qtype.applyDATAFunction();
2697        if (qtype == null || !qtype.isNumeric())
2698            throw new TypeException("Function call floor '" + arg + "', argument is not numeric");
2699        // type setting
2700
arg.setQType(new QTypeAtom((SimpleType) getType(SC_INTEGER)));
2701    }
2702
2703    public void visit(FunctionGET_MONTH_FROM_DATE arg) throws XQueryException {
2704        // TYPE VERIFICATION
2705
// argument must be a date
2706
// TYPE BUILDING
2707
// the return type is an integer
2708

2709        // type checking
2710
if (noForce && arg.getQType() != null)
2711            return;
2712        ArrayList arguments = arg.getArguments();
2713        XQueryExpression expr = (XQueryExpression) arguments.get(0);
2714        // forward checking and typing
2715
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2716            if (expr.getQType() == null)
2717                return;
2718        if (/*!noForce ||*/
2719            expr.getQType() == null)
2720            expr.accept(this);
2721        if (expr.getQType() == null)
2722            throw new TypeException("Function call lower-case '" + arg + "', argument could not be typed"); // return;
2723
// CHANGE
2724
QType qtype = expr.getQType();
2725        if (!qtype.isAtom()) {
2726            qtype = qtype.applyDATAFunction();
2727            if (qtype == null || !qtype.isAtom())
2728                throw new TypeException("Function call get-month-from-date '" + arg + "', argument has invalid type, not an atom");
2729        }
2730        if (!qtype.canBeCastedInto(QType.PRIMITIVE_date))
2731            throw new TypeException("Function call get-month-from-date '" + arg + "', argument has type that can not be casted");
2732
2733        //if (!(argument instanceof ValueString))
2734
// throw new TypeException("Function call decimal '" + arg + "', argument is not a string literal");
2735
if (expr instanceof ValueString) {
2736            try {
2737                SimpleType simpleType = context.getSchemaManager().getDateType();
2738                String JavaDoc dateValue = simpleType.normalizedValue(((ValueString) expr).getValue());
2739                simpleType.validate(dateValue, false, null);
2740                ((ValueString) expr).setValue(dateValue);
2741            } catch (SchemaException se) {
2742                throw new TypeException("Function call get-month-from-date '" + arg + "', argument is string with invalid format");
2743            }
2744        }
2745        // type setting
2746
arg.setQType(new QTypeAtom(context.getSchemaManager().getIntegerType()));
2747    }
2748
2749    public void visit(FunctionGET_YEAR_FROM_DATE arg) throws XQueryException {
2750        // TYPE VERIFICATION
2751
// argument must be a date
2752
// TYPE BUILDING
2753
// the return type is an integer
2754

2755        // type checking
2756
if (noForce && arg.getQType() != null)
2757            return;
2758        ArrayList arguments = arg.getArguments();
2759        XQueryExpression expr = (XQueryExpression) arguments.get(0);
2760        // forward checking and typing
2761
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2762            if (expr.getQType() == null)
2763                return;
2764        if (/*!noForce ||*/
2765            expr.getQType() == null)
2766            expr.accept(this);
2767        if (expr.getQType() == null)
2768            throw new TypeException("Function call lower-case '" + arg + "', argument could not be typed"); // return;
2769
// CHANGE
2770
QType qtype = expr.getQType();
2771        if (!qtype.isAtom()) {
2772            qtype = qtype.applyDATAFunction();
2773            if (qtype != null || !qtype.isAtom())
2774                throw new TypeException("Function call get-month-from-date '" + arg + "', argument has invalid type, not an atom");
2775        }
2776        if (!qtype.canBeCastedInto(QType.PRIMITIVE_date))
2777            throw new TypeException("Function call get-month-from-date '" + arg + "', argument has type that can not be casted");
2778
2779        //if (!(argument instanceof ValueString))
2780
// throw new TypeException("Function call decimal '" + arg + "', argument is not a string literal");
2781
if (expr instanceof ValueString) {
2782            try {
2783                SimpleType simpleType = context.getSchemaManager().getDateType();
2784                String JavaDoc dateValue = simpleType.normalizedValue(((ValueString) expr).getValue());
2785                simpleType.validate(dateValue, false, null);
2786                ((ValueString) expr).setValue(dateValue);
2787            } catch (SchemaException se) {
2788                throw new TypeException("Function call get-month-from-date '" + arg + "', argument is string with invalid format");
2789            }
2790        }
2791        // type setting
2792
arg.setQType(new QTypeAtom(context.getSchemaManager().getIntegerType()));
2793    }
2794
2795    public void visit(FunctionINTEGER arg) throws XQueryException {
2796        // TYPE VERIFICATION
2797
// arguments must be numeric
2798
// TYPE BUILDING
2799
// the return type is a numeric
2800

2801        // type checking
2802
if (noForce && arg.getQType() != null)
2803            return;
2804        ArrayList arguments = arg.getArguments();
2805        XQueryExpression expr = (XQueryExpression) arguments.get(0);
2806        // forward checking and typing
2807
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2808            if (expr.getQType() == null)
2809                return;
2810        if (/*!noForce ||*/
2811            expr.getQType() == null)
2812            expr.accept(this);
2813        if (expr.getQType() == null)
2814            throw new TypeException("Function call integer '" + arg + "', argument could not be typed"); // return;
2815
QType qtype = expr.getQType();
2816        if (!qtype.canBeCastedInto(QType.PRIMITIVE_decimal))
2817            throw new TypeException("Function call integer '" + arg + "', argument has type that can not be casted");
2818        if (expr instanceof ValueString) {
2819            try {
2820                SimpleType simpleType = context.getSchemaManager().getIntegerType();
2821                String JavaDoc value = simpleType.normalizedValue(((ValueString) expr).getValue());
2822                simpleType.validate(value, false, null);
2823                ((ValueString) expr).setValue(value);
2824            } catch (SchemaException se) {
2825                throw new TypeException("Function call float '" + arg + "', argument is string with invalid format");
2826            }
2827        }
2828        // type setting
2829
arg.setQType(new QTypeAtom(context.getSchemaManager().getIntegerType()));
2830    }
2831
2832    public void visit(FunctionLOCAL_NAME arg) throws XQueryException {
2833        // TYPE VERIFICATION
2834
// arguments must be sequence
2835
// TYPE BUILDING
2836
// the return type is a string
2837

2838        // type checking
2839
if (noForce && arg.getQType() != null)
2840            return;
2841        ArrayList arguments = arg.getArguments();
2842        XQueryExpression expr = (XQueryExpression) arguments.get(0);
2843        // forward checking and typing
2844
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2845            if (expr.getQType() == null)
2846                return;
2847        if (/*!noForce ||*/
2848            expr.getQType() == null)
2849            expr.accept(this);
2850        if (expr.getQType() == null)
2851            throw new TypeException("Function call local-name'" + arg + "', argument could not be typed"); // return;
2852
// type verification
2853
QType qtype = expr.getQType();
2854        if (!qtype.isNode())
2855            throw new TypeException("Function call local-name '" + arg + "', argument is not a node");
2856        if (!qtype.isAtomic() /*&& !inPredicate*/)
2857            throw new TypeException("Function call local-name '" + arg + "', argument is not an atomic value.'");
2858        // type setting
2859
arg.setQType(new QTypeAtom((SimpleType) getType(SC_STRING)));
2860    }
2861
2862    public void visit(FunctionLOWER_CASE arg) throws XQueryException {
2863        // TYPE VERIFICATION
2864
// arguments must be sequence
2865
// TYPE BUILDING
2866
// the return type is a string
2867

2868        // type checking
2869
if (noForce && arg.getQType() != null)
2870            return;
2871        ArrayList arguments = arg.getArguments();
2872        XQueryExpression expr = (XQueryExpression) arguments.get(0);
2873        // forward checking and typing
2874
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2875            if (expr.getQType() == null)
2876                return;
2877        if (/*!noForce ||*/
2878            expr.getQType() == null)
2879            expr.accept(this);
2880        if (expr.getQType() == null)
2881            throw new TypeException("Function call lower-case '" + arg + "', argument could not be typed"); // return;
2882
// type verification
2883
QType qtype = expr.getQType();
2884        if (!qtype.isString())
2885            throw new TypeException("Function call lower-case '" + arg + "', argument is not a string");
2886        if (!qtype.isAtomic() /*&& !inPredicate*/)
2887            throw new TypeException("Function call lower-case '" + arg + "', argument is not an atomic value.'");
2888        // type setting
2889
arg.setQType(new QTypeAtom((SimpleType) getType(SC_STRING)));
2890    }
2891
2892    public void visit(FunctionMATCHES arg) throws XQueryException {
2893        // TYPE VERIFICATION
2894
// arguments must be sequence
2895
// TYPE BUILDING
2896
// the return type is a string
2897

2898        // type checking
2899
if (noForce && arg.getQType() != null)
2900            return;
2901        ArrayList arguments = arg.getArguments();
2902        // forward checking and typing, and verification
2903
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2904            for (int i = 0; i < arguments.size(); i++)
2905                if (((XQueryExpression) arguments.get(i)).getQType() == null)
2906                    return;
2907        for (int i = 0; i < arguments.size(); i++) {
2908            XQueryExpression expri = (XQueryExpression) arguments.get(i);
2909            if (/*!noForce ||*/
2910                expri.getQType() == null)
2911                expri.accept(this);
2912            if (expri.getQType() == null) //return;
2913
throw new TypeException("Function call match '" + arg + "', argument " + (i + 1) + " could not be typed"); // return;
2914
if (!expri.getQType().isString())
2915                throw new TypeException("Function call match '" + arg + "', argument " + (i + 1) + " is not a string");
2916            if (!expri.getQType().isAtomic() /*&& !inPredicate*/)
2917                throw new TypeException("Function call match '" + arg + "', argument " + (i + 1) + " is not an atomic value.'");
2918        }
2919        // type setting
2920
arg.setQType(new QTypeAtom((SimpleType) getType(SC_INTEGER), QType.OCC_0_N));
2921    }
2922
2923    public void visit(FunctionMAX arg) throws XQueryException {
2924        // TYPE VERIFICATION
2925
// arguments must be numeric
2926
// TYPE BUILDING
2927
// the return type is a numeric
2928

2929        // type checking
2930
if (noForce && arg.getQType() != null)
2931            return;
2932        ArrayList arguments = arg.getArguments();
2933        XQueryExpression expr = (XQueryExpression) arguments.get(0);
2934        // forward checking and typing
2935
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2936            if (expr.getQType() == null)
2937                return;
2938        if (/*!noForce ||*/
2939            expr.getQType() == null)
2940            expr.accept(this);
2941        if (expr.getQType() == null)
2942            throw new TypeException("Function call max '" + arg + "', argument could not be typed"); // return;
2943
// type verification
2944
QType qtype = expr.getQType();
2945        /*
2946        if (!(qtype instanceof QTypeAtom) || (!qtype.isNumeric() && !qtype.isDate() && !qtype.isString() && !qtype.isDuration()))
2947            qtype = qtype.applyDATAFunction();
2948        if (qtype == null || (!qtype.isNumeric() && !qtype.isDate() && !qtype.isString() && !qtype.isDuration()))
2949            throw new TypeException("Function call max '" + arg + "', argument is not numeric, date, duration or string");
2950        */

2951        if (!qtype.isAtom())
2952            qtype = qtype.applyDATAFunction();
2953        if (qtype == null || !qtype.isAtom())
2954            throw new TypeException("Function call max '" + arg + "', argument has incorrect type");
2955        // type setting
2956
//arg.setQType(new QTypeAtom((SimpleType) getType(SC_DOUBLE)));
2957
if (qtype.getSubClass() == QType.SEQUENCE || qtype.getSubClass() == QType.UNION)
2958            arg.setQType(new QTypeAtom((SimpleType) getType(SC_DOUBLE)));
2959        else {
2960            if (qtype.getOccurence() != QType.OCC_1_1)
2961                qtype = qtype.changeOccurence(QType.OCC_1_1);
2962            arg.setQType(qtype);
2963        }
2964    }
2965
2966    public void visit(FunctionMIN arg) throws XQueryException {
2967        // TYPE VERIFICATION
2968
// arguments must be numeric
2969
// TYPE BUILDING
2970
// the return type is a numeric
2971

2972        // type checking
2973
if (noForce && arg.getQType() != null)
2974            return;
2975        ArrayList arguments = arg.getArguments();
2976        XQueryExpression expr = (XQueryExpression) arguments.get(0);
2977        // forward checking and typing
2978
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
2979            if (expr.getQType() == null)
2980                return;
2981        if (/*!noForce ||*/
2982            expr.getQType() == null)
2983            expr.accept(this);
2984        if (expr.getQType() == null)
2985            throw new TypeException("Function call min '" + arg + "', argument could not be typed"); // return;
2986
// type verification
2987
QType qtype = expr.getQType();
2988        /*
2989        if (!(qtype instanceof QTypeAtom) || (!qtype.isNumeric() && !qtype.isDate() && !qtype.isString() && !qtype.isDuration()))
2990            qtype = qtype.applyDATAFunction();
2991        if (qtype == null || (!qtype.isNumeric() && !qtype.isDate() && !qtype.isString() && !qtype.isDuration()))
2992            throw new TypeException("Function call min '" + arg + "', argument is not numeric, date, duration or string");
2993        */

2994        if (!qtype.isAtom())
2995            qtype = qtype.applyDATAFunction();
2996        if (qtype == null || !qtype.isAtom())
2997            throw new TypeException("Function call min '" + arg + "', argument has incorrect type");
2998        // type setting
2999
//arg.setQType(new QTypeAtom((SimpleType) getType(SC_DOUBLE)));
3000
if (qtype.getSubClass() == QType.SEQUENCE || qtype.getSubClass() == QType.UNION)
3001            arg.setQType(new QTypeAtom((SimpleType) getType(SC_DOUBLE)));
3002        else {
3003            if (qtype.getOccurence() != QType.OCC_1_1)
3004                qtype = qtype.changeOccurence(QType.OCC_1_1);
3005            arg.setQType(qtype);
3006        }
3007    }
3008
3009    public void visit(FunctionNAMESPACE_URI arg) throws XQueryException {
3010        // TYPE VERIFICATION
3011
// arguments must be sequence
3012
// TYPE BUILDING
3013
// the return type is a string
3014

3015        // type checking
3016
if (noForce && arg.getQType() != null)
3017            return;
3018        ArrayList arguments = arg.getArguments();
3019        XQueryExpression expr = (XQueryExpression) arguments.get(0);
3020        // forward checking and typing
3021
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
3022            if (expr.getQType() == null)
3023                return;
3024        if (/*!noForce ||*/
3025            expr.getQType() == null)
3026            expr.accept(this);
3027        if (expr.getQType() == null)
3028            throw new TypeException("Function call namespace-uri'" + arg + "', argument could not be typed"); // return;
3029
// type verification
3030
QType qtype = expr.getQType();
3031        if (!qtype.isNode())
3032            throw new TypeException("Function call namespace-uri '" + arg + "', argument is not a node");
3033        if (!qtype.isAtomic() /*&& !inPredicate*/)
3034            throw new TypeException("Function call local-name '" + arg + "', argument is not an atomic value.'");
3035        // type setting
3036
arg.setQType(new QTypeAtom((SimpleType) getType(SC_STRING)));
3037    }
3038
3039    public void visit(FunctionNOT arg) throws XQueryException {
3040        // TYPE VERIFICATION
3041
// arguments must be boolean
3042
// TYPE BUILDING
3043
// the return type is a boolean
3044

3045        // type checking
3046
if (noForce && arg.getQType() != null)
3047            return;
3048        ArrayList arguments = arg.getArguments();
3049        XQueryExpression expr = (XQueryExpression) arguments.get(0);
3050        // forward checking and typing
3051
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
3052            if (expr.getQType() == null)
3053                return;
3054        if (/*!noForce ||*/
3055            expr.getQType() == null)
3056            expr.accept(this);
3057        if (expr.getQType() == null)
3058            throw new TypeException("Function call not '" + arg + "', argument could not be typed"); // return;
3059
// type verification
3060
if (!expr.getQType().isBoolean())
3061            throw new TypeException("Function call not '" + arg + "', argument is not a boolean");
3062        // type setting
3063
arg.setQType(new QTypeAtom((SimpleType) getType(SC_BOOLEAN)));
3064    }
3065
3066    public void visit(FunctionNUMBER arg) throws XQueryException {
3067        // TYPE VERIFICATION
3068
// arguments must be an element
3069
// TYPE BUILDING
3070
// returns the content of an element expressed as a number
3071

3072        // type checking
3073
if (noForce && arg.getQType() != null)
3074            return;
3075        ArrayList arguments = arg.getArguments();
3076        if (arguments != null) {
3077            XQueryExpression expr = (XQueryExpression) arguments.get(0);
3078            // forward checking and typing
3079
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
3080                if (expr.getQType() == null)
3081                    return;
3082            if (/*!noForce ||*/
3083                expr.getQType() == null)
3084                expr.accept(this);
3085            if (expr.getQType() == null)
3086                throw new TypeException("Function call number '" + arg + "', argument could not be typed"); // return;
3087
// type verification
3088
if (!expr.getQType().isSimpleTypeNode())
3089                throw new TypeException("Function call number '" + arg + "', argument is not a simple node or collection of simple nodes");
3090        }
3091        // type setting
3092
arg.setQType(new QTypeAtom((SimpleType) getType(SC_FLOAT)));
3093    }
3094
3095    // public void visit(FunctionPOSITION arg) throws XQueryException {
3096
// // TYPE VERIFICATION
3097
// // arguments must be an element
3098
// // TYPE BUILDING
3099
// // returns the content of an element expressed as a number
3100
//
3101
// ArrayList arguments = arg.getArguments();
3102
// // type checking
3103
// if (noForce && arg.getQType() != null)
3104
// return;
3105
// // type setting
3106
// arg.setQType(new QTypeAtom((SimpleType) getType(SC_INTEGER)));
3107
// }
3108

3109    public void visit(FunctionQNAME arg) throws XQueryException {
3110        if (noForce && arg.getQType() != null)
3111            return;
3112
3113        ArrayList arguments = arg.getArguments();
3114        XQueryExpression expr = (XQueryExpression) arguments.get(0);
3115        // forward checking and typing
3116
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
3117            if (expr.getQType() == null)
3118                return;
3119        if (/*!noForce ||*/
3120            expr.getQType() == null)
3121            expr.accept(this);
3122        if (expr.getQType() == null) //return;
3123
throw new TypeException("Function call QName '" + arg + "', argument could not be typed"); // return;
3124
if (!expr.getQType().isAtom() || !expr.getQType().isString())
3125            throw new TypeException("Function call QName '" + arg + "', argument is not an atomic string.'");
3126        // type setting
3127
arg.setQType(new QTypeAtom((SimpleType) getType(SC_QNAME)));
3128    }
3129
3130    public void visit(FunctionROUND arg) throws XQueryException {
3131        // TYPE VERIFICATION
3132
// arguments must be numeric
3133
// TYPE BUILDING
3134
// the return type is a numeric
3135

3136        // type checking
3137
if (noForce && arg.getQType() != null)
3138            return;
3139        ArrayList arguments = arg.getArguments();
3140        XQueryExpression expr = (XQueryExpression) arguments.get(0);
3141        // forward checking and typing
3142
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
3143            if (expr.getQType() == null)
3144                return;
3145        if (/*!noForce ||*/
3146            expr.getQType() == null)
3147            expr.accept(this);
3148        if (expr.getQType() == null)
3149            throw new TypeException("Function call round '" + arg + "', argument could not be typed"); // return;
3150
// type verification
3151
QType qtype = expr.getQType();
3152        if (!qtype.isNumeric())
3153            qtype = qtype.applyDATAFunction();
3154        if (qtype == null || !qtype.isNumeric())
3155            throw new TypeException("Function call round '" + arg + "', argument is not numeric");
3156        // type setting
3157
arg.setQType(new QTypeAtom((SimpleType) getType(SC_INTEGER)));
3158    }
3159
3160    public void visit(FunctionSTARTS_WITH arg) throws XQueryException {
3161        // TYPE VERIFICATION
3162
// arguments must be sequence
3163
// TYPE BUILDING
3164
// the return type is a boolean
3165

3166        // type checking
3167
if (noForce && arg.getQType() != null)
3168            return;
3169        ArrayList arguments = arg.getArguments();
3170        // forward checking and typing, and verification
3171
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
3172            for (int i = 0; i < arguments.size(); i++)
3173                if (((XQueryExpression) arguments.get(i)).getQType() == null)
3174                    return;
3175        for (int i = 0; i < arguments.size(); i++) {
3176            XQueryExpression expri = (XQueryExpression) arguments.get(i);
3177            if (/*!noForce ||*/
3178                expri.getQType() == null)
3179                expri.accept(this);
3180            if (expri.getQType() == null) //return;
3181
throw new TypeException("Function call starts-with '" + arg + "', argument " + (i + 1) + " could not be typed"); // return;
3182
if (!expri.getQType().isString())
3183                throw new TypeException("Function call starts-with '" + arg + "', argument " + (i + 1) + " is not a string");
3184            if (!expri.getQType().isAtomic() /*&& !inPredicate*/)
3185                throw new TypeException("Function call starts-with '" + arg + "', argument " + (i + 1) + " is not an atomic value.'");
3186        }
3187        // type setting
3188
arg.setQType(new QTypeAtom((SimpleType) getType(SC_BOOLEAN)));
3189    }
3190
3191    public void visit(FunctionSTRING arg) throws XQueryException {
3192        // TYPE VERIFICATION
3193
/*
3194        The string function converts its argument to a string according to the following rules
3195        A number is converted to a string as follows:
3196            NaN is converted to the string NaN.
3197            Positive zero is converted to the string 0.
3198            Negative zero is converted to the string 0.
3199            Positive infinity is converted to the string Infinity.
3200            Negative infinity is converted to the string -Infinity.
3201            If the number is an integer, the number is represented in decimal form with no decimal point and no leading zeros, preceded by a minus sign (-) if the number is negative.
3202            Otherwise, the number is represented in decimal form including a decimal point with at least one digit before the decimal point and at least one digit after the decimal point, preceded by a minus sign (-) if the number is negative; there must be no leading zeros before the decimal point apart possibly from the one required digit immediately before the decimal point; beyond the one required digit after the decimal point there must be as many, but only as many, more digits as are needed to uniquely distinguish the number from all other IEEE 754 numeric values.
3203        The boolean false value is converted to the string false. The boolean true value is converted to the string true.
3204        An object of a type other than the above types is converted to a string in a way that is dependent on that type.
3205        If the argument is omitted, it defaults to a node-set with the context node as its only member
3206         */

3207        // each argument must be either
3208
// - element
3209
// - attribute
3210
// - union (with at least a member being node)
3211
// - collection (of one of the previous types)
3212
// TYPE BUILDING
3213
// returns the content of an element expressed as a string
3214

3215        // type checking
3216
if (noForce && arg.getQType() != null)
3217            return;
3218        ArrayList arguments = arg.getArguments();
3219        XQueryExpression expr = (XQueryExpression) arguments.get(0);
3220        // forward checking and typing
3221
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
3222            if (expr.getQType() == null)
3223                return;
3224        if (/*!noForce ||*/
3225            expr.getQType() == null)
3226            expr.accept(this);
3227        if (expr.getQType() == null)
3228            throw new TypeException("Function call string '" + arg + "', argument could not be typed"); // return;
3229
// type verification
3230
QType qtype = expr.getQType();
3231        // type verification
3232
//if (!qtype.isAtom()) qtype = qtype.applyDATAFunction();
3233
if (qtype == null || (!qtype.isAtomic() && !inPredicate && !qtype.isSimpleTypeNode()))
3234            throw new TypeException("Function call string '" + arg + "', argument must be an atomic value or simple content element.");
3235        // type setting
3236
arg.setQType(new QTypeAtom((SimpleType) getType(SC_STRING), qtype.isMultiple() ? QType.OCC_0_N : QType.OCC_1_1));
3237        // if (qtype instanceof QTypeCollection)
3238
// arg.setQType(new QTypeCollection(new QTypeAtom((SimpleType) getType(SC_STRING))));
3239
// else
3240
// arg.setQType(new QTypeAtom((SimpleType) getType(SC_STRING)));
3241
}
3242
3243    public void visit(FunctionSTRING_LENGTH arg) throws XQueryException {
3244        // TYPE VERIFICATION
3245
// arguments must be sequence
3246
// TYPE BUILDING
3247
// the return type is a boolean
3248

3249        // type checking
3250
if (noForce && arg.getQType() != null)
3251            return;
3252        ArrayList arguments = arg.getArguments();
3253        XQueryExpression expr = (XQueryExpression) arguments.get(0);
3254        // forward checking and typing
3255
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
3256            if (expr.getQType() == null)
3257                return;
3258        // type verification
3259
if (/*!noForce ||*/
3260            expr.getQType() == null)
3261            expr.accept(this);
3262        if (expr.getQType() == null) //return;
3263
throw new TypeException("Function call string-length '" + arg + "', argument could not be typed"); // return;
3264
if (!expr.getQType().isString())
3265            throw new TypeException("Function call string-length '" + arg + "', argument is not a string");
3266        if (!expr.getQType().isAtomic() /*&& !inPredicate*/)
3267            throw new TypeException("Function call string-length '" + arg + "', argument is not an atomic value.'");
3268        // type setting
3269
arg.setQType(new QTypeAtom((SimpleType) getType(SC_INTEGER)));
3270    }
3271
3272    public void visit(FunctionSUBSTRING arg) throws XQueryException {
3273        // TYPE VERIFICATION
3274
// arguments must be sequence
3275
// TYPE BUILDING
3276
// the return type is a string
3277

3278        // type checking
3279
if (noForce && arg.getQType() != null)
3280            return;
3281        ArrayList arguments = arg.getArguments();
3282        // forward checking and typing, and verification
3283
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
3284            for (int i = 0; i < arguments.size(); i++)
3285                if (((XQueryExpression) arguments.get(i)).getQType() == null)
3286                    return;
3287        for (int i = 0; i < arguments.size(); i++) {
3288            XQueryExpression expri = (XQueryExpression) arguments.get(i);
3289            if (/*!noForce ||*/
3290                expri.getQType() == null)
3291                expri.accept(this);
3292            if (expri.getQType() == null) //return;
3293
throw new TypeException("Function call substring '" + arg + "', argument " + (i + 1) + " could not be typed"); // return;
3294
if (i == 0 && !expri.getQType().isString())
3295                throw new TypeException("Function call substring '" + arg + "', argument " + (i + 1) + " is not a string");
3296            if (i != 0 && !expri.getQType().isNumeric())
3297                throw new TypeException("Function call substring '" + arg + "', argument " + (i + 1) + " is not numeric");
3298        }
3299        // type setting
3300
arg.setQType(new QTypeAtom((SimpleType) getType(SC_STRING)));
3301    }
3302
3303    public void visit(FunctionSUM arg) throws XQueryException {
3304        // TYPE VERIFICATION
3305
// arguments must be numeric (or can be casted into a numeric)
3306
// each argument must be either
3307
// - atom
3308
// - attribute (hopefully the value can be casted into a numeric)
3309
// - union (with at least a member being numeric)
3310
// - collection (of one of the previous types)
3311
// TYPE BUILDING
3312
// the return type is a float
3313

3314        // type checking
3315
if (noForce && arg.getQType() != null)
3316            return;
3317        ArrayList arguments = arg.getArguments();
3318        XQueryExpression expr = (XQueryExpression) arguments.get(0);
3319        // forward checking and typing
3320
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
3321            if (expr.getQType() == null)
3322                return;
3323        if (/*!noForce ||*/
3324            expr.getQType() == null)
3325            expr.accept(this);
3326        if (expr.getQType() == null)
3327            throw new TypeException("Function call sum '" + arg + "', argument could not be typed"); // return;
3328
// type verification
3329
QType qtype = expr.getQType();
3330        /*
3331        if (!(qtype instanceof QTypeAtom) || (!qtype.isNumeric() && !qtype.isDuration()))
3332            qtype = qtype.applyDATAFunction();
3333        if (qtype == null || (!qtype.isNumeric() && !qtype.isDuration()))
3334            throw new TypeException("Function call sum '" + arg + "', argument is not numeric or duration");
3335        */

3336        if (!qtype.isAtom())
3337            qtype = qtype.applyDATAFunction();
3338        if (qtype == null || !qtype.isAtom())
3339            throw new TypeException("Function call sum '" + arg + "', argument has incorrect type");
3340        // type setting
3341
if (qtype.getSubClass() == QType.SEQUENCE || qtype.getSubClass() == QType.UNION)
3342            arg.setQType(new QTypeAtom((SimpleType) getType(SC_DOUBLE)));
3343        else {
3344            PrimitiveType primType = ((SimpleType) qtype.getType()).getPrimitive();
3345            int prim = primType.getType();
3346            switch (prim) {
3347                case PrimitiveType.FLOAT :
3348                    arg.setQType(new QTypeAtom((SimpleType) getType(SC_FLOAT)));
3349                    break;
3350                case PrimitiveType.DECIMAL :
3351                    if (primType.getFractionDigits() == 0)
3352                        arg.setQType(new QTypeAtom((SimpleType) getType(SC_INTEGER)));
3353                    else
3354                        arg.setQType(new QTypeAtom((SimpleType) getType(SC_DECIMAL)));
3355                    break;
3356                case PrimitiveType.DOUBLE :
3357                    arg.setQType(new QTypeAtom((SimpleType) getType(SC_DOUBLE)));
3358                    break;
3359                default :
3360                    arg.setQType(new QTypeAtom((SimpleType) getType(SC_DOUBLE)));
3361                    break;
3362            }
3363        }
3364        //arg.setQType(new QTypeAtom((SimpleType) getType(SC_DOUBLE)));
3365
}
3366
3367    public void visit(FunctionTIME arg) throws XQueryException {
3368        // but it exists signature like xf:current-dateTime() => date
3369
// TYPE VERIFICATION
3370
// 0 arguments
3371
// TYPE BUILDING
3372
// the return type is a simpleType date
3373

3374        // type checking
3375
if (noForce && arg.getQType() != null)
3376            return;
3377        XQueryExpression argument = (XQueryExpression) arg.getArguments().get(0);
3378        // forward checking and typing, and verification
3379
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
3380            if (argument.getQType() == null)
3381                return;
3382        if (!(argument instanceof ValueString))
3383            throw new TypeException("Function call time '" + arg + "', argument is not a string literal");
3384        try {
3385            SimpleType simpleType = context.getSchemaManager().getTimeType();
3386            String JavaDoc timeValue = simpleType.normalizedValue(((ValueString) argument).getValue());
3387            simpleType.validate(timeValue, false, null);
3388            ((ValueString) argument).setValue(timeValue);
3389        } catch (SchemaException se) {
3390            throw new TypeException("Function call time '" + arg + "', argument has invalid datetime format");
3391        }
3392        // type setting
3393
arg.setQType(new QTypeAtom(context.getSchemaManager().getTimeType()));
3394    }
3395
3396    public void visit(FunctionTRUE arg) throws XQueryException {
3397        // TYPE VERIFICATION
3398
// TYPE BUILDING
3399
// the return type is a boolean atom
3400

3401        // type checking
3402
if (noForce && arg.getQType() != null)
3403            return;
3404        // type setting
3405
arg.setQType(new QTypeAtom((SimpleType) getType(SC_BOOLEAN)));
3406    }
3407
3408    public void visit(FunctionUPPER_CASE arg) throws XQueryException {
3409        // TYPE VERIFICATION
3410
// arguments must be sequence
3411
// TYPE BUILDING
3412
// the return type is a string
3413

3414        // type checking
3415
if (noForce && arg.getQType() != null)
3416            return;
3417        ArrayList arguments = arg.getArguments();
3418        XQueryExpression expr = (XQueryExpression) arguments.get(0);
3419        // forward checking and typing
3420
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
3421            if (expr.getQType() == null)
3422                return;
3423        if (/*!noForce ||*/
3424            expr.getQType() == null)
3425            expr.accept(this);
3426        if (expr.getQType() == null)
3427            throw new TypeException("Function call upper-case '" + arg + "', argument could not be typed"); // return;
3428
// type verification
3429
QType qtype = expr.getQType();
3430        if (!qtype.isString())
3431            throw new TypeException("Function call upper-case '" + arg + "', argument is not a string");
3432        if (!qtype.isAtomic() /*&& !inPredicate*/)
3433            throw new TypeException("Function call upper-case '" + arg + "', argument is not an atomic value.'");
3434        // type setting
3435
arg.setQType(new QTypeAtom((SimpleType) getType(SC_STRING)));
3436    }
3437
3438    public void visit(FunctionDEEP_EQUALS arg) throws XQueryException {
3439        // TYPE VERIFICATION
3440
// arguments must be sequence
3441
// TYPE BUILDING
3442
// the return type is a boolean
3443

3444        // type checking
3445
if (noForce && arg.getQType() != null)
3446            return;
3447
3448        ArrayList arguments = arg.getArguments();
3449        // forward checking and typing, and verification
3450
if ((contextXNodes == null || contextXNodes.isEmpty()) && contextQType == null)
3451            for (int i = 0; i < arguments.size(); i++)
3452                if (((XQueryExpression) arguments.get(i)).getQType() == null)
3453                    return;
3454        for (int i = 0; i < arguments.size(); i++) {
3455            XQueryExpression expri = (XQueryExpression) arguments.get(i);
3456            if (/*!noForce ||*/
3457                expri.getQType() == null)
3458                expri.accept(this);
3459            if (expri.getQType() == null) //return;
3460
throw new TypeException("Function call deep-equals '" + arg + "', argument " + (i + 1) + " could not be typed"); // return;
3461
if (!expri.getQType().isAtomic() /*&& !inPredicate*/)
3462                throw new TypeException("Function call deep-equals '" + arg + "', argument " + (i + 1) + " is not an atomic value.'");
3463        }
3464        // type setting
3465
arg.setQType(new QTypeAtom((SimpleType) getType(SC_BOOLEAN)));
3466    }
3467
3468    //*******************************************************************************************
3469
// UTLITIES
3470
//*******************************************************************************************
3471
private Type getType(String JavaDoc typeStr) {
3472        return context.getSchemaManager().getType(XML_SCHEMA, typeStr);
3473    }
3474
3475    private QType buildQTypeFromXNodes(ArrayList schemaNodes, byte occurence) throws XQueryException {
3476        return buildQTypeFromXNodes(schemaNodes, occurence, null, false);
3477    }
3478
3479    private QType buildQTypeFromXNodes(ArrayList schemaNodes, byte occurence, XQueryExpression expr, boolean verify) throws XQueryException {
3480        if (schemaNodes == null || schemaNodes.isEmpty())
3481            return null;
3482
3483        QType retQType = null;
3484        ArrayList list = new ArrayList(schemaNodes.size());
3485        QType tmpQType = null;
3486        for (int i = 0; i < schemaNodes.size(); i++) {
3487            TypedXTreeNode typedXTreeNode = (TypedXTreeNode) schemaNodes.get(i);
3488            Declaration decl = typedXTreeNode.getDeclaration();
3489            if (decl == null) {
3490                if (typedXTreeNode.getLocalName() != null) {
3491                    // // TODO check if test is correct
3492
if (typedXTreeNode.getChildren() == null) {
3493                        SimpleType type = context.getSchemaManager().getAnySimpleType();
3494                        tmpQType = new QTypeAttribute(new QName(typedXTreeNode.getNamespace(), null, typedXTreeNode.getLocalName(), null, null), type, QType.computeOccurence(occurence, QType.OCC_0_1));
3495                    } else
3496                        tmpQType = new QTypeElement(new QName(typedXTreeNode.getNamespace(), null, typedXTreeNode.getLocalName(), null, null), getType(SC_ANYTYPE), QType.OCC_0_N);
3497                } else {
3498                    // TODO find out why this case happens --> collection("ITEMS")//DESCRIPTION
3499
// for now do nothing
3500
}
3501            } else
3502                tmpQType = getQTypeFromDeclaration(decl, occurence);
3503            list.add(tmpQType);
3504        }
3505        if (list.isEmpty())
3506            if (verify)
3507                throw new TypeException("Could not find declaration(s) of expression '" + expr + "'");
3508            else
3509                return null;
3510        else if (list.size() == 1)
3511            return (QType) list.get(0);
3512        return makeUnion(list);
3513    }
3514
3515    private QType getQTypeFromDeclaration(Declaration decl, byte occurence) throws XQueryException {
3516        if (decl == null)
3517            return null;
3518        // throw new TypeException("Expression not found in metadata");
3519
QType retQType = null;
3520        QName qname = new QName(decl.getNamespace(), null, decl.getName(), null, null);
3521        if (decl instanceof AttributeDeclaration)
3522            retQType = new QTypeAttribute(qname, (AttributeDeclaration) decl, (SimpleType) decl.getType(), QType.computeOccurence(occurence, (((AttributeDeclaration) decl).getUse() == AttributeDeclaration.REQUIRED) ? QType.OCC_1_1 : QType.OCC_0_1));
3523        if (decl instanceof ElementDeclaration) {
3524            byte elemOccurence = QType.OCC_1_1;
3525            ElementDeclaration eltDecl = (ElementDeclaration) decl;
3526            SchemaScope scopeType = eltDecl.getScope(); // see zhang yun for always true!
3527
if (scopeType != null && scopeType instanceof ComplexType) {
3528                int size[] = ((ComplexType) scopeType).getDeclarationOccurrence(eltDecl.getNamespace(), eltDecl.getName());
3529                elemOccurence = QType.getOccurence(size[0], size[1]);
3530            }
3531            retQType = new QTypeElement(qname, decl.getType(), QType.computeOccurence(occurence, elemOccurence));
3532            // if (multi)
3533
// retQType = new QTypeCollection(new QTypeElement(qname, decl.getType()));
3534
// else
3535
// retQType = new QTypeElement(qname, decl.getType());
3536
}
3537        return retQType;
3538    }
3539
3540    private QType makeUnion(ArrayList list) throws XQueryException {
3541        if (list == null || list.isEmpty())
3542            return null;
3543        // check special case : only simple types with same name and diffrent namespaces
3544
for (int i = 0; i < list.size(); i++) {
3545            QType qtypei = (QType) list.get(i);
3546            Type typei = qtypei.getType();
3547            if (typei != null) {
3548            }
3549        }
3550        for (int i = 0; i < list.size() - 1; i++) {
3551            QType qtypei = (QType) list.get(i);
3552            for (int j = i + 1; j < list.size(); j++) {
3553                if (qtypei.equals((QType) list.get(j))) {
3554                    list.remove(j);
3555                    j--;
3556                }
3557            }
3558        }
3559        if (list.size() == 1)
3560            return (QType) list.get(0);
3561        return new QTypeUnion(list);
3562    }
3563
3564    private QTypeElement buildQTypeElementFromSubElements(XQueryExpression name, Set allElements) throws XQueryException {
3565        int size = allElements.size();
3566        ElementTools eTools = new ElementTools(size, name);
3567        // case of <tag/>
3568
if (size == 0)
3569            return new QTypeElement(name, getType(SC_ANYTYPE));
3570        ComplexType complexType = new ComplexType(this.typingschema, null, null);
3571        //complexType.setRequiredAndDefaultAttributes(new ArrayList());
3572

3573        SequenceModelGroup sequenceModel = new SequenceModelGroup();
3574        QTypeElement qte = null;
3575        // try {
3576
for (Iterator it = allElements.iterator();it.hasNext();) {
3577            QType qtype = ((XQueryExpression) it.next()).getQType();
3578            int subclass = qtype.getSubClass();
3579            if (subclass == QType.ATOM) {
3580                // case of <tag> [simpleType] </tag>, like <a> 23 </a>
3581
if (size == 1)
3582                    return new QTypeElement(name, qtype.getSimpleType() == null ? getType(SC_ANYTYPE) : qtype.getSimpleType());
3583                else
3584                    buildQTypeAtom(eTools, qtype);
3585            } else if (subclass == QType.TEXT) {
3586                if (size == 1)
3587                    return new QTypeElement(name, qtype.getSimpleType() == null ? getType(SC_ANYTYPE) : qtype.getSimpleType());
3588                else
3589                    buildQTypeText(eTools, qtype);
3590            } else if (subclass == QType.ATTRIBUTE) {
3591                buildQTypeAttribute(eTools, (QTypeAttribute)qtype, complexType);
3592            } else if (subclass == QType.ELEMENT) {
3593                buildQTypeElement(eTools, qtype, complexType, sequenceModel, qtype.getMinOccurence() == 1, qtype.isMultiple());
3594            } else if (subclass == QType.UNION) {
3595                buildQTypeUnion(eTools, qtype, complexType, sequenceModel);
3596            } else if (subclass == QType.SEQUENCE) {
3597                qte = buildQTypeSequence(eTools, qtype, complexType, sequenceModel);
3598                if (qte != null)
3599                    return qte;
3600            }
3601        }
3602        // case of <tag> [simpleType]+ </tag>, like <a> 23 toto</a>
3603
if (eTools.getCountAttribute() == 0 && eTools.getSize() == eTools.getCountSimpleType())
3604            return new QTypeElement(name, (SimpleType) getType(SC_STRING));
3605        // case of <tag (attr)* > [simpleType]+ </tag>, like <a b="1"> 23 toto </a>
3606
if ((eTools.getCountAttribute() == eTools.getSize() - eTools.getCountSimpleType()) && (eTools.getMixed())) {
3607            complexType.setBaseType((SimpleType) getType(SC_STRING));
3608            complexType.setExtension(true);
3609            complexType.setContentModel(new ContentModel((SimpleType) getType(SC_STRING)));
3610        }
3611        // case of <tag (attr)* > [simpleType] </tag>, like <a b="1"> 23 </a>
3612
else if ((eTools.getCountAttribute() == eTools.getSize() - 1) && (eTools.getMixed())) {
3613            complexType.setBaseType(eTools.getSimpleType());
3614            complexType.setExtension(true);
3615            complexType.setContentModel(new ContentModel(eTools.getSimpleType()));
3616
3617        }
3618        // all others cases...
3619
else {
3620            ContentModel contentModel = new ContentModel();
3621            contentModel.setModel(new Particle(sequenceModel));
3622            if (eTools.getMixed())
3623                contentModel.setContentType(SchemaConstants.MIXED);
3624            else
3625                contentModel.setContentType(SchemaConstants.ELEMENT_ONLY);
3626            complexType.setContentModel(contentModel);
3627        }
3628        // } catch (SchemaException se) {
3629
// complexType = (ComplexType) this.getType(SC_ANYTYPE);
3630
// }
3631
return new QTypeElement(name, complexType);
3632    }
3633
3634    private void buildQTypeAtom(ElementTools eTools, QType qtype) throws XQueryException {
3635        eTools.setSimpleType(qtype.getSimpleType());
3636        eTools.setMixed(true);
3637        eTools.incCountSimpleType();
3638        eTools.incCountSimpleList();
3639    }
3640
3641    private void buildQTypeText(ElementTools eTools, QType qtype) throws XQueryException {
3642        eTools.setSimpleType(qtype.getSimpleType());
3643        eTools.setMixed(true);
3644        eTools.incCountSimpleType();
3645        eTools.incCountSimpleList();
3646    }
3647
3648    private void buildQTypeAttribute(ElementTools eTools, QTypeAttribute qtype, ComplexType complexType) throws XQueryException {
3649        String JavaDoc name = null;
3650        XQueryExpression qname = qtype.getName();
3651        if (qname instanceof QName)
3652            name = ((QName) qtype.getName()).getName();
3653        else
3654            name = getTemporaryName();
3655        // add LARS 05/07/04
3656
if (name.equals("xmlns"))
3657            return;
3658        eTools.incCountAttribute();
3659        AttributeDeclaration attribute = new AttributeDeclaration(this.typingschema, name, complexType);
3660        attribute.setType(qtype.getSimpleType());
3661        try {
3662            complexType.register(attribute);
3663        } catch (SchemaException saxe) {
3664            throw new TypeException("Error in register(ElementDeclaration): " + saxe.getMessage());
3665        }
3666    }
3667
3668    private byte index = 0;
3669    private String JavaDoc getTemporaryName() {
3670        return TEMP_NAME + index++;
3671    }
3672
3673    private void buildQTypeElement(ElementTools eTools, QType qtype, ComplexType complexType, ModelGroup model, boolean hasOne, boolean unbounded) throws XQueryException {
3674        String JavaDoc name = null;
3675        String JavaDoc uri = null;
3676        Schema tmpschema = this.typingschema;
3677        try {
3678            QName qname = (QName) ((QTypeElement) qtype).getName();
3679            uri = qname.getNameSpace();
3680            if (uri != null && !uri.equals(STAR)) {
3681                tmpschema = this.typingschemamanager.getSchema(uri);
3682                if (tmpschema == null) {
3683                    tmpschema = new Schema(uri, null, typingschemamanager);
3684                    try {
3685                        typingschemamanager.putSchema(tmpschema);
3686                    } catch (SAXException JavaDoc saxe) {
3687                        throw new TypeException("Could not add schema to manager");
3688                    }
3689                }
3690            }
3691            name = qname.getName();
3692        } catch (ClassCastException JavaDoc cce) {
3693            name = "TagDefineInEvaluation";
3694        }
3695        Particle particle = null;
3696        if (!name.equals(STAR)) {
3697            ElementDeclaration element = null;
3698            // test if element already exists
3699
element = complexType.getElementDeclaration(uri, name);
3700            if (element == null) {
3701                SchemaScope scope = null;
3702                if (uri != null && !uri.equals(STAR)) {
3703                    scope = tmpschema;
3704                    element = new ElementDeclaration(tmpschema, name, scope);
3705                    element.setQualified(true);
3706                } else {
3707                    scope = complexType;
3708                    element = new ElementDeclaration(tmpschema, name, scope);
3709                }
3710                element.setType(qtype.getType());
3711                try {
3712                    if (uri != null && !uri.equals(STAR))
3713                        complexType.register(element);
3714                    else
3715                        scope.register(element);
3716                } catch (SchemaException se) {
3717                    throw new XQueryException(se.getMessage());
3718                }
3719            } else {
3720                element.setType(tmpschema.getType(SC_ANYTYPE));
3721                /*
3722                Type elementType = element.getType();
3723                if (elementType.getValueType() != null)
3724                */

3725            }
3726            particle = new Particle(element);
3727        } else { // name = STAR
3728
// TODO? make a choice of different wildcards?
3729
particle = eTools.getWildCard();
3730            if (particle == null) {
3731                particle = new Particle(new Wildcard(tmpschema,true));
3732                eTools.addWildCard(particle);
3733            }
3734        }
3735        if (!hasOne)
3736            particle.setMinOccurs(0);
3737        if (unbounded)
3738            particle.setMaxOccursUnbounded();
3739        model.add(particle);
3740    }
3741
3742    private QTypeElement buildQTypeSequence(ElementTools eTools, QType qtype, ComplexType complexType, SequenceModelGroup sequenceModel) throws XQueryException {
3743        List list = qtype.getList();
3744        if (list == null)
3745            return null;
3746        int size = list.size();
3747        QTypeElement qte = null;
3748        for (int i = 0; i < size; i++) {
3749            QType stype = (QType) list.get(i);
3750            int subclass = stype.getSubClass();
3751            if (subclass == QType.ATOM) {
3752                // case of <tag> [simpleType] </tag>, like <a> 23 </a>
3753
if (size == 1 && eTools.getSize() == 1)
3754                    return new QTypeElement(eTools.getName(), qtype.getSimpleType() == null ? getType(SC_ANYTYPE) : qtype.getSimpleType());
3755                else
3756                    buildQTypeAtom(eTools, stype);
3757            } else if (subclass == QType.TEXT) {
3758                buildQTypeText(eTools, stype);
3759            } else if (subclass == QType.ATTRIBUTE) {
3760                buildQTypeAttribute(eTools, (QTypeAttribute)stype, complexType);
3761            } else if (subclass == QType.ELEMENT) {
3762                buildQTypeElement(eTools, stype, complexType, sequenceModel, stype.getMinOccurence() == 1, stype.isMultiple());
3763            } else if (subclass == QType.UNION) {
3764                buildQTypeUnion(eTools, stype, complexType, sequenceModel);
3765            } else if (subclass == QType.SEQUENCE) {
3766                qte = buildQTypeSequence(eTools, stype, complexType, sequenceModel);
3767                if (qte != null)
3768                    return qte;
3769            }
3770
3771        }
3772        return null;
3773    }
3774
3775    private void buildQTypeUnion(ElementTools eTools, QType qtype, ComplexType complexType, SequenceModelGroup sequenceModel) throws XQueryException {
3776        List list = qtype.getList();
3777        ChoiceModelGroup choiceModel = null;
3778        for (int i = 0; i < list.size(); i++) {
3779            if (i != 0)
3780                eTools.incSize();
3781            QType utype = (QType) list.get(i);
3782            int subclass = utype.getSubClass();
3783            boolean atom = false;
3784            if (subclass == QType.ATOM) {
3785                if (!atom) {
3786                    buildQTypeAtom(eTools, utype);
3787                    atom = true;
3788                }
3789            } else if (subclass == QType.TEXT) {
3790                buildQTypeText(eTools, utype);
3791            } else if (subclass == QType.ATTRIBUTE) {
3792                buildQTypeAttribute(eTools, (QTypeAttribute)utype, complexType);
3793            } else if (subclass == QType.ELEMENT) {
3794                if (choiceModel == null)
3795                    choiceModel = new ChoiceModelGroup();
3796                buildQTypeElement(eTools, utype, complexType, choiceModel, utype.getMinOccurence() == 1, utype.isMultiple());
3797            } else if (subclass == QType.SEQUENCE) {
3798                this.buildQTypeSequence(eTools, utype, complexType, sequenceModel);
3799            } else
3800                throw new TypeException("We have not specification for this case (NYI), definition: union { (atom | element | attribute)+ }.");
3801
3802        }
3803        if (choiceModel != null)
3804            sequenceModel.add(new Particle(choiceModel));
3805    }
3806
3807    private boolean isAnyTypeKind(QType qType) {
3808        Type type = qType.getType();
3809        if (type != null && type.getNamespace() != null && type.getNamespace().equals(SchemaConstants.XMLSCHEMA_URI) && type.getName() != null && (type.getName().equals(SchemaConstants.ANY_TYPE) || type.getName().equals(SchemaConstants.SIMPLE_UR_TYPE)))
3810            return true;
3811        return false;
3812    }
3813}
3814
Popular Tags