/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * 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. * * The Initial Developer of the Original Code is The MITRE Corporation. * Portions created by MITRE are Copyright (C) 1999 The MITRE Corporation. * * Portions created by Keith Visco as a Non MITRE employee, * (C) 1999 Keith Visco. All Rights Reserved. * * Contributor(s): * Keith Visco, kvisco@ziplink.net * -- original author. * * Olivier Gerardin, ogerardin@vo.lu * -- added support for number function calls * -- fixed a bug in CreateExpr (@xxx=/yyy was parsed as @xxx=@xxx/yyy) * * Marina Mechtcheriakova * -- added support for lang() * -- fixed bug in ::parsePredicates, * made sure we continue looking for more predicates. * */ /** * ExprParser * This class is used to parse XSL Expressions * @see ExprLexer **/ #include "ExprParser.h" #include "ExprLexer.h" #include "FunctionLib.h" #include "txStack.h" #include "txAtoms.h" #include "txIXPathContext.h" #include "txStringUtils.h" /** * Creates an Attribute Value Template using the given value * This should move to XSLProcessor class **/ AttributeValueTemplate* ExprParser::createAttributeValueTemplate (const nsAFlatString& attValue, txIParseContext* aContext) { AttributeValueTemplate* avt = new AttributeValueTemplate(); if (!avt) { // XXX ErrorReport: out of memory return 0; } if (attValue.IsEmpty()) return avt; PRUint32 size = attValue.Length(); PRUint32 cc = 0; PRUnichar nextCh; PRUnichar ch; nsAutoString buffer; MBool inExpr = MB_FALSE; MBool inLiteral = MB_FALSE; PRUnichar endLiteral = 0; nextCh = attValue.CharAt(cc); while (cc++ < size) { ch = nextCh; nextCh = cc != size ? attValue.CharAt(cc) : 0; // if in literal just add ch to buffer if (inLiteral && (ch != endLiteral)) { buffer.Append(ch); continue; } switch ( ch ) { case '\'' : case '"' : buffer.Append(ch); if (inLiteral) inLiteral = MB_FALSE; else if (inExpr) { inLiteral = MB_TRUE; endLiteral = ch; } break; case '{' : if (!inExpr) { // Ignore case where we find two { if (nextCh == ch) { buffer.Append(ch); //-- append '{' cc++; nextCh = cc != size ? attValue.CharAt(cc) : 0; } else { if (!buffer.IsEmpty()) { Expr* strExpr = new StringExpr(buffer); if (!strExpr) { // XXX ErrorReport: out of memory delete avt; return 0; } avt->addExpr(strExpr); } buffer.Truncate(); inExpr = MB_TRUE; } } else buffer.Append(ch); //-- simply append '{' break; case '}': if (inExpr) { inExpr = MB_FALSE; ExprLexer lexer(buffer); Expr* expr = createExpr(lexer, aContext); if (!expr) { delete avt; return 0; } avt->addExpr(expr); buffer.Truncate(); } else if (nextCh == ch) { buffer.Append(ch); cc++; nextCh = cc != size ? attValue.CharAt(cc) : 0; } else { //XXX ErrorReport: unmatched '}' found delete avt; return 0; } break; default: buffer.Append(ch); break; } } if (inExpr) { //XXX ErrorReport: ending '}' missing delete avt; return 0; } if (!buffer.IsEmpty()) { Expr* strExpr = new StringExpr(buffer); if (!strExpr) { // XXX ErrorReport: out of memory delete avt; return 0; } avt->addExpr(strExpr); } return avt; } //-- createAttributeValueTemplate Expr* ExprParser::createExpr(const nsAFlatString& aExpression, txIParseContext* aContext) { ExprLexer lexer(aExpression); Expr* expr = createExpr(lexer, aContext); return expr; } //-- createExpr //--------------------/ //- Private Methods -/ //-------------------/ /** * Creates a binary Expr for the given operator **/ Expr* ExprParser::createBinaryExpr (Expr* left, Expr* right, Token* op) { if (!op) return 0; switch (op->type) { //-- additive ops case Token::ADDITION_OP : return new AdditiveExpr(left, right, AdditiveExpr::ADDITION); case Token::SUBTRACTION_OP: return new AdditiveExpr(left, right, AdditiveExpr::SUBTRACTION); //-- case boolean ops case Token::AND_OP: return new BooleanExpr(left, right, BooleanExpr::AND); case Token::OR_OP: return new BooleanExpr(left, right, BooleanExpr::OR); //-- equality ops case Token::EQUAL_OP : return new RelationalExpr(left, right, RelationalExpr::EQUAL); case Token::NOT_EQUAL_OP : return new RelationalExpr(left, right, RelationalExpr::NOT_EQUAL); //-- relational ops case Token::LESS_THAN_OP: return new RelationalExpr(left, right, RelationalExpr::LESS_THAN); case Token::GREATER_THAN_OP: return new RelationalExpr(left, right, RelationalExpr::GREATER_THAN); case Token::LESS_OR_EQUAL_OP: return new RelationalExpr(left, right, RelationalExpr::LESS_OR_EQUAL); case Token::GREATER_OR_EQUAL_OP: return new RelationalExpr(left, right, RelationalExpr::GREATER_OR_EQUAL); //-- multiplicative ops case Token::DIVIDE_OP : return new MultiplicativeExpr(left, right, MultiplicativeExpr::DIVIDE); case Token::MODULUS_OP : return new MultiplicativeExpr(left, right, MultiplicativeExpr::MODULUS); case Token::MULTIPLY_OP : return new MultiplicativeExpr(left, right, MultiplicativeExpr::MULTIPLY); default: break; } return 0; } //-- createBinaryExpr Expr* ExprParser::createExpr(ExprLexer& lexer, txIParseContext* aContext) { MBool done = MB_FALSE; Expr* expr = 0; txStack exprs; txStack ops; while (!done) { MBool unary = MB_FALSE; while (lexer.peek()->type == Token::SUBTRACTION_OP) { unary = !unary; lexer.nextToken(); } expr = createUnionExpr(lexer, aContext); if (!expr) break; if (unary) { Expr* uExpr = new UnaryExpr(expr); if (!uExpr) { // XXX ErrorReport: out of memory delete expr; return 0; } expr = uExpr; } Token* tok = lexer.nextToken(); switch (tok->type) { case Token::ADDITION_OP: case Token::DIVIDE_OP: //-- boolean ops case Token::AND_OP : case Token::OR_OP : //-- equality ops case Token::EQUAL_OP: case Token::NOT_EQUAL_OP: //-- relational ops case Token::LESS_THAN_OP: case Token::GREATER_THAN_OP: case Token::LESS_OR_EQUAL_OP: case Token::GREATER_OR_EQUAL_OP: //-- multiplicative ops case Token::MODULUS_OP: case Token::MULTIPLY_OP: case Token::SUBTRACTION_OP: { while (!exprs.isEmpty() && precedenceLevel(tok->type) <= precedenceLevel(((Token*)ops.peek())->type)) { expr = createBinaryExpr((Expr*)exprs.pop(), expr, (Token*)ops.pop()); } exprs.push(expr); ops.push(tok); break; } default: lexer.pushBack(); done = MB_TRUE; break; } } // make sure expr != 0 if (!expr) { while (!exprs.isEmpty()) { delete (Expr*)exprs.pop(); } return 0; } while (!exprs.isEmpty()) { expr = createBinaryExpr((Expr*)exprs.pop(), expr, (Token*)ops.pop()); } return expr; } //-- createExpr Expr* ExprParser::createFilterExpr(ExprLexer& lexer, txIParseContext* aContext) { Token* tok = lexer.nextToken(); Expr* expr = 0; switch (tok->type) { case Token::FUNCTION_NAME : lexer.pushBack(); expr = createFunctionCall(lexer, aContext); break; case Token::VAR_REFERENCE : { nsCOMPtr prefix, lName; PRInt32 nspace; nsresult rv = resolveQName(tok->value, getter_AddRefs(prefix), aContext, getter_AddRefs(lName), nspace); if (NS_FAILED(rv)) { // XXX error report namespace resolve failed return 0; } expr = new VariableRefExpr(prefix, lName, nspace); } break; case Token::L_PAREN: expr = createExpr(lexer, aContext); if (!expr) return 0; if (lexer.nextToken()->type != Token::R_PAREN) { lexer.pushBack(); //XXX ErrorReport: right parenthesis expected delete expr; return 0; } break; case Token::LITERAL : expr = new StringExpr(tok->value); break; case Token::NUMBER: { expr = new NumberExpr(Double::toDouble(tok->value)); break; } default: // this should never ever happen. lexer.pushBack(); //XXX ErrorReport: error in parser, please report on bugzilla.mozilla.org return 0; break; } if (!expr) { // XXX ErrorReport: out of memory return 0; } if (lexer.peek()->type == Token::L_BRACKET) { FilterExpr* filterExpr = new FilterExpr(expr); if (!filterExpr) { // XXX ErrorReport: out of memory delete expr; return 0; } //-- handle predicates if (!parsePredicates(filterExpr, lexer, aContext)) { delete filterExpr; return 0; } expr = filterExpr; } return expr; } //-- createFilterExpr Expr* ExprParser::createFunctionCall(ExprLexer& lexer, txIParseContext* aContext) { FunctionCall* fnCall = 0; Token* tok = lexer.nextToken(); if (tok->type != Token::FUNCTION_NAME) { //XXX ErrorReport: error in parser, please report on bugzilla.mozilla.org return 0; } //-- compare function names //-- * we should hash these names for speed nsresult rv = NS_OK; if (TX_StringEqualsAtom(tok->value, txXPathAtoms::boolean)) { fnCall = new BooleanFunctionCall(BooleanFunctionCall::TX_BOOLEAN); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::concat)) { fnCall = new StringFunctionCall(StringFunctionCall::CONCAT); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::contains)) { fnCall = new StringFunctionCall(StringFunctionCall::CONTAINS); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::count)) { fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::COUNT); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::_false)) { fnCall = new BooleanFunctionCall(BooleanFunctionCall::TX_FALSE); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::id)) { fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::ID); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::lang)) { fnCall = new BooleanFunctionCall(BooleanFunctionCall::TX_LANG); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::last)) { fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::LAST); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::localName)) { fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::LOCAL_NAME); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::name)) { fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::NAME); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::namespaceUri)) { fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::NAMESPACE_URI); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::normalizeSpace)) { fnCall = new StringFunctionCall(StringFunctionCall::NORMALIZE_SPACE); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::_not)) { fnCall = new BooleanFunctionCall(BooleanFunctionCall::TX_NOT); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::position)) { fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::POSITION); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::startsWith)) { fnCall = new StringFunctionCall(StringFunctionCall::STARTS_WITH); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::string)) { fnCall = new StringFunctionCall(StringFunctionCall::STRING); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::stringLength)) { fnCall = new StringFunctionCall(StringFunctionCall::STRING_LENGTH); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::substring)) { fnCall = new StringFunctionCall(StringFunctionCall::SUBSTRING); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::substringAfter)) { fnCall = new StringFunctionCall(StringFunctionCall::SUBSTRING_AFTER); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::substringBefore)) { fnCall = new StringFunctionCall(StringFunctionCall::SUBSTRING_BEFORE); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::sum)) { fnCall = new NumberFunctionCall(NumberFunctionCall::SUM); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::translate)) { fnCall = new StringFunctionCall(StringFunctionCall::TRANSLATE); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::_true)) { fnCall = new BooleanFunctionCall(BooleanFunctionCall::TX_TRUE); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::number)) { fnCall = new NumberFunctionCall(NumberFunctionCall::NUMBER); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::round)) { fnCall = new NumberFunctionCall(NumberFunctionCall::ROUND); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::ceiling)) { fnCall = new NumberFunctionCall(NumberFunctionCall::CEILING); } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::floor)) { fnCall = new NumberFunctionCall(NumberFunctionCall::FLOOR); } else { nsCOMPtr prefix, lName; PRInt32 namespaceID; rv = resolveQName(tok->value, getter_AddRefs(prefix), aContext, getter_AddRefs(lName), namespaceID); if (NS_FAILED(rv)) { // XXX error report namespace resolve failed return 0; } rv = aContext->resolveFunctionCall(lName, namespaceID, fnCall); // XXX this should be removed once we don't return // NS_ERROR_NOT_IMPLEMENTED for unparsed-entity-uri(). As should the // code in parseParameters that deals with fnCall = 0. // Bug 65981 if (rv == NS_ERROR_NOT_IMPLEMENTED) { NS_ASSERTION(!fnCall, "Now is it implemented or not?"); if (!parseParameters(0, lexer, aContext)) { return 0; } return new StringExpr(tok->value + NS_LITERAL_STRING(" not implemented.")); } if (NS_FAILED(rv)) { return 0; } } // check that internal functions got created properly if (!fnCall) { // XXX ErrorReport: out of memory return 0; } //-- handle parametes if (!parseParameters(fnCall, lexer, aContext)) { delete fnCall; return 0; } return fnCall; } //-- createFunctionCall LocationStep* ExprParser::createLocationStep(ExprLexer& lexer, txIParseContext* aContext) { //-- child axis is default LocationStep::LocationStepType axisIdentifier = LocationStep::CHILD_AXIS; txNodeTest* nodeTest = 0; //-- get Axis Identifier or AbbreviatedStep, if present Token* tok = lexer.peek(); switch (tok->type) { case Token::AXIS_IDENTIFIER: { //-- eat token lexer.nextToken(); //-- should switch to a hash here for speed if necessary if (TX_StringEqualsAtom(tok->value, txXPathAtoms::ancestor)) { axisIdentifier = LocationStep::ANCESTOR_AXIS; } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::ancestorOrSelf)) { axisIdentifier = LocationStep::ANCESTOR_OR_SELF_AXIS; } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::attribute)) { axisIdentifier = LocationStep::ATTRIBUTE_AXIS; } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::child)) { axisIdentifier = LocationStep::CHILD_AXIS; } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::descendant)) { axisIdentifier = LocationStep::DESCENDANT_AXIS; } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::descendantOrSelf)) { axisIdentifier = LocationStep::DESCENDANT_OR_SELF_AXIS; } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::following)) { axisIdentifier = LocationStep::FOLLOWING_AXIS; } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::followingSibling)) { axisIdentifier = LocationStep::FOLLOWING_SIBLING_AXIS; } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::_namespace)) { axisIdentifier = LocationStep::NAMESPACE_AXIS; } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::parent)) { axisIdentifier = LocationStep::PARENT_AXIS; } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::preceding)) { axisIdentifier = LocationStep::PRECEDING_AXIS; } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::precedingSibling)) { axisIdentifier = LocationStep::PRECEDING_SIBLING_AXIS; } else if (TX_StringEqualsAtom(tok->value, txXPathAtoms::self)) { axisIdentifier = LocationStep::SELF_AXIS; } else { //XXX ErrorReport: unknow axis return 0; } 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); if (!nodeTest) { //XXX out of memory return 0; } break; case Token::SELF_NODE : //-- eat token lexer.nextToken(); axisIdentifier = LocationStep::SELF_AXIS; nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); if (!nodeTest) { //XXX out of memory return 0; } break; default: break; } //-- get NodeTest unless an AbbreviatedStep was found if (!nodeTest) { tok = lexer.nextToken(); switch (tok->type) { case Token::CNAME : { // resolve QName nsCOMPtr prefix, lName; PRInt32 nspace; nsresult rv = resolveQName(tok->value, getter_AddRefs(prefix), aContext, getter_AddRefs(lName), nspace); if (NS_FAILED(rv)) { // XXX error report namespace resolve failed return 0; } switch (axisIdentifier) { case LocationStep::ATTRIBUTE_AXIS: nodeTest = new txNameTest(prefix, lName, nspace, Node::ATTRIBUTE_NODE); break; default: nodeTest = new txNameTest(prefix, lName, nspace, Node::ELEMENT_NODE); break; } } if (!nodeTest) { //XXX ErrorReport: out of memory return 0; } break; default: lexer.pushBack(); nodeTest = createNodeTypeTest(lexer); if (!nodeTest) { return 0; } } } LocationStep* lstep = new LocationStep(nodeTest, axisIdentifier); if (!lstep) { //XXX out of memory delete nodeTest; return 0; } //-- handle predicates if (!parsePredicates(lstep, lexer, aContext)) { delete lstep; return 0; } return lstep; } //-- createLocationPath /** * This method only handles comment(), text(), processing-instructing() and node() * **/ txNodeTypeTest* ExprParser::createNodeTypeTest(ExprLexer& lexer) { txNodeTypeTest* nodeTest = 0; Token* nodeTok = lexer.nextToken(); switch (nodeTok->type) { case Token::COMMENT: nodeTest = new txNodeTypeTest(txNodeTypeTest::COMMENT_TYPE); break; case Token::NODE : nodeTest = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); break; case Token::PROC_INST : nodeTest = new txNodeTypeTest(txNodeTypeTest::PI_TYPE); break; case Token::TEXT : nodeTest = new txNodeTypeTest(txNodeTypeTest::TEXT_TYPE); break; default: lexer.pushBack(); // XXX ErrorReport: unexpected token return 0; } if (!nodeTest) { //XXX out of memory return 0; } if (lexer.nextToken()->type != Token::L_PAREN) { lexer.pushBack(); //XXX ErrorReport: left parenthesis expected delete nodeTest; return 0; } if (nodeTok->type == Token::PROC_INST && lexer.peek()->type == Token::LITERAL) { Token* tok = lexer.nextToken(); nodeTest->setNodeName(tok->value); } if (lexer.nextToken()->type != Token::R_PAREN) { lexer.pushBack(); //XXX ErrorReport: right parenthesis expected (or literal for pi) delete nodeTest; return 0; } return nodeTest; } //-- createNodeTypeTest /** * Creates a PathExpr using the given ExprLexer * @param lexer the ExprLexer for retrieving Tokens **/ Expr* ExprParser::createPathExpr(ExprLexer& lexer, txIParseContext* aContext) { Expr* expr = 0; Token* tok = lexer.peek(); // is this a root expression? if (tok->type == Token::PARENT_OP) { lexer.nextToken(); if (!isLocationStepToken(lexer.peek())) return new RootExpr(MB_TRUE); lexer.pushBack(); } // parse first step (possibly a FilterExpr) if (tok->type != Token::PARENT_OP && tok->type != Token::ANCESTOR_OP) { if (isFilterExprToken(tok)) { expr = createFilterExpr(lexer, aContext); } else expr = createLocationStep(lexer, aContext); if (!expr) return 0; // is this a singlestep path expression? tok = lexer.peek(); if (tok->type != Token::PARENT_OP && tok->type != Token::ANCESTOR_OP) return expr; } else { expr = new RootExpr(MB_FALSE); if (!expr) { // XXX ErrorReport: out of memory return 0; } } // We have a PathExpr containing several steps PathExpr* pathExpr = new PathExpr(); if (!pathExpr) { // XXX ErrorReport: out of memory delete expr; return 0; } pathExpr->addExpr(expr, PathExpr::RELATIVE_OP); // this is ugly while (1) { PathExpr::PathOperator pathOp; tok = lexer.nextToken(); switch (tok->type) { case Token::ANCESTOR_OP : pathOp = PathExpr::DESCENDANT_OP; break; case Token::PARENT_OP : pathOp = PathExpr::RELATIVE_OP; break; default: lexer.pushBack(); return pathExpr; } expr = createLocationStep(lexer, aContext); if (!expr) { delete pathExpr; return 0; } pathExpr->addExpr(expr, pathOp); } return pathExpr; } //-- createPathExpr /** * Creates a PathExpr using the given ExprLexer * XXX temporary use as top of XSLT Pattern * @param lexer the ExprLexer for retrieving Tokens **/ Expr* ExprParser::createUnionExpr(ExprLexer& lexer, txIParseContext* aContext) { Expr* expr = createPathExpr(lexer, aContext); if (!expr) return 0; if (lexer.peek()->type != Token::UNION_OP) return expr; UnionExpr* unionExpr = new UnionExpr(); if (!unionExpr) { // XXX ErrorReport: out of memory delete expr; return 0; } unionExpr->addExpr(expr); while (lexer.peek()->type == Token::UNION_OP) { lexer.nextToken(); //-- eat token expr = createPathExpr(lexer, aContext); if (!expr) { delete unionExpr; return 0; } unionExpr->addExpr(expr); } return unionExpr; } //-- createUnionExpr MBool ExprParser::isFilterExprToken(Token* token) { switch (token->type) { case Token::LITERAL: case Token::NUMBER: case Token::FUNCTION_NAME: case Token::VAR_REFERENCE: case Token::L_PAREN: // grouping expr return MB_TRUE; default: return MB_FALSE; } } //-- isFilterExprToken MBool ExprParser::isLocationStepToken(Token* token) { switch (token->type) { case Token::AXIS_IDENTIFIER : case Token::AT_SIGN : case Token::PARENT_NODE : case Token::SELF_NODE : return MB_TRUE; default: return isNodeTypeToken(token); } } //-- isLocationStepToken MBool ExprParser::isNodeTypeToken(Token* token) { switch (token->type) { case Token::CNAME: case Token::COMMENT: case Token::NODE : case Token::PROC_INST : case Token::TEXT : return MB_TRUE; default: return MB_FALSE; } } //-- isNodeTypeToken /** * 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 ExprLexer to use for parsing tokens * @return 0 if successful, or a String pointer to the error message **/ MBool ExprParser::parsePredicates(PredicateList* predicateList, ExprLexer& lexer, txIParseContext* aContext) { while (lexer.peek()->type == Token::L_BRACKET) { //-- eat Token lexer.nextToken(); Expr* expr = createExpr(lexer, aContext); if (!expr) return MB_FALSE; predicateList->add(expr); if (lexer.nextToken()->type != Token::R_BRACKET) { lexer.pushBack(); //XXX ErrorReport: right bracket expected return MB_FALSE; } } return MB_TRUE; } //-- parsePredicates /** * 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 ExprLexer to use for parsing tokens * @return MB_TRUE if successful, or a MB_FALSE otherwise **/ MBool ExprParser::parseParameters(FunctionCall* fnCall, ExprLexer& lexer, txIParseContext* aContext) { if (lexer.nextToken()->type != Token::L_PAREN) { lexer.pushBack(); //XXX ErrorReport: left parenthesis expected return MB_FALSE; } if (lexer.peek()->type == Token::R_PAREN) { lexer.nextToken(); return MB_TRUE; } while (1) { Expr* expr = createExpr(lexer, aContext); if (!expr) return MB_FALSE; if (fnCall) fnCall->addParam(expr); else delete expr; switch (lexer.nextToken()->type) { case Token::R_PAREN : return MB_TRUE; case Token::COMMA: //-- param separator break; default: lexer.pushBack(); //XXX ErrorReport: right parenthesis or comma expected return MB_FALSE; } } return MB_FALSE; } //-- parseParameters short ExprParser::precedenceLevel(short tokenType) { switch (tokenType) { 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 ExprParser::resolveQName(const nsAString& aQName, nsIAtom** aPrefix, txIParseContext* aContext, nsIAtom** aLocalName, PRInt32& aNamespace) { aNamespace = kNameSpaceID_None; PRInt32 idx = aQName.FindChar(':'); if (idx > 0) { *aPrefix = NS_NewAtom(Substring(aQName, 0, (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; *aLocalName = NS_NewAtom(aQName); if (!*aLocalName) { return NS_ERROR_OUT_OF_MEMORY; } return NS_OK; }