001: // Copyright (c) 2003, 2004, 2006 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.xquery.lang;
005:
006: import gnu.expr.*;
007: import gnu.kawa.xml.*;
008: import gnu.xml.*;
009: import gnu.mapping.*;
010: import gnu.bytecode.*;
011: import gnu.kawa.reflect.StaticFieldLocation;
012: import gnu.kawa.functions.GetNamedPart;
013: import gnu.xquery.util.NamedCollator;
014: import gnu.xquery.util.QNameUtils;
015: import java.util.Vector;
016: import gnu.math.DateTime;
017: import gnu.math.IntNum;
018:
019: public class XQResolveNames extends ResolveNames {
020: XQParser parser;
021:
022: /** Code number for the special <code>last</code> function. */
023: public static final int LAST_BUILTIN = -1;
024:
025: /** Code number for the special <code>position</code> function. */
026: public static final int POSITION_BUILTIN = -2;
027:
028: /** Value of {@code xs:QName()} constructor. */
029: public static final int XS_QNAME_BUILTIN = -3;
030:
031: /** Code number for the special <code>compare</code> function. */
032: public static final int COMPARE_BUILTIN = -4;
033:
034: /** Code number for the special <code>distinct-values</code> function. */
035: public static final int DISTINCT_VALUES_BUILTIN = -5;
036:
037: /** Code number for the special <code>local-name</code> function. */
038: public static final int LOCAL_NAME_BUILTIN = -6;
039:
040: /** Code number for the special <code>namespace-uri</code> function. */
041: public static final int NAMESPACE_URI_BUILTIN = -7;
042:
043: /** Code number for the special <code>collection</code> function. */
044: public static final int COLLECTION_BUILTIN = -8;
045:
046: /** Code number for the special <code>doc</code> function. */
047: public static final int DOC_BUILTIN = -9;
048:
049: /** Code number for the special <code>doc-available</code> function. */
050: public static final int DOC_AVAILABLE_BUILTIN = -10;
051:
052: /** Code number for the special <code>doc-available</code> function. */
053: public static final int BASE_URI_BUILTIN = -11;
054:
055: /** Code number for the special <code>ressolve-uri</code> function. */
056: public static final int RESOLVE_URI_BUILTIN = -12;
057:
058: /** Code number for internal function that maps prefix to uri. */
059: public static final int RESOLVE_PREFIX_BUILTIN = -13;
060:
061: /** Code number for the special <code>static-base-uri</code> function. */
062: public static final int STATIC_BASE_URI_BUILTIN = -14;
063:
064: /** Code number for the special <code>index-of</code> function. */
065: public static final int INDEX_OF_BUILTIN = -15;
066:
067: /** Code number for the special <code>string</code> function. */
068: public static final int STRING_BUILTIN = -16;
069:
070: /** Code number for the special <code>normalize-space</code> function. */
071: public static final int NORMALIZE_SPACE_BUILTIN = -17;
072:
073: /** Code number for the special <code>unordered</code> function. */
074: public static final int UNORDERED_BUILTIN = -18;
075:
076: /** Code number for the special <code>lang</code> function. */
077: public static final int LANG_BUILTIN = -23;
078:
079: /** Code number for the special <code>name</code> function. */
080: public static final int NAME_BUILTIN = -24;
081:
082: /** Code number for the special <code>deep-equal</code> function. */
083: public static final int DEEP_EQUAL_BUILTIN = -25;
084:
085: /** Code number for the special <code>min</code> function. */
086: public static final int MIN_BUILTIN = -26;
087:
088: /** Code number for the special <code>max</code> function. */
089: public static final int MAX_BUILTIN = -27;
090:
091: /** Code number for the special <code>number</code> function. */
092: public static final int NUMBER_BUILTIN = -28;
093:
094: /** Code number for the special <code>default-collation</code> function. */
095: public static final int DEFAULT_COLLATION_BUILTIN = -29;
096:
097: /** Code number for the special <code>id</code> function. */
098: public static final int ID_BUILTIN = -30;
099:
100: /** Code number for the special <code>idref</code> function. */
101: public static final int IDREF_BUILTIN = -31;
102:
103: /** Code number for the special <code>root</code> function. */
104: public static final int ROOT_BUILTIN = -32;
105:
106: public static final int CAST_AS_BUILTIN = -33;
107: public static final int CASTABLE_AS_BUILTIN = -34;
108:
109: /** Code number for internal function to handle extensions. */
110: public static final int HANDLE_EXTENSION_BUILTIN = -35;
111:
112: public static final Declaration handleExtensionDecl = makeBuiltin(
113: "(extension)", HANDLE_EXTENSION_BUILTIN);
114:
115: public static final Declaration castAsDecl = makeBuiltin(
116: "(cast as)", CAST_AS_BUILTIN);
117:
118: public static final Declaration castableAsDecl = makeBuiltin(
119: "(castable as)", CASTABLE_AS_BUILTIN);
120:
121: /** Declaration for the <code>fn:last()</code> function. */
122: public static final Declaration lastDecl = makeBuiltin("last",
123: LAST_BUILTIN);
124:
125: public static final Declaration xsQNameDecl = makeBuiltin(Symbol
126: .make(XQuery.SCHEMA_NAMESPACE, "QName"), XS_QNAME_BUILTIN);
127:
128: public static final Declaration staticBaseUriDecl = makeBuiltin(
129: "static-base-uri", STATIC_BASE_URI_BUILTIN);
130:
131: public static final Declaration resolvePrefixDecl = makeBuiltin(
132: Symbol.make(XQuery.SCHEMA_NAMESPACE, "(resolve-prefix)"),
133: RESOLVE_PREFIX_BUILTIN);
134:
135: /** Create a <code>Declaration</code> for a builtin function. */
136: public static Declaration makeBuiltin(String name, int code) {
137: return makeBuiltin(Symbol.make(
138: XQuery.XQUERY_FUNCTION_NAMESPACE, name, "fn"), code);
139: }
140:
141: /** Create a <code>Declaration</code> for a builtin function. */
142: public static Declaration makeBuiltin(Symbol name, int code) {
143: Declaration decl = new Declaration(name);
144: decl.setProcedureDecl(true);
145: decl.setCode(code);
146: return decl;
147: }
148:
149: public XQResolveNames() {
150: this (null);
151: }
152:
153: void pushBuiltin(String name, int code) {
154: lookup.push(makeBuiltin(name, code));
155: }
156:
157: public XQResolveNames(Compilation comp) {
158: super (comp);
159: lookup.push(lastDecl);
160: lookup.push(xsQNameDecl);
161: lookup.push(staticBaseUriDecl);
162: pushBuiltin("position", POSITION_BUILTIN);
163: pushBuiltin("compare", COMPARE_BUILTIN);
164: pushBuiltin("distinct-values", DISTINCT_VALUES_BUILTIN);
165: pushBuiltin("local-name", LOCAL_NAME_BUILTIN);
166: pushBuiltin("name", NAME_BUILTIN);
167: pushBuiltin("namespace-uri", NAMESPACE_URI_BUILTIN);
168: pushBuiltin("root", ROOT_BUILTIN);
169: pushBuiltin("base-uri", BASE_URI_BUILTIN);
170: pushBuiltin("lang", LANG_BUILTIN);
171: pushBuiltin("resolve-uri", RESOLVE_URI_BUILTIN);
172: pushBuiltin("collection", COLLECTION_BUILTIN);
173: pushBuiltin("doc", DOC_BUILTIN);
174: pushBuiltin("document", DOC_BUILTIN); // Obsolete
175: pushBuiltin("doc-available", DOC_AVAILABLE_BUILTIN);
176: pushBuiltin("index-of", INDEX_OF_BUILTIN);
177: pushBuiltin("string", STRING_BUILTIN);
178: pushBuiltin("normalize-space", NORMALIZE_SPACE_BUILTIN);
179: pushBuiltin("unordered", UNORDERED_BUILTIN);
180: pushBuiltin("deep-equal", DEEP_EQUAL_BUILTIN);
181: pushBuiltin("min", MIN_BUILTIN);
182: pushBuiltin("max", MAX_BUILTIN);
183: pushBuiltin("number", NUMBER_BUILTIN);
184: pushBuiltin("default-collation", DEFAULT_COLLATION_BUILTIN);
185: pushBuiltin("id", ID_BUILTIN);
186: pushBuiltin("idref", IDREF_BUILTIN);
187: }
188:
189: public Namespace[] functionNamespacePath = XQuery.defaultFunctionNamespacePath;
190:
191: protected void push(ScopeExp exp) {
192: for (Declaration decl = exp.firstDecl(); decl != null; decl = decl
193: .nextDecl()) {
194: push(decl);
195: }
196: }
197:
198: void push(Declaration decl) {
199: Compilation comp = getCompilation();
200: Object name = decl.getSymbol();
201: boolean function = decl.isProcedureDecl();
202: if (name instanceof String) {
203: int line = decl.getLineNumber();
204: if (line > 0 && comp != null) {
205: String saveFilename = comp.getFileName();
206: int saveLine = comp.getLineNumber();
207: int saveColumn = comp.getColumnNumber();
208: comp.setLocation(decl);
209: name = parser.namespaceResolve((String) name, function);
210: comp.setLine(saveFilename, saveLine, saveColumn);
211: } else
212: name = parser.namespaceResolve((String) name, function);
213: if (name == null)
214: return;
215: decl.setName(name);
216: }
217:
218: Declaration old = lookup.lookup(name, XQuery.instance
219: .getNamespaceOf(decl));
220: if (old != null) {
221: if (decl.context == old.context)
222: ScopeExp.duplicateDeclarationError(old, decl, comp);
223: else if (XQParser.warnHidePreviousDeclaration
224: && (!(name instanceof Symbol) || ((Symbol) name)
225: .getNamespace() != null))
226: comp.error('w', decl, "declaration ",
227: " hides previous declaration");
228: }
229: lookup.push(decl);
230: }
231:
232: Declaration flookup(Symbol sym) {
233: Environment env = XQuery.xqEnvironment;
234: gnu.mapping.Location loc = env.lookup(sym,
235: EnvironmentKey.FUNCTION);
236: if (loc == null)
237: return null;
238: loc = loc.getBase();
239: if (loc instanceof StaticFieldLocation) {
240: Declaration decl = ((StaticFieldLocation) loc)
241: .getDeclaration();
242: if (decl != null)
243: return decl;
244: }
245: Object val = loc.get(null);
246: if (val != null)
247: return procToDecl(sym, val);
248: return null;
249: }
250:
251: protected Expression walkReferenceExp(ReferenceExp exp) {
252: return walkReferenceExp(exp, null);
253: }
254:
255: protected Expression walkReferenceExp(ReferenceExp exp,
256: ApplyExp call) {
257: if (exp.getBinding() == null) {
258: Object symbol = exp.getSymbol();
259: boolean function = exp.isProcedureName();
260: int namespace = call == null ? XQuery.VALUE_NAMESPACE
261: : XQuery.namespaceForFunctions(call.getArgCount());
262: Declaration decl = lookup.lookup(symbol, namespace);
263: Symbol sym;
264: if (decl != null)
265: ;
266: else if (symbol instanceof Symbol
267: && "".equals((sym = (Symbol) symbol)
268: .getNamespaceURI())) {
269: // kludge - use xxx_BUILTIN mechanism? FIXME
270: String name = sym.getLocalName();
271: Expression f;
272: if ("request".equals(name))
273: f = XQParser
274: .makeFunctionExp(
275: "gnu.kawa.servlet.GetRequest",
276: "getRequest");
277: else if ("response".equals(name))
278: f = XQParser.makeFunctionExp(
279: "gnu.kawa.servlet.GetResponse",
280: "getResponse");
281: else
282: f = null;
283: if (f != null)
284: return new ApplyExp(f, Expression.noExpressions);
285: } else if (symbol instanceof Symbol) {
286: // Never happens, I believe.
287: decl = flookup((Symbol) symbol);
288: } else // if (symbol instanceof String)
289: {
290: String name = (String) symbol;
291: if (name.indexOf(':') < 0) {
292: name = name.intern();
293: if (function) {
294: for (int i = 0; i < functionNamespacePath.length; i++) {
295: sym = functionNamespacePath[i]
296: .getSymbol(name);
297: decl = lookup.lookup(sym, function);
298: if (decl != null)
299: break;
300: if (!function)
301: continue;
302: decl = flookup(sym);
303: if (decl != null)
304: break;
305: }
306: }
307: }
308: if (decl == null) {
309: sym = parser.namespaceResolve(name, function);
310: if (sym != null) {
311: decl = lookup.lookup(sym, namespace);
312: if (decl == null && function) {
313: String uri = sym.getNamespaceURI();
314: if (XQuery.SCHEMA_NAMESPACE.equals(uri)) {
315: Type type = XQuery.getStandardType(sym
316: .getName());
317: if (type != null)
318: return QuoteExp.getInstance(type);
319: }
320: if (uri != null && uri.length() > 6
321: && uri.startsWith("class:")) {
322: ClassType ctype = ClassType.make(uri
323: .substring(6));
324: return GetNamedPart.makeExp(ctype, sym
325: .getName());
326: }
327: decl = flookup(sym);
328: }
329: }
330: }
331: }
332: if (decl != null)
333: exp.setBinding(decl);
334: else if (function)
335: error('e', "unknown function " + symbol);
336: else
337: messages.error('e', "unknown variable $" + symbol,
338: "XPST0008");
339: }
340: return exp;
341: }
342:
343: protected Expression walkSetExp(SetExp exp) {
344: Expression result = super .walkSetExp(exp);
345: Declaration decl = exp.getBinding();
346: Object name;
347: Expression new_value;
348: if (decl != null
349: && !getCompilation().immediate
350: && (name = decl.getSymbol()) instanceof Symbol
351: && XQuery.LOCAL_NAMESPACE.equals(((Symbol) name)
352: .getNamespaceURI())
353: && (!((new_value = exp.getNewValue()) instanceof ApplyExp) || ((ApplyExp) new_value)
354: .getFunction() != XQParser.getExternalFunction)) {
355: decl.setFlag(Declaration.PRIVATE_SPECIFIED);
356: decl.setPrivate(true);
357: }
358: return result;
359: }
360:
361: private Declaration moduleDecl;
362:
363: private Expression walkStatements(Expression exp) {
364: // The tricky part here is interleaving declarations and statements
365: // so that a variable declaration is only visible *after* we have
366: // walked its initializing expression.
367: if (exp instanceof BeginExp) {
368: BeginExp bbody = (BeginExp) exp;
369: Expression[] exps = bbody.getExpressions();
370: int nexps = bbody.getExpressionCount();
371: for (int i = 0; i < nexps; i++) {
372: exps[i] = walkStatements(exps[i]);
373: }
374: } else if (exp instanceof SetExp) {
375: Declaration decl = moduleDecl;
376: SetExp sexp = (SetExp) exp;
377: exp = walkSetExp(sexp);
378: if (sexp.isDefining() && sexp.getBinding() == decl) {
379: if (!decl.isProcedureDecl())
380: push(decl);
381: decl = decl.nextDecl();
382: }
383: moduleDecl = decl;
384: } else
385: exp = walk(exp);
386: return exp;
387: }
388:
389: public void resolveModule(ModuleExp exp) {
390: currentLambda = exp;
391: for (Declaration decl = exp.firstDecl(); decl != null; decl = decl
392: .nextDecl()) {
393: if (decl.isProcedureDecl())
394: push(decl);
395: }
396: moduleDecl = exp.firstDecl();
397: exp.body = walkStatements(exp.body);
398: }
399:
400: /**
401: * Coerce argument to NamedCallator, or return default collator.
402: * @param args argument list
403: * @param argno index in args of collator argument
404: */
405: Expression getCollator(Expression[] args, int argno) {
406: if (args != null && args.length > argno)
407: return new ApplyExp(ClassType.make(
408: "gnu.xquery.util.NamedCollator").getDeclaredMethod(
409: "find", 1), new Expression[] { args[argno] });
410: NamedCollator coll = parser.defaultCollator;
411: return coll == null ? QuoteExp.nullExp : new QuoteExp(coll);
412: }
413:
414: Expression withCollator(Method method, Expression[] args,
415: String name, int minArgs) {
416: return withCollator(new QuoteExp(new PrimProcedure(method)),
417: args, name, minArgs);
418: }
419:
420: /** Adjust call to add default collator if collator argument is missing. */
421: Expression withCollator(Expression function, Expression[] args,
422: String name, int minArgs) {
423: String err = WrongArguments.checkArgCount(name, minArgs,
424: minArgs + 1, args.length);
425: if (err != null)
426: return getCompilation().syntaxError(err);
427: Expression[] xargs = new Expression[minArgs + 1];
428: System.arraycopy(args, 0, xargs, 0, minArgs);
429: xargs[minArgs] = getCollator(args, minArgs);
430: return new ApplyExp(function, xargs);
431: }
432:
433: /** Adjust call to add default contex itemt if that argument is missing. */
434: Expression withContext(Method method, Expression[] args,
435: String name, int minArgs) {
436: String err = WrongArguments.checkArgCount(name, minArgs,
437: minArgs + 1, args.length);
438: if (err != null)
439: return getCompilation().syntaxError(err);
440: if (args.length == minArgs) {
441: Expression[] xargs = new Expression[minArgs + 1];
442: System.arraycopy(args, 0, xargs, 0, minArgs);
443: Declaration dot = lookup
444: .lookup(XQParser.DOT_VARNAME, false);
445: if (dot == null) {
446: String message = "undefined context for " + name;
447: messages.error('e', message, "XPDY0002");
448: return new ErrorExp(message);
449: }
450: xargs[minArgs] = new ReferenceExp(dot);
451: args = xargs;
452: }
453: return new ApplyExp(method, args);
454: }
455:
456: private Expression checkArgCount(Expression[] args,
457: Declaration decl, int min, int max) {
458: String err = WrongArguments.checkArgCount("fn:"
459: + decl.getName(), min, max, args.length);
460: if (err == null)
461: return null;
462: else
463: return getCompilation().syntaxError(err);
464: }
465:
466: protected Expression walkApplyExp(ApplyExp exp) {
467: Expression func = exp.getFunction();
468: NamespaceBinding namespaceSave = parser.constructorNamespaces;
469: Object proc = exp.getFunctionValue();
470: if (proc instanceof MakeElement) {
471: MakeElement mk = (MakeElement) proc;
472: NamespaceBinding nschain = NamespaceBinding.nconc(mk
473: .getNamespaceNodes(), namespaceSave);
474: mk.setNamespaceNodes(nschain);
475: parser.constructorNamespaces = nschain;
476: }
477: if (func instanceof ReferenceExp)
478: func = walkReferenceExp((ReferenceExp) func, exp);
479: else
480: func = walk(func);
481: exp.setFunction(func);
482: walkExps(exp.getArgs());
483: parser.constructorNamespaces = namespaceSave;
484: func = exp.getFunction();
485: if (func instanceof ReferenceExp) {
486: Declaration decl = ((ReferenceExp) func).getBinding();
487: int code;
488: Expression err;
489: ModuleExp mexp;
490: if (decl != null && (code = decl.getCode()) < 0) {
491: switch (code) {
492: case POSITION_BUILTIN:
493: case LAST_BUILTIN:
494: Symbol sym = code == LAST_BUILTIN ? XQParser.LAST_VARNAME
495: : XQParser.POSITION_VARNAME;
496: decl = lookup.lookup(sym, false);
497: if (decl == null)
498: error('e', "undefined context for "
499: + sym.getName());
500: else
501: // So ValuesFilter.inline can tell whether last() is used.
502: decl.setCanRead(true);
503: return new ReferenceExp(sym, decl);
504: case CAST_AS_BUILTIN: {
505: Expression[] args = exp.getArgs();
506: if (args[0].valueIfConstant() == Compilation.typeSymbol)
507: return walkApplyExp(XQParser.castQName(args[1]));
508: func = XQParser.makeFunctionExp(
509: "gnu.xquery.util.CastAs", "castAs");
510: return new ApplyExp(func, args);
511: }
512: case CASTABLE_AS_BUILTIN: {
513: Expression[] args = exp.getArgs();
514: if (args[1].valueIfConstant() == Compilation.typeSymbol
515: && args[0] instanceof QuoteExp) {
516: Object value = ((QuoteExp) args[0]).getValue();
517: try {
518: QNameUtils.resolveQName(value,
519: parser.constructorNamespaces,
520: parser.prologNamespaces);
521: return XQuery.trueExp;
522: } catch (RuntimeException ex) {
523: return XQuery.falseExp;
524: }
525: }
526: func = XQParser.makeFunctionExp(
527: "gnu.xquery.lang.XQParser", "castableAs");
528: return new ApplyExp(func, args);
529: }
530: case XS_QNAME_BUILTIN: {
531: Expression[] args = exp.getArgs();
532: if ((err = checkArgCount(args, decl, 1, 1)) != null)
533: return err;
534: if (args[0] instanceof QuoteExp) {
535: try {
536: Object val = ((QuoteExp) args[0])
537: .getValue();
538: val = QNameUtils.resolveQName(val,
539: parser.constructorNamespaces,
540: parser.prologNamespaces);
541: return new QuoteExp(val);
542: } catch (RuntimeException ex) {
543: return getCompilation().syntaxError(
544: ex.getMessage());
545: }
546: }
547: Expression[] xargs = { args[0],
548: new QuoteExp(parser.constructorNamespaces),
549: new QuoteExp(parser.prologNamespaces) };
550: Method meth = (ClassType
551: .make("gnu.xquery.util.QNameUtils")
552: .getDeclaredMethod("resolveQName", 3));
553: ApplyExp app = new ApplyExp(meth, xargs);
554: app.setFlag(ApplyExp.INLINE_IF_CONSTANT);
555: return app;
556: }
557: case RESOLVE_PREFIX_BUILTIN: {
558: Expression[] args = exp.getArgs();
559: if ((err = checkArgCount(args, decl, 1, 1)) != null)
560: return err;
561: if (args[0] instanceof QuoteExp) {
562: Object val = ((QuoteExp) args[0]).getValue();
563: String prefix = val == null ? null : val
564: .toString();
565: val = QNameUtils.lookupPrefix(prefix,
566: parser.constructorNamespaces,
567: parser.prologNamespaces);
568: if (val == null)
569: return getCompilation().syntaxError(
570: "unknown namespace prefix '"
571: + prefix + "'");
572: return new QuoteExp(val);
573: }
574: Expression[] xargs = { args[0],
575: new QuoteExp(parser.constructorNamespaces),
576: new QuoteExp(parser.prologNamespaces) };
577: PrimProcedure pproc = new PrimProcedure(ClassType
578: .make("gnu.xquery.util.QNameUtils")
579: .getDeclaredMethod("resolvePrefix", 3));
580: ApplyExp app = new ApplyExp(pproc, xargs);
581: app.setFlag(ApplyExp.INLINE_IF_CONSTANT);
582: return app;
583: }
584: case LOCAL_NAME_BUILTIN: {
585: Method meth = ClassType.make(
586: "gnu.xquery.util.NodeUtils")
587: .getDeclaredMethod("localName", 1);
588: return withContext(meth, exp.getArgs(),
589: "fn:local-name", 0);
590: }
591: case NAME_BUILTIN: {
592: Method meth = ClassType.make(
593: "gnu.xquery.util.NodeUtils")
594: .getDeclaredMethod("name", 1);
595: return withContext(meth, exp.getArgs(), "fn:name",
596: 0);
597: }
598: case NUMBER_BUILTIN: {
599: Method meth = ClassType.make(
600: "gnu.xquery.util.NumberValue")
601: .getDeclaredMethod("numberValue", 1);
602: return withContext(meth, exp.getArgs(),
603: "fn:number", 0);
604: }
605: case ROOT_BUILTIN: {
606: Method meth = ClassType.make(
607: "gnu.xquery.util.NodeUtils")
608: .getDeclaredMethod("root", 1);
609: return withContext(meth, exp.getArgs(), "fn:root",
610: 0);
611: }
612: case BASE_URI_BUILTIN: {
613: Method meth = ClassType.make(
614: "gnu.xquery.util.NodeUtils")
615: .getDeclaredMethod("baseUri", 1);
616: return withContext(meth, exp.getArgs(),
617: "fn:base-uri", 0);
618: }
619: case LANG_BUILTIN: {
620: Method meth = ClassType.make(
621: "gnu.xquery.util.NodeUtils")
622: .getDeclaredMethod("lang", 2);
623: return withContext(meth, exp.getArgs(), "fn:lang",
624: 1);
625: }
626: case ID_BUILTIN: {
627: Method meth = ClassType.make(
628: "gnu.xquery.util.NodeUtils")
629: .getDeclaredMethod("id$X", 3);
630: return withContext(meth, exp.getArgs(), "fn:id", 1);
631: }
632: case IDREF_BUILTIN: {
633: Method meth = ClassType.make(
634: "gnu.xquery.util.NodeUtils")
635: .getDeclaredMethod("idref", 2);
636: return withContext(meth, exp.getArgs(), "fn:idref",
637: 1);
638: }
639:
640: case STATIC_BASE_URI_BUILTIN: {
641: Expression[] args = exp.getArgs();
642: if ((err = checkArgCount(args, decl, 0, 0)) != null)
643: return err;
644: return getBaseUriExpr();
645: }
646: case NAMESPACE_URI_BUILTIN: {
647: Method meth = ClassType.make(
648: "gnu.xquery.util.NodeUtils")
649: .getDeclaredMethod("namespaceURI", 1);
650: return withContext(meth, exp.getArgs(),
651: "fn:namespace-uri", 0);
652: }
653:
654: case NORMALIZE_SPACE_BUILTIN: {
655: Method meth = ClassType.make(
656: "gnu.xquery.util.StringUtils")
657: .getDeclaredMethod("normalizeSpace", 1);
658: return withContext(meth, exp.getArgs(),
659: "fn:normalize-space", 0);
660: }
661:
662: case UNORDERED_BUILTIN: {
663: Expression[] args = exp.getArgs();
664: if ((err = checkArgCount(args, decl, 1, 1)) != null)
665: return err;
666: return args[0];
667: }
668:
669: case COMPARE_BUILTIN: {
670: Method meth = ClassType.make(
671: "gnu.xquery.util.StringUtils")
672: .getDeclaredMethod("compare", 3);
673: return withCollator(meth, exp.getArgs(),
674: "fn:compare", 2);
675: }
676:
677: case STRING_BUILTIN:
678: return withContext(ClassType.make(
679: "gnu.xml.TextUtils").getDeclaredMethod(
680: "asString", 1), exp.getArgs(), "fn:string",
681: 0);
682:
683: case INDEX_OF_BUILTIN: {
684: Method meth = ClassType.make(
685: "gnu.xquery.util.SequenceUtils")
686: .getDeclaredMethod("indexOf$X", 4);
687: return withCollator(meth, exp.getArgs(),
688: "fn:index-of", 2);
689: }
690: case COLLECTION_BUILTIN: {
691: Expression[] args = exp.getArgs();
692: ClassType cl = ClassType
693: .make("gnu.xquery.util.NodeUtils");
694: Method meth = cl.getDeclaredMethod("collection", 2);
695: if ((err = checkArgCount(args, decl, 0, 1)) != null)
696: return err;
697: Expression base = getBaseUriExpr();
698: Expression uri = args.length > 0 ? args[0]
699: : QuoteExp.voidExp;
700: ApplyExp aexp = new ApplyExp(meth,
701: new Expression[] { uri, base });
702: if (code == DOC_BUILTIN)
703: aexp.setType(NodeType.documentNodeTest);
704: else
705: aexp.setType(XDataType.booleanType);
706: return aexp;
707: }
708: case DOC_BUILTIN:
709: case DOC_AVAILABLE_BUILTIN: {
710: Expression[] args = exp.getArgs();
711: ClassType cl = ClassType
712: .make("gnu.xquery.util.NodeUtils");
713: String mname;
714: if (code == DOC_BUILTIN) {
715: mname = "docCached";
716: if (parser.warnOldVersion
717: && "document".equals(decl.getName()))
718: getCompilation().error('w',
719: "replace 'document' by 'doc'");
720: } else
721: mname = "availableCached";
722: Method meth = cl.getDeclaredMethod(mname, 2);
723: if ((err = checkArgCount(args, decl, 1, 1)) != null)
724: return err;
725: Expression base = getBaseUriExpr();
726: ApplyExp aexp = new ApplyExp(meth,
727: new Expression[] { args[0], base });
728: if (code == DOC_BUILTIN)
729: aexp.setType(NodeType.documentNodeTest);
730: else
731: aexp.setType(XDataType.booleanType);
732: return aexp;
733: }
734: case RESOLVE_URI_BUILTIN: {
735: Expression[] args = exp.getArgs();
736: if ((err = checkArgCount(args, decl, 1, 2)) != null)
737: return err;
738: Expression[] margs = new Expression[2];
739: margs[0] = args[0];
740: if (args.length == 1)
741: margs[1] = getBaseUriExpr();
742: else
743: margs[1] = args[1];
744: Method meth = ClassType.make(
745: "gnu.xquery.util.QNameUtils")
746: .getDeclaredMethod("resolveURI", 2);
747: return new ApplyExp(meth, margs);
748: }
749: case DISTINCT_VALUES_BUILTIN: {
750: Method meth = ClassType.make(
751: "gnu.xquery.util.DistinctValues")
752: .getDeclaredMethod("distinctValues$X", 3);
753: return withCollator(meth, exp.getArgs(),
754: "fn:distinct-values", 1);
755:
756: }
757: case DEEP_EQUAL_BUILTIN: {
758: Method meth = ClassType.make(
759: "gnu.xquery.util.SequenceUtils")
760: .getDeclaredMethod("deepEqual", 3);
761: return withCollator(meth, exp.getArgs(),
762: "fn:deep-equal", 2);
763: }
764: case MIN_BUILTIN: {
765: Method meth = ClassType.make(
766: "gnu.xquery.util.MinMax")
767: .getDeclaredMethod("min", 2);
768: return withCollator(meth, exp.getArgs(), "fn:min",
769: 1);
770: }
771: case MAX_BUILTIN: {
772: Method meth = ClassType.make(
773: "gnu.xquery.util.MinMax")
774: .getDeclaredMethod("max", 2);
775: return withCollator(meth, exp.getArgs(), "fn:max",
776: 1);
777: }
778: case DEFAULT_COLLATION_BUILTIN:
779: if ((err = checkArgCount(exp.getArgs(), decl, 0, 0)) != null)
780: return err;
781: NamedCollator coll = parser.defaultCollator;
782: return QuoteExp
783: .getInstance(coll != null ? coll.getName()
784: : NamedCollator.UNICODE_CODEPOINT_COLLATION);
785: case HANDLE_EXTENSION_BUILTIN: {
786: Compilation comp = getCompilation();
787: Expression[] args = exp.getArgs();
788: int i = 0;
789: for (; i < args.length - 1; i += 2) {
790: Expression pname = args[i];
791: String qname = (String) ((QuoteExp) pname)
792: .getValue();
793: Symbol psymbol = parser.namespaceResolve(qname,
794: false);
795: if (psymbol == null)
796: ; // error emitted in namespaceResolve
797: else if (psymbol.getNamespaceURI().length() == 0)
798: comp
799: .error('e',
800: "pragma name cannot be in the empty namespace");
801: else {
802: Expression replacement = checkPragma(
803: psymbol, args[i + 1]);
804: if (replacement != null)
805: return replacement;
806: }
807: }
808: if (i < args.length)
809: return args[args.length - 1];
810: String msg = "no recognized pragma or default in extension expression";
811: getMessages().error('e', msg, "XQST0079");
812: return new ErrorExp(msg);
813: }
814: }
815: }
816: }
817: proc = exp.getFunctionValue();
818: if (proc instanceof Type) {
819: Expression[] args = exp.getArgs();
820: if (args.length != 1) {
821: messages.error('e',
822: "type constructor requires a single argument");
823: return exp;
824: }
825: return new ApplyExp(XQParser.makeFunctionExp(
826: "gnu.xquery.util.CastAs", "castAs"),
827: new Expression[] { exp.getFunction(), args[0] });
828: }
829: if (proc instanceof MakeElement) {
830: MakeElement make = (MakeElement) proc;
831:
832: // Add namespaces nodes that might be needed.
833: NamespaceBinding nsBindings = make.getNamespaceNodes();
834: nsBindings = maybeAddNamespace(MakeElement.getTagName(exp),
835: nsBindings);
836: Expression[] args = exp.getArgs();
837: Symbol[] attrSyms = new Symbol[args.length];
838: int nattrSyms = 0;
839: for (int i = 0; i < args.length; i++) {
840: Expression arg = args[i];
841: if (arg instanceof ApplyExp) {
842: ApplyExp app = (ApplyExp) arg;
843: if (app.getFunction() == MakeAttribute.makeAttributeExp) {
844: Symbol sym = MakeElement.getTagName(app);
845: if (sym != null) {
846: for (int j = 0;; j++) {
847: if (j == nattrSyms) {
848: attrSyms[nattrSyms++] = sym;
849: break;
850: }
851: if (sym.equals(attrSyms[j])) {
852: getCompilation().setLine(app);
853: Symbol elementSym = MakeElement
854: .getTagName(exp);
855: String elementName = elementSym == null ? null
856: : elementSym.toString();
857: messages.error('e', XMLFilter
858: .duplicateAttributeMessage(
859: sym, elementName),
860: "XQST0040");
861: }
862: }
863: }
864: nsBindings = maybeAddNamespace(sym, nsBindings);
865: }
866: }
867: }
868: if (nsBindings != null)
869: make.setNamespaceNodes(nsBindings);
870: }
871: return exp;
872: }
873:
874: public Expression checkPragma(Symbol name, Expression contents) {
875: return null;
876: }
877:
878: Expression getBaseUriExpr() {
879: Compilation comp = getCompilation();
880: String staticBaseUri = parser.getStaticBaseUri();
881: if (staticBaseUri != null)
882: return QuoteExp.getInstance(staticBaseUri);
883: else
884: return gnu.kawa.functions.GetModuleClass
885: .getModuleClassURI(comp);
886: }
887:
888: static NamespaceBinding maybeAddNamespace(Symbol qname,
889: NamespaceBinding bindings) {
890: if (qname == null) // Happens if prevously-reported unknown prefix.
891: return bindings;
892: String prefix = qname.getPrefix();
893: String uri = qname.getNamespaceURI();
894: return NamespaceBinding.maybeAdd(prefix == "" ? null : prefix,
895: uri == "" ? null : uri, bindings);
896: }
897:
898: /** Wrap a (known) procedure value as a Declaration. */
899: static Declaration procToDecl(Object symbol, Object val) {
900: Declaration decl = new Declaration(symbol);
901: decl.setProcedureDecl(true);
902: decl.noteValue(new QuoteExp(val));
903: decl.setFlag(Declaration.IS_CONSTANT);
904: return decl;
905: }
906: }
|