summaryrefslogtreecommitdiff
path: root/JPratt/src/main/java/bjc/pratt/commands
diff options
context:
space:
mode:
authorbjculkin <bjculkin@mix.wvu.edu>2017-04-05 15:35:13 -0400
committerbjculkin <bjculkin@mix.wvu.edu>2017-04-05 15:35:13 -0400
commitc82452e59b1547392c3e89d08d9173cc6dc79e23 (patch)
tree1927051f7cab7a64eef3f53a78b77780db6cf281 /JPratt/src/main/java/bjc/pratt/commands
parentb61c66d5e0c18faee68eb91881d5dfe760818856 (diff)
Reorganize
Diffstat (limited to 'JPratt/src/main/java/bjc/pratt/commands')
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/AbstractInitialCommand.java32
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/BinaryCommand.java43
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/BinaryPostCommand.java40
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/ChainCommand.java73
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/ConstantCommand.java40
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/DefaultInitialCommand.java28
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/DefaultNonInitialCommand.java32
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/DenestingCommand.java45
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/GroupingCommand.java51
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/InitialCommands.java168
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/LeafCommand.java29
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/LeftBinaryCommand.java32
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/NonBinaryCommand.java37
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/NonInitialCommands.java140
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/PostCircumfixCommand.java60
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/PostfixCommand.java39
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/PreTernaryCommand.java75
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/RightBinaryCommand.java30
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/TernaryCommand.java77
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/TransformingInitialCommand.java52
-rw-r--r--JPratt/src/main/java/bjc/pratt/commands/UnaryCommand.java47
21 files changed, 1170 insertions, 0 deletions
diff --git a/JPratt/src/main/java/bjc/pratt/commands/AbstractInitialCommand.java b/JPratt/src/main/java/bjc/pratt/commands/AbstractInitialCommand.java
new file mode 100644
index 0000000..b5a789c
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/AbstractInitialCommand.java
@@ -0,0 +1,32 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.InitialCommand;
+import bjc.pratt.ParserContext;
+import bjc.pratt.Token;
+import bjc.utils.data.ITree;
+import bjc.utils.parserutils.ParserException;
+
+/**
+ * Abstract base for initial commands.
+ *
+ * @author bjculkin
+ *
+ * @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 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/JPratt/src/main/java/bjc/pratt/commands/BinaryCommand.java b/JPratt/src/main/java/bjc/pratt/commands/BinaryCommand.java
new file mode 100644
index 0000000..44cb5f8
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/BinaryCommand.java
@@ -0,0 +1,43 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.ParserContext;
+import bjc.pratt.Token;
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+
+/**
+ * A binary operator.
+ *
+ * @author bjculkin
+ *
+ * @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 abstract class BinaryCommand<K, V, C> extends BinaryPostCommand<K, V, C> {
+ /**
+ * Create a new binary operator with the specified precedence.
+ *
+ * @param precedence
+ * The precedence of the operator.
+ */
+ public BinaryCommand(int precedence) {
+ super(precedence);
+ }
+
+ 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/JPratt/src/main/java/bjc/pratt/commands/BinaryPostCommand.java b/JPratt/src/main/java/bjc/pratt/commands/BinaryPostCommand.java
new file mode 100644
index 0000000..18a5584
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/BinaryPostCommand.java
@@ -0,0 +1,40 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.NonInitialCommand;
+
+/**
+ * A operator with fixed precedence.
+ *
+ * @author bjculkin
+ *
+ * @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 abstract class BinaryPostCommand<K, V, C> extends NonInitialCommand<K, V, C> {
+ private final int leftPower;
+
+ /**
+ * Create a new operator with fixed precedence.
+ *
+ * @param precedence
+ * The precedence of the operator.
+ */
+ public BinaryPostCommand(int precedence) {
+ if (precedence < 0) {
+ throw new IllegalArgumentException("Precedence must be non-negative");
+ }
+
+ leftPower = precedence;
+ }
+
+ @Override
+ public int leftBinding() {
+ return leftPower;
+ }
+} \ No newline at end of file
diff --git a/JPratt/src/main/java/bjc/pratt/commands/ChainCommand.java b/JPratt/src/main/java/bjc/pratt/commands/ChainCommand.java
new file mode 100644
index 0000000..c7a10b1
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/ChainCommand.java
@@ -0,0 +1,73 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.ParserContext;
+import bjc.pratt.Token;
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+
+import java.util.Set;
+
+/**
+ * Create a new chained operator.
+ *
+ * @author bjculkin
+ *
+ * @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 ChainCommand<K, V, C> extends BinaryPostCommand<K, V, C> {
+ private Set<K> chainWith;
+
+ private Token<K, V> chain;
+
+ /**
+ * Create a new chained operator.
+ *
+ * @param precedence
+ * The precedence of this operator.
+ *
+ * @param chainSet
+ * The operators to chain with.
+ *
+ * @param chainMarker
+ * The token to use as the node in the AST.
+ */
+ public ChainCommand(int precedence, Set<K> chainSet, Token<K, V> chainMarker) {
+ super(precedence);
+
+ 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/JPratt/src/main/java/bjc/pratt/commands/ConstantCommand.java b/JPratt/src/main/java/bjc/pratt/commands/ConstantCommand.java
new file mode 100644
index 0000000..86a172f
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/ConstantCommand.java
@@ -0,0 +1,40 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.InitialCommand;
+import bjc.pratt.ParserContext;
+import bjc.pratt.Token;
+import bjc.utils.data.ITree;
+import bjc.utils.parserutils.ParserException;
+
+/**
+ * A command that represents a specific tree.
+ *
+ * @author bjculkin
+ *
+ * @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 ConstantCommand<K, V, C> implements InitialCommand<K, V, C> {
+ private ITree<Token<K, V>> val;
+
+ /**
+ * Create a new constant.
+ *
+ * @param con
+ * The tree this constant represents.
+ */
+ 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/JPratt/src/main/java/bjc/pratt/commands/DefaultInitialCommand.java b/JPratt/src/main/java/bjc/pratt/commands/DefaultInitialCommand.java
new file mode 100644
index 0000000..717444a
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/DefaultInitialCommand.java
@@ -0,0 +1,28 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.InitialCommand;
+import bjc.pratt.ParserContext;
+import bjc.pratt.Token;
+import bjc.utils.data.ITree;
+import bjc.utils.parserutils.ParserException;
+
+/**
+ * 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/JPratt/src/main/java/bjc/pratt/commands/DefaultNonInitialCommand.java b/JPratt/src/main/java/bjc/pratt/commands/DefaultNonInitialCommand.java
new file mode 100644
index 0000000..aeb337d
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/DefaultNonInitialCommand.java
@@ -0,0 +1,32 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.NonInitialCommand;
+import bjc.pratt.ParserContext;
+import bjc.pratt.Token;
+import bjc.utils.data.ITree;
+
+/**
+ * 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/JPratt/src/main/java/bjc/pratt/commands/DenestingCommand.java b/JPratt/src/main/java/bjc/pratt/commands/DenestingCommand.java
new file mode 100644
index 0000000..9b4518f
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/DenestingCommand.java
@@ -0,0 +1,45 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.InitialCommand;
+import bjc.pratt.ParserContext;
+import bjc.pratt.Token;
+import bjc.utils.data.ITree;
+import bjc.utils.parserutils.ParserException;
+
+/**
+ * A command that denests a input tree.
+ *
+ * Useful for processing the result of passing a complex parse group to a
+ * command.
+ *
+ * @author bjculkin
+ *
+ * @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 DenestingCommand<K, V, C> extends AbstractInitialCommand<K, V, C> {
+ private InitialCommand<K, V, C> wrapped;
+
+ /**
+ * Create a new transforming initial command.
+ *
+ * @param internal
+ * The initial command to delegate to.
+ */
+ public DenestingCommand(InitialCommand<K, V, C> internal) {
+ wrapped = internal;
+ }
+
+ @Override
+ protected ITree<Token<K, V>> intNullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
+ throws ParserException {
+ return wrapped.denote(operator, ctx).getChild(0);
+ }
+} \ No newline at end of file
diff --git a/JPratt/src/main/java/bjc/pratt/commands/GroupingCommand.java b/JPratt/src/main/java/bjc/pratt/commands/GroupingCommand.java
new file mode 100644
index 0000000..1a8d3c8
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/GroupingCommand.java
@@ -0,0 +1,51 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.ParseBlock;
+import bjc.pratt.ParserContext;
+import bjc.pratt.Token;
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+
+/**
+ * A grouping operator.
+ *
+ * @author bjculkin
+ *
+ * @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 GroupingCommand<K, V, C> extends AbstractInitialCommand<K, V, C> {
+ private ParseBlock<K, V, C> innerBlock;
+
+ private Token<K, V> mark;
+
+ /**
+ * Create a new grouping command.
+ *
+ * @param inner
+ * The inner block.
+ *
+ * @param marker
+ * The token to use as the node in the AST.
+ */
+ public GroupingCommand(ParseBlock<K, V, C> inner, Token<K, V> marker) {
+ innerBlock = inner;
+
+ mark = marker;
+ }
+
+ @Override
+ protected ITree<Token<K, V>> intNullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
+ throws ParserException {
+ ITree<Token<K, V>> opr = innerBlock.parse(ctx);
+
+ return new Tree<>(mark, opr);
+ }
+} \ No newline at end of file
diff --git a/JPratt/src/main/java/bjc/pratt/commands/InitialCommands.java b/JPratt/src/main/java/bjc/pratt/commands/InitialCommands.java
new file mode 100644
index 0000000..3ece14c
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/InitialCommands.java
@@ -0,0 +1,168 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.InitialCommand;
+import bjc.pratt.ParseBlock;
+import bjc.pratt.Token;
+import bjc.utils.data.ITree;
+
+import java.util.function.UnaryOperator;
+
+import static bjc.pratt.blocks.ParseBlocks.*;
+
+/**
+ * * 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) {
+ ParseBlock<K, V, C> innerBlock = simple(precedence, term, null);
+
+ return new GroupingCommand<>(innerBlock, 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) {
+ ParseBlock<K, V, C> condBlock = simple(cond1, mark1, null);
+ ParseBlock<K, V, C> opblock1 = simple(block1, mark2, null);
+ ParseBlock<K, V, C> opblock2 = simple(block2, null, null);
+
+ return new PreTernaryCommand<>(condBlock, opblock1, opblock2, 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) {
+ ParseBlock<K, V, C> innerBlock = simple(inner, null, null);
+ ParseBlock<K, V, C> delimsBlock = repeating(innerBlock, delim, mark, term, onDelim);
+ ParseBlock<K, V, C> scopedBlock = trigger(delimsBlock, onEnter, onExit);
+
+ GroupingCommand<K, V, C> command = new GroupingCommand<>(scopedBlock, term);
+
+ /*
+ * Remove the wrapper layer from grouping-command on top of
+ * RepeatingParseBlock.
+ */
+ return denest(command);
+ }
+
+ /**
+ * Create a new denesting command.
+ *
+ * This removes one tree-level, and is useful when combining complex
+ * parse blocks with commands.
+ *
+ * @param comm
+ * The command to denest.
+ *
+ * @return A command that denests the result of the provided command.
+ */
+ public static <K, V, C> InitialCommand<K, V, C> denest(InitialCommand<K, V, C> comm) {
+ return new DenestingCommand<>(comm);
+ }
+}
diff --git a/JPratt/src/main/java/bjc/pratt/commands/LeafCommand.java b/JPratt/src/main/java/bjc/pratt/commands/LeafCommand.java
new file mode 100644
index 0000000..798b9ce
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/LeafCommand.java
@@ -0,0 +1,29 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.InitialCommand;
+import bjc.pratt.ParserContext;
+import bjc.pratt.Token;
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+
+/**
+ * A operator that stands for itself.
+ *
+ * @author bjculkin
+ *
+ * @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 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/JPratt/src/main/java/bjc/pratt/commands/LeftBinaryCommand.java b/JPratt/src/main/java/bjc/pratt/commands/LeftBinaryCommand.java
new file mode 100644
index 0000000..4a481d7
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/LeftBinaryCommand.java
@@ -0,0 +1,32 @@
+package bjc.pratt.commands;
+
+/**
+ * A left-associative operator.
+ *
+ * @author bjculkin
+ *
+ * @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 LeftBinaryCommand<K, V, C> extends BinaryCommand<K, V, C> {
+ /**
+ * Create a new left-associative operator.
+ *
+ * @param precedence
+ * The precedence of the operator.
+ */
+ public LeftBinaryCommand(int precedence) {
+ super(precedence);
+ }
+
+ @Override
+ protected int rightBinding() {
+ return 1 + leftBinding();
+ }
+} \ No newline at end of file
diff --git a/JPratt/src/main/java/bjc/pratt/commands/NonBinaryCommand.java b/JPratt/src/main/java/bjc/pratt/commands/NonBinaryCommand.java
new file mode 100644
index 0000000..d1208bd
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/NonBinaryCommand.java
@@ -0,0 +1,37 @@
+package bjc.pratt.commands;
+
+/**
+ * A non-associative operator.
+ *
+ * @author bjculkin
+ *
+ * @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 NonBinaryCommand<K, V, C> extends BinaryCommand<K, V, C> {
+ /**
+ * Create a new non-associative operator.
+ *
+ * @param precedence
+ * The precedence of the operator.
+ */
+ public NonBinaryCommand(int precedence) {
+ super(precedence);
+ }
+
+ @Override
+ protected int rightBinding() {
+ return 1 + leftBinding();
+ }
+
+ @Override
+ public int nextBinding() {
+ return leftBinding() - 1;
+ }
+} \ No newline at end of file
diff --git a/JPratt/src/main/java/bjc/pratt/commands/NonInitialCommands.java b/JPratt/src/main/java/bjc/pratt/commands/NonInitialCommands.java
new file mode 100644
index 0000000..b7eda95
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/NonInitialCommands.java
@@ -0,0 +1,140 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.NonInitialCommand;
+import bjc.pratt.ParseBlock;
+import bjc.pratt.Token;
+import bjc.pratt.blocks.SimpleParseBlock;
+
+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) {
+ ParseBlock<K, V, C> innerBlock = new SimpleParseBlock<>(insidePrecedence, closer, null);
+
+ return new PostCircumfixCommand<>(precedence, innerBlock, 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) {
+ ParseBlock<K, V, C> innerBlock = new SimpleParseBlock<>(insidePrecedence, closer, null);
+
+ return new TernaryCommand<>(precedence, innerBlock, marker, nonassoc);
+ }
+}
diff --git a/JPratt/src/main/java/bjc/pratt/commands/PostCircumfixCommand.java b/JPratt/src/main/java/bjc/pratt/commands/PostCircumfixCommand.java
new file mode 100644
index 0000000..6bed0ff
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/PostCircumfixCommand.java
@@ -0,0 +1,60 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.ParseBlock;
+import bjc.pratt.ParserContext;
+import bjc.pratt.Token;
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+
+/**
+ * A post-circumfix operator, like array indexing.
+ *
+ * @author bjculkin
+ *
+ * @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 PostCircumfixCommand<K, V, C> extends BinaryPostCommand<K, V, C> {
+ private ParseBlock<K, V, C> innerBlock;
+
+ private Token<K, V> mark;
+
+ /**
+ * Create a new post-circumfix operator.
+ *
+ * @param precedence
+ * The precedence of the operator.
+ *
+ * @param inner
+ * The block inside the expression.
+ *
+ * @param marker
+ * The token to use as the node for the AST.
+ */
+ public PostCircumfixCommand(int precedence, ParseBlock<K, V, C> inner, Token<K, V> marker) {
+ super(precedence);
+
+ if (inner == null) {
+ throw new NullPointerException("Inner block must not be null");
+ }
+
+ innerBlock = inner;
+
+ mark = marker;
+ }
+
+ @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 = innerBlock.parse(ctx);
+
+ return new Tree<>(mark, operand, inside);
+ }
+} \ No newline at end of file
diff --git a/JPratt/src/main/java/bjc/pratt/commands/PostfixCommand.java b/JPratt/src/main/java/bjc/pratt/commands/PostfixCommand.java
new file mode 100644
index 0000000..5e2ce28
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/PostfixCommand.java
@@ -0,0 +1,39 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.ParserContext;
+import bjc.pratt.Token;
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+
+/**
+ * A postfix operator.
+ *
+ * @author bjculkin
+ *
+ * @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 PostfixCommand<K, V, C> extends BinaryPostCommand<K, V, C> {
+ /**
+ * Create a new postfix operator.
+ *
+ * @param precedence
+ * The precedence of the operator.
+ */
+ public PostfixCommand(int precedence) {
+ super(precedence);
+ }
+
+ @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/JPratt/src/main/java/bjc/pratt/commands/PreTernaryCommand.java b/JPratt/src/main/java/bjc/pratt/commands/PreTernaryCommand.java
new file mode 100644
index 0000000..efa7872
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/PreTernaryCommand.java
@@ -0,0 +1,75 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.ParseBlock;
+import bjc.pratt.ParserContext;
+import bjc.pratt.Token;
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+
+/**
+ * A prefix ternary operator, like an if/then/else group.
+ *
+ * @author bjculkin
+ *
+ * @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 PreTernaryCommand<K, V, C> extends AbstractInitialCommand<K, V, C> {
+ private Token<K, V> term;
+
+ private ParseBlock<K, V, C> condBlock;
+
+ private ParseBlock<K, V, C> opblock1;
+ private ParseBlock<K, V, C> opblock2;
+
+ /**
+ * Create a new ternary statement.
+ *
+ * @param cond
+ * The block for handling the condition.
+ *
+ * @param op1
+ * The block for handling the first operator.
+ *
+ * @param op2
+ * The block for handling the second operator.
+ *
+ * @param term
+ * The token to use as the node for the AST.
+ */
+ public PreTernaryCommand(ParseBlock<K, V, C> cond, ParseBlock<K, V, C> op1, ParseBlock<K, V, C> op2,
+ Token<K, V> term) {
+ super();
+
+ if (cond == null)
+ throw new NullPointerException("Cond block must not be null");
+ else if (op1 == null)
+ throw new NullPointerException("Op block #1 must not be null");
+ else if (op2 == null) throw new NullPointerException("Op block #2 must not be null");
+
+ this.condBlock = cond;
+ this.opblock1 = op1;
+ this.opblock2 = op2;
+
+ this.term = term;
+ }
+
+ @Override
+ protected ITree<Token<K, V>> intNullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
+ throws ParserException {
+ ITree<Token<K, V>> cond = condBlock.parse(ctx);
+
+ ITree<Token<K, V>> op1 = opblock1.parse(ctx);
+
+ ITree<Token<K, V>> op2 = opblock2.parse(ctx);
+
+ return new Tree<>(term, cond, op1, op2);
+ }
+} \ No newline at end of file
diff --git a/JPratt/src/main/java/bjc/pratt/commands/RightBinaryCommand.java b/JPratt/src/main/java/bjc/pratt/commands/RightBinaryCommand.java
new file mode 100644
index 0000000..8ddab06
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/RightBinaryCommand.java
@@ -0,0 +1,30 @@
+package bjc.pratt.commands;
+
+/**
+ * A right-associative binary operator.
+ *
+ * @author bjculkin
+ *
+ * @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 RightBinaryCommand<K, V, C> extends BinaryCommand<K, V, C> {
+ /**
+ * Create a new right-associative operator.
+ *
+ * @param precedence
+ * The precedence of the operator.
+ */
+ public RightBinaryCommand(int precedence) {
+ super(precedence);
+ }
+
+ @Override
+ protected int rightBinding() {
+ return leftBinding();
+ }
+} \ No newline at end of file
diff --git a/JPratt/src/main/java/bjc/pratt/commands/TernaryCommand.java b/JPratt/src/main/java/bjc/pratt/commands/TernaryCommand.java
new file mode 100644
index 0000000..bac12cd
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/TernaryCommand.java
@@ -0,0 +1,77 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.ParseBlock;
+import bjc.pratt.ParserContext;
+import bjc.pratt.Token;
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+
+/**
+ * A ternary command, like C's ?:
+ *
+ * @author bjculkin
+ *
+ * @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 TernaryCommand<K, V, C> extends BinaryPostCommand<K, V, C> {
+ private ParseBlock<K, V, C> innerBlck;
+
+ private Token<K, V> mark;
+
+ private boolean nonassoc;
+
+ /**
+ * Create a new ternary command.
+ *
+ * @param precedence
+ * The precedence of this operator.
+ *
+ * @param innerBlock
+ * The representation of the inner block of the
+ * expression.
+ *
+ * @param marker
+ * The token to use as the root of the AST node.
+ *
+ * @param isNonassoc
+ * Whether or not the conditional is associative.
+ */
+ public TernaryCommand(int precedence, ParseBlock<K, V, C> innerBlock, Token<K, V> marker, boolean isNonassoc) {
+ super(precedence);
+
+ if (innerBlock == null)
+ throw new NullPointerException("Inner block must not be null");
+ else if (marker == null) throw new NullPointerException("Marker must not be null");
+
+ innerBlck = innerBlock;
+ mark = marker;
+ nonassoc = isNonassoc;
+ }
+
+ @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 = innerBlck.parse(ctx);
+
+ 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/JPratt/src/main/java/bjc/pratt/commands/TransformingInitialCommand.java b/JPratt/src/main/java/bjc/pratt/commands/TransformingInitialCommand.java
new file mode 100644
index 0000000..9ec3631
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/TransformingInitialCommand.java
@@ -0,0 +1,52 @@
+package bjc.pratt.commands;
+
+import java.util.function.UnaryOperator;
+
+import bjc.pratt.InitialCommand;
+import bjc.pratt.ParserContext;
+import bjc.pratt.Token;
+import bjc.utils.data.ITree;
+import bjc.utils.parserutils.ParserException;
+
+/**
+ * An initial command that transforms the result of another command.
+ *
+ * @author bjculkin
+ *
+ * @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 TransformingInitialCommand<K, V, C> extends AbstractInitialCommand<K, V, C> {
+ private InitialCommand<K, V, C> internal;
+
+ private UnaryOperator<ITree<Token<K, V>>> transform;
+
+ /**
+ * Create a new transforming initial command.
+ *
+ * @param internal
+ * The initial command to delegate to.
+ *
+ * @param transform
+ * The transform to apply to the returned tree.
+ */
+ public TransformingInitialCommand(InitialCommand<K, V, C> internal,
+ UnaryOperator<ITree<Token<K, V>>> transform) {
+ super();
+ this.internal = internal;
+ this.transform = transform;
+ }
+
+ @Override
+ protected ITree<Token<K, V>> intNullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
+ throws ParserException {
+ return transform.apply(internal.denote(operator, ctx));
+ }
+
+}
diff --git a/JPratt/src/main/java/bjc/pratt/commands/UnaryCommand.java b/JPratt/src/main/java/bjc/pratt/commands/UnaryCommand.java
new file mode 100644
index 0000000..0689210
--- /dev/null
+++ b/JPratt/src/main/java/bjc/pratt/commands/UnaryCommand.java
@@ -0,0 +1,47 @@
+package bjc.pratt.commands;
+
+import bjc.pratt.ParserContext;
+import bjc.pratt.Token;
+import bjc.utils.data.ITree;
+import bjc.utils.data.Tree;
+import bjc.utils.parserutils.ParserException;
+
+/**
+ * A unary operator.
+ *
+ * @author bjculkin
+ *
+ * @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 UnaryCommand<K, V, C> extends AbstractInitialCommand<K, V, C> {
+ private final int nullPwer;
+
+ /**
+ * Create a new unary command.
+ *
+ * @param precedence
+ * The precedence of this operator.
+ */
+ public UnaryCommand(int precedence) {
+ if(precedence < 0) {
+ throw new IllegalArgumentException("Precedence must be non-negative");
+ }
+
+ nullPwer = precedence;
+ }
+
+ @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