Source Code Cross Referenced for QueryParser.java in  » XML » XPath-Saxon » net » sf » saxon » query » 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.query 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package net.sf.saxon.query;
0002:
0003:        import net.sf.saxon.Configuration;
0004:        import net.sf.saxon.Err;
0005:        import net.sf.saxon.StandardURIResolver;
0006:        import net.sf.saxon.event.PipelineConfiguration;
0007:        import net.sf.saxon.expr.*;
0008:        import net.sf.saxon.functions.*;
0009:        import net.sf.saxon.instruct.*;
0010:        import net.sf.saxon.om.*;
0011:        import net.sf.saxon.pattern.NodeTest;
0012:        import net.sf.saxon.sort.FixedSortKeyDefinition;
0013:        import net.sf.saxon.sort.IntHashSet;
0014:        import net.sf.saxon.sort.TupleExpression;
0015:        import net.sf.saxon.sort.TupleSorter;
0016:        import net.sf.saxon.style.AttributeValueTemplate;
0017:        import net.sf.saxon.style.StandardNames;
0018:        import net.sf.saxon.trace.Location;
0019:        import net.sf.saxon.trans.IndependentContext;
0020:        import net.sf.saxon.trans.StaticError;
0021:        import net.sf.saxon.trans.XPathException;
0022:        import net.sf.saxon.trans.DynamicError;
0023:        import net.sf.saxon.type.ItemType;
0024:        import net.sf.saxon.type.SchemaType;
0025:        import net.sf.saxon.type.Type;
0026:        import net.sf.saxon.type.TypeHierarchy;
0027:        import net.sf.saxon.value.*;
0028:
0029:        import javax.xml.transform.OutputKeys;
0030:        import javax.xml.transform.TransformerConfigurationException;
0031:        import javax.xml.transform.stream.StreamSource;
0032:        import java.net.URI;
0033:        import java.net.URISyntaxException;
0034:        import java.util.*;
0035:
0036:        /**
0037:         * This class defines extensions to the XPath parser to handle the additional
0038:         * syntax supported in XQuery
0039:         */
0040:        class QueryParser extends ExpressionParser {
0041:
0042:            private boolean preserveSpace = false;
0043:            private boolean defaultEmptyLeast = true;
0044:
0045:            private int errorCount = 0;
0046:            private StaticError firstError = null;
0047:
0048:            protected Executable executable;
0049:
0050:            private boolean foundCopyNamespaces = false;
0051:            private boolean foundBoundarySpaceDeclaration = false;
0052:            private boolean foundOrderingDeclaration = false;
0053:            private boolean foundEmptyOrderingDeclaration = false;
0054:            private boolean foundDefaultCollation = false;
0055:            private boolean foundConstructionDeclaration = false;
0056:            private boolean foundDefaultFunctionNamespace = false;
0057:            private boolean foundDefaultElementNamespace = false;
0058:            private boolean foundBaseURIDeclaration = false;
0059:            private boolean preambleProcessed = false;
0060:
0061:            public Set importedModules = new HashSet(5);
0062:            List namespacesToBeSealed = new ArrayList(10);
0063:            List schemaImports = new ArrayList(5);
0064:            List moduleImports = new ArrayList(5);
0065:
0066:            private Expression defaultValue = null;
0067:
0068:            /**
0069:             * Protected Constructor: this class should be instantiated via the StaticQueryContext
0070:             */
0071:
0072:            protected QueryParser() {
0073:            };
0074:
0075:            /**
0076:             * Create an XQueryExpression
0077:             */
0078:
0079:            public XQueryExpression makeXQueryExpression(String query,
0080:                    StaticQueryContext staticContext, Configuration config)
0081:                    throws XPathException {
0082:                try {
0083:                    if (config.getXMLVersion() == Configuration.XML10) {
0084:                        query = normalizeLineEndings10(query);
0085:                    } else {
0086:                        query = normalizeLineEndings11(query);
0087:                    }
0088:                    Executable exec = new Executable();
0089:
0090:                    Properties outputProps = new Properties();
0091:                    outputProps.setProperty(OutputKeys.METHOD, "xml");
0092:                    outputProps.setProperty(OutputKeys.INDENT, "yes");
0093:                    exec.setDefaultOutputProperties(outputProps);
0094:
0095:                    exec.setLocationMap(new LocationMap());
0096:                    exec.setConfiguration(config);
0097:                    exec.setFunctionLibrary(new ExecutableFunctionLibrary(
0098:                            config));
0099:                    // this will be changed later
0100:                    exec.setHostLanguage(Configuration.XQUERY);
0101:                    setExecutable(exec);
0102:                    staticContext.setExecutable(exec);
0103:                    Expression exp = parseQuery(query, 0, Token.EOF,
0104:                            staticContext);
0105:                    if (exp instanceof  ComputedExpression) {
0106:                        int loc = env.getLocationMap().allocateLocationId(
0107:                                env.getSystemId(), 1);
0108:                        ((ComputedExpression) exp)
0109:                                .setParentExpression(new TemporaryContainer(
0110:                                        staticContext.getLocationMap(), loc));
0111:                    }
0112:                    staticContext.bindUnboundFunctionCalls();
0113:                    exec.fixupQueryModules(staticContext);
0114:                    XQueryExpression queryExp = new XQueryExpression(exp, exec,
0115:                            staticContext, config);
0116:                    exp = queryExp.getExpression();
0117:                    DocumentInstr docInstruction;
0118:                    if (exp instanceof  DocumentInstr) {
0119:                        docInstruction = (DocumentInstr) exp;
0120:                    } else {
0121:                        docInstruction = new DocumentInstr(false, null,
0122:                                staticContext.getSystemId());
0123:                        docInstruction.setContentExpression(exp);
0124:                        setLocation(docInstruction, 1);
0125:                        //makeContentConstructor(exp, docInstruction, 1);
0126:                    }
0127:                    queryExp.setDocumentInstruction(docInstruction);
0128:
0129:                    // Make the function library that's available at run-time (e.g. for saxon:evaluate()). This includes
0130:                    // all user-defined functions regardless of which module they are in
0131:
0132:                    FunctionLibrary userlib = exec.getFunctionLibrary();
0133:                    FunctionLibraryList lib = new FunctionLibraryList();
0134:                    lib.addFunctionLibrary(new SystemFunctionLibrary(
0135:                            SystemFunctionLibrary.XPATH_ONLY));
0136:                    lib.addFunctionLibrary(config.getVendorFunctionLibrary());
0137:                    lib.addFunctionLibrary(new ConstructorFunctionLibrary(
0138:                            config));
0139:                    if (config.isAllowExternalFunctions()) {
0140:                        lib.addFunctionLibrary(config.getExtensionBinder());
0141:                    }
0142:                    lib.addFunctionLibrary(userlib);
0143:                    exec.setFunctionLibrary(lib);
0144:
0145:                    return queryExp;
0146:                } catch (XPathException e) {
0147:                    if (!e.hasBeenReported()) {
0148:                        e = StaticError.makeStaticError(e);
0149:                        reportError((StaticError) e);
0150:                    }
0151:                    throw e;
0152:                }
0153:            }
0154:
0155:            /**
0156:             * Normalize line endings in the source query, according to the XML 1.1 rules.
0157:             */
0158:
0159:            private static String normalizeLineEndings11(String in) {
0160:                if (in.indexOf((char) 0xa) < 0 && in.indexOf((char) 0x85) < 0
0161:                        && in.indexOf((char) 0x2028) < 0) {
0162:                    return in;
0163:                }
0164:                FastStringBuffer sb = new FastStringBuffer(in.length());
0165:                for (int i = 0; i < in.length(); i++) {
0166:                    char ch = in.charAt(i);
0167:                    switch (ch) {
0168:                    case 0x85:
0169:                    case 0x2028:
0170:                        sb.append((char) 0xa);
0171:                        break;
0172:                    case 0xd:
0173:                        if (i < in.length() - 1
0174:                                && (in.charAt(i + 1) == (char) 0xa || in
0175:                                        .charAt(i + 1) == (char) 0x85)) {
0176:                            sb.append((char) 0xa);
0177:                            i++;
0178:                        } else {
0179:                            sb.append((char) 0xa);
0180:                        }
0181:                        break;
0182:                    default:
0183:                        sb.append(ch);
0184:                    }
0185:                }
0186:                return sb.toString();
0187:            }
0188:
0189:            /**
0190:             * Normalize line endings in the source query, according to the XML 1.0 rules.
0191:             */
0192:
0193:            private static String normalizeLineEndings10(String in) {
0194:                if (in.indexOf((char) 0xa) < 0) {
0195:                    return in;
0196:                }
0197:                FastStringBuffer sb = new FastStringBuffer(in.length());
0198:                for (int i = 0; i < in.length(); i++) {
0199:                    char ch = in.charAt(i);
0200:                    switch (ch) {
0201:                    case 0xd:
0202:                        if (i < in.length() - 1
0203:                                && in.charAt(i + 1) == (char) 0xa) {
0204:                            sb.append((char) 0xa);
0205:                            i++;
0206:                        } else {
0207:                            sb.append((char) 0xa);
0208:                        }
0209:                        break;
0210:                    default:
0211:                        sb.append(ch);
0212:                    }
0213:                }
0214:                return sb.toString();
0215:            }
0216:
0217:            /**
0218:             * Get the executable containing this expression.
0219:             */
0220:
0221:            public Executable getExecutable() {
0222:                return executable;
0223:            }
0224:
0225:            /**
0226:             * Set the executable used for this query expression
0227:             */
0228:
0229:            public void setExecutable(Executable exec) {
0230:                executable = exec;
0231:            }
0232:
0233:            /**
0234:             * Parse a top-level Query.
0235:             * Prolog? Expression
0236:             *
0237:             * @param queryString The text of the query
0238:             * @param start       Offset of the start of the query
0239:             * @param terminator  Token expected to follow the query (usually Token.EOF)
0240:             * @param env         The static context
0241:             * @return the Expression object that results from parsing
0242:             * @throws net.sf.saxon.trans.XPathException
0243:             *          if the expression contains a syntax error
0244:             */
0245:
0246:            private Expression parseQuery(String queryString, int start,
0247:                    int terminator, StaticQueryContext env)
0248:                    throws XPathException {
0249:                this .env = env;
0250:                this .nameChecker = env.getConfiguration().getNameChecker();
0251:                this .language = XQUERY;
0252:                t = new Tokenizer();
0253:                try {
0254:                    t.tokenize(queryString, start, -1, 1);
0255:                } catch (StaticError err) {
0256:                    grumble(err.getMessage());
0257:                }
0258:                parseVersionDeclaration();
0259:                parseProlog();
0260:                processPreamble();
0261:                Expression exp = parseExpression();
0262:                if (t.currentToken != terminator) {
0263:                    grumble("Unexpected token " + currentTokenDisplay()
0264:                            + " beyond end of query");
0265:                }
0266:                setLocation(exp);
0267:                if (errorCount == 0) {
0268:                    return exp;
0269:                } else {
0270:                    StaticError err = new StaticError(
0271:                            "One or more static errors were reported during query analysis");
0272:                    err.setHasBeenReported();
0273:                    err.setErrorCode(firstError.getErrorCodeLocalPart()); // largely for the XQTS test driver
0274:                    throw err;
0275:                }
0276:            }
0277:
0278:            /**
0279:             * Parse a library module.
0280:             * Prolog? Expression
0281:             *
0282:             * @param queryString The text of the library module.
0283:             * @param env         The static context. The result of parsing
0284:             *                    a library module is that the static context is populated with a set of function
0285:             *                    declarations and variable declarations. Each library module must have its own
0286:             *                    static context objext.
0287:             * @throws net.sf.saxon.trans.StaticError if the expression contains a syntax error
0288:             */
0289:
0290:            public final void parseLibraryModule(String queryString,
0291:                    StaticQueryContext env) throws StaticError {
0292:                this .env = env;
0293:                this .nameChecker = env.getConfiguration().getNameChecker();
0294:                this .executable = env.getExecutable();
0295:                t = new Tokenizer();
0296:                try {
0297:                    t.tokenize(queryString, 0, -1, 1);
0298:                } catch (StaticError err) {
0299:                    grumble(err.getMessage());
0300:                }
0301:                parseVersionDeclaration();
0302:                parseModuleDeclaration();
0303:                parseProlog();
0304:                processPreamble();
0305:                if (t.currentToken != Token.EOF) {
0306:                    grumble("Unrecognized content found after the variable and function declarations in a library module");
0307:                }
0308:                if (errorCount != 0) {
0309:                    throw new StaticError(
0310:                            "Static errors were reported in the imported library module");
0311:                }
0312:            }
0313:
0314:            /**
0315:             * Report a static error
0316:             *
0317:             * @param message the error message
0318:             * @throws net.sf.saxon.trans.StaticError always thrown: an exception containing the
0319:             *                                        supplied message
0320:             */
0321:
0322:            protected void grumble(String message, String errorCode)
0323:                    throws StaticError {
0324:                String s = t.recentText();
0325:                ExpressionLocation loc = makeLocator();
0326:                String prefix = getLanguage()
0327:                        + ("XPST0003".equals(errorCode) ? " syntax error "
0328:                                : " static error ")
0329:                        + (message.startsWith("...") ? "near" : "in") + " #"
0330:                        + s + "#:\n    ";
0331:                StaticError exception = new StaticError(prefix + message);
0332:                exception.setErrorCode(errorCode);
0333:                exception.setLocator(loc);
0334:                reportError(exception);
0335:            }
0336:
0337:            private void reportError(StaticError exception) throws StaticError {
0338:                errorCount++;
0339:                if (firstError == null) {
0340:                    firstError = exception;
0341:                }
0342:                env.getConfiguration().reportFatalError(exception);
0343:                throw exception;
0344:            }
0345:
0346:            /**
0347:             * Make a Locator object representing the current parsing location
0348:             *
0349:             * @return a Locator
0350:             */
0351:            private ExpressionLocation makeLocator() {
0352:                int line = t.getLineNumber();
0353:                int column = t.getColumnNumber();
0354:
0355:                ExpressionLocation loc = new ExpressionLocation();
0356:                loc.setSystemId(env.getSystemId());
0357:                loc.setLineNumber(line);
0358:                loc.setColumnNumber(column);
0359:                return loc;
0360:            }
0361:
0362:            /**
0363:             * Parse the version declaration if present.
0364:             *
0365:             * @throws net.sf.saxon.trans.StaticError in the event of a syntax error.
0366:             */
0367:            private void parseVersionDeclaration() throws StaticError {
0368:                if (t.currentToken == Token.XQUERY_VERSION) {
0369:                    nextToken();
0370:                    expect(Token.STRING_LITERAL);
0371:                    if (!("1.0".equals(t.currentTokenValue))) {
0372:                        grumble("XQuery version must be 1.0", "XQST0031");
0373:                    }
0374:                    nextToken();
0375:                    if ("encoding".equals(t.currentTokenValue)) {
0376:                        nextToken();
0377:                        expect(Token.STRING_LITERAL);
0378:                        // we ignore the encoding now: it was handled earlier, while decoding the byte stream
0379:                        nextToken();
0380:                    }
0381:                    expect(Token.SEMICOLON);
0382:                    nextToken();
0383:                }
0384:            }
0385:
0386:            /**
0387:             * In a library module, parse the module declaration
0388:             * Syntax: <"module" "namespace"> prefix "=" uri ";"
0389:             *
0390:             * @throws net.sf.saxon.trans.StaticError in the event of a syntax error.
0391:             */
0392:
0393:            private void parseModuleDeclaration() throws StaticError {
0394:                expect(Token.MODULE_NAMESPACE);
0395:                nextToken();
0396:                expect(Token.NAME);
0397:                String prefix = t.currentTokenValue;
0398:                checkProhibitedPrefixes(prefix);
0399:                nextToken();
0400:                expect(Token.EQUALS);
0401:                nextToken();
0402:                expect(Token.STRING_LITERAL);
0403:                String uri = URILiteral(t.currentTokenValue);
0404:                if (uri.equals("")) {
0405:                    grumble("Module namespace cannot be \"\"", "XQST0008");
0406:                    uri = "http://saxon.fallback.namespace/"; // for error recovery
0407:                }
0408:                nextToken();
0409:                expect(Token.SEMICOLON);
0410:                nextToken();
0411:                try {
0412:                    ((StaticQueryContext) env).declarePassiveNamespace(prefix,
0413:                            uri, true);
0414:                } catch (StaticError err) {
0415:                    err.setLocator(makeLocator());
0416:                    reportError(err);
0417:                }
0418:                ((StaticQueryContext) env).setModuleNamespace(uri);
0419:            }
0420:
0421:            /**
0422:             * Parse the query prolog. This method, and its subordinate methods which handle
0423:             * individual declarations in the prolog, cause the static context to be updated
0424:             * with relevant context information. On exit, t.currentToken is the first token
0425:             * that is not recognized as being part of the prolog.
0426:             *
0427:             * @throws net.sf.saxon.trans.StaticError in the event of a syntax error.
0428:             */
0429:
0430:            private void parseProlog() throws StaticError {
0431:                //boolean allowSetters = true;
0432:                boolean allowModuleDecl = true;
0433:                boolean allowDeclarations = true;
0434:
0435:                while (true) {
0436:                    try {
0437:                        if (t.currentToken == Token.MODULE_NAMESPACE) {
0438:                            String uri = ((StaticQueryContext) env)
0439:                                    .getModuleNamespace();
0440:                            if (uri == null) {
0441:                                grumble("Module declaration must not be used in a main module");
0442:                            } else {
0443:                                grumble("Module declaration appears more than once");
0444:                            }
0445:                            if (!allowModuleDecl) {
0446:                                grumble("Module declaration must precede other declarations in the query prolog");
0447:                            }
0448:                        }
0449:                        allowModuleDecl = false;
0450:                        switch (t.currentToken) {
0451:                        case Token.DECLARE_NAMESPACE:
0452:                            if (!allowDeclarations) {
0453:                                grumble("Namespace declarations cannot follow variables, functions, or options");
0454:                            }
0455:                            //allowSetters = false;
0456:                            parseNamespaceDeclaration();
0457:                            break;
0458:                        case Token.DECLARE_DEFAULT:
0459:                            nextToken();
0460:                            expect(Token.NAME);
0461:                            if (t.currentTokenValue == "element") {
0462:                                if (!allowDeclarations) {
0463:                                    grumble("Namespace declarations cannot follow variables, functions, or options");
0464:                                }
0465:                                //allowSetters = false;
0466:                                parseDefaultElementNamespace();
0467:                            } else if (t.currentTokenValue == "function") {
0468:                                if (!allowDeclarations) {
0469:                                    grumble("Namespace declarations cannot follow variables, functions, or options");
0470:                                }
0471:                                //allowSetters = false;
0472:                                parseDefaultFunctionNamespace();
0473:                            } else if (t.currentTokenValue == "collation") {
0474:                                if (!allowDeclarations) {
0475:                                    grumble("Collation declarations must appear earlier in the prolog");
0476:                                }
0477:                                parseDefaultCollation();
0478:                            } else if (t.currentTokenValue == "order") {
0479:                                if (!allowDeclarations) {
0480:                                    grumble("Order declarations must appear earlier in the prolog");
0481:                                }
0482:                                parseDefaultOrder();
0483:                            } else {
0484:                                grumble("After 'declare default', expected 'element', 'function', or 'collation'");
0485:                            }
0486:                            break;
0487:                        case Token.DECLARE_BOUNDARY_SPACE:
0488:                            if (!allowDeclarations) {
0489:                                grumble("'declare boundary-space' must appear earlier in the query prolog");
0490:                            }
0491:                            parseBoundarySpaceDeclaration();
0492:                            break;
0493:                        case Token.DECLARE_ORDERING:
0494:                            if (!allowDeclarations) {
0495:                                grumble("'declare ordering' must appear earlier in the query prolog");
0496:                            }
0497:                            parseOrderingDeclaration();
0498:                            break;
0499:                        case Token.DECLARE_COPY_NAMESPACES:
0500:                            if (!allowDeclarations) {
0501:                                grumble("'declare copy-namespaces' must appear earlier in the query prolog");
0502:                            }
0503:                            parseCopyNamespacesDeclaration();
0504:                            break;
0505:                        case Token.DECLARE_BASEURI:
0506:                            if (!allowDeclarations) {
0507:                                grumble("'declare base-uri' must appear earlier in the query prolog");
0508:                            }
0509:                            parseBaseURIDeclaration();
0510:                            break;
0511:                        case Token.IMPORT_SCHEMA:
0512:                            //allowSetters = false;
0513:                            if (!allowDeclarations) {
0514:                                grumble("Import schema must appear earlier in the prolog");
0515:                            }
0516:                            parseSchemaImport();
0517:                            break;
0518:                        case Token.IMPORT_MODULE:
0519:                            //allowSetters = false;
0520:                            if (!allowDeclarations) {
0521:                                grumble("Import module must appear earlier in the prolog");
0522:                            }
0523:                            parseModuleImport();
0524:                            break;
0525:                        case Token.DECLARE_VARIABLE:
0526:                            //allowSetters = false;
0527:                            if (allowDeclarations) {
0528:                                sealNamespaces(namespacesToBeSealed, env
0529:                                        .getConfiguration());
0530:                                allowDeclarations = false;
0531:                            }
0532:                            processPreamble();
0533:                            parseVariableDeclaration();
0534:                            break;
0535:                        case Token.DECLARE_FUNCTION:
0536:                            //allowSetters = false;
0537:                            if (allowDeclarations) {
0538:                                sealNamespaces(namespacesToBeSealed, env
0539:                                        .getConfiguration());
0540:                                allowDeclarations = false;
0541:                            }
0542:                            processPreamble();
0543:                            parseFunctionDeclaration();
0544:                            break;
0545:                        case Token.DECLARE_OPTION:
0546:                            //allowSetters = false;
0547:                            if (allowDeclarations) {
0548:                                sealNamespaces(namespacesToBeSealed, env
0549:                                        .getConfiguration());
0550:                                allowDeclarations = false;
0551:                            }
0552:                            processPreamble();
0553:                            parseOptionDeclaration();
0554:                            break;
0555:                        case Token.DECLARE_CONSTRUCTION:
0556:                            if (!allowDeclarations) {
0557:                                grumble("'declare construction' must appear earlier in the query prolog");
0558:                            }
0559:                            parseConstructionDeclaration();
0560:                            break;
0561:                        default:
0562:                            return;
0563:                        }
0564:                        expect(Token.SEMICOLON);
0565:                        nextToken();
0566:                    } catch (StaticError err) {
0567:                        if (err.getLocator() == null) {
0568:                            err.setLocator(makeLocator());
0569:                        }
0570:                        if (!err.hasBeenReported()) {
0571:                            errorCount++;
0572:                            if (firstError == null) {
0573:                                firstError = err;
0574:                            }
0575:                            env.getConfiguration().reportFatalError(err);
0576:                        }
0577:                        // we've reported an error, attempt to recover by skipping to the
0578:                        // next semicolon
0579:                        while (t.currentToken != Token.SEMICOLON) {
0580:                            nextToken();
0581:                            if (t.currentToken == Token.EOF) {
0582:                                return;
0583:                            } else if (t.currentToken == Token.RCURLY) {
0584:                                t.lookAhead();
0585:                            } else if (t.currentToken == Token.TAG) {
0586:                                parsePseudoXML(true);
0587:                            }
0588:                        }
0589:                        nextToken();
0590:                    }
0591:                }
0592:            }
0593:
0594:            private void sealNamespaces(List namespacesToBeSealed,
0595:                    Configuration config) {
0596:                for (Iterator iter = namespacesToBeSealed.iterator(); iter
0597:                        .hasNext();) {
0598:                    String ns = (String) iter.next();
0599:                    config.sealNamespace(ns);
0600:                }
0601:            }
0602:
0603:            /**
0604:             * Method called once the setters have been read to do tidying up that can't be done until we've got
0605:             * to the end
0606:             *
0607:             * @throws StaticError
0608:             */
0609:
0610:            private void processPreamble() throws StaticError {
0611:                if (preambleProcessed) {
0612:                    return;
0613:                }
0614:                preambleProcessed = true;
0615:                if (foundDefaultCollation) {
0616:                    String collationName = env.getDefaultCollationName();
0617:                    URI collationURI;
0618:                    try {
0619:                        collationURI = new URI(collationName);
0620:                        if (!collationURI.isAbsolute()) {
0621:                            URI base = new URI(env.getBaseURI());
0622:                            collationURI = base.resolve(collationURI);
0623:                            collationName = collationURI.toString();
0624:                        }
0625:                    } catch (URISyntaxException err) {
0626:                        grumble("Default collation name '" + collationName
0627:                                + "' is not a valid URI");
0628:                        collationName = NamespaceConstant.CODEPOINT_COLLATION_URI;
0629:                    }
0630:                    if (env.getCollation(collationName) == null) {
0631:                        grumble("Default collation name '" + collationName
0632:                                + "' is not a recognized collation", "XQST0038");
0633:                        collationName = NamespaceConstant.CODEPOINT_COLLATION_URI;
0634:                    }
0635:                    ((StaticQueryContext) env)
0636:                            .declareDefaultCollation(collationName);
0637:                }
0638:                for (Iterator iter = schemaImports.iterator(); iter.hasNext();) {
0639:                    Import imp = (Import) iter.next();
0640:                    applySchemaImport(imp);
0641:                }
0642:                for (Iterator iter = moduleImports.iterator(); iter.hasNext();) {
0643:                    Import imp = (Import) iter.next();
0644:                    applyModuleImport(imp);
0645:                }
0646:            }
0647:
0648:            private void parseDefaultCollation() throws StaticError {
0649:                // <"default" "collation"> StringLiteral
0650:                if (foundDefaultCollation) {
0651:                    grumble("default collation appears more than once",
0652:                            "XQST0038");
0653:                }
0654:                foundDefaultCollation = true;
0655:                nextToken();
0656:                expect(Token.STRING_LITERAL);
0657:                String uri = URILiteral(t.currentTokenValue);
0658:                ((StaticQueryContext) env).declareDefaultCollation(uri);
0659:                nextToken();
0660:            }
0661:
0662:            /**
0663:             * parse "declare default order empty (least|greatest)"
0664:             */
0665:            private void parseDefaultOrder() throws StaticError {
0666:                if (foundEmptyOrderingDeclaration) {
0667:                    grumble(
0668:                            "empty ordering declaration appears more than once",
0669:                            "XQST0069");
0670:                }
0671:                foundEmptyOrderingDeclaration = true;
0672:                nextToken();
0673:                if (!isKeyword("empty")) {
0674:                    grumble("After 'declare default order', expected keyword 'empty'");
0675:                }
0676:                nextToken();
0677:                if (isKeyword("least")) {
0678:                    defaultEmptyLeast = true;
0679:                } else if (isKeyword("greatest")) {
0680:                    defaultEmptyLeast = false;
0681:                } else {
0682:                    grumble("After 'declare default order empty', expected keyword 'least' or 'greatest'");
0683:                }
0684:                nextToken();
0685:            }
0686:
0687:            /**
0688:             * Parse the "declare xmlspace" declaration.
0689:             * Syntax: <"declare" "boundary-space"> ("preserve" | "strip")
0690:             *
0691:             * @throws net.sf.saxon.trans.StaticError
0692:             */
0693:
0694:            private void parseBoundarySpaceDeclaration() throws StaticError {
0695:                if (foundBoundarySpaceDeclaration) {
0696:                    grumble("'declare boundary-space' appears more than once",
0697:                            "XQST0068");
0698:                }
0699:                foundBoundarySpaceDeclaration = true;
0700:                nextToken();
0701:                expect(Token.NAME);
0702:                if ("preserve".equals(t.currentTokenValue)) {
0703:                    preserveSpace = true;
0704:                } else if ("strip".equals(t.currentTokenValue)) {
0705:                    preserveSpace = false;
0706:                } else {
0707:                    grumble("boundary-space must be 'preserve' or 'strip'");
0708:                }
0709:                nextToken();
0710:            }
0711:
0712:            /**
0713:             * Parse the "declare ordering" declaration.
0714:             * Syntax: <"declare" "ordering"> ("ordered" | "unordered")
0715:             *
0716:             * @throws net.sf.saxon.trans.StaticError
0717:             */
0718:
0719:            private void parseOrderingDeclaration() throws StaticError {
0720:                if (foundOrderingDeclaration) {
0721:                    grumble("ordering mode declaration appears more than once",
0722:                            "XQST0065");
0723:                }
0724:                foundOrderingDeclaration = true;
0725:                nextToken();
0726:                expect(Token.NAME);
0727:                if ("ordered".equals(t.currentTokenValue)) {
0728:                    // no action
0729:                } else if ("unordered".equals(t.currentTokenValue)) {
0730:                    // no action
0731:                } else {
0732:                    grumble("ordering mode must be 'ordered' or 'unordered'");
0733:                }
0734:                nextToken();
0735:            }
0736:
0737:            /**
0738:             * Parse the "declare copy-namespaces" declaration.
0739:             * Syntax: <"declare" "copy-namespaces"> ("preserve" | "no-preserve") "," ("inherit" | "no-inherit")
0740:             *
0741:             * @throws net.sf.saxon.trans.StaticError
0742:             */
0743:
0744:            private void parseCopyNamespacesDeclaration() throws StaticError {
0745:                if (foundCopyNamespaces) {
0746:                    grumble(
0747:                            "declare inherit-namespaces appears more than once",
0748:                            "XQST0055");
0749:                }
0750:                foundCopyNamespaces = true;
0751:                nextToken();
0752:                expect(Token.NAME);
0753:                if ("preserve".equals(t.currentTokenValue)) {
0754:                    ((StaticQueryContext) env).setPreserveNamespaces(true);
0755:                } else if ("no-preserve".equals(t.currentTokenValue)) {
0756:                    ((StaticQueryContext) env).setPreserveNamespaces(false);
0757:                } else {
0758:                    grumble("copy-namespaces must be followed by 'preserve' or 'no-preserve'");
0759:                }
0760:                nextToken();
0761:                expect(Token.COMMA);
0762:                nextToken();
0763:                expect(Token.NAME);
0764:                if ("inherit".equals(t.currentTokenValue)) {
0765:                    ((StaticQueryContext) env).setInheritNamespaces(true);
0766:                } else if ("no-inherit".equals(t.currentTokenValue)) {
0767:                    ((StaticQueryContext) env).setInheritNamespaces(false);
0768:                } else {
0769:                    grumble("After the comma in the copy-namespaces declaration, expected 'inherit' or 'no-inherit'");
0770:                }
0771:                nextToken();
0772:            }
0773:
0774:            /**
0775:             * Parse the "declare construction" declaration.
0776:             * Syntax: <"declare" "construction"> ("preserve" | "strip")
0777:             *
0778:             * @throws net.sf.saxon.trans.StaticError
0779:             */
0780:
0781:            private void parseConstructionDeclaration() throws StaticError {
0782:                if (foundConstructionDeclaration) {
0783:                    grumble("declare construction appears more than once",
0784:                            "XQST0067");
0785:                }
0786:                foundConstructionDeclaration = true;
0787:                nextToken();
0788:                expect(Token.NAME);
0789:                int val;
0790:                if ("preserve".equals(t.currentTokenValue)) {
0791:                    val = Validation.PRESERVE;
0792:                } else if ("strip".equals(t.currentTokenValue)) {
0793:                    val = Validation.STRIP;
0794:                } else {
0795:                    grumble("construction mode must be 'preserve' or 'strip'");
0796:                    val = Validation.STRIP;
0797:                }
0798:                ((StaticQueryContext) env).setConstructionMode(val);
0799:                nextToken();
0800:            }
0801:
0802:            /**
0803:             * Parse (and process) the schema import declaration.
0804:             * SchemaImport ::=	"import" "schema" SchemaPrefix? URILiteral ("at" URILiteral ("," URILiteral)*)?
0805:             * SchemaPrefix ::=	("namespace" NCName "=") | ("default" "element" "namespace")
0806:             */
0807:
0808:            private void parseSchemaImport() throws StaticError {
0809:                if (!env.getConfiguration().isSchemaAware(Configuration.XQUERY)) {
0810:                    grumble(
0811:                            "To import a schema, you need the schema-aware version of Saxon",
0812:                            "XQST0009");
0813:                }
0814:                Import sImport = new Import();
0815:                String prefix = null;
0816:                sImport.namespaceURI = null;
0817:                sImport.locationURIs = new ArrayList(5);
0818:                nextToken();
0819:                if (isKeyword("namespace")) {
0820:                    nextToken();
0821:                    expect(Token.NAME);
0822:                    prefix = t.currentTokenValue;
0823:                    checkProhibitedPrefixes(prefix);
0824:                    nextToken();
0825:                    expect(Token.EQUALS);
0826:                    nextToken();
0827:                } else if (isKeyword("default")) {
0828:                    nextToken();
0829:                    if (!isKeyword("element")) {
0830:                        grumble("In 'import schema', expected 'element namespace'");
0831:                    }
0832:                    nextToken();
0833:                    if (!isKeyword("namespace")) {
0834:                        grumble("In 'import schema', expected keyword 'namespace'");
0835:                    }
0836:                    nextToken();
0837:                    prefix = "";
0838:                }
0839:                if (t.currentToken == Token.STRING_LITERAL) {
0840:                    sImport.namespaceURI = URILiteral(t.currentTokenValue);
0841:                    nextToken();
0842:                    if (isKeyword("at")) {
0843:                        nextToken();
0844:                        expect(Token.STRING_LITERAL);
0845:                        sImport.locationURIs
0846:                                .add(URILiteral(t.currentTokenValue));
0847:                        nextToken();
0848:                        while (t.currentToken == Token.COMMA) {
0849:                            nextToken();
0850:                            expect(Token.STRING_LITERAL);
0851:                            sImport.locationURIs
0852:                                    .add(URILiteral(t.currentTokenValue));
0853:                            nextToken();
0854:                        }
0855:                    } else if (t.currentToken != Token.SEMICOLON) {
0856:                        grumble("After the target namespace URI, expected 'at' or ';'");
0857:                    }
0858:                } else {
0859:                    grumble("After 'import schema', expected 'namespace', 'default', or a string-literal");
0860:                }
0861:                if (prefix != null) {
0862:                    try {
0863:                        if ("".equals(prefix)) {
0864:                            ((StaticQueryContext) env)
0865:                                    .setDefaultElementNamespace(sImport.namespaceURI);
0866:                        } else {
0867:                            if (sImport.namespaceURI == null
0868:                                    || "".equals(sImport.namespaceURI)) {
0869:                                grumble(
0870:                                        "A prefix cannot be bound to the null namespace",
0871:                                        "XQST0057");
0872:                            }
0873:                            ((StaticQueryContext) env).declarePassiveNamespace(
0874:                                    prefix, sImport.namespaceURI, true);
0875:                        }
0876:                    } catch (StaticError err) {
0877:                        err.setLocator(makeLocator());
0878:                        reportError(err);
0879:                    }
0880:                }
0881:                schemaImports.add(sImport);
0882:
0883:            }
0884:
0885:            private void applySchemaImport(Import sImport) throws StaticError {
0886:
0887:                // Do the importing
0888:
0889:                Configuration config = env.getConfiguration();
0890:                if (config.getSchema(sImport.namespaceURI) == null) {
0891:                    if (sImport.locationURIs.size() > 0) {
0892:                        try {
0893:                            PipelineConfiguration pipe = config
0894:                                    .makePipelineConfiguration();
0895:                            config.readMultipleSchemas(pipe, env.getBaseURI(),
0896:                                    sImport.locationURIs, sImport.namespaceURI);
0897:                            namespacesToBeSealed.add(sImport.namespaceURI);
0898:                        } catch (TransformerConfigurationException err) {
0899:                            grumble("Error in schema. " + err.getMessage(),
0900:                                    "XQST0059");
0901:                        }
0902:                    } else {
0903:                        grumble("Unable to locate requested schema", "XQST0059");
0904:                    }
0905:                }
0906:                ((StaticQueryContext) env)
0907:                        .addImportedSchema(sImport.namespaceURI);
0908:            }
0909:
0910:            /**
0911:             * Parse (and expand) the module import declaration.
0912:             * Syntax: <"import" "module" ("namespace" NCName "=")? uri ("at" uri ("," uri)*)? ";"
0913:             */
0914:
0915:            private void parseModuleImport() throws StaticError {
0916:                StaticQueryContext this Module = (StaticQueryContext) env;
0917:                Import mImport = new Import();
0918:                String prefix = null;
0919:                mImport.namespaceURI = null;
0920:                mImport.locationURIs = new ArrayList(5);
0921:                nextToken();
0922:                if (t.currentToken == Token.NAME
0923:                        && t.currentTokenValue == "namespace") {
0924:                    nextToken();
0925:                    expect(Token.NAME);
0926:                    prefix = t.currentTokenValue;
0927:                    checkProhibitedPrefixes(prefix);
0928:                    nextToken();
0929:                    expect(Token.EQUALS);
0930:                    nextToken();
0931:                }
0932:                if (t.currentToken == Token.STRING_LITERAL) {
0933:                    mImport.namespaceURI = URILiteral(t.currentTokenValue);
0934:                    if (mImport.namespaceURI.equals("")) {
0935:                        grumble("Imported module namespace cannot be \"\"",
0936:                                "XQST0008");
0937:                        mImport.namespaceURI = "http://saxon.fallback.namespace/line"
0938:                                + t.getLineNumber(); // for error recovery
0939:                    }
0940:                    if (importedModules.contains(mImport.namespaceURI)) {
0941:                        grumble(
0942:                                "Two 'import module' declarations specify the same module namespace",
0943:                                "XQST0047");
0944:                    }
0945:                    importedModules.add(mImport.namespaceURI);
0946:                    ((StaticQueryContext) env)
0947:                            .addImportedNamespace(mImport.namespaceURI);
0948:                    nextToken();
0949:                    if (isKeyword("at")) {
0950:                        do {
0951:                            nextToken();
0952:                            expect(Token.STRING_LITERAL);
0953:                            String uri = URILiteral(t.currentTokenValue);
0954:                            mImport.locationURIs.add(uri);
0955:                            nextToken();
0956:                        } while (t.currentToken == Token.COMMA);
0957:                    }
0958:                } else {
0959:                    grumble("After 'import module', expected 'namespace' or a string-literal");
0960:                }
0961:                if (prefix != null) {
0962:                    try {
0963:                        this Module.declarePassiveNamespace(prefix,
0964:                                mImport.namespaceURI, true);
0965:                    } catch (StaticError err) {
0966:                        err.setLocator(makeLocator());
0967:                        reportError(err);
0968:                    }
0969:                }
0970:
0971:                // Check that this import would not create a cycle involving a change of namespace
0972:                if (!mImport.namespaceURI.equals(((StaticQueryContext) env)
0973:                        .getModuleNamespace())) {
0974:                    StaticQueryContext parent = (StaticQueryContext) env;
0975:                    if (!parent.mayImport(mImport.namespaceURI)) {
0976:                        StaticError err = new StaticError(
0977:                                "A module cannot import itself directly or indirectly, unless all modules in the cycle are in the same namespace");
0978:                        err.setErrorCode("XQST0073");
0979:                        throw err;
0980:                    }
0981:                }
0982:
0983:                moduleImports.add(mImport);
0984:            }
0985:
0986:            public void applyModuleImport(Import mImport) throws StaticError {
0987:                boolean foundOne = false;
0988:
0989:                // resolve the location URIs against the base URI
0990:                for (int i = 0; i < mImport.locationURIs.size(); i++) {
0991:                    try {
0992:                        String uri = (String) mImport.locationURIs.get(i);
0993:                        uri = StandardURIResolver.makeAbsolute(uri,
0994:                                env.getBaseURI()).toString();
0995:                        mImport.locationURIs.set(i, uri);
0996:                    } catch (DynamicError dynamicError) {
0997:                        grumble(dynamicError.getMessage());
0998:                    } catch (URISyntaxException e) {
0999:                        grumble("Invalid URI " + mImport.locationURIs.get(i)
1000:                                + ": " + e.getMessage());
1001:                    }
1002:                }
1003:
1004:                // If any of the modules are already loaded, don't re-read them; but do check that none of them
1005:                // references the current module namespace directly or indirectly
1006:                List existingModules = executable
1007:                        .getQueryLibraryModules(mImport.namespaceURI);
1008:                if (existingModules != null) {
1009:                    for (int m = 0; m < existingModules.size(); m++) {
1010:                        StaticQueryContext importedModule = (StaticQueryContext) existingModules
1011:                                .get(m);
1012:                        if (!importedModule.getLocationURI().equals(
1013:                                ((StaticQueryContext) env).getLocationURI())) {
1014:                            QueryReader.importModuleContents(importedModule,
1015:                                    (StaticQueryContext) env);
1016:                            foundOne = true;
1017:                        }
1018:                        if (((StaticQueryContext) env).getModuleNamespace() != null
1019:                                && !((StaticQueryContext) env)
1020:                                        .getModuleNamespace().equals(
1021:                                                importedModule
1022:                                                        .getModuleNamespace())
1023:                                && importedModule
1024:                                        .importsNamespaceIndirectly(((StaticQueryContext) env)
1025:                                                .getModuleNamespace())) {
1026:                            grumble("A cycle exists among the module imports, involving namespaces "
1027:                                    + ((StaticQueryContext) env)
1028:                                            .getModuleNamespace()
1029:                                    + " and "
1030:                                    + importedModule.getModuleNamespace());
1031:                        }
1032:                        for (int h = mImport.locationURIs.size() - 1; h >= 0; h--) {
1033:                            if (mImport.locationURIs.get(h).equals(
1034:                                    importedModule.getLocationURI())) {
1035:                                mImport.locationURIs.remove(h);
1036:                            }
1037:                        }
1038:                    }
1039:                }
1040:
1041:                // If we've found at least one module, and there are no location URIs left, call it a day.
1042:
1043:                if (mImport.locationURIs.size() == 0 && foundOne) {
1044:                    return;
1045:                }
1046:
1047:                // Call the module URI resolver to find the remaining modules
1048:
1049:                ModuleURIResolver resolver = env.getConfiguration()
1050:                        .getModuleURIResolver();
1051:
1052:                String[] hints = new String[mImport.locationURIs.size()];
1053:                hints = (String[]) mImport.locationURIs.toArray(hints);
1054:                StreamSource[] sources = null;
1055:                try {
1056:                    if (resolver != null) {
1057:                        sources = resolver.resolve(mImport.namespaceURI, env
1058:                                .getBaseURI(), hints);
1059:                    }
1060:                    if (sources == null) {
1061:                        if (hints.length == 0) {
1062:                            if (existingModules == null) {
1063:                                grumble("Cannot locate module for namespace "
1064:                                        + mImport.namespaceURI, "XQST0059");
1065:                            }
1066:                        }
1067:                        resolver = env.getConfiguration()
1068:                                .getStandardModuleURIResolver();
1069:                        sources = resolver.resolve(mImport.namespaceURI, env
1070:                                .getBaseURI(), hints);
1071:                    }
1072:                } catch (XPathException e) {
1073:                    throw StaticError.makeStaticError(e);
1074:                }
1075:
1076:                for (int m = 0; m < sources.length; m++) {
1077:                    StreamSource ss = sources[m];
1078:                    String baseURI = ss.getSystemId();
1079:                    if (baseURI == null) {
1080:                        if (m < hints.length) {
1081:                            ss.setSystemId(hints[m]);
1082:                        } else {
1083:                            grumble(
1084:                                    "No base URI available for imported module",
1085:                                    "XQST0059");
1086:                        }
1087:                    }
1088:                    try {
1089:                        String queryText = QueryReader.readSourceQuery(ss,
1090:                                nameChecker);
1091:                        StaticQueryContext importedModule = StaticQueryContext
1092:                                .makeStaticQueryContext(baseURI, executable,
1093:                                        (StaticQueryContext) env, queryText,
1094:                                        mImport.namespaceURI);
1095:                        QueryReader.importModuleContents(importedModule,
1096:                                (StaticQueryContext) env);
1097:                    } catch (StaticError err) {
1098:                        if (err.getLocator() == null) {
1099:                            err.setLocator(makeLocator());
1100:                        }
1101:                        reportError(err);
1102:                    }
1103:                }
1104:            }
1105:
1106:            /**
1107:             * Parse the Base URI declaration.
1108:             * Syntax: <"declare" "base-uri"> uri-literal
1109:             *
1110:             * @throws net.sf.saxon.trans.StaticError
1111:             */
1112:
1113:            private void parseBaseURIDeclaration() throws StaticError {
1114:                if (foundBaseURIDeclaration) {
1115:                    grumble("Base URI Declaration may only appear once",
1116:                            "XQST0032");
1117:                }
1118:                foundBaseURIDeclaration = true;
1119:                nextToken();
1120:                expect(Token.STRING_LITERAL);
1121:                String uri = URILiteral(t.currentTokenValue);
1122:                ((StaticQueryContext) env).setBaseURI(uri);
1123:                nextToken();
1124:            }
1125:
1126:            /**
1127:             * Parse the "default function namespace" declaration.
1128:             * Syntax: <"declare" "default" "function" "namespace"> StringLiteral
1129:             *
1130:             * @throws net.sf.saxon.trans.StaticError to indicate a syntax error
1131:             */
1132:
1133:            private void parseDefaultFunctionNamespace() throws StaticError {
1134:                if (foundDefaultFunctionNamespace) {
1135:                    grumble(
1136:                            "default function namespace appears more than once",
1137:                            "XQST0066");
1138:                }
1139:                foundDefaultFunctionNamespace = true;
1140:                nextToken();
1141:                expect(Token.NAME);
1142:                if (!"namespace".equals(t.currentTokenValue)) {
1143:                    grumble("After 'declare default function', expected 'namespace'");
1144:                }
1145:                nextToken();
1146:                expect(Token.STRING_LITERAL);
1147:                String uri = URILiteral(t.currentTokenValue);
1148:                ((StaticQueryContext) env).setDefaultFunctionNamespace(uri);
1149:                nextToken();
1150:            }
1151:
1152:            /**
1153:             * Parse the "default element namespace" declaration.
1154:             * Syntax: <"declare" "default" "element" "namespace"> StringLiteral
1155:             *
1156:             * @throws net.sf.saxon.trans.StaticError to indicate a syntax error
1157:             */
1158:
1159:            private void parseDefaultElementNamespace() throws StaticError {
1160:                if (foundDefaultElementNamespace) {
1161:                    grumble("default element namespace appears more than once",
1162:                            "XQST0066");
1163:                }
1164:                foundDefaultElementNamespace = true;
1165:                nextToken();
1166:                expect(Token.NAME);
1167:                if (!"namespace".equals(t.currentTokenValue)) {
1168:                    grumble("After 'declare default element', expected 'namespace'");
1169:                }
1170:                nextToken();
1171:                expect(Token.STRING_LITERAL);
1172:                String uri = URILiteral(t.currentTokenValue);
1173:                ((StaticQueryContext) env).setDefaultElementNamespace(uri);
1174:                nextToken();
1175:            }
1176:
1177:            /**
1178:             * Parse a namespace declaration in the Prolog.
1179:             * Syntax: <"declare" "namespace"> NCName "=" StringLiteral
1180:             *
1181:             * @throws net.sf.saxon.trans.StaticError
1182:             */
1183:
1184:            private void parseNamespaceDeclaration() throws StaticError {
1185:                nextToken();
1186:                expect(Token.NAME);
1187:                String prefix = t.currentTokenValue;
1188:                if (!nameChecker.isValidNCName(prefix)) {
1189:                    grumble("Invalid namespace prefix " + Err.wrap(prefix));
1190:                }
1191:                checkProhibitedPrefixes(prefix);
1192:                nextToken();
1193:                expect(Token.EQUALS);
1194:                nextToken();
1195:                expect(Token.STRING_LITERAL);
1196:                String uri = URILiteral(t.currentTokenValue);
1197:                try {
1198:                    ((StaticQueryContext) env).declarePassiveNamespace(prefix,
1199:                            uri, true);
1200:                } catch (StaticError err) {
1201:                    err.setLocator(makeLocator());
1202:                    reportError(err);
1203:                }
1204:                nextToken();
1205:            }
1206:
1207:            /**
1208:             * Check that a namespace prefix is not a prohibited prefix (xml or xmlns)
1209:             *
1210:             * @param prefix the prefix to be tested
1211:             * @throws StaticError if the prefix is prohibited
1212:             */
1213:
1214:            private void checkProhibitedPrefixes(String prefix)
1215:                    throws StaticError {
1216:                if ("xml".equals(prefix) || "xmlns".equals(prefix)) {
1217:                    grumble("The namespace prefix " + Err.wrap(prefix)
1218:                            + " cannot be redeclared", "XQST0070");
1219:                }
1220:            }
1221:
1222:            /**
1223:             * Parse a global variable definition.
1224:             * <"declare" "variable" "$"> VarName TypeDeclaration?
1225:             * ((":=" Expr ) | "external")
1226:             * Currently accept both
1227:             *
1228:             * @throws net.sf.saxon.trans.StaticError
1229:             */
1230:
1231:            private void parseVariableDeclaration() throws StaticError {
1232:                int offset = t.currentTokenStartOffset;
1233:                GlobalVariableDefinition var = new GlobalVariableDefinition();
1234:                var.setLineNumber(t.getLineNumber());
1235:                var.setSystemId(env.getSystemId());
1236:                nextToken();
1237:                expect(Token.DOLLAR);
1238:                t.setState(Tokenizer.BARE_NAME_STATE);
1239:                nextToken();
1240:                expect(Token.NAME);
1241:                String varName = t.currentTokenValue;
1242:                var.setVariableName(varName);
1243:                int varNameCode = makeNameCode(t.currentTokenValue, false);
1244:                int varFingerprint = varNameCode & 0xfffff;
1245:                var.setNameCode(varFingerprint);
1246:
1247:                String uri = env.getNamePool().getURI(varNameCode);
1248:                String moduleURI = ((StaticQueryContext) env)
1249:                        .getModuleNamespace();
1250:                if (moduleURI != null && !moduleURI.equals(uri)) {
1251:                    grumble(
1252:                            "A variable declared in a library module must be in the module namespace",
1253:                            "XQST0048");
1254:                }
1255:
1256:                nextToken();
1257:                SequenceType requiredType = SequenceType.ANY_SEQUENCE;
1258:                if (isKeyword("as")) {
1259:                    t.setState(Tokenizer.SEQUENCE_TYPE_STATE);
1260:                    nextToken();
1261:                    requiredType = parseSequenceType();
1262:                }
1263:                var.setRequiredType(requiredType);
1264:
1265:                if (t.currentToken == Token.ASSIGN) {
1266:                    t.setState(Tokenizer.DEFAULT_STATE);
1267:                    nextToken();
1268:                    Expression exp = parseExpression();
1269:                    var.setIsParameter(false);
1270:                    var.setValueExpression(makeTracer(offset, exp,
1271:                            StandardNames.XSL_VARIABLE, varNameCode));
1272:                } else if (t.currentToken == Token.NAME) {
1273:                    if ("external".equals(t.currentTokenValue)) {
1274:                        var.setIsParameter(true);
1275:                        if (defaultValue != null) {
1276:                            var.setValueExpression(defaultValue);
1277:                        }
1278:                        nextToken();
1279:                    } else {
1280:                        grumble("Variable must either be initialized or be declared as external");
1281:                    }
1282:                } else {
1283:                    grumble("Expected ':=' or 'external' in variable declaration");
1284:                }
1285:
1286:                StaticQueryContext qenv = (StaticQueryContext) env;
1287:                if (qenv.getModuleNamespace() != null
1288:                        && env.getNamePool().getURICode(varFingerprint) != qenv
1289:                                .getModuleNamespaceCode()) {
1290:                    grumble("Variable " + Err.wrap(varName, Err.VARIABLE)
1291:                            + " is not defined in the module namespace");
1292:                }
1293:                try {
1294:                    qenv.declareVariable(var);
1295:                } catch (XPathException e) {
1296:                    grumble(e.getMessage(), e.getErrorCodeLocalPart());
1297:                }
1298:            }
1299:
1300:            /**
1301:             * Parse a function declaration.
1302:             * <p>Syntax:<br/>
1303:             * <"declare" "function"> <QName "("> ParamList? (")" | (<")" "as"> SequenceType))
1304:             * (EnclosedExpr | "external")
1305:             * </p>
1306:             * <p>On entry, the "define function" has already been recognized</p>
1307:             *
1308:             * @throws net.sf.saxon.trans.StaticError if a syntax error is found
1309:             */
1310:
1311:            private void parseFunctionDeclaration() throws StaticError {
1312:                // the next token should be the < QNAME "("> pair
1313:                int offset = t.currentTokenStartOffset;
1314:                nextToken();
1315:                expect(Token.FUNCTION);
1316:
1317:                String uri;
1318:                int fnc;
1319:                if (t.currentTokenValue.indexOf(':') < 0) {
1320:                    uri = env.getDefaultFunctionNamespace();
1321:                    fnc = env.getNamePool().allocate("", uri,
1322:                            t.currentTokenValue);
1323:                } else {
1324:                    fnc = makeNameCode(t.currentTokenValue, false);
1325:                    uri = env.getNamePool().getURI(fnc);
1326:                }
1327:
1328:                if (uri.equals("")) {
1329:                    grumble("The function must be in a namespace", "XQST0060");
1330:                }
1331:
1332:                String moduleURI = ((StaticQueryContext) env)
1333:                        .getModuleNamespace();
1334:                if (moduleURI != null && !moduleURI.equals(uri)) {
1335:                    grumble(
1336:                            "A function in a library module must be in the module namespace",
1337:                            "XQST0048");
1338:                }
1339:
1340:                if (NamespaceConstant.isReservedInQuery(uri)) {
1341:                    grumble("The function name " + t.currentTokenValue
1342:                            + " is in a reserved namespace", "XQST0045");
1343:                }
1344:
1345:                XQueryFunction func = new XQueryFunction();
1346:                func.setNameCode(fnc);
1347:                func.arguments = new ArrayList(8);
1348:                func.resultType = SequenceType.ANY_SEQUENCE;
1349:                func.body = null;
1350:                func.lineNumber = t.getLineNumber(offset);
1351:                func.columnNumber = t.getColumnNumber(offset);
1352:                func.systemId = env.getSystemId();
1353:                func.setExecutable(getExecutable());
1354:
1355:                nextToken();
1356:                IntHashSet paramNames = new IntHashSet(8);
1357:                while (t.currentToken != Token.RPAR) {
1358:                    //     ParamList   ::=     Param ("," Param)*
1359:                    //     Param       ::=     "$" VarName  TypeDeclaration?
1360:                    expect(Token.DOLLAR);
1361:                    nextToken();
1362:                    expect(Token.NAME);
1363:                    String argName = t.currentTokenValue;
1364:                    int nameCode = makeNameCode(argName, false);
1365:                    int fingerprint = nameCode & 0xfffff;
1366:                    if (paramNames.contains(fingerprint)) {
1367:                        grumble("Duplicate parameter name "
1368:                                + Err.wrap(t.currentTokenValue, Err.VARIABLE),
1369:                                "XQST0039");
1370:                    }
1371:                    paramNames.add(fingerprint);
1372:                    SequenceType paramType = SequenceType.ANY_SEQUENCE;
1373:                    nextToken();
1374:                    if (t.currentToken == Token.NAME
1375:                            && "as".equals(t.currentTokenValue)) {
1376:                        nextToken();
1377:                        paramType = parseSequenceType();
1378:                    }
1379:
1380:                    RangeVariableDeclaration arg = new RangeVariableDeclaration();
1381:                    arg.setNameCode(nameCode);
1382:                    arg.setRequiredType(paramType);
1383:                    arg.setVariableName(argName);
1384:                    func.arguments.add(arg);
1385:                    declareRangeVariable(arg);
1386:                    if (t.currentToken == Token.RPAR) {
1387:                        break;
1388:                    } else if (t.currentToken == Token.COMMA) {
1389:                        nextToken();
1390:                    } else {
1391:                        grumble("Expected ',' or ')' after function argument, found '"
1392:                                + Token.tokens[t.currentToken] + '\'');
1393:                    }
1394:                }
1395:                t.setState(Tokenizer.BARE_NAME_STATE);
1396:                nextToken();
1397:                if (isKeyword("as")) {
1398:                    t.setState(Tokenizer.SEQUENCE_TYPE_STATE);
1399:                    nextToken();
1400:                    func.resultType = parseSequenceType();
1401:                }
1402:                if (isKeyword("external")) {
1403:                    grumble("Saxon does not allow external functions to be declared");
1404:                } else {
1405:                    expect(Token.LCURLY);
1406:                    t.setState(Tokenizer.DEFAULT_STATE);
1407:                    nextToken();
1408:                    func.body = parseExpression();
1409:                    if (func.body instanceof  ComputedExpression) {
1410:                        ((ComputedExpression) func.body)
1411:                                .setParentExpression(func);
1412:                    }
1413:                    expect(Token.RCURLY);
1414:                    lookAhead(); // must be done manually after an RCURLY
1415:                }
1416:                UserFunctionParameter[] params = func.getParameterDefinitions();
1417:                for (int i = 0; i < params.length; i++) {
1418:                    undeclareRangeVariable();
1419:                }
1420:                t.setState(Tokenizer.DEFAULT_STATE);
1421:                nextToken();
1422:
1423:                StaticQueryContext qenv = (StaticQueryContext) env;
1424:
1425:                try {
1426:                    qenv.declareFunction(func);
1427:                } catch (XPathException e) {
1428:                    grumble(e.getMessage(), e.getErrorCodeLocalPart());
1429:                }
1430:
1431:            }
1432:
1433:            /**
1434:             * Parse an option declaration.
1435:             * <p>Syntax:<br/>
1436:             * <"declare" "option">  QName "string-literal"
1437:             * </p>
1438:             * <p>On entry, the "declare option" has already been recognized</p>
1439:             *
1440:             * @throws net.sf.saxon.trans.StaticError if a syntax error is found
1441:             */
1442:
1443:            private void parseOptionDeclaration() throws StaticError {
1444:                nextToken();
1445:                expect(Token.NAME);
1446:                int varNameCode = makeNameCode(t.currentTokenValue, false);
1447:                String uri = env.getNamePool().getURI(varNameCode);
1448:
1449:                nextToken();
1450:                expect(Token.STRING_LITERAL);
1451:                String value = URILiteral(t.currentTokenValue);
1452:
1453:                if (uri.equals(NamespaceConstant.SAXON)) {
1454:                    String localName = env.getNamePool().getLocalName(
1455:                            varNameCode);
1456:                    if (localName.equals("output")) {
1457:                        setOutputProperty(value);
1458:                    } else if (localName.equals("default")) {
1459:                        defaultValue = setDefaultValue(value);
1460:                    } else {
1461:                        warning("Unknown Saxon option declaration: "
1462:                                + env.getNamePool().getDisplayName(varNameCode));
1463:                    }
1464:                }
1465:
1466:                nextToken();
1467:            }
1468:
1469:            /**
1470:             * Handle a saxon:output option declaration. Format:
1471:             * declare option saxon:output "indent = yes"
1472:             */
1473:
1474:            private void setOutputProperty(String property) {
1475:                int equals = property.indexOf("=");
1476:                if (equals < 0) {
1477:                    badOutputProperty("no equals sign");
1478:                } else if (equals == 0) {
1479:                    badOutputProperty("starts with '=");
1480:                } else if (equals == property.length() - 1) {
1481:                    badOutputProperty("ends with '=");
1482:                }
1483:                String keyword = property.substring(0, equals).trim();
1484:                String value = property.substring(equals + 1).trim();
1485:
1486:                Properties props = getExecutable().getDefaultOutputProperties();
1487:                try {
1488:                    int key = makeNameCode(keyword, false) & NamePool.FP_MASK;
1489:                    String lname = env.getNamePool().getLocalName(key);
1490:                    String uri = env.getNamePool().getURI(key);
1491:                    ResultDocument.setSerializationProperty(props, uri, lname,
1492:                            value, env.getNamespaceResolver(), false,
1493:                            nameChecker);
1494:                } catch (XPathException e) {
1495:                    badOutputProperty(e.getMessage());
1496:                }
1497:            }
1498:
1499:            private void badOutputProperty(String s) {
1500:                try {
1501:                    warning("Invalid serialization property (" + s
1502:                            + ") - ignored");
1503:                } catch (StaticError staticError) {
1504:                    //
1505:                }
1506:            }
1507:
1508:            /**
1509:             * Parse the expression (inside a string literal) used to define default values
1510:             * for external variables. This requires instantiating a nested XPath parser.
1511:             */
1512:
1513:            public Expression setDefaultValue(String exp) {
1514:                try {
1515:                    IndependentContext ic = new IndependentContext(env
1516:                            .getConfiguration());
1517:                    ic.setNamespaceResolver(env.getNamespaceResolver());
1518:                    Expression expr = ExpressionTool.make(exp, ic, 0,
1519:                            Token.EOF, 1);
1520:
1521:                    ItemType contextItemType = Type.ITEM_TYPE;
1522:                    expr = expr.typeCheck(ic, contextItemType);
1523:                    expr = expr.optimize(env.getConfiguration().getOptimizer(),
1524:                            env, contextItemType);
1525:                    SlotManager stackFrameMap = ic.getStackFrameMap();
1526:                    ExpressionTool.allocateSlots(expr, stackFrameMap
1527:                            .getNumberOfVariables(), stackFrameMap);
1528:                    return expr;
1529:                } catch (XPathException e) {
1530:                    try {
1531:                        warning("Invalid expression for default value: "
1532:                                + e.getMessage() + " (ignored)");
1533:                    } catch (StaticError staticError) {
1534:                        //
1535:                    }
1536:                    return null;
1537:                }
1538:            }
1539:
1540:            /**
1541:             * Parse a FLWOR expression. This replaces the XPath "for" expression.
1542:             * Full syntax:
1543:             * <p/>
1544:             * [41] FLWORExpr ::=  (ForClause  | LetClause)+
1545:             * WhereClause? OrderByClause?
1546:             * "return" ExprSingle
1547:             * [42] ForClause ::=  <"for" "$"> VarName TypeDeclaration? PositionalVar? "in" ExprSingle
1548:             * ("," "$" VarName TypeDeclaration? PositionalVar? "in" ExprSingle)*
1549:             * [43] PositionalVar  ::= "at" "$" VarName
1550:             * [44] LetClause ::= <"let" "$"> VarName TypeDeclaration? ":=" ExprSingle
1551:             * ("," "$" VarName TypeDeclaration? ":=" ExprSingle)*
1552:             * [45] WhereClause  ::= "where" Expr
1553:             * [46] OrderByClause ::= (<"order" "by"> | <"stable" "order" "by">) OrderSpecList
1554:             * [47] OrderSpecList ::= OrderSpec  ("," OrderSpec)*
1555:             * [48] OrderSpec     ::=     ExprSingle  OrderModifier
1556:             * [49] OrderModifier ::= ("ascending" | "descending")?
1557:             * (<"empty" "greatest"> | <"empty" "least">)?
1558:             * ("collation" StringLiteral)?
1559:             * </p>
1560:             *
1561:             * @return the resulting subexpression
1562:             * @throws net.sf.saxon.trans.StaticError if any error is encountered
1563:             */
1564:
1565:            protected Expression parseForExpression() throws StaticError {
1566:                int offset = t.currentTokenStartOffset;
1567:                Expression whereCondition = null;
1568:                int whereOffset = -1;
1569:                //boolean stableOrder = false;
1570:                List clauseList = new ArrayList(4);
1571:                while (true) {
1572:                    if (t.currentToken == Token.FOR) {
1573:                        parseForClause(clauseList);
1574:                    } else if (t.currentToken == Token.LET) {
1575:                        parseLetClause(clauseList);
1576:                    } else {
1577:                        break;
1578:                    }
1579:                }
1580:                if (t.currentToken == Token.WHERE || isKeyword("where")) {
1581:                    whereOffset = t.currentTokenStartOffset;
1582:                    nextToken();
1583:                    whereCondition = parseExprSingle();
1584:                }
1585:                int orderByOffset = t.currentTokenStartOffset;
1586:                if (isKeyword("stable")) {
1587:                    // we read the "stable" keyword but ignore it; Saxon ordering is always stable
1588:                    nextToken();
1589:                    if (!isKeyword("order")) {
1590:                        grumble("'stable' must be followed by 'order by'");
1591:                    }
1592:                }
1593:                List sortSpecList = null;
1594:                if (isKeyword("order")) {
1595:                    t.setState(Tokenizer.BARE_NAME_STATE);
1596:                    nextToken();
1597:                    if (!isKeyword("by")) {
1598:                        grumble("'order' must be followed by 'by'");
1599:                    }
1600:                    t.setState(Tokenizer.DEFAULT_STATE);
1601:                    nextToken();
1602:                    sortSpecList = parseSortDefinition();
1603:                }
1604:                int returnOffset = t.currentTokenStartOffset;
1605:                expect(Token.RETURN);
1606:                t.setState(Tokenizer.DEFAULT_STATE);
1607:                nextToken();
1608:                Expression action = parseExprSingle();
1609:                action = makeTracer(returnOffset, action,
1610:                        Location.RETURN_EXPRESSION, -1);
1611:
1612:                // If there is an order by clause, we modify the "return" expression so that it
1613:                // returns a tuple containing the actual return value, plus the value of
1614:                // each of the sort keys. We then wrap the entire FLWR expression inside a
1615:                // TupleSorter that sorts the stream of tuples according to the sort keys,
1616:                // discarding the sort keys and returning only the true result. The tuple
1617:                // is implemented as a Java object wrapped inside an ObjectValue, which is
1618:                // a general-purpose wrapper for objects that don't fit in the XPath type system.
1619:
1620:                if (sortSpecList != null) {
1621:                    TupleExpression exp = new TupleExpression(1 + sortSpecList
1622:                            .size());
1623:                    setLocation(exp);
1624:                    exp.setExpression(0, action);
1625:                    for (int i = 0; i < sortSpecList.size(); i++) {
1626:                        try {
1627:                            RoleLocator role = new RoleLocator(
1628:                                    RoleLocator.ORDER_BY, "FLWR", i, null);
1629:                            role.setSourceLocator(makeLocator());
1630:                            Expression sk = TypeChecker.staticTypeCheck(
1631:                                    ((SortSpec) sortSpecList.get(i)).sortKey,
1632:                                    SequenceType.OPTIONAL_ATOMIC, false, role,
1633:                                    env);
1634:                            exp.setExpression(i + 1, sk);
1635:                        } catch (XPathException err) {
1636:                            grumble(err.getMessage());
1637:                        }
1638:                    }
1639:                    action = exp;
1640:                }
1641:
1642:                // if there is a "where" condition, we implement this by wrapping an if/then/else
1643:                // around the "return" expression. No clever optimization yet!
1644:
1645:                if (whereCondition != null) {
1646:                    action = new IfExpression(whereCondition, action,
1647:                            EmptySequence.getInstance());
1648:                    action = makeTracer(whereOffset, action,
1649:                            Location.WHERE_CLAUSE, -1);
1650:                    setLocation(action);
1651:                }
1652:
1653:                for (int i = clauseList.size() - 1; i >= 0; i--) {
1654:                    Object clause = clauseList.get(i);
1655:                    if (clause instanceof  ExpressionParser.ForClause) {
1656:                        ExpressionParser.ForClause fc = (ExpressionParser.ForClause) clause;
1657:                        ForExpression exp = new ForExpression();
1658:                        exp.setVariableDeclaration(fc.rangeVariable);
1659:                        exp.setPositionVariable(fc.positionVariable);
1660:                        exp.setLocationId(env.getLocationMap()
1661:                                .allocateLocationId(env.getSystemId(),
1662:                                        t.getLineNumber(fc.offset)));
1663:                        exp.setSequence(fc.sequence);
1664:                        exp.setAction(action);
1665:                        action = makeTracer(fc.offset, exp,
1666:                                Location.FOR_EXPRESSION, fc.rangeVariable
1667:                                        .getNameCode());
1668:                    } else {
1669:                        LetClause lc = (LetClause) clause;
1670:                        LetExpression exp = makeLetExpression();
1671:                        exp.setVariableDeclaration(lc.variable);
1672:                        exp.setLocationId(env.getLocationMap()
1673:                                .allocateLocationId(env.getSystemId(),
1674:                                        t.getLineNumber(lc.offset)));
1675:                        exp.setSequence(lc.value);
1676:                        exp.setAction(action);
1677:                        action = makeTracer(lc.offset, exp,
1678:                                Location.LET_EXPRESSION, lc.variable
1679:                                        .getNameCode());
1680:                    }
1681:                }
1682:
1683:                // Now wrap the whole expression in a TupleSorter if there is a sort specification
1684:
1685:                if (sortSpecList != null) {
1686:                    FixedSortKeyDefinition[] keys = new FixedSortKeyDefinition[sortSpecList
1687:                            .size()];
1688:                    for (int i = 0; i < sortSpecList.size(); i++) {
1689:                        SortSpec spec = (SortSpec) sortSpecList.get(i);
1690:                        FixedSortKeyDefinition key = new FixedSortKeyDefinition();
1691:                        //key.setSortKey(((SortSpec) sortSpecList.get(i)).sortKey);
1692:                        key.setSortKey(StringValue.EMPTY_STRING);
1693:                        key.setOrder(new StringValue(
1694:                                spec.ascending ? "ascending" : "descending"));
1695:                        key.setEmptyFirst(spec.ascending ? spec.emptyLeast
1696:                                : !spec.emptyLeast);
1697:
1698:                        if (spec.collation != null) {
1699:                            final Comparator comparator = env
1700:                                    .getCollation(spec.collation);
1701:                            if (comparator == null) {
1702:                                grumble("Unknown collation '" + spec.collation
1703:                                        + '\'', "XQST0076");
1704:                            }
1705:                            key.setCollation(comparator);
1706:                        }
1707:                        try {
1708:                            key.bindComparer(env.makeEarlyEvaluationContext());
1709:                            keys[i] = key;
1710:                        } catch (XPathException e) {
1711:                            grumble(e.getMessage());
1712:                        }
1713:                    }
1714:                    TupleSorter sorter = new TupleSorter(action, keys);
1715:                    setLocation(sorter);
1716:                    action = makeTracer(orderByOffset, sorter,
1717:                            Location.ORDER_BY_CLAUSE, -1);
1718:                }
1719:
1720:                // undeclare all the range variables
1721:
1722:                for (int i = clauseList.size() - 1; i >= 0; i--) {
1723:                    Object clause = clauseList.get(i);
1724:                    if ((clause instanceof  ExpressionParser.ForClause)
1725:                            && ((ExpressionParser.ForClause) clause).positionVariable != null) {
1726:                        // undeclare the "at" variable if it was declared
1727:                        undeclareRangeVariable();
1728:                    }
1729:                    // undeclare the primary variable
1730:                    undeclareRangeVariable();
1731:                }
1732:
1733:                setLocation(action, offset);
1734:                return action;
1735:
1736:            }
1737:
1738:            /**
1739:             * Make a LetExpression. This returns an ordinary LetExpression if tracing is off, and an EagerLetExpression
1740:             * if tracing is on. This is so that trace events occur in an order that the user can follow.
1741:             */
1742:
1743:            private LetExpression makeLetExpression() {
1744:                if (env.getConfiguration().getTraceListener() == null) {
1745:                    return new LetExpression();
1746:                } else {
1747:                    return new EagerLetExpression();
1748:                }
1749:            }
1750:
1751:            /**
1752:             * Parse a ForClause.
1753:             * <p/>
1754:             * [42] ForClause ::=  <"for" "$"> VarName TypeDeclaration? PositionalVar? "in" ExprSingle
1755:             * ("," "$" VarName TypeDeclaration? PositionalVar? "in" ExprSingle)*
1756:             * </p>
1757:             *
1758:             * @param clauseList - the components of the parsed ForClause are appended to the
1759:             *                   supplied list
1760:             * @throws net.sf.saxon.trans.StaticError
1761:             */
1762:            private void parseForClause(List clauseList) throws StaticError {
1763:                boolean first = true;
1764:                do {
1765:                    ExpressionParser.ForClause clause = new ExpressionParser.ForClause();
1766:                    if (first) {
1767:                        clause.offset = t.currentTokenStartOffset;
1768:                    }
1769:                    clauseList.add(clause);
1770:                    nextToken();
1771:                    if (first) {
1772:                        first = false;
1773:                    } else {
1774:                        clause.offset = t.currentTokenStartOffset;
1775:                    }
1776:                    expect(Token.DOLLAR);
1777:                    nextToken();
1778:                    expect(Token.NAME);
1779:                    String var = t.currentTokenValue;
1780:
1781:                    RangeVariableDeclaration v = new RangeVariableDeclaration();
1782:                    v.setNameCode(makeNameCode(var, false));
1783:                    v.setRequiredType(SequenceType.SINGLE_ITEM);
1784:                    v.setVariableName(var);
1785:                    clause.rangeVariable = v;
1786:                    nextToken();
1787:
1788:                    if (isKeyword("as")) {
1789:                        nextToken();
1790:                        SequenceType type = parseSequenceType();
1791:                        v.setRequiredType(type);
1792:                        if (type.getCardinality() != StaticProperty.EXACTLY_ONE) {
1793:                            grumble(
1794:                                    "Cardinality of range variable must be exactly one",
1795:                                    "XPTY0004");
1796:                        }
1797:                    }
1798:                    clause.positionVariable = null;
1799:                    if (isKeyword("at")) {
1800:                        nextToken();
1801:                        expect(Token.DOLLAR);
1802:                        nextToken();
1803:                        expect(Token.NAME);
1804:                        RangeVariableDeclaration pos = new RangeVariableDeclaration();
1805:                        pos
1806:                                .setNameCode(makeNameCode(t.currentTokenValue,
1807:                                        false));
1808:                        pos.setRequiredType(SequenceType.SINGLE_INTEGER);
1809:                        pos.setVariableName(t.currentTokenValue);
1810:                        clause.positionVariable = pos;
1811:                        //declareRangeVariable(pos);
1812:                        nextToken();
1813:                    }
1814:                    expect(Token.IN);
1815:                    nextToken();
1816:                    clause.sequence = parseExprSingle();
1817:                    declareRangeVariable(clause.rangeVariable);
1818:                    if (clause.positionVariable != null) {
1819:                        declareRangeVariable(clause.positionVariable);
1820:                    }
1821:                } while (t.currentToken == Token.COMMA);
1822:            }
1823:
1824:            /**
1825:             * Parse a LetClause.
1826:             * <p/>
1827:             * [44] LetClause ::= <"let" "$"> VarName TypeDeclaration? ":=" ExprSingle
1828:             * ("," "$" VarName TypeDeclaration? ":=" ExprSingle)*
1829:             * </p>
1830:             *
1831:             * @param clauseList - the components of the parsed LetClause are appended to the
1832:             *                   supplied list
1833:             * @throws net.sf.saxon.trans.StaticError
1834:             */
1835:            private void parseLetClause(List clauseList) throws StaticError {
1836:                boolean first = true;
1837:                do {
1838:                    LetClause clause = new LetClause();
1839:                    if (first) {
1840:                        clause.offset = t.currentTokenStartOffset;
1841:                    }
1842:                    clauseList.add(clause);
1843:                    nextToken();
1844:                    if (first) {
1845:                        first = false;
1846:                    } else {
1847:                        clause.offset = t.currentTokenStartOffset;
1848:                    }
1849:                    expect(Token.DOLLAR);
1850:                    nextToken();
1851:                    expect(Token.NAME);
1852:                    String var = t.currentTokenValue;
1853:
1854:                    RangeVariableDeclaration v = new RangeVariableDeclaration();
1855:                    v.setNameCode(makeNameCode(var, false));
1856:                    v.setRequiredType(SequenceType.ANY_SEQUENCE);
1857:                    v.setVariableName(var);
1858:                    clause.variable = v;
1859:                    nextToken();
1860:
1861:                    if (isKeyword("as")) {
1862:                        nextToken();
1863:                        v.setRequiredType(parseSequenceType());
1864:                    }
1865:
1866:                    expect(Token.ASSIGN);
1867:                    nextToken();
1868:                    clause.value = parseExprSingle();
1869:                    declareRangeVariable(v);
1870:                } while (t.currentToken == Token.COMMA);
1871:            }
1872:
1873:            /**
1874:             * Make a string-join expression that concatenates the string-values of items in
1875:             * a sequence with intervening spaces. This may be simplified later as a result
1876:             * of type-checking.
1877:             */
1878:
1879:            public static Expression makeStringJoin(Expression exp,
1880:                    StaticContext env) {
1881:
1882:                exp = new Atomizer(exp, env.getConfiguration());
1883:                final TypeHierarchy th = env.getNamePool().getTypeHierarchy();
1884:                ItemType t = exp.getItemType(th);
1885:                if (t != Type.STRING_TYPE && t != Type.UNTYPED_ATOMIC_TYPE) {
1886:                    exp = new AtomicSequenceConverter(exp, Type.STRING_TYPE);
1887:                }
1888:
1889:                StringJoin fn = (StringJoin) SystemFunction.makeSystemFunction(
1890:                        "string-join", 2, env.getNamePool());
1891:                Expression[] args = new Expression[2];
1892:                args[0] = exp;
1893:                args[1] = StringValue.SINGLE_SPACE;
1894:                fn.setArguments(args);
1895:                if (exp instanceof  ComputedExpression) {
1896:                    fn
1897:                            .setLocationId(((ComputedExpression) exp)
1898:                                    .getLocationId());
1899:                }
1900:                return fn;
1901:            }
1902:
1903:            private static class LetClause {
1904:                public RangeVariableDeclaration variable;
1905:                public Expression value;
1906:                public int offset;
1907:            }
1908:
1909:            /**
1910:             * Parse the "order by" clause.
1911:             * [46] OrderByClause ::= (<"order" "by"> | <"stable" "order" "by">) OrderSpecList
1912:             * [47] OrderSpecList ::= OrderSpec  ("," OrderSpec)*
1913:             * [48] OrderSpec     ::=     ExprSingle  OrderModifier
1914:             * [49] OrderModifier ::= ("ascending" | "descending")?
1915:             * (<"empty" "greatest"> | <"empty" "least">)?
1916:             * ("collation" StringLiteral)?
1917:             *
1918:             * @return a list of sort specifications (SortSpec), one per sort key
1919:             * @throws net.sf.saxon.trans.StaticError
1920:             */
1921:            private List parseSortDefinition() throws StaticError {
1922:                List sortSpecList = new ArrayList(5);
1923:                while (true) {
1924:                    SortSpec sortSpec = new SortSpec();
1925:                    sortSpec.sortKey = parseExprSingle();
1926:                    sortSpec.ascending = true;
1927:                    sortSpec.emptyLeast = defaultEmptyLeast;
1928:                    sortSpec.collation = env.getDefaultCollationName();
1929:                    //t.setState(t.BARE_NAME_STATE);
1930:                    if (isKeyword("ascending")) {
1931:                        nextToken();
1932:                    } else if (isKeyword("descending")) {
1933:                        sortSpec.ascending = false;
1934:                        nextToken();
1935:                    }
1936:                    if (isKeyword("empty")) {
1937:                        nextToken();
1938:                        if (isKeyword("greatest")) {
1939:                            sortSpec.emptyLeast = false;
1940:                            nextToken();
1941:                        } else if (isKeyword("least")) {
1942:                            sortSpec.emptyLeast = true;
1943:                            nextToken();
1944:                        } else {
1945:                            grumble("'empty' must be followed by 'greatest' or 'least'");
1946:                        }
1947:                    }
1948:                    if (isKeyword("collation")) {
1949:                        nextToken();
1950:                        expect(Token.STRING_LITERAL);
1951:                        String collationName = URILiteral(t.currentTokenValue);
1952:                        URI collationURI;
1953:                        try {
1954:                            collationURI = new URI(collationName);
1955:                            if (!collationURI.isAbsolute()) {
1956:                                URI base = new URI(env.getBaseURI());
1957:                                collationURI = base.resolve(collationURI);
1958:                                collationName = collationURI.toString();
1959:                            }
1960:                        } catch (URISyntaxException err) {
1961:                            grumble("Collation name '" + collationName
1962:                                    + "' is not a valid URI");
1963:                            collationName = NamespaceConstant.CODEPOINT_COLLATION_URI;
1964:                        }
1965:                        sortSpec.collation = collationName;
1966:                        nextToken();
1967:                    }
1968:                    sortSpecList.add(sortSpec);
1969:                    if (t.currentToken == Token.COMMA) {
1970:                        nextToken();
1971:                    } else {
1972:                        break;
1973:                    }
1974:                }
1975:                return sortSpecList;
1976:            }
1977:
1978:            private static class SortSpec {
1979:                public Expression sortKey;
1980:                public boolean ascending;
1981:                public boolean emptyLeast;
1982:                public String collation;
1983:            }
1984:
1985:            /**
1986:             * Parse a Typeswitch Expression.
1987:             * This construct is XQuery-only.
1988:             * TypeswitchExpr   ::=
1989:             * "typeswitch" "(" Expr ")"
1990:             * CaseClause+
1991:             * "default" ("$" VarName)? "return" ExprSingle
1992:             * CaseClause   ::=
1993:             * "case" ("$" VarName "as")? SequenceType "return" Expr
1994:             */
1995:
1996:            protected Expression parseTypeswitchExpression() throws StaticError {
1997:
1998:                // On entry, the "(" has already been read
1999:                int offset = t.currentTokenStartOffset;
2000:                nextToken();
2001:                Expression operand = parseExpression();
2002:                List types = new ArrayList(10);
2003:                List actions = new ArrayList(10);
2004:                expect(Token.RPAR);
2005:                nextToken();
2006:
2007:                // The code generated takes the form:
2008:                //    let $zzz := operand return
2009:                //    if ($zzz instance of t1) then action1
2010:                //    else if ($zzz instance of t2) then action2
2011:                //    else default-action
2012:                //
2013:                // If a variable is declared in a case clause or default clause,
2014:                // then "action-n" takes the form
2015:                //    let $v as type := $zzz return action-n
2016:
2017:                // we were generating "let $v as type := $zzz return action-n" but this gives a compile time error if
2018:                // there's a case clause that specifies an impossible type.
2019:
2020:                LetExpression outerLet = makeLetExpression();
2021:
2022:                RangeVariableDeclaration gen = new RangeVariableDeclaration();
2023:                gen.setNameCode(makeNameCode("zz_typeswitchVar", false));
2024:                gen.setRequiredType(SequenceType.ANY_SEQUENCE);
2025:                gen.setVariableName("zz_typeswitchVar");
2026:
2027:                outerLet.setVariableDeclaration(gen);
2028:                outerLet.setSequence(operand);
2029:
2030:                while (t.currentToken == Token.CASE) {
2031:                    int caseOffset = t.currentTokenStartOffset;
2032:                    SequenceType type;
2033:                    Expression action;
2034:                    nextToken();
2035:                    if (t.currentToken == Token.DOLLAR) {
2036:                        nextToken();
2037:                        expect(Token.NAME);
2038:                        final String var = t.currentTokenValue;
2039:                        final int varCode = makeNameCode(var, false);
2040:                        nextToken();
2041:                        expect(Token.NAME);
2042:                        if (!"as".equals(t.currentTokenValue)) {
2043:                            grumble("After 'case $" + var + "', expected 'as'");
2044:                        }
2045:                        nextToken();
2046:                        type = parseSequenceType();
2047:                        action = makeTracer(caseOffset,
2048:                                parseTypeswitchReturnClause(var, varCode, gen),
2049:                                Location.CASE_EXPRESSION, varCode);
2050:                        if (action instanceof  TraceExpression) {
2051:                            ((TraceExpression) action).setProperty("type", type
2052:                                    .toString());
2053:                        }
2054:
2055:                    } else {
2056:                        type = parseSequenceType();
2057:                        t.treatCurrentAsOperator();
2058:                        expect(Token.RETURN);
2059:                        nextToken();
2060:                        action = makeTracer(caseOffset, parseExprSingle(),
2061:                                Location.CASE_EXPRESSION, -1);
2062:                        if (action instanceof  TraceExpression) {
2063:                            ((TraceExpression) action).setProperty("type", type
2064:                                    .toString());
2065:                        }
2066:                    }
2067:                    types.add(type);
2068:                    actions.add(action);
2069:                }
2070:                if (types.size() == 0) {
2071:                    grumble("At least one case clause is required in a typeswitch");
2072:                }
2073:                expect(Token.DEFAULT);
2074:                final int defaultOffset = t.currentTokenStartOffset;
2075:                nextToken();
2076:                Expression defaultAction;
2077:                if (t.currentToken == Token.DOLLAR) {
2078:                    nextToken();
2079:                    expect(Token.NAME);
2080:                    final String var = t.currentTokenValue;
2081:                    final int varCode = makeNameCode(var, false);
2082:                    nextToken();
2083:                    defaultAction = makeTracer(defaultOffset,
2084:                            parseTypeswitchReturnClause(var, varCode, gen),
2085:                            Location.DEFAULT_EXPRESSION, varCode);
2086:                } else {
2087:                    t.treatCurrentAsOperator();
2088:                    expect(Token.RETURN);
2089:                    nextToken();
2090:                    defaultAction = makeTracer(defaultOffset,
2091:                            parseExprSingle(), Location.DEFAULT_EXPRESSION, -1);
2092:                }
2093:
2094:                Expression lastAction = defaultAction;
2095:                for (int i = types.size() - 1; i >= 0; i--) {
2096:                    final VariableReference var = new VariableReference(gen);
2097:                    setLocation(var);
2098:                    final InstanceOfExpression ioe = new InstanceOfExpression(
2099:                            var, (SequenceType) types.get(i));
2100:                    setLocation(ioe);
2101:                    final IfExpression ife = new IfExpression(ioe,
2102:                            (Expression) actions.get(i), lastAction);
2103:                    setLocation(ife);
2104:                    lastAction = ife;
2105:                }
2106:                outerLet.setAction(lastAction);
2107:                return makeTracer(offset, outerLet,
2108:                        Location.TYPESWITCH_EXPRESSION, -1);
2109:            }
2110:
2111:            private Expression parseTypeswitchReturnClause(String var,
2112:                    int varCode, RangeVariableDeclaration gen)
2113:                    throws StaticError {
2114:                Expression action;
2115:                t.treatCurrentAsOperator();
2116:                expect(Token.RETURN);
2117:                nextToken();
2118:
2119:                RangeVariableDeclaration v = new RangeVariableDeclaration();
2120:                v.setNameCode(varCode);
2121:                v.setRequiredType(SequenceType.ANY_SEQUENCE);
2122:                v.setVariableName(var);
2123:
2124:                declareRangeVariable(v);
2125:                action = parseExprSingle();
2126:                undeclareRangeVariable();
2127:
2128:                LetExpression innerLet = makeLetExpression();
2129:                innerLet.setVariableDeclaration(v);
2130:                innerLet.setSequence(new VariableReference(gen));
2131:                innerLet.setAction(action);
2132:                action = innerLet;
2133:                return action;
2134:            }
2135:
2136:            /**
2137:             * Parse a Validate Expression.
2138:             * This construct is XQuery-only. The syntax allows:
2139:             * validate mode? { Expr }
2140:             * mode ::= "strict" | "lax"
2141:             */
2142:
2143:            protected Expression parseValidateExpression() throws StaticError {
2144:                if (!env.getConfiguration().isSchemaAware(Configuration.XQUERY)) {
2145:                    grumble("To use a validate expression, you need the schema-aware processor from http://www.saxonica.com/");
2146:                }
2147:                int offset = t.currentTokenStartOffset;
2148:                int mode = Validation.STRICT;
2149:                boolean foundCurly = false;
2150:                switch (t.currentToken) {
2151:                case Token.VALIDATE_STRICT:
2152:                    mode = Validation.STRICT;
2153:                    nextToken();
2154:                    break;
2155:                case Token.VALIDATE_LAX:
2156:                    mode = Validation.LAX;
2157:                    nextToken();
2158:                    break;
2159:                case Token.KEYWORD_CURLY:
2160:                    if (t.currentTokenValue == "validate") {
2161:                        mode = Validation.STRICT;
2162:                    } else {
2163:                        throw new AssertionError(
2164:                                "shouldn't be parsing a validate expression");
2165:                    }
2166:                    foundCurly = true;
2167:                }
2168:
2169:                if (!foundCurly) {
2170:                    expect(Token.LCURLY);
2171:                }
2172:                nextToken();
2173:
2174:                Expression exp = parseExpression();
2175:                if (exp instanceof  ElementCreator) {
2176:                    ((ElementCreator) exp).setValidationMode(mode);
2177:                } else if (exp instanceof  DocumentInstr) {
2178:                    ((DocumentInstr) exp).setValidationAction(mode);
2179:                } else {
2180:                    // the expression must return a single element or document node. The type-
2181:                    // checking machinery can't handle a union type, so we just check that it's
2182:                    // a node for now. Because we are reusing XSLT copy-of code, we need
2183:                    // an ad-hoc check that the node is of the right kind.
2184:                    try {
2185:                        RoleLocator role = new RoleLocator(RoleLocator.TYPE_OP,
2186:                                "validate", 0, null);
2187:                        role.setSourceLocator(makeLocator());
2188:                        exp = TypeChecker.staticTypeCheck(exp,
2189:                                SequenceType.SINGLE_NODE, false, role, env);
2190:                    } catch (XPathException err) {
2191:                        grumble(err.getMessage());
2192:                    }
2193:                    exp = new CopyOf(exp, true, mode, null, true);
2194:                    setLocation(exp);
2195:                    ((CopyOf) exp).setRequireDocumentOrElement(true);
2196:                }
2197:
2198:                expect(Token.RCURLY);
2199:                t.lookAhead(); // always done manually after an RCURLY
2200:                nextToken();
2201:                return makeTracer(offset, exp, Location.VALIDATE_EXPRESSION, -1);
2202:            }
2203:
2204:            /**
2205:             * Parse an Extension Expression.
2206:             * Syntax: "(#" QName arbitrary-text "#)")+ "{" expr? "}"
2207:             * Currenly Saxon does not recognize any extension expressions, so the pragma is ignored and
2208:             * the following expression is returned. (We don't even check the QName)
2209:             */
2210:
2211:            protected Expression parseExtensionExpression() throws StaticError {
2212:                SchemaType requiredType = null;
2213:                String pragmaContents = t.currentTokenValue.trim();
2214:                Tokenizer s = new Tokenizer();
2215:                s.setState(Tokenizer.BARE_NAME_STATE); // don't recognize QNAME() as a function call
2216:                s.tokenize(pragmaContents, 0, pragmaContents.length(), 1);
2217:                if (s.currentToken == Token.NAME) {
2218:                    int nameCode = makeNameCode(s.currentTokenValue, false);
2219:                    if ((nameCode & NamePool.FP_MASK) == StandardNames.SAXON_VALIDATE_TYPE) {
2220:                        if (!env.getConfiguration().isSchemaAware(
2221:                                Configuration.XQUERY)) {
2222:                            grumble("To use saxon:validate-type, "
2223:                                    + "you need the schema-aware processor from http://www.saxonica.com/");
2224:                        }
2225:                        s.next();
2226:                        if (s.currentToken != Token.NAME) {
2227:                            grumble("Schema type expected in saxon:validate-type pragma");
2228:                        }
2229:                        int typeCode = makeNameCode(s.currentTokenValue, true);
2230:                        requiredType = env.getConfiguration().getSchemaType(
2231:                                typeCode & NamePool.FP_MASK);
2232:                        if (requiredType == null) {
2233:                            grumble("Unknown schema type "
2234:                                    + s.currentTokenValue);
2235:                        }
2236:                        s.next();
2237:                        if (s.currentToken != Token.EOF) {
2238:                            grumble("Unexpected characters after schema type in saxon:validate-type pragma");
2239:                        }
2240:                    } else if (env.getNamePool().getURI(nameCode) == NamespaceConstant.SAXON) {
2241:                        grumble("Unrecognized Saxon pragma "
2242:                                + s.currentTokenValue);
2243:                    }
2244:                } else {
2245:                    grumble("Pragma must start with a valid QName");
2246:                }
2247:
2248:                nextToken();
2249:                Expression expr;
2250:                if (t.currentToken == Token.PRAGMA) {
2251:                    expr = parseExtensionExpression();
2252:                } else {
2253:                    expect(Token.LCURLY);
2254:                    nextToken();
2255:                    if (t.currentToken == Token.RCURLY) {
2256:                        t.lookAhead(); // always done manually after an RCURLY
2257:                        nextToken();
2258:                        grumble("Unrecognized pragma, with no fallback expression");
2259:                    }
2260:                    expr = parseExpression();
2261:                    expect(Token.RCURLY);
2262:                    t.lookAhead(); // always done manually after an RCURLY
2263:                    nextToken();
2264:                }
2265:                if (requiredType == null) {
2266:                    return expr;
2267:                } else if (expr instanceof  ElementCreator) {
2268:                    ((ElementCreator) expr).setSchemaType(requiredType);
2269:                    return expr;
2270:                } else if (expr instanceof  ElementCreator) {
2271:                    ((ElementCreator) expr).setSchemaType(requiredType);
2272:                    return expr;
2273:                } else {
2274:                    CopyOf copy = new CopyOf(expr, true, 0, requiredType, true);
2275:                    copy.setLocationId(env.getLocationMap().allocateLocationId(
2276:                            env.getSystemId(), t.getLineNumber()));
2277:                    return copy;
2278:                }
2279:            }
2280:
2281:            /**
2282:             * Parse a node constructor. This is allowed only in XQuery. This method handles
2283:             * both the XML-like "direct" constructors, and the XQuery-based "computed"
2284:             * constructors.
2285:             *
2286:             * @return an Expression for evaluating the parsed constructor
2287:             * @throws net.sf.saxon.trans.StaticError in the event of a syntax error.
2288:             */
2289:
2290:            protected Expression parseConstructor() throws StaticError {
2291:                int offset = t.currentTokenStartOffset;
2292:                switch (t.currentToken) {
2293:                case Token.TAG:
2294:                    Expression tag = parsePseudoXML(false);
2295:                    lookAhead();
2296:                    t.setState(Tokenizer.OPERATOR_STATE);
2297:                    nextToken();
2298:                    return tag;
2299:                case Token.KEYWORD_CURLY:
2300:                    String nodeKind = t.currentTokenValue;
2301:                    if (nodeKind == "validate") {
2302:                        return parseValidateExpression();
2303:                    } else if (nodeKind == "ordered" || nodeKind == "unordered") {
2304:                        // these are currently no-ops in Saxon
2305:                        nextToken();
2306:                        Expression content = parseExpression();
2307:                        expect(Token.RCURLY);
2308:                        lookAhead(); // must be done manually after an RCURLY
2309:                        nextToken();
2310:                        return content;
2311:                    } else if (nodeKind == "document") {
2312:                        nextToken();
2313:                        Expression content = parseExpression();
2314:                        expect(Token.RCURLY);
2315:                        lookAhead(); // must be done manually after an RCURLY
2316:                        nextToken();
2317:                        DocumentInstr doc = new DocumentInstr(false, null, env
2318:                                .getBaseURI());
2319:                        if (!((StaticQueryContext) env).isPreserveNamespaces()) {
2320:                            content = new CopyOf(content, false,
2321:                                    Validation.PRESERVE, null, true);
2322:                        }
2323:                        doc.setValidationAction(((StaticQueryContext) env)
2324:                                .getConstructionMode());
2325:                        doc.setContentExpression(content);
2326:                        setLocation(doc, offset);
2327:                        return doc;
2328:
2329:                    } else if ("element".equals(nodeKind)) {
2330:                        nextToken();
2331:                        // get the expression that yields the element name
2332:                        Expression name = parseExpression();
2333:                        expect(Token.RCURLY);
2334:                        lookAhead(); // must be done manually after an RCURLY
2335:                        nextToken();
2336:                        expect(Token.LCURLY);
2337:                        t.setState(Tokenizer.DEFAULT_STATE);
2338:                        nextToken();
2339:                        Expression content = null;
2340:                        if (t.currentToken != Token.RCURLY) {
2341:                            // get the expression that yields the element content
2342:                            content = parseExpression();
2343:                            // if the child expression creates another element,
2344:                            // suppress validation, as the parent already takes care of it
2345:                            if (content instanceof  ElementCreator) {
2346:                                ((ElementCreator) content)
2347:                                        .setValidationMode(Validation.PRESERVE);
2348:                            }
2349:                            expect(Token.RCURLY);
2350:                        }
2351:                        lookAhead(); // done manually after an RCURLY
2352:                        nextToken();
2353:
2354:                        Instruction inst;
2355:                        if (name instanceof  Value) {
2356:                            // if element name is supplied as a literal, treat it like a direct element constructor
2357:                            int nameCode;
2358:                            if (name instanceof  StringValue
2359:                                    && !(name instanceof  AnyURIValue)) {
2360:                                String lex = ((StringValue) name)
2361:                                        .getStringValue();
2362:                                // prevalidate the name before calling makeNameCode, because we want different
2363:                                // error behaviour
2364:                                try {
2365:                                    nameChecker.getQNameParts(lex);
2366:                                } catch (QNameException err) {
2367:                                    DynamicError e = new DynamicError(
2368:                                            "Invalid QName in element constructor: "
2369:                                                    + lex);
2370:                                    e.setErrorCode("XQDY0074");
2371:                                    return new ErrorExpression(e);
2372:                                }
2373:                                try {
2374:                                    nameCode = makeNameCode(lex, true);
2375:                                } catch (StaticError staticError) {
2376:                                    String code = staticError
2377:                                            .getErrorCodeLocalPart();
2378:                                    if ("XPST0008".equals(code)
2379:                                            || "XPST0081".equals(code)) {
2380:                                        staticError.setErrorCode("XQDY0074");
2381:                                    }
2382:                                    throw staticError;
2383:                                }
2384:                            } else if (name instanceof  QNameValue) {
2385:                                nameCode = env.getNamePool().allocate("",
2386:                                        ((QNameValue) name).getNamespaceURI(),
2387:                                        ((QNameValue) name).getLocalName());
2388:                            } else {
2389:                                grumble(
2390:                                        "Element name must be either a string or a QName",
2391:                                        "XPTY0004");
2392:                                return null;
2393:                            }
2394:                            inst = new FixedElement(nameCode,
2395:                                    ((StaticQueryContext) env)
2396:                                            .getActiveNamespaceCodes(),
2397:                                    ((StaticQueryContext) env)
2398:                                            .isInheritNamespaces(), null,
2399:                                    ((StaticQueryContext) env)
2400:                                            .getConstructionMode());
2401:                            if (content == null) {
2402:                                content = EmptySequence.getInstance();
2403:                            }
2404:                            ((FixedElement) inst).setContentExpression(content);
2405:                            setLocation(inst, offset);
2406:                            //makeContentConstructor(content, (InstructionWithChildren) inst, offset);
2407:                            return makeTracer(offset, inst,
2408:                                    Location.LITERAL_RESULT_ELEMENT, nameCode);
2409:                        } else {
2410:                            // it really is a computed element constructor: save the namespace context
2411:                            inst = new ComputedElement(name, null, env
2412:                                    .getNamespaceResolver(), null,
2413:                                    ((StaticQueryContext) env)
2414:                                            .getConstructionMode(),
2415:                                    ((StaticQueryContext) env)
2416:                                            .isInheritNamespaces(), true);
2417:                            setLocation(inst);
2418:                            if (content == null) {
2419:                                content = EmptySequence.getInstance();
2420:                            }
2421:                            ((ComputedElement) inst)
2422:                                    .setContentExpression(content);
2423:                            setLocation(inst, offset);
2424:                            //makeContentConstructor(content, (InstructionWithChildren) inst, offset);
2425:                            return makeTracer(offset, inst,
2426:                                    StandardNames.XSL_ELEMENT, -1);
2427:                        }
2428:
2429:                    } else if ("attribute".equals(nodeKind)) {
2430:                        nextToken();
2431:                        Expression name = parseExpression();
2432:                        expect(Token.RCURLY);
2433:                        lookAhead(); // must be done manually after an RCURLY
2434:                        nextToken();
2435:                        expect(Token.LCURLY);
2436:                        t.setState(Tokenizer.DEFAULT_STATE);
2437:                        nextToken();
2438:                        Expression content = null;
2439:                        if (t.currentToken != Token.RCURLY) {
2440:                            content = parseExpression();
2441:                            expect(Token.RCURLY);
2442:                        }
2443:                        lookAhead(); // after an RCURLY
2444:                        nextToken();
2445:                        if (name instanceof  StringValue
2446:                                && !(name instanceof  AnyURIValue)
2447:                                && content instanceof  Value) {
2448:                            String attName = ((StringValue) name)
2449:                                    .getStringValue();
2450:                            if (attName.equals("xmlns")
2451:                                    || attName.startsWith("xmlns:")) {
2452:                                grumble(
2453:                                        "Cannot create a namespace using an attribute constructor",
2454:                                        "XQDY0044");
2455:                            }
2456:                            int nameCode;
2457:                            String lex = ((StringValue) name).getStringValue();
2458:                            // prevalidate the name before calling makeNameCode, because we want different
2459:                            // error behaviour
2460:                            try {
2461:                                nameChecker.getQNameParts(lex);
2462:                            } catch (QNameException err) {
2463:                                DynamicError e = new DynamicError(
2464:                                        "Invalid QName in attribute constructor: "
2465:                                                + lex);
2466:                                e.setErrorCode("XQDY0074");
2467:                                return new ErrorExpression(e);
2468:                            }
2469:                            try {
2470:                                nameCode = makeNameCode(attName, false);
2471:                            } catch (StaticError staticError) {
2472:                                String code = staticError
2473:                                        .getErrorCodeLocalPart();
2474:                                if ("XPST0008".equals(code)
2475:                                        || "XPST0081".equals(code)) {
2476:                                    staticError.setErrorCode("XQDY0074");
2477:                                }
2478:                                throw staticError;
2479:                            }
2480:                            FixedAttribute fatt = new FixedAttribute(nameCode,
2481:                                    Validation.STRIP, null,
2482:                                    StandardNames.XDT_UNTYPED_ATOMIC);
2483:                            fatt.setRejectDuplicates();
2484:                            makeSimpleContent(content, fatt, offset);
2485:                            return makeTracer(offset, fatt,
2486:                                    StandardNames.XSL_ATTRIBUTE, -1);
2487:                        } else {
2488:                            Attribute att = new Attribute(name, null, env
2489:                                    .getNamespaceResolver(), Validation.STRIP,
2490:                                    null, -1, true);
2491:                            att.setRejectDuplicates();
2492:                            makeSimpleContent(content, att, offset);
2493:                            return makeTracer(offset, att,
2494:                                    StandardNames.XSL_ATTRIBUTE, -1);
2495:                        }
2496:
2497:                    } else if ("text".equals(nodeKind)) {
2498:                        nextToken();
2499:                        if (t.currentToken == Token.RCURLY) {
2500:                            lookAhead(); // after an RCURLY
2501:                            nextToken();
2502:                            return EmptySequence.getInstance();
2503:                        } else {
2504:                            Expression value = parseExpression();
2505:                            expect(Token.RCURLY);
2506:                            lookAhead(); // after an RCURLY
2507:                            nextToken();
2508:                            Expression select;
2509:                            try {
2510:                                select = stringify(value, true);
2511:                            } catch (XPathException e) {
2512:                                throw StaticError.makeStaticError(e);
2513:                            }
2514:                            ValueOf vof = new ValueOf(select, false, true);
2515:                            setLocation(vof, offset);
2516:                            return makeTracer(offset, vof,
2517:                                    StandardNames.XSL_TEXT, -1);
2518:                        }
2519:                    } else if ("comment".equals(nodeKind)) {
2520:                        nextToken();
2521:                        if (t.currentToken == Token.RCURLY) {
2522:                            lookAhead(); // after an RCURLY
2523:                            nextToken();
2524:                            return EmptySequence.getInstance();
2525:                        } else {
2526:                            Expression value = parseExpression();
2527:                            expect(Token.RCURLY);
2528:                            lookAhead(); // after an RCURLY
2529:                            nextToken();
2530:                            Comment com = new Comment();
2531:                            makeSimpleContent(value, com, offset);
2532:                            return makeTracer(offset, com,
2533:                                    StandardNames.XSL_COMMENT, -1);
2534:                        }
2535:                    } else if ("processing-instruction".equals(nodeKind)) {
2536:                        nextToken();
2537:                        Expression name = parseExpression();
2538:                        expect(Token.RCURLY);
2539:                        lookAhead(); // must be done manually after an RCURLY
2540:                        nextToken();
2541:                        expect(Token.LCURLY);
2542:                        t.setState(Tokenizer.DEFAULT_STATE);
2543:                        nextToken();
2544:                        Expression content = null;
2545:                        if (t.currentToken != Token.RCURLY) {
2546:                            content = parseExpression();
2547:                            expect(Token.RCURLY);
2548:                        }
2549:                        lookAhead(); // after an RCURLY
2550:                        nextToken();
2551:                        ProcessingInstruction pi = new ProcessingInstruction(
2552:                                name);
2553:                        makeSimpleContent(content, pi, offset);
2554:                        return makeTracer(offset, pi,
2555:                                StandardNames.XSL_PROCESSING_INSTRUCTION, -1);
2556:
2557:                    } else {
2558:                        grumble("Unrecognized node constructor "
2559:                                + t.currentTokenValue + "{}");
2560:
2561:                    }
2562:                case Token.ELEMENT_QNAME:
2563:                    int nameCode = makeNameCode(t.currentTokenValue, true);
2564:                    Expression content = null;
2565:                    nextToken();
2566:                    if (t.currentToken != Token.RCURLY) {
2567:                        content = parseExpression();
2568:                        expect(Token.RCURLY);
2569:                    }
2570:                    lookAhead(); // after an RCURLY
2571:                    nextToken();
2572:                    FixedElement el2 = new FixedElement(nameCode,
2573:                            ((StaticQueryContext) env)
2574:                                    .getActiveNamespaceCodes(),
2575:                            ((StaticQueryContext) env).isInheritNamespaces(),
2576:                            null, ((StaticQueryContext) env)
2577:                                    .getConstructionMode());
2578:                    setLocation(el2, offset);
2579:                    if (content == null) {
2580:                        content = EmptySequence.getInstance();
2581:                    }
2582:                    el2.setContentExpression(content);
2583:                    //makeContentConstructor(content, el2, offset);
2584:                    return makeTracer(offset, el2,
2585:                            Location.LITERAL_RESULT_ELEMENT, nameCode);
2586:                case Token.ATTRIBUTE_QNAME:
2587:                    if (t.currentTokenValue.equals("xmlns")
2588:                            || t.currentTokenValue.startsWith("xmlns:")) {
2589:                        grumble(
2590:                                "Cannot create a namespace using an attribute constructor",
2591:                                "XQDY0044");
2592:                    }
2593:                    int attNameCode = makeNameCode(t.currentTokenValue, false);
2594:                    Expression attContent = null;
2595:                    nextToken();
2596:                    if (t.currentToken != Token.RCURLY) {
2597:                        attContent = parseExpression();
2598:                        expect(Token.RCURLY);
2599:                    }
2600:                    lookAhead(); // after an RCURLY
2601:                    nextToken();
2602:                    FixedAttribute att2 = new FixedAttribute(attNameCode,
2603:                            Validation.STRIP, null,
2604:                            StandardNames.XDT_UNTYPED_ATOMIC);
2605:                    att2.setRejectDuplicates();
2606:                    makeSimpleContent(attContent, att2, offset);
2607:                    return makeTracer(offset, att2,
2608:                            Location.LITERAL_RESULT_ATTRIBUTE, attNameCode);
2609:                case Token.PI_QNAME:
2610:                    Expression piName = new StringValue(t.currentTokenValue);
2611:                    Expression piContent = null;
2612:                    nextToken();
2613:                    if (t.currentToken != Token.RCURLY) {
2614:                        piContent = parseExpression();
2615:                        expect(Token.RCURLY);
2616:                    }
2617:                    lookAhead(); // after an RCURLY
2618:                    nextToken();
2619:                    ProcessingInstruction pi2 = new ProcessingInstruction(
2620:                            piName);
2621:                    makeSimpleContent(piContent, pi2, offset);
2622:                    return makeTracer(offset, pi2,
2623:                            StandardNames.XSL_PROCESSING_INSTRUCTION, -1);
2624:                }
2625:                return null;
2626:            }
2627:
2628:            /**
2629:             * Make the instructions for the children of a node with simple content (attribute, text, PI, etc)
2630:             *
2631:             * @param content
2632:             * @param inst
2633:             * @param offset
2634:             */
2635:
2636:            private void makeSimpleContent(Expression content,
2637:                    SimpleNodeConstructor inst, int offset) throws StaticError {
2638:                try {
2639:                    if (content == null) {
2640:                        inst.setSelect(StringValue.EMPTY_STRING);
2641:                    } else {
2642:                        inst.setSelect(stringify(content, false));
2643:                    }
2644:                    setLocation(inst, offset);
2645:                } catch (XPathException e) {
2646:                    grumble(e.getMessage());
2647:                }
2648:            }
2649:
2650:            /**
2651:             * Make a sequence of instructions as the children of an element-construction instruction.
2652:             * The idea here is to convert an XPath expression that "pulls" the content into a sequence
2653:             * of XSLT-style instructions that push nodes directly onto the subtree, thus reducing the
2654:             * need for copying of intermediate nodes.
2655:             * @param content The content of the element as an expression
2656:             * @param inst The element-construction instruction (Element or FixedElement)
2657:             * @param offset the character position in the query
2658:             */
2659:            //    private void makeContentConstructor(Expression content, InstructionWithChildren inst, int offset) {
2660:            //        if (content == null) {
2661:            //            inst.setChildren(null);
2662:            //        } else if (content instanceof AppendExpression) {
2663:            //            List instructions = new ArrayList(10);
2664:            //            convertAppendExpression((AppendExpression) content, instructions);
2665:            //            inst.setChildren((Expression[]) instructions.toArray(new Expression[instructions.size()]));
2666:            //        } else {
2667:            //            Expression children[] = {content};
2668:            //            inst.setChildren(children);
2669:            //        }
2670:            //        setLocation(inst, offset);
2671:            //    }
2672:            /**
2673:             * Parse pseudo-XML syntax in direct element constructors, comments, CDATA, etc.
2674:             * This is handled by reading single characters from the Tokenizer until the
2675:             * end of the tag (or an enclosed expression) is enountered.
2676:             * This method is also used to read an end tag. Because an end tag is not an
2677:             * expression, the method in this case returns a StringValue containing the
2678:             * contents of the end tag.
2679:             *
2680:             * @param allowEndTag true if the context allows an End Tag to appear here
2681:             * @return an Expression representing the result of parsing the constructor.
2682:             *         If an end tag was read, its contents will be returned as a StringValue.
2683:             */
2684:
2685:            private Expression parsePseudoXML(boolean allowEndTag)
2686:                    throws StaticError {
2687:                Expression exp = null;
2688:                int offset = t.inputOffset;
2689:                // we're reading raw characters, so we don't want the currentTokenStartOffset
2690:                char c = t.nextChar();
2691:                switch (c) {
2692:                case '!':
2693:                    c = t.nextChar();
2694:                    if (c == '-') {
2695:                        exp = parseCommentConstructor();
2696:                    } else if (c == '[') {
2697:                        grumble("A CDATA section is allowed only in element content");
2698:                        // if CDATA were allowed here, we would have already read it
2699:                    } else {
2700:                        grumble("Expected '--' or '[CDATA[' after '<!'");
2701:                    }
2702:                    break;
2703:                case '?':
2704:                    exp = parsePIConstructor();
2705:                    break;
2706:                case '/':
2707:                    if (allowEndTag) {
2708:                        FastStringBuffer sb = new FastStringBuffer(40);
2709:                        while (true) {
2710:                            c = t.nextChar();
2711:                            if (c == '>') {
2712:                                break;
2713:                            }
2714:                            sb.append(c);
2715:                        }
2716:                        return new StringValue(sb);
2717:                    }
2718:                    grumble("Unmatched XML end tag");
2719:                    break;
2720:                default:
2721:                    t.unreadChar();
2722:                    exp = parseDirectElementConstructor();
2723:                }
2724:                setLocation(exp, offset);
2725:                return exp;
2726:            }
2727:
2728:            /**
2729:             * Parse a direct element constructor
2730:             *
2731:             * @return the expression representing the constructor
2732:             * @throws StaticError
2733:             */
2734:
2735:            private Expression parseDirectElementConstructor()
2736:                    throws StaticError {
2737:                int offset = t.inputOffset - 1;
2738:                // we're reading raw characters, so we don't want the currentTokenStartOffset
2739:                char c;
2740:                FastStringBuffer buff = new FastStringBuffer(40);
2741:                int namespaceCount = 0;
2742:                while (true) {
2743:                    c = t.nextChar();
2744:                    if (c == ' ' || c == '\n' || c == '\r' || c == '\t'
2745:                            || c == '/' || c == '>') {
2746:                        break;
2747:                    }
2748:                    buff.append(c);
2749:                }
2750:                String elname = buff.toString();
2751:                HashMap attributes = new HashMap(10);
2752:                while (true) {
2753:                    // loop through the attributes
2754:                    // We must process namespace declaration attributes first;
2755:                    // their scope applies to all preceding attribute names and values.
2756:                    // But finding the delimiting quote of an attribute value requires the
2757:                    // XPath expressions to be parsed, because they may contain nested quotes.
2758:                    // So we parse in "scanOnly" mode, which ignores any undeclared namespace
2759:                    // prefixes, use the result of this parse to determine the length of the
2760:                    // attribute value, save the value, and reparse it when all the namespace
2761:                    // declarations have been dealt with.
2762:                    c = skipSpaces(c);
2763:                    if (c == '/' || c == '>') {
2764:                        break;
2765:                    }
2766:                    int attOffset = t.inputOffset - 1;
2767:                    buff.setLength(0);
2768:                    // read the attribute name
2769:                    while (true) {
2770:                        buff.append(c);
2771:                        c = t.nextChar();
2772:                        if (c == ' ' || c == '\n' || c == '\r' || c == '\t'
2773:                                || c == '=') {
2774:                            break;
2775:                        }
2776:                    }
2777:                    String attName = buff.toString();
2778:                    if (!nameChecker.isQName(attName)) {
2779:                        grumble("Invalid attribute name "
2780:                                + Err.wrap(attName, Err.ATTRIBUTE));
2781:                    }
2782:                    c = skipSpaces(c);
2783:                    expectChar(c, '=');
2784:                    c = t.nextChar();
2785:                    c = skipSpaces(c);
2786:
2787:                    Expression avt;
2788:                    try {
2789:                        avt = makeAttributeContent(t.input, t.inputOffset, c,
2790:                                true);
2791:                    } catch (StaticError err) {
2792:                        grumble(err.getMessage());
2793:                        return null;
2794:                    } catch (XPathException err) {
2795:                        throw err.makeStatic();
2796:                    }
2797:                    // by convention, this returns the end position when called with scanOnly set
2798:                    int end = (int) ((IntegerValue) avt).longValue();
2799:                    // save the value with its surrounding quotes
2800:                    String val = t.input.substring(t.inputOffset - 1, end + 1);
2801:                    // and without
2802:                    String rval = t.input.substring(t.inputOffset, end);
2803:                    t.inputOffset = end + 1;
2804:                    // on return, the current character is the closing quote
2805:                    c = t.nextChar();
2806:                    if (!(c == ' ' || c == '\n' || c == '\r' || c == '\t'
2807:                            || c == '/' || c == '>')) {
2808:                        grumble("There must be whitespace after every attribute except the last");
2809:                    }
2810:                    if ("xmlns".equals(attName) || attName.startsWith("xmlns:")) {
2811:                        if (rval.indexOf('{') >= 0) {
2812:                            grumble("Namespace URI must be a constant value",
2813:                                    "XQST0022");
2814:                        }
2815:                        String prefix, uri;
2816:                        if ("xmlns".equals(attName)) {
2817:                            prefix = "";
2818:                            uri = rval;
2819:                        } else {
2820:                            prefix = attName.substring(6);
2821:                            if (prefix.equals("xml")) {
2822:                                grumble("Cannot redeclare the XML namespace",
2823:                                        "XQST0070");
2824:                            } else if (prefix.equals("xmlns")) {
2825:                                grumble(
2826:                                        "Cannot use xmlns as a namespace prefix",
2827:                                        "XQST0070");
2828:                            }
2829:                            uri = rval;
2830:                            if ("".equals(uri)) {
2831:                                grumble("Namespace URI must not be empty",
2832:                                        "XQST0085");
2833:                            }
2834:                        }
2835:                        namespaceCount++;
2836:                        ((StaticQueryContext) env).declareActiveNamespace(
2837:                                prefix, uri);
2838:                    }
2839:                    if (attributes.get(attName) != null) {
2840:                        if ("xmlns".equals(attName)
2841:                                || attName.startsWith("xmlns:")) {
2842:                            grumble("Duplicate namespace declaration "
2843:                                    + attName, "XQST0071");
2844:                        } else {
2845:                            grumble("Duplicate attribute name " + attName,
2846:                                    "XQST0040");
2847:                        }
2848:                    }
2849:                    if (attName.equals("xml:id")
2850:                            && !nameChecker.isValidNCName(rval)) {
2851:                        grumble("Value of xml:id must be a valid NCName",
2852:                                "XQST0082");
2853:                    }
2854:                    AttributeDetails a = new AttributeDetails();
2855:                    a.value = val;
2856:                    a.startOffset = attOffset;
2857:                    attributes.put(attName, a);
2858:                }
2859:                String namespace;
2860:                int elNameCode = 0;
2861:                try {
2862:                    String[] parts = nameChecker.getQNameParts(elname);
2863:                    namespace = ((StaticQueryContext) env)
2864:                            .checkURIForPrefix(parts[0]);
2865:                    if (namespace == null) {
2866:                        grumble("Undeclared prefix in element name "
2867:                                + Err.wrap(elname, Err.ELEMENT), "XPST0008");
2868:                    }
2869:                    elNameCode = env.getNamePool().allocate(parts[0],
2870:                            namespace, parts[1]);
2871:                } catch (QNameException e) {
2872:                    grumble("Invalid element name "
2873:                            + Err.wrap(elname, Err.ELEMENT));
2874:                }
2875:                int validationMode = ((StaticQueryContext) env)
2876:                        .getConstructionMode();
2877:                FixedElement elInst = new FixedElement(elNameCode,
2878:                        ((StaticQueryContext) env).getActiveNamespaceCodes(),
2879:                        ((StaticQueryContext) env).isInheritNamespaces(), null,
2880:                        validationMode);
2881:
2882:                setLocation(elInst, offset);
2883:
2884:                List contents = new ArrayList(10);
2885:
2886:                IntHashSet attFingerprints = new IntHashSet(attributes.size());
2887:                // we've checked for duplicate lexical QNames, but not for duplicate expanded-QNames
2888:                for (Iterator iter = attributes.keySet().iterator(); iter
2889:                        .hasNext();) {
2890:                    String attName = (String) iter.next();
2891:                    AttributeDetails a = (AttributeDetails) attributes
2892:                            .get(attName);
2893:                    String attValue = a.value;
2894:                    int attOffset = a.startOffset;
2895:
2896:                    if ("xmlns".equals(attName) || attName.startsWith("xmlns:")) {
2897:                        // do nothing
2898:                    } else if (scanOnly) {
2899:                        // This means we are prescanning an attribute constructor, and we found a nested attribute
2900:                        // constructor, which we have prescanned; we now don't want to re-process the nested attribute
2901:                        // constructor because it might depend on things like variables declared in the containing
2902:                        // attribute constructor, and in any case we're going to come back to it again later.
2903:                        // See test qxmp180
2904:                    } else {
2905:                        int attNameCode = 0;
2906:                        String attNamespace;
2907:                        try {
2908:                            String[] parts = nameChecker.getQNameParts(attName);
2909:                            if ("".equals(parts[0])) {
2910:                                // attributes don't use the default namespace
2911:                                attNamespace = "";
2912:                            } else {
2913:                                attNamespace = ((StaticQueryContext) env)
2914:                                        .checkURIForPrefix(parts[0]);
2915:                            }
2916:                            if (attNamespace == null) {
2917:                                grumble("Undeclared prefix in attribute name "
2918:                                        + Err.wrap(attName, Err.ATTRIBUTE),
2919:                                        "XPST0008");
2920:                            }
2921:                            attNameCode = env.getNamePool().allocate(parts[0],
2922:                                    attNamespace, parts[1]);
2923:                            int key = (attNameCode & NamePool.FP_MASK);
2924:                            if (attFingerprints.contains(key)) {
2925:                                grumble("Duplicate expanded attribute name "
2926:                                        + attName, "XQST0040");
2927:                            }
2928:                            attFingerprints.add(key);
2929:                        } catch (QNameException e) {
2930:                            grumble("Invalid attribute name "
2931:                                    + Err.wrap(attName, Err.ATTRIBUTE));
2932:                        }
2933:
2934:                        FixedAttribute attInst = new FixedAttribute(
2935:                                attNameCode, Validation.STRIP, null,
2936:                                StandardNames.XDT_UNTYPED_ATOMIC);
2937:
2938:                        setLocation(attInst);
2939:                        Expression select;
2940:                        try {
2941:                            select = makeAttributeContent(attValue, 1, attValue
2942:                                    .charAt(0), false);
2943:                        } catch (XPathException err) {
2944:                            throw err.makeStatic();
2945:                        }
2946:                        attInst.setSelect(select);
2947:                        attInst.setRejectDuplicates();
2948:                        setLocation(attInst);
2949:                        contents
2950:                                .add(makeTracer(attOffset, attInst,
2951:                                        Location.LITERAL_RESULT_ATTRIBUTE,
2952:                                        attNameCode));
2953:                    }
2954:                }
2955:                if (c == '/') {
2956:                    // empty element tag
2957:                    expectChar(t.nextChar(), '>');
2958:                } else {
2959:                    readElementContent(elname, contents);
2960:                }
2961:
2962:                Expression[] elk = new Expression[contents.size()];
2963:                for (int i = 0; i < contents.size(); i++) {
2964:                    // if the child expression creates another element,
2965:                    // suppress validation, as the parent already takes care of it
2966:                    if (validationMode != Validation.STRIP
2967:                            && contents.get(i) instanceof  ComputedExpression) {
2968:                        ((ComputedExpression) contents.get(i))
2969:                                .suppressValidation(validationMode);
2970:                    }
2971:                    elk[i] = (Expression) contents.get(i);
2972:                }
2973:                Block block = new Block();
2974:                block.setChildren(elk);
2975:                elInst.setContentExpression(block);
2976:
2977:                // reset the in-scope namespaces to what they were before
2978:
2979:                for (int n = 0; n < namespaceCount; n++) {
2980:                    ((StaticQueryContext) env).undeclareNamespace();
2981:                }
2982:
2983:                return makeTracer(offset, elInst,
2984:                        Location.LITERAL_RESULT_ELEMENT, elNameCode);
2985:            }
2986:
2987:            /**
2988:             * Parse the content of an attribute in a direct element constructor. This may contain nested expressions
2989:             * within curly braces. A particular problem is that the namespaces used in the expression may not yet be
2990:             * known. This means we need the ability to parse in "scanOnly" mode, where undeclared namespace prefixes
2991:             * are ignored.
2992:             * <p/>
2993:             * The code is based on the XSLT code in {@link AttributeValueTemplate#make}: the main difference is that
2994:             * character entities and built-in entity references need to be recognized and expanded. Also, whitespace
2995:             * needs to be normalized, mimicking the action of an XML parser
2996:             */
2997:
2998:            private Expression makeAttributeContent(String avt, int start,
2999:                    char terminator, boolean scanOnly) throws XPathException {
3000:
3001:                int lineNumber = t.getLineNumber();
3002:                List components = new ArrayList(10);
3003:
3004:                int i0, i1, i2, i8, i9, len, last;
3005:                last = start;
3006:                len = avt.length();
3007:                while (last < len) {
3008:                    i2 = avt.indexOf(terminator, last);
3009:                    if (i2 < 0) {
3010:                        throw new StaticError(
3011:                                "Attribute constructor is not properly terminated");
3012:                    }
3013:
3014:                    i0 = avt.indexOf("{", last);
3015:                    i1 = avt.indexOf("{{", last);
3016:                    i8 = avt.indexOf("}", last);
3017:                    i9 = avt.indexOf("}}", last);
3018:
3019:                    if ((i0 < 0 || i2 < i0) && (i8 < 0 || i2 < i8)) { // found end of string
3020:                        addStringComponent(components, avt, last, i2);
3021:
3022:                        // look for doubled quotes, and skip them (for now)
3023:                        if (i2 + 1 < avt.length()
3024:                                && avt.charAt(i2 + 1) == terminator) {
3025:                            components.add(new StringValue(terminator + ""));
3026:                            last = i2 + 2;
3027:                            continue;
3028:                        } else {
3029:                            last = i2;
3030:                            break;
3031:                        }
3032:                    } else if (i8 >= 0 && (i0 < 0 || i8 < i0)) { // found a "}"
3033:                        if (i8 != i9) { // a "}" that isn't a "}}"
3034:                            throw new StaticError(
3035:                                    "Closing curly brace in attribute value template \""
3036:                                            + avt + "\" must be doubled");
3037:                        }
3038:                        addStringComponent(components, avt, last, i8 + 1);
3039:                        last = i8 + 2;
3040:                    } else if (i1 >= 0 && i1 == i0) { // found a doubled "{{"
3041:                        addStringComponent(components, avt, last, i1 + 1);
3042:                        last = i1 + 2;
3043:                    } else if (i0 >= 0) { // found a single "{"
3044:                        if (i0 > last) {
3045:                            addStringComponent(components, avt, last, i0);
3046:                        }
3047:                        Expression exp;
3048:                        ExpressionParser parser;
3049:                        parser = new QueryParser();
3050:                        parser.setScanOnly(scanOnly);
3051:                        if (rangeVariables != null) {
3052:                            parser.setRangeVariableStack(rangeVariables);
3053:                        }
3054:                        exp = parser.parse(avt, i0 + 1, Token.RCURLY,
3055:                                lineNumber, env);
3056:                        if (!scanOnly) {
3057:                            exp = exp.simplify(env);
3058:                        }
3059:                        last = parser.getTokenizer().currentTokenStartOffset + 1;
3060:                        components.add(makeStringJoin(exp, env));
3061:
3062:                    } else {
3063:                        throw new IllegalStateException(
3064:                                "Internal error parsing direct attribute constructor");
3065:                    }
3066:                }
3067:
3068:                // if this is simply a prescan, return the position of the end of the
3069:                // AVT, so we can parse it properly later
3070:
3071:                if (scanOnly) {
3072:                    return new IntegerValue(last);
3073:                }
3074:
3075:                // is it empty?
3076:
3077:                if (components.size() == 0) {
3078:                    return StringValue.EMPTY_STRING;
3079:                }
3080:
3081:                // is it a single component?
3082:
3083:                if (components.size() == 1) {
3084:                    return ((Expression) components.get(0)).simplify(env);
3085:                }
3086:
3087:                // otherwise, return an expression that concatenates the components
3088:
3089:                Concat fn = (Concat) SystemFunction.makeSystemFunction(
3090:                        "concat", components.size(), env.getNamePool());
3091:                Expression[] args = new Expression[components.size()];
3092:                components.toArray(args);
3093:                fn.setArguments(args);
3094:                fn.setLocationId(env.getLocationMap().allocateLocationId(
3095:                        env.getSystemId(), lineNumber));
3096:                return fn.simplify(env);
3097:
3098:            }
3099:
3100:            private void addStringComponent(List components, String avt,
3101:                    int start, int end) throws XPathException {
3102:                // analyze fixed text within the value of a direct attribute constructor.
3103:                if (start < end) {
3104:                    FastStringBuffer sb = new FastStringBuffer(end - start);
3105:                    for (int i = start; i < end; i++) {
3106:                        char c = avt.charAt(i);
3107:                        switch (c) {
3108:                        case '&': {
3109:                            int semic = avt.indexOf(';', i);
3110:                            if (semic < 0) {
3111:                                grumble("No closing ';' found for entity or character reference");
3112:                            } else {
3113:                                String entity = avt.substring(i + 1, semic);
3114:                                sb.append(analyzeEntityReference(entity));
3115:                                i = semic;
3116:                            }
3117:                            break;
3118:                        }
3119:                        case '<':
3120:                            grumble("The < character must not appear in attribute content");
3121:                            break;
3122:                        case '\n':
3123:                        case '\t':
3124:                            sb.append(' ');
3125:                            break;
3126:                        case '\r':
3127:                            sb.append(' ');
3128:                            if (i + 1 < end && avt.charAt(i + 1) == '\n') {
3129:                                i++;
3130:                            }
3131:                            break;
3132:                        default:
3133:                            sb.append(c);
3134:
3135:                        }
3136:                    }
3137:                    components.add(StringValue.makeStringValue(sb));
3138:                }
3139:            }
3140:
3141:            /**
3142:             * Read the content of a direct element constructor
3143:             *
3144:             * @param startTag   the element start tag
3145:             * @param components an empty list, to which the expressions comprising the element contents are added
3146:             * @throws StaticError if any static errors are detected
3147:             */
3148:            private void readElementContent(String startTag, List components)
3149:                    throws StaticError {
3150:                final TypeHierarchy th = env.getNamePool().getTypeHierarchy();
3151:                try {
3152:                    boolean afterEnclosedExpr = false;
3153:                    while (true) {
3154:                        // read all the components of the element value
3155:                        FastStringBuffer text = new FastStringBuffer(256);
3156:                        char c;
3157:                        boolean containsEntities = false;
3158:                        while (true) {
3159:                            c = t.nextChar();
3160:                            if (c == '<') {
3161:                                // See if we've got a CDATA section
3162:                                if (t.nextChar() == '!') {
3163:                                    if (t.nextChar() == '[') {
3164:                                        readCDATASection(text);
3165:                                        containsEntities = true;
3166:                                        continue;
3167:                                    } else {
3168:                                        t.unreadChar();
3169:                                        t.unreadChar();
3170:                                    }
3171:                                } else {
3172:                                    t.unreadChar();
3173:                                }
3174:                                break;
3175:                            } else if (c == '&') {
3176:                                text.append(readEntityReference());
3177:                                containsEntities = true;
3178:                            } else if (c == '}') {
3179:                                c = t.nextChar();
3180:                                if (c != '}') {
3181:                                    grumble("'}' must be written as '}}' within element content");
3182:                                }
3183:                                text.append(c);
3184:                            } else if (c == '{') {
3185:                                c = t.nextChar();
3186:                                if (c != '{') {
3187:                                    c = '{';
3188:                                    break;
3189:                                }
3190:                                text.append(c);
3191:                            } else {
3192:                                text.append(c);
3193:                            }
3194:                        }
3195:                        if (text.length() > 0
3196:                                && (containsEntities | preserveSpace | !Whitespace
3197:                                        .isWhite(text))) {
3198:                            ValueOf inst = new ValueOf(new StringValue(text
3199:                                    .condense()), false, false);
3200:                            setLocation(inst);
3201:                            components.add(inst);
3202:                            afterEnclosedExpr = false;
3203:                        }
3204:                        if (c == '<') {
3205:                            Expression exp = parsePseudoXML(true);
3206:                            // An end tag can appear here, and is returned as a string value
3207:                            if (exp instanceof  StringValue) {
3208:                                String endTag = ((StringValue) exp)
3209:                                        .getStringValue().trim();
3210:                                if (endTag.equals(startTag)) {
3211:                                    return;
3212:                                } else {
3213:                                    grumble("end tag </" + endTag
3214:                                            + "> does not match start tag <"
3215:                                            + startTag + '>');
3216:                                }
3217:                            } else {
3218:                                components.add(exp);
3219:                            }
3220:                        } else {
3221:                            // we read an '{' indicating an enclosed expression
3222:                            if (afterEnclosedExpr) {
3223:                                Expression previousComponent = (Expression) components
3224:                                        .get(components.size() - 1);
3225:                                ItemType previousItemType = previousComponent
3226:                                        .getItemType(th);
3227:                                if (!(previousItemType instanceof  NodeTest)) {
3228:                                    // Add a zero-length text node, to prevent {"a"}{"b"} generating an intervening space
3229:                                    // See tests (qxmp132, qxmp261)
3230:                                    ValueOf inst = new ValueOf(
3231:                                            StringValue.EMPTY_STRING, false,
3232:                                            false);
3233:                                    setLocation(inst);
3234:                                    components.add(inst);
3235:                                }
3236:                            }
3237:                            t.unreadChar();
3238:                            t.setState(Tokenizer.DEFAULT_STATE);
3239:                            lookAhead();
3240:                            nextToken();
3241:                            Expression exp = parseExpression();
3242:                            if (!((StaticQueryContext) env)
3243:                                    .isPreserveNamespaces()) {
3244:                                exp = new CopyOf(exp, false,
3245:                                        Validation.PRESERVE, null, true);
3246:                            }
3247:                            components.add(exp);
3248:                            expect(Token.RCURLY);
3249:                            afterEnclosedExpr = true;
3250:                        }
3251:                    }
3252:                } catch (StringIndexOutOfBoundsException err) {
3253:                    grumble("No closing end tag found for direct element constructor");
3254:                }
3255:            }
3256:
3257:            private Expression parsePIConstructor() throws StaticError {
3258:                try {
3259:                    FastStringBuffer pi = new FastStringBuffer(120);
3260:                    int firstSpace = -1;
3261:                    while (!pi.toString().endsWith("?>")) {
3262:                        char c = t.nextChar();
3263:                        if (firstSpace < 0 && " \t\r\n".indexOf(c) >= 0) {
3264:                            firstSpace = pi.length();
3265:                        }
3266:                        pi.append(c);
3267:                    }
3268:                    pi.setLength(pi.length() - 2);
3269:
3270:                    String target;
3271:                    String data = "";
3272:                    if (firstSpace < 0) {
3273:                        // there is no data part
3274:                        target = pi.toString();
3275:                    } else {
3276:                        // trim leading space from the data part, but not trailing space
3277:                        target = pi.toString().substring(0, firstSpace);
3278:                        firstSpace++;
3279:                        while (firstSpace < pi.length()
3280:                                && " \t\r\n".indexOf(pi.charAt(firstSpace)) >= 0) {
3281:                            firstSpace++;
3282:                        }
3283:                        data = pi.toString().substring(firstSpace);
3284:                    }
3285:
3286:                    if (!nameChecker.isValidNCName(target)) {
3287:                        grumble("Invalid processing instruction name "
3288:                                + Err.wrap(target));
3289:                    }
3290:
3291:                    ProcessingInstruction instruction = new ProcessingInstruction(
3292:                            new StringValue(target));
3293:                    instruction.setSelect(StringValue.makeStringValue(data));
3294:                    setLocation(instruction);
3295:                    return instruction;
3296:                } catch (StringIndexOutOfBoundsException err) {
3297:                    grumble("No closing '?>' found for processing instruction");
3298:                    return null;
3299:                }
3300:            }
3301:
3302:            private void readCDATASection(FastStringBuffer cdata)
3303:                    throws StaticError {
3304:                try {
3305:                    char c;
3306:                    // CDATA section
3307:                    c = t.nextChar();
3308:                    expectChar(c, 'C');
3309:                    c = t.nextChar();
3310:                    expectChar(c, 'D');
3311:                    c = t.nextChar();
3312:                    expectChar(c, 'A');
3313:                    c = t.nextChar();
3314:                    expectChar(c, 'T');
3315:                    c = t.nextChar();
3316:                    expectChar(c, 'A');
3317:                    c = t.nextChar();
3318:                    expectChar(c, '[');
3319:                    while (!cdata.toString().endsWith("]]>")) {
3320:                        cdata.append(t.nextChar());
3321:                    }
3322:                    cdata.setLength(cdata.length() - 3);
3323:                } catch (StringIndexOutOfBoundsException err) {
3324:                    grumble("No closing ']]>' found for CDATA section");
3325:                }
3326:            }
3327:
3328:            private Expression parseCommentConstructor() throws StaticError {
3329:                try {
3330:                    char c = t.nextChar();
3331:                    ;
3332:                    // XML-like comment
3333:                    expectChar(c, '-');
3334:                    FastStringBuffer comment = new FastStringBuffer(240);
3335:                    while (!comment.toString().endsWith("--")) {
3336:                        comment.append(t.nextChar());
3337:                    }
3338:                    if (t.nextChar() != '>') {
3339:                        grumble("'--' is not permitted in an XML comment");
3340:                    }
3341:                    CharSequence commentText = comment.subSequence(0, comment
3342:                            .length() - 2);
3343:                    Comment instruction = new Comment();
3344:                    instruction.setSelect(new StringValue(commentText));
3345:                    setLocation(instruction);
3346:                    return instruction;
3347:                } catch (StringIndexOutOfBoundsException err) {
3348:                    grumble("No closing '-->' found for comment constructor");
3349:                    return null;
3350:                }
3351:            }
3352:
3353:            /**
3354:             * Convert an expression so it generates a space-separated sequence of strings
3355:             *
3356:             * @param exp           the expression that calculates the content
3357:             * @param noNodeIfEmpty if true, no node is produced when the value of the content
3358:             *                      expression is an empty sequence. If false, the effect of supplying an empty sequence
3359:             *                      is that a node is created whose string-value is a zero-length string. Set to true for
3360:             *                      text node constructors, false for other kinds of node.
3361:             */
3362:
3363:            private Expression stringify(Expression exp, boolean noNodeIfEmpty)
3364:                    throws XPathException {
3365:                return new QuerySimpleContentConstructor(exp,
3366:                        StringValue.SINGLE_SPACE, noNodeIfEmpty).simplify(env);
3367:            }
3368:
3369:            /**
3370:             * Method to make a string literal from a token identified as a string
3371:             * literal. This is trivial in XPath, but in XQuery the method is overridden
3372:             * to identify pseudo-XML character and entity references
3373:             *
3374:             * @param token
3375:             * @return The string value of the string literal, after dereferencing entity and
3376:             *         character references
3377:             */
3378:
3379:            protected StringValue makeStringLiteral(String token)
3380:                    throws StaticError {
3381:                if (token.indexOf('&') == -1) {
3382:                    return StringValue.makeStringValue(token);
3383:                } else {
3384:                    FastStringBuffer sb = unescape(token);
3385:                    return StringValue.makeStringValue(sb);
3386:                }
3387:            }
3388:
3389:            /**
3390:             * Unescape character references and built-in entity references in a string
3391:             *
3392:             * @param token
3393:             * @return
3394:             * @throws StaticError
3395:             */
3396:
3397:            private FastStringBuffer unescape(String token) throws StaticError {
3398:                FastStringBuffer sb = new FastStringBuffer(80);
3399:                for (int i = 0; i < token.length(); i++) {
3400:                    char c = token.charAt(i);
3401:                    if (c == '&') {
3402:                        int semic = token.indexOf(';', i);
3403:                        if (semic < 0) {
3404:                            grumble("No closing ';' found for entity or character reference");
3405:                        } else {
3406:                            String entity = token.substring(i + 1, semic);
3407:                            sb.append(analyzeEntityReference(entity));
3408:                            i = semic;
3409:                        }
3410:                    } else {
3411:                        sb.append(c);
3412:                    }
3413:                }
3414:                return sb;
3415:            }
3416:
3417:            /**
3418:             * Read a pseudo-XML character reference or entity reference.
3419:             *
3420:             * @return The character represented by the character or entity reference. Note
3421:             *         that this is a string rather than a char because a char only accommodates characters
3422:             *         up to 65535.
3423:             * @throws net.sf.saxon.trans.StaticError if the character or entity reference is not well-formed
3424:             */
3425:
3426:            private String readEntityReference() throws StaticError {
3427:                try {
3428:                    FastStringBuffer sb = new FastStringBuffer(40);
3429:                    while (true) {
3430:                        char c = t.nextChar();
3431:                        if (c == ';') {
3432:                            break;
3433:                        }
3434:                        sb.append(c);
3435:                    }
3436:                    String entity = sb.toString();
3437:                    return analyzeEntityReference(entity);
3438:                } catch (StringIndexOutOfBoundsException err) {
3439:                    grumble("No closing ';' found for entity or character reference");
3440:                }
3441:                return null; // to keep the Java compiler happy
3442:            }
3443:
3444:            private String analyzeEntityReference(String entity)
3445:                    throws StaticError {
3446:                if ("lt".equals(entity)) {
3447:                    return "<";
3448:                } else if ("gt".equals(entity)) {
3449:                    return ">";
3450:                } else if ("amp".equals(entity)) {
3451:                    return "&";
3452:                } else if ("quot".equals(entity)) {
3453:                    return "\"";
3454:                } else if ("apos".equals(entity)) {
3455:                    return "'";
3456:                } else if (entity.length() < 2 || entity.charAt(0) != '#') {
3457:                    grumble("invalid entity reference &" + entity + ';');
3458:                    return null;
3459:                } else {
3460:                    entity = entity.toLowerCase();
3461:                    return parseCharacterReference(entity);
3462:                }
3463:            }
3464:
3465:            private String parseCharacterReference(String entity)
3466:                    throws StaticError {
3467:                int value = 0;
3468:                if (entity.charAt(1) == 'x') {
3469:                    for (int i = 2; i < entity.length(); i++) {
3470:                        int digit = "0123456789abcdef"
3471:                                .indexOf(entity.charAt(i));
3472:                        if (digit < 0) {
3473:                            grumble("invalid character '" + entity.charAt(i)
3474:                                    + "' in hex character reference");
3475:                        }
3476:                        value = (value * 16) + digit;
3477:                    }
3478:                } else {
3479:                    for (int i = 1; i < entity.length(); i++) {
3480:                        int digit = "0123456789".indexOf(entity.charAt(i));
3481:                        if (digit < 0) {
3482:                            grumble("invalid character '" + entity.charAt(i)
3483:                                    + "' in decimal character reference");
3484:                        }
3485:                        value = (value * 10) + digit;
3486:                    }
3487:                }
3488:                // following code borrowed from AElfred
3489:                // check for character refs being legal XML
3490:                if ((value < 0x0020 && !(value == '\n' || value == '\t' || value == '\r'))
3491:                        || (value >= 0xD800 && value <= 0xDFFF)
3492:                        || value == 0xFFFE
3493:                        || value == 0xFFFF
3494:                        || value > 0x0010ffff) {
3495:                    grumble("Invalid XML character reference x"
3496:                            + Integer.toHexString(value));
3497:                }
3498:
3499:                // Check for surrogates: 00000000 0000xxxx yyyyyyyy zzzzzzzz
3500:                //  (1101|10xx|xxyy|yyyy + 1101|11yy|zzzz|zzzz:
3501:                if (value <= 0x0000ffff) {
3502:                    // no surrogates needed
3503:                    return "" + (char) value;
3504:                } else if (value <= 0x0010ffff) {
3505:                    value -= 0x10000;
3506:                    // > 16 bits, surrogate needed
3507:                    return "" + ((char) (0xd800 | (value >> 10)))
3508:                            + ((char) (0xdc00 | (value & 0x0003ff)));
3509:                } else {
3510:                    // too big for surrogate
3511:                    grumble("Character reference x"
3512:                            + Integer.toHexString(value) + " is too large");
3513:                }
3514:                return null;
3515:            }
3516:
3517:            /**
3518:             * Handle a URI literal. This is whitespace-normalized as well as being unescaped
3519:             */
3520:
3521:            private String URILiteral(String in) throws StaticError {
3522:                return Whitespace.applyWhitespaceNormalization(
3523:                        Whitespace.COLLAPSE, unescape(in)).toString();
3524:            }
3525:
3526:            /**
3527:             * Lookahead one token, catching any exception thrown by the tokenizer. This
3528:             * method is only called from the query parser when switching from character-at-a-time
3529:             * mode to tokenizing mode
3530:             */
3531:
3532:            private void lookAhead() throws StaticError {
3533:                try {
3534:                    t.lookAhead();
3535:                } catch (XPathException err) {
3536:                    grumble(err.getMessage());
3537:                }
3538:            }
3539:
3540:            /**
3541:             * Skip whitespace.
3542:             *
3543:             * @param c the current character
3544:             * @return the first character after any whitespace
3545:             */
3546:
3547:            private char skipSpaces(char c) {
3548:                while (c == ' ' || c == '\n' || c == '\r' || c == '\t') {
3549:                    c = t.nextChar();
3550:                }
3551:                return c;
3552:            }
3553:
3554:            /**
3555:             * Test whether the current character is the expected character.
3556:             *
3557:             * @param actual   The character that was read
3558:             * @param expected The character that was expected
3559:             * @throws net.sf.saxon.trans.StaticError if they are different
3560:             */
3561:
3562:            private void expectChar(char actual, char expected)
3563:                    throws StaticError {
3564:                if (actual != expected) {
3565:                    grumble("Expected '" + expected + "', found '" + actual
3566:                            + '\'');
3567:                }
3568:            }
3569:
3570:            /**
3571:             * Get the current language (XPath or XQuery)
3572:             */
3573:
3574:            protected String getLanguage() {
3575:                return "XQuery";
3576:            }
3577:
3578:            private static class AttributeDetails {
3579:                String value;
3580:                int startOffset;
3581:            }
3582:
3583:            private static class Import {
3584:                String namespaceURI;
3585:                List locationURIs;
3586:            }
3587:        }
3588:
3589:        //
3590:        // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
3591:        // you may not use this file except in compliance with the License. You may obtain a copy of the
3592:        // License at http://www.mozilla.org/MPL/
3593:        //
3594:        // Software distributed under the License is distributed on an "AS IS" basis,
3595:        // WITHOUT WARRANTY OF ANY KIND, either express or implied.
3596:        // See the License for the specific language governing rights and limitations under the License.
3597:        //
3598:        // The Original Code is: all this file.
3599:        //
3600:        // The Initial Developer of the Original Code is Michael H. Kay
3601:        //
3602:        // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
3603:        //
3604:        // Contributor(s): none.
3605:        //
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.