protected Expression parseExtensionExpression() throws XPathException {
        SchemaType requiredType = null;
        CharSequence trimmed = Whitespace.removeLeadingWhitespace(t.currentTokenValue);
        int c = 0;
        int len = trimmed.length();
        while (c < len && " \t\r\n".indexOf(trimmed.charAt(c)) < 0) {
            c++;
        }
        String qname = trimmed.subSequence(0, c).toString();
        String pragmaContents = "";
        while (c < len && " \t\r\n".indexOf(trimmed.charAt(c)) >= 0) {
            c++;
        }
        if (c < len) {
            pragmaContents = trimmed.subSequence(c, len).toString();
        }

        boolean validateType = false;
        boolean streaming = false;
        if (!nameChecker.isQName(qname)) {
            grumble("First token in pragma must be a valid QName, terminated by whitespace");
        } else {
            int nameCode = makeNameCode(qname, false);
            String uri = env.getNamePool().getURI(nameCode);
            if (uri.equals(NamespaceConstant.SAXON)) {
                String localName = env.getNamePool().getLocalName(nameCode);
                if (localName.equals("validate-type")) {
                    if (!env.getConfiguration().isLicensedFeature(Configuration.LicenseFeature.SCHEMA_AWARE_XQUERY)) {
                        grumble("To use saxon:validate-type, " +
                                "you need the Saxon-EE processor from http://www.saxonica.com/");
                    }
                    String typeName = Whitespace.trim(pragmaContents);
                    if (!nameChecker.isQName(typeName)) {
                        grumble("Schema type expected in saxon:validate-type pragma");
                    }
                    int typeCode = makeNameCode(typeName, true);
                    requiredType = env.getConfiguration().getSchemaType(typeCode & NamePool.FP_MASK);
                    if (requiredType == null) {
                        grumble("Unknown schema type " + typeName);
                    }
                    validateType = true;
                } else if (localName.equals("stream")) {
                    if (!env.getConfiguration().isLicensedFeature(Configuration.LicenseFeature.SCHEMA_AWARE_XQUERY)) {
                        grumble("To use saxon:stream, " +
                                "you need the Saxon-EE processor from http://www.saxonica.com/");
                    }
                    streaming = true;
                } else {
                    grumble("Unrecognized Saxon pragma " + qname);
                }
            } else if (uri.length() == 0) {
                grumble("The QName identifying an option declaration must be prefixed", "XPST0081");
            }
        }

        nextToken();
        Expression expr;
        if (t.currentToken == Token.PRAGMA) {
            expr = parseExtensionExpression();
        } else {
            expect(Token.LCURLY);
            nextToken();
            if (t.currentToken == Token.RCURLY) {
                t.lookAhead();      // always done manually after an RCURLY
                nextToken();
                grumble("Unrecognized pragma, with no fallback expression", "XQST0079");
            }
            expr = parseExpression();
            expect(Token.RCURLY);
            t.lookAhead();      // always done manually after an RCURLY
            nextToken();
        }
        if (validateType) {
            if (expr instanceof ElementCreator) {
                ((ElementCreator)expr).setSchemaType(requiredType);
                ((ElementCreator)expr).setValidationMode(Validation.BY_TYPE);
                return expr;
            } else if (expr instanceof DocumentInstr) {
                ((DocumentInstr)expr).setSchemaType(requiredType);
                ((DocumentInstr)expr).setValidationMode(Validation.BY_TYPE);
                return expr;
            } else if (expr instanceof AttributeCreator) {
                if (!(requiredType instanceof SimpleType)) {
                    grumble("The type used for validating an attribute must be a simple type");
                }
                ((AttributeCreator)expr).setSchemaType((SimpleType)requiredType);
                ((AttributeCreator)expr).setAnnotation(requiredType.getFingerprint());
                ((AttributeCreator)expr).setValidationAction(Validation.BY_TYPE);
                return expr;
            } else {
                CopyOf copy = new CopyOf(expr, true, Validation.BY_TYPE, requiredType, true);
                copy.setLocationId(env.getLocationMap().allocateLocationId(env.getSystemId(), t.getLineNumber()));
                return copy;
            }
        } else if (streaming) {
            CopyOf copy = new CopyOf(expr, true, Validation.PRESERVE, null, true);
            copy.setLocationId(env.getLocationMap().allocateLocationId(env.getSystemId(), t.getLineNumber()));
            copy.setReadOnce(true);
            return copy;
        } else {
            return expr;
        }
    }