1 // Copyright (c) 2003, 2004, 2006 Per M.A. Bothner. 2 // This is free software; for terms and warranty disclaimer see ./COPYING. 3 4 package gnu.xquery.lang; 5 import gnu.expr.*; 6 import gnu.kawa.xml.*; 7 import gnu.xml.*; 8 import gnu.mapping.*; 9 import gnu.bytecode.*; 10 import gnu.kawa.reflect.StaticFieldLocation; 11 import gnu.kawa.reflect.SingletonType; 12 import gnu.kawa.functions.CompileNamedPart; 13 import gnu.xquery.util.NamedCollator; 14 import gnu.xquery.util.QNameUtils; 15 import java.util.*; 16 17 public class XQResolveNames extends ResolveNames 18 { 19 public XQParser parser; 20 21 /** Code number for the special <code>last</code> function. */ 22 public static final int LAST_BUILTIN = -1; 23 24 /** Code number for the special <code>position</code> function. */ 25 public static final int POSITION_BUILTIN = -2; 26 27 /** Code number for internal function to handle extensions. */ 28 public static final int HANDLE_EXTENSION_BUILTIN = -3; 29 30 /** Code number for the special <code>compare</code> function. */ 31 public static final int COMPARE_BUILTIN = -4; 32 33 /** Code number for the special <code>distinct-values</code> function. */ 34 public static final int DISTINCT_VALUES_BUILTIN = -5; 35 36 /** Code number for the special <code>local-name</code> function. */ 37 public static final int LOCAL_NAME_BUILTIN = -6; 38 39 /** Code number for the special <code>namespace-uri</code> function. */ 40 public static final int NAMESPACE_URI_BUILTIN = -7; 41 42 /** Code number for the special <code>collection</code> function. */ 43 public static final int COLLECTION_BUILTIN = -8; 44 45 /** Code number for the special <code>doc</code> function. */ 46 public static final int DOC_BUILTIN = -9; 47 48 /** Code number for the special <code>doc-available</code> function. */ 49 public static final int DOC_AVAILABLE_BUILTIN = -10; 50 51 /** Code number for the special <code>base-uri</code> function. */ 52 public static final int BASE_URI_BUILTIN = -11; 53 54 /** Code number for the special <code>ressolve-uri</code> function. */ 55 public static final int RESOLVE_URI_BUILTIN = -12; 56 57 /** Code number for internal function that maps prefix to uri. */ 58 public static final int RESOLVE_PREFIX_BUILTIN = -13; 59 60 /** Code number for the special <code>static-base-uri</code> function. */ 61 public static final int STATIC_BASE_URI_BUILTIN = -14; 62 63 /** Code number for the special <code>index-of</code> function. */ 64 public static final int INDEX_OF_BUILTIN = -15; 65 66 /** Code number for the special <code>string</code> function. */ 67 public static final int STRING_BUILTIN = -16; 68 69 /** Code number for the special <code>normalize-space</code> function. */ 70 public static final int NORMALIZE_SPACE_BUILTIN = -17; 71 72 /** Code number for the special <code>unordered</code> function. */ 73 public static final int UNORDERED_BUILTIN = -18; 74 75 /** Code number for the special <code>lang</code> function. */ 76 public static final int LANG_BUILTIN = -23; 77 78 /** Code number for the special <code>name</code> function. */ 79 public static final int NAME_BUILTIN = -24; 80 81 /** Code number for the special <code>deep-equal</code> function. */ 82 public static final int DEEP_EQUAL_BUILTIN = -25; 83 84 /** Code number for the special <code>min</code> function. */ 85 public static final int MIN_BUILTIN = -26; 86 87 /** Code number for the special <code>max</code> function. */ 88 public static final int MAX_BUILTIN = -27; 89 90 /** Code number for the special <code>number</code> function. */ 91 public static final int NUMBER_BUILTIN = -28; 92 93 /** Code number for the special <code>default-collation</code> function. */ 94 public static final int DEFAULT_COLLATION_BUILTIN = -29; 95 96 /** Code number for the special <code>id</code> function. */ 97 public static final int ID_BUILTIN = -30; 98 99 /** Code number for the special <code>idref</code> function. */ 100 public static final int IDREF_BUILTIN = -31; 101 102 /** Code number for the special <code>root</code> function. */ 103 public static final int ROOT_BUILTIN = -32; 104 105 public static final int CAST_AS_BUILTIN = -33; 106 public static final int CASTABLE_AS_BUILTIN = -34; 107 108 /** Value of {@code xs:QName()} constructor. */ 109 public static final int XS_QNAME_BUILTIN = -35; 110 111 /** Like {@code XS_QNAME_BUILTIN}, but ignore the default 112 * element namespace. The is appropriate fro resolving atributes. */ 113 public static final int XS_QNAME_IGNORE_DEFAULT_BUILTIN = -36; 114 115 public static final Declaration handleExtensionDecl 116 = makeBuiltin("(extension)", HANDLE_EXTENSION_BUILTIN); 117 118 public static final Declaration castAsDecl 119 = makeBuiltin("(cast as)", CAST_AS_BUILTIN); 120 121 public static final Declaration castableAsDecl 122 = makeBuiltin("(castable as)", CASTABLE_AS_BUILTIN); 123 124 /** Declaration for the <code>fn:last()</code> function. */ 125 public static final Declaration lastDecl 126 = makeBuiltin("last", LAST_BUILTIN); 127 128 public static final Declaration xsQNameDecl 129 = makeBuiltin(Symbol.make(XQuery.SCHEMA_NAMESPACE, "QName"), XS_QNAME_BUILTIN); 130 131 public static final Declaration xsQNameIgnoreDefaultDecl 132 = makeBuiltin(Symbol.make(XQuery.SCHEMA_NAMESPACE, "(QName-ignore-default)"), XS_QNAME_IGNORE_DEFAULT_BUILTIN); 133 134 public static final Declaration staticBaseUriDecl 135 = makeBuiltin("static-base-uri", STATIC_BASE_URI_BUILTIN); 136 137 public static final Declaration resolvePrefixDecl 138 = makeBuiltin(Symbol.make(XQuery.SCHEMA_NAMESPACE, "(resolve-prefix)"), 139 RESOLVE_PREFIX_BUILTIN); 140 141 /** Create a <code>Declaration</code> for a builtin function. */ makeBuiltin(String name, int code)142 public static Declaration makeBuiltin (String name, int code) 143 { 144 return makeBuiltin (Symbol.make(XQuery.XQUERY_FUNCTION_NAMESPACE, name, "fn"), 145 code); 146 } 147 148 /** Create a <code>Declaration</code> for a builtin function. */ makeBuiltin(Symbol name, int code)149 public static Declaration makeBuiltin (Symbol name, int code) 150 { 151 Declaration decl = new Declaration(name); 152 decl.setProcedureDecl(true); 153 decl.setCode(code); 154 return decl; 155 } 156 XQResolveNames()157 public XQResolveNames () 158 { 159 this(null); 160 } 161 pushBuiltin(String name, int code)162 void pushBuiltin (String name, int code) 163 { 164 lookup.push(makeBuiltin(name, code)); 165 } 166 XQResolveNames(Compilation comp)167 public XQResolveNames (Compilation comp) 168 { 169 super(comp); 170 lookup.push(lastDecl); 171 lookup.push(xsQNameDecl); 172 lookup.push(staticBaseUriDecl); 173 pushBuiltin("position", POSITION_BUILTIN); 174 pushBuiltin("compare", COMPARE_BUILTIN); 175 pushBuiltin("distinct-values", DISTINCT_VALUES_BUILTIN); 176 pushBuiltin("local-name", LOCAL_NAME_BUILTIN); 177 pushBuiltin("name", NAME_BUILTIN); 178 pushBuiltin("namespace-uri", NAMESPACE_URI_BUILTIN); 179 pushBuiltin("root", ROOT_BUILTIN); 180 pushBuiltin("base-uri", BASE_URI_BUILTIN); 181 pushBuiltin("lang", LANG_BUILTIN); 182 pushBuiltin("resolve-uri", RESOLVE_URI_BUILTIN); 183 pushBuiltin("collection", COLLECTION_BUILTIN); 184 pushBuiltin("doc", DOC_BUILTIN); 185 pushBuiltin("document", DOC_BUILTIN); // Obsolete 186 pushBuiltin("doc-available", DOC_AVAILABLE_BUILTIN); 187 pushBuiltin("index-of", INDEX_OF_BUILTIN); 188 pushBuiltin("string", STRING_BUILTIN); 189 pushBuiltin("normalize-space", NORMALIZE_SPACE_BUILTIN); 190 pushBuiltin("unordered", UNORDERED_BUILTIN); 191 pushBuiltin("deep-equal", DEEP_EQUAL_BUILTIN); 192 pushBuiltin("min", MIN_BUILTIN); 193 pushBuiltin("max", MAX_BUILTIN); 194 pushBuiltin("number", NUMBER_BUILTIN); 195 pushBuiltin("default-collation", DEFAULT_COLLATION_BUILTIN); 196 pushBuiltin("id", ID_BUILTIN); 197 pushBuiltin("idref", IDREF_BUILTIN); 198 } 199 200 public Namespace[] functionNamespacePath 201 = XQuery.defaultFunctionNamespacePath; 202 push(ScopeExp exp)203 protected void push (ScopeExp exp) 204 { 205 for (Declaration decl = exp.firstDecl(); 206 decl != null; decl = decl.nextDecl()) 207 { 208 push(decl); 209 } 210 } 211 push(Declaration decl)212 void push (Declaration decl) 213 { 214 Compilation comp = getCompilation(); 215 Object name = decl.getSymbol(); 216 boolean function = decl.isProcedureDecl(); 217 if (name instanceof String) 218 { 219 int line = decl.getLineNumber(); 220 if (line > 0 && comp != null) 221 { 222 String saveFilename = comp.getFileName(); 223 int saveLine = comp.getLineNumber(); 224 int saveColumn = comp.getColumnNumber(); 225 comp.setLocation(decl); 226 name = parser.namespaceResolve((String) name, function); 227 comp.setLine(saveFilename, saveLine, saveColumn); 228 } 229 else 230 name = parser.namespaceResolve((String) name, function); 231 if (name == null) 232 return; 233 decl.setName(name); 234 } 235 236 Declaration old = lookup.lookup(name, XQuery.instance.getNamespaceOf(decl)); 237 if (old != null) 238 { 239 if (decl.context == old.context) 240 ScopeExp.duplicateDeclarationError(old, decl, comp); 241 else if (XQParser.warnHidePreviousDeclaration 242 && (! (name instanceof Symbol) 243 || ((Symbol) name).getNamespace() != null)) 244 comp.error('w', decl, "declaration ", 245 " hides previous declaration"); 246 } 247 lookup.push(decl); 248 } 249 flookup(Symbol sym)250 Declaration flookup (Symbol sym) 251 { 252 Environment env = XQuery.xqEnvironment; 253 gnu.mapping.Location loc = env.lookup(sym, EnvironmentKey.FUNCTION); 254 if (loc == null) 255 return null; 256 loc = loc.getBase(); 257 if (loc instanceof StaticFieldLocation) 258 { 259 Declaration decl = ((StaticFieldLocation) loc).getDeclaration(); 260 if (decl != null) 261 return decl; 262 } 263 Object val = loc.get(null); 264 if (val != null) 265 return procToDecl(sym, val); 266 return null; 267 } 268 visitReferenceExp(ReferenceExp exp, Void ignored)269 protected Expression visitReferenceExp (ReferenceExp exp, Void ignored) 270 { 271 return visitReferenceExp(exp, (ApplyExp) null); 272 } 273 visitReferenceExp(ReferenceExp exp, ApplyExp call)274 protected Expression visitReferenceExp (ReferenceExp exp, ApplyExp call) 275 { 276 if (exp.getBinding() == null) 277 { 278 Object symbol = exp.getSymbol(); 279 boolean needFunction = exp.isProcedureName(); 280 boolean needType = exp.getFlag(ReferenceExp.TYPE_NAME); 281 int namespace = call == null ? XQuery.VALUE_NAMESPACE 282 : XQuery.namespaceForFunctions(call.getArgCount()); 283 Declaration decl = lookup.lookup(symbol, namespace); 284 Symbol sym; 285 if (decl != null) 286 ; 287 else if (symbol instanceof Symbol 288 && "".equals((sym = (Symbol) symbol).getNamespaceURI())) 289 { 290 // kludge - use xxx_BUILTIN mechanism? FIXME 291 String name = sym.getLocalName(); 292 String mname; 293 if ("request".equals(name)) 294 mname = "getCurrentRequest"; 295 else if ("response".equals(name)) 296 mname = "getCurrentResponse"; 297 else 298 mname = null; 299 if (mname != null) 300 { 301 Method meth = 302 ClassType.make("gnu.kawa.servlet.KawaServlet") 303 .getDeclaredMethod(mname, 0); 304 return new ApplyExp(meth, Expression.noExpressions); 305 } 306 } 307 else if (symbol instanceof Symbol) 308 { 309 // Never happens, I believe. 310 decl = flookup((Symbol) symbol); 311 } 312 else // if (symbol instanceof String) 313 { 314 String name = (String) symbol; 315 if (name.indexOf(':') < 0) 316 { 317 name = name.intern(); 318 if (needFunction) 319 { 320 for (int i = 0; i < functionNamespacePath.length; i++) 321 { 322 sym = functionNamespacePath[i].getSymbol(name); 323 decl = lookup.lookup(sym, namespace); 324 if (decl != null) 325 break; 326 decl = flookup(sym); 327 if (decl != null) 328 break; 329 } 330 } 331 } 332 if (decl == null) 333 { 334 sym = parser.namespaceResolve(name, needFunction); 335 if (sym != null) 336 { 337 decl = lookup.lookup(sym, namespace); 338 if (decl == null 339 && (needFunction || needType)) 340 { 341 String uri = sym.getNamespaceURI(); 342 Type type = null; 343 if (XQuery.SCHEMA_NAMESPACE.equals(uri)) 344 { 345 type = parser.interpreter.getStandardType(sym.getName()); 346 } 347 else if (needType && uri == "" 348 && ! getCompilation().isPedantic()) 349 { 350 type = parser.interpreter.getTypeFor(name); 351 } 352 if (type != null) 353 return new QuoteExp(type).setLine(exp); 354 if (uri != null && uri.length() > 6 && 355 uri.startsWith("class:")) 356 { 357 ClassType ctype = ClassType.make(uri.substring(6)); 358 return CompileNamedPart.makeExp(ctype, sym.getName()); 359 } 360 decl = flookup(sym); 361 } 362 } 363 } 364 } 365 if (decl != null) 366 exp.setBinding(decl); 367 else if (needFunction) 368 error('e', "unknown function "+symbol); 369 else if (needType) 370 messages.error('e', exp, "unknown type "+symbol, "XPST0051"); 371 else 372 messages.error('e', exp, "unknown variable $"+symbol, "XPST0008"); 373 } 374 return exp; 375 } 376 visitSetExp(SetExp exp, Void ignored)377 protected Expression visitSetExp (SetExp exp, Void ignored) 378 { 379 Expression result = super.visitSetExp(exp, ignored); 380 Declaration decl = exp.getBinding(); 381 Object name; 382 Expression new_value; 383 if (decl != null && ! getCompilation().immediate 384 && (name = decl.getSymbol()) instanceof Symbol 385 && XQuery.LOCAL_NAMESPACE.equals(((Symbol) name).getNamespaceURI()) 386 && (! ((new_value = exp.getNewValue()) instanceof ApplyExp) 387 || ((ApplyExp) new_value).getFunction() != XQParser.getExternalFunction)) 388 { 389 decl.setFlag(Declaration.PRIVATE_SPECIFIED); 390 decl.setPrivate(true); 391 } 392 return result; 393 } 394 395 private Declaration moduleDecl; visitStatements(Expression exp)396 private Expression visitStatements (Expression exp) 397 { 398 // The tricky part here is interleaving declarations and statements 399 // so that a variable declaration is only visible *after* we have 400 // visited its initializing expression. 401 if (exp instanceof BeginExp) 402 { 403 BeginExp bbody = (BeginExp) exp; 404 Expression[] exps = bbody.getExpressions(); 405 int nexps = bbody.getExpressionCount(); 406 for (int i = 0; i < nexps; i++) 407 { 408 exps[i] = visitStatements(exps[i]); 409 } 410 } 411 else if (exp instanceof SetExp) 412 { 413 Declaration decl = moduleDecl; 414 SetExp sexp = (SetExp) exp; 415 exp = visitSetExp(sexp, null); 416 if (sexp.isDefining() && sexp.getBinding() == decl) 417 { 418 if (! decl.isProcedureDecl()) 419 push(decl); 420 decl = decl.nextDecl(); 421 } 422 moduleDecl = decl; 423 } 424 else 425 exp = visit(exp, null); 426 return exp; 427 } 428 429 static class CycleDetector extends ExpExpVisitor<Void> { 430 Map<Declaration,Integer> depsScanState = new HashMap<Declaration,Integer>(); 431 static final Integer SCANNING = 0; 432 static final Integer SCANNED_CYCLE = 1; 433 static final Integer SCANNED_NO_CYCLE = -1; 434 435 Declaration target; 436 boolean cycleSeen; 437 visitReferenceExp(ReferenceExp exp, Void ignored)438 protected Expression visitReferenceExp(ReferenceExp exp, Void ignored) { 439 Declaration decl = exp.getBinding(); 440 if (decl != null && decl.context instanceof ModuleExp) 441 scanDependencies(decl); 442 return exp; 443 } 444 scanDependencies(Declaration decl)445 public void scanDependencies(Declaration decl) { 446 if (target == null) 447 target = decl; 448 else if (target == decl) { 449 cycleSeen = true; 450 return; 451 } 452 Integer state = depsScanState.get(decl); 453 if (state != null) { 454 if (state == SCANNING) 455 depsScanState.put(decl, SCANNED_CYCLE); 456 return; 457 } 458 depsScanState.put(decl, SCANNING); 459 Expression dval = decl.getValue(); 460 if (dval != null) 461 visit(dval, null); 462 state = depsScanState.get(decl); 463 if (state == SCANNING) 464 depsScanState.put(decl, SCANNED_NO_CYCLE); 465 } 466 467 /** Return true if cycle detected. */ scanVariable(Declaration decl)468 public static boolean scanVariable(Declaration decl) { 469 CycleDetector cycleDetector = new CycleDetector(); 470 cycleDetector.scanDependencies(decl); 471 return cycleDetector.cycleSeen; 472 } 473 } 474 resolveModule(ModuleExp exp)475 public void resolveModule(ModuleExp exp) 476 { 477 currentLambda = exp; 478 for (Declaration decl = exp.firstDecl(); 479 decl != null; decl = decl.nextDecl()) 480 { 481 if (decl.isProcedureDecl()) 482 push(decl); 483 } 484 moduleDecl = exp.firstDecl(); 485 exp.body = visitStatements(exp.body); 486 487 for (Declaration decl = exp.firstDecl(); 488 decl != null; decl = decl.nextDecl()) 489 { 490 if (! decl.isProcedureDecl() && CycleDetector.scanVariable(decl)) 491 getCompilation().error('e', 492 "cycle detected initializing $"+decl.getName(), 493 "XQST0054", decl); 494 495 // Remove old hidden declarations, for GC and speed. 496 if (decl.getSymbol() != null) 497 lookup.removeSubsumed(decl); 498 } 499 } 500 501 /** 502 * Coerce argument to NamedCallator, or return default collator. 503 * @param args argument list 504 * @param argno index in args of collator argument 505 */ getCollator(Expression[] args, int argno)506 Expression getCollator (Expression[] args, int argno) 507 { 508 if (args != null && args.length > argno) 509 return new ApplyExp(ClassType.make("gnu.xquery.util.NamedCollator") 510 .getDeclaredMethod("find", 1), 511 new Expression[] { args[argno] }); 512 NamedCollator coll = parser.defaultCollator; 513 return coll == null ? QuoteExp.nullExp : new QuoteExp(coll); 514 } 515 withCollator(Method method, Expression[] args, String name, int minArgs)516 Expression withCollator (Method method, Expression[] args, 517 String name, int minArgs) 518 { 519 return withCollator(new QuoteExp(new PrimProcedure(method)), 520 args, name, minArgs); 521 } 522 523 /** Adjust call to add default collator if collator argument is missing. */ withCollator(Expression function, Expression[] args, String name, int minArgs)524 Expression withCollator (Expression function, Expression[] args, 525 String name, int minArgs) 526 { 527 String err = WrongArguments.checkArgCount(name, minArgs, minArgs+1, args.length); 528 if (err != null) 529 return getCompilation().syntaxError(err); 530 Expression[] xargs = new Expression[minArgs+1]; 531 System.arraycopy(args, 0, xargs, 0, minArgs); 532 xargs[minArgs] = getCollator(args, minArgs); 533 return new ApplyExp(function, xargs); 534 } 535 536 /** Adjust call to add default contex itemt if that argument is missing. */ withContext(Method method, Expression[] args, String name, int minArgs)537 Expression withContext (Method method, Expression[] args, 538 String name, int minArgs) 539 { 540 String err = WrongArguments.checkArgCount(name, minArgs, minArgs+1, 541 args.length); 542 if (err != null) 543 return getCompilation().syntaxError(err); 544 if (args.length == minArgs) 545 { 546 Expression[] xargs = new Expression[minArgs+1]; 547 System.arraycopy(args, 0, xargs, 0, minArgs); 548 Declaration dot = lookup.lookup(XQParser.DOT_VARNAME, false); 549 if (dot == null) 550 { 551 String message = "undefined context for " + name; 552 messages.error('e', message, "XPDY0002"); 553 return new ErrorExp(message); 554 } 555 xargs[minArgs] = new ReferenceExp(dot); 556 args = xargs; 557 } 558 return new ApplyExp(method, args); 559 } 560 checkArgCount(Expression[] args, Declaration decl, int min, int max)561 private Expression checkArgCount (Expression[] args, Declaration decl, 562 int min, int max) 563 { 564 String err = WrongArguments.checkArgCount("fn:"+decl.getName(), 565 min, max, args.length); 566 if (err == null) 567 return null; 568 else 569 return getCompilation().syntaxError(err); 570 } 571 visitApplyExp(ApplyExp exp, Void ignored)572 protected Expression visitApplyExp (ApplyExp exp, Void ignored) 573 { 574 Expression func = exp.getFunction(); 575 NamespaceBinding namespaceSave = parser.constructorNamespaces; 576 Object proc = exp.getFunctionValue(); 577 if (proc instanceof MakeElement) 578 { 579 MakeElement mk = (MakeElement) proc; 580 NamespaceBinding nschain 581 = NamespaceBinding.nconc(mk.getNamespaceNodes(), namespaceSave); 582 mk.setNamespaceNodes(nschain); 583 parser.constructorNamespaces = nschain; 584 } 585 if (func instanceof ReferenceExp) 586 func = visitReferenceExp((ReferenceExp) func, exp); 587 else 588 func = visit(func, ignored); 589 exp.setFunction(func); 590 visitExps(exp.getArgs(), ignored); 591 parser.constructorNamespaces = namespaceSave; 592 func = exp.getFunction(); 593 if (func instanceof ReferenceExp) 594 { 595 Declaration decl = ((ReferenceExp) func).getBinding(); 596 int code; 597 Expression err; 598 if (decl != null && (code = decl.getCode()) < 0) 599 { 600 switch (code) 601 { 602 case POSITION_BUILTIN: 603 case LAST_BUILTIN: 604 Symbol sym = code == LAST_BUILTIN ? XQParser.LAST_VARNAME 605 : XQParser.POSITION_VARNAME; 606 decl = lookup.lookup(sym, false); 607 if (decl == null) 608 error('e', "undefined context for " + sym.getName()); 609 else 610 // So CompileMisc:validateApplyValuesFilter 611 // can tell whether last() is used. 612 decl.setCanRead(true); 613 return new ReferenceExp(sym, decl); 614 case CAST_AS_BUILTIN: 615 case CASTABLE_AS_BUILTIN: 616 { 617 Expression[] args = exp.getArgs(); 618 Expression texp = args[code == CAST_AS_BUILTIN ? 0 : 1]; 619 Expression qexp = texp; 620 if (texp instanceof ApplyExp) 621 { 622 ApplyExp taexp = (ApplyExp) texp; 623 if (taexp.getFunction().valueIfConstant() 624 == XQParser.proc_OccurrenceType_getInstance) 625 qexp = taexp.getArg(0); 626 } 627 Object value = qexp.valueIfConstant(); 628 String msg = null; 629 if (value == SingletonType.getInstance()) 630 msg = "type to 'cast as' or 'castable as' must be atomic"; 631 else if (value == XDataType.anyAtomicType) 632 msg = "type to 'cast as' or 'castable as' cannot be anyAtomicType"; 633 else if (value == XDataType.anySimpleType) 634 msg = "type to 'cast as' or 'castable as' cannot be anySimpleType"; 635 else if (value == XDataType.untypedType) 636 msg = "type to 'cast as' or 'castable as' cannot be untyped"; 637 else if (value == XDataType.NotationType) 638 msg = "type to 'cast as' or 'castable as' cannot be NOTATION"; 639 if (msg != null) 640 messages.error('e', texp, msg, "XPST0080"); 641 boolean toQName = (value == Compilation.typeSymbol 642 && ! (texp instanceof ApplyExp)); 643 if (code == CAST_AS_BUILTIN) 644 { 645 if (toQName) 646 return visitApplyExp(XQParser.castQName(args[1], true), ignored); 647 func 648 = XQParser.makeFunctionExp("gnu.xquery.util.CastAs", "castAs"); 649 } 650 else 651 { 652 if (toQName && args[0] instanceof QuoteExp) 653 { 654 value = ((QuoteExp) args[0]).getValue(); 655 try 656 { 657 QNameUtils.resolveQName(value, 658 parser.constructorNamespaces, 659 parser.prologNamespaces); 660 return XQuery.trueExp; 661 } 662 catch (RuntimeException ex) 663 { 664 return XQuery.falseExp; 665 } 666 } 667 func = XQParser.makeFunctionExp("gnu.xquery.lang.XQParser", "castableAs"); 668 } 669 return new ApplyExp(func, args).setLine(exp); 670 } 671 case XS_QNAME_BUILTIN: 672 case XS_QNAME_IGNORE_DEFAULT_BUILTIN: 673 { 674 Expression[] args = exp.getArgs(); 675 if ((err = checkArgCount(args, decl, 1, 1)) != null) 676 return err; 677 NamespaceBinding constructorNamespaces 678 = parser.constructorNamespaces; 679 if (code == XS_QNAME_IGNORE_DEFAULT_BUILTIN) 680 constructorNamespaces 681 = new NamespaceBinding(null, "", constructorNamespaces); 682 if (args[0] instanceof QuoteExp) 683 { 684 try 685 { 686 Object val = ((QuoteExp) args[0]).getValue(); 687 val = QNameUtils.resolveQName(val, 688 constructorNamespaces, 689 parser.prologNamespaces); 690 return new QuoteExp(val); 691 } 692 catch (RuntimeException ex) 693 { 694 return getCompilation().syntaxError(ex.getMessage()); 695 } 696 } 697 Expression[] xargs = { 698 args[0], 699 new QuoteExp(constructorNamespaces), 700 new QuoteExp(parser.prologNamespaces) }; 701 Method meth 702 = (ClassType.make("gnu.xquery.util.QNameUtils") 703 .getDeclaredMethod("resolveQName", 3)); 704 ApplyExp app = new ApplyExp(meth, xargs); 705 app.setFlag(ApplyExp.INLINE_IF_CONSTANT); 706 return app; 707 } 708 case RESOLVE_PREFIX_BUILTIN: 709 { 710 Expression[] args = exp.getArgs(); 711 if ((err = checkArgCount(args, decl, 1, 1)) != null) 712 return err; 713 if (args[0] instanceof QuoteExp) 714 { 715 Object val = ((QuoteExp) args[0]).getValue(); 716 String prefix = val == null ? null : val.toString(); 717 val = QNameUtils.lookupPrefix(prefix, 718 parser.constructorNamespaces, 719 parser.prologNamespaces); 720 if (val == null) 721 return getCompilation() 722 .syntaxError("unknown namespace prefix '" 723 +prefix+"'"); 724 return new QuoteExp(val); 725 } 726 Expression[] xargs = { 727 args[0], 728 new QuoteExp(parser.constructorNamespaces), 729 new QuoteExp(parser.prologNamespaces) }; 730 PrimProcedure pproc 731 = new PrimProcedure(ClassType.make("gnu.xquery.util.QNameUtils") 732 .getDeclaredMethod("resolvePrefix", 3)); 733 ApplyExp app = new ApplyExp(pproc, xargs); 734 app.setFlag(ApplyExp.INLINE_IF_CONSTANT); 735 return app; 736 } 737 case LOCAL_NAME_BUILTIN: 738 { 739 Method meth = ClassType.make("gnu.xquery.util.NodeUtils") 740 .getDeclaredMethod("localName", 1); 741 return withContext(meth, exp.getArgs(), "fn:local-name", 0); 742 } 743 case NAME_BUILTIN: 744 { 745 Method meth = ClassType.make("gnu.xquery.util.NodeUtils") 746 .getDeclaredMethod("name", 1); 747 return withContext(meth, exp.getArgs(), "fn:name", 0); 748 } 749 case NUMBER_BUILTIN: 750 { 751 Method meth = ClassType.make("gnu.xquery.util.NumberValue") 752 .getDeclaredMethod("numberValue", 1); 753 return withContext(meth, exp.getArgs(), "fn:number", 0); 754 } 755 case ROOT_BUILTIN: 756 { 757 Method meth = ClassType.make("gnu.xquery.util.NodeUtils") 758 .getDeclaredMethod("root", 1); 759 return withContext(meth, exp.getArgs(), "fn:root", 0); 760 } 761 case BASE_URI_BUILTIN: 762 { 763 Method meth = ClassType.make("gnu.xquery.util.NodeUtils") 764 .getDeclaredMethod("baseUri", 1); 765 return withContext(meth, exp.getArgs(), "fn:base-uri", 0); 766 } 767 case LANG_BUILTIN: 768 { 769 Method meth = ClassType.make("gnu.xquery.util.NodeUtils") 770 .getDeclaredMethod("lang", 2); 771 return withContext(meth, exp.getArgs(), "fn:lang", 1); 772 } 773 case ID_BUILTIN: 774 { 775 Method meth = ClassType.make("gnu.xquery.util.NodeUtils") 776 .getDeclaredMethod("id$X", 3); 777 return withContext(meth, exp.getArgs(), "fn:id", 1); 778 } 779 case IDREF_BUILTIN: 780 { 781 Method meth = ClassType.make("gnu.xquery.util.NodeUtils") 782 .getDeclaredMethod("idref", 2); 783 return withContext(meth, exp.getArgs(), "fn:idref", 1); 784 } 785 786 case STATIC_BASE_URI_BUILTIN: 787 { 788 Expression[] args = exp.getArgs(); 789 if ((err = checkArgCount(args, decl, 0, 0)) != null) 790 return err; 791 return getBaseUriExpr(); 792 } 793 case NAMESPACE_URI_BUILTIN: 794 { 795 Method meth = ClassType.make("gnu.xquery.util.NodeUtils") 796 .getDeclaredMethod("namespaceURI", 1); 797 return withContext(meth, exp.getArgs(), 798 "fn:namespace-uri", 0); 799 } 800 801 case NORMALIZE_SPACE_BUILTIN: 802 { 803 Method meth = ClassType.make("gnu.xquery.util.StringUtils") 804 .getDeclaredMethod("normalizeSpace", 1); 805 return withContext(meth, exp.getArgs(), 806 "fn:normalize-space", 0); 807 } 808 809 case UNORDERED_BUILTIN: 810 { 811 Expression[] args = exp.getArgs(); 812 if ((err = checkArgCount(args, decl, 1, 1)) != null) 813 return err; 814 return args[0]; 815 } 816 817 case COMPARE_BUILTIN: 818 { 819 Method meth = ClassType.make("gnu.xquery.util.StringUtils") 820 .getDeclaredMethod("compare", 3); 821 return withCollator(meth, exp.getArgs(), "fn:compare", 2); 822 } 823 824 case STRING_BUILTIN: 825 return withContext(ClassType.make("gnu.xml.TextUtils") 826 .getDeclaredMethod("asString", 1), 827 exp.getArgs(), "fn:string", 0); 828 829 case INDEX_OF_BUILTIN: 830 { 831 Method meth = ClassType.make("gnu.xquery.util.SequenceUtils") 832 .getDeclaredMethod("indexOf$X", 4); 833 return withCollator(meth, exp.getArgs(), "fn:index-of", 2); 834 } 835 case COLLECTION_BUILTIN: 836 { 837 Expression[] args = exp.getArgs(); 838 ClassType cl = ClassType.make("gnu.xquery.util.NodeUtils"); 839 Method meth = cl.getDeclaredMethod("collection", 2); 840 if ((err = checkArgCount(args, decl, 0, 1)) != null) 841 return err; 842 Expression base = getBaseUriExpr(); 843 Expression uri = args.length > 0 ? args[0] 844 : QuoteExp.voidExp; 845 return new ApplyExp(meth, new Expression[]{ uri, base }); 846 } 847 case DOC_BUILTIN: 848 case DOC_AVAILABLE_BUILTIN: 849 { 850 Expression[] args = exp.getArgs(); 851 ClassType cl = ClassType.make("gnu.xquery.util.NodeUtils"); 852 String mname; 853 if (code == DOC_BUILTIN) 854 { 855 mname = "docCached"; 856 if (XQParser.warnOldVersion 857 && "document".equals(decl.getName())) 858 getCompilation() 859 .error('w', "replace 'document' by 'doc'"); 860 } 861 else 862 mname = "availableCached"; 863 Method meth = cl.getDeclaredMethod(mname, 2); 864 if ((err = checkArgCount(args, decl, 1, 1)) != null) 865 return err; 866 PrimProcedure pproc = new PrimProcedure(meth); 867 if (code == DOC_BUILTIN) 868 pproc.setSideEffectFree(); 869 Expression base = getBaseUriExpr(); 870 ApplyExp aexp 871 = new ApplyExp(pproc, new Expression[]{args[0], base}); 872 if (code == DOC_BUILTIN) 873 aexp.setType(NodeType.documentNodeTest); 874 else 875 aexp.setType(XDataType.booleanType); 876 return aexp; 877 } 878 case RESOLVE_URI_BUILTIN: 879 { 880 Expression[] args = exp.getArgs(); 881 if ((err = checkArgCount(args, decl, 1, 2)) != null) 882 return err; 883 Expression[] margs = new Expression[2]; 884 margs[0] = args[0]; 885 if (args.length == 1) 886 margs[1] = getBaseUriExpr(); 887 else 888 margs[1] = args[1]; 889 Method meth = ClassType.make("gnu.xquery.util.QNameUtils") 890 .getDeclaredMethod("resolveURI", 2); 891 return new ApplyExp(meth, margs); 892 } 893 case DISTINCT_VALUES_BUILTIN: 894 { 895 Method meth = ClassType.make("gnu.xquery.util.DistinctValues") 896 .getDeclaredMethod("distinctValues$X", 3); 897 return withCollator(meth, exp.getArgs(), 898 "fn:distinct-values", 1); 899 900 } 901 case DEEP_EQUAL_BUILTIN: 902 { 903 Method meth = ClassType.make("gnu.xquery.util.SequenceUtils") 904 .getDeclaredMethod("deepEqual", 3); 905 return withCollator(meth, exp.getArgs(), 906 "fn:deep-equal", 2); 907 } 908 case MIN_BUILTIN: 909 { 910 Method meth = ClassType.make("gnu.xquery.util.MinMax") 911 .getDeclaredMethod("min", 2); 912 return withCollator(meth, exp.getArgs(), 913 "fn:min", 1); 914 } 915 case MAX_BUILTIN: 916 { 917 Method meth = ClassType.make("gnu.xquery.util.MinMax") 918 .getDeclaredMethod("max", 2); 919 return withCollator(meth, exp.getArgs(), 920 "fn:max", 1); 921 } 922 case DEFAULT_COLLATION_BUILTIN: 923 if ((err = checkArgCount(exp.getArgs(), decl, 0, 0)) != null) 924 return err; 925 NamedCollator coll = parser.defaultCollator; 926 return QuoteExp.getInstance(coll != null ? coll.getName() 927 : NamedCollator.UNICODE_CODEPOINT_COLLATION); 928 case HANDLE_EXTENSION_BUILTIN: 929 { 930 Compilation comp = getCompilation(); 931 Expression[] args = exp.getArgs(); 932 int i = 0; 933 for (; i < args.length - 1; i += 2) 934 { 935 Expression pname = args[i]; 936 String qname = (String) ((QuoteExp) pname).getValue(); 937 Symbol psymbol = parser.namespaceResolve(qname, false); 938 if (psymbol == null) 939 ; // error emitted in namespaceResolve 940 else if (psymbol.getNamespaceURI().length() == 0) 941 comp.error('e', "pragma name cannot be in the empty namespace"); 942 else 943 { 944 Expression replacement 945 = checkPragma(psymbol, args[i+1]); 946 if (replacement != null) 947 return replacement; 948 } 949 } 950 if (i < args.length) 951 return args[args.length-1]; 952 String msg = "no recognized pragma or default in extension expression"; 953 getMessages().error('e', msg, "XQST0079"); 954 return new ErrorExp(msg); 955 } 956 } 957 } 958 } 959 proc = exp.getFunctionValue(); 960 if (proc instanceof Type) 961 { 962 Expression[] args = exp.getArgs(); 963 if (args.length != 1) 964 { 965 messages.error('e', "type constructor requires a single argument"); 966 return exp; 967 } 968 return new ApplyExp(XQParser.makeFunctionExp("gnu.xquery.util.CastAs", "castAs"), 969 new Expression[] { exp.getFunction(), args[0] }); 970 } 971 if (proc instanceof MakeElement) 972 { 973 MakeElement make = (MakeElement) proc; 974 975 // Add namespaces nodes that might be needed. 976 NamespaceBinding nsBindings = make.getNamespaceNodes(); 977 Symbol tag = make.tag; 978 if (tag == null) 979 tag = MakeElement.getTagName(exp); 980 nsBindings = maybeAddNamespace(tag, false, nsBindings); 981 Expression[] args = exp.getArgs(); 982 Symbol[] attrSyms = new Symbol[args.length]; 983 int nattrSyms = 0; 984 for (int i = 0; i < args.length; i++) 985 { 986 Expression arg = args[i]; 987 if (arg instanceof ApplyExp) 988 { 989 ApplyExp app = (ApplyExp) arg; 990 if (app.getFunction() == MakeAttribute.makeAttributeExp) 991 { 992 Symbol sym = MakeElement.getTagName(app); 993 if (sym != null) 994 { 995 for (int j = 0; ; j++) 996 { 997 if (j == nattrSyms) 998 { 999 attrSyms[nattrSyms++] = sym; 1000 break; 1001 } 1002 if (sym.equals(attrSyms[j])) 1003 { 1004 getCompilation().setLine(app); 1005 Symbol elementSym = MakeElement.getTagName(exp); 1006 String elementName = elementSym == null ? null 1007 : elementSym.toString(); 1008 messages.error('e', XMLFilter.duplicateAttributeMessage(sym, elementName), "XQST0040"); 1009 } 1010 } 1011 nsBindings = maybeAddNamespace(sym, true, nsBindings); 1012 } 1013 } 1014 } 1015 } 1016 if (nsBindings != null) 1017 make.setNamespaceNodes(nsBindings); 1018 } 1019 return exp; 1020 } 1021 1022 public Expression checkPragma(Symbol name, Expression contents)1023 checkPragma (Symbol name, Expression contents) 1024 { 1025 return null; 1026 } 1027 getBaseUriExpr()1028 Expression getBaseUriExpr () 1029 { 1030 Compilation comp = getCompilation(); 1031 String staticBaseUri = parser.getStaticBaseUri(); 1032 if (staticBaseUri != null) 1033 return QuoteExp.getInstance(staticBaseUri); 1034 else 1035 return gnu.kawa.functions.GetModuleClass.getModuleClassURI(comp); 1036 } 1037 maybeAddNamespace(Symbol qname, boolean isAttribute, NamespaceBinding bindings)1038 static NamespaceBinding maybeAddNamespace(Symbol qname, boolean isAttribute, 1039 NamespaceBinding bindings) 1040 { 1041 if (qname == null) // Happens if prevously-reported unknown prefix. 1042 return bindings; 1043 String prefix = qname.getPrefix(); 1044 String uri = qname.getNamespaceURI(); 1045 if (prefix == "") 1046 prefix = null; 1047 if (uri == "") 1048 uri = null; 1049 if (isAttribute && prefix == null && uri == null) 1050 return bindings; 1051 return NamespaceBinding.maybeAdd(prefix, uri, bindings); 1052 } 1053 1054 /** Wrap a (known) procedure value as a Declaration. */ procToDecl(Object symbol, Object val)1055 static Declaration procToDecl (Object symbol, Object val) 1056 { 1057 Declaration decl = new Declaration(symbol); 1058 decl.setProcedureDecl(true); 1059 decl.noteValue(new QuoteExp(val)); 1060 decl.setFlag(Declaration.IS_CONSTANT); 1061 return decl; 1062 } 1063 } 1064