eu.cqse.check.framework.util.tokens.TokenPatternMatch Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of teamscale-check-api Show documentation
Show all versions of teamscale-check-api Show documentation
The Teamscale Custom Check API allows users to extend Teamscale by writing custom analyses that create findings.
/*
* Copyright (c) CQSE GmbH
*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package eu.cqse.check.framework.util.tokens;
import java.util.ArrayList;
import java.util.List;
import org.conqat.lib.commons.collections.CollectionUtils;
import org.conqat.lib.commons.collections.ListMap;
import org.conqat.lib.commons.string.StringUtils;
import eu.cqse.check.framework.scanner.IToken;
import eu.cqse.check.framework.shallowparser.TokenStreamTextUtils;
/**
* A single match created by a {@link TokenPattern}. Keeps track of any groups that have been
* matched by parts of the pattern. A group is identified by an arbitrary integer. See also
* {@link TokenPattern#group(int)}.
*
* Multiple segments of the tokenStream can be associated with the same group. In this case,
* {@link #getMatchGroup(int)} will return multiple {@link MatchGroupElement}s for the group.
*/
public class TokenPatternMatch {
/** The token stream against which the matches were constructed. */
private final List tokenStream;
/**
* Maps from the group index to the ranges that are included in the group.
*/
private final ListMap groups = new ListMap<>();
/** Constructor. */
public TokenPatternMatch(List tokenStream) {
this.tokenStream = tokenStream;
}
/**
* Appends the given tokens to the group with the given index if the given range contains at least
* one token.
*/
public void appendToGroup(Integer groupIndex, int inclusiveStartIndex, int exclusiveEndIndex) {
if (inclusiveStartIndex < exclusiveEndIndex) {
groups.add(groupIndex, new Range(inclusiveStartIndex, exclusiveEndIndex));
}
}
/**
* Returns the text of the tokens in the given group. All {@link MatchGroupElement}s for the given
* group will be concatenated.
*/
public List groupTexts(int groupIndex) {
return TokenStreamTextUtils.getTokenTexts(groupTokens(groupIndex));
}
/**
* Returns the indices into the token stream in the given group or an empty list. All
* {@link MatchGroupElement}s for the given group will be concatenated.
*/
public List groupIndices(int groupIndex) {
List ranges = groups.getCollection(groupIndex);
if (ranges == null) {
return CollectionUtils.emptyList();
}
List indices = new ArrayList<>();
for (Range range : ranges) {
for (int i = range.inclusiveStartIndex; i < range.exclusiveEndIndex; i++) {
indices.add(i);
}
}
return indices;
}
/**
* Returns the tokens in the given group or an empty list. All {@link MatchGroupElement}s for the
* given group will be concatenated.
*/
public List groupTokens(int groupIndex) {
List tokens = new ArrayList<>();
for (Integer index : groupIndices(groupIndex)) {
tokens.add(tokenStream.get(index));
}
return tokens;
}
/**
* Returns the TokenStream parts matched in this group. Each part is represented by a
* {@link MatchGroupElement} and can contain multiple {@link IToken}s, depending on the used
* pattern.
*/
public List getMatchGroup(int groupIndex) {
List ranges = groups.getCollection(groupIndex);
if (ranges == null) {
return CollectionUtils.emptyList();
}
List groupElements = new ArrayList<>();
for (Range range : ranges) {
groupElements.add(
new MatchGroupElement(tokenStream.subList(range.inclusiveStartIndex, range.exclusiveEndIndex)));
}
return groupElements;
}
/**
* Returns the concatenated text of the tokens in the given group. All {@link MatchGroupElement}s
* for the given group will be concatenated. If the group was not matched, returns the empty string.
*/
public String groupString(int groupIndex) {
return StringUtils.concat(groupTexts(groupIndex), StringUtils.EMPTY_STRING);
}
/**
* Returns true
if the match contains tokens in the given group.
*/
public boolean hasGroup(int groupIndex) {
return groups.containsCollection(groupIndex);
}
/** Merges the group information from given match into this match. */
public void mergeFrom(TokenPatternMatch other) {
groups.addAll(other.groups);
}
/**
* Returns a list of all group strings in all matches of the group with the given index.
*/
public static List getAllStrings(List matches, int groupIndex) {
List strings = new ArrayList<>();
for (TokenPatternMatch match : matches) {
strings.add(match.groupString(groupIndex));
}
return strings;
}
/**
* Returns a list of all group tokens in all matches of the group with the given index.
*/
public static List getAllTokens(List matches, int groupIndex) {
List tokens = new ArrayList<>();
for (TokenPatternMatch match : matches) {
tokens.addAll(match.groupTokens(groupIndex));
}
return tokens;
}
/** A range of indices into a token stream. */
private static class Range {
/** The inclusive start index into the token stream. */
private final int inclusiveStartIndex;
/** The exclusive end index into the token stream. */
private final int exclusiveEndIndex;
/** Constructor. */
public Range(int inclusiveStartIndex, int exclusiveEndIndex) {
this.inclusiveStartIndex = inclusiveStartIndex;
this.exclusiveEndIndex = exclusiveEndIndex;
}
}
}