summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'BJC-Utils2/src/main')
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/data/Tree.java75
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/funcutils/ListUtils.java4
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/DefaultLeftCommand.java17
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/DefaultNullCommand.java25
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/InitialCommand.java (renamed from BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/NullCommand.java)6
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/LeftCommands.java320
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/NonInitialCommand.java (renamed from BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/LeftCommand.java)4
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/NullCommands.java207
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/PrattParser.java83
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/AbstractInitialCommand.java19
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/BinaryCommand.java23
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/BinaryPostCommand.java19
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/ChainCommand.java47
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/ConstantCommand.java21
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DefaultInitialCommand.java28
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DefaultNonInitialCommand.java34
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DelimitedCommand.java65
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/GroupingCommand.java30
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/InitialCommands.java134
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/LeafCommand.java17
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/LeftBinaryCommand.java12
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/NonBinaryCommand.java17
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/NonInitialCommands.java134
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/PostCircumfixCommand.java32
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/PostfixCommand.java19
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/PreTernaryCommand.java45
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/RightBinaryCommand.java12
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/TernaryCommand.java47
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/UnaryCommand.java23
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/splitter/SimpleTokenSplitter.java (renamed from BJC-Utils2/src/main/java/bjc/utils/parserutils/TokenSplitter.java)30
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/splitter/TokenSplitter.java26
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/splitter/TwoLevelSplitter.java110
32 files changed, 1015 insertions, 670 deletions
diff --git a/BJC-Utils2/src/main/java/bjc/utils/data/Tree.java b/BJC-Utils2/src/main/java/bjc/utils/data/Tree.java
index cef9d51..3f8d258 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/data/Tree.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/data/Tree.java
@@ -51,6 +51,8 @@ public class Tree<ContainedType> implements ITree<ContainedType> {
public Tree(ContainedType leaf, IList<ITree<ContainedType>> childrn) {
this(leaf);
+ hasChildren = true;
+
childCount = childrn.getSize();
children = childrn;
@@ -74,7 +76,7 @@ public class Tree<ContainedType> implements ITree<ContainedType> {
children = new FunctionalList<>();
- for (ITree<ContainedType> child : childrn) {
+ for(ITree<ContainedType> child : childrn) {
children.add(child);
childCount++;
@@ -83,7 +85,7 @@ public class Tree<ContainedType> implements ITree<ContainedType> {
@Override
public void addChild(ITree<ContainedType> child) {
- if (hasChildren == false) {
+ if(hasChildren == false) {
hasChildren = true;
children = new FunctionalList<>();
@@ -104,14 +106,14 @@ public class Tree<ContainedType> implements ITree<ContainedType> {
@Override
public void doForChildren(Consumer<ITree<ContainedType>> action) {
- if (childCount > 0) {
+ if(childCount > 0) {
children.forEach(action);
}
}
@Override
public ITree<ContainedType> flatMapTree(Function<ContainedType, ITree<ContainedType>> mapper) {
- if (hasChildren) {
+ if(hasChildren) {
ITree<ContainedType> flatMappedData = mapper.apply(data);
children.map((child) -> child.flatMapTree(mapper))
@@ -130,7 +132,7 @@ public class Tree<ContainedType> implements ITree<ContainedType> {
protected <NewType> NewType internalCollapse(Function<ContainedType, NewType> leafTransform,
Function<ContainedType, Function<IList<NewType>, NewType>> nodeCollapser) {
- if (hasChildren) {
+ if(hasChildren) {
Function<IList<NewType>, NewType> nodeTransformer = nodeCollapser.apply(data);
IList<NewType> collapsedChildren = children.map((child) -> {
@@ -147,7 +149,7 @@ public class Tree<ContainedType> implements ITree<ContainedType> {
}
protected void internalToString(StringBuilder builder, int indentLevel, boolean initial) {
- for (int i = 0; i < indentLevel; i++) {
+ for(int i = 0; i < indentLevel; i++) {
builder.append(">\t");
}
@@ -157,7 +159,7 @@ public class Tree<ContainedType> implements ITree<ContainedType> {
builder.append(data == null ? "(null)" : data.toString());
builder.append("\n");
- if (hasChildren) {
+ if(hasChildren) {
children.forEach((child) -> {
((Tree<ContainedType>) child).internalToString(builder, indentLevel + 1, false);
});
@@ -167,7 +169,7 @@ public class Tree<ContainedType> implements ITree<ContainedType> {
@Override
public <MappedType> ITree<MappedType> rebuildTree(Function<ContainedType, MappedType> leafTransformer,
Function<ContainedType, MappedType> operatorTransformer) {
- if (hasChildren) {
+ if(hasChildren) {
IList<ITree<MappedType>> mappedChildren = children.map((child) -> {
return child.rebuildTree(leafTransformer, operatorTransformer);
});
@@ -180,7 +182,7 @@ public class Tree<ContainedType> implements ITree<ContainedType> {
@Override
public void selectiveTransform(Predicate<ContainedType> nodePicker, UnaryOperator<ContainedType> transformer) {
- if (hasChildren) {
+ if(hasChildren) {
children.forEach((child) -> child.selectiveTransform(nodePicker, transformer));
} else {
data = transformer.apply(data);
@@ -192,11 +194,11 @@ public class Tree<ContainedType> implements ITree<ContainedType> {
UnaryOperator<ITree<ContainedType>> transformer) {
TopDownTransformResult transformResult = transformPicker.apply(data);
- switch (transformResult) {
+ switch(transformResult) {
case PASSTHROUGH:
ITree<ContainedType> result = new Tree<>(data);
- if (hasChildren) {
+ if(hasChildren) {
children.forEach((child) -> {
result.addChild(child.topDownTransform(transformPicker, transformer));
});
@@ -212,7 +214,7 @@ public class Tree<ContainedType> implements ITree<ContainedType> {
case PUSHDOWN:
result = new Tree<>(data);
- if (hasChildren) {
+ if(hasChildren) {
children.forEach((child) -> {
result.addChild(child.topDownTransform(transformPicker, transformer));
});
@@ -249,7 +251,7 @@ public class Tree<ContainedType> implements ITree<ContainedType> {
@Override
public <TransformedType> TransformedType transformChild(int childNo,
Function<ITree<ContainedType>, TransformedType> transformer) {
- if (childNo < 0 || childNo > childCount - 1)
+ if(childNo < 0 || childNo > childCount - 1)
throw new IllegalArgumentException("Child index #" + childNo + " is invalid");
return transformer.apply(children.getByIndex(childNo));
@@ -262,7 +264,7 @@ public class Tree<ContainedType> implements ITree<ContainedType> {
@Override
public <MappedType> ITree<MappedType> transformTree(Function<ContainedType, MappedType> transformer) {
- if (hasChildren) {
+ if(hasChildren) {
IList<ITree<MappedType>> transformedChildren = children
.map((child) -> child.transformTree(transformer));
@@ -274,12 +276,11 @@ public class Tree<ContainedType> implements ITree<ContainedType> {
@Override
public void traverse(TreeLinearizationMethod linearizationMethod, Consumer<ContainedType> action) {
- if (hasChildren) {
- switch (linearizationMethod) {
+ if(hasChildren) {
+ switch(linearizationMethod) {
case INORDER:
- if (childCount != 2)
- throw new IllegalArgumentException(
- "Can only do in-order traversal for binary trees.");
+ if(childCount != 2) throw new IllegalArgumentException(
+ "Can only do in-order traversal for binary trees.");
children.getByIndex(0).traverse(linearizationMethod, action);
@@ -320,40 +321,32 @@ public class Tree<ContainedType> implements ITree<ContainedType> {
@Override
public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
+ if(this == obj) return true;
+ if(obj == null) return false;
+ if(getClass() != obj.getClass()) return false;
Tree<?> other = (Tree<?>) obj;
- if (data == null) {
- if (other.data != null)
- return false;
- } else if (!data.equals(other.data))
- return false;
+ if(data == null) {
+ if(other.data != null) return false;
+ } else if(!data.equals(other.data)) return false;
- if (childCount != other.childCount)
- return false;
+ if(childCount != other.childCount) return false;
- if (children == null) {
- if (other.children != null)
- return false;
- } else if (!children.equals(other.children))
- return false;
+ if(children == null) {
+ if(other.children != null) return false;
+ } else if(!children.equals(other.children)) return false;
return true;
}
@Override
public int revFind(Predicate<ITree<ContainedType>> childPred) {
- if (childCount == 0) {
+ if(childCount == 0) {
return -1;
} else {
- for (int i = childCount - 1; i >= 0; i--) {
- if (childPred.test(getChild(i))) {
+ for(int i = childCount - 1; i >= 0; i--) {
+ if(childPred.test(getChild(i))) {
return i;
}
}
@@ -364,7 +357,7 @@ public class Tree<ContainedType> implements ITree<ContainedType> {
@Override
public void prependChild(ITree<ContainedType> child) {
- if (hasChildren == false) {
+ if(hasChildren == false) {
hasChildren = true;
children = new FunctionalList<>();
diff --git a/BJC-Utils2/src/main/java/bjc/utils/funcutils/ListUtils.java b/BJC-Utils2/src/main/java/bjc/utils/funcutils/ListUtils.java
index f55eb36..791598f 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/funcutils/ListUtils.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/funcutils/ListUtils.java
@@ -80,7 +80,7 @@ public class ListUtils {
* The affixes to remove
* @return The tokens that have been deaffixed
*
- * @deprecated Replaced by TokenSplitter.
+ * @deprecated Replaced by SimpleTokenSplitter.
*/
@Deprecated
public static IList<String> deAffixTokens(IList<String> input, Deque<IPair<String, String>> operators) {
@@ -301,7 +301,7 @@ public class ListUtils {
* those operators
* @return A list of tokens split on all the operators
*
- * @deprecated Use TokenSplitter now
+ * @deprecated Use SimpleTokenSplitter now
*/
@Deprecated
public static IList<String> splitTokens(IList<String> input, Deque<IPair<String, String>> operators) {
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/DefaultLeftCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/DefaultLeftCommand.java
deleted file mode 100644
index 24802a6..0000000
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/DefaultLeftCommand.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package bjc.utils.parserutils.pratt;
-
-import bjc.utils.data.ITree;
-
-class DefaultLeftCommand<K, V, C> extends LeftCommand<K, V, C> {
-
- @Override
- public ITree<Token<K, V>> leftDenote(ITree<Token<K, V>> operand, Token<K, V> operator, ParserContext<K, V, C> ctx) {
- throw new UnsupportedOperationException("Default command has no left denotation");
- }
-
- @Override
- public int leftBinding() {
- return -1;
- }
-
-}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/DefaultNullCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/DefaultNullCommand.java
deleted file mode 100644
index 04216f9..0000000
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/DefaultNullCommand.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package bjc.utils.parserutils.pratt;
-
-import bjc.utils.data.ITree;
-import bjc.utils.parserutils.ParserException;
-
-/**
- * Default implementation of null command.
- *
- * @author EVE
- *
- * @param <K>
- * The key type of the token.
- * @param <V>
- * The value type of the token.
- *
- * @param <C>
- * The state type of the parser.
- */
-public class DefaultNullCommand<K, V, C> extends NullCommand<K, V, C> {
- @Override
- public ITree<Token<K, V>> nullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
- throws ParserException {
- throw new ParserException("Unexpected token " + operator);
- }
-}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/NullCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/InitialCommand.java
index c105361..716b99e 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/NullCommand.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/InitialCommand.java
@@ -19,7 +19,8 @@ import bjc.utils.parserutils.ParserException;
*
*
*/
-public abstract class NullCommand<K, V, C> {
+@FunctionalInterface
+public interface InitialCommand<K, V, C> {
/**
* Construct the null denotation of this command.
*
@@ -33,6 +34,5 @@ public abstract class NullCommand<K, V, C> {
* @throws ParserException
* If something goes wrong during parsing.
*/
- public abstract ITree<Token<K, V>> nullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
- throws ParserException;
+ ITree<Token<K, V>> denote(Token<K, V> operator, ParserContext<K, V, C> ctx) throws ParserException;
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/LeftCommands.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/LeftCommands.java
deleted file mode 100644
index 82ec843..0000000
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/LeftCommands.java
+++ /dev/null
@@ -1,320 +0,0 @@
-package bjc.utils.parserutils.pratt;
-
-import bjc.utils.data.ITree;
-import bjc.utils.data.Tree;
-import bjc.utils.parserutils.ParserException;
-
-import java.util.Set;
-
-/**
- * Contains factory methods for producing common implementations of
- * {@link LeftCommand}
- *
- * @author EVE
- *
- */
-public class LeftCommands {
- /*
- * A command with constant binding power.
- */
- private static abstract class BinaryPostCommand<K, V, C> extends LeftCommand<K, V, C> {
- private final int leftPower;
-
- public BinaryPostCommand(int power) {
- leftPower = power;
- }
-
- @Override
- public int leftBinding() {
- return leftPower;
- }
- }
-
- private static abstract class BinaryCommand<K, V, C> extends BinaryPostCommand<K, V, C> {
- public BinaryCommand(int leftPower) {
- super(leftPower);
- }
-
- protected abstract int rightBinding();
-
- @Override
- public ITree<Token<K, V>> leftDenote(ITree<Token<K, V>> operand, Token<K, V> operator,
- ParserContext<K, V, C> ctx) throws ParserException {
- ITree<Token<K, V>> opr = ctx.parse.parseExpression(rightBinding(), ctx.tokens, ctx.state, false);
-
- return new Tree<>(operator, operand, opr);
- }
- }
-
- private static class LeftBinaryCommand<K, V, C> extends BinaryCommand<K, V, C> {
- public LeftBinaryCommand(int leftPower) {
- super(leftPower);
- }
-
- @Override
- protected int rightBinding() {
- return 1 + leftBinding();
- }
- }
-
- private static class RightBinaryCommand<K, V, C> extends BinaryCommand<K, V, C> {
- public RightBinaryCommand(int leftPower) {
- super(leftPower);
- }
-
- @Override
- protected int rightBinding() {
- return leftBinding();
- }
- }
-
- private static class NonBinaryCommand<K, V, C> extends BinaryCommand<K, V, C> {
- public NonBinaryCommand(int leftPower) {
- super(leftPower);
- }
-
- @Override
- protected int rightBinding() {
- return 1 + leftBinding();
- }
-
- @Override
- public int nextBinding() {
- return leftBinding() - 1;
- }
- }
-
- private static class PostCircumfixCommand<K, V, C> extends BinaryPostCommand<K, V, C> {
- private int insidePrec;
- private K term;
- private Token<K, V> mark;
-
- public PostCircumfixCommand(int leftPower, int insidePower, K terminator, Token<K, V> marker) {
- super(leftPower);
-
- insidePrec = insidePower;
- term = terminator;
- mark = marker;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public ITree<Token<K, V>> leftDenote(ITree<Token<K, V>> operand, Token<K, V> operator,
- ParserContext<K, V, C> ctx) throws ParserException {
- ITree<Token<K, V>> inside = ctx.parse.parseExpression(insidePrec, ctx.tokens, ctx.state, false);
-
- ctx.tokens.expect(term);
-
- return new Tree<>(mark, operand, inside);
- }
- }
-
- private static class PostfixCommand<K, V, C> extends BinaryPostCommand<K, V, C> {
- public PostfixCommand(int leftPower) {
- super(leftPower);
- }
-
- @Override
- public ITree<Token<K, V>> leftDenote(ITree<Token<K, V>> operand, Token<K, V> operator,
- ParserContext<K, V, C> ctx) throws ParserException {
- return new Tree<>(operator, operand);
- }
- }
-
- private static class TernaryCommand<K, V, C> extends BinaryPostCommand<K, V, C> {
- private K term;
-
- private int innerExp;
-
- private Token<K, V> mark;
-
- private boolean nonassoc;
-
- public TernaryCommand(int leftPower, K terminator, Token<K, V> marker, boolean isNonassoc) {
- super(leftPower);
-
- term = terminator;
- mark = marker;
- nonassoc = isNonassoc;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public ITree<Token<K, V>> leftDenote(ITree<Token<K, V>> operand, Token<K, V> operator,
- ParserContext<K, V, C> ctx) throws ParserException {
- ITree<Token<K, V>> inner = ctx.parse.parseExpression(innerExp, ctx.tokens, ctx.state, false);
-
- ctx.tokens.expect(term);
-
- ITree<Token<K, V>> outer = ctx.parse.parseExpression(1 + leftBinding(), ctx.tokens, ctx.state, false);
-
- return new Tree<>(mark, inner, operand, outer);
- }
-
- @Override
- public int nextBinding() {
- if (nonassoc) {
- return leftBinding() - 1;
- } else {
- return leftBinding();
- }
- }
- }
-
- private static class ChainCommand<K, V, C> extends BinaryPostCommand<K, V, C> {
- private Set<K> chainWith;
-
- private Token<K, V> chain;
-
- public ChainCommand(int leftPower, Set<K> chainSet, Token<K, V> chainMarker) {
- super(leftPower);
-
- chainWith = chainSet;
- chain = chainMarker;
- }
-
- @Override
- public ITree<Token<K, V>> leftDenote(ITree<Token<K, V>> operand, Token<K, V> operator,
- ParserContext<K, V, C> ctx) throws ParserException {
- ITree<Token<K, V>> tree = ctx.parse.parseExpression(1 + leftBinding(), ctx.tokens, ctx.state, false);
-
- ITree<Token<K, V>> res = new Tree<>(operator, operand, tree);
-
- if (chainWith.contains(ctx.tokens.current().getKey())) {
- Token<K, V> tok = ctx.tokens.current();
- ctx.tokens.next();
-
- ITree<Token<K, V>> other = leftDenote(tree, tok,
- new ParserContext<>(ctx.tokens, ctx.parse, ctx.state));
-
- return new Tree<>(chain, res, other);
- } else {
- return res;
- }
- }
-
- @Override
- public int nextBinding() {
- return leftBinding() - 1;
- }
- }
-
- /**
- * Create a left-associative infix operator.
- *
- * @param precedence
- * The precedence of the operator.
- *
- * @return A command implementing that operator.
- */
- public static <K, V, C> LeftCommand<K, V, C> infixLeft(int precedence) {
- return new LeftBinaryCommand<>(precedence);
- }
-
- /**
- * Create a right-associative infix operator.
- *
- * @param precedence
- * The precedence of the operator.
- *
- * @return A command implementing that operator.
- */
- public static <K, V, C> LeftCommand<K, V, C> infixRight(int precedence) {
- return new RightBinaryCommand<>(precedence);
- }
-
- /**
- * Create a non-associative infix operator.
- *
- * @param precedence
- * The precedence of the operator.
- *
- * @return A command implementing that operator.
- */
- public static <K, V, C> LeftCommand<K, V, C> infixNon(int precedence) {
- return new NonBinaryCommand<>(precedence);
- }
-
- /**
- * Create a chained operator.
- *
- * @param precedence
- * The precedence of the operator.
- *
- * @param chainSet
- * The operators it forms a chain with.
- *
- * @param marker
- * The token to use as the AST node for the chained
- * operators.
- *
- * @return A command implementing that operator.
- */
- public static <K, V, C> LeftCommand<K, V, C> chain(int precedence, Set<K> chainSet, Token<K, V> marker) {
- return new ChainCommand<>(precedence, chainSet, marker);
- }
-
- /**
- * Create a postfix operator.
- *
- * @param precedence
- * The precedence of the operator.
- *
- * @return A command implementing that operator.
- */
- public static <K, V, C> LeftCommand<K, V, C> postfix(int precedence) {
- return new PostfixCommand<>(precedence);
- }
-
- /**
- * Create a post-circumfix operator.
- *
- * This is an operator in form similar to array indexing.
- *
- * @param precedence
- * The precedence of this operator
- *
- * @param insidePrecedence
- * The precedence of the expression inside the operator
- *
- * @param closer
- * The token that closes the circumfix.
- *
- * @param marker
- * The token to use as the AST node for the operator.
- *
- * @return A command implementing that operator.
- */
- public static <K, V, C> LeftCommand<K, V, C> postCircumfix(int precedence, int insidePrecedence, K closer,
- Token<K, V> marker) {
- return new PostCircumfixCommand<>(precedence, insidePrecedence, closer, marker);
- }
-
- /**
- * Create a ternary operator.
- *
- * This is like C's ?: operator.
- *
- * @param precedence
- * The precedence of the operator.
- *
- * @param insidePrecedence
- * The precedence of the inner section of the operator.
- *
- * @param closer
- * The token that marks the end of the inner section.
- *
- * @param marker
- * The token to use as the AST node for the operator.
- *
- * @param nonassoc
- * True if the command is non-associative, false
- * otherwise.
- *
- * @return A command implementing this operator.
- */
- public static <K, V, C> LeftCommand<K, V, C> ternary(int precedence, int insidePrecedence, K closer,
- Token<K, V> marker, boolean nonassoc) {
- return new TernaryCommand<>(insidePrecedence, closer, marker, nonassoc);
- }
-}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/LeftCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/NonInitialCommand.java
index 747c207..b6797d3 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/LeftCommand.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/NonInitialCommand.java
@@ -18,7 +18,7 @@ import bjc.utils.parserutils.ParserException;
* The state type of the parser.
*
*/
-public abstract class LeftCommand<K, V, C> {
+public abstract class NonInitialCommand<K, V, C> {
/**
* Construct the left denotation of this command.
*
@@ -35,7 +35,7 @@ public abstract class LeftCommand<K, V, C> {
* @throws ParserException
* If something went wrong during parsing.
*/
- public abstract ITree<Token<K, V>> leftDenote(ITree<Token<K, V>> operand, Token<K, V> operator,
+ public abstract ITree<Token<K, V>> denote(ITree<Token<K, V>> operand, Token<K, V> operator,
ParserContext<K, V, C> ctx) throws ParserException;
/**
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/NullCommands.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/NullCommands.java
deleted file mode 100644
index f0c2a80..0000000
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/NullCommands.java
+++ /dev/null
@@ -1,207 +0,0 @@
-package bjc.utils.parserutils.pratt;
-
-import bjc.utils.data.ITree;
-import bjc.utils.data.Tree;
-import bjc.utils.parserutils.ParserException;
-
-/**
- * * Contains factory methods for producing common implementations of
- * {@link NullCommand}
- *
- * @author EVE
- *
- */
-public class NullCommands {
- private static abstract class AbstractNullCommand<K, V, C> extends NullCommand<K, V, C> {
- @Override
- public ITree<Token<K, V>> nullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
- throws ParserException {
- // tokens.next();
-
- return intNullDenotation(operator, ctx);
- }
-
- protected abstract ITree<Token<K, V>> intNullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
- throws ParserException;
-
- }
-
- private static class UnaryCommand<K, V, C> extends AbstractNullCommand<K, V, C> {
- private final int nullPwer;
-
- public UnaryCommand(int nullPower) {
- nullPwer = nullPower;
- }
-
- @Override
- protected ITree<Token<K, V>> intNullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
- throws ParserException {
- ITree<Token<K, V>> opr = ctx.parse.parseExpression(nullPwer, ctx.tokens, ctx.state, false);
-
- return new Tree<>(operator, opr);
- }
- }
-
- private static class GroupingCommand<K, V, C> extends AbstractNullCommand<K, V, C> {
- private K term;
- private Token<K, V> mark;
- private int inner;
-
- public GroupingCommand(int innerPrec, K terminator, Token<K, V> marker) {
- inner = innerPrec;
- term = terminator;
- mark = marker;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- protected ITree<Token<K, V>> intNullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
- throws ParserException {
- ITree<Token<K, V>> opr = ctx.parse.parseExpression(inner, ctx.tokens, ctx.state, false);
-
- ctx.tokens.expect(term);
-
- return new Tree<>(mark, opr);
- }
- }
-
- private static class LeafCommand<K, V, C> extends NullCommand<K, V, C> {
- @Override
- public ITree<Token<K, V>> nullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
- throws ParserException {
-
- return new Tree<>(operator);
- }
- }
-
- private static class ConstantCommand<K, V, C> extends NullCommand<K, V, C> {
- private ITree<Token<K, V>> val;
-
- public ConstantCommand(ITree<Token<K, V>> con) {
- val = con;
- }
-
- @Override
- public ITree<Token<K, V>> nullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
- throws ParserException {
- return val;
- }
- }
-
- private static class PreTernaryCommand<K, V, C> extends AbstractNullCommand<K, V, C> {
- private int cond1;
- private int block1;
- private int block2;
-
- private K mark1;
- private K mark2;
-
- private Token<K, V> term;
-
- public PreTernaryCommand(int cond1, int block1, int block2, K mark1, K mark2, Token<K, V> term) {
- super();
- this.cond1 = cond1;
- this.block1 = block1;
- this.block2 = block2;
- this.mark1 = mark1;
- this.mark2 = mark2;
- this.term = term;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- protected ITree<Token<K, V>> intNullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
- throws ParserException {
- ITree<Token<K, V>> cond = ctx.parse.parseExpression(cond1, ctx.tokens, ctx.state, false);
-
- ctx.tokens.expect(mark1);
-
- ITree<Token<K, V>> fstBlock = ctx.parse.parseExpression(block1, ctx.tokens, ctx.state, false);
-
- ctx.tokens.expect(mark2);
-
- ITree<Token<K, V>> sndBlock = ctx.parse.parseExpression(block2, ctx.tokens, ctx.state, false);
-
- return new Tree<>(term, cond, fstBlock, sndBlock);
- }
- }
-
- /**
- * Create a new unary operator.
- *
- * @param precedence
- * The precedence of the operator.
- *
- * @return A command implementing that operator.
- */
- public static <K, V, C> NullCommand<K, V, C> unary(int precedence) {
- return new UnaryCommand<>(precedence);
- }
-
- /**
- * Create a new grouping operator.
- *
- * @param precedence
- * The precedence of the expression in the operator.
- *
- * @param term
- * The type that closes the group.
- *
- * @param mark
- * The token for the AST node of the group.
- *
- * @return A command implementing the operator.
- */
- public static <K, V, C> NullCommand<K, V, C> grouping(int precedence, K term, Token<K, V> mark) {
- return new GroupingCommand<>(precedence, term, mark);
- }
-
- /**
- * Create a new leaf operator.
- *
- * @return A command implementing the operator.
- */
- public static <K, V, C> NullCommand<K, V, C> leaf() {
- return new LeafCommand<>();
- }
-
- /**
- * Create a new pre-ternary operator, like an if-then-else statement.
- *
- * @param cond1
- * The priority of the first block.
- *
- * @param block1
- * The priority of the second block.
- *
- * @param block2
- * The priority of the third block.
- *
- * @param mark1
- * The marker that ends the first block.
- *
- * @param mark2
- * The marker that ends the second block.
- *
- * @param term
- * The token for the AST node of the group.
- *
- * @return A command implementing the operator.
- */
- public static <K, V, C> NullCommand<K, V, C> preTernary(int cond1, int block1, int block2, K mark1, K mark2,
- Token<K, V> term) {
- return new PreTernaryCommand<>(cond1, block1, block2, mark1, mark2, term);
- }
-
- /**
- * Create a new named constant.
- *
- * @param val
- * The value of the constant.
- *
- * @return A command implementing the constant.
- */
- public static <K, V, C> NullCommand<K, V, C> constant(ITree<Token<K, V>> val) {
- return new ConstantCommand<>(val);
- }
-}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/PrattParser.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/PrattParser.java
index a8c273d..e8543dc 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/PrattParser.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/PrattParser.java
@@ -3,6 +3,8 @@ package bjc.utils.parserutils.pratt;
import bjc.utils.data.ITree;
import bjc.utils.funcutils.NumberUtils;
import bjc.utils.parserutils.ParserException;
+import bjc.utils.parserutils.pratt.commands.DefaultNonInitialCommand;
+import bjc.utils.parserutils.pratt.commands.DefaultInitialCommand;
import java.util.HashMap;
import java.util.Map;
@@ -13,29 +15,29 @@ import java.util.Map;
* @author EVE
*
* @param <K>
- * The key type for the tokens.
+ * The key type for the tokens.
*
* @param <V>
- * The value type for the tokens.
+ * The value type for the tokens.
*
* @param <C>
- * The state type of the parser.
+ * The state type of the parser.
*
*
*/
public class PrattParser<K, V, C> {
- private final LeftCommand<K, V, C> DEFAULT_LEFT_COMMAND = new DefaultLeftCommand<>();
- private final NullCommand<K, V, C> DEFAULT_NULL_COMMAND = new DefaultNullCommand<>();
+ private final NonInitialCommand<K, V, C> DEFAULT_LEFT_COMMAND = new DefaultNonInitialCommand<>();
+ private final InitialCommand<K, V, C> DEFAULT_NULL_COMMAND = new DefaultInitialCommand<>();
- private Map<K, LeftCommand<K, V, C>> leftCommands;
- private Map<K, NullCommand<K, V, C>> nullCommands;
- private Map<K, NullCommand<K, V, C>> statementCommands;
+ private Map<K, NonInitialCommand<K, V, C>> leftCommands;
+ private Map<K, InitialCommand<K, V, C>> nullCommands;
+ private Map<K, InitialCommand<K, V, C>> statementCommands;
/**
* Create a new Pratt parser.
*
* @param terminal
- * The terminal symbol.
+ * The terminal symbol.
*/
public PrattParser() {
leftCommands = new HashMap<>();
@@ -47,22 +49,25 @@ public class PrattParser<K, V, C> {
* Parse an expression.
*
* @param precedence
- * The initial precedence for the expression.
+ * The initial precedence for the expression.
*
* @param tokens
- * The tokens for the expression.
+ * The tokens for the expression.
*
* @param state
- * The state of the parser.
+ * The state of the parser.
+ *
+ * @param isStatement
+ * Whether or not to parse statements.
*
* @return The expression as an AST.
*
* @throws ParserException
- * If something goes wrong during parsing.
+ * If something goes wrong during parsing.
*/
- public ITree<Token<K, V>> parseExpression(int precedence, TokenStream<K, V> tokens, C state, boolean isStatement)
- throws ParserException {
- if (precedence < 0) {
+ public ITree<Token<K, V>> parseExpression(int precedence, TokenStream<K, V> tokens, C state,
+ boolean isStatement) throws ParserException {
+ if(precedence < 0) {
throw new IllegalArgumentException("Precedence must be greater than zero");
}
@@ -71,28 +76,28 @@ public class PrattParser<K, V, C> {
ITree<Token<K, V>> ast;
- if (isStatement && statementCommands.containsKey(initToken.getKey())) {
- ast = statementCommands.getOrDefault(initToken.getKey(), DEFAULT_NULL_COMMAND).nullDenotation(initToken,
- new ParserContext<>(tokens, this, state));
+ if(isStatement && statementCommands.containsKey(initToken.getKey())) {
+ ast = statementCommands.getOrDefault(initToken.getKey(), DEFAULT_NULL_COMMAND)
+ .denote(initToken, new ParserContext<>(tokens, this, state));
} else {
- ast = nullCommands.getOrDefault(initToken.getKey(), DEFAULT_NULL_COMMAND).nullDenotation(initToken,
- new ParserContext<>(tokens, this, state));
+ ast = nullCommands.getOrDefault(initToken.getKey(), DEFAULT_NULL_COMMAND)
+ .denote(initToken, new ParserContext<>(tokens, this, state));
}
int rightPrec = Integer.MAX_VALUE;
- while (true) {
+ while(true) {
Token<K, V> tok = tokens.current();
K key = tok.getKey();
- LeftCommand<K, V, C> command = leftCommands.getOrDefault(key, DEFAULT_LEFT_COMMAND);
+ NonInitialCommand<K, V, C> command = leftCommands.getOrDefault(key, DEFAULT_LEFT_COMMAND);
int leftBind = command.leftBinding();
- if (NumberUtils.between(precedence, rightPrec, leftBind)) {
+ if(NumberUtils.between(precedence, rightPrec, leftBind)) {
tokens.next();
- ast = command.leftDenote(ast, tok, new ParserContext<>(tokens, this, state));
+ ast = command.denote(ast, tok, new ParserContext<>(tokens, this, state));
rightPrec = command.nextBinding();
} else {
break;
@@ -106,12 +111,12 @@ public class PrattParser<K, V, C> {
* Add a non-initial command to this parser.
*
* @param marker
- * The key that marks the command.
+ * The key that marks the command.
*
* @param comm
- * The command.
+ * The command.
*/
- public void addNonInitialCommand(K marker, LeftCommand<K, V, C> comm) {
+ public void addNonInitialCommand(K marker, NonInitialCommand<K, V, C> comm) {
leftCommands.put(marker, comm);
}
@@ -119,12 +124,28 @@ public class PrattParser<K, V, C> {
* Add a initial command to this parser.
*
* @param marker
- * The key that marks the command.
+ * The key that marks the command.
*
* @param comm
- * The command.
+ * The command.
*/
- public void addInitialCommand(K marker, NullCommand<K, V, C> comm) {
+ public void addInitialCommand(K marker, InitialCommand<K, V, C> comm) {
nullCommands.put(marker, comm);
}
+
+ /**
+ * Add a statement command to this parser.
+ *
+ * The difference between statements and initial commands is that
+ * statements can only appear at the start of the expression.
+ *
+ * @param marker
+ * The key that marks the command.
+ *
+ * @param comm
+ * The command.
+ */
+ public void addStatementCommand(K marker, InitialCommand<K, V, C> comm) {
+ statementCommands.put(marker, comm);
+ }
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/AbstractInitialCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/AbstractInitialCommand.java
new file mode 100644
index 0000000..b263422
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/AbstractInitialCommand.java
@@ -0,0 +1,19 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.data.ITree;
+import bjc.utils.parserutils.ParserException;
+import bjc.utils.parserutils.pratt.InitialCommand;
+import bjc.utils.parserutils.pratt.ParserContext;
+import bjc.utils.parserutils.pratt.Token;
+
+public abstract class AbstractInitialCommand<K, V, C> implements InitialCommand<K, V, C> {
+ @Override
+ public ITree<Token<K, V>> denote(Token<K, V> operator, ParserContext<K, V, C> ctx)
+ throws ParserException {
+ return intNullDenotation(operator, ctx);
+ }
+
+ protected abstract ITree<Token<K, V>> intNullDenotation(Token<K, V> operator,
+ ParserContext<K, V, C> ctx) throws ParserException;
+
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/BinaryCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/BinaryCommand.java
new file mode 100644
index 0000000..bf6786b
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/BinaryCommand.java
@@ -0,0 +1,23 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+import bjc.utils.parserutils.pratt.ParserContext;
+import bjc.utils.parserutils.pratt.Token;
+
+public abstract class BinaryCommand<K, V, C> extends BinaryPostCommand<K, V, C> {
+ public BinaryCommand(int leftPower) {
+ super(leftPower);
+ }
+
+ protected abstract int rightBinding();
+
+ @Override
+ public ITree<Token<K, V>> denote(ITree<Token<K, V>> operand, Token<K, V> operator,
+ ParserContext<K, V, C> ctx) throws ParserException {
+ ITree<Token<K, V>> opr = ctx.parse.parseExpression(rightBinding(), ctx.tokens, ctx.state, false);
+
+ return new Tree<>(operator, operand, opr);
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/BinaryPostCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/BinaryPostCommand.java
new file mode 100644
index 0000000..7aaf735
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/BinaryPostCommand.java
@@ -0,0 +1,19 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.parserutils.pratt.NonInitialCommand;
+
+/*
+ * A command with constant binding power.
+ */
+public abstract class BinaryPostCommand<K, V, C> extends NonInitialCommand<K, V, C> {
+ private final int leftPower;
+
+ public BinaryPostCommand(int power) {
+ leftPower = power;
+ }
+
+ @Override
+ public int leftBinding() {
+ return leftPower;
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/ChainCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/ChainCommand.java
new file mode 100644
index 0000000..aa85f75
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/ChainCommand.java
@@ -0,0 +1,47 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+import bjc.utils.parserutils.pratt.ParserContext;
+import bjc.utils.parserutils.pratt.Token;
+
+import java.util.Set;
+
+public class ChainCommand<K, V, C> extends BinaryPostCommand<K, V, C> {
+ private Set<K> chainWith;
+
+ private Token<K, V> chain;
+
+ public ChainCommand(int leftPower, Set<K> chainSet, Token<K, V> chainMarker) {
+ super(leftPower);
+
+ chainWith = chainSet;
+ chain = chainMarker;
+ }
+
+ @Override
+ public ITree<Token<K, V>> denote(ITree<Token<K, V>> operand, Token<K, V> operator,
+ ParserContext<K, V, C> ctx) throws ParserException {
+ ITree<Token<K, V>> tree = ctx.parse.parseExpression(1 + leftBinding(), ctx.tokens, ctx.state, false);
+
+ ITree<Token<K, V>> res = new Tree<>(operator, operand, tree);
+
+ if (chainWith.contains(ctx.tokens.current().getKey())) {
+ Token<K, V> tok = ctx.tokens.current();
+ ctx.tokens.next();
+
+ ITree<Token<K, V>> other = denote(tree, tok,
+ new ParserContext<>(ctx.tokens, ctx.parse, ctx.state));
+
+ return new Tree<>(chain, res, other);
+ } else {
+ return res;
+ }
+ }
+
+ @Override
+ public int nextBinding() {
+ return leftBinding() - 1;
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/ConstantCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/ConstantCommand.java
new file mode 100644
index 0000000..2308cc7
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/ConstantCommand.java
@@ -0,0 +1,21 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.data.ITree;
+import bjc.utils.parserutils.ParserException;
+import bjc.utils.parserutils.pratt.InitialCommand;
+import bjc.utils.parserutils.pratt.ParserContext;
+import bjc.utils.parserutils.pratt.Token;
+
+public class ConstantCommand<K, V, C> implements InitialCommand<K, V, C> {
+ private ITree<Token<K, V>> val;
+
+ public ConstantCommand(ITree<Token<K, V>> con) {
+ val = con;
+ }
+
+ @Override
+ public ITree<Token<K, V>> denote(Token<K, V> operator, ParserContext<K, V, C> ctx)
+ throws ParserException {
+ return val;
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DefaultInitialCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DefaultInitialCommand.java
new file mode 100644
index 0000000..7409755
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DefaultInitialCommand.java
@@ -0,0 +1,28 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.data.ITree;
+import bjc.utils.parserutils.ParserException;
+import bjc.utils.parserutils.pratt.InitialCommand;
+import bjc.utils.parserutils.pratt.ParserContext;
+import bjc.utils.parserutils.pratt.Token;
+
+/**
+ * Default implementation of an initial command.
+ *
+ * @author EVE
+ *
+ * @param <K>
+ * The key type of the token.
+ *
+ * @param <V>
+ * The value type of the token.
+ *
+ * @param <C>
+ * The state type of the parser.
+ */
+public class DefaultInitialCommand<K, V, C> implements InitialCommand<K, V, C> {
+ @Override
+ public ITree<Token<K, V>> denote(Token<K, V> operator, ParserContext<K, V, C> ctx) throws ParserException {
+ throw new ParserException("Unexpected token " + operator);
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DefaultNonInitialCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DefaultNonInitialCommand.java
new file mode 100644
index 0000000..8c500a9
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DefaultNonInitialCommand.java
@@ -0,0 +1,34 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.data.ITree;
+import bjc.utils.parserutils.pratt.NonInitialCommand;
+import bjc.utils.parserutils.pratt.ParserContext;
+import bjc.utils.parserutils.pratt.Token;
+
+/**
+ * Default implementation of a non-initial command.
+ *
+ * @author EVE
+ *
+ * @param <K>
+ * The key type of the tokens.
+ *
+ * @param <V>
+ * The value type of the tokens.
+ *
+ * @param <C>
+ * The state type of the parser.
+ */
+public class DefaultNonInitialCommand<K, V, C> extends NonInitialCommand<K, V, C> {
+
+ @Override
+ public ITree<Token<K, V>> denote(ITree<Token<K, V>> operand, Token<K, V> operator, ParserContext<K, V, C> ctx) {
+ throw new UnsupportedOperationException("Default command has no left denotation");
+ }
+
+ @Override
+ public int leftBinding() {
+ return -1;
+ }
+
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DelimitedCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DelimitedCommand.java
new file mode 100644
index 0000000..090b2f4
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DelimitedCommand.java
@@ -0,0 +1,65 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.funcdata.FunctionalList;
+import bjc.utils.funcdata.IList;
+import bjc.utils.parserutils.ParserException;
+import bjc.utils.parserutils.pratt.ParserContext;
+import bjc.utils.parserutils.pratt.Token;
+
+import java.util.function.UnaryOperator;
+
+public class DelimitedCommand<K, V, C> extends AbstractInitialCommand<K, V, C> {
+ private int inner;
+
+ private K delim;
+ private K mark;
+
+ private Token<K, V> term;
+
+ private UnaryOperator<C> onEnter;
+ private UnaryOperator<C> onDelim;
+ private UnaryOperator<C> onExit;
+
+ private boolean statement;
+
+ public DelimitedCommand(int inner, K delim, K mark, Token<K, V> term, UnaryOperator<C> onEnter,
+ UnaryOperator<C> onDelim, UnaryOperator<C> onExit, boolean statement) {
+ this.inner = inner;
+ this.delim = delim;
+ this.mark = mark;
+ this.term = term;
+ this.onEnter = onEnter;
+ this.onDelim = onDelim;
+ this.onExit = onExit;
+ this.statement = statement;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected ITree<Token<K, V>> intNullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
+ throws ParserException {
+ C newState = onEnter.apply(ctx.state);
+
+ IList<ITree<Token<K, V>>> kids = new FunctionalList<>();
+
+ while(true) {
+ ITree<Token<K, V>> kid = ctx.parse.parseExpression(inner, ctx.tokens, newState,
+ statement);
+ kids.add(kid);
+
+ Token<K, V> tok = ctx.tokens.current();
+
+ ctx.tokens.expect(delim, mark);
+
+ if(tok.getKey().equals(mark)) break;
+
+ newState = onDelim.apply(newState);
+ }
+
+ ctx.state = onExit.apply(newState);
+
+ return new Tree<>(term, kids);
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/GroupingCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/GroupingCommand.java
new file mode 100644
index 0000000..407a39e
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/GroupingCommand.java
@@ -0,0 +1,30 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+import bjc.utils.parserutils.pratt.ParserContext;
+import bjc.utils.parserutils.pratt.Token;
+
+public class GroupingCommand<K, V, C> extends AbstractInitialCommand<K, V, C> {
+ private K term;
+ private Token<K, V> mark;
+ private int inner;
+
+ public GroupingCommand(int innerPrec, K terminator, Token<K, V> marker) {
+ inner = innerPrec;
+ term = terminator;
+ mark = marker;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected ITree<Token<K, V>> intNullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
+ throws ParserException {
+ ITree<Token<K, V>> opr = ctx.parse.parseExpression(inner, ctx.tokens, ctx.state, false);
+
+ ctx.tokens.expect(term);
+
+ return new Tree<>(mark, opr);
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/InitialCommands.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/InitialCommands.java
new file mode 100644
index 0000000..d9e7f90
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/InitialCommands.java
@@ -0,0 +1,134 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.data.ITree;
+import bjc.utils.parserutils.pratt.InitialCommand;
+import bjc.utils.parserutils.pratt.Token;
+
+import java.util.function.UnaryOperator;
+
+/**
+ * * Contains factory methods for producing common implementations of
+ * {@link InitialCommand}
+ *
+ * @author EVE
+ *
+ */
+public class InitialCommands {
+ /**
+ * Create a new unary operator.
+ *
+ * @param precedence
+ * The precedence of the operator.
+ *
+ * @return A command implementing that operator.
+ */
+ public static <K, V, C> InitialCommand<K, V, C> unary(int precedence) {
+ return new UnaryCommand<>(precedence);
+ }
+
+ /**
+ * Create a new grouping operator.
+ *
+ * @param precedence
+ * The precedence of the expression in the operator.
+ *
+ * @param term
+ * The type that closes the group.
+ *
+ * @param mark
+ * The token for the AST node of the group.
+ *
+ * @return A command implementing the operator.
+ */
+ public static <K, V, C> InitialCommand<K, V, C> grouping(int precedence, K term, Token<K, V> mark) {
+ return new GroupingCommand<>(precedence, term, mark);
+ }
+
+ /**
+ * Create a new leaf operator.
+ *
+ * @return A command implementing the operator.
+ */
+ public static <K, V, C> InitialCommand<K, V, C> leaf() {
+ return new LeafCommand<>();
+ }
+
+ /**
+ * Create a new pre-ternary operator, like an if-then-else statement.
+ *
+ * @param cond1
+ * The priority of the first block.
+ *
+ * @param block1
+ * The priority of the second block.
+ *
+ * @param block2
+ * The priority of the third block.
+ *
+ * @param mark1
+ * The marker that ends the first block.
+ *
+ * @param mark2
+ * The marker that ends the second block.
+ *
+ * @param term
+ * The token for the AST node of the group.
+ *
+ * @return A command implementing the operator.
+ */
+ public static <K, V, C> InitialCommand<K, V, C> preTernary(int cond1, int block1, int block2, K mark1, K mark2,
+ Token<K, V> term) {
+ return new PreTernaryCommand<>(cond1, block1, block2, mark1, mark2, term);
+ }
+
+ /**
+ * Create a new named constant.
+ *
+ * @param val
+ * The value of the constant.
+ *
+ * @return A command implementing the constant.
+ */
+ public static <K, V, C> InitialCommand<K, V, C> constant(ITree<Token<K, V>> val) {
+ return new ConstantCommand<>(val);
+ }
+
+ /**
+ * Create a new delimited command. This is for block-like constructs.
+ *
+ * @param inner
+ * The precedence of the inner blocks.
+ *
+ * @param delim
+ * The marker between sub-blocks.
+ *
+ * @param mark
+ * The block terminator.
+ *
+ * @param term
+ * The token for the AST node of the group.
+ *
+ * @param onEnter
+ * The function to apply to the state on entering the
+ * block.
+ *
+ * @param onDelim
+ * The function to apply to the state on finishing a
+ * sub-block.
+ *
+ * @param onExit
+ * The function to apply to the state on exiting the
+ * block.
+ *
+ * @param statement
+ * Whether or not the sub-blocks are statements or
+ * expressions.
+ *
+ * @return A command implementing the operator.
+ */
+ public static <K, V, C> InitialCommand<K, V, C> delimited(int inner, K delim, K mark, Token<K, V> term,
+ UnaryOperator<C> onEnter, UnaryOperator<C> onDelim, UnaryOperator<C> onExit,
+ boolean statement) {
+ return new DelimitedCommand<>(inner, delim, mark, term, onEnter, onDelim, onExit, statement);
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/LeafCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/LeafCommand.java
new file mode 100644
index 0000000..87fe7c1
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/LeafCommand.java
@@ -0,0 +1,17 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+import bjc.utils.parserutils.pratt.InitialCommand;
+import bjc.utils.parserutils.pratt.ParserContext;
+import bjc.utils.parserutils.pratt.Token;
+
+public class LeafCommand<K, V, C> implements InitialCommand<K, V, C> {
+ @Override
+ public ITree<Token<K, V>> denote(Token<K, V> operator, ParserContext<K, V, C> ctx)
+ throws ParserException {
+
+ return new Tree<>(operator);
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/LeftBinaryCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/LeftBinaryCommand.java
new file mode 100644
index 0000000..1306735
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/LeftBinaryCommand.java
@@ -0,0 +1,12 @@
+package bjc.utils.parserutils.pratt.commands;
+
+public class LeftBinaryCommand<K, V, C> extends BinaryCommand<K, V, C> {
+ public LeftBinaryCommand(int leftPower) {
+ super(leftPower);
+ }
+
+ @Override
+ protected int rightBinding() {
+ return 1 + leftBinding();
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/NonBinaryCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/NonBinaryCommand.java
new file mode 100644
index 0000000..36ea0e1
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/NonBinaryCommand.java
@@ -0,0 +1,17 @@
+package bjc.utils.parserutils.pratt.commands;
+
+public class NonBinaryCommand<K, V, C> extends BinaryCommand<K, V, C> {
+ public NonBinaryCommand(int leftPower) {
+ super(leftPower);
+ }
+
+ @Override
+ protected int rightBinding() {
+ return 1 + leftBinding();
+ }
+
+ @Override
+ public int nextBinding() {
+ return leftBinding() - 1;
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/NonInitialCommands.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/NonInitialCommands.java
new file mode 100644
index 0000000..086ecf8
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/NonInitialCommands.java
@@ -0,0 +1,134 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.parserutils.pratt.NonInitialCommand;
+import bjc.utils.parserutils.pratt.Token;
+
+import java.util.Set;
+
+/**
+ * Contains factory methods for producing common implementations of
+ * {@link NonInitialCommand}
+ *
+ * @author EVE
+ *
+ */
+public class NonInitialCommands {
+ /**
+ * Create a left-associative infix operator.
+ *
+ * @param precedence
+ * The precedence of the operator.
+ *
+ * @return A command implementing that operator.
+ */
+ public static <K, V, C> NonInitialCommand<K, V, C> infixLeft(int precedence) {
+ return new LeftBinaryCommand<>(precedence);
+ }
+
+ /**
+ * Create a right-associative infix operator.
+ *
+ * @param precedence
+ * The precedence of the operator.
+ *
+ * @return A command implementing that operator.
+ */
+ public static <K, V, C> NonInitialCommand<K, V, C> infixRight(int precedence) {
+ return new RightBinaryCommand<>(precedence);
+ }
+
+ /**
+ * Create a non-associative infix operator.
+ *
+ * @param precedence
+ * The precedence of the operator.
+ *
+ * @return A command implementing that operator.
+ */
+ public static <K, V, C> NonInitialCommand<K, V, C> infixNon(int precedence) {
+ return new NonBinaryCommand<>(precedence);
+ }
+
+ /**
+ * Create a chained operator.
+ *
+ * @param precedence
+ * The precedence of the operator.
+ *
+ * @param chainSet
+ * The operators it forms a chain with.
+ *
+ * @param marker
+ * The token to use as the AST node for the chained
+ * operators.
+ *
+ * @return A command implementing that operator.
+ */
+ public static <K, V, C> NonInitialCommand<K, V, C> chain(int precedence, Set<K> chainSet, Token<K, V> marker) {
+ return new ChainCommand<>(precedence, chainSet, marker);
+ }
+
+ /**
+ * Create a postfix operator.
+ *
+ * @param precedence
+ * The precedence of the operator.
+ *
+ * @return A command implementing that operator.
+ */
+ public static <K, V, C> NonInitialCommand<K, V, C> postfix(int precedence) {
+ return new PostfixCommand<>(precedence);
+ }
+
+ /**
+ * Create a post-circumfix operator.
+ *
+ * This is an operator in form similar to array indexing.
+ *
+ * @param precedence
+ * The precedence of this operator
+ *
+ * @param insidePrecedence
+ * The precedence of the expression inside the operator
+ *
+ * @param closer
+ * The token that closes the circumfix.
+ *
+ * @param marker
+ * The token to use as the AST node for the operator.
+ *
+ * @return A command implementing that operator.
+ */
+ public static <K, V, C> NonInitialCommand<K, V, C> postCircumfix(int precedence, int insidePrecedence, K closer,
+ Token<K, V> marker) {
+ return new PostCircumfixCommand<>(precedence, insidePrecedence, closer, marker);
+ }
+
+ /**
+ * Create a ternary operator.
+ *
+ * This is like C's ?: operator.
+ *
+ * @param precedence
+ * The precedence of the operator.
+ *
+ * @param insidePrecedence
+ * The precedence of the inner section of the operator.
+ *
+ * @param closer
+ * The token that marks the end of the inner section.
+ *
+ * @param marker
+ * The token to use as the AST node for the operator.
+ *
+ * @param nonassoc
+ * True if the command is non-associative, false
+ * otherwise.
+ *
+ * @return A command implementing this operator.
+ */
+ public static <K, V, C> NonInitialCommand<K, V, C> ternary(int precedence, int insidePrecedence, K closer,
+ Token<K, V> marker, boolean nonassoc) {
+ return new TernaryCommand<>(insidePrecedence, closer, marker, nonassoc);
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/PostCircumfixCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/PostCircumfixCommand.java
new file mode 100644
index 0000000..ba5099e
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/PostCircumfixCommand.java
@@ -0,0 +1,32 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+import bjc.utils.parserutils.pratt.ParserContext;
+import bjc.utils.parserutils.pratt.Token;
+
+public class PostCircumfixCommand<K, V, C> extends BinaryPostCommand<K, V, C> {
+ private int insidePrec;
+ private K term;
+ private Token<K, V> mark;
+
+ public PostCircumfixCommand(int leftPower, int insidePower, K terminator, Token<K, V> marker) {
+ super(leftPower);
+
+ insidePrec = insidePower;
+ term = terminator;
+ mark = marker;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public ITree<Token<K, V>> denote(ITree<Token<K, V>> operand, Token<K, V> operator,
+ ParserContext<K, V, C> ctx) throws ParserException {
+ ITree<Token<K, V>> inside = ctx.parse.parseExpression(insidePrec, ctx.tokens, ctx.state, false);
+
+ ctx.tokens.expect(term);
+
+ return new Tree<>(mark, operand, inside);
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/PostfixCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/PostfixCommand.java
new file mode 100644
index 0000000..19c540a
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/PostfixCommand.java
@@ -0,0 +1,19 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+import bjc.utils.parserutils.pratt.ParserContext;
+import bjc.utils.parserutils.pratt.Token;
+
+public class PostfixCommand<K, V, C> extends BinaryPostCommand<K, V, C> {
+ public PostfixCommand(int leftPower) {
+ super(leftPower);
+ }
+
+ @Override
+ public ITree<Token<K, V>> denote(ITree<Token<K, V>> operand, Token<K, V> operator,
+ ParserContext<K, V, C> ctx) throws ParserException {
+ return new Tree<>(operator, operand);
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/PreTernaryCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/PreTernaryCommand.java
new file mode 100644
index 0000000..04604be
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/PreTernaryCommand.java
@@ -0,0 +1,45 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+import bjc.utils.parserutils.pratt.ParserContext;
+import bjc.utils.parserutils.pratt.Token;
+
+public class PreTernaryCommand<K, V, C> extends AbstractInitialCommand<K, V, C> {
+ private int cond1;
+ private int block1;
+ private int block2;
+
+ private K mark1;
+ private K mark2;
+
+ private Token<K, V> term;
+
+ public PreTernaryCommand(int cond1, int block1, int block2, K mark1, K mark2, Token<K, V> term) {
+ super();
+ this.cond1 = cond1;
+ this.block1 = block1;
+ this.block2 = block2;
+ this.mark1 = mark1;
+ this.mark2 = mark2;
+ this.term = term;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected ITree<Token<K, V>> intNullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
+ throws ParserException {
+ ITree<Token<K, V>> cond = ctx.parse.parseExpression(cond1, ctx.tokens, ctx.state, false);
+
+ ctx.tokens.expect(mark1);
+
+ ITree<Token<K, V>> fstBlock = ctx.parse.parseExpression(block1, ctx.tokens, ctx.state, false);
+
+ ctx.tokens.expect(mark2);
+
+ ITree<Token<K, V>> sndBlock = ctx.parse.parseExpression(block2, ctx.tokens, ctx.state, false);
+
+ return new Tree<>(term, cond, fstBlock, sndBlock);
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/RightBinaryCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/RightBinaryCommand.java
new file mode 100644
index 0000000..729c33d
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/RightBinaryCommand.java
@@ -0,0 +1,12 @@
+package bjc.utils.parserutils.pratt.commands;
+
+public class RightBinaryCommand<K, V, C> extends BinaryCommand<K, V, C> {
+ public RightBinaryCommand(int leftPower) {
+ super(leftPower);
+ }
+
+ @Override
+ protected int rightBinding() {
+ return leftBinding();
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/TernaryCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/TernaryCommand.java
new file mode 100644
index 0000000..c3204b9
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/TernaryCommand.java
@@ -0,0 +1,47 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+import bjc.utils.parserutils.pratt.ParserContext;
+import bjc.utils.parserutils.pratt.Token;
+
+public class TernaryCommand<K, V, C> extends BinaryPostCommand<K, V, C> {
+ private K term;
+
+ private int innerExp;
+
+ private Token<K, V> mark;
+
+ private boolean nonassoc;
+
+ public TernaryCommand(int leftPower, K terminator, Token<K, V> marker, boolean isNonassoc) {
+ super(leftPower);
+
+ term = terminator;
+ mark = marker;
+ nonassoc = isNonassoc;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public ITree<Token<K, V>> denote(ITree<Token<K, V>> operand, Token<K, V> operator,
+ ParserContext<K, V, C> ctx) throws ParserException {
+ ITree<Token<K, V>> inner = ctx.parse.parseExpression(innerExp, ctx.tokens, ctx.state, false);
+
+ ctx.tokens.expect(term);
+
+ ITree<Token<K, V>> outer = ctx.parse.parseExpression(1 + leftBinding(), ctx.tokens, ctx.state, false);
+
+ return new Tree<>(mark, inner, operand, outer);
+ }
+
+ @Override
+ public int nextBinding() {
+ if (nonassoc) {
+ return leftBinding() - 1;
+ } else {
+ return leftBinding();
+ }
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/UnaryCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/UnaryCommand.java
new file mode 100644
index 0000000..9a79d21
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/UnaryCommand.java
@@ -0,0 +1,23 @@
+package bjc.utils.parserutils.pratt.commands;
+
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+import bjc.utils.parserutils.pratt.ParserContext;
+import bjc.utils.parserutils.pratt.Token;
+
+public class UnaryCommand<K, V, C> extends AbstractInitialCommand<K, V, C> {
+ private final int nullPwer;
+
+ public UnaryCommand(int nullPower) {
+ nullPwer = nullPower;
+ }
+
+ @Override
+ protected ITree<Token<K, V>> intNullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
+ throws ParserException {
+ ITree<Token<K, V>> opr = ctx.parse.parseExpression(nullPwer, ctx.tokens, ctx.state, false);
+
+ return new Tree<>(operator, opr);
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/TokenSplitter.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/splitter/SimpleTokenSplitter.java
index d2569d9..8b078a9 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/TokenSplitter.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/splitter/SimpleTokenSplitter.java
@@ -1,15 +1,16 @@
-package bjc.utils.parserutils;
+package bjc.utils.parserutils.splitter;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
/**
- * Split a string and keep given delimiters.
+ * Simple implementation of {@link TokenSplitter}
+ *
+ * @author EVE
*
- * @author Ben Culkin
*/
-public class TokenSplitter {
+public class SimpleTokenSplitter implements TokenSplitter {
/*
* This string is a format template for the delimiter matching regex
*
@@ -58,28 +59,13 @@ public class TokenSplitter {
/**
* Create a new token splitter.
*/
- public TokenSplitter() {
+ public SimpleTokenSplitter() {
delimSet = new HashSet<>();
multidelimSet = new HashSet<>();
exclusionSet = new HashSet<>();
}
- /**
- * Split a provided string using configured delimiters, and keeping the
- * delimiters.
- *
- * <p>
- * The splitter must be compiled first.
- * </p>
- *
- * @param inp
- * The string to split.
- *
- * @return The split string, including delimiters.
- *
- * @throws IllegalStateException
- * If the splitter isn't compiled.
- */
+ @Override
public String[] split(String inp) {
if(compPatt == null) throw new IllegalStateException("Token splitter has not been compiled yet");
@@ -200,7 +186,7 @@ public class TokenSplitter {
public String toString() {
StringBuilder builder = new StringBuilder();
- builder.append("TokenSplitter [");
+ builder.append("SimpleTokenSplitter [");
if(currPatt != null) {
builder.append("currPatt=");
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/splitter/TokenSplitter.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/splitter/TokenSplitter.java
new file mode 100644
index 0000000..e59d88e
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/splitter/TokenSplitter.java
@@ -0,0 +1,26 @@
+package bjc.utils.parserutils.splitter;
+
+/**
+ * Split a string and keep given delimiters.
+ *
+ * @author Ben Culkin
+ */
+public interface TokenSplitter {
+ /**
+ * Split a provided string using configured delimiters, and keeping the
+ * delimiters.
+ *
+ * <p>
+ * The splitter must be compiled first.
+ * </p>
+ *
+ * @param inp
+ * The string to split.
+ *
+ * @return The split string, including delimiters.
+ *
+ * @throws IllegalStateException
+ * If the splitter isn't compiled.
+ */
+ String[] split(String inp);
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/splitter/TwoLevelSplitter.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/splitter/TwoLevelSplitter.java
new file mode 100644
index 0000000..38f303d
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/splitter/TwoLevelSplitter.java
@@ -0,0 +1,110 @@
+package bjc.utils.parserutils.splitter;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * Implementation of a splitter that runs in two passes.
+ *
+ * This is useful because {@link SimpleTokenSplitter} doesn't like handling both
+ * <= and = without mangling them.
+ *
+ * The first pass splits on compound operators, which are built up from simple
+ * operators.
+ *
+ * The second pass removes simple operators.
+ *
+ * @author EVE
+ *
+ */
+public class TwoLevelSplitter implements TokenSplitter {
+ private SimpleTokenSplitter high;
+ private SimpleTokenSplitter low;
+
+ /**
+ * Create a new two level splitter.
+ */
+ public TwoLevelSplitter() {
+ high = new SimpleTokenSplitter();
+ low = new SimpleTokenSplitter();
+ }
+
+ @Override
+ public String[] split(String inp) {
+ List<String> ret = new ArrayList<>();
+
+ String[] partials = high.split(inp);
+
+ for(String partial : partials) {
+ String[] finals = low.split(partial);
+
+ for(String fin : finals) {
+ ret.add(fin);
+ }
+ }
+
+ return ret.toArray(new String[ret.size()]);
+ }
+
+ /**
+ * Adds compound operators to split on.
+ *
+ * @param delims
+ * The compound operators to split on.
+ */
+ public void addCompoundDelim(String... delims) {
+ for(String delim : delims) {
+ high.addDelimiter(delim);
+
+ low.addNonMatcher(Pattern.quote(delim));
+ }
+ }
+
+ /**
+ * Adds simple operators to split on.
+ *
+ * @param delims
+ * The simple operators to split on.
+ */
+ public void addSimpleDelim(String... delims) {
+ for(String delim : delims) {
+ low.addDelimiter(delim);
+ }
+ }
+
+ /**
+ * Adds repeated compound operators to split on.
+ *
+ * @param delims
+ * The repeated compound operators to split on.
+ */
+ public void addCompoundMulti(String... delims) {
+ for(String delim : delims) {
+ high.addMultiDelimiter(delim);
+
+ low.addNonMatcher("(?:" + delim + ")+");
+ }
+ }
+
+ /**
+ * Adds simple compound operators to split on.
+ *
+ * @param delims
+ * The repeated simple operators to split on.
+ */
+ public void addSimpleMulti(String... delims) {
+ for(String delim : delims) {
+ low.addMultiDelimiter(delim);
+ }
+ }
+
+ /**
+ * Ready the splitter for use.
+ */
+ public void compile() {
+ high.compile();
+
+ low.compile();
+ }
+}