diff options
Diffstat (limited to 'BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/SequenceDelimiter.java')
| -rw-r--r-- | BJC-Utils2/src/main/java/bjc/utils/parserutils/delims/SequenceDelimiter.java | 160 |
1 files changed, 79 insertions, 81 deletions
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 e723123..48d85c1 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 @@ -1,5 +1,14 @@ package bjc.utils.parserutils.delims; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multiset; + import bjc.utils.data.IPair; import bjc.utils.data.ITree; import bjc.utils.data.Tree; @@ -9,18 +18,9 @@ import bjc.utils.esodata.Stack; import bjc.utils.funcdata.IMap; import bjc.utils.funcutils.StringUtils; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.HashMultiset; -import com.google.common.collect.Multimap; -import com.google.common.collect.Multiset; - -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - /** * Convert linear sequences into trees that represent group structure. - * + * * @author EVE * * @param <T> @@ -30,7 +30,7 @@ public class SequenceDelimiter<T> { /* * Mapping from group names to actual groups. */ - private Map<T, DelimiterGroup<T>> groups; + private final Map<T, DelimiterGroup<T>> groups; private DelimiterGroup<T> initialGroup; @@ -44,64 +44,62 @@ public class SequenceDelimiter<T> { /** * Convert a linear sequence into a tree that matches the delimiter * structure. - * + * * Essentially, creates a parse tree of the expression against the * following grammar while obeying the defined grouping rules. - * + * * <pre> * <tree> -> (<data> | <subgroup> | <group>)* * <subgroup> -> <tree> <marker> * <group> -> <open> <tree> <close> - * + * * <data> -> STRING * <open> -> STRING * <close> -> STRING * <marker> -> STRING * </pre> - * + * * @param chars * The parameters on how to mark certain portions of the * tree. * @param seq * The sequence to delimit. - * + * * @return The sequence as a tree that matches its group structure. Each * node in the tree is either a data node, a subgroup node, or a * group node. - * + * * A data node is a leaf node whose data is the string it * represents. - * + * * A subgroup node is a node with two children, and the name of * the sub-group as its label. The first child is the contents * of the sub-group, and the second is the marker that started * the subgroup. The marker is a leaf node labeled with its * contents, and the contents contains a recursive tree. - * + * * A group node is a node with three children, and the name of * the group as its label. The first child is the opening * delimiter, the second is the group contents, and the third is * the closing delimiter. The delimiters are leaf nodes labeled * with their contents, while the group node contains a * recursive tree. - * + * * @throws DelimiterException * Thrown if something went wrong during sequence * delimitation. - * + * */ - public ITree<T> delimitSequence(SequenceCharacteristics<T> chars, @SuppressWarnings("unchecked") T... seq) - throws DelimiterException { - if(initialGroup == null) { + 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"); - } + else if (chars == null) throw new NullPointerException("Sequence characteristics must not be null"); /* * The stack of opened and not yet closed groups. */ - Stack<DelimiterGroup<T>.OpenGroup> groupStack = new SimpleStack<>(); + final Stack<DelimiterGroup<T>.OpenGroup> groupStack = new SimpleStack<>(); /* * Open initial group. @@ -111,34 +109,34 @@ public class SequenceDelimiter<T> { /* * Groups that aren't allowed to be opened at the moment. */ - Stack<Multiset<T>> forbiddenDelimiters = new SimpleStack<>(); + final Stack<Multiset<T>> forbiddenDelimiters = new SimpleStack<>(); forbiddenDelimiters.push(HashMultiset.create()); /* * Groups that are allowed to be opened at the moment. */ - Stack<Multimap<T, T>> allowedDelimiters = new SimpleStack<>(); + final Stack<Multimap<T, T>> allowedDelimiters = new SimpleStack<>(); allowedDelimiters.push(HashMultimap.create()); /* * Map of who forbid what for debugging purposes. */ - IMap<T, T> whoForbid = new PushdownMap<>(); + final IMap<T, T> whoForbid = new PushdownMap<>(); - for(int i = 0; i < seq.length; i++) { - T tok = seq[i]; + for (int i = 0; i < seq.length; i++) { + final T tok = seq[i]; - IPair<T, T[]> possibleOpenPar = groupStack.top().doesOpen(tok); + final IPair<T, T[]> possibleOpenPar = groupStack.top().doesOpen(tok); T possibleOpen = possibleOpenPar.getLeft(); - if(possibleOpen == null) { + if (possibleOpen == null) { /* * Handle nested openers. - * + * * Local openers take priority over nested ones * if they overlap. */ - if(allowedDelimiters.top().containsKey(tok)) { + if (allowedDelimiters.top().containsKey(tok)) { possibleOpen = allowedDelimiters.top().get(tok).iterator().next(); } } @@ -146,29 +144,29 @@ public class SequenceDelimiter<T> { /* * If we have an opening delimiter, handle it. */ - if(possibleOpen != null) { - DelimiterGroup<T> group = groups.get(possibleOpen); + if (possibleOpen != null) { + final DelimiterGroup<T> group = groups.get(possibleOpen); /* * Error on groups that can't open in this * context. - * + * * This means groups that can't occur at the * top-level of this group, as well as nested * exclusions from all enclosing groups. */ - if(isForbidden(groupStack, forbiddenDelimiters, possibleOpen)) { - StringBuilder msgBuilder = new StringBuilder(); + if (isForbidden(groupStack, forbiddenDelimiters, possibleOpen)) { + final StringBuilder msgBuilder = new StringBuilder(); T forbiddenBy; - if(whoForbid.containsKey(tok)) { + if (whoForbid.containsKey(tok)) { forbiddenBy = whoForbid.get(tok); } else { forbiddenBy = groupStack.top().getName(); } - String ctxList = StringUtils.toEnglishList(groupStack.toArray(), "then"); + final String ctxList = StringUtils.toEnglishList(groupStack.toArray(), "then"); msgBuilder.append("Group '"); msgBuilder.append(group); @@ -184,13 +182,13 @@ public class SequenceDelimiter<T> { /* * Add an open group. */ - DelimiterGroup<T>.OpenGroup open = group.open(tok, possibleOpenPar.getRight()); + final DelimiterGroup<T>.OpenGroup open = group.open(tok, possibleOpenPar.getRight()); groupStack.push(open); /* * Handle 'forgetful' groups that reset nesting */ - if(open.isForgetful()) { + if (open.isForgetful()) { allowedDelimiters.push(HashMultimap.create()); forbiddenDelimiters.push(HashMultiset.create()); } @@ -198,33 +196,33 @@ public class SequenceDelimiter<T> { /* * Add the nested opens from this group. */ - Multimap<T, T> currentAllowed = allowedDelimiters.top(); - for(Entry<T, T> opener : open.getNestingOpeners().entrySet()) { + final Multimap<T, T> currentAllowed = allowedDelimiters.top(); + for (final Entry<T, T> opener : open.getNestingOpeners().entrySet()) { currentAllowed.put(opener.getKey(), opener.getValue()); } /* * Add the nested exclusions from this group */ - Multiset<T> currentForbidden = forbiddenDelimiters.top(); - for(T exclusion : open.getNestingExclusions()) { + final Multiset<T> currentForbidden = forbiddenDelimiters.top(); + for (final T exclusion : open.getNestingExclusions()) { currentForbidden.add(exclusion); whoForbid.put(exclusion, possibleOpen); } - } else if(!groupStack.empty() && groupStack.top().isClosing(tok)) { + } else if (!groupStack.empty() && groupStack.top().isClosing(tok)) { /* * Close the group. */ - DelimiterGroup<T>.OpenGroup closed = groupStack.pop(); + final DelimiterGroup<T>.OpenGroup closed = groupStack.pop(); groupStack.top().addItem(closed.toTree(tok, chars)); /* * Remove nested exclusions from this group. */ - Multiset<T> currentForbidden = forbiddenDelimiters.top(); - for(T excludedGroup : closed.getNestingExclusions()) { + final Multiset<T> currentForbidden = forbiddenDelimiters.top(); + for (final T excludedGroup : closed.getNestingExclusions()) { currentForbidden.remove(excludedGroup); whoForbid.remove(excludedGroup); @@ -233,19 +231,19 @@ public class SequenceDelimiter<T> { /* * Remove the nested opens from this group. */ - Multimap<T, T> currentAllowed = allowedDelimiters.top(); - for(Entry<T, T> closer : closed.getNestingOpeners().entrySet()) { + final Multimap<T, T> currentAllowed = allowedDelimiters.top(); + for (final Entry<T, T> closer : closed.getNestingOpeners().entrySet()) { currentAllowed.remove(closer.getKey(), closer.getValue()); } /* * Handle 'forgetful' groups that reset nesting. */ - if(closed.isForgetful()) { + if (closed.isForgetful()) { allowedDelimiters.drop(); forbiddenDelimiters.drop(); } - } else if(!groupStack.empty() && groupStack.top().marksSubgroup(tok)) { + } else if (!groupStack.empty() && groupStack.top().marksSubgroup(tok)) { groupStack.top().markSubgroup(tok, chars); } else { groupStack.top().addItem(new Tree<>(tok)); @@ -255,14 +253,15 @@ public class SequenceDelimiter<T> { /* * Error if not all groups were closed. */ - if(groupStack.size() > 1) { - DelimiterGroup<T>.OpenGroup group = groupStack.top(); + if (groupStack.size() > 1) { + final DelimiterGroup<T>.OpenGroup group = groupStack.top(); - StringBuilder msgBuilder = new StringBuilder(); + final StringBuilder msgBuilder = new StringBuilder(); - String closingDelims = StringUtils.toEnglishList(group.getNestingExclusions().toArray(), false); + final String closingDelims = StringUtils.toEnglishList(group.getNestingExclusions().toArray(), + false); - String ctxList = StringUtils.toEnglishList(groupStack.toArray(), "then"); + final String ctxList = StringUtils.toEnglishList(groupStack.toArray(), "then"); msgBuilder.append("Unclosed group '"); msgBuilder.append(group.getName()); @@ -277,35 +276,34 @@ public class SequenceDelimiter<T> { return groupStack.pop().toTree(chars.root, chars); } - private boolean isForbidden(Stack<DelimiterGroup<T>.OpenGroup> groupStack, - Stack<Multiset<T>> forbiddenDelimiters, T groupName) { + private boolean isForbidden(final Stack<DelimiterGroup<T>.OpenGroup> groupStack, + final Stack<Multiset<T>> forbiddenDelimiters, final T groupName) { boolean localForbid; - if(groupStack.empty()) + if (groupStack.empty()) { localForbid = false; - else + } else { localForbid = groupStack.top().excludes(groupName); + } return localForbid || forbiddenDelimiters.top().contains(groupName); } /** * Add a delimiter group. - * + * * @param group * The delimiter group. */ - public void addGroup(DelimiterGroup<T> group) { - if(group == null) { - throw new NullPointerException("Group must not be null"); - } + public void addGroup(final DelimiterGroup<T> group) { + if (group == null) throw new NullPointerException("Group must not be null"); groups.put(group.groupName, group); } /** * Creates and adds a delimiter group using the provided settings. - * + * * @param openers * The tokens that open this group * @param groupName @@ -313,31 +311,31 @@ public class SequenceDelimiter<T> { * @param closers * The tokens that close this group */ - public void addGroup(T[] openers, T groupName, @SuppressWarnings("unchecked") T... closers) { - DelimiterGroup<T> group = new DelimiterGroup<>(groupName); + public void addGroup(final T[] openers, final T groupName, @SuppressWarnings("unchecked") final T... closers) { + final DelimiterGroup<T> group = new DelimiterGroup<>(groupName); group.addClosing(closers); addGroup(group); - for(T open : openers) { + for (final T open : openers) { group.addOpener(open, groupName); } } @Override public String toString() { - StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(); builder.append("SequenceDelimiter ["); - if(groups != null) { + if (groups != null) { builder.append("groups="); builder.append(groups); builder.append(","); } - if(initialGroup != null) { + if (initialGroup != null) { builder.append("initialGroup="); builder.append(initialGroup); } @@ -349,11 +347,11 @@ public class SequenceDelimiter<T> { /** * Set the initial group of this delimiter. - * + * * @param initialGroup * The initial group of this delimiter. */ - public void setInitialGroup(DelimiterGroup<T> initialGroup) { + public void setInitialGroup(final DelimiterGroup<T> initialGroup) { this.initialGroup = initialGroup; } } |
