KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > xquery > lang > XQParser


1 // Copyright (c) 2001, 2002, 2003, 2004, 2006 Per M.A. Bothner and Brainfood Inc.
2
// This is free software; for terms and warranty disclaimer see ./COPYING.
3

4 package gnu.xquery.lang;
5 import gnu.kawa.lispexpr.*;
6 import gnu.mapping.*;
7 import gnu.lists.*;
8 import gnu.text.*;
9 import gnu.expr.*;
10 import gnu.math.IntNum;
11 import java.util.Vector JavaDoc;
12 import java.util.Stack JavaDoc;
13 import java.io.File JavaDoc;
14 import gnu.kawa.xml.*;
15 import gnu.xml.*;
16 import gnu.bytecode.*;
17 import gnu.kawa.reflect.OccurrenceType;
18 import gnu.kawa.reflect.SingletonType;
19 import gnu.kawa.functions.Convert;
20 import gnu.xquery.util.NamedCollator;
21 import gnu.xquery.util.CastableAs;
22 import gnu.xquery.util.QNameUtils;
23 import gnu.xquery.util.RelativeStep;
24 import gnu.xquery.util.ValuesFilter;
25 import kawa.standard.require;
26
27 /** A class to read xquery forms. */
28
29 public class XQParser extends Lexer
30 {
31   int curToken;
32   Object JavaDoc curValue;
33
34   /** Normally null.
35    * 'C' means parsing the type of a 'cast as' or 'castable as'. */

36   int parseContext;
37   /** True if we've seen a VarDecl, FunctionDecl, or OptionDecl. */
38   boolean seenDeclaration;
39
40   String JavaDoc libraryModuleNamespace;
41
42   /** Value of getLineNumber() at start of current token.
43    * Sometimes set otherwise, to report errors. */

44   int curLine;
45
46   /** Value of getColumnNumber() at start of current token.
47    * Sometimes set otherwise, to report errors. */

48   int curColumn;
49
50   XQuery interpreter;
51
52   int seenPosition;
53   int seenLast;
54
55   public static boolean warnOldVersion = true;
56   public static boolean warnHidePreviousDeclaration = false;
57
58   /** The internal name of the variable containing '.', the context node. */
59   static final Symbol DOT_VARNAME = Symbol.makeUninterned("$dot$");
60
61   /** The pseduo-function position() is mapped to a reference. */
62   static final Symbol POSITION_VARNAME = Symbol.makeUninterned("$position$");
63
64   /** The pseduo-function last() is mapped to a reference to this variable. */
65   static final Symbol LAST_VARNAME = Symbol.makeUninterned("$last$");
66
67   public static final gnu.kawa.reflect.InstanceOf instanceOf
68   = new gnu.kawa.reflect.InstanceOf(XQuery.getInstance(), "instance");
69   public static final CastableAs castableAs = CastableAs.castableAs;
70   public static final Convert treatAs = Convert.as;
71
72   NameLookup lexical;
73
74   NamedCollator defaultCollator = null;
75
76   /** The default order for empty sequences.
77    * Either <code>'L'</code> (for "least") or <code>'G'</code> (for "greatest").
78    */

79   char defaultEmptyOrder = 'L';
80   boolean emptyOrderDeclarationSeen;
81
82   String JavaDoc baseURI = null;
83   boolean baseURIDeclarationSeen;
84   public String JavaDoc getStaticBaseUri ()
85   {
86     if (baseURI == null)
87       {
88         Environment env = Environment.getCurrent();
89         Object JavaDoc value = env.get(Symbol.make("", "base-uri"), null, null);
90         if (value != null)
91           baseURI = value.toString();
92       }
93     return baseURI;
94   }
95
96   boolean boundarySpacePreserve;
97   boolean boundarySpaceDeclarationSeen;
98
99   boolean orderingModeUnordered;
100   boolean orderingModeSeen;
101
102   /** True if we've seen a 'copy-namespaces' declaration'. */
103   boolean copyNamespacesDeclarationSeen;
104   int copyNamespacesMode
105   = XMLFilter.COPY_NAMESPACES_PRESERVE|XMLFilter.COPY_NAMESPACES_INHERIT;
106
107   /** The static construction mode. True if "strip"; false if "preserve". */
108   boolean constructionModeStrip;
109   /** True if a construction mode declaration has been seen. */
110   boolean constructionModeDeclarationSeen;
111
112   public Namespace[] functionNamespacePath
113     = XQuery.defaultFunctionNamespacePath;
114
115   /** Stack of currently active for/let Declarations. */
116   Declaration[] flworDecls;
117   /* Index in flworDecls of first Declaration in current FLWOR. */
118   int flworDeclsFirst;
119   /* Total number of currently active for/let Declarations. */
120   int flworDeclsCount;
121
122   int parseCount;
123   int commentCount;
124   /** An error message if comments are disallowed. Normally null. */
125   String JavaDoc errorIfComment;
126
127   /** Skip whitespace.
128    * Sets 'index' to the that of the next non-whitespace character,
129    * and returns that. If there are no more non-space characters,
130    * returns ' '. */

131   final int skipSpace()
132     throws java.io.IOException JavaDoc, SyntaxException
133   {
134     return skipSpace(true);
135   }
136
137   final int skipSpace(boolean verticalToo)
138     throws java.io.IOException JavaDoc, SyntaxException
139   {
140     for (;;)
141       {
142     int ch = read();
143     if (ch == '(')
144       {
145         if (! checkNext(':'))
146           return '(';
147         skipComment();
148       }
149     else if (ch == '{')
150       {
151         ch = read();
152          if (ch != '-')
153            {
154          unread(ch);
155          return '{';
156            }
157         ch = read();
158          if (ch != '-')
159            {
160          unread(ch);
161          unread('-');
162          return '{';
163            }
164          skipOldComment();
165       }
166     else if (verticalToo
167          ? (ch < 0 || ! Character.isWhitespace((char) ch))
168          : (ch != ' ' && ch != '\t'))
169       return ch;
170       }
171   }
172
173   final void skipToSemicolon ()
174     throws java.io.IOException JavaDoc
175   {
176     for (;;)
177       {
178     int next = read();
179     if (next < 0 || next == ';')
180       break;
181       }
182   }
183
184   final void skipOldComment()
185     throws java.io.IOException JavaDoc, SyntaxException
186   {
187     int seenDashes = 0;
188     int startLine = getLineNumber() + 1;
189     int startColumn = getColumnNumber() - 2;
190     warnOldVersion("use (: :) instead of old-style comment {-- --}");
191     for (;;)
192       {
193     int ch = read();
194     if (ch == '-')
195       seenDashes++;
196     else if (ch == '}' && seenDashes >= 2)
197       return;
198     else if (ch < 0)
199       {
200         curLine = startLine;
201         curColumn = startColumn;
202         eofError("non-terminated comment starting here");
203       }
204     else
205       seenDashes = 0;
206       }
207   }
208
209   final void skipComment()
210     throws java.io.IOException JavaDoc, SyntaxException
211   {
212     commentCount++;
213     int startLine = getLineNumber() + 1;
214     int startColumn = getColumnNumber() - 1;
215     if (errorIfComment != null)
216       {
217         curLine = startLine;
218         curColumn = startColumn;
219         error('e', errorIfComment);
220       }
221     int prev = 0;
222     int commentNesting = 0;
223     char saveReadState = pushNesting(':');
224     for (;;)
225       {
226     int ch = read();
227     if (ch == ':')
228       {
229         if (prev == '(')
230           {
231         commentNesting++;
232         ch = 0;
233           }
234       }
235     else if (ch == ')' && prev == ':')
236       {
237         if (commentNesting == 0)
238           {
239         popNesting(saveReadState);
240         return;
241           }
242         --commentNesting;
243       }
244     else if (ch < 0)
245       {
246         curLine = startLine;
247         curColumn = startColumn;
248         eofError("non-terminated comment starting here");
249       }
250     prev = ch;
251       }
252   }
253
254   /** Do skipSpace followed by unread to find next non-space character. */
255   final int peekNonSpace(String JavaDoc message)
256     throws java.io.IOException JavaDoc, SyntaxException
257   {
258     int ch = skipSpace();
259     if (ch < 0)
260       eofError(message);
261     unread(ch);
262     return ch;
263   }
264
265   static final int EOF_TOKEN = -1;
266   static final int EOL_TOKEN = '\n';
267   static final char INTEGER_TOKEN = '0';
268   static final char DECIMAL_TOKEN = '1';
269   static final char DOUBLE_TOKEN = '2';
270   static final int STRING_TOKEN = '"';
271   static final int SLASHSLASH_TOKEN = 'D';
272   static final int DOTDOT_TOKEN = '3';
273   static final int COLON_EQUAL_TOKEN = 'L'; // ":="
274
static final int COLON_COLON_TOKEN = 'X';
275
276   /** A non-qualified (simple) name (NCName).
277    * The tokenBuffer contains the name (which does not contain a ':'). */

278   static final int NCNAME_TOKEN = 'A';
279
280   /** A non-qualified (simple) name (NCName) followed by a colon.
281    * The colon is not followed by another NCNAME (in which it would
282    * be a QNAME_TOKEN instead).
283    * The tokenBuffer contains the name (which does not contain the ':'). */

284   static final int NCNAME_COLON_TOKEN = 'C';
285
286   /** A Qualified name (QName).
287    * The tokenBuffer contains the full name, which contains one ':'. */

288   static final int QNAME_TOKEN = 'Q';
289
290   static final int ARROW_TOKEN = 'R';
291
292   /* FuncName including following '('). */
293   static final int FNAME_TOKEN = 'F';
294
295   static final int IMPORT_MODULE_TOKEN = 'I'; // <"import" "module">
296
static final int IMPORT_SCHEMA_TOKEN = 'T'; // <"import" "schema">
297
static final int MODULE_NAMESPACE_TOKEN = 'M'; // <"module" "namespace">
298
static final int DECLARE_NAMESPACE_TOKEN = 'N'; // <"declare" "namespace">
299
static final int DECLARE_BOUNDARY_SPACE_TOKEN = 'S'; // <"declare" "boundary-space">
300
static final int DEFAULT_ELEMENT_TOKEN = 'E'; // <"declare" "default" "element">
301
static final int DEFAULT_FUNCTION_TOKEN = 'O'; // <"declare" "default" "function">
302
static final int DEFAULT_COLLATION_TOKEN = 'G';
303   static final int DEFAULT_ORDER_TOKEN = 'H'; // <"declare" "default" "order">
304

305   static final int DECLARE_FUNCTION_TOKEN = 'P'; // <"declare" "function">
306
static final int DECLARE_VARIABLE_TOKEN = 'V'; // <"declare" "variable">
307
static final int DECLARE_BASE_URI_TOKEN = 'B'; // <"declare" "base-uri">
308
static final int DECLARE_ORDERING_TOKEN = 'U'; // <"declare" "ordering">
309
static final int DECLARE_CONSTRUCTION_TOKEN = 'K'; // <"declare" "construction">
310
static final int DECLARE_OPTION_TOKEN = 'o'; // <"declare" "option">
311
static final int DECLARE_COPY_NAMESPACES_TOKEN = 'L'; // <"declare" "copy-namespaces">
312
static final int DEFINE_QNAME_TOKEN = 'W'; // <"define" QName> - an error
313
static final int XQUERY_VERSION_TOKEN = 'Y'; // <"xquery" "version">
314

315   /* 'Q': QName (intern'ed name is curValue)
316    * 'R': NCName ':' '*'
317    * OP_AXIS_FIRST: 'ancestor' followed by '::'
318    * ...
319    * OP_AXIS_FIRST+AXIS_SELF: 'self' followed by '::'
320    */

321
322   static final int OP_AXIS_FIRST = 100;
323   static final int COUNT_OP_AXIS = 13;
324   static final int AXIS_ANCESTOR = 0;
325   static final int AXIS_ANCESTOR_OR_SELF = 1;
326   static final int AXIS_ATTRIBUTE = 2;
327   static final int AXIS_CHILD = 3;
328   static final int AXIS_DESCENDANT = 4;
329   static final int AXIS_DESCENDANT_OR_SELF = 5;
330   static final int AXIS_FOLLOWING = 6;
331   static final int AXIS_FOLLOWING_SIBLING = 7;
332   static final int AXIS_NAMESPACE = 8;
333   static final int AXIS_PARENT = 9;
334   static final int AXIS_PRECEDING = 10;
335   static final int AXIS_PRECEDING_SIBLING = 11;
336   static final int AXIS_SELF = 12;
337   static final int OP_WHERE = 196;
338   static final int PRAGMA_START_TOKEN = 197; // '{#'
339
// Token types for binary operators.
340
static final int OP_BASE = 400;
341   static final int OP_OR = OP_BASE; // 'or'
342
static final int OP_AND = OP_BASE + 1; // 'and'
343
static final int OP_EQU = OP_BASE + 2; // ' ='
344
static final int OP_NEQ = OP_BASE + 3; // '! ='
345
static final int OP_LSS = OP_BASE + 4; // '<'
346
static final int OP_GRT = OP_BASE + 5; // '>'
347
static final int OP_LEQ = OP_BASE + 6; // '< ='
348
static final int OP_GEQ = OP_BASE + 7; // '> ='
349
static final int OP_IS = OP_BASE + 8; // 'is'
350
static final int OP_ISNOT = OP_BASE + 9; // 'isnot'
351
static final int OP_GRTGRT = OP_BASE + 10; // '>>'
352
static final int OP_LSSLSS = OP_BASE + 11; // '<<'
353

354   static final int OP_RANGE_TO = OP_BASE + 12; // 'to'
355

356   static final int OP_ADD = OP_BASE + 13; // '+'
357
static final int OP_SUB = OP_BASE + 14; // '-'
358

359   static final int OP_MUL = OP_BASE + 15; // '*'
360
static final int OP_DIV = OP_BASE + 16; // 'div'
361
static final int OP_IDIV = OP_BASE + 17; // 'idiv'
362
static final int OP_MOD = OP_BASE + 18; // 'mod'
363

364   static final int OP_UNION = OP_BASE + 19; // 'union'
365

366   static final int OP_INTERSECT = OP_BASE + 20; // 'intersect'
367
static final int OP_EXCEPT = OP_BASE + 21; // 'except'
368

369   static final int OP_INSTANCEOF = OP_BASE + 22; // 'instance' 'of'
370
static final int OP_TREAT_AS = OP_BASE + 23; // 'treat' 'as'
371
static final int OP_CASTABLE_AS= OP_BASE + 24; // 'castable' 'as'
372
static final int OP_CAST_AS = OP_BASE + 25; // 'cast' 'as'
373

374   static final int OP_EQ = OP_BASE + 26; // 'eq'
375
static final int OP_NE = OP_BASE + 27; // 'ne'
376
static final int OP_LT = OP_BASE + 28; // 'lt'
377
static final int OP_LE = OP_BASE + 29; // 'le
378
static final int OP_GT = OP_BASE + 30; // 'gt'
379
static final int OP_GE = OP_BASE + 31; // 'ge'
380

381   static final int OP_NODE = 230; // 'node' followed by '('
382
static final int OP_TEXT = 231; // 'text' followed by '('
383
static final int OP_COMMENT = 232; // 'comment' followed by '('
384
static final int OP_PI = 233; // 'processing-instruction' '('
385
static final int OP_DOCUMENT = 234; // 'document-node' '('
386
static final int OP_ELEMENT = 235; // 'element' '('
387
static final int OP_ATTRIBUTE = 236; // 'attribute' '('
388
static final int OP_ITEM = 237; // 'item' '('
389
static final int OP_EMPTY_SEQUENCE = 238; // 'empty-sequence' '('
390
static final int OP_SCHEMA_ATTRIBUTE = 239; // 'schema-attribute' '('
391
static final int OP_SCHEMA_ELEMENT = 240; // 'schema-element' '('
392
static final int IF_LPAREN_TOKEN = 241; // 'if' '('
393
static final int TYPESWITCH_LPAREN_TOKEN = 242; // 'typeswitch' '('
394

395   static final int FOR_DOLLAR_TOKEN = 243; // 'for' '$'
396
static final int LET_DOLLAR_TOKEN = 244; // 'let' '$'
397
static final int SOME_DOLLAR_TOKEN = 245; // 'some' '$'
398
static final int EVERY_DOLLAR_TOKEN = 246; // 'every' '$'
399
static final int CASE_DOLLAR_TOKEN = 247; // 'case' '$'
400
static final int VALIDATE_LBRACE_TOKEN = 248; // 'validate' '{'
401
static final int ORDERED_LBRACE_TOKEN = 249; // 'ordered' '{'
402
static final int UNORDERED_LBRACE_TOKEN = 250; // 'unordered' '{'
403
static final int ELEMENT_TOKEN = 251; // 'element' followed by '{' or alpha
404
static final int ATTRIBUTE_TOKEN = 252;// 'attribute' followed by '{' or alpha
405
static final int TEXT_TOKEN = 253; // 'text' followed by '{'
406
static final int COMMENT_TOKEN = 254; // 'text' followed by '{'
407
static final int PI_TOKEN = 255; // 'processing-instruction' followed by '{' or alpha
408
static final int DOCUMENT_TOKEN = 256; // ;document' followed by '{'
409

410   private int saveToken;
411   private Object JavaDoc saveValue;
412
413   public void mark ()
414     throws java.io.IOException JavaDoc
415   {
416     super.mark();
417     saveToken = curToken;
418     saveValue = curValue;
419   }
420
421   public void reset()
422     throws java.io.IOException JavaDoc
423   {
424     curToken = saveToken;
425     curValue = saveValue;
426     super.reset();
427   }
428
429   private int setToken (int token, int width)
430   {
431     curToken = token;
432     curLine = port.getLineNumber() + 1;
433     curColumn = port.getColumnNumber() + 1 - width;
434     return token;
435   }
436
437   void checkSeparator (char ch)
438   {
439     if (XName.isNameStart(ch))
440       error('e', "missing separator", "XPST0003");
441   }
442
443   int getRawToken()
444       throws java.io.IOException JavaDoc, SyntaxException
445   {
446     int next;
447     for (;;)
448       {
449     next = read();
450     if (next < 0)
451       return setToken(EOF_TOKEN, 0);
452     if (next == '\n' || next == '\r')
453       {
454         if (nesting <= 0)
455           return setToken(EOL_TOKEN, 0);
456       }
457     else if (next == '(')
458       {
459         if (checkNext(':'))
460           skipComment();
461             else if (checkNext('#'))
462               return setToken(PRAGMA_START_TOKEN, 2);
463         else
464           return setToken('(', 1);
465       }
466     else if (next == '{')
467       {
468         if (! checkNext('-'))
469           return setToken('{', 1);
470         next = read();
471         if (next != '-')
472           {
473         // FIXME backup 2 chars. Can fix using special token for '{-'.
474
unread();
475         unread();
476         return setToken('{', 1);
477           }
478         skipOldComment();
479       }
480     else if (next != ' ' && next != '\t')
481       break;
482       }
483     tokenBufferLength = 0;
484     curLine = port.getLineNumber() + 1;
485     curColumn = port.getColumnNumber();
486     char ch = (char) next;
487     switch (ch)
488       {
489       case ')': case '[': case ']': case '}':
490       case '$': case '@': case ',': case '?': case ';':
491     break;
492       case ':':
493     if (checkNext('='))
494       ch = COLON_EQUAL_TOKEN;
495     else if (checkNext(':'))
496       ch = COLON_COLON_TOKEN;
497     break;
498       case '|':
499     ch = OP_UNION;
500     break;
501       case '*':
502     ch = OP_MUL;
503     break;
504       case '+':
505     ch = OP_ADD;
506     break;
507       case '-':
508     ch = OP_SUB;
509     break;
510       case '!':
511     if (checkNext('='))
512       ch = OP_NEQ;
513     break;
514       case '/':
515     if (checkNext('/'))
516       ch = SLASHSLASH_TOKEN;
517     break;
518       case '=':
519     if (checkNext('>'))
520       ch = ARROW_TOKEN;
521     ch = OP_EQU;
522     break;
523       case '>':
524     ch = checkNext('=') ? (char) OP_GEQ
525       : checkNext('>') ? (char) OP_GRTGRT : (char) OP_GRT;
526     break;
527       case '<':
528     ch = checkNext('=') ? (char) OP_LEQ
529       : checkNext('<') ? (char) OP_LSSLSS : (char) OP_LSS;
530     break;
531       case '\'': case '\"':
532     char saveReadState = pushNesting ((char) next);
533     for (;;)
534       {
535         next = read();
536         if (next < 0)
537           eofError("unexpected end-of-file in string starting here");
538         if (next == '&')
539           {
540         parseEntityOrCharRef();
541         continue;
542           }
543         else if (ch == next)
544           {
545         next = read ();
546         if (ch != next)
547           {
548             unread(next);
549             break;
550           }
551           }
552         tokenBufferAppend((char) next);
553       }
554     popNesting(saveReadState);
555     ch = STRING_TOKEN;
556     break;
557       default:
558     if (Character.isDigit(ch)
559             || (ch == '.' && Character.isDigit((char) peek())))
560       {
561         boolean seenDot = ch == '.';
562         for (;; )
563           {
564         tokenBufferAppend(ch);
565         next = read();
566         if (next < 0)
567           break;
568         ch = (char) next;
569         if (ch == '.')
570           {
571             if (seenDot) break;
572             seenDot = true;
573           }
574         else if (! Character.isDigit(ch))
575           break;
576           }
577         if (next == 'e' || next == 'E')
578           {
579         tokenBufferAppend((char) next);
580         next = read();
581         if (next == '+' || next == '-')
582           {
583             tokenBufferAppend((char) next);
584             next = read();
585           }
586         int expDigits = 0;
587         for (;;)
588           {
589             if (next < 0)
590               break;
591             ch = (char) next;
592             if (! Character.isDigit(ch))
593               {
594                         checkSeparator(ch);
595             unread();
596             break;
597               }
598             tokenBufferAppend(ch);
599             next = read();
600             expDigits++;
601           }
602         if (expDigits == 0)
603           error('e', "no digits following exponent", "XPST0003");
604         ch = DOUBLE_TOKEN;
605           }
606         else
607           {
608         ch = seenDot ? DECIMAL_TOKEN : INTEGER_TOKEN;
609         if (next >= 0)
610                   {
611                     checkSeparator((char) next);
612                     unread(next);
613                   }
614           }
615       }
616         else if (ch == '.')
617           {
618             if (checkNext('.'))
619               ch = DOTDOT_TOKEN;
620         break;
621           }
622     else if (XName.isNameStart(ch))
623       {
624         for (;;)
625           {
626         tokenBufferAppend(ch);
627         next = read();
628         ch = (char) next;
629         if (! XName.isNamePart(ch))
630           break;
631           }
632         if (next < 0)
633           ch = NCNAME_TOKEN;
634         else
635           {
636         if (next != ':')
637             ch = NCNAME_TOKEN;
638         else
639           {
640             next = read();
641             if (next < 0)
642               eofError("unexpected end-of-file after NAME ':'");
643             ch = (char) next;
644             if (XName.isNameStart(ch))
645               {
646             tokenBufferAppend(':');
647             for (;;)
648               {
649                 tokenBufferAppend(ch);
650                 next = read();
651                 ch = (char) next;
652                 if (! XName.isNamePart(ch))
653                   break;
654               }
655             ch = QNAME_TOKEN;
656               }
657             else if (ch == '=')
658               {
659             unread(ch);
660             ch = NCNAME_TOKEN;
661               }
662             else
663               ch = NCNAME_COLON_TOKEN;
664           }
665         unread(next);
666           }
667       }
668     else if (ch >= ' ' && ch < 127)
669       syntaxError("invalid character '"+ch+'\'');
670     else
671       syntaxError("invalid character '\\u"+Integer.toHexString(ch)+'\'');
672       }
673     curToken = ch;
674     return ch;
675   }
676
677   /** Scan until a given delimiter.
678    * On success, text upto the delimiter is in then tokenBuffer (with
679    * tokenBufferLength marking its length); the delimiter is not included.
680    */

681   public void getDelimited(String JavaDoc delimiter)
682       throws java.io.IOException JavaDoc, SyntaxException
683   {
684     tokenBufferLength = 0;
685     int dlen = delimiter.length();
686     char last = delimiter.charAt(dlen-1);
687     for (;;)
688       {
689     int ch = read();
690     if (ch < 0)
691       eofError("unexpected end-of-file looking for '"+delimiter+'\'');
692     int dstart, j;
693     // Look for a match for the last delimiter character.
694
if (ch == last
695         && (dstart = tokenBufferLength - (j = dlen - 1)) >= 0)
696       {
697         // Check that the initial part of the delimiter has also been seen.
698
do
699           {
700         if (j == 0)
701           {
702             tokenBufferLength = dstart;
703             return;
704           }
705         j--;
706           }
707         while (tokenBuffer[dstart+j] == delimiter.charAt(j));
708       }
709     tokenBufferAppend((char) ch);
710       }
711   }
712
713   public void appendNamedEntity(String JavaDoc name)
714   {
715     name = name.intern();
716     char ch = '?';
717     if (name == "lt")
718       ch = '<';
719     else if (name == "gt")
720       ch = '>';
721     else if (name == "amp")
722       ch = '&';
723     else if (name == "quot")
724       ch = '"';
725     else if (name == "apos")
726       ch = '\'';
727     else
728       error("unknown enity reference: '"+name+"'");
729     tokenBufferAppend(ch);
730   }
731
732   boolean match (String JavaDoc word1, String JavaDoc word2, boolean force)
733       throws java.io.IOException JavaDoc, SyntaxException
734   {
735     if (match(word1))
736       {
737         mark();
738         getRawToken();
739         if (match(word2))
740           {
741             reset();
742             getRawToken();
743             return true;
744           }
745         reset();
746         if (force)
747           {
748             error('e', "'"+word1+"' must be followed by '"+word2+"'",
749                   "XPST0003");
750             return true;
751           }
752       }
753     return false;
754   }
755
756   /** Return the current token, assuming it is in operator context.
757    * Resolve NCNAME_TOKEN (identifier) to 'and', 'or', 'div', etc.
758    */

759   int peekOperator()
760       throws java.io.IOException JavaDoc, SyntaxException
761   {
762     while (curToken == EOL_TOKEN)
763       {
764     if (nesting == 0)
765       return EOL_TOKEN;
766     getRawToken();
767       }
768     if (curToken == NCNAME_TOKEN)
769       {
770     int len = tokenBufferLength;
771         char c1, c2, c3;
772         switch (len)
773           {
774           case 2:
775             c1 = tokenBuffer[0];
776             c2 = tokenBuffer[1];
777             if (c1 == 'o' && c2 == 'r')
778               curToken = OP_OR;
779             else if (c1 == 't' && c2 == 'o')
780               curToken = OP_RANGE_TO;
781             else if (c1 == 'i' && c2 == 's')
782               curToken = OP_IS;
783             else if (c1 == 'e' && c2 == 'q')
784               curToken = OP_EQ;
785             else if (c1 == 'n' && c2 == 'e')
786               curToken = OP_NE;
787             else if (c1 == 'g')
788               {
789                 if (c2 == 'e') curToken = OP_GE;
790                 else if (c2 == 't') curToken = OP_GT;
791               }
792             else if (c1 == 'l')
793               {
794                 if (c2 == 'e') curToken = OP_LE;
795                 else if (c2 == 't') curToken = OP_LT;
796               }
797             break;
798
799           case 3:
800             c1 = tokenBuffer[0];
801             c2 = tokenBuffer[1];
802             c3 = tokenBuffer[2];
803             if (c1 == 'a')
804               {
805                 if (c2 == 'n' && c3 == 'd')
806                   curToken = OP_AND;
807               }
808             else if (c1 == 'm') {
809               if (c2 == 'u' && c3 == 'l')
810                 curToken = OP_MUL;
811               if (c2 == 'o' && c3 == 'd')
812                 curToken = OP_MOD;
813             }
814             else if (c1 == 'd') {
815               if (c2 == 'i' && c3 == 'v')
816                 curToken = OP_DIV;
817             }
818             break;
819           case 4:
820             if (match("idiv"))
821               curToken = OP_IDIV;
822             else if (match("cast", "as", true))
823               curToken = OP_CAST_AS;
824             break;
825           case 5:
826             if (match("where"))
827               curToken = OP_WHERE;
828             else if (match("isnot"))
829               curToken = OP_ISNOT;
830             else if (match("union"))
831               curToken = OP_UNION;
832             else if (match("treat", "as", true))
833               curToken = OP_TREAT_AS;
834             break;
835           case 6:
836             if (match("except"))
837               curToken = OP_EXCEPT;
838             break;
839           case 8:
840             if (match("instance", "of", true))
841               curToken = OP_INSTANCEOF;
842             else if (match("castable", "as", true))
843               curToken = OP_CASTABLE_AS;
844             break;
845           case 9:
846             if (match("intersect"))
847               curToken = OP_INTERSECT;
848             break;
849           case 10:
850             if (match("instanceof")) // obsolete
851
{
852                 warnOldVersion("use 'instanceof of' (two words) instead of 'instanceof'");
853                 curToken = OP_INSTANCEOF;
854               }
855             break;
856           default:
857             break;
858           }
859       }
860     return curToken;
861   }
862
863   /**
864    * Internal method to match against double-lexeme tokens.
865    * @param word0 expected previous word
866    * @param word1 expected next word
867    */

868   private boolean lookingAt (String JavaDoc word0, String JavaDoc word1)
869       throws java.io.IOException JavaDoc, SyntaxException
870   {
871     if (! word0.equals(curValue))
872       return false;
873     int i = 0;
874     int len = word1.length();
875     for (;; )
876       {
877     int ch = read();
878     if (i == len)
879       {
880         if (ch < 0)
881           return true;
882         if ( ! XName.isNamePart((char) ch))
883           {
884         unread();
885         return true;
886           }
887         i++;
888         break;
889       }
890     if (ch < 0 || ch != word1.charAt(i++))
891       break;
892       }
893     port.skip(-i);
894     return false;
895   }
896
897   int getAxis ()
898   {
899     // match axis name
900
String JavaDoc name = new String JavaDoc(tokenBuffer, 0, tokenBufferLength).intern();
901     int i;
902     for (i = COUNT_OP_AXIS; --i >= 0; )
903       if (axisNames[i] == name)
904     break;
905     if (i < 0)
906       {
907     error("unknown axis name '" + name + '\'');
908     i = AXIS_CHILD;
909       }
910     return (char) (OP_AXIS_FIRST + i);
911   }
912
913   /** Process token, assuming we are in operand context.
914    */

915
916   int peekOperand()
917       throws java.io.IOException JavaDoc, SyntaxException
918   {
919     while (curToken == EOL_TOKEN)
920       getRawToken();
921     if (curToken == NCNAME_TOKEN || curToken == QNAME_TOKEN)
922       {
923     int next = skipSpace(nesting != 0);
924         switch (tokenBuffer[0])
925           {
926           case 'a':
927             if (match("attribute"))
928               {
929                 if (next == '(')
930                   return curToken = OP_ATTRIBUTE;
931                 if (next == '{' || XName.isNameStart((char) next))
932                   {
933                     unread();
934                     return curToken = ATTRIBUTE_TOKEN;
935                   }
936                 break;
937               }
938             break;
939           case 'c':
940             if (match("comment"))
941               {
942                 if (next == '(')
943                   return curToken = OP_COMMENT;
944                 if (next == '{')
945                   {
946                     unread();
947                     return curToken = COMMENT_TOKEN;
948                   }
949               }
950             break;
951           case 'd':
952             if (next == '{' && match("document"))
953               {
954                 unread();
955                 return curToken = DOCUMENT_TOKEN;
956               }
957             if (next == '(' && match("document-node"))
958               return curToken = OP_DOCUMENT;
959             break;
960           case 'e':
961             if (match("element"))
962               {
963                 if (next == '(')
964                   return curToken = OP_ELEMENT;
965                 if (next == '{' || XName.isNameStart((char) next))
966                   {
967                     unread();
968                     return curToken = ELEMENT_TOKEN;
969                   }
970                 break;
971               }
972             if (match("empty-sequence"))
973               return curToken = OP_EMPTY_SEQUENCE;
974             if (next == '$' && match("every"))
975               return curToken = EVERY_DOLLAR_TOKEN;
976             break;
977           case 'f':
978             if (next == '$' && match("for"))
979               return curToken = FOR_DOLLAR_TOKEN;
980             break;
981           case 'i':
982             if (next == '(' && match("if"))
983               return curToken = IF_LPAREN_TOKEN;
984             if (next == '(' && match("item"))
985               return curToken = OP_ITEM;
986             break;
987           case 'l':
988             if (next == '$' && match("let"))
989               return curToken = LET_DOLLAR_TOKEN;
990             break;
991           case 'n':
992             if (next == '(' && match("node"))
993               return curToken = OP_NODE;
994             break;
995           case 'o':
996             if (next == '{' && match("ordered"))
997               return curToken = ORDERED_LBRACE_TOKEN;
998             break;
999           case 'p':
1000            if (match("processing-instruction"))
1001              {
1002                if (next == '(')
1003                  return curToken = OP_PI;
1004                if (next == '{' || XName.isNameStart((char) next))
1005                  {
1006                    unread();
1007                    return curToken = PI_TOKEN;
1008                  }
1009                break;
1010              }
1011            break;
1012          case 's':
1013            if (next == '$' && match("some"))
1014              return curToken = SOME_DOLLAR_TOKEN;
1015            if (next == '(' && match("schema-attribute"))
1016              return curToken = OP_SCHEMA_ATTRIBUTE;
1017            if (next == '(' && match("schema-element"))
1018              return curToken = OP_SCHEMA_ELEMENT;
1019            break;
1020          case 't':
1021            if (match("text"))
1022              {
1023                if (next == '(')
1024                  return curToken = OP_TEXT;
1025                if (next == '{')
1026                  {
1027                    unread();
1028                    return curToken = TEXT_TOKEN;
1029                  }
1030              }
1031            if (next == '(' && match("typeswitch"))
1032              return curToken = TYPESWITCH_LPAREN_TOKEN;
1033            break;
1034          case 'u':
1035            if (next == '{' && match("unordered"))
1036              return curToken = UNORDERED_LBRACE_TOKEN;
1037            break;
1038          case 'v':
1039            if (next == '{' && match("validate"))
1040              return curToken = VALIDATE_LBRACE_TOKEN;
1041            break;
1042          }
1043    if (next == '(' && peek() != ':')
1044      {
1045        return curToken = FNAME_TOKEN;
1046      }
1047    if (next == ':' && peek() == ':')
1048      return curToken = getAxis();
1049    String JavaDoc name = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
1050    curValue = name;
1051    switch (next)
1052      {
1053          case 'b':
1054        if (lookingAt("declare", /*"b"+*/ "ase-uri"))
1055              return curToken = DECLARE_BASE_URI_TOKEN;
1056        if (lookingAt("declare", /*"b"+*/ "oundary-space"))
1057              return curToken = DECLARE_BOUNDARY_SPACE_TOKEN;
1058            break;
1059          case 'c':
1060        if (lookingAt("declare", /*"c"+*/ "onstruction"))
1061              return curToken = DECLARE_CONSTRUCTION_TOKEN;
1062        if (lookingAt("declare", /*"c"+*/ "opy-namespaces"))
1063              return curToken = DECLARE_COPY_NAMESPACES_TOKEN;
1064            break;
1065      case 'd':
1066        if (lookingAt("declare", /*"d"+*/ "efault"))
1067          {
1068        getRawToken();
1069        if (match("function"))
1070          return curToken = DEFAULT_FUNCTION_TOKEN;
1071        if (match("element"))
1072          return curToken = DEFAULT_ELEMENT_TOKEN;
1073        if (match("collation"))
1074          return curToken = DEFAULT_COLLATION_TOKEN;
1075        if (match("order"))
1076          return curToken = DEFAULT_ORDER_TOKEN;
1077        error("unrecognized/unimplemented 'declare default'");
1078        skipToSemicolon();
1079        return peekOperand();
1080          }
1081      case 'e':
1082        if (lookingAt("default", /*"e"+*/ "lement"))
1083          {
1084        warnOldVersion("replace 'default element' by 'declare default element namespace'");
1085        return curToken = DEFAULT_ELEMENT_TOKEN;
1086          }
1087        break;
1088      case 'f':
1089        if (lookingAt("declare", /*"f"+*/ "unction"))
1090          return curToken = DECLARE_FUNCTION_TOKEN;
1091        if (lookingAt("define", /*"f"+*/ "unction"))
1092          {
1093                warnOldVersion("replace 'define function' by 'declare function'");
1094        return curToken = DECLARE_FUNCTION_TOKEN;
1095          }
1096        if (lookingAt("default", /*"f"+*/ "unction"))
1097          {
1098        warnOldVersion("replace 'default function' by 'declare default function namespace'");
1099        return curToken = DEFAULT_FUNCTION_TOKEN;
1100          }
1101        break;
1102      case 'm':
1103        if (lookingAt("import", /*"m"+*/ "odule"))
1104          return curToken = IMPORT_MODULE_TOKEN;
1105        break;
1106      case 'n':
1107        if (lookingAt("declare", /*"n"+*/ "amespace"))
1108          return curToken = DECLARE_NAMESPACE_TOKEN;
1109        if (lookingAt("default", /*"n"+*/ "amespace"))
1110          {
1111        warnOldVersion("replace 'default namespace' by 'declare default element namespace'");
1112        return curToken = DEFAULT_ELEMENT_TOKEN;
1113          }
1114        if (lookingAt("module", /*"n"+*/ "amespace"))
1115          return curToken = MODULE_NAMESPACE_TOKEN;
1116        break;
1117      case 'o':
1118        if (lookingAt("declare", /*"o"+*/ "rdering"))
1119          return curToken = DECLARE_ORDERING_TOKEN;
1120        if (lookingAt("declare", /*"o"+*/ "ption"))
1121          return curToken = DECLARE_OPTION_TOKEN;
1122        break;
1123      case 's':
1124        if (lookingAt("import", /*"s"+*/ "chema"))
1125          return curToken = IMPORT_SCHEMA_TOKEN;
1126        break;
1127      case 'v':
1128        if (lookingAt("declare", /*"v"+*/ "ariable"))
1129          return curToken = DECLARE_VARIABLE_TOKEN;
1130        if (lookingAt("define", /*"v"+*/ "ariable"))
1131          {
1132                warnOldVersion("replace 'define variable' by 'declare variable'");
1133        return curToken = DECLARE_VARIABLE_TOKEN;
1134          }
1135            if (lookingAt("xquery", /*"v"+*/ "ersion"))
1136              return curToken = XQUERY_VERSION_TOKEN;
1137        break;
1138      case 'x':
1139        if (lookingAt("declare", /*"x"+*/ "mlspace"))
1140              {
1141        warnOldVersion("replace 'define xmlspace' by 'declare boundary-space'");
1142                return curToken = DECLARE_BOUNDARY_SPACE_TOKEN;
1143              }
1144        break;
1145      }
1146    if (next >= 0)
1147      {
1148        unread();
1149        if (XName.isNameStart((char) next) && curValue.equals("define"))
1150          {
1151        getRawToken();
1152        curToken = DEFINE_QNAME_TOKEN;
1153          }
1154      }
1155    return curToken;
1156      }
1157    if (curToken == NCNAME_COLON_TOKEN)
1158      {
1159    int next = read();
1160    if (next == ':') // We've seen an Axis specifier.
1161
curToken = getAxis();
1162    else
1163      unread(next);
1164      }
1165    return curToken;
1166  }
1167
1168  void checkAllowedNamespaceDeclaration (String JavaDoc prefix, String JavaDoc uri)
1169  {
1170    if ("xml".equals(prefix) || "xmlns".equals(prefix))
1171      error('e', "namespace prefix cannot be 'xml' or 'xmlns'",
1172            "XQST0070");
1173    else if (NamespaceBinding.XML_NAMESPACE.equals(uri))
1174      error('e', "namespace uri cannot be the same as the prefined xml namespace",
1175            "XQST0070");
1176  }
1177
1178  void pushNamespace(String JavaDoc prefix, String JavaDoc uri)
1179  {
1180    if (uri.length() == 0)
1181      uri = null;
1182    prologNamespaces = new NamespaceBinding(prefix, uri, prologNamespaces);
1183  }
1184
1185  public XQParser(InPort port, SourceMessages messages, XQuery interp)
1186  {
1187    super(port, messages);
1188    interpreter = interp;
1189    lexical = new NameLookup(interp);
1190    nesting = 1;
1191
1192    // Push standard namespaces into lexical scope.
1193
NamespaceBinding ns = builtinNamespaces;
1194    prologNamespaces = ns;
1195  }
1196
1197  public void setInteractive(boolean v)
1198  {
1199    if (interactive != v)
1200      if (v) nesting--; else nesting++;
1201    interactive = v;
1202  }
1203  
1204  private static final int priority(int opcode)
1205  {
1206    switch (opcode)
1207      {
1208      case OP_OR:
1209    return 1;
1210      case OP_AND:
1211        return 2;
1212      case OP_EQU: case OP_NEQ:
1213      case OP_LSS: case OP_GRT: case OP_LEQ: case OP_GEQ:
1214      case OP_EQ: case OP_NE:
1215      case OP_LT: case OP_GT: case OP_LE: case OP_GE:
1216      case OP_IS: case OP_ISNOT:
1217      case OP_GRTGRT: case OP_LSSLSS:
1218        return 3;
1219      case OP_RANGE_TO:
1220        return 4;
1221      case OP_ADD: case OP_SUB:
1222    return 5;
1223      case OP_MUL: case OP_DIV: case OP_IDIV: case OP_MOD:
1224        return 6;
1225      case OP_UNION:
1226        return 7;
1227      case OP_INTERSECT: case OP_EXCEPT:
1228        return 8;
1229      case OP_INSTANCEOF:
1230    return 9;
1231      case OP_TREAT_AS:
1232        return 10;
1233      case OP_CASTABLE_AS:
1234        return 11;
1235      case OP_CAST_AS:
1236        return 12;
1237      default:
1238    return 0;
1239      }
1240  }
1241
1242  static Expression makeBinary(Expression func,
1243                   Expression exp1, Expression exp2)
1244  {
1245    Expression[] args = new Expression[2];
1246    args[0] = exp1;
1247    args[1] = exp2;
1248    return new ApplyExp(func, args);
1249  }
1250
1251  static Expression makeExprSequence(Expression exp1, Expression exp2)
1252  {
1253    return makeBinary(makeFunctionExp
1254              ("gnu.kawa.functions.AppendValues", "appendValues"),
1255              exp1, exp2);
1256  }
1257
1258  Expression makeBinary(int op, Expression exp1, Expression exp2)
1259      throws java.io.IOException JavaDoc, SyntaxException
1260  {
1261    Expression func;
1262    switch (op)
1263      {
1264      case OP_ADD:
1265    func = makeFunctionExp("gnu.xquery.util.ArithOp", "add", "+");
1266    break;
1267      case OP_SUB:
1268    func = makeFunctionExp("gnu.xquery.util.ArithOp", "sub", "-");
1269    break;
1270      case OP_MUL:
1271    func = makeFunctionExp("gnu.xquery.util.ArithOp", "mul", "*");
1272    break;
1273      case OP_DIV:
1274    func = makeFunctionExp("gnu.xquery.util.ArithOp", "div", "div");
1275    break;
1276      case OP_IDIV:
1277    func = makeFunctionExp("gnu.xquery.util.ArithOp", "idiv", "idiv");
1278    break;
1279      case OP_MOD:
1280    func = makeFunctionExp("gnu.xquery.util.ArithOp", "mod", "mod");
1281    break;
1282      case OP_EQ:
1283    func = makeFunctionExp("gnu.xquery.util.Compare", "valEq", "eq");
1284    break;
1285      case OP_NE:
1286    func = makeFunctionExp("gnu.xquery.util.Compare", "valNe", "ne");
1287    break;
1288      case OP_LT:
1289    func = makeFunctionExp("gnu.xquery.util.Compare", "valLt", "lt");
1290    break;
1291      case OP_LE:
1292    func = makeFunctionExp("gnu.xquery.util.Compare", "valLe", "le");
1293    break;
1294      case OP_GT:
1295    func = makeFunctionExp("gnu.xquery.util.Compare", "valGt", "gt");
1296    break;
1297      case OP_GE:
1298    func = makeFunctionExp("gnu.xquery.util.Compare", "valGe", "ge");
1299    break;
1300      case OP_EQU:
1301    func = makeFunctionExp("gnu.xquery.util.Compare", "=");
1302    break;
1303      case OP_NEQ:
1304    func = makeFunctionExp("gnu.xquery.util.Compare", "!=");
1305    break;
1306      case OP_LSS:
1307    func = makeFunctionExp("gnu.xquery.util.Compare", "<");
1308    break;
1309      case OP_LEQ:
1310    func = makeFunctionExp("gnu.xquery.util.Compare", "<=");
1311    break;
1312      case OP_GRT:
1313    func = makeFunctionExp("gnu.xquery.util.Compare", ">");
1314    break;
1315      case OP_GEQ:
1316    func = makeFunctionExp("gnu.xquery.util.Compare", ">=");
1317    break;
1318      case OP_IS:
1319    func = makeFunctionExp("gnu.kawa.xml.NodeCompare", "$Eq", "is");
1320    break;
1321      case OP_ISNOT:
1322    func = makeFunctionExp("gnu.kawa.xml.NodeCompare", "$Ne", "isnot");
1323    break;
1324      case OP_GRTGRT:
1325    func = makeFunctionExp("gnu.kawa.xml.NodeCompare", "$Gr", ">>");
1326    break;
1327      case OP_LSSLSS:
1328    func = makeFunctionExp("gnu.kawa.xml.NodeCompare", "$Ls", "<<");
1329    break;
1330      case OP_RANGE_TO:
1331    func = makeFunctionExp("gnu.xquery.util.IntegerRange", "integerRange");
1332    break;
1333      case OP_UNION:
1334    func = makeFunctionExp("gnu.kawa.xml.UnionNodes", "unionNodes");
1335    break;
1336      case OP_INTERSECT:
1337    func = makeFunctionExp("gnu.kawa.xml.IntersectNodes",
1338                   "intersectNodes");
1339    break;
1340      case OP_EXCEPT:
1341    func = makeFunctionExp("gnu.kawa.xml.IntersectNodes", "exceptNodes");
1342    break;
1343      default:
1344    return syntaxError("unimplemented binary op: "+op);
1345      }
1346    return makeBinary(func, exp1, exp2);
1347  }
1348
1349  private void parseSimpleKindType ()
1350    throws java.io.IOException JavaDoc, SyntaxException
1351  {
1352    getRawToken();
1353    if (curToken == ')')
1354      getRawToken();
1355    else
1356      error("expected ')'");
1357  }
1358
1359  public Expression parseNamedNodeType (boolean attribute)
1360      throws java.io.IOException JavaDoc, SyntaxException
1361  {
1362    Expression qname;
1363    getRawToken();
1364    if (curToken == ')')
1365      {
1366        qname = QuoteExp.getInstance(ElementType.MATCH_ANY_QNAME);
1367        getRawToken();
1368      }
1369    else
1370      {
1371        if (curToken == QNAME_TOKEN || curToken == NCNAME_TOKEN)
1372          qname = parseNameTest(attribute);
1373        else
1374          {
1375            if (curToken != OP_MUL)
1376              syntaxError("expected QName or *");
1377            qname = QuoteExp.getInstance(ElementType.MATCH_ANY_QNAME);
1378          }
1379
1380        getRawToken();
1381        if (curToken == ',')
1382          {
1383            getRawToken();
1384            if (curToken == QNAME_TOKEN || curToken == NCNAME_TOKEN)
1385              {
1386                Expression tname = parseNameTest(true);
1387              }
1388            else
1389               syntaxError("expected QName");
1390            getRawToken();
1391          }
1392        if (curToken == ')')
1393          getRawToken();
1394        else
1395          error("expected ')' after element");
1396      }
1397    return makeNamedNodeType(attribute, qname);
1398  }
1399
1400  static Expression makeNamedNodeType (boolean attribute, Expression qname)
1401  {
1402    Expression[] name = new Expression[2];
1403    ClassType nodeType = ClassType.make(attribute
1404                                        ? "gnu.kawa.xml.AttributeType"
1405                                        : "gnu.kawa.xml.ElementType");
1406    ApplyExp elt = new ApplyExp(nodeType.getDeclaredMethod("make", 1),
1407                                new Expression[] { qname });
1408    elt.setFlag(ApplyExp.INLINE_IF_CONSTANT);
1409    return elt;
1410  }
1411
1412  private boolean warnedOldStyleKindTest;
1413  private void warnOldStyleKindTest()
1414  {
1415    if (warnedOldStyleKindTest)
1416      return;
1417    error('w', "old-style KindTest - first one here");
1418    warnedOldStyleKindTest = true;
1419  }
1420
1421  /** Parse: ["as" SequenceType] */
1422  public Expression parseOptionalTypeDeclaration ()
1423      throws java.io.IOException JavaDoc, SyntaxException
1424  {
1425    if (! match("as"))
1426      return null;
1427    getRawToken();
1428    return parseDataType();
1429  }
1430
1431  public Expression parseDataType()
1432      throws java.io.IOException JavaDoc, SyntaxException
1433  {
1434    Expression etype = parseItemType();
1435    int min, max;
1436    if (etype == null)
1437      {
1438        if (curToken != OP_EMPTY_SEQUENCE)
1439          return syntaxError("bad syntax - expected DataType");
1440        parseSimpleKindType();
1441        if (curToken == '?' || curToken == OP_ADD || curToken == OP_MUL)
1442          {
1443            getRawToken();
1444            return syntaxError("occurrence-indicator meaningless after empty-sequence()");
1445          }
1446        etype = QuoteExp.getInstance(OccurrenceType.emptySequenceType);
1447        min = 0;
1448        max = 0;
1449      }
1450    else if (curToken == '?')
1451      {
1452    min = 0;
1453    max = 1;
1454      }
1455    else if (curToken == OP_ADD)
1456      {
1457    min = 1;
1458    max = -1;
1459      }
1460    else if (curToken == OP_MUL)
1461      {
1462    min = 0;
1463    max = -1;
1464      }
1465    else
1466      {
1467    min = 1;
1468    max = 1;
1469      }
1470    if (parseContext == 'C')
1471      {
1472        if (max != 1)
1473          return syntaxError("type to 'cast as' or 'castable as' must be a 'SingleType'");
1474      }
1475    if (min != max)
1476      {
1477    getRawToken();
1478        Expression[] args = { etype,
1479                              QuoteExp.getInstance(gnu.math.IntNum.make(min)),
1480                              QuoteExp.getInstance(gnu.math.IntNum.make(max)) };
1481        ApplyExp otype
1482          = new ApplyExp(ClassType.make("gnu.kawa.reflect.OccurrenceType")
1483                         .getDeclaredMethod("getInstance", 3),
1484                         args);
1485        otype.setFlag(ApplyExp.INLINE_IF_CONSTANT);
1486        return otype;
1487      }
1488    return etype;
1489  }
1490
1491  public Expression parseMaybeKindTest ()
1492      throws java.io.IOException JavaDoc, SyntaxException
1493  {
1494    Type type;
1495    switch (curToken)
1496      {
1497      case OP_ATTRIBUTE:
1498      case OP_ELEMENT:
1499        return parseNamedNodeType(curToken == OP_ATTRIBUTE);
1500
1501      case OP_TEXT:
1502        parseSimpleKindType();
1503        type = NodeType.textNodeTest;
1504        break;
1505
1506      case OP_COMMENT:
1507        parseSimpleKindType();
1508        type = NodeType.commentNodeTest;
1509        break;
1510
1511      case OP_DOCUMENT:
1512        parseSimpleKindType();
1513        type = NodeType.documentNodeTest;
1514        break;
1515
1516      case OP_NODE:
1517        parseSimpleKindType();
1518        type = NodeType.anyNodeTest;
1519        break;
1520
1521      case OP_PI:
1522        getRawToken();
1523        String JavaDoc piTarget = null;
1524        if (curToken == NCNAME_TOKEN || curToken == STRING_TOKEN)
1525          {
1526            piTarget = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
1527            getRawToken();
1528          }
1529        if (curToken == ')')
1530          getRawToken();
1531        else
1532          error("expected ')'");
1533        type = ProcessingInstructionType.getInstance(piTarget);
1534        break;
1535
1536      default:
1537        return null;
1538      }
1539    return QuoteExp.getInstance(type);
1540  }
1541
1542  public Expression parseItemType()
1543      throws java.io.IOException JavaDoc, SyntaxException
1544  {
1545    peekOperand();
1546    Expression etype = parseMaybeKindTest();
1547    Type type;
1548    if (etype != null)
1549      {
1550        if (parseContext == 'C')
1551          // Kludge to force error below.
1552
type = Type.pointer_type;
1553        else
1554          return etype;
1555      }
1556    else if (curToken == OP_ITEM)
1557      {
1558        parseSimpleKindType();
1559        type = Type.pointer_type;
1560      }
1561    else if (curToken == NCNAME_TOKEN || curToken == QNAME_TOKEN)
1562      {
1563    String JavaDoc tname = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
1564    getRawToken();
1565    type = interpreter.getTypeFor(tname);
1566    if (type == null)
1567          {
1568            error('e', "unknown type "+tname, "XPST0051");
1569            type = Type.pointer_type;
1570          }
1571      }
1572    else
1573      return null;
1574    if (parseContext == 'C')
1575      {
1576        if (type == Type.pointer_type)
1577          return syntaxError("type to 'cast as' or 'castable as' must be atomic", "XPST0080");
1578        if (type == XDataType.NotationType)
1579          return syntaxError("type to 'cast as' or 'castable as' cannot be NOTATION", "XPST0080");
1580      }
1581    return QuoteExp.getInstance(type);
1582  }
1583
1584  /** Parse a <code>URILiteral</code>..
1585   * @return either a String (on success),
1586   * or an ErrorExp (after emitting an error).
1587   */

1588  Object JavaDoc parseURILiteral ()
1589      throws java.io.IOException JavaDoc, SyntaxException
1590  {
1591    getRawToken();
1592    if (curToken != STRING_TOKEN)
1593      return declError("expected a URILiteral");
1594    String JavaDoc str = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
1595    str = TextUtils.replaceWhitespace(str, true);
1596    // FUTURE: An implementation MAY raise a static error if the value
1597
// of a URILiteral is of nonzero length and is not in the lexical
1598
// space of xs:anyURI, or if it is a string that represents a
1599
// relative URI as defined in [RFC2396]. err:XQST0046
1600
return str;
1601  }
1602
1603  Expression parseExpr()
1604      throws java.io.IOException JavaDoc, SyntaxException
1605  {
1606    return parseExprSingle();
1607  }
1608
1609  final Expression parseExprSingle ()
1610      throws java.io.IOException JavaDoc, SyntaxException
1611  {
1612    int startLine = curLine;
1613    int startColumn = curColumn;
1614    peekOperand();
1615    switch (curToken)
1616      {
1617        // FIXME old code tweaked line/column
1618
// as in:
1619
// exp.setFile(getName());
1620
// exp.setLine(startLine, startColumn - 3);
1621

1622      case IF_LPAREN_TOKEN:
1623        return parseIfExpr();
1624      case TYPESWITCH_LPAREN_TOKEN:
1625        return parseTypeSwitch();
1626      case FOR_DOLLAR_TOKEN:
1627        return parseFLWRExpression(true);
1628      case LET_DOLLAR_TOKEN:
1629        return parseFLWRExpression(false);
1630      case SOME_DOLLAR_TOKEN:
1631        return parseQuantifiedExpr(false);
1632      case EVERY_DOLLAR_TOKEN:
1633        return parseQuantifiedExpr(true);
1634      default:
1635        return parseBinaryExpr(priority(OP_OR));
1636      }
1637  }
1638
1639  Expression parseBinaryExpr(int prio)
1640      throws java.io.IOException JavaDoc, SyntaxException
1641  {
1642    Expression exp = parseUnaryExpr();
1643    for (;;)
1644      {
1645    int token = peekOperator();
1646    if (token == EOL_TOKEN
1647        // Following makes for better error handling.
1648
|| (token == OP_LSS && peek() == '/'))
1649      return exp;
1650    int tokPriority = priority(token);
1651    if (tokPriority < prio)
1652      return exp;
1653    char saveReadState = pushNesting('%');
1654    getRawToken();
1655    popNesting(saveReadState);
1656        if (token >= OP_INSTANCEOF && token <= OP_CAST_AS)
1657          {
1658            if (token == OP_CAST_AS || token == OP_CASTABLE_AS)
1659              parseContext = 'C';
1660            Expression type = parseDataType();
1661            parseContext = '\0';
1662            Expression[] args = new Expression[2];
1663            Expression func;
1664            switch (token)
1665              {
1666              case OP_INSTANCEOF:
1667                args[0] = exp;
1668                args[1] = type;
1669                func = makeFunctionExp("gnu.xquery.lang.XQParser",
1670                                       "instanceOf");
1671                break;
1672              case OP_CASTABLE_AS:
1673                args[0] = exp;
1674                args[1] = type;
1675                func = new ReferenceExp(XQResolveNames.castableAsDecl);
1676                break;
1677              case OP_TREAT_AS:
1678                args[0] = type;
1679                args[1] = exp;
1680                func = makeFunctionExp("gnu.xquery.lang.XQParser",
1681                                       "treatAs");
1682                break;
1683              default: // i.e. case OP_CAST_AS:
1684
args[0] = type;
1685                args[1] = exp;
1686                func = new ReferenceExp(XQResolveNames.castAsDecl);
1687                break;
1688              }
1689            exp = new ApplyExp(func, args);
1690          }
1691    else if (token == OP_INSTANCEOF)
1692      {
1693        Expression[] args = { exp, parseDataType() };
1694        exp = new ApplyExp(makeFunctionExp("gnu.xquery.lang.XQParser",
1695                           "instanceOf"),
1696                   args);
1697      }
1698    else
1699      {
1700        Expression exp2 = parseBinaryExpr(tokPriority+1);
1701        if (token == OP_AND)
1702          exp = new IfExp(booleanValue(exp), booleanValue(exp2), XQuery.falseExp);
1703        else if (token == OP_OR)
1704          exp = new IfExp(booleanValue(exp), XQuery.trueExp, booleanValue(exp2));
1705        else
1706          exp = makeBinary(token, exp, exp2);
1707      }
1708    }
1709  }
1710
1711  Expression parseUnaryExpr()
1712      throws java.io.IOException JavaDoc, SyntaxException
1713  {
1714    Expression exp;
1715    if (curToken == OP_SUB || curToken == OP_ADD)
1716      {
1717        int op = curToken;
1718        getRawToken();
1719        exp = parseUnaryExpr();
1720        Expression func
1721          = makeFunctionExp("gnu.xquery.util.ArithOp",
1722                            op == OP_ADD ? "plus" : "minus",
1723                            op == OP_ADD ? "+" : "-");
1724        exp = new ApplyExp(func, new Expression[] { exp });
1725      }
1726    else
1727      exp = parseUnionExpr();
1728    return exp;
1729  }
1730
1731  Expression parseUnionExpr()
1732      throws java.io.IOException JavaDoc, SyntaxException
1733  {
1734    Expression exp = parseIntersectExceptExpr();
1735    for (;;)
1736      {
1737    int op = peekOperator();
1738    if (op != OP_UNION)
1739      break;
1740    getRawToken();
1741    Expression exp2 = parseIntersectExceptExpr();
1742    exp = makeBinary(op, exp, exp2);
1743      }
1744    return exp;
1745  }
1746
1747  Expression parseIntersectExceptExpr()
1748      throws java.io.IOException JavaDoc, SyntaxException
1749  {
1750    Expression exp = parsePathExpr();
1751    for (;;)
1752      {
1753    int op = peekOperator();
1754    if (op != OP_INTERSECT && op != OP_EXCEPT)
1755      break;
1756    getRawToken();
1757    Expression exp2 = parsePathExpr();
1758    exp = makeBinary(op, exp, exp2);
1759      }
1760    return exp;
1761  }
1762
1763  Expression parsePathExpr()
1764      throws java.io.IOException JavaDoc, SyntaxException
1765  {
1766    Expression step1;
1767    if (curToken == '/' || curToken == SLASHSLASH_TOKEN)
1768      {
1769    Declaration dotDecl = lexical.lookup(DOT_VARNAME, false);
1770        Expression dot;
1771    if (dotDecl == null)
1772      dot = syntaxError("context item is undefined", "XPDY0002");
1773        else
1774          dot = new ReferenceExp(DOT_VARNAME, dotDecl);
1775    step1 = new ApplyExp(ClassType.make("gnu.xquery.util.NodeUtils")
1776                 .getDeclaredMethod("root", 1),
1777                 new Expression[] { dot } );
1778    int next = skipSpace(nesting != 0);
1779        unread(next);
1780        if (next < 0 || next == ')' || next == '}')
1781          {
1782        getRawToken();
1783            return step1;
1784          }
1785      }
1786    else
1787      step1 = parseStepExpr();
1788    return parseRelativePathExpr(step1);
1789  }
1790
1791  /** Returns an expression that evaluates to a Symbol.
1792   * The expression will normally be constant
1793   * folded to a Symbol, but we cannot do that yet. */

1794  Expression parseNameTest (boolean attribute)
1795      throws java.io.IOException JavaDoc, SyntaxException
1796  {
1797    String JavaDoc local = null, prefix = null;
1798    if (curToken == QNAME_TOKEN)
1799      {
1800    int colon = tokenBufferLength;
1801    while (tokenBuffer[--colon] != ':') ;
1802    prefix = new String JavaDoc(tokenBuffer, 0, colon);
1803    colon++;
1804    local = new String JavaDoc(tokenBuffer, colon,
1805               tokenBufferLength - colon);
1806      }
1807    else if (curToken == OP_MUL)
1808      {
1809    int next = read();
1810        local = ElementType.MATCH_ANY_LOCALNAME;
1811    if (next != ':')
1812      unread(next);
1813    else
1814      {
1815        next = read();
1816        if (next < 0)
1817          eofError("unexpected end-of-file after '*:'");
1818        if (XName.isNameStart((char) next))
1819          {
1820        unread();
1821        getRawToken();
1822        if (curToken != NCNAME_TOKEN)
1823          syntaxError("invalid name test");
1824        else
1825          local = new String JavaDoc(tokenBuffer, 0, tokenBufferLength)
1826                    .intern();
1827          }
1828        else if (next != '*')
1829          syntaxError("missing local-name after '*:'");
1830      }
1831        return QuoteExp.getInstance(new Symbol(null, local));
1832      }
1833    else if (curToken == NCNAME_TOKEN)
1834      {
1835    local = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
1836        if (attribute)
1837          return new QuoteExp(Namespace.EmptyNamespace.getSymbol(local.intern()));
1838        prefix = null;
1839      }
1840    else if (curToken == NCNAME_COLON_TOKEN)
1841      {
1842    prefix = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
1843    int next = read();
1844    if (next != '*')
1845      syntaxError("invalid characters after 'NCName:'");
1846    local = ElementType.MATCH_ANY_LOCALNAME;
1847      }
1848    if (prefix != null)
1849      prefix = prefix.intern();
1850    Expression[] args = new Expression[3];
1851    args[0] = new ApplyExp(new ReferenceExp(XQResolveNames.resolvePrefixDecl),
1852                           new Expression[] { QuoteExp.getInstance(prefix) });
1853    args[1] = new QuoteExp(local == null ? "" : local);
1854    args[2] = new QuoteExp(prefix);
1855    ApplyExp make = new ApplyExp(Compilation.typeSymbol
1856                                 .getDeclaredMethod("make", 3),
1857                                 args);
1858    make.setFlag(ApplyExp.INLINE_IF_CONSTANT);
1859    return make;
1860  }
1861
1862  Expression parseNodeTest(int axis)
1863      throws java.io.IOException JavaDoc, SyntaxException
1864  {
1865    int token = peekOperand();
1866    Expression[] args = new Expression[1];
1867
1868    Expression etype = parseMaybeKindTest();
1869
1870    if (etype != null)
1871      {
1872    args[0] = etype;
1873      }
1874    else if (curToken == NCNAME_TOKEN || curToken == QNAME_TOKEN
1875         || curToken == NCNAME_COLON_TOKEN || curToken == OP_MUL)
1876      {
1877        args[0] = makeNamedNodeType(axis == AXIS_ATTRIBUTE,
1878                                    parseNameTest(axis == AXIS_ATTRIBUTE) );
1879      }
1880    else if (axis >= 0)
1881      return syntaxError("unsupported axis '"+axisNames[axis]+"::'");
1882    else
1883      return null;
1884
1885    Declaration dotDecl = lexical.lookup(DOT_VARNAME, false);
1886    Expression dot;
1887    if (dotDecl == null)
1888      dot = syntaxError("node test when context item is undefined", "XPDY0002");
1889    else
1890      dot = new ReferenceExp(DOT_VARNAME, dotDecl);
1891    if (etype == null)
1892      getRawToken();
1893
1894    Expression makeAxisStep;
1895    if (axis == AXIS_CHILD || axis == -1)
1896      makeAxisStep = makeChildAxisStep;
1897    else if (axis == AXIS_DESCENDANT)
1898      makeAxisStep = makeDescendantAxisStep;
1899    else
1900      {
1901        String JavaDoc axisName;
1902        switch (axis)
1903          {
1904          case AXIS_DESCENDANT_OR_SELF: axisName = "DescendantOrSelf"; break;
1905          case AXIS_SELF: axisName = "Self"; break;
1906          case AXIS_PARENT: axisName = "Parent"; break;
1907          case AXIS_ANCESTOR: axisName = "Ancestor"; break;
1908          case AXIS_ANCESTOR_OR_SELF: axisName = "AncestorOrSelf"; break;
1909          case AXIS_FOLLOWING: axisName = "Following"; break;
1910          case AXIS_FOLLOWING_SIBLING: axisName = "FollowingSibling"; break;
1911          case AXIS_PRECEDING: axisName = "Preceding"; break;
1912          case AXIS_PRECEDING_SIBLING: axisName = "PrecedingSibling"; break;
1913          case AXIS_ATTRIBUTE: axisName = "Attribute"; break;
1914          default: throw new Error JavaDoc();
1915          }
1916        makeAxisStep
1917          = QuoteExp.getInstance(new PrimProcedure
1918                                 ("gnu.kawa.xml."+axisName+"Axis",
1919                                  "make", 1));
1920      }
1921    ApplyExp mkAxis = new ApplyExp(makeAxisStep, args);
1922    mkAxis.setFlag(ApplyExp.INLINE_IF_CONSTANT);
1923    return new ApplyExp(mkAxis, new Expression[] { dot });
1924  }
1925
1926  public static QuoteExp makeChildAxisStep
1927  = QuoteExp.getInstance(new PrimProcedure("gnu.kawa.xml.ChildAxis", "make", 1));
1928  public static QuoteExp makeDescendantAxisStep
1929  = QuoteExp.getInstance(new PrimProcedure("gnu.kawa.xml.DescendantAxis", "make", 1));
1930
1931  Expression parseRelativePathExpr(Expression exp)
1932      throws java.io.IOException JavaDoc, SyntaxException
1933  {
1934    // If the previous operator was '//', then the corresponding E1.
1935
Expression beforeSlashSlash = null;
1936
1937    while (curToken == '/' || curToken == SLASHSLASH_TOKEN)
1938      {
1939    boolean descendants = curToken == SLASHSLASH_TOKEN;
1940
1941    LambdaExp lexp = new LambdaExp(3);
1942    Declaration dotDecl = lexp.addDeclaration(DOT_VARNAME);
1943    dotDecl.setFlag(Declaration.IS_SINGLE_VALUE);
1944        dotDecl.setType(SingletonType.getInstance());
1945    dotDecl.noteValue (null); // Does not have a known value.
1946
lexp.addDeclaration(POSITION_VARNAME, LangPrimType.intType);
1947    lexp.addDeclaration(LAST_VARNAME, LangPrimType.intType);
1948    comp.push(lexp);
1949    if (descendants)
1950      {
1951        curToken = '/';
1952        Expression dot = new ReferenceExp(DOT_VARNAME, dotDecl);
1953        Expression[] args = { dot };
1954        TreeScanner op = DescendantOrSelfAxis.anyNode;
1955        lexp.body = new ApplyExp(op, args);
1956            beforeSlashSlash = exp;
1957      }
1958    else
1959      {
1960        getRawToken();
1961            Expression exp2 = parseStepExpr();
1962
1963            // Optimize: 'E1//child::TEST' to 'E1/descendant::TEST'
1964
Expression func;
1965            ApplyExp aexp;
1966            if (beforeSlashSlash != null
1967                && exp2 instanceof ApplyExp
1968                && (func = ((ApplyExp) exp2).getFunction()) instanceof ApplyExp
1969                && (aexp = (ApplyExp) func).getFunction() == makeChildAxisStep)
1970              {
1971                aexp.setFunction(makeDescendantAxisStep);
1972                exp = beforeSlashSlash;
1973              }
1974
1975            lexp.body = exp2;
1976            beforeSlashSlash = null;
1977      }
1978    comp.pop(lexp);
1979
1980    /*
1981    if (lexp.body instanceof ApplyExp)
1982      {
1983        // Optimize the case of a simple name step.
1984        ApplyExp aexp = (ApplyExp) lexp.body;
1985        Expression func = aexp.getFunction();
1986        Expression[] args = aexp.getArgs();
1987        if (false
1988        && func == funcNamedChildren && args.length==2
1989        && args[0] instanceof ReferenceExp
1990        && ((ReferenceExp) args[0]).getBinding() == decl)
1991          {
1992        args[0] = exp;
1993        if (descendants)
1994          func = funcNamedDescendants;
1995        exp = new ApplyExp (func, args);
1996        handled = true;
1997          }
1998        else if (func == funcForwardFilter && args.length==2
1999             && args[0] instanceof ApplyExp
2000             && descendants)
2001          {
2002        ApplyExp xapp = (ApplyExp) args[0];
2003        Expression[] xargs = xapp.getArgs();
2004        if (xapp.getFunction() == funcNamedChildren
2005            && xargs.length == 2
2006            && ((ReferenceExp) xargs[0]).getBinding() == decl)
2007          {
2008            xapp.setFunction(funcNamedDescendants);
2009          }
2010          }
2011      }
2012    */

2013
2014    Expression[] args = new Expression[] { exp, lexp };
2015    exp = new ApplyExp(RelativeStep.relativeStep, args);
2016      }
2017    return exp;
2018  }
2019
2020  Expression parseStepExpr()
2021      throws java.io.IOException JavaDoc, SyntaxException
2022  {
2023    int axis;
2024    if (curToken == '.' || curToken == DOTDOT_TOKEN)
2025      {
2026    axis = curToken == '.' ? AXIS_SELF : AXIS_PARENT;
2027    getRawToken();
2028    Declaration dotDecl = lexical.lookup(DOT_VARNAME, false);
2029        Expression exp;
2030    if (dotDecl == null)
2031      exp = syntaxError("context item is undefined", "XPDY0002");
2032    else
2033          exp = new ReferenceExp(DOT_VARNAME, dotDecl);
2034    if (axis == AXIS_PARENT)
2035      {
2036        Expression[] args = { exp };
2037        exp = new ApplyExp(ParentAxis.make(NodeType.anyNodeTest), args);
2038      }
2039        // Note that '..' is an AbbrevReverseStep,
2040
// but '.' is a FilterExpr - and hence not a valid ForwardStep.
2041
return parseStepQualifiers(exp, axis == AXIS_SELF ? -1 : axis);
2042      }
2043    axis = peekOperand() - OP_AXIS_FIRST;
2044    Expression unqualifiedStep;
2045    if (axis >= 0 && axis < COUNT_OP_AXIS)
2046      {
2047    getRawToken();
2048    unqualifiedStep = parseNodeTest(axis);
2049      }
2050    else if (curToken == '@')
2051      {
2052    getRawToken();
2053    axis = AXIS_ATTRIBUTE;
2054    unqualifiedStep = parseNodeTest(axis);
2055      }
2056    else
2057      {
2058    unqualifiedStep = parseNodeTest(-1);
2059        if (unqualifiedStep != null)
2060          {
2061            axis = AXIS_CHILD;
2062          }
2063        else
2064          {
2065            axis = -1;
2066            unqualifiedStep = parsePrimaryExpr();
2067          }
2068      }
2069    return parseStepQualifiers(unqualifiedStep, axis);
2070  }
2071
2072  Expression parseStepQualifiers(Expression exp, int axis)
2073    throws java.io.IOException JavaDoc, SyntaxException
2074  {
2075    for (;;)
2076      {
2077    if (curToken == '[')
2078      {
2079        int startLine = getLineNumber() + 1;
2080        int startColumn = getColumnNumber() + 1;
2081        int saveSeenPosition = seenPosition;
2082        int saveSawLast = seenLast;
2083        getRawToken();
2084        LambdaExp lexp = new LambdaExp(3);
2085        lexp.setFile(getName());
2086        lexp.setLine(startLine, startColumn);
2087        Declaration dot = lexp.addDeclaration(DOT_VARNAME);
2088            if (axis >= 0)
2089              dot.setType(NodeType.anyNodeTest);
2090            else
2091              dot.setType(SingletonType.getInstance());
2092        lexp.addDeclaration(POSITION_VARNAME, Type.int_type);
2093        lexp.addDeclaration(LAST_VARNAME, Type.int_type);
2094        comp.push(lexp);
2095        dot.noteValue(null);
2096        Expression cond = parseExprSequence(']', false);
2097            if (curToken == EOF_TOKEN)
2098              eofError("missing ']' - unexpected end-of-file");
2099        char kind;
2100        Procedure valuesFilter;
2101        if (axis < 0)
2102          {
2103        kind = 'P';
2104        valuesFilter = ValuesFilter.exprFilter;
2105          }
2106        else if (axis == AXIS_ANCESTOR || axis == AXIS_ANCESTOR_OR_SELF
2107             || axis == AXIS_PARENT || axis == AXIS_PRECEDING
2108             || axis == AXIS_PRECEDING_SIBLING)
2109          {
2110        kind = 'R';
2111        valuesFilter = ValuesFilter.reverseFilter;
2112          }
2113        else
2114          {
2115        kind = 'F';
2116        valuesFilter = ValuesFilter.forwardFilter;
2117          }
2118        /*)
2119        boolean sawPosition = seenPosition > saveSeenPosition;
2120        boolean sawLast = seenLast > saveSeenLast;
2121        */

2122        cond.setFile(getName());
2123        cond.setLine(startLine, startColumn);
2124        comp.pop(lexp);
2125        lexp.body = cond;
2126        getRawToken();
2127        Expression[] args = { exp, lexp };
2128        exp = new ApplyExp(valuesFilter, args);
2129      }
2130    /*
2131    else if (curToken == ARROW_TOKEN)
2132      ...;
2133    */

2134    else
2135      {
2136        return exp;
2137      }
2138      }
2139  }
2140
2141  /**
2142   * Parse a PrimaryExpr.
2143   * @return an Expression.
2144   */

2145  Expression parsePrimaryExpr()
2146      throws java.io.IOException JavaDoc, SyntaxException
2147  {
2148    Expression exp = parseMaybePrimaryExpr();
2149    if (exp == null)
2150      {
2151    exp = syntaxError("missing expression");
2152    if (curToken != EOF_TOKEN)
2153      getRawToken();
2154    return exp;
2155      }
2156    return exp;
2157  }
2158
2159  void parseEntityOrCharRef ()
2160      throws java.io.IOException JavaDoc, SyntaxException
2161  {
2162    int next = read();
2163    if (next == '#')
2164      {
2165    int base;
2166    next = read();
2167    if (next == 'x')
2168      {
2169        base = 16;
2170        next = read();
2171      }
2172    else
2173      base = 10;
2174    int value = 0;
2175    while (next >= 0)
2176      {
2177        char ch = (char) next;
2178        int digit = Character.digit((char) ch, base);
2179        if (digit < 0)
2180          break;
2181        if (value >= 0x8000000)
2182          break; // Overflow likely.
2183
value = value * base;
2184        value += digit;
2185        next = read();
2186      }
2187    if (next != ';')
2188      {
2189        unread();
2190        error("invalid character reference");
2191      }
2192        // See definition of 'Char' in XML 1.1 2nd ed Specification.
2193
else if ((value > 0 && value <= 0xD7FF)
2194                 || (value >= 0xE000 && value <= 0xFFFD)
2195                 || (value >= 0x10000 && value <= 0x10FFFF))
2196          tokenBufferAppend(value);
2197        else
2198          error('e', "invalid character value "+value, "XQST0090");
2199      }
2200    else
2201      {
2202    int saveLength = tokenBufferLength;
2203    while (next >= 0)
2204      {
2205        char ch = (char) next;
2206        if (! XName.isNamePart(ch))
2207          break;
2208        tokenBufferAppend(ch);
2209        next = read();
2210      }
2211    if (next != ';')
2212      {
2213        unread();
2214        error("invalid entity reference");
2215        return;
2216      }
2217    String JavaDoc ref = new String JavaDoc(tokenBuffer, saveLength,
2218                tokenBufferLength - saveLength);
2219    tokenBufferLength = saveLength;
2220    appendNamedEntity(ref);
2221      }
2222  }
2223
2224  /** Count of enclosed expressions seen in element or attribute content. */
2225  int enclosedExpressionsSeen;
2226
2227  static Expression makeText = makeFunctionExp("gnu.kawa.xml.MakeText",
2228                                               "makeText");
2229
2230  /** Parse ElementContent (delimiter == '<') or AttributeContent (otherwise).
2231   * @param delimiter is '<' if parsing ElementContent, is either '\'' or
2232   * '\"' if parsing AttributeContent depending on the starting quote
2233   * @param result a buffer to place the resulting Expressions.
2234   */

2235  void parseContent(char delimiter, Vector JavaDoc result)
2236      throws java.io.IOException JavaDoc, SyntaxException
2237  {
2238    tokenBufferLength = 0;
2239    int startSize = result.size();
2240    int prevEnclosed = startSize - 1;
2241    boolean skipBoundarySpace = ! boundarySpacePreserve && delimiter == '<';
2242    boolean skippable = skipBoundarySpace;
2243    for (;;)
2244      {
2245    int next = read();
2246    if (next == delimiter && delimiter != '<' && checkNext(delimiter))
2247      {
2248        tokenBufferAppend(delimiter);
2249        continue;
2250      }
2251    if (next == delimiter || next < 0 || next == '{')
2252      {
2253          addText:
2254            {
2255              String JavaDoc text;
2256              if (tokenBufferLength > 0 && ! skippable)
2257                text = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
2258              else if (next == '{' && prevEnclosed == result.size())
2259                // Handle the <a>{E1}{E2}</a> case - we must insert a
2260
// joiner between E1 ad E2 to avoid a space being inserted.
2261
text = "";
2262              else
2263                break addText; // Don't need to add anything.
2264
Expression[] args = { new QuoteExp(text) };
2265              result.addElement(new ApplyExp(makeText, args));
2266            }
2267        tokenBufferLength = 0;
2268      }
2269    if (next < 0)
2270      eofError("unexpected end-of-file");
2271    if (next == '{')
2272      {
2273        next = read();
2274        if (next == '{')
2275          {
2276        tokenBufferAppend('{');
2277        skippable = false;
2278          }
2279        else
2280          {
2281        unread(next);
2282                enclosedExpressionsSeen++;
2283        Expression exp = parseEnclosedExpr();
2284        result.addElement(exp);
2285        tokenBufferLength = 0;
2286        prevEnclosed = result.size();
2287        skippable = skipBoundarySpace;
2288          }
2289      }
2290    else if (next == '}')
2291      {
2292        next = read();
2293        if (next == '}')
2294          {
2295        tokenBufferAppend('}');
2296        skippable = false;
2297          }
2298        else
2299          {
2300        error("unexpected '}' in element content");
2301        unread(next);
2302          }
2303      }
2304    else if (next == delimiter)
2305      {
2306        if (delimiter != '<')
2307          {
2308        break;
2309          }
2310        else
2311          {
2312        next = read();
2313        if (next == '/')
2314          break;
2315                Expression content = parseXMLConstructor(next, true);
2316        result.addElement(content);
2317        tokenBufferLength = 0;
2318                if (content instanceof ApplyExp
2319                    && ((ApplyExp) content).getFunction() == makeCDATA)
2320                  skippable = false;
2321                else
2322                  skippable = skipBoundarySpace;
2323          }
2324      }
2325    else if (next == '&')
2326      {
2327        parseEntityOrCharRef();
2328        skippable = false;
2329      }
2330    else
2331      {
2332            if (delimiter != '<'
2333                && (next == '\t' || next == '\n' || next == '\r'))
2334              next = ' ';
2335            if (next == '<')
2336              error('e', "'<' must be quoted in a direct attribute value");
2337        if (skippable)
2338          skippable = Character.isWhitespace((char) next);
2339        tokenBufferAppend((char) next);
2340      }
2341      }
2342  }
2343
2344  /** Parse an EnclosedExpr.
2345   * Assume the '{' has been read.
2346   */

2347  Expression parseEnclosedExpr()
2348      throws java.io.IOException JavaDoc, SyntaxException
2349  {
2350    String JavaDoc saveErrorIfComment = errorIfComment;
2351    errorIfComment = null;
2352    char saveReadState = pushNesting('{');
2353    peekNonSpace("unexpected end-of-file after '{'");
2354    int startLine = getLineNumber() + 1;
2355    int startColumn = getColumnNumber() + 1;
2356    getRawToken();
2357    Expression exp = parseExpr();
2358    for (;;)
2359      {
2360    if (curToken == '}')
2361      break;
2362    if (curToken == EOF_TOKEN || curToken == ')' || curToken == ']')
2363      {
2364        exp = syntaxError("missing '}'");
2365        break;
2366      }
2367    if (curToken != ',')
2368      exp = syntaxError("missing '}' or ','");
2369    else
2370      getRawToken();
2371
2372    exp = makeExprSequence(exp, parseExpr());
2373
2374      }
2375    exp.setFile(getName());
2376    exp.setLine(startLine, startColumn);
2377    popNesting(saveReadState);
2378    errorIfComment = saveErrorIfComment;
2379    return exp;
2380  }
2381
2382  /** Coerce the value of an expresison to a boolean value. */
2383  public static Expression booleanValue(Expression exp)
2384  {
2385    Expression[] args = { exp };
2386    Expression string
2387      = makeFunctionExp("gnu.xquery.util.BooleanValue", "booleanValue");
2388    return new ApplyExp(string, args);
2389  }
2390
2391  static final Expression makeCDATA =
2392    makeFunctionExp("gnu.kawa.xml.MakeCDATA", "makeCDATA");
2393
2394  /** Parse an ElementConstructor or other constructs starting with '<'.
2395   * Assume initial '<' has been processed.
2396   * @param next next character (after '<').
2397   */

2398  Expression parseXMLConstructor (int next, boolean inElementContent)
2399      throws java.io.IOException JavaDoc, SyntaxException
2400  {
2401    Expression exp;
2402    if (next == '!')
2403      {
2404    next = read();
2405    if (next == '-' && peek() == '-')
2406      {
2407        skip();
2408        getDelimited("-->");
2409            boolean bad = false;
2410            int i = tokenBufferLength;
2411            boolean sawHyphen = true;
2412            while (--i >= 0)
2413              {
2414                boolean curHyphen = tokenBuffer[i] == '-';
2415                if (sawHyphen && curHyphen)
2416                  {
2417                    bad = true;
2418                    break;
2419                  }
2420                sawHyphen = curHyphen;
2421              }
2422            if (bad)
2423              exp = syntaxError("consecutive or final hyphen in XML comment");
2424            else
2425              {
2426                Expression[] args =
2427                  { new QuoteExp(new String JavaDoc(tokenBuffer, 0, tokenBufferLength)) };
2428                exp = new ApplyExp(makeFunctionExp("gnu.kawa.xml.CommentConstructor",
2429                                                   "commentConstructor"),
2430                                   args);
2431              }
2432      }
2433    else if (next == '[' && read() == 'C' && read() == 'D'
2434         && read() == 'A' && read() == 'T' && read() == 'A'
2435         && read() == '[')
2436      {
2437            if (! inElementContent)
2438              error('e', "CDATA section must be in element content");
2439        getDelimited("]]>");
2440        Expression[] args =
2441          { new QuoteExp(new String JavaDoc(tokenBuffer, 0, tokenBufferLength)) };
2442        exp = new ApplyExp(makeCDATA, args);
2443      }
2444    else
2445      exp = syntaxError("'<!' must be followed by '--' or '[CDATA['");
2446      }
2447    else if (next == '?')
2448      {
2449    next = peek();
2450    if (next < 0 || ! XName.isNameStart((char) next)
2451        || getRawToken() != NCNAME_TOKEN)
2452      syntaxError("missing target after '<?'");
2453    String JavaDoc target = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
2454        int nspaces = 0;
2455        for (;;)
2456          {
2457            int ch = read();
2458            if (ch < 0)
2459              break;
2460            if (! Character.isWhitespace((char) ch))
2461              {
2462                unread();
2463                break;
2464              }
2465            nspaces++;
2466          }
2467    getDelimited("?>");
2468        if (nspaces == 0 && tokenBufferLength > 0)
2469          syntaxError("target must be followed by space or '?>'");
2470    String JavaDoc content = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
2471    Expression[] args = { new QuoteExp(target), new QuoteExp(content) };
2472    exp = new ApplyExp(makeFunctionExp("gnu.kawa.xml.MakeProcInst",
2473                       "makeProcInst"),
2474               args);
2475      }
2476    else if (next < 0 || ! XName.isNameStart((char) next))
2477      exp = syntaxError("expected QName after '<'");
2478    else
2479      {
2480    unread(next);
2481    getRawToken();
2482    char saveReadState = pushNesting('<');
2483    exp = parseElementConstructor();
2484        if (! inElementContent)
2485          exp = wrapWithBaseUri(exp);
2486    popNesting(saveReadState);
2487      }
2488    return exp;
2489  }
2490
2491  /** Generate code to cast argument to a QName
2492   * (which is implemented using <code>Symbol</code>). */

2493  static ApplyExp castQName (Expression value)
2494  {
2495    return new ApplyExp(new ReferenceExp(XQResolveNames.xsQNameDecl),
2496            new Expression[] { value });
2497  }
2498
2499  /** Parse ElementConstructor.
2500   * Assume initial {@code '<'} has been processed,
2501   * and we're looking at the next token..
2502   * Reads through end of the end tag. FIXME
2503   */

2504  Expression parseElementConstructor()
2505      throws java.io.IOException JavaDoc, SyntaxException
2506  {
2507    // Note that we cannot do namespace resolution at parse time,
2508
// because of constructs like this: <a x="{$x:v}" xmlns:x="xx"/>
2509
// Instead we defer namespaced lookup until XQResolveNames. (Mostly -
2510
// some places still incorrectly do premature namespace resolution.)
2511
String JavaDoc startTag = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
2512    Vector JavaDoc vec = new Vector JavaDoc();
2513    Expression[] args;
2514    vec.addElement(castQName(new QuoteExp(startTag)));
2515    errorIfComment = "comment not allowed in element start tag";
2516    NamespaceBinding nsBindings = null;
2517    int ch;
2518    for (;;)
2519      {
2520    ch = skipSpace();
2521    if (ch < 0 || ch == '>' || ch == '/')
2522      break;
2523    unread(ch);
2524    getRawToken();
2525    int vecSize = vec.size();
2526    if (curToken != NCNAME_TOKEN && curToken != QNAME_TOKEN)
2527      break;
2528    String JavaDoc attrName = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
2529    int startLine = getLineNumber() + 1;
2530    int startColumn = getColumnNumber() + 1 - tokenBufferLength;
2531    String JavaDoc definingNamespace = null;
2532    if (curToken == NCNAME_TOKEN)
2533      {
2534        if (attrName.equals("xmlns"))
2535          definingNamespace = "";
2536      }
2537    else
2538      {
2539        if (attrName.startsWith("xmlns:"))
2540          definingNamespace = attrName.substring(6).intern();
2541      }
2542    Expression makeAttr
2543      = definingNamespace != null ? null
2544      : MakeAttribute.makeAttributeExp;
2545    vec.addElement(castQName(new QuoteExp(attrName)));
2546    ch = skipSpace();
2547    if (ch != '=')
2548          {
2549            errorIfComment = null;
2550            return syntaxError("missing '=' after attribute");
2551          }
2552    ch = skipSpace();
2553        int enclosedExpressionsStart = enclosedExpressionsSeen;
2554    if (ch == '{')
2555      {
2556            warnOldVersion("enclosed attribute value expression should be quoted");
2557        vec.addElement(parseEnclosedExpr());
2558      }
2559    else
2560      parseContent((char) ch, vec);
2561    int n = vec.size() - vecSize;
2562    if (definingNamespace != null)
2563      {
2564        String JavaDoc ns = "";
2565        if (n == 1)
2566          ns = "";
2567        else if (enclosedExpressionsSeen > enclosedExpressionsStart)
2568          syntaxError("enclosed expression not allowed in namespace declaration");
2569        else
2570              {
2571                Object JavaDoc x = vec.elementAt(vecSize+1);
2572                ApplyExp ax;
2573                if (x instanceof ApplyExp
2574                    && (ax = (ApplyExp) x).getFunction() == makeText)
2575                  x = ax.getArg(0);
2576                ns = ((QuoteExp) x).getValue()
2577        .toString().intern();
2578              }
2579        vec.setSize(vecSize);
2580            checkAllowedNamespaceDeclaration(definingNamespace, ns);
2581        if (definingNamespace == "")
2582          definingNamespace = null;
2583            for (NamespaceBinding nsb = nsBindings;
2584                 nsb != null; nsb = nsb.getNext())
2585              {
2586                if (nsb.getPrefix() == definingNamespace)
2587                  {
2588                    error('e',
2589                          definingNamespace == null
2590                          ? "duplicate default namespace declaration"
2591                          : "duplicate namespace prefix '"+definingNamespace+'\'',
2592                          "XQST0071");
2593                    break;
2594                  }
2595              }
2596        nsBindings
2597          = new NamespaceBinding(definingNamespace,
2598                     ns == "" ? null : ns,
2599                     nsBindings);
2600      }
2601    else
2602      {
2603        args = new Expression[n];
2604        for (int i = n; --i >= 0; )
2605          args[i] = (Expression) vec.elementAt(vecSize + i);
2606        vec.setSize(vecSize);
2607        ApplyExp aexp = new ApplyExp(makeAttr, args);
2608        aexp.setFile(getName());
2609        aexp.setLine(startLine, startColumn);
2610        vec.addElement(aexp);
2611      }
2612      }
2613    errorIfComment = null;
2614    boolean empty = false;
2615    if (ch == '/')
2616      {
2617    ch = read();
2618    if (ch == '>')
2619      empty = true;
2620    else
2621      unread(ch);
2622      }
2623    if (! empty)
2624      {
2625    if (ch != '>')
2626      return syntaxError("missing '>' after start element");
2627    parseContent('<', vec);
2628    ch = peek();
2629        if (ch >= 0)
2630      {
2631            if (! XName.isNameStart((char) ch))
2632          return syntaxError("invalid tag syntax after '</'");
2633        getRawToken();
2634        String JavaDoc tag = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
2635        if (! (tag.equals(startTag)))
2636          return syntaxError("'<"+startTag+">' closed by '</"+tag+">'");
2637            errorIfComment = "comment not allowed in element end tag";
2638        ch = skipSpace();
2639            errorIfComment = null;
2640      }
2641    if (ch != '>')
2642      return syntaxError("missing '>' after end element");
2643      }
2644    args = new Expression[vec.size()];
2645    vec.copyInto(args);
2646    MakeElement mkElement = new MakeElement();
2647    mkElement.copyNamespacesMode = copyNamespacesMode;
2648    // Ths is just the chain of NamespaceBindings for namespace declaration
2649
// attributes from this immediate constructor. At resolve time we chain
2650
// this list onto the list from outer element constructors.
2651
mkElement.setNamespaceNodes(nsBindings);
2652    Expression result = new ApplyExp(new QuoteExp(mkElement), args);
2653    return result;
2654  }
2655
2656  Expression wrapWithBaseUri (Expression exp)
2657  {
2658    if (getStaticBaseUri() == null)
2659      return exp;
2660    return new ApplyExp(MakeWithBaseUri.makeWithBaseUri,
2661                        new Expression[] {
2662                          new ApplyExp(new ReferenceExp(XQResolveNames.staticBaseUriDecl), Expression.noExpressions),
2663                          exp })
2664      .setLine(exp);
2665  }
2666
2667  /** Parse ParenthesizedExpr.
2668   *.When called, curToken should be pointing at a '(',
2669   * or a token which ends if a '(', such as IF_LPAREN_TOKEN.
2670   */

2671  Expression parseParenExpr ()
2672      throws java.io.IOException JavaDoc, SyntaxException
2673  {
2674    getRawToken();
2675    char saveReadState = pushNesting('(');
2676    Expression exp = parseExprSequence(')', true);
2677    popNesting(saveReadState);
2678    if (curToken == EOF_TOKEN)
2679      eofError("missing ')' - unexpected end-of-file");
2680    return exp;
2681  }
2682
2683  Expression parseExprSequence(int rightToken, boolean optional)
2684      throws java.io.IOException JavaDoc, SyntaxException
2685  {
2686    if (curToken == rightToken || curToken == EOF_TOKEN)
2687      {
2688        if (! optional)
2689          syntaxError("missing expression");
2690        return QuoteExp.voidExp;
2691      }
2692    Expression exp = null;
2693    for (;;)
2694      {
2695    Expression exp1 = parseExprSingle();
2696
2697    exp = exp == null ? exp1 : makeExprSequence(exp, exp1);
2698    if (curToken == rightToken || curToken == EOF_TOKEN)
2699      break;
2700    if (nesting == 0 && curToken == EOL_TOKEN)
2701      return exp;
2702    if (curToken != ',')
2703      return syntaxError (rightToken == ')' ? "expected ')'"
2704                   : "confused by syntax error");
2705    getRawToken();
2706      }
2707    return exp;
2708  }
2709
2710  Expression parseTypeSwitch()
2711    throws java.io.IOException JavaDoc, SyntaxException
2712  {
2713    char save = pushNesting('t');
2714    Expression selector = parseParenExpr();
2715    getRawToken();
2716    Object JavaDoc varName = null;
2717    Declaration decl;
2718    Vector JavaDoc vec = new Vector JavaDoc();
2719    vec.addElement(selector);
2720    while (match("case"))
2721      {
2722    pushNesting('c');
2723    getRawToken();
2724    if (curToken == '$')
2725      {
2726        decl = parseVariableDeclaration();
2727        if (decl == null)
2728          return syntaxError("missing Variable after '$'");
2729        getRawToken();
2730        if (match("as"))
2731          getRawToken();
2732        else
2733          error('e', "missing 'as'");
2734      }
2735    else
2736      decl = new Declaration("(arg)");
2737    decl.setTypeExp(parseDataType());
2738    popNesting('t');
2739    LambdaExp lexp = new LambdaExp(1);
2740    lexp.addDeclaration(decl);
2741    if (match("return"))
2742      getRawToken();
2743    else
2744      error("missing 'return' after 'case'");
2745    comp.push(lexp);
2746    pushNesting('r');
2747    Expression caseExpr = parseExpr();
2748    lexp.body = caseExpr;
2749    popNesting('t');
2750    comp.pop(lexp);
2751    vec.addElement(lexp);
2752      }
2753    if (curToken == '$')
2754      {
2755    decl = parseVariableDeclaration();
2756    if (decl == null)
2757      return syntaxError("missing Variable after '$'");
2758    getRawToken();
2759      }
2760    else
2761      decl = new Declaration("(arg)");
2762    LambdaExp lexp = new LambdaExp(1);
2763    lexp.addDeclaration(decl);
2764    if (match("default"))
2765      {
2766    getRawToken();
2767    if (match("return"))
2768      getRawToken();
2769    else
2770      error("missing 'return' after 'default'");
2771    comp.push(lexp);
2772    Expression defaultExpr = parseExpr();
2773    lexp.body = defaultExpr;
2774    comp.pop(lexp);
2775      }
2776    else
2777      {
2778    lexp.body = QuoteExp.voidExp;
2779     error(comp.isPedantic() ? 'e' : 'w',
2780               "no 'default' clause in 'typeswitch'",
2781               "XPST0003");
2782      }
2783    vec.addElement(lexp);
2784    popNesting(save);
2785    Expression[] args = new Expression[vec.size()];
2786    vec.copyInto(args);
2787    return new ApplyExp(makeFunctionExp("gnu.kawa.reflect.TypeSwitch",
2788                    "typeSwitch"),
2789            args);
2790  }
2791
2792  /**
2793   * Try to parse a PrimaryExpr.
2794   * @return an Expression, or null if no PrimaryExpr was seen.
2795   */

2796  Expression parseMaybePrimaryExpr()
2797      throws java.io.IOException JavaDoc, SyntaxException
2798  {
2799    int startLine = curLine;
2800    int startColumn = curColumn;
2801    int token = peekOperand();
2802    Expression exp;
2803    int c1, c2, c3;
2804    Vector JavaDoc vec;
2805    Expression[] args;
2806    switch (token)
2807      {
2808      case '(':
2809        exp = parseParenExpr();
2810        break;
2811
2812      case PRAGMA_START_TOKEN:
2813        Stack JavaDoc extArgs = new Stack JavaDoc();
2814        for (;;)
2815          {
2816            getRawToken();
2817            Expression qname;
2818            if (curToken != QNAME_TOKEN && curToken != NCNAME_TOKEN)
2819              qname = syntaxError("missing pragma name");
2820            else
2821              qname = QuoteExp.getInstance(new String JavaDoc(tokenBuffer, 0, tokenBufferLength));
2822            extArgs.push(qname);
2823            StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
2824            int ch;
2825            int spaces = -1;
2826            do { ch = read(); spaces++; }
2827            while (ch >= 0 && Character.isWhitespace((char) ch));
2828            while (ch != '#' || peek() != ')')
2829              {
2830                if (ch < 0)
2831                  eofError("pragma ended by end-of-file");
2832                if (spaces == 0)
2833                  error("missing space between pragma and extension content");
2834                spaces = 1;
2835                sbuf.append((char) ch);
2836                ch = read();
2837              }
2838            read(); // skip ')'
2839
extArgs.push(QuoteExp.getInstance(sbuf.toString()));
2840            getRawToken();
2841            if (curToken != PRAGMA_START_TOKEN)
2842              break;
2843          }
2844        if (curToken == '{')
2845          {
2846            getRawToken();
2847            if (curToken != '}')
2848              {
2849                char saveReadState = pushNesting('{');
2850                extArgs.push(parseExprSequence('}', false));
2851                popNesting(saveReadState);
2852                if (curToken == EOF_TOKEN)
2853                  eofError("missing '}' - unexpected end-of-file");
2854              }
2855            args = new Expression[extArgs.size()];
2856            extArgs.copyInto(args);
2857            exp = new ApplyExp(new ReferenceExp(XQResolveNames.handleExtensionDecl), args);
2858          }
2859        else
2860          exp = syntaxError("missing '{' after pragma");
2861        break;
2862
2863      case '{':
2864    exp = syntaxError("saw unexpected '{' - assume you meant '('");
2865    parseEnclosedExpr();
2866        break;
2867
2868      case OP_LSS:
2869    int next = read();
2870    if (next == '/')
2871      {
2872        getRawToken();
2873        String JavaDoc msg;
2874        if (curToken == NCNAME_TOKEN || curToken == QNAME_TOKEN
2875        || curToken == NCNAME_COLON_TOKEN)
2876          msg = "saw end tag '</" + new String JavaDoc(tokenBuffer, 0, tokenBufferLength) + ">' not in an element constructor";
2877        else
2878          msg = "saw end tag '</' not in an element constructor";
2879        curLine = startLine;
2880        curColumn = startColumn;
2881        exp = syntaxError(msg);
2882        while (curToken != OP_GRT && curToken != EOF_TOKEN && curToken != EOL_TOKEN)
2883          getRawToken();
2884        return exp;
2885      }
2886    else
2887      {
2888        exp = parseXMLConstructor(next, false);
2889        exp.setFile(getName());
2890        exp.setLine(startLine, startColumn);
2891      }
2892        break;
2893
2894      case STRING_TOKEN:
2895    exp = new QuoteExp(new String JavaDoc(tokenBuffer, 0, tokenBufferLength).intern());
2896        break;
2897
2898      case INTEGER_TOKEN:
2899    exp = new QuoteExp(IntNum.valueOf(tokenBuffer, 0, tokenBufferLength,
2900                                          10, false));
2901        break;
2902
2903      case DECIMAL_TOKEN:
2904      case DOUBLE_TOKEN:
2905        String JavaDoc str = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
2906        try
2907          {
2908            Object JavaDoc val;
2909            if (token == DECIMAL_TOKEN)
2910              val = new java.math.BigDecimal JavaDoc(str);
2911            else
2912              val = new java.lang.Double JavaDoc(str);
2913            exp = new QuoteExp(val);
2914          }
2915        catch (Throwable JavaDoc ex)
2916          {
2917            exp = syntaxError("invalid decimal literal: '"+str+"'");
2918          }
2919        break;
2920      case '$':
2921    Object JavaDoc name = parseVariable();
2922    if (name == null)
2923      return syntaxError("missing Variable");
2924    exp = new ReferenceExp(name);
2925        break;
2926      case FNAME_TOKEN:
2927    name = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
2928    char save = pushNesting('(');
2929    getRawToken();
2930        vec = new Vector JavaDoc(10);
2931    if (curToken != ')')
2932      {
2933        for (;;)
2934          {
2935        Expression arg = parseExpr();
2936        vec.addElement(arg);
2937        if (curToken == ')')
2938          break;
2939        if (curToken != ',')
2940          return syntaxError("missing ')' after function call");
2941        getRawToken();
2942          }
2943      }
2944    args = new Expression[vec.size()];
2945
2946    vec.copyInto(args);
2947    ReferenceExp rexp = new ReferenceExp(name, null);
2948    rexp.setProcedureName(true);
2949    exp = new ApplyExp(rexp, args);
2950
2951    exp.setFile(getName());
2952    exp.setLine(startLine, startColumn);
2953    popNesting(save);
2954        break;
2955
2956      case ELEMENT_TOKEN:
2957      case ATTRIBUTE_TOKEN:
2958      case COMMENT_TOKEN:
2959      case DOCUMENT_TOKEN:
2960      case TEXT_TOKEN:
2961      case PI_TOKEN:
2962        getRawToken(); // Skip 'element'.
2963
vec = new Vector JavaDoc();
2964        Expression func;
2965
2966        if (token == ELEMENT_TOKEN || token == ATTRIBUTE_TOKEN)
2967          {
2968            Expression element;
2969            if (curToken == NCNAME_TOKEN || curToken == QNAME_TOKEN)
2970              element = parseNameTest(token != ELEMENT_TOKEN);
2971            else if (curToken == '{')
2972              element = parseEnclosedExpr();
2973            else
2974              return syntaxError("missing element/attribute name");
2975            vec.addElement(castQName(element));
2976            if (token == ELEMENT_TOKEN)
2977              {
2978                MakeElement mk = new MakeElement();
2979                mk.copyNamespacesMode = copyNamespacesMode;
2980                func = new QuoteExp(mk);
2981              }
2982            else
2983              func = MakeAttribute.makeAttributeExp;
2984            getRawToken();
2985          }
2986        else if (token == DOCUMENT_TOKEN)
2987          func = makeFunctionExp("gnu.kawa.xml.DocumentConstructor",
2988                                 "documentConstructor");
2989        else if (token == COMMENT_TOKEN)
2990          func = makeFunctionExp("gnu.kawa.xml.CommentConstructor",
2991                                 "commentConstructor");
2992        else if (token == PI_TOKEN)
2993          {
2994            Expression target;
2995            if (curToken == NCNAME_TOKEN)
2996              target = new QuoteExp(new String JavaDoc(tokenBuffer, 0,
2997                                               tokenBufferLength).intern());
2998            else if (curToken == '{')
2999              {
3000                target = parseEnclosedExpr();
3001              }
3002            else
3003              {
3004                target = syntaxError("expected NCName or '{' after 'processing-instruction'");
3005                if (curToken != QNAME_TOKEN)
3006                  return target;
3007              }
3008            vec.addElement(target);
3009            func = makeFunctionExp("gnu.kawa.xml.MakeProcInst",
3010                                 "makeProcInst");
3011            getRawToken();
3012          }
3013        else /* token == TEXT_TOKEN */
3014          func = makeFunctionExp("gnu.kawa.xml.MakeText",
3015                                 "makeText");
3016        char saveReadState = pushNesting('{');
3017        peekNonSpace("unexpected end-of-file after '{'");
3018        if (curToken != '{')
3019          return syntaxError("missing '{'");
3020        getRawToken();
3021        if (token == TEXT_TOKEN || token == COMMENT_TOKEN
3022            || token == PI_TOKEN)
3023          vec.addElement(parseExprSequence('}', token == PI_TOKEN));
3024        else if (curToken != '}')
3025          {
3026            vec.addElement(parseExpr());
3027            while (curToken == ',')
3028              {
3029                getRawToken();
3030                vec.addElement(parseExpr());
3031              }
3032          }
3033        popNesting(saveReadState);
3034        if (curToken != '}')
3035          return syntaxError("missing '}'");
3036        args = new Expression[vec.size()];
3037        vec.copyInto(args);
3038        exp = new ApplyExp(func, args);
3039        exp.setFile(getName());
3040        exp.setLine(startLine, startColumn);
3041        if (token == DOCUMENT_TOKEN || token == ELEMENT_TOKEN)
3042          exp = wrapWithBaseUri(exp);
3043        break;
3044
3045      case ORDERED_LBRACE_TOKEN:
3046      case UNORDERED_LBRACE_TOKEN:
3047        getRawToken();
3048        exp = parseExprSequence('}', false);
3049        break;
3050
3051      default:
3052        return null;
3053      }
3054    /*
3055    if (nesting == 0)
3056      {
3057    int ch = skipSpace(false);
3058    if (ch < 0 || ch == '\n' || ch == '\r')
3059      return exp;
3060    unread(ch);
3061      }
3062    */

3063    getRawToken();
3064    return exp;
3065  }
3066
3067  public Expression parseIfExpr()
3068      throws java.io.IOException JavaDoc, SyntaxException
3069  {
3070    char saveReadState1 = pushNesting('i');
3071    getRawToken();
3072    char saveReadState2 = pushNesting('(');
3073    Expression cond = parseExprSequence(')', false);
3074    popNesting(saveReadState2);
3075    if (curToken == EOF_TOKEN)
3076      eofError("missing ')' - unexpected end-of-file");
3077    getRawToken();
3078    if (! match("then"))
3079      syntaxError("missing 'then'");
3080    else
3081      getRawToken();
3082    Expression thenPart = parseExpr();
3083    if (! match("else"))
3084      syntaxError("missing 'else'");
3085    else
3086      getRawToken();
3087    popNesting(saveReadState1);
3088    Expression elsePart = parseExpr();
3089    return new IfExp(booleanValue(cond), thenPart, elsePart);
3090  }
3091
3092  public boolean match(String JavaDoc word)
3093  {
3094    if (curToken != NCNAME_TOKEN)
3095      return false;
3096    int len = word.length();
3097    if (tokenBufferLength != len)
3098      return false;
3099    for (int i = len; --i >= 0; )
3100      {
3101    char cs = word.charAt(i);
3102    char cb = tokenBuffer[i];
3103    if (cs != cb)
3104      return false;
3105      }
3106    return true;
3107  }
3108
3109  /** Parse a Variable. */
3110  public Object JavaDoc parseVariable ()
3111      throws java.io.IOException JavaDoc, SyntaxException
3112  {
3113    if (curToken == '$')
3114      getRawToken();
3115    else
3116      syntaxError("missing '$' before variable name");
3117    String JavaDoc str = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
3118    // Note we cannot do namespace resolution here - see comment in
3119
// parseElementConstructor.
3120
if (curToken == QNAME_TOKEN)
3121      return str;
3122    else if (curToken == NCNAME_TOKEN)
3123      return Namespace.EmptyNamespace.getSymbol(str.intern());
3124    else
3125      return null;
3126  }
3127
3128  public Declaration parseVariableDeclaration ()
3129      throws java.io.IOException JavaDoc, SyntaxException
3130  {
3131    Object JavaDoc name = parseVariable();
3132    if (name == null)
3133      return null;
3134    Declaration decl = new Declaration(name);
3135    decl.setFile(getName());
3136    decl.setLine(getLineNumber() + 1,
3137         getColumnNumber() + 1 - tokenBufferLength);
3138    return decl;
3139  }
3140
3141  public Expression parseFLWRExpression (boolean isFor)
3142      throws java.io.IOException JavaDoc, SyntaxException
3143  {
3144    int flworDeclsSave = flworDeclsFirst;
3145    flworDeclsFirst = flworDeclsCount;
3146    Expression exp = parseFLWRInner(isFor);
3147
3148    if (match ("order"))
3149      {
3150        getRawToken();
3151        if (match ("by"))
3152          getRawToken();
3153        else
3154          error("missing 'by' following 'order'");
3155        Stack JavaDoc specs = new Stack JavaDoc();
3156        for (;;)
3157          {
3158            boolean descending = false;
3159            char emptyOrder = defaultEmptyOrder;
3160
3161            LambdaExp lexp = new LambdaExp(flworDeclsCount-flworDeclsFirst);
3162            for (int i = flworDeclsFirst; i < flworDeclsCount; i++)
3163              lexp.addDeclaration(flworDecls[i].getSymbol());
3164            comp.push(lexp);
3165            lexp.body = parseExprSingle();
3166            comp.pop(lexp);
3167            specs.push(lexp);
3168
3169            if (match("ascending"))
3170              getRawToken();
3171            else if (match("descending"))
3172              {
3173                getRawToken();
3174                descending = true;
3175              }
3176            if (match("empty"))
3177              {
3178                getRawToken();
3179                if (match("greatest"))
3180                  {
3181                    getRawToken();
3182                    emptyOrder = 'G';
3183                  }
3184                else if (match("least"))
3185                  {
3186                    getRawToken();
3187                    emptyOrder = 'L';
3188                  }
3189                else
3190                  error
3191                    ("'empty' sequence order must be 'greatest' or 'least'");
3192              }
3193            specs.push(new QuoteExp((descending ? "D" : "A") + emptyOrder));
3194            Object JavaDoc collation = defaultCollator;
3195            if (match("collation"))
3196              {
3197                Object JavaDoc uri = parseURILiteral();
3198                if (uri instanceof String JavaDoc)
3199                  {
3200                    try
3201                      {
3202                        collation = NamedCollator.make((String JavaDoc) uri);
3203                      }
3204                    catch (Exception JavaDoc name)
3205                      {
3206                        error('e', "unknown collation '"+uri+"'", "XQST0076");
3207                      }
3208                  }
3209                getRawToken();
3210              }
3211            specs.push(new QuoteExp(collation));
3212            if (curToken != ',')
3213              break;
3214            getRawToken();
3215          }
3216        if (! match("return"))
3217          return syntaxError("expected 'return' clause");
3218        getRawToken();
3219
3220        LambdaExp lexp = new LambdaExp(flworDeclsCount-flworDeclsFirst);
3221        //lexp.setFile(getName());
3222
//lexp.setLine(declLine, declColumn);
3223
for (int i = flworDeclsFirst; i < flworDeclsCount; i++)
3224          lexp.addDeclaration(flworDecls[i].getSymbol());
3225        comp.push(lexp);
3226    lexp.body = parseExprSingle();
3227        comp.pop(lexp);
3228        int nspecs = specs.size();
3229        Expression[] args = new Expression[2 + nspecs];
3230        args[0] = exp;
3231        args[1] = lexp;
3232        for (int i = 0; i < nspecs; i++)
3233          args[2+i] = (Expression) specs.elementAt(i);
3234    return new ApplyExp(makeFunctionExp("gnu.xquery.util.OrderedMap",
3235                        "orderedMap"),
3236                args);
3237
3238      }
3239    flworDeclsCount = flworDeclsFirst;
3240    flworDeclsFirst = flworDeclsSave;
3241    return exp;
3242  }
3243
3244  /** Parse a let- or a for-expression.
3245   * Assume the 'let'/'for'-token has been seen, and we've read '$'.
3246   *
3247   * If we see the 'order' keyword of an 'order by' clause then we stop
3248   * parsing, and return a result as if we instead saw a
3249   * 'return make-tuple($x, ...)'. The 'order by' clause will get
3250   * parsed by the outer-most 'for' or 'let'.
3251   */

3252  public Expression parseFLWRInner (boolean isFor)
3253      throws java.io.IOException JavaDoc, SyntaxException
3254  {
3255    char saveNesting = pushNesting(isFor ? 'f' : 'l');
3256    curToken = '$';
3257    Declaration decl = parseVariableDeclaration();
3258    if (decl == null)
3259      return syntaxError("missing Variable - saw "+tokenString());
3260    if (flworDecls == null)
3261      flworDecls = new Declaration[8];
3262    else if (flworDeclsCount >= flworDecls.length)
3263      {
3264        Declaration[] tmp = new Declaration[2 * flworDeclsCount];
3265        System.arraycopy(flworDecls, 0, tmp, 0, flworDeclsCount);
3266        flworDecls = tmp;
3267      }
3268    flworDecls[flworDeclsCount++] = decl;
3269    getRawToken();
3270
3271    Expression type = parseOptionalTypeDeclaration();
3272    ScopeExp sc;
3273    Expression[] inits = new Expression[1];
3274    Declaration posDecl = null;
3275    if (isFor)
3276      {
3277    boolean sawAt = match("at");
3278    LambdaExp lexp = new LambdaExp(sawAt ? 2 : 1);
3279    if (sawAt)
3280      {
3281        getRawToken();
3282        if (curToken == '$')
3283          {
3284        posDecl = parseVariableDeclaration();
3285        getRawToken();
3286          }
3287        if (posDecl == null)
3288          syntaxError("missing Variable after 'at'");
3289      }
3290    sc = lexp;
3291    if (match("in"))
3292      getRawToken();
3293    else
3294      {
3295        if (curToken == COLON_EQUAL_TOKEN)
3296          getRawToken();
3297        syntaxError("missing 'in' in 'for' clause");
3298      }
3299      }
3300    else
3301      {
3302    if (curToken == COLON_EQUAL_TOKEN)
3303      getRawToken();
3304    else
3305      {
3306        if (match("in"))
3307          getRawToken();
3308        syntaxError("missing ':=' in 'let' clause");
3309      }
3310    LetExp let = new LetExp(inits);
3311    sc = let;
3312      }
3313    inits[0] = parseExprSingle();
3314    if (type != null && ! isFor) // FIXME - for now
3315
inits[0] = Convert.makeCoercion(inits[0], type);
3316    popNesting(saveNesting);
3317    comp.push(sc);
3318    sc.addDeclaration(decl);
3319    decl.setTypeExp(type);
3320    if (isFor)
3321      {
3322    decl.noteValue (null); // Does not have a known value.
3323
decl.setFlag(Declaration.IS_SINGLE_VALUE);
3324      }
3325    if (posDecl != null)
3326      {
3327    sc.addDeclaration(posDecl);
3328    posDecl.setType(LangPrimType.intType);
3329    posDecl.noteValue(null);
3330    posDecl.setFlag(Declaration.IS_SINGLE_VALUE);
3331      }
3332    Expression body;
3333    if (curToken == ',')
3334      {
3335    getRawToken();
3336    if (curToken != '$')
3337      return syntaxError("missing $NAME after ','");
3338    body = parseFLWRInner(isFor);
3339      }
3340    else if (match("for"))
3341      {
3342    getRawToken();
3343    if (curToken != '$')
3344      return syntaxError("missing $NAME after 'for'");
3345    body = parseFLWRInner(true);
3346      }
3347    else if (match("let"))
3348      {
3349    getRawToken();
3350    if (curToken != '$')
3351      return syntaxError("missing $NAME after 'let'");
3352    body = parseFLWRInner(false);
3353      }
3354    else
3355      {
3356    Expression cond;
3357    char save = pushNesting('w');
3358    if (curToken == OP_WHERE)
3359      {
3360        getRawToken();
3361        cond = parseExprSingle();
3362      }
3363    else if (match("where"))
3364      {
3365        cond = parseExprSingle();
3366      }
3367    else
3368      cond = null;
3369    popNesting(save);
3370    boolean sawStable = match("stable");
3371    if (sawStable)
3372      getRawToken();
3373    boolean sawReturn = match("return");
3374    boolean sawOrder = match("order");
3375    if (! sawReturn && ! sawOrder && ! match("let") && ! match("for"))
3376      return syntaxError("missing 'return' clause");
3377        if (! sawOrder)
3378          peekNonSpace("unexpected eof-of-file after 'return'");
3379    int bodyLine = getLineNumber() + 1;
3380    int bodyColumn = getColumnNumber() + 1;
3381    if (sawReturn)
3382      getRawToken();
3383        if (sawOrder)
3384          {
3385            int ndecls = flworDeclsCount - flworDeclsFirst;
3386            Expression[] args = new Expression[ndecls];
3387            for (int i = 0; i < ndecls; i++)
3388              args[i] = new ReferenceExp(flworDecls[flworDeclsFirst+i]);
3389            body = new ApplyExp(new PrimProcedure("gnu.xquery.util.OrderedMap",
3390                                                  "makeTuple$V", 1),
3391                                args);
3392          }
3393        else
3394          body = parseExprSingle();
3395    if (cond != null)
3396          body = new IfExp(booleanValue(cond), body, QuoteExp.voidExp);
3397    body.setFile(getName());
3398    body.setLine(bodyLine, bodyColumn);
3399      }
3400    comp.pop(sc);
3401    if (isFor)
3402      {
3403    LambdaExp lexp = (LambdaExp) sc;
3404    lexp.body = body;
3405    Expression[] args = { sc, inits[0]}; // SIC
3406
return new ApplyExp(makeFunctionExp("gnu.kawa.functions.ValuesMap",
3407                        lexp.min_args == 1 ? "valuesMap"
3408                        : "valuesMapWithPos"),
3409                args);
3410      }
3411    else
3412      ((LetExp) sc).setBody(body);
3413    return sc;
3414
3415  }
3416
3417  /** Parse a some- or an every-expression.
3418   * Assume the 'some'/'every'-token has been seen, and we've read '$'. */

3419  public Expression parseQuantifiedExpr (boolean isEvery)
3420      throws java.io.IOException JavaDoc, SyntaxException
3421  {
3422    char saveNesting = pushNesting(isEvery ? 'e' : 's');
3423    curToken = '$';
3424    Declaration decl = parseVariableDeclaration();
3425    if (decl == null)
3426      return syntaxError("missing Variable token:"+curToken);
3427    getRawToken();
3428    
3429    LambdaExp lexp = new LambdaExp(1);
3430    lexp.addDeclaration(decl);
3431    decl.noteValue (null); // Does not have a known value.
3432
decl.setFlag(Declaration.IS_SINGLE_VALUE);
3433    decl.setTypeExp(parseOptionalTypeDeclaration());
3434
3435    if (match("in"))
3436      getRawToken();
3437    else
3438      {
3439    if (curToken == COLON_EQUAL_TOKEN)
3440      getRawToken();
3441    syntaxError("missing 'in' in QuantifiedExpr");
3442      }
3443    Expression[] inits = { parseExprSingle() };
3444    popNesting(saveNesting);
3445    comp.push(lexp);
3446    Expression body;
3447    if (curToken == ',')
3448      {
3449    getRawToken();
3450    if (curToken != '$')
3451      return syntaxError("missing $NAME after ','");
3452    body = parseQuantifiedExpr(isEvery);
3453      }
3454    else
3455      {
3456    boolean sawSatisfies = match("satisfies");
3457    if (! sawSatisfies && ! match("every") && ! match("some"))
3458      return syntaxError("missing 'satisfies' clause");
3459    peekNonSpace("unexpected eof-of-file after 'satisfies'");
3460    int bodyLine = getLineNumber() + 1;
3461    int bodyColumn = getColumnNumber() + 1;
3462    if (sawSatisfies)
3463      getRawToken();
3464    body = parseExprSingle();
3465    body.setFile(getName());
3466    body.setLine(bodyLine, bodyColumn);
3467      }
3468    comp.pop(lexp);
3469    lexp.body = body;
3470    Expression[] args = { lexp, inits[0]}; // SIC
3471
return new ApplyExp(makeFunctionExp("gnu.xquery.util.ValuesEvery",
3472                    isEvery ? "every" : "some"),
3473            args);
3474  }
3475
3476  public Expression parseFunctionDefinition(int declLine, int declColumn)
3477      throws java.io.IOException JavaDoc, SyntaxException
3478  {
3479    if (curToken != QNAME_TOKEN && curToken != NCNAME_TOKEN)
3480      return syntaxError("missing function name");
3481    String JavaDoc name = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
3482    Symbol sym = namespaceResolve(name, true);
3483    String JavaDoc uri = sym.getNamespaceURI();
3484    if (uri == NamespaceBinding.XML_NAMESPACE
3485        || uri == XQuery.SCHEMA_NAMESPACE
3486        || uri == XQuery.SCHEMA_INSTANCE_NAMESPACE
3487        || uri == XQuery.XQUERY_FUNCTION_NAMESPACE)
3488      {
3489        error('e',
3490              "cannot declare function in standard namespace '"+uri+'\'',
3491              "XQST0045");
3492      }
3493    else if (uri == "")
3494      {
3495        error(comp.isPedantic() ? 'e' : 'w',
3496              "cannot declare function in empty namespace",
3497              "XQST0060");
3498      }
3499    else if (libraryModuleNamespace != null && uri != libraryModuleNamespace
3500             && (! XQuery.LOCAL_NAMESPACE.equals(uri) || comp.isPedantic()))
3501      {
3502        error('e', "function not in namespace of library module", "XQST0048");
3503      }
3504    getRawToken();
3505    if (curToken != '(')
3506      return syntaxError("missing parameter list:"+curToken);
3507    getRawToken();
3508    LambdaExp lexp = new LambdaExp();
3509    lexp.setFile(getName());
3510    lexp.setLine(declLine, declColumn);
3511    lexp.setName(name);
3512    Declaration decl = comp.currentScope().addDeclaration(sym);
3513    if (comp.isStatic())
3514      decl.setFlag(Declaration.STATIC_SPECIFIED);
3515    lexp.setFlag(LambdaExp.OVERLOADABLE_FIELD);
3516    decl.setCanRead(true);
3517    decl.setProcedureDecl(true);
3518    decl.setFile(getName());
3519    decl.setLine(declLine, declColumn);
3520    comp.push(lexp);
3521    if (curToken != ')')
3522      {
3523      paramLoop:
3524    for (;;)
3525      {
3526        Declaration param = parseVariableDeclaration();
3527        if (param == null)
3528          error("missing parameter name");
3529        else
3530          {
3531        lexp.addDeclaration(param);
3532        getRawToken();
3533        lexp.min_args++;
3534        lexp.max_args++;
3535        param.setTypeExp(parseOptionalTypeDeclaration());
3536          }
3537        if (curToken == ')')
3538          break;
3539        if (curToken != ',')
3540              {
3541                Expression err = syntaxError("missing ',' in parameter list");
3542                for (;;)
3543                  {
3544                    getRawToken();
3545                    if (curToken < 0 || curToken == ';' || curToken == ';')
3546                      return err;
3547                    if (curToken == ')')
3548                      break paramLoop;
3549                    if (curToken == ',')
3550                      break;
3551                  }
3552              }
3553            else
3554              getRawToken();
3555      }
3556      }
3557    getRawToken();
3558    Expression retType = parseOptionalTypeDeclaration ();
3559    lexp.body = parseEnclosedExpr();
3560    comp.pop(lexp);
3561    if (retType != null)
3562      Convert.setCoercedReturnValue(lexp, retType, interpreter);
3563    SetExp sexp = new SetExp(decl, lexp);
3564    sexp.setDefining (true);
3565    decl.noteValue(lexp);
3566    return sexp;
3567  }
3568
3569  public Object JavaDoc readObject ()
3570      throws java.io.IOException JavaDoc, SyntaxException
3571  {
3572    return parse(null);
3573  }
3574
3575  Compilation comp;
3576
3577  String JavaDoc defaultElementNamespace = "";
3578
3579  /** Chain of namespace bindings from namespace declaration attributes
3580   * in outer direct element constructors. This is only non-empty during
3581   * resolve time, but it is declared here so namespaceResolve can use it. */

3582  NamespaceBinding constructorNamespaces = NamespaceBinding.predefinedXML;
3583
3584  /** Chain of namespace bindings from declarations in prolog,
3585   * followed by the builtinNamespaces. */

3586  NamespaceBinding prologNamespaces;
3587
3588  static NamespaceBinding builtinNamespaces;
3589  static {
3590    NamespaceBinding ns = NamespaceBinding.predefinedXML;
3591    ns = new NamespaceBinding("xml", NamespaceBinding.XML_NAMESPACE, ns);
3592    ns = new NamespaceBinding("xs", XQuery.SCHEMA_NAMESPACE, ns);
3593    ns = new NamespaceBinding("xsi", XQuery.SCHEMA_INSTANCE_NAMESPACE, ns);
3594    ns = new NamespaceBinding("fn", XQuery.XQUERY_FUNCTION_NAMESPACE, ns);
3595    ns = new NamespaceBinding("html", XQuery.XHTML_NAMESPACE, ns);
3596    ns = new NamespaceBinding("kawa", XQuery.KAWA_FUNCTION_NAMESPACE, ns);
3597    ns = new NamespaceBinding("qexo", XQuery.QEXO_FUNCTION_NAMESPACE, ns);
3598    ns = new NamespaceBinding("local", XQuery.LOCAL_NAMESPACE, ns);
3599    builtinNamespaces = ns;
3600  }
3601
3602  protected Symbol namespaceResolve (String JavaDoc name, boolean function)
3603  {
3604    int colon = name.indexOf(':');
3605    String JavaDoc prefix = colon >= 0 ? name.substring(0, colon).intern()
3606      : function ? XQuery.DEFAULT_FUNCTION_PREFIX
3607      : XQuery.DEFAULT_ELEMENT_PREFIX;
3608    String JavaDoc uri = QNameUtils.lookupPrefix(prefix, constructorNamespaces,
3609                                         prologNamespaces);
3610
3611    if (uri == null)
3612      {
3613    if (colon < 0)
3614      uri = "";
3615    else if (! comp.isPedantic())
3616      {
3617        try
3618          {
3619        Class JavaDoc cl = Class.forName(prefix);
3620        uri = "class:" + prefix;
3621          }
3622        catch (Exception JavaDoc ex)
3623          {
3624                uri = null;
3625              }
3626      }
3627        if (uri == null)
3628          {
3629            error('e',
3630                  "unknown namespace prefix '" + prefix + "'",
3631                  "XPST0081");
3632            uri = "(unknown namespace)";
3633          }
3634      }
3635    String JavaDoc local = colon < 0 ? name : name.substring(colon+1);
3636    return Symbol.make((String JavaDoc) uri, local, prefix);
3637  }
3638
3639  void parseSeparator ()
3640    throws java.io.IOException JavaDoc, SyntaxException
3641  {
3642    int startLine = port.getLineNumber() + 1;
3643    int startColumn = port.getColumnNumber() + 1;
3644    int next = skipSpace(nesting != 0);
3645    if (next == ';')
3646      return;
3647    if (warnOldVersion && next != '\n')
3648      {
3649    curLine = startLine;
3650    curColumn = startColumn;
3651    error('w', "missing ';' after declaration");
3652      }
3653    if (next >= 0)
3654      unread(next);
3655  }
3656
3657  public static final QuoteExp getExternalFunction =
3658    QuoteExp.getInstance(new PrimProcedure("gnu.xquery.lang.XQuery",
3659                                           "getExternal", 2));
3660
3661  /** Parse an expression.
3662   * Return null on EOF. */

3663  public Expression parse(Compilation comp)
3664      throws java.io.IOException JavaDoc, SyntaxException
3665  {
3666    this.comp = comp;
3667    int ch = skipSpace();
3668    if (ch < 0)
3669      return null;
3670    parseCount++;
3671    unread(ch);
3672    int startLine = getLineNumber() + 1;
3673    int startColumn = getColumnNumber() + 1;
3674
3675    // Handle Unix #!PROGRAM convention. */
3676
if (ch == '#' && startLine == 1 && startColumn == 1)
3677      {
3678    read();
3679    if ((ch = read()) != '!' || (ch = read()) != '/')
3680      error("'#' is only allowed in initial '#!/PROGRAM'");
3681    while (ch != '\r' && ch != '\n' && ch >= 0)
3682      ch = read();
3683      }
3684
3685    if (getRawToken() == EOF_TOKEN)
3686      return null;
3687    peekOperand();
3688
3689    if (curToken == NCNAME_TOKEN
3690    && "namespace".equals((String JavaDoc) curValue))
3691      {
3692    if (warnOldVersion)
3693      error('w', "use 'declare namespace' instead of 'namespace'");
3694    curToken = DECLARE_NAMESPACE_TOKEN;
3695      }
3696
3697    int declLine, declColumn, next;
3698    Declaration decl;
3699    String JavaDoc prefix, uri;
3700    Object JavaDoc val;
3701    Expression exp;
3702    switch (curToken)
3703      {
3704      case DEFINE_QNAME_TOKEN:
3705    declLine = getLineNumber() + 1;
3706    declColumn = getColumnNumber() + 1;
3707    next = peekNonSpace("unexpected end-of-file after 'define QName'");
3708    if (next == '(')
3709      {
3710        syntaxError("'missing 'function' after 'define'");
3711        curToken = NCNAME_TOKEN;
3712        return parseFunctionDefinition(declLine, declColumn);
3713      }
3714    else
3715      return syntaxError("missing keyword after 'define'");
3716
3717      case DECLARE_FUNCTION_TOKEN:
3718    declLine = getLineNumber() + 1;
3719    declColumn = getColumnNumber() + 1;
3720    getRawToken();
3721    peekNonSpace("unexpected end-of-file after 'define function'");
3722    char save = pushNesting('d');
3723    exp = parseFunctionDefinition(declLine, declColumn);
3724    popNesting(save);
3725    parseSeparator();
3726    exp.setFile(getName());
3727    exp.setLine(startLine, startColumn);
3728        seenDeclaration = true;
3729    return exp;
3730
3731      case DECLARE_VARIABLE_TOKEN:
3732    getRawToken();
3733    decl = parseVariableDeclaration();
3734    if (decl == null)
3735      return syntaxError("missing Variable");
3736        Object JavaDoc name = decl.getSymbol();
3737        if (name instanceof String JavaDoc)
3738          decl.setSymbol(namespaceResolve((String JavaDoc) name, false));
3739        if (libraryModuleNamespace != null)
3740          {
3741            uri = ((Symbol) decl.getSymbol()).getNamespaceURI();
3742            if (uri != libraryModuleNamespace
3743                && (! XQuery.LOCAL_NAMESPACE.equals(uri) || comp.isPedantic()))
3744              error('e', "variable not in namespace of library module"
3745                    , "XQST0048");
3746          }
3747    comp.currentScope().addDeclaration(decl);
3748    getRawToken();
3749    Expression type = parseOptionalTypeDeclaration();
3750    decl.setCanRead(true);
3751    //decl.setFlag(Declaration.NONSTATIC_SPECIFIED);
3752
decl.setFlag(Declaration.IS_CONSTANT);
3753    Expression init = null;
3754    boolean sawEq = false;
3755    if (curToken == OP_EQU || curToken == COLON_EQUAL_TOKEN)
3756      {
3757        if (curToken==OP_EQU)
3758          error("declare variable contains '=' instead of ':='");
3759        getRawToken();
3760        sawEq = true;
3761      }
3762    if (curToken == '{')
3763      {
3764        warnOldVersion("obsolete '{' in variable declaration");
3765        init = parseEnclosedExpr();
3766        parseSeparator();
3767      }
3768    else if (match("external"))
3769      {
3770            Expression[] args =
3771              {
3772                castQName(new QuoteExp(decl.getSymbol())),
3773                type==null ? QuoteExp.nullExp : type
3774              };
3775            init = new ApplyExp(getExternalFunction, args);
3776            init.setFile(getName());
3777            init.setLine(curLine, curColumn);
3778            getRawToken();
3779      }
3780    else
3781      {
3782        init = parseExpr();
3783        Expression err = null;
3784        if (! sawEq || init == null)
3785          err = syntaxError("expected ':= init' or 'external'");
3786        if (init == null)
3787          init = err;
3788      }
3789        if (type != null)
3790          init = Convert.makeCoercion(init, type);
3791        decl.noteValue(init);
3792    exp = SetExp.makeDefinition(decl, init);
3793    exp.setFile(getName());
3794    exp.setLine(startLine, startColumn);
3795        seenDeclaration = true;
3796    return exp;
3797
3798      case DECLARE_NAMESPACE_TOKEN:
3799      case MODULE_NAMESPACE_TOKEN:
3800    int command = curToken;
3801        if (command == MODULE_NAMESPACE_TOKEN
3802            && libraryModuleNamespace != null )
3803          error('e', "duplicate module declaration");
3804        else if (seenDeclaration && ! interactive)
3805          error('e', "namespace declared after function/variable/option");
3806    next = skipSpace(nesting != 0);
3807    if (next >= 0)
3808      {
3809        unread();
3810        if (XName.isNameStart((char) next))
3811          {
3812        getRawToken();
3813        if (curToken != NCNAME_TOKEN)
3814          return syntaxError("missing namespace prefix");
3815        prefix = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
3816        getRawToken();
3817        if (curToken != OP_EQU)
3818          return syntaxError("missing '=' in namespace declaration");
3819        getRawToken();
3820        if (curToken != STRING_TOKEN)
3821          return syntaxError("missing uri in namespace declaration");
3822        uri = new String JavaDoc(tokenBuffer, 0, tokenBufferLength).intern();
3823                prefix = prefix.intern();
3824                for (NamespaceBinding ns = prologNamespaces;
3825                     ns != builtinNamespaces;
3826                     ns = ns.getNext())
3827                  {
3828                    if (ns.getPrefix() == prefix)
3829                      {
3830                        error('e',
3831                              "duplicate declarations for the same namespace prefix '"
3832                              +prefix+"'",
3833                              "XQST0033");
3834                        break;
3835                      }
3836                  }
3837        pushNamespace(prefix, uri);
3838                checkAllowedNamespaceDeclaration(prefix, uri);
3839        parseSeparator();
3840        if (command == MODULE_NAMESPACE_TOKEN)
3841                  {
3842                    ModuleExp module = comp.getModule();
3843                    String JavaDoc className = Compilation.mangleURI(uri)
3844                      + '.' + XQuery.makeClassName(module.getFileName());
3845                    module.setName(className);
3846                    comp.mainClass = new ClassType(className);
3847                    module.setType(comp.mainClass);
3848                    ModuleManager manager = ModuleManager.getInstance();
3849                    ModuleInfo info = manager.find(comp);
3850                    info.setNamespaceUri(uri);
3851                    module.setType(comp.mainClass);
3852                    if (uri.length() == 0)
3853                      return syntaxError("zero-length module namespace", "XQST0088");
3854                    libraryModuleNamespace = uri;
3855                  }
3856                return QuoteExp.voidExp;
3857          }
3858      }
3859
3860      case IMPORT_SCHEMA_TOKEN:
3861        fatal("'import schema' not implemented", "XQST0009");
3862
3863      case IMPORT_MODULE_TOKEN:
3864    getRawToken();
3865    prefix = null;
3866    if (match("namespace"))
3867      {
3868        getRawToken();
3869        if (curToken != NCNAME_TOKEN)
3870          return syntaxError("missing namespace prefix");
3871        prefix = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
3872        getRawToken();
3873        if (curToken != OP_EQU)
3874          return syntaxError("missing '=' in namespace declaration");
3875        getRawToken();
3876      }
3877    if (curToken != STRING_TOKEN)
3878      return syntaxError("missing uri in namespace declaration");
3879        if (tokenBufferLength == 0)
3880          return syntaxError("zero-length target namespace", "XQST0088");
3881    uri = new String JavaDoc(tokenBuffer, 0, tokenBufferLength).intern();
3882    if (prefix != null)
3883          {
3884            checkAllowedNamespaceDeclaration(prefix, uri);
3885            pushNamespace(prefix.intern(), uri);
3886          }
3887    getRawToken();
3888        // Make sure we have a ModuleInfo before we call importDefinitions.
3889
ModuleManager.getInstance().find(comp);
3890
3891        String JavaDoc at;
3892    ModuleExp module = comp.getModule();
3893    Vector JavaDoc forms = new Vector JavaDoc();
3894        String JavaDoc packageName = Compilation.mangleURI(uri);
3895        comp.setLine(port.getName(), startLine, startColumn);
3896    if (match("at"))
3897      {
3898            for (;;)
3899              {
3900                getRawToken();
3901                if (curToken != STRING_TOKEN)
3902                  return syntaxError("missing module location");
3903                at = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
3904                String JavaDoc className = Compilation.mangleURI(uri)
3905                  + '.' + XQuery.makeClassName(at);
3906
3907                ModuleInfo info = require.lookupModuleFromSourcePath(at, module);
3908                if (info == null)
3909                  comp.error('e', "malformed URL: "+at);
3910                require.importDefinitions(className, info,
3911                                          uri, forms, module, comp);
3912                next = skipSpace(nesting != 0);
3913                if (next != ',')
3914                  {
3915                    unread(next);
3916                    break;
3917                  }
3918              }
3919        parseSeparator();
3920      }
3921    else
3922          {
3923            ModuleManager manager = ModuleManager.getInstance();
3924            int n = 0;
3925            try
3926              {
3927                manager.loadPackageInfo(packageName);
3928              }
3929            catch (ClassNotFoundException JavaDoc ex)
3930              {
3931                // Do nothing. If there is no such module,
3932
// that will be reported below.
3933
}
3934            catch (Throwable JavaDoc ex)
3935              {
3936                error('e', "error loading map for "+uri+" - "+ex);
3937              }
3938            for (ModuleInfo info = manager.firstModule(); info != null;
3939                 info = info.nextModule())
3940              {
3941                if (! uri.equals(info.getNamespaceUri()))
3942                  continue;
3943                n++;
3944                require.importDefinitions(info.className, info, uri, forms, module, comp);
3945              }
3946            if (n == 0)
3947              error('e', "no module found for "+uri);
3948            at = null;
3949            if (curToken != ';')
3950              parseSeparator();
3951          }
3952        if (comp.pendingImports != null && comp.pendingImports.size() > 0)
3953          {
3954            error('e', "module import forms a cycle", "XQST0073");
3955          }
3956    Expression[] inits = new Expression[forms.size()];
3957    forms.toArray(inits);
3958    return BeginExp.canonicalize(inits);
3959
3960      case DEFAULT_COLLATION_TOKEN:
3961    if (defaultCollator != null && ! interactive)
3962          error('e', "duplicate default collation declaration", "XQST0038");
3963        val = parseURILiteral();
3964        if (val instanceof Expression) // an ErrorExp
3965
return (Expression) val;
3966    String JavaDoc collation = (String JavaDoc) val;
3967    try
3968      {
3969            if (! InPort.uriSchemeSpecified(collation))
3970              {
3971                String JavaDoc base = getStaticBaseUri();
3972                if (base == null)
3973                  base = CallContext.getInstance().getBaseUri();
3974                collation = URI_utils.resolve(collation, base).toString();
3975              }
3976        defaultCollator = NamedCollator.make(collation);
3977      }
3978    catch (Exception JavaDoc ex)
3979      {
3980        defaultCollator = NamedCollator.codepointCollation;
3981        error('e', "unknown collation '"+collation+"'", "XQST0038");
3982      }
3983    parseSeparator();
3984    return QuoteExp.voidExp;
3985
3986      case DEFAULT_ELEMENT_TOKEN:
3987      case DEFAULT_FUNCTION_TOKEN:
3988    boolean forFunctions = curToken == DEFAULT_FUNCTION_TOKEN;
3989        prefix = forFunctions ? XQuery.DEFAULT_FUNCTION_PREFIX
3990          : XQuery.DEFAULT_ELEMENT_PREFIX;
3991        if (prologNamespaces.resolve(prefix, builtinNamespaces) != null)
3992          error('e',
3993                "duplicate default namespace declaration",
3994                "XQST0066");
3995    getRawToken();
3996    if (match("namespace"))
3997      getRawToken();
3998    else
3999      {
4000        String JavaDoc msg = "expected 'namespace' keyword";
4001        if (curToken != STRING_TOKEN && curToken != OP_EQU)
4002          return declError(msg);
4003        else
4004          warnOldVersion(msg);
4005      }
4006    if (curToken == OP_EQU || curToken == COLON_EQUAL_TOKEN)
4007      {
4008        warnOldVersion("extra '=' in default namespace declaration");
4009        getRawToken();
4010      }
4011    if (curToken != STRING_TOKEN)
4012      return declError("missing namespace uri");
4013    uri = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
4014    if (forFunctions)
4015      {
4016        functionNamespacePath = new Namespace[1];
4017        functionNamespacePath[0] = Namespace.getInstance(uri);
4018      }
4019    else
4020      {
4021        defaultElementNamespace = uri;
4022      }
4023    pushNamespace(prefix, uri);
4024        checkAllowedNamespaceDeclaration(prefix, uri);
4025    parseSeparator();
4026    return QuoteExp.voidExp;
4027
4028      case DECLARE_BOUNDARY_SPACE_TOKEN:
4029    getRawToken();
4030    if (curToken == OP_EQU)
4031      {
4032        warnOldVersion("obsolate '=' in boundary-space declaration");
4033        getRawToken();
4034      }
4035        if (boundarySpaceDeclarationSeen && ! interactive)
4036          syntaxError("duplicate 'declare boundary-space' seen", "XQST0068");
4037        boundarySpaceDeclarationSeen = true;
4038    if (match("preserve"))
4039      boundarySpacePreserve = true;
4040    else if (match("strip"))
4041      boundarySpacePreserve = false;
4042    else if (match("skip"))
4043          {
4044        warnOldVersion("update: declare boundary-space skip -> strip");
4045            boundarySpacePreserve = false;
4046          }
4047    else
4048      return syntaxError("boundary-space declaration must be preserve or strip");
4049    parseSeparator();
4050    return QuoteExp.voidExp;
4051
4052      case DECLARE_CONSTRUCTION_TOKEN:
4053    getRawToken();
4054        if (constructionModeDeclarationSeen && ! interactive)
4055          syntaxError("duplicate 'declare construction' seen", "XQST0067");
4056        constructionModeDeclarationSeen = true;
4057    if (match("strip"))
4058          constructionModeStrip = true;
4059    else if (match("preserve"))
4060          constructionModeStrip = false;
4061    else
4062      return syntaxError("construction declaration must be strip or preserve");
4063    parseSeparator();
4064    return QuoteExp.voidExp;
4065
4066      case DECLARE_COPY_NAMESPACES_TOKEN:
4067    getRawToken();
4068        if (copyNamespacesDeclarationSeen && ! interactive)
4069          syntaxError("duplicate 'declare copy-namespaces' seen", "XQST0055");
4070        copyNamespacesDeclarationSeen = true;
4071    if (match("preserve"))
4072          copyNamespacesMode |= XMLFilter.COPY_NAMESPACES_PRESERVE;
4073    else if (match("no-preserve"))
4074          copyNamespacesMode &= ~XMLFilter.COPY_NAMESPACES_PRESERVE;
4075    else
4076      return syntaxError("expected 'preserve' or 'no-preserve' after 'declare copy-namespaces'");
4077        getRawToken();
4078        if (curToken != ',')
4079          return syntaxError("missing ',' in copy-namespaces declaration");
4080        getRawToken();
4081    if (match("inherit"))
4082          copyNamespacesMode |= XMLFilter.COPY_NAMESPACES_INHERIT;
4083    else if (match("no-inherit"))
4084          copyNamespacesMode &= ~XMLFilter.COPY_NAMESPACES_INHERIT;
4085    else
4086      return syntaxError("expected 'inherit' or 'no-inherit' in copy-namespaces declaration");
4087    parseSeparator();
4088    return QuoteExp.voidExp;
4089
4090      case DEFAULT_ORDER_TOKEN:
4091        getRawToken();
4092        boolean sawEmpty = match("empty");
4093        if (emptyOrderDeclarationSeen && ! interactive)
4094          syntaxError("duplicate 'declare default empty order' seen", "XQST0069");
4095        emptyOrderDeclarationSeen = true;
4096        if (sawEmpty)
4097          getRawToken();
4098        else
4099          syntaxError("expected 'empty greatest' or 'empty least'");
4100        if (match("greatest"))
4101          defaultEmptyOrder = 'G';
4102        else if (match("least"))
4103          defaultEmptyOrder = 'L';
4104        else
4105          return syntaxError("expected 'empty greatest' or 'empty least'");
4106        parseSeparator();
4107    return QuoteExp.voidExp;
4108
4109      case DECLARE_OPTION_TOKEN:
4110    getRawToken();
4111        if (curToken != QNAME_TOKEN)
4112          syntaxError("expected QName after 'declare option'");
4113        else
4114          {
4115            String JavaDoc str = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
4116            getRawToken();
4117            if (curToken != STRING_TOKEN)
4118              syntaxError("expected string literal after 'declare option <QName>'");
4119            else
4120              handleOption(namespaceResolve(str, false),
4121                           new String JavaDoc(tokenBuffer, 0, tokenBufferLength));
4122          }
4123        parseSeparator();
4124        seenDeclaration = true;
4125    return QuoteExp.voidExp;
4126
4127      case DECLARE_ORDERING_TOKEN:
4128        if (orderingModeSeen && ! interactive)
4129          syntaxError("duplicate 'declare ordering' seen", "XQST0065");
4130        orderingModeSeen = true;
4131    getRawToken();
4132    if (match("ordered"))
4133          orderingModeUnordered = false;
4134    else if (match("unordered"))
4135          orderingModeUnordered = true;
4136    else
4137      return syntaxError("ordering declaration must be ordered or unordered");
4138    parseSeparator();
4139    return QuoteExp.voidExp;
4140
4141      case XQUERY_VERSION_TOKEN:
4142        if (parseCount != 1)
4143          error('e', "'xquery version' does not start module");
4144        else if (commentCount > 0)
4145          error('w', "comments should not precede 'xquery version'");
4146        getRawToken();
4147        if (curToken == STRING_TOKEN)
4148          {
4149            String JavaDoc version = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
4150            if (! version.equals("1.0"))
4151              error('e', "unrecognized xquery version "+version, "XQST0031");
4152            getRawToken();
4153          }
4154        else
4155          return syntaxError("missing version string after 'xquery version'");
4156        if (match("encoding"))
4157          {
4158            getRawToken();
4159            if (curToken != STRING_TOKEN)
4160              return syntaxError("invalid encoding specification");
4161            else
4162              {
4163                String JavaDoc encoding = new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
4164                int i = tokenBufferLength;
4165                boolean bad = i == 0;
4166                while (--i >= 0 && ! bad)
4167                  {
4168                    ch = tokenBuffer[i];
4169                    if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
4170                      continue;
4171                    if (i == 0
4172                        || ! ((ch >= '0' && ch <= '9')
4173                              || ch == '.' || ch == '_' || ch == '-'))
4174                      bad = true;
4175                  }
4176                if (bad)
4177                  error('e', "invalid encoding name syntax", "XQST0087");
4178                // ignore encoding specification.
4179
getRawToken();
4180              }
4181          }
4182        if (curToken != ';')
4183          syntaxError("missing ';'");
4184        return QuoteExp.voidExp;
4185
4186      case DECLARE_BASE_URI_TOKEN:
4187        if (baseURIDeclarationSeen && ! interactive)
4188          syntaxError("duplicate 'declare base-uri' seen", "XQST0032");
4189        baseURIDeclarationSeen = true;
4190        val = parseURILiteral();
4191        if (val instanceof Expression) // an ErrorExp
4192
return (Expression) val;
4193    parseSeparator();
4194        baseURI = (String JavaDoc) val;
4195    return QuoteExp.voidExp;
4196      }
4197    exp = parseExprSequence(EOF_TOKEN, true);
4198    if (curToken == EOL_TOKEN)
4199      unread('\n');
4200    exp.setFile(getName());
4201    exp.setLine(startLine, startColumn);
4202    return exp;
4203  }
4204
4205  public void handleOption (Symbol name, String JavaDoc value)
4206  {
4207    // Nothing, for now.
4208
}
4209
4210  public final static String JavaDoc[] axisNames = new String JavaDoc[COUNT_OP_AXIS];
4211  static
4212  {
4213    axisNames[AXIS_ANCESTOR] = "ancestor";
4214    axisNames[AXIS_ANCESTOR_OR_SELF] = "ancestor-or-self";
4215    axisNames[AXIS_ATTRIBUTE] = "attribute";
4216    axisNames[AXIS_CHILD] = "child";
4217    axisNames[AXIS_DESCENDANT] = "descendant";
4218    axisNames[AXIS_DESCENDANT_OR_SELF] = "descendant-or-self";
4219    axisNames[AXIS_FOLLOWING] = "following";
4220    axisNames[AXIS_FOLLOWING_SIBLING] = "following-sibling";
4221    axisNames[AXIS_NAMESPACE] = "namespace";
4222    axisNames[AXIS_PARENT] = "parent";
4223    axisNames[AXIS_PRECEDING] = "preceding";
4224    axisNames[AXIS_PRECEDING_SIBLING] = "preceding-sibling";
4225    axisNames[AXIS_SELF] = "self";
4226  }
4227    
4228  public static Expression makeFunctionExp(String JavaDoc className, String JavaDoc name)
4229  {
4230    return makeFunctionExp(className,
4231               Compilation.mangleNameIfNeeded(name),
4232               name);
4233  }
4234
4235  public static Expression makeFunctionExp(String JavaDoc className,
4236                       String JavaDoc fieldName, String JavaDoc name)
4237  {
4238    return new ReferenceExp(name,
4239                            Declaration.getDeclarationValueFromStatic
4240                            (className, fieldName, name));
4241  }
4242
4243  /** Helper method for debugging. */
4244  String JavaDoc tokenString()
4245  {
4246    switch (curToken)
4247      {
4248      case STRING_TOKEN:
4249    StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
4250    sbuf.append('"');
4251    for (int i = 0; i < tokenBufferLength; i++)
4252      {
4253        char ch = tokenBuffer[i];
4254        if (ch == '"')
4255          sbuf.append('"');
4256        sbuf.append(ch);
4257      }
4258    sbuf.append('"');
4259    return sbuf.toString();
4260      case FNAME_TOKEN:
4261    return new String JavaDoc(tokenBuffer, 0, tokenBufferLength) + " + '('";
4262      case NCNAME_TOKEN:
4263      case QNAME_TOKEN:
4264    return new String JavaDoc(tokenBuffer, 0, tokenBufferLength);
4265      case EOF_TOKEN:
4266    return "<EOF>";
4267      default:
4268        if (curToken >= OP_AXIS_FIRST
4269            && curToken - OP_AXIS_FIRST < COUNT_OP_AXIS)
4270          return axisNames[curToken - OP_AXIS_FIRST]+"::-axis("+curToken+")";
4271    return Integer.toString(curToken);
4272      }
4273  }
4274
4275  public void error(char severity, String JavaDoc message, String JavaDoc code)
4276  {
4277    SourceMessages messages = getMessages();
4278    SourceError err
4279      = new SourceError(severity, port.getName(), curLine, curColumn, message);
4280    err.code = code;
4281    messages.error(err);
4282  }
4283
4284  public void error(char severity, String JavaDoc message)
4285  {
4286    error(severity, message, null);
4287  }
4288
4289  public Expression declError (String JavaDoc message)
4290    throws java.io.IOException JavaDoc, SyntaxException
4291  {
4292    if (interactive)
4293      return syntaxError(message);
4294    error(message);
4295    for (;;)
4296      {
4297    if (curToken==';' || curToken == EOF_TOKEN)
4298      break;
4299    getRawToken();
4300      }
4301    return new ErrorExp (message);
4302  }
4303
4304  /**
4305   * Handle syntax errors (at rewrite time).
4306   * @param message an error message to print out
4307   * @return an ErrorExp
4308   */

4309  public Expression syntaxError (String JavaDoc message, String JavaDoc code)
4310    throws java.io.IOException JavaDoc, SyntaxException
4311  {
4312    error('e', message, code);
4313    if (interactive)
4314      {
4315    curToken = 0;
4316    curValue = null;
4317    nesting = 0;
4318    ((InPort) getPort()).readState = '\n';
4319    for (;;)
4320      {
4321        int ch = read();
4322        if (ch < 0)
4323          break;
4324        if (ch == '\r' || ch == '\n')
4325          {
4326        unread(ch);
4327        break;
4328          }
4329      }
4330    throw new SyntaxException(getMessages());
4331      }
4332    return new ErrorExp (message);
4333  }
4334
4335  public Expression syntaxError (String JavaDoc message)
4336    throws java.io.IOException JavaDoc, SyntaxException
4337  {
4338    return syntaxError(message, "XPST0003");
4339  }
4340
4341  public void eofError(String JavaDoc msg) throws SyntaxException
4342  {
4343    fatal(msg, "XPST0003");
4344  }
4345
4346  public void fatal(String JavaDoc msg, String JavaDoc code) throws SyntaxException
4347  {
4348    SourceMessages messages = getMessages();
4349    SourceError err
4350      = new SourceError('f', port.getName(), curLine, curColumn, msg);
4351    err.code = code;
4352    messages.error(err);
4353    throw new SyntaxException(messages);
4354  }
4355
4356  void warnOldVersion (String JavaDoc message)
4357  {
4358    if (warnOldVersion || comp.isPedantic())
4359      error(comp.isPedantic() ? 'e' : 'w', message);
4360  }
4361}
4362
Popular Tags