eu.cqse.check.framework.util.tokens.SkipNestedPattern 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;
/**
* Matches a nested structure (e.g. nested parentheses).
*/
public class SkipNestedPattern extends TokenPatternBase {
/** Matches the token that increases the nesting level. */
private final TokenPatternBase openMatcher;
/** Matches the token that decreases the nesting level. */
private final TokenPatternBase closeMatcher;
/**
* If this is true
, this pattern matches, even if no nested structure is found at the
* current position. In this case, an empty match is returned.
*/
private final boolean optional;
/** Constructor. */
public SkipNestedPattern(TokenPatternBase openMatcher, TokenPatternBase closeMatcher, boolean optional) {
this.openMatcher = openMatcher;
this.closeMatcher = closeMatcher;
this.optional = optional;
}
/** {@inheritDoc} */
@Override
protected TokenPatternMatch matchesLocally(TokenStream stream) {
int beforeMatch = stream.getPosition();
TokenPatternMatch parentMatch = createMatch(stream);
TokenPatternMatch openMatch = openMatcher.matches(stream);
if (openMatch == null) {
if (optional) {
stream.setPosition(beforeMatch);
return createMatch(stream);
}
return null;
}
parentMatch.mergeFrom(openMatch);
int level = 1;
while (level > 0) {
if (stream.isExhausted()) {
if (optional) {
stream.setPosition(beforeMatch);
return createMatch(stream);
}
return null;
}
int beforeAlternative = stream.getPosition();
TokenPatternMatch alternativeSubMatch = closeMatcher.matches(stream);
if (alternativeSubMatch != null) {
parentMatch.mergeFrom(alternativeSubMatch);
level -= 1;
continue;
}
stream.setPosition(beforeAlternative);
alternativeSubMatch = openMatcher.matches(stream);
if (alternativeSubMatch != null) {
parentMatch.mergeFrom(alternativeSubMatch);
level += 1;
continue;
}
stream.setPosition(beforeAlternative);
stream.next();
}
return parentMatch;
}
/** {@inheritDoc} */
@Override
public String toString() {
return "SkipNested (OPEN: " + openMatcher.toString() + " CLOSE: " + closeMatcher.toString() + " optional: "
+ optional + ")";
}
}