/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TransforMiiX XSLT processor code. * * The Initial Developer of the Original Code is * The MITRE Corporation. * Portions created by the Initial Developer are Copyright (C) 1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Keith Visco (Original Author) * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /** * ExprParser * This class is used to parse XSL Expressions * @see ExprLexer **/ #include "txExprParser.h" #include "txExprLexer.h" #include "txExpr.h" #include "txStack.h" #include "txAtoms.h" #include "txError.h" #include "txIXPathContext.h" #include "txStringUtils.h" #include "txXPathNode.h" #include "txXPathOptimizer.h" /** * Creates an Attribute Value Template using the given value * This should move to XSLProcessor class */ nsresult txExprParser::createAVT(const nsSubstring& aAttrValue, txIParseContext* aContext, Expr** aResult) { *aResult = nsnull; nsresult rv = NS_OK; nsAutoPtr expr; FunctionCall* concat = nsnull; nsAutoString literalString; PRBool inExpr = PR_FALSE; nsSubstring::const_char_iterator iter, start, end, avtStart; aAttrValue.BeginReading(iter); aAttrValue.EndReading(end); avtStart = iter; while (iter != end) { // Every iteration through this loop parses either a literal section // or an expression start = iter; nsAutoPtr newExpr; if (!inExpr) { // Parse literal section literalString.Truncate(); while (iter != end) { PRUnichar q = *iter; if (q == '{' || q == '}') { // Store what we've found so far and set a new |start| to // skip the (first) brace literalString.Append(Substring(start, iter)); start = ++iter; // Unless another brace follows we've found the start of // an expression (in case of '{') or an unbalanced brace // (in case of '}') if (iter == end || *iter != q) { if (q == '}') { aContext->SetErrorOffset(iter - avtStart); return NS_ERROR_XPATH_UNBALANCED_CURLY_BRACE; } inExpr = PR_TRUE; break; } // We found a second brace, let that be part of the next // literal section being parsed and continue looping } ++iter; } if (start == iter && literalString.IsEmpty()) { // Restart the loop since we didn't create an expression continue; } newExpr = new txLiteralExpr(literalString + Substring(start, iter)); NS_ENSURE_TRUE(newExpr, NS_ERROR_OUT_OF_MEMORY); } else { // Parse expressions, iter is already past the initial '{' when // we get here. while (iter != end) { if (*iter == '}') { rv = createExprInternal(Substring(start, iter), start - avtStart, aContext, getter_Transfers(newExpr)); NS_ENSURE_SUCCESS(rv, rv); inExpr = PR_FALSE; ++iter; // skip closing '}' break; } else if (*iter == '\'' || *iter == '"') { PRUnichar q = *iter; while (++iter != end && *iter != q) {} /* do nothing */ if (iter == end) { break; } } ++iter; } if (inExpr) { aContext->SetErrorOffset(start - avtStart); return NS_ERROR_XPATH_UNBALANCED_CURLY_BRACE; } } // Add expression, create a concat() call if neccesary if (!expr) { expr = newExpr; } else { if (!concat) { concat = new txCoreFunctionCall(txCoreFunctionCall::CONCAT); NS_ENSURE_TRUE(concat, NS_ERROR_OUT_OF_MEMORY); rv = concat->addParam(expr.forget()); expr = concat; NS_ENSURE_SUCCESS(rv, rv); } rv = concat->addParam(newExpr.forget()); NS_ENSURE_SUCCESS(rv, rv); } } if (inExpr) { aContext->SetErrorOffset(iter - avtStart); return NS_ERROR_XPATH_UNBALANCED_CURLY_BRACE; } if (!expr) { expr = new txLiteralExpr(EmptyString()); NS_ENSURE_TRUE(expr, NS_ERROR_OUT_OF_MEMORY); } *aResult = expr.forget(); return NS_OK; } nsresult txExprParser::createExprInternal(const nsSubstring& aExpression, PRUint32 aSubStringPos, txIParseContext* aContext, Expr** aExpr) { NS_ENSURE_ARG_POINTER(aExpr); *aExpr = nsnull; txExprLexer lexer; nsresult rv = lexer.parse(aExpression); if (NS_FAILED(rv)) { nsASingleFragmentString::const_char_iterator start; aExpression.BeginReading(start); aContext->SetErrorOffset(lexer.mPosition - start + aSubStringPos); return rv; } nsAutoPtr expr; rv = createExpr(lexer, aContext, getter_Transfers(expr)); if (NS_SUCCEEDED(rv) && lexer.peek()->mType != Token::END) { rv = NS_ERROR_XPATH_BINARY_EXPECTED; } if (NS_FAILED(rv)) { nsASingleFragmentString::const_char_iterator start; aExpression.BeginReading(start); aContext->SetErrorOffset(lexer.peek()->mStart - start + aSubStringPos); return rv; } txXPathOptimizer optimizer; Expr* newExpr = nsnull; rv = optimizer.optimize(expr, &newExpr); NS_ENSURE_SUCCESS(rv, rv); *aExpr = newExpr ? newExpr : expr.forget(); return NS_OK; } /** * Private Methods */ /** * Creates a binary Expr for the given operator */ nsresult txExprParser::createBinaryExpr(nsAutoPtr& left, nsAutoPtr& right, Token* op, Expr** aResult) { NS_ASSERTION(op, "internal error"); *aResult = nsnull; Expr* expr = nsnull; switch (op->mType) { //-- math ops case Token::ADDITION_OP : expr = new txNumberExpr(left, right, txNumberExpr::ADD); break; case Token::SUBTRACTION_OP: expr = new txNumberExpr(left, right, txNumberExpr::SUBTRACT); break; case Token::DIVIDE_OP : expr = new txNumberExpr(left, right, txNumberExpr::DIVIDE); break; case Token::MODULUS_OP : expr = new txNumberExpr(left, right, txNumberExpr::MODULUS); break; case Token::MULTIPLY_OP : expr = new txNumberExpr(left, right, txNumberExpr::MULTIPLY); break; //-- case boolean ops case Token::AND_OP: expr = new BooleanExpr(left, right, BooleanExpr::AND); break; case Token::OR_OP: expr = new BooleanExpr(left, right, BooleanExpr::OR); break; //-- equality ops case Token::EQUAL_OP : expr = new RelationalExpr(left, right, RelationalExpr::EQUAL); break; case Token::NOT_EQUAL_OP : expr = new RelationalExpr(left, right, RelationalExpr::NOT_EQUAL); break; //-- relational ops case Token::LESS_THAN_OP: expr = new RelationalExpr(left, right, RelationalExpr::LESS_THAN); break; case Token::GREATER_THAN_OP: expr = new RelationalExpr(left, right, RelationalExpr::GREATER_THAN); break; case Token::LESS_OR_EQUAL_OP: expr = new RelationalExpr(left, right, RelationalExpr::LESS_OR_EQUAL); break; case Token::GREATER_OR_EQUAL_OP: expr = new RelationalExpr(left, right, RelationalExpr::GREATER_OR_EQUAL); break; default: NS_NOTREACHED("operator tokens should be already checked"); return NS_ERROR_UNEXPECTED; } NS_ENSURE_TRUE(expr, NS_ERROR_OUT_OF_MEMORY); left.forget(); right.forget(); *aResult = expr; return NS_OK; } nsresult txExprParser::createExpr(txExprLexer& lexer, txIParseContext* aContext, Expr** aResult) { *aResult = nsnull; nsresult rv = NS_OK; MBool done = MB_FALSE; nsAutoPtr expr; txStack exprs; txStack ops; while (!done) { MBool unary = MB_FALSE; while (lexer.peek()->mType == Token::SUBTRACTION_OP) { unary = !unary; lexer.nextToken(); } rv = createUnionExpr(lexer, aContext, getter_Transfers(expr)); if (NS_FAILED(rv)) { break; } if (unary) { Expr* unaryExpr = new UnaryExpr(expr); if (!unaryExpr) { rv = NS_ERROR_OUT_OF_MEMORY; break; } expr.forget(); expr = unaryExpr; } Token* tok = lexer.nextToken(); short tokPrecedence = precedence(tok); if (tokPrecedence != 0) { while (!exprs.isEmpty() && tokPrecedence <= precedence(static_cast(ops.peek()))) { // can't use expr as argument due to order of evaluation nsAutoPtr left(static_cast(exprs.pop())); nsAutoPtr right(expr); rv = createBinaryExpr(left, right, static_cast(ops.pop()), getter_Transfers(expr)); if (NS_FAILED(rv)) { done = PR_TRUE; break; } } exprs.push(expr.forget()); ops.push(tok); } else { lexer.pushBack(); done = PR_TRUE; } } while (NS_SUCCEEDED(rv) && !exprs.isEmpty()) { nsAutoPtr left(static_cast(exprs.pop())); nsAutoPtr right(expr); rv = createBinaryExpr(left, right, static_cast(ops.pop()), getter_Transfers(expr)); } // clean up on error while (!exprs.isEmpty()) { delete static_cast(exprs.pop()); } NS_ENSURE_SUCCESS(rv, rv); *aResult = expr.forget(); return NS_OK; } nsresult txExprParser::createFilterOrStep(txExprLexer& lexer, txIParseContext* aContext, Expr** aResult) { *aResult = nsnull; nsresult rv = NS_OK; Token* tok = lexer.nextToken(); nsAutoPtr expr; switch (tok->mType) { case Token::FUNCTION_NAME_AND_PAREN: lexer.pushBack(); rv = createFunctionCall(lexer, aContext, getter_Transfers(expr)); NS_ENSURE_SUCCESS(rv, rv); break; case Token::VAR_REFERENCE : { nsCOMPtr prefix, lName; PRInt32 nspace; nsresult rv = resolveQName(tok->Value(), getter_AddRefs(prefix), aContext, getter_AddRefs(lName), nspace); NS_ENSURE_SUCCESS(rv, rv); expr = new VariableRefExpr(prefix, lName, nspace); NS_ENSURE_TRUE(expr, NS_ERROR_OUT_OF_MEMORY); } break; case Token::L_PAREN: rv = createExpr(lexer, aContext, getter_Transfers(expr)); NS_ENSURE_SUCCESS(rv, rv); if (lexer.nextToken()->mType != Token::R_PAREN) { lexer.pushBack(); return NS_ERROR_XPATH_PAREN_EXPECTED; } break; case Token::LITERAL : expr = new txLiteralExpr(tok->Value()); NS_ENSURE_TRUE(expr, NS_ERROR_OUT_OF_MEMORY); break; case Token::NUMBER: { expr = new txLiteralExpr(Double::toDouble(tok->Value())); NS_ENSURE_TRUE(expr, NS_ERROR_OUT_OF_MEMORY); break; } default: lexer.pushBack(); return createLocationStep(lexer, aContext, aResult); } if (lexer.peek()->mType == Token::L_BRACKET) { nsAutoPtr filterExpr(new FilterExpr(expr)); NS_ENSURE_TRUE(filterExpr, NS_ERROR_OUT_OF_MEMORY); expr.forget(); //-- handle predicates rv = parsePredicates(filterExpr, lexer, aContext); NS_ENSURE_SUCCESS(rv, rv); expr = filterExpr.forget(); } *aResult = expr.forget(); return NS_OK; } nsresult txExprParser::createFunctionCall(txExprLexer& lexer, txIParseContext* aContext, Expr** aResult) { *aResult = nsnull; nsAutoPtr fnCall; Token* tok = lexer.nextToken(); NS_ASSERTION(tok->mType == Token::FUNCTION_NAME_AND_PAREN, "FunctionCall expected"); //-- compare function names nsCOMPtr prefix, lName; PRInt32 namespaceID; nsresult rv = resolveQName(tok->Value(), getter_AddRefs(prefix), aContext, getter_AddRefs(lName), namespaceID); NS_ENSURE_SUCCESS(rv, rv); txCoreFunctionCall::eType type; if (namespaceID == kNameSpaceID_None && txCoreFunctionCall::getTypeFromAtom(lName, type)) { // It is a known built-in function. fnCall = new txCoreFunctionCall(type); NS_ENSURE_TRUE(fnCall, NS_ERROR_OUT_OF_MEMORY); } // check extension functions and xslt if (!fnCall) { rv = aContext->resolveFunctionCall(lName, namespaceID, getter_Transfers(fnCall)); if (rv == NS_ERROR_NOT_IMPLEMENTED) { // this should just happen for unparsed-entity-uri() NS_ASSERTION(!fnCall, "Now is it implemented or not?"); rv = parseParameters(0, lexer, aContext); NS_ENSURE_SUCCESS(rv, rv); *aResult = new txLiteralExpr(tok->Value() + NS_LITERAL_STRING(" not implemented.")); NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); return NS_OK; } if (NS_FAILED(rv)) { NS_ERROR("Creation of FunctionCall failed"); return rv; } } //-- handle parametes rv = parseParameters(fnCall, lexer, aContext); NS_ENSURE_SUCCESS(rv, rv); *aResult = fnCall.forget(); return NS_OK; } nsresult txExprParser::createLocationStep(txExprLexer& lexer, txIParseContext* aContext, Expr** aExpr) { *aExpr = nsnull; //-- child axis is default LocationStep::LocationStepType axisIdentifier = LocationStep::CHILD_AXIS; nsAutoPtr nodeTest; //-- get Axis Identifier or AbbreviatedStep, if present Token* tok = lexer.peek(); switch (tok->mType) { case Token::AXIS_IDENTIFIER: { //-- eat token lexer.nextToken(); nsCOMPtr axis = do_GetAtom(tok->Value()); if (axis == txXPathAtoms::ancestor) { axisIdentifier = LocationStep::ANCESTOR_AXIS; } else if (axis == txXPathAtoms::ancestorOrSelf) { axisIdentifier = LocationStep::ANCESTOR_OR_SELF_AXIS; } else if (axis == txXPathAtoms::attribute) { axisIdentifier = LocationStep::ATTRIBUTE_AXIS; } else if (axis == txXPathAtoms::child) { axisIdentifier = LocationStep::CHILD_AXIS; } else if (axis == txXPathAtoms::descendant) { axisIdentifier = LocationStep::DESCENDANT_AXIS; } else if (axis == txXPathAtoms::descendantOrSelf) { axisIdentifier = LocationStep::DESCENDANT_OR_SELF_AXIS; } else if (axis == txXPathAtoms::following) { axisIdentifier = LocationStep::FOLLOWING_AXIS; } else if (axis == txXPathAtoms::followingSibling) { axisIdentifier = LocationStep::FOLLOWING_SIBLING_AXIS; } else if (axis == txXPathAtoms::_namespace) { axisIdentifier = LocationStep::NAMESPACE_AXIS; } else if (axis == txXPathAtoms::parent) { axisIdentifier = LocationStep::PARENT_AXIS; } else if (axis == txXPathAtoms::preceding) { axisIdentifier = LocationStep::PRECEDING_AXIS; } else if (axis == txXPathAtoms::precedingSibling) { axisIdentifier = LocationStep::PRECEDING_SIBLING_AXIS; } else if (axis == txXPathAtoms::self) { axisIdentifier = LocationStep::SELF_AXIS; } else { return NS_ERROR_XPATH_INVALID_AXIS; } break; } case Token::AT_SIGN: //-- eat token lexer.nextToken(); axisIdentifier = LocationStep::ATTRIBUTE_AXIS; break; case Token::PARENT_NODE : //-- eat token lexer.nextToken(); axisIdentifier = LocationStep::PARENT_AXIS; nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); NS_ENSURE_TRUE(nodeTest, NS_ERROR_OUT_OF_MEMORY); break; case Token::SELF_NODE : //-- eat token lexer.nextToken(); axisIdentifier = LocationStep::SELF_AXIS; nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); NS_ENSURE_TRUE(nodeTest, NS_ERROR_OUT_OF_MEMORY); break; default: break; } //-- get NodeTest unless an AbbreviatedStep was found nsresult rv = NS_OK; if (!nodeTest) { tok = lexer.nextToken(); if (tok->mType == Token::CNAME) { // resolve QName nsCOMPtr prefix, lName; PRInt32 nspace; rv = resolveQName(tok->Value(), getter_AddRefs(prefix), aContext, getter_AddRefs(lName), nspace, PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); nodeTest = new txNameTest(prefix, lName, nspace, axisIdentifier == LocationStep::ATTRIBUTE_AXIS ? txXPathNodeType::ATTRIBUTE_NODE : txXPathNodeType::ELEMENT_NODE); NS_ENSURE_TRUE(nodeTest, NS_ERROR_OUT_OF_MEMORY); } else { lexer.pushBack(); rv = createNodeTypeTest(lexer, getter_Transfers(nodeTest)); NS_ENSURE_SUCCESS(rv, rv); } } nsAutoPtr lstep(new LocationStep(nodeTest, axisIdentifier)); NS_ENSURE_TRUE(lstep, NS_ERROR_OUT_OF_MEMORY); nodeTest.forget(); //-- handle predicates rv = parsePredicates(lstep, lexer, aContext); NS_ENSURE_SUCCESS(rv, rv); *aExpr = lstep.forget(); return NS_OK; } /** * This method only handles comment(), text(), processing-instructing() * and node() */ nsresult txExprParser::createNodeTypeTest(txExprLexer& lexer, txNodeTest** aTest) { *aTest = 0; nsAutoPtr nodeTest; Token* nodeTok = lexer.nextToken(); switch (nodeTok->mType) { case Token::COMMENT_AND_PAREN: nodeTest = new txNodeTypeTest(txNodeTypeTest::COMMENT_TYPE); break; case Token::NODE_AND_PAREN: nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); break; case Token::PROC_INST_AND_PAREN: nodeTest = new txNodeTypeTest(txNodeTypeTest::PI_TYPE); break; case Token::TEXT_AND_PAREN: nodeTest = new txNodeTypeTest(txNodeTypeTest::TEXT_TYPE); break; default: lexer.pushBack(); return NS_ERROR_XPATH_NO_NODE_TYPE_TEST; } NS_ENSURE_TRUE(nodeTest, NS_ERROR_OUT_OF_MEMORY); if (nodeTok->mType == Token::PROC_INST_AND_PAREN && lexer.peek()->mType == Token::LITERAL) { Token* tok = lexer.nextToken(); nodeTest->setNodeName(tok->Value()); } if (lexer.nextToken()->mType != Token::R_PAREN) { lexer.pushBack(); return NS_ERROR_XPATH_PAREN_EXPECTED; } *aTest = nodeTest.forget(); return NS_OK; } /** * Creates a PathExpr using the given txExprLexer * @param lexer the txExprLexer for retrieving Tokens */ nsresult txExprParser::createPathExpr(txExprLexer& lexer, txIParseContext* aContext, Expr** aResult) { *aResult = nsnull; nsAutoPtr expr; Token* tok = lexer.peek(); // is this a root expression? if (tok->mType == Token::PARENT_OP) { lexer.nextToken(); if (!isLocationStepToken(lexer.peek())) { *aResult = new RootExpr(); NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); return NS_OK; } lexer.pushBack(); } // parse first step (possibly a FilterExpr) nsresult rv = NS_OK; if (tok->mType != Token::PARENT_OP && tok->mType != Token::ANCESTOR_OP) { rv = createFilterOrStep(lexer, aContext, getter_Transfers(expr)); NS_ENSURE_SUCCESS(rv, rv); // is this a singlestep path expression? tok = lexer.peek(); if (tok->mType != Token::PARENT_OP && tok->mType != Token::ANCESTOR_OP) { *aResult = expr.forget(); return NS_OK; } } else { expr = new RootExpr(); NS_ENSURE_TRUE(expr, NS_ERROR_OUT_OF_MEMORY); #ifdef TX_TO_STRING static_cast(expr.get())->setSerialize(PR_FALSE); #endif } // We have a PathExpr containing several steps nsAutoPtr pathExpr(new PathExpr()); NS_ENSURE_TRUE(pathExpr, NS_ERROR_OUT_OF_MEMORY); rv = pathExpr->addExpr(expr, PathExpr::RELATIVE_OP); NS_ENSURE_SUCCESS(rv, rv); expr.forget(); // this is ugly while (1) { PathExpr::PathOperator pathOp; tok = lexer.nextToken(); switch (tok->mType) { case Token::ANCESTOR_OP : pathOp = PathExpr::DESCENDANT_OP; break; case Token::PARENT_OP : pathOp = PathExpr::RELATIVE_OP; break; default: lexer.pushBack(); *aResult = pathExpr.forget(); return NS_OK; } rv = createLocationStep(lexer, aContext, getter_Transfers(expr)); NS_ENSURE_SUCCESS(rv, rv); rv = pathExpr->addExpr(expr, pathOp); NS_ENSURE_SUCCESS(rv, rv); expr.forget(); } NS_NOTREACHED("internal xpath parser error"); return NS_ERROR_UNEXPECTED; } /** * Creates a PathExpr using the given txExprLexer * @param lexer the txExprLexer for retrieving Tokens */ nsresult txExprParser::createUnionExpr(txExprLexer& lexer, txIParseContext* aContext, Expr** aResult) { *aResult = nsnull; nsAutoPtr expr; nsresult rv = createPathExpr(lexer, aContext, getter_Transfers(expr)); NS_ENSURE_SUCCESS(rv, rv); if (lexer.peek()->mType != Token::UNION_OP) { *aResult = expr.forget(); return NS_OK; } nsAutoPtr unionExpr(new UnionExpr()); NS_ENSURE_TRUE(unionExpr, NS_ERROR_OUT_OF_MEMORY); rv = unionExpr->addExpr(expr); NS_ENSURE_SUCCESS(rv, rv); expr.forget(); while (lexer.peek()->mType == Token::UNION_OP) { lexer.nextToken(); //-- eat token rv = createPathExpr(lexer, aContext, getter_Transfers(expr)); NS_ENSURE_SUCCESS(rv, rv); rv = unionExpr->addExpr(expr.forget()); NS_ENSURE_SUCCESS(rv, rv); } *aResult = unionExpr.forget(); return NS_OK; } PRBool txExprParser::isLocationStepToken(Token* aToken) { // We could put these in consecutive order in ExprLexer.h for speed return aToken->mType == Token::AXIS_IDENTIFIER || aToken->mType == Token::AT_SIGN || aToken->mType == Token::PARENT_NODE || aToken->mType == Token::SELF_NODE || aToken->mType == Token::CNAME || aToken->mType == Token::COMMENT_AND_PAREN || aToken->mType == Token::NODE_AND_PAREN || aToken->mType == Token::PROC_INST_AND_PAREN || aToken->mType == Token::TEXT_AND_PAREN; } /** * Using the given lexer, parses the tokens if they represent a predicate list * If an error occurs a non-zero String pointer will be returned containing the * error message. * @param predicateList, the PredicateList to add predicate expressions to * @param lexer the txExprLexer to use for parsing tokens * @return 0 if successful, or a String pointer to the error message */ nsresult txExprParser::parsePredicates(PredicateList* aPredicateList, txExprLexer& lexer, txIParseContext* aContext) { nsAutoPtr expr; nsresult rv = NS_OK; while (lexer.peek()->mType == Token::L_BRACKET) { //-- eat Token lexer.nextToken(); rv = createExpr(lexer, aContext, getter_Transfers(expr)); NS_ENSURE_SUCCESS(rv, rv); rv = aPredicateList->add(expr); NS_ENSURE_SUCCESS(rv, rv); expr.forget(); if (lexer.nextToken()->mType != Token::R_BRACKET) { lexer.pushBack(); return NS_ERROR_XPATH_BRACKET_EXPECTED; } } return NS_OK; } /** * Using the given lexer, parses the tokens if they represent a parameter list * If an error occurs a non-zero String pointer will be returned containing the * error message. * @param list, the List to add parameter expressions to * @param lexer the txExprLexer to use for parsing tokens * @return NS_OK if successful, or another rv otherwise */ nsresult txExprParser::parseParameters(FunctionCall* aFnCall, txExprLexer& lexer, txIParseContext* aContext) { if (lexer.peek()->mType == Token::R_PAREN) { lexer.nextToken(); return NS_OK; } nsAutoPtr expr; nsresult rv = NS_OK; while (1) { rv = createExpr(lexer, aContext, getter_Transfers(expr)); NS_ENSURE_SUCCESS(rv, rv); if (aFnCall) { rv = aFnCall->addParam(expr.forget()); NS_ENSURE_SUCCESS(rv, rv); } switch (lexer.nextToken()->mType) { case Token::R_PAREN : return NS_OK; case Token::COMMA: //-- param separator break; default: lexer.pushBack(); return NS_ERROR_XPATH_PAREN_EXPECTED; } } NS_NOTREACHED("internal xpath parser error"); return NS_ERROR_UNEXPECTED; } short txExprParser::precedence(Token* aToken) { switch (aToken->mType) { case Token::OR_OP: return 1; case Token::AND_OP: return 2; //-- equality case Token::EQUAL_OP: case Token::NOT_EQUAL_OP: return 3; //-- relational case Token::LESS_THAN_OP: case Token::GREATER_THAN_OP: case Token::LESS_OR_EQUAL_OP: case Token::GREATER_OR_EQUAL_OP: return 4; //-- additive operators case Token::ADDITION_OP: case Token::SUBTRACTION_OP: return 5; //-- multiplicative case Token::DIVIDE_OP: case Token::MULTIPLY_OP: case Token::MODULUS_OP: return 6; default: break; } return 0; } nsresult txExprParser::resolveQName(const nsAString& aQName, nsIAtom** aPrefix, txIParseContext* aContext, nsIAtom** aLocalName, PRInt32& aNamespace, PRBool aIsNameTest) { aNamespace = kNameSpaceID_None; PRInt32 idx = aQName.FindChar(':'); if (idx > 0) { *aPrefix = NS_NewAtom(StringHead(aQName, (PRUint32)idx)); if (!*aPrefix) { return NS_ERROR_OUT_OF_MEMORY; } *aLocalName = NS_NewAtom(Substring(aQName, (PRUint32)idx + 1, aQName.Length() - (idx + 1))); if (!*aLocalName) { NS_RELEASE(*aPrefix); return NS_ERROR_OUT_OF_MEMORY; } return aContext->resolveNamespacePrefix(*aPrefix, aNamespace); } // the lexer dealt with idx == 0 *aPrefix = 0; if (aIsNameTest && aContext->caseInsensitiveNameTests()) { nsAutoString lcname; TX_ToLowerCase(aQName, lcname); *aLocalName = NS_NewAtom(lcname); } else { *aLocalName = NS_NewAtom(aQName); } if (!*aLocalName) { return NS_ERROR_OUT_OF_MEMORY; } return NS_OK; }