First commit

This commit is contained in:
GotPPay
2018-02-23 00:40:26 +01:00
commit f9a08ea8da
333 changed files with 50313 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "tree/pattern/Chunk.h"
antlr4::tree::pattern::Chunk::~Chunk() {
}

View File

@@ -0,0 +1,44 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "antlr4-common.h"
namespace antlr4 {
namespace tree {
namespace pattern {
/// <summary>
/// A chunk is either a token tag, a rule tag, or a span of literal text within a
/// tree pattern.
/// <p/>
/// The method <seealso cref="ParseTreePatternMatcher#split(String)"/> returns a list of
/// chunks in preparation for creating a token stream by
/// <seealso cref="ParseTreePatternMatcher#tokenize(String)"/>. From there, we get a parse
/// tree from with <seealso cref="ParseTreePatternMatcher#compile(String, int)"/>. These
/// chunks are converted to <seealso cref="RuleTagToken"/>, <seealso cref="TokenTagToken"/>, or the
/// regular tokens of the text surrounding the tags.
/// </summary>
class ANTLR4CPP_PUBLIC Chunk {
public:
Chunk() = default;
Chunk(Chunk const&) = default;
virtual ~Chunk();
Chunk& operator=(Chunk const&) = default;
/// This method returns a text representation of the tag chunk. Labeled tags
/// are returned in the form {@code label:tag}, and unlabeled tags are
/// returned as just the tag name.
virtual std::string toString() {
std::string str;
return str;
}
};
} // namespace pattern
} // namespace tree
} // namespace antlr4

View File

@@ -0,0 +1,69 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "Exceptions.h"
#include "tree/pattern/ParseTreeMatch.h"
using namespace antlr4::tree;
using namespace antlr4::tree::pattern;
ParseTreeMatch::ParseTreeMatch(ParseTree *tree, const ParseTreePattern &pattern,
const std::map<std::string, std::vector<ParseTree *>> &labels,
ParseTree *mismatchedNode)
: _tree(tree), _pattern(pattern), _labels(labels), _mismatchedNode(mismatchedNode) {
if (tree == nullptr) {
throw IllegalArgumentException("tree cannot be nul");
}
}
ParseTreeMatch::~ParseTreeMatch() {
}
ParseTree* ParseTreeMatch::get(const std::string &label) {
auto iterator = _labels.find(label);
if (iterator == _labels.end() || iterator->second.empty()) {
return nullptr;
}
return iterator->second.back(); // return last if multiple
}
std::vector<ParseTree *> ParseTreeMatch::getAll(const std::string &label) {
auto iterator = _labels.find(label);
if (iterator == _labels.end()) {
return {};
}
return iterator->second;
}
std::map<std::string, std::vector<ParseTree *>>& ParseTreeMatch::getLabels() {
return _labels;
}
ParseTree *ParseTreeMatch::getMismatchedNode() {
return _mismatchedNode;
}
bool ParseTreeMatch::succeeded() {
return _mismatchedNode == nullptr;
}
const ParseTreePattern& ParseTreeMatch::getPattern() {
return _pattern;
}
ParseTree * ParseTreeMatch::getTree() {
return _tree;
}
std::string ParseTreeMatch::toString() {
if (succeeded()) {
return "Match succeeded; found " + std::to_string(_labels.size()) + " labels";
} else {
return "Match failed; found " + std::to_string(_labels.size()) + " labels";
}
}

View File

@@ -0,0 +1,133 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "antlr4-common.h"
namespace antlr4 {
namespace tree {
namespace pattern {
/// Represents the result of matching a ParseTree against a tree pattern.
class ANTLR4CPP_PUBLIC ParseTreeMatch {
private:
/// This is the backing field for getTree().
ParseTree *_tree;
/// This is the backing field for getPattern().
const ParseTreePattern &_pattern;
/// This is the backing field for getLabels().
std::map<std::string, std::vector<ParseTree *>> _labels;
/// This is the backing field for getMismatchedNode().
ParseTree *_mismatchedNode;
public:
/// <summary>
/// Constructs a new instance of <seealso cref="ParseTreeMatch"/> from the specified
/// parse tree and pattern.
/// </summary>
/// <param name="tree"> The parse tree to match against the pattern. </param>
/// <param name="pattern"> The parse tree pattern. </param>
/// <param name="labels"> A mapping from label names to collections of
/// <seealso cref="ParseTree"/> objects located by the tree pattern matching process. </param>
/// <param name="mismatchedNode"> The first node which failed to match the tree
/// pattern during the matching process.
/// </param>
/// <exception cref="IllegalArgumentException"> if {@code tree} is {@code null} </exception>
/// <exception cref="IllegalArgumentException"> if {@code pattern} is {@code null} </exception>
/// <exception cref="IllegalArgumentException"> if {@code labels} is {@code null} </exception>
ParseTreeMatch(ParseTree *tree, ParseTreePattern const& pattern,
const std::map<std::string, std::vector<ParseTree *>> &labels, ParseTree *mismatchedNode);
ParseTreeMatch(ParseTreeMatch const&) = default;
virtual ~ParseTreeMatch();
ParseTreeMatch& operator=(ParseTreeMatch const&) = default;
/// <summary>
/// Get the last node associated with a specific {@code label}.
/// <p/>
/// For example, for pattern {@code <id:ID>}, {@code get("id")} returns the
/// node matched for that {@code ID}. If more than one node
/// matched the specified label, only the last is returned. If there is
/// no node associated with the label, this returns {@code null}.
/// <p/>
/// Pattern tags like {@code <ID>} and {@code <expr>} without labels are
/// considered to be labeled with {@code ID} and {@code expr}, respectively.
/// </summary>
/// <param name="labe"> The label to check.
/// </param>
/// <returns> The last <seealso cref="ParseTree"/> to match a tag with the specified
/// label, or {@code null} if no parse tree matched a tag with the label. </returns>
virtual ParseTree* get(const std::string &label);
/// <summary>
/// Return all nodes matching a rule or token tag with the specified label.
/// <p/>
/// If the {@code label} is the name of a parser rule or token in the
/// grammar, the resulting list will contain both the parse trees matching
/// rule or tags explicitly labeled with the label and the complete set of
/// parse trees matching the labeled and unlabeled tags in the pattern for
/// the parser rule or token. For example, if {@code label} is {@code "foo"},
/// the result will contain <em>all</em> of the following.
///
/// <ul>
/// <li>Parse tree nodes matching tags of the form {@code <foo:anyRuleName>} and
/// {@code <foo:AnyTokenName>}.</li>
/// <li>Parse tree nodes matching tags of the form {@code <anyLabel:foo>}.</li>
/// <li>Parse tree nodes matching tags of the form {@code <foo>}.</li>
/// </ul>
/// </summary>
/// <param name="labe"> The label.
/// </param>
/// <returns> A collection of all <seealso cref="ParseTree"/> nodes matching tags with
/// the specified {@code label}. If no nodes matched the label, an empty list
/// is returned. </returns>
virtual std::vector<ParseTree *> getAll(const std::string &label);
/// <summary>
/// Return a mapping from label &rarr; [list of nodes].
/// <p/>
/// The map includes special entries corresponding to the names of rules and
/// tokens referenced in tags in the original pattern. For additional
/// information, see the description of <seealso cref="#getAll(String)"/>.
/// </summary>
/// <returns> A mapping from labels to parse tree nodes. If the parse tree
/// pattern did not contain any rule or token tags, this map will be empty. </returns>
virtual std::map<std::string, std::vector<ParseTree *>>& getLabels();
/// <summary>
/// Get the node at which we first detected a mismatch.
/// </summary>
/// <returns> the node at which we first detected a mismatch, or {@code null}
/// if the match was successful. </returns>
virtual ParseTree* getMismatchedNode();
/// <summary>
/// Gets a value indicating whether the match operation succeeded.
/// </summary>
/// <returns> {@code true} if the match operation succeeded; otherwise,
/// {@code false}. </returns>
virtual bool succeeded();
/// <summary>
/// Get the tree pattern we are matching against.
/// </summary>
/// <returns> The tree pattern we are matching against. </returns>
virtual const ParseTreePattern& getPattern();
/// <summary>
/// Get the parse tree we are trying to match to a pattern.
/// </summary>
/// <returns> The <seealso cref="ParseTree"/> we are trying to match to a pattern. </returns>
virtual ParseTree* getTree();
virtual std::string toString();
};
} // namespace pattern
} // namespace tree
} // namespace antlr4

View File

@@ -0,0 +1,64 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "tree/ParseTree.h"
#include "tree/pattern/ParseTreePatternMatcher.h"
#include "tree/pattern/ParseTreeMatch.h"
#include "tree/xpath/XPath.h"
#include "tree/xpath/XPathElement.h"
#include "tree/pattern/ParseTreePattern.h"
using namespace antlr4::tree;
using namespace antlr4::tree::pattern;
using namespace antlrcpp;
ParseTreePattern::ParseTreePattern(ParseTreePatternMatcher *matcher, const std::string &pattern, int patternRuleIndex_,
ParseTree *patternTree)
: patternRuleIndex(patternRuleIndex_), _pattern(pattern), _patternTree(patternTree), _matcher(matcher) {
}
ParseTreePattern::~ParseTreePattern() {
}
ParseTreeMatch ParseTreePattern::match(ParseTree *tree) {
return _matcher->match(tree, *this);
}
bool ParseTreePattern::matches(ParseTree *tree) {
return _matcher->match(tree, *this).succeeded();
}
std::vector<ParseTreeMatch> ParseTreePattern::findAll(ParseTree *tree, const std::string &xpath) {
xpath::XPath finder(_matcher->getParser(), xpath);
std::vector<ParseTree *> subtrees = finder.evaluate(tree);
std::vector<ParseTreeMatch> matches;
for (auto t : subtrees) {
ParseTreeMatch aMatch = match(t);
if (aMatch.succeeded()) {
matches.push_back(aMatch);
}
}
return matches;
}
ParseTreePatternMatcher *ParseTreePattern::getMatcher() const {
return _matcher;
}
std::string ParseTreePattern::getPattern() const {
return _pattern;
}
int ParseTreePattern::getPatternRuleIndex() const {
return patternRuleIndex;
}
ParseTree* ParseTreePattern::getPatternTree() const {
return _patternTree;
}

View File

@@ -0,0 +1,106 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "antlr4-common.h"
namespace antlr4 {
namespace tree {
namespace pattern {
/// <summary>
/// A pattern like {@code <ID> = <expr>;} converted to a <seealso cref="ParseTree"/> by
/// <seealso cref="ParseTreePatternMatcher#compile(String, int)"/>.
/// </summary>
class ANTLR4CPP_PUBLIC ParseTreePattern {
public:
/// <summary>
/// Construct a new instance of the <seealso cref="ParseTreePattern"/> class.
/// </summary>
/// <param name="matcher"> The <seealso cref="ParseTreePatternMatcher"/> which created this
/// tree pattern. </param>
/// <param name="pattern"> The tree pattern in concrete syntax form. </param>
/// <param name="patternRuleIndex"> The parser rule which serves as the root of the
/// tree pattern. </param>
/// <param name="patternTree"> The tree pattern in <seealso cref="ParseTree"/> form. </param>
ParseTreePattern(ParseTreePatternMatcher *matcher, const std::string &pattern, int patternRuleIndex,
ParseTree *patternTree);
ParseTreePattern(ParseTreePattern const&) = default;
virtual ~ParseTreePattern();
ParseTreePattern& operator=(ParseTreePattern const&) = default;
/// <summary>
/// Match a specific parse tree against this tree pattern.
/// </summary>
/// <param name="tree"> The parse tree to match against this tree pattern. </param>
/// <returns> A <seealso cref="ParseTreeMatch"/> object describing the result of the
/// match operation. The <seealso cref="ParseTreeMatch#succeeded()"/> method can be
/// used to determine whether or not the match was successful. </returns>
virtual ParseTreeMatch match(ParseTree *tree);
/// <summary>
/// Determine whether or not a parse tree matches this tree pattern.
/// </summary>
/// <param name="tree"> The parse tree to match against this tree pattern. </param>
/// <returns> {@code true} if {@code tree} is a match for the current tree
/// pattern; otherwise, {@code false}. </returns>
virtual bool matches(ParseTree *tree);
/// Find all nodes using XPath and then try to match those subtrees against
/// this tree pattern.
/// @param tree The ParseTree to match against this pattern.
/// @param xpath An expression matching the nodes
///
/// @returns A collection of ParseTreeMatch objects describing the
/// successful matches. Unsuccessful matches are omitted from the result,
/// regardless of the reason for the failure.
virtual std::vector<ParseTreeMatch> findAll(ParseTree *tree, const std::string &xpath);
/// <summary>
/// Get the <seealso cref="ParseTreePatternMatcher"/> which created this tree pattern.
/// </summary>
/// <returns> The <seealso cref="ParseTreePatternMatcher"/> which created this tree
/// pattern. </returns>
virtual ParseTreePatternMatcher *getMatcher() const;
/// <summary>
/// Get the tree pattern in concrete syntax form.
/// </summary>
/// <returns> The tree pattern in concrete syntax form. </returns>
virtual std::string getPattern() const;
/// <summary>
/// Get the parser rule which serves as the outermost rule for the tree
/// pattern.
/// </summary>
/// <returns> The parser rule which serves as the outermost rule for the tree
/// pattern. </returns>
virtual int getPatternRuleIndex() const;
/// <summary>
/// Get the tree pattern as a <seealso cref="ParseTree"/>. The rule and token tags from
/// the pattern are present in the parse tree as terminal nodes with a symbol
/// of type <seealso cref="RuleTagToken"/> or <seealso cref="TokenTagToken"/>.
/// </summary>
/// <returns> The tree pattern as a <seealso cref="ParseTree"/>. </returns>
virtual ParseTree* getPatternTree() const;
private:
const int patternRuleIndex;
/// This is the backing field for <seealso cref="#getPattern()"/>.
const std::string _pattern;
/// This is the backing field for <seealso cref="#getPatternTree()"/>.
ParseTree *_patternTree;
/// This is the backing field for <seealso cref="#getMatcher()"/>.
ParseTreePatternMatcher *const _matcher;
};
} // namespace pattern
} // namespace tree
} // namespace antlr4

View File

@@ -0,0 +1,371 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "tree/pattern/ParseTreePattern.h"
#include "tree/pattern/ParseTreeMatch.h"
#include "tree/TerminalNode.h"
#include "CommonTokenStream.h"
#include "ParserInterpreter.h"
#include "tree/pattern/TokenTagToken.h"
#include "ParserRuleContext.h"
#include "tree/pattern/RuleTagToken.h"
#include "tree/pattern/TagChunk.h"
#include "atn/ATN.h"
#include "Lexer.h"
#include "BailErrorStrategy.h"
#include "ListTokenSource.h"
#include "tree/pattern/TextChunk.h"
#include "ANTLRInputStream.h"
#include "support/Arrays.h"
#include "Exceptions.h"
#include "support/StringUtils.h"
#include "support/CPPUtils.h"
#include "tree/pattern/ParseTreePatternMatcher.h"
using namespace antlr4;
using namespace antlr4::tree;
using namespace antlr4::tree::pattern;
using namespace antlrcpp;
ParseTreePatternMatcher::CannotInvokeStartRule::CannotInvokeStartRule(const RuntimeException &e) : RuntimeException(e.what()) {
}
ParseTreePatternMatcher::CannotInvokeStartRule::~CannotInvokeStartRule() {
}
ParseTreePatternMatcher::StartRuleDoesNotConsumeFullPattern::~StartRuleDoesNotConsumeFullPattern() {
}
ParseTreePatternMatcher::ParseTreePatternMatcher(Lexer *lexer, Parser *parser) : _lexer(lexer), _parser(parser) {
InitializeInstanceFields();
}
ParseTreePatternMatcher::~ParseTreePatternMatcher() {
}
void ParseTreePatternMatcher::setDelimiters(const std::string &start, const std::string &stop, const std::string &escapeLeft) {
if (start.empty()) {
throw IllegalArgumentException("start cannot be null or empty");
}
if (stop.empty()) {
throw IllegalArgumentException("stop cannot be null or empty");
}
_start = start;
_stop = stop;
_escape = escapeLeft;
}
bool ParseTreePatternMatcher::matches(ParseTree *tree, const std::string &pattern, int patternRuleIndex) {
ParseTreePattern p = compile(pattern, patternRuleIndex);
return matches(tree, p);
}
bool ParseTreePatternMatcher::matches(ParseTree *tree, const ParseTreePattern &pattern) {
std::map<std::string, std::vector<ParseTree *>> labels;
ParseTree *mismatchedNode = matchImpl(tree, pattern.getPatternTree(), labels);
return mismatchedNode == nullptr;
}
ParseTreeMatch ParseTreePatternMatcher::match(ParseTree *tree, const std::string &pattern, int patternRuleIndex) {
ParseTreePattern p = compile(pattern, patternRuleIndex);
return match(tree, p);
}
ParseTreeMatch ParseTreePatternMatcher::match(ParseTree *tree, const ParseTreePattern &pattern) {
std::map<std::string, std::vector<ParseTree *>> labels;
tree::ParseTree *mismatchedNode = matchImpl(tree, pattern.getPatternTree(), labels);
return ParseTreeMatch(tree, pattern, labels, mismatchedNode);
}
ParseTreePattern ParseTreePatternMatcher::compile(const std::string &pattern, int patternRuleIndex) {
ListTokenSource tokenSrc(tokenize(pattern));
CommonTokenStream tokens(&tokenSrc);
ParserInterpreter parserInterp(_parser->getGrammarFileName(), _parser->getVocabulary(),
_parser->getRuleNames(), _parser->getATNWithBypassAlts(), &tokens);
ParserRuleContext *tree = nullptr;
try {
parserInterp.setErrorHandler(std::make_shared<BailErrorStrategy>());
tree = parserInterp.parse(patternRuleIndex);
} catch (ParseCancellationException &e) {
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023026
// rethrow_if_nested is not available before VS 2015.
throw e;
#else
std::rethrow_if_nested(e); // Unwrap the nested exception.
#endif
} catch (RecognitionException &re) {
throw re;
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023026
} catch (std::exception &e) {
// throw_with_nested is not available before VS 2015.
throw e;
#else
} catch (std::exception & /*e*/) {
std::throw_with_nested((const char*)"Cannot invoke start rule"); // Wrap any other exception. We should however probably use one of the ANTLR exceptions here.
#endif
}
// Make sure tree pattern compilation checks for a complete parse
if (tokens.LA(1) != Token::EOF) {
throw StartRuleDoesNotConsumeFullPattern();
}
return ParseTreePattern(this, pattern, patternRuleIndex, tree);
}
Lexer* ParseTreePatternMatcher::getLexer() {
return _lexer;
}
Parser* ParseTreePatternMatcher::getParser() {
return _parser;
}
ParseTree* ParseTreePatternMatcher::matchImpl(ParseTree *tree, ParseTree *patternTree,
std::map<std::string, std::vector<ParseTree *>> &labels) {
if (tree == nullptr) {
throw IllegalArgumentException("tree cannot be nul");
}
if (patternTree == nullptr) {
throw IllegalArgumentException("patternTree cannot be nul");
}
// x and <ID>, x and y, or x and x; or could be mismatched types
if (is<TerminalNode *>(tree) && is<TerminalNode *>(patternTree)) {
TerminalNode *t1 = dynamic_cast<TerminalNode *>(tree);
TerminalNode *t2 = dynamic_cast<TerminalNode *>(patternTree);
ParseTree *mismatchedNode = nullptr;
// both are tokens and they have same type
if (t1->getSymbol()->getType() == t2->getSymbol()->getType()) {
if (is<TokenTagToken *>(t2->getSymbol())) { // x and <ID>
TokenTagToken *tokenTagToken = dynamic_cast<TokenTagToken *>(t2->getSymbol());
// track label->list-of-nodes for both token name and label (if any)
labels[tokenTagToken->getTokenName()].push_back(tree);
if (tokenTagToken->getLabel() != "") {
labels[tokenTagToken->getLabel()].push_back(tree);
}
} else if (t1->getText() == t2->getText()) {
// x and x
} else {
// x and y
if (mismatchedNode == nullptr) {
mismatchedNode = t1;
}
}
} else {
if (mismatchedNode == nullptr) {
mismatchedNode = t1;
}
}
return mismatchedNode;
}
if (is<ParserRuleContext *>(tree) && is<ParserRuleContext *>(patternTree)) {
ParserRuleContext *r1 = dynamic_cast<ParserRuleContext *>(tree);
ParserRuleContext *r2 = dynamic_cast<ParserRuleContext *>(patternTree);
ParseTree *mismatchedNode = nullptr;
// (expr ...) and <expr>
RuleTagToken *ruleTagToken = getRuleTagToken(r2);
if (ruleTagToken != nullptr) {
//ParseTreeMatch *m = nullptr; // unused?
if (r1->getRuleIndex() == r2->getRuleIndex()) {
// track label->list-of-nodes for both rule name and label (if any)
labels[ruleTagToken->getRuleName()].push_back(tree);
if (ruleTagToken->getLabel() != "") {
labels[ruleTagToken->getLabel()].push_back(tree);
}
} else {
if (!mismatchedNode) {
mismatchedNode = r1;
}
}
return mismatchedNode;
}
// (expr ...) and (expr ...)
if (r1->children.size() != r2->children.size()) {
if (mismatchedNode == nullptr) {
mismatchedNode = r1;
}
return mismatchedNode;
}
std::size_t n = r1->children.size();
for (size_t i = 0; i < n; i++) {
ParseTree *childMatch = matchImpl(r1->children[i], patternTree->children[i], labels);
if (childMatch) {
return childMatch;
}
}
return mismatchedNode;
}
// if nodes aren't both tokens or both rule nodes, can't match
return tree;
}
RuleTagToken* ParseTreePatternMatcher::getRuleTagToken(ParseTree *t) {
if (t->children.size() == 1 && is<TerminalNode *>(t->children[0])) {
TerminalNode *c = dynamic_cast<TerminalNode *>(t->children[0]);
if (is<RuleTagToken *>(c->getSymbol())) {
return dynamic_cast<RuleTagToken *>(c->getSymbol());
}
}
return nullptr;
}
std::vector<std::unique_ptr<Token>> ParseTreePatternMatcher::tokenize(const std::string &pattern) {
// split pattern into chunks: sea (raw input) and islands (<ID>, <expr>)
std::vector<Chunk> chunks = split(pattern);
// create token stream from text and tags
std::vector<std::unique_ptr<Token>> tokens;
for (auto chunk : chunks) {
if (is<TagChunk *>(&chunk)) {
TagChunk &tagChunk = (TagChunk&)chunk;
// add special rule token or conjure up new token from name
if (isupper(tagChunk.getTag()[0])) {
size_t ttype = _parser->getTokenType(tagChunk.getTag());
if (ttype == Token::INVALID_TYPE) {
throw IllegalArgumentException("Unknown token " + tagChunk.getTag() + " in pattern: " + pattern);
}
tokens.emplace_back(new TokenTagToken(tagChunk.getTag(), (int)ttype, tagChunk.getLabel()));
} else if (islower(tagChunk.getTag()[0])) {
size_t ruleIndex = _parser->getRuleIndex(tagChunk.getTag());
if (ruleIndex == INVALID_INDEX) {
throw IllegalArgumentException("Unknown rule " + tagChunk.getTag() + " in pattern: " + pattern);
}
size_t ruleImaginaryTokenType = _parser->getATNWithBypassAlts().ruleToTokenType[ruleIndex];
tokens.emplace_back(new RuleTagToken(tagChunk.getTag(), ruleImaginaryTokenType, tagChunk.getLabel()));
} else {
throw IllegalArgumentException("invalid tag: " + tagChunk.getTag() + " in pattern: " + pattern);
}
} else {
TextChunk &textChunk = (TextChunk&)chunk;
ANTLRInputStream input(textChunk.getText());
_lexer->setInputStream(&input);
std::unique_ptr<Token> t(_lexer->nextToken());
while (t->getType() != Token::EOF) {
tokens.push_back(std::move(t));
t = _lexer->nextToken();
}
_lexer->setInputStream(nullptr);
}
}
return tokens;
}
std::vector<Chunk> ParseTreePatternMatcher::split(const std::string &pattern) {
size_t p = 0;
size_t n = pattern.length();
std::vector<Chunk> chunks;
// find all start and stop indexes first, then collect
std::vector<size_t> starts;
std::vector<size_t> stops;
while (p < n) {
if (p == pattern.find(_escape + _start,p)) {
p += _escape.length() + _start.length();
} else if (p == pattern.find(_escape + _stop,p)) {
p += _escape.length() + _stop.length();
} else if (p == pattern.find(_start,p)) {
starts.push_back(p);
p += _start.length();
} else if (p == pattern.find(_stop,p)) {
stops.push_back(p);
p += _stop.length();
} else {
p++;
}
}
if (starts.size() > stops.size()) {
throw IllegalArgumentException("unterminated tag in pattern: " + pattern);
}
if (starts.size() < stops.size()) {
throw IllegalArgumentException("missing start tag in pattern: " + pattern);
}
size_t ntags = starts.size();
for (size_t i = 0; i < ntags; i++) {
if (starts[i] >= stops[i]) {
throw IllegalArgumentException("tag delimiters out of order in pattern: " + pattern);
}
}
// collect into chunks now
if (ntags == 0) {
std::string text = pattern.substr(0, n);
chunks.push_back(TextChunk(text));
}
if (ntags > 0 && starts[0] > 0) { // copy text up to first tag into chunks
std::string text = pattern.substr(0, starts[0]);
chunks.push_back(TextChunk(text));
}
for (size_t i = 0; i < ntags; i++) {
// copy inside of <tag>
std::string tag = pattern.substr(starts[i] + _start.length(), stops[i] - (starts[i] + _start.length()));
std::string ruleOrToken = tag;
std::string label = "";
size_t colon = tag.find(':');
if (colon != std::string::npos) {
label = tag.substr(0,colon);
ruleOrToken = tag.substr(colon + 1, tag.length() - (colon + 1));
}
chunks.push_back(TagChunk(label, ruleOrToken));
if (i + 1 < ntags) {
// copy from end of <tag> to start of next
std::string text = pattern.substr(stops[i] + _stop.length(), starts[i + 1] - (stops[i] + _stop.length()));
chunks.push_back(TextChunk(text));
}
}
if (ntags > 0) {
size_t afterLastTag = stops[ntags - 1] + _stop.length();
if (afterLastTag < n) { // copy text from end of last tag to end
std::string text = pattern.substr(afterLastTag, n - afterLastTag);
chunks.push_back(TextChunk(text));
}
}
// strip out all backslashes from text chunks but not tags
for (size_t i = 0; i < chunks.size(); i++) {
Chunk &c = chunks[i];
if (is<TextChunk *>(&c)) {
TextChunk &tc = (TextChunk&)c;
std::string unescaped = tc.getText();
unescaped.erase(std::remove(unescaped.begin(), unescaped.end(), '\\'), unescaped.end());
if (unescaped.length() < tc.getText().length()) {
chunks[i] = TextChunk(unescaped);
}
}
}
return chunks;
}
void ParseTreePatternMatcher::InitializeInstanceFields() {
_start = "<";
_stop = ">";
_escape = "\\";
}

View File

@@ -0,0 +1,185 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "Exceptions.h"
namespace antlr4 {
namespace tree {
namespace pattern {
/// <summary>
/// A tree pattern matching mechanism for ANTLR <seealso cref="ParseTree"/>s.
/// <p/>
/// Patterns are strings of source input text with special tags representing
/// token or rule references such as:
/// <p/>
/// {@code <ID> = <expr>;}
/// <p/>
/// Given a pattern start rule such as {@code statement}, this object constructs
/// a <seealso cref="ParseTree"/> with placeholders for the {@code ID} and {@code expr}
/// subtree. Then the <seealso cref="#match"/> routines can compare an actual
/// <seealso cref="ParseTree"/> from a parse with this pattern. Tag {@code <ID>} matches
/// any {@code ID} token and tag {@code <expr>} references the result of the
/// {@code expr} rule (generally an instance of {@code ExprContext}.
/// <p/>
/// Pattern {@code x = 0;} is a similar pattern that matches the same pattern
/// except that it requires the identifier to be {@code x} and the expression to
/// be {@code 0}.
/// <p/>
/// The <seealso cref="#matches"/> routines return {@code true} or {@code false} based
/// upon a match for the tree rooted at the parameter sent in. The
/// <seealso cref="#match"/> routines return a <seealso cref="ParseTreeMatch"/> object that
/// contains the parse tree, the parse tree pattern, and a map from tag name to
/// matched nodes (more below). A subtree that fails to match, returns with
/// <seealso cref="ParseTreeMatch#mismatchedNode"/> set to the first tree node that did not
/// match.
/// <p/>
/// For efficiency, you can compile a tree pattern in string form to a
/// <seealso cref="ParseTreePattern"/> object.
/// <p/>
/// See {@code TestParseTreeMatcher} for lots of examples.
/// <seealso cref="ParseTreePattern"/> has two static helper methods:
/// <seealso cref="ParseTreePattern#findAll"/> and <seealso cref="ParseTreePattern#match"/> that
/// are easy to use but not super efficient because they create new
/// <seealso cref="ParseTreePatternMatcher"/> objects each time and have to compile the
/// pattern in string form before using it.
/// <p/>
/// The lexer and parser that you pass into the <seealso cref="ParseTreePatternMatcher"/>
/// constructor are used to parse the pattern in string form. The lexer converts
/// the {@code <ID> = <expr>;} into a sequence of four tokens (assuming lexer
/// throws out whitespace or puts it on a hidden channel). Be aware that the
/// input stream is reset for the lexer (but not the parser; a
/// <seealso cref="ParserInterpreter"/> is created to parse the input.). Any user-defined
/// fields you have put into the lexer might get changed when this mechanism asks
/// it to scan the pattern string.
/// <p/>
/// Normally a parser does not accept token {@code <expr>} as a valid
/// {@code expr} but, from the parser passed in, we create a special version of
/// the underlying grammar representation (an <seealso cref="ATN"/>) that allows imaginary
/// tokens representing rules ({@code <expr>}) to match entire rules. We call
/// these <em>bypass alternatives</em>.
/// <p/>
/// Delimiters are {@code <} and {@code >}, with {@code \} as the escape string
/// by default, but you can set them to whatever you want using
/// <seealso cref="#setDelimiters"/>. You must escape both start and stop strings
/// {@code \<} and {@code \>}.
/// </summary>
class ANTLR4CPP_PUBLIC ParseTreePatternMatcher {
public:
class CannotInvokeStartRule : public RuntimeException {
public:
CannotInvokeStartRule(const RuntimeException &e);
~CannotInvokeStartRule();
};
// Fixes https://github.com/antlr/antlr4/issues/413
// "Tree pattern compilation doesn't check for a complete parse"
class StartRuleDoesNotConsumeFullPattern : public RuntimeException {
public:
StartRuleDoesNotConsumeFullPattern() = default;
StartRuleDoesNotConsumeFullPattern(StartRuleDoesNotConsumeFullPattern const&) = default;
~StartRuleDoesNotConsumeFullPattern();
StartRuleDoesNotConsumeFullPattern& operator=(StartRuleDoesNotConsumeFullPattern const&) = default;
};
/// Constructs a <seealso cref="ParseTreePatternMatcher"/> or from a <seealso cref="Lexer"/> and
/// <seealso cref="Parser"/> object. The lexer input stream is altered for tokenizing
/// the tree patterns. The parser is used as a convenient mechanism to get
/// the grammar name, plus token, rule names.
ParseTreePatternMatcher(Lexer *lexer, Parser *parser);
virtual ~ParseTreePatternMatcher();
/// <summary>
/// Set the delimiters used for marking rule and token tags within concrete
/// syntax used by the tree pattern parser.
/// </summary>
/// <param name="start"> The start delimiter. </param>
/// <param name="stop"> The stop delimiter. </param>
/// <param name="escapeLeft"> The escape sequence to use for escaping a start or stop delimiter.
/// </param>
/// <exception cref="IllegalArgumentException"> if {@code start} is {@code null} or empty. </exception>
/// <exception cref="IllegalArgumentException"> if {@code stop} is {@code null} or empty. </exception>
virtual void setDelimiters(const std::string &start, const std::string &stop, const std::string &escapeLeft);
/// <summary>
/// Does {@code pattern} matched as rule {@code patternRuleIndex} match {@code tree}? </summary>
virtual bool matches(ParseTree *tree, const std::string &pattern, int patternRuleIndex);
/// <summary>
/// Does {@code pattern} matched as rule patternRuleIndex match tree? Pass in a
/// compiled pattern instead of a string representation of a tree pattern.
/// </summary>
virtual bool matches(ParseTree *tree, const ParseTreePattern &pattern);
/// <summary>
/// Compare {@code pattern} matched as rule {@code patternRuleIndex} against
/// {@code tree} and return a <seealso cref="ParseTreeMatch"/> object that contains the
/// matched elements, or the node at which the match failed.
/// </summary>
virtual ParseTreeMatch match(ParseTree *tree, const std::string &pattern, int patternRuleIndex);
/// <summary>
/// Compare {@code pattern} matched against {@code tree} and return a
/// <seealso cref="ParseTreeMatch"/> object that contains the matched elements, or the
/// node at which the match failed. Pass in a compiled pattern instead of a
/// string representation of a tree pattern.
/// </summary>
virtual ParseTreeMatch match(ParseTree *tree, const ParseTreePattern &pattern);
/// <summary>
/// For repeated use of a tree pattern, compile it to a
/// <seealso cref="ParseTreePattern"/> using this method.
/// </summary>
virtual ParseTreePattern compile(const std::string &pattern, int patternRuleIndex);
/// <summary>
/// Used to convert the tree pattern string into a series of tokens. The
/// input stream is reset.
/// </summary>
virtual Lexer* getLexer();
/// <summary>
/// Used to collect to the grammar file name, token names, rule names for
/// used to parse the pattern into a parse tree.
/// </summary>
virtual Parser* getParser();
// ---- SUPPORT CODE ----
virtual std::vector<std::unique_ptr<Token>> tokenize(const std::string &pattern);
/// Split "<ID> = <e:expr>;" into 4 chunks for tokenizing by tokenize().
virtual std::vector<Chunk> split(const std::string &pattern);
protected:
std::string _start;
std::string _stop;
std::string _escape; // e.g., \< and \> must escape BOTH!
/// Recursively walk {@code tree} against {@code patternTree}, filling
/// {@code match.}<seealso cref="ParseTreeMatch#labels labels"/>.
///
/// <returns> the first node encountered in {@code tree} which does not match
/// a corresponding node in {@code patternTree}, or {@code null} if the match
/// was successful. The specific node returned depends on the matching
/// algorithm used by the implementation, and may be overridden. </returns>
virtual ParseTree* matchImpl(ParseTree *tree, ParseTree *patternTree, std::map<std::string, std::vector<ParseTree *>> &labels);
/// Is t <expr> subtree?
virtual RuleTagToken* getRuleTagToken(ParseTree *t);
private:
Lexer *_lexer;
Parser *_parser;
void InitializeInstanceFields();
};
} // namespace pattern
} // namespace tree
} // namespace antlr4

View File

@@ -0,0 +1,77 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "Exceptions.h"
#include "tree/pattern/RuleTagToken.h"
using namespace antlr4::tree::pattern;
RuleTagToken::RuleTagToken(const std::string &/*ruleName*/, int _bypassTokenType) : bypassTokenType(_bypassTokenType) {
}
RuleTagToken::RuleTagToken(const std::string &ruleName, size_t bypassTokenType, const std::string &label)
: ruleName(ruleName), bypassTokenType(bypassTokenType), label(label) {
if (ruleName.empty()) {
throw IllegalArgumentException("ruleName cannot be null or empty.");
}
}
std::string RuleTagToken::getRuleName() const {
return ruleName;
}
std::string RuleTagToken::getLabel() const {
return label;
}
size_t RuleTagToken::getChannel() const {
return DEFAULT_CHANNEL;
}
std::string RuleTagToken::getText() const {
if (label != "") {
return std::string("<") + label + std::string(":") + ruleName + std::string(">");
}
return std::string("<") + ruleName + std::string(">");
}
size_t RuleTagToken::getType() const {
return bypassTokenType;
}
size_t RuleTagToken::getLine() const {
return 0;
}
size_t RuleTagToken::getCharPositionInLine() const {
return INVALID_INDEX;
}
size_t RuleTagToken::getTokenIndex() const {
return INVALID_INDEX;
}
size_t RuleTagToken::getStartIndex() const {
return INVALID_INDEX;
}
size_t RuleTagToken::getStopIndex() const {
return INVALID_INDEX;
}
antlr4::TokenSource *RuleTagToken::getTokenSource() const {
return nullptr;
}
antlr4::CharStream *RuleTagToken::getInputStream() const {
return nullptr;
}
std::string RuleTagToken::toString() const {
return ruleName + ":" + std::to_string(bypassTokenType);
}

View File

@@ -0,0 +1,117 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "Token.h"
namespace antlr4 {
namespace tree {
namespace pattern {
/// <summary>
/// A <seealso cref="Token"/> object representing an entire subtree matched by a parser
/// rule; e.g., {@code <expr>}. These tokens are created for <seealso cref="TagChunk"/>
/// chunks where the tag corresponds to a parser rule.
/// </summary>
class ANTLR4CPP_PUBLIC RuleTagToken : public Token {
/// <summary>
/// This is the backing field for <seealso cref="#getRuleName"/>.
/// </summary>
private:
const std::string ruleName;
/// The token type for the current token. This is the token type assigned to
/// the bypass alternative for the rule during ATN deserialization.
const size_t bypassTokenType;
/// This is the backing field for <seealso cref="#getLabe"/>.
const std::string label;
public:
/// <summary>
/// Constructs a new instance of <seealso cref="RuleTagToken"/> with the specified rule
/// name and bypass token type and no label.
/// </summary>
/// <param name="ruleName"> The name of the parser rule this rule tag matches. </param>
/// <param name="bypassTokenType"> The bypass token type assigned to the parser rule.
/// </param>
/// <exception cref="IllegalArgumentException"> if {@code ruleName} is {@code null}
/// or empty. </exception>
RuleTagToken(const std::string &ruleName, int bypassTokenType); //this(ruleName, bypassTokenType, nullptr);
/// <summary>
/// Constructs a new instance of <seealso cref="RuleTagToken"/> with the specified rule
/// name, bypass token type, and label.
/// </summary>
/// <param name="ruleName"> The name of the parser rule this rule tag matches. </param>
/// <param name="bypassTokenType"> The bypass token type assigned to the parser rule. </param>
/// <param name="label"> The label associated with the rule tag, or {@code null} if
/// the rule tag is unlabeled.
/// </param>
/// <exception cref="IllegalArgumentException"> if {@code ruleName} is {@code null}
/// or empty. </exception>
RuleTagToken(const std::string &ruleName, size_t bypassTokenType, const std::string &label);
/// <summary>
/// Gets the name of the rule associated with this rule tag.
/// </summary>
/// <returns> The name of the parser rule associated with this rule tag. </returns>
std::string getRuleName() const;
/// <summary>
/// Gets the label associated with the rule tag.
/// </summary>
/// <returns> The name of the label associated with the rule tag, or
/// {@code null} if this is an unlabeled rule tag. </returns>
std::string getLabel() const;
/// <summary>
/// {@inheritDoc}
/// <p/>
/// Rule tag tokens are always placed on the <seealso cref="#DEFAULT_CHANNE"/>.
/// </summary>
virtual size_t getChannel() const override;
/// <summary>
/// {@inheritDoc}
/// <p/>
/// This method returns the rule tag formatted with {@code <} and {@code >}
/// delimiters.
/// </summary>
virtual std::string getText() const override;
/// Rule tag tokens have types assigned according to the rule bypass
/// transitions created during ATN deserialization.
virtual size_t getType() const override;
/// The implementation for <seealso cref="RuleTagToken"/> always returns 0.
virtual size_t getLine() const override;
/// The implementation for <seealso cref="RuleTagToken"/> always returns INVALID_INDEX.
virtual size_t getCharPositionInLine() const override;
/// The implementation for <seealso cref="RuleTagToken"/> always returns INVALID_INDEX.
virtual size_t getTokenIndex() const override;
/// The implementation for <seealso cref="RuleTagToken"/> always returns INVALID_INDEX.
virtual size_t getStartIndex() const override;
/// The implementation for <seealso cref="RuleTagToken"/> always returns INVALID_INDEX.
virtual size_t getStopIndex() const override;
/// The implementation for <seealso cref="RuleTagToken"/> always returns {@code null}.
virtual TokenSource *getTokenSource() const override;
/// The implementation for <seealso cref="RuleTagToken"/> always returns {@code null}.
virtual CharStream *getInputStream() const override;
/// The implementation for <seealso cref="RuleTagToken"/> returns a string of the form {@code ruleName:bypassTokenType}.
virtual std::string toString() const override;
};
} // namespace pattern
} // namespace tree
} // namespace antlr4

View File

@@ -0,0 +1,39 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "Exceptions.h"
#include "tree/pattern/TagChunk.h"
using namespace antlr4::tree::pattern;
TagChunk::TagChunk(const std::string &tag) : TagChunk("", tag) {
}
TagChunk::TagChunk(const std::string &label, const std::string &tag) : _tag(tag), _label(label) {
if (tag.empty()) {
throw IllegalArgumentException("tag cannot be null or empty");
}
}
TagChunk::~TagChunk() {
}
std::string TagChunk::getTag() {
return _tag;
}
std::string TagChunk::getLabel() {
return _label;
}
std::string TagChunk::toString() {
if (!_label.empty()) {
return _label + ":" + _tag;
}
return _tag;
}

View File

@@ -0,0 +1,86 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "Chunk.h"
namespace antlr4 {
namespace tree {
namespace pattern {
/// <summary>
/// Represents a placeholder tag in a tree pattern. A tag can have any of the
/// following forms.
///
/// <ul>
/// <li>{@code expr}: An unlabeled placeholder for a parser rule {@code expr}.</li>
/// <li>{@code ID}: An unlabeled placeholder for a token of type {@code ID}.</li>
/// <li>{@code e:expr}: A labeled placeholder for a parser rule {@code expr}.</li>
/// <li>{@code id:ID}: A labeled placeholder for a token of type {@code ID}.</li>
/// </ul>
///
/// This class does not perform any validation on the tag or label names aside
/// from ensuring that the tag is a non-null, non-empty string.
/// </summary>
class ANTLR4CPP_PUBLIC TagChunk : public Chunk {
public:
/// <summary>
/// Construct a new instance of <seealso cref="TagChunk"/> using the specified tag and
/// no label.
/// </summary>
/// <param name="tag"> The tag, which should be the name of a parser rule or token
/// type.
/// </param>
/// <exception cref="IllegalArgumentException"> if {@code tag} is {@code null} or
/// empty. </exception>
TagChunk(const std::string &tag);
virtual ~TagChunk();
/// <summary>
/// Construct a new instance of <seealso cref="TagChunk"/> using the specified label
/// and tag.
/// </summary>
/// <param name="label"> The label for the tag. If this is {@code null}, the
/// <seealso cref="TagChunk"/> represents an unlabeled tag. </param>
/// <param name="tag"> The tag, which should be the name of a parser rule or token
/// type.
/// </param>
/// <exception cref="IllegalArgumentException"> if {@code tag} is {@code null} or
/// empty. </exception>
TagChunk(const std::string &label, const std::string &tag);
/// <summary>
/// Get the tag for this chunk.
/// </summary>
/// <returns> The tag for the chunk. </returns>
std::string getTag();
/// <summary>
/// Get the label, if any, assigned to this chunk.
/// </summary>
/// <returns> The label assigned to this chunk, or {@code null} if no label is
/// assigned to the chunk. </returns>
std::string getLabel();
/// <summary>
/// This method returns a text representation of the tag chunk. Labeled tags
/// are returned in the form {@code label:tag}, and unlabeled tags are
/// returned as just the tag name.
/// </summary>
virtual std::string toString();
private:
/// This is the backing field for <seealso cref="#getTag"/>.
const std::string _tag;
/// <summary>
/// This is the backing field for <seealso cref="#getLabe"/>.
/// </summary>
const std::string _label;
};
} // namespace pattern
} // namespace tree
} // namespace antlr4

View File

@@ -0,0 +1,28 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "Exceptions.h"
#include "tree/pattern/TextChunk.h"
using namespace antlr4::tree::pattern;
TextChunk::TextChunk(const std::string &text) : text(text) {
if (text == "") {
throw IllegalArgumentException("text cannot be nul");
}
}
TextChunk::~TextChunk() {
}
std::string TextChunk::getText() {
return text;
}
std::string TextChunk::toString() {
return std::string("'") + text + std::string("'");
}

View File

@@ -0,0 +1,51 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "Chunk.h"
namespace antlr4 {
namespace tree {
namespace pattern {
/// <summary>
/// Represents a span of raw text (concrete syntax) between tags in a tree
/// pattern string.
/// </summary>
class ANTLR4CPP_PUBLIC TextChunk : public Chunk {
private:
/// <summary>
/// This is the backing field for <seealso cref="#getText"/>.
/// </summary>
const std::string text;
/// <summary>
/// Constructs a new instance of <seealso cref="TextChunk"/> with the specified text.
/// </summary>
/// <param name="text"> The text of this chunk. </param>
/// <exception cref="IllegalArgumentException"> if {@code text} is {@code null}. </exception>
public:
TextChunk(const std::string &text);
virtual ~TextChunk();
/// <summary>
/// Gets the raw text of this chunk.
/// </summary>
/// <returns> The text of the chunk. </returns>
std::string getText();
/// <summary>
/// {@inheritDoc}
/// <p/>
/// The implementation for <seealso cref="TextChunk"/> returns the result of
/// <seealso cref="#getText()"/> in single quotes.
/// </summary>
virtual std::string toString();
};
} // namespace pattern
} // namespace tree
} // namespace antlr4

View File

@@ -0,0 +1,36 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "tree/pattern/TokenTagToken.h"
using namespace antlr4::tree::pattern;
TokenTagToken::TokenTagToken(const std::string &/*tokenName*/, int type)
: CommonToken(type), tokenName(""), label("") {
}
TokenTagToken::TokenTagToken(const std::string &tokenName, int type, const std::string &label)
: CommonToken(type), tokenName(tokenName), label(label) {
}
std::string TokenTagToken::getTokenName() const {
return tokenName;
}
std::string TokenTagToken::getLabel() const {
return label;
}
std::string TokenTagToken::getText() const {
if (!label.empty()) {
return "<" + label + ":" + tokenName + ">";
}
return "<" + tokenName + ">";
}
std::string TokenTagToken::toString() const {
return tokenName + ":" + std::to_string(_type);
}

View File

@@ -0,0 +1,80 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "CommonToken.h"
namespace antlr4 {
namespace tree {
namespace pattern {
/// <summary>
/// A <seealso cref="Token"/> object representing a token of a particular type; e.g.,
/// {@code <ID>}. These tokens are created for <seealso cref="TagChunk"/> chunks where the
/// tag corresponds to a lexer rule or token type.
/// </summary>
class ANTLR4CPP_PUBLIC TokenTagToken : public CommonToken {
/// <summary>
/// This is the backing field for <seealso cref="#getTokenName"/>.
/// </summary>
private:
const std::string tokenName;
/// <summary>
/// This is the backing field for <seealso cref="#getLabe"/>.
/// </summary>
const std::string label;
/// <summary>
/// Constructs a new instance of <seealso cref="TokenTagToken"/> for an unlabeled tag
/// with the specified token name and type.
/// </summary>
/// <param name="tokenName"> The token name. </param>
/// <param name="type"> The token type. </param>
public:
TokenTagToken(const std::string &tokenName, int type); //this(tokenName, type, nullptr);
/// <summary>
/// Constructs a new instance of <seealso cref="TokenTagToken"/> with the specified
/// token name, type, and label.
/// </summary>
/// <param name="tokenName"> The token name. </param>
/// <param name="type"> The token type. </param>
/// <param name="label"> The label associated with the token tag, or {@code null} if
/// the token tag is unlabeled. </param>
TokenTagToken(const std::string &tokenName, int type, const std::string &label);
/// <summary>
/// Gets the token name. </summary>
/// <returns> The token name. </returns>
std::string getTokenName() const;
/// <summary>
/// Gets the label associated with the rule tag.
/// </summary>
/// <returns> The name of the label associated with the rule tag, or
/// {@code null} if this is an unlabeled rule tag. </returns>
std::string getLabel() const;
/// <summary>
/// {@inheritDoc}
/// <p/>
/// The implementation for <seealso cref="TokenTagToken"/> returns the token tag
/// formatted with {@code <} and {@code >} delimiters.
/// </summary>
virtual std::string getText() const override;
/// <summary>
/// {@inheritDoc}
/// <p/>
/// The implementation for <seealso cref="TokenTagToken"/> returns a string of the form
/// {@code tokenName:type}.
/// </summary>
virtual std::string toString() const override;
};
} // namespace pattern
} // namespace tree
} // namespace antlr4