summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src/main
diff options
context:
space:
mode:
authorbjculkin <bjculkin@WIT-136XG42.wvu-ad.wvu.edu>2017-03-27 10:51:28 -0400
committerbjculkin <bjculkin@WIT-136XG42.wvu-ad.wvu.edu>2017-03-27 10:51:28 -0400
commit572551b78e7f36b65185cb258bea31114d9992f6 (patch)
tree3b5491e001e2a0b667f92eda78476146f41cfd9b /BJC-Utils2/src/main
parentc9bce5d0ad88667eebf0f646fcc2323505ebc4ac (diff)
Simplifications
Diffstat (limited to 'BJC-Utils2/src/main')
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/functypes/ID.java9
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReaders.java26
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/PrattParser.java67
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/TokenStream.java4
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/ParseBlocks.java73
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DenestingCommand.java31
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/InitialCommands.java36
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/tokens/StringToken.java4
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/tokens/StringTokenStream.java8
9 files changed, 230 insertions, 28 deletions
diff --git a/BJC-Utils2/src/main/java/bjc/utils/functypes/ID.java b/BJC-Utils2/src/main/java/bjc/utils/functypes/ID.java
new file mode 100644
index 0000000..af72d1a
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/functypes/ID.java
@@ -0,0 +1,9 @@
+package bjc.utils.functypes;
+
+import java.util.function.UnaryOperator;
+
+public class ID {
+ public static <A> UnaryOperator<A> id() {
+ return (x) -> x;
+ }
+}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReaders.java b/BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReaders.java
new file mode 100644
index 0000000..ec8dcfb
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/ioutils/BlockReaders.java
@@ -0,0 +1,26 @@
+package bjc.utils.ioutils;
+
+import java.io.Reader;
+
+/**
+ * Utility methods for constructing instances of {@link BlockReader}
+ *
+ * @author bjculkin
+ *
+ */
+public class BlockReaders {
+ /**
+ * Create a new simple block reader that works off a regex.
+ *
+ * @param blockDelim
+ * The regex that seperates blocks.
+ *
+ * @param source
+ * The reader to get blocks from.
+ *
+ * @return A configured simple reader.
+ */
+ public static BlockReader simple(String blockDelim, Reader source) {
+ return new SimpleBlockReader(blockDelim, source);
+ }
+}
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 20572e8..c53b4e1 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
@@ -26,18 +26,37 @@ import java.util.Map;
*
*/
public class PrattParser<K, V, C> {
+ /*
+ * Default commands that error when used.
+ */
private final NonInitialCommand<K, V, C> DEFAULT_LEFT_COMMAND = new DefaultNonInitialCommand<>();
- private final InitialCommand<K, V, C> DEFAULT_NULL_COMMAND = new DefaultInitialCommand<>();
+ private final InitialCommand<K, V, C> DEFAULT_NULL_COMMAND = new DefaultInitialCommand<>();
+
+ /*
+ * Left-commands that depend on what the null command was.
+ */
+ private Map<K, Map<K, NonInitialCommand<K, V, C>>> dependantLeftCommands;
- private Map<K, NonInitialCommand<K, V, C>> leftCommands;
- private Map<K, InitialCommand<K, V, C>> nullCommands;
- private Map<K, InitialCommand<K, V, C>> statementCommands;
+ /*
+ * The left commands.
+ */
+ private Map<K, NonInitialCommand<K, V, C>> leftCommands;
+ /*
+ * The initial commands.
+ */
+ private Map<K, InitialCommand<K, V, C>> nullCommands;
+ /*
+ * Initial commands only checked for statements.
+ */
+ private Map<K, InitialCommand<K, V, C>> statementCommands;
/**
* Create a new Pratt parser.
*
*/
public PrattParser() {
+ dependantLeftCommands = new HashMap<>();
+
leftCommands = new HashMap<>();
nullCommands = new HashMap<>();
statementCommands = new HashMap<>();
@@ -65,34 +84,41 @@ public class PrattParser<K, V, C> {
*/
public ITree<Token<K, V>> parseExpression(int precedence, TokenStream<K, V> tokens, C state,
boolean isStatement) throws ParserException {
- if(precedence < 0) {
+ if (precedence < 0) {
throw new IllegalArgumentException("Precedence must be greater than zero");
}
Token<K, V> initToken = tokens.current();
tokens.next();
+ K initKey = initToken.getKey();
+
ITree<Token<K, V>> ast;
- if(isStatement && statementCommands.containsKey(initToken.getKey())) {
- ast = statementCommands.getOrDefault(initToken.getKey(), DEFAULT_NULL_COMMAND)
- .denote(initToken, new ParserContext<>(tokens, this, state));
+ if (isStatement && statementCommands.containsKey(initKey)) {
+ ast = statementCommands.getOrDefault(initKey, DEFAULT_NULL_COMMAND).denote(initToken,
+ new ParserContext<>(tokens, this, state));
} else {
- ast = nullCommands.getOrDefault(initToken.getKey(), DEFAULT_NULL_COMMAND)
- .denote(initToken, new ParserContext<>(tokens, this, state));
+ ast = nullCommands.getOrDefault(initKey, 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();
NonInitialCommand<K, V, C> command = leftCommands.getOrDefault(key, DEFAULT_LEFT_COMMAND);
+
+ if (dependantLeftCommands.containsKey(initKey)) {
+ command = dependantLeftCommands.get(initKey).getOrDefault(key, command);
+ }
+
int leftBind = command.leftBinding();
- if(NumberUtils.between(precedence, rightPrec, leftBind)) {
+ if (NumberUtils.between(precedence, rightPrec, leftBind)) {
tokens.next();
ast = command.denote(ast, tok, new ParserContext<>(tokens, this, state));
@@ -146,4 +172,19 @@ public class PrattParser<K, V, C> {
public void addStatementCommand(K marker, InitialCommand<K, V, C> comm) {
statementCommands.put(marker, comm);
}
-}
+
+ /**
+ * Add a dependant non-initial command to this parser.
+ */
+ public void addDependantCommand(K dependant, K marker, NonInitialCommand<K, V, C> comm) {
+ if (dependantLeftCommands.containsKey(dependant)) {
+ dependantLeftCommands.get(dependant).put(marker, comm);
+ } else {
+ Map<K, NonInitialCommand<K, V, C>> comms = new HashMap<>();
+
+ comms.put(marker, comm);
+
+ dependantLeftCommands.put(dependant, comms);
+ }
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/TokenStream.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/TokenStream.java
index 71482b4..db7d1e0 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/TokenStream.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/TokenStream.java
@@ -86,4 +86,8 @@ public abstract class TokenStream<K, V> implements Iterator<Token<K, V>> {
public final void expect(K... expectedKeys) throws ExpectationException {
expect(new HashSet<>(Arrays.asList(expectedKeys)));
}
+
+ public boolean headIs(K val) {
+ return current().getKey().equals(val);
+ }
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/ParseBlocks.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/ParseBlocks.java
index 43163e6..9df8355 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/ParseBlocks.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/blocks/ParseBlocks.java
@@ -1,6 +1,11 @@
package bjc.utils.parserutils.pratt.blocks;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+
+import bjc.utils.data.ITree;
import bjc.utils.parserutils.pratt.ParseBlock;
+import bjc.utils.parserutils.pratt.Token;
/**
* Utility class for creating common implementations of {@link ParseBlock}
@@ -9,5 +14,71 @@ import bjc.utils.parserutils.pratt.ParseBlock;
*
*/
public class ParseBlocks {
+ /**
+ * Create a new repeating parse block.
+ *
+ * @param inner
+ * The parse block to repeat.
+ *
+ * @param delim
+ * The token type that seperates repetitions.
+ *
+ * @param term
+ * The token type that terminates repititions.
+ *
+ * @param mark
+ * The token to use as the node in the AST.
+ *
+ * @param action
+ * The action to perform on the state after every
+ * repitition.
+ *
+ * @return A configured repeating parse block.
+ */
+ public static <K, V, C> ParseBlock<K, V, C> repeating(ParseBlock<K, V, C> inner, K delim, K term,
+ Token<K, V> mark, UnaryOperator<C> action) {
+ return new RepeatingParseBlock<>(inner, delim, term, mark, action);
+ }
+
+ /**
+ * Create a new triggered parse block.
+ *
+ * @param source
+ * The block to trigger around.
+ *
+ * @param onEnter
+ * The action to perform upon the state before entering
+ * the block.
+ *
+ * @param onExit
+ * The action to perform upon the state after exiting the
+ * block.
+ *
+ * @return A configured trigger parse block.
+ */
+ public static <K, V, C> ParseBlock<K, V, C> trigger(ParseBlock<K, V, C> source, UnaryOperator<C> onEnter,
+ UnaryOperator<C> onExit) {
+ return new TriggeredParseBlock<>(onEnter, onExit, source);
+ }
-}
+ /**
+ * Create a new simple parse block.
+ *
+ * @param precedence
+ * The precedence of the expression inside the block.
+ *
+ * @param terminator
+ * The key type of the token expected after this block,
+ * or null if none is expected.
+ *
+ * @param validator
+ * The predicate to use to validate parsed expressions,
+ * or null if none is used.
+ *
+ * @return A configured simple parse block.
+ */
+ public static <K, V, C> ParseBlock<K, V, C> simple(int precedence, K terminator,
+ Predicate<ITree<Token<K, V>>> validator) {
+ return new SimpleParseBlock<>(precedence, terminator, validator);
+ }
+} \ No newline at end of file
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DenestingCommand.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DenestingCommand.java
new file mode 100644
index 0000000..d2d7829
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/commands/DenestingCommand.java
@@ -0,0 +1,31 @@
+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 DenestingCommand<C, V, K> extends AbstractInitialCommand<K, V, C> {
+ private InitialCommand<K, V, C> internal;
+
+ /**
+ * 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 DenestingCommand(InitialCommand<K, V, C> internal) {
+ super();
+ this.internal = internal;
+ }
+
+ @Override
+ protected ITree<Token<K, V>> intNullDenotation(Token<K, V> operator, ParserContext<K, V, C> ctx)
+ throws ParserException {
+ return internal.denote(operator, ctx).getChild(0);
+ }
+} \ 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
index bad5964..eac357a 100644
--- 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
@@ -4,12 +4,11 @@ import bjc.utils.data.ITree;
import bjc.utils.parserutils.pratt.InitialCommand;
import bjc.utils.parserutils.pratt.ParseBlock;
import bjc.utils.parserutils.pratt.Token;
-import bjc.utils.parserutils.pratt.blocks.RepeatingParseBlock;
-import bjc.utils.parserutils.pratt.blocks.SimpleParseBlock;
-import bjc.utils.parserutils.pratt.blocks.TriggeredParseBlock;
import java.util.function.UnaryOperator;
+import static bjc.utils.parserutils.pratt.blocks.ParseBlocks.*;
+
/**
* * Contains factory methods for producing common implementations of
* {@link InitialCommand}
@@ -45,7 +44,7 @@ public class InitialCommands {
* @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 = new SimpleParseBlock<>(precedence, term, null);
+ ParseBlock<K, V, C> innerBlock = simple(precedence, term, null);
return new GroupingCommand<>(innerBlock, mark);
}
@@ -84,9 +83,9 @@ public class InitialCommands {
*/
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 = new SimpleParseBlock<>(cond1, mark1, null);
- ParseBlock<K, V, C> opblock1 = new SimpleParseBlock<>(block1, mark2, null);
- ParseBlock<K, V, C> opblock2 = new SimpleParseBlock<>(block2, null, null);
+ 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);
}
@@ -139,9 +138,9 @@ public class InitialCommands {
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 = new SimpleParseBlock<>(inner, null, null);
- ParseBlock<K, V, C> delimsBlock = new RepeatingParseBlock<>(innerBlock, delim, mark, term, onDelim);
- ParseBlock<K, V, C> scopedBlock = new TriggeredParseBlock<>(onEnter, onExit, delimsBlock);
+ 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);
@@ -149,6 +148,21 @@ public class InitialCommands {
* Remove the wrapper layer from grouping-command on top of
* RepeatingParseBlock.
*/
- return new TransformingInitialCommand<>(command, (tree) -> tree.getChild(0));
+ 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/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/tokens/StringToken.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/tokens/StringToken.java
index 7e779aa..f156f02 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/tokens/StringToken.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/tokens/StringToken.java
@@ -77,4 +77,8 @@ public class StringToken implements Token<String, String> {
public String toString() {
return String.format("StringToken [key='%s', val='%s']", key, val);
}
+
+ public static StringToken litToken(String val) {
+ return new StringToken(val, val);
+ }
}
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/tokens/StringTokenStream.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/tokens/StringTokenStream.java
index d7d4a66..75e86c4 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/tokens/StringTokenStream.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/pratt/tokens/StringTokenStream.java
@@ -5,11 +5,13 @@ import java.util.Iterator;
import bjc.utils.parserutils.pratt.Token;
import bjc.utils.parserutils.pratt.TokenStream;
+import static bjc.utils.parserutils.pratt.tokens.StringToken.litToken;
+
/**
* Simple implementation of token stream for strings.
*
- * The terminal token here is represented by a token with type '(end)' and null
- * value.
+ * The terminal token here is represented by a token with type and value
+ * '(end)'.
*
* @author EVE
*
@@ -41,7 +43,7 @@ public class StringTokenStream extends TokenStream<String, String> {
if (iter.hasNext()) {
curr = iter.next();
} else {
- curr = new StringToken("(end)", null);
+ curr = litToken("(end)");
}
return curr;