Source Code Cross Referenced for ExpressionParser.java in  » XML » XPath-Saxon » net » sf » saxon » expr » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » XML » XPath Saxon » net.sf.saxon.expr 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package net.sf.saxon.expr;
0002:
0003:        import net.sf.saxon.Err;
0004:        import net.sf.saxon.event.LocationProvider;
0005:        import net.sf.saxon.instruct.Block;
0006:        import net.sf.saxon.instruct.Executable;
0007:        import net.sf.saxon.instruct.LocationMap;
0008:        import net.sf.saxon.instruct.TraceExpression;
0009:        import net.sf.saxon.om.Axis;
0010:        import net.sf.saxon.om.NameChecker;
0011:        import net.sf.saxon.om.NamespaceConstant;
0012:        import net.sf.saxon.om.QNameException;
0013:        import net.sf.saxon.pattern.*;
0014:        import net.sf.saxon.sort.Reverser;
0015:        import net.sf.saxon.style.StandardNames;
0016:        import net.sf.saxon.trace.Location;
0017:        import net.sf.saxon.trans.DynamicError;
0018:        import net.sf.saxon.trans.StaticError;
0019:        import net.sf.saxon.trans.XPathException;
0020:        import net.sf.saxon.type.*;
0021:        import net.sf.saxon.value.*;
0022:
0023:        import java.io.Serializable;
0024:        import java.util.ArrayList;
0025:        import java.util.List;
0026:        import java.util.Stack;
0027:
0028:        /**
0029:         * Parser for XPath expressions and XSLT patterns.
0030:         *
0031:         * This code was originally inspired by James Clark's xt but has been totally rewritten (several times)
0032:         *
0033:         * @author Michael Kay
0034:         */
0035:
0036:        public class ExpressionParser {
0037:
0038:            protected Tokenizer t;
0039:            protected StaticContext env;
0040:            protected Stack rangeVariables = null;
0041:            // The stack holds a list of range variables that are in scope.
0042:            // Each entry on the stack is a VariableDeclaration object containing details
0043:            // of the variable.
0044:
0045:            protected NameChecker nameChecker;
0046:
0047:            protected boolean scanOnly = false;
0048:            // scanOnly is set to true while attributes in direct element constructors
0049:            // are being processed. We need to parse enclosed expressions in the attribute
0050:            // in order to find the end of the attribute value, but we don't yet know the
0051:            // full namespace context at this stage.
0052:
0053:            protected int language = XPATH; // know which language we are parsing, for diagnostics
0054:            protected static final int XPATH = 0;
0055:            protected static final int XSLT_PATTERN = 1;
0056:            protected static final int SEQUENCE_TYPE = 2;
0057:            protected static final int XQUERY = 3;
0058:
0059:            public ExpressionParser() {
0060:            }
0061:
0062:            public Tokenizer getTokenizer() {
0063:                return t;
0064:            }
0065:
0066:            /**
0067:             * Read the next token, catching any exception thrown by the tokenizer
0068:             */
0069:
0070:            protected void nextToken() throws StaticError {
0071:                try {
0072:                    t.next();
0073:                } catch (StaticError err) {
0074:                    grumble(err.getMessage());
0075:                }
0076:            }
0077:
0078:            /**
0079:             * Expect a given token; fail if the current token is different. Note that this method
0080:             * does not read any tokens.
0081:             *
0082:             * @param token the expected token
0083:             * @throws net.sf.saxon.trans.StaticError if the current token is not the expected
0084:             *     token
0085:             */
0086:
0087:            protected void expect(int token) throws StaticError {
0088:                if (t.currentToken != token)
0089:                    grumble("expected \"" + Token.tokens[token] + "\", found "
0090:                            + currentTokenDisplay());
0091:            }
0092:
0093:            /**
0094:             * Report a syntax error (a static error with error code XP0003)
0095:             * @param message the error message
0096:             * @exception net.sf.saxon.trans.StaticError always thrown: an exception containing the
0097:             *     supplied message
0098:             */
0099:
0100:            protected void grumble(String message) throws StaticError {
0101:                grumble(message, (language == XSLT_PATTERN ? "XTSE0340"
0102:                        : "XPST0003"));
0103:            }
0104:
0105:            /**
0106:             * Report a static error
0107:             *
0108:             * @param message the error message
0109:             * @param errorCode the error code
0110:             * @throws net.sf.saxon.trans.StaticError always thrown: an exception containing the
0111:             *     supplied message
0112:             */
0113:
0114:            protected void grumble(String message, String errorCode)
0115:                    throws StaticError {
0116:                if (errorCode == null) {
0117:                    errorCode = "XPST0003";
0118:                }
0119:                String s = t.recentText();
0120:                int line = t.getLineNumber();
0121:                int column = t.getColumnNumber();
0122:                String lineInfo = (line == 1 ? "" : ("on line " + line + ' '));
0123:                String columnInfo = "at char " + column + ' ';
0124:                String prefix = getLanguage() + " syntax error " + columnInfo
0125:                        + lineInfo
0126:                        + (message.startsWith("...") ? "near" : "in") + ' '
0127:                        + Err.wrap(s) + ":\n    ";
0128:                StaticError err = new StaticError(prefix + message);
0129:                err.setErrorCode(errorCode);
0130:                throw err;
0131:            }
0132:
0133:            /**
0134:             * Output a warning message
0135:             */
0136:
0137:            protected void warning(String message) throws StaticError {
0138:                String s = t.recentText();
0139:                int line = t.getLineNumber();
0140:                String lineInfo = (line == 1 ? "" : ("on line " + line + ' '));
0141:                String prefix = "Warning " + lineInfo
0142:                        + (message.startsWith("...") ? "near" : "in") + ' '
0143:                        + Err.wrap(s) + ":\n    ";
0144:                env.issueWarning(prefix + message, null);
0145:            }
0146:
0147:            /**
0148:             * Get the current language (XPath or XQuery)
0149:             */
0150:
0151:            protected String getLanguage() {
0152:                switch (language) {
0153:                case XPATH:
0154:                    return "XPath";
0155:                case XSLT_PATTERN:
0156:                    return "XSLT Pattern";
0157:                case SEQUENCE_TYPE:
0158:                    return "SequenceType";
0159:                case XQUERY:
0160:                    return "XQuery";
0161:                default:
0162:                    return "XPath";
0163:                }
0164:            }
0165:
0166:            /**
0167:             * Display the current token in an error message
0168:             *
0169:             * @return the display representation of the token
0170:             */
0171:            protected String currentTokenDisplay() {
0172:                if (t.currentToken == Token.NAME) {
0173:                    return "name \"" + t.currentTokenValue + '\"';
0174:                } else if (t.currentToken == Token.UNKNOWN) {
0175:                    return "(unknown token)";
0176:                } else {
0177:                    return '\"' + Token.tokens[t.currentToken] + '\"';
0178:                }
0179:            }
0180:
0181:            /**
0182:             * Parse a string representing an expression
0183:             *
0184:             * @throws net.sf.saxon.trans.StaticError if the expression contains a syntax error
0185:             * @param expression the expression expressed as a String
0186:             * @param start offset within the string where parsing is to start
0187:             * @param terminator character to treat as terminating the expression
0188:             * @param lineNumber location of the start of the expression, for diagnostics
0189:             * @param env the static context for the expression
0190:             * @return an Expression object representing the result of parsing
0191:             */
0192:
0193:            public Expression parse(String expression, int start,
0194:                    int terminator, int lineNumber, StaticContext env)
0195:                    throws StaticError {
0196:                // System.err.println("Parse expression: " + expression);
0197:                this .env = env;
0198:                this .nameChecker = env.getConfiguration().getNameChecker();
0199:                t = new Tokenizer();
0200:                try {
0201:                    t.tokenize(expression, start, -1, lineNumber);
0202:                } catch (StaticError err) {
0203:                    grumble(err.getMessage());
0204:                }
0205:                Expression exp = parseExpression();
0206:                if (t.currentToken != terminator) {
0207:                    if (t.currentToken == Token.EOF
0208:                            && terminator == Token.RCURLY) {
0209:                        grumble(
0210:                                "Missing curly brace after expression in attribute value template",
0211:                                "XTSE0350");
0212:                    } else {
0213:                        grumble("Unexpected token " + currentTokenDisplay()
0214:                                + " beyond end of expression");
0215:                    }
0216:                }
0217:                return exp;
0218:            }
0219:
0220:            /**
0221:             * Parse a string representing an XSLT pattern
0222:             *
0223:             * @throws net.sf.saxon.trans.StaticError if the pattern contains a syntax error
0224:             * @param pattern the pattern expressed as a String
0225:             * @param env the static context for the pattern
0226:             * @return a Pattern object representing the result of parsing
0227:             */
0228:
0229:            public Pattern parsePattern(String pattern, StaticContext env)
0230:                    throws StaticError {
0231:                //System.err.println("Parse pattern: " + pattern);
0232:                this .env = env;
0233:                this .nameChecker = env.getConfiguration().getNameChecker();
0234:                language = XSLT_PATTERN;
0235:                t = new Tokenizer();
0236:                try {
0237:                    t.tokenize(pattern, 0, -1, env.getLineNumber());
0238:                } catch (StaticError err) {
0239:                    grumble(err.getMessage());
0240:                }
0241:                Pattern pat = parseUnionPattern();
0242:                if (t.currentToken != Token.EOF)
0243:                    grumble("Unexpected token " + currentTokenDisplay()
0244:                            + " beyond end of pattern");
0245:                //pat.setStaticContext(env);
0246:                //System.err.println("Parsed [" + pattern + "] to " + pat.getClass() + " default prio = " + pat.getDefaultPriority());
0247:                return pat;
0248:            }
0249:
0250:            /**
0251:             * Parse a string representing a sequence type
0252:             *
0253:             * @param input the string, which should conform to the XPath SequenceType
0254:             *      production
0255:             * @param env the static context
0256:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0257:             * @return a SequenceType object representing the type
0258:             */
0259:
0260:            public SequenceType parseSequenceType(String input,
0261:                    StaticContext env) throws StaticError {
0262:                this .env = env;
0263:                this .nameChecker = env.getConfiguration().getNameChecker();
0264:                language = SEQUENCE_TYPE;
0265:                t = new Tokenizer();
0266:                try {
0267:                    t.tokenize(input, 0, -1, 1);
0268:                } catch (StaticError err) {
0269:                    grumble(err.getMessage());
0270:                }
0271:                SequenceType req = parseSequenceType();
0272:                if (t.currentToken != Token.EOF) {
0273:                    grumble("Unexpected token " + currentTokenDisplay()
0274:                            + " beyond end of SequenceType");
0275:                }
0276:                return req;
0277:            }
0278:
0279:            //////////////////////////////////////////////////////////////////////////////////
0280:            //                     EXPRESSIONS                                              //
0281:            //////////////////////////////////////////////////////////////////////////////////
0282:
0283:            /**
0284:             * Parse a top-level Expression:
0285:             * ExprSingle ( ',' ExprSingle )*
0286:             *
0287:             * @throws net.sf.saxon.trans.StaticError if the expression contains a syntax error
0288:             * @return the Expression object that results from parsing
0289:             */
0290:
0291:            protected Expression parseExpression() throws StaticError {
0292:                Expression exp = parseExprSingle();
0293:                while (t.currentToken == Token.COMMA) {
0294:                    nextToken();
0295:                    exp = Block.makeBlock(exp, parseExpression());
0296:                    setLocation(exp);
0297:                }
0298:                return exp;
0299:            }
0300:
0301:            /**
0302:             * Parse an ExprSingle
0303:             *
0304:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0305:             * @return the resulting subexpression
0306:             */
0307:
0308:            protected Expression parseExprSingle() throws StaticError {
0309:                switch (t.currentToken) {
0310:                case Token.FOR:
0311:                case Token.LET: // XQuery only
0312:                    return parseForExpression();
0313:                case Token.SOME:
0314:                case Token.EVERY:
0315:                    return parseQuantifiedExpression();
0316:                case Token.IF:
0317:                    return parseIfExpression();
0318:                case Token.TYPESWITCH:
0319:                    return parseTypeswitchExpression();
0320:                case Token.VALIDATE:
0321:                case Token.VALIDATE_STRICT:
0322:                case Token.VALIDATE_LAX:
0323:                    return parseValidateExpression();
0324:                case Token.PRAGMA:
0325:                    return parseExtensionExpression();
0326:
0327:                default:
0328:                    return parseOrExpression();
0329:                }
0330:            }
0331:
0332:            /**
0333:             * Parse a Typeswitch Expression.
0334:             * This construct is XQuery-only, so the XPath version of this
0335:             * method throws an error unconditionally
0336:             */
0337:
0338:            protected Expression parseTypeswitchExpression() throws StaticError {
0339:                grumble("typeswitch is not allowed in XPath");
0340:                return null;
0341:            }
0342:
0343:            /**
0344:             * Parse a Validate Expression.
0345:             * This construct is XQuery-only, so the XPath version of this
0346:             * method throws an error unconditionally
0347:             */
0348:
0349:            protected Expression parseValidateExpression() throws StaticError {
0350:                grumble("validate{} expressions are not allowed in XPath");
0351:                return null;
0352:            }
0353:
0354:            /**
0355:             * Parse an Extension Expression
0356:             * This construct is XQuery-only, so the XPath version of this
0357:             * method throws an error unconditionally
0358:             */
0359:
0360:            protected Expression parseExtensionExpression() throws StaticError {
0361:                grumble("extension expressions (#...#) are not allowed in XPath");
0362:                return null;
0363:            }
0364:
0365:            /**
0366:             * Parse an OrExpression:
0367:             * AndExpr ( 'or' AndExpr )*
0368:             *
0369:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0370:             * @return the resulting subexpression
0371:             */
0372:
0373:            private Expression parseOrExpression() throws StaticError {
0374:                Expression exp = parseAndExpression();
0375:                while (t.currentToken == Token.OR) {
0376:                    nextToken();
0377:                    exp = new BooleanExpression(exp, Token.OR,
0378:                            parseAndExpression());
0379:                    setLocation(exp);
0380:                }
0381:                return exp;
0382:            }
0383:
0384:            /**
0385:             * Parse an AndExpr:
0386:             * EqualityExpr ( 'and' EqualityExpr )*
0387:             *
0388:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0389:             * @return the resulting subexpression
0390:             */
0391:
0392:            private Expression parseAndExpression() throws StaticError {
0393:                Expression exp = parseComparisonExpression();
0394:                while (t.currentToken == Token.AND) {
0395:                    nextToken();
0396:                    exp = new BooleanExpression(exp, Token.AND,
0397:                            parseComparisonExpression());
0398:                    setLocation(exp);
0399:                }
0400:                return exp;
0401:            }
0402:
0403:            /**
0404:             * Parse a FOR expression:
0405:             * for $x in expr (',' $y in expr)* 'return' expr
0406:             *
0407:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0408:             * @return the resulting subexpression
0409:             */
0410:
0411:            protected Expression parseForExpression() throws StaticError {
0412:                if (t.currentToken == Token.LET) {
0413:                    grumble("'let' is not supported in XPath");
0414:                }
0415:                return parseMappingExpression();
0416:            }
0417:
0418:            /**
0419:             * Parse a quantified expression:
0420:             * (some|every) $x in expr 'satisfies' expr
0421:             *
0422:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0423:             * @return the resulting subexpression
0424:             */
0425:
0426:            private Expression parseQuantifiedExpression() throws StaticError {
0427:                return parseMappingExpression();
0428:            }
0429:
0430:            /**
0431:             * Parse a mapping expression. This is a common routine that handles
0432:             * XPath for expressions and quantified expressions.
0433:             *
0434:             * <p>Syntax: <br/>
0435:             * (for|some|every) $x in expr (',' $y in expr)* (return|satisfies) expr
0436:             * </p>
0437:             *
0438:             * <p>On entry, the current token indicates whether a for, some, or every
0439:             * expression is expected.</p>
0440:             *
0441:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0442:             * @return the resulting subexpression
0443:             */
0444:
0445:            protected Expression parseMappingExpression() throws StaticError {
0446:                int offset = t.currentTokenStartOffset;
0447:                int operator = t.currentToken;
0448:                List clauseList = new ArrayList(3);
0449:                do {
0450:                    ForClause clause = new ForClause();
0451:                    clause.offset = offset;
0452:                    clause.requiredType = SequenceType.SINGLE_ITEM;
0453:                    clauseList.add(clause);
0454:                    nextToken();
0455:                    expect(Token.DOLLAR);
0456:                    nextToken();
0457:                    expect(Token.NAME);
0458:                    String var = t.currentTokenValue;
0459:
0460:                    // declare the range variable
0461:                    RangeVariableDeclaration v = new RangeVariableDeclaration();
0462:                    v.setNameCode(makeNameCode(var, false));
0463:                    v.setRequiredType(SequenceType.SINGLE_ITEM);
0464:                    v.setVariableName(var);
0465:                    clause.rangeVariable = v;
0466:                    nextToken();
0467:
0468:                    if (isKeyword("as") && "XQuery".equals(getLanguage())) {
0469:                        nextToken();
0470:                        SequenceType type = parseSequenceType();
0471:                        clause.requiredType = type;
0472:                        v.setRequiredType(type);
0473:                        if (type.getCardinality() != StaticProperty.EXACTLY_ONE) {
0474:                            grumble(
0475:                                    "Cardinality of range variable must be exactly one",
0476:                                    "XPTY0004");
0477:                        }
0478:                    }
0479:
0480:                    // "at" clauses are not recognized in XPath
0481:                    clause.positionVariable = null;
0482:
0483:                    // process the "in" clause
0484:                    expect(Token.IN);
0485:                    nextToken();
0486:                    clause.sequence = parseExprSingle();
0487:                    declareRangeVariable(clause.rangeVariable);
0488:
0489:                } while (t.currentToken == Token.COMMA);
0490:
0491:                // process the "return/satisfies" expression (called the "action")
0492:                if (operator == Token.FOR) {
0493:                    expect(Token.RETURN);
0494:                } else {
0495:                    expect(Token.SATISFIES);
0496:                }
0497:                nextToken();
0498:                Expression action = parseExprSingle();
0499:
0500:                // work back through the list of range variables, fixing up all references
0501:                // to the variables in the inner expression
0502:
0503:                final TypeHierarchy th = env.getNamePool().getTypeHierarchy();
0504:                for (int i = clauseList.size() - 1; i >= 0; i--) {
0505:                    ForClause fc = (ForClause) clauseList.get(i);
0506:                    Assignation exp;
0507:                    if (operator == Token.FOR) {
0508:                        exp = new ForExpression();
0509:                    } else {
0510:                        exp = new QuantifiedExpression();
0511:                        ((QuantifiedExpression) exp).setOperator(operator);
0512:                    }
0513:                    setLocation(exp, offset);
0514:                    exp.setVariableDeclaration(fc.rangeVariable);
0515:                    exp.setSequence(fc.sequence);
0516:
0517:                    // Attempt to give the range variable a more precise type, base on analysis of the
0518:                    // "action" expression. This will often be approximate, because variables and function
0519:                    // calls in the action expression have not yet been resolved. We rely on the ability
0520:                    // of all expressions to return some kind of type information even if this is
0521:                    // imprecise.
0522:
0523:                    if (fc.requiredType == SequenceType.SINGLE_ITEM) {
0524:                        SequenceType type = SequenceType.makeSequenceType(
0525:                                fc.sequence.getItemType(th),
0526:                                StaticProperty.EXACTLY_ONE);
0527:                        fc.rangeVariable.setRequiredType(type);
0528:                    } else {
0529:                        fc.rangeVariable.setRequiredType(fc.requiredType);
0530:                    }
0531:                    exp.setAction(action);
0532:
0533:                    // for the next outermost "for" clause, the "action" is this ForExpression
0534:                    action = exp;
0535:                }
0536:
0537:                // undeclare all the range variables
0538:
0539:                for (int i = clauseList.size() - 1; i >= 0; i--) {
0540:                    undeclareRangeVariable();
0541:                }
0542:                //action = makeTracer(offset, action, Location.FOR_EXPRESSION, -1);
0543:                return action;
0544:            }
0545:
0546:            /**
0547:             * Parse an IF expression:
0548:             * if '(' expr ')' 'then' expr 'else' expr
0549:             *
0550:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0551:             * @return the resulting subexpression
0552:             */
0553:
0554:            private Expression parseIfExpression() throws StaticError {
0555:                // left paren already read
0556:                int ifoffset = t.currentTokenStartOffset;
0557:                nextToken();
0558:                Expression condition = parseExpression();
0559:                expect(Token.RPAR);
0560:                nextToken();
0561:                int thenoffset = t.currentTokenStartOffset;
0562:                expect(Token.THEN);
0563:                nextToken();
0564:                Expression thenExp = makeTracer(thenoffset, parseExpression(),
0565:                        Location.THEN_EXPRESSION, -1);
0566:                int elseoffset = t.currentTokenStartOffset;
0567:                expect(Token.ELSE);
0568:                nextToken();
0569:                Expression elseExp = makeTracer(elseoffset, parseExprSingle(),
0570:                        Location.ELSE_EXPRESSION, -1);
0571:                Expression ifExp = new IfExpression(condition, thenExp, elseExp);
0572:                setLocation(ifExp, ifoffset);
0573:                return makeTracer(ifoffset, ifExp, Location.IF_EXPRESSION, -1);
0574:            }
0575:
0576:            /**
0577:             * Parse an "instance of"  expression
0578:             * Expr ("instance" "of") SequenceType
0579:             *
0580:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0581:             * @return the resulting subexpression
0582:             */
0583:
0584:            private Expression parseInstanceOfExpression() throws StaticError {
0585:                Expression exp = parseTreatExpression();
0586:                if (t.currentToken == Token.INSTANCE_OF) {
0587:                    nextToken();
0588:                    exp = new InstanceOfExpression(exp, parseSequenceType());
0589:                    setLocation(exp);
0590:                }
0591:                return exp;
0592:            }
0593:
0594:            /**
0595:             * Parse a "treat as" expression
0596:             * castable-expression ("treat" "as" SequenceType )?
0597:             *
0598:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0599:             * @return the resulting subexpression
0600:             */
0601:
0602:            private Expression parseTreatExpression() throws StaticError {
0603:                Expression exp = parseCastableExpression();
0604:                if (t.currentToken == Token.TREAT_AS) {
0605:                    nextToken();
0606:                    SequenceType target = parseSequenceType();
0607:                    exp = TreatExpression.make(exp, target);
0608:                    setLocation(exp);
0609:                }
0610:                return exp;
0611:            }
0612:
0613:            /**
0614:             * Parse a "castable as" expression
0615:             * Expr "castable as" AtomicType "?"?
0616:             *
0617:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0618:             * @return the resulting subexpression
0619:             */
0620:
0621:            private Expression parseCastableExpression() throws StaticError {
0622:                Expression exp = parseCastExpression();
0623:                if (t.currentToken == Token.CASTABLE_AS) {
0624:                    nextToken();
0625:                    expect(Token.NAME);
0626:                    AtomicType at = getAtomicType(t.currentTokenValue);
0627:                    if (at.getFingerprint() == StandardNames.XDT_ANY_ATOMIC_TYPE) {
0628:                        grumble("No value is castable to xdt:anyAtomicType",
0629:                                "XPST0080");
0630:                    }
0631:                    if (at.getFingerprint() == StandardNames.XS_NOTATION) {
0632:                        grumble("No value is castable to xs:NOTATION",
0633:                                "XPST0080");
0634:                    }
0635:                    nextToken();
0636:                    boolean allowEmpty = (t.currentToken == Token.QMARK);
0637:                    if (allowEmpty) {
0638:                        nextToken();
0639:                    }
0640:                    exp = new CastableExpression(exp, at, allowEmpty);
0641:                    setLocation(exp);
0642:                }
0643:                return exp;
0644:            }
0645:
0646:            /**
0647:             * Parse a "cast as" expression
0648:             * castable-expression ("cast" "as" AtomicType "?"?)
0649:             *
0650:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0651:             * @return the resulting subexpression
0652:             */
0653:
0654:            private Expression parseCastExpression() throws StaticError {
0655:                Expression exp = parseUnaryExpression();
0656:                if (t.currentToken == Token.CAST_AS) {
0657:                    nextToken();
0658:                    expect(Token.NAME);
0659:                    AtomicType at = getAtomicType(t.currentTokenValue);
0660:                    if (at.getFingerprint() == StandardNames.XDT_ANY_ATOMIC_TYPE) {
0661:                        grumble("Cannot cast to xdt:anyAtomicType", "XPST0080");
0662:                    }
0663:                    if (at.getFingerprint() == StandardNames.XS_NOTATION) {
0664:                        grumble("Cannot cast to xs:NOTATION", "XPST0080");
0665:                    }
0666:                    nextToken();
0667:                    boolean allowEmpty = (t.currentToken == Token.QMARK);
0668:                    if (allowEmpty) {
0669:                        nextToken();
0670:                    }
0671:                    exp = new CastExpression(exp, at, allowEmpty);
0672:                    // A QName or NOTATION constructor function must be evaluated now, while we know the namespace context
0673:                    final TypeHierarchy th = env.getNamePool()
0674:                            .getTypeHierarchy();
0675:                    if (((AtomicType) exp.getItemType(th))
0676:                            .isNamespaceSensitive()) {
0677:                        try {
0678:                            return ((CastExpression) exp).doQNameCast(env);
0679:                        } catch (XPathException e) {
0680:                            grumble(e.getMessage());
0681:                        }
0682:                    }
0683:                    setLocation(exp);
0684:                }
0685:                return exp;
0686:            }
0687:
0688:            /**
0689:             * Analyze a token whose expected value is the name of an atomic type,
0690:             * and return the object representing the atomic type.
0691:             * @param qname The lexical QName of the atomic type
0692:             * @return The atomic type
0693:             * @throws net.sf.saxon.trans.StaticError if the QName is invalid or if no atomic type of that
0694:             * name exists as a built-in type or a type in an imported schema
0695:             */
0696:            private AtomicType getAtomicType(String qname) throws StaticError {
0697:                if (scanOnly) {
0698:                    return Type.STRING_TYPE;
0699:                }
0700:                try {
0701:                    String[] parts = nameChecker.getQNameParts(qname);
0702:                    String uri;
0703:                    if ("".equals(parts[0])) {
0704:                        short uriCode = env.getDefaultElementNamespace();
0705:                        uri = env.getNamePool().getURIFromURICode(uriCode);
0706:                    } else {
0707:                        try {
0708:                            uri = env.getURIForPrefix(parts[0]);
0709:                        } catch (XPathException err) {
0710:                            grumble(err.getMessage());
0711:                            uri = "";
0712:                        }
0713:                    }
0714:
0715:                    boolean builtInNamespace = uri
0716:                            .equals(NamespaceConstant.SCHEMA);
0717:                    if (!builtInNamespace
0718:                            && NamespaceConstant.isXDTNamespace(uri)) {
0719:                        uri = NamespaceConstant.XDT;
0720:                        builtInNamespace = true;
0721:                    }
0722:
0723:                    if (builtInNamespace) {
0724:                        ItemType t = Type.getBuiltInItemType(uri, parts[1]);
0725:                        if (t == null) {
0726:                            grumble("Unknown atomic type " + qname, "XPST0051");
0727:                        }
0728:                        if (t instanceof  BuiltInAtomicType) {
0729:                            return (AtomicType) t;
0730:                        } else {
0731:                            grumble("The type " + qname + " is not atomic",
0732:                                    "XPST0051");
0733:                        }
0734:                    } else if (uri.equals(NamespaceConstant.JAVA_TYPE)) {
0735:                        Class theClass = null;
0736:                        try {
0737:                            String className = parts[1].replace('-', '$');
0738:                            theClass = env.getConfiguration().getClass(
0739:                                    className, false, null);
0740:                        } catch (XPathException err) {
0741:                            grumble("Unknown Java class " + parts[1]);
0742:                        }
0743:                        return new ExternalObjectType(theClass);
0744:                    } else {
0745:                        if (env.isImportedSchema(uri)) {
0746:                            int fp = env.getNamePool().getFingerprint(uri,
0747:                                    parts[1]);
0748:                            if (fp == -1) {
0749:                                grumble("Unknown type " + qname);
0750:                            }
0751:                            SchemaType st = env.getConfiguration()
0752:                                    .getSchemaType(fp);
0753:                            if (st == null) {
0754:                                grumble("Unknown atomic type " + qname);
0755:                            } else if (st instanceof  AtomicType) {
0756:                                return (AtomicType) st;
0757:                            } else if (st.isComplexType()) {
0758:                                grumble("Type (" + qname
0759:                                        + ") is a complex type");
0760:                                return null;
0761:                            } else {
0762:                                grumble("Type (" + qname
0763:                                        + ") is a list or union type");
0764:                                return null;
0765:                            }
0766:
0767:                        } else {
0768:                            if ("".equals(uri)) {
0769:                                grumble("There is no imported schema for the null namespace");
0770:                            } else {
0771:                                grumble("There is no imported schema for namespace "
0772:                                        + uri);
0773:                            }
0774:                            return null;
0775:                        }
0776:                    }
0777:                    grumble("Unknown atomic type " + qname);
0778:                } catch (QNameException err) {
0779:                    grumble(err.getMessage());
0780:                }
0781:                return null;
0782:            }
0783:
0784:            /**
0785:             * Parse a ComparisonExpr:<br>
0786:             * RangeExpr ( op RangeExpr )*
0787:             * where op is one of =, <, >, !=, <=, >=,
0788:             * eq, lt, gt, ne, le, ge,
0789:             * is, isnot, <<, >>
0790:             *
0791:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0792:             * @return the resulting subexpression
0793:             */
0794:
0795:            private Expression parseComparisonExpression() throws StaticError {
0796:                Expression exp = parseRangeExpression();
0797:                switch (t.currentToken) {
0798:                case Token.IS:
0799:                case Token.PRECEDES:
0800:                case Token.FOLLOWS:
0801:                    int op = t.currentToken;
0802:                    nextToken();
0803:                    exp = new IdentityComparison(exp, op,
0804:                            parseRangeExpression());
0805:                    setLocation(exp);
0806:                    return exp;
0807:
0808:                case Token.EQUALS:
0809:                case Token.NE:
0810:                case Token.LT:
0811:                case Token.GT:
0812:                case Token.LE:
0813:                case Token.GE:
0814:                    op = t.currentToken;
0815:                    nextToken();
0816:                    exp = env.getConfiguration().getOptimizer()
0817:                            .makeGeneralComparison(exp, op,
0818:                                    parseRangeExpression(),
0819:                                    env.isInBackwardsCompatibleMode());
0820:                    setLocation(exp);
0821:                    return exp;
0822:
0823:                case Token.FEQ:
0824:                case Token.FNE:
0825:                case Token.FLT:
0826:                case Token.FGT:
0827:                case Token.FLE:
0828:                case Token.FGE:
0829:                    op = t.currentToken;
0830:                    nextToken();
0831:                    exp = new ValueComparison(exp, op, parseRangeExpression());
0832:                    setLocation(exp);
0833:                    return exp;
0834:
0835:                default:
0836:                    return exp;
0837:                }
0838:            }
0839:
0840:            /**
0841:             * Parse a RangeExpr:<br>
0842:             * AdditiveExpr ('to' AdditiveExpr )?
0843:             *
0844:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0845:             * @return the resulting subexpression
0846:             */
0847:
0848:            private Expression parseRangeExpression() throws StaticError {
0849:                Expression exp = parseAdditiveExpression();
0850:                if (t.currentToken == Token.TO) {
0851:                    nextToken();
0852:                    exp = new RangeExpression(exp, Token.TO,
0853:                            parseAdditiveExpression());
0854:                    setLocation(exp);
0855:                }
0856:                return exp;
0857:            }
0858:
0859:            /**
0860:             * Parse the sequence type production.
0861:             * Provisionally, we use the syntax (QName | node-kind "()") ( "*" | "+" | "?" )?
0862:             * We also allow "element of type QName" and "attribute of type QName"
0863:             * The QName must be the name of a built-in schema-defined data type.
0864:             *
0865:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0866:             * @return the resulting subexpression
0867:             */
0868:
0869:            protected SequenceType parseSequenceType() throws StaticError {
0870:                ItemType primaryType;
0871:                if (t.currentToken == Token.NAME) {
0872:                    primaryType = getAtomicType(t.currentTokenValue);
0873:                    nextToken();
0874:                } else if (t.currentToken == Token.NODEKIND) {
0875:                    if (t.currentTokenValue == "item") {
0876:                        nextToken();
0877:                        expect(Token.RPAR);
0878:                        nextToken();
0879:                        primaryType = AnyItemType.getInstance();
0880:                    } else if (t.currentTokenValue == "empty-sequence") {
0881:                        nextToken();
0882:                        expect(Token.RPAR);
0883:                        nextToken();
0884:                        return SequenceType.makeSequenceType(NoNodeTest
0885:                                .getInstance(), StaticProperty.EMPTY);
0886:                        // return before trying to read an occurrence indicator
0887:                    } else {
0888:                        primaryType = parseKindTest();
0889:                    }
0890:                } else {
0891:                    grumble("Expected type name in SequenceType, found "
0892:                            + Token.tokens[t.currentToken]);
0893:                    return null;
0894:                }
0895:
0896:                int occurrenceFlag;
0897:                switch (t.currentToken) {
0898:                case Token.STAR:
0899:                case Token.MULT:
0900:                    // "*" will be tokenized different ways depending on what precedes it
0901:                    occurrenceFlag = StaticProperty.ALLOWS_ZERO_OR_MORE;
0902:                    // Make the tokenizer ignore the occurrence indicator when classifying the next token
0903:                    t.currentToken = Token.RPAR;
0904:                    nextToken();
0905:                    break;
0906:                case Token.PLUS:
0907:                    occurrenceFlag = StaticProperty.ALLOWS_ONE_OR_MORE;
0908:                    // Make the tokenizer ignore the occurrence indicator when classifying the next token
0909:                    t.currentToken = Token.RPAR;
0910:                    nextToken();
0911:                    break;
0912:                case Token.QMARK:
0913:                    occurrenceFlag = StaticProperty.ALLOWS_ZERO_OR_ONE;
0914:                    // Make the tokenizer ignore the occurrence indicator when classifying the next token
0915:                    t.currentToken = Token.RPAR;
0916:                    nextToken();
0917:                    break;
0918:                default:
0919:                    occurrenceFlag = StaticProperty.EXACTLY_ONE;
0920:                }
0921:                return SequenceType.makeSequenceType(primaryType,
0922:                        occurrenceFlag);
0923:            }
0924:
0925:            /**
0926:             * Parse an AdditiveExpr:
0927:             * MultiplicativeExpr ( (+|-) MultiplicativeExpr )*
0928:             *
0929:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0930:             * @return the resulting subexpression
0931:             */
0932:
0933:            private Expression parseAdditiveExpression() throws StaticError {
0934:                Expression exp = parseMultiplicativeExpression();
0935:                while (t.currentToken == Token.PLUS
0936:                        || t.currentToken == Token.MINUS) {
0937:                    int op = t.currentToken;
0938:                    nextToken();
0939:                    exp = new ArithmeticExpression(exp, op,
0940:                            parseMultiplicativeExpression());
0941:                    setLocation(exp);
0942:                }
0943:                return exp;
0944:            }
0945:
0946:            /**
0947:             * Parse a MultiplicativeExpr:<br>
0948:             * UnionExpr ( (*|div|idiv|mod) UnionExpr )*
0949:             *
0950:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0951:             * @return the resulting subexpression
0952:             */
0953:
0954:            private Expression parseMultiplicativeExpression()
0955:                    throws StaticError {
0956:                Expression exp = parseUnionExpression();
0957:                while (t.currentToken == Token.MULT
0958:                        || t.currentToken == Token.DIV
0959:                        || t.currentToken == Token.IDIV
0960:                        || t.currentToken == Token.MOD) {
0961:                    int op = t.currentToken;
0962:                    nextToken();
0963:                    exp = new ArithmeticExpression(exp, op,
0964:                            parseUnionExpression());
0965:                    setLocation(exp);
0966:                }
0967:                return exp;
0968:            }
0969:
0970:            /**
0971:             * Parse a UnaryExpr:<br>
0972:             * ('+'|'-')* ValueExpr
0973:             * parsed as ('+'|'-')? UnaryExpr
0974:             *
0975:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
0976:             * @return the resulting subexpression
0977:             */
0978:
0979:            private Expression parseUnaryExpression() throws StaticError {
0980:                Expression exp;
0981:                switch (t.currentToken) {
0982:                case Token.MINUS:
0983:                    nextToken();
0984:                    exp = new ArithmeticExpression(new IntegerValue(0),
0985:                            Token.NEGATE, parseUnaryExpression());
0986:                    break;
0987:                case Token.PLUS:
0988:                    nextToken();
0989:                    // Unary plus: can't ignore it completely, it might be a type error, or it might
0990:                    // force conversion to a number which would affect operations such as "=".
0991:                    exp = new ArithmeticExpression(new IntegerValue(0),
0992:                            Token.PLUS, parseUnaryExpression());
0993:                    break;
0994:                case Token.VALIDATE:
0995:                case Token.VALIDATE_STRICT:
0996:                case Token.VALIDATE_LAX:
0997:                    exp = parseValidateExpression();
0998:                    break;
0999:                case Token.PRAGMA:
1000:                    exp = parseExtensionExpression();
1001:                    break;
1002:                default:
1003:                    exp = parsePathExpression();
1004:                }
1005:                setLocation(exp);
1006:                return exp;
1007:            }
1008:
1009:            /**
1010:             * Parse a UnionExpr:<br>
1011:             * IntersectExceptExpr ( "|" | "union" IntersectExceptExpr )*
1012:             *
1013:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
1014:             * @return the resulting subexpression
1015:             */
1016:
1017:            private Expression parseUnionExpression() throws StaticError {
1018:                Expression exp = parseIntersectExpression();
1019:                while (t.currentToken == Token.UNION) {
1020:                    nextToken();
1021:                    exp = new VennExpression(exp, Token.UNION,
1022:                            parseIntersectExpression());
1023:                    setLocation(exp);
1024:                }
1025:                return exp;
1026:            }
1027:
1028:            /**
1029:             * Parse an IntersectExceptExpr:<br>
1030:             * PathExpr ( ( 'intersect' | 'except') PathExpr )*
1031:             *
1032:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
1033:             * @return the resulting subexpression
1034:             */
1035:
1036:            private Expression parseIntersectExpression() throws StaticError {
1037:                Expression exp = parseInstanceOfExpression();
1038:                while (t.currentToken == Token.INTERSECT
1039:                        || t.currentToken == Token.EXCEPT) {
1040:                    int op = t.currentToken;
1041:                    nextToken();
1042:                    exp = new VennExpression(exp, op,
1043:                            parseInstanceOfExpression());
1044:                    setLocation(exp);
1045:                }
1046:                return exp;
1047:            }
1048:
1049:            /**
1050:             * Test whether the current token is one that can start a RelativePathExpression
1051:             *
1052:             * @return the resulting subexpression
1053:             */
1054:
1055:            private boolean atStartOfRelativePath() {
1056:                switch (t.currentToken) {
1057:                case Token.AXIS:
1058:                case Token.AT:
1059:                case Token.NAME:
1060:                case Token.PREFIX:
1061:                case Token.SUFFIX:
1062:                case Token.STAR:
1063:                case Token.NODEKIND:
1064:                case Token.DOT:
1065:                case Token.DOTDOT:
1066:                case Token.FUNCTION:
1067:                case Token.STRING_LITERAL:
1068:                case Token.NUMBER:
1069:                case Token.LPAR:
1070:                    return true;
1071:                default:
1072:                    return false;
1073:                }
1074:            }
1075:
1076:            /**
1077:             * Parse a PathExpresssion. This includes "true" path expressions such as A/B/C, and also
1078:             * constructs that may start a path expression such as a variable reference $name or a
1079:             * parenthesed expression (A|B). Numeric and string literals also come under this heading.
1080:             *
1081:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
1082:             * @return the resulting subexpression
1083:             */
1084:
1085:            private Expression parsePathExpression() throws StaticError {
1086:                switch (t.currentToken) {
1087:                case Token.SLASH:
1088:                    nextToken();
1089:                    final RootExpression start = new RootExpression();
1090:                    setLocation(start);
1091:                    if (atStartOfRelativePath()) {
1092:                        //final Expression path = new PathExpression(start, parseRelativePath(null));
1093:                        final Expression path = parseRemainingPath(start);
1094:                        setLocation(path);
1095:                        return path;
1096:                    } else {
1097:                        return start;
1098:                    }
1099:
1100:                case Token.SLSL:
1101:                    // The logic for absolute path expressions changed in 8.4 so that //A/B/C parses to
1102:                    // (((root()/descendant-or-self::node())/A)/B)/C rather than
1103:                    // (root()/descendant-or-self::node())/(((A)/B)/C) as previously. This is to allow
1104:                    // the subsequent //A optimization to kick in.
1105:                    nextToken();
1106:                    // add in the implicit descendant-or-self::node() step
1107:                    //            final RootExpression start2 = new RootExpression();
1108:                    //            setLocation(start2);
1109:                    //            final AxisExpression axisExp = new AxisExpression(Axis.DESCENDANT_OR_SELF, null);
1110:                    //            setLocation(axisExp);
1111:                    //            final PathExpression pathExp = new PathExpression(axisExp, parseRelativePath(null));
1112:                    //            setLocation(pathExp);
1113:                    //            final Expression exp = new PathExpression(start2, pathExp);
1114:                    //            setLocation(exp);
1115:                    //            return exp;
1116:                    final RootExpression start2 = new RootExpression();
1117:                    setLocation(start2);
1118:                    final AxisExpression axisExp = new AxisExpression(
1119:                            Axis.DESCENDANT_OR_SELF, null);
1120:                    setLocation(axisExp);
1121:                    final Expression exp = parseRemainingPath(new PathExpression(
1122:                            start2, axisExp));
1123:                    setLocation(exp);
1124:                    return exp;
1125:                default:
1126:                    return parseRelativePath();
1127:                }
1128:
1129:            }
1130:
1131:            /**
1132:             * Parse a relative path (a sequence of steps). Called when the current token immediately
1133:             * follows a separator (/ or //), or an implicit separator (XYZ is equivalent to ./XYZ)
1134:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
1135:             * @return the resulting subexpression
1136:             */
1137:
1138:            protected Expression parseRelativePath() throws StaticError {
1139:                Expression exp = parseStepExpression();
1140:                while (t.currentToken == Token.SLASH
1141:                        || t.currentToken == Token.SLSL) {
1142:                    int op = t.currentToken;
1143:                    nextToken();
1144:                    Expression next = parseStepExpression();
1145:                    if (op == Token.SLASH) {
1146:                        exp = new PathExpression(exp, next);
1147:                    } else {
1148:                        // add implicit descendant-or-self::node() step
1149:                        exp = new PathExpression(exp, new PathExpression(
1150:                                new AxisExpression(Axis.DESCENDANT_OR_SELF,
1151:                                        null), next));
1152:                    }
1153:                    setLocation(exp);
1154:                }
1155:                return exp;
1156:            }
1157:
1158:            /**
1159:             * Parse the remaining steps of an absolute path expression (one starting in "/" or "//"). Note that the
1160:             * token immediately after the "/" or "//" has already been read, and in the case of "/", it has been confirmed
1161:             * that we have a path expression starting with "/" rather than a standalone "/" expression.
1162:             * @param start the initial implicit expression: root() in the case of "/", root()/descendant-or-self::node in
1163:             * the case of "//"
1164:             * @return the completed path expression
1165:             * @throws StaticError
1166:             */
1167:            protected Expression parseRemainingPath(Expression start)
1168:                    throws StaticError {
1169:                Expression exp = start;
1170:                int op = Token.SLASH;
1171:                while (true) {
1172:                    Expression next = parseStepExpression();
1173:                    if (op == Token.SLASH) {
1174:                        exp = new PathExpression(exp, next);
1175:                    } else {
1176:                        // add implicit descendant-or-self::node() step
1177:                        exp = new PathExpression(exp, new PathExpression(
1178:                                new AxisExpression(Axis.DESCENDANT_OR_SELF,
1179:                                        null), next));
1180:                    }
1181:                    setLocation(exp);
1182:                    op = t.currentToken;
1183:                    if (op != Token.SLASH && op != Token.SLSL) {
1184:                        break;
1185:                    }
1186:                    nextToken();
1187:                }
1188:                return exp;
1189:            }
1190:
1191:            /**
1192:             * Parse a step (including an optional sequence of predicates)
1193:             *
1194:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
1195:             * @return the resulting subexpression
1196:             */
1197:
1198:            protected Expression parseStepExpression() throws StaticError {
1199:                Expression step = parseBasicStep();
1200:
1201:                // When the filter is applied to an Axis step, the nodes are considered in
1202:                // axis order. In all other cases they are considered in document order
1203:                boolean reverse = (step instanceof  AxisExpression)
1204:                        && Axis.isReverse[((AxisExpression) step).getAxis()]
1205:                        && ((AxisExpression) step).getAxis() != Axis.SELF;
1206:
1207:                while (t.currentToken == Token.LSQB) {
1208:                    nextToken();
1209:                    Expression predicate = parseExpression();
1210:                    expect(Token.RSQB);
1211:                    nextToken();
1212:                    step = new FilterExpression(step, predicate, env);
1213:                    setLocation(step);
1214:                }
1215:                if (reverse) {
1216:                    return new Reverser(step);
1217:                } else {
1218:                    return step;
1219:                }
1220:            }
1221:
1222:            /**
1223:             * Parse a basic step expression (without the predicates)
1224:             *
1225:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
1226:             * @return the resulting subexpression
1227:             */
1228:
1229:            private Expression parseBasicStep() throws StaticError {
1230:                switch (t.currentToken) {
1231:                case Token.DOLLAR:
1232:                    nextToken();
1233:                    expect(Token.NAME);
1234:                    String var = t.currentTokenValue;
1235:                    nextToken();
1236:
1237:                    if (scanOnly) {
1238:                        return new ContextItemExpression();
1239:                        // don't do any semantic checks during a prescan
1240:                    }
1241:
1242:                    int vtest = makeNameCode(var, false) & 0xfffff;
1243:
1244:                    // See if it's a range variable or a variable in the context
1245:                    VariableDeclaration b = findRangeVariable(vtest);
1246:                    VariableReference ref;
1247:                    if (b != null) {
1248:                        ref = new VariableReference(b);
1249:                    } else {
1250:                        try {
1251:                            ref = env.bindVariable(vtest);
1252:                        } catch (XPathException err) {
1253:                            grumble("Variable $" + var
1254:                                    + " has not been declared", "XPST0008");
1255:                            ref = null;
1256:                        }
1257:                    }
1258:                    setLocation(ref);
1259:                    return ref;
1260:
1261:                case Token.LPAR:
1262:                    nextToken();
1263:                    if (t.currentToken == Token.RPAR) {
1264:                        nextToken();
1265:                        return EmptySequence.getInstance();
1266:                    }
1267:                    Expression seq = parseExpression();
1268:                    expect(Token.RPAR);
1269:                    nextToken();
1270:                    return seq;
1271:
1272:                case Token.STRING_LITERAL:
1273:                    StringValue literal = makeStringLiteral(t.currentTokenValue);
1274:                    nextToken();
1275:                    return literal;
1276:
1277:                case Token.NUMBER:
1278:                    NumericValue number = NumericValue
1279:                            .parseNumber(t.currentTokenValue);
1280:                    if (number.isNaN()) {
1281:                        grumble("Invalid numeric literal "
1282:                                + Err.wrap(t.currentTokenValue, Err.VALUE));
1283:                    }
1284:                    nextToken();
1285:                    return number;
1286:
1287:                case Token.FUNCTION:
1288:                    return parseFunctionCall();
1289:
1290:                case Token.DOT:
1291:                    nextToken();
1292:                    Expression cie = new ContextItemExpression();
1293:                    setLocation(cie);
1294:                    return cie;
1295:
1296:                case Token.DOTDOT:
1297:                    nextToken();
1298:                    Expression pne = new ParentNodeExpression();
1299:                    setLocation(pne);
1300:                    return pne;
1301:
1302:                case Token.NAME:
1303:                case Token.PREFIX:
1304:                case Token.SUFFIX:
1305:                case Token.STAR:
1306:                case Token.NODEKIND:
1307:                    byte defaultAxis = Axis.CHILD;
1308:                    if (t.currentToken == Token.NODEKIND
1309:                            && t.currentTokenValue == "attribute") {
1310:                        defaultAxis = Axis.ATTRIBUTE;
1311:                    }
1312:                    AxisExpression ae = new AxisExpression(defaultAxis,
1313:                            parseNodeTest(Type.ELEMENT));
1314:                    setLocation(ae);
1315:                    return ae;
1316:
1317:                case Token.AT:
1318:                    nextToken();
1319:                    switch (t.currentToken) {
1320:
1321:                    case Token.NAME:
1322:                    case Token.PREFIX:
1323:                    case Token.SUFFIX:
1324:                    case Token.STAR:
1325:                    case Token.NODEKIND:
1326:                        AxisExpression ae2 = new AxisExpression(Axis.ATTRIBUTE,
1327:                                parseNodeTest(Type.ATTRIBUTE));
1328:                        setLocation(ae2);
1329:                        return ae2;
1330:
1331:                    default:
1332:                        grumble("@ must be followed by a NodeTest");
1333:                    }
1334:                    break;
1335:
1336:                case Token.AXIS:
1337:                    byte axis;
1338:                    try {
1339:                        axis = Axis.getAxisNumber(t.currentTokenValue);
1340:                    } catch (StaticError err) {
1341:                        grumble(err.getMessage());
1342:                        axis = Axis.CHILD; // error recovery
1343:                    }
1344:                    if (axis == Axis.NAMESPACE && language == XQUERY) {
1345:                        grumble("The namespace axis is not available in XQuery");
1346:                    }
1347:                    short principalNodeType = Axis.principalNodeType[axis];
1348:                    nextToken();
1349:                    switch (t.currentToken) {
1350:
1351:                    case Token.NAME:
1352:                    case Token.PREFIX:
1353:                    case Token.SUFFIX:
1354:                    case Token.STAR:
1355:                    case Token.NODEKIND:
1356:                        Expression ax = new AxisExpression(axis,
1357:                                parseNodeTest(principalNodeType));
1358:                        setLocation(ax);
1359:                        return ax;
1360:
1361:                    default:
1362:                        grumble("Unexpected token " + currentTokenDisplay()
1363:                                + " after axis name");
1364:                    }
1365:                    break;
1366:
1367:                case Token.KEYWORD_CURLY:
1368:                case Token.ELEMENT_QNAME:
1369:                case Token.ATTRIBUTE_QNAME:
1370:                case Token.PI_QNAME:
1371:                case Token.TAG:
1372:                    return parseConstructor();
1373:
1374:                default:
1375:                    grumble("Unexpected token " + currentTokenDisplay()
1376:                            + " in path expression");
1377:                    //break;
1378:                }
1379:                return null;
1380:            }
1381:
1382:            /**
1383:             * Method to make a string literal from a token identified as a string
1384:             * literal. This is trivial in XPath, but in XQuery the method is overridden
1385:             * to identify pseudo-XML character and entity references. Note that the job of handling
1386:             * doubled string delimiters is done by the tokenizer.
1387:             * @param currentTokenValue
1388:             * @return The string value of the string literal
1389:             */
1390:
1391:            protected StringValue makeStringLiteral(String currentTokenValue)
1392:                    throws StaticError {
1393:                return StringValue.makeStringValue(currentTokenValue);
1394:            }
1395:
1396:            /**
1397:             * Parse a node constructor. This is allowed only in XQuery, so the method throws
1398:             * an error for XPath.
1399:             */
1400:
1401:            protected Expression parseConstructor() throws StaticError {
1402:                grumble("Node constructor expressions are allowed only in XQuery, not in XPath");
1403:                return null;
1404:            }
1405:
1406:            /**
1407:             * Parse a NodeTest.
1408:             * One of QName, prefix:*, *:suffix, *, text(), node(), comment(), or
1409:             * processing-instruction(literal?), or element(~,~), attribute(~,~), etc.
1410:             *
1411:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
1412:             * @param nodeType the node type being sought if one is specified
1413:             * @return the resulting NodeTest object
1414:             */
1415:
1416:            protected NodeTest parseNodeTest(short nodeType) throws StaticError {
1417:                int tok = t.currentToken;
1418:                String tokv = t.currentTokenValue;
1419:                switch (tok) {
1420:                case Token.NAME:
1421:                    nextToken();
1422:                    return makeNameTest(nodeType, tokv,
1423:                            nodeType == Type.ELEMENT);
1424:
1425:                case Token.PREFIX:
1426:                    nextToken();
1427:                    return makeNamespaceTest(nodeType, tokv);
1428:
1429:                case Token.SUFFIX:
1430:                    nextToken();
1431:                    tokv = t.currentTokenValue;
1432:                    expect(Token.NAME);
1433:                    nextToken();
1434:                    return makeLocalNameTest(nodeType, tokv);
1435:
1436:                case Token.STAR:
1437:                    nextToken();
1438:                    return NodeKindTest.makeNodeKindTest(nodeType);
1439:
1440:                case Token.NODEKIND:
1441:                    return parseKindTest();
1442:
1443:                default:
1444:                    grumble("Unrecognized node test");
1445:                    return null;
1446:                }
1447:            }
1448:
1449:            /**
1450:             * Parse a KindTest
1451:             */
1452:
1453:            private NodeTest parseKindTest() throws StaticError {
1454:                String typeName = t.currentTokenValue;
1455:                boolean schemaDeclaration = (typeName.startsWith("schema-"));
1456:                int primaryType = getSystemType(typeName);
1457:                int nameCode = -1;
1458:                int contentType;
1459:                boolean empty = false;
1460:                nextToken();
1461:                if (t.currentToken == Token.RPAR) {
1462:                    if (schemaDeclaration) {
1463:                        grumble("schema-element() and schema-attribute() require a name to be supplied");
1464:                        return null;
1465:                    }
1466:                    empty = true;
1467:                    nextToken();
1468:                }
1469:                switch (primaryType) {
1470:                case Type.ITEM:
1471:                    grumble("item() is not allowed in a path expression");
1472:                    return null;
1473:                case Type.NODE:
1474:                    if (empty) {
1475:                        return AnyNodeTest.getInstance();
1476:                    } else {
1477:                        grumble("No arguments are allowed in node()");
1478:                        return null;
1479:                    }
1480:                case Type.TEXT:
1481:                    if (empty) {
1482:                        return NodeKindTest.TEXT;
1483:                    } else {
1484:                        grumble("No arguments are allowed in text()");
1485:                        return null;
1486:                    }
1487:                case Type.COMMENT:
1488:                    if (empty) {
1489:                        return NodeKindTest.COMMENT;
1490:                    } else {
1491:                        grumble("No arguments are allowed in comment()");
1492:                        return null;
1493:                    }
1494:                case Type.NAMESPACE:
1495:                    grumble("No node test is defined for namespace nodes");
1496:                    return null;
1497:                case Type.DOCUMENT:
1498:                    if (empty) {
1499:                        return NodeKindTest.DOCUMENT;
1500:                    } else {
1501:                        int innerType;
1502:                        try {
1503:                            innerType = getSystemType(t.currentTokenValue);
1504:                        } catch (XPathException err) {
1505:                            innerType = Type.EMPTY;
1506:                        }
1507:                        if (innerType != Type.ELEMENT) {
1508:                            grumble("Argument to document-node() must be an element type descriptor");
1509:                            return null;
1510:                        }
1511:                        NodeTest inner = parseKindTest();
1512:                        expect(Token.RPAR);
1513:                        nextToken();
1514:                        return new DocumentNodeTest(inner);
1515:                    }
1516:                case Type.PROCESSING_INSTRUCTION:
1517:                    if (empty) {
1518:                        return NodeKindTest.PROCESSING_INSTRUCTION;
1519:                    } else if (t.currentToken == Token.STRING_LITERAL) {
1520:                        try {
1521:                            String[] parts = nameChecker
1522:                                    .getQNameParts(t.currentTokenValue);
1523:                            if ("".equals(parts[0])) {
1524:                                nameCode = makeNameCode(parts[1], false);
1525:                            } else {
1526:                                warning("No processing instruction name will ever contain a colon");
1527:                                nameCode = env
1528:                                        .getNamePool()
1529:                                        .allocate(
1530:                                                "prefix",
1531:                                                "http://saxon.sf.net/ nonexistent namespace",
1532:                                                "___invalid-name");
1533:                            }
1534:                        } catch (QNameException e) {
1535:                            warning("No processing instruction will ever be named '"
1536:                                    + t.currentTokenValue
1537:                                    + "'. "
1538:                                    + e.getMessage());
1539:                            nameCode = env
1540:                                    .getNamePool()
1541:                                    .allocate(
1542:                                            "prefix",
1543:                                            "http://saxon.sf.net/ nonexistent namespace",
1544:                                            "___invalid-name");
1545:                        }
1546:                    } else if (t.currentToken == Token.NAME) {
1547:                        try {
1548:                            String[] parts = nameChecker
1549:                                    .getQNameParts(t.currentTokenValue);
1550:                            if ("".equals(parts[0])) {
1551:                                nameCode = makeNameCode(parts[1], false);
1552:                            } else {
1553:                                grumble("Processing instruction name must not contain a colon");
1554:                            }
1555:                        } catch (QNameException e) {
1556:                            grumble("Invalid processing instruction name. "
1557:                                    + e.getMessage());
1558:                        }
1559:                    } else {
1560:                        grumble("Processing instruction name must be a QName or a string literal");
1561:                    }
1562:                    nextToken();
1563:                    expect(Token.RPAR);
1564:                    nextToken();
1565:                    return new NameTest(Type.PROCESSING_INSTRUCTION, nameCode,
1566:                            env.getNamePool());
1567:
1568:                case Type.ATTRIBUTE:
1569:                    // drop through
1570:
1571:                case Type.ELEMENT:
1572:                    String nodeName = "";
1573:                    if (empty) {
1574:                        return NodeKindTest.makeNodeKindTest(primaryType);
1575:                    } else if (t.currentToken == Token.STAR
1576:                            || t.currentToken == Token.MULT) {
1577:                        // allow for both representations of "*" to be safe
1578:                        if (schemaDeclaration) {
1579:                            grumble("schema-element() and schema-attribute() must specify an actual name, not '*'");
1580:                            return null;
1581:                        }
1582:                        nameCode = -1;
1583:                    } else if (t.currentToken == Token.NAME) {
1584:                        nodeName = t.currentTokenValue;
1585:                        nameCode = makeNameCode(t.currentTokenValue,
1586:                                primaryType == Type.ELEMENT); // & 0xfffff;
1587:                    } else {
1588:                        grumble("Unexpected " + Token.tokens[t.currentToken]
1589:                                + " after '(' in SequenceType");
1590:                    }
1591:                    String suri = null;
1592:                    if (nameCode != -1) {
1593:                        suri = env.getNamePool().getURI(nameCode);
1594:                    }
1595:                    nextToken();
1596:                    if (t.currentToken == Token.SLASH) {
1597:                        grumble("Schema context paths have been dropped from the language specification");
1598:                    } else if (t.currentToken == Token.RPAR) {
1599:                        nextToken();
1600:                        if (nameCode == -1) {
1601:                            // element(*) or attribute(*)
1602:                            return NodeKindTest.makeNodeKindTest(primaryType);
1603:                        } else {
1604:                            NodeTest nameTest = null;
1605:                            SchemaType schemaType = null;
1606:                            if (primaryType == Type.ATTRIBUTE) {
1607:                                // attribute(N) or schema-attribute(N)
1608:                                if (schemaDeclaration) {
1609:                                    SchemaDeclaration attributeDecl = env
1610:                                            .getConfiguration()
1611:                                            .getAttributeDeclaration(
1612:                                                    nameCode & 0xfffff);
1613:                                    if (!env.isImportedSchema(suri)) {
1614:                                        grumble("No schema has been imported for namespace '"
1615:                                                + suri + '\'');
1616:                                    }
1617:                                    if (attributeDecl == null) {
1618:                                        grumble("There is no declaration for attribute @"
1619:                                                + nodeName
1620:                                                + " in an imported schema");
1621:                                    } else {
1622:                                        schemaType = attributeDecl.getType();
1623:                                        nameTest = new NameTest(Type.ATTRIBUTE,
1624:                                                nameCode, env.getNamePool());
1625:                                    }
1626:                                } else {
1627:                                    nameTest = new NameTest(Type.ATTRIBUTE,
1628:                                            nameCode, env.getNamePool());
1629:                                    return nameTest;
1630:                                }
1631:                            } else {
1632:                                // element(N) or schema-element(N)
1633:                                if (schemaDeclaration) {
1634:                                    SchemaDeclaration elementDecl = env
1635:                                            .getConfiguration()
1636:                                            .getElementDeclaration(
1637:                                                    nameCode & 0xfffff);
1638:                                    if (!env.isImportedSchema(suri)) {
1639:                                        grumble("No schema has been imported for namespace '"
1640:                                                + suri + '\'');
1641:                                    }
1642:                                    if (elementDecl == null) {
1643:                                        grumble("There is no declaration for element <"
1644:                                                + nodeName
1645:                                                + "> in an imported schema");
1646:                                    } else {
1647:                                        schemaType = elementDecl.getType();
1648:                                        nameTest = env.getConfiguration()
1649:                                                .makeSubstitutionGroupTest(
1650:                                                        elementDecl);
1651:
1652:                                    }
1653:                                } else {
1654:                                    nameTest = new NameTest(Type.ELEMENT,
1655:                                            nameCode, env.getNamePool());
1656:                                    return nameTest;
1657:                                }
1658:                            }
1659:                            ContentTypeTest contentTest = null;
1660:                            if (schemaType != null) {
1661:                                contentTest = new ContentTypeTest(primaryType,
1662:                                        schemaType, env.getConfiguration());
1663:                            }
1664:
1665:                            if (contentTest == null) {
1666:                                return nameTest;
1667:                            } else {
1668:                                return new CombinedNodeTest(nameTest,
1669:                                        Token.INTERSECT, contentTest);
1670:                            }
1671:                        }
1672:                    } else if (t.currentToken == Token.COMMA) {
1673:                        if (schemaDeclaration) {
1674:                            grumble("schema-element() and schema-attribute() must have one argument only");
1675:                            return null;
1676:                        }
1677:                        nextToken();
1678:                        NodeTest result;
1679:                        if (t.currentToken == Token.STAR) {
1680:                            grumble("'*' is no longer permitted as the second argument of element() and attribute()");
1681:                            return null;
1682:                        } else if (t.currentToken == Token.NAME) {
1683:                            SchemaType schemaType;
1684:                            contentType = makeNameCode(t.currentTokenValue,
1685:                                    true) & 0xfffff;
1686:                            String uri = env.getNamePool().getURI(contentType);
1687:                            String lname = env.getNamePool().getLocalName(
1688:                                    contentType);
1689:                            if (uri.equals(NamespaceConstant.SCHEMA)
1690:                                    || NamespaceConstant.isXDTNamespace(uri)) {
1691:                                schemaType = env.getConfiguration()
1692:                                        .getSchemaType(contentType);
1693:                            } else {
1694:                                if (!env.isImportedSchema(uri)) {
1695:                                    grumble("No schema has been imported for namespace '"
1696:                                            + uri + '\'');
1697:                                }
1698:                                schemaType = env.getConfiguration()
1699:                                        .getSchemaType(contentType);
1700:                            }
1701:                            if (schemaType == null) {
1702:                                grumble("Unknown type name " + lname);
1703:                            }
1704:                            if (primaryType == Type.ATTRIBUTE
1705:                                    && schemaType.isComplexType()) {
1706:                                grumble("An attribute cannot have a complex type");
1707:                            }
1708:                            ContentTypeTest typeTest = new ContentTypeTest(
1709:                                    primaryType, schemaType, env
1710:                                            .getConfiguration());
1711:                            if (nameCode == -1) {
1712:                                // this represents element(*,T) or attribute(*,T)
1713:                                result = typeTest;
1714:                                if (primaryType == Type.ATTRIBUTE) {
1715:                                    nextToken();
1716:                                } else {
1717:                                    // assert (primaryType == Type.ELEMENT);
1718:                                    nextToken();
1719:                                    if (t.currentToken == Token.QMARK) {
1720:                                        typeTest.setNillable(true);
1721:                                        nextToken();
1722:                                    }
1723:                                }
1724:                            } else {
1725:                                if (primaryType == Type.ATTRIBUTE) {
1726:                                    NodeTest nameTest = new NameTest(
1727:                                            Type.ATTRIBUTE, nameCode, env
1728:                                                    .getNamePool());
1729:                                    result = new CombinedNodeTest(nameTest,
1730:                                            Token.INTERSECT, typeTest);
1731:                                    nextToken();
1732:                                } else {
1733:                                    // assert (primaryType == Type.ELEMENT);
1734:                                    NodeTest nameTest = new NameTest(
1735:                                            Type.ELEMENT, nameCode, env
1736:                                                    .getNamePool());
1737:                                    result = new CombinedNodeTest(nameTest,
1738:                                            Token.INTERSECT, typeTest);
1739:                                    nextToken();
1740:                                    if (t.currentToken == Token.QMARK) {
1741:                                        typeTest.setNillable(true);
1742:                                        nextToken();
1743:                                    }
1744:                                }
1745:                            }
1746:                        } else {
1747:                            grumble("Unexpected "
1748:                                    + Token.tokens[t.currentToken]
1749:                                    + " after ',' in SequenceType");
1750:                            return null;
1751:                        }
1752:
1753:                        expect(Token.RPAR);
1754:                        nextToken();
1755:                        return result;
1756:                    } else {
1757:                        grumble("Expected ')' or ',' in SequenceType");
1758:                    }
1759:                    return null;
1760:                default:
1761:                    // can't happen!
1762:                    grumble("Unknown node kind");
1763:                    return null;
1764:                }
1765:            }
1766:
1767:            /**
1768:             * Get a system type - that is, one whose name is a keyword rather than a QName. This includes the node
1769:             * kinds such as element and attribute, the generic types node() and item(), and the pseudo-type empty-sequence()
1770:             *
1771:             * @param name
1772:             * @exception net.sf.saxon.trans.StaticError
1773:             */
1774:            private static int getSystemType(String name) throws StaticError {
1775:                if ("item".equals(name))
1776:                    return Type.ITEM;
1777:                else if ("document-node".equals(name))
1778:                    return Type.DOCUMENT;
1779:                else if ("element".equals(name))
1780:                    return Type.ELEMENT;
1781:                else if ("schema-element".equals(name))
1782:                    return Type.ELEMENT;
1783:                else if ("attribute".equals(name))
1784:                    return Type.ATTRIBUTE;
1785:                else if ("schema-attribute".equals(name))
1786:                    return Type.ATTRIBUTE;
1787:                else if ("text".equals(name))
1788:                    return Type.TEXT;
1789:                else if ("comment".equals(name))
1790:                    return Type.COMMENT;
1791:                else if ("processing-instruction".equals(name))
1792:                    return Type.PROCESSING_INSTRUCTION;
1793:                else if ("namespace".equals(name))
1794:                    return Type.NAMESPACE;
1795:                else if ("node".equals(name))
1796:                    return Type.NODE;
1797:                else if ("empty".equals(name))
1798:                    return Type.EMPTY;
1799:                else
1800:                    throw new StaticError("Unknown type " + name);
1801:            }
1802:
1803:            /**
1804:             * Parse a function call
1805:             * function-name '(' ( Expression (',' Expression )* )? ')'
1806:             *
1807:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
1808:             * @return the resulting subexpression
1809:             */
1810:
1811:            private Expression parseFunctionCall() throws StaticError {
1812:
1813:                String fname = t.currentTokenValue;
1814:                int offset = t.currentTokenStartOffset;
1815:                ArrayList args = new ArrayList(10);
1816:
1817:                // the "(" has already been read by the Tokenizer: now parse the arguments
1818:
1819:                nextToken();
1820:                if (t.currentToken != Token.RPAR) {
1821:                    Expression arg = parseExprSingle();
1822:                    args.add(arg);
1823:                    while (t.currentToken == Token.COMMA) {
1824:                        nextToken();
1825:                        arg = parseExprSingle();
1826:                        args.add(arg);
1827:                    }
1828:                    expect(Token.RPAR);
1829:                }
1830:                nextToken();
1831:
1832:                if (scanOnly) {
1833:                    return StringValue.EMPTY_STRING;
1834:                }
1835:
1836:                Expression[] arguments = new Expression[args.size()];
1837:                args.toArray(arguments);
1838:
1839:                String[] parts;
1840:                try {
1841:                    parts = nameChecker.getQNameParts(fname);
1842:                } catch (QNameException e) {
1843:                    grumble("Unknown prefix in function name " + fname + "()");
1844:                    return null;
1845:                }
1846:                String uri;
1847:                if ("".equals(parts[0])) {
1848:                    uri = env.getDefaultFunctionNamespace();
1849:                } else {
1850:                    try {
1851:                        uri = env.getURIForPrefix(parts[0]);
1852:                    } catch (XPathException err) {
1853:                        grumble(err.getMessage());
1854:                        return null;
1855:                    }
1856:                }
1857:                int nameCode = env.getNamePool().allocate(parts[0], uri,
1858:                        parts[1]);
1859:                if (uri.equals(NamespaceConstant.SCHEMA)) {
1860:                    ItemType t = Type.getBuiltInItemType(uri, parts[1]);
1861:                    if (t instanceof  BuiltInAtomicType
1862:                            && !env.isAllowedBuiltInType((BuiltInAtomicType) t)) {
1863:                        warning("The type "
1864:                                + fname
1865:                                + " is not recognized by a Basic XSLT Processor. "
1866:                                + "Saxon permits it for the time being.");
1867:                    }
1868:                }
1869:                Expression fcall;
1870:                try {
1871:                    fcall = env.getFunctionLibrary().bind(nameCode, uri,
1872:                            parts[1], arguments);
1873:                } catch (XPathException err) {
1874:                    if (err.getErrorCodeLocalPart() == null) {
1875:                        err.setErrorCode("XPST0017");
1876:                    }
1877:                    grumble(err.getMessage(), err.getErrorCodeLocalPart());
1878:                    return null;
1879:                }
1880:                if (fcall == null) {
1881:                    String msg = "Cannot find a matching " + arguments.length
1882:                            + "-argument function named "
1883:                            + env.getNamePool().getClarkName(nameCode) + "()";
1884:                    if (!env.getConfiguration().isAllowExternalFunctions()) {
1885:                        msg += ". Note: external function calls have been disabled";
1886:                    }
1887:                    if (env.isInBackwardsCompatibleMode()) {
1888:                        // treat this as a dynamic error to be reported only if the function call is executed
1889:                        DynamicError err = new DynamicError(msg);
1890:                        ErrorExpression exp = new ErrorExpression(err);
1891:                        setLocation(exp);
1892:                        return exp;
1893:                    }
1894:                    grumble(msg);
1895:                }
1896:                // A QName or NOTATION constructor function must be evaluated now, while we know the namespace context
1897:                if (fcall instanceof  CastExpression
1898:                        && ((AtomicType) fcall.getItemType(env.getNamePool()
1899:                                .getTypeHierarchy())).isNamespaceSensitive()) {
1900:                    try {
1901:                        return ((CastExpression) fcall).doQNameCast(env);
1902:                    } catch (XPathException e) {
1903:                        grumble(e.getMessage());
1904:                    }
1905:                }
1906:                setLocation(fcall, offset);
1907:                for (int a = 0; a < arguments.length; a++) {
1908:                    ((ComputedExpression) fcall)
1909:                            .adoptChildExpression(arguments[a]);
1910:                }
1911:                return makeTracer(offset, fcall, Location.FUNCTION_CALL,
1912:                        nameCode);
1913:
1914:            }
1915:
1916:            //////////////////////////////////////////////////////////////////////////////////
1917:            // Routines for handling range variables
1918:            //////////////////////////////////////////////////////////////////////////////////
1919:
1920:            /**
1921:             * Declare a range variable (record its existence within the parser).
1922:             * A range variable is a variable declared within an expression, as distinct
1923:             * from a variable declared in the context.
1924:             *
1925:             * @param declaration the VariableDeclaration to be added to the stack
1926:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
1927:             */
1928:
1929:            protected void declareRangeVariable(VariableDeclaration declaration)
1930:                    throws StaticError {
1931:                if (rangeVariables == null) {
1932:                    rangeVariables = new Stack();
1933:                }
1934:                rangeVariables.push(declaration);
1935:            }
1936:
1937:            /**
1938:             * Note when the most recently declared range variable has gone out of scope
1939:             */
1940:
1941:            protected void undeclareRangeVariable() {
1942:                rangeVariables.pop();
1943:            }
1944:
1945:            /**
1946:             * Locate a range variable with a given name. (By "range variable", we mean a
1947:             * variable declared within the expression where it is used.)
1948:             *
1949:             * @param fingerprint identifies the name of the range variable within the
1950:             *      name pool
1951:             * @return null if not found (this means the variable is probably a
1952:             *     context variable); otherwise the relevant VariableDeclaration
1953:             */
1954:
1955:            private VariableDeclaration findRangeVariable(int fingerprint) {
1956:                if (rangeVariables == null) {
1957:                    return null;
1958:                }
1959:                for (int v = rangeVariables.size() - 1; v >= 0; v--) {
1960:                    VariableDeclaration b = (VariableDeclaration) rangeVariables
1961:                            .elementAt(v);
1962:                    if ((b.getNameCode() & 0xfffff) == fingerprint) {
1963:                        return b;
1964:                    }
1965:                }
1966:                return null; // not an in-scope range variable
1967:            }
1968:
1969:            /**
1970:             * Get the range variable stack. Used when parsing a nested subexpression
1971:             * inside an attribute constructor
1972:             */
1973:
1974:            public Stack getRangeVariableStack() {
1975:                return rangeVariables;
1976:            }
1977:
1978:            /**
1979:             * Set the range variable stack. Used when parsing a nested subexpression
1980:             * inside an attribute constructor.
1981:             */
1982:
1983:            public void setRangeVariableStack(Stack stack) {
1984:                rangeVariables = stack;
1985:            }
1986:
1987:            //////////////////////////////////////////////////////////////////////////////////
1988:            //                     PATTERNS                                                 //
1989:            //////////////////////////////////////////////////////////////////////////////////
1990:
1991:            /**
1992:             * Parse a Union Pattern:<br>
1993:             * pathPattern ( | pathPattern )*
1994:             *
1995:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
1996:             * @return the pattern that results from parsing
1997:             */
1998:
1999:            private Pattern parseUnionPattern() throws StaticError {
2000:                Pattern exp1 = parsePathPattern();
2001:
2002:                while (t.currentToken == Token.UNION) {
2003:                    if (t.currentTokenValue == "union") {
2004:                        grumble("Union operator in a pattern must be written as '|'");
2005:                    }
2006:                    nextToken();
2007:                    Pattern exp2 = parsePathPattern();
2008:                    exp1 = new UnionPattern(exp1, exp2);
2009:                }
2010:
2011:                return exp1;
2012:            }
2013:
2014:            /**
2015:             * Parse a Location Path Pattern:
2016:             *
2017:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
2018:             * @return the pattern that results from parsing
2019:             */
2020:
2021:            private Pattern parsePathPattern() throws StaticError {
2022:
2023:                Pattern prev = null;
2024:                int connector = -1;
2025:                boolean rootonly = false;
2026:
2027:                // special handling of stuff before the first component
2028:
2029:                switch (t.currentToken) {
2030:                case Token.SLASH:
2031:                    connector = t.currentToken;
2032:                    nextToken();
2033:                    prev = new NodeTestPattern(NodeKindTest
2034:                            .makeNodeKindTest(Type.DOCUMENT));
2035:                    rootonly = true;
2036:                    break;
2037:                case Token.SLSL: // leading double slash can't be ignored
2038:                    // because it changes the default priority
2039:                    connector = t.currentToken;
2040:                    nextToken();
2041:                    prev = new NodeTestPattern(NodeKindTest
2042:                            .makeNodeKindTest(Type.DOCUMENT));
2043:                    rootonly = false;
2044:                    break;
2045:                default:
2046:                    break;
2047:                }
2048:
2049:                while (true) {
2050:                    Pattern pat = null;
2051:                    switch (t.currentToken) {
2052:                    case Token.AXIS:
2053:                        if ("child".equals(t.currentTokenValue)) {
2054:                            nextToken();
2055:                            pat = parsePatternStep(Type.ELEMENT);
2056:                        } else if ("attribute".equals(t.currentTokenValue)) {
2057:                            nextToken();
2058:                            pat = parsePatternStep(Type.ATTRIBUTE);
2059:                        } else {
2060:                            grumble("Axis in pattern must be child or attribute");
2061:                        }
2062:                        break;
2063:
2064:                    case Token.STAR:
2065:                    case Token.NAME:
2066:                    case Token.PREFIX:
2067:                    case Token.SUFFIX:
2068:                        pat = parsePatternStep(Type.ELEMENT);
2069:                        break;
2070:
2071:                    case Token.NODEKIND:
2072:                        pat = parsePatternStep(t.currentTokenValue == "attribute" ? Type.ATTRIBUTE
2073:                                : Type.ELEMENT);
2074:                        break;
2075:
2076:                    case Token.AT:
2077:                        nextToken();
2078:                        pat = parsePatternStep(Type.ATTRIBUTE);
2079:                        break;
2080:
2081:                    case Token.FUNCTION: // must be id(literal) or key(literal,literal)
2082:                        if (prev != null) {
2083:                            grumble("Function call may appear only at the start of a pattern");
2084:                        }
2085:                        if ("id".equals(t.currentTokenValue)) {
2086:                            nextToken();
2087:                            Expression idValue = null;
2088:                            if (t.currentToken == Token.STRING_LITERAL) {
2089:                                idValue = new StringValue(t.currentTokenValue);
2090:                            } else if (t.currentToken == Token.DOLLAR) {
2091:                                nextToken();
2092:                                expect(Token.NAME);
2093:                                int varNameCode = makeNameCode(
2094:                                        t.currentTokenValue, false) & 0xfffff;
2095:                                idValue = env.bindVariable(varNameCode);
2096:                            } else {
2097:                                grumble("id value in pattern must be either a literal or a variable reference");
2098:                            }
2099:                            pat = new IDPattern(idValue);
2100:                            nextToken();
2101:                            expect(Token.RPAR);
2102:                            nextToken();
2103:                        } else if ("key".equals(t.currentTokenValue)) {
2104:                            nextToken();
2105:                            expect(Token.STRING_LITERAL);
2106:                            String keyname = t.currentTokenValue;
2107:                            nextToken();
2108:                            expect(Token.COMMA);
2109:                            nextToken();
2110:                            Expression idValue = null;
2111:                            if (t.currentToken == Token.STRING_LITERAL) {
2112:                                idValue = new StringValue(t.currentTokenValue);
2113:                            } else if (t.currentToken == Token.DOLLAR) {
2114:                                nextToken();
2115:                                expect(Token.NAME);
2116:                                int varNameCode = makeNameCode(
2117:                                        t.currentTokenValue, false) & 0xfffff;
2118:                                idValue = env.bindVariable(varNameCode);
2119:                            } else {
2120:                                grumble("key value must be either a literal or a variable reference");
2121:                            }
2122:                            pat = new KeyPattern(makeNameCode(keyname, false),
2123:                                    idValue);
2124:                            nextToken();
2125:                            expect(Token.RPAR);
2126:                            nextToken();
2127:                        } else {
2128:                            grumble("The only functions allowed in a pattern are id() and key()");
2129:                        }
2130:                        break;
2131:
2132:                    default:
2133:                        if (rootonly) { // the pattern was plain '/'
2134:                            return prev;
2135:                        }
2136:                        grumble("Unexpected token in pattern, found "
2137:                                + currentTokenDisplay());
2138:                    }
2139:
2140:                    if (prev != null) {
2141:                        if (connector == Token.SLASH) {
2142:                            ((LocationPathPattern) pat).parentPattern = prev;
2143:                        } else { // connector == SLSL
2144:                            ((LocationPathPattern) pat).ancestorPattern = prev;
2145:                        }
2146:                    }
2147:                    connector = t.currentToken;
2148:                    rootonly = false;
2149:                    if (connector == Token.SLASH || connector == Token.SLSL) {
2150:                        prev = pat;
2151:                        nextToken();
2152:                    } else {
2153:                        return pat;
2154:                    }
2155:                }
2156:            }
2157:
2158:            /**
2159:             * Parse a pattern step (after any axis name or @)
2160:             *
2161:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
2162:             * @param principalNodeType is ELEMENT if we're on the child axis, ATTRIBUTE for
2163:             *     the attribute axis
2164:             * @return the pattern that results from parsing
2165:             */
2166:
2167:            private Pattern parsePatternStep(short principalNodeType)
2168:                    throws StaticError {
2169:                LocationPathPattern step = new LocationPathPattern();
2170:                NodeTest test = parseNodeTest(principalNodeType);
2171:                if (test instanceof  AnyNodeTest) {
2172:                    // handle node() and @node() specially
2173:                    if (principalNodeType == Type.ELEMENT) {
2174:                        // this means we're on the CHILD axis
2175:                        test = new AnyChildNodePattern();
2176:                    } else {
2177:                        // we're on the attribute axis
2178:                        test = NodeKindTest.makeNodeKindTest(principalNodeType);
2179:                    }
2180:                }
2181:
2182:                // Deal with nonsense patterns such as @comment() or child::attribute(). These
2183:                // are legal, but will never match anything.
2184:
2185:                int kind = test.getPrimitiveType();
2186:                if (principalNodeType == Type.ELEMENT
2187:                        && (kind == Type.ATTRIBUTE || kind == Type.NAMESPACE)) {
2188:                    test = new NoNodeTest();
2189:                } else if (principalNodeType == Type.ATTRIBUTE
2190:                        && (kind == Type.COMMENT || kind == Type.TEXT
2191:                                || kind == Type.PROCESSING_INSTRUCTION
2192:                                || kind == Type.ELEMENT || kind == Type.DOCUMENT)) {
2193:                    test = new NoNodeTest();
2194:                }
2195:
2196:                step.nodeTest = test;
2197:                parseFilters(step);
2198:                return step;
2199:            }
2200:
2201:            /**
2202:             * Test to see if there are filters for a Pattern, if so, parse them
2203:             *
2204:             * @param path the LocationPathPattern to which the filters are to be
2205:             *     added
2206:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
2207:             */
2208:
2209:            private void parseFilters(LocationPathPattern path)
2210:                    throws StaticError {
2211:                while (t.currentToken == Token.LSQB) {
2212:                    nextToken();
2213:                    Expression qual = parseExpression();
2214:                    expect(Token.RSQB);
2215:                    nextToken();
2216:                    path.addFilter(qual);
2217:                }
2218:            }
2219:
2220:            // Helper methods to access the static context
2221:
2222:            /**
2223:             * Make a NameCode, using this Element as the context for namespace resolution
2224:             *
2225:             * @throws net.sf.saxon.trans.StaticError if the name is invalid, or the prefix
2226:             *     undeclared
2227:             * @param qname The name as written, in the form "[prefix:]localname"
2228:             * @param useDefault Defines the action when there is no prefix. If
2229:             *      true, use the default namespace URI for element names. If false,
2230:             *     use no namespace URI (as for attribute names).
2231:             * @return the namecode, which can be used to identify this name in the
2232:             *     name pool
2233:             */
2234:
2235:            public final int makeNameCode(String qname, boolean useDefault)
2236:                    throws StaticError {
2237:                if (scanOnly) {
2238:                    return -1;
2239:                }
2240:                try {
2241:                    String[] parts = nameChecker.getQNameParts(qname);
2242:                    String prefix = parts[0];
2243:                    if ("".equals(prefix)) {
2244:                        short uricode = 0;
2245:                        if (useDefault) {
2246:                            uricode = env.getDefaultElementNamespace();
2247:                        }
2248:                        return env.getNamePool().allocate(prefix, uricode,
2249:                                qname);
2250:                    } else {
2251:                        try {
2252:                            String uri = env.getURIForPrefix(prefix);
2253:                            return env.getNamePool().allocate(prefix, uri,
2254:                                    parts[1]);
2255:                        } catch (XPathException err) {
2256:                            grumble(err.getMessage(), err
2257:                                    .getErrorCodeLocalPart());
2258:                            return -1;
2259:                        }
2260:                    }
2261:                } catch (QNameException e) {
2262:                    //throw new XPathException.Static(e.getMessage());
2263:                    grumble(e.getMessage());
2264:                    return -1;
2265:                }
2266:            }
2267:
2268:            /**
2269:             * Make a NameTest, using the static context for namespace resolution
2270:             *
2271:             * @param nodeType the type of node required (identified by a constant in
2272:             *     class Type)
2273:             * @param qname the lexical QName of the required node
2274:             * @param useDefault true if the default namespace should be used when
2275:             *     the QName is unprefixed
2276:             * @throws net.sf.saxon.trans.StaticError if the QName is invalid
2277:             * @return a NameTest, representing a pattern that tests for a node of a
2278:             *     given node kind and a given name
2279:             */
2280:
2281:            public NameTest makeNameTest(short nodeType, String qname,
2282:                    boolean useDefault) throws StaticError {
2283:                int nameCode = makeNameCode(qname, useDefault);
2284:                NameTest nt = new NameTest(nodeType, nameCode, env
2285:                        .getNamePool());
2286:                //nt.setOriginalText(qname);
2287:                return nt;
2288:            }
2289:
2290:            /**
2291:             * Make a NamespaceTest (name:*)
2292:             *
2293:             * @param nodeType integer code identifying the type of node required
2294:             * @param prefix the namespace prefix
2295:             * @throws net.sf.saxon.trans.StaticError if the namespace prefix is not declared
2296:             * @return the NamespaceTest, a pattern that matches all nodes in this
2297:             *     namespace
2298:             */
2299:
2300:            public NamespaceTest makeNamespaceTest(short nodeType, String prefix)
2301:                    throws StaticError {
2302:                if (scanOnly) {
2303:                    // return an arbitrary namespace if we're only doing a syntax check
2304:                    return new NamespaceTest(env.getNamePool(), nodeType,
2305:                            NamespaceConstant.SAXON);
2306:                }
2307:
2308:                try {
2309:                    NamespaceTest nt = new NamespaceTest(env.getNamePool(),
2310:                            nodeType, env.getURIForPrefix(prefix));
2311:                    //nt.setOriginalText(prefix + ":*");
2312:                    return nt;
2313:                } catch (XPathException e) {
2314:                    // env.getURIForPrefix can return a dynamic error
2315:                    grumble(e.getMessage());
2316:                    return null;
2317:                }
2318:            }
2319:
2320:            /**
2321:             * Make a LocalNameTest (*:name)
2322:             *
2323:             * @param nodeType the kind of node to be matched
2324:             * @param localName the requred local name
2325:             * @throws net.sf.saxon.trans.StaticError if the local name is invalid
2326:             * @return a LocalNameTest, a pattern which matches all nodes of a given
2327:             *     local name, regardless of namespace
2328:             */
2329:
2330:            public LocalNameTest makeLocalNameTest(short nodeType,
2331:                    String localName) throws StaticError {
2332:                if (!nameChecker.isValidNCName(localName)) {
2333:                    grumble("Local name [" + localName
2334:                            + "] contains invalid characters");
2335:                }
2336:                return new LocalNameTest(env.getNamePool(), nodeType, localName);
2337:            }
2338:
2339:            /**
2340:             * Set location information on an expression. At present this consists of a simple
2341:             * line number. Needed mainly for XQuery.
2342:             */
2343:
2344:            protected void setLocation(Expression exp) {
2345:                if (exp instanceof  ComputedExpression) {
2346:                    setLocation(exp, t.currentTokenStartOffset);
2347:                }
2348:            }
2349:
2350:            /**
2351:             * Set location information on an expression. At present only the line number
2352:             * is retained. Needed mainly for XQuery. This version of the method supplies an
2353:             * explicit offset (character position within the expression or query), which the tokenizer
2354:             * can convert to a line number and column number.
2355:             */
2356:
2357:            protected void setLocation(Expression exp, int offset) {
2358:                // TODO: we are losing the column position and retaining only the line number
2359:                int line = t.getLineNumber(offset);
2360:                if (exp instanceof  ComputedExpression
2361:                        && ((ComputedExpression) exp).getLocationId() == -1) {
2362:                    int loc = env.getLocationMap().allocateLocationId(
2363:                            env.getSystemId(), line);
2364:                    ComputedExpression cexp = (ComputedExpression) exp;
2365:                    cexp.setLocationId(loc);
2366:                    // add a temporary container to provide location information
2367:                    if (cexp.getParentExpression() == null) {
2368:                        TemporaryContainer container = new TemporaryContainer(
2369:                                env.getLocationMap(), loc);
2370:                        cexp.setParentExpression(container);
2371:                    }
2372:                }
2373:            }
2374:
2375:            /**
2376:             * If tracing, wrap an instruction in a trace instruction
2377:             */
2378:
2379:            protected Expression makeTracer(int startOffset, Expression exp,
2380:                    int construct, int objectNameCode) {
2381:                if (env.getConfiguration().getTraceListener() != null) {
2382:                    TraceExpression trace = new TraceExpression(exp);
2383:                    long lc = t.getLineAndColumn(startOffset);
2384:                    trace.setLineNumber((int) (lc >> 32));
2385:                    trace.setColumnNumber((int) (lc & 0x7fffffff));
2386:                    trace.setSystemId(env.getSystemId());
2387:                    trace.setNamespaceResolver(env.getNamespaceResolver());
2388:                    trace.setConstructType(construct);
2389:                    trace.setObjectNameCode(objectNameCode);
2390:                    return trace;
2391:                } else {
2392:                    return exp;
2393:                }
2394:            }
2395:
2396:            /**
2397:             * Test whether the current token is a given keyword.
2398:             * @param s     The string to be compared with the current token
2399:             * @return true if they are the same
2400:             */
2401:
2402:            protected boolean isKeyword(String s) {
2403:                return (t.currentToken == Token.NAME && t.currentTokenValue
2404:                        .equals(s));
2405:            }
2406:
2407:            public void setScanOnly(boolean scanOnly) {
2408:                this .scanOnly = scanOnly;
2409:            }
2410:
2411:            public static class ForClause {
2412:
2413:                public RangeVariableDeclaration rangeVariable;
2414:                public RangeVariableDeclaration positionVariable;
2415:                public Expression sequence;
2416:                public SequenceType requiredType;
2417:                public int offset;
2418:            }
2419:
2420:            protected static class TemporaryContainer implements  Container,
2421:                    LocationProvider, Serializable {
2422:                private LocationMap map;
2423:                private int locationId;
2424:
2425:                public TemporaryContainer(LocationMap map, int locationId) {
2426:                    this .map = map;
2427:                    this .locationId = locationId;
2428:                }
2429:
2430:                public Executable getExecutable() {
2431:                    return null;
2432:                }
2433:
2434:                public LocationProvider getLocationProvider() {
2435:                    return map;
2436:                }
2437:
2438:                public String getPublicId() {
2439:                    return null;
2440:                }
2441:
2442:                public String getSystemId() {
2443:                    return map.getSystemId(locationId);
2444:                }
2445:
2446:                public int getLineNumber() {
2447:                    return map.getLineNumber(locationId);
2448:                }
2449:
2450:                public int getColumnNumber() {
2451:                    return -1;
2452:                }
2453:
2454:                public String getSystemId(int locationId) {
2455:                    return getSystemId();
2456:                }
2457:
2458:                public int getLineNumber(int locationId) {
2459:                    return getLineNumber();
2460:                }
2461:            }
2462:
2463:        }
2464:
2465:        //
2466:        // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
2467:        // you may not use this file except in compliance with the License. You may obtain a copy of the
2468:        // License at http://www.mozilla.org/MPL/
2469:        //
2470:        // Software distributed under the License is distributed on an "AS IS" basis,
2471:        // WITHOUT WARRANTY OF ANY KIND, either express or implied.
2472:        // See the License for the specific language governing rights and limitations under the License.
2473:        //
2474:        // The Original Code is: all this file.
2475:        //
2476:        // The Initial Developer of the Original Code is Michael H. Kay.
2477:        //
2478:        // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
2479:        //
2480:        // Contributor(s): none.
2481:        //
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.