package org.kefirsf.bb.proc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.List;
/**
* Represents the pattern
*
* @author Vitaliy Samolovskih aka Kefir
*/
public class ProcPattern {
private final Logger log = LoggerFactory.getLogger(BBProcessor.LOGGER_PARSE);
/**
* Pattern elements
*/
private final List<? extends ProcPatternElement> elements;
// Performance optimization
private final ProcPatternElement firstElement;
private final int patternSize;
/**
* Construct pattern.
*
* @param elements pattern elements
*/
public ProcPattern(List<? extends ProcPatternElement> elements) {
this.elements = Collections.unmodifiableList(elements);
this.patternSize = elements.size();
// Performance optimization
if (!this.elements.isEmpty()) {
firstElement = this.elements.get(0);
} else {
throw new IllegalArgumentException("Parameter \"elements\" can't be empty.");
}
}
/**
* Указывает на то что следующая последовательность вполне может оказаться данным тэгом
*
* @param context current context
* @return true - если следующие несколько символов совпадают с первой константой в коде
* false - означает, что это точно не тот код
*/
public boolean suspicious(Context context) {
return firstElement.isNextIn(context);
}
/**
* Parse context with this pattern
*
* @param context current context
* @return true if next subsequence is valid to this pattern,
* false others
* @throws NestingException if nesting is too big.
*/
public boolean parse(Context context) throws NestingException {
boolean flag = true;
Source source = context.getSource();
int offset = source.getOffset();
// Log start parsing
if (log.isTraceEnabled()) {
log.trace("[{}] Begin {}", offset, this);
}
int i;
for (i = 0; i < patternSize && flag; i++) {
ProcPatternElement current = elements.get(i);
ProcPatternElement next;
if (i < patternSize - 1) {
next = elements.get(i + 1);
} else {
next = context.getTerminator();
}
flag = current.parse(context, next);
}
if (!flag) {
if (log.isTraceEnabled()) {
log.trace("[{}] Rollback {} on {} element", source.getOffset(), this, i);
}
source.setOffset(offset);
} else {
if (log.isTraceEnabled()) {
log.trace("[{}] Complete {}", source.getOffset(), this);
}
}
return flag;
}
public boolean startsWithConstant() {
return
firstElement instanceof PatternConstant ||
firstElement instanceof ProcEol;
}
public boolean hasCheck() {
for (ProcPatternElement element : elements) {
if (element instanceof Check) {
return true;
}
}
return false;
}
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append("<pattern>");
for(ProcPatternElement element:elements){
b.append(element);
}
b.append("</pattern>");
return b.toString();
}
}