1 package net.sf.saxon.expr; 2 import net.sf.saxon.Err; 3 import net.sf.saxon.style.StandardNames; 4 import net.sf.saxon.event.LocationProvider; 5 import net.sf.saxon.instruct.Block; 6 import net.sf.saxon.instruct.Executable; 7 import net.sf.saxon.instruct.LocationMap; 8 import net.sf.saxon.instruct.TraceExpression; 9 import net.sf.saxon.om.*; 10 import net.sf.saxon.pattern.*; 11 import net.sf.saxon.sort.Reverser; 12 import net.sf.saxon.trace.Location; 13 import net.sf.saxon.trans.DynamicError; 14 import net.sf.saxon.trans.StaticError; 15 import net.sf.saxon.trans.XPathException; 16 import net.sf.saxon.type.*; 17 import net.sf.saxon.value.*; 18 19 import java.util.ArrayList ; 20 import java.util.List ; 21 import java.util.Stack ; 22 23 30 31 32 public class ExpressionParser { 33 34 protected Tokenizer t; 35 protected StaticContext env; 36 protected Stack rangeVariables = null; 37 41 protected boolean scanOnly = false; 42 47 protected int language = XPATH; protected static final int XPATH = 0; 49 protected static final int XSLT_PATTERN = 1; 50 protected static final int SEQUENCE_TYPE = 2; 51 protected static final int XQUERY = 3; 52 53 public ExpressionParser(){} 54 55 public Tokenizer getTokenizer() { 56 return t; 57 } 58 59 62 63 protected void nextToken() throws StaticError { 64 try { 65 t.next(); 66 } catch (StaticError err) { 67 grumble(err.getMessage()); 68 } 69 } 70 71 79 80 protected void expect(int token) throws StaticError { 81 if (t.currentToken != token) 82 grumble("expected \"" + Token.tokens[token] + 83 "\", found " + currentTokenDisplay()); 84 } 85 86 92 93 protected void grumble(String message) throws StaticError { 94 grumble(message, (language == XSLT_PATTERN ? "XTSE0340" : "XPST0003")); 95 } 96 97 105 106 protected void grumble(String message, String errorCode) throws StaticError { 107 if (errorCode == null) { 108 errorCode = "XPST0003"; 109 } 110 String s = t.recentText(); 111 int line = t.getLineNumber(); 112 int column = t.getColumnNumber(); 113 String lineInfo = (line==1 ? "" : ("on line " + line + ' ')); 114 String columnInfo = "at char " + column + ' '; 115 String prefix = getLanguage() + " syntax error " + columnInfo + lineInfo + 116 (message.startsWith("...") ? "near" : "in") + 117 ' ' + Err.wrap(s) + ":\n "; 118 StaticError err = new StaticError(prefix + message); 119 err.setErrorCode(errorCode); 120 throw err; 121 } 122 123 126 127 protected void warning(String message) throws StaticError { 128 String s = t.recentText(); 129 int line = t.getLineNumber(); 130 String lineInfo = (line==1 ? "" : ("on line " + line + ' ')); 131 String prefix = "Warning " + lineInfo + 132 (message.startsWith("...") ? "near" : "in") + 133 ' ' + Err.wrap(s) + ":\n "; 134 env.issueWarning(prefix + message, null); 135 } 136 137 140 141 protected String getLanguage() { 142 switch (language) { 143 case XPATH: 144 return "XPath"; 145 case XSLT_PATTERN: 146 return "XSLT Pattern"; 147 case SEQUENCE_TYPE: 148 return "SequenceType"; 149 case XQUERY: 150 return "XQuery"; 151 default: 152 return "XPath"; 153 } 154 } 155 156 161 protected String currentTokenDisplay() { 162 if (t.currentToken==Token.NAME) { 163 return "name \"" + t.currentTokenValue + '\"'; 164 } else if (t.currentToken==Token.UNKNOWN) { 165 return "(unknown token)"; 166 } else { 167 return '\"' + Token.tokens[t.currentToken] + '\"'; 168 } 169 } 170 171 182 183 public Expression parse(String expression, int start, int terminator, int lineNumber, StaticContext env) throws StaticError { 184 this.env = env; 186 t = new Tokenizer(); 187 try { 188 t.tokenize(expression, start, -1, lineNumber); 189 } catch (StaticError err) { 190 grumble(err.getMessage()); 191 } 192 Expression exp = parseExpression(); 193 if (t.currentToken != terminator) { 194 if (t.currentToken == Token.EOF && terminator == Token.RCURLY) { 195 grumble("Missing curly brace after expression in attribute value template", "XTSE0350"); 196 } else { 197 grumble("Unexpected token " + currentTokenDisplay() + " beyond end of expression"); 198 } 199 } 200 return exp; 201 } 202 203 211 212 public Pattern parsePattern(String pattern, StaticContext env) throws StaticError { 213 this.env = env; 215 language = XSLT_PATTERN; 216 t = new Tokenizer(); 217 try { 218 t.tokenize(pattern, 0, -1, env.getLineNumber()); 219 } catch (StaticError err) { 220 grumble(err.getMessage()); 221 } 222 Pattern pat = parseUnionPattern(); 223 if (t.currentToken != Token.EOF) 224 grumble("Unexpected token " + currentTokenDisplay() + " beyond end of pattern"); 225 return pat; 228 } 229 230 239 240 public SequenceType parseSequenceType(String input, StaticContext env) throws StaticError { 241 this.env = env; 242 language = SEQUENCE_TYPE; 243 t = new Tokenizer(); 244 try { 245 t.tokenize(input, 0, -1, 1); 246 } catch (StaticError err) { 247 grumble(err.getMessage()); 248 } 249 SequenceType req = parseSequenceType(); 250 if (t.currentToken != Token.EOF) { 251 grumble("Unexpected token " + currentTokenDisplay() + " beyond end of SequenceType"); 252 } 253 return req; 254 } 255 256 257 261 268 269 protected Expression parseExpression() throws StaticError { 270 Expression exp = parseExprSingle(); 271 while (t.currentToken == Token.COMMA) { 272 nextToken(); 273 exp = Block.makeBlock(exp, parseExpression()); 274 setLocation(exp); 276 } 277 return exp; 278 } 279 280 286 287 protected Expression parseExprSingle() throws StaticError { 288 switch (t.currentToken) { 289 case Token.FOR: 290 case Token.LET: return parseForExpression(); 292 case Token.SOME: 293 case Token.EVERY: 294 return parseQuantifiedExpression(); 295 case Token.IF: 296 return parseIfExpression(); 297 case Token.TYPESWITCH: 298 return parseTypeswitchExpression(); 299 case Token.VALIDATE: 300 case Token.VALIDATE_STRICT: 301 case Token.VALIDATE_LAX: 302 return parseValidateExpression(); 303 case Token.PRAGMA: 304 return parseExtensionExpression(); 305 306 default: 307 return parseOrExpression(); 308 } 309 } 310 311 316 317 protected Expression parseTypeswitchExpression() throws StaticError { 318 grumble("typeswitch is not allowed in XPath"); 319 return null; 320 } 321 322 327 328 protected Expression parseValidateExpression() throws StaticError { 329 grumble("validate{} expressions are not allowed in XPath"); 330 return null; 331 } 332 333 338 339 protected Expression parseExtensionExpression() throws StaticError { 340 grumble("extension expressions (#...#) are not allowed in XPath"); 341 return null; 342 } 343 344 351 352 private Expression parseOrExpression() throws StaticError { 353 Expression exp = parseAndExpression(); 354 while (t.currentToken == Token.OR) { 355 nextToken(); 356 exp = new BooleanExpression(exp, Token.OR, parseAndExpression()); 357 setLocation(exp); 358 } 359 return exp; 360 } 361 362 369 370 private Expression parseAndExpression() throws StaticError { 371 Expression exp = parseComparisonExpression(); 372 while (t.currentToken == Token.AND) { 373 nextToken(); 374 exp = new BooleanExpression(exp, Token.AND, parseComparisonExpression()); 375 setLocation(exp); 376 } 377 return exp; 378 } 379 380 387 388 protected Expression parseForExpression() throws StaticError { 389 if (t.currentToken==Token.LET) { 390 grumble("'let' is not supported in XPath"); 391 } 392 return parseMappingExpression(); 393 } 394 395 402 403 private Expression parseQuantifiedExpression() throws StaticError { 404 return parseMappingExpression(); 405 } 406 407 421 422 protected Expression parseMappingExpression() throws StaticError { 423 int offset = t.currentTokenStartOffset; 424 int operator = t.currentToken; 425 List clauseList = new ArrayList (3); 426 do { 427 ForClause clause = new ForClause(); 428 clause.offset = offset; 429 clause.requiredType = SequenceType.SINGLE_ITEM; 430 clauseList.add(clause); 431 nextToken(); 432 expect(Token.DOLLAR); 433 nextToken(); 434 expect(Token.NAME); 435 String var = t.currentTokenValue; 436 437 RangeVariableDeclaration v = new RangeVariableDeclaration(); 439 v.setNameCode(makeNameCode(var, false)); 440 v.setRequiredType(SequenceType.SINGLE_ITEM); 441 v.setVariableName(var); 442 clause.rangeVariable = v; 443 nextToken(); 444 445 if (isKeyword("as") && "XQuery".equals(getLanguage())) { 446 nextToken(); 447 SequenceType type = parseSequenceType(); 448 clause.requiredType = type; 449 v.setRequiredType(type); 450 if (type.getCardinality() != StaticProperty.EXACTLY_ONE) { 451 grumble("Cardinality of range variable must be exactly one"); 452 } 453 } 454 455 clause.positionVariable = null; 457 458 expect(Token.IN); 460 nextToken(); 461 clause.sequence = parseExprSingle(); 462 declareRangeVariable(clause.rangeVariable); 463 464 } while (t.currentToken==Token.COMMA); 465 466 if (operator==Token.FOR) { 468 expect(Token.RETURN); 469 } else { 470 expect(Token.SATISFIES); 471 } 472 nextToken(); 473 Expression action = parseExprSingle(); 474 475 478 for (int i = clauseList.size()-1; i>=0; i--) { 479 ForClause fc = (ForClause)clauseList.get(i); 480 Assignation exp; 481 if (operator==Token.FOR) { 482 exp = new ForExpression(); 483 } else { 484 exp = new QuantifiedExpression(); 485 ((QuantifiedExpression)exp).setOperator(operator); 486 } 487 setLocation(exp, offset); 488 exp.setVariableDeclaration(fc.rangeVariable); 489 exp.setSequence(fc.sequence); 490 491 497 if (fc.requiredType == SequenceType.SINGLE_ITEM) { 498 SequenceType type = SequenceType.makeSequenceType( 499 fc.sequence.getItemType(), StaticProperty.EXACTLY_ONE); 500 fc.rangeVariable.setRequiredType(type); 501 } else { 502 fc.rangeVariable.setRequiredType(fc.requiredType); 503 } 504 exp.setAction(action); 505 506 action = exp; 508 } 509 510 512 for (int i = clauseList.size()-1; i>=0; i--) { 513 undeclareRangeVariable(); 514 } 515 return action; 517 } 518 519 520 527 528 private Expression parseIfExpression() throws StaticError { 529 int ifoffset = t.currentTokenStartOffset; 531 nextToken(); 532 Expression condition = parseExpression(); 533 expect(Token.RPAR); 534 nextToken(); 535 int thenoffset = t.currentTokenStartOffset; 536 expect(Token.THEN); 537 nextToken(); 538 Expression thenExp = makeTracer(thenoffset, parseExpression(), Location.THEN_EXPRESSION, -1); 539 int elseoffset = t.currentTokenStartOffset; 540 expect(Token.ELSE); 541 nextToken(); 542 Expression elseExp = makeTracer(elseoffset, parseExprSingle(), Location.ELSE_EXPRESSION, -1); 543 Expression ifExp = new IfExpression(condition, thenExp, elseExp); 544 setLocation(ifExp, ifoffset); 545 return makeTracer(ifoffset, ifExp, Location.IF_EXPRESSION, -1); 546 } 547 548 555 556 private Expression parseInstanceOfExpression() throws StaticError { 557 Expression exp = parseTreatExpression(); 558 if (t.currentToken == Token.INSTANCE_OF) { 559 nextToken(); 560 exp = new InstanceOfExpression(exp, parseSequenceType()); 561 setLocation(exp); 562 } 563 return exp; 564 } 565 566 573 574 private Expression parseTreatExpression() throws StaticError { 575 Expression exp = parseCastableExpression(); 576 if (t.currentToken == Token.TREAT_AS) { 577 nextToken(); 578 SequenceType target = parseSequenceType(); 579 exp = TreatExpression.make(exp, target); 580 setLocation(exp); 581 } 582 return exp; 583 } 584 585 592 593 private Expression parseCastableExpression() throws StaticError { 594 Expression exp = parseCastExpression(); 595 if (t.currentToken == Token.CASTABLE_AS) { 596 nextToken(); 597 expect(Token.NAME); 598 AtomicType at = getAtomicType(t.currentTokenValue); 599 if (at.getFingerprint() == StandardNames.XDT_ANY_ATOMIC_TYPE) { 600 grumble("No value is castable to xdt:anyAtomicType", "XPST0080"); 601 } 602 if (at.getFingerprint() == StandardNames.XS_NOTATION) { 603 grumble("No value is castable to xs:NOTATION", "XPST0080"); 604 } 605 nextToken(); 606 boolean allowEmpty = (t.currentToken == Token.QMARK); 607 if (allowEmpty) { 608 nextToken(); 609 } 610 exp = new CastableExpression(exp, at, allowEmpty); 611 setLocation(exp); 612 } 613 return exp; 614 } 615 616 623 624 private Expression parseCastExpression() throws StaticError { 625 Expression exp = parseUnaryExpression(); 626 if (t.currentToken == Token.CAST_AS) { 627 nextToken(); 628 expect(Token.NAME); 629 AtomicType at = getAtomicType(t.currentTokenValue); 630 if (at.getFingerprint() == StandardNames.XDT_ANY_ATOMIC_TYPE) { 631 grumble("Cannot cast to xdt:anyAtomicType", "XPST0080"); 632 } 633 if (at.getFingerprint() == StandardNames.XS_NOTATION) { 634 grumble("Cannot cast to xs:NOTATION", "XPST0080"); 635 } 636 nextToken(); 637 boolean allowEmpty = (t.currentToken == Token.QMARK); 638 if (allowEmpty) { 639 nextToken(); 640 } 641 exp = new CastExpression(exp, at, allowEmpty); 642 if (((AtomicType)exp.getItemType()).isNamespaceSensitive()) { 644 try { 645 return ((CastExpression)exp).doQNameCast(env); 646 } catch (XPathException e) { 647 grumble(e.getMessage()); 648 } 649 } 650 setLocation(exp); 651 } 652 return exp; 653 } 654 655 663 private AtomicType getAtomicType(String qname) throws StaticError { 664 if (scanOnly) { 665 return Type.STRING_TYPE; 666 } 667 try { 668 String [] parts = Name.getQNameParts(qname); 669 String uri; 670 if ("".equals(parts[0])) { 671 short uriCode = env.getDefaultElementNamespace(); 672 uri = env.getNamePool().getURIFromURICode(uriCode); 673 } else { 674 try { 675 uri = env.getURIForPrefix(parts[0]); 676 } catch (XPathException err) { 677 grumble(err.getMessage()); 678 uri = ""; 679 } 680 } 681 682 boolean builtInNamespace = uri.equals(NamespaceConstant.SCHEMA); 683 if (!builtInNamespace && NamespaceConstant.isXDTNamespace(uri)) { 684 uri = NamespaceConstant.XDT; 685 builtInNamespace = true; 686 } 687 688 if (builtInNamespace) { 689 ItemType t = Type.getBuiltInItemType(uri, parts[1]); 690 if (t == null) { 691 grumble("Unknown atomic type " + qname, "XPST0051"); 692 } 693 if (t instanceof BuiltInAtomicType) { 694 return (AtomicType)t; 701 } else { 702 grumble("The type " + qname + " is not atomic"); 703 } 704 } else if (uri.equals(NamespaceConstant.JAVA_TYPE)) { 705 Class theClass = null; 706 try { 707 String className = parts[1].replace('-', '$'); 708 theClass = env.getConfiguration().getClass(className, false, null); 709 } catch (XPathException err) { 710 grumble("Unknown Java class " + parts[1]); 711 } 712 return new ExternalObjectType(theClass); 713 } else { 714 if (env.isImportedSchema(uri)) { 715 int fp = env.getNamePool().getFingerprint(uri, parts[1]); 716 if (fp == -1) { 717 grumble("Unknown type " + qname); 718 } 719 SchemaType st = env.getConfiguration().getSchemaType(fp); 720 if (st == null) { 721 grumble("Unknown atomic type " + qname); 722 } else if (st instanceof AtomicType) { 723 return (AtomicType)st; 724 } else if (st.isComplexType()) { 725 grumble("Type (" + qname + ") is a complex type"); 726 return null; 727 } else { 728 grumble("Type (" + qname + ") is a list or union type"); 729 return null; 730 } 731 732 } else { 733 if ("".equals(uri)) { 734 grumble("There is no imported schema for the null namespace"); 735 } else { 736 grumble("There is no imported schema for namespace " + uri); 737 } 738 return null; 739 } 740 } 741 grumble("Unknown atomic type " + qname); 742 } catch (QNameException err) { 743 grumble(err.getMessage()); 744 } 745 return null; 746 } 747 757 758 private Expression parseComparisonExpression() throws StaticError { 759 Expression exp = parseRangeExpression(); 760 switch (t.currentToken) { 761 case Token.IS: 762 case Token.PRECEDES: 763 case Token.FOLLOWS: 764 int op = t.currentToken; 765 nextToken(); 766 exp = new IdentityComparison(exp, op, parseRangeExpression()); 767 setLocation(exp); 768 return exp; 769 770 case Token.EQUALS: 771 case Token.NE: 772 case Token.LT: 773 case Token.GT: 774 case Token.LE: 775 case Token.GE: 776 op = t.currentToken; 777 nextToken(); 778 exp = env.getConfiguration().getOptimizer().makeGeneralComparison( 779 exp, op, parseRangeExpression(), env.isInBackwardsCompatibleMode()); 780 setLocation(exp); 781 return exp; 782 783 case Token.FEQ: 784 case Token.FNE: 785 case Token.FLT: 786 case Token.FGT: 787 case Token.FLE: 788 case Token.FGE: 789 op = t.currentToken; 790 nextToken(); 791 exp = new ValueComparison(exp, op, parseRangeExpression()); 792 setLocation(exp); 793 return exp; 794 795 default: 796 return exp; 797 } 798 } 799 800 807 808 private Expression parseRangeExpression() throws StaticError { 809 Expression exp = parseAdditiveExpression(); 810 if (t.currentToken == Token.TO ) { 811 nextToken(); 812 exp = new RangeExpression(exp, Token.TO, parseAdditiveExpression()); 813 setLocation(exp); 814 } 815 return exp; 816 } 817 818 819 820 829 830 protected SequenceType parseSequenceType() throws StaticError { 831 ItemType primaryType; 832 if (t.currentToken == Token.NAME) { 833 primaryType = getAtomicType(t.currentTokenValue); 834 nextToken(); 835 } else if (t.currentToken == Token.NODEKIND) { 836 if (t.currentTokenValue == "item") { 837 nextToken(); 838 expect(Token.RPAR); 839 nextToken(); 840 primaryType = AnyItemType.getInstance(); 841 } else if (t.currentTokenValue == "void" || t.currentTokenValue == "empty-sequence") { 842 nextToken(); 844 expect(Token.RPAR); 845 nextToken(); 846 return SequenceType.makeSequenceType(NoNodeTest.getInstance(), StaticProperty.EMPTY); 847 } else { 849 primaryType = parseKindTest(); 850 } 851 } else { 852 grumble("Expected type name in SequenceType, found " + Token.tokens[t.currentToken]); 853 return null; 854 } 855 856 int occurrenceFlag; 857 switch (t.currentToken) { 858 case Token.STAR: 859 case Token.MULT: 860 occurrenceFlag = StaticProperty.ALLOWS_ZERO_OR_MORE; 862 t.currentToken = Token.RPAR; 864 nextToken(); 865 break; 866 case Token.PLUS: 867 occurrenceFlag = StaticProperty.ALLOWS_ONE_OR_MORE; 868 t.currentToken = Token.RPAR; 870 nextToken(); 871 break; 872 case Token.QMARK: 873 occurrenceFlag = StaticProperty.ALLOWS_ZERO_OR_ONE; 874 t.currentToken = Token.RPAR; 876 nextToken(); 877 break; 878 default: 879 occurrenceFlag = StaticProperty.EXACTLY_ONE; 880 } 881 return SequenceType.makeSequenceType(primaryType, occurrenceFlag); 882 } 883 884 885 892 893 private Expression parseAdditiveExpression() throws StaticError { 894 Expression exp = parseMultiplicativeExpression(); 895 while (t.currentToken == Token.PLUS || 896 t.currentToken == Token.MINUS ) { 897 int op = t.currentToken; 898 nextToken(); 899 exp = new ArithmeticExpression(exp, op, parseMultiplicativeExpression()); 900 setLocation(exp); 901 } 902 return exp; 903 } 904 905 912 913 private Expression parseMultiplicativeExpression() throws StaticError { 914 Expression exp = parseUnionExpression(); 915 while (t.currentToken == Token.MULT || 916 t.currentToken == Token.DIV || 917 t.currentToken == Token.IDIV || 918 t.currentToken == Token.MOD ) { 919 int op = t.currentToken; 920 nextToken(); 921 exp = new ArithmeticExpression(exp, op, parseUnionExpression()); 922 setLocation(exp); 923 } 924 return exp; 925 } 926 927 935 936 private Expression parseUnaryExpression() throws StaticError { 937 Expression exp; 938 switch (t.currentToken) { 939 case Token.MINUS: 940 nextToken(); 941 exp = new ArithmeticExpression(new IntegerValue(0), 942 Token.NEGATE, 943 parseUnaryExpression()); 944 break; 945 case Token.PLUS: 946 nextToken(); 947 exp = new ArithmeticExpression(new IntegerValue(0), 950 Token.PLUS, 951 parseUnaryExpression()); 952 break; 953 case Token.VALIDATE: 954 case Token.VALIDATE_STRICT: 955 case Token.VALIDATE_LAX: 956 exp = parseValidateExpression(); 957 break; 958 case Token.PRAGMA: 959 exp = parseExtensionExpression(); 960 break; 961 default: 962 exp = parsePathExpression(); 963 } 964 setLocation(exp); 965 return exp; 966 } 967 968 975 976 private Expression parseUnionExpression() throws StaticError { 977 Expression exp = parseIntersectExpression(); 978 while (t.currentToken == Token.UNION ) { 979 nextToken(); 980 exp = new VennExpression(exp, Token.UNION, parseIntersectExpression()); 981 setLocation(exp); 982 } 983 return exp; 984 } 985 986 993 994 private Expression parseIntersectExpression() throws StaticError { 995 Expression exp = parseInstanceOfExpression(); 996 while (t.currentToken == Token.INTERSECT || 997 t.currentToken == Token.EXCEPT ) { 998 int op = t.currentToken; 999 nextToken(); 1000 exp = new VennExpression(exp, op, parseInstanceOfExpression()); 1001 setLocation(exp); 1002 } 1003 return exp; 1004 } 1005 1006 1007 1008 1013 1014 private boolean atStartOfRelativePath() { 1015 switch(t.currentToken) { 1016 case Token.AXIS: 1017 case Token.AT: 1018 case Token.NAME: 1019 case Token.PREFIX: 1020 case Token.SUFFIX: 1021 case Token.STAR: 1022 case Token.NODEKIND: 1023 case Token.DOT: 1024 case Token.DOTDOT: 1025 case Token.FUNCTION: 1026 case Token.STRING_LITERAL: 1027 case Token.NUMBER: 1028 case Token.LPAR: 1029 return true; 1030 default: 1031 return false; 1032 } 1033 } 1034 1035 1043 1044 private Expression parsePathExpression() throws StaticError { 1045 switch (t.currentToken) { 1046 case Token.SLASH: 1047 nextToken(); 1048 final RootExpression start = new RootExpression(); 1049 setLocation(start); 1050 if (atStartOfRelativePath()) { 1051 final Expression path = parseRemainingPath(start); 1053 setLocation(path); 1054 return path; 1055 } else { 1056 return start; 1057 } 1058 1059 case Token.SLSL: 1060 nextToken(); 1065 final RootExpression start2 = new RootExpression(); 1076 setLocation(start2); 1077 final AxisExpression axisExp = new AxisExpression(Axis.DESCENDANT_OR_SELF, null); 1078 setLocation(axisExp); 1079 final Expression exp = parseRemainingPath(new PathExpression(start2, axisExp)); 1080 setLocation(exp); 1081 return exp; 1082 default: 1083 return parseRelativePath(); 1084 } 1085 1086 } 1087 1088 1089 1095 1096 protected Expression parseRelativePath() throws StaticError { 1097 Expression exp = parseStepExpression(); 1098 while (t.currentToken == Token.SLASH || 1099 t.currentToken == Token.SLSL ) { 1100 int op = t.currentToken; 1101 nextToken(); 1102 Expression next = parseStepExpression(); 1103 if (op == Token.SLASH) { 1104 exp = new PathExpression(exp, next); 1105 } else { 1106 exp = new PathExpression(exp, 1108 new PathExpression(new AxisExpression(Axis.DESCENDANT_OR_SELF, null), 1109 next)); 1110 } 1111 setLocation(exp); 1112 } 1113 return exp; 1114 } 1115 1116 1125 protected Expression parseRemainingPath(Expression start) throws StaticError { 1126 Expression exp = start; 1127 int op = Token.SLASH; 1128 while (true) { 1129 Expression next = parseStepExpression(); 1130 if (op == Token.SLASH) { 1131 exp = new PathExpression(exp, next); 1132 } else { 1133 exp = new PathExpression(exp, 1135 new PathExpression(new AxisExpression(Axis.DESCENDANT_OR_SELF, null), 1136 next)); 1137 } 1138 setLocation(exp); 1139 op = t.currentToken; 1140 if (op != Token.SLASH && op != Token.SLSL) { 1141 break; 1142 } 1143 nextToken(); 1144 } 1145 return exp; 1146 } 1147 1148 1149 1155 1156 protected Expression parseStepExpression() throws StaticError { 1157 Expression step = parseBasicStep(); 1158 1159 boolean reverse = (step instanceof AxisExpression) && 1162 Axis.isReverse[((AxisExpression)step).getAxis()]; 1163 1164 while (t.currentToken == Token.LSQB) { 1165 nextToken(); 1166 Expression predicate = parseExpression(); 1167 expect(Token.RSQB); 1168 nextToken(); 1169 step = new FilterExpression(step, predicate, env); 1170 setLocation(step); 1171 } 1172 if (reverse) { 1173 return new Reverser(step); 1174 } else { 1175 return step; 1176 } 1177 } 1178 1179 1185 1186 private Expression parseBasicStep() throws StaticError { 1187 switch(t.currentToken) { 1188 case Token.DOLLAR: 1189 nextToken(); 1190 expect(Token.NAME); 1191 String var = t.currentTokenValue; 1192 nextToken(); 1193 1194 if (scanOnly) { 1195 return new ContextItemExpression(); 1196 } 1198 1199 int vtest = makeNameCode(var, false) & 0xfffff; 1200 1201 VariableDeclaration b = findRangeVariable(vtest); 1203 VariableReference ref; 1204 if (b!=null) { 1205 ref = new VariableReference(b); 1206 } else { 1207 try { 1208 ref = new VariableReference(env.bindVariable(vtest)); 1209 } catch (XPathException err) { 1210 grumble("Variable $" + var + " has not been declared"); 1211 ref = null; 1212 } 1213 } 1214 setLocation(ref); 1215 return ref; 1216 1217 case Token.LPAR: 1218 nextToken(); 1219 if (t.currentToken==Token.RPAR) { 1220 nextToken(); 1221 return EmptySequence.getInstance(); 1222 } 1223 Expression seq = parseExpression(); 1224 expect(Token.RPAR); 1225 nextToken(); 1226 return seq; 1227 1228 case Token.STRING_LITERAL: 1229 StringValue literal = makeStringLiteral(t.currentTokenValue); 1230 nextToken(); 1231 return literal; 1232 1233 case Token.NUMBER: 1234 NumericValue number = NumericValue.parseNumber(t.currentTokenValue); 1235 if (number.isNaN()) { 1236 grumble("Invalid numeric literal " + Err.wrap(t.currentTokenValue, Err.VALUE)); 1237 } 1238 nextToken(); 1239 return number; 1240 1241 case Token.FUNCTION: 1242 return parseFunctionCall(); 1243 1244 case Token.DOT: 1245 nextToken(); 1246 Expression cie = new ContextItemExpression(); 1247 setLocation(cie); 1248 return cie; 1249 1250 case Token.DOTDOT: 1251 nextToken(); 1252 Expression pne = new ParentNodeExpression(); 1253 setLocation(pne); 1254 return pne; 1255 1256 case Token.NAME: 1257 case Token.PREFIX: 1258 case Token.SUFFIX: 1259 case Token.STAR: 1260 case Token.NODEKIND: 1261 byte defaultAxis = Axis.CHILD; 1262 if (t.currentToken == Token.NODEKIND && t.currentTokenValue == "attribute") { 1263 defaultAxis = Axis.ATTRIBUTE; 1264 } 1265 AxisExpression ae = new AxisExpression(defaultAxis, parseNodeTest(Type.ELEMENT)); 1266 setLocation(ae); 1267 return ae; 1268 1269 case Token.AT: 1270 nextToken(); 1271 switch(t.currentToken) { 1272 1273 case Token.NAME: 1274 case Token.PREFIX: 1275 case Token.SUFFIX: 1276 case Token.STAR: 1277 case Token.NODEKIND: 1278 AxisExpression ae2 = new AxisExpression(Axis.ATTRIBUTE, parseNodeTest(Type.ATTRIBUTE)); 1279 setLocation(ae2); 1280 return ae2; 1281 1282 default: 1283 grumble("@ must be followed by a NodeTest"); 1284 } 1285 break; 1286 1287 case Token.AXIS: 1288 byte axis; 1289 try { 1290 axis = Axis.getAxisNumber(t.currentTokenValue); 1291 } catch (StaticError err) { 1292 grumble(err.getMessage()); 1293 axis = Axis.CHILD; } 1295 if (axis == Axis.NAMESPACE && language == XQUERY) { 1296 grumble("The namespace axis is not available in XQuery"); 1297 } 1298 short principalNodeType = Axis.principalNodeType[axis]; 1299 nextToken(); 1300 switch (t.currentToken) { 1301 1302 case Token.NAME: 1303 case Token.PREFIX: 1304 case Token.SUFFIX: 1305 case Token.STAR: 1306 case Token.NODEKIND: 1307 Expression ax = new AxisExpression(axis, parseNodeTest(principalNodeType)); 1308 setLocation(ax); 1309 return ax; 1310 1311 default: 1312 grumble("Unexpected token " + currentTokenDisplay() + " after axis name"); 1313 } 1314 break; 1315 1316 case Token.KEYWORD_CURLY: 1317 case Token.ELEMENT_QNAME: 1318 case Token.ATTRIBUTE_QNAME: 1319 case Token.PI_QNAME: 1320 case Token.TAG: 1321 return parseConstructor(); 1322 1323 default: 1324 grumble("Unexpected token " + currentTokenDisplay() + " in path expression"); 1325 } 1327 return null; 1328 } 1329 1330 1338 1339 protected StringValue makeStringLiteral(String currentTokenValue) throws StaticError { 1340 return StringValue.makeStringValue(currentTokenValue); 1341 } 1342 1343 1347 1348 protected Expression parseConstructor() throws StaticError { 1349 grumble("Node constructor expressions are allowed only in XQuery, not in XPath"); 1350 return null; 1351 } 1352 1353 1362 1363 protected NodeTest parseNodeTest(short nodeType) throws StaticError { 1364 int tok = t.currentToken; 1365 String tokv = t.currentTokenValue; 1366 switch (tok) { 1367 case Token.NAME: 1368 nextToken(); 1369 return makeNameTest(nodeType, tokv, nodeType==Type.ELEMENT); 1370 1371 case Token.PREFIX: 1372 nextToken(); 1373 return makeNamespaceTest(nodeType, tokv); 1374 1375 case Token.SUFFIX: 1376 nextToken(); 1377 tokv = t.currentTokenValue; 1378 expect(Token.NAME); 1379 nextToken(); 1380 return makeLocalNameTest(nodeType, tokv); 1381 1382 case Token.STAR: 1383 nextToken(); 1384 return NodeKindTest.makeNodeKindTest(nodeType); 1385 1386 case Token.NODEKIND: 1387 return parseKindTest(); 1388 1389 default: 1390 grumble("Unrecognized node test"); 1391 return null; 1392 } 1393 } 1394 1395 1398 1399 private NodeTest parseKindTest() throws StaticError { 1400 String typeName = t.currentTokenValue; 1401 boolean schemaDeclaration = (typeName.startsWith("schema-")); 1402 int primaryType = getSystemType(typeName); 1403 int nameCode = -1; 1404 int contentType; 1405 boolean empty = false; 1406 nextToken(); 1407 if (t.currentToken == Token.RPAR) { 1408 if (schemaDeclaration) { 1409 grumble("schema-element() and schema-attribute() require a name to be supplied"); 1410 return null; 1411 } 1412 empty = true; 1413 nextToken(); 1414 } 1415 switch (primaryType) { 1416 case Type.ITEM: 1417 grumble("item() is not allowed in a path expression"); 1418 return null; 1419 case Type.NODE: 1420 if (empty) { 1421 return AnyNodeTest.getInstance(); 1422 } else { 1423 grumble("No arguments are allowed in node()"); 1424 return null; 1425 } 1426 case Type.TEXT: 1427 if (empty) { 1428 return NodeKindTest.TEXT; 1429 } else { 1430 grumble("No arguments are allowed in text()"); 1431 return null; 1432 } 1433 case Type.COMMENT: 1434 if (empty) { 1435 return NodeKindTest.COMMENT; 1436 } else { 1437 grumble("No arguments are allowed in comment()"); 1438 return null; 1439 } 1440 case Type.NAMESPACE: 1441 grumble("No node test is defined for namespace nodes"); 1442 return null; 1443 case Type.DOCUMENT: 1444 if (empty) { 1445 return NodeKindTest.DOCUMENT; 1446 } else { 1447 int innerType; 1448 try { 1449 innerType = getSystemType(t.currentTokenValue); 1450 } catch (XPathException err) { 1451 innerType = Type.EMPTY; 1452 } 1453 if (innerType != Type.ELEMENT) { 1454 grumble("Argument to document-node() must be an element type descriptor"); 1455 return null; 1456 } 1457 NodeTest inner = parseKindTest(); 1458 expect(Token.RPAR); 1459 nextToken(); 1460 return new DocumentNodeTest(inner); 1461 } 1462 case Type.PROCESSING_INSTRUCTION: 1463 if (empty) { 1464 return NodeKindTest.PROCESSING_INSTRUCTION; 1465 } else if (t.currentToken == Token.STRING_LITERAL) { 1466 try { 1467 String [] parts = Name.getQNameParts(t.currentTokenValue); 1468 if ("".equals(parts[0])) { 1469 nameCode = makeNameCode(parts[1], false); 1470 } else { 1471 warning("No processing instruction name will ever contain a colon"); 1472 nameCode = env.getNamePool().allocate("prefix", "http://saxon.sf.net/ nonexistent namespace", "___invalid-name"); 1473 } 1474 } catch (QNameException e) { 1475 warning("No processing instruction will ever be named '" + 1476 t.currentTokenValue + "'. " + e.getMessage()); 1477 nameCode = env.getNamePool().allocate("prefix", "http://saxon.sf.net/ nonexistent namespace", "___invalid-name"); 1478 } 1479 } else if (t.currentToken == Token.NAME) { 1480 try { 1481 String [] parts = Name.getQNameParts(t.currentTokenValue); 1482 if ("".equals(parts[0])) { 1483 nameCode = makeNameCode(parts[1], false); 1484 } else { 1485 grumble("Processing instruction name must not contain a colon"); 1486 } 1487 } catch (QNameException e) { 1488 grumble("Invalid processing instruction name. " + e.getMessage()); 1489 } 1490 } else { 1491 grumble("Processing instruction name must be a QName or a string literal"); 1492 } 1493 nextToken(); 1494 expect(Token.RPAR); 1495 nextToken(); 1496 return new NameTest(Type.PROCESSING_INSTRUCTION, nameCode, env.getNamePool()); 1497 1498 case Type.ATTRIBUTE: 1499 1501 case Type.ELEMENT: 1502 String nodeName = ""; 1503 if (empty) { 1504 return NodeKindTest.makeNodeKindTest(primaryType); 1505 } else if (t.currentToken == Token.STAR || t.currentToken == Token.MULT) { 1506 if (schemaDeclaration) { 1508 grumble("schema-element() and schema-attribute() must specify an actual name, not '*'"); 1509 return null; 1510 } 1511 nameCode = -1; 1512 } else if (t.currentToken == Token.NAME) { 1513 nodeName = t.currentTokenValue; 1514 nameCode = makeNameCode(t.currentTokenValue, true); } else { 1516 grumble("Unexpected " + Token.tokens[t.currentToken] + " after '(' in SequenceType"); 1517 } 1518 String suri = null; 1519 if (nameCode != -1) { 1520 suri = env.getNamePool().getURI(nameCode); 1521 } 1522 nextToken(); 1523 if (t.currentToken == Token.SLASH) { 1524 grumble("Schema context paths have been dropped from the language specification"); 1525 } else if (t.currentToken == Token.RPAR) { 1526 nextToken(); 1527 if (nameCode == -1) { 1528 return NodeKindTest.makeNodeKindTest(primaryType); 1530 } else { 1531 NodeTest nameTest = null; 1532 SchemaType schemaType = null; 1533 if (primaryType == Type.ATTRIBUTE) { 1534 if (schemaDeclaration) { 1536 SchemaDeclaration attributeDecl = 1537 env.getConfiguration().getAttributeDeclaration(nameCode & 0xfffff); 1538 if (!env.isImportedSchema(suri)) { 1539 grumble("No schema has been imported for namespace '" + suri + '\''); 1540 } 1541 if (attributeDecl == null) { 1542 grumble("There is no declaration for attribute @" + nodeName + " in an imported schema"); 1543 } else { 1544 schemaType = attributeDecl.getType(); 1545 nameTest = new NameTest(Type.ATTRIBUTE, nameCode, env.getNamePool()); 1546 } 1547 } else { 1548 nameTest = new NameTest(Type.ATTRIBUTE, nameCode, env.getNamePool()); 1549 return nameTest; 1550 } 1551 } else { 1552 if (schemaDeclaration) { 1554 SchemaDeclaration elementDecl = 1555 env.getConfiguration().getElementDeclaration(nameCode & 0xfffff); 1556 if (!env.isImportedSchema(suri)) { 1557 grumble("No schema has been imported for namespace '" + suri + '\''); 1558 } 1559 if (elementDecl == null) { 1560 grumble("There is no declaration for element <" + nodeName + "> in an imported schema"); 1561 } else { 1562 schemaType = elementDecl.getType(); 1563 nameTest = env.getConfiguration().makeSubstitutionGroupTest(elementDecl); 1564 1565 } 1566 } else { 1567 nameTest = new NameTest(Type.ELEMENT, nameCode, env.getNamePool()); 1568 return nameTest; 1569 } 1570 } 1571 ContentTypeTest contentTest = null; 1572 if (schemaType != null) { 1573 contentTest = new ContentTypeTest(primaryType, schemaType, env.getConfiguration()); 1574 } 1575 1576 if (contentTest == null) { 1577 return nameTest; 1578 } else { 1579 return new CombinedNodeTest(nameTest, Token.INTERSECT, contentTest); 1580 } 1581 } 1582 } else if (t.currentToken == Token.COMMA) { 1583 if (schemaDeclaration) { 1584 grumble("schema-element() and schema-attribute() must have one argument only"); 1585 return null; 1586 } 1587 nextToken(); 1588 NodeTest result; 1589 if (t.currentToken == Token.STAR) { 1590 grumble("'*' is no longer permitted as the second argument of element() and attribute()"); 1591 return null; 1592 } else if (t.currentToken == Token.NAME) { 1593 SchemaType schemaType; 1594 contentType = makeNameCode(t.currentTokenValue, true) & 0xfffff; 1595 String uri = env.getNamePool().getURI(contentType); 1596 String lname = env.getNamePool().getLocalName(contentType); 1597 if (uri.equals(NamespaceConstant.SCHEMA) || 1598 NamespaceConstant.isXDTNamespace(uri)) { 1599 schemaType = env.getConfiguration().getSchemaType(contentType); 1600 } else { 1601 if (!env.isImportedSchema(uri)) { 1602 grumble("No schema has been imported for namespace '" + uri + '\''); 1603 } 1604 schemaType = env.getConfiguration().getSchemaType(contentType); 1605 } 1606 if (schemaType == null) { 1607 grumble("Unknown type name " + lname); 1608 } 1609 if (primaryType == Type.ATTRIBUTE && schemaType.isComplexType()) { 1610 grumble("An attribute cannot have a complex type"); 1611 } 1612 ContentTypeTest typeTest = new ContentTypeTest(primaryType, schemaType, env.getConfiguration()); 1613 if (nameCode == -1) { 1614 result = typeTest; 1616 if (primaryType == Type.ATTRIBUTE) { 1617 nextToken(); 1618 } else { 1619 nextToken(); 1621 if (t.currentToken == Token.QMARK) { 1622 typeTest.setNillable(true); 1623 nextToken(); 1624 } 1625 } 1626 } else { 1627 if (primaryType == Type.ATTRIBUTE) { 1628 NodeTest nameTest = new NameTest(Type.ATTRIBUTE, nameCode, env.getNamePool()); 1629 result = new CombinedNodeTest(nameTest, Token.INTERSECT, typeTest); 1630 nextToken(); 1631 } else { 1632 NodeTest nameTest = new NameTest(Type.ELEMENT, nameCode, env.getNamePool()); 1634 result = new CombinedNodeTest(nameTest, Token.INTERSECT, typeTest); 1635 nextToken(); 1636 if (t.currentToken == Token.QMARK) { 1637 typeTest.setNillable(true); 1638 nextToken(); 1639 } 1640 } 1641 } 1642 } else { 1643 grumble("Unexpected " + Token.tokens[t.currentToken] + " after ',' in SequenceType"); 1644 return null; 1645 } 1646 1647 expect(Token.RPAR); 1648 nextToken(); 1649 return result; 1650 } else { 1651 grumble("Expected ')' or ',' in SequenceType"); 1652 } 1653 return null; 1654 default: 1655 grumble("Unknown node kind"); 1657 return null; 1658 } 1659 } 1660 1661 1668 private static int getSystemType(String name) throws StaticError { 1669 if ("item".equals(name)) return Type.ITEM; 1670 else if ("document-node".equals(name)) return Type.DOCUMENT; 1671 else if ("element".equals(name)) return Type.ELEMENT; 1672 else if ("schema-element".equals(name)) return Type.ELEMENT; 1673 else if ("attribute".equals(name)) return Type.ATTRIBUTE; 1674 else if ("schema-attribute".equals(name)) return Type.ATTRIBUTE; 1675 else if ("text".equals(name)) return Type.TEXT; 1676 else if ("comment".equals(name)) return Type.COMMENT; 1677 else if ("processing-instruction".equals(name)) 1678 return Type.PROCESSING_INSTRUCTION; 1679 else if ("namespace".equals(name)) return Type.NAMESPACE; 1680 else if ("node".equals(name)) return Type.NODE; 1681 else if ("empty".equals(name)) return Type.EMPTY; 1682 else throw new StaticError("Unknown type " + name); 1683 } 1684 1685 1692 1693 private Expression parseFunctionCall() throws StaticError { 1694 1695 String fname = t.currentTokenValue; 1696 int offset = t.currentTokenStartOffset; 1697 ArrayList args = new ArrayList (10); 1698 1699 1701 nextToken(); 1702 if (t.currentToken!=Token.RPAR) { 1703 Expression arg = parseExprSingle(); 1704 args.add(arg); 1705 while(t.currentToken==Token.COMMA) { 1706 nextToken(); 1707 arg = parseExprSingle(); 1708 args.add(arg); 1709 } 1710 expect(Token.RPAR); 1711 } 1712 nextToken(); 1713 1714 if (scanOnly) { 1715 return StringValue.EMPTY_STRING; 1716 } 1717 1718 Expression[] arguments = new Expression[args.size()]; 1719 args.toArray(arguments); 1720 1721 String [] parts; 1722 try { 1723 parts = Name.getQNameParts(fname); 1724 } catch (QNameException e) { 1725 grumble("Unknown prefix in function name " + fname + "()"); 1726 return null; 1727 } 1728 String uri; 1729 if ("".equals(parts[0])) { 1730 uri = env.getDefaultFunctionNamespace(); 1731 } else { 1732 try { 1733 uri = env.getURIForPrefix(parts[0]); 1734 } catch (XPathException err) { 1735 grumble(err.getMessage()); 1736 return null; 1737 } 1738 } 1739 int nameCode = env.getNamePool().allocate(parts[0], uri, parts[1]); 1740 if (uri.equals(NamespaceConstant.SCHEMA)) { 1741 ItemType t = Type.getBuiltInItemType(uri, parts[1]); 1742 if (t instanceof BuiltInAtomicType && !env.isAllowedBuiltInType((BuiltInAtomicType)t)) { 1743 warning("The type " + fname + " is not recognized by a Basic XSLT Processor. " + 1744 "Saxon permits it for the time being."); 1745 } 1746 } 1747 Expression fcall; 1748 try { 1749 fcall = env.getFunctionLibrary().bind(nameCode, uri, parts[1], arguments); 1750 } catch (XPathException err) { 1751 if (err.getErrorCodeLocalPart() == null) { 1752 err.setErrorCode("XPST0017"); 1753 } 1754 grumble(err.getMessage(), err.getErrorCodeLocalPart()); 1755 return null; 1756 } 1757 if (fcall == null) { 1758 String msg = "Cannot find a matching " + arguments.length + 1759 "-argument function named " + env.getNamePool().getClarkName(nameCode) + "()"; 1760 if (!env.getConfiguration().isAllowExternalFunctions()) { 1761 msg += ". Note: external function calls have been disabled"; 1762 } 1763 if (env.isInBackwardsCompatibleMode()) { 1764 DynamicError err = new DynamicError(msg); 1766 ErrorExpression exp = new ErrorExpression(err); 1767 setLocation(exp); 1768 return exp; 1769 } 1770 grumble(msg); 1771 } 1772 if (fcall instanceof CastExpression && ((AtomicType)fcall.getItemType()).isNamespaceSensitive()) { 1774 try { 1775 return ((CastExpression)fcall).doQNameCast(env); 1776 } catch (XPathException e) { 1777 grumble(e.getMessage()); 1778 } 1779 } 1780 setLocation(fcall, offset); 1781 for (int a=0; a<arguments.length; a++) { 1782 ((ComputedExpression)fcall).adoptChildExpression(arguments[a]); 1783 } 1784 return makeTracer(offset, fcall, Location.FUNCTION_CALL, nameCode); 1785 1786 } 1787 1788 1789 1793 1801 1802 protected void declareRangeVariable(VariableDeclaration declaration) throws StaticError { 1803 if (rangeVariables == null) { 1804 rangeVariables = new Stack (); 1805 } 1806 rangeVariables.push(declaration); 1807 } 1808 1809 1812 1813 protected void undeclareRangeVariable() { 1814 rangeVariables.pop(); 1815 } 1816 1817 1826 1827 private VariableDeclaration findRangeVariable(int fingerprint) { 1828 if (rangeVariables==null) { 1829 return null; 1830 } 1831 for (int v=rangeVariables.size()-1; v>=0; v--) { 1832 VariableDeclaration b = (VariableDeclaration)rangeVariables.elementAt(v); 1833 if ((b.getNameCode() & 0xfffff) == fingerprint) { 1834 return b; 1835 } 1836 } 1837 return null; } 1839 1840 1844 1845 public Stack getRangeVariableStack() { 1846 return rangeVariables; 1847 } 1848 1849 1853 1854 public void setRangeVariableStack(Stack stack) { 1855 rangeVariables = stack; 1856 } 1857 1858 1862 1863 1870 1871 private Pattern parseUnionPattern() throws StaticError { 1872 Pattern exp1 = parsePathPattern(); 1873 1874 while (t.currentToken == Token.UNION ) { 1875 if (t.currentTokenValue == "union") { 1876 grumble("Union operator in a pattern must be written as '|'"); 1877 } 1878 nextToken(); 1879 Pattern exp2 = parsePathPattern(); 1880 exp1 = new UnionPattern(exp1, exp2); 1881 } 1882 1883 return exp1; 1884 } 1885 1886 1892 1893 private Pattern parsePathPattern() throws StaticError { 1894 1895 Pattern prev = null; 1896 int connector = -1; 1897 boolean rootonly = false; 1898 1899 1901 switch(t.currentToken) { 1902 case Token.SLASH: 1903 connector = t.currentToken; 1904 nextToken(); 1905 prev = new NodeTestPattern(NodeKindTest.makeNodeKindTest(Type.DOCUMENT)); 1906 rootonly = true; 1907 break; 1908 case Token.SLSL: connector = t.currentToken; 1911 nextToken(); 1912 prev = new NodeTestPattern(NodeKindTest.makeNodeKindTest(Type.DOCUMENT)); 1913 rootonly = false; 1914 break; 1915 default: 1916 break; 1917 } 1918 1919 while(true) { 1920 Pattern pat = null; 1921 switch(t.currentToken) { 1922 case Token.AXIS: 1923 if ("child".equals(t.currentTokenValue)) { 1924 nextToken(); 1925 pat = parsePatternStep(Type.ELEMENT); 1926 } else if ("attribute".equals(t.currentTokenValue)) { 1927 nextToken(); 1928 pat = parsePatternStep(Type.ATTRIBUTE); 1929 } else { 1930 grumble("Axis in pattern must be child or attribute"); 1931 } 1932 break; 1933 1934 case Token.STAR: 1935 case Token.NAME: 1936 case Token.PREFIX: 1937 case Token.SUFFIX: 1938 pat = parsePatternStep(Type.ELEMENT); 1939 break; 1940 1941 case Token.NODEKIND: 1942 pat = parsePatternStep(t.currentTokenValue=="attribute" ? Type.ATTRIBUTE : Type.ELEMENT); 1943 break; 1944 1945 case Token.AT: 1946 nextToken(); 1947 pat = parsePatternStep(Type.ATTRIBUTE); 1948 break; 1949 1950 case Token.FUNCTION: if (prev!=null) { 1952 grumble("Function call may appear only at the start of a pattern"); 1953 } 1954 if ("id".equals(t.currentTokenValue)) { 1955 nextToken(); 1956 Expression idValue = null; 1957 if (t.currentToken == Token.STRING_LITERAL) { 1958 idValue = new StringValue(t.currentTokenValue); 1959 } else if (t.currentToken == Token.DOLLAR) { 1960 nextToken(); 1961 expect(Token.NAME); 1962 int varNameCode = makeNameCode(t.currentTokenValue, false) & 0xfffff; 1963 idValue = new VariableReference(env.bindVariable(varNameCode)); 1964 } else { 1965 grumble("id value in pattern must be either a literal or a variable reference"); 1966 } 1967 pat = new IDPattern(idValue); 1968 nextToken(); 1969 expect(Token.RPAR); 1970 nextToken(); 1971 } else if ("key".equals(t.currentTokenValue)) { 1972 nextToken(); 1973 expect(Token.STRING_LITERAL); 1974 String keyname = t.currentTokenValue; 1975 nextToken(); 1976 expect(Token.COMMA); 1977 nextToken(); 1978 Expression idValue = null; 1979 if (t.currentToken == Token.STRING_LITERAL) { 1980 idValue = new StringValue(t.currentTokenValue); 1981 } else if (t.currentToken == Token.DOLLAR) { 1982 nextToken(); 1983 expect(Token.NAME); 1984 int varNameCode = makeNameCode(t.currentTokenValue, false) & 0xfffff; 1985 idValue = new VariableReference(env.bindVariable(varNameCode)); 1986 } else { 1987 grumble("key value must be either a literal or a variable reference"); 1988 } 1989 pat = new KeyPattern(makeNameCode(keyname, false), 1990 idValue); 1991 nextToken(); 1992 expect(Token.RPAR); 1993 nextToken(); 1994 } else { 1995 grumble("The only functions allowed in a pattern are id() and key()"); 1996 } 1997 break; 1998 1999 default: 2000 if (rootonly) { return prev; 2002 } 2003 grumble("Unexpected token in pattern, found " + currentTokenDisplay()); 2004 } 2005 2006 if (prev != null) { 2007 if (connector==Token.SLASH) { 2008 ((LocationPathPattern)pat).parentPattern = prev; 2009 } else { ((LocationPathPattern)pat).ancestorPattern = prev; 2011 } 2012 } 2013 connector = t.currentToken; 2014 rootonly = false; 2015 if (connector == Token.SLASH || connector == Token.SLSL) { 2016 prev = pat; 2017 nextToken(); 2018 } else { 2019 return pat; 2020 } 2021 } 2022 } 2023 2024 2032 2033 private Pattern parsePatternStep(short principalNodeType) throws StaticError { 2034 LocationPathPattern step = new LocationPathPattern(); 2035 NodeTest test = parseNodeTest(principalNodeType); 2036 if (test instanceof AnyNodeTest) { 2037 if (principalNodeType == Type.ELEMENT) { 2039 test = new AnyChildNodePattern(); 2041 } else { 2042 test = NodeKindTest.makeNodeKindTest(principalNodeType); 2044 } 2045 } 2046 2047 2050 int kind = test.getPrimitiveType(); 2051 if (principalNodeType == Type.ELEMENT && 2052 (kind == Type.ATTRIBUTE || kind == Type.NAMESPACE)) { 2053 test = new NoNodeTest(); 2054 } else if (principalNodeType == Type.ATTRIBUTE && 2055 (kind == Type.COMMENT || kind == Type.TEXT || 2056 kind == Type.PROCESSING_INSTRUCTION || kind == Type.ELEMENT || 2057 kind == Type.DOCUMENT)) { 2058 test = new NoNodeTest(); 2059 } 2060 2061 step.nodeTest = test; 2062 parseFilters(step); 2063 return step; 2064 } 2065 2066 2073 2074 private void parseFilters(LocationPathPattern path) throws StaticError { 2075 while (t.currentToken == Token.LSQB) { 2076 nextToken(); 2077 Expression qual = parseExpression(); 2078 expect(Token.RSQB); 2079 nextToken(); 2080 path.addFilter(qual); 2081 } 2082 } 2083 2084 2086 2098 2099 public final int makeNameCode(String qname, boolean useDefault) throws StaticError { 2100 if (scanOnly) { 2101 return -1; 2102 } 2103 try { 2104 String [] parts = Name.getQNameParts(qname); 2105 String prefix = parts[0]; 2106 if ("".equals(prefix)) { 2107 short uricode = 0; 2108 if (useDefault) { 2109 uricode = env.getDefaultElementNamespace(); 2110 } 2111 return env.getNamePool().allocate(prefix, uricode, qname); 2112 } else { 2113 try { 2114 String uri = env.getURIForPrefix(prefix); 2115 if (uri == null) { 2116 grumble("Undeclared namespace prefix " + Err.wrap(prefix)); 2117 return -1; 2118 } 2119 return env.getNamePool().allocate(prefix, uri, parts[1]); 2120 } catch (XPathException err) { 2121 grumble(err.getMessage()); 2122 return -1; 2123 } 2124 } 2125 } catch (QNameException e) { 2126 grumble(e.getMessage()); 2128 return -1; 2129 } 2130 } 2131 2132 2144 2145 public NameTest makeNameTest(short nodeType, String qname, boolean useDefault) 2146 throws StaticError { 2147 int nameCode = makeNameCode(qname, useDefault); 2148 NameTest nt = new NameTest(nodeType, nameCode, env.getNamePool()); 2149 return nt; 2151 } 2152 2153 2162 2163 public NamespaceTest makeNamespaceTest(short nodeType, String prefix) 2164 throws StaticError { 2165 if (scanOnly) { 2166 return new NamespaceTest(env.getNamePool(), nodeType, NamespaceConstant.SAXON); 2168 } 2169 2170 try { 2171 NamespaceTest nt = new NamespaceTest(env.getNamePool(), nodeType, env.getURIForPrefix(prefix)); 2172 return nt; 2174 } catch (XPathException e) { 2175 grumble(e.getMessage()); 2177 return null; 2178 } 2179 } 2180 2181 2190 2191 public LocalNameTest makeLocalNameTest(short nodeType, String localName) 2192 throws StaticError { 2193 if (!XMLChar.isValidNCName(localName)) { 2194 grumble("Local name [" + localName + "] contains invalid characters"); 2195 } 2196 return new LocalNameTest(env.getNamePool(), nodeType, localName); 2197 } 2198 2199 2203 2204 protected void setLocation(Expression exp) { 2205 if (exp instanceof ComputedExpression) { 2206 setLocation(exp, t.currentTokenStartOffset); 2207 } 2208 } 2209 2210 2216 2217 protected void setLocation(Expression exp, int offset) { 2218 int line = t.getLineNumber(offset); 2220 if (exp instanceof ComputedExpression && ((ComputedExpression)exp).getLocationId()==-1) { 2221 int loc = env.getLocationMap().allocateLocationId(env.getSystemId(), line); 2222 ComputedExpression cexp = (ComputedExpression)exp; 2223 cexp.setLocationId(loc); 2224 if (cexp.getParentExpression() == null) { 2226 TemporaryContainer container = new TemporaryContainer(env.getLocationMap(), loc); 2227 cexp.setParentExpression(container); 2228 } 2229 } 2230 } 2231 2232 2235 2236 protected Expression makeTracer(int startOffset, Expression exp, int construct, int objectNameCode) { 2237 if (env.getConfiguration().getTraceListener() != null) { 2238 TraceExpression trace = new TraceExpression(exp); 2239 long lc = t.getLineAndColumn(startOffset); 2240 trace.setLineNumber((int)(lc>>32)); 2241 trace.setColumnNumber((int)(lc&0x7fffffff)); 2242 trace.setSystemId(env.getSystemId()); 2243 trace.setNamespaceResolver(env.getNamespaceResolver()); 2244 trace.setConstructType(construct); 2245 trace.setObjectNameCode(objectNameCode); 2246 return trace; 2247 } else { 2248 return exp; 2249 } 2250 } 2251 2252 2257 2258 protected boolean isKeyword(String s) { 2259 return (t.currentToken == Token.NAME && t.currentTokenValue.equals(s)); 2260 } 2261 2262 public void setScanOnly(boolean scanOnly) { 2263 this.scanOnly = scanOnly; 2264 } 2265 2266 public static class ForClause { 2267 2268 public RangeVariableDeclaration rangeVariable; 2269 public RangeVariableDeclaration positionVariable; 2270 public Expression sequence; 2271 public SequenceType requiredType; 2272 public int offset; 2273 } 2274 2275 protected static class TemporaryContainer implements Container, LocationProvider { 2276 private LocationMap map; 2277 private int locationId; 2278 2279 public TemporaryContainer(LocationMap map, int locationId) { 2280 this.map = map; 2281 this.locationId = locationId; 2282 } 2283 2284 public Executable getExecutable() { 2285 return null; 2286 } 2287 2288 public LocationProvider getLocationProvider() { 2289 return map; 2290 } 2291 2292 public String getPublicId() { 2293 return null; 2294 } 2295 2296 public String getSystemId() { 2297 return map.getSystemId(locationId); 2298 } 2299 2300 public int getLineNumber() { 2301 return map.getLineNumber(locationId); 2302 } 2303 2304 public int getColumnNumber() { 2305 return -1; 2306 } 2307 2308 public String getSystemId(int locationId) { 2309 return getSystemId(); 2310 } 2311 2312 public int getLineNumber(int locationId) { 2313 return getLineNumber(); 2314 } 2315 } 2316 2317} 2318 2319 | Popular Tags |