Another attempt at solving this issue

There was already a patch to fix this issue, but it had some problems and was closed by the author after a while.
This commit is contained in:
Mike Lischke 2019-10-11 14:47:39 +02:00
parent 9723e4b9c9
commit 4d649fbf71
2 changed files with 27 additions and 19 deletions

View File

@ -28,8 +28,8 @@ XPath::XPath(Parser *parser, const std::string &path) {
_elements = split(path);
}
std::vector<XPathElement> XPath::split(const std::string &path) {
ANTLRFileStream in(path);
std::vector<std::unique_ptr<XPathElement>> XPath::split(const std::string &path) {
ANTLRInputStream in(path);
XPathLexer lexer(&in);
lexer.removeErrorListeners();
XPathLexerErrorListener listener;
@ -44,7 +44,7 @@ std::vector<XPathElement> XPath::split(const std::string &path) {
}
std::vector<Token *> tokens = tokenStream.getTokens();
std::vector<XPathElement> elements;
std::vector<std::unique_ptr<XPathElement>> elements;
size_t n = tokens.size();
size_t i = 0;
bool done = false;
@ -62,9 +62,9 @@ std::vector<XPathElement> XPath::split(const std::string &path) {
i++;
next = tokens[i];
}
XPathElement pathElement = getXPathElement(next, anywhere);
pathElement.setInvert(invert);
elements.push_back(pathElement);
std::unique_ptr<XPathElement> pathElement = getXPathElement(next, anywhere);
pathElement->setInvert(invert);
elements.push_back(std::move(pathElement));
i++;
break;
@ -81,25 +81,26 @@ std::vector<XPathElement> XPath::split(const std::string &path) {
break;
default :
throw IllegalArgumentException("Unknow path element " + el->toString());
throw IllegalArgumentException("Unknown path element " + el->toString());
}
}
return elements;
}
XPathElement XPath::getXPathElement(Token *wordToken, bool anywhere) {
std::unique_ptr<XPathElement> XPath::getXPathElement(Token *wordToken, bool anywhere) {
if (wordToken->getType() == Token::EOF) {
throw IllegalArgumentException("Missing path element at end of path");
}
std::string word = wordToken->getText();
size_t ttype = _parser->getTokenType(word);
ssize_t ruleIndex = _parser->getRuleIndex(word);
switch (wordToken->getType()) {
case XPathLexer::WILDCARD :
if (anywhere)
return XPathWildcardAnywhereElement();
return XPathWildcardElement();
return std::unique_ptr<XPathWildcardAnywhereElement>(new XPathWildcardAnywhereElement());
return std::unique_ptr<XPathWildcardElement>(new XPathWildcardElement());
case XPathLexer::TOKEN_REF:
case XPathLexer::STRING :
@ -107,21 +108,26 @@ XPathElement XPath::getXPathElement(Token *wordToken, bool anywhere) {
throw IllegalArgumentException(word + " at index " + std::to_string(wordToken->getStartIndex()) + " isn't a valid token name");
}
if (anywhere)
return XPathTokenAnywhereElement(word, (int)ttype);
return XPathTokenElement(word, (int)ttype);
return std::unique_ptr<XPathTokenAnywhereElement>(new XPathTokenAnywhereElement(word, (int)ttype));
return std::unique_ptr<XPathTokenElement>(new XPathTokenElement(word, (int)ttype));
default :
if (ruleIndex == -1) {
throw IllegalArgumentException(word + " at index " + std::to_string(wordToken->getStartIndex()) + " isn't a valid rule name");
}
if (anywhere)
return XPathRuleAnywhereElement(word, (int)ruleIndex);
return XPathRuleElement(word, (int)ruleIndex);
return std::unique_ptr<XPathRuleAnywhereElement>(new XPathRuleAnywhereElement(word, (int)ruleIndex));
return std::unique_ptr<XPathRuleElement>(new XPathRuleElement(word, (int)ruleIndex));
}
}
static ParserRuleContext dummyRoot;
std::vector<ParseTree *> XPath::findAll(ParseTree *tree, std::string const& xpath, Parser *parser) {
XPath p(parser, xpath);
return p.evaluate(tree);
}
std::vector<ParseTree *> XPath::evaluate(ParseTree *t) {
dummyRoot.children = { t }; // don't set t's parent.
@ -135,7 +141,7 @@ std::vector<ParseTree *> XPath::evaluate(ParseTree *t) {
// only try to match next element if it has children
// e.g., //func/*/stat might have a token node for which
// we can't go looking for stat nodes.
auto matching = _elements[i].evaluate(node);
auto matching = _elements[i]->evaluate(node);
next.insert(next.end(), matching.begin(), matching.end());
}
}

View File

@ -61,8 +61,10 @@ namespace xpath {
XPath(Parser *parser, const std::string &path);
virtual ~XPath() {}
// TO_DO: check for invalid token/rule names, bad syntax
virtual std::vector<XPathElement> split(const std::string &path);
// TODO: check for invalid token/rule names, bad syntax
virtual std::vector<std::unique_ptr<XPathElement>> split(const std::string &path);
static std::vector<ParseTree *> findAll(ParseTree *tree, std::string const& xpath, Parser *parser);
/// Return a list of all nodes starting at {@code t} as root that satisfy the
/// path. The root {@code /} is relative to the node passed to
@ -71,13 +73,13 @@ namespace xpath {
protected:
std::string _path;
std::vector<XPathElement> _elements;
std::vector<std::unique_ptr<XPathElement>> _elements;
Parser *_parser;
/// Convert word like {@code *} or {@code ID} or {@code expr} to a path
/// element. {@code anywhere} is {@code true} if {@code //} precedes the
/// word.
virtual XPathElement getXPathElement(Token *wordToken, bool anywhere);
virtual std::unique_ptr<XPathElement> getXPathElement(Token *wordToken, bool anywhere);
};
} // namespace xpath