KickJava   Java API By Example, From Geeks To Geeks.

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


1 // Copyright (c) 2001, 2002, 2003 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.mapping.*;
6 import gnu.lists.*;
7 import gnu.expr.*;
8 import gnu.text.Char;
9 import kawa.standard.Scheme;
10 import gnu.bytecode.*;
11 import gnu.kawa.lispexpr.LangPrimType;
12 import gnu.xquery.util.*;
13 import gnu.xml.*;
14 import gnu.text.Lexer;
15 import gnu.text.SourceMessages;
16 import java.io.Reader JavaDoc;
17 import java.util.Vector JavaDoc;
18 import gnu.kawa.functions.ConstantFunction0;
19 import gnu.kawa.reflect.ClassMethods;
20 import gnu.math.IntNum;
21 import gnu.kawa.xml.*;
22
23 /** The XQuery language. */
24
25 public class XQuery extends Language
26 {
27   public static final String JavaDoc XQUERY_FUNCTION_NAMESPACE
28     = "http://www.w3.org/2005/xpath-functions";
29   public static final String JavaDoc KAWA_FUNCTION_NAMESPACE
30     = "http://kawa.gnu.org/";
31   public static final String JavaDoc QEXO_FUNCTION_NAMESPACE
32     = "http://qexo.gnu.org/";
33   public static final String JavaDoc LOCAL_NAMESPACE
34     = "http://www.w3.org/2005/xquery-local-functions";
35   public static final String JavaDoc SCHEMA_NAMESPACE
36     = "http://www.w3.org/2001/XMLSchema";
37   public static final String JavaDoc SCHEMA_INSTANCE_NAMESPACE
38     = "http://www.w3.org/2001/XMLSchema-instance";
39   public static final String JavaDoc XHTML_NAMESPACE
40     = "http://www.w3.org/1999/xhtml";
41   public static final Namespace xqueryFunctionNamespace
42     = Namespace.getInstance(XQUERY_FUNCTION_NAMESPACE);
43   public static final Namespace kawaFunctionNamespace
44     = Namespace.getInstance(KAWA_FUNCTION_NAMESPACE);
45   public static final Namespace qexoFunctionNamespace
46     = Namespace.getInstance(QEXO_FUNCTION_NAMESPACE);
47   public static final Namespace[] defaultFunctionNamespacePath
48     = { qexoFunctionNamespace,
49     xqueryFunctionNamespace,
50     Namespace.EmptyNamespace,
51     kawaFunctionNamespace };
52   static boolean charIsInt = false;
53
54   /** Pseudo-namespace "prefix" for the default element namespace. */
55   public static final String JavaDoc DEFAULT_ELEMENT_PREFIX = null;
56   /** Pseudo-namespace "prefix" for the default function namespace. */
57   public static final String JavaDoc DEFAULT_FUNCTION_PREFIX = "(functions)";
58
59   Namespace defaultNamespace;
60
61   public boolean hasSeparateFunctionNamespace()
62   {
63     return true;
64   }
65
66   public static gnu.math.Numeric asNumber(Object JavaDoc arg)
67   {
68     if (arg instanceof Char)
69       return gnu.math.IntNum.make(((Char) arg).intValue());
70     return (gnu.math.Numeric) arg;
71   }
72
73   public static char asChar(Object JavaDoc x)
74   {
75     if (x instanceof Char)
76       return ((Char) x).charValue();
77     int i;
78     if (x instanceof gnu.math.Numeric)
79       i = ((gnu.math.Numeric) x).intValue();
80     else
81       i = -1;
82     if (i < 0 || i > 0xffff)
83       throw new ClassCastException JavaDoc("not a character value");
84     return (char) i;
85   }
86
87   public boolean isTrue(Object JavaDoc value)
88   {
89     return gnu.xquery.util.BooleanValue.booleanValue(value);
90   }
91
92   public gnu.text.Lexer getLexer(InPort inp, SourceMessages messages)
93   {
94     return new XQParser(inp, messages, this);
95   }
96
97   public Compilation getCompilation (Lexer lexer, SourceMessages messages)
98   {
99     return new Compilation(this, messages, ((XQParser) lexer).lexical);
100   }
101
102   /** Special parser flag used by <code>evalToFocusProc</code>. */
103   public static final int PARSE_WITH_FOCUS = 0x10000;
104
105   public boolean parse (Compilation tr, int options)
106     throws java.io.IOException JavaDoc, gnu.text.SyntaxException
107   {
108     ModuleExp mexp = tr.mainLambda;
109     Compilation.defaultCallConvention = Compilation.CALL_WITH_CONSUMER;
110     tr.mustCompileHere();
111     XQParser parser = (XQParser) tr.lexer;
112     if (parser.isInteractive())
113       {
114     Expression sexp = parser.parse(tr);
115     if (sexp == null)
116       return false;
117     mexp.body = sexp;
118       }
119     else if ((options & PARSE_WITH_FOCUS) != 0)
120       {
121     LambdaExp lexp = new LambdaExp(3);
122     Declaration dotDecl = lexp.addDeclaration(XQParser.DOT_VARNAME);
123     dotDecl.setFlag(Declaration.IS_SINGLE_VALUE);
124     dotDecl.noteValue (null); // Does not have a known value.
125
lexp.addDeclaration(XQParser.POSITION_VARNAME, Type.int_type);
126     lexp.addDeclaration(XQParser.LAST_VARNAME, Type.int_type);
127     tr.push(lexp);
128     lexp.body = parser.parse(tr);
129     tr.pop(lexp);
130     mexp.body = lexp;
131       }
132     else
133       {
134     Vector JavaDoc exps = new Vector JavaDoc(10);
135         Expression sexp = mexp.body;
136         if (sexp instanceof BeginExp)
137           {
138             BeginExp bexp = (BeginExp) sexp;
139             int blen = bexp.getExpressionCount();
140             Expression[] bexps = bexp.getExpressions();
141             for (int i = 0; i < blen; i++)
142               exps.addElement(bexps[i]);
143           }
144         else if (sexp != null && sexp != QuoteExp.voidExp)
145           {
146             exps.addElement(sexp);
147           }
148     for (;;)
149       {
150         sexp = parser.parse(tr);
151         if (sexp == null)
152               {
153                 if (parser.parseCount == 0 && !parser.isInteractive())
154                   {
155                     parser.error('e', "empty module", "XPST0003");
156                     return false;
157                   }
158                 break;
159               }
160         exps.addElement(sexp);
161       }
162     int nexps = exps.size();
163     if (nexps == 0)
164       mexp.body = QuoteExp.voidExp;
165     else if (nexps == 1)
166       mexp.body = (Expression) exps.elementAt(0);
167     else
168       {
169         Expression[] arr = new Expression[nexps];
170         exps.copyInto(arr);
171         mexp.body = new BeginExp(arr);
172       }
173       }
174     // It seems silly to pop all the declarations, and then push them
175
// in resolveModule. The complication is that imported variable
176
// declarations are pushed eagerly in the first pass.
177
tr.pop(mexp);
178
179     if (false)
180       {
181     OutPort dout = OutPort.outDefault();
182     dout.println ("[Before name-resolving \""+mexp.getName()+"\":");
183     mexp.print(dout);
184     dout.println(']');
185     dout.flush();
186       }
187
188     XQResolveNames resolver = new XQResolveNames(tr);
189     resolver.functionNamespacePath = parser.functionNamespacePath;
190     resolver.parser = parser;
191     resolver.resolveModule(mexp); // FIXME should move to resolve(Compilation)
192
tr.setState(Compilation.BODY_PARSED);
193     return true;
194   }
195
196   public void resolve (Compilation comp)
197   {
198   }
199
200   public static int namespaceForFunctions (int argCount)
201   {
202     return (argCount << 2) | FUNCTION_NAMESPACE;
203   }
204
205   public static final int VARIADIC_FUNCTION_NAMESPACE =
206     (-1 << 2) | FUNCTION_NAMESPACE;
207
208   public int getNamespaceOf(Declaration decl)
209   {
210     if (decl.isProcedureDecl())
211       {
212         if (decl.getCode() < 0)
213           return VARIADIC_FUNCTION_NAMESPACE;
214         Expression value = decl.getValue();
215         if (value instanceof LambdaExp)
216           {
217             LambdaExp lexp = (LambdaExp) value;
218             if (lexp.min_args == lexp.max_args)
219               return namespaceForFunctions(lexp.min_args);
220           }
221         else if (value instanceof QuoteExp)
222           {
223             Object JavaDoc val = ((QuoteExp) value).getValue();
224             if (val instanceof Procedure)
225               {
226                 Procedure proc = (Procedure) val;
227                 int min = proc.minArgs();
228                 int max = proc.maxArgs();
229                 if (min == max)
230                   return namespaceForFunctions(min);
231               }
232           }
233         else if (value instanceof ReferenceExp)
234           return getNamespaceOf(((ReferenceExp) value).getBinding());
235         // I believe we only get here after an error.
236
return VARIADIC_FUNCTION_NAMESPACE;
237       }
238     return VALUE_NAMESPACE;
239   }
240
241   public boolean hasNamespace (Declaration decl, int namespace)
242   {
243     int dnspace = getNamespaceOf(decl);
244     return (dnspace == namespace
245             || (dnspace == VARIADIC_FUNCTION_NAMESPACE
246                 && (namespace & FUNCTION_NAMESPACE) != 0)
247             || (namespace == VARIADIC_FUNCTION_NAMESPACE
248                 && (dnspace & FUNCTION_NAMESPACE) != 0));
249   }
250
251   public Symbol getSymbol (String JavaDoc name)
252   {
253     return Symbol.make(defaultNamespace, name);
254   }
255
256   public void define(String JavaDoc name, Object JavaDoc value)
257   {
258     Symbol sym = Symbol.make(defaultNamespace, name);
259     Object JavaDoc prop = value instanceof Procedure ? EnvironmentKey.FUNCTION : null;
260     environ.define(sym, prop, value);
261   }
262
263   protected void define_method(String JavaDoc name, String JavaDoc cname, String JavaDoc mname)
264   {
265     Symbol sym = Symbol.make(defaultNamespace, name);
266     // This does require eager loading of the class, which takes
267
// extra time on startup. FIXME.
268
ClassType ctype = ClassType.make(cname);
269     Procedure proc = ClassMethods.apply(ctype, mname, '\0', this);
270     proc.setSymbol(sym);
271     environ.define(sym, EnvironmentKey.FUNCTION, proc);
272   }
273
274   public String JavaDoc getName()
275   {
276     return "XQuery";
277   }
278
279   static int envCounter = 0;
280
281   /** Environment of pre-defined non-standard Qexo/Kawa functions. */
282   public static Environment extensionsEnvEnv
283     = Environment.getInstance(KAWA_FUNCTION_NAMESPACE);
284
285   /** Call a procedure with a given focus (context).
286    * @param proc a 3-operand <code>Procedure</code> as returned by
287    * <code>evalToFocusProc</code>
288    * @param item the context item, passed as the first argument to <code>proc</code>
289    * @param position the context position, passed as the second argument
290    * @param size the context size, passed as the second argument
291    * @param out where to send the result of <code>proc</code>
292    */

293   public void applyWithFocus (Procedure proc,
294                   Object JavaDoc item, int position, int size,
295                   Consumer out)
296     throws Throwable JavaDoc
297   {
298     CallContext ctx = CallContext.getInstance();
299     proc.check3(item, IntNum.make(position),IntNum.make(size), ctx);
300     Consumer save = ctx.consumer;
301     try
302       {
303     ctx.consumer = out;
304     ctx.runUntilDone();
305       }
306     finally
307       {
308     ctx.consumer = save;
309       }
310   }
311
312   /** Call a procedure with a given focus (context).
313    * @param proc a 3-operand <code>Procedure</code> as returned by
314    * <code>evalToFocusProc</code>
315    * @param item the context item, passed as the first argument to <code>proc</code>
316    * @param position the context position, passed as the second argument
317    * @param size the context size, passed as the second argument
318    * @return the result of applying <code>proc</code>
319    */

320   public Object JavaDoc applyWithFocus (Procedure proc,
321                 Object JavaDoc item, int position, int size)
322     throws Throwable JavaDoc
323   {
324     CallContext ctx = CallContext.getInstance();
325     int oldIndex = ctx.startFromContext();
326     try
327       {
328     proc.check3(item, IntNum.make(position),IntNum.make(size), ctx);
329     return ctx.getFromContext(oldIndex);
330       }
331     catch (Throwable JavaDoc ex)
332       {
333     ctx.cleanupFromContext(oldIndex);
334     throw ex;
335       }
336   }
337
338   /** Call a procedure with each item in a sequence as the context item.
339    * @param proc a 3-operand <code>Procedure</code> as returned by
340    * <code>evalToFocusProc</code>
341    * @param values a sequence. The <code>proc</code> is called once for each
342    * item, with the item as the first argument, a 1-based index as the
343    * second argument, and the sequence size as the third argument.
344    * @param out where to send the result of <code>proc</code>
345    */

346   public void applyWithFocus (Procedure proc, Object JavaDoc values, Consumer out)
347     throws Throwable JavaDoc
348   {
349     CallContext ctx = CallContext.getInstance();
350     Consumer save = ctx.consumer;
351     try
352       {
353     ctx.consumer = out;
354     applyWithFocus$X(proc, values, ctx);
355       }
356     finally
357       {
358     ctx.consumer = save;
359       }
360   }
361
362   /** Call a procedure with each item in a sequence as the context item.
363    * @param proc a 3-operand <code>Procedure</code> as returned by
364    * <code>evalToFocusProc</code>
365    * @param values a sequence. The <code>proc</code> is called once for each
366    * item, with the item as the first argument, a 1-based index as the
367    * second argument, and the sequence size as the third argument.
368    * @return the result of applying <code>proc</code>
369    */

370   public Object JavaDoc applyWithFocus (Procedure proc, Object JavaDoc values)
371     throws Throwable JavaDoc
372   {
373     CallContext ctx = CallContext.getInstance();
374     int oldIndex = ctx.startFromContext();
375     try
376       {
377     applyWithFocus$X(proc, values, ctx);
378     return ctx.getFromContext(oldIndex);
379       }
380     catch (Throwable JavaDoc ex)
381       {
382     ctx.cleanupFromContext(oldIndex);
383     throw ex;
384       }
385   }
386
387   /** Call a procedure with each item in a sequence as the context item.
388    * @param proc a 3-operand <code>Procedure</code> as returned by
389    * <code>evalToFocusProc</code>
390    * @param values a sequence. The <code>proc</code> is called once for each
391    * item, with the item as the first argument, a 1-based index as the
392    * second argument, and the sequence size as the third argument.
393    * @param ctx the <code>CallContext</code>. The <code>$X</code> in the
394    * method name tells Kawa that this argument is implicit when invoked
395    * from XQuery.
396    */

397   public void applyWithFocus$X (Procedure proc, Object JavaDoc values, CallContext ctx)
398     throws Throwable JavaDoc
399   {
400     if (values instanceof Values)
401       {
402     Values v = (Values) values;
403     int count = v.size();
404     if (count == 0)
405       return;
406     int ipos = 0;
407     IntNum size = IntNum.make(count);
408     for (int i = 1; ; i++)
409       {
410         proc.check3(v.getPosNext(ipos), IntNum.make(i), size, ctx);
411         ctx.runUntilDone();
412         if (i == count)
413           break;
414             ipos = v.nextPos(ipos);
415       }
416       }
417     else
418       {
419     IntNum one = IntNum.one();
420     proc.check3(values, one, one, ctx);
421     ctx.runUntilDone();
422       }
423   }
424
425   /** Parse an XQuery expression that is the body of a procedure.
426    * Helper method used by <code>evalWithFocus</code> methods.
427    * @param expr an XQuery expression (query) to evaluate
428    * @return a 3-operand Procedure whose arguments become
429    * the context item, position, and size.
430    */

431   public Procedure evalToFocusProc (String JavaDoc expr)
432     throws Throwable JavaDoc
433   {
434     SourceMessages messages = new SourceMessages();
435     Procedure proc = evalToFocusProc(new CharArrayInPort(expr), messages);
436     if (messages.seenErrors())
437       throw new RuntimeException JavaDoc("invalid syntax in eval form:\n"
438                  + messages.toString(20));
439     return proc;
440   }
441
442   /** Parse an XQuery expression from a <code>Reader</code> that is the body of a procedure.
443    * Helper method used by <code>evalWithFocus</code> methods.
444    * @param in where we read the expression from
445    * @param messages where to write syntax errors
446    * @return a 3-operand Procedure whose arguments become
447    * the context item, position, and size.
448    */

449   public Procedure evalToFocusProc (Reader JavaDoc in, SourceMessages messages)
450     throws Throwable JavaDoc
451   {
452     InPort port = in instanceof InPort ? (InPort) in : new InPort(in);
453     Compilation comp = parse(port, messages, PARSE_WITH_FOCUS|PARSE_IMMEDIATE);
454     CallContext ctx = CallContext.getInstance();
455     int oldIndex = ctx.startFromContext();
456     try
457       {
458     ModuleExp.evalModule(Environment.getCurrent(), ctx, comp, null, null);
459     return (Procedure) ctx.getFromContext(oldIndex);
460       }
461     catch (Throwable JavaDoc ex)
462       {
463     ctx.cleanupFromContext(oldIndex);
464     throw ex;
465       }
466   }
467
468   /** Evaluate an expression with each item in a sequence as the context item.
469    * @param in where we read the expression from
470    * @param messages where to write syntax errors
471    * @param values becomes the context sequence while
472    * evaluating <code>expr</code>.
473    * @param out where to send the result of the expression
474    */

475   public void evalWithFocus (Reader JavaDoc in, SourceMessages messages,
476                  Object JavaDoc values, Consumer out)
477     throws Throwable JavaDoc
478   {
479     applyWithFocus(evalToFocusProc(in, messages), values, out);
480   }
481
482   /** Evaluate an expression with each item in a sequence as the context item.
483    * @param expr an XQuery expression (query) to evaluate
484    * @param values becomes the context sequence while
485    * evaluating the expression
486    * @return the result of evaluating the expression
487    */

488   public Object JavaDoc evalWithFocus (String JavaDoc expr, Object JavaDoc values)
489     throws Throwable JavaDoc
490   {
491     return applyWithFocus(evalToFocusProc(expr), values);
492   }
493
494   /** Evaluate an expression with a given focus (context).
495    * @param expr an XQuery expression (query) to evaluate
496    * @param item becomes the context item while evaluating <code>expr</code>.
497    * @param position becomes the context position
498    * @param size becomes the context size
499    * @return the result of evaluating <code>expr</code>
500    */

501   public Object JavaDoc evalWithFocus (String JavaDoc expr,
502                    Object JavaDoc item, int position, int size)
503     throws Throwable JavaDoc
504   {
505     return applyWithFocus(evalToFocusProc(expr), item, position, size);
506   }
507
508   /** Evaluate an expression with a given focus (context).
509    * @param in where we read the expression from
510    * @param messages where to write syntax errors
511    * @param item becomes the context item while evaluating the expression
512    * @param position becomes the context position
513    * @param size becomes the context size
514    * @param out where to send the result of the expression
515    */

516   public void evalWithFocus (Reader JavaDoc in, SourceMessages messages,
517                  Object JavaDoc item, int position, int size,
518                  Consumer out)
519     throws Throwable JavaDoc
520   {
521     applyWithFocus(evalToFocusProc(in, messages), item, position, size, out);
522   }
523
524   /** Evaluate an expression with a given focus (context).
525    * Similar to <code>evalWithFocus(String, Object, Consumer)</code>.
526    * The "$X" in the method name tells the Kawa compiler that the CallContext
527    * argument is implicit, so it can be invoked from XQuery code thus:
528    * <code>XQuery:eval-with-focus($xquery, "expr", $sequence)</code>
529    */

530   public void eval_with_focus$X (String JavaDoc expr,
531                  Object JavaDoc values,
532                  CallContext ctx)
533     throws Throwable JavaDoc
534   {
535     applyWithFocus$X(evalToFocusProc(expr), values, ctx);
536   }
537
538   /** Evaluate an expression with a given focus (context).
539    * Similar to <code>evalWithFocus(String, Object, int, int, Consumer)</code>.
540    * The "$X" in the method name tells the Kawa compiler that the CallContext
541    * argument is implicit, so it can be invoked from XQuery code thus:
542    * <code>XQuery:eval-with-focus($xquery, "expr", $item, $pos, $size)</code>
543    */

544   public void eval_with_focus$X (String JavaDoc expr,
545                    Object JavaDoc item, int position, int size,
546                    CallContext ctx)
547     throws Throwable JavaDoc
548   {
549     Procedure proc = evalToFocusProc(expr);
550     proc.check3(item, IntNum.make(position), IntNum.make(size), ctx);
551   }
552
553   public static final Environment xqEnvironment
554     = Environment.make(XQUERY_FUNCTION_NAMESPACE);
555
556   // This field need to be public so that the findLiteral method in
557
// gnu.expr.LitTable can find it.
558
public static final XQuery instance = new XQuery();
559   static { instance.initXQuery(); }
560
561   public XQuery()
562   {
563     environ = xqEnvironment;
564     defaultNamespace = xqueryFunctionNamespace;
565   }
566
567   private void initXQuery ()
568   {
569     ModuleBody.setMainPrintValues(true);
570
571     /*
572     Environment scmEnv = Scheme.builtin();
573
574     Environment saveEnv = Environment.getCurrent();
575     try
576       {
577     Environment.setCurrent(scmEnv);
578     SymbolEnumeration e = scmEnv.enumerateAllSymbols();
579     while (e.hasMoreElements())
580       {
581         Symbol b = e.nextSymbol();
582         Object val = b.get(null);
583         if (val instanceof Procedure)
584           extensionsEnvEnv.getSymbol(b.getName()).setFunctionValue(val);
585       }
586     // Force it to be loaded now, so we can over-ride let* length etc.
587     loadClass("kawa.lib.std_syntax");
588     loadClass("kawa.lib.lists");
589     loadClass("kawa.lib.strings");
590     loadClass("gnu.commonlisp.lisp.PrimOps");
591     loadClass("gnu.kawa.slib.XStrings");
592       }
593     catch (Throwable ex)
594       {
595     // Ignore. We get a ClassNotFoundException if gnu.kawa.servlet.HTTP
596     // was not built. We get a NoClassDefFoundError if gnu.kawa.servlet.HTTP
597     // can't find servlets in the classpath.
598       }
599     finally
600       {
601     Environment.setCurrent(saveEnv);
602       }
603     */

604
605     defProcStFld("unescaped-data", "gnu.kawa.xml.MakeUnescapedData", "unescapedData");
606     defProcStFld("item-at", "gnu.xquery.util.ItemAt", "itemAt");
607     defProcStFld("count", "gnu.kawa.functions.CountValues", "countValues");
608     define_method("sum", "gnu.xquery.util.Reduce", "sum"); // Overloaded
609
defProcStFld("avg", "gnu.xquery.util.Average", "avg");
610     defProcStFld("sublist", "gnu.xquery.util.SubList", "subList"); // deprecated
611
defProcStFld("subsequence", "gnu.xquery.util.SubList", "subList");
612     define_method("empty", "gnu.xquery.util.SequenceUtils",
613           "isEmptySequence");
614     define_method("exists", "gnu.xquery.util.SequenceUtils",
615           "exists");
616     define_method("insert-before", "gnu.xquery.util.SequenceUtils",
617           "insertBefore$X");
618     define_method("remove", "gnu.xquery.util.SequenceUtils",
619           "remove$X");
620     define_method("reverse", "gnu.xquery.util.SequenceUtils",
621           "reverse$X");
622     defProcStFld("false", "gnu.xquery.lang.XQuery", "falseFunction");
623     defProcStFld("true", "gnu.xquery.lang.XQuery", "trueFunction");
624     defProcStFld("boolean", "gnu.xquery.util.BooleanValue", "booleanValue");
625
626     define_method("trace", "gnu.xquery.util.Debug", "trace");
627     define_method("error", "gnu.xquery.util.XQException",
628                   "error"); // overloaded
629
defProcStFld("write-to", "gnu.kawa.xml.WriteTo", "writeTo");
630     defProcStFld("write-to-if-changed", "gnu.kawa.xml.WriteTo",
631                  "writeToIfChanged");
632     defProcStFld("iterator-items",
633          "gnu.kawa.xml.IteratorItems", "iteratorItems");
634     defProcStFld("list-items", "gnu.kawa.xml.ListItems", "listItems");
635     define_method("node-name", "gnu.kawa.xml.NodeName", "nodeName");
636     define_method("nilled", "gnu.xquery.util.NodeUtils", "nilled");
637     define_method("data", "gnu.xquery.util.NodeUtils", "data$X");
638     define_method("lower-case", "gnu.xquery.util.StringUtils", "lowerCase");
639     define_method("upper-case", "gnu.xquery.util.StringUtils", "upperCase");
640     define_method("substring", "gnu.xquery.util.StringUtils", "substring");
641     define_method("string-length",
642           "gnu.xquery.util.StringUtils", "stringLength");
643     define_method("substring-before",
644           "gnu.xquery.util.StringUtils", "substringBefore");
645     define_method("substring-after",
646           "gnu.xquery.util.StringUtils", "substringAfter");
647     define_method("translate", "gnu.xquery.util.StringUtils", "translate");
648     define_method("encode-for-uri", "gnu.xquery.util.StringUtils",
649                   "encodeForUri");
650     define_method("iri-to-uri", "gnu.xquery.util.StringUtils", "iriToUri");
651     define_method("escape-html-uri", "gnu.xquery.util.StringUtils",
652                   "escapeHtmlUri");
653     // Non-standard (in F&O example appendix). Put in qexo namespace?
654
// define_method("string-pad", "gnu.xquery.util.StringUtils", "stringPad");
655
define_method("contains", "gnu.xquery.util.StringUtils", "contains");
656     define_method("starts-with", "gnu.xquery.util.StringUtils", "startsWith");
657     define_method("ends-with","gnu.xquery.util.StringUtils", "endsWith");
658     define_method("codepoint-equal", "gnu.xquery.util.StringUtils",
659                   "codepointEqual");
660     define_method("normalize-unicode", "gnu.xquery.util.StringUtils",
661                   "normalizeUnicode");
662     define_method("string-join", "gnu.xquery.util.StringUtils", "stringJoin");
663     define_method("concat", "gnu.xquery.util.StringUtils", "concat$V");
664     define_method("matches", "gnu.xquery.util.StringUtils", "matches");
665     define_method("replace", "gnu.xquery.util.StringUtils", "replace");
666     define_method("tokenize", "gnu.xquery.util.StringUtils", "tokenize$X");
667     define_method("string-to-codepoints", "gnu.xquery.util.StringUtils",
668           "stringToCodepoints$X");
669     define_method("codepoints-to-string", "gnu.xquery.util.StringUtils",
670           "codepointsToString");
671
672     define_method("abs", "gnu.xquery.util.NumberValue", "abs");
673     define_method("floor", "gnu.xquery.util.NumberValue", "floor");
674     define_method("ceiling", "gnu.xquery.util.NumberValue", "ceiling");
675     define_method("round", "gnu.xquery.util.NumberValue", "round");
676     define_method("round-half-to-even", "gnu.xquery.util.NumberValue",
677                   "roundHalfToEven");
678
679     define_method("QName", "gnu.xquery.util.QNameUtils", "makeQName");
680     define_method("resolve-QName", "gnu.xquery.util.QNameUtils",
681                   "resolveQNameUsingElement");
682     define_method("prefix-from-QName", "gnu.xquery.util.QNameUtils",
683           "prefixFromQName");
684     define_method("local-name-from-QName", "gnu.xquery.util.QNameUtils",
685           "localNameFromQName");
686     define_method("namespace-uri-from-QName", "gnu.xquery.util.QNameUtils",
687           "namespaceURIFromQName");
688     define_method("namespace-uri-for-prefix", "gnu.xquery.util.QNameUtils",
689           "namespaceURIForPrefix");
690     define_method("in-scope-prefixes", "gnu.xquery.util.NodeUtils",
691                   "inScopePrefixes$X");
692     define_method("document-uri", "gnu.xquery.util.NodeUtils", "documentUri");
693
694     define_method("years-from-duration", "gnu.xquery.util.TimeUtils",
695                   "yearsFromDuration");
696     define_method("months-from-duration", "gnu.xquery.util.TimeUtils",
697                   "monthsFromDuration");
698     define_method("days-from-duration", "gnu.xquery.util.TimeUtils",
699                   "daysFromDuration");
700     define_method("hours-from-duration", "gnu.xquery.util.TimeUtils",
701                   "hoursFromDuration");
702     define_method("minutes-from-duration", "gnu.xquery.util.TimeUtils",
703                   "minutesFromDuration");
704     define_method("seconds-from-duration", "gnu.xquery.util.TimeUtils",
705                   "secondsFromDuration");
706     define_method("year-from-dateTime", "gnu.xquery.util.TimeUtils",
707                   "yearFromDateTime");
708     define_method("month-from-dateTime", "gnu.xquery.util.TimeUtils",
709                   "monthFromDateTime");
710     define_method("day-from-dateTime", "gnu.xquery.util.TimeUtils",
711                   "dayFromDateTime");
712     define_method("hours-from-dateTime", "gnu.xquery.util.TimeUtils",
713                   "hoursFromDateTime");
714     define_method("minutes-from-dateTime", "gnu.xquery.util.TimeUtils",
715                   "minutesFromDateTime");
716     define_method("seconds-from-dateTime", "gnu.xquery.util.TimeUtils",
717                   "secondsFromDateTime");
718     define_method("timezone-from-dateTime", "gnu.xquery.util.TimeUtils",
719                   "timezoneFromDateTime");
720     define_method("year-from-date", "gnu.xquery.util.TimeUtils",
721                   "yearFromDate");
722     define_method("month-from-date", "gnu.xquery.util.TimeUtils",
723                   "monthFromDate");
724     define_method("day-from-date", "gnu.xquery.util.TimeUtils",
725                   "dayFromDate");
726     define_method("timezone-from-date", "gnu.xquery.util.TimeUtils",
727                   "timezoneFromDate");
728     define_method("hours-from-time", "gnu.xquery.util.TimeUtils",
729                   "hoursFromTime");
730     define_method("minutes-from-time", "gnu.xquery.util.TimeUtils",
731                   "minutesFromTime");
732     define_method("seconds-from-time", "gnu.xquery.util.TimeUtils",
733                   "secondsFromTime");
734     define_method("timezone-from-time", "gnu.xquery.util.TimeUtils",
735                   "timezoneFromTime");
736     define_method("adjust-dateTime-to-timezone", "gnu.xquery.util.TimeUtils",
737                   "adjustDateTimeToTimezone"); // overloaded
738
define_method("adjust-date-to-timezone", "gnu.xquery.util.TimeUtils",
739                   "adjustDateToTimezone"); // overloaded
740
define_method("adjust-time-to-timezone", "gnu.xquery.util.TimeUtils",
741                   "adjustTimeToTimezone"); // overloaded
742
define_method("dateTime", "gnu.xquery.util.TimeUtils", "dateTime");
743
744     define_method("zero-or-one", "gnu.xquery.util.SequenceUtils", "zeroOrOne");
745     define_method("one-or-more", "gnu.xquery.util.SequenceUtils", "oneOrMore");
746     define_method("exactly-one", "gnu.xquery.util.SequenceUtils", "exactlyOne");
747
748     defProcStFld("distinct-nodes", "gnu.kawa.xml.SortNodes", "sortNodes");
749
750     // FIXME - should be imported?
751
defProcStFld("children", "gnu.kawa.xml.Children", "children");
752     define_method("not", "gnu.xquery.util.BooleanValue", "not");
753
754     defaultNamespace = qexoFunctionNamespace;
755     defProcStFld("response-header", "gnu.kawa.servlet.HTTP");
756     defProcStFld("response-content-type", "gnu.kawa.servlet.HTTP");
757     defProcStFld("response-status", "gnu.kawa.servlet.HTTP");
758     defProcStFld("error-response", "gnu.kawa.servlet.HTTP");
759     defProcStFld("current-servlet", "gnu.kawa.servlet.HTTP");
760     defProcStFld("current-servlet-context", "gnu.kawa.servlet.HTTP");
761     defProcStFld("current-servlet-config", "gnu.kawa.servlet.HTTP");
762     defProcStFld("servlet-context-realpath", "gnu.kawa.servlet.HTTP");
763     defProcStFld("get-response", "gnu.kawa.servlet.HTTP");
764     defProcStFld("get-request", "gnu.kawa.servlet.HTTP");
765     defProcStFld("request-method", "gnu.kawa.servlet.HTTP");
766     defProcStFld("request-uri", "gnu.kawa.servlet.HTTP");
767     defProcStFld("request-url", "gnu.kawa.servlet.HTTP");
768     defProcStFld("request-path-info", "gnu.kawa.servlet.HTTP");
769     defProcStFld("request-path-translated", "gnu.kawa.servlet.HTTP");
770     defProcStFld("request-servlet-path", "gnu.kawa.servlet.HTTP");
771     defProcStFld("request-query-string", "gnu.kawa.servlet.HTTP");
772     defProcStFld("request-parameter", "gnu.kawa.servlet.HTTP");
773     defProcStFld("request-parameters", "gnu.kawa.servlet.HTTP");
774     defaultNamespace = xqueryFunctionNamespace;
775   }
776
777   public static XQuery getInstance()
778   {
779     return instance;
780   }
781
782   /** The compiler insert calls to this method for applications and applets. */
783   public static void registerEnvironment()
784   {
785     Language.setDefaults(new XQuery());
786   }
787
788   static public QuoteExp falseExp =
789     new QuoteExp(Boolean.FALSE, XDataType.booleanType);
790   static public QuoteExp trueExp =
791     new QuoteExp(Boolean.TRUE, XDataType.booleanType);
792
793   public static final ConstantFunction0 falseFunction
794     = new ConstantFunction0("false", falseExp);
795   public static final ConstantFunction0 trueFunction
796     = new ConstantFunction0("true", trueExp);
797
798   public Consumer getOutputConsumer(java.io.Writer JavaDoc out)
799   {
800     return new XMLPrinter(out, false);
801   }
802
803   static Object JavaDoc[] typeMap =
804     { "string", XDataType.stringType,
805       "untypedAtomic", XDataType.untypedAtomicType,
806       "boolean", XDataType.booleanType,
807       "integer", XIntegerType.integerType,
808       "long", XIntegerType.longType,
809       "int", XIntegerType.intType,
810       "short", XIntegerType.shortType,
811       "byte", XIntegerType.byteType,
812       "unsignedLong", XIntegerType.unsignedLongType,
813       "unsignedInt", XIntegerType.unsignedIntType,
814       "unsignedShort", XIntegerType.unsignedShortType,
815       "unsignedByte", XIntegerType.unsignedByteType,
816       "positiveInteger", XIntegerType.positiveIntegerType,
817       "nonPositiveInteger", XIntegerType.nonPositiveIntegerType,
818       "negativeInteger", XIntegerType.negativeIntegerType,
819       "nonNegativeInteger", XIntegerType.nonNegativeIntegerType,
820       "date", XTimeType.dateType,
821       "dateTime", XTimeType.dateTimeType,
822       "time", XTimeType.timeType,
823       "duration", XTimeType.durationType,
824       "yearMonthDuration", XTimeType.yearMonthDurationType,
825       "dayTimeDuration", XTimeType.dayTimeDurationType,
826       "gYearMonth", XTimeType.gYearMonthType,
827       "gYear", XTimeType.gYearType,
828       "gMonthDay", XTimeType.gMonthDayType,
829       "gDay", XTimeType.gDayType,
830       "gMonth", XTimeType.gMonthType,
831       "decimal", XDataType.decimalType,
832       "float", XDataType.floatType,
833       "double", XDataType.doubleType,
834       "anyURI", XDataType.anyURIType,
835       "hexBinary", XDataType.hexBinaryType,
836       "base64Binary", XDataType.base64BinaryType,
837       "NOTATION", XDataType.NotationType,
838       "QName", "gnu.mapping.Symbol",
839       "anyAtomicType", Type.pointer_type
840     };
841
842   public static Type getStandardType (String JavaDoc name)
843   {
844     for (int i = typeMap.length; (i -= 2) >= 0; )
845       {
846     if (typeMap[i].equals(name))
847       {
848         Object JavaDoc t = typeMap[i+1];
849         if (t instanceof String JavaDoc)
850           return Scheme.string2Type((String JavaDoc) t);
851         else
852           return (Type) t;
853       }
854       }
855     return null;
856   }
857
858   public Type getTypeFor(String JavaDoc name)
859   {
860     String JavaDoc core = name.startsWith("xs:") ? name.substring(3)
861       : name.startsWith("xdt:") ? name.substring(4)
862       : name;
863     Type t = getStandardType(core);
864     return t != null ? t : Scheme.string2Type(name);
865   }
866
867   public Type getTypeFor (Class JavaDoc clas)
868   {
869     if (clas.isPrimitive())
870       {
871     String JavaDoc name = clas.getName();
872     if (name.equals("boolean"))
873           return XDataType.booleanType;
874     return Scheme.getNamedType(name);
875       }
876     else if (! clas.isArray())
877       {
878         String JavaDoc name = clas.getName();
879         if (name.equals("java.lang.String"))
880           return XDataType.stringType;
881         if (name.equals("gnu.kawa.xml.UntypedAtomic"))
882           return XDataType.untypedAtomicType;
883         if (name.equals("java.lang.Boolean"))
884           return XDataType.booleanType;
885         if (name.equals("java.lang.Float"))
886           return XDataType.floatType;
887         if (name.equals("java.lang.Double"))
888           return XDataType.doubleType;
889         if (name.equals("java.math.BigDecimal"))
890           return XDataType.decimalType;
891         if (name.equals("gnu.math.Duration"))
892           return XDataType.durationType;
893         /* #ifdef use:java.net.URI */
894         if (name.equals("java.net.URI"))
895           return XDataType.anyURIType;
896         /* #endif */
897       }
898     return Type.make(clas);
899   }
900
901   public Procedure getPrompter()
902   {
903     return new Prompter();
904   }
905
906   /*
907   static boolean isPunctuation (char ch)
908   {
909     return ch == '-' || ch == '.' || ch == ':' || ch == '_'
910       || (ch >= 0xB7 // To short-circuit rare tests
911       && (ch == '·' // middle dot
912           || ch == '?' // greek ano teleia
913           || ch == '?' // arabic end of ayah
914           || ch == '?' // arabic start of rub el hizb
915           ));
916   }
917
918   static boolean isMark (char ch)
919   {
920     return ! Character.isLetter(ch)
921       && ! Characfter.isDigit(ch)
922       && Character.isJavaIdnteiferiPart(ch);
923   }
924   */

925
926   /** Mangle an XML name as specified by JAXB. */
927   static void mangle (String JavaDoc name, int start, int length,
928               StringBuffer JavaDoc sbuf, char mode)
929   {
930     // One of 'P' for punctuation; 'D' for digit; 'M' for mark;
931
// 'L' for lower-case; 'U' for upper-case; 'O' other (uncased) letter.
932
char prev = 'P';
933     int outStart = sbuf.length();
934     for (int i = 0; i < length; )
935       {
936     boolean wordStart;
937     char ch = name.charAt(start + i);
938     i++;
939     if (Character.isUpperCase(ch))
940       {
941         wordStart = prev != 'U'
942           || (i < length
943           && Character.isLowerCase(name.charAt(start+i)));
944         prev = 'U';
945       }
946     else if (Character.isLowerCase(ch))
947       {
948         wordStart = prev != 'L' || prev != 'U';
949         prev = 'L';
950       }
951     else if (Character.isLetter(ch))
952       { // uncased letter
953
wordStart = prev != 'O';
954         prev = 'O';
955       }
956     else if (Character.isDigit(ch))
957       {
958         wordStart = prev != 'D';
959         prev = 'D';
960       }
961     else if (Character.isJavaIdentifierPart(ch))
962       {
963         wordStart = prev != 'D' && prev != 'M';
964         prev = 'M';
965       }
966     else // if (isPunctuation(ch))
967
{
968         prev = 'P';
969         continue;
970       }
971     if (wordStart || mode == '_')
972       {
973         if (wordStart && mode == '_' && sbuf.length() > outStart)
974           sbuf.append('_');
975         ch = Character.toUpperCase(ch);
976       }
977     sbuf.append(ch);
978       }
979   }
980   public static String JavaDoc mangle (String JavaDoc name)
981   {
982     StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
983     mangle(name, 0, name.length(), sbuf, 'U');
984     return sbuf.toString();
985   }
986
987   public static String JavaDoc makeClassName (String JavaDoc source)
988   {
989     source = source.replace(java.io.File.separatorChar, '/');
990     int sl = source.lastIndexOf('/');
991     if (sl >= 0)
992       source = source.substring(sl+1);
993     int dot = source.lastIndexOf('.');
994     if (dot >= 0)
995       source = source.substring(0, dot);
996     return Compilation.mangleNameIfNeeded(source);
997   }
998
999   public static Object JavaDoc getExternal (Symbol name, Object JavaDoc type)
1000  {
1001    Environment env = Environment.getCurrent();
1002    Object JavaDoc value = env.get(name, null, null);
1003    if (value == null)
1004      value = env.get(Symbol.makeWithUnknownNamespace(name.getLocalName(),
1005                                                      name.getPrefix()),
1006                      null, null);
1007    if (value == null)
1008      throw new RuntimeException JavaDoc("unbound external "+name);
1009    if (type == null)
1010      return value;
1011    if (type instanceof XDataType)
1012      return ((XDataType) type).cast(value);
1013    if (type instanceof ClassType)
1014      {
1015        String JavaDoc cname = ((ClassType) type).getName();
1016        // KLUDGE - FIXME
1017
if ("gnu.math.IntNum".equals(cname))
1018          return IntNum.valueOf(value.toString());
1019        if ("gnu.math.RealNum".equals(cname))
1020          return gnu.math.DFloNum.make(Double.parseDouble(value.toString()));
1021      }
1022    try
1023      {
1024        value = ((Type) type).coerceFromObject(value);
1025      }
1026    catch (ClassCastException JavaDoc ex)
1027      {
1028        throw new WrongType(name.toString(),
1029                            WrongType.ARG_VARNAME,
1030                            value,
1031                            type.toString());
1032      }
1033    return value;
1034  }
1035}
1036
1037class Prompter extends Procedure1
1038{
1039  public Object JavaDoc apply1 (Object JavaDoc arg)
1040  {
1041    InPort port = (InPort) arg;
1042    int line = port.getLineNumber() + 1;
1043    char state = port.readState;
1044    if (state == '\n')
1045      state = ' ';
1046    if (state == '<')
1047      return "<!--" + line + "-->";
1048    else if (state == ':')
1049      return "-(:" + line + "c:) ";
1050    else
1051      return "(: " + line + state + ":) ";
1052  }
1053}
1054
Popular Tags