summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/PrattParserTest.java119
-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
10 files changed, 305 insertions, 72 deletions
diff --git a/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/PrattParserTest.java b/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/PrattParserTest.java
index 6b97c19..522bf6f 100644
--- a/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/PrattParserTest.java
+++ b/BJC-Utils2/src/examples/java/bjc/utils/examples/parsing/PrattParserTest.java
@@ -4,6 +4,8 @@ import bjc.utils.data.ITree;
import bjc.utils.data.TransformIterator;
import bjc.utils.esodata.Directory;
import bjc.utils.parserutils.ParserException;
+import bjc.utils.parserutils.pratt.InitialCommand;
+import bjc.utils.parserutils.pratt.NonInitialCommand;
import bjc.utils.parserutils.pratt.PrattParser;
import bjc.utils.parserutils.pratt.Token;
import bjc.utils.parserutils.pratt.tokens.StringToken;
@@ -19,11 +21,16 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
+import java.util.function.Function;
import java.util.function.UnaryOperator;
import static bjc.utils.parserutils.pratt.commands.NonInitialCommands.*;
import static bjc.utils.parserutils.pratt.commands.InitialCommands.*;
+import static bjc.utils.parserutils.pratt.tokens.StringToken.litToken;
+
+import static bjc.utils.functypes.ID.id;
+
/**
* Simple test for Pratt parser.
*
@@ -31,6 +38,29 @@ import static bjc.utils.parserutils.pratt.commands.InitialCommands.*;
*
*/
public class PrattParserTest {
+ private static final class Tokenizer implements Function<String, Token<String, String>> {
+ private Set<String> ops;
+ private Set<String> reserved;
+ private TestContext ctx;
+
+ public Tokenizer(Set<String> operators, Set<String> reservedWords, TestContext context) {
+ ops = operators;
+ reserved = reservedWords;
+ ctx = context;
+ }
+
+ @Override
+ public Token<String, String> apply(String strang) {
+ if (ops.contains(strang) || reserved.contains(strang)) {
+ return litToken(strang);
+ } else if (ctx.scopes.top().containsKey(strang)) {
+ return new StringToken("(vref)", strang);
+ } else {
+ return new StringToken("(literal)", strang);
+ }
+ }
+ }
+
private static final class BlockExit implements UnaryOperator<TestContext> {
@Override
public TestContext apply(TestContext state) {
@@ -119,7 +149,7 @@ public class PrattParserTest {
System.out.print("Enter a command (blank line to exit): ");
String ln = scn.nextLine();
- while(!ln.trim().equals("")) {
+ while (!ln.trim().equals("")) {
Iterator<Token<String, String>> tokens = preprocessInput(ops, split, ln, reserved, ctx);
try {
@@ -132,12 +162,12 @@ public class PrattParserTest {
ITree<Token<String, String>> tree = parser.parseExpression(0, tokenStream, ctx, true);
- if(!tokenStream.current().getKey().equals("(end)")) {
+ if (!tokenStream.headIs("(end)")) {
System.out.println("Multiple expressions on line");
}
System.out.println("Parsed expression:\n" + tree);
- } catch(ParserException pex) {
+ } catch (ParserException pex) {
pex.printStackTrace();
}
@@ -157,17 +187,17 @@ public class PrattParserTest {
List<String> splitTokens = new LinkedList<>();
- for(String raw : rawTokens) {
+ for (String raw : rawTokens) {
boolean doSplit = false;
- for(String op : ops) {
- if(raw.contains(op)) {
+ for (String op : ops) {
+ if (raw.contains(op)) {
doSplit = true;
break;
}
}
- if(doSplit) {
+ if (doSplit) {
String[] strangs = split.split(raw);
splitTokens.addAll(Arrays.asList(strangs));
@@ -180,15 +210,8 @@ public class PrattParserTest {
Iterator<String> source = splitTokens.iterator();
- Iterator<Token<String, String>> tokens = new TransformIterator<>(source, (String strang) -> {
- if(ops.contains(strang) || reserved.contains(strang)) {
- return new StringToken(strang, strang);
- } else if(ctx.scopes.top().containsKey(strang)) {
- return new StringToken("(vref)", strang);
- } else {
- return new StringToken("(literal)", strang);
- }
- });
+ Iterator<Token<String, String>> tokens = new TransformIterator<>(source,
+ new Tokenizer(ops, reserved, ctx));
return tokens;
}
@@ -202,33 +225,43 @@ public class PrattParserTest {
/*
* Token for marking chains.
*/
- StringToken chainToken = new StringToken("and", "and");
+ StringToken chainToken = litToken("and");
+
+ /*
+ * ID function.
+ */
+ UnaryOperator<TestContext> idfun = id();
PrattParser<String, String, TestContext> parser = new PrattParser<>();
parser.addNonInitialCommand(":", infixNon(3));
- parser.addNonInitialCommand("if", ternary(5, 0, "else", new StringToken("cond", "cond"), false));
+ parser.addNonInitialCommand("if", ternary(5, 0, "else", litToken("cond"), false));
parser.addNonInitialCommand(":=", new AssignCommand());
- parser.addNonInitialCommand("and", infixLeft(13));
- parser.addNonInitialCommand("or", infixLeft(13));
+ NonInitialCommand<String, String, TestContext> nonSSRelJoin = infixLeft(13);
+ parser.addNonInitialCommand("and", nonSSRelJoin);
+ parser.addNonInitialCommand("or", nonSSRelJoin);
- parser.addNonInitialCommand("=", chain(15, relChain, chainToken));
- parser.addNonInitialCommand("<", chain(15, relChain, chainToken));
- parser.addNonInitialCommand(">", chain(15, relChain, chainToken));
- parser.addNonInitialCommand("<=", chain(15, relChain, chainToken));
- parser.addNonInitialCommand(">=", chain(15, relChain, chainToken));
+ NonInitialCommand<String, String, TestContext> chainRelOp = chain(15, relChain, chainToken);
+ parser.addNonInitialCommand("=", chainRelOp);
+ parser.addNonInitialCommand("<", chainRelOp);
+ parser.addNonInitialCommand(">", chainRelOp);
+ parser.addNonInitialCommand("<=", chainRelOp);
+ parser.addNonInitialCommand(">=", chainRelOp);
- parser.addNonInitialCommand("&&", infixRight(17));
- parser.addNonInitialCommand("||", infixRight(17));
+ NonInitialCommand<String, String, TestContext> ssRelJoin = infixRight(17);
+ parser.addNonInitialCommand("&&", ssRelJoin);
+ parser.addNonInitialCommand("||", ssRelJoin);
- parser.addNonInitialCommand("+", infixLeft(20));
- parser.addNonInitialCommand("-", infixLeft(20));
+ NonInitialCommand<String, String, TestContext> addSub = infixLeft(20);
+ parser.addNonInitialCommand("+", addSub);
+ parser.addNonInitialCommand("-", addSub);
- parser.addNonInitialCommand("*", infixLeft(30));
- parser.addNonInitialCommand("/", infixLeft(30));
+ NonInitialCommand<String, String, TestContext> mulDiv = infixLeft(30);
+ parser.addNonInitialCommand("*", mulDiv);
+ parser.addNonInitialCommand("/", mulDiv);
parser.addNonInitialCommand("!", postfix(40));
@@ -236,28 +269,26 @@ public class PrattParserTest {
parser.addNonInitialCommand(".", infixLeft(60));
- parser.addNonInitialCommand("[", postCircumfix(60, 0, "]", new StringToken("idx", "idx")));
+ parser.addNonInitialCommand("[", postCircumfix(60, 0, "]", litToken("idx")));
- parser.addInitialCommand("if",
- preTernary(0, 0, 0, "then", "else", new StringToken("ifelse", "ifelse")));
+ parser.addInitialCommand("if", preTernary(0, 0, 0, "then", "else", litToken("ifelse")));
- parser.addInitialCommand("(", grouping(0, ")", new StringToken("parens", "parens")));
+ parser.addInitialCommand("(", grouping(0, ")", litToken("parens")));
- parser.addInitialCommand("begin", delimited(0, ";", "end", new StringToken("block", "block"),
- new BlockEnter(), (state) -> state, new BlockExit(), true));
+ parser.addInitialCommand("begin", delimited(0, ";", "end", litToken("block"), new BlockEnter(), idfun,
+ new BlockExit(), true));
- parser.addInitialCommand("[", delimited(0, ",", "]", new StringToken("array", "array"),
- (state) -> state, (state) -> state, (state) -> state, false));
+ parser.addInitialCommand("[", delimited(0, ",", "]", litToken("array"), idfun, idfun, idfun, false));
- parser.addInitialCommand("{", delimited(0, ",", "}", new StringToken("json", "json"), (state) -> state,
- (state) -> state, (state) -> state, false));
+ parser.addInitialCommand("{", delimited(0, ",", "}", litToken("json"), idfun, idfun, idfun, false));
parser.addInitialCommand("case", unary(5));
parser.addInitialCommand("-", unary(30));
- parser.addInitialCommand("(literal)", leaf());
- parser.addInitialCommand("(vref)", leaf());
+ InitialCommand<String, String, TestContext> leaf = leaf();
+ parser.addInitialCommand("(literal)", leaf);
+ parser.addInitialCommand("(vref)", leaf);
parser.addInitialCommand("var", new VarCommand());
@@ -265,4 +296,4 @@ public class PrattParserTest {
return parser;
}
-}
+} \ No newline at end of file
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;