/** * 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> 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> 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; }
/** * 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> 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; }
/** * 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> 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; }
nsresult txPatternParser::createUnionPattern(txExprLexer& aLexer, txIParseContext* aContext, txPattern*& aPattern) { nsresult rv = NS_OK; txPattern* locPath = 0; rv = createLocPathPattern(aLexer, aContext, locPath); if (NS_FAILED(rv)) return rv; Token::Type type = aLexer.peek()->mType; if (type == Token::END) { aPattern = locPath; return NS_OK; } if (type != Token::UNION_OP) { delete locPath; return NS_ERROR_XPATH_PARSE_FAILURE; } txUnionPattern* unionPattern = new txUnionPattern(); rv = unionPattern->addPattern(locPath); #if 0 // XXX addPattern can't fail yet, it doesn't check for mem if (NS_FAILED(rv)) { delete unionPattern; delete locPath; return rv; } #endif aLexer.nextToken(); do { rv = createLocPathPattern(aLexer, aContext, locPath); if (NS_FAILED(rv)) { delete unionPattern; return rv; } rv = unionPattern->addPattern(locPath); #if 0 // XXX addPattern can't fail yet, it doesn't check for mem if (NS_FAILED(rv)) { delete unionPattern; delete locPath; return rv; } #endif type = aLexer.nextToken()->mType; } while (type == Token::UNION_OP); if (type != Token::END) { delete unionPattern; return NS_ERROR_XPATH_PARSE_FAILURE; } aPattern = unionPattern; return NS_OK; }
nsresult txPatternParser::createStepPattern(txExprLexer& aLexer, txIParseContext* aContext, txPattern*& aPattern) { nsresult rv = NS_OK; bool isAttr = false; Token* tok = aLexer.peek(); if (tok->mType == Token::AXIS_IDENTIFIER) { if (TX_StringEqualsAtom(tok->Value(), nsGkAtoms::attribute)) { isAttr = true; } else if (!TX_StringEqualsAtom(tok->Value(), nsGkAtoms::child)) { // all done already for CHILD_AXIS, for all others // XXX report unexpected axis error return NS_ERROR_XPATH_PARSE_FAILURE; } aLexer.nextToken(); } else if (tok->mType == Token::AT_SIGN) { aLexer.nextToken(); isAttr = true; } txNodeTest* nodeTest; if (aLexer.peek()->mType == Token::CNAME) { tok = aLexer.nextToken(); // resolve QName RefPtr<nsAtom> prefix, lName; int32_t nspace; rv = resolveQName(tok->Value(), getter_AddRefs(prefix), aContext, getter_AddRefs(lName), nspace, true); if (NS_FAILED(rv)) { // XXX error report namespace resolve failed return rv; } uint16_t nodeType = isAttr ? (uint16_t)txXPathNodeType::ATTRIBUTE_NODE : (uint16_t)txXPathNodeType::ELEMENT_NODE; nodeTest = new txNameTest(prefix, lName, nspace, nodeType); } else { rv = createNodeTypeTest(aLexer, &nodeTest); NS_ENSURE_SUCCESS(rv, rv); } nsAutoPtr<txStepPattern> step(new txStepPattern(nodeTest, isAttr)); rv = parsePredicates(step, aLexer, aContext); NS_ENSURE_SUCCESS(rv, rv); aPattern = step.forget(); return NS_OK; }
nsresult txPatternParser::createIdPattern(txExprLexer& aLexer, txPattern*& aPattern) { // check for '(' Literal ')' if (aLexer.peek()->mType != Token::LITERAL) return NS_ERROR_XPATH_PARSE_FAILURE; const nsDependentSubstring& value = aLexer.nextToken()->Value(); if (aLexer.nextToken()->mType != Token::R_PAREN) return NS_ERROR_XPATH_PARSE_FAILURE; aPattern = new txIdPattern(value); return NS_OK; }
nsresult txExprParser::createFunctionCall(txExprLexer& lexer, txIParseContext* aContext, Expr** aResult) { *aResult = nsnull; nsAutoPtr<FunctionCall> fnCall; Token* tok = lexer.nextToken(); NS_ASSERTION(tok->mType == Token::FUNCTION_NAME_AND_PAREN, "FunctionCall expected"); //-- compare function names nsCOMPtr<nsIAtom> 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; } NS_ENSURE_SUCCESS(rv, rv); } //-- handle parametes rv = parseParameters(fnCall, lexer, aContext); NS_ENSURE_SUCCESS(rv, rv); *aResult = fnCall.forget(); return NS_OK; }
nsresult txPatternParser::createKeyPattern(txExprLexer& aLexer, txIParseContext* aContext, txPattern*& aPattern) { // check for '(' Literal, Literal ')' if (aLexer.peek()->mType != Token::LITERAL) return NS_ERROR_XPATH_PARSE_FAILURE; const nsDependentSubstring& key = aLexer.nextToken()->Value(); if (aLexer.nextToken()->mType != Token::COMMA && aLexer.peek()->mType != Token::LITERAL) return NS_ERROR_XPATH_PARSE_FAILURE; const nsDependentSubstring& value = aLexer.nextToken()->Value(); if (aLexer.nextToken()->mType != Token::R_PAREN) return NS_ERROR_XPATH_PARSE_FAILURE; if (!aContext->allowed(txIParseContext::KEY_FUNCTION)) return NS_ERROR_XSLT_CALL_TO_KEY_NOT_ALLOWED; const char16_t* colon; if (!XMLUtils::isValidQName(key, &colon)) { return NS_ERROR_XPATH_PARSE_FAILURE; } RefPtr<nsAtom> prefix, localName; int32_t namespaceID; nsresult rv = resolveQName(key, getter_AddRefs(prefix), aContext, getter_AddRefs(localName), namespaceID); if (NS_FAILED(rv)) return rv; aPattern = new txKeyPattern(prefix, localName, namespaceID, value); return NS_OK; }
nsresult txPatternParser::createKeyPattern(txExprLexer& aLexer, txIParseContext* aContext, txPattern*& aPattern) { // check for '(' Literal, Literal ')' if (aLexer.peek()->mType != Token::LITERAL) return NS_ERROR_XPATH_PARSE_FAILURE; const nsDependentSubstring& key = aLexer.nextToken()->Value(); if (aLexer.nextToken()->mType != Token::COMMA && aLexer.peek()->mType != Token::LITERAL) return NS_ERROR_XPATH_PARSE_FAILURE; const nsDependentSubstring& value = aLexer.nextToken()->Value(); if (aLexer.nextToken()->mType != Token::R_PAREN) return NS_ERROR_XPATH_PARSE_FAILURE; const PRUnichar* colon; if (!XMLUtils::isValidQName(PromiseFlatString(key), &colon)) return NS_ERROR_XPATH_PARSE_FAILURE; nsCOMPtr<nsIAtom> prefix, localName; PRInt32 namespaceID; nsresult rv = resolveQName(key, getter_AddRefs(prefix), aContext, getter_AddRefs(localName), namespaceID); if (NS_FAILED(rv)) return rv; aPattern = new txKeyPattern(prefix, localName, namespaceID, value); return aPattern ? NS_OK : NS_ERROR_OUT_OF_MEMORY; }
/** * This method only handles comment(), text(), processing-instructing() * and node() */ nsresult txExprParser::createNodeTypeTest(txExprLexer& lexer, txNodeTest** aTest) { *aTest = 0; nsAutoPtr<txNodeTypeTest> 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; }
nsresult txExprParser::createExpr(txExprLexer& lexer, txIParseContext* aContext, Expr** aResult) { *aResult = nsnull; nsresult rv = NS_OK; MBool done = MB_FALSE; nsAutoPtr<Expr> 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<Token*>(ops.peek()))) { // can't use expr as argument due to order of evaluation nsAutoPtr<Expr> left(static_cast<Expr*>(exprs.pop())); nsAutoPtr<Expr> right(expr); rv = createBinaryExpr(left, right, static_cast<Token*>(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<Expr> left(static_cast<Expr*>(exprs.pop())); nsAutoPtr<Expr> right(expr); rv = createBinaryExpr(left, right, static_cast<Token*>(ops.pop()), getter_Transfers(expr)); } // clean up on error while (!exprs.isEmpty()) { delete static_cast<Expr*>(exprs.pop()); } NS_ENSURE_SUCCESS(rv, rv); *aResult = expr.forget(); return NS_OK; }
nsresult txPatternParser::createLocPathPattern(txExprLexer& aLexer, txIParseContext* aContext, txPattern*& aPattern) { nsresult rv = NS_OK; bool isChild = true; bool isAbsolute = false; txPattern* stepPattern = 0; txLocPathPattern* pathPattern = 0; Token::Type type = aLexer.peek()->mType; switch (type) { case Token::ANCESTOR_OP: isChild = false; isAbsolute = true; aLexer.nextToken(); break; case Token::PARENT_OP: aLexer.nextToken(); isAbsolute = true; if (aLexer.peek()->mType == Token::END || aLexer.peek()->mType == Token::UNION_OP) { aPattern = new txRootPattern(); return NS_OK; } break; case Token::FUNCTION_NAME_AND_PAREN: // id(Literal) or key(Literal, Literal) { RefPtr<nsAtom> nameAtom = NS_Atomize(aLexer.nextToken()->Value()); if (nameAtom == nsGkAtoms::id) { rv = createIdPattern(aLexer, stepPattern); } else if (nameAtom == nsGkAtoms::key) { rv = createKeyPattern(aLexer, aContext, stepPattern); } if (NS_FAILED(rv)) return rv; } break; default: break; } if (!stepPattern) { rv = createStepPattern(aLexer, aContext, stepPattern); if (NS_FAILED(rv)) return rv; } type = aLexer.peek()->mType; if (!isAbsolute && type != Token::PARENT_OP && type != Token::ANCESTOR_OP) { aPattern = stepPattern; return NS_OK; } pathPattern = new txLocPathPattern(); if (isAbsolute) { txRootPattern* root = new txRootPattern(); #ifdef TX_TO_STRING root->setSerialize(false); #endif rv = pathPattern->addStep(root, isChild); if (NS_FAILED(rv)) { delete stepPattern; delete pathPattern; delete root; return NS_ERROR_OUT_OF_MEMORY; } } rv = pathPattern->addStep(stepPattern, isChild); if (NS_FAILED(rv)) { delete stepPattern; delete pathPattern; return NS_ERROR_OUT_OF_MEMORY; } stepPattern = 0; // stepPattern is part of pathPattern now while (type == Token::PARENT_OP || type == Token::ANCESTOR_OP) { isChild = type == Token::PARENT_OP; aLexer.nextToken(); rv = createStepPattern(aLexer, aContext, stepPattern); if (NS_FAILED(rv)) { delete pathPattern; return rv; } rv = pathPattern->addStep(stepPattern, isChild); if (NS_FAILED(rv)) { delete stepPattern; delete pathPattern; return NS_ERROR_OUT_OF_MEMORY; } stepPattern = 0; // stepPattern is part of pathPattern now type = aLexer.peek()->mType; } aPattern = pathPattern; return rv; }
nsresult txPatternParser::createStepPattern(txExprLexer& aLexer, txIParseContext* aContext, txPattern*& aPattern) { nsresult rv = NS_OK; MBool isAttr = MB_FALSE; Token* tok = aLexer.peek(); if (tok->mType == Token::AXIS_IDENTIFIER) { if (TX_StringEqualsAtom(tok->Value(), txXPathAtoms::attribute)) { isAttr = MB_TRUE; } else if (!TX_StringEqualsAtom(tok->Value(), txXPathAtoms::child)) { // all done already for CHILD_AXIS, for all others // XXX report unexpected axis error return NS_ERROR_XPATH_PARSE_FAILURE; } aLexer.nextToken(); } else if (tok->mType == Token::AT_SIGN) { aLexer.nextToken(); isAttr = MB_TRUE; } tok = aLexer.nextToken(); txNodeTest* nodeTest; if (tok->mType == Token::CNAME) { // resolve QName nsCOMPtr<nsIAtom> prefix, lName; PRInt32 nspace; rv = resolveQName(tok->Value(), getter_AddRefs(prefix), aContext, getter_AddRefs(lName), nspace, PR_TRUE); if (NS_FAILED(rv)) { // XXX error report namespace resolve failed return rv; } PRUint16 nodeType = isAttr ? (PRUint16)txXPathNodeType::ATTRIBUTE_NODE : (PRUint16)txXPathNodeType::ELEMENT_NODE; nodeTest = new txNameTest(prefix, lName, nspace, nodeType); if (!nodeTest) { return NS_ERROR_OUT_OF_MEMORY; } } else { aLexer.pushBack(); rv = createNodeTypeTest(aLexer, &nodeTest); NS_ENSURE_SUCCESS(rv, rv); } nsAutoPtr<txStepPattern> step(new txStepPattern(nodeTest, isAttr)); if (!step) { delete nodeTest; return NS_ERROR_OUT_OF_MEMORY; } rv = parsePredicates(step, aLexer, aContext); NS_ENSURE_SUCCESS(rv, rv); aPattern = step.forget(); return NS_OK; }
nsresult txExprParser::createExpr(txExprLexer& lexer, txIParseContext* aContext, Expr** aResult) { *aResult = nullptr; nsresult rv = NS_OK; bool done = false; nsAutoPtr<Expr> 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<Token*>(ops.peek()))) { // can't use expr as argument due to order of evaluation nsAutoPtr<Expr> left(static_cast<Expr*>(exprs.pop())); nsAutoPtr<Expr> right(expr); rv = createBinaryExpr(left, right, static_cast<Token*>(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<Expr> left(static_cast<Expr*>(exprs.pop())); nsAutoPtr<Expr> right(expr); rv = createBinaryExpr(left, right, static_cast<Token*>(ops.pop()), getter_Transfers(expr)); } // clean up on error while (!exprs.isEmpty()) { delete static_cast<Expr*>(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> 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<nsIAtom> 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> 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; }
/** * 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> 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<RootExpr*>(expr.get())->setSerialize(false); #endif } // We have a PathExpr containing several steps nsAutoPtr<PathExpr> 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; }
nsresult txExprParser::createLocationStep(txExprLexer& lexer, txIParseContext* aContext, Expr** aExpr) { *aExpr = nullptr; //-- child axis is default LocationStep::LocationStepType axisIdentifier = LocationStep::CHILD_AXIS; nsAutoPtr<txNodeTest> nodeTest; //-- get Axis Identifier or AbbreviatedStep, if present Token* tok = lexer.peek(); switch (tok->mType) { case Token::AXIS_IDENTIFIER: { //-- eat token lexer.nextToken(); nsCOMPtr<nsIAtom> axis = do_GetAtom(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<nsIAtom> 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<uint16_t>(txXPathNodeType::ATTRIBUTE_NODE) : static_cast<uint16_t>(txXPathNodeType::ELEMENT_NODE)); } else { rv = createNodeTypeTest(lexer, getter_Transfers(nodeTest)); NS_ENSURE_SUCCESS(rv, rv); } } nsAutoPtr<LocationStep> 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; }