fr.vergne.parsing.layer.impl.Suite Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of parsing-core Show documentation
Show all versions of parsing-core Show documentation
Implementation of the parsing features.
package fr.vergne.parsing.layer.impl;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import fr.vergne.parsing.layer.Layer;
import fr.vergne.parsing.layer.exception.ParsingException;
/**
* A {@link Suite} is a {@link Layer} representing an ordered sequence of
* elements. This is particularly suited for structure templates like in
* C/C++/Java/...:
*
* - "if ("
* - condition
* - ") {"
* - block
* - "}"
*
* or in HTML:
*
* - "<a href='"
* - url
* - "'>"
* - content
* - "</a>"
*
* At a higher level, it also fits global structures like the architecture of a
* scientific paper for instance:
*
* - title
* - authors
* - abstract
* - introduction
* - problem
* - solution
* - discussion
* - conclusion
*
*
* @author Matthieu Vergne
*
*/
public class Suite extends AbstractLayer {
private final List extends Layer> sequence;
public Suite(List extends Layer> sequence) {
this.sequence = Collections.unmodifiableList(sequence);
}
public Suite(Layer... sequence) {
this(Arrays.asList(sequence));
}
@Override
protected String buildRegex() {
String regex = "";
for (Layer layer : sequence) {
regex += "(?:" + layer.getRegex() + ")";
}
return regex;
}
@Override
public String getContent() {
String content = "";
for (Layer layer : sequence) {
content += layer.getContent();
}
return content;
}
@Override
protected void setInternalContent(String content) {
Matcher matcher = Pattern.compile(
"^" + buildCapturingRegex(sequence) + "$").matcher(content);
if (matcher.find()) {
int delta = 0;
for (int i = 1; i <= matcher.groupCount(); i++) {
String match = matcher.group(i);
int subStart = delta;
int subEnd = subStart + match.length();
sequence.get(i - 1).setContent(
content.substring(subStart, subEnd));
delta += match.length();
}
} else {
LinkedList preOk = new LinkedList(sequence);
LinkedList postKo = new LinkedList();
do {
postKo.addFirst(preOk.removeLast());
String regex = buildCapturingRegex(preOk);
matcher = Pattern.compile("^" + regex).matcher(content);
} while (!matcher.find());
List fakeSequence = new LinkedList(preOk);
Formula remaining = new Formula("[\\s\\S]*");
fakeSequence.add(remaining);
new Suite(fakeSequence).setContent(content);
String incompatible = remaining.getContent();
try {
postKo.getFirst().setContent(incompatible);
} catch (ParsingException e) {
throw new ParsingException(this, postKo.getFirst(), content,
content.length() - incompatible.length(),
content.length(), e);
}
throw new IllegalStateException(
"No exception thrown while it should not be parsable.");
}
}
private String buildCapturingRegex(List extends Layer> sequence) {
String regex;
regex = "";
for (Layer layer : sequence) {
regex += "(" + layer.getRegex() + ")";
}
return regex;
}
@Override
public String toString() {
List suite = new LinkedList();
for (Layer layer : sequence) {
suite.add(layer.getClass().getSimpleName());
}
return getClass().getSimpleName() + suite;
}
@SuppressWarnings("unchecked")
public CLayer get(int index) {
return (CLayer) sequence.get(index);
}
}