From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- dom/xslt/xpath/txExprParser.cpp | 923 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 923 insertions(+) create mode 100644 dom/xslt/xpath/txExprParser.cpp (limited to 'dom/xslt/xpath/txExprParser.cpp') diff --git a/dom/xslt/xpath/txExprParser.cpp b/dom/xslt/xpath/txExprParser.cpp new file mode 100644 index 000000000..f8474004b --- /dev/null +++ b/dom/xslt/xpath/txExprParser.cpp @@ -0,0 +1,923 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +/** + * ExprParser + * This class is used to parse XSL Expressions + * @see ExprLexer +**/ + +#include "mozilla/Move.h" +#include "txExprParser.h" +#include "txExprLexer.h" +#include "txExpr.h" +#include "txStack.h" +#include "nsGkAtoms.h" +#include "nsError.h" +#include "txIXPathContext.h" +#include "txStringUtils.h" +#include "txXPathNode.h" +#include "txXPathOptimizer.h" + +using mozilla::Move; + +/** + * 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 = nullptr; + nsresult rv = NS_OK; + nsAutoPtr expr; + FunctionCall* concat = nullptr; + + nsAutoString literalString; + bool inExpr = 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) { + char16_t 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 = 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)); + } + 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 = false; + ++iter; // skip closing '}' + break; + } + else if (*iter == '\'' || *iter == '"') { + char16_t 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 necessary + if (!expr) { + expr = Move(newExpr); + } + else { + if (!concat) { + concat = new txCoreFunctionCall(txCoreFunctionCall::CONCAT); + 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()); + } + + *aResult = expr.forget(); + + return NS_OK; +} + +nsresult +txExprParser::createExprInternal(const nsSubstring& aExpression, + uint32_t aSubStringPos, + txIParseContext* aContext, Expr** aExpr) +{ + NS_ENSURE_ARG_POINTER(aExpr); + *aExpr = nullptr; + 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 = nullptr; + 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 = nullptr; + + Expr* expr = nullptr; + 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 = nullptr; + + nsresult rv = NS_OK; + bool done = false; + + nsAutoPtr expr; + + txStack exprs; + txStack ops; + + while (!done) { + + uint16_t negations = 0; + while (lexer.peek()->mType == Token::SUBTRACTION_OP) { + negations++; + lexer.nextToken(); + } + + rv = createUnionExpr(lexer, aContext, getter_Transfers(expr)); + if (NS_FAILED(rv)) { + break; + } + + if (negations > 0) { + if (negations % 2 == 0) { + FunctionCall* fcExpr = new txCoreFunctionCall(txCoreFunctionCall::NUMBER); + + rv = fcExpr->addParam(expr); + if (NS_FAILED(rv)) + return rv; + expr.forget(); + expr = fcExpr; + } + else { + expr = new UnaryExpr(expr.forget()); + } + } + + short tokPrecedence = precedence(lexer.peek()); + if (tokPrecedence != 0) { + Token* tok = lexer.nextToken(); + 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(Move(expr)); + rv = createBinaryExpr(left, right, + static_cast(ops.pop()), + getter_Transfers(expr)); + if (NS_FAILED(rv)) { + done = true; + break; + } + } + exprs.push(expr.forget()); + ops.push(tok); + } + else { + done = true; + } + } + + while (NS_SUCCEEDED(rv) && !exprs.isEmpty()) { + nsAutoPtr left(static_cast(exprs.pop())); + nsAutoPtr right(Move(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 = nullptr; + + nsresult rv = NS_OK; + Token* tok = lexer.peek(); + + nsAutoPtr expr; + switch (tok->mType) { + case Token::FUNCTION_NAME_AND_PAREN: + rv = createFunctionCall(lexer, aContext, getter_Transfers(expr)); + NS_ENSURE_SUCCESS(rv, rv); + break; + case Token::VAR_REFERENCE : + lexer.nextToken(); + { + nsCOMPtr prefix, lName; + int32_t 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); + } + break; + case Token::L_PAREN: + lexer.nextToken(); + rv = createExpr(lexer, aContext, getter_Transfers(expr)); + NS_ENSURE_SUCCESS(rv, rv); + + if (lexer.peek()->mType != Token::R_PAREN) { + return NS_ERROR_XPATH_PAREN_EXPECTED; + } + lexer.nextToken(); + break; + case Token::LITERAL : + lexer.nextToken(); + expr = new txLiteralExpr(tok->Value()); + break; + case Token::NUMBER: + { + lexer.nextToken(); + expr = new txLiteralExpr(txDouble::toDouble(tok->Value())); + break; + } + default: + return createLocationStep(lexer, aContext, aResult); + } + + if (lexer.peek()->mType == Token::L_BRACKET) { + nsAutoPtr filterExpr(new FilterExpr(expr)); + + 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 = nullptr; + + nsAutoPtr fnCall; + + Token* tok = lexer.nextToken(); + NS_ASSERTION(tok->mType == Token::FUNCTION_NAME_AND_PAREN, + "FunctionCall expected"); + + //-- compare function names + nsCOMPtr prefix, lName; + int32_t 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); + } + + // 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.")); + + return NS_OK; + } + + NS_ENSURE_SUCCESS(rv, 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 = nullptr; + + //-- 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 = NS_Atomize(tok->Value()); + if (axis == nsGkAtoms::ancestor) { + axisIdentifier = LocationStep::ANCESTOR_AXIS; + } + else if (axis == nsGkAtoms::ancestorOrSelf) { + axisIdentifier = LocationStep::ANCESTOR_OR_SELF_AXIS; + } + else if (axis == nsGkAtoms::attribute) { + axisIdentifier = LocationStep::ATTRIBUTE_AXIS; + } + else if (axis == nsGkAtoms::child) { + axisIdentifier = LocationStep::CHILD_AXIS; + } + else if (axis == nsGkAtoms::descendant) { + axisIdentifier = LocationStep::DESCENDANT_AXIS; + } + else if (axis == nsGkAtoms::descendantOrSelf) { + axisIdentifier = LocationStep::DESCENDANT_OR_SELF_AXIS; + } + else if (axis == nsGkAtoms::following) { + axisIdentifier = LocationStep::FOLLOWING_AXIS; + } + else if (axis == nsGkAtoms::followingSibling) { + axisIdentifier = LocationStep::FOLLOWING_SIBLING_AXIS; + } + else if (axis == nsGkAtoms::_namespace) { + axisIdentifier = LocationStep::NAMESPACE_AXIS; + } + else if (axis == nsGkAtoms::parent) { + axisIdentifier = LocationStep::PARENT_AXIS; + } + else if (axis == nsGkAtoms::preceding) { + axisIdentifier = LocationStep::PRECEDING_AXIS; + } + else if (axis == nsGkAtoms::precedingSibling) { + axisIdentifier = LocationStep::PRECEDING_SIBLING_AXIS; + } + else if (axis == nsGkAtoms::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); + break; + case Token::SELF_NODE : + //-- eat token + lexer.nextToken(); + axisIdentifier = LocationStep::SELF_AXIS; + nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); + break; + default: + break; + } + + //-- get NodeTest unless an AbbreviatedStep was found + nsresult rv = NS_OK; + if (!nodeTest) { + tok = lexer.peek(); + + if (tok->mType == Token::CNAME) { + lexer.nextToken(); + // resolve QName + nsCOMPtr prefix, lName; + int32_t nspace; + rv = resolveQName(tok->Value(), getter_AddRefs(prefix), + aContext, getter_AddRefs(lName), + nspace, true); + NS_ENSURE_SUCCESS(rv, rv); + + nodeTest = + new txNameTest(prefix, lName, nspace, + axisIdentifier == LocationStep::ATTRIBUTE_AXIS ? + static_cast(txXPathNodeType::ATTRIBUTE_NODE) : + static_cast(txXPathNodeType::ELEMENT_NODE)); + } + else { + rv = createNodeTypeTest(lexer, getter_Transfers(nodeTest)); + NS_ENSURE_SUCCESS(rv, rv); + } + } + + nsAutoPtr lstep(new LocationStep(nodeTest, axisIdentifier)); + + 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.peek(); + + switch (nodeTok->mType) { + case Token::COMMENT_AND_PAREN: + lexer.nextToken(); + nodeTest = new txNodeTypeTest(txNodeTypeTest::COMMENT_TYPE); + break; + case Token::NODE_AND_PAREN: + lexer.nextToken(); + nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); + break; + case Token::PROC_INST_AND_PAREN: + lexer.nextToken(); + nodeTest = new txNodeTypeTest(txNodeTypeTest::PI_TYPE); + break; + case Token::TEXT_AND_PAREN: + lexer.nextToken(); + nodeTest = new txNodeTypeTest(txNodeTypeTest::TEXT_TYPE); + break; + default: + 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.peek()->mType != Token::R_PAREN) { + return NS_ERROR_XPATH_PAREN_EXPECTED; + } + lexer.nextToken(); + + *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 = nullptr; + + nsAutoPtr expr; + + Token* tok = lexer.peek(); + + // is this a root expression? + if (tok->mType == Token::PARENT_OP) { + if (!isLocationStepToken(lexer.peekAhead())) { + lexer.nextToken(); + *aResult = new RootExpr(); + return NS_OK; + } + } + + // 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(); + +#ifdef TX_TO_STRING + static_cast(expr.get())->setSerialize(false); +#endif + } + + // We have a PathExpr containing several steps + nsAutoPtr pathExpr(new PathExpr()); + + rv = pathExpr->addExpr(expr, PathExpr::RELATIVE_OP); + NS_ENSURE_SUCCESS(rv, rv); + + expr.forget(); + + // this is ugly + while (1) { + PathExpr::PathOperator pathOp; + switch (lexer.peek()->mType) { + case Token::ANCESTOR_OP : + pathOp = PathExpr::DESCENDANT_OP; + break; + case Token::PARENT_OP : + pathOp = PathExpr::RELATIVE_OP; + break; + default: + *aResult = pathExpr.forget(); + return NS_OK; + } + lexer.nextToken(); + + 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 = nullptr; + + 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()); + + 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; +} + +bool +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.peek()->mType != Token::R_BRACKET) { + return NS_ERROR_XPATH_BRACKET_EXPECTED; + } + lexer.nextToken(); + } + 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.peek()->mType) { + case Token::R_PAREN : + lexer.nextToken(); + return NS_OK; + case Token::COMMA: //-- param separator + lexer.nextToken(); + break; + default: + 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, int32_t& aNamespace, + bool aIsNameTest) +{ + aNamespace = kNameSpaceID_None; + int32_t idx = aQName.FindChar(':'); + if (idx > 0) { + *aPrefix = NS_Atomize(StringHead(aQName, (uint32_t)idx)).take(); + if (!*aPrefix) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aLocalName = NS_Atomize(Substring(aQName, (uint32_t)idx + 1, + aQName.Length() - (idx + 1))).take(); + 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; + nsContentUtils::ASCIIToLower(aQName, lcname); + *aLocalName = NS_Atomize(lcname).take(); + } + else { + *aLocalName = NS_Atomize(aQName).take(); + } + if (!*aLocalName) { + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} -- cgit v1.2.3