DynamicPositionBuilder.java
/*
* (c) Copyright 2021 Hasan Selman Kara. All rights reserved.
*
* 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 li.selman.jpbe.dsl.position;
import com.google.common.base.Preconditions;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import li.selman.jpbe.dsl.token.Token;
import li.selman.jpbe.dsl.token.TokenSequence;
import li.selman.jpbe.dsl.token.TokenSequenceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DynamicPositionBuilder implements PositionBuilder {
// com.palantir.logsafe.logger.SafeLogger;
// https://github.com/palantir/gradle-baseline/blob/develop/baseline-error-prone/src/test/java/com/palantir/baseline/errorprone/PreferSafeLoggerTest.java#L46
private static final Logger log = LoggerFactory.getLogger(DynamicPositionBuilder.class);
private final TokenSequenceBuilder tokenSequenceBuilder;
public DynamicPositionBuilder(TokenSequenceBuilder tokenSequenceBuilder) {
this.tokenSequenceBuilder = tokenSequenceBuilder;
}
@Override
public Set<Position> computePositions(String input, int k) {
Preconditions.checkArgument(k >= 0, "k cannot be < 0");
Preconditions.checkArgument(k <= input.length(), "k cannot be > input.length()");
Map<Integer, TokenSequence> leftTokenSeq = computeLeftTokenSeq(input, k);
Map<Integer, TokenSequence> rightTokenSeq = computeRightTokenSeq(input, k);
Set<Position> dynamicPositions = new HashSet<>();
for (Entry<Integer, TokenSequence> leftEntry : leftTokenSeq.entrySet()) {
for (Entry<Integer, TokenSequence> rightEntry : rightTokenSeq.entrySet()) {
if (Objects.equals(leftEntry.getValue().getLastToken(), rightEntry.getValue().getLastToken())
&& !Objects.equals(leftEntry.getValue().getLastToken(), Token.START)
&& !Objects.equals(leftEntry.getValue().getLastToken(), Token.END)) {
// No valid token combination
continue;
}
TokenSequence r12 = leftEntry.getValue().union(rightEntry.getValue());
int c;
try {
c = Matcher.positionOfRegex(r12, input, leftEntry.getKey(), rightEntry.getKey());
} catch (Exception ex) {
if (ex instanceof IllegalStateException) {
// TODO(#api): check if this ever happens and whether we should return Optional in Matcher
// .positionOfRegex
log.error("Matcher.positionOfRegex failed", ex);
continue;
} else {
// TODO(#bug): should not be need?
// bubble up
throw ex;
}
}
int cMax = Matcher.totalNumberOfMatches(r12, input);
dynamicPositions.add(new DynamicPosition(leftEntry.getValue(), rightEntry.getValue(), c));
dynamicPositions.add(new DynamicPosition(leftEntry.getValue(), rightEntry.getValue(), -(cMax - c + 1)));
}
}
return dynamicPositions;
}
Map<Integer, TokenSequence> computeRightTokenSeq(String input, int k) {
Map<Integer, TokenSequence> rightTokenSeq = new HashMap<>();
for (int k2 = k + 1; k2 <= input.length(); k2++) {
TokenSequence tokenSequence = tokenSequenceBuilder.computeTokenSequence(input, k, k2);
if (!tokenSequence.isEmpty()) {
rightTokenSeq.put(k2, tokenSequence);
}
}
return rightTokenSeq;
}
Map<Integer, TokenSequence> computeLeftTokenSeq(String input, int k) {
Map<Integer, TokenSequence> leftTokenSeq = new HashMap<>();
for (int k1 = 0; k1 < k; k1++) {
TokenSequence tokenSequence = tokenSequenceBuilder.computeTokenSequence(input, k1, k);
if (!tokenSequence.isEmpty()) {
leftTokenSeq.put(k1, tokenSequence);
}
}
return leftTokenSeq;
}
}