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