package client.net.sf.saxon.ce.pattern; import client.net.sf.saxon.ce.expr.*; import client.net.sf.saxon.ce.functions.Id; import client.net.sf.saxon.ce.functions.KeyFn; import client.net.sf.saxon.ce.js.IXSLFunction; import client.net.sf.saxon.ce.trans.XPathException; /** * Parser for XSLT patterns. This is created by overriding selected parts of the standard ExpressionParser. */ public class PatternParser extends ExpressionParser { int inPredicate = 0; /** * Parse a string representing an XSLT pattern * @param pattern the pattern expressed as a String * @param env the static context for the pattern * @return a Pattern object representing the result of parsing * @throws XPathException if the pattern contains a syntax error */ public Pattern parsePattern(String pattern, StaticContext env) throws XPathException { this.env = env; language = XSLT_PATTERN; Expression exp = parse(pattern, 0, Token.EOF, env); exp.setContainer(defaultContainer); ExpressionVisitor visitor = ExpressionVisitor.make(env, exp.getExecutable()); return PatternMaker.fromExpression(exp.simplify(visitor), env.getConfiguration()); } public Expression parseExpression() throws XPathException { if (inPredicate > 0) { return super.parseExpression(); } else { // TODO:CLAXON - disallow "union" as synonym for "|" in patterns return parseBinaryExpression(parsePathExpression(), 10); } } // protected Expression parseUnionExpression() throws XPathException { // if (inPredicate > 0) { // return parseBinaryExpression(parse10); // } else { // Expression exp = parsePathExpression(); // while (t.currentToken == Token.UNION) { // if (t.currentTokenValue.equals("union") && !env.getXPathLanguageLevel().equals(DecimalValue.THREE)) { // grumble("Union operator in an XSLT 2.0 pattern must be written as '|'"); // } // nextToken(); // exp = new VennExpression(exp, Token.UNION, parsePathExpression()); // setLocation(exp); // } // return exp; // } // } /** * Parse a basic step expression (without the predicates) * @param firstInPattern true only if we are parsing the first step in a * RelativePathPattern in the XSLT Pattern syntax * @return the resulting subexpression * @throws XPathException if any error is encountered */ protected Expression parseBasicStep(boolean firstInPattern) throws XPathException { if (inPredicate > 0) { return super.parseBasicStep(firstInPattern); } else { switch (t.currentToken) { case Token.LPAR: case Token.STRING_LITERAL: case Token.NUMBER: grumble("Token " + currentTokenDisplay() + " not allowed here in an XSLT pattern"); return null; case Token.FUNCTION: if (!firstInPattern) { grumble("In an XSLT pattern, a function call is allowed only as the first step in a path"); } return super.parseBasicStep(firstInPattern); default: return super.parseBasicStep(firstInPattern); } } } protected Expression parsePredicate() throws XPathException { ++inPredicate; Expression exp = parseExpression(); --inPredicate; return exp; } protected Expression parseFunctionCall() throws XPathException { Expression fn = super.parseFunctionCall(); if (inPredicate > 0) { return fn; } else { if (fn instanceof Id) { // Only one argument allowed, which must be a string literal or variable reference if (((Id)fn).getNumberOfArguments() != 1) { grumble("id() in an XSLT 2.0 pattern must have only one argument"); } else { Expression arg = ((Id)fn).getArguments()[0]; if (!(arg instanceof VariableReference || arg instanceof StringLiteral)) { grumble("Argument to id() in a pattern must be a variable reference or string literal"); } } } else if (fn instanceof KeyFn) { // Only two arguments allowed if (((KeyFn)fn).getNumberOfArguments() != 2) { grumble("key() in an XSLT 2.0 pattern must have exactly two arguments"); } else { Expression arg0 = ((KeyFn)fn).getArguments()[0]; if (!(arg0 instanceof StringLiteral)) { grumble("First argument to key() in an XSLT 2.0 pattern must be a string literal"); } Expression arg1 = ((KeyFn)fn).getArguments()[1]; if (!(arg1 instanceof VariableReference || arg1 instanceof Literal)) { grumble("Second argument to id() in an XSLT 2.0 pattern must be a variable reference or literal"); } } } else if (fn instanceof IXSLFunction) { return fn; //for ixsl:window() pattern match } else { grumble("The " + fn.toString() + " function is not allowed at the head of a pattern"); } } return fn; } protected Expression parseFunctionArgument() throws XPathException { if (inPredicate > 0) { return super.parseFunctionArgument(); } else { switch(t.currentToken) { case Token.DOLLAR: return parseVariableReference(); case Token.STRING_LITERAL: return parseStringLiteral(); case Token.NUMBER: return parseNumericLiteral(); default: grumble("A function argument in an XSLT pattern must be a variable reference or literal"); return null; } } } } // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.