summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src/main/java/bjc/utils/parserutils/delims
diff options
context:
space:
mode:
Diffstat (limited to 'BJC-Utils2/src/main/java/bjc/utils/parserutils/delims')
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/DelimiterGroup.java47
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/RegexOpener.java4
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/SequenceDelimiter.java56
3 files changed, 69 insertions, 38 deletions
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/DelimiterGroup.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/DelimiterGroup.java
index 85d4038..b1d8597 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/DelimiterGroup.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/DelimiterGroup.java
@@ -34,12 +34,20 @@ public class DelimiterGroup<T> {
*
*/
public class OpenGroup {
+ /*
+ * The contents of this group.
+ */
private final Deque<ITree<T>> contents;
+ /*
+ * The contents of the current subgroup.
+ */
private IList<ITree<T>> currentGroup;
+ /*
+ * The token that opened the group, and any opening parameters.
+ */
private final T opener;
-
private final T[] params;
/**
@@ -80,14 +88,23 @@ public class DelimiterGroup<T> {
* The characteristics for building the tree.
*/
public void markSubgroup(final T marker, final SequenceCharacteristics<T> chars) {
+ /*
+ * Add all of the contents to the subgroup.
+ */
final ITree<T> subgroupContents = new Tree<>(chars.contents);
for (final ITree<T> itm : currentGroup) {
subgroupContents.addChild(itm);
}
+ /*
+ * Handle subordinate sub-groups.
+ */
while (!contents.isEmpty()) {
final ITree<T> possibleSubordinate = contents.peek();
+ /*
+ * Subordinate lower priority subgroups.
+ */
if (possibleSubordinate.getHead().equals(chars.subgroup)) {
final T otherMarker = possibleSubordinate.getChild(1).getHead();
@@ -103,7 +120,6 @@ public class DelimiterGroup<T> {
final Tree<T> subgroup = new Tree<>(chars.subgroup, subgroupContents, new Tree<>(marker));
- //System.out.println("\tTRACE: generated subgroup\n" + subgroup + "\n\n");
contents.push(subgroup);
currentGroup = new FunctionalList<>();
@@ -121,12 +137,19 @@ public class DelimiterGroup<T> {
* @return This group as a tree.
*/
public ITree<T> toTree(final T closer, final SequenceCharacteristics<T> chars) {
+ /*
+ * Mark any implied subgroups.
+ */
if (impliedSubgroups.containsKey(closer)) {
markSubgroup(impliedSubgroups.get(closer), chars);
}
final ITree<T> res = new Tree<>(chars.contents);
+ /*
+ * Add either the contents of the current group,
+ * or subgroups if they're their.
+ */
if (contents.isEmpty()) {
currentGroup.forEach(res::addChild);
} else {
@@ -440,8 +463,7 @@ public class DelimiterGroup<T> {
* The group opened by the marker.
*/
public void addOpener(final T opener, final T group) {
- if (opener == null)
- throw new NullPointerException("Opener must not be null");
+ if (opener == null) throw new NullPointerException("Opener must not be null");
else if (group == null) throw new NullPointerException("Group to open must not be null");
openDelimiters.put(opener, group);
@@ -457,8 +479,7 @@ public class DelimiterGroup<T> {
* The group opened by the marker.
*/
public void addNestedOpener(final T opener, final T group) {
- if (opener == null)
- throw new NullPointerException("Opener must not be null");
+ if (opener == null) throw new NullPointerException("Opener must not be null");
else if (group == null) throw new NullPointerException("Group to open must not be null");
nestedOpenDelimiters.put(opener, group);
@@ -474,14 +495,10 @@ public class DelimiterGroup<T> {
* The subgroup to imply.
*/
public void implySubgroup(final T closer, final T subgroup) {
- if (closer == null)
- throw new NullPointerException("Closer must not be null");
- else if (subgroup == null)
- throw new NullPointerException("Subgroup must not be null");
- else if (!closingDelimiters.contains(closer))
- throw new IllegalArgumentException(String.format("No closing delimiter '%s' defined", closer));
- else if (!subgroups.containsKey(subgroup))
- throw new IllegalArgumentException(String.format("No subgroup '%s' defined", subgroup));
+ if (closer == null) throw new NullPointerException("Closer must not be null");
+ else if (subgroup == null) throw new NullPointerException("Subgroup must not be null");
+ else if (!closingDelimiters.contains(closer)) throw new IllegalArgumentException(String.format("No closing delimiter '%s' defined", closer));
+ else if (!subgroups.containsKey(subgroup)) throw new IllegalArgumentException(String.format("No subgroup '%s' defined", subgroup));
impliedSubgroups.put(closer, subgroup);
}
@@ -573,4 +590,4 @@ public class DelimiterGroup<T> {
public void setForgetful(final boolean forgetful) {
this.forgetful = forgetful;
}
-} \ No newline at end of file
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/RegexOpener.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/RegexOpener.java
index 98c1dc1..ee93b73 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/RegexOpener.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/RegexOpener.java
@@ -8,7 +8,7 @@ import bjc.utils.data.IPair;
import bjc.utils.data.Pair;
/**
- * A predicated opener for use with {@link RegexOpener}
+ * A predicated opener for use with {@link RegexCloser}
*
* @author bjculkin
*
@@ -51,4 +51,4 @@ public class RegexOpener implements Function<String, IPair<String, String[]>> {
return new Pair<>(null, null);
}
-} \ No newline at end of file
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/SequenceDelimiter.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/SequenceDelimiter.java
index 48d85c1..ccfaffb 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/SequenceDelimiter.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/SequenceDelimiter.java
@@ -32,6 +32,9 @@ public class SequenceDelimiter<T> {
*/
private final Map<T, DelimiterGroup<T>> groups;
+ /*
+ * The initial group to start with.
+ */
private DelimiterGroup<T> initialGroup;
/**
@@ -49,14 +52,14 @@ public class SequenceDelimiter<T> {
* following grammar while obeying the defined grouping rules.
*
* <pre>
- * <tree> -> (<data> | <subgroup> | <group>)*
- * <subgroup> -> <tree> <marker>
- * <group> -> <open> <tree> <close>
+ * <tree> → (<data> | <subgroup> | <group>)*
+ * <subgroup> → <tree> <marker>
+ * <group> → <open> <tree> <close>
*
- * <data> -> STRING
- * <open> -> STRING
- * <close> -> STRING
- * <marker> -> STRING
+ * <data> → STRING
+ * <open> → STRING
+ * <close> → STRING
+ * <marker> → STRING
* </pre>
*
* @param chars
@@ -92,9 +95,8 @@ public class SequenceDelimiter<T> {
*/
public ITree<T> delimitSequence(final SequenceCharacteristics<T> chars,
@SuppressWarnings("unchecked") final T... seq) throws DelimiterException {
- if (initialGroup == null)
- throw new NullPointerException("Initial group must be specified.");
- else if (chars == null) throw new NullPointerException("Sequence characteristics must not be null");
+ if (initialGroup == null) throw new NullPointerException("Initial group must be specified.");
+ else if (chars == null) throw new NullPointerException("Sequence characteristics must not be null");
/*
* The stack of opened and not yet closed groups.
@@ -123,9 +125,15 @@ public class SequenceDelimiter<T> {
*/
final IMap<T, T> whoForbid = new PushdownMap<>();
+ /*
+ * Process each member of the sequence.
+ */
for (int i = 0; i < seq.length; i++) {
final T tok = seq[i];
+ /*
+ * Check if this token could open a group.
+ */
final IPair<T, T[]> possibleOpenPar = groupStack.top().doesOpen(tok);
T possibleOpen = possibleOpenPar.getLeft();
@@ -156,8 +164,6 @@ public class SequenceDelimiter<T> {
* exclusions from all enclosing groups.
*/
if (isForbidden(groupStack, forbiddenDelimiters, possibleOpen)) {
- final StringBuilder msgBuilder = new StringBuilder();
-
T forbiddenBy;
if (whoForbid.containsKey(tok)) {
@@ -168,15 +174,9 @@ public class SequenceDelimiter<T> {
final String ctxList = StringUtils.toEnglishList(groupStack.toArray(), "then");
- msgBuilder.append("Group '");
- msgBuilder.append(group);
- msgBuilder.append("' can't be opened in this context.");
- msgBuilder.append(" (forbidden by '");
- msgBuilder.append(forbiddenBy);
- msgBuilder.append("')\nContext stack: ");
- msgBuilder.append(ctxList);
+ final String fmt = "Group '%s' can't be opened in this context. (forbidden by '%s')\nContext Stack: %s";
- throw new DelimiterException(msgBuilder.toString());
+ throw new DelimiterException(String.format(fmt, group, forbiddenBy, ctxList));
}
/*
@@ -244,8 +244,14 @@ public class SequenceDelimiter<T> {
forbiddenDelimiters.drop();
}
} else if (!groupStack.empty() && groupStack.top().marksSubgroup(tok)) {
+ /*
+ * Mark a subgroup.
+ */
groupStack.top().markSubgroup(tok, chars);
} else {
+ /*
+ * Add an item to the group.
+ */
groupStack.top().addItem(new Tree<>(tok));
}
}
@@ -270,16 +276,24 @@ public class SequenceDelimiter<T> {
msgBuilder.append(" to close it\nOpen groups: ");
msgBuilder.append(ctxList);
- throw new DelimiterException(msgBuilder.toString());
+ final String fmt = "Unclosed group '%s'. Expected one of %s to close it.\nOpen groups: %n";
+
+ throw new DelimiterException(String.format(fmt, group.getName(), closingDelims, ctxList));
}
return groupStack.pop().toTree(chars.root, chars);
}
+ /*
+ * Check if a group is forbidden to open in a context.
+ */
private boolean isForbidden(final Stack<DelimiterGroup<T>.OpenGroup> groupStack,
final Stack<Multiset<T>> forbiddenDelimiters, final T groupName) {
boolean localForbid;
+ /*
+ * Check if a delimiter is locally forbidden.
+ */
if (groupStack.empty()) {
localForbid = false;
} else {